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