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 addresses are
40 * Marcelo F. Vianna (Jul-31-1997)
43 * 26-Sep-98: Added some more movement (the cube do not stays in the screen
44 * center anymore. Also fixed the scale problem imediatelly after
45 * shuffling when the puzzle is solved.
46 * 08-Aug-97: Now has some internals from xrubik by David Bagley
47 * This should make it easier to add features.
48 * 02-Aug-97: Now behaves more like puzzle.c: first show the cube being
49 * shuffled and then being solved. A mode specific option was added:
50 * "+/-hideshuffling" to provide the original behavior (in which
51 * only the solution is shown).
52 * The color labels corners are now rounded.
53 * Optimized the cubit() routine using glLists.
54 * 01-Aug-97: Shuffling now avoids movements that undoes the previous movement
55 * and three consecutive identical moves (which is pretty stupid).
56 * improved the "cycles" option in replacement of David's hack,
57 * now rp->anglestep is a GLfloat, so this option selects the
58 * "exact" number of frames that a rotation (movement) takes to
60 * 30-Jul-97: Initial release, there is no algorithm to solve the puzzle,
61 * instead, it randomly shuffle the cube and then make the
62 * movements in the reverse order.
63 * The mode was written in 1 day (I got sick and had the day off).
64 * There was not much to do since I could not leave home... :)
69 * Color labels mapping:
70 * =====================
80 * +-----------+------------+-----------+
84 * | LEFT(1) | FRONT(2) | RIGHT(3) |
88 * +-----------+------------+-----------+
92 * | BOTTOM(4) | rp->faces[N][X+AVSIZE*Y]=
93 * | | rp->cubeLoc[N][X+AVSIZE*Y]=
96 * +------------+ | | | |
97 * |0--> | | 0 | 1 | 2 |
100 * | BACK(5) | | 3 | 4 | 5 |
104 * +------------+ +---+---+---+
116 * PURIFY 3.0a on SunOS4 reports an unitialized memory read on each of
117 * the glCallList() functions below when using MesaGL 2.1. This has
118 * been fixed in MesaGL 2.2 and later releases.
122 * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
123 * otherwise caddr_t is not defined correctly
125 #include <X11/Intrinsic.h>
128 # define PROGCLASS "Rubik"
129 # define HACK_INIT init_rubik
130 # define HACK_DRAW draw_rubik
131 # define rubik_opts xlockmore_opts
132 # define DEFAULTS "*delay: 40000 \n" \
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 GLfloat PX, PY, VX, VY;
389 GLXContext *glx_context;
390 int AreObjectsDefined[1];
393 static float front_shininess[] =
395 static float front_specular[] =
396 {0.7, 0.7, 0.7, 1.0};
397 static float ambient[] =
398 {0.0, 0.0, 0.0, 1.0};
399 static float diffuse[] =
400 {1.0, 1.0, 1.0, 1.0};
401 static float position0[] =
402 {1.0, 1.0, 1.0, 0.0};
403 static float position1[] =
404 {-1.0, -1.0, 1.0, 0.0};
405 static float lmodel_ambient[] =
406 {0.5, 0.5, 0.5, 1.0};
407 static float lmodel_twoside[] =
410 static float MaterialRed[] =
411 {0.5, 0.0, 0.0, 1.0};
412 static float MaterialGreen[] =
413 {0.0, 0.5, 0.0, 1.0};
414 static float MaterialBlue[] =
415 {0.0, 0.0, 0.5, 1.0};
416 static float MaterialYellow[] =
417 {0.7, 0.7, 0.0, 1.0};
418 static float MaterialOrange[] =
419 {0.9, 0.45, 0.36, 1.0};
422 static float MaterialMagenta[] =
423 {0.7, 0.0, 0.7, 1.0};
424 static float MaterialCyan[] =
425 {0.0, 0.7, 0.7, 1.0};
428 static float MaterialWhite[] =
429 {0.8, 0.8, 0.8, 1.0};
430 static float MaterialGray[] =
431 {0.2, 0.2, 0.2, 1.0};
432 static float MaterialGray3[] =
433 {0.3, 0.3, 0.3, 1.0};
434 static float MaterialGray4[] =
435 {0.4, 0.4, 0.4, 1.0};
436 static float MaterialGray5[] =
437 {0.5, 0.5, 0.5, 1.0};
438 static float MaterialGray6[] =
439 {0.6, 0.6, 0.6, 1.0};
440 static float MaterialGray7[] =
441 {0.7, 0.7, 0.7, 1.0};
443 static rubikstruct *rubik = NULL;
444 static GLuint objects;
449 pickcolor(int C, int mono)
454 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray3);
456 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
460 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray6);
462 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
465 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
469 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray4);
471 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGreen);
475 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray7);
477 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialOrange);
481 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
483 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
486 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialCyan);
487 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialMagenta);
494 draw_cubit(ModeInfo * mi,
495 int back, int front, int left, int right, int bottom, int top)
497 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
498 int mono = MI_IS_MONO(mi);
500 if (!rp->AreObjectsDefined[ObjCubit]) {
501 glNewList(objects + ObjCubit, GL_COMPILE_AND_EXECUTE);
503 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
504 glNormal3f(0.00, 0.00, 1.00);
505 glVertex3f(-0.45, -0.45, 0.50);
506 glVertex3f(0.45, -0.45, 0.50);
507 glVertex3f(0.45, 0.45, 0.50);
508 glVertex3f(-0.45, 0.45, 0.50);
509 glNormal3f(0.00, 0.00, -1.00);
510 glVertex3f(-0.45, 0.45, -0.50);
511 glVertex3f(0.45, 0.45, -0.50);
512 glVertex3f(0.45, -0.45, -0.50);
513 glVertex3f(-0.45, -0.45, -0.50);
514 glNormal3f(-1.00, 0.00, 0.00);
515 glVertex3f(-0.50, -0.45, 0.45);
516 glVertex3f(-0.50, 0.45, 0.45);
517 glVertex3f(-0.50, 0.45, -0.45);
518 glVertex3f(-0.50, -0.45, -0.45);
519 glNormal3f(1.00, 0.00, 0.00);
520 glVertex3f(0.50, -0.45, -0.45);
521 glVertex3f(0.50, 0.45, -0.45);
522 glVertex3f(0.50, 0.45, 0.45);
523 glVertex3f(0.50, -0.45, 0.45);
524 glNormal3f(0.00, -1.00, 0.00);
525 glVertex3f(0.45, -0.50, -0.45);
526 glVertex3f(0.45, -0.50, 0.45);
527 glVertex3f(-0.45, -0.50, 0.45);
528 glVertex3f(-0.45, -0.50, -0.45);
529 glNormal3f(0.00, 1.00, 0.00);
530 glVertex3f(-0.45, 0.50, -0.45);
531 glVertex3f(-0.45, 0.50, 0.45);
532 glVertex3f(0.45, 0.50, 0.45);
533 glVertex3f(0.45, 0.50, -0.45);
534 glNormal3f(-1.00, -1.00, 0.00);
535 glVertex3f(-0.45, -0.50, -0.45);
536 glVertex3f(-0.45, -0.50, 0.45);
537 glVertex3f(-0.50, -0.45, 0.45);
538 glVertex3f(-0.50, -0.45, -0.45);
539 glNormal3f(1.00, 1.00, 0.00);
540 glVertex3f(0.45, 0.50, -0.45);
541 glVertex3f(0.45, 0.50, 0.45);
542 glVertex3f(0.50, 0.45, 0.45);
543 glVertex3f(0.50, 0.45, -0.45);
544 glNormal3f(-1.00, 1.00, 0.00);
545 glVertex3f(-0.50, 0.45, -0.45);
546 glVertex3f(-0.50, 0.45, 0.45);
547 glVertex3f(-0.45, 0.50, 0.45);
548 glVertex3f(-0.45, 0.50, -0.45);
549 glNormal3f(1.00, -1.00, 0.00);
550 glVertex3f(0.50, -0.45, -0.45);
551 glVertex3f(0.50, -0.45, 0.45);
552 glVertex3f(0.45, -0.50, 0.45);
553 glVertex3f(0.45, -0.50, -0.45);
554 glNormal3f(0.00, -1.00, -1.00);
555 glVertex3f(-0.45, -0.45, -0.50);
556 glVertex3f(0.45, -0.45, -0.50);
557 glVertex3f(0.45, -0.50, -0.45);
558 glVertex3f(-0.45, -0.50, -0.45);
559 glNormal3f(0.00, 1.00, 1.00);
560 glVertex3f(-0.45, 0.45, 0.50);
561 glVertex3f(0.45, 0.45, 0.50);
562 glVertex3f(0.45, 0.50, 0.45);
563 glVertex3f(-0.45, 0.50, 0.45);
564 glNormal3f(0.00, -1.00, 1.00);
565 glVertex3f(-0.45, -0.50, 0.45);
566 glVertex3f(0.45, -0.50, 0.45);
567 glVertex3f(0.45, -0.45, 0.50);
568 glVertex3f(-0.45, -0.45, 0.50);
569 glNormal3f(0.00, 1.00, -1.00);
570 glVertex3f(-0.45, 0.50, -0.45);
571 glVertex3f(0.45, 0.50, -0.45);
572 glVertex3f(0.45, 0.45, -0.50);
573 glVertex3f(-0.45, 0.45, -0.50);
574 glNormal3f(-1.00, 0.00, -1.00);
575 glVertex3f(-0.50, -0.45, -0.45);
576 glVertex3f(-0.50, 0.45, -0.45);
577 glVertex3f(-0.45, 0.45, -0.50);
578 glVertex3f(-0.45, -0.45, -0.50);
579 glNormal3f(1.00, 0.00, 1.00);
580 glVertex3f(0.50, -0.45, 0.45);
581 glVertex3f(0.50, 0.45, 0.45);
582 glVertex3f(0.45, 0.45, 0.50);
583 glVertex3f(0.45, -0.45, 0.50);
584 glNormal3f(1.00, 0.00, -1.00);
585 glVertex3f(0.45, -0.45, -0.50);
586 glVertex3f(0.45, 0.45, -0.50);
587 glVertex3f(0.50, 0.45, -0.45);
588 glVertex3f(0.50, -0.45, -0.45);
589 glNormal3f(-1.00, 0.00, 1.00);
590 glVertex3f(-0.45, -0.45, 0.50);
591 glVertex3f(-0.45, 0.45, 0.50);
592 glVertex3f(-0.50, 0.45, 0.45);
593 glVertex3f(-0.50, -0.45, 0.45);
595 glBegin(GL_TRIANGLES);
596 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
597 glNormal3f(1.00, 1.00, 1.00);
598 glVertex3f(0.45, 0.45, 0.50);
599 glVertex3f(0.50, 0.45, 0.45);
600 glVertex3f(0.45, 0.50, 0.45);
601 glNormal3f(-1.00, -1.00, -1.00);
602 glVertex3f(-0.45, -0.50, -0.45);
603 glVertex3f(-0.50, -0.45, -0.45);
604 glVertex3f(-0.45, -0.45, -0.50);
605 glNormal3f(-1.00, 1.00, 1.00);
606 glVertex3f(-0.45, 0.45, 0.50);
607 glVertex3f(-0.45, 0.50, 0.45);
608 glVertex3f(-0.50, 0.45, 0.45);
609 glNormal3f(1.00, -1.00, -1.00);
610 glVertex3f(0.50, -0.45, -0.45);
611 glVertex3f(0.45, -0.50, -0.45);
612 glVertex3f(0.45, -0.45, -0.50);
613 glNormal3f(1.00, -1.00, 1.00);
614 glVertex3f(0.45, -0.45, 0.50);
615 glVertex3f(0.45, -0.50, 0.45);
616 glVertex3f(0.50, -0.45, 0.45);
617 glNormal3f(-1.00, 1.00, -1.00);
618 glVertex3f(-0.50, 0.45, -0.45);
619 glVertex3f(-0.45, 0.50, -0.45);
620 glVertex3f(-0.45, 0.45, -0.50);
621 glNormal3f(-1.00, -1.00, 1.00);
622 glVertex3f(-0.45, -0.45, 0.50);
623 glVertex3f(-0.50, -0.45, 0.45);
624 glVertex3f(-0.45, -0.50, 0.45);
625 glNormal3f(1.00, 1.00, -1.00);
626 glVertex3f(0.50, 0.45, -0.45);
627 glVertex3f(0.45, 0.45, -0.50);
628 glVertex3f(0.45, 0.50, -0.45);
631 rp->AreObjectsDefined[ObjCubit] = 1;
633 (void) printf("Cubit drawn SLOWLY\n");
636 glCallList(objects + ObjCubit);
638 (void) printf("Cubit drawn quickly\n");
642 if (back != NO_FACE) {
644 pickcolor(back, mono);
645 glNormal3f(0.00, 0.00, -1.00);
646 glVertex3f(-0.35, 0.40, -0.51);
647 glVertex3f(0.35, 0.40, -0.51);
648 glVertex3f(0.40, 0.35, -0.51);
649 glVertex3f(0.40, -0.35, -0.51);
650 glVertex3f(0.35, -0.40, -0.51);
651 glVertex3f(-0.35, -0.40, -0.51);
652 glVertex3f(-0.40, -0.35, -0.51);
653 glVertex3f(-0.40, 0.35, -0.51);
656 if (front != NO_FACE) {
658 pickcolor(front, mono);
659 glNormal3f(0.00, 0.00, 1.00);
660 glVertex3f(-0.35, -0.40, 0.51);
661 glVertex3f(0.35, -0.40, 0.51);
662 glVertex3f(0.40, -0.35, 0.51);
663 glVertex3f(0.40, 0.35, 0.51);
664 glVertex3f(0.35, 0.40, 0.51);
665 glVertex3f(-0.35, 0.40, 0.51);
666 glVertex3f(-0.40, 0.35, 0.51);
667 glVertex3f(-0.40, -0.35, 0.51);
670 if (left != NO_FACE) {
672 pickcolor(left, mono);
673 glNormal3f(-1.00, 0.00, 0.00);
674 glVertex3f(-0.51, -0.35, 0.40);
675 glVertex3f(-0.51, 0.35, 0.40);
676 glVertex3f(-0.51, 0.40, 0.35);
677 glVertex3f(-0.51, 0.40, -0.35);
678 glVertex3f(-0.51, 0.35, -0.40);
679 glVertex3f(-0.51, -0.35, -0.40);
680 glVertex3f(-0.51, -0.40, -0.35);
681 glVertex3f(-0.51, -0.40, 0.35);
684 if (right != NO_FACE) {
686 pickcolor(right, mono);
687 glNormal3f(1.00, 0.00, 0.00);
688 glVertex3f(0.51, -0.35, -0.40);
689 glVertex3f(0.51, 0.35, -0.40);
690 glVertex3f(0.51, 0.40, -0.35);
691 glVertex3f(0.51, 0.40, 0.35);
692 glVertex3f(0.51, 0.35, 0.40);
693 glVertex3f(0.51, -0.35, 0.40);
694 glVertex3f(0.51, -0.40, 0.35);
695 glVertex3f(0.51, -0.40, -0.35);
698 if (bottom != NO_FACE) {
700 pickcolor(bottom, mono);
701 glNormal3f(0.00, -1.00, 0.00);
702 glVertex3f(0.40, -0.51, -0.35);
703 glVertex3f(0.40, -0.51, 0.35);
704 glVertex3f(0.35, -0.51, 0.40);
705 glVertex3f(-0.35, -0.51, 0.40);
706 glVertex3f(-0.40, -0.51, 0.35);
707 glVertex3f(-0.40, -0.51, -0.35);
708 glVertex3f(-0.35, -0.51, -0.40);
709 glVertex3f(0.35, -0.51, -0.40);
712 if (top != NO_FACE) {
714 pickcolor(top, mono);
715 glNormal3f(0.00, 1.00, 0.00);
716 glVertex3f(-0.40, 0.51, -0.35);
717 glVertex3f(-0.40, 0.51, 0.35);
718 glVertex3f(-0.35, 0.51, 0.40);
719 glVertex3f(0.35, 0.51, 0.40);
720 glVertex3f(0.40, 0.51, 0.35);
721 glVertex3f(0.40, 0.51, -0.35);
722 glVertex3f(0.35, 0.51, -0.40);
723 glVertex3f(-0.35, 0.51, -0.40);
730 convertMove(rubikstruct * rp, RubikMove move)
735 plane = rotateSlice[(int) move.face][move.direction % 2];
736 slice.face = plane.face;
737 slice.rotation = plane.rotation;
738 if (slice.rotation == CW) /* I just know this to be true... */
739 slice.depth = AVSIZESQ - 1 - move.position;
741 slice.depth = move.position;
742 slice.depth = slice.depth / AVSIZE;
743 /* If slice.depth = 0 then face 0, face 1, or face 2 moves */
744 if (move.direction / 2)
745 slice.rotation = (plane.rotation == CW) ? CCW : CW;
749 /* Assume for the moment that the size is at least 2 */
751 draw_cube(ModeInfo * mi)
754 #define SX ((GLint)S1*(MAXSIZEX-1))
755 #define SY ((GLint)S1*(MAXSIZEY-1))
756 #define SZ ((GLint)S1*(MAXSIZEZ-1))
757 #define HALFX (((GLfloat)MAXSIZEX-1.0)/2.0)
758 #define HALFY (((GLfloat)MAXSIZEY-1.0)/2.0)
759 #define HALFZ (((GLfloat)MAXSIZEZ-1.0)/2.0)
760 #define MIDX(a) (((GLfloat)(2*a-MAXSIZEX+1))/2.0)
761 #define MIDY(a) (((GLfloat)(2*a-MAXSIZEY+1))/2.0)
762 #define MIDZ(a) (((GLfloat)(2*a-MAXSIZEZ+1))/2.0)
763 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
768 if (rp->movement.face == NO_FACE) {
769 slice.face = NO_FACE;
770 slice.rotation = NO_ROTATION;
771 slice.depth = NO_DEPTH;
773 slice = convertMove(rp, rp->movement);
775 rotatestep = (slice.rotation == CCW) ? rp->rotatestep : -rp->rotatestep;
778 * The glRotatef() routine transforms the coordinate system for every future
779 * vertex specification (this is not so simple, but by now comprehending this
780 * is sufficient). So if you want to rotate the inner slice, you can draw
781 * one slice, rotate the anglestep for the centerslice, draw the inner slice,
782 * rotate reversely and draw the other slice.
783 * There is a sequence for drawing cubies for each axis being moved...
785 switch (slice.face) {
787 case TOP_FACE: /* BOTTOM_FACE too */
789 if (slice.depth == MAXSIZEY - 1)
790 glRotatef(rotatestep, 0, HALFY, 0);
792 glTranslatef(-HALFX, -HALFY, -HALFZ);
794 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
795 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
796 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
797 for (k = 1; k < MAXSIZEZ - 1; k++) {
798 glTranslatef(0, 0, S1);
801 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
802 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
804 glTranslatef(0, 0, S1);
806 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
807 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
808 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
809 for (i = 1; i < MAXSIZEX - 1; i++) {
810 glTranslatef(S1, 0, -SZ);
812 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
814 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
815 for (k = 1; k < MAXSIZEZ - 1; k++) {
816 glTranslatef(0, 0, S1);
820 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
822 glTranslatef(0, 0, S1);
824 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
826 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
828 glTranslatef(1, 0, -SZ);
830 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
831 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
832 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
833 for (k = 1; k < MAXSIZEZ - 1; k++) {
834 glTranslatef(0, 0, S1);
837 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
838 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
840 glTranslatef(0, 0, S1);
842 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
843 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
844 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
846 for (j = 1; j < MAXSIZEY - 1; j++) {
848 if (slice.depth == REVY(j))
849 glRotatef(rotatestep, 0, HALFY, 0);
850 glTranslatef(-HALFX, MIDY(j), -HALFZ);
852 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
853 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
855 for (k = 1; k < MAXSIZEZ - 1; k++) {
856 glTranslatef(0, 0, S1);
859 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
862 glTranslatef(0, 0, S1);
864 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
865 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
867 for (i = 1; i < MAXSIZEX - 1; i++) {
868 glTranslatef(1, 0, -SZ);
870 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
874 glTranslatef(0, 0, SZ);
876 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
880 glTranslatef(S1, 0, -SZ);
882 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
883 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
885 for (k = 1; k < MAXSIZEZ - 1; k++) {
886 glTranslatef(0, 0, S1);
889 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
892 glTranslatef(0, 0, S1);
894 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
895 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
899 if (slice.depth == 0)
900 glRotatef(rotatestep, 0, HALFY, 0);
902 glTranslatef(-HALFX, HALFY, -HALFZ);
904 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
905 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
906 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
907 for (k = 1; k < MAXSIZEZ - 1; k++) {
908 glTranslatef(0, 0, S1);
911 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
912 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
914 glTranslatef(0, 0, S1);
916 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
917 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
918 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
919 for (i = 1; i < MAXSIZEX - 1; i++) {
920 glTranslatef(S1, 0, -SZ);
922 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
924 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
925 for (k = 1; k < MAXSIZEZ - 1; k++) {
926 glTranslatef(0, 0, S1);
930 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
932 glTranslatef(0, 0, S1);
934 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
936 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
938 glTranslatef(S1, 0, -SZ);
940 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
941 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
942 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
943 for (k = 1; k < MAXSIZEZ - 1; k++) {
944 glTranslatef(0, 0, S1);
947 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
948 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
950 glTranslatef(0, 0, S1);
952 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
953 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
954 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
956 case LEFT_FACE: /* RIGHT_FACE too */
957 /* rotatestep is negative because the RIGHT face is the default here */
959 if (slice.depth == 0)
960 glRotatef(-rotatestep, HALFX, 0, 0);
962 glTranslatef(-HALFX, -HALFY, -HALFZ);
964 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
965 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
966 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
967 for (j = 1; j < MAXSIZEY - 1; j++) {
968 glTranslatef(0, S1, 0);
970 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
971 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
974 glTranslatef(0, S1, 0);
976 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
977 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
978 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
979 for (k = 1; k < MAXSIZEZ - 1; k++) {
980 glTranslatef(0, -SY, S1);
983 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
984 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
985 for (j = 1; j < MAXSIZEY - 1; j++) {
986 glTranslatef(0, S1, 0);
989 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
992 glTranslatef(0, S1, 0);
995 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
996 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
998 glTranslatef(0, -SY, S1);
1000 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1001 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1002 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1003 for (j = 1; j < MAXSIZEY - 1; j++) {
1004 glTranslatef(0, S1, 0);
1006 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1007 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1010 glTranslatef(0, S1, 0);
1012 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1013 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1014 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1016 for (i = 1; i < MAXSIZEX - 1; i++) {
1018 if (slice.depth == i)
1019 glRotatef(-rotatestep, HALFX, 0, 0);
1020 glTranslatef(MIDX(i), -HALFY, -HALFZ);
1022 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1024 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1025 for (j = 1; j < MAXSIZEY - 1; j++) {
1026 glTranslatef(0, S1, 0);
1028 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1032 glTranslatef(0, S1, 0);
1034 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1036 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1037 for (k = 1; k < MAXSIZEZ - 1; k++) {
1038 glTranslatef(0, -SY, S1);
1042 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1044 glTranslatef(0, SY, 0);
1048 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1050 glTranslatef(0, -SY, S1);
1052 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1054 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1055 for (j = 1; j < MAXSIZEY - 1; j++) {
1056 glTranslatef(0, S1, 0);
1058 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1062 glTranslatef(0, S1, 0);
1064 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1066 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1069 if (slice.depth == MAXSIZEX - 1)
1070 glRotatef(-rotatestep, HALFX, 0, 0);
1071 glTranslatef(HALFX, -HALFY, -HALFZ);
1073 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1074 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1075 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1076 for (j = 1; j < MAXSIZEY - 1; j++) {
1077 glTranslatef(0, S1, 0);
1079 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1080 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1083 glTranslatef(0, S1, 0);
1085 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1086 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1087 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1088 for (k = 1; k < MAXSIZEZ - 1; k++) {
1089 glTranslatef(0, -SY, S1);
1092 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1093 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1094 for (j = 1; j < MAXSIZEY - 1; j++) {
1095 glTranslatef(0, S1, 0);
1098 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1101 glTranslatef(0, S1, 0);
1104 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1105 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1107 glTranslatef(0, -SY, S1);
1109 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1110 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1111 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1112 for (j = 1; j < MAXSIZEY - 1; j++) {
1113 glTranslatef(0, S1, 0);
1115 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1116 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1119 glTranslatef(0, S1, 0);
1121 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1122 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1123 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1125 case FRONT_FACE: /* BACK_FACE too */
1127 if (slice.depth == MAXSIZEZ - 1)
1128 glRotatef(rotatestep, 0, 0, HALFZ);
1130 glTranslatef(-HALFX, -HALFY, -HALFZ);
1132 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1133 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1134 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * LASTZ].face, NO_FACE);
1135 for (i = 1; i < MAXSIZEX - 1; i++) {
1136 glTranslatef(S1, 0, 0);
1138 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * FIRSTY].face, NO_FACE,
1140 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * LASTZ].face, NO_FACE);
1142 glTranslatef(S1, 0, 0);
1144 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * FIRSTY].face, NO_FACE,
1145 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * LASTY].face,
1146 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * LASTZ].face, NO_FACE);
1147 for (j = 1; j < MAXSIZEY - 1; j++) {
1148 glTranslatef(-SX, S1, 0);
1150 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * j].face, NO_FACE,
1151 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1153 for (i = 1; i < MAXSIZEX - 1; i++) {
1154 glTranslatef(S1, 0, 0);
1156 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * j].face, NO_FACE,
1160 glTranslatef(S1, 0, 0);
1162 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * j].face, NO_FACE,
1163 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face,
1166 glTranslatef(-SX, S1, 0);
1168 rp->cubeLoc[BACK_FACE][FIRSTX + MAXSIZEX * LASTY].face, NO_FACE,
1169 rp->cubeLoc[LEFT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1170 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face);
1171 for (i = 1; i < MAXSIZEX - 1; i++) {
1172 glTranslatef(S1, 0, 0);
1174 rp->cubeLoc[BACK_FACE][i + MAXSIZEX * LASTY].face, NO_FACE,
1176 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * FIRSTZ].face);
1178 glTranslatef(S1, 0, 0);
1180 rp->cubeLoc[BACK_FACE][LASTX + MAXSIZEX * LASTY].face, NO_FACE,
1181 NO_FACE, rp->cubeLoc[RIGHT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face,
1182 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * FIRSTZ].face);
1184 for (k = 1; k < MAXSIZEZ - 1; k++) {
1186 if (slice.depth == REVZ(k))
1187 glRotatef(rotatestep, 0, 0, HALFZ);
1188 glTranslatef(-HALFX, -HALFY, MIDZ(k));
1191 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * LASTY].face, NO_FACE,
1192 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1193 for (i = 1; i < MAXSIZEX - 1; i++) {
1194 glTranslatef(S1, 0, 0);
1198 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * REVZ(k)].face, NO_FACE);
1200 glTranslatef(S1, 0, 0);
1203 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * LASTY].face,
1204 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * REVZ(k)].face, NO_FACE);
1205 for (j = 1; j < MAXSIZEY - 1; j++) {
1206 glTranslatef(-SX, S1, 0);
1209 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * REVY(j)].face, NO_FACE,
1212 glTranslatef(SX, 0, 0);
1215 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * REVY(j)].face,
1218 glTranslatef(-SX, S1, 0);
1221 rp->cubeLoc[LEFT_FACE][k + MAXSIZEZ * FIRSTY].face, NO_FACE,
1222 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * k].face);
1223 for (i = 1; i < MAXSIZEX - 1; i++) {
1224 glTranslatef(S1, 0, 0);
1228 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * k].face);
1230 glTranslatef(S1, 0, 0);
1233 NO_FACE, rp->cubeLoc[RIGHT_FACE][REVZ(k) + MAXSIZEZ * FIRSTY].face,
1234 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * k].face);
1237 if (slice.depth == 0)
1238 glRotatef(rotatestep, 0, 0, HALFZ);
1239 glTranslatef(-HALFX, -HALFY, HALFZ);
1241 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * LASTY].face,
1242 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * LASTY].face, NO_FACE,
1243 rp->cubeLoc[BOTTOM_FACE][FIRSTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1244 for (i = 1; i < MAXSIZEX - 1; i++) {
1245 glTranslatef(S1, 0, 0);
1247 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * LASTY].face,
1249 rp->cubeLoc[BOTTOM_FACE][i + MAXSIZEX * FIRSTZ].face, NO_FACE);
1251 glTranslatef(S1, 0, 0);
1253 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * LASTY].face,
1254 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * LASTY].face,
1255 rp->cubeLoc[BOTTOM_FACE][LASTX + MAXSIZEX * FIRSTZ].face, NO_FACE);
1256 for (j = 1; j < MAXSIZEY - 1; j++) {
1257 glTranslatef(-SX, S1, 0);
1259 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * REVY(j)].face,
1260 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * REVY(j)].face, NO_FACE,
1262 for (i = 1; i < MAXSIZEX - 1; i++) {
1263 glTranslatef(S1, 0, 0);
1265 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * REVY(j)].face,
1269 glTranslatef(S1, 0, 0);
1271 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * REVY(j)].face,
1272 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * REVY(j)].face,
1275 glTranslatef(-SX, S1, 0);
1277 NO_FACE, rp->cubeLoc[FRONT_FACE][FIRSTX + MAXSIZEX * FIRSTY].face,
1278 rp->cubeLoc[LEFT_FACE][LASTZ + MAXSIZEZ * FIRSTY].face, NO_FACE,
1279 NO_FACE, rp->cubeLoc[TOP_FACE][FIRSTX + MAXSIZEX * LASTZ].face);
1280 for (i = 1; i < MAXSIZEX - 1; i++) {
1281 glTranslatef(S1, 0, 0);
1283 NO_FACE, rp->cubeLoc[FRONT_FACE][i + MAXSIZEX * FIRSTY].face,
1285 NO_FACE, rp->cubeLoc[TOP_FACE][i + MAXSIZEX * LASTZ].face);
1287 glTranslatef(S1, 0, 0);
1289 NO_FACE, rp->cubeLoc[FRONT_FACE][LASTX + MAXSIZEX * FIRSTY].face,
1290 NO_FACE, rp->cubeLoc[RIGHT_FACE][FIRSTZ + MAXSIZEZ * FIRSTY].face,
1291 NO_FACE, rp->cubeLoc[TOP_FACE][LASTX + MAXSIZEX * LASTZ].face);
1297 /* From David Bagley's xrubik. Used by permission. ;) */
1299 readRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1303 if (dir == TOP || dir == BOTTOM)
1304 for (g = 0; g < size; g++)
1305 rp->rowLoc[orient][g] =
1306 rp->cubeLoc[face][g * size + h];
1307 else /* dir == RIGHT || dir == LEFT */
1308 for (g = 0; g < size; g++)
1309 rp->rowLoc[orient][g] =
1310 rp->cubeLoc[face][h * size + g];
1314 rotateRC(rubikstruct * rp, int rotate, int orient, int size)
1318 for (g = 0; g < size; g++)
1319 rp->rowLoc[orient][g].rotation =
1320 (rp->rowLoc[orient][g].rotation + rotate) % MAXORIENT;
1324 reverseRC(rubikstruct * rp, int orient, int size)
1329 for (g = 0; g < size / 2; g++) {
1330 temp = rp->rowLoc[orient][size - 1 - g];
1331 rp->rowLoc[orient][size - 1 - g] = rp->rowLoc[orient][g];
1332 rp->rowLoc[orient][g] = temp;
1337 writeRC(rubikstruct * rp, int face, int dir, int h, int orient, int size)
1341 if (dir == TOP || dir == BOTTOM) {
1342 for (g = 0; g < size; g++) {
1343 position = g * size + h;
1344 rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1345 /* DrawSquare(face, position); */
1347 } else { /* dir == RIGHT || dir == LEFT */
1348 for (g = 0; g < size; g++) {
1349 position = h * size + g;
1350 rp->cubeLoc[face][position] = rp->rowLoc[orient][g];
1351 /* DrawSquare(face, position); */
1357 rotateFace(rubikstruct * rp, int face, int direction)
1360 RubikLoc *faceLoc = NULL;
1362 if ((faceLoc = (RubikLoc *) malloc(AVSIZESQ * sizeof (RubikLoc))) == NULL)
1363 (void) fprintf(stderr,
1364 "Could not allocate memory for rubik face position info\n");
1366 for (position = 0; position < AVSIZESQ; position++)
1367 faceLoc[position] = rp->cubeLoc[face][position];
1369 for (position = 0; position < AVSIZESQ; position++) {
1370 i = position % AVSIZE;
1371 j = position / AVSIZE;
1372 rp->cubeLoc[face][position] = (direction == CW) ?
1373 faceLoc[(AVSIZE - i - 1) * AVSIZE + j] :
1374 faceLoc[i * AVSIZE + AVSIZE - j - 1];
1375 rp->cubeLoc[face][position].rotation =
1376 (rp->cubeLoc[face][position].rotation + direction - MAXORIENT) %
1378 /* DrawSquare(face, position); */
1380 if (faceLoc != NULL)
1381 (void) free((void *) faceLoc);
1385 moveRubik(rubikstruct * rp, int face, int direction, int position)
1387 int newFace, newDirection, rotate, reverse = False;
1391 if (direction == CW || direction == CCW) {
1392 direction = (direction == CCW) ?
1393 (rotateToRow[face].direction + 2) % MAXORIENT :
1394 rotateToRow[face].direction;
1395 i = j = (rotateToRow[face].sideFace == RIGHT ||
1396 rotateToRow[face].sideFace == BOTTOM) ? AVSIZE - 1 : 0;
1397 face = rotateToRow[face].face;
1398 position = j * AVSIZE + i;
1400 i = position % AVSIZE;
1401 j = position / AVSIZE;
1402 h = (direction == TOP || direction == BOTTOM) ? i : j;
1403 /* rotate sides CW or CCW */
1404 if (h == AVSIZE - 1) {
1405 newDirection = (direction == TOP || direction == BOTTOM) ?
1407 if (direction == TOP || direction == RIGHT)
1408 rotateFace(rp, rowToRotate[face][newDirection], CW);
1409 else /* direction == BOTTOM || direction == LEFT */
1410 rotateFace(rp, rowToRotate[face][newDirection], CCW);
1413 newDirection = (direction == TOP || direction == BOTTOM) ?
1415 if (direction == TOP || direction == RIGHT)
1416 rotateFace(rp, rowToRotate[face][newDirection], CCW);
1417 else /* direction == BOTTOM || direction == LEFT */
1418 rotateFace(rp, rowToRotate[face][newDirection], CW);
1421 readRC(rp, face, direction, h, 0, AVSIZE);
1422 for (k = 1; k <= MAXORIENT; k++) {
1423 newFace = slideNextRow[face][direction].face;
1424 rotate = slideNextRow[face][direction].rotation;
1425 newDirection = (rotate + direction) % MAXORIENT;
1432 if (newDirection == TOP || newDirection == BOTTOM) {
1433 newH = AVSIZE - 1 - h;
1435 } else { /* newDirection == RIGHT || newDirection == LEFT */
1441 newH = AVSIZE - 1 - h;
1445 if (newDirection == TOP || newDirection == BOTTOM) {
1448 } else { /* newDirection == RIGHT || newDirection == LEFT */
1449 newH = AVSIZE - 1 - h;
1454 (void) printf("moveRubik: rotate %d\n", rotate);
1457 readRC(rp, newFace, newDirection, newH, k, AVSIZE);
1458 rotateRC(rp, rotate, k - 1, AVSIZE);
1459 if (reverse == True)
1460 reverseRC(rp, k - 1, AVSIZE);
1461 writeRC(rp, newFace, newDirection, newH, k - 1, AVSIZE);
1463 direction = newDirection;
1470 printCube(rubikstruct * rp)
1474 for (face = 0; face < MAXFACES; face++) {
1475 for (position = 0; position < AVSIZESQ; position++) {
1476 (void) printf("%d %d ", rp->cubeLoc[face][position].face,
1477 rp->cubeLoc[face][position].rotation);
1478 if (!((position + 1) % AVSIZE))
1479 (void) printf("\n");
1481 (void) printf("\n");
1483 (void) printf("\n");
1489 evalmovement(ModeInfo * mi, RubikMove movement)
1491 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1496 if (movement.face < 0 || movement.face >= MAXFACES)
1499 moveRubik(rp, movement.face, movement.direction, movement.position);
1504 compare_moves(rubikstruct * rp, RubikMove move1, RubikMove move2, Bool opp)
1506 RubikSlice slice1, slice2;
1508 slice1 = convertMove(rp, move1);
1509 slice2 = convertMove(rp, move2);
1510 if (slice1.face == slice2.face &&
1511 slice1.depth == slice2.depth) {
1512 if (slice1.rotation == slice2.rotation) { /* CW or CCW */
1524 shuffle(ModeInfo * mi)
1526 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1527 int i, face, position;
1530 AVSIZE = MI_SIZE(mi);
1531 if (AVSIZE < -MINSIZE)
1532 AVSIZE = NRAND(-AVSIZE - MINSIZE + 1) + MINSIZE;
1533 else if (AVSIZE < MINSIZE)
1535 /* Let me waste a little space for the moment */
1536 /* Future cube to be LxMxN and not just NxNxN, but not done yet */
1537 AVSIZESQ = AVSIZE * AVSIZE;
1543 MAXSIZESQ = AVSIZESQ;
1546 for (face = 0; face < MAXFACES; face++) {
1547 if (rp->cubeLoc[face] != NULL)
1548 (void) free((void *) rp->cubeLoc[face]);
1549 if ((rp->cubeLoc[face] =
1550 (RubikLoc *) malloc(AVSIZESQ * sizeof (RubikLoc))) == NULL)
1551 (void) fprintf(stderr,
1552 "Could not allocate memory for rubik cube position info\n");
1553 for (position = 0; position < AVSIZESQ; position++) {
1554 rp->cubeLoc[face][position].face = face;
1555 rp->cubeLoc[face][position].rotation = TOP;
1558 for (i = 0; i < MAXORIENT; i++) {
1559 if (rp->rowLoc[i] != NULL)
1560 (void) free((void *) rp->rowLoc[i]);
1561 if ((rp->rowLoc[i] =
1562 (RubikLoc *) malloc(AVSIZE * sizeof (RubikLoc))) == NULL)
1563 (void) fprintf(stderr,
1564 "Could not allocate memory for rubik row position info\n");
1566 rp->storedmoves = MI_COUNT(mi);
1567 if (rp->storedmoves < 0) {
1568 if (rp->moves != NULL)
1569 (void) free((void *) rp->moves);
1571 rp->storedmoves = NRAND(-rp->storedmoves) + 1;
1573 if ((rp->storedmoves) && (rp->moves == NULL))
1575 (RubikMove *) calloc(rp->storedmoves + 1, sizeof (RubikMove))) == NULL)
1576 (void) fprintf(stderr,
1577 "Could not allocate memory for rubik move buffer\n");
1579 if (MI_CYCLES(mi) <= 1) {
1580 rp->anglestep = 90.0;
1582 rp->anglestep = 90.0 / (GLfloat) (MI_CYCLES(mi));
1585 for (i = 0; i < rp->storedmoves; i++) {
1589 move.face = NRAND(6);
1590 move.direction = NRAND(4); /* Exclude CW and CCW, its ok */
1592 * Randomize position along diagonal, each plane gets an equal chance.
1593 * This trick will only work for NxNxN cubes
1594 * draw_cube DEPENDS on that they are chosen this way.
1596 move.position = NRAND(AVSIZE) * (AVSIZE + 1);
1601 if (i > 0) /* avoid immediate undoing moves */
1602 if (compare_moves(rp, move, rp->moves[i - 1], True))
1604 if (i > 1) /* avoid 3 consecutive identical moves */
1605 if (compare_moves(rp, move, rp->moves[i - 1], False) &&
1606 compare_moves(rp, move, rp->moves[i - 2], False))
1609 * Still some silly moves being made....
1611 } while (!condition);
1613 evalmovement(mi, move);
1614 rp->moves[i] = move;
1617 if (NRAND(100) < 50)
1620 if (NRAND(100) < 50)
1622 rp->movement.face = NO_FACE;
1624 rp->action = hideshuffling ? ACTION_SOLVE : ACTION_SHUFFLE;
1625 rp->shufflingmoves = 0;
1630 reshape(ModeInfo * mi, int width, int height)
1632 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1634 glViewport(0, 0, rp->WindW = (GLint) width, rp->WindH = (GLint) height);
1635 glMatrixMode(GL_PROJECTION);
1637 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
1638 glMatrixMode(GL_MODELVIEW);
1640 rp->AreObjectsDefined[ObjCubit] = 0;
1644 pinit(ModeInfo * mi)
1647 glClearColor(0.0, 0.0, 0.0, 1.0);
1648 glColor3f(1.0, 1.0, 1.0);
1650 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
1651 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
1652 glLightfv(GL_LIGHT0, GL_POSITION, position0);
1653 glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
1654 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
1655 glLightfv(GL_LIGHT1, GL_POSITION, position1);
1656 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1657 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1658 glEnable(GL_LIGHTING);
1659 glEnable(GL_LIGHT0);
1660 glEnable(GL_LIGHT1);
1661 glEnable(GL_DEPTH_TEST);
1662 glEnable(GL_NORMALIZE);
1663 glEnable(GL_CULL_FACE);
1665 glShadeModel(GL_FLAT);
1666 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1667 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1673 init_rubik(ModeInfo * mi)
1675 int screen = MI_SCREEN(mi);
1678 if (rubik == NULL) {
1679 if ((rubik = (rubikstruct *) calloc(MI_NUM_SCREENS(mi),
1680 sizeof (rubikstruct))) == NULL)
1683 rp = &rubik[screen];
1684 rp->step = NRAND(90);
1686 rp->PX = ((float) LRAND() / (float) RAND_MAX) * 2 - 1;
1687 rp->PY = ((float) LRAND() / (float) RAND_MAX) * 2 - 1;
1689 if ((rp->glx_context = init_GL(mi)) != NULL) {
1691 reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1692 objects = glGenLists(1);
1700 draw_rubik(ModeInfo * mi)
1704 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1705 Display *display = MI_DISPLAY(mi);
1706 Window window = MI_WINDOW(mi);
1708 MI_IS_DRAWN(mi) = True;
1710 if (!rp->glx_context)
1713 glDrawBuffer(GL_BACK);
1714 glXMakeCurrent(display, window, *(rp->glx_context));
1716 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1720 glTranslatef(0.0, 0.0, -10.0);
1726 rp->PY += (-1) - (rp->PY);
1731 rp->PY -= (rp->PY) - 1;
1736 rp->PX += (-1) - (rp->PX);
1741 rp->PX -= (rp->PX) - 1;
1746 rp->VX += ((float) LRAND() / (float) RAND_MAX) * 0.02 - 0.01;
1747 rp->VX += ((float) LRAND() / (float) RAND_MAX) * 0.02 - 0.01;
1757 if (!MI_IS_ICONIC(mi)) {
1758 glTranslatef(rp->PX, rp->PY, 0);
1759 glScalef(Scale4Window * rp->WindH / rp->WindW, Scale4Window, Scale4Window);
1761 glScalef(Scale4Iconic * rp->WindH / rp->WindW, Scale4Iconic, Scale4Iconic);
1764 glRotatef(rp->step * 100, 1, 0, 0);
1765 glRotatef(rp->step * 95, 0, 1, 0);
1766 glRotatef(rp->step * 90, 0, 0, 1);
1769 glXSwapBuffers(display, window);
1771 if (rp->action == ACTION_SHUFFLE) {
1773 if (++rp->rotatestep > DELAY_AFTER_SHUFFLING) {
1774 rp->movement.face = NO_FACE;
1776 rp->action = ACTION_SOLVE;
1780 if (rp->movement.face == NO_FACE) {
1781 if (rp->shufflingmoves < rp->storedmoves) {
1783 rp->movement = rp->moves[rp->shufflingmoves];
1789 rp->rotatestep += rp->anglestep;
1790 if (rp->rotatestep > 90) {
1791 evalmovement(mi, rp->movement);
1792 rp->shufflingmoves++;
1793 rp->movement.face = NO_FACE;
1799 if (++rp->rotatestep > DELAY_AFTER_SOLVING)
1802 if (rp->movement.face == NO_FACE) {
1803 if (rp->storedmoves > 0) {
1805 rp->movement = rp->moves[rp->storedmoves - 1];
1806 rp->movement.direction = (rp->movement.direction + (MAXORIENT / 2)) %
1813 rp->rotatestep += rp->anglestep;
1814 if (rp->rotatestep > 90) {
1815 evalmovement(mi, rp->movement);
1817 rp->movement.face = NO_FACE;
1831 change_rubik(ModeInfo * mi)
1833 rubikstruct *rp = &rubik[MI_SCREEN(mi)];
1835 if (!rp->glx_context)
1841 release_rubik(ModeInfo * mi)
1843 if (rubik != NULL) {
1846 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1847 rubikstruct *rp = &rubik[screen];
1850 for (i = 0; i < MAXFACES; i++)
1851 if (rp->cubeLoc[i] != NULL)
1852 (void) free((void *) rp->cubeLoc[i]);
1853 for (i = 0; i < MAXORIENT; i++)
1854 if (rp->rowLoc[i] != NULL)
1855 (void) free((void *) rp->rowLoc[i]);
1856 if (rp->moves != NULL)
1857 (void) free((void *) rp->moves);
1859 (void) free((void *) rubik);