com.wallstop-studios.unity-helpers 2.0.0-rc73 → 2.0.0-rc73.10
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 +18 -25
- package/Editor/AnimationEventEditor.cs +11 -23
- package/Editor/FitTextureSizeWindow.cs +9 -9
- package/Editor/PrefabChecker.cs +14 -19
- package/Editor/SpriteAtlasGenerator.cs +503 -206
- package/Editor/SpriteCropper.cs +157 -131
- package/Editor/SpriteSettingsApplier.cs +5 -3
- package/Editor/Utils/GUIHorizontalScope.cs +20 -0
- package/Editor/Utils/GUIHorizontalScope.cs.meta +3 -0
- 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/StringExtensions.cs +49 -0
- 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
|
@@ -7,17 +7,134 @@
|
|
|
7
7
|
using System.Linq;
|
|
8
8
|
using System.Text.RegularExpressions;
|
|
9
9
|
using Core.Extension;
|
|
10
|
-
using
|
|
10
|
+
using Core.Helper;
|
|
11
11
|
using UnityEditor;
|
|
12
12
|
using UnityEditor.U2D;
|
|
13
13
|
using UnityEngine;
|
|
14
14
|
using UnityEngine.U2D;
|
|
15
|
+
using Utils;
|
|
15
16
|
using Object = UnityEngine.Object;
|
|
16
17
|
|
|
17
18
|
public sealed class SpriteAtlasGenerator : EditorWindow
|
|
18
19
|
{
|
|
19
20
|
private const string Name = "Sprite Atlas Generator";
|
|
20
21
|
private const string DefaultPlatformName = "DefaultTexturePlatform";
|
|
22
|
+
private const int MaxAtlasDimension = 8192;
|
|
23
|
+
private const int MaxTextureSize = 16384;
|
|
24
|
+
private const long AtlasAreaBudget = (long)MaxAtlasDimension * MaxAtlasDimension;
|
|
25
|
+
private const int MaxAtlasNameLength = 100;
|
|
26
|
+
|
|
27
|
+
private sealed class AtlasCandidate
|
|
28
|
+
{
|
|
29
|
+
public string OriginalGroupKey { get; }
|
|
30
|
+
public List<Sprite> Sprites { get; }
|
|
31
|
+
public long TotalArea { get; }
|
|
32
|
+
public string CandidateName { get; }
|
|
33
|
+
|
|
34
|
+
public AtlasCandidate(
|
|
35
|
+
string originalGroupKey,
|
|
36
|
+
List<Sprite> sprites,
|
|
37
|
+
string candidateName
|
|
38
|
+
)
|
|
39
|
+
{
|
|
40
|
+
OriginalGroupKey = originalGroupKey;
|
|
41
|
+
Sprites = new List<Sprite>(sprites);
|
|
42
|
+
CandidateName = candidateName;
|
|
43
|
+
TotalArea = 0;
|
|
44
|
+
if (Sprites != null)
|
|
45
|
+
{
|
|
46
|
+
foreach (Sprite sprite in Sprites)
|
|
47
|
+
{
|
|
48
|
+
if (sprite is { rect: { width: > 0, height: > 0 } })
|
|
49
|
+
{
|
|
50
|
+
TotalArea += (long)(sprite.rect.width * sprite.rect.height);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private sealed class MergeableAtlas
|
|
58
|
+
{
|
|
59
|
+
public HashSet<string> OriginalGroupKeys { get; }
|
|
60
|
+
public List<Sprite> Sprites { get; }
|
|
61
|
+
public long TotalArea { get; }
|
|
62
|
+
public string RepresentativeInitialName { get; }
|
|
63
|
+
|
|
64
|
+
public MergeableAtlas(
|
|
65
|
+
string originalGroupKey,
|
|
66
|
+
List<Sprite> initialSprites,
|
|
67
|
+
string initialCandidateName,
|
|
68
|
+
long totalArea
|
|
69
|
+
)
|
|
70
|
+
{
|
|
71
|
+
OriginalGroupKeys = new HashSet<string>(StringComparer.Ordinal)
|
|
72
|
+
{
|
|
73
|
+
originalGroupKey,
|
|
74
|
+
};
|
|
75
|
+
Sprites = initialSprites;
|
|
76
|
+
TotalArea = totalArea;
|
|
77
|
+
RepresentativeInitialName = initialCandidateName;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private MergeableAtlas(
|
|
81
|
+
HashSet<string> combinedKeys,
|
|
82
|
+
List<Sprite> combinedSprites,
|
|
83
|
+
long combinedArea,
|
|
84
|
+
string representativeName
|
|
85
|
+
)
|
|
86
|
+
{
|
|
87
|
+
OriginalGroupKeys = combinedKeys;
|
|
88
|
+
Sprites = combinedSprites;
|
|
89
|
+
TotalArea = combinedArea;
|
|
90
|
+
RepresentativeInitialName = representativeName;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public static MergeableAtlas Merge(MergeableAtlas atlas1, MergeableAtlas atlas2)
|
|
94
|
+
{
|
|
95
|
+
HashSet<string> newKeys = new(atlas1.OriginalGroupKeys, StringComparer.Ordinal);
|
|
96
|
+
newKeys.UnionWith(atlas2.OriginalGroupKeys);
|
|
97
|
+
|
|
98
|
+
List<Sprite> newSprites = new(atlas1.Sprites.Count + atlas2.Sprites.Count);
|
|
99
|
+
newSprites.AddRange(atlas1.Sprites);
|
|
100
|
+
newSprites.AddRange(atlas2.Sprites);
|
|
101
|
+
|
|
102
|
+
long newArea = atlas1.TotalArea + atlas2.TotalArea;
|
|
103
|
+
|
|
104
|
+
return new MergeableAtlas(
|
|
105
|
+
newKeys,
|
|
106
|
+
newSprites,
|
|
107
|
+
newArea,
|
|
108
|
+
atlas1.RepresentativeInitialName
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public string GenerateFinalName()
|
|
113
|
+
{
|
|
114
|
+
if (!OriginalGroupKeys.Any())
|
|
115
|
+
{
|
|
116
|
+
return "EmptyOrInvalidAtlas";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
List<string> sortedKeys = OriginalGroupKeys
|
|
120
|
+
.OrderBy(k => k, StringComparer.Ordinal)
|
|
121
|
+
.ToList();
|
|
122
|
+
string name = string.Join("_", sortedKeys);
|
|
123
|
+
|
|
124
|
+
if (name.Length > MaxAtlasNameLength)
|
|
125
|
+
{
|
|
126
|
+
const string suffix = "_etc";
|
|
127
|
+
int actualLength = MaxAtlasNameLength - suffix.Length;
|
|
128
|
+
if (actualLength <= 0)
|
|
129
|
+
{
|
|
130
|
+
return name.Substring(0, MaxAtlasNameLength);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
name = name.Substring(0, actualLength) + suffix;
|
|
134
|
+
}
|
|
135
|
+
return name;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
21
138
|
|
|
22
139
|
[SerializeField]
|
|
23
140
|
private Object[] _sourceFolders = Array.Empty<Object>();
|
|
@@ -35,8 +152,12 @@
|
|
|
35
152
|
private TextureImporterCompression _compressionLevel =
|
|
36
153
|
TextureImporterCompression.Compressed;
|
|
37
154
|
|
|
155
|
+
[SerializeField]
|
|
156
|
+
private bool _optimizeGroupings = true;
|
|
157
|
+
|
|
38
158
|
private int _matchCount;
|
|
39
159
|
private int _totalCount;
|
|
160
|
+
private GUIStyle _impactButtonStyle;
|
|
40
161
|
|
|
41
162
|
[MenuItem("Tools/Wallstop Studios/Unity Helpers/" + Name)]
|
|
42
163
|
public static void ShowWindow() => GetWindow<SpriteAtlasGenerator>("Atlas Generator");
|
|
@@ -57,38 +178,70 @@
|
|
|
57
178
|
|
|
58
179
|
private void OnGUI()
|
|
59
180
|
{
|
|
181
|
+
_impactButtonStyle ??= new GUIStyle(GUI.skin.button)
|
|
182
|
+
{
|
|
183
|
+
normal = { textColor = Color.yellow },
|
|
184
|
+
fontStyle = FontStyle.Bold,
|
|
185
|
+
};
|
|
60
186
|
GUILayout.Label("Source Folders", EditorStyles.boldLabel);
|
|
61
187
|
SerializedObject so = new(this);
|
|
62
188
|
so.Update();
|
|
63
189
|
EditorGUILayout.PropertyField(so.FindProperty(nameof(_sourceFolders)), true);
|
|
64
190
|
so.ApplyModifiedProperties();
|
|
65
191
|
GUILayout.Space(8);
|
|
66
|
-
|
|
67
|
-
|
|
192
|
+
using (new GUIHorizontalScope())
|
|
193
|
+
{
|
|
194
|
+
EditorGUILayout.LabelField("Sprite Name Regex");
|
|
195
|
+
GUILayout.FlexibleSpace();
|
|
196
|
+
_nameRegex = EditorGUILayout.TextField(_nameRegex);
|
|
197
|
+
}
|
|
68
198
|
|
|
69
199
|
GUILayout.Space(4);
|
|
200
|
+
using (new GUIHorizontalScope())
|
|
201
|
+
{
|
|
202
|
+
if (GUILayout.Button("Calculate Matches"))
|
|
203
|
+
{
|
|
204
|
+
UpdateMatchCounts();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
70
207
|
|
|
71
|
-
|
|
208
|
+
using (new GUIHorizontalScope())
|
|
72
209
|
{
|
|
73
|
-
|
|
210
|
+
EditorGUILayout.LabelField($"Matches: {_matchCount}");
|
|
211
|
+
GUILayout.FlexibleSpace();
|
|
212
|
+
EditorGUILayout.LabelField($"Non-matches: {_totalCount - _matchCount}");
|
|
74
213
|
}
|
|
75
214
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
215
|
+
GUILayout.Space(4);
|
|
216
|
+
using (new GUIHorizontalScope())
|
|
217
|
+
{
|
|
218
|
+
EditorGUILayout.LabelField("Crunch Compression");
|
|
219
|
+
GUILayout.FlexibleSpace();
|
|
220
|
+
_crunchCompression = EditorGUILayout.IntField(_crunchCompression);
|
|
221
|
+
}
|
|
79
222
|
|
|
80
223
|
GUILayout.Space(4);
|
|
81
|
-
|
|
82
|
-
|
|
224
|
+
using (new GUIHorizontalScope())
|
|
225
|
+
{
|
|
226
|
+
EditorGUILayout.LabelField("Compression Level", GUILayout.Width(150));
|
|
227
|
+
_compressionLevel = (TextureImporterCompression)
|
|
228
|
+
EditorGUILayout.EnumPopup(_compressionLevel);
|
|
229
|
+
}
|
|
83
230
|
|
|
84
231
|
GUILayout.Space(4);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
EditorGUILayout.
|
|
232
|
+
using (new GUIHorizontalScope())
|
|
233
|
+
{
|
|
234
|
+
EditorGUILayout.LabelField("Optimize Groupings");
|
|
235
|
+
_optimizeGroupings = EditorGUILayout.Toggle(_optimizeGroupings);
|
|
236
|
+
}
|
|
88
237
|
|
|
89
238
|
GUILayout.Space(12);
|
|
90
|
-
|
|
91
|
-
|
|
239
|
+
using (new GUIHorizontalScope())
|
|
240
|
+
{
|
|
241
|
+
EditorGUILayout.LabelField("Atlas Output Folder");
|
|
242
|
+
EditorGUILayout.LabelField(_outputFolder, EditorStyles.textField);
|
|
243
|
+
}
|
|
244
|
+
|
|
92
245
|
if (GUILayout.Button("Select Output Folder"))
|
|
93
246
|
{
|
|
94
247
|
string absPath = EditorUtility.OpenFolderPanel(
|
|
@@ -96,7 +249,7 @@
|
|
|
96
249
|
Application.dataPath,
|
|
97
250
|
""
|
|
98
251
|
);
|
|
99
|
-
if (!string.
|
|
252
|
+
if (!string.IsNullOrWhiteSpace(absPath))
|
|
100
253
|
{
|
|
101
254
|
if (absPath.StartsWith(Application.dataPath, StringComparison.Ordinal))
|
|
102
255
|
{
|
|
@@ -114,9 +267,12 @@
|
|
|
114
267
|
}
|
|
115
268
|
|
|
116
269
|
GUILayout.Space(12);
|
|
117
|
-
|
|
270
|
+
using (new GUIHorizontalScope())
|
|
118
271
|
{
|
|
119
|
-
|
|
272
|
+
if (GUILayout.Button("Generate Atlases", _impactButtonStyle))
|
|
273
|
+
{
|
|
274
|
+
GenerateAtlases();
|
|
275
|
+
}
|
|
120
276
|
}
|
|
121
277
|
}
|
|
122
278
|
|
|
@@ -136,47 +292,54 @@
|
|
|
136
292
|
return;
|
|
137
293
|
}
|
|
138
294
|
|
|
139
|
-
|
|
295
|
+
try
|
|
140
296
|
{
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
string folderPath = AssetDatabase.GetAssetPath(obj);
|
|
147
|
-
if (string.IsNullOrEmpty(folderPath) || !AssetDatabase.IsValidFolder(folderPath))
|
|
297
|
+
float total = _sourceFolders.Length;
|
|
298
|
+
foreach (Object obj in _sourceFolders.Where(Objects.NotNull))
|
|
148
299
|
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
foreach (string guid in guids)
|
|
155
|
-
{
|
|
156
|
-
string path = AssetDatabase.GUIDToAssetPath(guid);
|
|
157
|
-
|
|
158
|
-
Object[] assets = AssetDatabase.LoadAllAssetsAtPath(path);
|
|
159
|
-
if (assets == null)
|
|
300
|
+
string folderPath = AssetDatabase.GetAssetPath(obj);
|
|
301
|
+
if (
|
|
302
|
+
string.IsNullOrWhiteSpace(folderPath)
|
|
303
|
+
|| !AssetDatabase.IsValidFolder(folderPath)
|
|
304
|
+
)
|
|
160
305
|
{
|
|
306
|
+
this.LogWarn($"Skipping invalid or null source folder entry.");
|
|
161
307
|
continue;
|
|
162
308
|
}
|
|
163
309
|
|
|
164
|
-
|
|
165
|
-
|
|
310
|
+
string[] guids = AssetDatabase.FindAssets("t:Sprite", new[] { folderPath });
|
|
311
|
+
for (int i = 0; i < guids.Length; ++i)
|
|
166
312
|
{
|
|
167
|
-
|
|
313
|
+
EditorUtility.DisplayProgressBar(
|
|
314
|
+
Name,
|
|
315
|
+
"Calculating...",
|
|
316
|
+
i * 1f / guids.Length / total
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
string guid = guids[i];
|
|
320
|
+
string path = AssetDatabase.GUIDToAssetPath(guid);
|
|
321
|
+
|
|
322
|
+
Object[] assets = AssetDatabase.LoadAllAssetsAtPath(path);
|
|
323
|
+
if (assets == null)
|
|
168
324
|
{
|
|
169
325
|
continue;
|
|
170
326
|
}
|
|
171
327
|
|
|
172
|
-
|
|
173
|
-
if (regex.IsMatch(sp.name))
|
|
328
|
+
foreach (Sprite sp in assets.OfType<Sprite>().Where(Objects.NotNull))
|
|
174
329
|
{
|
|
175
|
-
|
|
330
|
+
_totalCount++;
|
|
331
|
+
if (regex.IsMatch(sp.name))
|
|
332
|
+
{
|
|
333
|
+
_matchCount++;
|
|
334
|
+
}
|
|
176
335
|
}
|
|
177
336
|
}
|
|
178
337
|
}
|
|
179
338
|
}
|
|
339
|
+
finally
|
|
340
|
+
{
|
|
341
|
+
EditorUtility.ClearProgressBar();
|
|
342
|
+
}
|
|
180
343
|
|
|
181
344
|
Repaint();
|
|
182
345
|
}
|
|
@@ -185,6 +348,7 @@
|
|
|
185
348
|
{
|
|
186
349
|
List<SpriteAtlas> atlases = new();
|
|
187
350
|
int processed = 0;
|
|
351
|
+
AssetDatabase.StartAssetEditing();
|
|
188
352
|
try
|
|
189
353
|
{
|
|
190
354
|
EditorUtility.DisplayProgressBar(Name, "Initializing...", 0f);
|
|
@@ -195,11 +359,7 @@
|
|
|
195
359
|
return;
|
|
196
360
|
}
|
|
197
361
|
|
|
198
|
-
if (
|
|
199
|
-
_sourceFolders == null
|
|
200
|
-
|| _sourceFolders.Length == 0
|
|
201
|
-
|| _sourceFolders.All(f => f == null)
|
|
202
|
-
)
|
|
362
|
+
if (_sourceFolders == null || Array.TrueForAll(_sourceFolders, Objects.Null))
|
|
203
363
|
{
|
|
204
364
|
this.LogError($"No valid source folders specified.");
|
|
205
365
|
EditorUtility.ClearProgressBar();
|
|
@@ -212,7 +372,10 @@
|
|
|
212
372
|
{
|
|
213
373
|
string parent = Path.GetDirectoryName(_outputFolder);
|
|
214
374
|
string newFolderName = Path.GetFileName(_outputFolder);
|
|
215
|
-
if (
|
|
375
|
+
if (
|
|
376
|
+
string.IsNullOrWhiteSpace(parent)
|
|
377
|
+
|| string.IsNullOrWhiteSpace(newFolderName)
|
|
378
|
+
)
|
|
216
379
|
{
|
|
217
380
|
this.LogError($"Output folder path '{_outputFolder}' is invalid.");
|
|
218
381
|
EditorUtility.ClearProgressBar();
|
|
@@ -237,11 +400,11 @@
|
|
|
237
400
|
}
|
|
238
401
|
}
|
|
239
402
|
|
|
240
|
-
EditorUtility.DisplayProgressBar(Name, "Deleting old atlases...", 0.
|
|
403
|
+
EditorUtility.DisplayProgressBar(Name, "Deleting old atlases...", 0.05f);
|
|
241
404
|
string[] existing = AssetDatabase
|
|
242
405
|
.FindAssets("t:SpriteAtlas", new[] { _outputFolder })
|
|
243
406
|
.Select(AssetDatabase.GUIDToAssetPath)
|
|
244
|
-
.Where(
|
|
407
|
+
.Where(path => !string.IsNullOrWhiteSpace(path))
|
|
245
408
|
.ToArray();
|
|
246
409
|
|
|
247
410
|
if (existing.Length > 0)
|
|
@@ -257,11 +420,15 @@
|
|
|
257
420
|
AssetDatabase.Refresh();
|
|
258
421
|
}
|
|
259
422
|
|
|
260
|
-
EditorUtility.DisplayProgressBar(
|
|
423
|
+
EditorUtility.DisplayProgressBar(
|
|
424
|
+
Name,
|
|
425
|
+
"Scanning sprites & initial grouping...",
|
|
426
|
+
0.1f
|
|
427
|
+
);
|
|
261
428
|
Regex regex;
|
|
262
429
|
try
|
|
263
430
|
{
|
|
264
|
-
regex = new(_nameRegex);
|
|
431
|
+
regex = new Regex(_nameRegex);
|
|
265
432
|
}
|
|
266
433
|
catch (ArgumentException ex)
|
|
267
434
|
{
|
|
@@ -273,16 +440,12 @@
|
|
|
273
440
|
}
|
|
274
441
|
Dictionary<string, List<Sprite>> groups = new(StringComparer.Ordinal);
|
|
275
442
|
|
|
276
|
-
float
|
|
277
|
-
|
|
443
|
+
float sourceFolderIncrement =
|
|
444
|
+
_sourceFolders.Length > 0 ? 0.2f / _sourceFolders.Length : 0f;
|
|
445
|
+
float sourceFolderProgress = 0.1f;
|
|
278
446
|
|
|
279
|
-
foreach (Object sourceDirectory in _sourceFolders)
|
|
447
|
+
foreach (Object sourceDirectory in _sourceFolders.Where(Objects.NotNull))
|
|
280
448
|
{
|
|
281
|
-
if (sourceDirectory == null)
|
|
282
|
-
{
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
449
|
string folderPath = AssetDatabase.GetAssetPath(sourceDirectory);
|
|
287
450
|
if (!AssetDatabase.IsValidFolder(folderPath))
|
|
288
451
|
{
|
|
@@ -295,9 +458,9 @@
|
|
|
295
458
|
EditorUtility.DisplayProgressBar(
|
|
296
459
|
Name,
|
|
297
460
|
$"Scanning folder '{folderPath}'...",
|
|
298
|
-
|
|
461
|
+
sourceFolderProgress
|
|
299
462
|
);
|
|
300
|
-
|
|
463
|
+
sourceFolderProgress += sourceFolderIncrement;
|
|
301
464
|
foreach (
|
|
302
465
|
string assetGuid in AssetDatabase.FindAssets(
|
|
303
466
|
"t:Sprite",
|
|
@@ -306,7 +469,7 @@
|
|
|
306
469
|
)
|
|
307
470
|
{
|
|
308
471
|
string assetPath = AssetDatabase.GUIDToAssetPath(assetGuid);
|
|
309
|
-
if (string.
|
|
472
|
+
if (string.IsNullOrWhiteSpace(assetPath))
|
|
310
473
|
{
|
|
311
474
|
continue;
|
|
312
475
|
}
|
|
@@ -317,13 +480,8 @@
|
|
|
317
480
|
continue;
|
|
318
481
|
}
|
|
319
482
|
|
|
320
|
-
foreach (Sprite sub in allAssets.OfType<Sprite>())
|
|
483
|
+
foreach (Sprite sub in allAssets.OfType<Sprite>().Where(Objects.NotNull))
|
|
321
484
|
{
|
|
322
|
-
if (sub == null)
|
|
323
|
-
{
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
485
|
string assetName = sub.name;
|
|
328
486
|
if (!regex.IsMatch(assetName))
|
|
329
487
|
{
|
|
@@ -335,43 +493,37 @@
|
|
|
335
493
|
groups.GetOrAdd(key).Add(sub);
|
|
336
494
|
}
|
|
337
495
|
}
|
|
338
|
-
currentProgress += sourceFolderProgressIncrement;
|
|
339
496
|
}
|
|
340
497
|
|
|
341
|
-
const int atlasSize = 8192;
|
|
342
|
-
const long budget = (long)atlasSize * atlasSize;
|
|
343
498
|
int totalChunks = 0;
|
|
344
499
|
Dictionary<string, List<List<Sprite>>> groupChunks = new();
|
|
345
|
-
|
|
346
|
-
EditorUtility.DisplayProgressBar(Name, "Calculating chunks...", 0.4f);
|
|
347
|
-
|
|
500
|
+
EditorUtility.DisplayProgressBar(Name, "Calculating chunks...", 0.3f);
|
|
348
501
|
foreach (KeyValuePair<string, List<Sprite>> kv in groups)
|
|
349
502
|
{
|
|
350
|
-
List<Sprite>
|
|
351
|
-
.Value.
|
|
503
|
+
List<Sprite> spritesInGroup = kv
|
|
504
|
+
.Value.Where(Objects.NotNull)
|
|
505
|
+
.Where(sprite => sprite.rect is { width: > 0, height: > 0 })
|
|
506
|
+
.OrderByDescending(sprite => sprite.rect.width * sprite.rect.height)
|
|
352
507
|
.ToList();
|
|
508
|
+
if (!spritesInGroup.Any())
|
|
509
|
+
{
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
|
|
353
513
|
List<List<Sprite>> chunks = new();
|
|
354
514
|
List<Sprite> current = new();
|
|
355
515
|
long currentArea = 0;
|
|
356
|
-
foreach (Sprite sprite in
|
|
516
|
+
foreach (Sprite sprite in spritesInGroup)
|
|
357
517
|
{
|
|
358
|
-
if (sprite == null || sprite.rect.width <= 0 || sprite.rect.height <= 0)
|
|
359
|
-
{
|
|
360
|
-
this.LogWarn(
|
|
361
|
-
$"Skipping invalid sprite '{sprite?.name ?? "null"}' in group '{kv.Key}'."
|
|
362
|
-
);
|
|
363
|
-
continue;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
518
|
long area = (long)(sprite.rect.width * sprite.rect.height);
|
|
367
|
-
if (area >
|
|
519
|
+
if (area > AtlasAreaBudget)
|
|
368
520
|
{
|
|
369
521
|
this.LogWarn(
|
|
370
522
|
$"Sprite '{sprite.name}' ({sprite.rect.width}x{sprite.rect.height}) is larger than max atlas area budget and will be placed in its own atlas chunk."
|
|
371
523
|
);
|
|
372
524
|
continue;
|
|
373
525
|
}
|
|
374
|
-
if (currentArea + area <=
|
|
526
|
+
if (currentArea + area <= AtlasAreaBudget && current.Count < 2000)
|
|
375
527
|
{
|
|
376
528
|
current.Add(sprite);
|
|
377
529
|
currentArea += area;
|
|
@@ -408,166 +560,307 @@
|
|
|
408
560
|
return;
|
|
409
561
|
}
|
|
410
562
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
float atlasCreationProgressRange = 0.5f;
|
|
414
|
-
|
|
415
|
-
foreach ((string prefix, List<List<Sprite>> chunks) in groupChunks)
|
|
563
|
+
List<(string Name, List<Sprite> Sprites)> finalAtlasesData;
|
|
564
|
+
if (_optimizeGroupings)
|
|
416
565
|
{
|
|
417
|
-
|
|
566
|
+
EditorUtility.DisplayProgressBar(
|
|
567
|
+
Name,
|
|
568
|
+
"Preparing for merge optimization...",
|
|
569
|
+
0.4f
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
List<AtlasCandidate> allInitialCandidates = new();
|
|
573
|
+
foreach (
|
|
574
|
+
(
|
|
575
|
+
string originalGroupKey,
|
|
576
|
+
List<List<Sprite>> chunksForThisGroup
|
|
577
|
+
) in groupChunks
|
|
578
|
+
)
|
|
418
579
|
{
|
|
419
|
-
|
|
420
|
-
if (chunk == null || chunk.Count == 0)
|
|
580
|
+
for (int i = 0; i < chunksForThisGroup.Count; ++i)
|
|
421
581
|
{
|
|
422
|
-
|
|
582
|
+
if (!chunksForThisGroup[i].Any())
|
|
583
|
+
{
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
string candidateName =
|
|
588
|
+
chunksForThisGroup.Count > 1
|
|
589
|
+
? $"{originalGroupKey}_{i}"
|
|
590
|
+
: originalGroupKey;
|
|
591
|
+
allInitialCandidates.Add(
|
|
592
|
+
new AtlasCandidate(
|
|
593
|
+
originalGroupKey,
|
|
594
|
+
chunksForThisGroup[i],
|
|
595
|
+
candidateName
|
|
596
|
+
)
|
|
597
|
+
);
|
|
423
598
|
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
allInitialCandidates = allInitialCandidates
|
|
602
|
+
.OrderByDescending(candidate => candidate.TotalArea)
|
|
603
|
+
.ThenBy(candidate => candidate.CandidateName, StringComparer.Ordinal)
|
|
604
|
+
.ToList();
|
|
424
605
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
606
|
+
List<MergeableAtlas> workingAtlases = allInitialCandidates
|
|
607
|
+
.Select(candidate => new MergeableAtlas(
|
|
608
|
+
candidate.OriginalGroupKey,
|
|
609
|
+
candidate.Sprites,
|
|
610
|
+
candidate.CandidateName,
|
|
611
|
+
candidate.TotalArea
|
|
612
|
+
))
|
|
613
|
+
.ToList();
|
|
614
|
+
int passNumber = 0;
|
|
615
|
+
const float mergeOptimizationProgressStart = 0.3f;
|
|
616
|
+
const float mergeOptimizationProgressRange = 0.5f;
|
|
428
617
|
|
|
429
|
-
|
|
618
|
+
while (true)
|
|
619
|
+
{
|
|
620
|
+
passNumber++;
|
|
621
|
+
bool mergedInThisPass = false;
|
|
622
|
+
float currentPassProgress =
|
|
623
|
+
mergeOptimizationProgressStart
|
|
624
|
+
+ passNumber * (mergeOptimizationProgressRange / 15f);
|
|
430
625
|
EditorUtility.DisplayProgressBar(
|
|
431
626
|
Name,
|
|
432
|
-
$"
|
|
433
|
-
|
|
627
|
+
$"Optimizing atlas count (Pass {passNumber}, {workingAtlases.Count} atlases)...",
|
|
628
|
+
Mathf.Min(
|
|
629
|
+
currentPassProgress,
|
|
630
|
+
mergeOptimizationProgressStart + mergeOptimizationProgressRange
|
|
631
|
+
)
|
|
434
632
|
);
|
|
435
633
|
|
|
436
|
-
|
|
437
|
-
|
|
634
|
+
workingAtlases = workingAtlases
|
|
635
|
+
.OrderByDescending(atlas => atlas.TotalArea)
|
|
636
|
+
.ThenBy(
|
|
637
|
+
atlas => atlas.RepresentativeInitialName,
|
|
638
|
+
StringComparer.Ordinal
|
|
639
|
+
)
|
|
640
|
+
.ToList();
|
|
438
641
|
|
|
439
|
-
|
|
440
|
-
packingSettings.enableTightPacking = true;
|
|
441
|
-
packingSettings.padding = 4;
|
|
442
|
-
packingSettings.enableRotation = false;
|
|
443
|
-
atlas.SetPackingSettings(packingSettings);
|
|
642
|
+
bool[] isSubsumed = new bool[workingAtlases.Count];
|
|
444
643
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
644
|
+
for (int i = 0; i < workingAtlases.Count; ++i)
|
|
645
|
+
{
|
|
646
|
+
if (isSubsumed[i])
|
|
647
|
+
{
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
MergeableAtlas baseAtlas = workingAtlases[i];
|
|
652
|
+
string baseRepresentativeKey = baseAtlas
|
|
653
|
+
.OriginalGroupKeys.OrderBy(key => key, StringComparer.Ordinal)
|
|
654
|
+
.First();
|
|
450
655
|
|
|
451
|
-
|
|
452
|
-
|
|
656
|
+
int bestPartnerIndex = -1;
|
|
657
|
+
MergeableAtlas bestPartnerObject = null;
|
|
658
|
+
int currentMinLevenshtein = int.MaxValue;
|
|
453
659
|
|
|
454
|
-
|
|
660
|
+
for (int j = i + 1; j < workingAtlases.Count; ++j)
|
|
661
|
+
{
|
|
662
|
+
if (isSubsumed[j])
|
|
663
|
+
{
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
MergeableAtlas potentialPartner = workingAtlases[j];
|
|
668
|
+
if (
|
|
669
|
+
baseAtlas.TotalArea + potentialPartner.TotalArea
|
|
670
|
+
> AtlasAreaBudget
|
|
671
|
+
)
|
|
672
|
+
{
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
string partnerRepresentativeKey = potentialPartner
|
|
677
|
+
.OriginalGroupKeys.OrderBy(key => key, StringComparer.Ordinal)
|
|
678
|
+
.First();
|
|
679
|
+
int distance = baseRepresentativeKey.LevenshteinDistance(
|
|
680
|
+
partnerRepresentativeKey
|
|
681
|
+
);
|
|
682
|
+
bool updateBest = false;
|
|
683
|
+
if (bestPartnerObject == null || distance < currentMinLevenshtein)
|
|
684
|
+
{
|
|
685
|
+
updateBest = true;
|
|
686
|
+
}
|
|
687
|
+
else if (distance == currentMinLevenshtein)
|
|
688
|
+
{
|
|
689
|
+
if (
|
|
690
|
+
potentialPartner.TotalArea > bestPartnerObject.TotalArea
|
|
691
|
+
|| (
|
|
692
|
+
potentialPartner.TotalArea
|
|
693
|
+
== bestPartnerObject.TotalArea
|
|
694
|
+
&& string.Compare(
|
|
695
|
+
potentialPartner.RepresentativeInitialName,
|
|
696
|
+
bestPartnerObject.RepresentativeInitialName,
|
|
697
|
+
StringComparison.Ordinal
|
|
698
|
+
) < 0
|
|
699
|
+
)
|
|
700
|
+
)
|
|
701
|
+
{
|
|
702
|
+
updateBest = true;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
if (updateBest)
|
|
706
|
+
{
|
|
707
|
+
currentMinLevenshtein = distance;
|
|
708
|
+
bestPartnerObject = potentialPartner;
|
|
709
|
+
bestPartnerIndex = j;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (bestPartnerObject != null)
|
|
713
|
+
{
|
|
714
|
+
workingAtlases[i] = MergeableAtlas.Merge(
|
|
715
|
+
baseAtlas,
|
|
716
|
+
bestPartnerObject
|
|
717
|
+
);
|
|
718
|
+
isSubsumed[bestPartnerIndex] = true;
|
|
719
|
+
mergedInThisPass = true;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
if (!mergedInThisPass)
|
|
723
|
+
{
|
|
724
|
+
break;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
workingAtlases = workingAtlases.Where((_, k) => !isSubsumed[k]).ToList();
|
|
728
|
+
if (passNumber > 100)
|
|
455
729
|
{
|
|
456
|
-
platformSettings = new TextureImporterPlatformSettings();
|
|
457
|
-
platformSettings.name = DefaultPlatformName;
|
|
458
730
|
this.LogWarn(
|
|
459
|
-
$"
|
|
731
|
+
$"Merge optimization exceeded 100 passes, aborting merge loop."
|
|
460
732
|
);
|
|
733
|
+
break;
|
|
461
734
|
}
|
|
735
|
+
}
|
|
462
736
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
737
|
+
finalAtlasesData = workingAtlases
|
|
738
|
+
.Select(atlas => (Name: atlas.GenerateFinalName(), atlas.Sprites))
|
|
739
|
+
.OrderBy(atlas => atlas.Name, StringComparer.Ordinal)
|
|
740
|
+
.ToList();
|
|
741
|
+
}
|
|
742
|
+
else
|
|
743
|
+
{
|
|
744
|
+
finalAtlasesData = groupChunks
|
|
745
|
+
.SelectMany(chunk =>
|
|
469
746
|
{
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
747
|
+
string prefix = chunk.Key;
|
|
748
|
+
List<List<Sprite>> chunks = chunk.Value;
|
|
749
|
+
List<(string, List<Sprite>)> finalChunks = new();
|
|
750
|
+
for (int i = 0; i < chunks.Count; ++i)
|
|
751
|
+
{
|
|
752
|
+
string atlasName = chunks.Count > 1 ? $"{prefix}_{i}" : prefix;
|
|
753
|
+
finalChunks.Add((atlasName, chunks[i]));
|
|
754
|
+
}
|
|
755
|
+
return finalChunks;
|
|
756
|
+
})
|
|
757
|
+
.ToList();
|
|
758
|
+
int chunkIndex = 0;
|
|
759
|
+
const float atlasCreationProgressStart = 0.45f;
|
|
760
|
+
const float atlasCreationProgressRange = 0.5f;
|
|
761
|
+
|
|
762
|
+
foreach ((string prefix, List<List<Sprite>> chunks) in groupChunks)
|
|
763
|
+
{
|
|
764
|
+
for (int i = 0; i < chunks.Count; ++i)
|
|
474
765
|
{
|
|
475
|
-
|
|
766
|
+
List<Sprite> chunk = chunks[i];
|
|
767
|
+
if (chunk is not { Count: > 0 })
|
|
476
768
|
{
|
|
477
|
-
|
|
478
|
-
$"Invalid crunch compression: {_crunchCompression}. Using default (off)."
|
|
479
|
-
);
|
|
769
|
+
continue;
|
|
480
770
|
}
|
|
481
|
-
platformSettings.crunchedCompression = false;
|
|
482
|
-
platformSettings.compressionQuality = 50;
|
|
483
|
-
}
|
|
484
771
|
|
|
485
|
-
|
|
772
|
+
float progress =
|
|
773
|
+
atlasCreationProgressStart
|
|
774
|
+
+ atlasCreationProgressRange * (chunkIndex / (float)totalChunks);
|
|
486
775
|
|
|
487
|
-
|
|
488
|
-
.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
{
|
|
493
|
-
this.LogWarn(
|
|
494
|
-
$"Skipping atlas '{atlasName}' as it contained no valid sprites after filtering."
|
|
776
|
+
string atlasName = chunks.Count > 1 ? $"{prefix}_{i}" : prefix;
|
|
777
|
+
EditorUtility.DisplayProgressBar(
|
|
778
|
+
Name,
|
|
779
|
+
$"Creating atlas '{atlasName}' ({i + 1}/{chunks.Count})... Sprites: {chunk.Count}",
|
|
780
|
+
progress
|
|
495
781
|
);
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
else
|
|
499
|
-
{
|
|
500
|
-
atlas.Add(validSprites);
|
|
501
|
-
atlas.SetIncludeInBuild(true);
|
|
502
|
-
string path = Path.Combine(_outputFolder, atlasName + ".spriteatlas");
|
|
503
|
-
path = AssetDatabase.GenerateUniqueAssetPath(path);
|
|
504
|
-
AssetDatabase.CreateAsset(atlas, path);
|
|
505
|
-
processed++;
|
|
782
|
+
|
|
783
|
+
chunkIndex++;
|
|
506
784
|
}
|
|
507
|
-
chunkIndex++;
|
|
508
785
|
}
|
|
509
786
|
}
|
|
510
787
|
|
|
511
|
-
|
|
788
|
+
foreach ((string atlasName, List<Sprite> sprites) in finalAtlasesData)
|
|
512
789
|
{
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
790
|
+
SpriteAtlas atlas = new();
|
|
791
|
+
atlases.Add(atlas);
|
|
792
|
+
|
|
793
|
+
SpriteAtlasPackingSettings packingSettings = atlas.GetPackingSettings();
|
|
794
|
+
packingSettings.enableTightPacking = true;
|
|
795
|
+
packingSettings.padding = 4;
|
|
796
|
+
packingSettings.enableRotation = false;
|
|
797
|
+
atlas.SetPackingSettings(packingSettings);
|
|
798
|
+
|
|
799
|
+
SpriteAtlasTextureSettings textureSettings = atlas.GetTextureSettings();
|
|
800
|
+
textureSettings.generateMipMaps = false;
|
|
801
|
+
textureSettings.filterMode = FilterMode.Bilinear;
|
|
802
|
+
textureSettings.readable = true;
|
|
803
|
+
atlas.SetTextureSettings(textureSettings);
|
|
804
|
+
|
|
805
|
+
TextureImporterPlatformSettings platformSettings = atlas.GetPlatformSettings(
|
|
806
|
+
DefaultPlatformName
|
|
521
807
|
);
|
|
522
808
|
|
|
523
|
-
|
|
524
|
-
EditorUtility.DisplayProgressBar(Name, "Optimizing atlas sizes...", 0.98f);
|
|
525
|
-
foreach (
|
|
526
|
-
SpriteAtlas atlas in atlases
|
|
527
|
-
.Select(AssetDatabase.GetAssetPath)
|
|
528
|
-
.Where(p => !string.IsNullOrEmpty(p))
|
|
529
|
-
.Select(AssetDatabase.LoadAssetAtPath<SpriteAtlas>)
|
|
530
|
-
.Where(a => a != null)
|
|
531
|
-
)
|
|
809
|
+
if (platformSettings == null)
|
|
532
810
|
{
|
|
533
|
-
|
|
534
|
-
if (preview == null)
|
|
811
|
+
platformSettings = new TextureImporterPlatformSettings
|
|
535
812
|
{
|
|
536
|
-
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
atlas.GetPlatformSettings(DefaultPlatformName);
|
|
541
|
-
if (platformSettings is not { overridden: true })
|
|
542
|
-
{
|
|
543
|
-
continue;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
int actualWidth = preview.width;
|
|
547
|
-
int actualHeight = preview.height;
|
|
548
|
-
int newMaxSize = Mathf.Max(
|
|
549
|
-
Mathf.NextPowerOfTwo(actualWidth),
|
|
550
|
-
Mathf.NextPowerOfTwo(actualHeight)
|
|
813
|
+
name = DefaultPlatformName,
|
|
814
|
+
};
|
|
815
|
+
this.LogWarn(
|
|
816
|
+
$"Could not get default platform settings for {atlasName}. Creating new default."
|
|
551
817
|
);
|
|
552
|
-
|
|
818
|
+
}
|
|
553
819
|
|
|
554
|
-
|
|
820
|
+
platformSettings.overridden = true;
|
|
821
|
+
platformSettings.maxTextureSize = MaxAtlasDimension;
|
|
822
|
+
platformSettings.textureCompression = _compressionLevel;
|
|
823
|
+
platformSettings.format = TextureImporterFormat.Automatic;
|
|
824
|
+
|
|
825
|
+
if (_crunchCompression is >= 0 and <= 100)
|
|
826
|
+
{
|
|
827
|
+
platformSettings.crunchedCompression = true;
|
|
828
|
+
platformSettings.compressionQuality = _crunchCompression;
|
|
829
|
+
}
|
|
830
|
+
else
|
|
831
|
+
{
|
|
832
|
+
if (100 < _crunchCompression)
|
|
555
833
|
{
|
|
556
|
-
this.
|
|
557
|
-
$"
|
|
834
|
+
this.LogWarn(
|
|
835
|
+
$"Invalid crunch compression: {_crunchCompression}. Using default (off)."
|
|
558
836
|
);
|
|
559
|
-
platformSettings.maxTextureSize = newMaxSize;
|
|
560
|
-
atlas.SetPlatformSettings(platformSettings);
|
|
561
|
-
EditorUtility.SetDirty(atlas);
|
|
562
|
-
anyChanged = true;
|
|
563
837
|
}
|
|
838
|
+
|
|
839
|
+
platformSettings.crunchedCompression = false;
|
|
840
|
+
platformSettings.compressionQuality = 50;
|
|
564
841
|
}
|
|
565
842
|
|
|
566
|
-
|
|
843
|
+
atlas.SetPlatformSettings(platformSettings);
|
|
844
|
+
|
|
845
|
+
Object[] validSprites = sprites
|
|
846
|
+
.Select(sprite => sprite as Object)
|
|
847
|
+
.Where(Objects.NotNull)
|
|
848
|
+
.ToArray();
|
|
849
|
+
if (validSprites.Length == 0)
|
|
567
850
|
{
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
851
|
+
this.LogWarn(
|
|
852
|
+
$"Skipping atlas '{atlasName}' as it contained no valid sprites after filtering."
|
|
853
|
+
);
|
|
854
|
+
atlases.Remove(atlas);
|
|
855
|
+
}
|
|
856
|
+
else
|
|
857
|
+
{
|
|
858
|
+
atlas.Add(validSprites);
|
|
859
|
+
atlas.SetIncludeInBuild(true);
|
|
860
|
+
string path = Path.Combine(_outputFolder, atlasName + ".spriteatlas");
|
|
861
|
+
path = AssetDatabase.GenerateUniqueAssetPath(path);
|
|
862
|
+
AssetDatabase.CreateAsset(atlas, path);
|
|
863
|
+
processed++;
|
|
571
864
|
}
|
|
572
865
|
}
|
|
573
866
|
}
|
|
@@ -577,11 +870,15 @@
|
|
|
577
870
|
}
|
|
578
871
|
finally
|
|
579
872
|
{
|
|
873
|
+
AssetDatabase.StopAssetEditing();
|
|
580
874
|
EditorUtility.ClearProgressBar();
|
|
581
875
|
}
|
|
582
876
|
|
|
583
877
|
if (processed > 0)
|
|
584
878
|
{
|
|
879
|
+
AssetDatabase.SaveAssets();
|
|
880
|
+
AssetDatabase.Refresh();
|
|
881
|
+
SpriteAtlasUtility.PackAllAtlases(EditorUserBuildSettings.activeBuildTarget, false);
|
|
585
882
|
this.Log(
|
|
586
883
|
$"[SpriteAtlasGenerator] Successfully created or updated {processed} atlases in '{_outputFolder}'."
|
|
587
884
|
);
|