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