Crossfire Client, Trunk  R19362
sdl.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 
19 #include <config.h>
20 
21 #ifdef HAVE_SDL
22 
23 #include <client-types.h>
24 #include <SDL.h>
25 #include <SDL_image.h>
26 
27 /* Pick up the gtk headers we need */
28 #include <gtk/gtk.h>
29 #ifndef WIN32
30 #include <gdk/gdkx.h>
31 #else
32 #include <gdk/gdkwin32.h>
33 #endif
34 #include <gdk/gdkkeysyms.h>
35 
36 #include "main.h"
37 #include "image.h"
38 #include <client.h>
39 #include "gtk2proto.h"
40 #include "mapdata.h"
41 
42 SDL_Surface* mapsurface;
43 static SDL_Surface* lightmap;
44 static SDL_Surface* fogmap;
45 static char *redrawbitmap;
46 
47 extern int time_map_redraw;
48 
49 
50 /* Move some of the SDL code to this file here. This makes it easier to share
51  * between the gnome and gtk client. It also reduces the length of both the
52  * gx11.c and gnome.c file. It also is more readable, as not as many #ifdef
53  * SDL.. #endif constructs are needed. Note that there may still be some SDL
54  * code in gx11.c - some areas are embedded so much that it is not easy to
55  * remove.
56  */
57 
58 /* these should generally be included by the file including this file. */
59 #include <SDL.h>
60 #include <SDL_image.h>
61 
62 
63 static void do_SDL_error(const char *SDL_function, const char *file, int line)
64 {
65  LOG(LOG_CRITICAL,SDL_function,"SDL error in file %s line %d\n%s",
66  file, line, SDL_GetError());
67  SDL_Quit();
68  exit( 1);
69 }
70 
78 static void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
79 {
80  int bpp = surface->format->BytesPerPixel;
81  /* Here p is the address to the pixel we want to set */
82  Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
83 
84  switch(bpp) {
85  case 1:
86  *p = pixel;
87  break;
88 
89  case 2:
90  *(Uint16 *)p = pixel;
91  break;
92 
93  case 3:
94  if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
95  p[0] = (pixel >> 16) & 0xff;
96  p[1] = (pixel >> 8) & 0xff;
97  p[2] = pixel & 0xff;
98  } else {
99  p[0] = pixel & 0xff;
100  p[1] = (pixel >> 8) & 0xff;
101  p[2] = (pixel >> 16) & 0xff;
102  }
103  break;
104 
105  case 4:
106  *(Uint32 *)p = pixel;
107  break;
108  }
109 }
110 
117 static void overlay_grid( int re_init, int ax, int ay)
118 {
119 
120  static SDL_Surface* grid_overlay;
121 
122  static int first_pass;
123 
124  int x= 0;
125  int y= 0;
126  SDL_Rect dst;
127  Uint32 *pixel;
128  SDL_PixelFormat* fmt;
129 
130  /* Need to convert back to screen coordinates */
131  ax-= pl_pos.x;
132  ay-= pl_pos.y;
133 
134  if( re_init == TRUE) {
135  if( grid_overlay) {
136  SDL_FreeSurface( grid_overlay);
137  }
138 
139  first_pass= 0;
140  grid_overlay= NULL;
141  }
142 
143  if( grid_overlay == NULL) {
144  grid_overlay= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA,
146  use_config[CONFIG_MAPHEIGHT]*map_image_size,
147  mapsurface->format->BitsPerPixel,
148  mapsurface->format->Rmask,
149  mapsurface->format->Gmask,
150  mapsurface->format->Bmask,
151  mapsurface->format->Amask);
152  if( grid_overlay == NULL) {
153  do_SDL_error( "CreateRGBSurface", __FILE__, __LINE__);
154  }
155 
156  grid_overlay= SDL_DisplayFormatAlpha( grid_overlay);
157 
158  first_pass= 0;
159  }
160 
161  /*
162  * If this is our first time drawing the grid, we need to build up the
163  * grid overlay
164  */
165  if( first_pass== 0) {
166 
167  /* Red pixels around the edge and along image borders
168  * fully transparent pixels everywhere else
169  */
170 
171  fmt= grid_overlay->format;
172  for( x= 0; x < map_image_size*use_config[CONFIG_MAPWIDTH]; x++) {
173  for( y= 0; y < map_image_size*use_config[CONFIG_MAPHEIGHT]; y++) {
174  /* FIXME: Only works for 32 bit displays right now */
175  pixel= (Uint32*)grid_overlay->pixels+y*grid_overlay->pitch/4+x;
176 
177  if( x == 0 || y == 0 ||
178  ((x % map_image_size) == 0) || ((y % map_image_size) == 0 ) ||
179  y == use_config[CONFIG_MAPHEIGHT]*map_image_size-1 || x == use_config[CONFIG_MAPWIDTH]*map_image_size -1 ) {
180  *pixel= SDL_MapRGBA( fmt, 255, 0, 0, SDL_ALPHA_OPAQUE);
181  } else {
182  *pixel= SDL_MapRGBA( fmt, 0, 0, 0, SDL_ALPHA_TRANSPARENT);
183  }
184  }
185  }
186  first_pass= 1;
187 
188  /*
189  * If this is our first pass then we need to overlay the entire grid
190  * now. Otherwise we just update the tile we are on
191  */
192  dst.x= 0;
193  dst.y= 0;
194  dst.w= map_image_size*use_config[CONFIG_MAPWIDTH];
195  dst.h= map_image_size*use_config[CONFIG_MAPHEIGHT];
196  SDL_BlitSurface( grid_overlay, NULL, mapsurface, &dst);
197  } else {
198  dst.x= ax* map_image_size;
199  dst.y= ay* map_image_size;
200  dst.w= map_image_size;
201  dst.h= map_image_size;
202  /* One to one pixel mapping of grid and mapsurface so we
203  * can share the SDL_Rect
204  */
205  SDL_BlitSurface( grid_overlay, &dst, mapsurface, &dst);
206  }
207 
208  return;
209 }
210 
221 void init_SDL( GtkWidget* sdl_window, int just_lightmap)
222 {
223 
224  char SDL_windowhack[32];
225 
226  if( just_lightmap == 0) {
227  g_assert( sdl_window != NULL);
228  if( SDL_WasInit( SDL_INIT_VIDEO) != 0) {
229  if( lightmap) {
230  SDL_FreeSurface( lightmap);
231  }
232  if( mapsurface) {
233  SDL_FreeSurface( mapsurface);
234  }
235  SDL_Quit();
236  }
237 
238  /*
239  * SDL hack to tell SDL which xwindow to paint onto
240  */
241 
242 #ifndef WIN32
243  snprintf(SDL_windowhack, sizeof(SDL_windowhack), "SDL_WINDOWID=%ld",
244  GDK_WINDOW_XWINDOW(sdl_window->window) );
245 #else
246  sprintf( SDL_windowhack, "SDL_WINDOWID=%ld",
247  GDK_WINDOW_HWND(sdl_window->window) );
248 #endif
249  putenv( SDL_windowhack);
250 
251  if( SDL_Init( SDL_INIT_VIDEO) < 0) {
252  LOG(LOG_CRITICAL,"gtk-v2::init_SDL", "Could not initialize SDL: %s", SDL_GetError());
253  gtk_main_quit();
254  }
255 
257  SDL_HWSURFACE|SDL_DOUBLEBUF);
258 
259  if( mapsurface == NULL) {
260  do_SDL_error( "SetVideoMode", __FILE__, __LINE__);
261  }
262 
263  if( fogmap) {
264  SDL_FreeSurface( fogmap);
265  }
266 
267  fogmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size,
269  mapsurface->format->BitsPerPixel,
270  mapsurface->format->Rmask,
271  mapsurface->format->Gmask,
272  mapsurface->format->Bmask,
273  mapsurface->format->Amask);
274 
275  if( fogmap == NULL) {
276  do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__);
277  }
278 
279  /*
280  * This is a persurface alpha value, not an alpha channel value.
281  * So this surface doesn't actually need a full alpha channel
282  */
283  if( SDL_SetAlpha( fogmap, SDL_SRCALPHA|SDL_RLEACCEL, 128) < 0) {
284  do_SDL_error( "SDL_SetAlpha", __FILE__, __LINE__);
285  }
286  }
287 
288  if( just_lightmap != 0 && lightmap) {
289  SDL_FreeSurface( lightmap);
290  }
291 
292  lightmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size,
294  mapsurface->format->BitsPerPixel,
295  mapsurface->format->Rmask,
296  mapsurface->format->Gmask,
297  mapsurface->format->Bmask,
298  mapsurface->format->Amask);
299  if( lightmap == NULL) {
300  do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__);
301  }
302 
304  /* Convert surface to have a full alpha channel if we are doing
305  * per-pixel lighting */
306  lightmap= SDL_DisplayFormatAlpha( lightmap);
307  if( lightmap == NULL) {
308  do_SDL_error( "DisplayFormatAlpha", __FILE__, __LINE__);
309  }
310  }
311 
313  overlay_grid( TRUE, 0, 0);
314  }
315  /* We make this a bit bigger than the actual map - thus, there
316  * is a 1 space pad in all directions. This enables us
317  * to store a value in that area without having to do checks to
318  * see if we are at the edge of the map - doing a store vs 4
319  * checks is going to be much faster.
320  */
321  redrawbitmap = malloc(sizeof(char) * (MAP_MAX_SIZE +2)* (MAP_MAX_SIZE+2));
322 }
323 
324 
351 void drawquarterlightmap_sdl(int tl, int tr, int bl, int br,
352  int width, int height,
353  int startx, int starty, int endx, int endy,
354  int destx, int desty)
355 {
356  int x,y;
357  int top,bottom,val;
358  for (x=startx; x<endx; x++) {
359  top= ((x*(tr-tl))/ width)+tl; /*linear interpolation for top color*/
360  bottom= ((x*(br-bl))/ width)+bl; /*linear interpolation for bottom color*/
361  for (y=starty; y<endy; y++) {
362  val=((y*(bottom-top))/height)+top; /*linear interpolation between top and bottom*/
363  if (val>255) {
364  val=255;
365  }
366  if (val<0) {
367  val=0;
368  }
369  /*printf("writing pel at %d,%d\n",destx+x,desty+y);*/
370  putpixel(lightmap, destx+x-startx, desty+y-starty,
371  SDL_MapRGBA(lightmap->format, 0, 0, 0, val));
372  }
373  }
374 }
375 
376 
377 /* See note below about ALPHA_FUDGE - used to adjust lighting effects some */
378 
379 #define ALPHA_FUDGE(x) (2*(x) / 3)
380 #define GENDARK(x,y) ( (((x)&(y) & 1) == 1)?255:0 )
381 
414 static void do_sdl_per_pixel_lighting(int x, int y, int mx, int my)
415 {
416 
417  int dark0, dark1, dark2, dark3, dark4;
418  SDL_Rect dst;
419 
420  /* I use dark0 -> dark4 in the order to keep it similar to
421  * the old code.
422  */
423  dark0 = the_map.cells[mx][my].darkness;
424 
425  if (y-1 < 0 || !the_map.cells[mx][my-1].have_darkness) {
426  dark1 = dark0;
427  } else {
428  dark1 = the_map.cells[mx][my-1].darkness;
429  }
430 
431  if (x+1 >= use_config[CONFIG_MAPWIDTH] || !the_map.cells[mx+1][my].have_darkness) {
432  dark2 = dark0;
433  } else {
434  dark2 = the_map.cells[mx+1][my].darkness;
435  }
436 
437  if (y+1 >= use_config[CONFIG_MAPHEIGHT] || !the_map.cells[mx][my+1].have_darkness) {
438  dark3 = dark0;
439  } else {
440  dark3 = the_map.cells[mx][my+1].darkness;
441  }
442 
443  if (x-1 < 0 || !the_map.cells[mx-1][my].have_darkness) {
444  dark4 = dark0;
445  } else {
446  dark4 = the_map.cells[mx-1][my].darkness;
447  }
448 
449  /* If they are all the same, processing is easy
450  *
451  * Note, the best lightining algorithm also uses diagonals
452  * so we should check the diagonals are same too
453  * We don't check for now, simply do all raw computation on best mode
454  * Tchize 19 may 2004
455  */
456  if (dark0 == dark1 && dark0 == dark2 && dark0 == dark3 && dark0 == dark4 && (use_config[CONFIG_LIGHTING] != CFG_LT_PIXEL_BEST)) {
457  dst.x = x * map_image_size;
458  dst.y = y * map_image_size;
459  dst.w = map_image_size;
460  dst.h = map_image_size;
461 
462  if (dark0 == 255) {
463  SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
464  } else if (the_map.cells[mx][my].darkness != 0) {
465  SDL_FillRect(lightmap,NULL, SDL_MapRGBA(lightmap->format, 0, 0, 0, the_map.cells[mx][my].darkness));
466  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
467  }
468  return;
469  }
470 
471 
473  /* This almost works as well as the per pixel code below, but does have some various
474  * artifacts in the drawing. It uses the same logic as the per pixel code below,
475  * bit since SDL does the blit, the alpha handling ends up being different
476  * (I think it ends up being additive). This results in the darkness being
477  * darker, but you also don't get the smooth effects. If you divide all the values
478  * by 2 (change ALPHA_FUDGE), the blending is smooth, but now the things are not dark
479  * enough, so the blending aganst solid black spaces does not look good.
480  * The reason this code is of interest is that on my system, it is about 50%
481  * faster than the code below (25 ms to darkness the church in the starting
482  * town vs 50 ms for the code further down)
483  * Setting ALPHA_FUDGE to 2/3 seems to reduce the artifacts described above
484  * to fairly minimal levels, while still keeping things dark enough.
485  * MSW 2001-10-12
486  */
487 
488  int i;
489 
490  if (dark1 == dark0) {
491  /* If we don't have usable darkness at the top, then this entire region
492  * should be the same value. Likewise, if the top value and center value
493  * are the same, we can do the entire region.
494  */
495  dst.x=0;
496  dst.y=0;
497  dst.w = map_image_size;
498  dst.h = map_image_half_size;
499  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
500  } else for (i=0; i<map_image_half_size; i++) {
501  /* Need to do it line by line */
502 
503  dst.x = 0;
504  dst.y = i;
505  dst.w = map_image_size;
506  dst.h = 1;
507  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
508  ALPHA_FUDGE((map_image_half_size - i) * dark1 + i * dark0)/map_image_half_size));
509 
510  }
511  /* All the following blocks are basically the same as above, just different
512  * darkness areas.
513  */
514  if (dark3 == dark0) {
515  dst.x=0;
516  dst.y=map_image_half_size;
517  dst.w = map_image_size;
518  dst.h = map_image_half_size;
519  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
520  } else for (i=map_image_half_size; i<map_image_size; i++) {
521  /* Need to do it line by line */
522 
523  dst.x = 0;
524  dst.y = i;
525  dst.w = map_image_size;
526  dst.h = 1;
527  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
528  ALPHA_FUDGE(dark0*(map_image_size-i) + dark3*(i-map_image_half_size)) / map_image_half_size));
529  }
530  /* Blit this to the screen now. Otherwise, we need to look at the alpha values
531  * and re-average.
532  */
533 
534  dst.x= x * map_image_size;
535  dst.y= y * map_image_size;
536  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
537 
538  if (dark4 == dark0) {
539  dst.x=0;
540  dst.y=0;
541  dst.w = map_image_half_size;
542  dst.h = map_image_size;
543  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
544  } else for (i=0; i<map_image_half_size; i++) {
545  /* Need to do it line by line */
546  dst.x = i;
547  dst.y = 0;
548  dst.w = 1;
549  dst.h = map_image_size;
550  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
551  ALPHA_FUDGE(dark4*(map_image_half_size-i) + dark0*i) / map_image_half_size));
552  }
553  if (dark2 == dark0) {
554  dst.x=map_image_half_size;
555  dst.y=0;
556  dst.w = map_image_half_size;
557  dst.h = map_image_size;
558  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
559  } else for (i=map_image_half_size; i<map_image_size; i++) {
560  /* Need to do it line by line */
561 
562  dst.x = i;
563  dst.y = 0;
564  dst.w = 1;
565  dst.h = map_image_size;
566  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
567  ALPHA_FUDGE(dark0*(map_image_size-i) + dark2*(i-map_image_half_size)) / map_image_half_size));
568  }
569  dst.x= x * map_image_size;
570  dst.y= y * map_image_size;
571  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
572  } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST ) {
573 #if 0
574  int dx,dy;
575  static int *darkx=NULL, *darky=NULL,darkx_allocated=0;
576 
577  /* Generated stored for the darkx[] array. Do it dynamically, but
578  * only allocate if the size needs to be expanded to keep performance
579  * better. darkx could be null in the initial case, but realloc should
580  * just treat that as a malloc (so according to the man page)
581  */
582  if (map_image_size > darkx_allocated) {
583  darkx = realloc(darkx, map_image_size * sizeof(int));
584  darky = realloc(darky, map_image_size * sizeof(int));
585  darkx_allocated = map_image_size;
586  }
587 
588  for( dx= 0; dx < map_image_half_size; dx++) {
589  darkx[dx]= (dark4*(map_image_half_size-dx) + dark0*dx) / map_image_half_size;
590  }
591  for( dx= map_image_half_size; dx < map_image_size; dx++) {
592  darkx[dx] = (dark0*(map_image_size-dx) + dark2*(dx-map_image_half_size)) / map_image_half_size;
593  }
594 
595  for( dy= 0; dy < map_image_half_size; dy++) {
596  darky[dy]= (dark1*(map_image_half_size-dy) + dark0*dy) / map_image_half_size;
597  }
598  for( dy= map_image_half_size; dy < map_image_size; dy++) {
599  darky[dy] = (dark0*(map_image_size-dy) + dark3*(dy-map_image_half_size)) / map_image_half_size;
600  }
601 
602  SDL_LockSurface( lightmap);
603 
604  for (dx=0; dx<map_image_size; dx++)
605  for (dy=0; dy<map_image_size; dy++) {
606  putpixel(lightmap, dx, dy, SDL_MapRGBA(lightmap->format, 0, 0, 0,(darkx[dx] + darky[dy])/2));
607  }
608 #else
609  /*we need additionnal surrounding infos*/
610  int dark5, dark6, dark7, dark8;
611  if ( (y-1 < 0) || (x+1 >= use_config[CONFIG_MAPWIDTH])
612  || !the_map.cells[mx+1][my-1].have_darkness) {
613  dark5 = (dark1+dark2)>>1; /*(fast div 2)*/
614  } else {
615  dark5 = the_map.cells[mx+1][my-1].darkness;
616  }
617 
618  if ( (x+1 >= use_config[CONFIG_MAPWIDTH])
619  || (y+1 >= use_config[CONFIG_MAPHEIGHT])
620  || !the_map.cells[mx+1][my+1].have_darkness) {
621  dark6 = (dark2+dark3)>>1;
622  } else {
623  dark6 = the_map.cells[mx+1][my+1].darkness;
624  }
625 
626  if ( (y+1 >= use_config[CONFIG_MAPHEIGHT]) || (x-1 < 0)
627  || !the_map.cells[mx-1][my+1].have_darkness) {
628  dark7 = (dark3+dark4)>>1;
629  } else {
630  dark7 = the_map.cells[mx-1][my+1].darkness;
631  }
632 
633  if ( (x-1 < 0) || (y-1 < 0)
634  || !the_map.cells[mx-1][my-1].have_darkness) {
635  dark8 = (dark4+dark1)>>1;
636  } else {
637  dark8 = the_map.cells[mx-1][my-1].darkness;
638  }
639  /*upper left lightmap quarter*/
640  drawquarterlightmap_sdl(dark8, dark1, dark4, dark0, /*colors*/
641  map_image_size, map_image_size, /*color square size*/
642  map_image_half_size, map_image_half_size, map_image_size, map_image_size, /*interpolation region*/
643  0, 0); /*where in lightmap to save result*/
644  /*upper right lightmap quarter*/
645  drawquarterlightmap_sdl(dark1, dark5, dark0, dark2, /*colors*/
646  map_image_size, map_image_size, /*color square size*/
647  0, map_image_half_size, map_image_half_size, map_image_size, /*interpolation region*/
648  map_image_half_size, 0); /*where in lightmap to save result*/
649  /*bottom left lightmap quarter*/
650  drawquarterlightmap_sdl(dark4, dark0, dark7, dark3, /*colors*/
651  map_image_size, map_image_size, /*color square size*/
652  map_image_half_size, 0, map_image_size, map_image_half_size, /*interpolation region*/
653  0, map_image_half_size); /*where in lightmap to save result*/
654  /*bottom right lightmap quarter*/
655  drawquarterlightmap_sdl(dark0, dark2, dark3, dark6, /*colors*/
656  map_image_size, map_image_size, /*color square size*/
657  0, 0, map_image_half_size, map_image_half_size, /*interpolation region*/
658  map_image_half_size, map_image_half_size); /*where in lightmap to save result*/
659 #endif
660  dst.w= map_image_size;
661  dst.h= map_image_size;
662  dst.x= x * map_image_size;
663  dst.y= y * map_image_size;
664  SDL_UnlockSurface(lightmap);
665  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
666  }
667 }
668 
681 static void drawsmooth_sdl (int mx,int my,int layer,SDL_Rect dst)
682 {
683  static int dx[8]= {0,1,1,1,0,-1,-1,-1};
684  static int dy[8]= {-1,-1,0,1,1,1,0,-1};
685  static int bweights[8]= {2,0,4,0,8,0,1,0};
686  static int cweights[8]= {0,2,0,4,0,8,0,1};
687  static int bc_exclude[8]= {
688  1+2,/*north exclude northwest (bit0) and northeast(bit1)*/
689  0,
690  2+4,/*east exclude northeast and southeast*/
691  0,
692  4+8,/*and so on*/
693  0,
694  8+1,
695  0
696  };
697  int partdone[8]= {0,0,0,0,0,0,0,0};
698  int slevels[8];
699  int sfaces[8];
700  int i,weight,weightC;
701  int emx,emy;
702  int smoothface;
703  int hasFace = 0;
704  SDL_Rect src;
705  for (i=0; i<=layer; i++) {
706  hasFace |= the_map.cells[mx][my].heads[i].face;
707  }
708  if (!hasFace
709  || !CAN_SMOOTH(the_map.cells[mx][my], layer)) {
710  return;
711  }
712 
713  src.w=dst.w;
714  src.h=dst.h;
715 
716  for (i=0; i<8; i++) {
717  emx=mx+dx[i];
718  emy=my+dy[i];
719  if ( (emx<0) || (emy<0) || (the_map.x<=emx) || (the_map.y<=emy)) {
720  slevels[i]=0;
721  sfaces[i]=0; /*black picture*/
722  } else if (the_map.cells[emx][emy].smooth[layer]<=the_map.cells[mx][my].smooth[layer]) {
723  slevels[i]=0;
724  sfaces[i]=0; /*black picture*/
725  } else {
726  slevels[i]=the_map.cells[emx][emy].smooth[layer];
727  sfaces[i]=pixmaps[the_map.cells[emx][emy].heads[layer].face]->smooth_face;
728  }
729  }
730  /* ok, now we have a list of smoothlevel higher than current square.
731  * there are at most 8 different levels. so... let's check 8 times
732  * for the lowest one (we draw from botto to top!).
733  */
734  while (1) {
735  int lowest = -1;
736  for (i=0; i<8; i++) {
737  if ( (slevels[i]>0) && (!partdone[i]) &&
738  ((lowest<0) || (slevels[i]<slevels[lowest]))
739  ) {
740  lowest=i;
741  }
742  }
743  if (lowest<0) {
744  break; /*no more smooth to do on this square*/
745  }
746  /*printf ("hey, must smooth something...%d\n",sfaces[lowest]);*/
747  /*here we know 'what' to smooth*/
748  /* we need to calculate the weight
749  * for border and weight for corners.
750  * then we 'markdone'
751  * the corresponding squares
752  */
753  /*first, the border, which may exclude some corners*/
754  weight=0;
755  weightC=15; /*works in backward. remove where there is nothing*/
756  /*for (i=0;i<8;i++)
757  cornermask[i]=1;*/
758  for (i=0; i<8; i++) { /*check all nearby squares*/
759  if ( (slevels[i]==slevels[lowest]) &&
760  (sfaces[i]==sfaces[lowest])) {
761  partdone[i]=1;
762  weight=weight+bweights[i];
763  weightC&=~bc_exclude[i];
764  } else {
765  /*must rmove the weight of a corner if not in smoothing*/
766  weightC&=~cweights[i];
767  }
768 
769  }
770  /*We can't do this before since we need the partdone to be adjusted*/
771  if (sfaces[lowest]<=0) {
772  continue; /*Can't smooth black*/
773  }
774  smoothface=sfaces[lowest];
775  if (smoothface<=0) {
776  continue; /*picture for smoothing not yet available*/
777  }
778  /* now, it's quite easy. We must draw using a 32x32 part of
779  * the picture smoothface.
780  * This part is located using the 2 weights calculated:
781  * (32*weight,0) and (32*weightC,32)
782  */
783  if ( (!pixmaps[smoothface]->map_image) ||
784  (pixmaps[smoothface] == pixmaps[0])) {
785  continue; /*don't have the picture associated*/
786  }
787  if (weight>0) {
788  src.x=map_image_size*weight;
789  src.y=0;
790  if (the_map.cells[mx][my].cleared) {
791  if (SDL_BlitSurface(pixmaps[smoothface]->fog_image,
792  &src, mapsurface, &dst)) {
793  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
794  }
795  } else {
796  if (SDL_BlitSurface(pixmaps[smoothface]->map_image,
797  &src, mapsurface, &dst)) {
798  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
799  }
800  }
801  }
802  if (weightC>0) {
803  src.x=map_image_size*weightC;
804  src.y=map_image_size;
805  if (the_map.cells[mx][my].cleared) {
806  if (SDL_BlitSurface(pixmaps[smoothface]->fog_image,
807  &src, mapsurface, &dst)) {
808  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
809  }
810  } else {
811  if (SDL_BlitSurface(pixmaps[smoothface]->map_image,
812  &src, mapsurface, &dst)) {
813  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
814  }
815  }
816  }
817  }/*while there's some smooth to do*/
818 }
819 
830 static void update_redrawbitmap(void)
831 {
832  int mx,my, x,y;
833 
834  memset(redrawbitmap, 0, (use_config[CONFIG_MAPWIDTH]+2) * (use_config[CONFIG_MAPHEIGHT]+2));
835 
836  for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) {
837  for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) {
838  mx = x + pl_pos.x;
839  my = y + pl_pos.y;
840 
841  /* Basically, we need to check the conditions that require this space.
842  * to be redrawn. We store this in redrawbitmap, because storing
843  * in the_map[][].need_update would cause a cascade effect, of space
844  * 1,0 need an update, so we thing 2,0 needs an update due to smoothing/
845  * like, which causes 3,0 to be updated, etc. Having our own
846  * memory area allows the memset above, which is an optimized routine
847  * to clear memory.
848  */
849  if (the_map.cells[mx][my].need_update) {
850  redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
851  /* If this space has changed, and using non tile lighting,
852  * we need to update the neighbor spaces. Ideally, we'd
853  * have a flag just to denote lighting changes, since
854  * that is handled on a different surface anyways.
855  */
856  if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL ||
857  use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) {
858  /* This is where having redrawbitmap bigger pays off - don't have
859  * to check to see if values are within redrawbitmap is within bounds
860  */
861  redrawbitmap[x + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
862  redrawbitmap[x + 2 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
863  redrawbitmap[x + 1 + (y) * use_config[CONFIG_MAPWIDTH]] = 1;
864  redrawbitmap[x + 1 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1;
865  }
866  /* In best mode, have to update diaganols in addition*/
867  if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) {
868  redrawbitmap[x + (y) * use_config[CONFIG_MAPWIDTH]] = 1;
869  redrawbitmap[x + 2 + (y) * use_config[CONFIG_MAPWIDTH]] = 1;
870  redrawbitmap[x + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1;
871  redrawbitmap[x + 2 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1;
872  }
873  } else if (the_map.cells[mx][my].need_resmooth) {
874  redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
875  }
876  }
877  }
878 }
879 
887 static void display_mapcell(int ax, int ay, int mx, int my)
888 {
889  SDL_Rect dst, src;
890  int layer;
891 
892  /* First, we need to black out this space. */
893  dst.x = ax*map_image_size;
894  dst.y = ay*map_image_size;
895  dst.w = map_image_size;
896  dst.h = map_image_size;
897  SDL_FillRect(mapsurface, &dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
898 
899  /* now draw the different layers. Only draw if using fog of war or the
900  * space isn't clear.
901  */
902  if (use_config[CONFIG_FOGWAR] || !the_map.cells[mx][my].cleared) {
903  for (layer=0; layer<MAXLAYERS; layer++) {
904  int sx, sy;
905 
906  /* draw single-tile faces first */
907  int face = mapdata_face(ax, ay, layer);
908  if (face > 0 && pixmaps[face]->map_image != NULL) {
909  int w = pixmaps[face]->map_width;
910  int h = pixmaps[face]->map_height;
911  /* add one to the size values to take into account the actual width of the space */
912  src.x = w-map_image_size;
913  src.y = h-map_image_size;
914  src.w = map_image_size;
915  src.h = map_image_size;
916  dst.x = ax*map_image_size;
917  dst.y = ay*map_image_size;
918  if (the_map.cells[mx][my].cleared) {
919  if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst)) {
920  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
921  }
922  } else {
923  if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst)) {
924  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
925  }
926  }
927 
928  }
929  /* Sometimes, it may happens we need to draw the smooth while there
930  * is nothing to draw at that layer (but there was something at lower
931  * layers). This is handled here. The else part is to take into account
932  * cases where the smooth as already been handled 2 code lines before
933  */
934  if (use_config[CONFIG_SMOOTH]) {
935  drawsmooth_sdl (mx,my,layer,dst);
936  }
937 
938  /* draw big faces last (should overlap other objects) */
939  face = mapdata_bigface(ax, ay, layer, &sx, &sy);
940  if (face > 0 && pixmaps[face]->map_image != NULL) {
941  /* We have to handle images that are not an equal
942  * multiplier of map_image_size. See
943  * display_mapcell() in gtk-v2/src/map.c for
944  * more details on this logic, since it is basically
945  * the same.
946  */
947  int dx, dy, sourcex, sourcey, offx, offy;
948 
949  dx = pixmaps[face]->map_width % map_image_size;
950  offx = dx?(map_image_size -dx):0;
951 
952  if (sx) {
953  sourcex = sx * map_image_size - offx ;
954  offx=0;
955  } else {
956  sourcex=0;
957  }
958 
959  dy = pixmaps[face]->map_height % map_image_size;
960  offy = dy?(map_image_size -dy):0;
961 
962  if (sy) {
963  sourcey = sy * map_image_size - offy;
964  offy=0;
965  } else {
966  sourcey=0;
967  }
968 
969  src.x = sourcex;
970  src.y = sourcey;
971  src.w = map_image_size - offx;
972  src.h = map_image_size - offy;
973  dst.x = ax*map_image_size + offx;
974  dst.y = ay*map_image_size + offy;
975  if (the_map.cells[mx][my].cleared) {
976  if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst)) {
977  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
978  }
979  } else {
980  if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst)) {
981  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
982  }
983  }
984  } /* else for processing the layers */
985  }
986  }
987 
988  if (use_config[CONFIG_LIGHTING] == CFG_LT_TILE) {
989  dst.x = ax*map_image_size;
990  dst.y = ay*map_image_size;
991  dst.w = map_image_size;
992  dst.h = map_image_size;
993 
994  /* Note - Instead of using a lightmap, I just fillrect
995  * directly onto the map surface - I would think this should be
996  * faster
997  */
998  if (the_map.cells[mx][my].darkness == 255) {
999  SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
1000  } else if (the_map.cells[mx][my].darkness != 0) {
1001  SDL_SetAlpha(lightmap, SDL_SRCALPHA|SDL_RLEACCEL, the_map.cells[mx][my].darkness);
1002  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
1003  }
1004  } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL || use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) {
1005  do_sdl_per_pixel_lighting(ax, ay, mx, my);
1006  }
1007 }
1008 
1033 void sdl_gen_map(int redraw)
1034 {
1035  int x, y, num_spaces=0, num_drawn=0;
1036  struct timeval tv1, tv2, tv3;
1037  long elapsed1, elapsed2;
1038 
1039  if (time_map_redraw) {
1040  gettimeofday(&tv1, NULL);
1041  }
1042 
1043  update_redrawbitmap();
1044 
1045  for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) {
1046  for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) {
1047  num_spaces++;
1048 
1049  /* This will be updated in the for loop above for
1050  * whatever conditions that need this space to be redrawn
1051  */
1052  if (redraw || redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]]) {
1053  num_drawn++;
1054  display_mapcell(x, y, pl_pos.x+x, pl_pos.y+y);
1055  the_map.cells[pl_pos.x+x][pl_pos.y+y].need_update = 0;
1057  }
1058  }
1059  }
1060 
1061  if (time_map_redraw) {
1062  gettimeofday(&tv2, NULL);
1063  }
1064 
1065  SDL_Flip(mapsurface);
1066 
1067  if (time_map_redraw) {
1068  gettimeofday(&tv3, NULL);
1069  elapsed1 = (tv2.tv_sec - tv1.tv_sec)*1000000 + (tv2.tv_usec - tv1.tv_usec);
1070  elapsed2 = (tv3.tv_sec - tv2.tv_sec)*1000000 + (tv3.tv_usec - tv2.tv_usec);
1071 
1072  /* I care about performance for 'long' updates, so put the check in to make
1073  * these a little more noticable */
1074  if ((elapsed1 + elapsed2)>10000)
1075  LOG(LOG_INFO,"gtk-v2::sdl_gen_map","gen took %7ld, flip took %7ld, total = %7ld",
1076  elapsed1, elapsed2, elapsed1 + elapsed2);
1077  }
1078 } /* sdl_gen_map function */
1079 
1085 int sdl_mapscroll(int dx, int dy)
1086 {
1087  /* Don't sdl_gen_map should take care of the redraw */
1088 
1089  /* a copy of what pngximage does except sdl specfic
1090  * mapsurface->pitch is the length of a scanline in bytes
1091  * including alignment padding
1092  */
1093  SDL_LockSurface( mapsurface);
1094  if( dy < 0) {
1095  int offset= mapsurface->pitch * (-dy*map_image_size);
1096  memmove( mapsurface->pixels + offset, mapsurface->pixels,
1097  mapsurface->pitch * (mapsurface->h + dy*map_image_size) );
1098  } else if( dy > 0) {
1099  int offset= mapsurface->pitch * (dy*map_image_size);
1100  memmove( mapsurface->pixels, mapsurface->pixels + offset,
1101  mapsurface->pitch * (mapsurface->h - dy*map_image_size) );
1102  }
1103 
1104  if (dx) {
1105  int y;
1106  for( y= 0; y < mapsurface->h; y++) {
1107  if( dx < 0) {
1108  char* start_of_row= mapsurface->pixels + mapsurface->pitch * y;
1109  int offset= ( mapsurface->format->BytesPerPixel * map_image_size * -dx);
1110  memmove( start_of_row + offset, start_of_row,
1111  mapsurface->pitch - offset);
1112  } else {
1113  char* start_of_row= mapsurface->pixels + mapsurface->pitch * y;
1114  int offset= ( mapsurface->format->BytesPerPixel * map_image_size * dx);
1115  memmove( start_of_row, start_of_row + offset,
1116  mapsurface->pitch - offset);
1117  }
1118  }
1119  }
1120  SDL_UnlockSurface( mapsurface);
1121 
1122  return 1;
1123 }
1124 
1125 #endif
#define CAN_SMOOTH(__SQUARE, __LEVEL)
Definition: client.h:63
int y
Definition: mapdata.h:97
#define CONFIG_SHOWGRID
Definition: client.h:158
int map_image_size
Definition: map.c:58
#define CONFIG_LIGHTING
Definition: client.h:159
void sdl_gen_map(int redraw)
#define MAP_MAX_SIZE
Map size the client will request the map to be.
Definition: client.h:454
uint32 height
Definition: image.c:61
#define CFG_LT_PIXEL_BEST
Definition: client.h:189
uint16 map_height
Definition: image.h:51
static GdkBitmap * dark2
Definition: map.c:60
uint8 have_darkness
Definition: mapdata.h:86
uint8 need_update
Definition: mapdata.h:85
sint16 face
Definition: mapdata.h:49
Contains various global definitions and XML file name and path defaults.
void LOG(LogLevel level, const char *origin, const char *format,...)
Log messages of a certain importance to stderr.
Definition: misc.c:183
#define TRUE
Definition: client-types.h:76
Pixmap data.
static void display_mapcell(int ax, int ay, int mx, int my)
Definition: map.c:362
int sdl_mapscroll(int dx, int dy)
sint16 use_config[CONFIG_NUMS]
Definition: init.c:39
sint16 mapdata_face(int x, int y, int layer)
Returns the face to display at a given location.
Definition: mapdata.c:966
uint8 darkness
Definition: mapdata.h:84
int time_map_redraw
Definition: map.c:67
uint8 cleared
Definition: mapdata.h:88
#define CONFIG_MAPHEIGHT
Definition: client.h:162
struct Map the_map
Definition: mapdata.c:115
struct MapCell ** cells
Definition: mapdata.h:99
int x
Definition: mapdata.h:96
static GdkBitmap * dark1
Definition: map.c:60
void drawquarterlightmap_sdl(int tl, int tr, int bl, int br, int width, int height, int startx, int starty, int endx, int endy, int destx, int desty)
uint8 need_resmooth
Definition: mapdata.h:87
#define CFG_LT_TILE
Definition: client.h:187
uint32 width
Definition: image.c:61
#define MAXLAYERS
The protocol supports 10 layers, so set MAXLAYERS accordingly.
Definition: mapdata.h:36
uint16 smooth[MAXLAYERS]
Definition: mapdata.h:83
#define CONFIG_SMOOTH
Definition: client.h:168
sint16 mapdata_bigface(int x, int y, int layer, int *ww, int *hh)
Returns the face to display at a given location.
Definition: mapdata.c:979
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: image.c:66
#define CFG_LT_PIXEL
Definition: client.h:188
uint16 smooth_face
A face used for smoothing with this face.
Definition: image.h:53
Includes various dependencies header files needed by most everything.
void init_SDL(GtkWidget *sdl_window, int just_lightmap)
struct MapCellLayer heads[MAXLAYERS]
Definition: mapdata.h:81
#define CONFIG_FOGWAR
Definition: client.h:148
static GdkBitmap * dark3
Definition: map.c:60
PlayerPosition pl_pos
Definition: map.c:54
int map_image_half_size
Definition: map.c:59
#define CONFIG_MAPWIDTH
Definition: client.h:161
uint16 map_width
Definition: image.h:51