mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-26 06:20:24 +00:00
Add support for Luigi's Mansion 3 Models
This commit is contained in:
parent
ed961ef10a
commit
544a30639b
11 changed files with 459 additions and 245 deletions
|
@ -22,7 +22,7 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
|||
public enum IndexFormat : ushort
|
||||
{
|
||||
Index_16 = 0x0,
|
||||
Index_8 = 0x8000,
|
||||
Index_8 = 0x8000,
|
||||
}
|
||||
|
||||
public enum SubDataType : uint
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
{
|
||||
public class ChunkEntry
|
||||
{
|
||||
public uint Unknown1;
|
||||
public uint ChunkSize;
|
||||
public uint ChunkOffset;
|
||||
public DataType ChunkType;
|
||||
public uint ChunkSubCount;
|
||||
|
@ -26,7 +26,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
//Table consists of 2 chunk entry lists that define how the .data reads sections
|
||||
public class LM3_ChunkTable
|
||||
{
|
||||
private const int ChunkInfoIdenfier = 0x2001301;
|
||||
private const short ChunkInfoIdenfier = 0x1301;
|
||||
|
||||
//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
|
||||
|
@ -38,7 +38,40 @@ namespace FirstPlugin.LuigisMansion3
|
|||
{
|
||||
tableReader.SetByteOrder(false);
|
||||
|
||||
//Read to the end of the file as the rest of the table are types, offsets, and an unknown value
|
||||
//Load the first chunk table
|
||||
//These point to sections which usually have magic and a hash
|
||||
//The chunk table afterwards contains the data itself
|
||||
while (tableReader.ReadUInt16() == ChunkInfoIdenfier)
|
||||
{
|
||||
tableReader.ReadUInt16();
|
||||
|
||||
ChunkEntry entry = new ChunkEntry();
|
||||
ChunkEntries.Add(entry);
|
||||
|
||||
entry.ChunkSize = tableReader.ReadUInt32(); //Always 8
|
||||
entry.ChunkOffset = tableReader.ReadUInt32(); //The chunk offset in the file. Relative to the first chunk position in the file
|
||||
entry.ChunkType = tableReader.ReadEnum<DataType>(false); //The type of chunk. 0x8701B5 for example for texture info
|
||||
entry.ChunkSubCount = tableReader.ReadByte(); //Uncertain about this. 2 for textures (info + block). Some sections however use large numbers.
|
||||
tableReader.ReadByte();
|
||||
tableReader.ReadByte();
|
||||
tableReader.ReadByte();
|
||||
|
||||
//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();
|
||||
|
||||
Console.WriteLine("ChunkOffset " + entry.ChunkOffset);
|
||||
}
|
||||
|
||||
if (ChunkEntries.Count > 0)
|
||||
ChunkEntries.LastOrDefault<ChunkEntry>().Unknown3 = 0;
|
||||
|
||||
tableReader.Position -= 2; //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 sizes
|
||||
while (!tableReader.EndOfStream && tableReader.Position <= tableReader.BaseStream.Length - 12)
|
||||
{
|
||||
ChunkSubEntry subEntry = new ChunkSubEntry();
|
||||
|
|
|
@ -13,7 +13,7 @@ using System.Drawing;
|
|||
namespace FirstPlugin.LuigisMansion3
|
||||
{
|
||||
//Parse info based on https://github.com/TheFearsomeDzeraora/LM3L
|
||||
public class LM3_DICT : TreeNodeFile, IFileFormat
|
||||
public class LM3_DICT : TreeNodeFile, IFileFormat, ILeaveOpenOnLoad
|
||||
{
|
||||
public FileType FileType { get; set; } = FileType.Archive;
|
||||
|
||||
|
@ -63,7 +63,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
}
|
||||
}
|
||||
|
||||
public static bool DebugMode = false;
|
||||
public static bool DebugMode = true;
|
||||
|
||||
public List<ChunkDataEntry> chunkEntries = new List<ChunkDataEntry>();
|
||||
|
||||
|
@ -84,22 +84,28 @@ namespace FirstPlugin.LuigisMansion3
|
|||
|
||||
private void LoadHashes()
|
||||
{
|
||||
/* foreach (string hashStr in Properties.Resources.LM3_Hashes.Split('\n'))
|
||||
foreach (string hashStr in Properties.Resources.LM3_Hashes.Split('\n'))
|
||||
{
|
||||
uint hash = Toolbox.Library.Security.Cryptography.Crc32.Compute(hashStr);
|
||||
if (!HashNames.ContainsKey(hash))
|
||||
HashNames.Add(hash, hashStr);
|
||||
//This hash txt includes a hash and then the string path after seperated by a comma
|
||||
//The game does not store actual strings in the exefs so it's impossible to get the original names
|
||||
//Instead I use a text file with user generated names based on the texture for easier searching
|
||||
string[] hashes = hashStr.Split(',');
|
||||
if (hashes.Length != 2) continue;
|
||||
|
||||
foreach (string pathStr in hashStr.Split('/'))
|
||||
{
|
||||
uint hash2 = Toolbox.Library.Security.Cryptography.Crc32.Compute(pathStr);
|
||||
if (!HashNames.ContainsKey(hash2))
|
||||
HashNames.Add(hash2, pathStr);
|
||||
}
|
||||
}*/
|
||||
uint hash = 0;
|
||||
uint.TryParse(hashes[0], System.Globalization.NumberStyles.HexNumber, null, out hash);
|
||||
if (!HashNames.ContainsKey(hash))
|
||||
HashNames.Add(hash, hashes[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetFileVertexData()
|
||||
|
||||
public System.IO.Stream GetFileBufferData()
|
||||
{
|
||||
return fileEntries[54].GetData(); //Get the fourth file
|
||||
}
|
||||
|
||||
public System.IO.Stream GetFileVertexData()
|
||||
{
|
||||
return fileEntries[60].GetData(); //Get the fourth file
|
||||
}
|
||||
|
@ -145,6 +151,9 @@ namespace FirstPlugin.LuigisMansion3
|
|||
|
||||
var FileCount = 120;
|
||||
|
||||
TreeNode chunkTexFolder = new TreeNode("Texture");
|
||||
TreeNode chunkModelFolder = new TreeNode("Model");
|
||||
|
||||
long FileTablePos = reader.Position;
|
||||
for (int i = 0; i < FileCount; i++)
|
||||
{
|
||||
|
@ -180,7 +189,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
|
||||
foreach (var chunk in ChunkTable.ChunkEntries)
|
||||
{
|
||||
list1.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkOffset {chunk.ChunkOffset} Unknown1 {chunk.Unknown1} ChunkSubCount {chunk.ChunkSubCount} Unknown3 {chunk.Unknown3}");
|
||||
list1.Nodes.Add($"ChunkType {chunk.ChunkType.ToString("X")} ChunkOffset {chunk.ChunkOffset} ChunkSize {chunk.ChunkSize} ChunkSubCount {chunk.ChunkSubCount} Unknown3 {chunk.Unknown3}");
|
||||
}
|
||||
foreach (var chunk in ChunkTable.ChunkSubEntries)
|
||||
{
|
||||
|
@ -194,22 +203,28 @@ namespace FirstPlugin.LuigisMansion3
|
|||
|
||||
//Model data block
|
||||
//Contains texture hash refs and model headers
|
||||
byte[] File052Data = fileEntries[52].GetData();
|
||||
var File052Data = fileEntries[52].GetData();
|
||||
|
||||
//Unsure, layout data??
|
||||
var File053Data = fileEntries[53].GetData();
|
||||
|
||||
//Contains model data
|
||||
byte[] File054Data = fileEntries[54].GetData();
|
||||
var File054Data = fileEntries[54].GetData();
|
||||
|
||||
//Image header block
|
||||
byte[] File063Data = fileEntries[63].GetData();
|
||||
//Image header block. Also contains shader data
|
||||
var File063Data = fileEntries[63].GetData();
|
||||
|
||||
//Image data block
|
||||
byte[] File065Data = fileEntries[65].GetData();
|
||||
var File065Data = fileEntries[65].GetData();
|
||||
|
||||
//Set an instance of our current data
|
||||
//Chunks are in order, so you build off of when an instance gets loaded
|
||||
LM3_Model currentModel = new LM3_Model(this);
|
||||
|
||||
TexturePOWE currentTexture = new TexturePOWE();
|
||||
ChunkDataEntry currentVertexPointerList = null;
|
||||
|
||||
List<uint> TextureHashes = new List<uint>();
|
||||
|
||||
int chunkId = 0;
|
||||
uint modelIndex = 0;
|
||||
|
@ -223,7 +238,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
chunkEntry.DataFile = File063Data;
|
||||
|
||||
//Read the info
|
||||
using (var textureReader = new FileReader(chunkEntry.FileData))
|
||||
using (var textureReader = new FileReader(chunkEntry.FileData, true))
|
||||
{
|
||||
currentTexture = new TexturePOWE();
|
||||
currentTexture.ImageKey = "texture";
|
||||
|
@ -240,20 +255,21 @@ namespace FirstPlugin.LuigisMansion3
|
|||
textureFolder.Nodes.Add(currentTexture);
|
||||
Renderer.TextureList.Add(currentTexture);
|
||||
|
||||
TextureHashes.Add(currentTexture.ID2);
|
||||
|
||||
ImageHeaderIndex++;
|
||||
}
|
||||
break;
|
||||
case SubDataType.TextureData:
|
||||
chunkEntry.DataFile = File065Data;
|
||||
currentTexture.ImageData = chunkEntry.FileData;
|
||||
currentTexture.ImageData = chunkEntry.FileData.ToBytes();
|
||||
break;
|
||||
/* case SubDataType.ModelStart:
|
||||
case SubDataType.ModelStart:
|
||||
chunkEntry.DataFile = File052Data;
|
||||
currentModel = new LM3_Model(this);
|
||||
currentModel.ModelInfo = new LM3_ModelInfo();
|
||||
currentModel.Text = $"Model {modelIndex}";
|
||||
currentModel.ModelInfo.Data = chunkEntry.FileData;
|
||||
modelFolder.Nodes.Add(currentModel);
|
||||
currentModel.ModelInfo.Data = chunkEntry.FileData.ToBytes();
|
||||
modelIndex++;
|
||||
break;
|
||||
case SubDataType.MeshBuffers:
|
||||
|
@ -263,25 +279,31 @@ namespace FirstPlugin.LuigisMansion3
|
|||
break;
|
||||
case SubDataType.VertexStartPointers:
|
||||
chunkEntry.DataFile = File052Data;
|
||||
using (var vtxPtrReader = new FileReader(chunkEntry.FileData))
|
||||
{
|
||||
while (!vtxPtrReader.EndOfStream)
|
||||
currentModel.VertexBufferPointers.Add(vtxPtrReader.ReadUInt32());
|
||||
}
|
||||
currentVertexPointerList = chunkEntry;
|
||||
break;
|
||||
case SubDataType.SubmeshInfo:
|
||||
chunkEntry.DataFile = File052Data;
|
||||
int MeshCount = chunkEntry.FileData.Length / 0x28;
|
||||
int MeshCount = (int)chunkEntry.FileData.Length / 0x40;
|
||||
|
||||
using (var vtxPtrReader = new FileReader(currentVertexPointerList.FileData))
|
||||
using (var meshReader = new FileReader(chunkEntry.FileData))
|
||||
{
|
||||
for (uint i = 0; i < MeshCount; i++)
|
||||
{
|
||||
meshReader.SeekBegin(i * 0x40);
|
||||
LM3_Mesh mesh = new LM3_Mesh();
|
||||
mesh.Read(meshReader);
|
||||
currentModel.Meshes.Add(mesh);
|
||||
|
||||
Console.WriteLine($"mesh.Unknown3 {mesh.Unknown3 }");
|
||||
|
||||
var buffer = new LM3_Model.PointerInfo();
|
||||
buffer.Read(vtxPtrReader, mesh.Unknown3 != 4294967295);
|
||||
currentModel.VertexBufferPointers.Add(buffer);
|
||||
}
|
||||
}
|
||||
currentModel.ModelInfo.Read(new FileReader(currentModel.ModelInfo.Data), currentModel.Meshes);
|
||||
|
||||
modelFolder.Nodes.Add(currentModel);
|
||||
break;
|
||||
case SubDataType.ModelTransform:
|
||||
chunkEntry.DataFile = File052Data;
|
||||
|
@ -297,28 +319,42 @@ namespace FirstPlugin.LuigisMansion3
|
|||
}
|
||||
break;
|
||||
case SubDataType.MaterialName:
|
||||
using (var matReader = new FileReader(chunkEntry.FileData))
|
||||
chunkEntry.DataFile = File053Data;
|
||||
/* using (var matReader = new FileReader(chunkEntry.FileData))
|
||||
{
|
||||
materialNamesFolder.Nodes.Add(matReader.ReadZeroTerminatedString());
|
||||
}
|
||||
break;*/
|
||||
}*/
|
||||
break;
|
||||
case SubDataType.UILayoutMagic:
|
||||
chunkEntry.DataFile = File053Data;
|
||||
break;
|
||||
case SubDataType.UILayout:
|
||||
chunkEntry.DataFile = File053Data;
|
||||
break;
|
||||
default:
|
||||
chunkEntry.DataFile = File052Data;
|
||||
break;
|
||||
}
|
||||
|
||||
chunkEntry.Text = $"{chunk.ChunkType.ToString("X")} {chunk.ChunkType} {chunk.ChunkOffset} {chunk.ChunkSize}";
|
||||
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;
|
||||
|
||||
chunkId++;
|
||||
}
|
||||
|
||||
foreach (var model in modelFolder.Nodes)
|
||||
{
|
||||
((LM3_Model)currentModel).ModelInfo.Read(new FileReader(
|
||||
currentModel.ModelInfo.Data), currentModel.Meshes, TextureHashes);
|
||||
}
|
||||
|
||||
if (textureFolder.Nodes.Count > 0)
|
||||
Nodes.Add(textureFolder);
|
||||
|
||||
foreach (LM3_Model model in modelFolder.Nodes)
|
||||
{
|
||||
model.ReadVertexBuffers();
|
||||
}
|
||||
|
||||
if (modelFolder.Nodes.Count > 0)
|
||||
Nodes.Add(modelFolder);
|
||||
}
|
||||
|
@ -331,6 +367,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
|
||||
public void Save(System.IO.Stream stream)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public bool AddFile(ArchiveFileInfo archiveFileInfo)
|
||||
|
@ -364,7 +401,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
|
||||
public class ChunkDataEntry : TreeNodeFile, IContextMenuNode
|
||||
{
|
||||
public byte[] DataFile;
|
||||
public System.IO.Stream DataFile;
|
||||
public LM3_DICT ParentDictionary { get; set; }
|
||||
public ChunkSubEntry Entry;
|
||||
|
||||
|
@ -374,15 +411,16 @@ namespace FirstPlugin.LuigisMansion3
|
|||
Entry = entry;
|
||||
}
|
||||
|
||||
public byte[] FileData
|
||||
public System.IO.Stream FileData
|
||||
{
|
||||
get
|
||||
{
|
||||
using (var reader = new FileReader(DataFile))
|
||||
{
|
||||
reader.SeekBegin(Entry.ChunkOffset);
|
||||
return reader.ReadBytes((int)Entry.ChunkSize);
|
||||
}
|
||||
if (Entry.ChunkSize == 0)
|
||||
return new System.IO.MemoryStream();
|
||||
else if (Entry.ChunkOffset + Entry.ChunkSize < DataFile?.Length)
|
||||
return new SubStream(DataFile, Entry.ChunkOffset, Entry.ChunkSize);
|
||||
else
|
||||
return new System.IO.MemoryStream();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,9 +438,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
sfd.Filter = "Raw Data (*.*)|*.*";
|
||||
|
||||
if (sfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
System.IO.File.WriteAllBytes(sfd.FileName, FileData);
|
||||
}
|
||||
FileData.ExportToFile(sfd.FileName);
|
||||
}
|
||||
|
||||
public override void OnClick(TreeView treeView)
|
||||
|
@ -447,12 +483,11 @@ namespace FirstPlugin.LuigisMansion3
|
|||
|
||||
private bool IsTextureBinary()
|
||||
{
|
||||
byte[] Data = GetData();
|
||||
|
||||
if (Data.Length < 4)
|
||||
var stream = GetData();
|
||||
if (stream.Length < 4)
|
||||
return false;
|
||||
|
||||
using (var reader = new FileReader(Data))
|
||||
using (var reader = new FileReader(stream, true))
|
||||
{
|
||||
return reader.ReadUInt32() == 0xE977D350;
|
||||
}
|
||||
|
@ -472,9 +507,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
sfd.Filter = "Raw Data (*.*)|*.*";
|
||||
|
||||
if (sfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
System.IO.File.WriteAllBytes(sfd.FileName, GetData());
|
||||
}
|
||||
GetData().ExportToFile(sfd.FileName);
|
||||
}
|
||||
|
||||
public override void OnClick(TreeView treeView)
|
||||
|
@ -490,19 +523,19 @@ namespace FirstPlugin.LuigisMansion3
|
|||
editor.LoadData(GetData());
|
||||
}
|
||||
|
||||
public byte[] GetData()
|
||||
public System.IO.Stream GetData()
|
||||
{
|
||||
byte[] Data = new byte[DecompressedSize];
|
||||
System.IO.Stream Data = new System.IO.MemoryStream();
|
||||
|
||||
string FolderPath = System.IO.Path.GetDirectoryName(ParentDictionary.FilePath);
|
||||
string DataFile = System.IO.Path.Combine(FolderPath, $"{ParentDictionary.FileName.Replace(".dict", ".data")}");
|
||||
|
||||
if (System.IO.File.Exists(DataFile))
|
||||
{
|
||||
using (var reader = new FileReader(DataFile))
|
||||
using (var reader = new FileReader(DataFile, true))
|
||||
{
|
||||
if (Offset > reader.BaseStream.Length)
|
||||
return reader.ReadBytes((int)CompressedSize);
|
||||
return new System.IO.MemoryStream();
|
||||
|
||||
reader.SeekBegin(Offset);
|
||||
if (ParentDictionary.IsCompressed)
|
||||
|
@ -510,16 +543,15 @@ namespace FirstPlugin.LuigisMansion3
|
|||
ushort Magic = reader.ReadUInt16();
|
||||
reader.SeekBegin(Offset);
|
||||
|
||||
Data = reader.ReadBytes((int)CompressedSize);
|
||||
if (Magic == 0x9C78 || Magic == 0xDA78)
|
||||
return STLibraryCompression.ZLIB.Decompress(Data);
|
||||
return new System.IO.MemoryStream(STLibraryCompression.ZLIB.Decompress(reader.ReadBytes((int)CompressedSize)));
|
||||
else //Unknown compression
|
||||
return Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return reader.ReadBytes((int)DecompressedSize);
|
||||
}
|
||||
else if (DecompressedSize == 0)
|
||||
return new System.IO.MemoryStream();
|
||||
else if (Offset + DecompressedSize < reader.BaseStream.Length)
|
||||
return new SubStream(reader.BaseStream, Offset, DecompressedSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@ namespace FirstPlugin.LuigisMansion3
|
|||
{
|
||||
public enum DataType : uint
|
||||
{
|
||||
Texture = 0x8701B500,
|
||||
Texture = 0xBA41B500,
|
||||
Model = 0x8101B000,
|
||||
Unknown = 0x08C17000,
|
||||
}
|
||||
|
||||
public enum VertexDataFormat
|
||||
|
@ -22,7 +24,9 @@ namespace FirstPlugin.LuigisMansion3
|
|||
public enum IndexFormat : ushort
|
||||
{
|
||||
Index_16 = 0x0,
|
||||
Index_8 = 0x8000,
|
||||
Index_32 = 0x1,
|
||||
Index_32_ = 0x2,
|
||||
Index_8 = 0x8000,
|
||||
}
|
||||
|
||||
public enum SubDataType2 : uint
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace FirstPlugin.LuigisMansion3
|
|||
public LM3_DICT DataDictionary;
|
||||
public LM3_ModelInfo ModelInfo;
|
||||
public List<LM3_Mesh> Meshes = new List<LM3_Mesh>();
|
||||
public List<uint> VertexBufferPointers = new List<uint>();
|
||||
public List<PointerInfo> VertexBufferPointers = new List<PointerInfo>();
|
||||
|
||||
public uint BufferStart;
|
||||
public uint BufferSize;
|
||||
|
@ -87,8 +87,12 @@ namespace FirstPlugin.LuigisMansion3
|
|||
}
|
||||
}
|
||||
|
||||
private bool loaded = false;
|
||||
public override void OnClick(TreeView treeView)
|
||||
{
|
||||
if (!loaded)
|
||||
UpdateVertexData();
|
||||
|
||||
if (Runtime.UseOpenGL)
|
||||
{
|
||||
if (viewport == null)
|
||||
|
@ -97,13 +101,36 @@ namespace FirstPlugin.LuigisMansion3
|
|||
viewport.Dock = DockStyle.Fill;
|
||||
}
|
||||
|
||||
viewport.ReloadDrawables(DataDictionary.DrawableContainer);
|
||||
LibraryGUI.LoadEditor(viewport);
|
||||
viewport.SuppressUpdating = true;
|
||||
|
||||
foreach (var mesh in DataDictionary.Renderer.Meshes)
|
||||
mesh.Checked = false;
|
||||
|
||||
foreach (TreeNode mesh in Nodes)
|
||||
mesh.Checked = true;
|
||||
|
||||
viewport.SuppressUpdating = false;
|
||||
|
||||
Viewport editor = (Viewport)LibraryGUI.GetActiveContent(typeof(Viewport));
|
||||
if (editor == null)
|
||||
{
|
||||
editor = viewport;
|
||||
LibraryGUI.LoadEditor(viewport);
|
||||
}
|
||||
|
||||
viewport.ReloadDrawables(DataDictionary.DrawableContainer);
|
||||
viewport.Text = Text;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVertexData()
|
||||
{
|
||||
ReadVertexBuffers();
|
||||
DataDictionary.Renderer.UpdateVertexData();
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
public ToolStripItem[] GetContextMenuItems()
|
||||
{
|
||||
List<ToolStripItem> Items = new List<ToolStripItem>();
|
||||
|
@ -143,13 +170,35 @@ namespace FirstPlugin.LuigisMansion3
|
|||
DataDictionary = dict;
|
||||
}
|
||||
|
||||
public class PointerInfo
|
||||
{
|
||||
//Note if a pointer is not used, it will be 0xFFFFF
|
||||
|
||||
public uint WeightTablePointer;
|
||||
public uint VertexBufferPointer;
|
||||
public uint IndexBufferPointer;
|
||||
public uint IndexBufferPointer2;
|
||||
|
||||
public void Read(FileReader reader, bool hasWeightTable = true)
|
||||
{
|
||||
if (hasWeightTable && !reader.EndOfStream)
|
||||
WeightTablePointer = reader.ReadUInt32();
|
||||
if (!reader.EndOfStream)
|
||||
VertexBufferPointer = reader.ReadUInt32();
|
||||
if (!reader.EndOfStream)
|
||||
IndexBufferPointer = reader.ReadUInt32();
|
||||
if (!reader.EndOfStream)
|
||||
IndexBufferPointer2 = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPropertyChanged() { }
|
||||
|
||||
public void ReadVertexBuffers()
|
||||
{
|
||||
Nodes.Clear();
|
||||
|
||||
using (var reader = new FileReader(DataDictionary.GetFileVertexData()))
|
||||
using (var reader = new FileReader(DataDictionary.GetFileBufferData()))
|
||||
{
|
||||
for (int i = 0; i < Meshes.Count; i++)
|
||||
{
|
||||
|
@ -157,7 +206,11 @@ namespace FirstPlugin.LuigisMansion3
|
|||
|
||||
RenderableMeshWrapper genericObj = new RenderableMeshWrapper();
|
||||
genericObj.Mesh = mesh;
|
||||
genericObj.Text = $"Mesh {i}";
|
||||
genericObj.Checked = true;
|
||||
genericObj.Text = $"Mesh {i} {mesh.HashID.ToString("X")}";
|
||||
if (LM3_DICT.HashNames.ContainsKey(mesh.HashID))
|
||||
genericObj.Text = LM3_DICT.HashNames[mesh.HashID];
|
||||
|
||||
genericObj.SetMaterial(mesh.Material);
|
||||
RenderedMeshes.Add(genericObj);
|
||||
|
||||
|
@ -167,127 +220,141 @@ namespace FirstPlugin.LuigisMansion3
|
|||
STGenericPolygonGroup polyGroup = new STGenericPolygonGroup();
|
||||
genericObj.PolygonGroups.Add(polyGroup);
|
||||
|
||||
using (reader.TemporarySeek(BufferStart + VertexBufferPointers[i], System.IO.SeekOrigin.Begin))
|
||||
uint vertexBufferPointer = VertexBufferPointers[i].VertexBufferPointer;
|
||||
|
||||
using (reader.TemporarySeek(BufferStart + vertexBufferPointer, System.IO.SeekOrigin.Begin))
|
||||
{
|
||||
var bufferNodeDebug = new DebugVisualBytes(reader.ReadBytes((int)80 * mesh.VertexCount));
|
||||
var bufferNodeDebug = new DebugVisualBytes(reader.ReadBytes((int)80 * (int)mesh.VertexCount));
|
||||
bufferNodeDebug.Text = $"Buffer {mesh.DataFormat.ToString("x")}";
|
||||
genericObj.Nodes.Add(bufferNodeDebug);
|
||||
}
|
||||
|
||||
LM3_Mesh.FormatInfo formatInfo;
|
||||
if (!LM3_Mesh.FormatInfos.ContainsKey(mesh.DataFormat))
|
||||
{
|
||||
Console.WriteLine($"Unsupported data format! " + mesh.DataFormat.ToString("x"));
|
||||
continue;
|
||||
formatInfo = new LM3_Mesh.FormatInfo(VertexDataFormat.Float32_32_32, 0x30);
|
||||
// continue;
|
||||
}
|
||||
else
|
||||
formatInfo = LM3_Mesh.FormatInfos[mesh.DataFormat];
|
||||
|
||||
if (formatInfo.BufferLength > 0)
|
||||
{
|
||||
var formatInfo = LM3_Mesh.FormatInfos[mesh.DataFormat];
|
||||
if (formatInfo.BufferLength > 0)
|
||||
Console.WriteLine($"BufferStart {BufferStart} IndexStartOffset {mesh.IndexStartOffset}");
|
||||
|
||||
reader.BaseStream.Position = BufferStart + mesh.IndexStartOffset;
|
||||
switch (mesh.IndexFormat)
|
||||
{
|
||||
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()));
|
||||
|
||||
Vector4 nrm = Read_8_8_8_8_Snorm(reader);
|
||||
vert.nrm = nrm.Xyz.Normalized();
|
||||
|
||||
vert.pos = Vector3.TransformPosition(vert.pos, mesh.Transform);
|
||||
vert.uv0 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
|
||||
if (formatInfo.BufferLength == 22)
|
||||
{
|
||||
Console.WriteLine("unk 1 " + reader.ReadUInt16());
|
||||
Console.WriteLine("unk 2 " + reader.ReadUInt16());
|
||||
Console.WriteLine("unk 3 " + reader.ReadUInt16());
|
||||
Console.WriteLine("unk 4 " + reader.ReadUInt16());
|
||||
}
|
||||
}
|
||||
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, mesh.Transform);
|
||||
}
|
||||
break;
|
||||
case VertexDataFormat.Float32_32:
|
||||
reader.BaseStream.Position = BufferStart + VertexBufferPointers[i] + 0x08;
|
||||
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, mesh.Transform);
|
||||
vert.uv0 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
vert.uv1 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
vert.col = Read_8_8_8_8_Unorm(reader);
|
||||
}
|
||||
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, mesh.Transform);
|
||||
Vector4 nrm = Read_8_8_8_8_Snorm(reader);
|
||||
vert.nrm = nrm.Xyz.Normalized();
|
||||
vert.uv0 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
vert.uv1 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
|
||||
if (formatInfo.BufferLength >= 0x1C)
|
||||
vert.col = Read_8_8_8_8_Unorm(reader);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
genericObj.TransformPosition(new Vector3(0), new Vector3(-90, 0, 0), new Vector3(1));
|
||||
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;
|
||||
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}");
|
||||
|
||||
Console.WriteLine($"BufferStart {BufferStart} VertexBufferPointers {vertexBufferPointer}");
|
||||
|
||||
uint bufferOffet = BufferStart + vertexBufferPointer;
|
||||
/* 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()));
|
||||
|
||||
Vector4 nrm = Read_8_8_8_8_Snorm(reader);
|
||||
vert.nrm = nrm.Xyz.Normalized();
|
||||
|
||||
vert.pos = Vector3.TransformPosition(vert.pos, mesh.Transform);
|
||||
vert.uv0 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
|
||||
if (formatInfo.BufferLength == 22)
|
||||
{
|
||||
Console.WriteLine("unk 1 " + reader.ReadUInt16());
|
||||
Console.WriteLine("unk 2 " + reader.ReadUInt16());
|
||||
Console.WriteLine("unk 3 " + reader.ReadUInt16());
|
||||
Console.WriteLine("unk 4 " + reader.ReadUInt16());
|
||||
}
|
||||
}
|
||||
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, mesh.Transform);
|
||||
}
|
||||
break;
|
||||
case VertexDataFormat.Float32_32:
|
||||
reader.BaseStream.Position = BufferStart + vertexBufferPointer + 0x08;
|
||||
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, mesh.Transform);
|
||||
vert.uv0 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
vert.uv1 = NormalizeUvCoordsToFloat(reader.ReadUInt16(), reader.ReadUInt16());
|
||||
vert.col = Read_8_8_8_8_Unorm(reader);
|
||||
}
|
||||
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, 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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
genericObj.TransformPosition(new Vector3(0), new Vector3(-90, 0, 0), new Vector3(1));
|
||||
}
|
||||
|
||||
|
||||
genericObj.RemoveDuplicateVertices();
|
||||
}
|
||||
}
|
||||
|
@ -325,61 +392,34 @@ namespace FirstPlugin.LuigisMansion3
|
|||
{
|
||||
public byte[] Data;
|
||||
|
||||
public void Read(FileReader reader, List<LM3_Mesh> Meshes)
|
||||
public void Read(FileReader reader, List<LM3_Mesh> Meshes, List<uint> Hashes)
|
||||
{
|
||||
// This is very dumb. Just look and try to find the mesh hash and get the texture after
|
||||
int pos = 0;
|
||||
//todo LM3 doesn't work right with this
|
||||
/* while (!reader.EndOfStream && reader.Position < reader.BaseStream.Length - 5)
|
||||
List<uint> ModelTexHashes = new List<uint>();
|
||||
|
||||
//Read entire section till i find a matching texture hash
|
||||
while (!reader.EndOfStream && reader.Position < reader.BaseStream.Length - 4)
|
||||
{
|
||||
reader.Position = pos++;
|
||||
uint HashIDCheck = reader.ReadUInt32();
|
||||
for (int i = 0; i < Meshes.Count; i++)
|
||||
{
|
||||
if (Meshes[i].HashID == HashIDCheck)
|
||||
{
|
||||
uint TextureHashID = reader.ReadUInt32();
|
||||
if (Hashes.Contains(HashIDCheck) && !ModelTexHashes.Contains(HashIDCheck))
|
||||
ModelTexHashes.Add(HashIDCheck);
|
||||
}
|
||||
|
||||
Meshes[i].Material = new LM3_Material();
|
||||
var texUnit = 1;
|
||||
Meshes[i].Material.TextureMaps.Add(new STGenericMatTexture()
|
||||
{
|
||||
textureUnit = texUnit++,
|
||||
Type = STGenericMatTexture.TextureType.Diffuse,
|
||||
Name = TextureHashID.ToString("x"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
for (int i = 0; i < Meshes.Count; i++)
|
||||
{
|
||||
//This section keeps varing so just search for mesh hash id and get texture hash after it
|
||||
|
||||
|
||||
uint Unknown = reader.ReadUInt32(); //A81E313F
|
||||
reader.Seek(40);
|
||||
|
||||
//Not sure what this is. Not a transform as the UVs seem fine as is
|
||||
float[] Unknown2 = reader.ReadSingles(5); //0.5, 1, 0.5,0.5, 1
|
||||
reader.Seek(4); //Padding
|
||||
uint MeshHashID = reader.ReadUInt32();
|
||||
uint TextureHashID = reader.ReadUInt32();
|
||||
uint UnknownHashID = reader.ReadUInt32(); //Material hash??
|
||||
|
||||
//Go through each mesh and find a matching hash
|
||||
for (int m = 0; m < Meshes.Count; m++)
|
||||
if (ModelTexHashes.Count > i)
|
||||
{
|
||||
if (Meshes[m].HashID == MeshHashID)
|
||||
uint TextureHashID = ModelTexHashes[i];
|
||||
|
||||
Meshes[i].Material = new LM3_Material();
|
||||
var texUnit = 1;
|
||||
Meshes[i].Material.TextureMaps.Add(new STGenericMatTexture()
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
if (i != Meshes.Count - 1)
|
||||
reader.Seek(4); //padding on all but last entry
|
||||
}*/
|
||||
textureUnit = texUnit++,
|
||||
Type = STGenericMatTexture.TextureType.Diffuse,
|
||||
Name = TextureHashID.ToString("x"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,9 +527,10 @@ namespace FirstPlugin.LuigisMansion3
|
|||
public ushort Unknown { get; private set; }
|
||||
public ulong DataFormat { get; private set; }
|
||||
public uint Unknown2 { get; private set; }
|
||||
public uint Unknown3 { get; private set; }
|
||||
public uint Unknown3 { get; private set; } //Possibly contributes to rigged meshes. 0xFFFF if static (no weight table / pointer)
|
||||
public uint Unknown4 { get; private set; } //Increases after each mesh. Always 0 for the first mesh (some sort of offset)?
|
||||
public ushort VertexCount { get; private set; }
|
||||
public uint Unknown5 { get; private set; }
|
||||
public uint VertexCount { get; private set; }
|
||||
public ushort Unknown7 { get; private set; } //Always 256?
|
||||
public uint HashID { get; private set; }
|
||||
|
||||
|
@ -501,19 +542,25 @@ namespace FirstPlugin.LuigisMansion3
|
|||
{
|
||||
Material = new LM3_Material();
|
||||
|
||||
HashID = reader.ReadUInt32();
|
||||
IndexStartOffset = reader.ReadUInt32();
|
||||
IndexCount = reader.ReadUInt16();
|
||||
IndexFormat = reader.ReadEnum<IndexFormat>(false);
|
||||
IndexFormat = IndexFormat.Index_16;
|
||||
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
|
||||
Unknown = reader.ReadUInt16();
|
||||
DataFormat = reader.ReadUInt64();
|
||||
Unknown2 = reader.ReadUInt32();
|
||||
Unknown3 = reader.ReadUInt32();
|
||||
Unknown3 = reader.ReadUInt32(); //Sometimes 0xFFFF.
|
||||
reader.ReadUInt16();
|
||||
Unknown4 = reader.ReadUInt32();
|
||||
VertexCount = reader.ReadUInt16();
|
||||
Unknown7 = reader.ReadUInt16(); //0x100
|
||||
HashID = reader.ReadUInt32(); //0x100
|
||||
Unknown5 = reader.ReadUInt32();
|
||||
Unknown7 = reader.ReadUInt16();
|
||||
reader.ReadUInt32(); //unknown
|
||||
reader.ReadUInt32(); //unknown
|
||||
}
|
||||
|
||||
public class FormatInfo
|
||||
|
@ -532,6 +579,25 @@ namespace FirstPlugin.LuigisMansion3
|
|||
//These may not be very accurate, i need to look more into these
|
||||
public static Dictionary<ulong, FormatInfo> FormatInfos = new Dictionary<ulong, FormatInfo>()
|
||||
{
|
||||
{ 0xcb418c82ba25920e, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
|
||||
{ 0x4c083342551178ce, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
|
||||
{ 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)},
|
||||
{ 0x568f92478fa0a2d3, new FormatInfo(VertexDataFormat.Float32_32_32, 0x30)},
|
||||
{ 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)},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{ 0x6350379972D28D0D, new FormatInfo(VertexDataFormat.Float16, 0x46)},
|
||||
{ 0xDC0291B311E26127, new FormatInfo(VertexDataFormat.Float16, 0x16)},
|
||||
{ 0x93359708679BEB7C, new FormatInfo(VertexDataFormat.Float16, 0x16)},
|
||||
|
|
|
@ -131,6 +131,7 @@
|
|||
this.Name,
|
||||
this.Format});
|
||||
this.listViewCustom1.Dock = System.Windows.Forms.DockStyle.Left;
|
||||
this.listViewCustom1.HideSelection = false;
|
||||
this.listViewCustom1.Location = new System.Drawing.Point(0, 25);
|
||||
this.listViewCustom1.Name = "listViewCustom1";
|
||||
this.listViewCustom1.OwnerDraw = true;
|
||||
|
|
33
File_Format_Library/Properties/Resources.Designer.cs
generated
33
File_Format_Library/Properties/Resources.Designer.cs
generated
|
@ -200,6 +200,39 @@ namespace FirstPlugin.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to D:\Project\NeoPlum\Out\Dist\NXROM\NeoPlumNX64_dist.nss
|
||||
///nnSdk.nss
|
||||
///c:/NXSDK/V7_3_2/NintendoSDK/Libraries/NX-NXFP2-a64/Release/multimedia.nss
|
||||
///__nnDetailNintendoSdkRuntimeObjectFile
|
||||
///__nnDetailNintendoSdkRuntimeObjectFileRefer
|
||||
///__nnmusl_fini_dso
|
||||
///__nnmusl_init_dso
|
||||
///__rel_dyn_end
|
||||
///__rel_dyn_start
|
||||
///__rel_plt_end
|
||||
///__rel_plt_start
|
||||
///nndetailRoGetRoDataEnd
|
||||
///nndetailRoGetRoDataStart
|
||||
///nnMain
|
||||
///nninitStartup
|
||||
///_ZdlPv
|
||||
///_ZNSt3__112__next_primeEm
|
||||
///strtoul
|
||||
///strtod
|
||||
///vsnprintf
|
||||
///vswprintf
|
||||
///_ZdaPv
|
||||
///_Znwm
|
||||
///_Znam
|
||||
///__cxa_guard_ac [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string LM3_Hashes {
|
||||
get {
|
||||
return ResourceManager.GetString("LM3_Hashes", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
|
|
|
@ -199,4 +199,7 @@
|
|||
<data name="MissingTexture" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\MissingTexture.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="LM3_Hashes" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Hashes\LM3_Hashes.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
|
||||
</data>
|
||||
</root>
|
10
File_Format_Library/Resources/Hashes/LM3_Hashes.txt
Normal file
10
File_Format_Library/Resources/Hashes/LM3_Hashes.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
-- Names here are user generated --
|
||||
-- Hashes are in hex format and names go after seperated by a comma --
|
||||
-- Names can be paths for multiple folders --
|
||||
|
||||
9d6bf95e, Body_Diffuse
|
||||
9deaa4e5, Body_SSS
|
||||
9e5737eb, Body_Normal
|
||||
852f0ba7, Cloth_Diffuse
|
||||
85adb72e, Cloth_SSS
|
||||
861a4a34, Cloth_Normal
|
|
@ -121,13 +121,22 @@ namespace Toolbox.Library.Forms
|
|||
Color uvColor = Color.LightGreen;
|
||||
Color gridColor = Color.Black;
|
||||
|
||||
|
||||
|
||||
List<int> f = genericObject.lodMeshes[0].getDisplayFace();
|
||||
|
||||
for (int v = 0; v < genericObject.lodMeshes[0].displayFaceSize; v += 3)
|
||||
List<int> f = new List<int>();
|
||||
int displayFaceSize = 0;
|
||||
if (genericObject.lodMeshes.Count > 0)
|
||||
{
|
||||
if (genericObject.lodMeshes[0].displayFaceSize < 3 ||
|
||||
f = genericObject.lodMeshes[0].getDisplayFace();
|
||||
displayFaceSize = genericObject.lodMeshes[0].displayFaceSize;
|
||||
}
|
||||
if (genericObject.PolygonGroups.Count > 0)
|
||||
{
|
||||
f = genericObject.PolygonGroups[0].GetDisplayFace();
|
||||
displayFaceSize = genericObject.PolygonGroups[0].displayFaceSize;
|
||||
}
|
||||
|
||||
for (int v = 0; v < displayFaceSize; v += 3)
|
||||
{
|
||||
if (displayFaceSize < 3 ||
|
||||
genericObject.vertices.Count < 3)
|
||||
return;
|
||||
|
||||
|
@ -135,6 +144,9 @@ namespace Toolbox.Library.Forms
|
|||
Vector2 v2 = new Vector2(0);
|
||||
Vector2 v3 = new Vector2(0);
|
||||
|
||||
if (f.Count < v + 2)
|
||||
continue;
|
||||
|
||||
if (UvChannelIndex == 0)
|
||||
{
|
||||
v1 = genericObject.vertices[f[v]].uv0;
|
||||
|
@ -563,6 +575,22 @@ namespace Toolbox.Library.Forms
|
|||
}
|
||||
}
|
||||
}
|
||||
if (container.Drawables[i] is Rendering.GenericModelRenderer && container.Drawables[i].Visible)
|
||||
{
|
||||
for (int m = 0; m < ((Rendering.GenericModelRenderer)container.Drawables[i]).Meshes.Count; m++)
|
||||
{
|
||||
var mesh = ((Rendering.GenericModelRenderer)container.Drawables[i]).Meshes[m];
|
||||
if (mesh.GetMaterial() != null)
|
||||
{
|
||||
Objects.Add(mesh);
|
||||
var mat = mesh.GetMaterial();
|
||||
if (!Materials.Contains(mat))
|
||||
{
|
||||
Materials.Add(mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
|
|
@ -30,6 +30,8 @@ namespace Toolbox.Library
|
|||
}
|
||||
}
|
||||
|
||||
public bool SuppressUpdating = false;
|
||||
|
||||
public List<DrawableContainer> DrawableContainers;
|
||||
|
||||
public EditorScene scene = new EditorScene();
|
||||
|
@ -285,6 +287,8 @@ namespace Toolbox.Library
|
|||
|
||||
public void UpdateViewport()
|
||||
{
|
||||
if (SuppressUpdating) return;
|
||||
|
||||
if (GL_ControlModern != null)
|
||||
GL_ControlModern.Refresh();
|
||||
if (GL_ControlLegacy != null)
|
||||
|
|
Loading…
Reference in a new issue