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; }
/** * graphene_vec4_length: * @v: a #graphene_vec4_t * * Computes the length of the given #graphene_vec4_t. * * Returns: the length of the vector * * Since: 1.0 */ float graphene_vec4_length (const graphene_vec4_t *v) { return graphene_simd4f_get_x (graphene_simd4f_length4 (v->value)); }