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)
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 ***********************************************************************/
15 #include <fc_config.h>
25 #include <X11/Intrinsic.h>
42 #include "client_main.h"
46 #include "mapview_g.h"
52 struct sprite
*intro_gfx_sprite
;
53 struct sprite
*radar_gfx_sprite
;
55 Cursor cursors
[CURSOR_LAST
];
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
);
61 /**************************************************************************
62 Return whether the client supports given view type
63 **************************************************************************/
64 bool is_view_supported(enum ts_type type
)
75 /***************************************************************************
77 ***************************************************************************/
78 #define COLOR_MOTTO_FACE "#2D71E3"
80 void load_intro_gfx(void)
86 const char *motto
= freeciv_motto();
87 XFontSetExtents
*exts
;
88 const char *rev_ver
= fc_svn_revision();
89 const char *radar_name
;
93 exts
= XExtentsOfFontSet(main_font_set
);
94 lin
= exts
->max_logical_extent
.height
;
98 if(XParseColor(display
, cmap
, COLOR_MOTTO_FACE
, &face
) &&
99 XAllocColor(display
, cmap
, &face
)) {
102 face
.pixel
= get_color(tileset
, COLOR_OVERVIEW_VIEWRECT
)->color
.pixel
;
108 intro_gfx_sprite
= load_gfxfile(tileset_main_intro_filename(tileset
));
109 tot
= intro_gfx_sprite
->width
;
111 y
= intro_gfx_sprite
->height
- (2 * lin
);
113 w
= XmbTextEscapement(main_font_set
, motto
, strlen(motto
));
114 XSetForeground(display
, font_gc
, face
.pixel
);
115 XmbDrawString(display
, intro_gfx_sprite
->pixmap
,
116 main_font_set
, font_gc
,
118 motto
, strlen(motto
));
120 /* Minimap graphic */
122 radar_name
= tileset_mini_intro_filename(tileset
);
124 if (radar_name
!= NULL
) {
125 radar_gfx_sprite
= load_gfxfile(radar_name
);
127 struct color
*pcol
= color_alloc(0, 0, 0);
129 radar_gfx_sprite
= create_sprite(200, 75, pcol
);
134 tot
= radar_gfx_sprite
->width
;
136 y
= radar_gfx_sprite
->height
- (2 * lin
+
137 1.5 * (exts
->max_logical_extent
.height
+ exts
->max_logical_extent
.y
));
139 w
= XmbTextEscapement(main_font_set
, word_version(), strlen(word_version()));
140 XSetForeground(display
, font_gc
,
141 get_color(tileset
, COLOR_OVERVIEW_UNKNOWN
)->color
.pixel
);
142 XmbDrawString(display
, radar_gfx_sprite
->pixmap
,
143 main_font_set
, font_gc
,
144 (tot
/ 2 - w
/ 2) + 1, y
+ 1,
145 word_version(), strlen(word_version()));
146 XSetForeground(display
, font_gc
,
147 get_color(tileset
, COLOR_OVERVIEW_VIEWRECT
)->color
.pixel
);
148 XmbDrawString(display
, radar_gfx_sprite
->pixmap
,
149 main_font_set
, font_gc
,
151 word_version(), strlen(word_version()));
155 if (rev_ver
!= NULL
) {
156 fc_snprintf(s
, sizeof(s
), "%s (%s)", VERSION_STRING
, rev_ver
);
158 fc_snprintf(s
, sizeof(s
), "%s", VERSION_STRING
);
160 w
= XmbTextEscapement(main_font_set
, s
, strlen(s
));
161 XSetForeground(display
, font_gc
,
162 get_color(tileset
, COLOR_OVERVIEW_UNKNOWN
)->color
.pixel
);
163 XmbDrawString(display
, radar_gfx_sprite
->pixmap
,
164 main_font_set
, font_gc
,
165 (tot
/ 2 - w
/ 2) + 1, y
+ 1, s
, strlen(s
));
166 XSetForeground(display
, font_gc
,
167 get_color(tileset
, COLOR_OVERVIEW_VIEWRECT
)->color
.pixel
);
168 XmbDrawString(display
, radar_gfx_sprite
->pixmap
,
169 main_font_set
, font_gc
,
170 tot
/ 2 - w
/ 2, y
, s
, strlen(s
));
174 w
= XmbTextEscapement(main_font_set
, client_string
, strlen(client_string
));
175 XSetForeground(display
, font_gc
,
176 get_color(tileset
, COLOR_OVERVIEW_UNKNOWN
)->color
.pixel
);
177 XmbDrawString(display
, radar_gfx_sprite
->pixmap
,
178 main_font_set
, font_gc
,
179 (tot
/ 2 - w
/ 2) + 1, y
+ 1, client_string
, strlen(client_string
));
180 XSetForeground(display
, font_gc
,
181 get_color(tileset
, COLOR_OVERVIEW_VIEWRECT
)->color
.pixel
);
182 XmbDrawString(display
, radar_gfx_sprite
->pixmap
,
183 main_font_set
, font_gc
,
184 tot
/ 2 - w
/ 2, y
, client_string
, strlen(client_string
));
189 XFreeColors(display
, cmap
, &(face
.pixel
), 1, 0);
197 /****************************************************************************
198 Create a new sprite by cropping and taking only the given portion of
200 ****************************************************************************/
201 struct sprite
*crop_sprite(struct sprite
*source
,
202 int x
, int y
, int width
, int height
,
204 int mask_offset_x
, int mask_offset_y
)
206 Pixmap mypixmap
, mymask
;
209 mypixmap
= XCreatePixmap(display
, root_window
,
210 width
, height
, display_depth
);
211 XCopyArea(display
, source
->pixmap
, mypixmap
, civ_gc
,
212 x
, y
, width
, height
, 0, 0);
214 if (source
->has_mask
) {
215 mymask
= XCreatePixmap(display
, root_window
, width
, height
, 1);
217 plane_gc
= XCreateGC(display
, mymask
, 0, NULL
);
218 XCopyArea(display
, source
->mask
, mymask
, plane_gc
,
219 x
, y
, width
, height
, 0, 0);
220 XFreeGC(display
, plane_gc
);
225 values
.function
= GXand
;
227 plane_gc
= XCreateGC(display
, mymask
, GCFunction
, &values
);
228 XCopyArea(display
, mask
->mask
, mymask
, plane_gc
,
229 x
- mask_offset_x
, y
- mask_offset_y
, width
, height
, 0, 0);
230 XFreeGC(display
, plane_gc
);
233 return ctor_sprite_mask(mypixmap
, mymask
, width
, height
);
235 mymask
= XCreatePixmap(display
, root_window
, width
, height
, 1);
237 plane_gc
= XCreateGC(display
, mymask
, 0, NULL
);
238 XCopyArea(display
, source
->mask
, mymask
, plane_gc
,
239 x
, y
, width
, height
, 0, 0);
240 XFreeGC(display
, plane_gc
);
241 return ctor_sprite_mask(mypixmap
, mymask
, width
, height
);
243 return ctor_sprite(mypixmap
, width
, height
);
247 /****************************************************************************
248 Create a sprite with the given height, width and color.
249 ****************************************************************************/
250 struct sprite
*create_sprite(int width
, int height
, struct color
*pcolor
)
252 struct sprite
*plrcolor
;
254 fc_assert_ret_val(width
> 0, NULL
);
255 fc_assert_ret_val(height
> 0, NULL
);
256 fc_assert_ret_val(pcolor
!= NULL
, NULL
);
259 /* FIXME: I do not know why it works but the code below allows the creation
260 * of the needed player color sprites. */
261 fc_assert_ret_val(tileset
!= NULL
, NULL
);
262 struct sprite
*psprite_dummy
= get_basic_fog_sprite(tileset
);
263 Pixmap mypixmap
, mymask
;
266 mypixmap
= XCreatePixmap(display
, root_window
, width
, height
,
268 mymask
= XCreatePixmap(display
, root_window
, width
, height
, 1);
269 plane_gc
= XCreateGC(display
, mymask
, 0, NULL
);
270 XCopyArea(display
, psprite_dummy
->mask
, mymask
, plane_gc
,
271 0, 0, width
, height
, 0, 0);
272 XFreeGC(display
, plane_gc
);
273 plrcolor
= ctor_sprite_mask(mypixmap
, mymask
, width
, height
);
276 XSetForeground(display
, fill_bg_gc
, pcolor
->color
.pixel
);
277 XFillRectangle(display
, plrcolor
->pixmap
, fill_bg_gc
, 0, 0, width
, height
);
282 /****************************************************************************
283 Find the dimensions of the sprite.
284 ****************************************************************************/
285 void get_sprite_dimensions(struct sprite
*sprite
, int *width
, int *height
)
287 *width
= sprite
->width
;
288 *height
= sprite
->height
;
291 /***************************************************************************
293 ***************************************************************************/
294 void load_cursors(void)
296 enum cursor_type cursor
;
298 struct sprite
*sprite
;
301 white
.pixel
= get_color(tileset
, COLOR_OVERVIEW_VIEWRECT
)->color
.pixel
;
302 black
.pixel
= get_color(tileset
, COLOR_OVERVIEW_UNKNOWN
)->color
.pixel
;
303 XQueryColor(display
, cmap
, &white
);
304 XQueryColor(display
, cmap
, &black
);
306 for (cursor
= 0; cursor
< CURSOR_LAST
; cursor
++) {
307 sprite
= get_cursor_sprite(tileset
, cursor
, &hot_x
, &hot_y
, 0);
309 /* FIXME: this is entirely wrong. It should be rewritten using
310 * XcursorImageLoadCursor. See gdkcursor-x11.c in the GTK sources for
312 cursors
[cursor
] = XCreatePixmapCursor(display
,
313 sprite
->mask
, sprite
->mask
,
314 &white
, &black
, hot_x
, hot_y
);
318 /***************************************************************************
320 ***************************************************************************/
321 static struct sprite
*ctor_sprite(Pixmap mypixmap
, int width
, int height
)
323 struct sprite
*mysprite
=fc_malloc(sizeof(struct sprite
));
324 mysprite
->pixmap
=mypixmap
;
325 mysprite
->width
=width
;
326 mysprite
->height
=height
;
328 mysprite
->pcolorarray
= NULL
;
329 mysprite
->has_mask
=0;
333 /***************************************************************************
335 ***************************************************************************/
336 static struct sprite
*ctor_sprite_mask(Pixmap mypixmap
, Pixmap mask
,
337 int width
, int height
)
339 struct sprite
*mysprite
=fc_malloc(sizeof(struct sprite
));
340 mysprite
->pixmap
=mypixmap
;
343 mysprite
->width
=width
;
344 mysprite
->height
=height
;
345 mysprite
->pcolorarray
= NULL
;
346 mysprite
->has_mask
=1;
350 /***************************************************************************
351 Returns the filename extensions the client supports
353 ***************************************************************************/
354 const char **gfx_fileextensions(void)
356 static const char *ext
[] =
365 /***************************************************************************
366 Converts an image to a pixmap...
367 ***************************************************************************/
368 static Pixmap
image2pixmap(XImage
*xi
)
374 ret
= XCreatePixmap(display
, root_window
, xi
->width
, xi
->height
, xi
->depth
);
376 values
.foreground
= 1;
377 values
.background
= 0;
378 gc
= XCreateGC(display
, ret
, GCForeground
| GCBackground
, &values
);
380 XPutImage(display
, ret
, gc
, xi
, 0, 0, 0, 0, xi
->width
, xi
->height
);
381 XFreeGC(display
, gc
);
385 /***************************************************************************
387 ***************************************************************************/
388 struct sprite
*load_gfxfile(const char *filename
)
392 png_int_32 width
, height
, x
, y
;
394 int npalette
, ntrans
;
399 unsigned long *pcolorarray
;
401 struct sprite
*mysprite
;
406 bool pixel
, reported
;
408 fp
= fc_fopen(filename
, "rb");
410 log_fatal("Failed reading PNG file: \"%s\"", filename
);
414 pngp
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
416 log_fatal("Failed creating PNG struct");
420 infop
= png_create_info_struct(pngp
);
422 log_fatal("Failed creating PNG struct");
426 if (setjmp(png_jmpbuf(pngp
))) {
427 log_fatal("Failed while reading PNG file: \"%s\"", filename
);
431 png_init_io(pngp
, fp
);
433 png_set_strip_16(pngp
);
434 png_set_packing(pngp
);
436 png_read_info(pngp
, infop
);
437 width
= png_get_image_width(pngp
, infop
);
438 height
= png_get_image_height(pngp
, infop
);
439 color_type
= png_get_color_type(pngp
, infop
);
441 if (color_type
== PNG_COLOR_TYPE_PALETTE
) {
442 if (png_get_PLTE(pngp
, infop
, &palette
, &npalette
)) {
446 pcolorarray
= fc_malloc(npalette
* sizeof(*pcolorarray
));
448 mycolors
= fc_malloc(npalette
* sizeof(*mycolors
));
450 for (i
= 0; i
< npalette
; i
++) {
451 mycolors
[i
].red
= palette
[i
].red
<< 8;
452 mycolors
[i
].green
= palette
[i
].green
<< 8;
453 mycolors
[i
].blue
= palette
[i
].blue
<< 8;
456 alloc_colors(mycolors
, npalette
);
458 for (i
= 0; i
< npalette
; i
++) {
459 pcolorarray
[i
] = mycolors
[i
].pixel
;
464 log_fatal("PNG file has no palette: \"%s\"", filename
);
468 has_mask
= png_get_tRNS(pngp
, infop
, &trans
, &ntrans
, NULL
);
473 ptransarray
= fc_calloc(npalette
, sizeof(*ptransarray
));
476 for (i
= 0; i
< ntrans
; i
++) {
477 if (trans
[i
] < npalette
) {
478 ptransarray
[trans
[i
]] = TRUE
;
479 } else if (!reported
) {
480 log_verbose("PNG: Transparent array entry is out of palette: "
493 if ((color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)
494 || (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
)) {
502 png_read_update_info(pngp
, infop
);
505 png_bytep
*row_pointers
;
507 stride
= png_get_rowbytes(pngp
, infop
);
508 buf
= fc_malloc(stride
* height
);
510 row_pointers
= fc_malloc(height
* sizeof(png_bytep
));
512 for (y
= 0, pb
= buf
; y
< height
; y
++, pb
+= stride
) {
513 row_pointers
[y
] = pb
;
516 png_read_image(pngp
, row_pointers
);
517 png_read_end(pngp
, infop
);
522 png_destroy_read_struct(&pngp
, &infop
, (png_infopp
)NULL
);
524 log_error("PNG info struct is NULL (non-fatal): \"%s\"", filename
);
525 png_destroy_read_struct(&pngp
, (png_infopp
)NULL
, (png_infopp
)NULL
);
529 mysprite
= fc_malloc(sizeof(*mysprite
));
532 xi
= XCreateImage(display
, DefaultVisual(display
, screen_number
),
533 display_depth
, ZPixmap
, 0, NULL
, width
, height
, 32, 0);
534 xi
->data
= fc_calloc(xi
->bytes_per_line
* xi
->height
, 1);
537 for (y
= 0; y
< height
; y
++) {
538 for (x
= 0; x
< width
; x
++) {
540 XPutPixel(xi
, x
, y
, pcolorarray
[pb
[x
]]);
542 if (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
) {
544 (pb
[2 * x
] << 16) + (pb
[2 * x
] << 8)
549 (pb
[4 * x
] << 16) + (pb
[4 * x
+ 1] << 8)
553 (pb
[3 * x
] << 16) + (pb
[3 * x
+ 1] << 8)
561 mysprite
->pixmap
= image2pixmap(xi
);
567 xm
= XCreateImage(display
, DefaultVisual(display
, screen_number
),
568 1, XYBitmap
, 0, NULL
, width
, height
, 8, 0);
569 xm
->data
= fc_calloc(xm
->bytes_per_line
* xm
->height
, 1);
572 for (y
= 0; y
< height
; y
++) {
573 for (x
= 0; x
< width
; x
++) {
575 XPutPixel(xm
, x
, y
, !ptransarray
[pb
[x
]]);
577 if (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
) {
578 alpha
= pb
[2 * x
+ 1];
580 alpha
= pb
[4 * x
+ 3];
584 } else if (alpha
> 153) {
585 if ((y
+ x
* 2) % 4 == 0) {
590 } else if (alpha
> 102) {
591 if ((y
+ x
) % 2 == 0) {
596 } else if (alpha
> 51) {
597 if ((y
+ x
* 2) % 4 == 0) {
605 XPutPixel(xm
, x
, y
, !pixel
);
610 mysprite
->mask
= image2pixmap(xm
);
614 mysprite
->has_mask
= has_mask
;
615 mysprite
->width
= width
;
616 mysprite
->height
= height
;
617 mysprite
->pcolorarray
= pcolorarray
;
618 mysprite
->ncols
= npalette
;
627 /***************************************************************************
628 Deletes a sprite. These things can use a lot of memory.
629 ***************************************************************************/
630 void free_sprite(struct sprite
*s
)
632 XFreePixmap(display
, s
->pixmap
);
634 XFreePixmap(display
, s
->mask
);
636 if (s
->pcolorarray
) {
637 free_colors(s
->pcolorarray
, s
->ncols
);
638 free(s
->pcolorarray
);
639 s
->pcolorarray
= NULL
;
644 /***************************************************************************
646 ***************************************************************************/
647 Pixmap
create_overlay_unit(const struct unit_type
*punittype
)
650 enum color_std bg_color
;
652 pm
=XCreatePixmap(display
, root_window
,
653 tileset_full_tile_width(tileset
), tileset_full_tile_height(tileset
), display_depth
);
655 /* Give tile a background color, based on the type of unit */
656 /* Should there be colors like COLOR_MAPVIEW_LAND etc? -ev */
657 switch (unit_color_type(punittype
)) {
659 bg_color
= COLOR_OVERVIEW_LAND
;
662 bg_color
= COLOR_OVERVIEW_OCEAN
;
664 case UNIT_BG_HP_LOSS
:
665 case UNIT_BG_AMPHIBIOUS
:
666 bg_color
= COLOR_OVERVIEW_MY_UNIT
;
669 bg_color
= COLOR_OVERVIEW_ENEMY_CITY
;
672 bg_color
= COLOR_OVERVIEW_UNKNOWN
;
675 XSetForeground(display
, fill_bg_gc
,
676 get_color(tileset
, bg_color
)->color
.pixel
);
677 XFillRectangle(display
, pm
, fill_bg_gc
, 0,0,
678 tileset_full_tile_width(tileset
), tileset_full_tile_height(tileset
));
680 /* If we're using flags, put one on the tile */
681 if (!gui_options
.solid_color_behind_units
) {
682 struct sprite
*flag
= get_nation_flag_sprite(tileset
,
683 nation_of_player(client
.conn
.playing
));
685 XSetClipOrigin(display
, civ_gc
, 0,0);
686 XSetClipMask(display
, civ_gc
, flag
->mask
);
687 XCopyArea(display
, flag
->pixmap
, pm
, civ_gc
, 0, 0,
688 flag
->width
,flag
->height
, 0,0);
689 XSetClipMask(display
, civ_gc
, None
);
692 /* Finally, put a picture of the unit in the tile */
693 /* if (i < utype_count()) */ {
694 struct sprite
*s
= get_unittype_sprite(tileset
, punittype
,
695 direction8_invalid(), TRUE
);
697 XSetClipOrigin(display
,civ_gc
,0,0);
698 XSetClipMask(display
,civ_gc
,s
->mask
);
699 XCopyArea(display
, s
->pixmap
, pm
, civ_gc
,
700 0,0, s
->width
,s
->height
, 0,0 );
701 XSetClipMask(display
,civ_gc
,None
);
707 /***************************************************************************
708 This function is so that packhand.c can be gui-independent, and
709 not have to deal with Sprites itself.
710 ***************************************************************************/
711 void free_intro_radar_sprites(void)
713 if (intro_gfx_sprite
) {
714 free_sprite(intro_gfx_sprite
);
715 intro_gfx_sprite
=NULL
;
717 if (radar_gfx_sprite
) {
718 free_sprite(radar_gfx_sprite
);
719 radar_gfx_sprite
=NULL
;