diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am index 7239f91c7..e2956317d 100644 --- a/doc/cookbook/Makefile.am +++ b/doc/cookbook/Makefile.am @@ -35,6 +35,7 @@ IMAGE_FILES = \ images/actors-opacity.png \ images/actors-opacity-container-affects-opacity.png \ images/text-shadow.png \ + images/textures-sub-texture.png \ $(NULL) VIDEO_FILES = \ videos/animations-fading-out.ogv \ @@ -48,6 +49,7 @@ VIDEO_FILES = \ videos/animations-rotating-y-centered.ogv \ videos/animations-rotating-z-centered.ogv \ videos/animations-rotating-container-reverses-direction.ogv \ + videos/textures-split-go.ogv \ $(NULL) EXTRA_DIST = \ diff --git a/doc/cookbook/examples/.gitignore b/doc/cookbook/examples/.gitignore index b07d1113b..af4ba9caf 100644 --- a/doc/cookbook/examples/.gitignore +++ b/doc/cookbook/examples/.gitignore @@ -1,3 +1,5 @@ +/animations-rotating /text-shadow /textures-reflection -/animations-rotating +/textures-split-go +/textures-sub-texture diff --git a/doc/cookbook/examples/Makefile.am b/doc/cookbook/examples/Makefile.am index 1ac230b19..662786ead 100644 --- a/doc/cookbook/examples/Makefile.am +++ b/doc/cookbook/examples/Makefile.am @@ -3,9 +3,11 @@ include $(top_srcdir)/build/autotools/Makefile.am.silent NULL = noinst_PROGRAMS = \ - textures-reflection \ + animations-rotating \ text-shadow \ - animations-rotating \ + textures-reflection \ + textures-split-go \ + textures-sub-texture \ $(NULL) INCLUDES = \ @@ -27,8 +29,8 @@ AM_CFLAGS = \ AM_LDFLAGS = $(CLUTTER_LIBS) -textures_reflection_SOURCES = textures-reflection.c - -text_shadow_SOURCES = text-shadow.c - -animations_rotating_SOURCE = animations-rotating.c +animations_rotating_SOURCES = animations-rotating.c +text_shadow_SOURCES = text-shadow.c +textures_reflection_SOURCES = textures-reflection.c +textures_split_go_SOURCES = textures-split-go.c +textures_sub_texture_SOURCES = textures-sub-texture.c diff --git a/doc/cookbook/examples/smiley.png b/doc/cookbook/examples/smiley.png new file mode 100644 index 000000000..5bcc67a2d Binary files /dev/null and b/doc/cookbook/examples/smiley.png differ diff --git a/doc/cookbook/examples/textures-split-go.c b/doc/cookbook/examples/textures-split-go.c new file mode 100644 index 000000000..940e9f1cc --- /dev/null +++ b/doc/cookbook/examples/textures-split-go.c @@ -0,0 +1,184 @@ +#include + +/* Context will be used to carry interesting variables between functions */ +typedef struct +{ + ClutterActor *sub_no, *sub_ne, *sub_so, *sub_se; + gfloat image_width, image_height; +} Context; + +/* Here, we animate the texture to go way by giving the new coordinates + * outside of the stage. We rotate the sub-textures around their anchor + * point (set in setup_sub() as well, it looks cool. */ +static gboolean +go_away (gpointer data) +{ + Context *context = data; + + clutter_actor_animate (context->sub_no, CLUTTER_EASE_OUT_CUBIC, 1500, + "x", -context->image_width, + "y", -context->image_height, + "rotation-angle-z", 2000., + NULL); + clutter_actor_animate (context->sub_ne, CLUTTER_EASE_OUT_CUBIC, 1500, + "x", +context->image_width, + "y", -context->image_height, + "rotation-angle-z", 2000., + NULL); + clutter_actor_animate (context->sub_so, CLUTTER_EASE_OUT_CUBIC, 1500, + "x", -context->image_width, + "y", +context->image_height, + "rotation-angle-z", 2000., + NULL); + clutter_actor_animate (context->sub_se, CLUTTER_EASE_OUT_CUBIC, 1500, + "x", -context->image_width, + "y", +context->image_height, + "rotation-angle-z", 2000., + NULL); + return FALSE; /* remove the timeout source */ +} + +/* We split the four sub-textures faking to be the big texture, moving them + * away by 10 pixels in each direction */ +static gboolean +split (gpointer data) +{ + Context *context = data; + gfloat x, y; + + clutter_actor_get_position (context->sub_no, &x, &y); + clutter_actor_animate (context->sub_no, CLUTTER_EASE_OUT_CUBIC, 300, + "x", x - 10, + "y", y - 10, + NULL); + clutter_actor_get_position (context->sub_ne, &x, &y); + clutter_actor_animate (context->sub_ne, CLUTTER_EASE_OUT_CUBIC, 300, + "x", x + 10, + "y", y - 10, + NULL); + clutter_actor_get_position (context->sub_so, &x, &y); + clutter_actor_animate (context->sub_so, CLUTTER_EASE_OUT_CUBIC, 300, + "x", x - 10, + "y", y + 10, + NULL); + clutter_actor_get_position (context->sub_se, &x, &y); + clutter_actor_animate (context->sub_se, CLUTTER_EASE_OUT_CUBIC, 300, + "x", x + 10, + "y", y + 10, + NULL); + + /* In 500ms the textures will flee! */ + g_timeout_add (500, go_away, context); + + return FALSE; /* remove the timeout source */ +} + +static ClutterActor * +setup_sub (CoglHandle texture, + gint image_width, + gint image_height, + gint t_x, + gint t_y, + gint t_width, + gint t_height) +{ + CoglHandle sub_texture; + ClutterActor *sub_image; + + /* Create a new sub-texture from textures */ + sub_texture = cogl_texture_new_from_sub_texture (texture, + t_x, t_y, + t_width, t_height); + + /* Create the corresponding ClutterTexture */ + sub_image = g_object_new (CLUTTER_TYPE_TEXTURE, + "cogl-texture", sub_texture, + NULL); + + /* Set the anchor point in the middle of each sub_image so the position and + * rotation of the textures are relative to that point */ + clutter_actor_set_anchor_point (sub_image, image_width / 4, image_height / 4); + + return sub_image; +} + +#define IMAGE "smiley.png" + +int +main (int argc, + char **argv) +{ + gfloat image_width, image_height, stage_width, stage_height; + ClutterActor *stage, *image; + GError *error = NULL; + CoglHandle texture; + Context context; + + clutter_init (NULL, NULL); + + stage = clutter_stage_get_default (); + clutter_actor_get_size (stage, &stage_width, &stage_height); + clutter_stage_set_title (CLUTTER_STAGE (stage), "Animate sub-textures"); + + /* Load smiley.png, creating a new ClutterTexture, get its size and the + * Cogl texture handle */ + image = clutter_texture_new_from_file (IMAGE, &error); + if (error != NULL) + { + g_warning ("Could not load " IMAGE ": %s", error->message); + g_clear_error (&error); + return 1; + } + clutter_actor_get_size (image, &image_width, &image_height); + texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (image)); + + /* Create four sub-textures from image, actually splitting the image in + * four */ + context.sub_no = setup_sub (texture, image_width, image_height, + 0, 0, image_width / 2 , image_width / 2); + context.sub_ne = setup_sub (texture, image_width, image_height, + image_width / 2 , 0, + image_width / 2, image_width / 2); + context.sub_so = setup_sub (texture, image_width, image_height, + 0.f, image_width / 2, + image_width / 2, image_width / 2); + context.sub_se = setup_sub (texture, image_width, image_height, + image_width / 2, image_width / 2, + image_width / 2, image_width / 2); + + /* We don't need the image anymore as we won't display it and as + * cogl_texture_new_from_sub_texture() keeps a reference to the underlying + * texture ressource */ + g_object_unref (image); + + /* Position the sub-texures in the middle of the screen, recreating the + * original texture */ + clutter_actor_set_position (context.sub_no, + stage_width / 2 - image_width / 4, + stage_height / 2 - image_height / 4); + clutter_actor_set_position (context.sub_ne, + stage_width / 2 + image_width / 4, + stage_height / 2 - image_height / 4); + clutter_actor_set_position (context.sub_so, + stage_width / 2 - image_width / 4, + stage_height / 2 + image_height / 4); + clutter_actor_set_position (context.sub_se, + stage_width / 2 + image_width / 4, + stage_height / 2 + image_height / 4); + + /* Add the four sub-textures to the stage */ + clutter_container_add (CLUTTER_CONTAINER (stage), context.sub_no, + context.sub_ne, context.sub_so, context.sub_se, NULL); + + clutter_actor_show_all (stage); + + context.image_width = image_width; + context.image_height = image_height; + + /* In two seconds, we'll split the texture! */ + g_timeout_add_seconds (2, split, &context); + + clutter_main (); + + return 0; +} diff --git a/doc/cookbook/examples/textures-sub-texture.c b/doc/cookbook/examples/textures-sub-texture.c new file mode 100644 index 000000000..0d6075cdb --- /dev/null +++ b/doc/cookbook/examples/textures-sub-texture.c @@ -0,0 +1,60 @@ +#include + +int +main (int argc, char **argv) +{ + ClutterActor *stage, *image, *sub_image; + CoglHandle texture, sub_texture; + gfloat image_width, image_height; + + /* Initialize Clutter */ + clutter_init (NULL, NULL); + + /* Get the default stage */ + stage = clutter_stage_get_default (); + clutter_stage_set_title (CLUTTER_STAGE (stage), "Sub-texture"); + + /* Create a new ClutterTexture that shows smiley.png */ + image = clutter_texture_new_from_file ("smiley.png", NULL); + clutter_actor_get_size (image, &image_width, &image_height); + clutter_actor_set_size (stage, + image_width * 3 / 2 + 30, + image_height + 20); + + /* Grab the CoglHandle of the underlying Cogl texture */ + texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (image)); + + /* Create a new Cogl texture from the handle above. That new texture is a + * rectangular region from image, more precisely the north ouest corner + * of the image */ + sub_texture = cogl_texture_new_from_sub_texture (texture, + 0, 0, + image_width / 2, + image_height / 2); + + /* Finally, use the newly created Cogl texture to feed a new ClutterTexture + * and thus create a new actor that displays sub_texture */ + sub_image = clutter_texture_new (); + clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (sub_image), sub_texture); + + /* + * You could have used the more straightforward g_object_new() function that + * can create an object and set some properties on it at the same time: + * sub_image = g_object_new (CLUTTER_TYPE_TEXTURE, + * "cogl-texture", sub_texture, + * NULL); + */ + + /* Put the original image at (10,10) and the new sub image next to it */ + clutter_actor_set_position (image, 10, 10); + clutter_actor_set_position (sub_image, 20 + image_width, 10); + + /* Add both ClutterTexture to the stage */ + clutter_container_add (CLUTTER_CONTAINER (stage), image, sub_image, NULL); + + clutter_actor_show_all (stage); + + clutter_main (); + + return 0; +} diff --git a/doc/cookbook/images/textures-sub-texture.png b/doc/cookbook/images/textures-sub-texture.png new file mode 100644 index 000000000..5650a8fc0 Binary files /dev/null and b/doc/cookbook/images/textures-sub-texture.png differ diff --git a/doc/cookbook/textures.xml b/doc/cookbook/textures.xml index c3ab4b0d2..56b661d7d 100644 --- a/doc/cookbook/textures.xml +++ b/doc/cookbook/textures.xml @@ -501,6 +501,142 @@ main (int argc, char *argv[]) +
+ Creating sub-textures from an existing texture + +
+ Problem + + You want to create a new ClutterTexture that only + displays a rectangular sub-region of an existing texture. +
+ +
+ Solution + + A possible way of achieving this is to retrieve the + CoglHandle of the underlying Cogl texture of the existing + ClutterTexture, create a new handle representing the + sub-region with cogl_texture_new_from_sub_texture() + and finally populate a new ClutterTexture with that handle. + + + + + + + + + + + + + + A texture and its sub-texture next to it + + + + +
+ +
+ Discussion + + The key of this recipe is the Cogl handle that represents the + underlying texture, the actual array of pixels the GPU will use + when it's told to texture geometry. + + From this handle, it's possible to create a new texture handle + that represents a rectangular region of the former texture. To do this + one must call cogl_texture_new_from_sub_texture() + with the position and size of the said region. The interesting bit + about this function is that, when drawing either with the original + texture or with the new one, it's still the same GPU resource (pixels) + being used, meaning that creating a sub-texture doesn't use extra GPU + memory. + + Once the sub-texture handle is created, the next step is + to create a new actor that will be able to draw it, namely a new + ClutterTexture. You then need to tell the texture to + draw from the sub-texture. + + The handle you can get from + clutter_texture_get_cogl_texture() is effectively + the same texture than the first layer of the material retrieved by + clutter_texture_get_cogl_material() + +
+ +
+ Full example + + + Creating a sub-texture from an existing texture + + FIXME: MISSING XINCLUDE CONTENT + + +
+ +
+ Going further + + Now that we know how to create sub-textures, it's time to make + something a bit more shiny with them. Let's animate them! In case you + have not heard about implicit animations in Clutter yet, it's a good + time to have a look at the animation section of this cookbook. + + + + + + + + Video showing 4 sub-textures being animated + + + + + Creating a sub-texture from an existing texture + + FIXME: MISSING XINCLUDE CONTENT + + +
+ +
+
Creating a reflection of a texture diff --git a/doc/cookbook/videos/textures-split-go.ogv b/doc/cookbook/videos/textures-split-go.ogv new file mode 100644 index 000000000..b9e9e8da7 Binary files /dev/null and b/doc/cookbook/videos/textures-split-go.ogv differ