diff --git a/File_Format_Library/FileFormats/NLG/LM2/LM2_DICT.cs b/File_Format_Library/FileFormats/NLG/LM2/LM2_DICT.cs index ad540e97..3d5e0f7c 100644 --- a/File_Format_Library/FileFormats/NLG/LM2/LM2_DICT.cs +++ b/File_Format_Library/FileFormats/NLG/LM2/LM2_DICT.cs @@ -134,7 +134,7 @@ namespace FirstPlugin.LuigisMansion.DarkMoon } foreach (var chunk in ChunkTable.ChunkSubEntries) { - list2.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkSize {chunk.ChunkSize} Unknown {chunk.ChunkOffset}"); + list2.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkSize {chunk.ChunkSize} ChunkOffset {chunk.ChunkOffset}"); } } } @@ -154,6 +154,8 @@ namespace FirstPlugin.LuigisMansion.DarkMoon byte[] File002Data = fileEntries[2].GetData(); //Get the third file byte[] File003Data = fileEntries[3].GetData(); //Get the fourth file + LuigisMansion3.LM3_DICT.LoadHashes(); + int chunkId = 0; uint ImageHeaderIndex = 0; uint modelIndex = 0; @@ -212,7 +214,13 @@ namespace FirstPlugin.LuigisMansion.DarkMoon for (int i = 0; i < numBones; i++) { boneReader.SeekBegin(i * 68); + uint hash = boneReader.ReadUInt32(); + STBone bone = new STBone(currentModel.Skeleton); + bone.Text = hash.ToString("X"); + if (LuigisMansion3.LM3_DICT.HashNames.ContainsKey(hash)) + bone.Text = LuigisMansion3.LM3_DICT.HashNames[hash]; + bone.position = new float[3] { 0, 0, 0 }; bone.rotation = new float[4] { 0, 0, 0, 1 }; bone.scale = new float[3] { 0.2f, 0.2f, 0.2f }; @@ -266,6 +274,43 @@ namespace FirstPlugin.LuigisMansion.DarkMoon } } break; + case SubDataType.BoneHashes: + using (var chunkReader = new FileReader(chunkEntry.FileData)) + { + while (chunkReader.Position <= chunkReader.BaseStream.Length - 4) + { + uint hash = chunkReader.ReadUInt32(); + + string strHash = hash.ToString("X"); + if (LuigisMansion3.LM3_DICT.HashNames.ContainsKey(hash)) + strHash = LuigisMansion3.LM3_DICT.HashNames[hash]; + + Console.WriteLine("Hash! T " + strHash); + } + } + break; + case (SubDataType)0x12017105: + using (var chunkReader = new FileReader(chunkEntry.FileData)) + { + while (chunkReader.Position <= chunkReader.BaseStream.Length - 8) + { + uint hash = chunkReader.ReadUInt32(); + uint unk = chunkReader.ReadUInt32(); + + string strHash = hash.ToString("X"); + if (LuigisMansion3.LM3_DICT.HashNames.ContainsKey(hash)) + strHash = LuigisMansion3.LM3_DICT.HashNames[hash]; + + foreach (var bone in currentModel.Skeleton.bones) { + if (bone.Text == strHash) + { + } + } + } + } + currentModel.Skeleton.reset(); + currentModel.Skeleton.update(); + break; case SubDataType.MaterialName: using (var matReader = new FileReader(chunkEntry.FileData)) { diff --git a/File_Format_Library/FileFormats/NLG/LM2/LM2_Enums.cs b/File_Format_Library/FileFormats/NLG/LM2/LM2_Enums.cs index 810ba975..e39bd5fd 100644 --- a/File_Format_Library/FileFormats/NLG/LM2/LM2_Enums.cs +++ b/File_Format_Library/FileFormats/NLG/LM2/LM2_Enums.cs @@ -33,6 +33,7 @@ namespace FirstPlugin.LuigisMansion.DarkMoon ModelTransform = 0x1301B001, //Matrix4x4. 0x40 in size MeshBuffers = 0x1301B005, //vertex and index buffer BoneData = 0x1201B102, + BoneHashes = 0x1201B103, MaterialName = 0x1201B333, MeshIndexTable = 0x1201B007, MessageData = 0x12027020, diff --git a/File_Format_Library/FileFormats/NLG/LM2/LM2_Model.cs b/File_Format_Library/FileFormats/NLG/LM2/LM2_Model.cs index 8701d527..ed66fad5 100644 --- a/File_Format_Library/FileFormats/NLG/LM2/LM2_Model.cs +++ b/File_Format_Library/FileFormats/NLG/LM2/LM2_Model.cs @@ -151,6 +151,15 @@ namespace FirstPlugin.LuigisMansion.DarkMoon { Nodes.Clear(); + TreeNode skeletonNode = new TreeNode("Skeleton"); + for (int t = 0; t < Skeleton?.bones.Count; t++) { + if (Skeleton.bones[t].Parent == null) + skeletonNode.Nodes.Add(Skeleton.bones[t]); + } + + if (skeletonNode.Nodes.Count > 0) + Nodes.Add(skeletonNode); + using (var reader = new FileReader(DataDictionary.GetFile003Data())) { for (int i = 0; i < VertexBufferPointers.Count; i++) diff --git a/File_Format_Library/FileFormats/NLG/LM3/LM3_Model.cs b/File_Format_Library/FileFormats/NLG/LM3/LM3_Model.cs index c8ef3c47..ae388c51 100644 --- a/File_Format_Library/FileFormats/NLG/LM3/LM3_Model.cs +++ b/File_Format_Library/FileFormats/NLG/LM3/LM3_Model.cs @@ -297,10 +297,14 @@ namespace FirstPlugin.LuigisMansion3 for (int f = 0; f < mesh.IndexCount; f++) polyGroup.faces.Add(reader.ReadUInt16()); break; - /* case IndexFormat.Index_32: - for (int f = 0; f < mesh.IndexCount; f++) - polyGroup.faces.Add((int)reader.ReadUInt32()); - break;*/ + case IndexFormat.Index_16_0x2: + for (int f = 0; f < mesh.IndexCount * 4; f++) + polyGroup.faces.Add(reader.ReadUInt16()); + break; + /* case IndexFormat.Index_32: + for (int f = 0; f < mesh.IndexCount; f++) + polyGroup.faces.Add((int)reader.ReadUInt32()); + break;*/ } Console.WriteLine($"Mesh {genericObj.Text} Format {formatInfo.Format} BufferLength {formatInfo.BufferLength}"); @@ -596,7 +600,7 @@ namespace FirstPlugin.LuigisMansion3 public class LM3_Mesh { public uint IndexStartOffset { get; private set; } //relative to buffer start - public ushort IndexCount { get; private set; } //divide by 3 to get face count + public uint IndexCount { get; private set; } //divide by 3 to get face count public IndexFormat IndexFormat { get; private set; } //0x0 - ushort, 0x8000 - byte public ushort BufferPtrOffset { get; private set; } @@ -620,10 +624,10 @@ namespace FirstPlugin.LuigisMansion3 HashID = reader.ReadUInt32(); IndexStartOffset = reader.ReadUInt32(); - IndexCount = reader.ReadUInt16(); - IndexFormat = reader.ReadEnum(false); - if (IndexFormat != (IndexFormat)0x8000 && IndexFormat != 0) - IndexFormat = IndexFormat.Index_16; + IndexCount = reader.ReadUInt32(); + // IndexFormat = reader.ReadEnum(false); + // if (IndexFormat != (IndexFormat)0x8000 && IndexFormat != 0 && IndexFormat != IndexFormat.Index_16_0x2) + IndexFormat = IndexFormat.Index_16; VertexCount = reader.ReadUInt32(); reader.ReadUInt32(); //unknown diff --git a/File_Format_Library/FileFormats/NLG/LM3/TexturePOWE.cs b/File_Format_Library/FileFormats/NLG/LM3/TexturePOWE.cs index 50a6e433..e9fdb0c2 100644 --- a/File_Format_Library/FileFormats/NLG/LM3/TexturePOWE.cs +++ b/File_Format_Library/FileFormats/NLG/LM3/TexturePOWE.cs @@ -12,6 +12,8 @@ namespace FirstPlugin.LuigisMansion3 { public class TexturePOWE : STGenericTexture { + public long DataOffset; + public static readonly uint Identifier = 0xE977D350; public uint Index { get; set; } @@ -82,6 +84,10 @@ namespace FirstPlugin.LuigisMansion3 // throw new Exception($"Invalid texture header magic! Expected {Identifier.ToString("x")}. Got {Identifier.ToString("x")}"); // ID = reader.ReadUInt32(); + CanReplace = true; + CanRename = false; + CanDelete = false; + ID2 = reader.ReadUInt32(); Width = reader.ReadUInt16(); Height = reader.ReadUInt16(); @@ -112,7 +118,11 @@ namespace FirstPlugin.LuigisMansion3 properties.Format = Format; } - public override void OnClick(TreeView treeview) + public override void OnClick(TreeView treeview) { + UpdateEditor(); + } + + private void UpdateEditor() { ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase)); if (editor == null) @@ -127,11 +137,73 @@ namespace FirstPlugin.LuigisMansion3 editor.LoadImage(this); } - public override bool CanEdit { get; set; } = false; + public override void Replace(string FileName) + { + var bntxFile = new BNTX(); + var tex = new TextureData(); + tex.Replace(FileName, MipCount, 0, Format); + + //If it's null, the operation is cancelled + if (tex.Texture == null) + return; + + var surfacesNew = tex.GetSurfaces(); + var surfaces = GetSurfaces(); + + if (surfaces[0].mipmaps[0].Length != surfacesNew[0].mipmaps[0].Length) + throw new Exception($"Image must be the same size! {surfaces[0].mipmaps[0].Length}"); + + if (Width != tex.Texture.Width || Height != tex.Texture.Height) + throw new Exception("Image size must be the same!"); + + ImageData = tex.Texture.TextureData[0][0]; + + Width = tex.Texture.Width; + Height = tex.Texture.Height; + MipCount = tex.Texture.MipCount; + + surfacesNew.Clear(); + surfaces.Clear(); + + UpdateEditor(); + } + + public override bool CanEdit { get; set; } = true; public override void SetImageData(Bitmap bitmap, int ArrayLevel) { - throw new NotImplementedException(); + var tex = new Syroot.NintenTools.NSW.Bntx.Texture(); + tex.Height = (uint)bitmap.Height; + tex.Width = (uint)bitmap.Width; + tex.Format = TextureData.GenericToBntxSurfaceFormat(Format); + tex.Name = Text; + tex.Path = ""; + tex.TextureData = new List>(); + + STChannelType[] channels = SetChannelsByFormat(Format); + tex.sparseBinding = 0; //false + tex.sparseResidency = 0; //false + tex.Flags = 0; + tex.Swizzle = 0; + tex.textureLayout = 0; + tex.Regs = new uint[0]; + tex.AccessFlags = 0x20; + tex.ArrayLength = (uint)ArrayLevel; + tex.MipCount = MipCount; + tex.Depth = Depth; + tex.Dim = Syroot.NintenTools.NSW.Bntx.GFX.Dim.Dim2D; + tex.TileMode = Syroot.NintenTools.NSW.Bntx.GFX.TileMode.Default; + tex.textureLayout2 = 0x010007; + tex.SurfaceDim = Syroot.NintenTools.NSW.Bntx.GFX.SurfaceDim.Dim2D; + tex.SampleCount = 1; + tex.Pitch = 32; + + tex.MipOffsets = new long[tex.MipCount]; + + var mipmaps = TextureImporterSettings.SwizzleSurfaceMipMaps(tex, + GenerateMipsAndCompress(bitmap, MipCount, Format), MipCount); + + ImageData = Utils.CombineByteArray(mipmaps.ToArray()); } public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0) @@ -159,19 +231,25 @@ namespace FirstPlugin.LuigisMansion3 { return new TEX_FORMAT[] { - TEX_FORMAT.B5G6R5_UNORM, - TEX_FORMAT.R8G8_UNORM, - TEX_FORMAT.B5G5R5A1_UNORM, - TEX_FORMAT.B4G4R4A4_UNORM, - TEX_FORMAT.LA8, - TEX_FORMAT.HIL08, - TEX_FORMAT.L8, - TEX_FORMAT.A8_UNORM, - TEX_FORMAT.LA4, - TEX_FORMAT.A4, - TEX_FORMAT.ETC1_UNORM, - TEX_FORMAT.ETC1_A4, - }; + TEX_FORMAT.R8G8B8A8_UNORM, + TEX_FORMAT.R8G8B8A8_UNORM_SRGB, + TEX_FORMAT.BC1_UNORM, + TEX_FORMAT.BC1_UNORM_SRGB, + TEX_FORMAT.BC2_UNORM, + TEX_FORMAT.BC3_UNORM, + TEX_FORMAT.BC4_UNORM, + TEX_FORMAT.BC5_SNORM, + TEX_FORMAT.BC6H_UF16, + TEX_FORMAT.BC7_UNORM, + TEX_FORMAT.ASTC_4x4_UNORM, + TEX_FORMAT.ASTC_5x4_UNORM, + TEX_FORMAT.ASTC_5x5_UNORM, + TEX_FORMAT.ASTC_6x5_UNORM, + TEX_FORMAT.ASTC_6x6_UNORM, + TEX_FORMAT.ASTC_8x5_UNORM, + TEX_FORMAT.ASTC_8x6_UNORM, + TEX_FORMAT.ASTC_8x8_UNORM, + }; } } } diff --git a/File_Format_Library/FileFormats/NLG/NLG_Common.cs b/File_Format_Library/FileFormats/NLG/NLG_Common.cs index 4705e468..0efd4754 100644 --- a/File_Format_Library/FileFormats/NLG/NLG_Common.cs +++ b/File_Format_Library/FileFormats/NLG/NLG_Common.cs @@ -2,12 +2,37 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using System.Threading.Tasks; +using System.Windows.Forms; +using Toolbox.Library.IO; namespace FirstPlugin { public class NLG_Common { + public static void PrintHashIdBin() + { + OpenFileDialog ofd = new OpenFileDialog(); + if (ofd.ShowDialog() == DialogResult.OK) + { + using (var reader = new FileReader(ofd.FileName)) + { + reader.SetByteOrder(true); + uint numHashes = reader.ReadUInt32(); + uint stringTblPos = (numHashes * 8) + 4; + for (int i = 0; i < numHashes; i++) + { + uint hash = reader.ReadUInt32(); + uint offset = reader.ReadUInt32(); + using (reader.TemporarySeek(stringTblPos + offset, System.IO.SeekOrigin.Begin)) + { + string name = reader.ReadZeroTerminatedString(); + Console.WriteLine(name); + } + } + } + } + } + public static uint StringToHash(string name, bool caseSensative = false) { //From (Works as tested comparing hashbin strings/hashes diff --git a/Switch_Toolbox_Library/Generics/Texture/GenericTexture.cs b/Switch_Toolbox_Library/Generics/Texture/GenericTexture.cs index c5993a10..70e45572 100644 --- a/Switch_Toolbox_Library/Generics/Texture/GenericTexture.cs +++ b/Switch_Toolbox_Library/Generics/Texture/GenericTexture.cs @@ -793,13 +793,12 @@ namespace Toolbox.Library { if (IsAtscFormat(Format)) { - return "Supported Formats|*.dds; *.png;*.tga;*.jpg;*.tiff;*.astc|" + - "Microsoft DDS |*.dds|" + + return "Supported Formats|*.astc; *.png;*.tga;*.jpg;*.tiff|" + + "ASTC |*.astc|" + "Portable Network Graphics |*.png|" + "Joint Photographic Experts Group |*.jpg|" + "Bitmap Image |*.bmp|" + "Tagged Image File Format |*.tiff|" + - "ASTC |*.astc|" + "All files(*.*)|*.*"; } else diff --git a/Switch_Toolbox_Library/Rendering/GenericModelRenderer/GenericModelRenderer.cs b/Switch_Toolbox_Library/Rendering/GenericModelRenderer/GenericModelRenderer.cs index 74b64395..3097714f 100644 --- a/Switch_Toolbox_Library/Rendering/GenericModelRenderer/GenericModelRenderer.cs +++ b/Switch_Toolbox_Library/Rendering/GenericModelRenderer/GenericModelRenderer.cs @@ -429,6 +429,10 @@ namespace Toolbox.Library.Rendering { DrawModelSelection(group, shader); } + else if (Runtime.RenderModelWireframe) + { + DrawModelWireframe(group, shader); + } else { if (Runtime.RenderModels) @@ -453,6 +457,10 @@ namespace Toolbox.Library.Rendering { DrawModelSelection(m, shader); } + else if (Runtime.RenderModelWireframe) + { + DrawModelWireframe(m, shader); + } else { if (Runtime.RenderModels) @@ -464,6 +472,30 @@ namespace Toolbox.Library.Rendering } + private static void DrawModelWireframe(STGenericObject p, ShaderProgram shader) + { + // use vertex color for wireframe color + shader.SetInt("colorOverride", 1); + GL.PolygonMode(MaterialFace.Front, PolygonMode.Line); + GL.Enable(EnableCap.LineSmooth); + GL.LineWidth(1.5f); + GL.DrawElements(PrimitiveType.Triangles, p.lodMeshes[p.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, p.Offset); + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); + shader.SetInt("colorOverride", 0); + } + + private static void DrawModelWireframe(STGenericPolygonGroup p, ShaderProgram shader) + { + // use vertex color for wireframe color + shader.SetInt("colorOverride", 1); + GL.PolygonMode(MaterialFace.Front, PolygonMode.Line); + GL.Enable(EnableCap.LineSmooth); + GL.LineWidth(1.5f); + GL.DrawElements(PrimitiveType.Triangles, p.displayFaceSize, DrawElementsType.UnsignedInt, p.Offset); + GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); + shader.SetInt("colorOverride", 0); + } + private static void DrawModelSelection(STGenericObject p, ShaderProgram shader) {