com.wallstop-studios.unity-helpers 2.0.0-rc75.9 → 2.0.0-rc76.1

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 (27) hide show
  1. package/Editor/CustomDrawers/IntDropdownDrawer.cs +46 -0
  2. package/Editor/CustomDrawers/IntDropdownDrawer.cs.meta +3 -0
  3. package/Editor/{StringInListeDrawer.cs → CustomDrawers/StringInListeDrawer.cs} +2 -2
  4. package/Editor/{WShowIfPropertyDrawer.cs → CustomDrawers/WShowIfPropertyDrawer.cs} +3 -3
  5. package/Editor/CustomDrawers.meta +3 -0
  6. package/Editor/Sprites/AnimationViewerWindow.cs +1521 -0
  7. package/Editor/Sprites/AnimationViewerWindow.cs.meta +3 -0
  8. package/Editor/Sprites/ProjectAnimationSettings.cs +50 -0
  9. package/Editor/Sprites/ProjectAnimationSettings.cs.meta +3 -0
  10. package/Editor/Sprites/ScriptableSpriteAtlas.cs +4 -2
  11. package/Editor/Sprites/ScriptableSpriteAtlasEditor.cs +1 -9
  12. package/Editor/Styles/AnimationViewer.uss +116 -0
  13. package/Editor/Styles/AnimationViewer.uss.meta +3 -0
  14. package/Editor/Styles/AnimationViewer.uxml +57 -0
  15. package/Editor/Styles/AnimationViewer.uxml.meta +3 -0
  16. package/Editor/Styles.meta +3 -0
  17. package/Editor/UI.meta +3 -0
  18. package/Runtime/Core/Attributes/IntDropdownAttribute.cs +14 -0
  19. package/Runtime/Core/Attributes/IntDropdownAttribute.cs.meta +3 -0
  20. package/Runtime/UI/LayeredImage.cs +193 -98
  21. package/Runtime/UI/MultiFileSelectorElement.cs +322 -0
  22. package/Runtime/UI/MultiFileSelectorElement.cs.meta +3 -0
  23. package/package.json +3 -1
  24. package/Editor/AnimatorControllerCopier.cs +0 -156
  25. package/Editor/AnimatorControllerCopier.cs.meta +0 -3
  26. /package/Editor/{StringInListeDrawer.cs.meta → CustomDrawers/StringInListeDrawer.cs.meta} +0 -0
  27. /package/Editor/{WShowIfPropertyDrawer.cs.meta → CustomDrawers/WShowIfPropertyDrawer.cs.meta} +0 -0
@@ -8,13 +8,15 @@
8
8
  using System.Threading.Tasks;
9
9
  using Core.Extension;
10
10
  using Core.Helper;
11
- using UnityEditor;
12
11
  using UnityEngine;
13
12
  using UnityEngine.UIElements;
14
13
  using Utils;
15
14
  using Debug = UnityEngine.Debug;
15
+ #if UNITY_EDITOR
16
+ using UnityEditor;
17
+ #endif
16
18
 
17
- public readonly struct AnimatedSpriteLayer
19
+ public readonly struct AnimatedSpriteLayer : IEquatable<AnimatedSpriteLayer>
18
20
  {
19
21
  public const float FrameRate = 12f;
20
22
 
@@ -85,27 +87,122 @@
85
87
  Enumerable.Empty<Sprite>(),
86
88
  #endif
87
89
  worldSpaceOffsets, alpha) { }
90
+
91
+ public static bool operator ==(AnimatedSpriteLayer left, AnimatedSpriteLayer right)
92
+ {
93
+ return left.Equals(right);
94
+ }
95
+
96
+ public static bool operator !=(AnimatedSpriteLayer left, AnimatedSpriteLayer right)
97
+ {
98
+ return !left.Equals(right);
99
+ }
100
+
101
+ public bool Equals(AnimatedSpriteLayer other)
102
+ {
103
+ bool equal = perFramePixelOffsets.AsSpan().SequenceEqual(other.perFramePixelOffsets);
104
+ if (!equal)
105
+ {
106
+ return false;
107
+ }
108
+
109
+ equal = frames.Length == other.frames.Length;
110
+ if (!equal)
111
+ {
112
+ return false;
113
+ }
114
+
115
+ for (int i = 0; i < frames.Length; ++i)
116
+ {
117
+ if (frames[i] != other.frames[i])
118
+ {
119
+ return false;
120
+ }
121
+ }
122
+
123
+ return alpha.Equals(other.alpha);
124
+ }
125
+
126
+ public override bool Equals(object obj)
127
+ {
128
+ return obj is AnimatedSpriteLayer other && Equals(other);
129
+ }
130
+
131
+ public override int GetHashCode()
132
+ {
133
+ return Objects.ValueTypeHashCode(perFramePixelOffsets.Length, frames.Length, alpha);
134
+ }
88
135
  }
89
136
 
90
137
  public sealed class LayeredImage : VisualElement
91
138
  {
139
+ public float Fps
140
+ {
141
+ get => _fps;
142
+ set
143
+ {
144
+ if (_fps == value)
145
+ {
146
+ return;
147
+ }
148
+
149
+ _fps = value;
150
+ if (_updatesSelf && _computed.Length > 1 && _fps > 0)
151
+ {
152
+ #if UNITY_EDITOR
153
+ if (Application.isEditor && !Application.isPlaying && !_tickAttached)
154
+ {
155
+ EditorApplication.update += () => Update(force: false);
156
+ _tickAttached = true;
157
+ return;
158
+ }
159
+ #endif
160
+ if (Application.isPlaying)
161
+ {
162
+ if (_coroutine != null)
163
+ {
164
+ CoroutineHandler.Instance.StopCoroutine(_coroutine);
165
+ }
166
+
167
+ _coroutine = CoroutineHandler.Instance.StartFunctionAsCoroutine(
168
+ () => Update(force: true),
169
+ 1f / _fps
170
+ );
171
+ }
172
+ }
173
+ }
174
+ }
175
+
92
176
  private readonly AnimatedSpriteLayer[] _layers;
93
177
  private readonly Texture2D[] _computed;
94
178
  private readonly Color _backgroundColor;
95
179
  private readonly Rect? _largestArea;
180
+ private readonly Stopwatch _timer;
181
+ private readonly bool _updatesSelf;
182
+ private readonly float _pixelCutoff;
183
+
184
+ private TimeSpan _lastTick;
185
+ private Coroutine _coroutine;
186
+ private bool _tickAttached;
187
+ private float _fps;
188
+ private int _index;
96
189
 
97
190
  public LayeredImage(
98
191
  IEnumerable<AnimatedSpriteLayer> inputSpriteLayers,
99
192
  Color? backgroundColor = null,
100
- float fps = AnimatedSpriteLayer.FrameRate
193
+ float fps = AnimatedSpriteLayer.FrameRate,
194
+ bool updatesSelf = true,
195
+ float pixelCutoff = 0.01f
101
196
  )
102
197
  {
198
+ _pixelCutoff = pixelCutoff;
103
199
  _layers = inputSpriteLayers.ToArray();
104
200
  _backgroundColor = backgroundColor ?? Color.white;
105
201
  _computed = ComputeTextures().ToArray();
106
202
  _largestArea = null;
203
+ _updatesSelf = updatesSelf;
107
204
 
108
- foreach (Texture2D? computedTexture in _computed)
205
+ foreach (Texture2D computedTexture in _computed)
109
206
  {
110
207
  if (computedTexture == null)
111
208
  {
@@ -128,57 +225,33 @@
128
225
  }
129
226
  }
130
227
 
131
- Render(0);
228
+ _timer = Stopwatch.StartNew();
229
+ Fps = fps;
230
+ Update();
231
+ }
132
232
 
133
- if (_computed.Length > 1 && fps > 0)
233
+ public void Update(bool force = false)
234
+ {
235
+ if (panel == null)
134
236
  {
135
- #if UNITY_EDITOR
136
- if (!Application.isPlaying)
137
- {
138
- TimeSpan lastTick = TimeSpan.Zero;
139
- TimeSpan fpsSpan = TimeSpan.FromMilliseconds(1000f / fps);
140
- int index = 0;
141
- Stopwatch timer = Stopwatch.StartNew();
142
- EditorApplication.update += Tick;
143
- return;
144
-
145
- void Tick()
146
- {
147
- if (panel == null)
148
- {
149
- EditorApplication.update -= Tick;
150
- return;
151
- }
152
- TimeSpan elapsed = timer.Elapsed;
153
- if (lastTick + fpsSpan >= elapsed)
154
- {
155
- return;
156
- }
237
+ return;
238
+ }
157
239
 
158
- index = index.WrappedIncrement(_computed.Length);
159
- lastTick = elapsed;
160
- Render(index);
161
- }
162
- }
163
- #endif
164
- if (Application.isPlaying && CoroutineHandler.Instance != null)
165
- {
166
- int index = 0;
167
- CoroutineHandler.Instance.StartFunctionAsCoroutine(
168
- () =>
169
- {
170
- if (panel == null)
171
- {
172
- return;
173
- }
240
+ if (_computed.Length == 0)
241
+ {
242
+ return;
243
+ }
174
244
 
175
- index = index.WrappedIncrement(_computed.Length);
176
- Render(index);
177
- },
178
- 1f / fps
179
- );
180
- }
245
+ TimeSpan elapsed = _timer.Elapsed;
246
+ TimeSpan deltaTime = TimeSpan.FromMilliseconds(1000 / _fps);
247
+ if (!force && _lastTick + deltaTime > elapsed)
248
+ {
249
+ return;
181
250
  }
251
+
252
+ _index = _index.WrappedIncrement(_computed.Length);
253
+ _lastTick += deltaTime;
254
+ Render(_index);
182
255
  }
183
256
 
184
257
  private void Render(int index)
@@ -223,9 +296,8 @@
223
296
  }
224
297
  }
225
298
 
226
- private IEnumerable<Texture2D?> ComputeTextures()
299
+ private IEnumerable<Texture2D> ComputeTextures()
227
300
  {
228
- const float pixelCutoff = 0.01f;
229
301
  if (_layers is not { Length: > 0 })
230
302
  {
231
303
  yield break;
@@ -367,7 +439,7 @@
367
439
  sySprite * spriteRectWidth + sxSprite
368
440
  ];
369
441
 
370
- if (spritePixelColor.a < pixelCutoff)
442
+ if (spritePixelColor.a < _pixelCutoff)
371
443
  {
372
444
  continue;
373
445
  }
@@ -393,7 +465,7 @@
393
465
 
394
466
  int bufferIndex = bufferY * compositeBufferWidth + bufferX;
395
467
  Color existingColor = bufferPixels[bufferIndex];
396
- if (existingColor.a < pixelCutoff)
468
+ if (existingColor.a < _pixelCutoff)
397
469
  {
398
470
  existingColor = _backgroundColor;
399
471
  }
@@ -410,66 +482,89 @@
410
482
  );
411
483
  }
412
484
 
413
- int finalMinX = int.MaxValue,
414
- finalMaxX = int.MinValue;
415
- int finalMinY = int.MaxValue,
416
- finalMaxY = int.MinValue;
485
+ int globalMinX = int.MaxValue;
486
+ int globalMaxX = int.MinValue;
487
+ int globalMinY = int.MaxValue;
488
+ int globalMaxY = int.MinValue;
489
+ object sync = new();
417
490
 
418
491
  Parallel.For(
419
492
  0,
420
- compositeBufferHeight * compositeBufferWidth,
421
- bufferIndex =>
493
+ compositeBufferHeight,
494
+ () =>
495
+ (
496
+ minX: int.MaxValue,
497
+ maxX: int.MinValue,
498
+ minY: int.MaxValue,
499
+ maxY: int.MinValue
500
+ ),
501
+ (y, _, local) =>
422
502
  {
423
- if (bufferPixels[bufferIndex].a >= pixelCutoff)
503
+ int baseIndex = y * compositeBufferWidth;
504
+ for (int x = 0; x < compositeBufferWidth; ++x)
424
505
  {
425
- int x = bufferIndex % compositeBufferWidth;
426
- int y = bufferIndex / compositeBufferWidth;
506
+ if (bufferPixels[baseIndex + x].a < _pixelCutoff)
507
+ {
508
+ continue;
509
+ }
427
510
 
428
- int currentVal;
429
- do
511
+ if (x < local.minX)
430
512
  {
431
- currentVal = Volatile.Read(ref finalMinX);
432
- } while (
433
- x < currentVal
434
- && Interlocked.CompareExchange(ref finalMinX, x, currentVal)
435
- != currentVal
436
- );
437
- do
513
+ local.minX = x;
514
+ }
515
+
516
+ if (x > local.maxX)
438
517
  {
439
- currentVal = Volatile.Read(ref finalMaxX);
440
- } while (
441
- x > currentVal
442
- && Interlocked.CompareExchange(ref finalMaxX, x, currentVal)
443
- != currentVal
444
- );
445
- do
518
+ local.maxX = x;
519
+ }
520
+
521
+ if (y < local.minY)
446
522
  {
447
- currentVal = Volatile.Read(ref finalMinY);
448
- } while (
449
- y < currentVal
450
- && Interlocked.CompareExchange(ref finalMinY, y, currentVal)
451
- != currentVal
452
- );
453
- do
523
+ local.minY = y;
524
+ }
525
+
526
+ if (y > local.maxY)
454
527
  {
455
- currentVal = Volatile.Read(ref finalMaxY);
456
- } while (
457
- y > currentVal
458
- && Interlocked.CompareExchange(ref finalMaxY, y, currentVal)
459
- != currentVal
460
- );
528
+ local.maxY = y;
529
+ }
530
+ }
531
+ return local;
532
+ },
533
+ local =>
534
+ {
535
+ lock (sync)
536
+ {
537
+ if (local.minX < globalMinX)
538
+ {
539
+ globalMinX = local.minX;
540
+ }
541
+
542
+ if (local.maxX > globalMaxX)
543
+ {
544
+ globalMaxX = local.maxX;
545
+ }
546
+
547
+ if (local.minY < globalMinY)
548
+ {
549
+ globalMinY = local.minY;
550
+ }
551
+
552
+ if (local.maxY > globalMaxY)
553
+ {
554
+ globalMaxY = local.maxY;
555
+ }
461
556
  }
462
557
  }
463
558
  );
464
559
 
465
- if (finalMinX == int.MaxValue)
560
+ if (globalMinX == int.MaxValue)
466
561
  {
467
562
  yield return null;
468
563
  continue;
469
564
  }
470
565
 
471
- int finalWidth = finalMaxX - finalMinX + 1;
472
- int finalHeight = finalMaxY - finalMinY + 1;
566
+ int finalWidth = globalMaxX - globalMinX + 1;
567
+ int finalHeight = globalMaxY - globalMinY + 1;
473
568
 
474
569
  Color[] finalPixels = new Color[finalWidth * finalHeight];
475
570
 
@@ -481,13 +576,13 @@
481
576
  {
482
577
  for (int xFinal = 0; xFinal < finalWidth; ++xFinal)
483
578
  {
484
- int bufferX = finalMinX + xFinal;
485
- int bufferY = finalMinY + yFinal;
579
+ int bufferX = globalMinX + xFinal;
580
+ int bufferY = globalMinY + yFinal;
486
581
  Color pixelColor = bufferPixels[
487
582
  bufferY * compositeBufferWidth + bufferX
488
583
  ];
489
584
 
490
- if (pixelColor.a >= pixelCutoff)
585
+ if (pixelColor.a >= _pixelCutoff)
491
586
  {
492
587
  finalPixels[yFinal * finalWidth + xFinal] = pixelColor;
493
588
  }