diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am index d13cbf195..e0c4ca7ba 100644 --- a/doc/cookbook/Makefile.am +++ b/doc/cookbook/Makefile.am @@ -39,6 +39,15 @@ IMAGE_FILES = \ VIDEO_FILES = \ videos/animations-fading-out.ogv \ videos/animations-fading-in-then-out.ogv \ + videos/animations-rotating-x-minus-45.ogv \ + videos/animations-rotating-y-45.ogv \ + videos/animations-rotating-z-90.ogv \ + videos/animations-rotating-x-minus-180-with-y-minus-96.ogv \ + videos/animations-rotating-x-minus-180-with-z-minus-96.ogv \ + videos/animations-rotating-x-centered.ogv \ + videos/animations-rotating-y-centered.ogv \ + videos/animations-rotating-z-centered.ogv \ + videos/animations-rotating-container-reverses-direction.ogv \ $(NULL) EXTRA_DIST = \ diff --git a/doc/cookbook/animations.xml b/doc/cookbook/animations.xml index 9d6ddbc6e..ee0b61b12 100644 --- a/doc/cookbook/animations.xml +++ b/doc/cookbook/animations.xml @@ -1,7 +1,7 @@ - + Animations @@ -161,7 +161,7 @@ _alpha_ease_in_sextic (ClutterAlpha *alpha, function to it. -
+
Clutter's animation API All of the animation approaches in Clutter use the same @@ -505,4 +505,510 @@ clutter_state_set_state (transitions, "fade-in");
+
+ Rotating an actor + +
+ Problem + + You want to animate rotation of an actor. Some example cases + where you might want to do this: + + + + To rotate an image so it's the right way up for + viewing. + + + To make actors more or less prominent, rotating them + towards or away from the view point. + + + To turn an actor "around" and display different UI + elements "behind" it. + + +
+ +
+ Solution + + Animate one of the rotation-angle-(x|y|z) + properties of the actor. + + The most "obvious" (and probably most commonly used) rotation is + in the z axis (parallel + to the 2D surface of the UI). The other rotation axes + (x and y) + are less obvious, as they rotate the actor in the depth dimension, + "away from" or "towards" the view point. + + Examples of each type of rotation are given below. While the + examples use implicit + animations, it is also possible to use + ClutterAnimator and ClutterState to animate + rotations: see the + full example at the end of this recipe for some + ClutterState code. + + + I've added an inaccurate (but hopefully useful) metaphor to + each rotation axis ("wheel", "letter box", "door"), to make it + easier to remember the effect you get from animating in that axis + (and when the rotation center is inside the actor). + + + Rotating on the z axis ("wheel") + + + + + + + + The above code animating a texture: + + + + + + + Video showing an actor rotating to 90 degrees on the + z axis + + + + By default, the center of the rotation is derived from + the anchor point of the actor; unless you've changed the anchor + point, the default is the top-left corner of the actor. See the + Discussion section below for more about setting the rotation center. + + + An animated rotation moves an actor to + the specified rotation angle; it does not + increment or decrement the actor's current rotation angle by + the amount specified. + + + Rotating on the x axis + ("letter box") + + + + + + + + The above code animating a texture: + + + + + + + Video showing an actor rotating to -45 degrees on the + x axis + + + + Notice how the texture rotates away from the view point, + and also how perspective effects are applied (as the actor is rotating + "into" the depth dimension). + + Rotating on the y axis + ("door") + + + + + + + + The above code animating a texture: + + + + + + + Video showing an actor rotating to 45 degrees on the + y axis + + + + Again, the rotation is into the depth dimension, so + you get perspective effects. + +
+ +
+ Discussion + + It can sometimes be difficult to predict exactly + how a particular rotation animation will appear when applied. + Often the only way to find out is to experiment. However, + the sections below outline some of the most common factors which + affect animated rotations, with the aim of minimising the + experimentation you need to do. + +
+ Setting the rotation center for an animation + + The examples in the previous section used the default + center of rotation for each axis. However, it is possible to + change the rotation center for an axis, in turn changing + the appearance of the animation. + + + Rotation center coordinates are relative to the + actor's coordinates, not to the coordinates of the actor's + container or the stage. + + +
+ Setting a rotation center inside an actor + + You can set the center for rotation on the x or y axes + like this: + + + + + + + + Because z axis rotations are more common, Clutter + provides some convenience functions to set the rotation + center for this axis: + + + + + + + + CLUTTER_GRAVITY_CENTER makes the + center of the actor the rotation center for + the z axis. See the ClutterGravity enumeration for + acceptable values for this parameter. + + + Setting the rotation center for the z axis using gravity + is recommended, as Clutter will automatically recompute the + rotation center if the actor's size changes. For the x and y + axes, you have to do this computation yourself if you + want an actor's center of rotation to stay in the same place + if it is resized. + + + Rotation on the x axis around an actor's center: + + + + + + + Video showing an actor rotating around its center + on the x axis + + + + Rotation on the y axis around an actor's center: + + + + + + + Video showing an actor rotating around its center + on the y axis + + + + Rotation on the z axis around an actor's center: + + + + + + + Video showing an actor rotating around its center + on the z axis + + + +
+ +
+ Setting the rotation center outside an actor + + Rather than rotating the actor around a point inside + itself, the rotation center can be moved to a position + outside the actor. (In the case of the z axis, + any rotation center setting is outside the actor as its depth + is 0.) When animated, the actor will describe an arc around the + rotation center, as if it's swinging from an invisible thread. + + The same code as shown above can be used to set the + rotation center: just set the rotation center coordinates to + negative numbers (outside the actor). However, you can't use the + gravity functions if the rotation center falls outside an actor. + + For example, here's a rotation to -180 degrees in the x + axis, with the y rotation center set to -96 (the same as the height + of the actor): + + + + + + + Video showing an actor rotating to -180 degrees on + the x axis with y rotation center set to -96 + + + + Similarly, moving the z rotation center (for a rotation + in the x or y axis) will cause the actor to swing "into" or "out + of" the UI. Its final apparent size may be different, as it could + reach a different depth in the UI by the end of the + animation. + + For example, here's a rotation to -180 in the x axis, + with the z rotation center set to -96 (the same as the height + of the actor): + + + + + + + Video showing an actor rotating to -180 degrees on + the x axis with z rotation center set to -96 + + + + The apparent final size of the actor is reduced, as it + has rotated away from the view point. + +
+ +
+ +
+ Direction of rotation + + The apparent direction of an animated rotation depends on + two things: + + + + Whether the angle of rotation is positive or negative. + + + The rotation of the container(s) the actor is inside. + + + + In the case of the sign of the rotation, here's what + happens for each axis and rotation angle sign (positive or + negative). + + + + + Axis + Sign of rotation angle + Effect on actor + + + + + z + + + + Clockwise spin about the x,y center of + rotation. + + + + z + - + + Anti-clockwise spin about the x,y + center of rotation. + + + + x + + + + The top swings away from the view point and the + bottom swings towards it. If y rotation center == 0, + the top is fixed; if y rotation center == the actor's + height, the bottom is fixed. + + + + x + - + + The bottom swings away from the view point and the + top swings towards it. If y rotation center == 0, + the top is fixed; if y rotation center == the actor's + height, the bottom is fixed. + + + + y + + + + The right-hand side swings away from the view point and + the left-hand side swings towards it. When x rotation + center == 0, the left-hand side if fixed; when x + rotation center == the actor's width, the right-hand + side is fixed. + + + + y + - + + The right-hand side swings towards the view point and + the left-hand side swings away from it. When x rotation + center == 0, the left-hand side if fixed; when x + rotation center == the actor's width, the right-hand + side is fixed. + + + + + + If an actor's container is rotated, this may affect the + appearance of rotation animations applied to the actor. In + particular, if an actor's container has been rotated + by 180 degrees in one axis, the direction of that actor's + rotation may appear reversed. + + For example, the video below shows an actor being animated + to 90 degrees on the z axis, then back to 0 degrees; + the actor's container is then rotated by 180 degrees in the y + axis; then the same rotation 90 degree rotation is applied + to the actor again. Note that the first time the animation + is applied, the rotation is clockwise; but the second time (as + the actor is effectively "reversed"), it is anti-clockwise. + + + + + + + Video showing how an actor's apparent rotation is + affected by the rotation of its parent + + + +
+ +
+ Apparent vs. actual rotation + + There is a difference between an actor's apparent + rotation (how much an actor appears to be rotating, from the + perspective of someone looking at the UI) and its + actual rotation (how much that actor is + really rotating). + + For example, if you rotate an actor and its container + simultaneously, each by 90 degrees in the same direction, the + actor will appear to have rotated by 180 degrees by the end + of the animation. However, calling the + clutter_actor_get_rotation() function + for that axis on the actor still returns a rotation of 90 + degrees. +
+ +
+ Orientation of rotation axes + + The rotation axes remain fixed in the same place on + the actor regardless of its rotation, even though from the viewer's + perspective they may appear to move. + + For example, when rotation in the z axis is 0 degrees, + the actor's x axis is horizontal (across the UI) from both the + actor's and the viewer's perspective. However, if you rotate the + actor by 90 degrees in the z axis, the x axis is now vertical from + the viewer's perspective, but still horizontal + across the actor from the actor's + perspective. +
+ +
+ +
+ Full example + + + Rotating an actor around x, y, and z axes using + <type>ClutterState</type> + + + a code sample should be here... but isn't + + + +
+ +
+ diff --git a/doc/cookbook/clutter-cookbook.xml.in b/doc/cookbook/clutter-cookbook.xml.in index 646d942a1..6f4b476d1 100644 --- a/doc/cookbook/clutter-cookbook.xml.in +++ b/doc/cookbook/clutter-cookbook.xml.in @@ -151,7 +151,7 @@ VIDEO_FILES = \ - + Video showing an actor fading in then out using @@ -168,6 +168,101 @@ VIDEO_FILES = \ + + To include a full code sample in a recipe (which can + be compiled into a runnable binary), do the following: + + + + Create a C code file in the + <clutter source>/doc/cookbook/examples + directory. It should be a standalone C application (with + a main() etc.). The filename should be + in the format + <section>-<recipe>.c; you + can add an optional identifier to the end if you have more + than one example for a recipe. + + If you want to load image files into the application + (e.g. to demonstrate something with a texture), you can use + the TESTS_DATA_DIR variable in your C + code to reuse images in the Clutter tests + directory; this will be replaced with + <clutter source>/tests/data + during the build. For example: + + + + + + + + + + Edit Makefile.am + in the cookbook/examples directory + so that the build recognises the new code; e.g. if + your C source file were called + fooing-barring.c you would do: + + + + + + + + + Note the second line is a new one to tell the + build where the source file is for your example. + + + + + Add a section at the end of your recipe which + XIncludes the sample code, e.g.: + + + + + Full example + + + Fooing with a bar + + + a code sample should be here... but isn't + + + +
+]]> + + + + + The <xi:include> element + should be aligned to the left-hand margin of the text + (no whitespace on the line before it), to prevent any + stray whitespace appearing in the program listing. + + + + + diff --git a/doc/cookbook/examples/.gitignore b/doc/cookbook/examples/.gitignore index 7f90480bd..b07d1113b 100644 --- a/doc/cookbook/examples/.gitignore +++ b/doc/cookbook/examples/.gitignore @@ -1,2 +1,3 @@ /text-shadow /textures-reflection +/animations-rotating diff --git a/doc/cookbook/examples/Makefile.am b/doc/cookbook/examples/Makefile.am index 5353a9d93..1ac230b19 100644 --- a/doc/cookbook/examples/Makefile.am +++ b/doc/cookbook/examples/Makefile.am @@ -5,6 +5,7 @@ NULL = noinst_PROGRAMS = \ textures-reflection \ text-shadow \ + animations-rotating \ $(NULL) INCLUDES = \ @@ -29,3 +30,5 @@ AM_LDFLAGS = $(CLUTTER_LIBS) textures_reflection_SOURCES = textures-reflection.c text_shadow_SOURCES = text-shadow.c + +animations_rotating_SOURCE = animations-rotating.c diff --git a/doc/cookbook/examples/animations-rotating.c b/doc/cookbook/examples/animations-rotating.c new file mode 100644 index 000000000..23985e72e --- /dev/null +++ b/doc/cookbook/examples/animations-rotating.c @@ -0,0 +1,136 @@ +#include + +#define ROTATION_ANGLE 75.0 +#define DURATION 2000 + +static void +_set_next_state (ClutterState *transitions, + gpointer user_data) +{ + const gchar *current = clutter_state_get_state (transitions); + gchar *next_state = "start"; + + if (g_strcmp0 (current, "start") == 0) + next_state = "x-cw"; + else if (g_strcmp0 (current, "x-cw") == 0) + next_state = "x-ccw"; + else if (g_strcmp0 (current, "x-ccw") == 0) + next_state = "x-after"; + else if (g_strcmp0 (current, "x-after") == 0) + next_state = "y-cw"; + else if (g_strcmp0 (current, "y-cw") == 0) + next_state = "y-ccw"; + else if (g_strcmp0 (current, "y-ccw") == 0) + next_state = "y-after"; + else if (g_strcmp0 (current, "y-after") == 0) + next_state = "z-cw"; + else if (g_strcmp0 (current, "z-cw") == 0) + next_state = "z-ccw"; + + clutter_state_set_state (transitions, next_state); +} + +int +main (int argc, char *argv[]) +{ + ClutterActor *stage; + ClutterActor *texture; + ClutterState *transitions; + GError *error = NULL; + gfloat texture_width, texture_height; + + clutter_init (&argc, &argv); + + stage = clutter_stage_get_default (); + g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); + + texture = clutter_texture_new (); + 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_texture_set_sync_size (CLUTTER_TEXTURE (texture), TRUE); + clutter_texture_set_from_file (CLUTTER_TEXTURE (texture), + TESTS_DATA_DIR "/redhand.png", + &error); + + if (error != NULL) + { + g_error ("Problem loading image into texture - %s", error->message); + g_error_free (error); + return 1; + } + + clutter_actor_get_size (texture, &texture_width, &texture_height); + clutter_actor_set_size (stage, texture_width * 2, texture_height * 2); + + /* set all centres of rotation to the centre of the texture */ + clutter_actor_set_rotation (texture, + CLUTTER_X_AXIS, + 0.0, + texture_width * 0.5, + texture_height * 0.5, + 0.0); + clutter_actor_set_rotation (texture, + CLUTTER_Y_AXIS, + 0.0, + texture_width * 0.5, + texture_height * 0.5, + 0.0); + clutter_actor_set_z_rotation_from_gravity (texture, 0.0, CLUTTER_GRAVITY_CENTER); + + clutter_container_add_actor (CLUTTER_CONTAINER (stage), texture); + + /* set up the animations */ + transitions = clutter_state_new (); + + clutter_state_set (transitions, NULL, "start", + texture, "rotation-angle-x", CLUTTER_LINEAR, 0.0, + texture, "rotation-angle-y", CLUTTER_LINEAR, 0.0, + texture, "rotation-angle-z", CLUTTER_LINEAR, 0.0, + NULL); + clutter_state_set (transitions, NULL, "x-cw", + texture, "rotation-angle-x", CLUTTER_LINEAR, ROTATION_ANGLE, + NULL); + clutter_state_set (transitions, NULL, "x-ccw", + texture, "rotation-angle-x", CLUTTER_LINEAR, -ROTATION_ANGLE, + NULL); + clutter_state_set (transitions, NULL, "x-after", + texture, "rotation-angle-x", CLUTTER_LINEAR, 0.0, + NULL); + clutter_state_set (transitions, NULL, "y-cw", + texture, "rotation-angle-y", CLUTTER_LINEAR, ROTATION_ANGLE, + NULL); + clutter_state_set (transitions, NULL, "y-ccw", + texture, "rotation-angle-y", CLUTTER_LINEAR, -ROTATION_ANGLE, + NULL); + clutter_state_set (transitions, NULL, "y-after", + texture, "rotation-angle-y", CLUTTER_LINEAR, 0.0, + NULL); + clutter_state_set (transitions, NULL, "z-cw", + texture, "rotation-angle-z", CLUTTER_LINEAR, ROTATION_ANGLE, + NULL); + clutter_state_set (transitions, NULL, "z-ccw", + texture, "rotation-angle-z", CLUTTER_LINEAR, -ROTATION_ANGLE, + NULL); + clutter_state_set_duration (transitions, NULL, NULL, DURATION); + clutter_state_set_duration (transitions, "start", NULL, DURATION * 0.5); + clutter_state_set_duration (transitions, NULL, "start", DURATION * 0.5); + clutter_state_set_duration (transitions, NULL, "x-after", DURATION * 0.5); + clutter_state_set_duration (transitions, NULL, "y-after", DURATION * 0.5); + + clutter_state_warp_to_state (transitions, "start"); + + g_signal_connect (transitions, + "completed", + G_CALLBACK (_set_next_state), + NULL); + + clutter_state_set_state (transitions, "x-cw"); + + clutter_actor_show (stage); + + clutter_main (); + + return 0; +} diff --git a/doc/cookbook/videos/animations-rotating-container-reverses-direction.ogv b/doc/cookbook/videos/animations-rotating-container-reverses-direction.ogv new file mode 100644 index 000000000..9d41bc3d3 Binary files /dev/null and b/doc/cookbook/videos/animations-rotating-container-reverses-direction.ogv differ diff --git a/doc/cookbook/videos/animations-rotating-x-centered.ogv b/doc/cookbook/videos/animations-rotating-x-centered.ogv new file mode 100644 index 000000000..dc1fa83ca Binary files /dev/null and b/doc/cookbook/videos/animations-rotating-x-centered.ogv differ diff --git a/doc/cookbook/videos/animations-rotating-x-minus-180-with-y-minus-96.ogv b/doc/cookbook/videos/animations-rotating-x-minus-180-with-y-minus-96.ogv new file mode 100644 index 000000000..4acaaafd3 Binary files /dev/null and b/doc/cookbook/videos/animations-rotating-x-minus-180-with-y-minus-96.ogv differ diff --git a/doc/cookbook/videos/animations-rotating-x-minus-180-with-z-minus-96.ogv b/doc/cookbook/videos/animations-rotating-x-minus-180-with-z-minus-96.ogv new file mode 100644 index 000000000..74a4464d8 Binary files /dev/null and b/doc/cookbook/videos/animations-rotating-x-minus-180-with-z-minus-96.ogv differ diff --git a/doc/cookbook/videos/animations-rotating-x-minus-45.ogv b/doc/cookbook/videos/animations-rotating-x-minus-45.ogv new file mode 100644 index 000000000..827f3e4df Binary files /dev/null and b/doc/cookbook/videos/animations-rotating-x-minus-45.ogv differ diff --git a/doc/cookbook/videos/animations-rotating-y-45.ogv b/doc/cookbook/videos/animations-rotating-y-45.ogv new file mode 100644 index 000000000..483284c1a Binary files /dev/null and b/doc/cookbook/videos/animations-rotating-y-45.ogv differ diff --git a/doc/cookbook/videos/animations-rotating-y-centered.ogv b/doc/cookbook/videos/animations-rotating-y-centered.ogv new file mode 100644 index 000000000..1e37b8fb4 Binary files /dev/null and b/doc/cookbook/videos/animations-rotating-y-centered.ogv differ diff --git a/doc/cookbook/videos/animations-rotating-z-90.ogv b/doc/cookbook/videos/animations-rotating-z-90.ogv new file mode 100644 index 000000000..24192eac3 Binary files /dev/null and b/doc/cookbook/videos/animations-rotating-z-90.ogv differ diff --git a/doc/cookbook/videos/animations-rotating-z-centered.ogv b/doc/cookbook/videos/animations-rotating-z-centered.ogv new file mode 100644 index 000000000..0ead686ff Binary files /dev/null and b/doc/cookbook/videos/animations-rotating-z-centered.ogv differ