using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;
using System.Runtime.InteropServices;
namespace ModelImporter
{
static class ModelReader
{
public static Model LoadFromFile(Stream stream)
{
var reader = new BinaryReader(stream);
reader.ReadBytes(44);
if (reader.ReadInt32() != 721465829)
throw new Exception("Magic number mismatch!");
var v4 = reader.ReadInt32();
if (v4 != 5 && v4 != 6)
throw new Exception("fish");
Console.WriteLine("First Long: {0}", v4);
var headerSize = reader.ReadInt32(); // 1900
var headerData = reader.ReadBytes(headerSize);
var headerReader = new BinaryReader(new MemoryStream(headerData));
headerReader.ReadBytes(68);
var numMaterialDefinitions = headerReader.ReadInt32(); // 68
var numMeshDescriptions = headerReader.ReadInt32(); // 72
var numBones = headerReader.ReadInt32(); // 76
var numEnts = headerReader.ReadInt32(); // 80
var numSomething4 = headerReader.ReadInt32(); // 84
var numSomething5 = headerReader.ReadInt32(); // 88
headerReader.ReadBytes(20);
var numVertex = headerReader.ReadInt32(); // 112
var numStrides = headerReader.ReadInt32(); // 116
headerReader.ReadInt32(); // 120
var numIndices = headerReader.ReadInt32(); // 124
var model = new Model();
model.MaterialDefinitions = new MaterialDefinition[numMaterialDefinitions];
Console.WriteLine("Reading {0} Material Definition(s)...", model.MaterialDefinitions.Length);
for (int i = 0; i < model.MaterialDefinitions.Length; i++)
{
// there's a special case if Type = _walls_ idk what tho
var materialDefinition = new MaterialDefinition();
materialDefinition.Texture = Util.ReadNullTerminatedString(headerReader, 64);
materialDefinition.Lightmap = Util.ReadNullTerminatedString(headerReader, 64);
materialDefinition.U3 = Util.ReadNullTerminatedString(headerReader, 64);
materialDefinition.SpecularMap = Util.ReadNullTerminatedString(headerReader, 64);
materialDefinition.U5 = Util.ReadNullTerminatedString(headerReader, 64);
materialDefinition.U6 = Util.ReadNullTerminatedString(headerReader, 64);
materialDefinition.Type = Util.ReadNullTerminatedString(headerReader, 64);
model.MaterialDefinitions[i] = materialDefinition;
}
model.MeshDescriptions = new MeshDescription[numMeshDescriptions];
Console.WriteLine("Reading {0} Mesh Description(s)...", model.MeshDescriptions.Length);
for (int i = 0; i < model.MeshDescriptions.Length; i++)
{
var meshDescription = new MeshDescription();
meshDescription.NumFaces = headerReader.ReadInt32(); // 0
meshDescription.IndicesPointer = headerReader.ReadInt32(); // 4
headerReader.ReadBytes(12); // 8
headerReader.ReadBytes(48); // 20 D3DXMATRIX ~~ ( 3x3 matrix into a 4x4? )
headerReader.ReadBytes(16); // 68 4 32bits
headerReader.ReadBytes(48); // 84
meshDescription.U1 = headerReader.ReadInt32(); // 132
meshDescription.NumMaterialRefs = headerReader.ReadInt32(); // 136
meshDescription.U2 = headerReader.ReadInt32(); // 140 ? = *(v17 + 140) + 32 * matRef;
meshDescription.ID = headerReader.ReadInt32(); // 144 increments 1 based, is this like an id
meshDescription.Name = Util.ReadNullTerminatedString(headerReader, 64); // 148
headerReader.ReadInt32(); // 212
headerReader.ReadInt32(); // 216
model.MeshDescriptions[i] = meshDescription;
}
// Material References?
Console.WriteLine("Reading {0} Mesh Description Material References(s)...", model.MeshDescriptions.Length);
for (int i = 0; i < model.MeshDescriptions.Length; i++)
{
var meshDescription = model.MeshDescriptions[i];
meshDescription.MaterialRefs = new MaterialRef[meshDescription.NumMaterialRefs];
for (int j = 0; j < meshDescription.NumMaterialRefs; j++)
{
var materialRef = new MaterialRef();
materialRef.MaterialDef = headerReader.ReadInt32();
materialRef.IndicesPointer = headerReader.ReadInt32();
materialRef.IndicesSize = headerReader.ReadInt32();
materialRef.VertexPointer = headerReader.ReadInt32();
materialRef.VertexSize = headerReader.ReadInt32();
materialRef.FacesPointer = headerReader.ReadInt32();
materialRef.FacesSize = headerReader.ReadInt32();
materialRef.Unknown = headerReader.ReadInt32();
meshDescription.MaterialRefs[j] = materialRef;
}
model.MeshDescriptions[i] = meshDescription;
}
// bones maybe
model.Bones = new Bone[numBones];
Console.WriteLine("Reading {0} Bone(s)...", model.Bones.Length);
for (int i = 0; i < model.Bones.Length; i++)
{
var bone = new Bone();
headerReader.ReadBytes(48); // D3DXMATRIX ~~ ( 3x3 matrix into a 4x4? )
// 12 floats in 48 bytes???
model.Bones[i] = bone;
}
model.Entities = new Entity[numEnts];
Console.WriteLine("Reading {0} Entity(s)...", model.Entities.Length);
for (int i = 0; i < model.Entities.Length; i++)
{
var entity = new Entity();
entity.U1X = headerReader.ReadSingle();
entity.U1Y = headerReader.ReadSingle();
entity.U1Z = headerReader.ReadSingle();
entity.U2X = headerReader.ReadSingle();
entity.U2Y = headerReader.ReadSingle();
entity.U2Z = headerReader.ReadSingle();
entity.U3X = headerReader.ReadSingle();
entity.U3Y = headerReader.ReadSingle();
entity.U3Z = headerReader.ReadSingle();
entity.PosX = headerReader.ReadSingle();
entity.PosY = headerReader.ReadSingle();
entity.PosZ = headerReader.ReadSingle();
entity.Name = Util.ReadNullTerminatedString(headerReader, 256);
model.Entities[i] = entity;
}
model.Scruct4s = new Struct4[numSomething4];
Console.WriteLine("Reading {0} Struct4(s)...", model.Scruct4s.Length);
for (int i = 0; i < model.Scruct4s.Length; i++)
{
var struct4 = new Struct4();
struct4.X = headerReader.ReadSingle();
struct4.Y = headerReader.ReadSingle();
struct4.Z = headerReader.ReadSingle();
model.Scruct4s[i] = struct4;
}
model.Scruct5s = new Struct5[numSomething5];
Console.WriteLine("Reading {0} Struct5(s)...", model.Scruct5s.Length);
for (int i = 0; i < model.Scruct5s.Length; i++)
{
var struct5 = new Struct5();
struct5.X = headerReader.ReadSingle();
struct5.Y = headerReader.ReadSingle();
struct5.Z = headerReader.ReadSingle();
model.Scruct5s[i] = struct5;
}
// there is only ever 1 of these it seems. ( in models, idk about skins yet )
// fishing skins use this more then once, gr8
model.Strides = new int[numStrides];
Console.WriteLine("Reading {0} Stride(s)...", model.Strides.Length);
for (int i = 0; i < model.Strides.Length; i++)
{
var sReader = new BinaryReader(new MemoryStream(headerReader.ReadBytes(136)));// 136
var count = sReader.ReadInt32();
var gay = sReader.ReadInt32();
Console.WriteLine("\tCount: {0}\tGay: {1}", count, gay);
var totalSize = 0;
for (int j = 0; j < count; j++)
{
var format = sReader.ReadInt32();
var stridesize = Util.StrideInBytesFromFormat(format);
// single byte strides are probably bone id
// also weight
Console.WriteLine("\t\t{2}: Format: {0}\tStrideS: {1}\tGay: {3}", format, stridesize, j, sReader.ReadInt32());
totalSize += stridesize;
}
model.Strides[i] = totalSize;
}
model.Verticies = new Vertex[model.Strides.Length][];
for (int i = 0; i < model.Strides.Length; i++)
{
model.Verticies[i] = new Vertex[numVertex];
Console.WriteLine("Reading {0} Vertex(s)...", model.Verticies[i].Length);
for (int j = 0; j < numVertex; j++)
{
byte[] buffer = new byte[Marshal.SizeOf(typeof(Vertex))];
reader.Read(buffer, 0, model.Strides[i]);
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Vertex vertex = (Vertex)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(Vertex));
handle.Free();
model.Verticies[i][j] = vertex;
}
}
model.Indices = new short[numIndices];
Console.WriteLine("Reading {0} Indice(s)...", model.Indices.Length);
for (int i = 0; i < model.Indices.Length; i++)
model.Indices[i] = reader.ReadInt16();
model.ModelCleave = new LHPoint[reader.ReadInt32()];
Console.WriteLine("Reading {0} Model Cleave Point(s)...", model.Indices.Length);
for (int i = 0; i < model.ModelCleave.Length; i++)
model.ModelCleave[i] = new LHPoint(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
Console.WriteLine("Remaining: {0}", reader.BaseStream.Length - reader.BaseStream.Position);
return model;
}
}
}