#include "pch.c" #pragma hdrstop #include "maze_std.h" #define VIEW_ANG 90 float maze_height; double view_rot; int maze_walls_list; extern TEX_ENV gTexEnv[]; typedef struct _FxRay2 { FxPt2 p; FxVec2 d; } FxRay2; BYTE maze_desc[MAZE_ARRAY][MAZE_ARRAY]; Cell maze_cells[MAZE_GRID][MAZE_GRID]; #define CellAt(x, y) (&maze_cells[y][x]) typedef struct _Wall { FxPt2 f, t; int col; TEX_ENV *pTexEnv; // points to texture environment } Wall; FxPt2 fmaze_pts[N_MAZE_PTS]; Wall maze[N_MAZE_WALLS]; int nwalls; typedef struct _WallHit { Cell *cell; int cx, cy; WallFlags flag; } WallHit; void AddObject(Object *obj, Cell *cell) { obj->next = cell->contents; cell->contents = obj; obj->cell = cell; } void PlaceObject(Object *obj, FxValue x, FxValue y) { Cell *cell; int cx, cy; cx = MfxToCell(x); cy = MfxToCell(y); cell = CellAt(cx, cy); obj->p.x = x; obj->p.y = y; AddObject(obj, cell); } void RemoveObject(Object *obj) { Object *o, *op; if (obj->cell != NULL) { op = NULL; for (o = obj->cell->contents; o != obj; o = o->next) { op = o; } if (op == NULL) { obj->cell->contents = obj->next; } else { op->next = obj->next; } obj->cell = NULL; } } void MoveObject(Object *obj, FxValue x, FxValue y) { int cx, cy; Cell *cell; obj->p.x = x; obj->p.y = y; cx = MfxToCell(x); cy = MfxToCell(y); cell = CellAt(cx, cy); if (cell == obj->cell) { return; } RemoveObject(obj); AddObject(obj, cell); } Object start_obj, end_obj; BOOL InitMaze(IntPt2 *start_cell, MazeGoal *goals, int *ngoals) { int i, j, n; FxPt2 p; if (!GenerateMaze(MAZE_GRID, MAZE_GRID, &maze_desc[0][0])) { return FALSE; } p.y = FxVal(0); n = 0; for (i = 0; i < MAZE_ARRAY; i++) { p.x = FxVal(0); for (j = 0; j < MAZE_ARRAY; j++) { fmaze_pts[n].x = p.x; fmaze_pts[n++].y = p.y; p.x += FMAZE_CELL_SIZE; } p.y += FMAZE_CELL_SIZE; } nwalls = 0; for (i = 0; i < MAZE_ARRAY; i++) { for (j = 0; j < MAZE_ARRAY; j++) { if (i < MAZE_ARRAY-1 && j < MAZE_ARRAY-1) { maze_cells[i][j].can_see = 0; maze_cells[i][j].contents = NULL; memset(maze_cells[i][j].walls, 0, 4*sizeof(Wall *)); } if (maze_desc[i][j] & MAZE_WALL_HORZ) { if (j == MAZE_ARRAY-1) { printf("MAZE_WALL_HORZ at right edge\n"); return FALSE; } maze[nwalls].f = fmaze_pts[i*MAZE_ARRAY+j]; maze[nwalls].t = fmaze_pts[i*MAZE_ARRAY+j+1]; maze[nwalls].col = (i+j+1) & 1; maze[nwalls].pTexEnv = &gTexEnv[TEX_WALL]; if (i > 0) { maze_cells[i-1][j].can_see |= MAZE_WALL_DOWN; maze_cells[i-1][j].walls[WIDX_DOWN] = &maze[nwalls]; } if (i < MAZE_ARRAY-1) { maze_cells[i][j].can_see |= MAZE_WALL_UP; maze_cells[i][j].walls[WIDX_UP] = &maze[nwalls]; } nwalls++; } if (maze_desc[i][j] & MAZE_WALL_VERT) { if (i == MAZE_ARRAY-1) { printf("MAZE_WALL_VERT at bottom edge\n"); return FALSE; } maze[nwalls].f = fmaze_pts[i*MAZE_ARRAY+j]; maze[nwalls].t = fmaze_pts[(i+1)*MAZE_ARRAY+j]; maze[nwalls].col = (i+j) & 1; maze[nwalls].pTexEnv = &gTexEnv[TEX_WALL]; if (j > 0) { maze_cells[i][j-1].can_see |= MAZE_WALL_RIGHT; maze_cells[i][j-1].walls[WIDX_RIGHT] = &maze[nwalls]; } if (j < MAZE_ARRAY-1) { maze_cells[i][j].can_see |= MAZE_WALL_LEFT; maze_cells[i][j].walls[WIDX_LEFT] = &maze[nwalls]; } nwalls++; } } } // Always place the start on the left and // the end on the right. This guarantees that there'll be // some traversing of the maze for the solution // Since the maze generator guarantees that the entire maze is // fully connected, the solution can always be found start_cell->x = 0; start_cell->y = rand() % MAZE_GRID; *ngoals = 1; goals[0].clx = MAZE_GRID-1; goals[0].cly = rand() % MAZE_GRID; start_obj.w = FMAZE_CELL_SIZE/6; start_obj.h = FxFltVal(.166); start_obj.z = FxFltVal(.5); start_obj.col = 12; start_obj.draw_style = DRAW_POLYGON; start_obj.pTexEnv = &gTexEnv[ TEX_START ]; start_obj.ang = FaDeg(0); PlaceObject(&start_obj, CellToMfx(start_cell->x)+FMAZE_CELL_SIZE/2, CellToMfx(start_cell->y)+FMAZE_CELL_SIZE/2); end_obj.w = FMAZE_CELL_SIZE/6; end_obj.h = FxFltVal(.166); end_obj.z = FxFltVal(.5); end_obj.col = 10; end_obj.draw_style = DRAW_POLYGON; end_obj.pTexEnv = &gTexEnv[ TEX_END ]; end_obj.ang = FaDeg(0); PlaceObject(&end_obj, CellToMfx(goals[0].clx)+FMAZE_CELL_SIZE/2, CellToMfx(goals[0].cly)+FMAZE_CELL_SIZE/2); // Reset some of the walls' textures to the OpenGL cover // for some variety i = (rand() % 5)+1; while (i-- > 0) { j = rand() % nwalls; maze[j].pTexEnv = &gTexEnv[TEX_COVER]; } #if 0 // Make some of the walls partially covered n = (rand() % 50)+1; while (n-- > 0) { Wall *wall; int dir; // The wall picked cannot be an edge wall because that // would allow walking out of the maze i = ((rand() >> 8) % (MAZE_GRID-2))+1; j = ((rand() >> 8) % (MAZE_GRID-2))+1; dir = (rand() >> 13) % 4; wall = maze_cells[i][j].walls[dir]; if (wall != NULL) { wall->pTexEnv = &gTexEnv[TEX_END]; maze_cells[i][j].can_see |= (MAZE_WALL_LEFT_PARTIAL << dir); switch(dir) { case WIDX_LEFT: if (j > 0) { maze_cells[i][j-1].can_see |= MAZE_WALL_RIGHT_PARTIAL; } break; case WIDX_RIGHT: if (j < MAZE_GRID-1) { maze_cells[i][j+1].can_see |= MAZE_WALL_LEFT_PARTIAL; } break; case WIDX_UP: if (i > 0) { maze_cells[i-1][j].can_see |= MAZE_WALL_DOWN_PARTIAL; } break; case WIDX_DOWN: if (i < MAZE_GRID-1) { maze_cells[i+1][j].can_see |= MAZE_WALL_UP_PARTIAL; } break; } } } #endif return TRUE; } #define PO_WALL 0 #define PO_PARTIAL 1 #define PO_COUNT 2 typedef struct _PaintWall { Wall *wall; } PaintWall; typedef struct _PaintPartial { Object *obj; } PaintPartial; typedef struct _PaintObject { int type; union { PaintWall wall; PaintPartial partial; } u; FxValue depth; struct _PaintObject *closer; } PaintObject; #define N_PAINT_OBJECTS (4*MAZE_CELLS) PaintObject paint[N_PAINT_OBJECTS]; int npaint; void WallCoords(int x, int y, WallFlags flag, FxPt2 *f, FxPt2 *t) { t->x = f->x = CellToMfx(x); t->y = f->y = CellToMfx(y); if (flag & MAZE_WALL_LEFT) { t->y += FMAZE_CELL_SIZE; } else if (flag & MAZE_WALL_UP) { t->x += FMAZE_CELL_SIZE; } else if (flag & MAZE_WALL_RIGHT) { f->x += FMAZE_CELL_SIZE; t->x = f->x; t->y += FMAZE_CELL_SIZE; } else if (flag & MAZE_WALL_DOWN) { f->y += FMAZE_CELL_SIZE; t->y = f->y; t->x += FMAZE_CELL_SIZE; } } void AddPaintWall(Cell *cell, int widx) { PaintWall *pw; if (npaint == N_PAINT_OBJECTS) { printf("Paint list full\n"); return; } pw = &paint[npaint].u.wall; paint[npaint].type = PO_WALL; npaint++; pw->wall = cell->walls[widx]; } void AddPaintWalls(Cell *cell, WallFlags wf) { if (wf & MAZE_WALL_LEFT) { AddPaintWall(cell, WIDX_LEFT); } if (wf & MAZE_WALL_RIGHT) { AddPaintWall(cell, WIDX_RIGHT); } if (wf & MAZE_WALL_DOWN) { AddPaintWall(cell, WIDX_DOWN); } if (wf & MAZE_WALL_UP) { AddPaintWall(cell, WIDX_UP); } } void AddPaintPartial(Object *obj) { PaintPartial *pp; if (npaint == N_PAINT_OBJECTS) { printf("Paint list full\n"); return; } pp = &paint[npaint].u.partial; paint[npaint].type = PO_PARTIAL; npaint++; pp->obj = obj; } void AddCell(int x, int y, WallFlags wf) { Cell *cell; Object *obj; wf |= MAZE_CONTENTS; cell = CellAt(x, y); if ((cell->unseen & wf) == 0) { return; } AddPaintWalls(cell, (WallFlags)(wf & cell->unseen)); if (cell->unseen & MAZE_CONTENTS) { for (obj = cell->contents; obj; obj = obj->next) { AddPaintPartial(obj); } } cell->unseen &= ~wf; } void TraceCells(FxPt2 *ip, FxVec2 *dp, WallHit *hit) { int cx, cy; int sgnx, sgny; FxVec2 dg, dst; FxPt2 fp, g; WallFlags xwf, ywf, iwf, xpf, ypf; FxValue sx, sy; cx = MfxToCell(ip->x); cy = MfxToCell(ip->y); fp = *ip; #ifdef TRACEDEB printf("pt %ld,%ld dp %ld,%ld\n", fp.x, fp.y, dp.x, dp.y); #endif if (dp->x < 0) { g.x = CellToMfx(cx)-FX_MIN_VALUE; dg.x = -FMAZE_CELL_SIZE; sgnx = -1; xwf = MAZE_WALL_LEFT; xpf = MAZE_WALL_LEFT_PARTIAL; } else { g.x = CellToMfx(cx+1); dg.x = FMAZE_CELL_SIZE; sgnx = 1; xwf = MAZE_WALL_RIGHT; xpf = MAZE_WALL_RIGHT_PARTIAL; if (dp->x == 0) { xwf |= MAZE_WALL_LEFT; xpf |= MAZE_WALL_LEFT_PARTIAL; } } if (dp->y < 0) { g.y = CellToMfx(cy)-FX_MIN_VALUE; dg.y = -FMAZE_CELL_SIZE; sgny = -1; ywf = MAZE_WALL_UP; ypf = MAZE_WALL_UP_PARTIAL; } else { g.y = CellToMfx(cy+1); dg.y = FMAZE_CELL_SIZE; sgny = 1; ywf = MAZE_WALL_DOWN; ypf = MAZE_WALL_DOWN_PARTIAL; if (dp->y == 0) { ywf |= MAZE_WALL_UP; ypf |= MAZE_WALL_UP_PARTIAL; } } for (;;) { AddCell(cx, cy, (WallFlags)(xwf | ywf)); dst.x = (g.x-fp.x)*sgnx; dst.y = (g.y-fp.y)*sgny; sx = FxMul(dst.x, dp->y); if (sx < 0) { sx = -sx; } sy = FxMul(dst.y, dp->x); if (sy < 0) { sy = -sy; } #ifdef TRACEDEB printf("dx %ld, sx %ld, dy %ld, sy %ld\n", dst.x, sx, dst.y, sy); #endif if (sx <= sy) { if ((maze_cells[cy][cx].can_see & xwf) && (maze_cells[cy][cx].can_see & xpf) == 0) { iwf = xwf; break; } fp.x = g.x; fp.y += FxDiv(sx, dp->x)*sgnx*sgny; if (fp.y == g.y) { if ((maze_cells[cy][cx].can_see & ywf) && (maze_cells[cy][cx].can_see & ypf) == 0) { iwf = ywf; break; } cy += sgny; g.y += dg.y; } cx += sgnx; g.x += dg.x; } else { if ((maze_cells[cy][cx].can_see & ywf) && (maze_cells[cy][cx].can_see & ypf) == 0) { iwf = ywf; break; } fp.y = g.y; fp.x += FxDiv(sy, dp->y)*sgnx*sgny; if (fp.x == g.x) { if ((maze_cells[cy][cx].can_see & xwf) && (maze_cells[cy][cx].can_see & xpf) == 0) { iwf = xwf; break; } cx += sgnx; g.x += dg.x; } cy += sgny; g.y += dg.y; } } hit->cell = CellAt(cx, cy); hit->cx = cx; hit->cy = cy; hit->flag = iwf; } void TraceView(MazeView *vw) { FaAngle acc; FxVec2 vcc; WallHit hit; int rc; acc = FaAdd(vw->ang, FaDeg(VIEW_ANG)/2); for (rc = 0; rc < VIEW_ANG; rc++) { vcc.x = FaCos(acc); vcc.y = FaSin(acc); TraceCells(&vw->pos, &vcc, &hit); acc = FaAdd(acc, -FaDeg(1)); } } static void WallCompute(PaintObject *po, MazeView *vw, FxValue cs, FxValue sn) { FxPt2 mid; Wall *wall; wall = po->u.wall.wall; // Compute depth at midpoint of wall // Eye coordinate depth increases along the X so // we only need to transform it mid.x = (wall->f.x+wall->t.x)/2-vw->pos.x; mid.y = (wall->f.y+wall->t.y)/2-vw->pos.y; po->depth = FxMul(mid.x, cs)+FxMul(mid.y, sn); } static void PartialCompute(PaintObject *po, MazeView *vw, FxValue cs, FxValue sn) { PaintPartial *pp; FxPt2 c; pp = &po->u.partial; // Compute depth at center of partial c.x = pp->obj->p.x-vw->pos.x; c.y = pp->obj->p.y-vw->pos.y; po->depth = FxMul(c.x, cs)+FxMul(c.y, sn); } typedef void (*PoComputeFn)(PaintObject *po, MazeView *vw, FxValue cs, FxValue sn); static PoComputeFn PoCompute[PO_COUNT] = { WallCompute, PartialCompute }; static float colors[17][3] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 0.75f, 0.75f, 0.75f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.75f, 0.39f, 0.0f }; #define WALL_SET 0 #define FLOOR_SET 1 #define CEILING_SET 2 static float *smooth_sets[3][2][4] = { &colors[1][0], &colors[2][0], &colors[4][0], &colors[7][0], &colors[2][0], &colors[1][0], &colors[7][0], &colors[4][0], &colors[10][0], &colors[2][0], &colors[4][0], &colors[6][0], &colors[10][0], &colors[2][0], &colors[4][0], &colors[6][0], &colors[9][0], &colors[1][0], &colors[2][0], &colors[3][0], &colors[9][0], &colors[1][0], &colors[2][0], &colors[3][0] }; static float *flat_sets[3][2][4] = { &colors[8][0], &colors[8][0], &colors[8][0], &colors[8][0], &colors[15][0], &colors[15][0], &colors[15][0], &colors[15][0], &colors[2][0], &colors[2][0], &colors[2][0], &colors[2][0], &colors[2][0], &colors[2][0], &colors[2][0], &colors[2][0], &colors[9][0], &colors[9][0], &colors[9][0], &colors[9][0], &colors[9][0], &colors[9][0], &colors[9][0], &colors[9][0] }; void SetAlphaCol(GLfloat *fv3) { if (maze_options.all_alpha) { GLfloat fv4[4]; fv4[0] = fv3[0]; fv4[1] = fv3[1]; fv4[2] = fv3[2]; fv4[3] = 0.5f; glColor4fv(fv4); } else { glColor3fv(fv3); } } static void WallDraw(PaintObject *po, MazeView *vw) { Wall *wall; float fx, fy, tx, ty, cx, cy, nx, ny; float **col_set; int reps; int rept; GLenum old_env; wall = po->u.wall.wall; reps = wall->pTexEnv->texRep.x; rept = wall->pTexEnv->texRep.y; fx = (float)FxFlt(wall->f.x); fy = (float)FxFlt(wall->f.y); tx = (float)FxFlt(wall->t.x); ty = (float)FxFlt(wall->t.y); nx = -(ty-fy); ny = (tx-fx); cx = (float)FxFlt(vw->pos.x); cy = (float)FxFlt(vw->pos.y); col_set = &flat_sets[WALL_SET][wall->col][0]; switch(maze_options.render[WALLS]) { case RENDER_NONE: return; case RENDER_SMOOTH: col_set = &smooth_sets[WALL_SET][wall->col][0]; break; case RENDER_FLAT: case RENDER_TEXTURED: break; } // Compute dot product with wall normal to determine // wall direction. We need to know the wall direction // in order to ensure that the wall texture faces the // correct direction UseTextureEnv(wall->pTexEnv); if (wall->pTexEnv->bTransp) { if (!maze_options.all_alpha) { glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &old_env); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gTexEnvMode); glEnable(GL_BLEND); } } glBegin(GL_POLYGON); if ((fx-cx)*nx+(fy-cy)*ny > 0) { glTexCoord2d(0, 0); SetAlphaCol(col_set[0]); glVertex3f(fx, fy, 0.0f); glTexCoord2d(reps, 0); SetAlphaCol(col_set[1]); glVertex3f(tx, ty, 0.0f); glTexCoord2d(reps, rept); SetAlphaCol(col_set[2]); glVertex3f(tx, ty, maze_height); glTexCoord2d(0, rept); SetAlphaCol(col_set[3]); glVertex3f(fx, fy, maze_height); } else { glTexCoord2d(reps, 0); SetAlphaCol(col_set[0]); glVertex3f(fx, fy, 0.0f); glTexCoord2d(0, 0); SetAlphaCol(col_set[1]); glVertex3f(tx, ty, 0.0f); glTexCoord2d(0, rept); SetAlphaCol(col_set[2]); glVertex3f(tx, ty, maze_height); glTexCoord2d(reps, rept); SetAlphaCol(col_set[3]); glVertex3f(fx, fy, maze_height); } glEnd(); if (wall->pTexEnv->bTransp) { if (!maze_options.all_alpha) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, old_env); glDisable(GL_BLEND); } } } void (APIENTRY *convex_solids[SPECIAL_ARG_COUNT])(GLdouble radius) = { auxSolidIcosahedron, auxSolidOctahedron, auxSolidDodecahedron, auxSolidTetrahedron }; static void PartialDraw(PaintObject *po, MazeView *vw) { PaintPartial *pp; float w, h, cx, cy, cz, vx, vy, fx, fy, fz, tx, ty, tz; float cs, sn; GLenum old_env; pp = &po->u.partial; w = (float)FxFlt(pp->obj->w); h = (float)FxFlt(pp->obj->h); // Partials are billboarded so we want it to always be // perpendicular to the view direction cs = (float)FxFlt(FaCos(vw->ang)); sn = (float)FxFlt(FaSin(vw->ang)); vx = -sn*w; vy = cs*w; cx = (float)FxFlt(pp->obj->p.x); cy = (float)FxFlt(pp->obj->p.y); cz = (float)FxFlt(pp->obj->z); fx = cx-vx; fy = cy-vy; fz = (cz-h)*maze_height; tx = cx+vx; ty = cy+vy; tz = (cz+h)*maze_height; if (maze_options.render[WALLS] == RENDER_TEXTURED) { glDisable(GL_TEXTURE_2D); } switch(pp->obj->draw_style) { case DRAW_POLYGON: glEnable(GL_TEXTURE_2D); if (!maze_options.all_alpha) { glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &old_env); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gTexEnvMode); glEnable(GL_BLEND); } UseTextureEnv( pp->obj->pTexEnv ); SetAlphaCol(colors[15]); glBegin(GL_POLYGON); glNormal3f(cs, sn, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(fx, fy, fz); glTexCoord2f(0.0f, 0.0f); glVertex3f(tx, ty, fz); glTexCoord2f(0.0f, 1.0f); glVertex3f(tx, ty, tz); glTexCoord2f(1.0f, 1.0f); glVertex3f(fx, fy, tz); glEnd(); glDisable(GL_TEXTURE_2D); if (!maze_options.all_alpha) { glDisable(GL_BLEND); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, old_env); } break; case DRAW_SPECIAL: SetAlphaCol(colors[pp->obj->col]); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glEnable(GL_LIGHTING); glEnable(GL_CULL_FACE); glEnable(GL_DITHER); glPushMatrix(); glTranslated(cx, cy, cz*maze_height); glScaled(1.0, 1.0, maze_height); glRotated(FaFltDegVal(pp->obj->ang), 0, 0, 1); glRotated(pp->obj->user3, 0, 1, 0); // Must use convex objects since depth testing can be off convex_solids[pp->obj->draw_arg](w); glPopMatrix(); if( !maze_options.bDither ) glDisable(GL_DITHER); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_AUTO_NORMAL); glDisable(GL_NORMALIZE); break; } if (maze_options.render[WALLS] == RENDER_TEXTURED) { glEnable(GL_TEXTURE_2D); } } typedef void (*PoDrawFn)(PaintObject *po, MazeView *vw); static PoDrawFn PoDraw[PO_COUNT] = { WallDraw, PartialDraw }; void RenderZPlane(int render, TEX_ENV *pTexEnv, int set, float zval) { float **col_set; int reps = pTexEnv->texRep.x; int rept = pTexEnv->texRep.y; switch(render) { case RENDER_NONE: break; case RENDER_TEXTURED: UseTextureEnv(pTexEnv); glEnable(GL_TEXTURE_2D); // Fall through case RENDER_FLAT: case RENDER_SMOOTH: col_set = &flat_sets[set][0][0]; if (render == RENDER_SMOOTH) { col_set = &smooth_sets[set][0][0]; } glBegin(GL_POLYGON); // Switch texture orientation dependent on surface type if( set == CEILING_SET ) { glTexCoord2f((float)reps*MAZE_SIZE, 0.0f); glColor3fv(col_set[0]); glVertex3f(0.0f, 0.0f, zval); glTexCoord2f(0.0f, 0.0f); glColor3fv(col_set[1]); glVertex3f((float)MAZE_SIZE, 0.0f, zval); glTexCoord2f(0.0f, (float)rept*MAZE_SIZE); glColor3fv(col_set[2]); glVertex3f((float)MAZE_SIZE, (float)MAZE_SIZE, zval); glTexCoord2f((float)reps*MAZE_SIZE, (float)rept*MAZE_SIZE); glColor3fv(col_set[3]); glVertex3f(0.0f, (float)MAZE_SIZE, zval); } else { glTexCoord2f(0.0f, 0.0f); glColor3fv(col_set[0]); glVertex3f(0.0f, 0.0f, zval); glTexCoord2f((float)reps*MAZE_SIZE, 0.0f); glColor3fv(col_set[1]); glVertex3f((float)MAZE_SIZE, 0.0f, zval); glTexCoord2f((float)reps*MAZE_SIZE, (float)rept*MAZE_SIZE); glColor3fv(col_set[2]); glVertex3f((float)MAZE_SIZE, (float)MAZE_SIZE, zval); glTexCoord2f(0.0f, (float)rept*MAZE_SIZE); glColor3fv(col_set[3]); glVertex3f(0.0f, (float)MAZE_SIZE, zval); } glEnd(); if (render == RENDER_TEXTURED) { glDisable(GL_TEXTURE_2D); } break; } } void Render(MazeView *vw) { FxValue cs, sn; PaintObject *sorted, *so, *pso; PaintObject *po; int i; FxPt2 at; BOOL special; float viewHeight; cs = FaCos(vw->ang); sn = FaSin(vw->ang); at.x = vw->pos.x+cs; at.y = vw->pos.y+sn; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glRotated(view_rot, 0, 0, 1); gluPerspective(VIEW_ANG, 1, .01, 100); viewHeight = 0.5f; gluLookAt(FxFlt(vw->pos.x), FxFlt(vw->pos.y), viewHeight, FxFlt(at.x), FxFlt(at.y), viewHeight, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); RenderZPlane(maze_options.render[FLOOR], &gTexEnv[TEX_FLOOR], FLOOR_SET, 0.0f); RenderZPlane(maze_options.render[CEILING], &gTexEnv[TEX_CEILING], CEILING_SET, 1.0f); sorted = NULL; special = FALSE; for (i = 0, po = paint; i < npaint; i++, po++) { if (po->type == PO_PARTIAL && po->u.partial.obj->draw_style == DRAW_SPECIAL) { special = TRUE; } PoCompute[po->type](po, vw, cs, sn); for (so = sorted, pso = NULL; so; pso = so, so = so->closer) { if (so->depth <= po->depth) { break; } } if (pso == NULL) { sorted = po; } else { pso->closer = po; } po->closer = so; } #if 0 // Unnecessary at the moment, but might be handy later if (special && !maze_options.depth_test) { glClear(GL_DEPTH_BUFFER_BIT); } #endif if (maze_options.render[WALLS] == RENDER_TEXTURED) { glEnable(GL_TEXTURE_2D); } for (so = sorted; so; so = so->closer) { PoDraw[so->type](so, vw); } if (maze_options.render[WALLS] == RENDER_TEXTURED) { glDisable(GL_TEXTURE_2D); } } void InitPaint(void) { int i, j; npaint = 0; for (i = 0; i < MAZE_GRID; i++) { for (j = 0; j < MAZE_GRID; j++) { maze_cells[i][j].unseen = maze_cells[i][j].can_see | MAZE_CONTENTS; } } } void DrawMaze(MazeView *vw) { InitPaint(); TraceView(vw); Render(vw); } void DrawMazeWalls(void) { int w; Wall *wall; wall = maze; glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_LINES); for (w = 0; w < nwalls; w++) { glVertex2f((float)FxFltVal(wall->f.x), (float)FxFltVal(wall->f.y)); glVertex2f((float)FxFltVal(wall->t.x), (float)FxFltVal(wall->t.y)); wall++; } glEnd(); } #define SQRT2_2 0.707107f void DrawTopView(MazeView *vw) { int c; Cell *cell; Object *obj; float vx, vy, cx, cy, width, ang; extern float gfAspect; glMatrixMode(GL_PROJECTION); glLoadIdentity(); //mf: if image being stretched, gfAspect isn't enought to make this straight - // need to compensate by using aspect of base dimensions as well. //mf? maybe use glScale ? gluOrtho2D( -MAZE_SIZE/2.0, MAZE_SIZE/2.0, -MAZE_SIZE/2.0/gfAspect, MAZE_SIZE/2.0/gfAspect ); glMatrixMode(GL_MODELVIEW); glPushMatrix(); ang = (float)FaFltDegVal(vw->ang)+90.0f; glRotatef(ang, 0.0f, 0.0f, 1.0f); vx = (float)FxFltVal(vw->pos.x); vy = (float)FxFltVal(vw->pos.y); glTranslatef(-vx, -vy, 0.0f); #define AA_LINES 1 #ifdef AA_LINES // Turn on antialiased lines glEnable( GL_BLEND ); glEnable( GL_LINE_SMOOTH ); glHint( GL_LINE_SMOOTH_HINT, GL_NICEST ); #endif glCallList(maze_walls_list); #ifdef AA_LINES glDisable( GL_BLEND ); glDisable( GL_LINE_SMOOTH ); #endif // Objects aren't put in the walls display list so that they // can move around cell = &maze_cells[0][0]; for (c = 0; c < MAZE_CELLS; c++) { for (obj = cell->contents; obj != NULL; obj = obj->next) { cx = (float)FxFltVal(obj->p.x); cy = (float)FxFltVal(obj->p.y); width = (float)FxFltVal(obj->w); glColor3fv(colors[obj->col]); glPushMatrix(); glTranslatef(cx, cy, 0.0f); glRotated(FaFltDegVal(obj->ang), 0, 0, 1); #if 1 glBegin(GL_POLYGON); glVertex2f(width, 0.0f); glVertex2f(-width*SQRT2_2, width*0.5f); glVertex2f(-width*SQRT2_2, -width*0.5f); glEnd(); #else glRectf(-width, -width, width, width); #endif glPopMatrix(); } cell++; } glPopMatrix(); // Draw self glColor3f(0.0f, 0.0f, 1.0f); width = MAZE_CELL_SIZE/4.0f; glBegin(GL_POLYGON); glVertex2f(0.0f, width); glVertex2f(width*0.5f, -width*SQRT2_2); glVertex2f(-width*0.5f, -width*SQRT2_2); glEnd(); }