From d8a57c3817cba0135120a66f0dae106e5607bd16 Mon Sep 17 00:00:00 2001 From: Lillith Rose Date: Sun, 25 Jan 2026 17:58:14 -0500 Subject: [PATCH] feat(TextureAtlas): Automatically regenerate --- .../TextureAtlasAutoRegen.cs | 67 ++++++ .../TextureAtlasAutoRegen.cs.meta | 11 + .../TextureAtlasGenerator.cs | 217 +++++++++--------- 3 files changed, 189 insertions(+), 106 deletions(-) create mode 100644 TextureAtlasGenerator/TextureAtlasAutoRegen.cs create mode 100644 TextureAtlasGenerator/TextureAtlasAutoRegen.cs.meta diff --git a/TextureAtlasGenerator/TextureAtlasAutoRegen.cs b/TextureAtlasGenerator/TextureAtlasAutoRegen.cs new file mode 100644 index 0000000..16ba269 --- /dev/null +++ b/TextureAtlasGenerator/TextureAtlasAutoRegen.cs @@ -0,0 +1,67 @@ +using UnityEditor; +using UnityEngine; +using System.Linq; + +namespace gay.lilyy.TextureAtlasGenerator +{ + public class TextureAtlasAutoRegen : AssetPostprocessor + { + private const string MenuPath = "LillithRosePup/Import Regens/Texture Atlas"; + private const string PrefKey = "TextureAtlasGenerator.AutoRegen"; + + [MenuItem(MenuPath)] + private static void Toggle() + { + bool enabled = !EditorPrefs.GetBool(PrefKey, true); + EditorPrefs.SetBool(PrefKey, enabled); + Menu.SetChecked(MenuPath, enabled); + } + + [MenuItem(MenuPath, true)] + private static bool ToggleValidate() + { + Menu.SetChecked(MenuPath, EditorPrefs.GetBool(PrefKey, true)); + return true; + } + + private static bool IsEnabled() + { + return EditorPrefs.GetBool(PrefKey, true); + } + static void OnPostprocessAllAssets( + string[] importedAssets, + string[] deletedAssets, + string[] movedAssets, + string[] movedFromAssetPaths) + { + if (!IsEnabled()) + return; + + if (importedAssets.Length == 0) + return; + + var atlases = AssetDatabase + .FindAssets("t:TextureAtlasSettings") + .Select(guid => + AssetDatabase.LoadAssetAtPath( + AssetDatabase.GUIDToAssetPath(guid))) + .Where(s => s && s.textures != null && s.textures.Length > 0) + .ToArray(); + + if (atlases.Length == 0) + return; + + foreach (string path in importedAssets) + { + var tex = AssetDatabase.LoadAssetAtPath(path); + if (!tex) continue; + + foreach (var atlas in atlases) + { + if (atlas.textures.Contains(tex)) + TextureAtlasEditor.GenerateAtlas(atlas); + } + } + } + } +} diff --git a/TextureAtlasGenerator/TextureAtlasAutoRegen.cs.meta b/TextureAtlasGenerator/TextureAtlasAutoRegen.cs.meta new file mode 100644 index 0000000..46dfc71 --- /dev/null +++ b/TextureAtlasGenerator/TextureAtlasAutoRegen.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f62a8a2b00eb0fe4598d1b45218ddfad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TextureAtlasGenerator/TextureAtlasGenerator.cs b/TextureAtlasGenerator/TextureAtlasGenerator.cs index 63c4635..3363c5b 100644 --- a/TextureAtlasGenerator/TextureAtlasGenerator.cs +++ b/TextureAtlasGenerator/TextureAtlasGenerator.cs @@ -5,119 +5,124 @@ using System.IO; namespace gay.lilyy.TextureAtlasGenerator { - [CreateAssetMenu(fileName = "TextureAtlasSettings", menuName = "Texture Atlas/Settings")] - public class TextureAtlasSettings : ScriptableObject + [CreateAssetMenu(fileName = "TextureAtlasSettings", menuName = "Texture Atlas/Settings")] + public class TextureAtlasSettings : ScriptableObject + { + public Texture2D[] textures; + public int atlasSize = 1024; + public int columns = 4; + public int rows = 4; + public string savePath = "Assets/Atlas.png"; + } + + [CustomEditor(typeof(TextureAtlasSettings))] + public class TextureAtlasEditor : Editor + { + private SerializedProperty texturesProp; + private SerializedProperty columnsProp; + private SerializedProperty rowsProp; + + private void OnEnable() { - public Texture2D[] textures; - public int atlasSize = 1024; - public int columns = 4; - public int rows = 4; - public string savePath = "Assets/Atlas.png"; + texturesProp = serializedObject.FindProperty("textures"); + columnsProp = serializedObject.FindProperty("columns"); + rowsProp = serializedObject.FindProperty("rows"); } - [CustomEditor(typeof(TextureAtlasSettings))] - public class TextureAtlasEditor : Editor + public override void OnInspectorGUI() { - private SerializedProperty texturesProp; - private SerializedProperty columnsProp; - private SerializedProperty rowsProp; + serializedObject.Update(); - private void OnEnable() - { - texturesProp = serializedObject.FindProperty("textures"); - columnsProp = serializedObject.FindProperty("columns"); - rowsProp = serializedObject.FindProperty("rows"); - } + EditorGUILayout.LabelField("Texture Atlas Settings", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(serializedObject.FindProperty("atlasSize")); + EditorGUILayout.PropertyField(columnsProp); + EditorGUILayout.PropertyField(rowsProp); + EditorGUILayout.PropertyField(serializedObject.FindProperty("savePath")); - public override void OnInspectorGUI() - { - serializedObject.Update(); + DrawTextureGrid(); - EditorGUILayout.LabelField("Texture Atlas Settings", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(serializedObject.FindProperty("atlasSize")); - EditorGUILayout.PropertyField(columnsProp); - EditorGUILayout.PropertyField(rowsProp); - EditorGUILayout.PropertyField(serializedObject.FindProperty("savePath")); + if (GUILayout.Button("Generate Atlas")) + { + GenerateAtlas(); + } - DrawTextureGrid(); - - if (GUILayout.Button("Generate Atlas")) - { - GenerateAtlas(); - } - - serializedObject.ApplyModifiedProperties(); - } - - private void DrawTextureGrid() - { - int totalSlots = columnsProp.intValue * rowsProp.intValue; - if (texturesProp.arraySize != totalSlots) - texturesProp.arraySize = totalSlots; - - EditorGUILayout.LabelField("Textures Grid", EditorStyles.boldLabel); - int gridWidth = 80; - int gridHeight = 80; - - for (int y = 0; y < rowsProp.intValue; y++) - { - EditorGUILayout.BeginHorizontal(); - for (int x = 0; x < columnsProp.intValue; x++) - { - int index = y * columnsProp.intValue + x; - SerializedProperty textureProp = texturesProp.GetArrayElementAtIndex(index); - textureProp.objectReferenceValue = (Texture2D)EditorGUILayout.ObjectField( - textureProp.objectReferenceValue, typeof(Texture2D), false, - GUILayout.Width(gridWidth), GUILayout.Height(gridHeight)); - } - EditorGUILayout.EndHorizontal(); - } - } - - private void GenerateAtlas() - { - TextureAtlasSettings settings = (TextureAtlasSettings)target; - if (settings.textures == null || settings.textures.Length == 0) - { - Debug.LogError("No textures assigned!"); - return; - } - - Texture2D atlas = new Texture2D(settings.atlasSize, settings.atlasSize); - Color[] blackPixels = new Color[settings.atlasSize * settings.atlasSize]; - for (int i = 0; i < blackPixels.Length; i++) blackPixels[i] = Color.black; - atlas.SetPixels(blackPixels); - - int cellWidth = settings.atlasSize / settings.columns; - int cellHeight = settings.atlasSize / settings.rows; - - for (int i = 0; i < settings.textures.Length; i++) - { - if (settings.textures[i] == null) continue; - int x = (i % settings.columns) * cellWidth; - int y = (settings.rows - 1 - (i / settings.columns)) * cellHeight; - Texture2D resized = ResizeTexture(settings.textures[i], cellWidth, cellHeight); - atlas.SetPixels(x, y, cellWidth, cellHeight, resized.GetPixels(), 0); - } - - atlas.Apply(); - byte[] bytes = atlas.EncodeToPNG(); - File.WriteAllBytes(settings.savePath, bytes); - AssetDatabase.Refresh(); - Debug.Log("Atlas saved at: " + settings.savePath); - } - - - private Texture2D ResizeTexture(Texture2D texture, int width, int height) - { - RenderTexture rt = new RenderTexture(width, height, 32); - Graphics.Blit(texture, rt); - Texture2D result = new Texture2D(width, height); - RenderTexture.active = rt; - result.ReadPixels(new Rect(0, 0, width, height), 0, 0); - result.Apply(); - RenderTexture.active = null; - return result; - } + serializedObject.ApplyModifiedProperties(); } + + private void DrawTextureGrid() + { + int totalSlots = columnsProp.intValue * rowsProp.intValue; + if (texturesProp.arraySize != totalSlots) + texturesProp.arraySize = totalSlots; + + EditorGUILayout.LabelField("Textures Grid", EditorStyles.boldLabel); + int gridWidth = 80; + int gridHeight = 80; + + for (int y = 0; y < rowsProp.intValue; y++) + { + EditorGUILayout.BeginHorizontal(); + for (int x = 0; x < columnsProp.intValue; x++) + { + int index = y * columnsProp.intValue + x; + SerializedProperty textureProp = texturesProp.GetArrayElementAtIndex(index); + textureProp.objectReferenceValue = (Texture2D)EditorGUILayout.ObjectField( + textureProp.objectReferenceValue, typeof(Texture2D), false, + GUILayout.Width(gridWidth), GUILayout.Height(gridHeight)); + } + EditorGUILayout.EndHorizontal(); + } + } + + private void GenerateAtlas() + { + TextureAtlasSettings settings = (TextureAtlasSettings)target; + GenerateAtlas(settings); + } + + internal static void GenerateAtlas(TextureAtlasSettings settings) + { + if (settings.textures == null || settings.textures.Length == 0) + { + Debug.LogError("No textures assigned!"); + return; + } + + Texture2D atlas = new Texture2D(settings.atlasSize, settings.atlasSize); + Color[] blackPixels = new Color[settings.atlasSize * settings.atlasSize]; + for (int i = 0; i < blackPixels.Length; i++) blackPixels[i] = Color.black; + atlas.SetPixels(blackPixels); + + int cellWidth = settings.atlasSize / settings.columns; + int cellHeight = settings.atlasSize / settings.rows; + + for (int i = 0; i < settings.textures.Length; i++) + { + if (settings.textures[i] == null) continue; + int x = (i % settings.columns) * cellWidth; + int y = (settings.rows - 1 - (i / settings.columns)) * cellHeight; + Texture2D resized = ResizeTexture(settings.textures[i], cellWidth, cellHeight); + atlas.SetPixels(x, y, cellWidth, cellHeight, resized.GetPixels(), 0); + } + + atlas.Apply(); + byte[] bytes = atlas.EncodeToPNG(); + File.WriteAllBytes(settings.savePath, bytes); + AssetDatabase.Refresh(); + Debug.Log("Atlas saved at: " + settings.savePath); + } + + + private static Texture2D ResizeTexture(Texture2D texture, int width, int height) + { + RenderTexture rt = new RenderTexture(width, height, 32); + Graphics.Blit(texture, rt); + Texture2D result = new Texture2D(width, height); + RenderTexture.active = rt; + result.ReadPixels(new Rect(0, 0, width, height), 0, 0); + result.Apply(); + RenderTexture.active = null; + return result; + } + } }