using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace LeTai.TrueShadow { interface IChangeTracker { void Check(); } class ChangeTracker : IChangeTracker { T previousValue; readonly Func getValue; readonly Func onChange; readonly IEqualityComparer comparer; public ChangeTracker(Func getValue, Func onChange, IEqualityComparer comparer = null) { this.getValue = getValue; this.onChange = onChange; this.comparer = comparer ?? EqualityComparer.Default; previousValue = this.getValue(); } public void Forget() { previousValue = getValue(); } public void Check() { T newValue = getValue(); if (!comparer.Equals(newValue, previousValue)) { previousValue = onChange(newValue); } } } public partial class TrueShadow { Action checkHierarchyDirtiedDelegate; IChangeTracker[] transformTrackers; ChangeTracker[] hierachyTrackers; void InitInvalidator() { checkHierarchyDirtiedDelegate = CheckHierarchyDirtied; hierachyTrackers = new[] { new ChangeTracker( () => transform.GetSiblingIndex(), newValue => { SetHierachyDirty(); return newValue; // + 1; } ), new ChangeTracker( () => { if (shadowRenderer) return shadowRenderer.transform.GetSiblingIndex(); return -1; }, newValue => { SetHierachyDirty(); return newValue; // + 1; } ) }; transformTrackers = new IChangeTracker[] { new ChangeTracker( () => transform.position, newValue => { SetLayoutDirty(); return newValue; } ), new ChangeTracker( () => transform.rotation, newValue => { SetLayoutDirty(); if (Cutout) SetTextureDirty(); return newValue; } ), }; Graphic.RegisterDirtyLayoutCallback(SetLayoutTextureDirty); Graphic.RegisterDirtyVerticesCallback(SetLayoutTextureDirty); Graphic.RegisterDirtyMaterialCallback(OnGraphicMaterialDirty); CheckHierarchyDirtied(); CheckTransformDirtied(); } void TerminateInvalidator() { if (Graphic) { Graphic.UnregisterDirtyLayoutCallback(SetLayoutTextureDirty); Graphic.UnregisterDirtyVerticesCallback(SetLayoutTextureDirty); Graphic.UnregisterDirtyMaterialCallback(OnGraphicMaterialDirty); } } void OnGraphicMaterialDirty() { SetLayoutTextureDirty(); shadowRenderer.UpdateMaterial(); } internal void CheckTransformDirtied() { if (transformTrackers != null) { for (var i = 0; i < transformTrackers.Length; i++) { transformTrackers[i].Check(); } } } internal void CheckHierarchyDirtied() { if (ShadowAsSibling && hierachyTrackers != null) { for (var i = 0; i < hierachyTrackers.Length; i++) { hierachyTrackers[i].Check(); } } } internal void ForgetSiblingIndexChanges() { for (var i = 0; i < hierachyTrackers.Length; i++) { hierachyTrackers[i].Forget(); } } protected override void OnTransformParentChanged() { base.OnTransformParentChanged(); if (!isActiveAndEnabled) return; SetHierachyDirty(); this.NextFrames(checkHierarchyDirtiedDelegate); } protected override void OnRectTransformDimensionsChange() { base.OnRectTransformDimensionsChange(); if (!isActiveAndEnabled) return; SetLayoutTextureDirty(); } protected override void OnDidApplyAnimationProperties() { if (!isActiveAndEnabled) return; SetLayoutTextureDirty(); } public void ModifyMesh(Mesh mesh) { if (!isActiveAndEnabled) return; if (SpriteMesh) Utility.SafeDestroy(SpriteMesh); SpriteMesh = Instantiate(mesh); SetLayoutTextureDirty(); } public void ModifyMesh(VertexHelper verts) { if (!isActiveAndEnabled) return; // For when pressing play while in prefab mode if (!SpriteMesh) SpriteMesh = new Mesh(); verts.FillMesh(SpriteMesh); SetLayoutTextureDirty(); } void SetLayoutTextureDirty() { SetLayoutDirty(); SetTextureDirty(); } } }