diff --git a/TextureStitcher.meta b/TextureStitcher.meta new file mode 100644 index 0000000..c47df09 --- /dev/null +++ b/TextureStitcher.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aa7127f4d0f097941933b00115d22660 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TextureStitcher/TextureStitcher.asmdef b/TextureStitcher/TextureStitcher.asmdef new file mode 100644 index 0000000..e452dcb --- /dev/null +++ b/TextureStitcher/TextureStitcher.asmdef @@ -0,0 +1,16 @@ +{ + "name": "TextureStitcher", + "rootNamespace": "", + "references": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/TextureStitcher/TextureStitcher.asmdef.meta b/TextureStitcher/TextureStitcher.asmdef.meta new file mode 100644 index 0000000..e56007f --- /dev/null +++ b/TextureStitcher/TextureStitcher.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dd440ea69f98580448e1719b0b71607d +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TextureStitcher/TextureStitcher.cs b/TextureStitcher/TextureStitcher.cs new file mode 100644 index 0000000..7ea3a8b --- /dev/null +++ b/TextureStitcher/TextureStitcher.cs @@ -0,0 +1,129 @@ +using UnityEditor; +using UnityEngine; +using System.IO; + +namespace gay.lilyy.TextureStitcher +{ + [CreateAssetMenu(fileName = "TextureStitcherSettings", menuName = "Texture Stitcher/Settings")] + public class TextureStitcherSettings : ScriptableObject + { + public Texture2D[] textures; + public string savePath = "Assets/StitchedTexture.png"; + } + + [CustomEditor(typeof(TextureStitcherSettings))] + public class TextureStitcherEditor : Editor + { + private SerializedProperty texturesProp; + private SerializedProperty savePathProp; + + private void OnEnable() + { + texturesProp = serializedObject.FindProperty("textures"); + savePathProp = serializedObject.FindProperty("savePath"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.LabelField("Texture Layers (Top → Bottom)", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(savePathProp); + + DrawReversedArray(texturesProp); + + GUILayout.Space(10); + + if (GUILayout.Button("Generate Stitched Texture")) + GenerateStitchedTexture(); + + serializedObject.ApplyModifiedProperties(); + } + + private void DrawReversedArray(SerializedProperty array) + { + if (!array.isArray) + return; + + // Draw size field (normal Unity behavior) + EditorGUILayout.PropertyField(array.FindPropertyRelative("Array.size")); + + // Reverse array in-place + int count = array.arraySize; + for (int i = 0; i < count / 2; i++) + array.MoveArrayElement(i, count - 1 - i); + + // Draw array normally + EditorGUILayout.PropertyField(array, GUIContent.none, true); + + // Restore original order + for (int i = 0; i < count / 2; i++) + array.MoveArrayElement(i, count - 1 - i); + } + + private void GenerateStitchedTexture() + { + TextureStitcherSettings settings = (TextureStitcherSettings)target; + GenerateStitchedTexture(settings); + } + + internal static void GenerateStitchedTexture(TextureStitcherSettings settings) + { + int width = 0; + int height = 0; + + foreach (var tex in settings.textures) + { + if (!tex) continue; + width = Mathf.Max(width, tex.width); + height = Mathf.Max(height, tex.height); + } + + Texture2D output = new Texture2D(width, height, TextureFormat.RGBA32, false); + Color[] pixels = new Color[width * height]; + for (int i = 0; i < pixels.Length; i++) pixels[i] = Color.clear; + + output.SetPixels(pixels); + + // Bottom → top + for (int i = 0; i < settings.textures.Length; i++) + { + var tex = settings.textures[i]; + if (!tex) continue; + + Texture2D resized = Resize(tex, width, height); + Color[] src = resized.GetPixels(); + Color[] dst = output.GetPixels(); + + for (int p = 0; p < dst.Length; p++) + { + Color s = src[p]; + dst[p] = Color.Lerp(dst[p], s, s.a); + } + + output.SetPixels(dst); + } + + output.Apply(); + File.WriteAllBytes(settings.savePath, output.EncodeToPNG()); + AssetDatabase.Refresh(); + + Debug.Log("Stitched texture saved to " + settings.savePath); + } + + private static Texture2D Resize(Texture2D src, int width, int height) + { + RenderTexture rt = RenderTexture.GetTemporary(width, height, 0); + Graphics.Blit(src, rt); + + RenderTexture.active = rt; + Texture2D result = new Texture2D(width, height, TextureFormat.RGBA32, false); + result.ReadPixels(new Rect(0, 0, width, height), 0, 0); + result.Apply(); + + RenderTexture.active = null; + RenderTexture.ReleaseTemporary(rt); + return result; + } + } +} diff --git a/TextureStitcher/TextureStitcher.cs.meta b/TextureStitcher/TextureStitcher.cs.meta new file mode 100644 index 0000000..312d22b --- /dev/null +++ b/TextureStitcher/TextureStitcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ebbfd7bebbeb0748bb1bf5a9191377f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TextureStitcher/TextureStitcherAutoRegen.cs b/TextureStitcher/TextureStitcherAutoRegen.cs new file mode 100644 index 0000000..10e77e8 --- /dev/null +++ b/TextureStitcher/TextureStitcherAutoRegen.cs @@ -0,0 +1,67 @@ +using UnityEditor; +using UnityEngine; +using System.Linq; + +namespace gay.lilyy.TextureStitcher +{ + public class TextureStitcherAutoRegen : AssetPostprocessor + { + private const string MenuPath = "LillithRosePup/Import Regens/Texture Stitcher"; + private const string PrefKey = "TextureStitcher.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 stitchers = AssetDatabase + .FindAssets("t:TextureStitcherSettings") + .Select(guid => + AssetDatabase.LoadAssetAtPath( + AssetDatabase.GUIDToAssetPath(guid))) + .Where(s => s && s.textures != null && s.textures.Length > 0) + .ToArray(); + + if (stitchers.Length == 0) + return; + + foreach (string path in importedAssets) + { + var tex = AssetDatabase.LoadAssetAtPath(path); + if (!tex) continue; + + foreach (var stitcher in stitchers) + { + if (stitcher.textures.Contains(tex)) + TextureStitcherEditor.GenerateStitchedTexture(stitcher); + } + } + } + } +} diff --git a/TextureStitcher/TextureStitcherAutoRegen.cs.meta b/TextureStitcher/TextureStitcherAutoRegen.cs.meta new file mode 100644 index 0000000..93ceb9d --- /dev/null +++ b/TextureStitcher/TextureStitcherAutoRegen.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f4211ffa1dc66ca43af9c753c61933c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: