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