From 32010751a69440b52780a4e570682f20b4ef70b2 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Fri, 1 Oct 2021 08:05:16 +0300 Subject: [PATCH] visibility determination --- src/game.c | 40 ++++++++++++++++--------------- src/level.c | 17 +++++++++++++- src/level.h | 5 ++++ src/player.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/player.h | 2 +- 5 files changed, 113 insertions(+), 25 deletions(-) diff --git a/src/game.c b/src/game.c index 64c00df..92843dc 100644 --- a/src/game.c +++ b/src/game.c @@ -124,36 +124,38 @@ void game_display(void) static void draw_level(void) { - int i, j, k; + int i; struct cell *cell; float xform[16]; glUseProgram(sdr_foo); - cell = lvl.cells; - for(i=0; itile) { - cgm_mrotation_y(xform, cell->tilerot * M_PI / 2.0f); + cell = player.vis; + while(cell) { + cgm_mtranslation(xform, cell->x * lvl.cell_size, 0, -cell->y * lvl.cell_size); - glPushMatrix(); - glMultMatrixf(xform); - draw_meshgroup(&cell->tile->mgrp); - glPopMatrix(); - } + glPushMatrix(); + glMultMatrixf(xform); - for(k=0; knum_mgrp; k++) { - draw_meshgroup(cell->mgrp + k); - } - cell++; + if(cell->tile) { + cgm_mrotation_y(xform, cell->tilerot * M_PI / 2.0f); + glPushMatrix(); + glMultMatrixf(xform); + draw_meshgroup(&cell->tile->mgrp); glPopMatrix(); } + + for(i=0; inum_mgrp; i++) { + draw_meshgroup(cell->mgrp + i); + } + glPopMatrix(); + + cell = cell->next; } glUseProgram(0); diff --git a/src/level.c b/src/level.c index c17c03a..5f7f77b 100644 --- a/src/level.c +++ b/src/level.c @@ -12,6 +12,9 @@ static int detect_cell_tile(struct level *lvl, int x, int y, int *rot); int init_level(struct level *lvl, int xsz, int ysz) { + int i, j; + struct cell *cell; + memset(lvl, 0, sizeof *lvl); if(!(lvl->cells = calloc(xsz * ysz, sizeof *lvl->cells))) { @@ -22,6 +25,18 @@ int init_level(struct level *lvl, int xsz, int ysz) lvl->height = ysz; lvl->cell_size = DEF_CELL_SIZE; lvl->px = lvl->py = -1; + + lvl->visdist = 4; + + /* assign cell coordinates */ + cell = lvl->cells; + for(i=0; ix = j; + cell->y = i; + cell++; + } + } return 0; } @@ -211,7 +226,7 @@ err: #ifndef LEVEL_EDITOR -static int get_cell_type(struct level *lvl, int x, int y) +int get_cell_type(struct level *lvl, int x, int y) { if(x < 0 || x >= lvl->width || y < 0 || y >= lvl->height) { return CELL_SOLID; diff --git a/src/level.h b/src/level.h index cbf6642..a5a2ae6 100644 --- a/src/level.h +++ b/src/level.h @@ -33,6 +33,7 @@ struct tile { }; struct cell { + int x, y; int type; int tiletype, tilerot; int wall[4]; @@ -59,6 +60,8 @@ struct level { * loaded, excluding meshes in tiles scenefiles */ struct mesh *meshlist; + + int visdist; }; @@ -73,4 +76,6 @@ struct tile *find_level_tile(struct level *lvl, int type); int gen_cell_geom(struct level *lvl, struct cell *cell); int gen_level_geom(struct level *lvl); +int get_cell_type(struct level *lvl, int x, int y); + #endif /* LEVEL_H_ */ diff --git a/src/player.c b/src/player.c index ab7d818..61a5989 100644 --- a/src/player.c +++ b/src/player.c @@ -1,5 +1,7 @@ #include "player.h" +static const int step[][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + void init_player(struct player *p) { memset(p, 0, sizeof *p); @@ -15,7 +17,7 @@ void init_player(struct player *p) void update_player_dir(struct player *p) { - int dir; + int prev_dir = p->dir; float angle; /* TODO: take vrot into account */ @@ -24,13 +26,15 @@ void update_player_dir(struct player *p) p->theta = angle; /* renormalize theta */ p->dir = (int)(4.0f * angle / TWO_PI + 0.5) & 3; + + if(p->dir != prev_dir) { + p->vis = 0; /* invalidate visibility list */ + } } void move_player(struct player *p, int right, int fwd) { - static const int step[][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; int fdir, rdir; - float angle; update_player_dir(p); @@ -38,6 +42,8 @@ void move_player(struct player *p, int right, int fwd) rdir = (fdir + 1) & 3; p->cx += step[fdir][0] * fwd + step[rdir][0] * right; p->cy += step[fdir][1] * fwd + step[rdir][1] * right; + + p->vis = 0; /* invalidate visibility list */ } void turn_player(struct player *p, int turn) @@ -48,6 +54,8 @@ void turn_player(struct player *p, int turn) update_player_dir(p); p->theta = (float)p->dir * HALF_PI; /* snap theta */ + + p->vis = 0; /* invalidate visibility list */ } void upd_player_xform(struct player *p) @@ -65,9 +73,67 @@ void upd_player_xform(struct player *p) cgm_mpretranslate(p->view_xform, -pos.x, -pos.y, -pos.z); } +static void vis_visit(struct player *p, int cx, int cy, int *cvis) +{ + int i, j, nx, ny, dx, dy; + struct level *lvl = p->lvl; + struct cell *cell; + + if(cx < 0 || cx >= lvl->width || cy < 0 || cy >= lvl->height) { + return; + } + cell = lvl->cells + cy * lvl->width + cx; + + /* stop when we encounter a solid cell */ + if(cell->type == CELL_SOLID) { + return; + } + + dx = cx - p->cx; + dy = cy - p->cy; + /* stop beyond the maximum visibility distance (manhattan) */ + if(abs(dx) > lvl->visdist || abs(dy) > lvl->visdist) { + return; + } + + /* dot product */ + if(step[p->dir][0] * dx + step[p->dir][1] * dy < 0) { + return; /* cell is behind the player */ + } + + cvis[cy * lvl->width + cx] = 1; /* mark as visited before recursing */ + + /* visit neighboring nodes before adding current cell */ + for(i=0; i<3; i++) { + ny = cy - 1 + i; + if(ny < 0) continue; + if(ny >= lvl->height) break; + + for(j=0; j<3; j++) { + if(i == 1 && j == 1) continue; + nx = cx - 1 + j; + if(nx < 0) continue; + if(nx >= lvl->width) break; + + if(!cvis[ny * lvl->width + nx]) { + vis_visit(p, nx, ny, cvis); + } + } + } + + /* then add this cell to the visible list */ + cell->next = p->vis; + p->vis = cell; +} + void upd_player_vis(struct player *p) { - p->vis = 0; + int *cvis; + struct level *lvl = p->lvl; + cvis = alloca(lvl->width * lvl->height * sizeof *cvis); + memset(cvis, 0, lvl->width * lvl->height * sizeof *cvis); + p->vis = 0; + vis_visit(p, p->cx, p->cy, cvis); } diff --git a/src/player.h b/src/player.h index ddba877..7d92422 100644 --- a/src/player.h +++ b/src/player.h @@ -30,6 +30,6 @@ void turn_player(struct player *p, int turn); void upd_player_xform(struct player *p); -void upd_level_vis(struct player *p); +void upd_player_vis(struct player *p); #endif /* PLAYER_H_ */ -- 1.7.10.4