Compare commits

...

2 Commits

Author SHA1 Message Date
Emmanuele Bassi b0c2d81014 Snapshot/WIP 2012-09-01 14:24:43 +01:00
Emmanuele Bassi afc797e196 Add Clutter.Matrix.determinant()
A simple method that computes the determinant of a 4x4 3D matrix.
2012-08-31 18:45:58 +01:00
8 changed files with 524 additions and 37 deletions

View File

@ -1054,6 +1054,9 @@ static inline void clutter_actor_set_margin_internal (ClutterActor *self,
gfloat margin,
GParamSpec *pspec);
static void clutter_actor_set_child_transform_internal (ClutterActor *self,
const ClutterMatrix *transform);
/* Helper macro which translates by the anchor coord, applies the
given transformation and then translates back */
#define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
@ -4224,6 +4227,7 @@ _clutter_actor_get_transform_info (ClutterActor *self)
info = g_slice_new (ClutterTransformInfo);
*info = default_transform_info;
clutter_matrix_init_identity (&info->child_transform);
g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
info,
@ -7196,7 +7200,8 @@ clutter_actor_class_init (ClutterActorClass *klass)
P_("Children transformation matrix"),
CLUTTER_TYPE_MATRIX,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
G_PARAM_STATIC_STRINGS |
CLUTTER_PARAM_ANIMATABLE);
/**
* ClutterActor:child-transform-set:
@ -14628,6 +14633,10 @@ clutter_actor_set_animatable_property (ClutterActor *actor,
pspec);
break;
case PROP_CHILD_TRANSFORM:
clutter_actor_set_child_transform_internal (actor, g_value_get_boxed (value));
break;
default:
g_object_set_property (obj, pspec->name, value);
break;
@ -18624,6 +18633,9 @@ _clutter_actor_create_transition (ClutterActor *actor,
*/
if (info->cur_state->easing_duration == 0)
{
CLUTTER_NOTE (ANIMATION, "Easing duration=0, immediate set for '%s::%s'",
_clutter_actor_get_debug_name (actor),
pspec->name);
clutter_actor_set_animatable_property (actor,
pspec->param_id,
&final,
@ -19930,6 +19942,35 @@ done:
g_ptr_array_free (event_tree, TRUE);
}
static void
clutter_actor_set_child_transform_internal (ClutterActor *self,
const ClutterMatrix *transform)
{
ClutterTransformInfo *info = _clutter_actor_get_transform_info (self);
ClutterActorIter iter;
ClutterActor *child;
GObject *obj;
gboolean was_set = info->child_transform_set;
clutter_matrix_init_from_matrix (&info->child_transform, transform);
/* if it's the identity matrix, we need to toggle the boolean flag */
info->child_transform_set = !cogl_matrix_is_identity (transform);
/* we need to reset the transform_valid flag on each child */
clutter_actor_iter_init (&iter, self);
while (clutter_actor_iter_next (&iter, &child))
child->priv->transform_valid = FALSE;
clutter_actor_queue_redraw (self);
obj = G_OBJECT (self);
g_object_notify_by_pspec (obj, obj_props[PROP_CHILD_TRANSFORM]);
if (was_set != info->child_transform_set)
g_object_notify_by_pspec (obj, obj_props[PROP_CHILD_TRANSFORM_SET]);
}
/**
* clutter_actor_set_child_transform:
* @self: a #ClutterActor
@ -19947,32 +19988,21 @@ void
clutter_actor_set_child_transform (ClutterActor *self,
const ClutterMatrix *transform)
{
ClutterTransformInfo *info;
ClutterActorIter iter;
ClutterActor *child;
GObject *obj;
const ClutterTransformInfo *info;
ClutterMatrix new_transform;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
info = _clutter_actor_get_transform_info (self);
info = _clutter_actor_get_transform_info_or_defaults (self);
if (transform != NULL)
clutter_matrix_init_from_matrix (&info->child_transform, transform);
clutter_matrix_init_from_matrix (&new_transform, transform);
else
clutter_matrix_init_identity (&info->child_transform);
clutter_matrix_init_identity (&new_transform);
info->child_transform_set = transform != NULL;
/* we need to reset the transform_valid flag on each child */
clutter_actor_iter_init (&iter, self);
while (clutter_actor_iter_next (&iter, &child))
child->priv->transform_valid = FALSE;
clutter_actor_queue_redraw (self);
obj = G_OBJECT (self);
g_object_notify_by_pspec (obj, obj_props[PROP_CHILD_TRANSFORM]);
g_object_notify_by_pspec (obj, obj_props[PROP_CHILD_TRANSFORM_SET]);
_clutter_actor_create_transition (self, obj_props[PROP_CHILD_TRANSFORM],
&info->child_transform,
&new_transform);
}
/**

View File

@ -284,6 +284,53 @@ clutter_vertex_equal (const ClutterVertex *vertex_a,
fabsf (vertex_a->z - vertex_b->z) < FLOAT_EPSILON;
}
float
clutter_vertex_length (const ClutterVertex *vertex)
{
return sqrtf (vertex->x * vertex->x + vertex->y * vertex->y + vertex->z * vertex->z);
}
void
clutter_vertex_normalize (ClutterVertex *vertex)
{
float factor = clutter_vertex_length (vertex);
if (factor == 0.f)
return;
vertex->x /= factor;
vertex->y /= factor;
vertex->z /= factor;
}
float
clutter_vertex_dot (const ClutterVertex *v1,
const ClutterVertex *v2)
{
return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
}
void
clutter_vertex_cross (const ClutterVertex *v1,
const ClutterVertex *v2,
ClutterVertex *res)
{
res->x = v1->y * v2->z - v2->y * v1->z;
res->y = v1->z * v2->x - v2->z * v1->x;
res->z = v1->x * v2->y - v2->x * v1->y;
}
static void
clutter_vertex_interpolate (const ClutterVertex *a,
const ClutterVertex *b,
double progress,
ClutterVertex *res)
{
res->x = a->x + (b->x - a->x) * progress;
res->y = a->y + (b->y - a->y) * progress;
res->z = a->z + (b->z - a->z) * progress;
}
static gboolean
clutter_vertex_progress (const GValue *a,
const GValue *b,
@ -294,9 +341,7 @@ clutter_vertex_progress (const GValue *a,
const ClutterVertex *bv = g_value_get_boxed (b);
ClutterVertex res;
res.x = av->x + (bv->x - av->x) * progress;
res.y = av->y + (bv->y - av->y) * progress;
res.z = av->z + (bv->z - av->z) * progress;
clutter_vertex_interpolate (av, bv, progress, &res);
g_value_set_boxed (retval, &res);
@ -1280,12 +1325,75 @@ clutter_rect_progress (const GValue *a,
static gpointer
clutter_matrix_copy (gpointer data)
{
return g_memdup (data, sizeof (ClutterMatrix));
return cogl_matrix_copy (data);
}
G_DEFINE_BOXED_TYPE (ClutterMatrix, clutter_matrix,
clutter_matrix_copy,
clutter_matrix_free)
static gboolean
clutter_matrix_progress (const GValue *a,
const GValue *b,
gdouble progress,
GValue *retval)
{
const ClutterMatrix *matrix1 = g_value_get_boxed (a);
const ClutterMatrix *matrix2 = g_value_get_boxed (b);
ClutterVertex scale1 = CLUTTER_VERTEX_INIT (1.f, 1.f, 1.f);
float shear1[3] = { 0.f, 0.f, 0.f };
ClutterVertex rotate1 = CLUTTER_VERTEX_INIT_ZERO;
ClutterVertex translate1 = CLUTTER_VERTEX_INIT_ZERO;
ClutterVertex4 perspective1 = { 0.f, 0.f, 0.f, 0.f };
ClutterVertex scale2 = CLUTTER_VERTEX_INIT (1.f, 1.f, 1.f);
float shear2[3] = { 0.f, 0.f, 0.f };
ClutterVertex rotate2 = CLUTTER_VERTEX_INIT_ZERO;
ClutterVertex translate2 = CLUTTER_VERTEX_INIT_ZERO;
ClutterVertex4 perspective2 = { 0.f, 0.f, 0.f, 0.f };
ClutterVertex scale_res = CLUTTER_VERTEX_INIT (1.f, 1.f, 1.f);
float shear_res[3] = { 0.f, 0.f, 0.f };
ClutterVertex rotate_res = CLUTTER_VERTEX_INIT_ZERO;
ClutterVertex translate_res = CLUTTER_VERTEX_INIT_ZERO;
ClutterVertex4 perspective_res = { 0.f, 0.f, 0.f, 0.f };
ClutterMatrix res;
clutter_matrix_init_identity (&res);
_clutter_util_matrix_decompose (matrix1,
&scale1, shear1, &rotate1, &translate1,
&perspective1);
_clutter_util_matrix_decompose (matrix2,
&scale2, shear2, &rotate2, &translate2,
&perspective2);
/* perspective */
_clutter_util_vertex4_interpolate (&perspective1, &perspective2, progress, &perspective_res);
res.wx = perspective_res.x;
res.wy = perspective_res.y;
res.wz = perspective_res.z;
res.ww = perspective_res.w;
/* translation */
clutter_vertex_interpolate (&translate1, &translate2, progress, &translate_res);
cogl_matrix_translate (&res, translate_res.x, translate_res.y, translate_res.z);
/* rotation */
clutter_vertex_interpolate (&rotate1, &rotate2, progress, &rotate_res);
cogl_matrix_rotate (&res, rotate_res.x, 1.0f, 0.0f, 0.0f);
cogl_matrix_rotate (&res, rotate_res.y, 0.0f, 1.0f, 0.0f);
cogl_matrix_rotate (&res, rotate_res.z, 0.0f, 0.0f, 1.0f);
/* skew */
/* scale */
clutter_vertex_interpolate (&scale1, &scale2, progress, &scale_res);
cogl_matrix_scale (&res, scale_res.x, scale_res.y, scale_res.z);
g_value_set_boxed (retval, &res);
return TRUE;
}
G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterMatrix, clutter_matrix,
clutter_matrix_copy,
clutter_matrix_free,
CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_matrix_progress))
/**
* clutter_matrix_alloc:
@ -1313,7 +1421,7 @@ clutter_matrix_alloc (void)
void
clutter_matrix_free (ClutterMatrix *matrix)
{
g_free (matrix);
cogl_matrix_free (matrix);
}
/**
@ -1381,3 +1489,60 @@ clutter_matrix_init_from_matrix (ClutterMatrix *a,
{
return memcpy (a, b, sizeof (ClutterMatrix));
}
/**
* clutter_matrix_determinant:
* @matrix: a #ClutterMatrix
*
* Calculates the determinant of the @matrix.
*
* Return value: the determinant of the #ClutterMatrix
*
* Since: 1.12
*/
float
clutter_matrix_determinant (const ClutterMatrix *matrix)
{
return matrix->xw * matrix->yz * matrix->zy * matrix->wz
- matrix->xz * matrix->yw * matrix->zy * matrix->wz
- matrix->xw * matrix->yy * matrix->zz * matrix->wz
+ matrix->xy * matrix->yw * matrix->zz * matrix->wz
+ matrix->xz * matrix->yy * matrix->zw * matrix->wz
- matrix->xy * matrix->yz * matrix->zw * matrix->wz
- matrix->xw * matrix->yz * matrix->zx * matrix->wy
+ matrix->xz * matrix->yw * matrix->zx * matrix->wy
+ matrix->xw * matrix->yx * matrix->zz * matrix->wy
- matrix->xx * matrix->yw * matrix->zz * matrix->wy
- matrix->xz * matrix->yx * matrix->zw * matrix->wy
+ matrix->xx * matrix->yz * matrix->zw * matrix->wy
+ matrix->xw * matrix->yy * matrix->zx * matrix->wz
- matrix->xy * matrix->yw * matrix->zx * matrix->wz
- matrix->xw * matrix->yx * matrix->zy * matrix->wz
+ matrix->xx * matrix->yw * matrix->zy * matrix->wz
+ matrix->xy * matrix->yx * matrix->zw * matrix->wz
- matrix->xx * matrix->yy * matrix->zw * matrix->wz
- matrix->xz * matrix->yy * matrix->zx * matrix->ww
+ matrix->xy * matrix->yz * matrix->zx * matrix->ww
+ matrix->xz * matrix->yx * matrix->zy * matrix->ww
- matrix->xx * matrix->yz * matrix->zy * matrix->ww
- matrix->xy * matrix->yx * matrix->zz * matrix->ww
+ matrix->xx * matrix->yy * matrix->zz * matrix->ww;
}
ClutterMatrix *
clutter_matrix_normalize (ClutterMatrix *matrix)
{
int i, j;
#define MAT(m,r,c) ((float *)(m))[(c)*4+(r)]
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
MAT (matrix, i, j) /= MAT (matrix, 3, 3);
}
#undef MAT
return matrix;
}

View File

@ -46,6 +46,7 @@
G_BEGIN_DECLS
typedef struct _ClutterMainContext ClutterMainContext;
typedef struct _ClutterVertex4 ClutterVertex4;
#define CLUTTER_REGISTER_VALUE_TRANSFORM_TO(TYPE_TO,func) { \
g_value_register_transform_func (g_define_type_id, TYPE_TO, func); \
@ -265,6 +266,29 @@ void _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1,
const cairo_rectangle_int_t *src2,
cairo_rectangle_int_t *dest);
struct _ClutterVertex4
{
float x;
float y;
float z;
float w;
};
void
_clutter_util_vertex4_interpolate (const ClutterVertex4 *a,
const ClutterVertex4 *b,
double progress,
ClutterVertex4 *res);
gboolean
_clutter_util_matrix_decompose (const ClutterMatrix *src,
ClutterVertex *scale_p,
float shear_p[3],
ClutterVertex *rotate_p,
ClutterVertex *translate_p,
ClutterVertex4 *perspective_p);
typedef struct _ClutterPlane
{
float v0[3];

View File

@ -422,6 +422,17 @@ ClutterVertex *clutter_vertex_copy (const ClutterVertex *vertex);
void clutter_vertex_free (ClutterVertex *vertex);
gboolean clutter_vertex_equal (const ClutterVertex *vertex_a,
const ClutterVertex *vertex_b);
CLUTTER_AVAILABLE_IN_1_12
float clutter_vertex_length (const ClutterVertex *vertex);
CLUTTER_AVAILABLE_IN_1_12
void clutter_vertex_normalize (ClutterVertex *vertex);
CLUTTER_AVAILABLE_IN_1_12
float clutter_vertex_dot (const ClutterVertex *v1,
const ClutterVertex *v2);
CLUTTER_AVAILABLE_IN_1_12
void clutter_vertex_cross (const ClutterVertex *v1,
const ClutterVertex *v2,
ClutterVertex *res);
/**
* ClutterActorBox:
@ -694,15 +705,25 @@ typedef gboolean (* ClutterProgressFunc) (const GValue *a,
void clutter_interval_register_progress_func (GType value_type,
ClutterProgressFunc func);
CLUTTER_AVAILABLE_IN_1_12
GType clutter_matrix_get_type (void) G_GNUC_CONST;
CLUTTER_AVAILABLE_IN_1_12
ClutterMatrix * clutter_matrix_alloc (void);
CLUTTER_AVAILABLE_IN_1_12
ClutterMatrix * clutter_matrix_init_identity (ClutterMatrix *matrix);
CLUTTER_AVAILABLE_IN_1_12
ClutterMatrix * clutter_matrix_init_from_array (ClutterMatrix *matrix,
const float values[16]);
CLUTTER_AVAILABLE_IN_1_12
ClutterMatrix * clutter_matrix_init_from_matrix (ClutterMatrix *a,
const ClutterMatrix *b);
CLUTTER_AVAILABLE_IN_1_12
void clutter_matrix_free (ClutterMatrix *matrix);
CLUTTER_AVAILABLE_IN_1_12
float clutter_matrix_determinant (const ClutterMatrix *matrix);
CLUTTER_AVAILABLE_IN_1_12
ClutterMatrix * clutter_matrix_normalize (ClutterMatrix *matrix);
G_END_DECLS

View File

@ -34,6 +34,8 @@
#include "config.h"
#endif
#include <math.h>
#include <glib/gi18n-lib.h>
#include "clutter-main.h"
@ -84,14 +86,6 @@ _clutter_gettext (const gchar *str)
#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
#define MTX_GL_SCALE_Z(z,w,v1,v2) (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
typedef struct _ClutterVertex4
{
float x;
float y;
float z;
float w;
} ClutterVertex4;
void
_clutter_util_fully_transform_vertices (const CoglMatrix *modelview,
const CoglMatrix *projection,
@ -182,6 +176,251 @@ _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1,
dest->y = dest_y;
}
static void
_clutter_util_matrix_transpose_vector4_transform (const ClutterMatrix *matrix,
const ClutterVertex4 *point,
ClutterVertex4 *res)
{
res->x = matrix->xx * point->x
+ matrix->xy * point->y
+ matrix->xz * point->z
+ matrix->xw * point->w;
res->y = matrix->yx * point->x
+ matrix->yy * point->y
+ matrix->yz * point->z
+ matrix->yw * point->w;
res->z = matrix->zx * point->x
+ matrix->zy * point->y
+ matrix->zz * point->z
+ matrix->zw * point->w;
res->w = matrix->wz * point->x
+ matrix->wy * point->w
+ matrix->wz * point->z
+ matrix->ww * point->w;
}
static void
_clutter_util_vertex_combine (const ClutterVertex *a,
const ClutterVertex *b,
double ascl,
double bscl,
ClutterVertex *res)
{
res->x = (ascl * a->x) + (bscl * b->x);
res->y = (ascl * a->y) + (bscl * b->y);
res->z = (ascl * a->z) + (bscl * b->z);
}
void
_clutter_util_vertex4_interpolate (const ClutterVertex4 *a,
const ClutterVertex4 *b,
double progress,
ClutterVertex4 *res)
{
res->x = a->x + (b->x - a->x) * progress;
res->y = a->y + (b->y - a->y) * progress;
res->z = a->z + (b->z - a->z) * progress;
res->w = a->w + (b->w - a->w) * progress;
}
/*< private >
* clutter_util_matrix_decompose:
* @src: the matrix to decompose
* @scale_p: (out caller-allocates): return location for a vertex containing
* the scaling factors
* @shear_p: (out) (array length=3): return location for an array of 3
* elements containing the skew factors (XY, XZ, and YZ respectively)
* @rotate_p: (out caller-allocates): return location for a vertex containing
* the Euler angles
* @translate_p: (out caller-allocates): return location for a vertex
* containing the translation vector
* @perspective_p: (out caller-allocates: return location for a 4D vertex
* containing the perspective
*
* Decomposes a #ClutterMatrix into the transformations that compose it.
*
* This code is based on the matrix decomposition algorithm as published in
* the CSS Transforms specification by the W3C CSS working group, available
* at http://www.w3.org/TR/css3-transforms/.
*
* The algorithm, in turn, is based on the "unmatrix" method published in
* "Graphics Gems II, edited by Jim Arvo", which is available at:
* http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c
*
* Return value: %TRUE if the decomposition was successful, and %FALSE
* if the matrix is singular
*/
gboolean
_clutter_util_matrix_decompose (const ClutterMatrix *src,
ClutterVertex *scale_p,
float shear_p[3],
ClutterVertex *rotate_p,
ClutterVertex *translate_p,
ClutterVertex4 *perspective_p)
{
CoglMatrix matrix = *src;
CoglMatrix perspective;
ClutterVertex4 vertex_tmp;
ClutterVertex row[3], pdum;
int i, j;
#define XY_SHEAR 0
#define XZ_SHEAR 1
#define YZ_SHEAR 2
#define MAT(m,r,c) ((float *)(m))[(c) * 4 + (r)]
/* normalize the matrix */
if (matrix.ww == 0.f)
return FALSE;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
MAT (&matrix, i, j) /= MAT (&matrix, 3, 3);
}
}
/* perspective is used to solve for perspective, but it also provides
* an easy way to test for singularity of the upper 3x3 component
*/
perspective = matrix;
/* transpose */
MAT (&perspective, 0, 3) = 0.f;
MAT (&perspective, 1, 3) = 0.f;
MAT (&perspective, 2, 3) = 0.f;
MAT (&perspective, 3, 3) = 1.f;
if (clutter_matrix_determinant (&perspective) == 0.f)
return FALSE;
if (MAT (&matrix, 0, 3) != 0.f ||
MAT (&matrix, 1, 3) != 0.f ||
MAT (&matrix, 2, 3) != 0.f)
{
CoglMatrix perspective_inv;
ClutterVertex4 p;
vertex_tmp.x = MAT (&matrix, 0, 3);
vertex_tmp.y = MAT (&matrix, 1, 3);
vertex_tmp.z = MAT (&matrix, 2, 3);
vertex_tmp.w = MAT (&matrix, 3, 3);
/* solve the equation by inverting perspective... */
cogl_matrix_get_inverse (&perspective, &perspective_inv);
/* ... and multiplying vertex_tmp by the inverse */
_clutter_util_matrix_transpose_vector4_transform (&perspective_inv,
&vertex_tmp,
&p);
*perspective_p = p;
/* clear the perspective part */
MAT (&matrix, 0, 3) = 0.0f;
MAT (&matrix, 1, 3) = 0.0f;
MAT (&matrix, 2, 3) = 0.0f;
MAT (&matrix, 3, 3) = 1.0f;
}
else
{
/* no perspective */
perspective_p->x = 0.0f;
perspective_p->y = 0.0f;
perspective_p->z = 0.0f;
perspective_p->w = 1.0f;
}
/* translation */
translate_p->x = MAT (&matrix, 3, 0);
MAT (&matrix, 3, 0) = 0.f;
translate_p->y = MAT (&matrix, 3, 1);
MAT (&matrix, 3, 1) = 0.f;
translate_p->z = MAT (&matrix, 3, 2);
MAT (&matrix, 3, 2) = 0.f;
/* scale and shear; we split the upper 3x3 matrix into rows */
for (i = 0; i < 3; i++)
{
row[i].x = MAT (&matrix, i, 0);
row[i].y = MAT (&matrix, i, 1);
row[i].z = MAT (&matrix, i, 2);
}
/* compute scale.x and normalize the first row */
scale_p->x = clutter_vertex_length (&row[0]);
clutter_vertex_normalize (&row[0]);
/* compute XY shear and make the second row orthogonal to the first */
shear_p[XY_SHEAR] = clutter_vertex_dot (&row[0], &row[1]);
_clutter_util_vertex_combine (&row[1], &row[0],
1.0, -shear_p[XY_SHEAR],
&row[1]);
/* compute the Y scale and normalize the second row */
scale_p->y = clutter_vertex_length (&row[1]);
clutter_vertex_normalize (&row[1]);
shear_p[XY_SHEAR] /= scale_p->y;
/* compute XZ and YZ shears, orthogonalize the third row */
shear_p[XZ_SHEAR] = clutter_vertex_dot (&row[0], &row[2]);
_clutter_util_vertex_combine (&row[2], &row[0],
1.0, -shear_p[XZ_SHEAR],
&row[2]);
shear_p[YZ_SHEAR] = clutter_vertex_dot (&row[1], &row[2]);
_clutter_util_vertex_combine (&row[2], &row[1],
1.0, -shear_p[YZ_SHEAR],
&row[2]);
/* get the Z scale and normalize the third row*/
scale_p->z = clutter_vertex_dot (&row[0], &row[2]);
clutter_vertex_normalize (&row[2]);
shear_p[XZ_SHEAR] /= scale_p->z;
shear_p[YZ_SHEAR] /= scale_p->z;
/* at this point, the matrix (inside row[]) is orthonormal.
* check for a coordinate system flip; if the determinant
* is -1, then negate the matrix and scaling factors
*/
clutter_vertex_cross (&row[1], &row[2], &pdum);
if (clutter_vertex_dot (&row[0], &pdum) < 0.f)
{
scale_p->x *= -1.f;
for (i = 0; i < 3; i++)
{
row[i].x *= -1.f;
row[i].y *= -1.f;
row[i].z *= -1.f;
}
}
/* now get the rotations out */
rotate_p->y = asinf (-row[0].z);
if (cosf (rotate_p->y) != 0.f)
{
rotate_p->x = atan2f (row[1].z, row[2].z);
rotate_p->z = atan2f (row[0].y, row[0].x);
}
else
{
rotate_p->x = atan2f (-row[2].x, row[1].y);
rotate_p->z = 0.f;
}
#undef XY_SHEAR
#undef XZ_SHEAR
#undef YZ_SHEAR
#undef MAT
return TRUE;
}
typedef struct
{
GType value_type;

View File

@ -908,11 +908,13 @@ clutter_margin_free
clutter_margin_get_type
clutter_margin_new
clutter_matrix_alloc
clutter_matrix_determinant
clutter_matrix_free
clutter_matrix_get_type
clutter_matrix_init_identity
clutter_matrix_init_from_array
clutter_matrix_init_from_matrix
clutter_matrix_normalize
clutter_media_get_audio_volume
clutter_media_get_buffer_fill
clutter_media_get_can_seek

View File

@ -3326,6 +3326,7 @@ clutter_matrix_free
clutter_matrix_init_from_array
clutter_matrix_init_from_matrix
clutter_matrix_init_identity
clutter_matrix_determinant
<SUBSECTION>
clutter_knot_copy

View File

@ -91,7 +91,12 @@ on_key_press (ClutterActor *stage,
key_symbol = clutter_event_get_key_symbol (event);
if (key_symbol == CLUTTER_KEY_space)
clutter_actor_set_child_transform (scroll, NULL);
{
clutter_actor_save_easing_state (scroll);
clutter_actor_set_easing_duration (scroll, 1000);
clutter_actor_set_child_transform (scroll, NULL);
clutter_actor_restore_easing_state (scroll);
}
return CLUTTER_EVENT_STOP;
}