From 5d782454590afacfe142ef41f332ea8f40d0a2b1 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 28 Jan 2023 10:08:31 +0200 Subject: [PATCH 25/25] gtk4: Implement canvas_put_sprite_full_scaled() This changes also client gui API; parameter is added to load_gfxfile() telling if the file to load is a svgflag. See osdn #46607 Signed-off-by: Marko Lindqvist --- client/gui-gtk-3.22/pages.c | 2 +- client/gui-gtk-3.22/sprite.c | 4 +-- client/gui-gtk-4.0/canvas.c | 59 ++++++++++++++++++++++++++--------- client/gui-gtk-4.0/gui_main.c | 8 +++++ client/gui-gtk-4.0/pages.c | 2 +- client/gui-gtk-4.0/sprite.c | 36 ++++++++++++++++----- client/gui-gtk-4.0/sprite.h | 1 + client/gui-qt/qtg_cxxside.h | 2 +- client/gui-qt/sprite.cpp | 6 ++-- client/gui-sdl2/sprite.c | 6 ++-- client/gui-sdl2/themespec.c | 8 ++--- client/gui-stub/sprite.c | 6 ++-- client/gui_interface.c | 4 +-- client/gui_interface.h | 2 +- client/include/sprite_g.h | 12 ++++--- client/tilespec.c | 3 +- 16 files changed, 112 insertions(+), 49 deletions(-) diff --git a/client/gui-gtk-3.22/pages.c b/client/gui-gtk-3.22/pages.c index 1e6581c90c..1e8f25e0c4 100644 --- a/client/gui-gtk-3.22/pages.c +++ b/client/gui-gtk-3.22/pages.c @@ -245,7 +245,7 @@ GtkWidget *create_main_page(void) gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT); gtk_container_add(GTK_CONTAINER(vbox), frame); - intro_in = load_gfxfile(tileset_main_intro_filename(tileset)); + intro_in = load_gfxfile(tileset_main_intro_filename(tileset), FALSE); get_sprite_dimensions(intro_in, &width, &height); sh = screen_height(); diff --git a/client/gui-gtk-3.22/sprite.c b/client/gui-gtk-3.22/sprite.c index 2cf4883661..7262e01416 100644 --- a/client/gui-gtk-3.22/sprite.c +++ b/client/gui-gtk-3.22/sprite.c @@ -167,10 +167,10 @@ static void surf_destroy_callback(void *data) entire image file, which may later be broken up into individual sprites with crop_sprite(). ****************************************************************************/ -struct sprite *load_gfxfile(const char *filename) +struct sprite *load_gfxfile(const char *filename, bool svgflag) { struct sprite *spr; - GError *err = NULL;; + GError *err = NULL; GdkPixbuf *pb = gdk_pixbuf_new_from_file(filename, &err); int width; int height; diff --git a/client/gui-gtk-4.0/canvas.c b/client/gui-gtk-4.0/canvas.c index 4c3beee9cb..14d0d552b3 100644 --- a/client/gui-gtk-4.0/canvas.c +++ b/client/gui-gtk-4.0/canvas.c @@ -107,9 +107,9 @@ void canvas_copy(struct canvas *dest, struct canvas *src, Supplied coordinates are prior to any canvas zoom. ****************************************************************************/ void canvas_put_sprite(struct canvas *pcanvas, - int canvas_x, int canvas_y, - struct sprite *sprite, - int offset_x, int offset_y, int width, int height) + int canvas_x, int canvas_y, + struct sprite *sprite, + int offset_x, int offset_y, int width, int height) { int sswidth, ssheight; cairo_t *cr; @@ -146,14 +146,14 @@ void canvas_put_sprite(struct canvas *pcanvas, Supplied canvas_x/y are prior to any canvas zoom. ****************************************************************************/ void canvas_put_sprite_full(struct canvas *pcanvas, - int canvas_x, int canvas_y, - struct sprite *sprite) + int canvas_x, int canvas_y, + struct sprite *sprite) { int width, height; get_sprite_dimensions(sprite, &width, &height); canvas_put_sprite(pcanvas, canvas_x, canvas_y, sprite, - 0, 0, width, height); + 0, 0, width, height); } /************************************************************************//** @@ -164,22 +164,50 @@ void canvas_put_sprite_full_scaled(struct canvas *pcanvas, int canvas_w, int canvas_h, struct sprite *sprite) { - /* This should never be called as we have not enabled support - * in this client yet. */ - fc_assert(FALSE); + int sswidth, ssheight; + cairo_t *cr; + + fc_assert(sprite->svg != NULL); + + get_sprite_dimensions(sprite, &sswidth, &ssheight); + + if (!pcanvas->drawable) { + cr = cairo_create(pcanvas->surface); + } else { + cr = pcanvas->drawable; + } + + if (pcanvas->drawable) { + cairo_save(cr); + } + + log_normal("sprite: (%d, %d), canvas: (%d, %d)", + sswidth, ssheight, canvas_w, canvas_y); + + cairo_scale(cr, canvas_w / sswidth, canvas_y / ssheight); + cairo_set_source_surface(cr, sprite->surface, 0, 0); + cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); + cairo_rectangle(cr, canvas_x, canvas_y, canvas_w, canvas_h); + cairo_fill(cr); + + if (!pcanvas->drawable) { + cairo_destroy(cr); + } else { + cairo_restore(cr); + } } /************************************************************************//** - Draw a full sprite onto the canvas. If "fog" is specified draw it with + Draw a full sprite onto the canvas. If "fog" is specified, draw it with fog. ****************************************************************************/ void canvas_put_sprite_fogged(struct canvas *pcanvas, - int canvas_x, int canvas_y, - struct sprite *psprite, - bool fog, int fog_x, int fog_y) + int canvas_x, int canvas_y, + struct sprite *psprite, + bool fog, int fog_x, int fog_y) { - pixmap_put_overlay_tile_draw(pcanvas, canvas_x, canvas_y, - psprite, fog); + pixmap_put_overlay_tile_draw(pcanvas, canvas_x, canvas_y, + psprite, fog); } /************************************************************************//** @@ -224,6 +252,7 @@ void canvas_fill_sprite_area(struct canvas *pcanvas, int canvas_x, int canvas_y) { int width, height; + get_sprite_dimensions(psprite, &width, &height); canvas_put_rectangle(pcanvas, pcolor, canvas_x, canvas_y, width, height); } diff --git a/client/gui-gtk-4.0/gui_main.c b/client/gui-gtk-4.0/gui_main.c index 25681a6bb1..c6c9c2c409 100644 --- a/client/gui-gtk-4.0/gui_main.c +++ b/client/gui-gtk-4.0/gui_main.c @@ -70,6 +70,7 @@ #include "control.h" #include "editor.h" #include "options.h" +#include "svgflag.h" #include "text.h" #include "tilespec.h" #include "zoom.h" @@ -102,6 +103,9 @@ #include "gui_main.h" +/* Uncomment to enable svg flags */ +/* #define FC_GTK4_SVGFLAG */ + const char *client_string = "gui-gtk-4.0"; GtkWidget *map_canvas; /* GtkDrawingArea */ @@ -1689,6 +1693,10 @@ void ui_init(void) **************************************************************************/ int main(int argc, char **argv) { +#ifdef FC_GTK4_SVGFLAG + svg_flag_enable(); +#endif /* FC_GTK4_SVGFLAG */ + return client_main(argc, argv, FALSE); } diff --git a/client/gui-gtk-4.0/pages.c b/client/gui-gtk-4.0/pages.c index 30bd8381a6..fa22d899bf 100644 --- a/client/gui-gtk-4.0/pages.c +++ b/client/gui-gtk-4.0/pages.c @@ -251,7 +251,7 @@ GtkWidget *create_main_page(void) gtk_widget_set_halign(frame, GTK_ALIGN_CENTER); gtk_grid_attach(GTK_GRID(vgrid), frame, 0, grid_row++, 1, 1); - intro_in = load_gfxfile(tileset_main_intro_filename(tileset)); + intro_in = load_gfxfile(tileset_main_intro_filename(tileset), FALSE); get_sprite_dimensions(intro_in, &width, &height); sh = screen_height(); diff --git a/client/gui-gtk-4.0/sprite.c b/client/gui-gtk-4.0/sprite.c index 2beffadbb1..9f07239317 100644 --- a/client/gui-gtk-4.0/sprite.c +++ b/client/gui-gtk-4.0/sprite.c @@ -34,14 +34,14 @@ source gives the sprite that is to be cropped. - x,y, width, height gives the rectangle to be cropped. The pixel at + x,y, width, height gives the rectangle to be cropped. The pixel at position of the source sprite will be at (0,0) in the new sprite, and the new sprite will have dimensions (width, height). mask gives an additional mask to be used for clipping the new sprite. mask_offset_x, mask_offset_y is the offset of the mask relative to the - origin of the source image. The pixel at (mask_offset_x,mask_offset_y) + origin of the source image. The pixel at (mask_offset_x, mask_offset_y) in the mask image will be used to clip pixel (0,0) in the source image which is pixel (-x,-y) in the new image. @@ -62,6 +62,7 @@ struct sprite *crop_sprite(struct sprite *source, new->surface = cairo_surface_create_similar(source->surface, CAIRO_CONTENT_COLOR_ALPHA, width, height); + new->svg = NULL; cr = cairo_create(new->surface); cairo_rectangle(cr, 0, 0, width, height); cairo_clip(cr); @@ -92,6 +93,7 @@ struct sprite *create_sprite(int width, int height, struct color *pcolor) sprite->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + sprite->svg = NULL; cr = cairo_create(sprite->surface); gdk_cairo_set_source_rgba(cr, &pcolor->color); @@ -106,8 +108,13 @@ struct sprite *create_sprite(int width, int height, struct color *pcolor) ****************************************************************************/ void get_sprite_dimensions(struct sprite *sprite, int *width, int *height) { - *width = cairo_image_surface_get_width(sprite->surface); - *height = cairo_image_surface_get_height(sprite->surface); + if (sprite->svg != NULL) { + *width = gdk_pixbuf_get_width(sprite->svg); + *height = gdk_pixbuf_get_height(sprite->svg); + } else { + *width = cairo_image_surface_get_width(sprite->surface); + *height = cairo_image_surface_get_height(sprite->surface); + } } /************************************************************************//** @@ -167,10 +174,10 @@ static void surf_destroy_callback(void *data) entire image file, which may later be broken up into individual sprites with crop_sprite(). ****************************************************************************/ -struct sprite *load_gfxfile(const char *filename) +struct sprite *load_gfxfile(const char *filename, bool svgflag) { struct sprite *spr; - GError *err = NULL;; + GError *err = NULL; GdkPixbuf *pb = gdk_pixbuf_new_from_file(filename, &err); int width; int height; @@ -198,6 +205,12 @@ struct sprite *load_gfxfile(const char *filename) has_alpha = gdk_pixbuf_get_has_alpha(pb); channels = gdk_pixbuf_get_n_channels(pb); + if (svgflag) { + spr->svg = pb; + } else { + spr->svg = NULL; + } + cairo_stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); if (cairo_stride <= 0) { log_error("Cairo does not give stride for width %d", width); @@ -246,7 +259,9 @@ struct sprite *load_gfxfile(const char *filename) pbdata += rs; } - g_object_unref(pb); + if (!svgflag) { + g_object_unref(pb); + } spr->surface = cairo_image_surface_create_for_data(cairo_data, CAIRO_FORMAT_ARGB32, width, height, cairo_stride); @@ -275,12 +290,16 @@ struct sprite *load_gfxfile(const char *filename) /************************************************************************//** Free a sprite and all associated image data. ****************************************************************************/ -void free_sprite(struct sprite * s) +void free_sprite(struct sprite *s) { if (s->surface != NULL) { cairo_surface_destroy(s->surface); } + if (s->svg != NULL) { + g_object_unref(s->svg); + } + free(s); } @@ -298,6 +317,7 @@ struct sprite *sprite_scale(struct sprite *src, int new_w, int new_h) new->surface = cairo_surface_create_similar(src->surface, CAIRO_CONTENT_COLOR_ALPHA, new_w, new_h); + new->svg = NULL; cr = cairo_create(new->surface); cairo_save(cr); diff --git a/client/gui-gtk-4.0/sprite.h b/client/gui-gtk-4.0/sprite.h index 78eb30063d..f43a64dcab 100644 --- a/client/gui-gtk-4.0/sprite.h +++ b/client/gui-gtk-4.0/sprite.h @@ -21,6 +21,7 @@ struct sprite { cairo_surface_t *surface; + GdkPixbuf *svg; }; struct sprite *sprite_scale(struct sprite *src, int new_w, int new_h); diff --git a/client/gui-qt/qtg_cxxside.h b/client/gui-qt/qtg_cxxside.h index e230745676..b1110a39ee 100644 --- a/client/gui-qt/qtg_cxxside.h +++ b/client/gui-qt/qtg_cxxside.h @@ -41,7 +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); -struct sprite *qtg_load_gfxfile(const char *filename); +struct sprite *qtg_load_gfxfile(const char *filename, bool svgflag); struct sprite *qtg_load_gfxnumber(int num); struct sprite *qtg_create_sprite(int width, int height, struct color *pcolor); void qtg_get_sprite_dimensions(struct sprite *sprite, int *width, int *height); diff --git a/client/gui-qt/sprite.cpp b/client/gui-qt/sprite.cpp index 89df676a29..8b903658c0 100644 --- a/client/gui-qt/sprite.cpp +++ b/client/gui-qt/sprite.cpp @@ -60,11 +60,11 @@ const char **gfx_fileextensions(void) } /************************************************************************//** - Load the given graphics file into a sprite. This function loads an + Load the given graphics file into a sprite. This function loads an entire image file, which may later be broken up into individual sprites - with crop_sprite. + with crop_sprite(). ****************************************************************************/ -struct sprite *qtg_load_gfxfile(const char *filename) +struct sprite *qtg_load_gfxfile(const char *filename, bool svgflag) { sprite *entire = new sprite; QPixmap *pm = new QPixmap; diff --git a/client/gui-sdl2/sprite.c b/client/gui-sdl2/sprite.c index 44dbc919ff..7e7efb4a38 100644 --- a/client/gui-sdl2/sprite.c +++ b/client/gui-sdl2/sprite.c @@ -54,11 +54,11 @@ const char **gfx_fileextensions(void) } /************************************************************************//** - Load the given graphics file into a sprite. This function loads an + Load the given graphics file into a sprite. This function loads an entire image file, which may later be broken up into individual sprites - with crop_sprite. + with crop_sprite(). ****************************************************************************/ -struct sprite *load_gfxfile(const char *filename) +struct sprite *load_gfxfile(const char *filename, bool svgflag) { SDL_Surface *pbuf = NULL; diff --git a/client/gui-sdl2/themespec.c b/client/gui-sdl2/themespec.c index 2f5fa719ce..be92b8a7d1 100644 --- a/client/gui-sdl2/themespec.c +++ b/client/gui-sdl2/themespec.c @@ -448,7 +448,7 @@ void themespec_reread(const char *new_theme_name) Loads the given graphics file (found in the data path) into a newly allocated sprite. ****************************************************************************/ -static struct sprite *load_gfx_file(const char *gfx_filename) +static struct sprite *load_sdl2_gfx_file(const char *gfx_filename) { const char **gfx_fileexts = gfx_fileextensions(), *gfx_fileext; struct sprite *s; @@ -462,7 +462,7 @@ static struct sprite *load_gfx_file(const char *gfx_filename) sprintf(full_name, "%s.%s", gfx_filename, gfx_fileext); if ((real_full_name = fileinfoname(get_data_dirs(), full_name))) { log_debug("trying to load gfx file \"%s\".", real_full_name); - s = load_gfxfile(real_full_name); + s = load_gfxfile(real_full_name, FALSE); if (s) { return s; } @@ -502,7 +502,7 @@ static void theme_ensure_big_sprite(struct specfile *sf) gfx_filename = secfile_lookup_str(file, "file.gfx"); - sf->big_sprite = load_gfx_file(gfx_filename); + sf->big_sprite = load_sdl2_gfx_file(gfx_filename); if (!sf->big_sprite) { log_fatal("Could not load gfx file for the spec file \"%s\".", @@ -856,7 +856,7 @@ static struct sprite *theme_load_sprite(struct theme *t, const char *tag_name) /* If the sprite hasn't been loaded already, then load it. */ fc_assert_ret_val(ss->ref_count == 0, NULL); if (ss->file) { - ss->sprite = load_gfx_file(ss->file); + ss->sprite = load_sdl2_gfx_file(ss->file); if (!ss->sprite) { log_fatal("Couldn't load gfx file \"%s\" for sprite '%s'.", ss->file, tag_name); diff --git a/client/gui-stub/sprite.c b/client/gui-stub/sprite.c index 23b6da97b0..4377fe9a3a 100644 --- a/client/gui-stub/sprite.c +++ b/client/gui-stub/sprite.c @@ -42,11 +42,11 @@ const char **gfx_fileextensions(void) } /************************************************************************//** - Load the given graphics file into a sprite. This function loads an + Load the given graphics file into a sprite. This function loads an entire image file, which may later be broken up into individual sprites - with crop_sprite. + with crop_sprite(). ****************************************************************************/ -struct sprite *gui_load_gfxfile(const char *filename) +struct sprite *gui_load_gfxfile(const char *filename, bool svgflag) { /* PORTME */ return NULL; diff --git a/client/gui_interface.c b/client/gui_interface.c index d434ff8956..fec424e1b5 100644 --- a/client/gui_interface.c +++ b/client/gui_interface.c @@ -121,9 +121,9 @@ void tileset_type_set(enum ts_type type) /**********************************************************************//** Call load_gfxfile callback **************************************************************************/ -struct sprite *load_gfxfile(const char *filename) +struct sprite *load_gfxfile(const char *filename, bool svgflag) { - return funcs.load_gfxfile(filename); + return funcs.load_gfxfile(filename, svgflag); } /**********************************************************************//** diff --git a/client/gui_interface.h b/client/gui_interface.h index 16d7fff3ca..be7864ed10 100644 --- a/client/gui_interface.h +++ b/client/gui_interface.h @@ -48,7 +48,7 @@ struct gui_funcs { bool (*is_view_supported)(enum ts_type type); void (*tileset_type_set)(enum ts_type type); - struct sprite * (*load_gfxfile)(const char *filename); + struct sprite * (*load_gfxfile)(const char *filename, bool svgflag); struct sprite * (*load_gfxnumber)(int num); struct sprite * (*create_sprite)(int width, int height, struct color *pcolor); void (*get_sprite_dimensions)(struct sprite *sprite, int *width, int *height); diff --git a/client/include/sprite_g.h b/client/include/sprite_g.h index 64f8887f2c..dff91657ba 100644 --- a/client/include/sprite_g.h +++ b/client/include/sprite_g.h @@ -1,4 +1,4 @@ -/********************************************************************** +/*********************************************************************** Freeciv - Copyright (C) 1996-2005 - Freeciv Development Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,15 +13,19 @@ #ifndef FC__SPRITE_G_H #define FC__SPRITE_G_H +/* utility */ #include "support.h" + +/* client */ #include "gui_proto_constructor.h" -struct sprite; /* opaque type, real type is gui-dep */ +struct sprite; /* Opaque type, real type is gui-dep */ struct color; GUI_FUNC_PROTO(const char **, gfx_fileextensions, void) -GUI_FUNC_PROTO(struct sprite *, load_gfxfile, const char *filename) +GUI_FUNC_PROTO(struct sprite *, load_gfxfile, const char *filename, + bool svgflag) GUI_FUNC_PROTO(struct sprite *, load_gfxnumber, int num) GUI_FUNC_PROTO(struct sprite *, crop_sprite, struct sprite *source, int x, int y, int width, int height, @@ -33,4 +37,4 @@ GUI_FUNC_PROTO(void, get_sprite_dimensions, struct sprite *sprite, int *width, int *height) GUI_FUNC_PROTO(void, free_sprite, struct sprite *s) -#endif /* FC__SPRITE_G_H */ +#endif /* FC__SPRITE_G_H */ diff --git a/client/tilespec.c b/client/tilespec.c index 91493cd67d..c85ea32b5d 100644 --- a/client/tilespec.c +++ b/client/tilespec.c @@ -1545,7 +1545,8 @@ static struct sprite *load_gfx_file(const char *gfx_filename, bool flag) sprintf(full_name, "%s.%s", gfx_filename, gfx_fileext); if ((real_full_name = fileinfoname(get_data_dirs(), full_name))) { log_debug("trying to load gfx file \"%s\".", real_full_name); - s = load_gfxfile(real_full_name); + s = load_gfxfile(real_full_name, + flag && !strcmp("svg", gfx_fileext)); if (s) { return s; } -- 2.39.0