From e5f4f39a182addf80f3183a82401f25675a5b443 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Mon, 11 Nov 2024 17:53:24 +0100 Subject: [PATCH] ModelEditor - Add material render support --- PCK-Studio/Forms/Editor/ModelEditor.cs | 14 +++-- PCK-Studio/Internal/Json/JsonModelMetaData.cs | 3 ++ PCK-Studio/MainForm.cs | 20 ++++++- PCK-Studio/Rendering/CubeMeshCollection.cs | 2 +- PCK-Studio/Rendering/ModelRenderer.cs | 34 ++++++++++++ PCK-Studio/Resources/model/modelMetaData.json | 53 +++++++++++++------ 6 files changed, 105 insertions(+), 21 deletions(-) diff --git a/PCK-Studio/Forms/Editor/ModelEditor.cs b/PCK-Studio/Forms/Editor/ModelEditor.cs index 5a95d5c1..856fc92e 100644 --- a/PCK-Studio/Forms/Editor/ModelEditor.cs +++ b/PCK-Studio/Forms/Editor/ModelEditor.cs @@ -15,6 +15,7 @@ using PckStudio.Interfaces; using PckStudio.Internal.Json; using PckStudio.Internal.App; using PckStudio.Extensions; +using OMI.Formats.Material; namespace PckStudio.Forms.Editor { @@ -22,13 +23,14 @@ namespace PckStudio.Forms.Editor { private readonly ModelContainer _models; private readonly ITryGetSet _textures; + private readonly ITryGet _tryGetEntityMaterial; - public ModelEditor(ModelContainer models, TryGetDelegate tryGetTexture, TrySetDelegate trySetTexture) + public ModelEditor(ModelContainer models, ITryGetSet tryGetSetTextures, ITryGet tryGetEntityMaterial) { InitializeComponent(); _models = models; - _textures = TryGetSet.FromDelegates(tryGetTexture, trySetTexture); - + _textures = tryGetSetTextures; + _tryGetEntityMaterial = tryGetEntityMaterial; modelTreeView.ImageList = new ImageList { ColorDepth = ColorDepth.Depth32Bit, @@ -240,6 +242,12 @@ namespace PckStudio.Forms.Editor modelViewport.Texture = textures[0].Texture; modelViewport.LoadModel(modelNode.Model); + if (GameModelImporter.ModelMetaData.TryGetValue(modelNode.Model.Name, out JsonModelMetaData modelMetaData) && !string.IsNullOrEmpty(modelMetaData.MaterialName) && + _tryGetEntityMaterial.TryGet(modelMetaData.MaterialName, out MaterialContainer.Material entityMaterial) || + _tryGetEntityMaterial.TryGet(modelNode.Model.Name, out entityMaterial)) + { + modelViewport.SetModelMaterial(entityMaterial); + } modelViewport.ResetCamera(); } if (e.Node is ModelPartNode modelPartNode && modelPartNode.Parent is ModelNode parentNode && modelViewport.CurrentModelName == parentNode.Model.Name) diff --git a/PCK-Studio/Internal/Json/JsonModelMetaData.cs b/PCK-Studio/Internal/Json/JsonModelMetaData.cs index 4f2db331..c9aea5bc 100644 --- a/PCK-Studio/Internal/Json/JsonModelMetaData.cs +++ b/PCK-Studio/Internal/Json/JsonModelMetaData.cs @@ -24,6 +24,9 @@ namespace PckStudio.Internal.Json [JsonProperty("textureLocations", Required = Required.Always)] public string[] TextureLocations { get; set; } + [JsonProperty("materialName", NullValueHandling = NullValueHandling.Ignore)] + public string MaterialName { get; set; } = string.Empty; + [JsonProperty("parts", NullValueHandling = NullValueHandling.Ignore)] public ModelMetaDataPart[] RootParts { get; set; } = Array.Empty(); } diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 2fbe6edf..1c55db3c 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -41,6 +41,7 @@ using PckStudio.Internal.Serializer; using PckStudio.Internal.App; using PckStudio.Internal.Skin; using PckStudio.Interfaces; +using System.Collections.ObjectModel; namespace PckStudio { @@ -621,7 +622,24 @@ namespace PckStudio return true; }; - var editor = new ModelEditor(modelContainer, tryGetTexture, trySetTexture); + bool hasMaterialAsset = currentPCK.TryGetAsset("entityMaterials.bin", PckAssetType.MaterialFile, out PckAsset entityMaterialAsset); + IReadOnlyDictionary entityMaterials = + hasMaterialAsset + ? entityMaterialAsset?.GetData(new MaterialFileReader()).ToDictionary(mat => mat.Name) + : new Dictionary(); + + TryGetDelegate tryGetEntityMaterial = (string materialName, out MaterialContainer.Material materialInfo) => + { + if (entityMaterials.TryGetValue(materialName, out MaterialContainer.Material material)) + { + materialInfo = material; + return true; + } + materialInfo = default; + return false; + }; + + var editor = new ModelEditor(modelContainer, TryGetSet.FromDelegates(tryGetTexture, trySetTexture), TryGet.FromDelegate(tryGetEntityMaterial)); if (editor.ShowDialog() == DialogResult.OK) { return; diff --git a/PCK-Studio/Rendering/CubeMeshCollection.cs b/PCK-Studio/Rendering/CubeMeshCollection.cs index d99fc259..a8d1043b 100644 --- a/PCK-Studio/Rendering/CubeMeshCollection.cs +++ b/PCK-Studio/Rendering/CubeMeshCollection.cs @@ -66,7 +66,7 @@ namespace PckStudio.Rendering Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(Rotation.Z)) ); Matrix4 translation = Matrix4.CreateTranslation(Translation + Offset); - return translation * (rotations).Pivoted(Pivot - Offset); + return translation * rotations.Pivoted(Pivot - Offset); } public int Count => cubes.Count; diff --git a/PCK-Studio/Rendering/ModelRenderer.cs b/PCK-Studio/Rendering/ModelRenderer.cs index 1c9f7f29..19d653a5 100644 --- a/PCK-Studio/Rendering/ModelRenderer.cs +++ b/PCK-Studio/Rendering/ModelRenderer.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using OMI.Formats.Material; using OMI.Formats.Model; using OpenTK; using OpenTK.Graphics.OpenGL; @@ -147,6 +148,10 @@ namespace PckStudio.Rendering ShaderProgram shader = GetShader("CubeShader"); shader.Bind(); shader.SetUniform2("TexSize", model.TextureSize); + + // Reset "Material" + GL.Disable(EnableCap.AlphaTest); + GL.BlendFunc(BlendingFactor.One, BlendingFactor.Zero); } _currentModelName = model.Name; } @@ -266,5 +271,34 @@ namespace PckStudio.Rendering { _highlightingInfo = HighlightInfo.Empty; } + + internal void SetModelMaterial(MaterialContainer.Material entityMaterial) + { + if (entityMaterial is null) + return; + switch (entityMaterial.Type) + { + // todo + //case "entity": + // break; + //case "entity_change_color": + // break; + case "entity_alphatest": + GL.Enable(EnableCap.AlphaTest); + break; + case "entity_alphatest_change_color": + GL.Enable(EnableCap.AlphaTest); + goto default; + case "entity_emissive_alpha": + GL.BlendFunc(BlendingFactor.One, BlendingFactor.Zero); + break; + case "entity_emissive_alpha_only": + GL.BlendFuncSeparate(BlendingFactorSrc.One, BlendingFactorDest.One, BlendingFactorSrc.One, BlendingFactorDest.Zero); + break; + default: + Debug.WriteLine($"[{nameof(ModelRenderer)}@{nameof(SetModelMaterial)}]: Unhandled entity material(type: {entityMaterial.Type})"); + break; + } + } } } diff --git a/PCK-Studio/Resources/model/modelMetaData.json b/PCK-Studio/Resources/model/modelMetaData.json index 704a75af..016d383e 100644 --- a/PCK-Studio/Resources/model/modelMetaData.json +++ b/PCK-Studio/Resources/model/modelMetaData.json @@ -3,6 +3,7 @@ "textureLocations": [ "res/mob/bat" ], + "materialName": "bat", "parts": [ { "name": "head", @@ -38,7 +39,8 @@ "blaze": { "textureLocations": [ "res/mob/fire" - ] + ], + "materialName": "blaze_head" }, "boat": { "textureLocations": [ @@ -97,6 +99,7 @@ "textureLocations": [ "res/mob/enderdragon/ender" ], + "materialName": "ender_dragon", "parts": [ { "name": "body" }, // only needs to be inside when neck 1-5 aren't present @@ -186,19 +189,22 @@ "enderman": { "textureLocations": [ "res/mob/enderman" - ] + ], + "materialName": "enderman" // "enderman_invisible" also valid }, "ghast": { "textureLocations": [ "res/mob/ghast", "res/mob/ghast_fire" - ] + ], + "materialName": "ghast" }, "guardian": { "textureLocations": [ "res/mob/guardian", "res/mob/guardian_elder" ], + "materialName": "guardian", "parts": [ { "name": "head", @@ -220,12 +226,14 @@ "irongolem": { "textureLocations": [ "res/mob/villager_golem" - ] + ], + "materialName": "iron_golem" }, "lavaslime": { "textureLocations": [ "res/mob/lava" - ] + ], + "materialName": "magma_cube" }, "llama": { "textureLocations": [ @@ -282,6 +290,7 @@ "textureLocations": [ "res/mob/phantom" ], + "materialName": "phantom", // phantom_invisible is also valid "parts": [ { "name": "body", @@ -312,7 +321,8 @@ "pigzombie": { "textureLocations": [ "res/mob/pigzombie" - ] + ], + "materialName": "zombie_pigman" }, "polarbear": { "textureLocations": [ @@ -333,19 +343,23 @@ }, "sheep": { "textureLocations": [ + "res/mob/sheep", "res/mob/sheep_fur" - ] + ], + "materialName": "sheep" }, "sheep.sheared": { "textureLocations": [ "res/mob/sheep" - ] + ], + "materialName": "sheep" }, "shulker": { "textureLocations": [ "res/mob/shulker/endergolem", "res/mob/shulker/spark" - ] + ], + "materialName": "shulker" }, "silverfish": { "textureLocations": [ @@ -355,17 +369,20 @@ "skeleton": { "textureLocations": [ "res/mob/skeleton" - ] + ], + "materialName": "skeleton" }, "skeleton.stray": { "textureLocations": [ "res/mob/skeleton/stray" - ] + ], + "materialName": "stray" }, "skeleton.wither": { "textureLocations": [ "res/mob/skeleton_wither" - ] + ], + "materialName": "wither_skeleton" }, "slime": { "textureLocations": [ @@ -386,7 +403,8 @@ "textureLocations": [ "res/mob/spider", "res/mob/cavespider" - ] + ], + "materialName": "spider" // "spider_invisible" also valid }, "squid": { "textureLocations": [ @@ -438,14 +456,16 @@ "textureLocations": [ "res/mob/wither/wither", "res/mob/wither/wither_invulnerable" - ] + ], + "materialName": "wither_boss" }, "wolf": { "textureLocations": [ "res/mob/wolf", "res/mob/wolf_angry", "res/mob/wolf_tame" - ] + ], + "materialName": "wolf" }, "zombie": { "textureLocations": [ @@ -529,7 +549,8 @@ "zombie.drowned": { "textureLocations": [ "res/mob/zombie/drowned" - ] + ], + "materialName": "drowned" }, "endermite": { "textureLocations": [