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