1 /*
2 * drawboard3d.c
3 * by Jon Kinsey, 2003
4 *
5 * 3d board drawing code
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 3 or later of the GNU General Public License as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * $Id: drawboard3d.c,v 1.105 2018/05/05 20:52:19 plm Exp $
22 */
23
24 #include "config.h"
25 #include "inc3d.h"
26 #include "boardpos.h"
27 #ifdef WIN32
28 #include "wglbuffer.h"
29 #endif
30 #include "gtklocdefs.h"
31
32 /* Used to calculate correct viewarea for board/fov angles */
33 typedef struct _viewArea {
34 float top;
35 float bottom;
36 float width;
37 } viewArea;
38
39 /* My logcube - more than 32 then return 0 (show 64) */
40 static int
LogCube(unsigned int n)41 LogCube(unsigned int n)
42 {
43 unsigned int i = 0;
44 while (n > (1u << i))
45 i++;
46
47 return i < 6 ? i : 0;
48 }
49
50 /* All the board element sizes - based on base_unit size */
51
52 /*lint --e{834} ignore potentially confusing operators - caused by lots of board sizes calculations */
53
54 /* Widths */
55
56 /* Side edge width of bearoff trays */
57 #define EDGE_WIDTH base_unit
58
59 #define TRAY_WIDTH (EDGE_WIDTH * 2.0f + PIECE_HOLE)
60 #define BOARD_WIDTH (PIECE_HOLE * 6.0f)
61 #define BAR_WIDTH (PIECE_HOLE * 1.7f)
62 #define DICE_AREA_CLICK_WIDTH BOARD_WIDTH
63
64 #define TAKI_WIDTH .9f
65
66 #define TOTAL_WIDTH ((TRAY_WIDTH + BOARD_WIDTH) * 2.0f + BAR_WIDTH)
67
68 /* Heights */
69
70 /* Bottom + top edge */
71 #define EDGE_HEIGHT (base_unit * 1.5f)
72
73 #define POINT_HEIGHT (PIECE_HOLE * 6)
74 #define TRAY_HEIGHT (EDGE_HEIGHT + POINT_HEIGHT)
75 #define MID_SIDE_GAP_HEIGHT (base_unit * 3.5f)
76 #define DICE_AREA_HEIGHT MID_SIDE_GAP_HEIGHT
77 /* Vertical gap between pieces */
78 #define PIECE_GAP_HEIGHT (base_unit / 5.0f)
79
80 #define TOTAL_HEIGHT (TRAY_HEIGHT * 2.0f + MID_SIDE_GAP_HEIGHT)
81
82 /* Depths */
83
84 #define EDGE_DEPTH (base_unit * 1.95f)
85 #define BASE_DEPTH base_unit
86
87 /* Other objects */
88
89 #define BOARD_FILLET (base_unit / 3.0f)
90
91 #define DOUBLECUBE_SIZE (PIECE_HOLE * .9f)
92
93 /* Dice animation step size */
94 #define DICE_STEP_SIZE0 (base_unit * 1.3f)
95 #define DICE_STEP_SIZE1 (base_unit * 1.7f)
96
97 #define HINGE_GAP (base_unit / 12.0f)
98 #define HINGE_WIDTH (base_unit / 2.0f)
99 #define HINGE_HEIGHT (base_unit * 7.0f)
100
101 #undef ARROW_SIZE
102 #define ARROW_SIZE (EDGE_HEIGHT * .8f)
103
104 #define FLAG_HEIGHT (base_unit * 3)
105 #define FLAG_WIDTH (FLAG_HEIGHT * 1.4f)
106 #define FLAG_WAG (FLAG_HEIGHT * .3f)
107 #define FLAGPOLE_WIDTH (base_unit * .2f)
108 #define FLAGPOLE_HEIGHT (FLAG_HEIGHT * 2.05f)
109
110 /* Slight offset from surface - avoid using unless necessary */
111 #define LIFT_OFF (base_unit / 50.0f)
112
113 float
getBoardWidth(void)114 getBoardWidth(void)
115 {
116 return TOTAL_WIDTH;
117 }
118
119 float
getBoardHeight(void)120 getBoardHeight(void)
121 {
122 return TOTAL_HEIGHT;
123 }
124
125 float
getDiceSize(const renderdata * prd)126 getDiceSize(const renderdata * prd)
127 {
128 return prd->diceSize * base_unit;
129 }
130
131 static void
TidyShadows(BoardData3d * bd3d)132 TidyShadows(BoardData3d * bd3d)
133 {
134 freeOccluder(&bd3d->Occluders[OCC_BOARD]);
135 freeOccluder(&bd3d->Occluders[OCC_CUBE]);
136 freeOccluder(&bd3d->Occluders[OCC_DICE1]);
137 freeOccluder(&bd3d->Occluders[OCC_FLAG]);
138 freeOccluder(&bd3d->Occluders[OCC_HINGE1]);
139 freeOccluder(&bd3d->Occluders[OCC_PIECE]);
140 }
141
142 void
Tidy3dObjects(BoardData3d * bd3d,const renderdata * prd)143 Tidy3dObjects(BoardData3d * bd3d, const renderdata * prd)
144 {
145 bd3d->shadowsInitialised = FALSE;
146
147 glDeleteLists(bd3d->pieceList, 1);
148 glDeleteLists(bd3d->diceList, 1);
149 glDeleteLists(bd3d->piecePickList, 1);
150 glDeleteLists(bd3d->DCList, 1);
151
152 FreeNumberFont(bd3d->numberFont);
153 FreeNumberFont(bd3d->cubeFont);
154
155 gluDeleteQuadric(bd3d->qobjTex);
156 gluDeleteQuadric(bd3d->qobj);
157
158 if (flag.flagNurb != NULL)
159 gluDeleteNurbsRenderer(flag.flagNurb);
160
161 if (bd3d->boardPoints)
162 freeEigthPoints(&bd3d->boardPoints, prd->curveAccuracy);
163
164 TidyShadows(bd3d);
165 ClearTextures(bd3d);
166 DeleteTextureList();
167 }
168
169 static void
preDrawPiece0(const renderdata * prd,int display)170 preDrawPiece0(const renderdata * prd, int display)
171 {
172 unsigned int i, j;
173 float angle2, step;
174
175 float radius = PIECE_HOLE / 2.0f;
176 float discradius = radius * 0.8f;
177 float lip = radius - discradius;
178 float height = PIECE_DEPTH - 2 * lip;
179 float ***p;
180 float ***n;
181
182 step = (2 * (float) G_PI) / prd->curveAccuracy;
183
184 /* Draw top/bottom of piece */
185 if (display) {
186 circleTex(discradius, PIECE_DEPTH, prd->curveAccuracy, prd->ChequerMat[0].pTexture);
187 if (prd->ChequerMat[0].pTexture && prd->pieceTextureType == PTT_TOP)
188 glDisable(GL_TEXTURE_2D);
189
190 circleRevTex(discradius, 0.f, prd->curveAccuracy, prd->ChequerMat[0].pTexture);
191 } else {
192 circleSloped(radius, 0.f, PIECE_DEPTH, prd->curveAccuracy);
193 return;
194 }
195 /* Draw side of piece */
196 glPushMatrix();
197 glTranslatef(0.f, 0.f, lip);
198 cylinder(radius, height, prd->curveAccuracy, prd->ChequerMat[0].pTexture);
199 glPopMatrix();
200
201 /* Draw edges of piece */
202 p = Alloc3d(prd->curveAccuracy + 1, prd->curveAccuracy / 4 + 1, 3);
203 n = Alloc3d(prd->curveAccuracy + 1, prd->curveAccuracy / 4 + 1, 3);
204
205 angle2 = 0;
206 for (j = 0; j <= prd->curveAccuracy / 4; j++) {
207 float latitude = sinf(angle2) * lip;
208 float new_radius = Dist2d(lip, latitude);
209 float angle = 0;
210
211 for (i = 0; i < prd->curveAccuracy; i++) {
212 n[i][j][0] = sinf(angle) * new_radius;
213 p[i][j][0] = sinf(angle) * (discradius + new_radius);
214 n[i][j][1] = cosf(angle) * new_radius;
215 p[i][j][1] = cosf(angle) * (discradius + new_radius);
216 p[i][j][2] = latitude + lip + height;
217 n[i][j][2] = latitude;
218
219 angle += step;
220 }
221 p[i][j][0] = p[0][j][0];
222 p[i][j][1] = p[0][j][1];
223 p[i][j][2] = p[0][j][2];
224 n[i][j][0] = n[0][j][0];
225 n[i][j][1] = n[0][j][1];
226 n[i][j][2] = n[0][j][2];
227
228 angle2 += step;
229 }
230
231 for (j = 0; j < prd->curveAccuracy / 4; j++) {
232 glBegin(GL_QUAD_STRIP);
233 for (i = 0; i < prd->curveAccuracy + 1; i++) {
234 glNormal3f((n[i][j][0]) / lip, (n[i][j][1]) / lip, n[i][j][2] / lip);
235 if (prd->ChequerMat[0].pTexture)
236 glTexCoord2f((p[i][j][0] + discradius) / (discradius * 2),
237 (p[i][j][1] + discradius) / (discradius * 2));
238 glVertex3f(p[i][j][0], p[i][j][1], p[i][j][2]);
239
240 glNormal3f((n[i][j + 1][0]) / lip, (n[i][j + 1][1]) / lip, n[i][j + 1][2] / lip);
241 if (prd->ChequerMat[0].pTexture)
242 glTexCoord2f((p[i][j + 1][0] + discradius) / (discradius * 2),
243 (p[i][j + 1][1] + discradius) / (discradius * 2));
244 glVertex3f(p[i][j + 1][0], p[i][j + 1][1], p[i][j + 1][2]);
245 }
246 glEnd();
247
248 glBegin(GL_QUAD_STRIP);
249 for (i = 0; i < prd->curveAccuracy + 1; i++) {
250 glNormal3f((n[i][j + 1][0]) / lip, (n[i][j + 1][1]) / lip, n[i][j + 1][2] / lip);
251 if (prd->ChequerMat[0].pTexture)
252 glTexCoord2f((p[i][j + 1][0] + discradius) / (discradius * 2),
253 (p[i][j + 1][1] + discradius) / (discradius * 2));
254 glVertex3f(p[i][j + 1][0], p[i][j + 1][1], PIECE_DEPTH - p[i][j + 1][2]);
255
256 glNormal3f((n[i][j][0]) / lip, (n[i][j][1]) / lip, n[i][j][2] / lip);
257 if (prd->ChequerMat[0].pTexture)
258 glTexCoord2f((p[i][j][0] + discradius) / (discradius * 2),
259 (p[i][j][1] + discradius) / (discradius * 2));
260 glVertex3f(p[i][j][0], p[i][j][1], PIECE_DEPTH - p[i][j][2]);
261 }
262 glEnd();
263 }
264
265 Free3d(p, prd->curveAccuracy + 1, prd->curveAccuracy / 4 + 1);
266 Free3d(n, prd->curveAccuracy + 1, prd->curveAccuracy / 4 + 1);
267
268 /* Anti-alias piece edges */
269 glLineWidth(1.f);
270 glEnable(GL_LINE_SMOOTH);
271 glEnable(GL_BLEND);
272 glDepthMask(GL_FALSE);
273
274 circleOutlineOutward(radius, PIECE_DEPTH - lip, prd->curveAccuracy);
275 circleOutlineOutward(radius, lip, prd->curveAccuracy);
276
277 glDisable(GL_BLEND);
278 glDisable(GL_LINE_SMOOTH);
279 glDepthMask(GL_TRUE);
280
281 if (prd->ChequerMat[0].pTexture && prd->pieceTextureType == PTT_TOP)
282 glEnable(GL_TEXTURE_2D); /* Re-enable texturing */
283 }
284
285 static void
preDrawPiece1(const renderdata * prd,int display)286 preDrawPiece1(const renderdata * prd, int display)
287 {
288 float pieceRad = PIECE_HOLE / 2.0f;
289
290 /* Draw top/bottom of piece */
291 if (display) {
292 circleTex(pieceRad, PIECE_DEPTH, prd->curveAccuracy, prd->ChequerMat[0].pTexture);
293
294 if (prd->ChequerMat[0].pTexture && prd->pieceTextureType == PTT_TOP)
295 glDisable(GL_TEXTURE_2D);
296
297 circleRevTex(pieceRad, 0.f, prd->curveAccuracy, prd->ChequerMat[0].pTexture);
298 } else {
299 circleSloped(pieceRad, 0.f, PIECE_DEPTH, prd->curveAccuracy);
300 return;
301 }
302
303 /* Edge of piece */
304 cylinder(pieceRad, PIECE_DEPTH, prd->curveAccuracy, prd->ChequerMat[0].pTexture);
305
306 /* Anti-alias piece edges */
307 glLineWidth(1.f);
308 glEnable(GL_LINE_SMOOTH);
309 glEnable(GL_BLEND);
310 glDepthMask(GL_FALSE);
311
312 circleOutlineOutward(pieceRad, PIECE_DEPTH, prd->curveAccuracy);
313 circleOutlineOutward(pieceRad, 0.f, prd->curveAccuracy);
314
315 glDisable(GL_BLEND);
316 glDisable(GL_LINE_SMOOTH);
317 glDepthMask(GL_TRUE);
318
319 if (prd->ChequerMat[0].pTexture && prd->pieceTextureType == PTT_TOP)
320 glEnable(GL_TEXTURE_2D); /* Re-enable texturing */
321 }
322
323 static void
preRenderPiece(GLuint pieceList,const renderdata * prd,int display)324 preRenderPiece(GLuint pieceList, const renderdata * prd, int display)
325 {
326 glNewList(pieceList, GL_COMPILE);
327
328 switch (prd->pieceType) {
329 case PT_ROUNDED:
330 preDrawPiece0(prd, display);
331 break;
332 case PT_FLAT:
333 preDrawPiece1(prd, display);
334 break;
335 default:
336 g_print("Error: Unhandled piece type\n");
337 }
338
339 glEndList();
340 }
341
342 static void
preDrawPiece(BoardData3d * bd3d,renderdata * prd)343 preDrawPiece(BoardData3d * bd3d, renderdata * prd)
344 {
345 unsigned int temp;
346 if (bd3d->pieceList) {
347 glDeleteLists(bd3d->pieceList, 1);
348 glDeleteLists(bd3d->piecePickList, 1);
349 }
350
351 bd3d->pieceList = glGenLists(1);
352 bd3d->piecePickList = glGenLists(1);
353 preRenderPiece(bd3d->pieceList, prd, TRUE);
354
355 /* Simplified piece for picking */
356 temp = prd->curveAccuracy;
357 prd->curveAccuracy = 10;
358 preRenderPiece(bd3d->piecePickList, prd, FALSE);
359 prd->curveAccuracy = temp;
360 }
361
362 static void
UnitNormal(float x,float y,float z)363 UnitNormal(float x, float y, float z)
364 {
365 /* Calculate the length of the vector */
366 float length = sqrtf((x * x) + (y * y) + (z * z));
367
368 /* Dividing each element by the length will result in a unit normal vector */
369 glNormal3f(x / length, y / length, z / length);
370 }
371
372 static void
renderDice(const renderdata * prd)373 renderDice(const renderdata * prd)
374 {
375 unsigned int ns, lns;
376 unsigned int i, j;
377 int c;
378 float lat_angle;
379 float lat_step;
380 float radius;
381 float step = 0;
382 float size = getDiceSize(prd);
383
384 unsigned int corner_steps = (prd->curveAccuracy / 4) + 1;
385 float ***corner_points = Alloc3d(corner_steps, corner_steps, 3);
386
387 radius = size / 2.0f;
388 step = (2 * (float) G_PI) / prd->curveAccuracy;
389
390 glPushMatrix();
391
392 /* Draw 6 faces */
393 for (c = 0; c < 6; c++) {
394 circle(radius, radius, prd->curveAccuracy);
395
396 if (c % 2 == 0)
397 glRotatef(-90.f, 0.f, 1.f, 0.f);
398 else
399 glRotatef(90.f, 1.f, 0.f, 0.f);
400 }
401
402 lat_angle = 0;
403 lns = (prd->curveAccuracy / 4);
404 lat_step = ((float) G_PI / 2) / lns;
405
406 /* Calculate corner points */
407 for (i = 0; i < lns + 1; i++) {
408 float angle = 0.0f;
409
410 ns = (prd->curveAccuracy / 4) - i;
411 if (ns > 0)
412 step = ((float) G_PI / 2 - lat_angle) / (ns);
413
414 for (j = 0; j <= ns; j++) {
415 corner_points[i][j][0] = cosf(lat_angle) * radius;
416 corner_points[i][j][1] = cosf(angle) * radius;
417 corner_points[i][j][2] = sinf(angle + lat_angle) * radius;
418
419 angle += step;
420 }
421 lat_angle += lat_step;
422 }
423
424 /* Draw 8 corners */
425 for (c = 0; c < 8; c++) {
426 glPushMatrix();
427
428 glRotatef((float) c * 90, 0.f, 0.f, 1.f);
429
430 for (i = 0; i < prd->curveAccuracy / 4; i++) {
431 ns = (prd->curveAccuracy / 4) - (i + 1);
432
433 glBegin(GL_TRIANGLE_STRIP);
434 UnitNormal(corner_points[i][0][0], corner_points[i][0][1], corner_points[i][0][2]);
435 glVertex3f(corner_points[i][0][0], corner_points[i][0][1], corner_points[i][0][2]);
436 for (j = 0; j <= ns; j++) {
437 UnitNormal(corner_points[i + 1][j][0], corner_points[i + 1][j][1], corner_points[i + 1][j][2]);
438 glVertex3f(corner_points[i + 1][j][0], corner_points[i + 1][j][1], corner_points[i + 1][j][2]);
439 UnitNormal(corner_points[i][j + 1][0], corner_points[i][j + 1][1], corner_points[i][j + 1][2]);
440 glVertex3f(corner_points[i][j + 1][0], corner_points[i][j + 1][1], corner_points[i][j + 1][2]);
441 }
442 glEnd();
443 }
444
445 glPopMatrix();
446 if (c == 3)
447 glRotatef(180.f, 1.f, 0.f, 0.f);
448 }
449
450 /* Anti-alias dice edges */
451 glLineWidth(1.f);
452 glEnable(GL_LINE_SMOOTH);
453 glEnable(GL_BLEND);
454 glDepthMask(GL_FALSE);
455
456 for (c = 0; c < 6; c++) {
457 circleOutline(radius, radius + LIFT_OFF, prd->curveAccuracy);
458
459 if (c % 2 == 0)
460 glRotatef(-90.f, 0.f, 1.f, 0.f);
461 else
462 glRotatef(90.f, 1.f, 0.f, 0.f);
463 }
464 glDisable(GL_BLEND);
465 glDisable(GL_LINE_SMOOTH);
466 glDepthMask(GL_TRUE);
467
468 glPopMatrix();
469
470 Free3d(corner_points, corner_steps, corner_steps);
471 }
472
473 static void
renderCube(const renderdata * prd,float size)474 renderCube(const renderdata * prd, float size)
475 {
476 int i, c;
477 float ***corner_points;
478 float radius = size / 7.0f;
479 float ds = (size * 5.0f / 7.0f);
480 float hds = (ds / 2);
481
482 glPushMatrix();
483
484 /* Draw 6 faces */
485 for (c = 0; c < 6; c++) {
486 glPushMatrix();
487 glTranslatef(0.f, 0.f, hds + radius);
488
489 glNormal3f(0.f, 0.f, 1.f);
490
491 glBegin(GL_QUADS);
492 glVertex3f(-hds, -hds, 0.f);
493 glVertex3f(hds, -hds, 0.f);
494 glVertex3f(hds, hds, 0.f);
495 glVertex3f(-hds, hds, 0.f);
496 glEnd();
497
498 /* Draw 12 edges */
499 for (i = 0; i < 2; i++) {
500 glPushMatrix();
501 glRotatef((float) i * 90, 0.f, 0.f, 1.f);
502
503 glTranslatef(hds, -hds, -radius);
504 QuarterCylinder(radius, ds, prd->curveAccuracy, 0);
505 glPopMatrix();
506 }
507 glPopMatrix();
508 if (c % 2 == 0)
509 glRotatef(-90.f, 0.f, 1.f, 0.f);
510 else
511 glRotatef(90.f, 1.f, 0.f, 0.f);
512 }
513
514 calculateEigthPoints(&corner_points, radius, prd->curveAccuracy);
515
516 /* Draw 8 corners */
517 for (c = 0; c < 8; c++) {
518 glPushMatrix();
519 glTranslatef(0.f, 0.f, hds + radius);
520
521 glRotatef((float) c * 90, 0.f, 0.f, 1.f);
522
523 glTranslatef(hds, -hds, -radius);
524 glRotatef(-90.f, 0.f, 0.f, 1.f);
525
526 drawCornerEigth(corner_points, radius, prd->curveAccuracy);
527
528 glPopMatrix();
529 if (c == 3)
530 glRotatef(180.f, 1.f, 0.f, 0.f);
531 }
532 glPopMatrix();
533
534 freeEigthPoints(&corner_points, prd->curveAccuracy);
535 }
536
537 static void
preDrawDice(BoardData3d * bd3d,const renderdata * prd)538 preDrawDice(BoardData3d * bd3d, const renderdata * prd)
539 {
540 if (bd3d->diceList)
541 glDeleteLists(bd3d->diceList, 1);
542
543 bd3d->diceList = glGenLists(1);
544 glNewList(bd3d->diceList, GL_COMPILE);
545 renderDice(prd);
546 glEndList();
547
548 if (bd3d->DCList)
549 glDeleteLists(bd3d->DCList, 1);
550
551 bd3d->DCList = glGenLists(1);
552 glNewList(bd3d->DCList, GL_COMPILE);
553 renderCube(prd, DOUBLECUBE_SIZE);
554 glEndList();
555 }
556
557 static void
getDoubleCubePos(const BoardData * bd,float v[3])558 getDoubleCubePos(const BoardData * bd, float v[3])
559 {
560 v[2] = BASE_DEPTH + DOUBLECUBE_SIZE / 2.0f; /* Cube on board most of time */
561
562 if (bd->doubled != 0) {
563 v[0] = TRAY_WIDTH + BOARD_WIDTH / 2;
564 if (bd->doubled != 1)
565 v[0] = TOTAL_WIDTH - v[0];
566
567 v[1] = TOTAL_HEIGHT / 2.0f;
568 } else {
569 if (fClockwise)
570 v[0] = TOTAL_WIDTH - TRAY_WIDTH / 2.0f;
571 else
572 v[0] = TRAY_WIDTH / 2.0f;
573
574 switch (bd->cube_owner) {
575 case 0:
576 v[1] = TOTAL_HEIGHT / 2.0f;
577 v[2] = BASE_DEPTH + EDGE_DEPTH + DOUBLECUBE_SIZE / 2.0f;
578 break;
579 case -1:
580 v[1] = EDGE_HEIGHT + DOUBLECUBE_SIZE / 2.0f;
581 break;
582 case 1:
583 v[1] = (TOTAL_HEIGHT - EDGE_HEIGHT) - DOUBLECUBE_SIZE / 2.0f;
584 break;
585 default:
586 v[1] = 0; /* error */
587 }
588 }
589 }
590
591 static void
moveToDoubleCubePos(const BoardData * bd)592 moveToDoubleCubePos(const BoardData * bd)
593 {
594 float v[3];
595 getDoubleCubePos(bd, v);
596 glTranslatef(v[0], v[1], v[2]);
597 }
598
599 NTH_STATIC void
drawDCNumbers(const BoardData * bd,const diceTest * dt)600 drawDCNumbers(const BoardData * bd, const diceTest * dt)
601 {
602 int c;
603 float radius = DOUBLECUBE_SIZE / 7.0f;
604 float ds = (DOUBLECUBE_SIZE * 5.0f / 7.0f);
605 float hds = (ds / 2);
606 float depth = hds + radius;
607
608 const char *sides[] = { "4", "16", "32", "64", "8", "2" };
609 int side;
610
611 glLineWidth(.5f);
612 glPushMatrix();
613 for (c = 0; c < 6; c++) {
614 int nice;
615
616 if (c < 3)
617 side = c;
618 else
619 side = 8 - c;
620 /* Nicer top numbers */
621 nice = (side == dt->top);
622
623 /* Don't draw bottom number or back number (unless cube at bottom) */
624 if (side != dt->bottom && !(side == dt->side[0] && bd->cube_owner != -1)) {
625 if (nice)
626 glDisable(GL_DEPTH_TEST);
627
628 glPushMatrix();
629 glTranslatef(0.f, 0.f, depth + (nice ? 0 : LIFT_OFF));
630
631 glPrintCube(bd->bd3d->cubeFont, sides[side]);
632
633 glPopMatrix();
634 if (nice)
635 glEnable(GL_DEPTH_TEST);
636 }
637 if (c % 2 == 0)
638 glRotatef(-90.f, 0.f, 1.f, 0.f);
639 else
640 glRotatef(90.f, 1.f, 0.f, 0.f);
641 }
642 glPopMatrix();
643 }
644
645 static void
DrawDCNumbers(const BoardData * bd)646 DrawDCNumbers(const BoardData * bd)
647 {
648 diceTest dt;
649 int extraRot = 0;
650 int rotDC[6][3] = { {1, 0, 0}, {2, 0, 3}, {0, 0, 0}, {0, 3, 1}, {0, 1, 0}, {3, 0, 3} };
651
652 int cubeIndex;
653 /* Rotate to correct number + rotation */
654 if (!bd->doubled) {
655 cubeIndex = LogCube(bd->cube);
656 extraRot = bd->cube_owner + 1;
657 } else {
658 cubeIndex = LogCube(bd->cube * 2); /* Show offered cube value */
659 extraRot = bd->turn + 1;
660 }
661
662 glRotatef((rotDC[cubeIndex][2] + extraRot) * 90.0f, 0.f, 0.f, 1.f);
663 glRotatef(rotDC[cubeIndex][0] * 90.0f, 1.f, 0.f, 0.f);
664 glRotatef(rotDC[cubeIndex][1] * 90.0f, 0.f, 1.f, 0.f);
665
666 initDT(&dt, rotDC[cubeIndex][0], rotDC[cubeIndex][1], rotDC[cubeIndex][2] + extraRot);
667
668 setMaterial(&bd->rd->CubeNumberMat);
669 glNormal3f(0.f, 0.f, 1.f);
670
671 drawDCNumbers(bd, &dt);
672 }
673
674 NTH_STATIC void
drawDC(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)675 drawDC(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
676 {
677 glPushMatrix();
678 moveToDoubleCubePos(bd);
679
680 setMaterial(&prd->CubeMat);
681 glCallList(bd3d->DCList);
682
683 DrawDCNumbers(bd);
684
685 glPopMatrix();
686 }
687
688 /* Define position of dots on dice */
689 static int dots1[] = { 2, 2, 0 };
690 static int dots2[] = { 1, 1, 3, 3, 0 };
691 static int dots3[] = { 1, 3, 2, 2, 3, 1, 0 };
692 static int dots4[] = { 1, 1, 1, 3, 3, 1, 3, 3, 0 };
693 static int dots5[] = { 1, 1, 1, 3, 2, 2, 3, 1, 3, 3, 0 };
694 static int dots6[] = { 1, 1, 1, 3, 2, 1, 2, 3, 3, 1, 3, 3, 0 };
695 static int *dots[6] = { dots1, dots2, dots3, dots4, dots5, dots6 };
696 static int dot_pos[] = { 0, 20, 50, 80 }; /* percentages across face */
697
698 static void
drawDots(const BoardData3d * bd3d,float diceSize,float dotOffset,const diceTest * dt,int showFront)699 drawDots(const BoardData3d * bd3d, float diceSize, float dotOffset, const diceTest * dt, int showFront)
700 {
701 int dot;
702 int c;
703 int *dp;
704 float radius;
705 float ds = (diceSize * 5.0f / 7.0f);
706 float hds = (ds / 2);
707 float x, y;
708 float dotSize = diceSize / 10.0f;
709 /* Remove specular effects */
710 float zero[4] = { 0, 0, 0, 0 };
711 glMaterialfv(GL_FRONT, GL_SPECULAR, zero);
712
713 radius = diceSize / 7.0f;
714
715 glPushMatrix();
716 for (c = 0; c < 6; c++) {
717 int nd;
718
719 if (c < 3)
720 dot = c;
721 else
722 dot = 8 - c;
723
724 /* Make sure top dot looks nice */
725 nd = !bd3d->shakingDice && (dot == dt->top);
726
727 if (bd3d->shakingDice || (showFront && dot != dt->bottom && dot != dt->side[0])
728 || (!showFront && dot != dt->top && dot != dt->side[2])) {
729 if (nd)
730 glDisable(GL_DEPTH_TEST);
731 glPushMatrix();
732 glTranslatef(0.f, 0.f, hds + radius);
733
734 glNormal3f(0.f, 0.f, 1.f);
735
736 /* Show all the dots for this number */
737 dp = dots[dot];
738 do {
739 x = (dot_pos[dp[0]] * ds) / 100;
740 y = (dot_pos[dp[1]] * ds) / 100;
741
742 glPushMatrix();
743 glTranslatef(x - hds, y - hds, 0.f);
744
745 glEnable(GL_TEXTURE_2D);
746 glBindTexture(GL_TEXTURE_2D, bd3d->dotTexture);
747
748 glBegin(GL_QUADS);
749 glTexCoord2f(0.f, 1.f);
750 glVertex3f(dotSize, dotSize, dotOffset);
751 glTexCoord2f(1.f, 1.f);
752 glVertex3f(-dotSize, dotSize, dotOffset);
753 glTexCoord2f(1.f, 0.f);
754 glVertex3f(-dotSize, -dotSize, dotOffset);
755 glTexCoord2f(0.f, 0.f);
756 glVertex3f(dotSize, -dotSize, dotOffset);
757 glEnd();
758
759 glPopMatrix();
760
761 dp += 2;
762 } while (*dp);
763
764 glPopMatrix();
765 if (nd)
766 glEnable(GL_DEPTH_TEST);
767 }
768
769 if (c % 2 == 0)
770 glRotatef(-90.f, 0.f, 1.f, 0.f);
771 else
772 glRotatef(90.f, 1.f, 0.f, 0.f);
773 }
774 glPopMatrix();
775 }
776
777 static void
getDicePos(const BoardData * bd,int num,float v[3])778 getDicePos(const BoardData * bd, int num, float v[3])
779 {
780 float size = getDiceSize(bd->rd);
781 if (bd->diceShown == DICE_BELOW_BOARD) { /* Show below board */
782 v[0] = size * 1.5f;
783 v[1] = -size / 2.0f;
784 v[2] = size / 2.0f;
785
786 if (bd->turn == 1)
787 v[0] += TOTAL_WIDTH - size * 4;
788 if (num == 1)
789 v[0] += size; /* Place 2nd dice by 1st */
790 } else {
791 v[0] = bd->bd3d->dicePos[num][0];
792 if (bd->turn == 1)
793 v[0] = TOTAL_WIDTH - v[0]; /* Dice on right side */
794
795 v[1] = (TOTAL_HEIGHT - DICE_AREA_HEIGHT) / 2.0f + bd->bd3d->dicePos[num][1];
796 v[2] = BASE_DEPTH + LIFT_OFF + size / 2.0f;
797 }
798 }
799
800 static void
moveToDicePos(const BoardData * bd,int num)801 moveToDicePos(const BoardData * bd, int num)
802 {
803 float v[3];
804 getDicePos(bd, num, v);
805 glTranslatef(v[0], v[1], v[2]);
806
807 if (bd->diceShown == DICE_ON_BOARD) { /* Spin dice to required rotation if on board */
808 glRotatef(bd->bd3d->dicePos[num][2], 0.f, 0.f, 1.f);
809 }
810 }
811
812 NTH_STATIC void
drawDice(const BoardData * bd,int num)813 drawDice(const BoardData * bd, int num)
814 {
815 unsigned int value;
816 int rotDice[6][2] = { {0, 0}, {0, 1}, {3, 0}, {1, 0}, {0, 3}, {2, 0} };
817 int diceCol = (bd->turn == 1);
818 int z;
819 float diceSize = getDiceSize(bd->rd);
820 diceTest dt;
821 Material *pDiceMat = &bd->rd->DiceMat[diceCol];
822 Material whiteMat;
823 SetupSimpleMat(&whiteMat, 1.f, 1.f, 1.f);
824
825 value = bd->diceRoll[num];
826
827 /* During program startup value may be zero, if so don't draw */
828 if (!value)
829 return;
830 value--; /* Zero based for array access */
831
832 /* Get dice rotation */
833 if (bd->diceShown == DICE_BELOW_BOARD)
834 z = 0;
835 else
836 z = ((int) bd->bd3d->dicePos[num][2] + 45) / 90;
837
838 /* Orientate dice correctly */
839 glRotatef(90.0f * rotDice[value][0], 1.f, 0.f, 0.f);
840 glRotatef(90.0f * rotDice[value][1], 0.f, 1.f, 0.f);
841
842 /* DT = dice test, use to work out which way up the dice is */
843 initDT(&dt, rotDice[value][0], rotDice[value][1], z);
844
845 if (pDiceMat->alphaBlend) { /* Draw back of dice separately */
846 glCullFace(GL_FRONT);
847 glEnable(GL_BLEND);
848
849 /* Draw dice */
850 setMaterial(pDiceMat);
851 glCallList(bd->bd3d->diceList);
852
853 /* Place back dots inside dice */
854 setMaterial(&bd->rd->DiceDotMat[diceCol]);
855 glEnable(GL_BLEND); /* NB. Disabled in diceList */
856 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
857 drawDots(bd->bd3d, diceSize, -LIFT_OFF, &dt, 0);
858 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
859
860 glCullFace(GL_BACK);
861 }
862 /* Draw dice */
863 setMaterial(&bd->rd->DiceMat[diceCol]);
864 glCallList(bd->bd3d->diceList);
865
866 /* Draw (front) dots */
867 glEnable(GL_BLEND);
868 /* First blank out space for dots */
869 setMaterial(&whiteMat);
870 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
871 drawDots(bd->bd3d, diceSize, LIFT_OFF, &dt, 1);
872
873 /* Now fill space with coloured dots */
874 setMaterial(&bd->rd->DiceDotMat[diceCol]);
875 glBlendFunc(GL_ONE, GL_ONE);
876 drawDots(bd->bd3d, diceSize, LIFT_OFF, &dt, 1);
877
878 /* Restore blending defaults */
879 glDisable(GL_BLEND);
880 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
881 }
882
883 void
getPiecePos(unsigned int point,unsigned int pos,float v[3])884 getPiecePos(unsigned int point, unsigned int pos, float v[3])
885 {
886 if (point == 0 || point == 25) { /* bars */
887 v[0] = TOTAL_WIDTH / 2.0f;
888 v[1] = TOTAL_HEIGHT / 2.0f;
889 v[2] = BASE_DEPTH + EDGE_DEPTH + (int) ((pos - 1) / 3) * PIECE_DEPTH;
890 pos = ((pos - 1) % 3) + 1;
891
892 if (point == 25) {
893 v[1] += DOUBLECUBE_SIZE / 2.0f + (PIECE_HOLE + PIECE_GAP_HEIGHT) * (pos + .5f);
894 } else {
895 v[1] -= DOUBLECUBE_SIZE / 2.0f + (PIECE_HOLE + PIECE_GAP_HEIGHT) * (pos + .5f);
896 }
897 v[1] -= PIECE_HOLE / 2.0f;
898 } else if (point >= 26) { /* homes */
899 v[2] = BASE_DEPTH;
900 if (fClockwise)
901 v[0] = TRAY_WIDTH / 2.0f;
902 else
903 v[0] = TOTAL_WIDTH - TRAY_WIDTH / 2.0f;
904
905 if (point == 26)
906 v[1] = EDGE_HEIGHT + (PIECE_DEPTH * 1.2f * (pos - 1)); /* 1.3 gives a gap between pieces */
907 else
908 v[1] = TOTAL_HEIGHT - EDGE_HEIGHT - PIECE_DEPTH - (PIECE_DEPTH * 1.2f * (pos - 1));
909 } else {
910 v[2] = BASE_DEPTH + (int) ((pos - 1) / 5) * PIECE_DEPTH;
911
912 if (point < 13) {
913 if (fClockwise)
914 point = 13 - point;
915
916 if (pos > 10)
917 pos -= 10;
918
919 if (pos > 5)
920 v[1] = EDGE_HEIGHT + (PIECE_HOLE / 2.0f) + (PIECE_HOLE + PIECE_GAP_HEIGHT) * (pos - 5 - 1);
921 else
922 v[1] = EDGE_HEIGHT + (PIECE_HOLE + PIECE_GAP_HEIGHT) * (pos - 1);
923
924 v[0] = TRAY_WIDTH + PIECE_HOLE * (12 - point);
925 if (point < 7)
926 v[0] += BAR_WIDTH;
927 } else {
928 if (fClockwise)
929 point = (24 + 13) - point;
930
931 if (pos > 10)
932 pos -= 10;
933
934 if (pos > 5)
935 v[1] =
936 TOTAL_HEIGHT - EDGE_HEIGHT - (PIECE_HOLE / 2.0f) - PIECE_HOLE - (PIECE_HOLE +
937 PIECE_GAP_HEIGHT) * (pos - 5 - 1);
938 else
939 v[1] = TOTAL_HEIGHT - EDGE_HEIGHT - PIECE_HOLE - (PIECE_HOLE + PIECE_GAP_HEIGHT) * (pos - 1);
940
941 v[0] = TRAY_WIDTH + PIECE_HOLE * (point - 13);
942 if (point > 18)
943 v[0] += BAR_WIDTH;
944 }
945 v[0] += PIECE_HOLE / 2.0f;
946 }
947 v[2] += LIFT_OFF * 2;
948
949 /* Move to centre of piece */
950 if (point < 26) {
951 v[1] += PIECE_HOLE / 2.0f;
952 } else { /* Home pieces are sideways */
953 if (point == 27)
954 v[1] += PIECE_DEPTH;
955 v[2] += PIECE_HOLE / 2.0f;
956 }
957 }
958
959 static void
renderSpecialPieces(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)960 renderSpecialPieces(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
961 {
962 if (bd->drag_point >= 0) {
963 glPushMatrix();
964 glTranslatef(bd3d->dragPos[0], bd3d->dragPos[1], bd3d->dragPos[2]);
965 glRotatef((float) bd3d->movingPieceRotation, 0.f, 0.f, 1.f);
966 setMaterial(&prd->ChequerMat[(bd->drag_colour == 1) ? 1 : 0]);
967 glCallList(bd3d->pieceList);
968 glPopMatrix();
969 }
970
971 if (bd3d->moving) {
972 glPushMatrix();
973 glTranslatef(bd3d->movingPos[0], bd3d->movingPos[1], bd3d->movingPos[2]);
974 if (bd3d->rotateMovingPiece > 0)
975 glRotatef(-90 * bd3d->rotateMovingPiece * bd->turn, 1.f, 0.f, 0.f);
976 glRotatef((float) bd3d->movingPieceRotation, 0.f, 0.f, 1.f);
977 setMaterial(&prd->ChequerMat[(bd->turn == 1) ? 1 : 0]);
978 glCallList(bd3d->pieceList);
979 glPopMatrix();
980 }
981 }
982
983 static void
drawSpecialPieces(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)984 drawSpecialPieces(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
985 { /* Draw animated or dragged pieces */
986 int blend = (prd->ChequerMat[0].alphaBlend) || (prd->ChequerMat[1].alphaBlend);
987
988 if (blend) { /* Draw back of piece separately */
989 glCullFace(GL_FRONT);
990 glEnable(GL_BLEND);
991 renderSpecialPieces(bd, bd3d, prd);
992 glCullFace(GL_BACK);
993 glEnable(GL_BLEND);
994 }
995 renderSpecialPieces(bd, bd3d, prd);
996
997 if (blend)
998 glDisable(GL_BLEND);
999 }
1000
1001 static void
drawPieceSimplified(GLuint UNUSED (pieceList),const BoardData3d * UNUSED (bd3d),unsigned int point,unsigned int pos)1002 drawPieceSimplified(GLuint UNUSED(pieceList), const BoardData3d * UNUSED(bd3d), unsigned int point, unsigned int pos)
1003 {
1004 float v[3];
1005 glPushMatrix();
1006
1007 getPiecePos(point, pos, v);
1008 drawBox(BOX_ALL, v[0] - PIECE_HOLE / 2.f, v[1] - PIECE_HOLE / 2.f, v[2] - PIECE_DEPTH / 2.f, PIECE_HOLE, PIECE_HOLE,
1009 PIECE_DEPTH, NULL);
1010
1011 glPopMatrix();
1012 }
1013
1014 static void
drawPiece(GLuint pieceList,const BoardData3d * bd3d,unsigned int point,unsigned int pos,int rotate)1015 drawPiece(GLuint pieceList, const BoardData3d * bd3d, unsigned int point, unsigned int pos, int rotate)
1016 {
1017 float v[3];
1018 glPushMatrix();
1019
1020 getPiecePos(point, pos, v);
1021 glTranslatef(v[0], v[1], v[2]);
1022
1023 /* Home pieces are sideways */
1024 if (point == 26)
1025 glRotatef(-90.f, 1.f, 0.f, 0.f);
1026 if (point == 27)
1027 glRotatef(90.f, 1.f, 0.f, 0.f);
1028
1029 if (rotate)
1030 glRotatef((float) bd3d->pieceRotation[point][pos - 1], 0.f, 0.f, 1.f);
1031 glCallList(pieceList);
1032
1033 glPopMatrix();
1034 }
1035
1036 NTH_STATIC void
drawPieces(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)1037 drawPieces(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
1038 {
1039 unsigned int i;
1040 unsigned int j;
1041 int blend = (prd->ChequerMat[0].alphaBlend) || (prd->ChequerMat[1].alphaBlend);
1042
1043 if (blend) { /* Draw back of piece separately */
1044 glCullFace(GL_FRONT);
1045
1046 setMaterial(&prd->ChequerMat[0]);
1047 for (i = 0; i < 28; i++) {
1048 if (bd->points[i] < 0) {
1049 unsigned int numPieces = (unsigned int) (-bd->points[i]);
1050 for (j = 1; j <= numPieces; j++) {
1051 glEnable(GL_BLEND);
1052 drawPiece(bd3d->pieceList, bd3d, i, j, TRUE);
1053 }
1054 }
1055 }
1056 setMaterial(&prd->ChequerMat[1]);
1057 for (i = 0; i < 28; i++) {
1058 if (bd->points[i] > 0) {
1059 unsigned int numPieces = (unsigned int) bd->points[i];
1060 for (j = 1; j <= numPieces; j++) {
1061 glEnable(GL_BLEND);
1062 drawPiece(bd3d->pieceList, bd3d, i, j, TRUE);
1063 }
1064 }
1065 }
1066 glCullFace(GL_BACK);
1067 }
1068
1069 setMaterial(&prd->ChequerMat[0]);
1070 for (i = 0; i < 28; i++) {
1071 if (bd->points[i] < 0) {
1072 unsigned int numPieces = (unsigned int) (-bd->points[i]);
1073 for (j = 1; j <= numPieces; j++) {
1074 if (blend)
1075 glEnable(GL_BLEND);
1076 drawPiece(bd3d->pieceList, bd3d, i, j, TRUE);
1077 }
1078 }
1079 }
1080 setMaterial(&prd->ChequerMat[1]);
1081 for (i = 0; i < 28; i++) {
1082 if (bd->points[i] > 0) {
1083 unsigned int numPieces = (unsigned int) bd->points[i];
1084 for (j = 1; j <= numPieces; j++) {
1085 if (blend)
1086 glEnable(GL_BLEND);
1087 drawPiece(bd3d->pieceList, bd3d, i, j, TRUE);
1088 }
1089 }
1090 }
1091 if (blend)
1092 glDisable(GL_BLEND);
1093
1094 if (bd->DragTargetHelp) { /* highlight target points */
1095 glPolygonMode(GL_FRONT, GL_LINE);
1096 SetColour3d(0.f, 1.f, 0.f, 0.f); /* Nice bright green... */
1097
1098 for (i = 0; i <= 3; i++) {
1099 int target = bd->iTargetHelpPoints[i];
1100 if (target != -1) { /* Make sure texturing is disabled */
1101 if (prd->ChequerMat[0].pTexture)
1102 glDisable(GL_TEXTURE_2D);
1103 drawPiece(bd3d->pieceList, bd3d, (unsigned int) target, Abs(bd->points[target]) + 1, TRUE);
1104 }
1105 }
1106 glPolygonMode(GL_FRONT, GL_FILL);
1107 }
1108 }
1109
1110 static void
DrawNumbers(const BoardData * bd,unsigned int sides)1111 DrawNumbers(const BoardData * bd, unsigned int sides)
1112 {
1113 int i;
1114 char num[3];
1115 float x;
1116 float textHeight = GetFontHeight3d(bd->bd3d->numberFont);
1117 int n;
1118
1119 glPushMatrix();
1120 glTranslatef(0.f, (EDGE_HEIGHT - textHeight) / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1121 x = TRAY_WIDTH - PIECE_HOLE / 2.0f;
1122
1123 for (i = 0; i < 12; i++) {
1124 x += PIECE_HOLE;
1125 if (i == 6)
1126 x += BAR_WIDTH;
1127
1128 if ((i < 6 && (sides & 1)) || (i >= 6 && (sides & 2))) {
1129 glPushMatrix();
1130 glTranslatef(x, 0.f, 0.f);
1131 if (!fClockwise)
1132 n = 12 - i;
1133 else
1134 n = i + 1;
1135
1136 if (bd->turn == -1 && bd->rd->fDynamicLabels)
1137 n = 25 - n;
1138
1139 sprintf(num, "%d", n);
1140 glPrintPointNumbers(bd->bd3d->numberFont, num);
1141 glPopMatrix();
1142 }
1143 }
1144
1145 glPopMatrix();
1146 glPushMatrix();
1147 glTranslatef(0.f, TOTAL_HEIGHT - textHeight - (EDGE_HEIGHT - textHeight) / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1148 x = TRAY_WIDTH - PIECE_HOLE / 2.0f;
1149
1150 for (i = 0; i < 12; i++) {
1151 x += PIECE_HOLE;
1152 if (i == 6)
1153 x += BAR_WIDTH;
1154 if ((i < 6 && (sides & 1)) || (i >= 6 && (sides & 2))) {
1155 glPushMatrix();
1156 glTranslatef(x, 0.f, 0.f);
1157 if (!fClockwise)
1158 n = 13 + i;
1159 else
1160 n = 24 - i;
1161
1162 if (bd->turn == -1 && bd->rd->fDynamicLabels)
1163 n = 25 - n;
1164
1165 sprintf(num, "%d", n);
1166 glPrintPointNumbers(bd->bd3d->numberFont, num);
1167 glPopMatrix();
1168 }
1169 }
1170 glPopMatrix();
1171 }
1172
1173 static void
drawNumbers(const BoardData * bd)1174 drawNumbers(const BoardData * bd)
1175 {
1176 /* No need to depth test as on top of board (depth test could cause alias problems too) */
1177 glDisable(GL_DEPTH_TEST);
1178 /* Draw inside then anti-aliased outline of numbers */
1179 setMaterial(&bd->rd->PointNumberMat);
1180 glNormal3f(0.f, 0.f, 1.f);
1181
1182 glLineWidth(1.f);
1183 DrawNumbers(bd, 1);
1184 DrawNumbers(bd, 2);
1185 glEnable(GL_DEPTH_TEST);
1186 }
1187
1188 static void
drawPoint(const renderdata * prd,float tuv,unsigned int i,int p,int outline)1189 drawPoint(const renderdata * prd, float tuv, unsigned int i, int p, int outline)
1190 { /* Draw point with correct texture co-ords */
1191 float w = PIECE_HOLE;
1192 float h = POINT_HEIGHT;
1193 float x, y;
1194
1195 if (p) {
1196 x = TRAY_WIDTH - EDGE_WIDTH + PIECE_HOLE * i;
1197 y = -LIFT_OFF;
1198 } else {
1199 x = TRAY_WIDTH - EDGE_WIDTH + BOARD_WIDTH - (PIECE_HOLE * i);
1200 y = TOTAL_HEIGHT - EDGE_HEIGHT * 2 + LIFT_OFF;
1201 w = -w;
1202 h = -h;
1203 }
1204
1205 glPushMatrix();
1206 if (prd->bgInTrays)
1207 glTranslatef(EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH);
1208 else {
1209 x -= TRAY_WIDTH - EDGE_WIDTH;
1210 glTranslatef(TRAY_WIDTH, EDGE_HEIGHT, BASE_DEPTH);
1211 }
1212
1213 if (prd->roundedPoints) { /* Draw rounded point ends */
1214 float xoff;
1215
1216 w = w * TAKI_WIDTH;
1217 y += w / 2.0f;
1218 h -= w / 2.0f;
1219
1220 if (p)
1221 xoff = x + (PIECE_HOLE / 2.0f);
1222 else
1223 xoff = x - (PIECE_HOLE / 2.0f);
1224
1225 /* Draw rounded semi-circle end of point (with correct texture co-ords) */
1226 {
1227 unsigned int j;
1228 float angle, step;
1229 float radius = w / 2.0f;
1230
1231 step = (2 * (float) G_PI) / prd->curveAccuracy;
1232 angle = -step * (int) (prd->curveAccuracy / 4);
1233 glNormal3f(0.f, 0.f, 1.f);
1234 glBegin(outline ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
1235 glTexCoord2f(xoff * tuv, y * tuv);
1236
1237 glVertex3f(xoff, y, 0.f);
1238 for (j = 0; j <= prd->curveAccuracy / 2; j++) {
1239 glTexCoord2f((xoff + sinf(angle) * radius) * tuv, (y + cosf(angle) * radius) * tuv);
1240 glVertex3f(xoff + sinf(angle) * radius, y + cosf(angle) * radius, 0.f);
1241 angle -= step;
1242 }
1243 glEnd();
1244 }
1245 /* Move rest of point in slighlty */
1246 if (p)
1247 x -= -((PIECE_HOLE * (1 - TAKI_WIDTH)) / 2.0f);
1248 else
1249 x -= ((PIECE_HOLE * (1 - TAKI_WIDTH)) / 2.0f);
1250 }
1251
1252 glBegin(outline ? GL_LINE_STRIP : GL_TRIANGLES);
1253 glNormal3f(0.f, 0.f, 1.f);
1254 glTexCoord2f((x + w) * tuv, y * tuv);
1255 glVertex3f(x + w, y, 0.f);
1256 glTexCoord2f((x + w / 2) * tuv, (y + h) * tuv);
1257 glVertex3f(x + w / 2, y + h, 0.f);
1258 glTexCoord2f(x * tuv, y * tuv);
1259 glVertex3f(x, y, 0.f);
1260 glEnd();
1261
1262 glPopMatrix();
1263 }
1264
1265 static void
drawPoints(const renderdata * prd)1266 drawPoints(const renderdata * prd)
1267 {
1268 /* texture unit value */
1269 float tuv;
1270
1271 /* Don't worry about depth testing (but set depth values) */
1272 glDepthFunc(GL_ALWAYS);
1273
1274 setMaterial(&prd->BaseMat);
1275 if (prd->bgInTrays)
1276 drawChequeredRect(EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH, BOARD_WIDTH + TRAY_WIDTH - EDGE_WIDTH,
1277 TOTAL_HEIGHT - EDGE_HEIGHT * 2, prd->acrossCheq, prd->downCheq, prd->BaseMat.pTexture);
1278 else
1279 drawChequeredRect(TRAY_WIDTH, EDGE_HEIGHT, BASE_DEPTH, BOARD_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT * 2,
1280 prd->acrossCheq, prd->downCheq, prd->BaseMat.pTexture);
1281
1282 /* Ignore depth values when drawing points */
1283 glDepthMask(GL_FALSE);
1284
1285 if (prd->PointMat[0].pTexture)
1286 tuv = (TEXTURE_SCALE) / prd->PointMat[0].pTexture->width;
1287 else
1288 tuv = 0;
1289 setMaterial(&prd->PointMat[0]);
1290 drawPoint(prd, tuv, 0, 0, 0);
1291 drawPoint(prd, tuv, 0, 1, 0);
1292 drawPoint(prd, tuv, 2, 0, 0);
1293 drawPoint(prd, tuv, 2, 1, 0);
1294 drawPoint(prd, tuv, 4, 0, 0);
1295 drawPoint(prd, tuv, 4, 1, 0);
1296
1297 glLineWidth(1.f);
1298 glEnable(GL_LINE_SMOOTH);
1299 glEnable(GL_BLEND);
1300
1301 drawPoint(prd, tuv, 0, 0, 1);
1302 drawPoint(prd, tuv, 0, 1, 1);
1303 drawPoint(prd, tuv, 2, 0, 1);
1304 drawPoint(prd, tuv, 2, 1, 1);
1305 drawPoint(prd, tuv, 4, 0, 1);
1306 drawPoint(prd, tuv, 4, 1, 1);
1307
1308 glDisable(GL_BLEND);
1309 glDisable(GL_LINE_SMOOTH);
1310
1311 if (prd->PointMat[1].pTexture)
1312 tuv = (TEXTURE_SCALE) / prd->PointMat[1].pTexture->width;
1313 else
1314 tuv = 0;
1315 setMaterial(&prd->PointMat[1]);
1316 drawPoint(prd, tuv, 1, 0, 0);
1317 drawPoint(prd, tuv, 1, 1, 0);
1318 drawPoint(prd, tuv, 3, 0, 0);
1319 drawPoint(prd, tuv, 3, 1, 0);
1320 drawPoint(prd, tuv, 5, 0, 0);
1321 drawPoint(prd, tuv, 5, 1, 0);
1322
1323 glEnable(GL_LINE_SMOOTH);
1324 glEnable(GL_BLEND);
1325
1326 drawPoint(prd, tuv, 1, 0, 1);
1327 drawPoint(prd, tuv, 1, 1, 1);
1328 drawPoint(prd, tuv, 3, 0, 1);
1329 drawPoint(prd, tuv, 3, 1, 1);
1330 drawPoint(prd, tuv, 5, 0, 1);
1331 drawPoint(prd, tuv, 5, 1, 1);
1332
1333 glDisable(GL_BLEND);
1334 glDisable(GL_LINE_SMOOTH);
1335
1336 /* Restore depth buffer settings */
1337 glDepthFunc(GL_LEQUAL);
1338 glDepthMask(GL_TRUE);
1339 }
1340
1341 static void
drawBase(const renderdata * prd,int sides)1342 drawBase(const renderdata * prd, int sides)
1343 {
1344 if (sides & 1)
1345 drawPoints(prd);
1346
1347 if (sides & 2) {
1348 /* Rotate right board around */
1349 glPushMatrix();
1350 glTranslatef(TOTAL_WIDTH, TOTAL_HEIGHT, 0.f);
1351 glRotatef(180.f, 0.f, 0.f, 1.f);
1352 drawPoints(prd);
1353 glPopMatrix();
1354 }
1355 }
1356
1357 static void
drawHinge(const BoardData3d * bd3d,const renderdata * prd,float height)1358 drawHinge(const BoardData3d * bd3d, const renderdata * prd, float height)
1359 {
1360 setMaterial(&prd->HingeMat);
1361
1362 glMatrixMode(GL_TEXTURE);
1363 glPushMatrix();
1364 glScalef(1.f, HINGE_SEGMENTS, 1.f);
1365 glMatrixMode(GL_MODELVIEW);
1366
1367 glPushMatrix();
1368 glTranslatef((TOTAL_WIDTH) / 2.0f, height, BASE_DEPTH + EDGE_DEPTH);
1369 glRotatef(-90.f, 1.f, 0.f, 0.f);
1370 gluCylinder(bd3d->qobjTex, (double) HINGE_WIDTH, (double) HINGE_WIDTH, (double) HINGE_HEIGHT,
1371 (GLint) prd->curveAccuracy, 1);
1372
1373 glMatrixMode(GL_TEXTURE);
1374 glPopMatrix();
1375 glMatrixMode(GL_MODELVIEW);
1376
1377 glRotatef(180.f, 1.f, 0.f, 0.f);
1378 gluDisk(bd3d->qobjTex, 0., (double) HINGE_WIDTH, (GLint) prd->curveAccuracy, 1);
1379
1380 glPopMatrix();
1381 }
1382
1383 NTH_STATIC void
tidyEdges(const renderdata * prd)1384 tidyEdges(const renderdata * prd)
1385 { /* Anti-alias board edges */
1386 setMaterial(&prd->BoxMat);
1387
1388 glLineWidth(1.f);
1389 glEnable(GL_BLEND);
1390 glEnable(GL_LINE_SMOOTH);
1391 glDepthMask(GL_FALSE);
1392
1393 glNormal3f(0.f, 0.f, 1.f);
1394
1395 glBegin(GL_LINES);
1396 if (prd->roundedEdges) {
1397 /* bar */
1398 glNormal3f(-1.f, 0.f, 0.f);
1399 glVertex3f(TRAY_WIDTH + BOARD_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1400 glVertex3f(TRAY_WIDTH + BOARD_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1401
1402 glNormal3f(1.f, 0.f, 0.f);
1403 glVertex3f(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1404 glVertex3f(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT,
1405 BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1406
1407 /* left bear off tray */
1408 glNormal3f(-1.f, 0.f, 0.f);
1409 glVertex3f(0.f, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1410 glVertex3f(0.f, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1411
1412 glVertex3f(TRAY_WIDTH - EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1413 glVertex3f(TRAY_WIDTH - EDGE_WIDTH, TRAY_HEIGHT, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1414 glVertex3f(TRAY_WIDTH - EDGE_WIDTH, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1415 glVertex3f(TRAY_WIDTH - EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1416
1417 /* right bear off tray */
1418 glNormal3f(1.f, 0.f, 0.f);
1419 glVertex3f(TOTAL_WIDTH, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1420 glVertex3f(TOTAL_WIDTH, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1421
1422 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1423 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, TRAY_HEIGHT, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1424 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT,
1425 BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1426 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT,
1427 BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1428
1429 } else {
1430 /* bar */
1431 glVertex3f(TRAY_WIDTH + BOARD_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1432 glVertex3f(TRAY_WIDTH + BOARD_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1433
1434 glVertex3f(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1435 glVertex3f(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1436
1437 /* left bear off tray */
1438 glVertex3f(0.f, 0.f, BASE_DEPTH + EDGE_DEPTH);
1439 glVertex3f(0.f, TOTAL_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1440
1441 glVertex3f(EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1442 glVertex3f(EDGE_WIDTH, TRAY_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1443 glVertex3f(EDGE_WIDTH, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1444 glVertex3f(EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1445
1446 glVertex3f(TRAY_WIDTH - EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1447 glVertex3f(TRAY_WIDTH - EDGE_WIDTH, TRAY_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1448 glVertex3f(TRAY_WIDTH - EDGE_WIDTH, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1449 glVertex3f(TRAY_WIDTH - EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1450
1451 glVertex3f(TRAY_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1452 glVertex3f(TRAY_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1453
1454 /* right bear off tray */
1455 glVertex3f(TOTAL_WIDTH, 0.f, BASE_DEPTH + EDGE_DEPTH);
1456 glVertex3f(TOTAL_WIDTH, TOTAL_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1457
1458 glVertex3f(TOTAL_WIDTH - EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1459 glVertex3f(TOTAL_WIDTH - EDGE_WIDTH, TRAY_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1460 glVertex3f(TOTAL_WIDTH - EDGE_WIDTH, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1461 glVertex3f(TOTAL_WIDTH - EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1462
1463 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1464 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, TRAY_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1465 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1466 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1467
1468 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1469 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1470 }
1471
1472 /* inner edges (sides) */
1473 glNormal3f(1.f, 0.f, 0.f);
1474 glVertex3f(EDGE_WIDTH + LIFT_OFF, EDGE_HEIGHT, BASE_DEPTH + LIFT_OFF);
1475 glVertex3f(EDGE_WIDTH + LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + LIFT_OFF);
1476 glVertex3f(TRAY_WIDTH + LIFT_OFF, EDGE_HEIGHT, BASE_DEPTH + LIFT_OFF);
1477 glVertex3f(TRAY_WIDTH + LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + LIFT_OFF);
1478
1479 glNormal3f(-1.f, 0.f, 0.f);
1480 glVertex3f(TOTAL_WIDTH - EDGE_WIDTH + LIFT_OFF, EDGE_HEIGHT, BASE_DEPTH + LIFT_OFF);
1481 glVertex3f(TOTAL_WIDTH - EDGE_WIDTH + LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + LIFT_OFF);
1482 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + LIFT_OFF, EDGE_HEIGHT, BASE_DEPTH + LIFT_OFF);
1483 glVertex3f(TOTAL_WIDTH - TRAY_WIDTH + LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH + LIFT_OFF);
1484 glEnd();
1485 glDepthMask(GL_TRUE);
1486 glDisable(GL_BLEND);
1487 glDisable(GL_LINE_SMOOTH);
1488 }
1489
1490 static void
getMoveIndicatorPos(const BoardData * bd,float pos[3])1491 getMoveIndicatorPos(const BoardData * bd, float pos[3])
1492 {
1493 if (!fClockwise)
1494 pos[0] = TOTAL_WIDTH - TRAY_WIDTH + ARROW_SIZE / 2.0f;
1495 else
1496 pos[0] = TRAY_WIDTH - ARROW_SIZE / 2.0f;
1497
1498 if (bd->turn == 1)
1499 pos[1] = EDGE_HEIGHT / 2.0f;
1500 else
1501 pos[1] = TOTAL_HEIGHT - EDGE_HEIGHT / 2.0f;
1502
1503 pos[2] = BASE_DEPTH + EDGE_DEPTH;
1504 }
1505
1506 static void
showMoveIndicator(const BoardData * bd)1507 showMoveIndicator(const BoardData * bd)
1508 {
1509 float pos[3];
1510 /* ARROW_UNIT used to draw sub-bits of arrow */
1511 #define ARROW_UNIT (ARROW_SIZE / 4.0f)
1512
1513 setMaterial(&bd->rd->ChequerMat[(bd->turn == 1) ? 1 : 0]);
1514
1515 glDisable(GL_DEPTH_TEST);
1516 glDisable(GL_TEXTURE_2D);
1517 glNormal3f(0.f, 0.f, 1.f);
1518
1519 glPushMatrix();
1520 getMoveIndicatorPos(bd, pos);
1521 glTranslatef(pos[0], pos[1], pos[2]);
1522 if (fClockwise)
1523 glRotatef(180.f, 0.f, 0.f, 1.f);
1524
1525 glBegin(GL_QUADS);
1526 glVertex2f(-ARROW_UNIT * 2, -ARROW_UNIT);
1527 glVertex2f(LIFT_OFF, -ARROW_UNIT);
1528 glVertex2f(LIFT_OFF, ARROW_UNIT);
1529 glVertex2f(-ARROW_UNIT * 2, ARROW_UNIT);
1530 glEnd();
1531 glBegin(GL_TRIANGLES);
1532 glVertex2f(0.f, ARROW_UNIT * 2);
1533 glVertex2f(0.f, -ARROW_UNIT * 2);
1534 glVertex2f(ARROW_UNIT * 2, 0.f);
1535 glEnd();
1536
1537 /* Outline arrow */
1538 SetColour3d(0.f, 0.f, 0.f, 1.f); /* Black outline */
1539
1540 glLineWidth(.5f);
1541 glEnable(GL_BLEND);
1542 glEnable(GL_LINE_SMOOTH);
1543
1544 glBegin(GL_LINE_LOOP);
1545 glVertex2f(-ARROW_UNIT * 2, -ARROW_UNIT);
1546 glVertex2f(-ARROW_UNIT * 2, ARROW_UNIT);
1547 glVertex2f(0.f, ARROW_UNIT);
1548 glVertex2f(0.f, ARROW_UNIT * 2);
1549 glVertex2f(ARROW_UNIT * 2, 0.f);
1550 glVertex2f(0.f, -ARROW_UNIT * 2);
1551 glVertex2f(0.f, -ARROW_UNIT);
1552 glEnd();
1553
1554 glDisable(GL_BLEND);
1555 glDisable(GL_LINE_SMOOTH);
1556
1557 glPopMatrix();
1558 glEnable(GL_DEPTH_TEST);
1559 }
1560
1561 static void
ClearScreen(const renderdata * prd)1562 ClearScreen(const renderdata * prd)
1563 {
1564 glClearColor(prd->BackGroundMat.ambientColour[0], prd->BackGroundMat.ambientColour[1],
1565 prd->BackGroundMat.ambientColour[2], 0.f);
1566 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1567 }
1568
1569 static void
RotateClosingBoard(const BoardData3d * bd3d,const renderdata * prd)1570 RotateClosingBoard(const BoardData3d * bd3d, const renderdata * prd)
1571 {
1572 float rotAngle = 90;
1573 float trans = getBoardHeight() * .4f;
1574 float zoom = .2f;
1575
1576 glPopMatrix();
1577
1578 ClearScreen(prd);
1579
1580 if ((bd3d->State == BOARD_OPENING) || (bd3d->State == BOARD_CLOSING)) {
1581 rotAngle *= bd3d->perOpen;
1582 trans *= bd3d->perOpen;
1583 zoom *= bd3d->perOpen;
1584 }
1585 glPushMatrix();
1586 glTranslatef(0.f, -trans, zoom);
1587 glTranslatef(getBoardWidth() / 2.0f, getBoardHeight() / 2.0f, 0.f);
1588 glRotatef(rotAngle, 0.f, 0.f, 1.f);
1589 glTranslatef(-getBoardWidth() / 2.0f, -getBoardHeight() / 2.0f, 0.f);
1590 }
1591
1592 /* Macros to make texture specification easier */
1593 #define M_X(x, y, z) if (tuv != 0.0f) glTexCoord2f((z) * tuv, (y) * tuv); glVertex3f(x, y, z);
1594 #define M_Z(x, y, z) if (tuv != 0.0f) glTexCoord2f((x) * tuv, (y) * tuv); glVertex3f(x, y, z);
1595
1596 #define DrawBottom(x, y, z, w, h)\
1597 glNormal3f(0.f, -1.f, 0.f);\
1598 glBegin(GL_QUADS);\
1599 if (tuv != 0.0f) glTexCoord2f((x) * tuv, ((y) + BOARD_FILLET - curveTextOff - (h)) * tuv);\
1600 glVertex3f(x, y, z);\
1601 if (tuv != 0.0f) glTexCoord2f(((x) + (w)) * tuv, ((y) + BOARD_FILLET - curveTextOff - (h)) * tuv);\
1602 glVertex3f((x) + (w), y, z);\
1603 if (tuv != 0.0f) glTexCoord2f(((x) + (w)) * tuv, ((y) + BOARD_FILLET - curveTextOff) * tuv);\
1604 glVertex3f((x) + (w), y, (z) + (h));\
1605 if (tuv != 0.0f) glTexCoord2f((x) * tuv, ((y) + BOARD_FILLET - curveTextOff) * tuv);\
1606 glVertex3f(x, y, (z) + (h));\
1607 glEnd();
1608
1609 #define DrawTop(x, y, z, w, h)\
1610 glNormal3f(0.f, 1.f, 0.f);\
1611 glBegin(GL_QUADS);\
1612 if (tuv != 0.0f) glTexCoord2f((x) * tuv, ((y) - (BOARD_FILLET - curveTextOff) + (h)) * tuv);\
1613 glVertex3f(x, y, z);\
1614 if (tuv != 0.0f) glTexCoord2f((x) * tuv, ((y) - (BOARD_FILLET - curveTextOff)) * tuv);\
1615 glVertex3f(x, y, (z) + (h));\
1616 if (tuv != 0.0f) glTexCoord2f(((x) + (w)) * tuv, ((y) - (BOARD_FILLET - curveTextOff)) * tuv);\
1617 glVertex3f((x) + (w), y, (z) + (h));\
1618 if (tuv != 0.0f) glTexCoord2f(((x) + (w)) * tuv, ((y) - (BOARD_FILLET - curveTextOff) + (h)) * tuv);\
1619 glVertex3f((x) + (w), y, z);\
1620 glEnd();
1621
1622 #define DrawLeft(x, y, z, w, h)\
1623 glNormal3f(-1.f, 0.f, 0.f);\
1624 glBegin(GL_QUADS);\
1625 if (tuv != 0.0f) glTexCoord2f(((x) + BOARD_FILLET - curveTextOff - (h)) * tuv, (y) * tuv);\
1626 glVertex3f(x, y, z);\
1627 if (tuv != 0.0f) glTexCoord2f(((x) + BOARD_FILLET - curveTextOff) * tuv, (y) * tuv);\
1628 glVertex3f(x, y, (z) + (h));\
1629 if (tuv != 0.0f) glTexCoord2f(((x) + BOARD_FILLET - curveTextOff) * tuv, ((y) + (w)) * tuv);\
1630 glVertex3f(x, (y) + (w), (z) + (h));\
1631 if (tuv != 0.0f) glTexCoord2f(((x) + BOARD_FILLET - curveTextOff - (h)) * tuv, ((y) + (w)) * tuv);\
1632 glVertex3f(x, (y) + (w), z);\
1633 glEnd();
1634
1635 #define DrawRight(x, y, z, w, h)\
1636 glNormal3f(1.f, 0.f, 0.f);\
1637 glBegin(GL_QUADS);\
1638 if (tuv != 0.0f) glTexCoord2f(((x) - (BOARD_FILLET - curveTextOff) + (h)) * tuv, (y) * tuv);\
1639 glVertex3f(x, y, z);\
1640 if (tuv != 0.0f) glTexCoord2f(((x) - (BOARD_FILLET - curveTextOff) + (h)) * tuv, ((y) + (w)) * tuv);\
1641 glVertex3f(x, (y) + (w), z);\
1642 if (tuv != 0.0f) glTexCoord2f(((x) - (BOARD_FILLET - curveTextOff)) * tuv, ((y) + (w)) * tuv);\
1643 glVertex3f(x, (y) + (w), (z) + (h));\
1644 if (tuv != 0.0f) glTexCoord2f(((x) - (BOARD_FILLET - curveTextOff)) * tuv, (y) * tuv);\
1645 glVertex3f(x, y, (z) + (h));\
1646 glEnd();
1647
1648 #define TextureOffset(s, t) if (tuv != 0.0f)\
1649 {\
1650 glMatrixMode(GL_TEXTURE);\
1651 glPushMatrix();\
1652 glTranslatef(s, t, 0.f);\
1653 glMatrixMode(GL_MODELVIEW);\
1654 }
1655
1656 #define TextureReset if (tuv != 0.0f)\
1657 {\
1658 glMatrixMode(GL_TEXTURE);\
1659 glPopMatrix();\
1660 glMatrixMode(GL_MODELVIEW);\
1661 }
1662
1663 /* texture unit value */
1664 static float tuv;
1665
1666 static void
InsideFillet(float x,float y,float z,float w,float h,float radius,unsigned int accuracy,const Texture * texture,float curveTextOff)1667 InsideFillet(float x, float y, float z, float w, float h, float radius, unsigned int accuracy, const Texture * texture,
1668 float curveTextOff)
1669 {
1670 /* Left */
1671 DrawRight(x + BOARD_FILLET, y + BOARD_FILLET, BASE_DEPTH, h, EDGE_DEPTH - BOARD_FILLET);
1672 /* Top */
1673 DrawBottom(x + BOARD_FILLET, y + h + BOARD_FILLET, BASE_DEPTH, w, EDGE_DEPTH - BOARD_FILLET + LIFT_OFF);
1674 /* Bottom */
1675 DrawTop(x + BOARD_FILLET, y + BOARD_FILLET, BASE_DEPTH, w, EDGE_DEPTH - BOARD_FILLET)
1676 /* Right */
1677 DrawLeft(x + w + BOARD_FILLET, y + BOARD_FILLET, BASE_DEPTH + LIFT_OFF, h, EDGE_DEPTH - BOARD_FILLET);
1678
1679 if (tuv != 0.0f) {
1680 glMatrixMode(GL_TEXTURE);
1681 glPushMatrix();
1682 glTranslatef((x + curveTextOff) * tuv, (y + h + radius * 2) * tuv, 0.f);
1683 glRotatef(-90.f, 0.f, 0.f, 1.f);
1684 glMatrixMode(GL_MODELVIEW);
1685 }
1686 glPushMatrix();
1687 glTranslatef(x, y + h + radius * 2, z - radius);
1688 glRotatef(-180.f, 1.f, 0.f, 0.f);
1689 glRotatef(90.f, 0.f, 1.f, 0.f);
1690 QuarterCylinderSplayed(radius, h + radius * 2, accuracy, texture);
1691 glPopMatrix();
1692 TextureReset TextureOffset(x * tuv, (y + curveTextOff) * tuv);
1693 glPushMatrix();
1694 glTranslatef(x, y, z - radius);
1695 glRotatef(-90.f, 1.f, 0.f, 0.f);
1696 glRotatef(-90.f, 0.f, 0.f, 1.f);
1697 QuarterCylinderSplayed(radius, w + radius * 2, accuracy, texture);
1698 glPopMatrix();
1699 TextureReset if (tuv != 0.0f) {
1700 glMatrixMode(GL_TEXTURE);
1701 glPushMatrix();
1702 glTranslatef((x + w + radius * 2 - curveTextOff) * tuv, y * tuv, 0.f);
1703 glRotatef(90.f, 0.f, 0.f, 1.f);
1704 glMatrixMode(GL_MODELVIEW);
1705 }
1706 glPushMatrix();
1707 glTranslatef(x + w + radius * 2, y, z - radius);
1708 glRotatef(-90.f, 0.f, 1.f, 0.f);
1709 QuarterCylinderSplayed(radius, h + radius * 2, accuracy, texture);
1710 glPopMatrix();
1711 TextureReset TextureOffset((x + radius) * tuv, (y + h + radius * 2) * tuv);
1712 glPushMatrix();
1713 glTranslatef(x + radius, y + h + radius * 2, z - radius);
1714 glRotatef(-90.f, 0.f, 0.f, 1.f);
1715 QuarterCylinderSplayedRev(radius, w, accuracy, texture);
1716 glPopMatrix();
1717 TextureReset}
1718
1719 NTH_STATIC void
drawTable(const BoardData3d * bd3d,const renderdata * prd)1720 drawTable(const BoardData3d * bd3d, const renderdata * prd)
1721 {
1722 float curveTextOff = 0;
1723 tuv = 0;
1724
1725 if (bd3d->State != BOARD_OPEN)
1726 RotateClosingBoard(bd3d, prd);
1727
1728 /* Draw background */
1729 setMaterial(&prd->BackGroundMat);
1730
1731 /* Set depth and default pixel values (as background covers entire screen) */
1732 glDepthFunc(GL_ALWAYS);
1733 drawRect(bd3d->backGroundPos[0], bd3d->backGroundPos[1], 0.f, bd3d->backGroundSize[0], bd3d->backGroundSize[1],
1734 prd->BackGroundMat.pTexture);
1735 glDepthFunc(GL_LEQUAL);
1736
1737 /* Right side of board */
1738 if (!prd->fHinges3d)
1739 drawBase(prd, 1 | 2);
1740 else
1741 drawBase(prd, 2);
1742 setMaterial(&prd->BoxMat);
1743
1744 if (!prd->bgInTrays)
1745 drawSplitRect(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH, PIECE_HOLE + LIFT_OFF,
1746 TOTAL_HEIGHT - EDGE_HEIGHT * 2, prd->BoxMat.pTexture);
1747
1748 if (prd->roundedEdges) {
1749 if (prd->BoxMat.pTexture) {
1750 float st, ct, dInc;
1751
1752 tuv = (TEXTURE_SCALE) / prd->BoxMat.pTexture->width;
1753 st = sinf((2 * (float) G_PI) / prd->curveAccuracy) * BOARD_FILLET;
1754 ct = (cosf((2 * (float) G_PI) / prd->curveAccuracy) - 1) * BOARD_FILLET;
1755 dInc = sqrtf(st * st + ct * ct);
1756 curveTextOff = (int) (prd->curveAccuracy / 4) * dInc;
1757 }
1758
1759 /* Right edge */
1760 glBegin(GL_QUADS);
1761 /* Front Face */
1762 glNormal3f(0.f, 0.f, 1.f);
1763
1764 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET - LIFT_OFF, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1765 M_Z(TOTAL_WIDTH - BOARD_FILLET + LIFT_OFF, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1766 M_Z(TOTAL_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1767 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1768
1769 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1770 M_Z(TOTAL_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1771 M_Z(TOTAL_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1772 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1773 glEnd();
1774
1775 /* Right face */
1776 DrawRight(TOTAL_WIDTH, BOARD_FILLET, 0.f, TOTAL_HEIGHT - BOARD_FILLET * 2,
1777 BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1778
1779 if (tuv != 0.0f) {
1780 glMatrixMode(GL_TEXTURE);
1781 glPushMatrix();
1782 glTranslatef((TOTAL_WIDTH - BOARD_FILLET) * tuv,
1783 (BOARD_FILLET - curveTextOff - (BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET)) * tuv, 0.f);
1784 glRotatef(90.f, 0.f, 0.f, 1.f);
1785 glMatrixMode(GL_MODELVIEW);
1786 }
1787 glPushMatrix();
1788 glTranslatef(TOTAL_WIDTH - BOARD_FILLET, BOARD_FILLET, 0.f);
1789 glRotatef(90.f, 1.f, 0.f, 0.f);
1790 QuarterCylinder(BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET, prd->curveAccuracy, prd->BoxMat.pTexture);
1791 glPopMatrix();
1792 TextureReset if (tuv != 0.0f) {
1793 glMatrixMode(GL_TEXTURE);
1794 glPushMatrix();
1795 glTranslatef((TOTAL_WIDTH - BOARD_FILLET) * tuv, (TOTAL_HEIGHT - (BOARD_FILLET - curveTextOff)) * tuv, 0.f);
1796 glRotatef(90.f, 0.f, 0.f, 1.f);
1797 glMatrixMode(GL_MODELVIEW);
1798 }
1799 glPushMatrix();
1800 glTranslatef(TOTAL_WIDTH - BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1801 glRotatef(-90.f, 1.f, 0.f, 0.f);
1802 QuarterCylinder(BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET, prd->curveAccuracy, prd->BoxMat.pTexture);
1803 glPopMatrix();
1804 TextureReset if (tuv != 0.0f) {
1805 glMatrixMode(GL_TEXTURE);
1806 glPushMatrix();
1807 glTranslatef((TOTAL_WIDTH - BOARD_FILLET + curveTextOff) * tuv, (TOTAL_HEIGHT - BOARD_FILLET) * tuv, 0.f);
1808 glRotatef(-90.f, 0.f, 0.f, 1.f);
1809 glMatrixMode(GL_MODELVIEW);
1810 }
1811 glPushMatrix();
1812 glTranslatef(TOTAL_WIDTH - BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1813 glRotatef(-180.f, 1.f, 0.f, 0.f);
1814 glRotatef(90.f, 0.f, 1.f, 0.f);
1815 QuarterCylinder(BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET * 2, prd->curveAccuracy, prd->BoxMat.pTexture);
1816 glPopMatrix();
1817 TextureReset glPushMatrix();
1818 glTranslatef(TOTAL_WIDTH - BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1819 glRotatef(-90.f, 0.f, 0.f, 1.f);
1820 drawCornerEigth(bd3d->boardPoints, BOARD_FILLET, prd->curveAccuracy);
1821 glPopMatrix();
1822
1823 glPushMatrix();
1824 glTranslatef(TOTAL_WIDTH - BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1825 drawCornerEigth(bd3d->boardPoints, BOARD_FILLET, prd->curveAccuracy);
1826 glPopMatrix();
1827
1828 /* Top + bottom edges */
1829 if (!prd->fHinges3d) {
1830 glBegin(GL_QUADS);
1831 /* Front Face */
1832 glNormal3f(0.f, 0.f, 1.f);
1833 M_Z(EDGE_WIDTH - BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1834 M_Z(TOTAL_WIDTH / 2.0f, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1835 M_Z(TOTAL_WIDTH / 2.0f, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1836 M_Z(EDGE_WIDTH - BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1837
1838 M_Z(TOTAL_WIDTH / 2.0f, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1839 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1840 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1841 M_Z(TOTAL_WIDTH / 2.0f, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1842 glEnd();
1843
1844 DrawBottom(BOARD_FILLET, 0.f, 0.f, TOTAL_WIDTH - BOARD_FILLET * 2, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1845
1846 glBegin(GL_QUADS);
1847 /* Front Face */
1848 glNormal3f(0.f, 0.f, 1.f);
1849 M_Z(EDGE_WIDTH - BOARD_FILLET, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1850 M_Z(TOTAL_WIDTH / 2.0f, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1851 M_Z(TOTAL_WIDTH / 2.0f, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1852 M_Z(EDGE_WIDTH - BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1853
1854 M_Z(TOTAL_WIDTH / 2.0f, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1855 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET,
1856 BASE_DEPTH + EDGE_DEPTH);
1857 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1858 M_Z(TOTAL_WIDTH / 2.0f, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1859 glEnd();
1860 /* Top Face */
1861 DrawTop(BOARD_FILLET, TOTAL_HEIGHT, 0.f, TOTAL_WIDTH - BOARD_FILLET * 2,
1862 BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1863
1864 TextureOffset(BOARD_FILLET * tuv, BOARD_FILLET * tuv);
1865 glPushMatrix();
1866 glTranslatef(BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1867 glRotatef(-90.f, 0.f, 0.f, 1.f);
1868 QuarterCylinder(BOARD_FILLET, TOTAL_WIDTH - BOARD_FILLET * 2, prd->curveAccuracy, prd->BoxMat.pTexture);
1869 glPopMatrix();
1870 TextureReset TextureOffset(BOARD_FILLET * tuv, (TOTAL_HEIGHT - (BOARD_FILLET - curveTextOff)) * tuv);
1871 glPushMatrix();
1872 glTranslatef(BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1873 glRotatef(-90.f, 1.f, 0.f, 0.f);
1874 glRotatef(-90.f, 0.f, 0.f, 1.f);
1875 QuarterCylinder(BOARD_FILLET, TOTAL_WIDTH - BOARD_FILLET * 2, prd->curveAccuracy, prd->BoxMat.pTexture);
1876 glPopMatrix();
1877 TextureReset} else {
1878 glBegin(GL_QUADS);
1879 /* Front Face */
1880 glNormal3f(0.f, 0.f, 1.f);
1881 M_Z((TOTAL_WIDTH + HINGE_GAP) / 2.0f, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1882 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1883 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1884 M_Z((TOTAL_WIDTH + HINGE_GAP) / 2.0f, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1885 glEnd();
1886
1887 DrawBottom((TOTAL_WIDTH + HINGE_GAP) / 2.0f, 0.f, 0.f, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - BOARD_FILLET,
1888 BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1889
1890 glBegin(GL_QUADS);
1891 /* Front Face */
1892 glNormal3f(0.f, 0.f, 1.f);
1893 M_Z((TOTAL_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1894 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET,
1895 BASE_DEPTH + EDGE_DEPTH);
1896 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1897 M_Z((TOTAL_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1898 glEnd();
1899 /* Top Face */
1900 DrawTop((TOTAL_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT, 0.f,
1901 (TOTAL_WIDTH - HINGE_GAP) / 2.0f - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET)
1902
1903 glBegin(GL_QUADS);
1904
1905 if (bd3d->State != BOARD_OPEN) {
1906 /* Cover up back when closing */
1907 glNormal3f(-1.f, 0.f, 0.f);
1908 M_X(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH + HINGE_GAP) / 2.0f, 0.f, 0.f);
1909 M_X(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH + HINGE_GAP) / 2.0f, 0.f, BASE_DEPTH + EDGE_DEPTH);
1910 M_X(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
1911 M_X(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT, 0.f);
1912 }
1913 glEnd();
1914
1915 TextureOffset(((TOTAL_WIDTH + HINGE_GAP) / 2.0f) * tuv, BOARD_FILLET * tuv);
1916 glPushMatrix();
1917 glTranslatef((TOTAL_WIDTH + HINGE_GAP) / 2.0f, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1918 glRotatef(-90.f, 0.f, 0.f, 1.f);
1919 QuarterCylinder(BOARD_FILLET, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - BOARD_FILLET, prd->curveAccuracy,
1920 prd->BoxMat.pTexture);
1921 glPopMatrix();
1922 TextureReset
1923 TextureOffset(((TOTAL_WIDTH + HINGE_GAP) / 2.0f) * tuv,
1924 (TOTAL_HEIGHT - (BOARD_FILLET - curveTextOff)) * tuv);
1925 glPushMatrix();
1926 glTranslatef((TOTAL_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT - BOARD_FILLET,
1927 BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
1928 glRotatef(-90.f, 1.f, 0.f, 0.f);
1929 glRotatef(-90.f, 0.f, 0.f, 1.f);
1930 QuarterCylinder(BOARD_FILLET, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - BOARD_FILLET, prd->curveAccuracy,
1931 prd->BoxMat.pTexture);
1932 glPopMatrix();
1933 TextureReset}
1934 /* Bar */
1935 if (!prd->fHinges3d) {
1936 glBegin(GL_QUADS);
1937 /* Front Face */
1938 glNormal3f(0.f, 0.f, 1.f);
1939 M_Z(TRAY_WIDTH + BOARD_WIDTH + BOARD_FILLET - LIFT_OFF, EDGE_HEIGHT - BOARD_FILLET,
1940 BASE_DEPTH + EDGE_DEPTH);
1941 M_Z(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET + LIFT_OFF, EDGE_HEIGHT - BOARD_FILLET,
1942 BASE_DEPTH + EDGE_DEPTH);
1943 M_Z(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f,
1944 BASE_DEPTH + EDGE_DEPTH);
1945 M_Z(TRAY_WIDTH + BOARD_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1946
1947 M_Z(TRAY_WIDTH + BOARD_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1948 M_Z(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f,
1949 BASE_DEPTH + EDGE_DEPTH);
1950 M_Z(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET + LIFT_OFF,
1951 TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1952 M_Z(TRAY_WIDTH + BOARD_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET,
1953 BASE_DEPTH + EDGE_DEPTH);
1954 glEnd();
1955 } else {
1956 glBegin(GL_QUADS);
1957 /* Front Face */
1958 glNormal3f(0.f, 0.f, 1.f);
1959 M_Z(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH + HINGE_GAP) / 2.0f, EDGE_HEIGHT - BOARD_FILLET,
1960 BASE_DEPTH + EDGE_DEPTH);
1961 M_Z(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET + LIFT_OFF, EDGE_HEIGHT - BOARD_FILLET,
1962 BASE_DEPTH + EDGE_DEPTH);
1963 M_Z(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f,
1964 BASE_DEPTH + EDGE_DEPTH);
1965 M_Z(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT / 2.0f,
1966 BASE_DEPTH + EDGE_DEPTH);
1967
1968 M_Z(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT / 2.0f,
1969 BASE_DEPTH + EDGE_DEPTH);
1970 M_Z(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f,
1971 BASE_DEPTH + EDGE_DEPTH);
1972 M_Z(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET + LIFT_OFF,
1973 TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1974 M_Z(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET,
1975 BASE_DEPTH + EDGE_DEPTH);
1976 glEnd();
1977 }
1978 /* Bear-off edge */
1979 glBegin(GL_QUADS);
1980 /* Front Face */
1981 glNormal3f(0.f, 0.f, 1.f);
1982 M_Z(TOTAL_WIDTH - TRAY_WIDTH + BOARD_FILLET - LIFT_OFF, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
1983 M_Z(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - BOARD_FILLET + LIFT_OFF, EDGE_HEIGHT - BOARD_FILLET,
1984 BASE_DEPTH + EDGE_DEPTH);
1985 M_Z(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f,
1986 BASE_DEPTH + EDGE_DEPTH);
1987 M_Z(TOTAL_WIDTH - TRAY_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1988
1989 M_Z(TOTAL_WIDTH - TRAY_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
1990 M_Z(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f,
1991 BASE_DEPTH + EDGE_DEPTH);
1992 M_Z(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET,
1993 BASE_DEPTH + EDGE_DEPTH);
1994 M_Z(TOTAL_WIDTH - TRAY_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET,
1995 BASE_DEPTH + EDGE_DEPTH);
1996 glEnd();
1997
1998 glBegin(GL_QUADS);
1999 /* Front Face */
2000 glNormal3f(0.f, 0.f, 1.f);
2001 M_Z(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - LIFT_OFF - BOARD_FILLET, TRAY_HEIGHT + BOARD_FILLET,
2002 BASE_DEPTH + EDGE_DEPTH);
2003 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, TRAY_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2004 M_Z(TOTAL_WIDTH - EDGE_WIDTH + BOARD_FILLET, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT - BOARD_FILLET,
2005 BASE_DEPTH + EDGE_DEPTH);
2006 M_Z(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - LIFT_OFF - BOARD_FILLET,
2007 TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2008 glEnd();
2009
2010 InsideFillet(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET,
2011 BASE_DEPTH + EDGE_DEPTH, TRAY_WIDTH - EDGE_WIDTH * 2, TRAY_HEIGHT - EDGE_HEIGHT, BOARD_FILLET,
2012 prd->curveAccuracy, prd->BoxMat.pTexture, curveTextOff);
2013 InsideFillet(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - BOARD_FILLET,
2014 TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH,
2015 TRAY_WIDTH - EDGE_WIDTH * 2, TRAY_HEIGHT - EDGE_HEIGHT, BOARD_FILLET, prd->curveAccuracy,
2016 prd->BoxMat.pTexture, curveTextOff);
2017
2018 InsideFillet(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET,
2019 BASE_DEPTH + EDGE_DEPTH, BOARD_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT * 2, BOARD_FILLET,
2020 prd->curveAccuracy, prd->BoxMat.pTexture, curveTextOff);
2021 } else {
2022 /* Right edge */
2023 drawBox(BOX_SPLITTOP, TOTAL_WIDTH - EDGE_WIDTH, 0.f, 0.f, EDGE_WIDTH, TOTAL_HEIGHT, BASE_DEPTH + EDGE_DEPTH,
2024 prd->BoxMat.pTexture);
2025
2026 /* Top + bottom edges */
2027 if (!prd->fHinges3d) {
2028 drawBox(BOX_NOSIDES | BOX_SPLITWIDTH, EDGE_WIDTH, 0.f, 0.f, TOTAL_WIDTH - EDGE_WIDTH * 2, EDGE_HEIGHT,
2029 BASE_DEPTH + EDGE_DEPTH, prd->BoxMat.pTexture);
2030 drawBox(BOX_NOSIDES | BOX_SPLITWIDTH, EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, 0.f,
2031 TOTAL_WIDTH - EDGE_WIDTH * 2, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH, prd->BoxMat.pTexture);
2032 } else {
2033 drawBox(BOX_ALL, (TOTAL_WIDTH + HINGE_GAP) / 2.0f, 0.f, 0.f, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - EDGE_WIDTH,
2034 EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH, prd->BoxMat.pTexture);
2035 drawBox(BOX_ALL, (TOTAL_WIDTH + HINGE_GAP) / 2.0f, TOTAL_HEIGHT - EDGE_HEIGHT, 0.f,
2036 (TOTAL_WIDTH - HINGE_GAP) / 2.0f - EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH,
2037 prd->BoxMat.pTexture);
2038 }
2039
2040 /* Bar */
2041 if (!prd->fHinges3d)
2042 drawBox(BOX_NOENDS | BOX_SPLITTOP, TRAY_WIDTH + BOARD_WIDTH, EDGE_HEIGHT, BASE_DEPTH, BAR_WIDTH,
2043 TOTAL_HEIGHT - EDGE_HEIGHT * 2, EDGE_DEPTH, prd->BoxMat.pTexture);
2044 else
2045 drawBox(BOX_NOENDS | BOX_SPLITTOP, TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH + HINGE_GAP) / 2.0f, EDGE_HEIGHT,
2046 0.f, (BAR_WIDTH - HINGE_GAP) / 2.0f, TOTAL_HEIGHT - EDGE_HEIGHT * 2, BASE_DEPTH + EDGE_DEPTH,
2047 prd->BoxMat.pTexture);
2048
2049 /* Bear-off edge */
2050 drawBox(BOX_NOENDS | BOX_SPLITTOP, TOTAL_WIDTH - TRAY_WIDTH, EDGE_HEIGHT, BASE_DEPTH, EDGE_WIDTH,
2051 TOTAL_HEIGHT - EDGE_HEIGHT * 2, EDGE_DEPTH, prd->BoxMat.pTexture);
2052 drawBox(BOX_NOSIDES, TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - LIFT_OFF, TRAY_HEIGHT, BASE_DEPTH,
2053 TRAY_WIDTH - EDGE_WIDTH * 2 + LIFT_OFF * 2, MID_SIDE_GAP_HEIGHT, EDGE_DEPTH, prd->BoxMat.pTexture);
2054 }
2055
2056 /* Left side of board */
2057 glPushMatrix();
2058
2059 if (bd3d->State != BOARD_OPEN) {
2060 float boardAngle = 180;
2061 if ((bd3d->State == BOARD_OPENING) || (bd3d->State == BOARD_CLOSING))
2062 boardAngle *= bd3d->perOpen;
2063
2064 glTranslatef(TOTAL_WIDTH / 2.0f, 0.f, BASE_DEPTH + EDGE_DEPTH);
2065 glRotatef(boardAngle, 0.f, 1.f, 0.f);
2066 glTranslatef(-TOTAL_WIDTH / 2.0f, 0.f, -(BASE_DEPTH + EDGE_DEPTH));
2067 }
2068
2069 if (prd->fHinges3d)
2070 drawBase(prd, 1);
2071
2072 setMaterial(&prd->BoxMat);
2073
2074 if (!prd->bgInTrays)
2075 drawSplitRect(EDGE_WIDTH - LIFT_OFF, EDGE_HEIGHT, BASE_DEPTH, PIECE_HOLE, TOTAL_HEIGHT - EDGE_HEIGHT * 2,
2076 prd->BoxMat.pTexture);
2077
2078 if (bd3d->State != BOARD_OPEN) { /* Back of board */
2079 float logoSize = (TOTAL_WIDTH * .3f) / 2.0f;
2080 drawRect(TOTAL_WIDTH / 2.0f, 0.f, 0.f, -(TOTAL_WIDTH / 2.0f), TOTAL_HEIGHT, prd->BoxMat.pTexture);
2081 /* logo */
2082 glPushMatrix();
2083 glTranslatef(TOTAL_WIDTH / 4.0f, TOTAL_HEIGHT / 2.0f, -LIFT_OFF);
2084 glRotatef(90.f, 0.f, 0.f, 1.f);
2085 setMaterial(&bd3d->logoMat);
2086 glNormal3f(0.f, 0.f, 1.f);
2087 glBegin(GL_QUADS);
2088 glTexCoord2f(0.f, 0.f);
2089 glVertex3f(logoSize, -logoSize, 0.f);
2090 glTexCoord2f(1.f, 0.f);
2091 glVertex3f(-logoSize, -logoSize, 0.f);
2092 glTexCoord2f(1.f, 1.f);
2093 glVertex3f(-logoSize, logoSize, 0.f);
2094 glTexCoord2f(0.f, 1.f);
2095 glVertex3f(logoSize, logoSize, 0.f);
2096 glEnd();
2097 glPopMatrix();
2098 setMaterial(&prd->BoxMat);
2099 }
2100
2101 if (prd->roundedEdges) {
2102 /* Left edge */
2103 glBegin(GL_QUADS);
2104 /* Front Face */
2105 glNormal3f(0.f, 0.f, 1.f);
2106 M_Z(BOARD_FILLET - LIFT_OFF, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2107 M_Z(EDGE_WIDTH - BOARD_FILLET + LIFT_OFF, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2108 M_Z(EDGE_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2109 M_Z(BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2110
2111 M_Z(BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2112 M_Z(EDGE_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2113 M_Z(EDGE_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2114 M_Z(BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2115 glEnd();
2116 /* Left Face */
2117 DrawLeft(0.f, BOARD_FILLET, 0.f, TOTAL_HEIGHT - BOARD_FILLET * 2, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
2118
2119 if (tuv != 0.0f) {
2120 glMatrixMode(GL_TEXTURE);
2121 glPushMatrix();
2122 glTranslatef(BOARD_FILLET * tuv, (BOARD_FILLET - curveTextOff) * tuv, 0.f);
2123 glRotatef(-90.f, 0.f, 0.f, 1.f);
2124 glMatrixMode(GL_MODELVIEW);
2125 }
2126 glPushMatrix();
2127 glTranslatef(BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
2128 glRotatef(-90.f, 1.f, 0.f, 0.f);
2129 glRotatef(180.f, 0.f, 1.f, 0.f);
2130 QuarterCylinder(BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET, prd->curveAccuracy, prd->BoxMat.pTexture);
2131 glPopMatrix();
2132 TextureReset if (tuv != 0.0f) {
2133 glMatrixMode(GL_TEXTURE);
2134 glPushMatrix();
2135 glTranslatef((BOARD_FILLET - curveTextOff) * tuv, (TOTAL_HEIGHT - (BOARD_FILLET - curveTextOff)) * tuv,
2136 0.f);
2137 glRotatef(90.f, 0.f, 0.f, 1.f);
2138 glMatrixMode(GL_MODELVIEW);
2139 }
2140 glPushMatrix();
2141 glTranslatef(BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
2142 glRotatef(-90.f, 1.f, 0.f, 0.f);
2143 glRotatef(-90.f, 0.f, 1.f, 0.f);
2144 QuarterCylinder(BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET, prd->curveAccuracy, prd->BoxMat.pTexture);
2145 glPopMatrix();
2146 TextureReset if (tuv != 0.0f) {
2147 glMatrixMode(GL_TEXTURE);
2148 glPushMatrix();
2149 glTranslatef((BOARD_FILLET - curveTextOff) * tuv, BOARD_FILLET * tuv, 0.f);
2150 glRotatef(90.f, 0.f, 0.f, 1.f);
2151 }
2152 glMatrixMode(GL_MODELVIEW);
2153 glPushMatrix();
2154 glTranslatef(BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
2155 glRotatef(-90.f, 0.f, 1.f, 0.f);
2156 QuarterCylinder(BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET * 2, prd->curveAccuracy, prd->BoxMat.pTexture);
2157 glPopMatrix();
2158 TextureReset glPushMatrix();
2159 glTranslatef(BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
2160 glRotatef(180.f, 0.f, 0.f, 1.f);
2161 drawCornerEigth(bd3d->boardPoints, BOARD_FILLET, prd->curveAccuracy);
2162 glPopMatrix();
2163
2164 glPushMatrix();
2165 glTranslatef(BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
2166 glRotatef(90.f, 0.f, 0.f, 1.f);
2167 drawCornerEigth(bd3d->boardPoints, BOARD_FILLET, prd->curveAccuracy);
2168 glPopMatrix();
2169
2170 if (prd->fHinges3d) { /* Top + bottom edges and bar */
2171 glBegin(GL_QUADS);
2172 /* Front Face */
2173 glNormal3f(0.f, 0.f, 1.f);
2174 M_Z(EDGE_WIDTH - BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2175 M_Z((TOTAL_WIDTH - HINGE_GAP) / 2.0f, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2176 M_Z((TOTAL_WIDTH - HINGE_GAP) / 2.0f, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2177 M_Z(EDGE_WIDTH - BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2178 glEnd();
2179
2180 DrawBottom(BOARD_FILLET, 0.f, 0.f, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - BOARD_FILLET,
2181 BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
2182
2183 glBegin(GL_QUADS);
2184 /* Front Face */
2185 glNormal3f(0.f, 0.f, 1.f);
2186 M_Z(EDGE_WIDTH - BOARD_FILLET, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2187 M_Z((TOTAL_WIDTH - HINGE_GAP) / 2.0f, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2188 M_Z((TOTAL_WIDTH - HINGE_GAP) / 2.0f, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2189 M_Z(EDGE_WIDTH - BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2190 /* Top Face */
2191 glEnd();
2192
2193 DrawTop(BOARD_FILLET, TOTAL_HEIGHT, 0.f, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - BOARD_FILLET,
2194 BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET)
2195
2196 glBegin(GL_QUADS);
2197 if (bd3d->State != BOARD_OPEN) {
2198 /* Cover up back when closing */
2199 glNormal3f(1.f, 0.f, 0.f);
2200 M_X((TOTAL_WIDTH - HINGE_GAP) / 2.0f, 0.f, 0.f);
2201 M_X((TOTAL_WIDTH - HINGE_GAP) / 2.0f, TOTAL_HEIGHT, 0.f);
2202 M_X((TOTAL_WIDTH - HINGE_GAP) / 2.0f, TOTAL_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
2203 M_X((TOTAL_WIDTH - HINGE_GAP) / 2.0f, 0.f, BASE_DEPTH + EDGE_DEPTH);
2204 }
2205 glEnd();
2206
2207 TextureOffset(BOARD_FILLET * tuv, BOARD_FILLET * tuv);
2208 glPushMatrix();
2209 glTranslatef(BOARD_FILLET, BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
2210 glRotatef(-90.f, 0.f, 0.f, 1.f);
2211 QuarterCylinder(BOARD_FILLET, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - BOARD_FILLET, prd->curveAccuracy,
2212 prd->BoxMat.pTexture);
2213 glPopMatrix();
2214 TextureReset TextureOffset(BOARD_FILLET * tuv, (TOTAL_HEIGHT - (BOARD_FILLET - curveTextOff)) * tuv);
2215 glPushMatrix();
2216 glTranslatef(BOARD_FILLET, TOTAL_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH - BOARD_FILLET);
2217 glRotatef(-90.f, 1.f, 0.f, 0.f);
2218 glRotatef(-90.f, 0.f, 0.f, 1.f);
2219 QuarterCylinder(BOARD_FILLET, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - BOARD_FILLET, prd->curveAccuracy,
2220 prd->BoxMat.pTexture);
2221 glPopMatrix();
2222 TextureReset glBegin(GL_QUADS);
2223 /* Front Face */
2224 glNormal3f(0.f, 0.f, 1.f);
2225 M_Z(TRAY_WIDTH + BOARD_WIDTH + BOARD_FILLET - LIFT_OFF, EDGE_HEIGHT - BOARD_FILLET,
2226 BASE_DEPTH + EDGE_DEPTH);
2227 M_Z(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH - HINGE_GAP) / 2.0f, EDGE_HEIGHT - BOARD_FILLET,
2228 BASE_DEPTH + EDGE_DEPTH);
2229 M_Z(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH - HINGE_GAP) / 2.0f, TOTAL_HEIGHT / 2.0f,
2230 BASE_DEPTH + EDGE_DEPTH);
2231 M_Z(TRAY_WIDTH + BOARD_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2232
2233 M_Z(TRAY_WIDTH + BOARD_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2234 M_Z(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH - HINGE_GAP) / 2.0f, TOTAL_HEIGHT / 2.0f,
2235 BASE_DEPTH + EDGE_DEPTH);
2236 M_Z(TRAY_WIDTH + BOARD_WIDTH + (BAR_WIDTH - HINGE_GAP) / 2.0f, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET,
2237 BASE_DEPTH + EDGE_DEPTH);
2238 M_Z(TRAY_WIDTH + BOARD_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET,
2239 BASE_DEPTH + EDGE_DEPTH);
2240 glEnd();
2241 }
2242
2243 /* Bear-off edge */
2244 glBegin(GL_QUADS);
2245 /* Front Face */
2246 glNormal3f(0.f, 0.f, 1.f);
2247 M_Z(TRAY_WIDTH - EDGE_WIDTH + BOARD_FILLET - LIFT_OFF, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2248 M_Z(TRAY_WIDTH - BOARD_FILLET + LIFT_OFF, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2249 M_Z(TRAY_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2250 M_Z(TRAY_WIDTH - EDGE_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2251
2252 M_Z(TRAY_WIDTH - EDGE_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2253 M_Z(TRAY_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT / 2.0f, BASE_DEPTH + EDGE_DEPTH);
2254 M_Z(TRAY_WIDTH - BOARD_FILLET + LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2255 M_Z(TRAY_WIDTH - EDGE_WIDTH + BOARD_FILLET - LIFT_OFF, TOTAL_HEIGHT - EDGE_HEIGHT + BOARD_FILLET,
2256 BASE_DEPTH + EDGE_DEPTH);
2257 glEnd();
2258
2259 glBegin(GL_QUADS);
2260 /* Front Face */
2261 glNormal3f(0.f, 0.f, 1.f);
2262 M_Z(EDGE_WIDTH - LIFT_OFF - BOARD_FILLET, TRAY_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2263 M_Z(TRAY_WIDTH - EDGE_WIDTH + BOARD_FILLET + LIFT_OFF * 2, TRAY_HEIGHT + BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH);
2264 M_Z(TRAY_WIDTH - EDGE_WIDTH + BOARD_FILLET + LIFT_OFF * 2, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT - BOARD_FILLET,
2265 BASE_DEPTH + EDGE_DEPTH);
2266 M_Z(EDGE_WIDTH - LIFT_OFF - BOARD_FILLET, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT - BOARD_FILLET,
2267 BASE_DEPTH + EDGE_DEPTH);
2268 glEnd();
2269
2270 InsideFillet(EDGE_WIDTH - BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH,
2271 TRAY_WIDTH - EDGE_WIDTH * 2, TRAY_HEIGHT - EDGE_HEIGHT, BOARD_FILLET, prd->curveAccuracy,
2272 prd->BoxMat.pTexture, curveTextOff);
2273 InsideFillet(EDGE_WIDTH - BOARD_FILLET, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT - BOARD_FILLET,
2274 BASE_DEPTH + EDGE_DEPTH, TRAY_WIDTH - EDGE_WIDTH * 2, TRAY_HEIGHT - EDGE_HEIGHT, BOARD_FILLET,
2275 prd->curveAccuracy, prd->BoxMat.pTexture, curveTextOff);
2276
2277 InsideFillet(TRAY_WIDTH - BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH + EDGE_DEPTH, BOARD_WIDTH,
2278 TOTAL_HEIGHT - EDGE_HEIGHT * 2, BOARD_FILLET, prd->curveAccuracy, prd->BoxMat.pTexture,
2279 curveTextOff);
2280 } else {
2281 /* Left edge */
2282 drawBox(BOX_SPLITTOP, 0.f, 0.f, 0.f, EDGE_WIDTH, TOTAL_HEIGHT, BASE_DEPTH + EDGE_DEPTH, prd->BoxMat.pTexture);
2283
2284 if (prd->fHinges3d) { /* Top + bottom edges and bar */
2285 drawBox(BOX_ALL, EDGE_WIDTH, 0.f, 0.f, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - EDGE_WIDTH, EDGE_HEIGHT,
2286 BASE_DEPTH + EDGE_DEPTH, prd->BoxMat.pTexture);
2287 drawBox(BOX_ALL, EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, 0.f, (TOTAL_WIDTH - HINGE_GAP) / 2.0f - EDGE_WIDTH,
2288 EDGE_HEIGHT, BASE_DEPTH + EDGE_DEPTH, prd->BoxMat.pTexture);
2289 }
2290
2291 if (prd->fHinges3d)
2292 drawBox(BOX_NOENDS | BOX_SPLITTOP, TRAY_WIDTH + BOARD_WIDTH, EDGE_HEIGHT, 0.f,
2293 (BAR_WIDTH - HINGE_GAP) / 2.0f, TOTAL_HEIGHT - EDGE_HEIGHT * 2, BASE_DEPTH + EDGE_DEPTH,
2294 prd->BoxMat.pTexture);
2295
2296 /* Bear-off edge */
2297 drawBox(BOX_NOENDS | BOX_SPLITTOP, TRAY_WIDTH - EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH, EDGE_WIDTH,
2298 TOTAL_HEIGHT - EDGE_HEIGHT * 2, EDGE_DEPTH, prd->BoxMat.pTexture);
2299 drawBox(BOX_NOSIDES, EDGE_WIDTH - LIFT_OFF, TRAY_HEIGHT, BASE_DEPTH, TRAY_WIDTH - EDGE_WIDTH * 2 + LIFT_OFF * 2,
2300 MID_SIDE_GAP_HEIGHT, EDGE_DEPTH, prd->BoxMat.pTexture);
2301 }
2302
2303 if (prd->fHinges3d) {
2304 drawHinge(bd3d, prd, ((TOTAL_HEIGHT / 2.0f) - HINGE_HEIGHT) / 2.0f);
2305 drawHinge(bd3d, prd, ((TOTAL_HEIGHT / 2.0f) - HINGE_HEIGHT + TOTAL_HEIGHT) / 2.0f);
2306
2307 if (bd3d->State == BOARD_OPEN) { /* Shadow in gap between boards */
2308 setMaterial(&bd3d->gapColour);
2309 drawRect((TOTAL_WIDTH - HINGE_GAP * 1.5f) / 2.0f, 0.f, LIFT_OFF, HINGE_GAP * 2, TOTAL_HEIGHT + LIFT_OFF, 0);
2310 }
2311 }
2312
2313 glPopMatrix();
2314 }
2315
2316 static void
GrayScaleCol(float * pCols)2317 GrayScaleCol(float *pCols)
2318 {
2319 float gs = (pCols[0] + pCols[1] + pCols[2]) / 2.5f; /* Slightly lighter gray */
2320 pCols[0] = pCols[1] = pCols[2] = gs;
2321 }
2322
2323 static void
GrayScale3D(Material * pMat)2324 GrayScale3D(Material * pMat)
2325 {
2326 GrayScaleCol(pMat->ambientColour);
2327 GrayScaleCol(pMat->diffuseColour);
2328 GrayScaleCol(pMat->specularColour);
2329 }
2330
2331 static void
drawTableGrayed(const BoardData3d * bd3d,renderdata tmp)2332 drawTableGrayed(const BoardData3d * bd3d, renderdata tmp)
2333 {
2334
2335 GrayScale3D(&tmp.BaseMat);
2336 GrayScale3D(&tmp.PointMat[0]);
2337 GrayScale3D(&tmp.PointMat[1]);
2338 GrayScale3D(&tmp.BoxMat);
2339
2340 drawTable(bd3d, &tmp);
2341
2342 }
2343
2344 static int
DiceShowing(const BoardData * bd)2345 DiceShowing(const BoardData * bd)
2346 {
2347 return ((bd->diceShown == DICE_ON_BOARD && bd->diceRoll[0]) ||
2348 (bd->rd->fDiceArea && bd->diceShown == DICE_BELOW_BOARD));
2349 }
2350
2351 NTH_STATIC void
drawPickAreas(const BoardData * bd,void * UNUSED (data))2352 drawPickAreas(const BoardData * bd, void *UNUSED(data))
2353 { /* Draw main board areas to see where user clicked */
2354 renderdata *prd = bd->rd;
2355 float barHeight;
2356
2357 /* boards */
2358 glLoadName(fClockwise ? 2 : 1);
2359 drawRect(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH, EDGE_HEIGHT, BASE_DEPTH, PIECE_HOLE * 6, POINT_HEIGHT, 0);
2360
2361 glLoadName(fClockwise ? 1 : 2);
2362 drawRect(TRAY_WIDTH, EDGE_HEIGHT, BASE_DEPTH, PIECE_HOLE * 6, POINT_HEIGHT, 0);
2363
2364 glLoadName(fClockwise ? 4 : 3);
2365 drawRect(TRAY_WIDTH + BOARD_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH, -PIECE_HOLE * 6, -POINT_HEIGHT, 0);
2366
2367 glLoadName(fClockwise ? 3 : 4);
2368 drawRect(TOTAL_WIDTH - TRAY_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH, -PIECE_HOLE * 6, -POINT_HEIGHT, 0);
2369
2370 /* bars + homes */
2371 barHeight = (PIECE_HOLE + PIECE_GAP_HEIGHT) * 4;
2372 glLoadName(0);
2373 drawRect(TOTAL_WIDTH / 2.0f - PIECE_HOLE / 2.0f,
2374 TOTAL_HEIGHT / 2.0f - (DOUBLECUBE_SIZE / 2.0f + barHeight + PIECE_HOLE / 2.0f), BASE_DEPTH + EDGE_DEPTH,
2375 PIECE_HOLE, barHeight, 0);
2376 glLoadName(25);
2377 drawRect(TOTAL_WIDTH / 2.0f - PIECE_HOLE / 2.0f, TOTAL_HEIGHT / 2.0f + (DOUBLECUBE_SIZE / 2.0f + PIECE_HOLE / 2.0f),
2378 BASE_DEPTH + EDGE_DEPTH, PIECE_HOLE, barHeight, 0);
2379
2380 /* Home/unused trays depend on direction */
2381 glLoadName((!fClockwise) ? 26 : POINT_UNUSED0);
2382 drawRect(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH, TRAY_WIDTH - EDGE_WIDTH * 2,
2383 TRAY_HEIGHT - EDGE_HEIGHT, 0);
2384 glLoadName((fClockwise) ? 26 : POINT_UNUSED0);
2385 drawRect(EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH, TRAY_WIDTH - EDGE_WIDTH * 2, TRAY_HEIGHT - EDGE_HEIGHT, 0);
2386
2387 glLoadName((!fClockwise) ? 27 : POINT_UNUSED1);
2388 drawRect(TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT - POINT_HEIGHT, BASE_DEPTH,
2389 TRAY_WIDTH - EDGE_WIDTH * 2, POINT_HEIGHT, 0);
2390 glLoadName((fClockwise) ? 27 : POINT_UNUSED1);
2391 drawRect(EDGE_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT - POINT_HEIGHT, BASE_DEPTH, TRAY_WIDTH - EDGE_WIDTH * 2,
2392 POINT_HEIGHT, 0);
2393
2394 /* Dice areas */
2395 glLoadName(POINT_LEFT);
2396 drawRect(TRAY_WIDTH, (TOTAL_HEIGHT - DICE_AREA_HEIGHT) / 2.0f, BASE_DEPTH, DICE_AREA_CLICK_WIDTH, DICE_AREA_HEIGHT,
2397 0);
2398 glLoadName(POINT_RIGHT);
2399 drawRect(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH, (TOTAL_HEIGHT - DICE_AREA_HEIGHT) / 2.0f, BASE_DEPTH,
2400 DICE_AREA_CLICK_WIDTH, DICE_AREA_HEIGHT, 0);
2401
2402 /* Dice */
2403 if (DiceShowing(bd)) {
2404 glLoadName(POINT_DICE);
2405 glPushMatrix();
2406 moveToDicePos(bd, 0);
2407 drawCube(getDiceSize(prd) * .95f);
2408 glPopMatrix();
2409 glPushMatrix();
2410 moveToDicePos(bd, 1);
2411 drawCube(getDiceSize(prd) * .95f);
2412 glPopMatrix();
2413 }
2414
2415 /* Double Cube */
2416 glPushMatrix();
2417 glLoadName(POINT_CUBE);
2418 moveToDoubleCubePos(bd);
2419 drawCube(DOUBLECUBE_SIZE * .95f);
2420 glPopMatrix();
2421 }
2422
2423 NTH_STATIC void
drawPickBoard(const BoardData * bd,void * data)2424 drawPickBoard(const BoardData * bd, void *data)
2425 { /* Draw points and piece objects for selected board */
2426 BoardData3d *bd3d = bd->bd3d;
2427 int selectedBoard = GPOINTER_TO_INT(data);
2428 unsigned int i, j;
2429
2430 unsigned int firstPoint = (selectedBoard - 1) * 6;
2431 /* pieces */
2432 for (i = firstPoint + 1; i <= firstPoint + 6; i++) {
2433 glLoadName(i);
2434 for (j = 1; j <= Abs(bd->points[i]); j++)
2435 drawPieceSimplified(bd3d->piecePickList, bd3d, i, j);
2436 }
2437 /* points */
2438 if (fClockwise) {
2439 int SwapBoard[4] = { 2, 1, 4, 3 };
2440 selectedBoard = SwapBoard[selectedBoard - 1];
2441 }
2442 for (i = 0; i < 6; i++) {
2443 switch (selectedBoard) {
2444 case 1:
2445 glLoadName(fClockwise ? i + 7 : 6 - i);
2446 drawRect(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH + PIECE_HOLE * i, EDGE_HEIGHT, BASE_DEPTH, PIECE_HOLE,
2447 POINT_HEIGHT, 0);
2448 break;
2449 case 2:
2450 glLoadName(fClockwise ? i + 1 : 12 - i);
2451 drawRect(TRAY_WIDTH + PIECE_HOLE * i, EDGE_HEIGHT, BASE_DEPTH, PIECE_HOLE, POINT_HEIGHT, 0);
2452 break;
2453 case 3:
2454 glLoadName(fClockwise ? i + 19 : 18 - i);
2455 drawRect(TRAY_WIDTH + BOARD_WIDTH - (PIECE_HOLE * i), TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH, -PIECE_HOLE,
2456 -POINT_HEIGHT, 0);
2457 break;
2458 case 4:
2459 glLoadName(fClockwise ? i + 13 : 24 - i);
2460 drawRect(TOTAL_WIDTH - TRAY_WIDTH - (PIECE_HOLE * i), TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH, -PIECE_HOLE,
2461 -POINT_HEIGHT, 0);
2462 break;
2463 }
2464 }
2465 }
2466
2467 static void
DrawPoint(const BoardData * bd,int point)2468 DrawPoint(const BoardData * bd, int point)
2469 {
2470 BoardData3d *bd3d = bd->bd3d;
2471 unsigned int j;
2472 glLoadName(point);
2473 for (j = 1; j <= Abs(bd->points[point]); j++)
2474 drawPiece(bd3d->piecePickList, bd3d, point, j, FALSE);
2475
2476 if (fClockwise) {
2477 point--;
2478 if (point < 6)
2479 drawRect(TRAY_WIDTH + PIECE_HOLE * point, EDGE_HEIGHT, BASE_DEPTH, PIECE_HOLE, POINT_HEIGHT, 0);
2480 else if (point < 12)
2481 drawRect(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH + PIECE_HOLE * (point - 6), EDGE_HEIGHT, BASE_DEPTH,
2482 PIECE_HOLE, POINT_HEIGHT, 0);
2483 else if (point < 18)
2484 drawRect(TOTAL_WIDTH - TRAY_WIDTH - (PIECE_HOLE * (point - 12)), TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH,
2485 -PIECE_HOLE, -POINT_HEIGHT, 0);
2486 else if (point < 24)
2487 drawRect(TRAY_WIDTH + BOARD_WIDTH - (PIECE_HOLE * (point - 18)), TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH,
2488 -PIECE_HOLE, -POINT_HEIGHT, 0);
2489 } else {
2490 if (point <= 6)
2491 drawRect(TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH + PIECE_HOLE * (6 - point), EDGE_HEIGHT, BASE_DEPTH,
2492 PIECE_HOLE, POINT_HEIGHT, 0);
2493 else if (point <= 12)
2494 drawRect(TRAY_WIDTH + PIECE_HOLE * (12 - point), EDGE_HEIGHT, BASE_DEPTH, PIECE_HOLE, POINT_HEIGHT, 0);
2495 else if (point <= 18)
2496 drawRect(TRAY_WIDTH + BOARD_WIDTH - (PIECE_HOLE * (18 - point)), TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH,
2497 -PIECE_HOLE, -POINT_HEIGHT, 0);
2498 else if (point <= 24)
2499 drawRect(TOTAL_WIDTH - TRAY_WIDTH - (PIECE_HOLE * (24 - point)), TOTAL_HEIGHT - EDGE_HEIGHT, BASE_DEPTH,
2500 -PIECE_HOLE, -POINT_HEIGHT, 0);
2501 }
2502 }
2503
2504 NTH_STATIC void
drawPickPoint(const BoardData * bd,void * data)2505 drawPickPoint(const BoardData * bd, void *data)
2506 { /* Draw all the objects on the board to see if any have been selected */
2507 int pointA = (GPOINTER_TO_INT(data)) / 100;
2508 int pointB = (GPOINTER_TO_INT(data)) - pointA * 100;
2509
2510 /* pieces on both points */
2511 DrawPoint(bd, pointA);
2512 DrawPoint(bd, pointB);
2513 }
2514
2515 static int
NearestHit(int hits,const GLuint * ptr)2516 NearestHit(int hits, const GLuint * ptr)
2517 {
2518 if (hits == 1) { /* Only one hit - just return this one */
2519 return (int) ptr[3];
2520 } else { /* Find the highest/closest object */
2521 int i, sel = -1;
2522 GLuint names;
2523 float minDepth = FLT_MAX;
2524
2525 for (i = 0; i < hits; i++) { /* for each hit */
2526 float depth;
2527
2528 names = *ptr++;
2529 depth = (float) *ptr++ / 0x7fffffff;
2530 ptr++; /* Skip max depth value */
2531 /* Ignore clicks on the board base as other objects must be closer */
2532 if (*ptr >= POINT_DICE && !(*ptr == POINT_LEFT || *ptr == POINT_RIGHT) && depth < minDepth) {
2533 minDepth = depth;
2534 sel = (int) *ptr;
2535 }
2536 ptr += names;
2537 }
2538 return sel;
2539 }
2540 }
2541
2542 static void
getProjectedPos(int x,int y,float atDepth,float pos[3])2543 getProjectedPos(int x, int y, float atDepth, float pos[3])
2544 { /* Work out where point (x, y) projects to at depth atDepth */
2545 GLint viewport[4];
2546 GLdouble mvmatrix[16], projmatrix[16];
2547 double nearX, nearY, nearZ, farX, farY, farZ, zRange;
2548
2549 glGetIntegerv(GL_VIEWPORT, viewport);
2550 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
2551 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
2552
2553 if ((gluUnProject((GLdouble) x, (GLdouble) y, 0.0, mvmatrix, projmatrix, viewport, &nearX, &nearY, &nearZ) ==
2554 GL_FALSE)
2555 || (gluUnProject((GLdouble) x, (GLdouble) y, 1.0, mvmatrix, projmatrix, viewport, &farX, &farY, &farZ) ==
2556 GL_FALSE)) {
2557 /* Maybe a g_assert_not_reached() would be appropriate here
2558 * Don't leave output parameters undefined anyway */
2559 pos[0] = pos[1] = pos[2] = 0.0f;
2560 g_print("gluUnProject failed!\n");
2561 return;
2562 }
2563
2564 zRange = (fabs(nearZ) - atDepth) / (fabs(farZ) + fabs(nearZ));
2565 pos[0] = (float) (nearX - (-farX + nearX) * zRange);
2566 pos[1] = (float) (nearY - (-farY + nearY) * zRange);
2567 pos[2] = (float) (nearZ - (-farZ + nearZ) * zRange);
2568 }
2569
2570 void
getProjectedPieceDragPos(int x,int y,float pos[3])2571 getProjectedPieceDragPos(int x, int y, float pos[3])
2572 {
2573 getProjectedPos(x, y, BASE_DEPTH + EDGE_DEPTH + DOUBLECUBE_SIZE + LIFT_OFF * 3, pos);
2574 }
2575
2576 void
calculateBackgroundSize(BoardData3d * bd3d,const GLint viewport[4])2577 calculateBackgroundSize(BoardData3d * bd3d, const GLint viewport[4])
2578 {
2579 float pos1[3], pos2[3], pos3[3];
2580
2581 getProjectedPos(0, viewport[1] + viewport[3], 0.f, pos1);
2582 getProjectedPos(viewport[2], viewport[1] + viewport[3], 0.f, pos2);
2583 getProjectedPos(0, viewport[1], 0.f, pos3);
2584
2585 bd3d->backGroundPos[0] = pos1[0];
2586 bd3d->backGroundPos[1] = pos3[1];
2587 bd3d->backGroundSize[0] = pos2[0] - pos1[0];
2588 bd3d->backGroundSize[1] = pos1[1] - pos3[1];
2589 }
2590
2591 static void
getFlagPos(const BoardData * bd,float v[3])2592 getFlagPos(const BoardData * bd, float v[3])
2593 {
2594 v[0] = (TRAY_WIDTH + BOARD_WIDTH) / 2.0f;
2595 v[1] = TOTAL_HEIGHT / 2.0f;
2596 v[2] = BASE_DEPTH + EDGE_DEPTH;
2597
2598 if (bd->turn == -1) /* Move to other side of board */
2599 v[0] += BOARD_WIDTH + BAR_WIDTH;
2600 }
2601
2602 void
waveFlag(float wag)2603 waveFlag(float wag)
2604 {
2605 int i, j;
2606
2607 /* wave the flag by rotating Z coords though a sine wave */
2608 for (i = 1; i < S_NUMPOINTS; i++)
2609 for (j = 0; j < T_NUMPOINTS; j++)
2610 flag.ctlpoints[i][j][2] = sinf((GLfloat) i + wag) * FLAG_WAG;
2611 }
2612
2613 NTH_STATIC void
drawFlagPick(const BoardData * bd,void * UNUSED (data))2614 drawFlagPick(const BoardData * bd, void *UNUSED(data))
2615 {
2616 BoardData3d *bd3d = bd->bd3d;
2617 renderdata *prd = bd->rd;
2618 int s;
2619 float v[3];
2620
2621 waveFlag(bd3d->flagWaved);
2622
2623 glLoadName(POINT_RESIGN);
2624
2625 glPushMatrix();
2626
2627 getFlagPos(bd, v);
2628 glTranslatef(v[0], v[1], v[2]);
2629
2630 /* Draw flag surface (approximation) */
2631 glBegin(GL_QUAD_STRIP);
2632 for (s = 0; s < S_NUMPOINTS; s++) {
2633 glVertex3fv(flag.ctlpoints[s][1]);
2634 glVertex3fv(flag.ctlpoints[s][0]);
2635 }
2636 glEnd();
2637
2638 /* Draw flag pole */
2639 glTranslatef(0.f, -FLAG_HEIGHT, 0.f);
2640
2641 glRotatef(-90.f, 1.f, 0.f, 0.f);
2642 gluCylinder(bd3d->qobj, (double) FLAGPOLE_WIDTH, (double) FLAGPOLE_WIDTH, (double) FLAGPOLE_HEIGHT,
2643 (GLint) prd->curveAccuracy, 1);
2644
2645 circleRev(FLAGPOLE_WIDTH, 0.f, prd->curveAccuracy);
2646 circleRev(FLAGPOLE_WIDTH * 2, FLAGPOLE_HEIGHT, prd->curveAccuracy);
2647
2648 glPopMatrix();
2649 }
2650
2651 NTH_STATIC void
drawPointPick(const BoardData * UNUSED (bd),void * data)2652 drawPointPick(const BoardData * UNUSED(bd), void *data)
2653 { /* Draw sub parts of point to work out which part of point clicked */
2654 unsigned int point = GPOINTER_TO_UINT(data);
2655
2656 if (point <= 25) { /* Split first point into 2 parts for zero and one selection */
2657 #define SPLIT_PERCENT .40f
2658 #define SPLIT_HEIGHT (PIECE_HOLE * SPLIT_PERCENT)
2659 unsigned int i;
2660 float pos[3];
2661
2662 getPiecePos(point, 1, pos);
2663
2664 glLoadName(0);
2665 if (point > 12)
2666 drawRect(pos[0] - (PIECE_HOLE / 2.0f), pos[1] + (PIECE_HOLE / 2.0f) + PIECE_GAP_HEIGHT - SPLIT_HEIGHT,
2667 pos[2], PIECE_HOLE, SPLIT_HEIGHT, 0);
2668 else
2669 drawRect(pos[0] - (PIECE_HOLE / 2.0f), pos[1] - (PIECE_HOLE / 2.0f), pos[2], PIECE_HOLE, SPLIT_HEIGHT, 0);
2670
2671 glLoadName(1);
2672 if (point > 12)
2673 drawRect(pos[0] - (PIECE_HOLE / 2.0f), pos[1] - (PIECE_HOLE / 2.0f), pos[2], PIECE_HOLE,
2674 PIECE_HOLE + PIECE_GAP_HEIGHT - SPLIT_HEIGHT, 0);
2675 else
2676 drawRect(pos[0] - (PIECE_HOLE / 2.0f), pos[1] - (PIECE_HOLE / 2.0f) + SPLIT_HEIGHT, pos[2], PIECE_HOLE,
2677 PIECE_HOLE + PIECE_GAP_HEIGHT - SPLIT_HEIGHT, 0);
2678
2679 for (i = 2; i < 6; i++) {
2680 /* Only 3 places for bar */
2681 if ((point == 0 || point == 25) && i == 4)
2682 break;
2683 getPiecePos(point, i, pos);
2684 glLoadName(i);
2685 drawRect(pos[0] - (PIECE_HOLE / 2.0f), pos[1] - (PIECE_HOLE / 2.0f), pos[2], PIECE_HOLE,
2686 PIECE_HOLE + PIECE_GAP_HEIGHT, 0);
2687 }
2688 /* extra bit */
2689 /* glLoadName(i);
2690 * if (point > 12)
2691 * {
2692 * pos[1] = pos[1] - (PIECE_HOLE / 2.0f);
2693 * drawRect(pos[0] - (PIECE_HOLE / 2.0f), TOTAL_HEIGHT - EDGE_HEIGHT - POINT_HEIGHT, pos[2], PIECE_HOLE, pos[1] - (TOTAL_HEIGHT - EDGE_HEIGHT - POINT_HEIGHT), 0);
2694 * }
2695 * else
2696 * {
2697 * pos[1] = pos[1] + (PIECE_HOLE / 2.0f) + PIECE_GAP_HEIGHT;
2698 * drawRect(pos[0] - (PIECE_HOLE / 2.0f), pos[1], pos[2], PIECE_HOLE, EDGE_HEIGHT + POINT_HEIGHT - pos[1], 0);
2699 * }
2700 */
2701 }
2702 }
2703
2704 /* 20 allows for 5 hit records (more than enough) */
2705 #define BUFSIZE 20
2706 static GLuint selectBuf[BUFSIZE];
2707
2708 typedef void (*PickDrawFun) (const BoardData * bd, void *data);
2709
2710 static int
PickDraw(int x,int y,PickDrawFun drawFun,const BoardData * bd,void * data)2711 PickDraw(int x, int y, PickDrawFun drawFun, const BoardData * bd, void *data)
2712 { /* Identify if anything is below point (x,y) */
2713 BoardData3d *bd3d = bd->bd3d;
2714 GLint hits;
2715 GLint viewport[4];
2716
2717 glSelectBuffer(BUFSIZE, selectBuf);
2718 glRenderMode(GL_SELECT);
2719 glInitNames();
2720 glPushName(0);
2721
2722 glGetIntegerv(GL_VIEWPORT, viewport);
2723
2724 glMatrixMode(GL_PROJECTION);
2725 glPushMatrix();
2726
2727 glLoadIdentity();
2728 gluPickMatrix((double) x, (double) y, 1.0, 1.0, viewport);
2729
2730 /* Setup projection matrix - using saved values */
2731 if (bd->rd->planView)
2732 glOrtho(-bd3d->horFrustrum, bd3d->horFrustrum, -bd3d->vertFrustrum, bd3d->vertFrustrum, 0.0, 5.0);
2733 else
2734 glFrustum(-bd3d->horFrustrum, bd3d->horFrustrum, -bd3d->vertFrustrum, bd3d->vertFrustrum, zNear, zFar);
2735
2736 glMatrixMode(GL_MODELVIEW);
2737 glLoadMatrixf(bd3d->modelMatrix);
2738
2739 drawFun(bd, data);
2740
2741 glPopName();
2742
2743 hits = glRenderMode(GL_RENDER);
2744
2745 glMatrixMode(GL_PROJECTION);
2746 glPopMatrix();
2747 glMatrixMode(GL_MODELVIEW);
2748
2749 return hits;
2750 }
2751
2752 int
BoardPoint3d(const BoardData * bd,int x,int y)2753 BoardPoint3d(const BoardData * bd, int x, int y)
2754 {
2755 int hits;
2756 if (bd->resigned) { /* Flag showing - just pick this */
2757 hits = PickDraw(x, y, drawFlagPick, bd, NULL);
2758 return NearestHit(hits, (GLuint *) selectBuf);
2759 } else {
2760 int picked, firstPoint, secondPoint;
2761 hits = PickDraw(x, y, drawPickAreas, bd, NULL);
2762 picked = NearestHit(hits, (GLuint *) selectBuf);
2763 if (picked <= 0 || picked > 24)
2764 return picked; /* Not a point so actual hit */
2765 g_assert(picked >= 1 && picked <= 4); /* one of 4 boards */
2766
2767 /* Work out which point in board was clicked */
2768 hits = PickDraw(x, y, drawPickBoard, bd, GINT_TO_POINTER(picked));
2769 firstPoint = (int) selectBuf[3];
2770 if (hits == 1)
2771 return firstPoint; /* Board point clicked */
2772
2773 secondPoint = (int) selectBuf[selectBuf[0] + 6];
2774 if (firstPoint == secondPoint)
2775 return firstPoint; /* Chequer clicked over point (common) */
2776
2777 /* Could be either chequer or point - work out which one */
2778 hits = PickDraw(x, y, drawPickPoint, bd, GINT_TO_POINTER(firstPoint * 100 + secondPoint));
2779 return NearestHit(hits, (GLuint *) selectBuf);
2780 }
2781 }
2782
2783 int
BoardSubPoint3d(const BoardData * bd,int x,int y,guint point)2784 BoardSubPoint3d(const BoardData * bd, int x, int y, guint point)
2785 {
2786 int hits = PickDraw(x, y, drawPointPick, bd, GUINT_TO_POINTER(point));
2787 return NearestHit(hits, (GLuint *) selectBuf);
2788 }
2789
2790 void
setupPath(const BoardData * bd,Path * p,float * pRotate,unsigned int fromPoint,unsigned int fromDepth,unsigned int toPoint,unsigned int toDepth)2791 setupPath(const BoardData * bd, Path * p, float *pRotate, unsigned int fromPoint, unsigned int fromDepth,
2792 unsigned int toPoint, unsigned int toDepth)
2793 { /* Work out the animation path for a moving piece */
2794 float point[3];
2795 float w, h, xDist, yDist;
2796 float xDiff, yDiff;
2797 float bar1Dist, bar1Ratio;
2798 float bar2Dist, bar2Ratio;
2799 float start[3], end[3], obj1, obj2, objHeight;
2800 unsigned int fromBoard = (fromPoint + 5) / 6;
2801 unsigned int toBoard = (toPoint - 1) / 6 + 1;
2802 int yDir = 0;
2803
2804 /* First work out were piece has to move */
2805 /* Get start and end points */
2806 getPiecePos(fromPoint, fromDepth, start);
2807 getPiecePos(toPoint, toDepth, end);
2808
2809 /* Only rotate piece going home */
2810 *pRotate = -1;
2811
2812 /* Swap boards if displaying other way around */
2813 if (fClockwise) {
2814 unsigned int swapBoard[] = { 0, 2, 1, 4, 3, 5 };
2815 fromBoard = swapBoard[fromBoard];
2816 toBoard = swapBoard[toBoard];
2817 }
2818
2819 /* Work out what obstacle needs to be avoided */
2820 if ((fromBoard == 2 || fromBoard == 3) && (toBoard == 1 || toBoard == 4)) { /* left side to right side */
2821 obj1 = TRAY_WIDTH + BOARD_WIDTH;
2822 obj2 = obj1 + BAR_WIDTH;
2823 objHeight = BASE_DEPTH + EDGE_DEPTH + DOUBLECUBE_SIZE;
2824 } else if ((fromBoard == 1 || fromBoard == 4) && (toBoard == 2 || toBoard == 3)) { /* right side to left side */
2825 obj2 = TRAY_WIDTH + BOARD_WIDTH;
2826 obj1 = obj2 + BAR_WIDTH;
2827 objHeight = BASE_DEPTH + EDGE_DEPTH + DOUBLECUBE_SIZE;
2828 } else if ((fromBoard == 1 && toBoard == 4) || (fromBoard == 2 && toBoard == 3)) { /* up same side */
2829 obj1 = (TOTAL_HEIGHT - DICE_AREA_HEIGHT) / 2.0f;
2830 obj2 = (TOTAL_HEIGHT + DICE_AREA_HEIGHT) / 2.0f;
2831 objHeight = BASE_DEPTH + getDiceSize(bd->rd);
2832 yDir = 1;
2833 } else if ((fromBoard == 4 && toBoard == 1) || (fromBoard == 3 && toBoard == 2)) { /* down same side */
2834 obj1 = (TOTAL_HEIGHT + DICE_AREA_HEIGHT) / 2.0f;
2835 obj2 = (TOTAL_HEIGHT - DICE_AREA_HEIGHT) / 2.0f;
2836 objHeight = BASE_DEPTH + getDiceSize(bd->rd);
2837 yDir = 1;
2838 } else if (fromBoard == toBoard) {
2839 if (fromBoard <= 2) {
2840 if (fClockwise) {
2841 fromPoint = 13 - fromPoint;
2842 toPoint = 13 - toPoint;
2843 }
2844
2845 if (fromPoint < toPoint)
2846 toPoint--;
2847 else
2848 fromPoint--;
2849
2850 fromPoint = 12 - fromPoint;
2851 toPoint = 12 - toPoint;
2852 } else {
2853 if (fClockwise) {
2854 fromPoint = 24 + 13 - fromPoint;
2855 toPoint = 24 + 13 - toPoint;
2856 }
2857
2858 if (fromPoint < toPoint)
2859 fromPoint++;
2860 else
2861 toPoint++;
2862 fromPoint = fromPoint - 13;
2863 toPoint = toPoint - 13;
2864 }
2865 obj1 = TRAY_WIDTH + PIECE_HOLE * fromPoint;
2866 obj2 = TRAY_WIDTH + PIECE_HOLE * toPoint;
2867 if ((fromBoard == 1) || (fromBoard == 4)) {
2868 obj1 += BAR_WIDTH;
2869 obj2 += BAR_WIDTH;
2870 }
2871
2872 objHeight = BASE_DEPTH + PIECE_DEPTH * 3;
2873 } else {
2874 if (fromPoint == 0 || fromPoint == 25) { /* Move from bar */
2875 if (!fClockwise) {
2876 obj1 = TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH;
2877 if (fromPoint == 0) {
2878 obj2 = TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH;
2879 if (toPoint > 20)
2880 obj2 += PIECE_HOLE * (toPoint - 20);
2881 } else {
2882 obj2 = TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH;
2883 if (toPoint < 5)
2884 obj2 += PIECE_HOLE * (5 - toPoint);
2885 }
2886 } else {
2887 obj1 = TRAY_WIDTH + BOARD_WIDTH;
2888 if (fromPoint == 0) {
2889 obj2 = TRAY_WIDTH + PIECE_HOLE * (25 - toPoint);
2890 if (toPoint > 19)
2891 obj2 += PIECE_HOLE;
2892 } else {
2893 obj2 = TRAY_WIDTH + PIECE_HOLE * toPoint;
2894 if (toPoint < 6)
2895 obj2 += PIECE_HOLE;
2896 }
2897 }
2898 objHeight = BASE_DEPTH + EDGE_DEPTH + DOUBLECUBE_SIZE;
2899 } else { /* Move home */
2900 if (!fClockwise) {
2901 if (toPoint == 26)
2902 obj1 = TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH + PIECE_HOLE * (7 - fromPoint);
2903 else /* (toPoint == 27) */
2904 obj1 = TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH + PIECE_HOLE * (fromPoint - 18);
2905 } else {
2906 if (toPoint == 26)
2907 obj1 = TRAY_WIDTH + PIECE_HOLE * (fromPoint - 1);
2908 else /* (toPoint == 27) */
2909 obj1 = TRAY_WIDTH + PIECE_HOLE * (24 - fromPoint);
2910 }
2911
2912 if (!fClockwise)
2913 obj2 = TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH;
2914 else
2915 obj2 = TRAY_WIDTH - EDGE_WIDTH;
2916
2917 *pRotate = 0;
2918 objHeight = BASE_DEPTH + EDGE_DEPTH + getDiceSize(bd->rd);
2919 }
2920 }
2921 if ((fromBoard == 3 && toBoard == 4) || (fromBoard == 4 && toBoard == 3)) { /* Special case when moving along top of board */
2922 if ((bd->cube_owner != 1) && (fromDepth <= 2) && (toDepth <= 2))
2923 objHeight = BASE_DEPTH + EDGE_DEPTH + PIECE_DEPTH;
2924 }
2925
2926 /* Now setup path object */
2927 /* Start point */
2928 initPath(p, start);
2929
2930 /* obstacle height */
2931 point[2] = objHeight;
2932
2933 if (yDir) { /* barriers are along y axis */
2934 xDiff = end[0] - start[0];
2935 yDiff = end[1] - start[1];
2936 bar1Dist = obj1 - start[1];
2937 bar1Ratio = bar1Dist / yDiff;
2938 bar2Dist = obj2 - start[1];
2939 bar2Ratio = bar2Dist / yDiff;
2940
2941 /* 2nd point - moved up from 1st one */
2942 /* Work out whether 2nd point is further away than height required */
2943 xDist = xDiff * bar1Ratio;
2944 yDist = obj1 - start[1];
2945 h = objHeight - start[2];
2946 w = sqrtf(xDist * xDist + yDist * yDist);
2947
2948 if (h > w) {
2949 point[0] = start[0] + xDiff * bar1Ratio;
2950 point[1] = obj1;
2951 } else {
2952 point[0] = start[0] + xDist * (h / w);
2953 point[1] = start[1] + yDist * (h / w);
2954 }
2955 addPathSegment(p, PATH_CURVE_9TO12, point);
2956
2957 /* Work out whether 3rd point is further away than height required */
2958 yDist = end[1] - obj2;
2959 xDist = xDiff * (yDist / yDiff);
2960 w = sqrtf(xDist * xDist + yDist * yDist);
2961 h = objHeight - end[2];
2962
2963 /* 3rd point - moved along from 2nd one */
2964 if (h > w) {
2965 point[0] = start[0] + xDiff * bar2Ratio;
2966 point[1] = obj2;
2967 } else {
2968 point[0] = end[0] - xDist * (h / w);
2969 point[1] = end[1] - yDist * (h / w);
2970 }
2971 addPathSegment(p, PATH_LINE, point);
2972 } else { /* barriers are along x axis */
2973 xDiff = end[0] - start[0];
2974 yDiff = end[1] - start[1];
2975 bar1Dist = obj1 - start[0];
2976 bar1Ratio = bar1Dist / xDiff;
2977 bar2Dist = obj2 - start[0];
2978 bar2Ratio = bar2Dist / xDiff;
2979
2980 /* Work out whether 2nd point is further away than height required */
2981 xDist = obj1 - start[0];
2982 yDist = yDiff * bar1Ratio;
2983 h = objHeight - start[2];
2984 w = sqrtf(xDist * xDist + yDist * yDist);
2985
2986 /* 2nd point - moved up from 1st one */
2987 if (h > w) {
2988 point[0] = obj1;
2989 point[1] = start[1] + yDiff * bar1Ratio;
2990 } else {
2991 point[0] = start[0] + xDist * (h / w);
2992 point[1] = start[1] + yDist * (h / w);
2993 }
2994 addPathSegment(p, PATH_CURVE_9TO12, point);
2995
2996 /* Work out whether 3rd point is further away than height required */
2997 xDist = end[0] - obj2;
2998 yDist = yDiff * (xDist / xDiff);
2999 w = sqrtf(xDist * xDist + yDist * yDist);
3000 h = objHeight - end[2];
3001
3002 /* 3rd point - moved along from 2nd one */
3003 if (h > w) {
3004 point[0] = obj2;
3005 point[1] = start[1] + yDiff * bar2Ratio;
3006 } else {
3007 point[0] = end[0] - xDist * (h / w);
3008 point[1] = end[1] - yDist * (h / w);
3009 }
3010 addPathSegment(p, PATH_LINE, point);
3011 }
3012 /* End point */
3013 addPathSegment(p, PATH_CURVE_12TO3, end);
3014 }
3015
3016 static void
setupDicePath(int num,float stepSize,Path * p,const BoardData * bd)3017 setupDicePath(int num, float stepSize, Path * p, const BoardData * bd)
3018 {
3019 float point[3];
3020 getDicePos(bd, num, point);
3021
3022 point[0] -= stepSize * 5;
3023 initPath(p, point);
3024
3025 point[0] += stepSize * 2;
3026 addPathSegment(p, PATH_PARABOLA_12TO3, point);
3027
3028 point[0] += stepSize * 2;
3029 addPathSegment(p, PATH_PARABOLA, point);
3030
3031 point[0] += stepSize;
3032 addPathSegment(p, PATH_PARABOLA, point);
3033 }
3034
3035 static void
randomDiceRotation(const Path * p,DiceRotation * diceRotation,int dir)3036 randomDiceRotation(const Path * p, DiceRotation * diceRotation, int dir)
3037 {
3038 /* Dice rotation range values */
3039 #define XROT_MIN 1
3040 #define XROT_RANGE 1.5f
3041
3042 #define YROT_MIN -.5f
3043 #define YROT_RANGE 1.f
3044
3045 diceRotation->xRotFactor = XROT_MIN + randRange(XROT_RANGE);
3046 diceRotation->xRotStart = 1 - (p->pts[p->numSegments][0] - p->pts[0][0]) * diceRotation->xRotFactor;
3047 diceRotation->xRot = diceRotation->xRotStart * 360;
3048
3049 diceRotation->yRotFactor = YROT_MIN + randRange(YROT_RANGE);
3050 diceRotation->yRotStart = 1 - (p->pts[p->numSegments][0] - p->pts[0][0]) * diceRotation->yRotFactor;
3051 diceRotation->yRot = diceRotation->yRotStart * 360;
3052
3053 if (dir == -1) {
3054 diceRotation->xRotFactor = -diceRotation->xRotFactor;
3055 diceRotation->yRotFactor = -diceRotation->yRotFactor;
3056 }
3057 }
3058
3059 void
setupDicePaths(const BoardData * bd,Path dicePaths[2],float diceMovingPos[2][3],DiceRotation diceRotation[2])3060 setupDicePaths(const BoardData * bd, Path dicePaths[2], float diceMovingPos[2][3], DiceRotation diceRotation[2])
3061 {
3062 int firstDie = (bd->turn == 1);
3063 int secondDie = !firstDie;
3064 int dir = (bd->turn == 1) ? -1 : 1;
3065
3066 setupDicePath(firstDie, dir * DICE_STEP_SIZE0, &dicePaths[firstDie], bd);
3067 setupDicePath(secondDie, dir * DICE_STEP_SIZE1, &dicePaths[secondDie], bd);
3068
3069 randomDiceRotation(&dicePaths[firstDie], &diceRotation[firstDie], dir);
3070 randomDiceRotation(&dicePaths[secondDie], &diceRotation[secondDie], dir);
3071
3072 copyPoint(diceMovingPos[0], dicePaths[0].pts[0]);
3073 copyPoint(diceMovingPos[1], dicePaths[1].pts[0]);
3074 }
3075
3076 int
DiceTooClose(const BoardData3d * bd3d,const renderdata * prd)3077 DiceTooClose(const BoardData3d * bd3d, const renderdata * prd)
3078 {
3079 float dist;
3080 float orgX[2];
3081 int firstDie = bd3d->dicePos[0][0] > bd3d->dicePos[1][0];
3082 int secondDie = !firstDie;
3083
3084 orgX[0] = bd3d->dicePos[firstDie][0] - DICE_STEP_SIZE0 * 5;
3085 orgX[1] = bd3d->dicePos[secondDie][0] - DICE_STEP_SIZE1 * 5;
3086 dist = sqrtf((orgX[1] - orgX[0]) * (orgX[1] - orgX[0])
3087 + (bd3d->dicePos[secondDie][1] - bd3d->dicePos[firstDie][1]) * (bd3d->dicePos[secondDie][1] -
3088 bd3d->dicePos[firstDie][1]));
3089 return (dist < getDiceSize(prd) * 1.1f);
3090 }
3091
3092 void
setDicePos(BoardData * bd,BoardData3d * bd3d)3093 setDicePos(BoardData * bd, BoardData3d * bd3d)
3094 {
3095 int iter = 0;
3096 float diceSize = getDiceSize(bd->rd);
3097 float firstX = TRAY_WIDTH + DICE_STEP_SIZE0 * 3 + diceSize * .75f;
3098 int firstDie = (bd->turn == 1);
3099 int secondDie = !firstDie;
3100
3101 bd3d->dicePos[firstDie][0] = firstX + randRange(BOARD_WIDTH + TRAY_WIDTH - firstX - diceSize * 2);
3102 bd3d->dicePos[firstDie][1] = randRange(DICE_AREA_HEIGHT);
3103
3104 do { /* insure dice are not too close together */
3105 if (iter++ > 20) { /* Trouble placing 2nd dice - replace 1st dice */
3106 setDicePos(bd, bd3d);
3107 return;
3108 }
3109
3110 firstX = bd3d->dicePos[firstDie][0] + diceSize;
3111 bd3d->dicePos[secondDie][0] = firstX + randRange(BOARD_WIDTH + TRAY_WIDTH - firstX - diceSize * .7f);
3112 bd3d->dicePos[secondDie][1] = randRange(DICE_AREA_HEIGHT);
3113 }
3114 while (DiceTooClose(bd3d, bd->rd));
3115
3116 bd3d->dicePos[firstDie][2] = (float) (rand() % 360);
3117 bd3d->dicePos[secondDie][2] = (float) (rand() % 360);
3118
3119 if (ShadowsInitilised(bd3d))
3120 updateDiceOccPos(bd, bd3d);
3121 }
3122
3123 NTH_STATIC void
drawDie(const BoardData * bd,const BoardData3d * bd3d,int num)3124 drawDie(const BoardData * bd, const BoardData3d * bd3d, int num)
3125 {
3126 glPushMatrix();
3127 /* Move to correct position for die */
3128 if (bd3d->shakingDice) {
3129 glTranslatef(bd3d->diceMovingPos[num][0], bd3d->diceMovingPos[num][1], bd3d->diceMovingPos[num][2]);
3130 glRotatef(bd3d->diceRotation[num].xRot, 0.f, 1.f, 0.f);
3131 glRotatef(bd3d->diceRotation[num].yRot, 1.f, 0.f, 0.f);
3132 glRotatef(bd3d->dicePos[num][2], 0.f, 0.f, 1.f);
3133 } else
3134 moveToDicePos(bd, num);
3135 /* Now draw dice */
3136 drawDice(bd, num);
3137
3138 glPopMatrix();
3139 }
3140
3141 static void
initViewArea(viewArea * pva)3142 initViewArea(viewArea * pva)
3143 { /* Initialize values to extremes */
3144 pva->top = -base_unit * 1000;
3145 pva->bottom = base_unit * 1000;
3146 pva->width = 0;
3147 }
3148
3149 static float
getViewAreaHeight(const viewArea * pva)3150 getViewAreaHeight(const viewArea * pva)
3151 {
3152 return pva->top - pva->bottom;
3153 }
3154
3155 static float
getViewAreaWidth(const viewArea * pva)3156 getViewAreaWidth(const viewArea * pva)
3157 {
3158 return pva->width;
3159 }
3160
3161 static float
getAreaRatio(const viewArea * pva)3162 getAreaRatio(const viewArea * pva)
3163 {
3164 return getViewAreaWidth(pva) / getViewAreaHeight(pva);
3165 }
3166
3167 static void
addViewAreaHeightPoint(viewArea * pva,float halfRadianFOV,float boardRadAngle,float inY,float inZ)3168 addViewAreaHeightPoint(viewArea * pva, float halfRadianFOV, float boardRadAngle, float inY, float inZ)
3169 { /* Rotate points by board angle */
3170 float adj;
3171 float y, z;
3172
3173 y = inY * cosf(boardRadAngle) - inZ * sinf(boardRadAngle);
3174 z = inZ * cosf(boardRadAngle) + inY * sinf(boardRadAngle);
3175
3176 /* Project height to zero depth */
3177 adj = z * tanf(halfRadianFOV);
3178 if (y > 0)
3179 y += adj;
3180 else
3181 y -= adj;
3182
3183 /* Store max / min heights */
3184 if (pva->top < y)
3185 pva->top = y;
3186 if (pva->bottom > y)
3187 pva->bottom = y;
3188 }
3189
3190 static void
workOutWidth(viewArea * pva,float halfRadianFOV,float boardRadAngle,float aspectRatio,const float ip[3])3191 workOutWidth(viewArea * pva, float halfRadianFOV, float boardRadAngle, float aspectRatio, const float ip[3])
3192 {
3193 float halfRadianXFOV;
3194 float w = getViewAreaHeight(pva) * aspectRatio;
3195 float w2, l;
3196
3197 float p[3];
3198
3199 /* Work out X-FOV from Y-FOV */
3200 float halfViewHeight = getViewAreaHeight(pva) / 2;
3201 l = halfViewHeight / tanf(halfRadianFOV);
3202 halfRadianXFOV = atanf((halfViewHeight * aspectRatio) / l);
3203
3204 /* Rotate z coord by board angle */
3205 copyPoint(p, ip);
3206 p[2] = ip[2] * cosf(boardRadAngle) + ip[1] * sinf(boardRadAngle);
3207
3208 /* Adjust x coord by projected z value at relevant X-FOV */
3209 w2 = w / 2 - p[2] * tanf(halfRadianXFOV);
3210 l = w2 / tanf(halfRadianXFOV);
3211 p[0] += p[2] * (p[0] / l);
3212
3213 if (pva->width < p[0] * 2)
3214 pva->width = p[0] * 2;
3215 }
3216
3217 NTH_STATIC float
GetFOVAngle(const BoardData * bd)3218 GetFOVAngle(const BoardData * bd)
3219 {
3220 float temp = bd->rd->boardAngle / 20.0f;
3221 float skewFactor = (bd->rd->skewFactor / 100.0f) * (4 - .6f) + .6f;
3222 /* Magic numbers to normalize viewing distance */
3223 return (47 - 2.3f * temp * temp) / skewFactor;
3224 }
3225
3226 static void
WorkOutViewArea(const BoardData * bd,viewArea * pva,float * pHalfRadianFOV,float aspectRatio)3227 WorkOutViewArea(const BoardData * bd, viewArea * pva, float *pHalfRadianFOV, float aspectRatio)
3228 {
3229 float p[3];
3230 float boardRadAngle;
3231 initViewArea(pva);
3232
3233 boardRadAngle = (bd->rd->boardAngle * (float) G_PI) / 180.0f;
3234 *pHalfRadianFOV = ((GetFOVAngle(bd) * (float) G_PI) / 180.0f) / 2.0f;
3235
3236 /* Sort out viewing area */
3237 addViewAreaHeightPoint(pva, *pHalfRadianFOV, boardRadAngle, -getBoardHeight() / 2, 0.f);
3238 addViewAreaHeightPoint(pva, *pHalfRadianFOV, boardRadAngle, -getBoardHeight() / 2, BASE_DEPTH + EDGE_DEPTH);
3239
3240 if (bd->rd->fDiceArea) {
3241 float diceSize = getDiceSize(bd->rd);
3242 addViewAreaHeightPoint(pva, *pHalfRadianFOV, boardRadAngle, getBoardHeight() / 2 + diceSize, 0.f);
3243 addViewAreaHeightPoint(pva, *pHalfRadianFOV, boardRadAngle, getBoardHeight() / 2 + diceSize,
3244 BASE_DEPTH + diceSize);
3245 } else { /* Bottom edge is defined by board */
3246 addViewAreaHeightPoint(pva, *pHalfRadianFOV, boardRadAngle, getBoardHeight() / 2, 0.f);
3247 addViewAreaHeightPoint(pva, *pHalfRadianFOV, boardRadAngle, getBoardHeight() / 2, BASE_DEPTH + EDGE_DEPTH);
3248 }
3249
3250 p[0] = getBoardWidth() / 2;
3251 p[1] = getBoardHeight() / 2;
3252 p[2] = BASE_DEPTH + EDGE_DEPTH;
3253 workOutWidth(pva, *pHalfRadianFOV, boardRadAngle, aspectRatio, p);
3254 }
3255
3256 void
SetupPerspVolume(const BoardData * bd,BoardData3d * bd3d,const renderdata * prd,GLint viewport[4])3257 SetupPerspVolume(const BoardData * bd, BoardData3d * bd3d, const renderdata * prd, GLint viewport[4])
3258 {
3259 float aspectRatio = (float) viewport[2] / (float) (viewport[3]);
3260 if (!prd->planView) {
3261 viewArea va;
3262 float halfRadianFOV;
3263 double fovScale;
3264 float zoom;
3265
3266 if (aspectRatio < .5f) { /* Viewing area to high - cut down so board rendered correctly */
3267 int newHeight = viewport[2] * 2;
3268 viewport[1] = (viewport[3] - newHeight) / 2;
3269 viewport[3] = newHeight;
3270 glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
3271 aspectRatio = .5f;
3272 /* Clear screen so top + bottom outside board shown ok */
3273 ClearScreen(prd);
3274 }
3275
3276 /* Workout how big the board is (in 3d space) */
3277 WorkOutViewArea(bd, &va, &halfRadianFOV, aspectRatio);
3278
3279 fovScale = zNear * tanf(halfRadianFOV);
3280
3281 if (aspectRatio > getAreaRatio(&va)) {
3282 bd3d->vertFrustrum = fovScale;
3283 bd3d->horFrustrum = bd3d->vertFrustrum * aspectRatio;
3284 } else {
3285 bd3d->horFrustrum = fovScale * getAreaRatio(&va);
3286 bd3d->vertFrustrum = bd3d->horFrustrum / aspectRatio;
3287 }
3288 /* Setup projection matrix */
3289 glFrustum(-bd3d->horFrustrum, bd3d->horFrustrum, -bd3d->vertFrustrum, bd3d->vertFrustrum, zNear, zFar);
3290
3291 /* Setup modelview matrix */
3292 glMatrixMode(GL_MODELVIEW);
3293 glLoadIdentity();
3294
3295 /* Zoom back so image fills window */
3296 zoom = (getViewAreaHeight(&va) / 2) / tanf(halfRadianFOV);
3297 glTranslatef(0.f, 0.f, -zoom);
3298
3299 /* Offset from centre because of perspective */
3300 glTranslatef(0.f, getViewAreaHeight(&va) / 2 + va.bottom, 0.f);
3301
3302 /* Rotate board */
3303 glRotatef((float) prd->boardAngle, -1.f, 0.f, 0.f);
3304
3305 /* Origin is bottom left, so move from centre */
3306 glTranslatef(-(getBoardWidth() / 2.0f), -((getBoardHeight()) / 2.0f), 0.f);
3307 } else {
3308 float size;
3309
3310 if (aspectRatio > getBoardWidth() / getBoardHeight()) {
3311 size = (getBoardHeight() / 2);
3312 bd3d->horFrustrum = size * aspectRatio;
3313 bd3d->vertFrustrum = size;
3314 } else {
3315 size = (getBoardWidth() / 2);
3316 bd3d->horFrustrum = size;
3317 bd3d->vertFrustrum = size / aspectRatio;
3318 }
3319 glOrtho(-bd3d->horFrustrum, bd3d->horFrustrum, -bd3d->vertFrustrum, bd3d->vertFrustrum, 0.0, 5.0);
3320
3321 glMatrixMode(GL_MODELVIEW);
3322 glLoadIdentity();
3323
3324 glTranslatef(-(getBoardWidth() / 2.0f), -(getBoardHeight() / 2.0f), -3.f);
3325 }
3326
3327 /* Save matrix for later */
3328 glGetFloatv(GL_MODELVIEW_MATRIX, bd3d->modelMatrix);
3329 }
3330
3331 extern void
SetupFlag(void)3332 SetupFlag(void)
3333 {
3334 int i;
3335 float width = FLAG_WIDTH;
3336 float height = FLAG_HEIGHT;
3337
3338 flag.flagNurb = NULL;
3339
3340 for (i = 0; i < S_NUMPOINTS; i++) {
3341 flag.ctlpoints[i][0][0] = width / (S_NUMPOINTS - 1) * i;
3342 flag.ctlpoints[i][1][0] = width / (S_NUMPOINTS - 1) * i;
3343 flag.ctlpoints[i][0][1] = 0;
3344 flag.ctlpoints[i][1][1] = height;
3345 flag.ctlpoints[i][0][2] = 0;
3346 flag.ctlpoints[i][1][2] = 0;
3347 }
3348 }
3349
3350 NTH_STATIC void
renderFlag(const BoardData * bd,const BoardData3d * bd3d,unsigned int curveAccuracy)3351 renderFlag(const BoardData * bd, const BoardData3d * bd3d, unsigned int curveAccuracy)
3352 {
3353 /* Simple knots i.e. no weighting */
3354 float s_knots[S_NUMKNOTS] = { 0, 0, 0, 0, 1, 1, 1, 1 };
3355 float t_knots[T_NUMKNOTS] = { 0, 0, 1, 1 };
3356
3357 /* Draw flag surface */
3358 setMaterial(&bd3d->flagMat);
3359
3360 if (flag.flagNurb == NULL)
3361 flag.flagNurb = gluNewNurbsRenderer();
3362
3363 /* Set size of polygons */
3364 gluNurbsProperty(flag.flagNurb, GLU_SAMPLING_TOLERANCE, 500.0f / curveAccuracy);
3365
3366 gluBeginSurface(flag.flagNurb);
3367 gluNurbsSurface(flag.flagNurb, S_NUMKNOTS, s_knots, T_NUMKNOTS, t_knots, 3 * T_NUMPOINTS, 3,
3368 &flag.ctlpoints[0][0][0], S_NUMPOINTS, T_NUMPOINTS, GL_MAP2_VERTEX_3);
3369 gluEndSurface(flag.flagNurb);
3370
3371 /* Draw flag pole */
3372 glPushMatrix();
3373
3374 glTranslatef(-FLAGPOLE_WIDTH, -FLAG_HEIGHT, 0.f);
3375
3376 glRotatef(-90.f, 1.f, 0.f, 0.f);
3377 SetColour3d(.2f, .2f, .4f, 0.f); /* Blue pole */
3378 gluCylinder(bd3d->qobj, (double) FLAGPOLE_WIDTH, (double) FLAGPOLE_WIDTH, (double) FLAGPOLE_HEIGHT,
3379 (GLint) curveAccuracy, 1);
3380
3381 circleRev(FLAGPOLE_WIDTH, 0.f, curveAccuracy);
3382 circleRev(FLAGPOLE_WIDTH * 2, FLAGPOLE_HEIGHT, curveAccuracy);
3383
3384 glPopMatrix();
3385
3386 /* Draw number on flag */
3387 glDisable(GL_DEPTH_TEST);
3388
3389 setMaterial(&bd3d->flagNumberMat);
3390
3391 glPushMatrix();
3392 {
3393 /* Move to middle of flag */
3394 float v[3];
3395 v[0] = (flag.ctlpoints[1][0][0] + flag.ctlpoints[2][0][0]) / 2.0f;
3396 v[1] = (flag.ctlpoints[1][0][0] + flag.ctlpoints[1][1][0]) / 2.0f;
3397 v[2] = (flag.ctlpoints[1][0][2] + flag.ctlpoints[2][0][2]) / 2.0f;
3398 glTranslatef(v[0], v[1], v[2]);
3399 }
3400 {
3401 /* Work out approx angle of number based on control points */
3402 float ang =
3403 atanf(-(flag.ctlpoints[2][0][2] - flag.ctlpoints[1][0][2]) /
3404 (flag.ctlpoints[2][0][0] - flag.ctlpoints[1][0][0]));
3405 float degAng = (ang) * 180 / (float) G_PI;
3406
3407 glRotatef(degAng, 0.f, 1.f, 0.f);
3408 }
3409
3410 {
3411 /* Draw number */
3412 char flagValue[2] = "x";
3413 /* No specular light */
3414 float specular[4];
3415 float zero[4] = { 0, 0, 0, 0 };
3416 glGetLightfv(GL_LIGHT0, GL_SPECULAR, specular);
3417 glLightfv(GL_LIGHT0, GL_SPECULAR, zero);
3418
3419 flagValue[0] = '0' + (char) abs(bd->resigned);
3420 glScalef(1.3f, 1.3f, 1.f);
3421
3422 glLineWidth(.5f);
3423 glPrintCube(bd3d->cubeFont, flagValue);
3424
3425 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
3426 }
3427 glPopMatrix();
3428
3429 glEnable(GL_DEPTH_TEST);
3430 }
3431
3432 static void
drawFlag(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)3433 drawFlag(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
3434 {
3435 float v[4];
3436 int isStencil = glIsEnabled(GL_STENCIL_TEST);
3437
3438 if (isStencil)
3439 glDisable(GL_STENCIL_TEST);
3440
3441 waveFlag(bd3d->flagWaved);
3442
3443 glPushMatrix();
3444
3445 getFlagPos(bd, v);
3446 glTranslatef(v[0], v[1], v[2]);
3447
3448 renderFlag(bd, bd3d, prd->curveAccuracy);
3449
3450 glPopMatrix();
3451 if (isStencil)
3452 glEnable(GL_STENCIL_TEST);
3453 }
3454
3455 static void
updateDieOccPos(const BoardData * bd,const BoardData3d * bd3d,Occluder * pOcc,int num)3456 updateDieOccPos(const BoardData * bd, const BoardData3d * bd3d, Occluder * pOcc, int num)
3457 {
3458 float id[4][4];
3459
3460 if (bd3d->shakingDice) {
3461 copyPoint(pOcc->trans, bd3d->diceMovingPos[num]);
3462
3463 pOcc->rot[0] = bd3d->diceRotation[num].xRot;
3464 pOcc->rot[1] = bd3d->diceRotation[num].yRot;
3465 pOcc->rot[2] = bd3d->dicePos[num][2];
3466
3467 makeInverseRotateMatrixZ(pOcc->invMat, pOcc->rot[2]);
3468
3469 makeInverseRotateMatrixX(id, pOcc->rot[1]);
3470 matrixmult(pOcc->invMat, (ConstMatrix) id);
3471
3472 makeInverseRotateMatrixY(id, pOcc->rot[0]);
3473 matrixmult(pOcc->invMat, (ConstMatrix) id);
3474
3475 makeInverseTransposeMatrix(id, pOcc->trans);
3476 matrixmult(pOcc->invMat, (ConstMatrix) id);
3477 } else {
3478 getDicePos(bd, num, pOcc->trans);
3479
3480 makeInverseTransposeMatrix(id, pOcc->trans);
3481
3482 if (bd->diceShown == DICE_ON_BOARD) {
3483 pOcc->rot[0] = pOcc->rot[1] = 0;
3484 pOcc->rot[2] = bd3d->dicePos[num][2];
3485
3486 makeInverseRotateMatrixZ(pOcc->invMat, pOcc->rot[2]);
3487 matrixmult(pOcc->invMat, (ConstMatrix) id);
3488 } else {
3489 pOcc->rot[0] = pOcc->rot[1] = pOcc->rot[2] = 0;
3490 copyMatrix(pOcc->invMat, id);
3491 }
3492 }
3493 if (ShadowsInitilised(bd3d))
3494 draw_shadow_volume_extruded_edges(pOcc, bd3d->shadow_light_position, GL_QUADS);
3495 }
3496
3497 void
updateDiceOccPos(const BoardData * bd,BoardData3d * bd3d)3498 updateDiceOccPos(const BoardData * bd, BoardData3d * bd3d)
3499 {
3500 int show = DiceShowing(bd);
3501
3502 bd3d->Occluders[OCC_DICE1].show = bd3d->Occluders[OCC_DICE2].show = show;
3503 if (show) {
3504 updateDieOccPos(bd, bd3d, &bd3d->Occluders[OCC_DICE1], 0);
3505 updateDieOccPos(bd, bd3d, &bd3d->Occluders[OCC_DICE2], 1);
3506 }
3507 }
3508
3509 NTH_STATIC void
updateCubeOccPos(const BoardData * bd,BoardData3d * bd3d)3510 updateCubeOccPos(const BoardData * bd, BoardData3d * bd3d)
3511 {
3512 getDoubleCubePos(bd, bd3d->Occluders[OCC_CUBE].trans);
3513 makeInverseTransposeMatrix(bd3d->Occluders[OCC_CUBE].invMat, bd3d->Occluders[OCC_CUBE].trans);
3514
3515 bd3d->Occluders[OCC_CUBE].show = (bd->cube_use && !bd->crawford_game);
3516 if (ShadowsInitilised(bd3d))
3517 draw_shadow_volume_extruded_edges(&bd3d->Occluders[OCC_CUBE], bd3d->shadow_light_position, GL_QUADS);
3518 }
3519
3520 void
updateMovingPieceOccPos(const BoardData * bd,BoardData3d * bd3d)3521 updateMovingPieceOccPos(const BoardData * bd, BoardData3d * bd3d)
3522 {
3523 if (bd->drag_point >= 0) {
3524 copyPoint(bd3d->Occluders[LAST_PIECE].trans, bd3d->dragPos);
3525 makeInverseTransposeMatrix(bd3d->Occluders[LAST_PIECE].invMat, bd3d->Occluders[LAST_PIECE].trans);
3526 } else { /* if (bd3d->moving) */
3527
3528 copyPoint(bd3d->Occluders[LAST_PIECE].trans, bd3d->movingPos);
3529
3530 if (bd3d->rotateMovingPiece > 0) { /* rotate shadow as piece is put in bear off tray */
3531 float id[4][4];
3532
3533 bd3d->Occluders[LAST_PIECE].rotator = 1;
3534 bd3d->Occluders[LAST_PIECE].rot[1] = -90 * bd3d->rotateMovingPiece * bd->turn;
3535 makeInverseTransposeMatrix(id, bd3d->Occluders[LAST_PIECE].trans);
3536 makeInverseRotateMatrixX(bd3d->Occluders[LAST_PIECE].invMat, bd3d->Occluders[LAST_PIECE].rot[1]);
3537 matrixmult(bd3d->Occluders[LAST_PIECE].invMat, (ConstMatrix) id);
3538 } else
3539 makeInverseTransposeMatrix(bd3d->Occluders[LAST_PIECE].invMat, bd3d->Occluders[LAST_PIECE].trans);
3540 }
3541 if (ShadowsInitilised(bd3d))
3542 draw_shadow_volume_extruded_edges(&bd3d->Occluders[LAST_PIECE], bd3d->shadow_light_position, GL_QUADS);
3543 }
3544
3545 void
updatePieceOccPos(const BoardData * bd,BoardData3d * bd3d)3546 updatePieceOccPos(const BoardData * bd, BoardData3d * bd3d)
3547 {
3548 unsigned int i, j, p = FIRST_PIECE;
3549
3550 for (i = 0; i < 28; i++) {
3551 for (j = 1; j <= Abs(bd->points[i]); j++) {
3552 if (p > LAST_PIECE)
3553 break; /* Found all pieces */
3554 getPiecePos(i, j, bd3d->Occluders[p].trans);
3555
3556 if (i == 26 || i == 27) { /* bars */
3557 float id[4][4];
3558
3559 bd3d->Occluders[p].rotator = 1;
3560 if (i == 26)
3561 bd3d->Occluders[p].rot[1] = -90;
3562 else
3563 bd3d->Occluders[p].rot[1] = 90;
3564 makeInverseTransposeMatrix(id, bd3d->Occluders[p].trans);
3565 makeInverseRotateMatrixX(bd3d->Occluders[p].invMat, bd3d->Occluders[p].rot[1]);
3566 matrixmult(bd3d->Occluders[p].invMat, (ConstMatrix) id);
3567 } else {
3568 makeInverseTransposeMatrix(bd3d->Occluders[p].invMat, bd3d->Occluders[p].trans);
3569 bd3d->Occluders[p].rotator = 0;
3570 }
3571 if (ShadowsInitilised(bd3d))
3572 draw_shadow_volume_extruded_edges(&bd3d->Occluders[p], bd3d->shadow_light_position, GL_QUADS);
3573
3574 p++;
3575 }
3576 }
3577 if (p == LAST_PIECE) {
3578 bd3d->Occluders[p].rotator = 0;
3579 updateMovingPieceOccPos(bd, bd3d);
3580 }
3581 }
3582
3583 void
updateFlagOccPos(const BoardData * bd,BoardData3d * bd3d)3584 updateFlagOccPos(const BoardData * bd, BoardData3d * bd3d)
3585 {
3586 if (bd->resigned) {
3587 freeOccluder(&bd3d->Occluders[OCC_FLAG]);
3588 initOccluder(&bd3d->Occluders[OCC_FLAG]);
3589
3590 bd3d->Occluders[OCC_FLAG].show = 1;
3591
3592 getFlagPos(bd, bd3d->Occluders[OCC_FLAG].trans);
3593 makeInverseTransposeMatrix(bd3d->Occluders[OCC_FLAG].invMat, bd3d->Occluders[OCC_FLAG].trans);
3594
3595 /* Flag pole */
3596 addCube(&bd3d->Occluders[OCC_FLAG], -FLAGPOLE_WIDTH * 1.95f, -FLAG_HEIGHT, -LIFT_OFF,
3597 FLAGPOLE_WIDTH * 1.95f, FLAGPOLE_HEIGHT, LIFT_OFF * 2);
3598
3599 /* Flag surface (approximation) */
3600 {
3601 int s;
3602 /* Change first ctlpoint to better match flag shape */
3603 float p1x = flag.ctlpoints[1][0][2];
3604 flag.ctlpoints[1][0][2] *= .7f;
3605
3606 for (s = 0; s < S_NUMPOINTS - 1; s++) { /* Reduce shadow size a bit to remove artifacts */
3607 float h = (flag.ctlpoints[s][1][1] - flag.ctlpoints[s][0][1]) * .92f - (FLAG_HEIGHT * .05f);
3608 float y = flag.ctlpoints[s][0][1] + FLAG_HEIGHT * .05f;
3609 float w = flag.ctlpoints[s + 1][0][0] - flag.ctlpoints[s][0][0];
3610 if (s == 2)
3611 w *= .95f;
3612 addWonkyCube(&bd3d->Occluders[OCC_FLAG], flag.ctlpoints[s][0][0], y, flag.ctlpoints[s][0][2],
3613 w, h, base_unit / 10.0f, flag.ctlpoints[s + 1][0][2] - flag.ctlpoints[s][0][2], s);
3614 }
3615 flag.ctlpoints[1][0][2] = p1x;
3616 }
3617 if (ShadowsInitilised(bd3d))
3618 draw_shadow_volume_extruded_edges(&bd3d->Occluders[OCC_FLAG], bd3d->shadow_light_position, GL_QUADS);
3619 } else {
3620 bd3d->Occluders[OCC_FLAG].show = 0;
3621 }
3622 }
3623
3624 void
updateHingeOccPos(BoardData3d * bd3d,int show3dHinges)3625 updateHingeOccPos(BoardData3d * bd3d, int show3dHinges)
3626 {
3627 if (!ShadowsInitilised(bd3d))
3628 return;
3629 bd3d->Occluders[OCC_HINGE1].show = bd3d->Occluders[OCC_HINGE2].show = show3dHinges;
3630 draw_shadow_volume_extruded_edges(&bd3d->Occluders[OCC_HINGE1], bd3d->shadow_light_position, GL_QUADS);
3631 draw_shadow_volume_extruded_edges(&bd3d->Occluders[OCC_HINGE2], bd3d->shadow_light_position, GL_QUADS);
3632 }
3633
3634 void
updateOccPos(const BoardData * bd)3635 updateOccPos(const BoardData * bd)
3636 { /* Make sure shadows are in correct place */
3637 if (ShadowsInitilised(bd->bd3d)) {
3638 updateCubeOccPos(bd, bd->bd3d);
3639 updateDiceOccPos(bd, bd->bd3d);
3640 updatePieceOccPos(bd, bd->bd3d);
3641 }
3642 }
3643
3644 static void
MakeShadowModel(const BoardData * bd,BoardData3d * bd3d,const renderdata * prd)3645 MakeShadowModel(const BoardData * bd, BoardData3d * bd3d, const renderdata * prd)
3646 {
3647 int i;
3648 if (!ShadowsInitilised(bd3d))
3649 return;
3650 TidyShadows(bd3d);
3651
3652 initOccluder(&bd3d->Occluders[OCC_BOARD]);
3653
3654 if (prd->roundedEdges) {
3655 addClosedSquare(&bd3d->Occluders[OCC_BOARD], EDGE_WIDTH - BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH,
3656 TRAY_WIDTH - EDGE_WIDTH * 2 + BOARD_FILLET * 2, TRAY_HEIGHT - EDGE_HEIGHT + BOARD_FILLET * 2,
3657 EDGE_DEPTH - LIFT_OFF);
3658 addClosedSquare(&bd3d->Occluders[OCC_BOARD], EDGE_WIDTH - BOARD_FILLET,
3659 TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT - BOARD_FILLET, BASE_DEPTH,
3660 TRAY_WIDTH - EDGE_WIDTH * 2 + BOARD_FILLET * 2, TRAY_HEIGHT - EDGE_HEIGHT + BOARD_FILLET * 2,
3661 EDGE_DEPTH - LIFT_OFF);
3662 addClosedSquare(&bd3d->Occluders[OCC_BOARD], TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - BOARD_FILLET,
3663 EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH, TRAY_WIDTH - EDGE_WIDTH * 2 + BOARD_FILLET * 2,
3664 TRAY_HEIGHT - EDGE_HEIGHT + BOARD_FILLET * 2, EDGE_DEPTH - LIFT_OFF);
3665 addClosedSquare(&bd3d->Occluders[OCC_BOARD], TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH - BOARD_FILLET,
3666 TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT - BOARD_FILLET, BASE_DEPTH,
3667 TRAY_WIDTH - EDGE_WIDTH * 2 + BOARD_FILLET * 2, TRAY_HEIGHT - EDGE_HEIGHT + BOARD_FILLET * 2,
3668 EDGE_DEPTH - LIFT_OFF);
3669 addClosedSquare(&bd3d->Occluders[OCC_BOARD], TRAY_WIDTH - BOARD_FILLET, EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH,
3670 BOARD_WIDTH + BOARD_FILLET * 2, TOTAL_HEIGHT - EDGE_HEIGHT * 2 + BOARD_FILLET * 2,
3671 EDGE_DEPTH - LIFT_OFF);
3672 addClosedSquare(&bd3d->Occluders[OCC_BOARD], TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH - BOARD_FILLET,
3673 EDGE_HEIGHT - BOARD_FILLET, BASE_DEPTH, BOARD_WIDTH + BOARD_FILLET * 2,
3674 TOTAL_HEIGHT - EDGE_HEIGHT * 2 + BOARD_FILLET * 2, EDGE_DEPTH - LIFT_OFF);
3675 addSquare(&bd3d->Occluders[OCC_BOARD], BOARD_FILLET, BOARD_FILLET, 0.f, TOTAL_WIDTH - BOARD_FILLET * 2,
3676 TOTAL_HEIGHT - BOARD_FILLET * 2, BASE_DEPTH + EDGE_DEPTH - LIFT_OFF);
3677 } else {
3678 addClosedSquare(&bd3d->Occluders[OCC_BOARD], EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH, TRAY_WIDTH - EDGE_WIDTH * 2,
3679 TRAY_HEIGHT - EDGE_HEIGHT, EDGE_DEPTH);
3680 addClosedSquare(&bd3d->Occluders[OCC_BOARD], EDGE_WIDTH, TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT, BASE_DEPTH,
3681 TRAY_WIDTH - EDGE_WIDTH * 2, TRAY_HEIGHT - EDGE_HEIGHT, EDGE_DEPTH);
3682 addClosedSquare(&bd3d->Occluders[OCC_BOARD], TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH, EDGE_HEIGHT, BASE_DEPTH,
3683 TRAY_WIDTH - EDGE_WIDTH * 2, TRAY_HEIGHT - EDGE_HEIGHT, EDGE_DEPTH);
3684 addClosedSquare(&bd3d->Occluders[OCC_BOARD], TOTAL_WIDTH - TRAY_WIDTH + EDGE_WIDTH,
3685 TRAY_HEIGHT + MID_SIDE_GAP_HEIGHT, BASE_DEPTH, TRAY_WIDTH - EDGE_WIDTH * 2,
3686 TRAY_HEIGHT - EDGE_HEIGHT, EDGE_DEPTH);
3687 addClosedSquare(&bd3d->Occluders[OCC_BOARD], TRAY_WIDTH, EDGE_HEIGHT, BASE_DEPTH, BOARD_WIDTH,
3688 TOTAL_HEIGHT - EDGE_HEIGHT * 2, EDGE_DEPTH);
3689 addClosedSquare(&bd3d->Occluders[OCC_BOARD], TRAY_WIDTH + BOARD_WIDTH + BAR_WIDTH, EDGE_HEIGHT, BASE_DEPTH,
3690 BOARD_WIDTH, TOTAL_HEIGHT - EDGE_HEIGHT * 2, EDGE_DEPTH);
3691 addSquare(&bd3d->Occluders[OCC_BOARD], 0.f, 0.f, 0.f, TOTAL_WIDTH, TOTAL_HEIGHT, BASE_DEPTH + EDGE_DEPTH);
3692 }
3693 setIdMatrix(bd3d->Occluders[OCC_BOARD].invMat);
3694 bd3d->Occluders[OCC_BOARD].trans[0] = bd3d->Occluders[OCC_BOARD].trans[1] = bd3d->Occluders[OCC_BOARD].trans[2] = 0;
3695 draw_shadow_volume_extruded_edges(&bd3d->Occluders[OCC_BOARD], bd3d->shadow_light_position, GL_QUADS);
3696
3697 initOccluder(&bd3d->Occluders[OCC_HINGE1]);
3698 copyOccluder(&bd3d->Occluders[OCC_HINGE1], &bd3d->Occluders[OCC_HINGE2]);
3699
3700 addHalfTube(&bd3d->Occluders[OCC_HINGE1], HINGE_WIDTH, HINGE_HEIGHT, prd->curveAccuracy / 2);
3701
3702 bd3d->Occluders[OCC_HINGE1].trans[0] = bd3d->Occluders[OCC_HINGE2].trans[0] = (TOTAL_WIDTH) / 2.0f;
3703 bd3d->Occluders[OCC_HINGE1].trans[2] = bd3d->Occluders[OCC_HINGE2].trans[2] = BASE_DEPTH + EDGE_DEPTH;
3704 bd3d->Occluders[OCC_HINGE1].trans[1] = ((TOTAL_HEIGHT / 2.0f) - HINGE_HEIGHT) / 2.0f;
3705 bd3d->Occluders[OCC_HINGE2].trans[1] = ((TOTAL_HEIGHT / 2.0f) - HINGE_HEIGHT + TOTAL_HEIGHT) / 2.0f;
3706
3707 makeInverseTransposeMatrix(bd3d->Occluders[OCC_HINGE1].invMat, bd3d->Occluders[OCC_HINGE1].trans);
3708 makeInverseTransposeMatrix(bd3d->Occluders[OCC_HINGE2].invMat, bd3d->Occluders[OCC_HINGE2].trans);
3709
3710 updateHingeOccPos(bd3d, prd->fHinges3d);
3711
3712 initOccluder(&bd3d->Occluders[OCC_CUBE]);
3713 addSquareCentered(&bd3d->Occluders[OCC_CUBE], 0.f, 0.f, 0.f, DOUBLECUBE_SIZE * .88f, DOUBLECUBE_SIZE * .88f,
3714 DOUBLECUBE_SIZE * .88f);
3715
3716 updateCubeOccPos(bd, bd3d);
3717
3718 initOccluder(&bd3d->Occluders[OCC_DICE1]);
3719 addDice(&bd3d->Occluders[OCC_DICE1], getDiceSize(prd) / 2.0f);
3720 copyOccluder(&bd3d->Occluders[OCC_DICE1], &bd3d->Occluders[OCC_DICE2]);
3721 bd3d->Occluders[OCC_DICE1].rotator = bd3d->Occluders[OCC_DICE2].rotator = 1;
3722 updateDiceOccPos(bd, bd3d);
3723
3724 initOccluder(&bd3d->Occluders[OCC_PIECE]);
3725 {
3726 float radius = PIECE_HOLE / 2.0f;
3727 float discradius = radius * 0.8f;
3728 float lip = radius - discradius;
3729 float height = PIECE_DEPTH - 2 * lip;
3730
3731 addCylinder(&bd3d->Occluders[OCC_PIECE], 0.f, 0.f, lip, PIECE_HOLE / 2.0f - LIFT_OFF, height,
3732 prd->curveAccuracy);
3733 }
3734 for (i = FIRST_PIECE; i <= LAST_PIECE; i++) {
3735 bd3d->Occluders[i].rot[0] = 0;
3736 bd3d->Occluders[i].rot[2] = 0;
3737 if (i != FIRST_PIECE)
3738 copyOccluder(&bd3d->Occluders[OCC_PIECE], &bd3d->Occluders[i]);
3739 }
3740
3741 updatePieceOccPos(bd, bd3d);
3742 updateFlagOccPos(bd, bd3d);
3743 }
3744
3745 static void
getCheqSize(renderdata * prd)3746 getCheqSize(renderdata * prd)
3747 {
3748 unsigned int i, accuracy = (prd->curveAccuracy / 4) - 1;
3749 prd->acrossCheq = prd->downCheq = 1;
3750 for (i = 1; i < accuracy; i++) {
3751 if (2 * prd->acrossCheq > prd->downCheq)
3752 prd->downCheq++;
3753 else
3754 prd->acrossCheq++;
3755 }
3756 }
3757
3758 void
preDraw3d(const BoardData * bd,BoardData3d * bd3d,renderdata * prd)3759 preDraw3d(const BoardData * bd, BoardData3d * bd3d, renderdata * prd)
3760 {
3761 if (!bd3d->qobjTex) {
3762 bd3d->qobjTex = gluNewQuadric();
3763 gluQuadricDrawStyle(bd3d->qobjTex, GLU_FILL);
3764 gluQuadricNormals(bd3d->qobjTex, GLU_FLAT);
3765 gluQuadricTexture(bd3d->qobjTex, GL_TRUE);
3766 }
3767 if (!bd3d->qobj) {
3768 bd3d->qobj = gluNewQuadric();
3769 gluQuadricDrawStyle(bd3d->qobj, GLU_FILL);
3770 gluQuadricNormals(bd3d->qobj, GLU_FLAT);
3771 gluQuadricTexture(bd3d->qobj, GL_FALSE);
3772 }
3773
3774 if (bd3d->boardPoints)
3775 freeEigthPoints(&bd3d->boardPoints, prd->curveAccuracy);
3776 calculateEigthPoints(&bd3d->boardPoints, BOARD_FILLET, prd->curveAccuracy);
3777
3778 preDrawPiece(bd3d, prd);
3779 preDrawDice(bd3d, prd);
3780
3781 MakeShadowModel(bd, bd3d, prd);
3782
3783 getCheqSize(prd);
3784 }
3785
3786 void
RestrictiveDrawPiece(unsigned int pos,unsigned int depth)3787 RestrictiveDrawPiece(unsigned int pos, unsigned int depth)
3788 {
3789 float newPos[3];
3790 getPiecePos(pos, depth, newPos);
3791 RestrictiveDrawFrame(newPos, PIECE_HOLE, PIECE_HOLE, PIECE_DEPTH);
3792 }
3793
3794 static void
RestrictiveDoDrawDice(BoardData * bd,DiceShown dicePos)3795 RestrictiveDoDrawDice(BoardData * bd, DiceShown dicePos)
3796 {
3797 float pos[3];
3798 float diceSize = getDiceSize(bd->rd);
3799 float overSize = diceSize * 1.5f;
3800 ClipBox temp;
3801 DiceShown tempDiceShown;
3802
3803 tempDiceShown = bd->diceShown;
3804 bd->diceShown = dicePos;
3805
3806 getDicePos(bd, 0, pos);
3807 pos[2] -= diceSize / 2.0f;
3808 RestrictiveDrawFrame(pos, overSize, overSize, overSize);
3809
3810 getDicePos(bd, 1, pos);
3811 pos[2] -= diceSize / 2.0f;
3812 RestrictiveDraw(&temp, pos, overSize, overSize, overSize);
3813 EnlargeCurrentToBox(&temp);
3814
3815 bd->diceShown = tempDiceShown;
3816 }
3817
3818 void
RestrictiveDrawDice(BoardData * bd)3819 RestrictiveDrawDice(BoardData * bd)
3820 {
3821 int tempTurn = 0;
3822
3823 if (numRestrictFrames == -1)
3824 return;
3825
3826 if (bd->rd->fDiceArea)
3827 RestrictiveDoDrawDice(bd, DICE_BELOW_BOARD);
3828
3829 if (bd->diceShown != DICE_ON_BOARD) {
3830 tempTurn = bd->turn;
3831 bd->turn *= -1;
3832 }
3833 RestrictiveDoDrawDice(bd, DICE_ON_BOARD);
3834
3835 if (tempTurn)
3836 bd->turn = tempTurn;
3837 }
3838
3839 void
RestrictiveDrawCube(BoardData * bd,int old_doubled,int old_cube_owner)3840 RestrictiveDrawCube(BoardData * bd, int old_doubled, int old_cube_owner)
3841 {
3842 float pos[3];
3843 int temp_dob = bd->doubled, temp_cow = bd->cube_owner;
3844 bd->doubled = old_doubled;
3845 bd->cube_owner = old_cube_owner;
3846 getDoubleCubePos(bd, pos);
3847 pos[2] -= DOUBLECUBE_SIZE / 2.0f;
3848 RestrictiveDrawFrame(pos, DOUBLECUBE_SIZE, DOUBLECUBE_SIZE, DOUBLECUBE_SIZE);
3849 bd->doubled = temp_dob;
3850 bd->cube_owner = temp_cow;
3851 getDoubleCubePos(bd, pos);
3852 pos[2] -= DOUBLECUBE_SIZE / 2.0f;
3853 RestrictiveDrawFrame(pos, DOUBLECUBE_SIZE, DOUBLECUBE_SIZE, DOUBLECUBE_SIZE);
3854 }
3855
3856 void
RestrictiveDrawMoveIndicator(BoardData * bd)3857 RestrictiveDrawMoveIndicator(BoardData * bd)
3858 { /* Need to redraw both indicators */
3859 float pos[3];
3860
3861 bd->turn *= -1;
3862 getMoveIndicatorPos(bd, pos);
3863 RestrictiveDrawFrame(pos, ARROW_SIZE, ARROW_SIZE, LIFT_OFF);
3864
3865 bd->turn *= -1;
3866 getMoveIndicatorPos(bd, pos);
3867 RestrictiveDrawFrame(pos, ARROW_SIZE, ARROW_SIZE, LIFT_OFF);
3868 }
3869
3870 void
RestrictiveDrawBoardNumbers(const BoardData3d * bd3d)3871 RestrictiveDrawBoardNumbers(const BoardData3d * bd3d)
3872 {
3873 #define NUMBER_WIDTH (TOTAL_WIDTH - (2 * TRAY_WIDTH))
3874 float pos[3] = { TRAY_WIDTH + (NUMBER_WIDTH / 2.0f), TOTAL_HEIGHT - EDGE_HEIGHT + (EDGE_HEIGHT / 2.0f),
3875 BASE_DEPTH + EDGE_DEPTH
3876 };
3877 float textHeight = GetFontHeight3d(bd3d->numberFont);
3878
3879 RestrictiveDrawFrame(pos, NUMBER_WIDTH, textHeight, LIFT_OFF);
3880 pos[1] = EDGE_HEIGHT / 2.0f;
3881 RestrictiveDrawFrame(pos, NUMBER_WIDTH, textHeight, LIFT_OFF);
3882 }
3883
3884 void
RestrictiveDrawFlag(const BoardData * bd)3885 RestrictiveDrawFlag(const BoardData * bd)
3886 {
3887 float v[4];
3888 getFlagPos(bd, v);
3889 v[0] += FLAG_WIDTH / 2.0f - FLAGPOLE_WIDTH;
3890 v[2] -= FLAG_WIDTH / 2.0f;
3891 RestrictiveDrawFrame(v, FLAG_WIDTH, FLAGPOLE_HEIGHT, FLAG_WIDTH);
3892 }
3893
3894 static void
drawBoardBase(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)3895 drawBoardBase(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
3896 {
3897 if (!bd->grayBoard)
3898 drawTable(bd3d, prd);
3899 else
3900 drawTableGrayed(bd3d, *prd);
3901
3902 if (prd->fLabels && !prd->fDynamicLabels)
3903 drawNumbers(bd);
3904
3905 if (bd3d->State == BOARD_OPEN)
3906 tidyEdges(prd);
3907
3908 if (bd->cube_use && !bd->crawford_game)
3909 drawDC(bd, bd3d, prd);
3910 }
3911
3912 void
drawBoardTop(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)3913 drawBoardTop(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
3914 {
3915 if (prd->fLabels && prd->fDynamicLabels)
3916 drawNumbers(bd);
3917 if (prd->showMoveIndicator)
3918 showMoveIndicator(bd);
3919
3920 /* Draw things in correct order so transparency works correctly */
3921 /* First pieces, then dice, then moving pieces */
3922 drawPieces(bd, bd3d, prd);
3923
3924 if (DiceShowing(bd)) {
3925 drawDie(bd, bd3d, 0);
3926 drawDie(bd, bd3d, 1);
3927 }
3928
3929 if (bd3d->moving || bd->drag_point >= 0)
3930 drawSpecialPieces(bd, bd3d, prd);
3931
3932 if (bd->resigned)
3933 drawFlag(bd, bd3d, prd);
3934 }
3935
3936 void
drawBoard(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)3937 drawBoard(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
3938 {
3939 drawBoardBase(bd, bd3d, prd);
3940 drawBoardTop(bd, bd3d, prd);
3941 }
3942
3943 #ifdef WIN32
3944 extern void
drawBasePreRender(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)3945 drawBasePreRender(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
3946 {
3947 GtkAllocation allocation;
3948
3949 if (bd->rd->showShadows) {
3950 renderingBase = TRUE;
3951 shadowDisplay(drawBoardBase, bd, bd3d, prd);
3952 renderingBase = FALSE;
3953 } else
3954 drawBoardBase(bd, bd3d, prd);
3955
3956 gtk_widget_get_allocation(bd3d->drawing_area3d, &allocation);
3957 SaveBufferRegion(bd3d->wglBuffer, 0, 0, allocation.width, allocation.height);
3958 }
3959 #endif
3960