X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=vrlugburz;a=blobdiff_plain;f=src%2Fplayer.c;h=61a59895236843628b5caa9f23274a890ba374cb;hp=ab7d818a776bf5410d1df16a367a1d8a255d6e40;hb=32010751a69440b52780a4e570682f20b4ef70b2;hpb=594c18e3671a27624a867071b5bafd08148652b3 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); }