polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

commit 23463bc3c2520d6a058de526e0e6edd4043899e4
parent 7ab896e9ceb94396729001b4123abc3773a39ec6
Author: William Casarin <jb55@jb55.com>
Date:   Sat,  6 Jul 2019 23:00:25 -0700

initial model compiler

Diffstat:
M.gitignore | 2++
MMakefile | 61++++++++++++++++++-------------------------------------------
Rsrc/main.c -> main.c | 0
Msrc/animation.c | 221-------------------------------------------------------------------------------
Dsrc/physics.c | 3---
Rsrc/half-edge.c -> src/wip/half-edge.c | 0
Rsrc/slab_geom.c -> src/wip/slab_geom.c | 0
Atools/compile-model.c | 259+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 279 insertions(+), 267 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -8,3 +8,5 @@ polyadvent /test/test_scene /archive *.zip +/tools/compile-model +/samples.bin diff --git a/Makefile b/Makefile @@ -12,58 +12,25 @@ CFLAGS = $(DEFS) -ggdb -O2 -I src -Wall -Werror -Wextra -std=c99 \ LDFLAGS = -lSDL2 -lGL -lm SRC=src -OBJS = $(SRC)/window.o -OBJS += $(SRC)/vbo.o -OBJS += $(SRC)/camera.o -OBJS += $(SRC)/xml.o -OBJS += $(SRC)/animation.o -OBJS += $(SRC)/debug.o -OBJS += $(SRC)/delaunay.o -OBJS += $(SRC)/entity.o -OBJS += $(SRC)/fbo.o -OBJS += $(SRC)/file.o -OBJS += $(SRC)/game.o -OBJS += $(SRC)/geometry.o -OBJS += $(SRC)/hires.o -OBJS += $(SRC)/input.o -OBJS += $(SRC)/mat4.o -OBJS += $(SRC)/mat_util.o -OBJS += $(SRC)/model.o -OBJS += $(SRC)/node.o -OBJS += $(SRC)/orbit.o -OBJS += $(SRC)/perlin.o -OBJS += $(SRC)/ply.o -OBJS += $(SRC)/poisson.o -OBJS += $(SRC)/quat.o -OBJS += $(SRC)/render.o -OBJS += $(SRC)/shader.o -OBJS += $(SRC)/skybox.o -OBJS += $(SRC)/stb_image.o -OBJS += $(SRC)/terrain.o -OBJS += $(SRC)/texture.o -OBJS += $(SRC)/ui.o -OBJS += $(SRC)/uniform.o -OBJS += $(SRC)/update.o -OBJS += $(SRC)/util.o -OBJS += $(SRC)/vec3.o -OBJS += $(SRC)/scene.o -OBJS += $(SRC)/resource.o -OBJS += $(SRC)/quickhull.o -OBJS += $(SRC)/procmesh.o +SRCS=$(wildcard $(SRC)/*.c) +DAES=$(wildcard data/models/*.dae) + +MODELS=$(DAES:.dae=.mdl) +OBJS=$(SRCS:.c=.o) TESTS = test/test_animation TESTS += test/test_resource TESTS += test/test_scene -SRCS=$(OBJS:.o=.c) +TOOLS = tools/compile-model -all: $(BIN) +all: $(BIN) $(MODELS) clean: - rm -f src/main.o test/*.o $(OBJS) $(TESTS) $(SHLIB) $(BIN) $(SRC)/*.d* + rm -f src/main.o test/*.o tools/*.o $(OBJS) $(TESTS) $(TOOLS) $(MODELS) $(SHLIB) $(BIN) $(SRC)/*.d* include $(OBJS:.o=.d) -include src/main.d +include main.d include test/test_animation.d %.d: %.c @@ -75,12 +42,20 @@ include test/test_animation.d test/%: test/%.o $(OBJS) $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ +tools/%: tools/%.o $(OBJS) + $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ + +tools: $(TOOLS) + +data/models/%.mdl: data/models/%.dae tools/compile-model + ./tools/compile-model $< $@ + check: $(TESTS) ./test/test_animation ./test/test_resource ./test/test_scene -$(BIN): src/main.o $(OBJS) +$(BIN): main.o $(OBJS) $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ install: $(BIN) diff --git a/src/main.c b/main.c diff --git a/src/animation.c b/src/animation.c @@ -6,27 +6,6 @@ #include "debug.h" #include "animation.h" -enum dae_state { - PARSING_START, - PARSING_NODE, - PARSING_FLOAT_ARRAY, - PARSING_POSE, - PARSING_JOINT, - PARSING_JOINT_MATRIX, - PARSING_WEIGHTS, -}; - -struct dae_data { - int node_level; - int state; - FILE *dae_file; - struct pose *poses; - int *nposes; - float *weights; - int nweights; - char current_name[JOINT_LABEL_SIZE]; -}; - void init_joint(struct joint *joint) { joint->id = -1; @@ -52,204 +31,4 @@ void init_pose(struct pose *pose) } } -static void parse_joint(const char *t, int id, struct joint *joint) -{ - struct node *node = get_node(&joint->node_id); - assert(node); - float *m = node->mat; - joint->id = id; - /* printf(" parsing joint %d: %s\n", id, t); */ - - sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", - &m[0], &m[1], &m[2], &m[3], - &m[4], &m[5], &m[6], &m[7], - &m[8], &m[9], &m[10], &m[11], - &m[12], &m[13], &m[14], &m[15] - ); -} - -static void dae_tag_start(struct xmlparser *x, const char *t, size_t tl) -{ - struct dae_data *data = (struct dae_data*)x->user_data; - - if (streq(t, "node")) { - data->state = PARSING_NODE; - data->node_level++; - } - else if (streq(t, "float_array")) { - data->state = PARSING_FLOAT_ARRAY; - } - else if (data->state == PARSING_JOINT && streq(t, "matrix")) - data->state = PARSING_JOINT_MATRIX; - else - return; -} - -static void dae_tag_end(struct xmlparser *x, const char *t, size_t tl, int what) -{ - struct dae_data *data = (struct dae_data*)x->user_data; - - if (streq(t, "node")) - data->node_level--; - - if (data->state == PARSING_NODE) { - data->state = PARSING_START; - } -} - -static void dae_tagbody(struct xmlparser *x, const char *d, size_t dl) -{ - static int count = 0; - struct dae_data *data = (struct dae_data*)x->user_data; - struct pose *pose; - - if (data->state == PARSING_JOINT_MATRIX) { - assert(*data->nposes); - - pose = &data->poses[*data->nposes - 1]; - assert(pose); - - struct joint *joint = &pose->joints[pose->njoints]; - assert(joint); - - struct node *node = new_node(&joint->node_id); - assert(node); - assert((int64_t)joint->node_id.uuid != -1); - assert(&joint->node_id == &pose->joints[pose->njoints].node_id); - - parse_joint(d, pose->njoints, joint); - print_id(&joint->node_id, 1); - node_set_label(node, data->current_name); - joint->children_ids[0] = data->node_level; - pose->njoints++; - data->state = PARSING_POSE; - } - else if (data->state == PARSING_WEIGHTS) { - pose = &data->poses[*data->nposes]; - assert(data->nweights > 0); - data->weights = calloc(data->nweights, sizeof(float)); - - const char *p = d; - float val; - int i; - - for (i = 0; i < data->nweights; i++) { - sscanf(p, "%f", &val); - data->weights[i] = val; - - while (p < d+dl) { - if (*(p++) == ' ') - break; - } - } - - assert(data->nweights == i); - - pose->nweights = data->nweights; - pose->weights = data->weights; - - data->state = PARSING_POSE; - } -} - -static int dae_getc(struct xmlparser *x) -{ - struct dae_data *data = (struct dae_data*)x->user_data; - return fgetc(data->dae_file); -} - -void dae_attr(struct xmlparser *x, const char *t, size_t tl, - const char *a, size_t al, const char *v, size_t vl) -{ - struct dae_data *data = (struct dae_data*)x->user_data; - - if (data->state == PARSING_NODE - && streq(a, "id") - && streq(v, "Armature")) { - - struct pose *pose = &data->poses[(*data->nposes)++]; - data->state = PARSING_POSE; - init_pose(pose); - } - else if (data->state == PARSING_FLOAT_ARRAY - && streq(a, "id") - && contains(v, "skin-weights-array")) { - data->state = PARSING_WEIGHTS; - } - else if (data->state == PARSING_WEIGHTS - && streq(a, "count")) { - data->nweights = atoi(v); - } - else if (data->state == PARSING_NODE - && streq(a, "name")) { - strncpy(data->current_name, v, sizeof(data->current_name)); - } - else if (data->state == PARSING_NODE - && streq(a, "type") - && streq(v, "JOINT")) { - - data->state = PARSING_JOINT; - } -} - -static void process_joint_children(struct joint *joints, int njoints) -{ - struct joint *joint, *j2; - for (int i = 0; i < njoints; i++) { - joint = &joints[i]; - - // node level is stored in here on the first parser pass - int level = joint->children_ids[0]; - - for (int j = i+1; j < njoints; j++) { - j2 = &joints[j]; - if (j2->children_ids[0] == level + 1) { - /* printf("%s(%d) assigning child %s(%d)\n", */ - /* joint->name, level, j2->name, j2->children[0]); */ - - assert(joint->n_children_ids+1 < MAX_JOINT_CHILDREN); - joint->children_ids[joint->n_children_ids++] = j; - } - else if (j2->children_ids[0] <= level) - break; - } - } -} - -void load_poses(const char *filename, struct pose *poses, int *nposes) -{ - *nposes = 0; - - struct xmlparser x = {0}; - struct dae_data data = { - .node_level = 0, - .state = PARSING_START, - .poses = poses, - .nposes = nposes, - .nweights = -1, - .weights = NULL - }; - - data.dae_file = fopen(filename, "rb"); - if (data.dae_file == NULL) - exit(1); - - x.user_data = &data; - x.xmltagstart = dae_tag_start; - x.xmltagend = dae_tag_end; - x.xmlattr = dae_attr; - x.xmldata = dae_tagbody; - /* x.xmlattrend = dae_attr_end; */ - x.getnext = dae_getc; - - xml_parse(&x); - - for (int i = 0; i < *nposes; i++) { - struct pose *pose = &poses[i]; - process_joint_children(pose->joints, pose->njoints); - } - - - fclose(data.dae_file); -} diff --git a/src/physics.c b/src/physics.c @@ -1,3 +0,0 @@ - -void simulate(struct entity_system *entity_system) { -} diff --git a/src/half-edge.c b/src/wip/half-edge.c diff --git a/src/slab_geom.c b/src/wip/slab_geom.c diff --git a/tools/compile-model.c b/tools/compile-model.c @@ -0,0 +1,259 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "xml.h" +#include "util.h" +#include "animation.h" + +enum dae_state { + PARSING_START, + PARSING_NODE, + PARSING_FLOAT_ARRAY, + PARSING_POSE, + PARSING_JOINT, + PARSING_JOINT_MATRIX, + PARSING_WEIGHTS, +}; + +struct dae_data { + int node_level; + int state; + FILE *dae_file; + struct pose *poses; + int *nposes; + float *weights; + int nweights; + char current_name[JOINT_LABEL_SIZE]; +}; + + +static void parse_joint(const char *t, int id, struct joint *joint) +{ + struct node *node = get_node(&joint->node_id); + assert(node); + + float *m = node->mat; + joint->id = id; + /* printf(" parsing joint %d: %s\n", id, t); */ + + sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", + &m[0], &m[1], &m[2], &m[3], + &m[4], &m[5], &m[6], &m[7], + &m[8], &m[9], &m[10], &m[11], + &m[12], &m[13], &m[14], &m[15] + ); +} + + +static void dae_tag_start(struct xmlparser *x, const char *t, size_t tl) +{ + struct dae_data *data = (struct dae_data*)x->user_data; + + if (streq(t, "node")) { + data->state = PARSING_NODE; + data->node_level++; + } + else if (streq(t, "float_array")) { + data->state = PARSING_FLOAT_ARRAY; + } + else if (data->state == PARSING_JOINT && streq(t, "matrix")) + data->state = PARSING_JOINT_MATRIX; + else + return; +} + +static void dae_tag_end(struct xmlparser *x, const char *t, size_t tl, int what) +{ + struct dae_data *data = (struct dae_data*)x->user_data; + + if (streq(t, "node")) + data->node_level--; + + if (data->state == PARSING_NODE) { + data->state = PARSING_START; + } +} + +static void dae_tagbody(struct xmlparser *x, const char *d, size_t dl) +{ + static int count = 0; + struct dae_data *data = (struct dae_data*)x->user_data; + struct pose *pose; + + if (data->state == PARSING_JOINT_MATRIX) { + assert(*data->nposes); + + pose = &data->poses[*data->nposes - 1]; + assert(pose); + + struct joint *joint = &pose->joints[pose->njoints]; + assert(joint); + + struct node *node = new_node(&joint->node_id); + assert(node); + assert((int64_t)joint->node_id.uuid != -1); + assert(&joint->node_id == &pose->joints[pose->njoints].node_id); + + parse_joint(d, pose->njoints, joint); + print_id(&joint->node_id, 1); + node_set_label(node, data->current_name); + joint->children_ids[0] = data->node_level; + pose->njoints++; + data->state = PARSING_POSE; + } + else if (data->state == PARSING_WEIGHTS) { + pose = &data->poses[*data->nposes]; + assert(data->nweights > 0); + data->weights = calloc(data->nweights, sizeof(float)); + + const char *p = d; + float val; + int i; + + for (i = 0; i < data->nweights; i++) { + sscanf(p, "%f", &val); + data->weights[i] = val; + + while (p < d+dl) { + if (*(p++) == ' ') + break; + } + } + + assert(data->nweights == i); + + pose->nweights = data->nweights; + pose->weights = data->weights; + + data->state = PARSING_POSE; + } +} + +static int dae_getc(struct xmlparser *x) +{ + struct dae_data *data = (struct dae_data*)x->user_data; + return fgetc(data->dae_file); +} + +void dae_attr(struct xmlparser *x, const char *t, size_t tl, + const char *a, size_t al, const char *v, size_t vl) +{ + struct dae_data *data = (struct dae_data*)x->user_data; + + if (data->state == PARSING_NODE + && streq(a, "id") + && streq(v, "Armature")) { + + struct pose *pose = &data->poses[(*data->nposes)++]; + data->state = PARSING_POSE; + init_pose(pose); + } + else if (data->state == PARSING_FLOAT_ARRAY + && streq(a, "id") + && contains(v, "skin-weights-array")) { + data->state = PARSING_WEIGHTS; + } + else if (data->state == PARSING_WEIGHTS + && streq(a, "count")) { + data->nweights = atoi(v); + } + else if (data->state == PARSING_NODE + && streq(a, "name")) { + strncpy(data->current_name, v, sizeof(data->current_name)); + } + else if (data->state == PARSING_NODE + && streq(a, "type") + && streq(v, "JOINT")) { + + data->state = PARSING_JOINT; + } +} + +static void process_joint_children(struct joint *joints, int njoints) +{ + struct joint *joint, *j2; + for (int i = 0; i < njoints; i++) { + joint = &joints[i]; + + // node level is stored in here on the first parser pass + int level = joint->children_ids[0]; + + for (int j = i+1; j < njoints; j++) { + j2 = &joints[j]; + if (j2->children_ids[0] == level + 1) { + /* printf("%s(%d) assigning child %s(%d)\n", */ + /* joint->name, level, j2->name, j2->children[0]); */ + + assert(joint->n_children_ids+1 < MAX_JOINT_CHILDREN); + joint->children_ids[joint->n_children_ids++] = j; + } + else if (j2->children_ids[0] <= level) + break; + } + } +} + +void load_poses(const char *filename, struct pose *poses, int *nposes) +{ + *nposes = 0; + + struct xmlparser x = {0}; + struct dae_data data = { + .node_level = 0, + .state = PARSING_START, + .poses = poses, + .nposes = nposes, + .nweights = -1, + .weights = NULL + }; + + data.dae_file = fopen(filename, "rb"); + if (data.dae_file == NULL) + exit(1); + + x.user_data = &data; + x.xmltagstart = dae_tag_start; + x.xmltagend = dae_tag_end; + x.xmlattr = dae_attr; + x.xmldata = dae_tagbody; + /* x.xmlattrend = dae_attr_end; */ + x.getnext = dae_getc; + + xml_parse(&x); + + for (int i = 0; i < *nposes; i++) { + struct pose *pose = &poses[i]; + process_joint_children(pose->joints, pose->njoints); + } + + + fclose(data.dae_file); +} + +void usage() +{ + printf("usage: compile-model <model.dae> <out.mdl>\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + usage(); + + const char *filename = argv[1]; + const char *outfile = argv[2]; + + int nposes; + static struct pose poses[5]; + + load_poses(outfile, poses, &nposes); + + FILE *out = fopen(outfile, "wb"); + fprintf(out, "hello, world\n"); + fclose(out); + + return 0; +}