A game about forced loneliness, made by TACStudios
at master 139 lines 5.1 kB view raw
1using Unity.Burst; 2using Unity.Collections; 3using Unity.Collections.LowLevel.Unsafe; 4using Unity.Mathematics; 5 6namespace UnityEngine.U2D.Animation 7{ 8 [BurstCompile] 9 internal static class MeshUtilities 10 { 11 /// <summary> 12 /// Get the outline edges from a set of indices. 13 /// This method expects the index array to be laid out with one triangle for every 3 indices. 14 /// E.g. triangle 0: index 0 - 2, triangle 1: index 3 - 5, etc. 15 /// </summary> 16 /// <returns>Returns a NativeArray of sorted edges. It is up to the caller to dispose this array.</returns> 17 public static NativeArray<int2> GetOutlineEdges(in NativeArray<ushort> indices) 18 { 19 var edges = new UnsafeHashMap<int, int3>(indices.Length, Allocator.Persistent); 20 21 for (var i = 0; i < indices.Length; i += 3) 22 { 23 var i0 = indices[i]; 24 var i1 = indices[i + 1]; 25 var i2 = indices[i + 2]; 26 27 var edge0 = new int2(i0, i1); 28 var edge1 = new int2(i1, i2); 29 var edge2 = new int2(i2, i0); 30 31 AddToEdgeMap(edge0, ref edges); 32 AddToEdgeMap(edge1, ref edges); 33 AddToEdgeMap(edge2, ref edges); 34 } 35 36#if COLLECTIONS_2_0_OR_ABOVE 37 var outlineEdges = new NativeList<int2>(edges.Count, Allocator.Temp); 38#else 39 var outlineEdges = new NativeList<int2>(edges.Count(), Allocator.Temp); 40#endif 41 foreach (var edgePair in edges) 42 { 43 // If an edge is only used in one triangle, it is an outline edge. 44 if (edgePair.Value.z == 1) 45 outlineEdges.Add(edgePair.Value.xy); 46 } 47 48 edges.Dispose(); 49 50 SortEdges(outlineEdges.AsArray(), out var sortedEdges); 51 return sortedEdges; 52 } 53 54 [BurstCompile] 55 static void AddToEdgeMap(in int2 edge, ref UnsafeHashMap<int, int3> edgeMap) 56 { 57 var tmpEdge = math.min(edge.x, edge.y) == edge.x ? edge.xy : edge.yx; 58 var hashCode = tmpEdge.GetHashCode(); 59 60 // We store the hashCode as key, so that we can do less GetHashCode-calls. 61 // Then we store the count the int3s z-value. 62 if (!edgeMap.ContainsKey(hashCode)) 63 edgeMap[hashCode] = new int3(edge, 1); 64 else 65 { 66 var val = edgeMap[hashCode]; 67 val.z++; 68 edgeMap[hashCode] = val; 69 } 70 } 71 72 [BurstCompile] 73 static void SortEdges(in NativeArray<int2> unsortedEdges, out NativeArray<int2> sortedEdges) 74 { 75 var tmpEdges = new NativeArray<int2>(unsortedEdges.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 76 var shapeStartingEdge = new NativeList<int>(1, Allocator.Persistent); 77 78 var edgeMap = new UnsafeHashMap<int, int>(unsortedEdges.Length, Allocator.Persistent); 79 var usedEdges = new NativeArray<bool>(unsortedEdges.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 80 81 for (var i = 0; i < unsortedEdges.Length; i++) 82 { 83 edgeMap[unsortedEdges[i].x] = i; 84 usedEdges[i] = false; 85 } 86 87 var findStartingEdge = true; 88 var edgeIndex = -1; 89 var startingEdge = 0; 90 for (var i = 0; i < unsortedEdges.Length; i++) 91 { 92 if (findStartingEdge) 93 { 94 edgeIndex = GetFirstUnusedIndex(usedEdges); 95 startingEdge = edgeIndex; 96 findStartingEdge = false; 97 shapeStartingEdge.Add(i); 98 } 99 100 usedEdges[edgeIndex] = true; 101 tmpEdges[i] = unsortedEdges[edgeIndex]; 102 var nextVertex = unsortedEdges[edgeIndex].y; 103 edgeIndex = edgeMap[nextVertex]; 104 105 if (edgeIndex == startingEdge) 106 findStartingEdge = true; 107 } 108 109 var finalEdgeArrLength = unsortedEdges.Length; 110 sortedEdges = new NativeArray<int2>(finalEdgeArrLength, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 111 var count = 0; 112 for (var i = 0; i < shapeStartingEdge.Length; ++i) 113 { 114 var edgeStart = shapeStartingEdge[i]; 115 var edgeEnd = (i + 1) == shapeStartingEdge.Length ? tmpEdges.Length : shapeStartingEdge[i + 1]; 116 117 for (var m = edgeStart; m < edgeEnd; ++m) 118 sortedEdges[count++] = tmpEdges[m]; 119 } 120 121 usedEdges.Dispose(); 122 edgeMap.Dispose(); 123 shapeStartingEdge.Dispose(); 124 tmpEdges.Dispose(); 125 } 126 127 [BurstCompile] 128 static int GetFirstUnusedIndex(in NativeArray<bool> usedValues) 129 { 130 for (var i = 0; i < usedValues.Length; i++) 131 { 132 if (!usedValues[i]) 133 return i; 134 } 135 136 return -1; 137 } 138 } 139}