LM3 fixes. and improvements.

Fixed UV issues which would show up broken.
Improved the tree loading. Havok files are loaded, and additional string data.
This commit is contained in:
KillzXGaming 2019-10-31 18:13:42 -04:00
parent 544a30639b
commit f5605f6878
6 changed files with 197 additions and 47 deletions

View file

@ -161,7 +161,7 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
{
var chunkEntry = new ChunkDataEntry(this, chunk);
chunkEntry.DataFile = File003Data;
chunkEntry.Text = $"Chunk {chunk.ChunkType} {chunkId++}";
chunkEntry.Text = $"Chunk {chunk.ChunkType.ToString("X")} {chunk.ChunkType} {chunkId++}";
chunkEntries.Add(chunkEntry);
chunkFolder.Nodes.Add(chunkEntry);

View file

@ -38,6 +38,9 @@ namespace FirstPlugin.LuigisMansion3
{
tableReader.SetByteOrder(false);
if (tableReader.BaseStream.Length <= 4)
return;
//Load the first chunk table
//These point to sections which usually have magic and a hash
//The chunk table afterwards contains the data itself

View file

@ -63,7 +63,7 @@ namespace FirstPlugin.LuigisMansion3
}
}
public static bool DebugMode = true;
public static bool DebugMode = false;
public List<ChunkDataEntry> chunkEntries = new List<ChunkDataEntry>();
@ -82,6 +82,7 @@ namespace FirstPlugin.LuigisMansion3
public static Dictionary<uint, string> HashNames = new Dictionary<uint, string>();
public List<string> StringList = new List<string>();
private void LoadHashes()
{
foreach (string hashStr in Properties.Resources.LM3_Hashes.Split('\n'))
@ -110,9 +111,15 @@ namespace FirstPlugin.LuigisMansion3
return fileEntries[60].GetData(); //Get the fourth file
}
private ushort Unknown0x4;
public List<ChunkInfo> ChunkInfos = new List<ChunkInfo>();
public bool DrawablesLoaded = false;
public void Load(System.IO.Stream stream)
{
CanSave = false;
LoadHashes();
modelFolder = new LM3_ModelFolder(this);
DrawableContainer.Name = FileName;
@ -125,37 +132,36 @@ namespace FirstPlugin.LuigisMansion3
{
reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
uint Identifier = reader.ReadUInt32();
ushort Unknown = reader.ReadUInt16(); //Could also be 2 bytes, not sure. Always 0x0401
Unknown0x4 = reader.ReadUInt16(); //Could also be 2 bytes, not sure. Always 0x0401
IsCompressed = reader.ReadByte() == 1;
reader.ReadByte(); //Padding
uint unk = reader.ReadUInt32();
uint unk2 = reader.ReadUInt32();
uint SizeLargestFile = reader.ReadUInt32();
byte numFiles = reader.ReadByte();
byte numChunkInfos = reader.ReadByte();
byte numStrings = reader.ReadByte();
reader.ReadByte(); //padding
//Start of the chunk info. A fixed list of chunk information
TreeNode chunkNodes = new TreeNode("Chunks Debug");
for (int i = 0; i < 52; i++)
for (int i = 0; i < numChunkInfos; i++)
{
ChunkInfo chunk = new ChunkInfo();
chunk.Read(reader);
chunkNodes.Nodes.Add(chunk);
ChunkInfos.Add(chunk);
}
TreeNode tableNodes = new TreeNode("File Section Entries");
if (DebugMode)
Nodes.Add(chunkNodes);
TreeNode chunkLookupNodes = new TreeNode("Chunk Lookup Files");
tableNodes.Nodes.Add(chunkLookupNodes);
Nodes.Add(tableNodes);
var FileCount = 120;
TreeNode stringFolder = new TreeNode("Strings");
TreeNode chunkTexFolder = new TreeNode("Texture");
TreeNode chunkModelFolder = new TreeNode("Model");
long FileTablePos = reader.Position;
for (int i = 0; i < FileCount; i++)
for (int i = 0; i < numFiles; i++)
{
var file = new FileEntry(this);
file.Read(reader);
@ -164,7 +170,11 @@ namespace FirstPlugin.LuigisMansion3
if (file.DecompressedSize > 0)
{
file.Text = $"entry {i}";
tableNodes.Nodes.Add(file);
if (i < 52)
chunkLookupNodes.Nodes.Add(file);
else
tableNodes.Nodes.Add(file);
}
//The first file stores a chunk layout
@ -200,6 +210,13 @@ namespace FirstPlugin.LuigisMansion3
}
}
for (int i = 0; i < numStrings; i++)
{
StringList.Add(reader.ReadZeroTerminatedString());
stringFolder.Nodes.Add(StringList[i]);
}
TreeNode havokFolder = new TreeNode("Havok Physics");
//Model data block
//Contains texture hash refs and model headers
@ -229,11 +246,20 @@ namespace FirstPlugin.LuigisMansion3
int chunkId = 0;
uint modelIndex = 0;
uint ImageHeaderIndex = 0;
uint havokFileIndex = 0;
foreach (var chunk in ChunkTable.ChunkSubEntries)
{
Console.WriteLine($"chunk.ChunkType {chunk.ChunkType}");
var chunkEntry = new ChunkDataEntry(this, chunk);
chunkEntry.Text = $"{chunkId} {chunk.ChunkType.ToString("X")} {chunk.ChunkType} {chunk.ChunkOffset} {chunk.ChunkSize}";
switch (chunk.ChunkType)
{
case SubDataType.HavokPhysics:
chunkEntry.DataFile = File052Data;
chunkEntry.Text = $"File_{havokFileIndex++}.hkx";
havokFolder.Nodes.Add(chunkEntry);
break;
case SubDataType.TextureHeader:
chunkEntry.DataFile = File063Data;
@ -331,17 +357,63 @@ namespace FirstPlugin.LuigisMansion3
case SubDataType.UILayout:
chunkEntry.DataFile = File053Data;
break;
case SubDataType.BoneData:
if (chunk.ChunkSize > 0x40 && currentModel.Skeleton == null)
{
/* chunkEntry.DataFile = File052Data;
using (var boneReader = new FileReader(chunkEntry.FileData))
{
currentModel.Skeleton = new STSkeleton();
DrawableContainer.Drawables.Add(currentModel.Skeleton);
uint numBones = chunk.ChunkSize / 0x40;
for (int i = 0; i < numBones; i++)
{
boneReader.SeekBegin(i * 0x40);
STBone bone = new STBone(currentModel.Skeleton);
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 };
boneReader.SeekBegin(48 + (i * 0x40));
var Position = new OpenTK.Vector3(boneReader.ReadSingle(), boneReader.ReadSingle(), boneReader.ReadSingle());
Position = OpenTK.Vector3.TransformPosition(Position, OpenTK.Matrix4.CreateRotationX(OpenTK.MathHelper.DegreesToRadians(90)));
bone.position[0] = Position.X;
bone.position[2] = Position.Y;
bone.position[1] = Position.Z;
bone.RotationType = STBone.BoneRotationType.Euler;
currentModel.Skeleton.bones.Add(bone);
}
currentModel.Skeleton.reset();
currentModel.Skeleton.update();
}*/
}
break;
case (SubDataType)0x5012:
case (SubDataType)0x5013:
case (SubDataType)0x5014:
chunkEntry.DataFile = File063Data;
break;
case (SubDataType)0x7101:
case (SubDataType)0x7102:
case (SubDataType)0x7103:
case (SubDataType)0x7104:
case (SubDataType)0x7105:
case (SubDataType)0x7106:
case (SubDataType)0x6503:
case (SubDataType)0x6501:
chunkEntry.DataFile = File053Data;
break;
default:
chunkEntry.DataFile = File052Data;
break;
}
chunkEntry.Text = $"{chunkId} {chunk.ChunkType.ToString("X")} {chunk.ChunkType} {chunk.ChunkOffset} {chunk.ChunkSize}";
chunkFolder.Nodes.Add(chunkEntry);
// if (currentModel != null && currentModel.Meshes?.Count > 0)
// break;
if (chunk.ChunkType != SubDataType.HavokPhysics)
chunkFolder.Nodes.Add(chunkEntry);
chunkId++;
}
@ -352,11 +424,17 @@ namespace FirstPlugin.LuigisMansion3
currentModel.ModelInfo.Data), currentModel.Meshes, TextureHashes);
}
if (havokFolder.Nodes.Count > 0)
Nodes.Add(havokFolder);
if (textureFolder.Nodes.Count > 0)
Nodes.Add(textureFolder);
if (modelFolder.Nodes.Count > 0)
Nodes.Add(modelFolder);
if (stringFolder.Nodes.Count > 0)
Nodes.Add(stringFolder);
}
}
@ -367,7 +445,43 @@ namespace FirstPlugin.LuigisMansion3
public void Save(System.IO.Stream stream)
{
using (var writer = new FileWriter(stream))
{
writer.SetByteOrder(true);
writer.Write(0x78340300);
writer.SetByteOrder(false);
writer.Write(Unknown0x4);
writer.Write(IsCompressed);
writer.Write((byte)0); //padding
writer.Write(GetLargestFileSize());
writer.Write((byte)fileEntries.Count);
writer.Write((byte)ChunkInfos.Count);
writer.Write((byte)StringList.Count);
writer.Write((byte)0); //padding
for (int i = 0; i < ChunkInfos.Count; i++)
{
writer.Write(ChunkInfos[i].Unknown1);
writer.Write(ChunkInfos[i].Unknown2);
writer.Write(ChunkInfos[i].Unknown3);
writer.Write(ChunkInfos[i].Unknown4);
writer.Write(ChunkInfos[i].Unknown5);
writer.Write(ChunkInfos[i].Unknown6);
}
for (int i = 0; i < fileEntries.Count; i++)
{
}
for (int i = 0; i < StringList.Count; i++)
writer.WriteString(StringList[i]);
}
}
private uint GetLargestFileSize()
{
return 0;
}
public bool AddFile(ArchiveFileInfo archiveFileInfo)
@ -380,22 +494,23 @@ namespace FirstPlugin.LuigisMansion3
return false;
}
public class ChunkInfo : TreeNodeCustom
public class ChunkInfo
{
public string Type;
public uint Unknown1;
public uint Unknown2;
public uint Unknown3;
public uint Unknown4;
public uint Unknown5;
public uint Unknown6;
public void Read(FileReader reader)
{
uint Unknown1 = reader.ReadUInt32();
ushort Unknown2 = reader.ReadUInt16();
ushort Unknown3 = reader.ReadUInt16();
uint Unknown2 = reader.ReadUInt32();
uint Unknown3 = reader.ReadUInt32();
uint Unknown4 = reader.ReadUInt32();
Type = reader.ReadString(3);
byte Unknown5 = reader.ReadByte();
uint Unknown5 = reader.ReadUInt32();
uint Unknown6 = reader.ReadUInt32();
uint Unknown7 = reader.ReadUInt32();
Text = $" Type: [{Type}] [{Unknown1} {Unknown2} {Unknown3} {Unknown4} {Unknown5} {Unknown6}] ";
}
}
@ -481,6 +596,11 @@ namespace FirstPlugin.LuigisMansion3
Unknown3 = reader.ReadByte();
}
public void Write()
{
}
private bool IsTextureBinary()
{
var stream = GetData();

View file

@ -66,5 +66,10 @@ namespace FirstPlugin.LuigisMansion3
UILayoutHeader = 0x7001,
UILayoutData = 0x7002, //Without header
UILayout = 0x7003, //All parts combined
HavokPhysics = 0xC900,
BoneData = 0xB102,
BoneHashList = 0xB103,
}
}

View file

@ -68,6 +68,8 @@ namespace FirstPlugin.LuigisMansion3
public List<LM3_Mesh> Meshes = new List<LM3_Mesh>();
public List<PointerInfo> VertexBufferPointers = new List<PointerInfo>();
public STSkeleton Skeleton;
public uint BufferStart;
public uint BufferSize;
@ -103,6 +105,15 @@ namespace FirstPlugin.LuigisMansion3
viewport.SuppressUpdating = true;
for (int i = 0; i < DataDictionary.DrawableContainer.Drawables.Count; i++)
{
if (DataDictionary.DrawableContainer.Drawables[i] is STSkeleton)
((STSkeleton)DataDictionary.DrawableContainer.Drawables[i]).HideSkeleton = true;
}
if (Skeleton != null)
Skeleton.HideSkeleton = false;
foreach (var mesh in DataDictionary.Renderer.Meshes)
mesh.Checked = false;
@ -339,14 +350,13 @@ namespace FirstPlugin.LuigisMansion3
vert.pos = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
vert.pos = Vector3.TransformPosition(vert.pos, mesh.Transform);
reader.ReadSingle();
vert.nrm = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()).Normalized();
vert.uv0 = new Vector2(reader.ReadSingle(), reader.ReadSingle());
vert.uv1 = new Vector2(reader.ReadSingle(), reader.ReadSingle());
var val = reader.ReadSingle();
// if (formatInfo.BufferLength >= 0x1C)
// vert.col = Read_8_8_8_8_Unorm(reader);
//Texture coordinates are stored between normals, WHY NLG
var texCoordU = reader.ReadSingle();
vert.nrm = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
var texCoordV = reader.ReadSingle();
vert.tan = new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
vert.uv0 = new Vector2(texCoordU, texCoordV);
}
break;
}
@ -375,6 +385,11 @@ namespace FirstPlugin.LuigisMansion3
return new Vector3(reader.ReadByte() / 255f, reader.ReadByte() / 255f, reader.ReadByte() / 255f );
}
public static Vector2 NormalizeUvCoordsToFloat(uint U, uint V)
{
return new Vector2(U / 1024f, V / 1024f);
}
public static Vector2 NormalizeUvCoordsToFloat(ushort U, ushort V)
{
return new Vector2( U / 1024f, V / 1024f);
@ -400,8 +415,17 @@ namespace FirstPlugin.LuigisMansion3
while (!reader.EndOfStream && reader.Position < reader.BaseStream.Length - 4)
{
uint HashIDCheck = reader.ReadUInt32();
if (Hashes.Contains(HashIDCheck) && !ModelTexHashes.Contains(HashIDCheck))
ModelTexHashes.Add(HashIDCheck);
if (Hashes.Contains(HashIDCheck))
{
using (reader.TemporarySeek(8, System.IO.SeekOrigin.Current))
{
uint unk = reader.ReadUInt32();
if (unk == 0xF880BD9F)
{
ModelTexHashes.Add(HashIDCheck);
}
}
}
}
for (int i = 0; i < Meshes.Count; i++)
@ -546,8 +570,6 @@ namespace FirstPlugin.LuigisMansion3
IndexStartOffset = reader.ReadUInt32();
IndexCount = reader.ReadUInt16();
IndexFormat = reader.ReadEnum<IndexFormat>(false);
if (IndexFormat != IndexFormat.Index_16)
IndexFormat = IndexFormat.Index_8;
VertexCount = reader.ReadUInt32();
reader.ReadUInt32(); //unknown
BufferPtrOffset = reader.ReadUInt16(); //I believe this might be for the buffer pointers. It shifts by 4 for each mesh
@ -584,7 +606,6 @@ namespace FirstPlugin.LuigisMansion3
{ 0xa2fdc74f42ce4fdb, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
{ 0xcb092e9f8322ba, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
{ 0x2031dd4da78347d9, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
{ 0x210ed90e5465129a, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
{ 0xa86b2280a1500a0c, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
{ 0xc5f54a808b32320c, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
@ -592,12 +613,11 @@ namespace FirstPlugin.LuigisMansion3
{ 0xc344835dd398dde9, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
{ 0x8d45618da4768c19, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
{ 0xd5b9166924e124f5, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
{ 0x5f5227f782c08883, new FormatInfo(VertexDataFormat.Float32_32_32, 0x0C)},
//Dark moon list just for the sake of having them defined
{ 0x6350379972D28D0D, new FormatInfo(VertexDataFormat.Float16, 0x46)},
{ 0xDC0291B311E26127, new FormatInfo(VertexDataFormat.Float16, 0x16)},
{ 0x93359708679BEB7C, new FormatInfo(VertexDataFormat.Float16, 0x16)},

View file

@ -183,11 +183,13 @@ namespace Toolbox.Library
return;
}
public bool HideSkeleton;
public override void Draw(GL_ControlModern control, Pass pass, EditorSceneBase editorScene)
{
CheckBuffers();
if (!Runtime.OpenTKInitialized || !Runtime.renderBones || !Visible)
if (!Runtime.OpenTKInitialized || !Runtime.renderBones || !Visible || HideSkeleton)
return;
SF.Shader shader = OpenTKSharedResources.shaders["BONE"];