Search Unity

Building an Atlas Slicer

Discussion in 'Scripting' started by Studio_Akiba, Aug 19, 2020.

  1. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,426
    alright, following difficulty with converting slices sprites to textures, I decided to build an editor window to do this.
    So far, I have a way to load up a texture, display divider lines, and set how many textures there are in the atlas.

    I've hit a bit of a snag. When I set the texture count greater than the x axis dimensions, the display just continues adding tiles to the right, and I can't work out how to get it to drop down, so I can get the other rows.

    This is kind of difficult to explain so I'm just going to attach my script below.

    I believe this bug is on line 246, but I can't work out for the life of me how to fix it. I've tried many combinations of calculations for the Rect locations and can't work it out.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System;
    6.  
    7. public class ArcaneAtlasSlicer : EditorWindow
    8. {
    9.     private Vector2 _scrollPosition;
    10.     private Vector2 _scrollPosition2;
    11.  
    12.     bool debugSect;
    13.     bool texSect;
    14.  
    15.     private List<Texture2D> slicedTextures;
    16.  
    17.     Color headerColor = new Color(0.65f, 0.65f, 0.65f, 1);
    18.  
    19.     GUIStyle btnSmall;
    20.  
    21.     Texture2D activeTexture;
    22.     Vector2 atlasDimensions = new Vector2(1f, 1f);
    23.     int atlasTextureCnt;
    24.     Color debugLineColor = Color.white;
    25.     bool debugLines = true;
    26.     Color debugTexColor = new Color(1f, 0.5f, 0.5f, 1.0f);
    27.     bool debugTexs = true;
    28.  
    29.     bool example;
    30.  
    31.     [MenuItem("Arcane Engine/Atlas Slicer", false, 102)]
    32.     public static void Init()
    33.     {
    34.         EditorWindow arcaneSlicer = GetWindow(typeof(ArcaneAtlasSlicer), false, "Arc Slicer");
    35.         arcaneSlicer.Show();
    36.     }
    37.  
    38.     void OnInspectorUpdate()
    39.     {
    40.         Repaint();
    41.     }
    42.  
    43.     void OnGUI()
    44.     {
    45.         #region setup
    46.         Rect texRect = new Rect((position.width / 4) / 2, (position.height - ((position.width / 4) * 2)) / 2, (position.width / 4) * 2, (position.width / 4) * 2);
    47.  
    48.         btnSmall = new GUIStyle("ShurikenModuleTitle");
    49.         btnSmall.fixedHeight = 20;
    50.         btnSmall.fixedWidth = 20;
    51.         btnSmall.padding = new RectOffset(-10, 0, 0, 0);
    52.         btnSmall.margin = new RectOffset(0, 4, 2, 0);
    53.         #endregion
    54.  
    55.         Vector2 tmpDimensions = new Vector2((float)Math.Truncate(atlasDimensions.x), (float)Math.Truncate(atlasDimensions.y));
    56.         if (tmpDimensions.x < 1)
    57.         {
    58.             tmpDimensions.x = 1;
    59.         }
    60.         if (tmpDimensions.y < 1)
    61.         {
    62.             tmpDimensions.y = 1;
    63.         }
    64.  
    65.         atlasDimensions = tmpDimensions;
    66.  
    67.         if (atlasTextureCnt < 1)
    68.         {
    69.             atlasTextureCnt = 1;
    70.         }
    71.         if (atlasTextureCnt > tmpDimensions.x * tmpDimensions.y)
    72.         {
    73.             atlasTextureCnt = (int)(tmpDimensions.x * tmpDimensions.y);
    74.         }
    75.  
    76.         if (!EditorGUIUtility.isProSkin)
    77.         {
    78.             headerColor = new Color(165 / 255f, 165 / 255f, 165 / 255f, 1);
    79.             //backgroundColor = new Color(193 / 255f, 193 / 255f, 193 / 255f, 1);
    80.         }
    81.         else
    82.         {
    83.             headerColor = new Color(41 / 255f, 41 / 255f, 41 / 255f, 1);
    84.             //backgroundColor = new Color(56 / 255f, 56 / 255f, 56 / 255f, 1);
    85.         }
    86.  
    87.         GUIStyle labelCentred = new GUIStyle("Label");
    88.         labelCentred.alignment = TextAnchor.MiddleCenter;
    89.  
    90.         GUIStyle bigLabelCentre = new GUIStyle("Label");
    91.         bigLabelCentre.alignment = TextAnchor.MiddleCenter;
    92.         bigLabelCentre.fontSize = 20;
    93.         bigLabelCentre.stretchHeight = true;
    94.         bigLabelCentre.stretchWidth = true;
    95.  
    96.         Texture2D backg = new Texture2D(1, 1, TextureFormat.RGBA32, false);
    97.         backg.SetPixel(0, 0, new Color(0.30f, 0.30f, 0.30f, 1.0f));
    98.         backg.Apply();
    99.  
    100.         Texture2D debugBg = new Texture2D(1, 1, TextureFormat.RGBA32, false);
    101.         debugBg.SetPixel(0, 0, debugTexColor);
    102.         debugBg.Apply();
    103.  
    104.         EditorGUILayout.BeginHorizontal(); //Begin Whole Window
    105.  
    106.         #region Sidebar
    107.         EditorGUILayout.BeginVertical(GUILayout.Width(position.width / 4)); //Begin Sidebar
    108.         _scrollPosition2 = GUILayout.BeginScrollView(_scrollPosition2);
    109.  
    110.         GUI.DrawTexture(new Rect(0, 0, position.width / 4, position.height), backg, ScaleMode.StretchToFill);
    111.  
    112.         EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.ExpandWidth(true));
    113.         {
    114.             GUILayout.Label("Menu", labelCentred);
    115.         }
    116.         EditorGUILayout.EndHorizontal();
    117.  
    118.         //Texture
    119.         GUILayout.Label("Atlas", EditorStyles.boldLabel);
    120.         activeTexture = (Texture2D)EditorGUILayout.ObjectField("Atlas Texture", activeTexture, typeof(Texture2D), true);
    121.         using (new EditorGUILayout.HorizontalScope())
    122.         {
    123.             GUI.backgroundColor = Color.red;
    124.             if (GUILayout.Button("Clear Atlas Texture"))
    125.             {
    126.                 activeTexture = null;
    127.             }
    128.             GUI.backgroundColor = Color.white;
    129.         }
    130.  
    131.         EditorGUILayout.Space();
    132.  
    133.         //Settings
    134.         GUILayout.Label("Atlas Settings", EditorStyles.boldLabel);
    135.         atlasDimensions = EditorGUILayout.Vector2Field("Atlas Dimensions", atlasDimensions);
    136.  
    137.         using (new EditorGUILayout.HorizontalScope())
    138.         {
    139.             GUILayout.Label("");
    140.             if (GUILayout.Button(new GUIContent("+", "x + 1")))
    141.             {
    142.                 atlasDimensions.x++;
    143.             }
    144.             if (GUILayout.Button(new GUIContent("-", "x - 1")))
    145.             {
    146.                 atlasDimensions.x--;
    147.             }
    148.             GUILayout.Label("");
    149.             if (GUILayout.Button(new GUIContent("+", "y + 1")))
    150.             {
    151.                 atlasDimensions.y++;
    152.             }
    153.             if (GUILayout.Button(new GUIContent("-", "y - 1")))
    154.             {
    155.                 atlasDimensions.y--;
    156.             }
    157.         }
    158.         EditorGUILayout.HelpBox("The dimensions the atlas will be divided by. 4 images in a 2x2 grid would be x2 y2 (use whole numbers).", MessageType.None);
    159.         atlasTextureCnt = EditorGUILayout.IntField("Atlas Texture Count", atlasTextureCnt);
    160.  
    161.         using (new EditorGUILayout.HorizontalScope())
    162.         {
    163.             GUILayout.Label("");
    164.             if (GUILayout.Button(new GUIContent("+", "Texture count + 1")))
    165.             {
    166.                 atlasTextureCnt++;
    167.             }
    168.             if (GUILayout.Button(new GUIContent("-", "Texture count - 1")))
    169.             {
    170.                 atlasTextureCnt--;
    171.             }
    172.         }
    173.         EditorGUILayout.HelpBox("The total number of individual textures in the atlas (allows blank spaces to be ignored).", MessageType.None);
    174.  
    175.         EditorGUILayout.Space();
    176.  
    177.         debugSect = Foldout("Debug", debugSect);
    178.         if (debugSect)
    179.         {
    180.             debugLines = EditorGUILayout.Toggle("Debug Lines", debugLines);
    181.             debugLineColor = EditorGUILayout.ColorField("Line Color", debugLineColor);
    182.             debugTexs = EditorGUILayout.Toggle("Debug Textures", debugTexs);
    183.             debugTexColor = EditorGUILayout.ColorField("Texture Color", debugTexColor);
    184.         }
    185.  
    186.         //Build sliced Images
    187.         texSect = Foldout("Textures", texSect);
    188.         if(texSect)
    189.         {
    190.             if(slicedTextures.Count <= 0)
    191.             {
    192.                 GUILayout.Label("No sliced textures available.");
    193.             }
    194.             for(int i = 0; i < atlasTextureCnt; i++)
    195.             {
    196.                 slicedTextures[i] = (Texture2D)EditorGUILayout.ObjectField(i.ToString() + " Sliced", slicedTextures[i], typeof(Texture2D), true);
    197.                 slicedTextures[i] = activeTexture;
    198.             }
    199.             if(slicedTextures.Count > 0)
    200.             {
    201.                 GUI.backgroundColor = Color.green;
    202.                 if(GUILayout.Button("Export Textures"))
    203.                 {
    204.  
    205.                 }
    206.                 GUI.backgroundColor = Color.white;
    207.             }
    208.         }
    209.  
    210.         GUILayout.EndScrollView();
    211.         EditorGUILayout.EndVertical(); //End Sidebar
    212.         #endregion
    213.  
    214.         #region Main Window
    215.         EditorGUILayout.BeginVertical(); //Begin Main Window
    216.         _scrollPosition = GUILayout.BeginScrollView(_scrollPosition);
    217.  
    218.         EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.ExpandWidth(true));
    219.         {
    220.             GUILayout.Label("Arcane Engine Atlas Slicer", labelCentred);
    221.         }
    222.         EditorGUILayout.EndHorizontal();
    223.  
    224.         if (activeTexture == null)
    225.         {
    226.             //Display Error
    227.             GUILayout.Label("No Atlas Selected", bigLabelCentre);
    228.         }
    229.         else
    230.         {
    231.             //Display Texture
    232.             GUI.DrawTexture(texRect, activeTexture);
    233.  
    234.             //Draw Bounding Lines
    235.             Handles.BeginGUI();
    236.  
    237.             //Generate Debugs
    238.             if (debugTexs)
    239.             {
    240.                 for (int i = 0; i < atlasTextureCnt; i++)
    241.                 {
    242.                     GUIStyle tmpTex = new GUIStyle("Label");
    243.                     tmpTex.fontSize = 15;
    244.                     tmpTex.contentOffset = new Vector2(texRect.xMin, texRect.yMin + texRect.height / atlasDimensions.y * i);
    245.  
    246.                     GUI.DrawTexture(new Rect(texRect.x + texRect.width / atlasDimensions.x * i, texRect.y, texRect.width / atlasDimensions.x, texRect.height / atlasDimensions.y), debugBg, ScaleMode.StretchToFill);
    247.                 }
    248.             }
    249.  
    250.             Handles.color = debugLineColor;
    251.             Handles.DrawLine(new Vector3(texRect.xMin - 20, texRect.yMin), new Vector3(texRect.xMax + 20, texRect.yMin));   //Top Horizontal
    252.             Handles.DrawLine(new Vector3(texRect.xMax, texRect.yMin - 20), new Vector3(texRect.xMax, texRect.yMax + 20));   //Bottom Horizontal
    253.             Handles.DrawLine(new Vector3(texRect.xMin, texRect.yMin - 20), new Vector3(texRect.xMin, texRect.yMax + 20));   //Left Vertical
    254.             Handles.DrawLine(new Vector3(texRect.xMin - 20, texRect.yMax), new Vector3(texRect.xMax + 20, texRect.yMax));   //Right Vertical
    255.  
    256.             if (debugLines)
    257.             {
    258.                 //Draw Vertical Dimension Handles
    259.                 for (int i = 1; i < atlasDimensions.x; i++)
    260.                 {
    261.                     Handles.DrawLine(new Vector3(texRect.xMin + texRect.width / atlasDimensions.x * i, texRect.yMin), new Vector3(texRect.xMin + texRect.width / atlasDimensions.x * i, texRect.yMax));
    262.                 }
    263.                 //Draw Horizontal Dimension Handles
    264.                 for (int i = 1; i < atlasDimensions.y; i++)
    265.                 {
    266.                     Handles.DrawLine(new Vector3(texRect.xMin, texRect.yMin + texRect.height / atlasDimensions.y * i), new Vector3(texRect.xMax, texRect.yMin + texRect.height / atlasDimensions.y * i));
    267.                 }
    268.             }
    269.  
    270.             Handles.EndGUI();
    271.         }
    272.  
    273.         GUILayout.EndScrollView();
    274.         EditorGUILayout.EndVertical(); //End Main Window
    275.         #endregion
    276.         EditorGUILayout.EndHorizontal(); //End Whole Window
    277.     }
    278.  
    279.     public static bool Foldout(string title, bool display)
    280.     {
    281.         var style = new GUIStyle("ShurikenModuleTitle");
    282.         style.font = new GUIStyle(EditorStyles.label).font;
    283.         style.border = new RectOffset(15, 7, 4, 4);
    284.         style.fixedHeight = 22;
    285.         style.contentOffset = new Vector2(20f, -2f);
    286.  
    287.         var rect = GUILayoutUtility.GetRect(16f, 22f, style);
    288.         GUI.Box(rect, title, style);
    289.  
    290.         var e = Event.current;
    291.  
    292.         var toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f);
    293.         if (e.type == EventType.Repaint)
    294.         {
    295.             EditorStyles.foldout.Draw(toggleRect, false, false, display, false);
    296.         }
    297.  
    298.         if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition))
    299.         {
    300.             display = !display;
    301.             e.Use();
    302.         }
    303.  
    304.         return display;
    305.     }
    306. }
     
    Last edited: Aug 19, 2020