Load joint info from GLB
This commit is contained in:
1 parent
221d68906d
commit
6454098c6a
1 file changed
+256
-14
+256
-14
@@ -3,6 +3,7 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -27,6 +28,7 @@ static_assert(
|
||||
#define VERSION 2
|
||||
|
||||
#define MAX_KEY_SIZE 128
|
||||
#define MAX_JOINT_COUNT 32
|
||||
|
||||
enum {
|
||||
CHUNK_TYPE_JSON = 0x4e4f534a, // "JSON"
|
||||
@@ -54,6 +56,19 @@ typedef struct {
|
||||
uint32_t indices;
|
||||
} mesh_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t inverse_bind_matrices;
|
||||
uint32_t joints[MAX_JOINT_COUNT];
|
||||
uint32_t joint_count;
|
||||
} skin_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t parent;
|
||||
vec3_t translation;
|
||||
vec4_t rotation;
|
||||
vec3_t scale;
|
||||
} joint_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t view;
|
||||
uint32_t offset;
|
||||
@@ -185,6 +200,100 @@ static uint32_t read_uint(const uint8_t **p)
|
||||
return value;
|
||||
}
|
||||
|
||||
static float read_float(const uint8_t **p)
|
||||
{
|
||||
enum {
|
||||
INTEGRAL,
|
||||
DECIMAL,
|
||||
EXPONENT,
|
||||
} state
|
||||
= INTEGRAL;
|
||||
|
||||
bool neg_val = false, neg_exp = false;
|
||||
float val = 0, exp = 0;
|
||||
unsigned div = 10;
|
||||
while (!ends_value(**p)) {
|
||||
const uint8_t c = *((*p)++);
|
||||
switch (state) {
|
||||
case INTEGRAL:
|
||||
if (isdigit(c))
|
||||
val = 10 * val + (c - '0');
|
||||
else if (c == '-')
|
||||
neg_val = true;
|
||||
else if (c == '.')
|
||||
state = DECIMAL;
|
||||
else
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
case DECIMAL:
|
||||
if (isdigit(c))
|
||||
val += (float)(c - '0') / div;
|
||||
else if (c == 'e')
|
||||
state = EXPONENT;
|
||||
else
|
||||
assert(false);
|
||||
div *= 10;
|
||||
break;
|
||||
|
||||
case EXPONENT:
|
||||
if (isdigit(c))
|
||||
exp = 10 * exp + (c - '0');
|
||||
else if (c == '-')
|
||||
neg_exp = true;
|
||||
else
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (neg_val)
|
||||
val *= -1;
|
||||
if (neg_exp)
|
||||
exp *= -1;
|
||||
return val * powf(10, exp);
|
||||
}
|
||||
|
||||
static vec3_t read_vec3(const uint8_t **p)
|
||||
{
|
||||
vec3_t v;
|
||||
assert(**p == '[');
|
||||
++(*p);
|
||||
v.x = read_float(p);
|
||||
assert(**p == ',');
|
||||
++(*p);
|
||||
v.y = read_float(p);
|
||||
assert(**p == ',');
|
||||
++(*p);
|
||||
v.z = read_float(p);
|
||||
assert(**p == ']');
|
||||
++(*p);
|
||||
return v;
|
||||
}
|
||||
|
||||
static vec4_t read_vec4(const uint8_t **p)
|
||||
{
|
||||
vec4_t v;
|
||||
assert(**p == '[');
|
||||
++(*p);
|
||||
v.x = read_float(p);
|
||||
assert(**p == ',');
|
||||
++(*p);
|
||||
v.y = read_float(p);
|
||||
assert(**p == ',');
|
||||
++(*p);
|
||||
v.z = read_float(p);
|
||||
assert(**p == ',');
|
||||
++(*p);
|
||||
v.w = read_float(p);
|
||||
assert(**p == ']');
|
||||
++(*p);
|
||||
return v;
|
||||
}
|
||||
|
||||
static mesh_t read_mesh_primitives(const uint8_t **p)
|
||||
{
|
||||
char buffer[MAX_KEY_SIZE];
|
||||
@@ -269,6 +378,127 @@ static mesh_t read_meshes(const uint8_t *p)
|
||||
assert(false);
|
||||
}
|
||||
|
||||
static skin_t read_skins(const uint8_t *p)
|
||||
{
|
||||
skin_t skin = {};
|
||||
char buffer[MAX_KEY_SIZE];
|
||||
size_t len;
|
||||
|
||||
assert(*p == '[');
|
||||
++p;
|
||||
assert(*p == '{');
|
||||
++p;
|
||||
|
||||
while (*p != '}') {
|
||||
len = read_key(&p, buffer);
|
||||
assert(*p == ':');
|
||||
++p;
|
||||
|
||||
if (memcmp("inverseBindMatrices", buffer, len) == 0) {
|
||||
skin.inverse_bind_matrices = read_uint(&p);
|
||||
} else if (memcmp("joints", buffer, len) == 0) {
|
||||
assert(*p == '[');
|
||||
++p;
|
||||
for (skin.joint_count = 0; *p != ']'; ++skin.joint_count) {
|
||||
assert(skin.joint_count < MAX_JOINT_COUNT);
|
||||
skin.joints[skin.joint_count] = read_uint(&p);
|
||||
|
||||
if (*p == ',')
|
||||
++p;
|
||||
}
|
||||
++p;
|
||||
} else {
|
||||
skip_value(&p);
|
||||
}
|
||||
|
||||
if (*p == ',')
|
||||
++p;
|
||||
}
|
||||
++p;
|
||||
|
||||
assert(*p == ']');
|
||||
return skin;
|
||||
}
|
||||
|
||||
static void read_joint_children(
|
||||
const uint8_t **p, skin_t skin, joint_t joints[MAX_JOINT_COUNT],
|
||||
uint32_t parent)
|
||||
{
|
||||
assert(**p == '[');
|
||||
++(*p);
|
||||
|
||||
while (**p != ']') {
|
||||
const uint32_t i = read_uint(p);
|
||||
uint32_t j;
|
||||
for (j = 0; j < skin.joint_count; ++j) {
|
||||
if (skin.joints[j] == i)
|
||||
break;
|
||||
}
|
||||
assert(j < skin.joint_count);
|
||||
assert(joints[j].parent == UINT32_MAX);
|
||||
joints[j].parent = parent;
|
||||
|
||||
if (**p == ',')
|
||||
++(*p);
|
||||
}
|
||||
++(*p);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (uint32_t i = 0; i < skin.joint_count; ++i)
|
||||
joints[i].parent = UINT32_MAX;
|
||||
|
||||
assert(*p == '[');
|
||||
++p;
|
||||
|
||||
for (uint32_t i = 0; *p != ']'; ++i) {
|
||||
uint32_t j;
|
||||
for (j = 0; j < skin.joint_count; ++j) {
|
||||
if (skin.joints[j] == i)
|
||||
break;
|
||||
}
|
||||
if (j >= skin.joint_count) {
|
||||
skip_value(&p);
|
||||
if (*p == ',')
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(*p == '{');
|
||||
++p;
|
||||
|
||||
while (*p != '}') {
|
||||
len = read_key(&p, buffer);
|
||||
assert(*p == ':');
|
||||
++p;
|
||||
|
||||
if (memcmp("children", buffer, len) == 0) {
|
||||
read_joint_children(&p, skin, joints, j);
|
||||
} else if (memcmp("translation", buffer, len) == 0) {
|
||||
joints[j].translation = read_vec3(&p);
|
||||
} else if (memcmp("rotation", buffer, len) == 0) {
|
||||
joints[j].rotation = read_vec4(&p);
|
||||
} else if (memcmp("scale", buffer, len) == 0) {
|
||||
joints[j].scale = read_vec3(&p);
|
||||
} else {
|
||||
skip_value(&p);
|
||||
}
|
||||
|
||||
if (*p == ',')
|
||||
++p;
|
||||
}
|
||||
++p;
|
||||
|
||||
if (*p == ',')
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
static accessor_t read_accessor(const uint8_t **p)
|
||||
{
|
||||
char buffer[MAX_KEY_SIZE];
|
||||
@@ -374,6 +604,9 @@ static views_t read_views(const uint8_t *p, accessors_t accessors)
|
||||
if (*p == ',')
|
||||
++p;
|
||||
}
|
||||
|
||||
if (accessors.normals.view == accessors.positions.view)
|
||||
views.positions = views.normals;
|
||||
return views;
|
||||
}
|
||||
|
||||
@@ -394,6 +627,8 @@ static gltf_info_t read_json(const uint8_t *json)
|
||||
* them in the necessary order.
|
||||
*/
|
||||
const uint8_t *meshes_json = nullptr;
|
||||
const uint8_t *skins_json = nullptr;
|
||||
const uint8_t *nodes_json = nullptr;
|
||||
const uint8_t *accessors_json = nullptr;
|
||||
const uint8_t *views_json = nullptr;
|
||||
while (*json != '}') {
|
||||
@@ -402,6 +637,10 @@ static gltf_info_t read_json(const uint8_t *json)
|
||||
++json;
|
||||
if (memcmp("meshes", buffer, len) == 0)
|
||||
meshes_json = json;
|
||||
else if (memcmp("skins", buffer, len) == 0)
|
||||
skins_json = json;
|
||||
else if (memcmp("nodes", buffer, len) == 0)
|
||||
nodes_json = json;
|
||||
else if (memcmp("accessors", buffer, len) == 0)
|
||||
accessors_json = json;
|
||||
else if (memcmp("bufferViews", buffer, len) == 0)
|
||||
@@ -411,36 +650,39 @@ static gltf_info_t read_json(const uint8_t *json)
|
||||
++json;
|
||||
}
|
||||
assert(meshes_json != nullptr);
|
||||
assert(skins_json != nullptr);
|
||||
assert(nodes_json != nullptr);
|
||||
assert(accessors_json != nullptr);
|
||||
assert(views_json != nullptr);
|
||||
|
||||
mesh_t mesh = read_meshes(meshes_json);
|
||||
accessors_t accessors = read_accessors(accessors_json, mesh);
|
||||
views_t views = read_views(views_json, accessors);
|
||||
const mesh_t mesh = read_meshes(meshes_json);
|
||||
const skin_t skin = read_skins(skins_json);
|
||||
joint_t joints[MAX_JOINT_COUNT] = {};
|
||||
read_joints(nodes_json, skin, joints);
|
||||
|
||||
const accessors_t accessors = read_accessors(accessors_json, mesh);
|
||||
const views_t views = read_views(views_json, accessors);
|
||||
|
||||
size_t normals_len, positions_len;
|
||||
if (accessors.positions.view == accessors.normals.view) {
|
||||
views.positions = views.normals;
|
||||
assert(views.normals.stride == sizeof(vec3_t));
|
||||
assert(views.positions.stride == sizeof(vec3_t));
|
||||
normals_len = accessors.normals.count * sizeof(vec3_t);
|
||||
positions_len = accessors.positions.count * sizeof(vec3_t);
|
||||
} else {
|
||||
normals_len = views.normals.len;
|
||||
positions_len = views.positions.len;
|
||||
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.stride == 0);
|
||||
assert(views.indices.len / accessors.indices.count == sizeof(index_t));
|
||||
|
||||
return (gltf_info_t) {
|
||||
.normals = {
|
||||
.offset = views.normals.offset + accessors.normals.offset,
|
||||
.len = normals_len,
|
||||
.len = accessors.normals.count * sizeof(vec3_t),
|
||||
},
|
||||
.positions = {
|
||||
.offset = views.positions.offset + accessors.positions.offset,
|
||||
.len = positions_len,
|
||||
.len = accessors.positions.count * sizeof(vec3_t),
|
||||
},
|
||||
.indices = {
|
||||
.offset = views.indices.offset + accessors.indices.offset,
|
||||
|
||||
Reference in new issue
Block a user