Crossfire Client, Branch  R11627
map.c
Go to the documentation of this file.
00001 const char * const rcsid_gtk2_map_c =
00002     "$Id: map.c 11117 2009-01-05 07:11:04Z mwedel $";
00003 /*
00004     Crossfire client, a client program for the crossfire program.
00005 
00006     Copyright (C) 2005 Mark Wedel & Crossfire Development Team
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022     The author can be reached via e-mail to crossfire@metalforge.org
00023 */
00024 
00031 #include <config.h>
00032 #include <stdlib.h>
00033 #include <sys/stat.h>
00034 #ifndef WIN32
00035 #include <unistd.h>
00036 #endif
00037 #include <png.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 <time.h>
00046 #include <gdk/gdkwin32.h>
00047 #endif
00048 #include <gdk/gdkkeysyms.h>
00049 
00050 #include "client-types.h"
00051 #include "image.h"
00052 #include "main.h"
00053 #include "client.h"
00054 #include "mapdata.h"
00055 #include "gtk2proto.h"
00056 
00057 static uint8 map_updated = 0;
00058 
00059 /*
00060  * Added for fog of war. Current size of the map structure in memory.
00061  * We assume a rectangular map so this is the length of one side.
00062  * command.c needs to know about this so not static
00063  * FIX ME: Don't assume rectangle
00064  */
00065 
00066 PlayerPosition pl_pos;
00067 
00068 GtkWidget *map_drawing_area, *map_notebook;
00069 GdkGC *mapgc;
00070 int map_image_size=DEFAULT_IMAGE_SIZE;
00071 int map_image_half_size=DEFAULT_IMAGE_SIZE/2;
00072 static GdkBitmap *dark1, *dark2, *dark3;
00073 static GdkPixmap *dark;
00074 
00075 /*
00076  * This should really be one of the CONFIG values, or perhaps a checkbox
00077  * someplace that displays frame rate.
00078  */
00079 int time_map_redraw=0;
00080 
00081 #if WIN32
00082 
00088 int gettimeofday(struct timeval* tp, void* tzp) {
00089     DWORD t;
00090     t = timeGetTime();
00091     tp->tv_sec = t / 1000;
00092     tp->tv_usec = t % 1000;
00093     /* 0 indicates that the call succeeded. */
00094     return 0;
00095 }
00096 #endif
00097 
00103 void map_init(GtkWidget *window_root)
00104 {
00105     GladeXML* xml_tree;
00106 
00107     xml_tree = glade_get_widget_tree(GTK_WIDGET(window_root));
00108 
00109     map_drawing_area = glade_xml_get_widget(xml_tree, "drawingarea_map");
00110     map_notebook = glade_xml_get_widget(xml_tree, "map_notebook");
00111 
00112     g_signal_connect ((gpointer) map_drawing_area, "expose_event",
00113         G_CALLBACK (on_drawingarea_map_expose_event), NULL);
00114     g_signal_connect ((gpointer) map_drawing_area, "button_press_event",
00115         G_CALLBACK (on_drawingarea_map_button_press_event), NULL);
00116     g_signal_connect ((gpointer) map_drawing_area, "configure_event",
00117         G_CALLBACK (on_drawingarea_map_configure_event), NULL);
00118 
00119 #if 0
00120     gtk_widget_set_size_request (map_drawing_area,
00121         use_config[CONFIG_MAPWIDTH] * map_image_size,
00122         use_config[CONFIG_MAPHEIGHT] * map_image_size);
00123 #endif
00124     mapgc = gdk_gc_new(map_drawing_area->window);
00125     gtk_widget_show(map_drawing_area);
00126     gtk_widget_add_events (map_drawing_area, GDK_BUTTON_PRESS_MASK);
00127 
00128     if (use_config[CONFIG_DISPLAYMODE] == CFG_DM_PIXMAP) {
00129         int x,y,count;
00130         GdkGC   *darkgc;
00131         /*
00132          * This is used when drawing with GdkPixmaps.  Create another surface,
00133          * as well as some light/dark images
00134          */
00135         dark = gdk_pixmap_new(map_drawing_area->window, map_image_size, map_image_size, -1);
00136         gdk_draw_rectangle(dark, map_drawing_area->style->black_gc, TRUE, 0, 0, map_image_size, map_image_size);
00137         dark1 = gdk_pixmap_new(map_drawing_area->window, map_image_size, map_image_size, 1);
00138         dark2 = gdk_pixmap_new(map_drawing_area->window, map_image_size, map_image_size, 1);
00139         dark3 = gdk_pixmap_new(map_drawing_area->window, map_image_size, map_image_size, 1);
00140         /*
00141          * We need our own GC here because we are working with single bit depth
00142          * images
00143          */
00144         darkgc = gdk_gc_new(dark1);
00145         gdk_gc_set_foreground(darkgc, &root_color[NDI_WHITE]);
00146         /* Clear any garbage values we get when we create the bitmaps */
00147         gdk_draw_rectangle(dark1, darkgc, TRUE, 0, 0, map_image_size, map_image_size);
00148         gdk_draw_rectangle(dark2, darkgc, TRUE, 0, 0, map_image_size, map_image_size);
00149         gdk_draw_rectangle(dark3, darkgc, TRUE, 0, 0, map_image_size, map_image_size);
00150         gdk_gc_set_foreground(darkgc, &root_color[NDI_BLACK]);
00151         count=0;
00152         for (x=0; x<map_image_size; x++) {
00153             for (y=0; y<map_image_size; y++) {
00154                 /*
00155                  * We just fill in points every X pixels - dark1 is the
00156                  * darkest, dark3 is the lightest.  dark1 has 50% of the pixels
00157                  * filled in, dark2 has 33%, dark3 has 25% The formula's here
00158                  * are not perfect - dark2 will not match perfectly with an
00159                  * adjacent dark2 image.  dark3 results in diagonal stripes.
00160                  * OTOH, these will change depending on the image size.
00161                  */
00162                 if ((x+y) % 2) {
00163                     gdk_draw_point(dark1, darkgc, x, y);
00164                 }
00165                 if ((x+y) %3) {
00166                     gdk_draw_point(dark2, darkgc, x, y);
00167                 }
00168                 if ((x+y) % 4) {
00169                     gdk_draw_point(dark3, darkgc, x, y);
00170                 }
00171                 /*
00172                  * dark1 gets filled on 0x01, 0x11, 0x10, only leaving 0x00
00173                  * empty
00174                  */
00175             }
00176             /*
00177              * if the row size is even, we put an extra value in count - in
00178              * this way, the pixels will be even on one line, odd on the next,
00179              * etc instead of vertical lines - at least for dark1 and dark3
00180              */
00181         }
00182         gdk_gc_unref(darkgc);
00183     }
00184 #ifdef HAVE_SDL
00185     else if (use_config[CONFIG_DISPLAYMODE] == CFG_DM_SDL) {
00186         init_SDL(map_drawing_area,0);
00187     }
00188 #endif
00189 #ifdef HAVE_OPENGL
00190     else if (use_config[CONFIG_DISPLAYMODE] == CFG_DM_OPENGL) {
00191         init_opengl(map_drawing_area);
00192     }
00193 #endif
00194 }
00195 
00201 void reset_map(void)
00202 {
00203 }
00204 
00218 static void draw_pixmap(int srcx, int srcy, int dstx, int dsty, int clipx, int clipy,
00219                         void *mask, void *image, int sizex, int sizey)
00220 {
00221     gdk_gc_set_clip_mask(mapgc, mask);
00222     gdk_gc_set_clip_origin(mapgc, clipx, clipy);
00223     gdk_draw_pixmap(map_drawing_area->window, mapgc, image, srcx, srcy, dstx, dsty, sizex, sizey);
00224 }
00225 
00231 int display_mapscroll(int dx, int dy)
00232 {
00233 #ifdef HAVE_SDL
00234     if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_SDL)
00235         return sdl_mapscroll(dx,dy);
00236     else
00237 #endif
00238     return 0;
00239 }
00240 
00251 void drawsmooth (int mx,int my,int layer,int picx,int picy){
00252     static int dx[8]={0,1,1,1,0,-1,-1,-1};
00253     static int dy[8]={-1,-1,0,1,1,1,0,-1};
00254     static int bweights[8]={2,0,4,0,8,0,1,0};
00255     static int cweights[8]={0,2,0,4,0,8,0,1};
00256     static int bc_exclude[8]={
00257                  1+2,/*north exclude northwest (bit0) and northeast(bit1)*/
00258                  0,
00259                  2+4,/*east exclude northeast and southeast*/
00260                  0,
00261                  4+8,/*and so on*/
00262                  0,
00263                  8+1,
00264                  0
00265                 };
00266     int partdone[8]={0,0,0,0,0,0,0,0};
00267     int slevels[8];
00268     int sfaces[8];
00269     int i,lowest,weight,weightC;
00270     int emx,emy;
00271     int smoothface;
00272     int hasFace = 0;
00273     for (i=0;i<=layer;i++)
00274         hasFace |= the_map.cells[mx][my].heads[i].face;
00275     if (!hasFace
00276     || !CAN_SMOOTH(the_map.cells[mx][my], layer)) {
00277         return;
00278     }
00279     for (i=0;i<8;i++){
00280         emx=mx+dx[i];
00281         emy=my+dy[i];
00282         if ( (emx<0) || (emy<0) || (the_map.x<=emx) || (the_map.y<=emy)){
00283             slevels[i]=0;
00284             sfaces[i]=0; /*black picture*/
00285         }
00286         else if (the_map.cells[emx][emy].smooth[layer]<=the_map.cells[mx][my].smooth[layer]){
00287             slevels[i]=0;
00288             sfaces[i]=0; /*black picture*/
00289         }else{
00290             slevels[i]=the_map.cells[emx][emy].smooth[layer];
00291             sfaces[i]=pixmaps[the_map.cells[emx][emy].heads[layer].face]->smooth_face;
00292         }
00293     }
00294     /*
00295      * Now we have a list of smoothlevel higher than current square.  There are
00296      * at most 8 different levels. so... check 8 times for the lowest one (we
00297      * draw from bottom to top!).
00298      */
00299     lowest=-1;
00300     while (1){
00301         lowest = -1;
00302         for (i=0;i<8;i++){
00303             if ( (slevels[i]>0) && (!partdone[i]) &&
00304                 ((lowest<0) || (slevels[i]<slevels[lowest]))
00305                )
00306                     lowest=i;
00307         }
00308         if (lowest<0)
00309             break;   /*no more smooth to do on this square*/
00310         /*printf ("hey, must smooth something...%d\n",sfaces[lowest]);*/
00311         /* Here we know 'what' to smooth
00312          *
00313          * Calculate the weight for border and weight for corners.  Then
00314          * 'markdone' the corresponding squares
00315          *
00316          * First, the border, which may exclude some corners
00317          */
00318         weight=0;
00319         weightC=15; /*works in backward. remove where there is nothing*/
00320         /*for (i=0;i<8;i++)
00321             cornermask[i]=1;*/
00322         for (i=0;i<8;i++){ /*check all nearby squares*/
00323             if ( (slevels[i]==slevels[lowest]) &&
00324                  (sfaces[i]==sfaces[lowest])){
00325                 partdone[i]=1;
00326                 weight=weight+bweights[i];
00327                 weightC&=~bc_exclude[i];
00328             }else{
00329                 /*must rmove the weight of a corner if not in smoothing*/
00330                 weightC&=~cweights[i];
00331             }
00332         }
00333         /*We can't do this before since we need the partdone to be adjusted*/
00334         if (sfaces[lowest]<=0)
00335             continue;  /*Can't smooth black*/
00336         smoothface=sfaces[lowest];
00337         if (smoothface<=0){
00338             continue;  /*picture for smoothing not yet available*/
00339         }
00340         /*
00341          * now, it's quite easy. We must draw using a 32x32 part of the picture
00342          * smoothface.  This part is located using the 2 weights calculated:
00343          * (32*weight,0) and (32*weightC,32)
00344          */
00345         if ( (!pixmaps[smoothface]->map_image) ||
00346              (pixmaps[smoothface] == pixmaps[0]))
00347             continue;   /*don't have the picture associated*/
00348         if (weight>0){
00349             draw_pixmap(
00350                 weight*map_image_size, 0,
00351                 picx, picy,
00352                 picx-weight*map_image_size, picy,
00353                 pixmaps[smoothface]->map_mask, pixmaps[smoothface]->map_image, map_image_size, map_image_size);
00354         }
00355         if (weightC>0){
00356             draw_pixmap(
00357                 weightC*map_image_size, map_image_size,
00358                 picx, picy,
00359                 picx-weightC*map_image_size, picy-map_image_size,
00360                 pixmaps[smoothface]->map_mask, pixmaps[smoothface]->map_image, map_image_size, map_image_size);
00361         }
00362     } /* while there's some smooth to do */
00363 }
00364 
00372 static void display_mapcell(int ax, int ay, int mx, int my)
00373 {
00374     int layer;
00375 
00376     /* First, we need to black out this space. */
00377     gdk_draw_rectangle(map_drawing_area->window, map_drawing_area->style->black_gc, TRUE, ax*map_image_size, ay*map_image_size, map_image_size, map_image_size);
00378     /*
00379      * Now draw the different layers.  Only draw if using fog of war or the
00380      * space isn't clear.
00381      */
00382     if (use_config[CONFIG_FOGWAR] || !the_map.cells[mx][my].cleared) {
00383         for (layer=0; layer<MAXLAYERS; layer++) {
00384             int sx, sy;
00385 
00386             /* draw single-tile faces first */
00387             int face = mapdata_face(ax, ay, layer);
00388             if (face > 0 && pixmaps[face]->map_image != NULL) {
00389                 int src_x = pixmaps[face]->map_width - map_image_size;;
00390                 int src_y = pixmaps[face]->map_height - map_image_size;
00391                 int off_x=0, off_y=0;
00392 
00393                 /* Normalize the source coordinates - clearly it can't be
00394                  * be less than zero.  If it is less than zero, this denotes
00395                  * a 'small' image.  By definition, the bottom right is the
00396                  * origin of the image (an image 16 pixels high is drawn on the
00397                  * bottom half of the space, not top), which is why
00398                  * the offsets are negative of the base values.
00399                  */
00400                 if (src_x<0) {
00401                     off_x=-src_x;
00402                     src_x=0;
00403                 }
00404                 if (src_y<0) {
00405                     off_y = -src_y;
00406                     src_y=0;
00407                 }
00408                 draw_pixmap(
00409                     src_x, src_y,
00410                     ax*map_image_size + off_x, ay*map_image_size + off_y,
00411                     ax*map_image_size+map_image_size-pixmaps[face]->map_width,
00412                     ay*map_image_size+map_image_size-pixmaps[face]->map_height,
00413                     pixmaps[face]->map_mask, pixmaps[face]->map_image,
00414                     pixmaps[face]->map_width>map_image_size?map_image_size:pixmaps[face]->map_width,
00415                     pixmaps[face]->map_height>map_image_size?map_image_size:pixmaps[face]->map_height);
00416 
00417             }
00418             /*
00419              * Sometimes, it may happens we need to draw the smooth while there
00420              * is nothing to draw at that layer (but there was something at
00421              * lower layers). This is handled here. The else part is to take
00422              * into account cases where the smooth as already been handled 2
00423              * code lines before
00424              */
00425             if ( use_config[CONFIG_SMOOTH])
00426                 drawsmooth (mx, my, layer, ax*map_image_size, ay*map_image_size);
00427 
00428             /* draw big faces last (should overlap other objects) */
00429             face = mapdata_bigface(ax, ay, layer, &sx, &sy);
00430 
00431             if (face > 0 && pixmaps[face]->map_image != NULL) {
00432                 /*
00433                  * This is pretty messy, because images are not required to be
00434                  * an integral multiplier of the image size.  There are really
00435                  * 4 main variables:
00436                  * source[xy]: Where within the pixmap to start grabbing pixels.
00437                  * off[xy]: Offset from space edge on the visible map to start
00438                  *     drawing pixels.
00439                  * off[xy] also determines how many pixels to draw
00440                  *     (map_image_size - off[xy])
00441                  * clip[xy]: Position of the clipmask.  The position of the
00442                  *     clipmask is always at the upper left of the image as we
00443                  *     drawn it on the map, so for any given big image, it will
00444                  *     have the same values for all the pieces.  However we
00445                  *     need to re-construct that location based on current
00446                  *     location.
00447                  *
00448                  * For a 32x72 image, it would be drawn like follows:
00449                  *                  sourcey         offy
00450                  * top space:       0               24
00451                  * middle space:    8               0
00452                  * bottom space:    40              0
00453                  */
00454                 int dx, dy, sourcex, sourcey, offx, offy, clipx, clipy;
00455 
00456                 dx = pixmaps[face]->map_width % map_image_size;
00457                 offx = dx?(map_image_size -dx):0;
00458                 clipx = (ax - sx)*map_image_size + offx;
00459 
00460                 if (sx) {
00461                     sourcex = sx * map_image_size - offx ;
00462                     offx=0;
00463                 } else {
00464                     sourcex=0;
00465                 }
00466 
00467                 dy = pixmaps[face]->map_height % map_image_size;
00468                 offy = dy?(map_image_size -dy):0;
00469                 clipy = (ay - sy)*map_image_size + offy;
00470 
00471                 if (sy) {
00472                     sourcey = sy * map_image_size - offy;
00473                     offy=0;
00474                 } else {
00475                     sourcey=0;
00476                 }
00477 
00478                 draw_pixmap(
00479                     sourcex,  sourcey,
00480                     ax*map_image_size+offx, ay*map_image_size + offy,
00481                     clipx, clipy,
00482                     pixmaps[face]->map_mask, pixmaps[face]->map_image,
00483                     map_image_size - offx, map_image_size - offy);
00484             }
00485         } /* else for processing the layers */
00486     }
00487     /*
00488      * If this is a fog cell, do darkening of the space.  otherwise, process
00489      * light/darkness - only do those if not a fog cell.
00490      */
00491     if (use_config[CONFIG_FOGWAR] && the_map.cells[mx][my].cleared) {
00492         draw_pixmap(0, 0, ax*map_image_size, ay*map_image_size, ax*map_image_size, ay*map_image_size, dark1, dark, map_image_size, map_image_size);
00493     }
00494     else if (the_map.cells[mx][my].darkness > 192) { /* Full dark */
00495         gdk_draw_rectangle (map_drawing_area->window, map_drawing_area->style->black_gc,
00496             TRUE,map_image_size*ax, map_image_size*ay,
00497             map_image_size, map_image_size);
00498     } else if (the_map.cells[mx][my].darkness> 128) {
00499         draw_pixmap(0, 0, ax*map_image_size, ay*map_image_size, ax*map_image_size, ay*map_image_size, dark1, dark, map_image_size, map_image_size);
00500     } else if (the_map.cells[mx][my].darkness> 64) {
00501         draw_pixmap(0, 0, ax*map_image_size, ay*map_image_size, ax*map_image_size, ay*map_image_size, dark2, dark, map_image_size, map_image_size);
00502     } else if (the_map.cells[mx][my].darkness> 1) {
00503         draw_pixmap(0, 0, ax*map_image_size, ay*map_image_size, ax*map_image_size, ay*map_image_size, dark3, dark, map_image_size, map_image_size);
00504     }
00505 }
00506 
00511 void gtk_draw_map(int redraw) {
00512     int mx, my;
00513     int x, y;
00514     struct timeval tv1, tv2,tv3;
00515     long elapsed1, elapsed2;
00516 
00517     if(!redraw && !map_updated)
00518         return;
00519 
00520     if (time_map_redraw)
00521         gettimeofday(&tv1, NULL);
00522 
00523     for(x = 0; x < use_config[CONFIG_MAPWIDTH]; x++) {
00524         for(y = 0; y < use_config[CONFIG_MAPHEIGHT]; y++) {
00525             /*
00526              * mx,my represent the spaces on the 'virtual' map (ie, the_map
00527              * structure).  x and y (from the for loop) represent the visible
00528              * screen.
00529              */
00530             mx = pl_pos.x+x;
00531             my = pl_pos.y+y;
00532 
00533             if (redraw
00534             || the_map.cells[mx][my].need_update
00535             || the_map.cells[mx][my].need_resmooth) {
00536                 display_mapcell(x, y, mx, my);
00537                 the_map.cells[mx][my].need_update = 0;
00538                 the_map.cells[mx][my].need_resmooth = 0;
00539             }
00540         } /* For y spaces */
00541     } /* for x spaces */
00542 
00543     if (time_map_redraw)
00544         gettimeofday(&tv2, NULL);
00545 
00546     if (time_map_redraw) {
00547         gettimeofday(&tv3, NULL);
00548         elapsed1 = (tv2.tv_sec - tv1.tv_sec)*1000000 + (tv2.tv_usec - tv1.tv_usec);
00549         elapsed2 = (tv3.tv_sec - tv2.tv_sec)*1000000 + (tv3.tv_usec - tv2.tv_usec);
00550         /*
00551          * I care about performance for 'long' updates, so put the check in to
00552          * make these a little more noticable
00553          */
00554         if ((elapsed1 + elapsed2)>10000)
00555             LOG(LOG_INFO,"gtk::sdl_gen_map","gen took %7ld, flip took %7ld, total = %7ld",
00556                     elapsed1, elapsed2, elapsed1 + elapsed2);
00557     }
00558 }
00559 
00564 void display_map_newmap(void)
00565 {
00566     reset_map();
00567 }
00568 
00575 void resize_map_window(int x, int y)
00576 {
00577     /* We do an implicit clear, since after a resize, there may be some
00578      * left over pixels at the edge which will not get drawn on by map spaces.
00579      */
00580     gdk_window_clear(map_drawing_area->window);
00581     draw_map(TRUE);
00582 }
00583 
00584 
00585 gboolean                                                                                          
00586 on_drawingarea_map_configure_event     (GtkWidget       *widget,
00587                                         GdkEventConfigure *event,
00588                                         gpointer         user_data)
00589 {
00590     sint16 w = event->width / map_image_size, h=event->height / map_image_size;
00591 
00592     if (w > MAP_MAX_SIZE) w = MAP_MAX_SIZE;
00593     if (h > MAP_MAX_SIZE) h = MAP_MAX_SIZE;
00594 
00595     /* Only need to do something if the size actually changes in terms
00596      * of displayable mapspaces.
00597      */
00598     if (w!= use_config[CONFIG_MAPWIDTH] || h!=use_config[CONFIG_MAPHEIGHT]) {
00599         /* We need to set the use_config values, even though we are not really using them,
00600          * because the setup processing basically expects the values returned from the
00601          * server to use these values.
00602          * Likewise, we need to call mapdata_set_size because we may try
00603          * to do map draws before we get the setup command from the server, and if it
00604          * is using the old values, that doesn't work quite right.
00605          */
00606         use_config[CONFIG_MAPWIDTH] = w;
00607         use_config[CONFIG_MAPHEIGHT] = h;
00608         mapdata_set_size(use_config[CONFIG_MAPWIDTH], use_config[CONFIG_MAPHEIGHT]);
00609         cs_print_string(csocket.fd,
00610                         "setup mapsize %dx%d", use_config[CONFIG_MAPWIDTH], use_config[CONFIG_MAPHEIGHT]);
00611     }
00612     return FALSE;
00613 }
00614 
00615 
00620 void draw_splash(void)
00621 {
00622     static GdkPixmap *splash;
00623     static int have_init=0;
00624     GdkBitmap *aboutgdkmask;
00625     int x,y, w, h;
00626 
00627 #include "../../pixmaps/crossfiretitle.xpm"
00628 
00629     if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_PIXMAP) {
00630         if (!have_init) {
00631             splash = gdk_pixmap_create_from_xpm_d(map_drawing_area->window,
00632                                                &aboutgdkmask, NULL,
00633                                                (gchar **)crossfiretitle_xpm);
00634             have_init=1;
00635         }
00636         gdk_window_clear(map_drawing_area->window);
00637         gdk_drawable_get_size(splash, &w, &h);
00638         x = (map_drawing_area->allocation.width- w)/2;
00639         y = (map_drawing_area->allocation.height - h)/2;
00640         /*
00641          * Clear the clip mask - it can be left in an inconsistent state from
00642          * last map redraw.
00643          */
00644         gdk_gc_set_clip_mask(mapgc, NULL);
00645         gdk_draw_pixmap(map_drawing_area->window, mapgc, splash, 0, 0,
00646                         x, y, w, h);
00647     }
00648 }
00649 
00654 void draw_map(int redraw)
00655 {
00656 #ifdef HAVE_SDL
00657     if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_SDL) sdl_gen_map(redraw);
00658     else
00659 #endif
00660 #ifdef HAVE_OPENGL
00661     if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_OPENGL) opengl_gen_map(redraw);
00662     else
00663 #endif
00664     if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_PIXMAP) {
00665         if (cpl.input_state == Metaserver_Select) draw_splash();
00666         else gtk_draw_map(redraw);
00667     }
00668 }
00669 
00677 gboolean
00678 on_drawingarea_map_expose_event        (GtkWidget       *widget,
00679                                         GdkEventExpose  *event,
00680                                         gpointer         user_data)
00681 {
00682     draw_map(TRUE);
00683     return FALSE;
00684 }
00685 
00693 gboolean
00694 on_drawingarea_map_button_press_event  (GtkWidget       *widget,
00695                                         GdkEventButton  *event,
00696                                         gpointer         user_data)
00697 {
00698     int dx, dy, i, x, y, xmidl, xmidh, ymidl, ymidh;
00699 
00700     x=(int)event->x;
00701     y=(int)event->y;
00702     dx=(x-2)/map_image_size-(use_config[CONFIG_MAPWIDTH]/2);
00703     dy=(y-2)/map_image_size-(use_config[CONFIG_MAPHEIGHT]/2);
00704     xmidl=(use_config[CONFIG_MAPWIDTH]/2) * map_image_size;
00705     xmidh=(use_config[CONFIG_MAPWIDTH]/2 + 1) * map_image_size;
00706     ymidl=(use_config[CONFIG_MAPHEIGHT]/2) * map_image_size;
00707     ymidh=(use_config[CONFIG_MAPHEIGHT]/2 + 1) * map_image_size;
00708 
00709     switch (event->button) {
00710         case 1:
00711             look_at(dx,dy);
00712             break;
00713 
00714         case 2:
00715         case 3:
00716             if (x<xmidl)
00717                 i = 0;
00718             else if (x>xmidh)
00719                 i = 6;
00720             else i =3;
00721 
00722             if (y>ymidh)
00723                 i += 2;
00724             else if (y>ymidl)
00725                 i++;
00726 
00727             if (event->button==2) {
00728                 switch (i) {
00729                     case 0: fire_dir (8);break;
00730                     case 1: fire_dir (7);break;
00731                     case 2: fire_dir (6);break;
00732                     case 3: fire_dir (1);break;
00733                     case 5: fire_dir (5);break;
00734                     case 6: fire_dir (2);break;
00735                     case 7: fire_dir (3);break;
00736                     case 8: fire_dir (4);break;
00737                 }
00738                 /* Only want to fire once */
00739                 clear_fire();
00740             }
00741             else switch (i) {
00742                 case 0: move_player (8);break;
00743                 case 1: move_player (7);break;
00744                 case 2: move_player (6);break;
00745                 case 3: move_player (1);break;
00746                 case 5: move_player (5);break;
00747                 case 6: move_player (2);break;
00748                 case 7: move_player (3);break;
00749                 case 8: move_player (4);break;
00750             }
00751     }
00752     return FALSE;
00753 }
00754 
00761 void display_map_startupdate(void)
00762 {
00763 }
00764 
00772 void display_map_doneupdate(int redraw, int notice)
00773 {
00774     map_updated |= redraw || !notice;
00775 }