暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

AsepriteImporter.cs 37KB

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