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 MAGIC 0x46546c67 // "glTF"
|
||||||
#define VERSION 2
|
#define VERSION 2
|
||||||
|
|
||||||
#define MAX_KEY_SIZE 128
|
#define MAX_STRING_SIZE 128
|
||||||
#define MAX_JOINT_COUNT 32
|
#define MAX_JOINT_COUNT 32
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -39,6 +39,25 @@ enum {
|
|||||||
RENDERING_MODE_TRIANGLES = 4,
|
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 {
|
typedef struct {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
@@ -53,6 +72,8 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t normals;
|
uint32_t normals;
|
||||||
uint32_t positions;
|
uint32_t positions;
|
||||||
|
uint32_t bones;
|
||||||
|
uint32_t weights;
|
||||||
uint32_t indices;
|
uint32_t indices;
|
||||||
} mesh_t;
|
} mesh_t;
|
||||||
|
|
||||||
@@ -120,17 +141,17 @@ static void *map_file(const char *path)
|
|||||||
return addr;
|
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 == '"');
|
assert(**p == '"');
|
||||||
++(*p);
|
++(*p);
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (**p != '"') {
|
while (**p != '"') {
|
||||||
assert(len < MAX_KEY_SIZE);
|
assert(len < MAX_STRING_SIZE - 1);
|
||||||
buffer[len++] = *(*p)++;
|
buffer[len++] = *(*p)++;
|
||||||
}
|
}
|
||||||
++(*p);
|
++(*p);
|
||||||
return len;
|
buffer[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ends_value(uint8_t b)
|
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)
|
static mesh_t read_mesh_primitives(const uint8_t **p)
|
||||||
{
|
{
|
||||||
char buffer[MAX_KEY_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
size_t len;
|
|
||||||
mesh_t mesh = {};
|
mesh_t mesh = {};
|
||||||
|
|
||||||
assert(**p == '[');
|
assert(**p == '[');
|
||||||
@@ -307,21 +327,21 @@ static mesh_t read_mesh_primitives(const uint8_t **p)
|
|||||||
++(*p);
|
++(*p);
|
||||||
|
|
||||||
while (**p != '}') {
|
while (**p != '}') {
|
||||||
len = read_key(p, buffer);
|
read_string(p, buffer);
|
||||||
assert(**p == ':');
|
assert(**p == ':');
|
||||||
++(*p);
|
++(*p);
|
||||||
|
|
||||||
if (memcmp("attributes", buffer, len) == 0) {
|
if (strcmp("attributes", buffer) == 0) {
|
||||||
assert(**p == '{');
|
assert(**p == '{');
|
||||||
++(*p);
|
++(*p);
|
||||||
|
|
||||||
while (**p != '}') {
|
while (**p != '}') {
|
||||||
len = read_key(p, buffer);
|
read_string(p, buffer);
|
||||||
assert(**p == ':');
|
assert(**p == ':');
|
||||||
++(*p);
|
++(*p);
|
||||||
if (memcmp("NORMAL", buffer, len) == 0) {
|
if (strcmp("NORMAL", buffer) == 0) {
|
||||||
mesh.normals = read_uint(p);
|
mesh.normals = read_uint(p);
|
||||||
} else if (memcmp("POSITION", buffer, len) == 0) {
|
} else if (strcmp("POSITION", buffer) == 0) {
|
||||||
mesh.positions = read_uint(p);
|
mesh.positions = read_uint(p);
|
||||||
} else {
|
} else {
|
||||||
skip_value(p);
|
skip_value(p);
|
||||||
@@ -330,9 +350,9 @@ static mesh_t read_mesh_primitives(const uint8_t **p)
|
|||||||
++(*p);
|
++(*p);
|
||||||
}
|
}
|
||||||
++(*p);
|
++(*p);
|
||||||
} else if (memcmp("indices", buffer, len) == 0) {
|
} else if (strcmp("indices", buffer) == 0) {
|
||||||
mesh.indices = read_uint(p);
|
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);
|
assert(read_uint(p) == RENDERING_MODE_TRIANGLES);
|
||||||
} else {
|
} else {
|
||||||
skip_value(p);
|
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)
|
static mesh_t read_meshes(const uint8_t *p)
|
||||||
{
|
{
|
||||||
char buffer[MAX_KEY_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
size_t len;
|
|
||||||
|
|
||||||
assert(*p == '[');
|
assert(*p == '[');
|
||||||
++p;
|
++p;
|
||||||
@@ -360,10 +379,10 @@ static mesh_t read_meshes(const uint8_t *p)
|
|||||||
++p;
|
++p;
|
||||||
|
|
||||||
while (*p != '}') {
|
while (*p != '}') {
|
||||||
len = read_key(&p, buffer);
|
read_string(&p, buffer);
|
||||||
assert(*p == ':');
|
assert(*p == ':');
|
||||||
++p;
|
++p;
|
||||||
if (memcmp("primitives", buffer, len) == 0)
|
if (strcmp("primitives", buffer) == 0)
|
||||||
return read_mesh_primitives(&p);
|
return read_mesh_primitives(&p);
|
||||||
else
|
else
|
||||||
skip_value(&p);
|
skip_value(&p);
|
||||||
@@ -371,18 +390,14 @@ static mesh_t read_meshes(const uint8_t *p)
|
|||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Primitives key missing from mesh object
|
||||||
* If we reach here, the primitives key was missing from the mesh
|
|
||||||
* definition.
|
|
||||||
*/
|
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static skin_t read_skins(const uint8_t *p)
|
static skin_t read_skins(const uint8_t *p)
|
||||||
{
|
{
|
||||||
skin_t skin = {};
|
skin_t skin = {};
|
||||||
char buffer[MAX_KEY_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
size_t len;
|
|
||||||
|
|
||||||
assert(*p == '[');
|
assert(*p == '[');
|
||||||
++p;
|
++p;
|
||||||
@@ -390,13 +405,13 @@ static skin_t read_skins(const uint8_t *p)
|
|||||||
++p;
|
++p;
|
||||||
|
|
||||||
while (*p != '}') {
|
while (*p != '}') {
|
||||||
len = read_key(&p, buffer);
|
read_string(&p, buffer);
|
||||||
assert(*p == ':');
|
assert(*p == ':');
|
||||||
++p;
|
++p;
|
||||||
|
|
||||||
if (memcmp("inverseBindMatrices", buffer, len) == 0) {
|
if (strcmp("inverseBindMatrices", buffer) == 0) {
|
||||||
skin.inverse_bind_matrices = read_uint(&p);
|
skin.inverse_bind_matrices = read_uint(&p);
|
||||||
} else if (memcmp("joints", buffer, len) == 0) {
|
} else if (strcmp("joints", buffer) == 0) {
|
||||||
assert(*p == '[');
|
assert(*p == '[');
|
||||||
++p;
|
++p;
|
||||||
for (skin.joint_count = 0; *p != ']'; ++skin.joint_count) {
|
for (skin.joint_count = 0; *p != ']'; ++skin.joint_count) {
|
||||||
@@ -447,8 +462,7 @@ static void read_joint_children(
|
|||||||
static void
|
static void
|
||||||
read_joints(const uint8_t *p, skin_t skin, joint_t joints[MAX_JOINT_COUNT])
|
read_joints(const uint8_t *p, skin_t skin, joint_t joints[MAX_JOINT_COUNT])
|
||||||
{
|
{
|
||||||
char buffer[MAX_KEY_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
size_t len;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < skin.joint_count; ++i)
|
for (uint32_t i = 0; i < skin.joint_count; ++i)
|
||||||
joints[i].parent = UINT32_MAX;
|
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;
|
++p;
|
||||||
|
|
||||||
while (*p != '}') {
|
while (*p != '}') {
|
||||||
len = read_key(&p, buffer);
|
read_string(&p, buffer);
|
||||||
assert(*p == ':');
|
assert(*p == ':');
|
||||||
++p;
|
++p;
|
||||||
|
|
||||||
if (memcmp("children", buffer, len) == 0) {
|
if (strcmp("children", buffer) == 0)
|
||||||
read_joint_children(&p, skin, joints, j);
|
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);
|
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);
|
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);
|
joints[j].scale = read_vec3(&p);
|
||||||
} else {
|
else
|
||||||
skip_value(&p);
|
skip_value(&p);
|
||||||
}
|
|
||||||
|
|
||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
++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];
|
char buffer[MAX_STRING_SIZE];
|
||||||
size_t len;
|
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 = {};
|
accessor_t accessor = {};
|
||||||
|
|
||||||
assert(**p == '{');
|
assert(**p == '{');
|
||||||
++(*p);
|
++(*p);
|
||||||
|
|
||||||
while (**p != '}') {
|
while (**p != '}') {
|
||||||
len = read_key(p, buffer);
|
read_string(p, buffer);
|
||||||
assert(**p == ':');
|
assert(**p == ':');
|
||||||
++(*p);
|
++(*p);
|
||||||
|
|
||||||
if (memcmp("bufferView", buffer, len) == 0)
|
if (strcmp("bufferView", buffer) == 0)
|
||||||
accessor.view = read_uint(p);
|
accessor.view = read_uint(p);
|
||||||
else if (memcmp("byteOffset", buffer, len) == 0)
|
else if (strcmp("byteOffset", buffer) == 0)
|
||||||
accessor.offset = read_uint(p);
|
accessor.offset = read_uint(p);
|
||||||
else if (memcmp("count", buffer, len) == 0)
|
else if (strcmp("count", buffer) == 0)
|
||||||
accessor.count = read_uint(p);
|
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
|
assert(false); // Sparse accessors are not supported
|
||||||
else
|
else
|
||||||
skip_value(p);
|
skip_value(p);
|
||||||
@@ -538,14 +571,18 @@ static accessors_t read_accessors(const uint8_t *p, mesh_t mesh)
|
|||||||
assert(*p == '[');
|
assert(*p == '[');
|
||||||
++p;
|
++p;
|
||||||
for (uint32_t i = 0; *p != ']'; ++i) {
|
for (uint32_t i = 0; *p != ']'; ++i) {
|
||||||
if (i == mesh.normals)
|
if (i == mesh.normals) {
|
||||||
accessors.normals = read_accessor(&p);
|
accessors.normals
|
||||||
else if (i == mesh.positions)
|
= read_accessor(&p, COMPONENT_TYPE_F32, ACCESSOR_TYPE_VEC3);
|
||||||
accessors.positions = read_accessor(&p);
|
} else if (i == mesh.positions) {
|
||||||
else if (i == mesh.indices)
|
accessors.positions
|
||||||
accessors.indices = read_accessor(&p);
|
= read_accessor(&p, COMPONENT_TYPE_F32, ACCESSOR_TYPE_VEC3);
|
||||||
else
|
} else if (i == mesh.indices) {
|
||||||
|
accessors.indices = read_accessor(
|
||||||
|
&p, COMPONENT_TYPE_U16, ACCESSOR_TYPE_SCALAR);
|
||||||
|
} else {
|
||||||
skip_value(&p);
|
skip_value(&p);
|
||||||
|
}
|
||||||
|
|
||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
++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)
|
static view_t read_view(const uint8_t **p)
|
||||||
{
|
{
|
||||||
char buffer[MAX_KEY_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
size_t len;
|
|
||||||
view_t view = {};
|
view_t view = {};
|
||||||
|
|
||||||
assert(**p == '{');
|
assert(**p == '{');
|
||||||
++(*p);
|
++(*p);
|
||||||
|
|
||||||
while (**p != '}') {
|
while (**p != '}') {
|
||||||
len = read_key(p, buffer);
|
read_string(p, buffer);
|
||||||
assert(**p == ':');
|
assert(**p == ':');
|
||||||
++(*p);
|
++(*p);
|
||||||
|
|
||||||
if (memcmp("buffer", buffer, len) == 0)
|
if (strcmp("buffer", buffer) == 0)
|
||||||
assert(read_uint(p) == 0);
|
assert(read_uint(p) == 0);
|
||||||
else if (memcmp("byteOffset", buffer, len) == 0)
|
else if (strcmp("byteOffset", buffer) == 0)
|
||||||
view.offset = read_uint(p);
|
view.offset = read_uint(p);
|
||||||
else if (memcmp("byteLength", buffer, len) == 0)
|
else if (strcmp("byteLength", buffer) == 0)
|
||||||
view.len = read_uint(p);
|
view.len = read_uint(p);
|
||||||
else if (memcmp("byteStride", buffer, len) == 0)
|
else if (strcmp("byteStride", buffer) == 0)
|
||||||
view.stride = read_uint(p);
|
view.stride = read_uint(p);
|
||||||
else
|
else
|
||||||
skip_value(p);
|
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)
|
static gltf_info_t read_json(const uint8_t *json)
|
||||||
{
|
{
|
||||||
char buffer[MAX_KEY_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
size_t len;
|
|
||||||
|
|
||||||
assert(*json == '{');
|
assert(*json == '{');
|
||||||
++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 *accessors_json = nullptr;
|
||||||
const uint8_t *views_json = nullptr;
|
const uint8_t *views_json = nullptr;
|
||||||
while (*json != '}') {
|
while (*json != '}') {
|
||||||
len = read_key(&json, buffer);
|
read_string(&json, buffer);
|
||||||
assert(*json == ':');
|
assert(*json == ':');
|
||||||
++json;
|
++json;
|
||||||
if (memcmp("meshes", buffer, len) == 0)
|
if (strcmp("meshes", buffer) == 0)
|
||||||
meshes_json = json;
|
meshes_json = json;
|
||||||
else if (memcmp("skins", buffer, len) == 0)
|
else if (strcmp("skins", buffer) == 0)
|
||||||
skins_json = json;
|
skins_json = json;
|
||||||
else if (memcmp("nodes", buffer, len) == 0)
|
else if (strcmp("nodes", buffer) == 0)
|
||||||
nodes_json = json;
|
nodes_json = json;
|
||||||
else if (memcmp("accessors", buffer, len) == 0)
|
else if (strcmp("accessors", buffer) == 0)
|
||||||
accessors_json = json;
|
accessors_json = json;
|
||||||
else if (memcmp("bufferViews", buffer, len) == 0)
|
else if (strcmp("bufferViews", buffer) == 0)
|
||||||
views_json = json;
|
views_json = json;
|
||||||
skip_value(&json);
|
skip_value(&json);
|
||||||
if (*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 accessors_t accessors = read_accessors(accessors_json, mesh);
|
||||||
const views_t views = read_views(views_json, accessors);
|
const views_t views = read_views(views_json, accessors);
|
||||||
|
|
||||||
if (accessors.positions.view == accessors.normals.view) {
|
// Assume indices are in their own buffer view
|
||||||
assert(views.normals.stride == sizeof(vec3_t));
|
assert(views.indices.stride == 0);
|
||||||
} 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));
|
|
||||||
|
|
||||||
return (gltf_info_t) {
|
return (gltf_info_t) {
|
||||||
.normals = {
|
.normals = {
|
||||||
|
|||||||
Reference in new issue
Block a user