1
0
Fork 0
mutter-performance-source/doc/cookbook/examples/textures-crossfade-cogl.c
Elliot Smith 83a8d0b3bb cookbook: Added example code for texture cross-fading
Added simple image viewer which loads image file names
from a directory, displays the first one, then displays
the next in the list with each key press. Uses the
primitive fade front in/fade back out approach.

Also adapted Emmanuele's example code which uses Cogl
to produce a similar effect, but within a single texture.
This code loads two images specified on the command
line and cross-fades between them.
2010-08-18 11:41:32 +01:00

174 lines
5.6 KiB
C

#include <stdlib.h>
#include <clutter/clutter.h>
static gchar *source = NULL;
static gchar *target = NULL;
static guint duration = 1000;
static GOptionEntry entries[] = {
{
"source", 's',
0,
G_OPTION_ARG_FILENAME, &source,
"The source image of the cross-fade", "FILE"
},
{
"target", 't',
0,
G_OPTION_ARG_FILENAME, &target,
"The target image of the cross-fade", "FILE"
},
{
"duration", 'd',
0,
G_OPTION_ARG_INT, &duration,
"The duration of the cross-fade, in milliseconds", "MSECS"
},
{ NULL }
};
static void
_update_progress_cb (ClutterTimeline *timeline,
guint elapsed_msecs,
ClutterTexture *texture)
{
CoglHandle material = clutter_texture_get_cogl_material (texture);
if (material == COGL_INVALID_HANDLE)
return;
/* You should assume that a material can only be modified once, after
* its creation; if you need to modify it later you should use a copy
* instead. Cogl makes copying materials reasonably cheap
*/
CoglHandle copy = cogl_material_copy (material);
gdouble progress = clutter_timeline_get_progress (timeline);
/* Create the constant color to be used when combining the two
* material layers; we use a black color with an alpha component
* depending on the current progress of the timeline
*/
CoglColor constant;
cogl_color_set_from_4ub (&constant, 0x00, 0x00, 0x00, 0xff * progress);
/* This sets the value of the constant color we use when combining
* the two layers
*/
cogl_material_set_layer_combine_constant (copy, 1, &constant);
/* The Texture now owns the material */
clutter_texture_set_cogl_material (texture, copy);
cogl_handle_unref (copy);
clutter_actor_queue_redraw (CLUTTER_ACTOR (texture));
}
static CoglHandle
load_cogl_texture (const char *type,
const char *file)
{
GError *error = NULL;
CoglHandle retval = cogl_texture_new_from_file (file,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY,
&error);
if (error != NULL)
{
g_print ("Unable to load %s image: %s\n", type, error->message);
g_error_free (error);
exit (EXIT_FAILURE);
}
return retval;
}
static int
print_usage_and_exit (const char *exec_name,
int exit_code)
{
g_print ("Usage: %s -s <source> -t <target> [-d <duration>]\n", exec_name);
return exit_code;
}
int
main (int argc, char *argv[])
{
clutter_init_with_args (&argc, &argv,
" - Crossfade", entries,
NULL,
NULL);
if (source == NULL || target == NULL)
return print_usage_and_exit (argv[0], EXIT_FAILURE);
/* Load the source and target images using Cogl, because we need
* to combine them into the same ClutterTexture.
*/
CoglHandle texture_1 = load_cogl_texture ("source", source);
CoglHandle texture_2 = load_cogl_texture ("target", target);
/* sizes of textures */
gfloat source_width, source_height, target_width, target_height;
source_width = cogl_texture_get_width (texture_1);
source_height = cogl_texture_get_height (texture_1);
target_width = cogl_texture_get_width (texture_2);
target_height = cogl_texture_get_height (texture_2);
/* Create a new Cogl material holding the two textures inside two
* separate layers. Layer 0 is the one which will end
* up being visible.
*/
CoglHandle material = cogl_material_new ();
cogl_material_set_layer (material, 1, texture_1);
cogl_material_set_layer (material, 0, texture_2);
/* Set the layer combination description for the second layer; the
* default for Cogl is to simply multiply the layer with the
* precendent one. In this case we interpolate the color for each
* pixel between the pixel value of the previous layer and the
* current one, using the alpha component of a constant color as
* the interpolation factor.
*/
cogl_material_set_layer_combine (material, 1,
"RGBA = INTERPOLATE (PREVIOUS, "
"TEXTURE, "
"CONSTANT[A])",
NULL);
/* The material now owns the two textures */
cogl_handle_unref (texture_1);
cogl_handle_unref (texture_2);
/* Create a Texture and place it in the middle of the stage; then
* assign the material we created earlier to the Texture for painting
* it
*/
ClutterActor *stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "cross-fade");
clutter_actor_set_size (stage, 600, 600);
clutter_actor_show (stage);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
ClutterActor *texture = clutter_texture_new ();
clutter_actor_set_size (texture, source_width, source_height);
clutter_texture_set_cogl_material (CLUTTER_TEXTURE (texture), material);
clutter_actor_add_constraint (texture, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5));
clutter_actor_add_constraint (texture, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5));
clutter_container_add_actor (CLUTTER_CONTAINER (stage), texture);
cogl_handle_unref (material);
/* The timeline will drive the cross-fading */
ClutterTimeline *timeline = clutter_timeline_new (duration);
g_signal_connect (timeline, "new-frame", G_CALLBACK (_update_progress_cb), texture);
/* animate */
clutter_timeline_start (timeline);
clutter_main ();
g_object_unref (timeline);
return EXIT_SUCCESS;
}