From 518fb9ac0020ed6ecf8f1f050cbfc0b7b868f862 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 3 Jun 2023 04:52:28 +0300 Subject: [PATCH 24/24] gtk4: Fix map recenter issues near map wrapping point The bug is not specific to gtk4-client, but the fix (/workaround) is. - Client-common code is improved slightly, so that the recenter works correctly in the special case when cached drawing is disabled - Added means for a gui to disable cached drawing - Made gtk4-client to always disable cached drawing See osdn #48150 Signed-off-by: Marko Lindqvist --- client/gui-gtk-3.0/graphics.c | 8 +++++ client/gui-gtk-3.22/graphics.c | 8 +++++ client/gui-gtk-4.0/graphics.c | 8 +++++ client/gui-qt/graphics.cpp | 8 +++++ client/gui-qt/qtg_cxxside.cpp | 1 + client/gui-qt/qtg_cxxside.h | 1 + client/gui-sdl2/graphics.c | 8 +++++ client/gui-stub/graphics.c | 8 +++++ client/gui_interface.c | 8 +++++ client/gui_interface.h | 1 + client/include/graphics_g.h | 4 ++- client/mapview_common.c | 55 +++++++++++++++++++++++----------- 12 files changed, 99 insertions(+), 19 deletions(-) diff --git a/client/gui-gtk-3.0/graphics.c b/client/gui-gtk-3.0/graphics.c index 8496afca7c..030498e597 100644 --- a/client/gui-gtk-3.0/graphics.c +++ b/client/gui-gtk-3.0/graphics.c @@ -68,6 +68,14 @@ void tileset_type_set(enum ts_type type) { } +/***********************************************************************//** + Tell client-common code that it may use cached drawing. +***************************************************************************/ +bool allow_cached_drawing(void) +{ + return TRUE; +} + #define COLOR_MOTTO_FACE_R 0x2D #define COLOR_MOTTO_FACE_G 0x71 #define COLOR_MOTTO_FACE_B 0xE3 diff --git a/client/gui-gtk-3.22/graphics.c b/client/gui-gtk-3.22/graphics.c index 388c0d2e19..84f65f38ca 100644 --- a/client/gui-gtk-3.22/graphics.c +++ b/client/gui-gtk-3.22/graphics.c @@ -68,6 +68,14 @@ void tileset_type_set(enum ts_type type) { } +/***********************************************************************//** + Tell client-common code that it may use cached drawing. +***************************************************************************/ +bool allow_cached_drawing(void) +{ + return TRUE; +} + #define COLOR_MOTTO_FACE_R 0x2D #define COLOR_MOTTO_FACE_G 0x71 #define COLOR_MOTTO_FACE_B 0xE3 diff --git a/client/gui-gtk-4.0/graphics.c b/client/gui-gtk-4.0/graphics.c index 1ec64bd5dd..a31f1d5a95 100644 --- a/client/gui-gtk-4.0/graphics.c +++ b/client/gui-gtk-4.0/graphics.c @@ -68,6 +68,14 @@ void tileset_type_set(enum ts_type type) { } +/***********************************************************************//** + Tell client-common code that cached drawing should never be used. +***************************************************************************/ +bool allow_cached_drawing(void) +{ + return FALSE; +} + #define COLOR_MOTTO_FACE_R 0x2D #define COLOR_MOTTO_FACE_G 0x71 #define COLOR_MOTTO_FACE_B 0xE3 diff --git a/client/gui-qt/graphics.cpp b/client/gui-qt/graphics.cpp index f09fd877f2..0425f8c9bb 100644 --- a/client/gui-qt/graphics.cpp +++ b/client/gui-qt/graphics.cpp @@ -42,3 +42,11 @@ bool qtg_is_view_supported(enum ts_type type) void qtg_tileset_type_set(enum ts_type type) { } + +/***********************************************************************//** + Tell client-common code that it may use cached drawing. +***************************************************************************/ +bool qtg_allow_cached_drawing() +{ + return TRUE; +} diff --git a/client/gui-qt/qtg_cxxside.cpp b/client/gui-qt/qtg_cxxside.cpp index 62518a0193..e75de4ec01 100644 --- a/client/gui-qt/qtg_cxxside.cpp +++ b/client/gui-qt/qtg_cxxside.cpp @@ -42,6 +42,7 @@ void setup_gui_funcs() funcs->is_view_supported = qtg_is_view_supported; funcs->tileset_type_set = qtg_tileset_type_set; + funcs->allow_cached_drawing = qtg_allow_cached_drawing; funcs->load_gfxfile = qtg_load_gfxfile; funcs->load_gfxnumber = qtg_load_gfxnumber; funcs->create_sprite = qtg_create_sprite; diff --git a/client/gui-qt/qtg_cxxside.h b/client/gui-qt/qtg_cxxside.h index c4f73e1f95..d5336e6960 100644 --- a/client/gui-qt/qtg_cxxside.h +++ b/client/gui-qt/qtg_cxxside.h @@ -41,6 +41,7 @@ void qtg_real_output_window_append(const char *astring, bool qtg_is_view_supported(enum ts_type type); void qtg_tileset_type_set(enum ts_type type); +bool qtg_allow_cached_drawing(); struct sprite *qtg_load_gfxfile(const char *filename); struct sprite *qtg_load_gfxnumber(int num); struct sprite *qtg_create_sprite(int width, int height, struct color *pcolor); diff --git a/client/gui-sdl2/graphics.c b/client/gui-sdl2/graphics.c index 191e44ddb6..01ff5c98fd 100644 --- a/client/gui-sdl2/graphics.c +++ b/client/gui-sdl2/graphics.c @@ -1798,6 +1798,14 @@ void tileset_type_set(enum ts_type type) { } +/***********************************************************************//** + Tell client-common code that it may use cached drawing. +***************************************************************************/ +bool allow_cached_drawing(void) +{ + return TRUE; +} + /**********************************************************************//** Create colored frame **************************************************************************/ diff --git a/client/gui-stub/graphics.c b/client/gui-stub/graphics.c index f34371cb24..d9f378906c 100644 --- a/client/gui-stub/graphics.c +++ b/client/gui-stub/graphics.c @@ -41,6 +41,14 @@ void gui_tileset_type_set(enum ts_type type) { } +/***********************************************************************//** + Tell client-common code that it may use cached drawing. +***************************************************************************/ +bool gui_allow_cached_drawing(void) +{ + return TRUE; +} + /************************************************************************//** Load the cursors (mouse substitute sprites), including a goto cursor, an airdrop cursor, a nuke cursor, and a patrol cursor. diff --git a/client/gui_interface.c b/client/gui_interface.c index fcc077b56a..7b2de5c6c5 100644 --- a/client/gui_interface.c +++ b/client/gui_interface.c @@ -117,6 +117,14 @@ void tileset_type_set(enum ts_type type) funcs.tileset_type_set(type); } +/**********************************************************************//** + Call allow_cached_drawing callback +**************************************************************************/ +bool allow_cached_drawing(void) +{ + return funcs.allow_cached_drawing(); +} + /**********************************************************************//** Call load_gfxfile callback **************************************************************************/ diff --git a/client/gui_interface.h b/client/gui_interface.h index e1e58454e1..f7e96df087 100644 --- a/client/gui_interface.h +++ b/client/gui_interface.h @@ -45,6 +45,7 @@ struct gui_funcs { bool (*is_view_supported)(enum ts_type type); void (*tileset_type_set)(enum ts_type type); + bool (*allow_cached_drawing)(void); struct sprite * (*load_gfxfile)(const char *filename); struct sprite * (*load_gfxnumber)(int num); struct sprite * (*create_sprite)(int width, int height, struct color *pcolor); diff --git a/client/include/graphics_g.h b/client/include/graphics_g.h index a8c30b7941..7a83e6353e 100644 --- a/client/include/graphics_g.h +++ b/client/include/graphics_g.h @@ -27,6 +27,8 @@ GUI_FUNC_PROTO(bool, is_view_supported, enum ts_type type) GUI_FUNC_PROTO(void, tileset_type_set, enum ts_type type) +GUI_FUNC_PROTO(bool, allow_cached_drawing, void) + GUI_FUNC_PROTO(void, load_cursors, void) -#endif /* FC__GRAPHICS_G_H */ +#endif /* FC__GRAPHICS_G_H */ diff --git a/client/mapview_common.c b/client/mapview_common.c index 29e6dcf207..c373da1c28 100644 --- a/client/mapview_common.c +++ b/client/mapview_common.c @@ -841,7 +841,6 @@ static void base_set_mapview_origin(float gui_x0, float gui_y0) float dx, dy; const int width = mapview.width, height = mapview.height; int common_x0, common_x1, common_y0, common_y1; - int update_x0, update_x1, update_y0, update_y1; /* Then update everything. This does some tricky math to avoid having * to do unnecessary redraws in update_map_canvas. This makes for ugly @@ -859,9 +858,6 @@ static void base_set_mapview_origin(float gui_x0, float gui_y0) old_gui_x0 = gui_x0 - dx; old_gui_y0 = gui_y0 - dy; - mapview.gui_x0 = gui_x0; - mapview.gui_y0 = gui_y0; - /* Find the overlapping area of the new and old mapview. This is * done in GUI coordinates. Note that if the GUI coordinates wrap * no overlap will be found. */ @@ -872,9 +868,10 @@ static void base_set_mapview_origin(float gui_x0, float gui_y0) if (mapview.can_do_cached_drawing && !zoom_is_enabled() && common_x1 > common_x0 && common_y1 > common_y0) { - /* Do a partial redraw only. This means the area of overlap (a - * rectangle) is copied. Then the remaining areas (two rectangles) + /* Do a partial redraw only. This means the area of overlap (a + * rectangle) is copied. Then the remaining areas (two rectangles) * are updated through update_map_canvas. */ + int update_x0, update_x1, update_y0, update_y1; struct canvas *target = mapview.tmp_store; if (old_gui_x0 < gui_x0) { @@ -901,6 +898,13 @@ static void base_set_mapview_origin(float gui_x0, float gui_y0) mapview.tmp_store = mapview.store; mapview.store = target; + /* FIXME: partial update_map_canvas() would break completely + * if these are not updated before the call, but + * it sometimes causes screen to recenter to wrong + * place when they *are* updated. */ + mapview.gui_x0 = gui_x0; + mapview.gui_y0 = gui_y0; + if (update_y1 > update_y0) { update_map_canvas(0, update_y0 - gui_y0, width, update_y1 - update_y0); @@ -912,6 +916,11 @@ static void base_set_mapview_origin(float gui_x0, float gui_y0) } else { dirty_all(); update_map_canvas(0, 0, mapview.store_width, mapview.store_height); + + /* Set them correctly after update_map_canvas() has done its + * updates based on old values. */ + mapview.gui_x0 = gui_x0; + mapview.gui_y0 = gui_y0; } center_tile_overviewcanvas(); @@ -3202,9 +3211,18 @@ void get_city_mapview_name_and_growth(struct city *pcity, ****************************************************************************/ static bool can_do_cached_drawing(void) { - const int W = tileset_tile_width(tileset) * map_zoom; - const int H = tileset_tile_height(tileset) * map_zoom; - int w = mapview.store_width, h = mapview.store_height; + int tw, th; + int w, h; + + if (!allow_cached_drawing()) { + /* gui does not allow it. */ + return FALSE; + } + + tw = tileset_tile_width(tileset) * map_zoom; + th = tileset_tile_height(tileset) * map_zoom; + w = mapview.store_width; + h = mapview.store_height; /* If the mapview window is too large, cached drawing is not possible. * @@ -3239,19 +3257,19 @@ static bool can_do_cached_drawing(void) return TRUE; } if (XOR(current_topo_has_flag(TF_ISO) || current_topo_has_flag(TF_HEX), - tileset_is_isometric(tileset))) { - /* Non-matching. In this case the mapview does not line up with the - * map's axis of wrapping. This will give very bad results for the + tileset_is_isometric(tileset))) { + /* Non-matching. In this case the mapview does not line up with the + * map's axis of wrapping. This will give very bad results for the * player! * We can never show more than half of the map. * - * We divide by 4 below because we have to divide by 2 twice. The + * We divide by 4 below because we have to divide by 2 twice. The * first division by 2 is because the square must be half the size - * of the (width+height). The second division by two is because for + * of the (width+height). The second division by two is because for * an iso-map, NATURAL_XXX has a scale of 2, whereas for iso-view * NORMAL_TILE_XXX has a scale of 2. */ - return (w <= (NATURAL_WIDTH + NATURAL_HEIGHT) * W / 4 - && h <= (NATURAL_WIDTH + NATURAL_HEIGHT) * H / 4); + return (w <= (NATURAL_WIDTH + NATURAL_HEIGHT) * tw / 4 + && h <= (NATURAL_WIDTH + NATURAL_HEIGHT) * th / 4); } else { /* Matching. */ const int isofactor = (tileset_is_isometric(tileset) ? 2 : 1); @@ -3260,13 +3278,14 @@ static bool can_do_cached_drawing(void) /* Now we can use the full width and height, with the exception of a small * area on each side. */ if (current_topo_has_flag(TF_WRAPX) - && w > (NATURAL_WIDTH - isodiff) * W / isofactor) { + && w > (NATURAL_WIDTH - isodiff) * tw / isofactor) { return FALSE; } if (current_topo_has_flag(TF_WRAPY) - && h > (NATURAL_HEIGHT - isodiff) * H / isofactor) { + && h > (NATURAL_HEIGHT - isodiff) * th / isofactor) { return FALSE; } + return TRUE; } } -- 2.39.2