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