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.
- package/Editor/AnimationCopier.cs +58 -50
- package/Editor/AnimationCreator.cs +24 -24
- package/Editor/AnimationEventEditor.cs +11 -23
- package/Editor/FitTextureSizeWindow.cs +9 -9
- package/Editor/PrefabChecker.cs +12 -18
- package/Editor/SpriteAtlasGenerator.cs +47 -66
- package/Editor/SpriteCropper.cs +157 -131
- package/Editor/SpriteSettingsApplier.cs +5 -3
- package/Editor/Utils/GUIIndentScope.cs +20 -0
- package/Editor/Utils/GUIIndentScope.cs.meta +3 -0
- package/Runtime/Core/DataStructure/Circle.cs +1 -1
- package/Runtime/Core/DataStructure/QuadTree.cs +4 -4
- package/Runtime/Core/Extension/ColorExtensions.cs +5 -5
- package/Runtime/Core/Extension/IEnumerableExtensions.cs +1 -1
- package/Runtime/Core/Extension/UnityExtensions.cs +14 -14
- package/Runtime/Core/Helper/Helpers.cs +9 -9
- package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs +31 -8
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +2 -2
- package/Runtime/Core/Helper/PathHelper.cs +15 -0
- package/Runtime/Core/Helper/PathHelper.cs.meta +3 -0
- package/Runtime/Core/Random/DotNetRandom.cs +1 -1
- package/Runtime/Core/Random/SplitMix64.cs +1 -1
- package/Runtime/Core/Random/SquirrelRandom.cs +7 -7
- package/Runtime/Core/Random/ThreadLocalRandom.cs +1 -1
- package/Runtime/Core/Random/WyRandom.cs +1 -1
- package/Runtime/Tags/AttributeEffect.cs +1 -0
- package/Runtime/Tags/EffectHandler.cs +1 -1
- package/Runtime/UI/LayeredImage.cs +309 -161
- package/Runtime/Utils/AnimatorEnumStateMachine.cs +1 -1
- package/Runtime/Utils/SetTextureImportData.cs +1 -1
- package/Runtime/Utils/TextureScale.cs +4 -4
- package/Styles/Elements/Progress/ArcedProgressBar.cs +345 -0
- package/Styles/Elements/Progress/ArcedProgressBar.cs.meta +3 -0
- package/Styles/Elements/Progress/CircularProgressBar.cs +307 -0
- package/Styles/Elements/Progress/CircularProgressBar.cs.meta +3 -0
- package/Styles/Elements/Progress/GlitchProgressBar.cs +416 -0
- package/Styles/Elements/Progress/GlitchProgressBar.cs.meta +3 -0
- package/Styles/Elements/Progress/LiquidProgressBar.cs +632 -0
- package/Styles/Elements/Progress/LiquidProgressBar.cs.meta +3 -0
- package/Styles/Elements/Progress/MarchingAntsProgressBar.cs +722 -0
- package/Styles/Elements/Progress/MarchingAntsProgressBar.cs.meta +3 -0
- package/Styles/Elements/Progress/RegularProgressBar.cs +405 -0
- package/Styles/Elements/Progress/RegularProgressBar.cs.meta +3 -0
- package/Styles/Elements/Progress/WigglyProgressBar.cs +837 -0
- package/Styles/Elements/Progress/WigglyProgressBar.cs.meta +3 -0
- package/Styles/Elements/Progress.meta +3 -0
- package/Styles/Elements.meta +3 -0
- package/Styles/USS/ArcedProgressBar.uss +19 -0
- package/Styles/USS/ArcedProgressBar.uss.meta +3 -0
- package/Styles/USS/CirclularProgressBar.uss +18 -0
- package/Styles/USS/CirclularProgressBar.uss.meta +3 -0
- package/Styles/USS/RegularProgressBar.uss +33 -0
- package/Styles/USS/RegularProgressBar.uss.meta +3 -0
- package/Styles/USS/WigglyProgressBar.uss +17 -0
- package/Styles/USS/WigglyProgressBar.uss.meta +3 -0
- package/Styles/USS.meta +3 -0
- package/Styles/WallstopStudios.UnityHelpers.Styles.asmdef +17 -0
- package/Styles/WallstopStudios.UnityHelpers.Styles.asmdef.meta +7 -0
- package/Styles.meta +3 -0
- package/package.json +11 -1
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
{
|
|
46
46
|
foreach (Sprite sprite in Sprites)
|
|
47
47
|
{
|
|
48
|
-
if (sprite
|
|
48
|
+
if (sprite is { rect: { width: > 0, height: > 0 } })
|
|
49
49
|
{
|
|
50
50
|
TotalArea += (long)(sprite.rect.width * sprite.rect.height);
|
|
51
51
|
}
|
|
@@ -249,7 +249,7 @@
|
|
|
249
249
|
Application.dataPath,
|
|
250
250
|
""
|
|
251
251
|
);
|
|
252
|
-
if (!string.
|
|
252
|
+
if (!string.IsNullOrWhiteSpace(absPath))
|
|
253
253
|
{
|
|
254
254
|
if (absPath.StartsWith(Application.dataPath, StringComparison.Ordinal))
|
|
255
255
|
{
|
|
@@ -295,16 +295,12 @@
|
|
|
295
295
|
try
|
|
296
296
|
{
|
|
297
297
|
float total = _sourceFolders.Length;
|
|
298
|
-
foreach (Object obj in _sourceFolders)
|
|
298
|
+
foreach (Object obj in _sourceFolders.Where(Objects.NotNull))
|
|
299
299
|
{
|
|
300
|
-
if (obj == null)
|
|
301
|
-
{
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
300
|
string folderPath = AssetDatabase.GetAssetPath(obj);
|
|
306
301
|
if (
|
|
307
|
-
string.
|
|
302
|
+
string.IsNullOrWhiteSpace(folderPath)
|
|
303
|
+
|| !AssetDatabase.IsValidFolder(folderPath)
|
|
308
304
|
)
|
|
309
305
|
{
|
|
310
306
|
this.LogWarn($"Skipping invalid or null source folder entry.");
|
|
@@ -312,7 +308,7 @@
|
|
|
312
308
|
}
|
|
313
309
|
|
|
314
310
|
string[] guids = AssetDatabase.FindAssets("t:Sprite", new[] { folderPath });
|
|
315
|
-
for (int i = 0; i < guids.Length; i
|
|
311
|
+
for (int i = 0; i < guids.Length; ++i)
|
|
316
312
|
{
|
|
317
313
|
EditorUtility.DisplayProgressBar(
|
|
318
314
|
Name,
|
|
@@ -329,14 +325,8 @@
|
|
|
329
325
|
continue;
|
|
330
326
|
}
|
|
331
327
|
|
|
332
|
-
|
|
333
|
-
foreach (Sprite sp in sprites)
|
|
328
|
+
foreach (Sprite sp in assets.OfType<Sprite>().Where(Objects.NotNull))
|
|
334
329
|
{
|
|
335
|
-
if (sp == null)
|
|
336
|
-
{
|
|
337
|
-
continue;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
330
|
_totalCount++;
|
|
341
331
|
if (regex.IsMatch(sp.name))
|
|
342
332
|
{
|
|
@@ -369,11 +359,7 @@
|
|
|
369
359
|
return;
|
|
370
360
|
}
|
|
371
361
|
|
|
372
|
-
if (
|
|
373
|
-
_sourceFolders == null
|
|
374
|
-
|| _sourceFolders.Length == 0
|
|
375
|
-
|| _sourceFolders.All(f => f == null)
|
|
376
|
-
)
|
|
362
|
+
if (_sourceFolders == null || Array.TrueForAll(_sourceFolders, Objects.Null))
|
|
377
363
|
{
|
|
378
364
|
this.LogError($"No valid source folders specified.");
|
|
379
365
|
EditorUtility.ClearProgressBar();
|
|
@@ -386,7 +372,10 @@
|
|
|
386
372
|
{
|
|
387
373
|
string parent = Path.GetDirectoryName(_outputFolder);
|
|
388
374
|
string newFolderName = Path.GetFileName(_outputFolder);
|
|
389
|
-
if (
|
|
375
|
+
if (
|
|
376
|
+
string.IsNullOrWhiteSpace(parent)
|
|
377
|
+
|| string.IsNullOrWhiteSpace(newFolderName)
|
|
378
|
+
)
|
|
390
379
|
{
|
|
391
380
|
this.LogError($"Output folder path '{_outputFolder}' is invalid.");
|
|
392
381
|
EditorUtility.ClearProgressBar();
|
|
@@ -415,7 +404,7 @@
|
|
|
415
404
|
string[] existing = AssetDatabase
|
|
416
405
|
.FindAssets("t:SpriteAtlas", new[] { _outputFolder })
|
|
417
406
|
.Select(AssetDatabase.GUIDToAssetPath)
|
|
418
|
-
.Where(
|
|
407
|
+
.Where(path => !string.IsNullOrWhiteSpace(path))
|
|
419
408
|
.ToArray();
|
|
420
409
|
|
|
421
410
|
if (existing.Length > 0)
|
|
@@ -439,7 +428,7 @@
|
|
|
439
428
|
Regex regex;
|
|
440
429
|
try
|
|
441
430
|
{
|
|
442
|
-
regex = new(_nameRegex);
|
|
431
|
+
regex = new Regex(_nameRegex);
|
|
443
432
|
}
|
|
444
433
|
catch (ArgumentException ex)
|
|
445
434
|
{
|
|
@@ -455,13 +444,8 @@
|
|
|
455
444
|
_sourceFolders.Length > 0 ? 0.2f / _sourceFolders.Length : 0f;
|
|
456
445
|
float sourceFolderProgress = 0.1f;
|
|
457
446
|
|
|
458
|
-
foreach (Object sourceDirectory in _sourceFolders)
|
|
447
|
+
foreach (Object sourceDirectory in _sourceFolders.Where(Objects.NotNull))
|
|
459
448
|
{
|
|
460
|
-
if (sourceDirectory == null)
|
|
461
|
-
{
|
|
462
|
-
continue;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
449
|
string folderPath = AssetDatabase.GetAssetPath(sourceDirectory);
|
|
466
450
|
if (!AssetDatabase.IsValidFolder(folderPath))
|
|
467
451
|
{
|
|
@@ -485,7 +469,7 @@
|
|
|
485
469
|
)
|
|
486
470
|
{
|
|
487
471
|
string assetPath = AssetDatabase.GUIDToAssetPath(assetGuid);
|
|
488
|
-
if (string.
|
|
472
|
+
if (string.IsNullOrWhiteSpace(assetPath))
|
|
489
473
|
{
|
|
490
474
|
continue;
|
|
491
475
|
}
|
|
@@ -496,13 +480,8 @@
|
|
|
496
480
|
continue;
|
|
497
481
|
}
|
|
498
482
|
|
|
499
|
-
foreach (Sprite sub in allAssets.OfType<Sprite>())
|
|
483
|
+
foreach (Sprite sub in allAssets.OfType<Sprite>().Where(Objects.NotNull))
|
|
500
484
|
{
|
|
501
|
-
if (sub == null)
|
|
502
|
-
{
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
485
|
string assetName = sub.name;
|
|
507
486
|
if (!regex.IsMatch(assetName))
|
|
508
487
|
{
|
|
@@ -518,14 +497,13 @@
|
|
|
518
497
|
|
|
519
498
|
int totalChunks = 0;
|
|
520
499
|
Dictionary<string, List<List<Sprite>>> groupChunks = new();
|
|
521
|
-
|
|
522
500
|
EditorUtility.DisplayProgressBar(Name, "Calculating chunks...", 0.3f);
|
|
523
|
-
|
|
524
501
|
foreach (KeyValuePair<string, List<Sprite>> kv in groups)
|
|
525
502
|
{
|
|
526
503
|
List<Sprite> spritesInGroup = kv
|
|
527
|
-
.Value.Where(
|
|
528
|
-
.
|
|
504
|
+
.Value.Where(Objects.NotNull)
|
|
505
|
+
.Where(sprite => sprite.rect is { width: > 0, height: > 0 })
|
|
506
|
+
.OrderByDescending(sprite => sprite.rect.width * sprite.rect.height)
|
|
529
507
|
.ToList();
|
|
530
508
|
if (!spritesInGroup.Any())
|
|
531
509
|
{
|
|
@@ -599,7 +577,7 @@
|
|
|
599
577
|
) in groupChunks
|
|
600
578
|
)
|
|
601
579
|
{
|
|
602
|
-
for (int i = 0; i < chunksForThisGroup.Count; i
|
|
580
|
+
for (int i = 0; i < chunksForThisGroup.Count; ++i)
|
|
603
581
|
{
|
|
604
582
|
if (!chunksForThisGroup[i].Any())
|
|
605
583
|
{
|
|
@@ -621,21 +599,21 @@
|
|
|
621
599
|
}
|
|
622
600
|
|
|
623
601
|
allInitialCandidates = allInitialCandidates
|
|
624
|
-
.OrderByDescending(
|
|
625
|
-
.ThenBy(
|
|
602
|
+
.OrderByDescending(candidate => candidate.TotalArea)
|
|
603
|
+
.ThenBy(candidate => candidate.CandidateName, StringComparer.Ordinal)
|
|
626
604
|
.ToList();
|
|
627
605
|
|
|
628
606
|
List<MergeableAtlas> workingAtlases = allInitialCandidates
|
|
629
|
-
.Select(
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
607
|
+
.Select(candidate => new MergeableAtlas(
|
|
608
|
+
candidate.OriginalGroupKey,
|
|
609
|
+
candidate.Sprites,
|
|
610
|
+
candidate.CandidateName,
|
|
611
|
+
candidate.TotalArea
|
|
634
612
|
))
|
|
635
613
|
.ToList();
|
|
636
614
|
int passNumber = 0;
|
|
637
|
-
float mergeOptimizationProgressStart = 0.
|
|
638
|
-
float mergeOptimizationProgressRange = 0.
|
|
615
|
+
const float mergeOptimizationProgressStart = 0.3f;
|
|
616
|
+
const float mergeOptimizationProgressRange = 0.5f;
|
|
639
617
|
|
|
640
618
|
while (true)
|
|
641
619
|
{
|
|
@@ -643,7 +621,7 @@
|
|
|
643
621
|
bool mergedInThisPass = false;
|
|
644
622
|
float currentPassProgress =
|
|
645
623
|
mergeOptimizationProgressStart
|
|
646
|
-
+ passNumber * (mergeOptimizationProgressRange /
|
|
624
|
+
+ passNumber * (mergeOptimizationProgressRange / 15f);
|
|
647
625
|
EditorUtility.DisplayProgressBar(
|
|
648
626
|
Name,
|
|
649
627
|
$"Optimizing atlas count (Pass {passNumber}, {workingAtlases.Count} atlases)...",
|
|
@@ -654,13 +632,16 @@
|
|
|
654
632
|
);
|
|
655
633
|
|
|
656
634
|
workingAtlases = workingAtlases
|
|
657
|
-
.OrderByDescending(
|
|
658
|
-
.ThenBy(
|
|
635
|
+
.OrderByDescending(atlas => atlas.TotalArea)
|
|
636
|
+
.ThenBy(
|
|
637
|
+
atlas => atlas.RepresentativeInitialName,
|
|
638
|
+
StringComparer.Ordinal
|
|
639
|
+
)
|
|
659
640
|
.ToList();
|
|
660
641
|
|
|
661
642
|
bool[] isSubsumed = new bool[workingAtlases.Count];
|
|
662
643
|
|
|
663
|
-
for (int i = 0; i < workingAtlases.Count; i
|
|
644
|
+
for (int i = 0; i < workingAtlases.Count; ++i)
|
|
664
645
|
{
|
|
665
646
|
if (isSubsumed[i])
|
|
666
647
|
{
|
|
@@ -669,14 +650,14 @@
|
|
|
669
650
|
|
|
670
651
|
MergeableAtlas baseAtlas = workingAtlases[i];
|
|
671
652
|
string baseRepresentativeKey = baseAtlas
|
|
672
|
-
.OriginalGroupKeys.OrderBy(
|
|
653
|
+
.OriginalGroupKeys.OrderBy(key => key, StringComparer.Ordinal)
|
|
673
654
|
.First();
|
|
674
655
|
|
|
675
656
|
int bestPartnerIndex = -1;
|
|
676
657
|
MergeableAtlas bestPartnerObject = null;
|
|
677
658
|
int currentMinLevenshtein = int.MaxValue;
|
|
678
659
|
|
|
679
|
-
for (int j = i + 1; j < workingAtlases.Count; j
|
|
660
|
+
for (int j = i + 1; j < workingAtlases.Count; ++j)
|
|
680
661
|
{
|
|
681
662
|
if (isSubsumed[j])
|
|
682
663
|
{
|
|
@@ -693,7 +674,7 @@
|
|
|
693
674
|
}
|
|
694
675
|
|
|
695
676
|
string partnerRepresentativeKey = potentialPartner
|
|
696
|
-
.OriginalGroupKeys.OrderBy(
|
|
677
|
+
.OriginalGroupKeys.OrderBy(key => key, StringComparer.Ordinal)
|
|
697
678
|
.First();
|
|
698
679
|
int distance = baseRepresentativeKey.LevenshteinDistance(
|
|
699
680
|
partnerRepresentativeKey
|
|
@@ -754,8 +735,8 @@
|
|
|
754
735
|
}
|
|
755
736
|
|
|
756
737
|
finalAtlasesData = workingAtlases
|
|
757
|
-
.Select(
|
|
758
|
-
.OrderBy(
|
|
738
|
+
.Select(atlas => (Name: atlas.GenerateFinalName(), atlas.Sprites))
|
|
739
|
+
.OrderBy(atlas => atlas.Name, StringComparer.Ordinal)
|
|
759
740
|
.ToList();
|
|
760
741
|
}
|
|
761
742
|
else
|
|
@@ -766,7 +747,7 @@
|
|
|
766
747
|
string prefix = chunk.Key;
|
|
767
748
|
List<List<Sprite>> chunks = chunk.Value;
|
|
768
749
|
List<(string, List<Sprite>)> finalChunks = new();
|
|
769
|
-
for (int i = 0; i < chunks.Count; i
|
|
750
|
+
for (int i = 0; i < chunks.Count; ++i)
|
|
770
751
|
{
|
|
771
752
|
string atlasName = chunks.Count > 1 ? $"{prefix}_{i}" : prefix;
|
|
772
753
|
finalChunks.Add((atlasName, chunks[i]));
|
|
@@ -775,15 +756,15 @@
|
|
|
775
756
|
})
|
|
776
757
|
.ToList();
|
|
777
758
|
int chunkIndex = 0;
|
|
778
|
-
float atlasCreationProgressStart = 0.45f;
|
|
779
|
-
float atlasCreationProgressRange = 0.5f;
|
|
759
|
+
const float atlasCreationProgressStart = 0.45f;
|
|
760
|
+
const float atlasCreationProgressRange = 0.5f;
|
|
780
761
|
|
|
781
762
|
foreach ((string prefix, List<List<Sprite>> chunks) in groupChunks)
|
|
782
763
|
{
|
|
783
|
-
for (int i = 0; i < chunks.Count; i
|
|
764
|
+
for (int i = 0; i < chunks.Count; ++i)
|
|
784
765
|
{
|
|
785
766
|
List<Sprite> chunk = chunks[i];
|
|
786
|
-
if (chunk
|
|
767
|
+
if (chunk is not { Count: > 0 })
|
|
787
768
|
{
|
|
788
769
|
continue;
|
|
789
770
|
}
|
package/Editor/SpriteCropper.cs
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
private const float AlphaThreshold = 0.01f;
|
|
31
31
|
|
|
32
32
|
[SerializeField]
|
|
33
|
-
private Object
|
|
33
|
+
private List<Object> _inputDirectories = new();
|
|
34
34
|
|
|
35
35
|
[SerializeField]
|
|
36
36
|
private bool _onlyNecessary;
|
|
@@ -44,12 +44,56 @@
|
|
|
44
44
|
{
|
|
45
45
|
GUILayout.Label("Drag folders below", EditorStyles.boldLabel);
|
|
46
46
|
SerializedObject so = new(this);
|
|
47
|
+
so.Update();
|
|
47
48
|
SerializedProperty dirs = so.FindProperty(nameof(_inputDirectories));
|
|
48
49
|
EditorGUILayout.PropertyField(dirs, true);
|
|
49
50
|
SerializedProperty onlyNecessary = so.FindProperty(nameof(_onlyNecessary));
|
|
50
51
|
EditorGUILayout.PropertyField(onlyNecessary, true);
|
|
51
52
|
so.ApplyModifiedProperties();
|
|
52
53
|
|
|
54
|
+
if (GUILayout.Button("Select Input Folder"))
|
|
55
|
+
{
|
|
56
|
+
string path = EditorUtility.OpenFolderPanel(
|
|
57
|
+
"Select Sprite Input Folder",
|
|
58
|
+
Application.dataPath,
|
|
59
|
+
""
|
|
60
|
+
);
|
|
61
|
+
if (!string.IsNullOrWhiteSpace(path))
|
|
62
|
+
{
|
|
63
|
+
if (path.StartsWith(Application.dataPath, StringComparison.Ordinal))
|
|
64
|
+
{
|
|
65
|
+
path = "Assets" + path.Substring(Application.dataPath.Length);
|
|
66
|
+
if (
|
|
67
|
+
!_inputDirectories
|
|
68
|
+
.Select(AssetDatabase.GetAssetPath)
|
|
69
|
+
.Any(directory =>
|
|
70
|
+
string.Equals(
|
|
71
|
+
directory,
|
|
72
|
+
path,
|
|
73
|
+
StringComparison.OrdinalIgnoreCase
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
{
|
|
78
|
+
Object folder = AssetDatabase.LoadAssetAtPath<Object>(path);
|
|
79
|
+
if (folder == null)
|
|
80
|
+
{
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
_inputDirectories.Add(folder);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else
|
|
87
|
+
{
|
|
88
|
+
EditorUtility.DisplayDialog(
|
|
89
|
+
"Invalid Folder",
|
|
90
|
+
"Please select a folder inside the project's Assets directory.",
|
|
91
|
+
"OK"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
53
97
|
if (GUILayout.Button("Find Sprites To Process"))
|
|
54
98
|
{
|
|
55
99
|
FindFilesToProcess();
|
|
@@ -79,7 +123,7 @@
|
|
|
79
123
|
private void FindFilesToProcess()
|
|
80
124
|
{
|
|
81
125
|
_filesToProcess = new List<string>();
|
|
82
|
-
if (_inputDirectories
|
|
126
|
+
if (_inputDirectories is not { Count: > 0 })
|
|
83
127
|
{
|
|
84
128
|
this.LogWarn($"No input directories selected.");
|
|
85
129
|
return;
|
|
@@ -118,7 +162,7 @@
|
|
|
118
162
|
|
|
119
163
|
private void ProcessFoundSprites()
|
|
120
164
|
{
|
|
121
|
-
if (_filesToProcess
|
|
165
|
+
if (_filesToProcess is not { Count: > 0 })
|
|
122
166
|
{
|
|
123
167
|
this.LogWarn($"No files found or selected for processing.");
|
|
124
168
|
return;
|
|
@@ -169,11 +213,6 @@
|
|
|
169
213
|
newImporters.Add(newImporter);
|
|
170
214
|
}
|
|
171
215
|
}
|
|
172
|
-
|
|
173
|
-
foreach (TextureImporter newImporter in newImporters)
|
|
174
|
-
{
|
|
175
|
-
newImporter.SaveAndReimport();
|
|
176
|
-
}
|
|
177
216
|
}
|
|
178
217
|
finally
|
|
179
218
|
{
|
|
@@ -209,7 +248,7 @@
|
|
|
209
248
|
}
|
|
210
249
|
|
|
211
250
|
TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
|
|
212
|
-
if (importer
|
|
251
|
+
if (importer is not { textureType: TextureImporterType.Sprite })
|
|
213
252
|
{
|
|
214
253
|
return;
|
|
215
254
|
}
|
|
@@ -232,8 +271,10 @@
|
|
|
232
271
|
return null;
|
|
233
272
|
}
|
|
234
273
|
|
|
235
|
-
|
|
236
|
-
|
|
274
|
+
if (
|
|
275
|
+
AssetImporter.GetAtPath(assetPath)
|
|
276
|
+
is not TextureImporter { textureType: TextureImporterType.Sprite } importer
|
|
277
|
+
)
|
|
237
278
|
{
|
|
238
279
|
return null;
|
|
239
280
|
}
|
|
@@ -241,7 +282,6 @@
|
|
|
241
282
|
TextureImporterSettings originalSettings = new();
|
|
242
283
|
importer.ReadTextureSettings(originalSettings);
|
|
243
284
|
|
|
244
|
-
bool originalReadableState = importer.isReadable;
|
|
245
285
|
if (!importer.isReadable)
|
|
246
286
|
{
|
|
247
287
|
importer.isReadable = true;
|
|
@@ -254,142 +294,128 @@
|
|
|
254
294
|
return null;
|
|
255
295
|
}
|
|
256
296
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
(index, _, localState) =>
|
|
277
|
-
{
|
|
278
|
-
int x = index % width;
|
|
279
|
-
int y = index / width;
|
|
297
|
+
Color32[] pixels = tex.GetPixels32();
|
|
298
|
+
int width = tex.width;
|
|
299
|
+
int height = tex.height;
|
|
300
|
+
int minX = width;
|
|
301
|
+
int minY = height;
|
|
302
|
+
int maxX = 0;
|
|
303
|
+
int maxY = 0;
|
|
304
|
+
bool hasVisible = false;
|
|
305
|
+
|
|
306
|
+
object lockObject = new();
|
|
307
|
+
|
|
308
|
+
Parallel.For(
|
|
309
|
+
0,
|
|
310
|
+
width * height,
|
|
311
|
+
() => (minX: width, minY: height, maxX: 0, maxY: 0, hasVisible: false),
|
|
312
|
+
(index, _, localState) =>
|
|
313
|
+
{
|
|
314
|
+
int x = index % width;
|
|
315
|
+
int y = index / width;
|
|
280
316
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
{
|
|
284
|
-
localState.hasVisible = true;
|
|
285
|
-
localState.minX = Mathf.Min(localState.minX, x);
|
|
286
|
-
localState.minY = Mathf.Min(localState.minY, y);
|
|
287
|
-
localState.maxX = Mathf.Max(localState.maxX, x);
|
|
288
|
-
localState.maxY = Mathf.Max(localState.maxY, y);
|
|
289
|
-
}
|
|
290
|
-
return localState;
|
|
291
|
-
},
|
|
292
|
-
finalLocalState =>
|
|
317
|
+
float a = pixels[index].a / 255f;
|
|
318
|
+
if (a > AlphaThreshold)
|
|
293
319
|
{
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
minX = Mathf.Min(minX, finalLocalState.minX);
|
|
300
|
-
minY = Mathf.Min(minY, finalLocalState.minY);
|
|
301
|
-
maxX = Mathf.Max(maxX, finalLocalState.maxX);
|
|
302
|
-
maxY = Mathf.Max(maxY, finalLocalState.maxY);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
320
|
+
localState.hasVisible = true;
|
|
321
|
+
localState.minX = Mathf.Min(localState.minX, x);
|
|
322
|
+
localState.minY = Mathf.Min(localState.minY, y);
|
|
323
|
+
localState.maxX = Mathf.Max(localState.maxX, x);
|
|
324
|
+
localState.maxY = Mathf.Max(localState.maxY, y);
|
|
305
325
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
{
|
|
310
|
-
return null;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
int cropWidth = maxX - minX + 1;
|
|
314
|
-
int cropHeight = maxY - minY + 1;
|
|
315
|
-
|
|
316
|
-
if (_onlyNecessary && cropWidth == width && cropHeight == height)
|
|
326
|
+
return localState;
|
|
327
|
+
},
|
|
328
|
+
finalLocalState =>
|
|
317
329
|
{
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
Texture2D cropped = new(cropWidth, cropHeight, TextureFormat.RGBA32, false);
|
|
322
|
-
Color32[] croppedPixels = new Color32[cropWidth * cropHeight];
|
|
323
|
-
|
|
324
|
-
Parallel.For(
|
|
325
|
-
0,
|
|
326
|
-
cropHeight,
|
|
327
|
-
y =>
|
|
330
|
+
if (finalLocalState.hasVisible)
|
|
328
331
|
{
|
|
329
|
-
|
|
330
|
-
int destYOffset = y * cropWidth;
|
|
331
|
-
for (int x = 0; x < cropWidth; ++x)
|
|
332
|
+
lock (lockObject)
|
|
332
333
|
{
|
|
333
|
-
|
|
334
|
+
hasVisible = true;
|
|
335
|
+
minX = Mathf.Min(minX, finalLocalState.minX);
|
|
336
|
+
minY = Mathf.Min(minY, finalLocalState.minY);
|
|
337
|
+
maxX = Mathf.Max(maxX, finalLocalState.maxX);
|
|
338
|
+
maxY = Mathf.Max(maxY, finalLocalState.maxY);
|
|
334
339
|
}
|
|
335
340
|
}
|
|
336
|
-
);
|
|
337
|
-
|
|
338
|
-
cropped.SetPixels32(croppedPixels);
|
|
339
|
-
cropped.Apply();
|
|
340
|
-
|
|
341
|
-
string newPath = Path.Combine(
|
|
342
|
-
assetDirectory,
|
|
343
|
-
CroppedPrefix + Path.GetFileName(assetPath)
|
|
344
|
-
);
|
|
345
|
-
File.WriteAllBytes(newPath, cropped.EncodeToPNG());
|
|
346
|
-
DestroyImmediate(cropped);
|
|
347
|
-
AssetDatabase.ImportAsset(newPath);
|
|
348
|
-
TextureImporter newImporter = AssetImporter.GetAtPath(newPath) as TextureImporter;
|
|
349
|
-
if (newImporter == null)
|
|
350
|
-
{
|
|
351
|
-
return null;
|
|
352
341
|
}
|
|
342
|
+
);
|
|
353
343
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
newImporter.wrapMode = importer.wrapMode;
|
|
359
|
-
newImporter.mipmapEnabled = importer.mipmapEnabled;
|
|
360
|
-
newImporter.spritePixelsPerUnit = importer.spritePixelsPerUnit;
|
|
361
|
-
|
|
362
|
-
TextureImporterSettings newSettings = new();
|
|
363
|
-
newImporter.ReadTextureSettings(newSettings);
|
|
364
|
-
newSettings.spriteExtrude = originalSettings.spriteExtrude;
|
|
365
|
-
|
|
366
|
-
Vector2 origPivot = GetSpritePivot(importer);
|
|
367
|
-
Vector2 origCenter = new(width * origPivot.x, height * origPivot.y);
|
|
368
|
-
Vector2 newPivotPixels = origCenter - new Vector2(minX, minY);
|
|
369
|
-
Vector2 newPivotNorm = new(
|
|
370
|
-
cropWidth > 0 ? newPivotPixels.x / cropWidth : 0.5f,
|
|
371
|
-
cropHeight > 0 ? newPivotPixels.y / cropHeight : 0.5f
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
newImporter.spriteImportMode = SpriteImportMode.Single;
|
|
375
|
-
newImporter.spritePivot = newPivotNorm;
|
|
376
|
-
newSettings.spritePivot = newPivotNorm;
|
|
377
|
-
newSettings.spriteAlignment = (int)SpriteAlignment.Custom;
|
|
344
|
+
if (!hasVisible)
|
|
345
|
+
{
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
378
348
|
|
|
379
|
-
|
|
380
|
-
|
|
349
|
+
int cropWidth = maxX - minX + 1;
|
|
350
|
+
int cropHeight = maxY - minY + 1;
|
|
381
351
|
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
finally
|
|
352
|
+
if (_onlyNecessary && cropWidth == width && cropHeight == height)
|
|
385
353
|
{
|
|
386
|
-
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
Texture2D cropped = new(cropWidth, cropHeight, TextureFormat.RGBA32, false);
|
|
358
|
+
Color32[] croppedPixels = new Color32[cropWidth * cropHeight];
|
|
359
|
+
|
|
360
|
+
Parallel.For(
|
|
361
|
+
0,
|
|
362
|
+
cropHeight,
|
|
363
|
+
y =>
|
|
387
364
|
{
|
|
388
|
-
|
|
389
|
-
|
|
365
|
+
int sourceYOffset = (y + minY) * width;
|
|
366
|
+
int destYOffset = y * cropWidth;
|
|
367
|
+
for (int x = 0; x < cropWidth; ++x)
|
|
368
|
+
{
|
|
369
|
+
croppedPixels[destYOffset + x] = pixels[sourceYOffset + x + minX];
|
|
370
|
+
}
|
|
390
371
|
}
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
cropped.SetPixels32(croppedPixels);
|
|
375
|
+
cropped.Apply();
|
|
376
|
+
|
|
377
|
+
string newPath = Path.Combine(
|
|
378
|
+
assetDirectory,
|
|
379
|
+
CroppedPrefix + Path.GetFileName(assetPath)
|
|
380
|
+
);
|
|
381
|
+
File.WriteAllBytes(newPath, cropped.EncodeToPNG());
|
|
382
|
+
DestroyImmediate(cropped);
|
|
383
|
+
AssetDatabase.ImportAsset(newPath);
|
|
384
|
+
TextureImporter newImporter = AssetImporter.GetAtPath(newPath) as TextureImporter;
|
|
385
|
+
if (newImporter == null)
|
|
386
|
+
{
|
|
387
|
+
return null;
|
|
391
388
|
}
|
|
392
389
|
|
|
390
|
+
newImporter.textureType = importer.textureType;
|
|
391
|
+
newImporter.spriteImportMode = importer.spriteImportMode;
|
|
392
|
+
newImporter.filterMode = importer.filterMode;
|
|
393
|
+
newImporter.textureCompression = importer.textureCompression;
|
|
394
|
+
newImporter.wrapMode = importer.wrapMode;
|
|
395
|
+
newImporter.mipmapEnabled = importer.mipmapEnabled;
|
|
396
|
+
newImporter.spritePixelsPerUnit = importer.spritePixelsPerUnit;
|
|
397
|
+
|
|
398
|
+
TextureImporterSettings newSettings = new();
|
|
399
|
+
importer.ReadTextureSettings(newSettings);
|
|
400
|
+
|
|
401
|
+
Vector2 origPivot = GetSpritePivot(importer);
|
|
402
|
+
Vector2 origCenter = new(width * origPivot.x, height * origPivot.y);
|
|
403
|
+
Vector2 newPivotPixels = origCenter - new Vector2(minX, minY);
|
|
404
|
+
Vector2 newPivotNorm = new(
|
|
405
|
+
cropWidth > 0 ? newPivotPixels.x / cropWidth : 0.5f,
|
|
406
|
+
cropHeight > 0 ? newPivotPixels.y / cropHeight : 0.5f
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
newImporter.spriteImportMode = SpriteImportMode.Single;
|
|
410
|
+
newImporter.spritePivot = newPivotNorm;
|
|
411
|
+
newSettings.spritePivot = newPivotNorm;
|
|
412
|
+
newSettings.spriteAlignment = (int)SpriteAlignment.Custom;
|
|
413
|
+
|
|
414
|
+
newImporter.SetTextureSettings(newSettings);
|
|
415
|
+
newImporter.isReadable = true;
|
|
416
|
+
newImporter.SaveAndReimport();
|
|
417
|
+
|
|
418
|
+
TextureImporter resultImporter = newImporter;
|
|
393
419
|
return resultImporter;
|
|
394
420
|
}
|
|
395
421
|
|