diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfExporter.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfExporter.cs index 26e0543e5..64a73d01a 100644 --- a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfExporter.cs +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfExporter.cs @@ -1,18 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; +using System.Linq; using fin.log; -using fin.model.util; using fin.util.asserts; -using fin.util.image; -using SharpGLTF.Materials; using SharpGLTF.Schema2; -using AlphaMode = SharpGLTF.Materials.AlphaMode; - namespace fin.model.io.exporters.gltf { public interface IGltfModelExporter : IModelExporter { bool UvIndices { get; set; } @@ -61,84 +53,8 @@ public ModelRoot CreateModelRoot(IModel model, float scale) { model.AnimationManager.Animations); // Builds materials. - // TODO: Update this if GLTF is ever extended... var finToTexCoordAndGltfMaterial = - new Dictionary, MaterialBuilder)>(); - { - foreach (var finMaterial in model.MaterialManager.All) { - var gltfMaterial = new MaterialBuilder(finMaterial.Name) - .WithDoubleSide(finMaterial.CullingMode switch { - CullingMode.SHOW_FRONT_ONLY => false, - // Darn, guess we can't support this. - CullingMode.SHOW_BACK_ONLY => true, - CullingMode.SHOW_BOTH => true, - // Darn, guess we can't support this either. - CullingMode.SHOW_NEITHER => false, - _ => throw new ArgumentOutOfRangeException() - }) - .WithSpecularGlossinessShader() - .WithSpecularGlossiness(new Vector3(0), 0); - - switch (finMaterial) { - case IStandardMaterial standardMaterial: { - var diffuseTexture = standardMaterial.DiffuseTexture; - if (diffuseTexture != null) { - gltfMaterial.UseChannel(KnownChannel.Diffuse) - .UseTexture(diffuseTexture); - } - - var normalTexture = standardMaterial.NormalTexture; - if (normalTexture != null) { - gltfMaterial.UseChannel(KnownChannel.Normal) - .UseTexture(normalTexture); - } - - var emissiveTexture = standardMaterial.EmissiveTexture; - if (emissiveTexture != null) { - gltfMaterial.UseChannel(KnownChannel.Emissive) - .UseTexture(emissiveTexture); - } - - /*var specularTexture = standardMaterial.SpecularTexture; - if (specularTexture != null) { - gltfMaterial.WithSpecularGlossiness( - GltfModelExporter.GetGltfImageFromFinTexture_( - specularTexture), new Vector3(.1f), .1f); - }*/ - - var ambientOcclusionTexture = - standardMaterial.AmbientOcclusionTexture; - if (ambientOcclusionTexture != null) { - gltfMaterial - .UseChannel(KnownChannel.Occlusion) - .UseTexture(ambientOcclusionTexture); - } - - break; - } - default: { - var texture = PrimaryTextureFinder.GetFor(finMaterial); - if (texture != null) { - var alphaMode = texture.TransparencyType switch { - ImageTransparencyType.OPAQUE => AlphaMode.OPAQUE, - ImageTransparencyType.MASK => AlphaMode.MASK, - ImageTransparencyType.TRANSPARENT => AlphaMode.BLEND, - _ => throw new ArgumentOutOfRangeException() - }; - gltfMaterial.WithAlpha(alphaMode); - - gltfMaterial - .UseChannel(KnownChannel.Diffuse) - .UseTexture(texture); - } - break; - } - } - - finToTexCoordAndGltfMaterial[finMaterial] = - (new byte[] { 0 }, gltfMaterial); - } - } + new GltfMaterialBuilder().GetMaterialBuilders(model.MaterialManager); // Builds meshes. var meshBuilder = new GltfMeshBuilder { UvIndices = this.UvIndices }; @@ -183,8 +99,8 @@ public void ExportModel(IModelExporterParams modelExporterParams) { var writeSettings = new WriteSettings { ImageWriting = this.Embedded - ? ResourceWriteMode.EmbeddedAsBase64 - : ResourceWriteMode.SatelliteFile, + ? ResourceWriteMode.EmbeddedAsBase64 + : ResourceWriteMode.SatelliteFile, }; var outputPath = outputFile.FullPath; diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMaterialManager.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMaterialManager.cs new file mode 100644 index 000000000..4c3d2c239 --- /dev/null +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMaterialManager.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; + +using CommunityToolkit.HighPerformance.Helpers; + +using fin.image; +using fin.model.util; +using fin.util.image; + +using SharpGLTF.Materials; +using SharpGLTF.Memory; +using SharpGLTF.Schema2; + +using AlphaMode = SharpGLTF.Materials.AlphaMode; + +namespace fin.model.io.exporters.gltf { + public class GltfMaterialBuilder { + private readonly struct Fin2GltfImageConverter : IAction { + private readonly IImage[] finImages_; + private readonly IDictionary gltfImageByFinImage_; + + public Fin2GltfImageConverter(IImage[] finImages, + IDictionary + gltfImageByFinImage) { + this.finImages_ = finImages; + this.gltfImageByFinImage_ = gltfImageByFinImage; + } + + public void Invoke(int i) { + var finImage = this.finImages_[i]; + + using var imageStream = new MemoryStream(); + finImage.ExportToStream(imageStream, LocalImageFormat.PNG); + + this.gltfImageByFinImage_[finImage] = + new MemoryImage(imageStream.ToArray()); + } + } + + public IDictionary GetMaterials( + ModelRoot gltfModelRoot, + IMaterialManager finMaterialManager) + => this.ConvertMaterials_(finMaterialManager) + .ToDictionary(tuple => tuple.Item1, + tuple => gltfModelRoot.CreateMaterial(tuple.Item2)); + + public IDictionary GetMaterialBuilders( + IMaterialManager finMaterialManager) + => this.ConvertMaterials_(finMaterialManager) + .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2); + + private IEnumerable<(IMaterial, MaterialBuilder)> ConvertMaterials_( + IMaterialManager finMaterialManager) { + var finImages = finMaterialManager.Textures + .Select(texture => texture.Image) + .Distinct() + .ToArray(); + var gltfImageByFinImage = new ConcurrentDictionary(); + ParallelHelper.For(0, + finImages.Length, + new Fin2GltfImageConverter( + finImages, + gltfImageByFinImage)); + + // TODO: Update this if GLTF is ever extended... + return finMaterialManager.All.Select(finMaterial => { + var gltfMaterialBuilder + = new MaterialBuilder(finMaterial.Name) + .WithDoubleSide(finMaterial.CullingMode switch { + CullingMode.SHOW_FRONT_ONLY => false, + // Darn, guess we can't support this. + CullingMode.SHOW_BACK_ONLY => true, + CullingMode.SHOW_BOTH => true, + // Darn, guess we can't support this either. + CullingMode.SHOW_NEITHER => false, + _ => throw new ArgumentOutOfRangeException() + }) + .WithSpecularGlossinessShader() + .WithSpecularGlossiness(new Vector3(0), 0); + + switch (finMaterial) { + case IStandardMaterial standardMaterial: { + var diffuseTexture = standardMaterial.DiffuseTexture; + if (diffuseTexture != null) { + gltfMaterialBuilder.UseChannel(KnownChannel.Diffuse) + .UseTexture(diffuseTexture, + gltfImageByFinImage[ + diffuseTexture.Image]); + } + + var normalTexture = standardMaterial.NormalTexture; + if (normalTexture != null) { + gltfMaterialBuilder.UseChannel(KnownChannel.Normal) + .UseTexture(normalTexture, + gltfImageByFinImage + [normalTexture.Image]); + } + + var emissiveTexture = standardMaterial.EmissiveTexture; + if (emissiveTexture != null) { + gltfMaterialBuilder.UseChannel(KnownChannel.Emissive) + .UseTexture(emissiveTexture, + gltfImageByFinImage[ + emissiveTexture.Image]); + } + + /*var specularTexture = standardMaterial.SpecularTexture; + if (specularTexture != null) { + gltfMaterial.WithSpecularGlossiness( + GltfModelExporter.GetGltfImageFromFinTexture_( + specularTexture), new Vector3(.1f), .1f); + }*/ + + var ambientOcclusionTexture = + standardMaterial.AmbientOcclusionTexture; + if (ambientOcclusionTexture != null) { + gltfMaterialBuilder + .UseChannel(KnownChannel.Occlusion) + .UseTexture(ambientOcclusionTexture, + gltfImageByFinImage[ + ambientOcclusionTexture.Image]); + } + + break; + } + default: { + var texture = PrimaryTextureFinder.GetFor(finMaterial); + if (texture != null) { + var alphaMode = texture.TransparencyType switch { + ImageTransparencyType.OPAQUE => AlphaMode.OPAQUE, + ImageTransparencyType.MASK => AlphaMode.MASK, + ImageTransparencyType.TRANSPARENT => AlphaMode.BLEND, + _ => throw new ArgumentOutOfRangeException() + }; + gltfMaterialBuilder.WithAlpha(alphaMode); + + gltfMaterialBuilder + .UseChannel(KnownChannel.Diffuse) + .UseTexture(texture, gltfImageByFinImage[texture.Image]); + } + + break; + } + } + + return (finMaterial, gltfMaterial: gltfMaterialBuilder); + }); + } + } +} \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilder.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilder.cs index 92ed0b600..a716f9d25 100644 --- a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilder.cs +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfMeshBuilder.cs @@ -25,8 +25,7 @@ public IList BuildAndBindMesh( ModelRoot gltfModel, IModel model, float scale, - Dictionary, MaterialBuilder)> - finToTexCoordAndGltfMaterial) { + IDictionary finToTexCoordAndGltfMaterial) { var skin = model.Skin; var vertexAccessor = ConsistentVertexAccessor.GetAccessorForModel(model); @@ -52,7 +51,7 @@ public IList BuildAndBindMesh( foreach (var primitive in finMesh.Primitives) { MaterialBuilder materialBuilder; if (primitive.Material != null) { - (_, materialBuilder) = + materialBuilder = finToTexCoordAndGltfMaterial[primitive.Material]; } else { materialBuilder = nullMaterialBuilder; @@ -161,9 +160,9 @@ public IList BuildAndBindMesh( gltfMeshBuilder.UsePrimitive(materialBuilder, 3); foreach (var (v1, v2, v3) in primitive - .GetOrderedTriangleVertexIndices() - .Select(i => vertices[i]) - .SeparateTriplets()) { + .GetOrderedTriangleVertexIndices() + .Select(i => vertices[i]) + .SeparateTriplets()) { triangles.AddTriangle(v1, v2, v3); } diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfTextureUtil.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfTextureUtil.cs index 3854b463e..367a69310 100644 --- a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfTextureUtil.cs +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/GltfTextureUtil.cs @@ -9,11 +9,11 @@ namespace fin.model.io.exporters.gltf { public static class GltfTextureUtil { public static TextureBuilder UseTexture(this ChannelBuilder channelBuilder, - ITexture finTexture) { + ITexture finTexture, + MemoryImage memoryImage) { var textureBuilder = channelBuilder.UseTexture(); textureBuilder - .WithPrimaryImage( - GltfTextureUtil.GetGltfImageFromFinTexture_(finTexture)) + .WithPrimaryImage(memoryImage) .WithCoordinateSet(0) .WithSampler( GltfTextureUtil.ConvertWrapMode_(finTexture.WrapModeU), @@ -29,14 +29,6 @@ public static TextureBuilder UseTexture(this ChannelBuilder channelBuilder, return textureBuilder; } - private static MemoryImage GetGltfImageFromFinTexture_( - ITexture finTexture) { - using var imageStream = new MemoryStream(); - finTexture.Image.ExportToStream(imageStream, finTexture.BestImageFormat); - var imageBytes = imageStream.ToArray(); - return new MemoryImage(imageBytes); - } - private static TextureWrapMode ConvertWrapMode_(WrapMode wrapMode) => wrapMode switch { WrapMode.CLAMP => TextureWrapMode.CLAMP_TO_EDGE, diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfExporter.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfExporter.cs index bbdfe0a2d..746cfcf65 100644 --- a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfExporter.cs +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfExporter.cs @@ -1,18 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Numerics; - -using fin.log; -using fin.model.util; +using fin.log; using fin.util.asserts; -using fin.util.image; -using SharpGLTF.Materials; using SharpGLTF.Schema2; using SharpGLTF.Validation; -using AlphaMode = SharpGLTF.Materials.AlphaMode; - namespace fin.model.io.exporters.gltf.lowlevel { public class LowLevelGltfModelExporter : IGltfModelExporter { private readonly ILogger logger_ = Logging.Create(); @@ -54,69 +45,14 @@ public ModelRoot CreateModelRoot(IModel model, float scale) { model.AnimationManager.Animations); // Builds materials. - // TODO: Update this if GLTF is ever extended... var finToTexCoordAndGltfMaterial = - new Dictionary, Material)>(); - { - foreach (var finMaterial in model.MaterialManager.All) { - var gltfMaterial = new MaterialBuilder(finMaterial.Name) - .WithDoubleSide(finMaterial.CullingMode switch { - CullingMode.SHOW_FRONT_ONLY => false, - // Darn, guess we can't support this. - CullingMode.SHOW_BACK_ONLY => true, - CullingMode.SHOW_BOTH => true, - // Darn, guess we can't support this either. - CullingMode.SHOW_NEITHER => false, - _ => throw new ArgumentOutOfRangeException() - }) - .WithSpecularGlossinessShader() - .WithSpecularGlossiness(new Vector3(0), 0); - - switch (finMaterial) { - case IStandardMaterial standardMaterial: { - var diffuseTexture = standardMaterial.DiffuseTexture; - if (diffuseTexture != null) { - gltfMaterial - .UseChannel(KnownChannel.Diffuse) - .UseTexture(diffuseTexture); - } - - var ambientOcclusionTexture = - standardMaterial.AmbientOcclusionTexture; - if (ambientOcclusionTexture != null) { - gltfMaterial - .UseChannel(KnownChannel.Occlusion) - .UseTexture(ambientOcclusionTexture); - } - - break; - } - default: { - var texture = PrimaryTextureFinder.GetFor(finMaterial); - if (texture != null) { - var alphaMode = texture.TransparencyType switch { - ImageTransparencyType.OPAQUE => AlphaMode.OPAQUE, - ImageTransparencyType.MASK => AlphaMode.MASK, - ImageTransparencyType.TRANSPARENT => AlphaMode.BLEND, - _ => throw new ArgumentOutOfRangeException() - }; - gltfMaterial.WithAlpha(alphaMode); - - gltfMaterial - .UseChannel(KnownChannel.Diffuse) - .UseTexture(texture); - } - break; - } - } - - finToTexCoordAndGltfMaterial[finMaterial] = - (new byte[] { 0 }, modelRoot.CreateMaterial(gltfMaterial)); - } - } + new GltfMaterialBuilder().GetMaterials( + modelRoot, + model.MaterialManager); // Builds meshes. - var meshBuilder = new LowLevelGltfMeshBuilder { UvIndices = this.UvIndices }; + var meshBuilder = new LowLevelGltfMeshBuilder + { UvIndices = this.UvIndices }; var gltfMeshes = meshBuilder.BuildAndBindMesh( modelRoot, model, @@ -154,8 +90,8 @@ public void ExportModel(IModelExporterParams modelExporterParams) { var writeSettings = new WriteSettings { ImageWriting = this.Embedded - ? ResourceWriteMode.EmbeddedAsBase64 - : ResourceWriteMode.SatelliteFile, + ? ResourceWriteMode.EmbeddedAsBase64 + : ResourceWriteMode.SatelliteFile, MergeBuffers = false, Validation = ValidationMode.Skip, }; diff --git a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfMeshBuilder.cs b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfMeshBuilder.cs index 652b90bc2..9a1675f95 100644 --- a/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfMeshBuilder.cs +++ b/FinModelUtility/Fin/Fin/src/model/io/exporters/gltf/lowlevel/LowLevelGltfMeshBuilder.cs @@ -9,7 +9,6 @@ using fin.color; using fin.math; -using SharpGLTF.Memory; using SharpGLTF.Schema2; using FinPrimitiveType = fin.model.PrimitiveType; @@ -24,8 +23,7 @@ public IList BuildAndBindMesh( ModelRoot gltfModel, IModel model, float scale, - Dictionary, Material)> - finToTexCoordAndGltfMaterial) { + IDictionary finToTexCoordAndGltfMaterial) { var skin = model.Skin; var vertexAccessor = ConsistentVertexAccessor.GetAccessorForModel(model); @@ -157,8 +155,7 @@ public IList BuildAndBindMesh( foreach (var finPrimitive in finMesh.Primitives) { Material material; if (finPrimitive.Material != null) { - (_, material) = - finToTexCoordAndGltfMaterial[finPrimitive.Material]; + material = finToTexCoordAndGltfMaterial[finPrimitive.Material]; } else { material = nullMaterial; } diff --git a/cli/tools/delete_golden_outputs.bat b/cli/tools/delete_golden_outputs.bat index e688af697..608fafb77 100644 --- a/cli/tools/delete_golden_outputs.bat +++ b/cli/tools/delete_golden_outputs.bat @@ -7,10 +7,20 @@ cd ../../FinModelUtility set hierarchyListCmd="dir /b /s /ad *.* | sort" -for /d %%p in (*) do ( +for /d %%p in (*, Formats/*, Games/*) do ( pushd "./" - cd "%%p" + if exist %%p ( + cd "%%p" + ) else ( + if exist "Formats/%%p" ( + cd "Formats/%%p" + ) else ( + if exist "Games/%%p" ( + cd "Games/%%p" + ) + ) + ) if exist "%%p Tests" ( cd "%%p Tests"