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