More LM2 archive improvements
This commit is contained in:
parent
571dad0776
commit
131af671bf
Binary file not shown.
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox.Library.IO;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
//Table consists of 2 chunk entry lists that define how the .data reads sections
|
||||
public class LM2_ChunkTable
|
||||
{
|
||||
private const int ChunkInfoIdenfier = 0x2001301;
|
||||
|
||||
//I am uncertain how these chunk lists work. There is first a list with an identifier and one extra unknown
|
||||
//The second list can contain the same entries as the other list, however it may include more chunks
|
||||
//Example, the first list may have image headers, while the second include both image headers and image blocks
|
||||
public List<ChunkEntry> ChunkEntries = new List<ChunkEntry>();
|
||||
public List<ChunkSubEntry> ChunkSubEntries = new List<ChunkSubEntry>();
|
||||
|
||||
public class ChunkEntry
|
||||
{
|
||||
public uint Unknown1;
|
||||
public uint ChunkOffset;
|
||||
public uint ChunkType;
|
||||
public uint Unknown2;
|
||||
public uint Unknown3;
|
||||
}
|
||||
|
||||
public class ChunkSubEntry
|
||||
{
|
||||
public uint ChunkOffset;
|
||||
public uint ChunkType;
|
||||
public uint Unknown;
|
||||
}
|
||||
|
||||
public void Read(FileReader tableReader)
|
||||
{
|
||||
//Each data type has chunk info. There is no counter so keep checking idenfier
|
||||
while (tableReader.ReadUInt32() == ChunkInfoIdenfier)
|
||||
{
|
||||
ChunkEntry entry = new ChunkEntry();
|
||||
ChunkEntries.Add(entry);
|
||||
|
||||
entry.Unknown1 = tableReader.ReadUInt32(); //8
|
||||
entry.ChunkOffset = tableReader.ReadUInt32(); //The chunk offset in the file. Relative to the first chunk position in the file
|
||||
entry.ChunkType = tableReader.ReadUInt32(); //The type of chunk. 0x8701B5 for example for texture info
|
||||
entry.Unknown2 = tableReader.ReadUInt32();
|
||||
|
||||
//This increases by 2 each chunk info, however the starting value is not 0
|
||||
//Note the last entry does not have this
|
||||
entry.Unknown3 = tableReader.ReadUInt32();
|
||||
}
|
||||
|
||||
if (ChunkEntries.Count > 0)
|
||||
ChunkEntries.LastOrDefault<ChunkEntry>().Unknown3 = 0;
|
||||
|
||||
tableReader.Seek(-4); //Seek 4 back as the last entry lacks unkown 4
|
||||
//Check the chunk types
|
||||
//This time it includes more chunks (like image blocks)
|
||||
|
||||
//Read to the end of the file as the rest of the table are types, offsets, and an unknown value
|
||||
while (!tableReader.EndOfStream && tableReader.Position <= tableReader.BaseStream.Length - 12)
|
||||
{
|
||||
ChunkSubEntry subEntry = new ChunkSubEntry();
|
||||
subEntry.ChunkType = tableReader.ReadUInt32(); //The type of chunk. 0x8701B5 for example for texture info
|
||||
subEntry.Unknown = tableReader.ReadUInt32(); //This seems to be the same value as the other Unknown2 in the last section
|
||||
subEntry.ChunkOffset = tableReader.ReadUInt32(); //The chunk offset in the file. Relative to the first chunk position in the file
|
||||
ChunkSubEntries.Add(subEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ using System.Drawing;
|
||||
namespace FirstPlugin
|
||||
{
|
||||
//Parse info based on https://github.com/TheFearsomeDzeraora/LM2L
|
||||
public class LM2_DICT : TreeNodeFile, IFileFormat
|
||||
public class LM2_DICT : TreeNodeFile, IFileFormat, IArchiveFile
|
||||
{
|
||||
public FileType FileType { get; set; } = FileType.Archive;
|
||||
|
||||
@ -48,9 +48,14 @@ namespace FirstPlugin
|
||||
}
|
||||
|
||||
public List<FileEntry> files = new List<FileEntry>();
|
||||
public IEnumerable<ArchiveFileInfo> Files => files;
|
||||
|
||||
public void ClearFiles() { files.Clear(); }
|
||||
|
||||
public bool IsCompressed = false;
|
||||
|
||||
public LM2_ChunkTable ChunkTable;
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
using (var reader = new FileReader(stream))
|
||||
@ -65,15 +70,46 @@ namespace FirstPlugin
|
||||
|
||||
reader.SeekBegin(0x2C);
|
||||
byte[] Unknowns = reader.ReadBytes((int)FileCount);
|
||||
|
||||
long FileTablePos = reader.Position;
|
||||
for (int i = 0; i < FileCount; i++)
|
||||
{
|
||||
var file = new FileEntry(this);
|
||||
file.Read(reader);
|
||||
if (file.FileType != 0)
|
||||
|
||||
//Skip the file table entries as those are not needed to be loaded
|
||||
if (file.FileType != 0 && i > 1)
|
||||
{
|
||||
file.Text = $"File {i} (Unknowns {file.FileType} {file.Unknown2} {file.Unknown3})";
|
||||
file.FileName = $"File {i} (FileType: ({file.FileType}) Unknowns: {file.Unknown2} {file.Unknown3})";
|
||||
files.Add(file);
|
||||
}
|
||||
//The first file stores a chunk layout
|
||||
//The second one seems to be a duplicate?
|
||||
if (i == 0)
|
||||
{
|
||||
using (var tableReader = new FileReader(file.FileData))
|
||||
{
|
||||
ChunkTable = new LM2_ChunkTable();
|
||||
ChunkTable.Read(tableReader);
|
||||
|
||||
TreeNode debugFolder = new TreeNode("DEBUG TABLE INFO");
|
||||
Nodes.Add(debugFolder);
|
||||
|
||||
TreeNode list1 = new TreeNode("Entry List 1");
|
||||
TreeNode list2 = new TreeNode("Entry List 2 ");
|
||||
debugFolder.Nodes.Add(list1);
|
||||
debugFolder.Nodes.Add(list2);
|
||||
|
||||
foreach (var chunk in ChunkTable.ChunkEntries)
|
||||
{
|
||||
list1.Nodes.Add($"ChunkOffset {chunk.ChunkOffset} ChunkType {chunk.ChunkType.ToString("X")} Unknown1 {chunk.Unknown1} Unknown2 {chunk.Unknown2} Unknown3 {chunk.Unknown3}");
|
||||
}
|
||||
foreach (var chunk in ChunkTable.ChunkSubEntries)
|
||||
{
|
||||
list2.Nodes.Add($"ChunkOffset {chunk.ChunkOffset} ChunkType {chunk.ChunkType.ToString("X")} Unknown {chunk.Unknown}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Now go through each file and format and connect the headers and blocks
|
||||
@ -85,13 +121,14 @@ namespace FirstPlugin
|
||||
|
||||
for (int i = 0; i < files.Count; i++)
|
||||
{
|
||||
if (files[i].FileType == FileEntry.FileDataType.Texture)
|
||||
if (files[i].FileType == FileEntry.DataType.Texture)
|
||||
{
|
||||
if (files[i].Unknown3 == 1) //Info
|
||||
{
|
||||
//Read the info
|
||||
using (var textureReader = new FileReader(files[i].FileData))
|
||||
{
|
||||
int headerIndex = 0;
|
||||
while (textureReader.ReadUInt32() == TexturePOWE.Identifier)
|
||||
{
|
||||
var texture = new TexturePOWE();
|
||||
@ -99,7 +136,7 @@ namespace FirstPlugin
|
||||
texture.SelectedImageKey = texture.ImageKey;
|
||||
texture.Index = ImageIndex;
|
||||
texture.Read(textureReader);
|
||||
texture.Text = $"Texture {ImageIndex}";
|
||||
texture.Text = $"Texture {headerIndex++}";
|
||||
textureFolder.Nodes.Add(texture);
|
||||
Textures.Add(texture);
|
||||
}
|
||||
@ -120,8 +157,6 @@ namespace FirstPlugin
|
||||
ImageIndex++;
|
||||
}
|
||||
}
|
||||
else
|
||||
Nodes.Add(files[i]);
|
||||
}
|
||||
|
||||
if (textureFolder.Nodes.Count > 0)
|
||||
@ -231,23 +266,23 @@ namespace FirstPlugin
|
||||
}
|
||||
}
|
||||
|
||||
public class FileEntry : TreeNodeCustom
|
||||
public class FileEntry : ArchiveFileInfo
|
||||
{
|
||||
public LM2_DICT ParentDictionary { get; set; }
|
||||
|
||||
public uint Offset;
|
||||
public uint DecompressedSize;
|
||||
public uint CompressedSize;
|
||||
public FileDataType FileType;
|
||||
public DataType FileType;
|
||||
public byte Unknown2;
|
||||
public byte Unknown3; //Possibly the effect? 0 for image block, 1 for info
|
||||
|
||||
public enum FileDataType : ushort
|
||||
public enum DataType : ushort
|
||||
{
|
||||
Texture = 0x80,
|
||||
}
|
||||
|
||||
public byte[] FileData
|
||||
public override byte[] FileData
|
||||
{
|
||||
get { return GetData(); }
|
||||
set
|
||||
@ -256,18 +291,6 @@ namespace FirstPlugin
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnClick(TreeView treeview)
|
||||
{
|
||||
HexEditor editor = (HexEditor)LibraryGUI.GetActiveContent(typeof(HexEditor));
|
||||
if (editor == null)
|
||||
{
|
||||
editor = new HexEditor();
|
||||
LibraryGUI.LoadEditor(editor);
|
||||
}
|
||||
editor.Dock = DockStyle.Fill;
|
||||
editor.LoadData(FileData);
|
||||
}
|
||||
|
||||
public FileEntry(LM2_DICT dict)
|
||||
{
|
||||
ParentDictionary = dict;
|
||||
@ -278,7 +301,7 @@ namespace FirstPlugin
|
||||
Offset = reader.ReadUInt32();
|
||||
DecompressedSize = reader.ReadUInt32();
|
||||
CompressedSize = reader.ReadUInt32();
|
||||
FileType = reader.ReadEnum<FileDataType>(false);
|
||||
FileType = reader.ReadEnum<DataType>(false);
|
||||
Unknown2 = reader.ReadByte();
|
||||
Unknown3 = reader.ReadByte();
|
||||
}
|
||||
|
@ -1403,6 +1403,12 @@ namespace Bfres.Structs
|
||||
vert.Data = weights.ToArray();
|
||||
vert.Format = att.Format;
|
||||
atrib.Add(vert);
|
||||
|
||||
for (int i = 0; i < weights.Count; i++)
|
||||
{
|
||||
Console.WriteLine($"w {i} {weights[i]}");
|
||||
}
|
||||
|
||||
}
|
||||
if (att.Name == "_i0")
|
||||
{
|
||||
|
@ -264,7 +264,7 @@ namespace FirstPlugin
|
||||
break;
|
||||
}
|
||||
|
||||
if (objects[0].weightsT.Count != objects[0].vertices.Count)
|
||||
if (objects[0].weightsT.Count > 0 && objects[0].weightsT.Count != objects[0].vertices.Count)
|
||||
throw new Exception("Incorrect vertex amount");
|
||||
|
||||
foreach (STGenericObject obj in objects)
|
||||
@ -277,16 +277,20 @@ namespace FirstPlugin
|
||||
foreach (float f in obj.weightsT[v])
|
||||
obj.vertices[v].boneWeights.Add(f);
|
||||
}
|
||||
|
||||
int vID = 0;
|
||||
foreach (Vertex v in obj.vertices)
|
||||
{
|
||||
if (v.boneNames.Count == 1)
|
||||
Console.WriteLine($"{v.boneNames[0]} {v.boneWeights[0]}");
|
||||
Console.WriteLine($"{vID} {v.boneNames[0]} {v.boneWeights[0]}");
|
||||
if (v.boneNames.Count == 2)
|
||||
Console.WriteLine($"{v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]}");
|
||||
Console.WriteLine($"{vID} {v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]}");
|
||||
if (v.boneNames.Count == 3)
|
||||
Console.WriteLine($"{v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]} {v.boneNames[2]} {v.boneWeights[2]}");
|
||||
Console.WriteLine($"{vID} {v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]} {v.boneNames[2]} {v.boneWeights[2]}");
|
||||
if (v.boneNames.Count == 4)
|
||||
Console.WriteLine($"{v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]} {v.boneNames[2]} {v.boneWeights[2]} {v.boneNames[3]} {v.boneWeights[3]}");
|
||||
Console.WriteLine($"{vID} {v.boneNames[0]} {v.boneWeights[0]} {v.boneNames[1]} {v.boneWeights[1]} {v.boneNames[2]} {v.boneWeights[2]} {v.boneNames[3]} {v.boneWeights[3]}");
|
||||
|
||||
vID++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,6 +204,7 @@
|
||||
<Compile Include="FileFormats\Archives\ARC.cs" />
|
||||
<Compile Include="FileFormats\Archives\GFA.cs" />
|
||||
<Compile Include="FileFormats\Archives\IGA_PAK.cs" />
|
||||
<Compile Include="FileFormats\Archives\LM2\LM2_ChunkTable.cs" />
|
||||
<Compile Include="FileFormats\Archives\LM2\LM2_DICT.cs" />
|
||||
<Compile Include="FileFormats\Archives\LZARC.cs" />
|
||||
<Compile Include="FileFormats\Archives\ME01.cs" />
|
||||
|
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user