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