diff --git a/.gitignore b/.gitignore index 3589bc0..5523acc 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ ExportedObj/ *.pidb.meta *.pdb.meta +# Unity3D meta files (not needed for the git) +*.meta + # Unity3D Generated File On Crash Reports sysinfo.txt diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Atlasses/Atlasses.txt b/MA_ToolBox/MA_TextureAtlasserPro/Atlasses/Atlasses.txt new file mode 100644 index 0000000..5ea6cf4 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Atlasses/Atlasses.txt @@ -0,0 +1 @@ +The created atlasses wil go here. \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Exports/Exports.txt b/MA_ToolBox/MA_TextureAtlasserPro/Exports/Exports.txt new file mode 100644 index 0000000..a613270 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Exports/Exports.txt @@ -0,0 +1 @@ +The exported assets will be saved in this folder. \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Icons/createAtlasIcon.png b/MA_ToolBox/MA_TextureAtlasserPro/Icons/createAtlasIcon.png new file mode 100644 index 0000000..11f2a32 Binary files /dev/null and b/MA_ToolBox/MA_TextureAtlasserPro/Icons/createAtlasIcon.png differ diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Icons/createQuadIcon.png b/MA_ToolBox/MA_TextureAtlasserPro/Icons/createQuadIcon.png new file mode 100644 index 0000000..2a04c60 Binary files /dev/null and b/MA_ToolBox/MA_TextureAtlasserPro/Icons/createQuadIcon.png differ diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Icons/dragHandleIcon.png b/MA_ToolBox/MA_TextureAtlasserPro/Icons/dragHandleIcon.png new file mode 100644 index 0000000..f1e4b12 Binary files /dev/null and b/MA_ToolBox/MA_TextureAtlasserPro/Icons/dragHandleIcon.png differ diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Icons/editIcon.png b/MA_ToolBox/MA_TextureAtlasserPro/Icons/editIcon.png new file mode 100644 index 0000000..63f7d7c Binary files /dev/null and b/MA_ToolBox/MA_TextureAtlasserPro/Icons/editIcon.png differ diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Icons/exportAtlasIcon.png b/MA_ToolBox/MA_TextureAtlasserPro/Icons/exportAtlasIcon.png new file mode 100644 index 0000000..653b01d Binary files /dev/null and b/MA_ToolBox/MA_TextureAtlasserPro/Icons/exportAtlasIcon.png differ diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Icons/loadAtlasIcon.png b/MA_ToolBox/MA_TextureAtlasserPro/Icons/loadAtlasIcon.png new file mode 100644 index 0000000..da4eea9 Binary files /dev/null and b/MA_ToolBox/MA_TextureAtlasserPro/Icons/loadAtlasIcon.png differ diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Icons/removeQuadIcon.png b/MA_ToolBox/MA_TextureAtlasserPro/Icons/removeQuadIcon.png new file mode 100644 index 0000000..5133df8 Binary files /dev/null and b/MA_ToolBox/MA_TextureAtlasserPro/Icons/removeQuadIcon.png differ diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Icons/showTexturesOffIcon.png b/MA_ToolBox/MA_TextureAtlasserPro/Icons/showTexturesOffIcon.png new file mode 100644 index 0000000..a2da94f Binary files /dev/null and b/MA_ToolBox/MA_TextureAtlasserPro/Icons/showTexturesOffIcon.png differ diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Icons/showTexturesOnIcon.png b/MA_ToolBox/MA_TextureAtlasserPro/Icons/showTexturesOnIcon.png new file mode 100644 index 0000000..8d94436 Binary files /dev/null and b/MA_ToolBox/MA_TextureAtlasserPro/Icons/showTexturesOnIcon.png differ diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Data/MA_TextureAtlasserProAtlas.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Data/MA_TextureAtlasserProAtlas.cs new file mode 100644 index 0000000..2bf6a0c --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Data/MA_TextureAtlasserProAtlas.cs @@ -0,0 +1,103 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using MA_Editor; +using MA_Editor.Grid; + +namespace MA_TextureAtlasserPro +{ + [System.Serializable] + public class MA_TextureAtlasserProAtlas : ScriptableObject + { + //Editor + public List textureQuads; + public MA_TextureAtlasserProQuad selectedTextureQuad; + private Rect editorWorkRect; + public bool showTextures = false; + + + //Data + public Vector2 textureAtlasSize; + public List textureGroupRegistration; + + public void CreateAtlas(string name, Vector2 size) + { + this.name = name; + textureAtlasSize = size; + } + + public void UpdateTextureQuads(Event e, Rect editorViewRect, Vector2 zoomCoordsOrigin, bool useEvents) + { + textureAtlasSize.x = Mathf.Clamp(textureAtlasSize.x, 128, 8192); + textureAtlasSize.y = Mathf.Clamp(textureAtlasSize.y, 128, 8192); + + editorWorkRect = new Rect(Vector2.zero - zoomCoordsOrigin, textureAtlasSize); + + GUI.backgroundColor = new Color(0, 0, 0, 0.1f); + GUI.Box(editorWorkRect, this.name); + GUI.backgroundColor = Color.white; + + MA_Editor.Grid.Grid.DrawZoomableGrid(editorWorkRect, 64, new Color(0, 0, 0, 0.1f), zoomCoordsOrigin); + + if(textureQuads != null) + { + foreach (MA_TextureAtlasserProQuad ts in textureQuads) + { + ts.UpdateTextureQuad(e, editorViewRect, editorWorkRect, zoomCoordsOrigin, useEvents, showTextures); + } + } + + if(useEvents) + ProcessEvents(e, zoomCoordsOrigin, useEvents); + + EditorUtility.SetDirty(this); + } + + private void ProcessEvents(Event e, Vector2 zoomCoordsOrigin, bool useEvents) + { + if(e.button == 0) + { + if(e.type == EventType.MouseDown) + { + DeselectQuad(); + + if(textureQuads != null) + { + foreach(MA_TextureAtlasserProQuad quad in textureQuads) + { + if(new Rect((int)quad.guiRect.x - zoomCoordsOrigin.x, (int)quad.guiRect.y - zoomCoordsOrigin.y, quad.guiRect.width, quad.guiRect.height).Contains(e.mousePosition)) + { + SelectQuad(quad); + e.Use(); + } + } + } + } + } + } + + private void SelectQuad(MA_TextureAtlasserProQuad quad) + { + if(selectedTextureQuad) + { + DeselectQuad(); + } + + quad.isSelected = true; + selectedTextureQuad = quad; + } + + private void DeselectQuad() + { + if(textureQuads != null) + { + foreach(MA_TextureAtlasserProQuad quad in textureQuads) + { + quad.isSelected = false; + } + selectedTextureQuad = null; + } + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Data/MA_TextureAtlasserProQuad.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Data/MA_TextureAtlasserProQuad.cs new file mode 100644 index 0000000..62ecc41 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Data/MA_TextureAtlasserProQuad.cs @@ -0,0 +1,166 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using MA_Editor; + +namespace MA_TextureAtlasserPro +{ + [System.Serializable] + public class MA_TextureAtlasserProQuad : ScriptableObject + { + //Editor + public bool isSelected = false; //Is this thing selected + public Rect rect; //The internal rect + public Rect guiRect; //The visual clamped and snapped rect + public bool debugMode = false; //Are we debugging, for showing some other things (like handles) + + private bool isDragging = false; //Are we editing the pos or size + private bool isDraggingRectHeigt = false; + public Rect dragRectHeight; + private bool isDraggingRectWidth = false; + public Rect dragRectWidth; + private bool isDraggingRectPos = false; + public Rect dragRectPos; + + //Data + public Texture texture; //Replace this with texture groups + public List textureGroups; + public List meshes; + + public void UpdateTextureQuad(Event e, Rect editorViewRect, Rect editorWorkRect, Vector2 zoomCoordsOrigin, bool useEvents, bool showTexture) + { + if(isSelected) + { + GUI.backgroundColor = new Color(0.05f, 0.05f, 0.05f, 0.75f); + } + else + { + GUI.backgroundColor = new Color(1, 1, 1, 0.5f); + } + + //Clamp and snap the guiRect + guiRect = new Rect(Mathf.RoundToInt(rect.x / 32) * 32, Mathf.RoundToInt(rect.y / 32) * 32, Mathf.RoundToInt(rect.width / 32) * 32, Mathf.RoundToInt(rect.height / 32) * 32); + + //Draw the sqaud background + if(showTexture && textureGroups != null && textureGroups.Count > 0 && textureGroups[0].texture != null) + GUI.DrawTexture(new Rect(guiRect.x - zoomCoordsOrigin.x, guiRect.y - zoomCoordsOrigin.y, guiRect.width, guiRect.height), textureGroups[0].texture, ScaleMode.StretchToFill); + else + GUI.Box(new Rect(guiRect.x - zoomCoordsOrigin.x, guiRect.y - zoomCoordsOrigin.y, guiRect.width, guiRect.height), ""); + + GUILayout.BeginArea(new Rect(guiRect.x - zoomCoordsOrigin.x, guiRect.y - zoomCoordsOrigin.y, guiRect.width, guiRect.height)); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Label(this.name); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + if(isSelected) + { + dragRectPos = new Rect(guiRect.width / 2 + guiRect.x - zoomCoordsOrigin.x - 16, guiRect.height / 2 + guiRect.y - zoomCoordsOrigin.y - 16, 32, 32); + dragRectWidth = new Rect(guiRect.width + guiRect.x - zoomCoordsOrigin.x - 16, guiRect.height / 2 + guiRect.y - zoomCoordsOrigin.y - 32, 16, 64); + dragRectHeight = new Rect(guiRect.width / 2 + guiRect.x - zoomCoordsOrigin.x - 32, guiRect.height + guiRect.y - zoomCoordsOrigin.y - 16, 64, 16); + + if(debugMode) + { + GUI.Box(new Rect(dragRectPos.x - guiRect.x + zoomCoordsOrigin.x, dragRectPos.y - guiRect.y + zoomCoordsOrigin.y, dragRectPos.width, dragRectPos.height), ""); + GUI.Box(new Rect(dragRectWidth.x - guiRect.x + zoomCoordsOrigin.x, dragRectWidth.y - guiRect.y + zoomCoordsOrigin.y, dragRectWidth.width, dragRectWidth.height), ""); + GUI.Box(new Rect(dragRectHeight.x - guiRect.x + zoomCoordsOrigin.x, dragRectHeight.y - guiRect.y + zoomCoordsOrigin.y, dragRectHeight.width, dragRectHeight.height), ""); + } + } + else + { + + } + + GUI.backgroundColor = Color.white; + GUILayout.EndArea(); + + if(useEvents) + ProcessEvents(e, editorViewRect, editorWorkRect, zoomCoordsOrigin); + + EditorUtility.SetDirty(this); + } + + void ProcessEvents(Event e, Rect editorViewRect, Rect editorWorkRect, Vector2 zoomCoordsOrigin) + { + if(isSelected) + { + //Right mouse + if(e.button == 0) + { + //Mouse drag + if(e.type == EventType.MouseDrag) + { + if(dragRectPos.Contains(e.mousePosition) && isDragging == false) + { + //Debug.Log("P"); + isDragging = true; + isDraggingRectPos = true; + } + if(dragRectWidth.Contains(e.mousePosition) && isDragging == false) + { + //Debug.Log("W"); + isDragging = true; + isDraggingRectWidth = true; + } + if(dragRectHeight.Contains(e.mousePosition) && isDragging == false) + { + //Debug.Log("W"); + isDragging = true; + isDraggingRectHeigt = true; + } + + if(isDraggingRectPos) + { + rect.x += e.delta.x; + rect.y += e.delta.y; + } + if(isDraggingRectWidth) + { + rect.width += e.delta.x; + } + if(isDraggingRectHeigt) + { + rect.height += e.delta.y; + } + + //Clamp rect with min/max values to stay inside the workrect + rect.width = Mathf.Clamp(rect.width, 64, editorWorkRect.width); + rect.height = Mathf.Clamp(rect.height, 64, editorWorkRect.height); + rect.x = Mathf.Clamp(rect.x, 0, editorWorkRect.width - rect.width); + rect.y = Mathf.Clamp(rect.y, 0, editorWorkRect.height - rect.height); + + if(isDragging) + e.Use(); + } + } + //Deselect on mouse up + if(e.type == EventType.MouseUp) + { + StopDragging(); + } + } + //Stop if we are not selected + else if(!isSelected && isDragging) + { + StopDragging(); + } + } + + private void StopDragging() + { + //Debug.Log("StopDragging"); + isDragging = false; + isDraggingRectPos = false; + isDraggingRectWidth = false; + isDraggingRectHeigt = false; + } + + public void SetDebugMode(bool isDebugging) + { + debugMode = isDebugging; + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Data/MA_TextureGroup.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Data/MA_TextureGroup.cs new file mode 100644 index 0000000..4f4bd6f --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Data/MA_TextureGroup.cs @@ -0,0 +1,19 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace MA_TextureAtlasserPro +{ + [System.Serializable] + public class MA_TextureGroup + { + public string name; + public Texture texture = null; + } + + [System.Serializable] + public class MA_TextureGroupRegistration + { + public string name; + } +} diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Utils/MA_TextureAtlasserProIcons.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Utils/MA_TextureAtlasserProIcons.cs new file mode 100644 index 0000000..7d3df4e --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Utils/MA_TextureAtlasserProIcons.cs @@ -0,0 +1,33 @@ +using UnityEngine; +using UnityEditor; + +namespace MA_TextureAtlasserPro +{ + public static class MA_TextureAtlasserProIcons + { + private const string LOADICONPATH = "Assets/MA_ToolBox/MA_TextureAtlasserPro/Icons/"; + + public static GUIContent createAtlasIcon; + public static GUIContent loadAtlasIcon; + public static GUIContent exportAtlasIcon; + public static GUIContent createQuadIcon; + public static GUIContent removeQuadIcon; + public static GUIContent showTexturesOnIcon; + public static GUIContent showTexturesOffIcon; + public static GUIContent dragHandleIcon; + public static GUIContent editIcon; + + public static void LoadIcons() + { + createAtlasIcon = new GUIContent("", (Texture)EditorGUIUtility.Load(LOADICONPATH + "createAtlasIcon" + ".png")); + loadAtlasIcon = new GUIContent("", (Texture)EditorGUIUtility.Load(LOADICONPATH + "loadAtlasIcon" + ".png")); + exportAtlasIcon = new GUIContent("", (Texture)EditorGUIUtility.Load(LOADICONPATH + "exportAtlasIcon" + ".png")); + createQuadIcon = new GUIContent("", (Texture)EditorGUIUtility.Load(LOADICONPATH + "createQuadIcon" + ".png")); + removeQuadIcon = new GUIContent("", (Texture)EditorGUIUtility.Load(LOADICONPATH + "removeQuadIcon" + ".png")); + showTexturesOnIcon = new GUIContent("", (Texture)EditorGUIUtility.Load(LOADICONPATH + "showTexturesOnIcon" + ".png")); + showTexturesOffIcon = new GUIContent("", (Texture)EditorGUIUtility.Load(LOADICONPATH + "showTexturesOffIcon" + ".png")); + dragHandleIcon = new GUIContent("", (Texture)EditorGUIUtility.Load(LOADICONPATH + "dragHandleIcon" + ".png")); + editIcon = new GUIContent("", (Texture)EditorGUIUtility.Load(LOADICONPATH + "editIcon" + ".png")); + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Utils/MA_TextureAtlasserProUtils.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Utils/MA_TextureAtlasserProUtils.cs new file mode 100644 index 0000000..858e102 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Utils/MA_TextureAtlasserProUtils.cs @@ -0,0 +1,317 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using MA_Mesh; +using MA_Texture; + +namespace MA_TextureAtlasserPro +{ + public static class MA_TextureAtlasserProUtils + { + public const string SAVEASSETPATH = "Assets/MA_ToolBox/MA_TextureAtlasserPro/Atlasses/"; + public const string LOADASSETPATH = "Assets/MA_ToolBox/MA_TextureAtlasserPro/Atlasses/"; + public const string EXPORTASSETPATH = "Assets/MA_ToolBox/MA_TextureAtlasserPro/Exports/"; + public const float VIEWOFFSET = 20; + public const string DEFAULTTEXTUREGROUPNAME = "Albedo"; + + public static MA_TextureAtlasserProAtlas CreateTextureAtlas(string name, Vector2 size) + { + MA_TextureAtlasserProAtlas _atlas = (MA_TextureAtlasserProAtlas)ScriptableObject.CreateInstance(); + + if(_atlas != null) + { + _atlas.CreateAtlas(name, size); + MA_CheckTextureAtlas(_atlas); + + AssetDatabase.CreateAsset(_atlas, SAVEASSETPATH + name + ".asset"); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + return _atlas; + } + else + { + return null; + } + } + + public static MA_TextureAtlasserProAtlas LoadTextureAtlas() + { + MA_TextureAtlasserProAtlas _atlas = null; + string absPath = EditorUtility.OpenFilePanel("Select Texture Atlas", LOADASSETPATH, ""); + + if(absPath.StartsWith(Application.dataPath)) + { + string relPath = absPath.Substring(Application.dataPath.Length - "Assets".Length); + _atlas = AssetDatabase.LoadAssetAtPath(relPath, typeof(MA_TextureAtlasserProAtlas)) as MA_TextureAtlasserProAtlas; + + MA_CheckTextureAtlas(_atlas); + + if(_atlas) + { + EditorPrefs.SetString("AtlasPath", null); + } + } + + if(_atlas != null) + { + if(_atlas.selectedTextureQuad != null) + { + _atlas.selectedTextureQuad.isSelected = false; + } + _atlas.selectedTextureQuad = null; + } + + return _atlas; + } + + public static void MA_CheckTextureAtlas(MA_TextureAtlasserProAtlas atlas) + { + if(atlas.textureGroupRegistration == null) + { + atlas.textureGroupRegistration = new List(); + + MA_TextureGroupRegistration groupRegistration = new MA_TextureGroupRegistration(); + groupRegistration.name = DEFAULTTEXTUREGROUPNAME; + + atlas.textureGroupRegistration.Add(groupRegistration); + } + + if(atlas.textureQuads == null) + { + atlas.textureQuads = new List(); + } + else + { + bool _sameCount = true; + foreach (MA_TextureAtlasserProQuad q in atlas.textureQuads) + { + if(q.textureGroups.Count != atlas.textureGroupRegistration.Count) + { + _sameCount = false; + Debug.LogWarning("TextureAtlasser: " + q.name + " doesn't have the right amount of texture groups!"); + } + } + + if(_sameCount) + { + foreach (MA_TextureAtlasserProQuad q in atlas.textureQuads) + { + for (int i = 0; i < atlas.textureQuads.Count; i++) + { + for (int j = 0; j < atlas.textureGroupRegistration.Count; j++) + { + if(atlas.textureQuads[i].textureGroups[j].name != atlas.textureGroupRegistration[j].name) + { + Debug.LogWarning("TextureAtlasser: " + q.name + " doesn't have the right texture group name!"); + } + } + } + } + } + } + } + + public static void CreateTextureQuad(MA_TextureAtlasserProAtlas atlas, string name, Rect rect) + { + if(atlas != null) + { + //Create new list if we haven't one already + if(atlas.textureQuads == null) + { + atlas.textureQuads = new List(); + } + + //Create new quad + MA_TextureAtlasserProQuad _quad = (MA_TextureAtlasserProQuad)ScriptableObject.CreateInstance("MA_TextureAtlasserProQuad"); + + //Add quad to asset + if(_quad != null) + { + //Set quad settings + _quad.name = name; + _quad.rect = rect; + + SetTextureGroups(atlas, _quad); + + atlas.textureQuads.Add((MA_TextureAtlasserProQuad)_quad); + + AssetDatabase.AddObjectToAsset(_quad, atlas); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + else + { + Debug.LogError("CreateTextureQuad Failed: _TextureQuad"); + } + } + else + { + Debug.LogError("CreateTextureQuad Failed: textureAtlas"); + } + } + + public static void RemoveTextureQuad(MA_TextureAtlasserProAtlas atlas) + { + if(atlas != null && atlas.selectedTextureQuad != null) + { + atlas.textureQuads.Remove(atlas.selectedTextureQuad); + GameObject.DestroyImmediate(atlas.selectedTextureQuad, true); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + } + + public static void SetTextureGroups(MA_TextureAtlasserProAtlas atlas, MA_TextureAtlasserProQuad quad) + { + if(quad.textureGroups == null) + { + quad.textureGroups = new List(); + } + + //Add texture groups + foreach (MA_TextureGroupRegistration tgr in atlas.textureGroupRegistration) + { + MA_TextureGroup textureGroup = new MA_TextureGroup(); + textureGroup.name = tgr.name; + quad.textureGroups.Add(textureGroup); + } + } + + public static void CreateTextureGroup(MA_TextureAtlasserProAtlas atlas, string name) + { + MA_TextureGroupRegistration _textureGroupRegistration = new MA_TextureGroupRegistration(); + _textureGroupRegistration.name = name; + atlas.textureGroupRegistration.Add(_textureGroupRegistration); + + foreach (MA_TextureAtlasserProQuad q in atlas.textureQuads) + { + MA_TextureGroup _textureGroup = new MA_TextureGroup(); + _textureGroup.name = name; + q.textureGroups.Add(_textureGroup); + } + } + + public static void RemoveTextureGroup(MA_TextureAtlasserProAtlas atlas, int index) + { + atlas.textureGroupRegistration.RemoveAt(index); + + foreach (MA_TextureAtlasserProQuad q in atlas.textureQuads) + { + q.textureGroups.RemoveAt(index); + } + } + + public static void CloseWindow(MA_TextureAtlasserProWindow curWindow) + { + if(curWindow == null) + { + Debug.LogError("Closing window Failed: curWindow == null"); + } + curWindow.Close(); + } + + public static void ExportAtlas(MA_TextureAtlasserProAtlas atlas, string savePath = EXPORTASSETPATH) + { + if(atlas != null && atlas.textureQuads != null) + { + ExportAtlasMeshesObj(atlas); + ExportAtlasTexturesPNG(atlas); + + AssetDatabase.Refresh(); + } + } + + public static void ExportAtlasMeshesObj(MA_TextureAtlasserProAtlas atlas, string savePath = EXPORTASSETPATH) + { + if(atlas != null && atlas.textureQuads != null) + { + foreach (MA_TextureAtlasserProQuad ta in atlas.textureQuads) + { + //Export Mesh + if(ta.meshes != null) + { + for (int m = 0; m < ta.meshes.Count; m++) + { + if(ta.meshes[m] != null) + { + //Create new mesh + Mesh newMesh = new Mesh(); + //Duplicate it from the current one + newMesh = MA_MeshUtils.MA_DuplicateMesh(ta.meshes[m]); + //Remap uvs + newMesh = MA_MeshUtils.MA_UVReMap(newMesh, atlas.textureAtlasSize, ta.guiRect); + //Save it + MA_MeshUtils.MeshToFile(newMesh, "MA_" + ta.name, savePath); + } + } + } + } + } + } + + // public static void ExportAtlasTexturePNG(MA_TextureAtlasserProAtlas atlas, string savePath = EXPORTASSETPATH) + // { + // if(atlas != null && atlas.textureQuads != null) + // { + // //Create new Texture Atlas + // Texture2D newTexture = new Texture2D((int)atlas.textureAtlasSize.x, (int)atlas.textureAtlasSize.y); + // newTexture.name = atlas.name; + + // foreach (MA_TextureAtlasserProQuad ta in atlas.textureQuads) + // { + // //Export Texture Atlas + // //TODO: Replace with texture groups (foreacht ...) + // if(ta.texture != null) + // { + // //Create new texture part + // Texture2D newTexturePart = (Texture2D)MA_Texture.MA_TextureUtils.ConvertToReadableTexture(ta.texture); + // //Scale it + // newTexturePart = newTexturePart.MA_Scale2D((int)ta.guiRect.width, (int)ta.guiRect.height); + // //Add it + // newTexture = newTexture.MA_Combine2D(newTexturePart, (int)ta.guiRect.x, (int)ta.guiRect.y); + // } + // } + + // //Save it + // newTexture.MA_Save2D("MA_" + newTexture.name, savePath); + // //Refresh + // AssetDatabase.Refresh(); + // } + // } + + public static void ExportAtlasTexturesPNG(MA_TextureAtlasserProAtlas atlas, string savePath = EXPORTASSETPATH) + { + if(atlas != null && atlas.textureQuads != null && atlas.textureGroupRegistration != null) + { + //Foreach texture group + for (int i = 0; i < atlas.textureGroupRegistration.Count; i++) + { + //Create new Texture Atlas + Texture2D newTexture = new Texture2D((int)atlas.textureAtlasSize.x, (int)atlas.textureAtlasSize.y); + newTexture.name = atlas.name + "_" + atlas.textureGroupRegistration[i].name; + + foreach (MA_TextureAtlasserProQuad q in atlas.textureQuads) + { + if(q.textureGroups != null && q.textureGroups[i].texture != null) + { + //Create new texture part + Texture2D newTexturePart = (Texture2D)MA_Texture.MA_TextureUtils.ConvertToReadableTexture(q.textureGroups[i].texture); + //Scale it + newTexturePart = newTexturePart.MA_Scale2D((int)q.guiRect.width, (int)q.guiRect.height); + //Add it + newTexture = newTexture.MA_Combine2D(newTexturePart, (int)q.guiRect.x, (int)q.guiRect.y); + } + } + + //Save it + newTexture.MA_Save2D("MA_" + newTexture.name, savePath); + } + + //Refresh + AssetDatabase.Refresh(); + } + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProDebugView.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProDebugView.cs new file mode 100644 index 0000000..bf7eb1d --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProDebugView.cs @@ -0,0 +1,78 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using MA_Editor; + +namespace MA_TextureAtlasserPro +{ + public class MA_TextureAtlasserProDebugView : MA_TextureAtlasserProViewBase + { + private bool isEditing = false; + + public MA_TextureAtlasserProDebugView(MA_TextureAtlasserProWindow currentEditorWindow, string title) : base(currentEditorWindow, title) + { + + } + + public override void UpdateView(Event e, Rect editorViewRect) + { + //Update base derived class + base.UpdateView(e, editorViewRect); + + //Draw inspector + if(isLoaded) + { + GUILayout.BeginArea(editorViewRect, EditorStyles.helpBox); + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + + //GUILayout.Label(curWindow.workView.Zoom.ToString("F2")); + if(GUILayout.Button(curWindow.workView.Zoom.ToString("F2"), EditorStyles.label)) + { + curWindow.workView.ResetWindow(); + } + + if(curWindow.textureAtlas != null) + { + GUILayout.FlexibleSpace(); + //GUILayout.Label(curWindow.textureAtlas.textureAtlasSize.ToString()); + if(!isEditing) + { + if(GUILayout.Button(curWindow.textureAtlas.textureAtlasSize.ToString("F0"), EditorStyles.label)) + { + isEditing = true; + } + } + else + { + curWindow.textureAtlas.textureAtlasSize = EditorGUILayout.Vector2Field("", curWindow.textureAtlas.textureAtlasSize, GUILayout.Width(110)); + } + } + + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } + + ProcessEvents(e, editorViewRect); + } + + protected override void ProcessEvents(Event e, Rect editorViewRect) + { + base.ProcessEvents(e, editorViewRect); + + if(isEditing) + { + if(e.type == EventType.KeyDown && e.keyCode == KeyCode.Return) + { + isEditing = false; + return; + } + if(e.type == EventType.MouseDown && !isMouseInEditorViewRect) + { + isEditing = false; + return; + } + } + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProInspectorView.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProInspectorView.cs new file mode 100644 index 0000000..32628a6 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProInspectorView.cs @@ -0,0 +1,134 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using MA_Editor; + +namespace MA_TextureAtlasserPro +{ + public class MA_TextureAtlasserProInspectorView : MA_TextureAtlasserProViewBase + { + private MA_TextureAtlasserProQuad lastSelectedQuad; + + private bool isEditing = false; + + public MA_TextureAtlasserProInspectorView(MA_TextureAtlasserProWindow currentEditorWindow, string title) : base(currentEditorWindow, title) + { + + } + + public override void UpdateView(Event e, Rect editorViewRect) + { + //Update base derived class + base.UpdateView(e, editorViewRect); + + if(isLoaded) + { + //Draw inspector + if(curWindow.textureAtlas != null && curWindow.textureAtlas.selectedTextureQuad != null) + { + //Deselect GUI elements when we are focusing on a new quad + if(lastSelectedQuad != curWindow.textureAtlas.selectedTextureQuad) + { + lastSelectedQuad = curWindow.textureAtlas.selectedTextureQuad; + GUI.FocusControl(null); + } + + GUILayout.BeginArea(editorViewRect, EditorStyles.helpBox); + GUILayout.BeginVertical(GUILayout.ExpandWidth(true)); + + GUILayout.Label("Quad Name"); + curWindow.textureAtlas.selectedTextureQuad.name = EditorGUILayout.TextField(curWindow.textureAtlas.selectedTextureQuad.name); + + GUILayout.Space(MA_TextureAtlasserProUtils.VIEWOFFSET / 2); + + //Textures + GUILayout.BeginHorizontal(); + GUILayout.Label("Textures", GUILayout.ExpandWidth(true)); + if(GUILayout.Button(MA_TextureAtlasserProIcons.editIcon, EditorStyles.miniButton, GUILayout.Width(36), GUILayout.Height(15))) + { + isEditing = !isEditing; + } + GUILayout.EndHorizontal(); + if(curWindow.textureAtlas.textureGroupRegistration == null || curWindow.textureAtlas.textureGroupRegistration.Count == 0) + { + if(GUILayout.Button("+", EditorStyles.miniButton, GUILayout.ExpandWidth(true))) + { + MA_TextureAtlasserProUtils.CreateTextureGroup(curWindow.textureAtlas, "New TextureGroup"); + } + } + for (int i = 0; i < curWindow.textureAtlas.textureGroupRegistration.Count; i++) + { + if(isEditing) + { + curWindow.textureAtlas.textureGroupRegistration[i].name = curWindow.textureAtlas.selectedTextureQuad.textureGroups[i].name = EditorGUILayout.TextField(curWindow.textureAtlas.textureGroupRegistration[i].name); + } + else + { + GUILayout.Label(curWindow.textureAtlas.textureGroupRegistration[i].name); + } + GUILayout.BeginHorizontal(); + curWindow.textureAtlas.selectedTextureQuad.textureGroups[i].texture = (Texture)EditorGUILayout.ObjectField(curWindow.textureAtlas.selectedTextureQuad.textureGroups[i].texture, typeof(Texture), false); + if(isEditing && GUILayout.Button("-", EditorStyles.miniButtonLeft, GUILayout.ExpandWidth(false))) + { + MA_TextureAtlasserProUtils.RemoveTextureGroup(curWindow.textureAtlas, i); + } + if(isEditing && GUILayout.Button("+", EditorStyles.miniButtonRight, GUILayout.ExpandWidth(false))) + { + MA_TextureAtlasserProUtils.CreateTextureGroup(curWindow.textureAtlas, "New TextureGroup"); + } + GUILayout.EndHorizontal(); + } + + GUILayout.Space(MA_TextureAtlasserProUtils.VIEWOFFSET / 2); + + //Meshes + GUILayout.Label("Meshes"); + if(curWindow.textureAtlas.selectedTextureQuad.meshes != null) + { + if(curWindow.textureAtlas.selectedTextureQuad.meshes.Count == 0) + { + if(GUILayout.Button("+", EditorStyles.miniButton, GUILayout.ExpandWidth(true))) + { + curWindow.textureAtlas.selectedTextureQuad.meshes.Add(null); + } + } + for (int i = 0; i < curWindow.textureAtlas.selectedTextureQuad.meshes.Count; i++) + { + GUILayout.BeginHorizontal(); + curWindow.textureAtlas.selectedTextureQuad.meshes[i] = (Mesh)EditorGUILayout.ObjectField(curWindow.textureAtlas.selectedTextureQuad.meshes[i], typeof(Mesh), false); + if(GUILayout.Button("-", EditorStyles.miniButtonLeft, GUILayout.ExpandWidth(false))) + { + curWindow.textureAtlas.selectedTextureQuad.meshes.RemoveAt(i); + } + if(GUILayout.Button("+", EditorStyles.miniButtonRight, GUILayout.ExpandWidth(false))) + { + curWindow.textureAtlas.selectedTextureQuad.meshes.Insert(i, null); + } + GUILayout.EndHorizontal(); + } + } + else + { + curWindow.textureAtlas.selectedTextureQuad.meshes = new List(); + } + + GUILayout.FlexibleSpace(); + GUILayout.Label("x " + curWindow.textureAtlas.selectedTextureQuad.guiRect.x.ToString() + ", y " + curWindow.textureAtlas.selectedTextureQuad.guiRect.y.ToString()); + GUILayout.Label("w " + curWindow.textureAtlas.selectedTextureQuad.guiRect.width.ToString() + ", h " + curWindow.textureAtlas.selectedTextureQuad.guiRect.height.ToString()); + + GUILayout.EndVertical(); + GUILayout.EndArea(); + } + } + + if(curWindow.textureAtlas != null && curWindow.textureAtlas.selectedTextureQuad != null) + ProcessEvents(e, editorViewRect); + } + + protected override void ProcessEvents(Event e, Rect editorViewRect) + { + base.ProcessEvents(e, editorViewRect); + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProMenuView.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProMenuView.cs new file mode 100644 index 0000000..77be0a9 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProMenuView.cs @@ -0,0 +1,76 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using MA_Editor; + +namespace MA_TextureAtlasserPro +{ + public class MA_TextureAtlasserProMenuView : MA_TextureAtlasserProViewBase + { + public MA_TextureAtlasserProMenuView(MA_TextureAtlasserProWindow currentEditorWindow, string title) : base(currentEditorWindow, title) + { + + } + + public override void UpdateView(Event e, Rect editorViewRect) + { + //Update base derived class + base.UpdateView(e, editorViewRect); + + //Draw Menu + if(isLoaded) + { + GUILayout.BeginArea(editorViewRect, EditorStyles.helpBox); + GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); + + if(GUILayout.Button(MA_TextureAtlasserProIcons.createAtlasIcon, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true))) + { + MA_TextureAtlasserProCreateWindow.InitEditorWindow(curWindow); + } + if(GUILayout.Button(MA_TextureAtlasserProIcons.loadAtlasIcon, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true))) + { + curWindow.textureAtlas = MA_TextureAtlasserProUtils.LoadTextureAtlas(); + } + + if(curWindow.textureAtlas != null) + { + if(GUILayout.Button(MA_TextureAtlasserProIcons.exportAtlasIcon, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true))) + { + MA_TextureAtlasserProExportWindow.InitEditorWindow(curWindow); + //MA_TextureAtlasserProUtils.ExportAtlas(curWindow.textureAtlas); + } + GUILayout.Space(MA_TextureAtlasserProUtils.VIEWOFFSET); + if(curWindow.textureAtlas.showTextures && GUILayout.Button(MA_TextureAtlasserProIcons.showTexturesOnIcon, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true))) + { + curWindow.textureAtlas.showTextures = false; + } + else if(!curWindow.textureAtlas.showTextures && GUILayout.Button(MA_TextureAtlasserProIcons.showTexturesOffIcon, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true))) + { + curWindow.textureAtlas.showTextures = true; + } + GUILayout.Space(MA_TextureAtlasserProUtils.VIEWOFFSET); + if(GUILayout.Button(MA_TextureAtlasserProIcons.createQuadIcon, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true))) + { + MA_TextureAtlasserProUtils.CreateTextureQuad(curWindow.textureAtlas, "new Quad", new Rect(0, 0, 128, 128)); + } + if(curWindow.textureAtlas.selectedTextureQuad != null && GUILayout.Button(MA_TextureAtlasserProIcons.removeQuadIcon, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true))) + { + if(curWindow.textureAtlas.selectedTextureQuad != null) + MA_TextureAtlasserProUtils.RemoveTextureQuad(curWindow.textureAtlas); + } + } + + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } + + ProcessEvents(e, editorViewRect); + } + + protected override void ProcessEvents(Event e, Rect editorViewRect) + { + base.ProcessEvents(e, editorViewRect); + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProViewBase.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProViewBase.cs new file mode 100644 index 0000000..128c149 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProViewBase.cs @@ -0,0 +1,55 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace MA_TextureAtlasserPro +{ + public class MA_TextureAtlasserProViewBase + { + public MA_TextureAtlasserProWindow curWindow; + public string viewTitle; + public bool isMouseInEditorViewRect = false; + public static bool editorIsLoaded = false; + public bool isLoaded = false; + + public MA_TextureAtlasserProViewBase(MA_TextureAtlasserProWindow currentEditorWindow, string title) + { + curWindow = currentEditorWindow; + viewTitle = title; + } + + [UnityEditor.Callbacks.DidReloadScripts] + static void OnReload() + { + //Make sure that when the compiler is finished and reloads the scripts, we are waiting for the next Event. + editorIsLoaded = false; + } + + public virtual void UpdateView(Event e, Rect editorViewRect) + { + + } + + protected virtual void ProcessEvents(Event e, Rect editorViewRect) + { + if(e.type == EventType.Repaint) + { + if(!isLoaded && editorIsLoaded) + isLoaded = true; + + if(!editorIsLoaded) + editorIsLoaded = true; + } + + if(editorViewRect.Contains(e.mousePosition)) + { + isMouseInEditorViewRect = true; + } + else + { + isMouseInEditorViewRect = false; + } + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProWorkView.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProWorkView.cs new file mode 100644 index 0000000..f92a8b0 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Views/MA_TextureAtlasserProWorkView.cs @@ -0,0 +1,122 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using MA_Editor; +using MA_Editor.GUILayoutZoom; +using MA_Editor.RectUtils; + +namespace MA_TextureAtlasserPro +{ + public class MA_TextureAtlasserProWorkView : MA_TextureAtlasserProViewBase + { + public MA_TextureAtlasserProWorkView(MA_TextureAtlasserProWindow currentEditorWindow, string title) : base(currentEditorWindow, title) + { + zoomCoordsOrigin = new Vector2(-(curWindow.position.width / 2) + (curWindow.position.width / 3), -(curWindow.position.height / 2) + (curWindow.position.height / 3)); + } + + private const float kZoomMin = 0.05f; + private const float kZoomMax = 2.0f; + private Rect zoomArea; + private float zoom = 1.0f; + public float Zoom { get { return zoom; } } + private Vector2 zoomCoordsOrigin = Vector2.zero; + + public override void UpdateView(Event e, Rect editorViewRect) + { + //Update base derived class + base.UpdateView(e, editorViewRect); + + zoomArea = editorViewRect; + + bool useEvents; + if(curWindow.menuView.isMouseInEditorViewRect || curWindow.inspectorView.isMouseInEditorViewRect || curWindow.debugView.isMouseInEditorViewRect) + useEvents = false; + else + useEvents = true; + + //Draw Work + if(isLoaded) + { + //Start zoom area + GUILayoutZoom.BeginArea(zoom, zoomArea); + + //Draw quads + if(curWindow.textureAtlas != null) + { + curWindow.textureAtlas.UpdateTextureQuads(e, editorViewRect, zoomCoordsOrigin, useEvents); + DrawQuadGUI(); + } + + //End zoom area + GUILayoutZoom.EndArea(); + } + + if(useEvents) + ProcessEvents(e, editorViewRect); + } + + protected override void ProcessEvents(Event e, Rect editorViewRect) + { + base.ProcessEvents(e, editorViewRect); + + // Allow adjusting the zoom with the mouse wheel as well. In this case, use the mouse coordinates + // as the zoom center instead of the top left corner of the zoom area. This is achieved by + // maintaining an origin that is used as offset when drawing any GUI elements in the zoom area. + if (e.type == EventType.ScrollWheel) + { + Vector2 screenCoordsMousePos = e.mousePosition; + Vector2 delta = e.delta; + Vector2 zoomCoordsMousePos = ConvertScreenCoordsToZoomCoords(screenCoordsMousePos); + float zoomDelta = -delta.y / 100.0f; + float oldZoom = zoom; + zoom += zoomDelta; + zoom = Mathf.Clamp(zoom, kZoomMin, kZoomMax); + if(zoom < 1.025f && zoom > 0.995f) + { + zoom = 1; + } + zoomCoordsOrigin += (zoomCoordsMousePos - zoomCoordsOrigin) - (oldZoom / zoom) * (zoomCoordsMousePos - zoomCoordsOrigin); + + e.Use(); + } + + // Allow moving the zoom area's origin by dragging by dragging with the left mouse button with Alt pressed. + if (e.type == EventType.MouseDrag && (e.button == 2 || (e.button == 0 && e.modifiers == EventModifiers.Alt))) + { + Vector2 delta = Event.current.delta; + delta /= zoom; + zoomCoordsOrigin -= delta; + + e.Use(); + } + } + + private Vector2 ConvertScreenCoordsToZoomCoords(Vector2 screenCoords) + { + return (screenCoords - zoomArea.TopLeft()) / zoom + zoomCoordsOrigin; + } + + //Draw quad GUI ontop of quad with custom GUIContent. + private void DrawQuadGUI() + { + if(curWindow.textureAtlas.textureQuads != null) + { + foreach (MA_TextureAtlasserProQuad q in curWindow.textureAtlas.textureQuads) + { + if(q.isSelected) + { + GUI.Button(new Rect(q.dragRectPos.x, q.dragRectPos.y, q.dragRectPos.width, q.dragRectPos.height), MA_TextureAtlasserProIcons.dragHandleIcon); + GUI.Button(new Rect(q.dragRectWidth.x, q.dragRectWidth.y, q.dragRectWidth.width, q.dragRectWidth.height), MA_TextureAtlasserProIcons.dragHandleIcon); + GUI.Button(new Rect(q.dragRectHeight.x, q.dragRectHeight.y, q.dragRectHeight.width, q.dragRectHeight.height), MA_TextureAtlasserProIcons.dragHandleIcon); + } + } + } + } + + public void ResetWindow() + { + zoom = 1; + zoomCoordsOrigin = new Vector2(-(curWindow.position.width / 2) + (curWindow.position.width / 3), -(curWindow.position.height / 2) + (curWindow.position.height / 3)); + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Windows/MA_TextureAtlasserProCreateWindow.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Windows/MA_TextureAtlasserProCreateWindow.cs new file mode 100644 index 0000000..d8e2eb7 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Windows/MA_TextureAtlasserProCreateWindow.cs @@ -0,0 +1,170 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using MA_Editor; + +namespace MA_TextureAtlasserPro +{ + public class MA_TextureAtlasserProCreateWindow : EditorWindow + { + //Editor + private static MA_TextureAtlasserProCreateWindow thisWindow; + public static MA_TextureAtlasserProWindow curWindow; + + private bool linkedAtlasSize = true; + private bool nameError = true; + private bool sizeError = true; + + //Data + private string textureAtlasName = "Atlas name"; + private Vector2 textureAtlasSize = new Vector2(512, 512); + private MA_TextureAtlasserProAtlas textureAtlas; + private static bool isLoaded = false; + + [MenuItem("MA_ToolKit/MA_TextureAtlasserPro/New Atlas")] + private static void Init() + { + GetCurrentWindow(); + + thisWindow.minSize = new Vector2(500,160); + thisWindow.maxSize = new Vector2(500,160); + + thisWindow.titleContent.text = "MA_CreateTextureAtlas"; + + thisWindow.Show(); + } + + public static void InitEditorWindow(MA_TextureAtlasserProWindow currentEditorWindow) + { + curWindow = currentEditorWindow; + + GetCurrentWindow(); + + thisWindow.minSize = new Vector2(500,160); + thisWindow.maxSize = new Vector2(500,160); + + thisWindow.titleContent.text = "MA_CreateTextureAtlas"; + + thisWindow.Show(); + } + + private static void GetCurrentWindow() + { + thisWindow = (MA_TextureAtlasserProCreateWindow)EditorWindow.GetWindow(); + } + + private void CloseWindow() + { + if(thisWindow == null) + { + GetCurrentWindow(); + thisWindow.Close(); + } + else + { + thisWindow.Close(); + } + } + + private Event ProcessEvents() + { + Event e = Event.current; + + return e; + } + + [UnityEditor.Callbacks.DidReloadScripts] + static void OnReload() + { + //Make sure that when the compiler is finished and reloads the scripts, we are waiting for the next Event. + isLoaded = false; + } + + private void OnGUI() + { + if(thisWindow == null) + { + GetCurrentWindow(); + return; + } + + //Get current event + Event e = ProcessEvents(); + + if(isLoaded) + { + GUILayout.BeginArea(new Rect(MA_TextureAtlasserProUtils.VIEWOFFSET, MA_TextureAtlasserProUtils.VIEWOFFSET, position.width - (MA_TextureAtlasserProUtils.VIEWOFFSET * 2), position.height - (MA_TextureAtlasserProUtils.VIEWOFFSET * 2))); + GUILayout.BeginVertical(); + + //Input options + textureAtlasName = EditorGUILayout.TextField("Atlas name", textureAtlasName, GUILayout.ExpandWidth(true)); + if(textureAtlasName == "Atlas name" || string.IsNullOrEmpty(textureAtlasName)) + { + nameError = true; + GUI.backgroundColor = Color.red; + GUILayout.Box("Error: Enter a valid atlas name!", EditorStyles.helpBox); + GUI.backgroundColor = Color.white; + } + else + { + nameError = false; + } + + textureAtlasSize.x = EditorGUILayout.IntField("Atlas width", (int)textureAtlasSize.x, GUILayout.ExpandWidth(true)); + if(linkedAtlasSize) + { + linkedAtlasSize = EditorGUILayout.Toggle("link height", linkedAtlasSize, GUILayout.ExpandWidth(true)); + textureAtlasSize.y = textureAtlasSize.x; + } + else + { + textureAtlasSize.y = EditorGUILayout.IntField("Atlas height", (int)textureAtlasSize.y, GUILayout.ExpandWidth(true)); + } + if(!Mathf.IsPowerOfTwo((int)textureAtlasSize.x) || !Mathf.IsPowerOfTwo((int)textureAtlasSize.y)) + { + GUI.backgroundColor = Color.yellow; + GUILayout.Box("Warning: Atlas size value isn't a power of two!", EditorStyles.helpBox); + GUI.backgroundColor = Color.white; + } + if(textureAtlasSize.x < 64 || textureAtlasSize.y < 64) + { + sizeError = true; + GUI.backgroundColor = Color.red; + GUILayout.Box("Error: The minimum atlas size is 64!", EditorStyles.helpBox); + GUI.backgroundColor = Color.white; + } + else + { + sizeError = false; + } + + //Create + if(!nameError && !sizeError) + { + if(GUILayout.Button("Create Atlas", GUILayout.ExpandWidth(true), GUILayout.Height(37))) + { + textureAtlas = MA_TextureAtlasserProUtils.CreateTextureAtlas(textureAtlasName, textureAtlasSize); + + if(curWindow != null) + { + curWindow.textureAtlas = textureAtlas; + } + else + { + Debug.Log("No editor window found"); + } + + CloseWindow(); + } + } + + GUILayout.EndVertical(); + GUILayout.EndArea(); + } + + if(e.type == EventType.Repaint) + isLoaded = true; + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Windows/MA_TextureAtlasserProExportWindow.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Windows/MA_TextureAtlasserProExportWindow.cs new file mode 100644 index 0000000..d21c23f --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Windows/MA_TextureAtlasserProExportWindow.cs @@ -0,0 +1,135 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using MA_Editor; + +namespace MA_TextureAtlasserPro +{ + public class MA_TextureAtlasserProExportWindow : EditorWindow + { + //Editor + private static MA_TextureAtlasserProExportWindow thisWindow; + public static MA_TextureAtlasserProWindow curWindow; + + //Data + private static bool isLoaded = false; //Make sure we wait a frame at the start to setup and don't draw. + + [MenuItem("MA_ToolKit/MA_TextureAtlasserPro/Export Atlas")] + private static void Init() + { + GetCurrentWindow(); + + thisWindow.minSize = new Vector2(500,160); + thisWindow.maxSize = new Vector2(500,160); + + thisWindow.titleContent.text = "MA_ExportTextureAtlas"; + + thisWindow.Show(); + } + + public static void InitEditorWindow(MA_TextureAtlasserProWindow currentEditorWindow) + { + curWindow = currentEditorWindow; + + GetCurrentWindow(); + + thisWindow.minSize = new Vector2(500,160); + thisWindow.maxSize = new Vector2(500,160); + + thisWindow.titleContent.text = "MA_ExportTextureAtlas"; + + thisWindow.Show(); + } + + private static void GetCurrentWindow() + { + thisWindow = (MA_TextureAtlasserProExportWindow)EditorWindow.GetWindow(); + } + + private void CloseWindow() + { + if(thisWindow == null) + { + GetCurrentWindow(); + thisWindow.Close(); + } + else + { + thisWindow.Close(); + } + } + + private Event ProcessEvents() + { + Event e = Event.current; + + return e; + } + + [UnityEditor.Callbacks.DidReloadScripts] + private static void OnReload() + { + //Make sure that when the compiler is finished and reloads the scripts, we are waiting for the next Event. + isLoaded = false; + } + + private void OnGUI() + { + if(thisWindow == null) + { + GetCurrentWindow(); + return; + } + + //Get current event + Event e = ProcessEvents(); + + if(isLoaded) + { + GUILayout.BeginArea(new Rect(MA_TextureAtlasserProUtils.VIEWOFFSET, MA_TextureAtlasserProUtils.VIEWOFFSET, position.width - (MA_TextureAtlasserProUtils.VIEWOFFSET * 2), position.height - (MA_TextureAtlasserProUtils.VIEWOFFSET * 2))); + GUILayout.BeginVertical(); + + + if(curWindow != null && curWindow.textureAtlas != null) + { + //Export options + GUILayout.Box("Note: No custom export options right now.. :<", EditorStyles.helpBox); + + //Export + GUILayout.BeginVertical(EditorStyles.helpBox); + + GUILayout.Label("Meshes: OBJ | Textures: PNG"); + if(GUILayout.Button("Export Atlas", GUILayout.ExpandWidth(true), GUILayout.Height(37))) + { + MA_TextureAtlasserProUtils.ExportAtlas(curWindow.textureAtlas); + } + + GUILayout.EndVertical(); + } + else if(curWindow == null) + { + GUI.backgroundColor = Color.red; + GUILayout.Box("Error: Link with the Texture Atlas Editor lost!", EditorStyles.helpBox); + if(GUILayout.Button("Link Atlas Editor", GUILayout.ExpandWidth(true), GUILayout.Height(37))) + { + curWindow = (MA_TextureAtlasserProWindow)EditorWindow.GetWindow(); + } + GUI.backgroundColor = Color.white; + } + else if(curWindow.textureAtlas == null) + { + GUI.backgroundColor = Color.red; + GUILayout.Box("Error: No Texture Atlas found make sure to open one!", EditorStyles.helpBox); + GUI.backgroundColor = Color.white; + } + + GUILayout.EndVertical(); + GUILayout.EndArea(); + } + + if(e.type == EventType.Repaint) + isLoaded = true; + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Windows/MA_TextureAtlasserProWindow.cs b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Windows/MA_TextureAtlasserProWindow.cs new file mode 100644 index 0000000..9fc42f4 --- /dev/null +++ b/MA_ToolBox/MA_TextureAtlasserPro/Scripts/Editor/Windows/MA_TextureAtlasserProWindow.cs @@ -0,0 +1,119 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace MA_TextureAtlasserPro +{ + public class MA_TextureAtlasserProWindow : EditorWindow + { + public static MA_TextureAtlasserProWindow thisWindow; + public MA_TextureAtlasserProAtlas textureAtlas; + + public MA_TextureAtlasserProWorkView workView; + public MA_TextureAtlasserProMenuView menuView; + public MA_TextureAtlasserProInspectorView inspectorView; + public MA_TextureAtlasserProDebugView debugView; + + private static bool isLoaded = false; //Make sure we wait a frame at the start to setup and don't draw. + + [MenuItem("MA_ToolKit/MA_TextureAtlasserPro/Atlas Editor")] + private static void Init() + { + GetCurrentWindow(); + + thisWindow.titleContent.text = "MA_TextureAtlasserPro"; + thisWindow.minSize = new Vector2(375, 360); + thisWindow.wantsMouseMove = true; + + thisWindow.Show(); + } + + private void OnEnable() + { + //Load the icons + MA_TextureAtlasserProIcons.LoadIcons(); + } + + private static void GetCurrentWindow() + { + thisWindow = (MA_TextureAtlasserProWindow)EditorWindow.GetWindow(); + } + + private void CloseCurrentWindow() + { + if(thisWindow == null) + { + GetCurrentWindow(); + } + thisWindow.Close(); + } + + private static void CreateViews() + { + if(thisWindow == null) + { + GetCurrentWindow(); + } + + thisWindow.workView = new MA_TextureAtlasserProWorkView(thisWindow, "workView"); + thisWindow.menuView = new MA_TextureAtlasserProMenuView(thisWindow, "menuView"); + thisWindow.inspectorView = new MA_TextureAtlasserProInspectorView(thisWindow, "inspectorView"); + thisWindow.debugView = new MA_TextureAtlasserProDebugView(thisWindow, "debugView"); + } + + private Event ProcessEvents() + { + Event e = Event.current; + + return e; + } + + [UnityEditor.Callbacks.DidReloadScripts] + private static void OnReload() + { + //Make sure that when the compiler is finished and reloads the scripts, we are waiting for the next Event. + isLoaded = false; + } + + private void OnGUI() + { + //Check window + if(thisWindow == null) + { + GetCurrentWindow(); + return; + } + + //Check views + if(workView == null || menuView == null || inspectorView == null || debugView == null) + { + CreateViews(); + return; + } + + //Get current event + Event e = ProcessEvents(); + + //Calculate view rects + Rect workViewRect = new Rect(position.width - position.width, position.height - position.height, position.width, position.height); + Rect debugViewRect = new Rect(position.width - MA_TextureAtlasserProUtils.VIEWOFFSET - 164, position.height - MA_TextureAtlasserProUtils.VIEWOFFSET - 22, 164, 22); + Rect menuViewRect = new Rect(MA_TextureAtlasserProUtils.VIEWOFFSET, MA_TextureAtlasserProUtils.VIEWOFFSET, position.width - (MA_TextureAtlasserProUtils.VIEWOFFSET * 2), 44); + Rect inspectorViewRect = new Rect(MA_TextureAtlasserProUtils.VIEWOFFSET, menuViewRect.y + menuViewRect.height + MA_TextureAtlasserProUtils.VIEWOFFSET, 164, position.height - menuViewRect.height - (MA_TextureAtlasserProUtils.VIEWOFFSET * 3)); + + //Draw views and windows in the right oder from back to front + if(isLoaded) + { + workView.UpdateView(e, workViewRect); + debugView.UpdateView(e, debugViewRect); + inspectorView.UpdateView(e, inspectorViewRect); + menuView.UpdateView(e, menuViewRect); + } + + Repaint(); + + if(e.type == EventType.Repaint) + isLoaded = true; + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_Utilities/EditorUtils/MA_EditorGridUtils.cs b/MA_ToolBox/MA_Utilities/EditorUtils/MA_EditorGridUtils.cs new file mode 100644 index 0000000..dab81a0 --- /dev/null +++ b/MA_ToolBox/MA_Utilities/EditorUtils/MA_EditorGridUtils.cs @@ -0,0 +1,61 @@ +//Maxartz15 +//Version 1.0 + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace MA_Editor.Grid +{ + public static class Grid + { + public static void DrawGrid(Rect editorWorkRect, float gridSpacing, Color gridColor) + { + //Process grid spacing values + int widthDivs = Mathf.CeilToInt(editorWorkRect.width / gridSpacing); + int heightDivs = Mathf.CeilToInt(editorWorkRect.height / gridSpacing); + + //Using handles + Handles.BeginGUI(); + Handles.color = gridColor; + + for (int x = 0; x < widthDivs; x++) + { + Handles.DrawLine(new Vector3(gridSpacing * x, 0, 0), new Vector3(gridSpacing * x, editorWorkRect.height, 0)); + } + + for (int y = 0; y < heightDivs; y++) + { + Handles.DrawLine(new Vector3(0, gridSpacing * y, 0), new Vector3(editorWorkRect.width, gridSpacing * y, 0)); + } + + Handles.color = Color.white; + Handles.EndGUI(); + } + + public static void DrawZoomableGrid(Rect editorWorkRect, float gridSpacing, Color gridColor, Vector2 zoomCoordsOrigin) + { + //Process grid spacing values + int widthDivs = Mathf.CeilToInt(editorWorkRect.width / gridSpacing); + int heightDivs = Mathf.CeilToInt(editorWorkRect.height / gridSpacing); + + //Using handles + Handles.BeginGUI(); + Handles.color = gridColor; + + for (int x = 1; x < widthDivs; x++) + { + Handles.DrawLine(new Vector3(gridSpacing * x - zoomCoordsOrigin.x, -zoomCoordsOrigin.y, 0), new Vector3(gridSpacing * x - zoomCoordsOrigin.x, editorWorkRect.height - zoomCoordsOrigin.y, 0)); + } + + for (int y = 1; y < heightDivs; y++) + { + Handles.DrawLine(new Vector3(-zoomCoordsOrigin.x, gridSpacing * y - zoomCoordsOrigin.y, 0), new Vector3(editorWorkRect.width - zoomCoordsOrigin.x, gridSpacing * y - zoomCoordsOrigin.y, 0)); + } + + Handles.color = Color.white; + Handles.EndGUI(); + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_Utilities/EditorUtils/MA_EditorRectUtils.cs b/MA_ToolBox/MA_Utilities/EditorUtils/MA_EditorRectUtils.cs new file mode 100644 index 0000000..ba1c65d --- /dev/null +++ b/MA_ToolBox/MA_Utilities/EditorUtils/MA_EditorRectUtils.cs @@ -0,0 +1,70 @@ +//Maxartz15 +//Version 1.0 + +using UnityEngine; +using MA_Editor; + +namespace MA_Editor.RectUtils +{ + public static class RectUtils + { + //Start http://martinecker.com/martincodes/unity-editor-window-zooming/ + public static Vector2 TopLeft(this Rect rect) + { + return new Vector2(rect.xMin, rect.yMin); + } + + public static Rect ScaleSizeBy(this Rect rect, float scale) + { + return rect.ScaleSizeBy(scale, rect.center); + } + + public static Rect ScaleSizeBy(this Rect rect, float scale, Vector2 pivotPoint) + { + Rect result = rect; + result.x -= pivotPoint.x; + result.y -= pivotPoint.y; + result.xMin *= scale; + result.xMax *= scale; + result.yMin *= scale; + result.yMax *= scale; + result.x += pivotPoint.x; + result.y += pivotPoint.y; + return result; + } + + public static Rect ScaleSizeBy(this Rect rect, Vector2 scale) + { + return rect.ScaleSizeBy(scale, rect.center); + } + + public static Rect ScaleSizeBy(this Rect rect, Vector2 scale, Vector2 pivotPoint) + { + Rect result = rect; + result.x -= pivotPoint.x; + result.y -= pivotPoint.y; + result.xMin *= scale.x; + result.xMax *= scale.x; + result.yMin *= scale.y; + result.yMax *= scale.y; + result.x += pivotPoint.x; + result.y += pivotPoint.y; + return result; + } + //End http://martinecker.com/martincodes/unity-editor-window-zooming/ + + public static Rect MultiplyRectSize(Rect rect, float amount) + { + Rect multipliedRect = new Rect(rect.x, rect.y, rect.width * amount, rect.height * amount); + return multipliedRect; + } + + public static Rect MultiplyRectSizeAndCenter(Rect rect, float amount) + { + Rect multipliedRect = new Rect(rect.x, rect.y, rect.width * amount, rect.height * amount); + multipliedRect.x = -(multipliedRect.width / 2); + multipliedRect.y = -(multipliedRect.height / 2); + return multipliedRect; + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_Utilities/EditorUtils/MA_EditorZoomUtils.cs b/MA_ToolBox/MA_Utilities/EditorUtils/MA_EditorZoomUtils.cs new file mode 100644 index 0000000..1e0ceb0 --- /dev/null +++ b/MA_ToolBox/MA_Utilities/EditorUtils/MA_EditorZoomUtils.cs @@ -0,0 +1,39 @@ +//Maxartz15 +//Version 1.0 + +using UnityEngine; +using MA_Editor; +using MA_Editor.RectUtils; + +namespace MA_Editor.GUILayoutZoom +{ + //http://martinecker.com/martincodes/unity-editor-window-zooming/ + public class GUILayoutZoom + { + private const float EditorWindowTabHeight = 21.0f; //The height of the editor window top bar. (were the name, zoom and exit buttons are) + private static Matrix4x4 prevGuiMatrix; + + public static Rect BeginArea(float zoomScale, Rect screenCoordsArea) + { + GUI.EndGroup(); // End the group Unity begins automatically for an EditorWindow to clip out the window tab. This allows us to draw outside of the size of the EditorWindow. + + Rect clippedArea = screenCoordsArea.ScaleSizeBy(1.0f / zoomScale, screenCoordsArea.TopLeft()); + clippedArea.y += EditorWindowTabHeight; + GUI.BeginGroup(clippedArea); + + prevGuiMatrix = GUI.matrix; + Matrix4x4 translation = Matrix4x4.TRS(clippedArea.TopLeft(), Quaternion.identity, Vector3.one); + Matrix4x4 scale = Matrix4x4.Scale(new Vector3(zoomScale, zoomScale, 1.0f)); + GUI.matrix = translation * scale * translation.inverse * GUI.matrix; + + return clippedArea; + } + + public static void EndArea() + { + GUI.matrix = prevGuiMatrix; + GUI.EndGroup(); + GUI.BeginGroup(new Rect(0.0f, EditorWindowTabHeight, Screen.width, Screen.height)); + } + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_Utilities/MeshUtils/MA_MeshUtils.cs b/MA_ToolBox/MA_Utilities/MeshUtils/MA_MeshUtils.cs new file mode 100644 index 0000000..cf8c569 --- /dev/null +++ b/MA_ToolBox/MA_Utilities/MeshUtils/MA_MeshUtils.cs @@ -0,0 +1,187 @@ +//Maxartz15 +//Version 1.0 + +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace MA_Mesh +{ + public static class MA_MeshUtils + { + public static void MA_SaveMeshAsset(Mesh mesh, string savePath, string meshName = "") + { + Mesh newMesh = new Mesh(); + newMesh.SetVertices(new List(mesh.vertices)); + newMesh.SetTriangles(mesh.triangles, 0); + newMesh.SetUVs(0, new List(mesh.uv)); + + if(meshName == "") + { + newMesh.name = mesh.name; + } + else + { + newMesh.name = meshName; + } + + AssetDatabase.CreateAsset(newMesh, savePath); + AssetDatabase.SaveAssets(); + } + + public static Mesh MA_DuplicateMesh(Mesh mesh) + { + Mesh newMesh = new Mesh(); + + newMesh.SetVertices(new List(mesh.vertices)); + for (int i = 0; i < mesh.subMeshCount; i++) + { + newMesh.SetTriangles(mesh.GetTriangles(i), i); + } + newMesh.SetNormals(new List(mesh.normals)); + newMesh.SetUVs(0, new List(mesh.uv)); + newMesh.SetTangents(new List(mesh.tangents)); + + return newMesh; + } + + public static Mesh MA_ReMapUV(this Mesh mesh, Vector2 atlasSize, Vector2 textureSize, Vector2 texturePosition, int uvChannel = 0) + { + /* + 0 1 + 512 x 512 + + 0 .5 = 1 / 512 * 256 + 256 x 256 + + + pos + */ + + List uvs = new List(); + + //Get UV's + mesh.GetUVs(uvChannel, uvs); + + foreach (Vector2 uvCordinate in uvs) + { + float x = (uvCordinate.x / atlasSize.x * textureSize.x) + texturePosition.x; + float y = (uvCordinate.y / atlasSize.y * textureSize.y) + texturePosition.y; + uvCordinate.Set(x, y); + } + + mesh.SetUVs(uvChannel, uvs); + + return mesh; + } + + public static Mesh MA_UVReMap(this Mesh mesh, Vector2 atlasSize, Rect textureRect, int uvChannel = 0, bool flipY = true) + { + List uvs = new List(); + + //Get UV's + mesh.GetUVs(uvChannel, uvs); + + for (int i = 0; i < uvs.Count; i++) + { + if(flipY) + { + Debug.Log("01" + uvs[i].x); + uvs[i] = new Vector2((uvs[i].x / atlasSize.x * textureRect.width) + (1 / atlasSize.x * textureRect.x), (uvs[i].y / atlasSize.y * textureRect.height) + (1 / atlasSize.y * (atlasSize.y - textureRect.height - textureRect.y))); + Debug.Log("02" + uvs[i].x); + } + else + { + Debug.Log("01" + uvs[i].x); + uvs[i] = new Vector2((uvs[i].x / atlasSize.x * textureRect.width) + (1 / atlasSize.x * textureRect.x), (uvs[i].y / atlasSize.y * textureRect.height) + (1 / atlasSize.y * textureRect.y)); + Debug.Log("02" + uvs[i].x); + } + } + + mesh.SetUVs(uvChannel, uvs); + + return mesh; + } + + //Start http://wiki.unity3d.com/index.php?title=ObjExporter + public static string MeshToString(Mesh mesh) + { + int vertexOffset = 0; + int normalOffset = 0; + int uvOffset = 0; + + + Material material = new Material(Shader.Find("Standard")); + + StringBuilder sb = new StringBuilder(); + + sb.Append("g ").Append(mesh.name).Append("\n"); + + foreach(Vector3 v in mesh.vertices) + { + //This is sort of ugly - inverting x-component since we're in + //a different coordinate system than "everyone" is "used to". + sb.Append(string.Format("v {0} {1} {2}\n", -v.x, v.y, v.z)); + } + + sb.Append("\n"); + + foreach(Vector3 v in mesh.normals) + { + sb.Append(string.Format("vn {0} {1} {2}\n", -v.x, v.y, v.z)); + } + + sb.Append("\n"); + + foreach(Vector3 v in mesh.uv) + { + sb.Append(string.Format("vt {0} {1}\n", v.x, v.y)); + } + + for (int m = 0 ; m < mesh.subMeshCount; m++) + { + sb.Append("\n"); + sb.Append("usemtl ").Append(material.name + m).Append("\n"); + sb.Append("usemap ").Append(material.name + m).Append("\n"); + + // int[] triangles = mesh.GetTriangles(m); + // for (int i = 0; i < triangles.Length; i += 3) + // { + // sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", triangles[i]+1, triangles[i+1]+1, triangles[i+2]+1)); + // } + + int[] triangles = mesh.GetTriangles(m); + for (int i = 0; i < triangles.Length; i += 3) + { + //Because we inverted the x-component, we also needed to alter the triangle winding. + sb.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n", triangles[i]+ 1 + vertexOffset, triangles[i + 1] + 1 + normalOffset, triangles[i +2 ] + 1 + uvOffset)); + } + } + + vertexOffset += mesh.vertices.Length; + normalOffset += mesh.normals.Length; + uvOffset += mesh.uv.Length; + + return sb.ToString(); + } + + public static void MeshToFile(Mesh mesh, string filename, string savePath) + { + using (StreamWriter sw = new StreamWriter(savePath + filename + ".obj")) + { + sw.Write(MeshToString(mesh)); + Debug.Log(savePath + filename); + } + } + //End + } + + struct ObjMaterial + { + public string name; + public string textureName; + } +} \ No newline at end of file diff --git a/MA_ToolBox/MA_Utilities/TextureUtils/MA_TextureUtils.cs b/MA_ToolBox/MA_Utilities/TextureUtils/MA_TextureUtils.cs new file mode 100644 index 0000000..3375c14 --- /dev/null +++ b/MA_ToolBox/MA_Utilities/TextureUtils/MA_TextureUtils.cs @@ -0,0 +1,203 @@ +//Maxartz15 +//Version 1.0 +//Part of MA_TextureUtils +//https://github.com/maxartz15/MA_TextureUtils + +using UnityEngine; +using UnityEditor; +using System.IO; +using System.Collections; +using System.Collections.Generic; + +//http://www.gamasutra.com/blogs/JoshSutphin/20131007/201829/Adding_to_Unitys_BuiltIn_Classes_Using_Extension_Methods.php +//https://forum.unity3d.com/threads/contribution-texture2d-blur-in-c.185694/ +//http://orbcreation.com/orbcreation/page.orb?1180 +//https://support.unity3d.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures- + +namespace MA_Texture +{ + public static class MA_TextureUtils + { + /// + /// Some base converters and texture settings setters. + /// + + public static Texture ConvertToReadableTexture(Texture texture) + { + if (texture == null) + return texture; + // Create a temporary RenderTexture of the same size as the texture + RenderTexture tmp = RenderTexture.GetTemporary( + texture.width, + texture.height, + 0, + RenderTextureFormat.Default, + RenderTextureReadWrite.Linear); + + // Blit the pixels on texture to the RenderTexture + Graphics.Blit(texture, tmp); + + // Backup the currently set RenderTexture + RenderTexture previous = RenderTexture.active; + + // Set the current RenderTexture to the temporary one we created + RenderTexture.active = tmp; + + // Create a new readable Texture2D to copy the pixels to it + Texture2D myTexture2D = new Texture2D(texture.width, texture.width); + + // Copy the pixels from the RenderTexture to the new Texture + myTexture2D.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0); + myTexture2D.Apply(); + + // Reset the active RenderTexture + RenderTexture.active = previous; + + // Release the temporary RenderTexture + RenderTexture.ReleaseTemporary(tmp); + // "myTexture2D" now has the same pixels from "texture" and it's readable. + + return myTexture2D; + } + + #region Save + public static Texture2D MA_Save2D(this Texture2D texture, string textureName, string savePath) + { + if (!Directory.Exists(savePath)) + Directory.CreateDirectory(savePath); + + FileStream fs = new FileStream(savePath + "/" + textureName + ".png", FileMode.Create); + BinaryWriter bw = new BinaryWriter(fs); + + bw.Write(texture.EncodeToPNG()); + bw.Close(); + fs.Close(); + + Debug.Log("Saved texture: " + texture.name); + + AssetDatabase.Refresh(); + + return texture; + } + + public static Texture MA_Save(this Texture texture, string name, string savePath) + { + Texture2D texture2D = (Texture2D)MA_TextureUtils.ConvertToReadableTexture(texture); + + texture2D.MA_Save2D(name, savePath); + + texture = texture2D; + + return texture; + } + #endregion + + #region Scale + public static Texture2D MA_Scale2D(this Texture2D texture, int newWidth, int newHeight) + { + Texture2D texture2D = new Texture2D(newWidth, newHeight); + float ratioWidth = texture.width / newWidth; + float ratioHeight = texture.height / newHeight; + + for (int x = 0; x < texture.width; x++) + { + for (int y = 0; y < texture.height; y++) + { + Color pixel = texture.GetPixel(x, y); + int posX = Mathf.FloorToInt(x / ratioWidth); + int posY = Mathf.FloorToInt(y / ratioHeight); + texture2D.SetPixel(posX, posY, new Color(pixel.r, pixel.g, pixel.b, pixel.a)); + } + } + texture2D.Apply(); + + return texture2D; + } + + public static Texture MA_Scale(this Texture texture, int newWidth, int newHeight) + { + Texture2D texture2D = (Texture2D)MA_TextureUtils.ConvertToReadableTexture(texture); + + texture2D.MA_Scale2D(newWidth, newHeight); + + texture = texture2D; + + return texture; + } + + public static Texture2D MA_Scale22D(this Texture2D texture, float width, float height) + { + float ratioWidth = width / texture.width; + float ratioHeight = height / texture.height; + + int newWidth = Mathf.RoundToInt(texture.width * ratioWidth); + int newHeight = Mathf.RoundToInt(texture.height * ratioHeight); + + Texture2D newTexture = new Texture2D(newWidth, newHeight); + + for (int x = 0; x < texture.width; x++) + { + for (int y = 0; y < texture.height; y++) + { + Color pixel = texture.GetPixel(x, y); + int posX = Mathf.RoundToInt(x * ratioWidth); + int posY = Mathf.RoundToInt(y * ratioHeight); + newTexture.SetPixel(posX, posY, new Color(pixel.r, pixel.g, pixel.b, pixel.a)); + } + } + + newTexture.name = texture.name; + + newTexture.Apply(); + return newTexture; + } + + public static Texture MA_Scale2(this Texture texture, float newWidth, float newHeight) + { + Texture2D texture2D = (Texture2D)MA_TextureUtils.ConvertToReadableTexture(texture); + + texture = texture2D.MA_Scale22D(newWidth, newHeight); + + return texture; + } + #endregion + + #region combine + public static Texture2D MA_Combine2D(this Texture2D texture, Texture2D combineTexture, int offsetX, int offsetY, bool flipY = true) + { + for (int x = 0; x < combineTexture.width; x++) + { + if(flipY) + { + //Y is 'flipped' because textures are made from left to right, bottom to top. We want to draw from left to right and top to bottom. + for (int y = combineTexture.height; y > 0; y--) + { + texture.SetPixel(x + offsetX, texture.height - y - offsetY, combineTexture.GetPixel(x, texture.height - y)); + } + } + else + { + for (int y = 0; y < combineTexture.height; y++) + { + texture.SetPixel(x + offsetX, y + offsetY, combineTexture.GetPixel(x, y)); + } + } + } + + texture.Apply(); + + return texture; + } + + public static Texture MA_Combine(this Texture texture, Texture combineTexture, int offsetX, int offsetY) + { + Texture2D texture2D = (Texture2D)MA_TextureUtils.ConvertToReadableTexture(texture); + Texture2D combineTexture2D = (Texture2D)MA_TextureUtils.ConvertToReadableTexture(texture); + + texture = texture2D.MA_Combine2D(combineTexture2D, offsetX, offsetY); + + return texture; + } + #endregion + } +} \ No newline at end of file