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