Tidy up GLB loading a little
This commit is contained in:
1 parent
6454098c6a
commit
955f606fb5
1 file changed
+102
-76
+102
-76
@@ -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 = {
|
||||
|
||||
Reference in new issue
Block a user