cookbook: Add a recipe on how to create sub-textures
Fiddle with Cogl textures to create a new ClutterTexture that only displays a rectangular region of a bigger ClutterTexture.
This commit is contained in:
parent
ad1f1cb741
commit
cbd6e047dd
@ -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 = \
|
||||
|
4
doc/cookbook/examples/.gitignore
vendored
4
doc/cookbook/examples/.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
/animations-rotating
|
||||
/text-shadow
|
||||
/textures-reflection
|
||||
/animations-rotating
|
||||
/textures-split-go
|
||||
/textures-sub-texture
|
||||
|
@ -3,9 +3,11 @@ include $(top_srcdir)/build/autotools/Makefile.am.silent
|
||||
NULL =
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
textures-reflection \
|
||||
text-shadow \
|
||||
animations-rotating \
|
||||
text-shadow \
|
||||
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
|
||||
|
||||
animations_rotating_SOURCES = animations-rotating.c
|
||||
text_shadow_SOURCES = text-shadow.c
|
||||
|
||||
animations_rotating_SOURCE = animations-rotating.c
|
||||
textures_reflection_SOURCES = textures-reflection.c
|
||||
textures_split_go_SOURCES = textures-split-go.c
|
||||
textures_sub_texture_SOURCES = textures-sub-texture.c
|
||||
|
BIN
doc/cookbook/examples/smiley.png
Normal file
BIN
doc/cookbook/examples/smiley.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
184
doc/cookbook/examples/textures-split-go.c
Normal file
184
doc/cookbook/examples/textures-split-go.c
Normal file
@ -0,0 +1,184 @@
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
/* 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;
|
||||
}
|
60
doc/cookbook/examples/textures-sub-texture.c
Normal file
60
doc/cookbook/examples/textures-sub-texture.c
Normal file
@ -0,0 +1,60 @@
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
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;
|
||||
}
|
BIN
doc/cookbook/images/textures-sub-texture.png
Normal file
BIN
doc/cookbook/images/textures-sub-texture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
@ -501,6 +501,142 @@ main (int argc, char *argv[])
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="textures-sub-textures">
|
||||
<title>Creating sub-textures from an existing texture</title>
|
||||
|
||||
<section>
|
||||
<title>Problem</title>
|
||||
|
||||
<para>You want to create a new <type>ClutterTexture</type> that only
|
||||
displays a rectangular sub-region of an existing texture.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Solution</title>
|
||||
|
||||
<para>A possible way of achieving this is to retrieve the
|
||||
<type>CoglHandle</type> of the underlying Cogl texture of the existing
|
||||
<type>ClutterTexture</type>, create a new handle representing the
|
||||
sub-region with <function>cogl_texture_new_from_sub_texture()</function>
|
||||
and finally populate a new <type>ClutterTexture</type> with that handle.
|
||||
</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
*/
|
||||
]]> </programlisting>
|
||||
</informalexample>
|
||||
|
||||
<screenshot>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata format="PNG"
|
||||
fileref="images/textures-sub-texture.png" />
|
||||
</imageobject>
|
||||
<alt>
|
||||
<para>A texture and its sub-texture next to it</para>
|
||||
</alt>
|
||||
</mediaobject>
|
||||
</screenshot>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Discussion</title>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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 <function>cogl_texture_new_from_sub_texture()</function>
|
||||
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.</para>
|
||||
|
||||
<para>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
|
||||
<type>ClutterTexture</type>. You then need to tell the texture to
|
||||
draw from the sub-texture.</para>
|
||||
|
||||
<note><para>The handle you can get from
|
||||
<function>clutter_texture_get_cogl_texture()</function> is effectively
|
||||
the same texture than the first layer of the material retrieved by
|
||||
<function>clutter_texture_get_cogl_material()</function></para></note>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Full example</title>
|
||||
|
||||
<example id="textures-sub-texture">
|
||||
<title>Creating a sub-texture from an existing texture</title>
|
||||
<programlisting
|
||||
><xi:include href="examples/textures-sub-texture.c" parse="text">
|
||||
<xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
|
||||
</xi:include></programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Going further</title>
|
||||
|
||||
<para>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.
|
||||
</para>
|
||||
|
||||
<inlinemediaobject>
|
||||
<videoobject>
|
||||
<videodata fileref="videos/textures-split-go.ogv"/>
|
||||
</videoobject>
|
||||
<alt>
|
||||
<para>Video showing 4 sub-textures being animated</para>
|
||||
</alt>
|
||||
</inlinemediaobject>
|
||||
|
||||
<example id="textures-split-go">
|
||||
<title>Creating a sub-texture from an existing texture</title>
|
||||
<programlisting
|
||||
><xi:include href="examples/textures-split-go.c" parse="text">
|
||||
<xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
|
||||
</xi:include></programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="textures-reflection">
|
||||
<title>Creating a reflection of a texture</title>
|
||||
|
||||
|
BIN
doc/cookbook/videos/textures-split-go.ogv
Normal file
BIN
doc/cookbook/videos/textures-split-go.ogv
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user