http://ftp.x.org/contrib/applications/xscreensaver-2.34.tar.gz
[xscreensaver] / hacks / glx / rubik.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* rubik --- Shows a auto-solving Rubik's cube */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)rubik.c       4.07 97/11/24 xlockmore";
6
7 #endif
8
9 #undef DEBUG_LISTS
10 #undef LMN
11
12 /*-
13  * Permission to use, copy, modify, and distribute this software and its
14  * documentation for any purpose and without fee is hereby granted,
15  * provided that the above copyright notice appear in all copies and that
16  * both that copyright notice and this permission notice appear in
17  * supporting documentation.
18  *
19  * This file is provided AS IS with no warranties of any kind.  The author
20  * shall have no liability with respect to the infringement of copyrights,
21  * trade secrets or any patents by this file or any part thereof.  In no
22  * event will the author be liable for any lost revenue or profits or
23  * other special, indirect and consequential damages.
24  *
25  * This mode shows an auto-solving rubik's cube "puzzle". If somebody
26  * intends to make a game or something based on this code, please let me
27  * know first, my e-mail address is provided in this comment. Marcelo.
28  *
29  * Thanks goes also to Brian Paul for making it possible and inexpensive
30  * to use OpenGL at home.
31  *
32  * Since I'm not a native English speaker, my apologies for any grammatical
33  * mistake.
34  *
35  * My e-mail addresses are
36  * vianna@cat.cbpf.br 
37  *         and
38  * m-vianna@usa.net
39  *
40  * Marcelo F. Vianna (Jul-31-1997)
41  *
42  * Revision History:
43  * 26-Sep-98: Added some more movement (the cube do not stays in the screen
44  *            center anymore. Also fixed the scale problem imediatelly after
45  *            shuffling when the puzzle is solved.
46  * 08-Aug-97: Now has some internals from xrubik by David Bagley
47  *            This should make it easier to add features.
48  * 02-Aug-97: Now behaves more like puzzle.c: first show the cube being
49  *            shuffled and then being solved. A mode specific option was added:
50  *            "+/-hideshuffling" to provide the original behavior (in which
51  *            only the solution is shown).
52  *            The color labels corners are now rounded.
53  *            Optimized the cubit() routine using glLists.
54  * 01-Aug-97: Shuffling now avoids movements that undoes the previous movement
55  *            and three consecutive identical moves (which is 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-97: 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 /*-
69  * Color labels mapping:
70  * =====================
71  *
72  *                       +------------+
73  *                       |0-->        |
74  *                       ||           |
75  *                       |v           |
76  *                       |   TOP(0)   |
77  *                       |            |
78  *                       |            |
79  *                       |           8|
80  *           +-----------+------------+-----------+
81  *           |0-->       |0-->        |0-->       |
82  *           ||          ||           ||          |
83  *           |v          |v           |v          |
84  *           |  LEFT(1)  |  FRONT(2)  |  RIGHT(3) |
85  *           |           |            |           |
86  *           |           |            |           |
87  *           |          8|           8|          8|
88  *           +-----------+------------+-----------+
89  *                       |0-->        |
90  *                       ||           |
91  *                       |v           |
92  *                       |  BOTTOM(4) |  rp->faces[N][X+AVSIZE*Y]=
93  *                       |            |         rp->cubeLoc[N][X+AVSIZE*Y]=
94  *                       |            | 
95  *                       |           8|         +---+---+---+
96  *                       +------------+         |   |   |   |
97  *                       |0-->        |         | 0 | 1 | 2 |
98  *                       ||           |         |---+---+---+
99  *                       |v           |         |  xxxxx(N) |
100  *                       |   BACK(5)  |         | 3 | 4 | 5 |
101  *                       |            |         +---+---+---+
102  *                       |            |         |   |   |  |
103  *                       |           8|         | 6 | 7 | 8 |
104  *                       +------------+         +---+---+---+
105  *
106  *  Map to 3d
107  *  FRONT  => X, Y
108  *  BACK   => X, Y
109  *  LEFT   => Z, Y
110  *  RIGHT  => Z, Y
111  *  TOP    => X, Z
112  *  BOTTOM => X, Z
113  */
114
115 /*-
116  * PURIFY 3.0a on SunOS4 reports an unitialized memory read on each of
117  * the glCallList() functions below when using MesaGL 2.1.  This has
118  * been fixed in MesaGL 2.2 and later releases.
119  */
120
121 /*-
122  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
123  * otherwise caddr_t is not defined correctly
124  */
125 #include <X11/Intrinsic.h>
126
127 #ifdef STANDALONE
128 # define PROGCLASS      "Rubik"
129 # define HACK_INIT      init_rubik
130 # define HACK_DRAW      draw_rubik
131 # define rubik_opts     xlockmore_opts
132 # define DEFAULTS       "*delay: 40000 \n"              \
133                                         "*count: -30 \n"                \
134                                         "*cycles: 5 \n"                 \
135                                         "*size:  -6 \n"
136 # include "xlockmore.h"                         /* from the xscreensaver distribution */
137 #else /* !STANDALONE */
138 # include "xlock.h"                                     /* from the xlockmore distribution */
139 # include "vis.h"
140 #endif /* !STANDALONE */
141
142 #ifdef USE_GL
143
144 #define DEF_HIDESHUFFLING     "False"
145
146 static Bool hideshuffling;
147
148 static XrmOptionDescRec opts[] =
149 {
150   {"-hideshuffling", ".rubik.hideshuffling", XrmoptionNoArg, (caddr_t) "on"},
151   {"+hideshuffling", ".rubik.hideshuffling", XrmoptionNoArg, (caddr_t) "off"}
152 };
153
154 static argtype vars[] =
155 {
156         {(caddr_t *) & hideshuffling, "hideshuffling", "Hideshuffling", DEF_HIDESHUFFLING, t_Bool}
157 };
158
159 static OptionStruct desc[] =
160 {
161         {"-/+hideshuffling", "turn on/off hidden shuffle phase"}
162 };
163
164 ModeSpecOpt rubik_opts =
165 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
166
167 #ifdef USE_MODULES
168 ModStruct   rubik_description =
169 {"rubik", "init_rubik", "draw_rubik", "release_rubik",
170  "draw_rubik", "change_rubik", NULL, &rubik_opts,
171  10000, -30, 5, -6, 4, 1.0, "",
172  "Shows an auto-solving Rubik's Cube", 0, NULL};
173
174 #endif
175
176 #define VectMul(X1,Y1,Z1,X2,Y2,Z2) (Y1)*(Z2)-(Z1)*(Y2),(Z1)*(X2)-(X1)*(Z2),(X1)*(Y2)-(Y1)*(X2)
177 #define sqr(A)                     ((A)*(A))
178
179 #ifndef Pi
180 #define Pi                         M_PI
181 #endif
182
183
184 #define ACTION_SOLVE    1
185 #define ACTION_SHUFFLE  0
186
187 #define DELAY_AFTER_SHUFFLING  5
188 #define DELAY_AFTER_SOLVING   20
189
190 /*************************************************************************/
191
192 #define MINSIZE 2
193 #ifdef LMN                      /* LxMxN not completed yet... */
194 #define MAXSIZEX (rp->sizex)
195 #define MAXSIZEY (rp->sizey)
196 #define MAXSIZEZ (rp->sizez)
197 #define AVSIZE (rp->avsize)
198 #define MAXSIZE (rp->maxsize)
199 #define AVSIZESQ (rp->avsizeSq)
200 #define MAXSIZESQ (rp->maxsizeSq)
201 #else
202 #define MAXSIZEX (rp->size)
203 #define MAXSIZEY (rp->size)
204 #define MAXSIZEZ (rp->size)
205 #define AVSIZE (rp->size)
206 #define MAXSIZE (rp->size)
207 #define AVSIZESQ (rp->sizeSq)
208 #define MAXSIZESQ (rp->sizeSq)
209 #endif
210 #define MAXSIZEXY (MAXSIZEX*MAXSIZEY)
211 #define MAXSIZEZY (MAXSIZEZ*MAXSIZEY)
212 #define MAXSIZEXZ (MAXSIZEX*MAXSIZEZ)
213 #define LASTX (MAXSIZEX-1)
214 #define LASTY (MAXSIZEY-1)
215 #define LASTZ (MAXSIZEZ-1)
216 /* These are not likely to change but... */
217 #define FIRSTX 0
218 #define FIRSTY 0
219 #define FIRSTZ 0
220
221 #define Scale4Window               (0.9/AVSIZE)
222 #define Scale4Iconic               (2.1/AVSIZE)
223
224 #define MAXORIENT 4             /* Number of orientations of a square */
225 #define MAXFACES 6              /* Number of faces */
226
227 /* Directions relative to the face of a cubie */
228 #define TOP 0
229 #define RIGHT 1
230 #define BOTTOM 2
231 #define LEFT 3
232 #define CW (MAXORIENT+1)
233 #define CCW (2*MAXORIENT-1)
234
235 #define TOP_FACE 0
236 #define LEFT_FACE 1
237 #define FRONT_FACE 2
238 #define RIGHT_FACE 3
239 #define BOTTOM_FACE 4
240 #define BACK_FACE 5
241 #define NO_FACE (MAXFACES)
242 #define NO_ROTATION (2*MAXORIENT)
243 #define NO_DEPTH MAXSIZE
244
245 #define REVX(a) (MAXSIZEX - a - 1)
246 #define REVY(a) (MAXSIZEY - a - 1)
247 #define REVZ(a) (MAXSIZEZ - a - 1)
248
249 typedef struct _RubikLoc {
250         int         face;
251         int         rotation;   /* Not used yet */
252 } RubikLoc;
253
254 typedef struct _RubikRowNext {
255         int         face, direction, sideFace;
256 } RubikRowNext;
257
258 typedef struct _RubikMove {
259         int         face, direction;
260         int         position;
261 } RubikMove;
262
263 typedef struct _RubikSlice {
264         int         face, rotation;
265         int         depth;
266 } RubikSlice;
267
268 /*-
269  * Pick a face and a direction on face the next face and orientation
270  * is then known.
271  */
272 static RubikLoc slideNextRow[MAXFACES][MAXORIENT] =
273 {
274         {
275                 {5, TOP},
276                 {3, RIGHT},
277                 {2, TOP},
278                 {1, LEFT}},
279         {
280                 {0, RIGHT},
281                 {2, TOP},
282                 {4, LEFT},
283                 {5, BOTTOM}},
284         {
285                 {0, TOP},
286                 {3, TOP},
287                 {4, TOP},
288                 {1, TOP}},
289         {
290                 {0, LEFT},
291                 {5, BOTTOM},
292                 {4, RIGHT},
293                 {2, TOP}},
294         {
295                 {2, TOP},
296                 {3, LEFT},
297                 {5, TOP},
298                 {1, RIGHT}},
299         {
300                 {4, TOP},
301                 {3, BOTTOM},
302                 {0, TOP},
303                 {1, BOTTOM}}
304 };
305
306 /*-
307  * Examine cubie 0 on each face, its 4 movements (well only 2 since the
308  * other 2 will be opposites) and translate it into slice movements).
309  * Beware.. using this for NxNxN makes some assumptions that referenced
310  * cubes are along the diagonal top-left to bottom-right.
311  * CW = DEEP Depth CCW == SHALLOW Depth with reference to faces 0, 1, and 2
312  */
313 static RubikLoc rotateSlice[MAXFACES][MAXORIENT / 2] =
314 {
315         {
316                 {1, CCW},
317                 {2, CW},
318         },
319         {
320                 {2, CW},
321                 {0, CCW},
322         },
323         {
324                 {1, CCW},
325                 {0, CCW},
326         },
327         {
328                 {2, CCW},
329                 {0, CCW},
330         },
331         {
332                 {1, CCW},
333                 {2, CCW},
334         },
335         {
336                 {1, CCW},
337                 {0, CW},
338         }
339 };
340
341 /*-
342  * Rotate face clockwise by a number of orients, then the top of the
343  * face then points to this face
344  */
345 static int  rowToRotate[MAXFACES][MAXORIENT] =
346 {
347         {3, 2, 1, 5},
348         {2, 4, 5, 0},
349         {3, 4, 1, 0},
350         {5, 4, 2, 0},
351         {3, 5, 1, 2},
352         {3, 0, 1, 4}
353 };
354
355 /* 
356  * This translates a clockwise move to something more manageable
357  */
358 static RubikRowNext rotateToRow[MAXFACES] =     /*CW to min face */
359 {
360         {1, LEFT, TOP},
361         {0, BOTTOM, LEFT},
362         {0, RIGHT, BOTTOM},
363         {0, TOP, RIGHT},
364         {1, RIGHT, BOTTOM},
365         {0, LEFT, TOP}
366 };
367
368 typedef struct {
369         GLint       WindH, WindW;
370         GLfloat     step;
371         RubikMove  *moves;
372         int         storedmoves;
373         int         shufflingmoves;
374 #ifdef LMN                      /* Under construction */
375         int         sizex, sizey, sizez;
376         int         avsize, maxsize;
377         int         avsizeSq, maxsizeSq;
378 #else
379         int         size, sizeSq;
380 #endif
381         int         action;
382         int         done;
383         GLfloat     anglestep;
384         RubikLoc   *cubeLoc[MAXFACES];
385         RubikLoc   *rowLoc[MAXORIENT];
386         RubikMove   movement;
387         GLfloat     rotatestep;
388         GLfloat     PX, PY, VX, VY;
389         GLXContext *glx_context;
390         int         AreObjectsDefined[1];
391 } rubikstruct;
392
393 static float front_shininess[] =
394 {60.0};
395 static float front_specular[] =
396 {0.7, 0.7, 0.7, 1.0};
397 static float ambient[] =
398 {0.0, 0.0, 0.0, 1.0};
399 static float diffuse[] =
400 {1.0, 1.0, 1.0, 1.0};
401 static float position0[] =
402 {1.0, 1.0, 1.0, 0.0};
403 static float position1[] =
404 {-1.0, -1.0, 1.0, 0.0};
405 static float lmodel_ambient[] =
406 {0.5, 0.5, 0.5, 1.0};
407 static float lmodel_twoside[] =
408 {GL_TRUE};
409
410 static float MaterialRed[] =
411 {0.5, 0.0, 0.0, 1.0};
412 static float MaterialGreen[] =
413 {0.0, 0.5, 0.0, 1.0};
414 static float MaterialBlue[] =
415 {0.0, 0.0, 0.5, 1.0};
416 static float MaterialYellow[] =
417 {0.7, 0.7, 0.0, 1.0};
418 static float MaterialOrange[] =
419 {0.9, 0.45, 0.36, 1.0};
420
421 #if 0
422 static float MaterialMagenta[] =
423 {0.7, 0.0, 0.7, 1.0};
424 static float MaterialCyan[] =
425 {0.0, 0.7, 0.7, 1.0};
426
427 #endif
428 static float MaterialWhite[] =
429 {0.8, 0.8, 0.8, 1.0};
430 static float MaterialGray[] =
431 {0.2, 0.2, 0.2, 1.0};
432 static float MaterialGray3[] =
433 {0.3, 0.3, 0.3, 1.0};
434 static float MaterialGray4[] =
435 {0.4, 0.4, 0.4, 1.0};
436 static float MaterialGray5[] =
437 {0.5, 0.5, 0.5, 1.0};
438 static float MaterialGray6[] =
439 {0.6, 0.6, 0.6, 1.0};
440 static float MaterialGray7[] =
441 {0.7, 0.7, 0.7, 1.0};
442
443 static rubikstruct *rubik = NULL;
444 static GLuint objects;
445
446 #define ObjCubit        0
447
448 static void
449 pickcolor(int C, int mono)
450 {
451         switch (C) {
452                 case TOP_FACE:
453                         if (mono)
454                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray3);
455                         else
456                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
457                         break;
458                 case LEFT_FACE:
459                         if (mono)
460                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray6);
461                         else
462                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
463                         break;
464                 case FRONT_FACE:
465                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
466                         break;
467                 case RIGHT_FACE:
468                         if (mono)
469                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray4);
470                         else
471                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGreen);
472                         break;
473                 case BOTTOM_FACE:
474                         if (mono)
475                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray7);
476                         else
477                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialOrange);
478                         break;
479                 case BACK_FACE:
480                         if (mono)
481                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
482                         else
483                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
484                         break;
485 #if 0
486                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialCyan);
487                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialMagenta);
488 #endif
489         }
490 }
491
492
493 static void
494 draw_cubit(ModeInfo * mi,
495            int back, int front, int left, int right, int bottom, int top)
496 {
497         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
498         int         mono = MI_IS_MONO(mi);
499
500         if (!rp->AreObjectsDefined[ObjCubit]) {
501                 glNewList(objects + ObjCubit, GL_COMPILE_AND_EXECUTE);
502                 glBegin(GL_QUADS);
503                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
504                 glNormal3f(0.00, 0.00, 1.00);
505                 glVertex3f(-0.45, -0.45, 0.50);
506                 glVertex3f(0.45, -0.45, 0.50);
507                 glVertex3f(0.45, 0.45, 0.50);
508                 glVertex3f(-0.45, 0.45, 0.50);
509                 glNormal3f(0.00, 0.00, -1.00);
510                 glVertex3f(-0.45, 0.45, -0.50);
511                 glVertex3f(0.45, 0.45, -0.50);
512                 glVertex3f(0.45, -0.45, -0.50);
513                 glVertex3f(-0.45, -0.45, -0.50);
514                 glNormal3f(-1.00, 0.00, 0.00);
515                 glVertex3f(-0.50, -0.45, 0.45);
516                 glVertex3f(-0.50, 0.45, 0.45);
517                 glVertex3f(-0.50, 0.45, -0.45);
518                 glVertex3f(-0.50, -0.45, -0.45);
519                 glNormal3f(1.00, 0.00, 0.00);
520                 glVertex3f(0.50, -0.45, -0.45);
521                 glVertex3f(0.50, 0.45, -0.45);
522                 glVertex3f(0.50, 0.45, 0.45);
523                 glVertex3f(0.50, -0.45, 0.45);
524                 glNormal3f(0.00, -1.00, 0.00);
525                 glVertex3f(0.45, -0.50, -0.45);
526                 glVertex3f(0.45, -0.50, 0.45);
527                 glVertex3f(-0.45, -0.50, 0.45);
528                 glVertex3f(-0.45, -0.50, -0.45);
529                 glNormal3f(0.00, 1.00, 0.00);
530                 glVertex3f(-0.45, 0.50, -0.45);
531                 glVertex3f(-0.45, 0.50, 0.45);
532                 glVertex3f(0.45, 0.50, 0.45);
533                 glVertex3f(0.45, 0.50, -0.45);
534                 glNormal3f(-1.00, -1.00, 0.00);
535                 glVertex3f(-0.45, -0.50, -0.45);
536                 glVertex3f(-0.45, -0.50, 0.45);
537                 glVertex3f(-0.50, -0.45, 0.45);
538                 glVertex3f(-0.50, -0.45, -0.45);
539                 glNormal3f(1.00, 1.00, 0.00);
540                 glVertex3f(0.45, 0.50, -0.45);
541                 glVertex3f(0.45, 0.50, 0.45);
542                 glVertex3f(0.50, 0.45, 0.45);
543                 glVertex3f(0.50, 0.45, -0.45);
544                 glNormal3f(-1.00, 1.00, 0.00);
545                 glVertex3f(-0.50, 0.45, -0.45);
546                 glVertex3f(-0.50, 0.45, 0.45);
547                 glVertex3f(-0.45, 0.50, 0.45);
548                 glVertex3f(-0.45, 0.50, -0.45);
549                 glNormal3f(1.00, -1.00, 0.00);
550                 glVertex3f(0.50, -0.45, -0.45);
551                 glVertex3f(0.50, -0.45, 0.45);
552                 glVertex3f(0.45, -0.50, 0.45);
553                 glVertex3f(0.45, -0.50, -0.45);
554                 glNormal3f(0.00, -1.00, -1.00);
555                 glVertex3f(-0.45, -0.45, -0.50);
556                 glVertex3f(0.45, -0.45, -0.50);
557                 glVertex3f(0.45, -0.50, -0.45);
558                 glVertex3f(-0.45, -0.50, -0.45);
559                 glNormal3f(0.00, 1.00, 1.00);
560                 glVertex3f(-0.45, 0.45, 0.50);
561                 glVertex3f(0.45, 0.45, 0.50);
562                 glVertex3f(0.45, 0.50, 0.45);
563                 glVertex3f(-0.45, 0.50, 0.45);
564                 glNormal3f(0.00, -1.00, 1.00);
565                 glVertex3f(-0.45, -0.50, 0.45);
566                 glVertex3f(0.45, -0.50, 0.45);
567                 glVertex3f(0.45, -0.45, 0.50);
568                 glVertex3f(-0.45, -0.45, 0.50);
569                 glNormal3f(0.00, 1.00, -1.00);
570                 glVertex3f(-0.45, 0.50, -0.45);
571                 glVertex3f(0.45, 0.50, -0.45);
572                 glVertex3f(0.45, 0.45, -0.50);
573                 glVertex3f(-0.45, 0.45, -0.50);
574                 glNormal3f(-1.00, 0.00, -1.00);
575                 glVertex3f(-0.50, -0.45, -0.45);
576                 glVertex3f(-0.50, 0.45, -0.45);
577                 glVertex3f(-0.45, 0.45, -0.50);
578                 glVertex3f(-0.45, -0.45, -0.50);
579                 glNormal3f(1.00, 0.00, 1.00);
580                 glVertex3f(0.50, -0.45, 0.45);
581                 glVertex3f(0.50, 0.45, 0.45);
582                 glVertex3f(0.45, 0.45, 0.50);
583                 glVertex3f(0.45, -0.45, 0.50);
584                 glNormal3f(1.00, 0.00, -1.00);
585                 glVertex3f(0.45, -0.45, -0.50);
586                 glVertex3f(0.45, 0.45, -0.50);
587                 glVertex3f(0.50, 0.45, -0.45);
588                 glVertex3f(0.50, -0.45, -0.45);
589                 glNormal3f(-1.00, 0.00, 1.00);
590                 glVertex3f(-0.45, -0.45, 0.50);
591                 glVertex3f(-0.45, 0.45, 0.50);
592                 glVertex3f(-0.50, 0.45, 0.45);
593                 glVertex3f(-0.50, -0.45, 0.45);
594                 glEnd();
595                 glBegin(GL_TRIANGLES);
596                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
597                 glNormal3f(1.00, 1.00, 1.00);
598                 glVertex3f(0.45, 0.45, 0.50);
599                 glVertex3f(0.50, 0.45, 0.45);
600                 glVertex3f(0.45, 0.50, 0.45);
601                 glNormal3f(-1.00, -1.00, -1.00);
602                 glVertex3f(-0.45, -0.50, -0.45);
603                 glVertex3f(-0.50, -0.45, -0.45);
604                 glVertex3f(-0.45, -0.45, -0.50);
605                 glNormal3f(-1.00, 1.00, 1.00);
606                 glVertex3f(-0.45, 0.45, 0.50);
607                 glVertex3f(-0.45, 0.50, 0.45);
608                 glVertex3f(-0.50, 0.45, 0.45);
609                 glNormal3f(1.00, -1.00, -1.00);
610                 glVertex3f(0.50, -0.45, -0.45);
611                 glVertex3f(0.45, -0.50, -0.45);
612                 glVertex3f(0.45, -0.45, -0.50);
613                 glNormal3f(1.00, -1.00, 1.00);
614                 glVertex3f(0.45, -0.45, 0.50);
615                 glVertex3f(0.45, -0.50, 0.45);
616                 glVertex3f(0.50, -0.45, 0.45);
617                 glNormal3f(-1.00, 1.00, -1.00);
618                 glVertex3f(-0.50, 0.45, -0.45);
619                 glVertex3f(-0.45, 0.50, -0.45);
620                 glVertex3f(-0.45, 0.45, -0.50);
621                 glNormal3f(-1.00, -1.00, 1.00);
622                 glVertex3f(-0.45, -0.45, 0.50);
623                 glVertex3f(-0.50, -0.45, 0.45);
624                 glVertex3f(-0.45, -0.50, 0.45);
625                 glNormal3f(1.00, 1.00, -1.00);
626                 glVertex3f(0.50, 0.45, -0.45);
627                 glVertex3f(0.45, 0.45, -0.50);
628                 glVertex3f(0.45, 0.50, -0.45);
629                 glEnd();
630                 glEndList();
631                 rp->AreObjectsDefined[ObjCubit] = 1;
632 #ifdef DEBUG_LISTS
633                 (void) printf("Cubit drawn SLOWLY\n");
634 #endif
635         } else {
636                 glCallList(objects + ObjCubit);
637 #ifdef DEBUG_LISTS
638                 (void) printf("Cubit drawn quickly\n");
639 #endif
640         }
641
642         if (back != NO_FACE) {
643                 glBegin(GL_POLYGON);
644                 pickcolor(back, mono);
645                 glNormal3f(0.00, 0.00, -1.00);
646                 glVertex3f(-0.35, 0.40, -0.51);
647                 glVertex3f(0.35, 0.40, -0.51);
648                 glVertex3f(0.40, 0.35, -0.51);
649                 glVertex3f(0.40, -0.35, -0.51);
650                 glVertex3f(0.35, -0.40, -0.51);
651                 glVertex3f(-0.35, -0.40, -0.51);
652                 glVertex3f(-0.40, -0.35, -0.51);
653                 glVertex3f(-0.40, 0.35, -0.51);
654                 glEnd();
655         }
656         if (front != NO_FACE) {
657                 glBegin(GL_POLYGON);
658                 pickcolor(front, mono);
659                 glNormal3f(0.00, 0.00, 1.00);
660                 glVertex3f(-0.35, -0.40, 0.51);
661                 glVertex3f(0.35, -0.40, 0.51);
662                 glVertex3f(0.40, -0.35, 0.51);
663                 glVertex3f(0.40, 0.35, 0.51);
664                 glVertex3f(0.35, 0.40, 0.51);
665                 glVertex3f(-0.35, 0.40, 0.51);
666                 glVertex3f(-0.40, 0.35, 0.51);
667                 glVertex3f(-0.40, -0.35, 0.51);
668                 glEnd();
669         }
670         if (left != NO_FACE) {
671                 glBegin(GL_POLYGON);
672                 pickcolor(left, mono);
673                 glNormal3f(-1.00, 0.00, 0.00);
674                 glVertex3f(-0.51, -0.35, 0.40);
675                 glVertex3f(-0.51, 0.35, 0.40);
676                 glVertex3f(-0.51, 0.40, 0.35);
677                 glVertex3f(-0.51, 0.40, -0.35);
678                 glVertex3f(-0.51, 0.35, -0.40);
679                 glVertex3f(-0.51, -0.35, -0.40);
680                 glVertex3f(-0.51, -0.40, -0.35);
681                 glVertex3f(-0.51, -0.40, 0.35);
682                 glEnd();
683         }
684         if (right != NO_FACE) {
685                 glBegin(GL_POLYGON);
686                 pickcolor(right, mono);
687                 glNormal3f(1.00, 0.00, 0.00);
688                 glVertex3f(0.51, -0.35, -0.40);
689                 glVertex3f(0.51, 0.35, -0.40);
690                 glVertex3f(0.51, 0.40, -0.35);
691                 glVertex3f(0.51, 0.40, 0.35);
692                 glVertex3f(0.51, 0.35, 0.40);
693                 glVertex3f(0.51, -0.35, 0.40);
694                 glVertex3f(0.51, -0.40, 0.35);
695                 glVertex3f(0.51, -0.40, -0.35);
696                 glEnd();
697         }
698         if (bottom != NO_FACE) {
699                 glBegin(GL_POLYGON);
700                 pickcolor(bottom, mono);
701                 glNormal3f(0.00, -1.00, 0.00);
702                 glVertex3f(0.40, -0.51, -0.35);
703                 glVertex3f(0.40, -0.51, 0.35);
704                 glVertex3f(0.35, -0.51, 0.40);
705                 glVertex3f(-0.35, -0.51, 0.40);
706                 glVertex3f(-0.40, -0.51, 0.35);
707                 glVertex3f(-0.40, -0.51, -0.35);
708                 glVertex3f(-0.35, -0.51, -0.40);
709                 glVertex3f(0.35, -0.51, -0.40);
710                 glEnd();
711         }
712         if (top != NO_FACE) {
713                 glBegin(GL_POLYGON);
714                 pickcolor(top, mono);
715                 glNormal3f(0.00, 1.00, 0.00);
716                 glVertex3f(-0.40, 0.51, -0.35);
717                 glVertex3f(-0.40, 0.51, 0.35);
718                 glVertex3f(-0.35, 0.51, 0.40);
719                 glVertex3f(0.35, 0.51, 0.40);
720                 glVertex3f(0.40, 0.51, 0.35);
721                 glVertex3f(0.40, 0.51, -0.35);
722                 glVertex3f(0.35, 0.51, -0.40);
723                 glVertex3f(-0.35, 0.51, -0.40);
724                 glEnd();
725         }
726 }
727
728
729 static      RubikSlice
730 convertMove(rubikstruct * rp, RubikMove move)
731 {
732         RubikSlice  slice;
733         RubikLoc    plane;
734
735         plane = rotateSlice[(int) move.face][move.direction % 2];
736         slice.face = plane.face;
737         slice.rotation = plane.rotation;
738         if (slice.rotation == CW)       /* I just know this to be true... */
739                 slice.depth = AVSIZESQ - 1 - move.position;
740         else
741                 slice.depth = move.position;
742         slice.depth = slice.depth / AVSIZE;
743         /* If slice.depth = 0 then face 0, face 1, or face 2 moves */
744         if (move.direction / 2)
745                 slice.rotation = (plane.rotation == CW) ? CCW : CW;
746         return slice;
747 }
748
749 /* Assume for the moment that the size is at least 2 */
750 static void
751 draw_cube(ModeInfo * mi)
752 {
753 #define S1 1
754 #define SX ((GLint)S1*(MAXSIZEX-1))
755 #define SY ((GLint)S1*(MAXSIZEY-1))
756 #define SZ ((GLint)S1*(MAXSIZEZ-1))
757 #define HALFX (((GLfloat)MAXSIZEX-1.0)/2.0)
758 #define HALFY (((GLfloat)MAXSIZEY-1.0)/2.0)
759 #define HALFZ (((GLfloat)MAXSIZEZ-1.0)/2.0)
760 #define MIDX(a) (((GLfloat)(2*a-MAXSIZEX+1))/2.0)
761 #define MIDY(a) (((GLfloat)(2*a-MAXSIZEY+1))/2.0)
762 #define MIDZ(a) (((GLfloat)(2*a-MAXSIZEZ+1))/2.0)
763         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
764         RubikSlice  slice;
765         GLfloat     rotatestep;
766         int         i, j, k;
767
768         if (rp->movement.face == NO_FACE) {
769                 slice.face = NO_FACE;
770                 slice.rotation = NO_ROTATION;
771                 slice.depth = NO_DEPTH;
772         } else {
773                 slice = convertMove(rp, rp->movement);
774         }
775         rotatestep = (slice.rotation == CCW) ? rp->rotatestep : -rp->rotatestep;
776
777 /*-
778  * The glRotatef() routine transforms the coordinate system for every future
779  * vertex specification (this is not so simple, but by now comprehending this
780  * is sufficient). So if you want to rotate the inner slice, you can draw
781  * one slice, rotate the anglestep for the centerslice, draw the inner slice,
782  * rotate reversely and draw the other slice.
783  * There is a sequence for drawing cubies for each axis being moved...
784  */
785         switch (slice.face) {
786                 case NO_FACE:
787                 case TOP_FACE:  /* BOTTOM_FACE too */
788                         glPushMatrix();
789                         if (slice.depth == MAXSIZEY - 1)
790                                 glRotatef(rotatestep, 0, HALFY, 0);
791
792                         glTranslatef(-HALFX, -HALFY, -HALFZ);
793                         draw_cubit(mi,
794                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
795                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
796                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
797                         for (k = 1; k < MAXSIZEZ - 1; k++) {
798                                 glTranslatef(0, 0, S1);
799                                 draw_cubit(mi,
800                                            NO_FACE, NO_FACE,
801                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
802                                            rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
803                         }
804                         glTranslatef(0, 0, S1);
805                         draw_cubit(mi,
806                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
807                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
808                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
809                         for (i = 1; i < MAXSIZEX - 1; i++) {
810                                 glTranslatef(S1, 0, -SZ);
811                                 draw_cubit(mi,
812                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
813                                            NO_FACE, NO_FACE,
814                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
815                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
816                                         glTranslatef(0, 0, S1);
817                                         draw_cubit(mi,
818                                                    NO_FACE, NO_FACE,
819                                                    NO_FACE, NO_FACE,
820                                                    rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
821                                 }
822                                 glTranslatef(0, 0, S1);
823                                 draw_cubit(mi,
824                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
825                                            NO_FACE, NO_FACE,
826                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
827                         }
828                         glTranslatef(1, 0, -SZ);
829                         draw_cubit(mi,
830                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
831                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
832                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
833                         for (k = 1; k < MAXSIZEZ - 1; k++) {
834                                 glTranslatef(0, 0, S1);
835                                 draw_cubit(mi,
836                                            NO_FACE, NO_FACE,
837                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
838                                            rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
839                         }
840                         glTranslatef(0, 0, S1);
841                         draw_cubit(mi,
842                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
843                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
844                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
845                         glPopMatrix();
846                         for (j = 1; j < MAXSIZEY - 1; j++) {
847                                 glPushMatrix();
848                                 if (slice.depth == REVY(j))
849                                         glRotatef(rotatestep, 0, HALFY, 0);
850                                 glTranslatef(-HALFX, MIDY(j), -HALFZ);
851                                 draw_cubit(mi,
852                                            rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
853                                            rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
854                                            NO_FACE, NO_FACE);
855                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
856                                         glTranslatef(0, 0, S1);
857                                         draw_cubit(mi,
858                                                    NO_FACE, NO_FACE,
859                                                    rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
860                                                    NO_FACE, NO_FACE);
861                                 }
862                                 glTranslatef(0, 0, S1);
863                                 draw_cubit(mi,
864                                            NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
865                                            rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
866                                            NO_FACE, NO_FACE);
867                                 for (i = 1; i < MAXSIZEX - 1; i++) {
868                                         glTranslatef(1, 0, -SZ);
869                                         draw_cubit(mi,
870                                                    rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
871                                                    NO_FACE, NO_FACE,
872                                                    NO_FACE, NO_FACE);
873                                         /* Center */
874                                         glTranslatef(0, 0, SZ);
875                                         draw_cubit(mi,
876                                                    NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
877                                                    NO_FACE, NO_FACE,
878                                                    NO_FACE, NO_FACE);
879                                 }
880                                 glTranslatef(S1, 0, -SZ);
881                                 draw_cubit(mi,
882                                            rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
883                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
884                                            NO_FACE, NO_FACE);
885                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
886                                         glTranslatef(0, 0, S1);
887                                         draw_cubit(mi,
888                                                    NO_FACE, NO_FACE,
889                                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
890                                                    NO_FACE, NO_FACE);
891                                 }
892                                 glTranslatef(0, 0, S1);
893                                 draw_cubit(mi,
894                                            NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
895                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
896                                            NO_FACE, NO_FACE);
897                                 glPopMatrix();
898                         }
899                         if (slice.depth == 0)
900                                 glRotatef(rotatestep, 0, HALFY, 0);
901
902                         glTranslatef(-HALFX, HALFY, -HALFZ);
903                         draw_cubit(mi,
904                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
905                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
906                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
907                         for (k = 1; k < MAXSIZEZ - 1; k++) {
908                                 glTranslatef(0, 0, S1);
909                                 draw_cubit(mi,
910                                            NO_FACE, NO_FACE,
911                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
912                                            NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
913                         }
914                         glTranslatef(0, 0, S1);
915                         draw_cubit(mi,
916                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
917                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
918                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
919                         for (i = 1; i < MAXSIZEX - 1; i++) {
920                                 glTranslatef(S1, 0, -SZ);
921                                 draw_cubit(mi,
922                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
923                                            NO_FACE, NO_FACE,
924                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
925                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
926                                         glTranslatef(0, 0, S1);
927                                         draw_cubit(mi,
928                                                    NO_FACE, NO_FACE,
929                                                    NO_FACE, NO_FACE,
930                                                    NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
931                                 }
932                                 glTranslatef(0, 0, S1);
933                                 draw_cubit(mi,
934                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
935                                            NO_FACE, NO_FACE,
936                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
937                         }
938                         glTranslatef(S1, 0, -SZ);
939                         draw_cubit(mi,
940                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
941                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
942                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
943                         for (k = 1; k < MAXSIZEZ - 1; k++) {
944                                 glTranslatef(0, 0, S1);
945                                 draw_cubit(mi,
946                                            NO_FACE, NO_FACE,
947                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
948                                            NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
949                         }
950                         glTranslatef(0, 0, S1);
951                         draw_cubit(mi,
952                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
953                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
954                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
955                         break;
956                 case LEFT_FACE: /* RIGHT_FACE too */
957                         /* rotatestep is negative because the RIGHT face is the default here */
958                         glPushMatrix();
959                         if (slice.depth == 0)
960                                 glRotatef(-rotatestep, HALFX, 0, 0);
961
962                         glTranslatef(-HALFX, -HALFY, -HALFZ);
963                         draw_cubit(mi,
964                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
965                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
966                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
967                         for (j = 1; j < MAXSIZEY - 1; j++) {
968                                 glTranslatef(0, S1, 0);
969                                 draw_cubit(mi,
970                                            rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
971                                            rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
972                                            NO_FACE, NO_FACE);
973                         }
974                         glTranslatef(0, S1, 0);
975                         draw_cubit(mi,
976                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
977                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
978                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
979                         for (k = 1; k < MAXSIZEZ - 1; k++) {
980                                 glTranslatef(0, -SY, S1);
981                                 draw_cubit(mi,
982                                            NO_FACE, NO_FACE,
983                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
984                                            rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
985                                 for (j = 1; j < MAXSIZEY - 1; j++) {
986                                         glTranslatef(0, S1, 0);
987                                         draw_cubit(mi,
988                                                    NO_FACE, NO_FACE,
989                                                    rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
990                                                    NO_FACE, NO_FACE);
991                                 }
992                                 glTranslatef(0, S1, 0);
993                                 draw_cubit(mi,
994                                            NO_FACE, NO_FACE,
995                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
996                                            NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
997                         }
998                         glTranslatef(0, -SY, S1);
999                         draw_cubit(mi,
1000                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1001                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1002                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1003                         for (j = 1; j < MAXSIZEY - 1; j++) {
1004                                 glTranslatef(0, S1, 0);
1005                                 draw_cubit(mi,
1006                                            NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1007                                            rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1008                                            NO_FACE, NO_FACE);
1009                         }
1010                         glTranslatef(0, S1, 0);
1011                         draw_cubit(mi,
1012                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1013                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1014                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1015                         glPopMatrix();
1016                         for (i = 1; i < MAXSIZEX - 1; i++) {
1017                                 glPushMatrix();
1018                                 if (slice.depth == i)
1019                                         glRotatef(-rotatestep, HALFX, 0, 0);
1020                                 glTranslatef(MIDX(i), -HALFY, -HALFZ);
1021                                 draw_cubit(mi,
1022                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1023                                            NO_FACE, NO_FACE,
1024                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1025                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1026                                         glTranslatef(0, S1, 0);
1027                                         draw_cubit(mi,
1028                                                    rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1029                                                    NO_FACE, NO_FACE,
1030                                                    NO_FACE, NO_FACE);
1031                                 }
1032                                 glTranslatef(0, S1, 0);
1033                                 draw_cubit(mi,
1034                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1035                                            NO_FACE, NO_FACE,
1036                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1037                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
1038                                         glTranslatef(0, -SY, S1);
1039                                         draw_cubit(mi,
1040                                                    NO_FACE, NO_FACE,
1041                                                    NO_FACE, NO_FACE,
1042                                                    rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1043                                         /* Center */
1044                                         glTranslatef(0, SY, 0);
1045                                         draw_cubit(mi,
1046                                                    NO_FACE, NO_FACE,
1047                                                    NO_FACE, NO_FACE,
1048                                                    NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1049                                 }
1050                                 glTranslatef(0, -SY, S1);
1051                                 draw_cubit(mi,
1052                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1053                                            NO_FACE, NO_FACE,
1054                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1055                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1056                                         glTranslatef(0, S1, 0);
1057                                         draw_cubit(mi,
1058                                                    NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1059                                                    NO_FACE, NO_FACE,
1060                                                    NO_FACE, NO_FACE);
1061                                 }
1062                                 glTranslatef(0, S1, 0);
1063                                 draw_cubit(mi,
1064                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1065                                            NO_FACE, NO_FACE,
1066                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1067                                 glPopMatrix();
1068                         }
1069                         if (slice.depth == MAXSIZEX - 1)
1070                                 glRotatef(-rotatestep, HALFX, 0, 0);
1071                         glTranslatef(HALFX, -HALFY, -HALFZ);
1072                         draw_cubit(mi,
1073                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1074                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1075                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1076                         for (j = 1; j < MAXSIZEY - 1; j++) {
1077                                 glTranslatef(0, S1, 0);
1078                                 draw_cubit(mi,
1079                                            rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1080                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1081                                            NO_FACE, NO_FACE);
1082                         }
1083                         glTranslatef(0, S1, 0);
1084                         draw_cubit(mi,
1085                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1086                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1087                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1088                         for (k = 1; k < MAXSIZEZ - 1; k++) {
1089                                 glTranslatef(0, -SY, S1);
1090                                 draw_cubit(mi,
1091                                            NO_FACE, NO_FACE,
1092                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1093                                            rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1094                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1095                                         glTranslatef(0, S1, 0);
1096                                         draw_cubit(mi,
1097                                                    NO_FACE, NO_FACE,
1098                                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1099                                                    NO_FACE, NO_FACE);
1100                                 }
1101                                 glTranslatef(0, S1, 0);
1102                                 draw_cubit(mi,
1103                                            NO_FACE, NO_FACE,
1104                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1105                                            NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1106                         }
1107                         glTranslatef(0, -SY, S1);
1108                         draw_cubit(mi,
1109                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1110                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1111                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1112                         for (j = 1; j < MAXSIZEY - 1; j++) {
1113                                 glTranslatef(0, S1, 0);
1114                                 draw_cubit(mi,
1115                                            NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1116                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1117                                            NO_FACE, NO_FACE);
1118                         }
1119                         glTranslatef(0, S1, 0);
1120                         draw_cubit(mi,
1121                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1122                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1123                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1124                         break;
1125                 case FRONT_FACE:        /* BACK_FACE too */
1126                         glPushMatrix();
1127                         if (slice.depth == MAXSIZEZ - 1)
1128                                 glRotatef(rotatestep, 0, 0, HALFZ);
1129
1130                         glTranslatef(-HALFX, -HALFY, -HALFZ);
1131                         draw_cubit(mi,
1132                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1133                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1134                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
1135                         for (i = 1; i < MAXSIZEX - 1; i++) {
1136                                 glTranslatef(S1, 0, 0);
1137                                 draw_cubit(mi,
1138                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1139                                            NO_FACE, NO_FACE,
1140                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1141                         }
1142                         glTranslatef(S1, 0, 0);
1143                         draw_cubit(mi,
1144                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1145                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1146                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1147                         for (j = 1; j < MAXSIZEY - 1; j++) {
1148                                 glTranslatef(-SX, S1, 0);
1149                                 draw_cubit(mi,
1150                                            rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
1151                                            rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1152                                            NO_FACE, NO_FACE);
1153                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1154                                         glTranslatef(S1, 0, 0);
1155                                         draw_cubit(mi,
1156                                                    rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1157                                                    NO_FACE, NO_FACE,
1158                                                    NO_FACE, NO_FACE);
1159                                 }
1160                                 glTranslatef(S1, 0, 0);
1161                                 draw_cubit(mi,
1162                                            rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1163                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1164                                            NO_FACE, NO_FACE);
1165                         }
1166                         glTranslatef(-SX, S1, 0);
1167                         draw_cubit(mi,
1168                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
1169                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1170                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
1171                         for (i = 1; i < MAXSIZEX - 1; i++) {
1172                                 glTranslatef(S1, 0, 0);
1173                                 draw_cubit(mi,
1174                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1175                                            NO_FACE, NO_FACE,
1176                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1177                         }
1178                         glTranslatef(S1, 0, 0);
1179                         draw_cubit(mi,
1180                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1181                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1182                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1183                         glPopMatrix();
1184                         for (k = 1; k < MAXSIZEZ - 1; k++) {
1185                                 glPushMatrix();
1186                                 if (slice.depth == REVZ(k))
1187                                         glRotatef(rotatestep, 0, 0, HALFZ);
1188                                 glTranslatef(-HALFX, -HALFY, MIDZ(k));
1189                                 draw_cubit(mi,
1190                                            NO_FACE, NO_FACE,
1191                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
1192                                            rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1193                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1194                                         glTranslatef(S1, 0, 0);
1195                                         draw_cubit(mi,
1196                                                    NO_FACE, NO_FACE,
1197                                                    NO_FACE, NO_FACE,
1198                                                    rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1199                                 }
1200                                 glTranslatef(S1, 0, 0);
1201                                 draw_cubit(mi,
1202                                            NO_FACE, NO_FACE,
1203                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1204                                            rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1205                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1206                                         glTranslatef(-SX, S1, 0);
1207                                         draw_cubit(mi,
1208                                                    NO_FACE, NO_FACE,
1209                                                    rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
1210                                                    NO_FACE, NO_FACE);
1211                                         /* Center */
1212                                         glTranslatef(SX, 0, 0);
1213                                         draw_cubit(mi,
1214                                                    NO_FACE, NO_FACE,
1215                                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1216                                                    NO_FACE, NO_FACE);
1217                                 }
1218                                 glTranslatef(-SX, S1, 0);
1219                                 draw_cubit(mi,
1220                                            NO_FACE, NO_FACE,
1221                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
1222                                            NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
1223                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1224                                         glTranslatef(S1, 0, 0);
1225                                         draw_cubit(mi,
1226                                                    NO_FACE, NO_FACE,
1227                                                    NO_FACE, NO_FACE,
1228                                                    NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1229                                 }
1230                                 glTranslatef(S1, 0, 0);
1231                                 draw_cubit(mi,
1232                                            NO_FACE, NO_FACE,
1233                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1234                                            NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1235                                 glPopMatrix();
1236                         }
1237                         if (slice.depth == 0)
1238                                 glRotatef(rotatestep, 0, 0, HALFZ);
1239                         glTranslatef(-HALFX, -HALFY, HALFZ);
1240                         draw_cubit(mi,
1241                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1242                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1243                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1244                         for (i = 1; i < MAXSIZEX - 1; i++) {
1245                                 glTranslatef(S1, 0, 0);
1246                                 draw_cubit(mi,
1247                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1248                                            NO_FACE, NO_FACE,
1249                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1250                         }
1251                         glTranslatef(S1, 0, 0);
1252                         draw_cubit(mi,
1253                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1254                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1255                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1256                         for (j = 1; j < MAXSIZEY - 1; j++) {
1257                                 glTranslatef(-SX, S1, 0);
1258                                 draw_cubit(mi,
1259                                            NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1260                                            rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1261                                            NO_FACE, NO_FACE);
1262                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1263                                         glTranslatef(S1, 0, 0);
1264                                         draw_cubit(mi,
1265                                                    NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1266                                                    NO_FACE, NO_FACE,
1267                                                    NO_FACE, NO_FACE);
1268                                 }
1269                                 glTranslatef(S1, 0, 0);
1270                                 draw_cubit(mi,
1271                                            NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1272                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1273                                            NO_FACE, NO_FACE);
1274                         }
1275                         glTranslatef(-SX, S1, 0);
1276                         draw_cubit(mi,
1277                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1278                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1279                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1280                         for (i = 1; i < MAXSIZEX - 1; i++) {
1281                                 glTranslatef(S1, 0, 0);
1282                                 draw_cubit(mi,
1283                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1284                                            NO_FACE, NO_FACE,
1285                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1286                         }
1287                         glTranslatef(S1, 0, 0);
1288                         draw_cubit(mi,
1289                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1290                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1291                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1292                         break;
1293         }
1294 #undef S1
1295 }
1296
1297 /* From David Bagley's xrubik.  Used by permission. ;)  */
1298 static void
1299 readRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1300 {
1301         int         g;
1302
1303         if (dir == TOP || dir == BOTTOM)
1304                 for (g = 0; g < size; g++)
1305                         rp->rowLoc[orient][g] =
1306                                 rp->cubeLoc[face][g * size + h];
1307         else                    /* dir == RIGHT || dir == LEFT */
1308                 for (g = 0; g < size; g++)
1309                         rp->rowLoc[orient][g] =
1310                                 rp->cubeLoc[face][h * size + g];
1311 }
1312
1313 static void
1314 rotateRC(rubikstruct * rp, int rotate, int orient, int size)
1315 {
1316         int         g;
1317
1318         for (g = 0; g < size; g++)
1319                 rp->rowLoc[orient][g].rotation =
1320                         (rp->rowLoc[orient][g].rotation + rotate) % MAXORIENT;
1321 }
1322
1323 static void
1324 reverseRC(rubikstruct * rp, int orient, int size)
1325 {
1326         int         g;
1327         RubikLoc    temp;
1328
1329         for (g = 0; g < size / 2; g++) {
1330                 temp = rp->rowLoc[orient][size - 1 - g];
1331                 rp->rowLoc[orient][size - 1 - g] = rp->rowLoc[orient][g];
1332                 rp->rowLoc[orient][g] = temp;
1333         }
1334 }
1335
1336 static void
1337 writeRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1338 {
1339         int         g, position;
1340
1341         if (dir == TOP || dir == BOTTOM) {
1342                 for (g = 0; g < size; g++) {
1343                         position = g * size + h;
1344                         rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1345                         /* DrawSquare(face, position); */
1346                 }
1347         } else {                /* dir == RIGHT || dir == LEFT */
1348                 for (g = 0; g < size; g++) {
1349                         position = h * size + g;
1350                         rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1351                         /* DrawSquare(face, position); */
1352                 }
1353         }
1354 }
1355
1356 static void
1357 rotateFace(rubikstruct * rp, int face, int direction)
1358 {
1359         int         position, i, j;
1360         RubikLoc   *faceLoc = NULL;
1361
1362         if ((faceLoc = (RubikLoc *) malloc(AVSIZESQ * sizeof (RubikLoc))) == NULL)
1363                 (void) fprintf(stderr,
1364                  "Could not allocate memory for rubik face position info\n");
1365         /* Read Face */
1366         for (position = 0; position < AVSIZESQ; position++)
1367                 faceLoc[position] = rp->cubeLoc[face][position];
1368         /* Write Face */
1369         for (position = 0; position < AVSIZESQ; position++) {
1370                 i = position % AVSIZE;
1371                 j = position / AVSIZE;
1372                 rp->cubeLoc[face][position] = (direction == CW) ?
1373                         faceLoc[(AVSIZE - i - 1) * AVSIZE + j] :
1374                         faceLoc[i * AVSIZE + AVSIZE - j - 1];
1375                 rp->cubeLoc[face][position].rotation =
1376                         (rp->cubeLoc[face][position].rotation + direction - MAXORIENT) %
1377                         MAXORIENT;
1378                 /* DrawSquare(face, position); */
1379         }
1380         if (faceLoc != NULL)
1381                 (void) free((void *) faceLoc);
1382 }
1383
1384 static void
1385 moveRubik(rubikstruct * rp, int face, int direction, int position)
1386 {
1387         int         newFace, newDirection, rotate, reverse = False;
1388         int         h, k, newH = 0;
1389         int         i, j;
1390
1391         if (direction == CW || direction == CCW) {
1392                 direction = (direction == CCW) ?
1393                         (rotateToRow[face].direction + 2) % MAXORIENT :
1394                         rotateToRow[face].direction;
1395                 i = j = (rotateToRow[face].sideFace == RIGHT ||
1396                       rotateToRow[face].sideFace == BOTTOM) ? AVSIZE - 1 : 0;
1397                 face = rotateToRow[face].face;
1398                 position = j * AVSIZE + i;
1399         }
1400         i = position % AVSIZE;
1401         j = position / AVSIZE;
1402         h = (direction == TOP || direction == BOTTOM) ? i : j;
1403         /* rotate sides CW or CCW */
1404         if (h == AVSIZE - 1) {
1405                 newDirection = (direction == TOP || direction == BOTTOM) ?
1406                         TOP : RIGHT;
1407                 if (direction == TOP || direction == RIGHT)
1408                         rotateFace(rp, rowToRotate[face][newDirection], CW);
1409                 else            /* direction == BOTTOM || direction == LEFT */
1410                         rotateFace(rp, rowToRotate[face][newDirection], CCW);
1411         }
1412         if (h == 0) {
1413                 newDirection = (direction == TOP || direction == BOTTOM) ?
1414                         BOTTOM : LEFT;
1415                 if (direction == TOP || direction == RIGHT)
1416                         rotateFace(rp, rowToRotate[face][newDirection], CCW);
1417                 else            /* direction == BOTTOM  || direction == LEFT */
1418                         rotateFace(rp, rowToRotate[face][newDirection], CW);
1419         }
1420         /* Slide rows */
1421         readRC(rp, face, direction, h, 0, AVSIZE);
1422         for (k = 1; k <= MAXORIENT; k++) {
1423                 newFace = slideNextRow[face][direction].face;
1424                 rotate = slideNextRow[face][direction].rotation;
1425                 newDirection = (rotate + direction) % MAXORIENT;
1426                 switch (rotate) {
1427                         case TOP:
1428                                 newH = h;
1429                                 reverse = False;
1430                                 break;
1431                         case RIGHT:
1432                                 if (newDirection == TOP || newDirection == BOTTOM) {
1433                                         newH = AVSIZE - 1 - h;
1434                                         reverse = False;
1435                                 } else {        /* newDirection == RIGHT || newDirection == LEFT */
1436                                         newH = h;
1437                                         reverse = True;
1438                                 }
1439                                 break;
1440                         case BOTTOM:
1441                                 newH = AVSIZE - 1 - h;
1442                                 reverse = True;
1443                                 break;
1444                         case LEFT:
1445                                 if (newDirection == TOP || newDirection == BOTTOM) {
1446                                         newH = h;
1447                                         reverse = True;
1448                                 } else {        /* newDirection == RIGHT || newDirection == LEFT */
1449                                         newH = AVSIZE - 1 - h;
1450                                         reverse = False;
1451                                 }
1452                                 break;
1453                         default:
1454                                 (void) printf("moveRubik: rotate %d\n", rotate);
1455                 }
1456                 if (k != MAXORIENT)
1457                         readRC(rp, newFace, newDirection, newH, k, AVSIZE);
1458                 rotateRC(rp, rotate, k - 1, AVSIZE);
1459                 if (reverse == True)
1460                         reverseRC(rp, k - 1, AVSIZE);
1461                 writeRC(rp, newFace, newDirection, newH, k - 1, AVSIZE);
1462                 face = newFace;
1463                 direction = newDirection;
1464                 h = newH;
1465         }
1466 }
1467
1468 #ifdef DEBUG
1469 void
1470 printCube(rubikstruct * rp)
1471 {
1472         int         face, position;
1473
1474         for (face = 0; face < MAXFACES; face++) {
1475                 for (position = 0; position < AVSIZESQ; position++) {
1476                         (void) printf("%d %d  ", rp->cubeLoc[face][position].face,
1477                                       rp->cubeLoc[face][position].rotation);
1478                         if (!((position + 1) % AVSIZE))
1479                                 (void) printf("\n");
1480                 }
1481                 (void) printf("\n");
1482         }
1483         (void) printf("\n");
1484 }
1485
1486 #endif
1487
1488 static void
1489 evalmovement(ModeInfo * mi, RubikMove movement)
1490 {
1491         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1492
1493 #ifdef DEBUG
1494         printCube(rp);
1495 #endif
1496         if (movement.face < 0 || movement.face >= MAXFACES)
1497                 return;
1498
1499         moveRubik(rp, movement.face, movement.direction, movement.position);
1500
1501 }
1502
1503 static      Bool
1504 compare_moves(rubikstruct * rp, RubikMove move1, RubikMove move2, Bool opp)
1505 {
1506         RubikSlice  slice1, slice2;
1507
1508         slice1 = convertMove(rp, move1);
1509         slice2 = convertMove(rp, move2);
1510         if (slice1.face == slice2.face &&
1511             slice1.depth == slice2.depth) {
1512                 if (slice1.rotation == slice2.rotation) {       /* CW or CCW */
1513                         if (!opp)
1514                                 return True;
1515                 } else {
1516                         if (opp)
1517                                 return True;
1518                 }
1519         }
1520         return False;
1521 }
1522
1523 static void
1524 shuffle(ModeInfo * mi)
1525 {
1526         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1527         int         i, face, position;
1528         RubikMove   move;
1529
1530         AVSIZE = MI_SIZE(mi);
1531         if (AVSIZE < -MINSIZE)
1532                 AVSIZE = NRAND(-AVSIZE - MINSIZE + 1) + MINSIZE;
1533         else if (AVSIZE < MINSIZE)
1534                 AVSIZE = MINSIZE;
1535         /* Let me waste a little space for the moment */
1536         /* Future cube to be LxMxN and not just NxNxN, but not done yet */
1537         AVSIZESQ = AVSIZE * AVSIZE;
1538 #ifdef LMN
1539         MAXSIZEX = AVSIZE;
1540         MAXSIZEY = AVSIZE;
1541         MAXSIZEZ = AVSIZE;
1542         MAXSIZE = AVSIZE;
1543         MAXSIZESQ = AVSIZESQ;
1544 #endif
1545
1546         for (face = 0; face < MAXFACES; face++) {
1547                 if (rp->cubeLoc[face] != NULL)
1548                         (void) free((void *) rp->cubeLoc[face]);
1549                 if ((rp->cubeLoc[face] =
1550                   (RubikLoc *) malloc(AVSIZESQ * sizeof (RubikLoc))) == NULL)
1551                         (void) fprintf(stderr,
1552                                        "Could not allocate memory for rubik cube position info\n");
1553                 for (position = 0; position < AVSIZESQ; position++) {
1554                         rp->cubeLoc[face][position].face = face;
1555                         rp->cubeLoc[face][position].rotation = TOP;
1556                 }
1557         }
1558         for (i = 0; i < MAXORIENT; i++) {
1559                 if (rp->rowLoc[i] != NULL)
1560                         (void) free((void *) rp->rowLoc[i]);
1561                 if ((rp->rowLoc[i] =
1562                      (RubikLoc *) malloc(AVSIZE * sizeof (RubikLoc))) == NULL)
1563                         (void) fprintf(stderr,
1564                                        "Could not allocate memory for rubik row position info\n");
1565         }
1566         rp->storedmoves = MI_COUNT(mi);
1567         if (rp->storedmoves < 0) {
1568                 if (rp->moves != NULL)
1569                         (void) free((void *) rp->moves);
1570                 rp->moves = NULL;
1571                 rp->storedmoves = NRAND(-rp->storedmoves) + 1;
1572         }
1573         if ((rp->storedmoves) && (rp->moves == NULL))
1574                 if ((rp->moves =
1575                      (RubikMove *) calloc(rp->storedmoves + 1, sizeof (RubikMove))) == NULL)
1576                         (void) fprintf(stderr,
1577                         "Could not allocate memory for rubik move buffer\n");
1578
1579         if (MI_CYCLES(mi) <= 1) {
1580                 rp->anglestep = 90.0;
1581         } else {
1582                 rp->anglestep = 90.0 / (GLfloat) (MI_CYCLES(mi));
1583         }
1584
1585         for (i = 0; i < rp->storedmoves; i++) {
1586                 int         condition;
1587
1588                 do {
1589                         move.face = NRAND(6);
1590                         move.direction = NRAND(4);      /* Exclude CW and CCW, its ok */
1591                         /*
1592                          * Randomize position along diagonal, each plane gets an equal chance.
1593                          * This trick will only work for NxNxN cubes
1594                          * draw_cube DEPENDS on that they are chosen this way.
1595                          */
1596                         move.position = NRAND(AVSIZE) * (AVSIZE + 1);
1597
1598
1599                         condition = 1;
1600
1601                         if (i > 0)      /* avoid immediate undoing moves */
1602                                 if (compare_moves(rp, move, rp->moves[i - 1], True))
1603                                         condition = 0;
1604                         if (i > 1)      /* avoid 3 consecutive identical moves */
1605                                 if (compare_moves(rp, move, rp->moves[i - 1], False) &&
1606                                     compare_moves(rp, move, rp->moves[i - 2], False))
1607                                         condition = 0;
1608                         /*
1609                            * Still some silly moves being made....
1610                          */
1611                 } while (!condition);
1612                 if (hideshuffling)
1613                         evalmovement(mi, move);
1614                 rp->moves[i] = move;
1615         }
1616         rp->VX = 0.05;
1617         if (NRAND(100) < 50)
1618                 rp->VX *= -1;
1619         rp->VY = 0.05;
1620         if (NRAND(100) < 50)
1621                 rp->VY *= -1;
1622         rp->movement.face = NO_FACE;
1623         rp->rotatestep = 0;
1624         rp->action = hideshuffling ? ACTION_SOLVE : ACTION_SHUFFLE;
1625         rp->shufflingmoves = 0;
1626         rp->done = 0;
1627 }
1628
1629 static void
1630 reshape(ModeInfo * mi, int width, int height)
1631 {
1632         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1633
1634         glViewport(0, 0, rp->WindW = (GLint) width, rp->WindH = (GLint) height);
1635         glMatrixMode(GL_PROJECTION);
1636         glLoadIdentity();
1637         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
1638         glMatrixMode(GL_MODELVIEW);
1639
1640         rp->AreObjectsDefined[ObjCubit] = 0;
1641 }
1642
1643 static void
1644 pinit(ModeInfo * mi)
1645 {
1646         glClearDepth(1.0);
1647         glClearColor(0.0, 0.0, 0.0, 1.0);
1648         glColor3f(1.0, 1.0, 1.0);
1649
1650         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
1651         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
1652         glLightfv(GL_LIGHT0, GL_POSITION, position0);
1653         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
1654         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
1655         glLightfv(GL_LIGHT1, GL_POSITION, position1);
1656         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1657         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1658         glEnable(GL_LIGHTING);
1659         glEnable(GL_LIGHT0);
1660         glEnable(GL_LIGHT1);
1661         glEnable(GL_DEPTH_TEST);
1662         glEnable(GL_NORMALIZE);
1663         glEnable(GL_CULL_FACE);
1664
1665         glShadeModel(GL_FLAT);
1666         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1667         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1668
1669         shuffle(mi);
1670 }
1671
1672 void
1673 init_rubik(ModeInfo * mi)
1674 {
1675         int         screen = MI_SCREEN(mi);
1676         rubikstruct *rp;
1677
1678         if (rubik == NULL) {
1679                 if ((rubik = (rubikstruct *) calloc(MI_NUM_SCREENS(mi),
1680                                               sizeof (rubikstruct))) == NULL)
1681                         return;
1682         }
1683         rp = &rubik[screen];
1684         rp->step = NRAND(90);
1685
1686         rp->PX = ((float) LRAND() / (float) RAND_MAX) * 2 - 1;
1687         rp->PY = ((float) LRAND() / (float) RAND_MAX) * 2 - 1;
1688
1689         if ((rp->glx_context = init_GL(mi)) != NULL) {
1690
1691                 reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1692                 objects = glGenLists(1);
1693                 pinit(mi);
1694         } else {
1695                 MI_CLEARWINDOW(mi);
1696         }
1697 }
1698
1699 void
1700 draw_rubik(ModeInfo * mi)
1701 {
1702         int         bounced = 0;
1703
1704         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1705         Display    *display = MI_DISPLAY(mi);
1706         Window      window = MI_WINDOW(mi);
1707
1708         MI_IS_DRAWN(mi) = True;
1709
1710         if (!rp->glx_context)
1711                 return;
1712
1713         glDrawBuffer(GL_BACK);
1714         glXMakeCurrent(display, window, *(rp->glx_context));
1715
1716         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1717
1718         glPushMatrix();
1719
1720         glTranslatef(0.0, 0.0, -10.0);
1721
1722         rp->PX += rp->VX;
1723         rp->PY += rp->VY;
1724
1725         if (rp->PY < -1) {
1726                 rp->PY += (-1) - (rp->PY);
1727                 rp->VY = -rp->VY;
1728                 bounced = 1;
1729         }
1730         if (rp->PY > 1) {
1731                 rp->PY -= (rp->PY) - 1;
1732                 rp->VY = -rp->VY;
1733                 bounced = 1;
1734         }
1735         if (rp->PX < -1) {
1736                 rp->PX += (-1) - (rp->PX);
1737                 rp->VX = -rp->VX;
1738                 bounced = 1;
1739         }
1740         if (rp->PX > 1) {
1741                 rp->PX -= (rp->PX) - 1;
1742                 rp->VX = -rp->VX;
1743                 bounced = 1;
1744         }
1745         if (bounced) {
1746                 rp->VX += ((float) LRAND() / (float) RAND_MAX) * 0.02 - 0.01;
1747                 rp->VX += ((float) LRAND() / (float) RAND_MAX) * 0.02 - 0.01;
1748                 if (rp->VX > 0.06)
1749                         rp->VX = 0.06;
1750                 if (rp->VY > 0.06)
1751                         rp->VY = 0.06;
1752                 if (rp->VX < -0.06)
1753                         rp->VX = -0.06;
1754                 if (rp->VY < -0.06)
1755                         rp->VY = -0.06;
1756         }
1757         if (!MI_IS_ICONIC(mi)) {
1758                 glTranslatef(rp->PX, rp->PY, 0);
1759                 glScalef(Scale4Window * rp->WindH / rp->WindW, Scale4Window, Scale4Window);
1760         } else {
1761                 glScalef(Scale4Iconic * rp->WindH / rp->WindW, Scale4Iconic, Scale4Iconic);
1762         }
1763
1764         glRotatef(rp->step * 100, 1, 0, 0);
1765         glRotatef(rp->step * 95, 0, 1, 0);
1766         glRotatef(rp->step * 90, 0, 0, 1);
1767
1768         draw_cube(mi);
1769         glXSwapBuffers(display, window);
1770
1771         if (rp->action == ACTION_SHUFFLE) {
1772                 if (rp->done) {
1773                         if (++rp->rotatestep > DELAY_AFTER_SHUFFLING) {
1774                                 rp->movement.face = NO_FACE;
1775                                 rp->rotatestep = 0;
1776                                 rp->action = ACTION_SOLVE;
1777                                 rp->done = 0;
1778                         }
1779                 } else {
1780                         if (rp->movement.face == NO_FACE) {
1781                                 if (rp->shufflingmoves < rp->storedmoves) {
1782                                         rp->rotatestep = 0;
1783                                         rp->movement = rp->moves[rp->shufflingmoves];
1784                                 } else {
1785                                         rp->rotatestep = 0;
1786                                         rp->done = 1;
1787                                 }
1788                         } else {
1789                                 rp->rotatestep += rp->anglestep;
1790                                 if (rp->rotatestep > 90) {
1791                                         evalmovement(mi, rp->movement);
1792                                         rp->shufflingmoves++;
1793                                         rp->movement.face = NO_FACE;
1794                                 }
1795                         }
1796                 }
1797         } else {
1798                 if (rp->done) {
1799                         if (++rp->rotatestep > DELAY_AFTER_SOLVING)
1800                                 shuffle(mi);
1801                 } else {
1802                         if (rp->movement.face == NO_FACE) {
1803                                 if (rp->storedmoves > 0) {
1804                                         rp->rotatestep = 0;
1805                                         rp->movement = rp->moves[rp->storedmoves - 1];
1806                                         rp->movement.direction = (rp->movement.direction + (MAXORIENT / 2)) %
1807                                                 MAXORIENT;
1808                                 } else {
1809                                         rp->rotatestep = 0;
1810                                         rp->done = 1;
1811                                 }
1812                         } else {
1813                                 rp->rotatestep += rp->anglestep;
1814                                 if (rp->rotatestep > 90) {
1815                                         evalmovement(mi, rp->movement);
1816                                         rp->storedmoves--;
1817                                         rp->movement.face = NO_FACE;
1818                                 }
1819                         }
1820                 }
1821         }
1822
1823         glPopMatrix();
1824
1825         glFlush();
1826
1827         rp->step += 0.05;
1828 }
1829
1830 void
1831 change_rubik(ModeInfo * mi)
1832 {
1833         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1834
1835         if (!rp->glx_context)
1836                 return;
1837         pinit(mi);
1838 }
1839
1840 void
1841 release_rubik(ModeInfo * mi)
1842 {
1843         if (rubik != NULL) {
1844                 int         screen;
1845
1846                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1847                         rubikstruct *rp = &rubik[screen];
1848                         int         i;
1849
1850                         for (i = 0; i < MAXFACES; i++)
1851                                 if (rp->cubeLoc[i] != NULL)
1852                                         (void) free((void *) rp->cubeLoc[i]);
1853                         for (i = 0; i < MAXORIENT; i++)
1854                                 if (rp->rowLoc[i] != NULL)
1855                                         (void) free((void *) rp->rowLoc[i]);
1856                         if (rp->moves != NULL)
1857                                 (void) free((void *) rp->moves);
1858                 }
1859                 (void) free((void *) rubik);
1860                 rubik = NULL;
1861         }
1862         FreeAllGL(mi);
1863 }
1864
1865 #endif