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