Advertisement
Guest User

Unity Texture Atlas Generator

a guest
Nov 10th, 2011
5,288
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.30 KB | None | 0 0
  1.  
  2. /*
  3.  * Texture atlas generator. Based of lightmap algorithm here: http://www.blackpawn.com/texts/lightmaps/.
  4.  * Jacob Schieck - 2011 - http://www.jacobschieck.com
  5.  * Usage
  6.  *      1. Open the window (Window/Atlas Creator).
  7.  *      2. Set a width and height for atlas.
  8.  *      3. Drag directory with textures for atlasing from Unity project.
  9.  *      4. Click create, it will ask a save location for the atlas(s) if more than one is needed.
  10.  *              Also creates a txt file with orignal file names, and new positions on the atlas.
  11.  * */
  12.  
  13.  
  14.  
  15. using UnityEngine;
  16. using System.Collections;
  17. using UnityEditor;
  18. using System.Collections.Generic;
  19. using System.IO;
  20. using System.Text.RegularExpressions;
  21. using System.Linq;
  22.  
  23. public class AtlasGenerator : EditorWindow
  24. {
  25.     static int width = 512;
  26.     static int height = 512;
  27.     static bool searchSubDir = true;
  28.     UnityEngine.Object directory;
  29.  
  30.     [MenuItem("Window/Atlas Creator")]
  31.     static void OpenWindow()
  32.     {
  33.         EditorWindow.GetWindow(typeof(AtlasGenerator));
  34.     }
  35.  
  36.     void OnGUI()
  37.     {
  38.         EditorGUIUtility.LookLikeInspector();
  39.         width = EditorGUILayout.IntField("Width:", width);
  40.         height = EditorGUILayout.IntField("Height:", height);
  41.         directory = EditorGUILayout.ObjectField("Textures Directory:", directory, typeof(UnityEngine.Object));
  42.         searchSubDir = EditorGUILayout.Toggle("Search sub-directories:", searchSubDir);
  43.         if (GUILayout.Button("Create Atlas(s)"))
  44.         {
  45.             Execute(AssetDatabase.GetAssetPath(directory));
  46.         }
  47.     }
  48.  
  49.     void Execute(string path)
  50.     {
  51.         DirectoryInfo di = new DirectoryInfo(path);
  52.         Run(di);
  53.     }
  54.  
  55.     void Run(DirectoryInfo directory)
  56.     {
  57.         List<FileInfo> imageFiles = GetImageFiles(directory);
  58.         List<ImageName> textureList = new List<ImageName>();
  59.  
  60.  
  61.         foreach (FileInfo f in imageFiles)
  62.         {
  63.  
  64.             string path = @"Assets\" + Regex.Split(f.FullName, @"Assets")[1].Remove(0, 1);
  65.             Texture2D image = (Texture2D)AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D));
  66.  
  67.             if (image.width > width || image.height > height)
  68.             {
  69.                 Debug.LogError("Error: '" + f.Name + "' (" + image.width + "x" + image.height + ") is larger than the atlas (" + width + "x" + height + ")");
  70.                 return;
  71.             }
  72.  
  73.             textureList.Add(new ImageName(image, f.Name));
  74.         }
  75.  
  76.         List<AtlasedTexture> textures = new List<AtlasedTexture>();
  77.         textures.Add(new AtlasedTexture(width, height));
  78.  
  79.         int count = 0;
  80.         foreach (ImageName imageName in textureList)
  81.         {
  82.             bool added = false;
  83.             foreach (AtlasedTexture texture in textures)
  84.             {
  85.                 if (texture.AddImage(imageName.image, imageName.name))
  86.                 {
  87.                     added = true;
  88.                     break;
  89.                 }
  90.             }
  91.  
  92.             if (!added)
  93.             {
  94.                 AtlasedTexture texture = new AtlasedTexture(width, height);
  95.                 texture.AddImage(imageName.image, imageName.name);
  96.                 textures.Add(texture);
  97.                 Debug.Log("Creating another atlas");
  98.             }
  99.         }
  100.  
  101.         count = 0;
  102.  
  103.         foreach (AtlasedTexture texture in textures)
  104.         {
  105.             string path = EditorUtility.SaveFilePanel("Save atlased texture...", Application.dataPath, "atlasedTexture" + count, "png");
  106.             Debug.Log("Writing atlas: " + path);
  107.             texture.Write(path);
  108.             count++;
  109.         }
  110.     }
  111.  
  112.     private List<FileInfo> GetImageFiles(DirectoryInfo directory)
  113.     {
  114.         string[] files = Directory.GetFiles(directory.FullName, "*.*", (searchSubDir) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
  115.             .Where(s => s.ToLower().EndsWith(".png") || s.ToLower().EndsWith(".tga") || s.ToLower().EndsWith(".jpg") ||
  116.                    s.ToLower().EndsWith(".psd") || s.ToLower().EndsWith(".dds")).ToArray();
  117.         Debug.Log(files.Length + " textures found.");
  118.         List<FileInfo> fileList = new List<FileInfo>();
  119.         foreach (string p in files) fileList.Add(new FileInfo(p));
  120.         return new List<FileInfo>(fileList);
  121.     }
  122.  
  123.     private class ImageName
  124.     {
  125.         public Texture2D image;
  126.         public string name;
  127.  
  128.         public ImageName(Texture2D image, string name)
  129.         {
  130.             this.image = image;
  131.             this.name = name;
  132.         }
  133.     }
  134.  
  135.     public class AtlasedTexture
  136.     {
  137.         private class Node
  138.         {
  139.             public Rect rect;
  140.             public Node[] child;
  141.             public Texture2D image;
  142.  
  143.             public Node(int x, int y, int width, int height)
  144.             {
  145.                 rect = new Rect(x, y, width, height);
  146.                 child = new Node[2];
  147.                 child[0] = null;
  148.                 child[1] = null;
  149.                 image = null;
  150.             }
  151.  
  152.             public bool IsLeaf()
  153.             {
  154.                 return child[0] == null && child[1] == null;
  155.             }
  156.  
  157.             public Node Insert(Texture2D image)
  158.             {
  159.                 if (!IsLeaf())
  160.                 {
  161.                     Node newNode = child[0].Insert(image);
  162.  
  163.                     if (newNode != null)
  164.                     {
  165.                         return newNode;
  166.                     }
  167.  
  168.                     return child[1].Insert(image);
  169.                 }
  170.                 else
  171.                 {
  172.                     if (this.image != null)
  173.                     {
  174.                         return null;
  175.                     }
  176.  
  177.                     if (image.width > rect.width || image.height > rect.height)
  178.                     {
  179.                         return null;
  180.                     }
  181.  
  182.                     if (image.width == rect.width && image.height == rect.height)
  183.                     {
  184.                         this.image = image;
  185.                         return this;
  186.                     }
  187.  
  188.                     int dw = (int)rect.width - image.width;
  189.                     int dh = (int)rect.height - image.height;
  190.  
  191.                     if (dw > dh)
  192.                     {
  193.                         child[0] = new Node((int)rect.x, (int)rect.y, (int)image.width, (int)rect.height);
  194.                         child[1] = new Node((int)rect.x + (int)image.width, (int)rect.y, (int)rect.width - (int)image.width, (int)rect.height);
  195.                     }
  196.                     else
  197.                     {
  198.                         child[0] = new Node((int)rect.x, (int)rect.y, (int)rect.width, (int)image.height);
  199.                         child[1] = new Node((int)rect.x, (int)rect.y + (int)image.height, (int)rect.width, (int)rect.height - image.height);
  200.                     }
  201.  
  202.                     return child[0].Insert(image);
  203.                 }
  204.             }
  205.         }
  206.         private Texture2D image;
  207.         private Node root;
  208.         private Dictionary<string, Rect> rectangleMap;
  209.  
  210.         public AtlasedTexture(int width, int height)
  211.         {
  212.             image = new Texture2D(width, height);
  213.             root = new Node(0, 0, width, height);
  214.             rectangleMap = new Dictionary<string, Rect>();
  215.         }
  216.  
  217.         public bool AddImage(Texture2D img, string name)
  218.         {
  219.             Node node = root.Insert(img);
  220.             if (node == null)
  221.             {
  222.                 return false;
  223.             }
  224.             rectangleMap.Add(name, node.rect);
  225.             image.SetPixels((int)node.rect.x, (int)node.rect.y, (int)node.rect.width, (int)node.rect.height, img.GetPixels());
  226.             image.Apply();
  227.             return true;
  228.         }
  229.  
  230.         public void Write(string name)
  231.         {
  232.             TextWriter tw = new StreamWriter(Path.ChangeExtension(name, ".txt"));
  233.             foreach (KeyValuePair<string, Rect> e in rectangleMap)
  234.             {
  235.                 Rect r = e.Value;
  236.                 tw.WriteLine(e.Key + "," + r.x + "," + r.y + "," + r.width + "," + r.height);
  237.             }
  238.             tw.Close();
  239.             byte[] bytes = image.EncodeToPNG();
  240.  
  241.             FileStream f = new FileStream(name, FileMode.Create, FileAccess.Write);
  242.             BinaryWriter b = new BinaryWriter(f);
  243.             for (int i = 0; i < bytes.Length; i++) b.Write(bytes[i]);
  244.             b.Close();
  245.         }
  246.     }
  247. }
  248.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement