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