Crossfire Client, Trunk
image.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, see the
9  * 'LICENSE' and 'COPYING' files.
10  *
11  * The authors can be reached via e-mail to crossfire-devel@real-time.com
12  */
13 
21 #include "client.h"
22 
23 #include <gtk/gtk.h>
24 
25 #include "image.h"
26 #include "main.h"
27 #include "gtk2proto.h"
28 
29 extern GtkWidget *window_root;
31 
32 #define BPP 4
33 
35 
36 /* Do we have new images to display? */
38 
39 /*
40  * this is used to rescale big images that will be drawn in the inventory/look
41  * lists. What the code further below basically does is figure out how big the
42  * object is (in squares), and this looks at the icon_rescale_factor to figure
43  * what scale factor it gives. Not that the icon_rescale_factor values are
44  * passed directly to the rescale routines. These represent percentages - so
45  * even taking into account that the values diminish as the table grows, they
46  * will still appear larger if the location in the table times the factor is
47  * greater than 100. We find the largest dimension that the image has. The
48  * values in the comment is the effective scaling compared to the base image
49  * size that this big image will appear as. Using a table makes it easier to
50  * adjust the values so things look right.
51  */
52 
53 #define MAX_ICON_SPACES 10
54 static const int icon_rescale_factor[MAX_ICON_SPACES] = {
55  100, 100, 80 /* 2 = 160 */, 60 /* 3 = 180 */,
56  50 /* 4 = 200 */, 45 /* 5 = 225 */, 40 /* 6 = 240 */,
57  35 /* 7 = 259 */, 35 /* 8 = 280 */, 33 /* 9 = 300 */
58 };
59 
60 /******************************************************************************
61  *
62  * Code related to face caching.
63  *
64  *****************************************************************************/
65 
66 /* Does not appear to be used anywhere
67 typedef struct Keys {
68  uint8 flags;
69  sint8 direction;
70  KeySym keysym;
71  char *command;
72  struct Keys *next;
73 } Key_Entry;
74 */
75 
76 /* Rotate right from bsd sum. */
77 #define ROTATE_RIGHT(c) if ((c) & 01) (c) = ((c) >>1) + 0x80000000; else (c) >>= 1;
78 
79 /*#define CHECKSUM_DEBUG*/
80 
84 static void create_icon_image(guint8 *data, PixmapInfo *pi) {
85  pi->icon_image = rgba_to_gdkpixbuf(data, pi->icon_width, pi->icon_height);
86 }
87 
88 static void create_full_icon_image(guint8 *data, PixmapInfo *pi) {
90 }
91 
98 static void create_map_image(guint8 *data, PixmapInfo *pi) {
100 }
101 
105 void do_new_image(guint8 *data, PixmapInfo *pi) {
106  create_icon_image(data, pi);
107  create_full_icon_image(data, pi);
108  create_map_image(data, pi);
109 }
110 
116 static void free_pixmap(PixmapInfo *pi)
117 {
118  if (pi->icon_image) {
119  g_object_unref(pi->icon_image);
120  }
121  if (pi->full_icon_image) {
122  g_object_unref(pi->full_icon_image);
123  }
124  if (pi->map_image) {
125  cairo_surface_destroy(pi->map_image);
126  }
127 }
128 
143  guint8 *rgba_data, int width, int height) {
144  int nx, ny, iscale, factor;
145  PixmapInfo *pi;
146 
147  if (pixmap_num <= 0 || pixmap_num >= MAXPIXMAPNUM) {
148  return 1;
149  }
150 
151  if (pixmaps[pixmap_num] != pixmaps[0]) {
152  /* As per bug 2938906, one can see image corruption when switching between
153  * servers. The cause is that the cache table stores away
154  * a pointer to the pixmap[] entry - if we go and free it,
155  * the cache table can point to garbage, so don't free it.
156  * This causes some memory leak, but if/when there is good
157  * cache support for multiple servers, eventually the amount
158  * of memory consumed will reach a limit (it has every image of
159  * every server in memory
160  *
161  * The cause of image corruption requires a few different things:
162  * 1) images of the same name have different numbers on the 2 serves.
163  * 2) the image number is higher on the first than second server
164  * 3) the image using the high number does not exist/is different
165  * on the second server, causing this routine to be called.
166  */
167 
168  if (!use_config[CONFIG_CACHE]) {
169  free_pixmap(pixmaps[pixmap_num]);
170  free(pixmaps[pixmap_num]);
171  }
172  pixmaps[pixmap_num] = pixmaps[0];
173  }
174 
175  pi = calloc(1, sizeof(PixmapInfo));
176 
177  iscale = use_config[CONFIG_ICONSCALE];
178 
179  /*
180  * If the image is big, figure out what we should scale it to so it fits
181  * better display
182  */
184  int ts = 100;
185 
186  factor = width / DEFAULT_IMAGE_SIZE;
187  if (factor >= MAX_ICON_SPACES) {
188  factor = MAX_ICON_SPACES - 1;
189  }
190  if (icon_rescale_factor[factor] < ts) {
191  ts = icon_rescale_factor[factor];
192  }
193 
194  factor = height / DEFAULT_IMAGE_SIZE;
195  if (factor >= MAX_ICON_SPACES) {
196  factor = MAX_ICON_SPACES - 1;
197  }
198  if (icon_rescale_factor[factor] < ts) {
199  ts = icon_rescale_factor[factor];
200  }
201 
202  iscale = ts * use_config[CONFIG_ICONSCALE] / 100;
203  }
204 
205  /* In all cases, the icon images are in native form. */
206  pi->full_icon_width = width;
207  pi->full_icon_height = height;
208  create_full_icon_image(rgba_data, pi);
209  if (iscale != 100) {
210  nx=width;
211  ny=height;
212  guint8 *png_tmp = rescale_rgba_data(rgba_data, &nx, &ny, iscale);
213  pi->icon_width = nx;
214  pi->icon_height = ny;
215  create_icon_image(png_tmp, pi);
216  free(png_tmp);
217  } else {
218  pi->icon_width = width;
219  pi->icon_height = height;
220  create_icon_image(rgba_data, pi);
221  }
222 
223  create_map_image(rgba_data, pi);
224  /*
225  * Not ideal, but if it is missing the map or icon image, presume something
226  * failed. However, opengl doesn't set the map_image, so if using that
227  * display mode, don't make this check.
228  */
230  free_pixmap(pi);
231  free(pi);
232  return 1;
233  }
234  if (ce) {
235  ce->image_data = pi;
236  }
237  pixmaps[pixmap_num] = pi;
238  if (use_config[CONFIG_CACHE]) {
239  have_new_image++;
240  }
241 
242  return 0;
243 }
244 
251 void addsmooth(guint16 face, guint16 smooth_face)
252 {
253  pixmaps[face]->smooth_face = smooth_face;
254 }
255 
264 int associate_cache_entry(Cache_Entry *ce, int pixnum)
265 {
266  pixmaps[pixnum] = ce->image_data;
267  return 0;
268 }
269 
277 {
278  int i;
279 
281  /*
282  * The entries in the pixmaps array are also tracked in the image cache in
283  * the common area. We will try to recycle those images that we can.
284  * Thus, if we connect to a new server, we can just re-use the images we
285  * have already rendered.
286  */
287  for (i=1; i<MAXPIXMAPNUM; i++) {
288  if (!want_config[CONFIG_CACHE] && pixmaps[i] != pixmaps[0]) {
289  free_pixmap(pixmaps[i]);
290  free(pixmaps[i]);
291  pixmaps[i] = pixmaps[0];
292  }
293  }
294 }
295 
296 static GtkWidget *pbar, *pbar_window;
297 
309 void image_update_download_status(int start, int end, int total) {
310  int x, y, wx, wy, w, h;
311 
312  if (start == 1) {
313  pbar = gtk_progress_bar_new();
314  get_window_coord(window_root, &x,&y, &wx,&wy,&w,&h);
315 
316  pbar_window = gtk_window_new(GTK_WINDOW_POPUP);
317  gtk_window_set_transient_for(GTK_WINDOW(pbar_window), GTK_WINDOW (window_root));
318 
319  gtk_container_add(GTK_CONTAINER(pbar_window), pbar);
320  gtk_widget_show(pbar);
321  gtk_widget_show(pbar_window);
322  } else if (start == total) {
323  gtk_widget_destroy(pbar_window);
324  pbar = NULL;
325  pbar_window = NULL;
326  return;
327  }
328 
329  gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pbar), (float)start / end);
330  while (gtk_events_pending()) {
331  gtk_main_iteration();
332  }
333 }
334 
341 void get_map_image_size(int face, guint8 *w, guint8 *h)
342 {
343  /* We want to calculate the number of spaces this image
344  * uses it. By adding the image size but substracting one,
345  * we cover the cases where the image size is not an even
346  * increment. EG, if the map_image_size is 32, and an image
347  * is 33 wide, we want that to register as two spaces. By
348  * adding 31, that works out.
349  */
350  if ( face < 0 || face >= MAXPIXMAPNUM) {
351  *w = 1;
352  *h = 1;
353  } else {
354  int scaled_image_size;
356  scaled_image_size = map_image_size;
357  } else {
358  scaled_image_size = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
359  }
360  *w = (pixmaps[face]->full_icon_width + scaled_image_size - 1)/ scaled_image_size;
361  *h = (pixmaps[face]->full_icon_height + scaled_image_size - 1)/ scaled_image_size;
362  }
363 }
364 
365 /******************************************************************************
366  *
367  * Code related to face caching.
368  *
369  *****************************************************************************/
370 
381 {
382 #include "../../pixmaps/question.xpm"
383  pixmaps[0] = g_new(PixmapInfo, 1);
384  pixmaps[0]->icon_image =
385  gdk_pixbuf_new_from_xpm_data((const gchar **)question_xpm);
387  gdk_pixbuf_new_from_xpm_data((const gchar **)question_xpm);
389 
391  pixmaps[0]->smooth_face = 0;
392 
393  /* Initialize all the images to be of the same value. */
394  for (int i = 1; i < MAXPIXMAPNUM; i++) {
395  pixmaps[i] = pixmaps[0];
396  }
397 
399 }
create_and_rescale_image_from_data
int create_and_rescale_image_from_data(Cache_Entry *ce, int pixmap_num, guint8 *rgba_data, int width, int height)
Definition: image.c:142
PixmapInfo::full_icon_width
guint16 full_icon_width
Definition: image.h:51
create_map_image
static void create_map_image(guint8 *data, PixmapInfo *pi)
Definition: image.c:98
create_icon_image
static void create_icon_image(guint8 *data, PixmapInfo *pi)
Definition: image.c:84
CFG_DM_OPENGL
#define CFG_DM_OPENGL
Definition: client.h:239
Cache_Entry
Definition: client.h:499
PixmapInfo::full_icon_height
guint16 full_icon_height
Definition: image.h:51
PixmapInfo::full_icon_image
GdkPixbuf * full_icon_image
Definition: image.h:50
reset_image_data
void reset_image_data(void)
Definition: image.c:276
pixmaps
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: image.c:34
CONFIG_MAPSCALE
#define CONFIG_MAPSCALE
Definition: client.h:190
height
static int height
Definition: mapdata.c:99
MAXPIXMAPNUM
#define MAXPIXMAPNUM
Definition: client.h:490
free_pixmap
static void free_pixmap(PixmapInfo *pi)
Definition: image.c:116
MAX_ICON_SPACES
#define MAX_ICON_SPACES
Definition: image.c:53
have_new_image
int have_new_image
Definition: image.c:37
create_full_icon_image
static void create_full_icon_image(guint8 *data, PixmapInfo *pi)
Definition: image.c:88
CONFIG_CACHE
#define CONFIG_CACHE
Definition: client.h:187
PixmapInfo::icon_height
guint16 icon_height
Definition: image.h:47
CFG_DM_PIXMAP
#define CFG_DM_PIXMAP
Definition: client.h:237
DEFAULT_IMAGE_SIZE
#define DEFAULT_IMAGE_SIZE
Definition: image.h:40
get_map_image_size
void get_map_image_size(int face, guint8 *w, guint8 *h)
Definition: image.c:341
reset_image_cache_data
void reset_image_cache_data(void)
Definition: image.c:509
associate_cache_entry
int associate_cache_entry(Cache_Entry *ce, int pixnum)
Definition: image.c:264
gtk2proto.h
pbar
static GtkWidget * pbar
Definition: image.c:296
width
static int width
Definition: mapdata.c:98
PixmapInfo::smooth_face
guint16 smooth_face
Definition: image.h:54
do_new_image
void do_new_image(guint8 *data, PixmapInfo *pi)
Definition: image.c:105
get_window_coord
void get_window_coord(GtkWidget *win, int *x, int *y, int *wx, int *wy, int *w, int *h)
Definition: main.c:579
want_config
gint16 want_config[CONFIG_NUMS]
Definition: init.c:41
image.h
icon_rescale_factor
static const int icon_rescale_factor[MAX_ICON_SPACES]
Definition: image.c:54
image_size
int image_size
Definition: image.c:30
Cache_Entry::image_data
void * image_data
Definition: client.h:503
addsmooth
void addsmooth(guint16 face, guint16 smooth_face)
Definition: image.c:251
main.h
init_image_cache_data
void init_image_cache_data(void)
Definition: image.c:380
rgba_to_cairo_surface
cairo_surface_t * rgba_to_cairo_surface(guint8 *data, int width, int height)
Definition: png.c:440
init_common_cache_data
void init_common_cache_data(void)
Definition: image.c:359
PixmapInfo::map_image
void * map_image
Definition: image.h:53
PixmapInfo::icon_image
GdkPixbuf * icon_image
Definition: image.h:46
image_update_download_status
void image_update_download_status(int start, int end, int total)
Definition: image.c:309
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:242
rgba_to_gdkpixbuf
GdkPixbuf * rgba_to_gdkpixbuf(guint8 *data, int width, int height)
Definition: png.c:414
PixmapInfo
Definition: image.h:43
CONFIG_ICONSCALE
#define CONFIG_ICONSCALE
Definition: client.h:189
window_root
GtkWidget * window_root
Definition: main.c:103
map_image_size
int map_image_size
Definition: map.c:34
rescale_rgba_data
guint8 * rescale_rgba_data(guint8 *data, int *width, int *height, int scale)
Definition: png.c:235
PixmapInfo::icon_width
guint16 icon_width
Definition: image.h:47
pbar_window
static GtkWidget * pbar_window
Definition: image.c:296
client.h
CONFIG_DISPLAYMODE
#define CONFIG_DISPLAYMODE
Definition: client.h:192