polyadvent

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

commit 179af98488dfe706850dac9548ef9277b5df8519
parent 3d8c9a28872923363e9ca4940662d8cc4d11bbd1
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 27 Jul 2019 20:54:28 -0700

triangle collision progress

Diffstat:
Mmain.c | 1+
Msrc/debug.h | 2+-
Msrc/entity.c | 14+++++++++++++-
Msrc/entity.h | 1+
Msrc/game.c | 2++
Msrc/game.h | 1+
Msrc/render.c | 7+++++++
Msrc/terrain.c | 147++++++++++++++++++++++++++++---------------------------------------------------
Msrc/terrain.h | 27+++++++++++++++++++++++++++
Asrc/terrain_collision.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/terrain_collision.h | 11+++++++++++
Msrc/update.c | 26++++++++++++++------------
12 files changed, 268 insertions(+), 110 deletions(-)

diff --git a/main.c b/main.c @@ -95,6 +95,7 @@ int main(void) check_fbo(fbo); bind_fbo(fbo); /* glDrawBuffer(GL_NONE); */ + render(&game, &fbo_render_config); unbind_fbo(&game.test_resources.shadow_buffer); render(&game, &default_config); diff --git a/src/debug.h b/src/debug.h @@ -9,7 +9,7 @@ void show_info_log(GLuint shader); #define unusual(...) fprintf(stderr, "UNUSUAL: " __VA_ARGS__) #ifdef DEBUG -#define debug(...) fprintf(stderr, "debug: " __VA_ARGS__) +#define debug(...) fprintf(stderr, __VA_ARGS__) #else #define debug(...) #endif diff --git a/src/entity.c b/src/entity.c @@ -79,7 +79,6 @@ void destroy_entities() { void destroy_entity(entity_id *id) { struct entity *ent = get_entity(id); - assert(ent); if (ent == NULL) return; @@ -118,4 +117,17 @@ void init_entity_system() { } } +struct entity *new_debug_entity(entity_id *ent_id, float *pos) +{ + init_id(ent_id); + struct entity *ent = new_entity(ent_id); + ent->model_id = get_static_model(model_barrel, NULL); + struct node *enode = get_node(&ent->node_id); + node_set_label(enode, "debug"); + vec3_copy(pos, enode->pos); + node_scale(enode, 5.0); + node_mark_for_recalc(enode); + node_recalc(enode); + return ent; +} diff --git a/src/entity.h b/src/entity.h @@ -36,6 +36,7 @@ const char *entity_label(struct entity *); struct entity *get_all_entities(u32 *count, entity_id **ids); struct entity *new_entity_(entity_id *); struct entity *new_entity_with_node(entity_id *, node_id *); +struct entity *new_debug_entity(entity_id *, float *pos); void destroy_entity_system(); static inline struct entity *static_entities() diff --git a/src/game.c b/src/game.c @@ -93,6 +93,8 @@ void game_init(struct game *game, int width, int height) { init_user_settings(&game->user_settings); check_gl(); + game->wireframe = 0; + struct resources *res = &game->test_resources; mat4 *mvp = res->test_mvp; diff --git a/src/game.h b/src/game.h @@ -88,6 +88,7 @@ struct game { int counter; int seed; int quit; + int wireframe; float dt; u64 frame; struct user_settings user_settings; diff --git a/src/render.c b/src/render.c @@ -367,6 +367,13 @@ void render (struct game *game, struct render_config *config) { check_gl(); } + if (game->wireframe) { + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + } + else { + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + } + if (!config->is_depth_pass) { mat4_inverse((float*)camera, view); mat4_remove_translations(view); diff --git a/src/terrain.c b/src/terrain.c @@ -69,7 +69,7 @@ void init_terrain(struct terrain *terrain, float size) { ent->casts_shadows = 0; // this is scale for some reason!? - node->pos[2] = 20.0; + /* node->pos[2] = 20.0; */ reset_terrain(terrain, size); } @@ -105,11 +105,12 @@ void gen_terrain_samples(struct terrain *terrain, float scale, const double pdis } -static inline struct terrain_cell *index_terrain_cell(struct terrain *terrain, - int x, int y) +static inline struct terrain_cell *index_terrain_cell(struct terrain *terrain, int x, int y) { - if (x < 0 || y < 0 || x >= terrain->n_cells || y >= terrain->n_cells) + if (x < 0 || y < 0 || x >= terrain->n_cells || y >= terrain->n_cells) { + assert(!"terrain oob"); return NULL; + } return &terrain->grid[y * terrain->n_cells + x]; } @@ -122,8 +123,8 @@ static inline struct terrain_cell *query_terrain_cell(struct terrain *terrain, assert(y >= 0); assert(x < terrain->size); assert(y < terrain->size); - *grid_x = x / terrain->cell_size; - *grid_y = y / terrain->cell_size; + *grid_x = grid_index(terrain, x); + *grid_y = grid_index(terrain, y); return index_terrain_cell(terrain, *grid_x, *grid_y); } @@ -151,97 +152,45 @@ 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) +static void insert_grid_vertex(struct terrain_cell *cell, int ind) { assert(cell->vert_count + 1 <= MAX_CELL_VERTS); cell->verts_index[cell->vert_count++] = ind; } -static void collide_terrain_debug(struct terrain *terrain, struct terrain_cell *cell) +static int terrain_cell_debug(struct terrain *terrain, struct terrain_cell *cell, int ind, vec3 *pos) { - for (int j = 0; j < cell->vert_count; j++) { - entity_id *ent_id = &cell->debug_ent[j]; - - if (is_null_id(ent_id)) { - init_id(ent_id); - struct entity *ent = new_entity(ent_id); - 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_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_mark_for_recalc(enode); - node_recalc(enode); - } + int ok = 0; + entity_id *ent_id = &cell->debug_ent[ind]; + + if (is_null_id(ent_id)) { + assert(cell->verts_index[ind] < terrain->n_verts); + float *vert = &terrain->verts[cell->verts_index[ind]]; + int gx = grid_index(terrain, pos[0]); + int gy = grid_index(terrain, pos[1]); + int vgx = grid_index(terrain, vert[0]); + int vgy = grid_index(terrain, vert[1]); + debug("creating new grid_debug entity at %f %f %f, cell (%d, %d) vert_cell(%d, %d)\n", + vert[0], vert[1], vert[2], + gx, gy, vgx, vgy); + new_debug_entity(ent_id, vert); + ok |= 1; } + + return ok; } -static inline void get_closest_cells(struct terrain *terrain, - vec3 *pos, - struct terrain_cell *cell, - struct terrain_cell *closest_cells[3], - float closest[3]) +static int collide_terrain_debug(struct terrain *terrain, struct terrain_cell *cell, int ind, vec3 *pos) { + int ok = 0; for (int j = 0; j < cell->vert_count; j++) { - vec3 *vpos = &terrain->verts[cell->verts_index[j]]; - float d = vec3_distsq(pos, vpos); - - if (d < closest[0]) { - closest[2] = closest[1]; - closest[1] = closest[0]; - closest[0] = d; - - closest_cells[2] = closest_cells[1]; - closest_cells[1] = closest_cells[0]; - closest_cells[0] = cell; - } - else if (d < closest[1]) { - closest[2] = closest[1]; - closest[1] = d; - - closest_cells[2] = closest_cells[1]; - closest_cells[1] = cell; - } - else if (d < closest[2]) { - closest[2] = d; - closest_cells[2] = cell; - } + ok |= terrain_cell_debug(terrain, cell, ind, pos); } -} -void collide_terrain(struct terrain *terrain, struct node *node, struct model *model, vec3 *move) -{ - struct terrain_cell *cells[9]; - struct terrain_cell *closest_cells[3] = {0}; - float closest[3] = {FLT_MAX}; - - 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]; - if (!cell) - continue; - - collide_terrain_debug(terrain, cell); - - get_closest_cells(terrain, node_world(node), cell, closest_cells, closest); - - /* assert(closest_cells[0]); */ - /* assert(closest_cells[1]); */ - /* assert(closest_cells[2]); */ - - // safe bail here - if (closest_cells[2] == NULL || closest_cells[1] == NULL || closest_cells[0] == NULL) - return; - - - } + return ok; } + void create_terrain(struct terrain *terrain, float scale, int seed) { u32 i; const double size = terrain->size; @@ -288,17 +237,15 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { verts[n] = (float)x; verts[n+1] = (float)y; - int grid_x = x / terrain->cell_size; - int grid_y = y / terrain->cell_size; + int grid_x = verts[n] / terrain->cell_size; + int grid_y = verts[n+1] / terrain->cell_size; - /* 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); assert(cell); - insert_grid_vertex(cell, verts, x, y, n); + insert_grid_vertex(cell, n); static const double limit = 1.4; if (x < limit || x > size-limit || y < limit || y > size-limit) @@ -311,9 +258,11 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { tri_delaunay2d_t *tri = tri_delaunay2d_from(del); int num_verts = tri->num_triangles * 3; - float *del_verts = calloc(num_verts * 3, sizeof(*del_verts)); - float *del_norms = calloc(num_verts * 3, sizeof(*del_norms)); - u32 *del_indices = calloc(num_verts, sizeof(*del_indices)); + float *del_verts = malloc(num_verts * 3 * sizeof(*del_verts)); + float *del_norms = malloc(num_verts * 3 * sizeof(*del_norms)); + u32 *del_indices = malloc(num_verts * sizeof(*del_indices)); + struct vert_tris *vert_tris = calloc(num_verts, sizeof(struct vert_tris)); + terrain->vtris = vert_tris; /// XXX (perf): we should be able to do this directly from del instead of /// triangulating with tri @@ -323,18 +272,24 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { int ndv = i * 9; int p[3] = { - tri->tris[nv + 0], - tri->tris[nv + 1], - tri->tris[nv + 2], + tri->tris[nv + 0]*3, + tri->tris[nv + 1]*3, + tri->tris[nv + 2]*3, }; float *v[3] = { - &verts[p[0]*3], - &verts[p[1]*3], - &verts[p[2]*3] + &verts[p[0]], + &verts[p[1]], + &verts[p[2]] }; for (int j = 0; j < 3; j++) { + struct vert_tris *vtris = &vert_tris[p[j]/3]; + assert(vtris->tri_count + 1 < MAX_VERT_TRIS); + struct tri *t = &vtris->tris[vtris->tri_count++]; + assert(sizeof(p) == sizeof(t->vert_indices)); + memcpy(t->vert_indices, p, sizeof(p)); + int ind = ndv + j*3; del_verts[ind+0] = v[j][0]; del_verts[ind+1] = v[j][1]; diff --git a/src/terrain.h b/src/terrain.h @@ -5,8 +5,10 @@ #include "entity.h" #include "model.h" +#include "debug.h" #define MAX_CELL_VERTS 4 +#define MAX_VERT_TRIS 24 struct point; @@ -22,15 +24,30 @@ struct perlin_settings { double exp; }; +struct tri { +#ifdef DEBUG + entity_id debug_id; +#endif + int vert_indices[3]; +}; + +struct vert_tris { + u8 tri_count; + struct tri tris[MAX_VERT_TRIS]; +}; + struct terrain_cell { u8 vert_count; int verts_index[MAX_CELL_VERTS]; +#ifdef DEBUG entity_id debug_ent[MAX_CELL_VERTS]; +#endif }; struct terrain { entity_id entity_id; struct terrain_cell *grid; + struct vert_tris *vtris; int n_cells; // all cells = grid_cells^2 float cell_size; float *verts; @@ -55,4 +72,14 @@ void create_terrain(struct terrain *terrain, float scale, int seed); void destroy_terrain(struct terrain *terrain); void query_terrain_grid(struct terrain *terrain, float x, float y, struct terrain_cell *cells[9]); +static inline int grid_index(struct terrain *terrain, float x) { + return x / terrain->cell_size; +} + +static inline void grid_pos_debug(const char *thing, struct terrain *terrain, float *pos) { + int gx = grid_index(terrain, pos[0]); + int gy = grid_index(terrain, pos[1]); + debug("%s grid pos (%d, %d)\n", thing, gx, gy); +} + #endif /* POLYADVENT_TERRAIN_H */ diff --git a/src/terrain_collision.c b/src/terrain_collision.c @@ -0,0 +1,139 @@ + +#include "terrain_collision.h" + + +struct grid_query { + struct terrain_cell *cell; + int cell_vert_index; + float distance; +}; + +struct tri_query { + struct vert_tri *vtri; +}; + +static void get_closest_verts(struct terrain *terrain, + vec3 *pos, + struct grid_query closest[3], + struct terrain_cell *cells[9] + ) +{ + for (int i = 0; i < 9; i++) { + struct terrain_cell *cell = cells[i]; + for (int j = 0; j < cell->vert_count; j++) { + vec3 *vpos = &terrain->verts[cell->verts_index[j]]; + float d = vec3_distsq(pos, vpos); + + if (d < closest[0].distance) { + closest[2] = closest[1]; + closest[1] = closest[0]; + closest[0] = (struct grid_query) { + .distance = d, + .cell = cell, + .cell_vert_index = j + }; + } + else if (d < closest[1].distance) { + closest[2] = closest[1]; + closest[1] = (struct grid_query) { + .distance = d, + .cell = cell, + .cell_vert_index = j + }; + } + else if (d < closest[2].distance) { + closest[2].distance = d; + closest[2].cell_vert_index = j; + closest[2].cell = cell; + } + } + } +} + +static inline float sign (float *p1, float *p2, float *p3) +{ + return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]); +} + +bool point_in_tri(float *pt, float *v1, float *v2, float *v3) +{ + float d1, d2, d3; + bool has_neg, has_pos; + + d1 = sign(pt, v1, v2); + d2 = sign(pt, v2, v3); + d3 = sign(pt, v3, v1); + + has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0); + has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0); + + return !(has_neg && has_pos); +} + +static void get_closest_tris(struct terrain *terrain, struct vert_tris *vtris) +{ + +} + +static void terrain_tri_debug(float *verts, struct tri *tri) +{ + + if (is_null_id(&tri->debug_id)) { + + float tmp[3]; + + float *v1 = &verts[tri->vert_indices[0]]; + float *v2 = &verts[tri->vert_indices[1]]; + float *v3 = &verts[tri->vert_indices[2]]; + + /* debug("v1 %f,%f v2 %f,%f v3 %f,%f\n", */ + /* v1[0], v1[1], */ + /* v2[0], v2[1], */ + /* v3[0], v3[1]); */ + + vec3_subtract(v1, v2, tmp); + + /* debug("tmp %f %f\n", tmp[0], tmp[1]); */ + + vec3_scale(tmp, 0.5, tmp); + vec3_subtract(v1, tmp, tmp); + vec3_subtract(v3, tmp, tmp); + vec3_scale(tmp, 0.5, tmp); + vec3_subtract(v3, tmp, tmp); + + /* debug("creating new grid_debug entity at %f %f %f\n", tmp[0], tmp[1], tmp[2]); */ + + new_debug_entity(&tri->debug_id, tmp); + } + +} + +void collide_terrain(struct terrain *terrain, struct node *node, struct model *model, vec3 *move) +{ + struct terrain_cell *cells[9] = {0}; + struct grid_query queries[3]; + for (int i = 0; i < 3; i++) { + queries[i].distance = FLT_MAX; + queries[i].cell = NULL; + queries[i].cell_vert_index = -1; + } + + float *pos = node_world(node); + + query_terrain_grid(terrain, pos[0], pos[1], cells); + + get_closest_verts(terrain, pos, queries, cells); + + int closest_vind = queries[0].cell->verts_index[queries[0].cell_vert_index]; + struct vert_tris *vtris = &terrain->vtris[closest_vind / 3]; + + for (int i = 0; i < vtris->tri_count; i++) {; + /* terrain_cell_debug(terrain, queries[i].cell, queries[i].cell_vert_index, pos); */ + terrain_tri_debug(terrain->verts, &vtris->tris[i]); + } +} + + + /* assert(closest_cells[0]); */ + /* assert(closest_cells[1]); */ + /* assert(closest_cells[2]); */ diff --git a/src/terrain_collision.h b/src/terrain_collision.h @@ -0,0 +1,11 @@ + +#ifndef TERRAIN_COLLISION_H +#define TERRAIN_COLLISION_H + +#include "terrain.h" +#include "node.h" +#include "model.h" + +void collide_terrain(struct terrain *terrain, struct node *node, struct model *model, float *move); + +#endif /* TERRAIN_COLLISION_H */ diff --git a/src/update.c b/src/update.c @@ -59,11 +59,13 @@ static void movement(struct game *game, struct node *node, float speed_mult) { /* node_translate(node, V3(0, 0, -amt)); */ if (was_key_pressed_this_frame(game, SDL_SCANCODE_P)) { - printf("%f %f %f\n", + debug("%f %f %f ", node->pos[0], node->pos[1], node->pos[2]); - mat4_print(node->mat); + node_recalc(node); + grid_pos_debug(node->label, &game->terrain, node_world(node)); + /* mat4_print(node->mat); */ } } @@ -88,10 +90,9 @@ static void remap_samples(struct point *points, int n_samples, } } -static void player_terrain_collision(struct terrain *terrain, struct entity *player) { +static void player_terrain_collision(struct terrain *terrain, struct node *node) { // player movement static vec3 last_pos[3] = {0}; - struct node *node = get_node(&player->node_id); if (!vec3_approxeq(node->pos, last_pos)) { float player_z = node->pos[2]; @@ -242,7 +243,9 @@ static void gravity(struct game *game) { struct node *pnode = get_node(&player->node_id); assert(pnode); - node_translate(pnode, V3(0.0, 0.0, -1.0)); + static const float g = -1.0; + + node_translate(pnode, V3(0.0, 0.0, g)); } void orbit_update_from_mouse(struct orbit *camera, struct input *input, @@ -312,10 +315,6 @@ static void camera_keep_above_ground(struct terrain *terrain, } } -static void terrain_collision_debug(struct terrain *terrain, struct node *node) -{ -} - static void player_update(struct game *game, struct entity *player) { @@ -339,11 +338,10 @@ static void player_update(struct game *game, struct entity *player) struct terrain *terrain = &game->terrain; - player_terrain_collision(terrain, player); - - node_recalc(node); + player_terrain_collision(terrain, node); collide_terrain(terrain, node, NULL, NULL); + node_recalc(node); } @@ -395,6 +393,10 @@ void update (struct game *game) { try_reload_shaders(res); #endif + if (was_key_pressed_this_frame(game, SDL_SCANCODE_F5)) { + game->wireframe ^= 1; + } + if (was_key_pressed_this_frame(game, SDL_SCANCODE_C)) printf("light_dir %f %f %f\n", light[0], light[1], light[2]);