Files
DreadScripts-Archive/TextureUtility/Editor/TextureAutoPacker.cs
2025-07-19 01:03:02 +02:00

374 lines
16 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace DreadScripts.TextureUtility
{
public class TextureAutoPackerWindow : EditorWindow
{
private static TextureAutoPackerData data;
private static SerializedObject serializedObject;
private static SerializedProperty _active;
private static SerializedProperty _activeModules;
private static UnityEditorInternal.ReorderableList modulesList;
private static Texture2D titleTexture;
[MenuItem("DreadTools/Utility/Texture Auto-Packer")]
public static void ShowWindow()
{
EditorWindow w = GetWindow<TextureAutoPackerWindow>(false, "Texture Auto-Packer", true);
if (!titleTexture)
{
titleTexture = TextureUtility.GetColors((Texture2D)EditorGUIUtility.IconContent("Texture2D Icon").image, 16, 16, out _);
titleTexture.Apply();
}
w.titleContent.image = titleTexture;
}
private void OnEnable()
{
data = TextureAutoPackerData.GetInstance();
serializedObject = new SerializedObject(data);
_active = serializedObject.FindProperty("active");
_activeModules = serializedObject.FindProperty("activeModules");
modulesList = new UnityEditorInternal.ReorderableList(serializedObject, _activeModules, true, true, true, false)
{
drawElementCallback = DrawElement,
drawHeaderCallback = DrawHeader
};
}
private void DrawHeader(Rect rect)
{
EditorGUI.LabelField(rect, "Active Modules");
}
private void DrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
if (!(index < _activeModules.arraySize && index >= 0))
return;
rect.y += 2;
rect.height = EditorGUIUtility.singleLineHeight;
if (GUI.Button(new Rect(rect.x, rect.y, 20, rect.height), "X"))
{
_activeModules.DeleteArrayElementAtIndex(index);
return;
}
rect.x += 20;
rect.width -= 20;
_activeModules.GetArrayElementAtIndex(index).objectReferenceValue = (TextureAutoPackerModule)EditorGUI.ObjectField(rect, _activeModules.GetArrayElementAtIndex(index).objectReferenceValue, typeof(TextureAutoPackerModule), false);
}
private void OnGUI()
{
serializedObject.Update();
Color og = GUI.backgroundColor;
GUI.backgroundColor = _active.boolValue ? Color.green : Color.grey;
_active.boolValue = GUILayout.Toggle(_active.boolValue, new GUIContent("Active","Determine whether the Auto-Packer should initiate on texture import"), "Toolbarbutton");
GUI.backgroundColor = og;
EditorGUI.BeginDisabledGroup(!_active.boolValue);
modulesList.DoLayoutList();
if (GUILayout.Button(new GUIContent("Force Check", "Initiate the Auto-Packer without having to trigger a texture import")))
{
TextureAutoPacker.InitiateAutoPacking();
TextureAutoPackerProcessor.OnAutoPackingEnd();
}
EditorGUI.EndDisabledGroup();
serializedObject.ApplyModifiedProperties();
}
}
[CustomEditor(typeof(TextureAutoPackerModule))]
public class TextureAutoPacker : Editor
{
static GUIContent removeIcon;
TextureAutoPackerModule module;
SerializedProperty packingList;
GUIStyle freeButtonStyle;
public override void OnInspectorGUI()
{
freeButtonStyle = new GUIStyle("toolbarbutton") { padding = new RectOffset(1, 1, 1, 1) };
serializedObject.Update();
if (GUILayout.Button(new GUIContent("Add","Create a new Auto-Packed texture"), "toolbarbutton"))
{
module.packedTextures.Add(new AutoPackedTexture());
serializedObject.Update();
}
for (int i = packingList.arraySize - 1; i >= 0; i--)
DrawPackingProperty(i);
serializedObject.ApplyModifiedProperties();
}
private void OnEnable()
{
module = (TextureAutoPackerModule)target;
packingList = serializedObject.FindProperty("packedTextures");
removeIcon = EditorGUIUtility.IconContent("winbtn_win_close");
}
static bool Running;
public static bool InitiateAutoPacking()
{
bool HasPacked=false;
if (Running)
return true;
Running = true;
TextureAutoPackerData data = TextureAutoPackerData.GetInstance();
if (!data.active)
return false;
data.activeModules.ForEach(m =>
{
if (!m)
goto Skip;
SerializedObject module = new SerializedObject(m);
module.Update();
for (int i = 0; i < m.packedTextures.Count; i++)
{
if (m.packedTextures[i].WasModified())
{
HasPacked = true;
string newTexturePath = m.packedTextures[i].Pack();
if (string.IsNullOrEmpty(newTexturePath))
goto Skip;
SerializedProperty packedTexture = module.FindProperty("packedTextures").GetArrayElementAtIndex(i);
SerializedProperty hashes = packedTexture.FindPropertyRelative("channelsHashes");
for (int j = 0; j < 4; j++)
{
hashes.GetArrayElementAtIndex(j).stringValue = string.Empty;
if (m.packedTextures[i].channels[j].texture)
hashes.GetArrayElementAtIndex(j).stringValue = m.packedTextures[i].channels[j].texture.imageContentsHash.ToString();
}
packedTexture.FindPropertyRelative("forceModified").boolValue = false;
AssetDatabase.ImportAsset(newTexturePath, ImportAssetOptions.ForceUpdate);
TextureAutoPackerProcessor.PathToProperty.Add(new System.Tuple<string, SerializedProperty>(newTexturePath, packedTexture.FindPropertyRelative("packed")));
}
}
module.ApplyModifiedPropertiesWithoutUndo();
Skip:;
});
Running = false;
return HasPacked;
}
public void DrawPackingProperty(int index)
{
SerializedProperty t = packingList.GetArrayElementAtIndex(index);
SerializedProperty _name = t.FindPropertyRelative("name");
SerializedProperty _expanded = t.FindPropertyRelative("expanded");
SerializedProperty _channels = t.FindPropertyRelative("channels");
SerializedProperty _packed = t.FindPropertyRelative("packed");
SerializedProperty _encoding = t.FindPropertyRelative("encoding");
SerializedProperty _quality = t.FindPropertyRelative("jpgQuality");
SerializedProperty _modified = t.FindPropertyRelative("forceModified");
AutoPackedTexture autoTexture = ((TextureAutoPackerModule)t.serializedObject.targetObject).packedTextures[index];
using (new GUILayout.VerticalScope("box"))
{
using (new GUILayout.HorizontalScope())
{
using (new GUILayout.HorizontalScope("toolbarbutton", GUILayout.Width(12)))
_expanded.boolValue = GUILayout.Toggle(_expanded.boolValue, GUIContent.none, "foldout", GUILayout.Width(10));
using (new GUILayout.HorizontalScope("toolbarbutton"))
_name.stringValue = EditorGUILayout.TextField(GUIContent.none, _name.stringValue, GUI.skin.label);
if (GUILayout.Button(removeIcon, freeButtonStyle, GUILayout.Width(17)))
{
packingList.DeleteArrayElementAtIndex(index);
return;
}
}
if (_expanded.boolValue)
{
using (new GUILayout.HorizontalScope("box"))
{
_encoding.enumValueIndex = (int)(TextureUtility.TexEncoding)EditorGUILayout.EnumPopup((TextureUtility.TexEncoding)_encoding.enumValueIndex, GUILayout.Width(95));
EditorGUI.BeginDisabledGroup(_encoding.enumValueIndex != 1);
EditorGUIUtility.labelWidth = 50;
_quality.intValue = EditorGUILayout.IntSlider("Quality", _quality.intValue, 1, 100);
EditorGUIUtility.labelWidth = 0;
EditorGUI.EndDisabledGroup();
}
using (new GUILayout.HorizontalScope())
{
for (int i = 0; i < _channels.arraySize; i++)
{
if (DrawChannelProperty(_channels.GetArrayElementAtIndex(i)))
_modified.boolValue = true;
}
GUILayout.Label("", GUI.skin.verticalSlider, GUILayout.Height(133));
using (new GUILayout.VerticalScope("box"))
{
using (new GUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
GUILayout.Label("Packed", "boldlabel");
GUILayout.FlexibleSpace();
}
GUILayout.Label(GUIContent.none);
using (new GUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
_packed.objectReferenceValue = (Texture2D)EditorGUILayout.ObjectField("", _packed.objectReferenceValue, typeof(Texture2D), false, GUILayout.Width(66));
GUILayout.FlexibleSpace();
}
using (new GUILayout.HorizontalScope())
{
if (GUILayout.Button("Force Pack", "toolbarbutton"))
{
string newTexturePath = autoTexture.Pack();
if (!string.IsNullOrEmpty(newTexturePath))
{
AssetDatabase.ImportAsset(newTexturePath);
_packed.objectReferenceValue = AssetDatabase.LoadAssetAtPath<Texture2D>(newTexturePath);
}
}
}
}
}
}
}
}
public bool DrawChannelProperty(SerializedProperty channel)
{
bool edited = false;
SerializedProperty _name = channel.FindPropertyRelative("name");
SerializedProperty _texture = channel.FindPropertyRelative("texture");
SerializedProperty _invert = channel.FindPropertyRelative("invert");
SerializedProperty _mode = channel.FindPropertyRelative("mode");
GUIStyle buttonGroupStyle = new GUIStyle(GUI.skin.GetStyle("toolbarbutton")) { padding = new RectOffset(1, 1, 1, 1), margin = new RectOffset(0, 0, 1, 1) };
using (new GUILayout.VerticalScope("box"))
{
using (new GUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
GUILayout.Label(_name.stringValue, "boldlabel");
GUILayout.FlexibleSpace();
}
using (new GUILayout.HorizontalScope())
{
EditorGUI.BeginChangeCheck();
GUILayout.FlexibleSpace();
bool dummy;
EditorGUI.BeginChangeCheck();
dummy = GUILayout.Toggle(_mode.enumValueIndex == (int)ChannelTexture.ColorMode.Red, "R", buttonGroupStyle, GUILayout.Width(16));
if (EditorGUI.EndChangeCheck())
if (dummy)
_mode.enumValueIndex = 0;
EditorGUI.BeginChangeCheck();
dummy = GUILayout.Toggle(_mode.enumValueIndex == (int)ChannelTexture.ColorMode.Green, "G", buttonGroupStyle, GUILayout.Width(16));
if (EditorGUI.EndChangeCheck())
if (dummy)
_mode.enumValueIndex = 1;
EditorGUI.BeginChangeCheck();
dummy = GUILayout.Toggle(_mode.enumValueIndex == (int)ChannelTexture.ColorMode.Blue, "B", buttonGroupStyle, GUILayout.Width(16));
if (EditorGUI.EndChangeCheck())
if (dummy)
_mode.enumValueIndex = 2;
EditorGUI.BeginChangeCheck();
dummy = GUILayout.Toggle(_mode.enumValueIndex == (int)ChannelTexture.ColorMode.Alpha, "A", buttonGroupStyle, GUILayout.Width(16));
if (EditorGUI.EndChangeCheck())
if (dummy)
_mode.enumValueIndex = 3;
GUILayout.FlexibleSpace();
if (EditorGUI.EndChangeCheck())
if (_texture.objectReferenceValue)
edited = true;
}
using (new GUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
_texture.objectReferenceValue = (Texture2D)EditorGUILayout.ObjectField("", _texture.objectReferenceValue, typeof(Texture2D), false, GUILayout.Width(66));
GUILayout.FlexibleSpace();
}
EditorGUI.BeginChangeCheck();
_invert.boolValue = GUILayout.Toggle(_invert.boolValue, "Invert", "toolbarbutton");
if (EditorGUI.EndChangeCheck())
if (_texture.objectReferenceValue)
edited = true;
}
return edited;
}
}
public class TextureAutoPackerProcessor : AssetPostprocessor
{
public static List<System.Tuple<string, SerializedProperty>> PathToProperty = new List<System.Tuple<string, SerializedProperty>>();
public static bool TextureImported = false;
void OnPostprocessTexture(Texture2D texture)
{
TextureImported = true;
}
public static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
if (TextureImported)
{
TextureImported = false;
if (!TextureAutoPacker.InitiateAutoPacking())
OnAutoPackingEnd();
}
}
public static void OnAutoPackingEnd()
{
PathToProperty.ForEach(t =>
{
t.Item2.serializedObject.Update();
t.Item2.objectReferenceValue = AssetDatabase.LoadAssetAtPath<Texture2D>(t.Item1);
t.Item2.serializedObject.ApplyModifiedPropertiesWithoutUndo();
});
PathToProperty.Clear();
}
}
public abstract class TAPDreadData<T> : ScriptableObject where T : ScriptableObject
{
private static T _instance = null;
private static string _SavePath;
protected static T GetInstance(string SavePath)
{
_SavePath = SavePath;
if (!_instance && Exists())
{
_instance = AssetDatabase.LoadAssetAtPath<T>(SavePath);
}
if (!_instance)
{
_instance = CreateInstance<T>();
string directoryPath = System.IO.Path.GetDirectoryName(SavePath);
if (!System.IO.Directory.Exists(directoryPath))
System.IO.Directory.CreateDirectory(directoryPath);
AssetDatabase.CreateAsset(_instance, _SavePath);
}
return _instance;
}
public static bool Exists()
{
return System.IO.File.Exists(_SavePath);
}
}
}