From 6ad6cf2cb2e82d8dcc1535a031a38eb991d2b396 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sat, 23 Feb 2019 21:10:17 +0200 Subject: [PATCH] writing a mesh abstraction --- src/cmesh.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cmesh.h | 117 ++++++++++++++++++++++++++++++++ src/dynarr.c | 141 ++++++++++++++++++++++++++++++++++++++ src/dynarr.h | 80 ++++++++++++++++++++++ src/game.c | 3 + src/gamescr.c | 76 +++++++++++++++++++++ src/menuscr.c | 76 +++++++++++++++++++++ src/opt.c | 29 ++++++-- src/opt.h | 1 + src/screen.c | 18 ++++- src/screen.h | 11 ++- 11 files changed, 746 insertions(+), 14 deletions(-) create mode 100644 src/cmesh.c create mode 100644 src/cmesh.h create mode 100644 src/dynarr.c create mode 100644 src/dynarr.h create mode 100644 src/gamescr.c create mode 100644 src/menuscr.c diff --git a/src/cmesh.c b/src/cmesh.c new file mode 100644 index 0000000..6d7b0f4 --- /dev/null +++ b/src/cmesh.c @@ -0,0 +1,208 @@ +#include +#include +#include "opengl.h" +#include "cmesh.h" + + +struct cmesh_vattrib { + int nelem; /* num elements per attribute [1, 4] */ + float *data; /* dynarr */ + unsigned int vbo; + int vbo_valid, data_valid; +}; + + +struct cmesh { + char *name; + unsigned int nverts, nfaces; + + /* current value for each attribute for the immediate mode interface */ + cgm_vec4 cur_val[CMESH_NUM_ATTR]; + + unsigned int buffer_objects[CMESH_NUM_ATTR + 1]; + struct cmesh_vattrib vattr[CMESH_NUM_ATTR]; + + unsigned int *idata; /* dynarr */ + unsigned int ibo; + int ibo_valid, idata_valid; + + /* index buffer for wireframe rendering (constructed on demand) */ + unsigned int wire_ibo; + int wire_ibo_valid; + + /* axis-aligned bounding box */ + cgm_vec3 aabb_min, aabb_max; + int aabb_valid; + /* bounding sphere */ + cgm_vec3 bsph_center; + float bsph_radius; + int bsph_valid; +}; + +static int sdr_loc[CMESH_NUM_ATTR] = {0, 1, 2, 3, 4, 5, 6, 7}; + + +/* global state */ +void cmesh_set_attrib_sdrloc(int attr, int loc) +{ + sdr_loc[attr] = loc; +} + +int cmesh_get_attrib_sdrloc(int attr) +{ + return sdr_loc[attr]; +} + +void cmesh_clear_attrib_sdrloc(void) +{ + int i; + for(i=0; ibuffer_objects); + + for(i=0; ivattr[i].data = dynarr_alloc(0, sizeof(float)))) { + cmesh_destroy(cm); + return -1; + } + cm->vattr[i].vbo = buffer_objects[i]; + } + + cm->ibo = buffer_objects[CMESH_NUM_ATTR]; + if(!(cm->idata = dynarr_alloc(0, sizeof *cm->idata))) { + cmesh_destroy(cm); + return -1; + } + return 0; +} + +void cmesh_destroy(struct cmesh *cm) +{ + int i; + + for(i=0; ivattr[i].data); + } + dynarr_free(cm->idata); + + glDeleteBuffers(CMESH_NUM_ATTR + 1, cm->buffer_objects); + if(cm->wire_ibo) { + glDeleteBuffers(1, &cm->wire_ibo); + } +} + +void cmesh_clear(struct cmesh *cm) +{ + memset(cm, 0, sizeof *cm); + + cgm_wcons(cm->cur_val + CMESH_ATTR_COLOR, 1, 1, 1, 1); + /* TODO */ +} + +void cmesh_copy(struct cmesh *cmdest, struct cmesh *cmsrc); + +void cmesh_set_name(struct cmesh *cm, const char *name); +const char *cmesh_name(struct cmesh *cm); + +int cmesh_has_attrib(struct cmesh *cm, int attr); +int cmesh_indexed(struct cmesh *cm); + +/* vdata can be 0, in which case only memory is allocated + * returns pointer to the attribute array + */ +float *cmesh_set_attrib(struct cmesh *cm, int attr, int nelem, unsigned int num, + const float *vdata); +float *cmesh_attrib(struct cmesh *cm, int attr); /* invalidates VBO */ +const float *cmesh_attrib_ro(struct cmesh *cm, int attr); /* doesn't invalidate */ +int cmesh_attrib_count(struct cmesh *cm, int attr); + +/* indices can be 0, in which case only memory is allocated + * returns pointer to the index array + */ +unsigned int *cmesh_set_index(struct cmesh *cm, int num, const unsigned int *indices); +unsigned int *cmesh_index(struct cmesh *cm); /* invalidates IBO */ +const unsigned int *cmesh_index_ro(struct cmesh *cm); /* doesn't invalidate */ +int cmesh_index_count(struct cmesh *cm); + +int get_poly_count(struct cmesh *cm); + +/* attr can be -1 to invalidate all attributes */ +void cmesh_invalidate_attrib(struct cmesh *cm, int attr); +void cmesh_invalidate_index(struct cmesh *cm); + +int cmesh_append(struct cmesh *cmdest, struct cmesh *cmsrc); + +/* immediate-mode style mesh construction interface */ +int cmesh_vertex(struct cmesh *cm, float x, float y, float z); +int cmesh_normal(struct cmesh *cm, float nx, float ny, float nz); +int cmesh_tangent(struct cmesh *cm, float tx, float ty, float tz); +int cmesh_texcoord(struct cmesh *cm, float u, float v, float w); +int cmesh_boneweights(struct cmesh *cm, float w1, float w2, float w3, float w4); +int cmesh_boneidx(struct cmesh *cm, int idx1, int idx2, int idx3, int idx4); + +/* dir_xform can be null, in which case it's calculated from xform */ +void cmesh_apply_xform(struct cmesh *cm, float *xform, float *dir_xform); + +void cmesh_flip(struct cmesh *cm); /* flip faces (winding) and normals */ +void cmesh_flip_faces(struct cmesh *cm); +void cmesh_flip_normals(struct cmesh *cm); + +void cmesh_explode(struct cmesh *cm); /* undo all vertex sharing */ + +/* this is only guaranteed to work on an exploded mesh */ +void cmesh_calc_face_normals(struct cmesh *cm); + +void cmesh_draw(struct cmesh *cm); +void cmesh_draw_wire(struct cmesh *cm, float linesz); +void cmesh_draw_vertices(struct cmesh *cm, float ptsz); +void cmesh_draw_normals(struct cmesh *cm, float len); +void cmesh_draw_tangents(struct cmesh *cm, float len); + +/* get the bounding box in local space. The result will be cached and subsequent + * calls will return the same box. The cache gets invalidated by any functions that + * can affect the vertex data + */ +void cmesh_aabbox(struct cmesh *cm, cgm_vec3 *vmin, cgm_vec3 *vmax); + +/* get the bounding sphere in local space. The result will be cached ... see above */ +float cmesh_bsphere(struct cmesh *cm, cgm_vec3 *center, float *rad); + +/* texture coordinate manipulation */ +void cmesh_texcoord_apply_xform(struct cmesh *cm, float *xform); +void cmesh_texcoord_gen_plane(struct cmesh *cm, cgm_vec3 *norm, cgm_vec3 *tang); +void cmesh_texcoord_gen_box(struct cmesh *cm); +void cmesh_texcoord_gen_cylinder(struct cmesh *cm); + +int cmesh_dump(struct cmesh *cm, const char *fname); +int cmesh_dump_file(struct cmesh *cm, FILE *fp); +int cmesh_dump_obj(struct cmesh *cm, const char *fname); +int cmesh_dump_obj_file(struct cmesh *cm, FILE *fp, int voffs); diff --git a/src/cmesh.h b/src/cmesh.h new file mode 100644 index 0000000..4531d0b --- /dev/null +++ b/src/cmesh.h @@ -0,0 +1,117 @@ +#ifndef CMESH_H_ +#define CMESH_H_ + +#include +#include +#include "dynarr.h" + +enum { + CMESH_ATTR_VERTEX, + CMESH_ATTR_NORMAL, + CMESH_ATTR_TANGENT, + CMESH_ATTR_TEXCOORD, + CMESH_ATTR_COLOR, + CMESH_ATTR_BONEWEIGHTS, + CMESH_ATTR_BONEIDX, + CMESH_ATTR_TEXCOORD2, + + CMESH_NUM_ATTR +}; + +struct cmesh; + +/* global state */ +void cmesh_set_attrib_sdrloc(int attr, int loc); +int cmesh_get_attrib_sdrloc(int attr); +void cmesh_clear_attrib_sdrloc(void); + +/* mesh functions */ +struct cmesh *cmesh_alloc(void); +void cmesh_free(struct cmesh *cm); + +int cmesh_init(struct cmesh *cm); +void cmesh_destroy(struct cmesh *cm); + +void cmesh_clear(struct cmesh *cm); +void cmesh_copy(struct cmesh *cmdest, struct cmesh *cmsrc); + +void cmesh_set_name(struct cmesh *cm, const char *name); +const char *cmesh_name(struct cmesh *cm); + +int cmesh_has_attrib(struct cmesh *cm, int attr); +int cmesh_indexed(struct cmesh *cm); + +/* vdata can be 0, in which case only memory is allocated + * returns pointer to the attribute array + */ +float *cmesh_set_attrib(struct cmesh *cm, int attr, int nelem, unsigned int num, + const float *vdata); +float *cmesh_attrib(struct cmesh *cm, int attr); /* invalidates VBO */ +const float *cmesh_attrib_ro(struct cmesh *cm, int attr); /* doesn't invalidate */ +int cmesh_attrib_count(struct cmesh *cm, int attr); + +/* indices can be 0, in which case only memory is allocated + * returns pointer to the index array + */ +unsigned int *cmesh_set_index(struct cmesh *cm, int num, const unsigned int *indices); +unsigned int *cmesh_index(struct cmesh *cm); /* invalidates IBO */ +const unsigned int *cmesh_index_ro(struct cmesh *cm); /* doesn't invalidate */ +int cmesh_index_count(struct cmesh *cm); + +int get_poly_count(struct cmesh *cm); + +/* attr can be -1 to invalidate all attributes */ +void cmesh_invalidate_attrib(struct cmesh *cm, int attr); +void cmesh_invalidate_index(struct cmesh *cm); + +int cmesh_append(struct cmesh *cmdest, struct cmesh *cmsrc); + +/* immediate-mode style mesh construction interface */ +int cmesh_vertex(struct cmesh *cm, float x, float y, float z); +int cmesh_normal(struct cmesh *cm, float nx, float ny, float nz); +int cmesh_tangent(struct cmesh *cm, float tx, float ty, float tz); +int cmesh_texcoord(struct cmesh *cm, float u, float v, float w); +int cmesh_boneweights(struct cmesh *cm, float w1, float w2, float w3, float w4); +int cmesh_boneidx(struct cmesh *cm, int idx1, int idx2, int idx3, int idx4); + +/* dir_xform can be null, in which case it's calculated from xform */ +void cmesh_apply_xform(struct cmesh *cm, float *xform, float *dir_xform); + +void cmesh_flip(struct cmesh *cm); /* flip faces (winding) and normals */ +void cmesh_flip_faces(struct cmesh *cm); +void cmesh_flip_normals(struct cmesh *cm); + +void cmesh_explode(struct cmesh *cm); /* undo all vertex sharing */ + +/* this is only guaranteed to work on an exploded mesh */ +void cmesh_calc_face_normals(struct cmesh *cm); + +void cmesh_draw(struct cmesh *cm); +void cmesh_draw_wire(struct cmesh *cm, float linesz); +void cmesh_draw_vertices(struct cmesh *cm, float ptsz); +void cmesh_draw_normals(struct cmesh *cm, float len); +void cmesh_draw_tangents(struct cmesh *cm, float len); + +/* get the bounding box in local space. The result will be cached and subsequent + * calls will return the same box. The cache gets invalidated by any functions that + * can affect the vertex data + */ +void cmesh_aabbox(struct cmesh *cm, cgm_vec3 *vmin, cgm_vec3 *vmax); + +/* get the bounding sphere in local space. The result will be cached ... see above */ +float cmesh_bsphere(struct cmesh *cm, cgm_vec3 *center, float *rad); + +/* texture coordinate manipulation */ +void cmesh_texcoord_apply_xform(struct cmesh *cm, float *xform); +void cmesh_texcoord_gen_plane(struct cmesh *cm, cgm_vec3 *norm, cgm_vec3 *tang); +void cmesh_texcoord_gen_box(struct cmesh *cm); +void cmesh_texcoord_gen_cylinder(struct cmesh *cm); + +int cmesh_dump(struct cmesh *cm, const char *fname); +int cmesh_dump_file(struct cmesh *cm, FILE *fp); +int cmesh_dump_obj(struct cmesh *cm, const char *fname); +int cmesh_dump_obj_file(struct cmesh *cm, FILE *fp, int voffs); + + + +#endif /* CMESH_H_ */ diff --git a/src/dynarr.c b/src/dynarr.c new file mode 100644 index 0000000..59bbf8c --- /dev/null +++ b/src/dynarr.c @@ -0,0 +1,141 @@ +/* dynarr - dynamic resizable C array data structure + * author: John Tsiombikas + * license: public domain + */ +#include +#include +#include +#include "dynarr.h" + +/* The array descriptor keeps auxilliary information needed to manipulate + * the dynamic array. It's allocated adjacent to the array buffer. + */ +struct arrdesc { + int nelem, szelem; + int max_elem; + int bufsz; /* not including the descriptor */ +}; + +#define DESC(x) ((struct arrdesc*)((char*)(x) - sizeof(struct arrdesc))) + +void *dynarr_alloc(int elem, int szelem) +{ + struct arrdesc *desc; + + if(!(desc = malloc(elem * szelem + sizeof *desc))) { + return 0; + } + desc->nelem = desc->max_elem = elem; + desc->szelem = szelem; + desc->bufsz = elem * szelem; + return (char*)desc + sizeof *desc; +} + +void dynarr_free(void *da) +{ + if(da) { + free(DESC(da)); + } +} + +void *dynarr_resize(void *da, int elem) +{ + int newsz; + void *tmp; + struct arrdesc *desc; + + if(!da) return 0; + desc = DESC(da); + + newsz = desc->szelem * elem; + + if(!(tmp = realloc(desc, newsz + sizeof *desc))) { + return 0; + } + desc = tmp; + + desc->nelem = desc->max_elem = elem; + desc->bufsz = newsz; + return (char*)desc + sizeof *desc; +} + +int dynarr_empty(void *da) +{ + return DESC(da)->nelem ? 0 : 1; +} + +int dynarr_size(void *da) +{ + return DESC(da)->nelem; +} + + +void *dynarr_clear(void *da) +{ + return dynarr_resize(da, 0); +} + +/* stack semantics */ +void *dynarr_push(void *da, void *item) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(nelem >= desc->max_elem) { + /* need to resize */ + struct arrdesc *tmp; + int newsz = desc->max_elem ? desc->max_elem * 2 : 1; + + if(!(tmp = dynarr_resize(da, newsz))) { + fprintf(stderr, "failed to resize\n"); + return da; + } + da = tmp; + desc = DESC(da); + desc->nelem = nelem; + } + + if(item) { + memcpy((char*)da + desc->nelem * desc->szelem, item, desc->szelem); + } + desc->nelem++; + return da; +} + +void *dynarr_pop(void *da) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(!nelem) return da; + + if(nelem <= desc->max_elem / 3) { + /* reclaim space */ + struct arrdesc *tmp; + int newsz = desc->max_elem / 2; + + if(!(tmp = dynarr_resize(da, newsz))) { + fprintf(stderr, "failed to resize\n"); + return da; + } + da = tmp; + desc = DESC(da); + desc->nelem = nelem; + } + desc->nelem--; + + return da; +} + +void *dynarr_finalize(void *da) +{ + struct arrdesc *desc = DESC(da); + memmove(desc, da, desc->bufsz); + return desc; +} diff --git a/src/dynarr.h b/src/dynarr.h new file mode 100644 index 0000000..8690b5a --- /dev/null +++ b/src/dynarr.h @@ -0,0 +1,80 @@ +/* dynarr - dynamic resizable C array data structure + * author: John Tsiombikas + * license: public domain + */ +#ifndef DYNARR_H_ +#define DYNARR_H_ + +/* usage example: + * ------------- + * int *arr = dynarr_alloc(0, sizeof *arr); + * + * int x = 10; + * arr = dynarr_push(arr, &x); + * x = 5; + * arr = dynarr_push(arr, &x); + * x = 42; + * arr = dynarr_push(arr, &x); + * + * for(i=0; i #include "screen.h" +#include "opt.h" + +/* defined in their respective screen source files */ +struct game_screen main_menu_screen; +struct game_screen game_screen; static struct game_screen *screens[16]; static int num_screens; @@ -7,12 +13,22 @@ static struct game_screen *stack; int init_screens(void) { - int i; + int i = 0; + + /* populate the screens */ + screens[i++] = &main_menu_screen; + screens[i++] = &game_screen; + num_screens = i; + + stack = screens[0]; for(i=0; iinit() == -1) { return -1; } + if(opt.start_scr && strcmp(screens[i]->name, opt.start_scr) == 0) { + stack = screens[i]; + } } return 0; } diff --git a/src/screen.h b/src/screen.h index 33897dc..95cf4df 100644 --- a/src/screen.h +++ b/src/screen.h @@ -15,13 +15,12 @@ struct game_screen { void (*update)(float dt); void (*draw)(void); + void (*reshape)(int, int); - /* these functions return 1 if they handled the event, or 0 - * if it should propagate to the next screen in the stack */ - int (*keyboard)(int, int); - int (*mouse)(int, int, int, int); - int (*motion)(int, int); - int (*wheel)(int dir); + void (*keyboard)(int, int); + void (*mouse)(int, int, int, int); + void (*motion)(int, int); + void (*wheel)(int dir); }; /* this always points to the top screen on the stack -- 1.7.10.4