A game about forced loneliness, made by TACStudios
at master 266 lines 7.5 kB view raw
1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5namespace UnityEditor.U2D.Animation 6{ 7 internal class TransformCache : SkinningObject, IEnumerable<TransformCache> 8 { 9 [SerializeField] 10 TransformCache m_Parent; 11 [SerializeField] 12 List<TransformCache> m_Children = new List<TransformCache>(); 13 [SerializeField] 14 Vector3 m_LocalPosition; 15 [SerializeField] 16 Quaternion m_LocalRotation = Quaternion.identity; 17 [SerializeField] 18 Vector3 m_LocalScale = Vector3.one; 19 [SerializeField] 20 Matrix4x4 m_LocalToWorldMatrix = Matrix4x4.identity; 21 22 public TransformCache parent => m_Parent; 23 24 public TransformCache[] children => m_Children.ToArray(); 25 26 internal int siblingIndex 27 { 28 get => GetSiblingIndex(); 29 set => SetSiblingIndex(value); 30 } 31 32 public int childCount => m_Children.Count; 33 34 public Vector3 localPosition 35 { 36 get => m_LocalPosition; 37 set 38 { 39 m_LocalPosition = value; 40 Update(); 41 } 42 } 43 44 public Quaternion localRotation 45 { 46 get => m_LocalRotation; 47 set 48 { 49 m_LocalRotation = MathUtility.NormalizeQuaternion(value); 50 Update(); 51 } 52 } 53 54 public Vector3 localScale 55 { 56 get => m_LocalScale; 57 set 58 { 59 m_LocalScale = value; 60 Update(); 61 } 62 } 63 64 public Vector3 position 65 { 66 get => parentMatrix.MultiplyPoint3x4(localPosition); 67 set => localPosition = parentMatrix.inverse.MultiplyPoint3x4(value); 68 } 69 70 public Quaternion rotation 71 { 72 get => GetGlobalRotation(); 73 set => SetGlobalRotation(value); 74 } 75 76 public Vector3 right 77 { 78 get => localToWorldMatrix.MultiplyVector(Vector3.right).normalized; 79 set => MatchDirection(Vector3.right, value); 80 } 81 82 public Vector3 up 83 { 84 get => localToWorldMatrix.MultiplyVector(Vector3.up).normalized; 85 set => MatchDirection(Vector3.up, value); 86 } 87 88 public Vector3 forward 89 { 90 get => localToWorldMatrix.MultiplyVector(Vector3.forward).normalized; 91 set => MatchDirection(Vector3.forward, value); 92 } 93 94 public Matrix4x4 localToWorldMatrix => m_LocalToWorldMatrix; 95 96 public Matrix4x4 worldToLocalMatrix => localToWorldMatrix.inverse; 97 98 Matrix4x4 parentMatrix 99 { 100 get 101 { 102 var matrix = Matrix4x4.identity; 103 if (parent != null) 104 matrix = parent.localToWorldMatrix; 105 return matrix; 106 } 107 } 108 109 internal override void OnDestroy() 110 { 111 if (parent != null) 112 parent.RemoveChild(this); 113 114 m_Parent = null; 115 m_Children.Clear(); 116 } 117 118 void Update() 119 { 120 m_LocalToWorldMatrix = parentMatrix * Matrix4x4.TRS(localPosition, localRotation, localScale); 121 122 foreach (var child in m_Children) 123 child.Update(); 124 } 125 126 void AddChild(TransformCache transform) 127 { 128 m_Children.Add(transform); 129 } 130 131 void InsertChildAt(int index, TransformCache transform) 132 { 133 m_Children.Insert(index, transform); 134 } 135 136 void RemoveChild(TransformCache transform) 137 { 138 m_Children.Remove(transform); 139 } 140 141 void RemoveChildAt(int index) 142 { 143 m_Children.RemoveAt(index); 144 } 145 146 int GetSiblingIndex() 147 { 148 if (parent == null) 149 return -1; 150 151 return parent.m_Children.IndexOf(this); 152 } 153 154 void SetSiblingIndex(int index) 155 { 156 if (parent == null) 157 return; 158 159 var currentIndex = parent.m_Children.IndexOf(this); 160 var indexToRemove = index < currentIndex ? currentIndex + 1 : currentIndex; 161 parent.InsertChildAt(index, this); 162 parent.RemoveChildAt(indexToRemove); 163 } 164 165 public void SetParent(TransformCache newParent, bool worldPositionStays = true) 166 { 167 if (m_Parent == newParent) 168 return; 169 170 var oldPosition = position; 171 var oldRotation = rotation; 172 173 if (m_Parent != null) 174 m_Parent.RemoveChild(this); 175 176 m_Parent = newParent; 177 178 if (m_Parent != null) 179 m_Parent.AddChild(this); 180 181 if (worldPositionStays) 182 { 183 position = oldPosition; 184 rotation = oldRotation; 185 } 186 else 187 { 188 Update(); 189 } 190 } 191 192 Quaternion GetGlobalRotation() 193 { 194 var globalRotation = localRotation; 195 var currentParent = parent; 196 197 while (currentParent != null) 198 { 199 globalRotation = ScaleMulQuaternion(currentParent.localScale, globalRotation); 200 globalRotation = currentParent.localRotation * globalRotation; 201 currentParent = currentParent.parent; 202 } 203 204 return globalRotation; 205 } 206 207 void SetGlobalRotation(Quaternion r) 208 { 209 if (parent != null) 210 r = parent.InverseTransformRotation(r); 211 localRotation = r; 212 } 213 214 Quaternion InverseTransformRotation(Quaternion r) 215 { 216 if (parent != null) 217 r = parent.InverseTransformRotation(r); 218 219 r = Quaternion.Inverse(localRotation) * r; 220 r = ScaleMulQuaternion(localScale, r); 221 222 return r; 223 } 224 225 static Quaternion ScaleMulQuaternion(Vector3 scale, Quaternion q) 226 { 227 var s = new Vector3(ChangeSign(1f, scale.x), ChangeSign(1f, scale.y), ChangeSign(1f, scale.z)); 228 q.x = ChangeSign(q.x, s.y * s.z); 229 q.y = ChangeSign(q.y, s.x * s.z); 230 q.z = ChangeSign(q.z, s.x * s.y); 231 return q; 232 } 233 234 static float ChangeSign(float x, float y) 235 { 236 return y < 0f ? -x : x; 237 } 238 239 void MatchDirection(Vector3 localDirection, Vector3 worldDirection) 240 { 241 var direction = worldToLocalMatrix.MultiplyVector(worldDirection); 242 direction = Matrix4x4.TRS(Vector3.zero, localRotation, localScale).MultiplyVector(direction); 243 var scaledLocalDirection = Vector3.Scale(localDirection, localScale); 244 var deltaRotation = Quaternion.identity; 245 246 if (scaledLocalDirection.sqrMagnitude > 0f) 247 { 248 var axis = Vector3.Cross(scaledLocalDirection, direction); 249 var angle = Vector3.SignedAngle(scaledLocalDirection, direction, axis); 250 deltaRotation = Quaternion.AngleAxis(angle, axis); 251 } 252 253 localRotation = deltaRotation; 254 } 255 256 IEnumerator<TransformCache> IEnumerable<TransformCache>.GetEnumerator() 257 { 258 return m_Children.GetEnumerator(); 259 } 260 261 IEnumerator IEnumerable.GetEnumerator() 262 { 263 return (IEnumerator)m_Children.GetEnumerator(); 264 } 265 } 266}