arenos-nexus/Arenos Nexus/Library/PackageCache/com.unity.2d.psdimporter@0adcab25a8fd/Editor/Tasks/FlattenImageTask.cs
Daniel 2e704cae70 init
Init Commit Unity
2025-09-25 22:01:28 +02:00

184 lines
7.9 KiB
C#

using System;
using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
namespace UnityEditor.U2D.PSD
{
static class FlattenImageTask
{
struct LayerData
{
public IntPtr layerBuffer;
public int4 layerRect;
}
public static unsafe void Execute(in PSDExtractLayerData[] layer, ref NativeArray<Color32> output, bool importHiddenLayer, Vector2Int documentSize)
{
UnityEngine.Profiling.Profiler.BeginSample("FlattenImage");
List<LayerData> layerData = new List<LayerData>();
for (int i = layer.Length - 1; i >= 0; --i)
{
GetLayerDataToMerge(in layer[i], ref layerData, importHiddenLayer);
}
if (layerData.Count == 0)
return;
int layersPerJob = layerData.Count / (SystemInfo.processorCount == 0 ? 8 : SystemInfo.processorCount);
layersPerJob = Mathf.Max(layersPerJob, 1);
FlattenImageInternalJob job = new FlattenImageInternalJob();
FlattenImageInternalJob combineJob = new FlattenImageInternalJob();
job.inputTextures = new NativeArray<IntPtr>(layerData.Count, Allocator.TempJob);
job.inputTextureRects = new NativeArray<int4>(layerData.Count, Allocator.TempJob);
for (int i = 0; i < layerData.Count; ++i)
{
job.inputTextures[i] = layerData[i].layerBuffer;
job.inputTextureRects[i] = layerData[i].layerRect;
}
job.layersPerJob = layersPerJob;
job.flipY = false;
combineJob.flipY = true;
int jobCount = layerData.Count / layersPerJob + (layerData.Count % layersPerJob > 0 ? 1 : 0);
combineJob.layersPerJob = jobCount;
NativeArray<byte>[] premergedBuffer = new NativeArray<byte>[jobCount];
job.outputTextureSizes = new NativeArray<int2>(jobCount, Allocator.TempJob);
job.outputTextures = new NativeArray<IntPtr>(jobCount, Allocator.TempJob);
combineJob.inputTextures = new NativeArray<IntPtr>(jobCount, Allocator.TempJob);
combineJob.inputTextureRects = new NativeArray<int4>(jobCount, Allocator.TempJob);
for (int i = 0; i < jobCount; ++i)
{
premergedBuffer[i] = new NativeArray<byte>(documentSize.x * documentSize.y * 4, Allocator.TempJob);
job.outputTextureSizes[i] = new int2(documentSize.x, documentSize.y);
job.outputTextures[i] = new IntPtr(premergedBuffer[i].GetUnsafePtr());
combineJob.inputTextures[i] = new IntPtr(premergedBuffer[i].GetUnsafeReadOnlyPtr());
combineJob.inputTextureRects[i] = new int4(0, 0, documentSize.x, documentSize.y);
}
combineJob.outputTextureSizes = new NativeArray<int2>(new[] { new int2(documentSize.x, documentSize.y) }, Allocator.TempJob);
combineJob.outputTextures = new NativeArray<IntPtr>(new[] { new IntPtr(output.GetUnsafePtr()) }, Allocator.TempJob);
JobHandle handle = job.Schedule(jobCount, 1);
combineJob.Schedule(1, 1, handle).Complete();
foreach (NativeArray<byte> b in premergedBuffer)
{
if (b.IsCreated)
b.Dispose();
}
UnityEngine.Profiling.Profiler.EndSample();
}
static unsafe void GetLayerDataToMerge(in PSDExtractLayerData layer, ref List<LayerData> layerData, bool importHiddenLayer)
{
PDNWrapper.BitmapLayer bitmapLayer = layer.bitmapLayer;
PSDLayerImportSetting importSetting = layer.importSetting;
if (!bitmapLayer.Visible && importHiddenLayer == false || importSetting.importLayer == false)
return;
if (bitmapLayer.IsGroup)
{
for (int i = layer.children.Length - 1; i >= 0; --i)
GetLayerDataToMerge(layer.children[i], ref layerData, importHiddenLayer);
}
if (bitmapLayer.Surface == null || bitmapLayer.localRect == default)
return;
PDNWrapper.Rectangle layerRect = bitmapLayer.documentRect;
LayerData data = new LayerData()
{
layerBuffer = new IntPtr(bitmapLayer.Surface.color.GetUnsafeReadOnlyPtr()),
layerRect = new int4(layerRect.X, layerRect.Y, layerRect.Width, layerRect.Height)
};
layerData.Add(data);
}
[BurstCompile]
struct FlattenImageInternalJob : IJobParallelFor
{
[ReadOnly, DeallocateOnJobCompletion]
public NativeArray<IntPtr> inputTextures;
[ReadOnly, DeallocateOnJobCompletion]
public NativeArray<int4> inputTextureRects;
[ReadOnly]
public int layersPerJob;
[ReadOnly]
public bool flipY;
[ReadOnly, DeallocateOnJobCompletion]
public NativeArray<int2> outputTextureSizes;
[DeallocateOnJobCompletion]
public NativeArray<IntPtr> outputTextures;
public unsafe void Execute(int index)
{
Color32* outputColor = (Color32*)outputTextures[index].ToPointer();
for (int layerIndex = index * layersPerJob; layerIndex < (index * layersPerJob) + layersPerJob; ++layerIndex)
{
if (inputTextures.Length <= layerIndex)
break;
Color32* inputColor = (Color32*)inputTextures[layerIndex].ToPointer();
int inStartPosX = inputTextureRects[layerIndex].x;
int inStartPosY = inputTextureRects[layerIndex].y;
int inWidth = inputTextureRects[layerIndex].z;
int inHeight = inputTextureRects[layerIndex].w;
int outWidth = outputTextureSizes[index].x;
int outHeight = outputTextureSizes[index].y;
for (int y = 0; y < inHeight; ++y)
{
int outPosY = y + inStartPosY;
// If pixel is outside of output texture's Y, move to the next pixel.
if (outPosY < 0 || outPosY >= outHeight)
continue;
int inRow = y * inWidth;
int outRow = flipY ? (outHeight - 1 - y - inStartPosY) * outWidth : (y + inStartPosY) * outWidth;
for (int x = 0; x < inWidth; ++x)
{
int outPosX = x + inStartPosX;
// If pixel is outside of output texture's X, move to the next pixel.
if (outPosX < 0 || outPosX >= outWidth)
continue;
int inBufferIndex = inRow + x;
int outBufferIndex = outRow + outPosX;
Color inColor = inputColor[inBufferIndex];
Color prevOutColor = outputColor[outBufferIndex];
Color outColor = new Color();
float destAlpha = prevOutColor.a * (1 - inColor.a);
outColor.a = inColor.a + prevOutColor.a * (1 - inColor.a);
float premultiplyAlpha = outColor.a > 0.0f ? 1 / outColor.a : 1f;
outColor.r = (inColor.r * inColor.a + prevOutColor.r * destAlpha) * premultiplyAlpha;
outColor.g = (inColor.g * inColor.a + prevOutColor.g * destAlpha) * premultiplyAlpha;
outColor.b = (inColor.b * inColor.a + prevOutColor.b * destAlpha) * premultiplyAlpha;
outputColor[outBufferIndex] = outColor;
}
}
}
}
}
}
}