A game about forced loneliness, made by TACStudios
at master 262 lines 8.9 kB view raw
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}