/**
 * graphene_quaternion_init_from_matrix:
 * @q: a #graphene_quaternion_t
 * @m: a #graphene_matrix_t
 *
 * Initializes a #graphene_quaternion_t using the rotation components
 * of a transformation matrix.
 *
 * Returns: (transfer none): the initialized quaternion
 *
 * Since: 1.0
 */
graphene_quaternion_t *
graphene_quaternion_init_from_matrix (graphene_quaternion_t   *q,
                                      const graphene_matrix_t *m)
{
  float xx, yy, zz;

  xx = graphene_matrix_get_value (m, 0, 0);
  yy = graphene_matrix_get_value (m, 1, 1);
  zz = graphene_matrix_get_value (m, 2, 2);

  q->w = 0.5f * sqrtf (MAX (1 + xx + yy + zz, 0.f));
  q->x = 0.5f * sqrtf (MAX (1 + xx - yy - zz, 0.f));
  q->y = 0.5f * sqrtf (MAX (1 - xx + yy - zz, 0.f));
  q->z = 0.5f * sqrtf (MAX (1 - xx - yy + zz, 0.f));

  if (graphene_matrix_get_value (m, 2, 1) > graphene_matrix_get_value (m, 1, 2))
    q->x = -q->x;

  if (graphene_matrix_get_value (m, 0, 2) > graphene_matrix_get_value (m, 2, 0))
    q->y = -q->y;

  if (graphene_matrix_get_value (m, 1, 0) > graphene_matrix_get_value (m, 0, 1))
    q->z = -q->z;

  return q;
}
Beispiel #2
0
/**
 * graphene_matrix_print:
 * @m: The matrix to print
 *
 * Prints the contents of a matrix.
 *
 * Since: 1.0
 */
void
graphene_matrix_print (const graphene_matrix_t *m)
{
  int i;

  for (i = 0; i < 4; i++)
    {
      fprintf (stderr,
               "%.5f %.5f %.5f %.5f\n",
               graphene_matrix_get_value (m, i, 0),
               graphene_matrix_get_value (m, i, 1),
               graphene_matrix_get_value (m, i, 2),
               graphene_matrix_get_value (m, i, 3));
    }
}
Beispiel #3
0
static void
extract_matrix_metadata (const graphene_matrix_t *m,
                         OpsMatrixMetadata       *md)
{
  switch (md->category)
    {
    case GSK_TRANSFORM_CATEGORY_IDENTITY:
      md->scale_x = 1;
      md->scale_y = 1;
    break;

    case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
      md->translate_x = graphene_matrix_get_value (m, 3, 0);
      md->translate_y = graphene_matrix_get_value (m, 3, 1);
      md->scale_x = 1;
      md->scale_y = 1;
    break;

    case GSK_TRANSFORM_CATEGORY_UNKNOWN:
    case GSK_TRANSFORM_CATEGORY_ANY:
    case GSK_TRANSFORM_CATEGORY_3D:
    case GSK_TRANSFORM_CATEGORY_2D:
    case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
      {
        graphene_vec3_t col1;
        graphene_vec3_t col2;

        md->translate_x = graphene_matrix_get_value (m, 3, 0);
        md->translate_y = graphene_matrix_get_value (m, 3, 1);

        graphene_vec3_init (&col1,
                            graphene_matrix_get_value (m, 0, 0),
                            graphene_matrix_get_value (m, 1, 0),
                            graphene_matrix_get_value (m, 2, 0));

        graphene_vec3_init (&col2,
                            graphene_matrix_get_value (m, 0, 1),
                            graphene_matrix_get_value (m, 1, 1),
                            graphene_matrix_get_value (m, 2, 1));

        md->scale_x = graphene_vec3_length (&col1);
        md->scale_y = graphene_vec3_length (&col2);
      }
    break;
    default:
      {}
    }
}
Beispiel #4
0
/**
 * graphene_matrix_is_backface_visible:
 * @m: a #graphene_matrix_t
 *
 * Checks whether a #graphene_matrix_t has a visible back face.
 *
 * Returns: %true if the back face of the matrix is visible
 *
 * Since: 1.0
 */
bool
graphene_matrix_is_backface_visible (const graphene_matrix_t *m)
{
  graphene_matrix_t tmp;

  graphene_matrix_inverse (m, &tmp);

  /* inverse.zz < 0 */
  return graphene_matrix_get_value (&tmp, 2, 2) < 0.f;
}
Beispiel #5
0
gboolean
graphene_matrix_is_backface_visible (const graphene_matrix_t *m)
{
  graphene_matrix_t tmp;

  g_return_val_if_fail (m != NULL, FALSE);

  graphene_matrix_inverse (m, &tmp);

  /* inverse.zz < 0 */
  return graphene_matrix_get_value (&tmp, 2, 2) < 0.f;
}
Beispiel #6
0
/**
 * graphene_matrix_to_2d:
 * @m: a #graphene_matrix_t
 * @xx: (out): return location for the xx member
 * @yx: (out): return location for the yx member
 * @xy: (out): return location for the xy member
 * @yy: (out): return location for the yy member
 * @x_0: (out): return location for the x0 member
 * @y_0: (out): return location for the y0 member
 *
 * Converts a #graphene_matrix_t to an affine transformation
 * matrix, if the given matrix is compatible.
 *
 * The returned values have the following layout:
 *
 * |[
 *   | xx yx |   |  a  b  0 |
 *   | xy yy | = |  c  d  0 |
 *   | x0 y0 |   | tx ty  1 |
 * ]|
 *
 * This function can be used to convert between a #graphene_matrix_t
 * and a matrix type from other libraries.
 *
 * Returns: %true if the matrix is compatible with an affine
 *   transformation matrix
 *
 * Since: 1.0
 */
bool
graphene_matrix_to_2d (const graphene_matrix_t *m,
                       double                  *xx,
                       double                  *yx,
                       double                  *xy,
                       double                  *yy,
                       double                  *x_0,
                       double                  *y_0)
{
  if (!graphene_simd4x4f_is_2d (&m->value))
    return false;

  if (xx != NULL)
    *xx = graphene_matrix_get_value (m, 0, 0);
  if (yx != NULL)
    *yx = graphene_matrix_get_value (m, 0, 1);
  if (xy != NULL)
    *xy = graphene_matrix_get_value (m, 1, 0);
  if (yy != NULL)
    *yy = graphene_matrix_get_value (m, 1, 1);
  if (x_0 != NULL)
    *x_0 = graphene_matrix_get_value (m, 3, 0);
  if (y_0 != NULL)
    *y_0 = graphene_matrix_get_value (m, 3, 1);

  return true;
}
Beispiel #7
0
/**
 * graphene_matrix_normalize:
 * @m: a #graphene_matrix_t
 * @res: (out caller-allocates): return location for the normalized matrix
 *
 * Normalizes the given #graphene_matrix_t.
 *
 * Since: 1.0
 */
void
graphene_matrix_normalize (const graphene_matrix_t *m,
                           graphene_matrix_t       *res)
{
  graphene_simd4f_t n;
  float ww;

  ww = graphene_matrix_get_value (m, 3, 3);
  n = graphene_simd4f_splat (ww);

  res->value.x = graphene_simd4f_div (m->value.x, n);
  res->value.y = graphene_simd4f_div (m->value.y, n);
  res->value.z = graphene_simd4f_div (m->value.z, n);
  res->value.w = graphene_simd4f_div (m->value.w, n);
}
Beispiel #8
0
static gboolean
matrix_decompose_2d (const graphene_matrix_t *m,
                     graphene_point3d_t      *scale_r,
                     float                    shear_r[3],
                     graphene_quaternion_t   *rotate_r,
                     graphene_point3d_t      *translate_r)
{
  float A = graphene_matrix_get_value (m, 0, 0);
  float B = graphene_matrix_get_value (m, 1, 0);
  float C = graphene_matrix_get_value (m, 0, 1);
  float D = graphene_matrix_get_value (m, 1, 1);
  float scale_x, scale_y;
  float shear_xy;
  float rotate;

  if (A * D == B * C)
    return FALSE;

  scale_x = sqrtf (A * A + B * B);
  A /= scale_x;
  B /= scale_x;

  shear_xy = A * C + B * D;
  C -= A * shear_xy;
  D -= B * shear_xy;

  scale_y = sqrtf (C * C + D * D);
  C /= scale_y;
  D /= scale_y;
  shear_xy /= scale_y;

  if (A * D < B * C)
    {
      A = -A;
      B = -B;
      C = -C;
      D = -D;

      shear_xy = -shear_xy;
      scale_x = -scale_x;
    }

  rotate = atan2f (B, A);
  graphene_quaternion_init (rotate_r, 0.f, 0.f, sin (rotate / 2.f), cos (rotate / 2.f));

  shear_r[XY_SHEAR] = shear_xy;
  graphene_point3d_init (scale_r, scale_x, scale_y, 1.f);

  graphene_point3d_init (translate_r,
                         graphene_matrix_get_value (m, 3, 0),
                         graphene_matrix_get_value (m, 3, 1),
                         0.f);

  return TRUE;
}
Beispiel #9
0
static gboolean
matrix_decompose_3d (const graphene_matrix_t *m,
                     graphene_point3d_t      *scale_r,
                     float                    shear_r[3],
                     graphene_quaternion_t   *rotate_r,
                     graphene_point3d_t      *translate_r,
                     graphene_vec4_t         *perspective_r)
{
  graphene_matrix_t local, perspective;
  float shear_xy, shear_xz, shear_yz;
  float scale_x, scale_y, scale_z;
  graphene_simd4f_t dot, cross;

  if (graphene_matrix_get_value (m, 3, 3) == 0.f)
    return FALSE;

  local = *m;

  /* normalize the matrix */
  graphene_matrix_normalize (&local, &local);

  /* perspective is used to solve for the perspective component,
   * but it also provides an easy way to test for singularity of
   * the upper 3x3 component
   */
  perspective = local;
  perspective.value.w = graphene_simd4f_init (0.f, 0.f, 0.f, 1.f);

  if (graphene_matrix_determinant (&perspective) == 0.f)
    return FALSE;

  /* isolate the perspective */
  if (graphene_simd4f_is_zero3 (local.value.w))
    {
      graphene_matrix_t tmp;

      /* perspective_r is the right hand side of the equation */
      perspective_r->value = local.value.w;

      /* solve the equation by inverting perspective and multiplying
       * the inverse with the perspective vector
       */
      graphene_matrix_inverse (&perspective, &tmp);
      graphene_matrix_transpose_transform_vec4 (&tmp, perspective_r, perspective_r);

      /* clear the perspective partition */
      local.value.w = graphene_simd4f_init (0.f, 0.f, 0.f, 1.f);
    }
  else
    graphene_vec4_init (perspective_r, 0.f, 0.f, 0.f, 1.f);

  /* next, take care of the translation partition */
  translate_r->x = graphene_simd4f_get_x (local.value.w);
  translate_r->y = graphene_simd4f_get_y (local.value.w);
  translate_r->z = graphene_simd4f_get_z (local.value.w);
  local.value.w = graphene_simd4f_init (0.f, 0.f, 0.f, graphene_simd4f_get_w (local.value.w));

  /* now get scale and shear */

  /* compute the X scale factor and normalize the first row */
  scale_x = graphene_simd4f_get_x (graphene_simd4f_length4 (local.value.x));
  local.value.x = graphene_simd4f_div (local.value.x, graphene_simd4f_splat (scale_x));

  /* compute XY shear factor and the second row orthogonal to the first */
  shear_xy = graphene_simd4f_get_x (graphene_simd4f_dot4 (local.value.x, local.value.y));
  local.value.y = graphene_simd4f_sub (local.value.y, graphene_simd4f_mul (local.value.x, graphene_simd4f_splat (shear_xy)));

  /* now, compute the Y scale factor and normalize the second row */
  scale_y = graphene_simd4f_get_x (graphene_simd4f_length4 (local.value.y));
  local.value.y = graphene_simd4f_div (local.value.y, graphene_simd4f_splat (scale_y));
  shear_xy /= scale_y;

  /* compute XZ and YZ shears, make the third row orthogonal */
  shear_xz = graphene_simd4f_get_x (graphene_simd4f_dot4 (local.value.x, local.value.z));
  local.value.z = graphene_simd4f_sub (local.value.z, graphene_simd4f_mul (local.value.x, graphene_simd4f_splat (shear_xz)));
  shear_yz = graphene_simd4f_get_x (graphene_simd4f_dot4 (local.value.y, local.value.z));
  local.value.z = graphene_simd4f_sub (local.value.z, graphene_simd4f_mul (local.value.y, graphene_simd4f_splat (shear_yz)));

  /* next, get the Z scale and normalize the third row */
  scale_z = graphene_simd4f_get_x (graphene_simd4f_length4 (local.value.z));
  local.value.z = graphene_simd4f_div (local.value.z, graphene_simd4f_splat (scale_z));

  shear_xz /= scale_z;
  shear_yz /= scale_z;

  shear_r[XY_SHEAR] = shear_xy;
  shear_r[XZ_SHEAR] = shear_xz;
  shear_r[YZ_SHEAR] = shear_yz;

  /* at this point, the matrix is orthonormal. we check for a
   * coordinate system flip. if the determinant is -1, then
   * negate the matrix and the scaling factors
   */
  dot = graphene_simd4f_cross3 (local.value.y, local.value.z);
  cross = graphene_simd4f_dot4 (local.value.x, dot);
  if (graphene_simd4f_get_x (cross) < 0.f)
    {
      scale_x *= -1.f;
      scale_y *= -1.f;
      scale_z *= -1.f;

      graphene_simd4f_mul (local.value.x, graphene_simd4f_splat (-1.f));
      graphene_simd4f_mul (local.value.y, graphene_simd4f_splat (-1.f));
      graphene_simd4f_mul (local.value.z, graphene_simd4f_splat (-1.f));
    }

  graphene_point3d_init (scale_r, scale_x, scale_y, scale_z);

  /* get the rotations out */
  graphene_quaternion_init_from_matrix (rotate_r, &local);

  return TRUE;
}