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