com.wallstop-studios.unity-helpers 2.0.0-rc73.1 → 2.0.0-rc73.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/Editor/AnimationCopier.cs +58 -50
  2. package/Editor/AnimationCreator.cs +24 -24
  3. package/Editor/AnimationEventEditor.cs +11 -23
  4. package/Editor/FitTextureSizeWindow.cs +9 -9
  5. package/Editor/PrefabChecker.cs +12 -18
  6. package/Editor/SpriteAtlasGenerator.cs +47 -66
  7. package/Editor/SpriteCropper.cs +157 -131
  8. package/Editor/SpriteSettingsApplier.cs +5 -3
  9. package/Editor/Utils/GUIIndentScope.cs +20 -0
  10. package/Editor/Utils/GUIIndentScope.cs.meta +3 -0
  11. package/Runtime/Core/DataStructure/Circle.cs +1 -1
  12. package/Runtime/Core/DataStructure/QuadTree.cs +4 -4
  13. package/Runtime/Core/Extension/ColorExtensions.cs +5 -5
  14. package/Runtime/Core/Extension/IEnumerableExtensions.cs +1 -1
  15. package/Runtime/Core/Extension/UnityExtensions.cs +14 -14
  16. package/Runtime/Core/Helper/Helpers.cs +9 -9
  17. package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs +31 -8
  18. package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +2 -2
  19. package/Runtime/Core/Helper/PathHelper.cs +15 -0
  20. package/Runtime/Core/Helper/PathHelper.cs.meta +3 -0
  21. package/Runtime/Core/Random/DotNetRandom.cs +1 -1
  22. package/Runtime/Core/Random/SplitMix64.cs +1 -1
  23. package/Runtime/Core/Random/SquirrelRandom.cs +7 -7
  24. package/Runtime/Core/Random/ThreadLocalRandom.cs +1 -1
  25. package/Runtime/Core/Random/WyRandom.cs +1 -1
  26. package/Runtime/Tags/AttributeEffect.cs +1 -0
  27. package/Runtime/Tags/EffectHandler.cs +1 -1
  28. package/Runtime/UI/LayeredImage.cs +309 -161
  29. package/Runtime/Utils/AnimatorEnumStateMachine.cs +1 -1
  30. package/Runtime/Utils/SetTextureImportData.cs +1 -1
  31. package/Runtime/Utils/TextureScale.cs +4 -4
  32. package/Styles/Elements/Progress/ArcedProgressBar.cs +345 -0
  33. package/Styles/Elements/Progress/ArcedProgressBar.cs.meta +3 -0
  34. package/Styles/Elements/Progress/CircularProgressBar.cs +307 -0
  35. package/Styles/Elements/Progress/CircularProgressBar.cs.meta +3 -0
  36. package/Styles/Elements/Progress/GlitchProgressBar.cs +416 -0
  37. package/Styles/Elements/Progress/GlitchProgressBar.cs.meta +3 -0
  38. package/Styles/Elements/Progress/LiquidProgressBar.cs +632 -0
  39. package/Styles/Elements/Progress/LiquidProgressBar.cs.meta +3 -0
  40. package/Styles/Elements/Progress/MarchingAntsProgressBar.cs +722 -0
  41. package/Styles/Elements/Progress/MarchingAntsProgressBar.cs.meta +3 -0
  42. package/Styles/Elements/Progress/RegularProgressBar.cs +405 -0
  43. package/Styles/Elements/Progress/RegularProgressBar.cs.meta +3 -0
  44. package/Styles/Elements/Progress/WigglyProgressBar.cs +837 -0
  45. package/Styles/Elements/Progress/WigglyProgressBar.cs.meta +3 -0
  46. package/Styles/Elements/Progress.meta +3 -0
  47. package/Styles/Elements.meta +3 -0
  48. package/Styles/USS/ArcedProgressBar.uss +19 -0
  49. package/Styles/USS/ArcedProgressBar.uss.meta +3 -0
  50. package/Styles/USS/CirclularProgressBar.uss +18 -0
  51. package/Styles/USS/CirclularProgressBar.uss.meta +3 -0
  52. package/Styles/USS/RegularProgressBar.uss +33 -0
  53. package/Styles/USS/RegularProgressBar.uss.meta +3 -0
  54. package/Styles/USS/WigglyProgressBar.uss +17 -0
  55. package/Styles/USS/WigglyProgressBar.uss.meta +3 -0
  56. package/Styles/USS.meta +3 -0
  57. package/Styles/WallstopStudios.UnityHelpers.Styles.asmdef +17 -0
  58. package/Styles/WallstopStudios.UnityHelpers.Styles.asmdef.meta +7 -0
  59. package/Styles.meta +3 -0
  60. package/package.json +11 -1
@@ -18,13 +18,13 @@
18
18
  {
19
19
  public const float FrameRate = 12f;
20
20
 
21
- public readonly Vector2[] offsets;
21
+ public readonly Vector2[] perFramePixelOffsets;
22
22
  public readonly Sprite[] frames;
23
23
  public readonly float alpha;
24
24
 
25
25
  public AnimatedSpriteLayer(
26
26
  IEnumerable<Sprite> sprites,
27
- IEnumerable<Vector2> offsets,
27
+ IEnumerable<Vector2> worldSpaceOffsets = null,
28
28
  float alpha = 1
29
29
  )
30
30
  {
@@ -37,21 +37,45 @@
37
37
  }
38
38
 
39
39
  frame.texture.MakeReadable();
40
+ try
41
+ {
42
+ frame.texture.GetPixel(0, 0);
43
+ }
44
+ catch (UnityException e)
45
+ {
46
+ Debug.LogError(
47
+ $"Texture '{frame.texture.name}' for sprite '{frame.name}' is not readable. Please enable Read/Write in its import settings. Error: {e.Message}"
48
+ );
49
+ }
50
+ }
51
+
52
+ if (worldSpaceOffsets != null && frames is { Length: > 0 })
53
+ {
54
+ perFramePixelOffsets = worldSpaceOffsets
55
+ .Zip(
56
+ frames,
57
+ (offset, frame) =>
58
+ frame != null && frame.pixelsPerUnit > 0
59
+ ? frame.pixelsPerUnit * offset
60
+ : Vector2.zero
61
+ )
62
+ .ToArray();
63
+ Debug.Assert(
64
+ perFramePixelOffsets.Length == frames.Length,
65
+ $"Expected {frames.Length} sprite frames to match {perFramePixelOffsets.Length} offsets after processing."
66
+ );
67
+ }
68
+ else
69
+ {
70
+ perFramePixelOffsets = null;
40
71
  }
41
72
 
42
- this.offsets =
43
- offsets?.Zip(frames, (offset, frame) => frame.pixelsPerUnit * offset).ToArray()
44
- ?? Array.Empty<Vector2>();
45
- Debug.Assert(
46
- this.offsets.Length == frames.Length,
47
- $"Expected {frames.Length} to match {this.offsets.Length}"
48
- );
49
73
  this.alpha = Mathf.Clamp01(alpha);
50
74
  }
51
75
 
52
76
  public AnimatedSpriteLayer(
53
77
  AnimationClip clip,
54
- IEnumerable<Vector2> offsets,
78
+ IEnumerable<Vector2> worldSpaceOffsets = null,
55
79
  float alpha = 1
56
80
  )
57
81
  : this(
@@ -60,7 +84,7 @@
60
84
  #else
61
85
  Enumerable.Empty<Sprite>(),
62
86
  #endif
63
- offsets, alpha) { }
87
+ worldSpaceOffsets, alpha) { }
64
88
  }
65
89
 
66
90
  public sealed class LayeredImage : VisualElement
@@ -68,7 +92,6 @@
68
92
  private readonly AnimatedSpriteLayer[] _layers;
69
93
  private readonly Texture2D[] _computed;
70
94
  private readonly Color _backgroundColor;
71
-
72
95
  private readonly Rect? _largestArea;
73
96
 
74
97
  public LayeredImage(
@@ -81,51 +104,74 @@
81
104
  _backgroundColor = backgroundColor ?? Color.white;
82
105
  _computed = ComputeTextures().ToArray();
83
106
  _largestArea = null;
84
- foreach (Texture2D computed in _computed)
107
+
108
+ foreach (Texture2D? computedTexture in _computed)
85
109
  {
110
+ if (computedTexture == null)
111
+ {
112
+ continue;
113
+ }
114
+
86
115
  if (_largestArea == null)
87
116
  {
88
- _largestArea = new Rect(0, 0, computed.width, computed.height);
117
+ _largestArea = new Rect(0, 0, computedTexture.width, computedTexture.height);
89
118
  }
90
119
  else
91
120
  {
92
- Rect largestArea = _largestArea.Value;
93
- largestArea.width = Mathf.Max(largestArea.width, computed.width);
94
- largestArea.height = Mathf.Max(largestArea.height, computed.height);
95
- _largestArea = largestArea;
121
+ Rect currentLargest = _largestArea.Value;
122
+ currentLargest.width = Mathf.Max(currentLargest.width, computedTexture.width);
123
+ currentLargest.height = Mathf.Max(
124
+ currentLargest.height,
125
+ computedTexture.height
126
+ );
127
+ _largestArea = currentLargest;
96
128
  }
97
129
  }
98
130
 
99
131
  Render(0);
100
- float fpsMs = 1000f / fps;
101
- if (1 < _computed.Length)
132
+
133
+ if (_computed.Length > 1 && fps > 0)
102
134
  {
103
135
  #if UNITY_EDITOR
104
136
  if (!Application.isPlaying)
105
137
  {
106
138
  TimeSpan lastTick = TimeSpan.Zero;
107
- TimeSpan fpsSpan = TimeSpan.FromMilliseconds(fpsMs);
139
+ TimeSpan fpsSpan = TimeSpan.FromMilliseconds(1000f / fps);
108
140
  int index = 0;
109
141
  Stopwatch timer = Stopwatch.StartNew();
110
- EditorApplication.update += () =>
142
+ EditorApplication.update += Tick;
143
+ return;
144
+
145
+ void Tick()
111
146
  {
147
+ if (panel == null)
148
+ {
149
+ EditorApplication.update -= Tick;
150
+ return;
151
+ }
112
152
  TimeSpan elapsed = timer.Elapsed;
113
- if (lastTick + fpsSpan < elapsed)
153
+ if (lastTick + fpsSpan >= elapsed)
114
154
  {
115
- index = index.WrappedIncrement(_computed.Length);
116
- lastTick = elapsed;
117
- Render(index);
155
+ return;
118
156
  }
119
- };
120
- return;
121
- }
122
157
 
158
+ index = index.WrappedIncrement(_computed.Length);
159
+ lastTick = elapsed;
160
+ Render(index);
161
+ }
162
+ }
123
163
  #endif
164
+ if (Application.isPlaying && CoroutineHandler.Instance != null)
124
165
  {
125
166
  int index = 0;
126
167
  CoroutineHandler.Instance.StartFunctionAsCoroutine(
127
168
  () =>
128
169
  {
170
+ if (panel == null)
171
+ {
172
+ return;
173
+ }
174
+
129
175
  index = index.WrappedIncrement(_computed.Length);
130
176
  Render(index);
131
177
  },
@@ -137,6 +183,11 @@
137
183
 
138
184
  private void Render(int index)
139
185
  {
186
+ if (index < 0 || index >= _computed.Length)
187
+ {
188
+ return;
189
+ }
190
+
140
191
  Texture2D computed = _computed[index];
141
192
  if (computed != null)
142
193
  {
@@ -144,205 +195,303 @@
144
195
  style.width = computed.width;
145
196
  style.height = computed.height;
146
197
  }
198
+ else
199
+ {
200
+ style.backgroundImage = null;
201
+ style.width = _largestArea?.width ?? 0;
202
+ style.height = _largestArea?.height ?? 0;
203
+ }
147
204
 
148
205
  style.marginRight = 0;
149
206
  style.marginBottom = 0;
150
- if (_largestArea != null)
207
+ if (_largestArea == null)
151
208
  {
152
- Rect largestArea = _largestArea.Value;
153
- if (style.width.value.value < largestArea.width)
154
- {
155
- style.marginRight = largestArea.width - style.width.value.value;
156
- }
209
+ return;
210
+ }
157
211
 
158
- if (style.height.value.value < largestArea.height)
159
- {
160
- style.marginBottom = largestArea.height - style.height.value.value;
161
- }
212
+ Rect largestAreaRect = _largestArea.Value;
213
+ float currentWidth = computed != null ? computed.width : _largestArea?.width ?? 0;
214
+ float currentHeight = computed != null ? computed.height : _largestArea?.height ?? 0;
215
+
216
+ if (currentWidth < largestAreaRect.width)
217
+ {
218
+ style.marginRight = largestAreaRect.width - currentWidth;
219
+ }
220
+ if (currentHeight < largestAreaRect.height)
221
+ {
222
+ style.marginBottom = largestAreaRect.height - currentHeight;
162
223
  }
163
224
  }
164
225
 
165
- private IEnumerable<Texture2D> ComputeTextures()
226
+ private IEnumerable<Texture2D?> ComputeTextures()
166
227
  {
167
228
  const float pixelCutoff = 0.01f;
168
- int frameCount = _layers.Select(layer => layer.frames.Length).Distinct().Single();
229
+ if (_layers is not { Length: > 0 })
230
+ {
231
+ yield break;
232
+ }
233
+
234
+ int frameCount = 0;
235
+ foreach (AnimatedSpriteLayer layer in _layers)
236
+ {
237
+ if (layer.frames != null)
238
+ {
239
+ frameCount = Mathf.Max(frameCount, layer.frames.Length);
240
+ }
241
+ }
242
+ if (frameCount == 0)
243
+ {
244
+ yield break;
245
+ }
169
246
 
170
- Color transparent = Color.clear;
171
247
  for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex)
172
248
  {
173
- int minX = int.MaxValue;
174
- int maxX = int.MinValue;
175
- int minY = int.MaxValue;
176
- int maxY = int.MinValue;
249
+ float overallMinX = float.MaxValue;
250
+ float overallMaxX = float.MinValue;
251
+ float overallMinY = float.MaxValue;
252
+ float overallMaxY = float.MinValue;
253
+ bool hasVisibleSpriteThisFrame = false;
254
+
177
255
  foreach (AnimatedSpriteLayer layer in _layers)
178
256
  {
179
- if (layer.frames.Length <= 0)
257
+ if (layer.frames == null || frameIndex >= layer.frames.Length)
180
258
  {
181
259
  continue;
182
260
  }
183
261
 
184
262
  Sprite sprite = layer.frames[frameIndex];
185
- Vector2 offset = layer.offsets[frameIndex];
186
- Rect spriteRect = sprite.rect;
187
-
188
- int left = Mathf.RoundToInt(offset.x + spriteRect.xMin);
189
- int right = Mathf.RoundToInt(offset.x + spriteRect.xMax);
190
- int bottom = Mathf.RoundToInt(offset.y + spriteRect.yMin);
191
- int top = Mathf.RoundToInt(offset.y + spriteRect.yMax);
192
-
193
- minX = Mathf.Min(minX, left);
194
- maxX = Mathf.Max(maxX, right);
195
- minY = Mathf.Min(minY, bottom);
196
- maxY = Mathf.Max(maxY, top);
263
+ if (sprite == null)
264
+ {
265
+ continue;
266
+ }
267
+
268
+ hasVisibleSpriteThisFrame = true;
269
+ Rect spriteGeomRect = sprite.rect;
270
+ Vector2 pivot = sprite.pivot;
271
+
272
+ Vector2 additionalPixelOffset = Vector2.zero;
273
+ if (
274
+ layer.perFramePixelOffsets != null
275
+ && frameIndex < layer.perFramePixelOffsets.Length
276
+ )
277
+ {
278
+ additionalPixelOffset = layer.perFramePixelOffsets[frameIndex];
279
+ }
280
+
281
+ float spriteWorldMinX = -pivot.x + additionalPixelOffset.x;
282
+ float spriteWorldMaxX =
283
+ spriteGeomRect.width - pivot.x + additionalPixelOffset.x;
284
+ float spriteWorldMinY = -pivot.y + additionalPixelOffset.y;
285
+ float spriteWorldMaxY =
286
+ spriteGeomRect.height - pivot.y + additionalPixelOffset.y;
287
+
288
+ overallMinX = Mathf.Min(overallMinX, spriteWorldMinX);
289
+ overallMaxX = Mathf.Max(overallMaxX, spriteWorldMaxX);
290
+ overallMinY = Mathf.Min(overallMinY, spriteWorldMinY);
291
+ overallMaxY = Mathf.Max(overallMaxY, spriteWorldMaxY);
292
+ }
293
+
294
+ if (!hasVisibleSpriteThisFrame)
295
+ {
296
+ yield return null;
297
+ continue;
197
298
  }
198
299
 
199
- if (minX == int.MaxValue)
300
+ int compositeBufferOriginX = Mathf.FloorToInt(overallMinX);
301
+ int compositeBufferOriginY = Mathf.FloorToInt(overallMinY);
302
+ int compositeBufferWidth = Mathf.CeilToInt(overallMaxX) - compositeBufferOriginX;
303
+ int compositeBufferHeight = Mathf.CeilToInt(overallMaxY) - compositeBufferOriginY;
304
+
305
+ if (compositeBufferWidth <= 0 || compositeBufferHeight <= 0)
200
306
  {
307
+ yield return null;
201
308
  continue;
202
309
  }
203
310
 
204
- // Calculate the width and height of the non-transparent region
205
- int width = maxX - minX + 1;
206
- int height = maxY - minY + 1;
311
+ Color[] bufferPixels = new Color[compositeBufferWidth * compositeBufferHeight];
207
312
 
208
- Color[] pixels = new Color[width * height];
209
- Array.Fill(pixels, Color.clear);
313
+ Array.Fill(bufferPixels, Color.clear);
210
314
 
211
315
  foreach (AnimatedSpriteLayer layer in _layers)
212
316
  {
213
- if (layer.frames.Length <= 0)
317
+ if (layer.frames == null || frameIndex >= layer.frames.Length)
214
318
  {
215
319
  continue;
216
320
  }
217
321
 
218
322
  Sprite sprite = layer.frames[frameIndex];
219
- Vector2 offset = layer.offsets[frameIndex];
220
- float alpha = layer.alpha;
221
- int offsetX = Mathf.RoundToInt(offset.x);
222
- int offsetY = Mathf.RoundToInt(offset.y);
223
- Texture2D texture = sprite.texture;
224
- Rect spriteRect = sprite.rect;
225
-
226
- int spriteX = Mathf.RoundToInt(spriteRect.xMin);
227
- int spriteWidth = Mathf.RoundToInt(spriteRect.width);
228
- int spriteY = Mathf.RoundToInt(spriteRect.yMin);
229
- int spriteHeight = Mathf.RoundToInt(spriteRect.height);
230
- Color[] spritePixels = texture.GetPixels(
231
- spriteX,
232
- spriteY,
233
- spriteWidth,
234
- spriteHeight
235
- );
323
+ if (sprite == null)
324
+ {
325
+ continue;
326
+ }
236
327
 
237
- Parallel.For(
238
- 0,
239
- spritePixels.Length,
240
- inIndex =>
241
- {
242
- int x = inIndex % spriteWidth;
243
- int y = inIndex / spriteWidth;
328
+ float layerAlpha = layer.alpha;
329
+ Texture2D spriteTexture = sprite.texture;
330
+ Rect spriteGeomRect = sprite.rect;
331
+ Vector2 pivot = sprite.pivot;
244
332
 
245
- Color pixelColor = spritePixels[inIndex];
246
- if (pixelColor.a < pixelCutoff)
247
- {
248
- return;
249
- }
333
+ Vector2 additionalPixelOffset = Vector2.zero;
334
+ if (
335
+ layer.perFramePixelOffsets != null
336
+ && frameIndex < layer.perFramePixelOffsets.Length
337
+ )
338
+ {
339
+ additionalPixelOffset = layer.perFramePixelOffsets[frameIndex];
340
+ }
250
341
 
251
- int textureX = (-1 * minX) + offsetX + x + spriteX;
252
- int textureY = (-1 * minY) + offsetY + y + spriteY;
253
- int index = textureY * width + textureX;
342
+ int spriteRectX = Mathf.FloorToInt(spriteGeomRect.x);
343
+ int spriteRectY = Mathf.FloorToInt(spriteGeomRect.y);
344
+ int spriteRectWidth = Mathf.FloorToInt(spriteGeomRect.width);
345
+ int spriteRectHeight = Mathf.FloorToInt(spriteGeomRect.height);
254
346
 
255
- if (index < 0 || pixels.Length <= index)
256
- {
257
- return;
258
- }
347
+ if (spriteRectWidth <= 0 || spriteRectHeight <= 0)
348
+ {
349
+ continue;
350
+ }
351
+
352
+ Color[] spriteRawPixels = spriteTexture.GetPixels(
353
+ spriteRectX,
354
+ spriteRectY,
355
+ spriteRectWidth,
356
+ spriteRectHeight
357
+ );
259
358
 
260
- Color existingColor = pixels[index];
261
- if (existingColor == transparent)
359
+ Parallel.For(
360
+ 0,
361
+ spriteRectHeight,
362
+ sySprite =>
363
+ {
364
+ for (int sxSprite = 0; sxSprite < spriteRectWidth; ++sxSprite)
262
365
  {
263
- existingColor = _backgroundColor;
366
+ Color spritePixelColor = spriteRawPixels[
367
+ sySprite * spriteRectWidth + sxSprite
368
+ ];
369
+
370
+ if (spritePixelColor.a < pixelCutoff)
371
+ {
372
+ continue;
373
+ }
374
+
375
+ float pixelWorldX = sxSprite - pivot.x + additionalPixelOffset.x;
376
+ float pixelWorldY = sySprite - pivot.y + additionalPixelOffset.y;
377
+ int bufferX = Mathf.FloorToInt(
378
+ pixelWorldX - compositeBufferOriginX
379
+ );
380
+ int bufferY = Mathf.FloorToInt(
381
+ pixelWorldY - compositeBufferOriginY
382
+ );
383
+
384
+ if (
385
+ bufferX < 0
386
+ || bufferX >= compositeBufferWidth
387
+ || bufferY < 0
388
+ || bufferY >= compositeBufferHeight
389
+ )
390
+ {
391
+ continue;
392
+ }
393
+
394
+ int bufferIndex = bufferY * compositeBufferWidth + bufferX;
395
+ Color existingColor = bufferPixels[bufferIndex];
396
+ if (existingColor.a < pixelCutoff)
397
+ {
398
+ existingColor = _backgroundColor;
399
+ }
400
+
401
+ Color blendedColor = Color.Lerp(
402
+ existingColor,
403
+ spritePixelColor,
404
+ layerAlpha
405
+ );
406
+
407
+ bufferPixels[bufferIndex] = blendedColor;
264
408
  }
265
-
266
- Color blendedColor = Color.Lerp(existingColor, pixelColor, alpha);
267
- pixels[index] = blendedColor;
268
409
  }
269
410
  );
270
411
  }
271
412
 
272
- // Find the bounds of the non-transparent pixels in the temporary texture
273
- int finalMinX = int.MaxValue;
274
- int finalMaxX = int.MinValue;
275
- int finalMinY = int.MaxValue;
276
- int finalMaxY = int.MinValue;
413
+ int finalMinX = int.MaxValue,
414
+ finalMaxX = int.MinValue;
415
+ int finalMinY = int.MaxValue,
416
+ finalMaxY = int.MinValue;
277
417
 
278
418
  Parallel.For(
279
419
  0,
280
- height * width,
281
- inIndex =>
420
+ compositeBufferHeight * compositeBufferWidth,
421
+ bufferIndex =>
282
422
  {
283
- Color pixelColor = pixels[inIndex];
284
- if (pixelColor.a < pixelCutoff)
285
- {
286
- return;
287
- }
288
-
289
- int x = inIndex % width;
290
- int y = inIndex / width;
291
-
292
- int expectedX = finalMinX;
293
- while (x < expectedX)
294
- {
295
- expectedX = Interlocked.CompareExchange(ref finalMinX, x, expectedX);
296
- }
297
-
298
- expectedX = finalMaxX;
299
- while (expectedX < x)
300
- {
301
- expectedX = Interlocked.CompareExchange(ref finalMaxX, x, expectedX);
302
- }
303
-
304
- int expectedY = finalMinY;
305
- while (y < expectedY)
423
+ if (bufferPixels[bufferIndex].a >= pixelCutoff)
306
424
  {
307
- expectedY = Interlocked.CompareExchange(ref finalMinY, y, expectedY);
308
- }
425
+ int x = bufferIndex % compositeBufferWidth;
426
+ int y = bufferIndex / compositeBufferWidth;
309
427
 
310
- expectedY = finalMaxY;
311
- while (expectedY < y)
312
- {
313
- expectedY = Interlocked.CompareExchange(ref finalMaxY, y, expectedY);
428
+ int currentVal;
429
+ do
430
+ {
431
+ currentVal = Volatile.Read(ref finalMinX);
432
+ } while (
433
+ x < currentVal
434
+ && Interlocked.CompareExchange(ref finalMinX, x, currentVal)
435
+ != currentVal
436
+ );
437
+ do
438
+ {
439
+ currentVal = Volatile.Read(ref finalMaxX);
440
+ } while (
441
+ x > currentVal
442
+ && Interlocked.CompareExchange(ref finalMaxX, x, currentVal)
443
+ != currentVal
444
+ );
445
+ do
446
+ {
447
+ currentVal = Volatile.Read(ref finalMinY);
448
+ } while (
449
+ y < currentVal
450
+ && Interlocked.CompareExchange(ref finalMinY, y, currentVal)
451
+ != currentVal
452
+ );
453
+ do
454
+ {
455
+ currentVal = Volatile.Read(ref finalMaxY);
456
+ } while (
457
+ y > currentVal
458
+ && Interlocked.CompareExchange(ref finalMaxY, y, currentVal)
459
+ != currentVal
460
+ );
314
461
  }
315
462
  }
316
463
  );
317
464
 
318
465
  if (finalMinX == int.MaxValue)
319
466
  {
467
+ yield return null;
320
468
  continue;
321
469
  }
322
470
 
323
- // Calculate the final width and height of the culled texture
324
471
  int finalWidth = finalMaxX - finalMinX + 1;
325
472
  int finalHeight = finalMaxY - finalMinY + 1;
326
473
 
327
474
  Color[] finalPixels = new Color[finalWidth * finalHeight];
328
- Array.Fill(finalPixels, _backgroundColor);
329
475
 
330
- // Copy the non-transparent pixels from the temporary texture to the final texture
476
+ Array.Fill(finalPixels, _backgroundColor);
331
477
  Parallel.For(
332
478
  0,
333
- finalWidth * finalHeight,
334
- inIndex =>
479
+ finalHeight,
480
+ yFinal =>
335
481
  {
336
- int x = inIndex % finalWidth;
337
- int y = inIndex / finalWidth;
338
- int outerX = x + finalMinX;
339
- int outerY = y + finalMinY;
340
- Color pixelColor = pixels[outerY * width + outerX];
341
- if (pixelColor.a < pixelCutoff)
482
+ for (int xFinal = 0; xFinal < finalWidth; ++xFinal)
342
483
  {
343
- return;
484
+ int bufferX = finalMinX + xFinal;
485
+ int bufferY = finalMinY + yFinal;
486
+ Color pixelColor = bufferPixels[
487
+ bufferY * compositeBufferWidth + bufferX
488
+ ];
489
+
490
+ if (pixelColor.a >= pixelCutoff)
491
+ {
492
+ finalPixels[yFinal * finalWidth + xFinal] = pixelColor;
493
+ }
344
494
  }
345
- finalPixels[y * finalWidth + x] = pixelColor;
346
495
  }
347
496
  );
348
497
 
@@ -351,12 +500,11 @@
351
500
  finalHeight,
352
501
  TextureFormat.RGBA32,
353
502
  mipChain: false,
354
- linear: false,
355
- createUninitialized: true
503
+ linear: false
356
504
  );
357
- finalTexture.SetPixels(finalPixels);
358
- finalTexture.Apply(false, false);
359
505
 
506
+ finalTexture.SetPixels(finalPixels);
507
+ finalTexture.Apply(updateMipmaps: false, makeNoLongerReadable: false);
360
508
  yield return finalTexture;
361
509
  }
362
510
  }
@@ -21,7 +21,7 @@
21
21
 
22
22
  [JsonIgnore]
23
23
  [IgnoreDataMember]
24
- private readonly HashSet<string> _availableBools = new HashSet<string>();
24
+ private readonly HashSet<string> _availableBools = new();
25
25
 
26
26
  [JsonIgnore]
27
27
  [IgnoreDataMember]
@@ -53,7 +53,7 @@
53
53
 
54
54
  tImporter.isReadable = isReadable;
55
55
 
56
- TextureImporterPlatformSettings importerSettings = new TextureImporterPlatformSettings
56
+ TextureImporterPlatformSettings importerSettings = new()
57
57
  {
58
58
  resizeAlgorithm = TextureResizeAlgorithm.Bilinear,
59
59
  maxTextureSize = MaxTextureSize,