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,8 +8,7 @@
#include <fstream>
#include <algorithm>
Model parseMDL(MemorySpan data) {
struct ModelFileHeader {
struct ModelFileHeader {
uint32_t version;
uint32_t stackSize;
uint32_t runtimeSize;
@ -23,47 +22,38 @@ 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
};
struct VertexElement {
uint8_t stream, offset, type, usage, usageIndex;
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];
};
};
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
{
enum ModelFlags1 : uint8_t
{
DustOcclusionEnabled = 0x80,
SnowOcclusionEnabled = 0x40,
RainOcclusionEnabled = 0x20,
@ -72,10 +62,10 @@ Model parseMDL(MemorySpan data) {
WavingAnimationDisabled = 0x04,
LightShadowDisabled = 0x02,
ShadowDisabled = 0x01,
};
};
enum ModelFlags2 : uint8_t
{
enum ModelFlags2 : uint8_t
{
Unknown2 = 0x80,
BgUvScrollEnabled = 0x40,
EnableForceNonResident = 0x20,
@ -84,9 +74,9 @@ Model parseMDL(MemorySpan data) {
ForceLodRangeEnabled = 0x04,
EdgeGeometryEnabled = 0x02,
Unknown3 = 0x01
};
};
struct ModelHeader {
struct ModelHeader {
float radius;
unsigned short meshCount;
unsigned short attributeCount;
@ -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;
@ -162,14 +133,16 @@ Model parseMDL(MemorySpan data) {
unsigned int indexBufferSize;
unsigned int vertexDataOffset;
unsigned int indexDataOffset;
};
};
std::vector<Lod> lods;
struct ElementId {
uint32_t elementId;
uint32_t parentBoneName;
std::vector<float> translate;
std::vector<float> rotate;
};
// TODO: support models that support more than 3 lods
data.read_structures(&lods, 3);
struct Mesh {
struct Mesh {
unsigned short vertexCount;
unsigned short padding;
unsigned int indexCount;
@ -183,8 +156,76 @@ Model parseMDL(MemorySpan data) {
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) {
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;
}
}
}