No Description
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.

FlattenImageTask.cs 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using System;
  2. using System.Collections.Generic;
  3. using Unity.Burst;
  4. using UnityEngine;
  5. using Unity.Collections;
  6. using Unity.Collections.LowLevel.Unsafe;
  7. using Unity.Jobs;
  8. using Unity.Mathematics;
  9. namespace UnityEditor.U2D.PSD
  10. {
  11. static class FlattenImageTask
  12. {
  13. struct LayerData
  14. {
  15. public IntPtr layerBuffer;
  16. public int4 layerRect;
  17. }
  18. public static unsafe void Execute(in PSDExtractLayerData[] layer, ref NativeArray<Color32> output, bool importHiddenLayer, Vector2Int documentSize)
  19. {
  20. UnityEngine.Profiling.Profiler.BeginSample("FlattenImage");
  21. var layerData = new List<LayerData>();
  22. for (var i = layer.Length - 1; i >= 0; --i)
  23. {
  24. GetLayerDataToMerge(in layer[i], ref layerData, importHiddenLayer);
  25. }
  26. if (layerData.Count == 0)
  27. return;
  28. var layersPerJob = layerData.Count / (SystemInfo.processorCount == 0 ? 8 : SystemInfo.processorCount);
  29. layersPerJob = Mathf.Max(layersPerJob, 1);
  30. var job = new FlattenImageInternalJob();
  31. var combineJob = new FlattenImageInternalJob();
  32. job.inputTextures = new NativeArray<IntPtr>(layerData.Count, Allocator.TempJob);
  33. job.inputTextureRects = new NativeArray<int4>(layerData.Count, Allocator.TempJob);
  34. for (var i = 0; i < layerData.Count; ++i)
  35. {
  36. job.inputTextures[i] = layerData[i].layerBuffer;
  37. job.inputTextureRects[i] = layerData[i].layerRect;
  38. }
  39. job.layersPerJob = layersPerJob;
  40. job.flipY = false;
  41. combineJob.flipY = true;
  42. var jobCount = layerData.Count / layersPerJob + (layerData.Count % layersPerJob > 0 ? 1 : 0);
  43. combineJob.layersPerJob = jobCount;
  44. var premergedBuffer = new NativeArray<byte>[jobCount];
  45. job.outputTextureSizes = new NativeArray<int2>(jobCount, Allocator.TempJob);
  46. job.outputTextures = new NativeArray<IntPtr>(jobCount, Allocator.TempJob);
  47. combineJob.inputTextures = new NativeArray<IntPtr>(jobCount, Allocator.TempJob);
  48. combineJob.inputTextureRects = new NativeArray<int4>(jobCount, Allocator.TempJob);
  49. for (var i = 0; i < jobCount; ++i)
  50. {
  51. premergedBuffer[i] = new NativeArray<byte>(documentSize.x * documentSize.y * 4, Allocator.TempJob);
  52. job.outputTextureSizes[i] = new int2(documentSize.x, documentSize.y);
  53. job.outputTextures[i] = new IntPtr(premergedBuffer[i].GetUnsafePtr());
  54. combineJob.inputTextures[i] = new IntPtr(premergedBuffer[i].GetUnsafeReadOnlyPtr());
  55. combineJob.inputTextureRects[i] = new int4(0, 0, documentSize.x, documentSize.y);
  56. }
  57. combineJob.outputTextureSizes = new NativeArray<int2>(new [] {new int2(documentSize.x, documentSize.y) }, Allocator.TempJob);
  58. combineJob.outputTextures = new NativeArray<IntPtr>(new[] { new IntPtr(output.GetUnsafePtr()) }, Allocator.TempJob);
  59. var handle = job.Schedule(jobCount, 1);
  60. combineJob.Schedule(1, 1, handle).Complete();
  61. foreach (var b in premergedBuffer)
  62. {
  63. if (b.IsCreated)
  64. b.Dispose();
  65. }
  66. UnityEngine.Profiling.Profiler.EndSample();
  67. }
  68. static unsafe void GetLayerDataToMerge(in PSDExtractLayerData layer, ref List<LayerData> layerData, bool importHiddenLayer)
  69. {
  70. var bitmapLayer = layer.bitmapLayer;
  71. var importSetting = layer.importSetting;
  72. if (!bitmapLayer.Visible && importHiddenLayer == false || importSetting.importLayer == false)
  73. return;
  74. if (bitmapLayer.IsGroup)
  75. {
  76. for (var i = layer.children.Length - 1; i >= 0; --i)
  77. GetLayerDataToMerge(layer.children[i], ref layerData, importHiddenLayer);
  78. }
  79. if (bitmapLayer.Surface == null || bitmapLayer.localRect == default)
  80. return;
  81. var layerRect = bitmapLayer.documentRect;
  82. var data = new LayerData()
  83. {
  84. layerBuffer = new IntPtr(bitmapLayer.Surface.color.GetUnsafeReadOnlyPtr()),
  85. layerRect = new int4(layerRect.X, layerRect.Y, layerRect.Width, layerRect.Height)
  86. };
  87. layerData.Add(data);
  88. }
  89. [BurstCompile]
  90. struct FlattenImageInternalJob : IJobParallelFor
  91. {
  92. [ReadOnly, DeallocateOnJobCompletion]
  93. public NativeArray<IntPtr> inputTextures;
  94. [ReadOnly, DeallocateOnJobCompletion]
  95. public NativeArray<int4> inputTextureRects;
  96. [ReadOnly]
  97. public int layersPerJob;
  98. [ReadOnly]
  99. public bool flipY;
  100. [ReadOnly, DeallocateOnJobCompletion]
  101. public NativeArray<int2> outputTextureSizes;
  102. [DeallocateOnJobCompletion]
  103. public NativeArray<IntPtr> outputTextures;
  104. public unsafe void Execute(int index)
  105. {
  106. var outputColor = (Color32*)outputTextures[index].ToPointer();
  107. for (var layerIndex = index * layersPerJob; layerIndex < (index * layersPerJob) + layersPerJob; ++layerIndex)
  108. {
  109. if (inputTextures.Length <= layerIndex)
  110. break;
  111. var inputColor = (Color32*)inputTextures[layerIndex].ToPointer();
  112. var inStartPosX = inputTextureRects[layerIndex].x;
  113. var inStartPosY = inputTextureRects[layerIndex].y;
  114. var inWidth = inputTextureRects[layerIndex].z;
  115. var inHeight = inputTextureRects[layerIndex].w;
  116. var outWidth = outputTextureSizes[index].x;
  117. var outHeight = outputTextureSizes[index].y;
  118. for (var y = 0; y < inHeight; ++y)
  119. {
  120. var outPosY = y + inStartPosY;
  121. // If pixel is outside of output texture's Y, move to the next pixel.
  122. if (outPosY < 0 || outPosY >= outHeight)
  123. continue;
  124. var inRow = y * inWidth;
  125. var outRow = flipY ? (outHeight - 1 - y - inStartPosY) * outWidth : (y + inStartPosY) * outWidth;
  126. for (var x = 0; x < inWidth; ++x)
  127. {
  128. var outPosX = x + inStartPosX;
  129. // If pixel is outside of output texture's X, move to the next pixel.
  130. if (outPosX < 0 || outPosX >= outWidth)
  131. continue;
  132. var inBufferIndex = inRow + x;
  133. var outBufferIndex = outRow + outPosX;
  134. Color inColor = inputColor[inBufferIndex];
  135. Color prevOutColor = outputColor[outBufferIndex];
  136. var outColor = new Color();
  137. var destAlpha = prevOutColor.a * (1 - inColor.a);
  138. outColor.a = inColor.a + prevOutColor.a * (1 - inColor.a);
  139. var premultiplyAlpha = outColor.a > 0.0f ? 1 / outColor.a : 1f;
  140. outColor.r = (inColor.r * inColor.a + prevOutColor.r * destAlpha) * premultiplyAlpha;
  141. outColor.g = (inColor.g * inColor.a + prevOutColor.g * destAlpha) * premultiplyAlpha;
  142. outColor.b = (inColor.b * inColor.a + prevOutColor.b * destAlpha) * premultiplyAlpha;
  143. outputColor[outBufferIndex] = outColor;
  144. }
  145. }
  146. }
  147. }
  148. }
  149. }
  150. }