1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* maze3d --- A recreation of the old 3D maze screensaver from Windows 95.
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted,
6 * provided that the above copyright notice appear in all copies and that
7 * both that copyright notice and this permission notice appear in
8 * supporting documentation.
10 * This file is provided AS IS with no warranties of any kind. The author
11 * shall have no liability with respect to the infringement of copyrights,
12 * trade secrets or any patents by this file or any part thereof. In no
13 * event will the author be liable for any lost revenue or profits or
14 * other special, indirect and consequential damages.
18 * 03-Apr-2018: Released initial version of "3D Maze"
22 #undef USE_FLOATING_IMAGES
23 #undef USE_FRACTAL_IMAGES
26 #define DEFAULTS "*delay: 20000 \n" \
27 "*showFPS: False \n" \
29 #define release_maze 0
30 # include "xlockmore.h" /* from the xscreensaver distribution */
31 #else /* !STANDALONE */
32 # include "xlock.h" /* from the xlockmore distribution */
33 #endif /* !STANDALONE */
36 #ifdef USE_GL /* whole file */
38 #define DEF_ANGULAR_CONVERSION_FACTOR 90
39 #define DEF_SPEED "1.0"
40 #define DEF_NUM_ROWS "12"
41 #define DEF_NUM_COLUMNS "12"
42 #define DEF_NUM_RATS "1"
43 #define DEF_NUM_INVERTERS "10"
44 #define DEF_SHOW_OVERLAY "False"
45 #define DEF_DROP_ACID "False"
48 #define countof(x) (sizeof((x))/sizeof((*x)))
50 #include "../images/gen/brick1_png.h"
51 #include "../images/gen/brick2_png.h"
52 #include "../images/gen/wood2_png.h"
53 #include "../images/gen/start_png.h"
54 #include "../images/gen/bob_png.h"
55 #include "../images/gen/logo-32_png.h"
57 #ifdef USE_FLOATING_IMAGES
58 # include "../images/gen/opengltxt_png.h"
59 # include "../images/gen/openglbook_png.h"
61 #ifdef USE_FRACTAL_IMAGES
62 # include "../images/gen/fractal1_png.h"
63 # include "../images/gen/fractal2_png.h"
64 # include "../images/gen/fractal3_png.h"
65 # include "../images/gen/fractal4_png.h"
68 #include "ximage-loader.h"
70 static int dropAcid, dropAcidWalls, dropAcidCeiling, dropAcidFloor, numInverters, numRats;
71 #ifdef USE_FLOATING_IMAGES
72 static int numGl3dTexts, numGlRedbooks;
74 static int shouldDrawOverlay, numRows, numColumns;
75 static char *wallTexture, *floorTexture, *ceilingTexture;
78 static XrmOptionDescRec opts[] = {
79 {"-drop-acid", ".maze3d.dropAcid", XrmoptionNoArg, "true"},
80 {"-drop-acid-walls", ".maze3d.dropAcidWalls", XrmoptionNoArg, "true"},
81 {"-drop-acid-floor", ".maze3d.dropAcidFloor", XrmoptionNoArg, "true"},
82 {"-drop-acid-ceiling", ".maze3d.dropAcidCeiling", XrmoptionNoArg, "true"},
83 {"-wall-texture", ".maze3d.wallTexture", XrmoptionSepArg, 0},
84 {"-floor-texture", ".maze3d.floorTexture", XrmoptionSepArg, 0},
85 {"-ceiling-texture", ".maze3d.ceilingTexture", XrmoptionSepArg, 0},
86 {"-rows", ".maze3d.numRows", XrmoptionSepArg, 0},
87 {"-columns", ".maze3d.numColumns", XrmoptionSepArg, 0},
88 {"-inverters", ".maze3d.numInverters", XrmoptionSepArg, 0},
89 {"-rats", ".maze3d.numRats", XrmoptionSepArg, 0},
90 # ifdef USE_FLOATING_IMAGES
91 {"-gl-3d-texts", ".maze3d.numGl3dTexts", XrmoptionSepArg, 0},
92 {"-gl-redbooks", ".maze3d.numGlRedbooks", XrmoptionSepArg, 0},
94 {"-overlay", ".maze3d.showOverlay", XrmoptionNoArg, "true"},
95 {"-speed", ".maze3d.speed", XrmoptionSepArg, 0},
98 static argtype vars[] = {
99 {&dropAcid, "dropAcid", "Drop Acid", DEF_DROP_ACID, t_Bool},
100 {&dropAcidWalls, "dropAcidWalls", "Drop Acid Walls", "False", t_Bool},
101 {&dropAcidFloor, "dropAcidFloor", "Drop Acid Floor", "False", t_Bool},
102 {&dropAcidCeiling, "dropAcidCeiling", "Drop Acid Ceiling", "False", t_Bool},
103 {&wallTexture, "wallTexture", "Wall Texture", "brick-wall", t_String},
104 {&floorTexture, "floorTexture", "Floor Texture", "wood-floor", t_String},
105 {&ceilingTexture, "ceilingTexture", "Ceiling Texture", "ceiling-tiles",
107 {&numRows, "numRows", "Number of Rows", DEF_NUM_ROWS, t_Int},
108 {&numColumns, "numColumns", "Number of Columns", DEF_NUM_COLUMNS, t_Int},
109 {&numInverters, "numInverters", "Number of Inverters", DEF_NUM_INVERTERS, t_Int},
110 {&numRats, "numRats", "Number of Rats", DEF_NUM_RATS, t_Int},
111 # ifdef USE_FLOATING_IMAGES
112 {&numGl3dTexts, "numGl3dTexts", "Number of GL 3D Texts", "3", t_Int},
113 {&numGlRedbooks, "numGlRedbooks", "Number of GL Redbooks", "3", t_Int},
115 {&shouldDrawOverlay, "showOverlay", "Show Overlay", DEF_SHOW_OVERLAY, t_Bool},
116 {&speed, "speed", "speed", DEF_SPEED, t_Float},
119 ENTRYPOINT ModeSpecOpt maze_opts = {countof(opts), opts, countof(vars), vars, NULL};
123 WALL, CELL_UNVISITED, CELL, START, FINISH, GL_3D_TEXT, INVERTER_TETRAHEDRON,
124 INVERTER_OCTAHEDRON, INVERTER_DODECAHEDRON, INVERTER_ICOSAHEDRON,
130 STARTING, WALKING, TURNING_LEFT, TURNING_RIGHT, TURNING_AROUND, INVERTING,
136 ARROW = 15, SQUARE, STAR, TRIANGLE
141 NORTH = 0, EAST = 90, SOUTH = 180, WEST = 270
146 unsigned row, column;
156 GLfloat red, green, blue;
162 GLfloat rotation, desiredRotation, inversion, remainingDistanceToTravel;
163 unsigned char state, isCamera;
167 /* structure for holding the maze data */
170 GLXContext *glx_context;
172 unsigned char **mazeGrid;
174 unsigned wallListSize;
175 Tuple startPosition, finishPosition, *inverterPosition,
177 GLuint wallTexture, floorTexture, ceilingTexture, startTexture,
178 finishTexture, ratTexture;
181 # ifdef USE_FLOATING_IMAGES
182 GLuint gl3dTextTexture, glTextbookTexture;
184 # ifdef USE_FRACTAL_IMAGES
185 GLuint fractal1Texture, fractal2Texture, fractal3Texture, fractal4Texture;
189 GLfloat wallHeight, inverterRotation;
191 int numRows, numColumns, numGlRedbooks;
192 GLuint dlists[30]; /* ARROW etc index into this */
194 } maze_configuration;
196 static maze_configuration *mazes = NULL;
198 static void newMaze(maze_configuration* maze);
199 static void constructLists(ModeInfo *);
200 static void initializeGrid(maze_configuration* maze);
201 static float roundToNearestHalf(float num);
202 static unsigned isOdd(unsigned num);
203 static unsigned isEven(unsigned num);
204 static void buildMaze(maze_configuration* maze);
205 static void addWallsToList(Tuple cell, maze_configuration* maze);
206 static unsigned char isRemovableWall(Tuple coordinates,
207 maze_configuration* maze);
208 static void addCells(Tuple cellToAdd, Tuple currentWall,
209 maze_configuration* maze);
210 static void removeWallFromList(unsigned index, maze_configuration* maze);
211 static void placeMiscObjects(maze_configuration* maze);
212 static Tuple placeObject(maze_configuration* maze, unsigned char type);
213 static void shiftAcidColor(maze_configuration* maze);
214 static void refreshRemainingDistanceToTravel(ModeInfo * mi);
215 static void step(Rat* rat, maze_configuration* maze);
216 static void walk(Rat* rat, char axis, int sign, maze_configuration* maze);
217 static void turn(Rat* rat, maze_configuration* maze);
218 static void turnAround(Rat* rat, maze_configuration* maze);
219 static void invert(maze_configuration* maze);
220 static void changeState(Rat* rat, maze_configuration* maze);
221 static void updateInverterRotation(maze_configuration* maze);
222 static void drawInverter(maze_configuration* maze, Tuple coordinates);
223 static void drawWalls(ModeInfo * mi);
224 static void drawWall(Tuple startCoordinates, Tuple endCoordinates,
225 maze_configuration* maze);
226 static void drawCeiling(ModeInfo * mi);
227 static void drawFloor(ModeInfo * mi);
228 static void drawPane(ModeInfo *, GLuint texture, Tuple position);
229 static void drawRat(Tuplef position, maze_configuration* maze);
230 static void drawOverlay(ModeInfo *);
232 /* Set up and enable texturing on our object */
234 setup_png_texture (ModeInfo *mi, const unsigned char *png_data,
235 unsigned long data_size)
237 XImage *image = image_data_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
238 png_data, data_size);
241 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
243 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
245 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
246 image->width, image->height, 0,
248 /* GL_UNSIGNED_BYTE, */
249 GL_UNSIGNED_INT_8_8_8_8_REV,
251 sprintf (buf, "builtin texture (%dx%d)", image->width, image->height);
257 setup_file_texture (ModeInfo *mi, char *filename)
259 Display *dpy = mi->dpy;
260 Visual *visual = mi->xgwa.visual;
263 XImage *image = file_to_ximage (dpy, visual, filename);
264 if (!image) return False;
267 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
268 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
269 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
270 image->width, image->height, 0,
272 GL_UNSIGNED_BYTE, image->data);
273 sprintf (buf, "texture: %.100s (%dx%d)",
274 filename, image->width, image->height);
280 setup_textures(ModeInfo * mi)
282 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
283 GLint mag = GL_NEAREST; /* GL_LINEAR */
285 glGenTextures(1, &maze->finishTexture);
286 glBindTexture(GL_TEXTURE_2D, maze->finishTexture);
287 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
288 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
289 setup_png_texture(mi, logo_32_png, sizeof(logo_32_png));
291 glGenTextures(1, &maze->ratTexture);
292 glBindTexture(GL_TEXTURE_2D, maze->ratTexture);
293 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
294 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
295 setup_png_texture(mi, bob_png, sizeof(bob_png));
297 # ifdef USE_FLOATING_IMAGES
298 glGenTextures(1, &maze->glTextbookTexture);
299 glBindTexture(GL_TEXTURE_2D, maze->glTextbookTexture);
300 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
301 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
302 setup_png_texture(mi, openglbook_png, sizeof(openglbook_png));
304 glGenTextures(1, &maze->gl3dTextTexture);
305 glBindTexture(GL_TEXTURE_2D, maze->gl3dTextTexture);
306 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
307 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
308 setup_png_texture(mi, opengltxt_png, sizeof(opengltxt_png));
311 # ifdef USE_FRACTAL_IMAGES
312 glGenTextures(1, &maze->fractal1Texture);
313 glBindTexture(GL_TEXTURE_2D, maze->fractal1Texture);
314 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
315 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
316 setup_png_texture(mi, fractal1_png, sizeof(fractal1_png));
318 glGenTextures(1, &maze->fractal2Texture);
319 glBindTexture(GL_TEXTURE_2D, maze->fractal2Texture);
320 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
321 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
322 setup_png_texture(mi, fractal2_png, sizeof(fractal2_png));
324 glGenTextures(1, &maze->fractal3Texture);
325 glBindTexture(GL_TEXTURE_2D, maze->fractal3Texture);
326 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
327 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
328 setup_png_texture(mi, fractal3_png, sizeof(fractal3_png));
330 glGenTextures(1, &maze->fractal4Texture);
331 glBindTexture(GL_TEXTURE_2D, maze->fractal4Texture);
332 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
333 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
334 setup_png_texture(mi, fractal4_png, sizeof(fractal4_png));
337 glGenTextures(1, &maze->startTexture);
338 glBindTexture(GL_TEXTURE_2D, maze->startTexture);
339 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
340 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
341 setup_png_texture(mi, start_png, sizeof(start_png));
343 glGenTextures(1, &maze->ceilingTexture);
344 glBindTexture(GL_TEXTURE_2D, maze->ceilingTexture);
345 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
346 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
347 if (!ceilingTexture || !*ceilingTexture
348 || !strcmp(ceilingTexture, "ceiling-tiles")) {
349 DEFAULT_CEILING_TEXTURE:
350 setup_png_texture(mi, brick2_png, sizeof(brick2_png));
351 } else if (!strcmp(ceilingTexture, "brick-wall")) {
352 setup_png_texture(mi, brick1_png, sizeof(brick1_png));
353 } else if (!strcmp(ceilingTexture, "wood-floor")) {
354 setup_png_texture(mi, wood2_png, sizeof(wood2_png));
355 # ifdef USE_FRACTAL_IMAGES
356 } else if (!strcmp(ceilingTexture, "fractal-1")) {
357 setup_png_texture(mi, fractal1_png, sizeof(fractal1_png));
359 } else if (!strcmp(ceilingTexture, "fractal-2")) {
360 setup_png_texture(mi, fractal2_png, sizeof(fractal2_png));
362 } else if (!strcmp(ceilingTexture, "fractal-3")) {
363 setup_png_texture(mi, fractal3_png, sizeof(fractal3_png));
365 } else if (!strcmp(ceilingTexture, "fractal-4")) {
366 setup_png_texture(mi, fractal4_png, sizeof(fractal4_png));
370 if (!setup_file_texture(mi, ceilingTexture))
371 goto DEFAULT_CEILING_TEXTURE;
374 glGenTextures(1, &maze->floorTexture);
375 glBindTexture(GL_TEXTURE_2D, maze->floorTexture);
376 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
377 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
378 if (!floorTexture || !*floorTexture
379 || !strcmp(floorTexture, "wood-floor")) {
380 DEFAULT_FLOOR_TEXTURE:
381 setup_png_texture(mi, wood2_png, sizeof(wood2_png));
382 } else if (!strcmp(floorTexture, "ceiling-tiles")) {
383 setup_png_texture(mi, brick2_png, sizeof(brick2_png));
384 } else if (!strcmp(floorTexture, "brick-wall")) {
385 setup_png_texture(mi, brick1_png, sizeof(brick1_png));
386 # ifdef USE_FRACTAL_IMAGES
387 } else if (!strcmp(floorTexture, "fractal-1")) {
388 setup_png_texture(mi, fractal1_png, sizeof(fractal1_png));
390 } else if (!strcmp(floorTexture, "fractal-2")) {
391 setup_png_texture(mi, fractal2_png, sizeof(fractal2_png));
393 } else if (!strcmp(floorTexture, "fractal-3")) {
394 setup_png_texture(mi, fractal3_png, sizeof(fractal3_png));
396 } else if (!strcmp(floorTexture, "fractal-4")) {
397 setup_png_texture(mi, fractal4_png, sizeof(fractal4_png));
401 if (!setup_file_texture(mi, floorTexture))
402 goto DEFAULT_FLOOR_TEXTURE;
405 glGenTextures(1, &maze->wallTexture);
406 glBindTexture(GL_TEXTURE_2D, maze->wallTexture);
407 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
408 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mag);
409 if (!wallTexture || !*wallTexture || !strcmp(wallTexture, "brick-wall")) {
410 DEFAULT_WALL_TEXTURE:
411 setup_png_texture(mi, brick1_png, sizeof(brick1_png));
412 } else if (!strcmp(wallTexture, "ceiling-tiles")) {
413 setup_png_texture(mi, brick2_png, sizeof(brick2_png));
414 } else if (!strcmp(wallTexture, "wood-floor")) {
415 setup_png_texture(mi, wood2_png, sizeof(wood2_png));
416 # ifdef USE_FRACTAL_IMAGES
417 } else if (!strcmp(wallTexture, "fractal-1")) {
418 setup_png_texture(mi, fractal1_png, sizeof(fractal1_png));
420 } else if (!strcmp(wallTexture, "fractal-2")) {
421 setup_png_texture(mi, fractal2_png, sizeof(fractal2_png));
423 } else if (!strcmp(wallTexture, "fractal-3")) {
424 setup_png_texture(mi, fractal3_png, sizeof(fractal3_png));
426 } else if (!strcmp(wallTexture, "fractal-4")) {
427 setup_png_texture(mi, fractal4_png, sizeof(fractal4_png));
431 if (!setup_file_texture(mi, wallTexture))
432 goto DEFAULT_WALL_TEXTURE;
437 initializeGrid(maze_configuration* maze)
441 for (i = 0; i < maze->numRows; i++) {
442 for (j = 0; j < maze->numColumns; j++) {
443 if (isOdd(i) && isOdd(j))
444 maze->mazeGrid[i][j] = CELL_UNVISITED;
446 maze->mazeGrid[i][j] = WALL;
452 roundToNearestHalf(float num)
454 return roundf(2.0 * num) / 2.0;
469 /*This is the randomized Prim's algorithm.*/
471 buildMaze(maze_configuration* maze)
473 Tuple cellToAdd, firstCell = {1, 1};
474 maze->mazeGrid[1][1] = CELL;
476 addWallsToList(firstCell, maze);
478 while (maze->wallListSize > 0) {
479 unsigned randomNum = random() % maze->wallListSize;
480 Tuple currentWall = maze->wallList[randomNum];
482 if (isEven(currentWall.row)) {
483 if (maze->mazeGrid[currentWall.row - 1][currentWall.column]
485 && maze->mazeGrid[currentWall.row + 1][currentWall.column]
488 cellToAdd.row = currentWall.row + 1;
489 cellToAdd.column = currentWall.column;
490 addCells(cellToAdd, currentWall, maze);
492 else if (maze->mazeGrid[currentWall.row + 1][currentWall.column]
494 && maze->mazeGrid[currentWall.row - 1][currentWall.column]
497 cellToAdd.row = currentWall.row - 1;
498 cellToAdd.column = currentWall.column;
499 addCells(cellToAdd, currentWall, maze);
502 if (maze->mazeGrid[currentWall.row][currentWall.column - 1]
504 && maze->mazeGrid[currentWall.row][currentWall.column + 1]
507 cellToAdd.row = currentWall.row;
508 cellToAdd.column = currentWall.column + 1;
509 addCells(cellToAdd, currentWall, maze);
511 else if (maze->mazeGrid[currentWall.row][currentWall.column + 1]
513 && maze->mazeGrid[currentWall.row][currentWall.column - 1]
516 cellToAdd.row = currentWall.row;
517 cellToAdd.column = currentWall.column - 1;
518 addCells(cellToAdd, currentWall, maze);
522 removeWallFromList(randomNum, maze);
527 addWallsToList(Tuple cell, maze_configuration* maze)
531 walls[0].row = cell.row - 1;
532 walls[0].column = cell.column;
533 walls[1].row = cell.row + 1;
534 walls[1].column = cell.column;
535 walls[2].row = cell.row;
536 walls[2].column = cell.column - 1;
537 walls[3].row = cell.row;
538 walls[3].column = cell.column + 1;
540 for (i = 0; i < 4; i++) {
541 if (isRemovableWall(walls[i], maze)) {
542 maze->wallList[maze->wallListSize] = walls[i];
543 maze->wallListSize++;
549 isRemovableWall(Tuple coordinates, maze_configuration* maze)
551 if (maze->mazeGrid[coordinates.row][coordinates.column] == WALL
552 && coordinates.row > 0
553 && coordinates.row < maze->numRows - 1
554 && coordinates.column > 0
555 && coordinates.column < maze->numColumns - 1
563 addCells(Tuple cellToAdd, Tuple currentWall, maze_configuration* maze)
565 maze->mazeGrid[currentWall.row][currentWall.column] = CELL;
566 maze->mazeGrid[cellToAdd.row][cellToAdd.column] = CELL;
567 addWallsToList(cellToAdd, maze);
571 removeWallFromList(unsigned index, maze_configuration* maze)
574 for (i = index + 1; i < maze->wallListSize; i++)
575 maze->wallList[i - 1] = maze->wallList[i];
577 maze->wallListSize--;
581 placeMiscObjects(maze_configuration* maze)
585 unsigned char object;
586 unsigned numSurroundingWalls = 3;
589 while (numSurroundingWalls >= 3) {
590 numSurroundingWalls = 0;
591 maze->startPosition = placeObject(maze, CELL);
593 object = maze->mazeGrid[maze->startPosition.row]
594 [maze->startPosition.column + 1];
595 if (object == WALL || object == WALL_GL_REDBOOK)
596 numSurroundingWalls++;
597 object = maze->mazeGrid[maze->startPosition.row - 1]
598 [maze->startPosition.column];
599 if (object == WALL || object == WALL_GL_REDBOOK)
600 numSurroundingWalls++;
601 object = maze->mazeGrid[maze->startPosition.row]
602 [maze->startPosition.column - 1];
603 if (object == WALL || object == WALL_GL_REDBOOK)
604 numSurroundingWalls++;
605 object = maze->mazeGrid[maze->startPosition.row + 1]
606 [maze->startPosition.column];
607 if (object == WALL || object == WALL_GL_REDBOOK)
608 numSurroundingWalls++;
610 maze->mazeGrid[maze->startPosition.row][maze->startPosition.column] = START;
612 if (maze->mazeGrid[maze->startPosition.row][maze->startPosition.column + 1]
613 != WALL && maze->mazeGrid[maze->startPosition.row]
614 [maze->startPosition.column + 1] != WALL_GL_REDBOOK) {
615 maze->camera.position.x = (maze->startPosition.column + 1) / 2.0;
616 maze->camera.position.z = maze->startPosition.row / 2.0;
617 maze->camera.rotation = WEST;
619 else if (maze->mazeGrid[maze->startPosition.row - 1]
620 [maze->startPosition.column] != WALL
621 && maze->mazeGrid[maze->startPosition.row - 1]
622 [maze->startPosition.column] != WALL_GL_REDBOOK) {
623 maze->camera.position.x = maze->startPosition.column / 2.0;
624 maze->camera.position.z = (maze->startPosition.row - 1) / 2.0;
625 maze->camera.rotation = SOUTH;
627 else if (maze->mazeGrid[maze->startPosition.row]
628 [maze->startPosition.column - 1] != WALL
629 && maze->mazeGrid[maze->startPosition.row]
630 [maze->startPosition.column - 1] != WALL_GL_REDBOOK) {
631 maze->camera.position.x = (maze->startPosition.column - 1) / 2.0;
632 maze->camera.position.z = maze->startPosition.row / 2.0;
633 maze->camera.rotation = EAST;
636 maze->camera.position.x = maze->startPosition.column / 2.0;
637 maze->camera.position.z = (maze->startPosition.row + 1) / 2.0;
638 maze->camera.rotation = NORTH;
641 maze->finishPosition = placeObject(maze, FINISH);
643 for (i = 0; i < numInverters; i++)
644 maze->inverterPosition[i] =
645 placeObject(maze, random() % 4 + INVERTER_TETRAHEDRON);
650 # ifdef USE_FLOATING_IMAGES
651 for (i = 0; i < numGl3dTexts; i++)
652 maze->gl3dTextPosition[i] =
653 placeObject(maze, GL_3D_TEXT);
656 for (i = 0; i < numRats; i++) {
657 rat = &(maze->rats[i]);
658 temp = placeObject(maze, CELL);
659 rat->position.x = temp.column / 2.0;
660 rat->position.z = temp.row / 2.0;
661 rat->state = WALKING;
663 if (temp.row == 0 && temp.column == 0) {
667 if (maze->mazeGrid[(int)(rat->position.z * 2)]
668 [(int)(rat->position.x * 2) + 1]
669 != WALL && maze->mazeGrid[(int)(rat->position.z * 2)]
670 [(int)(rat->position.x * 2) + 1] != WALL_GL_REDBOOK)
671 rat->rotation = EAST;
672 else if (maze->mazeGrid[(int)(rat->position.z * 2) - 1]
673 [(int)(rat->position.x * 2)]
674 != WALL && maze->mazeGrid[(int)(rat->position.z * 2) - 1]
675 [(int)(rat->position.x * 2)] != WALL_GL_REDBOOK)
676 rat->rotation = NORTH;
677 else if (maze->mazeGrid[(int)(rat->position.z * 2)]
678 [(int)(rat->position.x * 2) - 1]
679 != WALL && maze->mazeGrid[(int)(rat->position.z * 2)]
680 [(int)(rat->position.x * 2) - 1] != WALL_GL_REDBOOK)
681 rat->rotation = WEST;
683 rat->rotation = SOUTH;
686 # ifdef USE_FLOATING_IMAGES
687 for (i = 0; i < numGlRedbooks; i++) {
688 while (!(((isOdd(temp.row) && isEven(temp.column))
689 || (isEven(temp.row) && isOdd(temp.column)))
690 && maze->mazeGrid[temp.row][temp.column] == WALL)) {
691 temp.row = random() % maze->numRows;
692 temp.column = random() % maze->numColumns;
695 maze->mazeGrid[temp.row][temp.column] = WALL_GL_REDBOOK;
701 placeObject(maze_configuration* maze, unsigned char type)
703 Tuple position = {0, 0};
705 while (!(maze->mazeGrid[position.row][position.column] == CELL
706 && isOdd(position.row) && isOdd(position.column))) {
707 position.row = random() % maze->numRows;
708 position.column = random() % maze->numColumns;
711 maze->mazeGrid[position.row][position.column] = type;
716 reshape_maze (ModeInfo *mi, int width, int height)
718 glViewport(0, 0, (GLint) width, (GLint) height);
719 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
724 maze_handle_event (ModeInfo *mi, XEvent *event)
726 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
727 if (event->xany.type == ButtonPress)
729 maze->button_down_p = True;
732 else if (event->xany.type == ButtonRelease)
734 maze->button_down_p = False;
741 init_maze (ModeInfo * mi)
744 maze_configuration *maze;
745 GLfloat ambient[] = {0, 0, 0, 1},
746 diffuse[] = {1, 1, 1, 1},
747 position[] = {0, 2, 0, 0},
748 mcolor[] = {1, 1, 1, 1};
751 maze = &mazes[MI_SCREEN(mi)];
753 maze->glx_context = init_GL(mi);
755 reshape_maze(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
757 for (i = 0; i < countof(maze->dlists); i++)
758 maze->dlists[i] = glGenLists (1);
760 maze->numRows = (numRows < 2 ? 5 : numRows * 2 + 1);
761 maze->numColumns = (numColumns < 2 ? 5 : numColumns * 2 + 1);
763 i = (maze->numRows / 2) * (maze->numColumns / 2) - 2;
764 if (i < numInverters) {
767 } else i -= numInverters;
773 # ifdef USE_FLOATING_IMAGES
774 if (i < numGl3dTexts) {
777 } else i -= numGl3dTexts;
779 if (((maze->numRows - 1) + (maze->numColumns - 1)
780 + ((maze->numRows / 2 - 1) * (maze->numColumns / 2 - 1))) < maze->numGlRedbooks)
781 maze->numGlRedbooks = (maze->numRows - 1) + (maze->numColumns - 1)
782 + ((maze->numRows / 2 - 1) * (maze->numColumns / 2 - 1));
785 glEnable(GL_DEPTH_TEST);
786 glEnable(GL_TEXTURE_2D);
789 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
790 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
791 glLightfv(GL_LIGHT0, GL_POSITION, position);
792 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mcolor);
794 glShadeModel(GL_FLAT);
796 maze->mazeGrid = calloc(maze->numRows, sizeof(unsigned char*));
797 for (i = 0; i < maze->numRows; i++)
798 maze->mazeGrid[i] = calloc(maze->numColumns, sizeof(unsigned char));
799 maze->wallList = calloc(((maze->numColumns - 2) / 2) * ((maze->numRows - 2) / 2 + 1)
800 + ((maze->numColumns - 2) / 2 + 1) * ((maze->numRows - 2) / 2), sizeof(Tuple));
801 maze->inverterPosition = calloc(numInverters, sizeof(Tuple));
802 maze->rats = calloc(numRats, sizeof(Rat));
803 # ifdef USE_FLOATING_IMAGES
804 maze->gl3dTextPosition = calloc(numGl3dTexts, sizeof(Tuple));
812 refreshRemainingDistanceToTravel(mi);
814 maze->camera.isCamera = 1;
815 for (i = 0; i < numRats; i++)
816 maze->rats[i].isCamera = 0;
820 newMaze(maze_configuration* maze)
822 maze->camera.state = STARTING;
823 maze->camera.inversion = 0;
824 maze->wallHeight = 0;
825 maze->inverterRotation = 0;
828 initializeGrid(maze);
830 placeMiscObjects(maze);
834 constructLists(ModeInfo *mi)
836 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
838 glNewList(maze->dlists[ARROW], GL_COMPILE);
840 glVertex2f(0, -0.25);
841 glVertex2f(0.146946313, 0.202254249);
842 glVertex2f(0, 0.125);
843 glVertex2f(-0.146946313, 0.202254249);
847 glNewList(maze->dlists[SQUARE], GL_COMPILE);
849 glVertex2f(-0.176776695, -0.176776695);
850 glVertex2f(0.176776695, -0.176776695);
851 glVertex2f(0.176776695, 0.176776695);
852 glVertex2f(-0.176776695, 0.176776695);
856 glNewList(maze->dlists[STAR], GL_COMPILE);
857 glBegin(GL_TRIANGLE_FAN);
859 glVertex2f(0, -0.25);
860 glVertex2f(0.073473157, -0.101127124);
861 glVertex2f(0.237764129, -0.077254249);
862 glVertex2f(0.118882065, 0.038627124);
863 glVertex2f(0.146946313, 0.202254249);
864 glVertex2f(0, 0.125);
865 glVertex2f(-0.146946313, 0.202254249);
866 glVertex2f(-0.118882065, 0.038627124);
867 glVertex2f(-0.237764129, -0.077254249);
868 glVertex2f(-0.073473157, -0.101127124);
869 glVertex2f(0, -0.25);
873 glNewList(maze->dlists[TRIANGLE], GL_COMPILE);
875 glVertex2f(0, -0.25);
876 glVertex2f(0.216506351, 0.125);
877 glVertex2f(-0.216506351, 0.125);
881 glNewList(maze->dlists[INVERTER_TETRAHEDRON], GL_COMPILE);
882 glBegin(GL_TRIANGLES);
883 glNormal3f(0.471404521, 0.816496581, 0.333333333);
884 glVertex3f(0, 0, 0.25);
885 glVertex3f(0.23570226, 0, -0.083333333);
886 glVertex3f(-0.11785113, 0.204124145, -0.083333333);
888 glNormal3f(-0.942809042, 0, 0.333333333);
889 glVertex3f(0, 0, 0.25);
890 glVertex3f(-0.11785113, 0.204124145, -0.083333333);
891 glVertex3f(-0.11785113, -0.204124145, -0.083333333);
893 glNormal3f(0.471404521, -0.816496581, 0.333333333);
894 glVertex3f(0, 0, 0.25);
895 glVertex3f(-0.11785113, -0.204124145, -0.083333333);
896 glVertex3f(0.23570226, 0, -0.083333333);
898 glNormal3f(0, 0, -1);
899 glVertex3f(0.23570226, 0, -0.083333333);
900 glVertex3f(-0.11785113, -0.204124145, -0.083333333);
901 glVertex3f(-0.11785113, 0.204124145, -0.083333333);
905 glNewList(maze->dlists[INVERTER_OCTAHEDRON], GL_COMPILE);
906 glBegin(GL_TRIANGLES);
907 glNormal3f(0.577350269, 0.577350269, 0.577350269);
908 glVertex3f(0, 0, 0.25);
909 glVertex3f(0.25, 0, 0);
910 glVertex3f(0, 0.25, 0);
912 glNormal3f(-0.577350269, 0.577350269, 0.577350269);
913 glVertex3f(0, 0, 0.25);
914 glVertex3f(0, 0.25, 0);
915 glVertex3f(-0.25, 0, 0);
917 glNormal3f(-0.577350269, -0.577350269, 0.577350269);
918 glVertex3f(0, 0, 0.25);
919 glVertex3f(-0.25, 0, 0);
920 glVertex3f(0, -0.25, 0);
922 glNormal3f(0.577350269, -0.577350269, 0.577350269);
923 glVertex3f(0, 0, 0.25);
924 glVertex3f(0, -0.25, 0);
925 glVertex3f(0.25, 0, 0);
927 glNormal3f(0.577350269, -0.577350269, -0.577350269);
928 glVertex3f(0.25, 0, 0);
929 glVertex3f(0, -0.25, 0);
930 glVertex3f(0, 0, -0.25);
932 glNormal3f(0.577350269, 0.577350269, -0.577350269);
933 glVertex3f(0.25, 0, 0);
934 glVertex3f(0, 0, -0.25);
935 glVertex3f(0, 0.25, 0);
937 glNormal3f(-0.577350269, 0.577350269, -0.577350269);
938 glVertex3f(0, 0.25, 0);
939 glVertex3f(0, 0, -0.25);
940 glVertex3f(-0.25, 0, 0);
942 glNormal3f(-0.577350269, -0.577350269, -0.577350269);
943 glVertex3f(-0.25, 0, 0);
944 glVertex3f(0, 0, -0.25);
945 glVertex3f(0, -0.25, 0);
949 glNewList(maze->dlists[INVERTER_DODECAHEDRON], GL_COMPILE);
951 glNormal3f(0.000000000, 0.000000000, 1.000000000);
952 glVertex3f(0.122780868, 0.089205522, 0.198663618);
953 glVertex3f(-0.046898119, 0.144337567, 0.198663618);
954 glVertex3f(-0.151765500, 0.000000000, 0.198663618);
955 glVertex3f(-0.046898119, -0.144337567, 0.198663618);
956 glVertex3f(0.122780868, -0.089205522, 0.198663618);
960 glNormal3f(0.894427191, 0.000000000, 0.447213595);
961 glVertex3f(0.198663618, -0.144337567, 0.046898119);
962 glVertex3f(0.245561737, 0.000000000, -0.046898119);
963 glVertex3f(0.198663618, 0.144337567, 0.046898119);
964 glVertex3f(0.122780868, 0.089205522, 0.198663618);
965 glVertex3f(0.122780868, -0.089205522, 0.198663618);
969 glNormal3f(0.276393202, 0.850650808, 0.447213595);
970 glVertex3f(0.198663618, 0.144337567, 0.046898119);
971 glVertex3f(0.075882750, 0.233543090, -0.046898119);
972 glVertex3f(-0.075882750, 0.233543090, 0.046898119);
973 glVertex3f(-0.046898119, 0.144337567, 0.198663618);
974 glVertex3f(0.122780868, 0.089205522, 0.198663618);
978 glNormal3f(-0.723606798, 0.525731112, 0.447213595);
979 glVertex3f(-0.075882750, 0.233543090, 0.046898119);
980 glVertex3f(-0.198663618, 0.144337567, -0.046898119);
981 glVertex3f(-0.245561737, 0.000000000, 0.046898119);
982 glVertex3f(-0.151765500, 0.000000000, 0.198663618);
983 glVertex3f(-0.046898119, 0.144337567, 0.198663618);
987 glNormal3f(-0.723606798, -0.525731112, 0.447213595);
988 glVertex3f(-0.245561737, 0.000000000, 0.046898119);
989 glVertex3f(-0.198663618, -0.144337567, -0.046898119);
990 glVertex3f(-0.075882750, -0.233543090, 0.046898119);
991 glVertex3f(-0.046898119, -0.144337567, 0.198663618);
992 glVertex3f(-0.151765500, 0.000000000, 0.198663618);
996 glNormal3f(0.276393202, -0.850650808, 0.447213595);
997 glVertex3f(-0.075882750, -0.233543090, 0.046898119);
998 glVertex3f(0.075882750, -0.233543090, -0.046898119);
999 glVertex3f(0.198663618, -0.144337567, 0.046898119);
1000 glVertex3f(0.122780868, -0.089205522, 0.198663618);
1001 glVertex3f(-0.046898119, -0.144337567, 0.198663618);
1004 glBegin(GL_POLYGON);
1005 glNormal3f(0.723606798, 0.525731112, -0.447213595);
1006 glVertex3f(0.245561737, 0.000000000, -0.046898119);
1007 glVertex3f(0.151765500, 0.000000000, -0.198663618);
1008 glVertex3f(0.046898119, 0.144337567, -0.198663618);
1009 glVertex3f(0.075882750, 0.233543090, -0.046898119);
1010 glVertex3f(0.198663618, 0.144337567, 0.046898119);
1013 glBegin(GL_POLYGON);
1014 glNormal3f(0.723606798, -0.525731112, -0.447213595);
1015 glVertex3f(0.198663618, -0.144337567, 0.046898119);
1016 glVertex3f(0.075882750, -0.233543090, -0.046898119);
1017 glVertex3f(0.046898119, -0.144337567, -0.198663618);
1018 glVertex3f(0.151765500, 0.000000000, -0.198663618);
1019 glVertex3f(0.245561737, 0.000000000, -0.046898119);
1022 glBegin(GL_POLYGON);
1023 glNormal3f(-0.276393202, 0.850650808, -0.447213595);
1024 glVertex3f(0.075882750, 0.233543090, -0.046898119);
1025 glVertex3f(0.046898119, 0.144337567, -0.198663618);
1026 glVertex3f(-0.122780868, 0.089205522, -0.198663618);
1027 glVertex3f(-0.198663618, 0.144337567, -0.046898119);
1028 glVertex3f(-0.075882750, 0.233543090, 0.046898119);
1031 glBegin(GL_POLYGON);
1032 glNormal3f(-0.894427191, 0.000000000, -0.447213595);
1033 glVertex3f(-0.198663618, 0.144337567, -0.046898119);
1034 glVertex3f(-0.122780868, 0.089205522, -0.198663618);
1035 glVertex3f(-0.122780868, -0.089205522, -0.198663618);
1036 glVertex3f(-0.198663618, -0.144337567, -0.046898119);
1037 glVertex3f(-0.245561737, 0.000000000, 0.046898119);
1040 glBegin(GL_POLYGON);
1041 glNormal3f(-0.276393202, -0.850650808, -0.447213595);
1042 glVertex3f(-0.198663618, -0.144337567, -0.046898119);
1043 glVertex3f(-0.122780868, -0.089205522, -0.198663618);
1044 glVertex3f(0.046898119, -0.144337567, -0.198663618);
1045 glVertex3f(0.075882750, -0.233543090, -0.046898119);
1046 glVertex3f(-0.075882750, -0.233543090, 0.046898119);
1049 glBegin(GL_POLYGON);
1050 glNormal3f(0.000000000, 0.000000000, -1.000000000);
1051 glVertex3f(0.046898119, -0.144337567, -0.198663618);
1052 glVertex3f(-0.122780868, -0.089205522, -0.198663618);
1053 glVertex3f(-0.122780868, 0.089205522, -0.198663618);
1054 glVertex3f(0.046898119, 0.144337567, -0.198663618);
1055 glVertex3f(0.151765500, 0.000000000, -0.198663618);
1059 glNewList(maze->dlists[INVERTER_ICOSAHEDRON], GL_COMPILE);
1060 glBegin(GL_TRIANGLES);
1061 glNormal3f(0.491123473, 0.356822090, 0.794654473);
1062 glVertex3f(0.000000000, 0.000000000, 0.250000000);
1063 glVertex3f(0.223606798, 0.000000000, 0.111803399);
1064 glVertex3f(0.069098301, 0.212662702, 0.111803399);
1066 glNormal3f(-0.187592474, 0.577350269, 0.794654473);
1067 glVertex3f(0.000000000, 0.000000000, 0.250000000);
1068 glVertex3f(0.069098301, 0.212662702, 0.111803399);
1069 glVertex3f(-0.180901699, 0.131432778, 0.111803399);
1071 glNormal3f(-0.607061998, 0.000000000, 0.794654473);
1072 glVertex3f(0.000000000, 0.000000000, 0.250000000);
1073 glVertex3f(-0.180901699, 0.131432778, 0.111803399);
1074 glVertex3f(-0.180901699, -0.131432778, 0.111803399);
1076 glNormal3f(-0.187592474, -0.577350269, 0.794654473);
1077 glVertex3f(0.000000000, 0.000000000, 0.250000000);
1078 glVertex3f(-0.180901699, -0.131432778, 0.111803399);
1079 glVertex3f(0.069098301, -0.212662702, 0.111803399);
1081 glNormal3f(0.491123473, -0.356822090, 0.794654473);
1082 glVertex3f(0.000000000, 0.000000000, 0.250000000);
1083 glVertex3f(0.069098301, -0.212662702, 0.111803399);
1084 glVertex3f(0.223606798, 0.000000000, 0.111803399);
1086 glNormal3f(0.794654473, -0.577350269, 0.187592474);
1087 glVertex3f(0.223606798, 0.000000000, 0.111803399);
1088 glVertex3f(0.069098301, -0.212662702, 0.111803399);
1089 glVertex3f(0.180901699, -0.131432778, -0.111803399);
1091 glNormal3f(0.982246947, 0.000000000, -0.187592474);
1092 glVertex3f(0.223606798, 0.000000000, 0.111803399);
1093 glVertex3f(0.180901699, -0.131432778, -0.111803399);
1094 glVertex3f(0.180901699, 0.131432778, -0.111803399);
1096 glNormal3f(0.794654473, 0.577350269, 0.187592474);
1097 glVertex3f(0.223606798, 0.000000000, 0.111803399);
1098 glVertex3f(0.180901699, 0.131432778, -0.111803399);
1099 glVertex3f(0.069098301, 0.212662702, 0.111803399);
1101 glNormal3f(0.303530999, 0.934172359, -0.187592474);
1102 glVertex3f(0.069098301, 0.212662702, 0.111803399);
1103 glVertex3f(0.180901699, 0.131432778, -0.111803399);
1104 glVertex3f(-0.069098301, 0.212662702, -0.111803399);
1106 glNormal3f(-0.303530999, 0.934172359, 0.187592474);
1107 glVertex3f(0.069098301, 0.212662702, 0.111803399);
1108 glVertex3f(-0.069098301, 0.212662702, -0.111803399);
1109 glVertex3f(-0.180901699, 0.131432778, 0.111803399);
1111 glNormal3f(-0.794654473, 0.577350269, -0.187592474);
1112 glVertex3f(-0.180901699, 0.131432778, 0.111803399);
1113 glVertex3f(-0.069098301, 0.212662702, -0.111803399);
1114 glVertex3f(-0.223606798, 0.000000000, -0.111803399);
1116 glNormal3f(-0.982246947, 0.000000000, 0.187592474);
1117 glVertex3f(-0.180901699, 0.131432778, 0.111803399);
1118 glVertex3f(-0.223606798, 0.000000000, -0.111803399);
1119 glVertex3f(-0.180901699, -0.131432778, 0.111803399);
1121 glNormal3f(-0.794654473, -0.577350269, -0.187592474);
1122 glVertex3f(-0.180901699, -0.131432778, 0.111803399);
1123 glVertex3f(-0.223606798, 0.000000000, -0.111803399);
1124 glVertex3f(-0.069098301, -0.212662702, -0.111803399);
1126 glNormal3f(-0.303530999, -0.934172359, 0.187592474);
1127 glVertex3f(-0.180901699, -0.131432778, 0.111803399);
1128 glVertex3f(-0.069098301, -0.212662702, -0.111803399);
1129 glVertex3f(0.069098301, -0.212662702, 0.111803399);
1131 glNormal3f(0.303530999, -0.934172359, -0.187592474);
1132 glVertex3f(0.069098301, -0.212662702, 0.111803399);
1133 glVertex3f(-0.069098301, -0.212662702, -0.111803399);
1134 glVertex3f(0.180901699, -0.131432778, -0.111803399);
1136 glNormal3f(0.607061998, 0.000000000, -0.794654473);
1137 glVertex3f(0.180901699, 0.131432778, -0.111803399);
1138 glVertex3f(0.180901699, -0.131432778, -0.111803399);
1139 glVertex3f(0.000000000, 0.000000000, -0.250000000);
1141 glNormal3f(0.187592474, 0.577350269, -0.794654473);
1142 glVertex3f(0.180901699, 0.131432778, -0.111803399);
1143 glVertex3f(0.000000000, 0.000000000, -0.250000000);
1144 glVertex3f(-0.069098301, 0.212662702, -0.111803399);
1146 glNormal3f(0.187592474, -0.577350269, -0.794654473);
1147 glVertex3f(0.180901699, -0.131432778, -0.111803399);
1148 glVertex3f(-0.069098301, -0.212662702, -0.111803399);
1149 glVertex3f(0.000000000, 0.000000000, -0.250000000);
1151 glNormal3f(-0.491123473, 0.356822090, -0.794654473);
1152 glVertex3f(-0.069098301, 0.212662702, -0.111803399);
1153 glVertex3f(0.000000000, 0.000000000, -0.250000000);
1154 glVertex3f(-0.223606798, 0.000000000, -0.111803399);
1156 glNormal3f(-0.491123473, -0.356822090, -0.794654473);
1157 glVertex3f(-0.223606798, 0.000000000, -0.111803399);
1158 glVertex3f(0.000000000, 0.000000000, -0.250000000);
1159 glVertex3f(-0.069098301, -0.212662702, -0.111803399);
1165 draw_maze (ModeInfo * mi)
1168 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
1169 GLfloat h = (GLfloat) MI_HEIGHT(mi) / MI_WIDTH(mi);
1171 if (!maze->glx_context)
1173 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(maze->glx_context));
1175 glMatrixMode(GL_PROJECTION);
1177 gluPerspective(90, 1/h, 0.05, 100);
1179 if (MI_WIDTH(mi) > 2560) /* Retina displays */
1188 glRotatef(maze->camera.inversion, 0, 0, 1);
1189 glRotatef(maze->camera.rotation, 0, 1, 0);
1190 glTranslatef(-1 * maze->camera.position.x, -0.5,
1191 -1 * maze->camera.position.z);
1193 refreshRemainingDistanceToTravel(mi);
1195 updateInverterRotation(maze);
1196 shiftAcidColor(maze);
1197 step(&maze->camera, maze);
1199 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1204 for (i = 0; i < numInverters; i++)
1205 drawInverter(maze, maze->inverterPosition[i]);
1207 # ifdef USE_FLOATING_IMAGES
1208 for (i = 0; i < numGl3dTexts; i++)
1209 drawPane(mi, maze->gl3dTextTexture, maze->gl3dTextPosition[i]);
1212 for (i = 0; i < numRats; i++) {
1213 step(&maze->rats[i], maze);
1214 drawRat(maze->rats[i].position, maze);
1217 drawPane(mi, maze->finishTexture, maze->finishPosition);
1218 drawPane(mi, maze->startTexture, maze->startPosition);
1220 if (shouldDrawOverlay || maze->button_down_p)
1223 if (mi->fps_p) do_fps(mi);
1225 glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi));
1229 shiftAcidColor(maze_configuration* maze)
1231 GLfloat x = 1 - fabs(fmod(maze->acidHue / 60.0, 2) - 1);
1233 if (0 <= maze->acidHue && maze->acidHue <= 60) {
1234 maze->acidColor.red = 1;
1235 maze->acidColor.green = x;
1236 maze->acidColor.blue = 0;
1237 } else if (60 <= maze->acidHue && maze->acidHue <= 120) {
1238 maze->acidColor.red = x;
1239 maze->acidColor.green = 1;
1240 maze->acidColor.blue = 0;
1241 } else if (120 <= maze->acidHue && maze->acidHue <= 180) {
1242 maze->acidColor.red = 0;
1243 maze->acidColor.green = 1;
1244 maze->acidColor.blue = x;
1245 } else if (180 <= maze->acidHue && maze->acidHue <= 240) {
1246 maze->acidColor.red = 0;
1247 maze->acidColor.green = x;
1248 maze->acidColor.blue = 1;
1249 } else if (240 <= maze->acidHue && maze->acidHue <= 300) {
1250 maze->acidColor.red = x;
1251 maze->acidColor.green = 0;
1252 maze->acidColor.blue = 1;
1254 maze->acidColor.red = 1;
1255 maze->acidColor.green = 0;
1256 maze->acidColor.blue = x;
1259 maze->acidHue += 75 * maze->camera.remainingDistanceToTravel;
1260 if (maze->acidHue >= 360) maze->acidHue -= 360;
1264 refreshRemainingDistanceToTravel(ModeInfo * mi)
1267 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
1268 maze->camera.remainingDistanceToTravel
1269 = speed * 1.6 * (MI_DELAY(mi) / 1000000.0);
1270 for (i = 0; i < numRats; i++)
1271 maze->rats[i].remainingDistanceToTravel =
1272 maze->camera.remainingDistanceToTravel;
1276 step(Rat* rat, maze_configuration* maze)
1278 GLfloat previousWallHeight = maze->wallHeight;
1280 if (!rat->isCamera && (maze->wallHeight < 1
1281 || (rat->position.x == 0 && rat->position.z == 0)))
1284 while (rat->remainingDistanceToTravel > 0) {
1285 switch(rat->state) {
1287 switch((int)rat->rotation) {
1289 walk(rat, 'z', -1, maze);
1292 walk(rat, 'x', 1, maze);
1295 walk(rat, 'z', 1, maze);
1298 walk(rat, 'x', -1, maze);
1301 rat->rotation = 90 * roundf(rat->rotation / 90.0);
1311 case TURNING_AROUND:
1312 turnAround(rat, maze);
1318 maze->wallHeight += 0.48 * rat->remainingDistanceToTravel;
1319 if (maze->wallHeight > 1.0) {
1320 maze->wallHeight = 1.0;
1321 rat->remainingDistanceToTravel =
1322 fabs(previousWallHeight - maze->wallHeight);
1323 changeState(&maze->camera, maze);
1325 rat->remainingDistanceToTravel = 0;
1328 if (maze->wallHeight == 0) {
1330 rat->remainingDistanceToTravel = 0;
1332 else if (maze->wallHeight < 0) {
1333 maze->wallHeight = 0;
1334 rat->remainingDistanceToTravel =
1335 fabs(previousWallHeight - maze->wallHeight);
1338 maze->wallHeight -= 0.48 * rat->remainingDistanceToTravel;
1339 rat->remainingDistanceToTravel = 0;
1349 walk(Rat* rat, char axis, int sign, maze_configuration* maze)
1351 GLfloat* component = (axis == 'x' ? &rat->position.x : &rat->position.z);
1352 GLfloat previousPosition = *component;
1353 int isMultipleOfOneHalf = 0;
1354 unsigned temp = (unsigned)((*component) * 2.0);
1356 if (((*component) * 2) == roundf((*component) * 2))
1357 isMultipleOfOneHalf = 1;
1358 *component += sign * rat->remainingDistanceToTravel;
1360 if (!isMultipleOfOneHalf && ((unsigned)((*component) * 2.0)) != temp) {
1361 *component = roundToNearestHalf(*component);
1362 rat->remainingDistanceToTravel -=
1363 fabs((*component) - previousPosition);
1364 changeState(rat, maze);
1366 rat->remainingDistanceToTravel = 0;
1371 turn(Rat* rat, maze_configuration* maze)
1373 Tuplef rotatingAround;
1374 GLfloat tangentVectorDirection, previousRotation
1377 if (rat->state == TURNING_LEFT) {
1378 tangentVectorDirection = rat->rotation * (M_PI / 180) + M_PI;
1379 rotatingAround.x = roundToNearestHalf(rat->position.x
1380 + 0.5 * cos(tangentVectorDirection));
1381 rotatingAround.z = roundToNearestHalf(rat->position.z
1382 + 0.5 * sin(tangentVectorDirection));
1384 rat->rotation -= DEF_ANGULAR_CONVERSION_FACTOR
1385 * rat->remainingDistanceToTravel;
1387 if (previousRotation > WEST && rat->rotation <= WEST) {
1388 rat->rotation = WEST;
1389 rat->remainingDistanceToTravel -= (M_PI / 180)
1390 * fabs(previousRotation - rat->rotation);
1391 } else if (previousRotation > SOUTH && rat->rotation <= SOUTH) {
1392 rat->rotation = SOUTH;
1393 rat->remainingDistanceToTravel -= (M_PI / 180)
1394 * fabs(previousRotation - rat->rotation);
1395 } else if (previousRotation > EAST && rat->rotation <= EAST) {
1396 rat->rotation = EAST;
1397 rat->remainingDistanceToTravel -= (M_PI / 180)
1398 * fabs(previousRotation - rat->rotation);
1399 } else if (previousRotation > NORTH && rat->rotation <= NORTH) {
1400 rat->rotation = NORTH;
1401 rat->remainingDistanceToTravel -= (M_PI / 180)
1402 * fabs(previousRotation - rat->rotation);
1404 rat->remainingDistanceToTravel = 0;
1406 tangentVectorDirection = rat->rotation * (M_PI / 180);
1409 tangentVectorDirection = rat->rotation * (M_PI / 180);
1410 rotatingAround.x = roundToNearestHalf(rat->position.x
1411 + 0.5 * cos(tangentVectorDirection));
1412 rotatingAround.z = roundToNearestHalf(rat->position.z
1413 + 0.5 * sin(tangentVectorDirection));
1415 rat->rotation += DEF_ANGULAR_CONVERSION_FACTOR
1416 * rat->remainingDistanceToTravel;
1418 if (rat->rotation >= 360) {
1419 rat->rotation = NORTH;
1420 rat->remainingDistanceToTravel -= (M_PI / 180)
1421 * fabs(previousRotation - 360);
1422 } else if (previousRotation < WEST && rat->rotation >= WEST) {
1423 rat->rotation = WEST;
1424 rat->remainingDistanceToTravel -= (M_PI / 180)
1425 * fabs(previousRotation - rat->rotation);
1426 } else if (previousRotation < SOUTH && rat->rotation >= SOUTH) {
1427 rat->rotation = SOUTH;
1428 rat->remainingDistanceToTravel -= (M_PI / 180)
1429 * fabs(previousRotation - rat->rotation);
1430 } else if (previousRotation < EAST && rat->rotation >= EAST) {
1431 rat->rotation = EAST;
1432 rat->remainingDistanceToTravel -= (M_PI / 180)
1433 * fabs(previousRotation - rat->rotation);
1435 rat->remainingDistanceToTravel = 0;
1437 tangentVectorDirection = rat->rotation * (M_PI / 180) + M_PI;
1440 rat->position.x = rotatingAround.x + 0.5 * cos(tangentVectorDirection);
1441 rat->position.z = rotatingAround.z + 0.5 * sin(tangentVectorDirection);
1443 if (rat->rotation < 0)
1444 rat->rotation += 360;
1446 if (rat->rotation == NORTH || rat->rotation == EAST
1447 || rat->rotation == SOUTH || rat->rotation == WEST) {
1448 rat->position.x = roundToNearestHalf(rat->position.x);
1449 rat->position.z = roundToNearestHalf(rat->position.z);
1450 changeState(rat, maze);
1455 turnAround(Rat* rat, maze_configuration* maze)
1457 GLfloat previousRotation = rat->rotation;
1459 rat->rotation -= 1.5 * DEF_ANGULAR_CONVERSION_FACTOR
1460 * rat->remainingDistanceToTravel;
1462 if (previousRotation > rat->desiredRotation
1463 && rat->rotation <= rat->desiredRotation) {
1464 rat->rotation = rat->desiredRotation;
1465 rat->remainingDistanceToTravel -= (M_PI / 180)
1466 * fabs(previousRotation - rat->rotation);
1467 changeState(rat, maze);
1470 rat->remainingDistanceToTravel = 0;
1471 if (rat->rotation < 0) rat->rotation += 360;
1476 invert(maze_configuration* maze)
1478 GLfloat previousInversion = maze->camera.inversion;
1479 int shouldChangeState = 0;
1480 unsigned cameraX = (unsigned)roundf(maze->camera.position.x * 2),
1481 cameraZ = (unsigned)roundf(maze->camera.position.z * 2);
1483 maze->camera.inversion += 1.5 * DEF_ANGULAR_CONVERSION_FACTOR
1484 * maze->camera.remainingDistanceToTravel;
1485 if (previousInversion < 180 && maze->camera.inversion >= 180) {
1486 maze->camera.inversion = 180;
1487 maze->camera.remainingDistanceToTravel -= (M_PI / 180)
1488 * fabs(previousInversion - maze->camera.inversion);
1489 shouldChangeState = 1;
1491 else if (maze->camera.inversion >= 360) {
1492 maze->camera.inversion = 0;
1493 maze->camera.remainingDistanceToTravel -= (M_PI / 180)
1494 * fabs(previousInversion - maze->camera.inversion);
1495 shouldChangeState = 1;
1497 maze->camera.remainingDistanceToTravel = 0;
1499 if (shouldChangeState) {
1500 switch ((int)maze->camera.rotation) {
1502 maze->mazeGrid[cameraZ - 1][cameraX] = CELL;
1505 maze->mazeGrid[cameraZ][cameraX + 1] = CELL;
1508 maze->mazeGrid[cameraZ + 1][cameraX] = CELL;
1511 maze->mazeGrid[cameraZ][cameraX - 1] = CELL;
1517 changeState(&maze->camera, maze);
1522 changeState(Rat* rat, maze_configuration* maze)
1524 unsigned char inFrontOfRat, toTheLeft, straightAhead, toTheRight;
1525 unsigned ratX = (unsigned)roundf(rat->position.x * 2),
1526 ratZ = (unsigned)roundf(rat->position.z * 2);
1528 switch ((int)rat->rotation) {
1530 inFrontOfRat = maze->mazeGrid[ratZ - 1][ratX];
1531 toTheLeft = maze->mazeGrid[ratZ - 1][ratX - 1];
1532 straightAhead = maze->mazeGrid[ratZ - 2][ratX];
1533 toTheRight = maze->mazeGrid[ratZ - 1][ratX + 1];
1536 inFrontOfRat = maze->mazeGrid[ratZ][ratX + 1];
1537 toTheLeft = maze->mazeGrid[ratZ - 1][ratX + 1];
1538 straightAhead = maze->mazeGrid[ratZ][ratX + 2];
1539 toTheRight = maze->mazeGrid[ratZ + 1][ratX + 1];
1542 inFrontOfRat = maze->mazeGrid[ratZ + 1][ratX];
1543 toTheLeft = maze->mazeGrid[ratZ + 1][ratX + 1];
1544 straightAhead = maze->mazeGrid[ratZ + 2][ratX];
1545 toTheRight = maze->mazeGrid[ratZ + 1][ratX - 1];
1548 inFrontOfRat = maze->mazeGrid[ratZ][ratX - 1];
1549 toTheLeft = maze->mazeGrid[ratZ + 1][ratX - 1];
1550 straightAhead = maze->mazeGrid[ratZ][ratX - 2];
1551 toTheRight = maze->mazeGrid[ratZ - 1][ratX - 1];
1554 inFrontOfRat = toTheLeft = straightAhead = toTheRight = CELL;
1558 if (rat->isCamera && inFrontOfRat == FINISH)
1559 rat->state = FINISHING;
1560 else if (rat->isCamera && inFrontOfRat >= INVERTER_TETRAHEDRON
1561 && inFrontOfRat <= INVERTER_ICOSAHEDRON)
1562 rat->state = INVERTING;
1563 else if (toTheLeft != WALL && toTheLeft != WALL_GL_REDBOOK)
1564 rat->state = TURNING_LEFT;
1565 else if (straightAhead != WALL && straightAhead != WALL_GL_REDBOOK)
1566 rat->state = WALKING;
1567 else if (toTheRight != WALL && toTheRight != WALL_GL_REDBOOK)
1568 rat->state = TURNING_RIGHT;
1570 rat->state = TURNING_AROUND;
1572 switch ((int)rat->rotation) {
1574 rat->desiredRotation = SOUTH;
1577 rat->desiredRotation = WEST;
1580 rat->desiredRotation = NORTH;
1583 rat->desiredRotation = EAST;
1592 updateInverterRotation(maze_configuration* maze)
1594 maze->inverterRotation += 45 * maze->camera.remainingDistanceToTravel;
1597 static void drawInverter(maze_configuration* maze, Tuple coordinates)
1599 unsigned char type = maze->mazeGrid[coordinates.row][coordinates.column];
1601 if (maze->wallHeight < 1 ||
1602 type < INVERTER_TETRAHEDRON || type > INVERTER_ICOSAHEDRON
1603 || (coordinates.row == 0 && coordinates.column == 0))
1606 glEnable(GL_LIGHTING);
1607 glEnable(GL_CULL_FACE);
1609 glMatrixMode(GL_MODELVIEW);
1612 glTranslatef(coordinates.column / 2.0, 0.25, coordinates.row / 2.0);
1613 glRotatef(0.618033989 * maze->inverterRotation, 0, 1, 0);
1614 glRotatef(maze->inverterRotation, 1, 0, 0);
1616 if (type >= countof(maze->dlists)) abort();
1617 glCallList(maze->dlists[type]);
1621 glDisable(GL_LIGHTING);
1622 glDisable(GL_CULL_FACE);
1626 drawWalls(ModeInfo * mi)
1629 Tuple startCoordinates, endCoordinates;
1631 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
1633 for (i = 0; i < maze->numRows; i++) {
1634 for (j = 0; j < maze->numColumns; j++) {
1635 if (maze->mazeGrid[i][j] == WALL
1636 || maze->mazeGrid[i][j] == WALL_GL_REDBOOK) {
1637 if (maze->mazeGrid[i][j] == WALL) {
1638 glBindTexture(GL_TEXTURE_2D, maze->wallTexture);
1639 if (dropAcid || dropAcidWalls)
1640 glColor3f(maze->acidColor.red, maze->acidColor.green,
1641 maze->acidColor.blue);
1642 # ifdef USE_FLOATING_IMAGES
1644 glBindTexture(GL_TEXTURE_2D, maze->glTextbookTexture);
1649 if (isOdd(i) && isEven(j)) {
1650 startCoordinates.row = i / 2;
1651 startCoordinates.column = j / 2;
1652 endCoordinates.row = i / 2 + 1;
1653 endCoordinates.column = j / 2;
1654 drawWall(startCoordinates, endCoordinates, maze);
1655 } else if (isEven(i) && isOdd(j)) {
1656 startCoordinates.row = i / 2;
1657 startCoordinates.column = j / 2;
1658 endCoordinates.row = i / 2;
1659 endCoordinates.column = j / 2 + 1;
1660 drawWall(startCoordinates, endCoordinates, maze);
1666 glBindTexture(GL_TEXTURE_2D, 0);
1671 drawWall(Tuple startCoordinates, Tuple endCoordinates, maze_configuration* maze)
1673 GLfloat wallHeight = maze->wallHeight;
1676 if (startCoordinates.row == endCoordinates.row) {
1678 glVertex3f(startCoordinates.column, 0, startCoordinates.row);
1680 glVertex3f(endCoordinates.column, 0, startCoordinates.row);
1682 glVertex3f(endCoordinates.column, wallHeight, endCoordinates.row);
1684 glVertex3f(startCoordinates.column, wallHeight, endCoordinates.row);
1687 glVertex3f(startCoordinates.column, 0, startCoordinates.row);
1689 glVertex3f(startCoordinates.column, 0, endCoordinates.row);
1691 glVertex3f(endCoordinates.column, wallHeight, endCoordinates.row);
1693 glVertex3f(endCoordinates.column, wallHeight, startCoordinates.row);
1699 drawCeiling(ModeInfo * mi)
1701 Tuple farRightCorner;
1702 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
1703 farRightCorner.row = maze->numRows / 2;
1704 farRightCorner.column = maze->numColumns / 2;
1705 glBindTexture(GL_TEXTURE_2D, maze->ceilingTexture);
1708 if (dropAcid || dropAcidCeiling)
1709 glColor3f(maze->acidColor.red, maze->acidColor.green,
1710 maze->acidColor.blue);
1712 glVertex3f(0, 1, 0);
1713 glTexCoord2f(farRightCorner.column, 0);
1714 glVertex3f(farRightCorner.column, 1, 0);
1715 glTexCoord2f(farRightCorner.column, farRightCorner.row);
1716 glVertex3f(farRightCorner.column, 1, farRightCorner.row);
1717 glTexCoord2f(0, farRightCorner.row);
1718 glVertex3f(0, 1, farRightCorner.row);
1722 glBindTexture(GL_TEXTURE_2D, 0);
1726 drawFloor(ModeInfo * mi)
1728 Tuple farRightCorner;
1729 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
1730 farRightCorner.row = maze->numRows / 2;
1731 farRightCorner.column = maze->numColumns / 2;
1732 glBindTexture(GL_TEXTURE_2D, maze->floorTexture);
1735 if (dropAcid || dropAcidFloor)
1736 glColor3f(maze->acidColor.red, maze->acidColor.green,
1737 maze->acidColor.blue);
1739 glVertex3f(0, 0, 0);
1740 glTexCoord2f(farRightCorner.column, 0);
1741 glVertex3f(farRightCorner.column, 0, 0);
1742 glTexCoord2f(farRightCorner.column, farRightCorner.row);
1743 glVertex3f(farRightCorner.column, 0, farRightCorner.row);
1744 glTexCoord2f(0, farRightCorner.row);
1745 glVertex3f(0, 0, farRightCorner.row);
1749 glBindTexture(GL_TEXTURE_2D, 0);
1753 drawPane(ModeInfo *mi, GLuint texture, Tuple position)
1755 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
1756 if (position.row == 0 && position.column == 0) return;
1759 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1761 glBindTexture(GL_TEXTURE_2D, texture);
1763 glMatrixMode(GL_MODELVIEW);
1765 glTranslatef(position.column / 2.0, 0, position.row / 2.0);
1766 glRotatef(-1 * maze->camera.rotation - 90, 0, 1, 0);
1768 if (MI_WIDTH(mi) < MI_HEIGHT(mi))
1770 /* Keep the Start button readable in phone portrait mode. */
1771 glScalef (0.5, 0.5, 0.5);
1772 glTranslatef (0, 0.5, 0);
1776 glColor4f(1, 1, 1, 0.9);
1778 glVertex3f(0, 0, 0.5);
1780 glVertex3f(0, 0, -0.5);
1782 glVertex3f(0, maze->wallHeight, -0.5);
1784 glVertex3f(0, maze->wallHeight, 0.5);
1789 glBindTexture(GL_TEXTURE_2D, 0);
1790 glDisable(GL_BLEND);
1794 drawRat(Tuplef position, maze_configuration* maze)
1796 if (position.x == 0 && position.z == 0) return;
1799 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1801 glBindTexture(GL_TEXTURE_2D, maze->ratTexture);
1803 glMatrixMode(GL_MODELVIEW);
1805 glTranslatef(position.x, 0, position.z);
1806 glRotatef(-1 * maze->camera.rotation - 90, 0, 1, 0);
1808 glScalef (0.25, 0.25, 0.25);
1811 glVertex3f(0, 0, 0.5);
1813 glVertex3f(0, 0, -0.5);
1815 glVertex3f(0, maze->wallHeight, -0.5);
1817 glVertex3f(0, maze->wallHeight, 0.5);
1821 glBindTexture(GL_TEXTURE_2D, 0);
1822 glDisable(GL_BLEND);
1826 static void drawOverlay(ModeInfo *mi)
1828 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
1830 GLfloat h = (GLfloat) MI_HEIGHT(mi) / MI_WIDTH(mi);
1832 glMatrixMode(GL_PROJECTION);
1835 glMatrixMode(GL_MODELVIEW);
1838 glOrtho(-1/h, 1/h, 1, -1, -1, 1);
1841 glColor4f(0, 0, 1, 0.75);
1842 glScalef(0.25, 0.25, 0.25);
1844 glCallList(maze->dlists[ARROW]);
1846 glRotatef(maze->camera.inversion, 0, 1, 0);
1847 glRotatef(maze->camera.rotation, 0, 0, -1);
1848 glTranslatef(-maze->camera.position.x, -maze->camera.position.z, 0);
1849 glColor4f(1, 1, 1, 0.75);
1852 for (i = 0; i < maze->numRows; i++) {
1853 for (j = 0; j < maze->numColumns; j++) {
1854 if (maze->mazeGrid[i][j] == WALL
1855 || maze->mazeGrid[i][j] == WALL_GL_REDBOOK) {
1856 if (isOdd(i) && isEven(j)) {
1857 glVertex2f(j / 2, i / 2);
1858 glVertex2f(j / 2, i / 2 + 1);
1859 } else if (isEven(i) && isOdd(j)) {
1860 glVertex2f(j / 2, i / 2);
1861 glVertex2f(j / 2 + 1, i / 2);
1868 glColor4f(1, 0, 0, 0.75);
1871 glTranslatef(maze->startPosition.column / 2.0,
1872 maze->startPosition.row / 2.0, 0);
1873 glCallList(maze->dlists[SQUARE]);
1876 glColor4f(1, 1, 0, 0.75);
1879 glTranslatef(maze->finishPosition.column / 2.0,
1880 maze->finishPosition.row / 2.0, 0);
1881 glCallList(maze->dlists[STAR]);
1884 glColor4f(1, 0.607843137, 0, 0.75);
1886 for (i = 0; i < numRats; i++) {
1887 if (maze->rats[i].position.x == 0 && maze->rats[i].position.z == 0)
1890 glTranslatef(maze->rats[i].position.x, maze->rats[i].position.z, 0);
1891 glRotatef(maze->rats[i].rotation, 0, 0, 1);
1892 glCallList(maze->dlists[ARROW]);
1896 glColor4f(1, 1, 1, 1);
1898 for (i = 0; i < numInverters; i++) {
1899 j = maze->mazeGrid[maze->inverterPosition[i].row]
1900 [maze->inverterPosition[i].column];
1901 if (j >= INVERTER_TETRAHEDRON && j <= INVERTER_ICOSAHEDRON) {
1903 glTranslatef(maze->inverterPosition[i].column / 2.0,
1904 maze->inverterPosition[i].row / 2.0, 0);
1905 glRotatef(1.5 * maze->inverterRotation, 0, 0, 1);
1906 glCallList(maze->dlists[TRIANGLE]);
1911 glDisable(GL_BLEND);
1914 glMatrixMode(GL_PROJECTION);
1919 free_maze (ModeInfo * mi)
1921 maze_configuration *maze = &mazes[MI_SCREEN(mi)];
1923 glDeleteTextures(1, &maze->wallTexture);
1924 glDeleteTextures(1, &maze->floorTexture);
1925 glDeleteTextures(1, &maze->ceilingTexture);
1926 glDeleteTextures(1, &maze->startTexture);
1927 glDeleteTextures(1, &maze->ratTexture);
1928 glDeleteTextures(1, &maze->finishTexture);
1929 # ifdef USE_FLOATING_IMAGES
1930 glDeleteTextures(1, &maze->glTextbookTexture);
1931 glDeleteTextures(1, &maze->gl3dTextTexture);
1933 # ifdef USE_FRACTAL_IMAGES
1934 glDeleteTextures(1, &maze->fractal1Texture);
1935 glDeleteTextures(1, &maze->fractal2Texture);
1936 glDeleteTextures(1, &maze->fractal3Texture);
1937 glDeleteTextures(1, &maze->fractal4Texture);
1940 glDeleteLists(maze->dlists[ARROW], 4);
1941 glDeleteLists(maze->dlists[INVERTER_TETRAHEDRON], 4);
1943 free(maze->mazeGrid);
1944 free(maze->wallList);
1945 free(maze->inverterPosition);
1946 free(maze->gl3dTextPosition);
1949 memset(maze, 0, sizeof(*maze));
1953 XSCREENSAVER_MODULE_2 ("Maze3D", maze3d, maze)