[clutter] Add interpolation for matrices



commit 22ce4409b3f3994e3487617c01e96886c860dc9b
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Mon Sep 3 20:54:43 2012 +0100

    Add interpolation for matrices
    
    Interpolating between two transformations expressed using a 3D matrix
    can be achieved by decomposing the matrices into their transformations
    and do a simple numeric interpolation between the initial and final
    states, like we do for other data types.
    
    Luckily for us, the CSS Transforms specification from the W3C provides
    the decomposition algorithm, using the "unmatrix" code taken from the
    book "Graphics Gems II, edited by Jim Arvo".
    
    Once the matrices have been decomposed, we can simply interpolate the
    transformations, and re-apply them onto the result matrix, using the
    facilities that Clutter provides for interpolating between two known
    GTypes.

 clutter/clutter-base-types.c |   99 +++++++++++-
 clutter/clutter-private.h    |   39 +++++
 clutter/clutter-types.h      |    6 +
 clutter/clutter-util.c       |  351 +++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 479 insertions(+), 16 deletions(-)
---
diff --git a/clutter/clutter-base-types.c b/clutter/clutter-base-types.c
index 91fbd95..0496b52 100644
--- a/clutter/clutter-base-types.c
+++ b/clutter/clutter-base-types.c
@@ -284,6 +284,17 @@ clutter_vertex_equal (const ClutterVertex *vertex_a,
          fabsf (vertex_a->z - vertex_b->z) < FLOAT_EPSILON;
 }
 
+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 +305,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 +1289,86 @@ clutter_rect_progress (const GValue *a,
 static gpointer
 clutter_matrix_copy (gpointer data)
 {
-  return g_memdup (data, sizeof (ClutterMatrix));
+  return cogl_matrix_copy (data);
+}
+
+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 = 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 */
+  shear_res = shear1[2] + (shear2[2] - shear1[2]) * progress; /* YZ */
+  if (shear_res != 0.f)
+    _clutter_util_matrix_skew_yz (&res, shear_res);
+
+  shear_res = shear1[1] + (shear2[1] - shear1[1]) * progress; /* XZ */
+  if (shear_res != 0.f)
+    _clutter_util_matrix_skew_xz (&res, shear_res);
+
+  shear_res = shear1[0] + (shear2[0] - shear1[0]) * progress; /* XY */
+  if (shear_res != 0.f)
+    _clutter_util_matrix_skew_xy (&res, shear_res);
+
+  /* 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 (ClutterMatrix, clutter_matrix,
-                     clutter_matrix_copy,
-                     clutter_matrix_free)
+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 +1396,7 @@ clutter_matrix_alloc (void)
 void
 clutter_matrix_free (ClutterMatrix *matrix)
 {
-  g_free (matrix);
+  cogl_matrix_free (matrix);
 }
 
 /**
diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h
index f855727..1d28ee0 100644
--- a/clutter/clutter-private.h
+++ b/clutter/clutter-private.h
@@ -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,44 @@ 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);
+
+#define CLUTTER_MATRIX_INIT_IDENTITY { \
+  1.0f, 0.0f, 0.0f, 0.0f, \
+  0.0f, 1.0f, 0.0f, 0.0f, \
+  0.0f, 0.0f, 1.0f, 0.0f, \
+  0.0f, 0.0f, 0.0f, 1.0f, \
+}
+
+float   _clutter_util_matrix_determinant        (const ClutterMatrix *matrix);
+
+void    _clutter_util_matrix_skew_xy            (ClutterMatrix *matrix,
+                                                 float          factor);
+void    _clutter_util_matrix_skew_xz            (ClutterMatrix *matrix,
+                                                 float          factor);
+void    _clutter_util_matrix_skew_yz            (ClutterMatrix *matrix,
+                                                 float          factor);
+
+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];
diff --git a/clutter/clutter-types.h b/clutter/clutter-types.h
index d5e4662..431964a 100644
--- a/clutter/clutter-types.h
+++ b/clutter/clutter-types.h
@@ -694,14 +694,20 @@ 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);
 
 G_END_DECLS
diff --git a/clutter/clutter-util.c b/clutter/clutter-util.c
index b95629c..20dd2f9 100644
--- a/clutter/clutter-util.c
+++ b/clutter/clutter-util.c
@@ -34,8 +34,11 @@
 #include "config.h"
 #endif
 
+#include <math.h>
+
 #include <glib/gi18n-lib.h>
 
+#include "clutter-debug.h"
 #include "clutter-main.h"
 #include "clutter-interval.h"
 #include "clutter-private.h"
@@ -84,14 +87,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 +177,346 @@ _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1,
   dest->y = dest_y;
 }
 
+float
+_clutter_util_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;
+}
+
+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;
+}
+
+void
+_clutter_util_matrix_skew_xy (ClutterMatrix *matrix,
+                              float          factor)
+{
+  matrix->yx += matrix->xx * factor;
+  matrix->yy += matrix->xy * factor;
+  matrix->yz += matrix->xz * factor;
+  matrix->yw += matrix->xw * factor;
+}
+
+void
+_clutter_util_matrix_skew_xz (ClutterMatrix *matrix,
+                              float          factor)
+{
+  matrix->zx += matrix->xx * factor;
+  matrix->zy += matrix->xy * factor;
+  matrix->zz += matrix->xz * factor;
+  matrix->zw += matrix->xw * factor;
+}
+
+void
+_clutter_util_matrix_skew_yz (ClutterMatrix *matrix,
+                              float          factor)
+{
+  matrix->zx += matrix->yx * factor;
+  matrix->zy += matrix->yy * factor;
+  matrix->zz += matrix->yz * factor;
+  matrix->zw += matrix->yw * factor;
+}
+
+static float
+_clutter_util_vertex_length (const ClutterVertex *vertex)
+{
+  return sqrtf (vertex->x * vertex->x + vertex->y * vertex->y + vertex->z * vertex->z);
+}
+
+static void
+_clutter_util_vertex_normalize (ClutterVertex *vertex)
+{
+  float factor = _clutter_util_vertex_length (vertex);
+
+  if (factor == 0.f)
+    return;
+
+  vertex->x /= factor;
+  vertex->y /= factor;
+  vertex->z /= factor;
+}
+
+static float
+_clutter_util_vertex_dot (const ClutterVertex *v1,
+                          const ClutterVertex *v2)
+{
+  return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
+}
+
+static void
+_clutter_util_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_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, j, i) /= 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, 3, 0) = 0.f;
+  MAT (&perspective, 3, 1) = 0.f;
+  MAT (&perspective, 3, 2) = 0.f;
+  MAT (&perspective, 3, 3) = 1.f;
+
+  if (_clutter_util_matrix_determinant (&perspective) == 0.f)
+    return FALSE;
+
+  if (MAT (&matrix, 3, 0) != 0.f ||
+      MAT (&matrix, 3, 1) != 0.f ||
+      MAT (&matrix, 3, 2) != 0.f)
+    {
+      CoglMatrix perspective_inv;
+      ClutterVertex4 p;
+
+      vertex_tmp.x = MAT (&matrix, 3, 0);
+      vertex_tmp.y = MAT (&matrix, 3, 1);
+      vertex_tmp.z = MAT (&matrix, 3, 2);
+      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, 3, 0) = 0.0f;
+      MAT (&matrix, 3, 1) = 0.0f;
+      MAT (&matrix, 3, 2) = 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, 0, 3);
+  MAT (&matrix, 0, 3) = 0.f;
+  translate_p->y = MAT (&matrix, 1, 3);
+  MAT (&matrix, 1, 3) = 0.f;
+  translate_p->z = MAT (&matrix, 2, 3);
+  MAT (&matrix, 2, 3) = 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_util_vertex_length (&row[0]);
+  _clutter_util_vertex_normalize (&row[0]);
+
+  /* compute XY shear and make the second row orthogonal to the first */
+  shear_p[XY_SHEAR] = _clutter_util_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_util_vertex_length (&row[1]);
+  _clutter_util_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_util_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_util_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_util_vertex_length (&row[2]);
+  _clutter_util_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_util_vertex_cross (&row[1], &row[2], &pdum);
+  if (_clutter_util_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;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]