Crossfire Client, Branch
R11627
|
00001 const char * const rcsid_gtk_sdl_c = 00002 "$Id: sdl.c 9200 2008-06-01 17:12:43Z anmaster $"; 00003 00004 /* 00005 Crossfire client, a client program for the crossfire program. 00006 00007 Copyright (C) 2005 Mark Wedel & Crossfire Development Team 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 2 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program; if not, write to the Free Software 00021 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00022 00023 The author can be reached via e-mail to crossfire@metalforge.org 00024 */ 00025 00031 #include <config.h> 00032 00033 #ifdef HAVE_SDL 00034 00035 #include <client-types.h> 00036 #include <SDL.h> 00037 #include <SDL_image.h> 00038 00039 /* Pick up the gtk headers we need */ 00040 #include <gtk/gtk.h> 00041 #include <glade/glade.h> 00042 #ifndef WIN32 00043 #include <gdk/gdkx.h> 00044 #else 00045 #include <gdk/gdkwin32.h> 00046 #endif 00047 #include <gdk/gdkkeysyms.h> 00048 00049 #include "main.h" 00050 #include "image.h" 00051 #include <client.h> 00052 #include "gtk2proto.h" 00053 #include "mapdata.h" 00054 00055 SDL_Surface* mapsurface; 00056 static SDL_Surface* lightmap; 00057 static SDL_Surface* fogmap; 00058 static char *redrawbitmap; 00059 00060 extern int time_map_redraw; 00061 00062 00063 /* Move some of the SDL code to this file here. This makes it easier to share 00064 * between the gnome and gtk client. It also reduces the length of both the 00065 * gx11.c and gnome.c file. It also is more readable, as not as many #ifdef 00066 * SDL.. #endif constructs are needed. Note that there may still be some SDL 00067 * code in gx11.c - some areas are embedded so much that it is not easy to 00068 * remove. 00069 */ 00070 00071 /* these should generally be included by the file including this file. */ 00072 #include <SDL.h> 00073 #include <SDL_image.h> 00074 00075 00076 static void do_SDL_error(const char *SDL_function, const char *file, int line) 00077 { 00078 LOG(LOG_CRITICAL,SDL_function,"SDL error in file %s line %d\n%s", 00079 file, line, SDL_GetError()); 00080 SDL_Quit(); 00081 exit( 1); 00082 } 00083 00091 static void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) 00092 { 00093 int bpp = surface->format->BytesPerPixel; 00094 /* Here p is the address to the pixel we want to set */ 00095 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; 00096 00097 switch(bpp) { 00098 case 1: 00099 *p = pixel; 00100 break; 00101 00102 case 2: 00103 *(Uint16 *)p = pixel; 00104 break; 00105 00106 case 3: 00107 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { 00108 p[0] = (pixel >> 16) & 0xff; 00109 p[1] = (pixel >> 8) & 0xff; 00110 p[2] = pixel & 0xff; 00111 } else { 00112 p[0] = pixel & 0xff; 00113 p[1] = (pixel >> 8) & 0xff; 00114 p[2] = (pixel >> 16) & 0xff; 00115 } 00116 break; 00117 00118 case 4: 00119 *(Uint32 *)p = pixel; 00120 break; 00121 } 00122 } 00123 00130 static void overlay_grid( int re_init, int ax, int ay) 00131 { 00132 00133 static SDL_Surface* grid_overlay; 00134 00135 static int first_pass; 00136 00137 int x= 0; 00138 int y= 0; 00139 SDL_Rect dst; 00140 Uint32 *pixel; 00141 SDL_PixelFormat* fmt; 00142 00143 /* Need to convert back to screen coordinates */ 00144 ax-= pl_pos.x; 00145 ay-= pl_pos.y; 00146 00147 if( re_init == TRUE) 00148 { 00149 if( grid_overlay) 00150 SDL_FreeSurface( grid_overlay); 00151 00152 first_pass= 0; 00153 grid_overlay= NULL; 00154 } 00155 00156 if( grid_overlay == NULL) 00157 { 00158 grid_overlay= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, 00159 use_config[CONFIG_MAPWIDTH]*map_image_size, 00160 use_config[CONFIG_MAPHEIGHT]*map_image_size, 00161 mapsurface->format->BitsPerPixel, 00162 mapsurface->format->Rmask, 00163 mapsurface->format->Gmask, 00164 mapsurface->format->Bmask, 00165 mapsurface->format->Amask); 00166 if( grid_overlay == NULL) 00167 do_SDL_error( "CreateRGBSurface", __FILE__, __LINE__); 00168 00169 grid_overlay= SDL_DisplayFormatAlpha( grid_overlay); 00170 00171 first_pass= 0; 00172 } 00173 00174 /* 00175 * If this is our first time drawing the grid, we need to build up the 00176 * grid overlay 00177 */ 00178 if( first_pass== 0) 00179 { 00180 00181 /* Red pixels around the edge and along image borders 00182 * fully transparent pixels everywhere else 00183 */ 00184 00185 fmt= grid_overlay->format; 00186 for( x= 0; x < map_image_size*use_config[CONFIG_MAPWIDTH]; x++) 00187 { 00188 for( y= 0; y < map_image_size*use_config[CONFIG_MAPHEIGHT]; y++) 00189 { 00190 /* FIXME: Only works for 32 bit displays right now */ 00191 pixel= (Uint32*)grid_overlay->pixels+y*grid_overlay->pitch/4+x; 00192 00193 if( x == 0 || y == 0 || 00194 ((x % map_image_size) == 0) || ((y % map_image_size) == 0 ) || 00195 y == use_config[CONFIG_MAPHEIGHT]*map_image_size-1 || x == use_config[CONFIG_MAPWIDTH]*map_image_size -1 ) 00196 { 00197 *pixel= SDL_MapRGBA( fmt, 255, 0, 0, SDL_ALPHA_OPAQUE); 00198 } 00199 else 00200 { 00201 *pixel= SDL_MapRGBA( fmt, 0, 0, 0, SDL_ALPHA_TRANSPARENT); 00202 } 00203 } 00204 } 00205 first_pass= 1; 00206 00207 /* 00208 * If this is our first pass then we need to overlay the entire grid 00209 * now. Otherwise we just update the tile we are on 00210 */ 00211 dst.x= 0; 00212 dst.y= 0; 00213 dst.w= map_image_size*use_config[CONFIG_MAPWIDTH]; 00214 dst.h= map_image_size*use_config[CONFIG_MAPHEIGHT]; 00215 SDL_BlitSurface( grid_overlay, NULL, mapsurface, &dst); 00216 } 00217 else 00218 { 00219 dst.x= ax* map_image_size; 00220 dst.y= ay* map_image_size; 00221 dst.w= map_image_size; 00222 dst.h= map_image_size; 00223 /* One to one pixel mapping of grid and mapsurface so we 00224 * can share the SDL_Rect 00225 */ 00226 SDL_BlitSurface( grid_overlay, &dst, mapsurface, &dst); 00227 } 00228 00229 return; 00230 } 00231 00242 void init_SDL( GtkWidget* sdl_window, int just_lightmap) 00243 { 00244 00245 char SDL_windowhack[32]; 00246 00247 if( just_lightmap == 0) { 00248 g_assert( sdl_window != NULL); 00249 if( SDL_WasInit( SDL_INIT_VIDEO) != 0) { 00250 if( lightmap) 00251 SDL_FreeSurface( lightmap); 00252 if( mapsurface) 00253 SDL_FreeSurface( mapsurface); 00254 SDL_Quit(); 00255 } 00256 00257 /* 00258 * SDL hack to tell SDL which xwindow to paint onto 00259 */ 00260 00261 #ifndef WIN32 00262 snprintf(SDL_windowhack, sizeof(SDL_windowhack), "SDL_WINDOWID=%ld", 00263 GDK_WINDOW_XWINDOW(sdl_window->window) ); 00264 #else 00265 sprintf( SDL_windowhack, "SDL_WINDOWID=%ld", 00266 GDK_WINDOW_HWND(sdl_window->window) ); 00267 #endif 00268 putenv( SDL_windowhack); 00269 00270 if( SDL_Init( SDL_INIT_VIDEO) < 0) 00271 { 00272 LOG(LOG_CRITICAL,"gtk::init_SDL", "Could not initialize SDL: %s", SDL_GetError()); 00273 gtk_main_quit(); 00274 } 00275 00276 mapsurface= SDL_SetVideoMode( map_image_size*use_config[CONFIG_MAPWIDTH], map_image_size*use_config[CONFIG_MAPHEIGHT], 0, 00277 SDL_HWSURFACE|SDL_DOUBLEBUF); 00278 00279 if( mapsurface == NULL) 00280 { 00281 do_SDL_error( "SetVideoMode", __FILE__, __LINE__); 00282 } 00283 00284 if( fogmap) 00285 SDL_FreeSurface( fogmap); 00286 00287 fogmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size, 00288 map_image_size, 00289 mapsurface->format->BitsPerPixel, 00290 mapsurface->format->Rmask, 00291 mapsurface->format->Gmask, 00292 mapsurface->format->Bmask, 00293 mapsurface->format->Amask); 00294 00295 if( fogmap == NULL) 00296 { 00297 do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__); 00298 } 00299 00300 /* 00301 * This is a persurface alpha value, not an alpha channel value. 00302 * So this surface doesn't actually need a full alpha channel 00303 */ 00304 if( SDL_SetAlpha( fogmap, SDL_SRCALPHA|SDL_RLEACCEL, 128) < 0) 00305 { 00306 do_SDL_error( "SDL_SetAlpha", __FILE__, __LINE__); 00307 } 00308 } 00309 00310 if( just_lightmap != 0 && lightmap) 00311 SDL_FreeSurface( lightmap); 00312 00313 lightmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size, 00314 map_image_size, 00315 mapsurface->format->BitsPerPixel, 00316 mapsurface->format->Rmask, 00317 mapsurface->format->Gmask, 00318 mapsurface->format->Bmask, 00319 mapsurface->format->Amask); 00320 if( lightmap == NULL) 00321 { 00322 do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__); 00323 } 00324 00325 if(use_config[CONFIG_LIGHTING] != CFG_LT_TILE) 00326 { 00327 /* Convert surface to have a full alpha channel if we are doing 00328 * per-pixel lighting */ 00329 lightmap= SDL_DisplayFormatAlpha( lightmap); 00330 if( lightmap == NULL) 00331 { 00332 do_SDL_error( "DisplayFormatAlpha", __FILE__, __LINE__); 00333 } 00334 } 00335 00336 if(use_config[CONFIG_SHOWGRID] == TRUE) 00337 { 00338 overlay_grid( TRUE, 0, 0); 00339 } 00340 /* We make this a bit bigger than the actual map - thus, there 00341 * is a 1 space pad in all directions. This enables us 00342 * to store a value in that area without having to do checks to 00343 * see if we are at the edge of the map - doing a store vs 4 00344 * checks is going to be much faster. 00345 */ 00346 redrawbitmap = malloc(sizeof(char) * (MAP_MAX_SIZE +2)* (MAP_MAX_SIZE+2)); 00347 } 00348 00349 00372 void drawquarterlightmap_sdl(int tl, int tr, int bl, int br, /*colors*/ 00373 int width, int height, /*color square size*/ 00374 int startx, int starty, int endx, int endy, /*interpolation region*/ 00375 int destx, int desty){ /*where in lightmap to save result*/ 00376 int x,y; 00377 int top,bottom,val; 00378 for (x=startx;x<endx;x++){ 00379 top= ((x*(tr-tl))/ width)+tl; /*linear interpolation for top color*/ 00380 bottom= ((x*(br-bl))/ width)+bl; /*linear interpolation for bottom color*/ 00381 for (y=starty;y<endy;y++){ 00382 val=((y*(bottom-top))/height)+top; /*linear interpolation between top and bottom*/ 00383 if (val>255) 00384 val=255; 00385 if (val<0) 00386 val=0; 00387 /*printf("writing pel at %d,%d\n",destx+x,desty+y);*/ 00388 putpixel(lightmap, destx+x-startx, desty+y-starty, 00389 SDL_MapRGBA(lightmap->format, 0, 0, 0, val)); 00390 } 00391 } 00392 } 00393 00394 00395 /* See note below about ALPHA_FUDGE - used to adjust lighting effects some */ 00396 00397 #define ALPHA_FUDGE(x) (2*(x) / 3) 00398 #define GENDARK(x,y) ( (((x)&(y) & 1) == 1)?255:0 ) 00399 00432 static void do_sdl_per_pixel_lighting(int x, int y, int mx, int my) 00433 { 00434 00435 int dark0, dark1, dark2, dark3, dark4; 00436 SDL_Rect dst; 00437 00438 /* I use dark0 -> dark4 in the order to keep it similar to 00439 * the old code. 00440 */ 00441 dark0 = the_map.cells[mx][my].darkness; 00442 00443 if (y-1 < 0 || !the_map.cells[mx][my-1].have_darkness) dark1 = dark0; 00444 else dark1 = the_map.cells[mx][my-1].darkness; 00445 00446 if (x+1 >= use_config[CONFIG_MAPWIDTH] || !the_map.cells[mx+1][my].have_darkness) dark2 = dark0; 00447 else dark2 = the_map.cells[mx+1][my].darkness; 00448 00449 if (y+1 >= use_config[CONFIG_MAPHEIGHT] || !the_map.cells[mx][my+1].have_darkness) dark3 = dark0; 00450 else dark3 = the_map.cells[mx][my+1].darkness; 00451 00452 if (x-1 < 0 || !the_map.cells[mx-1][my].have_darkness) dark4 = dark0; 00453 else dark4 = the_map.cells[mx-1][my].darkness; 00454 00455 /* If they are all the same, processing is easy 00456 * 00457 * Note, the best lightining algorithm also uses diagonals 00458 * so we should check the diagonals are same too 00459 * We don't check for now, simply do all raw computation on best mode 00460 * Tchize 19 may 2004 00461 */ 00462 if (dark0 == dark1 && dark0 == dark2 && dark0 == dark3 && dark0 == dark4 && (use_config[CONFIG_LIGHTING] != CFG_LT_PIXEL_BEST)) { 00463 dst.x = x * map_image_size; 00464 dst.y = y * map_image_size; 00465 dst.w = map_image_size; 00466 dst.h = map_image_size; 00467 00468 if (dark0 == 255) { 00469 SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0)); 00470 } else if (the_map.cells[mx][my].darkness != 0) { 00471 SDL_FillRect(lightmap,NULL, SDL_MapRGBA(lightmap->format, 0, 0, 0, the_map.cells[mx][my].darkness)); 00472 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00473 } 00474 return; 00475 } 00476 00477 00478 if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL ) { 00479 /* This almost works as well as the per pixel code below, but does have some various 00480 * artifacts in the drawing. It uses the same logic as the per pixel code below, 00481 * bit since SDL does the blit, the alpha handling ends up being different 00482 * (I think it ends up being additive). This results in the darkness being 00483 * darker, but you also don't get the smooth effects. If you divide all the values 00484 * by 2 (change ALPHA_FUDGE), the blending is smooth, but now the things are not dark 00485 * enough, so the blending aganst solid black spaces does not look good. 00486 * The reason this code is of interest is that on my system, it is about 50% 00487 * faster than the code below (25 ms to darkness the church in the starting 00488 * town vs 50 ms for the code further down) 00489 * Setting ALPHA_FUDGE to 2/3 seems to reduce the artifacts described above 00490 * to fairly minimal levels, while still keeping things dark enough. 00491 * MSW 2001-10-12 00492 */ 00493 00494 int i; 00495 00496 if (dark1 == dark0) { 00497 /* If we don't have usable darkness at the top, then this entire region 00498 * should be the same value. Likewise, if the top value and center value 00499 * are the same, we can do the entire region. 00500 */ 00501 dst.x=0; 00502 dst.y=0; 00503 dst.w = map_image_size; 00504 dst.h = map_image_half_size; 00505 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00506 } 00507 else for (i=0; i<map_image_half_size; i++) { 00508 /* Need to do it line by line */ 00509 00510 dst.x = 0; 00511 dst.y = i; 00512 dst.w = map_image_size; 00513 dst.h = 1; 00514 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00515 ALPHA_FUDGE((map_image_half_size - i) * dark1 + i * dark0)/map_image_half_size)); 00516 00517 } 00518 /* All the following blocks are basically the same as above, just different 00519 * darkness areas. 00520 */ 00521 if (dark3 == dark0) { 00522 dst.x=0; 00523 dst.y=map_image_half_size; 00524 dst.w = map_image_size; 00525 dst.h = map_image_half_size; 00526 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00527 } 00528 else for (i=map_image_half_size; i<map_image_size; i++) { 00529 /* Need to do it line by line */ 00530 00531 dst.x = 0; 00532 dst.y = i; 00533 dst.w = map_image_size; 00534 dst.h = 1; 00535 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00536 ALPHA_FUDGE(dark0*(map_image_size-i) + dark3*(i-map_image_half_size)) / map_image_half_size)); 00537 } 00538 /* Blit this to the screen now. Otherwise, we need to look at the alpha values 00539 * and re-average. 00540 */ 00541 00542 dst.x= x * map_image_size; 00543 dst.y= y * map_image_size; 00544 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00545 00546 if (dark4 == dark0) { 00547 dst.x=0; 00548 dst.y=0; 00549 dst.w = map_image_half_size; 00550 dst.h = map_image_size; 00551 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00552 } 00553 else for (i=0; i<map_image_half_size; i++) { 00554 /* Need to do it line by line */ 00555 dst.x = i; 00556 dst.y = 0; 00557 dst.w = 1; 00558 dst.h = map_image_size; 00559 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00560 ALPHA_FUDGE(dark4*(map_image_half_size-i) + dark0*i) / map_image_half_size)); 00561 } 00562 if (dark2 == dark0) { 00563 dst.x=map_image_half_size; 00564 dst.y=0; 00565 dst.w = map_image_half_size; 00566 dst.h = map_image_size; 00567 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00568 } 00569 else for (i=map_image_half_size; i<map_image_size; i++) { 00570 /* Need to do it line by line */ 00571 00572 dst.x = i; 00573 dst.y = 0; 00574 dst.w = 1; 00575 dst.h = map_image_size; 00576 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00577 ALPHA_FUDGE(dark0*(map_image_size-i) + dark2*(i-map_image_half_size)) / map_image_half_size)); 00578 } 00579 dst.x= x * map_image_size; 00580 dst.y= y * map_image_size; 00581 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00582 } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST ) { 00583 #if 0 00584 int dx,dy; 00585 static int *darkx=NULL, *darky=NULL,darkx_allocated=0; 00586 00587 /* Generated stored for the darkx[] array. Do it dynamically, but 00588 * only allocate if the size needs to be expanded to keep performance 00589 * better. darkx could be null in the initial case, but realloc should 00590 * just treat that as a malloc (so according to the man page) 00591 */ 00592 if (map_image_size > darkx_allocated) { 00593 darkx = realloc(darkx, map_image_size * sizeof(int)); 00594 darky = realloc(darky, map_image_size * sizeof(int)); 00595 darkx_allocated = map_image_size; 00596 } 00597 00598 for( dx= 0; dx < map_image_half_size; dx++) 00599 darkx[dx]= (dark4*(map_image_half_size-dx) + dark0*dx) / map_image_half_size; 00600 for( dx= map_image_half_size; dx < map_image_size; dx++) 00601 darkx[dx] = (dark0*(map_image_size-dx) + dark2*(dx-map_image_half_size)) / map_image_half_size; 00602 00603 for( dy= 0; dy < map_image_half_size; dy++) 00604 darky[dy]= (dark1*(map_image_half_size-dy) + dark0*dy) / map_image_half_size; 00605 for( dy= map_image_half_size; dy < map_image_size; dy++) 00606 darky[dy] = (dark0*(map_image_size-dy) + dark3*(dy-map_image_half_size)) / map_image_half_size; 00607 00608 SDL_LockSurface( lightmap); 00609 00610 for (dx=0; dx<map_image_size; dx++) 00611 for (dy=0; dy<map_image_size; dy++) 00612 putpixel(lightmap, dx, dy, SDL_MapRGBA(lightmap->format, 0, 0, 0,(darkx[dx] + darky[dy])/2)); 00613 #else 00614 /*we need additionnal surrounding infos*/ 00615 int dark5, dark6, dark7, dark8; 00616 if ( (y-1 < 0) || (x+1 >= use_config[CONFIG_MAPWIDTH]) 00617 || !the_map.cells[mx+1][my-1].have_darkness) dark5 = (dark1+dark2)>>1; /*(fast div 2)*/ 00618 else dark5 = the_map.cells[mx+1][my-1].darkness; 00619 00620 if ( (x+1 >= use_config[CONFIG_MAPWIDTH]) 00621 || (y+1 >= use_config[CONFIG_MAPHEIGHT]) 00622 || !the_map.cells[mx+1][my+1].have_darkness) dark6 = (dark2+dark3)>>1; 00623 else dark6 = the_map.cells[mx+1][my+1].darkness; 00624 00625 if ( (y+1 >= use_config[CONFIG_MAPHEIGHT]) || (x-1 < 0) 00626 || !the_map.cells[mx-1][my+1].have_darkness) dark7 = (dark3+dark4)>>1; 00627 else dark7 = the_map.cells[mx-1][my+1].darkness; 00628 00629 if ( (x-1 < 0) || (y-1 < 0) 00630 || !the_map.cells[mx-1][my-1].have_darkness) dark8 = (dark4+dark1)>>1; 00631 else dark8 = the_map.cells[mx-1][my-1].darkness; 00632 /*upper left lightmap quarter*/ 00633 drawquarterlightmap_sdl(dark8, dark1, dark4, dark0, /*colors*/ 00634 map_image_size, map_image_size, /*color square size*/ 00635 map_image_half_size, map_image_half_size, map_image_size, map_image_size, /*interpolation region*/ 00636 0, 0); /*where in lightmap to save result*/ 00637 /*upper right lightmap quarter*/ 00638 drawquarterlightmap_sdl(dark1, dark5, dark0, dark2, /*colors*/ 00639 map_image_size, map_image_size, /*color square size*/ 00640 0, map_image_half_size, map_image_half_size, map_image_size, /*interpolation region*/ 00641 map_image_half_size, 0); /*where in lightmap to save result*/ 00642 /*bottom left lightmap quarter*/ 00643 drawquarterlightmap_sdl(dark4, dark0, dark7, dark3, /*colors*/ 00644 map_image_size, map_image_size, /*color square size*/ 00645 map_image_half_size, 0, map_image_size, map_image_half_size, /*interpolation region*/ 00646 0, map_image_half_size); /*where in lightmap to save result*/ 00647 /*bottom right lightmap quarter*/ 00648 drawquarterlightmap_sdl(dark0, dark2, dark3, dark6, /*colors*/ 00649 map_image_size, map_image_size, /*color square size*/ 00650 0, 0, map_image_half_size, map_image_half_size, /*interpolation region*/ 00651 map_image_half_size, map_image_half_size); /*where in lightmap to save result*/ 00652 #endif 00653 dst.w= map_image_size; 00654 dst.h= map_image_size; 00655 dst.x= x * map_image_size; 00656 dst.y= y * map_image_size; 00657 SDL_UnlockSurface(lightmap); 00658 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00659 } 00660 } 00661 00674 static void drawsmooth_sdl (int mx,int my,int layer,SDL_Rect dst){ 00675 static int dx[8]={0,1,1,1,0,-1,-1,-1}; 00676 static int dy[8]={-1,-1,0,1,1,1,0,-1}; 00677 static int bweights[8]={2,0,4,0,8,0,1,0}; 00678 static int cweights[8]={0,2,0,4,0,8,0,1}; 00679 static int bc_exclude[8]={ 00680 1+2,/*north exclude northwest (bit0) and northeast(bit1)*/ 00681 0, 00682 2+4,/*east exclude northeast and southeast*/ 00683 0, 00684 4+8,/*and so on*/ 00685 0, 00686 8+1, 00687 0 00688 }; 00689 int partdone[8]={0,0,0,0,0,0,0,0}; 00690 int slevels[8]; 00691 int sfaces[8]; 00692 int i,lowest,weight,weightC; 00693 int emx,emy; 00694 int smoothface; 00695 int hasFace = 0; 00696 SDL_Rect src; 00697 for (i=0;i<=layer;i++) 00698 hasFace |= the_map.cells[mx][my].heads[i].face; 00699 if (!hasFace 00700 || !CAN_SMOOTH(the_map.cells[mx][my], layer)) { 00701 return; 00702 } 00703 00704 src.w=dst.w; 00705 src.h=dst.h; 00706 00707 for (i=0;i<8;i++){ 00708 emx=mx+dx[i]; 00709 emy=my+dy[i]; 00710 if ( (emx<0) || (emy<0) || (the_map.x<=emx) || (the_map.y<=emy)){ 00711 slevels[i]=0; 00712 sfaces[i]=0; /*black picture*/ 00713 } 00714 else if (the_map.cells[emx][emy].smooth[layer]<=the_map.cells[mx][my].smooth[layer]){ 00715 slevels[i]=0; 00716 sfaces[i]=0; /*black picture*/ 00717 }else{ 00718 slevels[i]=the_map.cells[emx][emy].smooth[layer]; 00719 sfaces[i]=pixmaps[the_map.cells[emx][emy].heads[layer].face]->smooth_face; 00720 } 00721 } 00722 /* ok, now we have a list of smoothlevel higher than current square. 00723 * there are at most 8 different levels. so... let's check 8 times 00724 * for the lowest one (we draw from botto to top!). 00725 */ 00726 lowest=-1; 00727 while (1){ 00728 lowest = -1; 00729 for (i=0;i<8;i++){ 00730 if ( (slevels[i]>0) && (!partdone[i]) && 00731 ((lowest<0) || (slevels[i]<slevels[lowest])) 00732 ) 00733 lowest=i; 00734 } 00735 if (lowest<0) 00736 break; /*no more smooth to do on this square*/ 00737 /*printf ("hey, must smooth something...%d\n",sfaces[lowest]);*/ 00738 /*here we know 'what' to smooth*/ 00739 /* we need to calculate the weight 00740 * for border and weight for corners. 00741 * then we 'markdone' 00742 * the corresponding squares 00743 */ 00744 /*first, the border, which may exclude some corners*/ 00745 weight=0; 00746 weightC=15; /*works in backward. remove where there is nothing*/ 00747 /*for (i=0;i<8;i++) 00748 cornermask[i]=1;*/ 00749 for (i=0;i<8;i++){ /*check all nearby squares*/ 00750 if ( (slevels[i]==slevels[lowest]) && 00751 (sfaces[i]==sfaces[lowest])){ 00752 partdone[i]=1; 00753 weight=weight+bweights[i]; 00754 weightC&=~bc_exclude[i]; 00755 }else{ 00756 /*must rmove the weight of a corner if not in smoothing*/ 00757 weightC&=~cweights[i]; 00758 } 00759 00760 } 00761 /*We can't do this before since we need the partdone to be adjusted*/ 00762 if (sfaces[lowest]<=0) 00763 continue; /*Can't smooth black*/ 00764 smoothface=sfaces[lowest]; 00765 if (smoothface<=0){ 00766 continue; /*picture for smoothing not yet available*/ 00767 } 00768 /* now, it's quite easy. We must draw using a 32x32 part of 00769 * the picture smoothface. 00770 * This part is located using the 2 weights calculated: 00771 * (32*weight,0) and (32*weightC,32) 00772 */ 00773 if ( (!pixmaps[smoothface]->map_image) || 00774 (pixmaps[smoothface] == pixmaps[0])) 00775 continue; /*don't have the picture associated*/ 00776 if (weight>0){ 00777 src.x=map_image_size*weight; 00778 src.y=0; 00779 if (the_map.cells[mx][my].cleared) { 00780 if (SDL_BlitSurface(pixmaps[smoothface]->fog_image, 00781 &src, mapsurface, &dst)) 00782 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00783 } else { 00784 if (SDL_BlitSurface(pixmaps[smoothface]->map_image, 00785 &src, mapsurface, &dst)) 00786 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00787 } 00788 } 00789 if (weightC>0){ 00790 src.x=map_image_size*weightC; 00791 src.y=map_image_size; 00792 if (the_map.cells[mx][my].cleared) { 00793 if (SDL_BlitSurface(pixmaps[smoothface]->fog_image, 00794 &src, mapsurface, &dst)) 00795 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00796 } else { 00797 if (SDL_BlitSurface(pixmaps[smoothface]->map_image, 00798 &src, mapsurface, &dst)) 00799 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00800 } 00801 } 00802 }/*while there's some smooth to do*/ 00803 } 00804 00815 static void update_redrawbitmap(void) 00816 { 00817 int mx,my, x,y; 00818 00819 memset(redrawbitmap, 0, (use_config[CONFIG_MAPWIDTH]+2) * (use_config[CONFIG_MAPHEIGHT]+2)); 00820 00821 for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) { 00822 for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) { 00823 mx = x + pl_pos.x; 00824 my = y + pl_pos.y; 00825 00826 /* Basically, we need to check the conditions that require this space. 00827 * to be redrawn. We store this in redrawbitmap, because storing 00828 * in the_map[][].need_update would cause a cascade effect, of space 00829 * 1,0 need an update, so we thing 2,0 needs an update due to smoothing/ 00830 * like, which causes 3,0 to be updated, etc. Having our own 00831 * memory area allows the memset above, which is an optimized routine 00832 * to clear memory. 00833 */ 00834 if (the_map.cells[mx][my].need_update) { 00835 redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1; 00836 /* If this space has changed, and using non tile lighting, 00837 * we need to update the neighbor spaces. Ideally, we'd 00838 * have a flag just to denote lighting changes, since 00839 * that is handled on a different surface anyways. 00840 */ 00841 if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL || 00842 use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) { 00843 /* This is where having redrawbitmap bigger pays off - don't have 00844 * to check to see if values are within redrawbitmap is within bounds 00845 */ 00846 redrawbitmap[x + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1; 00847 redrawbitmap[x + 2 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1; 00848 redrawbitmap[x + 1 + (y) * use_config[CONFIG_MAPWIDTH]] = 1; 00849 redrawbitmap[x + 1 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1; 00850 } 00851 /* In best mode, have to update diaganols in addition*/ 00852 if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) { 00853 redrawbitmap[x + (y) * use_config[CONFIG_MAPWIDTH]] = 1; 00854 redrawbitmap[x + 2 + (y) * use_config[CONFIG_MAPWIDTH]] = 1; 00855 redrawbitmap[x + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1; 00856 redrawbitmap[x + 2 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1; 00857 } 00858 } 00859 else if (the_map.cells[mx][my].need_resmooth) { 00860 redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1; 00861 } 00862 } 00863 } 00864 } 00865 00873 static void display_mapcell(int ax, int ay, int mx, int my) 00874 { 00875 SDL_Rect dst, src; 00876 int layer; 00877 00878 /* First, we need to black out this space. */ 00879 dst.x = ax*map_image_size; 00880 dst.y = ay*map_image_size; 00881 dst.w = map_image_size; 00882 dst.h = map_image_size; 00883 SDL_FillRect(mapsurface, &dst, SDL_MapRGB(mapsurface->format, 0, 0, 0)); 00884 00885 /* now draw the different layers. Only draw if using fog of war or the 00886 * space isn't clear. 00887 */ 00888 if (use_config[CONFIG_FOGWAR] || !the_map.cells[mx][my].cleared) { 00889 for (layer=0; layer<MAXLAYERS; layer++) { 00890 int sx, sy; 00891 00892 /* draw single-tile faces first */ 00893 int face = mapdata_face(ax, ay, layer); 00894 if (face > 0 && pixmaps[face]->map_image != NULL) { 00895 int w = pixmaps[face]->map_width; 00896 int h = pixmaps[face]->map_height; 00897 /* add one to the size values to take into account the actual width of the space */ 00898 src.x = w-map_image_size; 00899 src.y = h-map_image_size; 00900 src.w = map_image_size; 00901 src.h = map_image_size; 00902 dst.x = ax*map_image_size; 00903 dst.y = ay*map_image_size; 00904 if (the_map.cells[mx][my].cleared) { 00905 if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst)) 00906 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00907 } else { 00908 if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst)) 00909 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00910 } 00911 00912 } 00913 /* Sometimes, it may happens we need to draw the smooth while there 00914 * is nothing to draw at that layer (but there was something at lower 00915 * layers). This is handled here. The else part is to take into account 00916 * cases where the smooth as already been handled 2 code lines before 00917 */ 00918 if (use_config[CONFIG_SMOOTH]) 00919 drawsmooth_sdl (mx,my,layer,dst); 00920 00921 /* draw big faces last (should overlap other objects) */ 00922 face = mapdata_bigface(ax, ay, layer, &sx, &sy); 00923 if (face > 0 && pixmaps[face]->map_image != NULL) { 00924 /* We have to handle images that are not an equal 00925 * multiplier of map_image_size. See 00926 * display_mapcell() in gtk-v2/src/map.c for 00927 * more details on this logic, since it is basically 00928 * the same. 00929 */ 00930 int dx, dy, sourcex, sourcey, offx, offy; 00931 00932 dx = pixmaps[face]->map_width % map_image_size; 00933 offx = dx?(map_image_size -dx):0; 00934 00935 if (sx) { 00936 sourcex = sx * map_image_size - offx ; 00937 offx=0; 00938 } else { 00939 sourcex=0; 00940 } 00941 00942 dy = pixmaps[face]->map_height % map_image_size; 00943 offy = dy?(map_image_size -dy):0; 00944 00945 if (sy) { 00946 sourcey = sy * map_image_size - offy; 00947 offy=0; 00948 } else { 00949 sourcey=0; 00950 } 00951 00952 src.x = sourcex; 00953 src.y = sourcey; 00954 src.w = map_image_size - offx; 00955 src.h = map_image_size - offy; 00956 dst.x = ax*map_image_size + offx; 00957 dst.y = ay*map_image_size + offy; 00958 if (the_map.cells[mx][my].cleared) { 00959 if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst)) 00960 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00961 } else { 00962 if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst)) 00963 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00964 } 00965 } /* else for processing the layers */ 00966 } 00967 } 00968 00969 if (use_config[CONFIG_LIGHTING] == CFG_LT_TILE) { 00970 dst.x = ax*map_image_size; 00971 dst.y = ay*map_image_size; 00972 dst.w = map_image_size; 00973 dst.h = map_image_size; 00974 00975 /* Note - Instead of using a lightmap, I just fillrect 00976 * directly onto the map surface - I would think this should be 00977 * faster 00978 */ 00979 if (the_map.cells[mx][my].darkness == 255) { 00980 SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0)); 00981 } else if (the_map.cells[mx][my].darkness != 0) { 00982 SDL_SetAlpha(lightmap, SDL_SRCALPHA|SDL_RLEACCEL, the_map.cells[mx][my].darkness); 00983 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00984 } 00985 } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL || use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) { 00986 do_sdl_per_pixel_lighting(ax, ay, mx, my); 00987 } 00988 } 00989 01014 void sdl_gen_map(int redraw) { 01015 int x, y, num_spaces=0, num_drawn=0; 01016 struct timeval tv1, tv2, tv3; 01017 long elapsed1, elapsed2; 01018 01019 if (time_map_redraw) 01020 gettimeofday(&tv1, NULL); 01021 01022 update_redrawbitmap(); 01023 01024 for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) { 01025 for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) { 01026 num_spaces++; 01027 01028 /* This will be updated in the for loop above for 01029 * whatever conditions that need this space to be redrawn 01030 */ 01031 if (redraw || redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]]) { 01032 num_drawn++; 01033 display_mapcell(x, y, pl_pos.x+x, pl_pos.y+y); 01034 the_map.cells[pl_pos.x+x][pl_pos.y+y].need_update = 0; 01035 the_map.cells[pl_pos.x+x][pl_pos.y+y].need_resmooth = 0; 01036 } 01037 } 01038 } 01039 01040 if (time_map_redraw) 01041 gettimeofday(&tv2, NULL); 01042 01043 SDL_Flip(mapsurface); 01044 01045 if (time_map_redraw) { 01046 gettimeofday(&tv3, NULL); 01047 elapsed1 = (tv2.tv_sec - tv1.tv_sec)*1000000 + (tv2.tv_usec - tv1.tv_usec); 01048 elapsed2 = (tv3.tv_sec - tv2.tv_sec)*1000000 + (tv3.tv_usec - tv2.tv_usec); 01049 01050 /* I care about performance for 'long' updates, so put the check in to make 01051 * these a little more noticable */ 01052 if ((elapsed1 + elapsed2)>10000) 01053 LOG(LOG_INFO,"gtk::sdl_gen_map","gen took %7ld, flip took %7ld, total = %7ld", 01054 elapsed1, elapsed2, elapsed1 + elapsed2); 01055 } 01056 } /* sdl_gen_map function */ 01057 01063 int sdl_mapscroll(int dx, int dy) 01064 { 01065 /* Don't sdl_gen_map should take care of the redraw */ 01066 01067 /* a copy of what pngximage does except sdl specfic 01068 * mapsurface->pitch is the length of a scanline in bytes 01069 * including alignment padding 01070 */ 01071 SDL_LockSurface( mapsurface); 01072 if( dy < 0) { 01073 int offset= mapsurface->pitch * (-dy*map_image_size); 01074 memmove( mapsurface->pixels + offset, mapsurface->pixels, 01075 mapsurface->pitch * (mapsurface->h + dy*map_image_size) ); 01076 } 01077 else if( dy > 0) { 01078 int offset= mapsurface->pitch * (dy*map_image_size); 01079 memmove( mapsurface->pixels, mapsurface->pixels + offset, 01080 mapsurface->pitch * (mapsurface->h - dy*map_image_size) ); 01081 } 01082 01083 if (dx) { 01084 int y; 01085 for( y= 0; y < mapsurface->h; y++) { 01086 if( dx < 0) { 01087 char* start_of_row= mapsurface->pixels + mapsurface->pitch * y; 01088 int offset= ( mapsurface->format->BytesPerPixel * map_image_size * -dx); 01089 memmove( start_of_row + offset, start_of_row, 01090 mapsurface->pitch - offset); 01091 } 01092 else { 01093 char* start_of_row= mapsurface->pixels + mapsurface->pitch * y; 01094 int offset= ( mapsurface->format->BytesPerPixel * map_image_size * dx); 01095 memmove( start_of_row, start_of_row + offset, 01096 mapsurface->pitch - offset); 01097 } 01098 } 01099 } 01100 SDL_UnlockSurface( mapsurface); 01101 01102 return 1; 01103 } 01104 01105 #endif