diff --git a/CHANGELOG.md b/CHANGELOG.md index f8ba1da..5537bad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # Changelog +## [8.0.2] - 2022-12-01 +### Fixed +- Fixed an issue where the editor would crash when importing .psd/.psb files with their layers outside of the document canvas. (Case DANB-300) +- Fixed an issue where the amount of alpha removed from layers would not be re-applied as final position offset of the layers. +- Fixed an issue where the generated GameObjects would be laid out differently from how they appear in the DCC tool. (Case DANB-298) ## [8.0.1] - 2022-10-11 ### Fixed diff --git a/Editor/PSDImporter.cs b/Editor/PSDImporter.cs index 9a0c924..c2c0faf 100644 --- a/Editor/PSDImporter.cs +++ b/Editor/PSDImporter.cs @@ -19,7 +19,7 @@ namespace UnityEditor.U2D.PSD /// ScriptedImporter to import Photoshop files /// // Version using unity release + 5 digit padding for future upgrade. Eg 2021.2 -> 21200000 - [ScriptedImporter(22200002, new string[]{"psb"}, new []{"psd"}, AllowCaching = true)] + [ScriptedImporter(22200003, new string[]{"psb"}, new []{"psd"}, AllowCaching = true)] [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.psdimporter@latest")] [MovedFrom("UnityEditor.Experimental.AssetImporters")] public partial class PSDImporter : ScriptedImporter, ISpriteEditorDataProvider @@ -488,7 +488,7 @@ TextureGenerationOutput ImportFlattenImage(Document doc, AssetImportContext ctx, var outputImageBuffer = new NativeArray(doc.width * doc.height, Allocator.Persistent); try { - FlattenImageTask.Execute(m_ExtractData, ref outputImageBuffer, m_ImportHiddenLayers, documentSize); + FlattenImageTask.Execute(m_ExtractData, ref outputImageBuffer, m_ImportHiddenLayers, canvasSize); var spriteImportData = GetSpriteImportData(); if (spriteImportData.Count <= 0 || spriteImportData[0] == null) @@ -538,7 +538,7 @@ TextureGenerationOutput ImportFromLayers(AssetImportContext ctx) List psdLayers = null; try { - ExtractLayerTask.Execute(in m_ExtractData, out psdLayers, m_ImportHiddenLayers, documentSize); + ExtractLayerTask.Execute(in m_ExtractData, out psdLayers, m_ImportHiddenLayers, canvasSize); var mappingStrategy = GetLayerMappingStrategy(); var layerUnique = mappingStrategy.LayersUnique(psdLayers.ConvertAll(x => (IPSDLayerMappingStrategyComparable)x)); @@ -586,6 +586,10 @@ TextureGenerationOutput ImportFromLayers(AssetImportContext ctx) ImagePacker.Pack(layerBuffers.ToArray(), layerWidth.ToArray(), layerHeight.ToArray(), m_Padding, m_SpriteSizeExpand, out outputImageBuffer, out int width, out int height, out RectInt[] spriteData, out Vector2Int[] uvTransform); + var packOffsets = new Vector2[spriteData.Length]; + for (var i = 0; i < packOffsets.Length; ++i) + packOffsets[i] = new Vector2((uvTransform[i].x - spriteData[i].position.x) / -1f, (uvTransform[i].y - spriteData[i].position.y) / -1f); + var spriteImportData = GetSpriteImportData(); if (spriteImportData.Count <= 0 || shouldResliceFromLayer || hasNewLayer) { @@ -613,12 +617,11 @@ TextureGenerationOutput ImportFromLayers(AssetImportContext ctx) psdLayer.spriteName = ImportUtilities.GetUniqueSpriteName(psdLayer.name, spriteNameHash, m_KeepDupilcateSpriteName); spriteSheet.name = psdLayer.spriteName; - spriteSheet.spritePosition = psdLayer.layerPosition; + spriteSheet.spritePosition = psdLayer.layerPosition + packOffsets[i]; if(shouldResliceFromLayer) spriteSheet.rect = new Rect(spriteData[i].x, spriteData[i].y, spriteData[i].width, spriteData[i].height); - - + spriteSheet.uvTransform = uvTransform[i]; psdLayer.spriteID = spriteSheet.spriteID; @@ -688,7 +691,7 @@ TextureGenerationOutput ImportFromLayers(AssetImportContext ctx) r.height = spriteData[k].height; } spriteSheet.rect = r; - spriteSheet.spritePosition = psdLayers[i].layerPosition; + spriteSheet.spritePosition = psdLayers[i].layerPosition + packOffsets[k]; } if (spriteSheet != null) @@ -1227,7 +1230,7 @@ internal CharacterData characterData } } - internal Vector2Int documentSize => importData.documentSize; + internal Vector2Int canvasSize => importData.documentSize; SpriteLibraryAsset ProduceSpriteLibAsset(Sprite[] sprites) { diff --git a/Editor/PSDImporterDataProvider.cs b/Editor/PSDImporterDataProvider.cs index d3d95b2..40c5cd4 100644 --- a/Editor/PSDImporterDataProvider.cs +++ b/Editor/PSDImporterDataProvider.cs @@ -282,7 +282,7 @@ public CharacterData GetCharacterData() parts.Reverse(); cd.parts = parts.ToArray(); - cd.dimension = dataProvider.documentSize; + cd.dimension = dataProvider.canvasSize; cd.characterGroups = groups.ToArray(); return cd; } diff --git a/Editor/PSDLayer.cs b/Editor/PSDLayer.cs index d792cd6..3d0a5ec 100644 --- a/Editor/PSDLayer.cs +++ b/Editor/PSDLayer.cs @@ -48,6 +48,25 @@ public PSDLayer(NativeArray tex, int parent, bool group, string layerNa m_SpriteID = new GUID().ToString(); } + public PSDLayer(PSDLayer layer) + { + m_Name = layer.m_Name; + m_SpriteName = layer.m_SpriteName; + m_IsGroup = layer.m_IsGroup; + m_ParentIndex = layer.m_ParentIndex; + m_SpriteID = layer.m_SpriteID; + m_LayerID = layer.m_LayerID; + m_MosaicPosition = layer.m_MosaicPosition; + m_Flatten = layer.m_Flatten; + m_IsImported = layer.m_IsImported; + m_IsVisible = layer.m_IsVisible; + m_LayerPosition = layer.m_LayerPosition; + m_GameObject = layer.m_GameObject; + width = layer.width; + height = layer.height; + texture = layer.texture; + } + public bool isVisible => m_IsVisible; public int layerID { get { return m_LayerID; } private set { m_LayerID = value; } } diff --git a/Editor/Tasks/ExtractLayerTask.cs b/Editor/Tasks/ExtractLayerTask.cs index 88e2205..53be72b 100644 --- a/Editor/Tasks/ExtractLayerTask.cs +++ b/Editor/Tasks/ExtractLayerTask.cs @@ -20,9 +20,6 @@ struct LayerGroupData /// The layer's bounding box in document space. /// public int4 documentRect { get; set; } - - public int width => documentRect.z; - public int height => documentRect.w; } [BurstCompile] @@ -36,75 +33,87 @@ struct ConvertBufferJob : IJobParallelFor public NativeArray inputLayerRects; [ReadOnly, DeallocateOnJobCompletion] public NativeArray layerGroupDataData; - + [ReadOnly, DeallocateOnJobCompletion] - public NativeArray outputTextureSizes; + public NativeArray outputLayerRect; [DeallocateOnJobCompletion] public NativeArray outputTextures; - public unsafe void Execute(int index) + public unsafe void Execute(int groupIndex) { - var outputColor = (Color32*)outputTextures[index]; - var groupStartIndex = layerGroupDataData[index].startIndex; - var groupEndIndex = layerGroupDataData[index].endIndex; - var groupRect = layerGroupDataData[index].documentRect; - - var outWidth = outputTextureSizes[index].x; - var outHeight = outputTextureSizes[index].y; + var outputColor = (Color32*)outputTextures[groupIndex]; + var groupStartIndex = layerGroupDataData[groupIndex].startIndex; + var groupEndIndex = layerGroupDataData[groupIndex].endIndex; + + var outStartX = outputLayerRect[groupIndex].x; + var outStartY = outputLayerRect[groupIndex].y; + var outWidth = outputLayerRect[groupIndex].z; + var outHeight = outputLayerRect[groupIndex].w; - for (var i = groupEndIndex; i >= groupStartIndex; --i) + for (var layerIndex = groupEndIndex; layerIndex >= groupStartIndex; --layerIndex) { - if (inputTextures[i] == IntPtr.Zero) + if (inputTextures[layerIndex] == IntPtr.Zero) continue; - var inputColor = (Color32*)inputTextures[i]; - var inWidth = inputLayerRects[i].z; - var inHeight = inputLayerRects[i].w; - - var layerToGroupSpace = new int2(inputLayerRects[i].x - groupRect.x, inputLayerRects[i].y - groupRect.y); - // Flip Y position - layerToGroupSpace.y = outHeight - layerToGroupSpace.y - inHeight; + var inputColor = (Color32*)inputTextures[layerIndex]; + var inX = inputLayerRects[layerIndex].x; + var inY = inputLayerRects[layerIndex].y; + var inWidth = inputLayerRects[layerIndex].z; + var inHeight = inputLayerRects[layerIndex].w; for (var y = 0; y < inHeight; ++y) { - var inY = y * inWidth; - var outY = (outHeight - 1 - y - layerToGroupSpace.y) * outWidth; + var outPosY = (y + inY) - outStartY; + // If pixel is outside of output texture's Y, move to the next pixel. + if (outPosY < 0 || outPosY >= outHeight) + continue; + // Flip Y position on the input texture, because + // PSDs textures are stored "upside-down" + var inRow = ((inHeight - 1) - y) * inWidth; + var outRow = outPosY * outWidth; + for (var x = 0; x < inWidth; ++x) { - var inX = inY + x; - var outX = outY + x + layerToGroupSpace.x; - - if (inX >= inputTextureBufferSizes[i]) - break; - if (outX >= (outWidth * outHeight)) - break; + var outPosX = (x + inX) - outStartX; + // If pixel is outside of output texture's X, move to the next pixel. + if (outPosX < 0 || outPosX >= outWidth) + continue; - Color inColor = inputColor[inX]; - Color prevOutColor = outputColor[outX]; + var inBufferIndex = inRow + x; + var outBufferIndex = outRow + outPosX; + if (outBufferIndex < 0 || outBufferIndex > (outWidth * outHeight)) + continue; + + Color inColor = inputColor[inBufferIndex]; + Color prevOutColor = outputColor[outBufferIndex]; var outColor = new Color(); - + var destAlpha = prevOutColor.a * (1 - inColor.a); outColor.a = inColor.a + prevOutColor.a * (1 - inColor.a); - var premultiplyAlpha = 1 / outColor.a; + + var 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[outX] = outColor; + + outputColor[outBufferIndex] = outColor; } } } } } - public static unsafe void Execute(in PSDExtractLayerData[] inputLayers, out List outputLayers, bool importHiddenLayer, Vector2Int documentSize) + public static unsafe void Execute(in PSDExtractLayerData[] psdExtractLayerData, out List outputLayers, bool importHiddenLayer, Vector2Int canvasSize) { outputLayers = new List(); UnityEngine.Profiling.Profiler.BeginSample("ExtractLayer_PrepareJob"); + + var inputLayers = new List(); + ExtractLayerData(in psdExtractLayerData, ref inputLayers, importHiddenLayer, false, true, canvasSize); var layerGroupData = new List(); - ExtractLayer(in inputLayers, ref outputLayers, ref layerGroupData, importHiddenLayer, false, true, documentSize); - + GenerateOutputLayers(in inputLayers, ref outputLayers, ref layerGroupData, false, canvasSize); + if (layerGroupData.Count == 0) { foreach (var layer in outputLayers) @@ -113,35 +122,36 @@ public static unsafe void Execute(in PSDExtractLayerData[] inputLayers, out List } var job = new ConvertBufferJob(); - job.inputTextureBufferSizes = new NativeArray(outputLayers.Count, Allocator.TempJob); - job.inputTextures = new NativeArray(outputLayers.Count, Allocator.TempJob); - job.inputLayerRects = new NativeArray(outputLayers.Count, Allocator.TempJob); - job.outputTextureSizes = new NativeArray(layerGroupData.Count, Allocator.TempJob); + job.inputTextureBufferSizes = new NativeArray(inputLayers.Count, Allocator.TempJob); + job.inputTextures = new NativeArray(inputLayers.Count, Allocator.TempJob); + job.inputLayerRects = new NativeArray(inputLayers.Count, Allocator.TempJob); + job.outputLayerRect = new NativeArray(layerGroupData.Count, Allocator.TempJob); job.outputTextures = new NativeArray(layerGroupData.Count, Allocator.TempJob); - for (int i = 0, outputLayerIndex = 0; i < outputLayers.Count; ++i) + for (int i = 0, groupIndex = 0; i < inputLayers.Count; ++i) { + var inputLayer = inputLayers[i]; var outputLayer = outputLayers[i]; - job.inputTextures[i] = outputLayer.texture.IsCreated ? new IntPtr(outputLayer.texture.GetUnsafePtr()) : IntPtr.Zero; + job.inputTextures[i] = inputLayer.texture.IsCreated ? new IntPtr(inputLayer.texture.GetUnsafePtr()) : IntPtr.Zero; - if (outputLayerIndex < layerGroupData.Count && layerGroupData[outputLayerIndex].startIndex == i) + var isGroupOwner = groupIndex < layerGroupData.Count && layerGroupData[groupIndex].startIndex == i; + if (isGroupOwner) { - var inputLayer = layerGroupData[outputLayerIndex]; + outputLayer.texture = new NativeArray(outputLayer.width * outputLayer.height, Allocator.Persistent); - outputLayer.texture = new NativeArray(inputLayer.width * inputLayer.height, Allocator.Persistent); - job.outputTextureSizes[outputLayerIndex] = new int2(inputLayer.width, inputLayer.height); - job.outputTextures[outputLayerIndex] = outputLayer.texture.IsCreated ? new IntPtr(outputLayer.texture.GetUnsafePtr()) : IntPtr.Zero; - job.inputTextureBufferSizes[i] = outputLayer.texture.IsCreated ? outputLayer.texture.Length : -1; - ++outputLayerIndex; + job.outputLayerRect[groupIndex] = new int4((int)outputLayer.layerPosition.x, (int)outputLayer.layerPosition.y, outputLayer.width, outputLayer.height); + job.outputTextures[groupIndex] = outputLayer.texture.IsCreated ? new IntPtr(outputLayer.texture.GetUnsafePtr()) : IntPtr.Zero; + job.inputTextureBufferSizes[i] = inputLayer.texture.IsCreated ? inputLayer.texture.Length : -1; + job.inputLayerRects[i] = layerGroupData[groupIndex].documentRect; + ++groupIndex; } else { - job.inputTextureBufferSizes[i] = outputLayer.texture.IsCreated ? outputLayer.texture.Length : -1; + job.inputTextureBufferSizes[i] = inputLayer.texture.IsCreated ? inputLayer.texture.Length : -1; + job.inputLayerRects[i] = new int4((int)inputLayer.layerPosition.x, (int)inputLayer.layerPosition.y, inputLayer.width, inputLayer.height); outputLayer.texture = default; } - - job.inputLayerRects[i] = new int4((int)outputLayer.layerPosition.x, (int)outputLayer.layerPosition.y, outputLayer.width, outputLayer.height); } job.layerGroupDataData = new NativeArray(layerGroupData.ToArray(), Allocator.TempJob); @@ -152,98 +162,176 @@ public static unsafe void Execute(in PSDExtractLayerData[] inputLayers, out List handle.Complete(); } - static Rect ExtractLayer(in PSDExtractLayerData[] inputLayers, ref List outputLayers, ref List layerGroupData, bool importHiddenLayer, bool flatten, bool parentGroupVisible, Vector2Int documentSize) + static void ExtractLayerData(in PSDExtractLayerData[] inputLayers, ref List extractedLayers, bool importHiddenLayer, bool flatten, bool parentGroupVisible, Vector2Int canvasSize) { - // parent is the previous element in extractedLayer - var parentGroupIndex = outputLayers.Count - 1; - var layerBoundingBox = default(Rect); - + var parentGroupIndex = extractedLayers.Count - 1; + foreach (var inputLayer in inputLayers) { var bitmapLayer = inputLayer.bitmapLayer; var importSettings = inputLayer.importSetting; var layerVisible = bitmapLayer.Visible && parentGroupVisible; + + var layerRect = new RectInt(bitmapLayer.documentRect.X, bitmapLayer.documentRect.Y, bitmapLayer.Surface.width, bitmapLayer.Surface.height); + + if (!bitmapLayer.IsGroup) + layerRect.y = (canvasSize.y - layerRect.y - layerRect.height); - var layerRect = new Rect(float.MaxValue, float.MaxValue, 0f, 0f); - if (inputLayer.bitmapLayer.IsGroup) + NativeArray surface = default; + if ((importHiddenLayer || bitmapLayer.Visible) && + importSettings.importLayer && + bitmapLayer.Surface.color.IsCreated && + bitmapLayer.Surface.color.Length > 0) + surface = bitmapLayer.Surface.color; + + var extractedLayer = new PSDLayer(surface, parentGroupIndex, bitmapLayer.IsGroup, bitmapLayer.Name, layerRect.width, layerRect.height, bitmapLayer.LayerID, bitmapLayer.Visible) { - var outputLayer = new PSDLayer(bitmapLayer.Surface.color, parentGroupIndex, bitmapLayer.IsGroup, bitmapLayer.Name, 0, 0, bitmapLayer.LayerID, bitmapLayer.Visible) - { - layerPosition = Vector2.zero, - spriteID = inputLayer.importSetting.spriteId, - flatten = inputLayer.importSetting.flatten - }; - outputLayer.isImported = (importHiddenLayer || layerVisible) && !flatten && outputLayer.flatten && importSettings.importLayer; + spriteID = inputLayer.importSetting.spriteId, + flatten = bitmapLayer.IsGroup && inputLayer.importSetting.flatten, + layerPosition = bitmapLayer.IsGroup ? Vector2.zero : layerRect.position + }; + + extractedLayer.isImported = (importHiddenLayer || layerVisible) && !flatten && importSettings.importLayer; + if (extractedLayer.isGroup) + extractedLayer.isImported = extractedLayer.isImported && extractedLayer.flatten; + + extractedLayers.Add(extractedLayer); + + if (inputLayer.children.Length > 0) + ExtractLayerData(in inputLayer.children, ref extractedLayers, importHiddenLayer, flatten || extractedLayer.flatten, layerVisible, canvasSize); + } + } + + static void GenerateOutputLayers(in List inputLayers, ref List outputLayers, ref List layerGroupData, bool flatten, Vector2Int canvasSize) + { + var canvasRect = new RectInt(Vector2Int.zero, canvasSize); + + for (var i = 0; i < inputLayers.Count; ++i) + { + var inputLayer = inputLayers[i]; + + var outputLayer = new PSDLayer(inputLayer); + var outputRect = new RectInt((int)outputLayer.layerPosition.x, (int)outputLayer.layerPosition.y, outputLayer.width, outputLayer.height); + + if (inputLayer.isGroup) + { + var childIndices = FindAllChildrenOfParent(i, in inputLayers); + childIndices.Sort(); - var startIndex = outputLayers.Count; - outputLayers.Add(outputLayer); - layerRect = ExtractLayer(in inputLayer.children, ref outputLayers, ref layerGroupData, importHiddenLayer, flatten || outputLayer.flatten, layerVisible, documentSize); - var endIndex = outputLayers.Count - 1; + var startIndex = i; + var endIndex = i + childIndices.Count; - // If this group is to be flatten and there are flatten layers - if (flatten == false && outputLayer.flatten && startIndex < endIndex) + if (flatten == false && inputLayer.flatten && startIndex < endIndex) { + var groupBoundingBox = CalculateLayerRectInChildren(in inputLayers, in childIndices); layerGroupData.Add(new LayerGroupData() { startIndex = startIndex, endIndex = endIndex, - documentRect = new int4((int)layerRect.x, (int)layerRect.y, (int)layerRect.width, (int)layerRect.height) + documentRect = new int4(groupBoundingBox.x, groupBoundingBox.y, groupBoundingBox.width, groupBoundingBox.height) }); - outputLayer.texture = default; - outputLayer.layerPosition = new Vector2(layerRect.x, layerRect.y); - outputLayer.width = (int)layerRect.width; - outputLayer.height = (int)layerRect.height; + outputRect = groupBoundingBox; } } - else + else if(!inputLayer.isGroup && inputLayer.isImported) { - var layerRectDocSpace = bitmapLayer.documentRect; - // From Photoshop "space" into Unity "space" - layerRectDocSpace.Y = (documentSize.y - layerRectDocSpace.Y) - layerRectDocSpace.Height; - - var surface = (importHiddenLayer || bitmapLayer.Visible) && importSettings.importLayer ? bitmapLayer.Surface.color : default; - var outputLayer = new PSDLayer(surface, parentGroupIndex, bitmapLayer.IsGroup, bitmapLayer.Name, bitmapLayer.Surface.width, bitmapLayer.Surface.height, bitmapLayer.LayerID,bitmapLayer.Visible) - { - spriteID = importSettings.spriteId, - layerPosition = new Vector2(layerRectDocSpace.X, layerRectDocSpace.Y) - }; - outputLayer.isImported = (importHiddenLayer || layerVisible) && !flatten && importSettings.importLayer; - outputLayers.Add(outputLayer); - if (outputLayer.isImported) + var inputRect = new int4((int)inputLayer.layerPosition.x, (int)inputLayer.layerPosition.y, inputLayer.width, inputLayer.height); + layerGroupData.Add(new LayerGroupData() { - layerGroupData.Add(new LayerGroupData() - { - startIndex = outputLayers.Count - 1, - endIndex = outputLayers.Count - 1, - documentRect = new int4(layerRectDocSpace.X, layerRectDocSpace.Y, layerRectDocSpace.Width, layerRectDocSpace.Height) - }); - } - - layerRect.x = layerRectDocSpace.X; - layerRect.y = layerRectDocSpace.Y; - layerRect.width = bitmapLayer.Surface.width; - layerRect.height = bitmapLayer.Surface.height; + startIndex = i, + endIndex = i, + documentRect = inputRect + }); } + + CropRect(ref outputRect, canvasRect); + outputLayer.layerPosition = outputRect.position; + outputLayer.width = outputRect.width; + outputLayer.height = outputRect.height; + + outputLayers.Add(outputLayer); + } + } - if (layerBoundingBox == default) - layerBoundingBox = layerRect; - else + static List FindAllChildrenOfParent(int parentIndex, in List layers) + { + var childIndices = new List(); + for (var i = parentIndex + 1; i < layers.Count; ++i) + { + if (layers[i].parentIndex == parentIndex) { - if (layerBoundingBox.xMin > layerRect.xMin) - layerBoundingBox.xMin = layerRect.xMin; - if (layerBoundingBox.yMin > layerRect.yMin) - layerBoundingBox.yMin = layerRect.yMin; - if (layerBoundingBox.xMax < layerRect.xMax) - layerBoundingBox.xMax = layerRect.xMax; - if (layerBoundingBox.yMax < layerRect.yMax) - layerBoundingBox.yMax = layerRect.yMax; + childIndices.Add(i); + if (layers[i].isGroup) + childIndices.AddRange(FindAllChildrenOfParent(i, in layers)); } + } + return childIndices; + } + + static RectInt CalculateLayerRectInChildren(in List inputLayers, in List childIndices) + { + var groupBoundingBox = default(RectInt); + for (var m = 0; m < childIndices.Count; ++m) + { + var childLayer = inputLayers[childIndices[m]]; + if (childLayer.isGroup) + continue; + + var layerRect = new RectInt((int) childLayer.layerPosition.x, (int) childLayer.layerPosition.y, + childLayer.width, childLayer.height); + if (IsRectIntDefault(groupBoundingBox)) + groupBoundingBox = layerRect; + else + FitRectInsideRect(ref groupBoundingBox, in layerRect); + } + + return groupBoundingBox; + } + + static bool IsRectIntDefault(RectInt rectInt) + { + return rectInt.x == 0 && + rectInt.y == 0 && + rectInt.width == 0 && + rectInt.height == 0; + } - layerBoundingBox.width = Mathf.Min(layerBoundingBox.width, documentSize.x); - layerBoundingBox.height = Mathf.Min(layerBoundingBox.height, documentSize.y); + static void CropRect(ref RectInt baseRect, in RectInt cropArea) + { + if (baseRect.x < cropArea.x) + { + baseRect.width = Mathf.Max(baseRect.width - (cropArea.x - baseRect.x), 0); + baseRect.x = cropArea.x; } - return layerBoundingBox; + if (baseRect.xMax > cropArea.xMax) + { + baseRect.x = Mathf.Min(baseRect.x, cropArea.xMax); + baseRect.width = Mathf.Max(cropArea.xMax - baseRect.x, 0); + } + + if (baseRect.y < cropArea.y) + { + baseRect.height = Mathf.Max(baseRect.height - (cropArea.y - baseRect.y), 0); + baseRect.y = cropArea.y; + } + if (baseRect.yMax > cropArea.yMax) + { + baseRect.y = Mathf.Min(baseRect.y, cropArea.yMax); + baseRect.height = Mathf.Max(cropArea.yMax - baseRect.y, 0); + } + } + + static void FitRectInsideRect(ref RectInt baseRect, in RectInt rectToFitIn) + { + if (baseRect.xMin > rectToFitIn.xMin) + baseRect.xMin = rectToFitIn.xMin; + if (baseRect.yMin > rectToFitIn.yMin) + baseRect.yMin = rectToFitIn.yMin; + if (baseRect.xMax < rectToFitIn.xMax) + baseRect.xMax = rectToFitIn.xMax; + if (baseRect.yMax < rectToFitIn.yMax) + baseRect.yMax = rectToFitIn.yMax; } } } diff --git a/Editor/Tasks/FlattenImageTask.cs b/Editor/Tasks/FlattenImageTask.cs index a051134..c6c73c9 100644 --- a/Editor/Tasks/FlattenImageTask.cs +++ b/Editor/Tasks/FlattenImageTask.cs @@ -72,7 +72,7 @@ public static unsafe void Execute(in PSDExtractLayerData[] layer, ref NativeArra var handle = job.Schedule(jobCount, 1); combineJob.Schedule(1, 1, handle).Complete(); - + foreach (var b in premergedBuffer) { if (b.IsCreated) @@ -133,8 +133,8 @@ public unsafe void Execute(int index) break; var inputColor = (Color32*)inputTextures[layerIndex].ToPointer(); - var inPosX = inputTextureRects[layerIndex].x; - var inPosY = inputTextureRects[layerIndex].y; + var inStartPosX = inputTextureRects[layerIndex].x; + var inStartPosY = inputTextureRects[layerIndex].y; var inWidth = inputTextureRects[layerIndex].z; var inHeight = inputTextureRects[layerIndex].w; @@ -143,26 +143,37 @@ public unsafe void Execute(int index) for (var y = 0; y < inHeight; ++y) { - var inY = y * inWidth; - var outY = flipY ? (outHeight - 1 - y - inPosY) * outWidth : (y + inPosY) * outWidth; + var outPosY = y + inStartPosY; + // If pixel is outside of output texture's Y, move to the next pixel. + if (outPosY < 0 || outPosY >= outHeight) + continue; + var inRow = y * inWidth; + var outRow = flipY ? (outHeight - 1 - y - inStartPosY) * outWidth : (y + inStartPosY) * outWidth; + for (var x = 0; x < inWidth; ++x) { - var inX = inY + x; - var outX = outY + x + inPosX; - - Color inColor = inputColor[inX]; - Color prevOutColor = outputColor[outX]; + var outPosX = x + inStartPosX; + // If pixel is outside of output texture's X, move to the next pixel. + if (outPosX < 0 || outPosX >= outWidth) + continue; + + var inBufferIndex = inRow + x; + var outBufferIndex = outRow + outPosX; + + Color inColor = inputColor[inBufferIndex]; + Color prevOutColor = outputColor[outBufferIndex]; var outColor = new Color(); var destAlpha = prevOutColor.a * (1 - inColor.a); outColor.a = inColor.a + prevOutColor.a * (1 - inColor.a); - var premultiplyAlpha = 1 / outColor.a; + + var 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[outX] = outColor; + outputColor[outBufferIndex] = outColor; } } } diff --git a/package.json b/package.json index 0db070f..b5b672c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.unity.2d.psdimporter", - "version": "8.0.1", + "version": "8.0.2", "unity": "2022.2", "displayName": "2D PSD Importer", "description": "A ScriptedImporter for importing Adobe Photoshop PSB (Photoshop Big) file format. The ScriptedImporter is currently targeted for users who wants to create multi Sprite character animation using Unity 2D Animation Package.", @@ -16,14 +16,18 @@ "com.unity.2d.sprite": "1.0.0" }, "relatedPackages": { - "com.unity.2d.psdimporter.tests": "8.0.1" + "com.unity.2d.psdimporter.tests": "8.0.2" + }, + "_upm": { + "changelog": "### Fixed\n- Fixed an issue where the editor would crash when importing .psd/.psb files with their layers outside of the document canvas. (Case DANB-300)\n- Fixed an issue where the amount of alpha removed from layers would not be re-applied as final position offset of the layers.\n- Fixed an issue where the generated GameObjects would be laid out differently from how they appear in the DCC tool. (Case DANB-298)" }, "upmCi": { - "footprint": "416b3e291d020809bbacb36c154fb901e9b28821" + "footprint": "8ef88654f594021fbcd7ef795e2659378442556f" }, + "documentationUrl": "https://docs.unity3d.com/Packages/com.unity.2d.psdimporter@8.0/manual/index.html", "repository": { "url": "https://github.cds.internal.unity3d.com/unity/2d.git", "type": "git", - "revision": "6fc635d83d4bb0b2640893b8d4a0f3934044aeb5" + "revision": "fc4212736e8bcb753039f1a18964b98d929e4093" } }