mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-10 07:04:36 +00:00
A few more fixes and additions.
Fix LM3 meshes with large amounts of faces (ie Luigi's cutscene model). Improvements to hashing. Start on LM3 saving. Start to support texture replacing.
This commit is contained in:
parent
120a86f4f5
commit
30d4a538f1
8 changed files with 223 additions and 30 deletions
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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<IndexFormat>(false);
|
||||
if (IndexFormat != (IndexFormat)0x8000 && IndexFormat != 0)
|
||||
IndexFormat = IndexFormat.Index_16;
|
||||
IndexCount = reader.ReadUInt32();
|
||||
// IndexFormat = reader.ReadEnum<IndexFormat>(false);
|
||||
// if (IndexFormat != (IndexFormat)0x8000 && IndexFormat != 0 && IndexFormat != IndexFormat.Index_16_0x2)
|
||||
IndexFormat = IndexFormat.Index_16;
|
||||
|
||||
VertexCount = reader.ReadUInt32();
|
||||
reader.ReadUInt32(); //unknown
|
||||
|
|
|
@ -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<List<byte[]>>();
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue