1 /**********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <ctype.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <X11/Xlib.h>
25 #include <X11/Intrinsic.h>
26 
27 #include <png.h>
28 
29 /* utility */
30 #include "fcintl.h"
31 #include "log.h"
32 #include "mem.h"
33 #include "shared.h"
34 #include "support.h"
35 
36 /* common */
37 #include "movement.h"
38 #include "unit.h"
39 #include "version.h"
40 
41 /* client */
42 #include "client_main.h"
43 #include "climisc.h"
44 #include "colors.h"
45 #include "gui_main.h"
46 #include "mapview_g.h"
47 #include "options.h"
48 #include "tilespec.h"
49 
50 #include "graphics.h"
51 
52 struct sprite *intro_gfx_sprite;
53 struct sprite *radar_gfx_sprite;
54 
55 Cursor cursors[CURSOR_LAST];
56 
57 static struct sprite *ctor_sprite(Pixmap mypixmap, int width, int height);
58 static struct sprite *ctor_sprite_mask(Pixmap mypixmap, Pixmap mask,
59  				       int width, int height);
60 
61 /**************************************************************************
62   Return whether the client supports given view type
63 **************************************************************************/
is_view_supported(enum ts_type type)64 bool is_view_supported(enum ts_type type)
65 {
66   switch (type) {
67   case TS_ISOMETRIC:
68   case TS_OVERHEAD:
69     return TRUE;
70   }
71 
72   return FALSE;
73 }
74 
75 /***************************************************************************
76 ...
77 ***************************************************************************/
78 #define COLOR_MOTTO_FACE    "#2D71E3"
79 
load_intro_gfx(void)80 void load_intro_gfx(void)
81 {
82   int tot, lin, y, w;
83   char s[64];
84   XColor face;
85   int have_face;
86   const char *motto = freeciv_motto();
87   XFontSetExtents *exts;
88   const char *radar_name;
89 
90   /* metrics */
91 
92   exts = XExtentsOfFontSet(main_font_set);
93   lin = exts->max_logical_extent.height;
94 
95   /* get colors */
96 
97   if (XParseColor(display, cmap, COLOR_MOTTO_FACE, &face)
98       && XAllocColor(display, cmap, &face)) {
99     have_face = TRUE;
100   } else {
101     face.pixel = get_color(tileset, COLOR_OVERVIEW_VIEWRECT)->color.pixel;
102     have_face = FALSE;
103   }
104 
105   /* Main graphic */
106 
107   intro_gfx_sprite = load_gfxfile(tileset_main_intro_filename(tileset));
108   tot = intro_gfx_sprite->width;
109 
110   y = intro_gfx_sprite->height - (2 * lin);
111 
112   w = XmbTextEscapement(main_font_set, motto, strlen(motto));
113   XSetForeground(display, font_gc, face.pixel);
114   XmbDrawString(display, intro_gfx_sprite->pixmap,
115       		main_font_set, font_gc,
116 		tot / 2 - w / 2, y,
117 		motto, strlen(motto));
118 
119   /* Minimap graphic */
120 
121   radar_name = tileset_mini_intro_filename(tileset);
122 
123   if (radar_name != NULL) {
124     radar_gfx_sprite = load_gfxfile(radar_name);
125   } else {
126     struct color *pcol = color_alloc(0, 0, 0);
127 
128     radar_gfx_sprite = create_sprite(200, 75, pcol);
129 
130     color_free(pcol);
131   }
132 
133   tot = radar_gfx_sprite->width;
134 
135   y = radar_gfx_sprite->height - (2 * lin +
136       1.5 * (exts->max_logical_extent.height + exts->max_logical_extent.y));
137 
138   w = XmbTextEscapement(main_font_set, word_version(), strlen(word_version()));
139   XSetForeground(display, font_gc,
140                  get_color(tileset, COLOR_OVERVIEW_UNKNOWN)->color.pixel);
141   XmbDrawString(display, radar_gfx_sprite->pixmap,
142                 main_font_set, font_gc,
143                 (tot / 2 - w / 2) + 1, y + 1,
144                 word_version(), strlen(word_version()));
145   XSetForeground(display, font_gc,
146                  get_color(tileset, COLOR_OVERVIEW_VIEWRECT)->color.pixel);
147   XmbDrawString(display, radar_gfx_sprite->pixmap,
148                 main_font_set, font_gc,
149                 tot / 2 - w / 2, y,
150                 word_version(), strlen(word_version()));
151 
152   y += lin;
153 
154   fc_snprintf(s, sizeof(s), "%s", VERSION_STRING);
155 
156   w = XmbTextEscapement(main_font_set, s, strlen(s));
157   XSetForeground(display, font_gc,
158 		 get_color(tileset, COLOR_OVERVIEW_UNKNOWN)->color.pixel);
159   XmbDrawString(display, radar_gfx_sprite->pixmap,
160 		main_font_set, font_gc,
161 		(tot / 2 - w / 2) + 1, y + 1, s, strlen(s));
162   XSetForeground(display, font_gc,
163 		 get_color(tileset, COLOR_OVERVIEW_VIEWRECT)->color.pixel);
164   XmbDrawString(display, radar_gfx_sprite->pixmap,
165 		main_font_set, font_gc,
166 		tot / 2 - w / 2, y, s, strlen(s));
167 
168   y += lin;
169 
170   w = XmbTextEscapement(main_font_set, client_string, strlen(client_string));
171   XSetForeground(display, font_gc,
172 		 get_color(tileset, COLOR_OVERVIEW_UNKNOWN)->color.pixel);
173   XmbDrawString(display, radar_gfx_sprite->pixmap,
174 		main_font_set, font_gc,
175 		(tot / 2 - w / 2) + 1, y + 1, client_string, strlen(client_string));
176   XSetForeground(display, font_gc,
177 		 get_color(tileset, COLOR_OVERVIEW_VIEWRECT)->color.pixel);
178   XmbDrawString(display, radar_gfx_sprite->pixmap,
179 		main_font_set, font_gc,
180 		tot / 2 - w / 2, y, client_string, strlen(client_string));
181 
182   /* free colors */
183 
184   if (have_face) {
185     XFreeColors(display, cmap, &(face.pixel), 1, 0);
186   }
187 
188   /* done */
189 
190   return;
191 }
192 
193 /****************************************************************************
194   Create a new sprite by cropping and taking only the given portion of
195   the image.
196 ****************************************************************************/
crop_sprite(struct sprite * source,int x,int y,int width,int height,struct sprite * mask,int mask_offset_x,int mask_offset_y,float scale,bool smooth)197 struct sprite *crop_sprite(struct sprite *source,
198 			   int x, int y, int width, int height,
199 			   struct sprite *mask, int mask_offset_x, int mask_offset_y,
200                float scale, bool smooth)
201 {
202   Pixmap mypixmap, mymask;
203   GC plane_gc;
204 
205   mypixmap = XCreatePixmap(display, root_window,
206 			   width, height, display_depth);
207   XCopyArea(display, source->pixmap, mypixmap, civ_gc,
208 	    x, y, width, height, 0, 0);
209 
210   if (source->has_mask) {
211     mymask = XCreatePixmap(display, root_window, width, height, 1);
212 
213     plane_gc = XCreateGC(display, mymask, 0, NULL);
214     XCopyArea(display, source->mask, mymask, plane_gc,
215 	      x, y, width, height, 0, 0);
216     XFreeGC(display, plane_gc);
217 
218     if (mask) {
219       XGCValues values;
220 
221       values.function = GXand;
222 
223       plane_gc = XCreateGC(display, mymask, GCFunction, &values);
224       XCopyArea(display, mask->mask, mymask, plane_gc,
225 		x - mask_offset_x, y - mask_offset_y, width, height, 0, 0);
226       XFreeGC(display, plane_gc);
227     }
228 
229     return ctor_sprite_mask(mypixmap, mymask, width, height);
230   } else if (mask) {
231     mymask = XCreatePixmap(display, root_window, width, height, 1);
232 
233     plane_gc = XCreateGC(display, mymask, 0, NULL);
234     XCopyArea(display, source->mask, mymask, plane_gc,
235 	      x, y, width, height, 0, 0);
236     XFreeGC(display, plane_gc);
237     return ctor_sprite_mask(mypixmap, mymask, width, height);
238   } else {
239     return ctor_sprite(mypixmap, width, height);
240   }
241 }
242 
243 /****************************************************************************
244   Create a sprite with the given height, width and color.
245 ****************************************************************************/
create_sprite(int width,int height,struct color * pcolor)246 struct sprite *create_sprite(int width, int height, struct color *pcolor)
247 {
248   struct sprite *plrcolor;
249 
250   fc_assert_ret_val(width > 0, NULL);
251   fc_assert_ret_val(height > 0, NULL);
252   fc_assert_ret_val(pcolor != NULL, NULL);
253 
254   {
255     /* FIXME: I do not know why it works but the code below allows the creation
256      *        of the needed player color sprites. */
257     fc_assert_ret_val(tileset != NULL, NULL);
258     struct sprite *psprite_dummy = get_basic_fog_sprite(tileset);
259     Pixmap mypixmap, mymask;
260     GC plane_gc;
261 
262     mypixmap = XCreatePixmap(display, root_window, width, height,
263                              display_depth);
264     mymask = XCreatePixmap(display, root_window, width, height, 1);
265     plane_gc = XCreateGC(display, mymask, 0, NULL);
266     XCopyArea(display, psprite_dummy->mask, mymask, plane_gc,
267               0, 0, width, height, 0, 0);
268     XFreeGC(display, plane_gc);
269     plrcolor = ctor_sprite_mask(mypixmap, mymask, width, height);
270   }
271 
272   XSetForeground(display, fill_bg_gc, pcolor->color.pixel);
273   XFillRectangle(display, plrcolor->pixmap, fill_bg_gc, 0, 0, width, height);
274 
275   return plrcolor;
276 }
277 
278 /****************************************************************************
279   Find the dimensions of the sprite.
280 ****************************************************************************/
get_sprite_dimensions(struct sprite * sprite,int * width,int * height)281 void get_sprite_dimensions(struct sprite *sprite, int *width, int *height)
282 {
283   *width = sprite->width;
284   *height = sprite->height;
285 }
286 
287 /***************************************************************************
288 ...
289 ***************************************************************************/
load_cursors(void)290 void load_cursors(void)
291 {
292   enum cursor_type cursor;
293   XColor white, black;
294   struct sprite *sprite;
295   int hot_x, hot_y;
296 
297   white.pixel = get_color(tileset, COLOR_OVERVIEW_VIEWRECT)->color.pixel;
298   black.pixel = get_color(tileset, COLOR_OVERVIEW_UNKNOWN)->color.pixel;
299   XQueryColor(display, cmap, &white);
300   XQueryColor(display, cmap, &black);
301 
302   for (cursor = 0; cursor < CURSOR_LAST; cursor++) {
303     sprite = get_cursor_sprite(tileset, cursor, &hot_x, &hot_y, 0);
304 
305     /* FIXME: this is entirely wrong.  It should be rewritten using
306      * XcursorImageLoadCursor.  See gdkcursor-x11.c in the GTK sources for
307      * examples. */
308     cursors[cursor] = XCreatePixmapCursor(display,
309 					  sprite->mask, sprite->mask,
310 					  &white, &black, hot_x, hot_y);
311   }
312 }
313 
314 /***************************************************************************
315 ...
316 ***************************************************************************/
ctor_sprite(Pixmap mypixmap,int width,int height)317 static struct sprite *ctor_sprite(Pixmap mypixmap, int width, int height)
318 {
319   struct sprite *mysprite=fc_malloc(sizeof(struct sprite));
320   mysprite->pixmap=mypixmap;
321   mysprite->width=width;
322   mysprite->height=height;
323   mysprite->ncols = 0;
324   mysprite->pcolorarray = NULL;
325   mysprite->has_mask=0;
326   return mysprite;
327 }
328 
329 /***************************************************************************
330 ...
331 ***************************************************************************/
ctor_sprite_mask(Pixmap mypixmap,Pixmap mask,int width,int height)332 static struct sprite *ctor_sprite_mask(Pixmap mypixmap, Pixmap mask,
333 				       int width, int height)
334 {
335   struct sprite *mysprite=fc_malloc(sizeof(struct sprite));
336   mysprite->pixmap=mypixmap;
337   mysprite->mask=mask;
338 
339   mysprite->width=width;
340   mysprite->height=height;
341   mysprite->pcolorarray = NULL;
342   mysprite->has_mask=1;
343   return mysprite;
344 }
345 
346 /***************************************************************************
347  Returns the filename extensions the client supports
348  Order is important.
349 ***************************************************************************/
gfx_fileextensions(void)350 const char **gfx_fileextensions(void)
351 {
352   static const char *ext[] =
353   {
354     "png",
355     NULL
356   };
357 
358   return ext;
359 }
360 
361 /***************************************************************************
362   Converts an image to a pixmap...
363 ***************************************************************************/
image2pixmap(XImage * xi)364 static Pixmap image2pixmap(XImage *xi)
365 {
366   Pixmap ret;
367   XGCValues values;
368   GC gc;
369 
370   ret = XCreatePixmap(display, root_window, xi->width, xi->height, xi->depth);
371 
372   values.foreground = 1;
373   values.background = 0;
374   gc = XCreateGC(display, ret, GCForeground | GCBackground, &values);
375 
376   XPutImage(display, ret, gc, xi, 0, 0, 0, 0, xi->width, xi->height);
377   XFreeGC(display, gc);
378   return ret;
379 }
380 
381 /***************************************************************************
382 ...
383 ***************************************************************************/
load_gfxfile(const char * filename)384 struct sprite *load_gfxfile(const char *filename)
385 {
386   png_structp pngp;
387   png_infop infop;
388   png_int_32 width, height, x, y;
389   FILE *fp;
390   int npalette, ntrans;
391   png_colorp palette;
392   png_bytep trans;
393   png_bytep buf, pb;
394   png_uint_32 stride;
395   unsigned long *pcolorarray;
396   bool *ptransarray;
397   struct sprite *mysprite;
398   XImage *xi;
399   int has_mask;
400   png_byte color_type;
401   png_byte alpha;
402   bool pixel, reported;
403 
404   fp = fc_fopen(filename, "rb");
405   if (!fp) {
406     log_fatal("Failed reading PNG file: \"%s\"", filename);
407     exit(EXIT_FAILURE);
408   }
409 
410   pngp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
411   if (!pngp) {
412     log_fatal("Failed creating PNG struct");
413     exit(EXIT_FAILURE);
414   }
415 
416   infop = png_create_info_struct(pngp);
417   if (!infop) {
418     log_fatal("Failed creating PNG struct");
419     exit(EXIT_FAILURE);
420   }
421 
422   if (setjmp(png_jmpbuf(pngp))) {
423     log_fatal("Failed while reading PNG file: \"%s\"", filename);
424     exit(EXIT_FAILURE);
425   }
426 
427   png_init_io(pngp, fp);
428 
429   png_set_strip_16(pngp);
430   png_set_packing(pngp);
431 
432   png_read_info(pngp, infop);
433   width = png_get_image_width(pngp, infop);
434   height = png_get_image_height(pngp, infop);
435   color_type = png_get_color_type(pngp, infop);
436 
437   if (color_type == PNG_COLOR_TYPE_PALETTE) {
438     if (png_get_PLTE(pngp, infop, &palette, &npalette)) {
439       int i;
440       XColor *mycolors;
441 
442       pcolorarray = fc_malloc(npalette * sizeof(*pcolorarray));
443 
444       mycolors = fc_malloc(npalette * sizeof(*mycolors));
445 
446       for (i = 0; i < npalette; i++) {
447 	mycolors[i].red  = palette[i].red << 8;
448 	mycolors[i].green = palette[i].green << 8;
449 	mycolors[i].blue = palette[i].blue << 8;
450       }
451 
452       alloc_colors(mycolors, npalette);
453 
454       for (i = 0; i < npalette; i++) {
455 	pcolorarray[i] = mycolors[i].pixel;
456       }
457 
458       free(mycolors);
459     } else {
460       log_fatal("PNG file has no palette: \"%s\"", filename);
461       exit(EXIT_FAILURE);
462     }
463 
464     has_mask = png_get_tRNS(pngp, infop, &trans, &ntrans, NULL);
465 
466     if (has_mask) {
467       int i;
468 
469       ptransarray = fc_calloc(npalette, sizeof(*ptransarray));
470 
471       reported = FALSE;
472       for (i = 0; i < ntrans; i++) {
473 	if (trans[i] < npalette) {
474 	  ptransarray[trans[i]] = TRUE;
475 	} else if (!reported) {
476           log_verbose("PNG: Transparent array entry is out of palette: "
477                       "\"%s\"", filename);
478 	  reported = TRUE;
479 	}
480       }
481     } else {
482       ptransarray = NULL;
483     }
484 
485   } else {
486     pcolorarray = NULL;
487     ptransarray = NULL;
488     npalette = 0;
489     if ((color_type == PNG_COLOR_TYPE_RGB_ALPHA)
490         || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) {
491       has_mask = 1;
492     } else {
493       has_mask = 0;
494     }
495     ntrans = 0;
496   }
497 
498   png_read_update_info(pngp, infop);
499 
500   {
501     png_bytep *row_pointers;
502 
503     stride = png_get_rowbytes(pngp, infop);
504     buf = fc_malloc(stride * height);
505 
506     row_pointers = fc_malloc(height * sizeof(png_bytep));
507 
508     for (y = 0, pb = buf; y < height; y++, pb += stride) {
509       row_pointers[y] = pb;
510     }
511 
512     png_read_image(pngp, row_pointers);
513     png_read_end(pngp, infop);
514     fclose(fp);
515 
516     free(row_pointers);
517     if (infop != NULL) {
518       png_destroy_read_struct(&pngp, &infop, (png_infopp)NULL);
519     } else {
520       log_error("PNG info struct is NULL (non-fatal): \"%s\"", filename);
521       png_destroy_read_struct(&pngp, (png_infopp)NULL, (png_infopp)NULL);
522     }
523   }
524 
525   mysprite = fc_malloc(sizeof(*mysprite));
526 
527 
528   xi = XCreateImage(display, DefaultVisual(display, screen_number),
529 		    display_depth, ZPixmap, 0, NULL, width, height, 32, 0);
530   xi->data = fc_calloc(xi->bytes_per_line * xi->height, 1);
531 
532   pb = buf;
533   for (y = 0; y < height; y++) {
534     for (x = 0; x < width; x++) {
535       if (pcolorarray) {
536 	XPutPixel(xi, x, y, pcolorarray[pb[x]]);
537       } else {
538         if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
539           XPutPixel(xi, x, y,
540                     (pb[2 * x] << 16) + (pb[2 * x] << 8)
541                     + pb[2 * x]);
542         } else {
543           if (has_mask) {
544 	    XPutPixel(xi, x, y,
545 		      (pb[4 * x] << 16) + (pb[4 * x + 1] << 8)
546 		      + pb[4 * x + 2]);
547           } else {
548 	    XPutPixel(xi, x, y,
549 		      (pb[3 * x] << 16) + (pb[3 * x + 1] << 8)
550 		      + pb[3 * x + 2]);
551 	  }
552         }
553       }
554     }
555     pb += stride;
556   }
557   mysprite->pixmap = image2pixmap(xi);
558   XDestroyImage(xi);
559 
560   if (has_mask) {
561     XImage *xm;
562 
563     xm = XCreateImage(display, DefaultVisual(display, screen_number),
564 		      1, XYBitmap, 0, NULL, width, height, 8, 0);
565     xm->data = fc_calloc(xm->bytes_per_line * xm->height, 1);
566 
567     pb = buf;
568     for (y = 0; y < height; y++) {
569       for (x = 0; x < width; x++) {
570 	if (ptransarray) {
571 	  XPutPixel(xm, x, y, !ptransarray[pb[x]]);
572 	} else {
573           if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
574             alpha = pb[2 * x + 1];
575           } else {
576 	    alpha = pb[4 * x + 3];
577           }
578 	  if (alpha > 204) {
579 	    pixel = FALSE;
580 	  } else if (alpha > 153) {
581 	    if ((y + x * 2) % 4 == 0) {
582 	      pixel = TRUE;
583 	    } else {
584 	      pixel = FALSE;
585 	    }
586 	  } else if (alpha > 102) {
587 	    if ((y + x) % 2 == 0) {
588 	      pixel = TRUE;
589 	    } else {
590 	      pixel = FALSE;
591 	    }
592 	  } else if (alpha > 51) {
593 	    if ((y + x * 2) % 4 == 0) {
594 	      pixel = FALSE;
595 	    } else {
596 	      pixel = TRUE;
597 	    }
598 	  } else {
599 	    pixel = TRUE;
600 	  }
601 	  XPutPixel(xm, x, y, !pixel);
602 	}
603       }
604       pb += stride;
605     }
606     mysprite->mask = image2pixmap(xm);
607     XDestroyImage(xm);
608   }
609 
610   mysprite->has_mask = has_mask;
611   mysprite->width = width;
612   mysprite->height = height;
613   mysprite->pcolorarray = pcolorarray;
614   mysprite->ncols = npalette;
615 
616   if (ptransarray) {
617     free(ptransarray);
618   }
619   free(buf);
620   return mysprite;
621 }
622 
623 /***************************************************************************
624    Deletes a sprite.  These things can use a lot of memory.
625 ***************************************************************************/
free_sprite(struct sprite * s)626 void free_sprite(struct sprite *s)
627 {
628   XFreePixmap(display, s->pixmap);
629   if (s->has_mask) {
630     XFreePixmap(display, s->mask);
631   }
632   if (s->pcolorarray) {
633     free_colors(s->pcolorarray, s->ncols);
634     free(s->pcolorarray);
635     s->pcolorarray = NULL;
636   }
637   free(s);
638 }
639 
640 /***************************************************************************
641 ...
642 ***************************************************************************/
create_overlay_unit(const struct unit_type * punittype)643 Pixmap create_overlay_unit(const struct unit_type *punittype)
644 {
645   Pixmap pm;
646   enum color_std bg_color;
647 
648   pm=XCreatePixmap(display, root_window,
649 		   tileset_full_tile_width(tileset), tileset_full_tile_height(tileset), display_depth);
650 
651   /* Give tile a background color, based on the type of unit */
652   /* Should there be colors like COLOR_MAPVIEW_LAND etc? -ev */
653   switch (unit_color_type(punittype)) {
654     case UNIT_BG_LAND:
655       bg_color = COLOR_OVERVIEW_LAND;
656       break;
657     case UNIT_BG_SEA:
658       bg_color = COLOR_OVERVIEW_OCEAN;
659       break;
660     case UNIT_BG_HP_LOSS:
661     case UNIT_BG_AMPHIBIOUS:
662       bg_color = COLOR_OVERVIEW_MY_UNIT;
663       break;
664     case UNIT_BG_FLYING:
665       bg_color = COLOR_OVERVIEW_ENEMY_CITY;
666       break;
667     default:
668       bg_color = COLOR_OVERVIEW_UNKNOWN;
669       break;
670   }
671   XSetForeground(display, fill_bg_gc,
672 		 get_color(tileset, bg_color)->color.pixel);
673   XFillRectangle(display, pm, fill_bg_gc, 0,0,
674 		 tileset_full_tile_width(tileset), tileset_full_tile_height(tileset));
675 
676   /* If we're using flags, put one on the tile */
677   if (!gui_options.solid_color_behind_units) {
678     struct sprite *flag = get_nation_flag_sprite(tileset,
679                                                  nation_of_player(client.conn.playing));
680 
681     XSetClipOrigin(display, civ_gc, 0,0);
682     XSetClipMask(display, civ_gc, flag->mask);
683     XCopyArea(display, flag->pixmap, pm, civ_gc, 0, 0,
684     	      flag->width,flag->height, 0,0);
685     XSetClipMask(display, civ_gc, None);
686   }
687 
688   /* Finally, put a picture of the unit in the tile */
689 /*  if (i < utype_count()) */ {
690     struct sprite *s = get_unittype_sprite(tileset, punittype,
691                                            direction8_invalid(), TRUE);
692 
693     XSetClipOrigin(display,civ_gc,0,0);
694     XSetClipMask(display,civ_gc,s->mask);
695     XCopyArea(display, s->pixmap, pm, civ_gc,
696 	      0,0, s->width,s->height, 0,0 );
697     XSetClipMask(display,civ_gc,None);
698   }
699   return(pm);
700 }
701 
702 
703 /***************************************************************************
704   This function is so that packhand.c can be gui-independent, and
705   not have to deal with Sprites itself.
706 ***************************************************************************/
free_intro_radar_sprites(void)707 void free_intro_radar_sprites(void)
708 {
709   if (intro_gfx_sprite) {
710     free_sprite(intro_gfx_sprite);
711     intro_gfx_sprite=NULL;
712   }
713   if (radar_gfx_sprite) {
714     free_sprite(radar_gfx_sprite);
715     radar_gfx_sprite=NULL;
716   }
717 }
718