polyadvent

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

commit 1e59967d82b2bb62226bbabd3b365fecde31fcfb
parent e10fbec6715724f9d7f662d25846222e5c8f20bb
Author: William Casarin <jb55@jb55.com>
Date:   Sun,  7 Jul 2019 02:13:39 -0700

mdl wip progress

Diffstat:
MMakefile | 2+-
Msrc/geometry.c | 15+++++++++++++++
Msrc/geometry.h | 6+++++-
Msrc/mdl.c | 160++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/mdl.h | 25++++++++++++++++++++++++-
Msrc/ply.c | 70++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/ply.h | 3++-
Msrc/update.c | 2+-
Msrc/vbo.c | 2+-
Msrc/vbo.h | 2+-
Msrc/vec3.h | 3+++
Mtest/test_dae.c | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
12 files changed, 304 insertions(+), 57 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ NAME ?= polyadvent BIN ?= $(NAME) PREFIX ?= /usr/local -DEFS= -DGLFW_INCLUDE_NONE # -DDEBUG +DEFS= -DGLFW_INCLUDE_NONE -DDEBUG CFLAGS = $(DEFS) -ggdb -O2 -I src -Wall -Werror -Wextra -std=c99 \ -Wno-unused-function \ -Wno-unused-parameter \ diff --git a/src/geometry.c b/src/geometry.c @@ -211,3 +211,18 @@ void destroy_geometry(geometry_id *geom_id) destroy_resource(&geom_manager, geom_id); } + +void free_make_geometry(struct make_geometry *mkgeom) +{ + if (mkgeom->vertices) + free(mkgeom->vertices); + + if (mkgeom->normals) + free(mkgeom->normals); + + if (mkgeom->colors) + free(mkgeom->colors); + + if (mkgeom->indices) + free(mkgeom->indices); +} diff --git a/src/geometry.h b/src/geometry.h @@ -36,8 +36,11 @@ struct make_geometry { float *tex_coords; int num_uv_components; - int *joint_ids; + u32 *joint_ids; + int num_joint_ids; + float *joint_weights; + int num_weights; }; struct geometry_manager { @@ -50,6 +53,7 @@ void render_geometry(struct geometry *geom, gpu_addr *vertex_attrs, void bind_geometry(struct geometry *geom, gpu_addr *vertex_attrs); void init_geometry(struct geometry *geom); void init_make_geometry(struct make_geometry *mkgeom); +void free_make_geometry(struct make_geometry *mkgeom); void make_buffer_geometry(struct make_geometry *mkgeom, struct geometry *geom); void destroy_buffer_geometry(geometry_id *geom); void geometry_centroid(struct geometry *geom, float *v3); diff --git a/src/mdl.c b/src/mdl.c @@ -1,7 +1,165 @@ #include "mdl.h" +#include "debug.h" +#include <assert.h> -void save_mdl(struct model *model, struct make_geometry *geom) + +static inline void write_tag(enum mdl_tag tag, FILE *out) +{ + fwrite(&tag, 1, 1, out); +} + +// little endian is assumed... +static inline void write_int(int val, FILE *out) +{ + fwrite(&val, sizeof(val), 1, out); +} + +static inline void write_floats(float *floats, int num_floats, FILE *out) +{ + write_int(num_floats, out); + fwrite(floats, sizeof(*floats), num_floats, out); +} + +void init_mdl_geometry(struct mdl_geometry *lgeom) { + init_make_geometry(&lgeom->mkgeom); + memset(lgeom->min, 0, sizeof(lgeom->min)); + memset(lgeom->max, 0, sizeof(lgeom->max)); +} + +void save_mdl(FILE *out, struct model *model, struct mdl_geometry *lgeom) +{ + struct make_geometry *mkgeom = &lgeom->mkgeom; + assert(mkgeom->vertices); + + + if (mkgeom->normals) { + } + + if (mkgeom->colors) { + } + + for (int i = 0; i < N_MDL_TAGS; i++) { + write_tag(MDL_NORMAL, out); + switch ((enum mdl_tag)i) { + case MDL_POSITION: + write_floats(mkgeom->vertices, mkgeom->num_verts, out); + break; + case MDL_NORMAL: + write_floats(mkgeom->normals, mkgeom->num_verts, out); + break; + case MDL_COLOR: + write_floats(mkgeom->colors, mkgeom->num_verts, out); + break; + case MDL_INDEX: + write_ints(mkgeom->indices, mkgeom->num_indices, out); + + case MDL_JOINT_IDS: + case MDL_JOINT_WEIGHTS: + case MDL_TEX_COORD: + case MDL_MAX: + case MDL_MIN: + case N_MDL_TAGS: + assert(!"this shouldn't happend"); break; + } + } + + assert(mkgeom->indices); +} + +static inline enum mdl_tag read_tag(FILE *stream) +{ + enum mdl_tag tag = 0; + int read = fread(&tag, 1, 1, stream); + assert(read == 1 || feof(stream)); + assert(tag != 0 || feof(stream)); + return tag; +} + +static inline int read_int(FILE *stream) +{ + int val = 0; + int read = fread(&val, sizeof(val), 1, stream); + assert(read == 1); + assert(val != 0); + return val; +} + +#define MAX_MDL_ARRAY 128000 // only enforced at dev time for sanity + +static inline int read_nfloats(FILE *stream, int n, float *floats) +{ + return fread(floats, sizeof(float), n, stream); +} + +static int read_floats(FILE *stream, float **floats) +{ + int nfloats = read_int(stream); + assert(nfloats != 0); + assert(nfloats < MAX_MDL_ARRAY); // it's a low poly game... + *floats = malloc(nfloats*sizeof(float)); + int nread = read_nfloats(stream, nfloats, *floats); + assert(nread == nfloats); + return nread; +} + +static int read_ints(FILE *stream, u32 **ints) +{ + int nints = read_int(stream); + assert(nints != 0); + assert(nints < MAX_MDL_ARRAY); // it's a low poly game... + *ints = malloc(nints*sizeof(u32)); + int nread = fread(*ints, sizeof(u32), nints, stream); + assert(nread == nints); + return nread; +} + +void load_mdl(FILE *in, struct model *model, struct mdl_geometry *lgeom) +{ + struct make_geometry *mkgeom = &lgeom->mkgeom; + int num; + + while (1) { + enum mdl_tag tag = read_tag(in); + if (feof(in)) + break; + debug("tag %d\n", tag); + assert(tag < N_MDL_TAGS); + + switch (tag) { + case MDL_POSITION: + mkgeom->num_verts = read_floats(in, &mkgeom->vertices); + break; + + case MDL_NORMAL: + num = read_floats(in, &mkgeom->normals); + assert(num == mkgeom->num_verts); + break; + + case MDL_COLOR: + num = read_floats(in, &mkgeom->colors); + assert(num == mkgeom->num_verts); + break; + + case MDL_INDEX: + mkgeom->num_indices = read_ints(in, &mkgeom->indices); + break; + + case MDL_JOINT_IDS: + mkgeom->num_joint_ids = read_ints(in, &mkgeom->joint_ids); + break; + + case MDL_JOINT_WEIGHTS: + mkgeom->num_weights = read_floats(in, &mkgeom->joint_weights); + break; + case MDL_TEX_COORD: + read_floats(in, &mkgeom->tex_coords); + break; + case MDL_MAX: read_nfloats(in, 3, lgeom->max); break; + case MDL_MIN: read_nfloats(in, 3, lgeom->min); break; + case N_MDL_TAGS: assert(!"this shouldn't happend"); break; + } + } } diff --git a/src/mdl.h b/src/mdl.h @@ -5,6 +5,29 @@ #include "geometry.h" #include "model.h" -void save_mdl(struct model *model, struct make_geometry *geom); +enum mdl_tag { + MDL_POSITION = 1, + MDL_NORMAL, + MDL_COLOR, + MDL_INDEX, + MDL_TEX_COORD, + MDL_JOINT_IDS, + MDL_JOINT_WEIGHTS, + MDL_MIN, + MDL_MAX, + N_MDL_TAGS +}; + +struct mdl_geometry { + float min[3]; + float max[3]; + struct make_geometry mkgeom; +}; + + +void save_mdl(FILE *out, struct model *model, struct mdl_geometry *geom); +void load_mdl(FILE *in, struct model *model, struct mdl_geometry *geom); + +void init_mdl_geometry(struct mdl_geometry *); #endif /* MDL_H */ diff --git a/src/ply.c b/src/ply.c @@ -4,6 +4,7 @@ #include <string.h> #include <stdlib.h> #include "file.h" +#include "mdl.h" #include "common.h" #include "ply.h" #include "vec3.h" @@ -101,7 +102,22 @@ static int parse_magic(const char **cursor) { } -int parse_ply(const char *filename, struct geometry *geom) { +int parse_ply(const char *filename, struct geometry *geom) +{ + struct mdl_geometry mdlgeom; + init_mdl_geometry(&mdlgeom); + struct make_geometry *mkgeom = &mdlgeom.mkgeom; + + int ok = parse_ply_with_mkgeom(filename, &mdlgeom); + + make_buffer_geometry(mkgeom, geom); + free_make_geometry(mkgeom); + + return ok; +} + +int parse_ply_with_mkgeom(const char *filename, struct mdl_geometry *mdlgeom) +{ size_t len; int success = 0; int nverts = 0; @@ -111,11 +127,10 @@ int parse_ply(const char *filename, struct geometry *geom) { int cvert = 0; int cind = 0; + struct make_geometry *mkgeom = &mdlgeom->mkgeom; enum ply_state state = PLY_MAGIC; const char *data = file_contents(filename, &len); const char *p = data; - struct make_geometry mkgeom; - init_make_geometry(&mkgeom); float vert[3], norm[3], min[3], max[3]; int inds[3]; @@ -142,10 +157,10 @@ int parse_ply(const char *filename, struct geometry *geom) { break; } - mkgeom.vertices = calloc(nverts * 3, sizeof(*mkgeom.vertices)); - mkgeom.normals = calloc(nverts * 3, sizeof(*mkgeom.normals)); - mkgeom.colors = calloc(nverts * 3, sizeof(*mkgeom.colors)); - mkgeom.indices = calloc(ninds * 3, sizeof(*mkgeom.indices)); + mkgeom->vertices = calloc(nverts * 3, sizeof(*mkgeom->vertices)); + mkgeom->normals = calloc(nverts * 3, sizeof(*mkgeom->normals)); + mkgeom->colors = calloc(nverts * 3, sizeof(*mkgeom->colors)); + mkgeom->indices = calloc(ninds * 3, sizeof(*mkgeom->indices)); state = PLY_VERTICES; } @@ -168,17 +183,17 @@ int parse_ply(const char *filename, struct geometry *geom) { vec3_max(vert, max, max); } - mkgeom.vertices[cvert * 3] = vert[0]; - mkgeom.vertices[cvert * 3 + 1] = vert[1]; - mkgeom.vertices[cvert * 3 + 2] = vert[2]; + mkgeom->vertices[cvert * 3] = vert[0]; + mkgeom->vertices[cvert * 3 + 1] = vert[1]; + mkgeom->vertices[cvert * 3 + 2] = vert[2]; - mkgeom.normals[cvert * 3] = norm[0]; - mkgeom.normals[cvert * 3 + 1] = norm[1]; - mkgeom.normals[cvert * 3 + 2] = norm[2]; + mkgeom->normals[cvert * 3] = norm[0]; + mkgeom->normals[cvert * 3 + 1] = norm[1]; + mkgeom->normals[cvert * 3 + 2] = norm[2]; - mkgeom.colors[cvert * 3] = color[0] / 255.0; - mkgeom.colors[cvert * 3 + 1] = color[1] / 255.0; - mkgeom.colors[cvert * 3 + 2] = color[2] / 255.0; + mkgeom->colors[cvert * 3] = color[0] / 255.0; + mkgeom->colors[cvert * 3 + 1] = color[1] / 255.0; + mkgeom->colors[cvert * 3 + 2] = color[2] / 255.0; cvert++; @@ -194,9 +209,9 @@ int parse_ply(const char *filename, struct geometry *geom) { break; } - mkgeom.indices[cind * 3] = inds[0]; - mkgeom.indices[cind * 3 + 1] = inds[1]; - mkgeom.indices[cind * 3 + 2] = inds[2]; + mkgeom->indices[cind * 3] = inds[0]; + mkgeom->indices[cind * 3 + 1] = inds[1]; + mkgeom->indices[cind * 3 + 2] = inds[2]; cind++; @@ -222,20 +237,11 @@ int parse_ply(const char *filename, struct geometry *geom) { free((void*)data); if (success) { - assert(geom); - - mkgeom.num_indices = ninds * 3; - mkgeom.num_verts = nverts * 3; - - make_buffer_geometry(&mkgeom, geom); - - vec3_copy(min, geom->min); - vec3_copy(max, geom->max); + mkgeom->num_indices = ninds * 3; + mkgeom->num_verts = nverts * 3; - free(mkgeom.vertices); - free(mkgeom.normals); - free(mkgeom.colors); - free(mkgeom.indices); + vec3_copy(min, mdlgeom->min); + vec3_copy(max, mdlgeom->max); } return success; diff --git a/src/ply.h b/src/ply.h @@ -3,8 +3,9 @@ #ifndef PLYPARSER_H #define PLYPARSER_H -#include "geometry.h" +#include "mdl.h" int parse_ply(const char *filename, struct geometry *geom); +int parse_ply_with_mkgeom(const char *filename, struct mdl_geometry *mdlgeom); #endif /* PLYPARSER_H */ diff --git a/src/update.c b/src/update.c @@ -93,7 +93,7 @@ static void player_terrain_collision(struct terrain *terrain, struct entity *pla static vec3 last_pos[3] = {0}; struct node *node = get_node(&player->node_id); - if (!vec3_eq(node->pos, last_pos, 0.0001)) { + if (!vec3_approxeq(node->pos, last_pos)) { float player_z = node->pos[2]; float terrain_z = diff --git a/src/vbo.c b/src/vbo.c @@ -69,7 +69,7 @@ struct vbo* make_float_vertex_buffer(struct vbo *vbo, const void *data, } -struct vbo* make_int_vertex_buffer(struct vbo *vbo, const int *data, +struct vbo* make_int_vertex_buffer(struct vbo *vbo, const u32 *data, struct num_elements num_elements, struct components components) { diff --git a/src/vbo.h b/src/vbo.h @@ -62,7 +62,7 @@ struct vbo * make_uv_buffer(struct vbo *vbo, struct components); struct vbo * -make_int_vertex_buffer(struct vbo *vbo, const int *data, +make_int_vertex_buffer(struct vbo *vbo, const u32 *data, struct num_elements num_elements, struct components components); diff --git a/src/vec3.h b/src/vec3.h @@ -28,5 +28,8 @@ vec3 *vec3_add(vec3 *vec, vec3 *vec2, vec3 *dest); int vec3_eq(vec3 *a, vec3 *b, float precision); void vec3_copy(vec3 *a, vec3 *dest); +#define EPSILON 0.0001 +#define vec3_approxeq(a, b) vec3_eq(a, b, EPSILON) + #endif /* VEC3_H */ diff --git a/test/test_dae.c b/test/test_dae.c @@ -1,28 +1,20 @@ #include "animation.h" #include "util.h" +#include "ply.h" +#include "mdl.h" +#include "vec3.h" #include "debug.h" #include <assert.h> #include <stdio.h> #include "dae.h" -int main(int argc, char *argv[]) +static void test_load_pose(struct model *model) { - 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_dae("data/models/pirate-officer.dae", &model, &geom); - assert(model.nposes == 1); - pose = &model.poses[0]; + printf("test_load_pose\n"); + assert(model->nposes == 1); + struct pose *pose = &model->poses[0]; debug("pose->nweights %d\n", pose->nweights); assert(pose->nweights == 389); @@ -32,8 +24,8 @@ int main(int argc, char *argv[]) assert(pose->njoints == 11); - joint = &pose->joints[0]; - node = get_node(&joint->node_id); + struct joint *joint = &pose->joints[0]; + struct node *node = get_node(&joint->node_id); assert(node); assert(approxeq(node->mat[0], 0.999897)); @@ -43,6 +35,51 @@ int main(int argc, char *argv[]) assert(approxeq(node->mat[1], -0.01434187)); assert(pose->joints[0].n_children_ids == 3); +} + +static void test_save_mdl() +{ + printf("test_save_mdl\n"); + struct model model, model2; + struct mdl_geometry mg, mg2; + + init_model(&model); + init_mdl_geometry(&mg); + init_model(&model2); + init_mdl_geometry(&mg2); + + const char *filename = "data/models/pirate_officer.ply"; + parse_ply_with_mkgeom(filename, &mg); + + FILE *out = fopen("/tmp/test.mdl", "wb"); + save_mdl(out, &model, &mg); + fclose(out); + + out = fopen("/tmp/test.mdl", "rb"); + load_mdl(out, &model2, &mg2); + + assert(model.nposes == model2.nposes); + assert(vec3_approxeq(mg.min, mg2.min)); + assert(vec3_approxeq(mg.max, mg2.max)); +} + +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_dae("data/models/pirate-officer.dae", &model, &geom); + + test_load_pose(&model); + test_save_mdl(&model); return 0; }