Crossfire Client, Branch
R11627
|
00001 const char * const rcsid_gtk_sdl_c = 00002 "$Id: sdl.c 9190 2008-06-01 08:53:05Z anmaster $"; 00003 00004 /* 00005 CrossFire, A Multiplayer game for X-windows 00006 00007 Copyright (C) 2001 Mark Wedel & Crossfire Development Team 00008 Copyright (C) 1992 Frank Tore Johansen 00009 00010 This program is free software; you can redistribute it and/or modify 00011 it under the terms of the GNU General Public License as published by 00012 the Free Software Foundation; either version 2 of the License, or 00013 (at your option) any later version. 00014 00015 This program is distributed in the hope that it will be useful, 00016 but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 GNU General Public License for more details. 00019 00020 You should have received a copy of the GNU General Public License 00021 along with this program; if not, write to the Free Software 00022 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00023 00024 The author can be reached via e-mail to crossfire-devel@real-time.com 00025 */ 00026 00027 #include <config.h> 00028 #ifdef HAVE_SDL 00029 #include <client-types.h> 00030 #include <SDL.h> 00031 #include <SDL_image.h> 00032 00033 /* Pick up the gtk headers we need */ 00034 #include <gtk/gtk.h> 00035 #include <gdk/gdkx.h> 00036 #include <gdk/gdkkeysyms.h> 00037 00038 #include "gx11.h" 00039 #include <client.h> 00040 #include "mapdata.h" 00041 00042 /* Actual SDL surface the game view is painted on */ 00043 SDL_Surface* mapsurface; 00044 static SDL_Surface* lightmap; 00045 static SDL_Surface* fogmap; 00046 00047 00048 /* Move some of the SDL code to this file here. This makes it easier to share 00049 * between the gnome and gtk client. It also reduces the length of both the gx11.c 00050 * and gnome.c file. It also is more readable, as not as many #ifdef SDL.. #endif 00051 * constructs are needed. 00052 * Note that there may still be some SDL code in gx11.c - some areas are embedded 00053 * so much that it is not easy to remove. 00054 */ 00055 00056 /* these should generally be included by the file including this file. */ 00057 #include <SDL.h> 00058 #include <SDL_image.h> 00059 00060 00061 static void do_SDL_error(const char *SDL_function, const char *file, int line) 00062 { 00063 LOG(LOG_CRITICAL,SDL_function,"SDL error in file %s line %d\n%s", 00064 file, line, SDL_GetError()); 00065 SDL_Quit(); 00066 exit( 1); 00067 } 00068 00069 /* 00070 * Set the pixel at (x, y) to the given value 00071 * NOTE: The surface must be locked before calling this! 00072 * This function is directly grabbed from the SDL docs. 00073 * Note this is not currently used, but is useful enough 00074 * that it should be included. 00075 */ 00076 static void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) 00077 { 00078 int bpp = surface->format->BytesPerPixel; 00079 /* Here p is the address to the pixel we want to set */ 00080 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; 00081 00082 switch(bpp) { 00083 case 1: 00084 *p = pixel; 00085 break; 00086 00087 case 2: 00088 *(Uint16 *)p = pixel; 00089 break; 00090 00091 case 3: 00092 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { 00093 p[0] = (pixel >> 16) & 0xff; 00094 p[1] = (pixel >> 8) & 0xff; 00095 p[2] = pixel & 0xff; 00096 } else { 00097 p[0] = pixel & 0xff; 00098 p[1] = (pixel >> 8) & 0xff; 00099 p[2] = (pixel >> 16) & 0xff; 00100 } 00101 break; 00102 00103 case 4: 00104 *(Uint32 *)p = pixel; 00105 break; 00106 } 00107 } 00108 00109 static void overlay_grid( int re_init, int ax, int ay) 00110 { 00111 00112 static SDL_Surface* grid_overlay; 00113 00114 static int first_pass; 00115 00116 int x= 0; 00117 int y= 0; 00118 SDL_Rect dst; 00119 Uint32 *pixel; 00120 SDL_PixelFormat* fmt; 00121 00122 /* Need to convert back to screen coordinates */ 00123 ax-= pl_pos.x; 00124 ay-= pl_pos.y; 00125 00126 if( re_init == TRUE) 00127 { 00128 if( grid_overlay) 00129 SDL_FreeSurface( grid_overlay); 00130 00131 first_pass= 0; 00132 grid_overlay= NULL; 00133 } 00134 00135 if( grid_overlay == NULL) 00136 { 00137 grid_overlay= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, 00138 use_config[CONFIG_MAPWIDTH]*map_image_size, 00139 use_config[CONFIG_MAPHEIGHT]*map_image_size, 00140 mapsurface->format->BitsPerPixel, 00141 mapsurface->format->Rmask, 00142 mapsurface->format->Gmask, 00143 mapsurface->format->Bmask, 00144 mapsurface->format->Amask); 00145 if( grid_overlay == NULL) 00146 do_SDL_error( "CreateRGBSurface", __FILE__, __LINE__); 00147 00148 grid_overlay= SDL_DisplayFormatAlpha( grid_overlay); 00149 00150 first_pass= 0; 00151 } 00152 00153 /* 00154 * If this is our first time drawing the grid, we need to build up the 00155 * grid overlay 00156 */ 00157 if( first_pass== 0) 00158 { 00159 00160 /* Red pixels around the edge and along image borders 00161 * fully transparent pixels everywhere else 00162 */ 00163 00164 fmt= grid_overlay->format; 00165 for( x= 0; x < map_image_size*use_config[CONFIG_MAPWIDTH]; x++) 00166 { 00167 for( y= 0; y < map_image_size*use_config[CONFIG_MAPHEIGHT]; y++) 00168 { 00169 /* FIXME: Only works for 32 bit displays right now */ 00170 pixel= (Uint32*)grid_overlay->pixels+y*grid_overlay->pitch/4+x; 00171 00172 if( x == 0 || y == 0 || 00173 ((x % map_image_size) == 0) || ((y % map_image_size) == 0 ) || 00174 y == use_config[CONFIG_MAPHEIGHT]*map_image_size-1 || x == use_config[CONFIG_MAPWIDTH]*map_image_size -1 ) 00175 { 00176 *pixel= SDL_MapRGBA( fmt, 255, 0, 0, SDL_ALPHA_OPAQUE); 00177 } 00178 else 00179 { 00180 *pixel= SDL_MapRGBA( fmt, 0, 0, 0, SDL_ALPHA_TRANSPARENT); 00181 } 00182 } 00183 } 00184 first_pass= 1; 00185 00186 /* 00187 * If this is our first pass then we need to overlay the entire grid 00188 * now. Otherwise we just update the tile we are on 00189 */ 00190 dst.x= 0; 00191 dst.y= 0; 00192 dst.w= map_image_size*use_config[CONFIG_MAPWIDTH]; 00193 dst.h= map_image_size*use_config[CONFIG_MAPHEIGHT]; 00194 SDL_BlitSurface( grid_overlay, NULL, mapsurface, &dst); 00195 } 00196 else 00197 { 00198 dst.x= ax* map_image_size; 00199 dst.y= ay* map_image_size; 00200 dst.w= map_image_size; 00201 dst.h= map_image_size; 00202 /* One to one pixel mapping of grid and mapsurface so we 00203 * can share the SDL_Rect 00204 */ 00205 SDL_BlitSurface( grid_overlay, &dst, mapsurface, &dst); 00206 } 00207 00208 return; 00209 } 00210 00211 /* 00212 * Takes two args, the first is the GtkWindow to draw on, this should always 00213 * be 'drawingarea'. The second is a boolean, if 0 then the whole 00214 * SDL system in initialized or reinited if already run once before, 00215 * if non zero then only the lightmap is rebuilt, if we switch between 00216 * per-pixel or per-tile lighting 00217 */ 00218 void init_SDL( GtkWidget* sdl_window, int just_lightmap) 00219 { 00220 00221 char SDL_windowhack[32]; 00222 00223 if( just_lightmap == 0) { 00224 g_assert( sdl_window != NULL); 00225 if( SDL_WasInit( SDL_INIT_VIDEO) != 0) { 00226 if( lightmap) 00227 SDL_FreeSurface( lightmap); 00228 if( mapsurface) 00229 SDL_FreeSurface( mapsurface); 00230 SDL_Quit(); 00231 } 00232 00233 /* 00234 * SDL hack to tell SDL which xwindow to paint onto 00235 */ 00236 sprintf( SDL_windowhack, "SDL_WINDOWID=%ld", 00237 GDK_WINDOW_XWINDOW(sdl_window->window) ); 00238 putenv( SDL_windowhack); 00239 00240 if( SDL_Init( SDL_INIT_VIDEO) < 0) 00241 { 00242 LOG(LOG_CRITICAL,"gtk::init_SDL", "Could not initialize SDL: %s", SDL_GetError()); 00243 gtk_main_quit(); 00244 } 00245 00246 mapsurface= SDL_SetVideoMode( map_image_size*use_config[CONFIG_MAPWIDTH], map_image_size*use_config[CONFIG_MAPHEIGHT], 0, 00247 SDL_HWSURFACE|SDL_DOUBLEBUF); 00248 00249 if( mapsurface == NULL) 00250 { 00251 do_SDL_error( "SetVideoMode", __FILE__, __LINE__); 00252 } 00253 00254 if( fogmap) 00255 SDL_FreeSurface( fogmap); 00256 00257 fogmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size, 00258 map_image_size, 00259 mapsurface->format->BitsPerPixel, 00260 mapsurface->format->Rmask, 00261 mapsurface->format->Gmask, 00262 mapsurface->format->Bmask, 00263 mapsurface->format->Amask); 00264 00265 if( fogmap == NULL) 00266 { 00267 do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__); 00268 } 00269 00270 /* 00271 * This is a persurface alpha value, not an alpha channel value. 00272 * So this surface doesn't actually need a full alpha channel 00273 */ 00274 if( SDL_SetAlpha( fogmap, SDL_SRCALPHA|SDL_RLEACCEL, 128) < 0) 00275 { 00276 do_SDL_error( "SDL_SetAlpha", __FILE__, __LINE__); 00277 } 00278 } 00279 00280 if( just_lightmap != 0 && lightmap) 00281 SDL_FreeSurface( lightmap); 00282 00283 lightmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size, 00284 map_image_size, 00285 mapsurface->format->BitsPerPixel, 00286 mapsurface->format->Rmask, 00287 mapsurface->format->Gmask, 00288 mapsurface->format->Bmask, 00289 mapsurface->format->Amask); 00290 if( lightmap == NULL) 00291 { 00292 do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__); 00293 } 00294 00295 if(use_config[CONFIG_LIGHTING] != CFG_LT_TILE) 00296 { 00297 /* Convert surface to have a full alpha channel if we are doing 00298 * per-pixel lighting */ 00299 lightmap= SDL_DisplayFormatAlpha( lightmap); 00300 if( lightmap == NULL) 00301 { 00302 do_SDL_error( "DisplayFormatAlpha", __FILE__, __LINE__); 00303 } 00304 } 00305 00306 if(use_config[CONFIG_SHOWGRID] == TRUE) 00307 { 00308 overlay_grid( TRUE, 0, 0); 00309 } 00310 } 00311 00312 00313 /* Draw a alpha square on lightmap. Topleft corner is at startx,starty. 00314 * values for topleft, topright, bottomleft,bottomright corners are knowns 00315 * This use bilinear interpolation for other points. Width and heights are given 00316 * for surrouding known values square. Interpolation is done in a small square whose 00317 * coordinates are given by start{x|y} and end{x|y} 00318 * dest{x|y} is top-left corner in destination map. 00319 * Tchize 22 May 2004 00320 */ 00321 00322 static void drawquarterlightmap_sdl(int tl, int tr, int bl, int br, /*colors*/ 00323 int width, int height, /*color square size*/ 00324 int startx, int starty, int endx, int endy, /*interpolation region*/ 00325 int destx, int desty){ /*where in lightmap to save result*/ 00326 int x,y; 00327 int top,bottom,val; 00328 for (x=startx;x<endx;x++){ 00329 top= ((x*(tr-tl))/ width)+tl; /*linear interpolation for top color*/ 00330 bottom= ((x*(br-bl))/ width)+bl; /*linear interpolation for bottom color*/ 00331 for (y=starty;y<endy;y++){ 00332 val=((y*(bottom-top))/height)+top; /*linear interpolation between top and bottom*/ 00333 if (val>255) 00334 val=255; 00335 if (val<0) 00336 val=0; 00337 /*printf("writing pel at %d,%d\n",destx+x,desty+y);*/ 00338 putpixel(lightmap, destx+x-startx, desty+y-starty, 00339 SDL_MapRGBA(lightmap->format, 0, 0, 0, val)); 00340 } 00341 } 00342 } 00343 00344 /* Do the lighting on a per pixel basis. 00345 * x and y are coordinates on the drawable map surfaces (but in terms of 00346 * spaces, not pixels). mx and my are indexes into the 00347 * the_map.cells[][] array. 00348 * All the below goes out and figures lighting for each pixel on 00349 * the space, and creates a surface (with alpha) that is then put on 00350 * top of the exiting map space. 00351 * 00352 * TODO: I think it is possible to greatly speed this up by using 00353 * pre-generated darkness masks. Doing all the possibilities 00354 * would be 3125 images (5 positions, each with 5 values, 5^5), 00355 * Doing it based on quadrants would only reduce that to 1024. 00356 * But I _think_ it may be possible to do this with just 64 images 00357 * (2^5 + one 90 degree rotation of the same) based on quadrants. 00358 * ie, do a 16x16 image with the 5 gradiants (0,64,128,255 at the 00359 * left, and each of those values at the right). Then do the same 00360 * idea for top and bottom. For any single quadrant, you would 00361 * then merge thse two values (which can be done with a fast blit), 00362 * corresponding to the right values, and you do the same thing for 00363 * the other four quadrants. Note this only works so long as 00364 * 4 lighting values are used - if more are added, this quickly 00365 * breaks. Also, if lighting colored effects are desired, 00366 * this also doesn't work very well. 00367 * 00368 * For now, I've just kept the old logic. MSW 2001-10-09 00369 */ 00370 00371 /* See note below about ALPHA_FUDGE - used to adjust lighting effects some */ 00372 00373 #define ALPHA_FUDGE(x) (2*(x) / 3) 00374 static void do_sdl_per_pixel_lighting(int x, int y, int mx, int my) 00375 { 00376 int dark0, dark1, dark2, dark3, dark4; 00377 SDL_Rect dst; 00378 00379 /* I use dark0 -> dark4 in the order to keep it similar to 00380 * the old code. 00381 */ 00382 dark0 = the_map.cells[mx][my].darkness; 00383 00384 if (y-1 < 0 || !the_map.cells[mx][my-1].have_darkness) dark1 = dark0; 00385 else dark1 = the_map.cells[mx][my-1].darkness; 00386 00387 if (x+1 >= use_config[CONFIG_MAPWIDTH] || !the_map.cells[mx+1][my].have_darkness) dark2 = dark0; 00388 else dark2 = the_map.cells[mx+1][my].darkness; 00389 00390 if (y+1 >= use_config[CONFIG_MAPHEIGHT] || !the_map.cells[mx][my+1].have_darkness) dark3 = dark0; 00391 else dark3 = the_map.cells[mx][my+1].darkness; 00392 00393 if (x-1 < 0 || !the_map.cells[mx-1][my].have_darkness) dark4 = dark0; 00394 else dark4 = the_map.cells[mx-1][my].darkness; 00395 00396 /* If they are all the same, processing is easy 00397 * 00398 * Note, the best lightining algorithm also uses diagonals 00399 * so we should check the diagonals are same too 00400 * We don't check for now, simply do all raw computation on best mode 00401 * Tchize 19 may 2004 00402 */ 00403 if (dark0 == dark1 && dark0 == dark2 && dark0 == dark3 && dark0 == dark4 && (use_config[CONFIG_LIGHTING] != CFG_LT_PIXEL_BEST)) { 00404 dst.x = x * map_image_size; 00405 dst.y = y * map_image_size; 00406 dst.w = map_image_size; 00407 dst.h = map_image_size; 00408 00409 if (dark0 == 255) { 00410 SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0)); 00411 } else if (the_map.cells[mx][my].darkness != 0) { 00412 SDL_FillRect(lightmap,NULL, SDL_MapRGBA(lightmap->format, 0, 0, 0, the_map.cells[mx][my].darkness)); 00413 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00414 } 00415 return; 00416 } 00417 00418 00419 if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL ) { 00420 /* This almost works as well as the per pixel code below, but does have some various 00421 * artifacts in the drawing. It uses the same logic as the per pixel code below, 00422 * bit since SDL does the blit, the alpha handling ends up being different 00423 * (I think it ends up being additive). This results in the darkness being 00424 * darker, but you also don't get the smooth effects. If you divide all the values 00425 * by 2 (change ALPHA_FUDGE), the blending is smooth, but now the things are not dark 00426 * enough, so the blending aganst solid black spaces does not look good. 00427 * The reason this code is of interest is that on my system, it is about 50% 00428 * faster than the code below (25 ms to darkness the church in the starting 00429 * town vs 50 ms for the code further down) 00430 * Setting ALPHA_FUDGE to 2/3 seems to reduce the artifacts described above 00431 * to fairly minimal levels, while still keeping things dark enough. 00432 * MSW 2001-10-12 00433 */ 00434 00435 int i; 00436 00437 if (dark1 == dark0) { 00438 /* If we don't have usable darkness at the top, then this entire region 00439 * should be the same value. Likewise, if the top value and center value 00440 * are the same, we can do the entire region. 00441 */ 00442 dst.x=0; 00443 dst.y=0; 00444 dst.w = map_image_size; 00445 dst.h = map_image_half_size; 00446 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00447 } 00448 else for (i=0; i<map_image_half_size; i++) { 00449 /* Need to do it line by line */ 00450 00451 dst.x = 0; 00452 dst.y = i; 00453 dst.w = map_image_size; 00454 dst.h = 1; 00455 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00456 ALPHA_FUDGE((map_image_half_size - i) * dark1 + i * dark0)/map_image_half_size)); 00457 00458 } 00459 /* All the following blocks are basically the same as above, just different 00460 * darkness areas. 00461 */ 00462 if (dark3 == dark0) { 00463 dst.x=0; 00464 dst.y=map_image_half_size; 00465 dst.w = map_image_size; 00466 dst.h = map_image_half_size; 00467 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00468 } 00469 else for (i=map_image_half_size; i<map_image_size; i++) { 00470 /* Need to do it line by line */ 00471 00472 dst.x = 0; 00473 dst.y = i; 00474 dst.w = map_image_size; 00475 dst.h = 1; 00476 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00477 ALPHA_FUDGE(dark0*(map_image_size-i) + dark3*(i-map_image_half_size)) / map_image_half_size)); 00478 } 00479 /* Blit this to the screen now. Otherwise, we need to look at the alpha values 00480 * and re-average. 00481 */ 00482 00483 dst.x= x * map_image_size; 00484 dst.y= y * map_image_size; 00485 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00486 00487 if (dark4 == dark0) { 00488 dst.x=0; 00489 dst.y=0; 00490 dst.w = map_image_half_size; 00491 dst.h = map_image_size; 00492 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00493 } 00494 else for (i=0; i<map_image_half_size; i++) { 00495 /* Need to do it line by line */ 00496 dst.x = i; 00497 dst.y = 0; 00498 dst.w = 1; 00499 dst.h = map_image_size; 00500 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00501 ALPHA_FUDGE(dark4*(map_image_half_size-i) + dark0*i) / map_image_half_size)); 00502 } 00503 if (dark2 == dark0) { 00504 dst.x=map_image_half_size; 00505 dst.y=0; 00506 dst.w = map_image_half_size; 00507 dst.h = map_image_size; 00508 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0))); 00509 } 00510 else for (i=map_image_half_size; i<map_image_size; i++) { 00511 /* Need to do it line by line */ 00512 00513 dst.x = i; 00514 dst.y = 0; 00515 dst.w = 1; 00516 dst.h = map_image_size; 00517 SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, 00518 ALPHA_FUDGE(dark0*(map_image_size-i) + dark2*(i-map_image_half_size)) / map_image_half_size)); 00519 } 00520 dst.x= x * map_image_size; 00521 dst.y= y * map_image_size; 00522 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00523 } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST ) { 00524 #if 0 00525 int dx,dy; 00526 static int *darkx=NULL, *darky=NULL,darkx_allocated=0; 00527 00528 /* Generated stored for the darkx[] array. Do it dynamically, but 00529 * only allocate if the size needs to be expanded to keep performance 00530 * better. darkx could be null in the initial case, but realloc should 00531 * just treat that as a malloc (so according to the man page) 00532 */ 00533 if (map_image_size > darkx_allocated) { 00534 darkx = realloc(darkx, map_image_size * sizeof(int)); 00535 darky = realloc(darky, map_image_size * sizeof(int)); 00536 darkx_allocated = map_image_size; 00537 } 00538 00539 for( dx= 0; dx < map_image_half_size; dx++) 00540 darkx[dx]= (dark4*(map_image_half_size-dx) + dark0*dx) / map_image_half_size; 00541 for( dx= map_image_half_size; dx < map_image_size; dx++) 00542 darkx[dx] = (dark0*(map_image_size-dx) + dark2*(dx-map_image_half_size)) / map_image_half_size; 00543 00544 for( dy= 0; dy < map_image_half_size; dy++) 00545 darky[dy]= (dark1*(map_image_half_size-dy) + dark0*dy) / map_image_half_size; 00546 for( dy= map_image_half_size; dy < map_image_size; dy++) 00547 darky[dy] = (dark0*(map_image_size-dy) + dark3*(dy-map_image_half_size)) / map_image_half_size; 00548 00549 SDL_LockSurface( lightmap); 00550 00551 for (dx=0; dx<map_image_size; dx++) 00552 for (dy=0; dy<map_image_size; dy++) 00553 putpixel(lightmap, dx, dy, SDL_MapRGBA(lightmap->format, 0, 0, 0,(darkx[dx] + darky[dy])/2)); 00554 #else 00555 /*we need additionnal surrounding infos*/ 00556 int dark5, dark6, dark7, dark8; 00557 if ( (y-1 < 0) || (x+1 >= use_config[CONFIG_MAPWIDTH]) 00558 || !the_map.cells[mx+1][my-1].have_darkness) dark5 = (dark1+dark2)>>1; /*(fast div 2)*/ 00559 else dark5 = the_map.cells[mx+1][my-1].darkness; 00560 00561 if ( (x+1 >= use_config[CONFIG_MAPWIDTH]) 00562 || (y+1 >= use_config[CONFIG_MAPHEIGHT]) 00563 || !the_map.cells[mx+1][my+1].have_darkness) dark6 = (dark2+dark3)>>1; 00564 else dark6 = the_map.cells[mx+1][my+1].darkness; 00565 00566 if ( (y+1 >= use_config[CONFIG_MAPHEIGHT]) || (x-1 < 0) 00567 || !the_map.cells[mx-1][my+1].have_darkness) dark7 = (dark3+dark4)>>1; 00568 else dark7 = the_map.cells[mx-1][my+1].darkness; 00569 00570 if ( (x-1 < 0) || (y-1 < 0) 00571 || !the_map.cells[mx-1][my-1].have_darkness) dark8 = (dark4+dark1)>>1; 00572 else dark8 = the_map.cells[mx-1][my-1].darkness; 00573 /*upper left lightmap quarter*/ 00574 drawquarterlightmap_sdl(dark8, dark1, dark4, dark0, /*colors*/ 00575 map_image_size, map_image_size, /*color square size*/ 00576 map_image_half_size, map_image_half_size, map_image_size, map_image_size, /*interpolation region*/ 00577 0, 0); /*where in lightmap to save result*/ 00578 /*upper right lightmap quarter*/ 00579 drawquarterlightmap_sdl(dark1, dark5, dark0, dark2, /*colors*/ 00580 map_image_size, map_image_size, /*color square size*/ 00581 0, map_image_half_size, map_image_half_size, map_image_size, /*interpolation region*/ 00582 map_image_half_size, 0); /*where in lightmap to save result*/ 00583 /*bottom left lightmap quarter*/ 00584 drawquarterlightmap_sdl(dark4, dark0, dark7, dark3, /*colors*/ 00585 map_image_size, map_image_size, /*color square size*/ 00586 map_image_half_size, 0, map_image_size, map_image_half_size, /*interpolation region*/ 00587 0, map_image_half_size); /*where in lightmap to save result*/ 00588 /*bottom right lightmap quarter*/ 00589 drawquarterlightmap_sdl(dark0, dark2, dark3, dark6, /*colors*/ 00590 map_image_size, map_image_size, /*color square size*/ 00591 0, 0, map_image_half_size, map_image_half_size, /*interpolation region*/ 00592 map_image_half_size, map_image_half_size); /*where in lightmap to save result*/ 00593 #endif 00594 dst.w= map_image_size; 00595 dst.h= map_image_size; 00596 dst.x= x * map_image_size; 00597 dst.y= y * map_image_size; 00598 SDL_UnlockSurface(lightmap); 00599 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00600 } 00601 } 00602 /* Draw anything in adjacent squares that could smooth on given square 00603 * mx,my square to smooth on. you should not call this function to 00604 * smooth on a 'completly black' square. (simply for visual result) 00605 * layer layer to examine (we smooth only one layer at a time) 00606 * dst place on the mapwindow to draw 00607 */ 00608 static void drawsmooth_sdl (int mx,int my,int layer,SDL_Rect dst){ 00609 static int dx[8]={0,1,1,1,0,-1,-1,-1}; 00610 static int dy[8]={-1,-1,0,1,1,1,0,-1}; 00611 static int bweights[8]={2,0,4,0,8,0,1,0}; 00612 static int cweights[8]={0,2,0,4,0,8,0,1}; 00613 static int bc_exclude[8]={ 00614 1+2,/*north exclude northwest (bit0) and northeast(bit1)*/ 00615 0, 00616 2+4,/*east exclude northeast and southeast*/ 00617 0, 00618 4+8,/*and so on*/ 00619 0, 00620 8+1, 00621 0 00622 }; 00623 int partdone[8]={0,0,0,0,0,0,0,0}; 00624 int slevels[8]; 00625 int sfaces[8]; 00626 int i,lowest,weight,weightC; 00627 int emx,emy; 00628 int smoothface; 00629 int hasFace = 0; 00630 SDL_Rect src; 00631 for (i=0;i<=layer;i++) 00632 hasFace |= the_map.cells[mx][my].heads[i].face; 00633 if (!hasFace 00634 || !CAN_SMOOTH(the_map.cells[mx][my], layer)) { 00635 return; 00636 } 00637 00638 src.w = dst.w; 00639 src.h = dst.h; 00640 00641 for (i=0;i<8;i++){ 00642 emx=mx+dx[i]; 00643 emy=my+dy[i]; 00644 if ( (emx<0) || (emy<0) || (the_map.x<=emx) || (the_map.y<=emy)){ 00645 slevels[i]=0; 00646 sfaces[i]=0; /*black picture*/ 00647 } 00648 else if (the_map.cells[emx][emy].smooth[layer]<=the_map.cells[mx][my].smooth[layer]){ 00649 slevels[i]=0; 00650 sfaces[i]=0; /*black picture*/ 00651 }else{ 00652 slevels[i]=the_map.cells[emx][emy].smooth[layer]; 00653 sfaces[i]=pixmaps[the_map.cells[emx][emy].heads[layer].face]->smooth_face; 00654 } 00655 } 00656 /* ok, now we have a list of smoothlevel higher than current square. 00657 * there are at most 8 different levels. so... let's check 8 times 00658 * for the lowest one (we draw from botto to top!). 00659 */ 00660 lowest=-1; 00661 while (1){ 00662 lowest = -1; 00663 for (i=0;i<8;i++){ 00664 if ( (slevels[i]>0) && (!partdone[i]) && 00665 ((lowest<0) || (slevels[i]<slevels[lowest])) 00666 ) 00667 lowest=i; 00668 } 00669 if (lowest<0) 00670 break; /*no more smooth to do on this square*/ 00671 /*printf ("hey, must smooth something...%d\n",sfaces[lowest]);*/ 00672 /*here we know 'what' to smooth*/ 00673 /* we need to calculate the weight 00674 * for border and weight for corners. 00675 * then we 'markdone' 00676 * the corresponding squares 00677 */ 00678 /*first, the border, which may exclude some corners*/ 00679 weight=0; 00680 weightC=15; /*works in backward. remove where there is nothing*/ 00681 /*for (i=0;i<8;i++) 00682 cornermask[i]=1;*/ 00683 for (i=0;i<8;i++){ /*check all nearby squares*/ 00684 if ( (slevels[i]==slevels[lowest]) && 00685 (sfaces[i]==sfaces[lowest])){ 00686 partdone[i]=1; 00687 weight=weight+bweights[i]; 00688 weightC&=~bc_exclude[i]; 00689 }else{ 00690 /*must rmove the weight of a corner if not in smoothing*/ 00691 weightC&=~cweights[i]; 00692 } 00693 00694 } 00695 /*We can't do this before since we need the partdone to be adjusted*/ 00696 if (sfaces[lowest]<=0) 00697 continue; /*Can't smooth black*/ 00698 smoothface=sfaces[lowest]; 00699 if (smoothface<=0){ 00700 continue; /*picture for smoothing not yet available*/ 00701 } 00702 /* now, it's quite easy. We must draw using a 32x32 part of 00703 * the picture smoothface. 00704 * This part is located using the 2 weights calculated: 00705 * (32*weight,0) and (32*weightC,32) 00706 */ 00707 if ( (!pixmaps[smoothface]->map_image) || 00708 (pixmaps[smoothface] == pixmaps[0])) 00709 continue; /*don't have the picture associated*/ 00710 if (weight>0){ 00711 src.x=map_image_size*weight; 00712 src.y=0; 00713 if (the_map.cells[mx][my].cleared) { 00714 if (SDL_BlitSurface(pixmaps[smoothface]->fog_image, 00715 &src, mapsurface, &dst)) 00716 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00717 } else { 00718 if (SDL_BlitSurface(pixmaps[smoothface]->map_image, 00719 &src, mapsurface, &dst)) 00720 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00721 } 00722 } 00723 if (weightC>0){ 00724 src.x=map_image_size*weightC; 00725 src.y=map_image_size; 00726 if (the_map.cells[mx][my].cleared) { 00727 if (SDL_BlitSurface(pixmaps[smoothface]->fog_image, 00728 &src, mapsurface, &dst)) 00729 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00730 } else { 00731 if (SDL_BlitSurface(pixmaps[smoothface]->map_image, 00732 &src, mapsurface, &dst)) 00733 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00734 } 00735 } 00736 }/*while there's some smooth to do*/ 00737 } 00738 00739 /* This function tells if a specifi square need to be redrawn 00740 * Reason for redrawing can be content change, smoothing change or 00741 * surrounding lightning change. Conditions depend on type of 00742 * lightning code used. 00743 * Tchize 22 May 2004 00744 */ 00745 static int sdl_square_need_redraw(int mx, int my){ 00746 #define SDL_LIGHT_CHANGED(_x_,_y_) (!mapdata_is_inside((_x_), (_y_)) ? 0 : the_map.cells[_x_][_y_].need_update) 00747 if ( (the_map.cells[mx][my].need_update) || (the_map.cells[mx][my].need_resmooth)) 00748 return 1; 00749 00750 if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL){ 00751 /*The fast per pixel uses 4 additionnal datas which may have changed:*/ 00752 /*we suppose need_redraw -> lightr may have change. in future maybe we could add a need_relight toggle*/ 00753 if (SDL_LIGHT_CHANGED(mx-1,my) || 00754 SDL_LIGHT_CHANGED(mx,my-1) || 00755 SDL_LIGHT_CHANGED(mx+1,my) || 00756 SDL_LIGHT_CHANGED(mx,my+1)) 00757 return 1; 00758 } 00759 if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST){ 00760 if (SDL_LIGHT_CHANGED(mx-1,my) || 00761 SDL_LIGHT_CHANGED(mx,my-1) || 00762 SDL_LIGHT_CHANGED(mx+1,my) || 00763 SDL_LIGHT_CHANGED(mx,my+1) || 00764 SDL_LIGHT_CHANGED(mx-1,my+1) || 00765 SDL_LIGHT_CHANGED(mx-1,my-1) || 00766 SDL_LIGHT_CHANGED(mx+1,my-1) || 00767 SDL_LIGHT_CHANGED(mx+1,my+1) ) 00768 return 1; 00769 } 00770 return 0; /*no need to redraw :)*/ 00771 } 00772 00773 static void display_mapcell(int ax, int ay, int mx, int my) 00774 { 00775 SDL_Rect dst, src; 00776 int layer; 00777 00778 /* First, we need to black out this space. */ 00779 dst.x = ax*map_image_size; 00780 dst.y = ay*map_image_size; 00781 dst.w = map_image_size; 00782 dst.h = map_image_size; 00783 SDL_FillRect(mapsurface, &dst, SDL_MapRGB(mapsurface->format, 0, 0, 0)); 00784 00785 /* now draw the different layers. Only draw if using fog of war or the 00786 * space isn't clear. 00787 */ 00788 if (use_config[CONFIG_FOGWAR] || !the_map.cells[mx][my].cleared) { 00789 for (layer=0; layer<MAXLAYERS; layer++) { 00790 int sx, sy; 00791 00792 /* draw single-tile faces first */ 00793 int face = mapdata_face(ax, ay, layer); 00794 if (face > 0 && pixmaps[face]->map_image != NULL) { 00795 int w = pixmaps[face]->map_width; 00796 int h = pixmaps[face]->map_height; 00797 /* add one to the size values to take into account the actual width of the space */ 00798 src.x = w-map_image_size; 00799 src.y = h-map_image_size; 00800 src.w = map_image_size; 00801 src.h = map_image_size; 00802 dst.x = ax*map_image_size; 00803 dst.y = ay*map_image_size; 00804 if (the_map.cells[mx][my].cleared) { 00805 if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst)) 00806 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00807 } else { 00808 if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst)) 00809 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00810 } 00811 00812 } 00813 /* Sometimes, it may happens we need to draw the smooth while there 00814 * is nothing to draw at that layer (but there was something at lower 00815 * layers). This is handled here. The else part is to take into account 00816 * cases where the smooth as already been handled 2 code lines before 00817 */ 00818 if (use_config[CONFIG_SMOOTH]) 00819 drawsmooth_sdl (mx,my,layer,dst); 00820 00821 /* draw big faces last (should overlap other objects) */ 00822 face = mapdata_bigface(ax, ay, layer, &sx, &sy); 00823 if (face > 0 && pixmaps[face]->map_image != NULL) { 00824 /* We have to handle images that are not an equal 00825 * multiplier of map_image_size. See 00826 * display_mapcell() in gtk-v2/src/map.c for 00827 * more details on this logic, since it is basically 00828 * the same. 00829 */ 00830 int dx, dy, sourcex, sourcey, offx, offy; 00831 00832 dx = pixmaps[face]->map_width % map_image_size; 00833 offx = dx?(map_image_size -dx):0; 00834 00835 if (sx) { 00836 sourcex = sx * map_image_size - offx ; 00837 offx=0; 00838 } else { 00839 sourcex=0; 00840 } 00841 00842 dy = pixmaps[face]->map_height % map_image_size; 00843 offy = dy?(map_image_size -dy):0; 00844 00845 if (sy) { 00846 sourcey = sy * map_image_size - offy; 00847 offy=0; 00848 } else { 00849 sourcey=0; 00850 } 00851 00852 src.x = sourcex; 00853 src.y = sourcey; 00854 src.w = map_image_size - offx; 00855 src.h = map_image_size - offy; 00856 dst.x = ax*map_image_size + offx; 00857 dst.y = ay*map_image_size + offy; 00858 00859 if (the_map.cells[mx][my].cleared) { 00860 if (SDL_BlitSurface(pixmaps[face]->fog_image, &src, mapsurface, &dst)) 00861 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00862 } else { 00863 if (SDL_BlitSurface(pixmaps[face]->map_image, &src, mapsurface, &dst)) 00864 do_SDL_error( "BlitSurface", __FILE__, __LINE__); 00865 } 00866 } /* else for processing the layers */ 00867 } 00868 } 00869 00870 if (use_config[CONFIG_LIGHTING] == CFG_LT_TILE) { 00871 dst.x = ax*map_image_size; 00872 dst.y = ay*map_image_size; 00873 dst.w = map_image_size; 00874 dst.h = map_image_size; 00875 00876 /* Note - Instead of using a lightmap, I just fillrect 00877 * directly onto the map surface - I would think this should be 00878 * faster 00879 */ 00880 if (the_map.cells[mx][my].darkness == 255) { 00881 SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0)); 00882 } else if (the_map.cells[mx][my].darkness != 0) { 00883 SDL_SetAlpha(lightmap, SDL_SRCALPHA|SDL_RLEACCEL, the_map.cells[mx][my].darkness); 00884 SDL_BlitSurface(lightmap, NULL, mapsurface, &dst); 00885 } 00886 } else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL || use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) { 00887 do_sdl_per_pixel_lighting(ax, ay, mx, my); 00888 } 00889 } 00890 00891 /* This generates a map in SDL mode. 00892 * 00893 * I had to totally change the logic on how we do this in SDL mode - 00894 * to support variable sized images, the old method of generating each 00895 * space does not work, as one space may spill over to the other. 00896 * Instead, we first blit the bottom layer, then the layer above 00897 * that, and so on. This results in the map being drawn a bit 00898 * more correctly. In fact, that logic actually isn't needed, as 00899 * with the new map commands, we know the offset and size of the 00900 * images. 00901 * 00902 * The logic here only redraws spaces that change. The logic in the 00903 * common/commands.c files the odd layers with links for 'big images'. 00904 * for objects on these layers, we look at the size_x and size_y values 00905 * to determine the offset from which we should be blitting. 00906 * 00907 * Old notes, but left in: 00908 * The performance here is very good in most cases - about 30 ms (on my system) 00909 * is used just for my flip at the bottom of the function, drawing only what 00910 * is needed generally saves a lot of time (<15 ms in most cases) compared to the 00911 * 80-120 ms usually needed on a 15x15 map. 00912 */ 00913 00914 void sdl_gen_map(int redraw) { 00915 int mx, my, x, y; 00916 struct timeval tv1, tv2,tv3; 00917 long elapsed1, elapsed2; 00918 00919 static int last_mapwidth=0; 00920 static int last_mapheight=0; 00921 static uint8 *redrawbitmap=NULL; 00922 00923 if (time_map_redraw) 00924 gettimeofday(&tv1, NULL); 00925 00926 /* In per pixel lightning code, some square may have to be 00927 * redrawn just because a surrounding square did change 00928 * However, informations on changed square do get toggle 00929 * during the redraw process. To keep track of which 00930 * squares really need redraw (instead of redrawing eveything in 00931 * per pixel lightning case), we need to save this info in a array 00932 * Tchize, 22 May 2004 00933 */ 00934 if ( (use_config[CONFIG_MAPWIDTH] != last_mapwidth) || 00935 (use_config[CONFIG_MAPHEIGHT] != last_mapheight) ){ 00936 /* reallocate array */ 00937 last_mapwidth=use_config[CONFIG_MAPWIDTH]; 00938 last_mapheight=use_config[CONFIG_MAPHEIGHT]; 00939 redrawbitmap=(uint8*)malloc(sizeof(uint8)*last_mapwidth*last_mapheight); 00940 } 00941 if (redrawbitmap==NULL){ 00942 LOG(LOG_ERROR,"sdl::sdl_gen_map", 00943 "The redraw bitmap is NULL. Not enough memory? (width:%d,height:%d)", 00944 last_mapwidth,last_mapheight); 00945 return; /*without this bitmap, no drawing possible*/ 00946 } 00947 00948 for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) { 00949 for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) { 00950 redrawbitmap[x+y*last_mapwidth]=(uint8)sdl_square_need_redraw(x+pl_pos.x,y+pl_pos.y); 00951 } 00952 } 00953 for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) { 00954 for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) { 00955 /* mx,my represent the spaces on the 'virtual' map (ie, the_map structure). 00956 * x and y (from the for loop) represent the visable screen. 00957 */ 00958 mx = pl_pos.x+x; 00959 my = pl_pos.y+y; 00960 if (redraw || redrawbitmap[x+y*last_mapwidth]) { 00961 display_mapcell(x, y, mx, my); 00962 the_map.cells[mx][my].need_update = 0; 00963 the_map.cells[mx][my].need_resmooth = 0; 00964 } 00965 } 00966 } 00967 00968 if (time_map_redraw) 00969 gettimeofday(&tv2, NULL); 00970 00971 SDL_Flip(mapsurface); 00972 00973 if (time_map_redraw) { 00974 gettimeofday(&tv3, NULL); 00975 elapsed1 = (tv2.tv_sec - tv1.tv_sec)*1000000 + (tv2.tv_usec - tv1.tv_usec); 00976 elapsed2 = (tv3.tv_sec - tv2.tv_sec)*1000000 + (tv3.tv_usec - tv2.tv_usec); 00977 00978 /* I care about performance for 'long' updates, so put the check in to make 00979 * these a little more noticable */ 00980 if ((elapsed1 + elapsed2)>10000) 00981 LOG(LOG_INFO,"gtk::sdl_gen_map","gen took %7ld, flip took %7ld, total = %7ld", 00982 elapsed1, elapsed2, elapsed1 + elapsed2); 00983 } 00984 } /* sdl_gen_map function */ 00985 00986 int sdl_mapscroll(int dx, int dy) 00987 { 00988 /* a copy of what pngximage does except sdl specfic 00989 * mapsurface->pitch is the length of a scanline in bytes 00990 * including alignment padding 00991 */ 00992 SDL_LockSurface( mapsurface); 00993 if( dy < 0) { 00994 int offset= mapsurface->pitch * (-dy*map_image_size); 00995 memmove( mapsurface->pixels + offset, mapsurface->pixels, 00996 mapsurface->pitch * (mapsurface->h + dy*map_image_size) ); 00997 } 00998 else if( dy > 0) { 00999 int offset= mapsurface->pitch * (dy*map_image_size); 01000 memmove( mapsurface->pixels, mapsurface->pixels + offset, 01001 mapsurface->pitch * (mapsurface->h - dy*map_image_size) ); 01002 } 01003 01004 if (dx) { 01005 int y; 01006 for( y= 0; y < mapsurface->h; y++) { 01007 if( dx < 0) { 01008 char* start_of_row= mapsurface->pixels + mapsurface->pitch * y; 01009 int offset= ( mapsurface->format->BytesPerPixel * map_image_size * -dx); 01010 memmove( start_of_row + offset, start_of_row, 01011 mapsurface->pitch - offset); 01012 } 01013 else { 01014 char* start_of_row= mapsurface->pixels + mapsurface->pitch * y; 01015 int offset= ( mapsurface->format->BytesPerPixel * map_image_size * dx); 01016 memmove( start_of_row, start_of_row + offset, 01017 mapsurface->pitch - offset); 01018 } 01019 } 01020 } 01021 SDL_UnlockSurface( mapsurface); 01022 01023 return 1; 01024 } 01025 01026 #endif