mirror of
https://github.com/brl/mutter.git
synced 2024-11-23 00:20:42 -05:00
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.png \
|
||||||
images/actors-opacity-container-affects-opacity.png \
|
images/actors-opacity-container-affects-opacity.png \
|
||||||
images/text-shadow.png \
|
images/text-shadow.png \
|
||||||
|
images/textures-sub-texture.png \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
VIDEO_FILES = \
|
VIDEO_FILES = \
|
||||||
videos/animations-fading-out.ogv \
|
videos/animations-fading-out.ogv \
|
||||||
@ -48,6 +49,7 @@ VIDEO_FILES = \
|
|||||||
videos/animations-rotating-y-centered.ogv \
|
videos/animations-rotating-y-centered.ogv \
|
||||||
videos/animations-rotating-z-centered.ogv \
|
videos/animations-rotating-z-centered.ogv \
|
||||||
videos/animations-rotating-container-reverses-direction.ogv \
|
videos/animations-rotating-container-reverses-direction.ogv \
|
||||||
|
videos/textures-split-go.ogv \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
4
doc/cookbook/examples/.gitignore
vendored
4
doc/cookbook/examples/.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
|
/animations-rotating
|
||||||
/text-shadow
|
/text-shadow
|
||||||
/textures-reflection
|
/textures-reflection
|
||||||
/animations-rotating
|
/textures-split-go
|
||||||
|
/textures-sub-texture
|
||||||
|
@ -3,9 +3,11 @@ include $(top_srcdir)/build/autotools/Makefile.am.silent
|
|||||||
NULL =
|
NULL =
|
||||||
|
|
||||||
noinst_PROGRAMS = \
|
noinst_PROGRAMS = \
|
||||||
textures-reflection \
|
animations-rotating \
|
||||||
text-shadow \
|
text-shadow \
|
||||||
animations-rotating \
|
textures-reflection \
|
||||||
|
textures-split-go \
|
||||||
|
textures-sub-texture \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
@ -27,8 +29,8 @@ AM_CFLAGS = \
|
|||||||
|
|
||||||
AM_LDFLAGS = $(CLUTTER_LIBS)
|
AM_LDFLAGS = $(CLUTTER_LIBS)
|
||||||
|
|
||||||
textures_reflection_SOURCES = textures-reflection.c
|
animations_rotating_SOURCES = animations-rotating.c
|
||||||
|
text_shadow_SOURCES = text-shadow.c
|
||||||
text_shadow_SOURCES = text-shadow.c
|
textures_reflection_SOURCES = textures-reflection.c
|
||||||
|
textures_split_go_SOURCES = textures-split-go.c
|
||||||
animations_rotating_SOURCE = animations-rotating.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>
|
</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">
|
<section id="textures-reflection">
|
||||||
<title>Creating a reflection of a texture</title>
|
<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