1 
2 /*-
3 # X-BASED SKEWB
4 #
5 #  Skewb3d.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 Skewb3d */
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 "SkewbP.h"
35 #include "Skewb3dP.h"
36 
37 static void InitializeSkewb3D(Widget request, Widget renew);
38 static void ExposeSkewb3D(Widget renew, XEvent * event, Region region);
39 static void ResizeSkewb3D(Skewb3DWidget w);
40 static Boolean SetValuesSkewb3D(Widget current, Widget request, Widget renew);
41 static void MoveSkewb3DTl(Skewb3DWidget w, XEvent * event, char **args, int nArgs);
42 static void MoveSkewb3DTop(Skewb3DWidget w, XEvent * event, char **args, int nArgs);
43 static void MoveSkewb3DTr(Skewb3DWidget w, XEvent * event, char **args, int nArgs);
44 static void MoveSkewb3DLeft(Skewb3DWidget w, XEvent * event, char **args, int nArgs);
45 static void MoveSkewb3DRight(Skewb3DWidget w, XEvent * event, char **args, int nArgs);
46 static void MoveSkewb3DBl(Skewb3DWidget w, XEvent * event, char **args, int nArgs);
47 static void MoveSkewb3DBottom(Skewb3DWidget w, XEvent * event, char **args, int nArgs);
48 static void MoveSkewb3DBr(Skewb3DWidget w, XEvent * event, char **args, int nArgs);
49 static void ResizePolyhedrons(Skewb3DWidget w);
50 static void DrawFrame(Skewb3DWidget w, GC gc);
51 static void DiamondOffset3D(Skewb3DWidget w, int face, int *dx, int *dy);
52 static void MapFrom3D(int face, int corner, int *side);
53 static void MapTo3D(int face, int side, int *corner);
54 static void CubeOffset3D(Skewb3DWidget w, int face, int corner, int *dx, int *dy);
55 
56 static char defaultTranslationsSkewb3D[] =
57 "<KeyPress>q: Quit()\n\
58    Ctrl<KeyPress>C: Quit()\n\
59    <KeyPress>KP_Divide: MoveCcw()\n\
60    <KeyPress>Home: MoveTl()\n\
61    <KeyPress>KP_7: MoveTl()\n\
62    <KeyPress>R7: MoveTl()\n\
63    <KeyPress>Up: MoveTop()\n\
64    <KeyPress>KP_8: MoveTop()\n\
65    <KeyPress>R8: MoveTop()\n\
66    <KeyPress>Prior: MoveTr()\n\
67    <KeyPress>KP_9: MoveTr()\n\
68    <KeyPress>R9: MoveTr()\n\
69    <KeyPress>Left: MoveLeft()\n\
70    <KeyPress>KP_4: MoveLeft()\n\
71    <KeyPress>R10: MoveLeft()\n\
72    <KeyPress>Begin: MoveCw()\n\
73    <KeyPress>KP_5: MoveCw()\n\
74    <KeyPress>R11: MoveCw()\n\
75    <KeyPress>Right: MoveRight()\n\
76    <KeyPress>KP_6: MoveRight()\n\
77    <KeyPress>R12: MoveRight()\n\
78    <KeyPress>End: MoveBl()\n\
79    <KeyPress>KP_1: MoveBl()\n\
80    <KeyPress>R13: MoveBl()\n\
81    <KeyPress>Down: MoveBottom()\n\
82    <KeyPress>KP_2: MoveBottom()\n\
83    <KeyPress>R14: MoveBottom()\n\
84    <KeyPress>Next: MoveBr()\n\
85    <KeyPress>KP_3: MoveBr()\n\
86    <KeyPress>R15: MoveBr()\n\
87    <Btn1Down>: Select()\n\
88    <Btn1Up>: Release()\n\
89    <KeyPress>p: Practice()\n\
90    <Btn2Down>(2+): Practice()\n\
91    <Btn2Down>: PracticeMaybe()\n\
92    <KeyPress>r: Randomize()\n\
93    <Btn3Down>(2+): Randomize()\n\
94    <Btn3Down>: RandomizeMaybe()\n\
95    <KeyPress>g: Get()\n\
96    <KeyPress>w: Write()\n\
97    <KeyPress>u: Undo()\n\
98    <KeyPress>s: Solve()\n\
99    <KeyPress>o: Orientize()";
100 
101 static XtActionsRec actionsListSkewb3D[] =
102 {
103 	{"Quit", (XtActionProc) QuitSkewb},
104 	{"MoveCcw", (XtActionProc) MoveSkewbCcw},
105 	{"MoveTl", (XtActionProc) MoveSkewb3DTl},
106 	{"MoveTop", (XtActionProc) MoveSkewb3DTop},
107 	{"MoveTr", (XtActionProc) MoveSkewb3DTr},
108 	{"MoveLeft", (XtActionProc) MoveSkewb3DLeft},
109 	{"MoveCw", (XtActionProc) MoveSkewbCw},
110 	{"MoveRight", (XtActionProc) MoveSkewb3DRight},
111 	{"MoveBl", (XtActionProc) MoveSkewb3DBl},
112 	{"MoveBottom", (XtActionProc) MoveSkewb3DBottom},
113 	{"MoveBr", (XtActionProc) MoveSkewb3DBr},
114 	{"Select", (XtActionProc) SelectSkewb},
115 	{"Release", (XtActionProc) ReleaseSkewb},
116 	{"Practice", (XtActionProc) PracticeSkewb},
117 	{"PracticeMaybe", (XtActionProc) PracticeSkewbMaybe},
118 	{"Randomize", (XtActionProc) RandomizeSkewb},
119 	{"RandomizeMaybe", (XtActionProc) RandomizeSkewbMaybe},
120 	{"Get", (XtActionProc) GetSkewb},
121 	{"Write", (XtActionProc) WriteSkewb},
122 	{"Undo", (XtActionProc) UndoSkewb},
123 	{"Solve", (XtActionProc) SolveSkewb},
124 	{"Orientize", (XtActionProc) OrientizeSkewb}
125 };
126 
127 static XtResource resourcesSkewb3D[] =
128 {
129 	{XtNuserName, XtCUserName, XtRString, sizeof (String),
130 	 XtOffset(SkewbWidget, skewb.username), XtRString, "nobody"},
131 	{XtNfaceColor0, XtCLabel, XtRString, sizeof (String),
132 	 XtOffset(SkewbWidget, skewb.faceName[0]), XtRString, "Red"},
133 	{XtNfaceColor1, XtCLabel, XtRString, sizeof (String),
134 	 XtOffset(SkewbWidget, skewb.faceName[1]), XtRString, "Blue"},
135 	{XtNfaceColor2, XtCLabel, XtRString, sizeof (String),
136 	 XtOffset(SkewbWidget, skewb.faceName[2]), XtRString, "White"},
137 	{XtNfaceColor3, XtCLabel, XtRString, sizeof (String),
138 	 XtOffset(SkewbWidget, skewb.faceName[3]), XtRString, "Green"},
139 	{XtNfaceColor4, XtCLabel, XtRString, sizeof (String),
140 	 XtOffset(SkewbWidget, skewb.faceName[4]), XtRString, "Pink"},
141 	{XtNfaceColor5, XtCLabel, XtRString, sizeof (String),
142 	 XtOffset(SkewbWidget, skewb.faceName[5]), XtRString, "Yellow"},
143 	{XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
144     XtOffset(SkewbWidget, skewb.foreground), XtRString, XtDefaultForeground},
145 	{XtNpieceBorder, XtCColor, XtRPixel, sizeof (Pixel),
146    XtOffset(SkewbWidget, skewb.borderColor), XtRString, XtDefaultForeground},
147 	{XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
148 	 XtOffset(SkewbWidget, core.width), XtRString, "250"},
149 	{XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
150 	 XtOffset(SkewbWidget, core.height), XtRString, "400"},
151 	{XtNorient, XtCOrient, XtRBoolean, sizeof (Boolean),
152 	 XtOffset(SkewbWidget, skewb.orient), XtRString, "FALSE"},	/* DEFAULTORIENT */
153 	{XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
154 	 XtOffset(SkewbWidget, skewb.mono), XtRString, "FALSE"},
155 	{XtNreverse, XtCReverse, XtRBoolean, sizeof (Boolean),
156 	 XtOffset(SkewbWidget, skewb.reverse), XtRString, "FALSE"},
157 	{XtNface, XtCFace, XtRInt, sizeof (int),
158 	 XtOffset(SkewbWidget, skewb.currentFace), XtRString, "-1"},
159 	{XtNpos, XtCPos, XtRInt, sizeof (int),
160 	 XtOffset(SkewbWidget, skewb.currentPosition), XtRString, "-1"},
161 	{XtNdirection, XtCDirection, XtRInt, sizeof (int),
162 	 XtOffset(SkewbWidget, skewb.currentDirection), XtRString, "-1"},
163 	{XtNpractice, XtCBoolean, XtRBoolean, sizeof (Boolean),
164 	 XtOffset(SkewbWidget, skewb.practice), XtRString, "FALSE"},
165 	{XtNstart, XtCBoolean, XtRBoolean, sizeof (Boolean),
166 	 XtOffset(SkewbWidget, skewb.started), XtRString, "FALSE"},
167 	{XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
168 	 XtOffset(SkewbWidget, skewb.select), XtRCallback, NULL}
169 };
170 
171 Skewb3DClassRec skewb3dClassRec =
172 {
173 	{
174 		(WidgetClass) & skewbClassRec,	/* superclass */
175 		"Skewb3D",	/* class name */
176 		sizeof (Skewb3DRec),	/* widget size */
177 		NULL,		/* class initialize */
178 		NULL,		/* class part initialize */
179 		FALSE,		/* class inited */
180 		(XtInitProc) InitializeSkewb3D,		/* initialize */
181 		NULL,		/* initialize hook */
182 		XtInheritRealize,	/* realize */
183 		actionsListSkewb3D,	/* actions */
184 		XtNumber(actionsListSkewb3D),	/* num actions */
185 		resourcesSkewb3D,	/* resources */
186 		XtNumber(resourcesSkewb3D),	/* num resources */
187 		NULLQUARK,	/* xrm class */
188 		TRUE,		/* compress motion */
189 		TRUE,		/* compress exposure */
190 		TRUE,		/* compress enterleave */
191 		TRUE,		/* visible interest */
192 		NULL,		/* destroy */
193 		(XtWidgetProc) ResizeSkewb3D,	/* resize */
194 		(XtExposeProc) ExposeSkewb3D,	/* expose */
195 		(XtSetValuesFunc) SetValuesSkewb3D,	/* set values */
196 		NULL,		/* set values hook */
197 		XtInheritSetValuesAlmost,	/* set values almost */
198 		NULL,		/* get values hook */
199 		XtInheritAcceptFocus,	/* accept focus */
200 		XtVersion,	/* version */
201 		NULL,		/* callback private */
202 		defaultTranslationsSkewb3D,	/* tm table */
203 		NULL,		/* query geometry */
204 		NULL,		/* display accelerator */
205 		NULL		/* extension */
206 	},
207 	{
208 		0		/* ignore */
209 	},
210 	{
211 		0		/* ignore */
212 	}
213 };
214 
215 WidgetClass skewb3dWidgetClass = (WidgetClass) & skewb3dClassRec;
216 
217 static XPoint faceLoc3D[MAXFACES][MAXORIENT];
218 static XPoint cubeLoc3D[MAXFACES][MAXORIENT];
219 static XPoint diamondLoc3D[MAXFACES][MAXORIENT + 1];
220 static XPoint triangleLoc3D[MAXFACES][MAXORIENT][4];
221 static XPoint letter3DList[MAXFACES][MAXCUBES];
222 static XPoint orientDiamond[MAXFACES][MAXORIENT][2];
223 static XPoint orientTriangle[MAXFACES][MAXORIENT][2];
224 
225 static void
InitializeSkewb3D(Widget request,Widget renew)226 InitializeSkewb3D(Widget request, Widget renew)
227 {
228 	Skewb3DWidget w = (Skewb3DWidget) renew;
229 
230 	w->skewb.dim = 3;
231 	ResizeSkewb3D(w);
232 }
233 
234 static void
ResizeSkewb3D(Skewb3DWidget w)235 ResizeSkewb3D(Skewb3DWidget w)
236 {
237 	XPoint      tempSize;
238 
239 	w->skewb.delta = 4;
240 	w->skewb.vertical = (w->core.height >= w->core.width);
241 	if (w->skewb.vertical) {
242 		tempSize.y = w->core.height / MAXVIEWS;
243 		tempSize.x = w->core.width;
244 		if (tempSize.x >= DIVIDE(tempSize.y)) {
245 			w->skewb3d.cubeSize.y = MAX((tempSize.y - 3 * w->skewb.delta) / 2 -
246 						    w->skewb.delta - 2, 0);
247 			w->skewb3d.cubeSize.x = DIVIDE(w->skewb3d.cubeSize.y);
248 		} else {
249 			w->skewb3d.cubeSize.x = MAX((tempSize.x - 2 * w->skewb.delta - 7) / 2 -
250 						    w->skewb.delta, 0);
251 			w->skewb3d.cubeSize.y = MULTIPLY(w->skewb3d.cubeSize.x);
252 		}
253 		w->skewb3d.cubeDiagonal = w->skewb3d.cubeSize.x / 2;
254 		w->skewb3d.faceSize.x = w->skewb3d.cubeSize.x + 2 * w->skewb.delta + 1;
255 		w->skewb3d.faceSize.y = w->skewb3d.cubeSize.y + 2 * w->skewb.delta + 1;
256 		w->skewb3d.faceDiagonal = w->skewb3d.faceSize.x / 2;
257 		w->skewb3d.viewSize.x = 2 * w->skewb3d.faceSize.x + 3;
258 		w->skewb3d.viewSize.y = 2 * w->skewb3d.faceSize.y + 3;
259 		w->skewb.puzzleSize.x = w->skewb3d.viewSize.x + 1;
260 		w->skewb.puzzleSize.y = MAXVIEWS * w->skewb3d.viewSize.y + 1;
261 	} else {
262 		tempSize.x = w->core.width / MAXVIEWS;
263 		tempSize.y = w->core.height;
264 		if (tempSize.y >= DIVIDE(tempSize.x)) {
265 			w->skewb3d.cubeSize.x = MAX((tempSize.x - 3 * w->skewb.delta) / 2 -
266 						    w->skewb.delta - 2, 0);
267 			w->skewb3d.cubeSize.y = DIVIDE(w->skewb3d.cubeSize.x);
268 		} else {
269 			w->skewb3d.cubeSize.y = MAX((tempSize.y - 2 * w->skewb.delta - 7) / 2 -
270 						    w->skewb.delta, 0);
271 			w->skewb3d.cubeSize.x = MULTIPLY(w->skewb3d.cubeSize.y);
272 		}
273 		w->skewb3d.cubeDiagonal = w->skewb3d.cubeSize.y / 2;
274 		w->skewb3d.faceSize.y = w->skewb3d.cubeSize.y + 2 * w->skewb.delta + 1;
275 		w->skewb3d.faceSize.x = w->skewb3d.cubeSize.x + 2 * w->skewb.delta + 1;
276 		w->skewb3d.faceDiagonal = w->skewb3d.faceSize.y / 2;
277 		w->skewb3d.viewSize.y = 2 * w->skewb3d.faceSize.y + 3;
278 		w->skewb3d.viewSize.x = 2 * w->skewb3d.faceSize.x + 3;
279 		w->skewb.puzzleSize.y = w->skewb3d.viewSize.y + 1;
280 		w->skewb.puzzleSize.x = MAXVIEWS * w->skewb3d.viewSize.x + 1;
281 	}
282 	w->skewb.puzzleOffset.x = ((int) w->core.width - w->skewb.puzzleSize.x) / 2;
283 	w->skewb.puzzleOffset.y = ((int) w->core.height - w->skewb.puzzleSize.y) /
284 		2;
285 	ResizePolyhedrons(w);
286 }
287 
288 static void
ExposeSkewb3D(Widget renew,XEvent * event,Region region)289 ExposeSkewb3D(Widget renew, XEvent * event, Region region)
290 {
291 	Skewb3DWidget w = (Skewb3DWidget) renew;
292 
293 	if (w->core.visible) {
294 		if (w->skewb.reverse)
295 			XFillRectangle(XtDisplay(w), XtWindow(w),
296 				       w->skewb.inverseGC, 0, 0, w->core.width, w->core.height);
297 		DrawFrame(w, w->skewb.puzzleGC);
298 		DrawAllPolyhedrons((SkewbWidget) w);
299 	}
300 }
301 
302 static      Boolean
SetValuesSkewb3D(Widget current,Widget request,Widget renew)303 SetValuesSkewb3D(Widget current, Widget request, Widget renew)
304 {
305 	Skewb3DWidget c = (Skewb3DWidget) current, w = (Skewb3DWidget) renew;
306 	Boolean     redraw = False;
307 
308 	if (w->skewb3d.cubeSize.x != c->skewb3d.cubeSize.x) {
309 		ResizeSkewb3D(w);
310 		redraw = True;
311 	}
312 	return (redraw);
313 }
314 
315 static void
MoveSkewb3DTl(Skewb3DWidget w,XEvent * event,char ** args,int nArgs)316 MoveSkewb3DTl(Skewb3DWidget w, XEvent * event, char **args, int nArgs)
317 {
318 	MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, TL,
319 		       (int) (event->xkey.state & ControlMask),
320 		       (int) (event->xkey.state &
321 		    (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
322 }
323 
324 static void
MoveSkewb3DTop(Skewb3DWidget w,XEvent * event,char ** args,int nArgs)325 MoveSkewb3DTop(Skewb3DWidget w, XEvent * event, char **args, int nArgs)
326 {
327 	MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, TOP,
328 		       (int) (event->xkey.state & ControlMask),
329 		       (int) (event->xkey.state &
330 		    (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
331 }
332 
333 static void
MoveSkewb3DTr(Skewb3DWidget w,XEvent * event,char ** args,int nArgs)334 MoveSkewb3DTr(Skewb3DWidget w, XEvent * event, char **args, int nArgs)
335 {
336 	MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, TR,
337 		       (int) (event->xkey.state & ControlMask),
338 		       (int) (event->xkey.state &
339 		    (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
340 }
341 
342 static void
MoveSkewb3DLeft(Skewb3DWidget w,XEvent * event,char ** args,int nArgs)343 MoveSkewb3DLeft(Skewb3DWidget w, XEvent * event, char **args, int nArgs)
344 {
345 	MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, LEFT,
346 		       (int) (event->xkey.state & ControlMask),
347 		       (int) (event->xkey.state &
348 		    (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
349 }
350 
351 static void
MoveSkewb3DRight(Skewb3DWidget w,XEvent * event,char ** args,int nArgs)352 MoveSkewb3DRight(Skewb3DWidget w, XEvent * event, char **args, int nArgs)
353 {
354 	MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, RIGHT,
355 		       (int) (event->xkey.state & ControlMask),
356 		       (int) (event->xkey.state &
357 		    (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
358 }
359 
360 static void
MoveSkewb3DBl(Skewb3DWidget w,XEvent * event,char ** args,int nArgs)361 MoveSkewb3DBl(Skewb3DWidget w, XEvent * event, char **args, int nArgs)
362 {
363 	MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, BL,
364 		       (int) (event->xkey.state & ControlMask),
365 		       (int) (event->xkey.state &
366 		    (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
367 }
368 
369 static void
MoveSkewb3DBottom(Skewb3DWidget w,XEvent * event,char ** args,int nArgs)370 MoveSkewb3DBottom(Skewb3DWidget w, XEvent * event, char **args, int nArgs)
371 {
372 	MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, BOTTOM,
373 		       (int) (event->xkey.state & ControlMask),
374 		       (int) (event->xkey.state &
375 		    (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
376 }
377 
378 static void
MoveSkewb3DBr(Skewb3DWidget w,XEvent * event,char ** args,int nArgs)379 MoveSkewb3DBr(Skewb3DWidget w, XEvent * event, char **args, int nArgs)
380 {
381 	MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, BR,
382 		       (int) (event->xkey.state & ControlMask),
383 		       (int) (event->xkey.state &
384 		    (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
385 }
386 
387 static void
ResizePolyhedrons(Skewb3DWidget w)388 ResizePolyhedrons(Skewb3DWidget w)
389 {
390 	int         face, orient, side, corner;
391 	XPoint      subcubeLoc3D[MAXFACES][MAXORIENT];
392 	XPoint      orientCubeLoc3D[2][MAXFACES][MAXORIENT];
393 	XPoint      subdiamondLoc3D[MAXFACES][MAXORIENT];
394 	XPoint      orientDiamondLoc3D[2][MAXFACES][MAXORIENT];
395 
396 	w->skewb.letterOffset.x = -2;
397 	w->skewb.letterOffset.y = 3;
398 	w->skewb3d.viewMiddle.x = w->skewb3d.faceSize.x +
399 		w->skewb.puzzleOffset.x;
400 	w->skewb3d.viewMiddle.y = w->skewb3d.faceSize.y +
401 		w->skewb.puzzleOffset.y;
402 	for (face = 0; face < MAXFACES; face++) {
403 		faceLoc3D[face][0].x = w->skewb3d.viewMiddle.x;
404 		faceLoc3D[face][0].y = w->skewb3d.viewMiddle.y;
405 		for (orient = 1; orient < MAXORIENT; orient++) {
406 			faceLoc3D[face][orient].x = w->skewb3d.faceSize.x;
407 			faceLoc3D[face][orient].y = w->skewb3d.faceSize.y;
408 		}
409 	}
410 	if (w->skewb.vertical) {
411 		faceLoc3D[0][1].x /= -2;
412 		faceLoc3D[0][1].y /= -1;
413 		faceLoc3D[0][2].y = 0;
414 		faceLoc3D[0][3].x /= 2;
415 
416 		faceLoc3D[1][1].x /= -2;
417 		faceLoc3D[1][2].x /= -2;
418 		faceLoc3D[1][2].y /= -1;
419 		faceLoc3D[1][3].x /= 2;
420 		faceLoc3D[1][3].y /= -1;
421 
422 		faceLoc3D[2][1].y = 0;
423 		faceLoc3D[2][2].x /= -2;
424 		faceLoc3D[2][3].x /= -1;
425 		faceLoc3D[2][3].y = 0;
426 
427 		for (face = MAXFACES / 2; face < MAXFACES; face++)
428 			faceLoc3D[face][0].y += w->skewb3d.viewSize.y + 3;
429 
430 		faceLoc3D[3][1].x /= 2;
431 		faceLoc3D[3][1].y /= -1;
432 		faceLoc3D[3][2].x /= 2;
433 		faceLoc3D[3][3].x /= -2;
434 
435 		faceLoc3D[4][1].x /= -1;
436 		faceLoc3D[4][1].y = 0;
437 		faceLoc3D[4][2].x /= 2;
438 		faceLoc3D[4][2].y /= -1;
439 		faceLoc3D[4][3].y = 0;
440 
441 		faceLoc3D[5][1].x /= 2;
442 		faceLoc3D[5][2].x /= -1;
443 		faceLoc3D[5][2].y = 0;
444 		faceLoc3D[5][3].x /= -2;
445 		faceLoc3D[5][3].y /= -1;
446 	} else {
447 		faceLoc3D[0][1].x /= -1;
448 		faceLoc3D[0][1].y /= -2;
449 		faceLoc3D[0][2].y /= -2;
450 		faceLoc3D[0][3].y /= 2;
451 
452 		faceLoc3D[1][1].x = 0;
453 		faceLoc3D[1][2].x /= -1;
454 		faceLoc3D[1][2].y /= -2;
455 		faceLoc3D[1][3].x = 0;
456 		faceLoc3D[1][3].y /= -1;
457 
458 		faceLoc3D[2][1].y /= -2;
459 		faceLoc3D[2][2].x = 0;
460 		faceLoc3D[2][3].y /= 2;
461 		faceLoc3D[2][3].x /= -1;
462 
463 		for (face = MAXFACES / 2; face < MAXFACES; face++)
464 			faceLoc3D[face][0].x += w->skewb3d.viewSize.x + 3;
465 
466 		faceLoc3D[3][1].x /= -1;
467 		faceLoc3D[3][1].y /= 2;
468 		faceLoc3D[3][2].x = 0;
469 		faceLoc3D[3][2].y /= -1;
470 		faceLoc3D[3][3].y /= -2;
471 
472 		faceLoc3D[4][1].y /= 2;
473 		faceLoc3D[4][2].x /= -1;
474 		faceLoc3D[4][2].y /= 2;
475 		faceLoc3D[4][3].x /= -1;
476 		faceLoc3D[4][3].y /= -2;
477 
478 		faceLoc3D[5][1].x = 0;
479 		faceLoc3D[5][1].y /= -1;
480 		faceLoc3D[5][2].y /= 2;
481 		faceLoc3D[5][3].x = 0;
482 	}
483 
484 	for (face = 0; face < MAXFACES; face++) {
485 		cubeLoc3D[face][0].x = faceLoc3D[face][0].x;
486 		cubeLoc3D[face][0].y = faceLoc3D[face][0].y;
487 		subcubeLoc3D[face][0].x = faceLoc3D[face][0].x;
488 		subcubeLoc3D[face][0].y = faceLoc3D[face][0].y;
489 		orientCubeLoc3D[0][face][0].x = orientCubeLoc3D[1][face][0].x = 0;
490 		orientCubeLoc3D[0][face][0].y = orientCubeLoc3D[1][face][0].y = 0;
491 		for (orient = 1; orient < MAXORIENT; orient++) {
492 			cubeLoc3D[face][orient].x = faceLoc3D[face][orient].x - 3 *
493 				w->skewb.delta * faceLoc3D[face][orient].x /
494 				w->skewb3d.faceSize.x;
495 			cubeLoc3D[face][orient].y = faceLoc3D[face][orient].y - 3 *
496 				w->skewb.delta * faceLoc3D[face][orient].y /
497 				w->skewb3d.faceSize.y;
498 			subcubeLoc3D[face][orient].x = (faceLoc3D[face][orient].x -
499 			     5 * faceLoc3D[face][orient].x * w->skewb.delta /
500 						  w->skewb3d.faceSize.x) / 2;
501 			subcubeLoc3D[face][orient].y = (faceLoc3D[face][orient].y -
502 			     5 * faceLoc3D[face][orient].y * w->skewb.delta /
503 						  w->skewb3d.faceSize.y) / 2;
504 			orientCubeLoc3D[0][face][orient].x = (faceLoc3D[face][orient].x -
505 			     5 * faceLoc3D[face][orient].x * w->skewb.delta /
506 						  w->skewb3d.faceSize.x) / 4;
507 			orientCubeLoc3D[0][face][orient].y = (faceLoc3D[face][orient].y -
508 			     5 * faceLoc3D[face][orient].y * w->skewb.delta /
509 						  w->skewb3d.faceSize.y) / 4;
510 			orientCubeLoc3D[1][face][orient].x = (faceLoc3D[face][orient].x -
511 			     7 * faceLoc3D[face][orient].x * w->skewb.delta /
512 						  w->skewb3d.faceSize.x) / 6;
513 			orientCubeLoc3D[1][face][orient].y = (faceLoc3D[face][orient].y -
514 			     7 * faceLoc3D[face][orient].y * w->skewb.delta /
515 						  w->skewb3d.faceSize.y) / 6;
516 		}
517 		triangleLoc3D[face][0][1].x = subcubeLoc3D[face][1].x;
518 		triangleLoc3D[face][0][2].x = subcubeLoc3D[face][2].x -
519 			subcubeLoc3D[face][1].x;
520 		triangleLoc3D[face][0][1].y = subcubeLoc3D[face][1].y;
521 		triangleLoc3D[face][0][2].y = subcubeLoc3D[face][2].y -
522 			subcubeLoc3D[face][1].y;
523 		triangleLoc3D[face][1][1].x = subcubeLoc3D[face][2].x;
524 		triangleLoc3D[face][1][2].x = -subcubeLoc3D[face][1].x -
525 			subcubeLoc3D[face][2].x;
526 		triangleLoc3D[face][1][1].y = subcubeLoc3D[face][2].y;
527 		triangleLoc3D[face][1][2].y = -subcubeLoc3D[face][1].y -
528 			subcubeLoc3D[face][2].y;
529 		triangleLoc3D[face][2][1].x = -subcubeLoc3D[face][1].x;
530 		triangleLoc3D[face][2][2].x = subcubeLoc3D[face][1].x -
531 			subcubeLoc3D[face][2].x;
532 		triangleLoc3D[face][2][1].y = -subcubeLoc3D[face][1].y;
533 		triangleLoc3D[face][2][2].y = subcubeLoc3D[face][1].y -
534 			subcubeLoc3D[face][2].y;
535 		triangleLoc3D[face][3][1].x = -subcubeLoc3D[face][2].x;
536 		triangleLoc3D[face][3][2].x = subcubeLoc3D[face][1].x +
537 			subcubeLoc3D[face][2].x;
538 		triangleLoc3D[face][3][1].y = -subcubeLoc3D[face][2].y;
539 		triangleLoc3D[face][3][2].y = subcubeLoc3D[face][1].y +
540 			subcubeLoc3D[face][2].y;
541 		for (orient = 0; orient < MAXORIENT; orient++) {
542 			letter3DList[face][orient].x =
543 				(2 * triangleLoc3D[face][orient][1].x +
544 				 triangleLoc3D[face][orient][2].x) / 3;
545 			letter3DList[face][orient].y =
546 				(2 * triangleLoc3D[face][orient][1].y +
547 				 triangleLoc3D[face][orient][2].y) / 3;
548 			triangleLoc3D[face][orient][3].x =
549 				-triangleLoc3D[face][orient][1].x - triangleLoc3D[face][orient][2].x;
550 			triangleLoc3D[face][orient][3].y =
551 				-triangleLoc3D[face][orient][1].y - triangleLoc3D[face][orient][2].y;
552 		}
553 	}
554 	w->skewb3d.cubeSize.x = w->skewb3d.faceSize.x - 2 * w->skewb.delta;
555 	w->skewb3d.cubeSize.y = w->skewb3d.faceSize.y - 2 * w->skewb.delta;
556 	w->skewb3d.cubeDiagonal = w->skewb3d.faceDiagonal - 2 * w->skewb.delta;
557 	w->skewb3d.cubeDiag = w->skewb3d.faceDiagonal + 2 * w->skewb.delta;
558 
559 	if (w->skewb.vertical) {
560 		letter3DList[0][MAXORIENT].x = w->skewb3d.cubeSize.x / 4;
561 		letter3DList[0][MAXORIENT].y = -w->skewb3d.cubeSize.y / 2 + 2;
562 		letter3DList[1][MAXORIENT].x = -w->skewb3d.cubeDiagonal;
563 		letter3DList[1][MAXORIENT].y = 0;
564 		letter3DList[2][MAXORIENT].x = w->skewb3d.cubeSize.x / 4;
565 		letter3DList[2][MAXORIENT].y = w->skewb3d.cubeSize.y / 2 - 2;
566 		letter3DList[3][MAXORIENT].x = w->skewb3d.cubeDiagonal;
567 		letter3DList[3][MAXORIENT].y = 0;
568 		letter3DList[4][MAXORIENT].x = -w->skewb3d.cubeSize.x / 4;
569 		letter3DList[4][MAXORIENT].y = -w->skewb3d.cubeSize.y / 2 + 2;
570 		letter3DList[5][MAXORIENT].x = -w->skewb3d.cubeSize.x / 4;
571 		letter3DList[5][MAXORIENT].y = w->skewb3d.cubeSize.y / 2 - 2;
572 	} else {
573 		letter3DList[0][MAXORIENT].x = 0;
574 		letter3DList[0][MAXORIENT].y = -w->skewb3d.cubeDiagonal;
575 		letter3DList[1][MAXORIENT].x = -w->skewb3d.cubeSize.x / 2 + 2;
576 		letter3DList[1][MAXORIENT].y = w->skewb3d.cubeSize.y / 4;
577 		letter3DList[2][MAXORIENT].x = w->skewb3d.cubeSize.x / 2 - 2;
578 		letter3DList[2][MAXORIENT].y = w->skewb3d.cubeSize.y / 4;
579 		letter3DList[3][MAXORIENT].x = -w->skewb3d.cubeSize.x / 2 + 2;
580 		letter3DList[3][MAXORIENT].y = -w->skewb3d.cubeSize.y / 4;
581 		letter3DList[4][MAXORIENT].x = 0;
582 		letter3DList[4][MAXORIENT].y = w->skewb3d.cubeDiagonal;
583 		letter3DList[5][MAXORIENT].x = w->skewb3d.cubeSize.x / 2 - 2;
584 		letter3DList[5][MAXORIENT].y = -w->skewb3d.cubeSize.y / 4;
585 	}
586 
587 	for (face = 0; face < MAXFACES; face++) {
588 		for (orient = 0; orient < MAXORIENT - 1; orient++) {
589 			diamondLoc3D[face][orient].x = (cubeLoc3D[face][orient].x +
590 					  cubeLoc3D[face][orient + 1].x) / 2;
591 			diamondLoc3D[face][orient].y = (cubeLoc3D[face][orient].y +
592 					  cubeLoc3D[face][orient + 1].y) / 2;
593 			subdiamondLoc3D[face][orient].x = (subcubeLoc3D[face][orient].x +
594 				       subcubeLoc3D[face][orient + 1].x) / 2;
595 			subdiamondLoc3D[face][orient].y = (subcubeLoc3D[face][orient].y +
596 				       subcubeLoc3D[face][orient + 1].y) / 2;
597 			orientDiamondLoc3D[0][face][orient].x =
598 				(orientCubeLoc3D[0][face][orient].x +
599 				 orientCubeLoc3D[0][face][orient + 1].x) / 2;
600 			orientDiamondLoc3D[0][face][orient].y =
601 				(orientCubeLoc3D[0][face][orient].y +
602 				 orientCubeLoc3D[0][face][orient + 1].y) / 2;
603 			orientDiamondLoc3D[1][face][orient].x =
604 				(orientCubeLoc3D[1][face][orient].x +
605 				 orientCubeLoc3D[1][face][orient + 1].x) / 2;
606 			orientDiamondLoc3D[1][face][orient].y =
607 				(orientCubeLoc3D[1][face][orient].y +
608 				 orientCubeLoc3D[1][face][orient + 1].y) / 2;
609 		}
610 		/* Its a parallelagram so take advantage of that */
611 		diamondLoc3D[face][orient].x = (cubeLoc3D[face][MAXORIENT - 1].x -
612 				       cubeLoc3D[face][MAXORIENT / 2].x) / 2;
613 		diamondLoc3D[face][orient].y = (cubeLoc3D[face][MAXORIENT - 1].y -
614 				       cubeLoc3D[face][MAXORIENT / 2].y) / 2;
615 		diamondLoc3D[face][MAXORIENT].x = -diamondLoc3D[face][1].x -
616 			diamondLoc3D[face][2].x - diamondLoc3D[face][3].x;
617 		diamondLoc3D[face][MAXORIENT].y = -diamondLoc3D[face][1].y -
618 			diamondLoc3D[face][2].y - diamondLoc3D[face][3].y;
619 
620 		subdiamondLoc3D[face][orient].x = (subcubeLoc3D[face][MAXORIENT - 1].x -
621 				    subcubeLoc3D[face][MAXORIENT / 2].x) / 2;
622 		subdiamondLoc3D[face][orient].y = (subcubeLoc3D[face][MAXORIENT - 1].y -
623 				    subcubeLoc3D[face][MAXORIENT / 2].y) / 2;
624 		orientDiamondLoc3D[0][face][orient].x =
625 			(orientCubeLoc3D[0][face][MAXORIENT - 1].x -
626 			 orientCubeLoc3D[0][face][MAXORIENT / 2].x) / 2;
627 		orientDiamondLoc3D[0][face][orient].y =
628 			(orientCubeLoc3D[0][face][MAXORIENT - 1].y -
629 			 orientCubeLoc3D[0][face][MAXORIENT / 2].y) / 2;
630 		orientDiamondLoc3D[1][face][orient].x =
631 			(orientCubeLoc3D[1][face][MAXORIENT - 1].x -
632 			 orientCubeLoc3D[1][face][MAXORIENT / 2].x) / 2;
633 		orientDiamondLoc3D[1][face][orient].y =
634 			(orientCubeLoc3D[1][face][MAXORIENT - 1].y -
635 			 orientCubeLoc3D[1][face][MAXORIENT / 2].y) / 2;
636 
637 		MapFrom3D(face, 1, &corner);
638 		orientDiamond[face][corner][0].x = cubeLoc3D[face][1].x / 2;
639 		orientDiamond[face][corner][0].y = cubeLoc3D[face][1].y / 2;
640 		orientDiamond[face][corner][1].x = orientDiamond[face][corner][0].x +
641 			(cubeLoc3D[face][2].x - subcubeLoc3D[face][2].x) / 2;
642 		orientDiamond[face][corner][1].y = orientDiamond[face][corner][0].y +
643 			(cubeLoc3D[face][2].y - subcubeLoc3D[face][2].y) / 2;
644 		orientTriangle[face][corner][0].x = -orientCubeLoc3D[0][face][2].x / 2;
645 		orientTriangle[face][corner][0].y = -orientCubeLoc3D[0][face][2].y / 2;
646 		orientTriangle[face][corner][1].x = -orientCubeLoc3D[1][face][2].x / 2;
647 		orientTriangle[face][corner][1].y = -orientCubeLoc3D[1][face][2].y / 2;
648 		for (orient = 1; orient < MAXORIENT; orient++) {
649 			side = corner;
650 			MapFrom3D(face, (orient + 1) % MAXORIENT, &corner);
651 			orientDiamond[face][corner][0].x =
652 				orientDiamond[face][side][0].x +
653 				diamondLoc3D[face][orient].x;
654 			orientDiamond[face][corner][0].y =
655 				orientDiamond[face][side][0].y +
656 				diamondLoc3D[face][orient].y;
657 			orientDiamond[face][corner][1].x =
658 				orientDiamond[face][side][1].x +
659 				subdiamondLoc3D[face][orient].x;
660 			orientDiamond[face][corner][1].y =
661 				orientDiamond[face][side][1].y +
662 				subdiamondLoc3D[face][orient].y;
663 			orientTriangle[face][corner][0].x =
664 				orientTriangle[face][side][0].x +
665 				orientDiamondLoc3D[0][face][orient].x;
666 			orientTriangle[face][corner][0].y =
667 				orientTriangle[face][side][0].y +
668 				orientDiamondLoc3D[0][face][orient].y;
669 			orientTriangle[face][corner][1].x =
670 				orientTriangle[face][side][1].x +
671 				orientDiamondLoc3D[1][face][orient].x;
672 			orientTriangle[face][corner][1].y =
673 				orientTriangle[face][side][1].y +
674 				orientDiamondLoc3D[1][face][orient].y;
675 		}
676 	}
677 }
678 
679 Boolean
SelectPolyhedrons3D(Skewb3DWidget w,int x,int y,int * face,int * position)680 SelectPolyhedrons3D(Skewb3DWidget w, int x, int y, int *face, int *position)
681 {
682 	int         u, v, front, tl, ur, ul, found, side, x1, y1, x2, y2,
683 	            dx, dy;
684 
685 	x1 = x;
686 	y1 = y;
687 	if (w->skewb.vertical) {
688 		x -= w->skewb3d.viewMiddle.x;
689 		front = (y < w->skewb3d.viewSize.y + w->skewb.puzzleOffset.y);
690 		if (!front)
691 			y -= (w->skewb3d.viewSize.y);
692 		tl = (y < w->skewb3d.viewMiddle.y);
693 		y -= w->skewb3d.viewMiddle.y;
694 		u = -w->skewb3d.faceSize.y * x + w->skewb3d.faceDiagonal * y;
695 		v = w->skewb3d.faceSize.y * x + w->skewb3d.faceDiagonal * y;
696 		ur = (u < 0);
697 		ul = (v < 0);
698 		if (front) {
699 			if (tl)
700 				*face = (ur) ? 0 : 1;
701 			else
702 				*face = (ul) ? 1 : 2;
703 		} else {
704 			if (tl)
705 				*face = (ul) ? 4 : 3;
706 			else
707 				*face = (ur) ? 3 : 5;
708 		}
709 	} else {
710 		y -= w->skewb3d.viewMiddle.y;
711 		front = (x < w->skewb3d.viewSize.x + w->skewb.puzzleOffset.x);
712 		if (!front)
713 			x -= (w->skewb3d.viewSize.x);
714 		tl = (x < w->skewb3d.viewMiddle.x);
715 		x -= w->skewb3d.viewMiddle.x;
716 		u = -w->skewb3d.faceSize.x * y + w->skewb3d.faceDiagonal * x;
717 		v = w->skewb3d.faceSize.x * y + w->skewb3d.faceDiagonal * x;
718 		ur = (u < 0);
719 		ul = (v < 0);
720 		if (front) {
721 			if (tl)
722 				*face = (ur) ? 1 : 0;
723 			else
724 				*face = (ul) ? 0 : 2;
725 		} else {
726 			if (tl)
727 				*face = (ul) ? 3 : 4;
728 			else
729 				*face = (ur) ? 4 : 5;
730 		}
731 	}
732 	x = x1;
733 	y = y1;
734 	found = 0;
735 	DiamondOffset3D(w, *face, &dx, &dy);
736 	for (side = 0; side < MAXORIENT; side++) {
737 		x1 = dx + orientDiamond[*face][side][0].x;
738 		y1 = dy + orientDiamond[*face][side][0].y;
739 		x2 = dx + orientDiamond[*face][(side + 1) % MAXORIENT][0].x;
740 		y2 = dy + orientDiamond[*face][(side + 1) % MAXORIENT][0].y;
741 		if ((x2 - x1) * (y - y1) <= (y2 - y1) * (x - x1)) {
742 			*position = side;
743 			found++;
744 		}
745 	}
746 	if (found == 0)
747 		*position = MAXORIENT;
748 	else if (found > 1)
749 		return False;
750 	return True;
751 }
752 
753 Boolean
NarrowSelection3D(Skewb3DWidget w,int * face,int * position,int * direction)754 NarrowSelection3D(Skewb3DWidget w, int *face, int *position, int *direction)
755 {
756 	switch (*direction) {
757 		case TR:
758 		case BR:
759 		case BL:
760 		case TL:
761 			if (w->skewb.vertical) {
762 				if (*face == 1)
763 					*direction = *direction + 2 * MAXORIENT;
764 				else if (*face == 3)
765 					*direction = (*direction + 3) % MAXORIENT + 2 * MAXORIENT;
766 			} else {
767 				if (*face == 0)
768 					*direction = (*direction + 3) % MAXORIENT + 2 * MAXORIENT;
769 				else if (*face == 4)
770 					*direction = (*direction + 2) % MAXORIENT + 2 * MAXORIENT;
771 				else if (*face == 5)
772 					*direction = (*direction + 2) % MAXORIENT;
773 			}
774 			break;
775 		case CCW:
776 		case CW:
777 			break;
778 		case TOP:
779 		case RIGHT:
780 		case BOTTOM:
781 		case LEFT:
782 			if (w->skewb.vertical) {
783 				if (*face == 1)
784 					*direction = (TL + *direction) % MAXORIENT;
785 				else if (*face == 3)
786 					*direction = (BL + *direction) % MAXORIENT;
787 			} else {
788 				if (*face == 0)
789 					*direction = (TR + *direction) % MAXORIENT;
790 				else if (*face == 4)
791 					*direction = (BR + *direction) % MAXORIENT;
792 				else if (*face == 5)
793 					*direction = (BL + *direction) % MAXORIENT + 2 * MAXORIENT;
794 			}
795 			break;
796 		default:
797 			return False;
798 	}
799 	if (*position != MAXORIENT) {
800 		if (*direction == CW)
801 			*direction = (*position + 1) % MAXORIENT;
802 		else if (*direction == CCW)
803 			*direction = (*position + 3) % MAXORIENT;
804 		else if (*direction < MAXORIENT && !((*direction + *position) % 2))
805 			return False;
806 	}
807 	return True;
808 }
809 
810 static void
DrawFrame(Skewb3DWidget w,GC gc)811 DrawFrame(Skewb3DWidget w, GC gc)
812 {
813 	int         face, dx, dy;
814 
815 	dx = w->skewb3d.viewSize.x + w->skewb.puzzleOffset.x;
816 	dy = w->skewb3d.viewSize.y + w->skewb.puzzleOffset.y;
817 	if (w->skewb.vertical) {
818 		XDrawLine(XtDisplay(w), XtWindow(w), gc,
819 			  0, dy, dx + w->skewb.puzzleOffset.x + 1, dy);
820 		XDrawString(XtDisplay(w), XtWindow(w), gc,
821 			    (int) (2 * w->skewb.delta),
822 			(int) (3 * w->skewb.delta + w->skewb.letterOffset.y),
823 			    "Front", 5);
824 		XDrawString(XtDisplay(w), XtWindow(w), gc, (int)
825 			    (-4 * w->skewb.delta + 2 * 4 * w->skewb.letterOffset.x + w->core.width),
826 			    (int) (-w->skewb.delta - 2 * w->skewb.letterOffset.y + w->core.height),
827 			    "Back", 4);
828 	} else {
829 		XDrawLine(XtDisplay(w), XtWindow(w), gc,
830 			  dx, 0, dx, dy + w->skewb.puzzleOffset.y + 1);
831 		XDrawString(XtDisplay(w), XtWindow(w), gc,
832 			    (int) (2 * w->skewb.delta),
833 			(int) (3 * w->skewb.delta + w->skewb.letterOffset.y),
834 			    "Front", 5);
835 		XDrawString(XtDisplay(w), XtWindow(w), gc, (int)
836 			    (-4 * w->skewb.delta + 2 * 4 * w->skewb.letterOffset.x + w->core.width),
837 			    (int) (-w->skewb.delta - 2 * w->skewb.letterOffset.y + w->core.height),
838 			    "Back", 4);
839 	}
840 	for (face = 0; face < MAXFACES; face++)
841 		XDrawLines(XtDisplay(w), XtWindow(w), gc,
842 			   faceLoc3D[face], MAXORIENT, CoordModePrevious);
843 }
844 
845 void
DrawDiamond3D(Skewb3DWidget w,int face,int offset)846 DrawDiamond3D(Skewb3DWidget w, int face, int offset)
847 {
848 	GC          faceGC, borderGC;
849 	int         dx, dy;
850 
851 	DiamondOffset3D(w, face, &dx, &dy);
852 	diamondLoc3D[face][0].x = dx + cubeLoc3D[face][1].x / 2;
853 	diamondLoc3D[face][0].y = dy + cubeLoc3D[face][1].y / 2;
854 	if (offset) {
855 		borderGC = w->skewb.faceGC[(int) w->skewb.cubeLoc[face][MAXORIENT].face];
856 		if (w->skewb.depth < 2 || w->skewb.mono) {
857 			faceGC = w->skewb.inverseGC;
858 		} else {
859 			faceGC = w->skewb.borderGC;
860 		}
861 	} else {
862 		faceGC = w->skewb.faceGC[(int) w->skewb.cubeLoc[face][MAXORIENT].face];
863 		borderGC = w->skewb.borderGC;
864 	}
865 	XFillPolygon(XtDisplay(w), XtWindow(w),
866 		   faceGC, diamondLoc3D[face], 4, Convex, CoordModePrevious);
867 	XDrawLines(XtDisplay(w), XtWindow(w),
868 		   borderGC, diamondLoc3D[face], 5, CoordModePrevious);
869 	if (w->skewb.depth < 2 || w->skewb.mono) {
870 		int         letterX, letterY;
871 		char        buf[2];
872 
873 		(void) sprintf(buf, "%c",
874 		w->skewb.faceName[w->skewb.cubeLoc[face][MAXORIENT].face][0]);
875 		letterX = dx + letter3DList[face][MAXORIENT].x + w->skewb.letterOffset.x;
876 		letterY = dy + letter3DList[face][MAXORIENT].y + w->skewb.letterOffset.y;
877 		if (offset) {
878 			borderGC = w->skewb.borderGC;
879 		} else {
880 			borderGC = w->skewb.inverseGC;
881 		}
882 		XDrawString(XtDisplay(w), XtWindow(w), borderGC,
883 			    letterX, letterY, buf, 1);
884 	}
885 	if (w->skewb.orient) {
886 		XDrawLine(XtDisplay(w), XtWindow(w), borderGC,
887 			  dx +
888 			  orientDiamond[face][w->skewb.cubeLoc[face][MAXORIENT].rotation][0].x,
889 			  dy +
890 			  orientDiamond[face][w->skewb.cubeLoc[face][MAXORIENT].rotation][0].y,
891 			  dx +
892 			  orientDiamond[face][w->skewb.cubeLoc[face][MAXORIENT].rotation][1].x,
893 			  dy +
894 			  orientDiamond[face][w->skewb.cubeLoc[face][MAXORIENT].rotation][1].y);
895 	}
896 }
897 
898 void
DrawTriangle3D(Skewb3DWidget w,int face,int position,int offset)899 DrawTriangle3D(Skewb3DWidget w, int face, int position, int offset)
900 {
901 	GC          faceGC, borderGC;
902 	int         side, dx, dy, letterX, letterY;
903 
904 	MapTo3D(face, position, &side);
905 	CubeOffset3D(w, face, side, &dx, &dy);
906 	letterX = dx + letter3DList[face][side].x;
907 	letterY = dy + letter3DList[face][side].y;
908 	triangleLoc3D[face][side][0].x = dx;
909 	triangleLoc3D[face][side][0].y = dy;
910 	if (offset) {
911 		borderGC = w->skewb.faceGC[(int) w->skewb.cubeLoc[face][position].face];
912 		if (w->skewb.depth < 2 || w->skewb.mono) {
913 			faceGC = w->skewb.inverseGC;
914 		} else {
915 			faceGC = w->skewb.borderGC;
916 		}
917 	} else {
918 		faceGC = w->skewb.faceGC[(int) w->skewb.cubeLoc[face][position].face];
919 		borderGC = w->skewb.borderGC;
920 	}
921 	XFillPolygon(XtDisplay(w), XtWindow(w), faceGC,
922 		     triangleLoc3D[face][side], 3, Convex, CoordModePrevious);
923 	XDrawLines(XtDisplay(w), XtWindow(w), borderGC,
924 		   triangleLoc3D[face][side], 4, CoordModePrevious);
925 	if (w->skewb.depth < 2 || w->skewb.mono) {
926 		char        buf[2];
927 
928 		(void) sprintf(buf, "%c",
929 		w->skewb.faceName[w->skewb.cubeLoc[face][position].face][0]);
930 		if (offset) {
931 			borderGC = w->skewb.borderGC;
932 		} else {
933 			borderGC = w->skewb.inverseGC;
934 		}
935 		XDrawString(XtDisplay(w), XtWindow(w), borderGC,
936 			    letterX + w->skewb.letterOffset.x, letterY + w->skewb.letterOffset.y,
937 			    buf, 1);
938 	}
939 	if (w->skewb.orient) {
940 		XDrawLine(XtDisplay(w), XtWindow(w), borderGC,
941 			  letterX +
942 			  orientTriangle[face][w->skewb.cubeLoc[face][position].rotation][0].x,
943 			  letterY +
944 			  orientTriangle[face][w->skewb.cubeLoc[face][position].rotation][0].y,
945 			  letterX +
946 			  orientTriangle[face][w->skewb.cubeLoc[face][position].rotation][1].x,
947 			  letterY +
948 			  orientTriangle[face][w->skewb.cubeLoc[face][position].rotation][1].y);
949 	}
950 }
951 
952 static void
MapTo3D(int face,int side,int * corner)953 MapTo3D(int face, int side, int *corner)
954 {
955 	switch (face) {
956 		case 0:
957 			*corner = (side + 2) % MAXORIENT;
958 			break;
959 		case 1:
960 		case 5:
961 			*corner = side;
962 			break;
963 		case 2:
964 			*corner = (side + 1) % MAXORIENT;
965 			break;
966 		case 3:
967 		case 4:
968 			*corner = (side + 3) % MAXORIENT;
969 			break;
970 		default:
971 			(void) printf("MapTo3D: face %d\n", face);
972 	}
973 }
974 
975 static void
MapFrom3D(int face,int corner,int * side)976 MapFrom3D(int face, int corner, int *side)
977 {
978 	switch (face) {
979 		case 0:
980 			*side = (corner + 2) % MAXORIENT;
981 			break;
982 		case 1:
983 		case 5:
984 			*side = corner;
985 			break;
986 		case 2:
987 			*side = (corner + 3) % MAXORIENT;
988 			break;
989 		case 3:
990 		case 4:
991 			*side = (corner + 1) % MAXORIENT;
992 			break;
993 		default:
994 			(void) printf("MapFrom3D: face %d\n", face);
995 	}
996 }
997 
998 static void
DiamondOffset3D(Skewb3DWidget w,int face,int * dx,int * dy)999 DiamondOffset3D(Skewb3DWidget w, int face, int *dx, int *dy)
1000 {
1001 	if (w->skewb.vertical) {
1002 		switch (face) {
1003 			case 0:
1004 				*dx = w->skewb3d.viewMiddle.x + w->skewb.delta - 1;
1005 				*dy = w->skewb3d.viewMiddle.y - w->skewb.delta - 2;
1006 				break;
1007 			case 1:
1008 				*dx = w->skewb3d.viewMiddle.x - 2 * w->skewb.delta;
1009 				*dy = w->skewb3d.viewMiddle.y;
1010 				break;
1011 			case 2:
1012 				*dx = w->skewb3d.viewMiddle.x + w->skewb.delta - 1;
1013 				*dy = w->skewb3d.viewMiddle.y + 2 * w->skewb.delta - 1;
1014 				break;
1015 			case 3:
1016 				*dx = w->skewb3d.viewMiddle.x + 2 * w->skewb.delta;
1017 				*dy = w->skewb3d.viewSize.y + w->skewb3d.viewMiddle.y +
1018 					w->skewb.delta - 1;
1019 				break;
1020 			case 4:
1021 				*dx = w->skewb3d.viewMiddle.x - w->skewb.delta + 1;
1022 				*dy = w->skewb3d.viewSize.y + w->skewb3d.viewMiddle.y -
1023 					w->skewb.delta + 1;
1024 				break;
1025 			case 5:
1026 				*dx = w->skewb3d.viewMiddle.x - 2;
1027 				*dy = w->skewb3d.viewSize.y + w->skewb3d.viewMiddle.y +
1028 					2 * w->skewb.delta + 2;
1029 				break;
1030 			default:
1031 				(void) printf("DiamondOffset3D: face %d\n", face);
1032 		}
1033 	} else {
1034 		switch (face) {
1035 			case 0:
1036 				*dx = w->skewb3d.viewMiddle.x;
1037 				*dy = w->skewb3d.viewMiddle.y - 2 * w->skewb.delta + 1;
1038 				break;
1039 			case 1:
1040 				*dx = w->skewb3d.viewMiddle.x - w->skewb.delta - 2;
1041 				*dy = w->skewb3d.viewMiddle.y + w->skewb.delta;
1042 				break;
1043 			case 2:
1044 				*dx = w->skewb3d.viewMiddle.x + 2 * w->skewb.delta - 1;
1045 				*dy = w->skewb3d.viewMiddle.y + w->skewb.delta;
1046 				break;
1047 			case 3:
1048 				*dx = w->skewb3d.viewSize.x + w->skewb3d.viewMiddle.x -
1049 					w->skewb.delta + 1;
1050 				*dy = w->skewb3d.viewMiddle.y - w->skewb.delta;
1051 				break;
1052 			case 4:
1053 				*dx = w->skewb3d.viewSize.x + w->skewb3d.viewMiddle.x +
1054 					w->skewb.delta - 1;
1055 				*dy = w->skewb3d.viewMiddle.y + 2 * w->skewb.delta;
1056 				break;
1057 			case 5:
1058 				*dx = w->skewb3d.viewSize.x + w->skewb3d.viewMiddle.x +
1059 					2 * w->skewb.delta + 2;
1060 				*dy = w->skewb3d.viewMiddle.y - w->skewb.delta;
1061 				break;
1062 			default:
1063 				(void) printf("DiamondOffset3D: face %d\n", face);
1064 		}
1065 	}
1066 }
1067 
1068 static void
CubeOffset3D(Skewb3DWidget w,int face,int corner,int * dx,int * dy)1069 CubeOffset3D(Skewb3DWidget w, int face, int corner, int *dx, int *dy)
1070 {
1071 	int         side;
1072 
1073 	DiamondOffset3D(w, face, dx, dy);
1074 	for (side = 1; side <= corner; side++) {
1075 		*dx += cubeLoc3D[face][side].x;
1076 		*dy += cubeLoc3D[face][side].y;
1077 	}
1078 }
1079