diff --git a/model_format_glb.c b/model_format_glb.c index 8c820f7..3e35700 100644 --- a/model_format_glb.c +++ b/model_format_glb.c @@ -27,7 +27,7 @@ static_assert( #define MAGIC 0x46546c67 // "glTF" #define VERSION 2 -#define MAX_KEY_SIZE 128 +#define MAX_STRING_SIZE 128 #define MAX_JOINT_COUNT 32 enum { @@ -39,6 +39,25 @@ enum { RENDERING_MODE_TRIANGLES = 4, }; +typedef enum { + COMPONENT_TYPE_S8 = 5120, // Byte + COMPONENT_TYPE_U8 = 5121, // Unsigned byte + COMPONENT_TYPE_S16 = 5122, // Short + COMPONENT_TYPE_U16 = 5123, // Unsigned short + COMPONENT_TYPE_U32 = 5125, // Unsigned int + COMPONENT_TYPE_F32 = 5126, // Float +} component_type_t; + +typedef enum { + ACCESSOR_TYPE_SCALAR, + ACCESSOR_TYPE_VEC2, + ACCESSOR_TYPE_VEC3, + ACCESSOR_TYPE_VEC4, + ACCESSOR_TYPE_MAT2, + ACCESSOR_TYPE_MAT3, + ACCESSOR_TYPE_MAT4, +} accessor_type_t; + typedef struct { uint32_t magic; uint32_t version; @@ -53,6 +72,8 @@ typedef struct { typedef struct { uint32_t normals; uint32_t positions; + uint32_t bones; + uint32_t weights; uint32_t indices; } mesh_t; @@ -120,17 +141,17 @@ static void *map_file(const char *path) return addr; } -static int read_key(const uint8_t **p, char buffer[MAX_KEY_SIZE]) +static void read_string(const uint8_t **p, char buffer[MAX_STRING_SIZE]) { assert(**p == '"'); ++(*p); size_t len = 0; while (**p != '"') { - assert(len < MAX_KEY_SIZE); + assert(len < MAX_STRING_SIZE - 1); buffer[len++] = *(*p)++; } ++(*p); - return len; + buffer[len] = '\0'; } static bool ends_value(uint8_t b) @@ -296,8 +317,7 @@ static vec4_t read_vec4(const uint8_t **p) static mesh_t read_mesh_primitives(const uint8_t **p) { - char buffer[MAX_KEY_SIZE]; - size_t len; + char buffer[MAX_STRING_SIZE]; mesh_t mesh = {}; assert(**p == '['); @@ -307,21 +327,21 @@ static mesh_t read_mesh_primitives(const uint8_t **p) ++(*p); while (**p != '}') { - len = read_key(p, buffer); + read_string(p, buffer); assert(**p == ':'); ++(*p); - if (memcmp("attributes", buffer, len) == 0) { + if (strcmp("attributes", buffer) == 0) { assert(**p == '{'); ++(*p); while (**p != '}') { - len = read_key(p, buffer); + read_string(p, buffer); assert(**p == ':'); ++(*p); - if (memcmp("NORMAL", buffer, len) == 0) { + if (strcmp("NORMAL", buffer) == 0) { mesh.normals = read_uint(p); - } else if (memcmp("POSITION", buffer, len) == 0) { + } else if (strcmp("POSITION", buffer) == 0) { mesh.positions = read_uint(p); } else { skip_value(p); @@ -330,9 +350,9 @@ static mesh_t read_mesh_primitives(const uint8_t **p) ++(*p); } ++(*p); - } else if (memcmp("indices", buffer, len) == 0) { + } else if (strcmp("indices", buffer) == 0) { mesh.indices = read_uint(p); - } else if (memcmp("mode", buffer, len) == 0) { + } else if (strcmp("mode", buffer) == 0) { assert(read_uint(p) == RENDERING_MODE_TRIANGLES); } else { skip_value(p); @@ -351,8 +371,7 @@ static mesh_t read_mesh_primitives(const uint8_t **p) static mesh_t read_meshes(const uint8_t *p) { - char buffer[MAX_KEY_SIZE]; - size_t len; + char buffer[MAX_STRING_SIZE]; assert(*p == '['); ++p; @@ -360,10 +379,10 @@ static mesh_t read_meshes(const uint8_t *p) ++p; while (*p != '}') { - len = read_key(&p, buffer); + read_string(&p, buffer); assert(*p == ':'); ++p; - if (memcmp("primitives", buffer, len) == 0) + if (strcmp("primitives", buffer) == 0) return read_mesh_primitives(&p); else skip_value(&p); @@ -371,18 +390,14 @@ static mesh_t read_meshes(const uint8_t *p) ++p; } - /* - * If we reach here, the primitives key was missing from the mesh - * definition. - */ + // Primitives key missing from mesh object assert(false); } static skin_t read_skins(const uint8_t *p) { skin_t skin = {}; - char buffer[MAX_KEY_SIZE]; - size_t len; + char buffer[MAX_STRING_SIZE]; assert(*p == '['); ++p; @@ -390,13 +405,13 @@ static skin_t read_skins(const uint8_t *p) ++p; while (*p != '}') { - len = read_key(&p, buffer); + read_string(&p, buffer); assert(*p == ':'); ++p; - if (memcmp("inverseBindMatrices", buffer, len) == 0) { + if (strcmp("inverseBindMatrices", buffer) == 0) { skin.inverse_bind_matrices = read_uint(&p); - } else if (memcmp("joints", buffer, len) == 0) { + } else if (strcmp("joints", buffer) == 0) { assert(*p == '['); ++p; for (skin.joint_count = 0; *p != ']'; ++skin.joint_count) { @@ -447,8 +462,7 @@ static void read_joint_children( static void read_joints(const uint8_t *p, skin_t skin, joint_t joints[MAX_JOINT_COUNT]) { - char buffer[MAX_KEY_SIZE]; - size_t len; + char buffer[MAX_STRING_SIZE]; for (uint32_t i = 0; i < skin.joint_count; ++i) joints[i].parent = UINT32_MAX; @@ -473,21 +487,20 @@ read_joints(const uint8_t *p, skin_t skin, joint_t joints[MAX_JOINT_COUNT]) ++p; while (*p != '}') { - len = read_key(&p, buffer); + read_string(&p, buffer); assert(*p == ':'); ++p; - if (memcmp("children", buffer, len) == 0) { + if (strcmp("children", buffer) == 0) read_joint_children(&p, skin, joints, j); - } else if (memcmp("translation", buffer, len) == 0) { + else if (strcmp("translation", buffer) == 0) joints[j].translation = read_vec3(&p); - } else if (memcmp("rotation", buffer, len) == 0) { + else if (strcmp("rotation", buffer) == 0) joints[j].rotation = read_vec4(&p); - } else if (memcmp("scale", buffer, len) == 0) { + else if (strcmp("scale", buffer) == 0) joints[j].scale = read_vec3(&p); - } else { + else skip_value(&p); - } if (*p == ',') ++p; @@ -499,27 +512,47 @@ read_joints(const uint8_t *p, skin_t skin, joint_t joints[MAX_JOINT_COUNT]) } } -static accessor_t read_accessor(const uint8_t **p) +static accessor_type_t read_accessor_type(const uint8_t **p) { - char buffer[MAX_KEY_SIZE]; - size_t len; + char buffer[MAX_STRING_SIZE]; + read_string(p, buffer); + if (strcmp("SCALAR", buffer) == 0) + return ACCESSOR_TYPE_SCALAR; + else if (strcmp("VEC3", buffer) == 0) + return ACCESSOR_TYPE_VEC3; + else if (strcmp("VEC4", buffer) == 0) + return ACCESSOR_TYPE_VEC4; + else if (strcmp("MAT4", buffer) == 0) + return ACCESSOR_TYPE_MAT4; + else + assert(false); +} + +static accessor_t read_accessor( + const uint8_t **p, component_type_t component_type, accessor_type_t type) +{ + char buffer[MAX_STRING_SIZE]; accessor_t accessor = {}; assert(**p == '{'); ++(*p); while (**p != '}') { - len = read_key(p, buffer); + read_string(p, buffer); assert(**p == ':'); ++(*p); - if (memcmp("bufferView", buffer, len) == 0) + if (strcmp("bufferView", buffer) == 0) accessor.view = read_uint(p); - else if (memcmp("byteOffset", buffer, len) == 0) + else if (strcmp("byteOffset", buffer) == 0) accessor.offset = read_uint(p); - else if (memcmp("count", buffer, len) == 0) + else if (strcmp("count", buffer) == 0) accessor.count = read_uint(p); - else if (memcmp("sparse", buffer, len) == 0) + else if (strcmp("componentType", buffer) == 0) + assert(read_uint(p) == component_type); + else if (strcmp("type", buffer) == 0) + assert(read_accessor_type(p) == type); + else if (strcmp("sparse", buffer) == 0) assert(false); // Sparse accessors are not supported else skip_value(p); @@ -538,14 +571,18 @@ static accessors_t read_accessors(const uint8_t *p, mesh_t mesh) assert(*p == '['); ++p; for (uint32_t i = 0; *p != ']'; ++i) { - if (i == mesh.normals) - accessors.normals = read_accessor(&p); - else if (i == mesh.positions) - accessors.positions = read_accessor(&p); - else if (i == mesh.indices) - accessors.indices = read_accessor(&p); - else + if (i == mesh.normals) { + accessors.normals + = read_accessor(&p, COMPONENT_TYPE_F32, ACCESSOR_TYPE_VEC3); + } else if (i == mesh.positions) { + accessors.positions + = read_accessor(&p, COMPONENT_TYPE_F32, ACCESSOR_TYPE_VEC3); + } else if (i == mesh.indices) { + accessors.indices = read_accessor( + &p, COMPONENT_TYPE_U16, ACCESSOR_TYPE_SCALAR); + } else { skip_value(&p); + } if (*p == ',') ++p; @@ -555,25 +592,24 @@ static accessors_t read_accessors(const uint8_t *p, mesh_t mesh) static view_t read_view(const uint8_t **p) { - char buffer[MAX_KEY_SIZE]; - size_t len; + char buffer[MAX_STRING_SIZE]; view_t view = {}; assert(**p == '{'); ++(*p); while (**p != '}') { - len = read_key(p, buffer); + read_string(p, buffer); assert(**p == ':'); ++(*p); - if (memcmp("buffer", buffer, len) == 0) + if (strcmp("buffer", buffer) == 0) assert(read_uint(p) == 0); - else if (memcmp("byteOffset", buffer, len) == 0) + else if (strcmp("byteOffset", buffer) == 0) view.offset = read_uint(p); - else if (memcmp("byteLength", buffer, len) == 0) + else if (strcmp("byteLength", buffer) == 0) view.len = read_uint(p); - else if (memcmp("byteStride", buffer, len) == 0) + else if (strcmp("byteStride", buffer) == 0) view.stride = read_uint(p); else skip_value(p); @@ -612,8 +648,7 @@ static views_t read_views(const uint8_t *p, accessors_t accessors) static gltf_info_t read_json(const uint8_t *json) { - char buffer[MAX_KEY_SIZE]; - size_t len; + char buffer[MAX_STRING_SIZE]; assert(*json == '{'); ++json; @@ -632,18 +667,18 @@ static gltf_info_t read_json(const uint8_t *json) const uint8_t *accessors_json = nullptr; const uint8_t *views_json = nullptr; while (*json != '}') { - len = read_key(&json, buffer); + read_string(&json, buffer); assert(*json == ':'); ++json; - if (memcmp("meshes", buffer, len) == 0) + if (strcmp("meshes", buffer) == 0) meshes_json = json; - else if (memcmp("skins", buffer, len) == 0) + else if (strcmp("skins", buffer) == 0) skins_json = json; - else if (memcmp("nodes", buffer, len) == 0) + else if (strcmp("nodes", buffer) == 0) nodes_json = json; - else if (memcmp("accessors", buffer, len) == 0) + else if (strcmp("accessors", buffer) == 0) accessors_json = json; - else if (memcmp("bufferViews", buffer, len) == 0) + else if (strcmp("bufferViews", buffer) == 0) views_json = json; skip_value(&json); if (*json == ',') @@ -663,17 +698,8 @@ static gltf_info_t read_json(const uint8_t *json) const accessors_t accessors = read_accessors(accessors_json, mesh); const views_t views = read_views(views_json, accessors); - if (accessors.positions.view == accessors.normals.view) { - assert(views.normals.stride == sizeof(vec3_t)); - } else { - const size_t normal_size - = views.normals.len / accessors.normals.count; - assert(normal_size == sizeof(vec3_t)); - const size_t position_size - = views.positions.len / accessors.positions.count; - assert(position_size == sizeof(vec3_t)); - } - assert(views.indices.len / accessors.indices.count == sizeof(index_t)); + // Assume indices are in their own buffer view + assert(views.indices.stride == 0); return (gltf_info_t) { .normals = {