/* * Copyright (C) 2005 Benjamin Otte * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id$ */ #include "game-private.h" #include "game-image.h" #include #include #include "game-marshal.h" #include "game-portable.h" enum { PROP_0, PROP_IMAGE, }; static GameGraphicClass *parent_class = NULL; static void game_image_get_property (GObject *image_, guint param_id, GValue *value, GParamSpec * pspec) { GameImage *image = GAME_IMAGE (image_); switch (param_id) { case PROP_IMAGE: g_value_set_boxed (value, image->surface); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (image, param_id, pspec); break; } } static void game_image_set_property (GObject *obj, guint param_id, const GValue *value, GParamSpec *pspec) { cairo_surface_t *surface; GameImage *image = GAME_IMAGE (obj); switch (param_id) { case PROP_IMAGE: if (image->surface) cairo_surface_destroy (image->surface); image->surface = NULL; surface = g_value_get_boxed (value); if (surface) { #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE (1, 1, 0) g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE); #endif image->surface = surface; cairo_surface_reference (image->surface); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (image, param_id, pspec); break; } } static void game_image_dispose (GObject *object) { GameImage *image = GAME_IMAGE (object); if (image->surface) { cairo_surface_destroy (image->surface); image->surface = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); } static void game_image_draw (GameGraphic *graphic, cairo_t *cr) { GameImage *image = GAME_IMAGE (graphic); int width, height; double gw, gh; if (image->surface == NULL) return; width = cairo_image_surface_get_width (image->surface); height = cairo_image_surface_get_height (image->surface); gw = graphic->rect.x2 - graphic->rect.x1; gh = graphic->rect.y2 - graphic->rect.y1; cairo_translate (cr, graphic->rect.x1, graphic->rect.y1); cairo_scale (cr, gw / width, gh / height); cairo_set_source_surface (cr, image->surface, 0, 0); /* I dunno why that's needed, but there are drawing glitches without */ //cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT); cairo_paint (cr); } static gboolean game_image_copy (GameObject *odest, GameObject *osrc) { GameImage *dest = GAME_IMAGE (odest); GameImage *src = GAME_IMAGE (osrc); dest->surface = src->surface; if (dest->surface) cairo_surface_reference (dest->surface); return GAME_OBJECT_CLASS (parent_class)->copy (odest, osrc); } static void game_image_class_init (gpointer g_class, gpointer class_data) { GObjectClass *object_class = G_OBJECT_CLASS (g_class); GameObjectClass *gameobject_class = GAME_OBJECT_CLASS (g_class); GameGraphicClass *graphic_class = GAME_GRAPHIC_CLASS (g_class); parent_class = g_type_class_peek_parent (g_class); object_class->set_property = game_image_set_property; object_class->get_property = game_image_get_property; object_class->dispose = game_image_dispose; g_object_class_install_property (object_class, PROP_IMAGE, g_param_spec_boxed ("surface", _("surface"), _("cairo image surface to display"), CAIRO_GOBJECT_TYPE_SURFACE, G_PARAM_READWRITE)); gameobject_class->copy = game_image_copy; graphic_class->draw = game_image_draw; } static void game_image_init (GTypeInstance *instance, gpointer g_class) { } GType game_image_get_type () { static GType image_type = 0; if (!image_type) { static const GTypeInfo image_info = { sizeof (GameImageClass), NULL, NULL, game_image_class_init, NULL, NULL, sizeof (GameImage), 0, game_image_init, }; image_type = g_type_register_static (GAME_TYPE_GRAPHIC, "GameImage", &image_info, 0); } return image_type; } GameGraphic * game_image_new_from_file (GameGame *game, const char *filename, const GameRectangle *size, GError **error) { GdkPixbuf *pixbuf; g_return_val_if_fail (GAME_IS_GAME (game), NULL); g_return_val_if_fail (filename != NULL, NULL); if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) { pixbuf = gdk_pixbuf_new_from_file (filename, error); } else { char *s = g_build_filename (game_get_data_dir (), game->name, filename, NULL); pixbuf = gdk_pixbuf_new_from_file (s, error); g_free (s); } if (!pixbuf) return NULL; return game_image_new_from_pixbuf (game, pixbuf, size); } /** * game_image_new_from_pixbuf: * @pixbuf: a #GdkPixbuf - takes ownership of the image, so you need to ref it * if you want to keep using it. * @size: a #GameRectangle for the size taken by the image or NULL for the * default (0,0,1,1) * * Creates a graphic from a given #GdkPixbuf. * * Returns: a newly created graphic. **/ GameGraphic * game_image_new_from_pixbuf (GameGame *game, GdkPixbuf *pixbuf, const GameRectangle *size) { static const GameRectangle default_size = { 0.0, 0.0, 1.0, 1.0 }; GameGraphic *ret; cairo_surface_t *surface; g_return_val_if_fail (GAME_IS_GAME (game), NULL); g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); if (size == NULL) size = &default_size; surface = game_cairo_surface_from_pixbuf (pixbuf); g_object_unref (pixbuf); ret = GAME_GRAPHIC (game_game_add_object (game, GAME_TYPE_IMAGE, "x", size->x1, "width", size->x2 - size->x1, "y", size->y1, "height", size->y2 - size->y1, "surface", surface, NULL)); cairo_surface_destroy (surface); return ret; } cairo_surface_t * game_cairo_surface_from_pixbuf (GdkPixbuf *pixbuf) { cairo_surface_t *ret = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf)); cairo_t *cr = cairo_create (ret); gdk_cairo_set_source_pixbuf (cr, pixbuf, 0.0, 0.0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_destroy (cr); return ret; } cairo_surface_t * game_cairo_surface_from_file (const char *filename, GError **error) { GdkPixbuf *pixbuf; cairo_surface_t *surface; pixbuf = gdk_pixbuf_new_from_file (filename, error); if (pixbuf == NULL) return NULL; surface = game_cairo_surface_from_pixbuf (pixbuf); g_object_unref (pixbuf); return surface; }