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

ExtractLayerTask.cs 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using Unity.Collections;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. using Unity.Jobs;
  7. using Unity.Mathematics;
  8. using Unity.Burst;
  9. namespace UnityEditor.U2D.PSD
  10. {
  11. internal static class ExtractLayerTask
  12. {
  13. struct LayerGroupData
  14. {
  15. public int startIndex { get; set; }
  16. public int endIndex { get; set; }
  17. /// <summary>
  18. /// The layer's bounding box in document space.
  19. /// </summary>
  20. public int4 documentRect { get; set; }
  21. }
  22. [BurstCompile]
  23. struct ConvertBufferJob : IJobParallelFor
  24. {
  25. [ReadOnly, DeallocateOnJobCompletion]
  26. public NativeArray<int> inputTextureBufferSizes;
  27. [ReadOnly, DeallocateOnJobCompletion]
  28. public NativeArray<IntPtr> inputTextures;
  29. [ReadOnly, DeallocateOnJobCompletion]
  30. public NativeArray<int4> inputLayerRects;
  31. [ReadOnly, DeallocateOnJobCompletion]
  32. public NativeArray<LayerGroupData> layerGroupDataData;
  33. [ReadOnly, DeallocateOnJobCompletion]
  34. public NativeArray<int4> outputLayerRect;
  35. [DeallocateOnJobCompletion]
  36. public NativeArray<IntPtr> outputTextures;
  37. public unsafe void Execute(int groupIndex)
  38. {
  39. var outputColor = (Color32*)outputTextures[groupIndex];
  40. var groupStartIndex = layerGroupDataData[groupIndex].startIndex;
  41. var groupEndIndex = layerGroupDataData[groupIndex].endIndex;
  42. var outStartX = outputLayerRect[groupIndex].x;
  43. var outStartY = outputLayerRect[groupIndex].y;
  44. var outWidth = outputLayerRect[groupIndex].z;
  45. var outHeight = outputLayerRect[groupIndex].w;
  46. for (var layerIndex = groupEndIndex; layerIndex >= groupStartIndex; --layerIndex)
  47. {
  48. if (inputTextures[layerIndex] == IntPtr.Zero)
  49. continue;
  50. var inputColor = (Color32*)inputTextures[layerIndex];
  51. var inX = inputLayerRects[layerIndex].x;
  52. var inY = inputLayerRects[layerIndex].y;
  53. var inWidth = inputLayerRects[layerIndex].z;
  54. var inHeight = inputLayerRects[layerIndex].w;
  55. for (var y = 0; y < inHeight; ++y)
  56. {
  57. var outPosY = (y + inY) - outStartY;
  58. // If pixel is outside of output texture's Y, move to the next pixel.
  59. if (outPosY < 0 || outPosY >= outHeight)
  60. continue;
  61. // Flip Y position on the input texture, because
  62. // PSDs textures are stored "upside-down"
  63. var inRow = ((inHeight - 1) - y) * inWidth;
  64. var outRow = outPosY * outWidth;
  65. for (var x = 0; x < inWidth; ++x)
  66. {
  67. var outPosX = (x + inX) - outStartX;
  68. // If pixel is outside of output texture's X, move to the next pixel.
  69. if (outPosX < 0 || outPosX >= outWidth)
  70. continue;
  71. var inBufferIndex = inRow + x;
  72. var outBufferIndex = outRow + outPosX;
  73. if (outBufferIndex < 0 || outBufferIndex > (outWidth * outHeight))
  74. continue;
  75. Color inColor = inputColor[inBufferIndex];
  76. Color prevOutColor = outputColor[outBufferIndex];
  77. var outColor = new Color();
  78. var destAlpha = prevOutColor.a * (1 - inColor.a);
  79. outColor.a = inColor.a + prevOutColor.a * (1 - inColor.a);
  80. var premultiplyAlpha = outColor.a > 0.0f ? 1 / outColor.a : 1f;
  81. outColor.r = (inColor.r * inColor.a + prevOutColor.r * destAlpha) * premultiplyAlpha;
  82. outColor.g = (inColor.g * inColor.a + prevOutColor.g * destAlpha) * premultiplyAlpha;
  83. outColor.b = (inColor.b * inColor.a + prevOutColor.b * destAlpha) * premultiplyAlpha;
  84. outputColor[outBufferIndex] = outColor;
  85. }
  86. }
  87. }
  88. }
  89. }
  90. public static unsafe void Execute(in PSDExtractLayerData[] psdExtractLayerData, out List<PSDLayer> outputLayers, bool importHiddenLayer, Vector2Int canvasSize)
  91. {
  92. outputLayers = new List<PSDLayer>();
  93. UnityEngine.Profiling.Profiler.BeginSample("ExtractLayer_PrepareJob");
  94. var inputLayers = new List<PSDLayer>();
  95. ExtractLayerData(in psdExtractLayerData, ref inputLayers, importHiddenLayer, false, true, canvasSize);
  96. var layerGroupData = new List<LayerGroupData>();
  97. GenerateOutputLayers(in inputLayers, ref outputLayers, ref layerGroupData, false, canvasSize);
  98. if (layerGroupData.Count == 0)
  99. {
  100. foreach (var layer in outputLayers)
  101. layer.texture = default;
  102. return;
  103. }
  104. var job = new ConvertBufferJob();
  105. job.inputTextureBufferSizes = new NativeArray<int>(inputLayers.Count, Allocator.TempJob);
  106. job.inputTextures = new NativeArray<IntPtr>(inputLayers.Count, Allocator.TempJob);
  107. job.inputLayerRects = new NativeArray<int4>(inputLayers.Count, Allocator.TempJob);
  108. job.outputLayerRect = new NativeArray<int4>(layerGroupData.Count, Allocator.TempJob);
  109. job.outputTextures = new NativeArray<IntPtr>(layerGroupData.Count, Allocator.TempJob);
  110. for (int i = 0, groupIndex = 0; i < inputLayers.Count; ++i)
  111. {
  112. var inputLayer = inputLayers[i];
  113. var outputLayer = outputLayers[i];
  114. job.inputTextures[i] = inputLayer.texture.IsCreated ? new IntPtr(inputLayer.texture.GetUnsafePtr()) : IntPtr.Zero;
  115. var isGroupOwner = groupIndex < layerGroupData.Count && layerGroupData[groupIndex].startIndex == i;
  116. if (isGroupOwner)
  117. {
  118. outputLayer.texture = new NativeArray<Color32>(outputLayer.width * outputLayer.height, Allocator.Persistent);
  119. job.outputLayerRect[groupIndex] = new int4((int)outputLayer.layerPosition.x, (int)outputLayer.layerPosition.y, outputLayer.width, outputLayer.height);
  120. job.outputTextures[groupIndex] = outputLayer.texture.IsCreated ? new IntPtr(outputLayer.texture.GetUnsafePtr()) : IntPtr.Zero;
  121. job.inputTextureBufferSizes[i] = inputLayer.texture.IsCreated ? inputLayer.texture.Length : -1;
  122. job.inputLayerRects[i] = layerGroupData[groupIndex].documentRect;
  123. ++groupIndex;
  124. }
  125. else
  126. {
  127. job.inputTextureBufferSizes[i] = inputLayer.texture.IsCreated ? inputLayer.texture.Length : -1;
  128. job.inputLayerRects[i] = new int4((int)inputLayer.layerPosition.x, (int)inputLayer.layerPosition.y, inputLayer.width, inputLayer.height);
  129. outputLayer.texture = default;
  130. }
  131. }
  132. job.layerGroupDataData = new NativeArray<LayerGroupData>(layerGroupData.ToArray(), Allocator.TempJob);
  133. var jobsPerThread = layerGroupData.Count / (SystemInfo.processorCount == 0 ? 8 : SystemInfo.processorCount);
  134. jobsPerThread = Mathf.Max(jobsPerThread, 1);
  135. var handle = job.Schedule(layerGroupData.Count, jobsPerThread);
  136. UnityEngine.Profiling.Profiler.EndSample();
  137. handle.Complete();
  138. }
  139. static void ExtractLayerData(in PSDExtractLayerData[] inputLayers, ref List<PSDLayer> extractedLayers, bool importHiddenLayer, bool flatten, bool parentGroupVisible, Vector2Int canvasSize)
  140. {
  141. var parentGroupIndex = extractedLayers.Count - 1;
  142. foreach (var inputLayer in inputLayers)
  143. {
  144. var bitmapLayer = inputLayer.bitmapLayer;
  145. var importSettings = inputLayer.importSetting;
  146. var layerVisible = bitmapLayer.Visible && parentGroupVisible;
  147. var layerRect = new RectInt(bitmapLayer.documentRect.X, bitmapLayer.documentRect.Y, bitmapLayer.Surface.width, bitmapLayer.Surface.height);
  148. if (!bitmapLayer.IsGroup)
  149. layerRect.y = (canvasSize.y - layerRect.y - layerRect.height);
  150. NativeArray<Color32> surface = default;
  151. if ((importHiddenLayer || bitmapLayer.Visible) &&
  152. importSettings.importLayer &&
  153. bitmapLayer.Surface.color.IsCreated &&
  154. bitmapLayer.Surface.color.Length > 0)
  155. surface = bitmapLayer.Surface.color;
  156. var extractedLayer = new PSDLayer(surface, parentGroupIndex, bitmapLayer.IsGroup, bitmapLayer.Name, layerRect.width, layerRect.height, bitmapLayer.LayerID, bitmapLayer.Visible)
  157. {
  158. spriteID = inputLayer.importSetting.spriteId,
  159. flatten = bitmapLayer.IsGroup && inputLayer.importSetting.flatten,
  160. layerPosition = bitmapLayer.IsGroup ? Vector2.zero : layerRect.position
  161. };
  162. extractedLayer.isImported = (importHiddenLayer || layerVisible) && !flatten && importSettings.importLayer;
  163. if (extractedLayer.isGroup)
  164. extractedLayer.isImported = extractedLayer.isImported && extractedLayer.flatten;
  165. extractedLayers.Add(extractedLayer);
  166. if (inputLayer.children.Length > 0)
  167. ExtractLayerData(in inputLayer.children, ref extractedLayers, importHiddenLayer, flatten || extractedLayer.flatten, layerVisible, canvasSize);
  168. }
  169. }
  170. static void GenerateOutputLayers(in List<PSDLayer> inputLayers, ref List<PSDLayer> outputLayers, ref List<LayerGroupData> layerGroupData, bool flatten, Vector2Int canvasSize)
  171. {
  172. var canvasRect = new RectInt(Vector2Int.zero, canvasSize);
  173. for (var i = 0; i < inputLayers.Count; ++i)
  174. {
  175. var inputLayer = inputLayers[i];
  176. var outputLayer = new PSDLayer(inputLayer);
  177. var outputRect = new RectInt((int)outputLayer.layerPosition.x, (int)outputLayer.layerPosition.y, outputLayer.width, outputLayer.height);
  178. if (inputLayer.isGroup)
  179. {
  180. var childIndices = FindAllChildrenOfParent(i, in inputLayers);
  181. childIndices.Sort();
  182. var startIndex = i;
  183. var endIndex = i + childIndices.Count;
  184. if (flatten == false && inputLayer.flatten && startIndex < endIndex)
  185. {
  186. var groupBoundingBox = CalculateLayerRectInChildren(in inputLayers, in childIndices);
  187. layerGroupData.Add(new LayerGroupData()
  188. {
  189. startIndex = startIndex,
  190. endIndex = endIndex,
  191. documentRect = new int4(groupBoundingBox.x, groupBoundingBox.y, groupBoundingBox.width, groupBoundingBox.height)
  192. });
  193. outputLayer.texture = default;
  194. outputRect = groupBoundingBox;
  195. }
  196. }
  197. else if(!inputLayer.isGroup && inputLayer.isImported)
  198. {
  199. var inputRect = new int4((int)inputLayer.layerPosition.x, (int)inputLayer.layerPosition.y, inputLayer.width, inputLayer.height);
  200. layerGroupData.Add(new LayerGroupData()
  201. {
  202. startIndex = i,
  203. endIndex = i,
  204. documentRect = inputRect
  205. });
  206. }
  207. CropRect(ref outputRect, canvasRect);
  208. outputLayer.layerPosition = outputRect.position;
  209. outputLayer.width = outputRect.width;
  210. outputLayer.height = outputRect.height;
  211. outputLayers.Add(outputLayer);
  212. }
  213. }
  214. static List<int> FindAllChildrenOfParent(int parentIndex, in List<PSDLayer> layers)
  215. {
  216. var childIndices = new List<int>();
  217. for (var i = parentIndex + 1; i < layers.Count; ++i)
  218. {
  219. if (layers[i].parentIndex == parentIndex)
  220. {
  221. childIndices.Add(i);
  222. if (layers[i].isGroup)
  223. childIndices.AddRange(FindAllChildrenOfParent(i, in layers));
  224. }
  225. }
  226. return childIndices;
  227. }
  228. static RectInt CalculateLayerRectInChildren(in List<PSDLayer> inputLayers, in List<int> childIndices)
  229. {
  230. var groupBoundingBox = default(RectInt);
  231. for (var m = 0; m < childIndices.Count; ++m)
  232. {
  233. var childLayer = inputLayers[childIndices[m]];
  234. if (childLayer.isGroup)
  235. continue;
  236. var layerRect = new RectInt((int) childLayer.layerPosition.x, (int) childLayer.layerPosition.y,
  237. childLayer.width, childLayer.height);
  238. if (IsRectIntDefault(groupBoundingBox))
  239. groupBoundingBox = layerRect;
  240. else
  241. FitRectInsideRect(ref groupBoundingBox, in layerRect);
  242. }
  243. return groupBoundingBox;
  244. }
  245. static bool IsRectIntDefault(RectInt rectInt)
  246. {
  247. return rectInt.x == 0 &&
  248. rectInt.y == 0 &&
  249. rectInt.width == 0 &&
  250. rectInt.height == 0;
  251. }
  252. static void CropRect(ref RectInt baseRect, in RectInt cropArea)
  253. {
  254. if (baseRect.x < cropArea.x)
  255. {
  256. baseRect.width = Mathf.Max(baseRect.width - (cropArea.x - baseRect.x), 0);
  257. baseRect.x = cropArea.x;
  258. }
  259. if (baseRect.xMax > cropArea.xMax)
  260. {
  261. baseRect.x = Mathf.Min(baseRect.x, cropArea.xMax);
  262. baseRect.width = Mathf.Max(cropArea.xMax - baseRect.x, 0);
  263. }
  264. if (baseRect.y < cropArea.y)
  265. {
  266. baseRect.height = Mathf.Max(baseRect.height - (cropArea.y - baseRect.y), 0);
  267. baseRect.y = cropArea.y;
  268. }
  269. if (baseRect.yMax > cropArea.yMax)
  270. {
  271. baseRect.y = Mathf.Min(baseRect.y, cropArea.yMax);
  272. baseRect.height = Mathf.Max(cropArea.yMax - baseRect.y, 0);
  273. }
  274. }
  275. static void FitRectInsideRect(ref RectInt baseRect, in RectInt rectToFitIn)
  276. {
  277. if (baseRect.xMin > rectToFitIn.xMin)
  278. baseRect.xMin = rectToFitIn.xMin;
  279. if (baseRect.yMin > rectToFitIn.yMin)
  280. baseRect.yMin = rectToFitIn.yMin;
  281. if (baseRect.xMax < rectToFitIn.xMax)
  282. baseRect.xMax = rectToFitIn.xMax;
  283. if (baseRect.yMax < rectToFitIn.yMax)
  284. baseRect.yMax = rectToFitIn.yMax;
  285. }
  286. }
  287. }