commit 179af98488dfe706850dac9548ef9277b5df8519
parent 3d8c9a28872923363e9ca4940662d8cc4d11bbd1
Author: William Casarin <jb55@jb55.com>
Date: Sat, 27 Jul 2019 20:54:28 -0700
triangle collision progress
Diffstat:
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]);