summaryrefslogtreecommitdiffstats
path: root/Scripts/Editor
diff options
context:
space:
mode:
Diffstat (limited to 'Scripts/Editor')
-rw-r--r--Scripts/Editor/StackTextures3D.cs115
1 files changed, 115 insertions, 0 deletions
diff --git a/Scripts/Editor/StackTextures3D.cs b/Scripts/Editor/StackTextures3D.cs
new file mode 100644
index 0000000..3e88025
--- /dev/null
+++ b/Scripts/Editor/StackTextures3D.cs
@@ -0,0 +1,115 @@
+using UnityEngine;
+using UnityEditor;
+
+public class StackTextures3D : EditorWindow
+{
+ Texture2D[] _slices = new Texture2D[0];
+ SerializedObject _so;
+ SerializedProperty _slicesProp;
+
+ [MenuItem("Tools/yum_food/Stack Textures to 3D")]
+ static void Open() => GetWindow<StackTextures3D>("Stack Textures to 3D");
+
+ void OnEnable()
+ {
+ _so = new SerializedObject(this);
+ }
+
+ // SerializedObject needs a backing field with SerializeField for array GUI.
+ // Unity EditorWindow supports this natively.
+ [SerializeField] Texture2D[] slices = new Texture2D[0];
+
+ void OnGUI()
+ {
+ _so.Update();
+
+ EditorGUILayout.LabelField("Stack Textures to 3D", EditorStyles.boldLabel);
+ EditorGUILayout.HelpBox(
+ "Provide an ordered array of 2D textures. Each texture becomes one depth slice. " +
+ "All textures must share the same dimensions and format.",
+ MessageType.Info);
+
+ var prop = _so.FindProperty("slices");
+ EditorGUILayout.PropertyField(prop, new GUIContent("Slices"), true);
+ _so.ApplyModifiedProperties();
+
+ if (slices == null || slices.Length == 0)
+ return;
+
+ EditorGUILayout.Space();
+
+ // Show preview info.
+ int nullCount = 0;
+ foreach (var s in slices)
+ if (s == null) nullCount++;
+
+ if (nullCount > 0)
+ EditorGUILayout.HelpBox($"{nullCount} null slot(s) — fill all slots before generating.", MessageType.Warning);
+
+ if (nullCount == 0 && slices.Length > 0)
+ {
+ var first = slices[0];
+ EditorGUILayout.LabelField($"Resolution: {first.width} x {first.height} x {slices.Length}");
+ }
+
+ EditorGUI.BeginDisabledGroup(nullCount > 0);
+ if (GUILayout.Button("Generate"))
+ DoGenerate();
+ EditorGUI.EndDisabledGroup();
+ }
+
+ void DoGenerate()
+ {
+ if (slices.Length == 0)
+ return;
+
+ int width = slices[0].width;
+ int height = slices[0].height;
+ int depth = slices.Length;
+ TextureFormat fmt = slices[0].format;
+
+ for (int i = 1; i < depth; i++)
+ {
+ if (slices[i].width != width || slices[i].height != height)
+ {
+ EditorUtility.DisplayDialog("Error",
+ $"Slice {i} ({slices[i].name}) is {slices[i].width}x{slices[i].height}, " +
+ $"expected {width}x{height}.", "OK");
+ return;
+ }
+ if (slices[i].format != fmt)
+ {
+ EditorUtility.DisplayDialog("Error",
+ $"Slice {i} ({slices[i].name}) format is {slices[i].format}, " +
+ $"expected {fmt}.", "OK");
+ return;
+ }
+ }
+
+ bool mipMaps = true;
+ var tex = new Texture3D(width, height, depth, fmt, mipMaps);
+
+ for (int z = 0; z < depth; z++)
+ {
+ var pixels = slices[z].GetPixels();
+ for (int y = 0; y < height; y++)
+ for (int x = 0; x < width; x++)
+ {
+ tex.SetPixel(x, y, z, pixels[y * width + x]);
+ }
+ }
+
+ tex.wrapMode = TextureWrapMode.Repeat;
+ tex.filterMode = FilterMode.Trilinear;
+ tex.Apply();
+
+ string dir = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(slices[0]));
+ string path = $"{dir}/Stacked3D_{width}x{height}x{depth}.asset";
+ path = AssetDatabase.GenerateUniqueAssetPath(path);
+
+ AssetDatabase.CreateAsset(tex, path);
+ AssetDatabase.SaveAssets();
+ EditorGUIUtility.PingObject(tex);
+ Debug.Log($"[StackTextures3D] Saved {width}x{height}x{depth} ({fmt}) to {path}");
+ }
+}