blob: 8f6d26f8bf457e39c66f5091cfffe823812af186 [file] [edit]
#ifndef MATRIX4X4_HH
#define MATRIX4X4_HH
#ifdef _WIN32
#define _USE_MATH_DEFINES
#endif
#include <cmath>
#include <cstring>
/*
* Copyright (c) 2009, Mozilla Corp
* Copyright (c) 2012, Google, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carriers
* the following header:
*
* Book: OpenGL(R) ES 2.0 Programming Guide
* Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
* ISBN-10: 0321502795
* ISBN-13: 9780321502797
* Publisher: Addison-Wesley Professional
* URLs: http://safari.informit.com/9780321563835
* http://www.opengles-book.com
*/
/*
* Ported from JavaScript to C by Behdad Esfahbod, 2012.
* Added MultMatrix. Converting from fixed-function OpenGL matrix
* operations to these functions should be as simple as renaming the
* 'gl' prefix to 'm4' and adding the matrix argument to the call.
*
* The C version lives at http://code.google.com/p/matrix4x4-c/
*/
/*
* A simple 4x4 matrix utility implementation
*/
static inline float *
m4LoadIdentity (float *mat) {
unsigned int i;
for (i = 0; i < 16; i++)
mat[i] = 0;
mat[0*4+0] = 1.0;
mat[1*4+1] = 1.0;
mat[2*4+2] = 1.0;
mat[3*4+3] = 1.0;
return mat;
}
/* Copies other matrix into mat */
static inline float *
m4Copy (float *mat, const float *other) {
unsigned int i;
for (i = 0; i < 16; i++) {
mat[i] = other[i];
}
return mat;
}
static inline float *
m4Multiply (float *mat, const float *right) {
float tmp[16];
unsigned int i;
for (i = 0; i < 4; i++) {
tmp[i*4+0] =
(mat[i*4+0] * right[0*4+0]) +
(mat[i*4+1] * right[1*4+0]) +
(mat[i*4+2] * right[2*4+0]) +
(mat[i*4+3] * right[3*4+0]) ;
tmp[i*4+1] =
(mat[i*4+0] * right[0*4+1]) +
(mat[i*4+1] * right[1*4+1]) +
(mat[i*4+2] * right[2*4+1]) +
(mat[i*4+3] * right[3*4+1]) ;
tmp[i*4+2] =
(mat[i*4+0] * right[0*4+2]) +
(mat[i*4+1] * right[1*4+2]) +
(mat[i*4+2] * right[2*4+2]) +
(mat[i*4+3] * right[3*4+2]) ;
tmp[i*4+3] =
(mat[i*4+0] * right[0*4+3]) +
(mat[i*4+1] * right[1*4+3]) +
(mat[i*4+2] * right[2*4+3]) +
(mat[i*4+3] * right[3*4+3]) ;
}
return m4Copy (mat, tmp);
}
static inline float
m4Get (float *mat, unsigned int row, unsigned int col) {
return mat[4*row+col];
}
static inline float *
m4MultMatrix (float *mat, const float *left) {
float tmp[16];
return m4Copy (mat, m4Multiply (m4Copy (tmp, left), mat));
}
static inline float *
m4Scale (float *mat, float sx, float sy, float sz) {
mat[0*4+0] *= sx;
mat[0*4+1] *= sx;
mat[0*4+2] *= sx;
mat[0*4+3] *= sx;
mat[1*4+0] *= sy;
mat[1*4+1] *= sy;
mat[1*4+2] *= sy;
mat[1*4+3] *= sy;
mat[2*4+0] *= sz;
mat[2*4+1] *= sz;
mat[2*4+2] *= sz;
mat[2*4+3] *= sz;
return mat;
}
static inline float *
m4Translate (float *mat, float tx, float ty, float tz) {
mat[3*4+0] += mat[0*4+0] * tx + mat[1*4+0] * ty + mat[2*4+0] * tz;
mat[3*4+1] += mat[0*4+1] * tx + mat[1*4+1] * ty + mat[2*4+1] * tz;
mat[3*4+2] += mat[0*4+2] * tx + mat[1*4+2] * ty + mat[2*4+2] * tz;
mat[3*4+3] += mat[0*4+3] * tx + mat[1*4+3] * ty + mat[2*4+3] * tz;
return mat;
}
static inline float *
m4Rotate (float *mat, float angle, float x, float y, float z) {
float mag = sqrt(x*x + y*y + z*z);
float sinAngle = sin(angle * M_PI / 180.0);
float cosAngle = cos(angle * M_PI / 180.0);
float xx, yy, zz, xy, yz, zx, xs, ys, zs;
float oneMinusCos;
float rotMat[16];
if (mag <= 0)
return mat;
m4LoadIdentity (rotMat);
x /= mag;
y /= mag;
z /= mag;
xx = x * x;
yy = y * y;
zz = z * z;
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * sinAngle;
ys = y * sinAngle;
zs = z * sinAngle;
oneMinusCos = 1.0 - cosAngle;
rotMat[0*4+0] = (oneMinusCos * xx) + cosAngle;
rotMat[0*4+1] = (oneMinusCos * xy) - zs;
rotMat[0*4+2] = (oneMinusCos * zx) + ys;
rotMat[0*4+3] = 0.0;
rotMat[1*4+0] = (oneMinusCos * xy) + zs;
rotMat[1*4+1] = (oneMinusCos * yy) + cosAngle;
rotMat[1*4+2] = (oneMinusCos * yz) - xs;
rotMat[1*4+3] = 0.0;
rotMat[2*4+0] = (oneMinusCos * zx) - ys;
rotMat[2*4+1] = (oneMinusCos * yz) + xs;
rotMat[2*4+2] = (oneMinusCos * zz) + cosAngle;
rotMat[2*4+3] = 0.0;
rotMat[3*4+0] = 0.0;
rotMat[3*4+1] = 0.0;
rotMat[3*4+2] = 0.0;
rotMat[3*4+3] = 1.0;
return m4Copy (mat, m4Multiply (rotMat, mat));
}
static inline float *
m4Frustum (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) {
float deltaX = right - left;
float deltaY = top - bottom;
float deltaZ = farZ - nearZ;
float frust[16];
if ( (nearZ <= 0.0) || (farZ <= 0.0) ||
(deltaX <= 0.0) || (deltaY <= 0.0) || (deltaZ <= 0.0) )
return mat;
m4LoadIdentity (frust);
frust[0*4+0] = 2.0 * nearZ / deltaX;
frust[0*4+1] = frust[0*4+2] = frust[0*4+3] = 0.0;
frust[1*4+1] = 2.0 * nearZ / deltaY;
frust[1*4+0] = frust[1*4+2] = frust[1*4+3] = 0.0;
frust[2*4+0] = (right + left) / deltaX;
frust[2*4+1] = (top + bottom) / deltaY;
frust[2*4+2] = -(nearZ + farZ) / deltaZ;
frust[2*4+3] = -1.0;
frust[3*4+2] = -2.0 * nearZ * farZ / deltaZ;
frust[3*4+0] = frust[3*4+1] = frust[3*4+3] = 0.0;
return m4Copy (mat, m4Multiply (frust, mat));
}
static inline float *
m4Perspective (float *mat, float fovy, float aspect, float nearZ, float farZ) {
float frustumH = tan(fovy / 360.0 * M_PI) * nearZ;
float frustumW = frustumH * aspect;
return m4Frustum(mat, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ);
}
static inline float *
m4Ortho (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) {
float deltaX = right - left;
float deltaY = top - bottom;
float deltaZ = farZ - nearZ;
float ortho[16];
if ( (deltaX == 0.0) || (deltaY == 0.0) || (deltaZ == 0.0) )
return mat;
m4LoadIdentity (ortho);
ortho[0*4+0] = 2.0 / deltaX;
ortho[3*4+0] = -(right + left) / deltaX;
ortho[1*4+1] = 2.0 / deltaY;
ortho[3*4+1] = -(top + bottom) / deltaY;
ortho[2*4+2] = -2.0 / deltaZ;
ortho[3*4+2] = -(nearZ + farZ) / deltaZ;
return m4Copy (mat, m4Multiply (ortho, mat));
}
/* In-place inversion */
static inline float *
m4Invert (float *mat) {
float tmp_0 = m4Get(mat,2,2) * m4Get(mat,3,3);
float tmp_1 = m4Get(mat,3,2) * m4Get(mat,2,3);
float tmp_2 = m4Get(mat,1,2) * m4Get(mat,3,3);
float tmp_3 = m4Get(mat,3,2) * m4Get(mat,1,3);
float tmp_4 = m4Get(mat,1,2) * m4Get(mat,2,3);
float tmp_5 = m4Get(mat,2,2) * m4Get(mat,1,3);
float tmp_6 = m4Get(mat,0,2) * m4Get(mat,3,3);
float tmp_7 = m4Get(mat,3,2) * m4Get(mat,0,3);
float tmp_8 = m4Get(mat,0,2) * m4Get(mat,2,3);
float tmp_9 = m4Get(mat,2,2) * m4Get(mat,0,3);
float tmp_10 = m4Get(mat,0,2) * m4Get(mat,1,3);
float tmp_11 = m4Get(mat,1,2) * m4Get(mat,0,3);
float tmp_12 = m4Get(mat,2,0) * m4Get(mat,3,1);
float tmp_13 = m4Get(mat,3,0) * m4Get(mat,2,1);
float tmp_14 = m4Get(mat,1,0) * m4Get(mat,3,1);
float tmp_15 = m4Get(mat,3,0) * m4Get(mat,1,1);
float tmp_16 = m4Get(mat,1,0) * m4Get(mat,2,1);
float tmp_17 = m4Get(mat,2,0) * m4Get(mat,1,1);
float tmp_18 = m4Get(mat,0,0) * m4Get(mat,3,1);
float tmp_19 = m4Get(mat,3,0) * m4Get(mat,0,1);
float tmp_20 = m4Get(mat,0,0) * m4Get(mat,2,1);
float tmp_21 = m4Get(mat,2,0) * m4Get(mat,0,1);
float tmp_22 = m4Get(mat,0,0) * m4Get(mat,1,1);
float tmp_23 = m4Get(mat,1,0) * m4Get(mat,0,1);
float t0 = ((tmp_0 * m4Get(mat,1,1) + tmp_3 * m4Get(mat,2,1) + tmp_4 * m4Get(mat,3,1)) -
(tmp_1 * m4Get(mat,1,1) + tmp_2 * m4Get(mat,2,1) + tmp_5 * m4Get(mat,3,1)));
float t1 = ((tmp_1 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,2,1) + tmp_9 * m4Get(mat,3,1)) -
(tmp_0 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,2,1) + tmp_8 * m4Get(mat,3,1)));
float t2 = ((tmp_2 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,3,1)) -
(tmp_3 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,3,1)));
float t3 = ((tmp_5 * m4Get(mat,0,1) + tmp_8 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,2,1)) -
(tmp_4 * m4Get(mat,0,1) + tmp_9 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,2,1)));
float d = 1.0 / (m4Get(mat,0,0) * t0 + m4Get(mat,1,0) * t1 + m4Get(mat,2,0) * t2 + m4Get(mat,3,0) * t3);
float out_00 = d * t0;
float out_01 = d * t1;
float out_02 = d * t2;
float out_03 = d * t3;
float out_10 = d * ((tmp_1 * m4Get(mat,1,0) + tmp_2 * m4Get(mat,2,0) + tmp_5 * m4Get(mat,3,0)) -
(tmp_0 * m4Get(mat,1,0) + tmp_3 * m4Get(mat,2,0) + tmp_4 * m4Get(mat,3,0)));
float out_11 = d * ((tmp_0 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,2,0) + tmp_8 * m4Get(mat,3,0)) -
(tmp_1 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,2,0) + tmp_9 * m4Get(mat,3,0)));
float out_12 = d * ((tmp_3 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,3,0)) -
(tmp_2 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,3,0)));
float out_13 = d * ((tmp_4 * m4Get(mat,0,0) + tmp_9 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,2,0)) -
(tmp_5 * m4Get(mat,0,0) + tmp_8 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,2,0)));
float out_20 = d * ((tmp_12 * m4Get(mat,1,3) + tmp_15 * m4Get(mat,2,3) + tmp_16 * m4Get(mat,3,3)) -
(tmp_13 * m4Get(mat,1,3) + tmp_14 * m4Get(mat,2,3) + tmp_17 * m4Get(mat,3,3)));
float out_21 = d * ((tmp_13 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,2,3) + tmp_21 * m4Get(mat,3,3)) -
(tmp_12 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,2,3) + tmp_20 * m4Get(mat,3,3)));
float out_22 = d * ((tmp_14 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,3,3)) -
(tmp_15 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,3,3)));
float out_23 = d * ((tmp_17 * m4Get(mat,0,3) + tmp_20 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,2,3)) -
(tmp_16 * m4Get(mat,0,3) + tmp_21 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,2,3)));
float out_30 = d * ((tmp_14 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,1,2)) -
(tmp_16 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,1,2) + tmp_15 * m4Get(mat,2,2)));
float out_31 = d * ((tmp_20 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,2,2)) -
(tmp_18 * m4Get(mat,2,2) + tmp_21 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,0,2)));
float out_32 = d * ((tmp_18 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,3,2) + tmp_15 * m4Get(mat,0,2)) -
(tmp_22 * m4Get(mat,3,2) + tmp_14 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,1,2)));
float out_33 = d * ((tmp_22 * m4Get(mat,2,2) + tmp_16 * m4Get(mat,0,2) + tmp_21 * m4Get(mat,1,2)) -
(tmp_20 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,0,2)));
mat[0*4+0] = out_00;
mat[0*4+1] = out_01;
mat[0*4+2] = out_02;
mat[0*4+3] = out_03;
mat[1*4+0] = out_10;
mat[1*4+1] = out_11;
mat[1*4+2] = out_12;
mat[1*4+3] = out_13;
mat[2*4+0] = out_20;
mat[2*4+1] = out_21;
mat[2*4+2] = out_22;
mat[2*4+3] = out_23;
mat[3*4+0] = out_30;
mat[3*4+1] = out_31;
mat[3*4+2] = out_32;
mat[3*4+3] = out_33;
return mat;
}
/* Puts the inverse of other matrix into mat */
static inline float *
m4Inverse (float *mat, const float *other) {
m4Copy (mat, other);
m4Invert (mat);
return mat;
}
/* In-place transpose */
static inline float *
m4Transpose (float *mat) {
float tmp = mat[0*4+1];
mat[0*4+1] = mat[1*4+0];
mat[1*4+0] = tmp;
tmp = mat[0*4+2];
mat[0*4+2] = mat[2*4+0];
mat[2*4+0] = tmp;
tmp = mat[0*4+3];
mat[0*4+3] = mat[3*4+0];
mat[3*4+0] = tmp;
tmp = mat[1*4+2];
mat[1*4+2] = mat[2*4+1];
mat[2*4+1] = tmp;
tmp = mat[1*4+3];
mat[1*4+3] = mat[3*4+1];
mat[3*4+1] = tmp;
tmp = mat[2*4+3];
mat[2*4+3] = mat[3*4+2];
mat[3*4+2] = tmp;
return mat;
}
#endif /* MATRIX4X4_HH */