mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-10 15:14:55 +00:00
Draw LM2 models. Extreemly glitchy atm
This commit is contained in:
parent
1429a00178
commit
68a3933362
7 changed files with 286 additions and 40 deletions
Binary file not shown.
|
@ -57,24 +57,23 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
public LM2_ChunkTable ChunkTable;
|
||||
public List<FileEntry> fileEntries = new List<FileEntry>();
|
||||
|
||||
//The click event will load the viewport and any models found in the file if there are any
|
||||
public override void OnClick(TreeView treeview)
|
||||
{
|
||||
if (modelFolder.Nodes.Count != 0)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
public LM2_Renderer Renderer;
|
||||
public DrawableContainer DrawableContainer = new DrawableContainer();
|
||||
|
||||
TreeNode textureFolder = new TreeNode("Textures");
|
||||
TreeNode modelFolder = new TreeNode("Models");
|
||||
|
||||
public byte[] GetFile003Data()
|
||||
{
|
||||
return fileEntries[3].GetData(); //Get the fourth file
|
||||
}
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
DrawableContainer.Name = FileName;
|
||||
Renderer = new LM2_Renderer();
|
||||
DrawableContainer.Drawables.Add(Renderer);
|
||||
|
||||
using (var reader = new FileReader(stream))
|
||||
{
|
||||
reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
|
||||
|
@ -132,7 +131,7 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
//Set an instance of our current data
|
||||
//Chunks are in order, so you build off of when an instance gets loaded
|
||||
TexturePOWE currentTexture = new TexturePOWE();
|
||||
LM2_Model currentModel = new LM2_Model();
|
||||
LM2_Model currentModel = new LM2_Model(this);
|
||||
|
||||
//Each part of the file is divided into multiple file/section entries
|
||||
//The first entry being the chunk table parsed before this
|
||||
|
@ -176,13 +175,17 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
currentTexture.ImageData = chunkEntry.FileData;
|
||||
break;
|
||||
case SubDataType.ModelStart:
|
||||
currentModel = new LM2_Model(this);
|
||||
currentModel.ModelInfo = new LM2_ModelInfo();
|
||||
currentModel.Text = $"Model {modelIndex}";
|
||||
currentModel.ModelInfo.Data = chunkEntry.FileData;
|
||||
modelFolder.Nodes.Add(currentModel);
|
||||
|
||||
modelIndex++;
|
||||
break;
|
||||
case SubDataType.MeshBuffers:
|
||||
currentModel.BufferStart = chunkEntry.Entry.ChunkOffset;
|
||||
currentModel.BufferSize = chunkEntry.Entry.ChunkSize;
|
||||
break;
|
||||
case SubDataType.VertexStartPointers:
|
||||
using (var vtxPtrReader = new FileReader(chunkEntry.FileData))
|
||||
{
|
||||
|
@ -204,7 +207,12 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
break;
|
||||
case SubDataType.ModelTransform:
|
||||
using (var transformReader = new FileReader(chunkEntry.FileData))
|
||||
currentModel.Transform = transformReader.ReadMatrix4();
|
||||
{
|
||||
if (transformReader.BaseStream.Length == 0x40)
|
||||
currentModel.Transform = transformReader.ReadMatrix4();
|
||||
else
|
||||
currentModel.Transform = OpenTK.Matrix4.Identity;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -213,15 +221,7 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
|
||||
foreach (LM2_Model model in modelFolder.Nodes)
|
||||
{
|
||||
for (int i = 0; i < model.VertexBufferPointers.Count; i++)
|
||||
{
|
||||
LM2_Mesh mesh = model.Meshes[i];
|
||||
|
||||
RenderableMeshWrapper genericObj = new RenderableMeshWrapper();
|
||||
genericObj.Mesh = mesh;
|
||||
genericObj.Text = $"Mesh {i}";
|
||||
model.Nodes.Add(genericObj);
|
||||
}
|
||||
model.ReadVertexBuffers();
|
||||
}
|
||||
|
||||
if (modelFolder.Nodes.Count > 0)
|
||||
|
|
|
@ -11,6 +11,20 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
Texture = 0x8701B500,
|
||||
}
|
||||
|
||||
public enum VertexDataFormat
|
||||
{
|
||||
Float16,
|
||||
Float32,
|
||||
Float32_32,
|
||||
Float32_32_32,
|
||||
}
|
||||
|
||||
public enum IndexFormat : ushort
|
||||
{
|
||||
Index_16 = 0x0,
|
||||
Index_8 = 0x8000,
|
||||
}
|
||||
|
||||
public enum SubDataType : uint
|
||||
{
|
||||
ModelStart = 0x1201B006,
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||
using System.Windows.Forms;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.IO;
|
||||
using Toolbox.Library.Rendering;
|
||||
using Toolbox.Library.Forms;
|
||||
using OpenTK;
|
||||
|
||||
|
@ -13,25 +14,203 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
{
|
||||
public class LM2_Model : TreeNodeCustom
|
||||
{
|
||||
public LM2_DICT DataDictionary;
|
||||
public LM2_ModelInfo ModelInfo;
|
||||
public List<LM2_Mesh> Meshes = new List<LM2_Mesh>();
|
||||
public List<uint> VertexBufferPointers = new List<uint>();
|
||||
public Matrix4 Transform { get; set; }
|
||||
|
||||
public uint BufferStart;
|
||||
public uint BufferSize;
|
||||
|
||||
Viewport viewport
|
||||
{
|
||||
get
|
||||
{
|
||||
var editor = LibraryGUI.GetObjectEditor();
|
||||
return editor.GetViewport();
|
||||
}
|
||||
set
|
||||
{
|
||||
var editor = LibraryGUI.GetObjectEditor();
|
||||
editor.LoadViewport(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawablesLoaded = false;
|
||||
public override void OnClick(TreeView treeView)
|
||||
{
|
||||
STPropertyGrid editor = (STPropertyGrid)LibraryGUI.GetActiveContent(typeof(STPropertyGrid));
|
||||
if (editor == null)
|
||||
if (Runtime.UseOpenGL)
|
||||
{
|
||||
editor = new STPropertyGrid();
|
||||
LibraryGUI.LoadEditor(editor);
|
||||
if (viewport == null)
|
||||
{
|
||||
viewport = new Viewport(ObjectEditor.GetDrawableContainers());
|
||||
viewport.Dock = DockStyle.Fill;
|
||||
}
|
||||
|
||||
if (!DrawablesLoaded)
|
||||
{
|
||||
ObjectEditor.AddContainer(DataDictionary.DrawableContainer);
|
||||
DrawablesLoaded = true;
|
||||
}
|
||||
|
||||
viewport.ReloadDrawables(DataDictionary.DrawableContainer);
|
||||
LibraryGUI.LoadEditor(viewport);
|
||||
|
||||
viewport.Text = Text;
|
||||
}
|
||||
editor.Text = Text;
|
||||
editor.Dock = DockStyle.Fill;
|
||||
editor.LoadProperty(this, OnPropertyChanged);
|
||||
}
|
||||
|
||||
public LM2_Model(LM2_DICT dict)
|
||||
{
|
||||
DataDictionary = dict;
|
||||
}
|
||||
|
||||
public void OnPropertyChanged() { }
|
||||
|
||||
public void ReadVertexBuffers()
|
||||
{
|
||||
Nodes.Clear();
|
||||
|
||||
using (var reader = new FileReader(DataDictionary.GetFile003Data()))
|
||||
{
|
||||
for (int i = 0; i < VertexBufferPointers.Count; i++)
|
||||
{
|
||||
LM2_Mesh mesh = Meshes[i];
|
||||
|
||||
RenderableMeshWrapper genericObj = new RenderableMeshWrapper();
|
||||
genericObj.Mesh = mesh;
|
||||
genericObj.Text = $"Mesh {i}";
|
||||
Nodes.Add(genericObj);
|
||||
DataDictionary.Renderer.Meshes.Add(genericObj);
|
||||
|
||||
STGenericPolygonGroup polyGroup = new STGenericPolygonGroup();
|
||||
genericObj.PolygonGroups.Add(polyGroup);
|
||||
|
||||
if (!LM2_Mesh.FormatInfos.ContainsKey(mesh.DataFormat))
|
||||
{
|
||||
Console.WriteLine($"Unsupported data format! " + mesh.DataFormat.ToString("x"));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
var formatInfo = LM2_Mesh.FormatInfos[mesh.DataFormat];
|
||||
if (formatInfo.BufferLength > 0)
|
||||
{
|
||||
reader.BaseStream.Position = BufferStart + mesh.IndexStartOffset;
|
||||
switch (mesh.IndexFormat)
|
||||
{
|
||||
case IndexFormat.Index_8:
|
||||
for (int f = 0; f < mesh.IndexCount; f++)
|
||||
polyGroup.faces.Add(reader.ReadByte());
|
||||
break;
|
||||
case IndexFormat.Index_16:
|
||||
for (int f = 0; f < mesh.IndexCount; f++)
|
||||
polyGroup.faces.Add(reader.ReadUInt16());
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Mesh {genericObj.Text} Format {formatInfo.Format} BufferLength {formatInfo.BufferLength}");
|
||||
|
||||
uint bufferOffet = BufferStart + VertexBufferPointers[i];
|
||||
/* for (int v = 0; v < mesh.VertexCount; v++)
|
||||
{
|
||||
reader.SeekBegin(bufferOffet + (v * formatInfo.BufferLength));
|
||||
|
||||
}*/
|
||||
|
||||
switch (formatInfo.Format)
|
||||
{
|
||||
case VertexDataFormat.Float16:
|
||||
for (int v = 0; v < mesh.VertexCount; v++)
|
||||
{
|
||||
reader.SeekBegin(bufferOffet + (v * formatInfo.BufferLength));
|
||||
|
||||
Vertex vert = new Vertex();
|
||||
genericObj.vertices.Add(vert);
|
||||
vert.pos = new Vector3(
|
||||
UShortToFloatDecode(reader.ReadInt16()),
|
||||
UShortToFloatDecode(reader.ReadInt16()),
|
||||
UShortToFloatDecode(reader.ReadInt16()));
|
||||
reader.BaseStream.Position += 0x4;
|
||||
|
||||
vert.pos = Vector3.TransformPosition(vert.pos, Transform);
|
||||
|
||||
vert.uv0 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
|
||||
/* reader.BaseStream.Position += 8;
|
||||
|
||||
// vert.uv1 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
// vert.uv2 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
|
||||
vert.nrm = new Vector3(
|
||||
UShortToFloatDecode(reader.ReadInt16()),
|
||||
UShortToFloatDecode(reader.ReadInt16()),
|
||||
UShortToFloatDecode(reader.ReadInt16()));*/
|
||||
}
|
||||
break;
|
||||
case VertexDataFormat.Float32:
|
||||
for (int v = 0; v < mesh.VertexCount; v++)
|
||||
{
|
||||
reader.SeekBegin(bufferOffet + (v * formatInfo.BufferLength));
|
||||
|
||||
Vertex vert = new Vertex();
|
||||
genericObj.vertices.Add(vert);
|
||||
|
||||
vert.pos = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
vert.pos = Vector3.TransformPosition(vert.pos, Transform);
|
||||
}
|
||||
break;
|
||||
case VertexDataFormat.Float32_32:
|
||||
reader.BaseStream.Position = BufferStart + VertexBufferPointers[i] + 0x08;
|
||||
for (int v = 0; v < mesh.VertexCount; v++)
|
||||
{
|
||||
Vertex vert = new Vertex();
|
||||
genericObj.vertices.Add(vert);
|
||||
|
||||
vert.pos = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
vert.pos = Vector3.TransformPosition(vert.pos, Transform);
|
||||
|
||||
reader.BaseStream.Position += formatInfo.BufferLength - 0x14;
|
||||
}
|
||||
break;
|
||||
case VertexDataFormat.Float32_32_32:
|
||||
for (int v = 0; v < mesh.VertexCount; v++)
|
||||
{
|
||||
reader.SeekBegin(bufferOffet + (v * formatInfo.BufferLength));
|
||||
|
||||
Vertex vert = new Vertex();
|
||||
genericObj.vertices.Add(vert);
|
||||
|
||||
vert.pos = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
vert.pos = Vector3.TransformPosition(vert.pos, Transform);
|
||||
|
||||
reader.BaseStream.Position += 0x4;
|
||||
vert.uv0 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector2 NormalizeUvCoordsToFloat(ushort inU, ushort inV)
|
||||
{
|
||||
//Normalize U coordinate
|
||||
float U = (float)inU / (float)1024;
|
||||
//Normalize V coordinate
|
||||
float V = (float)inV / (float)1024;
|
||||
return new Vector2(U, V);
|
||||
}
|
||||
|
||||
public static float UShortToFloatDecode(short input)
|
||||
{
|
||||
float fraction = (float)BitConverter.GetBytes(input)[0] / (float)256;
|
||||
sbyte integer = (sbyte)BitConverter.GetBytes(input)[1];
|
||||
return integer + fraction;
|
||||
}
|
||||
}
|
||||
|
||||
public class LM2_ModelInfo
|
||||
|
@ -39,7 +218,7 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
public byte[] Data;
|
||||
}
|
||||
|
||||
public class RenderableMeshWrapper : STGenericObject
|
||||
public class RenderableMeshWrapper : GenericRenderedObject
|
||||
{
|
||||
public LM2_Mesh Mesh { get; set; }
|
||||
|
||||
|
@ -82,15 +261,14 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
{
|
||||
public uint IndexStartOffset { get; private set; } //relative to buffer start
|
||||
public ushort IndexCount { get; private set; } //divide by 3 to get face count
|
||||
public ushort IndexFormat { get; private set; } //0x0 - ushort, 0x8000 - byte
|
||||
public IndexFormat IndexFormat { get; private set; } //0x0 - ushort, 0x8000 - byte
|
||||
|
||||
public ushort BufferStride { get; private set; }
|
||||
public ushort Unknown { get; private set; }
|
||||
public ushort Unknown2 { get; private set; }
|
||||
public ulong DataFormat { get; private set; }
|
||||
public uint Unknown2 { get; private set; }
|
||||
public uint Unknown3 { get; private set; }
|
||||
public uint Unknown4 { get; private set; }
|
||||
public uint Unknown5 { get; private set; }
|
||||
public uint Unknown6 { get; private set; }
|
||||
public ushort VertexCount { get; private set; }
|
||||
public ushort Unknown7 { get; private set; }
|
||||
public uint HashID { get; private set; }
|
||||
|
@ -99,14 +277,13 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
{
|
||||
IndexStartOffset = reader.ReadUInt32();
|
||||
IndexCount = reader.ReadUInt16();
|
||||
IndexFormat = reader.ReadUInt16();
|
||||
IndexFormat = reader.ReadEnum<IndexFormat>(true);
|
||||
BufferStride = reader.ReadUInt16();
|
||||
Unknown = reader.ReadUInt16();
|
||||
Unknown2 = reader.ReadUInt16();
|
||||
DataFormat = reader.ReadUInt64();
|
||||
Unknown2 = reader.ReadUInt32();
|
||||
Unknown3 = reader.ReadUInt32();
|
||||
Unknown4 = reader.ReadUInt32();
|
||||
Unknown5 = reader.ReadUInt32();
|
||||
Unknown6 = reader.ReadUInt32();
|
||||
VertexCount = reader.ReadUInt16();
|
||||
Unknown7 = reader.ReadUInt16(); //0x100
|
||||
HashID = reader.ReadUInt32(); //0x100
|
||||
|
@ -114,7 +291,39 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
|
||||
public class FormatInfo
|
||||
{
|
||||
public VertexDataFormat Format { get; set; }
|
||||
public uint BufferLength { get; set; }
|
||||
|
||||
public FormatInfo(VertexDataFormat format, uint length)
|
||||
{
|
||||
Format = format;
|
||||
BufferLength = length;
|
||||
}
|
||||
}
|
||||
|
||||
//Formats are based on https://github.com/TheFearsomeDzeraora/LM2L/blob/master/ModelThingy.cs#L639
|
||||
//These may not be very accurate, i need to look more into these
|
||||
public static Dictionary<ulong, FormatInfo> FormatInfos = new Dictionary<ulong, FormatInfo>()
|
||||
{
|
||||
{ 0x6350379972D28D0D, new FormatInfo(VertexDataFormat.Float16, 0x46)},
|
||||
{ 0xDC0291B311E26127, new FormatInfo(VertexDataFormat.Float16, 0x16)},
|
||||
{ 0x93359708679BEB7C, new FormatInfo(VertexDataFormat.Float16, 0x16)},
|
||||
{ 0x1A833CEEC88C1762, new FormatInfo(VertexDataFormat.Float16, 0x46)},
|
||||
{ 0xD81AC10B8980687F, new FormatInfo(VertexDataFormat.Float16, 0x16)},
|
||||
{ 0x2AA2C56A0FFA5BDE, new FormatInfo(VertexDataFormat.Float16, 0x1A)},
|
||||
{ 0x5D6C62BAB3F4492E, new FormatInfo(VertexDataFormat.Float16, 0x16)},
|
||||
{ 0x3CC7AB6B4821B2DF, new FormatInfo(VertexDataFormat.Float32, 0x14)},
|
||||
{ 0x408E2B1F5576A693, new FormatInfo(VertexDataFormat.Float32_32_32, 0x10)},
|
||||
{ 0x0B663399DF24890D, new FormatInfo(VertexDataFormat.Float32_32_32, 0x18)},
|
||||
{ 0x7EB9853DF4F13EB1, new FormatInfo(VertexDataFormat.Float32_32_32, 0x18)},
|
||||
{ 0x314A20AEFADABB22, new FormatInfo(VertexDataFormat.Float32_32_32, 0x18)},
|
||||
{ 0x0F3F68A287C2B716, new FormatInfo(VertexDataFormat.Float32_32_32, 0x18)},
|
||||
{ 0x27F993771090E6EB, new FormatInfo(VertexDataFormat.Float32_32_32, 0x1C)},
|
||||
{ 0x4E315C83A856FBF7, new FormatInfo(VertexDataFormat.Float32, 0x1C)},
|
||||
{ 0xBD15F722F07FC596, new FormatInfo(VertexDataFormat.Float32_32_32, 0x1C)},
|
||||
{ 0xFBACD243DDCC31B7, new FormatInfo(VertexDataFormat.Float32_32_32, 0x1C)},
|
||||
{ 0x8A4CC565333626D9, new FormatInfo(VertexDataFormat.Float32_32, 0x1C)},
|
||||
{ 0x8B8CE58EAA846002, new FormatInfo(VertexDataFormat.Float32_32_32, 0x14)},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -266,6 +266,7 @@
|
|||
<Compile Include="FileFormats\Rom\GCDisk.cs" />
|
||||
<Compile Include="GL\BMD_Renderer.cs" />
|
||||
<Compile Include="GL\GXToOpenGL.cs" />
|
||||
<Compile Include="GL\LM2_Render.cs" />
|
||||
<Compile Include="GUI\BFFNT\BffntEditor.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
|
|
21
File_Format_Library/GL/LM2_Render.cs
Normal file
21
File_Format_Library/GL/LM2_Render.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox.Library.Rendering;
|
||||
using GL_EditorFramework.GL_Core;
|
||||
using GL_EditorFramework.Interfaces;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace FirstPlugin.LuigisMansion.DarkMoon
|
||||
{
|
||||
public class LM2_Renderer : GenericModelRenderer
|
||||
{
|
||||
public override void OnRender(GLControl control)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -463,6 +463,7 @@ namespace Toolbox.Library
|
|||
return BitmapExtension.GetBitmap(CSharpImageLibrary.DDS.Dxt.DecompressBc7(data, (int)Width, (int)Height), (int)Width, (int)Height);
|
||||
else
|
||||
{
|
||||
|
||||
if (Runtime.UseOpenGL)
|
||||
{
|
||||
Runtime.OpenTKInitialized = true;
|
||||
|
|
Loading…
Reference in a new issue