commit 2522f790272739f4933294c7c357db25e5e993f1
parent 23463bc3c2520d6a058de526e0e6edd4043899e4
Author: William Casarin <jb55@jb55.com>
Date: Sun, 7 Jul 2019 00:19:43 -0700
model compiler progress
Diffstat:
10 files changed, 355 insertions(+), 278 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -10,3 +10,4 @@ polyadvent
*.zip
/tools/compile-model
/samples.bin
+/test/test_dae
diff --git a/Makefile b/Makefile
@@ -18,7 +18,7 @@ DAES=$(wildcard data/models/*.dae)
MODELS=$(DAES:.dae=.mdl)
OBJS=$(SRCS:.c=.o)
-TESTS = test/test_animation
+TESTS = test/test_dae
TESTS += test/test_resource
TESTS += test/test_scene
@@ -31,7 +31,7 @@ clean:
include $(OBJS:.o=.d)
include main.d
-include test/test_animation.d
+include test/test_dae.d
%.d: %.c
@rm -f $@; \
@@ -51,7 +51,7 @@ data/models/%.mdl: data/models/%.dae tools/compile-model
./tools/compile-model $< $@
check: $(TESTS)
- ./test/test_animation
+ ./test/test_dae
./test/test_resource
./test/test_scene
diff --git a/src/animation.h b/src/animation.h
@@ -17,7 +17,6 @@ struct joint
node_id node_id;
};
-
struct pose
{
struct joint joints[MAX_JOINTS];
diff --git a/src/dae.c b/src/dae.c
@@ -0,0 +1,270 @@
+
+#include "xml.h"
+#include "util.h"
+#include "animation.h"
+#include "dae.h"
+
+enum dae_state {
+ PARSING_START,
+ PARSING_NODE,
+ PARSING_FLOAT_ARRAY,
+ PARSING_POSE,
+ PARSING_JOINT,
+ PARSING_JOINT_MATRIX,
+ PARSING_WEIGHTS,
+ PARSING_POSITIONS,
+ PARSING_COLORS,
+ PARSING_NORMALS,
+};
+
+struct dae_data {
+ int node_level;
+ int state;
+ FILE *dae_file;
+ struct model *model;
+ struct make_geometry *geom;
+ int counter;
+ 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 parse_floats(const char *d, int dl, float **floats, int nfloats)
+{
+ float val;
+ int i;
+
+ assert(nfloats > 0);
+ *floats = calloc(nfloats, sizeof(float));
+
+ const char *p = d;
+
+ for (i = 0; i < nfloats; i++) {
+ sscanf(p, "%f", &val);
+ (*floats)[i] = val;
+
+ while (p < d+dl) {
+ if (*(p++) == ' ')
+ break;
+ }
+ }
+
+ assert(nfloats == i);
+}
+
+static void parse_weights(struct dae_data *data, const char *d, int dl)
+{
+ assert(data->counter != -1);
+ float *weights;
+ parse_floats(d, dl, &weights, data->counter);
+ struct model *model = data->model;
+ struct pose *pose = &model->poses[model->nposes];
+ assert(pose);
+ pose->nweights = data->counter;
+ pose->weights = weights;
+ data->state = PARSING_POSE;
+ data->counter = -1;
+}
+
+static void parse_vertices(struct dae_data *data, float **verts,
+ const char *d, int dl)
+{
+ assert(data->counter != -1);
+ parse_floats(d, dl, verts, data->counter);
+
+}
+
+static void parse_joint_matrix(struct dae_data *data, const char *d,
+ int dl)
+{
+ assert(data->model->nposes);
+
+ struct model *model = data->model;
+ struct pose *pose = &model->poses[model->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;
+}
+
+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;
+
+ if (data->state == PARSING_JOINT_MATRIX) {
+ parse_joint_matrix(data, d, dl);
+ }
+ else if (data->state == PARSING_WEIGHTS) {
+ parse_weights(data, d, dl);
+ }
+ else if (data->state == PARSING_NORMALS) {
+ }
+}
+
+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 model *model = data->model;
+ struct pose *pose = &model->poses[model->nposes++];
+ data->state = PARSING_POSE;
+ init_pose(pose);
+ }
+ else if (data->state == PARSING_FLOAT_ARRAY && streq(a, "id")) {
+ if (contains(v, "skin-weights-array")) {
+ data->state = PARSING_WEIGHTS;
+ }
+ else if (contains(v, "positions-array")) {
+ data->state = PARSING_POSITIONS;
+ }
+ else if (contains(v, "normals-array")) {
+ data->state = PARSING_NORMALS;
+ }
+ else if (contains(v, "colors")) {
+ data->state = PARSING_COLORS;
+ }
+ }
+ else if (data->state == PARSING_WEIGHTS
+ && streq(a, "count")) {
+ data->counter = 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_model(const char *filename, struct model *model,
+ struct make_geometry *geom)
+{
+ struct xmlparser x = {0};
+ struct dae_data data = {
+ .node_level = 0,
+ .state = PARSING_START,
+ .model = model,
+ .geom = geom,
+ .counter = -1
+ };
+
+ 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 < model->nposes; i++) {
+ struct pose *pose = &model->poses[i];
+ process_joint_children(pose->joints, pose->njoints);
+ }
+
+
+ fclose(data.dae_file);
+}
diff --git a/src/dae.h b/src/dae.h
@@ -0,0 +1,11 @@
+
+#ifndef DAE_H
+#define DAE_H
+
+#include "geometry.h"
+#include "model.h"
+
+void load_model(const char *filename, struct model *model,
+ struct make_geometry *geom);
+
+#endif /* DAE_H */
diff --git a/src/model.c b/src/model.c
@@ -20,6 +20,10 @@ struct model *init_model(struct model *model) {
init_id(&model->geom_id);
model->shading = SHADING_VERT_COLOR;
model->texture = 0;
+ model->nposes = 0;
+ for (u16 i = 0; i < ARRAY_SIZE(model->poses); i++) {
+ init_pose(model->poses);
+ }
return model;
}
diff --git a/src/model.h b/src/model.h
@@ -7,11 +7,13 @@
#include "shader.h"
#include "geometry.h"
#include "common.h"
+#include "animation.h"
#include "static_resources.h"
#define DEF_DYNAMIC_MODELS 128
#define MAX_STATIC_MODELS 128
#define MAX_DYNAMIC_MODELS 2048
+#define MAX_POSES 2
typedef struct resource_id model_id;
@@ -25,6 +27,8 @@ struct model {
/* geometry_id geom_id; */
geometry_id geom_id;
enum shading shading;
+ struct pose poses[MAX_POSES]; // TODO: separate animated_model buffer?
+ int nposes;
u32 texture;
};
diff --git a/test/test_animation.c b/test/test_animation.c
@@ -1,48 +0,0 @@
-
-#include "animation.h"
-#include "util.h"
-#include "debug.h"
-#include <assert.h>
-#include <stdio.h>
-
-
-int main(int argc, char *argv[])
-{
- struct pose *pose;
- struct joint *joint;
- struct node *node;
- struct pose poses[4];
- int nposes;
-
- init_node_manager();
-
- for (int i = 0; i < (int)ARRAY_SIZE(poses); i++) {
- init_pose(&poses[i]);
- }
-
- load_poses("data/models/pirate-officer.dae", poses, &nposes);
- assert(nposes == 1);
- pose = &poses[0];
-
- debug("pose->nweights %d\n", pose->nweights);
- assert(pose->nweights == 389);
- assert(approxeq(pose->weights[0], 0.05213558));
- debug("pose last weight %f\n", pose->weights[388]);
- assert(approxeq(pose->weights[388], 0.01394611));
-
- assert(pose->njoints == 11);
-
- joint = &pose->joints[0];
- node = get_node(&joint->node_id);
- assert(node);
- assert(approxeq(node->mat[0], 0.999897));
-
- joint = &pose->joints[1];
- node = get_node(&joint->node_id);
- assert(node);
- assert(approxeq(node->mat[1], -0.01434187));
-
- assert(pose->joints[0].n_children_ids == 3);
-
- return 0;
-}
diff --git a/test/test_dae.c b/test/test_dae.c
@@ -0,0 +1,48 @@
+
+#include "animation.h"
+#include "util.h"
+#include "debug.h"
+#include <assert.h>
+#include <stdio.h>
+
+#include "dae.h"
+
+int main(int argc, char *argv[])
+{
+ struct pose *pose;
+ struct joint *joint;
+ struct node *node;
+ struct model model;
+ struct make_geometry geom;
+ int nposes;
+
+ init_node_manager();
+ init_model(&model);
+ init_make_geometry(&geom);
+
+ load_model("data/models/pirate-officer.dae", &model, &geom);
+ assert(model.nposes == 1);
+ pose = &model.poses[0];
+
+ debug("pose->nweights %d\n", pose->nweights);
+ assert(pose->nweights == 389);
+ assert(approxeq(pose->weights[0], 0.05213558));
+ debug("pose last weight %f\n", pose->weights[388]);
+ assert(approxeq(pose->weights[388], 0.01394611));
+
+ assert(pose->njoints == 11);
+
+ joint = &pose->joints[0];
+ node = get_node(&joint->node_id);
+ assert(node);
+ assert(approxeq(node->mat[0], 0.999897));
+
+ joint = &pose->joints[1];
+ node = get_node(&joint->node_id);
+ assert(node);
+ assert(approxeq(node->mat[1], -0.01434187));
+
+ assert(pose->joints[0].n_children_ids == 3);
+
+ return 0;
+}
diff --git a/tools/compile-model.c b/tools/compile-model.c
@@ -3,234 +3,13 @@
#include <stdlib.h>
#include <assert.h>
-#include "xml.h"
-#include "util.h"
-#include "animation.h"
+#include "dae.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)
+static void save_mdl(struct model *model, struct make_geometry *geom)
{
- 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()
{
@@ -243,17 +22,26 @@ int main(int argc, char *argv[])
if (argc != 3)
usage();
+ init_node_manager();
+ init_geometry_manager();
+ init_model_manager();
+
const char *filename = argv[1];
const char *outfile = argv[2];
+ struct model model;
+ struct make_geometry geom;
+
+ init_model(&model);
+ init_make_geometry(&geom);
+
int nposes;
- static struct pose poses[5];
- load_poses(outfile, poses, &nposes);
+ load_model(filename, &model, &geom);
FILE *out = fopen(outfile, "wb");
fprintf(out, "hello, world\n");
- fclose(out);
+
return 0;
}