Crossfire Client, Branches  R11627
map.c
Go to the documentation of this file.
1 const char * const rcsid_gtk_map_c =
2  "$Id: map.c 9218 2008-06-03 13:45:46Z anmaster $";
3 /*
4  Crossfire client, a client program for the crossfire program.
5 
6  Copyright (C) 2001 Mark Wedel & Crossfire Development Team
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22  The author can be reached via e-mail to crossfire-devel@real-time.com
23 */
24 
25 /* This file handles the map related code - both in terms of allocation,
26  * insertion of new objects, and actual rendering (although the
27  * sdl rendering is in the sdl file
28  */
29 
30 #include <config.h>
31 #include <stdlib.h>
32 #include <sys/stat.h>
33 #ifndef WIN32
34 #include <unistd.h>
35 #endif
36 #include <png.h>
37 
38 /* Pick up the gtk headers we need */
39 #include <gtk/gtk.h>
40 #ifndef WIN32
41 #include <gdk/gdkx.h>
42 #else
43 #include <time.h>
44 #include <gdk/gdkwin32.h>
45 #endif
46 #include <gdk/gdkkeysyms.h>
47 
48 #include "client-types.h"
49 #include "gx11.h"
50 #include "client.h"
51 #include "gtkproto.h"
52 #include "mapdata.h"
53 
54 
55 /* Start of map handling code.
56  * For the most part, this actually is not window system specific,
57  * but certainly how the client wants to store this may vary.
58  */
59 
60 extern struct Map the_map;
61 
62 /*
63  * Added for fog of war. Current size of the map structure in memory.
64  * We assume a rectangular map so this is the length of one side.
65  * command.c needs to know about this so not static
66  * FIX ME: Don't assume rectangle
67  */
68 
70 
76 void reset_map(void)
77 {
78 }
79 
80 static void draw_pixmap(int srcx, int srcy, int dstx, int dsty, int clipx, int clipy,
81  void *mask, void *image, int sizex, int sizey)
82 {
83  gdk_gc_set_clip_mask(mapgc, mask);
84  gdk_gc_set_clip_origin(mapgc, clipx, clipy);
85  gdk_draw_pixmap(mapwindow, mapgc, image, srcx, srcy, dstx, dsty, sizex, sizey);
86 }
87 
88 int display_mapscroll(int dx, int dy)
89  {
90 #ifdef HAVE_SDL
92  return sdl_mapscroll(dx,dy);
93  else
94 #endif
95  return 0;
96 }
97 
98 /* Draw anything in adjacent squares that could smooth on given square
99  * mx,my square to smooth on. you should not call this function to
100  * smooth on a 'completly black' square.
101  * layer layer to examine (we smooth only one layer at a time)
102  * picx,picy place on the mapwindow to draw
103  */
104 void drawsmooth (int mx,int my,int layer,int picx,int picy){
105  static int dx[8]={0,1,1,1,0,-1,-1,-1};
106  static int dy[8]={-1,-1,0,1,1,1,0,-1};
107  static int bweights[8]={2,0,4,0,8,0,1,0};
108  static int cweights[8]={0,2,0,4,0,8,0,1};
109  static int bc_exclude[8]={
110  1+2,/*north exclude northwest (bit0) and northeast(bit1)*/
111  0,
112  2+4,/*east exclude northeast and southeast*/
113  0,
114  4+8,/*and so on*/
115  0,
116  8+1,
117  0
118  };
119  int partdone[8]={0,0,0,0,0,0,0,0};
120  int slevels[8];
121  int sfaces[8];
122  int i,lowest,weight,weightC;
123  int emx,emy;
124  int smoothface;
125  int hasFace = 0;
126  for (i=0;i<=layer;i++)
127  hasFace |= the_map.cells[mx][my].heads[i].face;
128  if (!hasFace
129  || !CAN_SMOOTH(the_map.cells[mx][my], layer)) {
130  return;
131  }
132 
133  for (i=0;i<8;i++){
134  emx=mx+dx[i];
135  emy=my+dy[i];
136  if ( (emx<0) || (emy<0) || (the_map.x<=emx) || (the_map.y<=emy)){
137  slevels[i]=0;
138  sfaces[i]=0; /*black picture*/
139  }
140  else if (the_map.cells[emx][emy].smooth[layer]<=the_map.cells[mx][my].smooth[layer]){
141  slevels[i]=0;
142  sfaces[i]=0; /*black picture*/
143  }else{
144  slevels[i]=the_map.cells[emx][emy].smooth[layer];
145  sfaces[i]=pixmaps[the_map.cells[emx][emy].heads[layer].face]->smooth_face;
146  }
147  }
148  /* ok, now we have a list of smoothlevel higher than current square.
149  * there are at most 8 different levels. so... let's check 8 times
150  * for the lowest one (we draw from botto to top!).
151  */
152  lowest=-1;
153  while (1){
154  lowest = -1;
155  for (i=0;i<8;i++){
156  if ( (slevels[i]>0) && (!partdone[i]) &&
157  ((lowest<0) || (slevels[i]<slevels[lowest]))
158  )
159  lowest=i;
160  }
161  if (lowest<0)
162  break; /*no more smooth to do on this square*/
163  /*printf ("hey, must smooth something...%d\n",sfaces[lowest]);*/
164  /*here we know 'what' to smooth*/
165  /* we need to calculate the weight
166  * for border and weight for corners.
167  * then we 'markdone'
168  * the corresponding squares
169  */
170  /*first, the border, which may exclude some corners*/
171  weight=0;
172  weightC=15; /*works in backward. remove where there is nothing*/
173  /*for (i=0;i<8;i++)
174  cornermask[i]=1;*/
175  for (i=0;i<8;i++){ /*check all nearby squares*/
176  if ( (slevels[i]==slevels[lowest]) &&
177  (sfaces[i]==sfaces[lowest])){
178  partdone[i]=1;
179  weight=weight+bweights[i];
180  weightC&=~bc_exclude[i];
181  }else{
182  /*must rmove the weight of a corner if not in smoothing*/
183  weightC&=~cweights[i];
184  }
185 
186  }
187  /*We can't do this before since we need the partdone to be adjusted*/
188  if (sfaces[lowest]<=0)
189  continue; /*Can't smooth black*/
190  smoothface=sfaces[lowest];
191  if (smoothface<=0){
192  continue; /*picture for smoothing not yet available*/
193  }
194  /* now, it's quite easy. We must draw using a 32x32 part of
195  * the picture smoothface.
196  * This part is located using the 2 weights calculated:
197  * (32*weight,0) and (32*weightC,32)
198  */
199  if ( (!pixmaps[smoothface]->map_image) ||
200  (pixmaps[smoothface] == pixmaps[0]))
201  continue; /*don't have the picture associated*/
202  if (weight>0){
203  draw_pixmap(
204  weight*map_image_size, 0,
205  picx, picy,
206  picx-weight*map_image_size, picy,
207  pixmaps[smoothface]->map_mask, pixmaps[smoothface]->map_image, map_image_size, map_image_size);
208  }
209  if (weightC>0){
210  draw_pixmap(
211  weightC*map_image_size, map_image_size,
212  picx, picy,
213  picx-weightC*map_image_size, picy-map_image_size,
214  pixmaps[smoothface]->map_mask, pixmaps[smoothface]->map_image, map_image_size, map_image_size);
215  }
216  }/*while there's some smooth to do*/
217 }
218 
219 static void display_mapcell(int ax, int ay, int mx, int my)
220 {
221  int layer;
222  int face;
223 
224  /* First, we need to black out this space. */
225  for (layer=0; layer<MAXLAYERS; layer++) {
226  face = mapdata_face(ax, ay, layer);
227  if ((face > 0) && (!pixmaps[face]->map_mask))
228  break;
229  }
230  /* Only draw rectangle if all faces have transparency */
231  if (layer==MAXLAYERS)
232  gdk_draw_rectangle(mapwindow, drawingarea->style->black_gc, TRUE, ax*map_image_size, ay*map_image_size, map_image_size, map_image_size);
233 
234 
235  /* now draw the different layers. Only draw if using fog of war or the
236  * space isn't clear.
237  */
238  if (use_config[CONFIG_FOGWAR] || !the_map.cells[mx][my].cleared) {
239  for (layer=0; layer<MAXLAYERS; layer++) {
240  int sx, sy;
241 
242  /* draw single-tile faces first */
243  face = mapdata_face(ax, ay, layer);
244  if (face > 0 && pixmaps[face]->map_image != NULL) {
245  int w = pixmaps[face]->map_width;
246  int h = pixmaps[face]->map_height;
247  draw_pixmap(
248  w-map_image_size, h-map_image_size,
249  ax*map_image_size, ay*map_image_size,
250  ax*map_image_size+map_image_size-w, ay*map_image_size+map_image_size-h,
251  pixmaps[face]->map_mask, pixmaps[face]->map_image, map_image_size, map_image_size);
252  }
253  /*
254  * Sometimes, it may happens we need to draw the smooth while there
255  * is nothing to draw at that layer (but there was something at
256  * lower layers). This is handled here. The else part is to take
257  * into account cases where the smooth as already been handled 2
258  * code lines before
259  */
261  drawsmooth (mx, my, layer, ax*map_image_size, ay*map_image_size);
262 
263  /* draw big faces last (should overlap other objects) */
264  face = mapdata_bigface(ax, ay, layer, &sx, &sy);
265  if (face > 0 && pixmaps[face]->map_image != NULL) {
266  /* This is pretty messy, because images are not required to be
267  * an integral multiplier of the image size. There
268  * are really 4 main variables:
269  * source[xy]: From where within the pixmap to start grabbing pixels.
270  * off[xy]: Offset from space edge on the visible map to start drawing pixels.
271  * off[xy] also determines how many pixels to draw (map_image_size - off[xy])
272  * clip[xy]: Position of the clipmask. The position of the clipmask is always
273  * at the upper left of the image as we drawn it on the map, so for any
274  * given big image, it will have the same values for all the pieces. However
275  * we need to re-construct that location based on current location.
276  *
277  * For a 32x72 image, it would be drawn like follows:
278  * sourcey offy
279  * top space: 0 24
280  * middle space: 8 0
281  * bottom space: 40 0
282  */
283  int dx, dy, sourcex, sourcey, offx, offy, clipx, clipy;
284 
285  dx = pixmaps[face]->map_width % map_image_size;
286  offx = dx?(map_image_size -dx):0;
287  clipx = (ax - sx)*map_image_size + offx;
288 
289  if (sx) {
290  sourcex = sx * map_image_size - offx ;
291  offx=0;
292  } else {
293  sourcex=0;
294  }
295 
296  dy = pixmaps[face]->map_height % map_image_size;
297  offy = dy?(map_image_size -dy):0;
298  clipy = (ay - sy)*map_image_size + offy;
299 
300  if (sy) {
301  sourcey = sy * map_image_size - offy;
302  offy=0;
303  } else {
304  sourcey=0;
305  }
306 
307  draw_pixmap(
308  sourcex, sourcey,
309  ax*map_image_size+offx, ay*map_image_size + offy,
310  clipx, clipy,
311  pixmaps[face]->map_mask, pixmaps[face]->map_image,
312  map_image_size - offx, map_image_size - offy);
313  }
314  } /* else for processing the layers */
315  }
316 
317  /* If this is a fog cell, do darknening of the space.
318  * otherwise, process light/darkness - only do those if not a
319  * fog cell.
320  */
321  if (use_config[CONFIG_FOGWAR] && the_map.cells[mx][my].cleared) {
322  draw_pixmap(0, 0, ax*map_image_size, ay*map_image_size, ax*map_image_size, ay*map_image_size, dark1, dark, map_image_size, map_image_size);
323  }
324  else if (the_map.cells[mx][my].darkness > 192) { /* Full dark */
325  gdk_draw_rectangle (mapwindow, drawingarea->style->black_gc,
326  TRUE,map_image_size*ax, map_image_size*ay,
327  map_image_size, map_image_size);
328  } else if (the_map.cells[mx][my].darkness> 128) {
329  draw_pixmap(0, 0, ax*map_image_size, ay*map_image_size, ax*map_image_size, ay*map_image_size, dark1, dark, map_image_size, map_image_size);
330  } else if (the_map.cells[mx][my].darkness> 64) {
331  draw_pixmap(0, 0, ax*map_image_size, ay*map_image_size, ax*map_image_size, ay*map_image_size, dark2, dark, map_image_size, map_image_size);
332  } else if (the_map.cells[mx][my].darkness> 1) {
333  draw_pixmap(0, 0, ax*map_image_size, ay*map_image_size, ax*map_image_size, ay*map_image_size, dark3, dark, map_image_size, map_image_size);
334  }
335 }
336 
337 void gtk_draw_map(int redraw) {
338  int mx, my;
339  int x, y;
340  struct timeval tv1, tv2,tv3;
341  long elapsed1, elapsed2;
342 
343  if (time_map_redraw)
344  gettimeofday(&tv1, NULL);
345 
346  for(x = 0; x < use_config[CONFIG_MAPWIDTH]; x++) {
347  for(y = 0; y < use_config[CONFIG_MAPHEIGHT]; y++) {
348  /* mx,my represent the spaces on the 'virtual' map (ie, the_map structure).
349  * x and y (from the for loop) represent the visable screen.
350  */
351  mx = pl_pos.x+x;
352  my = pl_pos.y+y;
353  if (redraw
354  || the_map.cells[mx][my].need_update
355  || the_map.cells[mx][my].need_resmooth) {
356  display_mapcell(x, y, mx, my);
357  the_map.cells[mx][my].need_update=0;
358  the_map.cells[mx][my].need_resmooth=0;
359  }
360  }
361  }
362 
363  if (time_map_redraw)
364  gettimeofday(&tv2, NULL);
365 
366  gdk_draw_pixmap(drawingarea->window, drawingarea->style->black_gc, mapwindow,
367  0, 0, 0, 0, use_config[CONFIG_MAPWIDTH] * map_image_size, use_config[CONFIG_MAPHEIGHT] * map_image_size);
368  if (time_map_redraw) {
369  gettimeofday(&tv3, NULL);
370  elapsed1 = (tv2.tv_sec - tv1.tv_sec)*1000000 + (tv2.tv_usec - tv1.tv_usec);
371  elapsed2 = (tv3.tv_sec - tv2.tv_sec)*1000000 + (tv3.tv_usec - tv2.tv_usec);
372 
373  /* I care about performance for 'long' updates, so put the check in to make
374  * these a little more noticable */
375  if ((elapsed1 + elapsed2)>10000)
376  LOG(LOG_INFO,"gtk::sdl_gen_map","gen took %7ld, flip took %7ld, total = %7ld",
377  elapsed1, elapsed2, elapsed1 + elapsed2);
378  }
379 }
#define CAN_SMOOTH(__SQUARE, __LEVEL)
Definition: client.h:85
GdkGC * mapgc
Definition: map.c:69
int y
Definition: mapdata.h:93
void reset_map(void)
Definition: map.c:76
const char *const rcsid_gtk_map_c
Definition: map.c:1
#define CONFIG_FOGWAR
Definition: client.h:157
uint16 map_height
Definition: gx11.h:64
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: gx11.c:118
GdkPixmap * mapwindow
Definition: gx11.c:248
uint8 need_update
Definition: mapdata.h:81
#define CFG_DM_SDL
Definition: client.h:195
sint16 face
Definition: mapdata.h:45
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:178
static GdkBitmap * dark1
Definition: map.c:72
#define TRUE
Definition: client-types.h:71
Pixmap mask
Definition: xutil.c:67
int sdl_mapscroll(int dx, int dy)
static void display_mapcell(int ax, int ay, int mx, int my)
Definition: map.c:219
sint16 use_config[CONFIG_NUMS]
Definition: init.c:50
Definition: mapdata.h:87
sint16 mapdata_face(int x, int y, int layer)
Definition: mapdata.c:955
uint8 darkness
Definition: mapdata.h:80
int map_image_size
Definition: map.c:70
struct Map the_map
Definition: mapdata.c:121
static GdkBitmap * dark2
Definition: map.c:72
uint8 cleared
Definition: mapdata.h:84
struct MapCell ** cells
Definition: mapdata.h:95
int x
Definition: mapdata.h:92
void drawsmooth(int mx, int my, int layer, int picx, int picy)
Definition: map.c:104
#define CONFIG_SMOOTH
Definition: client.h:177
GtkWidget * drawingarea
Definition: gx11.c:256
static void draw_pixmap(int srcx, int srcy, int dstx, int dsty, int clipx, int clipy, void *mask, void *image, int sizex, int sizey)
Definition: map.c:80
uint8 need_resmooth
Definition: mapdata.h:83
#define MAXLAYERS
Definition: mapdata.h:32
#define CONFIG_MAPWIDTH
Definition: client.h:170
uint16 smooth[MAXLAYERS]
Definition: mapdata.h:79
#define CONFIG_MAPHEIGHT
Definition: client.h:171
sint16 mapdata_bigface(int x, int y, int layer, int *ww, int *hh)
Definition: mapdata.c:966
static GdkPixmap * dark
Definition: map.c:73
int time_map_redraw
Definition: map.c:79
int display_mapscroll(int dx, int dy)
Definition: map.c:88
PlayerPosition pl_pos
Definition: map.c:69
uint16 smooth_face
Definition: gx11.h:66
static GdkBitmap * dark3
Definition: map.c:72
#define CONFIG_DISPLAYMODE
Definition: client.h:161
void gtk_draw_map(int redraw)
Definition: map.c:337
struct MapCellLayer heads[MAXLAYERS]
Definition: mapdata.h:77
uint16 map_width
Definition: gx11.h:64