1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* rubik --- Shows a auto-solving Rubik's cube */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)rubik.c 4.07 97/11/24 xlockmore";
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.
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.
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.
29 * Thanks goes also to Brian Paul for making it possible and inexpensive
30 * to use OpenGL at home.
32 * Since I'm not a native English speaker, my apologies for any grammatical
35 * My e-mail address is
38 * Marcelo F. Vianna (Jul-31-1997)
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
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... :)
67 * Color labels mapping:
68 * =====================
78 * +-----------+------------+-----------+
82 * | LEFT(1) | FRONT(2) | RIGHT(3) |
86 * +-----------+------------+-----------+
90 * | BOTTOM(4) | rp->faces[N][X+AVSIZE*Y]=
91 * | | rp->cubeLoc[N][X+AVSIZE*Y]=
94 * +------------+ | | | |
95 * |0--> | | 0 | 1 | 2 |
98 * | BACK(5) | | 3 | 4 | 5 |
102 * +------------+ +---+---+---+
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.
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
123 #include <X11/Intrinsic.h>
126 # define PROGCLASS "Rubik"
127 # define HACK_INIT init_rubik
128 # define HACK_DRAW draw_rubik
129 # define HACK_RESHAPE reshape_rubik
130 # define rubik_opts xlockmore_opts
131 # define DEFAULTS "*delay: 40000 \n" \
133 "*showFPS: False \n" \
136 # include "xlockmore.h" /* from the xscreensaver distribution */
137 #else /* !STANDALONE */
138 # include "xlock.h" /* from the xlockmore distribution */
140 #endif /* !STANDALONE */
144 #define DEF_HIDESHUFFLING "False"
146 static Bool hideshuffling;
148 static XrmOptionDescRec opts[] =
150 {"-hideshuffling", ".rubik.hideshuffling", XrmoptionNoArg, (caddr_t) "on"},
151 {"+hideshuffling", ".rubik.hideshuffling", XrmoptionNoArg, (caddr_t) "off"}
154 static argtype vars[] =
156 {(caddr_t *) & hideshuffling, "hideshuffling", "Hideshuffling", DEF_HIDESHUFFLING, t_Bool}
159 static OptionStruct desc[] =
161 {"-/+hideshuffling", "turn on/off hidden shuffle phase"}
164 ModeSpecOpt rubik_opts =
165 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
168 ModStruct rubik_description =
169 {"rubik", "init_rubik", "draw_rubik", "release_rubik",
170 "draw_rubik", "change_rubik", NULL, &rubik_opts,
171 10000, -30, 5, -6, 4, 1.0, "",
172 "Shows an auto-solving Rubik's Cube", 0, NULL};
176 #define VectMul(X1,Y1,Z1,X2,Y2,Z2) (Y1)*(Z2)-(Z1)*(Y2),(Z1)*(X2)-(X1)*(Z2),(X1)*(Y2)-(Y1)*(X2)
177 #define sqr(A) ((A)*(A))
184 #define ACTION_SOLVE 1
185 #define ACTION_SHUFFLE 0
187 #define DELAY_AFTER_SHUFFLING 5
188 #define DELAY_AFTER_SOLVING 20
190 /*************************************************************************/
193 #ifdef LMN /* LxMxN not completed yet... */
194 #define MAXSIZEX (rp->sizex)
195 #define MAXSIZEY (rp->sizey)
196 #define MAXSIZEZ (rp->sizez)
197 #define AVSIZE (rp->avsize)
198 #define MAXSIZE (rp->maxsize)
199 #define AVSIZESQ (rp->avsizeSq)
200 #define MAXSIZESQ (rp->maxsizeSq)
202 #define MAXSIZEX (rp->size)
203 #define MAXSIZEY (rp->size)
204 #define MAXSIZEZ (rp->size)
205 #define AVSIZE (rp->size)
206 #define MAXSIZE (rp->size)
207 #define AVSIZESQ (rp->sizeSq)
208 #define MAXSIZESQ (rp->sizeSq)
210 #define MAXSIZEXY (MAXSIZEX*MAXSIZEY)
211 #define MAXSIZEZY (MAXSIZEZ*MAXSIZEY)
212 #define MAXSIZEXZ (MAXSIZEX*MAXSIZEZ)
213 #define LASTX (MAXSIZEX-1)
214 #define LASTY (MAXSIZEY-1)
215 #define LASTZ (MAXSIZEZ-1)
216 /* These are not likely to change but... */
221 #define Scale4Window (0.9/AVSIZE)
222 #define Scale4Iconic (2.1/AVSIZE)
224 #define MAXORIENT 4 /* Number of orientations of a square */
225 #define MAXFACES 6 /* Number of faces */
227 /* Directions relative to the face of a cubie */
232 #define CW (MAXORIENT+1)
233 #define CCW (2*MAXORIENT-1)
239 #define BOTTOM_FACE 4
241 #define NO_FACE (MAXFACES)
242 #define NO_ROTATION (2*MAXORIENT)
243 #define NO_DEPTH MAXSIZE
245 #define REVX(a) (MAXSIZEX - a - 1)
246 #define REVY(a) (MAXSIZEY - a - 1)
247 #define REVZ(a) (MAXSIZEZ - a - 1)
249 typedef struct _RubikLoc {
251 int rotation; /* Not used yet */
254 typedef struct _RubikRowNext {
255 int face, direction, sideFace;
258 typedef struct _RubikMove {
263 typedef struct _RubikSlice {
269 * Pick a face and a direction on face the next face and orientation
272 static RubikLoc slideNextRow[MAXFACES][MAXORIENT] =
307 * Examine cubie 0 on each face, its 4 movements (well only 2 since the
308 * other 2 will be opposites) and translate it into slice movements).
309 * Beware.. using this for NxNxN makes some assumptions that referenced
310 * cubes are along the diagonal top-left to bottom-right.
311 * CW = DEEP Depth CCW == SHALLOW Depth with reference to faces 0, 1, and 2
313 static RubikLoc rotateSlice[MAXFACES][MAXORIENT / 2] =
342 * Rotate face clockwise by a number of orients, then the top of the
343 * face then points to this face
345 static int rowToRotate[MAXFACES][MAXORIENT] =
356 * This translates a clockwise move to something more manageable
358 static RubikRowNext rotateToRow[MAXFACES] = /*CW to min face */
374 #ifdef LMN /* Under construction */
375 int sizex, sizey, sizez;
377 int avsizeSq, maxsizeSq;
384 RubikLoc *cubeLoc[MAXFACES];
385 RubikLoc *rowLoc[MAXORIENT];
388 GLXContext *glx_context;
389 int AreObjectsDefined[1];
392 static float front_shininess[] =
394 static float front_specular[] =
395 {0.7, 0.7, 0.7, 1.0};
396 static float ambient[] =
397 {0.0, 0.0, 0.0, 1.0};
398 static float diffuse[] =
399 {1.0, 1.0, 1.0, 1.0};
400 static float position0[] =
401 {1.0, 1.0, 1.0, 0.0};
402 static float position1[] =
403 {-1.0, -1.0, 1.0, 0.0};
404 static float lmodel_ambient[] =
405 {0.5, 0.5, 0.5, 1.0};
406 static float lmodel_twoside[] =
409 static float MaterialRed[] =
410 {0.5, 0.0, 0.0, 1.0};
411 static float MaterialGreen[] =
412 {0.0, 0.5, 0.0, 1.0};
413 static float MaterialBlue[] =
414 {0.0, 0.0, 0.5, 1.0};
415 static float MaterialYellow[] =
416 {0.7, 0.7, 0.0, 1.0};
417 static float MaterialOrange[] =
418 {0.9, 0.45, 0.36, 1.0};
421 static float MaterialMagenta[] =
422 {0.7, 0.0, 0.7, 1.0};
423 static float MaterialCyan[] =
424 {0.0, 0.7, 0.7, 1.0};
427 static float MaterialWhite[] =
428 {0.8, 0.8, 0.8, 1.0};
429 static float MaterialGray[] =
430 {0.2, 0.2, 0.2, 1.0};
431 static float MaterialGray3[] =
432 {0.3, 0.3, 0.3, 1.0};
433 static float MaterialGray4[] =
434 {0.4, 0.4, 0.4, 1.0};
435 static float MaterialGray5[] =
436 {0.5, 0.5, 0.5, 1.0};
437 static float MaterialGray6[] =
438 {0.6, 0.6, 0.6, 1.0};
439 static float MaterialGray7[] =
440 {0.7, 0.7, 0.7, 1.0};
442 static rubikstruct *rubik = NULL;
443 static GLuint objects;
448 pickcolor(int C, int mono)
453 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray3);
455 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
459 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray6);
461 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
464 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
468 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray4);
470 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGreen);
474 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray7);
476 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialOrange);
480 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
482 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
485 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialCyan);
486 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialMagenta);
493 draw_cubit(ModeInfo * mi,
494 int back, int front, int left, int right, int bottom, int top)
496 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
497 int mono = MI_IS_MONO(mi);
499 if (!rp->AreObjectsDefined[ObjCubit]) {
500 glNewList(objects + ObjCubit, GL_COMPILE_AND_EXECUTE);
502 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
503 glNormal3f(0.00, 0.00, 1.00);
504 glVertex3f(-0.45, -0.45, 0.50);
505 glVertex3f(0.45, -0.45, 0.50);
506 glVertex3f(0.45, 0.45, 0.50);
507 glVertex3f(-0.45, 0.45, 0.50);
508 glNormal3f(0.00, 0.00, -1.00);
509 glVertex3f(-0.45, 0.45, -0.50);
510 glVertex3f(0.45, 0.45, -0.50);
511 glVertex3f(0.45, -0.45, -0.50);
512 glVertex3f(-0.45, -0.45, -0.50);
513 glNormal3f(-1.00, 0.00, 0.00);
514 glVertex3f(-0.50, -0.45, 0.45);
515 glVertex3f(-0.50, 0.45, 0.45);
516 glVertex3f(-0.50, 0.45, -0.45);
517 glVertex3f(-0.50, -0.45, -0.45);
518 glNormal3f(1.00, 0.00, 0.00);
519 glVertex3f(0.50, -0.45, -0.45);
520 glVertex3f(0.50, 0.45, -0.45);
521 glVertex3f(0.50, 0.45, 0.45);
522 glVertex3f(0.50, -0.45, 0.45);
523 glNormal3f(0.00, -1.00, 0.00);
524 glVertex3f(0.45, -0.50, -0.45);
525 glVertex3f(0.45, -0.50, 0.45);
526 glVertex3f(-0.45, -0.50, 0.45);
527 glVertex3f(-0.45, -0.50, -0.45);
528 glNormal3f(0.00, 1.00, 0.00);
529 glVertex3f(-0.45, 0.50, -0.45);
530 glVertex3f(-0.45, 0.50, 0.45);
531 glVertex3f(0.45, 0.50, 0.45);
532 glVertex3f(0.45, 0.50, -0.45);
533 glNormal3f(-1.00, -1.00, 0.00);
534 glVertex3f(-0.45, -0.50, -0.45);
535 glVertex3f(-0.45, -0.50, 0.45);
536 glVertex3f(-0.50, -0.45, 0.45);
537 glVertex3f(-0.50, -0.45, -0.45);
538 glNormal3f(1.00, 1.00, 0.00);
539 glVertex3f(0.45, 0.50, -0.45);
540 glVertex3f(0.45, 0.50, 0.45);
541 glVertex3f(0.50, 0.45, 0.45);
542 glVertex3f(0.50, 0.45, -0.45);
543 glNormal3f(-1.00, 1.00, 0.00);
544 glVertex3f(-0.50, 0.45, -0.45);
545 glVertex3f(-0.50, 0.45, 0.45);
546 glVertex3f(-0.45, 0.50, 0.45);
547 glVertex3f(-0.45, 0.50, -0.45);
548 glNormal3f(1.00, -1.00, 0.00);
549 glVertex3f(0.50, -0.45, -0.45);
550 glVertex3f(0.50, -0.45, 0.45);
551 glVertex3f(0.45, -0.50, 0.45);
552 glVertex3f(0.45, -0.50, -0.45);
553 glNormal3f(0.00, -1.00, -1.00);
554 glVertex3f(-0.45, -0.45, -0.50);
555 glVertex3f(0.45, -0.45, -0.50);
556 glVertex3f(0.45, -0.50, -0.45);
557 glVertex3f(-0.45, -0.50, -0.45);
558 glNormal3f(0.00, 1.00, 1.00);
559 glVertex3f(-0.45, 0.45, 0.50);
560 glVertex3f(0.45, 0.45, 0.50);
561 glVertex3f(0.45, 0.50, 0.45);
562 glVertex3f(-0.45, 0.50, 0.45);
563 glNormal3f(0.00, -1.00, 1.00);
564 glVertex3f(-0.45, -0.50, 0.45);
565 glVertex3f(0.45, -0.50, 0.45);
566 glVertex3f(0.45, -0.45, 0.50);
567 glVertex3f(-0.45, -0.45, 0.50);
568 glNormal3f(0.00, 1.00, -1.00);
569 glVertex3f(-0.45, 0.50, -0.45);
570 glVertex3f(0.45, 0.50, -0.45);
571 glVertex3f(0.45, 0.45, -0.50);
572 glVertex3f(-0.45, 0.45, -0.50);
573 glNormal3f(-1.00, 0.00, -1.00);
574 glVertex3f(-0.50, -0.45, -0.45);
575 glVertex3f(-0.50, 0.45, -0.45);
576 glVertex3f(-0.45, 0.45, -0.50);
577 glVertex3f(-0.45, -0.45, -0.50);
578 glNormal3f(1.00, 0.00, 1.00);
579 glVertex3f(0.50, -0.45, 0.45);
580 glVertex3f(0.50, 0.45, 0.45);
581 glVertex3f(0.45, 0.45, 0.50);
582 glVertex3f(0.45, -0.45, 0.50);
583 glNormal3f(1.00, 0.00, -1.00);
584 glVertex3f(0.45, -0.45, -0.50);
585 glVertex3f(0.45, 0.45, -0.50);
586 glVertex3f(0.50, 0.45, -0.45);
587 glVertex3f(0.50, -0.45, -0.45);
588 glNormal3f(-1.00, 0.00, 1.00);
589 glVertex3f(-0.45, -0.45, 0.50);
590 glVertex3f(-0.45, 0.45, 0.50);
591 glVertex3f(-0.50, 0.45, 0.45);
592 glVertex3f(-0.50, -0.45, 0.45);
594 glBegin(GL_TRIANGLES);
595 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
596 glNormal3f(1.00, 1.00, 1.00);
597 glVertex3f(0.45, 0.45, 0.50);
598 glVertex3f(0.50, 0.45, 0.45);
599 glVertex3f(0.45, 0.50, 0.45);
600 glNormal3f(-1.00, -1.00, -1.00);
601 glVertex3f(-0.45, -0.50, -0.45);
602 glVertex3f(-0.50, -0.45, -0.45);
603 glVertex3f(-0.45, -0.45, -0.50);
604 glNormal3f(-1.00, 1.00, 1.00);
605 glVertex3f(-0.45, 0.45, 0.50);
606 glVertex3f(-0.45, 0.50, 0.45);
607 glVertex3f(-0.50, 0.45, 0.45);
608 glNormal3f(1.00, -1.00, -1.00);
609 glVertex3f(0.50, -0.45, -0.45);
610 glVertex3f(0.45, -0.50, -0.45);
611 glVertex3f(0.45, -0.45, -0.50);
612 glNormal3f(1.00, -1.00, 1.00);
613 glVertex3f(0.45, -0.45, 0.50);
614 glVertex3f(0.45, -0.50, 0.45);
615 glVertex3f(0.50, -0.45, 0.45);
616 glNormal3f(-1.00, 1.00, -1.00);
617 glVertex3f(-0.50, 0.45, -0.45);
618 glVertex3f(-0.45, 0.50, -0.45);
619 glVertex3f(-0.45, 0.45, -0.50);
620 glNormal3f(-1.00, -1.00, 1.00);
621 glVertex3f(-0.45, -0.45, 0.50);
622 glVertex3f(-0.50, -0.45, 0.45);
623 glVertex3f(-0.45, -0.50, 0.45);
624 glNormal3f(1.00, 1.00, -1.00);
625 glVertex3f(0.50, 0.45, -0.45);
626 glVertex3f(0.45, 0.45, -0.50);
627 glVertex3f(0.45, 0.50, -0.45);
630 rp->AreObjectsDefined[ObjCubit] = 1;
632 (void) printf("Cubit drawn SLOWLY\n");
635 glCallList(objects + ObjCubit);
637 (void) printf("Cubit drawn quickly\n");
641 if (back != NO_FACE) {
643 pickcolor(back, mono);
644 glNormal3f(0.00, 0.00, -1.00);
645 glVertex3f(-0.35, 0.40, -0.51);
646 glVertex3f(0.35, 0.40, -0.51);
647 glVertex3f(0.40, 0.35, -0.51);
648 glVertex3f(0.40, -0.35, -0.51);
649 glVertex3f(0.35, -0.40, -0.51);
650 glVertex3f(-0.35, -0.40, -0.51);
651 glVertex3f(-0.40, -0.35, -0.51);
652 glVertex3f(-0.40, 0.35, -0.51);
655 if (front != NO_FACE) {
657 pickcolor(front, mono);
658 glNormal3f(0.00, 0.00, 1.00);
659 glVertex3f(-0.35, -0.40, 0.51);
660 glVertex3f(0.35, -0.40, 0.51);
661 glVertex3f(0.40, -0.35, 0.51);
662 glVertex3f(0.40, 0.35, 0.51);
663 glVertex3f(0.35, 0.40, 0.51);
664 glVertex3f(-0.35, 0.40, 0.51);
665 glVertex3f(-0.40, 0.35, 0.51);
666 glVertex3f(-0.40, -0.35, 0.51);
669 if (left != NO_FACE) {
671 pickcolor(left, mono);
672 glNormal3f(-1.00, 0.00, 0.00);
673 glVertex3f(-0.51, -0.35, 0.40);
674 glVertex3f(-0.51, 0.35, 0.40);
675 glVertex3f(-0.51, 0.40, 0.35);
676 glVertex3f(-0.51, 0.40, -0.35);
677 glVertex3f(-0.51, 0.35, -0.40);
678 glVertex3f(-0.51, -0.35, -0.40);
679 glVertex3f(-0.51, -0.40, -0.35);
680 glVertex3f(-0.51, -0.40, 0.35);
683 if (right != NO_FACE) {
685 pickcolor(right, mono);
686 glNormal3f(1.00, 0.00, 0.00);
687 glVertex3f(0.51, -0.35, -0.40);
688 glVertex3f(0.51, 0.35, -0.40);
689 glVertex3f(0.51, 0.40, -0.35);
690 glVertex3f(0.51, 0.40, 0.35);
691 glVertex3f(0.51, 0.35, 0.40);
692 glVertex3f(0.51, -0.35, 0.40);
693 glVertex3f(0.51, -0.40, 0.35);
694 glVertex3f(0.51, -0.40, -0.35);
697 if (bottom != NO_FACE) {
699 pickcolor(bottom, mono);
700 glNormal3f(0.00, -1.00, 0.00);
701 glVertex3f(0.40, -0.51, -0.35);
702 glVertex3f(0.40, -0.51, 0.35);
703 glVertex3f(0.35, -0.51, 0.40);
704 glVertex3f(-0.35, -0.51, 0.40);
705 glVertex3f(-0.40, -0.51, 0.35);
706 glVertex3f(-0.40, -0.51, -0.35);
707 glVertex3f(-0.35, -0.51, -0.40);
708 glVertex3f(0.35, -0.51, -0.40);
711 if (top != NO_FACE) {
713 pickcolor(top, mono);
714 glNormal3f(0.00, 1.00, 0.00);
715 glVertex3f(-0.40, 0.51, -0.35);
716 glVertex3f(-0.40, 0.51, 0.35);
717 glVertex3f(-0.35, 0.51, 0.40);
718 glVertex3f(0.35, 0.51, 0.40);
719 glVertex3f(0.40, 0.51, 0.35);
720 glVertex3f(0.40, 0.51, -0.35);
721 glVertex3f(0.35, 0.51, -0.40);
722 glVertex3f(-0.35, 0.51, -0.40);
729 convertMove(rubikstruct * rp, RubikMove move)
734 plane = rotateSlice[(int) move.face][move.direction % 2];
735 slice.face = plane.face;
736 slice.rotation = plane.rotation;
737 if (slice.rotation == CW) /* I just know this to be true... */
738 slice.depth = AVSIZESQ - 1 - move.position;
740 slice.depth = move.position;
741 slice.depth = slice.depth / AVSIZE;
742 /* If slice.depth = 0 then face 0, face 1, or face 2 moves */
743 if (move.direction / 2)
744 slice.rotation = (plane.rotation == CW) ? CCW : CW;
748 /* Assume for the moment that the size is at least 2 */
750 draw_cube(ModeInfo * mi)
753 #define SX ((GLint)S1*(MAXSIZEX-1))
754 #define SY ((GLint)S1*(MAXSIZEY-1))
755 #define SZ ((GLint)S1*(MAXSIZEZ-1))
756 #define HALFX (((GLfloat)MAXSIZEX-1.0)/2.0)
757 #define HALFY (((GLfloat)MAXSIZEY-1.0)/2.0)
758 #define HALFZ (((GLfloat)MAXSIZEZ-1.0)/2.0)
759 #define MIDX(a) (((GLfloat)(2*a-MAXSIZEX+1))/2.0)
760 #define MIDY(a) (((GLfloat)(2*a-MAXSIZEY+1))/2.0)
761 #define MIDZ(a) (((GLfloat)(2*a-MAXSIZEZ+1))/2.0)
762 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
767 if (rp->movement.face == NO_FACE) {
768 slice.face = NO_FACE;
769 slice.rotation = NO_ROTATION;
770 slice.depth = NO_DEPTH;
772 slice = convertMove(rp, rp->movement);
774 rotatestep = (slice.rotation == CCW) ? rp->rotatestep : -rp->rotatestep;
777 * The glRotatef() routine transforms the coordinate system for every future
778 * vertex specification (this is not so simple, but by now comprehending this
779 * is sufficient). So if you want to rotate the inner slice, you can draw
780 * one slice, rotate the anglestep for the centerslice, draw the inner slice,
781 * rotate reversely and draw the other slice.
782 * There is a sequence for drawing cubies for each axis being moved...
784 switch (slice.face) {
786 case TOP_FACE: /* BOTTOM_FACE too */
788 if (slice.depth == MAXSIZEY - 1)
789 glRotatef(rotatestep, 0, HALFY, 0);
791 glTranslatef(-HALFX, -HALFY, -HALFZ);
793 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
794 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
795 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
796 for (k = 1; k < MAXSIZEZ - 1; k++) {
797 glTranslatef(0, 0, S1);
800 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
801 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
803 glTranslatef(0, 0, S1);
805 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
806 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
807 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
808 for (i = 1; i < MAXSIZEX - 1; i++) {
809 glTranslatef(S1, 0, -SZ);
811 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
813 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
814 for (k = 1; k < MAXSIZEZ - 1; k++) {
815 glTranslatef(0, 0, S1);
819 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
821 glTranslatef(0, 0, S1);
823 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
825 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
827 glTranslatef(1, 0, -SZ);
829 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
830 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
831 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
832 for (k = 1; k < MAXSIZEZ - 1; k++) {
833 glTranslatef(0, 0, S1);
836 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
837 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
839 glTranslatef(0, 0, S1);
841 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
842 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
843 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
845 for (j = 1; j < MAXSIZEY - 1; j++) {
847 if (slice.depth == REVY(j))
848 glRotatef(rotatestep, 0, HALFY, 0);
849 glTranslatef(-HALFX, MIDY(j), -HALFZ);
851 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
852 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
854 for (k = 1; k < MAXSIZEZ - 1; k++) {
855 glTranslatef(0, 0, S1);
858 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
861 glTranslatef(0, 0, S1);
863 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
864 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
866 for (i = 1; i < MAXSIZEX - 1; i++) {
867 glTranslatef(1, 0, -SZ);
869 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
873 glTranslatef(0, 0, SZ);
875 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
879 glTranslatef(S1, 0, -SZ);
881 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
882 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
884 for (k = 1; k < MAXSIZEZ - 1; k++) {
885 glTranslatef(0, 0, S1);
888 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
891 glTranslatef(0, 0, S1);
893 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
894 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
898 if (slice.depth == 0)
899 glRotatef(rotatestep, 0, HALFY, 0);
901 glTranslatef(-HALFX, HALFY, -HALFZ);
903 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
904 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
905 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
906 for (k = 1; k < MAXSIZEZ - 1; k++) {
907 glTranslatef(0, 0, S1);
910 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
911 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
913 glTranslatef(0, 0, S1);
915 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
916 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
917 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
918 for (i = 1; i < MAXSIZEX - 1; i++) {
919 glTranslatef(S1, 0, -SZ);
921 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
923 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
924 for (k = 1; k < MAXSIZEZ - 1; k++) {
925 glTranslatef(0, 0, S1);
929 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
931 glTranslatef(0, 0, S1);
933 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
935 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
937 glTranslatef(S1, 0, -SZ);
939 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
940 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
941 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
942 for (k = 1; k < MAXSIZEZ - 1; k++) {
943 glTranslatef(0, 0, S1);
946 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
947 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
949 glTranslatef(0, 0, S1);
951 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
952 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
953 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
955 case LEFT_FACE: /* RIGHT_FACE too */
956 /* rotatestep is negative because the RIGHT face is the default here */
958 if (slice.depth == 0)
959 glRotatef(-rotatestep, HALFX, 0, 0);
961 glTranslatef(-HALFX, -HALFY, -HALFZ);
963 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
964 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
965 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
966 for (j = 1; j < MAXSIZEY - 1; j++) {
967 glTranslatef(0, S1, 0);
969 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
970 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
973 glTranslatef(0, S1, 0);
975 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
976 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
977 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
978 for (k = 1; k < MAXSIZEZ - 1; k++) {
979 glTranslatef(0, -SY, S1);
982 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
983 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
984 for (j = 1; j < MAXSIZEY - 1; j++) {
985 glTranslatef(0, S1, 0);
988 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
991 glTranslatef(0, S1, 0);
994 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
995 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
997 glTranslatef(0, -SY, S1);
999 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1000 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1001 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1002 for (j = 1; j < MAXSIZEY - 1; j++) {
1003 glTranslatef(0, S1, 0);
1005 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1006 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1009 glTranslatef(0, S1, 0);
1011 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1012 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1013 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1015 for (i = 1; i < MAXSIZEX - 1; i++) {
1017 if (slice.depth == i)
1018 glRotatef(-rotatestep, HALFX, 0, 0);
1019 glTranslatef(MIDX(i), -HALFY, -HALFZ);
1021 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1023 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1024 for (j = 1; j < MAXSIZEY - 1; j++) {
1025 glTranslatef(0, S1, 0);
1027 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1031 glTranslatef(0, S1, 0);
1033 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1035 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1036 for (k = 1; k < MAXSIZEZ - 1; k++) {
1037 glTranslatef(0, -SY, S1);
1041 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1043 glTranslatef(0, SY, 0);
1047 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1049 glTranslatef(0, -SY, S1);
1051 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1053 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1054 for (j = 1; j < MAXSIZEY - 1; j++) {
1055 glTranslatef(0, S1, 0);
1057 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1061 glTranslatef(0, S1, 0);
1063 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1065 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1068 if (slice.depth == MAXSIZEX - 1)
1069 glRotatef(-rotatestep, HALFX, 0, 0);
1070 glTranslatef(HALFX, -HALFY, -HALFZ);
1072 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1073 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1074 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1075 for (j = 1; j < MAXSIZEY - 1; j++) {
1076 glTranslatef(0, S1, 0);
1078 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1079 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1082 glTranslatef(0, S1, 0);
1084 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1085 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1086 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1087 for (k = 1; k < MAXSIZEZ - 1; k++) {
1088 glTranslatef(0, -SY, S1);
1091 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1092 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1093 for (j = 1; j < MAXSIZEY - 1; j++) {
1094 glTranslatef(0, S1, 0);
1097 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1100 glTranslatef(0, S1, 0);
1103 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1104 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1106 glTranslatef(0, -SY, S1);
1108 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1109 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1110 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1111 for (j = 1; j < MAXSIZEY - 1; j++) {
1112 glTranslatef(0, S1, 0);
1114 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1115 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1118 glTranslatef(0, S1, 0);
1120 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1121 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1122 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1124 case FRONT_FACE: /* BACK_FACE too */
1126 if (slice.depth == MAXSIZEZ - 1)
1127 glRotatef(rotatestep, 0, 0, HALFZ);
1129 glTranslatef(-HALFX, -HALFY, -HALFZ);
1131 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1132 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1133 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
1134 for (i = 1; i < MAXSIZEX - 1; i++) {
1135 glTranslatef(S1, 0, 0);
1137 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1139 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1141 glTranslatef(S1, 0, 0);
1143 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1144 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1145 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1146 for (j = 1; j < MAXSIZEY - 1; j++) {
1147 glTranslatef(-SX, S1, 0);
1149 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
1150 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1152 for (i = 1; i < MAXSIZEX - 1; i++) {
1153 glTranslatef(S1, 0, 0);
1155 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1159 glTranslatef(S1, 0, 0);
1161 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1162 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1165 glTranslatef(-SX, S1, 0);
1167 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
1168 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1169 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
1170 for (i = 1; i < MAXSIZEX - 1; i++) {
1171 glTranslatef(S1, 0, 0);
1173 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1175 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1177 glTranslatef(S1, 0, 0);
1179 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1180 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1181 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1183 for (k = 1; k < MAXSIZEZ - 1; k++) {
1185 if (slice.depth == REVZ(k))
1186 glRotatef(rotatestep, 0, 0, HALFZ);
1187 glTranslatef(-HALFX, -HALFY, MIDZ(k));
1190 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
1191 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1192 for (i = 1; i < MAXSIZEX - 1; i++) {
1193 glTranslatef(S1, 0, 0);
1197 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1199 glTranslatef(S1, 0, 0);
1202 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1203 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1204 for (j = 1; j < MAXSIZEY - 1; j++) {
1205 glTranslatef(-SX, S1, 0);
1208 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
1211 glTranslatef(SX, 0, 0);
1214 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1217 glTranslatef(-SX, S1, 0);
1220 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
1221 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
1222 for (i = 1; i < MAXSIZEX - 1; i++) {
1223 glTranslatef(S1, 0, 0);
1227 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1229 glTranslatef(S1, 0, 0);
1232 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1233 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1236 if (slice.depth == 0)
1237 glRotatef(rotatestep, 0, 0, HALFZ);
1238 glTranslatef(-HALFX, -HALFY, HALFZ);
1240 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1241 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1242 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1243 for (i = 1; i < MAXSIZEX - 1; i++) {
1244 glTranslatef(S1, 0, 0);
1246 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1248 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1250 glTranslatef(S1, 0, 0);
1252 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1253 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1254 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1255 for (j = 1; j < MAXSIZEY - 1; j++) {
1256 glTranslatef(-SX, S1, 0);
1258 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1259 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1261 for (i = 1; i < MAXSIZEX - 1; i++) {
1262 glTranslatef(S1, 0, 0);
1264 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1268 glTranslatef(S1, 0, 0);
1270 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1271 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1274 glTranslatef(-SX, S1, 0);
1276 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1277 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1278 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1279 for (i = 1; i < MAXSIZEX - 1; i++) {
1280 glTranslatef(S1, 0, 0);
1282 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1284 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1286 glTranslatef(S1, 0, 0);
1288 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1289 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1290 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1296 /* From David Bagley's xrubik. Used by permission. ;) */
1298 readRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1302 if (dir == TOP || dir == BOTTOM)
1303 for (g = 0; g < size; g++)
1304 rp->rowLoc[orient][g] =
1305 rp->cubeLoc[face][g * size + h];
1306 else /* dir == RIGHT || dir == LEFT */
1307 for (g = 0; g < size; g++)
1308 rp->rowLoc[orient][g] =
1309 rp->cubeLoc[face][h * size + g];
1313 rotateRC(rubikstruct * rp, int rotate, int orient, int size)
1317 for (g = 0; g < size; g++)
1318 rp->rowLoc[orient][g].rotation =
1319 (rp->rowLoc[orient][g].rotation + rotate) % MAXORIENT;
1323 reverseRC(rubikstruct * rp, int orient, int size)
1328 for (g = 0; g < size / 2; g++) {
1329 temp = rp->rowLoc[orient][size - 1 - g];
1330 rp->rowLoc[orient][size - 1 - g] = rp->rowLoc[orient][g];
1331 rp->rowLoc[orient][g] = temp;
1336 writeRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1340 if (dir == TOP || dir == BOTTOM) {
1341 for (g = 0; g < size; g++) {
1342 position = g * size + h;
1343 rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1344 /* DrawSquare(face, position); */
1346 } else { /* dir == RIGHT || dir == LEFT */
1347 for (g = 0; g < size; g++) {
1348 position = h * size + g;
1349 rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1350 /* DrawSquare(face, position); */
1356 rotateFace(rubikstruct * rp, int face, int direction)
1359 RubikLoc *faceLoc = NULL;
1361 if ((faceLoc = (RubikLoc *) malloc(AVSIZESQ * sizeof (RubikLoc))) == NULL)
1362 (void) fprintf(stderr,
1363 "Could not allocate memory for rubik face position info\n");
1365 for (position = 0; position < AVSIZESQ; position++)
1366 faceLoc[position] = rp->cubeLoc[face][position];
1368 for (position = 0; position < AVSIZESQ; position++) {
1369 i = position % AVSIZE;
1370 j = position / AVSIZE;
1371 rp->cubeLoc[face][position] = (direction == CW) ?
1372 faceLoc[(AVSIZE - i - 1) * AVSIZE + j] :
1373 faceLoc[i * AVSIZE + AVSIZE - j - 1];
1374 rp->cubeLoc[face][position].rotation =
1375 (rp->cubeLoc[face][position].rotation + direction - MAXORIENT) %
1377 /* DrawSquare(face, position); */
1379 if (faceLoc != NULL)
1380 (void) free((void *) faceLoc);
1384 moveRubik(rubikstruct * rp, int face, int direction, int position)
1386 int newFace, newDirection, rotate, reverse = False;
1390 if (direction == CW || direction == CCW) {
1391 direction = (direction == CCW) ?
1392 (rotateToRow[face].direction + 2) % MAXORIENT :
1393 rotateToRow[face].direction;
1394 i = j = (rotateToRow[face].sideFace == RIGHT ||
1395 rotateToRow[face].sideFace == BOTTOM) ? AVSIZE - 1 : 0;
1396 face = rotateToRow[face].face;
1397 position = j * AVSIZE + i;
1399 i = position % AVSIZE;
1400 j = position / AVSIZE;
1401 h = (direction == TOP || direction == BOTTOM) ? i : j;
1402 /* rotate sides CW or CCW */
1403 if (h == AVSIZE - 1) {
1404 newDirection = (direction == TOP || direction == BOTTOM) ?
1406 if (direction == TOP || direction == RIGHT)
1407 rotateFace(rp, rowToRotate[face][newDirection], CW);
1408 else /* direction == BOTTOM || direction == LEFT */
1409 rotateFace(rp, rowToRotate[face][newDirection], CCW);
1412 newDirection = (direction == TOP || direction == BOTTOM) ?
1414 if (direction == TOP || direction == RIGHT)
1415 rotateFace(rp, rowToRotate[face][newDirection], CCW);
1416 else /* direction == BOTTOM || direction == LEFT */
1417 rotateFace(rp, rowToRotate[face][newDirection], CW);
1420 readRC(rp, face, direction, h, 0, AVSIZE);
1421 for (k = 1; k <= MAXORIENT; k++) {
1422 newFace = slideNextRow[face][direction].face;
1423 rotate = slideNextRow[face][direction].rotation;
1424 newDirection = (rotate + direction) % MAXORIENT;
1431 if (newDirection == TOP || newDirection == BOTTOM) {
1432 newH = AVSIZE - 1 - h;
1434 } else { /* newDirection == RIGHT || newDirection == LEFT */
1440 newH = AVSIZE - 1 - h;
1444 if (newDirection == TOP || newDirection == BOTTOM) {
1447 } else { /* newDirection == RIGHT || newDirection == LEFT */
1448 newH = AVSIZE - 1 - h;
1453 (void) printf("moveRubik: rotate %d\n", rotate);
1456 readRC(rp, newFace, newDirection, newH, k, AVSIZE);
1457 rotateRC(rp, rotate, k - 1, AVSIZE);
1458 if (reverse == True)
1459 reverseRC(rp, k - 1, AVSIZE);
1460 writeRC(rp, newFace, newDirection, newH, k - 1, AVSIZE);
1462 direction = newDirection;
1469 printCube(rubikstruct * rp)
1473 for (face = 0; face < MAXFACES; face++) {
1474 for (position = 0; position < AVSIZESQ; position++) {
1475 (void) printf("%d %d ", rp->cubeLoc[face][position].face,
1476 rp->cubeLoc[face][position].rotation);
1477 if (!((position + 1) % AVSIZE))
1478 (void) printf("\n");
1480 (void) printf("\n");
1482 (void) printf("\n");
1488 evalmovement(ModeInfo * mi, RubikMove movement)
1490 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1495 if (movement.face < 0 || movement.face >= MAXFACES)
1498 moveRubik(rp, movement.face, movement.direction, movement.position);
1503 compare_moves(rubikstruct * rp, RubikMove move1, RubikMove move2, Bool opp)
1505 RubikSlice slice1, slice2;
1507 slice1 = convertMove(rp, move1);
1508 slice2 = convertMove(rp, move2);
1509 if (slice1.face == slice2.face &&
1510 slice1.depth == slice2.depth) {
1511 if (slice1.rotation == slice2.rotation) { /* CW or CCW */
1523 shuffle(ModeInfo * mi)
1525 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1526 int i, face, position;
1529 AVSIZE = MI_SIZE(mi);
1530 if (AVSIZE < -MINSIZE)
1531 AVSIZE = NRAND(-AVSIZE - MINSIZE + 1) + MINSIZE;
1532 else if (AVSIZE < MINSIZE)
1534 /* Let me waste a little space for the moment */
1535 /* Future cube to be LxMxN and not just NxNxN, but not done yet */
1536 AVSIZESQ = AVSIZE * AVSIZE;
1542 MAXSIZESQ = AVSIZESQ;
1545 for (face = 0; face < MAXFACES; face++) {
1546 if (rp->cubeLoc[face] != NULL)
1547 (void) free((void *) rp->cubeLoc[face]);
1548 if ((rp->cubeLoc[face] =
1549 (RubikLoc *) malloc(AVSIZESQ * sizeof (RubikLoc))) == NULL)
1550 (void) fprintf(stderr,
1551 "Could not allocate memory for rubik cube position info\n");
1552 for (position = 0; position < AVSIZESQ; position++) {
1553 rp->cubeLoc[face][position].face = face;
1554 rp->cubeLoc[face][position].rotation = TOP;
1557 for (i = 0; i < MAXORIENT; i++) {
1558 if (rp->rowLoc[i] != NULL)
1559 (void) free((void *) rp->rowLoc[i]);
1560 if ((rp->rowLoc[i] =
1561 (RubikLoc *) malloc(AVSIZE * sizeof (RubikLoc))) == NULL)
1562 (void) fprintf(stderr,
1563 "Could not allocate memory for rubik row position info\n");
1565 rp->storedmoves = MI_COUNT(mi);
1566 if (rp->storedmoves < 0) {
1567 if (rp->moves != NULL)
1568 (void) free((void *) rp->moves);
1570 rp->storedmoves = NRAND(-rp->storedmoves) + 1;
1572 if ((rp->storedmoves) && (rp->moves == NULL))
1574 (RubikMove *) calloc(rp->storedmoves + 1, sizeof (RubikMove))) == NULL)
1575 (void) fprintf(stderr,
1576 "Could not allocate memory for rubik move buffer\n");
1578 if (MI_CYCLES(mi) <= 1) {
1579 rp->anglestep = 90.0;
1581 rp->anglestep = 90.0 / (GLfloat) (MI_CYCLES(mi));
1584 for (i = 0; i < rp->storedmoves; i++) {
1588 move.face = NRAND(6);
1589 move.direction = NRAND(4); /* Exclude CW and CCW, its ok */
1591 * Randomize position along diagonal, each plane gets an equal chance.
1592 * This trick will only work for NxNxN cubes
1593 * draw_cube DEPENDS on that they are chosen this way.
1595 move.position = NRAND(AVSIZE) * (AVSIZE + 1);
1600 if (i > 0) /* avoid immediate undoing moves */
1601 if (compare_moves(rp, move, rp->moves[i - 1], True))
1603 if (i > 1) /* avoid 3 consecutive identical moves */
1604 if (compare_moves(rp, move, rp->moves[i - 1], False) &&
1605 compare_moves(rp, move, rp->moves[i - 2], False))
1608 * Still some silly moves being made....
1610 } while (!condition);
1612 evalmovement(mi, move);
1613 rp->moves[i] = move;
1616 rp->movement.face = NO_FACE;
1618 rp->action = hideshuffling ? ACTION_SOLVE : ACTION_SHUFFLE;
1619 rp->shufflingmoves = 0;
1624 reshape_rubik(ModeInfo * mi, int width, int height)
1626 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1628 glViewport(0, 0, rp->WindW = (GLint) width, rp->WindH = (GLint) height);
1629 glMatrixMode(GL_PROJECTION);
1631 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
1632 glMatrixMode(GL_MODELVIEW);
1634 rp->AreObjectsDefined[ObjCubit] = 0;
1638 pinit(ModeInfo * mi)
1641 glClearColor(0.0, 0.0, 0.0, 1.0);
1642 glColor3f(1.0, 1.0, 1.0);
1644 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
1645 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
1646 glLightfv(GL_LIGHT0, GL_POSITION, position0);
1647 glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
1648 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
1649 glLightfv(GL_LIGHT1, GL_POSITION, position1);
1650 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1651 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1652 glEnable(GL_LIGHTING);
1653 glEnable(GL_LIGHT0);
1654 glEnable(GL_LIGHT1);
1655 glEnable(GL_DEPTH_TEST);
1656 glEnable(GL_NORMALIZE);
1657 glEnable(GL_CULL_FACE);
1659 glShadeModel(GL_FLAT);
1660 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1661 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1667 init_rubik(ModeInfo * mi)
1669 int screen = MI_SCREEN(mi);
1672 if (rubik == NULL) {
1673 if ((rubik = (rubikstruct *) calloc(MI_NUM_SCREENS(mi),
1674 sizeof (rubikstruct))) == NULL)
1677 rp = &rubik[screen];
1678 rp->step = NRAND(90);
1680 if ((rp->glx_context = init_GL(mi)) != NULL) {
1682 reshape_rubik(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1683 objects = glGenLists(1);
1691 draw_rubik(ModeInfo * mi)
1693 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1694 Display *display = MI_DISPLAY(mi);
1695 Window window = MI_WINDOW(mi);
1697 MI_IS_DRAWN(mi) = True;
1699 if (!rp->glx_context)
1702 glDrawBuffer(GL_BACK);
1703 glXMakeCurrent(display, window, *(rp->glx_context));
1705 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1709 glTranslatef(0.0, 0.0, -10.0);
1712 static int frame = 0;
1714 # define SINOID(SCALE,SIZE) \
1715 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
1716 x = SINOID(0.0071, 2.0);
1717 y = SINOID(0.0053, 2.0);
1718 z = SINOID(0.0037, 4.0);
1720 glTranslatef(x, y, z);
1723 if (!MI_IS_ICONIC(mi)) {
1724 glScalef(Scale4Window * rp->WindH / rp->WindW, Scale4Window, Scale4Window);
1726 glScalef(Scale4Iconic * rp->WindH / rp->WindW, Scale4Iconic, Scale4Iconic);
1729 glRotatef(rp->step * 100, 1, 0, 0);
1730 glRotatef(rp->step * 95, 0, 1, 0);
1731 glRotatef(rp->step * 90, 0, 0, 1);
1734 if (mi->fps_p) do_fps (mi);
1735 glXSwapBuffers(display, window);
1737 if (rp->action == ACTION_SHUFFLE) {
1739 if (++rp->rotatestep > DELAY_AFTER_SHUFFLING) {
1740 rp->movement.face = NO_FACE;
1742 rp->action = ACTION_SOLVE;
1746 if (rp->movement.face == NO_FACE) {
1747 if (rp->shufflingmoves < rp->storedmoves) {
1749 rp->movement = rp->moves[rp->shufflingmoves];
1755 rp->rotatestep += rp->anglestep;
1756 if (rp->rotatestep > 90) {
1757 evalmovement(mi, rp->movement);
1758 rp->shufflingmoves++;
1759 rp->movement.face = NO_FACE;
1765 if (++rp->rotatestep > DELAY_AFTER_SOLVING)
1768 if (rp->movement.face == NO_FACE) {
1769 if (rp->storedmoves > 0) {
1771 rp->movement = rp->moves[rp->storedmoves - 1];
1772 rp->movement.direction = (rp->movement.direction + (MAXORIENT / 2)) %
1779 rp->rotatestep += rp->anglestep;
1780 if (rp->rotatestep > 90) {
1781 evalmovement(mi, rp->movement);
1783 rp->movement.face = NO_FACE;
1797 change_rubik(ModeInfo * mi)
1799 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1801 if (!rp->glx_context)
1807 release_rubik(ModeInfo * mi)
1809 if (rubik != NULL) {
1812 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1813 rubikstruct *rp = &rubik[screen];
1816 for (i = 0; i < MAXFACES; i++)
1817 if (rp->cubeLoc[i] != NULL)
1818 (void) free((void *) rp->cubeLoc[i]);
1819 for (i = 0; i < MAXORIENT; i++)
1820 if (rp->rowLoc[i] != NULL)
1821 (void) free((void *) rp->rowLoc[i]);
1822 if (rp->moves != NULL)
1823 (void) free((void *) rp->moves);
1825 (void) free((void *) rubik);