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);
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))) {
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;
}
#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;
#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);
void update_player_dir(struct player *p)
{
- int dir;
+ int prev_dir = p->dir;
float angle;
/* TODO: take vrot into account */
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);
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)
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)
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);
}