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(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(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(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> PathToProperty = new List>(); 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(t.Item1); t.Item2.serializedObject.ApplyModifiedPropertiesWithoutUndo(); }); PathToProperty.Clear(); } } public abstract class TAPDreadData : 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(SavePath); } if (!_instance) { _instance = CreateInstance(); 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); } } }