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