174 lines
8.2 KiB
C#
Raw Normal View History

2025-03-11 15:30:07 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using PDNWrapper;
using UnityEngine;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
namespace UnityEditor.U2D.PSD
{
class ExtractLayerTask
{
struct LayerExtractData
{
public int start;
public int end;
public int width;
public int height;
}
struct ConvertBufferJob : IJobParallelFor
{
[ReadOnly]
[DeallocateOnJobCompletion]
public NativeArray<IntPtr> original;
[ReadOnly]
[DeallocateOnJobCompletion]
public NativeArray<LayerExtractData> flattenIndex;
[ReadOnly]
[DeallocateOnJobCompletion]
public NativeArray<int> width;
[ReadOnly]
[DeallocateOnJobCompletion]
public NativeArray<int> height;
[DeallocateOnJobCompletion]
public NativeArray<IntPtr> output;
public unsafe void Execute(int index)
{
Color32* outputColor = (Color32*)output[index];
for (int i = flattenIndex[index].start; i <= flattenIndex[index].end; ++i)
{
if (original[i] == IntPtr.Zero)
continue;
Color32* originalColor = (Color32*)original[i];
int bufferWidth = width[i];
int bufferHeight = height[i];
for (int h = 0; h < bufferHeight; ++h)
{
int originalYOffset = h * bufferWidth;
int outputYOffset = (bufferHeight - h - 1) * bufferWidth;
for (int w = 0; w < bufferWidth; ++w)
{
var outColor = outputColor[w + outputYOffset];
var inColor = originalColor[w + originalYOffset];
float alpha = outColor.a / 255.0f;
outColor.r = (byte)(alpha * (float)(outColor.r) + (float)((1.0f - alpha) * (float)inColor.r));
outColor.g = (byte)(alpha * (float)(outColor.g) + (float)((1.0f - alpha) * (float)inColor.g));
outColor.b = (byte)(alpha * (float)(outColor.b) + (float)((1.0f - alpha) * (float)inColor.b));
outColor.a = (byte)(alpha * (float)(outColor.a) + (float)((1.0f - alpha) * (float)inColor.a));
outputColor[w + outputYOffset] = outColor;
}
}
}
}
}
public static unsafe void Execute(List<PSDLayer> extractedLayer, List<BitmapLayer> layers, bool importHiddenLayer, FlattenLayerData[] previousFlattenLayer, IPSDLayerMappingStrategy mappingStrategy)
{
UnityEngine.Profiling.Profiler.BeginSample("ExtractLayer_PrepareJob");
List<LayerExtractData> layerToExtract = new List<LayerExtractData>();
ExtractLayer(extractedLayer, layers, importHiddenLayer, false, layerToExtract, previousFlattenLayer, mappingStrategy, true);
if (layerToExtract.Count == 0)
{
foreach (var l in extractedLayer)
l.texture = default;
return;
}
var job = new ConvertBufferJob();
job.original = new NativeArray<IntPtr>(extractedLayer.Count, Allocator.TempJob);
job.output = new NativeArray<IntPtr>(layerToExtract.Count, Allocator.TempJob);
job.width = new NativeArray<int>(extractedLayer.Count, Allocator.TempJob);
job.height = new NativeArray<int>(extractedLayer.Count, Allocator.TempJob);
for (int i = 0, extractLayerIndex = 0; i < extractedLayer.Count; ++i)
{
var el = extractedLayer[i];
job.original[i] = el.texture.IsCreated ? new IntPtr(el.texture.GetUnsafePtr()) : IntPtr.Zero;
if (extractLayerIndex < layerToExtract.Count && layerToExtract[extractLayerIndex].start == i)
{
el.texture = new NativeArray<Color32>(layerToExtract[extractLayerIndex].width * layerToExtract[extractLayerIndex].height, Allocator.Persistent);
job.output[extractLayerIndex] = el.texture.IsCreated ? new IntPtr(el.texture.GetUnsafePtr()) : IntPtr.Zero;
++extractLayerIndex;
}
else
{
el.texture = default;
}
job.width[i] = el.width;
job.height[i] = el.height;
}
job.flattenIndex = new NativeArray<LayerExtractData>(layerToExtract.ToArray(), Allocator.TempJob);
var jobsPerThread = layerToExtract.Count / (SystemInfo.processorCount == 0 ? 8 : SystemInfo.processorCount);
jobsPerThread = Mathf.Max(jobsPerThread, 1);
var handle = job.Schedule(layerToExtract.Count, jobsPerThread);
UnityEngine.Profiling.Profiler.EndSample();
handle.Complete();
}
static (int width, int height) ExtractLayer(List<PSDLayer> extractedLayer, List<BitmapLayer> layers, bool importHiddenLayer, bool flatten, List<LayerExtractData> layerExtract, FlattenLayerData[] previousFlatten, IPSDLayerMappingStrategy mappingStrategy, bool parentGroupVisible)
{
// parent is the previous element in extracedLayer
int parentGroupIndex = extractedLayer.Count - 1;
int maxWidth = 0, maxHeight = 0;
int width = 0, height = 0;
foreach (var l in layers)
{
bool layerVisible = l.Visible && parentGroupVisible;
if (l.IsGroup)
{
var layer = new PSDLayer(l.Surface.color, parentGroupIndex, l.IsGroup, l.Name, 0, 0, l.LayerID, l.Visible);
layer.flatten = previousFlatten == null ? false : previousFlatten.FirstOrDefault(x => mappingStrategy.Compare(x, l)) != null;
layer.isImported = (importHiddenLayer || layerVisible) && !flatten && layer.flatten;
int startIndex = extractedLayer.Count;
extractedLayer.Add(layer);
(width, height) = ExtractLayer(extractedLayer, l.ChildLayer, importHiddenLayer, flatten || layer.flatten, layerExtract, previousFlatten, mappingStrategy, layerVisible);
int endIndex = extractedLayer.Count - 1;
// If this group is to be flatten and there are flatten layers
if (flatten == false && layer.flatten && startIndex < endIndex)
{
layerExtract.Add(new LayerExtractData()
{
start = startIndex,
end = endIndex,
width = width,
height = height
});
}
}
else
{
var surface = importHiddenLayer || l.Visible ? l.Surface.color : default;
var layer = new PSDLayer(surface, parentGroupIndex, l.IsGroup, l.Name, l.Surface.width, l.Surface.height, l.LayerID,l.Visible);
layer.isImported = (importHiddenLayer || layerVisible) && !flatten;
extractedLayer.Add(layer);
if (layer.isImported)
{
layerExtract.Add(new LayerExtractData()
{
start = extractedLayer.Count-1,
end = extractedLayer.Count-1,
width = l.Surface.width,
height = l.Surface.height,
});
}
width = l.Surface.width;
height = l.Surface.height;
}
if (maxWidth < width)
maxWidth = width;
if (maxHeight < height)
maxHeight = height;
}
return (maxWidth, maxHeight);
}
}
}