A game about forced loneliness, made by TACStudios
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}