A game about forced loneliness, made by TACStudios
1using System.Collections.Generic;
2using Unity.Burst;
3using Unity.Collections;
4using Unity.Collections.LowLevel.Unsafe;
5using Unity.Mathematics;
6using UnityEditor.U2D.Common;
7using UnityEngine;
8using UnityEngine.U2D.Animation;
9
10namespace UnityEditor.U2D.Animation
11{
12 [BurstCompile]
13 internal static class BatchedDrawing
14 {
15 class Batch
16 {
17 public UnsafeList<float3> vertices;
18 public UnsafeList<Color> vertexColors;
19 public UnsafeList<int> indices;
20
21 public Batch()
22 {
23 vertices = new UnsafeList<float3>(1, Allocator.Persistent);
24 indices = new UnsafeList<int>(1, Allocator.Persistent);
25 vertexColors = new UnsafeList<Color>(1, Allocator.Persistent);
26 }
27
28 ~Batch()
29 {
30 vertices.Dispose();
31 indices.Dispose();
32 vertexColors.Dispose();
33 }
34
35 public void Clear()
36 {
37 vertices.Clear();
38 indices.Clear();
39 vertexColors.Clear();
40 }
41 }
42
43 // Unity's max index limit for meshes.
44 const int k_MaxIndexLimit = 65535;
45
46 static readonly int s_HandleSize = Shader.PropertyToID("_HandleSize");
47
48 static readonly List<Batch> s_Batches = new List<Batch>(1) { new Batch() };
49 static Mesh s_Mesh;
50 static NativeArray<float3> s_VertexTmpCache = default;
51
52 public static unsafe void RegisterLine(float3 p1, float3 p2, float3 normal, float widthP1, float widthP2, Color color)
53 {
54 var up = math.cross(normal, p2 - p1);
55 up = math.normalize(up);
56
57 const int dataToAdd = 6;
58 var batch = GetBatch(dataToAdd);
59 var startIndex = batch.vertices.Length;
60
61 batch.indices.Resize(startIndex + dataToAdd);
62 batch.vertexColors.Resize(startIndex + dataToAdd);
63 batch.vertices.Resize(startIndex + dataToAdd);
64
65 var vertexPtr = batch.vertices.Ptr;
66 vertexPtr[startIndex] = p1 + up * (widthP1 * 0.5f);
67 vertexPtr[startIndex + 1] = p1 - up * (widthP1 * 0.5f);
68 vertexPtr[startIndex + 2] = p2 - up * (widthP2 * 0.5f);
69 vertexPtr[startIndex + 3] = p1 + up * (widthP1 * 0.5f);
70 vertexPtr[startIndex + 4] = p2 - up * (widthP2 * 0.5f);
71 vertexPtr[startIndex + 5] = p2 + up * (widthP2 * 0.5f);
72
73 for (var i = 0; i < dataToAdd; ++i)
74 {
75 batch.indices.Ptr[startIndex + i] = startIndex + i;
76 batch.vertexColors.Ptr[startIndex + i] = color;
77 }
78 }
79
80 public static void RegisterSolidDisc(float3 center, float3 normal, float radius, Color color)
81 {
82 var from = math.cross(normal, math.up());
83 if (math.lengthsq(from) < 1.0 / 1000.0)
84 from = math.cross(normal, math.right());
85 RegisterSolidArc(center, normal, from, 360f, radius, color);
86 }
87
88 public static unsafe void RegisterSolidArc(float3 center, float3 normal, float3 from, float angle, float radius, Color color, int numSamples = 60)
89 {
90 numSamples = math.clamp(numSamples, 3, 60);
91
92 if (s_VertexTmpCache == default)
93 s_VertexTmpCache = new NativeArray<float3>(60, Allocator.Persistent);
94 SetDiscSectionPoints(ref s_VertexTmpCache, numSamples, in normal, in from, angle);
95
96 var dataToAdd = (numSamples - 1) * 3;
97 var batch = GetBatch(dataToAdd);
98 var startIndex = batch.vertices.Length;
99
100 batch.indices.Resize(startIndex + dataToAdd);
101 batch.vertexColors.Resize(startIndex + dataToAdd);
102 batch.vertices.Resize(startIndex + dataToAdd);
103
104 CreateSolidArcVertices(ref batch.vertices, startIndex, in s_VertexTmpCache, in center, numSamples, radius);
105
106 for (var i = 0; i < dataToAdd; ++i)
107 {
108 batch.indices.Ptr[startIndex + i] = startIndex + i;
109 batch.vertexColors.Ptr[startIndex + i] = color;
110 }
111 }
112
113 [BurstCompile]
114 static void CreateSolidArcVertices(
115 ref UnsafeList<float3> vertexPtr,
116 int startIndex,
117 in NativeArray<float3> vertexCache,
118 in float3 center,
119 int numSamples,
120 float radius)
121 {
122 var count = 0;
123 for (var i = 1; i < numSamples; i++, count += 3)
124 {
125 var index = startIndex + count;
126 vertexPtr[index] = center;
127 vertexPtr[index + 1] = center + vertexCache[i - 1] * radius;
128 vertexPtr[index + 2] = center + vertexCache[i] * radius;
129 }
130 }
131
132 public static unsafe void RegisterSolidArcWithOutline(float3 center, float3 normal, float3 from, float angle,
133 float radius, float outlineScale, Color color, int numSamples = 60)
134 {
135 numSamples = Mathf.Clamp(numSamples, 3, 60);
136
137 if (s_VertexTmpCache == default)
138 s_VertexTmpCache = new NativeArray<float3>(60, Allocator.Persistent);
139 SetDiscSectionPoints(ref s_VertexTmpCache, numSamples, in normal, in from, angle);
140
141 var dataToAdd = (numSamples - 1) * 6;
142 var batch = GetBatch(dataToAdd);
143 var startIndex = batch.vertices.Length;
144
145 batch.indices.Resize(startIndex + dataToAdd);
146 batch.vertexColors.Resize(startIndex + dataToAdd);
147 batch.vertices.Resize(startIndex + dataToAdd);
148
149 // var vertexPtr = batch.vertices.Ptr + startIndex;
150 CreateSolidArcWithOutlineVertices(ref batch.vertices, startIndex, in s_VertexTmpCache, in center, numSamples, outlineScale, radius);
151
152 for (var i = 0; i < dataToAdd; ++i)
153 {
154 batch.indices.Ptr[startIndex + i] = startIndex + i;
155 batch.vertexColors.Ptr[startIndex + i] = color;
156 }
157 }
158
159 [BurstCompile]
160 static void CreateSolidArcWithOutlineVertices(
161 ref UnsafeList<float3> vertexPtr,
162 int startIndex,
163 in NativeArray<float3> vertexCache,
164 in float3 center,
165 int numSamples,
166 float outlineScale,
167 float radius)
168 {
169 var count = 0;
170 for (var i = 1; i < numSamples; i++, count += 6)
171 {
172 var index = startIndex + count;
173 vertexPtr[index] = center + vertexCache[i - 1] * (radius * outlineScale);
174 vertexPtr[index + 1] = center + vertexCache[i - 1] * radius;
175 vertexPtr[index + 2] = center + vertexCache[i] * radius;
176 vertexPtr[index + 3] = center + vertexCache[i - 1] * (radius * outlineScale);
177 vertexPtr[index + 4] = center + vertexCache[i] * radius;
178 vertexPtr[index + 5] = center + vertexCache[i] * (radius * outlineScale);
179 }
180 }
181
182 [BurstCompile]
183 static void SetDiscSectionPoints(ref NativeArray<float3> dest, int count, in float3 normal, in float3 from, float angle)
184 {
185 var angleInRadians = math.degrees(angle / (float)(count - 1));
186 var rotation = quaternion.AxisAngle(normal, angleInRadians);
187
188 var vector = math.normalize(from);
189 for (var i = 0; i < count; i++)
190 {
191 dest[i] = vector;
192 vector = math.mul(rotation, vector);
193 }
194 }
195
196 static Batch GetBatch(int dataToAdd)
197 {
198 for (var i = 0; i < s_Batches.Count; ++i)
199 {
200 if ((s_Batches[i].indices.Length + dataToAdd) < k_MaxIndexLimit)
201 return s_Batches[i];
202 }
203
204 var newBatch = new Batch();
205 s_Batches.Add(newBatch);
206 return newBatch;
207 }
208
209 public static void Draw()
210 {
211 if (s_Batches[0].indices.Length == 0)
212 return;
213 if (Event.current.type != EventType.Repaint)
214 return;
215
216 Shader.SetGlobalFloat(s_HandleSize, 1);
217 InternalEditorBridge.ApplyWireMaterial();
218
219 for (var i = 0; i < s_Batches.Count; ++i)
220 {
221 DrawBatch(s_Batches[i]);
222 s_Batches[i].Clear();
223 }
224
225 s_VertexTmpCache.DisposeIfCreated();
226 s_VertexTmpCache = default;
227 }
228
229 static unsafe void DrawBatch(Batch batch)
230 {
231 var vertexPtr = batch.vertices.Ptr;
232 var indexPtr = batch.indices.Ptr;
233 var vertexColorPtr = batch.vertexColors.Ptr;
234
235 var vertexCount = batch.vertices.Length;
236
237 var vertexArr = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<Vector3>(vertexPtr, vertexCount, batch.vertices.Allocator.ToAllocator);
238 var indexArr = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<int>(indexPtr, vertexCount, batch.indices.Allocator.ToAllocator);
239 var colorArr = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<Color>(vertexColorPtr, vertexCount, batch.vertexColors.Allocator.ToAllocator);
240
241 NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref vertexArr, AtomicSafetyHandle.GetTempUnsafePtrSliceHandle());
242 NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref indexArr, AtomicSafetyHandle.GetTempUnsafePtrSliceHandle());
243 NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref colorArr, AtomicSafetyHandle.GetTempUnsafePtrSliceHandle());
244
245 if (s_Mesh == null)
246 s_Mesh = new Mesh();
247 else
248 s_Mesh.Clear();
249
250 s_Mesh.SetVertices(vertexArr);
251 s_Mesh.SetIndices(indexArr, MeshTopology.Triangles, 0);
252 s_Mesh.SetColors(colorArr);
253 Graphics.DrawMeshNow(s_Mesh, Handles.matrix);
254 }
255 }
256}