Nessuna descrizione
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AsepriteImporter.cs 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Unity.Collections;
  5. using UnityEngine;
  6. using UnityEditor.AssetImporters;
  7. using UnityEditor.U2D.Aseprite.Common;
  8. using UnityEditor.U2D.Sprites;
  9. using UnityEngine.Serialization;
  10. namespace UnityEditor.U2D.Aseprite
  11. {
  12. /// <summary>
  13. /// ScriptedImporter to import Aseprite files
  14. /// </summary>
  15. // Version using unity release + 5 digit padding for future upgrade. Eg 2021.2 -> 21200000
  16. [ScriptedImporter(21300003, new string[] { "aseprite", "ase" }, AllowCaching = true)]
  17. [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.aseprite@latest")]
  18. public partial class AsepriteImporter : ScriptedImporter, ISpriteEditorDataProvider
  19. {
  20. [SerializeField]
  21. TextureImporterSettings m_TextureImporterSettings = new TextureImporterSettings()
  22. {
  23. mipmapEnabled = false,
  24. mipmapFilter = TextureImporterMipFilter.BoxFilter,
  25. sRGBTexture = true,
  26. borderMipmap = false,
  27. mipMapsPreserveCoverage = false,
  28. alphaTestReferenceValue = 0.5f,
  29. readable = false,
  30. #if ENABLE_TEXTURE_STREAMING
  31. streamingMipmaps = false,
  32. streamingMipmapsPriority = 0,
  33. #endif
  34. fadeOut = false,
  35. mipmapFadeDistanceStart = 1,
  36. mipmapFadeDistanceEnd = 3,
  37. convertToNormalMap = false,
  38. heightmapScale = 0.25F,
  39. normalMapFilter = 0,
  40. generateCubemap = TextureImporterGenerateCubemap.AutoCubemap,
  41. cubemapConvolution = 0,
  42. seamlessCubemap = false,
  43. npotScale = TextureImporterNPOTScale.ToNearest,
  44. spriteMode = (int)SpriteImportMode.Multiple,
  45. spriteExtrude = 1,
  46. spriteMeshType = SpriteMeshType.Tight,
  47. spriteAlignment = (int)SpriteAlignment.Center,
  48. spritePivot = new Vector2(0.5f, 0.5f),
  49. spritePixelsPerUnit = 100.0f,
  50. spriteBorder = new Vector4(0.0f, 0.0f, 0.0f, 0.0f),
  51. alphaSource = TextureImporterAlphaSource.FromInput,
  52. alphaIsTransparency = true,
  53. spriteTessellationDetail = -1.0f,
  54. textureType = TextureImporterType.Sprite,
  55. textureShape = TextureImporterShape.Texture2D,
  56. filterMode = FilterMode.Point,
  57. aniso = 1,
  58. mipmapBias = 0.0f,
  59. wrapModeU = TextureWrapMode.Clamp,
  60. wrapModeV = TextureWrapMode.Clamp,
  61. wrapModeW = TextureWrapMode.Clamp
  62. };
  63. [SerializeField] AsepriteImporterSettings m_PreviousAsepriteImporterSettings;
  64. [SerializeField]
  65. AsepriteImporterSettings m_AsepriteImporterSettings = new AsepriteImporterSettings()
  66. {
  67. fileImportMode = FileImportModes.AnimatedSprite,
  68. importHiddenLayers = false,
  69. layerImportMode = LayerImportModes.MergeFrame,
  70. defaultPivotAlignment = SpriteAlignment.BottomCenter,
  71. defaultPivotSpace = PivotSpaces.Canvas,
  72. customPivotPosition = new Vector2(0.5f, 0.5f),
  73. mosaicPadding = 4,
  74. spritePadding = 0,
  75. generateAnimationClips = true,
  76. generateModelPrefab = true,
  77. addSortingGroup = true,
  78. addShadowCasters = false
  79. };
  80. // Use for inspector to check if the file node is checked
  81. [SerializeField]
  82. #pragma warning disable 169, 414
  83. bool m_ImportFileNodeState = true;
  84. // Used by platform settings to mark it dirty so that it will trigger a reimport
  85. [SerializeField]
  86. #pragma warning disable 169, 414
  87. long m_PlatformSettingsDirtyTick;
  88. [SerializeField] string m_TextureAssetName = null;
  89. [SerializeField] List<SpriteMetaData> m_SingleSpriteImportData = new List<SpriteMetaData>(1) { new SpriteMetaData() };
  90. [FormerlySerializedAs("m_MultiSpriteImportData")]
  91. [SerializeField] List<SpriteMetaData> m_AnimatedSpriteImportData = new List<SpriteMetaData>();
  92. [SerializeField] List<SpriteMetaData> m_SpriteSheetImportData = new List<SpriteMetaData>();
  93. [SerializeField] List<Layer> m_AsepriteLayers = new List<Layer>();
  94. [SerializeField] List<TextureImporterPlatformSettings> m_PlatformSettings = new List<TextureImporterPlatformSettings>();
  95. [SerializeField] bool m_GeneratePhysicsShape = false;
  96. [SerializeField] SecondarySpriteTexture[] m_SecondarySpriteTextures;
  97. [SerializeField] string m_SpritePackingTag = "";
  98. SpriteImportMode spriteImportModeToUse => m_TextureImporterSettings.textureType != TextureImporterType.Sprite ?
  99. SpriteImportMode.None : (SpriteImportMode)m_TextureImporterSettings.spriteMode;
  100. AsepriteImportData m_ImportData;
  101. AsepriteFile m_AsepriteFile;
  102. List<Tag> m_Tags = new List<Tag>();
  103. List<Frame> m_Frames = new List<Frame>();
  104. [SerializeField] Vector2Int m_CanvasSize;
  105. GameObject m_RootGameObject;
  106. readonly Dictionary<int, GameObject> m_LayerIdToGameObject = new Dictionary<int, GameObject>();
  107. AsepriteImportData importData
  108. {
  109. get
  110. {
  111. var returnValue = m_ImportData;
  112. if (returnValue == null)
  113. // Using LoadAllAssetsAtPath because AsepriteImportData is hidden
  114. returnValue = AssetDatabase.LoadAllAssetsAtPath(assetPath).FirstOrDefault(x => x is AsepriteImportData) as AsepriteImportData;
  115. if (returnValue == null)
  116. returnValue = ScriptableObject.CreateInstance<AsepriteImportData>();
  117. m_ImportData = returnValue;
  118. return returnValue;
  119. }
  120. }
  121. internal bool isNPOT => Mathf.IsPowerOfTwo(importData.textureActualWidth) && Mathf.IsPowerOfTwo(importData.textureActualHeight);
  122. internal int textureActualWidth
  123. {
  124. get => importData.textureActualWidth;
  125. private set => importData.textureActualWidth = value;
  126. }
  127. internal int textureActualHeight
  128. {
  129. get => importData.textureActualHeight;
  130. private set => importData.textureActualHeight = value;
  131. }
  132. float definitionScale
  133. {
  134. get
  135. {
  136. var definitionScaleW = importData.importedTextureWidth / (float)textureActualWidth;
  137. var definitionScaleH = importData.importedTextureHeight / (float)textureActualHeight;
  138. return Mathf.Min(definitionScaleW, definitionScaleH);
  139. }
  140. }
  141. internal SecondarySpriteTexture[] secondaryTextures
  142. {
  143. get => m_SecondarySpriteTextures;
  144. set => m_SecondarySpriteTextures = value;
  145. }
  146. public override void OnImportAsset(AssetImportContext ctx)
  147. {
  148. if (m_ImportData == null)
  149. m_ImportData = ScriptableObject.CreateInstance<AsepriteImportData>();
  150. m_ImportData.hideFlags = HideFlags.HideInHierarchy;
  151. try
  152. {
  153. m_AsepriteFile = AsepriteReader.ReadFile(ctx.assetPath);
  154. if (m_AsepriteFile == null)
  155. return;
  156. m_CanvasSize = new Vector2Int(m_AsepriteFile.width, m_AsepriteFile.height);
  157. var newLayers = RestructureImportData(in m_AsepriteFile);
  158. FilterOutLayers(ref newLayers);
  159. UpdateCellNames(ref newLayers);
  160. m_Frames = ExtractFrameData(in m_AsepriteFile);
  161. m_Tags = ExtractTagsData(in m_AsepriteFile);
  162. if (newLayers.Count == 0)
  163. return;
  164. var assetName = System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath);
  165. List<NativeArray<Color32>> cellBuffers;
  166. List<int> cellWidth;
  167. List<int> cellHeight;
  168. if (layerImportMode == LayerImportModes.IndividualLayers)
  169. {
  170. m_AsepriteLayers = UpdateLayers(in newLayers, in m_AsepriteLayers);
  171. ImportLayers.Import(m_AsepriteLayers, out cellBuffers, out cellWidth, out cellHeight);
  172. }
  173. else
  174. {
  175. ImportMergedLayers.Import(assetName, ref newLayers, out cellBuffers, out cellWidth, out cellHeight);
  176. // Update layers after merged, since merged import creates new layers.
  177. // The new layers should be compared and merged together with the ones existing in the meta file.
  178. m_AsepriteLayers = UpdateLayers(in newLayers, in m_AsepriteLayers);
  179. }
  180. var mosaicPad = m_AsepriteImporterSettings.mosaicPadding;
  181. var spritePad = m_AsepriteImporterSettings.fileImportMode == FileImportModes.AnimatedSprite ? m_AsepriteImporterSettings.spritePadding : 0;
  182. var requireSquarePotTexture = IsRequiringSquarePotTexture(ctx);
  183. ImagePacker.Pack(cellBuffers.ToArray(), cellWidth.ToArray(), cellHeight.ToArray(), (int)mosaicPad, spritePad, requireSquarePotTexture, out var outputImageBuffer, out var packedTextureWidth, out var packedTextureHeight, out var spriteRects, out var uvTransforms);
  184. var packOffsets = new Vector2Int[spriteRects.Length];
  185. for (var i = 0; i < packOffsets.Length; ++i)
  186. {
  187. packOffsets[i] = new Vector2Int(uvTransforms[i].x - spriteRects[i].position.x, uvTransforms[i].y - spriteRects[i].position.y);
  188. packOffsets[i] *= -1;
  189. }
  190. var spriteImportData = UpdateSpriteImportData(in m_AsepriteLayers, spriteRects, packOffsets, uvTransforms);
  191. importData.importedTextureHeight = textureActualHeight = packedTextureHeight;
  192. importData.importedTextureWidth = textureActualWidth = packedTextureWidth;
  193. var output = TextureGeneration.Generate(
  194. ctx,
  195. outputImageBuffer,
  196. packedTextureWidth,
  197. packedTextureHeight,
  198. spriteImportData.ToArray(),
  199. in m_PlatformSettings,
  200. in m_TextureImporterSettings,
  201. m_SpritePackingTag,
  202. secondaryTextures);
  203. if (output.texture)
  204. {
  205. importData.importedTextureHeight = output.texture.height;
  206. importData.importedTextureWidth = output.texture.width;
  207. }
  208. if (output.texture != null && output.sprites != null)
  209. SetPhysicsOutline(GetDataProvider<ISpritePhysicsOutlineDataProvider>(), output.sprites, definitionScale, pixelsPerUnit, m_GeneratePhysicsShape);
  210. RegisterAssets(ctx, output);
  211. OnPostAsepriteImport?.Invoke(new ImportEventArgs(this, ctx));
  212. outputImageBuffer.DisposeIfCreated();
  213. foreach (var cellBuffer in cellBuffers)
  214. cellBuffer.DisposeIfCreated();
  215. }
  216. catch (Exception e)
  217. {
  218. Debug.LogError($"Failed to import file {assetPath}. Error: {e.Message} \n{e.StackTrace}");
  219. }
  220. finally
  221. {
  222. m_PreviousAsepriteImporterSettings = m_AsepriteImporterSettings;
  223. EditorUtility.SetDirty(this);
  224. m_AsepriteFile?.Dispose();
  225. }
  226. }
  227. List<Layer> RestructureImportData(in AsepriteFile file)
  228. {
  229. var frameData = file.frameData;
  230. var nameGenerator = new UniqueNameGenerator();
  231. var layers = new List<Layer>();
  232. var parentTable = new Dictionary<int, Layer>();
  233. for (var i = 0; i < frameData.Count; ++i)
  234. {
  235. var chunks = frameData[i].chunks;
  236. for (var m = 0; m < chunks.Count; ++m)
  237. {
  238. if (chunks[m].chunkType == ChunkTypes.Layer)
  239. {
  240. var layerChunk = chunks[m] as LayerChunk;
  241. var layer = new Layer();
  242. var childLevel = layerChunk.childLevel;
  243. parentTable[childLevel] = layer;
  244. layer.parentIndex = childLevel == 0 ? -1 : parentTable[childLevel - 1].index;
  245. layer.name = nameGenerator.GetUniqueName(layerChunk.name, layer.parentIndex);
  246. layer.layerFlags = layerChunk.flags;
  247. layer.layerType = layerChunk.layerType;
  248. layer.blendMode = layerChunk.blendMode;
  249. layer.opacity = layerChunk.opacity / 255f;
  250. layer.index = layers.Count;
  251. layer.guid = Layer.GenerateGuid(layer);
  252. layers.Add(layer);
  253. }
  254. }
  255. }
  256. for (var i = 0; i < frameData.Count; ++i)
  257. {
  258. var chunks = frameData[i].chunks;
  259. for (var m = 0; m < chunks.Count; ++m)
  260. {
  261. if (chunks[m].chunkType == ChunkTypes.Cell)
  262. {
  263. var cellChunk = chunks[m] as CellChunk;
  264. var layer = layers.Find(x => x.index == cellChunk.layerIndex);
  265. if (layer == null)
  266. {
  267. Debug.LogWarning($"Could not find the layer for one of the cells. Frame Index={i}, Chunk Index={m}.");
  268. continue;
  269. }
  270. var cellType = cellChunk.cellType;
  271. if (cellType == CellTypes.LinkedCell)
  272. {
  273. var cell = new LinkedCell();
  274. cell.frameIndex = i;
  275. cell.linkedToFrame = cellChunk.linkedToFrame;
  276. layer.linkedCells.Add(cell);
  277. }
  278. else
  279. {
  280. var cell = new Cell();
  281. cell.frameIndex = i;
  282. cell.updatedCellRect = false;
  283. // Flip Y. Aseprite 0,0 is at Top Left. Unity 0,0 is at Bottom Left.
  284. var cellY = (m_CanvasSize.y - cellChunk.posY) - cellChunk.height;
  285. cell.cellRect = new RectInt(cellChunk.posX, cellY, cellChunk.width, cellChunk.height);
  286. cell.opacity = cellChunk.opacity / 255f;
  287. cell.blendMode = layer.blendMode;
  288. cell.image = cellChunk.image;
  289. cell.additiveSortOrder = cellChunk.zIndex;
  290. cell.name = layer.name;
  291. cell.spriteId = GUID.Generate();
  292. var opacity = cell.opacity * layer.opacity;
  293. if ((1f - opacity) > Mathf.Epsilon)
  294. TextureTasks.AddOpacity(ref cell.image, opacity);
  295. layer.cells.Add(cell);
  296. }
  297. }
  298. }
  299. }
  300. return layers;
  301. }
  302. void FilterOutLayers(ref List<Layer> layers)
  303. {
  304. for (var i = layers.Count - 1; i >= 0; --i)
  305. {
  306. var layer = layers[i];
  307. if (!includeHiddenLayers && !ImportUtilities.IsLayerVisible(layer.index, in layers))
  308. {
  309. DisposeCellsInLayer(layer);
  310. layers.RemoveAt(i);
  311. continue;
  312. }
  313. var cells = layer.cells;
  314. for (var m = cells.Count - 1; m >= 0; --m)
  315. {
  316. var width = cells[m].cellRect.width;
  317. var height = cells[m].cellRect.width;
  318. if (width == 0 || height == 0)
  319. cells.RemoveAt(m);
  320. else if (cells[m].image == default || !cells[m].image.IsCreated)
  321. cells.RemoveAt(m);
  322. }
  323. }
  324. }
  325. static void DisposeCellsInLayer(Layer layer)
  326. {
  327. foreach (var cell in layer.cells)
  328. {
  329. var image = cell.image;
  330. image.DisposeIfCreated();
  331. }
  332. }
  333. static void UpdateCellNames(ref List<Layer> layers)
  334. {
  335. for (var i = 0; i < layers.Count; ++i)
  336. {
  337. var cells = layers[i].cells;
  338. for (var m = 0; m < cells.Count; ++m)
  339. {
  340. var cell = cells[m];
  341. cell.name = ImportUtilities.GetCellName(cell.name, cell.frameIndex, cells.Count);
  342. cells[m] = cell;
  343. }
  344. }
  345. }
  346. static List<Layer> UpdateLayers(in List<Layer> newLayers, in List<Layer> oldLayers)
  347. {
  348. if (oldLayers.Count == 0)
  349. return new List<Layer>(newLayers);
  350. var finalLayers = new List<Layer>(oldLayers);
  351. // Remove old layers
  352. for (var i = 0; i < oldLayers.Count; ++i)
  353. {
  354. var oldLayer = oldLayers[i];
  355. if (newLayers.FindIndex(x => x.guid == oldLayer.guid) == -1)
  356. finalLayers.Remove(oldLayer);
  357. }
  358. // Add new layers
  359. for (var i = 0; i < newLayers.Count; ++i)
  360. {
  361. var newLayer = newLayers[i];
  362. var layerIndex = finalLayers.FindIndex(x => x.guid == newLayer.guid);
  363. if (layerIndex == -1)
  364. finalLayers.Add(newLayer);
  365. }
  366. // Update layer data
  367. for (var i = 0; i < finalLayers.Count; ++i)
  368. {
  369. var finalLayer = finalLayers[i];
  370. var layerIndex = newLayers.FindIndex(x => x.guid == finalLayer.guid);
  371. if (layerIndex != -1)
  372. {
  373. var oldCells = finalLayer.cells;
  374. var newCells = newLayers[layerIndex].cells;
  375. for (var m = 0; m < newCells.Count; ++m)
  376. {
  377. if (m < oldCells.Count)
  378. {
  379. var oldCell = oldCells[m];
  380. var newCell = newCells[m];
  381. newCell.spriteId = oldCell.spriteId;
  382. #if UNITY_2023_1_OR_NEWER
  383. newCell.updatedCellRect = newCell.cellRect != oldCell.cellRect;
  384. #else
  385. newCell.updatedCellRect = !newCell.cellRect.IsEqual(oldCell.cellRect);
  386. #endif
  387. newCells[m] = newCell;
  388. }
  389. }
  390. finalLayer.cells = new List<Cell>(newCells);
  391. finalLayer.linkedCells = new List<LinkedCell>(newLayers[layerIndex].linkedCells);
  392. finalLayer.index = newLayers[layerIndex].index;
  393. finalLayer.opacity = newLayers[layerIndex].opacity;
  394. finalLayer.parentIndex = newLayers[layerIndex].parentIndex;
  395. }
  396. }
  397. return finalLayers;
  398. }
  399. bool IsRequiringSquarePotTexture(AssetImportContext ctx)
  400. {
  401. var platformSettings = TextureImporterUtilities.GetPlatformTextureSettings(ctx.selectedBuildTarget, in m_PlatformSettings);
  402. return (TextureImporterFormat.PVRTC_RGB2 <= platformSettings.format && platformSettings.format <= TextureImporterFormat.PVRTC_RGBA4);
  403. }
  404. static List<Frame> ExtractFrameData(in AsepriteFile file)
  405. {
  406. var noOfFrames = file.noOfFrames;
  407. var frames = new List<Frame>(noOfFrames);
  408. for (var i = 0; i < noOfFrames; ++i)
  409. {
  410. var frameData = file.frameData[i];
  411. var eventStrings = ExtractEventStringFromCells(frameData);
  412. var frame = new Frame()
  413. {
  414. duration = frameData.frameDuration,
  415. eventStrings = eventStrings
  416. };
  417. frames.Add(frame);
  418. }
  419. return frames;
  420. }
  421. static string[] ExtractEventStringFromCells(FrameData frameData)
  422. {
  423. var chunks = frameData.chunks;
  424. var eventStrings = new HashSet<string>();
  425. for (var i = 0; i < chunks.Count; ++i)
  426. {
  427. if (chunks[i].chunkType != ChunkTypes.Cell)
  428. continue;
  429. var cellChunk = (CellChunk)chunks[i];
  430. if (cellChunk.dataChunk == null)
  431. continue;
  432. var dataText = cellChunk.dataChunk.text;
  433. if (string.IsNullOrEmpty(dataText) || !dataText.StartsWith("event:"))
  434. continue;
  435. var eventString = dataText.Remove(0, "event:".Length);
  436. eventString = eventString.Trim(' ');
  437. eventStrings.Add(eventString);
  438. }
  439. return eventStrings.ToArray();
  440. }
  441. static List<Tag> ExtractTagsData(in AsepriteFile file)
  442. {
  443. var tags = new List<Tag>();
  444. var noOfFrames = file.noOfFrames;
  445. for (var i = 0; i < noOfFrames; ++i)
  446. {
  447. var frame = file.frameData[i];
  448. var noOfChunks = frame.chunkCount;
  449. for (var m = 0; m < noOfChunks; ++m)
  450. {
  451. var chunk = frame.chunks[m];
  452. if (chunk.chunkType != ChunkTypes.Tags)
  453. continue;
  454. var tagChunk = chunk as TagsChunk;
  455. var noOfTags = tagChunk.noOfTags;
  456. for (var n = 0; n < noOfTags; ++n)
  457. {
  458. var data = tagChunk.tagData[n];
  459. var tag = new Tag();
  460. tag.name = data.name;
  461. tag.noOfRepeats = data.noOfRepeats;
  462. tag.fromFrame = data.fromFrame;
  463. // Adding one more frame as Aseprite's tags seems to always be 1 short.
  464. tag.toFrame = data.toFrame + 1;
  465. tags.Add(tag);
  466. }
  467. }
  468. }
  469. return tags;
  470. }
  471. List<SpriteMetaData> UpdateSpriteImportData(in List<Layer> layers, RectInt[] spriteRects, Vector2Int[] packOffsets, Vector2Int[] uvTransforms)
  472. {
  473. if (m_AsepriteImporterSettings.fileImportMode == FileImportModes.SpriteSheet)
  474. {
  475. return GetSpriteImportData();
  476. }
  477. var cellLookup = new List<Cell>();
  478. for (var i = 0; i < layers.Count; ++i)
  479. cellLookup.AddRange(layers[i].cells);
  480. var spriteImportData = GetSpriteImportData();
  481. if (spriteImportData.Count <= 0)
  482. {
  483. var newSpriteMeta = new List<SpriteMetaData>();
  484. for (var i = 0; i < spriteRects.Length; ++i)
  485. {
  486. var cell = cellLookup[i];
  487. var spriteData = CreateNewSpriteMetaData(in cell, in spriteRects[i], packOffsets[i], in uvTransforms[i]);
  488. newSpriteMeta.Add(spriteData);
  489. }
  490. spriteImportData.Clear();
  491. spriteImportData.AddRange(newSpriteMeta);
  492. }
  493. else
  494. {
  495. // Remove old cells
  496. for (var i = spriteImportData.Count - 1; i >= 0; --i)
  497. {
  498. var spriteData = spriteImportData[i];
  499. if (cellLookup.FindIndex(x => x.spriteId == spriteData.spriteID) == -1)
  500. spriteImportData.Remove(spriteData);
  501. }
  502. // Add new cells
  503. for (var i = 0; i < cellLookup.Count; ++i)
  504. {
  505. var cell = cellLookup[i];
  506. if (spriteImportData.FindIndex(x => x.spriteID == cell.spriteId) == -1)
  507. {
  508. var spriteData = CreateNewSpriteMetaData(in cell, spriteRects[i], packOffsets[i], uvTransforms[i]);
  509. spriteImportData.Add(spriteData);
  510. }
  511. }
  512. // Update with new pack data
  513. for (var i = 0; i < cellLookup.Count; ++i)
  514. {
  515. var cell = cellLookup[i];
  516. var spriteData = spriteImportData.Find(x => x.spriteID == cell.spriteId);
  517. if (spriteData != null)
  518. {
  519. var areSettingsUpdated = !m_PreviousAsepriteImporterSettings.IsDefault() &&
  520. (pivotAlignment != m_PreviousAsepriteImporterSettings.defaultPivotAlignment ||
  521. pivotSpace != m_PreviousAsepriteImporterSettings.defaultPivotSpace ||
  522. customPivotPosition != m_PreviousAsepriteImporterSettings.customPivotPosition ||
  523. spritePadding != m_PreviousAsepriteImporterSettings.spritePadding);
  524. // Update pivot if either the importer settings are updated
  525. // or the source files rect has been changed (Only for Canvas, as rect position doesn't matter in local).
  526. if (pivotSpace == PivotSpaces.Canvas &&
  527. (areSettingsUpdated || cell.updatedCellRect))
  528. {
  529. spriteData.alignment = SpriteAlignment.Custom;
  530. var cellRect = cell.cellRect;
  531. cellRect.x += packOffsets[i].x;
  532. cellRect.y += packOffsets[i].y;
  533. cellRect.width = spriteRects[i].width;
  534. cellRect.height = spriteRects[i].height;
  535. spriteData.pivot = ImportUtilities.CalculateCellPivot(cellRect, spritePadding, m_CanvasSize, pivotAlignment, customPivotPosition);
  536. }
  537. else if (pivotSpace == PivotSpaces.Local && areSettingsUpdated)
  538. {
  539. spriteData.alignment = pivotAlignment;
  540. spriteData.pivot = customPivotPosition;
  541. }
  542. spriteData.rect = new Rect(spriteRects[i].x, spriteRects[i].y, spriteRects[i].width, spriteRects[i].height);
  543. spriteData.uvTransform = uvTransforms[i];
  544. }
  545. }
  546. }
  547. return spriteImportData;
  548. }
  549. SpriteMetaData CreateNewSpriteMetaData(in Cell cell, in RectInt spriteRect, in Vector2Int packOffset, in Vector2Int uvTransform)
  550. {
  551. var spriteData = new SpriteMetaData();
  552. spriteData.border = Vector4.zero;
  553. if (pivotSpace == PivotSpaces.Canvas)
  554. {
  555. spriteData.alignment = SpriteAlignment.Custom;
  556. var cellRect = cell.cellRect;
  557. cellRect.x += packOffset.x;
  558. cellRect.y += packOffset.y;
  559. cellRect.width = spriteRect.width;
  560. cellRect.height = spriteRect.height;
  561. spriteData.pivot = ImportUtilities.CalculateCellPivot(cellRect, spritePadding, m_CanvasSize, pivotAlignment, customPivotPosition);
  562. }
  563. else
  564. {
  565. spriteData.alignment = pivotAlignment;
  566. spriteData.pivot = customPivotPosition;
  567. }
  568. spriteData.rect = new Rect(spriteRect.x, spriteRect.y, spriteRect.width, spriteRect.height);
  569. spriteData.spriteID = cell.spriteId;
  570. spriteData.name = cell.name;
  571. spriteData.uvTransform = uvTransform;
  572. return spriteData;
  573. }
  574. static void SetPhysicsOutline(ISpritePhysicsOutlineDataProvider physicsOutlineDataProvider, Sprite[] sprites, float definitionScale, float pixelsPerUnit, bool generatePhysicsShape)
  575. {
  576. foreach (var sprite in sprites)
  577. {
  578. var guid = sprite.GetSpriteID();
  579. var outline = physicsOutlineDataProvider.GetOutlines(guid);
  580. var generated = false;
  581. if ((outline == null || outline.Count == 0) && generatePhysicsShape)
  582. {
  583. InternalEditorBridge.GenerateOutlineFromSprite(sprite, 0.25f, 200, true, out var defaultOutline);
  584. outline = new List<Vector2[]>(defaultOutline.Length);
  585. for (var i = 0; i < defaultOutline.Length; ++i)
  586. {
  587. outline.Add(defaultOutline[i]);
  588. }
  589. generated = true;
  590. }
  591. if (outline != null && outline.Count > 0)
  592. {
  593. // Ensure that outlines are all valid.
  594. var validOutlineCount = 0;
  595. for (var i = 0; i < outline.Count; ++i)
  596. validOutlineCount += ((outline[i].Length > 2) ? 1 : 0);
  597. var index = 0;
  598. var convertedOutline = new Vector2[validOutlineCount][];
  599. var useScale = generated ? pixelsPerUnit * definitionScale : definitionScale;
  600. var outlineOffset = Vector2.zero;
  601. outlineOffset.x = sprite.rect.width * 0.5f;
  602. outlineOffset.y = sprite.rect.height * 0.5f;
  603. for (var i = 0; i < outline.Count; ++i)
  604. {
  605. if (outline[i].Length > 2)
  606. {
  607. convertedOutline[index] = new Vector2[outline[i].Length];
  608. for (var j = 0; j < outline[i].Length; ++j)
  609. convertedOutline[index][j] = outline[i][j] * useScale + outlineOffset;
  610. index++;
  611. }
  612. }
  613. sprite.OverridePhysicsShape(convertedOutline);
  614. }
  615. }
  616. }
  617. void RegisterAssets(AssetImportContext ctx, TextureGenerationOutput output)
  618. {
  619. if ((output.sprites == null || output.sprites.Length == 0) && output.texture == null)
  620. {
  621. Debug.LogWarning(TextContent.noSpriteOrTextureImportWarning, this);
  622. return;
  623. }
  624. var assetNameGenerator = new UniqueNameGenerator();
  625. if (!string.IsNullOrEmpty(output.importInspectorWarnings))
  626. {
  627. Debug.LogWarning(output.importInspectorWarnings);
  628. }
  629. if (output.importWarnings != null && output.importWarnings.Length != 0)
  630. {
  631. foreach (var warning in output.importWarnings)
  632. Debug.LogWarning(warning);
  633. }
  634. if (output.thumbNail == null)
  635. Debug.LogWarning("Thumbnail generation fail");
  636. if (output.texture == null)
  637. {
  638. throw new Exception("Texture import fail");
  639. }
  640. var assetName = assetNameGenerator.GetUniqueName(System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath), -1, true, this);
  641. UnityEngine.Object mainAsset = null;
  642. RegisterTextureAsset(ctx, output, assetName, ref mainAsset);
  643. RegisterSprites(ctx, output, assetNameGenerator);
  644. RegisterGameObjects(ctx, output, ref mainAsset);
  645. RegisterAnimationClip(ctx, assetName, output);
  646. RegisterAnimatorController(ctx, assetName);
  647. ctx.AddObjectToAsset("AsepriteImportData", m_ImportData);
  648. ctx.SetMainObject(mainAsset);
  649. }
  650. void RegisterTextureAsset(AssetImportContext ctx, TextureGenerationOutput output, string assetName, ref UnityEngine.Object mainAsset)
  651. {
  652. var registerTextureNameId = string.IsNullOrEmpty(m_TextureAssetName) ? "Texture" : m_TextureAssetName;
  653. output.texture.name = assetName;
  654. ctx.AddObjectToAsset(registerTextureNameId, output.texture, output.thumbNail);
  655. mainAsset = output.texture;
  656. }
  657. static void RegisterSprites(AssetImportContext ctx, TextureGenerationOutput output, UniqueNameGenerator assetNameGenerator)
  658. {
  659. if (output.sprites == null)
  660. return;
  661. foreach (var sprite in output.sprites)
  662. {
  663. var spriteGuid = sprite.GetSpriteID().ToString();
  664. var spriteAssetName = assetNameGenerator.GetUniqueName(spriteGuid, -1, false, sprite);
  665. ctx.AddObjectToAsset(spriteAssetName, sprite);
  666. }
  667. }
  668. void RegisterGameObjects(AssetImportContext ctx, TextureGenerationOutput output, ref UnityEngine.Object mainAsset)
  669. {
  670. if (output.sprites.Length == 0)
  671. return;
  672. if (m_AsepriteImporterSettings.fileImportMode != FileImportModes.AnimatedSprite)
  673. return;
  674. PrefabGeneration.Generate(
  675. ctx,
  676. output,
  677. m_AsepriteLayers,
  678. m_LayerIdToGameObject,
  679. m_CanvasSize,
  680. m_AsepriteImporterSettings,
  681. ref mainAsset,
  682. out m_RootGameObject);
  683. }
  684. void RegisterAnimationClip(AssetImportContext ctx, string assetName, TextureGenerationOutput output)
  685. {
  686. if (output.sprites.Length == 0)
  687. return;
  688. if (m_AsepriteImporterSettings.fileImportMode != FileImportModes.AnimatedSprite)
  689. return;
  690. if (!generateAnimationClips)
  691. return;
  692. var noOfFrames = m_AsepriteFile.noOfFrames;
  693. if (noOfFrames == 1)
  694. return;
  695. var sprites = output.sprites;
  696. var clips = AnimationClipGeneration.Generate(
  697. assetName,
  698. sprites,
  699. m_AsepriteFile,
  700. m_AsepriteLayers,
  701. m_Frames,
  702. m_Tags,
  703. m_LayerIdToGameObject);
  704. for (var i = 0; i < clips.Length; ++i)
  705. ctx.AddObjectToAsset(clips[i].name, clips[i]);
  706. }
  707. void RegisterAnimatorController(AssetImportContext ctx, string assetName)
  708. {
  709. if (m_AsepriteImporterSettings.fileImportMode != FileImportModes.AnimatedSprite)
  710. return;
  711. AnimatorControllerGeneration.Generate(ctx, assetName, m_RootGameObject, generateModelPrefab);
  712. }
  713. internal void Apply()
  714. {
  715. // Do this so that asset change save dialog will not show
  716. var originalValue = EditorPrefs.GetBool("VerifySavingAssets", false);
  717. EditorPrefs.SetBool("VerifySavingAssets", false);
  718. AssetDatabase.ForceReserializeAssets(new string[] { assetPath }, ForceReserializeAssetsOptions.ReserializeMetadata);
  719. EditorPrefs.SetBool("VerifySavingAssets", originalValue);
  720. }
  721. public override bool SupportsRemappedAssetType(Type type)
  722. {
  723. if (type == typeof(AnimationClip))
  724. return true;
  725. return base.SupportsRemappedAssetType(type);
  726. }
  727. void SetPlatformTextureSettings(TextureImporterPlatformSettings platformSettings)
  728. {
  729. var index = m_PlatformSettings.FindIndex(x => x.name == platformSettings.name);
  730. if (index < 0)
  731. m_PlatformSettings.Add(platformSettings);
  732. else
  733. m_PlatformSettings[index] = platformSettings;
  734. }
  735. void SetDirty()
  736. {
  737. EditorUtility.SetDirty(this);
  738. }
  739. List<SpriteMetaData> GetSpriteImportData()
  740. {
  741. if (spriteImportModeToUse == SpriteImportMode.Multiple)
  742. {
  743. switch (m_AsepriteImporterSettings.fileImportMode)
  744. {
  745. case FileImportModes.SpriteSheet:
  746. return m_SpriteSheetImportData;
  747. case FileImportModes.AnimatedSprite:
  748. default:
  749. return m_AnimatedSpriteImportData;
  750. }
  751. }
  752. return m_SingleSpriteImportData;
  753. }
  754. internal SpriteRect GetSpriteData(GUID guid)
  755. {
  756. if (spriteImportModeToUse == SpriteImportMode.Multiple)
  757. {
  758. switch (m_AsepriteImporterSettings.fileImportMode)
  759. {
  760. case FileImportModes.SpriteSheet:
  761. return m_SpriteSheetImportData.FirstOrDefault(x => x.spriteID == guid);
  762. case FileImportModes.AnimatedSprite:
  763. default:
  764. return m_AnimatedSpriteImportData.FirstOrDefault(x => x.spriteID == guid);
  765. }
  766. }
  767. return m_SingleSpriteImportData[0];
  768. }
  769. internal TextureImporterPlatformSettings[] GetAllPlatformSettings()
  770. {
  771. return m_PlatformSettings.ToArray();
  772. }
  773. internal void ReadTextureSettings(TextureImporterSettings dest)
  774. {
  775. m_TextureImporterSettings.CopyTo(dest);
  776. }
  777. }
  778. }