Freeciv-3.2: /fast/freeciv/nightly/S3_2/client/gui-gtk-3.22/sprite.c Source File

Freeciv-3.2

Loading...
Searching...
No Matches
sprite.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996-2005 - Freeciv Development Team
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/* utility */
19#include "log.h"
20#include "mem.h"
21#include "shared.h"
22
23/* client/gui-gtk-3.22 */
24#include "colors.h"
25#include "mapview.h"
26
27#include "sprite.h"
28
29#define MAX_FILE_EXTENSIONS 50
30
31/************************************************************************/
52 struct sprite *crop_sprite(struct sprite *source,
53 int x, int y,
54 int width, int height,
55 struct sprite *mask, int mask_offset_x, int mask_offset_y,
56 float scale, bool smooth)
57{
58 struct sprite *new = fc_malloc(sizeof(*new));
59 cairo_t *cr;
60
61 fc_assert_ret_val(source, NULL);
62
63 new->surface = cairo_surface_create_similar(source->surface,
64 CAIRO_CONTENT_COLOR_ALPHA, width, height);
65 cr = cairo_create(new->surface);
66 cairo_rectangle(cr, 0, 0, width, height);
67 cairo_clip(cr);
68
69 cairo_set_source_surface(cr, source->surface, -x, -y);
70 cairo_paint(cr);
71 if (mask) {
72 cairo_set_operator(cr, CAIRO_OPERATOR_DEST_IN);
73 cairo_set_source_surface(cr, mask->surface, mask_offset_x-x, mask_offset_y-y);
74 cairo_paint(cr);
75 }
76 cairo_destroy(cr);
77
78 return new;
79}
80
81/************************************************************************/
84 struct sprite *create_sprite(int width, int height, struct color *pcolor)
85{
86 struct sprite *sprite = fc_malloc(sizeof(*sprite));
87 cairo_t *cr;
88
89 fc_assert_ret_val(width > 0, NULL);
90 fc_assert_ret_val(height > 0, NULL);
91 fc_assert_ret_val(pcolor != NULL, NULL);
92
93 sprite->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
94 width, height);
95
96 cr = cairo_create(sprite->surface);
97 gdk_cairo_set_source_rgba(cr, &pcolor->color);
98 cairo_paint(cr);
99 cairo_destroy(cr);
100
101 return sprite;
102}
103
104/************************************************************************/
107 void get_sprite_dimensions(struct sprite *sprite, int *width, int *height)
108{
109 *width = cairo_image_surface_get_width(sprite->surface);
110 *height = cairo_image_surface_get_height(sprite->surface);
111}
112
113/************************************************************************/
117 const char **gfx_fileextensions(void)
118{
119 /* Includes space for hardcoded 'png' and termination NULL */
120 static const char *ext[MAX_FILE_EXTENSIONS + 2] =
121 {
122 NULL
123 };
124
125 if (ext[0] == NULL) {
126 int count = 0;
127 GSList *formats = gdk_pixbuf_get_formats();
128 GSList *next = formats;
129
130 while ((next = g_slist_next(next)) != NULL && count < MAX_FILE_EXTENSIONS) {
131 GdkPixbufFormat *format = g_slist_nth_data(next, 0);
132 gchar **mimes = gdk_pixbuf_format_get_mime_types(format);
133 int i;
134
135 /* Consider .png to be supported even when there's no mime-type called "png" */
136 ext[count++] = fc_strdup("png");
137
138 for (i = 0; mimes[i] != NULL && count < MAX_FILE_EXTENSIONS; i++) {
139 char *end = strstr(mimes[i], "/");
140
141 if (end != NULL) {
142 ext[count++] = fc_strdup(end + 1);
143 }
144 }
145
146 g_strfreev(mimes);
147 }
148
149 g_slist_free(formats);
150
151 ext[count] = NULL;
152 }
153
154 return ext;
155}
156
157/************************************************************************/
160 static void surf_destroy_callback(void *data)
161{
162 free(data);
163}
164
165/************************************************************************/
170 struct sprite *load_gfxfile(const char *filename, bool svgflag)
171{
172 struct sprite *spr;
173 GError *err = NULL;;
174 GdkPixbuf *pb = gdk_pixbuf_new_from_file(filename, &err);
175 int width;
176 int height;
177 unsigned char *pbdata;
178 int rs;
179 unsigned char *cairo_data;
180 unsigned char *data;
181 int i, j;
182 int cairo_stride;
183 bool has_alpha;
184 int channels;
185
186 if (pb == NULL) {
187 log_error(_("Can't load %s: %s"), filename, err->message);
188 return NULL;
189 }
190
191 spr = fc_malloc(sizeof(*spr));
192 spr->surface = NULL;
193
194 width = gdk_pixbuf_get_width(pb);
195 height = gdk_pixbuf_get_height(pb);
196 pbdata = gdk_pixbuf_get_pixels(pb);
197 rs = gdk_pixbuf_get_rowstride(pb);
198 has_alpha = gdk_pixbuf_get_has_alpha(pb);
199 channels = gdk_pixbuf_get_n_channels(pb);
200
201 cairo_stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
202 if (cairo_stride <= 0) {
203 log_error("Cairo does not give stride for width %d", width);
204 free_sprite(spr);
205
206 return NULL;
207 }
208
209 cairo_data = fc_malloc(height * cairo_stride * 4);
210 data = cairo_data;
211
212 for (i = 0; i < height; i++) {
213 for (j = 0; j < width; j++) {
214 if (has_alpha) {
215 unsigned char tmp;
216
217#define MULTI_UNc(a,b) ((a * b - (b / 2)) / 0xFF)
218
219 if (is_bigendian()) {
220 tmp = pbdata[j * channels + 3];
221 data[j * 4 + 3] = MULTI_UNc(pbdata[j * channels + 2], tmp);
222 data[j * 4 + 2] = MULTI_UNc(pbdata[j * channels + 1], tmp);
223 data[j * 4 + 1] = MULTI_UNc(pbdata[j * channels + 0], tmp);
224 data[j * 4 + 0] = tmp;
225 } else {
226 tmp = MULTI_UNc(pbdata[j * channels + 2], pbdata[j * channels + 3]);
227 data[j * 4 + 1] = MULTI_UNc(pbdata[j * channels + 1],
228 pbdata[j * channels + 3]);
229 data[j * 4 + 2] = MULTI_UNc(pbdata[j * channels + 0],
230 pbdata[j * channels + 3]);
231 data[j * 4 + 0] = tmp;
232 data[j * 4 + 3] = pbdata[j * channels + 3];
233 }
234
235#undef MULTI_UNc
236
237 } else {
238 data[j * 4 + 3] = 255;
239 data[j * 4 + 0] = pbdata[j * channels + 2];
240 data[j * 4 + 1] = pbdata[j * channels + 1];
241 data[j * 4 + 2] = pbdata[j * channels + 0];
242 }
243 }
244
245 data += cairo_stride;
246 pbdata += rs;
247 }
248
249 g_object_unref(pb);
250
251 spr->surface = cairo_image_surface_create_for_data(cairo_data, CAIRO_FORMAT_ARGB32,
252 width, height, cairo_stride);
253 if (spr->surface == NULL
254 || cairo_surface_status(spr->surface) != CAIRO_STATUS_SUCCESS) {
255 log_error("Cairo image surface creation error");
256 free_sprite(spr);
257 free(cairo_data);
258
259 return NULL;
260 }
261
262 cairo_surface_set_user_data(spr->surface, NULL, cairo_data, surf_destroy_callback);
263
264 fc_assert(cairo_image_surface_get_format(spr->surface) == CAIRO_FORMAT_ARGB32);
265
266 if (cairo_surface_status(spr->surface) != CAIRO_STATUS_SUCCESS) {
267 log_fatal("Failed reading graphics file: \"%s\"", filename);
268
269 exit(EXIT_FAILURE);
270 }
271
272 return spr;
273}
274
275/************************************************************************/
278 void free_sprite(struct sprite * s)
279{
280 if (s->surface != NULL) {
281 cairo_surface_destroy(s->surface);
282 }
283
284 free(s);
285}
286
287/************************************************************************/
291 struct sprite *sprite_scale(struct sprite *src, int new_w, int new_h)
292{
293 cairo_t *cr;
294 struct sprite *new = fc_malloc(sizeof(*new));
295 int width, height;
296
297 get_sprite_dimensions(src, &width, &height);
298
299 new->surface = cairo_surface_create_similar(src->surface,
300 CAIRO_CONTENT_COLOR_ALPHA, new_w, new_h);
301
302 cr = cairo_create(new->surface);
303 cairo_save(cr);
304 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
305 cairo_paint(cr);
306 cairo_restore(cr);
307 cairo_scale(cr, (double) new_w / (double) width, (double) new_h / (double) height);
308 cairo_set_source_surface(cr, src->surface, 0, 0);
309 cairo_paint(cr);
310
311 cairo_destroy(cr);
312
313 return new;
314}
315
316/************************************************************************/
321 void sprite_get_bounding_box(struct sprite * sprite, int *start_x,
322 int *start_y, int *end_x, int *end_y)
323{
324 unsigned char *data = cairo_image_surface_get_data(sprite->surface);
325 int width = cairo_image_surface_get_width(sprite->surface);
326 int height = cairo_image_surface_get_height(sprite->surface);
327 int i, j;
328 int endian;
329
330 if (is_bigendian()) {
331 endian = 0;
332 } else {
333 endian = 3;
334 }
335
336 fc_assert(cairo_image_surface_get_format(sprite->surface) == CAIRO_FORMAT_ARGB32);
337
338 /* parses mask image for the first column that contains a visible pixel */
339 *start_x = -1;
340 for (i = 0; i < width && *start_x == -1; i++) {
341 for (j = 0; j < height; j++) {
342 if (data[(j * width + i) * 4 + endian]) {
343 *start_x = i;
344 break;
345 }
346 }
347 }
348
349 /* parses mask image for the last column that contains a visible pixel */
350 *end_x = -1;
351 for (i = width - 1; i >= *start_x && *end_x == -1; i--) {
352 for (j = 0; j < height; j++) {
353 if (data[(j * width + i) * 4 + endian]) {
354 *end_x = i;
355 break;
356 }
357 }
358 }
359
360 /* parses mask image for the first row that contains a visible pixel */
361 *start_y = -1;
362 for (i = 0; i < height && *start_y == -1; i++) {
363 for (j = *start_x; j <= *end_x; j++) {
364 if (data[(i * width + j) * 4 + endian]) {
365 *start_y = i;
366 break;
367 }
368 }
369 }
370
371 /* parses mask image for the last row that contains a visible pixel */
372 *end_y = -1;
373 for (i = height - 1; i >= *end_y && *end_y == -1; i--) {
374 for (j = *start_x; j <= *end_x; j++) {
375 if (data[(i * width + j) * 4 + endian]) {
376 *end_y = i;
377 break;
378 }
379 }
380 }
381}
382
383/************************************************************************/
386 struct sprite *crop_blankspace(struct sprite *s)
387{
388 int x1, y1, x2, y2;
389
390 sprite_get_bounding_box(s, &x1, &y1, &x2, &y2);
391
392 return crop_sprite(s, x1, y1, x2 - x1 + 1, y2 - y1 + 1, NULL, -1, -1,
393 1.0, FALSE);
394}
395
396/************************************************************************/
402 GdkPixbuf *sprite_get_pixbuf(struct sprite *sprite)
403{
404 int width, height;
405
406 if (!sprite) {
407 return NULL;
408 }
409
410 get_sprite_dimensions(sprite, &width, &height);
411
412 return surface_get_pixbuf(sprite->surface, width, height);
413}
414
415/************************************************************************/
418 GdkPixbuf *surface_get_pixbuf(cairo_surface_t *surf, int width, int height)
419{
420 cairo_t *cr;
421 cairo_surface_t *tmpsurf;
422 GdkPixbuf *pb;
423 unsigned char *pixels;
424 int rowstride;
425 int i;
426
427 pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
428 pixels = gdk_pixbuf_get_pixels(pb);
429 rowstride = gdk_pixbuf_get_rowstride(pb);
430
431 tmpsurf = cairo_image_surface_create_for_data(pixels, CAIRO_FORMAT_ARGB32,
432 width, height, rowstride);
433
434 cr = cairo_create(tmpsurf);
435 cairo_save(cr);
436 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
437 cairo_paint(cr);
438 cairo_restore(cr);
439 cairo_set_source_surface(cr, surf, 0, 0);
440 cairo_paint(cr);
441 cairo_destroy(cr);
442
443 for (i = height; i > 0; i--) {
444 unsigned char *p = pixels;
445 unsigned char *end = p + 4 * width;
446 unsigned char tmp;
447
448#define DIV_UNc(a,b) (((guint16) (a) * 0xFF + ((b) / 2)) / (b))
449
450 while (p < end) {
451 tmp = p[0];
452
453 if (is_bigendian()) {
454 if (tmp != 0) {
455 p[0] = DIV_UNc(p[1], tmp);
456 p[1] = DIV_UNc(p[2], tmp);
457 p[2] = DIV_UNc(p[3], tmp);
458 p[3] = tmp;
459 } else {
460 p[1] = p[2] = p[3] = 0;
461 }
462 } else {
463 if (p[3] != 0) {
464 p[0] = DIV_UNc(p[2], p[3]);
465 p[1] = DIV_UNc(p[1], p[3]);
466 p[2] = DIV_UNc(tmp, p[3]);
467 } else {
468 p[0] = p[1] = p[2] = 0;
469 }
470 }
471
472 p += 4;
473 }
474
475#undef DIV_UNc
476
477 pixels += rowstride;
478 }
479
480 cairo_surface_destroy(tmpsurf);
481
482 return pb;
483}
484
485/************************************************************************/
494 GdkPixbuf *create_extra_pixbuf(const struct extra_type *pextra)
495{
496 struct drawn_sprite sprs[80];
497 int count, w, h, canvas_x, canvas_y;
498 GdkPixbuf *pixbuf;
499 struct canvas canvas = FC_STATIC_CANVAS_INIT;
500 cairo_t *cr;
501
502 w = tileset_tile_width(tileset);
503 h = tileset_tile_height(tileset);
504
505 canvas.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
506 canvas_x = 0;
507 canvas_y = 0;
508
509 cr = cairo_create(canvas.surface);
510 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
511 cairo_paint(cr);
512 cairo_destroy(cr);
513
514 count = fill_basic_extra_sprite_array(tileset, sprs, pextra);
515 put_drawn_sprites(&canvas, 1.0, canvas_x, canvas_y, count, sprs, FALSE);
516
517 pixbuf = surface_get_pixbuf(canvas.surface, w, h);
518 cairo_surface_destroy(canvas.surface);
519
520 return pixbuf;
521}
522
523/************************************************************************/
526 struct sprite *load_gfxnumber(int num)
527{
528 int width, height;
529 char buf[10];
530 struct sprite *spr;
531 struct color *sprcolor = color_alloc(0xff, 0xff, 0x00);
532 struct color *textcolor = color_alloc(0x00, 0x00, 0x00);
533 cairo_t *cr;
534 int border = 2;
535
536 fc_snprintf(buf, sizeof(buf), "%d", num);
537 get_text_size(&width, &height, FONT_CITY_PROD, buf);
538
539 spr = create_sprite(width + border * 2, height + border * 2, sprcolor);
540
541 cr = cairo_create(spr->surface);
542
543 surface_put_text(cr, border, border, 1.0, FONT_CITY_PROD, textcolor, buf);
544
545 cairo_destroy(cr);
546
547 color_free(textcolor);
548 color_free(sprcolor);
549
550 return spr;
551}
height
struct canvas int int struct sprite int int int int height
Definition canvas_g.h:44
pcolor
struct canvas int int int int struct sprite *sprite struct canvas struct color * pcolor
Definition canvas_g.h:56
canvas_y
struct canvas int int canvas_y
Definition canvas_g.h:43
canvas_x
struct canvas int canvas_x
Definition canvas_g.h:43
width
struct canvas int int struct sprite int int int width
Definition canvas_g.h:44
incite_cost
char * incite_cost
Definition comments.c:74
_
#define _(String)
Definition fcintl.h:67
get_text_size
void get_text_size(int *width, int *height, enum client_font font, const char *text)
Definition canvas.c:341
surface_put_text
void surface_put_text(cairo_t *cr, int x, int y, float zoom, enum client_font font, struct color *pcolor, const char *text)
Definition canvas.c:396
FC_STATIC_CANVAS_INIT
#define FC_STATIC_CANVAS_INIT
Definition canvas.h:28
color_alloc
struct color * color_alloc(int r, int g, int b)
Definition colors.c:38
color_free
void color_free(struct color *color)
Definition colors.c:53
source
static GtkWidget * source
Definition gotodlg.c:58
MULTI_UNc
#define MULTI_UNc(a, b)
surf_destroy_callback
static void surf_destroy_callback(void *data)
Definition sprite.c:160
free_sprite
void free_sprite(struct sprite *s)
Definition sprite.c:278
create_sprite
struct sprite * create_sprite(int width, int height, struct color *pcolor)
Definition sprite.c:84
sprite_scale
struct sprite * sprite_scale(struct sprite *src, int new_w, int new_h)
Definition sprite.c:291
load_gfxnumber
struct sprite * load_gfxnumber(int num)
Definition sprite.c:526
surface_get_pixbuf
GdkPixbuf * surface_get_pixbuf(cairo_surface_t *surf, int width, int height)
Definition sprite.c:418
DIV_UNc
#define DIV_UNc(a, b)
sprite_get_pixbuf
GdkPixbuf * sprite_get_pixbuf(struct sprite *sprite)
Definition sprite.c:402
create_extra_pixbuf
GdkPixbuf * create_extra_pixbuf(const struct extra_type *pextra)
Definition sprite.c:494
load_gfxfile
struct sprite * load_gfxfile(const char *filename, bool svgflag)
Definition sprite.c:170
MAX_FILE_EXTENSIONS
#define MAX_FILE_EXTENSIONS
Definition sprite.c:29
sprite_get_bounding_box
void sprite_get_bounding_box(struct sprite *sprite, int *start_x, int *start_y, int *end_x, int *end_y)
Definition sprite.c:321
crop_blankspace
struct sprite * crop_blankspace(struct sprite *s)
Definition sprite.c:386
gfx_fileextensions
const char ** gfx_fileextensions(void)
Definition sprite.c:117
colors.h
mapview.h
sprite.h
log.h
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
log_fatal
#define log_fatal(message,...)
Definition log.h:100
log_error
#define log_error(message,...)
Definition log.h:103
put_drawn_sprites
void put_drawn_sprites(struct canvas *pcanvas, float zoom, int canvas_x, int canvas_y, int count, struct drawn_sprite *pdrawn, bool fog)
Definition mapview_common.c:1328
mem.h
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
shared.h
mask
struct sprite int int int int struct sprite * mask
Definition sprite_g.h:32
y
struct sprite int int y
Definition sprite_g.h:31
scale
struct sprite int int int int struct sprite int int float scale
Definition sprite_g.h:33
mask_offset_x
struct sprite int int int int struct sprite int mask_offset_x
Definition sprite_g.h:32
x
struct sprite int x
Definition sprite_g.h:31
crop_sprite
crop_sprite
Definition sprite_g.h:30
get_sprite_dimensions
struct sprite int int int int struct sprite int int float bool smooth get_sprite_dimensions
Definition sprite_g.h:36
mask_offset_y
struct sprite int int int int struct sprite int int mask_offset_y
Definition sprite_g.h:32
canvas
Definition canvas.h:22
canvas::surface
cairo_surface_t * surface
Definition canvas.h:23
color
Definition colors.h:21
drawn_sprite
Definition tilespec.h:110
extra_type
Definition extras.h:88
sprite
Definition sprite.h:22
sprite::surface
cairo_surface_t * surface
Definition sprite.h:23
tileset
Definition tilespec.c:481
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
is_bigendian
static bool is_bigendian(void)
Definition support.h:229
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
fill_basic_extra_sprite_array
int fill_basic_extra_sprite_array(const struct tileset *t, struct drawn_sprite *sprs, const struct extra_type *pextra)
Definition tilespec.c:7204
tileset_tile_height
int tileset_tile_height(const struct tileset *t)
Definition tilespec.c:765
tileset_tile_width
int tileset_tile_width(const struct tileset *t)
Definition tilespec.c:753