#pragma warning disable 0219 using System; using System.Collections.Generic; using UnityEditor.AssetImporters; using UnityEditor.U2D.Aseprite.Common; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; namespace UnityEditor.U2D.Aseprite { [CustomEditor(typeof(AsepriteImporter))] [CanEditMultipleObjects] internal class AsepriteImporterEditor : ScriptedImporterEditor, ITexturePlatformSettingsDataProvider { const string k_BaseFieldAlignedUssClass = "unity-base-field__aligned"; const string k_HiddenElementUssClass = "HiddenElement"; const string k_PaddingElementUssClass = "PaddingElement"; const string k_SubElementUssClass = "SubElement"; const string k_SubSubElementUssClass = "SubSubElement"; // This number is in milliseconds. const long k_PollForChangesInternal = 50; SerializedProperty m_GeneratePhysicsShape; SerializedProperty m_TextureType; SerializedProperty m_TextureShape; SerializedProperty m_SpriteMode; SerializedProperty m_SpritePixelsToUnits; SerializedProperty m_SpriteMeshType; SerializedProperty m_SpriteExtrude; SerializedProperty m_Alignment; SerializedProperty m_SpritePivot; SerializedProperty m_NPOTScale; SerializedProperty m_IsReadable; SerializedProperty m_sRGBTexture; SerializedProperty m_AlphaSource; #if ENABLE_TEXTURE_STREAMING SerializedProperty m_StreamingMipmaps; SerializedProperty m_StreamingMipmapsPriority; #endif SerializedProperty m_MipMapMode; SerializedProperty m_EnableMipMap; SerializedProperty m_FadeOut; SerializedProperty m_BorderMipMap; SerializedProperty m_MipMapsPreserveCoverage; SerializedProperty m_AlphaTestReferenceValue; SerializedProperty m_MipMapFadeDistanceStart; SerializedProperty m_MipMapFadeDistanceEnd; SerializedProperty m_AlphaIsTransparency; SerializedProperty m_FilterMode; SerializedProperty m_Aniso; SerializedProperty m_WrapU; SerializedProperty m_WrapV; SerializedProperty m_WrapW; SerializedProperty m_ConvertToNormalMap; SerializedProperty m_PlatformSettingsArrProp; SerializedProperty m_FileImportMode; SerializedProperty m_ImportHiddenLayers; SerializedProperty m_LayerImportMode; SerializedProperty m_DefaultPivotSpace; SerializedProperty m_DefaultPivotAlignment; SerializedProperty m_CustomPivotPosition; SerializedProperty m_MosaicPadding; SerializedProperty m_SpritePadding; SerializedProperty m_GenerateModelPrefab; SerializedProperty m_AddSortingGroup; SerializedProperty m_AddShadowCasters; SerializedProperty m_GenerateAnimationClips; SerializedProperty m_PrevGenerateAnimationClips; SerializedProperty m_GenerateIndividualEvents; SerializedProperty m_GenerateSpriteAtlas; VisualElement m_RootVisualElement; VisualElement m_InspectorSettingsView; readonly AsepriteImporterEditorFoldOutState m_EditorFoldOutState = new(); bool m_ShowPerAxisWrapModes = false; readonly int[] m_FilterModeOptions = (int[])(Enum.GetValues(typeof(FilterMode))); TexturePlatformSettingsHelper m_TexturePlatformSettingsHelper; VisualElement[] m_InspectorUI; int m_ActiveEditorIndex = 0; bool ITexturePlatformSettingsDataProvider.textureTypeHasMultipleDifferentValues => m_TextureType.hasMultipleDifferentValues; TextureImporterType ITexturePlatformSettingsDataProvider.textureType => (TextureImporterType)m_TextureType.intValue; SpriteImportMode ITexturePlatformSettingsDataProvider.spriteImportMode => spriteImportMode; FileImportModes fileImportMode => (FileImportModes)m_FileImportMode.intValue; SpriteImportMode spriteImportMode => (SpriteImportMode)m_SpriteMode.intValue; AnimationClip m_DefaultClip; ModelPreviewer m_ModelPreviewer; AsepriteImporter[] m_ImporterTargets; string[] m_AssetPaths; /// /// The SerializedProperty of an array of TextureImporterPlatformSettings. /// public SerializedProperty platformSettingsArray => m_PlatformSettingsArrProp; public override bool showImportedObject => false; public override bool UseDefaultMargins() => false; /// /// Implementation of AssetImporterEditor.OnEnable /// public override void OnEnable() { base.OnEnable(); CacheImporterData(); InitPreview(); } /// /// Implementation of virtual method CreateInspectorGUI. /// /// VisualElement container for Inspector visual. public override VisualElement CreateInspectorGUI() { CacheSerializedProperties(); SetupInspectorUI(); m_RootVisualElement = new VisualElement() { name = "Root" }; var styleSheet = EditorGUIUtility.Load("packages/com.unity.2d.aseprite/Editor/Assets/UI/AsepriteImporterStyleSheet.uss") as StyleSheet; m_RootVisualElement.styleSheets.Add(styleSheet); m_InspectorSettingsView = new VisualElement() { name = "InspectorSettings" }; m_RootVisualElement.Add(m_InspectorSettingsView); ShowInspectorTab(m_ActiveEditorIndex); return m_RootVisualElement; } /// /// Implementation of AssetImporterEditor.OnDisable /// public override void OnDisable() { base.OnDisable(); DisposePreview(); if (m_RootVisualElement != null) m_RootVisualElement.Clear(); } void CacheImporterData() { m_ImporterTargets = new AsepriteImporter[targets.Length]; m_AssetPaths = new string[targets.Length]; for (var i = 0; i < targets.Length; ++i) { var importer = (AsepriteImporter)targets[i]; m_ImporterTargets[i] = importer; m_AssetPaths[i] = importer.assetPath; } } void CacheSerializedProperties() { m_GeneratePhysicsShape = serializedObject.FindProperty("m_GeneratePhysicsShape"); var textureImporterSettingsSP = serializedObject.FindProperty("m_TextureImporterSettings"); m_TextureType = textureImporterSettingsSP.FindPropertyRelative("m_TextureType"); m_TextureShape = textureImporterSettingsSP.FindPropertyRelative("m_TextureShape"); m_ConvertToNormalMap = textureImporterSettingsSP.FindPropertyRelative("m_ConvertToNormalMap"); m_SpriteMode = textureImporterSettingsSP.FindPropertyRelative("m_SpriteMode"); m_SpritePixelsToUnits = textureImporterSettingsSP.FindPropertyRelative("m_SpritePixelsToUnits"); m_SpriteMeshType = textureImporterSettingsSP.FindPropertyRelative("m_SpriteMeshType"); m_SpriteExtrude = textureImporterSettingsSP.FindPropertyRelative("m_SpriteExtrude"); m_Alignment = textureImporterSettingsSP.FindPropertyRelative("m_Alignment"); m_SpritePivot = textureImporterSettingsSP.FindPropertyRelative("m_SpritePivot"); m_NPOTScale = textureImporterSettingsSP.FindPropertyRelative("m_NPOTScale"); m_IsReadable = textureImporterSettingsSP.FindPropertyRelative("m_IsReadable"); m_sRGBTexture = textureImporterSettingsSP.FindPropertyRelative("m_sRGBTexture"); m_AlphaSource = textureImporterSettingsSP.FindPropertyRelative("m_AlphaSource"); #if ENABLE_TEXTURE_STREAMING m_StreamingMipmaps = textureImporterSettingsSP.FindPropertyRelative("m_StreamingMipmaps"); m_StreamingMipmapsPriority = textureImporterSettingsSP.FindPropertyRelative("m_StreamingMipmapsPriority"); #endif m_MipMapMode = textureImporterSettingsSP.FindPropertyRelative("m_MipMapMode"); m_EnableMipMap = textureImporterSettingsSP.FindPropertyRelative("m_EnableMipMap"); m_FadeOut = textureImporterSettingsSP.FindPropertyRelative("m_FadeOut"); m_BorderMipMap = textureImporterSettingsSP.FindPropertyRelative("m_BorderMipMap"); m_MipMapsPreserveCoverage = textureImporterSettingsSP.FindPropertyRelative("m_MipMapsPreserveCoverage"); m_AlphaTestReferenceValue = textureImporterSettingsSP.FindPropertyRelative("m_AlphaTestReferenceValue"); m_MipMapFadeDistanceStart = textureImporterSettingsSP.FindPropertyRelative("m_MipMapFadeDistanceStart"); m_MipMapFadeDistanceEnd = textureImporterSettingsSP.FindPropertyRelative("m_MipMapFadeDistanceEnd"); m_AlphaIsTransparency = textureImporterSettingsSP.FindPropertyRelative("m_AlphaIsTransparency"); m_FilterMode = textureImporterSettingsSP.FindPropertyRelative("m_FilterMode"); m_Aniso = textureImporterSettingsSP.FindPropertyRelative("m_Aniso"); m_WrapU = textureImporterSettingsSP.FindPropertyRelative("m_WrapU"); m_WrapV = textureImporterSettingsSP.FindPropertyRelative("m_WrapV"); m_WrapW = textureImporterSettingsSP.FindPropertyRelative("m_WrapW"); m_PlatformSettingsArrProp = extraDataSerializedObject.FindProperty("platformSettings"); var asepriteImporterSettings = serializedObject.FindProperty("m_AsepriteImporterSettings"); m_FileImportMode = asepriteImporterSettings.FindPropertyRelative("m_FileImportMode"); m_ImportHiddenLayers = asepriteImporterSettings.FindPropertyRelative("m_ImportHiddenLayers"); m_LayerImportMode = asepriteImporterSettings.FindPropertyRelative("m_LayerImportMode"); m_DefaultPivotSpace = asepriteImporterSettings.FindPropertyRelative("m_DefaultPivotSpace"); m_DefaultPivotAlignment = asepriteImporterSettings.FindPropertyRelative("m_DefaultPivotAlignment"); m_CustomPivotPosition = asepriteImporterSettings.FindPropertyRelative("m_CustomPivotPosition"); m_MosaicPadding = asepriteImporterSettings.FindPropertyRelative("m_MosaicPadding"); m_SpritePadding = asepriteImporterSettings.FindPropertyRelative("m_SpritePadding"); m_GenerateModelPrefab = asepriteImporterSettings.FindPropertyRelative("m_GenerateModelPrefab"); m_AddSortingGroup = asepriteImporterSettings.FindPropertyRelative("m_AddSortingGroup"); m_AddShadowCasters = asepriteImporterSettings.FindPropertyRelative("m_AddShadowCasters"); m_GenerateAnimationClips = asepriteImporterSettings.FindPropertyRelative("m_GenerateAnimationClips"); m_GenerateIndividualEvents = asepriteImporterSettings.FindPropertyRelative("m_GenerateIndividualEvents"); m_GenerateSpriteAtlas = asepriteImporterSettings.FindPropertyRelative("m_GenerateSpriteAtlas"); var prevAsepriteImporterSettings = serializedObject.FindProperty("m_PreviousAsepriteImporterSettings"); m_PrevGenerateAnimationClips = prevAsepriteImporterSettings.FindPropertyRelative("m_GenerateAnimationClips"); m_TexturePlatformSettingsHelper = new TexturePlatformSettingsHelper(this); } void SetupInspectorUI() { m_InspectorUI = new[] { SetupSpriteActorContainer() }; m_ActiveEditorIndex = Mathf.Max(EditorPrefs.GetInt(this.GetType().Name + "ActiveEditorIndex", 0), 0); m_ActiveEditorIndex %= m_InspectorUI.Length; } VisualElement SetupSpriteActorContainer() { var spriteActorContainer = new VisualElement() { name = "SpriteActorContainer" }; SetupGeneralContainer(spriteActorContainer); SetupLayerImportContainer(spriteActorContainer); SetupGenerateAssetContainer(spriteActorContainer); SetupCommonTextureSettingsContainer(spriteActorContainer); SetupPlatformSettingsContainer(spriteActorContainer); SetupAdvancedContainer(spriteActorContainer); var applyRevertContainer = new IMGUIContainer(ApplyRevertGUI); spriteActorContainer.Add(applyRevertContainer); return spriteActorContainer; } void SetupGeneralContainer(VisualElement root) { var foldOut = new Foldout() { text = styles.generalHeaderText.text, tooltip = styles.generalHeaderText.tooltip, value = m_EditorFoldOutState.generalFoldout }; ImporterEditorUtils.AddSkinUssClass(foldOut.Q()); foldOut.RegisterValueChangedCallback(_ => { m_EditorFoldOutState.generalFoldout = foldOut.value; }); root.Add(foldOut); var importModeField = new PropertyField(m_FileImportMode, styles.fileImportMode.text) { tooltip = styles.fileImportMode.tooltip }; importModeField.Bind(serializedObject); foldOut.Add(importModeField); var ppuField = new PropertyField(m_SpritePixelsToUnits, styles.spritePixelsPerUnit.text) { tooltip = styles.spritePixelsPerUnit.tooltip }; ppuField.Bind(serializedObject); ppuField.RegisterValueChangeCallback(x => { m_SpritePixelsToUnits.floatValue = Mathf.Max(m_SpritePixelsToUnits.floatValue, 1f); serializedObject.ApplyModifiedProperties(); }); foldOut.Add(ppuField); var meshField = new PopupField(styles.spriteMeshTypeOptions, m_SpriteMeshType.intValue) { label = styles.spriteMeshType.text, tooltip = styles.spriteMeshType.tooltip }; meshField.AddToClassList(k_BaseFieldAlignedUssClass); meshField.RegisterValueChangedCallback(x => { m_SpriteMeshType.intValue = meshField.index; serializedObject.ApplyModifiedProperties(); }); foldOut.Add(meshField); var physicsShapeField = new PropertyField(m_GeneratePhysicsShape, styles.generatePhysicsShape.text) { tooltip = styles.generatePhysicsShape.tooltip }; physicsShapeField.Bind(serializedObject); foldOut.Add(physicsShapeField); SetupSpriteEditorButton(foldOut); var paddingElement = new VisualElement() { name = "PaddingElement" }; paddingElement.AddToClassList(k_PaddingElementUssClass); foldOut.Add(paddingElement); } void SetupSpriteEditorButton(VisualElement root) { var spriteEditorBtn = new Button() { text = styles.spriteEditorButtonLabel.text }; root.Add(spriteEditorBtn); spriteEditorBtn.SetEnabled(CanOpenSpriteEditor()); spriteEditorBtn.clicked += () => { if (HasModified()) { // To ensure Sprite Editor Window to have the latest texture import setting, // We must applied those modified values first. var dialogText = string.Format(s_Styles.unappliedSettingsDialogContent.text, ((AssetImporter)target).assetPath); if (EditorUtility.DisplayDialog(s_Styles.unappliedSettingsDialogTitle.text, dialogText, s_Styles.applyButtonLabel.text, s_Styles.cancelButtonLabel.text)) { SaveChanges(); InternalEditorBridge.ShowSpriteEditorWindow(this.assetTarget); // We re-imported the asset which destroyed the editor, so we can't keep running the UI here. GUIUtility.ExitGUI(); } } else { InternalEditorBridge.ShowSpriteEditorWindow(this.assetTarget); } }; } bool CanOpenSpriteEditor() { return m_ImporterTargets.Length == 1 && m_ImporterTargets[0].textureActualWidth > 0; } void SetupLayerImportContainer(VisualElement root) { var foldOut = new Foldout() { text = styles.layerImportHeaderText.text, tooltip = styles.layerImportHeaderText.tooltip, value = m_EditorFoldOutState.layerImportFoldout }; ImporterEditorUtils.AddSkinUssClass(foldOut.Q()); foldOut.RegisterValueChangedCallback(_ => { m_EditorFoldOutState.layerImportFoldout = foldOut.value; }); root.Add(foldOut); var hiddenLayersField = new PropertyField(m_ImportHiddenLayers, styles.importHiddenLayer.text) { tooltip = styles.importHiddenLayer.tooltip }; hiddenLayersField.schedule.Execute(() => { var shouldShow = fileImportMode is FileImportModes.AnimatedSprite or FileImportModes.SpriteSheet; if (hiddenLayersField.visible != shouldShow) { hiddenLayersField.visible = shouldShow; hiddenLayersField.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); hiddenLayersField.Bind(serializedObject); foldOut.Add(hiddenLayersField); var layerModePopup = new PopupField(s_Styles.layerImportOptions, m_LayerImportMode.intValue) { label = s_Styles.layerImportMode.text, tooltip = s_Styles.layerImportMode.tooltip }; layerModePopup.RegisterValueChangedCallback(_ => { m_LayerImportMode.intValue = layerModePopup.index; serializedObject.ApplyModifiedProperties(); }); layerModePopup.schedule.Execute(() => { var shouldShow = fileImportMode is FileImportModes.AnimatedSprite; if (layerModePopup.visible != shouldShow) { layerModePopup.visible = shouldShow; layerModePopup.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); layerModePopup.AddToClassList(k_BaseFieldAlignedUssClass); foldOut.Add(layerModePopup); var pivotSpaceField = new PropertyField(m_DefaultPivotSpace, styles.defaultPivotSpace.text) { tooltip = styles.defaultPivotSpace.tooltip }; pivotSpaceField.Bind(serializedObject); pivotSpaceField.schedule.Execute(() => { var shouldShow = fileImportMode == FileImportModes.AnimatedSprite; if (pivotSpaceField.visible != shouldShow) { pivotSpaceField.visible = shouldShow; pivotSpaceField.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); foldOut.Add(pivotSpaceField); var pivotAlignmentPopup = new PopupField(s_Styles.spriteAlignmentOptions, m_DefaultPivotAlignment.intValue) { label = s_Styles.defaultPivotAlignment.text, tooltip = s_Styles.defaultPivotAlignment.tooltip }; pivotAlignmentPopup.RegisterValueChangedCallback(x => { m_DefaultPivotAlignment.intValue = pivotAlignmentPopup.index; serializedObject.ApplyModifiedProperties(); }); pivotAlignmentPopup.AddToClassList(k_BaseFieldAlignedUssClass); pivotAlignmentPopup.schedule.Execute(() => { var shouldShow = fileImportMode == FileImportModes.AnimatedSprite; if (pivotAlignmentPopup.visible != shouldShow) { pivotAlignmentPopup.visible = shouldShow; pivotAlignmentPopup.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); foldOut.Add(pivotAlignmentPopup); var shouldShow = (SpriteAlignment)pivotAlignmentPopup.index == SpriteAlignment.Custom; var customPivotField = new PropertyField(m_CustomPivotPosition, styles.customPivotPosition.text) { tooltip = styles.customPivotPosition.tooltip, visible = shouldShow }; customPivotField.Bind(serializedObject); customPivotField.EnableInClassList(k_HiddenElementUssClass, !shouldShow); customPivotField.schedule.Execute(x => { var isShowing = (SpriteAlignment)pivotAlignmentPopup.index == SpriteAlignment.Custom; if (customPivotField.visible != isShowing) { customPivotField.visible = isShowing; customPivotField.EnableInClassList(k_HiddenElementUssClass, !isShowing); } }).Every(k_PollForChangesInternal); foldOut.Add(customPivotField); var mosaicPaddingField = new PropertyField(m_MosaicPadding, styles.mosaicPadding.text) { tooltip = styles.mosaicPadding.tooltip }; mosaicPaddingField.Bind(serializedObject); foldOut.Add(mosaicPaddingField); var spritePaddingField = new PropertyField(m_SpritePadding, styles.spritePadding.text) { tooltip = styles.spritePadding.tooltip }; spritePaddingField.Bind(serializedObject); spritePaddingField.schedule.Execute(() => { var isShowing = fileImportMode == FileImportModes.AnimatedSprite; if (spritePaddingField.visible != isShowing) { spritePaddingField.visible = isShowing; spritePaddingField.EnableInClassList(k_HiddenElementUssClass, !isShowing); } }).Every(k_PollForChangesInternal); foldOut.Add(spritePaddingField); var paddingElement = new VisualElement() { name = "PaddingElement" }; paddingElement.AddToClassList(k_PaddingElementUssClass); foldOut.Add(paddingElement); } void SetupGenerateAssetContainer(VisualElement root) { // Generate Assets foldout var foldOut = new Foldout() { text = styles.generateAssetsHeaderText.text, tooltip = styles.generateAssetsHeaderText.tooltip, value = m_EditorFoldOutState.generateAssetFoldout }; ImporterEditorUtils.AddSkinUssClass(foldOut.Q()); foldOut.RegisterValueChangedCallback(_ => { m_EditorFoldOutState.generateAssetFoldout = foldOut.value; }); foldOut.schedule.Execute(() => { var shouldShow = fileImportMode is FileImportModes.AnimatedSprite; //or FileImportModes.TileSet; if (foldOut.visible != shouldShow) { foldOut.visible = shouldShow; foldOut.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); root.Add(foldOut); var animatedSpritesParent = new VisualElement() { name = "AnimatedSpritesParent" }; animatedSpritesParent.schedule.Execute(() => { var shouldShow = fileImportMode is FileImportModes.AnimatedSprite; if (animatedSpritesParent.visible != shouldShow) { animatedSpritesParent.visible = shouldShow; animatedSpritesParent.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); foldOut.Add(animatedSpritesParent); SetupGenerateAssetsForAnimatedSprites(animatedSpritesParent); /* var tileSetParent = new VisualElement(); tileSetParent.schedule.Execute(() => { var shouldShow = fileImportMode is FileImportModes.TileSet; if (tileSetParent.visible != shouldShow) { tileSetParent.visible = shouldShow; tileSetParent.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); foldOut.Add(tileSetParent); SetupGeneratedAssetsForTileSet(tileSetParent); */ // Footer element var paddingElement = new VisualElement() { name = "PaddingElement" }; paddingElement.AddToClassList(k_PaddingElementUssClass); foldOut.Add(paddingElement); } void SetupGenerateAssetsForAnimatedSprites(VisualElement parent) { #if ENABLE_URP const bool isUrpEnabled = true; #else const bool isUrpEnabled = false; #endif // Generate model prefab toggle var generateModelField = new PropertyField(m_GenerateModelPrefab, styles.generateModelPrefab.text) { tooltip = styles.generateModelPrefab.tooltip }; generateModelField.Bind(serializedObject); parent.Add(generateModelField); // Add "sorting group"-component var isSortingEnabled = m_GenerateModelPrefab.boolValue; var sortingGroupField = new PropertyField(m_AddSortingGroup, styles.addSortingGroup.text) { tooltip = styles.addSortingGroup.tooltip }; sortingGroupField.Bind(serializedObject); sortingGroupField.AddToClassList(k_SubElementUssClass); sortingGroupField.SetEnabled(isSortingEnabled); sortingGroupField.schedule.Execute(() => { isSortingEnabled = m_GenerateModelPrefab.boolValue; if (sortingGroupField.enabledSelf != isSortingEnabled) sortingGroupField.SetEnabled(isSortingEnabled); }).Every(k_PollForChangesInternal); parent.Add(sortingGroupField); // Add "shadow caster"-component var areShadowsEnabled = isUrpEnabled && m_GenerateModelPrefab.boolValue; var shadowCasterField = new PropertyField(m_AddShadowCasters, styles.addShadowCasters.text) { tooltip = styles.addShadowCasters.tooltip }; shadowCasterField.Bind(serializedObject); shadowCasterField.AddToClassList(k_SubElementUssClass); shadowCasterField.SetEnabled(areShadowsEnabled); shadowCasterField.schedule.Execute(() => { areShadowsEnabled = isUrpEnabled && m_GenerateModelPrefab.boolValue; if (shadowCasterField.enabledSelf != areShadowsEnabled) shadowCasterField.SetEnabled(areShadowsEnabled); }).Every(k_PollForChangesInternal); parent.Add(shadowCasterField); // Generate animation clips toggle var generateClipsField = new PropertyField(m_GenerateAnimationClips, styles.generateAnimationClips.text) { tooltip = styles.generateAnimationClips.tooltip }; generateClipsField.Bind(serializedObject); parent.Add(generateClipsField); // Generate individual animation events toggle var isIndividualEventsEnabled = m_GenerateAnimationClips.boolValue; var generateIndividualEventsField = new PropertyField(m_GenerateIndividualEvents, styles.generateIndividualEvents.text) { tooltip = styles.generateIndividualEvents.tooltip }; generateIndividualEventsField.Bind(serializedObject); generateIndividualEventsField.AddToClassList(k_SubElementUssClass); generateIndividualEventsField.SetEnabled(isIndividualEventsEnabled); generateIndividualEventsField.schedule.Execute(() => { isIndividualEventsEnabled = m_GenerateAnimationClips.boolValue; if (generateIndividualEventsField.enabledSelf != isIndividualEventsEnabled) generateIndividualEventsField.SetEnabled(isIndividualEventsEnabled); }).Every(k_PollForChangesInternal); parent.Add(generateIndividualEventsField); SetupAnimationAssetsButton(parent); } void SetupGeneratedAssetsForTileSet(VisualElement parent) { var generateSpriteAtlasField = new PropertyField(m_GenerateSpriteAtlas, styles.generateSpriteAtlas.text) { tooltip = styles.generateSpriteAtlas.tooltip }; generateSpriteAtlasField.Bind(serializedObject); parent.Add(generateSpriteAtlasField); } void SetupAnimationAssetsButton(VisualElement root) { var isEnabled = m_ImporterTargets.Length == 1 && m_DefaultClip != null && m_GenerateAnimationClips.boolValue; var assetsBtn = new Button() { text = styles.exportAnimationAssetsText.text }; assetsBtn.SetEnabled(isEnabled); assetsBtn.schedule.Execute(() => { isEnabled = m_ImporterTargets.Length == 1 && m_DefaultClip != null && m_GenerateAnimationClips.boolValue; if (assetsBtn.enabledSelf != isEnabled) assetsBtn.SetEnabled(isEnabled); }).Every(k_PollForChangesInternal); assetsBtn.clicked += () => { var window = EditorWindow.GetWindow(); window.ShowExportPopup(this, m_ImporterTargets); }; root.Add(assetsBtn); var helpBox = new HelpBox(styles.exportAnimationInfoText.text, HelpBoxMessageType.Info); helpBox.visible = m_GenerateAnimationClips.boolValue && !m_PrevGenerateAnimationClips.boolValue; helpBox.EnableInClassList(k_HiddenElementUssClass, !helpBox.visible); helpBox.schedule.Execute(() => { // If the Generate Animation Clips checkbox has been checked, but not yet applied. var isVisible = m_GenerateAnimationClips.boolValue && !m_PrevGenerateAnimationClips.boolValue; if (helpBox.visible != isVisible) { helpBox.visible = isVisible; helpBox.EnableInClassList(k_HiddenElementUssClass, !isVisible); } }).Every(k_PollForChangesInternal); root.Add(helpBox); } void SetupCommonTextureSettingsContainer(VisualElement root) { var foldOut = new Foldout() { text = styles.textureHeaderText.text, tooltip = styles.textureHeaderText.tooltip, value = m_EditorFoldOutState.textureFoldout }; ImporterEditorUtils.AddSkinUssClass(foldOut.Q()); foldOut.RegisterValueChangedCallback(_ => { m_EditorFoldOutState.textureFoldout = foldOut.value; }); root.Add(foldOut); var imguiContainer = new IMGUIContainer(() => { serializedObject.Update(); extraDataSerializedObject.Update(); EditorGUI.BeginChangeCheck(); // Wrap mode var isVolume = false; WrapModePopup(m_WrapU, m_WrapV, m_WrapW, isVolume, ref m_ShowPerAxisWrapModes); // Display warning about repeat wrap mode on restricted npot emulation if (m_NPOTScale.intValue == (int)TextureImporterNPOTScale.None && (m_WrapU.intValue == (int)TextureWrapMode.Repeat || m_WrapV.intValue == (int)TextureWrapMode.Repeat) && !InternalEditorBridge.DoesHardwareSupportsFullNPOT()) { var displayWarning = false; foreach (var importer in m_ImporterTargets) { var w = importer.textureActualWidth; var h = importer.textureActualHeight; if (!Mathf.IsPowerOfTwo(w) || !Mathf.IsPowerOfTwo(h)) { displayWarning = true; break; } } if (displayWarning) { EditorGUILayout.HelpBox(styles.warpNotSupportWarning.text, MessageType.Warning, true); } } // Filter mode EditorGUI.showMixedValue = m_FilterMode.hasMultipleDifferentValues; var filter = (FilterMode)m_FilterMode.intValue; if ((int)filter == -1) { if (m_FadeOut.intValue > 0 || m_ConvertToNormalMap.intValue > 0) filter = FilterMode.Trilinear; else filter = FilterMode.Bilinear; } filter = (FilterMode)EditorGUILayout.IntPopup(styles.filterMode, (int)filter, styles.filterModeOptions, m_FilterModeOptions); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) { m_FilterMode.intValue = (int)filter; m_FilterMode.serializedObject.ApplyModifiedProperties(); } // Aniso var showAniso = (FilterMode)m_FilterMode.intValue != FilterMode.Point && m_EnableMipMap.intValue > 0 && (TextureImporterShape)m_TextureShape.intValue != TextureImporterShape.TextureCube; using (new EditorGUI.DisabledScope(!showAniso)) { EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = m_Aniso.hasMultipleDifferentValues; int aniso = m_Aniso.intValue; if (aniso == -1) aniso = 1; aniso = EditorGUILayout.IntSlider(styles.anisoLevelLabel, aniso, 0, 16); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) { m_Aniso.intValue = aniso; m_Aniso.serializedObject.ApplyModifiedProperties(); } if (aniso > 1) { if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.Disable) EditorGUILayout.HelpBox(styles.anisotropicDisableInfo.text, MessageType.Info); else if (QualitySettings.anisotropicFiltering == AnisotropicFiltering.ForceEnable) EditorGUILayout.HelpBox(styles.anisotropicForceEnableInfo.text, MessageType.Info); } } GUILayout.Space(5); serializedObject.ApplyModifiedProperties(); extraDataSerializedObject.ApplyModifiedProperties(); }); foldOut.Add(imguiContainer); } void SetupPlatformSettingsContainer(VisualElement root) { var foldOut = new Foldout() { text = styles.platformSettingsHeaderText.text, tooltip = styles.platformSettingsHeaderText.tooltip, value = m_EditorFoldOutState.platformSettingsFoldout }; ImporterEditorUtils.AddSkinUssClass(foldOut.Q()); foldOut.RegisterValueChangedCallback(_ => { m_EditorFoldOutState.platformSettingsFoldout = foldOut.value; }); root.Add(foldOut); var imguiContainer = new IMGUIContainer(() => { serializedObject.Update(); extraDataSerializedObject.Update(); GUILayout.Space(5); m_TexturePlatformSettingsHelper.ShowPlatformSpecificSettings(); GUILayout.Space(5); serializedObject.ApplyModifiedProperties(); extraDataSerializedObject.ApplyModifiedProperties(); }); foldOut.Add(imguiContainer); } void SetupAdvancedContainer(VisualElement root) { if (m_TextureType.hasMultipleDifferentValues) return; var foldOut = new Foldout() { text = styles.advancedHeaderText.text, tooltip = styles.advancedHeaderText.tooltip, value = m_EditorFoldOutState.advancedFoldout }; ImporterEditorUtils.AddSkinUssClass(foldOut.Q()); foldOut.RegisterValueChangedCallback(_ => { m_EditorFoldOutState.advancedFoldout = foldOut.value; }); root.Add(foldOut); // sRGB Toggle var srgbToggle = new Toggle(styles.sRGBTexture.text) { value = m_sRGBTexture.intValue > 0, tooltip = styles.sRGBTexture.tooltip, }; srgbToggle.AddToClassList(k_BaseFieldAlignedUssClass); srgbToggle.RegisterValueChangedCallback(_ => { m_sRGBTexture.intValue = srgbToggle.value ? 1 : 0; m_sRGBTexture.serializedObject.ApplyModifiedProperties(); }); foldOut.Add(srgbToggle); // AlphaSource Enum var alphaSourceEnum = new EnumField(styles.alphaSource.text, TextureImporterAlphaSource.FromInput) { value = (TextureImporterAlphaSource)m_AlphaSource.intValue, tooltip = styles.alphaSource.tooltip }; alphaSourceEnum.AddToClassList(k_BaseFieldAlignedUssClass); alphaSourceEnum.RegisterValueChangedCallback(_ => { m_AlphaSource.intValue = (int)(TextureImporterAlphaSource)alphaSourceEnum.value; m_AlphaSource.serializedObject.ApplyModifiedProperties(); }); foldOut.Add(alphaSourceEnum); // AlphaIsTransparency Toggle var alphaIsTransparencyToggle = new Toggle(styles.alphaIsTransparency.text) { value = m_AlphaIsTransparency.intValue > 0, tooltip = styles.alphaIsTransparency.tooltip, }; alphaIsTransparencyToggle.AddToClassList(k_BaseFieldAlignedUssClass); alphaIsTransparencyToggle.RegisterValueChangedCallback(_ => { m_AlphaIsTransparency.intValue = alphaIsTransparencyToggle.value ? 1 : 0; m_AlphaIsTransparency.serializedObject.ApplyModifiedProperties(); }); var showAlphaIsTransparency = (TextureImporterAlphaSource)m_AlphaSource.intValue != TextureImporterAlphaSource.None; alphaIsTransparencyToggle.SetEnabled(showAlphaIsTransparency); alphaIsTransparencyToggle.schedule.Execute(() => { showAlphaIsTransparency = (TextureImporterAlphaSource)m_AlphaSource.intValue != TextureImporterAlphaSource.None; if (alphaIsTransparencyToggle.enabledSelf != showAlphaIsTransparency) alphaIsTransparencyToggle.SetEnabled(showAlphaIsTransparency); }).Every(k_PollForChangesInternal); foldOut.Add(alphaIsTransparencyToggle); // Read/Write Enabled Toggle var readWriteToggle = new Toggle(styles.readWrite.text) { value = m_IsReadable.intValue > 0, tooltip = styles.readWrite.tooltip, }; readWriteToggle.AddToClassList(k_BaseFieldAlignedUssClass); readWriteToggle.RegisterValueChangedCallback(_ => { m_IsReadable.intValue = readWriteToggle.value ? 1 : 0; m_IsReadable.serializedObject.ApplyModifiedProperties(); }); foldOut.Add(readWriteToggle); // MipMap Toggle var mipmapToggle = new Toggle(styles.generateMipMaps.text) { value = m_EnableMipMap.intValue > 0, tooltip = styles.generateMipMaps.tooltip, }; mipmapToggle.AddToClassList(k_BaseFieldAlignedUssClass); mipmapToggle.RegisterValueChangedCallback(_ => { m_EnableMipMap.intValue = mipmapToggle.value ? 1 : 0; m_EnableMipMap.serializedObject.ApplyModifiedProperties(); }); foldOut.Add(mipmapToggle); // MipMap container var mipMapOptionContainer = new VisualElement(); mipMapOptionContainer.schedule.Execute(() => { var shouldShow = mipmapToggle.value; if (mipMapOptionContainer.visible != shouldShow) { mipMapOptionContainer.visible = shouldShow; mipMapOptionContainer.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); foldOut.Add(mipMapOptionContainer); // Border MipMap Toggle var borderToggle = new Toggle(styles.borderMipMaps.text) { value = m_BorderMipMap.intValue > 0, tooltip = styles.borderMipMaps.tooltip, }; borderToggle.AddToClassList(k_BaseFieldAlignedUssClass); borderToggle.AddToClassList(k_SubElementUssClass); borderToggle.RegisterValueChangedCallback(_ => { m_BorderMipMap.intValue = borderToggle.value ? 1 : 0; m_BorderMipMap.serializedObject.ApplyModifiedProperties(); }); mipMapOptionContainer.Add(borderToggle); #if ENABLE_TEXTURE_STREAMING // Streaming Toggle var streamingToggle = new Toggle(styles.streamingMipMaps.text) { value = m_StreamingMipmaps.intValue > 0, tooltip = styles.streamingMipMaps.tooltip, }; streamingToggle.AddToClassList(k_BaseFieldAlignedUssClass); streamingToggle.AddToClassList(k_SubElementUssClass); streamingToggle.RegisterValueChangedCallback(_ => { m_StreamingMipmaps.intValue = streamingToggle.value ? 1 : 0; m_StreamingMipmaps.serializedObject.ApplyModifiedProperties(); }); mipMapOptionContainer.Add(streamingToggle); // Streaming Priority Field var streamingPriorityField = new PropertyField(m_StreamingMipmapsPriority, styles.streamingMipmapsPriority.text) { tooltip = styles.streamingMipmapsPriority.tooltip, }; streamingPriorityField.AddToClassList(k_BaseFieldAlignedUssClass); streamingPriorityField.AddToClassList(k_SubSubElementUssClass); streamingPriorityField.RegisterValueChangeCallback(x => { m_StreamingMipmapsPriority.intValue = Mathf.Clamp(m_StreamingMipmapsPriority.intValue, -128, 127); m_StreamingMipmapsPriority.serializedObject.ApplyModifiedProperties(); }); streamingPriorityField.schedule.Execute(() => { var shouldShow = streamingToggle.value; if (streamingPriorityField.visible != shouldShow) { streamingPriorityField.visible = shouldShow; streamingPriorityField.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); mipMapOptionContainer.Add(streamingPriorityField); #endif // Mip Map Filtering Enum var mipmapModeEnum = new EnumField(styles.mipMapFilter.text, TextureImporterMipFilter.BoxFilter) { value = (TextureImporterMipFilter)m_MipMapMode.intValue, tooltip = styles.mipMapFilter.tooltip }; mipmapModeEnum.AddToClassList(k_BaseFieldAlignedUssClass); mipmapModeEnum.AddToClassList(k_SubElementUssClass); mipmapModeEnum.RegisterValueChangedCallback(_ => { m_MipMapMode.intValue = (int)(TextureImporterMipFilter)mipmapModeEnum.value; m_MipMapMode.serializedObject.ApplyModifiedProperties(); }); mipMapOptionContainer.Add(mipmapModeEnum); // Preserve Coverage Toggle var preserveCoverageToggle = new Toggle(styles.mipMapsPreserveCoverage.text) { value = m_MipMapsPreserveCoverage.intValue > 0, tooltip = styles.mipMapsPreserveCoverage.tooltip, }; preserveCoverageToggle.AddToClassList(k_BaseFieldAlignedUssClass); preserveCoverageToggle.AddToClassList(k_SubElementUssClass); preserveCoverageToggle.RegisterValueChangedCallback(_ => { m_MipMapsPreserveCoverage.intValue = preserveCoverageToggle.value ? 1 : 0; m_MipMapsPreserveCoverage.serializedObject.ApplyModifiedProperties(); }); mipMapOptionContainer.Add(preserveCoverageToggle); // Alpha Cutoff Field var alphaCutoffField = new PropertyField(m_AlphaTestReferenceValue, styles.alphaTestReferenceValue.text) { tooltip = styles.alphaTestReferenceValue.tooltip, }; alphaCutoffField.AddToClassList(k_BaseFieldAlignedUssClass); alphaCutoffField.AddToClassList(k_SubSubElementUssClass); alphaCutoffField.schedule.Execute(() => { var shouldShow = preserveCoverageToggle.value; if (alphaCutoffField.visible != shouldShow) { alphaCutoffField.visible = shouldShow; alphaCutoffField.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); mipMapOptionContainer.Add(alphaCutoffField); // Fade Out Toggle var fadeOutToggle = new Toggle(styles.mipmapFadeOutToggle.text) { value = m_FadeOut.intValue > 0, tooltip = styles.mipmapFadeOutToggle.tooltip, }; fadeOutToggle.AddToClassList(k_BaseFieldAlignedUssClass); fadeOutToggle.AddToClassList(k_SubElementUssClass); fadeOutToggle.RegisterValueChangedCallback(_ => { m_FadeOut.intValue = fadeOutToggle.value ? 1 : 0; m_FadeOut.serializedObject.ApplyModifiedProperties(); }); mipMapOptionContainer.Add(fadeOutToggle); // Fade Distance Slider var fadeDistanceSlider = new MinMaxSlider(styles.mipmapFadeOut.text, m_MipMapFadeDistanceStart.intValue, m_MipMapFadeDistanceEnd.intValue, 0, 10) { tooltip = styles.mipmapFadeOut.tooltip }; fadeDistanceSlider.AddToClassList(k_BaseFieldAlignedUssClass); fadeDistanceSlider.AddToClassList(k_SubSubElementUssClass); fadeDistanceSlider.RegisterValueChangedCallback(_ => { m_MipMapFadeDistanceStart.intValue = Mathf.RoundToInt(fadeDistanceSlider.minValue); m_MipMapFadeDistanceEnd.intValue = Mathf.RoundToInt(fadeDistanceSlider.maxValue); m_MipMapFadeDistanceStart.serializedObject.ApplyModifiedProperties(); m_MipMapFadeDistanceEnd.serializedObject.ApplyModifiedProperties(); }); fadeDistanceSlider.schedule.Execute(() => { var shouldShow = fadeOutToggle.value; if (fadeDistanceSlider.visible != shouldShow) { fadeDistanceSlider.visible = shouldShow; fadeDistanceSlider.EnableInClassList(k_HiddenElementUssClass, !shouldShow); } }).Every(k_PollForChangesInternal); mipMapOptionContainer.Add(fadeDistanceSlider); } void InitPreview() { if (m_ImporterTargets.Length > 1) return; var importerPath = m_AssetPaths[0]; var gameObject = AssetDatabase.LoadAssetAtPath(importerPath); if (m_ModelPreviewer != null) { m_ModelPreviewer.Dispose(); m_ModelPreviewer = null; } if (gameObject != null && m_ImporterTargets[0].importMode == FileImportModes.AnimatedSprite && gameObject.GetComponent()) { var clips = GetAllAnimationClips(importerPath); m_ModelPreviewer = new ModelPreviewer(gameObject, clips); m_DefaultClip = clips != null && clips.Length > 0 ? clips[0] : null; } } void DisposePreview() { if (m_ModelPreviewer == null) return; m_ModelPreviewer.Dispose(); m_ModelPreviewer = null; } static AnimationClip[] GetAllAnimationClips(string assetPath) { var assets = AssetDatabase.LoadAllAssetsAtPath(assetPath); var clips = new List(); for (var i = 0; i < assets.Length; ++i) { if (assets[i] is AnimationClip clip) clips.Add(clip); } return clips.ToArray(); } /// /// Override for AssetImporter.extraDataType /// protected override Type extraDataType => typeof(AsepriteImporterEditorExternalData); /// /// Override for AssetImporter.InitializeExtraDataInstance /// /// Target object /// Target index protected override void InitializeExtraDataInstance(UnityEngine.Object extraTarget, int targetIndex) { var importer = targets[targetIndex] as AsepriteImporter; var extraData = extraTarget as AsepriteImporterEditorExternalData; var platformSettingsNeeded = TexturePlatformSettingsHelper.PlatformSettingsNeeded(PlatformSettingsUtilities.CreateDefaultSettings); if (importer != null) { extraData.Init(importer, platformSettingsNeeded); } } /// /// Implementation of AssetImporterEditor.DiscardChanges. /// public override void DiscardChanges() { base.DiscardChanges(); m_TexturePlatformSettingsHelper = new TexturePlatformSettingsHelper(this); } void ShowInspectorTab(int tab) { m_InspectorSettingsView.Clear(); m_InspectorSettingsView.Add(m_InspectorUI[tab]); } /// /// Implementation of AssetImporterEditor.SaveChanges. /// public override void SaveChanges() { ApplyTexturePlatformSettings(); serializedObject.ApplyModifiedProperties(); extraDataSerializedObject.ApplyModifiedProperties(); base.SaveChanges(); } // showPerAxisWrapModes is state of whether "Per-Axis" mode should be active in the main dropdown. // It is set automatically if wrap modes in UVW are different, or if user explicitly picks "Per-Axis" option -- when that one is picked, // then it should stay true even if UVW wrap modes will initially be the same. // // Note: W wrapping mode is only shown when isVolumeTexture is true. static void WrapModePopup(SerializedProperty wrapU, SerializedProperty wrapV, SerializedProperty wrapW, bool isVolumeTexture, ref bool showPerAxisWrapModes) { // In texture importer settings, serialized properties for things like wrap modes can contain -1; // that seems to indicate "use defaults, user has not changed them to anything" but not totally sure. // Show them as Repeat wrap modes in the popups. var wu = (TextureWrapMode)Mathf.Max(wrapU.intValue, 0); var wv = (TextureWrapMode)Mathf.Max(wrapV.intValue, 0); var ww = (TextureWrapMode)Mathf.Max(wrapW.intValue, 0); // automatically go into per-axis mode if values are already different if (wu != wv) showPerAxisWrapModes = true; if (isVolumeTexture) { if (wu != ww || wv != ww) showPerAxisWrapModes = true; } // It's not possible to determine whether any single texture in the whole selection is using per-axis wrap modes // just from SerializedProperty values. They can only tell if "some values in whole selection are different" (e.g. // wrap value on U axis is not the same among all textures), and can return value of "some" object in the selection // (typically based on object loading order). So in order for more intuitive behavior with multi-selection, // we go over the actual objects when there's >1 object selected and some wrap modes are different. if (!showPerAxisWrapModes) { if (wrapU.hasMultipleDifferentValues || wrapV.hasMultipleDifferentValues || (isVolumeTexture && wrapW.hasMultipleDifferentValues)) { if (IsAnyTextureObjectUsingPerAxisWrapMode(wrapU.serializedObject.targetObjects, isVolumeTexture)) { showPerAxisWrapModes = true; } } } int value = showPerAxisWrapModes ? -1 : (int)wu; // main wrap mode popup EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = !showPerAxisWrapModes && (wrapU.hasMultipleDifferentValues || wrapV.hasMultipleDifferentValues || (isVolumeTexture && wrapW.hasMultipleDifferentValues)); value = EditorGUILayout.IntPopup(styles.wrapModeLabel, value, styles.wrapModeContents, styles.wrapModeValues); if (EditorGUI.EndChangeCheck() && value != -1) { // assign the same wrap mode to all axes, and hide per-axis popups wrapU.intValue = value; wrapV.intValue = value; wrapW.intValue = value; showPerAxisWrapModes = false; wrapU.serializedObject.ApplyModifiedProperties(); wrapV.serializedObject.ApplyModifiedProperties(); wrapW.serializedObject.ApplyModifiedProperties(); } // show per-axis popups if needed if (value == -1) { showPerAxisWrapModes = true; EditorGUI.indentLevel++; WrapModeAxisPopup(styles.wrapU, wrapU); WrapModeAxisPopup(styles.wrapV, wrapV); if (isVolumeTexture) { WrapModeAxisPopup(styles.wrapW, wrapW); } EditorGUI.indentLevel--; } EditorGUI.showMixedValue = false; } static void WrapModeAxisPopup(GUIContent label, SerializedProperty wrapProperty) { // In texture importer settings, serialized properties for wrap modes can contain -1, which means "use default". var wrap = (TextureWrapMode)Mathf.Max(wrapProperty.intValue, 0); Rect rect = EditorGUILayout.GetControlRect(); EditorGUI.BeginChangeCheck(); EditorGUI.BeginProperty(rect, label, wrapProperty); wrap = (TextureWrapMode)EditorGUI.EnumPopup(rect, label, wrap); EditorGUI.EndProperty(); if (EditorGUI.EndChangeCheck()) { wrapProperty.intValue = (int)wrap; } } static bool IsAnyTextureObjectUsingPerAxisWrapMode(UnityEngine.Object[] objects, bool isVolumeTexture) { foreach (var o in objects) { int u = 0, v = 0, w = 0; // the objects can be Textures themselves, or texture-related importers if (o is Texture) { var ti = (Texture)o; u = (int)ti.wrapModeU; v = (int)ti.wrapModeV; w = (int)ti.wrapModeW; } if (o is TextureImporter) { var ti = (TextureImporter)o; u = (int)ti.wrapModeU; v = (int)ti.wrapModeV; w = (int)ti.wrapModeW; } if (o is IHVImageFormatImporter) { var ti = (IHVImageFormatImporter)o; u = (int)ti.wrapModeU; v = (int)ti.wrapModeV; w = (int)ti.wrapModeW; } u = Mathf.Max(0, u); v = Mathf.Max(0, v); w = Mathf.Max(0, w); if (u != v) { return true; } if (isVolumeTexture) { if (u != w || v != w) { return true; } } } return false; } /// /// Implementation of AssetImporterEditor.Apply /// protected override void Apply() { m_TexturePlatformSettingsHelper.Apply(); ApplyTexturePlatformSettings(); InternalEditorBridge.ApplySpriteEditorWindow(); base.Apply(); if (m_ModelPreviewer != null) { m_ModelPreviewer.Dispose(); m_ModelPreviewer = null; } } void ApplyTexturePlatformSettings() { for (var i = 0; i < targets.Length && i < extraDataTargets.Length; ++i) { var asepriteImporter = (AsepriteImporter)targets[i]; var externalData = (AsepriteImporterEditorExternalData)extraDataTargets[i]; foreach (var ps in externalData.platformSettings) { asepriteImporter.SetImporterPlatformSettings(ps); asepriteImporter.Apply(); } } } /// /// Override of AssetImporterEditor.HasModified. /// /// Returns True if has modified data. False otherwise. public override bool HasModified() { if (base.HasModified()) return true; return m_TexturePlatformSettingsHelper.HasModified(); } /// /// Implementation of ITexturePlatformSettingsDataProvider.GetTargetCount. /// /// Returns the number of selected targets. int ITexturePlatformSettingsDataProvider.GetTargetCount() => targets.Length; /// /// ITexturePlatformSettingsDataProvider.GetPlatformTextureSettings. /// /// Selected target index. /// Name of the platform. /// TextureImporterPlatformSettings for the given platform name and selected target index. TextureImporterPlatformSettings ITexturePlatformSettingsDataProvider.GetPlatformTextureSettings(int i, string name) { var externalData = extraDataSerializedObject.targetObjects[i] as AsepriteImporterEditorExternalData; if (externalData != null) { foreach (var ps in externalData.platformSettings) { if (ps.name == name) return ps; } } return new TextureImporterPlatformSettings() { name = name, overridden = false }; } /// /// Implementation of ITexturePlatformSettingsDataProvider.ShowPresetSettings. /// /// True if valid asset is selected, false otherwise. bool ITexturePlatformSettingsDataProvider.ShowPresetSettings() { return assetTarget == null; } /// /// Implementation of ITexturePlatformSettingsDataProvider.DoesSourceTextureHaveAlpha. /// /// Index to selected target. /// Always returns true since importer deals with source file that has alpha. bool ITexturePlatformSettingsDataProvider.DoesSourceTextureHaveAlpha(int i) { return true; } /// /// Implementation of ITexturePlatformSettingsDataProvider.IsSourceTextureHDR. /// /// Index to selected target. /// Always returns false since importer does not handle HDR textures. bool ITexturePlatformSettingsDataProvider.IsSourceTextureHDR(int i) { return false; } /// /// Implementation of ITexturePlatformSettingsDataProvider.SetPlatformTextureSettings. /// /// Selected target index. /// TextureImporterPlatformSettings to apply to target. void ITexturePlatformSettingsDataProvider.SetPlatformTextureSettings(int i, TextureImporterPlatformSettings platformSettings) { var importer = (AsepriteImporter)targets[i]; var sp = new SerializedObject(importer); sp.FindProperty("m_PlatformSettingsDirtyTick").longValue = System.DateTime.Now.Ticks; sp.ApplyModifiedProperties(); } /// /// Implementation of ITexturePlatformSettingsDataProvider.GetImporterSettings. /// /// Selected target index. /// TextureImporterPlatformSettings reference for data retrieval. void ITexturePlatformSettingsDataProvider.GetImporterSettings(int i, TextureImporterSettings settings) { ((AsepriteImporter)targets[i]).ReadTextureSettings(settings); // Get settings that have been changed in the inspector GetSerializedPropertySettings(settings); } /// /// Get the name property of TextureImporterPlatformSettings from a SerializedProperty. /// /// The SerializedProperty to retrive data. /// The name value in string. public string GetBuildTargetName(SerializedProperty sp) { return sp.FindPropertyRelative("m_Name").stringValue; } TextureImporterSettings GetSerializedPropertySettings(TextureImporterSettings settings) { if (!m_AlphaSource.hasMultipleDifferentValues) settings.alphaSource = (TextureImporterAlphaSource)m_AlphaSource.intValue; if (!m_ConvertToNormalMap.hasMultipleDifferentValues) settings.convertToNormalMap = m_ConvertToNormalMap.intValue > 0; if (!m_BorderMipMap.hasMultipleDifferentValues) settings.borderMipmap = m_BorderMipMap.intValue > 0; #if ENABLE_TEXTURE_STREAMING if (!m_StreamingMipmaps.hasMultipleDifferentValues) settings.streamingMipmaps = m_StreamingMipmaps.intValue > 0; if (!m_StreamingMipmapsPriority.hasMultipleDifferentValues) settings.streamingMipmapsPriority = m_StreamingMipmapsPriority.intValue; #endif if (!m_MipMapsPreserveCoverage.hasMultipleDifferentValues) settings.mipMapsPreserveCoverage = m_MipMapsPreserveCoverage.intValue > 0; if (!m_AlphaTestReferenceValue.hasMultipleDifferentValues) settings.alphaTestReferenceValue = m_AlphaTestReferenceValue.floatValue; if (!m_NPOTScale.hasMultipleDifferentValues) settings.npotScale = (TextureImporterNPOTScale)m_NPOTScale.intValue; if (!m_IsReadable.hasMultipleDifferentValues) settings.readable = m_IsReadable.intValue > 0; if (!m_sRGBTexture.hasMultipleDifferentValues) settings.sRGBTexture = m_sRGBTexture.intValue > 0; if (!m_EnableMipMap.hasMultipleDifferentValues) settings.mipmapEnabled = m_EnableMipMap.intValue > 0; if (!m_MipMapMode.hasMultipleDifferentValues) settings.mipmapFilter = (TextureImporterMipFilter)m_MipMapMode.intValue; if (!m_FadeOut.hasMultipleDifferentValues) settings.fadeOut = m_FadeOut.intValue > 0; if (!m_MipMapFadeDistanceStart.hasMultipleDifferentValues) settings.mipmapFadeDistanceStart = m_MipMapFadeDistanceStart.intValue; if (!m_MipMapFadeDistanceEnd.hasMultipleDifferentValues) settings.mipmapFadeDistanceEnd = m_MipMapFadeDistanceEnd.intValue; if (!m_SpriteMode.hasMultipleDifferentValues) settings.spriteMode = m_SpriteMode.intValue; if (!m_SpritePixelsToUnits.hasMultipleDifferentValues) settings.spritePixelsPerUnit = m_SpritePixelsToUnits.floatValue; if (!m_SpriteExtrude.hasMultipleDifferentValues) settings.spriteExtrude = (uint)m_SpriteExtrude.intValue; if (!m_SpriteMeshType.hasMultipleDifferentValues) settings.spriteMeshType = (SpriteMeshType)m_SpriteMeshType.intValue; if (!m_Alignment.hasMultipleDifferentValues) settings.spriteAlignment = m_Alignment.intValue; if (!m_SpritePivot.hasMultipleDifferentValues) settings.spritePivot = m_SpritePivot.vector2Value; if (!m_WrapU.hasMultipleDifferentValues) settings.wrapModeU = (TextureWrapMode)m_WrapU.intValue; if (!m_WrapV.hasMultipleDifferentValues) settings.wrapModeU = (TextureWrapMode)m_WrapV.intValue; if (!m_WrapW.hasMultipleDifferentValues) settings.wrapModeU = (TextureWrapMode)m_WrapW.intValue; if (!m_FilterMode.hasMultipleDifferentValues) settings.filterMode = (FilterMode)m_FilterMode.intValue; if (!m_Aniso.hasMultipleDifferentValues) settings.aniso = m_Aniso.intValue; if (!m_AlphaIsTransparency.hasMultipleDifferentValues) settings.alphaIsTransparency = m_AlphaIsTransparency.intValue > 0; if (!m_TextureType.hasMultipleDifferentValues) settings.textureType = (TextureImporterType)m_TextureType.intValue; if (!m_TextureShape.hasMultipleDifferentValues) settings.textureShape = (TextureImporterShape)m_TextureShape.intValue; return settings; } static void ToggleFromInt(SerializedProperty property, GUIContent label) { EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = property.hasMultipleDifferentValues; var value = EditorGUILayout.Toggle(label, property.intValue > 0) ? 1 : 0; EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) property.intValue = value; } static void EnumPopup(SerializedProperty property, System.Type type, GUIContent label) { EditorGUILayout.IntPopup(label.text, property.intValue, System.Enum.GetNames(type), System.Enum.GetValues(type) as int[]); } /// /// Override from AssetImporterEditor to show custom preview. /// /// Preview Rect. public override void DrawPreview(Rect r) { if (HasRenamedAssets()) ReloadPreviewData(); if (m_ModelPreviewer == null) InitPreview(); if (m_ModelPreviewer != null) m_ModelPreviewer.DrawPreview(r, "PreBackgroundSolid"); else base.DrawPreview(r); } void ReloadPreviewData() { DisposePreview(); CacheImporterData(); InitPreview(); Apply(); } bool HasRenamedAssets() { for (var i = 0; i < m_AssetPaths.Length; ++i) { if (m_AssetPaths[i] != (targets[i] as AsepriteImporter).assetPath) return true; } return false; } class Styles { readonly GUIContent textureShape2D = new("2D, Texture is 2D."); readonly GUIContent textureShapeCube = new("Cube", "Texture is a Cubemap."); public readonly Dictionary textureShapeOptionsDictionnary = new(); public readonly Dictionary textureShapeValuesDictionnary = new(); public readonly GUIContent filterMode = new("Filter Mode"); public readonly GUIContent[] filterModeOptions = { new ("Point (no filter)"), new ("Bilinear"), new ("Trilinear") }; public readonly GUIContent mipmapFadeOutToggle = new("Fadeout Mip Maps"); public readonly GUIContent mipmapFadeOut = new("Fade Range"); public readonly GUIContent readWrite = new("Read/Write Enabled", "Enable to be able to access the raw pixel data from code."); public readonly GUIContent alphaSource = new("Alpha Source", "How is the alpha generated for the imported texture."); public readonly GUIContent generateMipMaps = new("Generate Mip Maps"); public readonly GUIContent sRGBTexture = new("sRGB (Color Texture)", "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); public readonly GUIContent borderMipMaps = new("Border Mip Maps"); #if ENABLE_TEXTURE_STREAMING public readonly GUIContent streamingMipMaps = EditorGUIUtility.TrTextContent("Mip Streaming", "Only load larger mipmaps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings."); public readonly GUIContent streamingMipmapsPriority = EditorGUIUtility.TrTextContent("Priority", "Mipmap streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127."); #endif public readonly GUIContent mipMapsPreserveCoverage = new("Preserve Coverage", "The alpha channel of generated Mip Maps will preserve coverage during the alpha test."); public readonly GUIContent alphaTestReferenceValue = new("Alpha Cutoff Value", "The reference value used during the alpha test. Controls Mip Map coverage."); public readonly GUIContent mipMapFilter = new("Mip Map Filtering"); public readonly List spriteMeshTypeOptions = new() { L10n.Tr("Full Rect"), L10n.Tr("Tight"), }; public readonly GUIContent fileImportMode = new("Import Mode", "How the file should be imported."); public readonly GUIContent spritePixelsPerUnit = new("Pixels Per Unit", "How many pixels in the sprite correspond to one unit in the world."); public readonly GUIContent spriteMeshType = new("Mesh Type", "Type of sprite mesh to generate."); public readonly GUIContent generatePhysicsShape = new("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 warpNotSupportWarning = new("Graphics device doesn't support Repeat wrap mode on NPOT textures. Falling back to Clamp."); public readonly GUIContent anisoLevelLabel = new("Aniso Level"); public readonly GUIContent anisotropicDisableInfo = new("Anisotropic filtering is disabled for all textures in Quality Settings."); public readonly GUIContent anisotropicForceEnableInfo = new("Anisotropic filtering is enabled for all textures in Quality Settings."); public readonly GUIContent unappliedSettingsDialogTitle = new("Unapplied import settings"); public readonly GUIContent unappliedSettingsDialogContent = new("Unapplied import settings for \'{0}\'.\nApply and continue to sprite editor or cancel."); public readonly GUIContent applyButtonLabel = new("Apply"); public readonly GUIContent cancelButtonLabel = new("Cancel"); public readonly GUIContent spriteEditorButtonLabel = new("Open Sprite Editor"); public readonly GUIContent alphaIsTransparency = new("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."); public readonly GUIContent advancedHeaderText = new("Advanced", "Show advanced settings."); public readonly GUIContent platformSettingsHeaderText = new GUIContent("Platform Settings"); public readonly GUIContent[] platformSettingsSelection; public readonly GUIContent wrapModeLabel = new("Wrap Mode"); public readonly GUIContent wrapU = new("U axis"); public readonly GUIContent wrapV = new("V axis"); public readonly GUIContent wrapW = new("W axis"); public readonly GUIContent[] wrapModeContents = { new ("Repeat"), new ("Clamp"), new ("Mirror"), new ("Mirror Once"), new ("Per-axis") }; public readonly int[] wrapModeValues = { (int)TextureWrapMode.Repeat, (int)TextureWrapMode.Clamp, (int)TextureWrapMode.Mirror, (int)TextureWrapMode.MirrorOnce, -1 }; public readonly GUIContent importHiddenLayer = EditorGUIUtility.TrTextContent("Include Hidden Layers", "Settings to determine when hidden layers should be imported."); public readonly GUIContent defaultPivotSpace = EditorGUIUtility.TrTextContent("Pivot Space", "Select which space the pivot should be calculated in."); public readonly GUIContent defaultPivotAlignment = EditorGUIUtility.TrTextContent("Pivot Alignment", "Select where the pivot should be located based on the Pivot Space."); public readonly GUIContent customPivotPosition = EditorGUIUtility.TrTextContent("Custom Pivot Position", "Input the normalized position of the Sprite pivots. The position will be calculated based on the Pivot Space."); public readonly GUIContent mosaicPadding = EditorGUIUtility.TrTextContent("Mosaic Padding", "External padding between each SpriteRect, in pixels."); public readonly GUIContent spritePadding = EditorGUIUtility.TrTextContent("Sprite Padding", "Internal padding within each SpriteRect, in pixels."); public readonly List spriteAlignmentOptions = new() { L10n.Tr("Center"), L10n.Tr("Top Left"), L10n.Tr("Top"), L10n.Tr("Top Right"), L10n.Tr("Left"), L10n.Tr("Right"), L10n.Tr("Bottom Left"), L10n.Tr("Bottom"), L10n.Tr("Bottom Right"), L10n.Tr("Custom"), }; public readonly GUIContent layerImportMode = EditorGUIUtility.TrTextContent("Import Mode", "Choose between generating one Sprite per layer, or merge all layers in a frame into a single Sprite."); public readonly List layerImportOptions = new() { L10n.Tr("Individual Layers"), L10n.Tr("Merge Frame") }; public readonly GUIContent generateModelPrefab = EditorGUIUtility.TrTextContent("Model Prefab", "Generate a Model Prefab laid out the same way as inside Aseprite."); public readonly GUIContent addSortingGroup = EditorGUIUtility.TrTextContent("Sorting Group", "Add a Sorting Group component to the root of the generated model prefab if it has more than one Sprite Renderer."); public readonly GUIContent addShadowCasters = EditorGUIUtility.TrTextContent("Shadow Casters", "Add Shadow Casters on all GameObjects with SpriteRenderer. Note: The Universal Rendering Pipeline package has to be installed."); public readonly GUIContent generateAnimationClips = EditorGUIUtility.TrTextContent("Animation Clips", "Generate Animation Clips based on the frame and tag data from the Aseprite file."); public readonly GUIContent generateIndividualEvents = EditorGUIUtility.TrTextContent("Individual Events", "Events will be generated with their own method name. If disabled, all events will be received by the method `OnAnimationEvent(string)`."); public readonly GUIContent generateSpriteAtlas = EditorGUIUtility.TrTextContent("Sprite Atlas", "Generate a Sprite Atlas to contain the created texture. This is to remove any gaps between tiles when drawing a tile map."); public readonly GUIContent generalHeaderText = EditorGUIUtility.TrTextContent("General", "General settings."); public readonly GUIContent layerImportHeaderText = EditorGUIUtility.TrTextContent("Layer Import", "Layer Import settings."); public readonly GUIContent generateAssetsHeaderText = EditorGUIUtility.TrTextContent("Generate Assets", "Generated assets settings."); public readonly GUIContent textureHeaderText = EditorGUIUtility.TrTextContent("Texture", "Texture settings."); public readonly GUIContent exportAnimationAssetsText = EditorGUIUtility.TrTextContent("Export Animation Assets"); public readonly GUIContent exportAnimationInfoText = EditorGUIUtility.TrTextContent("To enable the Export Animation Assets button, make sure to first Apply the changes."); public Styles() { // This is far from ideal, but it's better than having tons of logic in the GUI code itself. // The combination should not grow too much anyway since only Texture3D will be added later. GUIContent[] s2D_Options = { textureShape2D }; GUIContent[] sCube_Options = { textureShapeCube }; GUIContent[] s2D_Cube_Options = { textureShape2D, textureShapeCube }; textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D, s2D_Options); textureShapeOptionsDictionnary.Add(TextureImporterShape.TextureCube, sCube_Options); textureShapeOptionsDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Options); int[] s2D_Values = { (int)TextureImporterShape.Texture2D }; int[] sCube_Values = { (int)TextureImporterShape.TextureCube }; int[] s2D_Cube_Values = { (int)TextureImporterShape.Texture2D, (int)TextureImporterShape.TextureCube }; textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D, s2D_Values); textureShapeValuesDictionnary.Add(TextureImporterShape.TextureCube, sCube_Values); textureShapeValuesDictionnary.Add(TextureImporterShape.Texture2D | TextureImporterShape.TextureCube, s2D_Cube_Values); platformSettingsSelection = new GUIContent[TexturePlatformSettingsModal.validBuildPlatform.Length]; for (var i = 0; i < TexturePlatformSettingsModal.validBuildPlatform.Length; ++i) { platformSettingsSelection[i] = new GUIContent(TexturePlatformSettingsModal.validBuildPlatform[i].buildTargetName); } } } static Styles s_Styles; static Styles styles { get { if (s_Styles == null) s_Styles = new Styles(); return s_Styles; } } class AsepriteImporterEditorFoldOutState { readonly SavedBool m_GeneralFoldout; readonly SavedBool m_LayerImportFoldout; readonly SavedBool m_GenerateAssetFoldout; readonly SavedBool m_AdvancedFoldout; readonly SavedBool m_TextureFoldout; readonly SavedBool m_PlatformSettingsFoldout; public bool generalFoldout { get => m_GeneralFoldout.value; set => m_GeneralFoldout.value = value; } public bool layerImportFoldout { get => m_LayerImportFoldout.value; set => m_LayerImportFoldout.value = value; } public bool generateAssetFoldout { get => m_GenerateAssetFoldout.value; set => m_GenerateAssetFoldout.value = value; } public bool advancedFoldout { get => m_AdvancedFoldout.value; set => m_AdvancedFoldout.value = value; } public bool textureFoldout { get => m_TextureFoldout.value; set => m_TextureFoldout.value = value; } public bool platformSettingsFoldout { get => m_PlatformSettingsFoldout.value; set => m_PlatformSettingsFoldout.value = value; } public AsepriteImporterEditorFoldOutState() { m_GeneralFoldout = new SavedBool("AsepriteImporterEditor.m_GeneralFoldout", true); m_LayerImportFoldout = new SavedBool("AsepriteImporterEditor.m_LayerImportFoldout", true); m_GenerateAssetFoldout = new SavedBool("AsepriteImporterEditor.m_ExportAssetFoldout", true); m_AdvancedFoldout = new SavedBool("AsepriteImporterEditor.m_AdvancedFoldout", false); m_TextureFoldout = new SavedBool("AsepriteImporterEditor.m_TextureFoldout", false); m_PlatformSettingsFoldout = new SavedBool("AsepriteImporterEditor.m_PlatformSettingsFoldout", false); } class SavedBool { readonly string m_Name; bool m_Value; bool m_Loaded; public SavedBool(string name, bool value) { m_Name = name; m_Loaded = false; m_Value = value; } void Load() { if (m_Loaded) return; m_Loaded = true; m_Value = EditorPrefs.GetBool(m_Name, m_Value); } public bool value { get { Load(); return m_Value; } set { Load(); if (m_Value == value) return; m_Value = value; EditorPrefs.SetBool(m_Name, value); } } public static implicit operator bool(SavedBool s) { return s.value; } } } } }