/** * 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; }
/** * 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)); } }
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: {} } }
/** * 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; }
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; }
/** * 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; }
/** * 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); }
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; }
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; }