Wrote chimara_glk_set_resource_load_callback()
authorP. F. Chimento <philip.chimento@gmail.com>
Tue, 23 Nov 2010 00:01:29 +0000 (01:01 +0100)
committerP. F. Chimento <philip.chimento@gmail.com>
Tue, 23 Nov 2010 00:01:29 +0000 (01:01 +0100)
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
libchimara/chimara-glk-private.h
libchimara/chimara-glk.c
libchimara/chimara-glk.h
libchimara/graphics.c

index d2e37f5cf0f0c3a09aa8ed1e4137e49cfa7adc19..df3ff5da3ca50bc2059c27ef542aa3da03b672e5 100644 (file)
@@ -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
 <SUBSECTION Standard>
 CHIMARA_GLK
 CHIMARA_IS_GLK
@@ -647,4 +650,4 @@ zcolor_DarkGrey
 keycode_Erase
 <SUBSECTION Private>
 zcolor_NUMCOLORS
-</SECTION>
\ No newline at end of file
+</SECTION>
index 44a2a49988ede5de56f680b913d80312fbc5ce62..e4f4123f5a00e9bd8dc00ed3817532a78718d456 100644 (file)
@@ -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);
index 622117591e2da39be487fbb5e850be8e21713fa5..d7ba466a94abb67183bbf0d5cdd401a24ac5a73b 100644 (file)
@@ -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 <ulink url="http://eblong.com/zarf/blorb/blorb.html#s14">Blorb
+ * specification</ulink> 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;
+}
index f4d9eddc0784f4dc27272e76ec48f17458af6d8b..089bccb50e7caaf7145ad8c9768913f7e9c7afdd 100644 (file)
@@ -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
 
index 190b44b99aa65975d9015f9f8cbd0d4d4274bff1..0011a8d56f19c64674f28cb356f50edc5b7163af 100644 (file)
@@ -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;
 }