From a5a21847627a81e7d53c841a69bb46fd65f3f643 Mon Sep 17 00:00:00 2001 From: mr-phazer Date: Tue, 28 Jan 2025 14:02:44 +0100 Subject: [PATCH 01/14] All changes --- .../Common/ImageProcessor/IImageProcessor.cs | 17 + .../ImageProcessor/ImageProcessorFactory.cs | 32 ++ .../Common/ImportExportSupportEnum.cs | 9 + .../DependencyInjectionContainer.cs | 10 +- .../Editors.ImportExport.csproj | 1 + .../Exporting/ExportFileContextMenuHelper.cs | 6 +- .../DdsToMaterialPngExporter.cs | 11 +- .../DdsToNormalPng/DdsToNormalPngExporter.cs | 11 +- .../Exporters/DdsToPng/DdsToPngExporter.cs | 7 +- .../RmvToGltf/Helpers/GltfSkeletonBuilder.cs | 1 - .../Helpers/SkeletalAnimationMath.cs | 58 ++- .../Exporters/RmvToGltf/RmvToGltfExporter.cs | 9 +- .../DdsToMaterialPngViewModel.cs | 4 +- .../DdsToNormalPng/DdsToNormalPngViewModel.cs | 4 +- .../DdsToPng/DdsToPngExporterViewModel.cs | 4 +- .../Presentation/ExporterCoreViewModel.cs | 6 +- .../Presentation/IExporterViewModel.cs | 4 +- .../RmvToGltf/RmvToGltfExporterViewModel.cs | 4 +- .../Importing/DisplayImportFileToolCommand.cs | 70 ++-- .../Importing/ImportFIleContextMenuHelper.cs | 14 +- .../Importers/GltfToRmv/GltfImporter.cs | 116 +++++- .../GltfToRmv/GltfImporterSettings.cs | 8 +- .../GltfToRmv/Helper/AnimationBuilder.cs | 130 +++++++ .../GltfToRmv/Helper/MeshWeightValidator.cs | 9 +- .../Helper/Rmv2FromGltfFIleConverter.cs | 352 +++++++++--------- .../GltfToRmv/Helper/RmvMaterialBuilder.cs | 184 +++++++++ .../GltfToRmv/Helper/RmvMeshBuilder.cs | 54 +-- .../PngToDds/Helpers/ColorChannels.cs | 107 ++++++ .../PngToDds/Helpers/DDSFormatHelper.cs | 74 ++++ .../BlenderToWH3MaterialMapProcessor.cs | 43 +++ .../BlueToOrangeNormalMapImageProcessor.cs | 47 +++ .../ImageProcessor/DefaultImageProcessor.cs | 36 ++ .../Importers/PngToDds/PngToDdsImporter.cs | 36 +- .../GltfToRmv/RmvToGltfImporterView.xaml | 75 ++++ .../GltfToRmv/RmvToGltfImporterView.xaml.cs | 29 ++ .../GltfToRmv/RmvToGltfImporterViewModel.cs | 46 +++ .../Presentation/IImporterViewModel.cs | 20 + .../Importing/Presentation/ImportWindow.xaml | 53 +++ .../Presentation/ImportWindow.xaml.cs | 49 +++ .../Presentation/ImporterCoreViewModel.cs | 86 +++++ .../Misc/ExportSupportEnum.cs | 9 - .../Misc/FileExtensionHelper.cs | 5 + .../GltfIToRmvImporterTests.cs | 26 +- .../External/IImportFileContextMenuHelper.cs | 6 +- 44 files changed, 1542 insertions(+), 340 deletions(-) create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Common/ImageProcessor/IImageProcessor.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Common/ImageProcessor/ImageProcessorFactory.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Common/ImportExportSupportEnum.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/AnimationBuilder.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/RmvMaterialBuilder.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ColorChannels.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/DDSFormatHelper.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/BlenderToWH3MaterialMapProcessor.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/BlueToOrangeNormalMapImageProcessor.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/DefaultImageProcessor.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterView.xaml create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterView.xaml.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterViewModel.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/IImporterViewModel.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/ImportWindow.xaml create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/ImportWindow.xaml.cs create mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/ImporterCoreViewModel.cs delete mode 100644 Editors/ImportExportEditor/Editors.ImportExport/Misc/ExportSupportEnum.cs diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Common/ImageProcessor/IImageProcessor.cs b/Editors/ImportExportEditor/Editors.ImportExport/Common/ImageProcessor/IImageProcessor.cs new file mode 100644 index 000000000..0f7c5d732 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Common/ImageProcessor/IImageProcessor.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DirectXTexNet; +using Shared.Core.Settings; +using Shared.GameFormats.RigidModel.Types; + +namespace Editors.ImportExport.Common.Interfaces +{ + public interface IImageProcessor + { + ScratchImage Transform(ScratchImage scratchImage); + } + +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Common/ImageProcessor/ImageProcessorFactory.cs b/Editors/ImportExportEditor/Editors.ImportExport/Common/ImageProcessor/ImageProcessorFactory.cs new file mode 100644 index 000000000..6400cd71a --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Common/ImageProcessor/ImageProcessorFactory.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Editors.ImportExport.Importing.Importers.PngToDds.Helpers.ImageProcessor; +using Shared.Core.Settings; +using Shared.GameFormats.RigidModel.Types; + +namespace Editors.ImportExport.Common.Interfaces +{ + public static class ImageProcessorFactory + { + private static readonly Dictionary _textureAndGameTypeToTranformer = new Dictionary() + { + {TextureType.Diffuse, new DefaultImageProcessor() }, + {TextureType.MaterialMap, new BlenderToWH3MaterialMapProcessor() }, + {TextureType.BaseColour, new DefaultImageProcessor() }, + {TextureType.Normal, new BlueToOrangeNormalMapProcessor() } + }; + + public static IImageProcessor CreateImageProcessor(TextureType textureType) + { + if (_textureAndGameTypeToTranformer.TryGetValue(textureType, out var imageProcessor)) + { + return imageProcessor; + } + + return new DefaultImageProcessor(); + } + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Common/ImportExportSupportEnum.cs b/Editors/ImportExportEditor/Editors.ImportExport/Common/ImportExportSupportEnum.cs new file mode 100644 index 000000000..498a8293d --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Common/ImportExportSupportEnum.cs @@ -0,0 +1,9 @@ +namespace Editors.ImportExport.Common +{ + public enum ImportExportSupportEnum + { + Supported, + NotSupported, + HighPriority + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/DependencyInjectionContainer.cs b/Editors/ImportExportEditor/Editors.ImportExport/DependencyInjectionContainer.cs index 28777f699..eff9883f9 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/DependencyInjectionContainer.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/DependencyInjectionContainer.cs @@ -13,9 +13,11 @@ using Editors.ImportExport.Importing; using Editors.ImportExport.Importing.Importers.GltfToRmv; using Editors.ImportExport.Importing.Importers.GltfToRmv.Helper; +using Editors.ImportExport.Importing.Presentation; using Microsoft.Extensions.DependencyInjection; using Shared.Core.DependencyInjection; using Shared.Core.DevConfig; +using Editors.ImportImport.Importing.Presentation.RmvToGltf; using Shared.Ui.BaseDialogs.PackFileTree.ContextMenu.External; namespace Editors.ImportExport @@ -38,8 +40,14 @@ public override void Register(IServiceCollection services) services.AddTransient(); services.AddTransient(); + // Importer ViewModels + RegisterWindow(services); + services.AddTransient(); + services.AddTransient(); + // Importers services.AddTransient(); + services.AddTransient(); // Image Save Helper services.AddScoped(); @@ -57,7 +65,7 @@ public override void Register(IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); - + RegisterAllAsInterface(services, ServiceLifetime.Transient); } } diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Editors.ImportExport.csproj b/Editors/ImportExportEditor/Editors.ImportExport/Editors.ImportExport.csproj index bb9a9ed0f..b164b566f 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Editors.ImportExport.csproj +++ b/Editors/ImportExportEditor/Editors.ImportExport/Editors.ImportExport.csproj @@ -17,6 +17,7 @@ + diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/ExportFileContextMenuHelper.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/ExportFileContextMenuHelper.cs index 3ed499e02..13332694e 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/ExportFileContextMenuHelper.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/ExportFileContextMenuHelper.cs @@ -1,5 +1,5 @@ -using Editors.ImportExport.Exporting.Exporters; -using Editors.ImportExport.Misc; +using Editors.ImportExport.Common; +using Editors.ImportExport.Exporting.Exporters; using Shared.Core.Events; using Shared.Core.PackFiles.Models; using Shared.Core.Settings; @@ -27,7 +27,7 @@ public bool CanExportFile(PackFile packFile) foreach (var exporter in _exporterViewModels) { - if (exporter.CanExportFile(packFile) != ExportSupportEnum.NotSupported) + if (exporter.CanExportFile(packFile) != ImportExportSupportEnum.NotSupported) return true; } return false; diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToMaterialPng/DdsToMaterialPngExporter.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToMaterialPng/DdsToMaterialPngExporter.cs index aada44e0c..7e2698dd0 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToMaterialPng/DdsToMaterialPngExporter.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToMaterialPng/DdsToMaterialPngExporter.cs @@ -1,5 +1,6 @@ using System.Drawing; using System.IO; +using Editors.ImportExport.Common; using Editors.ImportExport.Misc; using MeshImportExport; using Shared.Core.PackFiles; @@ -11,7 +12,7 @@ namespace Editors.ImportExport.Exporting.Exporters.DdsToMaterialPng public interface IDdsToMaterialPngExporter { public string Export(string filePath, string outputPath, bool convertToBlenderFormat); - public ExportSupportEnum CanExportFile(PackFile file); + public ImportExportSupportEnum CanExportFile(PackFile file); } public class DdsToMaterialPngExporter : IDdsToMaterialPngExporter @@ -52,13 +53,13 @@ public string Export(string filePath, string outputPath, bool convertToBlenderFo return outFilePath; } - public ExportSupportEnum CanExportFile(PackFile file) + public ImportExportSupportEnum CanExportFile(PackFile file) { if (FileExtensionHelper.IsDdsMaterialFile(file.Name)) - return ExportSupportEnum.HighPriority; + return ImportExportSupportEnum.HighPriority; else if (FileExtensionHelper.IsDdsFile(file.Name)) - return ExportSupportEnum.Supported; - return ExportSupportEnum.NotSupported; + return ImportExportSupportEnum.Supported; + return ImportExportSupportEnum.NotSupported; } byte[] ConvertToBlenderFormat(byte[] imgBytes, string outputPath, string fileDirectory) diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToNormalPng/DdsToNormalPngExporter.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToNormalPng/DdsToNormalPngExporter.cs index dafbf1cf2..e2fef43e7 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToNormalPng/DdsToNormalPngExporter.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToNormalPng/DdsToNormalPngExporter.cs @@ -1,6 +1,7 @@ using System.Drawing; using System.IO; using System.Numerics; +using Editors.ImportExport.Common; using Editors.ImportExport.Misc; using MeshImportExport; using Shared.Core.PackFiles; @@ -12,7 +13,7 @@ namespace Editors.ImportExport.Exporting.Exporters.DdsToNormalPng public interface IDdsToNormalPngExporter { public string Export(string filePath, string outputPath, bool convertToBlueNormalMap); - public ExportSupportEnum CanExportFile(PackFile file); + public ImportExportSupportEnum CanExportFile(PackFile file); } public class DdsToNormalPngExporter : IDdsToNormalPngExporter @@ -26,13 +27,13 @@ public DdsToNormalPngExporter(IPackFileService packFileService, IImageSaveHandle _imageSaveHandler = imageSaveHandler; } - public ExportSupportEnum CanExportFile(PackFile file) + public ImportExportSupportEnum CanExportFile(PackFile file) { if (FileExtensionHelper.IsDdsMaterialFile(file.Name)) - return ExportSupportEnum.HighPriority; + return ImportExportSupportEnum.HighPriority; else if (FileExtensionHelper.IsDdsFile(file.Name)) - return ExportSupportEnum.Supported; - return ExportSupportEnum.NotSupported; + return ImportExportSupportEnum.Supported; + return ImportExportSupportEnum.NotSupported; } public string Export(string filePath, string outputPath, bool convertToBlueNormalMap) diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToPng/DdsToPngExporter.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToPng/DdsToPngExporter.cs index f8607a572..b7c958c24 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToPng/DdsToPngExporter.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/DdsToPng/DdsToPngExporter.cs @@ -1,4 +1,5 @@ using System.IO; +using Editors.ImportExport.Common; using Editors.ImportExport.Misc; using MeshImportExport; using Shared.Core.PackFiles; @@ -16,11 +17,11 @@ public DdsToPngExporter(IPackFileService pfs, IImageSaveHandler imageSaveHandler _packFileService = pfs; _imageSaveHandler = imageSaveHandler; } - internal ExportSupportEnum CanExportFile(PackFile file) + internal ImportExportSupportEnum CanExportFile(PackFile file) { if (FileExtensionHelper.IsDdsFile(file.Name)) - return ExportSupportEnum.Supported; - return ExportSupportEnum.NotSupported; + return ImportExportSupportEnum.Supported; + return ImportExportSupportEnum.NotSupported; } public void Export(string outputPath, PackFile file) diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/Helpers/GltfSkeletonBuilder.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/Helpers/GltfSkeletonBuilder.cs index 5ca8377fd..914568be2 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/Helpers/GltfSkeletonBuilder.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/Helpers/GltfSkeletonBuilder.cs @@ -1,6 +1,5 @@ using System.Numerics; using Editors.ImportExport.Common; -using Editors.ImportExport.Exporting.Exporters.GltfSkeleton; using Editors.Shared.Core.Services; using GameWorld.Core.Animation; using GameWorld.Core.SceneNodes; diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/Helpers/SkeletalAnimationMath.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/Helpers/SkeletalAnimationMath.cs index 114a11146..40f706bf0 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/Helpers/SkeletalAnimationMath.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/Helpers/SkeletalAnimationMath.cs @@ -1,8 +1,10 @@ using Editors.ImportExport.Common; using Microsoft.Xna.Framework; using Shared.GameFormats.Animation; +using SharpGLTF.Animations; +using SharpGLTF.Schema2; -namespace Editors.ImportExport.Exporting.Exporters.GltfSkeleton +namespace Editors.ImportExport.Exporting.Exporters.RmvToGltf.Helpers { public class TransformData { @@ -32,7 +34,51 @@ public Matrix GlobalTransform } } } + public class GltfAnimationTrackSampler + { + static public Vector3 SampleTranslation(ModelRoot model, string boneName, float time) + { + // Access the first animation + var animation = model.LogicalAnimations[0]; + + // Access the first node + var node = model.LogicalNodes.FirstOrDefault(n => n.Name.ToLower() == boneName.ToLower()); + + if (node == null) + { + throw new Exception("Error, Unexpected, Node not found"); + } + + // Get the translation sampler for the node + var translationSampler = animation.FindTranslationChannel(node).GetTranslationSampler().CreateCurveSampler(); + + var translationVector = translationSampler.GetPoint(time); + + return GlobalSceneTransforms.FlipVector(translationVector, true); + } + + static public Quaternion SampleQuaternion(ModelRoot model, string boneName, float time) + { + // Access the first animation + var animation = model.LogicalAnimations[0]; + // Access the first nodef + var node = model.LogicalNodes.FirstOrDefault(n => n.Name.ToLower() == boneName.ToLower()); + + if (node == null) + { + throw new Exception("Error, Unexpected, Node not found"); + } + + // Get the translation sampler for the node + var quaternionSampler = animation.FindRotationChannel(node).GetRotationSampler().CreateCurveSampler(); + + var outQuaternion = quaternionSampler.GetPoint(time); + + return GlobalSceneTransforms.FlipQuaternion(outQuaternion, true); + } + + } internal class FramePoseMatrixCalculator { private readonly AnimationFile _animationFile; @@ -83,13 +129,13 @@ private static void ValidDateSkeletonFile(AnimationFile file) throw new Exception($"No anim parts! Bone Count: {file.Bones.Length}"); if (file.AnimationParts[0].DynamicFrames.Count == 0) - throw new Exception($"No anim frames, in part 0! Bone Count: {file.Bones.Length}, Anim Parts Count: {file.AnimationParts.Count}"); + throw new Exception($"No anim frames, in part 0! Bone Count: {file.Bones.Length}, Anim Parts Count: {file.AnimationParts.Count}"); if (file.AnimationParts[0].DynamicFrames[0].Quaternion.Count != file.Bones.Length) - throw new Exception($"Not a valid skeleton file, doesn't contain quaternion values for all bones! Quat count frame 0: {file.AnimationParts[0].DynamicFrames[0].Quaternion.Count}, Bone count {file.Bones.Length}"); - + throw new Exception($"Not a valid skeleton file, doesn't contain quaternion values for all bones! Quat count frame 0: {file.AnimationParts[0].DynamicFrames[0].Quaternion.Count}, Bone count {file.Bones.Length}"); + if (file.AnimationParts[0].DynamicFrames[0].Transforms.Count != file.Bones.Length) - throw new Exception($"Not a valid skeleton file, doesn't contain translation values for all bones! Trans count frame 0: {file.AnimationParts[0].DynamicFrames[0].Transforms.Count}, Bone count {file.Bones.Length}"); + throw new Exception($"Not a valid skeleton file, doesn't contain translation values for all bones! Trans count frame 0: {file.AnimationParts[0].DynamicFrames[0].Transforms.Count}, Bone count {file.Bones.Length}"); } private void RebuildSkeletonGlobalMatrices(bool doMirror) @@ -104,7 +150,7 @@ private void RebuildSkeletonGlobalMatrices(bool doMirror) _worldTransform[boneIndex] = transform; } - for (var i = 0; i < _worldTransform.Length; i++) + for (var i = 0; i < _worldTransform.Length; i++) { var parentIndex = _animationFile.Bones[i].ParentId; diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/RmvToGltfExporter.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/RmvToGltfExporter.cs index ad9d71862..7896ee6c5 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/RmvToGltfExporter.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Exporters/RmvToGltf/RmvToGltfExporter.cs @@ -1,4 +1,5 @@ using System.Windows; +using Editors.ImportExport.Common; using Editors.ImportExport.Exporting.Exporters.RmvToGltf.Helpers; using Editors.ImportExport.Misc; using Editors.Shared.Core.Services; @@ -33,13 +34,13 @@ public RmvToGltfExporter(IGltfSceneSaver gltfSaver, GltfMeshBuilder gltfMeshBuil _skeletonLookUpHelper = skeletonLookUpHelper; } - internal ExportSupportEnum CanExportFile(PackFile file) + internal ImportExportSupportEnum CanExportFile(PackFile file) { if (FileExtensionHelper.IsRmvFile(file.Name)) - return ExportSupportEnum.HighPriority; + return ImportExportSupportEnum.HighPriority; if (FileExtensionHelper.IsWsModelFile(file.Name)) - return ExportSupportEnum.NotSupported; // This should be supported in the future - return ExportSupportEnum.NotSupported; + return ImportExportSupportEnum.NotSupported; // This should be supported in the future + return ImportExportSupportEnum.NotSupported; } public void Export(RmvToGltfExporterSettings settings) diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToMaterialPng/DdsToMaterialPngViewModel.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToMaterialPng/DdsToMaterialPngViewModel.cs index 384547133..fe8cfc9e2 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToMaterialPng/DdsToMaterialPngViewModel.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToMaterialPng/DdsToMaterialPngViewModel.cs @@ -1,7 +1,7 @@ using CommunityToolkit.Mvvm.ComponentModel; +using Editors.ImportExport.Common; using Editors.ImportExport.Exporting.Exporters; using Editors.ImportExport.Exporting.Exporters.DdsToMaterialPng; -using Editors.ImportExport.Misc; using Shared.Core.PackFiles.Models; using Shared.Ui.Common.DataTemplates; @@ -20,7 +20,7 @@ public DdsToMaterialPngViewModel(IDdsToMaterialPngExporter exporter) _exporter = exporter; } - public ExportSupportEnum CanExportFile(PackFile file) => _exporter.CanExportFile(file); + public ImportExportSupportEnum CanExportFile(PackFile file) => _exporter.CanExportFile(file); public void Execute(PackFile exportSource, string outputPath, bool generateImporter) { diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToNormalPng/DdsToNormalPngViewModel.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToNormalPng/DdsToNormalPngViewModel.cs index ec5428387..c2d83003d 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToNormalPng/DdsToNormalPngViewModel.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToNormalPng/DdsToNormalPngViewModel.cs @@ -1,7 +1,7 @@ using CommunityToolkit.Mvvm.ComponentModel; +using Editors.ImportExport.Common; using Editors.ImportExport.Exporting.Exporters; using Editors.ImportExport.Exporting.Exporters.DdsToNormalPng; -using Editors.ImportExport.Misc; using Shared.Core.PackFiles; using Shared.Core.PackFiles.Models; using Shared.Ui.Common.DataTemplates; @@ -21,7 +21,7 @@ public DdsToNormalPngViewModel(IDdsToNormalPngExporter exporter) _exporter = exporter; } - public ExportSupportEnum CanExportFile(PackFile file) => _exporter.CanExportFile(file); + public ImportExportSupportEnum CanExportFile(PackFile file) => _exporter.CanExportFile(file); public void Execute(PackFile exportSource, string outputPath, bool generateImporter) { diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToPng/DdsToPngExporterViewModel.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToPng/DdsToPngExporterViewModel.cs index 1f6840c94..c74521cf8 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToPng/DdsToPngExporterViewModel.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/DdsToPng/DdsToPngExporterViewModel.cs @@ -1,7 +1,7 @@ using CommunityToolkit.Mvvm.ComponentModel; +using Editors.ImportExport.Common; using Editors.ImportExport.Exporting.Exporters; using Editors.ImportExport.Exporting.Exporters.DdsToPng; -using Editors.ImportExport.Misc; using Shared.Core.PackFiles.Models; using Shared.Ui.Common.DataTemplates; @@ -22,7 +22,7 @@ public DdsToPngExporterViewModel(DdsToPngExporter exporter) _exporter = exporter; } - public ExportSupportEnum CanExportFile(PackFile file) => _exporter.CanExportFile(file); + public ImportExportSupportEnum CanExportFile(PackFile file) => _exporter.CanExportFile(file); public void Execute(PackFile exportSource, string outputPath, bool generateImporter) { diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/ExporterCoreViewModel.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/ExporterCoreViewModel.cs index 70b2c9ed1..66a203426 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/ExporterCoreViewModel.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/ExporterCoreViewModel.cs @@ -2,8 +2,8 @@ using System.IO; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using Editors.ImportExport.Common; using Editors.ImportExport.Exporting.Exporters; -using Editors.ImportExport.Misc; using Shared.Core.PackFiles.Models; namespace Editors.ImportExport.Exporting.Presentation @@ -40,11 +40,11 @@ public void Initialize(PackFile packFile) foreach (var viewModel in _exporterViewModels) { var supported = viewModel.CanExportFile(packFile); - if (supported == ExportSupportEnum.NotSupported) + if (supported == ImportExportSupportEnum.NotSupported) continue; PossibleExporters.Add(viewModel); - if(supported == ExportSupportEnum.HighPriority) + if(supported == ImportExportSupportEnum.HighPriority) SelectedExporter = viewModel; } diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/IExporterViewModel.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/IExporterViewModel.cs index 0c8968866..e6a5d07dd 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/IExporterViewModel.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/IExporterViewModel.cs @@ -1,4 +1,4 @@ -using Editors.ImportExport.Misc; +using Editors.ImportExport.Common; using Shared.Core.PackFiles.Models; namespace Editors.ImportExport.Exporting.Exporters @@ -10,6 +10,6 @@ public interface IExporterViewModel string OutputExtension { get; } public void Execute(PackFile exportSource, string outputPath, bool generateImporter); - public ExportSupportEnum CanExportFile(PackFile file); + public ImportExportSupportEnum CanExportFile(PackFile file); } } diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/RmvToGltf/RmvToGltfExporterViewModel.cs b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/RmvToGltf/RmvToGltfExporterViewModel.cs index 37f6541bc..a7bef0a0f 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/RmvToGltf/RmvToGltfExporterViewModel.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Exporting/Presentation/RmvToGltf/RmvToGltfExporterViewModel.cs @@ -1,7 +1,7 @@ using CommunityToolkit.Mvvm.ComponentModel; +using Editors.ImportExport.Common; using Editors.ImportExport.Exporting.Exporters; using Editors.ImportExport.Exporting.Exporters.RmvToGltf; -using Editors.ImportExport.Misc; using Shared.Core.PackFiles.Models; using Shared.Ui.Common.DataTemplates; @@ -24,7 +24,7 @@ public RmvToGltfExporterViewModel(RmvToGltfExporter exporter) _exporter = exporter; } - public ExportSupportEnum CanExportFile(PackFile file) => _exporter.CanExportFile(file); + public ImportExportSupportEnum CanExportFile(PackFile file) => _exporter.CanExportFile(file); public void Execute(PackFile exportSource, string outputPath, bool generateImporter) { diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/DisplayImportFileToolCommand.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/DisplayImportFileToolCommand.cs index 49f259623..242096344 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Importing/DisplayImportFileToolCommand.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/DisplayImportFileToolCommand.cs @@ -1,56 +1,58 @@ using System.Windows.Forms; -using Editors.ImportExport.Importing.Importers.GltfToRmv; using Shared.Core.Events; +using Shared.Core.PackFiles.Models; using TreeNode = Shared.Ui.BaseDialogs.PackFileTree.TreeNode; +using Shared.Core.PackFiles; +using Editors.ImportExport.Importing.Importers.GltfToRmv; +using System.Windows.Forms.Design; +using Shared.Core.Settings; +using Shared.Core.Misc; +using Editors.ImportExport.Importing.Presentation; namespace Editors.ImportExport.Importing { public class DisplayImportFileToolCommand : IUiCommand - { - // TODO: ? - - private readonly GltfImporter _importer; + { + private readonly IEnumerable _importerViewModels; + private readonly IAbstractFormFactory _importWindowFactory; - - public DisplayImportFileToolCommand(GltfImporter importer) - { - // TODO: ? - //_ImportWindowFactory = importWindowFactory; - _importer = importer; + public DisplayImportFileToolCommand(IAbstractFormFactory exportWindowFactory, IEnumerable exporterViewModels) + { + _importWindowFactory = exportWindowFactory; + _importerViewModels = exporterViewModels; } - public void Execute(TreeNode clickedNode) + public void Execute(PackFileContainer packFileContainer, string packPath) { - var glftFilePath = GetFileFromDiskDialog(); - if (string.IsNullOrEmpty(glftFilePath)) + var fileExtentionFilters = GetFileDialogFilters(); + + var openFileDialog = new Microsoft.Win32.OpenFileDialog { Filter = fileExtentionFilters }; + if (openFileDialog.ShowDialog() != true) return; - var settings = new GltfImporterSettings(glftFilePath, clickedNode.GetFullPath(), clickedNode.FileOwner, true, true, true); - _importer.Import(settings); + var diskFilePath = openFileDialog.FileName; + + var window = _importWindowFactory.Create(); + window.Initialize(packFileContainer, packPath, diskFilePath); + window.ShowDialog(); } - private static string GetFileFromDiskDialog() + /// + /// Makes a filter string for the file dialog ("Word Documents|*.doc|Excel Worksheets|*.xls" ) + /// Searching all importer view models for their supported file extensions + /// + private string GetFileDialogFilters() { - string filePath = ""; - using (OpenFileDialog openFileDialog = new OpenFileDialog()) + var fileExtentionFilters = ""; + foreach (var importViewModel in _importerViewModels) // generate file dialog filters, of all support file formats { - openFileDialog.InitialDirectory = "c:\\"; - openFileDialog.Filter = "All files (*.*)|*.*|GLTF model files (*.gltf)|*.gltf"; - openFileDialog.FilterIndex = 2; - openFileDialog.RestoreDirectory = true; - - if (openFileDialog.ShowDialog() == DialogResult.OK) - { - // Get the path of specified file - filePath = openFileDialog.FileName; - } - else - { - filePath = ""; - } + var tempFilter = $"*{String.Join(";*", importViewModel.InputExtensions)}"; + fileExtentionFilters += $"{importViewModel.DisplayName} ({tempFilter}) |{tempFilter}|"; } - return filePath; + fileExtentionFilters += "All files (*.*)|*.*"; + + return fileExtentionFilters; } } } diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/ImportFIleContextMenuHelper.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/ImportFIleContextMenuHelper.cs index cff61fcdc..01c671571 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Importing/ImportFIleContextMenuHelper.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/ImportFIleContextMenuHelper.cs @@ -1,5 +1,8 @@ using System.IO; +using Editors.ImportExport.Exporting.Exporters; +using Editors.ImportExport.Misc; using Shared.Core.Events; +using Shared.Core.PackFiles.Models; using Shared.Core.Settings; using Shared.Ui.BaseDialogs.PackFileTree.ContextMenu.External; using TreeNode = Shared.Ui.BaseDialogs.PackFileTree.TreeNode; @@ -8,18 +11,21 @@ namespace Editors.ImportExport.Importing { public class ImportFileContextMenuHelper : IImportFileContextMenuHelper { + private readonly IUiCommandFactory _uiCommandFactory; + private readonly IEnumerable _exporterViewModels; private readonly ApplicationSettingsService _applicationSettings; - public ImportFileContextMenuHelper(IUiCommandFactory uiCommandFactory, ApplicationSettingsService applicationSettings) + public ImportFileContextMenuHelper(IUiCommandFactory uiCommandFactory, IEnumerable exporterViewModels, ApplicationSettingsService applicationSettings) { _uiCommandFactory = uiCommandFactory; + _exporterViewModels = exporterViewModels; _applicationSettings = applicationSettings; } - public bool CanImportFile(string filePath) + public bool CanImportFile(PackFile filePath) { - if (Path.GetExtension(filePath.ToUpperInvariant()) == new string(".gltf").ToUpperInvariant()) // mess to make sure the extension is case insensitive + if (FileExtensionHelper.IsGltfFile(filePath.Name)) // mess to make sure the extension is case insensitive { return true; } @@ -28,6 +34,6 @@ public bool CanImportFile(string filePath) } public void ShowDialog(TreeNode clickedNode) => - _uiCommandFactory.Create().Execute(clickedNode); + _uiCommandFactory.Create().Execute(clickedNode.FileOwner, clickedNode.GetFullPath()); } } diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/GltfImporter.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/GltfImporter.cs index d784a8dfa..2d128afe6 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/GltfImporter.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/GltfImporter.cs @@ -1,7 +1,12 @@ using System.IO; using CommonControls.BaseDialogs.ErrorListDialog; +using Editors.ImportExport.Common; using Editors.ImportExport.Importing.Importers.GltfToRmv.Helper; +using Editors.ImportExport.Misc; using Editors.Shared.Core.Services; +using GameWorld.Core.SceneNodes; +using Octokit; +using Serilog; using Shared.Core.ErrorHandling; using Shared.Core.PackFiles; using Shared.Core.PackFiles.Models; @@ -15,15 +20,69 @@ namespace Editors.ImportExport.Importing.Importers.GltfToRmv { public class GltfImporter { + private const string Value = "//skeleton//"; private readonly IPackFileService _packFileService; private readonly IStandardDialogs _exceptionService; + private readonly ILogger _logger = Logging.Create(); private readonly SkeletonAnimationLookUpHelper _skeletonLookUpHelper; + private readonly RmvMaterialBuilder _materialBuilder; - public GltfImporter(IPackFileService packFileSerivce, IStandardDialogs exceptionService, SkeletonAnimationLookUpHelper skeletonLookUpHelper) + public GltfImporter(IPackFileService packFileSerivce, IStandardDialogs exceptionService, SkeletonAnimationLookUpHelper skeletonLookUpHelper, RmvMaterialBuilder materialBuilder) { _packFileService = packFileSerivce; _exceptionService = exceptionService; _skeletonLookUpHelper = skeletonLookUpHelper; + _materialBuilder = materialBuilder; + } + + public ImportExportSupportEnum CanImportFile(PackFile file) + { + if (FileExtensionHelper.IsGltfFile(file.Name)) + return ImportExportSupportEnum.HighPriority; + + return ImportExportSupportEnum.NotSupported; + } + + private RmvFile? ImportMeshes(GltfImporterSettings settings, ModelRoot modelRoot, AnimationFile? skeletonAnimFile, string skeletonName) + { + var importedFileName = GetImportedPackFileName(settings); + + var rmv2File = RmvMeshBuilder.Build(settings, modelRoot, skeletonAnimFile, skeletonName); + if (rmv2File == null) + return null; + + return rmv2File; + } + + private void SaveRmvFileToPack(GltfImporterSettings settings, string importedFileName, RmvFile rmv2File) + { + var bytesRmv2 = ModelFactory.Create().Save(rmv2File); + + var packFileImported = new PackFile(importedFileName, new MemorySource(bytesRmv2)); + var newFile = new NewPackFileEntry(settings.DestinationPackPath, packFileImported); + + _packFileService.AddFilesToPack(settings.DestinationPackFileContainer, [newFile]); + } + + private void ImportMaterials(GltfImporterSettings settings, ModelRoot modelRoot, RmvFile rmv2File) + { + _materialBuilder.BuildRmvFileMaterials(settings, modelRoot, rmv2File); + } + + private void ImportAnimations(GltfImporterSettings settings, ModelRoot modelRoot, AnimationFile? skeletonAnimFile, string skeletonName) + { + var fileName = Path.GetFileNameWithoutExtension(settings.InputGltfFile); + string importedFileName = $@"{fileName}.anim"; + + var animFile = AnimationBuilder.Build(new AnimationBuilderSettings(modelRoot, skeletonName, settings.AnimationKeysPerSecond, settings.DestinationPackFileContainer, settings.DestinationPackPath), skeletonAnimFile); + + if (animFile != null) + { + var animBytes = AnimationFile.ConvertToBytes(animFile); + var packFileImported = new PackFile(importedFileName, new MemorySource(animBytes)); + var newFile = new NewPackFileEntry(settings.DestinationPackPath, packFileImported); + _packFileService.AddFilesToPack(settings.DestinationPackFileContainer, [newFile]); + } } public void Import(GltfImporterSettings settings) @@ -39,36 +98,53 @@ public void Import(GltfImporterSettings settings) return; } - var importedFileName = GetImportedPackFileName(settings); - + var skeletonData = GetSkeletonData(modelRoot); + + var rmv2File = ImportMeshes(settings, modelRoot, skeletonData.skeletonAnimFile, skeletonData.skeletonName ?? ""); + if (rmv2File == null) + throw new Exception($"Failed to import mesh, rmv2File == {rmv2File}"); + + if (settings.ImportMaterials) + ImportMaterials(settings, modelRoot, rmv2File); + + if (settings.ImportAnimations) + ImportAnimations(settings, modelRoot, skeletonData.skeletonAnimFile, skeletonData.skeletonName ?? ""); + + if (settings.ImportMeshes) + SaveRmvFileToPack(settings, GetImportedPackFileName(settings), rmv2File); + + } + + private (string? skeletonName, AnimationFile? skeletonAnimFile) GetSkeletonData(ModelRoot? modelRoot) + { + if (modelRoot == null) + throw new ArgumentException($"Invalid Input: {nameof(modelRoot)} == {modelRoot}"); + var skeletonName = FetchSkeletonIdStringFromScene(modelRoot); + if (skeletonName == null) - throw new ArgumentNullException(nameof(skeletonName), "Fatal eroro: This shouldn't be null"); + { + _logger.Information("Skeleton ID not found in scene, if the model loading is not rigged, then ignore this."); + return ("", null); + } AnimationFile? skeletonAnimFile = null; - if (skeletonName.Any()) + if (skeletonName != null && skeletonName.Any()) { skeletonAnimFile = _skeletonLookUpHelper.GetSkeletonFileFromName(skeletonName); - + if (skeletonAnimFile == null) { - var errorList = new ErrorList(); - errorList.Error("Skeleton Not Found", $"Skeleton named '{skeletonName}' could not be found\nHave you selected the correct game AND loaded all CA Pack Files?"); - + var errorList = new ErrorList(); + errorList.Error("Skeleton Not Found", $"Skeleton named '{skeletonName}' could not be found\nHave you selected the correct game AND loaded all CA Pack Files?"); + ErrorListWindow.ShowDialog("Skeleton Error", errorList); - return; + return (skeletonName = null, skeletonAnimFile = null); } } - var rmv2File = RmvMeshBuilder.Build(settings, modelRoot, skeletonAnimFile, skeletonName); - var bytesRmv2 = ModelFactory.Create().Save(rmv2File); - - var packFileImported = new PackFile(importedFileName, new MemorySource(bytesRmv2)); - - var newFile = new NewPackFileEntry(settings.DestinationPackPath, packFileImported); - _packFileService.AddFilesToPack(settings.DestinationPackFileContainer, [newFile]); - + return (skeletonName, skeletonAnimFile); } private static string GetImportedPackFileName(GltfImporterSettings settings) @@ -81,12 +157,12 @@ private static string GetImportedPackFileName(GltfImporterSettings settings) private static string FetchSkeletonIdStringFromScene(ModelRoot modelRoot) { - var nodeSearchResult = modelRoot.LogicalNodes.Where(node => node.Name.StartsWith("//skeleton//")); + var nodeSearchResult = modelRoot.LogicalNodes.Where(node => node.Name.StartsWith(Value)); if (nodeSearchResult == null || !nodeSearchResult.Any()) return ""; - var skeletonName = nodeSearchResult.First().Name.TrimStart("//skeleton//".ToCharArray()); + var skeletonName = nodeSearchResult.First().Name.TrimStart(Value.ToCharArray()); return skeletonName.ToLower(); } diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/GltfImporterSettings.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/GltfImporterSettings.cs index 1d410bca6..ed989a565 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/GltfImporterSettings.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/GltfImporterSettings.cs @@ -1,4 +1,5 @@ using Shared.Core.PackFiles.Models; +using Shared.Core.Settings; namespace Editors.ImportExport.Importing.Importers.GltfToRmv { @@ -7,8 +8,13 @@ public record GltfImporterSettings string InputGltfFile, string DestinationPackPath, PackFileContainer DestinationPackFileContainer, - bool ConvertNormalTextureToOrangeType, + GameTypeEnum GameType, + bool ImportMeshes, + bool ImportMaterials, + bool ConvertMaterialFromBlenderType, + bool ConvertNormalTextureFromBlueToOrangeType, bool ImportAnimations, + float AnimationKeysPerSecond, bool MirrorMesh ); } diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/AnimationBuilder.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/AnimationBuilder.cs new file mode 100644 index 000000000..082ba0761 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/AnimationBuilder.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using System.Text; +using System.Threading.Tasks; +using Shared.Core.ErrorHandling.Exceptions; +using SharpGLTF.Schema2; +using System.Windows; +using Shared.Core.Services; +using Shared.GameFormats.Animation; +using Shared.Core.PackFiles.Models; +using static Shared.GameFormats.Animation.AnimationFile; +using Microsoft.Xna.Framework.Graphics; +using System.Xml.Linq; +using System.Security.Authentication.ExtendedProtection; +using Editors.ImportExport.Exporting.Exporters.RmvToGltf.Helpers; +using Shared.GameFormats.RigidModel.Transforms; +using Editors.Shared.Core.Services; +using System.Windows.Media; + +namespace Editors.ImportExport.Importing.Importers.GltfToRmv.Helper +{ + public record AnimationBuilderSettings( + ModelRoot modelRoot, + string skeletonName, + float keysPerSecond, + PackFileContainer packFileContainer, + string packPath + ); + + public class AnimationBuilder + { + static public AnimationFile? Build(AnimationBuilderSettings settings, AnimationFile skeletonAnimFile) + { + if (settings.modelRoot.LogicalAnimations.Count() == 0) + return null; + + AnimationFile newAnimFile = new AnimationFile(); + + var animation = settings.modelRoot.LogicalAnimations[0]; + + var animationTime = animation.Duration; + var keyInterval = 1.0f / settings.keysPerSecond; // time between keys + var keyCount = (int)(animationTime / keyInterval); // number of keys + + newAnimFile.Header = new AnimationHeader() + { + Version = 7, + FrameRate = settings.keysPerSecond, + SkeletonName = settings.skeletonName, + + // TODO: this value is actually the time for the last key, not duration + // so, we subtract one "keytime" from the value. + AnimationTotalPlayTimeInSec = keyInterval * (float)(keyCount - 1) + }; + + newAnimFile.Bones = skeletonAnimFile.Bones; + newAnimFile.AnimationParts = new AnimationPart[1].ToList(); // ALLOCATE ONE PART + newAnimFile.AnimationParts[0] = new AnimationPart(); + var part = newAnimFile.AnimationParts[0]; + + part.DynamicFrames = new List(); + + DoQuantization(skeletonAnimFile, part); + + float keyTime = 0.0f; + for (int i = 0; i < keyCount; i++) + { + var frame = new Frame(); + FillFrame(settings, skeletonAnimFile, keyTime, frame); + part.DynamicFrames.Add(frame); + keyTime += keyInterval; + } + + return newAnimFile; + } + + private static void DoQuantization(AnimationFile skeletonAnimFile, AnimationPart part) + { + /* + -- TODO: add ANIM v6 quantization --- + + - which track are both constant and = bind pose? + - iterate through tracks, + - if track is constant and = bind pose, + - insert "-1" into the quantization list + - don't store the track in the frame + + -- TODO: add ANIM v7 quantization --- + - which track are both constant and which are = bind pose? + - iterate through tracks, + - if track is constant and = bind pose, + - insert "-1" into the quantization list + - don't store the track in the frame + - if constant but != bind pose + - adds its value to const track(aka static frame) + - in the quantization list, insert the index of the const track + 10000 + + */ + + + // set the quantization settings to UNquantized + for (int i = 0; i < skeletonAnimFile.Bones.Length; i++) + { + part.TranslationMappings.Add(new AnimationBoneMapping(i)); + part.RotationMappings.Add(new AnimationBoneMapping(i)); + } + } + + private static void FillFrame(AnimationBuilderSettings settings, AnimationFile skeletonAnimFile, float currentKeyTime, Frame frame) + { + RmvVector3[] translations = new RmvVector3[skeletonAnimFile.Bones.Length]; + RmvVector4[] quaternions = new RmvVector4[skeletonAnimFile.Bones.Length]; + + foreach (var bone in skeletonAnimFile.Bones) + { + var translation = GltfAnimationTrackSampler.SampleTranslation(settings.modelRoot, bone.Name, currentKeyTime); + var quaternion = GltfAnimationTrackSampler.SampleQuaternion(settings.modelRoot, bone.Name, currentKeyTime); + + // using the arrays with bone.id as index, makes sure sampled data is stored at the index + translations[bone.Id] = new RmvVector3(translation); + quaternions[bone.Id] = new RmvVector4(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W); + } + + frame.Transforms = translations.ToList(); + frame.Quaternion = quaternions.ToList(); + } + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/MeshWeightValidator.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/MeshWeightValidator.cs index 508ead521..62daa8462 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/MeshWeightValidator.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/MeshWeightValidator.cs @@ -24,7 +24,10 @@ static public bool Validate(RmvMesh rmv2mesh) return true; } static public void ValidateVertexWeighting(CommonVertex v) - { + { + if (v.WeightCount == 0) + throw new Exception("Error: Invalid weights, 1 of more null weights in weighted mesh"); + if (v.WeightCount != v.BoneWeight.Length || v.WeightCount != v.BoneIndex.Length) throw new Exception("Error: Invalid Vertex Weight State"); @@ -38,10 +41,8 @@ static public void ValidateVertexWeighting(CommonVertex v) const float tolerance = 0.05f; if (weightSum < (1.0f - tolerance) || weightSum > (1.0f + tolerance)) - throw new Exception("Error: sum of weights not 1.0f"); + throw new Exception("Error: sum of weights not 1.0f"); - if (v.WeightCount == 0) - throw new Exception("Error: Invalid weights, 1 of more null weights in weighted mesh"); } } } diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/Rmv2FromGltfFIleConverter.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/Rmv2FromGltfFIleConverter.cs index 56b1e6b93..52a55ccff 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/Rmv2FromGltfFIleConverter.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/Rmv2FromGltfFIleConverter.cs @@ -1,178 +1,178 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection.Metadata; -using System.Text; -using System.Threading.Tasks; -using Shared.GameFormats.RigidModel; -using SharpGLTF.Geometry.VertexTypes; -using SharpGLTF.Schema2; -using XNA = Microsoft.Xna.Framework; -using Xceed.Wpf.Toolkit.PropertyGrid.Editors; -using Editors.ImportExport.Exporting.Exporters.RmvToGltf.Helpers; -using Shared.GameFormats.RigidModel.Vertex; -using SharpGLTF.Geometry; -using System.ComponentModel.DataAnnotations; -using GameWorld.Core.Animation; -using GameWorld.Core.Rendering.Geometry; -using GameWorld.Core.Rendering.Materials.Serialization; -using GameWorld.Core.Rendering.Materials.Shaders; -using GameWorld.Core.Services; -using Shared.GameFormats.RigidModel.MaterialHeaders; -using SharpGLTF.Runtime; -using Shared.GameFormats.RigidModel.LodHeader; -using Shared; -using SharpDX.MediaFoundation; -using Editors.ImportExport.Common; -using Pfim; - -namespace Editors.ImportExport.Importing.Importers.GltfToRmv.Helper -{ - public class Rmv2FromGltfFIleConverter - { - private ModelRoot? _modelRoot; - - private void LoadGltfScene(GltfImporterSettings settings) - { - _modelRoot = ModelRoot.Load(settings.InputGltfFile); - } - - public RmvFile Convert(GltfImporterSettings settings) - { - LoadGltfScene(settings); - - var rmv2file = new RmvFile(); - rmv2file.Header = new RmvFileHeader() { SkeletonName = "", Version = RmvVersionEnum.RMV2_V7, LodCount = 1 }; - rmv2file.LodHeaders = new RmvLodHeader[1]; - rmv2file.LodHeaders[0] = LodHeaderFactory.Create().CreateEmpty(RmvVersionEnum.RMV2_V7, 100.0f, 0, 0); - rmv2file.LodHeaders[0].MeshCount = (uint)_modelRoot.LogicalMeshes.Count; - - - rmv2file.ModelList = new RmvModel[1][]; - var tempModelList = new List(); - - - foreach (var mesh in _modelRoot.LogicalMeshes) - { - var rmv2Mesh = ConvertToRmv2MeshByVertexColumns(mesh); - var rmvModel = CreateRmvModel(ModelMaterialEnum.default_type, VertexFormat.Cinematic, rmv2Mesh, mesh.Name); - tempModelList.Add(rmvModel); - } - - rmv2file.ModelList[0] = tempModelList.ToArray(); - - rmv2file.RecalculateOffsets(); - - return rmv2file; - } - - private RmvMesh ConvertToRmv2MeshByVertexColumns(SharpGLTF.Schema2.Mesh mesh) - { - var rmv2Mesh = new RmvMesh(); - - var prim = mesh.Primitives.First(); - var vertexBufferColumns = prim.GetVertexColumns(); - - rmv2Mesh.VertexList = new CommonVertex[vertexBufferColumns.Positions.Count()]; - for (var vertexIndex = 0; vertexIndex < vertexBufferColumns.Positions.Count(); vertexIndex++) - { - var vertexBuilder = vertexBufferColumns.GetVertex(vertexIndex); - rmv2Mesh.VertexList[vertexIndex] = ConvertToRmvVertex(vertexBuilder); - } +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Reflection.Metadata; +//using System.Text; +//using System.Threading.Tasks; +//using Shared.GameFormats.RigidModel; +//using SharpGLTF.Geometry.VertexTypes; +//using SharpGLTF.Schema2; +//using XNA = Microsoft.Xna.Framework; +//using Xceed.Wpf.Toolkit.PropertyGrid.Editors; +//using Editors.ImportExport.Exporting.Exporters.RmvToGltf.Helpers; +//using Shared.GameFormats.RigidModel.Vertex; +//using SharpGLTF.Geometry; +//using System.ComponentModel.DataAnnotations; +//using GameWorld.Core.Animation; +//using GameWorld.Core.Rendering.Geometry; +//using GameWorld.Core.Rendering.Materials.Serialization; +//using GameWorld.Core.Rendering.Materials.Shaders; +//using GameWorld.Core.Services; +//using Shared.GameFormats.RigidModel.MaterialHeaders; +//using SharpGLTF.Runtime; +//using Shared.GameFormats.RigidModel.LodHeader; +//using Shared; +//using SharpDX.MediaFoundation; +//using Editors.ImportExport.Common; +//using Pfim; + +//namespace Editors.ImportExport.Importing.Importers.GltfToRmv.Helper +//{ +// public class Rmv2FromGltfFIleConverter +// { +// private ModelRoot? _modelRoot; + +// private void LoadGltfScene(GltfImporterSettings settings) +// { +// _modelRoot = ModelRoot.Load(settings.InputGltfFile); +// } + +// public RmvFile Convert(GltfImporterSettings settings) +// { +// LoadGltfScene(settings); + +// var rmv2file = new RmvFile(); +// rmv2file.Header = new RmvFileHeader() { SkeletonName = "", Version = RmvVersionEnum.RMV2_V7, LodCount = 1 }; +// rmv2file.LodHeaders = new RmvLodHeader[1]; +// rmv2file.LodHeaders[0] = LodHeaderFactory.Create().CreateEmpty(RmvVersionEnum.RMV2_V7, 100.0f, 0, 0); +// rmv2file.LodHeaders[0].MeshCount = (uint)_modelRoot.LogicalMeshes.Count; + + +// rmv2file.ModelList = new RmvModel[1][]; +// var tempModelList = new List(); + + +// foreach (var mesh in _modelRoot.LogicalMeshes) +// { +// var rmv2Mesh = ConvertToRmv2MeshByVertexColumns(mesh); +// var rmvModel = CreateRmvModel(ModelMaterialEnum.default_type, VertexFormat.Cinematic, rmv2Mesh, mesh.Name); +// tempModelList.Add(rmvModel); +// } + +// rmv2file.ModelList[0] = tempModelList.ToArray(); + +// rmv2file.RecalculateOffsets(); + +// return rmv2file; +// } + +// private RmvMesh ConvertToRmv2MeshByVertexColumns(SharpGLTF.Schema2.Mesh mesh) +// { +// var rmv2Mesh = new RmvMesh(); + +// var prim = mesh.Primitives.First(); +// var vertexBufferColumns = prim.GetVertexColumns(); + +// rmv2Mesh.VertexList = new CommonVertex[vertexBufferColumns.Positions.Count()]; +// for (var vertexIndex = 0; vertexIndex < vertexBufferColumns.Positions.Count(); vertexIndex++) +// { +// var vertexBuilder = vertexBufferColumns.GetVertex(vertexIndex); +// rmv2Mesh.VertexList[vertexIndex] = ConvertToRmvVertex(vertexBuilder); +// } - rmv2Mesh.IndexList = prim.GetIndices().Select(i => (ushort)i).ToArray(); - - return rmv2Mesh; - } - - private RmvMesh ConvertToRmv2MeshByTriangles(SharpGLTF.Schema2.Mesh mesh) - { - var rmv2Mesh = new RmvMesh(); - - var prim = mesh.Primitives.First(); - { - var triangles = mesh.EvaluateTriangles(); - - var tempVertexList = new List(); - var tempIndexList = new List(); - foreach (var tri in triangles) - { - tempVertexList.Add(ConvertToRmvVertex(tri.A)); - tempVertexList.Add(ConvertToRmvVertex(tri.B)); - tempVertexList.Add(ConvertToRmvVertex(tri.C)); - - // make an "uindexed" index buffer, 0,1,2,3,4,5,6.... - tempIndexList.Add((ushort)tempIndexList.Count); - tempIndexList.Add((ushort)tempIndexList.Count); - tempIndexList.Add((ushort)tempIndexList.Count); - } - rmv2Mesh.VertexList = tempVertexList.ToArray(); - rmv2Mesh.IndexList = tempIndexList.ToArray(); - } - - return rmv2Mesh; - } - - private static CommonVertex ConvertToRmvVertex(VertexBuilder vertexBuilder) - { - var rmv2Vertex = new CommonVertex(); - - rmv2Vertex.Position = new XNA.Vector4(-vertexBuilder.Geometry.Position.X, vertexBuilder.Geometry.Position.Y, vertexBuilder.Geometry.Position.Z, 1); - rmv2Vertex.Uv = VecConv.GetXna(vertexBuilder.Material.TexCoord); - rmv2Vertex.Normal = new XNA.Vector3(-vertexBuilder.Geometry.Normal.X, vertexBuilder.Geometry.Normal.Y, vertexBuilder.Geometry.Normal.Z); - rmv2Vertex.Tangent = new XNA.Vector3(-vertexBuilder.Geometry.Tangent.X, vertexBuilder.Geometry.Tangent.Y, vertexBuilder.Geometry.Tangent.Z); - rmv2Vertex.BiNormal = XNA.Vector3.Cross(rmv2Vertex.Normal, rmv2Vertex.Tangent) * vertexBuilder.Geometry.Tangent.W; // should produce th correct bitangent - - rmv2Vertex.WeightCount = vertexBuilder.Skinning.MaxBindings; - rmv2Vertex.BoneIndex = new byte[rmv2Vertex.WeightCount]; - rmv2Vertex.BoneWeight = new float[rmv2Vertex.WeightCount]; - - for (var j = 0; j < rmv2Vertex.WeightCount; j++) - { - rmv2Vertex.BoneIndex[j] = (byte)vertexBuilder.Skinning.Joints[j]; - rmv2Vertex.BoneWeight[j] = vertexBuilder.Skinning.Weights[j]; - } - - return rmv2Vertex; - } +// rmv2Mesh.IndexList = prim.GetIndices().Select(i => (ushort)i).ToArray(); + +// return rmv2Mesh; +// } + +// private RmvMesh ConvertToRmv2MeshByTriangles(SharpGLTF.Schema2.Mesh mesh) +// { +// var rmv2Mesh = new RmvMesh(); + +// var prim = mesh.Primitives.First(); +// { +// var triangles = mesh.EvaluateTriangles(); + +// var tempVertexList = new List(); +// var tempIndexList = new List(); +// foreach (var tri in triangles) +// { +// tempVertexList.Add(ConvertToRmvVertex(tri.A)); +// tempVertexList.Add(ConvertToRmvVertex(tri.B)); +// tempVertexList.Add(ConvertToRmvVertex(tri.C)); + +// // make an "uindexed" index buffer, 0,1,2,3,4,5,6.... +// tempIndexList.Add((ushort)tempIndexList.Count); +// tempIndexList.Add((ushort)tempIndexList.Count); +// tempIndexList.Add((ushort)tempIndexList.Count); +// } +// rmv2Mesh.VertexList = tempVertexList.ToArray(); +// rmv2Mesh.IndexList = tempIndexList.ToArray(); +// } + +// return rmv2Mesh; +// } + +// private static CommonVertex ConvertToRmvVertex(VertexBuilder vertexBuilder) +// { +// var rmv2Vertex = new CommonVertex(); + +// rmv2Vertex.Position = new XNA.Vector4(-vertexBuilder.Geometry.Position.X, vertexBuilder.Geometry.Position.Y, vertexBuilder.Geometry.Position.Z, 1); +// rmv2Vertex.Uv = VecConv.GetXna(vertexBuilder.Material.TexCoord); +// rmv2Vertex.Normal = new XNA.Vector3(-vertexBuilder.Geometry.Normal.X, vertexBuilder.Geometry.Normal.Y, vertexBuilder.Geometry.Normal.Z); +// rmv2Vertex.Tangent = new XNA.Vector3(-vertexBuilder.Geometry.Tangent.X, vertexBuilder.Geometry.Tangent.Y, vertexBuilder.Geometry.Tangent.Z); +// rmv2Vertex.BiNormal = XNA.Vector3.Cross(rmv2Vertex.Normal, rmv2Vertex.Tangent) * vertexBuilder.Geometry.Tangent.W; // should produce th correct bitangent + +// rmv2Vertex.WeightCount = vertexBuilder.Skinning.MaxBindings; +// rmv2Vertex.BoneIndex = new byte[rmv2Vertex.WeightCount]; +// rmv2Vertex.BoneWeight = new float[rmv2Vertex.WeightCount]; + +// for (var j = 0; j < rmv2Vertex.WeightCount; j++) +// { +// rmv2Vertex.BoneIndex[j] = (byte)vertexBuilder.Skinning.Joints[j]; +// rmv2Vertex.BoneWeight[j] = vertexBuilder.Skinning.Weights[j]; +// } + +// return rmv2Vertex; +// } - RmvModel CreateRmvModel(ModelMaterialEnum rigidMaterial, VertexFormat vertexFormat, RmvMesh mesh, string modelName = "", GameSkeleton? skeleton = null, bool addBonesAsAttachmentPoints = false) - { - var materialHeader = new WeightedMaterial(); - materialHeader.BinaryVertexFormat = vertexFormat; - var newModel = new RmvModel() - { - CommonHeader = RmvCommonHeader.CreateDefault(), - Material = materialHeader, - Mesh = mesh - }; - - newModel.Material.ModelName = modelName; - - UpdateBoundBox(newModel); - - if (addBonesAsAttachmentPoints && skeleton != null) - { - var boneNames = skeleton.BoneNames.Select(x => x.Replace("bn_", "")).ToArray(); - newModel.Material.EnrichDataBeforeSaving(boneNames); - } - - return newModel; - } - - void UpdateBoundBox(RmvModel newModel) - { - var points = new XNA.Vector3[newModel.Mesh.VertexList.Length]; - - for (var i = 0; i < newModel.Mesh.VertexList.Length; i++) - { - points[i].X = newModel.Mesh.VertexList[i].Position.X; - points[i].Y = newModel.Mesh.VertexList[i].Position.Y; - points[i].Z = newModel.Mesh.VertexList[i].Position.Z; - } - - newModel.UpdateBoundingBox(XNA.BoundingBox.CreateFromPoints(points)); - newModel.UpdateModelTypeFlag(newModel.Material.MaterialId); - } - } -} +// RmvModel CreateRmvModel(ModelMaterialEnum rigidMaterial, VertexFormat vertexFormat, RmvMesh mesh, string modelName = "", GameSkeleton? skeleton = null, bool addBonesAsAttachmentPoints = false) +// { +// var materialHeader = new WeightedMaterial(); +// materialHeader.BinaryVertexFormat = vertexFormat; +// var newModel = new RmvModel() +// { +// CommonHeader = RmvCommonHeader.CreateDefault(), +// Material = materialHeader, +// Mesh = mesh +// }; + +// newModel.Material.ModelName = modelName; + +// UpdateBoundBox(newModel); + +// if (addBonesAsAttachmentPoints && skeleton != null) +// { +// var boneNames = skeleton.BoneNames.Select(x => x.Replace("bn_", "")).ToArray(); +// newModel.Material.EnrichDataBeforeSaving(boneNames); +// } + +// return newModel; +// } + +// void UpdateBoundBox(RmvModel newModel) +// { +// var points = new XNA.Vector3[newModel.Mesh.VertexList.Length]; + +// for (var i = 0; i < newModel.Mesh.VertexList.Length; i++) +// { +// points[i].X = newModel.Mesh.VertexList[i].Position.X; +// points[i].Y = newModel.Mesh.VertexList[i].Position.Y; +// points[i].Z = newModel.Mesh.VertexList[i].Position.Z; +// } + +// newModel.UpdateBoundingBox(XNA.BoundingBox.CreateFromPoints(points)); +// newModel.UpdateModelTypeFlag(newModel.Material.MaterialId); +// } +// } +//} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/RmvMaterialBuilder.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/RmvMaterialBuilder.cs new file mode 100644 index 000000000..645621095 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/RmvMaterialBuilder.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Editors.ImportExport.Importing.Importers.PngToDds; +using Shared.Core.PackFiles; +using Shared.Core.PackFiles.Models; +using Shared.Core.Services; +using Shared.Core.Settings; +using Shared.GameFormats.RigidModel; +using Shared.GameFormats.RigidModel.Types; +using SharpDX.DirectWrite; +using SharpGLTF.Schema2; +using TextureType = Shared.GameFormats.RigidModel.Types.TextureType; +using Editors.ImportExport.Importing.Importers.GltfToRmv.Helper; + +namespace Editors.ImportExport.Importing.Importers.GltfToRmv.Helper +{ + // TODO: MOVE THIS TO A SHARED LOCATION + public class TextureTypeHelper + { + static private readonly Dictionary _stringIdToTextureType = new Dictionary() + { + {"BaseColor", (TextureType.BaseColour, "base_colour")}, + {"Normal", (TextureType.Normal, "normal")}, + {"MetallicRoughness", (TextureType.MaterialMap, "material_map")}, + {"Diffuse", (TextureType.Diffuse, "diffuse")}, + {"Specular", (TextureType.Specular, "specular")}, + {"Glossiness", (TextureType.Gloss, "gloss_map") } + }; + + static public bool GetRmvTextureTypeFromGltfIdString(string textureTypeString, out TextureType outTextureType, out string postFix) + { + if (_stringIdToTextureType.TryGetValue(textureTypeString, out var textureType)) + { + outTextureType = textureType.texutureType; + postFix = textureType.namePostFix; + return true; + } + + outTextureType = TextureType.Diffuse; + postFix = "diffuse"; + return false; + } + } + public class RmvMaterialBuilder + { + private readonly IPackFileService _packFileService; + private readonly IStandardDialogs _exceptionService; + private readonly List _addedFiles = new List(); + + public RmvMaterialBuilder(IPackFileService packFileSerivce, IStandardDialogs exceptionService) + { + _packFileService = packFileSerivce; + _exceptionService = exceptionService; + } + + public void BuildRmvFileMaterials(GltfImporterSettings settings, SharpGLTF.Schema2.ModelRoot modelRoot, RmvFile rmvFile) + { + ValidateInput_BuildRmvFileMaterials(modelRoot, rmvFile); + + for (int i = 0; i < modelRoot.LogicalMeshes.Count; i++) + { + BuildRmvModelMaterial( + settings, + modelRoot.LogicalMeshes[i], + (rmvFile.ModelList.Any() && rmvFile.ModelList[0].Any()) + ? + rmvFile.ModelList[0][i] + : + null + ); + } + + rmvFile.RecalculateOffsets(); + } + + private void BuildRmvModelMaterial(GltfImporterSettings settings, Mesh mesh, RmvModel? rmvModel) + { + if (!ValidateInput_BuildRmvModelMaterial(mesh)) return; + + var primitive = mesh.Primitives.First(); + var gltfMaterial = primitive.Material; + + foreach (var itText in gltfMaterial.Channels) + { + if (itText.Texture == null) continue; + + var texPath = itText.Texture.PrimaryImage.Content.SourcePath; + if (!TextureTypeHelper.GetRmvTextureTypeFromGltfIdString( + itText.Key, + out var textureType, + out var postFixString)) continue; // gltf string id doesn't match any of the rmv texture types + + // get game type (originally from global app settings) + var gameType = settings.GameType; + + var texturePackFolder = GetTexturePackFolder(settings, mesh.Name, postFixString); + + // import texture PNG -> DDS + var ddsPackFile = PngToDdsImporter.Import(texPath, textureType, gameType, Path.GetFileName(texturePackFolder)); + + AddTextureToRmvModel(mesh.Name, settings, postFixString, rmvModel, textureType); + + var newFile = new NewPackFileEntry(Path.GetDirectoryName(texturePackFolder) ?? "", ddsPackFile); + _packFileService.AddFilesToPack(settings.DestinationPackFileContainer, [newFile]); + } + } + + private void AddTextureToRmvModel(String meshName, GltfImporterSettings settings, string textureTypeString, RmvModel rmvModel, TextureType textureType) + { + var textureFullPackPath = GetTexturePackFolder(settings, meshName, textureTypeString); + + // make sure we don't add the same file more the once, + // as several meshes may use the same texture + if (_addedFiles.Contains(textureFullPackPath.ToLower())) + return; + + // set texture in RMVmodel + if (rmvModel != null) + rmvModel.Material.SetTexture(textureType, textureFullPackPath); + + + _addedFiles.Add(textureFullPackPath.ToLower()); + } + + private static string GetTexturePackFolder(GltfImporterSettings settings, string meshName, string postFixString) + { + // set file name + var textureNameBase = meshName.Any() ? meshName : Path.GetFileNameWithoutExtension(settings.InputGltfFile); + var textureFileName = @$"{textureNameBase} {(postFixString.Any() ? @$"_{postFixString}.dds" : ".dds")}"; + + var texturePackFolder = settings.DestinationPackPath + @"\tex"; + var textureFullPackPath = @$"{texturePackFolder}\{textureFileName}"; + + return textureFullPackPath; + } + + private static void ValidateInput_BuildRmvFileMaterials(ModelRoot modelRoot, RmvFile rmvFile) + { + if (modelRoot == null) + throw new ArgumentNullException(nameof(modelRoot), "Invalid Scene: ModelRoot can't be null"); + + if (modelRoot.LogicalNodes == null) + throw new ArgumentNullException(nameof(modelRoot), "Invalid Scene: root.LogicalNodes can't be null"); + + if (!modelRoot.LogicalNodes.Any()) + throw new Exception("Invalid Scene: no (logical) nodes"); + + if (!rmvFile.ModelList.Any()) + throw new Exception("ERROR: unexpected not meshes in rmv2 file struct"); + + if (rmvFile.ModelList[0].Length != modelRoot.LogicalMeshes.Count) + throw new Exception("ERROR: unexpected rmv2 mesh count mismatch"); + } + + private static bool ValidateInput_BuildRmvModelMaterial(Mesh mesh) + { + if (mesh == null) + throw new ArgumentNullException(nameof(mesh), "Invalid Mesh: Mesh can't be null"); + + if (mesh.Primitives == null || !mesh.Primitives.Any()) + throw new Exception($"Invalid Mesh: No Primitives found in mesh. Primitives.Count = {mesh.Primitives?.Count}"); + + var primitive = mesh.Primitives.First(); + + if (primitive == null) + throw new Exception("Invalid Mesh: primitive[0] can't be null "); + + var gltfMaterial = primitive.Material; + + if (gltfMaterial == null) + return false; + + if (gltfMaterial.Channels == null || !gltfMaterial.Channels.Any()) + return false; + + return true; + } + } +} + diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/RmvMeshBuilder.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/RmvMeshBuilder.cs index 1a132b700..a8199325d 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/RmvMeshBuilder.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/GltfToRmv/Helper/RmvMeshBuilder.cs @@ -24,7 +24,7 @@ namespace Editors.ImportExport.Importing.Importers.GltfToRmv.Helper /// public class RmvMeshBuilder { - public static RmvFile Build(GltfImporterSettings settings, ModelRoot modelRoot, AnimationFile? animSkeletonFile, string SkeletonName) + public static RmvFile? Build(GltfImporterSettings settings, ModelRoot modelRoot, AnimationFile? animSkeletonFile, string SkeletonName) { if (modelRoot == null) throw new ArgumentNullException(nameof(modelRoot), "Invalid Scene: ModelRoot can't be null"); @@ -35,6 +35,11 @@ public static RmvFile Build(GltfImporterSettings settings, ModelRoot modelRoot, if (!modelRoot.LogicalNodes.Any()) throw new Exception("Invalid Scene: no (logical) nodes"); + if (modelRoot.LogicalMeshes == null || !modelRoot.LogicalMeshes.Any()) + { + return null; // no meshes to import + } + List boneNames = new List(); var test = boneNames?.Count; @@ -45,7 +50,7 @@ public static RmvFile Build(GltfImporterSettings settings, ModelRoot modelRoot, Header = new RmvFileHeader() { _fileType = Encoding.ASCII.GetBytes("RMV2"), - SkeletonName = SkeletonName, // TODO: Store + get skeleton name from gltf + SkeletonName = SkeletonName, Version = RmvVersionEnum.RMV2_V7, LodCount = lodCount }, @@ -57,17 +62,20 @@ public static RmvFile Build(GltfImporterSettings settings, ModelRoot modelRoot, rmv2File.LodHeaders[0].MeshCount = (uint)modelRoot.LogicalMeshes.Count; var modelList = new List(); - - foreach (var mesh in modelRoot.LogicalMeshes) - { + { + // We use NODE name as mesh name, because users typically name the NODE in Blender/Maya/3dsMax, not the mesh + var meshNodeName = + (mesh.VisualParents != null && mesh.VisualParents.Any()) ? + mesh.VisualParents.First().Name : mesh.Name; + var rmv2Mesh = GenerateRmvMesh(mesh, modelRoot, animSkeletonFile); - var rmvModel = CreateRmvModel(rmv2Mesh, mesh.Name,animSkeletonFile); + var rmvModel = CreateRmvModel(rmv2Mesh, meshNodeName, animSkeletonFile); modelList.Add(rmvModel); } rmv2File.ModelList[0] = modelList.ToArray(); - rmv2File.RecalculateOffsets(); + rmv2File.RecalculateOffsets(); return rmv2File; } @@ -129,26 +137,18 @@ private static CommonVertex ConvertToRmvVertex(VertexBuilder /// Maps the gltf vertex joint index to th CA AnimationFile bone index - /// + /// private static int GetMappedBoneTableIndex(VertexBuilder vertexBuilder, ModelRoot modelRoot, AnimationFile animSkeletonFile, int bindingIndex) { var binding = vertexBuilder.Skinning.GetBinding(bindingIndex); // Get binding @@ -174,17 +174,17 @@ private static int GetMappedBoneTableIndex(VertexBuilder 3) + throw new IndexOutOfRangeException("Index must be between 0 and 3."); + + byte[] intBytes = BitConverter.GetBytes(Value); + if (BitConverter.IsLittleEndian) + Array.Reverse(intBytes); + + return intBytes[index]; + } + set + { + if (index < 0 || index > 3) + throw new IndexOutOfRangeException("Index must be between 0 and 3."); + + byte[] intBytes = BitConverter.GetBytes(Value); + if (BitConverter.IsLittleEndian) + Array.Reverse(intBytes); + + intBytes[index] = value; + + if (BitConverter.IsLittleEndian) + Array.Reverse(intBytes); + + Value = BitConverter.ToInt32(intBytes, 0); + } + } + + public ColorChannels(nint rgbaValue) + { + Value = rgbaValue; + + + + } + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/DDSFormatHelper.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/DDSFormatHelper.cs new file mode 100644 index 000000000..5c0fc0640 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/DDSFormatHelper.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DirectXTexNet; +using Shared.Core.Settings; +using Shared.GameFormats.RigidModel.Types; + +namespace Editors.ImportExport.Importing.Importers.PngToDds.Helpers +{ + public class DDSFormatHelper + { + static private readonly Dictionary<(GameTypeEnum, TextureType), DXGI_FORMAT> _gameTypeAndTextureTypeToFormat = new Dictionary<(GameTypeEnum, TextureType), DXGI_FORMAT> + { + // spec gloss material games + {(GameTypeEnum.Warhammer, TextureType.Diffuse), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Warhammer, TextureType.Specular), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Warhammer, TextureType.Gloss), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Warhammer, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Warhammer, TextureType.Mask), DXGI_FORMAT.BC3_UNORM}, + + {(GameTypeEnum.Warhammer2, TextureType.Diffuse), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Warhammer2, TextureType.Specular), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Warhammer2, TextureType.Gloss), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Warhammer2, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Warhammer2, TextureType.Mask), DXGI_FORMAT.BC3_UNORM}, + + {(GameTypeEnum.Troy, TextureType.Diffuse), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Troy, TextureType.Specular), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Troy, TextureType.Gloss), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Troy, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Troy, TextureType.Mask), DXGI_FORMAT.BC3_UNORM}, + + {(GameTypeEnum.Pharaoh, TextureType.Diffuse), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Pharaoh, TextureType.Specular), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Pharaoh, TextureType.Gloss), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Pharaoh, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Pharaoh, TextureType.Mask), DXGI_FORMAT.BC3_UNORM}, + + // metal-roughness material games + {(GameTypeEnum.Warhammer3, TextureType.BaseColour), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Warhammer3, TextureType.MaterialMap), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Warhammer3, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Warhammer3, TextureType.Mask), DXGI_FORMAT.BC3_UNORM}, + + // Keys for "Empty" WH3 RMV2, that contains "old" spec-gloss paths pointing nowhere + {(GameTypeEnum.Warhammer3, TextureType.Diffuse), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Warhammer3, TextureType.Specular), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.Warhammer3, TextureType.Gloss), DXGI_FORMAT.BC3_UNORM}, + + {(GameTypeEnum.ThreeKingdoms, TextureType.BaseColour), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.ThreeKingdoms, TextureType.MaterialMap), DXGI_FORMAT.BC1_UNORM_SRGB}, + {(GameTypeEnum.ThreeKingdoms, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.ThreeKingdoms, TextureType.Mask), DXGI_FORMAT.BC3_UNORM}, + + {(GameTypeEnum.RomeRemastered, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Rome2, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Attila, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + {(GameTypeEnum.Arena, TextureType.Normal), DXGI_FORMAT.BC3_UNORM}, + + }; + + public static DXGI_FORMAT GetDDSFormat(GameTypeEnum gameType, TextureType textureType) + { + if (_gameTypeAndTextureTypeToFormat.TryGetValue((gameType, textureType), out var format)) + return format; + + // TODO: LOG No format found for gameType and textureType + + return DXGI_FORMAT.BC3_UNORM; + } + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/BlenderToWH3MaterialMapProcessor.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/BlenderToWH3MaterialMapProcessor.cs new file mode 100644 index 000000000..ec465bc34 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/BlenderToWH3MaterialMapProcessor.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using DirectXTexNet; +using Editors.ImportExport.Common.Interfaces; + +namespace Editors.ImportExport.Common.Interfaces +{ + public class BlenderToWH3MaterialMapProcessor : IImageProcessor + { + public ScratchImage Transform(ScratchImage scratchImage) + { + if (!(scratchImage.GetMetadata().Format == DXGI_FORMAT.B8G8R8A8_UNORM || scratchImage.GetMetadata().Format == DXGI_FORMAT.B8G8R8A8_UNORM_SRGB)) + { + throw new Exception($"Error: image format is {scratchImage.GetMetadata().Format} should be uncompressed RGBA8 (BC_B8G8R8A8_UNORM)"); + } + + var copyScratchImage = scratchImage.CreateImageCopy(0, false, CP_FLAGS.NONE); + var srcImage = copyScratchImage.GetImage(0, 0, 0); + byte[] rgbaBytes = new byte[srcImage.SlicePitch]; + Marshal.Copy(srcImage.Pixels, rgbaBytes, 0, (int)srcImage.SlicePitch); + + for (int index = 0; index < srcImage.SlicePitch; index += 4) + { + var r = rgbaBytes[index + 2]; + var g = rgbaBytes[index + 1]; + var b = rgbaBytes[index + 0]; + + rgbaBytes[index + 0] = r; + rgbaBytes[index + 1] = g; + rgbaBytes[index + 2] = b; + rgbaBytes[index + 3] = 255; + + } + + Marshal.Copy(rgbaBytes, 0, srcImage.Pixels, (int)srcImage.SlicePitch); + return copyScratchImage; + } + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/BlueToOrangeNormalMapImageProcessor.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/BlueToOrangeNormalMapImageProcessor.cs new file mode 100644 index 000000000..c71197e76 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/BlueToOrangeNormalMapImageProcessor.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using DirectXTexNet; +using Editors.ImportExport.Common.Interfaces; +using Microsoft.Xna.Framework; + +namespace Editors.ImportExport.Importing.Importers.PngToDds.Helpers.ImageProcessor +{ + public class BlueToOrangeNormalMapProcessor : IImageProcessor + { + public ScratchImage Transform(ScratchImage scratchImage) + { + if (!(scratchImage.GetMetadata().Format == DXGI_FORMAT.B8G8R8A8_UNORM || scratchImage.GetMetadata().Format == DXGI_FORMAT.B8G8R8A8_UNORM_SRGB)) + { + throw new Exception($"Error: image format is {scratchImage.GetMetadata().Format} should be uncompressed RGBA8 (BC_B8G8R8A8_UNORM)"); + } + + var copyScratchImage = scratchImage.CreateImageCopy(0, false, CP_FLAGS.NONE); + var srcImage = copyScratchImage.GetImage(0, 0, 0); + byte[] rgbaBytes = new byte[srcImage.SlicePitch]; + + // copy data from image pixel pointer to byte array + Marshal.Copy(srcImage.Pixels, rgbaBytes, 0, (int)srcImage.SlicePitch); + + for (int index = 0; index < srcImage.SlicePitch; index += 4) + { + var x_red = rgbaBytes[index + 2]; + var y_green = rgbaBytes[index + 1]; + + rgbaBytes[index + 0] = 0; + rgbaBytes[index + 1] = y_green; + rgbaBytes[index + 2] = 255; + rgbaBytes[index + 3] = x_red; + + rgbaBytes[index + 1] = ColorChannels.GammaComponent(rgbaBytes[index + 1], 1 / 2.2f); + } + + // copy processed pixel back to the image pixel pointer½ + Marshal.Copy(rgbaBytes, 0, srcImage.Pixels, (int)srcImage.SlicePitch); + return copyScratchImage; + } + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/DefaultImageProcessor.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/DefaultImageProcessor.cs new file mode 100644 index 000000000..73a0103b0 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/Helpers/ImageProcessor/DefaultImageProcessor.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using DirectXTexNet; +using Editors.ImportExport.Common.Interfaces; + +namespace Editors.ImportExport.Importing.Importers.PngToDds.Helpers.ImageProcessor +{ + public class DefaultImageProcessor : IImageProcessor + { + public ScratchImage Transform(ScratchImage scratchImage) + { + if (!(scratchImage.GetMetadata().Format == DXGI_FORMAT.B8G8R8A8_UNORM || scratchImage.GetMetadata().Format == DXGI_FORMAT.B8G8R8A8_UNORM_SRGB)) + { + throw new Exception($"Error: image format is {scratchImage.GetMetadata().Format} should be uncompressed RGBA8 (BC_B8G8R8A8_UNORM)"); + } + + var outScratchImage = scratchImage.CreateImageCopy(0, false, CP_FLAGS.NONE); + + var srcImage = scratchImage.GetImage(0, 0, 0); + var destImage = outScratchImage.GetImage(0, 0, 0); + + + // copy the pixel pointer's content to a byte array + byte[] rgbaBytes = new byte[srcImage.SlicePitch]; + Marshal.Copy(srcImage.Pixels, rgbaBytes, 0, (int)srcImage.SlicePitch); + + return outScratchImage; + } + } + +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/PngToDdsImporter.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/PngToDdsImporter.cs index 9b8f306c9..a7fa59660 100644 --- a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/PngToDdsImporter.cs +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Importers/PngToDds/PngToDdsImporter.cs @@ -1,12 +1,36 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using DirectXTexNet; +using Editors.ImportExport.Importing.Importers.PngToDds.Helpers; +using Shared.Core.PackFiles.Models; +using Shared.Core.Settings; +using Shared.GameFormats.RigidModel.Types; +using Editors.ImportExport.Common.Interfaces; namespace Editors.ImportExport.Importing.Importers.PngToDds { - internal class PngToDdsImporter + + public class PngToDdsImporter { + static public PackFile Import(string inputPath, TextureType textureType, GameTypeEnum gameType, string outFileName) + { + ScratchImage scratchImagePng = TexHelper.Instance.LoadFromWICFile(inputPath, WIC_FLAGS.DEFAULT_SRGB); + + bool isUncompressed = scratchImagePng.GetMetadata().Format == DXGI_FORMAT.B8G8R8A8_UNORM || scratchImagePng.GetMetadata().Format == DXGI_FORMAT.B8G8R8A8_UNORM_SRGB; + + var processedImage = ImageProcessorFactory.CreateImageProcessor(textureType).Transform(scratchImagePng); + // process image based on texture type + + var imageWithMips = processedImage.GenerateMipMaps(TEX_FILTER_FLAGS.DEFAULT, 0); + var ddsFormat = DDSFormatHelper.GetDDSFormat(gameType, textureType); + var ddsImage = imageWithMips.Compress(ddsFormat, TEX_COMPRESS_FLAGS.DEFAULT, 0.5f); + + var ddsMemStream = ddsImage.SaveToDDSMemory(DDS_FLAGS.NONE); + + byte[] ddsBytes = new byte[ddsMemStream.Length]; + ddsMemStream.Read(ddsBytes, 0, ddsBytes.Length); + + var ddsPackFile = new PackFile(outFileName, new MemorySource(ddsBytes)); + + return ddsPackFile; + } } } diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterView.xaml b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterView.xaml new file mode 100644 index 000000000..6f4ffa2b4 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterView.xaml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Convert the normal map texture from blue type into to orange type. + - Blue type is used by most 3d software, including blender, substance painter. + - Orange type is a specialal "compressed" 2 channel type, used by TW, and some other games. + + + + + + + Import Animations From GLTF File, convert to TW ANIM; + + + + + + + + + diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterView.xaml.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterView.xaml.cs new file mode 100644 index 000000000..8ab584b9e --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterView.xaml.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Editors.ImportExport.Importing.Presentation.RmvToGltf +{ + /// + /// Interaction logic for RmvToGltfExporterView.xaml + /// + public partial class RmvToGltfImporterView : UserControl + { + public RmvToGltfImporterView() + { + InitializeComponent(); + } + + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterViewModel.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterViewModel.cs new file mode 100644 index 000000000..a148332d1 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/GltfToRmv/RmvToGltfImporterViewModel.cs @@ -0,0 +1,46 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using Editors.ImportExport.Exporting.Exporters.RmvToGltf; +using Editors.ImportExport.Exporting.Presentation.RmvToGltf; +using Editors.ImportExport.Importing.Importers; +using Editors.ImportExport.Importing.Importers.GltfToRmv; +using Editors.ImportExport.Importing.Presentation; +using Shared.Core.PackFiles.Models; +using Shared.Core.Settings; +using Shared.Ui.Common.DataTemplates; +using Editors.ImportExport.Importing.Presentation.RmvToGltf; +using Editors.ImportExport.Common; + +namespace Editors.ImportImport.Importing.Presentation.RmvToGltf +{ + public partial class RmvToGltfImporterViewModel : ObservableObject, IImporterViewModel, IViewProvider + { + private readonly GltfImporter _Importer; + + public string DisplayName => "Gltf Importer"; + public string OutputExtension => ".rigid_model_v2"; + public string[] InputExtensions => new string[] { ".gltf", ".glb" }; + + [ObservableProperty] bool _importMeshes = true; + [ObservableProperty] bool _importMaterials = true; + [ObservableProperty] bool _convertFromBlenderMaterialMap = true; + [ObservableProperty] bool _convertNormalTextureToOrange = true; + [ObservableProperty] bool _importAnimations = true; + [ObservableProperty] float _animationKeysPerSecond = 20.0f; + + public RmvToGltfImporterViewModel(GltfImporter Importer) + { + _Importer = Importer; + } + + public ImportExportSupportEnum CanImportFile(PackFile file) => _Importer.CanImportFile(file); + + public void Execute(PackFile ImportSource, string outputPath, PackFileContainer packFileContainer, GameTypeEnum gameType) + { + // TODO: fill in the rest of the parameters from the UI + // TODO: test each param on and off + var settings = new GltfImporterSettings(ImportSource.Name, outputPath, packFileContainer, gameType, true, true, true, true, true, 20.0f, true); + + _Importer.Import(settings); + } + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/IImporterViewModel.cs b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/IImporterViewModel.cs new file mode 100644 index 000000000..b45d449a8 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/IImporterViewModel.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Editors.ImportExport.Common; +using Shared.Core.PackFiles.Models; +using Shared.Core.Settings; + +namespace Editors.ImportExport.Importing.Presentation +{ + public interface IImporterViewModel + { + public string DisplayName { get; } + string OutputExtension { get; } + string[] InputExtensions { get; } // ADDed THIS! + public void Execute(PackFile exportSource, string outputPath, PackFileContainer packFileContainer, GameTypeEnum gameType); + public ImportExportSupportEnum CanImportFile(PackFile file); + + } +} diff --git a/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/ImportWindow.xaml b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/ImportWindow.xaml new file mode 100644 index 000000000..b549ad931 --- /dev/null +++ b/Editors/ImportExportEditor/Editors.ImportExport/Importing/Presentation/ImportWindow.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +