visibility determination master
authorJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 1 Oct 2021 05:05:16 +0000 (08:05 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 1 Oct 2021 05:05:16 +0000 (08:05 +0300)
src/game.c
src/level.c
src/level.h
src/player.c
src/player.h

index 64c00df..92843dc 100644 (file)
@@ -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; i<lvl.height; i++) {
-               for(j=0; j<lvl.width; j++) {
-                       cgm_mtranslation(xform, j * lvl.cell_size, 0, -i * lvl.cell_size);
-
-                       glPushMatrix();
-                       glMultMatrixf(xform);
+       if(!player.vis) {
+               upd_player_vis(&player);
+       }
 
-                       if(cell->tile) {
-                               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; k<cell->num_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; i<cell->num_mgrp; i++) {
+                       draw_meshgroup(cell->mgrp + i);
+               }
+               glPopMatrix();
+
+               cell = cell->next;
        }
 
        glUseProgram(0);
index c17c03a..5f7f77b 100644 (file)
@@ -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; i<ysz; i++) {
+               for(j=0; j<xsz; j++) {
+                       cell->x = 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;
index cbf6642..a5a2ae6 100644 (file)
@@ -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_ */
index ab7d818..61a5989 100644 (file)
@@ -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);
 }
index ddba877..7d92422 100644 (file)
@@ -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_ */