1 /**
2 * XFrisk - The classic board game for X
3 * Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * $Id: cards.c,v 1.20 2000/01/12 19:40:41 morphy Exp $
20 *
21 * $Log: cards.c,v $
22 * Revision 1.20 2000/01/12 19:40:41 morphy
23 * Comment changes, removed note about Argentina card color (not current anymore)
24 *
25 * Revision 1.19 2000/01/10 22:47:40 tony
26 * made colorstuff more private to colormap.c, only scrollbars get set wrong, rest seems to work ok now
27 *
28 * Revision 1.18 2000/01/09 16:07:46 tony
29 * wrong doxygen tags
30 *
31 * Revision 1.17 2000/01/08 18:38:03 tony
32 * oops, even dumped core
33 *
34 * Revision 1.16 2000/01/08 17:28:03 tony
35 * comment added
36 *
37 * Revision 1.15 2000/01/08 01:45:34 tony
38 * color greenland card fixed! ?
39 *
40 * Revision 1.13 2000/01/04 21:41:53 tony
41 * removed redundant stuff for jokers
42 *
43 * Revision 1.12 2000/01/04 21:11:06 tony
44 * a bit more structure by using Cards[]
45 *
46 * Revision 1.11 1999/12/25 21:58:02 morphy
47 * Fixed typo in doxygen file comment
48 *
49 * Revision 1.10 1999/12/19 22:51:09 tony
50 * cl0d fixed greenland card
51 *
52 */
53
54 /** \file
55 * Graphical part of cards handling for client
56 */
57
58 #include <X11/Xlib.h>
59 #include <X11/X.h>
60 #include <X11/Intrinsic.h>
61 #include <X11/StringDefs.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <unistd.h>
65
66 #include "network.h"
67 #include "gui-vars.h"
68 #include "riskgame.h"
69 #include "client.h"
70 #include "types.h"
71 #include "utils.h"
72 #include "cards.h"
73 #include "colormap.h"
74 #include "callbacks.h"
75 #include "debug.h"
76
77 #define PICTURE_FRACTION 0.6
78
79 /* Private function */
80 static void _CARDS_ComputeScaleVector(Int32 *piVector, Int32 x0, Int32 y0,
81 Int32 x1, Int32 y1);
82
83 /* Private data */
84
85 /** A structure to hold the directory information */
86 static struct Directory
87 {
88 Int32 iWidth, iHeight, iLength;
89 Int32 lOffset;
90 } pDirectory[NUM_COUNTRIES];
91
92 /** Cards */
93 static struct {
94 Pixmap pixmap;
95 Int32 color;
96 } Cards[NUM_CARDS];
97
98 /** Font structure for card texts */
99 static XFontStruct *pCardFont;
100
101
102 /**
103 * Initialize the set of cards, called once on start
104 *
105 * \b History:
106 * \arg 27.10.99 TdH Moved out of CARDS_RenderCard
107 */
CARDS_Init()108 void CARDS_Init() {
109 int i;
110 /* Load the font */
111 if ((pCardFont=XLoadQueryFont(hDisplay, "*helvetica-b*-r-*12*")) == NULL)
112 {
113 (void)UTIL_PopupDialog("Warning",
114 "Could not open card font (using fixed)\n", 1,
115 "Ok", NULL, NULL);
116 /* Assume 'fixed' is always there -- not good. */
117 pCardFont = XLoadQueryFont(hDisplay, "fixed");
118 }
119 /* Init the pixmap cache */
120 for (i=0; i!=NUM_CARDS; i++) {
121 Cards[i].pixmap = 0L;
122 Cards[i].color = -1;
123 }
124 }
125
126
127 /**
128 * Set color of card, create bitmap if not yet there
129 * \b History:
130 * \arg 05.01.00 TdH Created
131 *
132 * \b Notes:
133 * Took out of CARDS_RenderCard
134 */
135
CARDS_SetColor(Int32 iCard,Int32 iColor)136 void CARDS_SetColor(Int32 iCard, Int32 iColor) {
137 XImage *pimageCountry;
138 Int32 iPictureWidth, iPictureHeight, iPictureOffset;
139 Int32 iFontHeight, iFontWidth;
140 Int32 blackpixel,whitepixel;
141 Int32 x, y, c;
142 char buf[256];
143
144 Cards[iCard].color = iColor;/* new color */
145 whitepixel = WhitePixel(hDisplay, 0);
146 blackpixel = BlackPixel(hDisplay, 0);
147
148
149 /* Makes life easier */
150 iPictureWidth = CARD_WIDTH;
151 iPictureHeight = (double)CARD_HEIGHT * PICTURE_FRACTION;
152 iPictureOffset = CARD_HEIGHT - iPictureHeight;
153
154 /* Check to see if pixmap is in cache. If not, build it */
155 if (Cards[iCard].pixmap == 0L) {
156 Cards[iCard].pixmap = XCreatePixmap(hDisplay, pixMapImage,
157 CARD_WIDTH, CARD_HEIGHT,
158 COLOR_GetDepth());
159
160 /* Fill the card up with white and black */
161 XSetForeground(hDisplay, hGC, blackpixel);
162 XFillRectangle(hDisplay, Cards[iCard].pixmap, hGC,
163 0, 0,
164 CARD_WIDTH, CARD_HEIGHT);
165 XSetForeground(hDisplay, hGC, WhitePixel(hDisplay, 0));
166 XFillRectangle(hDisplay, Cards[iCard].pixmap, hGC,
167 0, 0,
168 CARD_WIDTH, iPictureOffset);
169 }
170
171 pimageCountry = CARDS_GetCountryImage(iCard, -1, -1);
172
173 /* Compress the card image, being careful about the pointer */
174 pimageCountry = CARDS_ScaleImage(pimageCountry,
175 (Int32)(4.0/5.0 * (float)iPictureWidth),
176 (Int32)(4.0/5.0 * (float)iPictureHeight));
177
178 /* Dump image, centered, on lower 2/3 of card */
179 if (COLOR_IsTrueColor()) {
180 for (y = 0; y < pimageCountry->height; y++) {
181 for (x = 0; x < pimageCountry->width; x++) {
182 c = XGetPixel(pimageCountry, x, y);
183 if (c != blackpixel) {
184 c = iColor;
185 }
186 XSetForeground(hDisplay, hGC, c);
187 XDrawPoint(hDisplay, Cards[iCard].pixmap, hGC,
188 (iPictureWidth - pimageCountry->width)/2 + x,
189 iPictureOffset + (iPictureHeight - pimageCountry->height)/2 + y);
190 }
191 }
192 } else
193 XPutImage(hDisplay, Cards[iCard].pixmap, hGC, pimageCountry, 0, 0,
194 (iPictureWidth - pimageCountry->width)/2,
195 iPictureOffset +
196 (iPictureHeight - pimageCountry->height)/2,
197 pimageCountry->width,
198 pimageCountry->height);
199
200
201 /* Write the name of the country on the card */
202 iFontHeight = (pCardFont->max_bounds.ascent
203 + pFont->max_bounds.descent);
204 iFontWidth = XTextWidth(pCardFont,
205 RISK_GetNameOfCountry(iCard),
206 strlen(RISK_GetNameOfCountry(iCard)));
207
208 /* Set the font */
209 XSetFont(hDisplay, hGC, pCardFont->fid);
210
211 XSetForeground(hDisplay, hGC, whitepixel);
212 XDrawString(hDisplay, Cards[iCard].pixmap, hGC,
213 (iPictureWidth - iFontWidth)/2,
214 iPictureOffset+iFontHeight,
215 RISK_GetNameOfCountry(iCard),
216 strlen(RISK_GetNameOfCountry(iCard)));
217
218 /* Lose all of the used memory */
219 XDestroyImage(pimageCountry);
220
221 /* Now put the appropriate bitmap there */
222 #ifdef ENGLISH
223 snprintf(buf, sizeof(buf), "%s", (iCard%3==0) ? "Cavalry" :
224 (iCard%3==1) ? "Infantry" : "Artillery");
225 #endif
226 #ifdef FRENCH
227 snprintf(buf, sizeof(buf), "%s", (iCard%3==0) ? "Cavalerie" :
228 (iCard%3==1) ? "Infanterie" : "Artillerie");
229 #endif
230 iFontWidth = XTextWidth(pCardFont, buf, strlen(buf));
231 XSetForeground(hDisplay, hGC, blackpixel);
232 XDrawString(hDisplay, Cards[iCard].pixmap, hGC,
233 (CARD_WIDTH - iFontWidth)/2,
234 iFontHeight,
235 buf, strlen(buf));
236 }
237
238
239 /**
240 * Create pixmap for joker
241 *
242 * \b History:
243 * \arg 05.01.00 TdH Created
244 *
245 * \b Notes:
246 * Took out of CARDS_RenderCard
247 */
248
CARDS_GetJoker(Int32 iCard)249 void CARDS_GetJoker(Int32 iCard) {
250 char buf[256];
251
252 if (Cards[iCard].pixmap == 0L){
253 Int32 iFontHeight, iFontWidth;
254
255 /* Makes life easier */
256
257 Cards[iCard].pixmap = XCreatePixmap(hDisplay, pixMapImage,
258 CARD_WIDTH, CARD_HEIGHT, COLOR_GetDepth());
259
260 /* Jokers are all white */
261 XSetForeground(hDisplay, hGC, WhitePixel(hDisplay, 0));
262 XFillRectangle(hDisplay, Cards[iCard].pixmap, hGC,
263 0, 0,
264 CARD_WIDTH, CARD_HEIGHT);
265 /* Set the font */
266 XSetFont(hDisplay, hGC, pCardFont->fid);
267 /* It's a joker, put all of the bitmaps there ??*/
268 snprintf(buf, sizeof(buf), "%s", "Joker");
269 iFontWidth = XTextWidth(pCardFont, buf, strlen(buf));
270 iFontHeight = (pCardFont->max_bounds.ascent +
271 pCardFont->max_bounds.descent);
272 XSetForeground(hDisplay, hGC, BlackPixel(hDisplay, 0));
273 XDrawString(hDisplay, Cards[iCard].pixmap, hGC,
274 (CARD_WIDTH - iFontWidth)/2,
275 iFontHeight,
276 buf, strlen(buf));
277 }
278 }
279
280 /**
281 * Draw cards
282 *
283 * \b History:
284 * \arg 02.21.94 ESF Created.
285 * \arg 02.22.94 ESF Fixed positioning bug, made prettier.
286 * \arg 03.02.94 ESF Added the printing of the country name.
287 * \arg 03.29.94 ESF Fixed the setup for printing the jokers.
288 * \arg 04.02.94 ESF Fixed name centering, wasn't XSetFont'ing.
289 * \arg 05.06.94 ESF Made it more beautiful, took out hacks.
290 * \arg 06.25.94 ESF Optimized card decompression.
291 * \arg 09.02.94 ESF Fixed off-by-two bug.
292 * \arg 23.08.95 JC Use COLOR_Depth.
293 * \arg 27.10.99 TdH Took out CARDS_Init to get rid of static and check
294 */
295
CARDS_RenderCard(Int32 iCard,Int32 iPosition)296 void CARDS_RenderCard(Int32 iCard, Int32 iPosition) {
297 Int32 c;
298 /* Range check */
299 if (iCard<0 || iCard>=NUM_CARDS || iPosition>=MAX_CARDS || iPosition<0) {
300 (void)UTIL_PopupDialog("Warning!",
301 "Bogus request to CARDS_RenderCard()!\n", 1,
302 "Ok", NULL, NULL);
303 return;
304 }
305
306 /* Find out which country/image goes with the card */
307 if (iCard < NUM_COUNTRIES) {
308 /* Check to see if the color of the card/country has changed
309 * if card has no pixmap, color will be -1, which is no existing color
310 */
311 c = COLOR_QueryColor(COLOR_CountryToColor(iCard));
312 if(Cards[iCard].color != c)
313 CARDS_SetColor(iCard,c);
314 }
315 else {/* it's a joker */
316 if (Cards[iCard].pixmap == 0L)
317 CARDS_GetJoker(iCard);
318 }
319
320 /* Now it's built, put it in the card's bitmap resource, manage the card */
321 XtVaSetValues(wCardToggle[iPosition],XtNbitmap, Cards[iCard].pixmap, NULL);
322 XtManageChild(wCardToggle[iPosition]);
323 }
324
325
326 /**
327 * Using Bresenham's algorithm, squish the image passed in to
328 * a box [x, y]. Return the compressed image. Preserve aspect
329 * ratio of the image, so find out the MAX of the compression in
330 * the x and y directions.
331 * \b History:
332 * \arg ??.??.93 ESF Created for the XDissolver.
333 * \arg 02.22.94 ESF Made pretty, changed to work with 8 bit images.
334 * \arg 11.29.94 ESF Completely rewrote to use true Bresenham algorithm.
335 * \arg 01.15.95 ESF Fixed off by one error causing memory access errors.
336 */
337
CARDS_ScaleImage(XImage * pimageInput,Int32 iMaxWidth,Int32 iMaxHeight)338 XImage *CARDS_ScaleImage(XImage *pimageInput, Int32 iMaxWidth, Int32 iMaxHeight)
339 {
340 XImage *pimageCompressed;
341 Byte *pbData;
342 Int32 iOutputWidth, iOutputHeight;
343
344 /* Believe it or not, scaling a 2D image is like drawing two lines,
345 * using Bresenham's algorithm. This algorithm is probably analogous
346 * to the methods used in games such as Wolfenstein 3D, since one can
347 * use a similar algorithm for rotating bitmaps in 3D.
348 *
349 * The key here is that the first "line" that we use to scale is the
350 * hypotenuse of a triangle. The base of the triangle is the width of
351 * the input image, and the other side (vertical) is the width of the
352 * output image.
353 *
354 * The second "line" is similar, except that the dimensions of the sides
355 * are the heights of the input image and output image.
356 *
357 * We proceed to "draw" (i.e. perform the Bresenham algorithm for) the
358 * two lines, in the structure of a nested loop -- for each pixel of
359 * the outer line, draw the entire inner line).
360 *
361 * The line is going to be in the first quadrant, since the dimensions
362 * of the images are positive. Thus, the pixels of the line will either
363 * be drawn "to the right of", "above", or "above and to the right of"
364 * the anterior pixel (in other words, as we draw the line, the next
365 * pixel will either go to the right, up, or diagonally up and to the
366 * right.
367 *
368 * Remember, the base of the triangle represents the dimension of the
369 * _input_ image. As we draw the line, if the pixel that we draw is
370 * _heigher_ than the last one, we copy a pixel from the source image
371 * to the destination image. The pixel that we copy is the one that
372 * falls directly _below_ the pixel we are drawing, and we copy it to
373 * the location directly to the _right_ of the current pixel.
374 *
375 * You should be able to imagine in this fashion scaling a single
376 * scan-line of an image. The source line was the base of the
377 * triangle, and the verticle side of the triangle was the
378 * destination scan-line. Thus, in order to scale a 2D image, we
379 * simply perform two line drawings, one inside the other, as
380 * mentioned above.
381 *
382 * As for an informal proof of this method, (not like I was ever
383 * any good at _formal_ proofs), I show that the method works for
384 * a scan-line at the border conditions, and then, using smoke, magic,
385 * and poor man's induction, I handwave my way into 2 dimensions.
386 *
387 * The easiest scaling to prove is the 1:1 ratio. This will result in
388 * a completely diagonal line. Since we copy a pixel across whenever
389 * we go up at all, we will copy across a pixel every time we move,
390 * since we are moving diagonally all the way. Thus the scan-lines
391 * will be identical.
392 *
393 */
394
395 Int32 *pHorizontalLine, *pVerticalLine;
396 Int32 iCompression;
397 Int32 iWidthCompression, iHeightCompression;
398 Int32 x, y;
399
400 /* Calculate the dimensions of the output image, preserving aspect ratio.
401 * I want to avoid using any floating point, so use a primitive fixed
402 * point representation here, simply multiply the numbers by 1024 and then
403 * divide the final result by the same factor. This has two consequences:
404 *
405 * a) The accuracy is limited to approximately 3 digits.
406 * b) The range on the input parameters of the calculation is
407 * limited to 2^32 >> 10 = 2^22. I don't think there are
408 * countries larger than this in width or height :)
409 */
410
411 /* Watch out for negative numbers! */
412 D_Assert(pimageInput->width >= 0 && pimageInput->height >=0,
413 "Negative image?");
414
415 /*** Scale (encoding) ***/
416 pimageInput->width <<= 10;
417 pimageInput->height <<= 10;
418
419 iWidthCompression = MAX(pimageInput->width / iMaxWidth, 1<<10);
420 iHeightCompression = MAX(pimageInput->height / iMaxHeight, 1<<10);
421
422 /* To preserve the aspect ratio, choose the larger of
423 * the compression ratios, and use it in both directions.
424 */
425
426 iCompression = MAX(iWidthCompression, iHeightCompression);
427
428 /* Find out the size of the output image */
429 iOutputWidth = (pimageInput->width)/iCompression;
430 iOutputHeight = (pimageInput->height)/iCompression;
431
432 /*** Scale (decoding) ***/
433 pimageInput->width >>= 10;
434 pimageInput->height >>= 10;
435
436 /* After we have done this, do a sanity check on the result */
437 D_Assert(iOutputWidth <= iMaxWidth && iOutputHeight <= iMaxHeight,
438 "Scaling algorithm meltdown!");
439
440 /* Allocate memory for the lines */
441 pHorizontalLine = (Int32 *)MEM_Alloc(sizeof(Int32)*iOutputWidth);
442 pVerticalLine = (Int32 *)MEM_Alloc(sizeof(Int32)*iOutputHeight);
443
444 /* We want to draw lines that represent the hypotenuse of triangles
445 * that have heights of pimageInput->[height | width] pixels and
446 * widths of iOutput[Width | Height] pixels. Thus, since out lines
447 * start at (0, 0), we _must_ subtract 1 from the widths and heights
448 * in order to draw a line or the correct dimensions.
449 */
450
451 /* First "draw" the line representing the "width" compression */
452 _CARDS_ComputeScaleVector(pHorizontalLine, 0, 0,
453 pimageInput->width-1, iOutputWidth-1);
454
455 /* Now "draw" the line representing the "height" compression */
456 _CARDS_ComputeScaleVector(pVerticalLine, 0, 0,
457 pimageInput->height-1, iOutputHeight-1);
458
459 /* This will hold the compressed input data as we're compressing it */
460 pbData = (Byte *)XtMalloc(sizeof(Byte)*iOutputWidth*iOutputHeight);
461 pimageCompressed = XCreateImage(hDisplay, pVisual,
462 8, ZPixmap, 0, (char *)pbData,
463 iOutputWidth, iOutputHeight, 8,
464 iOutputWidth);
465
466 /* Loop through the scale vectors and compress the image (UNROLL?) */
467 for (y=0; y!=iOutputHeight; y++)
468 for (x=0; x!=iOutputWidth; x++)
469 {
470 /* CSE hand optimization */
471 const Int32 xx = pHorizontalLine[x], yy = pVerticalLine[y];
472
473 /* Sanity check */
474 D_Assert(xx>=0 && xx<pimageInput->width, "Bogus horiz. r-pixel.");
475 D_Assert(yy>=0 && yy<pimageInput->height, "Bogus vert. r-pixel.");
476 D_Assert(x>=0 && x<pimageCompressed->width, "Bogus horiz. w-pixel.");
477 D_Assert(y>=0 && y<pimageCompressed->height, "Bogus vert. w-pixel.");
478
479 /* Copy a pixel */
480 XPutPixel(pimageCompressed, x, y, XGetPixel(pimageInput, xx, yy));
481 }
482
483 /* Destroy the old image */
484 XDestroyImage(pimageInput);
485
486 /* Free memory */
487 MEM_Free(pHorizontalLine);
488 MEM_Free(pVerticalLine);
489
490 /* Return the compressed image */
491 return(pimageCompressed);
492 }
493
494
495 /**
496 * "Draws" a line from (x0, y0) to (x1, y1), including both endpoints,
497 * which is stored in a vector of function values in which (V[y], y)
498 * form the point pairs. Caller is reponsible for allocation and
499 * deallocation of vector.
500 *
501 * \b History:
502 * \arg 12.30.94 ESF Created.
503 * \arg 01.15.95 ESF Added check that line is in first quadrant.
504 *
505 * \par Notes:
506 * Taken from _Computer Graphics_, by Folen and van Dam et. al.,
507 * slightly hand optimized, at the cost of clarity -- sorry.
508 * Remember that the vector must have (y1-y0)+1 elements allocated.
509 * Also, this algorithm only draws lines in the first quadrant.
510 */
_CARDS_ComputeScaleVector(Int32 * piVector,Int32 x0,Int32 y0,Int32 x1,Int32 y1)511 static void _CARDS_ComputeScaleVector(Int32 *piVector, Int32 x0, Int32 y0,
512 Int32 x1, Int32 y1)
513 {
514 Int32 dx, dy, incrE, incrNE, d, x, y;
515
516 /* Ensure that the line is in the first quadrant */
517 if (x0>x1 || y0>y1)
518 {
519 #ifdef ENGLISH
520 printf("Error: (_CARDS_ScaleVector) Line not in first quadrant.");
521 #endif
522 #ifdef ENGLISH
523 printf("Erreur: (_CARDS_ScaleVector) La ligne n'est pas dans le premier quadrant.");
524 #endif
525 UTIL_ExitProgram(-1);
526 }
527
528 /* Initialize variables, prime the algorithm */
529 dx = x1 - x0;
530 dy = y1 - y0;
531 d = 2*dy - dx;
532 incrE = 2*dy;
533 incrNE = 2*(dy-dx);
534 x = x0;
535 y = y0;
536
537 /* Map one value (like drawing a pixel) */
538 piVector[y] = x;
539
540 while (x < x1)
541 {
542 if (d <= 0)
543 x++, d+=incrE;
544 else
545 x++, y++, d+=incrNE;
546
547 /* Map one value (like drawing a pixel) */
548 piVector[y] = x;
549 }
550 }
551
552
553 /**
554 * \b History:
555 * \arg 01.22.95 ESF Created.
556 * \arg 06.05.97 DAH Make hFile a local; remember to close it.
557 * \arg 06.06.97 DAH Actually, it needs to be static.
558 * \arg 19.12.99 TdH Cl0d suggested this fix, greenland card now shows
559 */
CARDS_GetCountryImage(Int32 iCountry,Int32 iFgColor,Int32 iBgColor)560 XImage *CARDS_GetCountryImage(Int32 iCountry, Int32 iFgColor, Int32 iBgColor)
561 {
562 static Flag fDirectoryRead = FALSE;
563 Int32 iCardColor, iCardBackground, i;
564 Int32 iNumCountries;
565 Byte bLength, bColor;
566 Byte *pbImage, *pTemp, *pTemp2;
567 Byte *pbBogus, *pbCompressed;
568 XImage *pimageCountry;
569 static FILE *hFile;
570 char buf[256];
571
572 const Int32 iCard = iCountry;
573
574 if (!fDirectoryRead)
575 {
576 fDirectoryRead = TRUE;
577
578 /* Open the file */
579 if ((hFile=UTIL_OpenFile(COUNTRYFILE, "r"))==NULL)
580 {
581 #ifdef ENGLISH
582 snprintf(buf, sizeof(buf), "CARDS: Cannot open %s!\n", COUNTRYFILE);
583 (void)UTIL_PopupDialog("Fatal Error", buf,
584 #endif
585 #ifdef FRENCH
586 snprintf(buf, sizeof(buf), "CARDS: Ne peut ouvrir %s!\n", COUNTRYFILE);
587 (void)UTIL_PopupDialog("Erreur fatale", buf,
588 #endif
589 1, "Ok", NULL, NULL);
590 UTIL_ExitProgram(-1);
591 }
592
593 /* Read the directory */
594 fscanf(hFile, "%d%c", &iNumCountries, (char *)&pbBogus);
595 if (iNumCountries != NUM_COUNTRIES) /* One is for ocean */
596 {
597 #ifdef ENGLISH
598 (void)UTIL_PopupDialog("Fatal Error",
599 "CARDS: Wrong number of countries!",
600 #endif
601 #ifdef FRENCH
602 (void)UTIL_PopupDialog("Erreur fatale",
603 "CARDS: Nombre de pays invalide!",
604 #endif
605 1, "Ok", NULL, NULL);
606 UTIL_ExitProgram(-1);
607 }
608 fread(pDirectory, iNumCountries, sizeof(pDirectory[0]), hFile);
609
610 /* Hack for now */
611 iNumCountries = NUM_COUNTRIES;
612 }
613
614 /* Allocate the memory for the card */
615 pbImage = (Byte *)XtMalloc(pDirectory[iCard].iWidth *
616 pDirectory[iCard].iHeight);
617 pbCompressed = (Byte *)MEM_Alloc(pDirectory[iCard].iLength);
618
619 /* Go seek the card */
620 fseek(hFile, pDirectory[iCard].lOffset, SEEK_SET);
621
622 /* Read it in from the data file */
623 fread(pbCompressed, pDirectory[iCard].iLength, 1, hFile);
624
625 /* Get the colors of the card. This is an optimization,
626 * since we should get the color from the compressed card
627 * bitmap. However, we know what color the card should
628 * be because of our nice organization of the card ->
629 * country mapping. If the caller has passed in specific values
630 * for these, use them instead of the defaults.
631 */
632
633 /* do NOT ask me why +1 must be used, but it seems to work */
634 iCardColor = (iFgColor == -1) ? COLOR_CountryToColor(iCard + 1) : iFgColor;
635 iCardBackground = (iFgColor == -1) ? BlackPixel(hDisplay, 0) : iBgColor;
636
637 /* Uncompress the data */
638 for (i=0,pTemp2=pbCompressed,pTemp=pbImage;
639 i<pDirectory[iCard].iLength; i+=2)
640 {
641 /* Get a color segment */
642 bLength = *pTemp2++;
643 bColor = *pTemp2++;
644
645 /* Put it in the country image */
646 if (bColor==BLACK)
647 memset(pTemp, iCardBackground, bLength);
648 else
649 memset(pTemp, iCardColor, bLength);
650 pTemp += bLength;
651 }
652
653 MEM_Free(pbCompressed);
654
655 /* Create the image */
656 pimageCountry = XCreateImage(hDisplay, pVisual, 8, ZPixmap, 0,
657 (char *)pbImage,
658 pDirectory[iCard].iWidth,
659 pDirectory[iCard].iHeight,
660 8, pDirectory[iCard].iWidth);
661 return pimageCountry;
662 }
663