1 
2 /*-
3 # X-BASED RUBIK'S CUBE(tm)
4 #
5 #  Rubik3d.c
6 #
7 ###
8 #
9 #  Copyright (c) 1994 - 99	David Albert Bagley, bagleyd@tux.org
10 #
11 #                   All Rights Reserved
12 #
13 #  Permission to use, copy, modify, and distribute this software and
14 #  its documentation for any purpose and without fee is hereby granted,
15 #  provided that the above copyright notice appear in all copies and
16 #  that both that copyright notice and this permission notice appear in
17 #  supporting documentation, and that the name of the author not be
18 #  used in advertising or publicity pertaining to distribution of the
19 #  software without specific, written prior permission.
20 #
21 #  This program is distributed in the hope that it will be "playable",
22 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
23 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 #
25 */
26 
27 /* Methods file for Rubik3d */
28 
29 #include <stdio.h>
30 #include <X11/IntrinsicP.h>
31 #include <X11/Intrinsic.h>
32 #include <X11/StringDefs.h>
33 #include <X11/CoreP.h>
34 #include "RubikP.h"
35 #include "Rubik3dP.h"
36 
37 static void InitializeRubik3D(Widget request, Widget renew);
38 static void ExposeRubik3D(Widget renew, XEvent * event, Region region);
39 static void ResizeRubik3D(Rubik3DWidget w);
40 static Boolean SetValuesRubik3D(Widget current, Widget request, Widget renew);
41 static void MoveRubik3DTl(Rubik3DWidget w, XEvent * event, char **args, int nArgs);
42 static void MoveRubik3DTop(Rubik3DWidget w, XEvent * event, char **args, int nArgs);
43 static void MoveRubik3DTr(Rubik3DWidget w, XEvent * event, char **args, int nArgs);
44 static void MoveRubik3DLeft(Rubik3DWidget w, XEvent * event, char **args, int nArgs);
45 static void MoveRubik3DRight(Rubik3DWidget w, XEvent * event, char **args, int nArgs);
46 static void MoveRubik3DBl(Rubik3DWidget w, XEvent * event, char **args, int nArgs);
47 static void MoveRubik3DBottom(Rubik3DWidget w, XEvent * event, char **args, int nArgs);
48 static void MoveRubik3DBr(Rubik3DWidget w, XEvent * event, char **args, int nArgs);
49 static void ResizePolyhedrons(Rubik3DWidget w);
50 static void DrawFrame(Rubik3DWidget w, GC gc);
51 static void MapTo3D(Rubik3DWidget w, int face, int i, int j, int *x, int *y);
52 
53 #ifdef DEBUG
54 static void MapFrom3D();
55 
56 #endif
57 static void MapOrientFrom3D(int face, int corner, int *side);
58 static void CubeOffset3D(Rubik3DWidget w, int face, int x, int y, int *dx, int *dy);
59 
60 static char defaultTranslationsRubik3D[] =
61 "<KeyPress>q: Quit()\n\
62    Ctrl<KeyPress>C: Quit()\n\
63    <KeyPress>KP_Divide: MoveCcw()\n\
64    <KeyPress>Home: MoveTl()\n\
65    <KeyPress>KP_7: MoveTl()\n\
66    <KeyPress>R7: MoveTl()\n\
67    <KeyPress>Up: MoveTop()\n\
68    <KeyPress>KP_8: MoveTop()\n\
69    <KeyPress>R8: MoveTop()\n\
70    <KeyPress>Prior: MoveTr()\n\
71    <KeyPress>KP_9: MoveTr()\n\
72    <KeyPress>R9: MoveTr()\n\
73    <KeyPress>Left: MoveLeft()\n\
74    <KeyPress>KP_4: MoveLeft()\n\
75    <KeyPress>R10: MoveLeft()\n\
76    <KeyPress>Begin: MoveCw()\n\
77    <KeyPress>KP_5: MoveCw()\n\
78    <KeyPress>R11: MoveCw()\n\
79    <KeyPress>Right: MoveRight()\n\
80    <KeyPress>KP_6: MoveRight()\n\
81    <KeyPress>R12: MoveRight()\n\
82    <KeyPress>End: MoveBl()\n\
83    <KeyPress>KP_1: MoveBl()\n\
84    <KeyPress>R13: MoveBl()\n\
85    <KeyPress>Down: MoveBottom()\n\
86    <KeyPress>KP_2: MoveBottom()\n\
87    <KeyPress>R14: MoveBottom()\n\
88    <KeyPress>Next: MoveBr()\n\
89    <KeyPress>KP_3: MoveBr()\n\
90    <KeyPress>R15: MoveBr()\n\
91    <Btn1Down>: Select()\n\
92    <Btn1Up>: Release()\n\
93    <KeyPress>p: Practice()\n\
94    <Btn2Down>(2+): Practice()\n\
95    <Btn2Down>: PracticeMaybe()\n\
96    <KeyPress>r: Randomize()\n\
97    <Btn3Down>(2+): Randomize()\n\
98    <Btn3Down>: RandomizeMaybe()\n\
99    <KeyPress>g: Get()\n\
100    <KeyPress>w: Write()\n\
101    <KeyPress>u: Undo()\n\
102    <KeyPress>s: Solve()\n\
103    <KeyPress>d: Decrement()\n\
104    <KeyPress>i: Increment()\n\
105    <KeyPress>x: IncrementX()\n\
106    <KeyPress>y: IncrementY()\n\
107    <KeyPress>z: IncrementZ()\n\
108    <KeyPress>o: Orientize()";
109 
110 static XtActionsRec actionsListRubik3D[] =
111 {
112 	{"Quit", (XtActionProc) QuitRubik},
113 	{"MoveCcw", (XtActionProc) MoveRubikCcw},
114 	{"MoveTl", (XtActionProc) MoveRubik3DTl},
115 	{"MoveTop", (XtActionProc) MoveRubik3DTop},
116 	{"MoveTr", (XtActionProc) MoveRubik3DTr},
117 	{"MoveLeft", (XtActionProc) MoveRubik3DLeft},
118 	{"MoveCw", (XtActionProc) MoveRubikCw},
119 	{"MoveRight", (XtActionProc) MoveRubik3DRight},
120 	{"MoveBl", (XtActionProc) MoveRubik3DBl},
121 	{"MoveBottom", (XtActionProc) MoveRubik3DBottom},
122 	{"MoveBr", (XtActionProc) MoveRubik3DBr},
123 	{"Select", (XtActionProc) SelectRubik},
124 	{"Release", (XtActionProc) ReleaseRubik},
125 	{"Practice", (XtActionProc) PracticeRubik},
126 	{"PracticeMaybe", (XtActionProc) PracticeRubikMaybe},
127 	{"Randomize", (XtActionProc) RandomizeRubik},
128 	{"RandomizeMaybe", (XtActionProc) RandomizeRubikMaybe},
129 	{"Get", (XtActionProc) GetRubik},
130 	{"Write", (XtActionProc) WriteRubik},
131 	{"Undo", (XtActionProc) UndoRubik},
132 	{"Solve", (XtActionProc) SolveRubik},
133 	{"Decrement", (XtActionProc) DecrementRubik},
134 	{"Increment", (XtActionProc) IncrementRubik},
135 	{"IncrementX", (XtActionProc) IncrementXRubik},
136 	{"IncrementY", (XtActionProc) IncrementYRubik},
137 	{"IncrementZ", (XtActionProc) IncrementZRubik},
138 	{"Orientize", (XtActionProc) OrientizeRubik}
139 };
140 
141 static XtResource resourcesRubik3D[] =
142 {
143 	{XtNuserName, XtCUserName, XtRString, sizeof (String),
144 	 XtOffset(RubikWidget, rubik.username), XtRString, "nobody"},
145 	{XtNfaceColor0, XtCLabel, XtRString, sizeof (String),
146 	 XtOffset(RubikWidget, rubik.faceName[0]), XtRString, "Red"},
147 	{XtNfaceColor1, XtCLabel, XtRString, sizeof (String),
148 	 XtOffset(RubikWidget, rubik.faceName[1]), XtRString, "Yellow"},
149 	{XtNfaceColor2, XtCLabel, XtRString, sizeof (String),
150 	 XtOffset(RubikWidget, rubik.faceName[2]), XtRString, "White"},
151 	{XtNfaceColor3, XtCLabel, XtRString, sizeof (String),
152 	 XtOffset(RubikWidget, rubik.faceName[3]), XtRString, "Green"},
153 	{XtNfaceColor4, XtCLabel, XtRString, sizeof (String),
154 	 XtOffset(RubikWidget, rubik.faceName[4]), XtRString, "Orange"},
155 	{XtNfaceColor5, XtCLabel, XtRString, sizeof (String),
156 	 XtOffset(RubikWidget, rubik.faceName[5]), XtRString, "Blue"},
157 	{XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
158     XtOffset(RubikWidget, rubik.foreground), XtRString, XtDefaultForeground},
159 	{XtNpieceBorder, XtCColor, XtRPixel, sizeof (Pixel),
160    XtOffset(RubikWidget, rubik.borderColor), XtRString, XtDefaultForeground},
161 	{XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
162 	 XtOffset(RubikWidget, core.width), XtRString, "250"},
163 	{XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
164 	 XtOffset(RubikWidget, core.height), XtRString, "400"},
165 	{XtNsizex, XtCSizeX, XtRInt, sizeof (int),
166 	 XtOffset(RubikWidget, rubik.sizex), XtRString, "3"},	/* DEFAULTCUBES */
167 	{XtNsizey, XtCSizeY, XtRInt, sizeof (int),
168 	 XtOffset(RubikWidget, rubik.sizey), XtRString, "3"},	/* DEFAULTCUBES */
169 	{XtNsizez, XtCSizeZ, XtRInt, sizeof (int),
170 	 XtOffset(RubikWidget, rubik.sizez), XtRString, "3"},	/* DEFAULTCUBES */
171 	{XtNorient, XtCOrient, XtRBoolean, sizeof (Boolean),
172 	 XtOffset(RubikWidget, rubik.orient), XtRString, "FALSE"},	/* DEFAULTORIENT */
173 	{XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
174 	 XtOffset(RubikWidget, rubik.mono), XtRString, "FALSE"},
175 	{XtNreverse, XtCReverse, XtRBoolean, sizeof (Boolean),
176 	 XtOffset(RubikWidget, rubik.reverse), XtRString, "FALSE"},
177 	{XtNface, XtCFace, XtRInt, sizeof (int),
178 	 XtOffset(RubikWidget, rubik.currentFace), XtRString, "-1"},
179 	{XtNpos, XtCPos, XtRInt, sizeof (int),
180 	 XtOffset(RubikWidget, rubik.currentPosition), XtRString, "-1"},
181 	{XtNdirection, XtCDirection, XtRInt, sizeof (int),
182 	 XtOffset(RubikWidget, rubik.currentDirection), XtRString, "-1"},
183 	{XtNpractice, XtCBoolean, XtRBoolean, sizeof (Boolean),
184 	 XtOffset(RubikWidget, rubik.practice), XtRString, "FALSE"},
185 	{XtNstart, XtCBoolean, XtRBoolean, sizeof (Boolean),
186 	 XtOffset(RubikWidget, rubik.started), XtRString, "FALSE"},
187 	{XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
188 	 XtOffset(RubikWidget, rubik.select), XtRCallback, NULL}
189 };
190 
191 Rubik3DClassRec rubik3dClassRec =
192 {
193 	{
194 		(WidgetClass) & rubikClassRec,	/* superclass */
195 		"Rubik3D",	/* class name */
196 		sizeof (Rubik3DRec),	/* widget size */
197 		NULL,		/* class initialize */
198 		NULL,		/* class part initialize */
199 		FALSE,		/* class inited */
200 		(XtInitProc) InitializeRubik3D,		/* initialize */
201 		NULL,		/* initialize hook */
202 		XtInheritRealize,	/* realize */
203 		actionsListRubik3D,	/* actions */
204 		XtNumber(actionsListRubik3D),	/* num actions */
205 		resourcesRubik3D,	/* resources */
206 		XtNumber(resourcesRubik3D),	/* num resources */
207 		NULLQUARK,	/* xrm class */
208 		TRUE,		/* compress motion */
209 		TRUE,		/* compress exposure */
210 		TRUE,		/* compress enterleave */
211 		TRUE,		/* visible interest */
212 		NULL,		/* destroy */
213 		(XtWidgetProc) ResizeRubik3D,	/* resize */
214 		(XtExposeProc) ExposeRubik3D,	/* expose */
215 		(XtSetValuesFunc) SetValuesRubik3D,	/* set values */
216 		NULL,		/* set values hook */
217 		XtInheritSetValuesAlmost,	/* set values almost */
218 		NULL,		/* get values hook */
219 		XtInheritAcceptFocus,	/* accept focus */
220 		XtVersion,	/* version */
221 		NULL,		/* callback private */
222 		defaultTranslationsRubik3D,	/* tm table */
223 		NULL,		/* query geometry */
224 		NULL,		/* display accelerator */
225 		NULL		/* extension */
226 	},
227 	{
228 		0		/* ignore */
229 	},
230 	{
231 		0		/* ignore */
232 	}
233 };
234 
235 WidgetClass rubik3dWidgetClass = (WidgetClass) & rubik3dClassRec;
236 
237 static XPoint faceLoc3D[MAXFACES][MAXORIENT];
238 static XPoint cubeLoc3D[MAXFACES][MAXORIENT + 1];
239 static XPoint letter3DList[MAXFACES];
240 static XPoint orient3DList[MAXFACES][MAXORIENT][2];
241 static RowNext rotateToRow[MAXFACES] =	/*CW to min face */
242 {
243 	{1, LEFT, TOP},
244 	{0, BOTTOM, RIGHT},
245 	{0, RIGHT, BOTTOM},
246 	{0, TOP, LEFT},
247 	{1, RIGHT, BOTTOM},
248 	{0, LEFT, TOP}
249 };
250 
251 static void
InitializeRubik3D(Widget request,Widget renew)252 InitializeRubik3D(Widget request, Widget renew)
253 {
254 	Rubik3DWidget w = (Rubik3DWidget) renew;
255 
256 	w->rubik.dim = 3;
257 	ResizeRubik3D(w);
258 }
259 
260 static void
ResizeRubik3D(Rubik3DWidget w)261 ResizeRubik3D(Rubik3DWidget w)
262 {
263 	/* XPoint      tempSize; */
264 
265 	w->rubik.delta = 4;
266 	w->rubik.vertical = (w->core.height >= w->core.width);
267 	/* Unlike the 2d implementation... lets have variable size cubies and
268 	   static sized cube */
269 	if (w->rubik.vertical) {
270 		w->rubik3d.viewSize.y = w->core.height / MAXVIEWS;
271 		w->rubik3d.viewSize.x = w->core.width;
272 		if (w->rubik3d.viewSize.x >= DIVIDE(w->rubik3d.viewSize.y)) {
273 			w->rubik3d.viewSize.y = MAX(w->rubik3d.viewSize.y, 0);
274 			w->rubik3d.viewSize.x = DIVIDE(w->rubik3d.viewSize.y);
275 		} else {
276 			w->rubik3d.viewSize.x = MAX(w->rubik3d.viewSize.x, 0);
277 			w->rubik3d.viewSize.y = MULTIPLY(w->rubik3d.viewSize.x);
278 		}
279 		w->rubik3d.faceSize.x = w->rubik3d.viewSize.x / 2 - 2;
280 		w->rubik3d.faceSize.y = w->rubik3d.viewSize.y / 2 - 2;
281 		w->rubik3d.faceDiagonal = w->rubik3d.faceSize.x / 2;
282 		w->rubik.puzzleSize.x = w->rubik3d.viewSize.x;
283 		w->rubik.puzzleSize.y = MAXVIEWS * w->rubik3d.viewSize.y;
284 	} else {
285 		w->rubik3d.viewSize.x = w->core.width / MAXVIEWS;
286 		w->rubik3d.viewSize.y = w->core.height;
287 		if (w->rubik3d.viewSize.y >= DIVIDE(w->rubik3d.viewSize.x)) {
288 			w->rubik3d.viewSize.x = MAX(w->rubik3d.viewSize.x, 0);
289 			w->rubik3d.viewSize.y = DIVIDE(w->rubik3d.viewSize.x);
290 		} else {
291 			w->rubik3d.viewSize.y = MAX(w->rubik3d.viewSize.y, 0);
292 			w->rubik3d.viewSize.x = MULTIPLY(w->rubik3d.viewSize.y);
293 		}
294 		w->rubik3d.faceSize.x = w->rubik3d.viewSize.x / 2 - 2;
295 		w->rubik3d.faceSize.y = w->rubik3d.viewSize.y / 2 - 2;
296 		w->rubik3d.faceDiagonal = w->rubik3d.faceSize.y / 2;
297 		w->rubik.puzzleSize.y = w->rubik3d.viewSize.y;
298 		w->rubik.puzzleSize.x = MAXVIEWS * w->rubik3d.viewSize.x;
299 	}
300 	w->rubik3d.cubeSizex.x = MAX(w->rubik3d.faceSize.x /
301 				     w->rubik.sizex - w->rubik.delta, 0);
302 	w->rubik3d.cubeSizey.x = MAX(w->rubik3d.faceSize.x /
303 				     w->rubik.sizey - w->rubik.delta, 0);
304 	w->rubik3d.cubeSizez.x = MAX(w->rubik3d.faceSize.x /
305 				     w->rubik.sizez - w->rubik.delta, 0);
306 	w->rubik3d.cubeSizex.y = MAX(w->rubik3d.faceSize.y /
307 				     w->rubik.sizex - w->rubik.delta, 0);
308 	w->rubik3d.cubeSizey.y = MAX(w->rubik3d.faceSize.y /
309 				     w->rubik.sizey - w->rubik.delta, 0);
310 	w->rubik3d.cubeSizez.y = MAX(w->rubik3d.faceSize.y /
311 				     w->rubik.sizez - w->rubik.delta, 0);
312 	w->rubik.puzzleOffset.x = ((int) w->core.width - w->rubik.puzzleSize.x) / 2;
313 	w->rubik.puzzleOffset.y = ((int) w->core.height - w->rubik.puzzleSize.y) /
314 		2;
315 	ResizePolyhedrons(w);
316 }
317 
318 static void
ExposeRubik3D(Widget renew,XEvent * event,Region region)319 ExposeRubik3D(Widget renew, XEvent * event, Region region)
320 {
321 	Rubik3DWidget w = (Rubik3DWidget) renew;
322 
323 	if (w->core.visible) {
324 		if (w->rubik.reverse)
325 			XFillRectangle(XtDisplay(w), XtWindow(w),
326 				       w->rubik.inverseGC, 0, 0, w->core.width, w->core.height);
327 		DrawFrame(w, w->rubik.puzzleGC);
328 		DrawAllPolyhedrons((RubikWidget) w);
329 	}
330 }
331 
332 static      Boolean
SetValuesRubik3D(Widget current,Widget request,Widget renew)333 SetValuesRubik3D(Widget current, Widget request, Widget renew)
334 {
335 	Rubik3DWidget c = (Rubik3DWidget) current, w = (Rubik3DWidget) renew;
336 	Boolean     redraw = False;
337 
338 	if (w->rubik.sizex != c->rubik.sizex ||
339 	    w->rubik.sizey != c->rubik.sizey ||
340 	    w->rubik.sizez != c->rubik.sizez) {
341 		ResetPolyhedrons((RubikWidget) w);
342 		ResizeRubik3D(w);
343 		redraw = True;
344 	}
345 	if (w->rubik3d.cubeSizex.x != c->rubik3d.cubeSizex.x ||
346 	    w->rubik3d.cubeSizey.x != c->rubik3d.cubeSizey.x ||
347 	    w->rubik3d.cubeSizez.x != c->rubik3d.cubeSizez.x ||
348 	    w->rubik3d.cubeSizex.y != c->rubik3d.cubeSizex.y ||
349 	    w->rubik3d.cubeSizey.y != c->rubik3d.cubeSizey.y ||
350 	    w->rubik3d.cubeSizez.y != c->rubik3d.cubeSizez.y) {
351 		ResizeRubik3D(w);
352 		redraw = True;
353 	}
354 	return (redraw);
355 }
356 
357 static void
MoveRubik3DTl(Rubik3DWidget w,XEvent * event,char ** args,int nArgs)358 MoveRubik3DTl(Rubik3DWidget w, XEvent * event, char **args, int nArgs)
359 {
360 	MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, TL,
361 		       (int) (event->xkey.state & ControlMask));
362 }
363 
364 static void
MoveRubik3DTop(Rubik3DWidget w,XEvent * event,char ** args,int nArgs)365 MoveRubik3DTop(Rubik3DWidget w, XEvent * event, char **args, int nArgs)
366 {
367 	MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, TOP,
368 		       (int) (event->xkey.state & ControlMask));
369 }
370 
371 static void
MoveRubik3DTr(Rubik3DWidget w,XEvent * event,char ** args,int nArgs)372 MoveRubik3DTr(Rubik3DWidget w, XEvent * event, char **args, int nArgs)
373 {
374 	MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, TR,
375 		       (int) (event->xkey.state & ControlMask));
376 }
377 
378 static void
MoveRubik3DLeft(Rubik3DWidget w,XEvent * event,char ** args,int nArgs)379 MoveRubik3DLeft(Rubik3DWidget w, XEvent * event, char **args, int nArgs)
380 {
381 	MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, LEFT,
382 		       (int) (event->xkey.state & ControlMask));
383 }
384 
385 static void
MoveRubik3DRight(Rubik3DWidget w,XEvent * event,char ** args,int nArgs)386 MoveRubik3DRight(Rubik3DWidget w, XEvent * event, char **args, int nArgs)
387 {
388 	MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, RIGHT,
389 		       (int) (event->xkey.state & ControlMask));
390 }
391 
392 static void
MoveRubik3DBl(Rubik3DWidget w,XEvent * event,char ** args,int nArgs)393 MoveRubik3DBl(Rubik3DWidget w, XEvent * event, char **args, int nArgs)
394 {
395 	MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, BL,
396 		       (int) (event->xkey.state & ControlMask));
397 }
398 
399 static void
MoveRubik3DBottom(Rubik3DWidget w,XEvent * event,char ** args,int nArgs)400 MoveRubik3DBottom(Rubik3DWidget w, XEvent * event, char **args, int nArgs)
401 {
402 	MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, BOTTOM,
403 		       (int) (event->xkey.state & ControlMask));
404 }
405 
406 static void
MoveRubik3DBr(Rubik3DWidget w,XEvent * event,char ** args,int nArgs)407 MoveRubik3DBr(Rubik3DWidget w, XEvent * event, char **args, int nArgs)
408 {
409 	MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, BR,
410 		       (int) (event->xkey.state & ControlMask));
411 }
412 
413 static void
ResizePolyhedrons(Rubik3DWidget w)414 ResizePolyhedrons(Rubik3DWidget w)
415 {
416 	int         face, orient, side, corner, sizex, sizey;
417 	XPoint      subcubeLoc3D[MAXFACES][MAXORIENT];
418 	XPoint      diamondLoc3D[MAXFACES][MAXORIENT];
419 	XPoint      subdiamondLoc3D[MAXFACES][MAXORIENT];
420 
421 	w->rubik.letterOffset.x = -2;
422 	w->rubik.letterOffset.y = 4;
423 	w->rubik3d.viewMiddle.x = w->rubik3d.faceSize.x +
424 		w->rubik.puzzleOffset.x;
425 	w->rubik3d.viewMiddle.y = w->rubik3d.faceSize.y +
426 		w->rubik.puzzleOffset.y;
427 	for (face = 0; face < MAXFACES; face++) {
428 		faceLoc3D[face][0].x = w->rubik3d.viewMiddle.x;
429 		faceLoc3D[face][0].y = w->rubik3d.viewMiddle.y;
430 		for (orient = 1; orient < MAXORIENT; orient++) {
431 			faceLoc3D[face][orient].x = w->rubik3d.faceSize.x;
432 			faceLoc3D[face][orient].y = w->rubik3d.faceSize.y;
433 		}
434 	}
435 	if (w->rubik.vertical) {
436 		faceLoc3D[0][1].x /= -2;
437 		faceLoc3D[0][1].y /= -1;
438 		faceLoc3D[0][2].y = 0;
439 		faceLoc3D[0][3].x /= 2;
440 
441 		faceLoc3D[1][1].x /= -2;
442 		faceLoc3D[1][2].x /= -2;
443 		faceLoc3D[1][2].y /= -1;
444 		faceLoc3D[1][3].x /= 2;
445 		faceLoc3D[1][3].y /= -1;
446 
447 		faceLoc3D[2][1].y = 0;
448 		faceLoc3D[2][2].x /= -2;
449 		faceLoc3D[2][3].x /= -1;
450 		faceLoc3D[2][3].y = 0;
451 
452 		for (face = MAXFACES / 2; face < MAXFACES; face++)
453 			faceLoc3D[face][0].y += w->rubik3d.viewSize.y + 3;
454 
455 		faceLoc3D[3][1].x /= 2;
456 		faceLoc3D[3][1].y /= -1;
457 		faceLoc3D[3][2].x /= 2;
458 		faceLoc3D[3][3].x /= -2;
459 
460 		faceLoc3D[4][1].x /= -1;
461 		faceLoc3D[4][1].y = 0;
462 		faceLoc3D[4][2].x /= 2;
463 		faceLoc3D[4][2].y /= -1;
464 		faceLoc3D[4][3].y = 0;
465 
466 		faceLoc3D[5][1].x /= 2;
467 		faceLoc3D[5][2].x /= -1;
468 		faceLoc3D[5][2].y = 0;
469 		faceLoc3D[5][3].x /= -2;
470 		faceLoc3D[5][3].y /= -1;
471 	} else {
472 		faceLoc3D[0][1].x /= -1;
473 		faceLoc3D[0][1].y /= -2;
474 		faceLoc3D[0][2].y /= -2;
475 		faceLoc3D[0][3].y /= 2;
476 
477 		faceLoc3D[1][1].x = 0;
478 		faceLoc3D[1][2].x /= -1;
479 		faceLoc3D[1][2].y /= -2;
480 		faceLoc3D[1][3].x = 0;
481 		faceLoc3D[1][3].y /= -1;
482 
483 		faceLoc3D[2][1].y /= -2;
484 		faceLoc3D[2][2].x = 0;
485 		faceLoc3D[2][3].y /= 2;
486 		faceLoc3D[2][3].x /= -1;
487 
488 		for (face = MAXFACES / 2; face < MAXFACES; face++)
489 			faceLoc3D[face][0].x += w->rubik3d.viewSize.x + 3;
490 
491 		faceLoc3D[3][1].x /= -1;
492 		faceLoc3D[3][1].y /= 2;
493 		faceLoc3D[3][2].x = 0;
494 		faceLoc3D[3][2].y /= -1;
495 		faceLoc3D[3][3].y /= -2;
496 
497 		faceLoc3D[4][1].y /= 2;
498 		faceLoc3D[4][2].x /= -1;
499 		faceLoc3D[4][2].y /= 2;
500 		faceLoc3D[4][3].x /= -1;
501 		faceLoc3D[4][3].y /= -2;
502 
503 		faceLoc3D[5][1].x = 0;
504 		faceLoc3D[5][1].y /= -1;
505 		faceLoc3D[5][2].y /= 2;
506 		faceLoc3D[5][3].x = 0;
507 	}
508 	for (face = 0; face < MAXFACES; face++) {
509 		cubeLoc3D[face][0].x = faceLoc3D[face][0].x;
510 		cubeLoc3D[face][0].y = faceLoc3D[face][0].y;
511 		subcubeLoc3D[face][0].x = faceLoc3D[face][0].x;
512 		subcubeLoc3D[face][0].y = faceLoc3D[face][0].y;
513 		if (face == 0 || face == 4) {
514 			sizex = w->rubik.sizex;
515 			sizey = w->rubik.sizez;
516 		} else if (face == 1 || face == 3) {
517 			sizex = w->rubik.sizez;
518 			sizey = w->rubik.sizey;
519 		} else {	/* if (face == 2 || face == 5) */
520 			sizex = w->rubik.sizex;
521 			sizey = w->rubik.sizey;
522 		}
523 		for (orient = 1; orient < MAXORIENT; orient++) {
524 			if (((orient & 1) && (face == 2 || face == 3 || face == 4)) ||
525 			    (!(orient & 1) && !(face == 2 || face == 3 || face == 4)))
526 				cubeLoc3D[face][orient].x =
527 					(faceLoc3D[face][orient].x - (3 + sizex) *
528 				 w->rubik.delta * faceLoc3D[face][orient].x /
529 					 w->rubik3d.faceSize.x) / sizex;
530 			else
531 				cubeLoc3D[face][orient].x =
532 					(faceLoc3D[face][orient].x - (3 + sizey) *
533 				 w->rubik.delta * faceLoc3D[face][orient].x /
534 					 w->rubik3d.faceSize.x) / sizey;
535 			if (((orient & 1) && !(face == 2 || face == 3 || face == 4)) ||
536 			    (!(orient & 1) && (face == 2 || face == 3 || face == 4)))
537 				cubeLoc3D[face][orient].y =
538 					(faceLoc3D[face][orient].y - (3 + sizey) *
539 				 w->rubik.delta * faceLoc3D[face][orient].y /
540 					 w->rubik3d.faceSize.y) / sizey;
541 			else
542 				cubeLoc3D[face][orient].y =
543 					(faceLoc3D[face][orient].y - (3 + sizex) *
544 				 w->rubik.delta * faceLoc3D[face][orient].y /
545 					 w->rubik3d.faceSize.y) / sizex;
546 			if (((orient & 1) && (face == 2 || face == 3 || face == 4)) ||
547 			    (!(orient & 1) && !(face == 2 || face == 3 || face == 4)))
548 				subcubeLoc3D[face][orient].x =
549 					(faceLoc3D[face][orient].x - (5 + sizex) *
550 				 w->rubik.delta * faceLoc3D[face][orient].x /
551 					 w->rubik3d.faceSize.x) / (2 * sizex);
552 			else
553 				subcubeLoc3D[face][orient].x =
554 					(faceLoc3D[face][orient].x - (5 + sizey) *
555 				 w->rubik.delta * faceLoc3D[face][orient].x /
556 					 w->rubik3d.faceSize.x) / (2 * sizey);
557 			if (((orient & 1) && !(face == 2 || face == 3 || face == 4)) ||
558 			    (!(orient & 1) && (face == 2 || face == 3 || face == 4)))
559 				subcubeLoc3D[face][orient].y =
560 					(faceLoc3D[face][orient].y - (5 + sizey) *
561 				 w->rubik.delta * faceLoc3D[face][orient].y /
562 					 w->rubik3d.faceSize.y) / (2 * sizey);
563 			else
564 				subcubeLoc3D[face][orient].y =
565 					(faceLoc3D[face][orient].y - (5 + sizex) *
566 				 w->rubik.delta * faceLoc3D[face][orient].y /
567 					 w->rubik3d.faceSize.y) / (2 * sizex);
568 		}
569 		cubeLoc3D[face][MAXORIENT].x = -cubeLoc3D[face][1].x -
570 			cubeLoc3D[face][2].x - cubeLoc3D[face][3].x;
571 		cubeLoc3D[face][MAXORIENT].y = -cubeLoc3D[face][1].y -
572 			cubeLoc3D[face][2].y - cubeLoc3D[face][3].y;
573 	}
574 	w->rubik3d.cubeSizex.x = MAX(w->rubik3d.faceSize.x /
575 				     w->rubik.sizex - w->rubik.delta, 0);
576 	w->rubik3d.cubeSizey.x = MAX(w->rubik3d.faceSize.x /
577 				     w->rubik.sizey - w->rubik.delta, 0);
578 	w->rubik3d.cubeSizez.x = MAX(w->rubik3d.faceSize.x /
579 				     w->rubik.sizez - w->rubik.delta, 0);
580 	w->rubik3d.cubeSizex.y = MAX(w->rubik3d.faceSize.y /
581 				     w->rubik.sizex - w->rubik.delta, 0);
582 	w->rubik3d.cubeSizey.y = MAX(w->rubik3d.faceSize.y /
583 				     w->rubik.sizey - w->rubik.delta, 0);
584 	w->rubik3d.cubeSizez.y = MAX(w->rubik3d.faceSize.y /
585 				     w->rubik.sizez - w->rubik.delta, 0);
586 	w->rubik3d.cubeDiagonalx = (w->rubik3d.faceDiagonal - w->rubik.delta) /
587 		w->rubik.sizex - w->rubik.delta;
588 	w->rubik3d.cubeDiagonaly = (w->rubik3d.faceDiagonal - w->rubik.delta) /
589 		w->rubik.sizey - w->rubik.delta;
590 	w->rubik3d.cubeDiagonalz = (w->rubik3d.faceDiagonal - w->rubik.delta) /
591 		w->rubik.sizez - w->rubik.delta;
592 	if (w->rubik.vertical) {
593 		letter3DList[0].x = w->rubik3d.cubeSizex.x / 4;
594 		letter3DList[0].y = -w->rubik3d.cubeSizez.y / 2;
595 		letter3DList[1].x = -w->rubik3d.cubeDiagonalz;
596 		letter3DList[1].y = 0;
597 		letter3DList[2].x = w->rubik3d.cubeSizex.x / 4;
598 		letter3DList[2].y = w->rubik3d.cubeSizey.y / 2;
599 		letter3DList[3].x = w->rubik3d.cubeDiagonalz;
600 		letter3DList[3].y = 0;
601 		letter3DList[4].x = -w->rubik3d.cubeSizex.x / 4;
602 		letter3DList[4].y = -w->rubik3d.cubeSizez.y / 2;
603 		letter3DList[5].x = -w->rubik3d.cubeSizex.x / 4;
604 		letter3DList[5].y = w->rubik3d.cubeSizey.y / 2;
605 	} else {
606 		letter3DList[0].x = 0;
607 		letter3DList[0].y = -w->rubik3d.cubeDiagonalz;
608 		letter3DList[1].x = -w->rubik3d.cubeSizez.x / 2;
609 		letter3DList[1].y = w->rubik3d.cubeSizey.y / 4;
610 		letter3DList[2].x = w->rubik3d.cubeSizex.x / 2;
611 		letter3DList[2].y = w->rubik3d.cubeSizey.y / 4;
612 		letter3DList[3].x = -w->rubik3d.cubeSizez.x / 2;
613 		letter3DList[3].y = -w->rubik3d.cubeSizey.y / 4;
614 		letter3DList[4].x = 0;
615 		letter3DList[4].y = w->rubik3d.cubeDiagonalz;
616 		letter3DList[5].x = w->rubik3d.cubeSizex.x / 2;
617 		letter3DList[5].y = -w->rubik3d.cubeSizey.y / 4;
618 	}
619 	/* The following figures out where to put the orient lines */
620 	for (face = 0; face < MAXFACES; face++) {
621 		for (orient = 0; orient < MAXORIENT - 1; orient++) {
622 			diamondLoc3D[face][orient].x = (cubeLoc3D[face][orient].x +
623 					  cubeLoc3D[face][orient + 1].x) / 2;
624 			diamondLoc3D[face][orient].y = (cubeLoc3D[face][orient].y +
625 					  cubeLoc3D[face][orient + 1].y) / 2;
626 			subdiamondLoc3D[face][orient].x = (subcubeLoc3D[face][orient].x +
627 				       subcubeLoc3D[face][orient + 1].x) / 2;
628 			subdiamondLoc3D[face][orient].y = (subcubeLoc3D[face][orient].y +
629 				       subcubeLoc3D[face][orient + 1].y) / 2;
630 		}
631 		/* Its a parallelagram so take advantage of that */
632 		diamondLoc3D[face][orient].x = (cubeLoc3D[face][MAXORIENT - 1].x -
633 				       cubeLoc3D[face][MAXORIENT / 2].x) / 2;
634 		diamondLoc3D[face][orient].y = (cubeLoc3D[face][MAXORIENT - 1].y -
635 				       cubeLoc3D[face][MAXORIENT / 2].y) / 2;
636 		subdiamondLoc3D[face][orient].x = (subcubeLoc3D[face][MAXORIENT - 1].x -
637 				    subcubeLoc3D[face][MAXORIENT / 2].x) / 2;
638 		subdiamondLoc3D[face][orient].y = (subcubeLoc3D[face][MAXORIENT - 1].y -
639 				    subcubeLoc3D[face][MAXORIENT / 2].y) / 2;
640 
641 		MapOrientFrom3D(face, 1, &corner);
642 		orient3DList[face][corner][0].x = cubeLoc3D[face][1].x / 2;
643 		orient3DList[face][corner][0].y = cubeLoc3D[face][1].y / 2;
644 		orient3DList[face][corner][1].x = orient3DList[face][corner][0].x +
645 			(cubeLoc3D[face][2].x - subcubeLoc3D[face][2].x) / 2;
646 		orient3DList[face][corner][1].y = orient3DList[face][corner][0].y +
647 			(cubeLoc3D[face][2].y - subcubeLoc3D[face][2].y) / 2;
648 		for (orient = 1; orient < MAXORIENT; orient++) {
649 			side = corner;
650 			MapOrientFrom3D(face, (orient + 1) % MAXORIENT, &corner);
651 			orient3DList[face][corner][0].x =
652 				orient3DList[face][side][0].x + diamondLoc3D[face][orient].x;
653 			orient3DList[face][corner][0].y =
654 				orient3DList[face][side][0].y + diamondLoc3D[face][orient].y;
655 			orient3DList[face][corner][1].x =
656 				orient3DList[face][side][1].x + subdiamondLoc3D[face][orient].x;
657 			orient3DList[face][corner][1].y =
658 				orient3DList[face][side][1].y + subdiamondLoc3D[face][orient].y;
659 		}
660 	}
661 }
662 
663 Boolean
SelectPolyhedrons3D(Rubik3DWidget w,int x,int y,int * face,int * position)664 SelectPolyhedrons3D(Rubik3DWidget w, int x, int y, int *face, int *position)
665 {
666 	int         u, v, front, tl, ur, ul, i, j, sizeOfRow, sizeOfColumn;
667 
668 	if (w->rubik.vertical) {
669 		x -= w->rubik3d.viewMiddle.x;
670 		front = (y < w->rubik3d.viewSize.y + w->rubik.puzzleOffset.y);
671 		if (!front)
672 			y -= (w->rubik3d.viewSize.y);
673 		tl = (y < w->rubik3d.viewMiddle.y);
674 		y -= w->rubik3d.viewMiddle.y;
675 		u = -w->rubik3d.faceSize.y * x + w->rubik3d.faceDiagonal * y;
676 		v = w->rubik3d.faceSize.y * x + w->rubik3d.faceDiagonal * y;
677 		ur = (u < 0);
678 		ul = (v < 0);
679 		if (front) {
680 			if (tl)
681 				*face = (ur) ? 0 : 1;
682 			else
683 				*face = (ul) ? 1 : 2;
684 		} else {
685 			if (tl)
686 				*face = (ul) ? 4 : 3;
687 			else
688 				*face = (ur) ? 3 : 5;
689 		}
690 	} else {
691 		y -= w->rubik3d.viewMiddle.y;
692 		front = (x < w->rubik3d.viewSize.x + w->rubik.puzzleOffset.x);
693 		if (!front)
694 			x -= (w->rubik3d.viewSize.x);
695 		tl = (x < w->rubik3d.viewMiddle.x);
696 		x -= w->rubik3d.viewMiddle.x;
697 		u = -w->rubik3d.faceSize.x * y + w->rubik3d.faceDiagonal * x;
698 		v = w->rubik3d.faceSize.x * y + w->rubik3d.faceDiagonal * x;
699 		ur = (u < 0);
700 		ul = (v < 0);
701 		if (front) {
702 			if (tl)
703 				*face = (ur) ? 1 : 0;
704 			else
705 				*face = (ul) ? 0 : 2;
706 		} else {
707 			if (tl)
708 				*face = (ul) ? 3 : 4;
709 			else
710 				*face = (ur) ? 4 : 5;
711 		}
712 	}
713 	faceSizes((RubikWidget) w, *face, &sizeOfRow, &sizeOfColumn);
714 	if (w->rubik.vertical)
715 		switch (*face) {
716 			case 0:
717 				i = (x - 2 - (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y)) /
718 					(w->rubik3d.cubeSizex.x + w->rubik.delta);
719 				j = (y + 2) / (w->rubik3d.cubeSizez.y + w->rubik.delta) +
720 					sizeOfColumn - 1;
721 				break;
722 			case 1:
723 				i = (x + 4 + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y)) /
724 					(2 * (w->rubik3d.cubeDiagonalz + w->rubik.delta)) + sizeOfRow - 1;
725 				j = (-x - 6 + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y)) /
726 					(2 * (w->rubik3d.cubeDiagonaly + w->rubik.delta));
727 				break;
728 			case 2:
729 				i = (x - 4 + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y)) /
730 					(w->rubik3d.cubeSizex.x + w->rubik.delta);
731 				j = (y - 4) / (w->rubik3d.cubeSizey.y + w->rubik.delta);
732 				break;
733 			case 3:
734 				i = (-x + 5 + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y)) /
735 					(2 * (w->rubik3d.cubeDiagonalz + w->rubik.delta)) + sizeOfRow - 1;
736 				j = (-x + 7 - (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y)) /
737 					(2 * (w->rubik3d.cubeDiagonaly + w->rubik.delta)) + sizeOfColumn - 1;
738 				break;
739 			case 4:
740 				i = (x + (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y)) /
741 					(w->rubik3d.cubeSizex.x + w->rubik.delta) + sizeOfRow - 1;
742 				j = (y - 2) / (w->rubik3d.cubeSizez.y + w->rubik.delta) +
743 					sizeOfColumn - 1;
744 				break;
745 			case 5:
746 				i = (x + 2 - (y * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.y)) /
747 					(w->rubik3d.cubeSizex.x + w->rubik.delta) + sizeOfRow - 1;
748 				j = (y - 6) / (w->rubik3d.cubeSizey.y + w->rubik.delta);
749 				break;
750 			default:
751 				return False;
752 	} else
753 		switch (*face) {
754 			case 0:
755 				i = (-y - 3 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
756 					(2 * (w->rubik3d.cubeDiagonalx + w->rubik.delta));
757 				j = (y + 1 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
758 					(2 * (w->rubik3d.cubeDiagonalz + w->rubik.delta)) + sizeOfColumn - 1;
759 				break;
760 			case 1:
761 				i = (x + 2) / (w->rubik3d.cubeSizez.x + w->rubik.delta) +
762 					sizeOfRow - 1;
763 				j = (y - 3 - (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
764 					(w->rubik3d.cubeSizey.y + w->rubik.delta);
765 				break;
766 			case 2:
767 				i = (x - 4) / (w->rubik3d.cubeSizex.x + w->rubik.delta);
768 				j = (y - 6 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
769 					(w->rubik3d.cubeSizey.y + w->rubik.delta);
770 				break;
771 			case 3:
772 				i = x / (w->rubik3d.cubeSizez.x + w->rubik.delta) +
773 					sizeOfRow - 1;
774 				j = (y + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
775 					(w->rubik3d.cubeSizey.y + w->rubik.delta) + sizeOfColumn - 1;
776 				break;
777 			case 4:
778 				i = (-y + 9 - (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
779 					(2 * (w->rubik3d.cubeDiagonalx + w->rubik.delta)) + sizeOfRow - 1;
780 				j = (-y + 7 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
781 					(2 * (w->rubik3d.cubeDiagonalz + w->rubik.delta)) + sizeOfColumn - 1;
782 				break;
783 			case 5:
784 				i = (-x + 7) / (w->rubik3d.cubeSizex.x + w->rubik.delta) +
785 					sizeOfRow - 1;
786 				j = (-y - 4 + (x * w->rubik3d.faceDiagonal / w->rubik3d.faceSize.x)) /
787 					(w->rubik3d.cubeSizey.y + w->rubik.delta);
788 				break;
789 			default:
790 				return False;
791 		}
792 	if (i < 0 || j < 0 || i >= sizeOfRow || j >= sizeOfColumn)
793 		return False;
794 	*position = j * sizeOfRow + i;
795 	return True;
796 }
797 
798 Boolean
NarrowSelection3D(Rubik3DWidget w,int * face,int * position,int * direction)799 NarrowSelection3D(Rubik3DWidget w, int *face, int *position, int *direction)
800 {
801 	switch (*direction) {
802 		case TOP:
803 		case RIGHT:
804 		case BOTTOM:
805 		case LEFT:
806 			if (w->rubik.vertical) {
807 				if (*face == 1 || *face == 3)
808 					return False;
809 			} else {
810 				if (*face == 0 || *face == 4)
811 					return False;
812 				if (*face == 5)
813 					*direction = (*direction + 2) % MAXORIENT;
814 			}
815 			break;
816 		case CCW:
817 		case CW:
818 			break;
819 		case TR:
820 			if (w->rubik.vertical) {
821 				if (*face == 0 || *face == 5)
822 					return False;
823 				else if (*face == 1 || *face == 2 || *face == 4)
824 					*direction = TOP;
825 				else	/* (*face == 3) */
826 					*direction = LEFT;
827 			} else {
828 				if (*face == 1 || *face == 5)
829 					return False;
830 				else if (*face == 0 || *face == 2 || *face == 3)
831 					*direction = RIGHT;
832 				else	/* (*face == 4) */
833 					*direction = BOTTOM;
834 			}
835 			break;
836 		case BR:
837 			if (w->rubik.vertical) {
838 				if (*face == 2 || *face == 4)
839 					return False;
840 				else if (*face == 0 || *face == 5)
841 					*direction = BOTTOM;
842 				else if (*face == 1)
843 					*direction = RIGHT;
844 				else	/* (*face == 3) */
845 					*direction = TOP;
846 			} else {
847 				if (*face == 2 || *face == 3)
848 					return False;
849 				else if (*face == 4 || *face == 5)
850 					*direction = LEFT;
851 				else if (*face == 0)
852 					*direction = BOTTOM;
853 				else	/* (*face == 1) */
854 					*direction = RIGHT;
855 			}
856 			break;
857 		case BL:
858 			if (w->rubik.vertical) {
859 				if (*face == 0 || *face == 5)
860 					return False;
861 				else if (*face == 1 || *face == 2 || *face == 4)
862 					*direction = BOTTOM;
863 				else	/* (*face == 3) */
864 					*direction = RIGHT;
865 			} else {
866 				if (*face == 1 || *face == 5)
867 					return False;
868 				else if (*face == 0 || *face == 2 || *face == 3)
869 					*direction = LEFT;
870 				else	/* (*face == 4) */
871 					*direction = TOP;
872 			}
873 			break;
874 		case TL:
875 			if (w->rubik.vertical) {
876 				if (*face == 2 || *face == 4)
877 					return False;
878 				else if (*face == 0 || *face == 5)
879 					*direction = TOP;
880 				else if (*face == 1)
881 					*direction = LEFT;
882 				else	/* (*face == 3) */
883 					*direction = BOTTOM;
884 			} else {
885 				if (*face == 2 || *face == 3)
886 					return False;
887 				else if (*face == 4 || *face == 5)
888 					*direction = RIGHT;
889 				else if (*face == 0)
890 					*direction = TOP;
891 				else	/* (*face == 1) */
892 					*direction = LEFT;
893 			}
894 			break;
895 		default:
896 			return False;
897 	}
898 	/* Remap to row movement */
899 	if (*direction == CW || *direction == CCW) {
900 		int         i, j, sizeOfRow, sizeOfColumn, newFace;
901 
902 		newFace = rotateToRow[*face].face;
903 		faceSizes((RubikWidget) w, newFace, &sizeOfRow, &sizeOfColumn);
904 		*direction = (*direction == CCW) ?
905 			(rotateToRow[*face].direction + 2) % MAXORIENT :
906 			rotateToRow[*face].direction;
907 		if (rotateToRow[*face].sideFace == LEFT ||
908 		    rotateToRow[*face].sideFace == BOTTOM) {
909 			i = sizeOfRow - 1;
910 			j = sizeOfColumn - 1;
911 		} else {
912 			i = j = 0;
913 		}
914 		*face = newFace;
915 		*position = j * sizeOfRow + i;
916 	}
917 	return True;
918 }
919 
920 static void
DrawFrame(Rubik3DWidget w,GC gc)921 DrawFrame(Rubik3DWidget w, GC gc)
922 {
923 	int         face, dx, dy;
924 
925 	dx = w->rubik3d.viewSize.x + w->rubik.puzzleOffset.x;
926 	dy = w->rubik3d.viewSize.y + w->rubik.puzzleOffset.y;
927 	if (w->rubik.vertical) {
928 		XDrawLine(XtDisplay(w), XtWindow(w), gc,
929 			  0, dy, dx + w->rubik.puzzleOffset.x + 1, dy);
930 		XDrawString(XtDisplay(w), XtWindow(w), gc,
931 			    (int) (2 * w->rubik.delta),
932 			(int) (3 * w->rubik.delta + w->rubik.letterOffset.y),
933 			    "Front", 5);
934 		XDrawString(XtDisplay(w), XtWindow(w), gc, (int)
935 			    (-4 * w->rubik.delta + 2 * 4 * w->rubik.letterOffset.x + w->core.width),
936 			    (int) (-w->rubik.delta - 2 * w->rubik.letterOffset.y + w->core.height),
937 			    "Back", 4);
938 	} else {
939 		XDrawLine(XtDisplay(w), XtWindow(w), gc,
940 			  dx, 0, dx, dy + w->rubik.puzzleOffset.y + 1);
941 		XDrawString(XtDisplay(w), XtWindow(w), gc,
942 			    (int) (2 * w->rubik.delta),
943 			(int) (3 * w->rubik.delta + w->rubik.letterOffset.y),
944 			    "Front", 5);
945 		XDrawString(XtDisplay(w), XtWindow(w), gc, (int)
946 			    (-4 * w->rubik.delta + 2 * 4 * w->rubik.letterOffset.x + w->core.width),
947 			    (int) (-w->rubik.delta - 2 * w->rubik.letterOffset.y + w->core.height),
948 			    "Back", 4);
949 	}
950 	for (face = 0; face < MAXFACES; face++)
951 		XDrawLines(XtDisplay(w), XtWindow(w), gc,
952 			   faceLoc3D[face], MAXORIENT, CoordModePrevious);
953 }
954 
955 void
DrawSquare3D(Rubik3DWidget w,int face,int position,int offset)956 DrawSquare3D(Rubik3DWidget w, int face, int position, int offset)
957 {
958 	GC          faceGC, borderGC;
959 	int         x, y, dx, dy, i, j, sizeOfRow;
960 
961 	sizeOfRow = sizeRow((RubikWidget) w, face);
962 	i = position % sizeOfRow;
963 	j = position / sizeOfRow;
964 	MapTo3D(w, face, i, j, &x, &y);
965 	CubeOffset3D(w, face, x, y, &dx, &dy);
966 	cubeLoc3D[face][0].x = dx;
967 	cubeLoc3D[face][0].y = dy;
968 	if (offset) {
969 		borderGC = w->rubik.faceGC[(int) w->rubik.cubeLoc[face][position].face];
970 		if (w->rubik.depth < 2 || w->rubik.mono) {
971 			faceGC = w->rubik.inverseGC;
972 		} else {
973 			faceGC = w->rubik.borderGC;
974 		}
975 	} else {
976 		faceGC = w->rubik.faceGC[(int) w->rubik.cubeLoc[face][position].face];
977 		borderGC = w->rubik.borderGC;
978 	}
979 	XFillPolygon(XtDisplay(w), XtWindow(w),
980 	      faceGC, cubeLoc3D[face], MAXORIENT, Convex, CoordModePrevious);
981 	XDrawLines(XtDisplay(w), XtWindow(w),
982 		   borderGC, cubeLoc3D[face], 5, CoordModePrevious);
983 	if (w->rubik.depth < 2 || w->rubik.mono) {
984 		int         letterX, letterY;
985 		char        buf[2];
986 
987 		(void) sprintf(buf, "%c",
988 			       w->rubik.faceName[(int) w->rubik.cubeLoc[face][position].face][0]);
989 		letterX = dx + letter3DList[face].x + w->rubik.letterOffset.x;
990 		letterY = dy + letter3DList[face].y + w->rubik.letterOffset.y;
991 		if (offset) {
992 			borderGC = w->rubik.borderGC;
993 		} else {
994 			borderGC = w->rubik.inverseGC;
995 		}
996 		XDrawString(XtDisplay(w), XtWindow(w), borderGC,
997 			    letterX, letterY, buf, 1);
998 	}
999 	if (w->rubik.orient) {
1000 		XDrawLine(XtDisplay(w), XtWindow(w), borderGC,
1001 			  dx + orient3DList[face][(int) w->rubik.cubeLoc[face][position].rotation][0].x,
1002 			  dy + orient3DList[face][(int) w->rubik.cubeLoc[face][position].rotation][0].y,
1003 			  dx + orient3DList[face][(int) w->rubik.cubeLoc[face][position].rotation][1].x,
1004 			  dy + orient3DList[face][(int) w->rubik.cubeLoc[face][position].rotation][1].y);
1005 	}
1006 }
1007 
1008 static void
MapTo3D(Rubik3DWidget w,int face,int i,int j,int * x,int * y)1009 MapTo3D(Rubik3DWidget w, int face, int i, int j, int *x, int *y)
1010 {
1011 	int         sizeOfRow, sizeOfColumn;
1012 
1013 	faceSizes((RubikWidget) w, face, &sizeOfRow, &sizeOfColumn);
1014 	switch (face) {
1015 		case 0:
1016 			*x = w->rubik.sizez - 1 - j;
1017 			*y = i;
1018 			break;
1019 		case 1:
1020 			*x = j;
1021 			*y = w->rubik.sizez - 1 - i;
1022 			break;
1023 		case 2:
1024 			*x = i;
1025 			*y = j;
1026 			break;
1027 		case 3:
1028 			*x = w->rubik.sizez - 1 - i;
1029 			*y = w->rubik.sizey - 1 - j;
1030 			break;
1031 		case 4:
1032 			*x = w->rubik.sizex - 1 - i;
1033 			*y = w->rubik.sizez - 1 - j;
1034 			break;
1035 		case 5:
1036 			*x = j;
1037 			*y = w->rubik.sizex - 1 - i;
1038 			break;
1039 		default:
1040 			(void) printf("MapTo3D: face %d\n", face);
1041 	}
1042 }
1043 
1044 #ifdef DEBUG
1045 static void
MapFrom3D(w,face,x,y,i,j)1046 MapFrom3D(w, face, x, y, i, j)
1047 	Rubik3DWidget w;
1048 	int         face, x, y, *i, *j;
1049 {
1050 	switch (face) {
1051 		case 0:
1052 			*i = y;
1053 			*j = w->rubik.size - 1 - x;
1054 			break;
1055 		case 1:
1056 			*i = w->rubik.size - 1 - y;
1057 			*j = x;
1058 			break;
1059 		case 2:
1060 			*i = x;
1061 			*j = y;
1062 			break;
1063 		case 3:
1064 			*i = w->rubik.size - 1 - x;
1065 			*j = w->rubik.size - 1 - y;
1066 			break;
1067 		case 4:
1068 			*i = w->rubik.size - 1 - x;
1069 			*j = w->rubik.size - 1 - y;
1070 			break;
1071 		case 5:
1072 			*i = w->rubik.size - 1 - y;
1073 			*j = x;
1074 			break;
1075 		default:
1076 			(void) printf("MapFrom3D: face %d\n", face);
1077 	}
1078 }
1079 
1080 #endif
1081 
1082 static void
MapOrientFrom3D(int face,int corner,int * side)1083 MapOrientFrom3D(int face, int corner, int *side)
1084 {
1085 	switch (face) {
1086 		case 0:
1087 			*side = (corner + 2) % MAXORIENT;
1088 			break;
1089 		case 1:
1090 			*side = corner;
1091 			break;
1092 		case 2:
1093 			*side = (corner + 3) % MAXORIENT;
1094 			break;
1095 		case 3:
1096 			*side = (corner + 1) % MAXORIENT;
1097 			break;
1098 		case 4:
1099 			*side = (corner + 1) % MAXORIENT;
1100 			break;
1101 		case 5:
1102 			*side = corner;
1103 			break;
1104 		default:
1105 			(void) printf("MapFrom3D: face %d\n", face);
1106 	}
1107 }
1108 
1109 static void
CubeOffset3D(Rubik3DWidget w,int face,int x,int y,int * dx,int * dy)1110 CubeOffset3D(Rubik3DWidget w, int face, int x, int y, int *dx, int *dy)
1111 {
1112 	if (w->rubik.vertical)
1113 		switch (face) {
1114 			case 0:
1115 				*dx = w->rubik3d.viewMiddle.x + w->rubik.delta - 1 +
1116 					y * (w->rubik3d.cubeSizex.x + w->rubik.delta) -
1117 					x * (w->rubik3d.cubeDiagonalz + w->rubik.delta);
1118 				*dy = w->rubik3d.viewMiddle.y - w->rubik.delta - 2 -
1119 					x * (w->rubik3d.cubeSizez.y + w->rubik.delta);
1120 				break;
1121 			case 1:
1122 				*dx = w->rubik3d.viewMiddle.x - 2 * w->rubik.delta -
1123 					x * (w->rubik3d.cubeDiagonaly + w->rubik.delta) -
1124 					y * (w->rubik3d.cubeDiagonalz + w->rubik.delta);
1125 				*dy = w->rubik3d.viewMiddle.y +
1126 					x * (w->rubik3d.cubeSizey.y + w->rubik.delta) -
1127 					y * (w->rubik3d.cubeSizez.y + w->rubik.delta);
1128 				break;
1129 			case 2:
1130 				*dx = w->rubik3d.viewMiddle.x + w->rubik.delta - 1 +
1131 					x * (w->rubik3d.cubeSizex.x + w->rubik.delta) -
1132 					y * (w->rubik3d.cubeDiagonaly + w->rubik.delta);
1133 				*dy = w->rubik3d.viewMiddle.y + 2 * w->rubik.delta - 1 +
1134 					y * (w->rubik3d.cubeSizey.y + w->rubik.delta);
1135 				break;
1136 			case 3:
1137 				*dx = w->rubik3d.viewMiddle.x + 2 * w->rubik.delta +
1138 					x * (w->rubik3d.cubeDiagonalz + w->rubik.delta) +
1139 					y * (w->rubik3d.cubeDiagonaly + w->rubik.delta);
1140 				*dy = w->rubik3d.viewSize.y + w->rubik3d.viewMiddle.y +
1141 					w->rubik.delta - 1 -
1142 					x * (w->rubik3d.cubeSizez.y + w->rubik.delta) +
1143 					y * (w->rubik3d.cubeSizey.y + w->rubik.delta);
1144 				break;
1145 			case 4:
1146 				*dx = w->rubik3d.viewMiddle.x - w->rubik.delta + 1 -
1147 					x * (w->rubik3d.cubeSizex.x + w->rubik.delta) +
1148 					y * (w->rubik3d.cubeDiagonalz + w->rubik.delta);
1149 				*dy = w->rubik3d.viewSize.y + w->rubik3d.viewMiddle.y -
1150 					w->rubik.delta + 1 -
1151 					y * (w->rubik3d.cubeSizez.y + w->rubik.delta);
1152 				break;
1153 			case 5:
1154 				*dx = w->rubik3d.viewMiddle.x - 2 -
1155 					y * (w->rubik3d.cubeSizex.x + w->rubik.delta) +
1156 					x * (w->rubik3d.cubeDiagonaly + w->rubik.delta);
1157 				*dy = w->rubik3d.viewSize.y + w->rubik3d.viewMiddle.y +
1158 					2 * w->rubik.delta + 2 +
1159 					x * (w->rubik3d.cubeSizey.y + w->rubik.delta);
1160 				break;
1161 			default:
1162 				(void) printf("CubeOffset3D: face %d\n", face);
1163 	} else
1164 		switch (face) {
1165 			case 0:
1166 				*dx = w->rubik3d.viewMiddle.x +
1167 					y * (w->rubik3d.cubeSizex.x + w->rubik.delta) -
1168 					x * (w->rubik3d.cubeSizez.x + w->rubik.delta);
1169 				*dy = w->rubik3d.viewMiddle.y - 2 * w->rubik.delta + 1 -
1170 					y * (w->rubik3d.cubeDiagonalx + w->rubik.delta) -
1171 					x * (w->rubik3d.cubeDiagonalz + w->rubik.delta);
1172 				break;
1173 			case 1:
1174 				*dx = w->rubik3d.viewMiddle.x - w->rubik.delta - 2 -
1175 					y * (w->rubik3d.cubeSizez.x + w->rubik.delta);
1176 				*dy = w->rubik3d.viewMiddle.y + w->rubik.delta +
1177 					x * (w->rubik3d.cubeSizey.y + w->rubik.delta) -
1178 					y * (w->rubik3d.cubeDiagonalz + w->rubik.delta);
1179 				break;
1180 			case 2:
1181 				*dx = w->rubik3d.viewMiddle.x + 2 * w->rubik.delta - 1 +
1182 					x * (w->rubik3d.cubeSizex.x + w->rubik.delta);
1183 				*dy = w->rubik3d.viewMiddle.y + w->rubik.delta +
1184 					y * (w->rubik3d.cubeSizey.y + w->rubik.delta) -
1185 					x * (w->rubik3d.cubeDiagonalx + w->rubik.delta);
1186 				break;
1187 			case 3:
1188 				*dx = w->rubik3d.viewSize.x + w->rubik3d.viewMiddle.x -
1189 					w->rubik.delta + 1 -
1190 					x * (w->rubik3d.cubeSizez.x + w->rubik.delta);
1191 				*dy = w->rubik3d.viewMiddle.y - w->rubik.delta -
1192 					y * (w->rubik3d.cubeSizey.y + w->rubik.delta) +
1193 					x * (w->rubik3d.cubeDiagonalz + w->rubik.delta);
1194 				break;
1195 			case 4:
1196 				*dx = w->rubik3d.viewSize.x + w->rubik3d.viewMiddle.x +
1197 					w->rubik.delta - 1 -
1198 					y * (w->rubik3d.cubeSizez.x + w->rubik.delta) +
1199 					x * (w->rubik3d.cubeSizex.x + w->rubik.delta);
1200 				*dy = w->rubik3d.viewMiddle.y + 2 * w->rubik.delta +
1201 					y * (w->rubik3d.cubeDiagonalz + w->rubik.delta) +
1202 					x * (w->rubik3d.cubeDiagonalx + w->rubik.delta);
1203 				break;
1204 			case 5:
1205 				*dx = w->rubik3d.viewSize.x + w->rubik3d.viewMiddle.x +
1206 					2 * w->rubik.delta + 2 +
1207 					y * (w->rubik3d.cubeSizex.x + w->rubik.delta);
1208 				*dy = w->rubik3d.viewMiddle.y - w->rubik.delta -
1209 					x * (w->rubik3d.cubeSizey.y + w->rubik.delta) +
1210 					y * (w->rubik3d.cubeDiagonalx + w->rubik.delta);
1211 				break;
1212 			default:
1213 				(void) printf("CubeOffset3D: face %d\n", face);
1214 		}
1215 }
1216