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