1 /*
2  * misc3d.c
3  * by Jon Kinsey, 2003
4  *
5  * Helper functions for 3d drawing
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: misc3d.c,v 1.120 2018/02/18 14:46:35 plm Exp $
22  */
23 
24 #include "config.h"
25 #include "inc3d.h"
26 #ifdef WIN32
27 #include <io.h>
28 #endif
29 #include "renderprefs.h"
30 #include "sound.h"
31 #include "export.h"
32 #include "gtkgame.h"
33 #ifdef WIN32
34 #include "wglbuffer.h"
35 #endif
36 #include "util.h"
37 #include <glib/gstdio.h>
38 #include "gtklocdefs.h"
39 #include "glib-ext.h"
40 
41 #define MAX_FRAMES 10
42 #define DOT_SIZE 32
43 #define MAX_DIST ((DOT_SIZE / 2) * (DOT_SIZE / 2))
44 #define MIN_DIST ((DOT_SIZE / 2) * .70f * (DOT_SIZE / 2) * .70f)
45 #define TEXTURE_FILE "textures.txt"
46 #define TEXTURE_FILE_VERSION 3
47 #define BUF_SIZE 100
48 
49 /* Performance test data */
50 static double testStartTime;
51 static int numFrames;
52 #define TEST_TIME 3000.0f
53 
54 static int stopNextTime;
55 static int slide_move;
56 NTH_STATIC double animStartTime = 0;
57 
58 static guint idleId = 0;
59 static idleFunc *pIdleFun;
60 static BoardData *pIdleBD;
61 Flag3d flag;                    /* Only one flag */
62 
63 static void SetupSimpleMatAlpha(Material * pMat, float r, float g, float b, float a);
64 
65 static gboolean
idle(BoardData3d * bd3d)66 idle(BoardData3d * bd3d)
67 {
68     if (pIdleFun(bd3d))
69         DrawScene3d(bd3d);
70 
71     return TRUE;
72 }
73 
74 void
StopIdle3d(const BoardData * bd,BoardData3d * bd3d)75 StopIdle3d(const BoardData * bd, BoardData3d * bd3d)
76 {                               /* Animation has finished (or could have been interruptted) */
77     /* If interruptted - reset dice/moving piece details */
78     if (bd3d->shakingDice) {
79         bd3d->shakingDice = 0;
80         updateDiceOccPos(bd, bd3d);
81         gtk_main_quit();
82     }
83     if (bd3d->moving) {
84         bd3d->moving = 0;
85         updatePieceOccPos(bd, bd3d);
86         animation_finished = TRUE;
87         gtk_main_quit();
88     }
89 
90     if (idleId) {
91         g_source_remove(idleId);
92         idleId = 0;
93     }
94 }
95 
96 NTH_STATIC void
setIdleFunc(BoardData * bd,idleFunc * pFun)97 setIdleFunc(BoardData * bd, idleFunc * pFun)
98 {
99     if (idleId) {
100         g_source_remove(idleId);
101         idleId = 0;
102     }
103     pIdleFun = pFun;
104     pIdleBD = bd;
105 
106     idleId = g_idle_add((GSourceFunc) idle, bd->bd3d);
107 }
108 
109 /* Test function to show normal direction */
110 #if 0
111 static void
112 CheckNormal()
113 {
114     float len;
115     GLfloat norms[3];
116     glGetFloatv(GL_CURRENT_NORMAL, norms);
117 
118     len = sqrtf(norms[0] * norms[0] + norms[1] * norms[1] + norms[2] * norms[2]);
119     if (fabs(len - 1) > 0.000001)
120         len = len;              /*break here */
121     norms[0] *= .1f;
122     norms[1] *= .1f;
123     norms[2] *= .1f;
124 
125     glBegin(GL_LINES);
126     glVertex3f(0, 0, 0);
127     glVertex3f(norms[0], norms[1], norms[2]);
128     glEnd();
129     glPointSize(5);
130     glBegin(GL_POINTS);
131     glVertex3f(norms[0], norms[1], norms[2]);
132     glEnd();
133 }
134 #endif
135 
136 void
CheckOpenglError(void)137 CheckOpenglError(void)
138 {
139     GLenum glErr = glGetError();
140     if (glErr != GL_NO_ERROR)
141         g_print("OpenGL Error: %s\n", gluErrorString(glErr));
142 }
143 
144 NTH_STATIC void
SetupLight3d(BoardData3d * bd3d,const renderdata * prd)145 SetupLight3d(BoardData3d * bd3d, const renderdata * prd)
146 {
147     float lp[4];
148     float al[4], dl[4], sl[4];
149 
150     copyPoint(lp, prd->lightPos);
151     lp[3] = prd->lightType == LT_POSITIONAL ? 1.0f : 0.0f;
152 
153     /* If directioinal vector is from origin */
154     if (prd->lightType != LT_POSITIONAL) {
155         lp[0] -= getBoardWidth() / 2.0f;
156         lp[1] -= getBoardHeight() / 2.0f;
157     }
158     glLightfv(GL_LIGHT0, GL_POSITION, lp);
159 
160     al[0] = al[1] = al[2] = prd->lightLevels[0] / 100.0f;
161     al[3] = 1;
162     glLightfv(GL_LIGHT0, GL_AMBIENT, al);
163 
164     dl[0] = dl[1] = dl[2] = prd->lightLevels[1] / 100.0f;
165     dl[3] = 1;
166     glLightfv(GL_LIGHT0, GL_DIFFUSE, dl);
167 
168     sl[0] = sl[1] = sl[2] = prd->lightLevels[2] / 100.0f;
169     sl[3] = 1;
170     glLightfv(GL_LIGHT0, GL_SPECULAR, sl);
171 
172     /* Shadow light position */
173     memcpy(bd3d->shadow_light_position, lp, sizeof(float[4]));
174     if (ShadowsInitilised(bd3d)) {
175         int i;
176         for (i = 0; i < NUM_OCC; i++)
177             draw_shadow_volume_extruded_edges(&bd3d->Occluders[i], bd3d->shadow_light_position, GL_QUADS);
178     }
179 }
180 
181 #ifdef WIN32
182 /* Determine if a particular extension is supported */
183 typedef char *(WINAPI * fGetExtStr) (HDC);
184 extern int
extensionSupported(const char * extension)185 extensionSupported(const char *extension)
186 {
187     static const char *extensionsString = NULL;
188     if (extensionsString == NULL)
189         extensionsString = (const char *) glGetString(GL_EXTENSIONS);
190 
191     if ((extensionsString != NULL) && strstr(extensionsString, extension) != 0)
192         return TRUE;
193 
194     if (StrNCaseCmp(extension, "WGL_", (gsize) strlen("WGL_")) == 0) {  /* Look for wgl extension */
195         static const char *wglExtString = NULL;
196         if (wglExtString == NULL) {
197             fGetExtStr wglGetExtensionsStringARB;
198             wglGetExtensionsStringARB = (fGetExtStr) wglGetProcAddress("wglGetExtensionsStringARB");
199             if (!wglGetExtensionsStringARB)
200                 return FALSE;
201 
202             wglExtString = wglGetExtensionsStringARB(wglGetCurrentDC());
203         }
204         if (strstr(wglExtString, extension) != 0)
205             return TRUE;
206     }
207 
208     return FALSE;
209 }
210 
211 #ifndef GL_VERSION_1_2
212 #ifndef GL_EXT_separate_specular_color
213 #define GL_LIGHT_MODEL_COLOR_CONTROL_EXT    0x81F8
214 #define GL_SEPARATE_SPECULAR_COLOR_EXT      0x81FA
215 #endif
216 #endif
217 
218 typedef BOOL(APIENTRY * PFNWGLSWAPINTERVALFARPROC) (int);
219 
220 extern int
setVSync(int state)221 setVSync(int state)
222 {
223     static PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0;
224 
225     if (state == -1)
226         return FALSE;
227 
228     if (!wglSwapIntervalEXT) {
229         if (!extensionSupported("WGL_EXT_swap_control"))
230             return FALSE;
231 
232         wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC) wglGetProcAddress("wglSwapIntervalEXT");
233     }
234     if ((wglSwapIntervalEXT == NULL) || (wglSwapIntervalEXT(state) == 0))
235         return FALSE;
236 
237     return TRUE;
238 }
239 #endif
240 
241 static void
CreateTexture(unsigned int * pID,int width,int height,const unsigned char * bits)242 CreateTexture(unsigned int *pID, int width, int height, const unsigned char *bits)
243 {
244     /* Create texture */
245     glGenTextures(1, (GLuint *) pID);
246     glBindTexture(GL_TEXTURE_2D, *pID);
247     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
248     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
249     /* Read bits */
250     glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, bits);
251 }
252 
253 static void
CreateDotTexture(unsigned int * pDotTexture)254 CreateDotTexture(unsigned int *pDotTexture)
255 {
256     unsigned int i, j;
257     unsigned char *data = (unsigned char *) malloc(sizeof(*data) * DOT_SIZE * DOT_SIZE * 3);
258     unsigned char *pData = data;
259     g_assert(pData);
260 
261     for (i = 0; i < DOT_SIZE; i++) {
262         for (j = 0; j < DOT_SIZE; j++) {
263             float xdiff = ((float) i) + .5f - DOT_SIZE / 2;
264             float ydiff = ((float) j) + .5f - DOT_SIZE / 2;
265             float dist = xdiff * xdiff + ydiff * ydiff;
266             float percentage = 1 - ((dist - MIN_DIST) / (MAX_DIST - MIN_DIST));
267             unsigned char value;
268             if (percentage <= 0)
269                 value = 0;
270             else if (percentage >= 1)
271                 value = 255;
272             else
273                 value = (unsigned char) (255 * percentage);
274             pData[0] = pData[1] = pData[2] = value;
275             pData += 3;
276         }
277     }
278     CreateTexture(pDotTexture, DOT_SIZE, DOT_SIZE, data);
279     free(data);
280 }
281 
282 int
CreateFonts(BoardData3d * bd3d)283 CreateFonts(BoardData3d * bd3d)
284 {
285     if (!CreateNumberFont(&bd3d->numberFont, FONT_VERA, FONT_PITCH, FONT_SIZE, FONT_HEIGHT_RATIO))
286         return FALSE;
287 
288     if (!CreateNumberFont
289         (&bd3d->cubeFont, FONT_VERA_SERIF_BOLD, CUBE_FONT_PITCH, CUBE_FONT_SIZE, CUBE_FONT_HEIGHT_RATIO))
290         return FALSE;
291 
292     return TRUE;
293 }
294 
295 void
InitGL(const BoardData * bd)296 InitGL(const BoardData * bd)
297 {
298     float gal[4];
299     /* Turn on light 0 */
300     glEnable(GL_LIGHT0);
301     glEnable(GL_LIGHTING);
302 
303     /* No global ambient light */
304     gal[0] = gal[1] = gal[2] = gal[3] = 0;
305     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gal);
306 
307     /* Local specular viewpoint */
308     glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
309 
310     /* Default to <= depth testing */
311     glDepthFunc(GL_LEQUAL);
312     glEnable(GL_DEPTH_TEST);
313 
314     /* Back face culling */
315     glCullFace(GL_BACK);
316     glEnable(GL_CULL_FACE);
317 
318     /* Nice hints */
319     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
320     glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
321 
322     /* Default blend function for alpha-blending */
323     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
324 
325     /* Generate normal co-ords for nurbs */
326     glEnable(GL_AUTO_NORMAL);
327 
328     if (bd) {
329         BoardData3d *bd3d = bd->bd3d;
330         /* Setup some 3d things */
331         if (!CreateFonts(bd3d))
332             g_print("Error creating fonts\n");
333 
334         shadowInit(bd3d, bd->rd);
335 #ifdef GL_VERSION_1_2
336         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
337 #else
338         if (extensionSupported("GL_EXT_separate_specular_color"))
339             glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SEPARATE_SPECULAR_COLOR_EXT);
340 #endif
341         CreateDotTexture(&bd3d->dotTexture);
342 #ifdef WIN32
343         {
344             static int UseBufferRegions = -1;
345             if (UseBufferRegions == -1)
346                 UseBufferRegions = wglBufferInitialize();
347 #if 0                           /* Remove this until option added to control this */
348             if (UseBufferRegions == 1) {
349                 bd3d->wglBuffer = CreateBufferRegion(WGL_BACK_COLOR_BUFFER_BIT_ARB | WGL_DEPTH_BUFFER_BIT_ARB);
350                 bd3d->fBuffers = (bd->bd3d->wglBuffer != NULL);
351             }
352 #endif
353         }
354 #endif
355     }
356 }
357 
358 void
setMaterial(const Material * pMat)359 setMaterial(const Material * pMat)
360 {
361     glMaterialfv(GL_FRONT, GL_AMBIENT, pMat->ambientColour);
362     glMaterialfv(GL_FRONT, GL_DIFFUSE, pMat->diffuseColour);
363     glMaterialfv(GL_FRONT, GL_SPECULAR, pMat->specularColour);
364     glMateriali(GL_FRONT, GL_SHININESS, pMat->shine);
365 
366     if (pMat->pTexture) {
367         glEnable(GL_TEXTURE_2D);
368         glBindTexture(GL_TEXTURE_2D, pMat->pTexture->texID);
369     } else {
370         glDisable(GL_TEXTURE_2D);
371     }
372 }
373 
374 float
Dist2d(float a,float b)375 Dist2d(float a, float b)
376 {                               /* Find 3rd side size */
377     float sqdD = a * a - b * b;
378     if (sqdD > 0)
379         return sqrtf(sqdD);
380     else
381         return 0;
382 }
383 
384 /* Texture functions */
385 
386 static GList *textures;
387 
388 static const char *TextureTypeStrs[TT_COUNT] = { "general", "piece", "hinge" };
389 
390 GList *
GetTextureList(TextureType type)391 GetTextureList(TextureType type)
392 {
393     GList *glist = NULL;
394     GList *pl;
395     glist = g_list_append(glist, NO_TEXTURE_STRING);
396 
397     for (pl = textures; pl; pl = pl->next) {
398         TextureInfo *text = (TextureInfo *) pl->data;
399         if (text->type == type)
400             glist = g_list_append(glist, text->name);
401     }
402     return glist;
403 }
404 
405 void
FindNamedTexture(TextureInfo ** textureInfo,char * name)406 FindNamedTexture(TextureInfo ** textureInfo, char *name)
407 {
408     GList *pl;
409     for (pl = textures; pl; pl = pl->next) {
410         TextureInfo *text = (TextureInfo *) pl->data;
411         if (!StrCaseCmp(text->name, name)) {
412             *textureInfo = text;
413             return;
414         }
415     }
416     *textureInfo = 0;
417     /* Only warn user if textures.txt file has been loaded */
418     if (g_list_length(textures) > 0)
419         g_print("Texture %s not in texture info file\n", name);
420 }
421 
422 void
FindTexture(TextureInfo ** textureInfo,const char * file)423 FindTexture(TextureInfo ** textureInfo, const char *file)
424 {
425     GList *pl;
426     for (pl = textures; pl; pl = pl->next) {
427         TextureInfo *text = (TextureInfo *) pl->data;
428         if (!StrCaseCmp(text->file, file)) {
429             *textureInfo = text;
430             return;
431         }
432     }
433     {                           /* Not in texture list, see if old texture on disc */
434         char *szFile = BuildFilename(file);
435         if (szFile && g_file_test(szFile, G_FILE_TEST_IS_REGULAR)) {
436             /* Add entry for unknown texture */
437             TextureInfo text;
438             strcpy(text.file, file);
439             strcpy(text.name, file);
440             text.type = TT_NONE;        /* Don't show in lists */
441 
442             *textureInfo = (TextureInfo *) malloc(sizeof(TextureInfo));
443             **textureInfo = text;
444 
445             textures = g_list_append(textures, *textureInfo);
446 
447             return;
448         }
449         g_free(szFile);
450     }
451 
452     *textureInfo = 0;
453     /* Only warn user if in 3d */
454     if (display_is_3d(GetMainAppearance()))
455         g_print("Texture %s not in texture info file\n", file);
456 }
457 
458 void
LoadTextureInfo(void)459 LoadTextureInfo(void)
460 {
461     FILE *fp;
462     gchar *szFile;
463     char buf[BUF_SIZE];
464 
465     textures = NULL;
466 
467     szFile = BuildFilename(TEXTURE_FILE);
468     fp = gnubg_g_fopen(szFile, "r");
469     g_free(szFile);
470 
471     if (!fp) {
472         g_print("Error: Texture file (%s) not found\n", TEXTURE_FILE);
473         return;
474     }
475 
476     if (!fgets(buf, BUF_SIZE, fp) || atoi(buf) != TEXTURE_FILE_VERSION) {
477         g_print("Error: Texture file (%s) out of date\n", TEXTURE_FILE);
478         fclose(fp);
479         return;
480     }
481 
482     do {
483         int err, found, i, val;
484         size_t len;
485         TextureInfo text;
486 
487         err = 0;
488 
489         /* filename */
490         if (!fgets(buf, BUF_SIZE, fp))
491             break;              /* finished */
492 
493         len = strlen(buf);
494         if (len > 0 && buf[len - 1] == '\n') {
495             len--;
496             buf[len] = '\0';
497         }
498         if (len > FILENAME_SIZE) {
499             g_print("Texture filename %s too big, maximum length %d.  Entry ignored.\n", buf, FILENAME_SIZE);
500             err = 1;
501             strcpy(text.file, "");
502         } else
503             strcpy(text.file, buf);
504 
505         /* name */
506         if (!fgets(buf, BUF_SIZE, fp)) {
507             g_print("Error in texture file info.\n");
508             fclose(fp);
509             return;
510         }
511         len = strlen(buf);
512         if (len > 0 && buf[len - 1] == '\n') {
513             len--;
514             buf[len] = '\0';
515         }
516         if (len > NAME_SIZE) {
517             g_print("Texture name %s too big, maximum length %d.  Entry ignored.\n", buf, NAME_SIZE);
518             err = 1;
519         } else
520             strcpy(text.name, buf);
521 
522         /* type */
523         if (!fgets(buf, BUF_SIZE, fp)) {
524             g_print("Error in texture file info.\n");
525             fclose(fp);
526             return;
527         }
528         len = strlen(buf);
529         if (len > 0 && buf[len - 1] == '\n') {
530             len--;
531             buf[len] = '\0';
532         }
533         found = -1;
534         val = 2;
535         for (i = 0; i < TT_COUNT; i++) {
536             if (!StrCaseCmp(buf, TextureTypeStrs[i])) {
537                 found = i;
538                 break;
539             }
540             val *= 2;
541         }
542         if (found == -1) {
543             g_print("Unknown texture type %s.  Entry ignored.\n", buf);
544             err = 1;
545         } else
546             text.type = (TextureType) val;
547 
548         if (!err) {             /* Add texture type */
549             TextureInfo *pNewText = (TextureInfo *) malloc(sizeof(TextureInfo));
550             g_assert(pNewText);
551             *pNewText = text;
552             textures = g_list_append(textures, pNewText);
553         }
554     } while (!feof(fp));
555     fclose(fp);
556 }
557 
558 static void
DeleteTexture(Texture * texture)559 DeleteTexture(Texture * texture)
560 {
561     if (texture->texID)
562         glDeleteTextures(1, (GLuint *) & texture->texID);
563 
564     texture->texID = 0;
565 }
566 
567 int
LoadTexture(Texture * texture,const char * filename)568 LoadTexture(Texture * texture, const char *filename)
569 {
570     unsigned char *bits = 0;
571     GError *pix_error = NULL;
572     GdkPixbuf *fpixbuf, *pixbuf;
573 
574     if (!filename)
575         return 0;
576 
577     if (g_file_test(filename, G_FILE_TEST_EXISTS))
578         fpixbuf = gdk_pixbuf_new_from_file(filename, &pix_error);
579     else {
580         gchar *tmp = BuildFilename(filename);
581         fpixbuf = gdk_pixbuf_new_from_file(tmp, &pix_error);
582         g_free(tmp);
583     }
584 
585     if (pix_error) {
586         g_print("Failed to open texture: %s, %s\n", filename, pix_error->message);
587         return 0;               /* failed to load file */
588     }
589 
590     pixbuf = gdk_pixbuf_flip(fpixbuf, FALSE);
591     g_object_unref(fpixbuf);
592 
593     bits = gdk_pixbuf_get_pixels(pixbuf);
594 
595     texture->width = gdk_pixbuf_get_width(pixbuf);
596     texture->height = gdk_pixbuf_get_height(pixbuf);
597 
598     if (!bits) {
599         g_print("Failed to load texture: %s\n", filename);
600         return 0;               /* failed to load file */
601     }
602 
603     if (texture->width != texture->height) {
604         g_print("Failed to load texture %s. width (%d) different to height (%d)\n",
605                 filename, texture->width, texture->height);
606         return 0;               /* failed to load file */
607     }
608     /* Check size is a power of 2 */
609     if (texture->width <= 0 || (texture->width & (texture->width -1))) {
610         g_print("Failed to load texture %s, size (%d) isn't a power of 2\n", filename, texture->width);
611         return 0;               /* failed to load file */
612     }
613 
614     CreateTexture(&texture->texID, texture->width, texture->height, bits);
615 
616     g_object_unref(pixbuf);
617 
618     return 1;
619 }
620 
621 static void
SetTexture(BoardData3d * bd3d,Material * pMat,const char * filename)622 SetTexture(BoardData3d * bd3d, Material * pMat, const char *filename)
623 {
624     /* See if already loaded */
625     int i;
626     const char *nameStart = filename;
627     /* Find start of name in filename */
628     const char *newStart = 0;
629 
630     do {
631         if ((newStart = strchr(nameStart, '\\')) == NULL)
632             newStart = strchr(nameStart, '/');
633 
634         if (newStart)
635             nameStart = newStart + 1;
636     } while (newStart);
637 
638     /* Search for name in cached list */
639     for (i = 0; i < bd3d->numTextures; i++) {
640         if (!StrCaseCmp(nameStart, bd3d->textureName[i])) {     /* found */
641             pMat->pTexture = &bd3d->textureList[i];
642             return;
643         }
644     }
645 
646     /* Not found - Load new texture */
647     if (bd3d->numTextures == MAX_TEXTURES - 1) {
648         g_print("Error: Too many textures loaded...\n");
649         return;
650     }
651 
652     if (LoadTexture(&bd3d->textureList[bd3d->numTextures], filename)) {
653         /* Remember name */
654         bd3d->textureName[bd3d->numTextures] = (char *) malloc(strlen(nameStart) + 1);
655         strcpy(bd3d->textureName[bd3d->numTextures], nameStart);
656 
657         pMat->pTexture = &bd3d->textureList[bd3d->numTextures];
658         bd3d->numTextures++;
659     }
660 }
661 
662 static void
GetTexture(BoardData3d * bd3d,Material * pMat)663 GetTexture(BoardData3d * bd3d, Material * pMat)
664 {
665     if (pMat->textureInfo) {
666         char buf[100];
667         strcpy(buf, TEXTURE_PATH);
668         strcat(buf, pMat->textureInfo->file);
669         SetTexture(bd3d, pMat, buf);
670     } else
671         pMat->pTexture = 0;
672 }
673 
674 void
GetTextures(BoardData3d * bd3d,renderdata * prd)675 GetTextures(BoardData3d * bd3d, renderdata * prd)
676 {
677     GetTexture(bd3d, &prd->ChequerMat[0]);
678     GetTexture(bd3d, &prd->ChequerMat[1]);
679     GetTexture(bd3d, &prd->BaseMat);
680     GetTexture(bd3d, &prd->PointMat[0]);
681     GetTexture(bd3d, &prd->PointMat[1]);
682     GetTexture(bd3d, &prd->BoxMat);
683     GetTexture(bd3d, &prd->HingeMat);
684     GetTexture(bd3d, &prd->BackGroundMat);
685 }
686 
687 void
Set3dSettings(renderdata * prdnew,const renderdata * prd)688 Set3dSettings(renderdata * prdnew, const renderdata * prd)
689 {
690     unsigned int i;
691     prdnew->pieceType = prd->pieceType;
692     prdnew->pieceTextureType = prd->pieceTextureType;
693     prdnew->fHinges3d = prd->fHinges3d;
694     prdnew->showMoveIndicator = prd->showMoveIndicator;
695     prdnew->showShadows = prd->showShadows;
696     prdnew->quickDraw = prd->quickDraw;
697     prdnew->roundedEdges = prd->roundedEdges;
698     prdnew->bgInTrays = prd->bgInTrays;
699     prdnew->roundedPoints = prd->roundedPoints;
700     prdnew->shadowDarkness = prd->shadowDarkness;
701     prdnew->curveAccuracy = prd->curveAccuracy;
702     prdnew->skewFactor = prd->skewFactor;
703     prdnew->boardAngle = prd->boardAngle;
704     prdnew->diceSize = prd->diceSize;
705     prdnew->planView = prd->planView;
706 
707     prdnew->lightType = prd->lightType;
708     for (i = 0; i < 3; i++) {
709       prdnew->lightPos[i] = prd->lightPos[i];
710       prdnew->lightLevels[i] = prd->lightLevels[i];
711     }
712 
713     memcpy(prdnew->ChequerMat, prd->ChequerMat, sizeof(Material[2]));
714     memcpy(&prdnew->DiceMat[0], prd->afDieColour3d[0] ? &prd->ChequerMat[0] : &prd->DiceMat[0], sizeof(Material));
715     memcpy(&prdnew->DiceMat[1], prd->afDieColour3d[1] ? &prd->ChequerMat[1] : &prd->DiceMat[1], sizeof(Material));
716     prdnew->DiceMat[0].textureInfo = prdnew->DiceMat[1].textureInfo = 0;
717     prdnew->DiceMat[0].pTexture = prdnew->DiceMat[1].pTexture = 0;
718     memcpy(prdnew->DiceDotMat, prd->DiceDotMat, sizeof(Material[2]));
719 
720     memcpy(&prdnew->CubeMat, &prd->CubeMat, sizeof(Material));
721     memcpy(&prdnew->CubeNumberMat, &prd->CubeNumberMat, sizeof(Material));
722 
723     memcpy(&prdnew->BaseMat, &prd->BaseMat, sizeof(Material));
724     memcpy(prdnew->PointMat, prd->PointMat, sizeof(Material[2]));
725 
726     memcpy(&prdnew->BoxMat, &prd->BoxMat, sizeof(Material));
727     memcpy(&prdnew->HingeMat, &prd->HingeMat, sizeof(Material));
728     memcpy(&prdnew->PointNumberMat, &prd->PointNumberMat, sizeof(Material));
729     memcpy(&prdnew->BackGroundMat, &prd->BackGroundMat, sizeof(Material));
730 }
731 
732 /* Return v position, d distance along path segment */
733 static float
moveAlong(float d,PathType type,const float start[3],const float end[3],float v[3],float * rotate)734 moveAlong(float d, PathType type, const float start[3], const float end[3], float v[3], float *rotate)
735 {
736     float per, lineLen;
737 
738     if (type == PATH_LINE) {
739         float xDiff = end[0] - start[0];
740         float yDiff = end[1] - start[1];
741         float zDiff = end[2] - start[2];
742 
743         lineLen = sqrtf(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff);
744         if (d <= lineLen) {
745             per = d / lineLen;
746             v[0] = start[0] + xDiff * per;
747             v[1] = start[1] + yDiff * per;
748             v[2] = start[2] + zDiff * per;
749 
750             return -1;
751         }
752     } else if (type == PATH_PARABOLA) {
753         float dist = end[0] - start[0];
754         lineLen = fabsf(dist);
755         if (d <= lineLen) {
756             v[0] = start[0] + d * (dist / lineLen);
757             v[1] = start[1];
758             v[2] = start[2] + 10 * (-d * d + lineLen * d);
759 
760             return -1;
761         }
762     } else if (type == PATH_PARABOLA_12TO3) {
763         float dist = end[0] - start[0];
764         lineLen = fabsf(dist);
765         if (d <= lineLen) {
766             v[0] = start[0] + d * (dist / lineLen);
767             v[1] = start[1];
768             d += lineLen;
769             v[2] = start[2] + 10 * (-d * d + lineLen * 2 * d) - 10 * lineLen * lineLen;
770             return -1;
771         }
772     } else {
773         float xCent, zCent, xRad, zRad;
774         float yOff, yDiff = end[1] - start[1];
775 
776         xRad = end[0] - start[0];
777         zRad = end[2] - start[2];
778         lineLen = (float) G_PI *((fabsf(xRad) + fabsf(zRad)) / 2.0f) / 2.0f;
779         if (d <= lineLen) {
780             per = d / lineLen;
781             if (rotate)
782                 *rotate = per;
783 
784             if (type == PATH_CURVE_9TO12) {
785                 xCent = end[0];
786                 zCent = start[2];
787                 yOff = yDiff * cosf((float)G_PI_2 * per);
788             } else {
789                 xCent = start[0];
790                 zCent = end[2];
791                 yOff = yDiff * sinf((float)G_PI_2 * per);
792             }
793 
794             if (type == PATH_CURVE_9TO12) {
795                 v[0] = xCent - xRad * cosf((float)G_PI_2 * per);
796                 v[1] = end[1] - yOff;
797                 v[2] = zCent + zRad * sinf((float)G_PI_2 * per);
798             } else {
799                 v[0] = xCent + xRad * sinf((float)G_PI_2 * per);
800                 v[1] = start[1] + yOff;
801                 v[2] = zCent - zRad * cosf((float)G_PI_2 * per);
802             }
803             return -1;
804         }
805     }
806     /* Finished path segment */
807     return lineLen;
808 }
809 
810 /* Return v position, d distance along path p */
811 static int
movePath(Path * p,float d,float * rotate,float v[3])812 movePath(Path * p, float d, float *rotate, float v[3])
813 {
814     float done;
815     d -= p->mileStone;
816 
817     while (!finishedPath(p) && (done = moveAlong(d, p->pathType[p->state], p->pts[p->state], p->pts[p->state + 1], v, rotate)) >= 0.0f) { /* Next path segment */
818         d -= done;
819         p->mileStone += done;
820         p->state++;
821     }
822     return !finishedPath(p);
823 }
824 
825 void
initPath(Path * p,const float start[3])826 initPath(Path * p, const float start[3])
827 {
828     p->state = 0;
829     p->numSegments = 0;
830     p->mileStone = 0;
831     copyPoint(p->pts[0], start);
832 }
833 
834 int
finishedPath(const Path * p)835 finishedPath(const Path * p)
836 {
837     return (p->state == p->numSegments);
838 }
839 
840 void
addPathSegment(Path * p,PathType type,const float point[3])841 addPathSegment(Path * p, PathType type, const float point[3])
842 {
843     if (type == PATH_PARABOLA_12TO3) {  /* Move start y up to top of parabola */
844         float l = p->pts[p->numSegments][0] - point[0];
845         p->pts[p->numSegments][2] += 10 * l * l;
846     }
847 
848     p->pathType[p->numSegments] = type;
849     p->numSegments++;
850     copyPoint(p->pts[p->numSegments], point);
851 }
852 
853 /* Return a random number in 0-range */
854 float
randRange(float range)855 randRange(float range)
856 {
857     return range * ((float) rand() / (float) RAND_MAX);
858 }
859 
860 /* Setup dice test to initial pos */
861 void
initDT(diceTest * dt,int x,int y,int z)862 initDT(diceTest * dt, int x, int y, int z)
863 {
864     dt->top = 0;
865     dt->bottom = 5;
866 
867     dt->side[0] = 3;
868     dt->side[1] = 1;
869     dt->side[2] = 2;
870     dt->side[3] = 4;
871 
872     /* Simulate rotations to determine actual dice position */
873     while (x--) {
874         int temp = dt->top;
875         dt->top = dt->side[0];
876         dt->side[0] = dt->bottom;
877         dt->bottom = dt->side[2];
878         dt->side[2] = temp;
879     }
880     while (y--) {
881         int temp = dt->top;
882         dt->top = dt->side[1];
883         dt->side[1] = dt->bottom;
884         dt->bottom = dt->side[3];
885         dt->side[3] = temp;
886     }
887     while (z--) {
888         int temp = dt->side[0];
889         dt->side[0] = dt->side[3];
890         dt->side[3] = dt->side[2];
891         dt->side[2] = dt->side[1];
892         dt->side[1] = temp;
893     }
894 }
895 
896 float ***
Alloc3d(unsigned int x,unsigned int y,unsigned int z)897 Alloc3d(unsigned int x, unsigned int y, unsigned int z)
898 {                               /* Allocate 3d array */
899     unsigned int i, j;
900     float ***array = (float ***) malloc(sizeof(float **) * x);
901     g_assert(array);
902     for (i = 0; i < x; i++) {
903         array[i] = (float **) malloc(sizeof(float *) * y);
904         for (j = 0; j < y; j++)
905             array[i][j] = (float *) malloc(sizeof(float) * z);
906     }
907     return array;
908 }
909 
910 void
Free3d(float *** array,unsigned int x,unsigned int y)911 Free3d(float ***array, unsigned int x, unsigned int y)
912 {                               /* Free 3d array */
913     unsigned int i, j;
914     for (i = 0; i < x; i++) {
915         for (j = 0; j < y; j++)
916             free(array[i][j]);
917         free(array[i]);
918     }
919     free(array);
920 }
921 
922 void
cylinder(float radius,float height,unsigned int accuracy,const Texture * texture)923 cylinder(float radius, float height, unsigned int accuracy, const Texture * texture)
924 {
925     unsigned int i;
926     float angle = 0;
927     float circum = (float) G_PI * radius * 2 / (accuracy + 1);
928     float step = (2 * (float) G_PI) / accuracy;
929     glBegin(GL_QUAD_STRIP);
930     for (i = 0; i < accuracy + 1; i++) {
931         glNormal3f(sinf(angle), cosf(angle), 0.f);
932         if (texture)
933             glTexCoord2f(circum * i / (radius * 2), 0.f);
934         glVertex3f(sinf(angle) * radius, cosf(angle) * radius, 0.f);
935 
936         if (texture)
937             glTexCoord2f(circum * i / (radius * 2), height / (radius * 2));
938         glVertex3f(sinf(angle) * radius, cosf(angle) * radius, height);
939 
940         angle += step;
941     }
942     glEnd();
943 }
944 
945 void
circleOutlineOutward(float radius,float height,unsigned int accuracy)946 circleOutlineOutward(float radius, float height, unsigned int accuracy)
947 {                               /* Draw an ouline of a disc in current z plane with outfacing normals */
948     unsigned int i;
949     float angle, step;
950 
951     step = (2 * (float) G_PI) / accuracy;
952     angle = 0;
953     glNormal3f(0.f, 0.f, 1.f);
954     glBegin(GL_LINE_STRIP);
955     for (i = 0; i <= accuracy; i++) {
956         glNormal3f(sinf(angle), cosf(angle), 0.f);
957         glVertex3f(sinf(angle) * radius, cosf(angle) * radius, height);
958         angle -= step;
959     }
960     glEnd();
961 }
962 
963 void
circleOutline(float radius,float height,unsigned int accuracy)964 circleOutline(float radius, float height, unsigned int accuracy)
965 {                               /* Draw an ouline of a disc in current z plane */
966     unsigned int i;
967     float angle, step;
968 
969     step = (2 * (float) G_PI) / accuracy;
970     angle = 0;
971     glNormal3f(0.f, 0.f, 1.f);
972     glBegin(GL_LINE_STRIP);
973     for (i = 0; i <= accuracy; i++) {
974         glVertex3f(sinf(angle) * radius, cosf(angle) * radius, height);
975         angle -= step;
976     }
977     glEnd();
978 }
979 
980 void
circle(float radius,float height,unsigned int accuracy)981 circle(float radius, float height, unsigned int accuracy)
982 {                               /* Draw a disc in current z plane */
983     unsigned int i;
984     float angle, step;
985 
986     step = (2 * (float) G_PI) / accuracy;
987     angle = 0;
988     glNormal3f(0.f, 0.f, 1.f);
989     glBegin(GL_TRIANGLE_FAN);
990     glVertex3f(0.f, 0.f, height);
991     for (i = 0; i <= accuracy; i++) {
992         glVertex3f(sinf(angle) * radius, cosf(angle) * radius, height);
993         angle -= step;
994     }
995     glEnd();
996 }
997 
998 void
circleSloped(float radius,float startHeight,float endHeight,unsigned int accuracy)999 circleSloped(float radius, float startHeight, float endHeight, unsigned int accuracy)
1000 {                               /* Draw a disc in sloping z plane */
1001     unsigned int i;
1002     float angle, step;
1003 
1004     step = (2 * (float) G_PI) / accuracy;
1005     angle = 0;
1006     glNormal3f(0.f, 0.f, 1.f);
1007     glBegin(GL_TRIANGLE_FAN);
1008     glVertex3f(0.f, 0.f, startHeight);
1009     for (i = 0; i <= accuracy; i++) {
1010         float height = ((cosf(angle) + 1) / 2) * (endHeight - startHeight);
1011         glVertex3f(sinf(angle) * radius, cosf(angle) * radius, startHeight + height);
1012         angle -= step;
1013     }
1014     glEnd();
1015 }
1016 
1017 void
circleRev(float radius,float height,unsigned int accuracy)1018 circleRev(float radius, float height, unsigned int accuracy)
1019 {                               /* Draw a disc with reverse winding in current z plane */
1020     unsigned int i;
1021     float angle, step;
1022 
1023     step = (2 * (float) G_PI) / accuracy;
1024     angle = 0;
1025     glNormal3f(0.f, 0.f, 1.f);
1026     glBegin(GL_TRIANGLE_FAN);
1027     glVertex3f(0.f, 0.f, height);
1028     for (i = 0; i <= accuracy; i++) {
1029         glVertex3f(sinf(angle) * radius, cosf(angle) * radius, height);
1030         angle += step;
1031     }
1032     glEnd();
1033 }
1034 
1035 void
circleTex(float radius,float height,unsigned int accuracy,const Texture * texture)1036 circleTex(float radius, float height, unsigned int accuracy, const Texture * texture)
1037 {                               /* Draw a disc in current z plane with a texture */
1038     unsigned int i;
1039     float angle, step;
1040 
1041     if (!texture) {
1042         circle(radius, height, accuracy);
1043         return;
1044     }
1045 
1046     step = (2 * (float) G_PI) / accuracy;
1047     angle = 0;
1048     glNormal3f(0.f, 0.f, 1.f);
1049     glBegin(GL_TRIANGLE_FAN);
1050     glTexCoord2f(.5f, .5f);
1051     glVertex3f(0.f, 0.f, height);
1052     for (i = 0; i <= accuracy; i++) {
1053         glTexCoord2f((sinf(angle) * radius + radius) / (radius * 2), (cosf(angle) * radius + radius) / (radius * 2));
1054         glVertex3f(sinf(angle) * radius, cosf(angle) * radius, height);
1055         angle -= step;
1056     }
1057     glEnd();
1058 }
1059 
1060 void
circleRevTex(float radius,float height,unsigned int accuracy,const Texture * texture)1061 circleRevTex(float radius, float height, unsigned int accuracy, const Texture * texture)
1062 {                               /* Draw a disc with reverse winding in current z plane with a texture */
1063     unsigned int i;
1064     float angle, step;
1065 
1066     if (!texture) {
1067         circleRev(radius, height, accuracy);
1068         return;
1069     }
1070 
1071     step = (2 * (float) G_PI) / accuracy;
1072     angle = 0;
1073     glNormal3f(0.f, 0.f, 1.f);
1074     glBegin(GL_TRIANGLE_FAN);
1075     glTexCoord2f(.5f, .5f);
1076     glVertex3f(0.f, 0.f, height);
1077     for (i = 0; i <= accuracy; i++) {
1078         glTexCoord2f((sinf(angle) * radius + radius) / (radius * 2), (cosf(angle) * radius + radius) / (radius * 2));
1079         glVertex3f(sinf(angle) * radius, cosf(angle) * radius, height);
1080         angle += step;
1081     }
1082     glEnd();
1083 }
1084 
1085 void
drawBox(int type,float x,float y,float z,float w,float h,float d,const Texture * texture)1086 drawBox(int type, float x, float y, float z, float w, float h, float d, const Texture * texture)
1087 {                               /* Draw a box with normals and optional textures */
1088     float repX, repY;
1089     float normX, normY, normZ;
1090     float w2 = w / 2.0f, h2 = h / 2.0f, d2 = d / 2.0f;
1091 
1092     glPushMatrix();
1093     glTranslatef(x + w2, y + h2, z + d2);
1094     glScalef(w2, h2, d2);
1095 
1096     /* Scale normals */
1097     normX = w2;
1098     normY = h2;
1099     normZ = d2;
1100 
1101     glBegin(GL_QUADS);
1102 
1103     if (texture) {
1104         repX = (w * TEXTURE_SCALE) / texture->width;
1105         repY = (h * TEXTURE_SCALE) / texture->height;
1106 
1107         /* Front Face */
1108         glNormal3f(0.f, 0.f, normZ);
1109         if (type & BOX_SPLITTOP) {
1110             glTexCoord2f(0.f, 0.f);
1111             glVertex3f(-1.f, -1.f, 1.f);
1112             glTexCoord2f(repX, 0.f);
1113             glVertex3f(1.f, -1.f, 1.f);
1114             glTexCoord2f(repX, repY / 2.0f);
1115             glVertex3f(1.f, 0.f, 1.f);
1116             glTexCoord2f(0.f, repY / 2.0f);
1117             glVertex3f(-1.f, 0.f, 1.f);
1118 
1119             glTexCoord2f(0.f, repY / 2.0f);
1120             glVertex3f(-1.f, 0.f, 1.f);
1121             glTexCoord2f(repX, repY / 2.0f);
1122             glVertex3f(1.f, 0.f, 1.f);
1123             glTexCoord2f(repX, repY);
1124             glVertex3f(1.f, 1.f, 1.f);
1125             glTexCoord2f(0.f, repY);
1126             glVertex3f(-1.f, 1.f, 1.f);
1127         } else if (type & BOX_SPLITWIDTH) {
1128             glTexCoord2f(0.f, 0.f);
1129             glVertex3f(-1.f, -1.f, 1.f);
1130             glTexCoord2f(repX / 2.0f, 0.f);
1131             glVertex3f(0.f, -1.f, 1.f);
1132             glTexCoord2f(repX / 2.0f, repY);
1133             glVertex3f(0.f, 1.f, 1.f);
1134             glTexCoord2f(0.f, repY);
1135             glVertex3f(-1.f, 1.f, 1.f);
1136 
1137             glTexCoord2f(repX / 2.0f, 0.f);
1138             glVertex3f(0.f, -1.f, 1.f);
1139             glTexCoord2f(repX, 0.f);
1140             glVertex3f(1.f, -1.f, 1.f);
1141             glTexCoord2f(repX, repY);
1142             glVertex3f(1.f, 1.f, 1.f);
1143             glTexCoord2f(repX / 2.0f, repY);
1144             glVertex3f(0.f, 1.f, 1.f);
1145         } else {
1146             glTexCoord2f(0.f, 0.f);
1147             glVertex3f(-1.f, -1.f, 1.f);
1148             glTexCoord2f(repX, 0.f);
1149             glVertex3f(1.f, -1.f, 1.f);
1150             glTexCoord2f(repX, repY);
1151             glVertex3f(1.f, 1.f, 1.f);
1152             glTexCoord2f(0.f, repY);
1153             glVertex3f(-1.f, 1.f, 1.f);
1154         }
1155         if (!(type & BOX_NOENDS)) {
1156             /* Top Face */
1157             glNormal3f(0.f, normY, 0.f);
1158             glTexCoord2f(0.f, repY);
1159             glVertex3f(-1.f, 1.f, -1.f);
1160             glTexCoord2f(0.f, 0.f);
1161             glVertex3f(-1.f, 1.f, 1.f);
1162             glTexCoord2f(repX, 0.f);
1163             glVertex3f(1.f, 1.f, 1.f);
1164             glTexCoord2f(repX, repY);
1165             glVertex3f(1.f, 1.f, -1.f);
1166             /* Bottom Face */
1167             glNormal3f(0.f, -normY, 0.f);
1168             glTexCoord2f(repX, repY);
1169             glVertex3f(-1.f, -1.f, -1.f);
1170             glTexCoord2f(0.f, repY);
1171             glVertex3f(1.f, -1.f, -1.f);
1172             glTexCoord2f(0.f, 0.f);
1173             glVertex3f(1.f, -1.f, 1.f);
1174             glTexCoord2f(repX, 0.f);
1175             glVertex3f(-1.f, -1.f, 1.f);
1176         }
1177         if (!(type & BOX_NOSIDES)) {
1178             /* Right face */
1179             glNormal3f(normX, 0.f, 0.f);
1180             glTexCoord2f(repX, 0.f);
1181             glVertex3f(1.f, -1.f, -1.f);
1182             glTexCoord2f(repX, repY);
1183             glVertex3f(1.f, 1.f, -1.f);
1184             glTexCoord2f(0.f, repY);
1185             glVertex3f(1.f, 1.f, 1.f);
1186             glTexCoord2f(0.f, 0.f);
1187             glVertex3f(1.f, -1.f, 1.f);
1188             /* Left Face */
1189             glNormal3f(-normX, 0.f, 0.f);
1190             glTexCoord2f(0.f, 0.f);
1191             glVertex3f(-1.f, -1.f, -1.f);
1192             glTexCoord2f(repX, 0.f);
1193             glVertex3f(-1.f, -1.f, 1.f);
1194             glTexCoord2f(repX, repY);
1195             glVertex3f(-1.f, 1.f, 1.f);
1196             glTexCoord2f(0.f, repY);
1197             glVertex3f(-1.f, 1.f, -1.f);
1198         }
1199     } else {                    /* no texture co-ords */
1200         /* Front Face */
1201         glNormal3f(0.f, 0.f, normZ);
1202         if (type & BOX_SPLITTOP) {
1203             glVertex3f(-1.f, -1.f, 1.f);
1204             glVertex3f(1.f, -1.f, 1.f);
1205             glVertex3f(1.f, 0.f, 1.f);
1206             glVertex3f(-1.f, 0.f, 1.f);
1207 
1208             glVertex3f(-1.f, 0.f, 1.f);
1209             glVertex3f(1.f, 0.f, 1.f);
1210             glVertex3f(1.f, 1.f, 1.f);
1211             glVertex3f(-1.f, 1.f, 1.f);
1212         } else if (type & BOX_SPLITWIDTH) {
1213             glVertex3f(-1.f, -1.f, 1.f);
1214             glVertex3f(0.f, -1.f, 1.f);
1215             glVertex3f(0.f, 1.f, 1.f);
1216             glVertex3f(-1.f, 1.f, 1.f);
1217 
1218             glVertex3f(0.f, -1.f, 1.f);
1219             glVertex3f(1.f, -1.f, 1.f);
1220             glVertex3f(1.f, 1.f, 1.f);
1221             glVertex3f(0.f, 1.f, 1.f);
1222         } else {
1223             glVertex3f(-1.f, -1.f, 1.f);
1224             glVertex3f(1.f, -1.f, 1.f);
1225             glVertex3f(1.f, 1.f, 1.f);
1226             glVertex3f(-1.f, 1.f, 1.f);
1227         }
1228 
1229         if (!(type & BOX_NOENDS)) {
1230             /* Top Face */
1231             glNormal3f(0.f, normY, 0.f);
1232             glVertex3f(-1.f, 1.f, -1.f);
1233             glVertex3f(-1.f, 1.f, 1.f);
1234             glVertex3f(1.f, 1.f, 1.f);
1235             glVertex3f(1.f, 1.f, -1.f);
1236             /* Bottom Face */
1237             glNormal3f(0.f, -normY, 0.f);
1238             glVertex3f(-1.f, -1.f, -1.f);
1239             glVertex3f(1.f, -1.f, -1.f);
1240             glVertex3f(1.f, -1.f, 1.f);
1241             glVertex3f(-1.f, -1.f, 1.f);
1242         }
1243         if (!(type & BOX_NOSIDES)) {
1244             /* Right face */
1245             glNormal3f(normX, 0.f, 0.f);
1246             glVertex3f(1.f, -1.f, -1.f);
1247             glVertex3f(1.f, 1.f, -1.f);
1248             glVertex3f(1.f, 1.f, 1.f);
1249             glVertex3f(1.f, -1.f, 1.f);
1250             /* Left Face */
1251             glNormal3f(-normX, 0.f, 0.f);
1252             glVertex3f(-1.f, -1.f, -1.f);
1253             glVertex3f(-1.f, -1.f, 1.f);
1254             glVertex3f(-1.f, 1.f, 1.f);
1255             glVertex3f(-1.f, 1.f, -1.f);
1256         }
1257     }
1258     glEnd();
1259     glPopMatrix();
1260 }
1261 
1262 void
drawCube(float size)1263 drawCube(float size)
1264 {                               /* Draw a simple cube */
1265     glPushMatrix();
1266     glScalef(size / 2.0f, size / 2.0f, size / 2.0f);
1267 
1268     glBegin(GL_QUADS);
1269     /* Front Face */
1270     glVertex3f(-1.f, -1.f, 1.f);
1271     glVertex3f(1.f, -1.f, 1.f);
1272     glVertex3f(1.f, 1.f, 1.f);
1273     glVertex3f(-1.f, 1.f, 1.f);
1274     /* Top Face */
1275     glVertex3f(-1.f, 1.f, -1.f);
1276     glVertex3f(-1.f, 1.f, 1.f);
1277     glVertex3f(1.f, 1.f, 1.f);
1278     glVertex3f(1.f, 1.f, -1.f);
1279     /* Bottom Face */
1280     glVertex3f(-1.f, -1.f, -1.f);
1281     glVertex3f(1.f, -1.f, -1.f);
1282     glVertex3f(1.f, -1.f, 1.f);
1283     glVertex3f(-1.f, -1.f, 1.f);
1284     /* Right face */
1285     glVertex3f(1.f, -1.f, -1.f);
1286     glVertex3f(1.f, 1.f, -1.f);
1287     glVertex3f(1.f, 1.f, 1.f);
1288     glVertex3f(1.f, -1.f, 1.f);
1289     /* Left Face */
1290     glVertex3f(-1.f, -1.f, -1.f);
1291     glVertex3f(-1.f, -1.f, 1.f);
1292     glVertex3f(-1.f, 1.f, 1.f);
1293     glVertex3f(-1.f, 1.f, -1.f);
1294     glEnd();
1295 
1296     glPopMatrix();
1297 }
1298 
1299 void
drawRect(float x,float y,float z,float w,float h,const Texture * texture)1300 drawRect(float x, float y, float z, float w, float h, const Texture * texture)
1301 {                               /* Draw a rectangle */
1302     float repX, repY, tuv;
1303 
1304     glPushMatrix();
1305     glTranslatef(x + w / 2, y + h / 2, z);
1306     glScalef(w / 2.0f, h / 2.0f, 1.f);
1307     glNormal3f(0.f, 0.f, 1.f);
1308 
1309     if (texture) {
1310         tuv = TEXTURE_SCALE / texture->width;
1311         repX = w * tuv;
1312         repY = h * tuv;
1313 
1314         glBegin(GL_QUADS);
1315         glTexCoord2f(0.f, 0.f);
1316         glVertex3f(-1.f, -1.f, 0.f);
1317         glTexCoord2f(repX, 0.f);
1318         glVertex3f(1.f, -1.f, 0.f);
1319         glTexCoord2f(repX, repY);
1320         glVertex3f(1.f, 1.f, 0.f);
1321         glTexCoord2f(0.f, repY);
1322         glVertex3f(-1.f, 1.f, 0.f);
1323         glEnd();
1324     } else {
1325         glBegin(GL_QUADS);
1326         glVertex3f(-1.f, -1.f, 0.f);
1327         glVertex3f(1.f, -1.f, 0.f);
1328         glVertex3f(1.f, 1.f, 0.f);
1329         glVertex3f(-1.f, 1.f, 0.f);
1330         glEnd();
1331     }
1332 
1333     glPopMatrix();
1334 }
1335 
1336 void
drawSplitRect(float x,float y,float z,float w,float h,const Texture * texture)1337 drawSplitRect(float x, float y, float z, float w, float h, const Texture * texture)
1338 {                               /* Draw a rectangle in 2 bits */
1339     float repX, repY, tuv;
1340 
1341     glPushMatrix();
1342     glTranslatef(x + w / 2, y + h / 2, z);
1343     glScalef(w / 2.0f, h / 2.0f, 1.f);
1344     glNormal3f(0.f, 0.f, 1.f);
1345 
1346     if (texture) {
1347         tuv = TEXTURE_SCALE / texture->width;
1348         repX = w * tuv;
1349         repY = h * tuv;
1350 
1351         glBegin(GL_QUADS);
1352         glTexCoord2f(0.f, 0.f);
1353         glVertex3f(-1.f, -1.f, 0.f);
1354         glTexCoord2f(repX, 0.f);
1355         glVertex3f(1.f, -1.f, 0.f);
1356         glTexCoord2f(repX, repY / 2.0f);
1357         glVertex3f(1.f, 0.f, 0.f);
1358         glTexCoord2f(0.f, repY / 2.0f);
1359         glVertex3f(-1.f, 0.f, 0.f);
1360 
1361         glTexCoord2f(0.f, repY / 2.0f);
1362         glVertex3f(-1.f, 0.f, 0.f);
1363         glTexCoord2f(repX, repY / 2.0f);
1364         glVertex3f(1.f, 0.f, 0.f);
1365         glTexCoord2f(repX, repY);
1366         glVertex3f(1.f, 1.f, 0.f);
1367         glTexCoord2f(0.f, repY);
1368         glVertex3f(-1.f, 1.f, 0.f);
1369         glEnd();
1370     } else {
1371         glBegin(GL_QUADS);
1372         glVertex3f(-1.f, -1.f, 0.f);
1373         glVertex3f(1.f, -1.f, 0.f);
1374         glVertex3f(1.f, 0.f, 0.f);
1375         glVertex3f(-1.f, 0.f, 0.f);
1376 
1377         glVertex3f(-1.f, 0.f, 0.f);
1378         glVertex3f(1.f, 0.f, 0.f);
1379         glVertex3f(1.f, 1.f, 0.f);
1380         glVertex3f(-1.f, 1.f, 0.f);
1381         glEnd();
1382     }
1383 
1384     glPopMatrix();
1385 }
1386 
1387 void
drawChequeredRect(float x,float y,float z,float w,float h,int across,int down,const Texture * texture)1388 drawChequeredRect(float x, float y, float z, float w, float h, int across, int down, const Texture * texture)
1389 {                               /* Draw a rectangle split into (across x down) chequers */
1390     int i, j;
1391     float hh = h / down;
1392     float ww = w / across;
1393 
1394     glPushMatrix();
1395     glTranslatef(x, y, z);
1396     glNormal3f(0.f, 0.f, 1.f);
1397 
1398     if (texture) {
1399         float tuv = TEXTURE_SCALE / texture->width;
1400         float tw = ww * tuv;
1401         float th = hh * tuv;
1402         float ty = 0.f;
1403 
1404         for (i = 0; i < down; i++) {
1405             float xx = 0, tx = 0;
1406             glPushMatrix();
1407             glTranslatef(0.f, hh * i, 0.f);
1408             glBegin(GL_QUAD_STRIP);
1409             for (j = 0; j <= across; j++) {
1410                 glTexCoord2f(tx, ty + th);
1411                 glVertex2f(xx, hh);
1412                 glTexCoord2f(tx, ty);
1413                 glVertex2f(xx, 0.f);
1414                 xx += ww;
1415                 tx += tw;
1416             }
1417             ty += th;
1418             glEnd();
1419             glPopMatrix();
1420         }
1421     } else {
1422         for (i = 0; i < down; i++) {
1423             float xx = 0;
1424             glPushMatrix();
1425             glTranslatef(0.f, hh * i, 0.f);
1426             glBegin(GL_QUAD_STRIP);
1427             for (j = 0; j <= across; j++) {
1428                 glVertex2f(xx, hh);
1429                 glVertex2f(xx, 0.f);
1430                 xx += ww;
1431             }
1432             glEnd();
1433             glPopMatrix();
1434         }
1435     }
1436     glPopMatrix();
1437 }
1438 
1439 void
QuarterCylinder(float radius,float len,unsigned int accuracy,const Texture * texture)1440 QuarterCylinder(float radius, float len, unsigned int accuracy, const Texture * texture)
1441 {
1442     unsigned int i;
1443     float angle;
1444     float d;
1445     float sar, car;
1446     float dInc = 0;
1447 
1448     /* texture unit value */
1449     float tuv;
1450     if (texture) {
1451         float st = sinf((2 * (float)G_PI) / accuracy) * radius;
1452         float ct = (cosf((2 * (float)G_PI) / accuracy) - 1) * radius;
1453         dInc = sqrtf(st * st + ct * ct);
1454         tuv = (TEXTURE_SCALE) / texture->width;
1455     } else
1456         tuv = 0.0f;
1457 
1458     d = 0;
1459     glBegin(GL_QUAD_STRIP);
1460     for (i = 0; i < accuracy / 4 + 1; i++) {
1461         angle = ((float) i * 2.f * (float) G_PI) / accuracy;
1462         glNormal3f(sinf(angle), 0.f, cosf(angle));
1463 
1464         sar = sinf(angle) * radius;
1465         car = cosf(angle) * radius;
1466 
1467         if (tuv != 0.0f)
1468             glTexCoord2f(len * tuv, d * tuv);
1469         glVertex3f(sar, len, car);
1470 
1471         if (tuv != 0.0f) {
1472             glTexCoord2f(0.f, d * tuv);
1473             d -= dInc;
1474         }
1475         glVertex3f(sar, 0.f, car);
1476     }
1477     glEnd();
1478 }
1479 
1480 void
QuarterCylinderSplayedRev(float radius,float len,unsigned int accuracy,const Texture * texture)1481 QuarterCylinderSplayedRev(float radius, float len, unsigned int accuracy, const Texture * texture)
1482 {
1483     unsigned int i;
1484     float angle;
1485     float d;
1486     float sar, car;
1487     float dInc = 0;
1488 
1489     /* texture unit value */
1490     float tuv;
1491     if (texture) {
1492         float st = sinf((2 * (float)G_PI) / accuracy) * radius;
1493         float ct = (cosf((2 * (float)G_PI) / accuracy) - 1) * radius;
1494         dInc = sqrtf(st * st + ct * ct);
1495         tuv = (TEXTURE_SCALE) / texture->width;
1496     } else
1497         tuv = 0;
1498 
1499     d = 0;
1500     glBegin(GL_QUAD_STRIP);
1501     for (i = 0; i < accuracy / 4 + 1; i++) {
1502         angle = ((float) i * 2.f * (float) G_PI) / accuracy;
1503         glNormal3f(sinf(angle), 0.f, cosf(angle));
1504 
1505         sar = sinf(angle) * radius;
1506         car = cosf(angle) * radius;
1507 
1508         if (tuv != 0.0f)
1509             glTexCoord2f((len + car) * tuv, d * tuv);
1510         glVertex3f(sar, len + car, car);
1511 
1512         if (tuv != 0.0f) {
1513             glTexCoord2f(-car * tuv, d * tuv);
1514             d -= dInc;
1515         }
1516         glVertex3f(sar, -car, car);
1517     }
1518     glEnd();
1519 }
1520 
1521 void
QuarterCylinderSplayed(float radius,float len,unsigned int accuracy,const Texture * texture)1522 QuarterCylinderSplayed(float radius, float len, unsigned int accuracy, const Texture * texture)
1523 {
1524     unsigned int i;
1525     float angle;
1526     float d;
1527     float sar, car;
1528     float dInc = 0;
1529 
1530     /* texture unit value */
1531     float tuv;
1532     if (texture) {
1533         float st = sinf((2 * (float)G_PI) / accuracy) * radius;
1534         float ct = (cosf((2 * (float)G_PI) / accuracy) - 1) * radius;
1535         dInc = sqrtf(st * st + ct * ct);
1536         tuv = (TEXTURE_SCALE) / texture->width;
1537     } else
1538         tuv = 0;
1539 
1540     d = 0;
1541     glBegin(GL_QUAD_STRIP);
1542     for (i = 0; i < accuracy / 4 + 1; i++) {
1543         angle = ((float) i * 2.f * (float) G_PI) / accuracy;
1544         glNormal3f(sinf(angle), 0.f, cosf(angle));
1545 
1546         sar = sinf(angle) * radius;
1547         car = cosf(angle) * radius;
1548 
1549         if (tuv != 0.0f)
1550             glTexCoord2f((len - car) * tuv, d * tuv);
1551         glVertex3f(sar, len - car, car);
1552 
1553         if (tuv != 0.0f) {
1554             glTexCoord2f(car * tuv, d * tuv);
1555             d -= dInc;
1556         }
1557         glVertex3f(sar, car, car);
1558     }
1559     glEnd();
1560 }
1561 
1562 void
drawCornerEigth(float ** const * boardPoints,float radius,unsigned int accuracy)1563 drawCornerEigth(float **const *boardPoints, float radius, unsigned int accuracy)
1564 {
1565     unsigned int i, ns;
1566     int j;
1567 
1568     for (i = 0; i < accuracy / 4; i++) {
1569         ns = (accuracy / 4) - (i + 1);
1570         glBegin(GL_TRIANGLE_STRIP);
1571         glNormal3f(boardPoints[i][ns + 1][0] / radius, boardPoints[i][ns + 1][1] / radius,
1572                    boardPoints[i][ns + 1][2] / radius);
1573         glVertex3f(boardPoints[i][ns + 1][0], boardPoints[i][ns + 1][1], boardPoints[i][ns + 1][2]);
1574         for (j = (int) ns; j >= 0; j--) {
1575             glNormal3f(boardPoints[i + 1][j][0] / radius, boardPoints[i + 1][j][1] / radius,
1576                        boardPoints[i + 1][j][2] / radius);
1577             glVertex3f(boardPoints[i + 1][j][0], boardPoints[i + 1][j][1], boardPoints[i + 1][j][2]);
1578             glNormal3f(boardPoints[i][j][0] / radius, boardPoints[i][j][1] / radius, boardPoints[i][j][2] / radius);
1579             glVertex3f(boardPoints[i][j][0], boardPoints[i][j][1], boardPoints[i][j][2]);
1580         }
1581         glEnd();
1582     }
1583 }
1584 
1585 void
calculateEigthPoints(float **** boardPoints,float radius,unsigned int accuracy)1586 calculateEigthPoints(float ****boardPoints, float radius, unsigned int accuracy)
1587 {
1588     unsigned int i, j, ns;
1589 
1590     float lat_angle;
1591     float lat_step;
1592     float latitude;
1593     float new_radius;
1594     float angle;
1595     float step = 0;
1596     unsigned int corner_steps = (accuracy / 4) + 1;
1597     *boardPoints = Alloc3d(corner_steps, corner_steps, 3);
1598 
1599     lat_angle = 0;
1600     lat_step = (2 * (float) G_PI) / accuracy;
1601 
1602     /* Calculate corner 1/8th sphere points */
1603     for (i = 0; i < (accuracy / 4) + 1; i++) {
1604         latitude = sinf(lat_angle) * radius;
1605         new_radius = Dist2d(radius, latitude);
1606 
1607         angle = 0;
1608         ns = (accuracy / 4) - i;
1609         if (ns > 0)
1610             step = (2.f * (float) G_PI) / (ns * 4.f);
1611 
1612         for (j = 0; j <= ns; j++) {
1613             (*boardPoints)[i][j][0] = sinf(angle) * new_radius;
1614             (*boardPoints)[i][j][1] = latitude;
1615             (*boardPoints)[i][j][2] = cosf(angle) * new_radius;
1616 
1617             angle += step;
1618         }
1619         lat_angle += lat_step;
1620     }
1621 }
1622 
1623 void
freeEigthPoints(float **** boardPoints,unsigned int accuracy)1624 freeEigthPoints(float ****boardPoints, unsigned int accuracy)
1625 {
1626     unsigned int corner_steps = (accuracy / 4) + 1;
1627     if (*boardPoints)
1628         Free3d(*boardPoints, corner_steps, corner_steps);
1629     *boardPoints = 0;
1630 }
1631 
1632 void
SetColour3d(float r,float g,float b,float a)1633 SetColour3d(float r, float g, float b, float a)
1634 {
1635     Material col;
1636     SetupSimpleMatAlpha(&col, r, g, b, a);
1637     setMaterial(&col);
1638 }
1639 
1640 void
SetMovingPieceRotation(const BoardData * bd,BoardData3d * bd3d,unsigned int pt)1641 SetMovingPieceRotation(const BoardData * bd, BoardData3d * bd3d, unsigned int pt)
1642 {                               /* Make sure piece is rotated correctly while dragging */
1643     bd3d->movingPieceRotation = bd3d->pieceRotation[pt][Abs(bd->points[pt])];
1644 }
1645 
1646 void
PlaceMovingPieceRotation(const BoardData * bd,BoardData3d * bd3d,unsigned int dest,unsigned int src)1647 PlaceMovingPieceRotation(const BoardData * bd, BoardData3d * bd3d, unsigned int dest, unsigned int src)
1648 {                               /* Make sure rotation is correct in new position */
1649     bd3d->pieceRotation[src][Abs(bd->points[src])] = bd3d->pieceRotation[dest][Abs(bd->points[dest] - 1)];
1650     bd3d->pieceRotation[dest][Abs(bd->points[dest]) - 1] = bd3d->movingPieceRotation;
1651 }
1652 
1653 static void
getProjectedCoord(const float pos[3],float * x,float * y)1654 getProjectedCoord(const float pos[3], float *x, float *y)
1655 {                               /* Work out where point (x, y, z) is on the screen */
1656     GLint viewport[4];
1657     GLdouble mvmatrix[16], projmatrix[16], xd, yd, zd;
1658 
1659     glGetIntegerv(GL_VIEWPORT, viewport);
1660     glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
1661     glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
1662 
1663     if (gluProject
1664         ((GLdouble) pos[0], (GLdouble) pos[1], (GLdouble) pos[2], mvmatrix, projmatrix, viewport, &xd, &yd,
1665          &zd) == GL_FALSE)
1666         g_print("Error calling gluProject()\n");
1667 
1668     *x = (float) xd;
1669     *y = (float) yd;
1670 }
1671 
1672 static int freezeRestrict = 0;
1673 static ClipBox cb[MAX_FRAMES], eraseCb, lastCb;
1674 int numRestrictFrames = 0;
1675 
1676 static float
BoxWidth(const ClipBox * pCb)1677 BoxWidth(const ClipBox * pCb)
1678 {
1679     return pCb->xx - pCb->x;
1680 }
1681 
1682 static float
BoxHeight(const ClipBox * pCb)1683 BoxHeight(const ClipBox * pCb)
1684 {
1685     return pCb->yy - pCb->y;
1686 }
1687 
1688 static float
BoxMidWidth(const ClipBox * pCb)1689 BoxMidWidth(const ClipBox * pCb)
1690 {
1691     return pCb->x + BoxWidth(pCb) / 2;
1692 }
1693 
1694 static float
BoxMidHeight(const ClipBox * pCb)1695 BoxMidHeight(const ClipBox * pCb)
1696 {
1697     return pCb->y + BoxHeight(pCb) / 2;
1698 }
1699 
1700 static void
CopyBox(ClipBox * pTo,const ClipBox * pFrom)1701 CopyBox(ClipBox * pTo, const ClipBox * pFrom)
1702 {
1703     *pTo = *pFrom;
1704 }
1705 
1706 static void
EnlargeTo(ClipBox * pCb,float x,float y)1707 EnlargeTo(ClipBox * pCb, float x, float y)
1708 {
1709     if (x < pCb->x)
1710         pCb->x = x;
1711     if (y < pCb->y)
1712         pCb->y = y;
1713     if (x > pCb->xx)
1714         pCb->xx = x;
1715     if (y > pCb->yy)
1716         pCb->yy = y;
1717 }
1718 
1719 void
EnlargeCurrentToBox(const ClipBox * pOtherCb)1720 EnlargeCurrentToBox(const ClipBox * pOtherCb)
1721 {
1722     EnlargeTo(&cb[numRestrictFrames], pOtherCb->x, pOtherCb->y);
1723     EnlargeTo(&cb[numRestrictFrames], pOtherCb->xx, pOtherCb->yy);
1724 }
1725 
1726 static void
InitBox(ClipBox * pCb,float x,float y)1727 InitBox(ClipBox * pCb, float x, float y)
1728 {
1729     pCb->x = pCb->xx = x;
1730     pCb->y = pCb->yy = y;
1731 }
1732 
1733 static void
RationalizeBox(ClipBox * pCb)1734 RationalizeBox(ClipBox * pCb)
1735 {
1736     int midX, midY, maxXoff, maxYoff;
1737     /* Make things a bit bigger to avoid slight drawing errors */
1738     pCb->x -= .5f;
1739     pCb->xx += .5f;
1740     pCb->y -= .5f;
1741     pCb->yy += .5f;
1742     midX = (int) BoxMidWidth(pCb);
1743     midY = (int) BoxMidHeight(pCb);
1744     maxXoff = MAX(midX - (int) pCb->x, (int) pCb->xx - midX) + 1;
1745     maxYoff = MAX(midY - (int) pCb->y, (int) pCb->yy - midY) + 1;
1746     pCb->x = (float) (midX - maxXoff);
1747     pCb->xx = (float) (midX + maxXoff);
1748     pCb->y = (float) (midY - maxYoff);
1749     pCb->yy = (float) (midY + maxYoff);
1750 }
1751 
1752 void
RestrictiveRedraw(void)1753 RestrictiveRedraw(void)
1754 {
1755     numRestrictFrames = -1;
1756 }
1757 
1758 void
RestrictiveDraw(ClipBox * pCb,const float pos[3],float width,float height,float depth)1759 RestrictiveDraw(ClipBox * pCb, const float pos[3], float width, float height, float depth)
1760 {
1761     float tpos[3];
1762     float x, y;
1763 
1764     copyPoint(tpos, pos);
1765     tpos[0] -= width / 2.0f;
1766     tpos[1] -= height / 2.0f;
1767 
1768     getProjectedCoord(tpos, &x, &y);
1769     InitBox(pCb, x, y);
1770 
1771     tpos[0] += width;
1772     getProjectedCoord(tpos, &x, &y);
1773     EnlargeTo(pCb, x, y);
1774 
1775     tpos[1] += height;
1776     getProjectedCoord(tpos, &x, &y);
1777     EnlargeTo(pCb, x, y);
1778 
1779     tpos[0] -= width;
1780     getProjectedCoord(tpos, &x, &y);
1781     EnlargeTo(pCb, x, y);
1782 
1783     tpos[1] -= height;
1784     tpos[2] += depth;
1785     getProjectedCoord(tpos, &x, &y);
1786     EnlargeTo(pCb, x, y);
1787 
1788     tpos[0] += width;
1789     getProjectedCoord(tpos, &x, &y);
1790     EnlargeTo(pCb, x, y);
1791 
1792     tpos[1] += height;
1793     getProjectedCoord(tpos, &x, &y);
1794     EnlargeTo(pCb, x, y);
1795 
1796     tpos[0] -= width;
1797     getProjectedCoord(tpos, &x, &y);
1798     EnlargeTo(pCb, x, y);
1799 }
1800 
1801 void
RestrictiveDrawFrame(const float pos[3],float width,float height,float depth)1802 RestrictiveDrawFrame(const float pos[3], float width, float height, float depth)
1803 {
1804     if (numRestrictFrames != -1) {
1805         numRestrictFrames++;
1806         if (numRestrictFrames == MAX_FRAMES) {  /* Too many drawing requests - just redraw whole screen */
1807             RestrictiveRedraw();
1808             return;
1809         }
1810         RestrictiveDraw(&cb[numRestrictFrames], pos, width, height, depth);
1811     }
1812 }
1813 
1814 void
RestrictiveDrawFrameWindow(int x,int y,int width,int height)1815 RestrictiveDrawFrameWindow(int x, int y, int width, int height)
1816 {
1817     if (numRestrictFrames != -1) {
1818         numRestrictFrames++;
1819         if (numRestrictFrames == MAX_FRAMES) {  /* Too many drawing requests - just redraw whole screen */
1820             RestrictiveRedraw();
1821             return;
1822         }
1823         cb[numRestrictFrames].x = (float) x;
1824         cb[numRestrictFrames].y = (float) y;
1825         cb[numRestrictFrames].xx = (float) x + width;
1826         cb[numRestrictFrames].yy = (float) y + height;
1827     }
1828 }
1829 
1830 void
RestrictiveRender(const BoardData * bd,const BoardData3d * bd3d,const renderdata * prd)1831 RestrictiveRender(const BoardData * bd, const BoardData3d * bd3d, const renderdata * prd)
1832 {
1833     GLint viewport[4];
1834     glGetIntegerv(GL_VIEWPORT, viewport);
1835 
1836     glMatrixMode(GL_PROJECTION);
1837     glPushMatrix();
1838 
1839     while (numRestrictFrames > 0) {
1840         RationalizeBox(&cb[numRestrictFrames]);
1841 
1842         glMatrixMode(GL_PROJECTION);
1843         glLoadIdentity();
1844         gluPickMatrix((double) BoxMidWidth(&cb[numRestrictFrames]), (double) BoxMidHeight(&cb[numRestrictFrames]),
1845                       (double) BoxWidth(&cb[numRestrictFrames]), (double) BoxHeight(&cb[numRestrictFrames]), viewport);
1846 
1847         /* Setup projection matrix - using saved values */
1848         if (prd->planView)
1849             glOrtho(-bd3d->horFrustrum, bd3d->horFrustrum, -bd3d->vertFrustrum, bd3d->vertFrustrum, 0.0, 5.0);
1850         else
1851             glFrustum(-bd3d->horFrustrum, bd3d->horFrustrum, -bd3d->vertFrustrum, bd3d->vertFrustrum, zNear, zFar);
1852 
1853         glMatrixMode(GL_MODELVIEW);
1854         glViewport((int) (cb[numRestrictFrames].x), (int) (cb[numRestrictFrames].y),
1855                    (int) BoxWidth(&cb[numRestrictFrames]), (int) BoxHeight(&cb[numRestrictFrames]));
1856 
1857         drawBoard(bd, bd3d, prd);
1858 
1859         if (!freezeRestrict)
1860             numRestrictFrames--;
1861         else {
1862             if (numRestrictFrames > 1)
1863                 numRestrictFrames--;
1864             else {
1865                 freezeRestrict = 0;
1866                 break;
1867             }
1868         }
1869     }
1870     /* Restore matrixes */
1871     glMatrixMode(GL_PROJECTION);
1872     glPopMatrix();
1873     glMatrixMode(GL_MODELVIEW);
1874     glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
1875 }
1876 
1877 int
MouseMove3d(const BoardData * bd,BoardData3d * bd3d,const renderdata * prd,int x,int y)1878 MouseMove3d(const BoardData * bd, BoardData3d * bd3d, const renderdata * prd, int x, int y)
1879 {
1880     if (bd->drag_point >= 0) {
1881         getProjectedPieceDragPos(x, y, bd3d->dragPos);
1882         updateMovingPieceOccPos(bd, bd3d);
1883 
1884         if (prd->quickDraw && numRestrictFrames != -1) {
1885             if (!freezeRestrict)
1886                 CopyBox(&eraseCb, &lastCb);
1887 
1888             RestrictiveDraw(&cb[numRestrictFrames], bd3d->dragPos, PIECE_HOLE, PIECE_HOLE, PIECE_DEPTH);
1889             freezeRestrict++;
1890 
1891             CopyBox(&lastCb, &cb[numRestrictFrames]);
1892             EnlargeCurrentToBox(&eraseCb);
1893         }
1894         return 1;
1895     } else
1896         return 0;
1897 }
1898 
1899 void
RestrictiveStartMouseMove(unsigned int pos,unsigned int depth)1900 RestrictiveStartMouseMove(unsigned int pos, unsigned int depth)
1901 {
1902     float erasePos[3];
1903     if (numRestrictFrames != -1) {
1904         getPiecePos(pos, depth, erasePos);
1905         RestrictiveDrawFrame(erasePos, PIECE_HOLE, PIECE_HOLE, PIECE_DEPTH);
1906         CopyBox(&eraseCb, &cb[numRestrictFrames]);
1907     }
1908     freezeRestrict = 1;
1909 }
1910 
1911 void
RestrictiveEndMouseMove(unsigned int pos,unsigned int depth)1912 RestrictiveEndMouseMove(unsigned int pos, unsigned int depth)
1913 {
1914     float newPos[3];
1915     getPiecePos(pos, depth, newPos);
1916 
1917     if (numRestrictFrames == -1)
1918         return;
1919 
1920     if (pos == 26 || pos == 27) {
1921         newPos[2] -= PIECE_HOLE / 2.0f;
1922         RestrictiveDraw(&cb[numRestrictFrames], newPos, PIECE_HOLE, PIECE_HOLE, PIECE_HOLE);
1923     } else
1924         RestrictiveDraw(&cb[numRestrictFrames], newPos, PIECE_HOLE, PIECE_HOLE, PIECE_DEPTH);
1925 
1926     if (freezeRestrict)
1927         EnlargeCurrentToBox(&eraseCb);
1928     else
1929         EnlargeCurrentToBox(&lastCb);
1930 
1931     freezeRestrict = 0;
1932 }
1933 
1934 static void
updateDicePos(Path * path,DiceRotation * diceRot,float dist,float pos[3])1935 updateDicePos(Path * path, DiceRotation * diceRot, float dist, float pos[3])
1936 {
1937     if (movePath(path, dist, 0, pos)) {
1938         diceRot->xRot = (dist * diceRot->xRotFactor + diceRot->xRotStart) * 360;
1939         diceRot->yRot = (dist * diceRot->yRotFactor + diceRot->yRotStart) * 360;
1940     } else {                    /* Finished - set to end point */
1941         copyPoint(pos, path->pts[path->numSegments]);
1942         diceRot->xRot = diceRot->yRot = 0;
1943     }
1944 }
1945 
1946 static void
SetupMove(BoardData * bd,BoardData3d * bd3d)1947 SetupMove(BoardData * bd, BoardData3d * bd3d)
1948 {
1949     unsigned int destDepth;
1950     unsigned int target = convert_point(animate_move_list[slide_move], animate_player);
1951     unsigned int dest = convert_point(animate_move_list[slide_move + 1], animate_player);
1952     int dir = animate_player ? 1 : -1;
1953 
1954     bd->points[target] -= dir;
1955 
1956     animStartTime = get_time();
1957 
1958     destDepth = Abs(bd->points[dest]) + 1;
1959     if ((Abs(bd->points[dest]) == 1) && (dir != SGN(bd->points[dest])))
1960         destDepth--;
1961 
1962     setupPath(bd, &bd3d->piecePath, &bd3d->rotateMovingPiece, target, Abs(bd->points[target]) + 1, dest, destDepth);
1963     copyPoint(bd3d->movingPos, bd3d->piecePath.pts[0]);
1964 
1965     SetMovingPieceRotation(bd, bd3d, target);
1966 
1967     updatePieceOccPos(bd, bd3d);
1968 }
1969 
1970 static int firstFrame;
1971 
1972 static int
idleAnimate(BoardData3d * bd3d)1973 idleAnimate(BoardData3d * bd3d)
1974 {
1975     BoardData *bd = pIdleBD;
1976     float elapsedTime = (float) ((get_time() - animStartTime) / 1000.0f);
1977     float vel = .2f + nGUIAnimSpeed * .3f;
1978     float animateDistance = elapsedTime * vel;
1979     renderdata *prd = bd->rd;
1980 
1981     if (stopNextTime) {         /* Stop now - last animation frame has been drawn */
1982         StopIdle3d(bd, bd->bd3d);
1983         gtk_main_quit();
1984         return 1;
1985     }
1986 
1987     if (bd3d->moving) {
1988         float old_pos[3];
1989         ClipBox temp;
1990         float *pRotate = 0;
1991         if (bd3d->rotateMovingPiece >= 0.0f && bd3d->piecePath.state == 2)
1992             pRotate = &bd3d->rotateMovingPiece;
1993 
1994         copyPoint(old_pos, bd3d->movingPos);
1995 
1996         if (!movePath(&bd3d->piecePath, animateDistance, pRotate, bd3d->movingPos)) {
1997             TanBoard points;
1998             unsigned int moveStart = convert_point(animate_move_list[slide_move], animate_player);
1999             unsigned int moveDest = convert_point(animate_move_list[slide_move + 1], animate_player);
2000 
2001             if ((Abs(bd->points[moveDest]) == 1) && (bd->turn != SGN(bd->points[moveDest]))) {  /* huff */
2002                 unsigned int bar;
2003                 if (bd->turn == 1)
2004                     bar = 0;
2005                 else
2006                     bar = 25;
2007                 bd->points[bar] -= bd->turn;
2008                 bd->points[moveDest] = 0;
2009 
2010                 if (prd->quickDraw)
2011                     RestrictiveDrawPiece(bar, Abs(bd->points[bar]));
2012             }
2013 
2014             bd->points[moveDest] += bd->turn;
2015 
2016             /* Update pip-count mid move */
2017             read_board(bd, points);
2018             update_pipcount(bd, (ConstTanBoard) points);
2019 
2020             PlaceMovingPieceRotation(bd, bd3d, moveDest, moveStart);
2021 
2022             if (prd->quickDraw && numRestrictFrames != -1) {
2023                 float new_pos[3];
2024                 getPiecePos(moveDest, Abs(bd->points[moveDest]), new_pos);
2025                 if (moveDest == 26 || moveDest == 27) {
2026                     new_pos[2] -= PIECE_HOLE / 2.0f;
2027                     RestrictiveDraw(&temp, new_pos, PIECE_HOLE, PIECE_HOLE, PIECE_HOLE);
2028                 } else
2029                     RestrictiveDraw(&temp, new_pos, PIECE_HOLE, PIECE_HOLE, PIECE_DEPTH);
2030             }
2031 
2032             /* Next piece */
2033             slide_move += 2;
2034 
2035             if (slide_move >= 8 || animate_move_list[slide_move] < 0) { /* All done */
2036                 bd3d->moving = 0;
2037                 updatePieceOccPos(bd, bd3d);
2038                 animation_finished = TRUE;
2039                 stopNextTime = 1;
2040             } else
2041                 SetupMove(bd, bd3d);
2042 
2043             playSound(SOUND_CHEQUER);
2044         } else {
2045             updateMovingPieceOccPos(bd, bd3d);
2046             if (prd->quickDraw && numRestrictFrames != -1)
2047                 RestrictiveDraw(&temp, bd3d->movingPos, PIECE_HOLE, PIECE_HOLE, PIECE_DEPTH);
2048         }
2049         if (prd->quickDraw && numRestrictFrames != -1) {
2050             RestrictiveDrawFrame(old_pos, PIECE_HOLE, PIECE_HOLE, PIECE_DEPTH);
2051             EnlargeCurrentToBox( /*lint -e(645) */ &temp);      /* temp is initilized above (lint error 645) */
2052         }
2053     }
2054 
2055     if (bd3d->shakingDice) {
2056         if (!finishedPath(&bd3d->dicePaths[0]))
2057             updateDicePos(&bd3d->dicePaths[0], &bd3d->diceRotation[0], animateDistance / 2.0f, bd3d->diceMovingPos[0]);
2058         if (!finishedPath(&bd3d->dicePaths[1]))
2059             updateDicePos(&bd3d->dicePaths[1], &bd3d->diceRotation[1], animateDistance / 2.0f, bd3d->diceMovingPos[1]);
2060 
2061         if (finishedPath(&bd3d->dicePaths[0]) && finishedPath(&bd3d->dicePaths[1])) {
2062             bd3d->shakingDice = 0;
2063             stopNextTime = 1;
2064         }
2065         updateDiceOccPos(bd, bd3d);
2066 
2067         if (bd->rd->quickDraw && numRestrictFrames != -1) {
2068             float pos[3];
2069             float overSize;
2070             ClipBox temp;
2071 
2072             overSize = getDiceSize(bd->rd) * 1.5f;
2073             copyPoint(pos, bd3d->diceMovingPos[0]);
2074             pos[2] -= getDiceSize(bd->rd) / 2.0f;
2075             RestrictiveDrawFrame(pos, overSize, overSize, overSize);
2076 
2077             copyPoint(pos, bd3d->diceMovingPos[1]);
2078             pos[2] -= getDiceSize(bd->rd) / 2.0f;
2079             RestrictiveDraw(&temp, pos, overSize, overSize, overSize);
2080             EnlargeCurrentToBox(&temp);
2081 
2082             CopyBox(&temp, &cb[numRestrictFrames]);
2083             if (!firstFrame)
2084                 EnlargeCurrentToBox(&eraseCb);
2085             else if (firstFrame == -1)
2086                 RestrictiveRedraw();
2087             else
2088                 firstFrame = 0;
2089 
2090             CopyBox(&eraseCb, &temp);
2091         }
2092     }
2093 
2094     return 1;
2095 }
2096 
2097 void
RollDice3d(BoardData * bd,BoardData3d * bd3d,const renderdata * prd)2098 RollDice3d(BoardData * bd, BoardData3d * bd3d, const renderdata * prd)
2099 {                               /* animate the dice roll if not below board */
2100     setDicePos(bd, bd3d);
2101     GTKSuspendInput();
2102 
2103     if (prd->animateRoll) {
2104         animStartTime = get_time();
2105 
2106         bd3d->shakingDice = 1;
2107         stopNextTime = 0;
2108         setIdleFunc(bd, idleAnimate);
2109 
2110         setupDicePaths(bd, bd3d->dicePaths, bd3d->diceMovingPos, bd3d->diceRotation);
2111         /* Make sure shadows are in correct place */
2112         UpdateShadows(bd->bd3d);
2113         if (prd->quickDraw) {   /* Mark this as the first frame (or -1 to indicate full draw in progress) */
2114             if (numRestrictFrames == -1)
2115                 firstFrame = -1;
2116             else
2117                 firstFrame = 1;
2118         }
2119         gtk_main();
2120     } else {
2121         /* Show dice on board */
2122         gtk_widget_queue_draw(bd3d->drawing_area3d);
2123         while (gtk_events_pending())
2124             gtk_main_iteration();
2125     }
2126     GTKResumeInput();
2127 }
2128 
2129 void
AnimateMove3d(BoardData * bd,BoardData3d * bd3d)2130 AnimateMove3d(BoardData * bd, BoardData3d * bd3d)
2131 {
2132     slide_move = 0;
2133     bd3d->moving = 1;
2134 
2135     SetupMove(bd, bd3d);
2136 
2137     stopNextTime = 0;
2138     setIdleFunc(bd, idleAnimate);
2139     GTKSuspendInput();
2140     gtk_main();
2141     GTKResumeInput();
2142 }
2143 
2144 NTH_STATIC int
idleWaveFlag(BoardData3d * bd3d)2145 idleWaveFlag(BoardData3d * bd3d)
2146 {
2147     BoardData *bd = pIdleBD;
2148     float elapsedTime = (float) (get_time() - animStartTime);
2149     bd3d->flagWaved = elapsedTime / 200;
2150     updateFlagOccPos(bd, bd3d);
2151     RestrictiveDrawFlag(bd);
2152     return 1;
2153 }
2154 
2155 void
ShowFlag3d(BoardData * bd,BoardData3d * bd3d,const renderdata * prd)2156 ShowFlag3d(BoardData * bd, BoardData3d * bd3d, const renderdata * prd)
2157 {
2158     bd3d->flagWaved = 0;
2159 
2160     if (prd->animateFlag && bd->resigned && ms.gs == GAME_PLAYING && bd->playing && (ap[bd->turn == 1 ? 0 : 1].pt == PLAYER_HUMAN)) {   /* not for computer turn */
2161         animStartTime = get_time();
2162         setIdleFunc(bd, idleWaveFlag);
2163     } else
2164         StopIdle3d(bd, bd->bd3d);
2165 
2166     waveFlag(bd3d->flagWaved);
2167     updateFlagOccPos(bd, bd3d);
2168 
2169     RestrictiveDrawFlag(bd);
2170 }
2171 
2172 static int
idleCloseBoard(BoardData3d * bd3d)2173 idleCloseBoard(BoardData3d * bd3d)
2174 {
2175     BoardData *bd = pIdleBD;
2176     float elapsedTime = (float) (get_time() - animStartTime);
2177     if (bd3d->State == BOARD_CLOSED) {  /* finished */
2178         StopIdle3d(bd, bd->bd3d);
2179 #ifdef WIN32
2180         Sleep(1000);
2181 #else
2182         sleep(1);
2183 #endif
2184         gtk_main_quit();
2185 
2186         return 1;
2187     }
2188 
2189     bd3d->perOpen = (elapsedTime / 3000);
2190     if (bd3d->perOpen >= 1) {
2191         bd3d->perOpen = 1;
2192         bd3d->State = BOARD_CLOSED;
2193     }
2194 
2195     return 1;
2196 }
2197 
2198 static int
idleTestPerformance(BoardData3d * bd3d)2199 idleTestPerformance(BoardData3d * bd3d)
2200 {
2201     BoardData *bd = pIdleBD;
2202     float elapsedTime = (float) (get_time() - testStartTime);
2203     if (elapsedTime > TEST_TIME) {
2204         StopIdle3d(bd, bd3d);
2205         gtk_main_quit();
2206         return 0;
2207     }
2208     numFrames++;
2209     return 1;
2210 }
2211 
2212 float
TestPerformance3d(BoardData * bd)2213 TestPerformance3d(BoardData * bd)
2214 {
2215     float elapsedTime;
2216 
2217     setIdleFunc(bd, idleTestPerformance);
2218     testStartTime = get_time();
2219     numFrames = 0;
2220     gtk_main();
2221     elapsedTime = (float) (get_time() - testStartTime);
2222 
2223     return (numFrames / (elapsedTime / 1000.0f));
2224 }
2225 
2226 NTH_STATIC void
EmptyPos(BoardData * bd)2227 EmptyPos(BoardData * bd)
2228 {                               /* All checkers home */
2229     int ip[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, -15 };
2230     memcpy(bd->points, ip, sizeof(bd->points));
2231     updatePieceOccPos(bd, bd->bd3d);
2232 }
2233 
2234 void
CloseBoard3d(BoardData * bd,BoardData3d * bd3d,renderdata * prd)2235 CloseBoard3d(BoardData * bd, BoardData3d * bd3d, renderdata * prd)
2236 {
2237     bd3d->fBuffers = FALSE;
2238     EmptyPos(bd);
2239     bd3d->State = BOARD_CLOSED;
2240     /* Turn off most things so they don't interfere when board closed/opening */
2241     bd->cube_use = 0;
2242     bd->colour = 0;
2243     bd->direction = 1;
2244     bd->resigned = 0;
2245     fClockwise = 0;
2246     GTKSuspendInput();
2247 
2248     prd->showShadows = 0;
2249     prd->showMoveIndicator = 0;
2250     prd->fLabels = 0;
2251     bd->diceShown = DICE_NOT_SHOWN;
2252     bd3d->State = BOARD_CLOSING;
2253 
2254     /* Random logo */
2255     SetupSimpleMat(&bd3d->logoMat, 1.f, 1.f, 1.f);
2256     SetTexture(bd3d, &bd3d->logoMat, TEXTURE_PATH "logo.png");
2257 
2258     animStartTime = get_time();
2259     bd3d->perOpen = 0;
2260     setIdleFunc(bd, idleCloseBoard);
2261     /* Push matrix as idleCloseBoard assumes last matrix is on stack */
2262     glPushMatrix();
2263 
2264     gtk_main();
2265 }
2266 
2267 void
SetupViewingVolume3d(const BoardData * bd,BoardData3d * bd3d,const renderdata * prd)2268 SetupViewingVolume3d(const BoardData * bd, BoardData3d * bd3d, const renderdata * prd)
2269 {
2270     GLint viewport[4];
2271     float tempMatrix[16];
2272     glGetIntegerv(GL_VIEWPORT, viewport);
2273 
2274     memcpy(tempMatrix, bd3d->modelMatrix, sizeof(float[16]));
2275 
2276     glMatrixMode(GL_PROJECTION);
2277     glLoadIdentity();
2278     SetupPerspVolume(bd, bd3d, prd, viewport);
2279 
2280     SetupLight3d(bd3d, prd);
2281     calculateBackgroundSize(bd3d, viewport);
2282     if (memcmp(tempMatrix, bd3d->modelMatrix, sizeof(float[16])))
2283         RestrictiveRedraw();
2284 
2285     RerenderBase(bd3d);
2286 }
2287 
2288 void
SetupMat(Material * pMat,float r,float g,float b,float dr,float dg,float db,float sr,float sg,float sb,int shin,float a)2289 SetupMat(Material * pMat, float r, float g, float b, float dr, float dg, float db, float sr, float sg, float sb,
2290          int shin, float a)
2291 {
2292     pMat->ambientColour[0] = r;
2293     pMat->ambientColour[1] = g;
2294     pMat->ambientColour[2] = b;
2295     pMat->ambientColour[3] = a;
2296 
2297     pMat->diffuseColour[0] = dr;
2298     pMat->diffuseColour[1] = dg;
2299     pMat->diffuseColour[2] = db;
2300     pMat->diffuseColour[3] = a;
2301 
2302     pMat->specularColour[0] = sr;
2303     pMat->specularColour[1] = sg;
2304     pMat->specularColour[2] = sb;
2305     pMat->specularColour[3] = a;
2306     pMat->shine = shin;
2307 
2308     pMat->alphaBlend = (a < 1.0f) && (a > 0.0f);
2309 
2310     pMat->textureInfo = NULL;
2311     pMat->pTexture = NULL;
2312 }
2313 
2314 static void
SetupSimpleMatAlpha(Material * pMat,float r,float g,float b,float a)2315 SetupSimpleMatAlpha(Material * pMat, float r, float g, float b, float a)
2316 {
2317     SetupMat(pMat, r, g, b, r, g, b, 0.f, 0.f, 0.f, 0, a);
2318 }
2319 
2320 void
SetupSimpleMat(Material * pMat,float r,float g,float b)2321 SetupSimpleMat(Material * pMat, float r, float g, float b)
2322 {
2323     SetupMat(pMat, r, g, b, r, g, b, 0.f, 0.f, 0.f, 0, 0.f);
2324 }
2325 
2326 /* Not currently used
2327  * void RemoveTexture(Material* pMat)
2328  * {
2329  * if (pMat->pTexture)
2330  * {
2331  * int i = 0;
2332  * while (&bd->textureList[i] != pMat->pTexture)
2333  * i++;
2334  *
2335  * DeleteTexture(&bd->textureList[i]);
2336  * free(bd->textureName[i]);
2337  *
2338  * while (i != bd->numTextures - 1)
2339  * {
2340  * bd->textureList[i] = bd->textureList[i + 1];
2341  * bd->textureName[i] = bd->textureName[i + 1];
2342  * i++;
2343  * }
2344  * bd->numTextures--;
2345  * pMat->pTexture = 0;
2346  * }
2347  * }
2348  */
2349 
2350 void
ClearTextures(BoardData3d * bd3d)2351 ClearTextures(BoardData3d * bd3d)
2352 {
2353     int i;
2354     if (!bd3d->numTextures)
2355         return;
2356 
2357     MakeCurrent3d(bd3d);
2358 
2359     for (i = 0; i < bd3d->numTextures; i++) {
2360         DeleteTexture(&bd3d->textureList[i]);
2361         free(bd3d->textureName[i]);
2362     }
2363     bd3d->numTextures = 0;
2364 }
2365 
2366 static void
free_texture(gpointer data,gpointer UNUSED (userdata))2367 free_texture(gpointer data, gpointer UNUSED(userdata))
2368 {
2369     free(data);
2370 }
2371 
2372 void
DeleteTextureList(void)2373 DeleteTextureList(void)
2374 {
2375     g_list_foreach(textures, free_texture, NULL);
2376     g_list_free(textures);
2377 }
2378 
2379 void
InitBoard3d(BoardData * bd,BoardData3d * bd3d)2380 InitBoard3d(BoardData * bd, BoardData3d * bd3d)
2381 {                               /* Initialize 3d parts of boarddata */
2382     int i, j;
2383     /* Assign random rotation to each board position */
2384     for (i = 0; i < 28; i++)
2385         for (j = 0; j < 15; j++)
2386             bd3d->pieceRotation[i][j] = rand() % 360;
2387 
2388     bd3d->shadowsInitialised = FALSE;
2389     bd3d->shadowsOutofDate = TRUE;
2390     bd3d->State = BOARD_OPEN;
2391     bd3d->moving = 0;
2392     bd3d->shakingDice = 0;
2393     bd->drag_point = -1;
2394     bd->DragTargetHelp = 0;
2395     bd3d->fBasePreRendered = FALSE;
2396 
2397     SetupSimpleMat(&bd3d->gapColour, 0.f, 0.f, 0.f);
2398     SetupMat(&bd3d->flagMat, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 50, 0.f);
2399     SetupMat(&bd3d->flagNumberMat, 0.f, 0.f, .4f, 0.f, 0.f, .4f, 1.f, 1.f, 1.f, 100, 1.f);
2400 
2401     bd3d->diceList = bd3d->DCList = bd3d->pieceList = 0;
2402     bd3d->qobjTex = bd3d->qobj = 0;
2403 
2404     bd3d->numTextures = 0;
2405 
2406     bd3d->boardPoints = NULL;
2407     bd3d->numberFont = bd3d->cubeFont = NULL;
2408 
2409     memset(bd3d->modelMatrix, 0, sizeof(float[16]));
2410 
2411     bd->bd3d->fBuffers = FALSE;
2412 }
2413 
2414 #if defined(HAVE_LIBPNG)
2415 
2416 void
GenerateImage3d(const char * szName,unsigned int nSize,unsigned int nSizeX,unsigned int nSizeY)2417 GenerateImage3d(const char *szName, unsigned int nSize, unsigned int nSizeX, unsigned int nSizeY)
2418 {
2419     unsigned char *puch;
2420     BoardData *bd = BOARD(pwBoard)->board_data;
2421     GdkPixbuf *pixbuf;
2422     GError *error = NULL;
2423     unsigned int line;
2424     unsigned int width = nSize * nSizeX;
2425     unsigned int height = nSize * nSizeY;
2426 
2427     /* Allocate buffer for image, height + 1 as extra line needed to invert image (opengl renders 'upside down') */
2428     if ((puch = (unsigned char *) malloc(width * (height + 1) * 3)) == NULL) {
2429         outputerr("malloc");
2430         return;
2431     }
2432 
2433     RenderToBuffer3d(bd, bd->bd3d, width, height, puch);
2434 
2435     /* invert image (y axis) */
2436     for (line = 0; line < height / 2; line++) {
2437         unsigned int lineSize = width * 3;
2438         /* Swap two lines at a time */
2439         memcpy(puch + height * lineSize, puch + line * lineSize, lineSize);
2440         memcpy(puch + line * lineSize, puch + ((height - line) - 1) * lineSize, lineSize);
2441         memcpy(puch + ((height - line) - 1) * lineSize, puch + height * lineSize, lineSize);
2442     }
2443 
2444     pixbuf = gdk_pixbuf_new_from_data(puch, GDK_COLORSPACE_RGB, FALSE, 8,
2445                                       (int) width, (int) height, (int) width * 3, NULL, NULL);
2446 
2447     gdk_pixbuf_save(pixbuf, szName, "png", &error, NULL);
2448     if (error) {
2449         outputerrf("png failed: %s\n", error->message);
2450         g_error_free(error);
2451     }
2452     g_object_unref(pixbuf);
2453     free(puch);
2454 }
2455 
2456 #endif
2457 
2458 extern GtkWidget *
GetDrawingArea3d(const BoardData3d * bd3d)2459 GetDrawingArea3d(const BoardData3d * bd3d)
2460 {
2461     return bd3d->drawing_area3d;
2462 }
2463 
2464 extern char *
MaterialGetTextureFilename(const Material * pMat)2465 MaterialGetTextureFilename(const Material * pMat)
2466 {
2467     return pMat->textureInfo->file;
2468 }
2469 
2470 extern void
TidyCurveAccuracy3d(BoardData3d * bd3d,unsigned int accuracy)2471 TidyCurveAccuracy3d(BoardData3d * bd3d, unsigned int accuracy)
2472 {
2473     freeEigthPoints(&bd3d->boardPoints, accuracy);
2474 }
2475 
2476 extern void
DrawScene3d(const BoardData3d * bd3d)2477 DrawScene3d(const BoardData3d * bd3d)
2478 {
2479     gtk_widget_queue_draw(bd3d->drawing_area3d);
2480 }
2481 
2482 extern int
Animating3d(const BoardData3d * bd3d)2483 Animating3d(const BoardData3d * bd3d)
2484 {
2485     return (bd3d->shakingDice || bd3d->moving);
2486 }
2487 
2488 extern void
RerenderBase(BoardData3d * bd3d)2489 RerenderBase(BoardData3d * bd3d)
2490 {
2491     bd3d->fBasePreRendered = FALSE;
2492 }
2493 
2494 extern gboolean
display_is_3d(const renderdata * prd)2495 display_is_3d(const renderdata * prd)
2496 {
2497     g_assert(prd->fDisplayType == DT_2D || (prd->fDisplayType == DT_3D && gtk_gl_init_success));
2498     return (prd->fDisplayType == DT_3D);
2499 }
2500 
2501 extern gboolean
display_is_2d(const renderdata * prd)2502 display_is_2d(const renderdata * prd)
2503 {
2504     displaytype fdt = prd->fDisplayType;
2505     g_assert(fdt == DT_2D || fdt == DT_3D);
2506     return (fdt == DT_2D ? TRUE : FALSE);
2507 }
2508 
2509 extern void
Draw3d(const BoardData * bd)2510 Draw3d(const BoardData * bd)
2511 {                               /* Render board: quick drawing, standard or 2 passes for shadows */
2512 #ifdef WIN32
2513     GtkAllocation allocation;
2514     gtk_widget_get_allocation(bd->bd3d->drawing_area3d, &allocation);
2515 
2516     if (bd->bd3d->fBuffers) {
2517         if (bd->bd3d->fBasePreRendered)
2518             RestoreBufferRegion(bd->bd3d->wglBuffer, 0, 0, allocation.width, allocation.height);
2519         else {
2520             drawBasePreRender(bd, bd->bd3d, bd->rd);
2521             bd->bd3d->fBasePreRendered = TRUE;
2522         }
2523 
2524         if (bd->rd->showShadows)
2525             shadowDisplay(drawBoardTop, bd, bd->bd3d, bd->rd);
2526         else
2527             drawBoardTop(bd, bd->bd3d, bd->rd);
2528     } else
2529 #endif
2530     {
2531         if (bd->rd->showShadows)
2532             shadowDisplay(drawBoard, bd, bd->bd3d, bd->rd);
2533         else
2534             drawBoard(bd, bd->bd3d, bd->rd);
2535     }
2536 }
2537 
2538 static int diceRollingSave;
2539 void
SuspendDiceRolling(renderdata * prd)2540 SuspendDiceRolling(renderdata * prd)
2541 {
2542     diceRollingSave = prd->animateRoll;
2543     prd->animateRoll = FALSE;
2544 }
2545 
2546 void
ResumeDiceRolling(renderdata * prd)2547 ResumeDiceRolling(renderdata * prd)
2548 {
2549     prd->animateRoll = diceRollingSave;
2550 }
2551