polyadvent

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

commit 17d00c8004ddb16ea5f75c323c86507a5d918ea7
parent a89e975fc593d70d429ddf5872cf9d9cac54af6c
Author: William Casarin <jb55@jb55.com>
Date:   Mon, 22 Jul 2019 09:53:05 -0700

collision: switch to triangulated vertices

but getting some really weird issues. it works fine when the player X coordinate
is around 1500 and the Y coordinate is around 7000-8000, but otherwise exibits
some very strange behavior.

I looked at the code for a good two hours and couldn't make any sense of it. My
suspicion is that there was something wrong with the grid indexing, but that
doesn't explain why it worked with the poisson sample points.

Diffstat:
Mmain.c | 3++-
Msrc/game.c | 2+-
Msrc/model.c | 23++++++++++++++++++++---
Msrc/model.h | 2++
Msrc/render.c | 1+
Msrc/terrain.c | 64+++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/terrain.h | 2+-
Msrc/update.c | 8++++----
8 files changed, 72 insertions(+), 33 deletions(-)

diff --git a/main.c b/main.c @@ -30,7 +30,8 @@ int main(void) { int nsamples; - int seed = time(NULL); + /* int seed = time(NULL); */ + int seed = 42; debug("seed %d\n", seed); srand(seed); diff --git a/src/game.c b/src/game.c @@ -182,7 +182,7 @@ void game_init(struct game *game, int width, int height) { assert(res->player_id.index == entity_player); struct model *pmodel; - player->model_id = get_static_model(model_barrel, &pmodel); + player->model_id = get_static_model(model_pirate_officer, &pmodel); node_set_label(pnode, "player"); /* node_rotate(pnode, V3(-5.0,0,0)); */ diff --git a/src/model.c b/src/model.c @@ -124,10 +124,27 @@ void destroy_model(model_id *model_id) model_id get_static_model(enum static_model m, struct model **model) { - if (model) - *model = load_static_model(m); + model_id model_id; - return make_static_id(m); + if (!is_static_model_loaded(m)) { + load_static_model(m); + } + + model_id = make_static_id(m); + + if (model) { + *model = get_model(&model_id); + } + + return model_id; +} + + +bool is_static_model_loaded(enum static_model m) +{ + geometry_id geom_id = make_static_id(m); + struct geometry *geom = get_geometry(&geom_id); + return geom->has_vbos; } diff --git a/src/model.h b/src/model.h @@ -47,6 +47,8 @@ struct model *new_model(model_id *); struct model *new_static_model(model_id *); void destroy_model(model_id *); +bool is_static_model_loaded(enum static_model); + model_id get_static_model(enum static_model, struct model**); #endif /* MODEL_H */ diff --git a/src/render.c b/src/render.c @@ -361,6 +361,7 @@ void render (struct game *game, struct render_config *config) { struct model *model = get_model(&entity->model_id); assert(model); struct geometry *geo = get_geometry(&model->geom_id); + /* debug("geo node %s\n", node->label); */ assert(geo); render_geometry(geo, res->vertex_attrs, current_program); check_gl(); diff --git a/src/terrain.c b/src/terrain.c @@ -111,13 +111,15 @@ static inline struct terrain_cell *index_terrain_cell(struct terrain *terrain, if (x < 0 || y < 0 || x >= terrain->n_cells || y >= terrain->n_cells) return NULL; - return &terrain->grid[x * terrain->n_cells + y]; + return &terrain->grid[y * terrain->n_cells + x]; } static inline struct terrain_cell *query_terrain_cell(struct terrain *terrain, float x, float y, int *grid_x, int *grid_y) { + assert(x >= 0); + assert(y >= 0); assert(x < terrain->size); assert(y < terrain->size); *grid_x = x / terrain->cell_size; @@ -149,6 +151,21 @@ void query_terrain_grid(struct terrain *terrain, float x, float y, cells[8] = index_terrain_cell(terrain, grid_x + 1, grid_y + 1); } +static void insert_grid_vertex(struct terrain_cell *cell, float *verts, + float x, float y, int ind) +{ + for (int i = 0; i < cell->vert_count; i++) { + float *vert = &verts[ind]; + if (approxeq(x, vert[0]) && approxeq(y, vert[1])) { + return; + } + } + + assert(cell->vert_count + 1 <= MAX_CELL_VERTS); + cell->verts_index[cell->vert_count++] = ind; +} + + void create_terrain(struct terrain *terrain, float scale, int seed) { u32 i; const double size = terrain->size; @@ -165,9 +182,8 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { del_point2d_t *points = calloc(terrain->n_samples, sizeof(*points)); float *verts = calloc(terrain->n_samples * 3, sizeof(*verts)); - terrain->verts = verts; - terrain->n_cells = round(size / pdist); terrain->cell_size = pdist; + terrain->n_cells = round(size / terrain->cell_size); debug("n_cells %d\n", terrain->n_cells); assert(terrain->n_cells == 417); @@ -189,16 +205,7 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { x = terrain->samples[i].x; y = terrain->samples[i].y; - int grid_x = x / pdist; - int grid_y = y / pdist; - - /* debug("grid %f %f %d %d\n", x, y, grid_x, grid_y); */ - struct terrain_cell *cell = &grid[grid_x * terrain->n_cells + grid_y]; - - assert(cell->vert_count + 1 <= MAX_CELL_VERTS); - double z = terrain->fn(terrain, x, y); - cell->verts_index[cell->vert_count++] = i; points[i].x = x; points[i].y = y; @@ -223,6 +230,7 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { /// XXX (perf): we should be able to do this directly from del instead of /// triangulating with tri + debug("terrain n_tris %d\n", tri->num_triangles); for (i = 0; i < tri->num_triangles; ++i) { int nv = i * 3; int ndv = i * 9; @@ -239,17 +247,24 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { &verts[p[2]*3] }; - del_verts[ndv+0] = v[0][0]; - del_verts[ndv+1] = v[0][1]; - del_verts[ndv+2] = v[0][2]; + for (int j = 0; j < 3; j++) { + int ind = ndv + j*3; + float x = del_verts[ind+0] = v[j][0]; + float y = del_verts[ind+1] = v[j][1]; + del_verts[ind+2] = v[j][2]; + + int grid_x = x / terrain->cell_size; + int grid_y = y / terrain->cell_size; - del_verts[ndv+3] = v[1][0]; - del_verts[ndv+4] = v[1][1]; - del_verts[ndv+5] = v[1][2]; + /* if (i > 169000) */ + /* debug("grid %f %f %d %d\n", x, y, grid_x, grid_y); */ + struct terrain_cell *cell = + index_terrain_cell(terrain, grid_x, grid_y); - del_verts[ndv+6] = v[2][0]; - del_verts[ndv+7] = v[2][1]; - del_verts[ndv+8] = v[2][2]; + assert(cell); + + insert_grid_vertex(cell, del_verts, x, y, ind); + } // normals vec3_subtract(v[1], v[0], tmp1); @@ -295,8 +310,11 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { free(points); // needed for collision - /* free(verts); */ - free(del_verts); + free(verts); + /* free(del_verts); */ + + terrain->verts = del_verts; + terrain->n_verts = num_verts; // we might need norms in memory eventually as well ? free(del_norms); diff --git a/src/terrain.h b/src/terrain.h @@ -6,7 +6,7 @@ #include "entity.h" #include "model.h" -#define MAX_CELL_VERTS 3 +#define MAX_CELL_VERTS 4 struct point; diff --git a/src/update.c b/src/update.c @@ -334,7 +334,7 @@ static void player_update(struct game *game, struct entity *player) player_terrain_collision(terrain, player); node_recalc(node); - query_terrain_grid(terrain, node->pos[0], node->pos[1], cells); + query_terrain_grid(terrain, node->mat[M_X], node->mat[M_Y], cells); for (int i = 0; i < ARRAY_SIZE(cells); i++) { struct terrain_cell *cell = cells[i]; @@ -350,11 +350,11 @@ static void player_update(struct game *game, struct entity *player) ent->model_id = get_static_model(model_barrel, NULL); struct node *enode = get_node(&ent->node_id); node_set_label(enode, "grid_debug");; - assert(cell->verts_index[j] < terrain->n_samples); - float *vert = &terrain->verts[cell->verts_index[j] * 3]; + assert(cell->verts_index[j] < terrain->n_verts); + float *vert = &terrain->verts[cell->verts_index[j]]; debug("creating new grid_debug entity at %f %f %f\n", vert[0], vert[1], vert[2]); vec3_copy(vert, enode->pos); - node_scale(enode, 5.0); + node_scale(enode, 25.0); node_mark_for_recalc(enode); node_recalc(enode); }