Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEditor;
- using UnityEditor.Experimental.AssetImporters;
- using UnityEditorInternal;
- using System.IO;
- using SimpleJSON;
- [CustomEditor(typeof(AsepriteImporter))]
- public class AsepriteImporterEditor : Editor {
- bool modified = false;
- SerializedObject copy;
- bool listFoldout;
- bool animationFoldout;
- ReorderableList groupList;
- private void OnEnable() {
- CreateCopy();
- groupList = new ReorderableList(serializedObject, serializedObject.FindProperty("layerGroups"), true, true, true, true);
- groupList.drawElementCallback += DrawLayerGroup;
- groupList.drawHeaderCallback += (Rect rect) => {
- EditorGUI.LabelField(new Rect(rect.x, rect.y, 100, rect.height), "Name");
- EditorGUI.LabelField(new Rect(rect.x + 130, rect.y, 50, rect.height), "Frames");
- EditorGUI.LabelField(new Rect(rect.x + 190, rect.y, 60, rect.height), "Tags");
- EditorGUI.LabelField(new Rect(rect.x + 240, rect.y, 50, rect.height), "Slices");
- };
- groupList.elementHeightCallback += (int index) => {
- return EditorGUIUtility.singleLineHeight * ((target as AsepriteImporter).layerNames.Count + 2.5f);
- };
- }
- private void OnDisable() {
- if (modified) Apply();
- }
- private void DrawLayerGroup(Rect rect, int index, bool isActive, bool isFocused) {
- AsepriteImporter importer = target as AsepriteImporter;
- Rect cur = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight);
- EditorGUI.PropertyField(new Rect(cur.x, cur.y, 120, cur.height),
- groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("name"), GUIContent.none);
- EditorGUI.PropertyField(new Rect(cur.x + 135, cur.y, cur.height, cur.height),
- groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("separateFrames"), GUIContent.none);
- EditorGUI.PropertyField(new Rect(cur.x + 185, cur.y, cur.height, cur.height),
- groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("separateAnimations"), GUIContent.none);
- EditorGUI.PropertyField(new Rect(cur.x + 235, cur.y, cur.height, cur.height),
- groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("separateSlices"), GUIContent.none);
- cur.y += EditorGUIUtility.singleLineHeight;
- EditorGUI.LabelField(cur, importer.layerGroups[index].sprites.Length + " sprites");
- cur.x += 10;
- cur.width -= 10;
- for (int i = 0; i < importer.layerNames.Count; i++) {
- cur.y += EditorGUIUtility.singleLineHeight;
- int t = importer.layerGroups[index].layers.FindIndex(f => f == importer.layerNames[i]);
- bool v = EditorGUI.ToggleLeft(cur, importer.layerNames[i], t != -1);
- if (v && t == -1) {
- SerializedProperty layerlist = groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("layers");
- int insertIndex = layerlist.arraySize;
- layerlist.InsertArrayElementAtIndex(insertIndex);
- layerlist.GetArrayElementAtIndex(insertIndex).stringValue = importer.layerNames[i];
- } else if (!v && t != -1) {
- groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("layers").DeleteArrayElementAtIndex(t);
- }
- }
- }
- public override void OnInspectorGUI() {
- serializedObject.Update();
- AsepriteImporter importer = target as AsepriteImporter;
- if (importer.layerGroups.Count == 0)
- importer.layerGroups.Add(new AsepriteImporter.LayerGroup());
- EditorGUI.BeginChangeCheck();
- EditorGUILayout.PropertyField(serializedObject.FindProperty("pivot"));
- EditorGUILayout.PropertyField(serializedObject.FindProperty("pixelsPerUnit"));
- EditorGUILayout.PropertyField(serializedObject.FindProperty("extrude"));
- EditorGUILayout.Space();
- listFoldout = EditorGUILayout.Foldout(listFoldout, "Layer Groups");
- if (listFoldout) groupList.DoLayoutList();
- animationFoldout = EditorGUILayout.Foldout(animationFoldout, "Animations");
- if (animationFoldout) {
- Rect rect = EditorGUILayout.GetControlRect();
- EditorGUI.LabelField(new Rect(rect.x, rect.y, 100, rect.height), "Name", EditorStyles.boldLabel);
- EditorGUI.LabelField(new Rect(rect.x + 125, rect.y, 50, rect.height), "Loop", EditorStyles.boldLabel);
- EditorGUI.LabelField(new Rect(rect.x + 165, rect.y, 60, rect.height), "Events", EditorStyles.boldLabel);
- for (int i = 0; i < importer.animations.Length; i++) {
- EditorGUILayout.BeginHorizontal();
- EditorGUILayout.PrefixLabel(importer.animations[i].name);
- serializedObject.FindProperty("animations").GetArrayElementAtIndex(i).FindPropertyRelative("loop").boolValue = EditorGUILayout.Toggle(importer.animations[i].loop);
- EditorGUILayout.LabelField(importer.animations[i].events.Length.ToString());
- EditorGUILayout.EndHorizontal();
- }
- }
- if (EditorGUI.EndChangeCheck()) {
- serializedObject.ApplyModifiedProperties();
- modified = true;
- }
- EditorGUILayout.Space();
- EditorGUI.BeginDisabledGroup(!modified);
- Rect r = EditorGUILayout.GetControlRect();
- float h = EditorStyles.miniButton.CalcHeight(new GUIContent("RevertApply"), 110);
- r.y += (r.height - h) / 2;
- r.height = h;
- if (GUI.Button(new Rect(r.xMax - 130, r.y, 60, r.height), "Revert", EditorStyles.miniButton)) Revert();
- if (GUI.Button(new Rect(r.xMax - 65, r.y, 60, r.height), "Apply", EditorStyles.miniButton)) Apply();
- EditorGUI.EndDisabledGroup();
- }
- void CreateCopy() {
- copy = new SerializedObject(target as AsepriteImporter);
- SerializedProperty prop = serializedObject.GetIterator();
- while (prop.NextVisible(true))
- copy.CopyFromSerializedProperty(prop);
- }
- void Revert() {
- SerializedProperty prop = copy.GetIterator();
- while (prop.NextVisible(true))
- serializedObject.CopyFromSerializedProperty(prop);
- serializedObject.ApplyModifiedPropertiesWithoutUndo();
- modified = false;
- }
- void Apply() {
- Undo.RecordObject(target as AsepriteImporter, "Reimport");
- AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target), ImportAssetOptions.ForceUpdate);
- modified = false;
- CreateCopy();
- }
- }
- [ScriptedImporter(1, new string[] { "aseprite", "ase" })]
- public class AsepriteImporter : ScriptedImporter {
- private SpriteMeshType spriteMeshType = SpriteMeshType.Tight;
- public Texture2D createdTexture;
- public Vector2 pivot = new Vector2(.5f, .5f);
- public float pixelsPerUnit = 4;
- public uint extrude = 0;
- public List<LayerGroup> layerGroups = new List<LayerGroup>() { new LayerGroup() };
- public List<string> layerNames = new List<string>();
- public AnimationData[] animations = new AnimationData[0];
- [System.Serializable]
- public class LayerGroup {
- public string name = "Default";
- public bool separateAnimations = true;
- public bool separateFrames = true;
- public bool separateSlices = true;
- public List<string> layers = new List<string>();
- public Sprite[] sprites = new Sprite[0];
- }
- [System.Serializable]
- public class AnimationData {
- public string name = "null";
- public bool loop = false;
- public AnimationEvent[] events = new AnimationEvent[0];
- }
- private class Frame {
- public Rect frame = new Rect(0, 0, 1, 1);
- public bool rotated = false;
- public bool trimmed = false;
- public Rect spriteSourceSize = new Rect(0, 0, 1, 1);
- public Vector2 sourceSize = new Vector2(1, 1);
- public int duration = 100;
- public Sprite sprite;
- public Dictionary<Slice, Sprite> sliceSprites = new Dictionary<Slice, Sprite>();
- }
- private class FrameTag {
- public string name;
- public bool reverse;
- public int start;
- public int end;
- }
- private class Slice {
- public Rect bounds = new Rect(0, 0, 1, 1);
- public Vector2 pivot = new Vector2();
- public string name;
- }
- private class Layer {
- public string name;
- public float opacity;
- }
- private class AseData {
- public int width;
- public int height;
- public List<Frame> frames = new List<Frame>();
- public List<FrameTag> tags = new List<FrameTag>();
- public List<Slice> slices = new List<Slice>();
- public List<Layer> layers = new List<Layer>();
- }
- private AseData GetData(string assetPath, string exePath) {
- string tmpData = Path.GetTempFileName();
- string tmpDataJson = Path.ChangeExtension(tmpData, "json");
- File.Move(tmpData, tmpDataJson);
- // Create json
- string args = "-b " + assetPath + " --data " + tmpDataJson + " --list-tags --list-slices --list-layers";
- System.Diagnostics.Process p = new System.Diagnostics.Process();
- p.StartInfo.FileName = exePath;
- p.StartInfo.Arguments = args;
- p.Start();
- p.WaitForExit();
- JSONNode root = JSON.Parse(File.ReadAllText(tmpDataJson));
- File.Delete(tmpDataJson);
- AseData data = new AseData();
- data.width = root["meta"]["size"]["w"].AsInt;
- data.height = root["meta"]["size"]["h"].AsInt;
- // Frames
- JSONNode.Enumerator enumerator = root["frames"].GetEnumerator();
- while (enumerator.MoveNext()) {
- Frame frame = new Frame();
- frame.frame.x = enumerator.Current.Value["frame"]["x"].AsInt;
- frame.frame.y = enumerator.Current.Value["frame"]["y"].AsInt;
- frame.frame.width = enumerator.Current.Value["frame"]["w"].AsInt;
- frame.frame.height = enumerator.Current.Value["frame"]["h"].AsInt;
- frame.rotated = enumerator.Current.Value["rotated"].AsBool;
- frame.trimmed = enumerator.Current.Value["trimmed"].AsBool;
- frame.spriteSourceSize.x = enumerator.Current.Value["spriteSourceSize"]["x"].AsInt;
- frame.spriteSourceSize.y = enumerator.Current.Value["spriteSourceSize"]["y"].AsInt;
- frame.spriteSourceSize.width = enumerator.Current.Value["spriteSourceSize"]["w"].AsInt;
- frame.spriteSourceSize.height = enumerator.Current.Value["spriteSourceSize"]["h"].AsInt;
- frame.sourceSize.x = enumerator.Current.Value["sourceSize"]["w"].AsInt;
- frame.sourceSize.y = enumerator.Current.Value["sourceSize"]["h"].AsInt;
- frame.duration = enumerator.Current.Value["duration"];
- frame.frame.y = data.height - frame.frame.height - frame.frame.y;
- data.frames.Add(frame);
- }
- // Frame Tags
- enumerator = root["meta"]["frameTags"].GetEnumerator();
- while (enumerator.MoveNext()) {
- FrameTag tag = new FrameTag();
- tag.name = enumerator.Current.Value["name"].Value;
- tag.reverse = enumerator.Current.Value["direction"].Value != "forward";
- tag.start = enumerator.Current.Value["from"].AsInt;
- tag.end = enumerator.Current.Value["to"].AsInt;
- data.tags.Add(tag);
- }
- // Slices
- enumerator = root["meta"]["slices"].GetEnumerator();
- while (enumerator.MoveNext()) {
- Slice slice = new Slice();
- slice.bounds = new Rect(0, 0, 0, 0);
- slice.pivot = this.pivot;
- IEnumerator<JSONNode> k = enumerator.Current.Value["keys"].Children.GetEnumerator();
- while (k.MoveNext()) {
- slice.bounds.x = k.Current["bounds"]["x"].AsInt;
- slice.bounds.y = k.Current["bounds"]["y"].AsInt;
- slice.bounds.width = k.Current["bounds"]["w"].AsInt;
- slice.bounds.height = k.Current["bounds"]["h"].AsInt;
- if (k.Current["pivot"] != null)
- pivot = new Vector2(k.Current["pivot"]["x"] / slice.bounds.width, k.Current["pivot"]["y"] / slice.bounds.height);
- break;
- }
- slice.bounds.y = data.height - slice.bounds.height - slice.bounds.y;
- slice.name = enumerator.Current.Value["name"].Value;
- data.slices.Add(slice);
- }
- // Layers
- layerNames.Clear();
- enumerator = root["meta"]["layers"].GetEnumerator();
- while (enumerator.MoveNext()) {
- Layer layer = new Layer();
- layer.name = enumerator.Current.Value["name"].Value;
- layer.opacity = enumerator.Current.Value["opacity"].AsInt / 255f;
- layerNames.Add(layer.name);
- data.layers.Add(layer);
- }
- return data;
- }
- private Texture2D CreateTexture(int groupIndex, AssetImportContext ctx, AseData data, string exePath) {
- string layers = "";
- foreach (string l in layerGroups[groupIndex].layers)
- layers += " --layer \"" + l + "\"";
- string tmpSheet = Path.GetTempFileName();
- string tmpSheetPng = Path.ChangeExtension(tmpSheet, "png");
- File.Move(tmpSheet, tmpSheetPng);
- // Create sprite sheet
- string args = "-b" + layers + " " + ctx.assetPath + " --sheet " + tmpSheetPng;
- System.Diagnostics.Process p = new System.Diagnostics.Process();
- p.StartInfo.FileName = exePath;
- p.StartInfo.Arguments = args;
- p.Start();
- p.WaitForExit();
- string name = Path.GetFileNameWithoutExtension(ctx.assetPath);
- if (layerGroups.Count > 1)
- name += layerGroups[groupIndex].name;
- // Copy sprite texture to the sheet
- Texture2D texture = new Texture2D(data.width, data.height, TextureFormat.ARGB32, false);
- texture.LoadImage(File.ReadAllBytes(tmpSheetPng));
- texture.wrapMode = TextureWrapMode.Clamp;
- texture.filterMode = FilterMode.Point;
- texture.alphaIsTransparency = true;
- texture.anisoLevel = 0;
- File.Delete(tmpSheetPng);
- return texture;
- }
- private AnimationClip CreateAnimationClip(string name, FrameTag tag) {
- AnimationClip a = new AnimationClip();
- a.name = name + "_" + tag.name;
- // pull animation data from previous animation
- AnimationData anim = null;
- for (int j = 0; j < animations.Length; j++)
- if (animations[j] != null && animations[j].name == a.name) {
- anim = animations[j];
- break;
- }
- // create animation settings
- AnimationClipSettings settings;
- if (anim != null) {
- settings = new AnimationClipSettings() {
- loopTime = anim.loop
- };
- AnimationUtility.SetAnimationEvents(a, anim.events);
- } else {
- settings = new AnimationClipSettings() {
- loopTime = false
- };
- ArrayUtility.Add(ref animations, new AnimationData() { name = a.name });
- }
- AnimationUtility.SetAnimationClipSettings(a, settings);
- a.legacy = false;
- a.frameRate = 10;
- return a;
- }
- private void CreateAssets(int groupIndex, Texture2D texture, Rect packRect, AssetImportContext ctx, AseData data) {
- string name = texture.name;
- if (layerGroups[groupIndex].name != "Default")
- name += "_" + layerGroups[groupIndex].name;
- List<Sprite> sprites = new List<Sprite>();
- if (data.frames.Count > 1) {
- int c = 0;
- foreach (Frame frame in data.frames) {
- // Create sprites for each slice, per frame
- if (data.slices.Count > 0 && layerGroups[groupIndex].separateSlices) {
- foreach (Slice s in data.slices) {
- Rect fr = s.bounds;
- fr.x += packRect.x;
- fr.y += packRect.y;
- Sprite sprite = Sprite.Create(texture, fr, pivot, pixelsPerUnit, extrude, spriteMeshType);
- sprite.name = name + "_" + s.name + "_" + c;
- ctx.AddObjectToAsset(sprite.name, sprite);
- frame.sliceSprites.Add(s, sprite);
- sprites.Add(sprite);
- }
- }
- // Create sprites for each whole frame
- if (layerGroups[groupIndex].separateFrames) {
- Rect fr = frame.frame;
- fr.x += packRect.x;
- fr.y += packRect.y;
- frame.sprite = Sprite.Create(texture, fr, pivot, pixelsPerUnit, extrude, spriteMeshType);
- frame.sprite.name = name + "_" + c;
- ctx.AddObjectToAsset(frame.sprite.name, frame.sprite);
- sprites.Add(frame.sprite);
- c++;
- }
- }
- // Create animations
- if (layerGroups[groupIndex].separateAnimations) {
- foreach (FrameTag tag in data.tags) {
- if (data.slices.Count > 0 && layerGroups[groupIndex].separateSlices) {
- foreach (Slice s in data.slices) {
- AnimationClip a = CreateAnimationClip(name + "_" + s.name, tag);
- // Create keyframes
- int frameCount = tag.end - tag.start + 1;
- ObjectReferenceKeyframe[] keyframes = new ObjectReferenceKeyframe[frameCount];
- float t = 0;
- int i = tag.reverse ? tag.end : tag.start;
- for (int k = 0; k < frameCount; k++) {
- keyframes[k] = new ObjectReferenceKeyframe() {
- time = t,
- value = data.frames[i].sliceSprites[s]
- };
- t += data.frames[i].duration / 1000f;
- if (tag.reverse) i--; else i++;
- }
- EditorCurveBinding curve = new EditorCurveBinding() {
- path = "",
- propertyName = "m_Sprite",
- type = typeof(SpriteRenderer)
- };
- AnimationUtility.SetObjectReferenceCurve(a, curve, keyframes);
- ctx.AddObjectToAsset(a.name, a);
- }
- }
- if (layerGroups[groupIndex].separateFrames) {
- AnimationClip a = CreateAnimationClip(name, tag);
- // Create keyframes
- int frameCount = tag.end - tag.start + 1;
- ObjectReferenceKeyframe[] keyframes = new ObjectReferenceKeyframe[frameCount];
- float t = 0;
- int i = tag.reverse ? tag.end : tag.start;
- for (int k = 0; k < frameCount; k++) {
- keyframes[k] = new ObjectReferenceKeyframe() {
- time = t,
- value = data.frames[i].sprite
- };
- t += data.frames[i].duration / 1000f;
- if (tag.reverse) i--; else i++;
- }
- EditorCurveBinding curve = new EditorCurveBinding() {
- path = "",
- propertyName = "m_Sprite",
- type = typeof(SpriteRenderer)
- };
- AnimationUtility.SetObjectReferenceCurve(a, curve, keyframes);
- ctx.AddObjectToAsset(a.name, a);
- }
- }
- }
- } else if (layerGroups[groupIndex].separateSlices) {
- foreach (Slice slice in data.slices) {
- Rect b = slice.bounds;
- b.x += packRect.x;
- b.y += packRect.y;
- Sprite sprite = Sprite.Create(texture, b, slice.pivot, pixelsPerUnit, extrude, spriteMeshType);
- sprite.name = name + "_" + slice.name;
- sprites.Add(sprite);
- ctx.AddObjectToAsset(sprite.name, sprite);
- }
- }
- layerGroups[groupIndex].sprites = sprites.ToArray();
- }
- public override void OnImportAsset(AssetImportContext ctx) {
- string exePath = System.Environment.GetEnvironmentVariable("AsepritePath") + @"\Aseprite.exe";
- if (!File.Exists(exePath)) {
- ctx.LogImportError("Aseprite not found! Make sure to set 'AsepritePath' environment variable.");
- return;
- }
- // Generate data about the spritesheet
- AseData data = GetData(ctx.assetPath, exePath);
- List<Texture2D> textures = new List<Texture2D>();
- // Generate textures from each layerGroup
- for (int i = 0; i < layerGroups.Count; i++)
- textures.Add(CreateTexture(i, ctx, data, exePath));
- // Pack the textures together
- string name = Path.GetFileNameWithoutExtension(ctx.assetPath);
- Texture2D sheet = new Texture2D(8192, 8192, TextureFormat.ARGB32, false);
- sheet.name = name;
- Rect[] pack = sheet.PackTextures(textures.ToArray(), 1, 8192);
- sheet.wrapMode = TextureWrapMode.Clamp;
- sheet.filterMode = FilterMode.Point;
- sheet.alphaIsTransparency = true;
- sheet.anisoLevel = 0;
- // Create sprites from the packed texture
- for (int i = 0; i < layerGroups.Count; i++) {
- CreateAssets(i, sheet,
- new Rect(pack[i].x * sheet.width, pack[i].y * sheet.height, pack[i].width * sheet.width, pack[i].height * sheet.height),
- ctx, data);
- }
- ctx.AddObjectToAsset(name, sheet);
- ctx.SetMainObject(sheet);
- createdTexture = sheet;
- }
- }
Add Comment
Please, Sign In to add comment