730 lines
28 KiB
C#
730 lines
28 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
public class ImageAtlasser : EditorWindow
|
|
{
|
|
#region Variables & Properties
|
|
|
|
// Editor Window Variables
|
|
private static Vector2 pos = new Vector2(100, 100);
|
|
private Rect windowRectangle = new Rect(210, 0, 0, 0);
|
|
private Vector2 scrollPosition1 = Vector2.zero;
|
|
private Vector2 scrollPosition2 = Vector2.zero;
|
|
private bool atlasPreview = false;
|
|
private string atlasWindowName = "Atlas";
|
|
private GUIContent calcContent = new GUIContent("Atlas");
|
|
|
|
// Atlas Settings Variables
|
|
private bool autoArrange = true;
|
|
private Vector2 atlasSize = Vector2.one;
|
|
new private int maxSize = 256;
|
|
private string[] maxSizeKeys =
|
|
{
|
|
"32",
|
|
"64",
|
|
"128",
|
|
"256",
|
|
"512",
|
|
"1024",
|
|
"2048",
|
|
"4096"
|
|
};
|
|
private int[] maxSizeValues =
|
|
{
|
|
32,
|
|
64,
|
|
128,
|
|
256,
|
|
512,
|
|
1024,
|
|
2048,
|
|
4096
|
|
};
|
|
private int packMethod = 0;
|
|
private string[] packMethodKeys =
|
|
{
|
|
"---",
|
|
"1",
|
|
"2",
|
|
"3 (Rotational)",
|
|
"4 (Rotational)",
|
|
"5 (Rotational)",
|
|
"6 (Rotational)",
|
|
"7 (Rotational)",
|
|
};
|
|
private int[] packMethodValues =
|
|
{
|
|
0,
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7
|
|
};
|
|
private int spacing = 1;
|
|
|
|
// Import Variables
|
|
private Texture2D atlasImage;
|
|
private TextAsset importCodings;
|
|
private Object importDirectory;
|
|
private string importDirectoryStr = string.Empty;
|
|
private bool subDirectories = true;
|
|
private bool replaceImages = true;
|
|
private bool readFromText = true;
|
|
|
|
// Export Variables
|
|
private string exportPath = string.Empty;
|
|
|
|
// Atlas Drawer Variables
|
|
private Texture2D[] systemImages;
|
|
private Color atlasBackgroundCol = Color.white;
|
|
private string imageNameFilter = string.Empty;
|
|
private bool isMasked = false;
|
|
|
|
// Atlas Variables
|
|
private List<ImageAtlasBase> parts = new List<ImageAtlasBase>();
|
|
|
|
#endregion
|
|
|
|
[MenuItem("RO_Tool/Image Atlasser")]
|
|
static void Init()
|
|
{
|
|
ImageAtlasser window = EditorWindow.GetWindow<ImageAtlasser>("Image Atlasser");
|
|
window.position = new Rect(pos.x, pos.y, 1024, 600);
|
|
window.Show();
|
|
}
|
|
|
|
void OnEnable()
|
|
{
|
|
systemImages = new Texture2D[]
|
|
{
|
|
AssetDatabase.LoadAssetAtPath("Assets/Image Atlasser/Editor/icons/bg.jpg", typeof(Texture2D)) as Texture2D,
|
|
AssetDatabase.LoadAssetAtPath("Assets/Image Atlasser/Editor/icons/mask.jpg", typeof(Texture2D)) as Texture2D
|
|
};
|
|
|
|
if (Selection.objects.Length > 0)
|
|
{
|
|
importDirectory = Selection.objects[0];
|
|
string assetPath = AssetDatabase.GetAssetPath(importDirectory);
|
|
importDirectoryStr = Directory.Exists(assetPath) ? assetPath : assetPath.Remove(assetPath.LastIndexOf('/') + 1, assetPath.Length - assetPath.LastIndexOf('/') - 1);
|
|
}
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
parts.Dispose();
|
|
pos = new Vector2(position.x, position.y);
|
|
}
|
|
|
|
void OnGUI()
|
|
{
|
|
GUILayout.BeginVertical(GUILayout.Width(200));
|
|
|
|
GUI.skin.label.fontSize = 15;
|
|
GUI.skin.label.fontStyle = FontStyle.Bold;
|
|
GUIX.LabelCentered("Import Settings", 200);
|
|
GUI.skin.label.fontStyle = FontStyle.Normal;
|
|
GUI.skin.label.fontSize = 11;
|
|
|
|
ImportSettings();
|
|
|
|
GUILayout.Space(5);
|
|
GUIX.Line();
|
|
GUILayout.Space(5);
|
|
|
|
GUI.skin.label.fontSize = 15;
|
|
GUI.skin.label.fontStyle = FontStyle.Bold;
|
|
GUIX.LabelCentered("Pack Settings", 200);
|
|
GUI.skin.label.fontStyle = FontStyle.Normal;
|
|
GUI.skin.label.fontSize = 11;
|
|
|
|
PackSettings();
|
|
|
|
GUILayout.Space(5);
|
|
GUIX.Line();
|
|
GUILayout.Space(5);
|
|
|
|
GUI.skin.label.fontSize = 15;
|
|
GUI.skin.label.fontStyle = FontStyle.Bold;
|
|
GUIX.LabelCentered("Extract Buttons", 200);
|
|
GUI.skin.label.fontStyle = FontStyle.Normal;
|
|
GUI.skin.label.fontSize = 11;
|
|
|
|
ExportButtons();
|
|
|
|
GUILayout.EndVertical();
|
|
|
|
windowRectangle.width = position.width - windowRectangle.x;
|
|
windowRectangle.height = position.height;
|
|
|
|
BeginWindows();
|
|
if (atlasPreview)
|
|
GUI.Window(0, windowRectangle, DrawAtlas, string.Empty);
|
|
else
|
|
GUI.Window(0, windowRectangle, DrawParts, string.Empty);
|
|
EndWindows();
|
|
|
|
Vector2 elementPosition = new Vector2(windowRectangle.x + 2, 0);
|
|
|
|
atlasWindowName = "Atlas [" +
|
|
atlasSize.x + "x" +
|
|
atlasSize.y + "]";
|
|
|
|
//atlasWindowName = "Atlas [" +
|
|
// atlasSize.x + "x" +
|
|
// atlasSize.y + "] - [" +
|
|
// string.Format("{0:0.000}", (atlasSize.x + atlasSize.y) * 0.5f) +
|
|
// "]";
|
|
|
|
GUI.skin.label.fontStyle = FontStyle.Bold;
|
|
if (atlasPreview)
|
|
{
|
|
calcContent.text = atlasWindowName;
|
|
float strWidth = GUI.skin.label.CalcSize(calcContent).x;
|
|
GUI.Label(new Rect(elementPosition.x, elementPosition.y, strWidth, 16), atlasWindowName);
|
|
elementPosition.x += strWidth + 10;
|
|
}
|
|
else
|
|
{
|
|
GUI.Label(new Rect(elementPosition.x, elementPosition.y, 48, 16), "Parts");
|
|
elementPosition.x += 48;
|
|
}
|
|
GUI.skin.label.fontStyle = FontStyle.Normal;
|
|
|
|
GUI.Label(new Rect(elementPosition.x, elementPosition.y, 98, 16), "| [Atlas preview ");
|
|
elementPosition.x += 98;
|
|
atlasPreview = GUI.Toggle(new Rect(elementPosition.x, elementPosition.y, 23, 16), atlasPreview, "]");
|
|
|
|
elementPosition.x += 25;
|
|
GUI.Label(new Rect(elementPosition.x, elementPosition.y, 55, 16), "[Masked ");
|
|
elementPosition.x += 55;
|
|
isMasked = GUI.Toggle(new Rect(elementPosition.x, elementPosition.y, 23, 16), isMasked, "]");
|
|
|
|
elementPosition.x += 25;
|
|
GUI.Label(new Rect(elementPosition.x, elementPosition.y, 200, 16), "[Toggle Rotate All ");
|
|
elementPosition.x += 110;
|
|
if (GUI.Button(new Rect(elementPosition.x, elementPosition.y, 60, 16), "Change") && parts.Count > 0)
|
|
{
|
|
bool rotated = parts[0].attr.canBeRotated;
|
|
for (int i = 0; i < parts.Count; i++)
|
|
parts[i].attr.canBeRotated = !rotated;
|
|
}
|
|
elementPosition.x += 60;
|
|
GUI.Label(new Rect(elementPosition.x, elementPosition.y, 10, 16), "]");
|
|
|
|
elementPosition.x = position.width - 210;
|
|
GUI.Label(new Rect(elementPosition.x, elementPosition.y, 115, 16), "Search Image Part");
|
|
imageNameFilter = GUI.TextField(new Rect(elementPosition.x + 117, elementPosition.y, 90, 15), imageNameFilter);
|
|
}
|
|
|
|
#region Import Settings
|
|
|
|
private void ImportSettings()
|
|
{
|
|
// [max width: 200]
|
|
// label field: 200
|
|
// texture field: 200
|
|
// toggle: 182 + 16
|
|
// button: 200
|
|
|
|
GUILayout.Label("Import directory", GUILayout.Width(200));
|
|
EditorGUI.indentLevel = 1;
|
|
importDirectory = EditorGUILayout.ObjectField(importDirectory, typeof(Object), false, GUILayout.Width(200));
|
|
EditorGUI.indentLevel = 0;
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Search sub-directories", GUILayout.Width(182));
|
|
subDirectories = EditorGUILayout.Toggle(subDirectories, GUILayout.Width(16));
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Replace imported parts", GUILayout.Width(182));
|
|
replaceImages = EditorGUILayout.Toggle(replaceImages, GUILayout.Width(16));
|
|
GUILayout.EndHorizontal();
|
|
|
|
if (GUILayout.Button("Import Parts", GUILayout.Width(200), GUILayout.Height(25)) && importDirectory)
|
|
{
|
|
string assetPath = AssetDatabase.GetAssetPath(importDirectory);
|
|
importDirectoryStr = Directory.Exists(assetPath) ? assetPath : assetPath.Remove(assetPath.LastIndexOf('/') + 1, assetPath.Length - assetPath.LastIndexOf('/') - 1);
|
|
if (ImportParts(importDirectoryStr))
|
|
Pack();
|
|
}
|
|
|
|
GUILayout.Space(5);
|
|
GUIX.LineDotted();
|
|
GUILayout.Space(5);
|
|
|
|
GUILayout.Label("Atlas Image", GUILayout.Width(200));
|
|
EditorGUI.indentLevel = 1;
|
|
atlasImage = EditorGUILayout.ObjectField((Texture2D)atlasImage, typeof(Texture2D), false, GUILayout.Width(200)) as Texture2D;
|
|
EditorGUI.indentLevel = 0;
|
|
|
|
GUILayout.Label("Atlas Codings", GUILayout.Width(200));
|
|
EditorGUI.indentLevel = 1;
|
|
importCodings = EditorGUILayout.ObjectField((TextAsset)importCodings, typeof(TextAsset), false, GUILayout.Width(200)) as TextAsset;
|
|
EditorGUI.indentLevel = 0;
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Read from Text", GUILayout.Width(182));
|
|
readFromText = EditorGUILayout.Toggle(readFromText, GUILayout.Width(16));
|
|
GUILayout.EndHorizontal();
|
|
|
|
if (GUILayout.Button("Import Atlas to Default", GUILayout.Width(200), GUILayout.Height(25)))
|
|
ImportAtlas();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Pack Settings
|
|
|
|
private void PackSettings()
|
|
{
|
|
// [max width: 200]
|
|
// label field: 200
|
|
// enam field: 200
|
|
// toggle: 182 + 16
|
|
// button: 200
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Auto Arrange", GUILayout.Width(182));
|
|
autoArrange = EditorGUILayout.Toggle(autoArrange, GUILayout.Width(16));
|
|
GUILayout.EndHorizontal();
|
|
|
|
if (autoArrange)
|
|
GUI.enabled = false;
|
|
EditorGUI.indentLevel = 1;
|
|
|
|
GUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField("Pack Method", GUILayout.Width(105));
|
|
int prevPackMethod = packMethod;
|
|
packMethod = EditorGUILayout.IntPopup(packMethod, packMethodKeys, packMethodValues, GUILayout.Width(95));
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField("Size", GUILayout.Width(105));
|
|
int prevMaxSize = maxSize;
|
|
maxSize = EditorGUILayout.IntPopup(maxSize, maxSizeKeys, maxSizeValues, GUILayout.Width(95));
|
|
GUILayout.EndHorizontal();
|
|
|
|
EditorGUI.indentLevel = 0;
|
|
GUI.enabled = true;
|
|
|
|
if (prevPackMethod != packMethod && packMethod > 0 && parts.Count > 0)
|
|
Pack();
|
|
|
|
if (prevMaxSize != maxSize && parts.Count > 0)
|
|
Pack();
|
|
|
|
if (GUILayout.Button("Pack", GUILayout.Height(25)) && parts.Count > 0)
|
|
Pack();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Export Buttons
|
|
|
|
private void ExportButtons()
|
|
{
|
|
if (GUILayout.Button("Export Atlas", GUILayout.Width(200), GUILayout.Height(25)) && parts.Count > 0)
|
|
{
|
|
exportPath = EditorUtility.SaveFilePanel("Export Atlas to...", Application.dataPath + "/", "Atlas image", string.Empty);
|
|
if (!string.IsNullOrEmpty(exportPath))
|
|
ExportAtlas();
|
|
}
|
|
|
|
if (GUILayout.Button("Export Parts", GUILayout.Width(200), GUILayout.Height(25)) && parts.Count > 0)
|
|
{
|
|
string exportPathFolder = EditorUtility.SaveFolderPanel("Export Parts to...", Application.dataPath, "Atlas parts");
|
|
if (!string.IsNullOrEmpty(exportPathFolder))
|
|
{
|
|
for (int i = 0; i < parts.Count; i++)
|
|
File.WriteAllBytes(exportPathFolder + "/" + parts[i].attr.name + ".png", parts[i].image.EncodeToPNG());
|
|
AssetDatabase.Refresh();
|
|
Debug.Log("OK(!): Image parts have been successfully exported to " + exportPathFolder);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Draw Parts
|
|
|
|
private void DrawParts(int winID)
|
|
{
|
|
int horizontalCount = (int)(windowRectangle.width / 105f);
|
|
|
|
int activeElementCount = 0;
|
|
for (int i = 0; i < parts.Count; i++)
|
|
if (string.IsNullOrEmpty(imageNameFilter) || parts[i].attr.name.Contains(imageNameFilter))
|
|
activeElementCount++;
|
|
if (horizontalCount == 0)
|
|
return;
|
|
int windowGridHeight = activeElementCount / horizontalCount;
|
|
if ((float)windowGridHeight >= (float)activeElementCount / (float)horizontalCount)
|
|
windowGridHeight--;
|
|
|
|
scrollPosition2 = GUI.BeginScrollView(
|
|
new Rect(0, 18, windowRectangle.width - 9, windowRectangle.height - 22),
|
|
scrollPosition2, new Rect(0, 0, 0, windowGridHeight * 125 + 125));
|
|
|
|
GUI.skin.label.fontStyle = FontStyle.Bold;
|
|
for (int i = 0, activeIndex = 1, xIndex = 0, yIndex = 0; i < parts.Count; i++)
|
|
if (string.IsNullOrEmpty(imageNameFilter) || parts[i].attr.name.Contains(imageNameFilter))
|
|
{
|
|
if (horizontalCount == 0)
|
|
horizontalCount = 1;
|
|
xIndex = activeIndex % horizontalCount;
|
|
if (xIndex == 0)
|
|
xIndex = horizontalCount;
|
|
xIndex--;
|
|
|
|
yIndex = activeIndex / horizontalCount;
|
|
if ((float)yIndex >= (float)activeIndex / (float)horizontalCount)
|
|
yIndex--;
|
|
|
|
GUILayout.BeginArea(new Rect(5 + 100 * xIndex, 125 * yIndex, 100, 120));
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.Label(": " + parts[i].attr.name + " :");
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.FlexibleSpace();
|
|
Rect partRect = GUILayoutUtility.GetRect(95, 50);
|
|
GUI.DrawTexture(partRect, parts[i].image);
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.BeginVertical();
|
|
GUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField("Rotate?", GUILayout.Width(78), GUILayout.Height(14));
|
|
parts[i].attr.canBeRotated = EditorGUILayout.Toggle(parts[i].attr.canBeRotated);
|
|
GUILayout.EndHorizontal();
|
|
GUI.color = Color.red;
|
|
if (GUILayout.Button("Remove", GUILayout.Height(25)))
|
|
{
|
|
ImageAtlasBase image = parts[i];
|
|
parts.RemoveAt(i);
|
|
image.Dispose();
|
|
}
|
|
GUI.color = Color.white;
|
|
GUILayout.EndVertical();
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.EndArea();
|
|
|
|
activeIndex++;
|
|
}
|
|
GUI.skin.label.fontStyle = FontStyle.Normal;
|
|
|
|
GUI.EndScrollView(true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Draw Atlas
|
|
|
|
public void DrawAtlas(int winID)
|
|
{
|
|
if (parts.Count == 0)
|
|
return;
|
|
|
|
scrollPosition1 = GUILayout.BeginScrollView(scrollPosition1, GUILayout.Width(windowRectangle.width - 12), GUILayout.Height(windowRectangle.height - 28));
|
|
|
|
GUILayout.Box("", GUILayout.Width(atlasSize.x - 0.5f), GUILayout.Height(atlasSize.y - 0.5f));
|
|
|
|
GUI.color = atlasBackgroundCol;
|
|
GUI.DrawTexture(new Rect(5, 5, atlasSize.x - 0.5f, atlasSize.y - 0.5f),
|
|
systemImages[0]);
|
|
GUI.color = Color.white;
|
|
|
|
for (int i = 0; i < parts.Count; i++)
|
|
if (string.IsNullOrEmpty(imageNameFilter) || parts[i].attr.name.Contains(imageNameFilter))
|
|
GUI.DrawTexture(
|
|
new Rect(
|
|
parts[i].attr.position.x + 5,
|
|
parts[i].attr.position.y + 5,
|
|
parts[i].attr.position.width,
|
|
parts[i].attr.position.height),
|
|
!isMasked ? parts[i].image : systemImages[1]);
|
|
|
|
GUILayout.EndScrollView();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Import Export Pack Methods
|
|
|
|
private bool ImportParts(string path)
|
|
{
|
|
DirectoryInfo importDirectory = new DirectoryInfo(path);
|
|
|
|
List<FileInfo> fileInfos = GetImageFilesFromDirectory(importDirectory);
|
|
if (replaceImages)
|
|
parts.Dispose();
|
|
|
|
for (int i = 0; i < fileInfos.Count; i++)
|
|
{
|
|
string fullName = fileInfos[i].FullName.Replace('\\', '/');
|
|
string pathDirectory = fullName.Remove(0, fullName.IndexOf("Assets/"));
|
|
Texture2D image = (Texture2D)AssetDatabase.LoadAssetAtPath(pathDirectory, typeof(Texture2D));
|
|
if ((AssetImporter.GetAtPath(pathDirectory) as TextureImporter).isReadable)
|
|
{
|
|
ImageAttributes attr = new ImageAttributes(fileInfos[i].Name.Remove(fileInfos[i].Name.IndexOf('.')), new Rect(), false);
|
|
parts.Add(new ImageAtlasBase(image, attr, false));
|
|
}
|
|
}
|
|
|
|
if (parts.Count > 0)
|
|
Debug.Log("OK(!): Imported [" + parts.Count + "] parts out of [" + fileInfos.Count + "]");
|
|
else
|
|
{
|
|
Debug.LogWarning("Warning: No parts have been imported");
|
|
if (fileInfos.Count > 0)
|
|
Debug.Log("Tip: Images must have \"Read/Write Enabled\" flag in order to be imported!");
|
|
}
|
|
|
|
return parts.Count > 0;
|
|
}
|
|
|
|
private void ImportAtlas()
|
|
{
|
|
TextureImporter importer;
|
|
|
|
if (atlasImage == null)
|
|
{
|
|
Debug.LogError("Error(!): Atlas image is not yet assigned.");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(atlasImage)) as TextureImporter;
|
|
|
|
if (!importer.isReadable)
|
|
{
|
|
Debug.LogError("Error(!): Atlas image must have \"Read/Write Enabled\" flag in order to be imported!");
|
|
return;
|
|
}
|
|
|
|
if (readFromText && importCodings == null)
|
|
{
|
|
Debug.LogError("Error(!): \"Read from text\" is enabled but no codings file is yet assigned.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (replaceImages)
|
|
parts.Dispose();
|
|
parts.AddRange(ImageAtlas.GetParts(atlasImage, importCodings, importer, readFromText));
|
|
maxSize = atlasImage.width > atlasImage.height ? atlasImage.width : atlasImage.height;
|
|
atlasSize = new Vector2(atlasImage.width, atlasImage.height);
|
|
|
|
if (parts.Count > 0)
|
|
Debug.Log("OK(!): Image parts have been successfully imported!");
|
|
else
|
|
Debug.LogWarning("Warning(!): Something must have gone wrong. No image parts have been imported.");
|
|
}
|
|
|
|
|
|
int GetPotValue(float size)
|
|
{
|
|
int value = 1;
|
|
while(value < size)
|
|
{
|
|
value *= 2;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private void ExportAtlas()
|
|
{
|
|
if (atlasSize == Vector2.zero || atlasSize == Vector2.one)
|
|
{
|
|
Debug.LogError("Error(!): Atlas creation failed.");
|
|
return;
|
|
}
|
|
atlasSize.Set(GetPotValue(atlasSize.x), GetPotValue((int)atlasSize.y));
|
|
Texture2D atlas = new Texture2D((int)(atlasSize.x), ((int)atlasSize.y), TextureFormat.RGBA32, false);
|
|
string codings = string.Empty;
|
|
|
|
Color clear = Color.clear;
|
|
for (int y = 0; y < atlasSize.y; y++)
|
|
for (int x = 0; x < atlasSize.x; x++)
|
|
atlas.SetPixel(x, y, clear);
|
|
atlas.Apply();
|
|
|
|
for (int i = 0; i < parts.Count; i++)
|
|
{
|
|
Rect position = new Rect(
|
|
parts[i].attr.position.x,
|
|
parts[i].attr.position.y,
|
|
parts[i].attr.position.width,
|
|
parts[i].attr.position.height);
|
|
|
|
atlas.SetPixels(
|
|
(int)position.x,
|
|
(int)(atlasSize.y - (position.y + parts[i].image.height)),
|
|
(int)parts[i].image.width,
|
|
(int)parts[i].image.height,
|
|
parts[i].image.GetPixels()
|
|
);
|
|
|
|
codings += ImageAtlas.EncodeLine(parts[i].attr);
|
|
|
|
if (i + 1 < parts.Count)
|
|
codings += '\n';
|
|
}
|
|
atlas.Apply();
|
|
|
|
if (codings[codings.Length - 1] == '\n')
|
|
codings = codings.Remove(codings.Length - 1);
|
|
|
|
if (exportPath.Contains(".png"))
|
|
exportPath = exportPath.Replace(".png", "");
|
|
|
|
File.WriteAllBytes(exportPath + ".png", atlas.EncodeToPNG());
|
|
File.WriteAllText(exportPath + ".txt", codings);
|
|
AssetDatabase.Refresh();
|
|
|
|
AtlasInfo atlasInfo = new AtlasInfo();
|
|
atlasInfo.texture = (Texture2D)AssetDatabase.LoadAssetAtPath(exportPath.Remove(0, exportPath.IndexOf("Assets/")) + ".png", typeof(Texture));
|
|
atlasInfo.uvDetails = new AtlasInfo.UVDetail[parts.Count];
|
|
SpriteMetaData[] spriteData = new SpriteMetaData[parts.Count];
|
|
for (int i = 0; i < spriteData.Length; i++)
|
|
{
|
|
spriteData[i] = new SpriteMetaData();
|
|
spriteData[i].name = parts[i].attr.name;
|
|
spriteData[i].alignment = 0;
|
|
spriteData[i].rect = new Rect(
|
|
parts[i].attr.position.x,
|
|
atlas.height - parts[i].attr.position.y - parts[i].attr.position.height,
|
|
parts[i].attr.position.width,
|
|
parts[i].attr.position.height
|
|
);
|
|
atlasInfo.uvDetails[i] = new AtlasInfo.UVDetail();
|
|
atlasInfo.uvDetails[i].Name = parts[i].attr.name;
|
|
atlasInfo.uvDetails[i].rotate = parts[i].attr.isRotated;
|
|
if(atlasInfo.uvDetails[i].rotate)
|
|
{
|
|
atlasInfo.uvDetails[i].uvTL = new Vector2((parts[i].attr.position.x + parts[i].attr.position.width) / atlas.width, (atlas.height - parts[i].attr.position.y) / atlas.height);
|
|
atlasInfo.uvDetails[i].uvTR = new Vector2((parts[i].attr.position.x + parts[i].attr.position.width) / atlas.width, (atlas.height - parts[i].attr.position.y - parts[i].attr.position.height) / atlas.height);
|
|
atlasInfo.uvDetails[i].uvBL = new Vector2(parts[i].attr.position.x / atlas.width, (atlas.height - parts[i].attr.position.y) / atlas.height);
|
|
atlasInfo.uvDetails[i].uvBR = new Vector2(parts[i].attr.position.x / atlas.width, (atlas.height - parts[i].attr.position.y - parts[i].attr.position.height) / atlas.height);
|
|
atlasInfo.uvDetails[i].height = parts[i].image.width;
|
|
atlasInfo.uvDetails[i].width = parts[i].image.height;
|
|
}
|
|
else
|
|
{
|
|
atlasInfo.uvDetails[i].uvTL = new Vector2(parts[i].attr.position.x / atlas.width, (atlas.height - parts[i].attr.position.y) / atlas.height);
|
|
atlasInfo.uvDetails[i].uvTR = new Vector2((parts[i].attr.position.x + parts[i].attr.position .width)/ atlas.width, (atlas.height - parts[i].attr.position.y) / atlas.height);
|
|
atlasInfo.uvDetails[i].uvBL = new Vector2(parts[i].attr.position.x / atlas.width, (atlas.height - parts[i].attr.position.y - parts[i].attr.position.height) / atlas.height);
|
|
atlasInfo.uvDetails[i].uvBR = new Vector2((parts[i].attr.position.x + parts[i].attr.position.width) / atlas.width, (atlas.height - parts[i].attr.position.y - parts[i].attr.position.height) / atlas.height);
|
|
atlasInfo.uvDetails[i].width = parts[i].image.width;
|
|
atlasInfo.uvDetails[i].height = parts[i].image.height;
|
|
}
|
|
}
|
|
|
|
string localAtlasPath = exportPath.Remove(0, exportPath.IndexOf("Assets/")) + ".png";
|
|
TextureImporter importer = AssetImporter.GetAtPath(localAtlasPath) as TextureImporter;
|
|
importer.textureType = TextureImporterType.Sprite;
|
|
importer.npotScale = TextureImporterNPOTScale.None;
|
|
importer.spriteImportMode = SpriteImportMode.Multiple;
|
|
importer.spritePackingTag = string.Empty;
|
|
importer.spritePixelsToUnits = 100;
|
|
importer.spritesheet = spriteData;
|
|
importer.filterMode = FilterMode.Bilinear;
|
|
importer.maxTextureSize = maxSize;
|
|
importer.textureFormat = TextureImporterFormat.AutomaticTruecolor;
|
|
|
|
AssetDatabase.ImportAsset(localAtlasPath);
|
|
DestroyImmediate(atlas);
|
|
|
|
string atlasInfoPath = exportPath.Remove(0, exportPath.IndexOf("Assets/")) + ".asset";
|
|
AssetDatabase.CreateAsset(atlasInfo, atlasInfoPath);
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
Debug.Log("OK(!): Atlas image have been successfully exported to " + localAtlasPath);
|
|
}
|
|
|
|
private List<FileInfo> GetImageFilesFromDirectory(DirectoryInfo importDirectory)
|
|
{
|
|
string[] files = Directory.GetFiles(importDirectory.FullName, "*.*", (subDirectories) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
|
|
.Where(s => s.ToLower().EndsWith(".png") || s.ToLower().EndsWith(".tga") || s.ToLower().EndsWith(".jpg") ||
|
|
s.ToLower().EndsWith(".psd") || s.ToLower().EndsWith(".dds")).ToArray();
|
|
List<FileInfo> fileList = new List<FileInfo>();
|
|
foreach (string p in files)
|
|
fileList.Add(new FileInfo(p));
|
|
|
|
ImageAtlas.AlphanumComparatorFast comparison = new ImageAtlas.AlphanumComparatorFast();
|
|
fileList.Sort(comparison);
|
|
|
|
return new List<FileInfo>(fileList);
|
|
}
|
|
|
|
private void Pack()
|
|
{
|
|
if (autoArrange)
|
|
ImageAtlas.PackParts(ref parts, out packMethod, out maxSize, spacing, out atlasSize);
|
|
else
|
|
ImageAtlas.PackParts(ref parts, packMethod, maxSize, spacing, out atlasSize);
|
|
Debug.Log("Last Action: Pack");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GUILayout Overloads
|
|
|
|
private static class GUIX
|
|
{
|
|
public static void LabelCentered(string label, int width)
|
|
{
|
|
EditorGUILayout.BeginHorizontal(GUILayout.Width(width));
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.Label(label);
|
|
GUILayout.FlexibleSpace();
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
|
|
public static void Line()
|
|
{
|
|
EditorGUILayout.BeginHorizontal();
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.Box("", GUILayout.Height(3), GUILayout.Width(100));
|
|
GUILayout.FlexibleSpace();
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
|
|
public static void LineDotted()
|
|
{
|
|
EditorGUILayout.BeginHorizontal();
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.Box("", GUILayout.Height(3), GUILayout.Width(15));
|
|
GUILayout.Space(5);
|
|
GUILayout.Box("", GUILayout.Height(3), GUILayout.Width(15));
|
|
GUILayout.Space(5);
|
|
GUILayout.Box("", GUILayout.Height(3), GUILayout.Width(15));
|
|
GUILayout.Space(5);
|
|
GUILayout.Box("", GUILayout.Height(3), GUILayout.Width(15));
|
|
GUILayout.Space(5);
|
|
GUILayout.Box("", GUILayout.Height(3), GUILayout.Width(15));
|
|
GUILayout.Space(5);
|
|
GUILayout.Box("", GUILayout.Height(3), GUILayout.Width(15));
|
|
GUILayout.FlexibleSpace();
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
} |