A game about forced loneliness, made by TACStudios
at master 433 lines 18 kB view raw
1using System; 2using System.Collections.Generic; 3using Unity.Collections; 4using Unity.Collections.LowLevel.Unsafe; 5using Unity.Jobs; 6using Unity.Mathematics; 7using Unity.Profiling; 8using UnityEngine.U2D.Common; 9 10namespace UnityEngine.U2D.Animation 11{ 12 internal abstract class BaseDeformationSystem 13 { 14 protected static class Profiling 15 { 16 public static readonly ProfilerMarker transformAccessJob = new ProfilerMarker("BaseDeformationSystem.TransformAccessJob"); 17 public static readonly ProfilerMarker getSpriteSkinBatchData = new ProfilerMarker("BaseDeformationSystem.GetSpriteSkinBatchData"); 18 public static readonly ProfilerMarker scheduleJobs = new ProfilerMarker("BaseDeformationSystem.ScheduleJobs"); 19 public static readonly ProfilerMarker setBatchDeformableBufferAndLocalAABB = new ProfilerMarker("BaseDeformationSystem.SetBatchDeformableBufferAndLocalAABB"); 20 public static readonly ProfilerMarker setBoneTransformsArray = new ProfilerMarker("BaseDeformationSystem.SetBoneTransformsArray"); 21 } 22 23 public abstract DeformationMethods deformationMethod { get; } 24 25 protected int m_ObjectId; 26 27 protected readonly HashSet<SpriteSkin> m_SpriteSkins = new HashSet<SpriteSkin>(); 28 protected SpriteRenderer[] m_SpriteRenderers = new SpriteRenderer[0]; 29 30 readonly HashSet<SpriteSkin> m_SpriteSkinsToAdd = new HashSet<SpriteSkin>(); 31 readonly HashSet<SpriteSkin> m_SpriteSkinsToRemove = new HashSet<SpriteSkin>(); 32 readonly List<int> m_TransformIdsToRemove = new List<int>(); 33 34 protected NativeByteArray m_DeformedVerticesBuffer; 35 protected NativeArray<float4x4> m_FinalBoneTransforms; 36 37 protected NativeArray<bool> m_IsSpriteSkinActiveForDeform; 38 protected NativeArray<SpriteSkinData> m_SpriteSkinData; 39 protected NativeArray<PerSkinJobData> m_PerSkinJobData; 40 protected NativeArray<Bounds> m_BoundsData; 41 protected NativeArray<IntPtr> m_Buffers; 42 protected NativeArray<int> m_BufferSizes; 43 protected NativeArray<IntPtr> m_BoneTransformBuffers; 44 45 protected NativeArray<int2> m_BoneLookupData; 46 protected NativeArray<int2> m_VertexLookupData; 47 protected NativeArray<PerSkinJobData> m_SkinBatchArray; 48 49 TransformAccessJob m_LocalToWorldTransformAccessJob; 50 TransformAccessJob m_WorldToLocalTransformAccessJob; 51 52 protected JobHandle m_DeformJobHandle; 53 54 internal void RemoveBoneTransforms(SpriteSkin spriteSkin) 55 { 56 if (!m_SpriteSkins.Contains(spriteSkin)) 57 return; 58 59 m_LocalToWorldTransformAccessJob.RemoveTransformById(spriteSkin.rootBoneTransformId); 60 var boneTransforms = spriteSkin.boneTransformId; 61 if (boneTransforms == default || !boneTransforms.IsCreated) 62 return; 63 64 for (var i = 0; i < boneTransforms.Length; ++i) 65 m_LocalToWorldTransformAccessJob.RemoveTransformById(boneTransforms[i]); 66 } 67 68 internal void AddBoneTransforms(SpriteSkin spriteSkin) 69 { 70 if (!m_SpriteSkins.Contains(spriteSkin)) 71 return; 72 73 m_LocalToWorldTransformAccessJob.AddTransform(spriteSkin.rootBone); 74 if (spriteSkin.boneTransforms != null) 75 { 76 foreach (var t in spriteSkin.boneTransforms) 77 { 78 if (t != null) 79 m_LocalToWorldTransformAccessJob.AddTransform(t); 80 } 81 } 82 } 83 84 internal virtual void UpdateMaterial(SpriteSkin spriteSkin) { } 85 86 internal virtual bool AddSpriteSkin(SpriteSkin spriteSkin) 87 { 88 if (!m_SpriteSkins.Contains(spriteSkin) && !m_SpriteSkinsToAdd.Contains(spriteSkin)) 89 { 90 m_SpriteSkinsToAdd.Add(spriteSkin); 91 return true; 92 } 93 94 if (m_SpriteSkinsToRemove.Contains(spriteSkin)) 95 { 96 m_SpriteSkinsToAdd.Add(spriteSkin); 97 return true; 98 } 99 100 return false; 101 } 102 103 internal void CopyToSpriteSkinData(SpriteSkin spriteSkin) 104 { 105 if (!m_SpriteSkinData.IsCreated) 106 throw new InvalidOperationException("Sprite Skin Data not initialized."); 107 108 var dataIndex = spriteSkin.dataIndex; 109 if(dataIndex < 0 || dataIndex >= m_SpriteSkinData.Length) 110 return; 111 112 var spriteSkinData = default(SpriteSkinData); 113 spriteSkin.CopyToSpriteSkinData(ref spriteSkinData); 114 115 m_SpriteSkinData[dataIndex] = spriteSkinData; 116 m_SpriteRenderers[dataIndex] = spriteSkin.spriteRenderer; 117 } 118 119 internal void RemoveSpriteSkin(SpriteSkin spriteSkin) 120 { 121 if (spriteSkin == null) 122 return; 123 124 if (m_SpriteSkins.Contains(spriteSkin) && !m_SpriteSkinsToRemove.Contains(spriteSkin)) 125 { 126 m_SpriteSkinsToRemove.Add(spriteSkin); 127 m_TransformIdsToRemove.Add(spriteSkin.transform.GetInstanceID()); 128 } 129 130 if (m_SpriteSkinsToAdd.Contains(spriteSkin)) 131 m_SpriteSkinsToAdd.Remove(spriteSkin); 132 133 RemoveBoneTransforms(spriteSkin); 134 } 135 136 internal HashSet<SpriteSkin> GetSpriteSkins() 137 { 138 return m_SpriteSkins; 139 } 140 141 internal void Initialize(int objectId) 142 { 143 m_ObjectId = objectId; 144 145 if (m_LocalToWorldTransformAccessJob == null) 146 m_LocalToWorldTransformAccessJob = new TransformAccessJob(); 147 if (m_WorldToLocalTransformAccessJob == null) 148 m_WorldToLocalTransformAccessJob = new TransformAccessJob(); 149 150 InitializeArrays(); 151 BatchRemoveSpriteSkins(); 152 BatchAddSpriteSkins(); 153 154 // Initialise all existing SpriteSkins as execution order is indeterminate 155 var count = 0; 156 foreach (var spriteSkin in m_SpriteSkins) 157 { 158 spriteSkin.SetDataIndex(count++); 159 160 CopyToSpriteSkinData(spriteSkin); 161 } 162 } 163 164 protected virtual void InitializeArrays() 165 { 166 const int startingCount = 0; 167 168 m_FinalBoneTransforms = new NativeArray<float4x4>(startingCount, Allocator.Persistent); 169 m_BoneLookupData = new NativeArray<int2>(startingCount, Allocator.Persistent); 170 m_VertexLookupData = new NativeArray<int2>(startingCount, Allocator.Persistent); 171 m_SkinBatchArray = new NativeArray<PerSkinJobData>(startingCount, Allocator.Persistent); 172 173 m_IsSpriteSkinActiveForDeform = new NativeArray<bool>(startingCount, Allocator.Persistent); 174 m_PerSkinJobData = new NativeArray<PerSkinJobData>(startingCount, Allocator.Persistent); 175 m_SpriteSkinData = new NativeArray<SpriteSkinData>(startingCount, Allocator.Persistent); 176 m_BoundsData = new NativeArray<Bounds>(startingCount, Allocator.Persistent); 177 m_Buffers = new NativeArray<IntPtr>(startingCount, Allocator.Persistent); 178 m_BufferSizes = new NativeArray<int>(startingCount, Allocator.Persistent); 179 } 180 181 protected void BatchRemoveSpriteSkins() 182 { 183 var spritesToRemoveCount = m_SpriteSkinsToRemove.Count; 184 if (spritesToRemoveCount == 0) 185 return; 186 187 m_WorldToLocalTransformAccessJob.RemoveTransformsByIds(m_TransformIdsToRemove); 188 189 var updatedCount = Math.Max(m_SpriteSkins.Count - spritesToRemoveCount, 0); 190 if (updatedCount == 0) 191 { 192 m_SpriteSkins.Clear(); 193 } 194 else 195 { 196 foreach (var spriteSkin in m_SpriteSkinsToRemove) 197 m_SpriteSkins.Remove(spriteSkin); 198 } 199 200 var count = 0; 201 foreach (var spriteSkin in m_SpriteSkins) 202 { 203 spriteSkin.SetDataIndex(count++); 204 CopyToSpriteSkinData(spriteSkin); 205 } 206 207 Array.Resize(ref m_SpriteRenderers, updatedCount); 208 ResizeAndCopyArrays(updatedCount); 209 210 m_TransformIdsToRemove.Clear(); 211 m_SpriteSkinsToRemove.Clear(); 212 } 213 214 protected void BatchAddSpriteSkins() 215 { 216 if (m_SpriteSkinsToAdd.Count == 0) 217 return; 218 219 if (!m_IsSpriteSkinActiveForDeform.IsCreated) 220 throw new InvalidOperationException("SpriteSkinActiveForDeform not initialized."); 221 222 var updatedCount = m_SpriteSkins.Count + m_SpriteSkinsToAdd.Count; 223 Array.Resize(ref m_SpriteRenderers, updatedCount); 224 ResizeAndCopyArrays(updatedCount); 225 226 foreach (var spriteSkin in m_SpriteSkinsToAdd) 227 { 228 if (m_SpriteSkins.Contains(spriteSkin)) 229 { 230 Debug.LogError($"Skin already exists! Name={spriteSkin.name}"); 231 continue; 232 } 233 234 m_SpriteSkins.Add(spriteSkin); 235 UpdateMaterial(spriteSkin); 236 var count = m_SpriteSkins.Count; 237 238 m_SpriteRenderers[count - 1] = spriteSkin.spriteRenderer; 239 m_WorldToLocalTransformAccessJob.AddTransform(spriteSkin.transform); 240 241 AddBoneTransforms(spriteSkin); 242 243 spriteSkin.SetDataIndex(count - 1); 244 CopyToSpriteSkinData(spriteSkin); 245 } 246 247 m_SpriteSkinsToAdd.Clear(); 248 } 249 250 protected virtual void ResizeAndCopyArrays(int updatedCount) 251 { 252 NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_IsSpriteSkinActiveForDeform, updatedCount); 253 NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_PerSkinJobData, updatedCount); 254 NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_Buffers, updatedCount); 255 NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_BufferSizes, updatedCount); 256 NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_SpriteSkinData, updatedCount); 257 NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_BoundsData, updatedCount); 258 } 259 260 internal virtual void Cleanup() 261 { 262 m_DeformJobHandle.Complete(); 263 264 m_SpriteSkins.Clear(); 265 m_SpriteRenderers = new SpriteRenderer[0]; 266 BufferManager.instance.ReturnBuffer(m_ObjectId); 267 m_IsSpriteSkinActiveForDeform.DisposeIfCreated(); 268 m_PerSkinJobData.DisposeIfCreated(); 269 m_Buffers.DisposeIfCreated(); 270 m_BufferSizes.DisposeIfCreated(); 271 m_SpriteSkinData.DisposeIfCreated(); 272 m_BoneLookupData.DisposeIfCreated(); 273 m_VertexLookupData.DisposeIfCreated(); 274 m_SkinBatchArray.DisposeIfCreated(); 275 m_FinalBoneTransforms.DisposeIfCreated(); 276 m_BoundsData.DisposeIfCreated(); 277 278 m_LocalToWorldTransformAccessJob.Destroy(); 279 m_WorldToLocalTransformAccessJob.Destroy(); 280 } 281 282 internal abstract void Update(); 283 284 protected void PrepareDataForDeformation(out JobHandle localToWorldJobHandle, out JobHandle worldToLocalJobHandle) 285 { 286 ValidateSpriteSkinData(); 287 288 using (Profiling.transformAccessJob.Auto()) 289 { 290 localToWorldJobHandle = m_LocalToWorldTransformAccessJob.StartLocalToWorldJob(); 291 worldToLocalJobHandle = m_WorldToLocalTransformAccessJob.StartWorldToLocalJob(); 292 } 293 294 using (Profiling.getSpriteSkinBatchData.Auto()) 295 { 296 NativeArrayHelpers.ResizeIfNeeded(ref m_SkinBatchArray, 1); 297 var fillPerSkinJobSingleThread = new FillPerSkinJobSingleThread() 298 { 299 isSpriteSkinValidForDeformArray = m_IsSpriteSkinActiveForDeform, 300 combinedSkinBatchArray = m_SkinBatchArray, 301 spriteSkinDataArray = m_SpriteSkinData, 302 perSkinJobDataArray = m_PerSkinJobData, 303 }; 304 fillPerSkinJobSingleThread.Run(); 305 } 306 } 307 308 void ValidateSpriteSkinData() 309 { 310 foreach (var spriteSkin in m_SpriteSkins) 311 { 312 var index = spriteSkin.dataIndex; 313 m_IsSpriteSkinActiveForDeform[index] = spriteSkin.BatchValidate(); 314 if (m_IsSpriteSkinActiveForDeform[index] && spriteSkin.NeedToUpdateDeformationCache()) 315 CopyToSpriteSkinData(spriteSkin); 316 } 317 } 318 319 protected bool GotVerticesToDeform(out int vertexBufferSize) 320 { 321 vertexBufferSize = m_SkinBatchArray[0].deformVerticesStartPos; 322 return vertexBufferSize > 0; 323 } 324 325 protected JobHandle SchedulePrepareJob(int batchCount) 326 { 327 var prepareJob = new PrepareDeformJob 328 { 329 batchDataSize = batchCount, 330 perSkinJobData = m_PerSkinJobData, 331 boneLookupData = m_BoneLookupData, 332 vertexLookupData = m_VertexLookupData 333 }; 334 return prepareJob.Schedule(); 335 } 336 337 protected JobHandle ScheduleBoneJobBatched(JobHandle jobHandle, PerSkinJobData skinBatch) 338 { 339 var boneJobBatched = new BoneDeformBatchedJob() 340 { 341 boneTransform = m_LocalToWorldTransformAccessJob.transformMatrix, 342 rootTransform = m_WorldToLocalTransformAccessJob.transformMatrix, 343 spriteSkinData = m_SpriteSkinData, 344 boneLookupData = m_BoneLookupData, 345 finalBoneTransforms = m_FinalBoneTransforms, 346 rootTransformIndex = m_WorldToLocalTransformAccessJob.transformData, 347 boneTransformIndex = m_LocalToWorldTransformAccessJob.transformData 348 }; 349 jobHandle = boneJobBatched.Schedule(skinBatch.bindPosesIndex.y, 8, jobHandle); 350 return jobHandle; 351 } 352 353 protected JobHandle ScheduleSkinDeformBatchedJob(JobHandle jobHandle, PerSkinJobData skinBatch) 354 { 355 var skinJobBatched = new SkinDeformBatchedJob() 356 { 357 vertices = m_DeformedVerticesBuffer.array, 358 vertexLookupData = m_VertexLookupData, 359 spriteSkinData = m_SpriteSkinData, 360 perSkinJobData = m_PerSkinJobData, 361 finalBoneTransforms = m_FinalBoneTransforms, 362 }; 363 return skinJobBatched.Schedule(skinBatch.verticesIndex.y, 16, jobHandle); 364 } 365 366 protected unsafe JobHandle ScheduleCopySpriteRendererBuffersJob(JobHandle jobHandle, int batchCount) 367 { 368 var copySpriteRendererBuffersJob = new CopySpriteRendererBuffersJob() 369 { 370 isSpriteSkinValidForDeformArray = m_IsSpriteSkinActiveForDeform, 371 spriteSkinData = m_SpriteSkinData, 372 ptrVertices = (IntPtr)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(m_DeformedVerticesBuffer.array), 373 buffers = m_Buffers, 374 bufferSizes = m_BufferSizes, 375 }; 376 return copySpriteRendererBuffersJob.Schedule(batchCount, 16, jobHandle); 377 } 378 379 protected JobHandle ScheduleCalculateSpriteSkinAABBJob(JobHandle jobHandle, int batchCount) 380 { 381 var updateBoundJob = new CalculateSpriteSkinAABBJob 382 { 383 vertices = m_DeformedVerticesBuffer.array, 384 isSpriteSkinValidForDeformArray = m_IsSpriteSkinActiveForDeform, 385 spriteSkinData = m_SpriteSkinData, 386 bounds = m_BoundsData, 387 }; 388 return updateBoundJob.Schedule(batchCount, 4, jobHandle); 389 } 390 391 protected void DeactivateDeformableBuffers() 392 { 393 for (var i = 0; i < m_IsSpriteSkinActiveForDeform.Length; ++i) 394 { 395 if (m_IsSpriteSkinActiveForDeform[i] || InternalEngineBridge.IsUsingDeformableBuffer(m_SpriteRenderers[i], IntPtr.Zero)) 396 continue; 397 m_SpriteRenderers[i].DeactivateDeformableBuffer(); 398 } 399 } 400 401 internal bool IsSpriteSkinActiveForDeformation(SpriteSkin spriteSkin) 402 { 403 return m_IsSpriteSkinActiveForDeform[spriteSkin.dataIndex]; 404 } 405 406 internal unsafe NativeArray<byte> GetDeformableBufferForSpriteSkin(SpriteSkin spriteSkin) 407 { 408 if (!m_SpriteSkins.Contains(spriteSkin)) 409 return default; 410 411 if (!m_DeformJobHandle.IsCompleted) 412 m_DeformJobHandle.Complete(); 413 414 var skinData = m_SpriteSkinData[spriteSkin.dataIndex]; 415 if (skinData.deformVerticesStartPos < 0) 416 return default; 417 418 var vertexBufferLength = skinData.spriteVertexCount * skinData.spriteVertexStreamSize; 419 var ptrVertices = (byte*)m_DeformedVerticesBuffer.array.GetUnsafeReadOnlyPtr(); 420 ptrVertices += skinData.deformVerticesStartPos; 421 var buffer = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>(ptrVertices, vertexBufferLength, Allocator.None); 422#if ENABLE_UNITY_COLLECTIONS_CHECKS 423 NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref buffer, NativeArrayUnsafeUtility.GetAtomicSafetyHandle(m_DeformedVerticesBuffer.array)); 424#endif 425 return buffer; 426 } 427 428#if UNITY_INCLUDE_TESTS 429 internal TransformAccessJob GetWorldToLocalTransformAccessJob() => m_WorldToLocalTransformAccessJob; 430 internal TransformAccessJob GetLocalToWorldTransformAccessJob() => m_LocalToWorldTransformAccessJob; 431#endif 432 } 433}