From a2474e2c470e7a6bcec4c5547440238de3163add Mon Sep 17 00:00:00 2001 From: "P. F. Chimento" Date: Tue, 23 Nov 2010 01:01:29 +0100 Subject: [PATCH] Wrote chimara_glk_set_resource_load_callback() Added a function for providing an alternate mechanism for loading resources, as described in the Blorb specification, section 14. This function allows the host program to specify a callback which the Glk program will call when a resource is requested and no Blorb resource map is loaded. --- docs/reference/chimara-sections.txt | 5 +- libchimara/chimara-glk-private.h | 3 ++ libchimara/chimara-glk.c | 29 +++++++++++ libchimara/chimara-glk.h | 26 ++++++++++ libchimara/graphics.c | 77 ++++++++++++++++++++++------- 5 files changed, 122 insertions(+), 18 deletions(-) diff --git a/docs/reference/chimara-sections.txt b/docs/reference/chimara-sections.txt index d2e37f5..df3ff5d 100644 --- a/docs/reference/chimara-sections.txt +++ b/docs/reference/chimara-sections.txt @@ -5,6 +5,8 @@ ChimaraGlk ChimaraError CHIMARA_ERROR chimara_error_quark +ChimaraResourceLoadFunc +ChimaraResourceType chimara_glk_new chimara_glk_set_interactive chimara_glk_get_interactive @@ -21,6 +23,7 @@ chimara_glk_wait chimara_glk_get_running chimara_glk_feed_char_input chimara_glk_feed_line_input +chimara_glk_set_resource_load_callback CHIMARA_GLK CHIMARA_IS_GLK @@ -647,4 +650,4 @@ zcolor_DarkGrey keycode_Erase zcolor_NUMCOLORS - \ No newline at end of file + diff --git a/libchimara/chimara-glk-private.h b/libchimara/chimara-glk-private.h index 44a2a49..e4f4123 100644 --- a/libchimara/chimara-glk-private.h +++ b/libchimara/chimara-glk-private.h @@ -89,6 +89,9 @@ struct _ChimaraGlkPrivate { giblorb_map_t *resource_map; /* File stream pointing to the blorb used as current resource map */ strid_t resource_file; + /* Optional callback for loading resource data */ + ChimaraResourceLoadFunc resource_load_callback; + gpointer resource_load_callback_data; /* Callbacks for registering and unregistering dispatch objects */ gidispatch_rock_t (*register_obj)(void *, glui32); void (*unregister_obj)(void *, glui32, gidispatch_rock_t); diff --git a/libchimara/chimara-glk.c b/libchimara/chimara-glk.c index 6221175..d7ba466 100644 --- a/libchimara/chimara-glk.c +++ b/libchimara/chimara-glk.c @@ -182,6 +182,8 @@ chimara_glk_init(ChimaraGlk *self) priv->resource_lock = g_mutex_new(); priv->resource_loaded = g_cond_new(); priv->resource_info_available = g_cond_new(); + priv->resource_load_callback = NULL; + priv->resource_load_callback_data = NULL; priv->image_cache = NULL; priv->program_name = NULL; priv->program_info = NULL; @@ -1505,3 +1507,30 @@ chimara_glk_update_style(ChimaraGlk *glk) g_mutex_unlock(priv->arrange_lock); gtk_widget_queue_resize( GTK_WIDGET(priv->self) ); } + +/** + * chimara_glk_set_resource_load_callback: + * @glk: a #ChimaraGlk widget + * @func: a function to call for loading resources, or %NULL + * @user_data: user data to pass to @func, or %NULL + * + * Sometimes it is preferable to load image and sound resources from somewhere + * else than a Blorb file, for example while developing a game. Section 14 of + * the Blorb + * specification allows for this possibility. This function sets @func + * to be called when the Glk program requests loading an image or sound without + * a Blorb resource map having been loaded, optionally passing @user_data as an + * extra parameter. + * + * Note that @func is only called if no Blorb resource map has been set; having + * a resource map in place overrides this function. + * + * To deactivate the callback, call this function with @func set to %NULL. + */ +void +chimara_glk_set_resource_load_callback(ChimaraGlk *glk, ChimaraResourceLoadFunc func, gpointer user_data) +{ + CHIMARA_GLK_USE_PRIVATE(glk, priv); + priv->resource_load_callback = func; + priv->resource_load_callback_data = user_data; +} diff --git a/libchimara/chimara-glk.h b/libchimara/chimara-glk.h index f4d9edd..089bccb 100644 --- a/libchimara/chimara-glk.h +++ b/libchimara/chimara-glk.h @@ -66,6 +66,31 @@ typedef enum _ChimaraError { CHIMARA_PLUGIN_ALREADY_RUNNING } ChimaraError; +/** + * ChimaraResourceType: + * @CHIMARA_RESOURCE_SOUND: A sound file. + * @CHIMARA_RESOURCE_IMAGE: An image file. + * + * The type of resource that the Glk program is requesting, passed to a + * #ChimaraResourceLoadFunc. + */ +typedef enum _ChimaraResourceType { + CHIMARA_RESOURCE_SOUND, + CHIMARA_RESOURCE_IMAGE +} ChimaraResourceType; + +/** + * ChimaraResourceLoadFunc: + * + * The type of function passed to chimara_glk_set_resource_load_callback(). It + * takes a #ChimaraResourceType constant, @usage, to indicate what sort of + * resource to look for; @resnum is the resource number to look for, and + * @user_data is the user data provided along with the callback. The function + * must return an allocated string containing the filename where the resource + * can be found. + */ +typedef gchar * (*ChimaraResourceLoadFunc)(ChimaraResourceType usage, guint32 resnum, gpointer user_data); + /** * CHIMARA_ERROR: * @@ -97,6 +122,7 @@ GtkTextTag *chimara_glk_get_tag(ChimaraGlk *glk, ChimaraGlkWindowType window, co const gchar **chimara_glk_get_tag_names(ChimaraGlk *glk); gint chimara_glk_get_num_tag_names(ChimaraGlk *glk); void chimara_glk_update_style(ChimaraGlk *glk); +void chimara_glk_set_resource_load_callback(ChimaraGlk *glk, ChimaraResourceLoadFunc func, gpointer user_data); G_END_DECLS diff --git a/libchimara/graphics.c b/libchimara/graphics.c index 190b44b..0011a8d 100644 --- a/libchimara/graphics.c +++ b/libchimara/graphics.c @@ -13,25 +13,12 @@ static gboolean image_loaded; static gboolean size_determined; static struct image_info* -load_image_in_cache(glui32 image, gint width, gint height) +load_image_from_blorb(giblorb_result_t resource, glui32 image, gint width, gint height) { ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); - giblorb_err_t blorb_error = 0; - giblorb_result_t resource; GError *pixbuf_error = NULL; guchar *buffer; - /* Lookup the proper resource */ - if(!glk_data->resource_map) { - WARNING("No resource map has been loaded yet."); - return NULL; - } - blorb_error = giblorb_load_resource(glk_data->resource_map, giblorb_method_FilePos, &resource, giblorb_ID_Pict, image); - if(blorb_error != giblorb_err_None) { - WARNING_S( "Error loading resource", giblorb_get_error_message(blorb_error) ); - return NULL; - } - struct image_info *info = g_new0(struct image_info, 1); info->resource_number = image; @@ -75,6 +62,65 @@ load_image_in_cache(glui32 image, gint width, gint height) } g_mutex_unlock(glk_data->resource_lock); + info->pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); + + g_object_unref(loader); + return info; +} + +static struct image_info * +load_image_from_file(const gchar *filename, glui32 image, gint width, gint height) +{ + GError *err = NULL; + + struct image_info *info = g_new0(struct image_info, 1); + info->resource_number = image; + + if(width > 0 && height > 0) { + info->scaled = TRUE; + info->pixbuf = gdk_pixbuf_new_from_file_at_size(filename, width, height, &err); + } else { + info->pixbuf = gdk_pixbuf_new_from_file(filename, &err); + } + if(!info->pixbuf) { + IO_WARNING("Error loading resource from alternative location", filename, err->message); + g_error_free(err); + g_free(info); + return NULL; + } + + return info; +} + +static struct image_info* +load_image_in_cache(glui32 image, gint width, gint height) +{ + ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + struct image_info *info = NULL; + + /* Lookup the proper resource */ + if(!glk_data->resource_map) { + if(!glk_data->resource_load_callback) { + WARNING("No resource map has been loaded yet."); + return NULL; + } + gchar *filename = glk_data->resource_load_callback(CHIMARA_RESOURCE_IMAGE, image, glk_data->resource_load_callback_data); + if(!filename) { + WARNING("Error loading resource from alternative location"); + return NULL; + } + info = load_image_from_file(filename, image, width, height); + g_free(filename); + } else { + giblorb_result_t resource; + giblorb_err_t blorb_error = giblorb_load_resource(glk_data->resource_map, giblorb_method_FilePos, &resource, giblorb_ID_Pict, image); + if(blorb_error != giblorb_err_None) { + WARNING_S( "Error loading resource", giblorb_get_error_message(blorb_error) ); + return NULL; + } + info = load_image_from_blorb(resource, image, width, height); + } + /* Store the image in the cache */ gdk_threads_enter(); @@ -84,15 +130,12 @@ load_image_in_cache(glui32 image, gint width, gint height) g_free(head); glk_data->image_cache = g_slist_remove_link(glk_data->image_cache, glk_data->image_cache); } - info->pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); gdk_pixbuf_ref(info->pixbuf); info->width = gdk_pixbuf_get_width(info->pixbuf); info->height = gdk_pixbuf_get_height(info->pixbuf); glk_data->image_cache = g_slist_prepend(glk_data->image_cache, info); gdk_threads_leave(); - - g_object_unref(loader); return info; } -- 2.30.2