commit 1e59967d82b2bb62226bbabd3b365fecde31fcfb
parent e10fbec6715724f9d7f662d25846222e5c8f20bb
Author: William Casarin <jb55@jb55.com>
Date: Sun, 7 Jul 2019 02:13:39 -0700
mdl wip progress
Diffstat:
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;
}