A game about forced loneliness, made by TACStudios
1using System;
2using UnityEngine;
3
4namespace UnityEditor.U2D.Animation
5{
6 [Serializable]
7 internal struct Pose
8 {
9 public Vector3 position;
10 public Quaternion rotation;
11 public Matrix4x4 matrix => Matrix4x4.TRS(position, rotation, Vector3.one);
12
13 public static Pose Create(Vector3 p, Quaternion r)
14 {
15 var pose = new Pose()
16 {
17 position = p,
18 rotation = r
19 };
20
21 return pose;
22 }
23
24 public override bool Equals(object other)
25 {
26 return other is Pose && this == (Pose)other;
27 }
28
29 public override int GetHashCode()
30 {
31 return position.GetHashCode() ^ rotation.GetHashCode();
32 }
33
34 public static bool operator ==(Pose p1, Pose p2)
35 {
36 return p1.position == p2.position && p1.rotation == p2.rotation;
37 }
38
39 public static bool operator !=(Pose p1, Pose p2)
40 {
41 return !(p1 == p2);
42 }
43 }
44
45 [Serializable]
46 internal struct BonePose
47 {
48 public Pose pose;
49 public float length;
50 public static BonePose Create(Pose p, float l)
51 {
52 var pose = new BonePose()
53 {
54 pose = p,
55 length = l
56 };
57
58 return pose;
59 }
60
61 public override bool Equals(object other)
62 {
63 return other is BonePose && this == (BonePose)other;
64 }
65
66 public override int GetHashCode()
67 {
68 return pose.GetHashCode() ^ length.GetHashCode();
69 }
70
71 public static bool operator ==(BonePose p1, BonePose p2)
72 {
73 return p1.pose == p2.pose && Mathf.Abs(p1.length - p2.length) < Mathf.Epsilon;
74 }
75
76 public static bool operator !=(BonePose p1, BonePose p2)
77 {
78 return !(p1 == p2);
79 }
80 }
81
82 internal class BoneCache : TransformCache
83 {
84 [SerializeField]
85 Color32 m_BindPoseColor;
86 [SerializeField]
87 Pose m_BindPose;
88 [SerializeField]
89 BonePose m_DefaultPose;
90 [SerializeField]
91 BoneCache m_ChainedChild;
92 [SerializeField]
93 float m_Depth;
94 [SerializeField]
95 float m_LocalLength = 1f;
96 [SerializeField]
97 bool m_IsVisible = true;
98 [SerializeField]
99 string m_Guid;
100
101 public bool NotInDefaultPose()
102 {
103 return localPosition != m_DefaultPose.pose.position
104 || localRotation != m_DefaultPose.pose.rotation
105 || Mathf.Abs(localLength - m_DefaultPose.length) > Mathf.Epsilon;
106 }
107
108 public bool isVisible
109 {
110 get => m_IsVisible;
111 set => m_IsVisible = value;
112 }
113
114 public Color bindPoseColor
115 {
116 get => m_BindPoseColor;
117 set => m_BindPoseColor = value;
118 }
119
120 public virtual BoneCache parentBone => parent as BoneCache;
121
122 public SkeletonCache skeleton
123 {
124 get
125 {
126 var parentSkeleton = parent as SkeletonCache;
127 if (parentSkeleton != null)
128 return parentSkeleton;
129
130 return parentBone != null ? parentBone.skeleton : null;
131 }
132 }
133
134 public virtual BoneCache chainedChild
135 {
136 get
137 {
138 if (m_ChainedChild != null && m_ChainedChild.parentBone == this)
139 return m_ChainedChild;
140
141 return null;
142 }
143 set
144 {
145 if (m_ChainedChild != value)
146 {
147 if (value == null || value.parentBone == this)
148 {
149 m_ChainedChild = value;
150 if (m_ChainedChild != null)
151 OrientToChainedChild(false);
152 }
153 }
154 }
155 }
156
157 Vector3 localEndPosition => Vector3.right * localLength;
158
159 public Vector3 endPosition
160 {
161 get => localToWorldMatrix.MultiplyPoint3x4(localEndPosition);
162 set
163 {
164 if (chainedChild != null)
165 return;
166
167 var direction = value - position;
168 right = direction;
169 length = direction.magnitude;
170 }
171 }
172
173 public BonePose localPose
174 {
175 get => BonePose.Create(Pose.Create(localPosition, localRotation), localLength);
176 set
177 {
178 localPosition = value.pose.position;
179 localRotation = value.pose.rotation;
180 localLength = value.length;
181 }
182 }
183
184 public BonePose worldPose
185 {
186 get => BonePose.Create(Pose.Create(position, rotation), length);
187 set
188 {
189 position = value.pose.position;
190 rotation = value.pose.rotation;
191 length = value.length;
192 }
193 }
194
195 public Pose bindPose => m_BindPose;
196
197 public string guid
198 {
199 get => m_Guid;
200 set => m_Guid = value;
201 }
202
203 public float depth
204 {
205 get => m_Depth;
206 set => m_Depth = value;
207 }
208 public float localLength
209 {
210 get => m_LocalLength;
211 set => m_LocalLength = Mathf.Max(0f, value);
212 }
213
214 public float length
215 {
216 get => localToWorldMatrix.MultiplyVector(localEndPosition).magnitude;
217 set => m_LocalLength = worldToLocalMatrix.MultiplyVector(right * Mathf.Max(0f, value)).magnitude;
218 }
219
220 internal Pose[] GetChildrenWoldPose()
221 {
222 return Array.ConvertAll(children, c => Pose.Create(c.position, c.rotation));
223 }
224
225 internal void SetChildrenWorldPose(Pose[] worldPoses)
226 {
227 var childrenArray = children;
228
229 Debug.Assert(childrenArray.Length == worldPoses.Length);
230
231 for (var i = 0; i < childrenArray.Length; ++i)
232 {
233 var child = childrenArray[i];
234 var pose = worldPoses[i];
235
236 child.position = pose.position;
237 child.rotation = pose.rotation;
238 }
239 }
240
241 internal override void OnDestroy()
242 {
243 base.OnDestroy();
244 m_ChainedChild = null;
245 }
246
247 public new void SetParent(TransformCache newParent, bool worldPositionStays = true)
248 {
249 if (parentBone != null && parentBone.chainedChild == this)
250 parentBone.chainedChild = null;
251
252 base.SetParent(newParent, worldPositionStays);
253
254 if (parentBone != null && parentBone.chainedChild == null && (parentBone.endPosition - position).sqrMagnitude < 0.001f)
255 parentBone.chainedChild = this;
256 }
257
258 public void OrientToChainedChild(bool freezeChildren)
259 {
260 Debug.Assert(chainedChild != null);
261
262 var childPosition = chainedChild.position;
263 var childRotation = chainedChild.rotation;
264
265 Pose[] childrenWorldPose = null;
266
267 if (freezeChildren)
268 childrenWorldPose = GetChildrenWoldPose();
269
270 right = childPosition - position;
271
272 if (freezeChildren)
273 {
274 SetChildrenWorldPose(childrenWorldPose);
275 }
276 else
277 {
278 chainedChild.position = childPosition;
279 chainedChild.rotation = childRotation;
280 }
281
282 length = (childPosition - position).magnitude;
283 }
284
285 public void SetDefaultPose()
286 {
287 m_DefaultPose = localPose;
288
289 if (IsUnscaled())
290 m_BindPose = worldPose.pose;
291 else
292 throw new Exception("BindPose cannot be set under global scale");
293 }
294
295 public void RestoreDefaultPose()
296 {
297 localPose = m_DefaultPose;
298 }
299
300 bool IsUnscaled()
301 {
302 var currentTransform = this as TransformCache;
303
304 while (currentTransform != null)
305 {
306 var scale = currentTransform.localScale;
307 var isUnscaled = Mathf.Approximately(scale.x, 1f) && Mathf.Approximately(scale.y, 1f) && Mathf.Approximately(scale.z, 1f);
308
309 if (!isUnscaled)
310 return false;
311
312 currentTransform = currentTransform.parent;
313 }
314
315 return true;
316 }
317 }
318}