(Temporarily) set "animate" to "none" by default (broken feature).
[gf1.git] / drawgif.cxx
blobd3cfb3f57538c64135cac5bdfa762a8096f26409
1 /*
2 ** $Id$
3 **
4 ** member-functions for the drawgif-class
5 */
6 /*
7 ** Copyright (C) 1998 Kurt Van den Branden
8 **
9 ** This program is free software; you can redistribute it and/or modify
10 ** it under the terms of the GNU General Public License as published by
11 ** the Free Software Foundation; either version 2 of the License, or
12 ** (at your option) any later version.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #ifdef HAVEGD
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include "drawgif.h"
31 extern "C" {
32 #include <gd.h>
33 #include <gdfontg.h>
34 #include <gdfontl.h>
35 #include <gdfontmb.h>
36 #include <gdfonts.h>
37 #include <gdfontt.h>
40 #define round(x) (int)(x + 0.5)
41 #define MY_PI 3.14159
43 // x and y-position of each first point of a column
44 // based on a square of 2.5 by 2.5
45 double gif_rowbase[9][2] = {
46 {.384, 2}, // row a
47 {.6005, 2.125}, // row b
48 {.817, 2.25}, // row c
49 {1.0335, 2.375}, // row d
50 {1.25, 2.5}, // row e
51 {1.4665, 2.375}, // row f
52 {1.683, 2.25}, // row g
53 {1.8995, 2.125}, // row h
54 {2.116, 2}};// row i
56 /* lines on the board */
57 const position gif_linetable[21][2] = {
58 {{0, 4}, {5, 8}}, {{0, 3}, {6, 7}}, {{0, 2}, {7, 6}},
59 {{0, 1}, {8, 5}}, {{1, 1}, {8, 4}}, {{2, 1}, {8, 3}},
60 {{3, 1}, {8, 2}}, {{0, 2}, {5, 1}}, {{0, 3}, {6, 1}},
61 {{0, 4}, {7, 1}}, {{0, 5}, {8, 1}}, {{1, 6}, {8, 2}},
62 {{2, 7}, {8, 3}}, {{3, 8}, {8, 4}}, {{1, 6}, {1, 1}},
63 {{2, 7}, {2, 1}}, {{3, 8}, {3, 1}}, {{4, 9}, {4, 1}},
64 {{5, 8}, {5, 1}}, {{6, 7}, {6, 1}}, {{7, 6}, {7, 1}}
67 /* possible from-points */
68 const position gif_fromtable[24] = {
69 {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {1, 6},
70 {2, 7}, {3, 8}, {4, 9}, {5, 8}, {6, 7}, {7, 6},
71 {8, 5}, {8, 4}, {8, 3}, {8, 2}, {8, 1}, {7, 1},
72 {6, 1}, {5, 1}, {4, 1}, {3, 1}, {2, 1}, {1, 1},
75 /* white hexagon */
76 const position gif_hexagon[7] = {
77 {1, 2}, {1, 5}, {4, 8}, {7, 5}, {7, 2}, {4, 2}, {1, 2}
81 drawgif::drawgif ()
83 filen = NULL;
84 size = 300;
85 colour = 1;
86 gipfb = NULL;
87 extratext = NULL;
89 return;
93 drawgif::~drawgif ()
95 char * ptr;
97 if (filen != NULL)
98 free (filen);
100 if (gipfb != NULL)
101 b_del (gipfb);
103 if (extratext != NULL)
105 while ((ptr = (char *) llrembynr (extratext, 1)) != NULL)
106 free (ptr);
108 free (extratext);
111 return;
115 void drawgif::filename (const char * fn)
117 if (filen != NULL)
118 free (filen);
120 filen = strdup (fn);
122 return;
126 void drawgif::gifboard (board * gb)
128 if (gipfb != NULL)
129 b_del (gipfb);
131 gipfb = b_copy (gb);
133 return;
137 void drawgif::addtext (const char * text)
139 char * tempstr,
140 * kar1,
141 * kar2;
143 if (extratext == NULL)
145 extratext = (listheader *) malloc (sizeof (listheader));
146 newlist (extratext);
149 tempstr = strdup (text);
150 kar1 = tempstr;
152 // split on '\n'
153 while ((kar2 = strchr (kar1, '\n')) != NULL)
155 kar2[0] = '\0';
156 pushll (extratext, strdup (kar1));
157 kar1 = kar2 + 1;
159 pushll (extratext, strdup (kar1));
161 free (tempstr);
163 return;
167 int drawgif::draw ()
169 int black,
170 white,
171 yellow,
172 lgray,
173 counter,
174 offset,
175 gray,
176 red,
177 notused,
178 texth,
179 pieceh,
180 poffset,
181 i, j;
182 gdImagePtr image;
183 FILE * imagefp;
184 FILE * fp;
185 int diam,
186 x,y,
187 x1, y1, x2, y2,
189 diam2;
190 char tempstr[20];
191 gdFontPtr thefont = gdFontTiny;
192 gdPoint hexa[7];
193 listheader * extralist;
194 int extralines = 0,
195 maxchar;
196 char * strptr;
197 position * temppos;
199 /* choose font according to drawing-size */
200 if (size < 200)
201 thefont = gdFontTiny;
202 else if (size < 250)
203 thefont = gdFontSmall;
204 else if (size < 350)
205 thefont = gdFontMediumBold;
206 else if (size < 450)
207 thefont = gdFontLarge;
208 else
209 thefont = gdFontGiant;
212 ** find out how many extra lines have to be displayed
213 ** and split lines that are to long to fit
215 extralist = (listheader *) malloc (sizeof (listheader));
216 newlist (extralist);
217 maxchar = size / thefont->w - 2;
218 counter = 1;
219 while ((strptr = (char *) llitembynr (extratext, counter)) != NULL)
221 counter++;
222 extralines += splitline (extralist, strptr, maxchar);
225 /* create image */
226 base = size / 2.5;
227 image = gdImageCreate(size, size + thefont->h *
228 (extralines == 0 ? 0 : extralines + 1));
229 gdImageInterlace(image, 1);
231 /* all colors have been chosen to be the ones used by Netscape
232 when used in 256 color mode */
234 /* Allocate the color lgray (red, green and blue).
235 Since this is the first color in a new image, it will
236 be the background color. */
237 if (!colour)
239 white = gdImageColorAllocate(image, 255, 255, 255);
240 black = gdImageColorAllocate(image, 0, 0, 0);
242 /*lgray = white;*/
244 else
245 lgray = gdImageColorAllocate(image, 204, 204, 204);
247 /* Allocate the color black (red, green and blue). */
248 if (!colour)
250 yellow = white;
251 gray = black;
252 red = black;
254 else
256 white = gdImageColorAllocate(image, 255, 255, 255);
257 black = gdImageColorAllocate(image, 0, 0, 0);
258 yellow = gdImageColorAllocate(image, 255, 255, 204);
259 gray = gdImageColorAllocate (image, 153, 153, 153);
260 red = gdImageColorAllocate (image, 255, 0, 0);
263 /* the 'notused' color can be used for drawing the outline of a figure
264 you want to fill later */
265 notused = gdImageColorAllocate (image, 1, 1, 1);
267 /* draw rectangle around image */
268 gdImageRectangle (image, 0, 0, size-1, size-1, black);
270 /* draw hexagon */
271 for (i = 0; i < 6; i++)
273 pos2coor (&gif_hexagon[i], hexa[i].x, hexa[i].y);
275 gdImageFilledPolygon(image, hexa, 6, white);
277 /* draw from-points */
278 diam = round (base / 12);
279 for (i = 0; i < 24; i++)
281 pos2coor (&gif_fromtable[i], x, y);
282 gdImageArc(image,
283 x, y,
284 diam, diam,
285 0, 360, black);
286 gdImageFillToBorder(image,
287 x, y,
288 black, black);
291 /* draw lines */
292 for (i = 0 ; i < 21; i++)
294 pos2coor (&gif_linetable[i][0], x1, y1);
295 pos2coor (&gif_linetable[i][1], x2, y2);
296 gdImageLine (image,
297 x1, y1, x2, y2,
298 black);
301 /* draw pieces */
302 /* calculate size of piece */
303 diam = round (base / 6);
304 diam2 = round (base / 10);
306 temppos = (position *) malloc (sizeof (position));
308 for (i = 1; i < 8; i++)
309 for (j = 2; j <= b_colsize (i); j++)
311 posp_col (temppos) = i;
312 posp_row (temppos) = j;
314 if (b_ppiece (gipfb, temppos) != '.')
316 /* calculate position of center of the piece */
317 pos2coor (temppos, x, y);
319 gdImageArc (image, x, y, diam, diam, 0, 360, notused);
320 if ((b_ppiece (gipfb, temppos) == 'o') ||
321 (b_ppiece (gipfb, temppos) == 'O'))
323 gdImageFillToBorder (image, x, y, notused, yellow);
325 else
327 gdImageFillToBorder (image, x, y, notused, black);
329 gdImageArc (image, x, y, diam, diam, 0, 360, black);
331 if ((b_ppiece (gipfb, temppos) == 'X') ||
332 (b_ppiece (gipfb, temppos) == 'O'))
334 if (!colour)
336 if (b_ppiece (gipfb, temppos) == 'O')
337 gray = black;
338 else
339 gray = white;
342 gdImageArc (image, x, y, diam2, diam2, 0, 360, gray);
343 if (size >= 250)
344 gdImageArc (image, x, y, diam2-1, diam2-1, 0, 360,
345 gray);
350 free (temppos);
352 #if 0
353 double base8;
354 gdPoint rotarrow[7];
355 double sina,
356 cosa;
358 /* draw arrows */
359 base8 = base / 8;
360 while ((arr = (arrowitem *) llrembynr (arrowlist, 1)) != NULL)
362 /* calculate position */
363 x = round (rowbase[arr->col][0] * base);
364 y = round ((rowbase[arr->col][1] - arr->row * .25) * base);
366 cosa = cos ((double) arr->angle * MY_PI / 180);
367 sina = sin ((double) arr->angle * MY_PI / 180);
368 for (i = 0; i < 8; i++)
369 { /* the 8th point is the center and used by the fill */
370 rotarrow[i].x = x +
371 round (base8 * (arrow[i][0] * cosa - arrow[i][1] * sina));
372 rotarrow[i].y = y -
373 round (base8 * (arrow[i][0] * sina + arrow[i][1] * cosa));
376 gdImagePolygon (image, rotarrow, 7, notused);
377 gdImageFillToBorder (image, rotarrow[7].x, rotarrow[7].y,
378 notused, red);
379 gdImagePolygon (image, rotarrow, 7, black);
381 free (arr);
383 free (arrowlist);
384 #endif
386 /* draw position-names */
387 for (i = 0; i < 9; i++)
389 sprintf (tempstr, "%c1", i+'a');
390 x = round (gif_rowbase[i][0] * base) - thefont->w;
391 y = round ((gif_rowbase[i][1] - .125) * base) - 3;
393 gdImageString(image, thefont, x, y, (unsigned char*)tempstr, black);
395 nr = (i < 5 ? i + 5 : 13 - i);
396 sprintf (tempstr, "%c%d", i+'a', nr);
397 y = size - round ((gif_rowbase[i][1] - .125) * base) - thefont->h + 3;
399 gdImageString(image, thefont, x, y, (unsigned char*)tempstr, black);
402 /* draw piles of available pieces */
403 pieceh = round (base / 30);
404 poffset = round (base / 20);
405 diam = round (base / 6);
406 texth = thefont->h;
408 /* white */
409 sprintf (tempstr, "white: %d", b_white (gipfb));
410 gdImageString (image, thefont, diam/4, size-texth*2-3, (unsigned char*)tempstr, black);
412 offset = size - texth*2 - 3;
413 for (i = 1; i <= b_white (gipfb); i++)
415 gdImageRectangle (image,
416 diam/2, offset - poffset * i,
417 round (diam * 1.5), offset - poffset * i + pieceh,
418 black);
419 gdImageFillToBorder (image, diam/2+1,
420 offset - poffset * i + 1,
421 black, yellow);
423 sprintf (tempstr, "lost : %d", b_white_lost (gipfb));
424 gdImageString (image, thefont, diam/4, size-texth-3, (unsigned char*)tempstr, black);
426 /* black */
427 sprintf (tempstr, "%d :black", b_black (gipfb));
428 gdImageString (image, thefont,
429 size - diam/4 - thefont->w * strlen (tempstr),
430 size-texth*2-3, (unsigned char*)tempstr, black);
432 offset = size - texth*2 - 3;
433 for (i = 1; i <= b_black (gipfb); i++)
435 gdImageRectangle (image,
436 round (size - diam * 1.5), offset - poffset * i,
437 size - diam/2, offset - poffset * i + pieceh,
438 black);
439 gdImageFillToBorder (image, size - diam/2 - 1,
440 offset - poffset * i + 1,
441 black, black);
443 sprintf (tempstr, "%d : lost", b_black_lost (gipfb));
444 gdImageString (image, thefont,
445 size - diam/4 - thefont->w * strlen (tempstr),
446 size-texth-3, (unsigned char*)tempstr, black);
449 ** draw gipf-logo
450 ** (if the file is available)
452 if ((imagefp = fopen ("small_logo.png", "rb")) != NULL)
454 gdImagePtr loadimage;
456 loadimage = gdImageCreateFromPng (imagefp);
457 fclose (imagefp);
458 if (loadimage != NULL)
460 gdImageCopy(image, loadimage, 1, 1, 0, 0,
461 loadimage->sx, loadimage->sy);
464 gdImageDestroy (loadimage);
468 /* draw extra lines of text */
469 if (extralines > 0)
471 gdImageFilledRectangle (image, 0, size, size-1,
472 size + thefont->h * (extralines + 1) - 1,
473 white);
474 gdImageRectangle (image, 0, size, size-1,
475 size + thefont->h * (extralines + 1) - 1,
476 black);
477 i = 0;
478 while ((strptr = (char *) llrembynr (extralist, 1)) != NULL)
480 gdImageString (image, thefont, thefont->w,
481 size + thefont->h / 2 + thefont->h * i,
482 (unsigned char*)strptr, black);
483 free (strptr);
484 i++;
487 free (extralist);
489 gdImageColorDeallocate(image, notused);
491 /* open file for output */
492 fp = fopen(filen, "wb");
493 /* Output the image to the disk file. */
494 gdImagePng(image, fp);
495 /* Close the file. */
496 fclose(fp);
498 /* Destroy the image in memory. */
499 gdImageDestroy(image);
502 return (1);
506 ** the 'string' will be copied and added to 'llist'
507 ** if 'string' is longer then 'maxchar', it will be splitted
508 ** into several strings and added to 'llist'
510 ** returns: nr of strings added to 'llist'
512 int drawgif::splitline (listheader * llist, char * string, int maxchar)
514 char * newstring,
515 * kar,
516 * kar2,
517 * tempstr,
518 savechar = 0;
519 int counter = 0;
521 tempstr = strdup (string);
522 kar = tempstr;
523 while (strlen(kar) > maxchar)
525 kar2 = kar + maxchar;
526 while ((kar2 > kar) && (!isspace ((int) kar2[0])))
528 kar2--;
530 if (kar2 == kar)
531 { /* string too long to be splitted, do the dirty split */
532 savechar = kar[maxchar];
533 kar2 = kar + maxchar;
535 kar2[0] = '\0';
536 newstring = (char *) malloc (strlen (kar) + 1);
537 strcpy (newstring, kar);
538 pushll (llist, (void *) newstring);
539 counter++;
541 if (savechar != 0)
543 kar[maxchar] = savechar;
544 savechar = 0;
545 kar = kar2;
547 else
549 kar = kar2 + 1;
553 /* last piece */
554 newstring = (char *) malloc (strlen (kar) + 1);
555 strcpy (newstring, kar);
556 pushll (llist, (void *) newstring);
557 counter++;
559 free (tempstr);
561 return (counter);
565 ** calculate coordinates starting from a board-position
567 void drawgif::pos2coor (const position *pos, int& x, int& y)
569 x = round (gif_rowbase[pos->col][0] * base);
570 y = round ((gif_rowbase[pos->col][1] - pos->row * .25) * base);
572 return;
575 #endif