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,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue