Merge branch 'async-textures'
* async-textures: Whitespace fixes in ClutterTexture [async-loading] Do not force the texture size on async load [async-loading] Update asynchronous image loading Add API for extracting image size from a file Update/clean and apply the async-texture patch from bug #1144
This commit is contained in:
commit
110489ee58
@ -96,6 +96,13 @@ struct _ClutterTexturePrivate
|
|||||||
guint repeat_y : 1;
|
guint repeat_y : 1;
|
||||||
guint in_dispose : 1;
|
guint in_dispose : 1;
|
||||||
guint keep_aspect_ratio : 1;
|
guint keep_aspect_ratio : 1;
|
||||||
|
guint load_async : 1;
|
||||||
|
|
||||||
|
GThread *load_thread;
|
||||||
|
guint load_idle;
|
||||||
|
gchar *load_filename;
|
||||||
|
CoglBitmap *load_bitmap;
|
||||||
|
GError *load_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -110,13 +117,17 @@ enum
|
|||||||
PROP_FILTER_QUALITY,
|
PROP_FILTER_QUALITY,
|
||||||
PROP_COGL_TEXTURE,
|
PROP_COGL_TEXTURE,
|
||||||
PROP_FILENAME,
|
PROP_FILENAME,
|
||||||
PROP_KEEP_ASPECT_RATIO
|
PROP_KEEP_ASPECT_RATIO,
|
||||||
|
PROP_LOAD_ASYNC
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
SIZE_CHANGE,
|
SIZE_CHANGE,
|
||||||
PIXBUF_CHANGE,
|
PIXBUF_CHANGE,
|
||||||
|
LOAD_SUCCESS,
|
||||||
|
LOAD_FINISHED,
|
||||||
|
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -252,8 +263,8 @@ clutter_texture_realize (ClutterActor *actor)
|
|||||||
if (priv->texture != COGL_INVALID_HANDLE)
|
if (priv->texture != COGL_INVALID_HANDLE)
|
||||||
cogl_texture_unref (priv->texture);
|
cogl_texture_unref (priv->texture);
|
||||||
|
|
||||||
priv->texture
|
priv->texture =
|
||||||
= cogl_texture_new_with_size
|
cogl_texture_new_with_size
|
||||||
(priv->width,
|
(priv->width,
|
||||||
priv->height,
|
priv->height,
|
||||||
priv->no_slice ? -1 : priv->max_tile_waste,
|
priv->no_slice ? -1 : priv->max_tile_waste,
|
||||||
@ -601,6 +612,45 @@ clutter_texture_paint (ClutterActor *self)
|
|||||||
0, 0, t_w, t_h);
|
0, 0, t_w, t_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clutter_texture_async_load_cancel:
|
||||||
|
* @texture: a #ClutterTexture
|
||||||
|
*
|
||||||
|
* Cancels an asynchronous loading operation, whether done
|
||||||
|
* with threads enabled or just using the main loop
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
clutter_texture_async_load_cancel (ClutterTexture *texture)
|
||||||
|
{
|
||||||
|
ClutterTexturePrivate *priv = texture->priv;
|
||||||
|
|
||||||
|
if (priv->load_thread)
|
||||||
|
{
|
||||||
|
g_thread_join (priv->load_thread);
|
||||||
|
priv->load_thread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->load_idle)
|
||||||
|
{
|
||||||
|
g_source_remove (priv->load_idle);
|
||||||
|
priv->load_idle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->load_error)
|
||||||
|
{
|
||||||
|
g_error_free (priv->load_error);
|
||||||
|
priv->load_error = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->load_bitmap)
|
||||||
|
{
|
||||||
|
cogl_bitmap_free (priv->load_bitmap);
|
||||||
|
priv->load_bitmap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (priv->load_filename);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_texture_dispose (GObject *object)
|
clutter_texture_dispose (GObject *object)
|
||||||
{
|
{
|
||||||
@ -626,6 +676,8 @@ clutter_texture_dispose (GObject *object)
|
|||||||
priv->local_data = NULL;
|
priv->local_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clutter_texture_async_load_cancel (texture);
|
||||||
|
|
||||||
G_OBJECT_CLASS (clutter_texture_parent_class)->dispose (object);
|
G_OBJECT_CLASS (clutter_texture_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,6 +738,9 @@ clutter_texture_set_property (GObject *object,
|
|||||||
case PROP_KEEP_ASPECT_RATIO:
|
case PROP_KEEP_ASPECT_RATIO:
|
||||||
priv->keep_aspect_ratio = g_value_get_boolean (value);
|
priv->keep_aspect_ratio = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_LOAD_ASYNC:
|
||||||
|
priv->load_async = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -736,6 +791,9 @@ clutter_texture_get_property (GObject *object,
|
|||||||
case PROP_KEEP_ASPECT_RATIO:
|
case PROP_KEEP_ASPECT_RATIO:
|
||||||
g_value_set_boolean (value, priv->keep_aspect_ratio);
|
g_value_set_boolean (value, priv->keep_aspect_ratio);
|
||||||
break;
|
break;
|
||||||
|
case PROP_LOAD_ASYNC:
|
||||||
|
g_value_set_boolean (value, priv->load_async);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -861,6 +919,29 @@ clutter_texture_class_init (ClutterTextureClass *klass)
|
|||||||
FALSE,
|
FALSE,
|
||||||
CLUTTER_PARAM_READWRITE));
|
CLUTTER_PARAM_READWRITE));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClutterTexture:load-async:
|
||||||
|
*
|
||||||
|
* Tries to load a texture from a filename by using a local thread
|
||||||
|
* to perform the read operations. Threading is only enabled if
|
||||||
|
* g_thread_init() has been called prior to clutter_init(), otherwise
|
||||||
|
* #ClutterTexture will use the main loop to load the image.
|
||||||
|
*
|
||||||
|
* The upload of the texture data on the GL pipeline is not
|
||||||
|
* asynchronous, as it must be performed from within the same
|
||||||
|
* thread that called clutter_main().
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
g_object_class_install_property
|
||||||
|
(gobject_class, PROP_LOAD_ASYNC,
|
||||||
|
g_param_spec_boolean ("load-async",
|
||||||
|
"Load asynchronously",
|
||||||
|
"Load files inside a thread to avoid blocking when "
|
||||||
|
"loading images.",
|
||||||
|
FALSE,
|
||||||
|
CLUTTER_PARAM_READWRITE));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ClutterTexture::size-change:
|
* ClutterTexture::size-change:
|
||||||
* @texture: the texture which received the signal
|
* @texture: the texture which received the signal
|
||||||
@ -896,6 +977,27 @@ clutter_texture_class_init (ClutterTextureClass *klass)
|
|||||||
g_cclosure_marshal_VOID__VOID,
|
g_cclosure_marshal_VOID__VOID,
|
||||||
G_TYPE_NONE,
|
G_TYPE_NONE,
|
||||||
0);
|
0);
|
||||||
|
/**
|
||||||
|
* ClutterTexture::load-finished:
|
||||||
|
* @texture: the texture which received the signal
|
||||||
|
* @error: A set error, or %NULL
|
||||||
|
*
|
||||||
|
* The ::load-finished signal is emitted when a texture load has
|
||||||
|
* completed. If there was an error during loading, @error will
|
||||||
|
* be set, otherwise it will be %NULL
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
texture_signals[LOAD_FINISHED] =
|
||||||
|
g_signal_new (I_("load-finished"),
|
||||||
|
G_TYPE_FROM_CLASS (gobject_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (ClutterTextureClass, load_finished),
|
||||||
|
NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__POINTER,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
1,
|
||||||
|
G_TYPE_POINTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClutterScriptableIface *parent_scriptable_iface = NULL;
|
static ClutterScriptableIface *parent_scriptable_iface = NULL;
|
||||||
@ -1262,7 +1364,7 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
|
|||||||
* Return value: %TRUE if the texture was successfully updated
|
* Return value: %TRUE if the texture was successfully updated
|
||||||
*
|
*
|
||||||
* Since: 0.4
|
* Since: 0.4
|
||||||
**/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
clutter_texture_set_from_yuv_data (ClutterTexture *texture,
|
clutter_texture_set_from_yuv_data (ClutterTexture *texture,
|
||||||
const guchar *data,
|
const guchar *data,
|
||||||
@ -1301,6 +1403,188 @@ clutter_texture_set_from_yuv_data (ClutterTexture *texture,
|
|||||||
error);
|
error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clutter_texture_async_load_complete:
|
||||||
|
* @self: a #ClutterTexture
|
||||||
|
* @error: load error
|
||||||
|
*
|
||||||
|
* If @error is %NULL, loads the #CoglBitmap into a #CoglTexture.
|
||||||
|
*
|
||||||
|
* This function emits the ::load-finished signal on @self.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
clutter_texture_async_load_complete (ClutterTexture *self,
|
||||||
|
const GError *error)
|
||||||
|
{
|
||||||
|
ClutterTexturePrivate *priv = self->priv;
|
||||||
|
CoglHandle handle;
|
||||||
|
gboolean enable_mipmap = FALSE;
|
||||||
|
gint waste = -1;
|
||||||
|
|
||||||
|
if (error == NULL)
|
||||||
|
{
|
||||||
|
if (priv->no_slice)
|
||||||
|
waste = priv->max_tile_waste;
|
||||||
|
|
||||||
|
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
|
||||||
|
enable_mipmap = TRUE;
|
||||||
|
|
||||||
|
handle = cogl_texture_new_from_bitmap (priv->load_bitmap,
|
||||||
|
waste, enable_mipmap,
|
||||||
|
COGL_PIXEL_FORMAT_ANY);
|
||||||
|
clutter_texture_set_cogl_texture (self, handle);
|
||||||
|
cogl_texture_unref (handle);
|
||||||
|
|
||||||
|
cogl_bitmap_free (priv->load_bitmap);
|
||||||
|
priv->load_bitmap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_emit (self, texture_signals[LOAD_FINISHED], 0, error);
|
||||||
|
|
||||||
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
clutter_texture_thread_cb (gpointer data)
|
||||||
|
{
|
||||||
|
ClutterTexture *self = data;
|
||||||
|
ClutterTexturePrivate *priv = self->priv;
|
||||||
|
|
||||||
|
priv->load_idle = 0;
|
||||||
|
|
||||||
|
if (priv->load_thread)
|
||||||
|
{
|
||||||
|
g_thread_join (priv->load_thread);
|
||||||
|
priv->load_thread = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
clutter_texture_async_load_complete (self, priv->load_error);
|
||||||
|
|
||||||
|
if (priv->load_error)
|
||||||
|
{
|
||||||
|
g_error_free (priv->load_error);
|
||||||
|
priv->load_error = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
clutter_texture_thread_func (gpointer data)
|
||||||
|
{
|
||||||
|
ClutterTexture *self = data;
|
||||||
|
ClutterTexturePrivate *priv = self->priv;
|
||||||
|
|
||||||
|
/* Try loading with imaging backend */
|
||||||
|
priv->load_bitmap = cogl_bitmap_new_from_file (priv->load_filename,
|
||||||
|
&priv->load_error);
|
||||||
|
g_free (priv->load_filename);
|
||||||
|
priv->load_filename = NULL;
|
||||||
|
|
||||||
|
/* make sure we load the image in the main thread, where we
|
||||||
|
* hold the main Clutter lock
|
||||||
|
*/
|
||||||
|
priv->load_idle =
|
||||||
|
clutter_threads_add_idle (clutter_texture_thread_cb, self);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
clutter_texture_idle_func (gpointer data)
|
||||||
|
{
|
||||||
|
ClutterTexture *self = data;
|
||||||
|
ClutterTexturePrivate *priv = self->priv;
|
||||||
|
GError *internal_error;
|
||||||
|
|
||||||
|
internal_error = NULL;
|
||||||
|
priv->load_bitmap = cogl_bitmap_new_from_file (priv->load_filename,
|
||||||
|
&internal_error);
|
||||||
|
|
||||||
|
clutter_texture_async_load_complete (self, internal_error);
|
||||||
|
|
||||||
|
g_free (priv->load_filename);
|
||||||
|
priv->load_filename = NULL;
|
||||||
|
|
||||||
|
if (internal_error)
|
||||||
|
g_error_free (internal_error);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clutter_texture_async_load:
|
||||||
|
* @self: a #ClutterTexture
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Starts an asynchronous load of the file name stored inside
|
||||||
|
* the load_filename private member.
|
||||||
|
*
|
||||||
|
* If threading is enabled we use a GThread to perform the actual
|
||||||
|
* I/O; if threading is not enabled, we use an idle GSource.
|
||||||
|
*
|
||||||
|
* The I/O is the only bit done in a thread -- uploading the
|
||||||
|
* texture data to the GL pipeline must be done from within the
|
||||||
|
* same thread that called clutter_main(). Threaded upload should
|
||||||
|
* be part of the GL implementation.
|
||||||
|
*
|
||||||
|
* This function will block until we get a size from the file
|
||||||
|
* so that we can effectively get the size the texture actor after
|
||||||
|
* clutter_texture_set_from_file().
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if the asynchronous loading was successfully
|
||||||
|
* initiated, %FALSE otherwise
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
clutter_texture_async_load (ClutterTexture *self,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
ClutterTexturePrivate *priv = self->priv;
|
||||||
|
gint width, height;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
g_assert (priv->load_filename != NULL);
|
||||||
|
|
||||||
|
/* ask the file for a size; if we cannot get the size then
|
||||||
|
* there's no point in even continuing the asynchronous
|
||||||
|
* loading, so we just stop there
|
||||||
|
*/
|
||||||
|
res = cogl_bitmap_get_size_from_file (priv->load_filename,
|
||||||
|
&width,
|
||||||
|
&height);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
g_set_error (error, CLUTTER_TEXTURE_ERROR,
|
||||||
|
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
|
||||||
|
"Failed to create COGL texture");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
priv->width = width;
|
||||||
|
priv->height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_thread_supported ())
|
||||||
|
{
|
||||||
|
priv->load_thread =
|
||||||
|
g_thread_create ((GThreadFunc) clutter_texture_thread_func,
|
||||||
|
self, TRUE,
|
||||||
|
error);
|
||||||
|
|
||||||
|
return priv->load_thread != NULL? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
priv->load_idle =
|
||||||
|
clutter_threads_add_idle (clutter_texture_idle_func, self);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_texture_set_from_file:
|
* clutter_texture_set_from_file:
|
||||||
* @texture: A #ClutterTexture
|
* @texture: A #ClutterTexture
|
||||||
@ -1310,6 +1594,12 @@ clutter_texture_set_from_yuv_data (ClutterTexture *texture,
|
|||||||
* Sets the #ClutterTexture image data from an image file. In case of
|
* Sets the #ClutterTexture image data from an image file. In case of
|
||||||
* failure, %FALSE is returned and @error is set.
|
* failure, %FALSE is returned and @error is set.
|
||||||
*
|
*
|
||||||
|
* If #ClutterTexture:load-async is set to %TRUE, this function
|
||||||
|
* will return as soon as possible, and the actual image loading
|
||||||
|
* from disk will be performed asynchronously. #ClutterTexture::load-finished
|
||||||
|
* will be emitted when the image has been loaded or if an error
|
||||||
|
* occurred.
|
||||||
|
*
|
||||||
* Return value: %TRUE if the image was successfully loaded and set
|
* Return value: %TRUE if the image was successfully loaded and set
|
||||||
*
|
*
|
||||||
* Since: 0.8
|
* Since: 0.8
|
||||||
@ -1319,28 +1609,48 @@ clutter_texture_set_from_file (ClutterTexture *texture,
|
|||||||
const gchar *filename,
|
const gchar *filename,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
CoglHandle new_texture;
|
|
||||||
ClutterTexturePrivate *priv;
|
ClutterTexturePrivate *priv;
|
||||||
|
CoglHandle new_texture = COGL_INVALID_HANDLE;
|
||||||
|
GError *internal_error = NULL;
|
||||||
|
gboolean enable_mipmap = FALSE;
|
||||||
|
gint max_waste = -1;
|
||||||
|
|
||||||
priv = texture->priv;
|
priv = texture->priv;
|
||||||
|
|
||||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
||||||
if ((new_texture = cogl_texture_new_from_file
|
if (priv->load_async)
|
||||||
(filename,
|
{
|
||||||
priv->no_slice ? -1 : priv->max_tile_waste,
|
clutter_texture_async_load_cancel (texture);
|
||||||
priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH,
|
|
||||||
|
priv->load_filename = g_strdup (filename);
|
||||||
|
|
||||||
|
return clutter_texture_async_load (texture, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->no_slice)
|
||||||
|
max_waste = priv->max_tile_waste;
|
||||||
|
|
||||||
|
if (priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH)
|
||||||
|
enable_mipmap = TRUE;
|
||||||
|
|
||||||
|
new_texture = cogl_texture_new_from_file (filename,
|
||||||
|
max_waste, enable_mipmap,
|
||||||
COGL_PIXEL_FORMAT_ANY,
|
COGL_PIXEL_FORMAT_ANY,
|
||||||
error))
|
&internal_error);
|
||||||
== COGL_INVALID_HANDLE)
|
if (new_texture == COGL_INVALID_HANDLE)
|
||||||
{
|
{
|
||||||
/* If COGL didn't give an error then make one up */
|
/* If COGL didn't give an error then make one up */
|
||||||
if (error && *error == NULL)
|
if (internal_error == NULL)
|
||||||
{
|
{
|
||||||
g_set_error (error, CLUTTER_TEXTURE_ERROR,
|
g_set_error (error, CLUTTER_TEXTURE_ERROR,
|
||||||
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
|
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
|
||||||
"Failed to create COGL texture");
|
"Failed to create COGL texture");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
g_propagate_error (error, internal_error);
|
||||||
|
|
||||||
|
g_signal_emit (texture, texture_signals[LOAD_FINISHED], 0, error);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1353,6 +1663,8 @@ clutter_texture_set_from_file (ClutterTexture *texture,
|
|||||||
|
|
||||||
cogl_texture_unref (new_texture);
|
cogl_texture_unref (new_texture);
|
||||||
|
|
||||||
|
g_signal_emit (texture, texture_signals[LOAD_FINISHED], 0, error);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +84,8 @@ struct _ClutterTextureClass
|
|||||||
gint width,
|
gint width,
|
||||||
gint height);
|
gint height);
|
||||||
void (*pixbuf_change) (ClutterTexture *texture);
|
void (*pixbuf_change) (ClutterTexture *texture);
|
||||||
|
void (*load_finished) (ClutterTexture *texture,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
/* padding, for future expansion */
|
/* padding, for future expansion */
|
||||||
@ -92,7 +94,6 @@ struct _ClutterTextureClass
|
|||||||
void (*_clutter_texture3) (void);
|
void (*_clutter_texture3) (void);
|
||||||
void (*_clutter_texture4) (void);
|
void (*_clutter_texture4) (void);
|
||||||
void (*_clutter_texture5) (void);
|
void (*_clutter_texture5) (void);
|
||||||
void (*_clutter_texture6) (void);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,6 +134,26 @@ CoglHandle cogl_texture_new_from_foreign (GLuint gl_handle,
|
|||||||
GLuint y_pot_waste,
|
GLuint y_pot_waste,
|
||||||
CoglPixelFormat format);
|
CoglPixelFormat format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_texture_new_from_bitmap:
|
||||||
|
* @handle: handle of the preloaded texture.
|
||||||
|
* @max_waste: maximum extra horizontal and|or vertical margin pixels to make
|
||||||
|
* texture fit GPU limitations.
|
||||||
|
* @auto_mipmap: enable or disable automatic generation of mipmap pyramid
|
||||||
|
* from the base level image whenever it is updated.
|
||||||
|
* @internal_format: the #CoglPixelFormat to use for the GPU storage of the
|
||||||
|
* texture.
|
||||||
|
*
|
||||||
|
* Create a cogl texture from a #CoglBitmap.
|
||||||
|
*
|
||||||
|
* Returns: a #CoglHandle to the newly created texture or COGL_INVALID_HANDLE
|
||||||
|
* if creating the texture failed.
|
||||||
|
*/
|
||||||
|
CoglHandle cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
|
||||||
|
gint max_waste,
|
||||||
|
gboolean auto_mipmap,
|
||||||
|
CoglPixelFormat internal_format);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cogl_is_texture:
|
* cogl_is_texture:
|
||||||
* @handle: A CoglHandle
|
* @handle: A CoglHandle
|
||||||
@ -385,6 +405,45 @@ void cogl_texture_polygon (CoglHandle handle,
|
|||||||
CoglTextureVertex *vertices,
|
CoglTextureVertex *vertices,
|
||||||
gboolean use_color);
|
gboolean use_color);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_bitmap_new_from_file:
|
||||||
|
* @filename: the file to load.
|
||||||
|
* @error: a #GError or %NULL.
|
||||||
|
*
|
||||||
|
* Load an image file from disk. This function can be safely called from
|
||||||
|
* within a thread.
|
||||||
|
*
|
||||||
|
* Returns: A #CoglBitmap to the new loaded image data, or %NULL if loading
|
||||||
|
* the image failed.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
CoglBitmap * cogl_bitmap_new_from_file (const gchar *filename,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_bitmap_get_size_from_file:
|
||||||
|
* @filename: the file to check
|
||||||
|
* @width: return location for the bitmap width
|
||||||
|
* @height: return location for the bitmap height
|
||||||
|
*
|
||||||
|
* Parses an image file enough to extract the width and height
|
||||||
|
* of the bitmap.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
gboolean cogl_bitmap_get_size_from_file (const gchar *filename,
|
||||||
|
gint *width,
|
||||||
|
gint *height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_bitmap_free:
|
||||||
|
* @bmp: a #CoglBitmap.
|
||||||
|
*
|
||||||
|
* Frees a #CoglBitmap.
|
||||||
|
*/
|
||||||
|
void cogl_bitmap_free (CoglBitmap *bmp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cogl_texture_multiple_rectangles:
|
* cogl_texture_multiple_rectangles:
|
||||||
* @handle: a @CoglHandle.
|
* @handle: a @CoglHandle.
|
||||||
|
@ -28,6 +28,13 @@
|
|||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CoglBitmap:
|
||||||
|
*
|
||||||
|
* Type used for storing image data.
|
||||||
|
*/
|
||||||
|
typedef struct _CoglBitmap CoglBitmap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CoglHandle:
|
* CoglHandle:
|
||||||
*
|
*
|
||||||
|
@ -84,6 +84,20 @@ cogl_bitmap_error_quark (void)
|
|||||||
return g_quark_from_static_string ("cogl-bitmap-error-quark");
|
return g_quark_from_static_string ("cogl-bitmap-error-quark");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_bitmap_get_size_from_file (const gchar *filename,
|
||||||
|
gint *width,
|
||||||
|
gint *height)
|
||||||
|
{
|
||||||
|
if (width)
|
||||||
|
*width = 0;
|
||||||
|
|
||||||
|
if (height)
|
||||||
|
*height = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* the error does not contain the filename as the caller already has it */
|
/* the error does not contain the filename as the caller already has it */
|
||||||
gboolean
|
gboolean
|
||||||
_cogl_bitmap_from_file (CoglBitmap *bmp,
|
_cogl_bitmap_from_file (CoglBitmap *bmp,
|
||||||
@ -176,6 +190,19 @@ _cogl_bitmap_from_file (CoglBitmap *bmp,
|
|||||||
|
|
||||||
#elif defined(USE_GDKPIXBUF)
|
#elif defined(USE_GDKPIXBUF)
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_bitmap_get_size_from_file (const gchar *filename,
|
||||||
|
gint *width,
|
||||||
|
gint *height)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (filename != NULL, FALSE);
|
||||||
|
|
||||||
|
if (gdk_pixbuf_get_file_info (filename, width, height) != NULL)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
_cogl_bitmap_from_file (CoglBitmap *bmp,
|
_cogl_bitmap_from_file (CoglBitmap *bmp,
|
||||||
const gchar *filename,
|
const gchar *filename,
|
||||||
@ -198,11 +225,13 @@ _cogl_bitmap_from_file (CoglBitmap *bmp,
|
|||||||
|
|
||||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
||||||
if (bmp == NULL) return FALSE;
|
if (bmp == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* Load from file using GdkPixbuf */
|
/* Load from file using GdkPixbuf */
|
||||||
pixbuf = gdk_pixbuf_new_from_file (filename, error);
|
pixbuf = gdk_pixbuf_new_from_file (filename, error);
|
||||||
if (pixbuf == NULL) return FALSE;
|
if (pixbuf == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* Get pixbuf properties */
|
/* Get pixbuf properties */
|
||||||
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
|
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
|
||||||
@ -278,6 +307,20 @@ _cogl_bitmap_from_file (CoglBitmap *bmp,
|
|||||||
|
|
||||||
#include "stb_image.c"
|
#include "stb_image.c"
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_bitmap_get_size_from_file (const gchar *filename,
|
||||||
|
gint *width,
|
||||||
|
gint *height)
|
||||||
|
{
|
||||||
|
if (width)
|
||||||
|
*width = 0;
|
||||||
|
|
||||||
|
if (height)
|
||||||
|
*height = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
_cogl_bitmap_from_file (CoglBitmap *bmp,
|
_cogl_bitmap_from_file (CoglBitmap *bmp,
|
||||||
const gchar *filename,
|
const gchar *filename,
|
||||||
@ -290,11 +333,15 @@ _cogl_bitmap_from_file (CoglBitmap *bmp,
|
|||||||
|
|
||||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
||||||
if (bmp == NULL) return FALSE;
|
if (bmp == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* Load from file using stb */
|
/* Load from file using stb */
|
||||||
pixels = stbi_load (filename, &width, &height, &stb_pixel_format, STBI_rgb_alpha);
|
pixels = stbi_load (filename,
|
||||||
if (pixels == NULL) return FALSE;
|
&width, &height, &stb_pixel_format,
|
||||||
|
STBI_rgb_alpha);
|
||||||
|
if (pixels == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* Store bitmap info */
|
/* Store bitmap info */
|
||||||
bmp->data = g_memdup (pixels, height * width * 4);
|
bmp->data = g_memdup (pixels, height * width * 4);
|
||||||
|
@ -148,3 +148,42 @@ _cogl_bitmap_copy_subregion (CoglBitmap *src,
|
|||||||
dstdata += dst->rowstride;
|
dstdata += dst->rowstride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
cogl_bitmap_get_size_from_file (const gchar *filename,
|
||||||
|
gint *width,
|
||||||
|
gint *height)
|
||||||
|
{
|
||||||
|
return _cogl_bitmap_get_size_from_file (filename, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoglBitmap *
|
||||||
|
cogl_bitmap_new_from_file (const gchar *filename,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
CoglBitmap bmp;
|
||||||
|
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE);
|
||||||
|
|
||||||
|
/* Try loading with imaging backend */
|
||||||
|
if (!_cogl_bitmap_from_file (&bmp, filename, error))
|
||||||
|
{
|
||||||
|
/* Try fallback */
|
||||||
|
if (!_cogl_bitmap_fallback_from_file (&bmp, filename))
|
||||||
|
return NULL;
|
||||||
|
else if (error && *error)
|
||||||
|
{
|
||||||
|
g_error_free (*error);
|
||||||
|
*error = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CoglBitmap *) g_memdup (&bmp, sizeof (CoglBitmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_bitmap_free (CoglBitmap *bmp)
|
||||||
|
{
|
||||||
|
g_free (bmp->data);
|
||||||
|
g_free (bmp);
|
||||||
|
}
|
||||||
|
@ -28,8 +28,6 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
typedef struct _CoglBitmap CoglBitmap;
|
|
||||||
|
|
||||||
struct _CoglBitmap
|
struct _CoglBitmap
|
||||||
{
|
{
|
||||||
guchar *data;
|
guchar *data;
|
||||||
@ -92,4 +90,9 @@ _cogl_bitmap_copy_subregion (CoglBitmap *src,
|
|||||||
gint width,
|
gint width,
|
||||||
gint height);
|
gint height);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_bitmap_get_size_from_file (const gchar *filename,
|
||||||
|
gint *width,
|
||||||
|
gint *height);
|
||||||
|
|
||||||
#endif /* __COGL_BITMAP_H */
|
#endif /* __COGL_BITMAP_H */
|
||||||
|
@ -1323,30 +1323,13 @@ cogl_texture_new_from_data (guint width,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CoglHandle
|
CoglHandle
|
||||||
cogl_texture_new_from_file (const gchar *filename,
|
cogl_texture_new_from_bitmap (CoglBitmap *bmp,
|
||||||
gint max_waste,
|
gint max_waste,
|
||||||
gboolean auto_mipmap,
|
gboolean auto_mipmap,
|
||||||
CoglPixelFormat internal_format,
|
CoglPixelFormat internal_format)
|
||||||
GError **error)
|
|
||||||
{
|
{
|
||||||
CoglBitmap bmp;
|
|
||||||
CoglTexture *tex;
|
CoglTexture *tex;
|
||||||
|
|
||||||
g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE);
|
|
||||||
|
|
||||||
/* Try loading with imaging backend */
|
|
||||||
if (!_cogl_bitmap_from_file (&bmp, filename, error))
|
|
||||||
{
|
|
||||||
/* Try fallback */
|
|
||||||
if (!_cogl_bitmap_fallback_from_file (&bmp, filename))
|
|
||||||
return COGL_INVALID_HANDLE;
|
|
||||||
else if (error && *error)
|
|
||||||
{
|
|
||||||
g_error_free (*error);
|
|
||||||
*error = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create new texture and fill with loaded data */
|
/* Create new texture and fill with loaded data */
|
||||||
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
|
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
|
||||||
|
|
||||||
@ -1356,8 +1339,9 @@ cogl_texture_new_from_file (const gchar *filename,
|
|||||||
tex->is_foreign = FALSE;
|
tex->is_foreign = FALSE;
|
||||||
tex->auto_mipmap = auto_mipmap;
|
tex->auto_mipmap = auto_mipmap;
|
||||||
|
|
||||||
tex->bitmap = bmp;
|
tex->bitmap = *bmp;
|
||||||
tex->bitmap_owner = TRUE;
|
tex->bitmap_owner = TRUE;
|
||||||
|
bmp->data = NULL;
|
||||||
|
|
||||||
tex->slice_x_spans = NULL;
|
tex->slice_x_spans = NULL;
|
||||||
tex->slice_y_spans = NULL;
|
tex->slice_y_spans = NULL;
|
||||||
@ -1398,6 +1382,30 @@ cogl_texture_new_from_file (const gchar *filename,
|
|||||||
return _cogl_texture_handle_new (tex);
|
return _cogl_texture_handle_new (tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoglHandle
|
||||||
|
cogl_texture_new_from_file (const gchar *filename,
|
||||||
|
gint max_waste,
|
||||||
|
gboolean auto_mipmap,
|
||||||
|
CoglPixelFormat internal_format,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
CoglBitmap *bmp;
|
||||||
|
CoglHandle handle;
|
||||||
|
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE);
|
||||||
|
|
||||||
|
if (!(bmp = cogl_bitmap_new_from_file (filename, error)))
|
||||||
|
return COGL_INVALID_HANDLE;
|
||||||
|
|
||||||
|
handle = cogl_texture_new_from_bitmap (bmp,
|
||||||
|
max_waste,
|
||||||
|
auto_mipmap,
|
||||||
|
internal_format);
|
||||||
|
cogl_bitmap_free (bmp);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
CoglHandle
|
CoglHandle
|
||||||
cogl_texture_new_from_foreign (GLuint gl_handle,
|
cogl_texture_new_from_foreign (GLuint gl_handle,
|
||||||
GLenum gl_target,
|
GLenum gl_target,
|
||||||
|
Loading…
Reference in New Issue
Block a user