1f2be0abee1884f97c1e912d5b78c3f8adada387
[xscreensaver] / hacks / glx / rubik.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* rubik --- Shows an auto-solving Rubik's cube */
3
4 #if 0
5 static const char sccsid[] = "@(#)rubik.c       5.01 2001/03/01 xlockmore";
6 #endif
7
8 /*-
9  * Permission to use, copy, modify, and distribute this software and its
10  * documentation for any purpose and without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and that
12  * both that copyright notice and this permission notice appear in
13  * supporting documentation.
14  *
15  * This file is provided AS IS with no warranties of any kind.  The author
16  * shall have no liability with respect to the infringement of copyrights,
17  * trade secrets or any patents by this file or any part thereof.  In no
18  * event will the author be liable for any lost revenue or profits or
19  * other special, indirect and consequential damages.
20  *
21  * This mode shows an auto-solving rubik's cube "puzzle". If somebody
22  * intends to make a game or something based on this code, please let me
23  * know first, my e-mail address is provided in this comment. Marcelo.
24  *
25  * Thanks goes also to Brian Paul for making it possible and inexpensive
26  * to use OpenGL at home.
27  *
28  * Since I'm not a native English speaker, my apologies for any grammatical
29  * mistakes.
30  *
31  * My e-mail address is
32  * mfvianna@centroin.com.br
33  *
34  * Marcelo F. Vianna (Jul-31-1997)
35  *
36  * Revision History:
37  * 05-Apr-2002: Removed all gllist uses (fix some bug with nvidia driver)
38  * 01-Mar-2001: Added FPS stuff - Eric Lassauge <lassauge@mail.dotcom.fr>
39  * 01-Nov-2000: Allocation checks
40  * 27-Apr-1999: LxMxN stuff added.
41  * 26-Sep-1998: Added some more movement (the cube does not stay in the screen
42  *              center anymore. Also fixed the scale problem immediately after
43  *              shuffling when the puzzle is solved.
44  * 08-Aug-1997: Now has some internals from xrubik by David Bagley
45  *              This should make it easier to add features.
46  * 02-Aug-1997: Now behaves more like puzzle.c: first show the cube being
47  *              shuffled and then being solved. A mode specific option was
48  *              added:
49  *              "+/-hideshuffling" to provide the original behavior (in which
50  *              only the solution is shown).
51  *              The color labels corners are now rounded.
52  *              Optimized the cubit() routine using glLists.
53  * 01-Aug-1997: Shuffling now avoids movements that undoes the previous
54  *              movement and three consecutive identical moves (which is
55  *              pretty stupid).
56  *              improved the "cycles" option in replacement of David's hack,
57  *              now rp->anglestep is a GLfloat, so this option selects the
58  *              "exact" number of frames that a rotation (movement) takes to
59  *              complete.
60  * 30-Jul-1997: Initial release, there is no algorithm to solve the puzzle,
61  *              instead, it randomly shuffle the cube and then make the
62  *              movements in the reverse order.
63  *              The mode was written in 1 day (I got sick and had the day off).
64  *              There was not much to do since I could not leave home... :)
65  */
66
67 /*-
68  * Color labels mapping:
69  * =====================
70  *
71  *             +-----------+
72  *             |0-->       |
73  *             ||          |
74  *             |v  TOP(0)  |
75  *             |           |
76  *             |          8|
77  * +-----------+-----------+-----------+
78  * |0-->       |0-->       |0-->       |
79  * ||          ||          ||          |
80  * |v  LEFT(1) |v FRONT(2) |v RIGHT(3) |
81  * |           |           |           |
82  * |          8|          8|          8|
83  * +-----------+-----------+-----------+
84  *             |0-->       |
85  *             ||          |
86  *             |v BOTTOM(4)|
87  *             |           |
88  *             |          8|
89  *             +-----------+             +---+---+---+
90  *             |0-->       |             | 0 | 1 | 2 |
91  *             ||          |             |--xxxxx(N)-+
92  *             |v  BACK(5) |             | 3 | 4 | 5 |
93  *             |           |             +---+---+---+
94  *             |          8|             | 6 | 7 | 8 |
95  *             +-----------+             +---+---+---+
96  *
97  *  Map to 3d
98  *  FRONT  => X, Y
99  *  BACK   => X, Y
100  *  LEFT   => Z, Y
101  *  RIGHT  => Z, Y
102  *  TOP    => X, Z
103  *  BOTTOM => X, Z
104  */
105
106 #ifdef VMS
107 /*-
108  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
109  * otherwise caddr_t is not defined correctly
110  */
111 #include <X11/Intrinsic.h>
112 #endif
113
114 #ifdef STANDALONE
115 # define MODE_rubik
116 # define PROGCLASS      "Rubik"
117 # define HACK_INIT      init_rubik
118 # define HACK_DRAW      draw_rubik
119 # define HACK_RESHAPE reshape
120 # define rubik_opts     xlockmore_opts
121 # define DEFAULTS       "*delay: 40000 \n"              \
122                                         "*count: -30 \n"                \
123                                         "*showFPS: False \n"    \
124                                         "*cycles: 5 \n"                 \
125                                         "*size:  -6 \n"
126 # include "xlockmore.h"                         /* from the xscreensaver distribution */
127 #else /* !STANDALONE */
128 # include "xlock.h"                                     /* from the xlockmore distribution */
129 # include "vis.h"
130 #endif /* !STANDALONE */
131
132 #ifdef MODE_rubik
133
134 #define DEF_SIZEX     "0"
135 #define DEF_SIZEY     "0"
136 #define DEF_SIZEZ     "0"
137 #define DEF_HIDESHUFFLING     "False"
138
139 static int sizex;
140 static int sizey;
141 static int sizez;
142 static Bool hideshuffling;
143
144 static XrmOptionDescRec opts[] =
145 {
146         {(char *) "-sizex", (char *) ".rubik.sizex", XrmoptionSepArg, (caddr_t) NULL},
147         {(char *) "-sizey", (char *) ".rubik.sizey", XrmoptionSepArg, (caddr_t) NULL},
148         {(char *) "-sizez", (char *) ".rubik.sizez", XrmoptionSepArg, (caddr_t) NULL},
149         {(char *) "-hideshuffling", (char *) ".rubik.hideshuffling", XrmoptionNoArg, (caddr_t) "on"},
150         {(char *) "+hideshuffling", (char *) ".rubik.hideshuffling", XrmoptionNoArg, (caddr_t) "off"}
151 };
152
153 static argtype vars[] =
154 {
155         {&sizex, "sizex", "SizeX", DEF_SIZEX, t_Int},
156         {&sizey, "sizey", "SizeY", DEF_SIZEY, t_Int},
157         {&sizez, "sizez", "SizeZ", DEF_SIZEZ, t_Int},
158         {&hideshuffling, "hideshuffling", "Hideshuffling", DEF_HIDESHUFFLING, t_Bool}
159 };
160
161 static OptionStruct desc[] =
162 {
163         {(char *) "-sizex num", (char *) "number of cubies along x axis (overrides size)"},
164         {(char *) "-sizey num", (char *) "number of cubies along y axis (overrides size)"},
165         {(char *) "-sizez num", (char *) "number of cubies along z axis (overrides size)"},
166         {(char *) "-/+hideshuffling", (char *) "turn on/off hidden shuffle phase"}
167 };
168
169 ModeSpecOpt rubik_opts =
170 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
171
172 #ifdef USE_MODULES
173 ModStruct   rubik_description =
174 {"rubik", "init_rubik", "draw_rubik", "release_rubik",
175  "draw_rubik", "change_rubik", (char *) NULL, &rubik_opts,
176  10000, -30, 5, -6, 64, 1.0, "",
177  "Shows an auto-solving Rubik's Cube", 0, NULL};
178
179 #endif
180
181 #define VectMul(X1,Y1,Z1,X2,Y2,Z2) (Y1)*(Z2)-(Z1)*(Y2),(Z1)*(X2)-(X1)*(Z2),(X1)*(Y2)-(Y1)*(X2)
182 #define sqr(A)                     ((A)*(A))
183
184 #ifndef Pi
185 #define Pi                         M_PI
186 #endif
187
188
189 #define ACTION_SOLVE    1
190 #define ACTION_SHUFFLE  0
191
192 #define DELAY_AFTER_SHUFFLING  5
193 #define DELAY_AFTER_SOLVING   20
194
195 /*************************************************************************/
196
197 #define MINSIZE 2
198 #define MAXSIZEX (rp->sizex)
199 #define MAXSIZEY (rp->sizey)
200 #define MAXSIZEZ (rp->sizez)
201 #define AVSIZE ((rp->sizex+rp->sizey+rp->sizez)/3.0)     /* Use of this should be minimized */
202 #define MAXMAXSIZE (MAX(MAXSIZEX,MAX(MAXSIZEY,MAXSIZEZ)))
203 #define MAXSIZEXY (MAXSIZEX*MAXSIZEY)
204 #define MAXSIZEYZ (MAXSIZEY*MAXSIZEZ)
205 #define MAXSIZEZX (MAXSIZEZ*MAXSIZEX)
206 #define LASTX (MAXSIZEX-1)
207 #define LASTY (MAXSIZEY-1)
208 #define LASTZ (MAXSIZEZ-1)
209 /* These are not likely to change but... */
210 #define FIRSTX 0
211 #define FIRSTY 0
212 #define FIRSTZ 0
213
214 #define Scale4Window               (0.9/AVSIZE)
215 #define Scale4Iconic               (2.1/AVSIZE)
216
217 #define MAXORIENT 4             /* Number of orientations of a square */
218 #define MAXFACES 6              /* Number of faces */
219
220 /* Directions relative to the face of a cubie */
221 #define TOP 0
222 #define RIGHT 1
223 #define BOTTOM 2
224 #define LEFT 3
225 #define CW (MAXORIENT+1)
226 #define HALF (MAXORIENT+2)
227 #define CCW (2*MAXORIENT-1)
228
229 #define TOP_FACE 0
230 #define LEFT_FACE 1
231 #define FRONT_FACE 2
232 #define RIGHT_FACE 3
233 #define BOTTOM_FACE 4
234 #define BACK_FACE 5
235 #define NO_FACE (MAXFACES)
236 #define NO_ROTATION (2*MAXORIENT)
237 #define NO_DEPTH MAXMAXSIZE
238
239 #define REVX(a) (MAXSIZEX - a - 1)
240 #define REVY(a) (MAXSIZEY - a - 1)
241 #define REVZ(a) (MAXSIZEZ - a - 1)
242
243 #define CUBELEN 0.50
244 #define CUBEROUND (CUBELEN-0.05)
245 #define STICKERLONG (CUBEROUND-0.05)
246 #define STICKERSHORT (STICKERLONG-0.05)
247 #define STICKERDEPTH (CUBELEN+0.01)
248
249 #define ObjCubit        0
250 #define MaxObj          1
251 typedef struct _RubikLoc {
252         int         face;
253         int         rotation;   /* Not used yet */
254 } RubikLoc;
255
256 typedef struct _RubikRowNext {
257         int         face, direction, sideFace;
258 } RubikRowNext;
259
260 typedef struct _RubikMove {
261         int         face, direction;
262         int         position;
263 } RubikMove;
264
265 typedef struct _RubikSlice {
266         int         face, rotation;
267         int         depth;
268 } RubikSlice;
269
270 /*-
271  * Pick a face and a direction on face the next face and orientation
272  * is then known.
273  */
274 static RubikLoc slideNextRow[MAXFACES][MAXORIENT] =
275 {
276         {
277                 {5, TOP},
278                 {3, RIGHT},
279                 {2, TOP},
280                 {1, LEFT}},
281         {
282                 {0, RIGHT},
283                 {2, TOP},
284                 {4, LEFT},
285                 {5, BOTTOM}},
286         {
287                 {0, TOP},
288                 {3, TOP},
289                 {4, TOP},
290                 {1, TOP}},
291         {
292                 {0, LEFT},
293                 {5, BOTTOM},
294                 {4, RIGHT},
295                 {2, TOP}},
296         {
297                 {2, TOP},
298                 {3, LEFT},
299                 {5, TOP},
300                 {1, RIGHT}},
301         {
302                 {4, TOP},
303                 {3, BOTTOM},
304                 {0, TOP},
305                 {1, BOTTOM}}
306 };
307
308 /*-
309  * Examine cubie 0 on each face, its 4 movements (well only 2 since the
310  * other 2 will be opposites) and translate it into slice movements).
311  * CW = DEEP Depth CCW == SHALLOW Depth with reference to faces 0, 1, and 2
312  */
313 static RubikLoc rotateSlice[MAXFACES][MAXORIENT / 2] =
314 {
315         {
316                 {1, CCW},
317                 {2, CW},
318         },
319         {
320                 {2, CW},
321                 {0, CCW},
322         },
323         {
324                 {1, CCW},
325                 {0, CCW},
326         },
327         {
328                 {2, CCW},
329                 {0, CCW},
330         },
331         {
332                 {1, CCW},
333                 {2, CCW},
334         },
335         {
336                 {1, CCW},
337                 {0, CW},
338         }
339 };
340
341 /*-
342  * Rotate face clockwise by a number of orients, then the top of the
343  * face then points to this face
344  */
345 static int  rowToRotate[MAXFACES][MAXORIENT] =
346 {
347         {3, 2, 1, 5},
348         {2, 4, 5, 0},
349         {3, 4, 1, 0},
350         {5, 4, 2, 0},
351         {3, 5, 1, 2},
352         {3, 0, 1, 4}
353 };
354
355 /*
356  * This translates a clockwise move to something more manageable
357  */
358 static RubikRowNext rotateToRow[MAXFACES] =     /*CW to min face */
359 {
360         {1, LEFT, TOP},
361         {0, BOTTOM, RIGHT},
362         {0, RIGHT, BOTTOM},
363         {0, TOP, LEFT},
364         {1, RIGHT, BOTTOM},
365         {0, LEFT, TOP}
366 };
367
368 typedef struct {
369         GLint       WindH, WindW;
370         GLfloat     step;
371         RubikMove  *moves;
372         int         storedmoves;
373         int         degreeTurn;
374         int         shufflingmoves;
375         int         sizex, sizey, sizez;
376         float       avsize, avsizeSq;
377         int         action;
378         int         done;
379         GLfloat     anglestep;
380         RubikLoc   *cubeLoc[MAXFACES];
381         RubikLoc   *rowLoc[MAXORIENT];
382         RubikMove   movement;
383         GLfloat     rotatestep;
384         GLfloat     PX, PY, VX, VY;
385         GLXContext *glx_context;
386 } rubikstruct;
387
388 static float front_shininess[] =
389 {60.0};
390 static float front_specular[] =
391 {0.7, 0.7, 0.7, 1.0};
392 static float ambient[] =
393 {0.0, 0.0, 0.0, 1.0};
394 static float diffuse[] =
395 {1.0, 1.0, 1.0, 1.0};
396 static float position0[] =
397 {1.0, 1.0, 1.0, 0.0};
398 static float position1[] =
399 {-1.0, -1.0, 1.0, 0.0};
400 static float lmodel_ambient[] =
401 {0.5, 0.5, 0.5, 1.0};
402 static float lmodel_twoside[] =
403 {GL_TRUE};
404
405 static float MaterialRed[] =
406 {0.5, 0.0, 0.0, 1.0};
407 static float MaterialGreen[] =
408 {0.0, 0.5, 0.0, 1.0};
409 static float MaterialBlue[] =
410 {0.0, 0.0, 0.5, 1.0};
411 static float MaterialYellow[] =
412 {0.7, 0.7, 0.0, 1.0};
413 static float MaterialOrange[] =
414 {0.9, 0.45, 0.36, 1.0};
415
416 #if 0
417 static float MaterialMagenta[] =
418 {0.7, 0.0, 0.7, 1.0};
419 static float MaterialCyan[] =
420 {0.0, 0.7, 0.7, 1.0};
421
422 #endif
423 static float MaterialWhite[] =
424 {0.8, 0.8, 0.8, 1.0};
425 static float MaterialGray[] =
426 {0.2, 0.2, 0.2, 1.0};
427 static float MaterialGray3[] =
428 {0.3, 0.3, 0.3, 1.0};
429 static float MaterialGray4[] =
430 {0.4, 0.4, 0.4, 1.0};
431 static float MaterialGray5[] =
432 {0.5, 0.5, 0.5, 1.0};
433 static float MaterialGray6[] =
434 {0.6, 0.6, 0.6, 1.0};
435 static float MaterialGray7[] =
436 {0.7, 0.7, 0.7, 1.0};
437
438 static rubikstruct *rubik = (rubikstruct *) NULL;
439
440
441 static void
442 pickcolor(int C, int mono)
443 {
444         switch (C) {
445                 case TOP_FACE:
446                         if (mono)
447                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray3);
448                         else
449                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
450                         break;
451                 case LEFT_FACE:
452                         if (mono)
453                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray6);
454                         else
455                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
456                         break;
457                 case FRONT_FACE:
458                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
459                         break;
460                 case RIGHT_FACE:
461                         if (mono)
462                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray4);
463                         else
464                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGreen);
465                         break;
466                 case BOTTOM_FACE:
467                         if (mono)
468                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray7);
469                         else
470                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialOrange);
471                         break;
472                 case BACK_FACE:
473                         if (mono)
474                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
475                         else
476                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
477                         break;
478 #if 0
479                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialCyan);
480                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialMagenta);
481 #endif
482         }
483 }
484
485 static void
486 faceSizes(rubikstruct * rp, int face, int * sizeOfRow, int * sizeOfColumn)
487 {
488         switch (face) {
489                 case 0: /* TOP */
490                 case 4: /* BOTTOM */
491                         *sizeOfRow = MAXSIZEX;
492                         *sizeOfColumn = MAXSIZEZ;
493                         break;
494                 case 1: /* LEFT */
495                 case 3: /* RIGHT */
496                         *sizeOfRow = MAXSIZEZ;
497                         *sizeOfColumn = MAXSIZEY;
498                         break;
499                 case 2: /* FRONT */
500                 case 5: /* BACK */
501                         *sizeOfRow = MAXSIZEX;
502                         *sizeOfColumn = MAXSIZEY;
503                         break;
504         }
505 }
506
507 static Bool
508 checkFaceSquare(rubikstruct * rp, int face)
509 {
510         int sizeOfRow, sizeOfColumn;
511
512         faceSizes(rp, face, &sizeOfRow, &sizeOfColumn);
513         return (sizeOfRow == sizeOfColumn);
514         /* Cubes can be made square with a 4x2 face where 90 degree turns
515          * should be permitted but that is kind of complicated for me.
516          * This can be done in 2 ways where the side of the cubies are
517          * the same size and one where one side (the side with half the
518          * number of cubies) is twice the size of the other.  The first is
519          * complicated because faces of cubies can go under other faces.
520          * The second way is similar to "banded cubes" where scotch tape
521          * restricts the moves of some cubes.  Here you have to keep track
522          * of the restrictions and show banded cubies graphically as one
523          * cube.
524          */
525 }
526
527 static int
528 sizeFace(rubikstruct * rp, int face)
529 {
530         int sizeOfRow, sizeOfColumn;
531
532         faceSizes(rp, face, &sizeOfRow, &sizeOfColumn);
533         return (sizeOfRow * sizeOfColumn);
534 }
535
536 static int
537 sizeRow(rubikstruct * rp, int face)
538 {
539         int sizeOfRow, sizeOfColumn;  /* sizeOfColumn not used */
540
541         faceSizes(rp, face, &sizeOfRow, &sizeOfColumn);
542         return sizeOfRow;
543 }
544
545 static Bool
546 draw_stickerless_cubit(rubikstruct *rp)
547 {
548         glBegin(GL_QUADS);
549         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
550         /* Put sticker here */
551         glNormal3f(0.00, 0.00, 1.00);
552         glVertex3f(-CUBEROUND, -CUBEROUND, CUBELEN);
553         glVertex3f(CUBEROUND, -CUBEROUND, CUBELEN);
554         glVertex3f(CUBEROUND, CUBEROUND, CUBELEN);
555         glVertex3f(-CUBEROUND, CUBEROUND, CUBELEN);
556         glNormal3f(0.00, 0.00, -1.00);
557         glVertex3f(-CUBEROUND, CUBEROUND, -CUBELEN);
558         glVertex3f(CUBEROUND, CUBEROUND, -CUBELEN);
559         glVertex3f(CUBEROUND, -CUBEROUND, -CUBELEN);
560         glVertex3f(-CUBEROUND, -CUBEROUND, -CUBELEN);
561         glNormal3f(-1.00, 0.00, 0.00);
562         glVertex3f(-CUBELEN, -CUBEROUND, CUBEROUND);
563         glVertex3f(-CUBELEN, CUBEROUND, CUBEROUND);
564         glVertex3f(-CUBELEN, CUBEROUND, -CUBEROUND);
565         glVertex3f(-CUBELEN, -CUBEROUND, -CUBEROUND);
566         glNormal3f(1.00, 0.00, 0.00);
567         glVertex3f(CUBELEN, -CUBEROUND, -CUBEROUND);
568         glVertex3f(CUBELEN, CUBEROUND, -CUBEROUND);
569         glVertex3f(CUBELEN, CUBEROUND, CUBEROUND);
570         glVertex3f(CUBELEN, -CUBEROUND, CUBEROUND);
571         glNormal3f(0.00, -1.00, 0.00);
572         glVertex3f(CUBEROUND, -CUBELEN, -CUBEROUND);
573         glVertex3f(CUBEROUND, -CUBELEN, CUBEROUND);
574         glVertex3f(-CUBEROUND, -CUBELEN, CUBEROUND);
575         glVertex3f(-CUBEROUND, -CUBELEN, -CUBEROUND);
576         glNormal3f(0.00, 1.00, 0.00);
577         glVertex3f(-CUBEROUND, CUBELEN, -CUBEROUND);
578         glVertex3f(-CUBEROUND, CUBELEN, CUBEROUND);
579         glVertex3f(CUBEROUND, CUBELEN, CUBEROUND);
580         glVertex3f(CUBEROUND, CUBELEN, -CUBEROUND);
581
582         /* Edges of cubit */
583         glNormal3f(-1.00, -1.00, 0.00);
584         glVertex3f(-CUBEROUND, -CUBELEN, -CUBEROUND);
585         glVertex3f(-CUBEROUND, -CUBELEN, CUBEROUND);
586         glVertex3f(-CUBELEN, -CUBEROUND, CUBEROUND);
587         glVertex3f(-CUBELEN, -CUBEROUND, -CUBEROUND);
588         glNormal3f(1.00, 1.00, 0.00);
589         glVertex3f(CUBEROUND, CUBELEN, -CUBEROUND);
590         glVertex3f(CUBEROUND, CUBELEN, CUBEROUND);
591         glVertex3f(CUBELEN, CUBEROUND, CUBEROUND);
592         glVertex3f(CUBELEN, CUBEROUND, -CUBEROUND);
593         glNormal3f(-1.00, 1.00, 0.00);
594         glVertex3f(-CUBELEN, CUBEROUND, -CUBEROUND);
595         glVertex3f(-CUBELEN, CUBEROUND, CUBEROUND);
596         glVertex3f(-CUBEROUND, CUBELEN, CUBEROUND);
597         glVertex3f(-CUBEROUND, CUBELEN, -CUBEROUND);
598         glNormal3f(1.00, -1.00, 0.00);
599         glVertex3f(CUBELEN, -CUBEROUND, -CUBEROUND);
600         glVertex3f(CUBELEN, -CUBEROUND, CUBEROUND);
601         glVertex3f(CUBEROUND, -CUBELEN, CUBEROUND);
602         glVertex3f(CUBEROUND, -CUBELEN, -CUBEROUND);
603         glNormal3f(0.00, -1.00, -1.00);
604         glVertex3f(-CUBEROUND, -CUBEROUND, -CUBELEN);
605         glVertex3f(CUBEROUND, -CUBEROUND, -CUBELEN);
606         glVertex3f(CUBEROUND, -CUBELEN, -CUBEROUND);
607         glVertex3f(-CUBEROUND, -CUBELEN, -CUBEROUND);
608         glNormal3f(0.00, 1.00, 1.00);
609         glVertex3f(-CUBEROUND, CUBEROUND, CUBELEN);
610         glVertex3f(CUBEROUND, CUBEROUND, CUBELEN);
611         glVertex3f(CUBEROUND, CUBELEN, CUBEROUND);
612         glVertex3f(-CUBEROUND, CUBELEN, CUBEROUND);
613         glNormal3f(0.00, -1.00, 1.00);
614         glVertex3f(-CUBEROUND, -CUBELEN, CUBEROUND);
615         glVertex3f(CUBEROUND, -CUBELEN, CUBEROUND);
616         glVertex3f(CUBEROUND, -CUBEROUND, CUBELEN);
617         glVertex3f(-CUBEROUND, -CUBEROUND, CUBELEN);
618         glNormal3f(0.00, 1.00, -1.00);
619         glVertex3f(-CUBEROUND, CUBELEN, -CUBEROUND);
620         glVertex3f(CUBEROUND, CUBELEN, -CUBEROUND);
621         glVertex3f(CUBEROUND, CUBEROUND, -CUBELEN);
622         glVertex3f(-CUBEROUND, CUBEROUND, -CUBELEN);
623         glNormal3f(-1.00, 0.00, -1.00);
624         glVertex3f(-CUBELEN, -CUBEROUND, -CUBEROUND);
625         glVertex3f(-CUBELEN, CUBEROUND, -CUBEROUND);
626         glVertex3f(-CUBEROUND, CUBEROUND, -CUBELEN);
627         glVertex3f(-CUBEROUND, -CUBEROUND, -CUBELEN);
628         glNormal3f(1.00, 0.00, 1.00);
629         glVertex3f(CUBELEN, -CUBEROUND, CUBEROUND);
630         glVertex3f(CUBELEN, CUBEROUND, CUBEROUND);
631         glVertex3f(CUBEROUND, CUBEROUND, CUBELEN);
632         glVertex3f(CUBEROUND, -CUBEROUND, CUBELEN);
633         glNormal3f(1.00, 0.00, -1.00);
634         glVertex3f(CUBEROUND, -CUBEROUND, -CUBELEN);
635         glVertex3f(CUBEROUND, CUBEROUND, -CUBELEN);
636         glVertex3f(CUBELEN, CUBEROUND, -CUBEROUND);
637         glVertex3f(CUBELEN, -CUBEROUND, -CUBEROUND);
638         glNormal3f(-1.00, 0.00, 1.00);
639         glVertex3f(-CUBEROUND, -CUBEROUND, CUBELEN);
640         glVertex3f(-CUBEROUND, CUBEROUND, CUBELEN);
641         glVertex3f(-CUBELEN, CUBEROUND, CUBEROUND);
642         glVertex3f(-CUBELEN, -CUBEROUND, CUBEROUND);
643         glEnd();
644         glBegin(GL_TRIANGLES);
645         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
646         /* Corners of cubit */
647         glNormal3f(1.00, 1.00, 1.00);
648         glVertex3f(CUBEROUND, CUBEROUND, CUBELEN);
649         glVertex3f(CUBELEN, CUBEROUND, CUBEROUND);
650         glVertex3f(CUBEROUND, CUBELEN, CUBEROUND);
651         glNormal3f(-1.00, -1.00, -1.00);
652         glVertex3f(-CUBEROUND, -CUBELEN, -CUBEROUND);
653         glVertex3f(-CUBELEN, -CUBEROUND, -CUBEROUND);
654         glVertex3f(-CUBEROUND, -CUBEROUND, -CUBELEN);
655         glNormal3f(-1.00, 1.00, 1.00);
656         glVertex3f(-CUBEROUND, CUBEROUND, CUBELEN);
657         glVertex3f(-CUBEROUND, CUBELEN, CUBEROUND);
658         glVertex3f(-CUBELEN, CUBEROUND, CUBEROUND);
659         glNormal3f(1.00, -1.00, -1.00);
660         glVertex3f(CUBELEN, -CUBEROUND, -CUBEROUND);
661         glVertex3f(CUBEROUND, -CUBELEN, -CUBEROUND);
662         glVertex3f(CUBEROUND, -CUBEROUND, -CUBELEN);
663         glNormal3f(1.00, -1.00, 1.00);
664         glVertex3f(CUBEROUND, -CUBEROUND, CUBELEN);
665         glVertex3f(CUBEROUND, -CUBELEN, CUBEROUND);
666         glVertex3f(CUBELEN, -CUBEROUND, CUBEROUND);
667         glNormal3f(-1.00, 1.00, -1.00);
668         glVertex3f(-CUBELEN, CUBEROUND, -CUBEROUND);
669         glVertex3f(-CUBEROUND, CUBELEN, -CUBEROUND);
670         glVertex3f(-CUBEROUND, CUBEROUND, -CUBELEN);
671         glNormal3f(-1.00, -1.00, 1.00);
672         glVertex3f(-CUBEROUND, -CUBEROUND, CUBELEN);
673         glVertex3f(-CUBELEN, -CUBEROUND, CUBEROUND);
674         glVertex3f(-CUBEROUND, -CUBELEN, CUBEROUND);
675         glNormal3f(1.00, 1.00, -1.00);
676         glVertex3f(CUBELEN, CUBEROUND, -CUBEROUND);
677         glVertex3f(CUBEROUND, CUBEROUND, -CUBELEN);
678         glVertex3f(CUBEROUND, CUBELEN, -CUBEROUND);
679         glEnd();
680         return True;
681 }
682
683 static Bool
684 draw_cubit(ModeInfo * mi,
685            int back, int front, int left, int right, int bottom, int top)
686 {
687         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
688         int         mono = MI_IS_MONO(mi);
689
690         if (!draw_stickerless_cubit(rp))
691                 return False;
692         if (back != NO_FACE) {
693                 glBegin(GL_POLYGON);
694                 pickcolor(back, mono);
695                 glNormal3f(0.00, 0.00, -1.00);
696                 glVertex3f(-STICKERSHORT, STICKERLONG, -STICKERDEPTH);
697                 glVertex3f(STICKERSHORT, STICKERLONG, -STICKERDEPTH);
698                 glVertex3f(STICKERLONG, STICKERSHORT, -STICKERDEPTH);
699                 glVertex3f(STICKERLONG, -STICKERSHORT, -STICKERDEPTH);
700                 glVertex3f(STICKERSHORT, -STICKERLONG, -STICKERDEPTH);
701                 glVertex3f(-STICKERSHORT, -STICKERLONG, -STICKERDEPTH);
702                 glVertex3f(-STICKERLONG, -STICKERSHORT, -STICKERDEPTH);
703                 glVertex3f(-STICKERLONG, STICKERSHORT, -STICKERDEPTH);
704                 glEnd();
705         }
706         if (front != NO_FACE) {
707                 glBegin(GL_POLYGON);
708                 pickcolor(front, mono);
709                 glNormal3f(0.00, 0.00, 1.00);
710                 glVertex3f(-STICKERSHORT, -STICKERLONG, STICKERDEPTH);
711                 glVertex3f(STICKERSHORT, -STICKERLONG, STICKERDEPTH);
712                 glVertex3f(STICKERLONG, -STICKERSHORT, STICKERDEPTH);
713                 glVertex3f(STICKERLONG, STICKERSHORT, STICKERDEPTH);
714                 glVertex3f(STICKERSHORT, STICKERLONG, STICKERDEPTH);
715                 glVertex3f(-STICKERSHORT, STICKERLONG, STICKERDEPTH);
716                 glVertex3f(-STICKERLONG, STICKERSHORT, STICKERDEPTH);
717                 glVertex3f(-STICKERLONG, -STICKERSHORT, STICKERDEPTH);
718                 glEnd();
719         }
720         if (left != NO_FACE) {
721                 glBegin(GL_POLYGON);
722                 pickcolor(left, mono);
723                 glNormal3f(-1.00, 0.00, 0.00);
724                 glVertex3f(-STICKERDEPTH, -STICKERSHORT, STICKERLONG);
725                 glVertex3f(-STICKERDEPTH, STICKERSHORT, STICKERLONG);
726                 glVertex3f(-STICKERDEPTH, STICKERLONG, STICKERSHORT);
727                 glVertex3f(-STICKERDEPTH, STICKERLONG, -STICKERSHORT);
728                 glVertex3f(-STICKERDEPTH, STICKERSHORT, -STICKERLONG);
729                 glVertex3f(-STICKERDEPTH, -STICKERSHORT, -STICKERLONG);
730                 glVertex3f(-STICKERDEPTH, -STICKERLONG, -STICKERSHORT);
731                 glVertex3f(-STICKERDEPTH, -STICKERLONG, STICKERSHORT);
732                 glEnd();
733         }
734         if (right != NO_FACE) {
735                 glBegin(GL_POLYGON);
736                 pickcolor(right, mono);
737                 glNormal3f(1.00, 0.00, 0.00);
738                 glVertex3f(STICKERDEPTH, -STICKERSHORT, -STICKERLONG);
739                 glVertex3f(STICKERDEPTH, STICKERSHORT, -STICKERLONG);
740                 glVertex3f(STICKERDEPTH, STICKERLONG, -STICKERSHORT);
741                 glVertex3f(STICKERDEPTH, STICKERLONG, STICKERSHORT);
742                 glVertex3f(STICKERDEPTH, STICKERSHORT, STICKERLONG);
743                 glVertex3f(STICKERDEPTH, -STICKERSHORT, STICKERLONG);
744                 glVertex3f(STICKERDEPTH, -STICKERLONG, STICKERSHORT);
745                 glVertex3f(STICKERDEPTH, -STICKERLONG, -STICKERSHORT);
746                 glEnd();
747         }
748         if (bottom != NO_FACE) {
749                 glBegin(GL_POLYGON);
750                 pickcolor(bottom, mono);
751                 glNormal3f(0.00, -1.00, 0.00);
752                 glVertex3f(STICKERLONG, -STICKERDEPTH, -STICKERSHORT);
753                 glVertex3f(STICKERLONG, -STICKERDEPTH, STICKERSHORT);
754                 glVertex3f(STICKERSHORT, -STICKERDEPTH, STICKERLONG);
755                 glVertex3f(-STICKERSHORT, -STICKERDEPTH, STICKERLONG);
756                 glVertex3f(-STICKERLONG, -STICKERDEPTH, STICKERSHORT);
757                 glVertex3f(-STICKERLONG, -STICKERDEPTH, -STICKERSHORT);
758                 glVertex3f(-STICKERSHORT, -STICKERDEPTH, -STICKERLONG);
759                 glVertex3f(STICKERSHORT, -STICKERDEPTH, -STICKERLONG);
760                 glEnd();
761         }
762         if (top != NO_FACE) {
763                 glBegin(GL_POLYGON);
764                 pickcolor(top, mono);
765                 glNormal3f(0.00, 1.00, 0.00);
766                 glVertex3f(-STICKERLONG, STICKERDEPTH, -STICKERSHORT);
767                 glVertex3f(-STICKERLONG, STICKERDEPTH, STICKERSHORT);
768                 glVertex3f(-STICKERSHORT, STICKERDEPTH, STICKERLONG);
769                 glVertex3f(STICKERSHORT, STICKERDEPTH, STICKERLONG);
770                 glVertex3f(STICKERLONG, STICKERDEPTH, STICKERSHORT);
771                 glVertex3f(STICKERLONG, STICKERDEPTH, -STICKERSHORT);
772                 glVertex3f(STICKERSHORT, STICKERDEPTH, -STICKERLONG);
773                 glVertex3f(-STICKERSHORT, STICKERDEPTH, -STICKERLONG);
774                 glEnd();
775         }
776         return True;
777 }
778
779 /* Convert move to weird general notation */
780 static void
781 convertMove(rubikstruct * rp, RubikMove move, RubikSlice * slice)
782 {
783         RubikLoc    plane;
784         int         sizeOfRow, sizeOfColumn;
785
786         plane = rotateSlice[(int) move.face][move.direction % 2];
787         (*slice).face = plane.face;
788         (*slice).rotation = plane.rotation;
789
790         faceSizes(rp, move.face, &sizeOfRow, &sizeOfColumn);
791         if (plane.face == 1 || /* VERTICAL */
792             (plane.face == 2 && (move.face == 1 || move.face == 3))) {
793                 if ((*slice).rotation == CW)
794                         (*slice).depth = sizeOfRow - 1 - move.position %
795                                 sizeOfRow;
796                 else
797                         (*slice).depth = move.position % sizeOfRow;
798         } else { /* (plane.face == 0 ||  *//* HORIZONTAL *//*
799                 (plane.face == 2 && (move.face == 0 || move.face == 4))) */
800                 if ((*slice).rotation == CW)
801                         (*slice).depth = sizeOfColumn - 1 - move.position /
802                                 sizeOfRow;
803                 else
804                         (*slice).depth = move.position / sizeOfRow;
805         }
806         /* If (*slice).depth = 0 then face 0, face 1, or face 2 moves */
807         if (move.direction / 2)
808                 (*slice).rotation = ((*slice).rotation == CW) ? CCW : CW;
809 }
810
811 /* Assume the size is at least 2, or its just not challenging... */
812 static Bool
813 draw_cube(ModeInfo * mi)
814 {
815 #define S1 1
816 #define SX ((GLint)S1*(MAXSIZEX-1))
817 #define SY ((GLint)S1*(MAXSIZEY-1))
818 #define SZ ((GLint)S1*(MAXSIZEZ-1))
819 #define HALFX (((GLfloat)MAXSIZEX-1.0)/2.0)
820 #define HALFY (((GLfloat)MAXSIZEY-1.0)/2.0)
821 #define HALFZ (((GLfloat)MAXSIZEZ-1.0)/2.0)
822 #define MIDX(a) (((GLfloat)(2*a-MAXSIZEX+1))/2.0)
823 #define MIDY(a) (((GLfloat)(2*a-MAXSIZEY+1))/2.0)
824 #define MIDZ(a) (((GLfloat)(2*a-MAXSIZEZ+1))/2.0)
825 #define DRAW_CUBIT(mi,b,f,l,r,bm,t) if (!draw_cubit(mi,b,f,l,r,bm,t)) return False
826         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
827         RubikSlice  slice;
828         GLfloat     rotatestep;
829         int         i, j, k;
830
831         if (rp->movement.face == NO_FACE) {
832                 slice.face = NO_FACE;
833                 slice.rotation = NO_ROTATION;
834                 slice.depth = NO_DEPTH;
835         } else {
836                 convertMove(rp, rp->movement, &slice);
837         }
838         rotatestep = (slice.rotation == CCW) ? rp->rotatestep : -rp->rotatestep;
839
840
841 /*-
842  * The glRotatef() routine transforms the coordinate system for every future
843  * vertex specification (this is not so simple, but by now comprehending this
844  * is sufficient). So if you want to rotate the inner slice, you can draw
845  * one slice, rotate the anglestep for the centerslice, draw the inner slice,
846  * rotate reversely and draw the other slice.
847  * There is a sequence for drawing cubies for each axis being moved...
848  */
849         switch (slice.face) {
850                 case NO_FACE:
851                 case TOP_FACE:  /* BOTTOM_FACE too */
852                         glPushMatrix();
853                         if (slice.depth == MAXSIZEY - 1)
854                                 glRotatef(rotatestep, 0, HALFY, 0);
855
856                         glTranslatef(-HALFX, -HALFY, -HALFZ);
857                         DRAW_CUBIT(mi,
858                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
859                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
860                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
861                         for (k = 1; k < MAXSIZEZ - 1; k++) {
862                                 glTranslatef(0, 0, S1);
863                                 DRAW_CUBIT(mi,
864                                            NO_FACE, NO_FACE,
865                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
866                                            rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
867                         }
868                         glTranslatef(0, 0, S1);
869                         DRAW_CUBIT(mi,
870                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
871                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
872                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
873                         for (i = 1; i < MAXSIZEX - 1; i++) {
874                                 glTranslatef(S1, 0, -SZ);
875                                 DRAW_CUBIT(mi,
876                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
877                                            NO_FACE, NO_FACE,
878                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
879                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
880                                         glTranslatef(0, 0, S1);
881                                         DRAW_CUBIT(mi,
882                                                    NO_FACE, NO_FACE,
883                                                    NO_FACE, NO_FACE,
884                                                    rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
885                                 }
886                                 glTranslatef(0, 0, S1);
887                                 DRAW_CUBIT(mi,
888                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
889                                            NO_FACE, NO_FACE,
890                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
891                         }
892                         glTranslatef(S1, 0, -SZ);
893                         DRAW_CUBIT(mi,
894                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
895                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
896                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
897                         for (k = 1; k < MAXSIZEZ - 1; k++) {
898                                 glTranslatef(0, 0, S1);
899                                 DRAW_CUBIT(mi,
900                                            NO_FACE, NO_FACE,
901                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
902                                            rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
903                         }
904                         glTranslatef(0, 0, S1);
905                         DRAW_CUBIT(mi,
906                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
907                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
908                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
909                         glPopMatrix();
910                         for (j = 1; j < MAXSIZEY - 1; j++) {
911                                 glPushMatrix();
912                                 if (slice.depth == REVY(j))
913                                         glRotatef(rotatestep, 0, HALFY, 0);
914                                 glTranslatef(-HALFX, MIDY(j), -HALFZ);
915                                 DRAW_CUBIT(mi,
916                                            rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
917                                            rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
918                                            NO_FACE, NO_FACE);
919                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
920                                         glTranslatef(0, 0, S1);
921                                         DRAW_CUBIT(mi,
922                                                    NO_FACE, NO_FACE,
923                                                    rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
924                                                    NO_FACE, NO_FACE);
925                                 }
926                                 glTranslatef(0, 0, S1);
927                                 DRAW_CUBIT(mi,
928                                            NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
929                                            rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
930                                            NO_FACE, NO_FACE);
931                                 for (i = 1; i < MAXSIZEX - 1; i++) {
932                                         glTranslatef(1, 0, -SZ);
933                                         DRAW_CUBIT(mi,
934                                                    rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
935                                                    NO_FACE, NO_FACE,
936                                                    NO_FACE, NO_FACE);
937                                         /* Center */
938                                         glTranslatef(0, 0, SZ);
939                                         DRAW_CUBIT(mi,
940                                                    NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
941                                                    NO_FACE, NO_FACE,
942                                                    NO_FACE, NO_FACE);
943                                 }
944                                 glTranslatef(S1, 0, -SZ);
945                                 DRAW_CUBIT(mi,
946                                            rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
947                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
948                                            NO_FACE, NO_FACE);
949                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
950                                         glTranslatef(0, 0, S1);
951                                         DRAW_CUBIT(mi,
952                                                    NO_FACE, NO_FACE,
953                                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
954                                                    NO_FACE, NO_FACE);
955                                 }
956                                 glTranslatef(0, 0, S1);
957                                 DRAW_CUBIT(mi,
958                                            NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
959                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
960                                            NO_FACE, NO_FACE);
961                                 glPopMatrix();
962                         }
963                         if (slice.depth == 0)
964                                 glRotatef(rotatestep, 0, HALFY, 0);
965
966                         glTranslatef(-HALFX, HALFY, -HALFZ);
967                         DRAW_CUBIT(mi,
968                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
969                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
970                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
971                         for (k = 1; k < MAXSIZEZ - 1; k++) {
972                                 glTranslatef(0, 0, S1);
973                                 DRAW_CUBIT(mi,
974                                            NO_FACE, NO_FACE,
975                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
976                                            NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
977                         }
978                         glTranslatef(0, 0, S1);
979                         DRAW_CUBIT(mi,
980                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
981                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
982                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
983                         for (i = 1; i < MAXSIZEX - 1; i++) {
984                                 glTranslatef(S1, 0, -SZ);
985                                 DRAW_CUBIT(mi,
986                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
987                                            NO_FACE, NO_FACE,
988                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
989                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
990                                         glTranslatef(0, 0, S1);
991                                         DRAW_CUBIT(mi,
992                                                    NO_FACE, NO_FACE,
993                                                    NO_FACE, NO_FACE,
994                                                    NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
995                                 }
996                                 glTranslatef(0, 0, S1);
997                                 DRAW_CUBIT(mi,
998                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
999                                            NO_FACE, NO_FACE,
1000                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1001                         }
1002                         glTranslatef(S1, 0, -SZ);
1003                         DRAW_CUBIT(mi,
1004                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1005                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1006                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1007                         for (k = 1; k < MAXSIZEZ - 1; k++) {
1008                                 glTranslatef(0, 0, S1);
1009                                 DRAW_CUBIT(mi,
1010                                            NO_FACE, NO_FACE,
1011                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1012                                            NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1013                         }
1014                         glTranslatef(0, 0, S1);
1015                         DRAW_CUBIT(mi,
1016                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1017                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1018                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1019                         break;
1020                 case LEFT_FACE: /* RIGHT_FACE too */
1021                         /* rotatestep is negative because the RIGHT face is the default here */
1022                         glPushMatrix();
1023                         if (slice.depth == 0)
1024                                 glRotatef(-rotatestep, HALFX, 0, 0);
1025
1026                         glTranslatef(-HALFX, -HALFY, -HALFZ);
1027                         DRAW_CUBIT(mi,
1028                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1029                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1030                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
1031                         for (j = 1; j < MAXSIZEY - 1; j++) {
1032                                 glTranslatef(0, S1, 0);
1033                                 DRAW_CUBIT(mi,
1034                                            rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
1035                                            rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1036                                            NO_FACE, NO_FACE);
1037                         }
1038                         glTranslatef(0, S1, 0);
1039                         DRAW_CUBIT(mi,
1040                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
1041                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1042                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
1043                         for (k = 1; k < MAXSIZEZ - 1; k++) {
1044                                 glTranslatef(0, -SY, S1);
1045                                 DRAW_CUBIT(mi,
1046                                            NO_FACE, NO_FACE,
1047                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
1048                                            rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1049                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1050                                         glTranslatef(0, S1, 0);
1051                                         DRAW_CUBIT(mi,
1052                                                    NO_FACE, NO_FACE,
1053                                                    rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
1054                                                    NO_FACE, NO_FACE);
1055                                 }
1056                                 glTranslatef(0, S1, 0);
1057                                 DRAW_CUBIT(mi,
1058                                            NO_FACE, NO_FACE,
1059                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
1060                                            NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
1061                         }
1062                         glTranslatef(0, -SY, S1);
1063                         DRAW_CUBIT(mi,
1064                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1065                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1066                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1067                         for (j = 1; j < MAXSIZEY - 1; j++) {
1068                                 glTranslatef(0, S1, 0);
1069                                 DRAW_CUBIT(mi,
1070                                            NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1071                                            rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1072                                            NO_FACE, NO_FACE);
1073                         }
1074                         glTranslatef(0, S1, 0);
1075                         DRAW_CUBIT(mi,
1076                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1077                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1078                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1079                         glPopMatrix();
1080                         for (i = 1; i < MAXSIZEX - 1; i++) {
1081                                 glPushMatrix();
1082                                 if (slice.depth == i)
1083                                         glRotatef(-rotatestep, HALFX, 0, 0);
1084                                 glTranslatef(MIDX(i), -HALFY, -HALFZ);
1085                                 DRAW_CUBIT(mi,
1086                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1087                                            NO_FACE, NO_FACE,
1088                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1089                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1090                                         glTranslatef(0, S1, 0);
1091                                         DRAW_CUBIT(mi,
1092                                                    rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1093                                                    NO_FACE, NO_FACE,
1094                                                    NO_FACE, NO_FACE);
1095                                 }
1096                                 glTranslatef(0, S1, 0);
1097                                 DRAW_CUBIT(mi,
1098                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1099                                            NO_FACE, NO_FACE,
1100                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1101                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
1102                                         glTranslatef(0, -SY, S1);
1103                                         DRAW_CUBIT(mi,
1104                                                    NO_FACE, NO_FACE,
1105                                                    NO_FACE, NO_FACE,
1106                                                    rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1107                                         /* Center */
1108                                         glTranslatef(0, SY, 0);
1109                                         DRAW_CUBIT(mi,
1110                                                    NO_FACE, NO_FACE,
1111                                                    NO_FACE, NO_FACE,
1112                                                    NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1113                                 }
1114                                 glTranslatef(0, -SY, S1);
1115                                 DRAW_CUBIT(mi,
1116                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1117                                            NO_FACE, NO_FACE,
1118                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1119                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1120                                         glTranslatef(0, S1, 0);
1121                                         DRAW_CUBIT(mi,
1122                                                    NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1123                                                    NO_FACE, NO_FACE,
1124                                                    NO_FACE, NO_FACE);
1125                                 }
1126                                 glTranslatef(0, S1, 0);
1127                                 DRAW_CUBIT(mi,
1128                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1129                                            NO_FACE, NO_FACE,
1130                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1131                                 glPopMatrix();
1132                         }
1133                         if (slice.depth == MAXSIZEX - 1)
1134                                 glRotatef(-rotatestep, HALFX, 0, 0);
1135                         glTranslatef(HALFX, -HALFY, -HALFZ);
1136                         DRAW_CUBIT(mi,
1137                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1138                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1139                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1140                         for (j = 1; j < MAXSIZEY - 1; j++) {
1141                                 glTranslatef(0, S1, 0);
1142                                 DRAW_CUBIT(mi,
1143                                            rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1144                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1145                                            NO_FACE, NO_FACE);
1146                         }
1147                         glTranslatef(0, S1, 0);
1148                         DRAW_CUBIT(mi,
1149                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1150                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1151                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1152                         for (k = 1; k < MAXSIZEZ - 1; k++) {
1153                                 glTranslatef(0, -SY, S1);
1154                                 DRAW_CUBIT(mi,
1155                                            NO_FACE, NO_FACE,
1156                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1157                                            rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1158                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1159                                         glTranslatef(0, S1, 0);
1160                                         DRAW_CUBIT(mi,
1161                                                    NO_FACE, NO_FACE,
1162                                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1163                                                    NO_FACE, NO_FACE);
1164                                 }
1165                                 glTranslatef(0, S1, 0);
1166                                 DRAW_CUBIT(mi,
1167                                            NO_FACE, NO_FACE,
1168                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1169                                            NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1170                         }
1171                         glTranslatef(0, -SY, S1);
1172                         DRAW_CUBIT(mi,
1173                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1174                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1175                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1176                         for (j = 1; j < MAXSIZEY - 1; j++) {
1177                                 glTranslatef(0, S1, 0);
1178                                 DRAW_CUBIT(mi,
1179                                            NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1180                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1181                                            NO_FACE, NO_FACE);
1182                         }
1183                         glTranslatef(0, S1, 0);
1184                         DRAW_CUBIT(mi,
1185                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1186                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1187                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1188                         break;
1189                 case FRONT_FACE:        /* BACK_FACE too */
1190                         glPushMatrix();
1191                         if (slice.depth == MAXSIZEZ - 1)
1192                                 glRotatef(rotatestep, 0, 0, HALFZ);
1193
1194                         glTranslatef(-HALFX, -HALFY, -HALFZ);
1195                         DRAW_CUBIT(mi,
1196                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1197                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1198                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
1199                         for (i = 1; i < MAXSIZEX - 1; i++) {
1200                                 glTranslatef(S1, 0, 0);
1201                                 DRAW_CUBIT(mi,
1202                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1203                                            NO_FACE, NO_FACE,
1204                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1205                         }
1206                         glTranslatef(S1, 0, 0);
1207                         DRAW_CUBIT(mi,
1208                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1209                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1210                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1211                         for (j = 1; j < MAXSIZEY - 1; j++) {
1212                                 glTranslatef(-SX, S1, 0);
1213                                 DRAW_CUBIT(mi,
1214                                            rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
1215                                            rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1216                                            NO_FACE, NO_FACE);
1217                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1218                                         glTranslatef(S1, 0, 0);
1219                                         DRAW_CUBIT(mi,
1220                                                    rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1221                                                    NO_FACE, NO_FACE,
1222                                                    NO_FACE, NO_FACE);
1223                                 }
1224                                 glTranslatef(S1, 0, 0);
1225                                 DRAW_CUBIT(mi,
1226                                            rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1227                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1228                                            NO_FACE, NO_FACE);
1229                         }
1230                         glTranslatef(-SX, S1, 0);
1231                         DRAW_CUBIT(mi,
1232                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
1233                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1234                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
1235                         for (i = 1; i < MAXSIZEX - 1; i++) {
1236                                 glTranslatef(S1, 0, 0);
1237                                 DRAW_CUBIT(mi,
1238                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1239                                            NO_FACE, NO_FACE,
1240                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1241                         }
1242                         glTranslatef(S1, 0, 0);
1243                         DRAW_CUBIT(mi,
1244                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1245                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1246                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1247                         glPopMatrix();
1248                         for (k = 1; k < MAXSIZEZ - 1; k++) {
1249                                 glPushMatrix();
1250                                 if (slice.depth == REVZ(k))
1251                                         glRotatef(rotatestep, 0, 0, HALFZ);
1252                                 glTranslatef(-HALFX, -HALFY, MIDZ(k));
1253                                 DRAW_CUBIT(mi,
1254                                            NO_FACE, NO_FACE,
1255                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
1256                                            rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1257                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1258                                         glTranslatef(S1, 0, 0);
1259                                         DRAW_CUBIT(mi,
1260                                                    NO_FACE, NO_FACE,
1261                                                    NO_FACE, NO_FACE,
1262                                                    rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1263                                 }
1264                                 glTranslatef(S1, 0, 0);
1265                                 DRAW_CUBIT(mi,
1266                                            NO_FACE, NO_FACE,
1267                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1268                                            rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1269                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1270                                         glTranslatef(-SX, S1, 0);
1271                                         DRAW_CUBIT(mi,
1272                                                    NO_FACE, NO_FACE,
1273                                                    rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
1274                                                    NO_FACE, NO_FACE);
1275                                         /* Center */
1276                                         glTranslatef(SX, 0, 0);
1277                                         DRAW_CUBIT(mi,
1278                                                    NO_FACE, NO_FACE,
1279                                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1280                                                    NO_FACE, NO_FACE);
1281                                 }
1282                                 glTranslatef(-SX, S1, 0);
1283                                 DRAW_CUBIT(mi,
1284                                            NO_FACE, NO_FACE,
1285                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
1286                                            NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
1287                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1288                                         glTranslatef(S1, 0, 0);
1289                                         DRAW_CUBIT(mi,
1290                                                    NO_FACE, NO_FACE,
1291                                                    NO_FACE, NO_FACE,
1292                                                    NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1293                                 }
1294                                 glTranslatef(S1, 0, 0);
1295                                 DRAW_CUBIT(mi,
1296                                            NO_FACE, NO_FACE,
1297                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1298                                            NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1299                                 glPopMatrix();
1300                         }
1301                         if (slice.depth == 0)
1302                                 glRotatef(rotatestep, 0, 0, HALFZ);
1303                         glTranslatef(-HALFX, -HALFY, HALFZ);
1304                         DRAW_CUBIT(mi,
1305                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1306                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1307                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1308                         for (i = 1; i < MAXSIZEX - 1; i++) {
1309                                 glTranslatef(S1, 0, 0);
1310                                 DRAW_CUBIT(mi,
1311                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1312                                            NO_FACE, NO_FACE,
1313                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1314                         }
1315                         glTranslatef(S1, 0, 0);
1316                         DRAW_CUBIT(mi,
1317                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1318                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1319                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1320                         for (j = 1; j < MAXSIZEY - 1; j++) {
1321                                 glTranslatef(-SX, S1, 0);
1322                                 DRAW_CUBIT(mi,
1323                                            NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1324                                            rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1325                                            NO_FACE, NO_FACE);
1326                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1327                                         glTranslatef(S1, 0, 0);
1328                                         DRAW_CUBIT(mi,
1329                                                    NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1330                                                    NO_FACE, NO_FACE,
1331                                                    NO_FACE, NO_FACE);
1332                                 }
1333                                 glTranslatef(S1, 0, 0);
1334                                 DRAW_CUBIT(mi,
1335                                            NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1336                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1337                                            NO_FACE, NO_FACE);
1338                         }
1339                         glTranslatef(-SX, S1, 0);
1340                         DRAW_CUBIT(mi,
1341                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1342                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1343                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1344                         for (i = 1; i < MAXSIZEX - 1; i++) {
1345                                 glTranslatef(S1, 0, 0);
1346                                 DRAW_CUBIT(mi,
1347                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1348                                            NO_FACE, NO_FACE,
1349                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1350                         }
1351                         glTranslatef(S1, 0, 0);
1352                         DRAW_CUBIT(mi,
1353                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1354                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1355                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1356                         break;
1357         }
1358         return True;
1359 #undef S1
1360 }
1361
1362 /* From David Bagley's xrubik.  Used by permission. ;)  */
1363 static void
1364 readRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1365 {
1366         int         g, sizeOfRow;
1367
1368         sizeOfRow = sizeRow(rp, face);
1369         if (dir == TOP || dir == BOTTOM)
1370                 for (g = 0; g < size; g++)
1371                         rp->rowLoc[orient][g] =
1372                                 rp->cubeLoc[face][g * sizeOfRow + h];
1373         else                    /* dir == RIGHT || dir == LEFT */
1374                 for (g = 0; g < size; g++)
1375                         rp->rowLoc[orient][g] =
1376                                 rp->cubeLoc[face][h * sizeOfRow + g];
1377 }
1378
1379 static void
1380 rotateRC(rubikstruct * rp, int rotate, int orient, int size)
1381 {
1382         int         g;
1383
1384         for (g = 0; g < size; g++)
1385                 rp->rowLoc[orient][g].rotation =
1386                         (rp->rowLoc[orient][g].rotation + rotate) % MAXORIENT;
1387 }
1388
1389 static void
1390 reverseRC(rubikstruct * rp, int orient, int size)
1391 {
1392         int         g;
1393         RubikLoc    temp;
1394
1395         for (g = 0; g < size / 2; g++) {
1396                 temp = rp->rowLoc[orient][size - 1 - g];
1397                 rp->rowLoc[orient][size - 1 - g] = rp->rowLoc[orient][g];
1398                 rp->rowLoc[orient][g] = temp;
1399         }
1400 }
1401
1402 static void
1403 writeRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1404 {
1405         int         g, position, sizeOfRow;
1406
1407         sizeOfRow = sizeRow(rp, face);
1408         if (dir == TOP || dir == BOTTOM) {
1409                 for (g = 0; g < size; g++) {
1410                         position = g * sizeOfRow + h;
1411                         rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1412                         /* DrawSquare(face, position); */
1413                 }
1414         } else {                /* dir == RIGHT || dir == LEFT */
1415                 for (g = 0; g < size; g++) {
1416                         position = h * sizeOfRow + g;
1417                         rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1418                         /* DrawSquare(face, position); */
1419                 }
1420         }
1421 }
1422
1423 static Bool
1424 rotateFace(rubikstruct * rp, int face, int direction)
1425 {
1426         int         position, i, j, sizeOfRow, sizeOfColumn, sizeOnPlane;
1427         RubikLoc   *faceLoc;
1428
1429         faceSizes(rp, face, &sizeOfRow, &sizeOfColumn);
1430         sizeOnPlane = sizeOfRow * sizeOfColumn;
1431         if ((faceLoc = (RubikLoc *) malloc(sizeOnPlane *
1432                         sizeof (RubikLoc))) == NULL) {
1433                 return False;
1434         }
1435         /* Read Face */
1436         for (position = 0; position < sizeOnPlane; position++)
1437                 faceLoc[position] = rp->cubeLoc[face][position];
1438         /* Write Face */
1439         for (position = 0; position < sizeOnPlane; position++) {
1440                 i = position % sizeOfRow;
1441                 j = position / sizeOfRow;
1442                 if (direction == CW)
1443                         rp->cubeLoc[face][position] =
1444                                 faceLoc[(sizeOfRow - i - 1) * sizeOfRow + j];
1445                 else if (direction == CCW)
1446                         rp->cubeLoc[face][position] =
1447                                 faceLoc[i * sizeOfRow + sizeOfColumn - j - 1];
1448                 else /* (direction == HALF) */
1449                         rp->cubeLoc[face][position] =
1450                                 faceLoc[sizeOfRow - i - 1 + (sizeOfColumn - j - 1) * sizeOfRow];
1451                 rp->cubeLoc[face][position].rotation =
1452                         (rp->cubeLoc[face][position].rotation +
1453                                 direction - MAXORIENT) % MAXORIENT;
1454                 /* DrawSquare(face, position); */
1455         }
1456         if (faceLoc != NULL)
1457                 (void) free((void *) faceLoc);
1458         return True;
1459 }
1460
1461 /* Yeah this is big and ugly */
1462 static void
1463 slideRC(int face, int direction, int h, int sizeOnOppAxis,
1464         int *newFace, int *newDirection, int *newH,
1465         int *rotate, Bool *reverse)
1466 {
1467         *newFace = slideNextRow[face][direction].face;
1468         *rotate = slideNextRow[face][direction].rotation;
1469         *newDirection = (*rotate + direction) % MAXORIENT;
1470         switch (*rotate) {
1471                 case TOP:
1472                         *newH = h;
1473                         *reverse = False;
1474                         break;
1475                 case RIGHT:
1476                         if (*newDirection == TOP || *newDirection == BOTTOM) {
1477                                 *newH = sizeOnOppAxis - 1 - h;
1478                                 *reverse = False;
1479                         } else {        /* *newDirection == RIGHT || *newDirection == LEFT */
1480                                 *newH = h;
1481                                 *reverse = True;
1482                         }
1483                                 break;
1484                 case BOTTOM:
1485                         *newH = sizeOnOppAxis - 1 - h;
1486                         *reverse = True;
1487                         break;
1488                 case LEFT:
1489                         if (*newDirection == TOP || *newDirection == BOTTOM) {
1490                                 *newH = h;
1491                                 *reverse = True;
1492                         } else {        /* *newDirection == RIGHT || *newDirection == LEFT */
1493                                 *newH = sizeOnOppAxis - 1 - h;
1494                                 *reverse = False;
1495                         }
1496                         break;
1497                 default:
1498                         (void) printf("slideRC: rotate %d\n", *rotate);
1499                         *newH = 0;
1500                         *reverse = False;
1501         }
1502 }
1503
1504 static Bool
1505 moveRubik(rubikstruct * rp, int face, int direction, int position)
1506 {
1507         int         newFace, newDirection, rotate, reverse; 
1508         int         h, k, newH;
1509         int         i, j, sizeOfRow, sizeOfColumn, sizeOnAxis, sizeOnOppAxis;
1510
1511         faceSizes(rp, face, &sizeOfRow, &sizeOfColumn);
1512         if (direction == CW || direction == CCW) {
1513                 direction = (direction == CCW) ?
1514                         (rotateToRow[face].direction + 2) % MAXORIENT :
1515                         rotateToRow[face].direction;
1516                 if (rotateToRow[face].sideFace == RIGHT) {
1517                         i = j = sizeOfColumn - 1;
1518                 } else if (rotateToRow[face].sideFace == BOTTOM) {
1519                         i = j = sizeOfRow - 1;
1520                 } else {
1521                         i = j = 0;
1522                 }
1523                 face = rotateToRow[face].face;
1524                 position = j * sizeOfRow + i;
1525         }
1526         i = position % sizeOfRow;
1527         j = position / sizeOfRow;
1528         h = (direction == TOP || direction == BOTTOM) ? i : j;
1529         if (direction == TOP || direction == BOTTOM) {
1530                 sizeOnAxis = sizeOfColumn;
1531                 sizeOnOppAxis = sizeOfRow;
1532         } else {
1533                 sizeOnAxis = sizeOfRow;
1534                 sizeOnOppAxis = sizeOfColumn;
1535         }
1536         /* rotate sides CW or CCW or HALF) */
1537
1538         if (h == sizeOnOppAxis - 1) {
1539                 newDirection = (direction == TOP || direction == BOTTOM) ?
1540                         TOP : RIGHT;
1541                 if (rp->degreeTurn == 180) {
1542                         if (!rotateFace(rp, rowToRotate[face][newDirection], HALF))
1543                                 return False;
1544                 } else if (direction == TOP || direction == RIGHT) {
1545                         if (!rotateFace(rp, rowToRotate[face][newDirection], CW))
1546                                 return False;
1547                 } else {                /* direction == BOTTOM || direction == LEFT */
1548                         if (!rotateFace(rp, rowToRotate[face][newDirection], CCW))
1549                                 return False;
1550                 }
1551         }
1552         if (h == 0) {
1553                 newDirection = (direction == TOP || direction == BOTTOM) ?
1554                         BOTTOM : LEFT;
1555                 if (rp->degreeTurn == 180) {
1556                         if (!rotateFace(rp, rowToRotate[face][newDirection], HALF))
1557                                 return False;
1558                 } else if (direction == TOP || direction == RIGHT) {
1559                         if (!rotateFace(rp, rowToRotate[face][newDirection], CCW))
1560                                 return False;
1561                 } else {                /* direction == BOTTOM  || direction == LEFT */
1562                         if (!rotateFace(rp, rowToRotate[face][newDirection], CW))
1563                                 return False;
1564                 }
1565         }
1566         /* Slide rows or columns */
1567         readRC(rp, face, direction, h, 0, sizeOnAxis);
1568         if (rp->degreeTurn == 180) {
1569                 int sizeOnDepthAxis;
1570
1571                 slideRC(face, direction, h, sizeOnOppAxis,
1572                         &newFace, &newDirection, &newH, &rotate, &reverse);
1573                 sizeOnDepthAxis = sizeFace(rp, newFace) / sizeOnOppAxis;
1574                 readRC(rp, newFace, newDirection, newH, 1, sizeOnDepthAxis);
1575                 rotateRC(rp, rotate, 0, sizeOnAxis);
1576                 if (reverse == True)
1577                         reverseRC(rp, 0, sizeOnAxis);
1578                 face = newFace;
1579                 direction = newDirection;
1580                 h = newH;
1581                 for (k = 2; k <= MAXORIENT + 1; k++) {
1582                         slideRC(face, direction, h, sizeOnOppAxis,
1583                                 &newFace, &newDirection, &newH, &rotate, &reverse);
1584                         if (k != MAXORIENT && k != MAXORIENT + 1)
1585                                 readRC(rp, newFace, newDirection, newH, k,
1586                                         (k % 2) ? sizeOnDepthAxis : sizeOnAxis);
1587                         rotateRC(rp, rotate, k - 2,
1588                                         (k % 2) ? sizeOnDepthAxis : sizeOnAxis);
1589                         if (k != MAXORIENT + 1)
1590                                 rotateRC(rp, rotate, k - 1,
1591                                         (k % 2) ? sizeOnAxis : sizeOnDepthAxis);
1592                         if (reverse == True) {
1593                                 reverseRC(rp, k - 2,
1594                                         (k % 2) ? sizeOnDepthAxis : sizeOnAxis);
1595                                 if (k != MAXORIENT + 1)
1596                                         reverseRC(rp, k - 1,
1597                                                 (k % 2) ? sizeOnAxis : sizeOnDepthAxis);
1598                         }
1599                         writeRC(rp, newFace, newDirection, newH, k - 2,
1600                                 (k % 2) ? sizeOnDepthAxis : sizeOnAxis);
1601                         face = newFace;
1602                         direction = newDirection;
1603                         h = newH;
1604                 }
1605         } else {
1606                 for (k = 1; k <= MAXORIENT; k++) {
1607                         slideRC(face, direction, h, sizeOnOppAxis,
1608                                 &newFace, &newDirection, &newH, &rotate, &reverse);
1609                         if (k != MAXORIENT)
1610                                 readRC(rp, newFace, newDirection, newH, k, sizeOnAxis);
1611                         rotateRC(rp, rotate, k - 1, sizeOnAxis);
1612                         if (reverse == True)
1613                                 reverseRC(rp, k - 1, sizeOnAxis);
1614                         writeRC(rp, newFace, newDirection, newH, k - 1, sizeOnAxis);
1615                         face = newFace;
1616                         direction = newDirection;
1617                         h = newH;
1618                 }
1619         }       
1620         return True;
1621 }
1622
1623 #ifdef DEBUG
1624 void
1625 printCube(rubikstruct * rp)
1626 {
1627         int         face, position, sizeOfRow, sizeOfColumn;
1628
1629         for (face = 0; face < MAXFACES; face++) {
1630                 faceSizes(rp, face, &sizeOfRow, &sizeOfColumn);
1631                 for (position = 0; position < sizeOfRow * sizeOfColumn; position++) {
1632                         (void) printf("%d %d  ", rp->cubeLoc[face][position].face,
1633                                       rp->cubeLoc[face][position].rotation);
1634                         if (!((position + 1) % sizeOfRow))
1635                                 (void) printf("\n");
1636                 }
1637                 (void) printf("\n");
1638         }
1639         (void) printf("\n");
1640 }
1641
1642 #endif
1643
1644 static Bool
1645 evalmovement(ModeInfo * mi, RubikMove movement)
1646 {
1647         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1648
1649 #ifdef DEBUG
1650         printCube(rp);
1651 #endif
1652         if (movement.face < 0 || movement.face >= MAXFACES)
1653                 return True;
1654         if (!moveRubik(rp, movement.face, movement.direction, movement.position))
1655                 return False;
1656         return True;
1657 }
1658
1659 static      Bool
1660 compare_moves(rubikstruct * rp, RubikMove move1, RubikMove move2, Bool opp)
1661 {
1662         RubikSlice  slice1, slice2;
1663
1664         convertMove(rp, move1, &slice1);
1665         convertMove(rp, move2, &slice2);
1666         if (slice1.face == slice2.face &&
1667             slice1.depth == slice2.depth) {
1668                 if (slice1.rotation == slice2.rotation) {       /* CW or CCW */
1669                         if (!opp)
1670                                 return True;
1671                 } else {
1672                         if (opp)
1673                                 return True;
1674                 }
1675         }
1676         return False;
1677 }
1678
1679 static Bool
1680 shuffle(ModeInfo * mi)
1681 {
1682         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1683         int         i, face, position;
1684         RubikMove   move;
1685
1686         if (sizex)
1687                 i = sizex;
1688         else
1689                 i = MI_SIZE(mi);
1690         if (i < -MINSIZE)
1691                 i = NRAND(-i - MINSIZE + 1) + MINSIZE;
1692         else if (i < MINSIZE)
1693                 i = MINSIZE;
1694
1695         if (LRAND() % 2 && !sizey && !sizez) { /* Make normal (NxNxN) cubes more likely */
1696                 MAXSIZEX = MAXSIZEY = MAXSIZEZ = i;
1697         } else {
1698                 MAXSIZEX = i;
1699                 if (sizey)
1700                         i = sizey;
1701                 else
1702                         i = MI_SIZE(mi);
1703                 if (i < -MINSIZE)
1704                         i = NRAND(-i - MINSIZE + 1) + MINSIZE;
1705                 else if (i < MINSIZE)
1706                         i = MINSIZE;
1707                 if (LRAND() % 2 && !sizez) { /* Make more MxNxN more likely than LxMxN */
1708                         MAXSIZEY = MAXSIZEZ = i;
1709                 } else {
1710                         MAXSIZEY = i;
1711                         if (sizez)
1712                                 i = sizez;
1713                         else
1714                                 i = MI_SIZE(mi);
1715                         if (i < -MINSIZE)
1716                                 i = NRAND(-i - MINSIZE + 1) + MINSIZE;
1717                         else if (i < MINSIZE)
1718                                 i = MINSIZE;
1719                         MAXSIZEZ = i;
1720                 }
1721         }
1722
1723         for (face = 0; face < MAXFACES; face++) {
1724                 if (rp->cubeLoc[face] != NULL)
1725                         (void) free((void *) rp->cubeLoc[face]);
1726                 if ((rp->cubeLoc[face] = (RubikLoc *) malloc(sizeFace(rp, face) *
1727                                 sizeof (RubikLoc))) == NULL) {
1728                         return False;
1729                 }
1730                 for (position = 0; position < sizeFace(rp, face); position++) {
1731                         rp->cubeLoc[face][position].face = face;
1732                         rp->cubeLoc[face][position].rotation = TOP;
1733                 }
1734         }
1735         for (i = 0; i < MAXORIENT; i++) {
1736                 if (rp->rowLoc[i] != NULL)
1737                         (void) free((void *) rp->rowLoc[i]);
1738                 /* The following is reused so make it the biggest size */
1739                 if ((rp->rowLoc[i] = (RubikLoc *) malloc(MAXMAXSIZE *
1740                                 sizeof (RubikLoc))) == NULL) {
1741                         return False;
1742                 }
1743         }
1744         rp->storedmoves = MI_COUNT(mi);
1745         if (rp->storedmoves < 0) {
1746                 if (rp->moves != NULL)
1747                         (void) free((void *) rp->moves);
1748                 rp->moves = (RubikMove *) NULL;
1749                 rp->storedmoves = NRAND(-rp->storedmoves) + 1;
1750         }
1751         if ((rp->storedmoves) && (rp->moves == NULL))
1752                 if ((rp->moves = (RubikMove *) calloc(rp->storedmoves + 1,
1753                                  sizeof (RubikMove))) == NULL) {
1754                         return False;
1755                 }
1756         if (MI_CYCLES(mi) <= 1) {
1757                 rp->anglestep = 90.0;
1758         } else {
1759                 rp->anglestep = 90.0 / (GLfloat) (MI_CYCLES(mi));
1760         }
1761
1762         for (i = 0; i < rp->storedmoves; i++) {
1763                 Bool condition;
1764
1765                 do {
1766                         move.face = NRAND(MAXFACES);
1767                         move.direction = NRAND(MAXORIENT);      /* Exclude CW and CCW, its ok */
1768                         move.position = NRAND(sizeFace(rp, move.face));
1769                         rp->degreeTurn = (checkFaceSquare(rp,
1770                                 rowToRotate[move.face][move.direction])) ? 90 : 180;
1771                         condition = True;
1772                         if (i > 0) {    /* avoid immediate undoing moves */
1773                                 if (compare_moves(rp, move, rp->moves[i - 1], True))
1774                                         condition = False;
1775                                 if (rp->degreeTurn == 180 &&
1776                                     compare_moves(rp, move, rp->moves[i - 1], False))
1777                                         condition = False;
1778                         }
1779                         if (i > 1)      /* avoid 3 consecutive identical moves */
1780                                 if (compare_moves(rp, move, rp->moves[i - 1], False) &&
1781                                     compare_moves(rp, move, rp->moves[i - 2], False))
1782                                         condition = False;
1783                         /*
1784                          * Still some silly moves being made....
1785                          */
1786                 } while (!condition);
1787                 if (hideshuffling)
1788                         if (!evalmovement(mi, move))
1789                                 return False;
1790                 rp->moves[i] = move;
1791         }
1792         rp->VX = 0.05;
1793         if (NRAND(100) < 50)
1794                 rp->VX *= -1;
1795         rp->VY = 0.05;
1796         if (NRAND(100) < 50)
1797                 rp->VY *= -1;
1798         rp->movement.face = NO_FACE;
1799         rp->rotatestep = 0;
1800         rp->action = hideshuffling ? ACTION_SOLVE : ACTION_SHUFFLE;
1801         rp->shufflingmoves = 0;
1802         rp->done = 0;
1803         return True;
1804 }
1805
1806 void
1807 reshape(ModeInfo * mi, int width, int height)
1808 {
1809         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1810
1811         glViewport(0, 0, rp->WindW = (GLint) width, rp->WindH = (GLint) height);
1812         glMatrixMode(GL_PROJECTION);
1813         glLoadIdentity();
1814         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
1815         glMatrixMode(GL_MODELVIEW);
1816
1817 }
1818
1819 static Bool
1820 pinit(ModeInfo * mi)
1821 {
1822         glClearDepth(1.0);
1823         glClearColor(0.0, 0.0, 0.0, 1.0);
1824         glColor3f(1.0, 1.0, 1.0);
1825
1826         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
1827         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
1828         glLightfv(GL_LIGHT0, GL_POSITION, position0);
1829         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
1830         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
1831         glLightfv(GL_LIGHT1, GL_POSITION, position1);
1832         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1833         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1834         glEnable(GL_LIGHTING);
1835         glEnable(GL_LIGHT0);
1836         glEnable(GL_LIGHT1);
1837         glEnable(GL_DEPTH_TEST);
1838         glEnable(GL_NORMALIZE);
1839         glEnable(GL_CULL_FACE);
1840
1841         glShadeModel(GL_FLAT);
1842         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1843         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1844
1845         return (shuffle(mi));
1846 }
1847
1848 static void
1849 free_rubik(rubikstruct *rp)
1850 {
1851         int         i;
1852
1853         for (i = 0; i < MAXFACES; i++)
1854                 if (rp->cubeLoc[i] != NULL) {
1855                         (void) free((void *) rp->cubeLoc[i]);
1856                         rp->cubeLoc[i] = (RubikLoc *) NULL;
1857                 }
1858         for (i = 0; i < MAXORIENT; i++)
1859                 if (rp->rowLoc[i] != NULL) {
1860                         (void) free((void *) rp->rowLoc[i]);
1861                         rp->rowLoc[i] = (RubikLoc *) NULL;
1862                 }
1863         if (rp->moves != NULL) {
1864                 (void) free((void *) rp->moves);
1865                 rp->moves = (RubikMove *) NULL;
1866         }
1867 }
1868
1869 void
1870 release_rubik(ModeInfo * mi)
1871 {
1872         if (rubik != NULL) {
1873                 int         screen;
1874
1875                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1876                         rubikstruct *rp = &rubik[screen];
1877
1878                         free_rubik(rp);
1879                 }
1880                 (void) free((void *) rubik);
1881                 rubik = (rubikstruct *) NULL;
1882         }
1883         FreeAllGL(mi);
1884 }
1885
1886 void
1887 init_rubik(ModeInfo * mi)
1888 {
1889         rubikstruct *rp;
1890
1891         if (rubik == NULL) {
1892                 if ((rubik = (rubikstruct *) calloc(MI_NUM_SCREENS(mi),
1893                                               sizeof (rubikstruct))) == NULL)
1894                         return;
1895         }
1896         rp = &rubik[MI_SCREEN(mi)];
1897         rp->step = NRAND(90);
1898         rp->PX = ((float) LRAND() / (float) MAXRAND) * 2.0 - 1.0;
1899         rp->PY = ((float) LRAND() / (float) MAXRAND) * 2.0 - 1.0;
1900
1901         if ((rp->glx_context = init_GL(mi)) != NULL) {
1902
1903                 reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1904                 glDrawBuffer(GL_BACK);
1905                 if (!pinit(mi)) {
1906                         free_rubik(rp);
1907                         if (MI_IS_VERBOSE(mi)) {
1908                                 (void) fprintf(stderr,
1909                                         "Could not allocate memory for rubik\n");
1910                         }
1911                         return;
1912                 }
1913         } else {
1914                 MI_CLEARWINDOW(mi);
1915         }
1916 }
1917
1918 void
1919 draw_rubik(ModeInfo * mi)
1920 {
1921         Bool bounced = False;
1922         Display    *display = MI_DISPLAY(mi);
1923         Window      window = MI_WINDOW(mi);
1924         rubikstruct *rp;
1925
1926         if (rubik == NULL)
1927                 return;
1928         rp = &rubik[MI_SCREEN(mi)];
1929         if (rp->cubeLoc[0] == NULL)
1930                 return;
1931
1932         MI_IS_DRAWN(mi) = True;
1933         if (!rp->glx_context)
1934                 return;
1935
1936         glXMakeCurrent(display, window, *(rp->glx_context));
1937
1938         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1939
1940         glPushMatrix();
1941
1942         glTranslatef(0.0, 0.0, -10.0);
1943
1944         rp->PX += rp->VX;
1945         rp->PY += rp->VY;
1946
1947         if (rp->PY < -1) {
1948                 rp->PY += (-1) - (rp->PY);
1949                 rp->VY = -rp->VY;
1950                 bounced = True;
1951         }
1952         if (rp->PY > 1) {
1953                 rp->PY -= (rp->PY) - 1;
1954                 rp->VY = -rp->VY;
1955                 bounced = True;
1956         }
1957         if (rp->PX < -1) {
1958                 rp->PX += (-1) - (rp->PX);
1959                 rp->VX = -rp->VX;
1960                 bounced = True;
1961         }
1962         if (rp->PX > 1) {
1963                 rp->PX -= (rp->PX) - 1;
1964                 rp->VX = -rp->VX;
1965                 bounced = True;
1966         }
1967         if (bounced) {
1968                 rp->VX += ((float) LRAND() / (float) MAXRAND) * 0.02 - 0.01;
1969                 rp->VX += ((float) LRAND() / (float) MAXRAND) * 0.02 - 0.01;
1970                 if (rp->VX > 0.06)
1971                         rp->VX = 0.06;
1972                 if (rp->VY > 0.06)
1973                         rp->VY = 0.06;
1974                 if (rp->VX < -0.06)
1975                         rp->VX = -0.06;
1976                 if (rp->VY < -0.06)
1977                         rp->VY = -0.06;
1978         }
1979         if (!MI_IS_ICONIC(mi)) {
1980                 glTranslatef(rp->PX, rp->PY, 0);
1981                 glScalef(Scale4Window * rp->WindH / rp->WindW, Scale4Window, Scale4Window);
1982         } else {
1983                 glScalef(Scale4Iconic * rp->WindH / rp->WindW, Scale4Iconic, Scale4Iconic);
1984         }
1985
1986         glRotatef(rp->step * 100, 1, 0, 0);
1987         glRotatef(rp->step * 95, 0, 1, 0);
1988         glRotatef(rp->step * 90, 0, 0, 1);
1989
1990         if (!draw_cube(mi)) {
1991                 release_rubik(mi);
1992                 return;
1993         }
1994         if (MI_IS_FPS(mi)) do_fps (mi);
1995         glXSwapBuffers(display, window);
1996
1997         if (rp->action == ACTION_SHUFFLE) {
1998                 if (rp->done) {
1999                         if (++rp->rotatestep > DELAY_AFTER_SHUFFLING) {
2000                                 rp->movement.face = NO_FACE;
2001                                 rp->rotatestep = 0;
2002                                 rp->action = ACTION_SOLVE;
2003                                 rp->done = 0;
2004                         }
2005                 } else {
2006                         if (rp->movement.face == NO_FACE) {
2007                                 if (rp->shufflingmoves < rp->storedmoves) {
2008                                         rp->rotatestep = 0;
2009                                         rp->movement = rp->moves[rp->shufflingmoves];
2010                                 } else {
2011                                         rp->rotatestep = 0;
2012                                         rp->done = 1;
2013                                 }
2014                         } else {
2015                                 if (rp->rotatestep == 0) {
2016                                         if (rp->movement.direction == CW || rp->movement.direction == CCW)
2017                                                 rp->degreeTurn = (checkFaceSquare(rp, rp->movement.face)) ? 90 : 180;
2018                                         else
2019                                                 rp->degreeTurn = (checkFaceSquare(rp, rowToRotate[rp->movement.face][rp->movement.direction])) ? 90 : 180;
2020                                 }
2021                                 rp->rotatestep += rp->anglestep;
2022                                 if (rp->rotatestep > rp->degreeTurn) {
2023                                         if (!evalmovement(mi, rp->movement)) {
2024                                                 free_rubik(rp);
2025                                                 if (MI_IS_VERBOSE(mi)) {
2026                                                         (void) fprintf(stderr,
2027                                                                 "Could not allocate memory for rubik\n");
2028                                                 }
2029                                                 return;
2030                                         }
2031                                         rp->shufflingmoves++;
2032                                         rp->movement.face = NO_FACE;
2033                                 }
2034                         }
2035                 }
2036         } else {
2037                 if (rp->done) {
2038                         if (++rp->rotatestep > DELAY_AFTER_SOLVING)
2039                                 if (!shuffle(mi)) {
2040                                         free_rubik(rp);
2041                                         if (MI_IS_VERBOSE(mi)) {
2042                                                 (void) fprintf(stderr,
2043                                                         "Could not allocate memory for rubik\n");
2044                                         }
2045                                         return;
2046                                 }
2047                 } else {
2048                         if (rp->movement.face == NO_FACE) {
2049                                 if (rp->storedmoves > 0) {
2050                                         rp->rotatestep = 0;
2051                                         rp->movement = rp->moves[rp->storedmoves - 1];
2052                                         rp->movement.direction = (rp->movement.direction +
2053                                                 (MAXORIENT / 2)) % MAXORIENT;
2054                                 } else {
2055                                         rp->rotatestep = 0;
2056                                         rp->done = 1;
2057                                 }
2058                         } else {
2059                                 if (rp->rotatestep == 0) {
2060                                         if (rp->movement.direction == CW || rp->movement.direction == CCW)
2061                                                 rp->degreeTurn = (checkFaceSquare(rp, rp->movement.face)) ? 90 : 180;
2062                                         else
2063                                                 rp->degreeTurn = (checkFaceSquare(rp, rowToRotate[rp->movement.face][rp->movement.direction])) ? 90 : 180;
2064                                 }
2065                                 rp->rotatestep += rp->anglestep;
2066                                 if (rp->rotatestep > rp->degreeTurn) {
2067                                         if (!evalmovement(mi, rp->movement)) {
2068                                                 free_rubik(rp);
2069                                                 if (MI_IS_VERBOSE(mi)) {
2070                                                         (void) fprintf(stderr,
2071                                                                 "Could not allocate memory for rubik\n");
2072                                                 }
2073                                                 return;
2074                                         }
2075                                         rp->storedmoves--;
2076                                         rp->movement.face = NO_FACE;
2077                                 }
2078                         }
2079                 }
2080         }
2081
2082         glPopMatrix();
2083
2084         glFlush();
2085
2086         rp->step += 0.05;
2087 }
2088
2089 void
2090 change_rubik(ModeInfo * mi)
2091 {
2092         rubikstruct *rp;
2093
2094         if (rubik == NULL)
2095                 return;
2096         rp = &rubik[MI_SCREEN(mi)];
2097
2098         if (!rp->glx_context)
2099                 return;
2100         if (!pinit(mi)) {
2101                 free_rubik(rp);
2102                 if (MI_IS_VERBOSE(mi)) {
2103                         (void) fprintf(stderr,
2104                                 "Could not allocate memory for rubik\n");
2105                 }
2106                 return;
2107         }
2108 }
2109
2110 #endif