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