Clean up mdl parser
Now all the structs live at the top of the file, and the main vertex element reading loop is much nicer looking.
This commit is contained in:
parent
c78a1ab245
commit
e53e1a0e6c
1 changed files with 189 additions and 180 deletions
|
@ -8,30 +8,178 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
struct ModelFileHeader {
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t stackSize;
|
||||||
|
uint32_t runtimeSize;
|
||||||
|
unsigned short vertexDeclarationCount;
|
||||||
|
unsigned short materialCount;
|
||||||
|
uint32_t vertexOffsets[3];
|
||||||
|
uint32_t indexOffsets[3];
|
||||||
|
uint32_t vertexBufferSize[3];
|
||||||
|
uint32_t indexBufferSize[3];
|
||||||
|
uint8_t lodCount;
|
||||||
|
bool indexBufferStreamingEnabled;
|
||||||
|
bool hasEdgeGeometry;
|
||||||
|
uint8_t padding;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum VertexType : uint8_t {
|
||||||
|
Single3 = 2,
|
||||||
|
Single4 = 3,
|
||||||
|
UInt = 5,
|
||||||
|
ByteFloat4 = 8,
|
||||||
|
Half2 = 13,
|
||||||
|
Half4 = 14
|
||||||
|
};
|
||||||
|
|
||||||
|
enum VertexUsage : uint8_t {
|
||||||
|
Position = 0,
|
||||||
|
BlendWeights = 1,
|
||||||
|
BlendIndices = 2,
|
||||||
|
Normal = 3,
|
||||||
|
UV = 4,
|
||||||
|
Tangent2 = 5,
|
||||||
|
Tangent1 = 6,
|
||||||
|
Color = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexElement {
|
||||||
|
uint8_t stream, offset;
|
||||||
|
VertexType type;
|
||||||
|
VertexUsage usage;
|
||||||
|
uint8_t usageIndex;
|
||||||
|
uint8_t padding[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ModelFlags1 : uint8_t
|
||||||
|
{
|
||||||
|
DustOcclusionEnabled = 0x80,
|
||||||
|
SnowOcclusionEnabled = 0x40,
|
||||||
|
RainOcclusionEnabled = 0x20,
|
||||||
|
Unknown1 = 0x10,
|
||||||
|
LightingReflectionEnabled = 0x08,
|
||||||
|
WavingAnimationDisabled = 0x04,
|
||||||
|
LightShadowDisabled = 0x02,
|
||||||
|
ShadowDisabled = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ModelFlags2 : uint8_t
|
||||||
|
{
|
||||||
|
Unknown2 = 0x80,
|
||||||
|
BgUvScrollEnabled = 0x40,
|
||||||
|
EnableForceNonResident = 0x20,
|
||||||
|
ExtraLodEnabled = 0x10,
|
||||||
|
ShadowMaskEnabled = 0x08,
|
||||||
|
ForceLodRangeEnabled = 0x04,
|
||||||
|
EdgeGeometryEnabled = 0x02,
|
||||||
|
Unknown3 = 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ModelHeader {
|
||||||
|
float radius;
|
||||||
|
unsigned short meshCount;
|
||||||
|
unsigned short attributeCount;
|
||||||
|
unsigned short submeshCount;
|
||||||
|
unsigned short materialCount;
|
||||||
|
unsigned short boneCount;
|
||||||
|
unsigned short boneTableCount;
|
||||||
|
unsigned short shapeCount;
|
||||||
|
unsigned short shapeMeshCount;
|
||||||
|
unsigned short shapeValueCount;
|
||||||
|
uint8_t lodCount;
|
||||||
|
|
||||||
|
ModelFlags1 flags1;
|
||||||
|
|
||||||
|
unsigned short elementIdCount;
|
||||||
|
uint8_t terrainShadowMeshCount;
|
||||||
|
|
||||||
|
ModelFlags2 flags2;
|
||||||
|
|
||||||
|
float modelClipOutDistance;
|
||||||
|
float shadowClipOutDistance;
|
||||||
|
unsigned short unknown4;
|
||||||
|
unsigned short terrainShadowSubmeshCount;
|
||||||
|
|
||||||
|
uint8_t unknown5;
|
||||||
|
|
||||||
|
uint8_t bgChangeMaterialIndex;
|
||||||
|
uint8_t bgCrestChangeMaterialIndex;
|
||||||
|
uint8_t unknown6;
|
||||||
|
unsigned short unknown7, unknown8, unknown9;
|
||||||
|
uint8_t padding[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshLod {
|
||||||
|
unsigned short meshIndex;
|
||||||
|
unsigned short meshCount;
|
||||||
|
float modelLodRange;
|
||||||
|
float textureLodRange;
|
||||||
|
unsigned short waterMeshIndex;
|
||||||
|
unsigned short waterMeshCount;
|
||||||
|
unsigned short shadowMeshIndex;
|
||||||
|
unsigned short shadowMeshCount;
|
||||||
|
unsigned short terrainShadowMeshIndex;
|
||||||
|
unsigned short terrainShadowMeshCount;
|
||||||
|
unsigned short verticalFogMeshIndex;
|
||||||
|
unsigned short verticalFogMeshCount;
|
||||||
|
|
||||||
|
// unused on win32 according to lumina devs
|
||||||
|
unsigned int edgeGeometrySize;
|
||||||
|
unsigned int edgeGeometryDataOffset;
|
||||||
|
unsigned int polygonCount;
|
||||||
|
unsigned int unknown1;
|
||||||
|
unsigned int vertexBufferSize;
|
||||||
|
unsigned int indexBufferSize;
|
||||||
|
unsigned int vertexDataOffset;
|
||||||
|
unsigned int indexDataOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ElementId {
|
||||||
|
uint32_t elementId;
|
||||||
|
uint32_t parentBoneName;
|
||||||
|
std::vector<float> translate;
|
||||||
|
std::vector<float> rotate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Mesh {
|
||||||
|
unsigned short vertexCount;
|
||||||
|
unsigned short padding;
|
||||||
|
unsigned int indexCount;
|
||||||
|
unsigned short materialIndex;
|
||||||
|
unsigned short subMeshIndex;
|
||||||
|
unsigned short subMeshCount;
|
||||||
|
unsigned short boneTableIndex;
|
||||||
|
unsigned int startIndex;
|
||||||
|
|
||||||
|
std::vector<uint32_t> vertexBufferOffset;
|
||||||
|
std::vector<uint8_t> vertexBufferStride;
|
||||||
|
|
||||||
|
uint8_t vertexStreamCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Submesh {
|
||||||
|
unsigned int indexOffset;
|
||||||
|
unsigned int indexCount;
|
||||||
|
unsigned int attributeIndexMask;
|
||||||
|
unsigned short boneStartIndex;
|
||||||
|
unsigned short boneCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoneTable {
|
||||||
|
std::vector<uint16_t> boneIndex;
|
||||||
|
uint8_t boneCount;
|
||||||
|
std::vector<uint8_t> padding;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoundingBox {
|
||||||
|
std::array<float, 4> min, max;
|
||||||
|
};
|
||||||
|
|
||||||
Model parseMDL(MemorySpan data) {
|
Model parseMDL(MemorySpan data) {
|
||||||
struct ModelFileHeader {
|
ModelFileHeader modelFileHeader;
|
||||||
uint32_t version;
|
|
||||||
uint32_t stackSize;
|
|
||||||
uint32_t runtimeSize;
|
|
||||||
unsigned short vertexDeclarationCount;
|
|
||||||
unsigned short materialCount;
|
|
||||||
uint32_t vertexOffsets[3];
|
|
||||||
uint32_t indexOffsets[3];
|
|
||||||
uint32_t vertexBufferSize[3];
|
|
||||||
uint32_t indexBufferSize[3];
|
|
||||||
uint8_t lodCount;
|
|
||||||
bool indexBufferStreamingEnabled;
|
|
||||||
bool hasEdgeGeometry;
|
|
||||||
uint8_t padding;
|
|
||||||
} modelFileHeader;
|
|
||||||
|
|
||||||
data.read(&modelFileHeader);
|
data.read(&modelFileHeader);
|
||||||
|
|
||||||
struct VertexElement {
|
|
||||||
uint8_t stream, offset, type, usage, usageIndex;
|
|
||||||
uint8_t padding[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VertexDeclaration {
|
struct VertexDeclaration {
|
||||||
std::vector<VertexElement> elements;
|
std::vector<VertexElement> elements;
|
||||||
};
|
};
|
||||||
|
@ -62,73 +210,9 @@ Model parseMDL(MemorySpan data) {
|
||||||
std::vector<uint8_t> strings;
|
std::vector<uint8_t> strings;
|
||||||
data.read_structures(&strings, stringSize);
|
data.read_structures(&strings, stringSize);
|
||||||
|
|
||||||
enum ModelFlags1 : uint8_t
|
ModelHeader modelHeader;
|
||||||
{
|
|
||||||
DustOcclusionEnabled = 0x80,
|
|
||||||
SnowOcclusionEnabled = 0x40,
|
|
||||||
RainOcclusionEnabled = 0x20,
|
|
||||||
Unknown1 = 0x10,
|
|
||||||
LightingReflectionEnabled = 0x08,
|
|
||||||
WavingAnimationDisabled = 0x04,
|
|
||||||
LightShadowDisabled = 0x02,
|
|
||||||
ShadowDisabled = 0x01,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ModelFlags2 : uint8_t
|
|
||||||
{
|
|
||||||
Unknown2 = 0x80,
|
|
||||||
BgUvScrollEnabled = 0x40,
|
|
||||||
EnableForceNonResident = 0x20,
|
|
||||||
ExtraLodEnabled = 0x10,
|
|
||||||
ShadowMaskEnabled = 0x08,
|
|
||||||
ForceLodRangeEnabled = 0x04,
|
|
||||||
EdgeGeometryEnabled = 0x02,
|
|
||||||
Unknown3 = 0x01
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ModelHeader {
|
|
||||||
float radius;
|
|
||||||
unsigned short meshCount;
|
|
||||||
unsigned short attributeCount;
|
|
||||||
unsigned short submeshCount;
|
|
||||||
unsigned short materialCount;
|
|
||||||
unsigned short boneCount;
|
|
||||||
unsigned short boneTableCount;
|
|
||||||
unsigned short shapeCount;
|
|
||||||
unsigned short shapeMeshCount;
|
|
||||||
unsigned short shapeValueCount;
|
|
||||||
uint8_t lodCount;
|
|
||||||
|
|
||||||
ModelFlags1 flags1;
|
|
||||||
|
|
||||||
unsigned short elementIdCount;
|
|
||||||
uint8_t terrainShadowMeshCount;
|
|
||||||
|
|
||||||
ModelFlags2 flags2;
|
|
||||||
|
|
||||||
float modelClipOutDistance;
|
|
||||||
float shadowClipOutDistance;
|
|
||||||
unsigned short unknown4;
|
|
||||||
unsigned short terrainShadowSubmeshCount;
|
|
||||||
|
|
||||||
uint8_t unknown5;
|
|
||||||
|
|
||||||
uint8_t bgChangeMaterialIndex;
|
|
||||||
uint8_t bgCrestChangeMaterialIndex;
|
|
||||||
uint8_t unknown6;
|
|
||||||
unsigned short unknown7, unknown8, unknown9;
|
|
||||||
uint8_t padding[6];
|
|
||||||
} modelHeader;
|
|
||||||
|
|
||||||
data.read(&modelHeader);
|
data.read(&modelHeader);
|
||||||
|
|
||||||
struct ElementId {
|
|
||||||
uint32_t elementId;
|
|
||||||
uint32_t parentBoneName;
|
|
||||||
std::vector<float> translate;
|
|
||||||
std::vector<float> rotate;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<ElementId> elementIds(modelHeader.elementIdCount);
|
std::vector<ElementId> elementIds(modelHeader.elementIdCount);
|
||||||
for(int i = 0; i < modelHeader.elementIdCount; i++) {
|
for(int i = 0; i < modelHeader.elementIdCount; i++) {
|
||||||
data.read(&elementIds[i].elementId);
|
data.read(&elementIds[i].elementId);
|
||||||
|
@ -139,51 +223,8 @@ Model parseMDL(MemorySpan data) {
|
||||||
data.read_structures(&elementIds[i].rotate, 3);
|
data.read_structures(&elementIds[i].rotate, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Lod {
|
std::vector<MeshLod> lods;
|
||||||
unsigned short meshIndex;
|
data.read_structures(&lods, modelHeader.lodCount);
|
||||||
unsigned short meshCount;
|
|
||||||
float modelLodRange;
|
|
||||||
float textureLodRange;
|
|
||||||
unsigned short waterMeshIndex;
|
|
||||||
unsigned short waterMeshCount;
|
|
||||||
unsigned short shadowMeshIndex;
|
|
||||||
unsigned short shadowMeshCount;
|
|
||||||
unsigned short terrainShadowMeshIndex;
|
|
||||||
unsigned short terrainShadowMeshCount;
|
|
||||||
unsigned short verticalFogMeshIndex;
|
|
||||||
unsigned short verticalFogMeshCount;
|
|
||||||
|
|
||||||
// unused on win32 according to lumina devs
|
|
||||||
unsigned int edgeGeometrySize;
|
|
||||||
unsigned int edgeGeometryDataOffset;
|
|
||||||
unsigned int polygonCount;
|
|
||||||
unsigned int unknown1;
|
|
||||||
unsigned int vertexBufferSize;
|
|
||||||
unsigned int indexBufferSize;
|
|
||||||
unsigned int vertexDataOffset;
|
|
||||||
unsigned int indexDataOffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Lod> lods;
|
|
||||||
|
|
||||||
// TODO: support models that support more than 3 lods
|
|
||||||
data.read_structures(&lods, 3);
|
|
||||||
|
|
||||||
struct Mesh {
|
|
||||||
unsigned short vertexCount;
|
|
||||||
unsigned short padding;
|
|
||||||
unsigned int indexCount;
|
|
||||||
unsigned short materialIndex;
|
|
||||||
unsigned short subMeshIndex;
|
|
||||||
unsigned short subMeshCount;
|
|
||||||
unsigned short boneTableIndex;
|
|
||||||
unsigned int startIndex;
|
|
||||||
|
|
||||||
std::vector<uint32_t> vertexBufferOffset;
|
|
||||||
std::vector<uint8_t> vertexBufferStride;
|
|
||||||
|
|
||||||
uint8_t vertexStreamCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Mesh> meshes(modelHeader.meshCount);
|
std::vector<Mesh> meshes(modelHeader.meshCount);
|
||||||
for(int i = 0; i < modelHeader.meshCount; i++) {
|
for(int i = 0; i < modelHeader.meshCount; i++) {
|
||||||
|
@ -207,14 +248,6 @@ Model parseMDL(MemorySpan data) {
|
||||||
|
|
||||||
// TODO: implement terrain shadow meshes
|
// TODO: implement terrain shadow meshes
|
||||||
|
|
||||||
struct Submesh {
|
|
||||||
unsigned int indexOffset;
|
|
||||||
unsigned int indexCount;
|
|
||||||
unsigned int attributeIndexMask;
|
|
||||||
unsigned short boneStartIndex;
|
|
||||||
unsigned short boneCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Submesh> submeshes;
|
std::vector<Submesh> submeshes;
|
||||||
data.read_structures(&submeshes, modelHeader.submeshCount);
|
data.read_structures(&submeshes, modelHeader.submeshCount);
|
||||||
|
|
||||||
|
@ -226,12 +259,6 @@ Model parseMDL(MemorySpan data) {
|
||||||
std::vector<uint32_t> boneNameOffsets;
|
std::vector<uint32_t> boneNameOffsets;
|
||||||
data.read_structures(&boneNameOffsets, modelHeader.boneCount);
|
data.read_structures(&boneNameOffsets, modelHeader.boneCount);
|
||||||
|
|
||||||
struct BoneTable {
|
|
||||||
std::vector<uint16_t> boneIndex;
|
|
||||||
uint8_t boneCount;
|
|
||||||
std::vector<uint8_t> padding;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<BoneTable> boneTables(modelHeader.boneTableCount);
|
std::vector<BoneTable> boneTables(modelHeader.boneTableCount);
|
||||||
for(int i = 0; i < modelHeader.boneTableCount; i++) {
|
for(int i = 0; i < modelHeader.boneTableCount; i++) {
|
||||||
data.read_structures(&boneTables[i].boneIndex, 64);
|
data.read_structures(&boneTables[i].boneIndex, 64);
|
||||||
|
@ -254,10 +281,6 @@ Model parseMDL(MemorySpan data) {
|
||||||
|
|
||||||
data.seek(paddingAmount, Seek::Current);
|
data.seek(paddingAmount, Seek::Current);
|
||||||
|
|
||||||
struct BoundingBox {
|
|
||||||
std::array<float, 4> min, max;
|
|
||||||
};
|
|
||||||
|
|
||||||
BoundingBox boundingBoxes, modelBoundingBoxes, waterBoundingBoxes, verticalFogBoundingBoxes;
|
BoundingBox boundingBoxes, modelBoundingBoxes, waterBoundingBoxes, verticalFogBoundingBoxes;
|
||||||
data.read(&boundingBoxes);
|
data.read(&boundingBoxes);
|
||||||
data.read(&modelBoundingBoxes);
|
data.read(&modelBoundingBoxes);
|
||||||
|
@ -270,48 +293,22 @@ Model parseMDL(MemorySpan data) {
|
||||||
Model model;
|
Model model;
|
||||||
|
|
||||||
for(int i = 0; i < modelHeader.lodCount; i++) {
|
for(int i = 0; i < modelHeader.lodCount; i++) {
|
||||||
::Lod lod;
|
Lod lod;
|
||||||
|
|
||||||
for(int j = lods[i].meshIndex; j < (lods[i].meshIndex + lods[i].meshCount); j++) {
|
for(int j = lods[i].meshIndex; j < (lods[i].meshIndex + lods[i].meshCount); j++) {
|
||||||
Part part;
|
Part part;
|
||||||
|
|
||||||
const VertexDeclaration decl = vertexDecls[j];
|
const VertexDeclaration decl = vertexDecls[j];
|
||||||
|
|
||||||
enum VertexType : uint8_t {
|
|
||||||
Single3 = 2,
|
|
||||||
Single4 = 3,
|
|
||||||
UInt = 5,
|
|
||||||
ByteFloat4 = 8,
|
|
||||||
Half2 = 13,
|
|
||||||
Half4 = 14
|
|
||||||
};
|
|
||||||
|
|
||||||
enum VertexUsage : uint8_t {
|
|
||||||
Position = 0,
|
|
||||||
BlendWeights = 1,
|
|
||||||
BlendIndices = 2,
|
|
||||||
Normal = 3,
|
|
||||||
UV = 4,
|
|
||||||
Tangent2 = 5,
|
|
||||||
Tangent1 = 6,
|
|
||||||
Color = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
int vertexCount = meshes[j].vertexCount;
|
int vertexCount = meshes[j].vertexCount;
|
||||||
std::vector<Vertex> vertices(vertexCount);
|
std::vector<Vertex> vertices(vertexCount);
|
||||||
|
|
||||||
for(int k = 0; k < vertexCount; k++) {
|
for(int k = 0; k < vertexCount; k++) {
|
||||||
for(auto& orderedElement : decl.elements) {
|
for(auto& element : decl.elements) {
|
||||||
auto type = static_cast<VertexType>(orderedElement.type);
|
data.seek(lods[i].vertexDataOffset + meshes[j].vertexBufferOffset[element.stream] + element.offset + meshes[i].vertexBufferStride[element.stream] * k, Seek::Set);
|
||||||
auto usage = static_cast<VertexUsage>(orderedElement.usage);
|
|
||||||
|
|
||||||
const int stream = orderedElement.stream;
|
|
||||||
|
|
||||||
data.seek(lods[i].vertexDataOffset + meshes[j].vertexBufferOffset[stream] + orderedElement.offset + meshes[i].vertexBufferStride[stream] * k, Seek::Set);
|
|
||||||
|
|
||||||
std::array<float, 4> floatData = {};
|
std::array<float, 4> floatData = {};
|
||||||
|
switch(element.type) {
|
||||||
switch(type) {
|
|
||||||
case VertexType::Single3:
|
case VertexType::Single3:
|
||||||
data.read_array(floatData.data(), 3);
|
data.read_array(floatData.data(), 3);
|
||||||
break;
|
break;
|
||||||
|
@ -351,13 +348,25 @@ Model parseMDL(MemorySpan data) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(usage) {
|
switch(element.usage) {
|
||||||
case VertexUsage::Position:
|
case VertexUsage::Position:
|
||||||
memcpy(vertices[k].position.data(), floatData.data(), sizeof(float) * 3);
|
memcpy(vertices[k].position.data(), floatData.data(), sizeof(float) * 3);
|
||||||
break;
|
break;
|
||||||
case VertexUsage::Normal:
|
case VertexUsage::Normal:
|
||||||
memcpy(vertices[k].normal.data(), floatData.data(), sizeof(float) * 3);
|
memcpy(vertices[k].normal.data(), floatData.data(), sizeof(float) * 3);
|
||||||
break;
|
break;
|
||||||
|
case BlendWeights:
|
||||||
|
break;
|
||||||
|
case BlendIndices:
|
||||||
|
break;
|
||||||
|
case UV:
|
||||||
|
break;
|
||||||
|
case Tangent2:
|
||||||
|
break;
|
||||||
|
case Tangent1:
|
||||||
|
break;
|
||||||
|
case Color:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue