Guest User

Untitled

a guest
Aug 14th, 2018
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.96 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEditor;
  4. using UnityEditor.Experimental.AssetImporters;
  5. using UnityEditorInternal;
  6. using System.IO;
  7. using SimpleJSON;
  8.  
  9. [CustomEditor(typeof(AsepriteImporter))]
  10. public class AsepriteImporterEditor : Editor {
  11. bool modified = false;
  12. SerializedObject copy;
  13.  
  14. bool listFoldout;
  15. bool animationFoldout;
  16. ReorderableList groupList;
  17.  
  18. private void OnEnable() {
  19. CreateCopy();
  20. groupList = new ReorderableList(serializedObject, serializedObject.FindProperty("layerGroups"), true, true, true, true);
  21. groupList.drawElementCallback += DrawLayerGroup;
  22. groupList.drawHeaderCallback += (Rect rect) => {
  23. EditorGUI.LabelField(new Rect(rect.x, rect.y, 100, rect.height), "Name");
  24. EditorGUI.LabelField(new Rect(rect.x + 130, rect.y, 50, rect.height), "Frames");
  25. EditorGUI.LabelField(new Rect(rect.x + 190, rect.y, 60, rect.height), "Tags");
  26. EditorGUI.LabelField(new Rect(rect.x + 240, rect.y, 50, rect.height), "Slices");
  27. };
  28. groupList.elementHeightCallback += (int index) => {
  29. return EditorGUIUtility.singleLineHeight * ((target as AsepriteImporter).layerNames.Count + 2.5f);
  30. };
  31. }
  32. private void OnDisable() {
  33. if (modified) Apply();
  34. }
  35.  
  36. private void DrawLayerGroup(Rect rect, int index, bool isActive, bool isFocused) {
  37. AsepriteImporter importer = target as AsepriteImporter;
  38. Rect cur = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight);
  39.  
  40. EditorGUI.PropertyField(new Rect(cur.x, cur.y, 120, cur.height),
  41. groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("name"), GUIContent.none);
  42.  
  43. EditorGUI.PropertyField(new Rect(cur.x + 135, cur.y, cur.height, cur.height),
  44. groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("separateFrames"), GUIContent.none);
  45. EditorGUI.PropertyField(new Rect(cur.x + 185, cur.y, cur.height, cur.height),
  46. groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("separateAnimations"), GUIContent.none);
  47. EditorGUI.PropertyField(new Rect(cur.x + 235, cur.y, cur.height, cur.height),
  48. groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("separateSlices"), GUIContent.none);
  49.  
  50. cur.y += EditorGUIUtility.singleLineHeight;
  51.  
  52. EditorGUI.LabelField(cur, importer.layerGroups[index].sprites.Length + " sprites");
  53.  
  54. cur.x += 10;
  55. cur.width -= 10;
  56. for (int i = 0; i < importer.layerNames.Count; i++) {
  57. cur.y += EditorGUIUtility.singleLineHeight;
  58.  
  59. int t = importer.layerGroups[index].layers.FindIndex(f => f == importer.layerNames[i]);
  60. bool v = EditorGUI.ToggleLeft(cur, importer.layerNames[i], t != -1);
  61. if (v && t == -1) {
  62. SerializedProperty layerlist = groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("layers");
  63. int insertIndex = layerlist.arraySize;
  64. layerlist.InsertArrayElementAtIndex(insertIndex);
  65. layerlist.GetArrayElementAtIndex(insertIndex).stringValue = importer.layerNames[i];
  66. } else if (!v && t != -1) {
  67. groupList.serializedProperty.GetArrayElementAtIndex(index).FindPropertyRelative("layers").DeleteArrayElementAtIndex(t);
  68. }
  69. }
  70. }
  71.  
  72. public override void OnInspectorGUI() {
  73. serializedObject.Update();
  74.  
  75. AsepriteImporter importer = target as AsepriteImporter;
  76. if (importer.layerGroups.Count == 0)
  77. importer.layerGroups.Add(new AsepriteImporter.LayerGroup());
  78.  
  79. EditorGUI.BeginChangeCheck();
  80.  
  81. EditorGUILayout.PropertyField(serializedObject.FindProperty("pivot"));
  82. EditorGUILayout.PropertyField(serializedObject.FindProperty("pixelsPerUnit"));
  83. EditorGUILayout.PropertyField(serializedObject.FindProperty("extrude"));
  84.  
  85. EditorGUILayout.Space();
  86.  
  87. listFoldout = EditorGUILayout.Foldout(listFoldout, "Layer Groups");
  88. if (listFoldout) groupList.DoLayoutList();
  89.  
  90. animationFoldout = EditorGUILayout.Foldout(animationFoldout, "Animations");
  91. if (animationFoldout) {
  92. Rect rect = EditorGUILayout.GetControlRect();
  93. EditorGUI.LabelField(new Rect(rect.x, rect.y, 100, rect.height), "Name", EditorStyles.boldLabel);
  94. EditorGUI.LabelField(new Rect(rect.x + 125, rect.y, 50, rect.height), "Loop", EditorStyles.boldLabel);
  95. EditorGUI.LabelField(new Rect(rect.x + 165, rect.y, 60, rect.height), "Events", EditorStyles.boldLabel);
  96. for (int i = 0; i < importer.animations.Length; i++) {
  97. EditorGUILayout.BeginHorizontal();
  98. EditorGUILayout.PrefixLabel(importer.animations[i].name);
  99. serializedObject.FindProperty("animations").GetArrayElementAtIndex(i).FindPropertyRelative("loop").boolValue = EditorGUILayout.Toggle(importer.animations[i].loop);
  100. EditorGUILayout.LabelField(importer.animations[i].events.Length.ToString());
  101. EditorGUILayout.EndHorizontal();
  102. }
  103. }
  104.  
  105. if (EditorGUI.EndChangeCheck()) {
  106. serializedObject.ApplyModifiedProperties();
  107. modified = true;
  108. }
  109.  
  110. EditorGUILayout.Space();
  111.  
  112. EditorGUI.BeginDisabledGroup(!modified);
  113.  
  114. Rect r = EditorGUILayout.GetControlRect();
  115. float h = EditorStyles.miniButton.CalcHeight(new GUIContent("RevertApply"), 110);
  116. r.y += (r.height - h) / 2;
  117. r.height = h;
  118. if (GUI.Button(new Rect(r.xMax - 130, r.y, 60, r.height), "Revert", EditorStyles.miniButton)) Revert();
  119. if (GUI.Button(new Rect(r.xMax - 65, r.y, 60, r.height), "Apply", EditorStyles.miniButton)) Apply();
  120. EditorGUI.EndDisabledGroup();
  121. }
  122.  
  123. void CreateCopy() {
  124. copy = new SerializedObject(target as AsepriteImporter);
  125. SerializedProperty prop = serializedObject.GetIterator();
  126. while (prop.NextVisible(true))
  127. copy.CopyFromSerializedProperty(prop);
  128. }
  129. void Revert() {
  130. SerializedProperty prop = copy.GetIterator();
  131. while (prop.NextVisible(true))
  132. serializedObject.CopyFromSerializedProperty(prop);
  133. serializedObject.ApplyModifiedPropertiesWithoutUndo();
  134. modified = false;
  135. }
  136. void Apply() {
  137. Undo.RecordObject(target as AsepriteImporter, "Reimport");
  138. AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target), ImportAssetOptions.ForceUpdate);
  139. modified = false;
  140. CreateCopy();
  141. }
  142. }
  143.  
  144. [ScriptedImporter(1, new string[] { "aseprite", "ase" })]
  145. public class AsepriteImporter : ScriptedImporter {
  146. private SpriteMeshType spriteMeshType = SpriteMeshType.Tight;
  147.  
  148. public Texture2D createdTexture;
  149.  
  150. public Vector2 pivot = new Vector2(.5f, .5f);
  151. public float pixelsPerUnit = 4;
  152. public uint extrude = 0;
  153.  
  154. public List<LayerGroup> layerGroups = new List<LayerGroup>() { new LayerGroup() };
  155. public List<string> layerNames = new List<string>();
  156. public AnimationData[] animations = new AnimationData[0];
  157.  
  158. [System.Serializable]
  159. public class LayerGroup {
  160. public string name = "Default";
  161. public bool separateAnimations = true;
  162. public bool separateFrames = true;
  163. public bool separateSlices = true;
  164. public List<string> layers = new List<string>();
  165.  
  166. public Sprite[] sprites = new Sprite[0];
  167. }
  168.  
  169. [System.Serializable]
  170. public class AnimationData {
  171. public string name = "null";
  172. public bool loop = false;
  173. public AnimationEvent[] events = new AnimationEvent[0];
  174. }
  175.  
  176. private class Frame {
  177. public Rect frame = new Rect(0, 0, 1, 1);
  178. public bool rotated = false;
  179. public bool trimmed = false;
  180. public Rect spriteSourceSize = new Rect(0, 0, 1, 1);
  181. public Vector2 sourceSize = new Vector2(1, 1);
  182. public int duration = 100;
  183. public Sprite sprite;
  184. public Dictionary<Slice, Sprite> sliceSprites = new Dictionary<Slice, Sprite>();
  185. }
  186. private class FrameTag {
  187. public string name;
  188. public bool reverse;
  189. public int start;
  190. public int end;
  191. }
  192. private class Slice {
  193. public Rect bounds = new Rect(0, 0, 1, 1);
  194. public Vector2 pivot = new Vector2();
  195. public string name;
  196. }
  197. private class Layer {
  198. public string name;
  199. public float opacity;
  200. }
  201.  
  202. private class AseData {
  203. public int width;
  204. public int height;
  205. public List<Frame> frames = new List<Frame>();
  206. public List<FrameTag> tags = new List<FrameTag>();
  207. public List<Slice> slices = new List<Slice>();
  208. public List<Layer> layers = new List<Layer>();
  209. }
  210.  
  211. private AseData GetData(string assetPath, string exePath) {
  212. string tmpData = Path.GetTempFileName();
  213. string tmpDataJson = Path.ChangeExtension(tmpData, "json");
  214. File.Move(tmpData, tmpDataJson);
  215.  
  216. // Create json
  217. string args = "-b " + assetPath + " --data " + tmpDataJson + " --list-tags --list-slices --list-layers";
  218. System.Diagnostics.Process p = new System.Diagnostics.Process();
  219. p.StartInfo.FileName = exePath;
  220. p.StartInfo.Arguments = args;
  221. p.Start();
  222. p.WaitForExit();
  223.  
  224. JSONNode root = JSON.Parse(File.ReadAllText(tmpDataJson));
  225.  
  226. File.Delete(tmpDataJson);
  227.  
  228. AseData data = new AseData();
  229. data.width = root["meta"]["size"]["w"].AsInt;
  230. data.height = root["meta"]["size"]["h"].AsInt;
  231.  
  232. // Frames
  233. JSONNode.Enumerator enumerator = root["frames"].GetEnumerator();
  234. while (enumerator.MoveNext()) {
  235. Frame frame = new Frame();
  236. frame.frame.x = enumerator.Current.Value["frame"]["x"].AsInt;
  237. frame.frame.y = enumerator.Current.Value["frame"]["y"].AsInt;
  238. frame.frame.width = enumerator.Current.Value["frame"]["w"].AsInt;
  239. frame.frame.height = enumerator.Current.Value["frame"]["h"].AsInt;
  240.  
  241. frame.rotated = enumerator.Current.Value["rotated"].AsBool;
  242. frame.trimmed = enumerator.Current.Value["trimmed"].AsBool;
  243.  
  244. frame.spriteSourceSize.x = enumerator.Current.Value["spriteSourceSize"]["x"].AsInt;
  245. frame.spriteSourceSize.y = enumerator.Current.Value["spriteSourceSize"]["y"].AsInt;
  246. frame.spriteSourceSize.width = enumerator.Current.Value["spriteSourceSize"]["w"].AsInt;
  247. frame.spriteSourceSize.height = enumerator.Current.Value["spriteSourceSize"]["h"].AsInt;
  248.  
  249. frame.sourceSize.x = enumerator.Current.Value["sourceSize"]["w"].AsInt;
  250. frame.sourceSize.y = enumerator.Current.Value["sourceSize"]["h"].AsInt;
  251.  
  252. frame.duration = enumerator.Current.Value["duration"];
  253.  
  254. frame.frame.y = data.height - frame.frame.height - frame.frame.y;
  255. data.frames.Add(frame);
  256. }
  257.  
  258. // Frame Tags
  259. enumerator = root["meta"]["frameTags"].GetEnumerator();
  260. while (enumerator.MoveNext()) {
  261. FrameTag tag = new FrameTag();
  262. tag.name = enumerator.Current.Value["name"].Value;
  263. tag.reverse = enumerator.Current.Value["direction"].Value != "forward";
  264. tag.start = enumerator.Current.Value["from"].AsInt;
  265. tag.end = enumerator.Current.Value["to"].AsInt;
  266. data.tags.Add(tag);
  267. }
  268.  
  269. // Slices
  270. enumerator = root["meta"]["slices"].GetEnumerator();
  271. while (enumerator.MoveNext()) {
  272. Slice slice = new Slice();
  273. slice.bounds = new Rect(0, 0, 0, 0);
  274. slice.pivot = this.pivot;
  275. IEnumerator<JSONNode> k = enumerator.Current.Value["keys"].Children.GetEnumerator();
  276. while (k.MoveNext()) {
  277. slice.bounds.x = k.Current["bounds"]["x"].AsInt;
  278. slice.bounds.y = k.Current["bounds"]["y"].AsInt;
  279. slice.bounds.width = k.Current["bounds"]["w"].AsInt;
  280. slice.bounds.height = k.Current["bounds"]["h"].AsInt;
  281. if (k.Current["pivot"] != null)
  282. pivot = new Vector2(k.Current["pivot"]["x"] / slice.bounds.width, k.Current["pivot"]["y"] / slice.bounds.height);
  283. break;
  284. }
  285.  
  286. slice.bounds.y = data.height - slice.bounds.height - slice.bounds.y;
  287. slice.name = enumerator.Current.Value["name"].Value;
  288. data.slices.Add(slice);
  289. }
  290.  
  291. // Layers
  292. layerNames.Clear();
  293. enumerator = root["meta"]["layers"].GetEnumerator();
  294. while (enumerator.MoveNext()) {
  295. Layer layer = new Layer();
  296. layer.name = enumerator.Current.Value["name"].Value;
  297. layer.opacity = enumerator.Current.Value["opacity"].AsInt / 255f;
  298. layerNames.Add(layer.name);
  299. data.layers.Add(layer);
  300. }
  301.  
  302. return data;
  303. }
  304.  
  305. private Texture2D CreateTexture(int groupIndex, AssetImportContext ctx, AseData data, string exePath) {
  306. string layers = "";
  307. foreach (string l in layerGroups[groupIndex].layers)
  308. layers += " --layer \"" + l + "\"";
  309.  
  310. string tmpSheet = Path.GetTempFileName();
  311. string tmpSheetPng = Path.ChangeExtension(tmpSheet, "png");
  312. File.Move(tmpSheet, tmpSheetPng);
  313.  
  314. // Create sprite sheet
  315. string args = "-b" + layers + " " + ctx.assetPath + " --sheet " + tmpSheetPng;
  316. System.Diagnostics.Process p = new System.Diagnostics.Process();
  317. p.StartInfo.FileName = exePath;
  318. p.StartInfo.Arguments = args;
  319. p.Start();
  320. p.WaitForExit();
  321.  
  322. string name = Path.GetFileNameWithoutExtension(ctx.assetPath);
  323.  
  324. if (layerGroups.Count > 1)
  325. name += layerGroups[groupIndex].name;
  326.  
  327. // Copy sprite texture to the sheet
  328. Texture2D texture = new Texture2D(data.width, data.height, TextureFormat.ARGB32, false);
  329. texture.LoadImage(File.ReadAllBytes(tmpSheetPng));
  330. texture.wrapMode = TextureWrapMode.Clamp;
  331. texture.filterMode = FilterMode.Point;
  332. texture.alphaIsTransparency = true;
  333. texture.anisoLevel = 0;
  334.  
  335. File.Delete(tmpSheetPng);
  336.  
  337. return texture;
  338. }
  339.  
  340. private AnimationClip CreateAnimationClip(string name, FrameTag tag) {
  341. AnimationClip a = new AnimationClip();
  342. a.name = name + "_" + tag.name;
  343.  
  344. // pull animation data from previous animation
  345. AnimationData anim = null;
  346. for (int j = 0; j < animations.Length; j++)
  347. if (animations[j] != null && animations[j].name == a.name) {
  348. anim = animations[j];
  349. break;
  350. }
  351.  
  352. // create animation settings
  353. AnimationClipSettings settings;
  354. if (anim != null) {
  355. settings = new AnimationClipSettings() {
  356. loopTime = anim.loop
  357. };
  358. AnimationUtility.SetAnimationEvents(a, anim.events);
  359. } else {
  360. settings = new AnimationClipSettings() {
  361. loopTime = false
  362. };
  363. ArrayUtility.Add(ref animations, new AnimationData() { name = a.name });
  364. }
  365. AnimationUtility.SetAnimationClipSettings(a, settings);
  366. a.legacy = false;
  367. a.frameRate = 10;
  368. return a;
  369. }
  370.  
  371. private void CreateAssets(int groupIndex, Texture2D texture, Rect packRect, AssetImportContext ctx, AseData data) {
  372. string name = texture.name;
  373. if (layerGroups[groupIndex].name != "Default")
  374. name += "_" + layerGroups[groupIndex].name;
  375.  
  376. List<Sprite> sprites = new List<Sprite>();
  377.  
  378. if (data.frames.Count > 1) {
  379. int c = 0;
  380. foreach (Frame frame in data.frames) {
  381. // Create sprites for each slice, per frame
  382. if (data.slices.Count > 0 && layerGroups[groupIndex].separateSlices) {
  383. foreach (Slice s in data.slices) {
  384. Rect fr = s.bounds;
  385. fr.x += packRect.x;
  386. fr.y += packRect.y;
  387. Sprite sprite = Sprite.Create(texture, fr, pivot, pixelsPerUnit, extrude, spriteMeshType);
  388. sprite.name = name + "_" + s.name + "_" + c;
  389. ctx.AddObjectToAsset(sprite.name, sprite);
  390. frame.sliceSprites.Add(s, sprite);
  391. sprites.Add(sprite);
  392. }
  393. }
  394.  
  395. // Create sprites for each whole frame
  396. if (layerGroups[groupIndex].separateFrames) {
  397. Rect fr = frame.frame;
  398. fr.x += packRect.x;
  399. fr.y += packRect.y;
  400. frame.sprite = Sprite.Create(texture, fr, pivot, pixelsPerUnit, extrude, spriteMeshType);
  401. frame.sprite.name = name + "_" + c;
  402. ctx.AddObjectToAsset(frame.sprite.name, frame.sprite);
  403. sprites.Add(frame.sprite);
  404. c++;
  405. }
  406. }
  407.  
  408. // Create animations
  409. if (layerGroups[groupIndex].separateAnimations) {
  410. foreach (FrameTag tag in data.tags) {
  411. if (data.slices.Count > 0 && layerGroups[groupIndex].separateSlices) {
  412. foreach (Slice s in data.slices) {
  413. AnimationClip a = CreateAnimationClip(name + "_" + s.name, tag);
  414.  
  415. // Create keyframes
  416. int frameCount = tag.end - tag.start + 1;
  417. ObjectReferenceKeyframe[] keyframes = new ObjectReferenceKeyframe[frameCount];
  418.  
  419. float t = 0;
  420. int i = tag.reverse ? tag.end : tag.start;
  421. for (int k = 0; k < frameCount; k++) {
  422. keyframes[k] = new ObjectReferenceKeyframe() {
  423. time = t,
  424. value = data.frames[i].sliceSprites[s]
  425. };
  426. t += data.frames[i].duration / 1000f;
  427. if (tag.reverse) i--; else i++;
  428. }
  429.  
  430. EditorCurveBinding curve = new EditorCurveBinding() {
  431. path = "",
  432. propertyName = "m_Sprite",
  433. type = typeof(SpriteRenderer)
  434. };
  435. AnimationUtility.SetObjectReferenceCurve(a, curve, keyframes);
  436.  
  437. ctx.AddObjectToAsset(a.name, a);
  438. }
  439. }
  440. if (layerGroups[groupIndex].separateFrames) {
  441. AnimationClip a = CreateAnimationClip(name, tag);
  442.  
  443. // Create keyframes
  444. int frameCount = tag.end - tag.start + 1;
  445. ObjectReferenceKeyframe[] keyframes = new ObjectReferenceKeyframe[frameCount];
  446.  
  447. float t = 0;
  448. int i = tag.reverse ? tag.end : tag.start;
  449. for (int k = 0; k < frameCount; k++) {
  450. keyframes[k] = new ObjectReferenceKeyframe() {
  451. time = t,
  452. value = data.frames[i].sprite
  453. };
  454. t += data.frames[i].duration / 1000f;
  455. if (tag.reverse) i--; else i++;
  456. }
  457.  
  458. EditorCurveBinding curve = new EditorCurveBinding() {
  459. path = "",
  460. propertyName = "m_Sprite",
  461. type = typeof(SpriteRenderer)
  462. };
  463. AnimationUtility.SetObjectReferenceCurve(a, curve, keyframes);
  464.  
  465. ctx.AddObjectToAsset(a.name, a);
  466. }
  467. }
  468. }
  469. } else if (layerGroups[groupIndex].separateSlices) {
  470. foreach (Slice slice in data.slices) {
  471. Rect b = slice.bounds;
  472. b.x += packRect.x;
  473. b.y += packRect.y;
  474. Sprite sprite = Sprite.Create(texture, b, slice.pivot, pixelsPerUnit, extrude, spriteMeshType);
  475. sprite.name = name + "_" + slice.name;
  476. sprites.Add(sprite);
  477. ctx.AddObjectToAsset(sprite.name, sprite);
  478. }
  479. }
  480.  
  481. layerGroups[groupIndex].sprites = sprites.ToArray();
  482. }
  483.  
  484. public override void OnImportAsset(AssetImportContext ctx) {
  485. string exePath = System.Environment.GetEnvironmentVariable("AsepritePath") + @"\Aseprite.exe";
  486. if (!File.Exists(exePath)) {
  487. ctx.LogImportError("Aseprite not found! Make sure to set 'AsepritePath' environment variable.");
  488. return;
  489. }
  490.  
  491. // Generate data about the spritesheet
  492. AseData data = GetData(ctx.assetPath, exePath);
  493.  
  494. List<Texture2D> textures = new List<Texture2D>();
  495.  
  496. // Generate textures from each layerGroup
  497. for (int i = 0; i < layerGroups.Count; i++)
  498. textures.Add(CreateTexture(i, ctx, data, exePath));
  499.  
  500. // Pack the textures together
  501. string name = Path.GetFileNameWithoutExtension(ctx.assetPath);
  502. Texture2D sheet = new Texture2D(8192, 8192, TextureFormat.ARGB32, false);
  503. sheet.name = name;
  504. Rect[] pack = sheet.PackTextures(textures.ToArray(), 1, 8192);
  505. sheet.wrapMode = TextureWrapMode.Clamp;
  506. sheet.filterMode = FilterMode.Point;
  507. sheet.alphaIsTransparency = true;
  508. sheet.anisoLevel = 0;
  509.  
  510. // Create sprites from the packed texture
  511. for (int i = 0; i < layerGroups.Count; i++) {
  512. CreateAssets(i, sheet,
  513. new Rect(pack[i].x * sheet.width, pack[i].y * sheet.height, pack[i].width * sheet.width, pack[i].height * sheet.height),
  514. ctx, data);
  515. }
  516.  
  517. ctx.AddObjectToAsset(name, sheet);
  518. ctx.SetMainObject(sheet);
  519. createdTexture = sheet;
  520. }
  521. }
Add Comment
Please, Sign In to add comment