diff --git a/Assets/UniGLTF/Editor/Animation/AnimationValidator.cs b/Assets/UniGLTF/Editor/Animation/AnimationValidator.cs index 120717b0e4..b451d4e9d6 100644 --- a/Assets/UniGLTF/Editor/Animation/AnimationValidator.cs +++ b/Assets/UniGLTF/Editor/Animation/AnimationValidator.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using MeshUtility; +using UniGLTF.M17N; using UnityEditor; using UnityEngine; diff --git a/Assets/UniGLTF/Editor/EditorSettingsValidator/Messages.cs b/Assets/UniGLTF/Editor/EditorSettingsValidator/Messages.cs index fef97c632c..6702fc7832 100644 --- a/Assets/UniGLTF/Editor/EditorSettingsValidator/Messages.cs +++ b/Assets/UniGLTF/Editor/EditorSettingsValidator/Messages.cs @@ -1,4 +1,6 @@  +using UniGLTF.M17N; + namespace UniGLTF.EditorSettingsValidator { public enum Messages diff --git a/Assets/UniGLTF/Editor/EditorSettingsValidator/UnityColorSpaceSettingsValidator.cs b/Assets/UniGLTF/Editor/EditorSettingsValidator/UnityColorSpaceSettingsValidator.cs index 6efda849a7..d0b7192567 100644 --- a/Assets/UniGLTF/Editor/EditorSettingsValidator/UnityColorSpaceSettingsValidator.cs +++ b/Assets/UniGLTF/Editor/EditorSettingsValidator/UnityColorSpaceSettingsValidator.cs @@ -1,4 +1,5 @@ using UnityEditor; +using UniGLTF.M17N; namespace UniGLTF.EditorSettingsValidator { @@ -15,4 +16,4 @@ public void Validate() PlayerSettings.colorSpace = UnityEngine.ColorSpace.Linear; } } -} \ No newline at end of file +} diff --git a/Assets/UniGLTF/Editor/EditorSettingsValidator/UnityEditorSettingsValidatorWindow.cs b/Assets/UniGLTF/Editor/EditorSettingsValidator/UnityEditorSettingsValidatorWindow.cs index d1f0825d56..f7fce289f6 100644 --- a/Assets/UniGLTF/Editor/EditorSettingsValidator/UnityEditorSettingsValidatorWindow.cs +++ b/Assets/UniGLTF/Editor/EditorSettingsValidator/UnityEditorSettingsValidatorWindow.cs @@ -1,4 +1,5 @@ using System; +using UniGLTF.M17N; using UnityEditor; using UnityEngine; diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs index b316f621d3..9d4722de4f 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs @@ -5,6 +5,7 @@ using UnityEngine; using UnityEditor; using UniGLTF; +using UniGLTF.M17N; namespace MeshUtility { @@ -133,7 +134,7 @@ private void OnGUI() _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); EditorGUIUtility.labelWidth = 150; // lang - Getter.OnGuiSelectLang(); + LanguageGetter.OnGuiSelectLang(); _tab = TabBar.OnGUI(_tab, _tabButtonStyle, _tabButtonSize); diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs new file mode 100644 index 0000000000..60c3c98ae7 --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs @@ -0,0 +1,176 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UniGLTF.M17N; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF +{ + /// + /// ヒエラルキーをエクスポートするダイアログ。 + /// + /// * Root管理(m_state) + /// * Validation管理(Exportボタンを押せるか否か) + /// + /// + public abstract class ExportDialogBase : EditorWindow + { + ExporterDialogState m_state; + protected ExporterDialogState State => m_state; + + protected virtual void OnEnable() + { + Undo.willFlushUndoRecord += Repaint; + Selection.selectionChanged += Repaint; + + m_state = new ExporterDialogState(); + + Initialize(); + + m_state.ExportRootChanged += (root) => + { + Repaint(); + }; + m_state.ExportRoot = Selection.activeObject as GameObject; + } + + protected abstract void Initialize(); + + void OnDisable() + { + Clear(); + + m_state.Dispose(); + + Selection.selectionChanged -= Repaint; + Undo.willFlushUndoRecord -= Repaint; + } + + protected abstract void Clear(); + + // + // scroll + // + public delegate Vector2 BeginVerticalScrollViewFunc(Vector2 scrollPosition, bool alwaysShowVertical, GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options); + static BeginVerticalScrollViewFunc s_func; + static BeginVerticalScrollViewFunc BeginVerticalScrollView + { + get + { + if (s_func == null) + { + var methods = typeof(EditorGUILayout).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Where(x => x.Name == "BeginVerticalScrollView").ToArray(); + var method = methods.First(x => x.GetParameters()[1].ParameterType == typeof(bool)); + s_func = (BeginVerticalScrollViewFunc)method.CreateDelegate(typeof(BeginVerticalScrollViewFunc)); + } + return s_func; + } + } + private Vector2 m_ScrollPosition; + + // + // validation + // + protected abstract IEnumerable ValidatorFactory(); + + void OnGUI() + { + var modified = false; + if (BeginGUI()) + { + modified = DoGUI(); + } + EndGUI(); + + if (modified) + { + State.Invalidate(); + } + } + + protected abstract bool DoGUI(); + + bool BeginGUI() + { + // ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint Aborting + // Validation により GUI の表示項目が変わる場合があるので、 + // EventType.Layout と EventType.Repaint 間で内容が変わらないようしている。 + if (Event.current.type == EventType.Layout) + { + State.Validate(ValidatorFactory()); + } + + EditorGUIUtility.labelWidth = 150; + + // lang + LanguageGetter.OnGuiSelectLang(); + + EditorGUILayout.LabelField("ExportRoot"); + { + State.ExportRoot = (GameObject)EditorGUILayout.ObjectField(State.ExportRoot, typeof(GameObject), true); + } + + // Render contents using Generic Inspector GUI + m_ScrollPosition = BeginVerticalScrollView(m_ScrollPosition, false, GUI.skin.verticalScrollbar, "OL Box"); + GUIUtility.GetControlID(645789, FocusType.Passive); + + // validation + foreach (var v in State.Validations) + { + v.DrawGUI(); + if (v.ErrorLevel == ErrorLevels.Critical) + { + // Export UI を表示しない + return false; + } + } + return true; + } + + protected abstract string SaveTitle { get; } + protected abstract string SaveName { get; } + protected abstract string[] SaveExtensions { get; } + + void EndGUI() + { + EditorGUILayout.EndScrollView(); + + // + // export button + // + // Create and Other Buttons + { + // errors + GUILayout.BeginVertical(); + // GUILayout.FlexibleSpace(); + + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUI.enabled = State.Validations.All(x => x.CanExport); + + if (GUILayout.Button("Export", GUILayout.MinWidth(100))) + { + var path = SaveFileDialog.GetPath(SaveTitle, SaveName, SaveExtensions); + if (!string.IsNullOrEmpty(path)) + { + ExportPath(path); + // close + Close(); + GUIUtility.ExitGUI(); + } + } + GUI.enabled = true; + + GUILayout.EndHorizontal(); + } + GUILayout.EndVertical(); + } + + GUILayout.Space(8); + } + + protected abstract void ExportPath(string path); + } +} diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs.meta b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs.meta new file mode 100644 index 0000000000..079c45185f --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/ExportDialogBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 292cdc4b7dd3b6d47a1215ad528f50c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs index 10ec1b905d..86fcd285a7 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/GltfExportWindow.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; using UniGLTF.Animation; using UnityEditor; using UnityEngine; @@ -9,7 +8,7 @@ namespace UniGLTF { - public class GltfExportWindow : EditorWindow + public class GltfExportWindow : ExportDialogBase { const string MENU_KEY = UniGLTFVersion.MENU + "/Export " + UniGLTFVersion.UNIGLTF_VERSION; @@ -23,228 +22,95 @@ private static void ExportFromMenu() private static void Export(GameObject go, string path, MeshExportSettings settings, Axises inverseAxis) { - var ext = Path.GetExtension(path).ToLower(); - var isGlb = false; - switch (ext) - { - case ".glb": isGlb = true; break; - case ".gltf": isGlb = false; break; - default: throw new System.Exception(); - } - - var gltf = new glTF(); - using (var exporter = new gltfExporter(gltf, inverseAxis)) - { - exporter.Prepare(go); - exporter.Export(settings, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); - } - - if (isGlb) - { - var bytes = gltf.ToGlbBytes(); - File.WriteAllBytes(path, bytes); - } - else - { - var (json, buffers) = gltf.ToGltf(path); - // without BOM - var encoding = new System.Text.UTF8Encoding(false); - File.WriteAllText(path, json, encoding); - // write to local folder - var dir = Path.GetDirectoryName(path); - foreach (var b in buffers) - { - var bufferPath = Path.Combine(dir, b.uri); - File.WriteAllBytes(bufferPath, b.GetBytes().ToArray()); - } - } - - if (path.StartsWithUnityAssetPath()) - { - AssetDatabase.ImportAsset(path.ToUnityRelativePath()); - AssetDatabase.Refresh(); - } } - ExporterDialogState m_state; GltfExportSettings m_settings; Editor m_settingsInspector; - void OnEnable() + protected override void Initialize() { - // Debug.Log("OnEnable"); - Undo.willFlushUndoRecord += Repaint; - Selection.selectionChanged += Repaint; - m_settings = ScriptableObject.CreateInstance(); + m_settings.InverseAxis = UniGLTFPreference.GltfIOAxis; m_settingsInspector = Editor.CreateEditor(m_settings); - - m_state = new ExporterDialogState(); - m_state.ExportRootChanged += (root) => - { - Repaint(); - }; - m_state.ExportRoot = Selection.activeObject as GameObject; } - void OnDisable() + protected override void Clear() { - m_state.Dispose(); - - // Debug.Log("OnDisable"); - Selection.selectionChanged -= Repaint; - Undo.willFlushUndoRecord -= Repaint; - // m_settingsInspector UnityEditor.Editor.DestroyImmediate(m_settingsInspector); m_settingsInspector = null; - // m_settings - ScriptableObject.DestroyImmediate(m_settings); - m_settings = null; } - public delegate Vector2 BeginVerticalScrollViewFunc(Vector2 scrollPosition, bool alwaysShowVertical, GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options); - static BeginVerticalScrollViewFunc s_func; - static BeginVerticalScrollViewFunc BeginVerticalScrollView - { - get - { - if (s_func == null) - { - var methods = typeof(EditorGUILayout).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Where(x => x.Name == "BeginVerticalScrollView").ToArray(); - var method = methods.First(x => x.GetParameters()[1].ParameterType == typeof(bool)); - s_func = (BeginVerticalScrollViewFunc)method.CreateDelegate(typeof(BeginVerticalScrollViewFunc)); - } - return s_func; - } - } - private Vector2 m_ScrollPosition; - - IEnumerable ValidatorFactory() + protected override IEnumerable ValidatorFactory() { yield return HierarchyValidator.ValidateRoot; yield return AnimationValidator.Validate; - if (!m_state.ExportRoot) + if (!State.ExportRoot) { yield break; } } - - private void OnGUI() + protected override bool DoGUI() { - // ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint Aborting - // Validation により GUI の表示項目が変わる場合があるので、 - // EventType.Layout と EventType.Repaint 間で内容が変わらないようしている。 - if (Event.current.type == EventType.Layout) - { - m_state.Validate(ValidatorFactory()); - } - - EditorGUIUtility.labelWidth = 150; + m_settings.Root = State.ExportRoot; + m_settingsInspector.OnInspectorGUI(); + return true; + } - // lang - Getter.OnGuiSelectLang(); + protected override string SaveTitle => "Save gltf"; + protected override string SaveName => $"{State.ExportRoot.name}.glb"; + protected override string[] SaveExtensions => new string[] { "glb", "gltf" }; - EditorGUILayout.LabelField("ExportRoot"); + protected override void ExportPath(string path) + { + var ext = Path.GetExtension(path).ToLower(); + var isGlb = false; + switch (ext) { - m_state.ExportRoot = (GameObject)EditorGUILayout.ObjectField(m_state.ExportRoot, typeof(GameObject), true); + case ".glb": isGlb = true; break; + case ".gltf": isGlb = false; break; + default: throw new System.Exception(); } - // Render contents using Generic Inspector GUI - m_ScrollPosition = BeginVerticalScrollView(m_ScrollPosition, false, GUI.skin.verticalScrollbar, "OL Box"); - GUIUtility.GetControlID(645789, FocusType.Passive); - - bool modified = ScrollArea(); - - EditorGUILayout.EndScrollView(); - - // Create and Other Buttons + var gltf = new glTF(); + using (var exporter = new gltfExporter(gltf, m_settings.InverseAxis)) { - // errors - GUILayout.BeginVertical(); - // GUILayout.FlexibleSpace(); - + exporter.Prepare(State.ExportRoot); + var settings = new MeshExportSettings { - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUI.enabled = m_state.Validations.All(x => x.CanExport); - - if (GUILayout.Button("Export", GUILayout.MinWidth(100))) - { - OnExportClicked(m_state.ExportRoot, m_settings); - Close(); - GUIUtility.ExitGUI(); - } - GUI.enabled = true; - - GUILayout.EndHorizontal(); - } - GUILayout.EndVertical(); + ExportOnlyBlendShapePosition = m_settings.DropNormal, + UseSparseAccessorForMorphTarget = m_settings.Sparse, + DivideVertexBuffer = m_settings.DivideVertexBuffer, + }; + exporter.Export(settings, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); } - GUILayout.Space(8); - - if (modified) + if (isGlb) { - m_state.Invalidate(); + var bytes = gltf.ToGlbBytes(); + File.WriteAllBytes(path, bytes); } - } - - bool ScrollArea() - { - // - // Validation - // - foreach (var v in m_state.Validations) + else { - v.DrawGUI(); - if (v.ErrorLevel == ErrorLevels.Critical) + var (json, buffers) = gltf.ToGltf(path); + // without BOM + var encoding = new System.Text.UTF8Encoding(false); + File.WriteAllText(path, json, encoding); + // write to local folder + var dir = Path.GetDirectoryName(path); + foreach (var b in buffers) { - // Export UI を表示しない - return false; + var bufferPath = Path.Combine(dir, b.uri); + File.WriteAllBytes(bufferPath, b.GetBytes().ToArray()); } } - // - // GUI - // - m_settings.Root = m_state.ExportRoot; - m_settingsInspector.OnInspectorGUI(); - return true; - } - - private static string m_lastExportDir; - static void OnExportClicked(GameObject root, GltfExportSettings settings) - { - string directory; - if (string.IsNullOrEmpty(m_lastExportDir)) - { - directory = Directory.GetParent(Application.dataPath).ToString(); - } - else - { - directory = m_lastExportDir; - } - - // save dialog - var path = EditorUtility.SaveFilePanel( - "Save vrm", - directory, - root.name + ".glb", - "glb,gltf"); - if (string.IsNullOrEmpty(path)) + if (path.StartsWithUnityAssetPath()) { - return; + AssetDatabase.ImportAsset(path.ToUnityRelativePath()); + AssetDatabase.Refresh(); } - m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/"); - // export - Export(root, path, new MeshExportSettings - { - ExportOnlyBlendShapePosition = settings.DropNormal, - UseSparseAccessorForMorphTarget = settings.Sparse, - DivideVertexBuffer = settings.DivideVertexBuffer, - }, settings.InverseAxis); } } } diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/M17N.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/M17N.cs index 5fe1f692a8..bec3eea5bf 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/M17N.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/M17N.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using UnityEditor; -namespace UniGLTF +namespace UniGLTF.M17N { /// /// 多言語対応 @@ -68,17 +69,41 @@ public static string Get(Languages language, T key) return map[key]; } } - public static class Getter + public static class LanguageGetter { const string LANG_KEY = "VRM_LANG"; - static Languages? m_lang; + static Dictionary CultureMap = new Dictionary + { + {new CultureInfo("ja-JP",false), Languages.ja}, + }; + + static Languages? s_lang; public static Languages Lang { get { - return m_lang.GetValueOrDefault(); + if (!s_lang.HasValue) + { + var value = EditorPrefs.GetString(LANG_KEY); + if (!string.IsNullOrEmpty(value) && Enum.TryParse(value, true, out Languages parsed)) + { + s_lang = parsed; + } + else + { + if (CultureMap.TryGetValue(CultureInfo.CurrentCulture, out Languages lang)) + { + s_lang = lang; + } + else + { + s_lang = default(Languages); + } + } + } + return s_lang.GetValueOrDefault(); } } @@ -92,8 +117,8 @@ public static void OnGuiSelectLang() var lang = (Languages)EditorGUILayout.EnumPopup("lang", Lang); if (lang != Lang) { - m_lang = lang; - EditorPrefs.SetString(LANG_KEY, Getter.Lang.ToString()); + s_lang = lang; + EditorPrefs.SetString(LANG_KEY, LanguageGetter.Lang.ToString()); } } } diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs new file mode 100644 index 0000000000..b2ed86a7b2 --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs @@ -0,0 +1,26 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF +{ + public static class SaveFileDialog + { + static string m_lastExportDir; + public static string GetPath(string title, string name, params string[] extensions) + { + string directory = m_lastExportDir; + if (string.IsNullOrEmpty(directory)) + { + directory = Directory.GetParent(Application.dataPath).ToString(); + } + + var path = EditorUtility.SaveFilePanel(title, directory, name, string.Join(",", extensions)); + if (!string.IsNullOrEmpty(path)) + { + m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/"); + } + return path; + } + } +} diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs.meta b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs.meta new file mode 100644 index 0000000000..1135ac0025 --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/SaveFileDialog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35dc28badc82c5e4a8aa813ddd3369fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/Valildators/HierarchyValidator.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/Valildators/HierarchyValidator.cs index ad8d4a48be..641e7d1bfa 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/Valildators/HierarchyValidator.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/Valildators/HierarchyValidator.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using UniGLTF.M17N; using UnityEngine; namespace UniGLTF diff --git a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/Valildators/NameValidator.cs b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/Valildators/NameValidator.cs index 7db19e374d..ba29e59d8c 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/Valildators/NameValidator.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ExportDialog/Valildators/NameValidator.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using UniGLTF.M17N; using UnityEditor; using UnityEngine; diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporter.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporter.cs index dead09d4f5..0f05db5200 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporter.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GlbScriptedImporter.cs @@ -1,5 +1,5 @@ - using UnityEngine; +using UnityEditor; #if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; #else @@ -13,10 +13,16 @@ namespace UniGLTF public class GlbScriptedImporter : ScriptedImporter { [SerializeField] - Axises m_reverseAxis = default; + Axises m_reverseAxis; public override void OnImportAsset(AssetImportContext ctx) { + var asset = AssetDatabase.LoadAssetAtPath(ctx.assetPath); + if (asset == null) + { + // first time. set default setting + m_reverseAxis = UniGLTFPreference.GltfIOAxis; + } ScriptedImporterImpl.Import(this, ctx, m_reverseAxis); } } diff --git a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs index 4719acf336..8808278972 100644 --- a/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs +++ b/Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/GltfScriptedImporter.cs @@ -1,5 +1,5 @@ - using UnityEngine; +using UnityEditor; #if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; #else @@ -17,6 +17,12 @@ public class GltfScriptedImporter : ScriptedImporter public override void OnImportAsset(AssetImportContext ctx) { + var asset = AssetDatabase.LoadAssetAtPath(ctx.assetPath); + if (asset == null) + { + // first time. set default setting + m_reverseAxis = UniGLTFPreference.GltfIOAxis; + } ScriptedImporterImpl.Import(this, ctx, m_reverseAxis); } } diff --git a/Assets/UniGLTF/Editor/UniGLTF/UniGLTFPreference.cs b/Assets/UniGLTF/Editor/UniGLTF/UniGLTFPreference.cs new file mode 100644 index 0000000000..c79eeb472f --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/UniGLTFPreference.cs @@ -0,0 +1,55 @@ +using UnityEngine; +using UnityEditor; +using System.Linq; +using System; + +namespace UniGLTF +{ + public static class UniGLTFPreference + { + [PreferenceItem("UniGLTF")] + private static void OnPreferenceGUI() + { + EditorGUI.BeginChangeCheck(); + + // language + M17N.LanguageGetter.OnGuiSelectLang(); + EditorGUILayout.HelpBox($"Custom editor language setting", MessageType.Info, true); + + // default axis + GltfIOAxis = (Axises)EditorGUILayout.EnumPopup("Default Invert axis", GltfIOAxis); + EditorGUILayout.HelpBox($"Default invert axis when glb/gltf import/export", MessageType.Info, true); + + if (EditorGUI.EndChangeCheck()) + { + } + } + + const string AXIS_KEY = "UNIGLTF_IO_AXIS"; + static Axises? s_axis; + public static Axises GltfIOAxis + { + set + { + EditorPrefs.SetString(AXIS_KEY, value.ToString()); + s_axis = value; + } + get + { + if (!s_axis.HasValue) + { + var value = EditorPrefs.GetString(AXIS_KEY, default(Axises).ToString()); + if (Enum.TryParse(value, out Axises parsed)) + { + s_axis = parsed; + } + else + { + s_axis = default(Axises); + } + } + return s_axis.Value; + } + } + } +} diff --git a/Assets/UniGLTF/Editor/UniGLTF/UniGLTFPreference.cs.meta b/Assets/UniGLTF/Editor/UniGLTF/UniGLTFPreference.cs.meta new file mode 100644 index 0000000000..4ca1ed517b --- /dev/null +++ b/Assets/UniGLTF/Editor/UniGLTF/UniGLTFPreference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08fd3e6c59bc903468e139f9e46684b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Editor/Format/HumanoidValidator.cs b/Assets/VRM/Editor/Format/HumanoidValidator.cs index 3e81e51d88..b333374b2b 100644 --- a/Assets/VRM/Editor/Format/HumanoidValidator.cs +++ b/Assets/VRM/Editor/Format/HumanoidValidator.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using UniGLTF; +using UniGLTF.M17N; using UnityEngine; namespace VRM diff --git a/Assets/VRM/Editor/Format/VRMExportSettingsEditor.cs b/Assets/VRM/Editor/Format/VRMExportSettingsEditor.cs index b4c24330ac..d805c98098 100644 --- a/Assets/VRM/Editor/Format/VRMExportSettingsEditor.cs +++ b/Assets/VRM/Editor/Format/VRMExportSettingsEditor.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Collections.Generic; using UniGLTF; +using UniGLTF.M17N; namespace VRM { @@ -48,7 +49,7 @@ public void Draw() static string Msg(Options key) { - return Getter.Msg(key); + return LanguageGetter.Msg(key); } public enum Options diff --git a/Assets/VRM/Editor/Format/VRMExporterVaildator.cs b/Assets/VRM/Editor/Format/VRMExporterVaildator.cs index edf3d15100..a8fd290cb8 100644 --- a/Assets/VRM/Editor/Format/VRMExporterVaildator.cs +++ b/Assets/VRM/Editor/Format/VRMExporterVaildator.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using UniGLTF; +using UniGLTF.M17N; using UnityEngine; namespace VRM diff --git a/Assets/VRM/Editor/Format/VRMExporterWizard.cs b/Assets/VRM/Editor/Format/VRMExporterWizard.cs index 756b754108..1bb73b27a2 100644 --- a/Assets/VRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/VRM/Editor/Format/VRMExporterWizard.cs @@ -1,14 +1,13 @@ using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Reflection; using UnityEditor; using UnityEngine; using UniGLTF; +using UniGLTF.M17N; namespace VRM { - public class VRMExporterWizard : EditorWindow + public class VRMExporterWizard : ExportDialogBase { const string CONVERT_HUMANOID_KEY = VRMVersion.MENU + "/Export " + VRMVersion.VRM_VERSION; @@ -29,8 +28,6 @@ enum Tabs } Tabs _tab; - ExporterDialogState m_state; - VRMExportSettings m_settings; VRMExportMeshes m_meshes; @@ -59,12 +56,8 @@ VRMMetaObject Meta Editor m_settingsInspector; Editor m_meshesInspector; - void OnEnable() + protected override void Initialize() { - // Debug.Log("OnEnable"); - Undo.willFlushUndoRecord += Repaint; - Selection.selectionChanged += Repaint; - m_tmpMeta = ScriptableObject.CreateInstance(); m_settings = ScriptableObject.CreateInstance(); @@ -73,8 +66,7 @@ void OnEnable() m_meshes = ScriptableObject.CreateInstance(); m_meshesInspector = Editor.CreateEditor(m_meshes); - m_state = new ExporterDialogState(); - m_state.ExportRootChanged += (root) => + State.ExportRootChanged += (root) => { // update meta if (root == null) @@ -99,20 +91,11 @@ void OnEnable() || m_meshes.Meshes.Any(x => x.ExportBlendShapeCount > 0 && !x.HasSkinning) ; } - - Repaint(); }; - m_state.ExportRoot = Selection.activeObject as GameObject; } - void OnDisable() + protected override void Clear() { - m_state.Dispose(); - - // Debug.Log("OnDisable"); - Selection.selectionChanged -= Repaint; - Undo.willFlushUndoRecord -= Repaint; - // m_metaEditor UnityEditor.Editor.DestroyImmediate(m_metaEditor); m_metaEditor = null; @@ -134,31 +117,20 @@ void OnDisable() m_meshes = null; } - public delegate Vector2 BeginVerticalScrollViewFunc(Vector2 scrollPosition, bool alwaysShowVertical, GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options); - static BeginVerticalScrollViewFunc s_func; - static BeginVerticalScrollViewFunc BeginVerticalScrollView - { - get - { - if (s_func == null) - { - var methods = typeof(EditorGUILayout).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Where(x => x.Name == "BeginVerticalScrollView").ToArray(); - var method = methods.First(x => x.GetParameters()[1].ParameterType == typeof(bool)); - s_func = (BeginVerticalScrollViewFunc)method.CreateDelegate(typeof(BeginVerticalScrollViewFunc)); - } - return s_func; - } - } - private Vector2 m_ScrollPosition; + protected override string SaveTitle => "Save vrm0"; + + protected override string SaveName => $"{State.ExportRoot.name}.vrm"; + + protected override string[] SaveExtensions => new string[] { "vrm" }; - IEnumerable ValidatorFactory() + protected override IEnumerable ValidatorFactory() { HumanoidValidator.MeshInformations = m_meshes.Meshes; HumanoidValidator.EnableFreeze = m_settings.PoseFreeze; VRMExporterValidator.ReduceBlendshape = m_settings.ReduceBlendshape; yield return HierarchyValidator.Validate; - if (!m_state.ExportRoot) + if (!State.ExportRoot) { yield break; } @@ -167,13 +139,13 @@ IEnumerable ValidatorFactory() yield return VRMExporterValidator.Validate; yield return VRMSpringBoneValidator.Validate; - var firstPerson = m_state.ExportRoot.GetComponent(); + var firstPerson = State.ExportRoot.GetComponent(); if (firstPerson != null) { yield return firstPerson.Validate; } - var proxy = m_state.ExportRoot.GetComponent(); + var proxy = State.ExportRoot.GetComponent(); if (proxy != null) { yield return proxy.Validate; @@ -183,82 +155,13 @@ IEnumerable ValidatorFactory() yield return meta.Validate; } - private void OnGUI() + protected override void ExportPath(string path) { - // ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint Aborting - // Validation により GUI の表示項目が変わる場合があるので、 - // EventType.Layout と EventType.Repaint 間で内容が変わらないようしている。 - if (Event.current.type == EventType.Layout) - { - // m_settings, m_meshes.Meshes - m_meshes.SetRoot(m_state.ExportRoot, m_settings); - m_state.Validate(ValidatorFactory()); - } - - EditorGUIUtility.labelWidth = 150; - - // lang - Getter.OnGuiSelectLang(); - - EditorGUILayout.LabelField("ExportRoot"); - { - m_state.ExportRoot = (GameObject)EditorGUILayout.ObjectField(m_state.ExportRoot, typeof(GameObject), true); - } - - // Render contents using Generic Inspector GUI - m_ScrollPosition = BeginVerticalScrollView(m_ScrollPosition, false, GUI.skin.verticalScrollbar, "OL Box"); - GUIUtility.GetControlID(645789, FocusType.Passive); - - bool modified = ScrollArea(); - - EditorGUILayout.EndScrollView(); - - // Create and Other Buttons - { - // errors - GUILayout.BeginVertical(); - // GUILayout.FlexibleSpace(); - - { - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUI.enabled = m_state.Validations.All(x => x.CanExport); - - if (GUILayout.Button("Export", GUILayout.MinWidth(100))) - { - OnExportClicked(m_state.ExportRoot, Meta != null ? Meta : m_tmpMeta, m_settings, m_meshes); - Close(); - GUIUtility.ExitGUI(); - } - GUI.enabled = true; - - GUILayout.EndHorizontal(); - } - GUILayout.EndVertical(); - } - - GUILayout.Space(8); - - if (modified) - { - m_state.Invalidate(); - } + VRMEditorExporter.Export(path, State.ExportRoot, Meta != null ? Meta : m_tmpMeta, m_settings, m_meshes.Meshes); } - bool ScrollArea() + protected override bool DoGUI() { - // - // Validation - // - foreach (var v in m_state.Validations) - { - v.DrawGUI(); - if (v.ErrorLevel == ErrorLevels.Critical) - { - // Export UI を表示しない - return false; - } - } EditorGUILayout.HelpBox($"Mesh size: {m_meshes.ExpectedExportByteSize / 1000000.0f:0.0} MByte", MessageType.Info); // @@ -308,14 +211,14 @@ bool DrawWizardGUI() break; case Tabs.BlendShape: - if (m_state.ExportRoot) + if (State.ExportRoot) { - OnBlendShapeGUI(m_state.ExportRoot.GetComponent()); + OnBlendShapeGUI(State.ExportRoot.GetComponent()); } break; case Tabs.ExportSettings: - m_settings.Root = m_state.ExportRoot; + m_settings.Root = State.ExportRoot; m_settingsInspector.OnInspectorGUI(); break; } @@ -347,7 +250,7 @@ enum BlendShapeTabMessages int m_selected = 0; void OnBlendShapeGUI(VRMBlendShapeProxy proxy) { - if (!m_state.ExportRoot.scene.IsValid()) + if (!State.ExportRoot.scene.IsValid()) { EditorGUILayout.HelpBox(BlendShapeTabMessages.CANNOT_MANIPULATE_PREFAB.Msg(), MessageType.Warning); return; @@ -386,31 +289,5 @@ void OnBlendShapeGUI(VRMBlendShapeProxy proxy) m_merger.Apply(); } } - - const string EXTENSION = ".vrm"; - private static string m_lastExportDir; - static void OnExportClicked(GameObject root, VRMMetaObject meta, VRMExportSettings settings, VRMExportMeshes meshes) - { - string directory; - if (string.IsNullOrEmpty(m_lastExportDir)) - directory = Directory.GetParent(Application.dataPath).ToString(); - else - directory = m_lastExportDir; - - // save dialog - var path = EditorUtility.SaveFilePanel( - "Save vrm", - directory, - root.name + EXTENSION, - EXTENSION.Substring(1)); - if (string.IsNullOrEmpty(path)) - { - return; - } - m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/"); - - // export - VRMEditorExporter.Export(path, root, meta, settings, meshes.Meshes); - } } } diff --git a/Assets/VRM/Editor/Meta/VRMMetaObjectEditor.cs b/Assets/VRM/Editor/Meta/VRMMetaObjectEditor.cs index 169cdac0a1..6c4fe76995 100644 --- a/Assets/VRM/Editor/Meta/VRMMetaObjectEditor.cs +++ b/Assets/VRM/Editor/Meta/VRMMetaObjectEditor.cs @@ -2,6 +2,7 @@ using UnityEngine; using System.IO; using UniGLTF; +using UniGLTF.M17N; namespace VRM { @@ -55,7 +56,7 @@ public void OnGUI() static string RequiredMessage(string name) { - switch (Getter.Lang) + switch (LanguageGetter.Lang) { case Languages.ja: return $"必須項目。{name} を入力してください"; @@ -162,7 +163,7 @@ enum MessageKeys static string Msg(MessageKeys key) { - return Getter.Msg(key); + return LanguageGetter.Msg(key); } bool m_foldoutInfo = true; diff --git a/Assets/VRM10/Editor/VRM10MetaObjectEditor.cs b/Assets/VRM10/Editor/VRM10MetaObjectEditor.cs index 3b97c6e72e..62a8c6398f 100644 --- a/Assets/VRM10/Editor/VRM10MetaObjectEditor.cs +++ b/Assets/VRM10/Editor/VRM10MetaObjectEditor.cs @@ -1,6 +1,7 @@ using UnityEditor; using UnityEngine; using UniGLTF; +using UniGLTF.M17N; namespace UniVRM10 { @@ -82,7 +83,7 @@ public void OnGUI() static string RequiredMessage(string name) { - switch (Getter.Lang) + switch (LanguageGetter.Lang) { case Languages.ja: return $"必須項目。{name} を入力してください"; @@ -184,7 +185,7 @@ enum MessageKeys static string Msg(MessageKeys key) { - return Getter.Msg(key); + return LanguageGetter.Msg(key); } bool m_foldoutInfo = true; diff --git a/Assets/VRM10/Editor/Vrm10ExportDialog.cs b/Assets/VRM10/Editor/Vrm10ExportDialog.cs index 82eee36319..81e7f26819 100644 --- a/Assets/VRM10/Editor/Vrm10ExportDialog.cs +++ b/Assets/VRM10/Editor/Vrm10ExportDialog.cs @@ -12,7 +12,7 @@ namespace UniVRM10 { - public class VRM10ExportDialog : EditorWindow + public class VRM10ExportDialog : ExportDialogBase { const string CONVERT_HUMANOID_KEY = VRMVersion.MENU + "/Export VRM-1.0"; @@ -32,8 +32,6 @@ enum Tabs } Tabs _tab; - ExporterDialogState m_state; - VRM10MetaObject m_meta; VRM10MetaObject Meta { @@ -59,21 +57,23 @@ VRM10MetaObject Meta m_meta = value; } } + + protected override string SaveTitle => "Vrm1"; + + protected override string SaveName => $"{State.ExportRoot.name}.vrm"; + protected override string[] SaveExtensions => new string[] { "vrm" }; + + VRM10MetaObject m_tmpMeta; Editor m_metaEditor; - void OnEnable() + protected override void Initialize() { - // Debug.Log("OnEnable"); - Undo.willFlushUndoRecord += Repaint; - Selection.selectionChanged += Repaint; - m_tmpMeta = ScriptableObject.CreateInstance(); m_tmpMeta.Authors = new List { "" }; - m_state = new ExporterDialogState(); - m_state.ExportRootChanged += (root) => + State.ExportRootChanged += (root) => { // update meta if (root == null) @@ -98,42 +98,19 @@ void OnEnable() // || m_meshes.Meshes.Any(x => x.ExportBlendShapeCount > 0 && !x.HasSkinning) // ; } - - Repaint(); }; - m_state.ExportRoot = Selection.activeObject as GameObject; } - void OnDisable() + protected override void Clear() { - m_state.Dispose(); - - // Debug.Log("OnDisable"); - Selection.selectionChanged -= Repaint; - Undo.willFlushUndoRecord -= Repaint; - } - - public delegate Vector2 BeginVerticalScrollViewFunc(Vector2 scrollPosition, bool alwaysShowVertical, GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options); - static BeginVerticalScrollViewFunc s_func; - static BeginVerticalScrollViewFunc BeginVerticalScrollView - { - get - { - if (s_func == null) - { - var methods = typeof(EditorGUILayout).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Where(x => x.Name == "BeginVerticalScrollView").ToArray(); - var method = methods.First(x => x.GetParameters()[1].ParameterType == typeof(bool)); - s_func = (BeginVerticalScrollViewFunc)method.CreateDelegate(typeof(BeginVerticalScrollViewFunc)); - } - return s_func; - } + ScriptableObject.DestroyImmediate(m_tmpMeta); + m_tmpMeta = null; } - private Vector2 m_ScrollPosition; - IEnumerable ValidatorFactory() + protected override IEnumerable ValidatorFactory() { yield return HierarchyValidator.Validate; - if (!m_state.ExportRoot) + if (!State.ExportRoot) { yield break; } @@ -144,13 +121,13 @@ IEnumerable ValidatorFactory() // yield return VRMExporterValidator.Validate; // yield return VRMSpringBoneValidator.Validate; - // var firstPerson = m_state.ExportRoot.GetComponent(); + // var firstPerson = State.ExportRoot.GetComponent(); // if (firstPerson != null) // { // yield return firstPerson.Validate; // } - // var proxy = m_state.ExportRoot.GetComponent(); + // var proxy = State.ExportRoot.GetComponent(); // if (proxy != null) // { // yield return proxy.Validate; @@ -160,81 +137,36 @@ IEnumerable ValidatorFactory() yield return meta.Validate; } - private void OnGUI() + // private void OnGUI() + // { + // { + // var path = SaveFileDialog.GetPath("Save vrm1", $"{State.ExportRoot.name}.vrm", "vrm"); + // if (!string.IsNullOrEmpty(path)) + // { + // // export + // Export(State.ExportRoot, path); + // // close + // Close(); + // GUIUtility.ExitGUI(); + // } + // } + // GUI.enabled = true; + + // GUILayout.EndHorizontal(); + // } + // GUILayout.EndVertical(); + // } + + // GUILayout.Space(8); + + // if (modified) + // { + // State.Invalidate(); + // } + // } + + protected override bool DoGUI() { - // ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint Aborting - // Validation により GUI の表示項目が変わる場合があるので、 - // EventType.Layout と EventType.Repaint 間で内容が変わらないようしている。 - if (Event.current.type == EventType.Layout) - { - m_state.Validate(ValidatorFactory()); - } - - EditorGUIUtility.labelWidth = 150; - - // lang - Getter.OnGuiSelectLang(); - - EditorGUILayout.LabelField("ExportRoot"); - { - m_state.ExportRoot = (GameObject)EditorGUILayout.ObjectField(m_state.ExportRoot, typeof(GameObject), true); - } - - // Render contents using Generic Inspector GUI - m_ScrollPosition = BeginVerticalScrollView(m_ScrollPosition, false, GUI.skin.verticalScrollbar, "OL Box"); - GUIUtility.GetControlID(645789, FocusType.Passive); - - bool modified = ScrollArea(); - - EditorGUILayout.EndScrollView(); - - // Create and Other Buttons - { - // errors - GUILayout.BeginVertical(); - // GUILayout.FlexibleSpace(); - - { - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUI.enabled = m_state.Validations.All(x => x.CanExport); - - if (GUILayout.Button("Export", GUILayout.MinWidth(100))) - { - OnExportClicked(m_state.ExportRoot); - Close(); - GUIUtility.ExitGUI(); - } - GUI.enabled = true; - - GUILayout.EndHorizontal(); - } - GUILayout.EndVertical(); - } - - GUILayout.Space(8); - - if (modified) - { - m_state.Invalidate(); - } - } - - bool ScrollArea() - { - // - // Validation - // - foreach (var v in m_state.Validations) - { - v.DrawGUI(); - if (v.ErrorLevel == ErrorLevels.Critical) - { - // Export UI を表示しない - return false; - } - } - if (m_tmpMeta == null) { // disabled @@ -274,32 +206,14 @@ bool ScrollArea() string m_logLabel; - const string EXTENSION = ".vrm"; - private static string m_lastExportDir; - void OnExportClicked(GameObject root) + protected override void ExportPath(string path) { m_logLabel = ""; - string directory; - if (string.IsNullOrEmpty(m_lastExportDir)) - directory = Directory.GetParent(Application.dataPath).ToString(); - else - directory = m_lastExportDir; - - // save dialog - var path = EditorUtility.SaveFilePanel( - "Save vrm", - directory, - root.name + EXTENSION, - EXTENSION.Substring(1)); - if (string.IsNullOrEmpty(path)) - { - return; - } - m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/"); - m_logLabel += $"export...\n"; + var root = State.ExportRoot; + try { var converter = new UniVRM10.RuntimeVrmConverter();