#pragma once #include #include #include constexpr size_t ModelPathLen = 256; constexpr size_t ModelNameLen = 64; constexpr size_t ModelMaxObjects = 256; // uint8_t constexpr size_t ModelMaxMaterials = 256; // uint8_t constexpr size_t ModelMaxVerts = 4294967296; // uint32_t constexpr size_t ModelMaxFaces = 4294967296; // uint32_t typedef uint16_t mdIdx; typedef struct mdVert { mdIdx position, texcoord, normal; } mdVert; typedef struct mdTri { mdVert v0, v1, v2; } mdTri; typedef struct mdVec2 { float x, y; } mdVec2; typedef struct mdVec3 { float x, y, z; } mdVec3; typedef struct ModelObject { uint32_t offset; // FlatModel: offset into indices. IndexedModel: offset into tris. uint32_t count; // FloatModel: number of indices. IndexedModel: number of tris. uint8_t material; // Material index. uint8_t pad[3]; char name[ModelNameLen]; } ModelObject; typedef struct ModelMaterial { char name[ModelNameLen]; char diffuseTexture[ModelPathLen]; } ModelMaterial; // Every three indices form a triangle, and each index indexes all attribute // arrays simultaneously. This is best for a fast, linear-scan rendering. // This is what you would render with glDrawElements(). typedef struct FlatModel { // Counts. uint32_t numIdxs; uint32_t numVerts; // Offsets. uint32_t offsetIdxs; uint32_t offsetPositions; uint32_t offsetTexcoords; uint32_t offsetNormals; /* [objects] -- numObjects Object [materials] -- numMaterials Material [indices] -- numIdxs mdIdx [positions] -- numVerts mdVec3 [texcoords] -- numVerts mdVec2 [normals] -- numVerts mdVec3 */ uint8_t data[]; } FlatModel; // Every triangle is made up of three vertices, and each vertex holds one index // for each of the attribute arrays. This allows for a smaller representation of // some models by virtue of being able to re-use attributes across vertices. // This is the sort of format that OBJ follows, where the indices to each array // given by a face may be non-uniform. typedef struct IndexedModel { // Counts. uint32_t numTris; uint32_t numPositions; uint32_t numTexcoords; uint32_t numNormals; // Offsets. uint32_t offsetTris; uint32_t offsetPositions; uint32_t offsetTexcoords; uint32_t offsetNormals; /* [objects] -- numObjects Object [materials] -- numMaterials Material [triangles] -- numTris mdTri [positions] -- numPositions mdVec3 [texcoords] -- numTexcoords mdVec2 [normals] -- numNormals mdVec3 */ uint8_t data[]; } IndexedModel; typedef enum ModelType { ModelTypeFlat, ModelTypeIndexed } ModelType; typedef struct Model { uint32_t type; // Counts. uint8_t numObjects; uint8_t numMaterials; uint8_t pad[2]; // Offsets. uint32_t offsetObjects; uint32_t offsetMaterials; // Model details. union { FlatModel flat; IndexedModel indexed; }; } Model; static inline const ModelObject* modelObjects(const Model* model) { assert(model); switch (model->type) { case ModelTypeIndexed: return (const ModelObject*)(model->indexed.data + model->offsetObjects); case ModelTypeFlat: return (const ModelObject*)(model->flat.data + model->offsetObjects); default: assert(false); break; } } static inline const ModelMaterial* modelMaterials(const Model* model) { assert(model); switch (model->type) { case ModelTypeIndexed: return (const ModelMaterial*)(model->indexed.data + model->offsetMaterials); case ModelTypeFlat: return (const ModelMaterial*)(model->flat.data + model->offsetMaterials); default: assert(false); break; } }