diff --git a/CHANGELOG.md b/CHANGELOG.md index 93afa93..5409c4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [6.0.0-pre.4] - 2021-07-05 +### Fixed +- Fixed changing PSD Importer inspector fields causes UnityEditor.ObjectPreview errors (case 1333823) +- Fixed 2D PSDImporter always imports .psb files when switching build platforms (case 1327701) +- Fixed 2D PSDImporter doesn't apply settings from Sprite Editor Window when changes made in Inspector (case 1339799) + ## [6.0.0-pre.3] - 2021-05-17 ### Changed - Update dependency version @@ -8,6 +14,7 @@ ### Changed - Update dependency version + ## [6.0.0-pre.1] - 2021-05-05 ### Changed - Version bump for Unity 2021.2 diff --git a/Documentation~/PSD-importer-SpriteRect.md b/Documentation~/PSD-importer-SpriteRect.md index 1828e86..4835271 100644 --- a/Documentation~/PSD-importer-SpriteRect.md +++ b/Documentation~/PSD-importer-SpriteRect.md @@ -1,15 +1,15 @@ # How the PSD Importer uses SpriteRect data -The PSD Importer can store five separate sets of[ SpriteRect](https://docs.unity3d.com/ScriptReference/Sprite-rect.html) data, with one set for each of the five combinations of Importer property settings below: - 1. When [**Sprite Mode**](PSD-importer-properties.md#SpriteMode) is set to **Single**. +The PSD Importer can store five separate sets of[ SpriteRect](https://docs.unity3d.com/Packages/com.unity.2d.sprite@1.0/api/UnityEditor.SpriteRect.html) data, with one set for each of the five combinations of Importer property settings below: + 1. When [Sprite Mode](PSD-importer-properties.html#SpriteMode) is set to **Single**. 2. When **Sprite Mode** is set to **Multiple**. - 3. When **Sprite Mode** is set to **Multiple,** and [**Mosaic**](PSD-importer-properties.md#Mosaic) is enabled. - 4. When **Sprite Mode** is set to **Multiple**, both **Mosaic** and [**Character Rig**](PSD-importer-properties.md#character-rig) are enabled, and there is no [Skeleton Asset](PSD-importer-properties.md#main-skeleton) assigned as the [**Main Skeleton**](PSD-importer-properties.md#main-skeleton). - 5. When **Sprite Mode** is set to **Multiple**, both **Mosaic** and **Character Rig** are enabled, and a Skeleton Asset is assigned as the **Main Skeleton**. + 3. When **Sprite Mode** is set to **Multiple,** and [Individual Sprites (Mosaic)](PSD-importer-properties.html#Mosaic) is enabled. + 4. When **Sprite Mode** is set to **Multiple**, both **Individual Sprites (Mosaic)** and [Use as Rig](PSD-importer-properties.html#use-as-rig) are enabled, and there is no [Skeleton Asset](PSD-importer-properties.html#main-skeleton) assigned as the [Main Skeleton](PSD-importer-properties.html#main-skeleton). + 5. When **Sprite Mode** is set to **Multiple**, both **Individual Sprites (Mosaic)** and **Use as Rig** are enabled, and a Skeleton Asset is assigned as the **Main Skeleton**. Each set of data is persistent, and does not affect or overwrite the data of other sets. This means you can save different SpriteRect data for different importer settings for the same source file. The SpriteRect data persists even if you modify the dimensions and position of images in the source file, as long as the original [Layer ID](https://github.com/adobe-photoshop/generator-core/wiki/Understanding-Layer-IDs-and-Layer-Indices) of the source layers remains the same. -## Modifying the SpriteRect data -The SpriteRect defines the location of the Sprite on the Texture that Unity generates from the imported source file. You can modify the location and size of each SpriteRect in the Sprite Editor. SpriteRect data persists until you manually delete the SpriteRect, or select the **Reslice** option and apply it in the importer settings. When you do this, Unity discards all user modifications for the current set of SpriteRect data and regenerates all the SpriteRects from the current source file. +## Modifying SpriteRect data +The SpriteRect defines the location of the Sprite on the Texture that Unity generates from the imported source file. You can modify the location and size of each SpriteRect in the Sprite Editor. ### Moving the SpriteRect @@ -24,20 +24,20 @@ A SpriteRect’s modified dimensions and location on the Texture is reflected fo | Original character prefab and its ‘head’ Sprite with unmodified SpriteRect data. | Character prefab with its ‘head’ Sprite’s SpriteRect data modified.| ### SpriteRect follows the position of its source layer -When you enable the [Mosaic](PSD-importer-properties.md#Mosaic) importer setting, the PSD Importer arranges the different layers of the source file together to form a single combined Texture when you import it. The importer generates a SpriteRect for each of these imported layers, and follows the position of its associated layer wherever it is placed in the Mosaic Texture. +When you enable the [Individual Sprites (Mosaic)](PSD-importer-properties.html#IndiSpriteMosaic) importer setting, the PSD Importer arranges the different layers of the source file together to form a single combined Texture when it is imported. The importer generates a SpriteRect for each of these imported layers which follows the position of its associated layer wherever that layer is placed in the combined Mosaic Texture. ![](images/21_2-Fei-SpriteRect-head-moved.png)
Before example: The SpriteRect of the ‘head’ layer after moving its SpriteRect from its original position. -![](images/21_2-Fei-SpriteRect-head-moved-hidden.png)
After hiding some of the layers in the source file and reimporting it, the resulting Mosaic Texture is different from the original. However, the SpriteRect follows the ‘head’ layer’s placement in the new Texture. +![](images/21_2-Fei-SpriteRect-head-moved-hidden.png)
After example: Some of the layers are hidden in the source file before it is reimported into the Editor. The reimported Texture is different from the original, but the 'head' layer's SpriteRect follows its source layer to its placement in the new Texture. ### Resizing the source file or image -A SpriteRect’s size and position remains the same if you change the image or canvas size of its source layer in the source file. You must manually edit the size and position of the SpriteRect in the Sprite Editor, or select and apply the [Reslice](PSD-importer-properties.md#reslice) option to regenerate the SpriteRect completely from the source file. +Note that a SpriteRect’s size and position remains the same if you change the image or canvas size of its source layer in the source file. You must manually edit the size and position of the SpriteRect in the Sprite Editor, or select and apply the [Automatic Reslice](PSD-importer-properties.html#automatic-reslice) option to regenerate the SpriteRect completely from the source file. ![](images/21_2-Fei-SpriteRect-head-original.png)
Before example: Original position and size of the SpriteRect for the generated ‘head’ Sprite from the 'head' layer. ![](images/21_2-Fei-SpriteRect-head-resized.png)
After example: After increasing the size of the 'head' layer, the SpriteRect's position and size remains the same. -SpriteRect data persists until you manually delete the SpriteRect, or select the **Reslice** option and apply it in the importer settings. When you do this, Unity discards all user modifications for the current set of SpriteRect data and regenerates all the SpriteRects from the current source file. +SpriteRect data persists until you manually delete the SpriteRect, or select the **Automatic Reslice** option and apply it in the importer settings. When you do this, Unity discards all user modifications for the current set of SpriteRect data and regenerates all the SpriteRects from the current source file. ## Summary of source file modifications and their effects on SpriteRect data | __Modification to the source file__ | __Effect on SpriteRect data__ | @@ -45,7 +45,7 @@ SpriteRect data persists until you manually delete the SpriteRect, or select the | __Add a new layer or enable layer visibility__ | The PSD importer automatically generates a new Sprite from the new layer, or newly visible layer, with its associated SpriteRect. | | __Delete a layer or disable layer visibility__ | The PSD Importer deletes the associated Sprite and SpriteRect from the Project file. | | __Rename a layer__ | By default, the SpriteRect copies the new name of its source layer. However if you rename the SpriteRect in the Sprite Editor, then it retains its modified name and does not copy the source layer’s new name. | -| __Change a layer or canvas size__ | When a source layer's size changes, the size and position of its related SpriteRect remain the same and do not reflect the changes made to its source layer.
To make the SpriteRect reflect the changes made to its source layer, manually edit the SpriteRect’s dimensions in the Sprite Editor, or go to the PSD Importer settings and select and apply the [Reslice](#Reslice) option. | +| __Change a layer or canvas size__ | When a source layer's size changes, the size and position of its related SpriteRect remain the same and do not reflect the changes made to its source layer.
To make the SpriteRect reflect the changes made to its source layer, manually edit the SpriteRect’s dimensions in the Sprite Editor, or go to the PSD Importer settings and select and apply the **Automatic Reslice** option. | ## Name collision errors diff --git a/Documentation~/PSD-importer-properties.md b/Documentation~/PSD-importer-properties.md index 7240a31..1cc3760 100644 --- a/Documentation~/PSD-importer-properties.md +++ b/Documentation~/PSD-importer-properties.md @@ -1,54 +1,135 @@ # PSD Importer Inspector properties -The PSD Importer is available after you import a .psb file into your Project. Select the .psb Asset file and set its **Texture Type** to [Sprite (2D and UI)](https://docs.unity3d.com/Manual/TextureTypes.html#Sprite). The following PSD Importer properties become available in the Inspector window. +The PSD Importer is available after you import a .psb file into your Project. Select the .psb Asset file and set its **Texture Type** to [Sprite (2D and UI)](https://docs.unity3d.com/Manual/TextureTypes.html#Sprite). The PSD Importer properties are split between two main tabs, with the following properties available. -![](images/21_2-PSDImporter-properties.png)
PSD Importer Inspector properties +![](images/psdimporter-properties-v6-21.2.png)
PSD Importer Inspector properties +## Settings tab +The Settings tab allows you to customize how the PSD Importer imports a file. The settings are categorized into individual section fold-outs. + +### General +![](images/psdimporter-properties-v6-21.2-general.png) | Property | Function | | ------------------------------------------------------------ | ------------------------------------------------------------ | -| __Texture Type__ | Select [Sprite (2D and UI)](https://docs.unity3d.com/Manual/TextureTypes.html#Sprite) to import the Texture as a [Sprite](https://docs.unity3d.com/Manual/Sprites.html). This is necessary to begin using the imported images with the [2D Animation](https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/) package. | -| __Sprite Mode__ | Use this property to specify how Unity extracts the Sprite graphic from the image. This property is set to __Multiple__ by default. | -|     Single | Select **Single** to have Unity treat the imported texture as a single Sprite Asset without multiple individual parts. This is ideal for characters that are a single layer in the source .psb file, which are not split into multiple layers. | -|     Multiple |If the imported texture has multiple parts, select **Multiple** to have Unity create a Sprite for each layer. This is ideal for complex characters which have different parts split between multiple layers in the source .psb file, because it prepares the characters for animation with the [2D Animation](https://docs.unity3d.com/Packages/com.unity.2d.animation@latest) package. | -| __Pixels Per Unit__ | Set the number of pixels that equal to one Unity unit. | -| __Mesh Type__ | Set the Mesh type that Unity generates for the Sprite. This is set to __Tight__ by default. | -|     [Full Rect](https://docs.unity3d.com/Documentation/ScriptReference/SpriteMeshType.FullRect.html) | Unity maps the Sprite onto a rectangular Mesh. | -|     [Tight](https://docs.unity3d.com/Documentation/ScriptReference/SpriteMeshType.Tight.html) | Unity generates a Mesh based on the outline of the Sprite. If the Sprite is smaller than 32 x 32 pixels, Unity always maps it onto a __Full Rect__ quad Mesh, even if you select __Tight__. | -| [__Extrude Edges__](https://docs.unity3d.com/Manual/Glossary.html#ExtrudeEdges) | Use the slider to determine how much to extend the Mesh from the edge of the Sprite. | -| __Import Hidden__ | Enable this property to include the hidden [layers](https://helpx.adobe.com/photoshop/using/layer-basics.html#layers_panel_overview) of the .psb file in the import. This is the equivalent of making all layers visible in the source file before it is imported into Unity. Disable this property if you want to only import the visible layers in the .psb file. | -| __Mosaic__ |Enable this property to make the PSD Importer generate Sprites from the imported layers and combine them into a single Texture in a Sprite sheet layout.
This setting is only available if you set the **Texture Type** to **Multiple**. | | | -| __Character Rig__ | Enable this property to make the importer generate a [Prefab](https://docs.unity3d.com/Manual/Prefabs.html) based on the imported source file. The PSD Importer generates Sprites from the imported layers of the source file, and the Sprites’ [hierarchy](https://docs.unity3d.com/Manual/Hierarchy.html) and positions are based on their [layer hierarchy](https://helpx.adobe.com/photoshop/using/layer-basics.html#layers_panel_overview) and their positions in the .psb file.
For more details, see [Property details: Character Rig](#character-rig), below. | -| __Use Layer Grouping__ | Enable this setting to make the importer generate a Prefab that follows the layer and grouping hierarchy of the imported .psb file.
This setting is only available when you enable **Character Rig**. | -| __Pivot__ |Select the pivot point of the Sprite.
This is only available when **Character Rig** is enabled. | -|      Custom | Define the X and Y coordinates of a custom __Pivot__ location. | -| __Main Skeleton__ | Assign the [Skeleton Asset](#main-skeleton) that this character Prefab’s bone hierarchy should reference.
If no Skeleton Asset is assigned, the importer automatically generates a Skeleton Asset as a sub-asset of this character. The Skeleton Asset contains the bone hierarchy of the Asset defined in the [Skinning Module]() (see [Skeleton Sharing](skeleton-sharing.md) for more information about using Skeleton Assets).
This property is only available when Character Rig is enabled.
For more details, see [Property details: Main Skeleton](#main-skeleton), below. | -| __Reslice__ |Enable this setting to regenerate the Sprite from the imported layers and clear any changes you have made to the Sprite and its metadata.
This is available only when Mosaic is enabled.
For more details, see [Property details: Reslice](#reslice) below. | -| __Keep Duplicate Name__ | Enable this setting to make the PSD Importer generate Sprites from the source files with the exact same name as their source layers, even when there are multiple layers with the same name.
For more details, see [Property details: Keep Duplicate Name](#keep-duplicate-name) below.| +| __Texture Type__ | Select [Sprite (2D and UI)](https://docs.unity3d.com/Manual/TextureTypes.html#Sprite) to import the Texture as a [Sprite](https://docs.unity3d.com/Manual/Sprites.html). The is required to begin using the imported Texture with the [2D Animation](https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/) package. | + +###Sprite +![](images/psdimporter-properties-v6-21.2-sprite.png) +Property |Function +--|-- +**Sprite Mode** | Use this property to specify how Unity extracts the Sprite graphic from the image. This property is set to __Multiple__ by default. +  Single |Select this option to have Unity treat the imported Texture as a single Sprite Asset without multiple individual parts. This is ideal for characters which are drawn on a single layer in the source file instead of being split onto multiple layers. +  Multiple |This is the default option. Select this option to have Unity create a Sprite for each layer in the source file. This is ideal for complex artwork which has different parts split between multiple layers in the source file, and prepares the imported Textures for animation with the [2D Animation](https://docs.unity3d.com/Packages/com.unity.2d.animation@latest) package. +|**Pixels Per Unit** | Sets the number of pixels that equal to one Unity unit. +| __Mesh Type__ | Sets the Mesh type that Unity generates for the Sprite. This is set to __Tight__ by default. +|  [Full Rect](https://docs.unity3d.com/Documentation/ScriptReference/SpriteMeshType.FullRect.html) | Unity maps the Sprite onto a rectangular Mesh. +|  [Tight](https://docs.unity3d.com/Documentation/ScriptReference/SpriteMeshType.Tight.html) | Unity generates a Mesh based on the outline of the Sprite. If the Sprite is smaller than 32 x 32 pixels, Unity always maps it onto a **Full Rect** quad Mesh, even if you select **Tight**. | +[Extrude Edges](https://docs.unity3d.com/Manual/Glossary.html#ExtrudeEdges) | Use the slider to determine how much to extend the Mesh from the edge of the Sprite. | +**Generate Physics Shape**| Enable this option to generate a default [Physics Shape](https://docs.unity3d.com/2017.4/Documentation/Manual/SpritePhysicsShapeEditor.html) from the outline of the Sprite, if a [Custom Physics Shape](https://docs.unity3d.com/Manual/CustomPhysicsShape.html) has not be defined. | +[Automatic Reslice](#automatic-reslice) | This is available only when the **Import Mode** is set to [Individual Sprites (Mosaic)](#Mosaic). Enable this setting to regenerate the Sprite from the imported layers and clear any changes you have made to the Sprite and its metadata. | + +####Automatic Reslice +Enable this setting to discard all user modifications for the current set of [SpriteRect](https://docs.unity3d.com/Packages/com.unity.2d.sprite@1.0/api/UnityEditor.SpriteRect.html) data and regenerate all SpriteRects based on the current source file. Extra SpriteRect metadata (such as weights and bones data) persist if they remain valid with the regenerated SpriteRects. + +###Layer Import +The following section is only available if the **Texture Type** is set to **Multiple**. +![](images/psdimporter-properties-v6-21.2-layerimport.png) +Property |Function +--|-- +**Import Mode** | Use this property to specify how the layers from the source file are imported. This property is set to **Individual Sprites (Mosaic)** by default. +  [Individual Sprites (Mosaic)](#Mosaic)|Select this option to have the PSD Importer generate individual Sprites from the individual layers of the source file, and combines them into a single Texture in a Sprite sheet layout. +  [Merged](#merged) | Select this to have the PSD Importer generate a Texture with all layers merged. +**Layer Name** |This setting is only available if you set the **Import Mode** to **Individual Sprites (Mosaic)**. Use this property to specify how the importer handles layer names when duplicated layer names are found. This property is set to **Keep Duplicate Names** by default. +  [Keep Duplicate Names](#keep-duplicate-names) | Select this to have the PSD Importer generate Sprites from the source files with the exact same name as their source layers, even when there are multiple layers with the same name. +  Resolve Duplicate Names | Select this to have the PSD Importer generate Sprites from the source files with the same name as their source layers. If there are multiple layers with the same name, the Sprite’s name will be prefixed with a number. +**Layer** |This setting is only available if you set the **Import Mode** to **Individual Sprites (Mosaic)**.
Use this property to specify how the importer handles layer’s that are set to not visible in the source file. This property is set to **Visible Layers Only** by default. | +  Visible Layers Only |Select this to only import the visible layers from the source file. +  Include Hidden Layers |Select this to include the hidden layers of the source file in the import. This produces the same import result as making all layers visible in the source file before you import it into Unity. | +**Layer Mapping ID**| Select this option to use the internal ID provided by the .psb file to map between the .psb file’s layer and the generated Sprite.| +  Use Layer ID |Select this to only import the visible layers in the .psb file. | +  Use Layer Name| Select this option to use the name of the layer in the .psb file to map between the .psb file’s layer and the generated Sprite. Note that for this option to work correctly, each layer's name needs to be unique. Duplicated names might cause layers to be mapped to the wrong Sprite.| +  Use Layer Name (Case Sensitive) | Select this option to use the name of the layer (with case sensitivity) in the .psb file to map between the .psb file’s layer and the generated Sprite. Note that for this option to work correctly, each layer's name needs to be unique. Duplicated names might cause layers to be mapped to the wrong Sprite. | +[Layer Group](#layer-group) |Use this property to specify how the importer handles the Layer group from the source file.
This setting is only available when you enable **Use as Rig** and set the **Import Mode** to **Individual Sprites (Mosaic)**. | +  Ignore Layer Groups |Select this option to have the generated Prefab contain only Layers from the source file while ignoring Layer Groups. | +  As Per Source File |Select this option to make the importer generate a Prefab that follows the layer and grouping hierarchy of the imported .psb. | + +####Individual Sprites (Mosaic) +Enable this to have the PSD Importer attempt to create a Texture with each layer from the source file laid out in a mosaic manner. +![](images/PhotoshopSetup.png)
The character artwork in Photoshop. +![](images/individual-sprites-mosaic-21.2.png)
The same file with its individual layers imported as separate Sprites merged into a single Texture in a mosaic formation. + +####Merged +Enable this option to have the PSD Importer create a Texture with the layers from the Photoshop file as if all [layers are flattened](https://helpx.adobe.com/photoshop/using/layers.html). +![](images/merged-layers-21.2.png) + +####Keep Duplicate Names +Unity's default import behavior when there are duplicate names is to append "_[number]" to the Sprites and SpriteRects it generates from source layers with identical names. Enable this feature to instead have Unity give both Sprites and SpriteRects the exact same name as their source layer, even when they have duplicate names. + +####Layer Group +Refer to the following examples of a character designed in Photoshop and how its original layer hierarchy is transposed to the Prefab generated by the PSD Importer. +![](images/PhotoshopSetup.png)
Example 1: Character artwork in Photoshop with different parts separated into different Photoshop layers. The following examples are generated from this source file. + +![](images/ignore-layer-groups-21.2.png)
Example 2:The generated Prefab with **Layer Group** set to **Ignore Layer Groups**. + +![](images/as-per-source-21.2.png)
Example 3: The generated Prefab of the same source file with **Layer Group** set to **As Per Source File**. + +###Character Rig +This section is only available if the **Texture Type** is set to **Multiple** and **Import Mode** is set to **Individual Sprites (Mosaic)**. +![](images/character-rig-21.2.png) +Property |Function +--|-- +[Use as Rig](#use-as-rig) | Enable this property to have the PSD Importer generate a Prefab based on the imported source file. The PSD Importer generates Sprites from the imported layers of the source file, and the Sprites’ [hierarchy](https://docs.unity3d.com/Manual/Hierarchy.html) and positions are based on their [layer hierarchy](https://helpx.adobe.com/photoshop/using/layer-basics.html#layers_panel_overview) and their positions in the source file. +[Main Skeleton](#main-skeleton) | This is only available when [Use as Rig](#use-as-rig) is enabled. Assign the **Skeleton Asset** that this character Prefab’s bone hierarchy will reference.
If no Skeleton Asset is assigned, the importer will automatically generate a Skeleton Asset as a sub-asset of this character. The Skeleton Asset contains the bone hierarchy of the Asset that was defined in the 2D Animation package's [Skinning Editor](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/SkinningEditor.html) (refer to **Skeleton Sharing** for more information). +**Pivot** |This is only available when **Use as Rig** is enabled. Select the pivot point of the Sprite. +  Custom | Define the X and Y coordinates of a custom **Pivot** location.| + +####Use as Rig +Enable this property to have the PSD Importer generate a Prefab containing Sprites based on the layers of the imported source file. The PSD Importer also automatically gives the Sprites an [Order in Layer](https://docs.unity3d.com/Manual/2DSorting.html#sortlayer) value that sorts them according to their positions in the layer hierarchy in the source file. As a result, the generated Prefab recreates the arrangement and appearance of the assets in the original source file as closely as possible. + +The name of each Sprite in the Prefab is the same as the source layer it is based on, unless a **name collision error** occurs, which is usually due to duplicate names in the source layers. + +If the Sprite contains [bone](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/SkinEdToolsShortcuts.html#bone-tools) or [weight](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/SkinEdToolsShortcuts.html#weight-tools) data, the PSD Importer automatically adds the Sprite Skin component to it. This happens if the Sprite has been [rigged](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/CharacterRig.html) with bones and weights in the [Skinning Editor](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/SkinningEditor.html) already and the source file is being reimported, or you have manually [copied and pasted](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/CopyPasteSkele.html) the bone and weight data onto the Sprites. + +####Main Skeleton +A skeleton Asset (.skeleton) is an Asset that contains the bone hierarchy structure that can be animated with the 2D Animation package. The **Main Skeleton** property is only available when you import a .psb file with the **Use As Rig** importer setting enabled. After importing the .psb file, assign a .skeleton Asset to the **Main Skeleton** property to have the generated prefab character be automatically rigged with the bone hierarchy structure contained in that .skeleton Asset. + +If there is no .skeleton Asset assigned to the importer’s **Main Skeleton** property, then a .skeleton Asset is automatically generated as a sub-Asset of the imported source file and it will be named ‘[Asset File Name] Skeleton’. You can **share .skeleton Assets** between different generated Prefabs by assigning the same .skeleton as their **Main Skeleton** property when they're imported. -## Property details -### Character Rig -When **Character Rig** is enabled, the PSD Importer generates a Prefab that contains [Sprites](https://docs.unity3d.com/Manual/Sprites.html) based on the layers of the imported source file. The PSD Importer also automatically gives the Sprites an [Order in Layer](https://docs.unity3d.com/Manual/2DSorting.html#sortlayer) value that sorts them according to their positions in the layer hierarchy in the source file. As a result, the generated Prefab recreates the arrangement and appearance of the assets in the original source file as closely as possible. +When you open and edit the character in 2D Animation package’s **Skinning Editor**, the module will display the bone hierarchy provided by the Skeleton Asset assigned to **Main Skeleton** for rigging. -The name of each Sprite in the Prefab is the same as the source layer it is based on, unless a [name collision error](PSD-importer-SpriteRect.md#name-collision-errors) occurs, which is usually due to duplicate names in the source layers. +## Layer Management Tab +The **Layer Management Tab** allows you to customize how the Importer imports the layers from the Photoshop file. +![](images/layer-management-tab-21.2.png) -If the Sprite contains [bone](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/SkinEdToolsShortcuts.html#bone-tools) or [weight](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/SkinEdToolsShortcuts.html#weight-tools) data, the PSD Importer automatically adds the __Sprite Skin__ component to it. This happens if the Sprite is already [rigged](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/CharacterRig.html) with bones and weights in the [Skinning Editor](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/SkinningEditor.html) already and you are reimporting the source file, or if you have manually [copied and pasted](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/CopyPasteSkele.html) the bone and weight data onto the Sprites. +###Layer hierarchy tree +[Group layers](https://helpx.adobe.com/photoshop/using/selecting-grouping-linking-layers.html) in Photoshop are represented with a fold-out folder icon ![](images/group-layers-icon.png) in the hierarchy tree of the Layer Management tab, while regular Photoshop layers in Photoshop represented only by their names. -The examples below demonstrate a character designed in Photoshop, and how its original layer hierarchy is transposed to the Prefab. +###Collapsing Groups +The Photoshop layers in a Group can be collapsed into a single Sprite when imported. Hover the cursor over a Group Layer and the **Collapse** icon appears on its left. +![](images/layer-tab-collapse-21.2.png)
Collapse icon with arrow facing down. -![](images/PhotoshopSetup.png)
Example 1: Character artwork in Photoshop with different parts separated into different Photoshop layers. +Click the icon to indicate that the layers in the selected Group should be imported as a single Sprite. +![](images/layer-tab-collapse-dim-21.2.png)
Layers in Collapsed groups are grayed out. -![](images/21_2-Fei-nogrouping.png)
Example 2: The generated Prefab with Sprites sorted according to the source file’s layer hierarchy. +###Uncollapsing Groups +Hovering over a Collapsed Group layer reveals the Uncollapse icon (the arrow faces upwards). -![](images/21_2-Fei-grouping-layers.png)
Example 3: The generated Prefab of the same source file but with [Layer Grouping](#LayerGrouping) enabled. +![](images/layer-tab-uncollapse-21.2.png)
Select the icon again to uncollapse the Group layer and to import all Layers in the Group as separate Sprites. -### Main Skeleton -A skeleton Asset (.skeleton) is an Asset that contains the bone hierarchy structure that you can animate with the 2D Animation package. The **Main Skeleton** property is only available when you import a .psb file with the [**Character Rig**](#character-rig) importer setting enabled. After importing the .psb file, assign a .skeleton Asset to the **Main Skeleton** property to have Unity automatically rig generated prefab character with the bone hierarchy structure contained in that .skeleton Asset. +####Sub-groups within Group layers +If a Group contains other Group layers and is collapsed, then the layers in the sub-groups will also be collapsed into a single Sprite. +![](images/layer-tab-subgroup-collapse-21.2.png)
Group 1 containing multiple sub-groups. +![](images/layer-tab-subgroup-uncollapse-21.2.png)
All layers in the sub-groups are grayed out when the parent Group 1 is set to Collapse. -If no Skeleton Asset is assigned to the importer’s **Main Skeleton** property, then Unity automatically generates a Skeleton Asset as a sub-asset of the imported source file and it will be named ‘[Asset File Name] Skeleton’. You can [share .skeleton Assets](skeleton-sharing.md) between different generated Prefabs; to do this, assign the same .skeleton as their **Main Skeleton** property when they're imported. +![](images/layer-tab-subgroup-child-collapse-21.2.png) +If a child Group is currently set to be collapsed, then the parent group will have separate icons indicating that are child Groups currently set to collapse. -When you open and edit the character in 2D Animation package’s [Skinning Editor](https://docs.unity3d.com/Packages/com.unity.2d.animation@6.0/manual/SkinningEditor.html), the module displays the bone hierarchy provided by the Skeleton Asset assigned to **Main Skeleton** for rigging. +###Layer visibility +Setting the **Layer** option in the [Settings Tab](#settings-tab) to **Visible Layers Only** causes only visible layers from the source file to be displayed in the **Layer Management Tab**. +![](images/layer-visibility-21.2.png) +![](images/layer-visibility-tree-21.2.png) -### Reslice -Enable this setting to discard all user modifications for the current set of [`SpriteRect`](https://docs.unity3d.com/Packages/com.unity.2d.sprite@1.0/api/UnityEditor.SpriteRect.html) data and regenerate all `SpriteRects` based on the current source file. Extra `SpriteRect` metadata (such as weights and bones data) persist if they remain valid with the regenerated `SpriteRects`. +Set the Layer option to **Include Hidden Layers** to also display any hidden layers from the source file in the **Layer Management Tab.** +![](images/layer-visibility-hidden-21.2.png) -### Keep Duplicate Name -Unity’s default import behavior when there are duplicate names is to append `_[number]` to Sprites and `SpriteRects` it generates from source layers with identical names. Enable this feature to instead have Unity give Sprites and `SpriteRects` the same name as their source layer even if they have duplicate names. +The icon ![](images/hidden-icon-21.2.png) appears besides layers that are hidden in the source file so that they can be easily identified in the **Layer Management Tab**. +![](images/hidden-layers-21.2.png) diff --git a/Documentation~/TableOfContents.md b/Documentation~/TableOfContents.md index bcbccb6..8a750f2 100644 --- a/Documentation~/TableOfContents.md +++ b/Documentation~/TableOfContents.md @@ -1,5 +1,5 @@ * [PSD Importer Overview](index) * [PSD Importer Inspector properties](PSD-importer-properties) - * [Skeleton sharing](skeleton-sharing) +* [Skeleton sharing](skeleton-sharing) * [How SpriteRect data is used](PSD-importer-SpriteRect) -* [Implementing the PSD File Importer Override](PSD-override) +* [PSD File Importer Override](PSD-override) diff --git a/Documentation~/images/as-per-source-21.2.png b/Documentation~/images/as-per-source-21.2.png new file mode 100644 index 0000000..ee152e9 Binary files /dev/null and b/Documentation~/images/as-per-source-21.2.png differ diff --git a/Documentation~/images/character-rig-21.2.png b/Documentation~/images/character-rig-21.2.png new file mode 100644 index 0000000..63aea5f Binary files /dev/null and b/Documentation~/images/character-rig-21.2.png differ diff --git a/Documentation~/images/group-layers-icon.png b/Documentation~/images/group-layers-icon.png new file mode 100644 index 0000000..eee5b0f Binary files /dev/null and b/Documentation~/images/group-layers-icon.png differ diff --git a/Documentation~/images/hidden-icon-21.2.png b/Documentation~/images/hidden-icon-21.2.png new file mode 100644 index 0000000..c069fe4 Binary files /dev/null and b/Documentation~/images/hidden-icon-21.2.png differ diff --git a/Documentation~/images/hidden-layers-21.2.png b/Documentation~/images/hidden-layers-21.2.png new file mode 100644 index 0000000..ee12ac8 Binary files /dev/null and b/Documentation~/images/hidden-layers-21.2.png differ diff --git a/Documentation~/images/ignore-layer-groups-21.2.png b/Documentation~/images/ignore-layer-groups-21.2.png new file mode 100644 index 0000000..8c06b0c Binary files /dev/null and b/Documentation~/images/ignore-layer-groups-21.2.png differ diff --git a/Documentation~/images/individual-sprites-mosaic-21.2.png b/Documentation~/images/individual-sprites-mosaic-21.2.png new file mode 100644 index 0000000..d00783a Binary files /dev/null and b/Documentation~/images/individual-sprites-mosaic-21.2.png differ diff --git a/Documentation~/images/layer-management-tab-21.2.png b/Documentation~/images/layer-management-tab-21.2.png new file mode 100644 index 0000000..35690e4 Binary files /dev/null and b/Documentation~/images/layer-management-tab-21.2.png differ diff --git a/Documentation~/images/layer-tab-collapse-21.2.png b/Documentation~/images/layer-tab-collapse-21.2.png new file mode 100644 index 0000000..0044443 Binary files /dev/null and b/Documentation~/images/layer-tab-collapse-21.2.png differ diff --git a/Documentation~/images/layer-tab-collapse-dim-21.2.png b/Documentation~/images/layer-tab-collapse-dim-21.2.png new file mode 100644 index 0000000..a837447 Binary files /dev/null and b/Documentation~/images/layer-tab-collapse-dim-21.2.png differ diff --git a/Documentation~/images/layer-tab-subgroup-child-collapse-21.2.png b/Documentation~/images/layer-tab-subgroup-child-collapse-21.2.png new file mode 100644 index 0000000..ce17a6e Binary files /dev/null and b/Documentation~/images/layer-tab-subgroup-child-collapse-21.2.png differ diff --git a/Documentation~/images/layer-tab-subgroup-collapse-21.2.png b/Documentation~/images/layer-tab-subgroup-collapse-21.2.png new file mode 100644 index 0000000..a2cbe55 Binary files /dev/null and b/Documentation~/images/layer-tab-subgroup-collapse-21.2.png differ diff --git a/Documentation~/images/layer-tab-subgroup-uncollapse-21.2.png b/Documentation~/images/layer-tab-subgroup-uncollapse-21.2.png new file mode 100644 index 0000000..b76e79c Binary files /dev/null and b/Documentation~/images/layer-tab-subgroup-uncollapse-21.2.png differ diff --git a/Documentation~/images/layer-tab-uncollapse-21.2.png b/Documentation~/images/layer-tab-uncollapse-21.2.png new file mode 100644 index 0000000..0753993 Binary files /dev/null and b/Documentation~/images/layer-tab-uncollapse-21.2.png differ diff --git a/Documentation~/images/layer-visibility-21.2.png b/Documentation~/images/layer-visibility-21.2.png new file mode 100644 index 0000000..affe81a Binary files /dev/null and b/Documentation~/images/layer-visibility-21.2.png differ diff --git a/Documentation~/images/layer-visibility-hidden-21.2.png b/Documentation~/images/layer-visibility-hidden-21.2.png new file mode 100644 index 0000000..c917981 Binary files /dev/null and b/Documentation~/images/layer-visibility-hidden-21.2.png differ diff --git a/Documentation~/images/layer-visibility-tree-21.2.png b/Documentation~/images/layer-visibility-tree-21.2.png new file mode 100644 index 0000000..7c47c1a Binary files /dev/null and b/Documentation~/images/layer-visibility-tree-21.2.png differ diff --git a/Documentation~/images/merged-layers-21.2.png b/Documentation~/images/merged-layers-21.2.png new file mode 100644 index 0000000..0d96d02 Binary files /dev/null and b/Documentation~/images/merged-layers-21.2.png differ diff --git a/Documentation~/images/psdimporter-properties-v6-21.2-general.png b/Documentation~/images/psdimporter-properties-v6-21.2-general.png new file mode 100644 index 0000000..70af7ba Binary files /dev/null and b/Documentation~/images/psdimporter-properties-v6-21.2-general.png differ diff --git a/Documentation~/images/psdimporter-properties-v6-21.2-layerimport.png b/Documentation~/images/psdimporter-properties-v6-21.2-layerimport.png new file mode 100644 index 0000000..c0bdc1f Binary files /dev/null and b/Documentation~/images/psdimporter-properties-v6-21.2-layerimport.png differ diff --git a/Documentation~/images/psdimporter-properties-v6-21.2-sprite.png b/Documentation~/images/psdimporter-properties-v6-21.2-sprite.png new file mode 100644 index 0000000..0a1371c Binary files /dev/null and b/Documentation~/images/psdimporter-properties-v6-21.2-sprite.png differ diff --git a/Documentation~/images/psdimporter-properties-v6-21.2.png b/Documentation~/images/psdimporter-properties-v6-21.2.png new file mode 100644 index 0000000..eefc359 Binary files /dev/null and b/Documentation~/images/psdimporter-properties-v6-21.2.png differ diff --git a/Editor/ImportUtilites.cs b/Editor/ImportUtilites.cs new file mode 100644 index 0000000..4ec29c2 --- /dev/null +++ b/Editor/ImportUtilites.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; +using UnityEngine; + +namespace UnityEditor.U2D.PSD +{ + class UniqueNameGenerator + { + List m_NameHash = new List(); + + public bool ContainHash(int i) + { + return m_NameHash.Contains(i); + } + + public void AddHash(int i) + { + m_NameHash.Add(i); + } + + public void AddHash(string name) + { + m_NameHash.Add(GetStringHash(name)); + } + + public string GetUniqueName(string name, bool logNewNameGenerated = false, UnityEngine.Object context = null) + { + return GetUniqueName(name, m_NameHash); + } + + static string GetUniqueName(string name, List stringHash, bool logNewNameGenerated = false, UnityEngine.Object context = null) + { + var sanitizedName = string.Copy(SanitizeName(name)); + string uniqueName = sanitizedName; + int index = 1; + while (true) + { + var hash = GetStringHash(uniqueName); + if (!stringHash.Contains(hash)) + { + stringHash.Add(hash); + if (logNewNameGenerated && sanitizedName != uniqueName) + Debug.Log(string.Format("Asset name {0} is changed to {1} to ensure uniqueness", name, uniqueName), context); + return uniqueName; + } + uniqueName = string.Format("{0}_{1}", sanitizedName, index); + ++index; + } + } + + static string SanitizeName(string name) + { + name = name.Replace('\0', ' '); + string newName = null; + // We can't create asset name with these name. + if ((name.Length == 2 && name[0] == '.' && name[1] == '.') + || (name.Length == 1 && name[0] == '.') + || (name.Length == 1 && name[0] == '/')) + newName += name + "_"; + + if (!string.IsNullOrEmpty(newName)) + { + Debug.LogWarning(string.Format("File contains layer with invalid name for generating asset. {0} is renamed to {1}", name, newName)); + return newName; + } + return name; + } + + static int GetStringHash(string str) + { + MD5 md5Hasher = MD5.Create(); + var hashed = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(str)); + return BitConverter.ToInt32(hashed, 0); + } + } + + class GameObjectCreationFactory : UniqueNameGenerator + { + + public GameObject CreateGameObject(string name, params System.Type[] components) + { + var newName = GetUniqueName(name); + return new GameObject(newName, components); + } + } + +} diff --git a/Editor/ImportUtilites.cs.meta b/Editor/ImportUtilites.cs.meta new file mode 100644 index 0000000..4c952f9 --- /dev/null +++ b/Editor/ImportUtilites.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6b05c5474b58463ea815d6ef8c13027 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDImportData.cs b/Editor/PSDImportData.cs new file mode 100644 index 0000000..e4f5204 --- /dev/null +++ b/Editor/PSDImportData.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using PDNWrapper; +using UnityEngine; + +namespace UnityEditor.U2D.PSD +{ + internal class PSDImportData : ScriptableObject + { + [SerializeField] + int m_ImportedTextureWidth; + public int importedTextureWidth + { + get => m_ImportedTextureWidth; + set => m_ImportedTextureWidth = value; + } + + [SerializeField] + public int m_ImportedTextureHeight; + public int importedTextureHeight + { + get => m_ImportedTextureHeight; + set => m_ImportedTextureHeight = value; + } + + [SerializeField] + Vector2Int m_DocumentSize; + public Vector2Int documentSize + { + get => m_DocumentSize; + set => m_DocumentSize = value; + } + + [SerializeField] + int m_TextureActualHeight; + public int textureActualHeight + { + get => m_TextureActualHeight; + set => m_TextureActualHeight = value; + } + + [SerializeField] + int m_TextureActualWidth; + public int textureActualWidth + { + get => m_TextureActualWidth; + set => m_TextureActualWidth = value; + } + + [SerializeField] + PSDLayerData[] m_PsdLayerData; + public PSDLayerData[] psdLayerData + { + get => m_PsdLayerData; + } + + public void CreatePSDLayerData(List bitmapLayer) + { + var layerData = new List(); + foreach (var fileLayer in bitmapLayer) + { + CreatePSDLayerData(fileLayer, layerData); + } + m_PsdLayerData = layerData.ToArray(); + } + + void CreatePSDLayerData(BitmapLayer layer, List layerData, int parentIndex = -1) + { + layerData.Add(new PSDLayerData() + { + isGroup = layer.IsGroup, + isVisible = layer.Visible, + layerID = layer.LayerID, + name = layer.Name, + parentIndex = parentIndex + }); + parentIndex = layerData.Count - 1; + foreach (var fileLayer in layer.ChildLayer) + { + CreatePSDLayerData(fileLayer, layerData, parentIndex); + } + } + } + + // Struct to keep track of GOs and bone + internal struct BoneGO + { + public GameObject go; + public int index; + } + + internal class FlattenLayerData: IPSDLayerMappingStrategyComparable + { + public int layerID { get; set; } + public string name { get; set;} + public bool isGroup => true; + } + + [Serializable] + class PSDLayerImportSetting + { + public string name; + public int layerId; + public bool flatten; + public bool isGroup; + } + + [Serializable] + class PSDLayerData : IPSDLayerMappingStrategyComparable + { + [SerializeField] + string m_Name; + public string name + { + get => m_Name; + set => m_Name = value; + } + + [SerializeField] + int m_ParentIndex; + public int parentIndex + { + get => m_ParentIndex; + set => m_ParentIndex = value; + } + + [SerializeField] + int m_LayerID; + public int layerID + { + get => m_LayerID; + set => m_LayerID = value; + } + + [SerializeField] + bool m_IsVisible; + public bool isVisible + { + get => m_IsVisible; + set => m_IsVisible = value; + } + + [SerializeField] + bool m_IsGroup; + public bool isGroup + { + get => m_IsGroup; + set => m_IsGroup = value; + } + } + + [Serializable] + struct SpriteLayerMapping + { + public string spriteId; + public int layerId; + public string layerName; + } +} + diff --git a/Editor/PSDImportData.cs.meta b/Editor/PSDImportData.cs.meta new file mode 100644 index 0000000..e5b4ed9 --- /dev/null +++ b/Editor/PSDImportData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bd443456a550044859583884e4baaff3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/PSDImporter.cs b/Editor/PSDImporter.cs index 61c78cc..092396b 100644 --- a/Editor/PSDImporter.cs +++ b/Editor/PSDImporter.cs @@ -5,8 +5,6 @@ using UnityEngine; using Unity.Collections; using System.Linq; -using System.Security.Cryptography; -using System.Text; using UnityEditor.AssetImporters; using UnityEditor.U2D.Animation; using UnityEditor.U2D.Common; @@ -21,7 +19,8 @@ namespace UnityEditor.U2D.PSD /// /// ScriptedImporter to import Photoshop files /// - [ScriptedImporter(5, "psb")] + // Version using unity release + 5 digit padding for future upgrade. Eg 2021.2 -> 21200000 + [ScriptedImporter(21200000, "psb", AllowCaching = true)] [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.psdimporter@latest")] [MovedFrom("UnityEditor.Experimental.AssetImporters")] public class PSDImporter : ScriptedImporter, ISpriteEditorDataProvider @@ -40,50 +39,9 @@ internal enum ELayerMappingOption new LayerMappingUserLayerID(), }; - internal class FlattenLayerData - { - public int layerId; - public string name; - } - - class UniqueNameGenerator - { - List m_NameHash = new List(); - - public bool ContainHash(int i) - { - return m_NameHash.Contains(i); - } - - public void AddHash(int i) - { - m_NameHash.Add(i); - } - - public string GetUniqueName(string name) - { - return PSDImporter.GetUniqueName(name, m_NameHash); - } - } - - class GameObjectCreationFactory : UniqueNameGenerator - { - - public GameObject CreateGameObject(string name, params System.Type[] components) - { - var newName = GetUniqueName(name); - return new GameObject(newName, components); - } - } - - struct BoneGO - { - public GameObject go; - public int index; - } - [SerializeField] - TextureImporterSettings m_TextureImporterSettings = new TextureImporterSettings() { + TextureImporterSettings m_TextureImporterSettings = new TextureImporterSettings() + { mipmapEnabled = true, mipmapFilter = TextureImporterMipFilter.BoxFilter, sRGBTexture = true, @@ -166,12 +124,6 @@ struct BoneGO [SerializeField] bool m_ImportHiddenLayers = false; [SerializeField] - int m_ImportedTextureWidth; - [SerializeField] - int m_ImportedTextureHeight; - [SerializeField] - Vector2Int m_DocumentSize; - [SerializeField] ELayerMappingOption m_LayerMappingOption = ELayerMappingOption.UseLayerId; [SerializeField] bool m_GeneratePhysicsShape = false; @@ -190,21 +142,33 @@ struct BoneGO GameObjectCreationFactory m_GameObjectFactory = new GameObjectCreationFactory(); internal SpriteCategoryList spriteCategoryList { get { return m_SpriteCategoryList; } set { m_SpriteCategoryList = value; } } + PSDImportData m_ImportData; + internal PSDImportData importData + { + get + { + var returnValue = m_ImportData; + if (returnValue == null) + returnValue = AssetDatabase.LoadAllAssetsAtPath(assetPath).FirstOrDefault(x => x is PSDImportData) as PSDImportData; + + if (returnValue == null) + returnValue = ScriptableObject.CreateInstance(); + + m_ImportData = returnValue; + return returnValue; + } + } - [SerializeField] - int m_TextureActualWidth; internal int textureActualWidth { - get { return m_TextureActualWidth; } - private set { m_TextureActualWidth = value; } + get => importData.textureActualWidth; + private set =>importData.textureActualWidth = value; } - [SerializeField] - int m_TextureActualHeight; internal int textureActualHeight { - get { return m_TextureActualHeight; } - private set { m_TextureActualHeight = value; } + get => importData.textureActualHeight; + private set =>importData.textureActualHeight = value; } [SerializeField] @@ -219,7 +183,9 @@ internal int textureActualHeight List m_RigPSDLayers = new List(); [SerializeField] List m_SharedRigPSDLayers = new List(); - + [SerializeField] + PSDLayerImportSetting[] m_PSDLayerImportSetting; + [SerializeField] bool m_GenerateGOHierarchy = false; @@ -249,6 +215,8 @@ public override void OnImportAsset(AssetImportContext ctx) { FileStream fileStream = new FileStream(ctx.assetPath, FileMode.Open, FileAccess.Read); Document doc = null; + m_ImportData = ScriptableObject.CreateInstance(); + m_ImportData.hideFlags = HideFlags.HideInHierarchy; try { UnityEngine.Profiling.Profiler.BeginSample("OnImportAsset"); @@ -256,10 +224,10 @@ public override void OnImportAsset(AssetImportContext ctx) UnityEngine.Profiling.Profiler.BeginSample("PsdLoad"); doc = PaintDotNet.Data.PhotoshopFileType.PsdLoad.Load(fileStream); UnityEngine.Profiling.Profiler.EndSample(); - + m_ImportData.CreatePSDLayerData(doc.Layers); ValidatePSDLayerId(doc); - m_DocumentSize = new Vector2Int(doc.width, doc.height); + importData.documentSize = new Vector2Int(doc.width, doc.height); bool singleSpriteMode = m_TextureImporterSettings.textureType == TextureImporterType.Sprite && m_TextureImporterSettings.spriteMode != (int)SpriteImportMode.Multiple; EnsureSingleSpriteExist(); @@ -289,11 +257,11 @@ public override void OnImportAsset(AssetImportContext ctx) spriteCount = 1; spriteIndexStart = 0; } - m_ImportedTextureWidth = textureActualWidth = doc.width; - m_ImportedTextureHeight = textureActualHeight = doc.height; + importData.importedTextureWidth = textureActualWidth = doc.width; + importData.importedTextureHeight = textureActualHeight = doc.height; var output = ImportTexture(ctx, image, doc.width, doc.height, spriteIndexStart, spriteCount); - m_ImportedTextureWidth = output.texture.width; - m_ImportedTextureHeight = output.texture.height; + importData.importedTextureWidth = output.texture.width; + importData.importedTextureHeight = output.texture.height; RegisterAssets(ctx, output); } finally @@ -314,6 +282,7 @@ public override void OnImportAsset(AssetImportContext ctx) ctx.DependsOnArtifact(primaryAssetPath); } } + ctx.AddObjectToAsset("PSDImportData", m_ImportData); } finally { @@ -486,11 +455,11 @@ void AutoGenerateSpriteSkinData(SpriteMetaData metaData) } } - string GetUniqueSpriteName(string name, List namehash) + string GetUniqueSpriteName(string name, UniqueNameGenerator generator) { if (m_KeepDupilcateSpriteName) return name; - return GetUniqueName(name, namehash); + return generator.GetUniqueName(name); } void ImportFromLayers(AssetImportContext ctx, Document doc) @@ -498,19 +467,34 @@ void ImportFromLayers(AssetImportContext ctx, Document doc) NativeArray output = default(NativeArray); List layerIndex = new List(); - List spriteNameHash = new List(); + UniqueNameGenerator spriteNameHash = new UniqueNameGenerator(); + var oldPsdLayers = GetPSDLayers(); try { var psdLayers = new List(); var mappingStrategy = GetLayerMappingStrategy(); - var flattenLayerData = oldPsdLayers.Where(x => x.flatten).Select(y => new FlattenLayerData() + + FlattenLayerData[] flattenLayerData = null; + if (m_PSDLayerImportSetting != null && m_PSDLayerImportSetting.Length > 0) { - layerId = y.layerID, - name = y.name - }).ToArray(); + flattenLayerData = m_PSDLayerImportSetting.Where(x => x.flatten).Select(y => new FlattenLayerData() + { + layerID = y.layerId, + name = y.name + }).ToArray(); + } + else + { + flattenLayerData = oldPsdLayers.Where(x => x.flatten).Select(y => new FlattenLayerData() + { + layerID = y.layerID, + name = y.name + }).ToArray(); + } + ExtractLayerTask.Execute(psdLayers, doc.Layers, m_ImportHiddenLayers, flattenLayerData, mappingStrategy); - var layerUnique = mappingStrategy.LayersUnique(psdLayers); + var layerUnique = mappingStrategy.LayersUnique(psdLayers.ConvertAll(x => (IPSDLayerMappingStrategyComparable)x)); if (!string.IsNullOrEmpty(layerUnique)) { Debug.LogWarning(layerUnique,this); @@ -530,7 +514,6 @@ void ImportFromLayers(AssetImportContext ctx, Document doc) psdLayer.spriteID = oldPsdLayers[j].spriteID; psdLayer.spriteName = oldPsdLayers[j].spriteName; psdLayer.mosaicPosition = oldPsdLayers[j].mosaicPosition; - psdLayer.flatten = oldPsdLayers[j].flatten; if (psdLayer.isImported != oldPsdLayers[j].isImported) hasNewLayer = true; break; @@ -565,22 +548,34 @@ void ImportFromLayers(AssetImportContext ctx, Document doc) for (int i = 0; i < spritedata.Length && i < layerIndex.Count; ++i) { - var spriteSheet = spriteImportData.FirstOrDefault(x => x.spriteID == psdLayers[layerIndex[i]].spriteID); + var psdLayer = psdLayers[layerIndex[i]]; + var spriteSheet = spriteImportData.FirstOrDefault(x => x.spriteID == psdLayer.spriteID); if (spriteSheet == null) { spriteSheet = new SpriteMetaData(); spriteSheet.border = Vector4.zero; spriteSheet.alignment = (SpriteAlignment)m_TextureImporterSettings.spriteAlignment; spriteSheet.pivot = m_TextureImporterSettings.spritePivot; + spriteSheet.rect = new Rect(spritedata[i].x, spritedata[i].y, spritedata[i].width, spritedata[i].height); + spriteSheet.spriteID = psdLayer.spriteID; } - - psdLayers[layerIndex[i]].spriteName = GetUniqueSpriteName(psdLayers[layerIndex[i]].name, spriteNameHash); - spriteSheet.name = psdLayers[layerIndex[i]].spriteName; - spriteSheet.rect = new Rect(spritedata[i].x, spritedata[i].y, spritedata[i].width, spritedata[i].height); + else + { + var r = spriteSheet.rect; + r.position = r.position - psdLayer.mosaicPosition + spritedata[i].position; + spriteSheet.rect = r; + } + + psdLayer.spriteName = GetUniqueSpriteName(psdLayer.name, spriteNameHash); + spriteSheet.name = psdLayer.spriteName; + if(shouldResliceFromLayer) + spriteSheet.rect = new Rect(spritedata[i].x, spritedata[i].y, spritedata[i].width, spritedata[i].height); + + spriteSheet.uvTransform = uvTransform[i]; - psdLayers[layerIndex[i]].spriteID = spriteSheet.spriteID; - psdLayers[layerIndex[i]].mosaicPosition = spritedata[i].position; + psdLayer.spriteID = spriteSheet.spriteID; + psdLayer.mosaicPosition = spritedata[i].position; newSpriteMeta.Add(spriteSheet); } spriteImportData.Clear(); @@ -595,7 +590,7 @@ void ImportFromLayers(AssetImportContext ctx, Document doc) { var psdLayer = psdLayers.FirstOrDefault(x => x.spriteID == spriteData.spriteID); if (psdLayer == null) - spriteNameHash.Add(GetStringHash(spriteData.name)); + spriteNameHash.AddHash(spriteData.name); } foreach (var spriteData in spriteImportData) @@ -606,7 +601,7 @@ void ImportFromLayers(AssetImportContext ctx, Document doc) // If it is user created rect or the name has been changed before // add it into the spriteNameHash and we don't copy it over from the layer if (psdLayer == null || psdLayer.spriteName != spriteData.name) - spriteNameHash.Add(GetStringHash(spriteData.name)); + spriteNameHash.AddHash(spriteData.name); // If the sprite name has not been changed, we ensure the new // layer name is still unique and use it as the sprite name @@ -655,14 +650,14 @@ void ImportFromLayers(AssetImportContext ctx, Document doc) oldPsdLayers.Clear(); oldPsdLayers.AddRange(psdLayers); - m_ImportedTextureHeight = textureActualHeight = height; - m_ImportedTextureWidth = textureActualWidth = width; + importData.importedTextureHeight = textureActualHeight = height; + importData.importedTextureWidth = textureActualWidth = width; var generatedTexture = ImportTexture(ctx, output, width, height, 0, spriteImportData.Count); if (generatedTexture.texture) { - m_ImportedTextureHeight = generatedTexture.texture.height; - m_ImportedTextureWidth = generatedTexture.texture.width; + importData.importedTextureHeight = generatedTexture.texture.height; + importData.importedTextureWidth = generatedTexture.texture.width; } RegisterAssets(ctx, generatedTexture); @@ -708,7 +703,7 @@ void RegisterAssets(AssetImportContext ctx, TextureGenerationOutput output) SetPhysicsOutline(output.texture, output.sprites); - List assetNameHash = new List(); + UniqueNameGenerator assetNameHash = new UniqueNameGenerator(); if (!string.IsNullOrEmpty(output.importInspectorWarnings)) { Debug.LogWarning(output.importInspectorWarnings); @@ -725,19 +720,16 @@ void RegisterAssets(AssetImportContext ctx, TextureGenerationOutput output) throw new Exception("Texture import fail"); } - var assetName = GetUniqueName(System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath), assetNameHash, true); + var assetName = assetNameHash.GetUniqueName(System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath), true, this); // Setup all fixed name on the hash table - if (string.IsNullOrEmpty(m_TextureAssetName)) - m_TextureAssetName = GetUniqueName(string.Format("{0} Texture",assetName), assetNameHash, true); - if (string.IsNullOrEmpty(m_PrefabAssetName)) - m_PrefabAssetName = GetUniqueName(string.Format("{0} Prefab", assetName), assetNameHash, true); - if (string.IsNullOrEmpty(m_SpriteLibAssetName)) - m_SpriteLibAssetName = GetUniqueName(string.Format("{0} Sprite Lib", assetName), assetNameHash, true); - if (string.IsNullOrEmpty(m_SkeletonAssetName)) - m_SkeletonAssetName = GetUniqueName(string.Format("{0} Skeleton", assetName), assetNameHash, true); - + var registerTextureNameId = string.IsNullOrEmpty(m_TextureAssetName) ? "Texture" : m_TextureAssetName; + var prefabRootNameId = string.IsNullOrEmpty(m_TextureAssetName) ? "root" : m_TextureAssetName; + var registerPrefabNameId = string.IsNullOrEmpty(m_PrefabAssetName) ? "Prefab" : m_PrefabAssetName; + var spriteLibAssetNameId = string.IsNullOrEmpty(m_SpriteLibAssetName) ? "SpriteLibAsset" : m_SpriteLibAssetName; + var skeletonAssetNameId = string.IsNullOrEmpty(m_SkeletonAssetName) ? "SkeletonAsset" : m_SkeletonAssetName; + output.texture.name = assetName; - ctx.AddObjectToAsset(m_TextureAssetName, output.texture, output.thumbNail); + ctx.AddObjectToAsset(registerTextureNameId, output.texture, output.thumbNail); UnityEngine.Object mainAsset = output.texture; @@ -749,26 +741,26 @@ void RegisterAssets(AssetImportContext ctx, TextureGenerationOutput output) { GameObject prefab = null; if (m_PaperDollMode) - prefab = OnProducePaperDollPrefab(m_TextureAssetName, output.sprites, slAsset); + prefab = OnProducePaperDollPrefab(prefabRootNameId, output.sprites, slAsset); else - prefab = OnProducePrefab(m_TextureAssetName, output.sprites, slAsset); + prefab = OnProducePrefab(prefabRootNameId, output.sprites, slAsset); if (prefab != null) { - ctx.AddObjectToAsset(m_PrefabAssetName, prefab); + ctx.AddObjectToAsset(registerPrefabNameId, prefab); mainAsset = prefab; } } foreach (var s in output.sprites) { - var spriteAssetName = GetUniqueName(s.GetSpriteID().ToString(), assetNameHash, false, s); + var spriteAssetName = assetNameHash.GetUniqueName(s.GetSpriteID().ToString(), false, s); ctx.AddObjectToAsset(spriteAssetName, s); } if (slAsset != null) { slAsset.name = assetName; - ctx.AddObjectToAsset(m_SpriteLibAssetName, slAsset); + ctx.AddObjectToAsset(spriteLibAssetNameId, slAsset); } if (characterMode && skeletonAsset == null) @@ -777,7 +769,7 @@ void RegisterAssets(AssetImportContext ctx, TextureGenerationOutput output) characterRig.name = assetName + " Skeleton"; var bones = GetDataProvider().GetCharacterData().bones; characterRig.SetSpriteBones(bones); - ctx.AddObjectToAsset(m_SkeletonAssetName, characterRig); + ctx.AddObjectToAsset(skeletonAssetNameId, characterRig); } } ctx.SetMainObject(mainAsset); @@ -836,7 +828,11 @@ void BuildGroupGameObject(List psdGroup, int index, Transform root) } if (psdData.gameObject != null) + { psdData.gameObject.transform.SetParent(root); + psdData.gameObject.transform.SetSiblingIndex(root.childCount-1); + } + } } @@ -859,13 +855,13 @@ float definitionScale { get { - float definitionScaleW = m_ImportedTextureWidth / (float)textureActualWidth; - float definitionScaleH = m_ImportedTextureHeight / (float)textureActualHeight; + float definitionScaleW = importData.importedTextureWidth / (float)textureActualWidth; + float definitionScaleH = importData.importedTextureHeight / (float)textureActualHeight; return Mathf.Min(definitionScaleW, definitionScaleH); } } - private Vector2 GetPivotPoint(Rect rect, SpriteAlignment alignment) + internal static Vector2 GetPivotPoint(Rect rect, SpriteAlignment alignment, Vector2 customPivot) { switch (alignment) { @@ -897,7 +893,7 @@ private Vector2 GetPivotPoint(Rect rect, SpriteAlignment alignment) return new Vector2(rect.xMax, rect.yMin); case SpriteAlignment.Custom: - return new Vector2(m_DocumentPivot.x * rect.width, m_DocumentPivot.y * rect.height); + return new Vector2(customPivot.x * rect.width, customPivot.y * rect.height); } return Vector2.zero; } @@ -1039,6 +1035,7 @@ GameObject OnProducePrefab(string assetname, Sprite[] sprites, SpriteLibraryAsse var currentCharacterData = characterData; var spriteImportData = GetSpriteImportData(); root = new GameObject(); + root.transform.SetSiblingIndex(0); root.name = assetname + "_GO"; if (spriteLib != null) root.AddComponent().spriteLibraryAsset = spriteLib; @@ -1097,8 +1094,8 @@ GameObject OnProducePrefab(string assetname, Sprite[] sprites, SpriteLibraryAsse } } - var prefabBounds = new Rect(0 , 0, m_DocumentSize.x / pixelsPerUnit, m_DocumentSize.y / pixelsPerUnit); - var documentPivot = (Vector3)GetPivotPoint(prefabBounds, m_DocumentAlignment); + var prefabBounds = new Rect(0 , 0, importData.documentSize.x / pixelsPerUnit, importData.documentSize.y / pixelsPerUnit); + var documentPivot = (Vector3)GetPivotPoint(prefabBounds, m_DocumentAlignment, m_DocumentPivot); for (int i = 0; i < psdLayers.Count; ++i) { var l = psdLayers[i]; @@ -1183,50 +1180,7 @@ bool CleanUpGameobjectsWithOutRig(GameObject root) return false; } - static string SanitizeName(string name) - { - name = name.Replace('\0', ' '); - string newName = null; - // We can't create asset name with these name. - if ((name.Length == 2 && name[0] == '.' && name[1] == '.') - || (name.Length == 1 && name[0] == '.') - || (name.Length == 1 && name[0] == '/')) - newName += name + "_"; - - if (!string.IsNullOrEmpty(newName)) - { - Debug.LogWarning(string.Format("File contains layer with invalid name for generating asset. {0} is renamed to {1}", name, newName)); - return newName; - } - return name; - } - - static int GetStringHash(string str) - { - MD5 md5Hasher = MD5.Create(); - var hashed = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(str)); - return BitConverter.ToInt32(hashed, 0); - } - static string GetUniqueName(string name, List stringHash, bool logNewNameGenerated = false, UnityEngine.Object context = null) - { - var sanitizedName = string.Copy(SanitizeName(name)); - string uniqueName = sanitizedName; - int index = 1; - while (true) - { - var hash = GetStringHash(uniqueName); - if (!stringHash.Contains(hash)) - { - stringHash.Add(hash); - if (logNewNameGenerated && sanitizedName != uniqueName) - Debug.Log(string.Format("Asset name {0} is changed to {1} to ensure uniqueness", name, uniqueName), context); - return uniqueName; - } - uniqueName = string.Format("{0}_{1}", sanitizedName, index); - ++index; - } - } // ISpriteEditorDataProvider interface internal SpriteImportMode spriteImportMode @@ -1540,16 +1494,14 @@ internal CharacterData characterData internal Vector2Int documentSize { - get { return m_DocumentSize; } + get => importData.documentSize; } SpriteLibraryAsset ProduceSpriteLibAsset(Sprite[] sprites) { if (!characterMode || m_SpriteCategoryList.categories == null) return null; - var sla = ScriptableObject.CreateInstance(); - sla.name = "Sprite Lib"; - sla.categories = m_SpriteCategoryList.categories.Select(x => + var categories = m_SpriteCategoryList.categories.Select(x => new SpriteLibCategory() { name = x.name, @@ -1563,11 +1515,11 @@ SpriteLibraryAsset ProduceSpriteLibAsset(Sprite[] sprites) }; }).ToList() }).ToList(); - sla.categories.RemoveAll(x => x.categoryList.Count == 0); - if (sla.categories.Count > 0) + categories.RemoveAll(x => x.categoryList.Count == 0); + if (categories.Count > 0) { - sla.UpdateHashes(); - return sla; + // Always set version to 0 since we will never be updating this + return SpriteLibraryAsset.CreateAsset(categories, "Sprite Lib", 0); } return null; } @@ -1592,7 +1544,7 @@ internal SpriteBone[] mainSkeletonBones } } - IPSDLayerMappingStrategy GetLayerMappingStrategy() + internal IPSDLayerMappingStrategy GetLayerMappingStrategy() { return m_MappingCompare[(int)m_LayerMappingOption]; } @@ -1602,6 +1554,10 @@ internal bool generatePhysicsOutline get => m_GeneratePhysicsShape; } + internal bool isNPOT + { + get => Mathf.IsPowerOfTwo(importData.textureActualWidth) && Mathf.IsPowerOfTwo(importData.textureActualHeight); + } void SetPhysicsOutline(Texture2D texture, Sprite[] sprites) { var scale = definitionScale; @@ -1650,7 +1606,7 @@ void SetPhysicsOutline(Texture2D texture, Sprite[] sprites) } sprite.OverridePhysicsShape(convertedOutline); } - } } } + } } diff --git a/Editor/PSDImporterEditor.cs b/Editor/PSDImporterEditor.cs index 0256b89..771fcf0 100644 --- a/Editor/PSDImporterEditor.cs +++ b/Editor/PSDImporterEditor.cs @@ -130,9 +130,11 @@ public override void OnEnable() m_WrapV = textureImporterSettingsSP.FindPropertyRelative("m_WrapV"); m_WrapW = textureImporterSettingsSP.FindPropertyRelative("m_WrapW"); - var textureWidth = serializedObject.FindProperty("m_TextureActualWidth"); - var textureHeight = serializedObject.FindProperty("m_TextureActualHeight"); - m_IsPOT = Mathf.IsPowerOfTwo(textureWidth.intValue) && Mathf.IsPowerOfTwo(textureHeight.intValue); + foreach (var t in targets) + { + m_IsPOT &= ((PSDImporter)t).isNPOT; + } + var assetPath = AssetDatabase.GUIDToAssetPath(m_SkeletonAssetReferenceID.stringValue); m_SkeletonAsset = AssetDatabase.LoadAssetAtPath(assetPath); @@ -172,7 +174,7 @@ void UpdateLayerTreeView() if (!ReferenceEquals(m_CurrentTarget,target) || m_LayerTreeView == null) { m_CurrentTarget = (PSDImporter)target; - m_LayerTreeView = new PSDImporterEditorLayerTreeView(m_TreeViewState, m_CurrentTarget.GetPSDLayers(), m_ImportHiddenLayers.boolValue); + m_LayerTreeView = new PSDImporterEditorLayerTreeView(assetTarget.name, m_TreeViewState, m_CurrentTarget.importData.psdLayerData, m_ImportHiddenLayers.boolValue, serializedObject.FindProperty("m_PSDLayerImportSetting"), m_CurrentTarget.GetLayerMappingStrategy()); } } @@ -186,7 +188,8 @@ public override void OnInspectorGUI() s_Styles = new Styles(); UpdateLayerTreeView(); - + + GUILayout.Space(5); using (new GUILayout.HorizontalScope()) { GUILayout.FlexibleSpace(); @@ -200,6 +203,7 @@ public override void OnInspectorGUI() } GUILayout.FlexibleSpace(); } + GUILayout.Space(5); m_InspectorUI[m_ActiveEditorIndex](); @@ -208,24 +212,13 @@ public override void OnInspectorGUI() ApplyRevertGUI(); Repaint(); } - - public override VisualElement CreateInspectorGUI() - { - var ve = new IMGUIContainer(OnInspectorGUI); - ve.AddToClassList("unity-imgui-container"); - ve.AddToClassList("unity-inspector-element_custom-inspector-container"); - ve.AddToClassList("unity-inspector-element__imgui-container"); - return null; - } void DoLayerManagementUI() { var rect = InternalEngineBridge.GetGUIClipVisibleRect(); //Magic number. 54 is for header. The rest no idea. - rect = GUILayoutUtility.GetRect(0,rect.height - (54 + 30 + 30 + 20), GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)); + rect = GUILayoutUtility.GetRect(0,rect.height - (54 + 120), GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)); m_LayerTreeView.OnGUI(rect); - if (m_LayerTreeView.GetHasChangeAndClear()) - serializedObject.Update(); } void DoSettingsUI() @@ -234,24 +227,26 @@ void DoSettingsUI() { EditorGUI.showMixedValue = m_TextureType.hasMultipleDifferentValues; m_TextureType.intValue = EditorGUILayout.IntPopup(s_Styles.textureTypeTitle, m_TextureType.intValue, s_Styles.textureTypeOptions, s_Styles.textureTypeValues); - EditorGUI.showMixedValue = false; - } - - - switch ((TextureImporterType)m_TextureType.intValue) - { - case TextureImporterType.Sprite: - DoSpriteInspector(); - break; - case TextureImporterType.Default: - DoTextureDefaultInspector(); - break; - default: - Debug.LogWarning("We only support Default or Sprite texture type for now. Texture type is set to default."); - m_TextureType.intValue = (int)TextureImporterType.Default; - break; + EditorGUI.showMixedValue = false; + + switch ((TextureImporterType)m_TextureType.intValue) + { + case TextureImporterType.Sprite: + DoSpriteTextureTypeInspector(); + break; + case TextureImporterType.Default: + DoTextureDefaultTextureTypeInspector(); + break; + default: + Debug.LogWarning("We only support Default or Sprite texture type for now. Texture type is set to default."); + m_TextureType.intValue = (int)TextureImporterType.Default; + break; + } + GUILayout.Space(5); } + if ((TextureImporterType)m_TextureType.intValue == TextureImporterType.Sprite) + DoSpriteInspector(); CommonTextureSettingsGUI(); DoPlatformSettings(); DoAdvanceInspector(); @@ -277,6 +272,7 @@ void MainRigPropertyField() /// protected override void Apply() { + InternalEditorBridge.ApplySpriteEditorWindow(); FileStream fileStream = new FileStream(((AssetImporter)target).assetPath, FileMode.Open, FileAccess.Read); var doc = PaintDotNet.Data.PhotoshopFileType.PsdLoad.Load(fileStream, ELoadFlag.Header | ELoadFlag.ColorMode); @@ -298,8 +294,6 @@ protected override void Apply() AnalyticFactory.analytics.SendApplyEvent(evt); m_TexturePlatformSettingsHelper.Apply(); base.Apply(); - Selection.activeObject = null; - Unsupported.SceneTrackerFlushDirty(); PSDImportPostProcessor.currentApplyAssetPath = ((PSDImporter) target).assetPath; } @@ -398,8 +392,9 @@ void DoPlatformSettings() { if (m_EditorFoldOutState.DoPlatformSettingsUI(s_Styles.platformSettingsHeaderText)) { + GUILayout.Space(5); m_TexturePlatformSettingsHelper.ShowPlatformSpecificSettings(); - GUILayout.Space(10); + GUILayout.Space(5); } } @@ -494,6 +489,7 @@ void CommonTextureSettingsGUI() EditorGUILayout.HelpBox(s_Styles.anisotropicForceEnableInfo.text, MessageType.Info); } } + GUILayout.Space(5); } } @@ -641,56 +637,56 @@ bool IsVolume() return t != null && t.dimension == UnityEngine.Rendering.TextureDimension.Tex3D; } - void DoSpriteInspector() + void DoSpriteTextureTypeInspector() { - if(m_EditorFoldOutState.DoSpriteUI(s_Styles.spriteHeaderText)) + EditorGUI.BeginChangeCheck(); + EditorGUILayout.IntPopup(m_SpriteMode, s_Styles.spriteModeOptions, new[] { 1, 2, 3 }, s_Styles.spriteMode); + + // Ensure that PropertyField focus will be cleared when we change spriteMode. + if (EditorGUI.EndChangeCheck()) { - EditorGUI.BeginChangeCheck(); - EditorGUILayout.IntPopup(m_SpriteMode, s_Styles.spriteModeOptions, new[] { 1, 2, 3 }, s_Styles.spriteMode); + GUIUtility.keyboardControl = 0; + } - // Ensure that PropertyField focus will be cleared when we change spriteMode. - if (EditorGUI.EndChangeCheck()) - { - GUIUtility.keyboardControl = 0; - } + // Show generic attributes + using (new EditorGUI.DisabledScope(m_SpriteMode.intValue == 0)) + { + EditorGUILayout.PropertyField(m_SpritePixelsToUnits, s_Styles.spritePixelsPerUnit); - // Show generic attributes - using (new EditorGUI.DisabledScope(m_SpriteMode.intValue == 0)) + if (m_SpriteMode.intValue != (int)SpriteImportMode.Polygon && !m_SpriteMode.hasMultipleDifferentValues) { - EditorGUILayout.PropertyField(m_SpritePixelsToUnits, s_Styles.spritePixelsPerUnit); + EditorGUILayout.IntPopup(m_SpriteMeshType, s_Styles.spriteMeshTypeOptions, new[] { 0, 1 }, s_Styles.spriteMeshType); + } - if (m_SpriteMode.intValue != (int)SpriteImportMode.Polygon && !m_SpriteMode.hasMultipleDifferentValues) - { - EditorGUILayout.IntPopup(m_SpriteMeshType, s_Styles.spriteMeshTypeOptions, new[] { 0, 1 }, s_Styles.spriteMeshType); - } + EditorGUILayout.IntSlider(m_SpriteExtrude, 0, 32, s_Styles.spriteExtrude); - EditorGUILayout.IntSlider(m_SpriteExtrude, 0, 32, s_Styles.spriteExtrude); + if (m_SpriteMode.intValue == 1) + { + EditorGUILayout.IntPopup(m_Alignment, s_Styles.spriteAlignmentOptions, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s_Styles.spriteAlignment); - if (m_SpriteMode.intValue == 1) + if (m_Alignment.intValue == (int)SpriteAlignment.Custom) { - EditorGUILayout.IntPopup(m_Alignment, s_Styles.spriteAlignmentOptions, new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s_Styles.spriteAlignment); - - if (m_Alignment.intValue == (int)SpriteAlignment.Custom) - { - GUILayout.BeginHorizontal(); - EditorGUILayout.PropertyField(m_SpritePivot, new GUIContent()); - GUILayout.EndHorizontal(); - } - } + GUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(m_SpritePivot, new GUIContent()); + GUILayout.EndHorizontal(); + } } - EditorGUILayout.PropertyField(m_GeneratePhysicsShape, s_Styles.generatePhysicsShape); - using (new EditorGUI.DisabledScope(!m_MosaicLayers.boolValue)) + } + EditorGUILayout.PropertyField(m_GeneratePhysicsShape, s_Styles.generatePhysicsShape); + using (new EditorGUI.DisabledScope(!m_MosaicLayers.boolValue)) + { + EditorGUILayout.PropertyField(m_ResliceFromLayer, s_Styles.resliceFromLayer); + if (m_ResliceFromLayer.boolValue) { - EditorGUILayout.PropertyField(m_ResliceFromLayer, s_Styles.resliceFromLayer); - if (m_ResliceFromLayer.boolValue) - { - EditorGUILayout.HelpBox(s_Styles.resliceFromLayerWarning.text, MessageType.Info, true); - } + EditorGUILayout.HelpBox(s_Styles.resliceFromLayerWarning.text, MessageType.Info, true); } } - + DoOpenSpriteEditorButton(); - + } + + void DoSpriteInspector() + { if (m_EditorFoldOutState.DoLayerImportUI(s_Styles.layerImportHeaderText)) { using (new EditorGUI.DisabledScope(m_SpriteMode.intValue != (int)SpriteImportMode.Multiple || m_SpriteMode.hasMultipleDifferentValues)) @@ -727,7 +723,8 @@ void DoSpriteInspector() m_GenerateGOHierarchy.boolValue = boolToInt == 1; } } - } + } + GUILayout.Space(5); } if (m_EditorFoldOutState.DoCharacterRigUI(s_Styles.characterRigHeaderText)) @@ -748,6 +745,7 @@ void DoSpriteInspector() } } } + GUILayout.Space(5); //EditorGUILayout.PropertyField(m_PaperDollMode, s_Styles.paperDollMode); } } @@ -766,7 +764,7 @@ void DoOpenSpriteEditorButton() // We must applied those modified values first. string dialogText = string.Format(s_Styles.unappliedSettingsDialogContent.text, ((AssetImporter)target).assetPath); if (EditorUtility.DisplayDialog(s_Styles.unappliedSettingsDialogTitle.text, - dialogText, s_Styles.applyButtonLabel.text, s_Styles.revertButtonLabel.text)) + dialogText, s_Styles.applyButtonLabel.text, s_Styles.cancelButtonLabel.text)) { ApplyAndImport(); InternalEditorBridge.ShowSpriteEditorWindow(this.assetTarget); @@ -784,13 +782,10 @@ void DoOpenSpriteEditorButton() } } - void DoTextureDefaultInspector() + void DoTextureDefaultTextureTypeInspector() { - if (m_EditorFoldOutState.DoDefaultTypeUI(s_Styles.defaultHeaderText)) - { - ColorSpaceGUI(); - AlphaHandlingGUI(); - } + ColorSpaceGUI(); + AlphaHandlingGUI(); } void ColorSpaceGUI() @@ -1174,7 +1169,7 @@ internal class Styles public readonly GUIContent unappliedSettingsDialogTitle = new GUIContent("Unapplied import settings"); public readonly GUIContent unappliedSettingsDialogContent = new GUIContent("Unapplied import settings for \'{0}\'.\nApply and continue to sprite editor or cancel."); public readonly GUIContent applyButtonLabel = new GUIContent("Apply"); - public readonly GUIContent revertButtonLabel = new GUIContent("Revert"); + public readonly GUIContent cancelButtonLabel = new GUIContent("Cancel"); public readonly GUIContent spriteEditorButtonLabel = new GUIContent("Open Sprite Editor"); public readonly GUIContent resliceFromLayerWarning = new GUIContent("This will reinitialize and recreate all Sprites based on the file’s layer data. Existing Sprite metadata from previously generated Sprites are copied over."); public readonly GUIContent alphaIsTransparency = new GUIContent("Alpha Is Transparency", "If the provided alpha channel is transparency, enable this to pre-filter the color to avoid texture filtering artifacts. This is not supported for HDR textures."); @@ -1210,7 +1205,7 @@ internal class Styles public readonly GUIContent layerMapping = EditorGUIUtility.TrTextContent("Layer Mapping", "Options for indicating how layer to Sprite mapping."); public readonly GUIContent generatePhysicsShape = EditorGUIUtility.TrTextContent("Generate Physics Shape", "Generates a default physics shape from the outline of the Sprite/s when a physics shape has not been set in the Sprite Editor."); - public readonly GUIContent importHiddenLayer = EditorGUIUtility.TrTextContent("Layer", "Import hidden layers."); + public readonly GUIContent importHiddenLayer = EditorGUIUtility.TrTextContent("Layer Visibility", "Settings to determine when hidden layers should be imported."); public readonly GUIContent mosaicLayers = EditorGUIUtility.TrTextContent("Import Mode", "Layers will be imported as individual Sprites."); public readonly GUIContent characterMode = EditorGUIUtility.TrTextContent("Use as Rig","Enable to support 2D Animation character rigging."); public readonly GUIContent layerGroupLabel = EditorGUIUtility.TrTextContent("Layer Group", "GameObjects are grouped according to source file layer grouping."); @@ -1234,7 +1229,7 @@ internal class Styles public readonly GUIContent[] layerOptions = { - EditorGUIUtility.TrTextContent("Visible Layers Only", "Import only layers that are visible."), + EditorGUIUtility.TrTextContent("Exclude Hidden Layers", "Import only layers that are visible."), EditorGUIUtility.TrTextContent("Include Hidden Layers","Import all layers, including hidden layers.") }; @@ -1267,7 +1262,7 @@ internal class Styles public readonly GUIContent[] layerGroupOption= { EditorGUIUtility.TrTextContent("Ignore Layer Groups","Only layers will generate GameObjects."), - EditorGUIUtility.TrTextContent("As Per Source File", "Group GameObjects according to source file's layer grouping") + EditorGUIUtility.TrTextContent("User Layer Groups", "Group GameObjects according to source file's layer grouping") }; public readonly GUIContent[] editorTabNames = @@ -1308,8 +1303,6 @@ public Styles() class PSDImporterEditorFoldOutState { SavedBool m_GeneralFoldout; - SavedBool m_DefaultTypeFoldout; - SavedBool m_SpriteFoldout; SavedBool m_LayerImportFoldout; SavedBool m_CharacterRigFoldout; SavedBool m_AdvancedFoldout; @@ -1319,8 +1312,6 @@ class PSDImporterEditorFoldOutState public PSDImporterEditorFoldOutState() { m_GeneralFoldout = new SavedBool("PSDImporterEditor.m_GeneralFoldout", true); - m_DefaultTypeFoldout = new SavedBool("PSDImporterEditor.m_DefaultTypeFoldout", true); - m_SpriteFoldout = new SavedBool("PSDImporterEditor.m_SpriteFoldout", true); m_LayerImportFoldout = new SavedBool("PSDImporterEditor.m_LayerImportFoldout", true); m_CharacterRigFoldout = new SavedBool("PSDImporterEditor.m_CharacterRigFoldout", false); m_AdvancedFoldout = new SavedBool("PSDImporterEditor.m_AdvancedFoldout", false); @@ -1340,18 +1331,6 @@ public bool DoGeneralUI(GUIContent title) return m_GeneralFoldout.value; } - public bool DoDefaultTypeUI(GUIContent title) - { - m_DefaultTypeFoldout.value = DoFoldout(title, m_DefaultTypeFoldout.value); - return m_DefaultTypeFoldout.value; - } - - public bool DoSpriteUI(GUIContent title) - { - m_SpriteFoldout.value = DoFoldout(title, m_SpriteFoldout.value); - return m_SpriteFoldout.value; - } - public bool DoLayerImportUI(GUIContent title) { m_LayerImportFoldout.value = DoFoldout(title, m_LayerImportFoldout.value); diff --git a/Editor/PSDImporterEditorLayerTreeView.cs b/Editor/PSDImporterEditorLayerTreeView.cs index c897062..795191a 100644 --- a/Editor/PSDImporterEditorLayerTreeView.cs +++ b/Editor/PSDImporterEditorLayerTreeView.cs @@ -4,15 +4,101 @@ using UnityEditor.Experimental; using UnityEditor.IMGUI.Controls; using UnityEngine; -using UnityEngine.UIElements; namespace UnityEditor.U2D.PSD { + internal class PSDLayerImportSettingSerializedPropertyWrapper : IPSDLayerMappingStrategyComparable + { + PSDLayerData m_Layer; + SerializedProperty m_Array; + SerializedProperty m_Element; + SerializedProperty m_NameProperty; + SerializedProperty m_LayerIdProperty; + SerializedProperty m_FlattenProperty; + SerializedProperty m_IsGroup; + + public string name + { + get => m_NameProperty.stringValue; + set + { + CheckAndAddElement(); + m_NameProperty.stringValue = value; + } + } + + public bool isGroup + { + get => m_IsGroup.boolValue; + set + { + CheckAndAddElement(); + m_IsGroup.boolValue = value; + } + } + + public int layerID + { + get => m_LayerIdProperty.intValue; + set + { + CheckAndAddElement(); + m_LayerIdProperty.intValue = value; + } + } + + public bool flatten + { + get => m_FlattenProperty == null ? false : m_FlattenProperty.boolValue; + set + { + CheckAndAddElement(); + m_FlattenProperty.boolValue = value; + } + } + + void CheckAndAddElement() + { + if (m_Element == null) + { + var arraySize = m_Array.arraySize; + m_Array.arraySize = arraySize + 1; + m_Element = m_Array.GetArrayElementAtIndex(arraySize); + CacheProperty(m_Element); + flatten = false; + name = m_Layer.name; + layerID = m_Layer.layerID; + isGroup = m_Layer.isGroup; + } + } + + void CacheProperty(SerializedProperty property) + { + m_NameProperty = property.FindPropertyRelative("name"); + m_LayerIdProperty = property.FindPropertyRelative("layerId"); + m_FlattenProperty = property.FindPropertyRelative("flatten"); + m_IsGroup = property.FindPropertyRelative("isGroup"); + + } + + public PSDLayerImportSettingSerializedPropertyWrapper(SerializedProperty sp, SerializedProperty array, PSDLayerData layer) + { + if (sp != null) + { + m_Element = sp; + CacheProperty(sp); + } + + m_Array = array; + m_Layer = layer; + } + } + class PSDNode : TreeViewItem { - public PSDLayer layer; + PSDLayerData m_Layer; bool m_Disable = false; - + PSDLayerImportSettingSerializedPropertyWrapper m_Property; public bool disable { get => m_Disable; @@ -25,29 +111,36 @@ public PSDNode() displayName = ""; } - public PSDNode(PSDLayer layer, int id) + public PSDNode(PSDLayerData layer, int id, PSDLayerImportSettingSerializedPropertyWrapper importSetting) { - this.layer = layer; + m_Layer = layer; displayName = layer.name; this.id = id; + m_Property = importSetting; } public virtual void ChildGroupFlatten(bool flatten) { } public virtual void FlattenStateChange() { } public virtual void NotifyParentOnFlattenChange() { } + public PSDLayerData layer => m_Layer; + public bool flatten + { + get => m_Property.flatten; + set => m_Property.flatten = value; + } } class PSDLayerNode : PSDNode { - public PSDLayerNode(PSDLayer layer, int id):base(layer, id) + public PSDLayerNode(PSDLayerData layer, int id, PSDLayerImportSettingSerializedPropertyWrapper property):base(layer, id, property) { } } class PSDLayerGroupNode : PSDNode { int m_ChildFlattenCount; - public PSDLayerGroupNode(PSDLayer layer, int id) - : base(layer, id) + public PSDLayerGroupNode(PSDLayerData layer, int id, PSDLayerImportSettingSerializedPropertyWrapper property) + : base(layer, id, property) { this.icon = EditorGUIUtility.FindTexture(EditorResources.folderIconName); m_ChildFlattenCount = 0; @@ -59,7 +152,7 @@ public override void NotifyParentOnFlattenChange() { var pp = parent as PSDNode; if(pp != null) - pp.ChildGroupFlatten(layer.flatten); + pp.ChildGroupFlatten(flatten); } public override void ChildGroupFlatten(bool flatten) @@ -79,7 +172,7 @@ public override void FlattenStateChange() var p = ((PSDNode)child); if (p != null) { - p.disable = layer.flatten || this.disable; + //p.disable = flatten || this.disable; p.FlattenStateChange(); } } @@ -94,21 +187,21 @@ static class Style static public readonly string k_LightIconResourcePath = "Icons/Light"; static public readonly string k_DarkIconResourcePath = "Icons/Dark"; static public readonly string k_SelectedIconResourcePath = "Icons/Selected"; - static public GUIContent visibilityIcon = EditorGUIUtility.IconContent("animationvisibilitytoggleoff", L10n.Tr("|Layer is not visible in source file")); - public static readonly GUIContent[] collapsedIcon = + public static readonly GUIContent layerHiddenToolTip = EditorGUIUtility.TrTextContent("", "The layer is hidden in the source file."); + public static readonly GUIContent[] mergedIcon = { - new GUIContent(LoadIconResource("Layers Separated", k_LightIconResourcePath, k_DarkIconResourcePath), L10n.Tr("Layers Separated. Click to collapse them.")), - new GUIContent(LoadIconResource("Layers Separated", k_SelectedIconResourcePath, k_SelectedIconResourcePath), L10n.Tr("Layers Separated. Click to collapse them.")) + new GUIContent(LoadIconResource("Layers Separated", k_LightIconResourcePath, k_DarkIconResourcePath), L10n.Tr("Layers Separated. Click to merge them.")), + new GUIContent(LoadIconResource("Layers Separated", k_SelectedIconResourcePath, k_SelectedIconResourcePath), L10n.Tr("Layers Separated. Click to merge them.")) }; public static readonly GUIContent[] separateIcon = { - new GUIContent(LoadIconResource("Layers Collapsed", k_LightIconResourcePath, k_DarkIconResourcePath), L10n.Tr("Layers collapsed. Click to separate them.")), - new GUIContent(LoadIconResource("Layers Collapsed", k_SelectedIconResourcePath, k_SelectedIconResourcePath), L10n.Tr("Layers collapsed. Click to separate them.")) + new GUIContent(LoadIconResource("Layers Collapsed", k_LightIconResourcePath, k_DarkIconResourcePath), L10n.Tr("Layers merged. Click to separate them.")), + new GUIContent(LoadIconResource("Layers Collapsed", k_SelectedIconResourcePath, k_SelectedIconResourcePath), L10n.Tr("Layers merged. Click to separate them.")) }; - public static readonly GUIContent[] collapseMix = + public static readonly GUIContent[] mergedMix = { - new GUIContent(LoadIconResource("Layers Mixed", k_LightIconResourcePath, k_DarkIconResourcePath), L10n.Tr("Group contains child groups that are collapsed.")), - new GUIContent(LoadIconResource("Layers Mixed", k_SelectedIconResourcePath, k_SelectedIconResourcePath), L10n.Tr("Group contains child groups that are collapsed.")) + new GUIContent(LoadIconResource("Layers Mixed", k_LightIconResourcePath, k_DarkIconResourcePath), L10n.Tr("Group contains child groups that are merged.")), + new GUIContent(LoadIconResource("Layers Mixed", k_SelectedIconResourcePath, k_SelectedIconResourcePath), L10n.Tr("Group contains child groups that are merged.")) }; const string k_ResourcePath = "Packages/com.unity.2d.psdimporter/Editor/Assets"; @@ -148,12 +241,17 @@ static Style() } } - internal class PSDImporterEditorLayerTreeView : TreeView + internal class PSDImporterEditorLayerTreeView : IMGUI.Controls.TreeView { - List m_Layers; + PSDLayerData[] m_Layers; bool m_ShowHidden; bool m_HasChanged; - public PSDImporterEditorLayerTreeView(TreeViewState treeViewState, List layers, bool showHidden) + string m_RootName; + SerializedProperty m_PSDLayerImportSetting; + IPSDLayerMappingStrategy m_MappingStrategy; + int m_LastArraySize; + + public PSDImporterEditorLayerTreeView(string rootName, TreeViewState treeViewState, PSDLayerData[] layers, bool showHidden, SerializedProperty psdLayerImportSetting, IPSDLayerMappingStrategy mappingStrategy) : base(treeViewState) { m_Layers = layers; @@ -161,115 +259,160 @@ public PSDImporterEditorLayerTreeView(TreeViewState treeViewState, List m_ShowHidden; - set - { - if (m_ShowHidden != value) - { - m_ShowHidden = value; - Reload(); - } - } + set => m_ShowHidden = value; + } + + public override void OnGUI(Rect rect) + { + if(m_PSDLayerImportSetting.arraySize != m_LastArraySize) + Reload(); + base.OnGUI(rect); + m_LastArraySize = m_PSDLayerImportSetting.arraySize; } protected override TreeViewItem BuildRoot() { - var root = new TreeViewItem { id = 0, depth = -1, displayName = "Root" }; + m_PSDLayerImportSetting.serializedObject.Update(); + m_LastArraySize = m_PSDLayerImportSetting.arraySize; + var root = new TreeViewItem { id = -1, depth = -1, displayName = "Root" }; + var fileRoot = new PSDNode(){id = -2}; + fileRoot.displayName = m_RootName; + //fileRoot.icon = EditorGUIUtility.IconContent("Texture Icon").image as Texture2D; + root.AddChild(fileRoot); + var spWrapper = new List(); + if (m_PSDLayerImportSetting.arraySize > 0) + { + var firstElement = m_PSDLayerImportSetting.GetArrayElementAtIndex(0); + for (int i = 0; i < m_PSDLayerImportSetting.arraySize; ++i) + { + spWrapper.Add(new PSDLayerImportSettingSerializedPropertyWrapper(firstElement, m_PSDLayerImportSetting, null)); + firstElement.Next(false); + } + } if (m_Layers != null) { - PSDNode[] nodes = new PSDNode[m_Layers.Count]; - for(int i = 0; i < m_Layers.Count; ++i) + PSDNode[] nodes = new PSDNode[m_Layers.Length]; + for(int i = 0; i < m_Layers.Length; ++i) { var l = m_Layers[i]; + var importSettingIndex = spWrapper.FindIndex(x => m_MappingStrategy.Compare(x, l)); + PSDLayerImportSettingSerializedPropertyWrapper importSetting = null; + if (importSettingIndex < 0) + { + importSetting = new PSDLayerImportSettingSerializedPropertyWrapper(null, m_PSDLayerImportSetting, l); + } + else + { + importSetting = spWrapper[importSettingIndex]; + spWrapper.RemoveAt(importSettingIndex); + } + if (l!= null && l.isGroup) - nodes[i] = new PSDLayerGroupNode(l, i); + nodes[i] = new PSDLayerGroupNode(l, i, importSetting); else - nodes[i] = new PSDLayerNode(l, i); + nodes[i] = new PSDLayerNode(l, i, importSetting); + var node = nodes[i]; + + node.disable = !node.layer.isVisible; + while (node.layer.parentIndex != -1 && nodes[i].disable == false) + { + if (!node.layer.isVisible || !nodes[node.layer.parentIndex].layer.isVisible) + { + nodes[i].disable = true; + } + + node = nodes[node.layer.parentIndex]; + } } foreach (var node in nodes) { - if (showHidden || node.layer.isVisible) + //if (showHidden || node.layer.isVisible) { if (node.layer.parentIndex == -1) { - root.AddChild(node); + fileRoot.AddChild(node); } else { nodes[node.layer.parentIndex].AddChild(node); - node.disable = nodes[node.layer.parentIndex].layer.flatten || nodes[node.layer.parentIndex].disable; - if(node.layer.flatten) - nodes[node.layer.parentIndex].ChildGroupFlatten(node.layer.flatten); + if(node.flatten) + nodes[node.layer.parentIndex].ChildGroupFlatten(node.flatten); } } } } - if(root.children == null) - root.children = new List(); SetupDepthsFromParentsAndChildren(root); - + SetExpanded(fileRoot.id, true); return root; } - - + protected override void RowGUI(RowGUIArgs args) { var node = (PSDNode)args.item; var rowRect = args.rowRect; + var hover = rowRect.Contains(Event.current.mousePosition); + var a1 = args.focused; + var a2 = args.selected; + if (hover && Event.current.type == EventType.Repaint) + { + args.selected = args.focused = true; + Style.hoverLine.Draw(rowRect, false, false, a2, true); + } using (new EditorGUI.DisabledScope(node.disable)) { - var hover = rowRect.Contains(Event.current.mousePosition); - var a1 = args.focused; - var a2 = args.selected; - if (hover && Event.current.type == EventType.Repaint) + if (node.disable) { - args.selected = args.focused = true; - Style.hoverLine.Draw(rowRect, false, false, a2, true); + var r = new Rect(rowRect.x + args.item.depth * this.depthIndentWidth + this.foldoutWidth + 32, rowRect.y, rowRect.width, rowRect.height); + GUI.Label(r, Style.layerHiddenToolTip); } - base.RowGUI(args); - args.focused = a1; - args.selected = a2; - - if (node.layer != null && !node.layer.isVisible) + } + + args.focused = a1; + args.selected = a2; + + // if (node.layer != null && !node.layer.isVisible) + // { + // //GUI.Box(new Rect(rowRect.x, rowRect.y, Style.iconSize, Style.iconSize), Style.visibilityIcon, Style.flattenToggleStyle); + // } + + if (args.item is PSDLayerGroupNode) + { + var group = (PSDLayerGroupNode)args.item; + Rect toggleRect = new Rect(rowRect.x + args.item.depth * this.depthIndentWidth, rowRect.y, Style.iconSize, Style.iconSize); + GUIContent[] icon = null; + if (group.childFlattenCount != 0) + icon = Style.mergedMix; + if (hover) { - GUI.Box(new Rect(rowRect.x, rowRect.y, Style.iconSize, Style.iconSize), Style.visibilityIcon, Style.flattenToggleStyle); + if(group.flatten) + icon = Style.separateIcon; + else + icon = Style.mergedIcon; } - - if (args.item is PSDLayerGroupNode) + else if(group.flatten) + icon = Style.mergedIcon; + + if (icon != null) { - var group = (PSDLayerGroupNode)args.item; - Rect toggleRect = new Rect(rowRect.x + foldoutWidth + Style.iconPadding + args.item.depth * this.depthIndentWidth, rowRect.y, Style.iconSize, Style.iconSize); + hover = toggleRect.Contains(Event.current.mousePosition); + var iconIndex = args.selected | hover ? 1 : 0; EditorGUI.BeginChangeCheck(); - GUIContent[] icon = null; - if (group.childFlattenCount != 0) - icon = Style.collapseMix; - if (hover) - { - if(group.layer.flatten) - icon = Style.separateIcon; - else - icon = Style.collapsedIcon; - } - else if(group.layer.flatten) - icon = Style.collapsedIcon; - - if (icon != null) - { - var iconIndex = args.selected ? 1 : 0; - group.layer.flatten = GUI.Toggle(toggleRect, group.layer.flatten, icon[iconIndex], Style.flattenToggleStyle); - } - - + var flatten = GUI.Toggle(toggleRect, group.flatten, icon[iconIndex], Style.flattenToggleStyle); if (EditorGUI.EndChangeCheck()) { + group.flatten = flatten; group.FlattenStateChange(); group.NotifyParentOnFlattenChange(); m_HasChanged = true; diff --git a/Editor/PSDLayer.cs b/Editor/PSDLayer.cs index 3db17e4..d5ca859 100644 --- a/Editor/PSDLayer.cs +++ b/Editor/PSDLayer.cs @@ -5,7 +5,7 @@ namespace UnityEditor.U2D.PSD { [Serializable] - class PSDLayer + class PSDLayer : IPSDLayerMappingStrategyComparable { [SerializeField] string m_Name; diff --git a/Editor/PSDLayerMappingStrategy.cs b/Editor/PSDLayerMappingStrategy.cs index 72f631a..d267ad6 100644 --- a/Editor/PSDLayerMappingStrategy.cs +++ b/Editor/PSDLayerMappingStrategy.cs @@ -5,21 +5,38 @@ namespace UnityEditor.U2D.PSD { + internal interface IPSDLayerMappingStrategyComparable + { + int layerID + { + get; + } + + string name + { + get; + } + + bool isGroup + { + get; + } + } + internal interface IPSDLayerMappingStrategy { - bool Compare(PSDLayer a, PSDLayer b); - bool Compare(PSDImporter.FlattenLayerData a, BitmapLayer b); - string LayersUnique(IEnumerable layers); + bool Compare(IPSDLayerMappingStrategyComparable a, IPSDLayerMappingStrategyComparable b); + bool Compare(IPSDLayerMappingStrategyComparable a, BitmapLayer b); + string LayersUnique(IEnumerable layers); } internal abstract class LayerMappingStrategy : IPSDLayerMappingStrategy { string m_DuplicatedStringError = L10n.Tr("The following layers have duplicated identifier."); - protected abstract T GetID(PSDLayer layer); + protected abstract T GetID(IPSDLayerMappingStrategyComparable layer); protected abstract T GetID(BitmapLayer layer); - protected abstract T GetID(PSDImporter.FlattenLayerData layer); - protected virtual bool IsGroup(PSDLayer layer) + protected virtual bool IsGroup(IPSDLayerMappingStrategyComparable layer) { return layer.isGroup; } @@ -29,29 +46,24 @@ protected virtual bool IsGroup(BitmapLayer layer) return layer.IsGroup; } - protected virtual bool IsGroup(PSDImporter.FlattenLayerData layer) - { - return true; - } - - public bool Compare(PSDImporter.FlattenLayerData x, BitmapLayer y) + public bool Compare(IPSDLayerMappingStrategyComparable x, BitmapLayer y) { return Comparer.Default.Compare(GetID(x), GetID(y)) == 0 && IsGroup(x) == IsGroup(y); } - public bool Compare(PSDLayer x, PSDLayer y) + public bool Compare(IPSDLayerMappingStrategyComparable x, IPSDLayerMappingStrategyComparable y) { return Comparer.Default.Compare(GetID(x), GetID(y)) == 0 && IsGroup(x) == IsGroup(y); } - public string LayersUnique(IEnumerable layers) + public string LayersUnique(IEnumerable layers) { var layerNameHash = new HashSet(); var layerGroupHash = new HashSet(); return LayersUnique(layers, layerNameHash, layerGroupHash); } - string LayersUnique(IEnumerable layers, HashSet layerNameHash, HashSet layerGroupHash) + string LayersUnique(IEnumerable layers, HashSet layerNameHash, HashSet layerGroupHash) { List duplicateLayerName = new List(); string duplicatedStringError = null; @@ -76,7 +88,7 @@ string LayersUnique(IEnumerable layers, HashSet layerNameHash, Hash internal class LayerMappingUseLayerName : LayerMappingStrategy { - protected override string GetID(PSDLayer x) + protected override string GetID(IPSDLayerMappingStrategyComparable x) { return x.name.ToLower(); } @@ -85,16 +97,11 @@ protected override string GetID(BitmapLayer x) { return x.Name.ToLower(); } - - protected override string GetID(PSDImporter.FlattenLayerData x) - { - return x.name.ToLower(); - } } internal class LayerMappingUseLayerNameCaseSensitive : LayerMappingStrategy { - protected override string GetID(PSDLayer x) + protected override string GetID(IPSDLayerMappingStrategyComparable x) { return x.name; } @@ -103,16 +110,11 @@ protected override string GetID(BitmapLayer x) { return x.Name; } - - protected override string GetID(PSDImporter.FlattenLayerData x) - { - return x.name; - } } internal class LayerMappingUserLayerID : LayerMappingStrategy { - protected override int GetID(PSDLayer x) + protected override int GetID(IPSDLayerMappingStrategyComparable x) { return x.layerID; } @@ -121,11 +123,6 @@ protected override int GetID(BitmapLayer x) { return x.LayerID; } - - protected override int GetID(PSDImporter.FlattenLayerData x) - { - return x.layerId; - } } } diff --git a/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs b/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs index a6f2521..cc3f423 100644 --- a/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs +++ b/Editor/PSDPlugin/PDNWrapper/BitmapLayer.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Collections.Generic; namespace PDNWrapper diff --git a/Editor/Tasks/ExtractLayerTask.cs b/Editor/Tasks/ExtractLayerTask.cs index 7f518d1..00dfebd 100644 --- a/Editor/Tasks/ExtractLayerTask.cs +++ b/Editor/Tasks/ExtractLayerTask.cs @@ -67,7 +67,7 @@ public unsafe void Execute(int index) } } - public static unsafe void Execute(List extractedLayer, List layers, bool importHiddenLayer, PSDImporter.FlattenLayerData[] previousFlattenLayer, IPSDLayerMappingStrategy mappingStrategy) + public static unsafe void Execute(List extractedLayer, List layers, bool importHiddenLayer, FlattenLayerData[] previousFlattenLayer, IPSDLayerMappingStrategy mappingStrategy) { UnityEngine.Profiling.Profiler.BeginSample("ExtractLayer_PrepareJob"); List layerToExtract = new List(); @@ -112,7 +112,7 @@ public static unsafe void Execute(List extractedLayer, List extractedLayer, List layers, bool importHiddenLayer, bool flatten, List layerExtract, PSDImporter.FlattenLayerData[] previousFlatten, IPSDLayerMappingStrategy mappingStrategy, bool parentGroupVisible) + static (int width, int height) ExtractLayer(List extractedLayer, List layers, bool importHiddenLayer, bool flatten, List layerExtract, FlattenLayerData[] previousFlatten, IPSDLayerMappingStrategy mappingStrategy, bool parentGroupVisible) { // parent is the previous element in extracedLayer int parentGroupIndex = extractedLayer.Count - 1; @@ -124,7 +124,7 @@ public static unsafe void Execute(List extractedLayer, List mappingStrategy.Compare(x, l)) != null; + 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); diff --git a/Third Party Notices.md b/Third Party Notices.md index 765a311..f926b81 100644 --- a/Third Party Notices.md +++ b/Third Party Notices.md @@ -3,17 +3,12 @@ This package contains third-party software components governed by the license(s) Component Name: Photoshop PSD FileType Plugin for Paint.NET -License Type: MIT, BSD - -///////////////////////////////////////////////////////////////////////////////// - -Photoshop PSD FileType Plugin for Paint.NET -http://psdplugin.codeplex.com/ +License Type: MIT Copyright (c) 2006-2007 Frank Blumenberg Copyright (c) 2010-2016 Tao Yue -MIT License: http://www.opensource.org/licenses/mit-license.php +https://www.psdplugin.com/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -33,18 +28,15 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -///////////////////////////////////////////////////////////////////////////////// +-------- +Component Name: Yet Another PSD Parser -Portions of the software have been adapted from Yet Another PSD Parser: - http://www.codeproject.com/KB/graphics/PSDParser.aspx +License Type: BSD -These portions are provided under the BSD License: - http://www.opensource.org/licenses/BSD-3-Clause +Copyright (c) 2006, Jonas Beckeman ----- +http://www.codeproject.com/KB/graphics/PSDParser.aspx -Copyright (c) 2006, Jonas Beckeman -All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -68,5 +60,3 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -///////////////////////////////////////////////////////////////////////////////// diff --git a/package.json b/package.json index addb052..37e6d79 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.unity.2d.psdimporter", - "version": "6.0.0-pre.3", + "version": "6.0.0-pre.4", "unity": "2021.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.\n\nDocumentation for v5.0 is currently being updated.", @@ -11,19 +11,19 @@ ], "category": "2D", "dependencies": { - "com.unity.2d.animation": "7.0.0-pre.2", - "com.unity.2d.common": "6.0.0-pre.3", + "com.unity.2d.animation": "7.0.0-pre.3", + "com.unity.2d.common": "6.0.0-pre.4", "com.unity.2d.sprite": "1.0.0" }, "relatedPackages": { - "com.unity.2d.psdimporter.tests": "6.0.0-pre.3" + "com.unity.2d.psdimporter.tests": "6.0.0-pre.4" }, "upmCi": { - "footprint": "690edb26ee15ca0820923327fcfe7cdce55471cc" + "footprint": "13f980d46f7c3a9b46e997bf6a6e1f1b2161f876" }, "repository": { "url": "https://github.cds.internal.unity3d.com/unity/2d.git", "type": "git", - "revision": "c86c46a25eac9ced170843924a73ec17abb5e115" + "revision": "e8ea646f9ae89420394c390784dae9e45f9f7e2c" } }