http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.29.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 address is
36  * m-vianna@usa.net
37  *
38  * Marcelo F. Vianna (Jul-31-1997)
39  *
40  * Revision History:
41  * 26-Sep-98: Added some more movement (the cube do not stays in the screen
42  *            center anymore. Also fixed the scale problem imediatelly after
43  *            shuffling when the puzzle is solved.
44  * 08-Aug-97: Now has some internals from xrubik by David Bagley
45  *            This should make it easier to add features.
46  * 02-Aug-97: Now behaves more like puzzle.c: first show the cube being
47  *            shuffled and then being solved. A mode specific option was added:
48  *            "+/-hideshuffling" to provide the original behavior (in which
49  *            only the solution is shown).
50  *            The color labels corners are now rounded.
51  *            Optimized the cubit() routine using glLists.
52  * 01-Aug-97: Shuffling now avoids movements that undoes the previous movement
53  *            and three consecutive identical moves (which is pretty stupid).
54  *            improved the "cycles" option in replacement of David's hack,
55  *            now rp->anglestep is a GLfloat, so this option selects the
56  *            "exact" number of frames that a rotation (movement) takes to
57  *            complete.
58  * 30-Jul-97: Initial release, there is no algorithm to solve the puzzle,
59  *            instead, it randomly shuffle the cube and then make the
60  *            movements in the reverse order.
61  *            The mode was written in 1 day (I got sick and had the day off).
62  *            There was not much to do since I could not leave home... :)
63  *
64  */
65
66 /*-
67  * Color labels mapping:
68  * =====================
69  *
70  *                       +------------+
71  *                       |0-->        |
72  *                       ||           |
73  *                       |v           |
74  *                       |   TOP(0)   |
75  *                       |            |
76  *                       |            |
77  *                       |           8|
78  *           +-----------+------------+-----------+
79  *           |0-->       |0-->        |0-->       |
80  *           ||          ||           ||          |
81  *           |v          |v           |v          |
82  *           |  LEFT(1)  |  FRONT(2)  |  RIGHT(3) |
83  *           |           |            |           |
84  *           |           |            |           |
85  *           |          8|           8|          8|
86  *           +-----------+------------+-----------+
87  *                       |0-->        |
88  *                       ||           |
89  *                       |v           |
90  *                       |  BOTTOM(4) |  rp->faces[N][X+AVSIZE*Y]=
91  *                       |            |         rp->cubeLoc[N][X+AVSIZE*Y]=
92  *                       |            | 
93  *                       |           8|         +---+---+---+
94  *                       +------------+         |   |   |   |
95  *                       |0-->        |         | 0 | 1 | 2 |
96  *                       ||           |         |---+---+---+
97  *                       |v           |         |  xxxxx(N) |
98  *                       |   BACK(5)  |         | 3 | 4 | 5 |
99  *                       |            |         +---+---+---+
100  *                       |            |         |   |   |  |
101  *                       |           8|         | 6 | 7 | 8 |
102  *                       +------------+         +---+---+---+
103  *
104  *  Map to 3d
105  *  FRONT  => X, Y
106  *  BACK   => X, Y
107  *  LEFT   => Z, Y
108  *  RIGHT  => Z, Y
109  *  TOP    => X, Z
110  *  BOTTOM => X, Z
111  */
112
113 /*-
114  * PURIFY 3.0a on SunOS4 reports an unitialized memory read on each of
115  * the glCallList() functions below when using MesaGL 2.1.  This has
116  * been fixed in MesaGL 2.2 and later releases.
117  */
118
119 /*-
120  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
121  * otherwise caddr_t is not defined correctly
122  */
123 #include <X11/Intrinsic.h>
124
125 #ifdef STANDALONE
126 # define PROGCLASS      "Rubik"
127 # define HACK_INIT      init_rubik
128 # define HACK_DRAW      draw_rubik
129 # define HACK_RESHAPE reshape_rubik
130 # define rubik_opts     xlockmore_opts
131 # define DEFAULTS       "*delay: 40000 \n"              \
132                                         "*count: -30 \n"                \
133                                         "*showFPS: False \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         GLXContext *glx_context;
389         int         AreObjectsDefined[1];
390 } rubikstruct;
391
392 static float front_shininess[] =
393 {60.0};
394 static float front_specular[] =
395 {0.7, 0.7, 0.7, 1.0};
396 static float ambient[] =
397 {0.0, 0.0, 0.0, 1.0};
398 static float diffuse[] =
399 {1.0, 1.0, 1.0, 1.0};
400 static float position0[] =
401 {1.0, 1.0, 1.0, 0.0};
402 static float position1[] =
403 {-1.0, -1.0, 1.0, 0.0};
404 static float lmodel_ambient[] =
405 {0.5, 0.5, 0.5, 1.0};
406 static float lmodel_twoside[] =
407 {GL_TRUE};
408
409 static float MaterialRed[] =
410 {0.5, 0.0, 0.0, 1.0};
411 static float MaterialGreen[] =
412 {0.0, 0.5, 0.0, 1.0};
413 static float MaterialBlue[] =
414 {0.0, 0.0, 0.5, 1.0};
415 static float MaterialYellow[] =
416 {0.7, 0.7, 0.0, 1.0};
417 static float MaterialOrange[] =
418 {0.9, 0.45, 0.36, 1.0};
419
420 #if 0
421 static float MaterialMagenta[] =
422 {0.7, 0.0, 0.7, 1.0};
423 static float MaterialCyan[] =
424 {0.0, 0.7, 0.7, 1.0};
425
426 #endif
427 static float MaterialWhite[] =
428 {0.8, 0.8, 0.8, 1.0};
429 static float MaterialGray[] =
430 {0.2, 0.2, 0.2, 1.0};
431 static float MaterialGray3[] =
432 {0.3, 0.3, 0.3, 1.0};
433 static float MaterialGray4[] =
434 {0.4, 0.4, 0.4, 1.0};
435 static float MaterialGray5[] =
436 {0.5, 0.5, 0.5, 1.0};
437 static float MaterialGray6[] =
438 {0.6, 0.6, 0.6, 1.0};
439 static float MaterialGray7[] =
440 {0.7, 0.7, 0.7, 1.0};
441
442 static rubikstruct *rubik = NULL;
443 static GLuint objects;
444
445 #define ObjCubit        0
446
447 static void
448 pickcolor(int C, int mono)
449 {
450         switch (C) {
451                 case TOP_FACE:
452                         if (mono)
453                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray3);
454                         else
455                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
456                         break;
457                 case LEFT_FACE:
458                         if (mono)
459                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray6);
460                         else
461                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
462                         break;
463                 case FRONT_FACE:
464                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
465                         break;
466                 case RIGHT_FACE:
467                         if (mono)
468                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray4);
469                         else
470                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGreen);
471                         break;
472                 case BOTTOM_FACE:
473                         if (mono)
474                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray7);
475                         else
476                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialOrange);
477                         break;
478                 case BACK_FACE:
479                         if (mono)
480                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
481                         else
482                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
483                         break;
484 #if 0
485                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialCyan);
486                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialMagenta);
487 #endif
488         }
489 }
490
491
492 static void
493 draw_cubit(ModeInfo * mi,
494            int back, int front, int left, int right, int bottom, int top)
495 {
496         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
497         int         mono = MI_IS_MONO(mi);
498
499         if (!rp->AreObjectsDefined[ObjCubit]) {
500                 glNewList(objects + ObjCubit, GL_COMPILE_AND_EXECUTE);
501                 glBegin(GL_QUADS);
502                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
503                 glNormal3f(0.00, 0.00, 1.00);
504                 glVertex3f(-0.45, -0.45, 0.50);
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                 glNormal3f(0.00, 0.00, -1.00);
509                 glVertex3f(-0.45, 0.45, -0.50);
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                 glNormal3f(-1.00, 0.00, 0.00);
514                 glVertex3f(-0.50, -0.45, 0.45);
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                 glNormal3f(1.00, 0.00, 0.00);
519                 glVertex3f(0.50, -0.45, -0.45);
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                 glNormal3f(0.00, -1.00, 0.00);
524                 glVertex3f(0.45, -0.50, -0.45);
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                 glNormal3f(0.00, 1.00, 0.00);
529                 glVertex3f(-0.45, 0.50, -0.45);
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                 glNormal3f(-1.00, -1.00, 0.00);
534                 glVertex3f(-0.45, -0.50, -0.45);
535                 glVertex3f(-0.45, -0.50, 0.45);
536                 glVertex3f(-0.50, -0.45, 0.45);
537                 glVertex3f(-0.50, -0.45, -0.45);
538                 glNormal3f(1.00, 1.00, 0.00);
539                 glVertex3f(0.45, 0.50, -0.45);
540                 glVertex3f(0.45, 0.50, 0.45);
541                 glVertex3f(0.50, 0.45, 0.45);
542                 glVertex3f(0.50, 0.45, -0.45);
543                 glNormal3f(-1.00, 1.00, 0.00);
544                 glVertex3f(-0.50, 0.45, -0.45);
545                 glVertex3f(-0.50, 0.45, 0.45);
546                 glVertex3f(-0.45, 0.50, 0.45);
547                 glVertex3f(-0.45, 0.50, -0.45);
548                 glNormal3f(1.00, -1.00, 0.00);
549                 glVertex3f(0.50, -0.45, -0.45);
550                 glVertex3f(0.50, -0.45, 0.45);
551                 glVertex3f(0.45, -0.50, 0.45);
552                 glVertex3f(0.45, -0.50, -0.45);
553                 glNormal3f(0.00, -1.00, -1.00);
554                 glVertex3f(-0.45, -0.45, -0.50);
555                 glVertex3f(0.45, -0.45, -0.50);
556                 glVertex3f(0.45, -0.50, -0.45);
557                 glVertex3f(-0.45, -0.50, -0.45);
558                 glNormal3f(0.00, 1.00, 1.00);
559                 glVertex3f(-0.45, 0.45, 0.50);
560                 glVertex3f(0.45, 0.45, 0.50);
561                 glVertex3f(0.45, 0.50, 0.45);
562                 glVertex3f(-0.45, 0.50, 0.45);
563                 glNormal3f(0.00, -1.00, 1.00);
564                 glVertex3f(-0.45, -0.50, 0.45);
565                 glVertex3f(0.45, -0.50, 0.45);
566                 glVertex3f(0.45, -0.45, 0.50);
567                 glVertex3f(-0.45, -0.45, 0.50);
568                 glNormal3f(0.00, 1.00, -1.00);
569                 glVertex3f(-0.45, 0.50, -0.45);
570                 glVertex3f(0.45, 0.50, -0.45);
571                 glVertex3f(0.45, 0.45, -0.50);
572                 glVertex3f(-0.45, 0.45, -0.50);
573                 glNormal3f(-1.00, 0.00, -1.00);
574                 glVertex3f(-0.50, -0.45, -0.45);
575                 glVertex3f(-0.50, 0.45, -0.45);
576                 glVertex3f(-0.45, 0.45, -0.50);
577                 glVertex3f(-0.45, -0.45, -0.50);
578                 glNormal3f(1.00, 0.00, 1.00);
579                 glVertex3f(0.50, -0.45, 0.45);
580                 glVertex3f(0.50, 0.45, 0.45);
581                 glVertex3f(0.45, 0.45, 0.50);
582                 glVertex3f(0.45, -0.45, 0.50);
583                 glNormal3f(1.00, 0.00, -1.00);
584                 glVertex3f(0.45, -0.45, -0.50);
585                 glVertex3f(0.45, 0.45, -0.50);
586                 glVertex3f(0.50, 0.45, -0.45);
587                 glVertex3f(0.50, -0.45, -0.45);
588                 glNormal3f(-1.00, 0.00, 1.00);
589                 glVertex3f(-0.45, -0.45, 0.50);
590                 glVertex3f(-0.45, 0.45, 0.50);
591                 glVertex3f(-0.50, 0.45, 0.45);
592                 glVertex3f(-0.50, -0.45, 0.45);
593                 glEnd();
594                 glBegin(GL_TRIANGLES);
595                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
596                 glNormal3f(1.00, 1.00, 1.00);
597                 glVertex3f(0.45, 0.45, 0.50);
598                 glVertex3f(0.50, 0.45, 0.45);
599                 glVertex3f(0.45, 0.50, 0.45);
600                 glNormal3f(-1.00, -1.00, -1.00);
601                 glVertex3f(-0.45, -0.50, -0.45);
602                 glVertex3f(-0.50, -0.45, -0.45);
603                 glVertex3f(-0.45, -0.45, -0.50);
604                 glNormal3f(-1.00, 1.00, 1.00);
605                 glVertex3f(-0.45, 0.45, 0.50);
606                 glVertex3f(-0.45, 0.50, 0.45);
607                 glVertex3f(-0.50, 0.45, 0.45);
608                 glNormal3f(1.00, -1.00, -1.00);
609                 glVertex3f(0.50, -0.45, -0.45);
610                 glVertex3f(0.45, -0.50, -0.45);
611                 glVertex3f(0.45, -0.45, -0.50);
612                 glNormal3f(1.00, -1.00, 1.00);
613                 glVertex3f(0.45, -0.45, 0.50);
614                 glVertex3f(0.45, -0.50, 0.45);
615                 glVertex3f(0.50, -0.45, 0.45);
616                 glNormal3f(-1.00, 1.00, -1.00);
617                 glVertex3f(-0.50, 0.45, -0.45);
618                 glVertex3f(-0.45, 0.50, -0.45);
619                 glVertex3f(-0.45, 0.45, -0.50);
620                 glNormal3f(-1.00, -1.00, 1.00);
621                 glVertex3f(-0.45, -0.45, 0.50);
622                 glVertex3f(-0.50, -0.45, 0.45);
623                 glVertex3f(-0.45, -0.50, 0.45);
624                 glNormal3f(1.00, 1.00, -1.00);
625                 glVertex3f(0.50, 0.45, -0.45);
626                 glVertex3f(0.45, 0.45, -0.50);
627                 glVertex3f(0.45, 0.50, -0.45);
628                 glEnd();
629                 glEndList();
630                 rp->AreObjectsDefined[ObjCubit] = 1;
631 #ifdef DEBUG_LISTS
632                 (void) printf("Cubit drawn SLOWLY\n");
633 #endif
634         } else {
635                 glCallList(objects + ObjCubit);
636 #ifdef DEBUG_LISTS
637                 (void) printf("Cubit drawn quickly\n");
638 #endif
639         }
640
641         if (back != NO_FACE) {
642                 glBegin(GL_POLYGON);
643                 pickcolor(back, mono);
644                 glNormal3f(0.00, 0.00, -1.00);
645                 glVertex3f(-0.35, 0.40, -0.51);
646                 glVertex3f(0.35, 0.40, -0.51);
647                 glVertex3f(0.40, 0.35, -0.51);
648                 glVertex3f(0.40, -0.35, -0.51);
649                 glVertex3f(0.35, -0.40, -0.51);
650                 glVertex3f(-0.35, -0.40, -0.51);
651                 glVertex3f(-0.40, -0.35, -0.51);
652                 glVertex3f(-0.40, 0.35, -0.51);
653                 glEnd();
654         }
655         if (front != NO_FACE) {
656                 glBegin(GL_POLYGON);
657                 pickcolor(front, mono);
658                 glNormal3f(0.00, 0.00, 1.00);
659                 glVertex3f(-0.35, -0.40, 0.51);
660                 glVertex3f(0.35, -0.40, 0.51);
661                 glVertex3f(0.40, -0.35, 0.51);
662                 glVertex3f(0.40, 0.35, 0.51);
663                 glVertex3f(0.35, 0.40, 0.51);
664                 glVertex3f(-0.35, 0.40, 0.51);
665                 glVertex3f(-0.40, 0.35, 0.51);
666                 glVertex3f(-0.40, -0.35, 0.51);
667                 glEnd();
668         }
669         if (left != NO_FACE) {
670                 glBegin(GL_POLYGON);
671                 pickcolor(left, mono);
672                 glNormal3f(-1.00, 0.00, 0.00);
673                 glVertex3f(-0.51, -0.35, 0.40);
674                 glVertex3f(-0.51, 0.35, 0.40);
675                 glVertex3f(-0.51, 0.40, 0.35);
676                 glVertex3f(-0.51, 0.40, -0.35);
677                 glVertex3f(-0.51, 0.35, -0.40);
678                 glVertex3f(-0.51, -0.35, -0.40);
679                 glVertex3f(-0.51, -0.40, -0.35);
680                 glVertex3f(-0.51, -0.40, 0.35);
681                 glEnd();
682         }
683         if (right != NO_FACE) {
684                 glBegin(GL_POLYGON);
685                 pickcolor(right, mono);
686                 glNormal3f(1.00, 0.00, 0.00);
687                 glVertex3f(0.51, -0.35, -0.40);
688                 glVertex3f(0.51, 0.35, -0.40);
689                 glVertex3f(0.51, 0.40, -0.35);
690                 glVertex3f(0.51, 0.40, 0.35);
691                 glVertex3f(0.51, 0.35, 0.40);
692                 glVertex3f(0.51, -0.35, 0.40);
693                 glVertex3f(0.51, -0.40, 0.35);
694                 glVertex3f(0.51, -0.40, -0.35);
695                 glEnd();
696         }
697         if (bottom != NO_FACE) {
698                 glBegin(GL_POLYGON);
699                 pickcolor(bottom, mono);
700                 glNormal3f(0.00, -1.00, 0.00);
701                 glVertex3f(0.40, -0.51, -0.35);
702                 glVertex3f(0.40, -0.51, 0.35);
703                 glVertex3f(0.35, -0.51, 0.40);
704                 glVertex3f(-0.35, -0.51, 0.40);
705                 glVertex3f(-0.40, -0.51, 0.35);
706                 glVertex3f(-0.40, -0.51, -0.35);
707                 glVertex3f(-0.35, -0.51, -0.40);
708                 glVertex3f(0.35, -0.51, -0.40);
709                 glEnd();
710         }
711         if (top != NO_FACE) {
712                 glBegin(GL_POLYGON);
713                 pickcolor(top, mono);
714                 glNormal3f(0.00, 1.00, 0.00);
715                 glVertex3f(-0.40, 0.51, -0.35);
716                 glVertex3f(-0.40, 0.51, 0.35);
717                 glVertex3f(-0.35, 0.51, 0.40);
718                 glVertex3f(0.35, 0.51, 0.40);
719                 glVertex3f(0.40, 0.51, 0.35);
720                 glVertex3f(0.40, 0.51, -0.35);
721                 glVertex3f(0.35, 0.51, -0.40);
722                 glVertex3f(-0.35, 0.51, -0.40);
723                 glEnd();
724         }
725 }
726
727
728 static      RubikSlice
729 convertMove(rubikstruct * rp, RubikMove move)
730 {
731         RubikSlice  slice;
732         RubikLoc    plane;
733
734         plane = rotateSlice[(int) move.face][move.direction % 2];
735         slice.face = plane.face;
736         slice.rotation = plane.rotation;
737         if (slice.rotation == CW)       /* I just know this to be true... */
738                 slice.depth = AVSIZESQ - 1 - move.position;
739         else
740                 slice.depth = move.position;
741         slice.depth = slice.depth / AVSIZE;
742         /* If slice.depth = 0 then face 0, face 1, or face 2 moves */
743         if (move.direction / 2)
744                 slice.rotation = (plane.rotation == CW) ? CCW : CW;
745         return slice;
746 }
747
748 /* Assume for the moment that the size is at least 2 */
749 static void
750 draw_cube(ModeInfo * mi)
751 {
752 #define S1 1
753 #define SX ((GLint)S1*(MAXSIZEX-1))
754 #define SY ((GLint)S1*(MAXSIZEY-1))
755 #define SZ ((GLint)S1*(MAXSIZEZ-1))
756 #define HALFX (((GLfloat)MAXSIZEX-1.0)/2.0)
757 #define HALFY (((GLfloat)MAXSIZEY-1.0)/2.0)
758 #define HALFZ (((GLfloat)MAXSIZEZ-1.0)/2.0)
759 #define MIDX(a) (((GLfloat)(2*a-MAXSIZEX+1))/2.0)
760 #define MIDY(a) (((GLfloat)(2*a-MAXSIZEY+1))/2.0)
761 #define MIDZ(a) (((GLfloat)(2*a-MAXSIZEZ+1))/2.0)
762         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
763         RubikSlice  slice;
764         GLfloat     rotatestep;
765         int         i, j, k;
766
767         if (rp->movement.face == NO_FACE) {
768                 slice.face = NO_FACE;
769                 slice.rotation = NO_ROTATION;
770                 slice.depth = NO_DEPTH;
771         } else {
772                 slice = convertMove(rp, rp->movement);
773         }
774         rotatestep = (slice.rotation == CCW) ? rp->rotatestep : -rp->rotatestep;
775
776 /*-
777  * The glRotatef() routine transforms the coordinate system for every future
778  * vertex specification (this is not so simple, but by now comprehending this
779  * is sufficient). So if you want to rotate the inner slice, you can draw
780  * one slice, rotate the anglestep for the centerslice, draw the inner slice,
781  * rotate reversely and draw the other slice.
782  * There is a sequence for drawing cubies for each axis being moved...
783  */
784         switch (slice.face) {
785                 case NO_FACE:
786                 case TOP_FACE:  /* BOTTOM_FACE too */
787                         glPushMatrix();
788                         if (slice.depth == MAXSIZEY - 1)
789                                 glRotatef(rotatestep, 0, HALFY, 0);
790
791                         glTranslatef(-HALFX, -HALFY, -HALFZ);
792                         draw_cubit(mi,
793                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
794                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
795                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
796                         for (k = 1; k < MAXSIZEZ - 1; k++) {
797                                 glTranslatef(0, 0, S1);
798                                 draw_cubit(mi,
799                                            NO_FACE, NO_FACE,
800                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
801                                            rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
802                         }
803                         glTranslatef(0, 0, S1);
804                         draw_cubit(mi,
805                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
806                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
807                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
808                         for (i = 1; i < MAXSIZEX - 1; i++) {
809                                 glTranslatef(S1, 0, -SZ);
810                                 draw_cubit(mi,
811                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
812                                            NO_FACE, NO_FACE,
813                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
814                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
815                                         glTranslatef(0, 0, S1);
816                                         draw_cubit(mi,
817                                                    NO_FACE, NO_FACE,
818                                                    NO_FACE, NO_FACE,
819                                                    rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
820                                 }
821                                 glTranslatef(0, 0, S1);
822                                 draw_cubit(mi,
823                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
824                                            NO_FACE, NO_FACE,
825                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
826                         }
827                         glTranslatef(1, 0, -SZ);
828                         draw_cubit(mi,
829                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
830                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
831                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
832                         for (k = 1; k < MAXSIZEZ - 1; k++) {
833                                 glTranslatef(0, 0, S1);
834                                 draw_cubit(mi,
835                                            NO_FACE, NO_FACE,
836                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
837                                            rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
838                         }
839                         glTranslatef(0, 0, S1);
840                         draw_cubit(mi,
841                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
842                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
843                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
844                         glPopMatrix();
845                         for (j = 1; j < MAXSIZEY - 1; j++) {
846                                 glPushMatrix();
847                                 if (slice.depth == REVY(j))
848                                         glRotatef(rotatestep, 0, HALFY, 0);
849                                 glTranslatef(-HALFX, MIDY(j), -HALFZ);
850                                 draw_cubit(mi,
851                                            rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
852                                            rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
853                                            NO_FACE, NO_FACE);
854                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
855                                         glTranslatef(0, 0, S1);
856                                         draw_cubit(mi,
857                                                    NO_FACE, NO_FACE,
858                                                    rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
859                                                    NO_FACE, NO_FACE);
860                                 }
861                                 glTranslatef(0, 0, S1);
862                                 draw_cubit(mi,
863                                            NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
864                                            rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
865                                            NO_FACE, NO_FACE);
866                                 for (i = 1; i < MAXSIZEX - 1; i++) {
867                                         glTranslatef(1, 0, -SZ);
868                                         draw_cubit(mi,
869                                                    rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
870                                                    NO_FACE, NO_FACE,
871                                                    NO_FACE, NO_FACE);
872                                         /* Center */
873                                         glTranslatef(0, 0, SZ);
874                                         draw_cubit(mi,
875                                                    NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
876                                                    NO_FACE, NO_FACE,
877                                                    NO_FACE, NO_FACE);
878                                 }
879                                 glTranslatef(S1, 0, -SZ);
880                                 draw_cubit(mi,
881                                            rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
882                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
883                                            NO_FACE, NO_FACE);
884                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
885                                         glTranslatef(0, 0, S1);
886                                         draw_cubit(mi,
887                                                    NO_FACE, NO_FACE,
888                                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
889                                                    NO_FACE, NO_FACE);
890                                 }
891                                 glTranslatef(0, 0, S1);
892                                 draw_cubit(mi,
893                                            NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
894                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
895                                            NO_FACE, NO_FACE);
896                                 glPopMatrix();
897                         }
898                         if (slice.depth == 0)
899                                 glRotatef(rotatestep, 0, HALFY, 0);
900
901                         glTranslatef(-HALFX, HALFY, -HALFZ);
902                         draw_cubit(mi,
903                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
904                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
905                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
906                         for (k = 1; k < MAXSIZEZ - 1; k++) {
907                                 glTranslatef(0, 0, S1);
908                                 draw_cubit(mi,
909                                            NO_FACE, NO_FACE,
910                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
911                                            NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
912                         }
913                         glTranslatef(0, 0, S1);
914                         draw_cubit(mi,
915                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
916                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
917                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
918                         for (i = 1; i < MAXSIZEX - 1; i++) {
919                                 glTranslatef(S1, 0, -SZ);
920                                 draw_cubit(mi,
921                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
922                                            NO_FACE, NO_FACE,
923                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
924                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
925                                         glTranslatef(0, 0, S1);
926                                         draw_cubit(mi,
927                                                    NO_FACE, NO_FACE,
928                                                    NO_FACE, NO_FACE,
929                                                    NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
930                                 }
931                                 glTranslatef(0, 0, S1);
932                                 draw_cubit(mi,
933                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
934                                            NO_FACE, NO_FACE,
935                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
936                         }
937                         glTranslatef(S1, 0, -SZ);
938                         draw_cubit(mi,
939                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
940                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
941                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
942                         for (k = 1; k < MAXSIZEZ - 1; k++) {
943                                 glTranslatef(0, 0, S1);
944                                 draw_cubit(mi,
945                                            NO_FACE, NO_FACE,
946                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
947                                            NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
948                         }
949                         glTranslatef(0, 0, S1);
950                         draw_cubit(mi,
951                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
952                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
953                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
954                         break;
955                 case LEFT_FACE: /* RIGHT_FACE too */
956                         /* rotatestep is negative because the RIGHT face is the default here */
957                         glPushMatrix();
958                         if (slice.depth == 0)
959                                 glRotatef(-rotatestep, HALFX, 0, 0);
960
961                         glTranslatef(-HALFX, -HALFY, -HALFZ);
962                         draw_cubit(mi,
963                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
964                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
965                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
966                         for (j = 1; j < MAXSIZEY - 1; j++) {
967                                 glTranslatef(0, S1, 0);
968                                 draw_cubit(mi,
969                                            rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
970                                            rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
971                                            NO_FACE, NO_FACE);
972                         }
973                         glTranslatef(0, S1, 0);
974                         draw_cubit(mi,
975                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
976                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
977                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
978                         for (k = 1; k < MAXSIZEZ - 1; k++) {
979                                 glTranslatef(0, -SY, S1);
980                                 draw_cubit(mi,
981                                            NO_FACE, NO_FACE,
982                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
983                                            rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
984                                 for (j = 1; j < MAXSIZEY - 1; j++) {
985                                         glTranslatef(0, S1, 0);
986                                         draw_cubit(mi,
987                                                    NO_FACE, NO_FACE,
988                                                    rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
989                                                    NO_FACE, NO_FACE);
990                                 }
991                                 glTranslatef(0, S1, 0);
992                                 draw_cubit(mi,
993                                            NO_FACE, NO_FACE,
994                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
995                                            NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
996                         }
997                         glTranslatef(0, -SY, S1);
998                         draw_cubit(mi,
999                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1000                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1001                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1002                         for (j = 1; j < MAXSIZEY - 1; j++) {
1003                                 glTranslatef(0, S1, 0);
1004                                 draw_cubit(mi,
1005                                            NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1006                                            rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1007                                            NO_FACE, NO_FACE);
1008                         }
1009                         glTranslatef(0, S1, 0);
1010                         draw_cubit(mi,
1011                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1012                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1013                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1014                         glPopMatrix();
1015                         for (i = 1; i < MAXSIZEX - 1; i++) {
1016                                 glPushMatrix();
1017                                 if (slice.depth == i)
1018                                         glRotatef(-rotatestep, HALFX, 0, 0);
1019                                 glTranslatef(MIDX(i), -HALFY, -HALFZ);
1020                                 draw_cubit(mi,
1021                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1022                                            NO_FACE, NO_FACE,
1023                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1024                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1025                                         glTranslatef(0, S1, 0);
1026                                         draw_cubit(mi,
1027                                                    rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1028                                                    NO_FACE, NO_FACE,
1029                                                    NO_FACE, NO_FACE);
1030                                 }
1031                                 glTranslatef(0, S1, 0);
1032                                 draw_cubit(mi,
1033                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1034                                            NO_FACE, NO_FACE,
1035                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1036                                 for (k = 1; k < MAXSIZEZ - 1; k++) {
1037                                         glTranslatef(0, -SY, S1);
1038                                         draw_cubit(mi,
1039                                                    NO_FACE, NO_FACE,
1040                                                    NO_FACE, NO_FACE,
1041                                                    rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1042                                         /* Center */
1043                                         glTranslatef(0, SY, 0);
1044                                         draw_cubit(mi,
1045                                                    NO_FACE, NO_FACE,
1046                                                    NO_FACE, NO_FACE,
1047                                                    NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1048                                 }
1049                                 glTranslatef(0, -SY, S1);
1050                                 draw_cubit(mi,
1051                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1052                                            NO_FACE, NO_FACE,
1053                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1054                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1055                                         glTranslatef(0, S1, 0);
1056                                         draw_cubit(mi,
1057                                                    NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1058                                                    NO_FACE, NO_FACE,
1059                                                    NO_FACE, NO_FACE);
1060                                 }
1061                                 glTranslatef(0, S1, 0);
1062                                 draw_cubit(mi,
1063                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1064                                            NO_FACE, NO_FACE,
1065                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1066                                 glPopMatrix();
1067                         }
1068                         if (slice.depth == MAXSIZEX - 1)
1069                                 glRotatef(-rotatestep, HALFX, 0, 0);
1070                         glTranslatef(HALFX, -HALFY, -HALFZ);
1071                         draw_cubit(mi,
1072                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1073                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1074                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1075                         for (j = 1; j < MAXSIZEY - 1; j++) {
1076                                 glTranslatef(0, S1, 0);
1077                                 draw_cubit(mi,
1078                                            rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1079                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1080                                            NO_FACE, NO_FACE);
1081                         }
1082                         glTranslatef(0, S1, 0);
1083                         draw_cubit(mi,
1084                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1085                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1086                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1087                         for (k = 1; k < MAXSIZEZ - 1; k++) {
1088                                 glTranslatef(0, -SY, S1);
1089                                 draw_cubit(mi,
1090                                            NO_FACE, NO_FACE,
1091                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1092                                            rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1093                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1094                                         glTranslatef(0, S1, 0);
1095                                         draw_cubit(mi,
1096                                                    NO_FACE, NO_FACE,
1097                                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1098                                                    NO_FACE, NO_FACE);
1099                                 }
1100                                 glTranslatef(0, S1, 0);
1101                                 draw_cubit(mi,
1102                                            NO_FACE, NO_FACE,
1103                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1104                                            NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1105                         }
1106                         glTranslatef(0, -SY, S1);
1107                         draw_cubit(mi,
1108                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1109                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1110                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1111                         for (j = 1; j < MAXSIZEY - 1; j++) {
1112                                 glTranslatef(0, S1, 0);
1113                                 draw_cubit(mi,
1114                                            NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1115                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1116                                            NO_FACE, NO_FACE);
1117                         }
1118                         glTranslatef(0, S1, 0);
1119                         draw_cubit(mi,
1120                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1121                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1122                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1123                         break;
1124                 case FRONT_FACE:        /* BACK_FACE too */
1125                         glPushMatrix();
1126                         if (slice.depth == MAXSIZEZ - 1)
1127                                 glRotatef(rotatestep, 0, 0, HALFZ);
1128
1129                         glTranslatef(-HALFX, -HALFY, -HALFZ);
1130                         draw_cubit(mi,
1131                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1132                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1133                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
1134                         for (i = 1; i < MAXSIZEX - 1; i++) {
1135                                 glTranslatef(S1, 0, 0);
1136                                 draw_cubit(mi,
1137                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1138                                            NO_FACE, NO_FACE,
1139                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1140                         }
1141                         glTranslatef(S1, 0, 0);
1142                         draw_cubit(mi,
1143                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1144                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1145                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1146                         for (j = 1; j < MAXSIZEY - 1; j++) {
1147                                 glTranslatef(-SX, S1, 0);
1148                                 draw_cubit(mi,
1149                                            rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
1150                                            rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1151                                            NO_FACE, NO_FACE);
1152                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1153                                         glTranslatef(S1, 0, 0);
1154                                         draw_cubit(mi,
1155                                                    rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1156                                                    NO_FACE, NO_FACE,
1157                                                    NO_FACE, NO_FACE);
1158                                 }
1159                                 glTranslatef(S1, 0, 0);
1160                                 draw_cubit(mi,
1161                                            rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1162                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1163                                            NO_FACE, NO_FACE);
1164                         }
1165                         glTranslatef(-SX, S1, 0);
1166                         draw_cubit(mi,
1167                                    rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
1168                                    rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1169                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
1170                         for (i = 1; i < MAXSIZEX - 1; i++) {
1171                                 glTranslatef(S1, 0, 0);
1172                                 draw_cubit(mi,
1173                                            rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1174                                            NO_FACE, NO_FACE,
1175                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1176                         }
1177                         glTranslatef(S1, 0, 0);
1178                         draw_cubit(mi,
1179                                    rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1180                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1181                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1182                         glPopMatrix();
1183                         for (k = 1; k < MAXSIZEZ - 1; k++) {
1184                                 glPushMatrix();
1185                                 if (slice.depth == REVZ(k))
1186                                         glRotatef(rotatestep, 0, 0, HALFZ);
1187                                 glTranslatef(-HALFX, -HALFY, MIDZ(k));
1188                                 draw_cubit(mi,
1189                                            NO_FACE, NO_FACE,
1190                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
1191                                            rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1192                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1193                                         glTranslatef(S1, 0, 0);
1194                                         draw_cubit(mi,
1195                                                    NO_FACE, NO_FACE,
1196                                                    NO_FACE, NO_FACE,
1197                                                    rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1198                                 }
1199                                 glTranslatef(S1, 0, 0);
1200                                 draw_cubit(mi,
1201                                            NO_FACE, NO_FACE,
1202                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1203                                            rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1204                                 for (j = 1; j < MAXSIZEY - 1; j++) {
1205                                         glTranslatef(-SX, S1, 0);
1206                                         draw_cubit(mi,
1207                                                    NO_FACE, NO_FACE,
1208                                                    rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
1209                                                    NO_FACE, NO_FACE);
1210                                         /* Center */
1211                                         glTranslatef(SX, 0, 0);
1212                                         draw_cubit(mi,
1213                                                    NO_FACE, NO_FACE,
1214                                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1215                                                    NO_FACE, NO_FACE);
1216                                 }
1217                                 glTranslatef(-SX, S1, 0);
1218                                 draw_cubit(mi,
1219                                            NO_FACE, NO_FACE,
1220                                            rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
1221                                            NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
1222                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1223                                         glTranslatef(S1, 0, 0);
1224                                         draw_cubit(mi,
1225                                                    NO_FACE, NO_FACE,
1226                                                    NO_FACE, NO_FACE,
1227                                                    NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1228                                 }
1229                                 glTranslatef(S1, 0, 0);
1230                                 draw_cubit(mi,
1231                                            NO_FACE, NO_FACE,
1232                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1233                                            NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1234                                 glPopMatrix();
1235                         }
1236                         if (slice.depth == 0)
1237                                 glRotatef(rotatestep, 0, 0, HALFZ);
1238                         glTranslatef(-HALFX, -HALFY, HALFZ);
1239                         draw_cubit(mi,
1240                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1241                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1242                                    rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1243                         for (i = 1; i < MAXSIZEX - 1; i++) {
1244                                 glTranslatef(S1, 0, 0);
1245                                 draw_cubit(mi,
1246                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1247                                            NO_FACE, NO_FACE,
1248                                            rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1249                         }
1250                         glTranslatef(S1, 0, 0);
1251                         draw_cubit(mi,
1252                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1253                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1254                                    rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1255                         for (j = 1; j < MAXSIZEY - 1; j++) {
1256                                 glTranslatef(-SX, S1, 0);
1257                                 draw_cubit(mi,
1258                                            NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1259                                            rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1260                                            NO_FACE, NO_FACE);
1261                                 for (i = 1; i < MAXSIZEX - 1; i++) {
1262                                         glTranslatef(S1, 0, 0);
1263                                         draw_cubit(mi,
1264                                                    NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1265                                                    NO_FACE, NO_FACE,
1266                                                    NO_FACE, NO_FACE);
1267                                 }
1268                                 glTranslatef(S1, 0, 0);
1269                                 draw_cubit(mi,
1270                                            NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1271                                            NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1272                                            NO_FACE, NO_FACE);
1273                         }
1274                         glTranslatef(-SX, S1, 0);
1275                         draw_cubit(mi,
1276                                    NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1277                                    rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1278                                    NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1279                         for (i = 1; i < MAXSIZEX - 1; i++) {
1280                                 glTranslatef(S1, 0, 0);
1281                                 draw_cubit(mi,
1282                                            NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1283                                            NO_FACE, NO_FACE,
1284                                            NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1285                         }
1286                         glTranslatef(S1, 0, 0);
1287                         draw_cubit(mi,
1288                                    NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1289                                    NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1290                                    NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1291                         break;
1292         }
1293 #undef S1
1294 }
1295
1296 /* From David Bagley's xrubik.  Used by permission. ;)  */
1297 static void
1298 readRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1299 {
1300         int         g;
1301
1302         if (dir == TOP || dir == BOTTOM)
1303                 for (g = 0; g < size; g++)
1304                         rp->rowLoc[orient][g] =
1305                                 rp->cubeLoc[face][g * size + h];
1306         else                    /* dir == RIGHT || dir == LEFT */
1307                 for (g = 0; g < size; g++)
1308                         rp->rowLoc[orient][g] =
1309                                 rp->cubeLoc[face][h * size + g];
1310 }
1311
1312 static void
1313 rotateRC(rubikstruct * rp, int rotate, int orient, int size)
1314 {
1315         int         g;
1316
1317         for (g = 0; g < size; g++)
1318                 rp->rowLoc[orient][g].rotation =
1319                         (rp->rowLoc[orient][g].rotation + rotate) % MAXORIENT;
1320 }
1321
1322 static void
1323 reverseRC(rubikstruct * rp, int orient, int size)
1324 {
1325         int         g;
1326         RubikLoc    temp;
1327
1328         for (g = 0; g < size / 2; g++) {
1329                 temp = rp->rowLoc[orient][size - 1 - g];
1330                 rp->rowLoc[orient][size - 1 - g] = rp->rowLoc[orient][g];
1331                 rp->rowLoc[orient][g] = temp;
1332         }
1333 }
1334
1335 static void
1336 writeRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1337 {
1338         int         g, position;
1339
1340         if (dir == TOP || dir == BOTTOM) {
1341                 for (g = 0; g < size; g++) {
1342                         position = g * size + h;
1343                         rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1344                         /* DrawSquare(face, position); */
1345                 }
1346         } else {                /* dir == RIGHT || dir == LEFT */
1347                 for (g = 0; g < size; g++) {
1348                         position = h * size + g;
1349                         rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1350                         /* DrawSquare(face, position); */
1351                 }
1352         }
1353 }
1354
1355 static void
1356 rotateFace(rubikstruct * rp, int face, int direction)
1357 {
1358         int         position, i, j;
1359         RubikLoc   *faceLoc = NULL;
1360
1361         if ((faceLoc = (RubikLoc *) malloc(AVSIZESQ * sizeof (RubikLoc))) == NULL)
1362                 (void) fprintf(stderr,
1363                  "Could not allocate memory for rubik face position info\n");
1364         /* Read Face */
1365         for (position = 0; position < AVSIZESQ; position++)
1366                 faceLoc[position] = rp->cubeLoc[face][position];
1367         /* Write Face */
1368         for (position = 0; position < AVSIZESQ; position++) {
1369                 i = position % AVSIZE;
1370                 j = position / AVSIZE;
1371                 rp->cubeLoc[face][position] = (direction == CW) ?
1372                         faceLoc[(AVSIZE - i - 1) * AVSIZE + j] :
1373                         faceLoc[i * AVSIZE + AVSIZE - j - 1];
1374                 rp->cubeLoc[face][position].rotation =
1375                         (rp->cubeLoc[face][position].rotation + direction - MAXORIENT) %
1376                         MAXORIENT;
1377                 /* DrawSquare(face, position); */
1378         }
1379         if (faceLoc != NULL)
1380                 (void) free((void *) faceLoc);
1381 }
1382
1383 static void
1384 moveRubik(rubikstruct * rp, int face, int direction, int position)
1385 {
1386         int         newFace, newDirection, rotate, reverse = False;
1387         int         h, k, newH = 0;
1388         int         i, j;
1389
1390         if (direction == CW || direction == CCW) {
1391                 direction = (direction == CCW) ?
1392                         (rotateToRow[face].direction + 2) % MAXORIENT :
1393                         rotateToRow[face].direction;
1394                 i = j = (rotateToRow[face].sideFace == RIGHT ||
1395                       rotateToRow[face].sideFace == BOTTOM) ? AVSIZE - 1 : 0;
1396                 face = rotateToRow[face].face;
1397                 position = j * AVSIZE + i;
1398         }
1399         i = position % AVSIZE;
1400         j = position / AVSIZE;
1401         h = (direction == TOP || direction == BOTTOM) ? i : j;
1402         /* rotate sides CW or CCW */
1403         if (h == AVSIZE - 1) {
1404                 newDirection = (direction == TOP || direction == BOTTOM) ?
1405                         TOP : RIGHT;
1406                 if (direction == TOP || direction == RIGHT)
1407                         rotateFace(rp, rowToRotate[face][newDirection], CW);
1408                 else            /* direction == BOTTOM || direction == LEFT */
1409                         rotateFace(rp, rowToRotate[face][newDirection], CCW);
1410         }
1411         if (h == 0) {
1412                 newDirection = (direction == TOP || direction == BOTTOM) ?
1413                         BOTTOM : LEFT;
1414                 if (direction == TOP || direction == RIGHT)
1415                         rotateFace(rp, rowToRotate[face][newDirection], CCW);
1416                 else            /* direction == BOTTOM  || direction == LEFT */
1417                         rotateFace(rp, rowToRotate[face][newDirection], CW);
1418         }
1419         /* Slide rows */
1420         readRC(rp, face, direction, h, 0, AVSIZE);
1421         for (k = 1; k <= MAXORIENT; k++) {
1422                 newFace = slideNextRow[face][direction].face;
1423                 rotate = slideNextRow[face][direction].rotation;
1424                 newDirection = (rotate + direction) % MAXORIENT;
1425                 switch (rotate) {
1426                         case TOP:
1427                                 newH = h;
1428                                 reverse = False;
1429                                 break;
1430                         case RIGHT:
1431                                 if (newDirection == TOP || newDirection == BOTTOM) {
1432                                         newH = AVSIZE - 1 - h;
1433                                         reverse = False;
1434                                 } else {        /* newDirection == RIGHT || newDirection == LEFT */
1435                                         newH = h;
1436                                         reverse = True;
1437                                 }
1438                                 break;
1439                         case BOTTOM:
1440                                 newH = AVSIZE - 1 - h;
1441                                 reverse = True;
1442                                 break;
1443                         case LEFT:
1444                                 if (newDirection == TOP || newDirection == BOTTOM) {
1445                                         newH = h;
1446                                         reverse = True;
1447                                 } else {        /* newDirection == RIGHT || newDirection == LEFT */
1448                                         newH = AVSIZE - 1 - h;
1449                                         reverse = False;
1450                                 }
1451                                 break;
1452                         default:
1453                                 (void) printf("moveRubik: rotate %d\n", rotate);
1454                 }
1455                 if (k != MAXORIENT)
1456                         readRC(rp, newFace, newDirection, newH, k, AVSIZE);
1457                 rotateRC(rp, rotate, k - 1, AVSIZE);
1458                 if (reverse == True)
1459                         reverseRC(rp, k - 1, AVSIZE);
1460                 writeRC(rp, newFace, newDirection, newH, k - 1, AVSIZE);
1461                 face = newFace;
1462                 direction = newDirection;
1463                 h = newH;
1464         }
1465 }
1466
1467 #ifdef DEBUG
1468 void
1469 printCube(rubikstruct * rp)
1470 {
1471         int         face, position;
1472
1473         for (face = 0; face < MAXFACES; face++) {
1474                 for (position = 0; position < AVSIZESQ; position++) {
1475                         (void) printf("%d %d  ", rp->cubeLoc[face][position].face,
1476                                       rp->cubeLoc[face][position].rotation);
1477                         if (!((position + 1) % AVSIZE))
1478                                 (void) printf("\n");
1479                 }
1480                 (void) printf("\n");
1481         }
1482         (void) printf("\n");
1483 }
1484
1485 #endif
1486
1487 static void
1488 evalmovement(ModeInfo * mi, RubikMove movement)
1489 {
1490         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1491
1492 #ifdef DEBUG
1493         printCube(rp);
1494 #endif
1495         if (movement.face < 0 || movement.face >= MAXFACES)
1496                 return;
1497
1498         moveRubik(rp, movement.face, movement.direction, movement.position);
1499
1500 }
1501
1502 static      Bool
1503 compare_moves(rubikstruct * rp, RubikMove move1, RubikMove move2, Bool opp)
1504 {
1505         RubikSlice  slice1, slice2;
1506
1507         slice1 = convertMove(rp, move1);
1508         slice2 = convertMove(rp, move2);
1509         if (slice1.face == slice2.face &&
1510             slice1.depth == slice2.depth) {
1511                 if (slice1.rotation == slice2.rotation) {       /* CW or CCW */
1512                         if (!opp)
1513                                 return True;
1514                 } else {
1515                         if (opp)
1516                                 return True;
1517                 }
1518         }
1519         return False;
1520 }
1521
1522 static void
1523 shuffle(ModeInfo * mi)
1524 {
1525         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1526         int         i, face, position;
1527         RubikMove   move;
1528
1529         AVSIZE = MI_SIZE(mi);
1530         if (AVSIZE < -MINSIZE)
1531                 AVSIZE = NRAND(-AVSIZE - MINSIZE + 1) + MINSIZE;
1532         else if (AVSIZE < MINSIZE)
1533                 AVSIZE = MINSIZE;
1534         /* Let me waste a little space for the moment */
1535         /* Future cube to be LxMxN and not just NxNxN, but not done yet */
1536         AVSIZESQ = AVSIZE * AVSIZE;
1537 #ifdef LMN
1538         MAXSIZEX = AVSIZE;
1539         MAXSIZEY = AVSIZE;
1540         MAXSIZEZ = AVSIZE;
1541         MAXSIZE = AVSIZE;
1542         MAXSIZESQ = AVSIZESQ;
1543 #endif
1544
1545         for (face = 0; face < MAXFACES; face++) {
1546                 if (rp->cubeLoc[face] != NULL)
1547                         (void) free((void *) rp->cubeLoc[face]);
1548                 if ((rp->cubeLoc[face] =
1549                   (RubikLoc *) malloc(AVSIZESQ * sizeof (RubikLoc))) == NULL)
1550                         (void) fprintf(stderr,
1551                                        "Could not allocate memory for rubik cube position info\n");
1552                 for (position = 0; position < AVSIZESQ; position++) {
1553                         rp->cubeLoc[face][position].face = face;
1554                         rp->cubeLoc[face][position].rotation = TOP;
1555                 }
1556         }
1557         for (i = 0; i < MAXORIENT; i++) {
1558                 if (rp->rowLoc[i] != NULL)
1559                         (void) free((void *) rp->rowLoc[i]);
1560                 if ((rp->rowLoc[i] =
1561                      (RubikLoc *) malloc(AVSIZE * sizeof (RubikLoc))) == NULL)
1562                         (void) fprintf(stderr,
1563                                        "Could not allocate memory for rubik row position info\n");
1564         }
1565         rp->storedmoves = MI_COUNT(mi);
1566         if (rp->storedmoves < 0) {
1567                 if (rp->moves != NULL)
1568                         (void) free((void *) rp->moves);
1569                 rp->moves = NULL;
1570                 rp->storedmoves = NRAND(-rp->storedmoves) + 1;
1571         }
1572         if ((rp->storedmoves) && (rp->moves == NULL))
1573                 if ((rp->moves =
1574                      (RubikMove *) calloc(rp->storedmoves + 1, sizeof (RubikMove))) == NULL)
1575                         (void) fprintf(stderr,
1576                         "Could not allocate memory for rubik move buffer\n");
1577
1578         if (MI_CYCLES(mi) <= 1) {
1579                 rp->anglestep = 90.0;
1580         } else {
1581                 rp->anglestep = 90.0 / (GLfloat) (MI_CYCLES(mi));
1582         }
1583
1584         for (i = 0; i < rp->storedmoves; i++) {
1585                 int         condition;
1586
1587                 do {
1588                         move.face = NRAND(6);
1589                         move.direction = NRAND(4);      /* Exclude CW and CCW, its ok */
1590                         /*
1591                          * Randomize position along diagonal, each plane gets an equal chance.
1592                          * This trick will only work for NxNxN cubes
1593                          * draw_cube DEPENDS on that they are chosen this way.
1594                          */
1595                         move.position = NRAND(AVSIZE) * (AVSIZE + 1);
1596
1597
1598                         condition = 1;
1599
1600                         if (i > 0)      /* avoid immediate undoing moves */
1601                                 if (compare_moves(rp, move, rp->moves[i - 1], True))
1602                                         condition = 0;
1603                         if (i > 1)      /* avoid 3 consecutive identical moves */
1604                                 if (compare_moves(rp, move, rp->moves[i - 1], False) &&
1605                                     compare_moves(rp, move, rp->moves[i - 2], False))
1606                                         condition = 0;
1607                         /*
1608                            * Still some silly moves being made....
1609                          */
1610                 } while (!condition);
1611                 if (hideshuffling)
1612                         evalmovement(mi, move);
1613                 rp->moves[i] = move;
1614         }
1615
1616         rp->movement.face = NO_FACE;
1617         rp->rotatestep = 0;
1618         rp->action = hideshuffling ? ACTION_SOLVE : ACTION_SHUFFLE;
1619         rp->shufflingmoves = 0;
1620         rp->done = 0;
1621 }
1622
1623 void
1624 reshape_rubik(ModeInfo * mi, int width, int height)
1625 {
1626         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1627
1628         glViewport(0, 0, rp->WindW = (GLint) width, rp->WindH = (GLint) height);
1629         glMatrixMode(GL_PROJECTION);
1630         glLoadIdentity();
1631         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
1632         glMatrixMode(GL_MODELVIEW);
1633
1634         rp->AreObjectsDefined[ObjCubit] = 0;
1635 }
1636
1637 static void
1638 pinit(ModeInfo * mi)
1639 {
1640         glClearDepth(1.0);
1641         glClearColor(0.0, 0.0, 0.0, 1.0);
1642         glColor3f(1.0, 1.0, 1.0);
1643
1644         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
1645         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
1646         glLightfv(GL_LIGHT0, GL_POSITION, position0);
1647         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
1648         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
1649         glLightfv(GL_LIGHT1, GL_POSITION, position1);
1650         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1651         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1652         glEnable(GL_LIGHTING);
1653         glEnable(GL_LIGHT0);
1654         glEnable(GL_LIGHT1);
1655         glEnable(GL_DEPTH_TEST);
1656         glEnable(GL_NORMALIZE);
1657         glEnable(GL_CULL_FACE);
1658
1659         glShadeModel(GL_FLAT);
1660         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1661         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1662
1663         shuffle(mi);
1664 }
1665
1666 void
1667 init_rubik(ModeInfo * mi)
1668 {
1669         int         screen = MI_SCREEN(mi);
1670         rubikstruct *rp;
1671
1672         if (rubik == NULL) {
1673                 if ((rubik = (rubikstruct *) calloc(MI_NUM_SCREENS(mi),
1674                                               sizeof (rubikstruct))) == NULL)
1675                         return;
1676         }
1677         rp = &rubik[screen];
1678         rp->step = NRAND(90);
1679
1680         if ((rp->glx_context = init_GL(mi)) != NULL) {
1681
1682                 reshape_rubik(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1683                 objects = glGenLists(1);
1684                 pinit(mi);
1685         } else {
1686                 MI_CLEARWINDOW(mi);
1687         }
1688 }
1689
1690 void
1691 draw_rubik(ModeInfo * mi)
1692 {
1693         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1694         Display    *display = MI_DISPLAY(mi);
1695         Window      window = MI_WINDOW(mi);
1696
1697         MI_IS_DRAWN(mi) = True;
1698
1699         if (!rp->glx_context)
1700                 return;
1701
1702         glDrawBuffer(GL_BACK);
1703         glXMakeCurrent(display, window, *(rp->glx_context));
1704
1705         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1706
1707         glPushMatrix();
1708
1709         glTranslatef(0.0, 0.0, -10.0);
1710
1711     {
1712       static int frame = 0;
1713       GLfloat x, y, z;
1714 #     define SINOID(SCALE,SIZE) \
1715         ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
1716       x = SINOID(0.0071, 2.0);
1717       y = SINOID(0.0053, 2.0);
1718       z = SINOID(0.0037, 4.0);
1719       frame++;
1720       glTranslatef(x, y, z);
1721     }
1722
1723         if (!MI_IS_ICONIC(mi)) {
1724                 glScalef(Scale4Window * rp->WindH / rp->WindW, Scale4Window, Scale4Window);
1725         } else {
1726                 glScalef(Scale4Iconic * rp->WindH / rp->WindW, Scale4Iconic, Scale4Iconic);
1727         }
1728
1729         glRotatef(rp->step * 100, 1, 0, 0);
1730         glRotatef(rp->step * 95, 0, 1, 0);
1731         glRotatef(rp->step * 90, 0, 0, 1);
1732
1733         draw_cube(mi);
1734     if (mi->fps_p) do_fps (mi);
1735         glXSwapBuffers(display, window);
1736
1737         if (rp->action == ACTION_SHUFFLE) {
1738                 if (rp->done) {
1739                         if (++rp->rotatestep > DELAY_AFTER_SHUFFLING) {
1740                                 rp->movement.face = NO_FACE;
1741                                 rp->rotatestep = 0;
1742                                 rp->action = ACTION_SOLVE;
1743                                 rp->done = 0;
1744                         }
1745                 } else {
1746                         if (rp->movement.face == NO_FACE) {
1747                                 if (rp->shufflingmoves < rp->storedmoves) {
1748                                         rp->rotatestep = 0;
1749                                         rp->movement = rp->moves[rp->shufflingmoves];
1750                                 } else {
1751                                         rp->rotatestep = 0;
1752                                         rp->done = 1;
1753                                 }
1754                         } else {
1755                                 rp->rotatestep += rp->anglestep;
1756                                 if (rp->rotatestep > 90) {
1757                                         evalmovement(mi, rp->movement);
1758                                         rp->shufflingmoves++;
1759                                         rp->movement.face = NO_FACE;
1760                                 }
1761                         }
1762                 }
1763         } else {
1764                 if (rp->done) {
1765                         if (++rp->rotatestep > DELAY_AFTER_SOLVING)
1766                                 shuffle(mi);
1767                 } else {
1768                         if (rp->movement.face == NO_FACE) {
1769                                 if (rp->storedmoves > 0) {
1770                                         rp->rotatestep = 0;
1771                                         rp->movement = rp->moves[rp->storedmoves - 1];
1772                                         rp->movement.direction = (rp->movement.direction + (MAXORIENT / 2)) %
1773                                                 MAXORIENT;
1774                                 } else {
1775                                         rp->rotatestep = 0;
1776                                         rp->done = 1;
1777                                 }
1778                         } else {
1779                                 rp->rotatestep += rp->anglestep;
1780                                 if (rp->rotatestep > 90) {
1781                                         evalmovement(mi, rp->movement);
1782                                         rp->storedmoves--;
1783                                         rp->movement.face = NO_FACE;
1784                                 }
1785                         }
1786                 }
1787         }
1788
1789         glPopMatrix();
1790
1791         glFlush();
1792
1793         rp->step += 0.05;
1794 }
1795
1796 void
1797 change_rubik(ModeInfo * mi)
1798 {
1799         rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1800
1801         if (!rp->glx_context)
1802                 return;
1803         pinit(mi);
1804 }
1805
1806 void
1807 release_rubik(ModeInfo * mi)
1808 {
1809         if (rubik != NULL) {
1810                 int         screen;
1811
1812                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1813                         rubikstruct *rp = &rubik[screen];
1814                         int         i;
1815
1816                         for (i = 0; i < MAXFACES; i++)
1817                                 if (rp->cubeLoc[i] != NULL)
1818                                         (void) free((void *) rp->cubeLoc[i]);
1819                         for (i = 0; i < MAXORIENT; i++)
1820                                 if (rp->rowLoc[i] != NULL)
1821                                         (void) free((void *) rp->rowLoc[i]);
1822                         if (rp->moves != NULL)
1823                                 (void) free((void *) rp->moves);
1824                 }
1825                 (void) free((void *) rubik);
1826                 rubik = NULL;
1827         }
1828         FreeAllGL(mi);
1829 }
1830
1831 #endif