diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 23721d68e..a2093b2d8 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -290,8 +290,6 @@ cogl_sources_c = \ $(srcdir)/cogl-journal.c \ $(srcdir)/cogl-framebuffer-private.h \ $(srcdir)/cogl-framebuffer.c \ - $(srcdir)/cogl-matrix-mesa.h \ - $(srcdir)/cogl-matrix-mesa.c \ $(srcdir)/cogl-profile.h \ $(srcdir)/cogl-profile.c \ $(srcdir)/cogl-flags.h \ diff --git a/cogl/cogl-matrix-mesa.c b/cogl/cogl-matrix-mesa.c deleted file mode 100644 index 5703efd5d..000000000 --- a/cogl/cogl-matrix-mesa.c +++ /dev/null @@ -1,1599 +0,0 @@ -/* - * Cogl - * - * An object oriented GL/GLES Abstraction/Utility Layer - * - * Copyright (C) 2009 Intel Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * - */ -/* - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/* - * file: cogl-matrix-mesa.c - * Matrix operations. - * - * note - * -# 4x4 transformation matrices are stored in memory in column major order. - * -# Points/vertices are to be thought of as column vectors. - * -# Transformation of a point p by a matrix M is: p' = M * p - */ - -/* - * Changes compared to the original code from Mesa: - * - * - instead of allocating matrix->m and matrix->inv using malloc, our - * public CoglMatrix typedef is large enough to directly contain the - * matrix, its inverse, a type and a set of flags. - * - instead of having a _cogl_matrix_analyse which updates the type, - * flags and inverse, we have _cogl_matrix_update_inverse which - * essentially does the same thing (internally making use of - * _cogl_matrix_update_type_and_flags()) but with additional guards in - * place to bail out when the inverse matrix is still valid. - * - when initializing a matrix with the identity matrix we don't - * immediately initialize the inverse matrix; rather we just set the - * dirty flag for the inverse (since it's likely the user won't request - * the inverse of the identity matrix) - */ - -#include "cogl-matrix-mesa.h" -#include "cogl-quaternion-private.h" - -#include -#include - - -#define DEG2RAD (G_PI/180.0) - -/* Dot product of two 2-element vectors */ -#define DOT2(A,B) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] ) - -/* Dot product of two 3-element vectors */ -#define DOT3(A,B) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] ) - -#define CROSS3(N, U, V) \ -do { \ - (N)[0] = (U)[1]*(V)[2] - (U)[2]*(V)[1]; \ - (N)[1] = (U)[2]*(V)[0] - (U)[0]*(V)[2]; \ - (N)[2] = (U)[0]*(V)[1] - (U)[1]*(V)[0]; \ -} while (0) - -#define SUB_3V(DST, SRCA, SRCB) \ -do { \ - (DST)[0] = (SRCA)[0] - (SRCB)[0]; \ - (DST)[1] = (SRCA)[1] - (SRCB)[1]; \ - (DST)[2] = (SRCA)[2] - (SRCB)[2]; \ -} while (0) - -#define LEN_SQUARED_3FV( V ) ((V)[0]*(V)[0]+(V)[1]*(V)[1]+(V)[2]*(V)[2]) - -/* - * \defgroup MatFlags MAT_FLAG_XXX-flags - * - * Bitmasks to indicate different kinds of 4x4 matrices in CoglMatrix::flags - */ -#define MAT_FLAG_IDENTITY 0 /*< is an identity matrix flag. - * (Not actually used - the identity - * matrix is identified by the absense - * of all other flags.) - */ -#define MAT_FLAG_GENERAL 0x1 /*< is a general matrix flag */ -#define MAT_FLAG_ROTATION 0x2 /*< is a rotation matrix flag */ -#define MAT_FLAG_TRANSLATION 0x4 /*< is a translation matrix flag */ -#define MAT_FLAG_UNIFORM_SCALE 0x8 /*< is an uniform scaling matrix flag */ -#define MAT_FLAG_GENERAL_SCALE 0x10 /*< is a general scaling matrix flag */ -#define MAT_FLAG_GENERAL_3D 0x20 /*< general 3D matrix flag */ -#define MAT_FLAG_PERSPECTIVE 0x40 /*< is a perspective proj matrix flag */ -#define MAT_FLAG_SINGULAR 0x80 /*< is a singular matrix flag */ -#define MAT_DIRTY_TYPE 0x100 /*< matrix type is dirty */ -#define MAT_DIRTY_FLAGS 0x200 /*< matrix flags are dirty */ -#define MAT_DIRTY_INVERSE 0x400 /*< matrix inverse is dirty */ - -/* angle preserving matrix flags mask */ -#define MAT_FLAGS_ANGLE_PRESERVING (MAT_FLAG_ROTATION | \ - MAT_FLAG_TRANSLATION | \ - MAT_FLAG_UNIFORM_SCALE) - -/* geometry related matrix flags mask */ -#define MAT_FLAGS_GEOMETRY (MAT_FLAG_GENERAL | \ - MAT_FLAG_ROTATION | \ - MAT_FLAG_TRANSLATION | \ - MAT_FLAG_UNIFORM_SCALE | \ - MAT_FLAG_GENERAL_SCALE | \ - MAT_FLAG_GENERAL_3D | \ - MAT_FLAG_PERSPECTIVE | \ - MAT_FLAG_SINGULAR) - -/* length preserving matrix flags mask */ -#define MAT_FLAGS_LENGTH_PRESERVING (MAT_FLAG_ROTATION | \ - MAT_FLAG_TRANSLATION) - - -/* 3D (non-perspective) matrix flags mask */ -#define MAT_FLAGS_3D (MAT_FLAG_ROTATION | \ - MAT_FLAG_TRANSLATION | \ - MAT_FLAG_UNIFORM_SCALE | \ - MAT_FLAG_GENERAL_SCALE | \ - MAT_FLAG_GENERAL_3D) - -/* dirty matrix flags mask */ -#define MAT_DIRTY_ALL (MAT_DIRTY_TYPE | \ - MAT_DIRTY_FLAGS | \ - MAT_DIRTY_INVERSE) - - -/* - * Test geometry related matrix flags. - * - * @mat a pointer to a CoglMatrix structure. - * @a flags mask. - * - * Returns: non-zero if all geometry related matrix flags are contained within - * the mask, or zero otherwise. - */ -#define TEST_MAT_FLAGS(mat, a) \ - ((MAT_FLAGS_GEOMETRY & (~(a)) & ((mat)->flags) ) == 0) - - - -/* - * Names of the corresponding CoglMatrixType values. - */ -static const char *types[] = { - "COGL_MATRIX_TYPE_GENERAL", - "COGL_MATRIX_TYPE_IDENTITY", - "COGL_MATRIX_TYPE_3D_NO_ROT", - "COGL_MATRIX_TYPE_PERSPECTIVE", - "COGL_MATRIX_TYPE_2D", - "COGL_MATRIX_TYPE_2D_NO_ROT", - "COGL_MATRIX_TYPE_3D" -}; - - -/* - * Identity matrix. - */ -static float identity[16] = { - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 -}; - - -#define A(row,col) a[(col<<2)+row] -#define B(row,col) b[(col<<2)+row] -#define R(row,col) result[(col<<2)+row] - -/* - * Perform a full 4x4 matrix multiplication. - * - * @a matrix. - * @b matrix. - * @product will receive the product of \p a and \p b. - * - * It'ss assumed that @product != @b. @product == @a is allowed. - * - * KW: 4*16 = 64 multiplications - */ -static void -matrix_multiply4x4 (float *result, const float *a, const float *b) -{ - int i; - for (i = 0; i < 4; i++) - { - const float ai0 = A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3); - R(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0); - R(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1); - R(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2); - R(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3); - } -} - -/* - * Multiply two matrices known to occupy only the top three rows, such - * as typical model matrices, and orthogonal matrices. - * - * @a matrix. - * @b matrix. - * @product will receive the product of \p a and \p b. - */ -static void -matrix_multiply3x4 (float *result, const float *a, const float *b) -{ - int i; - for (i = 0; i < 3; i++) - { - const float ai0 = A(i,0), ai1 = A(i,1), ai2 = A(i,2), ai3 = A(i,3); - R(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0); - R(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1); - R(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2); - R(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3; - } - R(3,0) = 0; - R(3,1) = 0; - R(3,2) = 0; - R(3,3) = 1; -} - -#undef A -#undef B -#undef R - -/* - * Multiply a matrix by an array of floats with known properties. - * - * @mat pointer to a CoglMatrix structure containing the left multiplication - * matrix, and that will receive the product result. - * @m right multiplication matrix array. - * @flags flags of the matrix \p m. - * - * Joins both flags and marks the type and inverse as dirty. Calls - * matrix_multiply3x4() if both matrices are 3D, or matrix_multiply4x4() - * otherwise. - */ -static void -matrix_multiply_array_with_flags (CoglMatrix *result, - const float *array, - unsigned int flags) -{ - result->flags |= (flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); - - if (TEST_MAT_FLAGS (result, MAT_FLAGS_3D)) - matrix_multiply3x4 ((float *)result, (float *)result, array); - else - matrix_multiply4x4 ((float *)result, (float *)result, array); -} - -/* - * Matrix multiplication. - * - * @dest destination matrix. - * @a left matrix. - * @b right matrix. - * - * Joins both flags and marks the type and inverse as dirty. Calls - * matrix_multiply3x4() if both matrices are 3D, or matrix_multiply4x4() - * otherwise. - */ -void -_cogl_matrix_multiply (CoglMatrix *result, - const CoglMatrix *a, - const CoglMatrix *b) -{ - result->flags = (a->flags | - b->flags | - MAT_DIRTY_TYPE | - MAT_DIRTY_INVERSE); - - if (TEST_MAT_FLAGS(result, MAT_FLAGS_3D)) - matrix_multiply3x4 ((float *)result, (float *)a, (float *)b); - else - matrix_multiply4x4 ((float *)result, (float *)a, (float *)b); -} - -/* - * Matrix multiplication. - * - * @dest left and destination matrix. - * @m right matrix array. - * - * Marks the matrix flags with general flag, and type and inverse dirty flags. - * Calls matrix_multiply4x4() for the multiplication. - */ -void -_cogl_matrix_multiply_array (CoglMatrix *result, const float *array) -{ - result->flags |= (MAT_FLAG_GENERAL | - MAT_DIRTY_TYPE | - MAT_DIRTY_INVERSE | - MAT_DIRTY_FLAGS); - - matrix_multiply4x4 ((float *)result, (float *)result, (float *)array); -} - -/* - * Print a matrix array. - * - * @m matrix array. - * - * Called by _cogl_matrix_print() to print a matrix or its inverse. - */ -static void -print_matrix_floats (const float m[16]) -{ - int i; - for (i = 0;i < 4; i++) - g_print ("\t%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] ); -} - -/* - * Dumps the contents of a CoglMatrix structure. - * - * @m pointer to the CoglMatrix structure. - */ -void -_cogl_matrix_print (const CoglMatrix *matrix) -{ - g_print ("Matrix type: %s, flags: %x\n", - types[matrix->type], (int)matrix->flags); - print_matrix_floats ((float *)matrix); - g_print ("Inverse: \n"); - if (!(matrix->flags & MAT_DIRTY_INVERSE)) - { - float prod[16]; - print_matrix_floats (matrix->inv); - matrix_multiply4x4 (prod, (float *)matrix, matrix->inv); - g_print ("Mat * Inverse:\n"); - print_matrix_floats (prod); - } - else - g_print (" - not available\n"); -} - -/* - * References an element of 4x4 matrix. - * - * @m matrix array. - * @c column of the desired element. - * @r row of the desired element. - * - * Returns: value of the desired element. - * - * Calculate the linear storage index of the element and references it. - */ -#define MAT(m,r,c) (m)[(c)*4+(r)] - -/* - * Swaps the values of two floating pointer variables. - * - * Used by invert_matrix_general() to swap the row pointers. - */ -#define SWAP_ROWS(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; } - -/* - * Compute inverse of 4x4 transformation matrix. - * - * @mat pointer to a CoglMatrix structure. The matrix inverse will be - * stored in the CoglMatrix::inv attribute. - * - * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). - * - * \author - * Code contributed by Jacques Leroy jle@star.be - * - * Calculates the inverse matrix by performing the gaussian matrix reduction - * with partial pivoting followed by back/substitution with the loops manually - * unrolled. - */ -static gboolean -invert_matrix_general (CoglMatrix *matrix) -{ - const float *m = (float *)matrix; - float *out = matrix->inv; - float wtmp[4][8]; - float m0, m1, m2, m3, s; - float *r0, *r1, *r2, *r3; - - r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; - - r0[0] = MAT (m, 0, 0), r0[1] = MAT (m, 0, 1), - r0[2] = MAT (m, 0, 2), r0[3] = MAT (m, 0, 3), - r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, - - r1[0] = MAT (m, 1, 0), r1[1] = MAT (m, 1, 1), - r1[2] = MAT (m, 1, 2), r1[3] = MAT (m, 1, 3), - r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, - - r2[0] = MAT (m, 2, 0), r2[1] = MAT (m, 2, 1), - r2[2] = MAT (m, 2, 2), r2[3] = MAT (m, 2, 3), - r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, - - r3[0] = MAT (m, 3, 0), r3[1] = MAT (m, 3, 1), - r3[2] = MAT (m, 3, 2), r3[3] = MAT (m, 3, 3), - r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; - - /* choose pivot - or die */ - if (fabsf (r3[0]) > fabsf (r2[0])) - SWAP_ROWS (r3, r2); - if (fabsf (r2[0]) > fabsf (r1[0])) - SWAP_ROWS (r2, r1); - if (fabsf (r1[0]) > fabsf (r0[0])) - SWAP_ROWS (r1, r0); - if (0.0 == r0[0]) - return FALSE; - - /* eliminate first variable */ - m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0]; - s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; - s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; - s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; - s = r0[4]; - if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } - s = r0[5]; - if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } - s = r0[6]; - if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } - s = r0[7]; - if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } - - /* choose pivot - or die */ - if (fabsf (r3[1]) > fabsf (r2[1])) - SWAP_ROWS (r3, r2); - if (fabsf (r2[1]) > fabsf (r1[1])) - SWAP_ROWS (r2, r1); - if (0.0 == r1[1]) - return FALSE; - - /* eliminate second variable */ - m2 = r2[1] / r1[1]; m3 = r3[1] / r1[1]; - r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; - r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; - s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } - s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } - s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } - s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } - - /* choose pivot - or die */ - if (fabsf (r3[2]) > fabsf (r2[2])) - SWAP_ROWS (r3, r2); - if (0.0 == r2[2]) - return FALSE; - - /* eliminate third variable */ - m3 = r3[2] / r2[2]; - r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], - r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], - r3[7] -= m3 * r2[7]; - - /* last check */ - if (0.0 == r3[3]) - return FALSE; - - s = 1.0f / r3[3]; /* now back substitute row 3 */ - r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; - - m2 = r2[3]; /* now back substitute row 2 */ - s = 1.0f / r2[2]; - r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), - r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); - m1 = r1[3]; - r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, - r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; - m0 = r0[3]; - r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, - r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; - - m1 = r1[2]; /* now back substitute row 1 */ - s = 1.0f / r1[1]; - r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), - r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); - m0 = r0[2]; - r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, - r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; - - m0 = r0[1]; /* now back substitute row 0 */ - s = 1.0f / r0[0]; - r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), - r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); - - MAT (out, 0, 0) = r0[4]; MAT (out, 0, 1) = r0[5], - MAT (out, 0, 2) = r0[6]; MAT (out, 0, 3) = r0[7], - MAT (out, 1, 0) = r1[4]; MAT (out, 1, 1) = r1[5], - MAT (out, 1, 2) = r1[6]; MAT (out, 1, 3) = r1[7], - MAT (out, 2, 0) = r2[4]; MAT (out, 2, 1) = r2[5], - MAT (out, 2, 2) = r2[6]; MAT (out, 2, 3) = r2[7], - MAT (out, 3, 0) = r3[4]; MAT (out, 3, 1) = r3[5], - MAT (out, 3, 2) = r3[6]; MAT (out, 3, 3) = r3[7]; - - return TRUE; -} -#undef SWAP_ROWS - -/* - * Compute inverse of a general 3d transformation matrix. - * - * @mat pointer to a CoglMatrix structure. The matrix inverse will be - * stored in the CoglMatrix::inv attribute. - * - * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). - * - * \author Adapted from graphics gems II. - * - * Calculates the inverse of the upper left by first calculating its - * determinant and multiplying it to the symmetric adjust matrix of each - * element. Finally deals with the translation part by transforming the - * original translation vector using by the calculated submatrix inverse. - */ -static gboolean -invert_matrix_3d_general (CoglMatrix *matrix) -{ - const float *in = (float *)matrix; - float *out = matrix->inv; - float pos, neg, t; - float det; - - /* Calculate the determinant of upper left 3x3 submatrix and - * determine if the matrix is singular. - */ - pos = neg = 0.0; - t = MAT (in,0,0) * MAT (in,1,1) * MAT (in,2,2); - if (t >= 0.0) pos += t; else neg += t; - - t = MAT (in,1,0) * MAT (in,2,1) * MAT (in,0,2); - if (t >= 0.0) pos += t; else neg += t; - - t = MAT (in,2,0) * MAT (in,0,1) * MAT (in,1,2); - if (t >= 0.0) pos += t; else neg += t; - - t = -MAT (in,2,0) * MAT (in,1,1) * MAT (in,0,2); - if (t >= 0.0) pos += t; else neg += t; - - t = -MAT (in,1,0) * MAT (in,0,1) * MAT (in,2,2); - if (t >= 0.0) pos += t; else neg += t; - - t = -MAT (in,0,0) * MAT (in,2,1) * MAT (in,1,2); - if (t >= 0.0) pos += t; else neg += t; - - det = pos + neg; - - if (det*det < 1e-25) - return FALSE; - - det = 1.0f / det; - MAT (out,0,0) = - ( (MAT (in, 1, 1)*MAT (in, 2, 2) - MAT (in, 2, 1)*MAT (in, 1, 2) )*det); - MAT (out,0,1) = - (- (MAT (in, 0, 1)*MAT (in, 2, 2) - MAT (in, 2, 1)*MAT (in, 0, 2) )*det); - MAT (out,0,2) = - ( (MAT (in, 0, 1)*MAT (in, 1, 2) - MAT (in, 1, 1)*MAT (in, 0, 2) )*det); - MAT (out,1,0) = - (- (MAT (in,1,0)*MAT (in,2,2) - MAT (in,2,0)*MAT (in,1,2) )*det); - MAT (out,1,1) = - ( (MAT (in,0,0)*MAT (in,2,2) - MAT (in,2,0)*MAT (in,0,2) )*det); - MAT (out,1,2) = - (- (MAT (in,0,0)*MAT (in,1,2) - MAT (in,1,0)*MAT (in,0,2) )*det); - MAT (out,2,0) = - ( (MAT (in,1,0)*MAT (in,2,1) - MAT (in,2,0)*MAT (in,1,1) )*det); - MAT (out,2,1) = - (- (MAT (in,0,0)*MAT (in,2,1) - MAT (in,2,0)*MAT (in,0,1) )*det); - MAT (out,2,2) = - ( (MAT (in,0,0)*MAT (in,1,1) - MAT (in,1,0)*MAT (in,0,1) )*det); - - /* Do the translation part */ - MAT (out,0,3) = - (MAT (in, 0, 3) * MAT (out, 0, 0) + - MAT (in, 1, 3) * MAT (out, 0, 1) + - MAT (in, 2, 3) * MAT (out, 0, 2) ); - MAT (out,1,3) = - (MAT (in, 0, 3) * MAT (out, 1, 0) + - MAT (in, 1, 3) * MAT (out, 1, 1) + - MAT (in, 2, 3) * MAT (out, 1, 2) ); - MAT (out,2,3) = - (MAT (in, 0, 3) * MAT (out, 2 ,0) + - MAT (in, 1, 3) * MAT (out, 2, 1) + - MAT (in, 2, 3) * MAT (out, 2, 2) ); - - return TRUE; -} - -/* - * Compute inverse of a 3d transformation matrix. - * - * @mat pointer to a CoglMatrix structure. The matrix inverse will be - * stored in the CoglMatrix::inv attribute. - * - * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). - * - * If the matrix is not an angle preserving matrix then calls - * invert_matrix_3d_general for the actual calculation. Otherwise calculates - * the inverse matrix analyzing and inverting each of the scaling, rotation and - * translation parts. - */ -static gboolean -invert_matrix_3d (CoglMatrix *matrix) -{ - const float *in = (float *)matrix; - float *out = matrix->inv; - - if (!TEST_MAT_FLAGS(matrix, MAT_FLAGS_ANGLE_PRESERVING)) - return invert_matrix_3d_general (matrix); - - if (matrix->flags & MAT_FLAG_UNIFORM_SCALE) - { - float scale = (MAT (in, 0, 0) * MAT (in, 0, 0) + - MAT (in, 0, 1) * MAT (in, 0, 1) + - MAT (in, 0, 2) * MAT (in, 0, 2)); - - if (scale == 0.0) - return FALSE; - - scale = 1.0f / scale; - - /* Transpose and scale the 3 by 3 upper-left submatrix. */ - MAT (out, 0, 0) = scale * MAT (in, 0, 0); - MAT (out, 1, 0) = scale * MAT (in, 0, 1); - MAT (out, 2, 0) = scale * MAT (in, 0, 2); - MAT (out, 0, 1) = scale * MAT (in, 1, 0); - MAT (out, 1, 1) = scale * MAT (in, 1, 1); - MAT (out, 2, 1) = scale * MAT (in, 1, 2); - MAT (out, 0, 2) = scale * MAT (in, 2, 0); - MAT (out, 1, 2) = scale * MAT (in, 2, 1); - MAT (out, 2, 2) = scale * MAT (in, 2, 2); - } - else if (matrix->flags & MAT_FLAG_ROTATION) - { - /* Transpose the 3 by 3 upper-left submatrix. */ - MAT (out, 0, 0) = MAT (in, 0, 0); - MAT (out, 1, 0) = MAT (in, 0, 1); - MAT (out, 2, 0) = MAT (in, 0, 2); - MAT (out, 0, 1) = MAT (in, 1, 0); - MAT (out, 1, 1) = MAT (in, 1, 1); - MAT (out, 2, 1) = MAT (in, 1, 2); - MAT (out, 0, 2) = MAT (in, 2, 0); - MAT (out, 1, 2) = MAT (in, 2, 1); - MAT (out, 2, 2) = MAT (in, 2, 2); - } - else - { - /* pure translation */ - memcpy (out, identity, 16 * sizeof (float)); - MAT (out, 0, 3) = - MAT (in, 0, 3); - MAT (out, 1, 3) = - MAT (in, 1, 3); - MAT (out, 2, 3) = - MAT (in, 2, 3); - return TRUE; - } - - if (matrix->flags & MAT_FLAG_TRANSLATION) - { - /* Do the translation part */ - MAT (out,0,3) = - (MAT (in, 0, 3) * MAT (out, 0, 0) + - MAT (in, 1, 3) * MAT (out, 0, 1) + - MAT (in, 2, 3) * MAT (out, 0, 2) ); - MAT (out,1,3) = - (MAT (in, 0, 3) * MAT (out, 1, 0) + - MAT (in, 1, 3) * MAT (out, 1, 1) + - MAT (in, 2, 3) * MAT (out, 1, 2) ); - MAT (out,2,3) = - (MAT (in, 0, 3) * MAT (out, 2, 0) + - MAT (in, 1, 3) * MAT (out, 2, 1) + - MAT (in, 2, 3) * MAT (out, 2, 2) ); - } - else - MAT (out, 0, 3) = MAT (out, 1, 3) = MAT (out, 2, 3) = 0.0; - - return TRUE; -} - -/* - * Compute inverse of an identity transformation matrix. - * - * @mat pointer to a CoglMatrix structure. The matrix inverse will be - * stored in the CoglMatrix::inv attribute. - * - * Returns: always %TRUE. - * - * Simply copies identity into CoglMatrix::inv. - */ -static gboolean -invert_matrix_identity (CoglMatrix *matrix) -{ - memcpy (matrix->inv, identity, 16 * sizeof (float)); - return TRUE; -} - -/* - * Compute inverse of a no-rotation 3d transformation matrix. - * - * @mat pointer to a CoglMatrix structure. The matrix inverse will be - * stored in the CoglMatrix::inv attribute. - * - * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). - * - * Calculates the - */ -static gboolean -invert_matrix_3d_no_rotation (CoglMatrix *matrix) -{ - const float *in = (float *)matrix; - float *out = matrix->inv; - - if (MAT (in,0,0) == 0 || MAT (in,1,1) == 0 || MAT (in,2,2) == 0) - return FALSE; - - memcpy (out, identity, 16 * sizeof (float)); - MAT (out,0,0) = 1.0f / MAT (in,0,0); - MAT (out,1,1) = 1.0f / MAT (in,1,1); - MAT (out,2,2) = 1.0f / MAT (in,2,2); - - if (matrix->flags & MAT_FLAG_TRANSLATION) - { - MAT (out,0,3) = - (MAT (in,0,3) * MAT (out,0,0)); - MAT (out,1,3) = - (MAT (in,1,3) * MAT (out,1,1)); - MAT (out,2,3) = - (MAT (in,2,3) * MAT (out,2,2)); - } - - return TRUE; -} - -/* - * Compute inverse of a no-rotation 2d transformation matrix. - * - * @mat pointer to a CoglMatrix structure. The matrix inverse will be - * stored in the CoglMatrix::inv attribute. - * - * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). - * - * Calculates the inverse matrix by applying the inverse scaling and - * translation to the identity matrix. - */ -static gboolean -invert_matrix_2d_no_rotation (CoglMatrix *matrix) -{ - const float *in = (float *)matrix; - float *out = matrix->inv; - - if (MAT (in, 0, 0) == 0 || MAT (in, 1, 1) == 0) - return FALSE; - - memcpy (out, identity, 16 * sizeof (float)); - MAT (out, 0, 0) = 1.0f / MAT (in, 0, 0); - MAT (out, 1, 1) = 1.0f / MAT (in, 1, 1); - - if (matrix->flags & MAT_FLAG_TRANSLATION) - { - MAT (out, 0, 3) = - (MAT (in, 0, 3) * MAT (out, 0, 0)); - MAT (out, 1, 3) = - (MAT (in, 1, 3) * MAT (out, 1, 1)); - } - - return TRUE; -} - -#if 0 -/* broken */ -static gboolean -invert_matrix_perspective (CoglMatrix *matrix) -{ - const float *in = matrix; - float *out = matrix->inv; - - if (MAT (in,2,3) == 0) - return FALSE; - - memcpy( out, identity, 16 * sizeof(float) ); - - MAT (out, 0, 0) = 1.0f / MAT (in, 0, 0); - MAT (out, 1, 1) = 1.0f / MAT (in, 1, 1); - - MAT (out, 0, 3) = MAT (in, 0, 2); - MAT (out, 1, 3) = MAT (in, 1, 2); - - MAT (out,2,2) = 0; - MAT (out,2,3) = -1; - - MAT (out,3,2) = 1.0f / MAT (in,2,3); - MAT (out,3,3) = MAT (in,2,2) * MAT (out,3,2); - - return TRUE; -} -#endif - -/* - * Matrix inversion function pointer type. - */ -typedef gboolean (*inv_mat_func)(CoglMatrix *matrix); - -/* - * Table of the matrix inversion functions according to the matrix type. - */ -static inv_mat_func inv_mat_tab[7] = { - invert_matrix_general, - invert_matrix_identity, - invert_matrix_3d_no_rotation, -#if 0 - /* Don't use this function for now - it fails when the projection matrix - * is premultiplied by a translation (ala Chromium's tilesort SPU). - */ - invert_matrix_perspective, -#else - invert_matrix_general, -#endif - invert_matrix_3d, /* lazy! */ - invert_matrix_2d_no_rotation, - invert_matrix_3d -}; - -/* - * Compute inverse of a transformation matrix. - * - * @mat pointer to a CoglMatrix structure. The matrix inverse will be - * stored in the CoglMatrix::inv attribute. - * - * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). - * - * Calls the matrix inversion function in inv_mat_tab corresponding to the - * given matrix type. In case of failure, updates the MAT_FLAG_SINGULAR flag, - * and copies the identity matrix into CoglMatrix::inv. - */ -gboolean -_cogl_matrix_update_inverse (CoglMatrix *matrix) -{ - if (matrix->flags & MAT_DIRTY_FLAGS || - matrix->flags & MAT_DIRTY_INVERSE) - { - _cogl_matrix_update_type_and_flags (matrix); - - if (inv_mat_tab[matrix->type](matrix)) - matrix->flags &= ~MAT_FLAG_SINGULAR; - else - { - matrix->flags |= MAT_FLAG_SINGULAR; - memcpy (matrix->inv, identity, 16 * sizeof (float)); - } - - matrix->flags &= ~MAT_DIRTY_INVERSE; - } - - if (matrix->flags & MAT_FLAG_SINGULAR) - return FALSE; - else - return TRUE; -} - -/* - * Generate a 4x4 transformation matrix from glRotate parameters, and - * post-multiply the input matrix by it. - * - * \author - * This function was contributed by Erich Boleyn (erich@uruk.org). - * Optimizations contributed by Rudolf Opalla (rudi@khm.de). - */ -void -_cogl_matrix_rotate (CoglMatrix *matrix, - float angle, - float x, - float y, - float z) -{ - float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c; - float m[16]; - gboolean optimized; - - s = sinf (angle * DEG2RAD); - c = cosf (angle * DEG2RAD); - - memcpy (m, identity, 16 * sizeof (float)); - optimized = FALSE; - -#define M(row,col) m[col*4+row] - - if (x == 0.0f) - { - if (y == 0.0f) - { - if (z != 0.0f) - { - optimized = TRUE; - /* rotate only around z-axis */ - M (0,0) = c; - M (1,1) = c; - if (z < 0.0f) - { - M (0,1) = s; - M (1,0) = -s; - } - else - { - M (0,1) = -s; - M (1,0) = s; - } - } - } - else if (z == 0.0f) - { - optimized = TRUE; - /* rotate only around y-axis */ - M (0,0) = c; - M (2,2) = c; - if (y < 0.0f) - { - M (0,2) = -s; - M (2,0) = s; - } - else - { - M (0,2) = s; - M (2,0) = -s; - } - } - } - else if (y == 0.0f) - { - if (z == 0.0f) - { - optimized = TRUE; - /* rotate only around x-axis */ - M (1,1) = c; - M (2,2) = c; - if (x < 0.0f) - { - M (1,2) = s; - M (2,1) = -s; - } - else - { - M (1,2) = -s; - M (2,1) = s; - } - } - } - - if (!optimized) - { - const float mag = sqrtf (x * x + y * y + z * z); - - if (mag <= 1.0e-4) - { - /* no rotation, leave mat as-is */ - return; - } - - x /= mag; - y /= mag; - z /= mag; - - - /* - * Arbitrary axis rotation matrix. - * - * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied - * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation - * (which is about the X-axis), and the two composite transforms - * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary - * from the arbitrary axis to the X-axis then back. They are - * all elementary rotations. - * - * Rz' is a rotation about the Z-axis, to bring the axis vector - * into the x-z plane. Then Ry' is applied, rotating about the - * Y-axis to bring the axis vector parallel with the X-axis. The - * rotation about the X-axis is then performed. Ry and Rz are - * simply the respective inverse transforms to bring the arbitrary - * axis back to it's original orientation. The first transforms - * Rz' and Ry' are considered inverses, since the data from the - * arbitrary axis gives you info on how to get to it, not how - * to get away from it, and an inverse must be applied. - * - * The basic calculation used is to recognize that the arbitrary - * axis vector (x, y, z), since it is of unit length, actually - * represents the sines and cosines of the angles to rotate the - * X-axis to the same orientation, with theta being the angle about - * Z and phi the angle about Y (in the order described above) - * as follows: - * - * cos ( theta ) = x / sqrt ( 1 - z^2 ) - * sin ( theta ) = y / sqrt ( 1 - z^2 ) - * - * cos ( phi ) = sqrt ( 1 - z^2 ) - * sin ( phi ) = z - * - * Note that cos ( phi ) can further be inserted to the above - * formulas: - * - * cos ( theta ) = x / cos ( phi ) - * sin ( theta ) = y / sin ( phi ) - * - * ...etc. Because of those relations and the standard trigonometric - * relations, it is pssible to reduce the transforms down to what - * is used below. It may be that any primary axis chosen will give the - * same results (modulo a sign convention) using thie method. - * - * Particularly nice is to notice that all divisions that might - * have caused trouble when parallel to certain planes or - * axis go away with care paid to reducing the expressions. - * After checking, it does perform correctly under all cases, since - * in all the cases of division where the denominator would have - * been zero, the numerator would have been zero as well, giving - * the expected result. - */ - - xx = x * x; - yy = y * y; - zz = z * z; - xy = x * y; - yz = y * z; - zx = z * x; - xs = x * s; - ys = y * s; - zs = z * s; - one_c = 1.0f - c; - - /* We already hold the identity-matrix so we can skip some statements */ - M (0,0) = (one_c * xx) + c; - M (0,1) = (one_c * xy) - zs; - M (0,2) = (one_c * zx) + ys; - /* M (0,3) = 0.0f; */ - - M (1,0) = (one_c * xy) + zs; - M (1,1) = (one_c * yy) + c; - M (1,2) = (one_c * yz) - xs; - /* M (1,3) = 0.0f; */ - - M (2,0) = (one_c * zx) - ys; - M (2,1) = (one_c * yz) + xs; - M (2,2) = (one_c * zz) + c; - /* M (2,3) = 0.0f; */ - - /* - M (3,0) = 0.0f; - M (3,1) = 0.0f; - M (3,2) = 0.0f; - M (3,3) = 1.0f; - */ - } -#undef M - - matrix_multiply_array_with_flags (matrix, m, MAT_FLAG_ROTATION); -} - -/* - * Apply a perspective projection matrix. - * - * @mat matrix to apply the projection. - * @left left clipping plane coordinate. - * @right right clipping plane coordinate. - * @bottom bottom clipping plane coordinate. - * @top top clipping plane coordinate. - * @nearval distance to the near clipping plane. - * @farval distance to the far clipping plane. - * - * Creates the projection matrix and multiplies it with \p mat, marking the - * MAT_FLAG_PERSPECTIVE flag. - */ -void -_cogl_matrix_frustum (CoglMatrix *matrix, - float left, - float right, - float bottom, - float top, - float nearval, - float farval) -{ - float x, y, a, b, c, d; - float m[16]; - - x = (2.0f * nearval) / (right - left); - y = (2.0f * nearval) / (top - bottom); - a = (right + left) / (right - left); - b = (top + bottom) / (top - bottom); - c = -(farval + nearval) / ( farval - nearval); - d = -(2.0f * farval * nearval) / (farval - nearval); /* error? */ - -#define M(row,col) m[col*4+row] - M (0,0) = x; M (0,1) = 0.0f; M (0,2) = a; M (0,3) = 0.0f; - M (1,0) = 0.0f; M (1,1) = y; M (1,2) = b; M (1,3) = 0.0f; - M (2,0) = 0.0f; M (2,1) = 0.0f; M (2,2) = c; M (2,3) = d; - M (3,0) = 0.0f; M (3,1) = 0.0f; M (3,2) = -1.0f; M (3,3) = 0.0f; -#undef M - - matrix_multiply_array_with_flags (matrix, m, MAT_FLAG_PERSPECTIVE); -} - -/* - * Apply an orthographic projection matrix. - * - * @mat matrix to apply the projection. - * @left left clipping plane coordinate. - * @right right clipping plane coordinate. - * @bottom bottom clipping plane coordinate. - * @top top clipping plane coordinate. - * @nearval distance to the near clipping plane. - * @farval distance to the far clipping plane. - * - * Creates the projection matrix and multiplies it with \p mat, marking the - * MAT_FLAG_GENERAL_SCALE and MAT_FLAG_TRANSLATION flags. - */ -void -_cogl_matrix_ortho (CoglMatrix *matrix, - float left, - float right, - float bottom, - float top, - float nearval, - float farval) -{ - float m[16]; - -#define M(row,col) m[col*4+row] - M (0,0) = 2.0f / (right-left); - M (0,1) = 0.0f; - M (0,2) = 0.0f; - M (0,3) = -(right+left) / (right-left); - - M (1,0) = 0.0f; - M (1,1) = 2.0f / (top-bottom); - M (1,2) = 0.0f; - M (1,3) = -(top+bottom) / (top-bottom); - - M (2,0) = 0.0f; - M (2,1) = 0.0f; - M (2,2) = -2.0f / (farval-nearval); - M (2,3) = -(farval+nearval) / (farval-nearval); - - M (3,0) = 0.0f; - M (3,1) = 0.0f; - M (3,2) = 0.0f; - M (3,3) = 1.0f; -#undef M - - matrix_multiply_array_with_flags (matrix, m, - (MAT_FLAG_GENERAL_SCALE | - MAT_FLAG_TRANSLATION)); -} - -/* - * Multiply a matrix with a general scaling matrix. - * - * @mat matrix. - * @x x axis scale factor. - * @y y axis scale factor. - * @z z axis scale factor. - * - * Multiplies in-place the elements of \p mat by the scale factors. Checks if - * the scales factors are roughly the same, marking the MAT_FLAG_UNIFORM_SCALE - * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE and - * MAT_DIRTY_INVERSE dirty flags. - */ -void -_cogl_matrix_scale (CoglMatrix *matrix, float x, float y, float z) -{ - float *m = (float *)matrix; - m[0] *= x; m[4] *= y; m[8] *= z; - m[1] *= x; m[5] *= y; m[9] *= z; - m[2] *= x; m[6] *= y; m[10] *= z; - m[3] *= x; m[7] *= y; m[11] *= z; - - if (fabsf (x - y) < 1e-8 && fabsf (x - z) < 1e-8) - matrix->flags |= MAT_FLAG_UNIFORM_SCALE; - else - matrix->flags |= MAT_FLAG_GENERAL_SCALE; - - matrix->flags |= (MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); -} - -/* - * Multiply a matrix with a translation matrix. - * - * @mat matrix. - * @x translation vector x coordinate. - * @y translation vector y coordinate. - * @z translation vector z coordinate. - * - * Adds the translation coordinates to the elements of \p mat in-place. Marks - * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and MAT_DIRTY_INVERSE - * dirty flags. - */ -void -_cogl_matrix_translate (CoglMatrix *matrix, float x, float y, float z) -{ - float *m = (float *)matrix; - m[12] = m[0] * x + m[4] * y + m[8] * z + m[12]; - m[13] = m[1] * x + m[5] * y + m[9] * z + m[13]; - m[14] = m[2] * x + m[6] * y + m[10] * z + m[14]; - m[15] = m[3] * x + m[7] * y + m[11] * z + m[15]; - - matrix->flags |= (MAT_FLAG_TRANSLATION | - MAT_DIRTY_TYPE | - MAT_DIRTY_INVERSE); -} - -/* - * Set matrix to do viewport and depthrange mapping. - * Transforms Normalized Device Coords to window/Z values. - */ -void -_cogl_matrix_viewport (CoglMatrix *matrix, - float x, float y, - float width, float height, - float zNear, float zFar, float depthMax) -{ - float *m = (float *)matrix; - m[MAT_SX] = width / 2.0f; - m[MAT_TX] = m[MAT_SX] + x; - m[MAT_SY] = height / 2.0f; - m[MAT_TY] = m[MAT_SY] + y; - m[MAT_SZ] = depthMax * ((zFar - zNear) / 2.0f); - m[MAT_TZ] = depthMax * ((zFar - zNear) / 2.0f + zNear); - matrix->flags = MAT_FLAG_GENERAL_SCALE | MAT_FLAG_TRANSLATION; - matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT; -} - - -/* - * Set a matrix to the identity matrix. - * - * @mat matrix. - * - * Copies ::identity into \p CoglMatrix::m, and into CoglMatrix::inv if - * not NULL. Sets the matrix type to identity, resets the flags. It - * doesn't initialize the inverse matrix, it just marks it dirty. - */ -void -_cogl_matrix_init_identity (CoglMatrix *matrix) -{ - memcpy (matrix, identity, 16 * sizeof (float)); - - matrix->type = COGL_MATRIX_TYPE_IDENTITY; - matrix->flags = MAT_DIRTY_INVERSE; -} - -#define ZERO(x) (1<flags &= ~MAT_FLAGS_GEOMETRY; - - /* Check for translation - no-one really cares - */ - if ((mask & MASK_NO_TRX) != MASK_NO_TRX) - matrix->flags |= MAT_FLAG_TRANSLATION; - - /* Do the real work - */ - if (mask == (unsigned int) MASK_IDENTITY) - matrix->type = COGL_MATRIX_TYPE_IDENTITY; - else if ((mask & MASK_2D_NO_ROT) == (unsigned int) MASK_2D_NO_ROT) - { - matrix->type = COGL_MATRIX_TYPE_2D_NO_ROT; - - if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE) - matrix->flags |= MAT_FLAG_GENERAL_SCALE; - } - else if ((mask & MASK_2D) == (unsigned int) MASK_2D) - { - float mm = DOT2 (m, m); - float m4m4 = DOT2 (m+4,m+4); - float mm4 = DOT2 (m,m+4); - - matrix->type = COGL_MATRIX_TYPE_2D; - - /* Check for scale */ - if (SQ (mm-1) > SQ (1e-6) || - SQ (m4m4-1) > SQ (1e-6)) - matrix->flags |= MAT_FLAG_GENERAL_SCALE; - - /* Check for rotation */ - if (SQ (mm4) > SQ (1e-6)) - matrix->flags |= MAT_FLAG_GENERAL_3D; - else - matrix->flags |= MAT_FLAG_ROTATION; - - } - else if ((mask & MASK_3D_NO_ROT) == (unsigned int) MASK_3D_NO_ROT) - { - matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT; - - /* Check for scale */ - if (SQ (m[0]-m[5]) < SQ (1e-6) && - SQ (m[0]-m[10]) < SQ (1e-6)) - { - if (SQ (m[0]-1.0) > SQ (1e-6)) - matrix->flags |= MAT_FLAG_UNIFORM_SCALE; - } - else - matrix->flags |= MAT_FLAG_GENERAL_SCALE; - } - else if ((mask & MASK_3D) == (unsigned int) MASK_3D) - { - float c1 = DOT3 (m,m); - float c2 = DOT3 (m+4,m+4); - float c3 = DOT3 (m+8,m+8); - float d1 = DOT3 (m, m+4); - float cp[3]; - - matrix->type = COGL_MATRIX_TYPE_3D; - - /* Check for scale */ - if (SQ (c1-c2) < SQ (1e-6) && SQ (c1-c3) < SQ (1e-6)) - { - if (SQ (c1-1.0) > SQ (1e-6)) - matrix->flags |= MAT_FLAG_UNIFORM_SCALE; - /* else no scale at all */ - } - else - matrix->flags |= MAT_FLAG_GENERAL_SCALE; - - /* Check for rotation */ - if (SQ (d1) < SQ (1e-6)) - { - CROSS3 ( cp, m, m+4); - SUB_3V ( cp, cp, (m+8)); - if (LEN_SQUARED_3FV(cp) < SQ(1e-6)) - matrix->flags |= MAT_FLAG_ROTATION; - else - matrix->flags |= MAT_FLAG_GENERAL_3D; - } - else - matrix->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */ - } - else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0f) - { - matrix->type = COGL_MATRIX_TYPE_PERSPECTIVE; - matrix->flags |= MAT_FLAG_GENERAL; - } - else - { - matrix->type = COGL_MATRIX_TYPE_GENERAL; - matrix->flags |= MAT_FLAG_GENERAL; - } -} - -/* - * Analyze a matrix given that its flags are accurate. - * - * This is the more common operation, hopefully. - */ -static void -analyse_from_flags (CoglMatrix *matrix) -{ - const float *m = (float *)matrix; - - if (TEST_MAT_FLAGS(matrix, 0)) - matrix->type = COGL_MATRIX_TYPE_IDENTITY; - else if (TEST_MAT_FLAGS(matrix, (MAT_FLAG_TRANSLATION | - MAT_FLAG_UNIFORM_SCALE | - MAT_FLAG_GENERAL_SCALE))) - { - if ( m[10] == 1.0f && m[14] == 0.0f ) - matrix->type = COGL_MATRIX_TYPE_2D_NO_ROT; - else - matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT; - } - else if (TEST_MAT_FLAGS (matrix, MAT_FLAGS_3D)) - { - if ( m[ 8]==0.0f - && m[ 9]==0.0f - && m[2]==0.0f && m[6]==0.0f && m[10]==1.0f && m[14]==0.0f) - { - matrix->type = COGL_MATRIX_TYPE_2D; - } - else - matrix->type = COGL_MATRIX_TYPE_3D; - } - else if ( m[4]==0.0f && m[12]==0.0f - && m[1]==0.0f && m[13]==0.0f - && m[2]==0.0f && m[6]==0.0f - && m[3]==0.0f && m[7]==0.0f && m[11]==-1.0f && m[15]==0.0f) - { - matrix->type = COGL_MATRIX_TYPE_PERSPECTIVE; - } - else - matrix->type = COGL_MATRIX_TYPE_GENERAL; -} - -/* - * Analyze and update the type and flags of a matrix. - * - * @mat matrix. - * - * If the matrix type is dirty then calls either analyse_from_scratch() or - * analyse_from_flags() to determine its type, according to whether the flags - * are dirty or not, respectively. If the matrix has an inverse and it's dirty - * then calls matrix_invert(). Finally clears the dirty flags. - */ -void -_cogl_matrix_update_type_and_flags (CoglMatrix *matrix) -{ - if (matrix->flags & MAT_DIRTY_TYPE) - { - if (matrix->flags & MAT_DIRTY_FLAGS) - analyse_from_scratch (matrix); - else - analyse_from_flags (matrix); - } - - matrix->flags &= ~(MAT_DIRTY_FLAGS | MAT_DIRTY_TYPE); -} - -/* - * Test if the given matrix preserves vector lengths. - */ -gboolean -_cogl_matrix_is_length_preserving (const CoglMatrix *m) -{ - return TEST_MAT_FLAGS (m, MAT_FLAGS_LENGTH_PRESERVING); -} - -/* - * Test if the given matrix does any rotation. - * (or perhaps if the upper-left 3x3 is non-identity) - */ -gboolean -_cogl_matrix_has_rotation (const CoglMatrix *matrix) -{ - if (matrix->flags & (MAT_FLAG_GENERAL | - MAT_FLAG_ROTATION | - MAT_FLAG_GENERAL_3D | - MAT_FLAG_PERSPECTIVE)) - return TRUE; - else - return FALSE; -} - -gboolean -_cogl_matrix_is_general_scale (const CoglMatrix *matrix) -{ - return (matrix->flags & MAT_FLAG_GENERAL_SCALE) ? TRUE : FALSE; -} - -gboolean -_cogl_matrix_is_dirty (const CoglMatrix *matrix) -{ - return (matrix->flags & MAT_DIRTY_ALL) ? TRUE : FALSE; -} - -/* - * Loads a matrix array into CoglMatrix. - * - * @m matrix array. - * @mat matrix. - * - * Copies \p m into CoglMatrix::m and marks the MAT_FLAG_GENERAL and - * MAT_DIRTY_ALL - * flags. - */ -void -_cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array) -{ - memcpy (matrix, array, 16 * sizeof (float)); - matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL); -} - -void -_cogl_matrix_init_from_quaternion (CoglMatrix *matrix, - CoglQuaternion *quaternion) -{ - float qnorm = _COGL_QUATERNION_NORM (quaternion); - float s = (qnorm > 0.0f) ? (2.0f / qnorm) : 0.0f; - float xs = quaternion->x * s; - float ys = quaternion->y * s; - float zs = quaternion->z * s; - float wx = quaternion->w * xs; - float wy = quaternion->w * ys; - float wz = quaternion->w * zs; - float xx = quaternion->x * xs; - float xy = quaternion->x * ys; - float xz = quaternion->x * zs; - float yy = quaternion->y * ys; - float yz = quaternion->y * zs; - float zz = quaternion->z * zs; - - matrix->xx = 1.0f - (yy + zz); - matrix->yx = xy + wz; - matrix->zx = xz - wy; - matrix->xy = xy - wz; - matrix->yy = 1.0f - (xx + zz); - matrix->zy = yz + wx; - matrix->xz = xz + wy; - matrix->yz = yz - wx; - matrix->zz = 1.0f - (xx + yy); - matrix->xw = matrix->yw = matrix->zw = 0.0f; - matrix->wx = matrix->wy = matrix->wz = 0.0f; - matrix->ww = 1.0f; - - matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL); -} - -/* - * Transpose a float matrix. - * - * @to destination array. - * @from source array. - */ -void -_math_transposef (float to[16], const float from[16]) -{ - to[0] = from[0]; - to[1] = from[4]; - to[2] = from[8]; - to[3] = from[12]; - to[4] = from[1]; - to[5] = from[5]; - to[6] = from[9]; - to[7] = from[13]; - to[8] = from[2]; - to[9] = from[6]; - to[10] = from[10]; - to[11] = from[14]; - to[12] = from[3]; - to[13] = from[7]; - to[14] = from[11]; - to[15] = from[15]; -} diff --git a/cogl/cogl-matrix-mesa.h b/cogl/cogl-matrix-mesa.h deleted file mode 100644 index d87688135..000000000 --- a/cogl/cogl-matrix-mesa.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Cogl - * - * An object oriented GL/GLES Abstraction/Utility Layer - * - * Copyright (C) 2009 Intel Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * - */ -/* - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/* - * \file math/m_matrix.h - * Defines basic structures for matrix-handling. - */ - -#ifndef _M_MATRIX_H -#define _M_MATRIX_H - -#include -#include - -#include - -/* - * Symbolic names to some of the entries in the matrix - * - * These are handy for the viewport mapping, which is expressed as a matrix. - */ -#define MAT_SX 0 -#define MAT_SY 5 -#define MAT_SZ 10 -#define MAT_TX 12 -#define MAT_TY 13 -#define MAT_TZ 14 - -/* - * These identify different kinds of 4x4 transformation matrices and we use - * this information to find fast-paths when available. - */ -enum CoglMatrixType { - COGL_MATRIX_TYPE_GENERAL, /**< general 4x4 matrix */ - COGL_MATRIX_TYPE_IDENTITY, /**< identity matrix */ - COGL_MATRIX_TYPE_3D_NO_ROT, /**< orthogonal projection and others... */ - COGL_MATRIX_TYPE_PERSPECTIVE, /**< perspective projection matrix */ - COGL_MATRIX_TYPE_2D, /**< 2-D transformation */ - COGL_MATRIX_TYPE_2D_NO_ROT, /**< 2-D scale & translate only */ - COGL_MATRIX_TYPE_3D /**< 3-D transformation */ -} ; - -void -_cogl_matrix_multiply (CoglMatrix *result, - const CoglMatrix *a, - const CoglMatrix *b); - -void -_cogl_matrix_multiply_array (CoglMatrix *result, const float *b); - -void -_cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array); - -void -_cogl_matrix_init_from_quaternion (CoglMatrix *matrix, - CoglQuaternion *quaternion); - -void -_cogl_matrix_translate (CoglMatrix *matrix, float x, float y, float z); - -void -_cogl_matrix_rotate (CoglMatrix *matrix, float angle, - float x, float y, float z); - -void -_cogl_matrix_scale (CoglMatrix *matrix, float x, float y, float z); - -void -_cogl_matrix_ortho (CoglMatrix *matrix, - float left, float right, - float bottom, float top, - float nearval, float farval); - -void -_cogl_matrix_frustum (CoglMatrix *matrix, - float left, float right, - float bottom, float top, - float nearval, float farval); - -void -_cogl_matrix_viewport (CoglMatrix *matrix, - float x, float y, float width, float height, - float z_near, float z_far, float depth_max); - -void -_cogl_matrix_init_identity (CoglMatrix *matrix); - -gboolean -_cogl_matrix_update_inverse (CoglMatrix *matrix); - -void -_cogl_matrix_update_type_and_flags (CoglMatrix *matrix); - -void -_cogl_matrix_print (const CoglMatrix *matrix); - -gboolean -_cogl_matrix_is_length_preserving (const CoglMatrix *matrix); - -gboolean -_cogl_matrix_has_rotation (const CoglMatrix *matrix); - -gboolean -_cogl_matrix_is_general_scale (const CoglMatrix *matrix); - -gboolean -_cogl_matrix_is_dirty (const CoglMatrix *matrix); - -void -_cogl_matrix_util_transposef ( float to[16], const float from[16]); - -#endif diff --git a/cogl/cogl-matrix.c b/cogl/cogl-matrix.c index 06c5fa1ed..51c98fb83 100644 --- a/cogl/cogl-matrix.c +++ b/cogl/cogl-matrix.c @@ -3,7 +3,7 @@ * * An object oriented GL/GLES Abstraction/Utility Layer * - * Copyright (C) 2008,2009 Intel Corporation. + * Copyright (C) 2009,2010,2011 Intel Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,27 +18,60 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * - * - * * Authors: * Robert Bragg */ +/* + * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Note: a lot of this code is based on code that was taken from Mesa. + * + * Changes compared to the original code from Mesa: + * + * - instead of allocating matrix->m and matrix->inv using malloc, our + * public CoglMatrix typedef is large enough to directly contain the + * matrix, its inverse, a type and a set of flags. + * - instead of having a _cogl_matrix_analyse which updates the type, + * flags and inverse, we have _cogl_matrix_update_inverse which + * essentially does the same thing (internally making use of + * _cogl_matrix_update_type_and_flags()) but with additional guards in + * place to bail out when the inverse matrix is still valid. + * - when initializing a matrix with the identity matrix we don't + * immediately initialize the inverse matrix; rather we just set the + * dirty flag for the inverse (since it's likely the user won't request + * the inverse of the identity matrix) + */ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#define USE_MESA_MATRIX_API - #include -#include "cogl-debug.h" +#include #include #include #include #include -#ifdef USE_MESA_MATRIX_API -#include -#endif +#include #include #include @@ -51,25 +84,248 @@ COGL_GTYPE_DEFINE_BOXED ("Matrix", matrix, cogl_matrix_free); #endif -void -cogl_matrix_init_identity (CoglMatrix *matrix) +/* + * Symbolic names to some of the entries in the matrix + * + * These are handy for the viewport mapping, which is expressed as a matrix. + */ +#define MAT_SX 0 +#define MAT_SY 5 +#define MAT_SZ 10 +#define MAT_TX 12 +#define MAT_TY 13 +#define MAT_TZ 14 + +/* + * These identify different kinds of 4x4 transformation matrices and we use + * this information to find fast-paths when available. + */ +enum CoglMatrixType { + COGL_MATRIX_TYPE_GENERAL, /**< general 4x4 matrix */ + COGL_MATRIX_TYPE_IDENTITY, /**< identity matrix */ + COGL_MATRIX_TYPE_3D_NO_ROT, /**< orthogonal projection and others... */ + COGL_MATRIX_TYPE_PERSPECTIVE, /**< perspective projection matrix */ + COGL_MATRIX_TYPE_2D, /**< 2-D transformation */ + COGL_MATRIX_TYPE_2D_NO_ROT, /**< 2-D scale & translate only */ + COGL_MATRIX_TYPE_3D /**< 3-D transformation */ +} ; + +#define DEG2RAD (G_PI/180.0) + +/* Dot product of two 2-element vectors */ +#define DOT2(A,B) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] ) + +/* Dot product of two 3-element vectors */ +#define DOT3(A,B) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] ) + +#define CROSS3(N, U, V) \ +do { \ + (N)[0] = (U)[1]*(V)[2] - (U)[2]*(V)[1]; \ + (N)[1] = (U)[2]*(V)[0] - (U)[0]*(V)[2]; \ + (N)[2] = (U)[0]*(V)[1] - (U)[1]*(V)[0]; \ +} while (0) + +#define SUB_3V(DST, SRCA, SRCB) \ +do { \ + (DST)[0] = (SRCA)[0] - (SRCB)[0]; \ + (DST)[1] = (SRCA)[1] - (SRCB)[1]; \ + (DST)[2] = (SRCA)[2] - (SRCB)[2]; \ +} while (0) + +#define LEN_SQUARED_3FV( V ) ((V)[0]*(V)[0]+(V)[1]*(V)[1]+(V)[2]*(V)[2]) + +/* + * \defgroup MatFlags MAT_FLAG_XXX-flags + * + * Bitmasks to indicate different kinds of 4x4 matrices in CoglMatrix::flags + */ +#define MAT_FLAG_IDENTITY 0 /*< is an identity matrix flag. + * (Not actually used - the identity + * matrix is identified by the absense + * of all other flags.) + */ +#define MAT_FLAG_GENERAL 0x1 /*< is a general matrix flag */ +#define MAT_FLAG_ROTATION 0x2 /*< is a rotation matrix flag */ +#define MAT_FLAG_TRANSLATION 0x4 /*< is a translation matrix flag */ +#define MAT_FLAG_UNIFORM_SCALE 0x8 /*< is an uniform scaling matrix flag */ +#define MAT_FLAG_GENERAL_SCALE 0x10 /*< is a general scaling matrix flag */ +#define MAT_FLAG_GENERAL_3D 0x20 /*< general 3D matrix flag */ +#define MAT_FLAG_PERSPECTIVE 0x40 /*< is a perspective proj matrix flag */ +#define MAT_FLAG_SINGULAR 0x80 /*< is a singular matrix flag */ +#define MAT_DIRTY_TYPE 0x100 /*< matrix type is dirty */ +#define MAT_DIRTY_FLAGS 0x200 /*< matrix flags are dirty */ +#define MAT_DIRTY_INVERSE 0x400 /*< matrix inverse is dirty */ + +/* angle preserving matrix flags mask */ +#define MAT_FLAGS_ANGLE_PRESERVING (MAT_FLAG_ROTATION | \ + MAT_FLAG_TRANSLATION | \ + MAT_FLAG_UNIFORM_SCALE) + +/* geometry related matrix flags mask */ +#define MAT_FLAGS_GEOMETRY (MAT_FLAG_GENERAL | \ + MAT_FLAG_ROTATION | \ + MAT_FLAG_TRANSLATION | \ + MAT_FLAG_UNIFORM_SCALE | \ + MAT_FLAG_GENERAL_SCALE | \ + MAT_FLAG_GENERAL_3D | \ + MAT_FLAG_PERSPECTIVE | \ + MAT_FLAG_SINGULAR) + +/* length preserving matrix flags mask */ +#define MAT_FLAGS_LENGTH_PRESERVING (MAT_FLAG_ROTATION | \ + MAT_FLAG_TRANSLATION) + + +/* 3D (non-perspective) matrix flags mask */ +#define MAT_FLAGS_3D (MAT_FLAG_ROTATION | \ + MAT_FLAG_TRANSLATION | \ + MAT_FLAG_UNIFORM_SCALE | \ + MAT_FLAG_GENERAL_SCALE | \ + MAT_FLAG_GENERAL_3D) + +/* dirty matrix flags mask */ +#define MAT_DIRTY_ALL (MAT_DIRTY_TYPE | \ + MAT_DIRTY_FLAGS | \ + MAT_DIRTY_INVERSE) + + +/* + * Test geometry related matrix flags. + * + * @mat a pointer to a CoglMatrix structure. + * @a flags mask. + * + * Returns: non-zero if all geometry related matrix flags are contained within + * the mask, or zero otherwise. + */ +#define TEST_MAT_FLAGS(mat, a) \ + ((MAT_FLAGS_GEOMETRY & (~(a)) & ((mat)->flags) ) == 0) + + + +/* + * Names of the corresponding CoglMatrixType values. + */ +static const char *types[] = { + "COGL_MATRIX_TYPE_GENERAL", + "COGL_MATRIX_TYPE_IDENTITY", + "COGL_MATRIX_TYPE_3D_NO_ROT", + "COGL_MATRIX_TYPE_PERSPECTIVE", + "COGL_MATRIX_TYPE_2D", + "COGL_MATRIX_TYPE_2D_NO_ROT", + "COGL_MATRIX_TYPE_3D" +}; + + +/* + * Identity matrix. + */ +static float identity[16] = { + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 +}; + + +#define A(row,col) a[(col<<2)+row] +#define B(row,col) b[(col<<2)+row] +#define R(row,col) result[(col<<2)+row] + +/* + * Perform a full 4x4 matrix multiplication. + * + * It's assumed that @result != @b. @product == @a is allowed. + * + * KW: 4*16 = 64 multiplications + */ +static void +matrix_multiply4x4 (float *result, const float *a, const float *b) { -#ifndef USE_MESA_MATRIX_API - matrix->xx = 1; matrix->xy = 0; matrix->xz = 0; matrix->xw = 0; - matrix->yx = 0; matrix->yy = 1; matrix->yz = 0; matrix->yw = 0; - matrix->zx = 0; matrix->zy = 0; matrix->zz = 1; matrix->zw = 0; - matrix->wx = 0; matrix->wy = 0; matrix->wz = 0; matrix->ww = 1; -#else - _cogl_matrix_init_identity (matrix); -#endif - _COGL_MATRIX_DEBUG_PRINT (matrix); + int i; + for (i = 0; i < 4; i++) + { + const float ai0 = A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3); + R(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0); + R(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1); + R(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2); + R(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3); + } } -void -cogl_matrix_init_from_quaternion (CoglMatrix *matrix, - CoglQuaternion *quaternion) +/* + * Multiply two matrices known to occupy only the top three rows, such + * as typical model matrices, and orthogonal matrices. + * + * @a matrix. + * @b matrix. + * @product will receive the product of \p a and \p b. + */ +static void +matrix_multiply3x4 (float *result, const float *a, const float *b) { - _cogl_matrix_init_from_quaternion (matrix, quaternion); + int i; + for (i = 0; i < 3; i++) + { + const float ai0 = A(i,0), ai1 = A(i,1), ai2 = A(i,2), ai3 = A(i,3); + R(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0); + R(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1); + R(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2); + R(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3; + } + R(3,0) = 0; + R(3,1) = 0; + R(3,2) = 0; + R(3,3) = 1; +} + +#undef A +#undef B +#undef R + +/* + * Multiply a matrix by an array of floats with known properties. + * + * @mat pointer to a CoglMatrix structure containing the left multiplication + * matrix, and that will receive the product result. + * @m right multiplication matrix array. + * @flags flags of the matrix \p m. + * + * Joins both flags and marks the type and inverse as dirty. Calls + * matrix_multiply3x4() if both matrices are 3D, or matrix_multiply4x4() + * otherwise. + */ +static void +matrix_multiply_array_with_flags (CoglMatrix *result, + const float *array, + unsigned int flags) +{ + result->flags |= (flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); + + if (TEST_MAT_FLAGS (result, MAT_FLAGS_3D)) + matrix_multiply3x4 ((float *)result, (float *)result, array); + else + matrix_multiply4x4 ((float *)result, (float *)result, array); +} + +/* Joins both flags and marks the type and inverse as dirty. Calls + * matrix_multiply3x4() if both matrices are 3D, or matrix_multiply4x4() + * otherwise. + */ +static void +_cogl_matrix_multiply (CoglMatrix *result, + const CoglMatrix *a, + const CoglMatrix *b) +{ + result->flags = (a->flags | + b->flags | + MAT_DIRTY_TYPE | + MAT_DIRTY_INVERSE); + + if (TEST_MAT_FLAGS(result, MAT_FLAGS_3D)) + matrix_multiply3x4 ((float *)result, (float *)a, (float *)b); + else + matrix_multiply4x4 ((float *)result, (float *)a, (float *)b); } void @@ -77,45 +333,999 @@ cogl_matrix_multiply (CoglMatrix *result, const CoglMatrix *a, const CoglMatrix *b) { -#ifndef USE_MESA_MATRIX_API - CoglMatrix r; - - /* row 0 */ - r.xx = a->xx * b->xx + a->xy * b->yx + a->xz * b->zx + a->xw * b->wx; - r.xy = a->xx * b->xy + a->xy * b->yy + a->xz * b->zy + a->xw * b->wy; - r.xz = a->xx * b->xz + a->xy * b->yz + a->xz * b->zz + a->xw * b->wz; - r.xw = a->xx * b->xw + a->xy * b->yw + a->xz * b->zw + a->xw * b->ww; - - /* row 1 */ - r.yx = a->yx * b->xx + a->yy * b->yx + a->yz * b->zx + a->yw * b->wx; - r.yy = a->yx * b->xy + a->yy * b->yy + a->yz * b->zy + a->yw * b->wy; - r.yz = a->yx * b->xz + a->yy * b->yz + a->yz * b->zz + a->yw * b->wz; - r.yw = a->yx * b->xw + a->yy * b->yw + a->yz * b->zw + a->yw * b->ww; - - /* row 2 */ - r.zx = a->zx * b->xx + a->zy * b->yx + a->zz * b->zx + a->zw * b->wx; - r.zy = a->zx * b->xy + a->zy * b->yy + a->zz * b->zy + a->zw * b->wy; - r.zz = a->zx * b->xz + a->zy * b->yz + a->zz * b->zz + a->zw * b->wz; - r.zw = a->zx * b->xw + a->zy * b->yw + a->zz * b->zw + a->zw * b->ww; - - /* row 3 */ - r.wx = a->wx * b->xx + a->wy * b->yx + a->wz * b->zx + a->ww * b->wx; - r.wy = a->wx * b->xy + a->wy * b->yy + a->wz * b->zy + a->ww * b->wy; - r.wz = a->wx * b->xz + a->wy * b->yz + a->wz * b->zz + a->ww * b->wz; - r.ww = a->wx * b->xw + a->wy * b->yw + a->wz * b->zw + a->ww * b->ww; - - /* The idea was that having this unrolled; it might be easier for the - * compiler to vectorize, but that's probably not true. Mesa does it - * using a single for (i=0; i<4; i++) approach, maybe that's better... - */ - - *result = r; -#else _cogl_matrix_multiply (result, a, b); -#endif _COGL_MATRIX_DEBUG_PRINT (result); } +#if 0 +/* Marks the matrix flags with general flag, and type and inverse dirty flags. + * Calls matrix_multiply4x4() for the multiplication. + */ +static void +_cogl_matrix_multiply_array (CoglMatrix *result, const float *array) +{ + result->flags |= (MAT_FLAG_GENERAL | + MAT_DIRTY_TYPE | + MAT_DIRTY_INVERSE | + MAT_DIRTY_FLAGS); + + matrix_multiply4x4 ((float *)result, (float *)result, (float *)array); +} +#endif + +/* + * Print a matrix array. + * + * Called by _cogl_matrix_print() to print a matrix or its inverse. + */ +static void +print_matrix_floats (const float m[16]) +{ + int i; + for (i = 0;i < 4; i++) + g_print ("\t%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] ); +} + +/* + * Dumps the contents of a CoglMatrix structure. + */ +void +_cogl_matrix_print (const CoglMatrix *matrix) +{ + g_print ("Matrix type: %s, flags: %x\n", + types[matrix->type], (int)matrix->flags); + print_matrix_floats ((float *)matrix); + g_print ("Inverse: \n"); + if (!(matrix->flags & MAT_DIRTY_INVERSE)) + { + float prod[16]; + print_matrix_floats (matrix->inv); + matrix_multiply4x4 (prod, (float *)matrix, matrix->inv); + g_print ("Mat * Inverse:\n"); + print_matrix_floats (prod); + } + else + g_print (" - not available\n"); +} + +/* + * References an element of 4x4 matrix. + * + * @m matrix array. + * @c column of the desired element. + * @r row of the desired element. + * + * Returns: value of the desired element. + * + * Calculate the linear storage index of the element and references it. + */ +#define MAT(m,r,c) (m)[(c)*4+(r)] + +/* + * Swaps the values of two floating pointer variables. + * + * Used by invert_matrix_general() to swap the row pointers. + */ +#define SWAP_ROWS(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; } + +/* + * Compute inverse of 4x4 transformation matrix. + * + * @mat pointer to a CoglMatrix structure. The matrix inverse will be + * stored in the CoglMatrix::inv attribute. + * + * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). + * + * \author + * Code contributed by Jacques Leroy jle@star.be + * + * Calculates the inverse matrix by performing the gaussian matrix reduction + * with partial pivoting followed by back/substitution with the loops manually + * unrolled. + */ +static gboolean +invert_matrix_general (CoglMatrix *matrix) +{ + const float *m = (float *)matrix; + float *out = matrix->inv; + float wtmp[4][8]; + float m0, m1, m2, m3, s; + float *r0, *r1, *r2, *r3; + + r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; + + r0[0] = MAT (m, 0, 0), r0[1] = MAT (m, 0, 1), + r0[2] = MAT (m, 0, 2), r0[3] = MAT (m, 0, 3), + r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, + + r1[0] = MAT (m, 1, 0), r1[1] = MAT (m, 1, 1), + r1[2] = MAT (m, 1, 2), r1[3] = MAT (m, 1, 3), + r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, + + r2[0] = MAT (m, 2, 0), r2[1] = MAT (m, 2, 1), + r2[2] = MAT (m, 2, 2), r2[3] = MAT (m, 2, 3), + r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, + + r3[0] = MAT (m, 3, 0), r3[1] = MAT (m, 3, 1), + r3[2] = MAT (m, 3, 2), r3[3] = MAT (m, 3, 3), + r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; + + /* choose pivot - or die */ + if (fabsf (r3[0]) > fabsf (r2[0])) + SWAP_ROWS (r3, r2); + if (fabsf (r2[0]) > fabsf (r1[0])) + SWAP_ROWS (r2, r1); + if (fabsf (r1[0]) > fabsf (r0[0])) + SWAP_ROWS (r1, r0); + if (0.0 == r0[0]) + return FALSE; + + /* eliminate first variable */ + m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0]; + s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; + s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; + s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; + s = r0[4]; + if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r0[5]; + if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r0[6]; + if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r0[7]; + if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabsf (r3[1]) > fabsf (r2[1])) + SWAP_ROWS (r3, r2); + if (fabsf (r2[1]) > fabsf (r1[1])) + SWAP_ROWS (r2, r1); + if (0.0 == r1[1]) + return FALSE; + + /* eliminate second variable */ + m2 = r2[1] / r1[1]; m3 = r3[1] / r1[1]; + r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; + r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; + s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabsf (r3[2]) > fabsf (r2[2])) + SWAP_ROWS (r3, r2); + if (0.0 == r2[2]) + return FALSE; + + /* eliminate third variable */ + m3 = r3[2] / r2[2]; + r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], + r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], + r3[7] -= m3 * r2[7]; + + /* last check */ + if (0.0 == r3[3]) + return FALSE; + + s = 1.0f / r3[3]; /* now back substitute row 3 */ + r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; + + m2 = r2[3]; /* now back substitute row 2 */ + s = 1.0f / r2[2]; + r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), + r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); + m1 = r1[3]; + r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, + r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; + m0 = r0[3]; + r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, + r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; + + m1 = r1[2]; /* now back substitute row 1 */ + s = 1.0f / r1[1]; + r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), + r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); + m0 = r0[2]; + r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, + r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; + + m0 = r0[1]; /* now back substitute row 0 */ + s = 1.0f / r0[0]; + r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), + r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); + + MAT (out, 0, 0) = r0[4]; MAT (out, 0, 1) = r0[5], + MAT (out, 0, 2) = r0[6]; MAT (out, 0, 3) = r0[7], + MAT (out, 1, 0) = r1[4]; MAT (out, 1, 1) = r1[5], + MAT (out, 1, 2) = r1[6]; MAT (out, 1, 3) = r1[7], + MAT (out, 2, 0) = r2[4]; MAT (out, 2, 1) = r2[5], + MAT (out, 2, 2) = r2[6]; MAT (out, 2, 3) = r2[7], + MAT (out, 3, 0) = r3[4]; MAT (out, 3, 1) = r3[5], + MAT (out, 3, 2) = r3[6]; MAT (out, 3, 3) = r3[7]; + + return TRUE; +} +#undef SWAP_ROWS + +/* + * Compute inverse of a general 3d transformation matrix. + * + * @mat pointer to a CoglMatrix structure. The matrix inverse will be + * stored in the CoglMatrix::inv attribute. + * + * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). + * + * \author Adapted from graphics gems II. + * + * Calculates the inverse of the upper left by first calculating its + * determinant and multiplying it to the symmetric adjust matrix of each + * element. Finally deals with the translation part by transforming the + * original translation vector using by the calculated submatrix inverse. + */ +static gboolean +invert_matrix_3d_general (CoglMatrix *matrix) +{ + const float *in = (float *)matrix; + float *out = matrix->inv; + float pos, neg, t; + float det; + + /* Calculate the determinant of upper left 3x3 submatrix and + * determine if the matrix is singular. + */ + pos = neg = 0.0; + t = MAT (in,0,0) * MAT (in,1,1) * MAT (in,2,2); + if (t >= 0.0) pos += t; else neg += t; + + t = MAT (in,1,0) * MAT (in,2,1) * MAT (in,0,2); + if (t >= 0.0) pos += t; else neg += t; + + t = MAT (in,2,0) * MAT (in,0,1) * MAT (in,1,2); + if (t >= 0.0) pos += t; else neg += t; + + t = -MAT (in,2,0) * MAT (in,1,1) * MAT (in,0,2); + if (t >= 0.0) pos += t; else neg += t; + + t = -MAT (in,1,0) * MAT (in,0,1) * MAT (in,2,2); + if (t >= 0.0) pos += t; else neg += t; + + t = -MAT (in,0,0) * MAT (in,2,1) * MAT (in,1,2); + if (t >= 0.0) pos += t; else neg += t; + + det = pos + neg; + + if (det*det < 1e-25) + return FALSE; + + det = 1.0f / det; + MAT (out,0,0) = + ( (MAT (in, 1, 1)*MAT (in, 2, 2) - MAT (in, 2, 1)*MAT (in, 1, 2) )*det); + MAT (out,0,1) = + (- (MAT (in, 0, 1)*MAT (in, 2, 2) - MAT (in, 2, 1)*MAT (in, 0, 2) )*det); + MAT (out,0,2) = + ( (MAT (in, 0, 1)*MAT (in, 1, 2) - MAT (in, 1, 1)*MAT (in, 0, 2) )*det); + MAT (out,1,0) = + (- (MAT (in,1,0)*MAT (in,2,2) - MAT (in,2,0)*MAT (in,1,2) )*det); + MAT (out,1,1) = + ( (MAT (in,0,0)*MAT (in,2,2) - MAT (in,2,0)*MAT (in,0,2) )*det); + MAT (out,1,2) = + (- (MAT (in,0,0)*MAT (in,1,2) - MAT (in,1,0)*MAT (in,0,2) )*det); + MAT (out,2,0) = + ( (MAT (in,1,0)*MAT (in,2,1) - MAT (in,2,0)*MAT (in,1,1) )*det); + MAT (out,2,1) = + (- (MAT (in,0,0)*MAT (in,2,1) - MAT (in,2,0)*MAT (in,0,1) )*det); + MAT (out,2,2) = + ( (MAT (in,0,0)*MAT (in,1,1) - MAT (in,1,0)*MAT (in,0,1) )*det); + + /* Do the translation part */ + MAT (out,0,3) = - (MAT (in, 0, 3) * MAT (out, 0, 0) + + MAT (in, 1, 3) * MAT (out, 0, 1) + + MAT (in, 2, 3) * MAT (out, 0, 2) ); + MAT (out,1,3) = - (MAT (in, 0, 3) * MAT (out, 1, 0) + + MAT (in, 1, 3) * MAT (out, 1, 1) + + MAT (in, 2, 3) * MAT (out, 1, 2) ); + MAT (out,2,3) = - (MAT (in, 0, 3) * MAT (out, 2 ,0) + + MAT (in, 1, 3) * MAT (out, 2, 1) + + MAT (in, 2, 3) * MAT (out, 2, 2) ); + + return TRUE; +} + +/* + * Compute inverse of a 3d transformation matrix. + * + * @mat pointer to a CoglMatrix structure. The matrix inverse will be + * stored in the CoglMatrix::inv attribute. + * + * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). + * + * If the matrix is not an angle preserving matrix then calls + * invert_matrix_3d_general for the actual calculation. Otherwise calculates + * the inverse matrix analyzing and inverting each of the scaling, rotation and + * translation parts. + */ +static gboolean +invert_matrix_3d (CoglMatrix *matrix) +{ + const float *in = (float *)matrix; + float *out = matrix->inv; + + if (!TEST_MAT_FLAGS(matrix, MAT_FLAGS_ANGLE_PRESERVING)) + return invert_matrix_3d_general (matrix); + + if (matrix->flags & MAT_FLAG_UNIFORM_SCALE) + { + float scale = (MAT (in, 0, 0) * MAT (in, 0, 0) + + MAT (in, 0, 1) * MAT (in, 0, 1) + + MAT (in, 0, 2) * MAT (in, 0, 2)); + + if (scale == 0.0) + return FALSE; + + scale = 1.0f / scale; + + /* Transpose and scale the 3 by 3 upper-left submatrix. */ + MAT (out, 0, 0) = scale * MAT (in, 0, 0); + MAT (out, 1, 0) = scale * MAT (in, 0, 1); + MAT (out, 2, 0) = scale * MAT (in, 0, 2); + MAT (out, 0, 1) = scale * MAT (in, 1, 0); + MAT (out, 1, 1) = scale * MAT (in, 1, 1); + MAT (out, 2, 1) = scale * MAT (in, 1, 2); + MAT (out, 0, 2) = scale * MAT (in, 2, 0); + MAT (out, 1, 2) = scale * MAT (in, 2, 1); + MAT (out, 2, 2) = scale * MAT (in, 2, 2); + } + else if (matrix->flags & MAT_FLAG_ROTATION) + { + /* Transpose the 3 by 3 upper-left submatrix. */ + MAT (out, 0, 0) = MAT (in, 0, 0); + MAT (out, 1, 0) = MAT (in, 0, 1); + MAT (out, 2, 0) = MAT (in, 0, 2); + MAT (out, 0, 1) = MAT (in, 1, 0); + MAT (out, 1, 1) = MAT (in, 1, 1); + MAT (out, 2, 1) = MAT (in, 1, 2); + MAT (out, 0, 2) = MAT (in, 2, 0); + MAT (out, 1, 2) = MAT (in, 2, 1); + MAT (out, 2, 2) = MAT (in, 2, 2); + } + else + { + /* pure translation */ + memcpy (out, identity, 16 * sizeof (float)); + MAT (out, 0, 3) = - MAT (in, 0, 3); + MAT (out, 1, 3) = - MAT (in, 1, 3); + MAT (out, 2, 3) = - MAT (in, 2, 3); + return TRUE; + } + + if (matrix->flags & MAT_FLAG_TRANSLATION) + { + /* Do the translation part */ + MAT (out,0,3) = - (MAT (in, 0, 3) * MAT (out, 0, 0) + + MAT (in, 1, 3) * MAT (out, 0, 1) + + MAT (in, 2, 3) * MAT (out, 0, 2) ); + MAT (out,1,3) = - (MAT (in, 0, 3) * MAT (out, 1, 0) + + MAT (in, 1, 3) * MAT (out, 1, 1) + + MAT (in, 2, 3) * MAT (out, 1, 2) ); + MAT (out,2,3) = - (MAT (in, 0, 3) * MAT (out, 2, 0) + + MAT (in, 1, 3) * MAT (out, 2, 1) + + MAT (in, 2, 3) * MAT (out, 2, 2) ); + } + else + MAT (out, 0, 3) = MAT (out, 1, 3) = MAT (out, 2, 3) = 0.0; + + return TRUE; +} + +/* + * Compute inverse of an identity transformation matrix. + * + * @mat pointer to a CoglMatrix structure. The matrix inverse will be + * stored in the CoglMatrix::inv attribute. + * + * Returns: always %TRUE. + * + * Simply copies identity into CoglMatrix::inv. + */ +static gboolean +invert_matrix_identity (CoglMatrix *matrix) +{ + memcpy (matrix->inv, identity, 16 * sizeof (float)); + return TRUE; +} + +/* + * Compute inverse of a no-rotation 3d transformation matrix. + * + * @mat pointer to a CoglMatrix structure. The matrix inverse will be + * stored in the CoglMatrix::inv attribute. + * + * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). + * + * Calculates the + */ +static gboolean +invert_matrix_3d_no_rotation (CoglMatrix *matrix) +{ + const float *in = (float *)matrix; + float *out = matrix->inv; + + if (MAT (in,0,0) == 0 || MAT (in,1,1) == 0 || MAT (in,2,2) == 0) + return FALSE; + + memcpy (out, identity, 16 * sizeof (float)); + MAT (out,0,0) = 1.0f / MAT (in,0,0); + MAT (out,1,1) = 1.0f / MAT (in,1,1); + MAT (out,2,2) = 1.0f / MAT (in,2,2); + + if (matrix->flags & MAT_FLAG_TRANSLATION) + { + MAT (out,0,3) = - (MAT (in,0,3) * MAT (out,0,0)); + MAT (out,1,3) = - (MAT (in,1,3) * MAT (out,1,1)); + MAT (out,2,3) = - (MAT (in,2,3) * MAT (out,2,2)); + } + + return TRUE; +} + +/* + * Compute inverse of a no-rotation 2d transformation matrix. + * + * @mat pointer to a CoglMatrix structure. The matrix inverse will be + * stored in the CoglMatrix::inv attribute. + * + * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). + * + * Calculates the inverse matrix by applying the inverse scaling and + * translation to the identity matrix. + */ +static gboolean +invert_matrix_2d_no_rotation (CoglMatrix *matrix) +{ + const float *in = (float *)matrix; + float *out = matrix->inv; + + if (MAT (in, 0, 0) == 0 || MAT (in, 1, 1) == 0) + return FALSE; + + memcpy (out, identity, 16 * sizeof (float)); + MAT (out, 0, 0) = 1.0f / MAT (in, 0, 0); + MAT (out, 1, 1) = 1.0f / MAT (in, 1, 1); + + if (matrix->flags & MAT_FLAG_TRANSLATION) + { + MAT (out, 0, 3) = - (MAT (in, 0, 3) * MAT (out, 0, 0)); + MAT (out, 1, 3) = - (MAT (in, 1, 3) * MAT (out, 1, 1)); + } + + return TRUE; +} + +#if 0 +/* broken */ +static gboolean +invert_matrix_perspective (CoglMatrix *matrix) +{ + const float *in = matrix; + float *out = matrix->inv; + + if (MAT (in,2,3) == 0) + return FALSE; + + memcpy( out, identity, 16 * sizeof(float) ); + + MAT (out, 0, 0) = 1.0f / MAT (in, 0, 0); + MAT (out, 1, 1) = 1.0f / MAT (in, 1, 1); + + MAT (out, 0, 3) = MAT (in, 0, 2); + MAT (out, 1, 3) = MAT (in, 1, 2); + + MAT (out,2,2) = 0; + MAT (out,2,3) = -1; + + MAT (out,3,2) = 1.0f / MAT (in,2,3); + MAT (out,3,3) = MAT (in,2,2) * MAT (out,3,2); + + return TRUE; +} +#endif + +/* + * Matrix inversion function pointer type. + */ +typedef gboolean (*inv_mat_func)(CoglMatrix *matrix); + +/* + * Table of the matrix inversion functions according to the matrix type. + */ +static inv_mat_func inv_mat_tab[7] = { + invert_matrix_general, + invert_matrix_identity, + invert_matrix_3d_no_rotation, +#if 0 + /* Don't use this function for now - it fails when the projection matrix + * is premultiplied by a translation (ala Chromium's tilesort SPU). + */ + invert_matrix_perspective, +#else + invert_matrix_general, +#endif + invert_matrix_3d, /* lazy! */ + invert_matrix_2d_no_rotation, + invert_matrix_3d +}; + +#define ZERO(x) (1<flags &= ~MAT_FLAGS_GEOMETRY; + + /* Check for translation - no-one really cares + */ + if ((mask & MASK_NO_TRX) != MASK_NO_TRX) + matrix->flags |= MAT_FLAG_TRANSLATION; + + /* Do the real work + */ + if (mask == (unsigned int) MASK_IDENTITY) + matrix->type = COGL_MATRIX_TYPE_IDENTITY; + else if ((mask & MASK_2D_NO_ROT) == (unsigned int) MASK_2D_NO_ROT) + { + matrix->type = COGL_MATRIX_TYPE_2D_NO_ROT; + + if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE) + matrix->flags |= MAT_FLAG_GENERAL_SCALE; + } + else if ((mask & MASK_2D) == (unsigned int) MASK_2D) + { + float mm = DOT2 (m, m); + float m4m4 = DOT2 (m+4,m+4); + float mm4 = DOT2 (m,m+4); + + matrix->type = COGL_MATRIX_TYPE_2D; + + /* Check for scale */ + if (SQ (mm-1) > SQ (1e-6) || + SQ (m4m4-1) > SQ (1e-6)) + matrix->flags |= MAT_FLAG_GENERAL_SCALE; + + /* Check for rotation */ + if (SQ (mm4) > SQ (1e-6)) + matrix->flags |= MAT_FLAG_GENERAL_3D; + else + matrix->flags |= MAT_FLAG_ROTATION; + + } + else if ((mask & MASK_3D_NO_ROT) == (unsigned int) MASK_3D_NO_ROT) + { + matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT; + + /* Check for scale */ + if (SQ (m[0]-m[5]) < SQ (1e-6) && + SQ (m[0]-m[10]) < SQ (1e-6)) + { + if (SQ (m[0]-1.0) > SQ (1e-6)) + matrix->flags |= MAT_FLAG_UNIFORM_SCALE; + } + else + matrix->flags |= MAT_FLAG_GENERAL_SCALE; + } + else if ((mask & MASK_3D) == (unsigned int) MASK_3D) + { + float c1 = DOT3 (m,m); + float c2 = DOT3 (m+4,m+4); + float c3 = DOT3 (m+8,m+8); + float d1 = DOT3 (m, m+4); + float cp[3]; + + matrix->type = COGL_MATRIX_TYPE_3D; + + /* Check for scale */ + if (SQ (c1-c2) < SQ (1e-6) && SQ (c1-c3) < SQ (1e-6)) + { + if (SQ (c1-1.0) > SQ (1e-6)) + matrix->flags |= MAT_FLAG_UNIFORM_SCALE; + /* else no scale at all */ + } + else + matrix->flags |= MAT_FLAG_GENERAL_SCALE; + + /* Check for rotation */ + if (SQ (d1) < SQ (1e-6)) + { + CROSS3 ( cp, m, m+4); + SUB_3V ( cp, cp, (m+8)); + if (LEN_SQUARED_3FV(cp) < SQ(1e-6)) + matrix->flags |= MAT_FLAG_ROTATION; + else + matrix->flags |= MAT_FLAG_GENERAL_3D; + } + else + matrix->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */ + } + else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0f) + { + matrix->type = COGL_MATRIX_TYPE_PERSPECTIVE; + matrix->flags |= MAT_FLAG_GENERAL; + } + else + { + matrix->type = COGL_MATRIX_TYPE_GENERAL; + matrix->flags |= MAT_FLAG_GENERAL; + } +} + +/* + * Analyze a matrix given that its flags are accurate. + * + * This is the more common operation, hopefully. + */ +static void +analyse_from_flags (CoglMatrix *matrix) +{ + const float *m = (float *)matrix; + + if (TEST_MAT_FLAGS(matrix, 0)) + matrix->type = COGL_MATRIX_TYPE_IDENTITY; + else if (TEST_MAT_FLAGS(matrix, (MAT_FLAG_TRANSLATION | + MAT_FLAG_UNIFORM_SCALE | + MAT_FLAG_GENERAL_SCALE))) + { + if ( m[10] == 1.0f && m[14] == 0.0f ) + matrix->type = COGL_MATRIX_TYPE_2D_NO_ROT; + else + matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT; + } + else if (TEST_MAT_FLAGS (matrix, MAT_FLAGS_3D)) + { + if ( m[ 8]==0.0f + && m[ 9]==0.0f + && m[2]==0.0f && m[6]==0.0f && m[10]==1.0f && m[14]==0.0f) + { + matrix->type = COGL_MATRIX_TYPE_2D; + } + else + matrix->type = COGL_MATRIX_TYPE_3D; + } + else if ( m[4]==0.0f && m[12]==0.0f + && m[1]==0.0f && m[13]==0.0f + && m[2]==0.0f && m[6]==0.0f + && m[3]==0.0f && m[7]==0.0f && m[11]==-1.0f && m[15]==0.0f) + { + matrix->type = COGL_MATRIX_TYPE_PERSPECTIVE; + } + else + matrix->type = COGL_MATRIX_TYPE_GENERAL; +} + +/* + * Analyze and update the type and flags of a matrix. + * + * If the matrix type is dirty then calls either analyse_from_scratch() or + * analyse_from_flags() to determine its type, according to whether the flags + * are dirty or not, respectively. If the matrix has an inverse and it's dirty + * then calls matrix_invert(). Finally clears the dirty flags. + */ +static void +_cogl_matrix_update_type_and_flags (CoglMatrix *matrix) +{ + if (matrix->flags & MAT_DIRTY_TYPE) + { + if (matrix->flags & MAT_DIRTY_FLAGS) + analyse_from_scratch (matrix); + else + analyse_from_flags (matrix); + } + + matrix->flags &= ~(MAT_DIRTY_FLAGS | MAT_DIRTY_TYPE); +} + +/* + * Compute inverse of a transformation matrix. + * + * @mat pointer to a CoglMatrix structure. The matrix inverse will be + * stored in the CoglMatrix::inv attribute. + * + * Returns: %TRUE for success, %FALSE for failure (\p singular matrix). + * + * Calls the matrix inversion function in inv_mat_tab corresponding to the + * given matrix type. In case of failure, updates the MAT_FLAG_SINGULAR flag, + * and copies the identity matrix into CoglMatrix::inv. + */ +static gboolean +_cogl_matrix_update_inverse (CoglMatrix *matrix) +{ + if (matrix->flags & MAT_DIRTY_FLAGS || + matrix->flags & MAT_DIRTY_INVERSE) + { + _cogl_matrix_update_type_and_flags (matrix); + + if (inv_mat_tab[matrix->type](matrix)) + matrix->flags &= ~MAT_FLAG_SINGULAR; + else + { + matrix->flags |= MAT_FLAG_SINGULAR; + memcpy (matrix->inv, identity, 16 * sizeof (float)); + } + + matrix->flags &= ~MAT_DIRTY_INVERSE; + } + + if (matrix->flags & MAT_FLAG_SINGULAR) + return FALSE; + else + return TRUE; +} + +gboolean +cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse) +{ + if (_cogl_matrix_update_inverse ((CoglMatrix *)matrix)) + { + cogl_matrix_init_from_array (inverse, matrix->inv); + return TRUE; + } + else + { + cogl_matrix_init_identity (inverse); + return FALSE; + } +} + +/* + * Generate a 4x4 transformation matrix from glRotate parameters, and + * post-multiply the input matrix by it. + * + * \author + * This function was contributed by Erich Boleyn (erich@uruk.org). + * Optimizations contributed by Rudolf Opalla (rudi@khm.de). + */ +static void +_cogl_matrix_rotate (CoglMatrix *matrix, + float angle, + float x, + float y, + float z) +{ + float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c; + float m[16]; + gboolean optimized; + + s = sinf (angle * DEG2RAD); + c = cosf (angle * DEG2RAD); + + memcpy (m, identity, 16 * sizeof (float)); + optimized = FALSE; + +#define M(row,col) m[col*4+row] + + if (x == 0.0f) + { + if (y == 0.0f) + { + if (z != 0.0f) + { + optimized = TRUE; + /* rotate only around z-axis */ + M (0,0) = c; + M (1,1) = c; + if (z < 0.0f) + { + M (0,1) = s; + M (1,0) = -s; + } + else + { + M (0,1) = -s; + M (1,0) = s; + } + } + } + else if (z == 0.0f) + { + optimized = TRUE; + /* rotate only around y-axis */ + M (0,0) = c; + M (2,2) = c; + if (y < 0.0f) + { + M (0,2) = -s; + M (2,0) = s; + } + else + { + M (0,2) = s; + M (2,0) = -s; + } + } + } + else if (y == 0.0f) + { + if (z == 0.0f) + { + optimized = TRUE; + /* rotate only around x-axis */ + M (1,1) = c; + M (2,2) = c; + if (x < 0.0f) + { + M (1,2) = s; + M (2,1) = -s; + } + else + { + M (1,2) = -s; + M (2,1) = s; + } + } + } + + if (!optimized) + { + const float mag = sqrtf (x * x + y * y + z * z); + + if (mag <= 1.0e-4) + { + /* no rotation, leave mat as-is */ + return; + } + + x /= mag; + y /= mag; + z /= mag; + + + /* + * Arbitrary axis rotation matrix. + * + * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied + * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation + * (which is about the X-axis), and the two composite transforms + * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary + * from the arbitrary axis to the X-axis then back. They are + * all elementary rotations. + * + * Rz' is a rotation about the Z-axis, to bring the axis vector + * into the x-z plane. Then Ry' is applied, rotating about the + * Y-axis to bring the axis vector parallel with the X-axis. The + * rotation about the X-axis is then performed. Ry and Rz are + * simply the respective inverse transforms to bring the arbitrary + * axis back to it's original orientation. The first transforms + * Rz' and Ry' are considered inverses, since the data from the + * arbitrary axis gives you info on how to get to it, not how + * to get away from it, and an inverse must be applied. + * + * The basic calculation used is to recognize that the arbitrary + * axis vector (x, y, z), since it is of unit length, actually + * represents the sines and cosines of the angles to rotate the + * X-axis to the same orientation, with theta being the angle about + * Z and phi the angle about Y (in the order described above) + * as follows: + * + * cos ( theta ) = x / sqrt ( 1 - z^2 ) + * sin ( theta ) = y / sqrt ( 1 - z^2 ) + * + * cos ( phi ) = sqrt ( 1 - z^2 ) + * sin ( phi ) = z + * + * Note that cos ( phi ) can further be inserted to the above + * formulas: + * + * cos ( theta ) = x / cos ( phi ) + * sin ( theta ) = y / sin ( phi ) + * + * ...etc. Because of those relations and the standard trigonometric + * relations, it is pssible to reduce the transforms down to what + * is used below. It may be that any primary axis chosen will give the + * same results (modulo a sign convention) using thie method. + * + * Particularly nice is to notice that all divisions that might + * have caused trouble when parallel to certain planes or + * axis go away with care paid to reducing the expressions. + * After checking, it does perform correctly under all cases, since + * in all the cases of division where the denominator would have + * been zero, the numerator would have been zero as well, giving + * the expected result. + */ + + xx = x * x; + yy = y * y; + zz = z * z; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * s; + ys = y * s; + zs = z * s; + one_c = 1.0f - c; + + /* We already hold the identity-matrix so we can skip some statements */ + M (0,0) = (one_c * xx) + c; + M (0,1) = (one_c * xy) - zs; + M (0,2) = (one_c * zx) + ys; + /* M (0,3) = 0.0f; */ + + M (1,0) = (one_c * xy) + zs; + M (1,1) = (one_c * yy) + c; + M (1,2) = (one_c * yz) - xs; + /* M (1,3) = 0.0f; */ + + M (2,0) = (one_c * zx) - ys; + M (2,1) = (one_c * yz) + xs; + M (2,2) = (one_c * zz) + c; + /* M (2,3) = 0.0f; */ + + /* + M (3,0) = 0.0f; + M (3,1) = 0.0f; + M (3,2) = 0.0f; + M (3,3) = 1.0f; + */ + } +#undef M + + matrix_multiply_array_with_flags (matrix, m, MAT_FLAG_ROTATION); +} + void cogl_matrix_rotate (CoglMatrix *matrix, float angle, @@ -123,75 +1333,43 @@ cogl_matrix_rotate (CoglMatrix *matrix, float y, float z) { -#ifndef USE_MESA_MATRIX_API - CoglMatrix rotation; - CoglMatrix result; - float c, s; - - angle *= G_PI / 180.0f; - c = cosf (angle); - s = sinf (angle); - - rotation.xx = x * x * (1.0f - c) + c; - rotation.yx = y * x * (1.0f - c) + z * s; - rotation.zx = x * z * (1.0f - c) - y * s; - rotation.wx = 0.0f; - - rotation.xy = x * y * (1.0f - c) - z * s; - rotation.yy = y * y * (1.0f - c) + c; - rotation.zy = y * z * (1.0f - c) + x * s; - rotation.wy = 0.0f; - - rotation.xz = x * z * (1.0f - c) + y * s; - rotation.yz = y * z * (1.0f - c) - x * s; - rotation.zz = z * z * (1.0f - c) + c; - rotation.wz = 0.0f; - - rotation.xw = 0.0f; - rotation.yw = 0.0f; - rotation.zw = 0.0f; - rotation.ww = 1.0f; - - cogl_matrix_multiply (&result, matrix, &rotation); - *matrix = result; -#else _cogl_matrix_rotate (matrix, angle, x, y, z); -#endif _COGL_MATRIX_DEBUG_PRINT (matrix); } -void -cogl_matrix_translate (CoglMatrix *matrix, - float x, - float y, - float z) +/* + * Apply a perspective projection matrix. + * + * Creates the projection matrix and multiplies it with matrix, marking the + * MAT_FLAG_PERSPECTIVE flag. + */ +static void +_cogl_matrix_frustum (CoglMatrix *matrix, + float left, + float right, + float bottom, + float top, + float nearval, + float farval) { -#ifndef USE_MESA_MATRIX_API - matrix->xw = matrix->xx * x + matrix->xy * y + matrix->xz * z + matrix->xw; - matrix->yw = matrix->yx * x + matrix->yy * y + matrix->yz * z + matrix->yw; - matrix->zw = matrix->zx * x + matrix->zy * y + matrix->zz * z + matrix->zw; - matrix->ww = matrix->wx * x + matrix->wy * y + matrix->wz * z + matrix->ww; -#else - _cogl_matrix_translate (matrix, x, y, z); -#endif - _COGL_MATRIX_DEBUG_PRINT (matrix); -} + float x, y, a, b, c, d; + float m[16]; -void -cogl_matrix_scale (CoglMatrix *matrix, - float sx, - float sy, - float sz) -{ -#ifndef USE_MESA_MATRIX_API - matrix->xx *= sx; matrix->xy *= sy; matrix->xz *= sz; - matrix->yx *= sx; matrix->yy *= sy; matrix->yz *= sz; - matrix->zx *= sx; matrix->zy *= sy; matrix->zz *= sz; - matrix->wx *= sx; matrix->wy *= sy; matrix->wz *= sz; -#else - _cogl_matrix_scale (matrix, sx, sy, sz); -#endif - _COGL_MATRIX_DEBUG_PRINT (matrix); + x = (2.0f * nearval) / (right - left); + y = (2.0f * nearval) / (top - bottom); + a = (right + left) / (right - left); + b = (top + bottom) / (top - bottom); + c = -(farval + nearval) / ( farval - nearval); + d = -(2.0f * farval * nearval) / (farval - nearval); /* error? */ + +#define M(row,col) m[col*4+row] + M (0,0) = x; M (0,1) = 0.0f; M (0,2) = a; M (0,3) = 0.0f; + M (1,0) = 0.0f; M (1,1) = y; M (1,2) = b; M (1,3) = 0.0f; + M (2,0) = 0.0f; M (2,1) = 0.0f; M (2,2) = c; M (2,3) = d; + M (3,0) = 0.0f; M (3,1) = 0.0f; M (3,2) = -1.0f; M (3,3) = 0.0f; +#undef M + + matrix_multiply_array_with_flags (matrix, m, MAT_FLAG_PERSPECTIVE); } void @@ -203,41 +1381,7 @@ cogl_matrix_frustum (CoglMatrix *matrix, float z_near, float z_far) { -#ifndef USE_MESA_MATRIX_API - float x, y, a, b, c, d; - CoglMatrix frustum; - - x = (2.0f * z_near) / (right - left); - y = (2.0f * z_near) / (top - bottom); - a = (right + left) / (right - left); - b = (top + bottom) / (top - bottom); - c = -(z_far + z_near) / ( z_far - z_near); - d = -(2.0f * z_far* z_near) / (z_far - z_near); - - frustum.xx = x; - frustum.yx = 0.0f; - frustum.zx = 0.0f; - frustum.wx = 0.0f; - - frustum.xy = 0.0f; - frustum.yy = y; - frustum.zy = 0.0f; - frustum.wy = 0.0f; - - frustum.xz = a; - frustum.yz = b; - frustum.zz = c; - frustum.wz = -1.0f; - - frustum.xw = 0.0f; - frustum.yw = 0.0f; - frustum.zw = d; - frustum.ww = 0.0f; - - cogl_matrix_multiply (matrix, matrix, &frustum); -#else _cogl_matrix_frustum (matrix, left, right, bottom, top, z_near, z_far); -#endif _COGL_MATRIX_DEBUG_PRINT (matrix); } @@ -260,6 +1404,50 @@ cogl_matrix_perspective (CoglMatrix *matrix, _COGL_MATRIX_DEBUG_PRINT (matrix); } +/* + * Apply an orthographic projection matrix. + * + * Creates the projection matrix and multiplies it with matrix, marking the + * MAT_FLAG_GENERAL_SCALE and MAT_FLAG_TRANSLATION flags. + */ +static void +_cogl_matrix_ortho (CoglMatrix *matrix, + float left, + float right, + float bottom, + float top, + float nearval, + float farval) +{ + float m[16]; + +#define M(row,col) m[col*4+row] + M (0,0) = 2.0f / (right-left); + M (0,1) = 0.0f; + M (0,2) = 0.0f; + M (0,3) = -(right+left) / (right-left); + + M (1,0) = 0.0f; + M (1,1) = 2.0f / (top-bottom); + M (1,2) = 0.0f; + M (1,3) = -(top+bottom) / (top-bottom); + + M (2,0) = 0.0f; + M (2,1) = 0.0f; + M (2,2) = -2.0f / (farval-nearval); + M (2,3) = -(farval+nearval) / (farval-nearval); + + M (3,0) = 0.0f; + M (3,1) = 0.0f; + M (3,2) = 0.0f; + M (3,3) = 1.0f; +#undef M + + matrix_multiply_array_with_flags (matrix, m, + (MAT_FLAG_GENERAL_SCALE | + MAT_FLAG_TRANSLATION)); +} + void cogl_matrix_ortho (CoglMatrix *matrix, float left, @@ -269,40 +1457,255 @@ cogl_matrix_ortho (CoglMatrix *matrix, float near_val, float far_val) { -#ifndef USE_MESA_MATRIX_API - CoglMatrix ortho; - - /* column 0 */ - ortho.xx = 2.0 / (right - left); - ortho.yx = 0.0; - ortho.zx = 0.0; - ortho.wx = 0.0; - - /* column 1 */ - ortho.xy = 0.0; - ortho.yy = 2.0 / (top - bottom); - ortho.zy = 0.0; - ortho.wy = 0.0; - - /* column 2 */ - ortho.xz = 0.0; - ortho.yz = 0.0; - ortho.zz = -2.0 / (far_val - near_val); - ortho.wz = 0.0; - - /* column 3 */ - ortho.xw = -(right + left) / (right - left); - ortho.yw = -(top + bottom) / (top - bottom); - ortho.zw = -(far_val + near_val) / (far_val - near_val); - ortho.ww = 1.0; - - cogl_matrix_multiply (matrix, matrix, &ortho); -#else _cogl_matrix_ortho (matrix, left, right, bottom, top, near_val, far_val); -#endif _COGL_MATRIX_DEBUG_PRINT (matrix); } +/* + * Multiply a matrix with a general scaling matrix. + * + * Multiplies in-place the elements of matrix by the scale factors. Checks if + * the scales factors are roughly the same, marking the MAT_FLAG_UNIFORM_SCALE + * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE and + * MAT_DIRTY_INVERSE dirty flags. + */ +static void +_cogl_matrix_scale (CoglMatrix *matrix, float x, float y, float z) +{ + float *m = (float *)matrix; + m[0] *= x; m[4] *= y; m[8] *= z; + m[1] *= x; m[5] *= y; m[9] *= z; + m[2] *= x; m[6] *= y; m[10] *= z; + m[3] *= x; m[7] *= y; m[11] *= z; + + if (fabsf (x - y) < 1e-8 && fabsf (x - z) < 1e-8) + matrix->flags |= MAT_FLAG_UNIFORM_SCALE; + else + matrix->flags |= MAT_FLAG_GENERAL_SCALE; + + matrix->flags |= (MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE); +} + +void +cogl_matrix_scale (CoglMatrix *matrix, + float sx, + float sy, + float sz) +{ + _cogl_matrix_scale (matrix, sx, sy, sz); + _COGL_MATRIX_DEBUG_PRINT (matrix); +} + +/* + * Multiply a matrix with a translation matrix. + * + * Adds the translation coordinates to the elements of matrix in-place. Marks + * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and MAT_DIRTY_INVERSE + * dirty flags. + */ +static void +_cogl_matrix_translate (CoglMatrix *matrix, float x, float y, float z) +{ + float *m = (float *)matrix; + m[12] = m[0] * x + m[4] * y + m[8] * z + m[12]; + m[13] = m[1] * x + m[5] * y + m[9] * z + m[13]; + m[14] = m[2] * x + m[6] * y + m[10] * z + m[14]; + m[15] = m[3] * x + m[7] * y + m[11] * z + m[15]; + + matrix->flags |= (MAT_FLAG_TRANSLATION | + MAT_DIRTY_TYPE | + MAT_DIRTY_INVERSE); +} + +void +cogl_matrix_translate (CoglMatrix *matrix, + float x, + float y, + float z) +{ + _cogl_matrix_translate (matrix, x, y, z); + _COGL_MATRIX_DEBUG_PRINT (matrix); +} + +#if 0 +/* + * Set matrix to do viewport and depthrange mapping. + * Transforms Normalized Device Coords to window/Z values. + */ +static void +_cogl_matrix_viewport (CoglMatrix *matrix, + float x, float y, + float width, float height, + float zNear, float zFar, float depthMax) +{ + float *m = (float *)matrix; + m[MAT_SX] = width / 2.0f; + m[MAT_TX] = m[MAT_SX] + x; + m[MAT_SY] = height / 2.0f; + m[MAT_TY] = m[MAT_SY] + y; + m[MAT_SZ] = depthMax * ((zFar - zNear) / 2.0f); + m[MAT_TZ] = depthMax * ((zFar - zNear) / 2.0f + zNear); + matrix->flags = MAT_FLAG_GENERAL_SCALE | MAT_FLAG_TRANSLATION; + matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT; +} +#endif + +/* + * Set a matrix to the identity matrix. + * + * @mat matrix. + * + * Copies ::identity into \p CoglMatrix::m, and into CoglMatrix::inv if + * not NULL. Sets the matrix type to identity, resets the flags. It + * doesn't initialize the inverse matrix, it just marks it dirty. + */ +static void +_cogl_matrix_init_identity (CoglMatrix *matrix) +{ + memcpy (matrix, identity, 16 * sizeof (float)); + + matrix->type = COGL_MATRIX_TYPE_IDENTITY; + matrix->flags = MAT_DIRTY_INVERSE; +} + +void +cogl_matrix_init_identity (CoglMatrix *matrix) +{ + _cogl_matrix_init_identity (matrix); + _COGL_MATRIX_DEBUG_PRINT (matrix); +} + +#if 0 +/* + * Test if the given matrix preserves vector lengths. + */ +static gboolean +_cogl_matrix_is_length_preserving (const CoglMatrix *m) +{ + return TEST_MAT_FLAGS (m, MAT_FLAGS_LENGTH_PRESERVING); +} + +/* + * Test if the given matrix does any rotation. + * (or perhaps if the upper-left 3x3 is non-identity) + */ +static gboolean +_cogl_matrix_has_rotation (const CoglMatrix *matrix) +{ + if (matrix->flags & (MAT_FLAG_GENERAL | + MAT_FLAG_ROTATION | + MAT_FLAG_GENERAL_3D | + MAT_FLAG_PERSPECTIVE)) + return TRUE; + else + return FALSE; +} + +static gboolean +_cogl_matrix_is_general_scale (const CoglMatrix *matrix) +{ + return (matrix->flags & MAT_FLAG_GENERAL_SCALE) ? TRUE : FALSE; +} + +static gboolean +_cogl_matrix_is_dirty (const CoglMatrix *matrix) +{ + return (matrix->flags & MAT_DIRTY_ALL) ? TRUE : FALSE; +} +#endif + +/* + * Loads a matrix array into CoglMatrix. + * + * @m matrix array. + * @mat matrix. + * + * Copies \p m into CoglMatrix::m and marks the MAT_FLAG_GENERAL and + * MAT_DIRTY_ALL + * flags. + */ +static void +_cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array) +{ + memcpy (matrix, array, 16 * sizeof (float)); + matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL); +} + +void +cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array) +{ + _cogl_matrix_init_from_array (matrix, array); + _COGL_MATRIX_DEBUG_PRINT (matrix); +} + +static void +_cogl_matrix_init_from_quaternion (CoglMatrix *matrix, + CoglQuaternion *quaternion) +{ + float qnorm = _COGL_QUATERNION_NORM (quaternion); + float s = (qnorm > 0.0f) ? (2.0f / qnorm) : 0.0f; + float xs = quaternion->x * s; + float ys = quaternion->y * s; + float zs = quaternion->z * s; + float wx = quaternion->w * xs; + float wy = quaternion->w * ys; + float wz = quaternion->w * zs; + float xx = quaternion->x * xs; + float xy = quaternion->x * ys; + float xz = quaternion->x * zs; + float yy = quaternion->y * ys; + float yz = quaternion->y * zs; + float zz = quaternion->z * zs; + + matrix->xx = 1.0f - (yy + zz); + matrix->yx = xy + wz; + matrix->zx = xz - wy; + matrix->xy = xy - wz; + matrix->yy = 1.0f - (xx + zz); + matrix->zy = yz + wx; + matrix->xz = xz + wy; + matrix->yz = yz - wx; + matrix->zz = 1.0f - (xx + yy); + matrix->xw = matrix->yw = matrix->zw = 0.0f; + matrix->wx = matrix->wy = matrix->wz = 0.0f; + matrix->ww = 1.0f; + + matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL); +} + +void +cogl_matrix_init_from_quaternion (CoglMatrix *matrix, + CoglQuaternion *quaternion) +{ + _cogl_matrix_init_from_quaternion (matrix, quaternion); +} + +#if 0 +/* + * Transpose a float matrix. + */ +static void +_cogl_matrix_util_transposef (float to[16], const float from[16]) +{ + to[0] = from[0]; + to[1] = from[4]; + to[2] = from[8]; + to[3] = from[12]; + to[4] = from[1]; + to[5] = from[5]; + to[6] = from[9]; + to[7] = from[13]; + to[8] = from[2]; + to[9] = from[6]; + to[10] = from[10]; + to[11] = from[14]; + to[12] = from[3]; + to[13] = from[7]; + to[14] = from[11]; + to[15] = from[15]; +} +#endif + void cogl_matrix_view_2d_in_frustum (CoglMatrix *matrix, float left, @@ -360,17 +1763,6 @@ cogl_matrix_view_2d_in_perspective (CoglMatrix *matrix, height_2d); } -void -cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array) -{ -#ifndef USE_MESA_MATRIX_API - memcpy (matrix, array, sizeof (float) * 16); -#else - _cogl_matrix_init_from_array (matrix, array); -#endif - _COGL_MATRIX_DEBUG_PRINT (matrix); -} - gboolean cogl_matrix_equal (gconstpointer v1, gconstpointer v2) { @@ -437,27 +1829,6 @@ cogl_matrix_get_array (const CoglMatrix *matrix) return (float *)matrix; } -gboolean -cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse) -{ -#ifndef USE_MESA_MATRIX_API -#warning "cogl_matrix_get_inverse not supported without Mesa matrix API" - cogl_matrix_init_identity (inverse); - return FALSE; -#else - if (_cogl_matrix_update_inverse ((CoglMatrix *)matrix)) - { - cogl_matrix_init_from_array (inverse, matrix->inv); - return TRUE; - } - else - { - cogl_matrix_init_identity (inverse); - return FALSE; - } -#endif -} - void cogl_matrix_transform_point (const CoglMatrix *matrix, float *x,