Crossfire Client, Branches  R11627
sdl.c
Go to the documentation of this file.
1 const char * const rcsid_gtk_sdl_c =
2  "$Id: sdl.c 9200 2008-06-01 17:12:43Z anmaster $";
3 
4 /*
5  Crossfire client, a client program for the crossfire program.
6 
7  Copyright (C) 2005 Mark Wedel & Crossfire Development Team
8 
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23  The author can be reached via e-mail to crossfire@metalforge.org
24 */
25 
31 #include <config.h>
32 
33 #ifdef HAVE_SDL
34 
35 #include <client-types.h>
36 #include <SDL.h>
37 #include <SDL_image.h>
38 
39 /* Pick up the gtk headers we need */
40 #include <gtk/gtk.h>
41 #include <glade/glade.h>
42 #ifndef WIN32
43 #include <gdk/gdkx.h>
44 #else
45 #include <gdk/gdkwin32.h>
46 #endif
47 #include <gdk/gdkkeysyms.h>
48 
49 #include "main.h"
50 #include "image.h"
51 #include <client.h>
52 #include "gtk2proto.h"
53 #include "mapdata.h"
54 
55 SDL_Surface* mapsurface;
56 static SDL_Surface* lightmap;
57 static SDL_Surface* fogmap;
58 static char *redrawbitmap;
59 
60 extern int time_map_redraw;
61 
62 
63 /* Move some of the SDL code to this file here. This makes it easier to share
64  * between the gnome and gtk client. It also reduces the length of both the
65  * gx11.c and gnome.c file. It also is more readable, as not as many #ifdef
66  * SDL.. #endif constructs are needed. Note that there may still be some SDL
67  * code in gx11.c - some areas are embedded so much that it is not easy to
68  * remove.
69  */
70 
71 /* these should generally be included by the file including this file. */
72 #include <SDL.h>
73 #include <SDL_image.h>
74 
75 
76 static void do_SDL_error(const char *SDL_function, const char *file, int line)
77 {
78  LOG(LOG_CRITICAL,SDL_function,"SDL error in file %s line %d\n%s",
79  file, line, SDL_GetError());
80  SDL_Quit();
81  exit( 1);
82 }
83 
91 static void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
92 {
93  int bpp = surface->format->BytesPerPixel;
94  /* Here p is the address to the pixel we want to set */
95  Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
96 
97  switch(bpp) {
98  case 1:
99  *p = pixel;
100  break;
101 
102  case 2:
103  *(Uint16 *)p = pixel;
104  break;
105 
106  case 3:
107  if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
108  p[0] = (pixel >> 16) & 0xff;
109  p[1] = (pixel >> 8) & 0xff;
110  p[2] = pixel & 0xff;
111  } else {
112  p[0] = pixel & 0xff;
113  p[1] = (pixel >> 8) & 0xff;
114  p[2] = (pixel >> 16) & 0xff;
115  }
116  break;
117 
118  case 4:
119  *(Uint32 *)p = pixel;
120  break;
121  }
122 }
123 
130 static void overlay_grid( int re_init, int ax, int ay)
131 {
132 
133  static SDL_Surface* grid_overlay;
134 
135  static int first_pass;
136 
137  int x= 0;
138  int y= 0;
139  SDL_Rect dst;
140  Uint32 *pixel;
141  SDL_PixelFormat* fmt;
142 
143  /* Need to convert back to screen coordinates */
144  ax-= pl_pos.x;
145  ay-= pl_pos.y;
146 
147  if( re_init == TRUE)
148  {
149  if( grid_overlay)
150  SDL_FreeSurface( grid_overlay);
151 
152  first_pass= 0;
153  grid_overlay= NULL;
154  }
155 
156  if( grid_overlay == NULL)
157  {
158  grid_overlay= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA,
160  use_config[CONFIG_MAPHEIGHT]*map_image_size,
161  mapsurface->format->BitsPerPixel,
162  mapsurface->format->Rmask,
163  mapsurface->format->Gmask,
164  mapsurface->format->Bmask,
165  mapsurface->format->Amask);
166  if( grid_overlay == NULL)
167  do_SDL_error( "CreateRGBSurface", __FILE__, __LINE__);
168 
169  grid_overlay= SDL_DisplayFormatAlpha( grid_overlay);
170 
171  first_pass= 0;
172  }
173 
174  /*
175  * If this is our first time drawing the grid, we need to build up the
176  * grid overlay
177  */
178  if( first_pass== 0)
179  {
180 
181  /* Red pixels around the edge and along image borders
182  * fully transparent pixels everywhere else
183  */
184 
185  fmt= grid_overlay->format;
186  for( x= 0; x < map_image_size*use_config[CONFIG_MAPWIDTH]; x++)
187  {
188  for( y= 0; y < map_image_size*use_config[CONFIG_MAPHEIGHT]; y++)
189  {
190  /* FIXME: Only works for 32 bit displays right now */
191  pixel= (Uint32*)grid_overlay->pixels+y*grid_overlay->pitch/4+x;
192 
193  if( x == 0 || y == 0 ||
194  ((x % map_image_size) == 0) || ((y % map_image_size) == 0 ) ||
195  y == use_config[CONFIG_MAPHEIGHT]*map_image_size-1 || x == use_config[CONFIG_MAPWIDTH]*map_image_size -1 )
196  {
197  *pixel= SDL_MapRGBA( fmt, 255, 0, 0, SDL_ALPHA_OPAQUE);
198  }
199  else
200  {
201  *pixel= SDL_MapRGBA( fmt, 0, 0, 0, SDL_ALPHA_TRANSPARENT);
202  }
203  }
204  }
205  first_pass= 1;
206 
207  /*
208  * If this is our first pass then we need to overlay the entire grid
209  * now. Otherwise we just update the tile we are on
210  */
211  dst.x= 0;
212  dst.y= 0;
213  dst.w= map_image_size*use_config[CONFIG_MAPWIDTH];
214  dst.h= map_image_size*use_config[CONFIG_MAPHEIGHT];
215  SDL_BlitSurface( grid_overlay, NULL, mapsurface, &dst);
216  }
217  else
218  {
219  dst.x= ax* map_image_size;
220  dst.y= ay* map_image_size;
221  dst.w= map_image_size;
222  dst.h= map_image_size;
223  /* One to one pixel mapping of grid and mapsurface so we
224  * can share the SDL_Rect
225  */
226  SDL_BlitSurface( grid_overlay, &dst, mapsurface, &dst);
227  }
228 
229  return;
230 }
231 
242 void init_SDL( GtkWidget* sdl_window, int just_lightmap)
243 {
244 
245  char SDL_windowhack[32];
246 
247  if( just_lightmap == 0) {
248  g_assert( sdl_window != NULL);
249  if( SDL_WasInit( SDL_INIT_VIDEO) != 0) {
250  if( lightmap)
251  SDL_FreeSurface( lightmap);
252  if( mapsurface)
253  SDL_FreeSurface( mapsurface);
254  SDL_Quit();
255  }
256 
257  /*
258  * SDL hack to tell SDL which xwindow to paint onto
259  */
260 
261 #ifndef WIN32
262  snprintf(SDL_windowhack, sizeof(SDL_windowhack), "SDL_WINDOWID=%ld",
263  GDK_WINDOW_XWINDOW(sdl_window->window) );
264 #else
265  sprintf( SDL_windowhack, "SDL_WINDOWID=%ld",
266  GDK_WINDOW_HWND(sdl_window->window) );
267 #endif
268  putenv( SDL_windowhack);
269 
270  if( SDL_Init( SDL_INIT_VIDEO) < 0)
271  {
272  LOG(LOG_CRITICAL,"gtk::init_SDL", "Could not initialize SDL: %s", SDL_GetError());
273  gtk_main_quit();
274  }
275 
277  SDL_HWSURFACE|SDL_DOUBLEBUF);
278 
279  if( mapsurface == NULL)
280  {
281  do_SDL_error( "SetVideoMode", __FILE__, __LINE__);
282  }
283 
284  if( fogmap)
285  SDL_FreeSurface( fogmap);
286 
287  fogmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size,
289  mapsurface->format->BitsPerPixel,
290  mapsurface->format->Rmask,
291  mapsurface->format->Gmask,
292  mapsurface->format->Bmask,
293  mapsurface->format->Amask);
294 
295  if( fogmap == NULL)
296  {
297  do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__);
298  }
299 
300  /*
301  * This is a persurface alpha value, not an alpha channel value.
302  * So this surface doesn't actually need a full alpha channel
303  */
304  if( SDL_SetAlpha( fogmap, SDL_SRCALPHA|SDL_RLEACCEL, 128) < 0)
305  {
306  do_SDL_error( "SDL_SetAlpha", __FILE__, __LINE__);
307  }
308  }
309 
310  if( just_lightmap != 0 && lightmap)
311  SDL_FreeSurface( lightmap);
312 
313  lightmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size,
315  mapsurface->format->BitsPerPixel,
316  mapsurface->format->Rmask,
317  mapsurface->format->Gmask,
318  mapsurface->format->Bmask,
319  mapsurface->format->Amask);
320  if( lightmap == NULL)
321  {
322  do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__);
323  }
324 
326  {
327  /* Convert surface to have a full alpha channel if we are doing
328  * per-pixel lighting */
329  lightmap= SDL_DisplayFormatAlpha( lightmap);
330  if( lightmap == NULL)
331  {
332  do_SDL_error( "DisplayFormatAlpha", __FILE__, __LINE__);
333  }
334  }
335 
337  {
338  overlay_grid( TRUE, 0, 0);
339  }
340  /* We make this a bit bigger than the actual map - thus, there
341  * is a 1 space pad in all directions. This enables us
342  * to store a value in that area without having to do checks to
343  * see if we are at the edge of the map - doing a store vs 4
344  * checks is going to be much faster.
345  */
346  redrawbitmap = malloc(sizeof(char) * (MAP_MAX_SIZE +2)* (MAP_MAX_SIZE+2));
347 }
348 
349 
372 void drawquarterlightmap_sdl(int tl, int tr, int bl, int br, /*colors*/
373  int width, int height, /*color square size*/
374  int startx, int starty, int endx, int endy, /*interpolation region*/
375  int destx, int desty){ /*where in lightmap to save result*/
376  int x,y;
377  int top,bottom,val;
378  for (x=startx;x<endx;x++){
379  top= ((x*(tr-tl))/ width)+tl; /*linear interpolation for top color*/
380  bottom= ((x*(br-bl))/ width)+bl; /*linear interpolation for bottom color*/
381  for (y=starty;y<endy;y++){
382  val=((y*(bottom-top))/height)+top; /*linear interpolation between top and bottom*/
383  if (val>255)
384  val=255;
385  if (val<0)
386  val=0;
387  /*printf("writing pel at %d,%d\n",destx+x,desty+y);*/
388  putpixel(lightmap, destx+x-startx, desty+y-starty,
389  SDL_MapRGBA(lightmap->format, 0, 0, 0, val));
390  }
391  }
392 }
393 
394 
395 /* See note below about ALPHA_FUDGE - used to adjust lighting effects some */
396 
397 #define ALPHA_FUDGE(x) (2*(x) / 3)
398 #define GENDARK(x,y) ( (((x)&(y) & 1) == 1)?255:0 )
399 
432 static void do_sdl_per_pixel_lighting(int x, int y, int mx, int my)
433 {
434 
435  int dark0, dark1, dark2, dark3, dark4;
436  SDL_Rect dst;
437 
438  /* I use dark0 -> dark4 in the order to keep it similar to
439  * the old code.
440  */
441  dark0 = the_map.cells[mx][my].darkness;
442 
443  if (y-1 < 0 || !the_map.cells[mx][my-1].have_darkness) dark1 = dark0;
444  else dark1 = the_map.cells[mx][my-1].darkness;
445 
446  if (x+1 >= use_config[CONFIG_MAPWIDTH] || !the_map.cells[mx+1][my].have_darkness) dark2 = dark0;
447  else dark2 = the_map.cells[mx+1][my].darkness;
448 
449  if (y+1 >= use_config[CONFIG_MAPHEIGHT] || !the_map.cells[mx][my+1].have_darkness) dark3 = dark0;
450  else dark3 = the_map.cells[mx][my+1].darkness;
451 
452  if (x-1 < 0 || !the_map.cells[mx-1][my].have_darkness) dark4 = dark0;
453  else dark4 = the_map.cells[mx-1][my].darkness;
454 
455  /* If they are all the same, processing is easy
456  *
457  * Note, the best lightining algorithm also uses diagonals
458  * so we should check the diagonals are same too
459  * We don't check for now, simply do all raw computation on best mode
460  * Tchize 19 may 2004
461  */
462  if (dark0 == dark1 && dark0 == dark2 && dark0 == dark3 && dark0 == dark4 && (use_config[CONFIG_LIGHTING] != CFG_LT_PIXEL_BEST)) {
463  dst.x = x * map_image_size;
464  dst.y = y * map_image_size;
465  dst.w = map_image_size;
466  dst.h = map_image_size;
467 
468  if (dark0 == 255) {
469  SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
470  } else if (the_map.cells[mx][my].darkness != 0) {
471  SDL_FillRect(lightmap,NULL, SDL_MapRGBA(lightmap->format, 0, 0, 0, the_map.cells[mx][my].darkness));
472  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
473  }
474  return;
475  }
476 
477 
479  /* This almost works as well as the per pixel code below, but does have some various
480  * artifacts in the drawing. It uses the same logic as the per pixel code below,
481  * bit since SDL does the blit, the alpha handling ends up being different
482  * (I think it ends up being additive). This results in the darkness being
483  * darker, but you also don't get the smooth effects. If you divide all the values
484  * by 2 (change ALPHA_FUDGE), the blending is smooth, but now the things are not dark
485  * enough, so the blending aganst solid black spaces does not look good.
486  * The reason this code is of interest is that on my system, it is about 50%
487  * faster than the code below (25 ms to darkness the church in the starting
488  * town vs 50 ms for the code further down)
489  * Setting ALPHA_FUDGE to 2/3 seems to reduce the artifacts described above
490  * to fairly minimal levels, while still keeping things dark enough.
491  * MSW 2001-10-12
492  */
493 
494  int i;
495 
496  if (dark1 == dark0) {
497  /* If we don't have usable darkness at the top, then this entire region
498  * should be the same value. Likewise, if the top value and center value
499  * are the same, we can do the entire region.
500  */
501  dst.x=0;
502  dst.y=0;
503  dst.w = map_image_size;
504  dst.h = map_image_half_size;
505  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
506  }
507  else for (i=0; i<map_image_half_size; i++) {
508  /* Need to do it line by line */
509 
510  dst.x = 0;
511  dst.y = i;
512  dst.w = map_image_size;
513  dst.h = 1;
514  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
515  ALPHA_FUDGE((map_image_half_size - i) * dark1 + i * dark0)/map_image_half_size));
516 
517  }
518  /* All the following blocks are basically the same as above, just different
519  * darkness areas.
520  */
521  if (dark3 == dark0) {
522  dst.x=0;
523  dst.y=map_image_half_size;
524  dst.w = map_image_size;
525  dst.h = map_image_half_size;
526  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
527  }
528  else for (i=map_image_half_size; i<map_image_size; i++) {
529  /* Need to do it line by line */
530 
531  dst.x = 0;
532  dst.y = i;
533  dst.w = map_image_size;
534  dst.h = 1;
535  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
536  ALPHA_FUDGE(dark0*(map_image_size-i) + dark3*(i-map_image_half_size)) / map_image_half_size));
537  }
538  /* Blit this to the screen now. Otherwise, we need to look at the alpha values
539  * and re-average.
540  */
541 
542  dst.x= x * map_image_size;
543  dst.y= y * map_image_size;
544  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
545 
546  if (dark4 == dark0) {
547  dst.x=0;
548  dst.y=0;
549  dst.w = map_image_half_size;
550  dst.h = map_image_size;
551  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
552  }
553  else for (i=0; i<map_image_half_size; i++) {
554  /* Need to do it line by line */
555  dst.x = i;
556  dst.y = 0;
557  dst.w = 1;
558  dst.h = map_image_size;
559  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
560  ALPHA_FUDGE(dark4*(map_image_half_size-i) + dark0*i) / map_image_half_size));
561  }
562  if (dark2 == dark0) {
563  dst.x=map_image_half_size;
564  dst.y=0;
565  dst.w = map_image_half_size;
566  dst.h = map_image_size;
567  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
568  }
569  else for (i=map_image_half_size; i<map_image_size; i++) {
570  /* Need to do it line by line */
571 
572  dst.x = i;
573  dst.y = 0;
574  dst.w = 1;
575  dst.h = map_image_size;
576  SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
577  ALPHA_FUDGE(dark0*(map_image_size-i) + dark2*(i-map_image_half_size)) / map_image_half_size));
578  }
579  dst.x= x * map_image_size;
580  dst.y= y * map_image_size;
581  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
582  } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST ) {
583 #if 0
584  int dx,dy;
585  static int *darkx=NULL, *darky=NULL,darkx_allocated=0;
586 
587  /* Generated stored for the darkx[] array. Do it dynamically, but
588  * only allocate if the size needs to be expanded to keep performance
589  * better. darkx could be null in the initial case, but realloc should
590  * just treat that as a malloc (so according to the man page)
591  */
592  if (map_image_size > darkx_allocated) {
593  darkx = realloc(darkx, map_image_size * sizeof(int));
594  darky = realloc(darky, map_image_size * sizeof(int));
595  darkx_allocated = map_image_size;
596  }
597 
598  for( dx= 0; dx < map_image_half_size; dx++)
599  darkx[dx]= (dark4*(map_image_half_size-dx) + dark0*dx) / map_image_half_size;
600  for( dx= map_image_half_size; dx < map_image_size; dx++)
601  darkx[dx] = (dark0*(map_image_size-dx) + dark2*(dx-map_image_half_size)) / map_image_half_size;
602 
603  for( dy= 0; dy < map_image_half_size; dy++)
604  darky[dy]= (dark1*(map_image_half_size-dy) + dark0*dy) / map_image_half_size;
605  for( dy= map_image_half_size; dy < map_image_size; dy++)
606  darky[dy] = (dark0*(map_image_size-dy) + dark3*(dy-map_image_half_size)) / map_image_half_size;
607 
608  SDL_LockSurface( lightmap);
609 
610  for (dx=0; dx<map_image_size; dx++)
611  for (dy=0; dy<map_image_size; dy++)
612  putpixel(lightmap, dx, dy, SDL_MapRGBA(lightmap->format, 0, 0, 0,(darkx[dx] + darky[dy])/2));
613 #else
614  /*we need additionnal surrounding infos*/
615  int dark5, dark6, dark7, dark8;
616  if ( (y-1 < 0) || (x+1 >= use_config[CONFIG_MAPWIDTH])
617  || !the_map.cells[mx+1][my-1].have_darkness) dark5 = (dark1+dark2)>>1; /*(fast div 2)*/
618  else dark5 = the_map.cells[mx+1][my-1].darkness;
619 
620  if ( (x+1 >= use_config[CONFIG_MAPWIDTH])
621  || (y+1 >= use_config[CONFIG_MAPHEIGHT])
622  || !the_map.cells[mx+1][my+1].have_darkness) dark6 = (dark2+dark3)>>1;
623  else dark6 = the_map.cells[mx+1][my+1].darkness;
624 
625  if ( (y+1 >= use_config[CONFIG_MAPHEIGHT]) || (x-1 < 0)
626  || !the_map.cells[mx-1][my+1].have_darkness) dark7 = (dark3+dark4)>>1;
627  else dark7 = the_map.cells[mx-1][my+1].darkness;
628 
629  if ( (x-1 < 0) || (y-1 < 0)
630  || !the_map.cells[mx-1][my-1].have_darkness) dark8 = (dark4+dark1)>>1;
631  else dark8 = the_map.cells[mx-1][my-1].darkness;
632  /*upper left lightmap quarter*/
633  drawquarterlightmap_sdl(dark8, dark1, dark4, dark0, /*colors*/
634  map_image_size, map_image_size, /*color square size*/
635  map_image_half_size, map_image_half_size, map_image_size, map_image_size, /*interpolation region*/
636  0, 0); /*where in lightmap to save result*/
637  /*upper right lightmap quarter*/
638  drawquarterlightmap_sdl(dark1, dark5, dark0, dark2, /*colors*/
639  map_image_size, map_image_size, /*color square size*/
640  0, map_image_half_size, map_image_half_size, map_image_size, /*interpolation region*/
641  map_image_half_size, 0); /*where in lightmap to save result*/
642  /*bottom left lightmap quarter*/
643  drawquarterlightmap_sdl(dark4, dark0, dark7, dark3, /*colors*/
644  map_image_size, map_image_size, /*color square size*/
645  map_image_half_size, 0, map_image_size, map_image_half_size, /*interpolation region*/
646  0, map_image_half_size); /*where in lightmap to save result*/
647  /*bottom right lightmap quarter*/
648  drawquarterlightmap_sdl(dark0, dark2, dark3, dark6, /*colors*/
649  map_image_size, map_image_size, /*color square size*/
650  0, 0, map_image_half_size, map_image_half_size, /*interpolation region*/
651  map_image_half_size, map_image_half_size); /*where in lightmap to save result*/
652 #endif
653  dst.w= map_image_size;
654  dst.h= map_image_size;
655  dst.x= x * map_image_size;
656  dst.y= y * map_image_size;
657  SDL_UnlockSurface(lightmap);
658  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
659  }
660 }
661 
674 static void drawsmooth_sdl (int mx,int my,int layer,SDL_Rect dst){
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,lowest,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 |= the_map.cells[mx][my].heads[i].face;
699  if (!hasFace
700  || !CAN_SMOOTH(the_map.cells[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 ( (emx<0) || (emy<0) || (the_map.x<=emx) || (the_map.y<=emy)){
711  slevels[i]=0;
712  sfaces[i]=0; /*black picture*/
713  }
714  else if (the_map.cells[emx][emy].smooth[layer]<=the_map.cells[mx][my].smooth[layer]){
715  slevels[i]=0;
716  sfaces[i]=0; /*black picture*/
717  }else{
718  slevels[i]=the_map.cells[emx][emy].smooth[layer];
719  sfaces[i]=pixmaps[the_map.cells[emx][emy].heads[layer].face]->smooth_face;
720  }
721  }
722  /* ok, now we have a list of smoothlevel higher than current square.
723  * there are at most 8 different levels. so... let's check 8 times
724  * for the lowest one (we draw from botto to top!).
725  */
726  lowest=-1;
727  while (1){
728  lowest = -1;
729  for (i=0;i<8;i++){
730  if ( (slevels[i]>0) && (!partdone[i]) &&
731  ((lowest<0) || (slevels[i]<slevels[lowest]))
732  )
733  lowest=i;
734  }
735  if (lowest<0)
736  break; /*no more smooth to do on this square*/
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  smoothface=sfaces[lowest];
765  if (smoothface<=0){
766  continue; /*picture for smoothing not yet available*/
767  }
768  /* now, it's quite easy. We must draw using a 32x32 part of
769  * the picture smoothface.
770  * This part is located using the 2 weights calculated:
771  * (32*weight,0) and (32*weightC,32)
772  */
773  if ( (!pixmaps[smoothface]->map_image) ||
774  (pixmaps[smoothface] == pixmaps[0]))
775  continue; /*don't have the picture associated*/
776  if (weight>0){
777  src.x=map_image_size*weight;
778  src.y=0;
779  if (the_map.cells[mx][my].cleared) {
780  if (SDL_BlitSurface(pixmaps[smoothface]->fog_image,
781  &src, mapsurface, &dst))
782  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
783  } else {
784  if (SDL_BlitSurface(pixmaps[smoothface]->map_image,
785  &src, mapsurface, &dst))
786  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
787  }
788  }
789  if (weightC>0){
790  src.x=map_image_size*weightC;
791  src.y=map_image_size;
792  if (the_map.cells[mx][my].cleared) {
793  if (SDL_BlitSurface(pixmaps[smoothface]->fog_image,
794  &src, mapsurface, &dst))
795  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
796  } else {
797  if (SDL_BlitSurface(pixmaps[smoothface]->map_image,
798  &src, mapsurface, &dst))
799  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
800  }
801  }
802  }/*while there's some smooth to do*/
803 }
804 
815 static void update_redrawbitmap(void)
816 {
817  int mx,my, x,y;
818 
819  memset(redrawbitmap, 0, (use_config[CONFIG_MAPWIDTH]+2) * (use_config[CONFIG_MAPHEIGHT]+2));
820 
821  for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) {
822  for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) {
823  mx = x + pl_pos.x;
824  my = y + pl_pos.y;
825 
826  /* Basically, we need to check the conditions that require this space.
827  * to be redrawn. We store this in redrawbitmap, because storing
828  * in the_map[][].need_update would cause a cascade effect, of space
829  * 1,0 need an update, so we thing 2,0 needs an update due to smoothing/
830  * like, which causes 3,0 to be updated, etc. Having our own
831  * memory area allows the memset above, which is an optimized routine
832  * to clear memory.
833  */
834  if (the_map.cells[mx][my].need_update) {
835  redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
836  /* If this space has changed, and using non tile lighting,
837  * we need to update the neighbor spaces. Ideally, we'd
838  * have a flag just to denote lighting changes, since
839  * that is handled on a different surface anyways.
840  */
841  if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL ||
842  use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) {
843  /* This is where having redrawbitmap bigger pays off - don't have
844  * to check to see if values are within redrawbitmap is within bounds
845  */
846  redrawbitmap[x + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
847  redrawbitmap[x + 2 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
848  redrawbitmap[x + 1 + (y) * use_config[CONFIG_MAPWIDTH]] = 1;
849  redrawbitmap[x + 1 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1;
850  }
851  /* In best mode, have to update diaganols in addition*/
852  if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) {
853  redrawbitmap[x + (y) * use_config[CONFIG_MAPWIDTH]] = 1;
854  redrawbitmap[x + 2 + (y) * use_config[CONFIG_MAPWIDTH]] = 1;
855  redrawbitmap[x + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1;
856  redrawbitmap[x + 2 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1;
857  }
858  }
859  else if (the_map.cells[mx][my].need_resmooth) {
860  redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
861  }
862  }
863  }
864 }
865 
873 static void display_mapcell(int ax, int ay, int mx, int my)
874 {
875  SDL_Rect dst, src;
876  int layer;
877 
878  /* First, we need to black out this space. */
879  dst.x = ax*map_image_size;
880  dst.y = ay*map_image_size;
881  dst.w = map_image_size;
882  dst.h = map_image_size;
883  SDL_FillRect(mapsurface, &dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
884 
885  /* now draw the different layers. Only draw if using fog of war or the
886  * space isn't clear.
887  */
888  if (use_config[CONFIG_FOGWAR] || !the_map.cells[mx][my].cleared) {
889  for (layer=0; layer<MAXLAYERS; layer++) {
890  int sx, sy;
891 
892  /* draw single-tile faces first */
893  int face = mapdata_face(ax, ay, layer);
894  if (face > 0 && pixmaps[face]->map_image != NULL) {
895  int w = pixmaps[face]->map_width;
896  int h = pixmaps[face]->map_height;
897  /* add one to the size values to take into account the actual width of the space */
898  src.x = w-map_image_size;
899  src.y = h-map_image_size;
900  src.w = map_image_size;
901  src.h = map_image_size;
902  dst.x = ax*map_image_size;
903  dst.y = ay*map_image_size;
904  if (the_map.cells[mx][my].cleared) {
905  if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst))
906  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
907  } else {
908  if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst))
909  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
910  }
911 
912  }
913  /* Sometimes, it may happens we need to draw the smooth while there
914  * is nothing to draw at that layer (but there was something at lower
915  * layers). This is handled here. The else part is to take into account
916  * cases where the smooth as already been handled 2 code lines before
917  */
918  if (use_config[CONFIG_SMOOTH])
919  drawsmooth_sdl (mx,my,layer,dst);
920 
921  /* draw big faces last (should overlap other objects) */
922  face = mapdata_bigface(ax, ay, layer, &sx, &sy);
923  if (face > 0 && pixmaps[face]->map_image != NULL) {
924  /* We have to handle images that are not an equal
925  * multiplier of map_image_size. See
926  * display_mapcell() in gtk-v2/src/map.c for
927  * more details on this logic, since it is basically
928  * the same.
929  */
930  int dx, dy, sourcex, sourcey, offx, offy;
931 
932  dx = pixmaps[face]->map_width % map_image_size;
933  offx = dx?(map_image_size -dx):0;
934 
935  if (sx) {
936  sourcex = sx * map_image_size - offx ;
937  offx=0;
938  } else {
939  sourcex=0;
940  }
941 
942  dy = pixmaps[face]->map_height % map_image_size;
943  offy = dy?(map_image_size -dy):0;
944 
945  if (sy) {
946  sourcey = sy * map_image_size - offy;
947  offy=0;
948  } else {
949  sourcey=0;
950  }
951 
952  src.x = sourcex;
953  src.y = sourcey;
954  src.w = map_image_size - offx;
955  src.h = map_image_size - offy;
956  dst.x = ax*map_image_size + offx;
957  dst.y = ay*map_image_size + offy;
958  if (the_map.cells[mx][my].cleared) {
959  if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst))
960  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
961  } else {
962  if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst))
963  do_SDL_error( "BlitSurface", __FILE__, __LINE__);
964  }
965  } /* else for processing the layers */
966  }
967  }
968 
969  if (use_config[CONFIG_LIGHTING] == CFG_LT_TILE) {
970  dst.x = ax*map_image_size;
971  dst.y = ay*map_image_size;
972  dst.w = map_image_size;
973  dst.h = map_image_size;
974 
975  /* Note - Instead of using a lightmap, I just fillrect
976  * directly onto the map surface - I would think this should be
977  * faster
978  */
979  if (the_map.cells[mx][my].darkness == 255) {
980  SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
981  } else if (the_map.cells[mx][my].darkness != 0) {
982  SDL_SetAlpha(lightmap, SDL_SRCALPHA|SDL_RLEACCEL, the_map.cells[mx][my].darkness);
983  SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
984  }
985  } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL || use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) {
986  do_sdl_per_pixel_lighting(ax, ay, mx, my);
987  }
988 }
989 
1014 void sdl_gen_map(int redraw) {
1015  int x, y, num_spaces=0, num_drawn=0;
1016  struct timeval tv1, tv2, tv3;
1017  long elapsed1, elapsed2;
1018 
1019  if (time_map_redraw)
1020  gettimeofday(&tv1, NULL);
1021 
1022  update_redrawbitmap();
1023 
1024  for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) {
1025  for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) {
1026  num_spaces++;
1027 
1028  /* This will be updated in the for loop above for
1029  * whatever conditions that need this space to be redrawn
1030  */
1031  if (redraw || redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]]) {
1032  num_drawn++;
1033  display_mapcell(x, y, pl_pos.x+x, pl_pos.y+y);
1034  the_map.cells[pl_pos.x+x][pl_pos.y+y].need_update = 0;
1036  }
1037  }
1038  }
1039 
1040  if (time_map_redraw)
1041  gettimeofday(&tv2, NULL);
1042 
1043  SDL_Flip(mapsurface);
1044 
1045  if (time_map_redraw) {
1046  gettimeofday(&tv3, NULL);
1047  elapsed1 = (tv2.tv_sec - tv1.tv_sec)*1000000 + (tv2.tv_usec - tv1.tv_usec);
1048  elapsed2 = (tv3.tv_sec - tv2.tv_sec)*1000000 + (tv3.tv_usec - tv2.tv_usec);
1049 
1050  /* I care about performance for 'long' updates, so put the check in to make
1051  * these a little more noticable */
1052  if ((elapsed1 + elapsed2)>10000)
1053  LOG(LOG_INFO,"gtk::sdl_gen_map","gen took %7ld, flip took %7ld, total = %7ld",
1054  elapsed1, elapsed2, elapsed1 + elapsed2);
1055  }
1056 } /* sdl_gen_map function */
1057 
1063 int sdl_mapscroll(int dx, int dy)
1064 {
1065  /* Don't sdl_gen_map should take care of the redraw */
1066 
1067  /* a copy of what pngximage does except sdl specfic
1068  * mapsurface->pitch is the length of a scanline in bytes
1069  * including alignment padding
1070  */
1071  SDL_LockSurface( mapsurface);
1072  if( dy < 0) {
1073  int offset= mapsurface->pitch * (-dy*map_image_size);
1074  memmove( mapsurface->pixels + offset, mapsurface->pixels,
1075  mapsurface->pitch * (mapsurface->h + dy*map_image_size) );
1076  }
1077  else if( dy > 0) {
1078  int offset= mapsurface->pitch * (dy*map_image_size);
1079  memmove( mapsurface->pixels, mapsurface->pixels + offset,
1080  mapsurface->pitch * (mapsurface->h - dy*map_image_size) );
1081  }
1082 
1083  if (dx) {
1084  int y;
1085  for( y= 0; y < mapsurface->h; y++) {
1086  if( dx < 0) {
1087  char* start_of_row= mapsurface->pixels + mapsurface->pitch * y;
1088  int offset= ( mapsurface->format->BytesPerPixel * map_image_size * -dx);
1089  memmove( start_of_row + offset, start_of_row,
1090  mapsurface->pitch - offset);
1091  }
1092  else {
1093  char* start_of_row= mapsurface->pixels + mapsurface->pitch * y;
1094  int offset= ( mapsurface->format->BytesPerPixel * map_image_size * dx);
1095  memmove( start_of_row, start_of_row + offset,
1096  mapsurface->pitch - offset);
1097  }
1098  }
1099  }
1100  SDL_UnlockSurface( mapsurface);
1101 
1102  return 1;
1103 }
1104 
1105 #endif
#define CAN_SMOOTH(__SQUARE, __LEVEL)
Definition: client.h:85
static int height
Definition: mapdata.c:104
int y
Definition: mapdata.h:93
void init_SDL(GtkWidget *sdl_window, int just_lightmap)
#define MAP_MAX_SIZE
Definition: client.h:447
int map_image_half_size
Definition: gx11.c:117
#define CONFIG_FOGWAR
Definition: client.h:157
uint16 map_height
Definition: gx11.h:64
#define CFG_LT_PIXEL_BEST
Definition: client.h:189
uint8 have_darkness
Definition: mapdata.h:82
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: gx11.c:118
uint8 need_update
Definition: mapdata.h:81
sint16 face
Definition: mapdata.h:45
static int width
Definition: mapdata.c:104
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:178
#define TRUE
Definition: client-types.h:71
int map_image_size
Definition: gx11.c:117
int sdl_mapscroll(int dx, int dy)
const char *const rcsid_gtk_sdl_c
Definition: sdl.c:1
static void display_mapcell(int ax, int ay, int mx, int my)
Definition: map.c:219
sint16 use_config[CONFIG_NUMS]
Definition: init.c:50
sint16 mapdata_face(int x, int y, int layer)
Definition: mapdata.c:955
#define CFG_LT_TILE
Definition: client.h:187
uint8 darkness
Definition: mapdata.h:80
#define CFG_LT_PIXEL
Definition: client.h:188
uint8 cleared
Definition: mapdata.h:84
struct Map the_map
Definition: mapdata.c:121
struct MapCell ** cells
Definition: mapdata.h:95
int x
Definition: mapdata.h:92
#define CONFIG_SMOOTH
Definition: client.h:177
void drawquarterlightmap_sdl(int tl, int tr, int bl, int br, int width, int height, int startx, int starty, int endx, int endy, int destx, int desty)
uint8 need_resmooth
Definition: mapdata.h:83
GdkBitmap * dark2
Definition: gx11.c:249
GdkBitmap * dark3
Definition: gx11.c:249
#define MAXLAYERS
Definition: mapdata.h:32
#define CONFIG_MAPWIDTH
Definition: client.h:170
#define CONFIG_SHOWGRID
Definition: client.h:167
GdkBitmap * dark1
Definition: gx11.c:249
uint16 smooth[MAXLAYERS]
Definition: mapdata.h:79
#define CONFIG_MAPHEIGHT
Definition: client.h:171
sint16 mapdata_bigface(int x, int y, int layer, int *ww, int *hh)
Definition: mapdata.c:966
uint16 smooth_face
Definition: gx11.h:66
struct MapCellLayer heads[MAXLAYERS]
Definition: mapdata.h:77
#define CONFIG_LIGHTING
Definition: client.h:168
uint8 time_map_redraw
Definition: gx11.c:203
void sdl_gen_map(int redraw)
PlayerPosition pl_pos
Definition: map.c:69
uint16 map_width
Definition: gx11.h:64