A game about forced loneliness, made by TACStudios
1using UnityEngine;
2using System;
3using System.Collections.Generic;
4
5namespace UnityEditor.U2D.Animation
6{
7 internal struct BoneWeightData : IComparable<BoneWeightData>
8 {
9 public int boneIndex;
10 public float weight;
11
12 public int CompareTo(BoneWeightData other)
13 {
14 return other.weight.CompareTo(weight);
15 }
16 }
17
18 internal static class EditableBoneWeightUtility
19 {
20 private static List<BoneWeightData> s_BoneWeightDataList = new List<BoneWeightData>();
21 private static EditableBoneWeight s_LerpFirst = new EditableBoneWeight();
22 private static EditableBoneWeight s_LerpSecond = new EditableBoneWeight();
23 private static EditableBoneWeight s_LerpResult = new EditableBoneWeight();
24
25 public static EditableBoneWeight CreateFromBoneWeight(BoneWeight boneWeight)
26 {
27 EditableBoneWeight editableBoneWeight = new EditableBoneWeight();
28
29 editableBoneWeight.SetFromBoneWeight(boneWeight);
30 editableBoneWeight.UnifyChannelsWithSameBoneIndex();
31
32 return editableBoneWeight;
33 }
34
35 public static void SetFromBoneWeight(this EditableBoneWeight editableBoneWeight, BoneWeight boneWeight)
36 {
37 editableBoneWeight.Clamp(4, false);
38
39 while (editableBoneWeight.Count < 4)
40 editableBoneWeight.AddChannel(0, 0f, false);
41
42 for (var i = 0; i < 4; ++i)
43 {
44 var weight = boneWeight.GetWeight(i);
45 editableBoneWeight[i].boneIndex = boneWeight.GetBoneIndex(i);
46 editableBoneWeight[i].weight = weight;
47 editableBoneWeight[i].enabled = weight > 0f;
48 }
49 }
50
51 public static BoneWeight ToBoneWeight(this EditableBoneWeight editableBoneWeight, bool sortByWeight)
52 {
53 var boneWeight = new BoneWeight();
54
55 if (editableBoneWeight.Count > 0)
56 {
57 s_BoneWeightDataList.Clear();
58 s_BoneWeightDataList.Capacity = editableBoneWeight.Count;
59
60 for (var i = 0; i < editableBoneWeight.Count; ++i)
61 {
62 s_BoneWeightDataList.Add(new BoneWeightData()
63 {
64 boneIndex = editableBoneWeight[i].boneIndex,
65 weight = editableBoneWeight[i].weight
66 });
67 }
68
69 if (sortByWeight)
70 s_BoneWeightDataList.Sort();
71
72 var count = Mathf.Min(editableBoneWeight.Count, 4);
73
74 for (var i = 0; i < count; ++i)
75 {
76 BoneWeightExtensions.SetBoneIndex(ref boneWeight, i, s_BoneWeightDataList[i].boneIndex);
77 BoneWeightExtensions.SetWeight(ref boneWeight, i, s_BoneWeightDataList[i].weight);
78 }
79 }
80
81 return boneWeight;
82 }
83
84 public static bool ContainsBoneIndex(this EditableBoneWeight editableBoneWeight, int boneIndex)
85 {
86 return GetChannelFromBoneIndex(editableBoneWeight, boneIndex) > -1;
87 }
88
89 public static int GetChannelFromBoneIndex(this EditableBoneWeight editableBoneWeight, int boneIndex)
90 {
91 for (int i = 0; i < editableBoneWeight.Count; ++i)
92 if (editableBoneWeight[i].enabled && editableBoneWeight[i].boneIndex == boneIndex)
93 return i;
94
95 return -1;
96 }
97
98 public static void Clamp(this EditableBoneWeight editableBoneWeight, int numChannels, bool sortChannels = true)
99 {
100 if (sortChannels)
101 editableBoneWeight.Sort();
102
103 while (editableBoneWeight.Count > numChannels)
104 editableBoneWeight.RemoveChannel(numChannels);
105 }
106
107 public static void ValidateChannels(this EditableBoneWeight editableBoneWeight)
108 {
109 for (int i = 0; i < editableBoneWeight.Count; ++i)
110 {
111 var weight = editableBoneWeight[i].weight;
112
113 if (!editableBoneWeight[i].enabled)
114 weight = 0f;
115
116 weight = Mathf.Clamp01(weight);
117 editableBoneWeight[i].weight = weight;
118 }
119 }
120
121 public static float Sum(this EditableBoneWeight editableBoneWeight)
122 {
123 var sum = 0f;
124
125 for (var i = 0; i < editableBoneWeight.Count; ++i)
126 if (editableBoneWeight[i].enabled)
127 sum += editableBoneWeight[i].weight;
128
129 return sum;
130 }
131
132 public static void Normalize(this EditableBoneWeight editableBoneWeight)
133 {
134 ValidateChannels(editableBoneWeight);
135
136 var sum = editableBoneWeight.Sum();
137
138 if (sum == 0f || sum == 1f)
139 return;
140
141 var sumInv = 1f / sum;
142
143 for (var i = 0; i < editableBoneWeight.Count; ++i)
144 if (editableBoneWeight[i].enabled)
145 editableBoneWeight[i].weight *= sumInv;
146 }
147
148 public static void CompensateOtherChannels(this EditableBoneWeight editableBoneWeight, int masterChannel)
149 {
150 ValidateChannels(editableBoneWeight);
151
152 var validChannelCount = 0;
153 var sum = 0f;
154
155 for (int i = 0; i < editableBoneWeight.Count; ++i)
156 {
157 if (i != masterChannel && editableBoneWeight[i].enabled)
158 {
159 sum += editableBoneWeight[i].weight;
160 ++validChannelCount;
161 }
162 }
163
164 if (validChannelCount == 0)
165 return;
166
167 var targetSum = 1f - editableBoneWeight[masterChannel].weight;
168
169 for (var i = 0; i < editableBoneWeight.Count; ++i)
170 {
171 if (i != masterChannel && editableBoneWeight[i].enabled)
172 {
173 if (sum == 0f)
174 editableBoneWeight[i].weight = targetSum / validChannelCount;
175 else
176 editableBoneWeight[i].weight *= targetSum / sum;
177 }
178 }
179 }
180
181 public static void UnifyChannelsWithSameBoneIndex(this EditableBoneWeight editableBoneWeight)
182 {
183 for (var i = 0; i < editableBoneWeight.Count; ++i)
184 {
185 if (!editableBoneWeight[i].enabled)
186 continue;
187
188 bool weightChanged = false;
189
190 for (var j = i + 1; j < editableBoneWeight.Count; ++j)
191 {
192 if (editableBoneWeight[j].boneIndex == editableBoneWeight[i].boneIndex)
193 {
194 weightChanged = true;
195 editableBoneWeight[i].weight += editableBoneWeight[j].weight;
196 editableBoneWeight[j].enabled = false;
197 }
198 }
199
200 if (weightChanged)
201 editableBoneWeight.CompensateOtherChannels(i);
202 }
203 }
204
205 public static void FilterChannels(this EditableBoneWeight editableBoneWeight, float weightTolerance)
206 {
207 for (var i = 0; i < editableBoneWeight.Count; ++i)
208 {
209 if (editableBoneWeight[i].weight <= weightTolerance)
210 {
211 editableBoneWeight[i].boneIndex = 0;
212 editableBoneWeight[i].weight = 0f;
213 editableBoneWeight[i].enabled = false;
214 }
215 }
216 }
217
218 public static BoneWeight Lerp(BoneWeight first, BoneWeight second, float t)
219 {
220 s_LerpFirst.SetFromBoneWeight(first);
221 s_LerpSecond.SetFromBoneWeight(second);
222 Lerp(s_LerpFirst, s_LerpSecond, ref s_LerpResult, t);
223
224 return s_LerpResult.ToBoneWeight(true);
225 }
226
227 private static void Lerp(EditableBoneWeight first, EditableBoneWeight second, ref EditableBoneWeight result, float t)
228 {
229 result.Clear();
230
231 foreach (BoneWeightChannel channel in first)
232 {
233 if (!channel.enabled)
234 continue;
235
236 var weight = channel.weight * (1f - t);
237
238 if (weight > 0f)
239 result.AddChannel(channel.boneIndex, weight, true);
240 }
241
242 foreach (BoneWeightChannel channel in second)
243 {
244 if (!channel.enabled)
245 continue;
246
247 var weight = channel.weight * t;
248
249 if (weight > 0f)
250 result.AddChannel(channel.boneIndex, weight, true);
251 }
252
253 result.UnifyChannelsWithSameBoneIndex();
254 result.Clamp(4);
255
256 if (result.Sum() > 1f)
257 result.Normalize();
258
259 result.FilterChannels(0f);
260 }
261 }
262}