Crossfire Client, Trunk
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/SDL.h>
24 #include <gtk/gtk.h>
25 
26 #ifndef WIN32
27 #include <gdk/gdkx.h>
28 #else
29 #include <gdk/gdkwin32.h>
30 #endif
31 
32 #include "image.h"
33 #include "main.h"
34 #include "mapdata.h"
35 #include "gtk2proto.h"
36 
37 SDL_Surface* mapsurface;
38 static SDL_Surface* lightmap;
39 static SDL_Surface* fogmap;
40 static char *redrawbitmap;
41 
42 /* Move some of the SDL code to this file here. This makes it easier to share
43  * between the gnome and gtk client. It also reduces the length of both the
44  * gx11.c and gnome.c file. It also is more readable, as not as many #ifdef
45  * SDL.. #endif constructs are needed. Note that there may still be some SDL
46  * code in gx11.c - some areas are embedded so much that it is not easy to
47  * remove.
48  */
49 
50 
51 static void do_SDL_error(const char *SDL_function, const char *file, int line)
52 {
53  LOG(LOG_CRITICAL,SDL_function,"SDL error in file %s line %d\n%s",
54  file, line, SDL_GetError());
55  SDL_Quit();
56  exit( 1);
57 }
58 
66 static void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
67 {
68  int bpp = surface->format->BytesPerPixel;
69  /* Here p is the address to the pixel we want to set */
70  Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
71 
72  switch(bpp) {
73  case 1:
74  *p = pixel;
75  break;
76 
77  case 2:
78  *(Uint16 *)p = pixel;
79  break;
80 
81  case 3:
82  if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
83  p[0] = (pixel >> 16) & 0xff;
84  p[1] = (pixel >> 8) & 0xff;
85  p[2] = pixel & 0xff;
86  } else {
87  p[0] = pixel & 0xff;
88  p[1] = (pixel >> 8) & 0xff;
89  p[2] = (pixel >> 16) & 0xff;
90  }
91  break;
92 
93  case 4:
94  *(Uint32 *)p = pixel;
95  break;
96  }
97 }
98 
105 static void overlay_grid( int re_init, int ax, int ay)
106 {
107 
108  static SDL_Surface* grid_overlay;
109 
110  static int first_pass;
111 
112  int x= 0;
113  int y= 0;
114  SDL_Rect dst;
115  Uint32 *pixel;
116  SDL_PixelFormat* fmt;
117 
118  /* Need to convert back to screen coordinates */
119  ax-= pl_pos.x;
120  ay-= pl_pos.y;
121 
122  if( re_init == TRUE) {
123  if( grid_overlay) {
124  SDL_FreeSurface( grid_overlay);
125  }
126 
127  first_pass= 0;
128  grid_overlay= NULL;
129  }
130 
131  if( grid_overlay == NULL) {
132  grid_overlay= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA,
135  mapsurface->format->BitsPerPixel,
136  mapsurface->format->Rmask,
137  mapsurface->format->Gmask,
138  mapsurface->format->Bmask,
139  mapsurface->format->Amask);
140  if( grid_overlay == NULL) {
141  do_SDL_error( "CreateRGBSurface", __FILE__, __LINE__);
142  }
143 
144  grid_overlay= SDL_DisplayFormatAlpha( grid_overlay);
145 
146  first_pass= 0;
147  }
148 
149  /*
150  * If this is our first time drawing the grid, we need to build up the
151  * grid overlay
152  */
153  if( first_pass== 0) {
154 
155  /* Red pixels around the edge and along image borders
156  * fully transparent pixels everywhere else
157  */
158 
159  fmt= grid_overlay->format;
160  for( x= 0; x < map_image_size*use_config[CONFIG_MAPWIDTH] * use_config[CONFIG_MAPSCALE] / 100; x++) {
161  for( y= 0; y < map_image_size*use_config[CONFIG_MAPHEIGHT] * use_config[CONFIG_MAPSCALE] / 100; y++) {
162  /* FIXME: Only works for 32 bit displays right now */
163  pixel= (Uint32*)grid_overlay->pixels+y*grid_overlay->pitch/4+x;
164 
165  if( x == 0 || y == 0 ||
166  ((x % map_image_size * use_config[CONFIG_MAPSCALE] / 100) == 0) || ((y % map_image_size * use_config[CONFIG_MAPSCALE] / 100) == 0 ) ||
169  *pixel= SDL_MapRGBA( fmt, 255, 0, 0, SDL_ALPHA_OPAQUE);
170  } else {
171  *pixel= SDL_MapRGBA( fmt, 0, 0, 0, SDL_ALPHA_TRANSPARENT);
172  }
173  }
174  }
175  first_pass= 1;
176 
177  /*
178  * If this is our first pass then we need to overlay the entire grid
179  * now. Otherwise we just update the tile we are on
180  */
181  dst.x= 0;
182  dst.y= 0;
185  SDL_BlitSurface( grid_overlay, NULL, mapsurface, &dst);
186  } else {
187  dst.x= ax* map_image_size * use_config[CONFIG_MAPSCALE] / 100;
188  dst.y= ay* map_image_size * use_config[CONFIG_MAPSCALE] / 100;
189  dst.w= map_image_size * use_config[CONFIG_MAPSCALE] / 100;
190  dst.h= map_image_size * use_config[CONFIG_MAPSCALE] / 100;
191  /* One to one pixel mapping of grid and mapsurface so we
192  * can share the SDL_Rect
193  */
194  SDL_BlitSurface( grid_overlay, &dst, mapsurface, &dst);
195  }
196 
197  return;
198 }
199 
210 void init_SDL( GtkWidget* sdl_window, int just_lightmap)
211 {
212 
213  char SDL_windowhack[32];
214 
215  if( just_lightmap == 0) {
216  g_assert( sdl_window != NULL);
217  if( SDL_WasInit( SDL_INIT_VIDEO) != 0) {
218  if( lightmap) {
219  SDL_FreeSurface( lightmap);
220  }
221  if( mapsurface) {
222  SDL_FreeSurface( mapsurface);
223  }
224  SDL_Quit();
225  }
226 
227  /*
228  * SDL hack to tell SDL which xwindow to paint onto
229  */
230 
231 #ifndef WIN32
232  snprintf(SDL_windowhack, sizeof(SDL_windowhack), "SDL_WINDOWID=%ld",
233  GDK_WINDOW_XWINDOW(gtk_widget_get_window(sdl_window)) );
234 #else
235  sprintf( SDL_windowhack, "SDL_WINDOWID=%ld",
236  GDK_WINDOW_HWND(gtk_widget_get_window(sdl_window)) );
237 #endif
238  putenv( SDL_windowhack);
239 
240  if( SDL_Init( SDL_INIT_VIDEO) < 0) {
241  LOG(LOG_CRITICAL,"gtk-v2::init_SDL", "Could not initialize SDL: %s", SDL_GetError());
242  gtk_main_quit();
243  }
244 
245  mapsurface= SDL_SetVideoMode( map_image_size*use_config[CONFIG_MAPWIDTH]*use_config[CONFIG_MAPSCALE] / 100,
247  SDL_HWSURFACE|SDL_DOUBLEBUF);
248 
249  if( mapsurface == NULL) {
250  do_SDL_error( "SetVideoMode", __FILE__, __LINE__);
251  }
252 
253  if( fogmap) {
254  SDL_FreeSurface( fogmap);
255  }
256 
257  fogmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size*use_config[CONFIG_MAPSCALE] / 100,
259  mapsurface->format->BitsPerPixel,
260  mapsurface->format->Rmask,
261  mapsurface->format->Gmask,
262  mapsurface->format->Bmask,
263  mapsurface->format->Amask);
264 
265  if( fogmap == NULL) {
266  do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__);
267  }
268 
269  /*
270  * This is a persurface alpha value, not an alpha channel value.
271  * So this surface doesn't actually need a full alpha channel
272  */
273  if( SDL_SetAlpha( fogmap, SDL_SRCALPHA|SDL_RLEACCEL, 128) < 0) {
274  do_SDL_error( "SDL_SetAlpha", __FILE__, __LINE__);
275  }
276  }
277 
278  if( just_lightmap != 0 && lightmap) {
279  SDL_FreeSurface( lightmap);
280  }
281 
282  lightmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size*use_config[CONFIG_MAPSCALE] / 100,
284  mapsurface->format->BitsPerPixel,
285  mapsurface->format->Rmask,
286  mapsurface->format->Gmask,
287  mapsurface->format->Bmask,
288  mapsurface->format->Amask);
289  if( lightmap == NULL) {
290  do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__);
291  }
292 
294  /* Convert surface to have a full alpha channel if we are doing
295  * per-pixel lighting */
296  lightmap= SDL_DisplayFormatAlpha( lightmap);
297  if( lightmap == NULL) {
298  do_SDL_error( "DisplayFormatAlpha", __FILE__, __LINE__);
299  }
300  }
301 
302  if(use_config[CONFIG_SHOWGRID] == TRUE) {
303  overlay_grid( TRUE, 0, 0);
304  }
305  /* We make this a bit bigger than the actual map - thus, there
306  * is a 1 space pad in all directions. This enables us
307  * to store a value in that area without having to do checks to
308  * see if we are at the edge of the map - doing a store vs 4
309  * checks is going to be much faster.
310  */
311  redrawbitmap = g_malloc(sizeof(char) * (MAP_MAX_SIZE +2)* (MAP_MAX_SIZE+2));
312 }
313 
314 
341 void drawquarterlightmap_sdl(int tl, int tr, int bl, int br,
342  int width, int height,
343  int startx, int starty, int endx, int endy,
344  int destx, int desty)
345 {
346  int x,y;
347  int top,bottom,val;
348  for (x=startx; x<endx; x++) {
349  top= ((x*(tr-tl))/ width)+tl; /*linear interpolation for top color*/
350  bottom= ((x*(br-bl))/ width)+bl; /*linear interpolation for bottom color*/
351  for (y=starty; y<endy; y++) {
352  val=((y*(bottom-top))/height)+top; /*linear interpolation between top and bottom*/
353  if (val>255) {
354  val=255;
355  }
356  if (val<0) {
357  val=0;
358  }
359  /*printf("writing pel at %d,%d\n",destx+x,desty+y);*/
360  putpixel(lightmap, destx+x-startx, desty+y-starty,
361  SDL_MapRGBA(lightmap->format, 0, 0, 0, val));
362  }
363  }
364 }
365 
366 
367 /* See note below about ALPHA_FUDGE - used to adjust lighting effects some */
368 
369 #define ALPHA_FUDGE(x) (2*(x) / 3)
370 #define GENDARK(x,y) ( (((x)&(y) & 1) == 1)?255:0 )
371 
404 static void do_sdl_per_pixel_lighting(int x, int y, int mx, int my)
405 {
406 
407  int dark0, dark1, dark2, dark3, dark4;
408  SDL_Rect dst;
409 
410  /* I use dark0 -> dark4 in the order to keep it similar to
411  * the old code.
412  */
413  dark0 = mapdata_cell(mx, my)->darkness;
414 
415  if (y-1 < 0 || !mapdata_cell(mx, my-1)->have_darkness) {
416  dark1 = dark0;
417  } else {
418  dark1 = mapdata_cell(mx, my-1)->darkness;
419  }
420 
421  if (x+1 >= use_config[CONFIG_MAPWIDTH] || !mapdata_cell(mx+1, my)->have_darkness) {
422  dark2 = dark0;
423  } else {
424  dark2 = mapdata_cell(mx+1, my)->darkness;
425  }
426 
427  if (y+1 >= use_config[CONFIG_MAPHEIGHT] || !mapdata_cell(mx, my+1)->have_darkness) {
428  dark3 = dark0;
429  } else {
430  dark3 = mapdata_cell(mx, my+1)->darkness;
431  }
432 
433  if (x-1 < 0 || !mapdata_cell(mx-1, my)->have_darkness) {
434  dark4 = dark0;
435  } else {
436  dark4 = mapdata_cell(mx-1, my)->darkness;
437  }
438 
439  /* If they are all the same, processing is easy
440  *
441  * Note, the best lightining algorithm also uses diagonals
442  * so we should check the diagonals are same too
443  * We don't check for now, simply do all raw computation on best mode
444  * Tchize 19 may 2004
445  */
446  if (dark0 == dark1 && dark0 == dark2 && dark0 == dark3 && dark0 == dark4 && (use_config[CONFIG_LIGHTING] != CFG_LT_PIXEL_BEST)) {
447  dst.x = x * map_image_size * use_config[CONFIG_MAPSCALE] / 100;
448  dst.y = y * map_image_size * use_config[CONFIG_MAPSCALE] / 100;
449  dst.w = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
450  dst.h = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
451 
452  if (dark0 == 255) {
453  SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
454  } else if (mapdata_cell(mx, my)->darkness != 0) {
455  SDL_FillRect(lightmap,NULL, SDL_MapRGBA(lightmap->format, 0, 0, 0, mapdata_cell(mx, my)->darkness));
456  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
457  }
458  return;
459  }
460 
461 
463  /* This almost works as well as the per pixel code below, but does have some various
464  * artifacts in the drawing. It uses the same logic as the per pixel code below,
465  * bit since SDL does the blit, the alpha handling ends up being different
466  * (I think it ends up being additive). This results in the darkness being
467  * darker, but you also don't get the smooth effects. If you divide all the values
468  * by 2 (change ALPHA_FUDGE), the blending is smooth, but now the things are not dark
469  * enough, so the blending aganst solid black spaces does not look good.
470  * The reason this code is of interest is that on my system, it is about 50%
471  * faster than the code below (25 ms to darkness the church in the starting
472  * town vs 50 ms for the code further down)
473  * Setting ALPHA_FUDGE to 2/3 seems to reduce the artifacts described above
474  * to fairly minimal levels, while still keeping things dark enough.
475  * MSW 2001-10-12
476  */
477 
478  int i;
479 
480  if (dark1 == dark0) {
481  /* If we don't have usable darkness at the top, then this entire region
482  * should be the same value. Likewise, if the top value and center value
483  * are the same, we can do the entire region.
484  */
485  dst.x=0;
486  dst.y=0;
487  dst.w = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
489  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
490  } else for (i=0; i<map_image_half_size; i++) {
491  /* Need to do it line by line */
492 
493  dst.x = 0;
494  dst.y = i;
495  dst.w = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
496  dst.h = 1;
497  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
498  ALPHA_FUDGE((map_image_half_size * use_config[CONFIG_MAPSCALE] / 100 - i) * dark1 + i * dark0)/(map_image_half_size * use_config[CONFIG_MAPSCALE] / 100)));
499 
500  }
501  /* All the following blocks are basically the same as above, just different
502  * darkness areas.
503  */
504  if (dark3 == dark0) {
505  dst.x=0;
507  dst.w = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
509  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
511  /* Need to do it line by line */
512 
513  dst.x = 0;
514  dst.y = i;
515  dst.w = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
516  dst.h = 1;
517  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
518  ALPHA_FUDGE(dark0*(map_image_size * use_config[CONFIG_MAPSCALE] / 100 - i)
519  + dark3*(i-map_image_half_size * use_config[CONFIG_MAPSCALE] / 100))
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 * use_config[CONFIG_MAPSCALE] / 100;
527  dst.y= y * map_image_size * use_config[CONFIG_MAPSCALE] / 100;
528  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
529 
530  if (dark4 == dark0) {
531  dst.x=0;
532  dst.y=0;
534  dst.h = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
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 * use_config[CONFIG_MAPSCALE] / 100;
542  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
543  ALPHA_FUDGE(dark4*(map_image_half_size * use_config[CONFIG_MAPSCALE] / 100 -i) + dark0*i) / (map_image_half_size * use_config[CONFIG_MAPSCALE] / 100)));
544  }
545  if (dark2 == dark0) {
547  dst.y=0;
549  dst.h = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
550  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
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 * use_config[CONFIG_MAPSCALE] / 100;
558  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
560  }
561  dst.x= x * map_image_size * use_config[CONFIG_MAPSCALE] / 100;
562  dst.y= y * map_image_size * use_config[CONFIG_MAPSCALE] / 100;
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 * use_config[CONFIG_MAPSCALE] / 100 > darkx_allocated) {
575  darkx = g_realloc(darkx, map_image_size * use_config[CONFIG_MAPSCALE] / 100 * sizeof(int));
576  darky = g_realloc(darky, map_image_size * use_config[CONFIG_MAPSCALE] / 100 * sizeof(int));
577  darkx_allocated = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
578  }
579 
580  for( dx= 0; dx < map_image_half_size * use_config[CONFIG_MAPSCALE] / 100; dx++) {
581  darkx[dx]= (dark4*(map_image_half_size * use_config[CONFIG_MAPSCALE] / 100-dx) + dark0*dx) / (map_image_half_size * use_config[CONFIG_MAPSCALE] / 100);
582  }
585  }
586 
587  for( dy= 0; dy < map_image_half_size* use_config[CONFIG_MAPSCALE] / 100; dy++) {
588  darky[dy]= (dark1*(map_image_half_size* use_config[CONFIG_MAPSCALE] / 100-dy) + dark0*dy) / (map_image_half_size * use_config[CONFIG_MAPSCALE] / 100);
589  }
591  darky[dy] = (dark0*(map_image_size * use_config[CONFIG_MAPSCALE] / 100-dy) + dark3*(dy-map_image_half_size * use_config[CONFIG_MAPSCALE] / 100)) / (map_image_half_size * use_config[CONFIG_MAPSCALE] / 100);
592  }
593 
594  SDL_LockSurface( lightmap);
595 
596  for (dx=0; dx<map_image_size* use_config[CONFIG_MAPSCALE] / 100; dx++)
597  for (dy=0; dy<map_image_size* use_config[CONFIG_MAPSCALE] / 100; 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 * use_config[CONFIG_MAPSCALE] / 100, map_image_size * use_config[CONFIG_MAPSCALE] / 100, /*color square size*/
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 * use_config[CONFIG_MAPSCALE] / 100, map_image_size * use_config[CONFIG_MAPSCALE] / 100, /*color square size*/
640  map_image_half_size * use_config[CONFIG_MAPSCALE] / 100, 0); /*where in lightmap to save result*/
641  /*bottom left lightmap quarter*/
642  drawquarterlightmap_sdl(dark4, dark0, dark7, dark3, /*colors*/
643  map_image_size* use_config[CONFIG_MAPSCALE] / 100, map_image_size * use_config[CONFIG_MAPSCALE] / 100, /*color square size*/
645  0, map_image_half_size * use_config[CONFIG_MAPSCALE] / 100); /*where in lightmap to save result*/
646  /*bottom right lightmap quarter*/
647  drawquarterlightmap_sdl(dark0, dark2, dark3, dark6, /*colors*/
648  map_image_size* use_config[CONFIG_MAPSCALE] / 100, map_image_size * use_config[CONFIG_MAPSCALE] / 100, /*color square size*/
649  0, 0, map_image_half_size * use_config[CONFIG_MAPSCALE] / 100, map_image_half_size * use_config[CONFIG_MAPSCALE] / 100, /*interpolation region*/
650  map_image_half_size * use_config[CONFIG_MAPSCALE] / 100, map_image_half_size * use_config[CONFIG_MAPSCALE] / 100); /*where in lightmap to save result*/
651 #endif
652  dst.w= map_image_size * use_config[CONFIG_MAPSCALE] / 100;
653  dst.h= map_image_size * use_config[CONFIG_MAPSCALE] / 100;
654  dst.x= x * map_image_size * use_config[CONFIG_MAPSCALE] / 100;
655  dst.y= y * map_image_size * use_config[CONFIG_MAPSCALE] / 100;
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 * use_config[CONFIG_MAPSCALE] / 100;
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* use_config[CONFIG_MAPSCALE] / 100;
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  */
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*/
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, scaled_image_size = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
882 
883  /* First, we need to black out this space. */
884  dst.x = ax*scaled_image_size;
885  dst.y = ay*scaled_image_size;
886  dst.w = scaled_image_size;
887  dst.h = scaled_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-scaled_image_size;
904  src.y = h-scaled_image_size;
905  src.w = scaled_image_size;
906  src.h = scaled_image_size;
907  dst.x = ax*scaled_image_size;
908  dst.y = ay*scaled_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 % scaled_image_size;
941  offx = dx?(scaled_image_size-dx):0;
942 
943  if (sx) {
944  sourcex = sx * scaled_image_size - offx ;
945  offx=0;
946  } else {
947  sourcex=0;
948  }
949 
950  dy = (pixmaps[face]->map_height) % scaled_image_size;
951  offy = dy?(scaled_image_size-dy):0;
952 
953  if (sy) {
954  sourcey = sy * scaled_image_size - offy;
955  offy=0;
956  } else {
957  sourcey=0;
958  }
959 
960  src.x = sourcex;
961  src.y = sourcey;
962  src.w = scaled_image_size - offx;
963  src.h = scaled_image_size - offy;
964  dst.x = ax*scaled_image_size + offx;
965  dst.y = ay*scaled_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 
980  dst.x = ax*scaled_image_size;
981  dst.y = ay*scaled_image_size;
982  dst.w = scaled_image_size;
983  dst.h = scaled_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  }
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  if (redrawbitmap == NULL) {
1027  return;
1028  }
1029  update_redrawbitmap();
1030 
1031  for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) {
1032  for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) {
1033  num_spaces++;
1034 
1035  /* This will be updated in the for loop above for
1036  * whatever conditions that need this space to be redrawn
1037  */
1038  if (redraw || redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]]) {
1039  num_drawn++;
1040  display_mapcell(x, y, pl_pos.x+x, pl_pos.y+y);
1041  mapdata_cell(pl_pos.x+x, pl_pos.y+y)->need_update = 0;
1043  }
1044  }
1045  }
1046 
1047  SDL_Flip(mapsurface);
1048 }
1049 
1055 int sdl_mapscroll(int dx, int dy)
1056 {
1057  /* Don't sdl_gen_map should take care of the redraw */
1058 
1059  // If we are more than about 15 tiles of movement, then
1060  // Don't scroll. This should avoid a segfault.
1061  if (dx > 15 || dx < -15 || dy > 15 || dy < 15)
1062  return 0;
1063 
1064  /* a copy of what pngximage does except sdl specfic
1065  * mapsurface->pitch is the length of a scanline in bytes
1066  * including alignment padding
1067  */
1068  SDL_LockSurface( mapsurface);
1069  if( dy < 0) {
1070  int offset= mapsurface->pitch * (-dy*map_image_size* use_config[CONFIG_MAPSCALE] / 100);
1071  memmove( mapsurface->pixels + offset, mapsurface->pixels,
1072  mapsurface->pitch * (mapsurface->h + dy*map_image_size* use_config[CONFIG_MAPSCALE] / 100) );
1073  } else if( dy > 0) {
1074  int offset= mapsurface->pitch * (dy*map_image_size * use_config[CONFIG_MAPSCALE] / 100);
1075  memmove( mapsurface->pixels, mapsurface->pixels + offset,
1076  mapsurface->pitch * (mapsurface->h - dy*map_image_size* use_config[CONFIG_MAPSCALE] / 100) );
1077  }
1078 
1079  if (dx) {
1080  int y;
1081  for( y= 0; y < mapsurface->h; y++) {
1082  if( dx < 0) {
1083  char* start_of_row= mapsurface->pixels + mapsurface->pitch * y;
1084  int offset= ( mapsurface->format->BytesPerPixel * map_image_size* use_config[CONFIG_MAPSCALE] / 100 * -dx);
1085  memmove( start_of_row + offset, start_of_row,
1086  mapsurface->pitch - offset);
1087  } else {
1088  char* start_of_row= mapsurface->pixels + mapsurface->pitch * y;
1089  int offset= ( mapsurface->format->BytesPerPixel * map_image_size* use_config[CONFIG_MAPSCALE] / 100 * dx);
1090  memmove( start_of_row, start_of_row + offset,
1091  mapsurface->pitch - offset);
1092  }
1093  }
1094  }
1095  SDL_UnlockSurface( mapsurface);
1096 
1097  return 1;
1098 }
1099 
1100 #endif
mapdata_cell
struct MapCell * mapdata_cell(const int x, const int y)
Definition: mapdata.c:127
redraw
static gboolean redraw(gpointer data)
Definition: main.c:126
PlayerPosition::x
int x
Definition: client.h:530
CFG_LT_PIXEL
#define CFG_LT_PIXEL
Definition: client.h:233
MapCell::cleared
guint8 cleared
Definition: mapdata.h:64
mapdata_bigface
gint16 mapdata_bigface(int x, int y, int layer, int *ww, int *hh)
Definition: mapdata.c:1087
pixmaps
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: image.c:38
mapdata_face
gint16 mapdata_face(int x, int y, int layer)
Definition: mapdata.c:1053
CONFIG_FOGWAR
#define CONFIG_FOGWAR
Definition: client.h:195
CONFIG_MAPSCALE
#define CONFIG_MAPSCALE
Definition: client.h:197
height
static int height
Definition: mapdata.c:90
mapdata_can_smooth
bool mapdata_can_smooth(int x, int y, int layer)
Definition: mapdata.c:142
CONFIG_LIGHTING
#define CONFIG_LIGHTING
Definition: client.h:206
PlayerPosition::y
int y
Definition: client.h:531
CFG_LT_TILE
#define CFG_LT_TILE
Definition: client.h:232
LOG_CRITICAL
@ LOG_CRITICAL
Fatal crash-worthy error.
Definition: client.h:442
mapdata.h
map_image_half_size
int map_image_half_size
Definition: main.h:34
sdl_gen_map
void sdl_gen_map(int redraw)
PixmapInfo::map_height
guint16 map_height
Definition: image.h:60
MapCellLayer::face
gint16 face
Definition: mapdata.h:19
PixmapInfo::map_width
guint16 map_width
Definition: image.h:60
MapCell::heads
struct MapCellLayer heads[MAXLAYERS]
Definition: mapdata.h:57
CONFIG_SHOWGRID
#define CONFIG_SHOWGRID
Definition: client.h:205
init_SDL
void init_SDL(GtkWidget *sdl_window, int just_lightmap)
gtk2proto.h
sdl_mapscroll
int sdl_mapscroll(int dx, int dy)
MapCell::smooth
guint8 smooth[MAXLAYERS]
Definition: mapdata.h:59
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:111
width
static int width
Definition: mapdata.c:89
PixmapInfo::smooth_face
guint16 smooth_face
Definition: image.h:62
MAP_MAX_SIZE
#define MAP_MAX_SIZE
Definition: client.h:471
CFG_LT_PIXEL_BEST
#define CFG_LT_PIXEL_BEST
Definition: client.h:234
MapCell::darkness
guint8 darkness
Definition: mapdata.h:60
image.h
drawquarterlightmap_sdl
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)
mapdata_contains
bool mapdata_contains(int x, int y)
Definition: mapdata.c:134
MapCell::need_resmooth
guint8 need_resmooth
Definition: mapdata.h:63
main.h
CONFIG_MAPWIDTH
#define CONFIG_MAPWIDTH
Definition: client.h:208
CONFIG_SMOOTH
#define CONFIG_SMOOTH
Definition: client.h:215
pl_pos
PlayerPosition pl_pos
Definition: map.c:37
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:247
MAXLAYERS
#define MAXLAYERS
Definition: mapdata.h:6
CONFIG_MAPHEIGHT
#define CONFIG_MAPHEIGHT
Definition: client.h:209
map_image_size
int map_image_size
Definition: map.c:41
MapCell::need_update
guint8 need_update
Definition: mapdata.h:61
client.h