/*
 * @(#)DinoGL.c
 *
 * Copyright 2007 - 2023  David A. Bagley, bagleyd AT verizon.net
 *
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of the author not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * This program is distributed in the hope that it will be "useful",
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

/*-
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * This file is provided AS IS with no warranties of any kind.  The author
 * shall have no liability with respect to the infringement of copyrights,
 * trade secrets or any patents by this file or any part thereof.  In no
 *event will the author be liable for any lost revenue or profits or
 * other special, indirect and consequential damages.
 *
 * Thanks goes also to Brian Paul for making it possible and inexpensive
 * to use OpenGL at home.
 *
 * Based on rubik.c by Marcelo F. Vianna <mfvianna@centroin.com.br>
 */

#ifdef HAVE_OPENGL

/* Methods file for DinoGL */

#include "DinoP.h"
#include "DinoGLP.h"

static float front_shininess[] =
{60.0};
static float front_specular[] =
{(float) 0.7, (float) 0.7, (float) 0.7, 1.0};
static float ambient[] =
{0.0, 0.0, 0.0, 1.0};
static float diffuse[] =
{1.0, 1.0, 1.0, 1.0};
static float position0[] =
{1.0, 1.0, 1.0, 0.0};
static float position1[] =
{-1.0, -1.0, 1.0, 0.0};
static float lmodel_ambient[] =
{0.5, 0.5, 0.5, 1.0};
static float lmodel_twoside[] =
{GL_TRUE};

static float face_material[MAX_FACES + 2][4] =
{{1.0, 1.0, 1.0, 1.0},
{1.0, 1.0, 1.0, 1.0},
{1.0, 1.0, 1.0, 1.0},
{1.0, 1.0, 1.0, 1.0},
{1.0, 1.0, 1.0, 1.0},
{1.0, 1.0, 1.0, 1.0},
{0.0, 0.0, 0.0, 1.0},
{0.0, 0.0, 0.0, 1.0}};

/*-
 * Color labels mapping:
 * =====================
 *
 *        +------+
 *        |  0   |
 *        |      |
 *        | TOP  |
 *        |3(0) 1|
 *        | RED  |
 *        |  2   |
 * +------+------+------+
 * |  0   |  0   |  0   |
 * |      |      |      |
 * | LEFT |FRONT |RIGHT |
 * |3(1) 1|3(2) 1|3(3) 1|
 * | BLUE |YELLOW|GREEN |
 * |  2   |  2   |  2   |
 * +------+------+------+
 *        |  0   |
 *        |      |
 *        |BOTTOM|
 *        |3(4) 1|
 *        |WHITE |
 *        |  2   |
 *        +------+         +------+
 *        |  0   |         |\ 0  /|
 *        |      |         | \  / |
 *        | BACK |         | xxxx |
 *        |3(5) 1|         |3(N) 1|
 *        |ORANGE|         | /  \ |
 *        |  2   |         |/ 2  \|
 *        +------+         +------+
 *
 *  Map to 3d
 *  FRONT  => X, Y
 *  BACK   => X, Y
 *  LEFT   => Z, Y
 *  RIGHT  => Z, Y
 *  TOP    => X, Z
 *  BOTTOM => X, Z
 */

static Boolean madeCurrent = False;

#ifdef WINVER
static HGLRC hRC = NULL;
#else
static GLXContext *glXContext = (GLXContext *) NULL;
static Boolean setValuesPuzzleGL(Widget current, Widget request, Widget renew);
static void resizePuzzleGL(DinoGLWidget w);
static void initializePuzzleGL(Widget request, Widget renew);
static void exposePuzzleGL(Widget renew, XEvent *event, Region region);
static void movePuzzleGLTl(DinoGLWidget w,
	XEvent *event, char **args, int nArgs);
static void movePuzzleGLTop(DinoGLWidget w,
	XEvent *event, char **args, int nArgs);
static void movePuzzleGLTr(DinoGLWidget w,
	XEvent *event, char **args, int nArgs);
static void movePuzzleGLLeft(DinoGLWidget w,
	XEvent *event, char **args, int nArgs);
static void movePuzzleGLRight(DinoGLWidget w,
	XEvent *event, char **args, int nArgs);
static void movePuzzleGLBl(DinoGLWidget w,
	XEvent *event, char **args, int nArgs);
static void movePuzzleGLBottom(DinoGLWidget w,
	XEvent *event, char **args, int nArgs);
static void movePuzzleGLBr(DinoGLWidget w,
	XEvent *event, char **args, int nArgs);

static char translationsGL[] =
"<KeyPress>q: Quit()\n\
 Ctrl<KeyPress>C: Quit()\n\
 <KeyPress>osfCancel: Hide()\n\
 <KeyPress>Escape: Hide()\n\
 <KeyPress>osfEscape: Hide()\n\
 Ctrl<KeyPress>[: Hide()\n\
 <KeyPress>0x1B: Hide()\n\
 <KeyPress>0x2E: Speed()\n\
 <KeyPress>0x3E: Speed()\n\
 <KeyPress>0x3C: Slow()\n\
 <KeyPress>0x2C: Slow()\n\
 Shift<KeyPress>2: Sound()\n\
 <KeyPress>F11: MoveCcw()\n\
 <KeyPress>KP_Divide: MoveCcw()\n\
 <KeyPress>R5: MoveCcw()\n\
 <KeyPress>Home: MoveTl()\n\
 <KeyPress>KP_7: MoveTl()\n\
 <KeyPress>R7: MoveTl()\n\
 <KeyPress>Up: MoveTop()\n\
 <KeyPress>osfUp: MoveTop()\n\
 <KeyPress>KP_Up: MoveTop()\n\
 <KeyPress>KP_8: MoveTop()\n\
 <KeyPress>R8: MoveTop()\n\
 <KeyPress>Prior: MoveTr()\n\
 <KeyPress>KP_9: MoveTr()\n\
 <KeyPress>R9: MoveTr()\n\
 <KeyPress>Left: MoveLeft()\n\
 <KeyPress>osfLeft: MoveLeft()\n\
 <KeyPress>KP_Left: MoveLeft()\n\
 <KeyPress>KP_4: MoveLeft()\n\
 <KeyPress>R10: MoveLeft()\n\
 <KeyPress>F12: MoveCw()\n\
 <KeyPress>Begin: MoveCw()\n\
 <KeyPress>KP_5: MoveCw()\n\
 <KeyPress>R11: MoveCw()\n\
 <KeyPress>Right: MoveRight()\n\
 <KeyPress>osfRight: MoveRight()\n\
 <KeyPress>KP_Right: MoveRight()\n\
 <KeyPress>KP_6: MoveRight()\n\
 <KeyPress>R12: MoveRight()\n\
 <KeyPress>End: MoveBl()\n\
 <KeyPress>KP_1: MoveBl()\n\
 <KeyPress>R13: MoveBl()\n\
 <KeyPress>Down: MoveBottom()\n\
 <KeyPress>osfDown: MoveBottom()\n\
 <KeyPress>KP_Down: MoveBottom()\n\
 <KeyPress>KP_2: MoveBottom()\n\
 <KeyPress>R14: MoveBottom()\n\
 <KeyPress>Next: MoveBr()\n\
 <KeyPress>KP_3: MoveBr()\n\
 <KeyPress>R15: MoveBr()\n\
 <Btn1Down>: Select()\n\
 <Btn1Up>: Release()\n\
 <Btn2Down>: PracticeMaybe()\n\
 <Btn2Down>(2+): Practice2()\n\
 <Btn3Down>: RandomizeMaybe()\n\
 <Btn3Down>(2+): Randomize2()\n\
 <Btn4Down>: MoveTop()\n\
 <Btn5Down>: MoveBottom()\n\
 <KeyPress>g: Get()\n\
 <KeyPress>w: Write()\n\
 <KeyPress>u: Undo()\n\
 <KeyPress>r: Redo()\n\
 <KeyPress>c: Clear()\n\
 <KeyPress>z: Randomize()\n\
 <KeyPress>s: Solve()\n\
 <KeyPress>f: Find()\n\
 <KeyPress>p: Practice()\n\
 <KeyPress>o: Orientize()\n\
 <KeyPress>2: Period2()\n\
 <KeyPress>3: Period3()\n\
 <KeyPress>b: Both()\n\
 <KeyPress>v: View()\n\
 <EnterWindow>: Enter()\n\
 <LeaveWindow>: Leave()";

static XtActionsRec actionsListGL[] =
{
	{(char *) "Quit", (XtActionProc) quitPuzzle},
	{(char *) "Hide", (XtActionProc) hidePuzzle},
	{(char *) "MoveCcw", (XtActionProc) movePuzzleCcw},
	{(char *) "MoveTl", (XtActionProc) movePuzzleGLTl},
	{(char *) "MoveTop", (XtActionProc) movePuzzleGLTop},
	{(char *) "MoveTr", (XtActionProc) movePuzzleGLTr},
	{(char *) "MoveLeft", (XtActionProc) movePuzzleGLLeft},
	{(char *) "MoveCw", (XtActionProc) movePuzzleCw},
	{(char *) "MoveRight", (XtActionProc) movePuzzleGLRight},
	{(char *) "MoveBl", (XtActionProc) movePuzzleGLBl},
	{(char *) "MoveBottom", (XtActionProc) movePuzzleGLBottom},
	{(char *) "MoveBr", (XtActionProc) movePuzzleGLBr},
	{(char *) "Select", (XtActionProc) selectPuzzle},
	{(char *) "Release", (XtActionProc) releasePuzzle},
	{(char *) "PracticeMaybe", (XtActionProc) practicePuzzleWithQuery},
	{(char *) "Practice2", (XtActionProc) practicePuzzleWithDoubleClick},
	{(char *) "RandomizeMaybe", (XtActionProc) randomizePuzzleWithQuery},
	{(char *) "Randomize2", (XtActionProc) randomizePuzzleWithDoubleClick},
	{(char *) "Get", (XtActionProc) getPuzzle},
	{(char *) "Write", (XtActionProc) writePuzzle},
	{(char *) "Undo", (XtActionProc) undoPuzzle},
	{(char *) "Redo", (XtActionProc) redoPuzzle},
	{(char *) "Clear", (XtActionProc) clearPuzzle},
	{(char *) "Randomize", (XtActionProc) randomizePuzzle},
	{(char *) "Solve", (XtActionProc) solvePuzzle},
	{(char *) "Find", (XtActionProc) findPuzzle},
	{(char *) "Practice", (XtActionProc) practicePuzzle},
	{(char *) "Orientize", (XtActionProc) orientizePuzzle},
	{(char *) "Period2", (XtActionProc) period2ModePuzzle},
	{(char *) "Period3", (XtActionProc) period3ModePuzzle},
	{(char *) "Both", (XtActionProc) bothModePuzzle},
	{(char *) "View", (XtActionProc) viewPuzzle},
	{(char *) "Speed", (XtActionProc) speedUpPuzzle},
	{(char *) "Slow", (XtActionProc) slowDownPuzzle},
	{(char *) "Sound", (XtActionProc) toggleSoundPuzzle},
	{(char *) "Enter", (XtActionProc) enterPuzzle},
	{(char *) "Leave", (XtActionProc) leavePuzzle}
};

static XtResource resourcesGL[] =
{
	{XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
	 XtOffset(DinoWidget, core.width),
	 XtRString, (caddr_t) "300"},
	{XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
	 XtOffset(DinoWidget, core.height),
	 XtRString, (caddr_t) "400"},
	{XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
	 XtOffset(DinoWidget, dino.mono),
	 XtRString, (caddr_t) "FALSE"},
	{XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
	 XtOffset(DinoWidget, dino.reverse),
	 XtRString, (caddr_t) "FALSE"},
	{XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
	 XtOffset(DinoWidget, dino.foreground),
	 XtRString, (caddr_t) XtDefaultForeground},
	{XtNbackground, XtCBackground, XtRPixel, sizeof (Pixel),
	 XtOffset(DinoWidget, dino.background),
	 XtRString, (caddr_t) "#AEB2C3" /*XtDefaultBackground*/},
	{XtNframeColor, XtCColor, XtRPixel, sizeof (Pixel),
	 XtOffset(DinoWidget, dino.frameColor),
	 XtRString, (caddr_t) "Cyan" /*XtDefaultForeground*/},
	{XtNfaceColor0, XtCLabel, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.faceName[0]),
	 XtRString, (caddr_t) "Red"},
	{XtNfaceColor1, XtCLabel, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.faceName[1]),
	 XtRString, (caddr_t) "Blue"},
	{XtNfaceColor2, XtCLabel, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.faceName[2]),
	 XtRString, (caddr_t) "Yellow"},
	{XtNfaceColor3, XtCLabel, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.faceName[3]),
	 XtRString, (caddr_t) "Green"},
	{XtNfaceColor4, XtCLabel, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.faceName[4]),
	 XtRString, (caddr_t) "White"},
	{XtNfaceColor5, XtCLabel, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.faceName[5]),
	 XtRString, (caddr_t) "Orange"},
	{XtNpieceBorder, XtCColor, XtRPixel, sizeof (Pixel),
	 XtOffset(DinoWidget, dino.borderColor),
	 XtRString, (caddr_t) "gray25" /*XtDefaultForeground*/},
	{XtNdelay, XtCDelay, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.delay),
	 XtRString, (caddr_t) "10"},
	{XtNsound, XtCSound, XtRBoolean, sizeof (Boolean),
	 XtOffset(DinoWidget, dino.sound),
	 XtRString, (caddr_t) "FALSE"},
	{XtNmoveSound, XtCMoveSound, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.moveSound),
	 XtRString, (caddr_t) MOVESOUND},
	{XtNfont, XtCFont, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.font),
	 XtRString, (caddr_t) "9x15bold"},
	{XtNview, XtCView, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.view),
	 XtRString, (caddr_t) "1"},
	{XtNmode, XtCMode, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.mode),
	 XtRString, (caddr_t) "3"}, /*DEFAULT_MODE */
	{XtNorient, XtCOrient, XtRBoolean, sizeof (Boolean),
	 XtOffset(DinoWidget, dino.orient),
	 XtRString, (caddr_t) "FALSE"},	/* DEFAULT_ORIENT */
	{XtNpractice, XtCPractice, XtRBoolean, sizeof (Boolean),
	 XtOffset(DinoWidget, dino.practice),
	 XtRString, (caddr_t) "TRUE"}, /* DEFAULT_PRACTICE */
	{XtNuserName, XtCUserName, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.userName),
	 XtRString, (caddr_t) ""},
	{XtNscoreFile, XtCScoreFile, XtRString, sizeof (String),
	 XtOffset(DinoWidget, dino.scoreFile),
	 XtRString, (caddr_t) ""},
	{XtNscoreOnly, XtCBoolean, XtRBoolean, sizeof (Boolean),
	 XtOffset(DinoWidget, dino.scoreOnly),
	 XtRString, (caddr_t) "FALSE"},
	{XtNversionOnly, XtCBoolean, XtRBoolean, sizeof (Boolean),
	 XtOffset(DinoWidget, dino.versionOnly),
	 XtRString, (caddr_t) "FALSE"},
	{XtNmenu, XtCMenu, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.menu),
	 XtRString, (caddr_t) "999"}, /* ACTION_IGNORE */
	{XtNstart, XtCBoolean, XtRBoolean, sizeof (Boolean),
	 XtOffset(DinoWidget, dino.started),
	 XtRString, (caddr_t) "FALSE"},
	{XtNcheat, XtCBoolean, XtRBoolean, sizeof (Boolean),
	 XtOffset(DinoWidget, dino.cheat),
	 XtRString, (caddr_t) "FALSE"},
	{XtNface, XtCFace, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.currentFace),
	 XtRString, (caddr_t) "-1"},
	{XtNpos, XtCPos, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.currentPosition),
	 XtRString, (caddr_t) "-1"},
	{XtNdirection, XtCDirection, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.currentDirection),
	 XtRString, (caddr_t) "-1"},
	{XtNstyle, XtCStyle, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.style),
	 XtRString, (caddr_t) "-1"},
	{XtNcontrol, XtCControl, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.currentControl),
	 XtRString, (caddr_t) "0"},
	{XtNfast, XtCFast, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.currentFast),
	 XtRString, (caddr_t) "1"},
	{XtNpixmapSize, XtCPixmapSize, XtRInt, sizeof (int),
	 XtOffset(DinoWidget, dino.pixmapSize),
	 XtRString, (caddr_t) "64"},
	{XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
	 XtOffset(DinoWidget, dino.select),
	 XtRCallback, (caddr_t) NULL}
};

DinoGLClassRec dinoGLClassRec =
{
	{
		(WidgetClass) & dinoClassRec,	/* superclass */
		(char *) "DinoGL",	/* class name */
		sizeof (DinoGLRec),	/* widget size */
		NULL,		/* class initialize */
		NULL,		/* class part initialize */
		FALSE,		/* class inited */
		(XtInitProc) initializePuzzleGL,	/* initialize */
		NULL,		/* initialize hook */
		XtInheritRealize,	/* realize */
		actionsListGL,	/* actions */
		XtNumber(actionsListGL),	/* num actions */
		resourcesGL,	/* resources */
		XtNumber(resourcesGL),	/* num resources */
		NULLQUARK,	/* xrm class */
		TRUE,		/* compress motion */
		TRUE,		/* compress exposure */
		TRUE,		/* compress enterleave */
		TRUE,		/* visible interest */
		NULL,		/* destroy */
		(XtWidgetProc) resizePuzzleGL,	/* resize */
		(XtExposeProc) exposePuzzleGL,	/* expose */
		(XtSetValuesFunc) setValuesPuzzleGL,	/* set values */
		NULL,		/* set values hook */
		XtInheritSetValuesAlmost,	/* set values almost */
		NULL,		/* get values hook */
		XtInheritAcceptFocus,	/* accept focus */
		XtVersion,	/* version */
		NULL,		/* callback private */
		translationsGL,	/* tm table */
		NULL,		/* query geometry */
		NULL,		/* display accelerator */
		NULL		/* extension */
	},
	{
		0		/* ignore */
	},
	{
		0		/* ignore */
	}
};

WidgetClass dinoGLWidgetClass = (WidgetClass) & dinoGLClassRec;
#endif

static void
pickColor(DinoGLWidget w, int c, int mono, float *material)
{
#ifdef WINVER
	struct tagColor {
		int red, green, blue;
	} color;
#define MAX_INTENSITY 0xFF
#else
	XColor color;
#define MAX_INTENSITY 0xFFFF
#endif

	switch (c) {
	case TOP_FACE:
	case LEFT_FACE:
	case FRONT_FACE:
	case RIGHT_FACE:
	case BOTTOM_FACE:
	case BACK_FACE:
#ifdef WINVER
		color.red = GetRValue(w->dino.faceGC[c]);
		color.green = GetGValue(w->dino.faceGC[c]);
		color.blue = GetBValue(w->dino.faceGC[c]);
#else
		color.pixel = w->dino.faceColor[c];
		XQueryColor(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)),
			&color);
#endif
		break;
	case BORDER_FACE:
#ifdef WINVER
		color.red = GetRValue(w->dino.borderGC);
		color.green = GetGValue(w->dino.borderGC);
		color.blue = GetBValue(w->dino.borderGC);
#else
		color.pixel = w->dino.borderColor;
		XQueryColor(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)),
			&color);
#endif
		break;
	case NO_FACE:
	default:
#ifdef WINVER
		color.red = GetRValue(w->dino.inverseGC);
		color.green = GetGValue(w->dino.inverseGC);
		color.blue = GetBValue(w->dino.inverseGC);
#else
		color.pixel = w->dino.background;
		XQueryColor(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)),
			&color);
#endif
		break;
	}
#ifdef DEBUG
	(void) printf("%d: i%d %d %d\n", c, color.red, color.green, color.blue);
#endif
	if (mono) {
		/* really GrayScale */
		float intensity = (float) (0.3 * color.red +
			0.59 * color.green + 0.11 * color.blue);
#ifdef DEBUG
		(void) printf("m%g\n", intensity);
#endif
		material[0] = (float) intensity / MAX_INTENSITY;
		material[1] = material[0];
		material[2] = material[0];
	} else {
		material[0] = (float) color.red / MAX_INTENSITY;
		material[1] = (float) color.green / MAX_INTENSITY;
		material[2] = (float) color.blue / MAX_INTENSITY;
	}
#ifdef DEBUG
	(void) printf("%d: f%g %g %g\n", c, material[0], material[1], material[2]);
#endif
}

typedef float Matrix[3][3];
typedef float Vector[3];

static void
matrixMatrix(Matrix a, Matrix b, Matrix x)
{
	int i, j;

	for (i = 0; i < 3; i++) {
		for (j = 0; j < 3; j++) {
			x[i][j] = a[i][0] * b[0][j] +
				a[i][1] * b[1][j] +
				a[i][2] * b[2][j];
		}
	}
}

static void
matrixVector(Matrix a, Vector v, Vector x)
{
	int i;

	for (i = 0; i < 3; i++) {
		x[i] = a[i][0] * v[0] +
			a[i][1] * v[1] +
			a[i][2] * v[2];
	}
}

static void
setMatrix(float theta, float x, float y, float z, Matrix a)
{
	float s = (float) sin(theta * M_PI / 180.0);
	float c = (float) cos(theta * M_PI / 180.0);

	if (x != 0.0 && y == 0.0 && z == 0.0) {
		a[0][0] = 1.0, a[0][1] = 0.0; a[0][2] = 0.0;
		a[1][0] = 0.0, a[1][1] = c; a[1][2] = -s;
		a[2][0] = 0.0, a[2][1] = s; a[2][2] = c;
	} else if (y != 0.0 && x == 0.0 && z == 0.0) {
		a[0][0] = c, a[0][1] = 0.0; a[0][2] = s;
		a[1][0] = 0.0, a[1][1] = 1.0; a[1][2] = 0.0;
		a[2][0] = -s, a[2][1] = 0.0; a[2][2] = c;
	} else if (z != 0.0 && x == 0.0 && y == 0.0) {
		a[0][0] = c, a[0][1] = -s; a[0][2] = 0.0;
		a[1][0] = s, a[1][1] = c; a[1][2] = 0.0;
		a[2][0] = 0.0, a[2][1] = 0.0; a[2][2] = 1.0;
	}
}

static void
drawStickerlessHalfCubit(int val)
{
	glBegin(GL_TRIANGLES);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
		face_material[BORDER_FACE]);
	if (val == 1) {
		glNormal3f(1.0, 0.0, 1.0);
		glVertex3f(CUBE_LENGTH, CUBE_ROUND, -CUBEFULLROUND - CUBE_LENGTH);
		glVertex3f(CUBE_LENGTH, -CUBE_ROUND, -CUBE_LENGTH);
		glVertex3f(CUBE_LENGTH - CUBE_ROUND, 0, -CUBE_LENGTH);
		glNormal3f(1.0, 0.0, 1.0);
		glVertex3f(CUBE_LENGTH - CUBE_ROUND, 0, -CUBE_LENGTH);
		glVertex3f(CUBE_LENGTH, -CUBE_ROUND, -CUBE_LENGTH);
		glVertex3f(CUBE_LENGTH, CUBE_ROUND, CUBEFULLROUND - CUBE_LENGTH);
		glNormal3f(1.0, 1.0, 0.0);
		glVertex3f(CUBE_LENGTH, CUBE_ROUND, CUBEFULLROUND - CUBE_LENGTH);
		glVertex3f(CUBE_LENGTH, CUBE_ROUND, -CUBEFULLROUND - CUBE_LENGTH);
		glVertex3f(CUBE_LENGTH - CUBE_ROUND, 0, -CUBE_LENGTH);
		/* Put sticker here */
		glNormal3f(1.0, 0.0, 0.0);
		glVertex3f(CUBE_LENGTH, CUBE_ROUND, -CUBEFULLROUND - CUBE_LENGTH);
		glVertex3f(CUBE_LENGTH, CUBE_ROUND, CUBEFULLROUND - CUBE_LENGTH);
		glVertex3f(CUBE_LENGTH, -CUBE_ROUND, -CUBE_LENGTH);
	} else {
		glNormal3f(0.0, 1.0, 1.0);
		glVertex3f(-CUBE_ROUND, CUBE_LENGTH, -CUBE_LENGTH);
		glVertex3f(CUBE_ROUND, CUBE_LENGTH, -CUBEFULLROUND - CUBE_LENGTH);
		glVertex3f(0, CUBE_LENGTH - CUBE_ROUND, -CUBE_LENGTH);
		glNormal3f(0.0, 1.0, 1.0);
		glVertex3f(-CUBE_ROUND, CUBE_LENGTH, -CUBE_LENGTH);
		glVertex3f(0, CUBE_LENGTH - CUBE_ROUND, -CUBE_LENGTH);
		glVertex3f(CUBE_ROUND, CUBE_LENGTH, CUBEFULLROUND - CUBE_LENGTH);
		glNormal3f(1.0, 1.0, 0.0);
		glVertex3f(CUBE_ROUND, CUBE_LENGTH, -CUBEFULLROUND - CUBE_LENGTH);
		glVertex3f(CUBE_ROUND, CUBE_LENGTH, CUBEFULLROUND - CUBE_LENGTH);
		glVertex3f(0, CUBE_LENGTH - CUBE_ROUND, -CUBE_LENGTH);
		/* Put sticker here */
		glNormal3f(0.0, 1.0, 0.0);
		glVertex3f(-CUBE_ROUND, CUBE_LENGTH, -CUBE_LENGTH);
		glVertex3f(CUBE_ROUND, CUBE_LENGTH, CUBEFULLROUND - CUBE_LENGTH);
		glVertex3f(CUBE_ROUND, CUBE_LENGTH, -CUBEFULLROUND - CUBE_LENGTH);
	}
	glEnd();
}

static void
drawStickerlessCubit(Boolean sep)
{
	if (sep) {
		drawStickerlessHalfCubit(1);
		drawStickerlessHalfCubit(0);
		return;
	}
	glBegin(GL_QUADS);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
		face_material[BORDER_FACE]);
	/* Edge of cubit */
	glNormal3f(1.0, 1.0, 0.0);
	glVertex3f(CUBE_ROUND, CUBE_LENGTH, -CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(CUBE_ROUND, CUBE_LENGTH, CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(CUBE_LENGTH, CUBE_ROUND, CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(CUBE_LENGTH, CUBE_ROUND, -CUBEFULLROUND - CUBE_LENGTH);
	/* Internal to cubit */
	glNormal3f(0.0, 1.0, 1.0);
	glVertex3f(CUBE_ROUND, CUBE_LENGTH, -CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(CUBE_LENGTH, CUBE_ROUND, -CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(CUBE_LENGTH, -CUBE_ROUND, -CUBE_LENGTH);
	glVertex3f(-CUBE_ROUND, CUBE_LENGTH, -CUBE_LENGTH);
	glNormal3f(0.0, 1.0, 1.0);
	glVertex3f(CUBE_ROUND, CUBE_LENGTH, CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(CUBE_LENGTH, CUBE_ROUND, CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(-CUBE_ROUND, CUBE_LENGTH, -CUBE_LENGTH);
	glVertex3f(CUBE_LENGTH, -CUBE_ROUND, -CUBE_LENGTH);
	glEnd();
	glBegin(GL_TRIANGLES);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
		face_material[BORDER_FACE]);
	/* Put sticker here */
	glNormal3f(1.0, 0.0, 0.0);
	glVertex3f(CUBE_LENGTH, CUBE_ROUND, -CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(CUBE_LENGTH, CUBE_ROUND, CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(CUBE_LENGTH, -CUBE_ROUND, -CUBE_LENGTH);
	glNormal3f(0.0, 1.0, 0.0);
	glVertex3f(-CUBE_ROUND, CUBE_LENGTH, -CUBE_LENGTH);
	glVertex3f(CUBE_ROUND, CUBE_LENGTH, CUBEFULLROUND - CUBE_LENGTH);
	glVertex3f(CUBE_ROUND, CUBE_LENGTH, -CUBEFULLROUND - CUBE_LENGTH);
	glEnd();
}

static void
drawOrientLine(DinoGLWidget w, int face, int rotation,
		float x, float y, float z)
{
	int err = 0;
	char *buf1, *buf2;

	glPushMatrix();
	glTranslatef(x, y, z);
	glBegin(GL_QUADS);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
		face_material[BORDER_FACE]);
	switch (face) {
	case 0:
		switch (rotation) {
		case 0:
			glVertex3f(-CUT, 0.0, -CUT);
			glVertex3f(CUT, 0.0, -CUT);
			glVertex3f(CUT, 0.0, -STICKER_SHORT);
			glVertex3f(-CUT, 0.0, -STICKER_SHORT);
			break;
		case 1:
			glVertex3f(CUT, 0.0, -CUT);
			glVertex3f(CUT, 0.0, CUT);
			glVertex3f(STICKER_SHORT, 0.0, CUT);
			glVertex3f(STICKER_SHORT, 0.0, -CUT);
			break;
		case 2:
			glVertex3f(CUT, 0.0, CUT);
			glVertex3f(-CUT, 0.0, CUT);
			glVertex3f(-CUT, 0.0, STICKER_SHORT);
			glVertex3f(CUT, 0.0, STICKER_SHORT);
			break;
		case 3:
			glVertex3f(-CUT, 0.0, CUT);
			glVertex3f(-CUT, 0.0, -CUT);
			glVertex3f(-STICKER_SHORT, 0.0, -CUT);
			glVertex3f(-STICKER_SHORT, 0.0, CUT);
			break;
		default:
			err = 1;
		}
		break;
	case 1:
		switch (rotation) {
		case 0:
			glVertex3f(0.0, CUT, -CUT);
			glVertex3f(0.0, CUT, CUT);
			glVertex3f(0.0, STICKER_SHORT, CUT);
			glVertex3f(0.0, STICKER_SHORT, -CUT);
			break;
		case 1:
			glVertex3f(0.0, CUT, CUT);
			glVertex3f(0.0, -CUT, CUT);
			glVertex3f(0.0, -CUT, STICKER_SHORT);
			glVertex3f(0.0, CUT, STICKER_SHORT);
			break;
		case 2:
			glVertex3f(0.0, -CUT, CUT);
			glVertex3f(0.0, -CUT, -CUT);
			glVertex3f(0.0, -STICKER_SHORT, -CUT);
			glVertex3f(0.0, -STICKER_SHORT, CUT);
			break;
		case 3:
			glVertex3f(0.0, -CUT, -CUT);
			glVertex3f(0.0, CUT, -CUT);
			glVertex3f(0.0, CUT, -STICKER_SHORT);
			glVertex3f(0.0, -CUT, -STICKER_SHORT);
			break;
		default:
			err = 1;
		}
		break;
	case 2:
		switch (rotation) {
		case 0:
			glVertex3f(-CUT, CUT, 0.0);
			glVertex3f(CUT, CUT, 0.0);
			glVertex3f(CUT, STICKER_SHORT, 0.0);
			glVertex3f(-CUT, STICKER_SHORT, 0.0);
			break;
		case 1:
			glVertex3f(CUT, CUT, 0.0);
			glVertex3f(CUT, -CUT, 0.0);
			glVertex3f(STICKER_SHORT, -CUT, 0.0);
			glVertex3f(STICKER_SHORT, CUT, 0.0);
			break;
		case 2:
			glVertex3f(CUT, -CUT, 0.0);
			glVertex3f(-CUT, -CUT, 0.0);
			glVertex3f(-CUT, -STICKER_SHORT, 0.0);
			glVertex3f(CUT, -STICKER_SHORT, 0.0);
			break;
		case 3:
			glVertex3f(-CUT, -CUT, 0.0);
			glVertex3f(-CUT, CUT, 0.0);
			glVertex3f(-STICKER_SHORT, CUT, 0.0);
			glVertex3f(-STICKER_SHORT, -CUT, 0.0);
			break;
		default:
			err = 1;
		}
		break;
	case 3:
		switch (rotation) {
		case 0:
			glVertex3f(0.0, CUT, -CUT);
			glVertex3f(0.0, STICKER_SHORT, -CUT);
			glVertex3f(0.0, STICKER_SHORT, CUT);
			glVertex3f(0.0, CUT, CUT);
			break;
		case 1:
			glVertex3f(0.0, -CUT, -CUT);
			glVertex3f(0.0, -CUT, -STICKER_SHORT);
			glVertex3f(0.0, CUT, -STICKER_SHORT);
			glVertex3f(0.0, CUT, -CUT);
			break;
		case 2:
			glVertex3f(0.0, -CUT, CUT);
			glVertex3f(0.0, -STICKER_SHORT, CUT);
			glVertex3f(0.0, -STICKER_SHORT, -CUT);
			glVertex3f(0.0, -CUT, -CUT);
			break;
		case 3:
			glVertex3f(0.0, CUT, CUT);
			glVertex3f(0.0, CUT, STICKER_SHORT);
			glVertex3f(0.0, -CUT, STICKER_SHORT);
			glVertex3f(0.0, -CUT, CUT);
			break;
		default:
			err = 1;
		}
		break;
	case 4:
		switch (rotation) {
		case 0:
			glVertex3f(CUT, 0.0, CUT);
			glVertex3f(CUT, 0.0, STICKER_SHORT);
			glVertex3f(-CUT, 0.0, STICKER_SHORT);
			glVertex3f(-CUT, 0.0, CUT);
			break;
		case 1:
			glVertex3f(CUT, 0.0, -CUT);
			glVertex3f(STICKER_SHORT, 0.0, -CUT);
			glVertex3f(STICKER_SHORT, 0.0, CUT);
			glVertex3f(CUT, 0.0, CUT);
			break;
		case 2:
			glVertex3f(-CUT, 0.0, -CUT);
			glVertex3f(-CUT, 0.0, -STICKER_SHORT);
			glVertex3f(CUT, 0.0, -STICKER_SHORT);
			glVertex3f(CUT, 0.0, -CUT);
			break;
		case 3:
			glVertex3f(-CUT, 0.0, CUT);
			glVertex3f(-STICKER_SHORT, 0.0, CUT);
			glVertex3f(-STICKER_SHORT, 0.0, -CUT);
			glVertex3f(-CUT, 0.0, -CUT);
			break;
		default:
			err = 1;
		}
		break;
	case 5:
		switch (rotation) {
		case 0:
			glVertex3f(CUT, -CUT, 0.0);
			glVertex3f(CUT, -STICKER_SHORT, 0.0);
			glVertex3f(-CUT, -STICKER_SHORT, 0.0);
			glVertex3f(-CUT, -CUT, 0.0);
			break;
		case 1:
			glVertex3f(CUT, CUT, 0.0);
			glVertex3f(STICKER_SHORT, CUT, 0.0);
			glVertex3f(STICKER_SHORT, -CUT, 0.0);
			glVertex3f(CUT, -CUT, 0.0);
			break;
		case 2:
			glVertex3f(-CUT, CUT, 0.0);
			glVertex3f(-CUT, STICKER_SHORT, 0.0);
			glVertex3f(CUT, STICKER_SHORT, 0.0);
			glVertex3f(CUT, CUT, 0.0);
			break;
		case 3:
			glVertex3f(-CUT, -CUT, 0.0);
			glVertex3f(-STICKER_SHORT, -CUT, 0.0);
			glVertex3f(-STICKER_SHORT, CUT, 0.0);
			glVertex3f(-CUT, CUT, 0.0);
			break;
		default:
			err = 1;
		}
		break;
	}
	glEnd();
	glPopMatrix();
	if (err == 1) {
		intCat(&buf1, "draw_orient_line: face ", face);
		stringCat(&buf2, buf1, ", rotation ");
		free(buf1);
		intCat(&buf1, buf2, rotation);
		free(buf2);
		DISPLAY_WARNING(buf1);
		free(buf1);
	}
}

/* so puzzle will not fall apart */
static void
drawCenter(void)
{
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
		face_material[BORDER_FACE]);
	glBegin(GL_QUADS);
	glNormal3f(0.0, 0.0, 1.0);
	glVertex3f(-CUBE_ROUND, -CUBE_ROUND, CUBE_ROUND);
	glVertex3f(CUBE_ROUND, -CUBE_ROUND, CUBE_ROUND);
	glVertex3f(CUBE_ROUND, CUBE_ROUND, CUBE_ROUND);
	glVertex3f(-CUBE_ROUND, CUBE_ROUND, CUBE_ROUND);
	glNormal3f(0.0, 0.0, -1.0);
	glVertex3f(-CUBE_ROUND, CUBE_ROUND, -CUBE_ROUND);
	glVertex3f(CUBE_ROUND, CUBE_ROUND, -CUBE_ROUND);
	glVertex3f(CUBE_ROUND, -CUBE_ROUND, -CUBE_ROUND);
	glVertex3f(-CUBE_ROUND, -CUBE_ROUND, -CUBE_ROUND);
	glNormal3f(-1.0, 0.0, 0.0);
	glVertex3f(-CUBE_ROUND, -CUBE_ROUND, CUBE_ROUND);
	glVertex3f(-CUBE_ROUND, CUBE_ROUND, CUBE_ROUND);
	glVertex3f(-CUBE_ROUND, CUBE_ROUND, -CUBE_ROUND);
	glVertex3f(-CUBE_ROUND, -CUBE_ROUND, -CUBE_ROUND);
	glNormal3f(1.0, 0.0, 0.0);
	glVertex3f(CUBE_ROUND, -CUBE_ROUND, -CUBE_ROUND);
	glVertex3f(CUBE_ROUND, CUBE_ROUND, -CUBE_ROUND);
	glVertex3f(CUBE_ROUND, CUBE_ROUND, CUBE_ROUND);
	glVertex3f(CUBE_ROUND, -CUBE_ROUND, CUBE_ROUND);
	glNormal3f(0.0, -1.0, 0.0);
	glVertex3f(CUBE_ROUND, -CUBE_ROUND, -CUBE_ROUND);
	glVertex3f(CUBE_ROUND, -CUBE_ROUND, CUBE_ROUND);
	glVertex3f(-CUBE_ROUND, -CUBE_ROUND, CUBE_ROUND);
	glVertex3f(-CUBE_ROUND, -CUBE_ROUND, -CUBE_ROUND);
	glNormal3f(0.0, 1.0, 0.0);
	glVertex3f(-CUBE_ROUND, CUBE_ROUND, -CUBE_ROUND);
	glVertex3f(-CUBE_ROUND, CUBE_ROUND, CUBE_ROUND);
	glVertex3f(CUBE_ROUND, CUBE_ROUND, CUBE_ROUND);
	glVertex3f(CUBE_ROUND, CUBE_ROUND, -CUBE_ROUND);
	glEnd();
}

static void
drawCubit(DinoGLWidget w,
		int back, int front, int left, int right, int bottom, int top)
{
	if (back < NO_FACE) { /* Orange */
		glPushMatrix();
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
			face_material[back]);
		glNormal3f(0.0, 0.0, -1.0);
		if (top != NO_FACE) {
			glPushMatrix();
			glTranslatef(-CUBE_LENGTH, -CUBE_ROUND, 0.0);
			glBegin(GL_TRIANGLES);
			glVertex3f(0.0, STICKER_OFFSET, -STICKER_DEPTH);
			glVertex3f(-STICKERFULLSHORT, STICKERFULLLONG, -STICKER_DEPTH);
			glVertex3f(STICKERFULLSHORT, STICKERFULLLONG, -STICKER_DEPTH);
			glEnd();
			if (w->dino.currentFace == BACK_FACE &&
					w->dino.currentPosition == 2) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(0.0, SELECT_OFFSET, -SELECT_DEPTH);
				glVertex3f(-SELECTFULLSHORT, SELECTFULLLONG, -SELECT_DEPTH);
				glVertex3f(SELECTFULLSHORT, SELECTFULLLONG, -SELECT_DEPTH);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, BACK_FACE,
					w->dino.cubeLoc[BACK_FACE][2].rotation,
					0.0, -CUBE_ROUND + CUBEFULLROUND, -CUT_DEPTH);
			}
			glPopMatrix();
		}
		if (left != NO_FACE) {
			glPushMatrix();
			glTranslatef(CUBE_ROUND, CUBE_LENGTH, 0.0);
			glBegin(GL_TRIANGLES);
			glVertex3f(-STICKER_OFFSET, 0.0, -STICKER_DEPTH);
			glVertex3f(-STICKERFULLLONG, -STICKERFULLSHORT, -STICKER_DEPTH);
			glVertex3f(-STICKERFULLLONG, STICKERFULLSHORT, -STICKER_DEPTH);
			glEnd();
			if (w->dino.currentFace == BACK_FACE &&
					w->dino.currentPosition == 3) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(-SELECT_OFFSET, 0.0, -SELECT_DEPTH);
				glVertex3f(-SELECTFULLLONG, -SELECTFULLSHORT, -SELECT_DEPTH);
				glVertex3f(-SELECTFULLLONG, SELECTFULLSHORT, -SELECT_DEPTH);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, BACK_FACE,
					w->dino.cubeLoc[BACK_FACE][3].rotation,
					CUBE_ROUND - CUBEFULLROUND, 0.0, -CUT_DEPTH);
			}
			glPopMatrix();
		}
		if (bottom != NO_FACE) {
			glPushMatrix();
			glTranslatef(CUBE_LENGTH, CUBE_ROUND, 0.0);
			glBegin(GL_TRIANGLES);
			glVertex3f(0.0, -STICKER_OFFSET, -STICKER_DEPTH);
			glVertex3f(STICKERFULLSHORT, -STICKERFULLLONG, -STICKER_DEPTH);
			glVertex3f(-STICKERFULLSHORT, -STICKERFULLLONG, -STICKER_DEPTH);
			glEnd();
			if (w->dino.currentFace == BACK_FACE &&
					w->dino.currentPosition == 0) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(0.0, -SELECT_OFFSET, -SELECT_DEPTH);
				glVertex3f(SELECTFULLSHORT, -SELECTFULLLONG, -SELECT_DEPTH);
				glVertex3f(-SELECTFULLSHORT, -SELECTFULLLONG, -SELECT_DEPTH);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, BACK_FACE,
					w->dino.cubeLoc[BACK_FACE][0].rotation,
					0.0, CUBE_ROUND - CUBEFULLROUND, -CUT_DEPTH);
			}
			glPopMatrix();
		}
		if (right != NO_FACE) {
			glPushMatrix();
			glTranslatef(-CUBE_ROUND, -CUBE_LENGTH, 0.0);
			glBegin(GL_TRIANGLES);
			glVertex3f(STICKER_OFFSET, 0.0, -STICKER_DEPTH);
			glVertex3f(STICKERFULLLONG, STICKERFULLSHORT, -STICKER_DEPTH);
			glVertex3f(STICKERFULLLONG, -STICKERFULLSHORT, -STICKER_DEPTH);
			glEnd();
			if (w->dino.currentFace == BACK_FACE &&
					w->dino.currentPosition == 1) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(SELECT_OFFSET, 0.0, -SELECT_DEPTH);
				glVertex3f(SELECTFULLLONG, SELECTFULLSHORT, -SELECT_DEPTH);
				glVertex3f(SELECTFULLLONG, -SELECTFULLSHORT, -SELECT_DEPTH);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, BACK_FACE,
					w->dino.cubeLoc[BACK_FACE][1].rotation,
					-CUBE_ROUND + CUBEFULLROUND, 0.0, -CUT_DEPTH);
			}
			glPopMatrix();
		}
		glPopMatrix();
	}
	if (front < NO_FACE) { /* Yellow */
		glPushMatrix();
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
			face_material[front]);
		glNormal3f(0.0, 0.0, 1.0);
		if (bottom != NO_FACE) {
			glPushMatrix();
			glTranslatef(-CUBE_LENGTH, CUBE_ROUND, 0.0);
			glBegin(GL_TRIANGLES);
			glVertex3f(0.0, -STICKER_OFFSET, STICKER_DEPTH);
			glVertex3f(-STICKERFULLSHORT, -STICKERFULLLONG, STICKER_DEPTH);
			glVertex3f(STICKERFULLSHORT, -STICKERFULLLONG, STICKER_DEPTH);
			glEnd();
			if (w->dino.currentFace == FRONT_FACE &&
					w->dino.currentPosition == 2) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(0.0, -SELECT_OFFSET, SELECT_DEPTH);
				glVertex3f(-SELECTFULLSHORT, -SELECTFULLLONG, SELECT_DEPTH);
				glVertex3f(SELECTFULLSHORT, -SELECTFULLLONG, SELECT_DEPTH);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, FRONT_FACE,
					w->dino.cubeLoc[FRONT_FACE][2].rotation,
					0.0, CUBE_ROUND - CUBEFULLROUND, CUT_DEPTH);
			}
			glPopMatrix();
		}
		if (left != NO_FACE) {
			glPushMatrix();
			glTranslatef(CUBE_ROUND, -CUBE_LENGTH, 0.0);
			glBegin(GL_TRIANGLES);
			glVertex3f(-STICKER_OFFSET, 0.0, STICKER_DEPTH);
			glVertex3f(-STICKERFULLLONG, STICKERFULLSHORT, STICKER_DEPTH);
			glVertex3f(-STICKERFULLLONG, -STICKERFULLSHORT, STICKER_DEPTH);
			glEnd();
			if (w->dino.currentFace == FRONT_FACE &&
					w->dino.currentPosition == 3) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(-SELECT_OFFSET, 0.0, SELECT_DEPTH);
				glVertex3f(-SELECTFULLLONG, SELECTFULLSHORT, SELECT_DEPTH);
				glVertex3f(-SELECTFULLLONG, -SELECTFULLSHORT, SELECT_DEPTH);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, FRONT_FACE,
					w->dino.cubeLoc[FRONT_FACE][3].rotation,
					CUBE_ROUND - CUBEFULLROUND, 0.0, CUT_DEPTH);
			}
			glPopMatrix();
		}
		if (top != NO_FACE) {
			glPushMatrix();
			glTranslatef(CUBE_LENGTH, -CUBE_ROUND, 0.0);
			glBegin(GL_TRIANGLES);
			glVertex3f(0.0, STICKER_OFFSET, STICKER_DEPTH);
			glVertex3f(STICKERFULLSHORT, STICKERFULLLONG, STICKER_DEPTH);
			glVertex3f(-STICKERFULLSHORT, STICKERFULLLONG, STICKER_DEPTH);
			glEnd();
			if (w->dino.currentFace == FRONT_FACE &&
					w->dino.currentPosition == 0) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(0.0, SELECT_OFFSET, SELECT_DEPTH);
				glVertex3f(SELECTFULLSHORT, SELECTFULLLONG, SELECT_DEPTH);
				glVertex3f(-SELECTFULLSHORT, SELECTFULLLONG, SELECT_DEPTH);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, FRONT_FACE,
					w->dino.cubeLoc[FRONT_FACE][0].rotation,
					0.0, -CUBE_ROUND + CUBEFULLROUND, CUT_DEPTH);
			}
			glPopMatrix();
		}
		if (right != NO_FACE) {
			glPushMatrix();
			glTranslatef(-CUBE_ROUND, CUBE_LENGTH, 0.0);
			glBegin(GL_TRIANGLES);
			glVertex3f(STICKER_OFFSET, 0.0, STICKER_DEPTH);
			glVertex3f(STICKERFULLLONG, -STICKERFULLSHORT, STICKER_DEPTH);
			glVertex3f(STICKERFULLLONG, STICKERFULLSHORT, STICKER_DEPTH);
			glEnd();
			if (w->dino.currentFace == FRONT_FACE &&
					w->dino.currentPosition == 1) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(SELECT_OFFSET, 0.0, SELECT_DEPTH);
				glVertex3f(SELECTFULLLONG, -SELECTFULLSHORT, SELECT_DEPTH);
				glVertex3f(SELECTFULLLONG, SELECTFULLSHORT, SELECT_DEPTH);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, FRONT_FACE,
					w->dino.cubeLoc[FRONT_FACE][1].rotation,
					-CUBE_ROUND + CUBEFULLROUND, 0.0, CUT_DEPTH);
			}
			glPopMatrix();
		}
		glPopMatrix();
	}
	if (left < NO_FACE) { /* Blue */
		glPushMatrix();
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
			face_material[left]);
		glNormal3f(-1.0, 0.0, 0.0);
		if (top != NO_FACE) {
			glPushMatrix();
			glTranslatef(0.0, -CUBE_ROUND, CUBE_LENGTH);
			glBegin(GL_TRIANGLES);
			glVertex3f(-STICKER_DEPTH, STICKER_OFFSET, 0.0);
			glVertex3f(-STICKER_DEPTH, STICKERFULLLONG, STICKERFULLSHORT);
			glVertex3f(-STICKER_DEPTH, STICKERFULLLONG, -STICKERFULLSHORT);
			glEnd();
			if (w->dino.currentFace == LEFT_FACE &&
					w->dino.currentPosition == 0) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(-SELECT_DEPTH, SELECT_OFFSET, 0.0);
				glVertex3f(-SELECT_DEPTH, SELECTFULLLONG, SELECTFULLSHORT);
				glVertex3f(-SELECT_DEPTH, SELECTFULLLONG, -SELECTFULLSHORT);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, LEFT_FACE,
					w->dino.cubeLoc[LEFT_FACE][0].rotation,
					-CUT_DEPTH, CUBE_ROUND, 0.0);
			}
			glPopMatrix();
		}
		if (back != NO_FACE) {
			glPushMatrix();
			glTranslatef(0.0, CUBE_LENGTH, CUBE_ROUND);
			glBegin(GL_TRIANGLES);
			glVertex3f(-STICKER_DEPTH, 0.0, -STICKER_OFFSET);
			glVertex3f(-STICKER_DEPTH, STICKERFULLSHORT, -STICKERFULLLONG);
			glVertex3f(-STICKER_DEPTH, -STICKERFULLSHORT, -STICKERFULLLONG);
			glEnd();
			if (w->dino.currentFace == LEFT_FACE &&
					w->dino.currentPosition == 3) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(-SELECT_DEPTH, 0.0, -SELECT_OFFSET);
				glVertex3f(-SELECT_DEPTH, SELECTFULLSHORT, -SELECTFULLLONG);
				glVertex3f(-SELECT_DEPTH, -SELECTFULLSHORT, -SELECTFULLLONG);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, LEFT_FACE,
					w->dino.cubeLoc[LEFT_FACE][3].rotation,
					-CUT_DEPTH, 0.0, CUBE_ROUND - CUBEFULLROUND);
			}
			glPopMatrix();
		}
		if (bottom != NO_FACE) {
			glPushMatrix();
			glTranslatef(0.0, CUBE_ROUND, -CUBE_LENGTH);
			glBegin(GL_TRIANGLES);
			glVertex3f(-STICKER_DEPTH, -STICKER_OFFSET, 0.0);
			glVertex3f(-STICKER_DEPTH, -STICKERFULLLONG, -STICKERFULLSHORT);
			glVertex3f(-STICKER_DEPTH, -STICKERFULLLONG, STICKERFULLSHORT);
			glEnd();
			if (w->dino.currentFace == LEFT_FACE &&
					w->dino.currentPosition == 2) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(-SELECT_DEPTH, -SELECT_OFFSET, 0.0);
				glVertex3f(-SELECT_DEPTH, -SELECTFULLLONG, -SELECTFULLSHORT);
				glVertex3f(-SELECT_DEPTH, -SELECTFULLLONG, SELECTFULLSHORT);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, LEFT_FACE,
					w->dino.cubeLoc[LEFT_FACE][2].rotation,
					-CUT_DEPTH, -CUBE_ROUND, 0.0);
			}
			glPopMatrix();
		}
		if (front != NO_FACE) {
			glPushMatrix();
			glTranslatef(0.0, -CUBE_LENGTH, -CUBE_ROUND);
			glBegin(GL_TRIANGLES);
			glVertex3f(-STICKER_DEPTH, 0.0, STICKER_OFFSET);
			glVertex3f(-STICKER_DEPTH, -STICKERFULLSHORT, STICKERFULLLONG);
			glVertex3f(-STICKER_DEPTH, STICKERFULLSHORT, STICKERFULLLONG);
			glEnd();
			if (w->dino.currentFace == LEFT_FACE &&
					w->dino.currentPosition == 1) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(-SELECT_DEPTH, 0.0, SELECT_OFFSET);
				glVertex3f(-SELECT_DEPTH, -SELECTFULLSHORT, SELECTFULLLONG);
				glVertex3f(-SELECT_DEPTH, SELECTFULLSHORT, SELECTFULLLONG);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, LEFT_FACE,
					w->dino.cubeLoc[LEFT_FACE][1].rotation,
					-CUT_DEPTH, 0.0, -CUBE_ROUND + CUBEFULLROUND);
			}
			glPopMatrix();
		}
		glPopMatrix();
	}
	if (right < NO_FACE) { /* Green */
		glPushMatrix();
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
			face_material[right]);
		glNormal3f(1.0, 0.0, 0.0);
		if (top != NO_FACE) {
			glPushMatrix();
			glTranslatef(0.0, -CUBE_ROUND, -CUBE_LENGTH);
			glBegin(GL_TRIANGLES);
			glVertex3f(STICKER_DEPTH, STICKER_OFFSET, 0.0);
			glVertex3f(STICKER_DEPTH, STICKERFULLLONG, -STICKERFULLSHORT);
			glVertex3f(STICKER_DEPTH, STICKERFULLLONG, STICKERFULLSHORT);
			glEnd();
			if (w->dino.currentFace == RIGHT_FACE &&
					w->dino.currentPosition == 0) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(SELECT_DEPTH, SELECT_OFFSET, 0.0);
				glVertex3f(SELECT_DEPTH, SELECTFULLLONG, -SELECTFULLSHORT);
				glVertex3f(SELECT_DEPTH, SELECTFULLLONG, SELECTFULLSHORT);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, RIGHT_FACE,
					w->dino.cubeLoc[RIGHT_FACE][0].rotation,
					CUT_DEPTH, CUBE_LENGTH, -CUBE_LENGTH + CUBE_ROUND);
			}
			glPopMatrix();
		}
		if (front != NO_FACE) {
			glPushMatrix();
			glTranslatef(0.0, CUBE_LENGTH, -CUBE_ROUND);
			glBegin(GL_TRIANGLES);
			glVertex3f(STICKER_DEPTH, 0.0, STICKER_OFFSET);
			glVertex3f(STICKER_DEPTH, STICKERFULLSHORT, STICKERFULLLONG);
			glVertex3f(STICKER_DEPTH, -STICKERFULLSHORT, STICKERFULLLONG);
			glEnd();
			if (w->dino.currentFace == RIGHT_FACE &&
					w->dino.currentPosition == 3) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(SELECT_DEPTH, 0.0, SELECT_OFFSET);
				glVertex3f(SELECT_DEPTH, SELECTFULLSHORT, SELECTFULLLONG);
				glVertex3f(SELECT_DEPTH, -SELECTFULLSHORT, SELECTFULLLONG);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, RIGHT_FACE,
					w->dino.cubeLoc[RIGHT_FACE][3].rotation,
					CUT_DEPTH, 0.0, -CUBE_ROUND + CUBEFULLROUND);
			}
			glPopMatrix();
		}
		if (bottom != NO_FACE) {
			glPushMatrix();
			glTranslatef(0.0, CUBE_ROUND, CUBE_LENGTH);
			glBegin(GL_TRIANGLES);
			glVertex3f(STICKER_DEPTH, -STICKER_OFFSET, 0.0);
			glVertex3f(STICKER_DEPTH, -STICKERFULLLONG, STICKERFULLSHORT);
			glVertex3f(STICKER_DEPTH, -STICKERFULLLONG, -STICKERFULLSHORT);
			glEnd();
			if (w->dino.currentFace == RIGHT_FACE &&
					w->dino.currentPosition == 2) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(SELECT_DEPTH, -SELECT_OFFSET, 0.0);
				glVertex3f(SELECT_DEPTH, -SELECTFULLLONG, SELECTFULLSHORT);
				glVertex3f(SELECT_DEPTH, -SELECTFULLLONG, -SELECTFULLSHORT);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, RIGHT_FACE,
					w->dino.cubeLoc[RIGHT_FACE][2].rotation,
					CUT_DEPTH, -CUBE_LENGTH, 0.0);
			}
			glPopMatrix();
		}
		if (back != NO_FACE) {
			glPushMatrix();
			glTranslatef(0.0, -CUBE_LENGTH, CUBE_ROUND);
			glBegin(GL_TRIANGLES);
			glVertex3f(STICKER_DEPTH, 0.0, -STICKER_OFFSET);
			glVertex3f(STICKER_DEPTH, -STICKERFULLSHORT, -STICKERFULLLONG);
			glVertex3f(STICKER_DEPTH, STICKERFULLSHORT, -STICKERFULLLONG);
			glEnd();
			if (w->dino.currentFace == RIGHT_FACE &&
					w->dino.currentPosition == 1) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(SELECT_DEPTH, 0.0, -SELECT_OFFSET);
				glVertex3f(SELECT_DEPTH, -SELECTFULLSHORT, -SELECTFULLLONG);
				glVertex3f(SELECT_DEPTH, SELECTFULLSHORT, -SELECTFULLLONG);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, RIGHT_FACE,
					w->dino.cubeLoc[RIGHT_FACE][1].rotation,
					CUT_DEPTH, CUBE_ROUND - CUBE_LENGTH, CUBE_ROUND - CUBEFULLROUND);
			}
			glPopMatrix();
		}
		glPopMatrix();
	}
	if (bottom < NO_FACE) { /* White */
		glPushMatrix();
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
			face_material[bottom]);
		glNormal3f(0.0, -1.0, 0.0);
		if (front != NO_FACE) {
			glPushMatrix();
			glTranslatef(-CUBE_LENGTH, 0.0, -CUBE_ROUND);
			glBegin(GL_TRIANGLES);
			glVertex3f(0.0, -STICKER_DEPTH, STICKER_OFFSET);
			glVertex3f(STICKERFULLSHORT, -STICKER_DEPTH, STICKERFULLLONG);
			glVertex3f(-STICKERFULLSHORT, -STICKER_DEPTH, STICKERFULLLONG);
			glEnd();
			if (w->dino.currentFace == BOTTOM_FACE &&
					w->dino.currentPosition == 0) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(0.0, -SELECT_DEPTH, SELECT_OFFSET);
				glVertex3f(SELECTFULLSHORT, -SELECT_DEPTH, SELECTFULLLONG);
				glVertex3f(-SELECTFULLSHORT, -SELECT_DEPTH, SELECTFULLLONG);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, BOTTOM_FACE,
					w->dino.cubeLoc[BOTTOM_FACE][0].rotation,
					0.0, -CUT_DEPTH, CUBE_ROUND);
			}
			glPopMatrix();
		}
		if (right != NO_FACE) {
			glPushMatrix();
			glTranslatef(-CUBE_ROUND, 0.0, CUBE_LENGTH);
			glBegin(GL_TRIANGLES);
			glVertex3f(STICKER_OFFSET, -STICKER_DEPTH, 0.0);
			glVertex3f(STICKERFULLLONG, -STICKER_DEPTH, -STICKERFULLSHORT);
			glVertex3f(STICKERFULLLONG, -STICKER_DEPTH, STICKERFULLSHORT);
			glEnd();
			if (w->dino.currentFace == BOTTOM_FACE &&
					w->dino.currentPosition == 1) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(SELECT_OFFSET, -SELECT_DEPTH, 0.0);
				glVertex3f(SELECTFULLLONG, -SELECT_DEPTH, -SELECTFULLSHORT);
				glVertex3f(SELECTFULLLONG, -SELECT_DEPTH, SELECTFULLSHORT);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, BOTTOM_FACE,
					w->dino.cubeLoc[BOTTOM_FACE][1].rotation,
					CUBE_ROUND, -CUT_DEPTH, 0.0);
			}
			glPopMatrix();
		}
		if (back != NO_FACE) {
			glPushMatrix();
			glTranslatef(CUBE_LENGTH, 0.0, CUBE_ROUND);
			glBegin(GL_TRIANGLES);
			glVertex3f(0.0, -STICKER_DEPTH, -STICKER_OFFSET);
			glVertex3f(-STICKERFULLSHORT, -STICKER_DEPTH, -STICKERFULLLONG);
			glVertex3f(STICKERFULLSHORT, -STICKER_DEPTH, -STICKERFULLLONG);
			glEnd();
			if (w->dino.currentFace == BOTTOM_FACE &&
					w->dino.currentPosition == 2) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(0.0, -SELECT_DEPTH, -SELECT_OFFSET);
				glVertex3f(-SELECTFULLSHORT, -SELECT_DEPTH, -SELECTFULLLONG);
				glVertex3f(SELECTFULLSHORT, -SELECT_DEPTH, -SELECTFULLLONG);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, BOTTOM_FACE,
					w->dino.cubeLoc[BOTTOM_FACE][2].rotation,
					0.0, -CUT_DEPTH, -CUBE_ROUND);
			}
			glPopMatrix();
		}
		if (left != NO_FACE) {
			glPushMatrix();
			glTranslatef(CUBE_ROUND, 0.0, -CUBE_LENGTH);
			glBegin(GL_TRIANGLES);
			glVertex3f(-STICKER_OFFSET, -STICKER_DEPTH, 0.0);
			glVertex3f(-STICKERFULLLONG, -STICKER_DEPTH, STICKERFULLSHORT);
			glVertex3f(-STICKERFULLLONG, -STICKER_DEPTH, -STICKERFULLSHORT);
			glEnd();
			if (w->dino.currentFace == BOTTOM_FACE &&
					w->dino.currentPosition == 3) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(-SELECT_OFFSET, -SELECT_DEPTH, 0.0);
				glVertex3f(-SELECTFULLLONG, -SELECT_DEPTH, SELECTFULLSHORT);
				glVertex3f(-SELECTFULLLONG, -SELECT_DEPTH, -SELECTFULLSHORT);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, BOTTOM_FACE,
					w->dino.cubeLoc[BOTTOM_FACE][3].rotation,
					-CUBE_ROUND, -CUT_DEPTH, 0.0);
			}
			glPopMatrix();
		}
		glPopMatrix();
	}
	if (top < NO_FACE) { /* Red */
		glPushMatrix();
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
			face_material[top]);
		glNormal3f(0.0, 1.0, 0.0);
		if (back != NO_FACE) {
			glPushMatrix();
			glTranslatef(-CUBE_LENGTH, 0, CUBE_ROUND);
			glBegin(GL_TRIANGLES);
			glVertex3f(0.0, STICKER_DEPTH, -STICKER_OFFSET);
			glVertex3f(STICKERFULLSHORT, STICKER_DEPTH, -STICKERFULLLONG);
			glVertex3f(-STICKERFULLSHORT, STICKER_DEPTH, -STICKERFULLLONG);
			glEnd();
			if (w->dino.currentFace == TOP_FACE &&
					w->dino.currentPosition == 0) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(0.0, SELECT_DEPTH, -SELECT_OFFSET);
				glVertex3f(SELECTFULLSHORT, SELECT_DEPTH, -SELECTFULLLONG);
				glVertex3f(-SELECTFULLSHORT, SELECT_DEPTH, -SELECTFULLLONG);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, TOP_FACE,
					w->dino.cubeLoc[TOP_FACE][0].rotation,
					0.0, CUT_DEPTH, -CUBE_LENGTH);
			}
			glPopMatrix();
		}
		if (right != NO_FACE) {
			glPushMatrix();
			glTranslatef(-CUBE_ROUND, 0.0, -CUBE_LENGTH);
			glBegin(GL_TRIANGLES);
			glVertex3f(STICKER_OFFSET, STICKER_DEPTH, 0.0);
			glVertex3f(STICKERFULLLONG, STICKER_DEPTH, STICKERFULLSHORT);
			glVertex3f(STICKERFULLLONG, STICKER_DEPTH, -STICKERFULLSHORT);
			glEnd();
			if (w->dino.currentFace == TOP_FACE &&
					w->dino.currentPosition == 1) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(SELECT_OFFSET, SELECT_DEPTH, 0.0);
				glVertex3f(SELECTFULLLONG, SELECT_DEPTH, SELECTFULLSHORT);
				glVertex3f(SELECTFULLLONG, SELECT_DEPTH, -SELECTFULLSHORT);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, TOP_FACE,
					w->dino.cubeLoc[TOP_FACE][1].rotation,
					CUBE_LENGTH, CUT_DEPTH, 0.0);
			}
			glPopMatrix();
		}
		if (front != NO_FACE) {
			glPushMatrix();
			glTranslatef(CUBE_LENGTH, 0, -CUBE_ROUND);
			glBegin(GL_TRIANGLES);
			glVertex3f(0.0, STICKER_DEPTH, STICKER_OFFSET);
			glVertex3f(-STICKERFULLSHORT, STICKER_DEPTH, STICKERFULLLONG);
			glVertex3f(STICKERFULLSHORT, STICKER_DEPTH, STICKERFULLLONG);
			glEnd();
			if (w->dino.currentFace == TOP_FACE &&
					w->dino.currentPosition == 2) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(0.0, SELECT_DEPTH, SELECT_OFFSET);
				glVertex3f(-SELECTFULLSHORT, SELECT_DEPTH, SELECTFULLLONG);
				glVertex3f(SELECTFULLSHORT, SELECT_DEPTH, SELECTFULLLONG);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, TOP_FACE,
					w->dino.cubeLoc[TOP_FACE][2].rotation,
					0.0, CUT_DEPTH, CUBE_LENGTH);
			}
			glPopMatrix();
		}
		if (left != NO_FACE) {
			glPushMatrix();
			glTranslatef(CUBE_ROUND, 0.0, CUBE_LENGTH);
			glBegin(GL_TRIANGLES);
			glVertex3f(-STICKER_OFFSET, STICKER_DEPTH, 0.0);
			glVertex3f(-STICKERFULLLONG, STICKER_DEPTH, -STICKERFULLSHORT);
			glVertex3f(-STICKERFULLLONG, STICKER_DEPTH, STICKERFULLSHORT);
			glEnd();
			if (w->dino.currentFace == TOP_FACE &&
					w->dino.currentPosition == 3) {
				glBegin(GL_TRIANGLES);
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
					face_material[BORDER_FACE]);
				glVertex3f(-SELECT_OFFSET, SELECT_DEPTH, 0.0);
				glVertex3f(-SELECTFULLLONG, SELECT_DEPTH, -SELECTFULLSHORT);
				glVertex3f(-SELECTFULLLONG, SELECT_DEPTH, SELECTFULLSHORT);
				glEnd();
			}
			if (w->dino.orient) {
				drawOrientLine(w, TOP_FACE,
					w->dino.cubeLoc[TOP_FACE][3].rotation,
					-CUBE_LENGTH, CUT_DEPTH, 0.0);
			}
			glPopMatrix();
		}
		glPopMatrix();
	}
}

static void
drawHalfCubit(DinoGLWidget w, int face, int x, int y, int z)
{
	const float h = 0.5;
	Boolean s = (w->dino.mode != PERIOD3);
	int f1 = NO_FACE + 1;
	int f2 = NO_FACE + 1;

	if (x < 0) {
		if (y < 0) {
			if (z == 0) {
				glPushMatrix();
				glTranslatef(-h, -h, h);
				glPushMatrix();
				glRotatef(180.0, 0, 0, 1);
				s = (face == LEFT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* White Blue */
				glPopMatrix();
				if (face == LEFT_FACE)
					f1 = w->dino.cubeLoc[LEFT_FACE][2].face;
				else if (face == BOTTOM_FACE)
					f2 = w->dino.cubeLoc[BOTTOM_FACE][3].face;
				drawCubit(w, /* LB */
					NO_FACE,
					NO_FACE,
					f1,
					NO_FACE,
					f2,
					NO_FACE);
				glPopMatrix();
			}
		} else if (y == 0) {
			if (z < 0) {
				glPushMatrix();
				glTranslatef(-h, -h, -h);
				glPushMatrix();
				glRotatef(90.0, 1, 0, 0);
				glRotatef(180.0, 0, 0, 1);
				s = (face == LEFT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* Blue Orange */
				glPopMatrix();
				if (face == BACK_FACE)
					f1 = w->dino.cubeLoc[BACK_FACE][3].face;
				else if (face == LEFT_FACE)
					f2 = w->dino.cubeLoc[LEFT_FACE][3].face;
				drawCubit(w, /* BL */
					f1,
					NO_FACE,
					f2,
					NO_FACE,
					NO_FACE,
					NO_FACE);
				glPopMatrix();
			} else if (z > 0) {
				glPushMatrix();
				glTranslatef(-h, h, h);
				glPushMatrix();
				glRotatef(90.0, -1, 0, 0);
				glRotatef(180.0, 0, 0, 1);
				s = (face == LEFT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* Blue Yellow */
				glPopMatrix();
				if (face == FRONT_FACE)
					f1 = w->dino.cubeLoc[FRONT_FACE][3].face;
				else if (face == LEFT_FACE)
					f2 = w->dino.cubeLoc[LEFT_FACE][1].face;
				drawCubit(w, /* FL */
					NO_FACE,
					f1,
					f2,
					NO_FACE,
					NO_FACE,
					NO_FACE);
				glPopMatrix();
			}
		} else /* if (y > 0) */ {
			if (z == 0) {
				glPushMatrix();
				glTranslatef(-h, h, -h);
				glPushMatrix();
				glRotatef(180.0, 0, 1, 0);
				s = (face == LEFT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* Red Blue */
				glPopMatrix();
				if (face == LEFT_FACE)
					f1 = w->dino.cubeLoc[LEFT_FACE][0].face;
				else if (face == TOP_FACE)
					f2 = w->dino.cubeLoc[TOP_FACE][3].face;
				drawCubit(w, /* LT */
					NO_FACE,
					NO_FACE,
					f1,
					NO_FACE,
					NO_FACE,
					f2);
				glPopMatrix();
			}
		}
	} else if (x == 0) {
		if (y < 0) {
			if (z < 0) {
				glPushMatrix();
				glTranslatef(-h, -h, -h);
				glPushMatrix();
				glRotatef(90.0, 0, -1, 0);
				glRotatef(180.0, 0, 0, 1);
				s = (face == BACK_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* White Orange */
				glPopMatrix();
				if (face == BACK_FACE)
					f1 = w->dino.cubeLoc[BACK_FACE][0].face;
				else if (face == BOTTOM_FACE)
					f2 = w->dino.cubeLoc[BOTTOM_FACE][2].face;
				drawCubit(w, /* BB */
					f1,
					NO_FACE,
					NO_FACE,
					NO_FACE,
					f2,
					NO_FACE);
				glPopMatrix();
			} else if (z > 0) {
				glPushMatrix();
				glTranslatef(h, -h, h);
				glPushMatrix();
				glRotatef(90.0, 0, 1, 0);
				glRotatef(180.0, 0, 0, 1);
				s = (face == FRONT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* White Yellow */
				glPopMatrix();
				if (face == FRONT_FACE)
					f1 = w->dino.cubeLoc[FRONT_FACE][2].face;
				else if (face == BOTTOM_FACE)
					f2 = w->dino.cubeLoc[BOTTOM_FACE][0].face;
				drawCubit(w, /* FB */
					NO_FACE,
					f1,
					NO_FACE,
					NO_FACE,
					f2,
					NO_FACE);
				glPopMatrix();
			}
		} else if (y > 0) {
			if (z < 0) {
				glPushMatrix();
				glTranslatef(h, h, -h);
				glPushMatrix();
				glRotatef(90.0, 0, 1, 0);
				s = (face == TOP_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* Red Orange */
				glPopMatrix();
				if (face == BACK_FACE)
					f1 = w->dino.cubeLoc[BACK_FACE][2].face;
				else if (face == TOP_FACE)
					f2 = w->dino.cubeLoc[TOP_FACE][0].face;
				drawCubit(w, /* BT */
					f1,
					NO_FACE,
					NO_FACE,
					NO_FACE,
					NO_FACE,
					f2);
				glPopMatrix();
			} else if (z > 0) {
				glPushMatrix();
				glTranslatef(-h, h, h);
				glPushMatrix();
				glRotatef(-90.0, 0, 1, 0);
				s = (face == FRONT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* Red Yellow */
				glPopMatrix();
				if (face == FRONT_FACE)
					f1 = w->dino.cubeLoc[FRONT_FACE][0].face;
				else if (face == TOP_FACE)
					f2 = w->dino.cubeLoc[TOP_FACE][2].face;
				drawCubit(w, /* FT */
					NO_FACE,
					f1,
					NO_FACE,
					NO_FACE,
					NO_FACE,
					f2);
				glPopMatrix();
			}
		}
	} else /* if (x > 0) */ {
		if (y < 0) {
			if (z == 0) {
				glPushMatrix();
				glTranslatef(h, -h, -h);
				glPushMatrix();
				glRotatef(180.0, 0, 1, 0);
				glRotatef(180.0, 0, 0, 1);
				s = (face == RIGHT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* White Green */
				glPopMatrix();
				if (face == RIGHT_FACE)
					f1 = w->dino.cubeLoc[RIGHT_FACE][2].face;
				else if (face == BOTTOM_FACE)
					f2 = w->dino.cubeLoc[BOTTOM_FACE][1].face;
				drawCubit(w, /* RB */
					NO_FACE,
					NO_FACE,
					NO_FACE,
					f1,
					f2,
					NO_FACE);
				glPopMatrix();
			}
		} else if (y == 0) {
			if (z < 0) {
				glPushMatrix();
				glTranslatef(h, h, -h);
				glPushMatrix();
				glRotatef(90.0, -1, 0, 0);
				s = (face == RIGHT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* Green Orange */
				glPopMatrix();
				if (face == BACK_FACE)
					f1 = w->dino.cubeLoc[BACK_FACE][1].face;
				else if (face == RIGHT_FACE)
					f2 = w->dino.cubeLoc[RIGHT_FACE][1].face;
				drawCubit(w, /* BR */
					f1,
					NO_FACE,
					NO_FACE,
					f2,
					NO_FACE,
					NO_FACE);
				glPopMatrix();
			} else if (z > 0) {
				glPushMatrix();
				glTranslatef(h, -h, h);
				glPushMatrix();
				glRotatef(90.0, 1, 0, 0);
				s = (face == RIGHT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* Green Yellow */
				glPopMatrix();
				if (face == FRONT_FACE)
					f1 = w->dino.cubeLoc[FRONT_FACE][1].face;
				else if (face == RIGHT_FACE)
					f2 = w->dino.cubeLoc[RIGHT_FACE][3].face;
				drawCubit(w, /* FR */
					NO_FACE,
					f1,
					NO_FACE,
					f2,
					NO_FACE,
					NO_FACE);
				glPopMatrix();
			}
		} else /* if (y > 0) */ {
			if (z == 0) {
				glPushMatrix();
				glTranslatef(h, h, h);
				glPushMatrix();
				s = (face == RIGHT_FACE) ? 1 : 0;
				drawStickerlessHalfCubit(s); /* Red Green */
				glPopMatrix();
				if (face == RIGHT_FACE)
					f1 = w->dino.cubeLoc[RIGHT_FACE][0].face;
				else if (face == TOP_FACE)
					f2 = w->dino.cubeLoc[TOP_FACE][1].face;
				drawCubit(w, /* RT */
					NO_FACE,
					NO_FACE,
					NO_FACE,
					f1,
					NO_FACE,
					f2);
				glPopMatrix();
			}
		}
	}
}

static void
drawWholeFace(DinoGLWidget w, int face)
{
	int s, v = 1;

	switch (face) {
	case 0:
		s = 1;
		drawHalfCubit(w, face, 0, s, -v);
		drawHalfCubit(w, face, v, s, 0);
		drawHalfCubit(w, face, 0, s, v);
		drawHalfCubit(w, face, -v, s, 0);
		break;
	case 1:
		s = -1;
		drawHalfCubit(w, face, s, v, 0);
		drawHalfCubit(w, face, s, 0, v);
		drawHalfCubit(w, face, s, -v, 0);
		drawHalfCubit(w, face, s, 0, -v);
		break;
	case 2:
		s = 1;
		drawHalfCubit(w, face, 0, v, s);
		drawHalfCubit(w, face, v, 0, s);
		drawHalfCubit(w, face, 0, -v, s);
		drawHalfCubit(w, face, -v, 0, s);
		break;
	case 3:
		s = 1;
		drawHalfCubit(w, face, s, v, 0);
		drawHalfCubit(w, face, s, 0, -v);
		drawHalfCubit(w, face, s, -v, 0);
		drawHalfCubit(w, face, s, 0, v);
		break;
	case 4:
		s = -1;
		drawHalfCubit(w, face, 0, s, v);
		drawHalfCubit(w, face, v, s, 0);
		drawHalfCubit(w, face, 0, s, -v);
		drawHalfCubit(w, face, -v, s, 0);
		break;
	case 5:
		s = -1;
		drawHalfCubit(w, face, 0, -v, s);
		drawHalfCubit(w, face, v, 0, s);
		drawHalfCubit(w, face, 0, v, s);
		drawHalfCubit(w, face, -v, 0, s);
		break;
	}
}

static void
drawHalfFace(DinoGLWidget w, int face, int rad)
{
	int s, v = 1;

	switch (face) {
	case 0:
		s = 1;
		if (rad == 0 || rad == 3)
			drawHalfCubit(w, face, 0, s, -v);
		if (rad == 0 || rad == 1)
			drawHalfCubit(w, face, v, s, 0);
		if (rad == 1 || rad == 2)
			drawHalfCubit(w, face, 0, s, v);
		if (rad == 2 || rad == 3)
			drawHalfCubit(w, face, -v, s, 0);
		break;
	case 1:
		s = -1;
		if (rad == 0 || rad == 3)
			drawHalfCubit(w, face, s, v, 0);
		if (rad == 0 || rad == 1)
			drawHalfCubit(w, face, s, 0, v);
		if (rad == 1 || rad == 2)
			drawHalfCubit(w, face, s, -v, 0);
		if (rad == 2 || rad == 3)
			drawHalfCubit(w, face, s, 0, -v);
		break;
	case 2:
		s = 1;
		if (rad == 0 || rad == 3)
			drawHalfCubit(w, face, 0, v, s);
		if (rad == 0 || rad == 1)
			drawHalfCubit(w, face, v, 0, s);
		if (rad == 1 || rad == 2)
			drawHalfCubit(w, face, 0, -v, s);
		if (rad == 2 || rad == 3)
			drawHalfCubit(w, face, -v, 0, s);
		break;
	case 3:
		s = 1;
		if (rad == 0 || rad == 3)
			drawHalfCubit(w, face, s, v, 0);
		if (rad == 0 || rad == 1)
			drawHalfCubit(w, face, s, 0, -v);
		if (rad == 1 || rad == 2)
			drawHalfCubit(w, face, s, -v, 0);
		if (rad == 2 || rad == 3)
			drawHalfCubit(w, face, s, 0, v);
		break;
	case 4:
		s = -1;
		if (rad == 0 || rad == 3)
			drawHalfCubit(w, face, 0, s, v);
		if (rad == 0 || rad == 1)
			drawHalfCubit(w, face, v, s, 0);
		if (rad == 1 || rad == 2)
			drawHalfCubit(w, face, 0, s, -v);
		if (rad == 2 || rad == 3)
			drawHalfCubit(w, face, -v, s, 0);
		break;
	case 5:
		s = -1;
		if (rad == 0 || rad == 3)
			drawHalfCubit(w, face, 0, -v, s);
		if (rad == 0 || rad == 1)
			drawHalfCubit(w, face, v, 0, s);
		if (rad == 1 || rad == 2)
			drawHalfCubit(w, face, 0, v, s);
		if (rad == 2 || rad == 3)
			drawHalfCubit(w, face, -v, 0, s);
		break;
	}
}

static void
drawWholeCubit(DinoGLWidget w, int x, int y, int z)
{
	const float h = 0.5;
	Boolean s = (w->dino.mode != PERIOD3);

	if (x < 0) {
		if (y < 0) {
			if (z == 0) {
				glPushMatrix();
				glTranslatef(-h, -h, h);
				glPushMatrix();
				glRotatef(180.0, 0, 0, 1);
				drawStickerlessCubit(s); /* White Blue */
				glPopMatrix();
				drawCubit(w, /* LB */
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[LEFT_FACE][2].face,
					NO_FACE,
					w->dino.cubeLoc[BOTTOM_FACE][3].face,
					NO_FACE);
				glPopMatrix();
			}
		} else if (y == 0) {
			if (z < 0) {
				glPushMatrix();
				glTranslatef(-h, -h, -h);
				glPushMatrix();
				glRotatef(90.0, 1, 0, 0);
				glRotatef(180.0, 0, 0, 1);
				drawStickerlessCubit(s); /* Blue Orange */
				glPopMatrix();
				drawCubit(w, /* BL */
					w->dino.cubeLoc[BACK_FACE][3].face,
					NO_FACE,
					w->dino.cubeLoc[LEFT_FACE][3].face,
					NO_FACE,
					NO_FACE,
					NO_FACE);
				glPopMatrix();
			} else if (z > 0) {
				glPushMatrix();
				glTranslatef(-h, h, h);
				glPushMatrix();
				glRotatef(90.0, -1, 0, 0);
				glRotatef(180.0, 0, 0, 1);
				drawStickerlessCubit(s); /* Blue Yellow */
				glPopMatrix();
				drawCubit(w, /* FL */
					NO_FACE,
					w->dino.cubeLoc[FRONT_FACE][3].face,
					w->dino.cubeLoc[LEFT_FACE][1].face,
					NO_FACE,
					NO_FACE,
					NO_FACE);
				glPopMatrix();
			}
		} else /* if (y > 0) */ {
			if (z == 0) {
				glPushMatrix();
				glTranslatef(-h, h, -h);
				glPushMatrix();
				glRotatef(180.0, 0, 1, 0);
				drawStickerlessCubit(s); /* Red Blue */
				glPopMatrix();
				drawCubit(w, /* LT */
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[LEFT_FACE][0].face,
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[TOP_FACE][3].face);
				glPopMatrix();
			}
		}
	} else if (x == 0) {
		if (y < 0) {
			if (z < 0) {
				glPushMatrix();
				glTranslatef(-h, -h, -h);
				glPushMatrix();
				glRotatef(90.0, 0, -1, 0);
				glRotatef(180.0, 0, 0, 1);
				drawStickerlessCubit(s); /* White Orange */
				glPopMatrix();
				drawCubit(w, /* BB */
					w->dino.cubeLoc[BACK_FACE][0].face,
					NO_FACE,
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[BOTTOM_FACE][2].face,
					NO_FACE);
				glPopMatrix();
			} else if (z > 0) {
				glPushMatrix();
				glTranslatef(h, -h, h);
				glPushMatrix();
				glRotatef(90.0, 0, 1, 0);
				glRotatef(180.0, 0, 0, 1);
				drawStickerlessCubit(s); /* White Yellow */
				glPopMatrix();
				drawCubit(w, /* FB */
					NO_FACE,
					w->dino.cubeLoc[FRONT_FACE][2].face,
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[BOTTOM_FACE][0].face,
					NO_FACE);
				glPopMatrix();
			}
		} else if (y > 0) {
			if (z < 0) {
				glPushMatrix();
				glTranslatef(h, h, -h);
				glPushMatrix();
				glRotatef(90.0, 0, 1, 0);
				drawStickerlessCubit(s); /* Red Orange */
				glPopMatrix();
				drawCubit(w, /* BT */
					w->dino.cubeLoc[BACK_FACE][2].face,
					NO_FACE,
					NO_FACE,
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[TOP_FACE][0].face);
				glPopMatrix();
			} else if (z > 0) {
				glPushMatrix();
				glTranslatef(-h, h, h);
				glPushMatrix();
				glRotatef(-90.0, 0, 1, 0);
				drawStickerlessCubit(s); /* Red Yellow */
				glPopMatrix();
				drawCubit(w, /* FT */
					NO_FACE,
					w->dino.cubeLoc[FRONT_FACE][0].face,
					NO_FACE,
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[TOP_FACE][2].face);
				glPopMatrix();
			}
		}
	} else /* if (x > 0) */ {
		if (y < 0) {
			if (z == 0) {
				glPushMatrix();
				glTranslatef(h, -h, -h);
				glPushMatrix();
				glRotatef(180.0, 0, 1, 0);
				glRotatef(180.0, 0, 0, 1);
				drawStickerlessCubit(s); /* White Green */
				glPopMatrix();
				drawCubit(w, /* RB */
					NO_FACE,
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[RIGHT_FACE][2].face,
					w->dino.cubeLoc[BOTTOM_FACE][1].face,
					NO_FACE);
				glPopMatrix();
			}
		} else if (y == 0) {
			if (z < 0) {
				glPushMatrix();
				glTranslatef(h, h, -h);
				glPushMatrix();
				glRotatef(90.0, -1, 0, 0);
				drawStickerlessCubit(s); /* Green Orange */
				glPopMatrix();
				drawCubit(w, /* BR */
					w->dino.cubeLoc[BACK_FACE][1].face,
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[RIGHT_FACE][1].face,
					NO_FACE,
					NO_FACE);
				glPopMatrix();
			} else if (z > 0) {
				glPushMatrix();
				glTranslatef(h, -h, h);
				glPushMatrix();
				glRotatef(90.0, 1, 0, 0);
				drawStickerlessCubit(s); /* Green Yellow */
				glPopMatrix();
				drawCubit(w, /* FR */
					NO_FACE,
					w->dino.cubeLoc[FRONT_FACE][1].face,
					NO_FACE,
					w->dino.cubeLoc[RIGHT_FACE][3].face,
					NO_FACE,
					NO_FACE);
				glPopMatrix();
			}
		} else /* if (y > 0) */ {
			if (z == 0) {
				glPushMatrix();
				glTranslatef(h, h, h);
				glPushMatrix();
				drawStickerlessCubit(s); /* Red Green */
				glPopMatrix();
				drawCubit(w, /* RT */
					NO_FACE,
					NO_FACE,
					NO_FACE,
					w->dino.cubeLoc[RIGHT_FACE][0].face,
					NO_FACE,
					w->dino.cubeLoc[TOP_FACE][1].face);
				glPopMatrix();
			}
		}
	}
}

static int nextCorner[MAX_FACES][MAX_ORIENT][2] =
{
	{{2, 6}, {7, 6}, {7, 3}, {2, 3}},
	{{2, 3}, {1, 3}, {1, 0}, {2, 0}},
	{{3, 7}, {5, 7}, {5, 1}, {3, 1}},
	{{7, 6}, {4, 6}, {4, 5}, {7, 5}},
	{{1, 5}, {4, 5}, {4, 0}, {1, 0}},
	{{0, 4}, {6, 4}, {6, 2}, {0, 2}}
};

static int nextFace[MAX_FACES][MAX_ORIENT] =
{
	{-4, -1, 4, 1},
	{-1, 2, 1, -2},
	{-4, 2, 4, -2},
	{1, 2, -1, -2},
	{-4, 1, 4, -1},
	{-4, -2, 4, 2},
};

static int edgeToFaces[MAX_EDGES][MAX_FACES] =
{
	{4, 5, 1, 3, 0, 2},
	{2, 4, 1, 3, 0, 5},
	{0, 5, 1, 3, 2, 4},
	{0, 2, 1, 3, 4, 5},

	{1, 5, 0, 4, 2, 3},
	{1, 2, 0, 4, 3, 5},
	{3, 5, 0, 4, 1, 2},
	{2, 3, 0, 4, 1, 5},

	{1, 4, 2, 5, 0, 3},
	{0, 1, 2, 5, 3, 4},
	{3, 4, 2, 5, 0, 1},
	{0, 3, 2, 5, 1, 4}
};

static int edgeToRad[MAX_EDGES][2] =
{
	{2, 1}, {1, 2}, {3, 0}, {0, 3},
	{3, 2}, {2, 3}, {0, 1}, {1, 0},
	{2, 3}, {3, 2}, {1, 0}, {0, 1},
};

static void
convertMove3(DinoMove move, DinoSlice * slice, int style)
{
	int position = move.position;

	if (style == MIDDLE)
		position = (position + 2) % MAX_ORIENT;
	(*slice).corner = nextCorner[move.face][position][move.direction % 2];
	switch (move.direction % MAX_ORIENT) {
	case 0:
		(*slice).rotation = (position == 1 || position == 2) ?
			CW : CCW;
		break;
	case 1:
		(*slice).rotation = (position == 2 || position == 3) ?
			CW : CCW;
		break;
	case 2:
		(*slice).rotation = (position == 1 || position == 2) ?
			CCW : CW;
		break;
	case 3:
		(*slice).rotation = (position == 2 || position == 3) ?
			CCW : CW;
		break;
	}
}

static void
convertMove2(DinoMove move, DinoSplit * split)
{
	int position = move.position;

	switch (move.face) {
	case 0:
		if (move.direction % 2 == 0) {
			if (position == 0 || position == 3) {
				(*split).edge = 4;
				(*split).rotation = (move.direction == 2) ?
					CW : CCW;
			} else if (position == 1 || position == 2) {
				(*split).edge = 7;
				(*split).rotation = (move.direction == 0) ?
					CW : CCW;
			}
		} else {
			if (position == 0 || position == 1) {
				(*split).edge = 6;
				(*split).rotation = (move.direction == 3) ?
					CW : CCW;
			} else if (position == 2 || position == 3) {
				(*split).edge = 5;
				(*split).rotation = (move.direction == 1) ?
					CW : CCW;
			}
		}
		break;
	case 1:
		if (move.direction % 2 == 0) {
			if (position == 0 || position == 3) {
				(*split).edge = 2;
				(*split).rotation = (move.direction == 2) ?
					CW : CCW;
			} else if (position == 1 || position == 2) {
				(*split).edge = 1;
				(*split).rotation = (move.direction == 0) ?
					CW : CCW;
			}
		} else {
			if (position == 0 || position == 1) {
				(*split).edge = 3;
				(*split).rotation = (move.direction == 3) ?
					CW : CCW;
			} else if (position == 2 || position == 3) {
				(*split).edge = 0;
				(*split).rotation = (move.direction == 1) ?
					CW : CCW;
			}
		}
		break;
	case 2:
		if (move.direction % 2 == 0) {
			if (position == 0 || position == 3) {
				(*split).edge = 9;
				(*split).rotation = (move.direction == 2) ?
					CW : CCW;
			} else if (position == 1 || position == 2) {
				(*split).edge = 10;
				(*split).rotation = (move.direction == 0) ?
					CW : CCW;
			}
		} else {
			if (position == 0 || position == 1) {
				(*split).edge = 11;
				(*split).rotation = (move.direction == 3) ?
					CW : CCW;
			} else if (position == 2 || position == 3) {
				(*split).edge = 8;
				(*split).rotation = (move.direction == 1) ?
					CW : CCW;
			}
		}
		break;
	case 3:
		if (move.direction % 2 == 0) {
			if (position == 0 || position == 3) {
				(*split).edge = 3;
				(*split).rotation = (move.direction == 2) ?
					CW : CCW;
			} else if (position == 1 || position == 2) {
				(*split).edge = 0;
				(*split).rotation = (move.direction == 0) ?
					CW : CCW;
			}
		} else {
			if (position == 0 || position == 1) {
				(*split).edge = 2;
				(*split).rotation = (move.direction == 3) ?
					CW : CCW;
			} else if (position == 2 || position == 3) {
				(*split).edge = 1;
				(*split).rotation = (move.direction == 1) ?
					CW : CCW;
			}
		}
		break;
	case 4:
		if (move.direction % 2 == 0) {
			if (position == 0 || position == 3) {
				(*split).edge = 5;
				(*split).rotation = (move.direction == 2) ?
					CW : CCW;
			} else if (position == 1 || position == 2) {
				(*split).edge = 6;
				(*split).rotation = (move.direction == 0) ?
					CW : CCW;
			}
		} else {
			if (position == 0 || position == 1) {
				(*split).edge = 7;
				(*split).rotation = (move.direction == 3) ?
					CW : CCW;
			} else if (position == 2 || position == 3) {
				(*split).edge = 4;
				(*split).rotation = (move.direction == 1) ?
					CW : CCW;
			}
		}
		break;
	case 5:
		if (move.direction % 2 == 0) {
			if (position == 0 || position == 3) {
				(*split).edge = 8;
				(*split).rotation = (move.direction == 2) ?
					CW : CCW;
			} else if (position == 1 || position == 2) {
				(*split).edge = 11;
				(*split).rotation = (move.direction == 0) ?
					CW : CCW;
			}
		} else {
			if (position == 0 || position == 1) {
				(*split).edge = 10;
				(*split).rotation = (move.direction == 3) ?
					CW : CCW;
			} else if (position == 2 || position == 3) {
				(*split).edge = 9;
				(*split).rotation = (move.direction == 1) ?
					CW : CCW;
			}
		}
		break;
	}
}

static void
cornerRotate(DinoGLWidget w, int corner, GLfloat rotateStep)
{
#define X1 (((corner & 4) != 0) ? 1 : -1)
#define Y1 (((corner & 2) != 0) ? 1 : -1)
#define Z1 (((corner & 1) != 0) ? 1 : -1)
#define Xn (((corner & 4) != 0) ? -1 : 1)
#define Yn (((corner & 2) != 0) ? -1 : 1)
#define Zn (((corner & 1) != 0) ? -1 : 1)
	drawCenter();
	glPushMatrix();
	glRotatef(rotateStep, X1, Y1, Z1);
	drawWholeCubit(w, 0, Y1, Z1);
	drawWholeCubit(w, X1, 0, Z1);
	drawWholeCubit(w, X1, Y1, 0);
	if (!w->dinoGL.movement.control)
		glPopMatrix();

	drawWholeCubit(w, 0, Yn, Zn);
	drawWholeCubit(w, Xn, 0, Zn);
	drawWholeCubit(w, Xn, Yn, 0);
	drawWholeCubit(w, 0, Y1, Zn);
	drawWholeCubit(w, 0, Yn, Z1);
	drawWholeCubit(w, X1, 0, Zn);
	drawWholeCubit(w, Xn, 0, Z1);
	drawWholeCubit(w, X1, Yn, 0);
	drawWholeCubit(w, Xn, Y1, 0);
	if (w->dinoGL.movement.control)
		glPopMatrix();
}

static void
middleRotate(DinoGLWidget w, int corner, GLfloat rotateStep)
{
	drawCenter();
	glPushMatrix();
	glRotatef(rotateStep, X1, Y1, Z1);
	drawWholeCubit(w, 0, Y1, Zn);
	drawWholeCubit(w, 0, Yn, Z1);
	drawWholeCubit(w, X1, 0, Zn);
	drawWholeCubit(w, Xn, 0, Z1);
	drawWholeCubit(w, X1, Yn, 0);
	drawWholeCubit(w, Xn, Y1, 0);
	if (!w->dinoGL.movement.control)
		glPopMatrix();

	drawWholeCubit(w, 0, Y1, Z1);
	drawWholeCubit(w, X1, 0, Z1);
	drawWholeCubit(w, X1, Y1, 0);
	drawWholeCubit(w, 0, Yn, Zn);
	drawWholeCubit(w, Xn, 0, Zn);
	drawWholeCubit(w, Xn, Yn, 0);
	if (w->dinoGL.movement.control)
		glPopMatrix();
}

static void
edgeRotate(DinoGLWidget w, int edge, GLfloat rotateStep)
{
	float Xf = 0.0, Yf = 0.0, Zf = 0.0;
	int radian1, radian2;

	if (edge < 4) {
		Yf = (edge / 2 == 1) ? 1.0 : -1.0;
		Zf = (edge % 2 == 1) ? 1.0 : -1.0;
	} else if (edge >= 8) {
		Xf = ((edge % 4) / 2 == 1) ? 1.0 : -1.0;
		Yf = (edge % 2 == 1) ? 1.0 : -1.0;
	} else {
		Xf = ((edge % 4) / 2 == 1) ? 1.0 : -1.0;
		Zf = (edge % 2 == 1) ? 1.0 : -1.0;
	}
#ifdef DEBUG
	(void) printf("edge=%d  Xf=%g Yf=%g Zf=%g\n", edge, Xf, Yf, Zf);
#endif
	radian1 = edgeToRad[edge][0];
	radian2 = edgeToRad[edge][1];
	drawCenter();
	glPushMatrix();
	glRotatef(rotateStep, Xf, Yf, Zf);
	drawWholeFace(w, edgeToFaces[edge][0]);
	drawWholeFace(w, edgeToFaces[edge][1]);
	drawHalfFace(w, edgeToFaces[edge][2], radian1);
	drawHalfFace(w, edgeToFaces[edge][3], radian2);
	if (!w->dinoGL.movement.control)
		glPopMatrix();
	drawWholeFace(w, edgeToFaces[edge][4]);
	drawWholeFace(w, edgeToFaces[edge][5]);
	drawHalfFace(w, edgeToFaces[edge][2], (radian1 + 2) % MAX_ORIENT);
	drawHalfFace(w, edgeToFaces[edge][3], (radian2 + 2) % MAX_ORIENT);
	if (w->dinoGL.movement.control)
		glPopMatrix();
}

/*-
 * This rotates whole cube.
 */
static void
faceRotate(DinoGLWidget w, int face, GLfloat rotateStep)
{
#define XP ((face == 4) ? 1 : ((face == -4) ? -1 : 0))
#define YP ((face == 2) ? 1 : ((face == -2) ? -1 : 0))
#define ZP ((face == 1) ? 1 : ((face == -1) ? -1 : 0))
	int corner = 0;

	drawCenter();
	glPushMatrix();
	glRotatef(rotateStep, XP, YP, ZP);
	drawWholeCubit(w, 0, Y1, Zn);
	drawWholeCubit(w, 0, Yn, Z1);
	drawWholeCubit(w, X1, 0, Zn);
	drawWholeCubit(w, Xn, 0, Z1);
	drawWholeCubit(w, X1, Yn, 0);
	drawWholeCubit(w, Xn, Y1, 0);

	drawWholeCubit(w, 0, Y1, Z1);
	drawWholeCubit(w, X1, 0, Z1);
	drawWholeCubit(w, X1, Y1, 0);
	drawWholeCubit(w, 0, Yn, Zn);
	drawWholeCubit(w, Xn, 0, Zn);
	drawWholeCubit(w, Xn, Yn, 0);
	glPopMatrix();
}

static void
drawCube(DinoGLWidget w)
{
	DinoSlice slice;
	GLfloat rotateStep = 0.0;

	slice.corner = NO_CORNER;
	slice.rotation = CW;
	if (w->dinoGL.movement.face == NO_FACE) {
		slice.rotation = NO_ROTATION;
		cornerRotate(w, slice.corner, rotateStep);
	} else if (w->dinoGL.movement.style == CORNER &&
			w->dinoGL.movement.direction < MAX_ORIENT) {
		convertMove3(w->dinoGL.movement, &slice, CORNER);
		if (slice.corner != NO_CORNER) {
			rotateStep = (float) ((slice.rotation == CCW) ?
				w->dinoGL.rotateStep : -w->dinoGL.rotateStep);
		}
		cornerRotate(w, slice.corner, rotateStep);
	} else if (w->dinoGL.movement.style == MIDDLE) {
		convertMove3(w->dinoGL.movement, &slice, MIDDLE);
		if (slice.corner != NO_CORNER) {
			rotateStep = (float) ((slice.rotation == CCW) ?
				w->dinoGL.rotateStep : -w->dinoGL.rotateStep);
		}
		middleRotate(w, slice.corner, rotateStep);
	} else if (w->dinoGL.movement.style == EDGE) {
		DinoSplit split;

		split.edge = NO_EDGE;
		split.rotation = CW;
		convertMove2(w->dinoGL.movement, &split);
		rotateStep = (float) ((split.rotation == CCW) ?
			w->dinoGL.rotateStep : -w->dinoGL.rotateStep);
		edgeRotate(w, split.edge, rotateStep);
	} else {
		int face = nextFace[w->dinoGL.movement.face][w->dinoGL.movement.direction % MAX_ORIENT];

		rotateStep = (float) w->dinoGL.rotateStep;
		faceRotate(w, face, rotateStep);
	}
}

void
movePiecesGL(DinoGLWidget w, int face, int position, int direction,
		int style, Boolean control, int fast)
{
	int i, f;
	w->dinoGL.movement.face = face;
	w->dinoGL.movement.position = position;
	w->dinoGL.movement.direction = direction;
	w->dinoGL.movement.style = style;
	w->dinoGL.movement.control = control;
	w->dinoGL.rotateStep = 0.0;
	w->dinoGL.angleStep = 0.0;
	f = (w->dinoGL.numTurnInc < fast) ? 1 : fast;
	for (i = 0; i < w->dinoGL.numTurnInc / f; i++) {
		double increment;

		if (style == CORNER || style == MIDDLE) {
			increment = 120.0 * f / w->dinoGL.numTurnInc;
		} else if (style == EDGE) {
			increment = 180.0 * f / w->dinoGL.numTurnInc;
		} else {
			increment = 90.0 * f / w->dinoGL.numTurnInc;
		}
		w->dinoGL.rotateStep += increment;
		/* rubik has 6 possibles... need 8 here */
		/*if (rotateDir[face][direction] == -1)*/
		drawAllPiecesGL(w);
		Sleep((unsigned int) ((w->dino.delay /
			(w->dinoGL.numTurnInc * f)) * 40.0));
		w->dino.currentFace = -1;
		w->dino.currentPosition = -1;
	}
	w->dinoGL.angleStep = 0.0;
	w->dinoGL.movement.face = NO_FACE;
	w->dinoGL.movement.position = NO_POSITION;
	w->dinoGL.movement.direction = NO_DEPTH;
	w->dinoGL.movement.style = CORNER;
	w->dinoGL.movement.control = False;
}

void
drawAllPiecesGL(DinoGLWidget w)
{
#ifdef WINVER
	wglMakeCurrent(w->core.hDC, hRC);
#else
	if (!glXMakeCurrent(XtDisplay(w), XtWindow(w), *glXContext)) {
		DISPLAY_WARNING("Draw All GL error");
	}
#endif
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPushMatrix();
	glTranslatef(0.0, 0.0, -10.0);
	if (w->core.height > w->core.width)
		glScalef(SCALE, SCALE * (float) w->core.width / (float) w->core.height, SCALE);
	else
		glScalef(SCALE * (float) w->core.height / (float) w->core.width, SCALE, SCALE);
	switch (w->dino.view) {
	case 0: /* >-  vertical */
		glRotatef((float) w->dinoGL.step / (float) 2.0, 0, 1, 0);
		glRotatef((float) w->dinoGL.step / (float) 2.0, 1, 0, 0);
		break;
	case 1: /* Y  !vertical */
		glRotatef((float) w->dinoGL.step / (float) 2.0, 1, 0, 0);
		glRotatef((float) w->dinoGL.step / (float) 2.0, 0, 1, 0);
		break;
	case 2: /* -<  vertical */
		glRotatef((float) (-w->dinoGL.step) / (float) 2.0, 0, 1, 0);
		glRotatef((float) (-3 * w->dinoGL.step) / (float) 2.0, 1, 0, 0);
		break;
	case 3: /* ^  !vertical */
		glRotatef((float) (-w->dinoGL.step) / (float) 2.0, 1, 0, 0);
		glRotatef((float) (-3 * w->dinoGL.step) / (float) 2.0, 0, 1, 0);
		break;
	default:
		break;
	}
	/*glRotatef(w->dinoGL.angleStep, 1, -1, 1);*/
	drawCube(w);
	glPopMatrix();
	glFlush();
#ifdef WINVER
	SwapBuffers(w->core.hDC);
#else
	glXSwapBuffers(XtDisplay(w), XtWindow(w));
#endif
}

/* UNUSED */
/*void
drawFrameGL(DinoGLWidget w, Boolean focus)
{
}*/

static int
normalizePosition(float x, float y)
{
	if (y < x && y <= -x)
		return 0;
	if (x > y && x >= -y)
		return 1;
	if (y > x && y >= -x)
		return 2;
	/* (x < y && x <= -y) */
	return 3;
}

Boolean
selectPiecesGL(DinoGLWidget w, int x, int y, int *face, int *position)
{
	/* Using gluUnProject By: Luke Benstead */
	/* http://nehe.gamedev.net/data/articles/article.asp?article=13 */

	GLint viewport[4];
	GLdouble modelview[16];
	GLdouble projection[16];
	GLfloat winX, winY, winZ;
	GLdouble posX, posY, posZ;
	Matrix a, b, r;
	Vector t, world, nw;

	glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
	glGetDoublev(GL_PROJECTION_MATRIX, projection);
	glGetIntegerv(GL_VIEWPORT, viewport);

	winX = (float) x;
	winY = (float) viewport[3] - (float) y;
	glReadPixels(x, (int) winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT,
		&winZ);
	gluUnProject(winX, winY, winZ, modelview, projection, viewport,
		&(posX), &(posY), &(posZ));
	t[0] = (float) posX;
	t[1] = (float) posY;
	t[2] = (float) (posZ + 10);
	if (w->core.height > w->core.width)
		t[1] *= (float) w->core.height / (float) w->core.width;
	else
		t[0] *= (float) w->core.width / (float) w->core.height;
	*face = -1;
	*position = -1;
	if (winZ == 1) {
		return False;
	}
	world[0] = t[0], world[1] = t[1], world[2] = t[2];
	switch (w->dino.view) {
	case 0: /* >-  vertical */
		setMatrix((float) (-w->dinoGL.step) / (float) 2.0, 1.0, 0.0, 0.0, a);
		setMatrix((float) (-w->dinoGL.step) / (float) 2.0, 0.0, 1.0, 0.0, b);
		matrixMatrix(a, b, r);
		matrixVector(r, t, world);
		nw[0] = -world[0] / (float) 2.0;
		nw[1] = world[1] / (float) 2.0;
		nw[2] = world[2] / (float) 2.0;
		if (nw[1] >= nw[0] && nw[1] >= nw[2]) {
			*face = 0;
			*position = normalizePosition(world[0], world[2]);
		} else if (nw[0] >= nw[1] && nw[0] >= nw[2]) {
			*face = 1;
			*position = normalizePosition(world[2], -world[1]);
		} else if (nw[2] >= nw[0] && nw[2] >= nw[1]) {
			*face = 2;
			*position = normalizePosition(world[0], -world[1]);
		}
		break;
	case 1: /* Y  !vertical */
		setMatrix((float) (-w->dinoGL.step) / (float) 2.0, 0.0, 1.0, 0.0, a);
		setMatrix((float) (-w->dinoGL.step) / (float) 2.0, 1.0, 0.0, 0.0, b);
		matrixMatrix(a, b, r);
		matrixVector(r, t, world);
		nw[0] = -world[0] / (float) 2.0;
		nw[1] = world[1] / (float) 2.0;
		nw[2] = world[2] / (float) 2.0;
		if (nw[1] >= nw[0] && nw[1] >= nw[2]) {
			*face = 0;
			*position = normalizePosition(world[0], world[2]);
		} else if (nw[0] >= nw[1] && nw[0] >= nw[2]) {
			*face = 1;
			*position = normalizePosition(world[2], -world[1]);
		} else if (nw[2] >= nw[0] && nw[2] >= nw[1]) {
			*face = 2;
			*position = normalizePosition(world[0], -world[1]);
		}
		break;
	case 2: /* -<  vertical */
		setMatrix((float) (3 * w->dinoGL.step) / (float) 2.0, 1.0, 0.0, 0.0, a);
		setMatrix((float) w->dinoGL.step / (float) 2.0, 0.0, 1.0, 0.0, b);
		matrixMatrix(a, b, r);
		matrixVector(r, t, world);
		nw[0] = -world[0] / (float) 2.0;
		nw[1] = world[1] / (float) 2.0;
		nw[2] = world[2] / (float) 2.0;
		if (nw[0] <= nw[1] && nw[0] <= nw[2]) {
			*face = 3;
			*position = normalizePosition(-world[2], -world[1]);
		} else if (nw[1] <= nw[0] && nw[1] <= nw[2]) {
			*face = 4;
			*position = normalizePosition(world[0], -world[2]);
		} else if (nw[2] <= nw[0] && nw[2] <= nw[1]) {
			*face = 5;
			*position = normalizePosition(world[0], world[1]);
		}
		break;
	case 3: /* ^  !vertical */
		setMatrix((float) (3 * w->dinoGL.step) / (float) 2.0, 0.0, 1.0, 0.0, a);
		setMatrix((float) w->dinoGL.step / (float) 2.0, 1.0, 0.0, 0.0, b);
		matrixMatrix(a, b, r);
		matrixVector(r, t, world);
		nw[0] = -world[0] / (float) 2.0;
		nw[1] = world[1] / (float) 2.0;
		nw[2] = world[2] / (float) 2.0;
		if (nw[0] <= nw[1] && nw[0] <= nw[2]) {
			*face = 3;
			*position = normalizePosition(-world[2], -world[1]);
		} else if (nw[1] <= nw[0] && nw[1] <= nw[2]) {
			*face = 4;
			*position = normalizePosition(world[0], -world[2]);
		} else if (nw[2] <= nw[0] && nw[2] <= nw[1]) {
			*face = 5;
			*position = normalizePosition(world[0], world[1]);
		}
		break;
	default:
		break;
	}
#ifdef DEBUG
	(void) printf("view %d, x %d, y %d\n", w->dino.view, x, y);
	(void) printf(" wx %g, wy %g, wz %g\n", winX, winY, winZ);
	(void) printf("  px %g, py %g, pz %g\n", posX, posY, posZ);
	(void) printf("   tx %g, ty %g, tz %g\n", t[0], t[1], t[2]);
	(void) printf("    rx %g, ry %g, rz %g\n",
		world[0], world[1], world[2]);
	(void) printf("     face %d, pos %d\n", *face, *position);
#endif
	return True;
}

Boolean
narrowSelectionGL(DinoGLWidget w, int *face, int *direction)
{
	switch (*direction) {
	case TR:
	case BR:
	case BL:
	case TL:
		if (w->dino.view % 2 == 0) {
			if (*face == 1)
				*direction = *direction + 2 * MAX_ORIENT;
			else if (*face == 3)
				*direction = (*direction + 3) % MAX_ORIENT +
					2 * MAX_ORIENT;
		} else {
			if (*face == 0)
				*direction = (*direction + 1) % MAX_ORIENT +
					2 * MAX_ORIENT;
			else if (*face == 4)
				*direction = (*direction + 2) % MAX_ORIENT +
					2 * MAX_ORIENT;
			else if (*face == 5)
				*direction = (*direction + 2) % MAX_ORIENT;
		}
		break;
	case CCW:
	case CW:
		/*if (*face == 3 || *face == 4)
			*direction = (TR + *direction - CW) % MAX_ORIENT;
		else if (*face == 0)
			*direction = (BR + *direction - CW) % MAX_ORIENT;
		else if (*face == 2)
			*direction = (BL + *direction - CW) % MAX_ORIENT;
		else if (*face == 1 || *face == 5)
			*direction = (TL + *direction - CW) % MAX_ORIENT;*/
		break;
	case TOP:
	case RIGHT:
	case BOTTOM:
	case LEFT:
		if (w->dino.view % 2 == 0) {
			if (*face == 1)
				*direction = (TL + *direction) % MAX_ORIENT;
			else if (*face == 3)
				*direction = (BL + *direction) % MAX_ORIENT;
		} else {
			if (*face == 0)
				*direction = (TR + *direction) % MAX_ORIENT;
			else if (*face == 4)
				*direction = (BR + *direction) % MAX_ORIENT;
			else if (*face == 5)
				*direction = (BL + *direction) % MAX_ORIENT +
					2 * MAX_ORIENT;
		}
		break;
	default:
		return False;
	}
	return True;
}

#ifdef WINVER
static Boolean
setupPixelFormat(DinoGLWidget w, BYTE type, DWORD flags)
{
	PIXELFORMATDESCRIPTOR pfd;
	int pixelFormat;

	memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
	pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
	pfd.nVersion = 1;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | flags;
	pfd.dwLayerMask = PFD_MAIN_PLANE;
	/*pfd.cColorBits = 8;
	pfd.cDepthBits = 16;*/
	pfd.iPixelType = type;
	pfd.cColorBits = 24;
	pfd.cDepthBits = 32;

	if ((pixelFormat = ChoosePixelFormat(w->core.hDC, &pfd)) == 0) {
		DWORD err;
		char *buf1;

		err = GetLastError();
		/* 6 ERROR_INVALID_HANDLE */
		intCat(&buf1, "ChoosePixelFormat failed ", (int) err);
		DISPLAY_WARNING(buf1);
		free(buf1);
		return FALSE;
	}

	if (SetPixelFormat(w->core.hDC, pixelFormat, &pfd) == FALSE) {
		MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
		return FALSE;
	}
	DescribePixelFormat(w->core.hDC, pixelFormat,
		sizeof(PIXELFORMATDESCRIPTOR), &pfd);
	return TRUE;
}

#else

static Boolean
setValuesPuzzleGL(Widget current, Widget request, Widget renew)
{
	DinoGLWidget c = (DinoGLWidget) current, w = (DinoGLWidget) renew;
	Boolean redraw = False;

	if (w->dino.view != c->dino.view) {
		resizePuzzleGL(w);
		redraw = True;
	}
	if (w->dino.delay != c->dino.delay) {
		w->dinoGL.numTurnInc = ((w->dino.delay < MAX_TURN_INC) ?
			w->dino.delay + 1 : MAX_TURN_INC);
	}
	return (redraw);
}

static GLXContext *
initGL(DinoGLWidget w) {
	XVisualInfo xviIn, *xviOut;
	int numVis;

	/*XGetWindowAttributes(XtDisplay(w), XtWindow(w), &xgwa); */
	xviIn.screen = DefaultScreen(XtDisplay(w));
	xviIn.visualid = XVisualIDFromVisual(DefaultVisual(XtDisplay(w),
		xviIn.screen));
	xviOut = XGetVisualInfo(XtDisplay(w), VisualScreenMask | VisualIDMask,
		&xviIn, &numVis);
	if (!xviOut) {
		XtWarning("Could not get XVisualInfo");
		return (GLXContext *) NULL;
	}
	if (glXContext)
		free(glXContext);
	if ((glXContext = (GLXContext *) malloc(sizeof (GLXContext))) ==
			NULL) {
		DISPLAY_ERROR("Not enough memory for glx info, exiting.");
	}
	/* assertion "glx_dpy" failed on Cygwin */
	if (!glXQueryExtension(XtDisplay(w), NULL, NULL)) {
		XtWarning("Could not find GLX");
		return (GLXContext *) NULL;
	}
	*glXContext = glXCreateContext(XtDisplay(w), xviOut, 0, GL_TRUE);
	(void) XFree((char *) xviOut);
	if (!*glXContext) {
		XtWarning("Could not create rendering context");
		return (GLXContext *) NULL;
	}
	return glXContext;
}
#endif

#ifndef WINVER
static
#endif
void
resizePuzzleGL(DinoGLWidget w)
{
#ifdef WINVER
	RECT rect;

	/* Determine size of client area */
	(void) GetClientRect(w->core.hWnd, &rect);
	w->core.width = rect.right;
	w->core.height = rect.bottom;
#endif
	glViewport(0, 0, (GLint) w->core.width, (GLint) w->core.height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
	glMatrixMode(GL_MODELVIEW);
}

static void
makeCurrentGL(DinoGLWidget w)
{
	GLboolean rgbaMode;

#ifdef WINVER
	wglMakeCurrent(w->core.hDC, hRC);
#else
	if (!glXMakeCurrent(XtDisplay(w), XtWindow(w), *glXContext)) {
		DISPLAY_WARNING("GL error");
	}
#endif
	madeCurrent = True;
	/* True Color junk */
	glGetBooleanv(GL_RGBA_MODE, &rgbaMode);
	if (!rgbaMode) {
#ifdef WINVER
		glClearIndex(0.0);
#else
		glIndexi(WhitePixel(XtDisplay(w),
			DefaultScreen(XtDisplay(w))));
		glClearIndex((float) BlackPixel(XtDisplay(w),
			DefaultScreen(XtDisplay(w))));
#endif
	}
	resizePuzzleGL(w);

	glDrawBuffer(GL_BACK);
	glClearDepth(1.0);
	glClearColor(face_material[NO_FACE][0], face_material[NO_FACE][1],
		face_material[NO_FACE][2], face_material[NO_FACE][3]);
	glColor3f(1.0, 1.0, 1.0);

	glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT0, GL_POSITION, position0);
	glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT1, GL_POSITION, position1);
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
	glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_NORMALIZE);
	glEnable(GL_CULL_FACE);
	glShadeModel(GL_FLAT);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);

	w->dinoGL.step = 90;
	w->dinoGL.rotateStep = 0.0;
}

#ifndef WINVER
static void
initializePuzzleGL(Widget request, Widget renew)
{
	DinoGLWidget w = (DinoGLWidget) renew;
	int i;

	setAllColors((DinoWidget) w);
	if (initGL(w) == (GLXContext *) NULL) {
		w->dino.dim = 0;
		return;
	}
	w->dino.dim = 4; /* 2 and 3 already taken */
	for (i = 0; i < MAX_FACES + 2; i++)
		pickColor(w, i, w->dino.mono, face_material[i]);
	w->dinoGL.numTurnInc = ((w->dino.delay < MAX_TURN_INC) ?
		w->dino.delay + 1 : MAX_TURN_INC);
	resizePuzzleGL(w);
}
#endif

#ifndef WINVER
static
#endif
void
exposePuzzleGL(
#ifdef WINVER
DinoGLWidget w
#else
Widget renew, XEvent *event, Region region
#endif
)
{
#ifdef WINVER
	if (hRC == NULL) {
		BYTE type;
		int i;
		DWORD flags = PFD_DOUBLEBUFFER;

#if 1
		type = PFD_TYPE_RGBA;
#else
		type = PFD_TYPE_COLORINDEX;
#endif
		(void) setupPixelFormat(w, type, flags);
		hRC = wglCreateContext(w->core.hDC);
		w->dinoGL.movement.face = NO_FACE;
		w->dinoGL.movement.position = NO_POSITION;
		w->dinoGL.movement.direction = NO_DEPTH;
		w->dinoGL.rotateStep = 0.0;
		w->dinoGL.angleStep = 0.0;
		w->dino.dim = 4; /* 2 and 3 already taken */
		for (i = 0; i < MAX_FACES + 2; i++)
			pickColor(w, i, w->dino.mono, face_material[i]);
		w->dinoGL.numTurnInc = ((w->dino.delay < MAX_TURN_INC) ?
			w->dino.delay + 1 : MAX_TURN_INC);
		resizePuzzleGL(w);
	}
#else
	DinoGLWidget w = (DinoGLWidget) renew;

	if (!w->core.visible)
		return;
	if (w->dino.dim != 4)
		return;
#endif
	if (!madeCurrent) {
		makeCurrentGL(w);
	}
	/*drawFrameGL(w, w->dino.focus);*/
	drawAllPiecesGL(w);
}

#ifndef WINVER
static void
movePuzzleGLTl(DinoGLWidget w, XEvent *event, char **args, int nArgs)
{
	movePuzzleInput((DinoWidget) w, event->xbutton.x, event->xbutton.y,
		TL,
		(int) (event->xkey.state & (ShiftMask | LockMask)),
		(int) (event->xkey.state & ControlMask),
		(int) (event->xkey.state & (Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
}

static void
movePuzzleGLTop(DinoGLWidget w, XEvent *event, char **args, int nArgs)
{
	movePuzzleInput((DinoWidget) w, event->xbutton.x, event->xbutton.y,
		TOP,
		(int) (event->xkey.state & (ShiftMask | LockMask)),
		(int) (event->xkey.state & ControlMask),
		(int) (event->xkey.state & (Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
}

static void
movePuzzleGLTr(DinoGLWidget w, XEvent *event, char **args, int nArgs)
{
	movePuzzleInput((DinoWidget) w, event->xbutton.x, event->xbutton.y,
		TR,
		(int) (event->xkey.state & (ShiftMask | LockMask)),
		(int) (event->xkey.state & ControlMask),
		(int) (event->xkey.state & (Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
}

static void
movePuzzleGLLeft(DinoGLWidget w, XEvent *event, char **args, int nArgs)
{
	movePuzzleInput((DinoWidget) w, event->xbutton.x, event->xbutton.y,
		LEFT,
		(int) (event->xkey.state & (ShiftMask | LockMask)),
		(int) (event->xkey.state & ControlMask),
		(int) (event->xkey.state & (Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
}

static void
movePuzzleGLRight(DinoGLWidget w, XEvent *event, char **args, int nArgs)
{
	movePuzzleInput((DinoWidget) w, event->xbutton.x, event->xbutton.y,
		RIGHT,
		(int) (event->xkey.state & (ShiftMask | LockMask)),
		(int) (event->xkey.state & ControlMask),
		(int) (event->xkey.state & (Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
}

static void
movePuzzleGLBl(DinoGLWidget w, XEvent *event, char **args, int nArgs)
{
	movePuzzleInput((DinoWidget) w, event->xbutton.x, event->xbutton.y,
		BL,
		(int) (event->xkey.state & (ShiftMask | LockMask)),
		(int) (event->xkey.state & ControlMask),
		(int) (event->xkey.state & (Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
}

static void
movePuzzleGLBottom(DinoGLWidget w, XEvent *event, char **args, int nArgs)
{
	movePuzzleInput((DinoWidget) w, event->xbutton.x, event->xbutton.y,
		BOTTOM,
		(int) (event->xkey.state & (ShiftMask | LockMask)),
		(int) (event->xkey.state & ControlMask),
		(int) (event->xkey.state & (Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
}

static void
movePuzzleGLBr(DinoGLWidget w, XEvent *event, char **args, int nArgs)
{
	movePuzzleInput((DinoWidget) w, event->xbutton.x, event->xbutton.y,
		BR,
		(int) (event->xkey.state & (ShiftMask | LockMask)),
		(int) (event->xkey.state & ControlMask),
		(int) (event->xkey.state & (Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
}
#endif
#else
int x = 0; /* non empty source */
#endif
