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