|
Crossfire Client, Trunk
R18666
|
00001 const char * const rcsid_gtk_sdl_c = 00002 "$Id: sdl.c 13982 2010-10-09 22:41:04Z 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-v2::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 00376 void drawquarterlightmap_sdl(int tl, int tr, int bl, int br, 00377 int width, int height, 00378 int startx, int starty, int endx, int endy, 00379 int destx, int desty){ 00380 int x,y; 00381 int top,bottom,val; 00382 for (x=startx;x<endx;x++){ 00383 top= ((x*(tr-tl))/ width)+tl; /*linear interpolation for top color*/ 00384 bottom= ((x*(br-bl))/ width)+bl; /*linear interpolation for bottom color*/ 00385 for (y=starty;y<endy;y++){ 00386 val=((y*(bottom-top))/height)+top; /*linear interpolation between top and bottom*/ 00387 if (val>255) 00388 val=255; 00389 if (val<0) 00390 val=0; 00391 /*printf("writing pel at %d,%d\n",destx+x,desty+y);*/ 00392 putpixel(lightmap, destx+x-startx, desty+y-starty, 00393 SDL_MapRGBA(lightmap->format, 0, 0, 0, val)); 00394 } 00395 } 00396 } 00397 00398 00399 /* See note below about ALPHA_FUDGE - used to adjust lighting effects some */ 00400 00401 #define ALPHA_FUDGE(x) (2*(x) / 3) 00402 #define GENDARK(x,y) ( (((x)&(y) & 1) == 1)?255:0 ) 00403 00436 static void do_sdl_per_pixel_lighting(int x, int y, int mx, int my) 00437 { 00438 00439 int dark0, dark1, dark2, dark3, dark4; 00440 SDL_Rect dst; 00441 00442 /* I use dark0 -> dark4 in the order to keep it similar to 00443 * the old code. 00444 */ 00445 dark0 = the_map.cells[mx][my].darkness; 00446 00447 if (y-1 < 0 || !the_map.cells[mx][my-1].have_darkness) dark1 = dark0; 00448 else dark1 = the_map.cells[mx][my-1].darkness; 00449 00450 if (x+1 >= use_config[CONFIG_MAPWIDTH] || !the_map.cells[mx+1][my].have_darkness) dark2 = dark0; 00451 else dark2 = the_map.cells[mx+1][my].darkness; 00452 00453 if (y+1 >= use_config[CONFIG_MAPHEIGHT] || !the_map.cells[mx][my+1].have_darkness) dark3 = dark0; 00454 else dark3 = the_map.cells[mx][my+1].darkness; 00455 00456 if (x-1 < 0 || !the_map.cells[mx-1][my].have_darkness) dark4 = dark0; 00457 else dark4 = the_map.cells[mx-1][my].darkness; 00458 00459 /* If they are all the same, processing is easy 00460 * 00461 * Note, the best lightining algorithm also uses diagonals 00462 * so we should check the diagonals are same too 00463 * We don't check for now, simply do all raw computation on best mode 00464 * Tchize 19 may 2004 00465 */ 00466 if (dark0 == dark1 && dark0 == dark2 && dark0 == dark3 && dark0 == dark4 && (use_config[CONFIG_LIGHTING] != CFG_LT_PIXEL_BEST)) { 00467 dst.x = x * map_image_size; 00468 dst.y = y * map_image_size; 00469 dst.w = map_image_size; 00470 dst.h = map_image_size; 00471 00472 if (dark0 == 255) { 00473 SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0)); 00474 } else if (the_map.cells[mx][my].darkness != 0) { 00475 SDL_FillRect(lightmap,NULL, SDL_MapRGBA(lightmap->format, 0, 0, 0, the_map.cells[mx][my].darkness)); 00476 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00477 } 00478 return; 00479 } 00480 00481 00482 if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL ) { 00483 /* This almost works as well as the per pixel code below, but does have some various 00484 * artifacts in the drawing. It uses the same logic as the per pixel code below, 00485 * bit since SDL does the blit, the alpha handling ends up being different 00486 * (I think it ends up being additive). This results in the darkness being 00487 * darker, but you also don't get the smooth effects. If you divide all the values 00488 * by 2 (change ALPHA_FUDGE), the blending is smooth, but now the things are not dark 00489 * enough, so the blending aganst solid black spaces does not look good. 00490 * The reason this code is of interest is that on my system, it is about 50% 00491 * faster than the code below (25 ms to darkness the church in the starting 00492 * town vs 50 ms for the code further down) 00493 * Setting ALPHA_FUDGE to 2/3 seems to reduce the artifacts described above 00494 * to fairly minimal levels, while still keeping things dark enough. 00495 * MSW 2001-10-12 00496 */ 00497 00498 int i; 00499 00500 if (dark1 == dark0) { 00501 /* If we don't have usable darkness at the top, then this entire region 00502 * should be the same value. Likewise, if the top value and center value 00503 * are the same, we can do the entire region. 00504 */ 00505 dst.x=0; 00506 dst.y=0; 00507 dst.w = map_image_size; 00508 dst.h = map_image_half_size; 00509 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00510 } 00511 else for (i=0; i<map_image_half_size; i++) { 00512 /* Need to do it line by line */ 00513 00514 dst.x = 0; 00515 dst.y = i; 00516 dst.w = map_image_size; 00517 dst.h = 1; 00518 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00519 ALPHA_FUDGE((map_image_half_size - i) * dark1 + i * dark0)/map_image_half_size)); 00520 00521 } 00522 /* All the following blocks are basically the same as above, just different 00523 * darkness areas. 00524 */ 00525 if (dark3 == dark0) { 00526 dst.x=0; 00527 dst.y=map_image_half_size; 00528 dst.w = map_image_size; 00529 dst.h = map_image_half_size; 00530 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00531 } 00532 else for (i=map_image_half_size; i<map_image_size; i++) { 00533 /* Need to do it line by line */ 00534 00535 dst.x = 0; 00536 dst.y = i; 00537 dst.w = map_image_size; 00538 dst.h = 1; 00539 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00540 ALPHA_FUDGE(dark0*(map_image_size-i) + dark3*(i-map_image_half_size)) / map_image_half_size)); 00541 } 00542 /* Blit this to the screen now. Otherwise, we need to look at the alpha values 00543 * and re-average. 00544 */ 00545 00546 dst.x= x * map_image_size; 00547 dst.y= y * map_image_size; 00548 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00549 00550 if (dark4 == dark0) { 00551 dst.x=0; 00552 dst.y=0; 00553 dst.w = map_image_half_size; 00554 dst.h = map_image_size; 00555 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00556 } 00557 else for (i=0; i<map_image_half_size; i++) { 00558 /* Need to do it line by line */ 00559 dst.x = i; 00560 dst.y = 0; 00561 dst.w = 1; 00562 dst.h = map_image_size; 00563 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00564 ALPHA_FUDGE(dark4*(map_image_half_size-i) + dark0*i) / map_image_half_size)); 00565 } 00566 if (dark2 == dark0) { 00567 dst.x=map_image_half_size; 00568 dst.y=0; 00569 dst.w = map_image_half_size; 00570 dst.h = map_image_size; 00571 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00572 } 00573 else for (i=map_image_half_size; i<map_image_size; i++) { 00574 /* Need to do it line by line */ 00575 00576 dst.x = i; 00577 dst.y = 0; 00578 dst.w = 1; 00579 dst.h = map_image_size; 00580 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00581 ALPHA_FUDGE(dark0*(map_image_size-i) + dark2*(i-map_image_half_size)) / map_image_half_size)); 00582 } 00583 dst.x= x * map_image_size; 00584 dst.y= y * map_image_size; 00585 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00586 } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST ) { 00587 #if 0 00588 int dx,dy; 00589 static int *darkx=NULL, *darky=NULL,darkx_allocated=0; 00590 00591 /* Generated stored for the darkx[] array. Do it dynamically, but 00592 * only allocate if the size needs to be expanded to keep performance 00593 * better. darkx could be null in the initial case, but realloc should 00594 * just treat that as a malloc (so according to the man page) 00595 */ 00596 if (map_image_size > darkx_allocated) { 00597 darkx = realloc(darkx, map_image_size * sizeof(int)); 00598 darky = realloc(darky, map_image_size * sizeof(int)); 00599 darkx_allocated = map_image_size; 00600 } 00601 00602 for( dx= 0; dx < map_image_half_size; dx++) 00603 darkx[dx]= (dark4*(map_image_half_size-dx) + dark0*dx) / map_image_half_size; 00604 for( dx= map_image_half_size; dx < map_image_size; dx++) 00605 darkx[dx] = (dark0*(map_image_size-dx) + dark2*(dx-map_image_half_size)) / map_image_half_size; 00606 00607 for( dy= 0; dy < map_image_half_size; dy++) 00608 darky[dy]= (dark1*(map_image_half_size-dy) + dark0*dy) / map_image_half_size; 00609 for( dy= map_image_half_size; dy < map_image_size; dy++) 00610 darky[dy] = (dark0*(map_image_size-dy) + dark3*(dy-map_image_half_size)) / map_image_half_size; 00611 00612 SDL_LockSurface( lightmap); 00613 00614 for (dx=0; dx<map_image_size; dx++) 00615 for (dy=0; dy<map_image_size; dy++) 00616 putpixel(lightmap, dx, dy, SDL_MapRGBA(lightmap->format, 0, 0, 0,(darkx[dx] + darky[dy])/2)); 00617 #else 00618 /*we need additionnal surrounding infos*/ 00619 int dark5, dark6, dark7, dark8; 00620 if ( (y-1 < 0) || (x+1 >= use_config[CONFIG_MAPWIDTH]) 00621 || !the_map.cells[mx+1][my-1].have_darkness) dark5 = (dark1+dark2)>>1; /*(fast div 2)*/ 00622 else dark5 = the_map.cells[mx+1][my-1].darkness; 00623 00624 if ( (x+1 >= use_config[CONFIG_MAPWIDTH]) 00625 || (y+1 >= use_config[CONFIG_MAPHEIGHT]) 00626 || !the_map.cells[mx+1][my+1].have_darkness) dark6 = (dark2+dark3)>>1; 00627 else dark6 = the_map.cells[mx+1][my+1].darkness; 00628 00629 if ( (y+1 >= use_config[CONFIG_MAPHEIGHT]) || (x-1 < 0) 00630 || !the_map.cells[mx-1][my+1].have_darkness) dark7 = (dark3+dark4)>>1; 00631 else dark7 = the_map.cells[mx-1][my+1].darkness; 00632 00633 if ( (x-1 < 0) || (y-1 < 0) 00634 || !the_map.cells[mx-1][my-1].have_darkness) dark8 = (dark4+dark1)>>1; 00635 else dark8 = the_map.cells[mx-1][my-1].darkness; 00636 /*upper left lightmap quarter*/ 00637 drawquarterlightmap_sdl(dark8, dark1, dark4, dark0, /*colors*/ 00638 map_image_size, map_image_size, /*color square size*/ 00639 map_image_half_size, map_image_half_size, map_image_size, map_image_size, /*interpolation region*/ 00640 0, 0); /*where in lightmap to save result*/ 00641 /*upper right lightmap quarter*/ 00642 drawquarterlightmap_sdl(dark1, dark5, dark0, dark2, /*colors*/ 00643 map_image_size, map_image_size, /*color square size*/ 00644 0, map_image_half_size, map_image_half_size, map_image_size, /*interpolation region*/ 00645 map_image_half_size, 0); /*where in lightmap to save result*/ 00646 /*bottom left lightmap quarter*/ 00647 drawquarterlightmap_sdl(dark4, dark0, dark7, dark3, /*colors*/ 00648 map_image_size, map_image_size, /*color square size*/ 00649 map_image_half_size, 0, map_image_size, map_image_half_size, /*interpolation region*/ 00650 0, map_image_half_size); /*where in lightmap to save result*/ 00651 /*bottom right lightmap quarter*/ 00652 drawquarterlightmap_sdl(dark0, dark2, dark3, dark6, /*colors*/ 00653 map_image_size, map_image_size, /*color square size*/ 00654 0, 0, map_image_half_size, map_image_half_size, /*interpolation region*/ 00655 map_image_half_size, map_image_half_size); /*where in lightmap to save result*/ 00656 #endif 00657 dst.w= map_image_size; 00658 dst.h= map_image_size; 00659 dst.x= x * map_image_size; 00660 dst.y= y * map_image_size; 00661 SDL_UnlockSurface(lightmap); 00662 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00663 } 00664 } 00665 00678 static void drawsmooth_sdl (int mx,int my,int layer,SDL_Rect dst){ 00679 static int dx[8]={0,1,1,1,0,-1,-1,-1}; 00680 static int dy[8]={-1,-1,0,1,1,1,0,-1}; 00681 static int bweights[8]={2,0,4,0,8,0,1,0}; 00682 static int cweights[8]={0,2,0,4,0,8,0,1}; 00683 static int bc_exclude[8]={ 00684 1+2,/*north exclude northwest (bit0) and northeast(bit1)*/ 00685 0, 00686 2+4,/*east exclude northeast and southeast*/ 00687 0, 00688 4+8,/*and so on*/ 00689 0, 00690 8+1, 00691 0 00692 }; 00693 int partdone[8]={0,0,0,0,0,0,0,0}; 00694 int slevels[8]; 00695 int sfaces[8]; 00696 int i,weight,weightC; 00697 int emx,emy; 00698 int smoothface; 00699 int hasFace = 0; 00700 SDL_Rect src; 00701 for (i=0;i<=layer;i++) 00702 hasFace |= the_map.cells[mx][my].heads[i].face; 00703 if (!hasFace 00704 || !CAN_SMOOTH(the_map.cells[mx][my], layer)) { 00705 return; 00706 } 00707 00708 src.w=dst.w; 00709 src.h=dst.h; 00710 00711 for (i=0;i<8;i++){ 00712 emx=mx+dx[i]; 00713 emy=my+dy[i]; 00714 if ( (emx<0) || (emy<0) || (the_map.x<=emx) || (the_map.y<=emy)){ 00715 slevels[i]=0; 00716 sfaces[i]=0; /*black picture*/ 00717 } 00718 else if (the_map.cells[emx][emy].smooth[layer]<=the_map.cells[mx][my].smooth[layer]){ 00719 slevels[i]=0; 00720 sfaces[i]=0; /*black picture*/ 00721 }else{ 00722 slevels[i]=the_map.cells[emx][emy].smooth[layer]; 00723 sfaces[i]=pixmaps[the_map.cells[emx][emy].heads[layer].face]->smooth_face; 00724 } 00725 } 00726 /* ok, now we have a list of smoothlevel higher than current square. 00727 * there are at most 8 different levels. so... let's check 8 times 00728 * for the lowest one (we draw from botto to top!). 00729 */ 00730 while (1){ 00731 int lowest = -1; 00732 for (i=0;i<8;i++){ 00733 if ( (slevels[i]>0) && (!partdone[i]) && 00734 ((lowest<0) || (slevels[i]<slevels[lowest])) 00735 ) 00736 lowest=i; 00737 } 00738 if (lowest<0) 00739 break; /*no more smooth to do on this square*/ 00740 /*printf ("hey, must smooth something...%d\n",sfaces[lowest]);*/ 00741 /*here we know 'what' to smooth*/ 00742 /* we need to calculate the weight 00743 * for border and weight for corners. 00744 * then we 'markdone' 00745 * the corresponding squares 00746 */ 00747 /*first, the border, which may exclude some corners*/ 00748 weight=0; 00749 weightC=15; /*works in backward. remove where there is nothing*/ 00750 /*for (i=0;i<8;i++) 00751 cornermask[i]=1;*/ 00752 for (i=0;i<8;i++){ /*check all nearby squares*/ 00753 if ( (slevels[i]==slevels[lowest]) && 00754 (sfaces[i]==sfaces[lowest])){ 00755 partdone[i]=1; 00756 weight=weight+bweights[i]; 00757 weightC&=~bc_exclude[i]; 00758 }else{ 00759 /*must rmove the weight of a corner if not in smoothing*/ 00760 weightC&=~cweights[i]; 00761 } 00762 00763 } 00764 /*We can't do this before since we need the partdone to be adjusted*/ 00765 if (sfaces[lowest]<=0) 00766 continue; /*Can't smooth black*/ 00767 smoothface=sfaces[lowest]; 00768 if (smoothface<=0){ 00769 continue; /*picture for smoothing not yet available*/ 00770 } 00771 /* now, it's quite easy. We must draw using a 32x32 part of 00772 * the picture smoothface. 00773 * This part is located using the 2 weights calculated: 00774 * (32*weight,0) and (32*weightC,32) 00775 */ 00776 if ( (!pixmaps[smoothface]->map_image) || 00777 (pixmaps[smoothface] == pixmaps[0])) 00778 continue; /*don't have the picture associated*/ 00779 if (weight>0){ 00780 src.x=map_image_size*weight; 00781 src.y=0; 00782 if (the_map.cells[mx][my].cleared) { 00783 if (SDL_BlitSurface(pixmaps[smoothface]->fog_image, 00784 &src, mapsurface, &dst)) 00785 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00786 } else { 00787 if (SDL_BlitSurface(pixmaps[smoothface]->map_image, 00788 &src, mapsurface, &dst)) 00789 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00790 } 00791 } 00792 if (weightC>0){ 00793 src.x=map_image_size*weightC; 00794 src.y=map_image_size; 00795 if (the_map.cells[mx][my].cleared) { 00796 if (SDL_BlitSurface(pixmaps[smoothface]->fog_image, 00797 &src, mapsurface, &dst)) 00798 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00799 } else { 00800 if (SDL_BlitSurface(pixmaps[smoothface]->map_image, 00801 &src, mapsurface, &dst)) 00802 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00803 } 00804 } 00805 }/*while there's some smooth to do*/ 00806 } 00807 00818 static void update_redrawbitmap(void) 00819 { 00820 int mx,my, x,y; 00821 00822 memset(redrawbitmap, 0, (use_config[CONFIG_MAPWIDTH]+2) * (use_config[CONFIG_MAPHEIGHT]+2)); 00823 00824 for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) { 00825 for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) { 00826 mx = x + pl_pos.x; 00827 my = y + pl_pos.y; 00828 00829 /* Basically, we need to check the conditions that require this space. 00830 * to be redrawn. We store this in redrawbitmap, because storing 00831 * in the_map[][].need_update would cause a cascade effect, of space 00832 * 1,0 need an update, so we thing 2,0 needs an update due to smoothing/ 00833 * like, which causes 3,0 to be updated, etc. Having our own 00834 * memory area allows the memset above, which is an optimized routine 00835 * to clear memory. 00836 */ 00837 if (the_map.cells[mx][my].need_update) { 00838 redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1; 00839 /* If this space has changed, and using non tile lighting, 00840 * we need to update the neighbor spaces. Ideally, we'd 00841 * have a flag just to denote lighting changes, since 00842 * that is handled on a different surface anyways. 00843 */ 00844 if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL || 00845 use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) { 00846 /* This is where having redrawbitmap bigger pays off - don't have 00847 * to check to see if values are within redrawbitmap is within bounds 00848 */ 00849 redrawbitmap[x + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1; 00850 redrawbitmap[x + 2 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1; 00851 redrawbitmap[x + 1 + (y) * use_config[CONFIG_MAPWIDTH]] = 1; 00852 redrawbitmap[x + 1 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1; 00853 } 00854 /* In best mode, have to update diaganols in addition*/ 00855 if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) { 00856 redrawbitmap[x + (y) * use_config[CONFIG_MAPWIDTH]] = 1; 00857 redrawbitmap[x + 2 + (y) * use_config[CONFIG_MAPWIDTH]] = 1; 00858 redrawbitmap[x + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1; 00859 redrawbitmap[x + 2 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1; 00860 } 00861 } 00862 else if (the_map.cells[mx][my].need_resmooth) { 00863 redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1; 00864 } 00865 } 00866 } 00867 } 00868 00876 static void display_mapcell(int ax, int ay, int mx, int my) 00877 { 00878 SDL_Rect dst, src; 00879 int layer; 00880 00881 /* First, we need to black out this space. */ 00882 dst.x = ax*map_image_size; 00883 dst.y = ay*map_image_size; 00884 dst.w = map_image_size; 00885 dst.h = map_image_size; 00886 SDL_FillRect(mapsurface, &dst, SDL_MapRGB(mapsurface->format, 0, 0, 0)); 00887 00888 /* now draw the different layers. Only draw if using fog of war or the 00889 * space isn't clear. 00890 */ 00891 if (use_config[CONFIG_FOGWAR] || !the_map.cells[mx][my].cleared) { 00892 for (layer=0; layer<MAXLAYERS; layer++) { 00893 int sx, sy; 00894 00895 /* draw single-tile faces first */ 00896 int face = mapdata_face(ax, ay, layer); 00897 if (face > 0 && pixmaps[face]->map_image != NULL) { 00898 int w = pixmaps[face]->map_width; 00899 int h = pixmaps[face]->map_height; 00900 /* add one to the size values to take into account the actual width of the space */ 00901 src.x = w-map_image_size; 00902 src.y = h-map_image_size; 00903 src.w = map_image_size; 00904 src.h = map_image_size; 00905 dst.x = ax*map_image_size; 00906 dst.y = ay*map_image_size; 00907 if (the_map.cells[mx][my].cleared) { 00908 if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst)) 00909 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00910 } else { 00911 if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst)) 00912 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00913 } 00914 00915 } 00916 /* Sometimes, it may happens we need to draw the smooth while there 00917 * is nothing to draw at that layer (but there was something at lower 00918 * layers). This is handled here. The else part is to take into account 00919 * cases where the smooth as already been handled 2 code lines before 00920 */ 00921 if (use_config[CONFIG_SMOOTH]) 00922 drawsmooth_sdl (mx,my,layer,dst); 00923 00924 /* draw big faces last (should overlap other objects) */ 00925 face = mapdata_bigface(ax, ay, layer, &sx, &sy); 00926 if (face > 0 && pixmaps[face]->map_image != NULL) { 00927 /* We have to handle images that are not an equal 00928 * multiplier of map_image_size. See 00929 * display_mapcell() in gtk-v2/src/map.c for 00930 * more details on this logic, since it is basically 00931 * the same. 00932 */ 00933 int dx, dy, sourcex, sourcey, offx, offy; 00934 00935 dx = pixmaps[face]->map_width % map_image_size; 00936 offx = dx?(map_image_size -dx):0; 00937 00938 if (sx) { 00939 sourcex = sx * map_image_size - offx ; 00940 offx=0; 00941 } else { 00942 sourcex=0; 00943 } 00944 00945 dy = pixmaps[face]->map_height % map_image_size; 00946 offy = dy?(map_image_size -dy):0; 00947 00948 if (sy) { 00949 sourcey = sy * map_image_size - offy; 00950 offy=0; 00951 } else { 00952 sourcey=0; 00953 } 00954 00955 src.x = sourcex; 00956 src.y = sourcey; 00957 src.w = map_image_size - offx; 00958 src.h = map_image_size - offy; 00959 dst.x = ax*map_image_size + offx; 00960 dst.y = ay*map_image_size + offy; 00961 if (the_map.cells[mx][my].cleared) { 00962 if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst)) 00963 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00964 } else { 00965 if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst)) 00966 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00967 } 00968 } /* else for processing the layers */ 00969 } 00970 } 00971 00972 if (use_config[CONFIG_LIGHTING] == CFG_LT_TILE) { 00973 dst.x = ax*map_image_size; 00974 dst.y = ay*map_image_size; 00975 dst.w = map_image_size; 00976 dst.h = map_image_size; 00977 00978 /* Note - Instead of using a lightmap, I just fillrect 00979 * directly onto the map surface - I would think this should be 00980 * faster 00981 */ 00982 if (the_map.cells[mx][my].darkness == 255) { 00983 SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0)); 00984 } else if (the_map.cells[mx][my].darkness != 0) { 00985 SDL_SetAlpha(lightmap, SDL_SRCALPHA|SDL_RLEACCEL, the_map.cells[mx][my].darkness); 00986 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00987 } 00988 } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL || use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) { 00989 do_sdl_per_pixel_lighting(ax, ay, mx, my); 00990 } 00991 } 00992 01017 void sdl_gen_map(int redraw) { 01018 int x, y, num_spaces=0, num_drawn=0; 01019 struct timeval tv1, tv2, tv3; 01020 long elapsed1, elapsed2; 01021 01022 if (time_map_redraw) 01023 gettimeofday(&tv1, NULL); 01024 01025 update_redrawbitmap(); 01026 01027 for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) { 01028 for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) { 01029 num_spaces++; 01030 01031 /* This will be updated in the for loop above for 01032 * whatever conditions that need this space to be redrawn 01033 */ 01034 if (redraw || redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]]) { 01035 num_drawn++; 01036 display_mapcell(x, y, pl_pos.x+x, pl_pos.y+y); 01037 the_map.cells[pl_pos.x+x][pl_pos.y+y].need_update = 0; 01038 the_map.cells[pl_pos.x+x][pl_pos.y+y].need_resmooth = 0; 01039 } 01040 } 01041 } 01042 01043 if (time_map_redraw) 01044 gettimeofday(&tv2, NULL); 01045 01046 SDL_Flip(mapsurface); 01047 01048 if (time_map_redraw) { 01049 gettimeofday(&tv3, NULL); 01050 elapsed1 = (tv2.tv_sec - tv1.tv_sec)*1000000 + (tv2.tv_usec - tv1.tv_usec); 01051 elapsed2 = (tv3.tv_sec - tv2.tv_sec)*1000000 + (tv3.tv_usec - tv2.tv_usec); 01052 01053 /* I care about performance for 'long' updates, so put the check in to make 01054 * these a little more noticable */ 01055 if ((elapsed1 + elapsed2)>10000) 01056 LOG(LOG_INFO,"gtk-v2::sdl_gen_map","gen took %7ld, flip took %7ld, total = %7ld", 01057 elapsed1, elapsed2, elapsed1 + elapsed2); 01058 } 01059 } /* sdl_gen_map function */ 01060 01066 int sdl_mapscroll(int dx, int dy) 01067 { 01068 /* Don't sdl_gen_map should take care of the redraw */ 01069 01070 /* a copy of what pngximage does except sdl specfic 01071 * mapsurface->pitch is the length of a scanline in bytes 01072 * including alignment padding 01073 */ 01074 SDL_LockSurface( mapsurface); 01075 if( dy < 0) { 01076 int offset= mapsurface->pitch * (-dy*map_image_size); 01077 memmove( mapsurface->pixels + offset, mapsurface->pixels, 01078 mapsurface->pitch * (mapsurface->h + dy*map_image_size) ); 01079 } 01080 else if( dy > 0) { 01081 int offset= mapsurface->pitch * (dy*map_image_size); 01082 memmove( mapsurface->pixels, mapsurface->pixels + offset, 01083 mapsurface->pitch * (mapsurface->h - dy*map_image_size) ); 01084 } 01085 01086 if (dx) { 01087 int y; 01088 for( y= 0; y < mapsurface->h; y++) { 01089 if( dx < 0) { 01090 char* start_of_row= mapsurface->pixels + mapsurface->pitch * y; 01091 int offset= ( mapsurface->format->BytesPerPixel * map_image_size * -dx); 01092 memmove( start_of_row + offset, start_of_row, 01093 mapsurface->pitch - offset); 01094 } 01095 else { 01096 char* start_of_row= mapsurface->pixels + mapsurface->pitch * y; 01097 int offset= ( mapsurface->format->BytesPerPixel * map_image_size * dx); 01098 memmove( start_of_row, start_of_row + offset, 01099 mapsurface->pitch - offset); 01100 } 01101 } 01102 } 01103 SDL_UnlockSurface( mapsurface); 01104 01105 return 1; 01106 } 01107 01108 #endif
1.7.6.1