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 
14 /**
15  * @file
16  * Functions that implement SDL support in the GTK V2 client.
17  */
18 
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; /**< Actual SDL surface the game view is painted on */
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 
do_SDL_error(const char * SDL_function,const char * file,int line)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 
59 /**
60  * Set the pixel at (x, y) to the given value
61  * NOTE: The surface must be locked before calling this!
62  * This function is directly grabbed from the SDL docs.
63  * Note this is not currently used, but is useful enough
64  * that it should be included.
65  */
putpixel(SDL_Surface * surface,int x,int y,Uint32 pixel)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 
99 /**
100  *
101  * @param re_init
102  * @param ax
103  * @param ay
104  */
overlay_grid(int re_init,int ax,int ay)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,
133                                             use_config[CONFIG_MAPWIDTH]*map_image_size * use_config[CONFIG_MAPSCALE] / 100,
134                                             use_config[CONFIG_MAPHEIGHT]*map_image_size * use_config[CONFIG_MAPSCALE] / 100,
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 ) ||
167                          y == use_config[CONFIG_MAPHEIGHT]*map_image_size * use_config[CONFIG_MAPSCALE] / 100 -1 ||
168                          x == use_config[CONFIG_MAPWIDTH]*map_image_size * use_config[CONFIG_MAPSCALE] / 100 -1 ) {
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;
183         dst.w= map_image_size*use_config[CONFIG_MAPWIDTH] * use_config[CONFIG_MAPSCALE] / 100;
184         dst.h= map_image_size*use_config[CONFIG_MAPHEIGHT] * use_config[CONFIG_MAPSCALE] / 100;
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 
200 /**
201  * Takes two args, the first is the GtkWindow to draw on, this should always
202  * be 'drawingarea'. The second is a boolean, if 0 then the whole
203  * SDL system in initialized or reinited if already run once before,
204  * if non zero then only the lightmap is rebuilt, if we switch between
205  * per-pixel or per-tile lighting
206  *
207  * @param sdl_window
208  * @param just_lightmap
209  */
init_SDL(GtkWidget * sdl_window,int just_lightmap)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,
246                                       map_image_size*use_config[CONFIG_MAPHEIGHT]*use_config[CONFIG_MAPSCALE] / 100, 0,
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,
258                                       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,
283                                     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 
293     if(use_config[CONFIG_LIGHTING] != CFG_LT_TILE) {
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 
315 /**
316  * Draw a alpha square on lightmap. Values for topleft, topright,
317  * bottomleft,bottomright corners are knowns This use bilinear interpolation
318  * for other points. Width and heights are given for surrounding known values
319  * square. Interpolation is done in a small square whose coordinates are
320  * given by start{x|y} and end{x|y}
321  *                             Tchize 22 May 2004
322  *
323  * Note - profile shows this is a very costly function - of a small run,
324  * 77% of the time of the cpu time for the client was in this function.
325  *
326  * @param tl     color
327  * @param tr     color
328  * @param bl     color
329  * @param br     color
330  * @param width  color square size
331  * @param height color square size
332  * @param startx Top left corner of the interpolation region.
333  * @param starty Top left corner of the interpolation region.
334  * @param endx   Bottom right corner of the interpolation region.
335  * @param endy   Bottom right corner of the interpolation region.
336  * @param destx  Coordinate of top left corner in destination map, or where in
337  *               the lightmap to save the result.
338  * @param desty  Coordinate of top left corner in destination map, or where in
339  *               the lightmap to save the result.
340  */
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)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 
372 /**
373  * Do the lighting on a per pixel basis.
374  * x and y are coordinates on the drawable map surfaces (but in terms of
375  * spaces, not pixels).  mx and my are indexes into the
376  * the_map.cells[][] array.
377  * All the below goes out and figures lighting for each pixel on
378  * the space, and creates a surface (with alpha) that is then put on
379  * top of the exiting map space.
380  *
381  * TODO: I think it is possible to greatly speed this up by using
382  * pre-generated darkness masks.  Doing all the possibilities
383  * would be 3125 images (5 positions, each with 5 values, 5^5),
384  * Doing it based on quadrants would only reduce that to 1024.
385  * But I _think_ it may be possible to do this with just 64 images
386  * (2^5 + one 90 degree rotation of the same) based on quadrants.
387  * ie, do a 16x16 image with the 5 gradiants (0,64,128,255 at the
388  * left, and each of those values at the right).  Then do the same
389  * idea for top and bottom.  For any single quadrant, you would
390  * then merge thse two values (which can be done with a fast blit),
391  * corresponding to the right values, and you do the same thing for
392  * the other four quadrants.  Note this only works so long as
393  * 4 lighting values are used - if more are added, this quickly
394  * breaks.  Also, if lighting colored effects are desired,
395  * this also doesn't work very well.
396  *
397  * For now, I've just kept the old logic. MSW 2001-10-09
398  *
399  * @param x
400  * @param y
401  * @param mx
402  * @param my
403  */
do_sdl_per_pixel_lighting(int x,int y,int mx,int my)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 
462     if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL ) {
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;
488             dst.h = map_image_half_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;
506             dst.y=map_image_half_size * use_config[CONFIG_MAPSCALE] / 100;
507             dst.w = map_image_size * use_config[CONFIG_MAPSCALE] / 100;
508             dst.h = map_image_half_size * use_config[CONFIG_MAPSCALE] / 100;
509             SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
510         } else for (i=map_image_half_size * use_config[CONFIG_MAPSCALE] / 100; i<map_image_size * use_config[CONFIG_MAPSCALE] / 100; i++) {
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))
520                                 / (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;
533             dst.w = map_image_half_size * use_config[CONFIG_MAPSCALE] / 100;
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) {
546             dst.x=map_image_half_size * use_config[CONFIG_MAPSCALE] / 100;
547             dst.y=0;
548             dst.w = map_image_half_size * use_config[CONFIG_MAPSCALE] / 100;
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)));
551         } else for (i=map_image_half_size * use_config[CONFIG_MAPSCALE] / 100; i<map_image_size * use_config[CONFIG_MAPSCALE] / 100; 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 * use_config[CONFIG_MAPSCALE] / 100;
558                 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
559                              ALPHA_FUDGE(dark0*(map_image_size* use_config[CONFIG_MAPSCALE] / 100-i) + dark2*(i-map_image_half_size* use_config[CONFIG_MAPSCALE] / 100)) / (map_image_half_size * use_config[CONFIG_MAPSCALE] / 100)));
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         }
583         for( dx= map_image_half_size* use_config[CONFIG_MAPSCALE] / 100; dx < map_image_size * use_config[CONFIG_MAPSCALE] / 100; dx++) {
584             darkx[dx] = (dark0*(map_image_size* use_config[CONFIG_MAPSCALE] / 100-dx) + dark2*(dx-map_image_half_size* use_config[CONFIG_MAPSCALE] / 100)) / (map_image_half_size* use_config[CONFIG_MAPSCALE] / 100);
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         }
590         for( dy= map_image_half_size * use_config[CONFIG_MAPSCALE] / 100; dy < map_image_size * use_config[CONFIG_MAPSCALE] / 100; dy++) {
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*/
634                                 map_image_half_size * use_config[CONFIG_MAPSCALE] / 100, map_image_half_size * use_config[CONFIG_MAPSCALE] / 100, map_image_size * use_config[CONFIG_MAPSCALE] / 100, map_image_size * use_config[CONFIG_MAPSCALE] / 100,    /*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 * use_config[CONFIG_MAPSCALE] / 100, map_image_size * use_config[CONFIG_MAPSCALE] / 100,               /*color square size*/
639                                 0, map_image_half_size * use_config[CONFIG_MAPSCALE] / 100, map_image_half_size * use_config[CONFIG_MAPSCALE] / 100, map_image_size * use_config[CONFIG_MAPSCALE] / 100,    /*interpolation region*/
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*/
644                                 map_image_half_size * use_config[CONFIG_MAPSCALE] / 100, 0, map_image_size * use_config[CONFIG_MAPSCALE] / 100, map_image_half_size * use_config[CONFIG_MAPSCALE] / 100,    /*interpolation region*/
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 
661 /**
662  * Draw anything in adjacent squares that could smooth on given square
663  * mx,my square to smooth on. you should not call this function to
664  * smooth on a 'completly black' square. (simply for visual result)
665  * layer layer to examine (we smooth only one layer at a time)
666  * dst place on the mapwindow to draw
667  *
668  * @param mx
669  * @param my
670  * @param layer
671  * @param dst
672  */
drawsmooth_sdl(int mx,int my,int layer,SDL_Rect dst)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;
795             src.y=map_image_size* 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 
811 /**
812  * Replacment of sdl_square_need_redraw logic.  use of sdl_square_need_redraw
813  * is relatively inefficient becuase it is called for every space (hence
814  * function call overhead), but also has 4 checks to make sure the neighbor
815  * space is within valid range, and if non tile mode, performs that check at
816  * least 4 times per space.
817  * This is much more efficient, because our redrawbitmap array is large enough
818  * we don't need those checks - we know we are always safe to go one outside
819  * the bounds (hence, the +1 in the coordinate values)
820  */
update_redrawbitmap(void)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 
871 /**
872  *
873  * @param ax
874  * @param ay
875  * @param mx
876  * @param my
877  */
display_mapcell(int ax,int ay,int mx,int my)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 
979     if (use_config[CONFIG_LIGHTING] == CFG_LT_TILE) {
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         }
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 
1000 /**
1001  * Generates a map in SDL mode.
1002  *
1003  * I had to totally change the logic on how we do this in SDL mode - to support
1004  * variable sized images, the old method of generating each space does not
1005  * work, as one space may spill over to the other.  Instead, we first blit the
1006  * bottom layer, then the layer above that, and so on.  This results in the map
1007  * being drawn a bit more correctly.  In fact, that logic actually isn't
1008  * needed, as with the new map commands, we know the offset and size of the
1009  * images.
1010  *
1011  * The logic here only redraws spaces that change.  The logic in the
1012  * common/commands.c files the odd layers with links for 'big images'.  For
1013  * objects on these layers, we look at the size_x and size_y values to
1014  * determine the offset from which we should be blitting.
1015  *
1016  * Old notes, but left in:
1017  * The performance here is very good in most cases - about 30 ms (on my system)
1018  * is used just for my flip at the bottom of the function, drawing only what is
1019  * needed generally saves a lot of time (<15 ms in most cases) compared to the
1020  * 80-120 ms usually needed on a 15x15 map.
1021  *
1022  * @param redraw
1023  */
sdl_gen_map(int redraw)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;
1042                 mapdata_cell(pl_pos.x+x, pl_pos.y+y)->need_resmooth = 0;
1043             }
1044         }
1045     }
1046 
1047     SDL_Flip(mapsurface);
1048 }
1049 
1050 /**
1051  *
1052  * @param dx
1053  * @param dy
1054  */
sdl_mapscroll(int dx,int dy)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
1101