feat(TextureAtlas): Automatically regenerate
This commit is contained in:
parent
c361ad2945
commit
d8a57c3817
3 changed files with 189 additions and 106 deletions
67
TextureAtlasGenerator/TextureAtlasAutoRegen.cs
Normal file
67
TextureAtlasGenerator/TextureAtlasAutoRegen.cs
Normal file
|
|
@ -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<TextureAtlasSettings>(
|
||||||
|
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<Texture2D>(path);
|
||||||
|
if (!tex) continue;
|
||||||
|
|
||||||
|
foreach (var atlas in atlases)
|
||||||
|
{
|
||||||
|
if (atlas.textures.Contains(tex))
|
||||||
|
TextureAtlasEditor.GenerateAtlas(atlas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
TextureAtlasGenerator/TextureAtlasAutoRegen.cs.meta
Normal file
11
TextureAtlasGenerator/TextureAtlasAutoRegen.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f62a8a2b00eb0fe4598d1b45218ddfad
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -5,119 +5,124 @@ using System.IO;
|
||||||
|
|
||||||
namespace gay.lilyy.TextureAtlasGenerator
|
namespace gay.lilyy.TextureAtlasGenerator
|
||||||
{
|
{
|
||||||
[CreateAssetMenu(fileName = "TextureAtlasSettings", menuName = "Texture Atlas/Settings")]
|
[CreateAssetMenu(fileName = "TextureAtlasSettings", menuName = "Texture Atlas/Settings")]
|
||||||
public class TextureAtlasSettings : ScriptableObject
|
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;
|
texturesProp = serializedObject.FindProperty("textures");
|
||||||
public int atlasSize = 1024;
|
columnsProp = serializedObject.FindProperty("columns");
|
||||||
public int columns = 4;
|
rowsProp = serializedObject.FindProperty("rows");
|
||||||
public int rows = 4;
|
|
||||||
public string savePath = "Assets/Atlas.png";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomEditor(typeof(TextureAtlasSettings))]
|
public override void OnInspectorGUI()
|
||||||
public class TextureAtlasEditor : Editor
|
|
||||||
{
|
{
|
||||||
private SerializedProperty texturesProp;
|
serializedObject.Update();
|
||||||
private SerializedProperty columnsProp;
|
|
||||||
private SerializedProperty rowsProp;
|
|
||||||
|
|
||||||
private void OnEnable()
|
EditorGUILayout.LabelField("Texture Atlas Settings", EditorStyles.boldLabel);
|
||||||
{
|
EditorGUILayout.PropertyField(serializedObject.FindProperty("atlasSize"));
|
||||||
texturesProp = serializedObject.FindProperty("textures");
|
EditorGUILayout.PropertyField(columnsProp);
|
||||||
columnsProp = serializedObject.FindProperty("columns");
|
EditorGUILayout.PropertyField(rowsProp);
|
||||||
rowsProp = serializedObject.FindProperty("rows");
|
EditorGUILayout.PropertyField(serializedObject.FindProperty("savePath"));
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnInspectorGUI()
|
DrawTextureGrid();
|
||||||
{
|
|
||||||
serializedObject.Update();
|
|
||||||
|
|
||||||
EditorGUILayout.LabelField("Texture Atlas Settings", EditorStyles.boldLabel);
|
if (GUILayout.Button("Generate Atlas"))
|
||||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("atlasSize"));
|
{
|
||||||
EditorGUILayout.PropertyField(columnsProp);
|
GenerateAtlas();
|
||||||
EditorGUILayout.PropertyField(rowsProp);
|
}
|
||||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("savePath"));
|
|
||||||
|
|
||||||
DrawTextureGrid();
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue