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