Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1180 lines
28 KiB

  1. #include "pch.c"
  2. #pragma hdrstop
  3. #include "maze_std.h"
  4. #define VIEW_ANG 90
  5. float maze_height;
  6. double view_rot;
  7. int maze_walls_list;
  8. extern TEX_ENV gTexEnv[];
  9. typedef struct _FxRay2
  10. {
  11. FxPt2 p;
  12. FxVec2 d;
  13. } FxRay2;
  14. BYTE maze_desc[MAZE_ARRAY][MAZE_ARRAY];
  15. Cell maze_cells[MAZE_GRID][MAZE_GRID];
  16. #define CellAt(x, y) (&maze_cells[y][x])
  17. typedef struct _Wall
  18. {
  19. FxPt2 f, t;
  20. int col;
  21. TEX_ENV *pTexEnv; // points to texture environment
  22. } Wall;
  23. FxPt2 fmaze_pts[N_MAZE_PTS];
  24. Wall maze[N_MAZE_WALLS];
  25. int nwalls;
  26. typedef struct _WallHit
  27. {
  28. Cell *cell;
  29. int cx, cy;
  30. WallFlags flag;
  31. } WallHit;
  32. void AddObject(Object *obj, Cell *cell)
  33. {
  34. obj->next = cell->contents;
  35. cell->contents = obj;
  36. obj->cell = cell;
  37. }
  38. void PlaceObject(Object *obj, FxValue x, FxValue y)
  39. {
  40. Cell *cell;
  41. int cx, cy;
  42. cx = MfxToCell(x);
  43. cy = MfxToCell(y);
  44. cell = CellAt(cx, cy);
  45. obj->p.x = x;
  46. obj->p.y = y;
  47. AddObject(obj, cell);
  48. }
  49. void RemoveObject(Object *obj)
  50. {
  51. Object *o, *op;
  52. if (obj->cell != NULL)
  53. {
  54. op = NULL;
  55. for (o = obj->cell->contents; o != obj; o = o->next)
  56. {
  57. op = o;
  58. }
  59. if (op == NULL)
  60. {
  61. obj->cell->contents = obj->next;
  62. }
  63. else
  64. {
  65. op->next = obj->next;
  66. }
  67. obj->cell = NULL;
  68. }
  69. }
  70. void MoveObject(Object *obj, FxValue x, FxValue y)
  71. {
  72. int cx, cy;
  73. Cell *cell;
  74. obj->p.x = x;
  75. obj->p.y = y;
  76. cx = MfxToCell(x);
  77. cy = MfxToCell(y);
  78. cell = CellAt(cx, cy);
  79. if (cell == obj->cell)
  80. {
  81. return;
  82. }
  83. RemoveObject(obj);
  84. AddObject(obj, cell);
  85. }
  86. Object start_obj, end_obj;
  87. BOOL InitMaze(IntPt2 *start_cell, MazeGoal *goals, int *ngoals)
  88. {
  89. int i, j, n;
  90. FxPt2 p;
  91. if (!GenerateMaze(MAZE_GRID, MAZE_GRID, &maze_desc[0][0]))
  92. {
  93. return FALSE;
  94. }
  95. p.y = FxVal(0);
  96. n = 0;
  97. for (i = 0; i < MAZE_ARRAY; i++)
  98. {
  99. p.x = FxVal(0);
  100. for (j = 0; j < MAZE_ARRAY; j++)
  101. {
  102. fmaze_pts[n].x = p.x;
  103. fmaze_pts[n++].y = p.y;
  104. p.x += FMAZE_CELL_SIZE;
  105. }
  106. p.y += FMAZE_CELL_SIZE;
  107. }
  108. nwalls = 0;
  109. for (i = 0; i < MAZE_ARRAY; i++)
  110. {
  111. for (j = 0; j < MAZE_ARRAY; j++)
  112. {
  113. if (i < MAZE_ARRAY-1 && j < MAZE_ARRAY-1)
  114. {
  115. maze_cells[i][j].can_see = 0;
  116. maze_cells[i][j].contents = NULL;
  117. memset(maze_cells[i][j].walls, 0, 4*sizeof(Wall *));
  118. }
  119. if (maze_desc[i][j] & MAZE_WALL_HORZ)
  120. {
  121. if (j == MAZE_ARRAY-1)
  122. {
  123. printf("MAZE_WALL_HORZ at right edge\n");
  124. return FALSE;
  125. }
  126. maze[nwalls].f = fmaze_pts[i*MAZE_ARRAY+j];
  127. maze[nwalls].t = fmaze_pts[i*MAZE_ARRAY+j+1];
  128. maze[nwalls].col = (i+j+1) & 1;
  129. maze[nwalls].pTexEnv = &gTexEnv[TEX_WALL];
  130. if (i > 0)
  131. {
  132. maze_cells[i-1][j].can_see |= MAZE_WALL_DOWN;
  133. maze_cells[i-1][j].walls[WIDX_DOWN] = &maze[nwalls];
  134. }
  135. if (i < MAZE_ARRAY-1)
  136. {
  137. maze_cells[i][j].can_see |= MAZE_WALL_UP;
  138. maze_cells[i][j].walls[WIDX_UP] = &maze[nwalls];
  139. }
  140. nwalls++;
  141. }
  142. if (maze_desc[i][j] & MAZE_WALL_VERT)
  143. {
  144. if (i == MAZE_ARRAY-1)
  145. {
  146. printf("MAZE_WALL_VERT at bottom edge\n");
  147. return FALSE;
  148. }
  149. maze[nwalls].f = fmaze_pts[i*MAZE_ARRAY+j];
  150. maze[nwalls].t = fmaze_pts[(i+1)*MAZE_ARRAY+j];
  151. maze[nwalls].col = (i+j) & 1;
  152. maze[nwalls].pTexEnv = &gTexEnv[TEX_WALL];
  153. if (j > 0)
  154. {
  155. maze_cells[i][j-1].can_see |= MAZE_WALL_RIGHT;
  156. maze_cells[i][j-1].walls[WIDX_RIGHT] = &maze[nwalls];
  157. }
  158. if (j < MAZE_ARRAY-1)
  159. {
  160. maze_cells[i][j].can_see |= MAZE_WALL_LEFT;
  161. maze_cells[i][j].walls[WIDX_LEFT] = &maze[nwalls];
  162. }
  163. nwalls++;
  164. }
  165. }
  166. }
  167. // Always place the start on the left and
  168. // the end on the right. This guarantees that there'll be
  169. // some traversing of the maze for the solution
  170. // Since the maze generator guarantees that the entire maze is
  171. // fully connected, the solution can always be found
  172. start_cell->x = 0;
  173. start_cell->y = rand() % MAZE_GRID;
  174. *ngoals = 1;
  175. goals[0].clx = MAZE_GRID-1;
  176. goals[0].cly = rand() % MAZE_GRID;
  177. start_obj.w = FMAZE_CELL_SIZE/6;
  178. start_obj.h = FxFltVal(.166);
  179. start_obj.z = FxFltVal(.5);
  180. start_obj.col = 12;
  181. start_obj.draw_style = DRAW_POLYGON;
  182. start_obj.pTexEnv = &gTexEnv[ TEX_START ];
  183. start_obj.ang = FaDeg(0);
  184. PlaceObject(&start_obj,
  185. CellToMfx(start_cell->x)+FMAZE_CELL_SIZE/2,
  186. CellToMfx(start_cell->y)+FMAZE_CELL_SIZE/2);
  187. end_obj.w = FMAZE_CELL_SIZE/6;
  188. end_obj.h = FxFltVal(.166);
  189. end_obj.z = FxFltVal(.5);
  190. end_obj.col = 10;
  191. end_obj.draw_style = DRAW_POLYGON;
  192. end_obj.pTexEnv = &gTexEnv[ TEX_END ];
  193. end_obj.ang = FaDeg(0);
  194. PlaceObject(&end_obj,
  195. CellToMfx(goals[0].clx)+FMAZE_CELL_SIZE/2,
  196. CellToMfx(goals[0].cly)+FMAZE_CELL_SIZE/2);
  197. // Reset some of the walls' textures to the OpenGL cover
  198. // for some variety
  199. i = (rand() % 5)+1;
  200. while (i-- > 0)
  201. {
  202. j = rand() % nwalls;
  203. maze[j].pTexEnv = &gTexEnv[TEX_COVER];
  204. }
  205. #if 0
  206. // Make some of the walls partially covered
  207. n = (rand() % 50)+1;
  208. while (n-- > 0)
  209. {
  210. Wall *wall;
  211. int dir;
  212. // The wall picked cannot be an edge wall because that
  213. // would allow walking out of the maze
  214. i = ((rand() >> 8) % (MAZE_GRID-2))+1;
  215. j = ((rand() >> 8) % (MAZE_GRID-2))+1;
  216. dir = (rand() >> 13) % 4;
  217. wall = maze_cells[i][j].walls[dir];
  218. if (wall != NULL)
  219. {
  220. wall->pTexEnv = &gTexEnv[TEX_END];
  221. maze_cells[i][j].can_see |= (MAZE_WALL_LEFT_PARTIAL << dir);
  222. switch(dir)
  223. {
  224. case WIDX_LEFT:
  225. if (j > 0)
  226. {
  227. maze_cells[i][j-1].can_see |= MAZE_WALL_RIGHT_PARTIAL;
  228. }
  229. break;
  230. case WIDX_RIGHT:
  231. if (j < MAZE_GRID-1)
  232. {
  233. maze_cells[i][j+1].can_see |= MAZE_WALL_LEFT_PARTIAL;
  234. }
  235. break;
  236. case WIDX_UP:
  237. if (i > 0)
  238. {
  239. maze_cells[i-1][j].can_see |= MAZE_WALL_DOWN_PARTIAL;
  240. }
  241. break;
  242. case WIDX_DOWN:
  243. if (i < MAZE_GRID-1)
  244. {
  245. maze_cells[i+1][j].can_see |= MAZE_WALL_UP_PARTIAL;
  246. }
  247. break;
  248. }
  249. }
  250. }
  251. #endif
  252. return TRUE;
  253. }
  254. #define PO_WALL 0
  255. #define PO_PARTIAL 1
  256. #define PO_COUNT 2
  257. typedef struct _PaintWall
  258. {
  259. Wall *wall;
  260. } PaintWall;
  261. typedef struct _PaintPartial
  262. {
  263. Object *obj;
  264. } PaintPartial;
  265. typedef struct _PaintObject
  266. {
  267. int type;
  268. union
  269. {
  270. PaintWall wall;
  271. PaintPartial partial;
  272. } u;
  273. FxValue depth;
  274. struct _PaintObject *closer;
  275. } PaintObject;
  276. #define N_PAINT_OBJECTS (4*MAZE_CELLS)
  277. PaintObject paint[N_PAINT_OBJECTS];
  278. int npaint;
  279. void WallCoords(int x, int y, WallFlags flag, FxPt2 *f, FxPt2 *t)
  280. {
  281. t->x = f->x = CellToMfx(x);
  282. t->y = f->y = CellToMfx(y);
  283. if (flag & MAZE_WALL_LEFT)
  284. {
  285. t->y += FMAZE_CELL_SIZE;
  286. }
  287. else if (flag & MAZE_WALL_UP)
  288. {
  289. t->x += FMAZE_CELL_SIZE;
  290. }
  291. else if (flag & MAZE_WALL_RIGHT)
  292. {
  293. f->x += FMAZE_CELL_SIZE;
  294. t->x = f->x;
  295. t->y += FMAZE_CELL_SIZE;
  296. }
  297. else if (flag & MAZE_WALL_DOWN)
  298. {
  299. f->y += FMAZE_CELL_SIZE;
  300. t->y = f->y;
  301. t->x += FMAZE_CELL_SIZE;
  302. }
  303. }
  304. void AddPaintWall(Cell *cell, int widx)
  305. {
  306. PaintWall *pw;
  307. if (npaint == N_PAINT_OBJECTS)
  308. {
  309. printf("Paint list full\n");
  310. return;
  311. }
  312. pw = &paint[npaint].u.wall;
  313. paint[npaint].type = PO_WALL;
  314. npaint++;
  315. pw->wall = cell->walls[widx];
  316. }
  317. void AddPaintWalls(Cell *cell, WallFlags wf)
  318. {
  319. if (wf & MAZE_WALL_LEFT)
  320. {
  321. AddPaintWall(cell, WIDX_LEFT);
  322. }
  323. if (wf & MAZE_WALL_RIGHT)
  324. {
  325. AddPaintWall(cell, WIDX_RIGHT);
  326. }
  327. if (wf & MAZE_WALL_DOWN)
  328. {
  329. AddPaintWall(cell, WIDX_DOWN);
  330. }
  331. if (wf & MAZE_WALL_UP)
  332. {
  333. AddPaintWall(cell, WIDX_UP);
  334. }
  335. }
  336. void AddPaintPartial(Object *obj)
  337. {
  338. PaintPartial *pp;
  339. if (npaint == N_PAINT_OBJECTS)
  340. {
  341. printf("Paint list full\n");
  342. return;
  343. }
  344. pp = &paint[npaint].u.partial;
  345. paint[npaint].type = PO_PARTIAL;
  346. npaint++;
  347. pp->obj = obj;
  348. }
  349. void AddCell(int x, int y, WallFlags wf)
  350. {
  351. Cell *cell;
  352. Object *obj;
  353. wf |= MAZE_CONTENTS;
  354. cell = CellAt(x, y);
  355. if ((cell->unseen & wf) == 0)
  356. {
  357. return;
  358. }
  359. AddPaintWalls(cell, (WallFlags)(wf & cell->unseen));
  360. if (cell->unseen & MAZE_CONTENTS)
  361. {
  362. for (obj = cell->contents; obj; obj = obj->next)
  363. {
  364. AddPaintPartial(obj);
  365. }
  366. }
  367. cell->unseen &= ~wf;
  368. }
  369. void TraceCells(FxPt2 *ip, FxVec2 *dp, WallHit *hit)
  370. {
  371. int cx, cy;
  372. int sgnx, sgny;
  373. FxVec2 dg, dst;
  374. FxPt2 fp, g;
  375. WallFlags xwf, ywf, iwf, xpf, ypf;
  376. FxValue sx, sy;
  377. cx = MfxToCell(ip->x);
  378. cy = MfxToCell(ip->y);
  379. fp = *ip;
  380. #ifdef TRACEDEB
  381. printf("pt %ld,%ld dp %ld,%ld\n", fp.x, fp.y, dp.x, dp.y);
  382. #endif
  383. if (dp->x < 0)
  384. {
  385. g.x = CellToMfx(cx)-FX_MIN_VALUE;
  386. dg.x = -FMAZE_CELL_SIZE;
  387. sgnx = -1;
  388. xwf = MAZE_WALL_LEFT;
  389. xpf = MAZE_WALL_LEFT_PARTIAL;
  390. }
  391. else
  392. {
  393. g.x = CellToMfx(cx+1);
  394. dg.x = FMAZE_CELL_SIZE;
  395. sgnx = 1;
  396. xwf = MAZE_WALL_RIGHT;
  397. xpf = MAZE_WALL_RIGHT_PARTIAL;
  398. if (dp->x == 0)
  399. {
  400. xwf |= MAZE_WALL_LEFT;
  401. xpf |= MAZE_WALL_LEFT_PARTIAL;
  402. }
  403. }
  404. if (dp->y < 0)
  405. {
  406. g.y = CellToMfx(cy)-FX_MIN_VALUE;
  407. dg.y = -FMAZE_CELL_SIZE;
  408. sgny = -1;
  409. ywf = MAZE_WALL_UP;
  410. ypf = MAZE_WALL_UP_PARTIAL;
  411. }
  412. else
  413. {
  414. g.y = CellToMfx(cy+1);
  415. dg.y = FMAZE_CELL_SIZE;
  416. sgny = 1;
  417. ywf = MAZE_WALL_DOWN;
  418. ypf = MAZE_WALL_DOWN_PARTIAL;
  419. if (dp->y == 0)
  420. {
  421. ywf |= MAZE_WALL_UP;
  422. ypf |= MAZE_WALL_UP_PARTIAL;
  423. }
  424. }
  425. for (;;)
  426. {
  427. AddCell(cx, cy, (WallFlags)(xwf | ywf));
  428. dst.x = (g.x-fp.x)*sgnx;
  429. dst.y = (g.y-fp.y)*sgny;
  430. sx = FxMul(dst.x, dp->y);
  431. if (sx < 0)
  432. {
  433. sx = -sx;
  434. }
  435. sy = FxMul(dst.y, dp->x);
  436. if (sy < 0)
  437. {
  438. sy = -sy;
  439. }
  440. #ifdef TRACEDEB
  441. printf("dx %ld, sx %ld, dy %ld, sy %ld\n", dst.x, sx, dst.y, sy);
  442. #endif
  443. if (sx <= sy)
  444. {
  445. if ((maze_cells[cy][cx].can_see & xwf) &&
  446. (maze_cells[cy][cx].can_see & xpf) == 0)
  447. {
  448. iwf = xwf;
  449. break;
  450. }
  451. fp.x = g.x;
  452. fp.y += FxDiv(sx, dp->x)*sgnx*sgny;
  453. if (fp.y == g.y)
  454. {
  455. if ((maze_cells[cy][cx].can_see & ywf) &&
  456. (maze_cells[cy][cx].can_see & ypf) == 0)
  457. {
  458. iwf = ywf;
  459. break;
  460. }
  461. cy += sgny;
  462. g.y += dg.y;
  463. }
  464. cx += sgnx;
  465. g.x += dg.x;
  466. }
  467. else
  468. {
  469. if ((maze_cells[cy][cx].can_see & ywf) &&
  470. (maze_cells[cy][cx].can_see & ypf) == 0)
  471. {
  472. iwf = ywf;
  473. break;
  474. }
  475. fp.y = g.y;
  476. fp.x += FxDiv(sy, dp->y)*sgnx*sgny;
  477. if (fp.x == g.x)
  478. {
  479. if ((maze_cells[cy][cx].can_see & xwf) &&
  480. (maze_cells[cy][cx].can_see & xpf) == 0)
  481. {
  482. iwf = xwf;
  483. break;
  484. }
  485. cx += sgnx;
  486. g.x += dg.x;
  487. }
  488. cy += sgny;
  489. g.y += dg.y;
  490. }
  491. }
  492. hit->cell = CellAt(cx, cy);
  493. hit->cx = cx;
  494. hit->cy = cy;
  495. hit->flag = iwf;
  496. }
  497. void TraceView(MazeView *vw)
  498. {
  499. FaAngle acc;
  500. FxVec2 vcc;
  501. WallHit hit;
  502. int rc;
  503. acc = FaAdd(vw->ang, FaDeg(VIEW_ANG)/2);
  504. for (rc = 0; rc < VIEW_ANG; rc++)
  505. {
  506. vcc.x = FaCos(acc);
  507. vcc.y = FaSin(acc);
  508. TraceCells(&vw->pos, &vcc, &hit);
  509. acc = FaAdd(acc, -FaDeg(1));
  510. }
  511. }
  512. static void WallCompute(PaintObject *po, MazeView *vw,
  513. FxValue cs, FxValue sn)
  514. {
  515. FxPt2 mid;
  516. Wall *wall;
  517. wall = po->u.wall.wall;
  518. // Compute depth at midpoint of wall
  519. // Eye coordinate depth increases along the X so
  520. // we only need to transform it
  521. mid.x = (wall->f.x+wall->t.x)/2-vw->pos.x;
  522. mid.y = (wall->f.y+wall->t.y)/2-vw->pos.y;
  523. po->depth = FxMul(mid.x, cs)+FxMul(mid.y, sn);
  524. }
  525. static void PartialCompute(PaintObject *po, MazeView *vw,
  526. FxValue cs, FxValue sn)
  527. {
  528. PaintPartial *pp;
  529. FxPt2 c;
  530. pp = &po->u.partial;
  531. // Compute depth at center of partial
  532. c.x = pp->obj->p.x-vw->pos.x;
  533. c.y = pp->obj->p.y-vw->pos.y;
  534. po->depth = FxMul(c.x, cs)+FxMul(c.y, sn);
  535. }
  536. typedef void (*PoComputeFn)(PaintObject *po, MazeView *vw,
  537. FxValue cs, FxValue sn);
  538. static PoComputeFn PoCompute[PO_COUNT] =
  539. {
  540. WallCompute,
  541. PartialCompute
  542. };
  543. static float colors[17][3] =
  544. {
  545. 0.0f, 0.0f, 0.0f,
  546. 0.0f, 0.0f, 0.5f,
  547. 0.0f, 0.5f, 0.0f,
  548. 0.0f, 0.5f, 0.5f,
  549. 0.5f, 0.0f, 0.0f,
  550. 0.5f, 0.0f, 0.5f,
  551. 0.5f, 0.5f, 0.0f,
  552. 0.5f, 0.5f, 0.5f,
  553. 0.75f, 0.75f, 0.75f,
  554. 0.0f, 0.0f, 1.0f,
  555. 0.0f, 1.0f, 0.0f,
  556. 0.0f, 1.0f, 1.0f,
  557. 1.0f, 0.0f, 0.0f,
  558. 1.0f, 0.0f, 1.0f,
  559. 1.0f, 1.0f, 0.0f,
  560. 1.0f, 1.0f, 1.0f,
  561. 0.75f, 0.39f, 0.0f
  562. };
  563. #define WALL_SET 0
  564. #define FLOOR_SET 1
  565. #define CEILING_SET 2
  566. static float *smooth_sets[3][2][4] =
  567. {
  568. &colors[1][0], &colors[2][0], &colors[4][0], &colors[7][0],
  569. &colors[2][0], &colors[1][0], &colors[7][0], &colors[4][0],
  570. &colors[10][0], &colors[2][0], &colors[4][0], &colors[6][0],
  571. &colors[10][0], &colors[2][0], &colors[4][0], &colors[6][0],
  572. &colors[9][0], &colors[1][0], &colors[2][0], &colors[3][0],
  573. &colors[9][0], &colors[1][0], &colors[2][0], &colors[3][0]
  574. };
  575. static float *flat_sets[3][2][4] =
  576. {
  577. &colors[8][0], &colors[8][0], &colors[8][0], &colors[8][0],
  578. &colors[15][0], &colors[15][0], &colors[15][0], &colors[15][0],
  579. &colors[2][0], &colors[2][0], &colors[2][0], &colors[2][0],
  580. &colors[2][0], &colors[2][0], &colors[2][0], &colors[2][0],
  581. &colors[9][0], &colors[9][0], &colors[9][0], &colors[9][0],
  582. &colors[9][0], &colors[9][0], &colors[9][0], &colors[9][0]
  583. };
  584. void SetAlphaCol(GLfloat *fv3)
  585. {
  586. if (maze_options.all_alpha)
  587. {
  588. GLfloat fv4[4];
  589. fv4[0] = fv3[0];
  590. fv4[1] = fv3[1];
  591. fv4[2] = fv3[2];
  592. fv4[3] = 0.5f;
  593. glColor4fv(fv4);
  594. }
  595. else
  596. {
  597. glColor3fv(fv3);
  598. }
  599. }
  600. static void WallDraw(PaintObject *po, MazeView *vw)
  601. {
  602. Wall *wall;
  603. float fx, fy, tx, ty, cx, cy, nx, ny;
  604. float **col_set;
  605. int reps;
  606. int rept;
  607. GLenum old_env;
  608. wall = po->u.wall.wall;
  609. reps = wall->pTexEnv->texRep.x;
  610. rept = wall->pTexEnv->texRep.y;
  611. fx = (float)FxFlt(wall->f.x);
  612. fy = (float)FxFlt(wall->f.y);
  613. tx = (float)FxFlt(wall->t.x);
  614. ty = (float)FxFlt(wall->t.y);
  615. nx = -(ty-fy);
  616. ny = (tx-fx);
  617. cx = (float)FxFlt(vw->pos.x);
  618. cy = (float)FxFlt(vw->pos.y);
  619. col_set = &flat_sets[WALL_SET][wall->col][0];
  620. switch(maze_options.render[WALLS])
  621. {
  622. case RENDER_NONE:
  623. return;
  624. case RENDER_SMOOTH:
  625. col_set = &smooth_sets[WALL_SET][wall->col][0];
  626. break;
  627. case RENDER_FLAT:
  628. case RENDER_TEXTURED:
  629. break;
  630. }
  631. // Compute dot product with wall normal to determine
  632. // wall direction. We need to know the wall direction
  633. // in order to ensure that the wall texture faces the
  634. // correct direction
  635. UseTextureEnv(wall->pTexEnv);
  636. if (wall->pTexEnv->bTransp)
  637. {
  638. if (!maze_options.all_alpha)
  639. {
  640. glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &old_env);
  641. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gTexEnvMode);
  642. glEnable(GL_BLEND);
  643. }
  644. }
  645. glBegin(GL_POLYGON);
  646. if ((fx-cx)*nx+(fy-cy)*ny > 0)
  647. {
  648. glTexCoord2d(0, 0);
  649. SetAlphaCol(col_set[0]);
  650. glVertex3f(fx, fy, 0.0f);
  651. glTexCoord2d(reps, 0);
  652. SetAlphaCol(col_set[1]);
  653. glVertex3f(tx, ty, 0.0f);
  654. glTexCoord2d(reps, rept);
  655. SetAlphaCol(col_set[2]);
  656. glVertex3f(tx, ty, maze_height);
  657. glTexCoord2d(0, rept);
  658. SetAlphaCol(col_set[3]);
  659. glVertex3f(fx, fy, maze_height);
  660. }
  661. else
  662. {
  663. glTexCoord2d(reps, 0);
  664. SetAlphaCol(col_set[0]);
  665. glVertex3f(fx, fy, 0.0f);
  666. glTexCoord2d(0, 0);
  667. SetAlphaCol(col_set[1]);
  668. glVertex3f(tx, ty, 0.0f);
  669. glTexCoord2d(0, rept);
  670. SetAlphaCol(col_set[2]);
  671. glVertex3f(tx, ty, maze_height);
  672. glTexCoord2d(reps, rept);
  673. SetAlphaCol(col_set[3]);
  674. glVertex3f(fx, fy, maze_height);
  675. }
  676. glEnd();
  677. if (wall->pTexEnv->bTransp)
  678. {
  679. if (!maze_options.all_alpha)
  680. {
  681. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, old_env);
  682. glDisable(GL_BLEND);
  683. }
  684. }
  685. }
  686. void (APIENTRY *convex_solids[SPECIAL_ARG_COUNT])(GLdouble radius) =
  687. {
  688. auxSolidIcosahedron,
  689. auxSolidOctahedron,
  690. auxSolidDodecahedron,
  691. auxSolidTetrahedron
  692. };
  693. static void PartialDraw(PaintObject *po, MazeView *vw)
  694. {
  695. PaintPartial *pp;
  696. float w, h, cx, cy, cz, vx, vy, fx, fy, fz, tx, ty, tz;
  697. float cs, sn;
  698. GLenum old_env;
  699. pp = &po->u.partial;
  700. w = (float)FxFlt(pp->obj->w);
  701. h = (float)FxFlt(pp->obj->h);
  702. // Partials are billboarded so we want it to always be
  703. // perpendicular to the view direction
  704. cs = (float)FxFlt(FaCos(vw->ang));
  705. sn = (float)FxFlt(FaSin(vw->ang));
  706. vx = -sn*w;
  707. vy = cs*w;
  708. cx = (float)FxFlt(pp->obj->p.x);
  709. cy = (float)FxFlt(pp->obj->p.y);
  710. cz = (float)FxFlt(pp->obj->z);
  711. fx = cx-vx;
  712. fy = cy-vy;
  713. fz = (cz-h)*maze_height;
  714. tx = cx+vx;
  715. ty = cy+vy;
  716. tz = (cz+h)*maze_height;
  717. if (maze_options.render[WALLS] == RENDER_TEXTURED)
  718. {
  719. glDisable(GL_TEXTURE_2D);
  720. }
  721. switch(pp->obj->draw_style)
  722. {
  723. case DRAW_POLYGON:
  724. glEnable(GL_TEXTURE_2D);
  725. if (!maze_options.all_alpha)
  726. {
  727. glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &old_env);
  728. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gTexEnvMode);
  729. glEnable(GL_BLEND);
  730. }
  731. UseTextureEnv( pp->obj->pTexEnv );
  732. SetAlphaCol(colors[15]);
  733. glBegin(GL_POLYGON);
  734. glNormal3f(cs, sn, 0.0f);
  735. glTexCoord2f(1.0f, 0.0f);
  736. glVertex3f(fx, fy, fz);
  737. glTexCoord2f(0.0f, 0.0f);
  738. glVertex3f(tx, ty, fz);
  739. glTexCoord2f(0.0f, 1.0f);
  740. glVertex3f(tx, ty, tz);
  741. glTexCoord2f(1.0f, 1.0f);
  742. glVertex3f(fx, fy, tz);
  743. glEnd();
  744. glDisable(GL_TEXTURE_2D);
  745. if (!maze_options.all_alpha)
  746. {
  747. glDisable(GL_BLEND);
  748. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, old_env);
  749. }
  750. break;
  751. case DRAW_SPECIAL:
  752. SetAlphaCol(colors[pp->obj->col]);
  753. glEnable(GL_AUTO_NORMAL);
  754. glEnable(GL_NORMALIZE);
  755. glEnable(GL_LIGHTING);
  756. glEnable(GL_CULL_FACE);
  757. glEnable(GL_DITHER);
  758. glPushMatrix();
  759. glTranslated(cx, cy, cz*maze_height);
  760. glScaled(1.0, 1.0, maze_height);
  761. glRotated(FaFltDegVal(pp->obj->ang), 0, 0, 1);
  762. glRotated(pp->obj->user3, 0, 1, 0);
  763. // Must use convex objects since depth testing can be off
  764. convex_solids[pp->obj->draw_arg](w);
  765. glPopMatrix();
  766. if( !maze_options.bDither )
  767. glDisable(GL_DITHER);
  768. glDisable(GL_CULL_FACE);
  769. glDisable(GL_LIGHTING);
  770. glDisable(GL_AUTO_NORMAL);
  771. glDisable(GL_NORMALIZE);
  772. break;
  773. }
  774. if (maze_options.render[WALLS] == RENDER_TEXTURED)
  775. {
  776. glEnable(GL_TEXTURE_2D);
  777. }
  778. }
  779. typedef void (*PoDrawFn)(PaintObject *po, MazeView *vw);
  780. static PoDrawFn PoDraw[PO_COUNT] =
  781. {
  782. WallDraw,
  783. PartialDraw
  784. };
  785. void RenderZPlane(int render, TEX_ENV *pTexEnv, int set, float zval)
  786. {
  787. float **col_set;
  788. int reps = pTexEnv->texRep.x;
  789. int rept = pTexEnv->texRep.y;
  790. switch(render)
  791. {
  792. case RENDER_NONE:
  793. break;
  794. case RENDER_TEXTURED:
  795. UseTextureEnv(pTexEnv);
  796. glEnable(GL_TEXTURE_2D);
  797. // Fall through
  798. case RENDER_FLAT:
  799. case RENDER_SMOOTH:
  800. col_set = &flat_sets[set][0][0];
  801. if (render == RENDER_SMOOTH)
  802. {
  803. col_set = &smooth_sets[set][0][0];
  804. }
  805. glBegin(GL_POLYGON);
  806. // Switch texture orientation dependent on surface type
  807. if( set == CEILING_SET ) {
  808. glTexCoord2f((float)reps*MAZE_SIZE, 0.0f);
  809. glColor3fv(col_set[0]);
  810. glVertex3f(0.0f, 0.0f, zval);
  811. glTexCoord2f(0.0f, 0.0f);
  812. glColor3fv(col_set[1]);
  813. glVertex3f((float)MAZE_SIZE, 0.0f, zval);
  814. glTexCoord2f(0.0f, (float)rept*MAZE_SIZE);
  815. glColor3fv(col_set[2]);
  816. glVertex3f((float)MAZE_SIZE, (float)MAZE_SIZE, zval);
  817. glTexCoord2f((float)reps*MAZE_SIZE, (float)rept*MAZE_SIZE);
  818. glColor3fv(col_set[3]);
  819. glVertex3f(0.0f, (float)MAZE_SIZE, zval);
  820. } else {
  821. glTexCoord2f(0.0f, 0.0f);
  822. glColor3fv(col_set[0]);
  823. glVertex3f(0.0f, 0.0f, zval);
  824. glTexCoord2f((float)reps*MAZE_SIZE, 0.0f);
  825. glColor3fv(col_set[1]);
  826. glVertex3f((float)MAZE_SIZE, 0.0f, zval);
  827. glTexCoord2f((float)reps*MAZE_SIZE, (float)rept*MAZE_SIZE);
  828. glColor3fv(col_set[2]);
  829. glVertex3f((float)MAZE_SIZE, (float)MAZE_SIZE, zval);
  830. glTexCoord2f(0.0f, (float)rept*MAZE_SIZE);
  831. glColor3fv(col_set[3]);
  832. glVertex3f(0.0f, (float)MAZE_SIZE, zval);
  833. }
  834. glEnd();
  835. if (render == RENDER_TEXTURED)
  836. {
  837. glDisable(GL_TEXTURE_2D);
  838. }
  839. break;
  840. }
  841. }
  842. void Render(MazeView *vw)
  843. {
  844. FxValue cs, sn;
  845. PaintObject *sorted, *so, *pso;
  846. PaintObject *po;
  847. int i;
  848. FxPt2 at;
  849. BOOL special;
  850. float viewHeight;
  851. cs = FaCos(vw->ang);
  852. sn = FaSin(vw->ang);
  853. at.x = vw->pos.x+cs;
  854. at.y = vw->pos.y+sn;
  855. glMatrixMode(GL_PROJECTION);
  856. glLoadIdentity();
  857. glRotated(view_rot, 0, 0, 1);
  858. gluPerspective(VIEW_ANG, 1, .01, 100);
  859. viewHeight = 0.5f;
  860. gluLookAt(FxFlt(vw->pos.x), FxFlt(vw->pos.y), viewHeight,
  861. FxFlt(at.x), FxFlt(at.y), viewHeight,
  862. 0, 0, 1);
  863. glMatrixMode(GL_MODELVIEW);
  864. glLoadIdentity();
  865. RenderZPlane(maze_options.render[FLOOR], &gTexEnv[TEX_FLOOR], FLOOR_SET, 0.0f);
  866. RenderZPlane(maze_options.render[CEILING], &gTexEnv[TEX_CEILING], CEILING_SET, 1.0f);
  867. sorted = NULL;
  868. special = FALSE;
  869. for (i = 0, po = paint; i < npaint; i++, po++)
  870. {
  871. if (po->type == PO_PARTIAL &&
  872. po->u.partial.obj->draw_style == DRAW_SPECIAL)
  873. {
  874. special = TRUE;
  875. }
  876. PoCompute[po->type](po, vw, cs, sn);
  877. for (so = sorted, pso = NULL; so; pso = so, so = so->closer)
  878. {
  879. if (so->depth <= po->depth)
  880. {
  881. break;
  882. }
  883. }
  884. if (pso == NULL)
  885. {
  886. sorted = po;
  887. }
  888. else
  889. {
  890. pso->closer = po;
  891. }
  892. po->closer = so;
  893. }
  894. #if 0
  895. // Unnecessary at the moment, but might be handy later
  896. if (special && !maze_options.depth_test)
  897. {
  898. glClear(GL_DEPTH_BUFFER_BIT);
  899. }
  900. #endif
  901. if (maze_options.render[WALLS] == RENDER_TEXTURED)
  902. {
  903. glEnable(GL_TEXTURE_2D);
  904. }
  905. for (so = sorted; so; so = so->closer)
  906. {
  907. PoDraw[so->type](so, vw);
  908. }
  909. if (maze_options.render[WALLS] == RENDER_TEXTURED)
  910. {
  911. glDisable(GL_TEXTURE_2D);
  912. }
  913. }
  914. void InitPaint(void)
  915. {
  916. int i, j;
  917. npaint = 0;
  918. for (i = 0; i < MAZE_GRID; i++)
  919. {
  920. for (j = 0; j < MAZE_GRID; j++)
  921. {
  922. maze_cells[i][j].unseen = maze_cells[i][j].can_see | MAZE_CONTENTS;
  923. }
  924. }
  925. }
  926. void DrawMaze(MazeView *vw)
  927. {
  928. InitPaint();
  929. TraceView(vw);
  930. Render(vw);
  931. }
  932. void DrawMazeWalls(void)
  933. {
  934. int w;
  935. Wall *wall;
  936. wall = maze;
  937. glColor3f(1.0f, 1.0f, 1.0f);
  938. glBegin(GL_LINES);
  939. for (w = 0; w < nwalls; w++)
  940. {
  941. glVertex2f((float)FxFltVal(wall->f.x), (float)FxFltVal(wall->f.y));
  942. glVertex2f((float)FxFltVal(wall->t.x), (float)FxFltVal(wall->t.y));
  943. wall++;
  944. }
  945. glEnd();
  946. }
  947. #define SQRT2_2 0.707107f
  948. void DrawTopView(MazeView *vw)
  949. {
  950. int c;
  951. Cell *cell;
  952. Object *obj;
  953. float vx, vy, cx, cy, width, ang;
  954. extern float gfAspect;
  955. glMatrixMode(GL_PROJECTION);
  956. glLoadIdentity();
  957. //mf: if image being stretched, gfAspect isn't enought to make this straight -
  958. // need to compensate by using aspect of base dimensions as well.
  959. //mf? maybe use glScale ?
  960. gluOrtho2D( -MAZE_SIZE/2.0, MAZE_SIZE/2.0,
  961. -MAZE_SIZE/2.0/gfAspect, MAZE_SIZE/2.0/gfAspect );
  962. glMatrixMode(GL_MODELVIEW);
  963. glPushMatrix();
  964. ang = (float)FaFltDegVal(vw->ang)+90.0f;
  965. glRotatef(ang, 0.0f, 0.0f, 1.0f);
  966. vx = (float)FxFltVal(vw->pos.x);
  967. vy = (float)FxFltVal(vw->pos.y);
  968. glTranslatef(-vx, -vy, 0.0f);
  969. #define AA_LINES 1
  970. #ifdef AA_LINES
  971. // Turn on antialiased lines
  972. glEnable( GL_BLEND );
  973. glEnable( GL_LINE_SMOOTH );
  974. glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
  975. #endif
  976. glCallList(maze_walls_list);
  977. #ifdef AA_LINES
  978. glDisable( GL_BLEND );
  979. glDisable( GL_LINE_SMOOTH );
  980. #endif
  981. // Objects aren't put in the walls display list so that they
  982. // can move around
  983. cell = &maze_cells[0][0];
  984. for (c = 0; c < MAZE_CELLS; c++)
  985. {
  986. for (obj = cell->contents; obj != NULL; obj = obj->next)
  987. {
  988. cx = (float)FxFltVal(obj->p.x);
  989. cy = (float)FxFltVal(obj->p.y);
  990. width = (float)FxFltVal(obj->w);
  991. glColor3fv(colors[obj->col]);
  992. glPushMatrix();
  993. glTranslatef(cx, cy, 0.0f);
  994. glRotated(FaFltDegVal(obj->ang), 0, 0, 1);
  995. #if 1
  996. glBegin(GL_POLYGON);
  997. glVertex2f(width, 0.0f);
  998. glVertex2f(-width*SQRT2_2, width*0.5f);
  999. glVertex2f(-width*SQRT2_2, -width*0.5f);
  1000. glEnd();
  1001. #else
  1002. glRectf(-width, -width, width, width);
  1003. #endif
  1004. glPopMatrix();
  1005. }
  1006. cell++;
  1007. }
  1008. glPopMatrix();
  1009. // Draw self
  1010. glColor3f(0.0f, 0.0f, 1.0f);
  1011. width = MAZE_CELL_SIZE/4.0f;
  1012. glBegin(GL_POLYGON);
  1013. glVertex2f(0.0f, width);
  1014. glVertex2f(width*0.5f, -width*SQRT2_2);
  1015. glVertex2f(-width*0.5f, -width*SQRT2_2);
  1016. glEnd();
  1017. }