[Freeciv-Dev] Re: (PR#12557) RFC: new files sprite.c and canvas.c
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://bugs.freeciv.org/Ticket/Display.html?id=12557 >
Jason Short wrote:
> This patch makes the base change.
>
> * New files canvas_g.h and sprite_g.h.
> * Some slightly changed includes.
> * New gui-stub files canvas.[ch] and sprite.[ch].
And here is a patch for gtk2. Naturally it requires the other patch.
I cheated a bit by adding the new headers as includes inside the old
headers (mapview and graphics) rather than adding new includes to all
the .c files. However I did remove the include from gui_main.h. I also
had to change gtkpixcomm.h to prevent a recursive include.
This patch is copy-and-paste but I fixed up a lot of comments. Really
the main advantage is that mapview.c (which is a monster) gets a little
smaller. However in future I think we could hide the structs and have
accessors for everything.
-jason
Index: client/gui-gtk-2.0/Makefile.am
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/Makefile.am,v
retrieving revision 1.7
diff -u -r1.7 Makefile.am
--- client/gui-gtk-2.0/Makefile.am 18 Oct 2004 23:49:27 -0000 1.7
+++ client/gui-gtk-2.0/Makefile.am 22 Mar 2005 00:01:58 -0000
@@ -22,6 +22,8 @@
libguiclient_a_SOURCES = \
rc2c \
Freeciv.h \
+ canvas.c \
+ canvas.h \
chatline.h \
chatline.c \
citydlg.c \
@@ -81,6 +83,8 @@
resources.h \
spaceshipdlg.c \
spaceshipdlg.h \
+ sprite.c \
+ sprite.h \
wldlg.c \
wldlg.h
Index: client/gui-gtk-2.0/canvas.c
===================================================================
RCS file: client/gui-gtk-2.0/canvas.c
diff -N client/gui-gtk-2.0/canvas.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ client/gui-gtk-2.0/canvas.c 22 Mar 2005 00:01:58 -0000
@@ -0,0 +1,322 @@
+/**********************************************************************
+ 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
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "canvas.h"
+#include "colors.h"
+#include "gui_main.h"
+#include "mapview.h"
+
+/****************************************************************************
+ Create a canvas of the given size.
+****************************************************************************/
+struct canvas *canvas_create(int width, int height)
+{
+ struct canvas *result = fc_malloc(sizeof(*result));
+
+ result->type = CANVAS_PIXMAP;
+ result->v.pixmap = gdk_pixmap_new(root_window, width, height, -1);
+ return result;
+}
+
+/****************************************************************************
+ Free any resources associated with this canvas and the canvas struct
+ itself.
+****************************************************************************/
+void canvas_free(struct canvas *store)
+{
+ if (store->type == CANVAS_PIXMAP) {
+ g_object_unref(store->v.pixmap);
+ }
+ free(store);
+}
+
+/****************************************************************************
+ Copies an area from the source canvas to the destination canvas.
+****************************************************************************/
+void canvas_copy(struct canvas *dest, struct canvas *src,
+ int src_x, int src_y, int dest_x, int dest_y,
+ int width, int height)
+{
+ if (dest->type == src->type) {
+ if (src->type == CANVAS_PIXMAP) {
+ gdk_draw_drawable(dest->v.pixmap, fill_bg_gc, src->v.pixmap,
+ src_x, src_y, dest_x, dest_y, width, height);
+ }
+ }
+}
+
+/****************************************************************************
+ Place part of a (possibly masked) sprite on a pixmap.
+****************************************************************************/
+static void pixmap_put_sprite(GdkDrawable *pixmap,
+ int pixmap_x, int pixmap_y,
+ struct Sprite *ssprite,
+ int offset_x, int offset_y,
+ int width, int height)
+{
+ if (ssprite->pixmap) {
+ if (ssprite->mask) {
+ gdk_gc_set_clip_origin(civ_gc, pixmap_x, pixmap_y);
+ gdk_gc_set_clip_mask(civ_gc, ssprite->mask);
+ }
+
+ gdk_draw_drawable(pixmap, civ_gc, ssprite->pixmap,
+ offset_x, offset_y,
+ pixmap_x + offset_x, pixmap_y + offset_y,
+ MIN(width, MAX(0, ssprite->width - offset_x)),
+ MIN(height, MAX(0, ssprite->height - offset_y)));
+
+ gdk_gc_set_clip_mask(civ_gc, NULL);
+ } else {
+ gdk_draw_pixbuf(pixmap, civ_gc, ssprite->pixbuf,
+ offset_x, offset_y,
+ pixmap_x + offset_x, pixmap_y + offset_y,
+ MIN(width, MAX(0, ssprite->width - offset_x)),
+ MIN(height, MAX(0, ssprite->height - offset_y)),
+ GDK_RGB_DITHER_NONE, 0, 0);
+ }
+}
+
+/****************************************************************************
+ Draw some or all of a sprite onto the mapview or citydialog canvas.
+****************************************************************************/
+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)
+{
+ switch (pcanvas->type) {
+ case CANVAS_PIXMAP:
+ pixmap_put_sprite(pcanvas->v.pixmap, canvas_x, canvas_y,
+ sprite, offset_x, offset_y, width, height);
+ break;
+ case CANVAS_PIXCOMM:
+ gtk_pixcomm_copyto(pcanvas->v.pixcomm, sprite, canvas_x, canvas_y);
+ break;
+ case CANVAS_PIXBUF:
+ {
+ GdkPixbuf *src, *dst;
+
+ /* FIXME: is this right??? */
+ if (canvas_x < 0) {
+ offset_x -= canvas_x;
+ canvas_x = 0;
+ }
+ if (canvas_y < 0) {
+ offset_y -= canvas_y;
+ canvas_y = 0;
+ }
+
+
+ src = sprite_get_pixbuf(sprite);
+ dst = pcanvas->v.pixbuf;
+ gdk_pixbuf_composite(src, dst, canvas_x, canvas_y,
+ MIN(width,
+ MIN(gdk_pixbuf_get_width(dst), gdk_pixbuf_get_width(src))),
+ MIN(height,
+ MIN(gdk_pixbuf_get_height(dst), gdk_pixbuf_get_height(src))),
+ canvas_x - offset_x, canvas_y - offset_y,
+ 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/****************************************************************************
+ Draw a full sprite onto the mapview or citydialog canvas.
+****************************************************************************/
+void canvas_put_sprite_full(struct canvas *pcanvas,
+ int canvas_x, int canvas_y,
+ struct Sprite *sprite)
+{
+ canvas_put_sprite(pcanvas, canvas_x, canvas_y, sprite,
+ 0, 0, sprite->width, sprite->height);
+}
+
+/****************************************************************************
+ 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)
+{
+ if (pcanvas->type == CANVAS_PIXMAP) {
+ pixmap_put_overlay_tile_draw(pcanvas->v.pixmap, canvas_x, canvas_y,
+ psprite, fog);
+ }
+}
+
+/****************************************************************************
+ Draw a filled-in colored rectangle onto the mapview or citydialog canvas.
+****************************************************************************/
+void canvas_put_rectangle(struct canvas *pcanvas,
+ enum color_std color,
+ int canvas_x, int canvas_y, int width, int height)
+{
+ GdkColor *col = colors_standard[color];
+
+ switch (pcanvas->type) {
+ case CANVAS_PIXMAP:
+ gdk_gc_set_foreground(fill_bg_gc, col);
+ gdk_draw_rectangle(pcanvas->v.pixmap, fill_bg_gc, TRUE,
+ canvas_x, canvas_y, width, height);
+ break;
+ case CANVAS_PIXCOMM:
+ gtk_pixcomm_fill(pcanvas->v.pixcomm, col);
+ break;
+ case CANVAS_PIXBUF:
+ gdk_pixbuf_fill(pcanvas->v.pixbuf,
+ ((guint32)(col->red & 0xff00) << 16)
+ | ((col->green & 0xff00) << 8) | (col->blue & 0xff00) | 0xff);
+ break;
+ default:
+ break;
+ }
+}
+
+/****************************************************************************
+ Fill the area covered by the sprite with the given color.
+****************************************************************************/
+void canvas_fill_sprite_area(struct canvas *pcanvas,
+ struct Sprite *psprite, enum color_std color,
+ int canvas_x, int canvas_y)
+{
+ if (pcanvas->type == CANVAS_PIXMAP) {
+ gdk_gc_set_clip_origin(fill_bg_gc, canvas_x, canvas_y);
+ gdk_gc_set_clip_mask(fill_bg_gc, sprite_get_mask(psprite));
+ gdk_gc_set_foreground(fill_bg_gc, colors_standard[color]);
+
+ gdk_draw_rectangle(pcanvas->v.pixmap, fill_bg_gc, TRUE,
+ canvas_x, canvas_y, psprite->width, psprite->height);
+
+ gdk_gc_set_clip_mask(fill_bg_gc, NULL);
+ }
+}
+
+/****************************************************************************
+ Fill the area covered by the sprite with the given color.
+****************************************************************************/
+void canvas_fog_sprite_area(struct canvas *pcanvas, struct Sprite *psprite,
+ int canvas_x, int canvas_y)
+{
+ if (pcanvas->type == CANVAS_PIXMAP) {
+ gdk_gc_set_clip_origin(fill_tile_gc, canvas_x, canvas_y);
+ gdk_gc_set_clip_mask(fill_tile_gc, sprite_get_mask(psprite));
+ gdk_gc_set_foreground(fill_tile_gc, colors_standard[COLOR_STD_BLACK]);
+ gdk_gc_set_stipple(fill_tile_gc, black50);
+ gdk_gc_set_ts_origin(fill_tile_gc, canvas_x, canvas_y);
+
+ gdk_draw_rectangle(pcanvas->v.pixmap, fill_tile_gc, TRUE,
+ canvas_x, canvas_y, psprite->width, psprite->height);
+
+ gdk_gc_set_clip_mask(fill_tile_gc, NULL);
+ }
+}
+
+/****************************************************************************
+ Draw a colored line onto the mapview or citydialog canvas.
+****************************************************************************/
+void canvas_put_line(struct canvas *pcanvas, enum color_std color,
+ enum line_type ltype, int start_x, int start_y,
+ int dx, int dy)
+{
+ if (pcanvas->type == CANVAS_PIXMAP) {
+ GdkGC *gc = NULL;
+
+ switch (ltype) {
+ case LINE_NORMAL:
+ gc = thin_line_gc;
+ break;
+ case LINE_BORDER:
+ gc = border_line_gc;
+ break;
+ case LINE_TILE_FRAME:
+ gc = thick_line_gc;
+ break;
+ case LINE_GOTO:
+ gc = thick_line_gc;
+ break;
+ }
+
+ gdk_gc_set_foreground(gc, colors_standard[color]);
+ gdk_draw_line(pcanvas->v.pixmap, gc,
+ start_x, start_y, start_x + dx, start_y + dy);
+ }
+}
+
+static PangoLayout *layout;
+static PangoFontDescription **fonts[FONT_COUNT] = {&main_font,
+ &city_productions_font};
+
+/****************************************************************************
+ Return the size of the given text in the given font. This size should
+ include the ascent and descent of the text. Either of width or height
+ may be NULL in which case those values simply shouldn't be filled out.
+****************************************************************************/
+void get_text_size(int *width, int *height,
+ enum client_font font, const char *text)
+{
+ PangoRectangle rect;
+
+ if (!layout) {
+ layout = pango_layout_new(gdk_pango_context_get());
+ }
+
+ pango_layout_set_font_description(layout, *fonts[font]);
+ pango_layout_set_text(layout, text, -1);
+
+ pango_layout_get_pixel_extents(layout, &rect, NULL);
+ if (width) {
+ *width = rect.width;
+ }
+ if (height) {
+ *height = rect.height;
+ }
+}
+
+/****************************************************************************
+ Draw the text onto the canvas in the given color and font. The canvas
+ position does not account for the ascent of the text; this function must
+ take care of this manually. The text will not be NULL but may be empty.
+****************************************************************************/
+void canvas_put_text(struct canvas *pcanvas, int canvas_x, int canvas_y,
+ enum client_font font, enum color_std color,
+ const char *text)
+{
+ PangoRectangle rect;
+
+ if (pcanvas->type != CANVAS_PIXMAP) {
+ return;
+ }
+ if (!layout) {
+ layout = pango_layout_new(gdk_pango_context_get());
+ }
+
+ gdk_gc_set_foreground(civ_gc, colors_standard[color]);
+ pango_layout_set_font_description(layout, *fonts[font]);
+ pango_layout_set_text(layout, text, -1);
+
+ pango_layout_get_pixel_extents(layout, &rect, NULL);
+ gtk_draw_shadowed_string(pcanvas->v.pixmap,
+ toplevel->style->black_gc, civ_gc,
+ canvas_x,
+ canvas_y + PANGO_ASCENT(rect), layout);
+}
Index: client/gui-gtk-2.0/canvas.h
===================================================================
RCS file: client/gui-gtk-2.0/canvas.h
diff -N client/gui-gtk-2.0/canvas.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ client/gui-gtk-2.0/canvas.h 22 Mar 2005 00:01:58 -0000
@@ -0,0 +1,39 @@
+/**********************************************************************
+ 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
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+***********************************************************************/
+#ifndef FC__CANVAS_H
+#define FC__CANVAS_H
+
+#include <gtk/gtk.h>
+
+#include "canvas_g.h"
+
+#include "gtkpixcomm.h"
+
+enum canvas_type {
+ CANVAS_PIXMAP,
+ CANVAS_PIXCOMM,
+ CANVAS_PIXBUF
+};
+
+struct canvas
+{
+ enum canvas_type type;
+
+ union {
+ GdkPixmap *pixmap;
+ GtkPixcomm *pixcomm;
+ GdkPixbuf *pixbuf;
+ } v;
+};
+
+#endif /* FC__CANVAS_H */
Index: client/gui-gtk-2.0/graphics.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/graphics.c,v
retrieving revision 1.40
diff -u -r1.40 graphics.c
--- client/gui-gtk-2.0/graphics.c 21 Mar 2005 16:37:52 -0000 1.40
+++ client/gui-gtk-2.0/graphics.c 22 Mar 2005 00:01:58 -0000
@@ -81,103 +81,6 @@
gdk_draw_layout(drawable, white_gc, x, y, layout);
}
-/****************************************************************************
- Create a new sprite by cropping and taking only the given portion of
- the image.
-
- source gives the sprite that is to be cropped.
-
- 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)
- 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.
-****************************************************************************/
-struct Sprite *crop_sprite(struct Sprite *source,
- int x, int y,
- int width, int height,
- struct Sprite *mask,
- int mask_offset_x, int mask_offset_y)
-{
- GdkPixbuf *mypixbuf, *sub, *mask_pixbuf;
-
- /* First just crop the image. */
- if (x < 0) {
- width += x;
- x = 0;
- }
- if (y < 0) {
- height += y;
- y = 0;
- }
- width = CLIP(0, width, source->width - x);
- height = CLIP(0, height, source->height - y);
- sub = gdk_pixbuf_new_subpixbuf(sprite_get_pixbuf(source), x, y,
- width, height);
- mypixbuf = gdk_pixbuf_copy(sub);
- g_object_unref(sub);
-
- /* Now mask. This reduces the alpha of the final image proportional to the
- * alpha of the mask. Thus if the mask has 50% alpha the final image will
- * be reduced by 50% alpha. Note that the mask offset is in coordinates
- * relative to the clipped image not the final image. */
- if (mask
- && (mask_pixbuf = sprite_get_pixbuf(mask))
- && gdk_pixbuf_get_has_alpha(mask_pixbuf)) {
- int x1, y1;
-
- /* The mask offset is the offset of the mask relative to the origin
- * of the original source image. For instance when cropping with
- * blending sprites the offset is always 0. Here we convert the
- * coordinates so that they are relative to the origin of the new
- * (cropped) image. */
- mask_offset_x -= x;
- mask_offset_y -= y;
-
- width = CLIP(0, width, mask->width + mask_offset_x);
- height = CLIP(0, height, mask->height + mask_offset_y);
-
- if (!gdk_pixbuf_get_has_alpha(mypixbuf)) {
- GdkPixbuf *p2 = mypixbuf;
-
- mypixbuf = gdk_pixbuf_add_alpha(mypixbuf, FALSE, 0, 0, 0);
- g_object_unref(p2);
- }
-
- for (x1 = 0; x1 < width; x1++) {
- for (y1 = 0; y1 < height; y1++) {
- int mask_x = x1 - mask_offset_x, mask_y = y1 - mask_offset_y;
- guchar *alpha = gdk_pixbuf_get_pixels(mypixbuf)
- + y1 * gdk_pixbuf_get_rowstride(mypixbuf)
- + x1 * gdk_pixbuf_get_n_channels(mypixbuf)
- + 3;
- guchar *mask_alpha = gdk_pixbuf_get_pixels(mask_pixbuf)
- + mask_y * gdk_pixbuf_get_rowstride(mask_pixbuf)
- + mask_x * gdk_pixbuf_get_n_channels(mask_pixbuf)
- + 3;
-
- *alpha = (*alpha) * (*mask_alpha) / 255;
- }
- }
- }
-
- return ctor_sprite(mypixbuf);
-}
-
-/****************************************************************************
- Find the dimensions of the sprite.
-****************************************************************************/
-void get_sprite_dimensions(struct Sprite *sprite, int *width, int *height)
-{
- *width = sprite->width;
- *height = sprite->height;
-}
-
/***************************************************************************
...
***************************************************************************/
@@ -197,126 +100,6 @@
}
/***************************************************************************
- Create a new sprite with the given pixmap, dimensions, and
- (optional) mask.
-***************************************************************************/
-SPRITE *ctor_sprite(GdkPixbuf *pixbuf)
-{
- struct Sprite *sprite = fc_malloc(sizeof(*sprite));
- bool has_alpha = FALSE, has_mask = FALSE;
-
- sprite->width = gdk_pixbuf_get_width(pixbuf);
- sprite->height = gdk_pixbuf_get_height(pixbuf);
-
- /* Check to see if this pixbuf has an alpha layer. */
- if (gdk_pixbuf_get_has_alpha(pixbuf)) {
- guchar *pixels = gdk_pixbuf_get_pixels(pixbuf);
- int x, y, rowstride = gdk_pixbuf_get_rowstride(pixbuf);
-
- for (y = 0; y < sprite->height; y++) {
- for (x = 0; x < sprite->width; x++) {
- int i = y * rowstride + 4 * x + 3;
- guchar pixel = pixels[i];
-
- if (pixel > 0 && pixel < 255) {
- has_alpha = TRUE;
- }
- if (pixel == 0) {
- has_mask = TRUE;
- }
- }
- }
- }
-
- sprite->pixbuf_fogged = NULL;
- sprite->pixmap_fogged = NULL;
- if (has_alpha) {
- sprite->pixbuf = pixbuf;
- sprite->pixmap = NULL;
- sprite->mask = NULL;
- } else {
- gdk_pixbuf_render_pixmap_and_mask(pixbuf, &sprite->pixmap,
- &sprite->mask, 1);
- if (!has_mask && sprite->mask) {
- g_object_unref(sprite->mask);
- sprite->mask = NULL;
- }
- g_object_unref(pixbuf);
- sprite->pixbuf = NULL;
- }
- return sprite;
-}
-
-
-#ifdef UNUSED
-/***************************************************************************
-...
-***************************************************************************/
-void dtor_sprite( SPRITE *mysprite )
-{
- free_sprite( mysprite );
- return;
-}
-#endif
-
-/***************************************************************************
- Returns the filename extensions the client supports
- Order is important.
-***************************************************************************/
-const char **gfx_fileextensions(void)
-{
- static const char *ext[] =
- {
- "png",
- "xpm",
- NULL
- };
-
- return ext;
-}
-
-/***************************************************************************
-...
-***************************************************************************/
-struct Sprite *load_gfxfile(const char *filename)
-{
- GdkPixbuf *im;
-
- if (!(im = gdk_pixbuf_new_from_file(filename, NULL))) {
- freelog(LOG_FATAL, "Failed reading graphics file: %s", filename);
- exit(EXIT_FAILURE);
- }
-
- return ctor_sprite(im);
-}
-
-/***************************************************************************
- Deletes a sprite. These things can use a lot of memory.
-***************************************************************************/
-void free_sprite(SPRITE * s)
-{
- if (s->pixmap) {
- g_object_unref(s->pixmap);
- s->pixmap = NULL;
- }
- if (s->mask) {
- g_object_unref(s->mask);
- s->mask = NULL;
- }
- if (s->pixbuf) {
- g_object_unref(s->pixbuf);
- s->pixbuf = NULL;
- }
- if (s->pixmap_fogged) {
- g_object_unref(s->pixmap_fogged);
- }
- if (s->pixbuf_fogged) {
- g_object_unref(s->pixbuf_fogged);
- }
- free(s);
-}
-
-/***************************************************************************
...
***************************************************************************/
void create_overlay_unit(struct canvas *pcanvas, int i)
@@ -362,177 +145,3 @@
radar_gfx_sprite=NULL;
}
}
-
-/***************************************************************************
- Scales a sprite. If the sprite contains a mask, the mask is scaled
- as as well.
-***************************************************************************/
-SPRITE* sprite_scale(SPRITE *src, int new_w, int new_h)
-{
- return ctor_sprite(gdk_pixbuf_scale_simple(sprite_get_pixbuf(src),
- new_w, new_h,
- GDK_INTERP_BILINEAR));
-}
-
-/***************************************************************************
- Method returns the bounding box of a sprite. It assumes a rectangular
- object/mask. The bounding box contains the border (pixel which have
- unset pixel as neighbours) pixel.
-***************************************************************************/
-void sprite_get_bounding_box(SPRITE * sprite, int *start_x,
- int *start_y, int *end_x, int *end_y)
-{
- GdkImage *mask_image;
- GdkBitmap *mask = sprite_get_mask(sprite);
- int i, j;
-
- if (!mask) {
- *start_x = 0;
- *start_y = 0;
- *end_x = sprite->width - 1;
- *end_y = sprite->height - 1;
- return;
- }
-
- mask_image =
- gdk_drawable_get_image(mask, 0, 0, sprite->width, sprite->height);
-
-
- /* parses mask image for the first column that contains a visible pixel */
- *start_x = -1;
- for (i = 0; i < sprite->width && *start_x == -1; i++) {
- for (j = 0; j < sprite->height; j++) {
- if (gdk_image_get_pixel(mask_image, i, j) != 0) {
- *start_x = i;
- break;
- }
- }
- }
-
- /* parses mask image for the last column that contains a visible pixel */
- *end_x = -1;
- for (i = sprite->width - 1; i >= *start_x && *end_x == -1; i--) {
- for (j = 0; j < sprite->height; j++) {
- if (gdk_image_get_pixel(mask_image, i, j) != 0) {
- *end_x = i;
- break;
- }
- }
- }
-
- /* parses mask image for the first row that contains a visible pixel */
- *start_y = -1;
- for (i = 0; i < sprite->height && *start_y == -1; i++) {
- for (j = *start_x; j <= *end_x; j++) {
- if (gdk_image_get_pixel(mask_image, j, i) != 0) {
- *start_y = i;
- break;
- }
- }
- }
-
- /* parses mask image for the last row that contains a visible pixel */
- *end_y = -1;
- for (i = sprite->height - 1; i >= *end_y && *end_y == -1; i--) {
- for (j = *start_x; j <= *end_x; j++) {
- if (gdk_image_get_pixel(mask_image, j, i) != 0) {
- *end_y = i;
- break;
- }
- }
- }
-
- g_object_unref(mask_image);
-}
-
-/*********************************************************************
- Crops all blankspace from a sprite (insofar as is possible as a rectangle)
-*********************************************************************/
-SPRITE *crop_blankspace(SPRITE *s)
-{
- int x1, y1, x2, y2;
-
- sprite_get_bounding_box(s, &x1, &y1, &x2, &y2);
-
- return crop_sprite(s, x1, y1, x2 - x1 + 1, y2 - y1 + 1, NULL, -1, -1);
-}
-
-/*********************************************************************
- Converts a pixmap/mask sprite to a GdkPixbuf.
-
- This is just a helper function for sprite_get_pixbuf(). Most callers
- should use that function instead.
-*********************************************************************/
-static GdkPixbuf *gdk_pixbuf_new_from_pixmap_sprite(SPRITE *src)
-{
- GdkPixbuf *dst;
- int w, h;
-
- w = src->width;
- h = src->height;
-
- /* convert pixmap */
- dst = gdk_pixbuf_new(GDK_COLORSPACE_RGB, src->mask != NULL, 8, w, h);
- gdk_pixbuf_get_from_drawable(dst, src->pixmap, NULL, 0, 0, 0, 0, w, h);
-
- /* convert mask */
- if (src->mask) {
- GdkImage *img;
- int x, y, rowstride;
- guchar *pixels;
-
- img = gdk_drawable_get_image(src->mask, 0, 0, w, h);
-
- pixels = gdk_pixbuf_get_pixels(dst);
- rowstride = gdk_pixbuf_get_rowstride(dst);
-
- for (y = 0; y < h; y++) {
- for (x = 0; x < w; x++) {
- guchar *pixel = pixels + y * rowstride + x * 4 + 3;
-
- if (gdk_image_get_pixel(img, x, y)) {
- *pixel = 255;
- } else {
- *pixel = 0;
- }
- }
- }
- g_object_unref(img);
- }
-
- return dst;
-}
-
-/********************************************************************
- Render a pixbuf from the sprite.
-
- NOTE: the pixmap and mask of a sprite must not change after this
- function is called!
-********************************************************************/
-GdkPixbuf *sprite_get_pixbuf(SPRITE *sprite)
-{
- if (!sprite) {
- return NULL;
- }
-
- if (!sprite->pixbuf) {
- sprite->pixbuf = gdk_pixbuf_new_from_pixmap_sprite(sprite);
- }
- return sprite->pixbuf;
-}
-
-/****************************************************************************
- Render a mask from the sprite.
-
- NOTE: the pixbuf of a sprite must not change after this function is called!
-****************************************************************************/
-GdkBitmap *sprite_get_mask(struct Sprite *sprite)
-{
- if (!sprite->pixmap && !sprite->mask) {
- /* If we're not in pixmap mode and we don't yet have a mask, render
- * the pixbuf to a mask. */
- gdk_pixbuf_render_pixmap_and_mask(sprite->pixbuf, NULL,
- &sprite->mask, 1);
- }
- return sprite->mask;
-}
Index: client/gui-gtk-2.0/graphics.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/graphics.h,v
retrieving revision 1.14
diff -u -r1.14 graphics.h
--- client/gui-gtk-2.0/graphics.h 11 Mar 2005 22:40:53 -0000 1.14
+++ client/gui-gtk-2.0/graphics.h 22 Mar 2005 00:01:58 -0000
@@ -18,22 +18,8 @@
#include "graphics_g.h"
#include "mapview_common.h"
-struct Sprite
-{
- /* A pixmap + mask is used if there's a 1-bit alpha channel. mask may be
- * NULL if there's no alpha. For multi-bit alpha levels, a pixbuf will be
- * used instead. For consistency a pixbuf may be generated on-demand when
- * doing drawing (into a gtkpixcomm or gtkimage), so it's important that
- * the sprite data not be changed after the sprite is loaded. */
- GdkPixmap *pixmap, *pixmap_fogged;
- GdkBitmap *mask;
- GdkPixbuf *pixbuf, *pixbuf_fogged;
-
- int width;
- int height;
-};
-
-typedef struct Sprite SPRITE;
+#include "canvas.h"
+#include "sprite.h"
void create_overlay_unit(struct canvas *pcanvas, int i);
@@ -49,17 +35,5 @@
GdkGC *white_gc,
gint x, gint y, PangoLayout *layout);
-SPRITE *ctor_sprite(GdkPixbuf *pixbuf);
-SPRITE* sprite_scale(SPRITE *src, int new_w, int new_h);
-void sprite_get_bounding_box(SPRITE * sprite, int *start_x,
- int *start_y, int *end_x, int *end_y);
-SPRITE *crop_blankspace(SPRITE *s);
-
-/********************************************************************
- Note: a sprite cannot be changed after these functions are called!
- ********************************************************************/
-GdkPixbuf *sprite_get_pixbuf(SPRITE *sprite);
-GdkBitmap *sprite_get_mask(struct Sprite *sprite);
-
#endif /* FC__GRAPHICS_H */
Index: client/gui-gtk-2.0/gtkpixcomm.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/gtkpixcomm.c,v
retrieving revision 1.14
diff -u -r1.14 gtkpixcomm.c
--- client/gui-gtk-2.0/gtkpixcomm.c 1 Feb 2005 01:08:45 -0000 1.14
+++ client/gui-gtk-2.0/gtkpixcomm.c 22 Mar 2005 00:01:58 -0000
@@ -37,6 +37,8 @@
#include <config.h>
#endif
+#include <math.h>
+
#include "gui_main.h"
#include "gtkpixcomm.h"
Index: client/gui-gtk-2.0/gtkpixcomm.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/gtkpixcomm.h,v
retrieving revision 1.4
diff -u -r1.4 gtkpixcomm.h
--- client/gui-gtk-2.0/gtkpixcomm.h 15 Dec 2004 23:18:18 -0000 1.4
+++ client/gui-gtk-2.0/gtkpixcomm.h 22 Mar 2005 00:01:58 -0000
@@ -29,7 +29,8 @@
#include <gtk/gtkmisc.h>
-#include "graphics.h"
+
+#include "sprite.h"
G_BEGIN_DECLS
Index: client/gui-gtk-2.0/gui_main.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/gui_main.h,v
retrieving revision 1.22
diff -u -r1.22 gui_main.h
--- client/gui-gtk-2.0/gui_main.h 14 Feb 2005 17:52:56 -0000 1.22
+++ client/gui-gtk-2.0/gui_main.h 22 Mar 2005 00:01:58 -0000
@@ -18,23 +18,6 @@
#include "gtkpixcomm.h"
#include "gui_main_g.h"
-enum canvas_type {
- CANVAS_PIXMAP,
- CANVAS_PIXCOMM,
- CANVAS_PIXBUF
-};
-
-struct canvas
-{
- enum canvas_type type;
-
- union {
- GdkPixmap *pixmap;
- GtkPixcomm *pixcomm;
- GdkPixbuf *pixbuf;
- } v;
-};
-
/* network string charset conversion */
gchar *ntoh_str(const gchar *netstr);
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.167
diff -u -r1.167 mapview.c
--- client/gui-gtk-2.0/mapview.c 21 Mar 2005 16:37:52 -0000 1.167
+++ client/gui-gtk-2.0/mapview.c 22 Mar 2005 00:01:58 -0000
@@ -55,15 +55,6 @@
#define map_canvas_store (mapview.store->v.pixmap)
-static void pixmap_put_overlay_tile(GdkDrawable *pixmap,
- int canvas_x, int canvas_y,
- struct Sprite *ssprite);
-
-static void pixmap_put_overlay_tile_draw(GdkDrawable *pixmap,
- int canvas_x, int canvas_y,
- struct Sprite *ssprite,
- bool fog);
-
static GtkObject *map_hadj, *map_vadj;
@@ -246,29 +237,6 @@
update_map_canvas_scrollbars_size();
}
-/**************************************************************************
-...
-**************************************************************************/
-struct canvas *canvas_create(int width, int height)
-{
- struct canvas *result = fc_malloc(sizeof(*result));
-
- result->type = CANVAS_PIXMAP;
- result->v.pixmap = gdk_pixmap_new(root_window, width, height, -1);
- return result;
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-void canvas_free(struct canvas *store)
-{
- if (store->type == CANVAS_PIXMAP) {
- g_object_unref(store->v.pixmap);
- }
- free(store);
-}
-
/****************************************************************************
Return a canvas that is the overview window.
****************************************************************************/
@@ -461,65 +429,6 @@
update_map_canvas_visible();
}
-static PangoLayout *layout;
-static PangoFontDescription **fonts[FONT_COUNT] = {&main_font,
- &city_productions_font};
-
-/****************************************************************************
- Return the size of the given text in the given font. This size should
- include the ascent and descent of the text. Either of width or height
- may be NULL in which case those values simply shouldn't be filled out.
-****************************************************************************/
-void get_text_size(int *width, int *height,
- enum client_font font, const char *text)
-{
- PangoRectangle rect;
-
- if (!layout) {
- layout = pango_layout_new(gdk_pango_context_get());
- }
-
- pango_layout_set_font_description(layout, *fonts[font]);
- pango_layout_set_text(layout, text, -1);
-
- pango_layout_get_pixel_extents(layout, &rect, NULL);
- if (width) {
- *width = rect.width;
- }
- if (height) {
- *height = rect.height;
- }
-}
-
-/****************************************************************************
- Draw the text onto the canvas in the given color and font. The canvas
- position does not account for the ascent of the text; this function must
- take care of this manually. The text will not be NULL but may be empty.
-****************************************************************************/
-void canvas_put_text(struct canvas *pcanvas, int canvas_x, int canvas_y,
- enum client_font font, enum color_std color,
- const char *text)
-{
- PangoRectangle rect;
-
- if (pcanvas->type != CANVAS_PIXMAP) {
- return;
- }
- if (!layout) {
- layout = pango_layout_new(gdk_pango_context_get());
- }
-
- gdk_gc_set_foreground(civ_gc, colors_standard[color]);
- pango_layout_set_font_description(layout, *fonts[font]);
- pango_layout_set_text(layout, text, -1);
-
- pango_layout_get_pixel_extents(layout, &rect, NULL);
- gtk_draw_shadowed_string(pcanvas->v.pixmap,
- toplevel->style->black_gc, civ_gc,
- canvas_x,
- canvas_y + PANGO_ASCENT(rect), layout);
-}
-
/**************************************************************************
...
**************************************************************************/
@@ -562,9 +471,9 @@
/**************************************************************************
...
**************************************************************************/
-static void pixmap_put_overlay_tile(GdkDrawable *pixmap,
- int canvas_x, int canvas_y,
- struct Sprite *ssprite)
+void pixmap_put_overlay_tile(GdkDrawable *pixmap,
+ int canvas_x, int canvas_y,
+ struct Sprite *ssprite)
{
if (!ssprite) {
return;
@@ -621,192 +530,6 @@
}
/**************************************************************************
- Draw some or all of a sprite onto the mapview or citydialog canvas.
-**************************************************************************/
-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)
-{
- switch (pcanvas->type) {
- case CANVAS_PIXMAP:
- pixmap_put_sprite(pcanvas->v.pixmap, canvas_x, canvas_y,
- sprite, offset_x, offset_y, width, height);
- break;
- case CANVAS_PIXCOMM:
- gtk_pixcomm_copyto(pcanvas->v.pixcomm, sprite, canvas_x, canvas_y);
- break;
- case CANVAS_PIXBUF:
- {
- GdkPixbuf *src, *dst;
-
- /* FIXME: is this right??? */
- if (canvas_x < 0) {
- offset_x -= canvas_x;
- canvas_x = 0;
- }
- if (canvas_y < 0) {
- offset_y -= canvas_y;
- canvas_y = 0;
- }
-
-
- src = sprite_get_pixbuf(sprite);
- dst = pcanvas->v.pixbuf;
- gdk_pixbuf_composite(src, dst, canvas_x, canvas_y,
- MIN(width,
- MIN(gdk_pixbuf_get_width(dst), gdk_pixbuf_get_width(src))),
- MIN(height,
- MIN(gdk_pixbuf_get_height(dst), gdk_pixbuf_get_height(src))),
- canvas_x - offset_x, canvas_y - offset_y,
- 1.0, 1.0, GDK_INTERP_NEAREST, 255);
- }
- break;
- default:
- break;
- }
-}
-
-/**************************************************************************
- Draw a full sprite onto the mapview or citydialog canvas.
-**************************************************************************/
-void canvas_put_sprite_full(struct canvas *pcanvas,
- int canvas_x, int canvas_y,
- struct Sprite *sprite)
-{
- canvas_put_sprite(pcanvas, canvas_x, canvas_y, sprite,
- 0, 0, sprite->width, sprite->height);
-}
-
-/****************************************************************************
- 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)
-{
- if (pcanvas->type == CANVAS_PIXMAP) {
- pixmap_put_overlay_tile_draw(pcanvas->v.pixmap, canvas_x, canvas_y,
- psprite, fog);
- }
-}
-
-/**************************************************************************
- Draw a filled-in colored rectangle onto the mapview or citydialog canvas.
-**************************************************************************/
-void canvas_put_rectangle(struct canvas *pcanvas,
- enum color_std color,
- int canvas_x, int canvas_y, int width, int height)
-{
- GdkColor *col = colors_standard[color];
-
- switch (pcanvas->type) {
- case CANVAS_PIXMAP:
- gdk_gc_set_foreground(fill_bg_gc, col);
- gdk_draw_rectangle(pcanvas->v.pixmap, fill_bg_gc, TRUE,
- canvas_x, canvas_y, width, height);
- break;
- case CANVAS_PIXCOMM:
- gtk_pixcomm_fill(pcanvas->v.pixcomm, col);
- break;
- case CANVAS_PIXBUF:
- gdk_pixbuf_fill(pcanvas->v.pixbuf,
- ((guint32)(col->red & 0xff00) << 16)
- | ((col->green & 0xff00) << 8) | (col->blue & 0xff00) | 0xff);
- break;
- default:
- break;
- }
-}
-
-/****************************************************************************
- Fill the area covered by the sprite with the given color.
-****************************************************************************/
-void canvas_fill_sprite_area(struct canvas *pcanvas,
- struct Sprite *psprite, enum color_std color,
- int canvas_x, int canvas_y)
-{
- if (pcanvas->type == CANVAS_PIXMAP) {
- gdk_gc_set_clip_origin(fill_bg_gc, canvas_x, canvas_y);
- gdk_gc_set_clip_mask(fill_bg_gc, sprite_get_mask(psprite));
- gdk_gc_set_foreground(fill_bg_gc, colors_standard[color]);
-
- gdk_draw_rectangle(pcanvas->v.pixmap, fill_bg_gc, TRUE,
- canvas_x, canvas_y, psprite->width, psprite->height);
-
- gdk_gc_set_clip_mask(fill_bg_gc, NULL);
- }
-}
-
-/****************************************************************************
- Fill the area covered by the sprite with the given color.
-****************************************************************************/
-void canvas_fog_sprite_area(struct canvas *pcanvas, struct Sprite *psprite,
- int canvas_x, int canvas_y)
-{
- if (pcanvas->type == CANVAS_PIXMAP) {
- gdk_gc_set_clip_origin(fill_tile_gc, canvas_x, canvas_y);
- gdk_gc_set_clip_mask(fill_tile_gc, sprite_get_mask(psprite));
- gdk_gc_set_foreground(fill_tile_gc, colors_standard[COLOR_STD_BLACK]);
- gdk_gc_set_stipple(fill_tile_gc, black50);
- gdk_gc_set_ts_origin(fill_tile_gc, canvas_x, canvas_y);
-
- gdk_draw_rectangle(pcanvas->v.pixmap, fill_tile_gc, TRUE,
- canvas_x, canvas_y, psprite->width, psprite->height);
-
- gdk_gc_set_clip_mask(fill_tile_gc, NULL);
- }
-}
-
-/**************************************************************************
- Draw a colored line onto the mapview or citydialog canvas.
-**************************************************************************/
-void canvas_put_line(struct canvas *pcanvas, enum color_std color,
- enum line_type ltype, int start_x, int start_y,
- int dx, int dy)
-{
- if (pcanvas->type == CANVAS_PIXMAP) {
- GdkGC *gc = NULL;
-
- switch (ltype) {
- case LINE_NORMAL:
- gc = thin_line_gc;
- break;
- case LINE_BORDER:
- gc = border_line_gc;
- break;
- case LINE_TILE_FRAME:
- gc = thick_line_gc;
- break;
- case LINE_GOTO:
- gc = thick_line_gc;
- break;
- }
-
- gdk_gc_set_foreground(gc, colors_standard[color]);
- gdk_draw_line(pcanvas->v.pixmap, gc,
- start_x, start_y, start_x + dx, start_y + dy);
- }
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-void canvas_copy(struct canvas *dest, struct canvas *src,
- int src_x, int src_y, int dest_x, int dest_y,
- int width, int height)
-{
- if (dest->type == src->type) {
- if (src->type == CANVAS_PIXMAP) {
- gdk_draw_drawable(dest->v.pixmap, fill_bg_gc, src->v.pixmap,
- src_x, src_y, dest_x, dest_y, width, height);
- }
- }
-}
-
-/**************************************************************************
Created a fogged version of the sprite. This can fail on older systems
in which case the callers needs a fallback.
**************************************************************************/
@@ -851,10 +574,10 @@
/**************************************************************************
Only used for isometric view.
**************************************************************************/
-static void pixmap_put_overlay_tile_draw(GdkDrawable *pixmap,
- int canvas_x, int canvas_y,
- struct Sprite *ssprite,
- bool fog)
+void pixmap_put_overlay_tile_draw(GdkDrawable *pixmap,
+ int canvas_x, int canvas_y,
+ struct Sprite *ssprite,
+ bool fog)
{
if (!ssprite) {
return;
Index: client/gui-gtk-2.0/mapview.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/mapview.h,v
retrieving revision 1.19
diff -u -r1.19 mapview.h
--- client/gui-gtk-2.0/mapview.h 1 Feb 2005 01:08:45 -0000 1.19
+++ client/gui-gtk-2.0/mapview.h 22 Mar 2005 00:01:58 -0000
@@ -21,6 +21,7 @@
#include "mapview_g.h"
#include "mapview_common.h"
+#include "canvas.h"
#include "graphics.h"
struct unit;
@@ -40,4 +41,13 @@
void scrollbar_jump_callback(GtkAdjustment *adj, gpointer hscrollbar);
void update_map_canvas_scrollbars_size(void);
+void pixmap_put_overlay_tile(GdkDrawable *pixmap,
+ int canvas_x, int canvas_y,
+ struct Sprite *ssprite);
+
+void pixmap_put_overlay_tile_draw(GdkDrawable *pixmap,
+ int canvas_x, int canvas_y,
+ struct Sprite *ssprite,
+ bool fog);
+
#endif /* FC__MAPVIEW_H */
Index: client/gui-gtk-2.0/sprite.c
===================================================================
RCS file: client/gui-gtk-2.0/sprite.c
diff -N client/gui-gtk-2.0/sprite.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ client/gui-gtk-2.0/sprite.c 22 Mar 2005 00:01:58 -0000
@@ -0,0 +1,403 @@
+/**********************************************************************
+ 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
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "log.h"
+
+#include "sprite.h"
+
+/****************************************************************************
+ Create a new sprite by cropping and taking only the given portion of
+ the image.
+
+ source gives the sprite that is to be cropped.
+
+ 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)
+ 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.
+****************************************************************************/
+struct Sprite *crop_sprite(struct Sprite *source,
+ int x, int y,
+ int width, int height,
+ struct Sprite *mask,
+ int mask_offset_x, int mask_offset_y)
+{
+ GdkPixbuf *mypixbuf, *sub, *mask_pixbuf;
+
+ /* First just crop the image. */
+ if (x < 0) {
+ width += x;
+ x = 0;
+ }
+ if (y < 0) {
+ height += y;
+ y = 0;
+ }
+ width = CLIP(0, width, source->width - x);
+ height = CLIP(0, height, source->height - y);
+ sub = gdk_pixbuf_new_subpixbuf(sprite_get_pixbuf(source), x, y,
+ width, height);
+ mypixbuf = gdk_pixbuf_copy(sub);
+ g_object_unref(sub);
+
+ /* Now mask. This reduces the alpha of the final image proportional to the
+ * alpha of the mask. Thus if the mask has 50% alpha the final image will
+ * be reduced by 50% alpha. Note that the mask offset is in coordinates
+ * relative to the clipped image not the final image. */
+ if (mask
+ && (mask_pixbuf = sprite_get_pixbuf(mask))
+ && gdk_pixbuf_get_has_alpha(mask_pixbuf)) {
+ int x1, y1;
+
+ /* The mask offset is the offset of the mask relative to the origin
+ * of the original source image. For instance when cropping with
+ * blending sprites the offset is always 0. Here we convert the
+ * coordinates so that they are relative to the origin of the new
+ * (cropped) image. */
+ mask_offset_x -= x;
+ mask_offset_y -= y;
+
+ width = CLIP(0, width, mask->width + mask_offset_x);
+ height = CLIP(0, height, mask->height + mask_offset_y);
+
+ if (!gdk_pixbuf_get_has_alpha(mypixbuf)) {
+ GdkPixbuf *p2 = mypixbuf;
+
+ mypixbuf = gdk_pixbuf_add_alpha(mypixbuf, FALSE, 0, 0, 0);
+ g_object_unref(p2);
+ }
+
+ for (x1 = 0; x1 < width; x1++) {
+ for (y1 = 0; y1 < height; y1++) {
+ int mask_x = x1 - mask_offset_x, mask_y = y1 - mask_offset_y;
+ guchar *alpha = gdk_pixbuf_get_pixels(mypixbuf)
+ + y1 * gdk_pixbuf_get_rowstride(mypixbuf)
+ + x1 * gdk_pixbuf_get_n_channels(mypixbuf)
+ + 3;
+ guchar *mask_alpha = gdk_pixbuf_get_pixels(mask_pixbuf)
+ + mask_y * gdk_pixbuf_get_rowstride(mask_pixbuf)
+ + mask_x * gdk_pixbuf_get_n_channels(mask_pixbuf)
+ + 3;
+
+ *alpha = (*alpha) * (*mask_alpha) / 255;
+ }
+ }
+ }
+
+ return ctor_sprite(mypixbuf);
+}
+
+/****************************************************************************
+ Find the dimensions of the sprite.
+****************************************************************************/
+void get_sprite_dimensions(struct Sprite *sprite, int *width, int *height)
+{
+ *width = sprite->width;
+ *height = sprite->height;
+}
+
+/****************************************************************************
+ Create a new sprite with the given pixmap, dimensions, and
+ (optional) mask.
+
+ FIXME: should be renamed as sprite_new or some such.
+****************************************************************************/
+struct Sprite *ctor_sprite(GdkPixbuf *pixbuf)
+{
+ struct Sprite *sprite = fc_malloc(sizeof(*sprite));
+ bool has_alpha = FALSE, has_mask = FALSE;
+
+ sprite->width = gdk_pixbuf_get_width(pixbuf);
+ sprite->height = gdk_pixbuf_get_height(pixbuf);
+
+ /* Check to see if this pixbuf has an alpha layer. */
+ if (gdk_pixbuf_get_has_alpha(pixbuf)) {
+ guchar *pixels = gdk_pixbuf_get_pixels(pixbuf);
+ int x, y, rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+
+ for (y = 0; y < sprite->height; y++) {
+ for (x = 0; x < sprite->width; x++) {
+ int i = y * rowstride + 4 * x + 3;
+ guchar pixel = pixels[i];
+
+ if (pixel > 0 && pixel < 255) {
+ has_alpha = TRUE;
+ }
+ if (pixel == 0) {
+ has_mask = TRUE;
+ }
+ }
+ }
+ }
+
+ sprite->pixbuf_fogged = NULL;
+ sprite->pixmap_fogged = NULL;
+ if (has_alpha) {
+ sprite->pixbuf = pixbuf;
+ sprite->pixmap = NULL;
+ sprite->mask = NULL;
+ } else {
+ gdk_pixbuf_render_pixmap_and_mask(pixbuf, &sprite->pixmap,
+ &sprite->mask, 1);
+ if (!has_mask && sprite->mask) {
+ g_object_unref(sprite->mask);
+ sprite->mask = NULL;
+ }
+ g_object_unref(pixbuf);
+ sprite->pixbuf = NULL;
+ }
+ return sprite;
+}
+
+/****************************************************************************
+ Returns the filename extensions the client supports
+ Order is important.
+****************************************************************************/
+const char **gfx_fileextensions(void)
+{
+ static const char *ext[] =
+ {
+ "png",
+ "xpm",
+ NULL
+ };
+
+ return ext;
+}
+
+/****************************************************************************
+ 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.
+****************************************************************************/
+struct Sprite *load_gfxfile(const char *filename)
+{
+ GdkPixbuf *im;
+
+ if (!(im = gdk_pixbuf_new_from_file(filename, NULL))) {
+ freelog(LOG_FATAL, "Failed reading graphics file: %s", filename);
+ exit(EXIT_FAILURE);
+ }
+
+ return ctor_sprite(im);
+}
+
+/****************************************************************************
+ Free a sprite and all associated image data.
+****************************************************************************/
+void free_sprite(struct Sprite * s)
+{
+ if (s->pixmap) {
+ g_object_unref(s->pixmap);
+ s->pixmap = NULL;
+ }
+ if (s->mask) {
+ g_object_unref(s->mask);
+ s->mask = NULL;
+ }
+ if (s->pixbuf) {
+ g_object_unref(s->pixbuf);
+ s->pixbuf = NULL;
+ }
+ if (s->pixmap_fogged) {
+ g_object_unref(s->pixmap_fogged);
+ }
+ if (s->pixbuf_fogged) {
+ g_object_unref(s->pixbuf_fogged);
+ }
+ free(s);
+}
+
+/****************************************************************************
+ Scales a sprite. If the sprite contains a mask, the mask is scaled
+ as as well.
+****************************************************************************/
+struct Sprite *sprite_scale(struct Sprite *src, int new_w, int new_h)
+{
+ return ctor_sprite(gdk_pixbuf_scale_simple(sprite_get_pixbuf(src),
+ new_w, new_h,
+ GDK_INTERP_BILINEAR));
+}
+
+/****************************************************************************
+ Method returns the bounding box of a sprite. It assumes a rectangular
+ object/mask. The bounding box contains the border (pixel which have
+ unset pixel as neighbours) pixel.
+****************************************************************************/
+void sprite_get_bounding_box(struct Sprite * sprite, int *start_x,
+ int *start_y, int *end_x, int *end_y)
+{
+ GdkImage *mask_image;
+ GdkBitmap *mask = sprite_get_mask(sprite);
+ int i, j;
+
+ if (!mask) {
+ *start_x = 0;
+ *start_y = 0;
+ *end_x = sprite->width - 1;
+ *end_y = sprite->height - 1;
+ return;
+ }
+
+ mask_image
+ = gdk_drawable_get_image(mask, 0, 0, sprite->width, sprite->height);
+
+
+ /* parses mask image for the first column that contains a visible pixel */
+ *start_x = -1;
+ for (i = 0; i < sprite->width && *start_x == -1; i++) {
+ for (j = 0; j < sprite->height; j++) {
+ if (gdk_image_get_pixel(mask_image, i, j) != 0) {
+ *start_x = i;
+ break;
+ }
+ }
+ }
+
+ /* parses mask image for the last column that contains a visible pixel */
+ *end_x = -1;
+ for (i = sprite->width - 1; i >= *start_x && *end_x == -1; i--) {
+ for (j = 0; j < sprite->height; j++) {
+ if (gdk_image_get_pixel(mask_image, i, j) != 0) {
+ *end_x = i;
+ break;
+ }
+ }
+ }
+
+ /* parses mask image for the first row that contains a visible pixel */
+ *start_y = -1;
+ for (i = 0; i < sprite->height && *start_y == -1; i++) {
+ for (j = *start_x; j <= *end_x; j++) {
+ if (gdk_image_get_pixel(mask_image, j, i) != 0) {
+ *start_y = i;
+ break;
+ }
+ }
+ }
+
+ /* parses mask image for the last row that contains a visible pixel */
+ *end_y = -1;
+ for (i = sprite->height - 1; i >= *end_y && *end_y == -1; i--) {
+ for (j = *start_x; j <= *end_x; j++) {
+ if (gdk_image_get_pixel(mask_image, j, i) != 0) {
+ *end_y = i;
+ break;
+ }
+ }
+ }
+
+ g_object_unref(mask_image);
+}
+
+/****************************************************************************
+ Crops all blankspace from a sprite (insofar as is possible as a rectangle)
+****************************************************************************/
+struct Sprite *crop_blankspace(struct Sprite *s)
+{
+ int x1, y1, x2, y2;
+
+ sprite_get_bounding_box(s, &x1, &y1, &x2, &y2);
+
+ return crop_sprite(s, x1, y1, x2 - x1 + 1, y2 - y1 + 1, NULL, -1, -1);
+}
+
+/****************************************************************************
+ Converts a pixmap/mask sprite to a GdkPixbuf.
+
+ This is just a helper function for sprite_get_pixbuf(). Most callers
+ should use that function instead.
+****************************************************************************/
+static GdkPixbuf *gdk_pixbuf_new_from_pixmap_sprite(struct Sprite *src)
+{
+ GdkPixbuf *dst;
+ int w, h;
+
+ w = src->width;
+ h = src->height;
+
+ /* convert pixmap */
+ dst = gdk_pixbuf_new(GDK_COLORSPACE_RGB, src->mask != NULL, 8, w, h);
+ gdk_pixbuf_get_from_drawable(dst, src->pixmap, NULL, 0, 0, 0, 0, w, h);
+
+ /* convert mask */
+ if (src->mask) {
+ GdkImage *img;
+ int x, y, rowstride;
+ guchar *pixels;
+
+ img = gdk_drawable_get_image(src->mask, 0, 0, w, h);
+
+ pixels = gdk_pixbuf_get_pixels(dst);
+ rowstride = gdk_pixbuf_get_rowstride(dst);
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ guchar *pixel = pixels + y * rowstride + x * 4 + 3;
+
+ if (gdk_image_get_pixel(img, x, y)) {
+ *pixel = 255;
+ } else {
+ *pixel = 0;
+ }
+ }
+ }
+ g_object_unref(img);
+ }
+
+ return dst;
+}
+
+/********************************************************************
+ Render a pixbuf from the sprite.
+
+ NOTE: the pixmap and mask of a sprite must not change after this
+ function is called!
+********************************************************************/
+GdkPixbuf *sprite_get_pixbuf(struct Sprite *sprite)
+{
+ if (!sprite) {
+ return NULL;
+ }
+
+ if (!sprite->pixbuf) {
+ sprite->pixbuf = gdk_pixbuf_new_from_pixmap_sprite(sprite);
+ }
+ return sprite->pixbuf;
+}
+
+/****************************************************************************
+ Render a mask from the sprite.
+
+ NOTE: the pixbuf of a sprite must not change after this function is called!
+****************************************************************************/
+GdkBitmap *sprite_get_mask(struct Sprite *sprite)
+{
+ if (!sprite->pixmap && !sprite->mask) {
+ /* If we're not in pixmap mode and we don't yet have a mask, render
+ * the pixbuf to a mask. */
+ gdk_pixbuf_render_pixmap_and_mask(sprite->pixbuf, NULL,
+ &sprite->mask, 1);
+ }
+ return sprite->mask;
+}
Index: client/gui-gtk-2.0/sprite.h
===================================================================
RCS file: client/gui-gtk-2.0/sprite.h
diff -N client/gui-gtk-2.0/sprite.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ client/gui-gtk-2.0/sprite.h 22 Mar 2005 00:01:58 -0000
@@ -0,0 +1,50 @@
+/**********************************************************************
+ 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
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+***********************************************************************/
+#ifndef FC__SPRITE_H
+#define FC__SPRITE_H
+
+#include <gtk/gtk.h>
+
+#include "sprite_g.h"
+
+struct Sprite
+{
+ /* A pixmap + mask is used if there's a 1-bit alpha channel. mask may be
+ * NULL if there's no alpha. For multi-bit alpha levels, a pixbuf will be
+ * used instead. For consistency a pixbuf may be generated on-demand when
+ * doing drawing (into a gtkpixcomm or gtkimage), so it's important that
+ * the sprite data not be changed after the sprite is loaded. */
+ GdkPixmap *pixmap, *pixmap_fogged;
+ GdkBitmap *mask;
+ GdkPixbuf *pixbuf, *pixbuf_fogged;
+
+ int width;
+ int height;
+};
+
+typedef struct Sprite SPRITE;
+
+struct Sprite *ctor_sprite(GdkPixbuf *pixbuf);
+struct Sprite *sprite_scale(struct Sprite *src, int new_w, int new_h);
+void sprite_get_bounding_box(struct Sprite *sprite, int *start_x,
+ int *start_y, int *end_x, int *end_y);
+struct Sprite *crop_blankspace(struct Sprite *s);
+
+/********************************************************************
+ Note: a sprite cannot be changed after these functions are called!
+********************************************************************/
+GdkPixbuf *sprite_get_pixbuf(SPRITE *sprite);
+GdkBitmap *sprite_get_mask(struct Sprite *sprite);
+
+#endif /* FC__SPRITE_H */
+
Index: client/gui-gtk-2.0/wldlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/wldlg.c,v
retrieving revision 1.42
diff -u -r1.42 wldlg.c
--- client/gui-gtk-2.0/wldlg.c 9 Mar 2005 20:43:48 -0000 1.42
+++ client/gui-gtk-2.0/wldlg.c 22 Mar 2005 00:01:59 -0000
@@ -24,6 +24,7 @@
#include "city.h"
#include "citydlg_common.h"
+#include "civclient.h"
#include "fcintl.h"
#include "game.h"
#include "gui_main.h"
@@ -39,9 +40,10 @@
#include "options.h"
#include "tilespec.h"
-#include "wldlg.h"
+#include "canvas.h"
#include "citydlg.h"
-#include "civclient.h"
+#include "graphics.h"
+#include "wldlg.h"
static GtkWidget *worklists_shell;
static GtkWidget *worklists_list;
|
|