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