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