Archived
1
Fork 0

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:
Joshua Goins 2022-04-17 20:00:12 -04:00
parent c78a1ab245
commit e53e1a0e6c

View file

@ -8,7 +8,6 @@
#include <fstream>
#include <algorithm>
Model parseMDL(MemorySpan data) {
struct ModelFileHeader {
uint32_t version;
uint32_t stackSize;
@ -23,45 +22,36 @@ Model parseMDL(MemorySpan data) {
bool indexBufferStreamingEnabled;
bool hasEdgeGeometry;
uint8_t padding;
} modelFileHeader;
};
data.read(&modelFileHeader);
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, type, usage, usageIndex;
uint8_t stream, offset;
VertexType type;
VertexUsage usage;
uint8_t usageIndex;
uint8_t padding[3];
};
struct VertexDeclaration {
std::vector<VertexElement> elements;
};
std::vector<VertexDeclaration> vertexDecls(modelFileHeader.vertexDeclarationCount);
for(int i = 0; i < modelFileHeader.vertexDeclarationCount; i++) {
VertexElement element {};
data.read(&element);
do {
vertexDecls[i].elements.push_back(element);
data.read(&element);
} while (element.stream != 255);
int toSeek = 17 * 8 - (vertexDecls[i].elements.size() + 1) * 8;
data.seek(toSeek, Seek::Current);
}
uint16_t stringCount;
data.read(&stringCount);
// dummy
data.seek(sizeof(uint16_t), Seek::Current);
uint32_t stringSize;
data.read(&stringSize);
std::vector<uint8_t> strings;
data.read_structures(&strings, stringSize);
enum ModelFlags1 : uint8_t
{
DustOcclusionEnabled = 0x80,
@ -118,28 +108,9 @@ Model parseMDL(MemorySpan data) {
uint8_t unknown6;
unsigned short unknown7, unknown8, unknown9;
uint8_t padding[6];
} 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);
for(int i = 0; i < modelHeader.elementIdCount; i++) {
data.read(&elementIds[i].elementId);
data.read(&elementIds[i].parentBoneName);
// FIXME: these always seem to be 3, convert to static array? then we could probably read this all in one go!
data.read_structures(&elementIds[i].translate, 3);
data.read_structures(&elementIds[i].rotate, 3);
}
struct Lod {
struct MeshLod {
unsigned short meshIndex;
unsigned short meshCount;
float modelLodRange;
@ -164,10 +135,12 @@ Model parseMDL(MemorySpan data) {
unsigned int indexDataOffset;
};
std::vector<Lod> lods;
// TODO: support models that support more than 3 lods
data.read_structures(&lods, 3);
struct ElementId {
uint32_t elementId;
uint32_t parentBoneName;
std::vector<float> translate;
std::vector<float> rotate;
};
struct Mesh {
unsigned short vertexCount;
@ -185,6 +158,74 @@ Model parseMDL(MemorySpan data) {
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) {
ModelFileHeader modelFileHeader;
data.read(&modelFileHeader);
struct VertexDeclaration {
std::vector<VertexElement> elements;
};
std::vector<VertexDeclaration> vertexDecls(modelFileHeader.vertexDeclarationCount);
for(int i = 0; i < modelFileHeader.vertexDeclarationCount; i++) {
VertexElement element {};
data.read(&element);
do {
vertexDecls[i].elements.push_back(element);
data.read(&element);
} while (element.stream != 255);
int toSeek = 17 * 8 - (vertexDecls[i].elements.size() + 1) * 8;
data.seek(toSeek, Seek::Current);
}
uint16_t stringCount;
data.read(&stringCount);
// dummy
data.seek(sizeof(uint16_t), Seek::Current);
uint32_t stringSize;
data.read(&stringSize);
std::vector<uint8_t> strings;
data.read_structures(&strings, stringSize);
ModelHeader modelHeader;
data.read(&modelHeader);
std::vector<ElementId> elementIds(modelHeader.elementIdCount);
for(int i = 0; i < modelHeader.elementIdCount; i++) {
data.read(&elementIds[i].elementId);
data.read(&elementIds[i].parentBoneName);
// FIXME: these always seem to be 3, convert to static array? then we could probably read this all in one go!
data.read_structures(&elementIds[i].translate, 3);
data.read_structures(&elementIds[i].rotate, 3);
}
std::vector<MeshLod> lods;
data.read_structures(&lods, modelHeader.lodCount);
std::vector<Mesh> meshes(modelHeader.meshCount);
for(int i = 0; i < modelHeader.meshCount; i++) {
data.read(&meshes[i].vertexCount);
@ -207,14 +248,6 @@ Model parseMDL(MemorySpan data) {
// 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;
data.read_structures(&submeshes, modelHeader.submeshCount);
@ -226,12 +259,6 @@ Model parseMDL(MemorySpan data) {
std::vector<uint32_t> boneNameOffsets;
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);
for(int i = 0; i < modelHeader.boneTableCount; i++) {
data.read_structures(&boneTables[i].boneIndex, 64);
@ -254,10 +281,6 @@ Model parseMDL(MemorySpan data) {
data.seek(paddingAmount, Seek::Current);
struct BoundingBox {
std::array<float, 4> min, max;
};
BoundingBox boundingBoxes, modelBoundingBoxes, waterBoundingBoxes, verticalFogBoundingBoxes;
data.read(&boundingBoxes);
data.read(&modelBoundingBoxes);
@ -270,48 +293,22 @@ Model parseMDL(MemorySpan data) {
Model model;
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++) {
Part part;
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;
std::vector<Vertex> vertices(vertexCount);
for(int k = 0; k < vertexCount; k++) {
for(auto& orderedElement : decl.elements) {
auto type = static_cast<VertexType>(orderedElement.type);
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);
for(auto& element : decl.elements) {
data.seek(lods[i].vertexDataOffset + meshes[j].vertexBufferOffset[element.stream] + element.offset + meshes[i].vertexBufferStride[element.stream] * k, Seek::Set);
std::array<float, 4> floatData = {};
switch(type) {
switch(element.type) {
case VertexType::Single3:
data.read_array(floatData.data(), 3);
break;
@ -351,13 +348,25 @@ Model parseMDL(MemorySpan data) {
break;
}
switch(usage) {
switch(element.usage) {
case VertexUsage::Position:
memcpy(vertices[k].position.data(), floatData.data(), sizeof(float) * 3);
break;
case VertexUsage::Normal:
memcpy(vertices[k].normal.data(), floatData.data(), sizeof(float) * 3);
break;
case BlendWeights:
break;
case BlendIndices:
break;
case UV:
break;
case Tangent2:
break;
case Tangent1:
break;
case Color:
break;
}
}
}