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