Complete.Org: Mailing Lists: Archives: freeciv-dev: February 2003:
[Freeciv-Dev] (PR#3424) New flush code
Home

[Freeciv-Dev] (PR#3424) New flush code

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: bursig@xxxxxxxxx
Subject: [Freeciv-Dev] (PR#3424) New flush code
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 24 Feb 2003 00:23:11 -0800
Reply-to: rt@xxxxxxxxxxxxxx

Attached is a new version of the patch.  I've removed the goto-line and
most other GUI changes, since they're no longer needed with some of the
other changes in the patch.

flush_dirty() no longer calls the GUI sync function (except for
gui-sdl).  This means drawing is faster (the GUI can synchronize the
framebuffer asynchronously), but does not work in a few cases
(specifically animation).  Eventually a new GUI function hard_flush()
may be required to call gdk_flush/XSync/GdiFlush during animation.

-----

For those of you who have not been paying attention up to this point...

This patch changes most refresh_tile_mapcanvas and update_map_canvas
calls to pass FALSE for write_to_screen.  Thus the changes are not sent
directly to the screen, but instead the drawn area is marked as 'dirty'
via a call to dirty_rect() or dirty_all().  Later when the drawing needs
to be done flush_dirty() is called.

Most GUI libraries handle buffering automatically, so there has
previously been no need for this.  But SDL does not do this - it simply
provides an interface for the application to access the underlying
hardware/os operations.  So for gui-sdl, to flush a change to the screen
means it actually gets flushed immediately.  It is inefficient to do
this in small batches; SDL provides a function for writing a set of
rectangular areas out to the display all at once.  The GUI functions
introduced by this patch will work well in conjunction with the
optimizations SDL provides.

This change is especially important because gui-sdl's new buffer code
uses four different drawing buffers and a lot of alpha-level (32-bit)
drawing to achieve a very high level of drawing quality (try running
gui-sdl; although there are a lot of bugs right now the effect is still
very impressive).  Flushing is especially expensive, so we need to try
to avoid it or do it in larger batches where possible.

Most GUIs will be largely unaffected by this change: since the GUI code
does (some) buffering already, we're just waiting a little bit before we
copy the data into the buffer.  However, it does help us to avoid some
drawing bugs like PR#2982.

For gui-gtk-2.0 the flush code is simply a wrapper to GDK functions. 
This means GDK may be able to optimize the flushing (to do it in batches
and avoid duplication), and it also means we can do other needed expose
redraws when we flush (see PR#3513).

For the most part, this patch takes a conservative approach to the
question of when to call flush_dirty.  In time (and with profiling) we
should be able to refine the locations where it is called.  The only
exception is update_map_canvas_visible, where we really don't want to do
the flushing all the time - since this function is called in so many
places, and only a few of them need a flush_dirty call.

jason

Index: client/climisc.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/climisc.c,v
retrieving revision 1.112
diff -u -r1.112 climisc.c
--- client/climisc.c    2003/02/15 20:26:17     1.112
+++ client/climisc.c    2003/02/24 07:22:45
@@ -111,7 +111,7 @@
            get_nation_name(city_owner(pcity)->nation), pcity->x, pcity->y);
   }
 
-  refresh_tile_mapcanvas(x, y, TRUE);
+  refresh_tile_mapcanvas(x, y, FALSE);
 }
 
 /**************************************************************************
@@ -142,7 +142,7 @@
   popdown_city_dialog(pcity);
   game_remove_city(pcity);
   city_report_dialog_update();
-  refresh_tile_mapcanvas(x, y, TRUE);
+  refresh_tile_mapcanvas(x, y, FALSE);
 }
 
 /**************************************************************************
@@ -368,6 +368,7 @@
   OUT:
     ;                          /* do nothing */
   }
+  flush_dirty();
 }
 
 /**************************************************************************
Index: client/control.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/control.c,v
retrieving revision 1.95
diff -u -r1.95 control.c
--- client/control.c    2003/02/20 21:58:14     1.95
+++ client/control.c    2003/02/24 07:22:45
@@ -110,7 +110,7 @@
     auto_center_on_focus_unit();
 
     punit->focus_status=FOCUS_AVAIL;
-    refresh_tile_mapcanvas(punit->x, punit->y, TRUE);
+    refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
 
     if (punit->activity != ACTIVITY_IDLE || punit->ai.control)  {
       punit->activity = ACTIVITY_IDLE;
@@ -124,7 +124,7 @@
   if (punit_old_focus
       && (!punit || !same_pos(punit_old_focus->x, punit_old_focus->y,
                                   punit->x, punit->y))) {
-    refresh_tile_mapcanvas(punit_old_focus->x, punit_old_focus->y, TRUE);
+    refresh_tile_mapcanvas(punit_old_focus->x, punit_old_focus->y, FALSE);
   }
 
   update_unit_info_label(punit);
@@ -142,7 +142,7 @@
   punit_focus=punit;
 
   if(punit) {
-    refresh_tile_mapcanvas(punit->x, punit->y, TRUE);
+    refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
     punit->focus_status=FOCUS_AVAIL;
   }
 }
@@ -215,7 +215,7 @@
    * because above we change punit_focus directly.
    */
   if(punit_old_focus && punit_old_focus!=punit_focus)
-    refresh_tile_mapcanvas(punit_old_focus->x, punit_old_focus->y, TRUE);
+    refresh_tile_mapcanvas(punit_old_focus->x, punit_old_focus->y, FALSE);
 
   set_unit_focus(punit_focus);
 
@@ -236,6 +236,8 @@
   if (auto_turn_done && punit_old_focus && !punit_focus && non_ai_unit_focus) {
     key_end_turn();
   }
+
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -916,6 +918,7 @@
 
   draw_map_grid^=1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -929,6 +932,7 @@
 
   draw_city_names ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
  
  /**************************************************************************
@@ -942,6 +946,7 @@
 
   draw_city_growth = !draw_city_growth;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -955,6 +960,7 @@
 
   draw_city_productions ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -968,6 +974,7 @@
 
   draw_terrain ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -981,6 +988,7 @@
 
   draw_coastline ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -994,6 +1002,7 @@
 
   draw_roads_rails ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1007,6 +1016,7 @@
 
   draw_irrigation ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1020,6 +1030,7 @@
 
   draw_mines ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1033,6 +1044,7 @@
 
   draw_fortress_airbase ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1046,6 +1058,7 @@
 
   draw_specials ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1059,6 +1072,7 @@
 
   draw_pollution ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1072,6 +1086,7 @@
 
   draw_cities ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1085,6 +1100,7 @@
 
   draw_units ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1098,6 +1114,7 @@
 
   draw_focus_unit ^= 1;
   update_map_canvas_visible();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1113,6 +1130,7 @@
   update_map_canvas_visible();
   refresh_overview_canvas();
   refresh_overview_viewrect();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -1120,10 +1138,12 @@
 **************************************************************************/
 void request_center_focus_unit(void)
 {
-  struct unit *punit;
+  struct unit *punit = get_unit_in_focus();
   
-  if((punit=get_unit_in_focus()))
+  if (punit) {
     center_tile_mapcanvas(punit->x, punit->y);
+    flush_dirty();
+  }
 }
 
 /**************************************************************************
@@ -1169,6 +1189,9 @@
 
   unit_list_unlink(&map_get_tile(x, y)->units, punit);
 
+  /* We need to update the canvas if the unit has moved.  But unless it
+   * teleported we shouldn't flush this yet (that is handled by
+   * move_unit_map_canvas. */
   if(!pinfo->carried)
     refresh_tile_mapcanvas(x, y, was_teleported);
   
@@ -1184,7 +1207,7 @@
       dx=1;
     if(smooth_move_units)
       move_unit_map_canvas(punit, x, y, dx, pinfo->y - punit->y);
-    refresh_tile_mapcanvas(x, y, TRUE);
+    refresh_tile_mapcanvas(x, y, FALSE);
   }
     
   punit->x=pinfo->x;
@@ -1203,12 +1226,12 @@
     } unit_list_iterate_end;
   out:
     if (refresh) {
-      refresh_tile_mapcanvas(x, y, TRUE);
+      refresh_tile_mapcanvas(x, y, FALSE);
     }
   } square_iterate_end;
   
   if(!pinfo->carried && tile_get_known(punit->x,punit->y) == TILE_KNOWN)
-    refresh_tile_mapcanvas(punit->x, punit->y, TRUE);
+    refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
 
   if(get_unit_in_focus()==punit) update_menus();
 }
@@ -1349,6 +1372,7 @@
     } else {
       append_output_window(_("Game: Didn't find a route to the destination!"));
     }
+    flush_dirty();
   }
 
   set_hover_state(NULL, HOVER_NONE);
Index: client/mapctrl_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapctrl_common.c,v
retrieving revision 1.5
diff -u -r1.5 mapctrl_common.c
--- client/mapctrl_common.c     2003/01/09 19:21:17     1.5
+++ client/mapctrl_common.c     2003/02/24 07:22:45
@@ -94,6 +94,7 @@
     get_line_dest(&old_x, &old_y);
     if (!same_pos(old_x, old_y, x, y)) {
       draw_line(x, y);
+      flush_dirty();
     }
   }
 }
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.32
diff -u -r1.32 mapview_common.c
--- client/mapview_common.c     2003/02/22 02:48:30     1.32
+++ client/mapview_common.c     2003/02/24 07:22:46
@@ -44,7 +44,7 @@
   if (tile_visible_mapcanvas(x, y)) {
     update_map_canvas(x, y, 1, 1, FALSE);
 
-    if (write_to_screen && (draw_city_names || draw_city_productions)) {
+    if (draw_city_names || draw_city_productions) {
       /* FIXME: update_map_canvas() will overwrite the city descriptions.
        * This is a workaround that redraws the city descriptions (most of
        * the time).  Although it seems inefficient to redraw the
@@ -90,12 +90,7 @@
     }
 
     if (write_to_screen) {
-      int canvas_start_x, canvas_start_y;
-
-      get_canvas_xy(x, y, &canvas_start_x, &canvas_start_y);
-      canvas_start_y += NORMAL_TILE_HEIGHT - UNIT_TILE_HEIGHT;
-      flush_mapcanvas(canvas_start_x, canvas_start_y,
-                     UNIT_TILE_WIDTH, UNIT_TILE_HEIGHT);
+      flush_dirty();
     }
   }
   overview_update_tile(x, y);
@@ -530,6 +525,8 @@
 void update_map_canvas(int x, int y, int width, int height, 
                       bool write_to_screen)
 {
+  int canvas_start_x, canvas_start_y;
+
   freelog(LOG_DEBUG,
          "update_map_canvas(pos=(%d,%d), size=(%d,%d), write_to_screen=%d)",
          x, y, width, height, write_to_screen);
@@ -604,31 +601,25 @@
 
 
     /* Lastly draw our changes to the screen. */
-    if (write_to_screen) {
-      int canvas_start_x, canvas_start_y;
+    /* top left corner */
+    get_canvas_xy(x, y, &canvas_start_x, &canvas_start_y);
 
-      /* top left corner */
-      get_canvas_xy(x, y, &canvas_start_x, &canvas_start_y);
+    /* top left corner in isometric view */
+    canvas_start_x -= height * NORMAL_TILE_WIDTH / 2;
 
-      /* top left corner in isometric view */
-      canvas_start_x -= height * NORMAL_TILE_WIDTH / 2;
+    /* because of where get_canvas_xy() sets canvas_x */
+    canvas_start_x += NORMAL_TILE_WIDTH / 2;
 
-      /* because of where get_canvas_xy() sets canvas_x */
-      canvas_start_x += NORMAL_TILE_WIDTH / 2;
-
-      /* And because units fill a little extra */
-      canvas_start_y -= NORMAL_TILE_HEIGHT / 2;
-
-      /* Here we draw a rectangle that includes the updated tiles.  This
-       * method can fail if the area wraps off one side of the screen and
-       * back to the other (although this will not be a problem for
-       * update_map_canvas_visible(). */
-      flush_mapcanvas(canvas_start_x, canvas_start_y,
-                     (height + width) * NORMAL_TILE_WIDTH / 2,
-                     (height + width) * NORMAL_TILE_HEIGHT / 2
-                     + NORMAL_TILE_HEIGHT / 2);
-    }
-
+    /* And because units fill a little extra */
+    canvas_start_y += NORMAL_TILE_HEIGHT - UNIT_TILE_HEIGHT;
+
+    /* Here we draw a rectangle that includes the updated tiles.  This
+     * method can fail if the area wraps off one side of the screen and
+     * back to the other. */
+    dirty_rect(canvas_start_x, canvas_start_y,
+              (height + width) * NORMAL_TILE_WIDTH / 2,
+              (height + width) * NORMAL_TILE_HEIGHT / 2
+              + NORMAL_TILE_HEIGHT / 2);
   } else {
     /* not isometric */
     int map_x, map_y;
@@ -643,18 +634,20 @@
       }
     }
 
-    if (write_to_screen) {
-      int canvas_x, canvas_y;
+    /* Here we draw a rectangle that includes the updated tiles.  This
+     * method can fail if the area wraps off one side of the screen and
+     * back to the other. */
+    get_canvas_xy(x, y, &canvas_start_x, &canvas_start_y);
+    dirty_rect(canvas_start_x, canvas_start_y,
+              width * NORMAL_TILE_WIDTH,
+              height * NORMAL_TILE_HEIGHT);
+  }
 
-      /* Here we draw a rectangle that includes the updated tiles.  This
-       * method can fail if the area wraps off one side of the screen and
-       * back to the other (although this will not be a problem for
-       * update_map_canvas_visible(). */
-      get_canvas_xy(x, y, &canvas_x, &canvas_y);
-      flush_mapcanvas(canvas_x, canvas_y,
-                     width * NORMAL_TILE_WIDTH,
-                     height * NORMAL_TILE_HEIGHT);
-    }
+  if (write_to_screen) {
+    /* We never want a partial flush; that would leave the screen in an
+     * inconsistent state.  If the caller tells us to write_to_screen we
+     * simply flush everything immediately. */
+    flush_dirty();
   }
 }
 
@@ -671,6 +664,8 @@
   map_tile_width = (map_win_width - 1) / NORMAL_TILE_WIDTH + 1;
   map_tile_height = (map_win_height - 1) / NORMAL_TILE_HEIGHT + 1;
 
+  dirty_all();
+
   if (is_isometric) {
     /* just find a big rectangle that includes the whole visible area. The
        invisible tiles will not be drawn. */
@@ -685,8 +680,6 @@
   }
 
   show_city_descriptions();
-
-  flush_mapcanvas(0, 0, map_win_width, map_win_height);
 }
 
 /**************************************************************************
@@ -761,16 +754,10 @@
     assert(0);
   }
 
-  if (is_isometric) {
-    /* somewhat inefficient */
-    update_map_canvas(MIN(src_x, dest_x), MIN(src_y, dest_y),
-                     src_x == dest_x ? 1 : 2,
-                     src_y == dest_y ? 1 : 2,
-                     TRUE);
-  } else {
-    refresh_tile_mapcanvas(src_x, src_y, TRUE);
-    refresh_tile_mapcanvas(dest_x, dest_y, TRUE);
+  refresh_tile_mapcanvas(src_x, src_y, FALSE);
+  refresh_tile_mapcanvas(dest_x, dest_y, FALSE);
 
+  if (!is_isometric) {
     if (NORMAL_TILE_WIDTH % 2 == 0 || NORMAL_TILE_HEIGHT % 2 == 0) {
       if (dir == DIR8_NORTHEAST) {
        /* Since the tile doesn't have a middle we draw an extra pixel
@@ -778,12 +765,12 @@
        if (!MAPSTEP(dest_x, dest_y, src_x, src_y, DIR8_EAST)) {
          assert(0);
        }
-       refresh_tile_mapcanvas(dest_x, dest_y, TRUE);
+       refresh_tile_mapcanvas(dest_x, dest_y, FALSE);
       } else if (dir == DIR8_SOUTHWEST) {      /* the same */
        if (!MAPSTEP(dest_x, dest_y, src_x, src_y, DIR8_SOUTH)) {
          assert(0);
        }
-       refresh_tile_mapcanvas(dest_x, dest_y, TRUE);
+       refresh_tile_mapcanvas(dest_x, dest_y, FALSE);
       }
     }
   }
@@ -814,6 +801,8 @@
   if (!normalize_map_pos(&dest_x, &dest_y)) {
     assert(0);
   }
+
+  flush_dirty();
 
   if (player_can_see_unit(game.player_ptr, punit) &&
       (tile_visible_mapcanvas(map_x, map_y) ||
Index: client/messagewin_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/messagewin_common.c,v
retrieving revision 1.11
diff -u -r1.11 messagewin_common.c
--- client/messagewin_common.c  2003/02/19 23:46:16     1.11
+++ client/messagewin_common.c  2003/02/24 07:22:46
@@ -209,6 +209,10 @@
        * highlighted at all - this is left up to the GUI. */
       popup_city_dialog(pcity, FALSE);
     }
+    
+    if (center_when_popup_city || pcity) {
+      flush_dirty();
+    }
   }
 }
 
@@ -222,6 +226,7 @@
   if (messages[message_index].location_ok) {
     center_tile_mapcanvas(messages[message_index].x,
                          messages[message_index].y);
+    flush_dirty();
   }
 }
 
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.293
diff -u -r1.293 packhand.c
--- client/packhand.c   2003/02/20 23:00:55     1.293
+++ client/packhand.c   2003/02/24 07:22:48
@@ -190,6 +190,7 @@
 **************************************************************************/
 void handle_nuke_tile(struct packet_nuke_tile *packet)
 {
+  flush_dirty();
   put_nuke_mushroom_pixmaps(packet->x, packet->y);
 }
 
@@ -223,14 +224,15 @@
                       unit_type(punit1)->sound_fight_alt);
 
       if (do_combat_animation) {
+       flush_dirty();
        decrease_unit_hp_smooth(punit0, hp0, punit1, hp1);
       } else {
        punit0->hp = hp0;
        punit1->hp = hp1;
 
        set_units_in_combat(NULL, NULL);
-       refresh_tile_mapcanvas(punit0->x, punit0->y, TRUE);
-       refresh_tile_mapcanvas(punit1->x, punit1->y, TRUE);
+       refresh_tile_mapcanvas(punit0->x, punit0->y, FALSE);
+       refresh_tile_mapcanvas(punit1->x, punit1->y, FALSE);
       }
     }
   }
@@ -503,7 +505,7 @@
                      CITY_MAP_SIZE, CITY_MAP_SIZE, FALSE);
     queue_mapview_update(UPDATE_CITY_DESCRIPTIONS);
   } else {
-    refresh_tile_mapcanvas(pcity->x, pcity->y, TRUE);
+    refresh_tile_mapcanvas(pcity->x, pcity->y, FALSE);
   }
 
   if (city_workers_display==pcity)  {
@@ -914,7 +916,7 @@
 
       if(punit->owner==game.player_idx) 
         refresh_unit_city_dialogs(punit);
-      /*      refresh_tile_mapcanvas(punit->x, punit->y, TRUE);
+      /*      refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
        *      update_unit_pix_label(punit);
        *      update_unit_focus();
        */
@@ -982,7 +984,7 @@
       else {
        do_move_unit(punit, packet); /* nice to see where a unit is going */
        client_remove_unit(punit);
-       refresh_tile_mapcanvas(packet->x, packet->y, TRUE);
+       refresh_tile_mapcanvas(packet->x, packet->y, FALSE);
         return;
       }
       if(pcity)  {
@@ -1052,7 +1054,7 @@
     /*fog of war*/
     if (!(tile_get_known(punit->x,punit->y) == TILE_KNOWN)) {
       client_remove_unit(punit);
-      refresh_tile_mapcanvas(dest_x, dest_y, TRUE);
+      refresh_tile_mapcanvas(dest_x, dest_y, FALSE);
     }
     agents_unit_changed(punit);
   }
@@ -1093,7 +1095,7 @@
   }
 
   if(repaint_unit)
-    refresh_tile_mapcanvas(punit->x, punit->y, TRUE);
+    refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
 
   if (check_focus || get_unit_in_focus() == NULL)
     update_unit_focus(); 
@@ -1703,14 +1705,14 @@
 
     /* the tile itself */
     if (tile_changed || old_known!=ptile->known)
-      refresh_tile_mapcanvas(x, y, TRUE);
+      refresh_tile_mapcanvas(x, y, FALSE);
 
     /* if the terrain or the specials of the tile
        have changed it affects the adjacent tiles */
     if (tile_changed) {
       adjc_iterate(x, y, x1, y1) {
        if (tile_get_known(x1, y1) >= TILE_KNOWN_FOGGED)
-         refresh_tile_mapcanvas(x1, y1, TRUE);
+         refresh_tile_mapcanvas(x1, y1, FALSE);
       }
       adjc_iterate_end;
       return;
@@ -1721,7 +1723,7 @@
     if (old_known == TILE_UNKNOWN && packet->known >= TILE_KNOWN_FOGGED) {     
       cartesian_adjacent_iterate(x, y, x1, y1) {
        if (tile_get_known(x1, y1) >= TILE_KNOWN_FOGGED)
-         refresh_tile_mapcanvas(x1, y1, TRUE);
+         refresh_tile_mapcanvas(x1, y1, FALSE);
       }
       cartesian_adjacent_iterate_end;
     }
@@ -2484,6 +2486,7 @@
   }
 
   agents_processing_finished();
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -2554,4 +2557,5 @@
   reports_thaw();
 
   agents_thaw_hint();
+  flush_dirty();
 }
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.110
diff -u -r1.110 tilespec.c
--- client/tilespec.c   2003/02/05 07:19:43     1.110
+++ client/tilespec.c   2003/02/24 07:22:49
@@ -361,6 +361,7 @@
   }
   tileset_changed();
   center_tile_mapcanvas(center_x, center_y);
+  flush_dirty();
 }
 
 /**************************************************************************
Index: client/gui-gtk/mapctrl.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/mapctrl.c,v
retrieving revision 1.76
diff -u -r1.76 mapctrl.c
--- client/gui-gtk/mapctrl.c    2003/02/17 22:49:27     1.76
+++ client/gui-gtk/mapctrl.c    2003/02/24 07:22:49
@@ -335,6 +335,7 @@
   } else if (ev->button == 3) {
     center_tile_mapcanvas(xtile, ytile);
   }
+  flush_dirty();
   return TRUE;
 }
 
@@ -428,6 +429,8 @@
   } else if (can_client_issue_orders() && ev->button == 1) {
     do_unit_goto(xtile, ytile);
   }
+
+  flush_dirty();
 
   return TRUE;
 }
Index: client/gui-gtk/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/mapview.c,v
retrieving revision 1.159
diff -u -r1.159 mapview.c
--- client/gui-gtk/mapview.c    2003/02/22 13:15:30     1.159
+++ client/gui-gtk/mapview.c    2003/02/24 07:22:50
@@ -903,6 +903,56 @@
   gdk_draw_pixmap(map_canvas->window, civ_gc, map_canvas_store,
                  canvas_x, canvas_y, canvas_x, canvas_y,
                  pixel_width, pixel_height);
+
+}
+
+#define MAX_DIRTY_RECTS 20
+static int num_dirty_rects = 0;
+static GdkRectangle dirty_rects[MAX_DIRTY_RECTS];
+
+/**************************************************************************
+  Mark the rectangular region as 'dirty' so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  if (num_dirty_rects < MAX_DIRTY_RECTS) {
+    dirty_rects[num_dirty_rects].x = canvas_x;
+    dirty_rects[num_dirty_rects].y = canvas_y;
+    dirty_rects[num_dirty_rects].width = pixel_width;
+    dirty_rects[num_dirty_rects].height = pixel_height;
+    num_dirty_rects++;
+  }
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  num_dirty_rects = MAX_DIRTY_RECTS;
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  if (num_dirty_rects == MAX_DIRTY_RECTS) {
+    flush_mapcanvas(0, 0, map_canvas->allocation.width,
+                   map_canvas->allocation.height);
+  } else {
+    int i;
+
+    for (i = 0; i < num_dirty_rects; i++) {
+      flush_mapcanvas(dirty_rects[i].x, dirty_rects[i].y,
+                     dirty_rects[i].width, dirty_rects[i].height);
+    }
+  }
+  num_dirty_rects = 0;
 }
 
 /**************************************************************************
Index: client/gui-gtk-2.0/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/mapview.c,v
retrieving revision 1.47
diff -u -r1.47 mapview.c
--- client/gui-gtk-2.0/mapview.c        2003/02/22 13:15:30     1.47
+++ client/gui-gtk-2.0/mapview.c        2003/02/24 07:22:51
@@ -940,6 +940,45 @@
 }
 
 /**************************************************************************
+  Mark the rectangular region as "dirty" so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  /* GDK gives an error if we invalidate out-of-bounds parts of the
+     window. */
+  GdkRectangle rect = {MAX(canvas_x, 0), MAX(canvas_y, 0),
+                      MIN(pixel_width,
+                          map_canvas->allocation.width - canvas_x),
+                      MIN(pixel_height,
+                          map_canvas->allocation.height - canvas_y)};
+
+  gdk_window_invalidate_rect(map_canvas->window, &rect, FALSE);
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  GdkRectangle rect = {0, 0, map_canvas->allocation.width,
+                      map_canvas->allocation.height};
+
+  gdk_window_invalidate_rect(map_canvas->window, &rect, FALSE);
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  gdk_window_process_updates(map_canvas->window, FALSE);
+}
+
+/**************************************************************************
  Update display of descriptions associated with cities on the main map.
 **************************************************************************/
 void update_city_descriptions(void)
Index: client/gui-stub/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-stub/mapview.c,v
retrieving revision 1.28
diff -u -r1.28 mapview.c
--- client/gui-stub/mapview.c   2003/02/22 02:48:31     1.28
+++ client/gui-stub/mapview.c   2003/02/24 07:22:51
@@ -225,6 +225,33 @@
   /* PORTME */
 }
 
+/**************************************************************************
+  Mark the rectangular region as 'dirty' so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  /* PORTME */
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  /* PORTME */
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  /* PORTME */
+}
 
 /**************************************************************************
   Update (refresh) the locations of the mapview scrollbars (if it uses
Index: client/gui-win32/mapctrl.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/mapctrl.c,v
retrieving revision 1.20
diff -u -r1.20 mapctrl.c
--- client/gui-win32/mapctrl.c  2003/02/17 22:49:27     1.20
+++ client/gui-win32/mapctrl.c  2003/02/24 07:22:51
@@ -302,6 +302,7 @@
       } else {
        center_tile_mapcanvas(xtile,ytile);
       }
+      flush_dirty();
     }
     break;
   case WM_SETFOCUS:
@@ -371,7 +372,7 @@
    return;
  }
  center_tile_mapcanvas(xtile,ytile); 
-
+ flush_dirty();
 }
 
 /**************************************************************************
Index: client/gui-win32/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/mapview.c,v
retrieving revision 1.59
diff -u -r1.59 mapview.c
--- client/gui-win32/mapview.c  2003/02/22 13:15:30     1.59
+++ client/gui-win32/mapview.c  2003/02/24 07:22:52
@@ -677,6 +677,56 @@
   DeleteDC(mapstoredc);
 }
 
+#define MAX_DIRTY_RECTS 10
+static int num_dirty_rects = 0;
+static struct {
+  int x, y, w, h;
+} dirty_rects[MAX_DIRTY_RECTS];
+
+/**************************************************************************
+  Mark the rectangular region as 'dirty' so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  if (num_dirty_rects < MAX_DIRTY_RECTS) {
+    dirty_rects[num_dirty_rects].x = canvas_x;
+    dirty_rects[num_dirty_rects].y = canvas_y;
+    dirty_rects[num_dirty_rects].w = pixel_width;
+    dirty_rects[num_dirty_rects].h = pixel_height;
+    num_dirty_rects++;
+  }
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  num_dirty_rects = MAX_DIRTY_RECTS;
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  if (num_dirty_rects == MAX_DIRTY_RECTS) {
+    flush_mapcanvas(0, 0, map_win_width, map_win_height);
+  } else {
+    int i;
+
+    for (i = 0; i < num_dirty_rects; i++) {
+      flush_mapcanvas(dirty_rects[i].x, dirty_rects[i].y,
+                     dirty_rects[i].w, dirty_rects[i].h);
+    }
+  }
+  num_dirty_rects = 0;
+}
+
 /**************************************************************************
 
 **************************************************************************/
Index: client/gui-xaw/mapctrl.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/mapctrl.c,v
retrieving revision 1.64
diff -u -r1.64 mapctrl.c
--- client/gui-xaw/mapctrl.c    2003/02/17 22:49:27     1.64
+++ client/gui-xaw/mapctrl.c    2003/02/24 07:22:52
@@ -273,6 +273,7 @@
   else if (ev->button == Button3) {
     center_tile_mapcanvas(x, y);
   }
+  flush_dirty();
 }
 
 /**************************************************************************
@@ -386,6 +387,8 @@
     do_unit_goto(xtile,ytile);
   else if(ev->button==Button3)
     center_tile_mapcanvas(xtile, ytile);
+
+  flush_dirty();
 }
 
 /**************************************************************************
Index: client/gui-xaw/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/mapview.c,v
retrieving revision 1.126
diff -u -r1.126 mapview.c
--- client/gui-xaw/mapview.c    2003/02/22 13:15:30     1.126
+++ client/gui-xaw/mapview.c    2003/02/24 07:22:53
@@ -672,6 +672,57 @@
            canvas_x, canvas_y);
 }
 
+#define MAX_DIRTY_RECTS 20
+static int num_dirty_rects = 0;
+static XRectangle dirty_rects[MAX_DIRTY_RECTS];
+
+/**************************************************************************
+  Mark the rectangular region as 'dirty' so that we know to flush it
+  later.
+**************************************************************************/
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height)
+{
+  if (num_dirty_rects < MAX_DIRTY_RECTS) {
+    dirty_rects[num_dirty_rects].x = canvas_x;
+    dirty_rects[num_dirty_rects].y = canvas_y;
+    dirty_rects[num_dirty_rects].width = pixel_width;
+    dirty_rects[num_dirty_rects].height = pixel_height;
+    num_dirty_rects++;
+  }
+}
+
+/**************************************************************************
+  Mark the entire screen area as "dirty" so that we can flush it later.
+**************************************************************************/
+void dirty_all(void)
+{
+  num_dirty_rects = MAX_DIRTY_RECTS;
+}
+
+/**************************************************************************
+  Flush all regions that have been previously marked as dirty.  See
+  dirty_rect and dirty_all.  This function is generally called after we've
+  processed a batch of drawing operations.
+**************************************************************************/
+void flush_dirty(void)
+{
+  if (num_dirty_rects == MAX_DIRTY_RECTS) {
+    Dimension width, height;
+
+    XtVaGetValues(map_canvas, XtNwidth, &width, XtNheight, &height, NULL);
+    flush_mapcanvas(0, 0, width, height);
+  } else {
+    int i;
+
+    for (i = 0; i < num_dirty_rects; i++) {
+      flush_mapcanvas(dirty_rects[i].x, dirty_rects[i].y,
+                     dirty_rects[i].width, dirty_rects[i].height);
+    }
+  }
+  num_dirty_rects = 0;
+}
+
 /**************************************************************************
 ...
 **************************************************************************/
Index: client/include/mapview_g.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/include/mapview_g.h,v
retrieving revision 1.33
diff -u -r1.33 mapview_g.h
--- client/include/mapview_g.h  2003/02/22 02:48:31     1.33
+++ client/include/mapview_g.h  2003/02/24 07:22:53
@@ -52,6 +52,10 @@
                    int width, int height);
 void flush_mapcanvas(int canvas_x, int canvas_y,
                     int pixel_width, int pixel_height);
+void dirty_rect(int canvas_x, int canvas_y,
+               int pixel_width, int pixel_height);
+void dirty_all(void);
+void flush_dirty(void);
 
 void update_map_canvas_scrollbars(void);
 

[Prev in Thread] Current Thread [Next in Thread]