2012-03-24 23:39:19 +01:00
# include "math/lin/matrix4x4.h"
# include <stdio.h>
# include "math/lin/vec3.h"
# include "math/lin/quat.h"
2014-03-22 00:31:10 +01:00
# include "math/fast/fast_matrix.h"
2012-03-24 23:39:19 +01:00
2012-03-30 00:45:16 +02:00
# ifdef _WIN32
# undef far
# undef near
# endif
2012-10-30 13:20:55 +01:00
// See http://code.google.com/p/oolongengine/source/browse/trunk/Oolong+Engine2/Math/neonmath/neon_matrix_impl.cpp?spec=svn143&r=143 when we need speed
2012-03-24 23:39:19 +01:00
// no wait. http://code.google.com/p/math-neon/
Matrix4x4 Matrix4x4 : : simpleInverse ( ) const {
2012-10-30 13:20:55 +01:00
Matrix4x4 out ;
out . xx = xx ;
out . xy = yx ;
out . xz = zx ;
2012-05-08 22:04:24 +02:00
2012-10-30 13:20:55 +01:00
out . yx = xy ;
out . yy = yy ;
out . yz = zy ;
2012-05-08 22:04:24 +02:00
2012-10-30 13:20:55 +01:00
out . zx = xz ;
out . zy = yz ;
out . zz = zz ;
2012-05-08 22:04:24 +02:00
2012-10-30 13:20:55 +01:00
out . wx = - ( xx * wx + xy * wy + xz * wz ) ;
out . wy = - ( yx * wx + yy * wy + yz * wz ) ;
out . wz = - ( zx * wx + zy * wy + zz * wz ) ;
2012-05-08 22:04:24 +02:00
2012-10-30 13:20:55 +01:00
out . xw = 0.0f ;
out . yw = 0.0f ;
out . zw = 0.0f ;
out . ww = 1.0f ;
2012-05-08 22:04:24 +02:00
2012-10-30 13:20:55 +01:00
return out ;
2012-03-24 23:39:19 +01:00
}
2014-07-15 19:45:22 +02:00
2012-03-24 23:39:19 +01:00
Matrix4x4 Matrix4x4 : : transpose ( ) const
{
2012-10-30 13:20:55 +01:00
Matrix4x4 out ;
out . xx = xx ; out . xy = yx ; out . xz = zx ; out . xw = wx ;
out . yx = xy ; out . yy = yy ; out . yz = zy ; out . yw = wy ;
out . zx = xz ; out . zy = yz ; out . zz = zz ; out . zw = wz ;
out . wx = xw ; out . wy = yw ; out . wz = zw ; out . ww = ww ;
return out ;
2012-03-24 23:39:19 +01:00
}
Matrix4x4 Matrix4x4 : : operator * ( const Matrix4x4 & other ) const
{
2012-10-30 13:20:55 +01:00
Matrix4x4 temp ;
2014-07-15 19:45:22 +02:00
fast_matrix_mul_4x4 ( temp . m , other . m , this - > m ) ;
2012-10-30 13:20:55 +01:00
return temp ;
2012-03-24 23:39:19 +01:00
}
Matrix4x4 Matrix4x4 : : inverse ( ) const {
2012-10-30 13:20:55 +01:00
Matrix4x4 temp ;
float dW = 1.0f / ( xx * ( yy * zz - yz * zy ) - xy * ( yx * zz - yz * zx ) - xz * ( yy * zx - yx * zy ) ) ;
temp . xx = ( yy * zz - yz * zy ) * dW ;
temp . xy = ( xz * zy - xy * zz ) * dW ;
temp . xz = ( xy * yz - xz * yy ) * dW ;
temp . xw = xw ;
temp . yx = ( yz * zx - yx * zz ) * dW ;
temp . yy = ( xx * zz - xz * zx ) * dW ;
temp . yz = ( xz * yx - xx * zx ) * dW ;
temp . yw = yw ;
temp . zx = ( yx * zy - yy * zx ) * dW ;
temp . zy = ( xy * zx - xx * zy ) * dW ;
temp . zz = ( xx * yy - xy * yx ) * dW ;
temp . zw = zw ;
temp . wx = ( yy * ( zx * wz - zz * wx ) + yz * ( zy * wx - zx * wy ) - yx * ( zy * wz - zz * wy ) ) * dW ;
temp . wy = ( xx * ( zy * wz - zz * wy ) + xy * ( zz * wx - zx * wz ) + xz * ( zx * wy - zy * wx ) ) * dW ;
temp . wz = ( xy * ( yx * wz - yz * wx ) + xz * ( yy * wx - yx * wy ) - xx * ( yy * wz - yz * wy ) ) * dW ;
temp . ww = ww ;
return temp ;
2012-03-24 23:39:19 +01:00
}
void Matrix4x4 : : setViewLookAt ( const Vec3 & vFrom , const Vec3 & vAt , const Vec3 & vWorldUp ) {
2012-10-30 13:20:55 +01:00
Vec3 vView = vFrom - vAt ; // OpenGL, sigh...
vView . normalize ( ) ;
float DotProduct = vWorldUp * vView ;
Vec3 vUp = vWorldUp - vView * DotProduct ;
float Length = vUp . length ( ) ;
if ( 1e-6 f > Length ) {
// EMERGENCY
vUp = Vec3 ( 0.0f , 1.0f , 0.0f ) - vView * vView . y ;
// If we still have near-zero length, resort to a different axis.
Length = vUp . length ( ) ;
if ( 1e-6 f > Length )
{
vUp = Vec3 ( 0.0f , 0.0f , 1.0f ) - vView * vView . z ;
Length = vUp . length ( ) ;
if ( 1e-6 f > Length )
return ;
}
}
vUp . normalize ( ) ;
Vec3 vRight = vUp % vView ;
empty ( ) ;
xx = vRight . x ; xy = vUp . x ; xz = vView . x ;
yx = vRight . y ; yy = vUp . y ; yz = vView . y ;
zx = vRight . z ; zy = vUp . z ; zz = vView . z ;
wx = - vFrom * vRight ;
wy = - vFrom * vUp ;
wz = - vFrom * vView ;
ww = 1.0f ;
2012-03-24 23:39:19 +01:00
}
void Matrix4x4 : : setViewLookAtD3D ( const Vec3 & vFrom , const Vec3 & vAt , const Vec3 & vWorldUp ) {
2012-10-30 13:20:55 +01:00
Vec3 vView = vAt - vFrom ;
vView . normalize ( ) ;
float DotProduct = vWorldUp * vView ;
Vec3 vUp = vWorldUp - vView * DotProduct ;
float Length = vUp . length ( ) ;
if ( 1e-6 f > Length ) {
vUp = Vec3 ( 0.0f , 1.0f , 0.0f ) - vView * vView . y ;
// If we still have near-zero length, resort to a different axis.
Length = vUp . length ( ) ;
if ( 1e-6 f > Length )
{
vUp = Vec3 ( 0.0f , 0.0f , 1.0f ) - vView * vView . z ;
Length = vUp . length ( ) ;
if ( 1e-6 f > Length )
return ;
}
}
vUp . normalize ( ) ;
Vec3 vRight = vUp % vView ;
empty ( ) ;
xx = vRight . x ; xy = vUp . x ; xz = vView . x ;
yx = vRight . y ; yy = vUp . y ; yz = vView . y ;
zx = vRight . z ; zy = vUp . z ; zz = vView . z ;
wx = - vFrom * vRight ;
wy = - vFrom * vUp ;
wz = - vFrom * vView ;
ww = 1.0f ;
2012-03-24 23:39:19 +01:00
}
void Matrix4x4 : : setViewFrame ( const Vec3 & pos , const Vec3 & vRight , const Vec3 & vView , const Vec3 & vUp ) {
2012-10-30 13:20:55 +01:00
xx = vRight . x ; xy = vUp . x ; xz = vView . x ; xw = 0.0f ;
yx = vRight . y ; yy = vUp . y ; yz = vView . y ; yw = 0.0f ;
zx = vRight . z ; zy = vUp . z ; zz = vView . z ; zw = 0.0f ;
wx = - pos * vRight ;
wy = - pos * vUp ;
wz = - pos * vView ;
ww = 1.0f ;
2012-03-24 23:39:19 +01:00
}
//YXZ euler angles
void Matrix4x4 : : setRotation ( float x , float y , float z )
{
2012-10-30 13:20:55 +01:00
setRotationY ( y ) ;
Matrix4x4 temp ;
temp . setRotationX ( x ) ;
* this * = temp ;
temp . setRotationZ ( z ) ;
* this * = temp ;
2012-03-24 23:39:19 +01:00
}
void Matrix4x4 : : setProjection ( float near , float far , float fov_horiz , float aspect ) {
2012-10-30 13:20:55 +01:00
// Now OpenGL style.
empty ( ) ;
float xFac = tanf ( fov_horiz * 3.14f / 360 ) ;
float yFac = xFac * aspect ;
xx = 1.0f / xFac ;
yy = 1.0f / yFac ;
zz = - ( far + near ) / ( far - near ) ;
zw = - 1.0f ;
wz = - ( 2 * far * near ) / ( far - near ) ;
2012-03-24 23:39:19 +01:00
}
void Matrix4x4 : : setProjectionD3D ( float near_plane , float far_plane , float fov_horiz , float aspect ) {
2012-10-30 13:20:55 +01:00
empty ( ) ;
float Q , f ;
2012-05-08 22:04:24 +02:00
2012-10-30 13:20:55 +01:00
f = fov_horiz * 0.5f ;
Q = far_plane / ( far_plane - near_plane ) ;
2012-05-08 22:04:24 +02:00
2012-10-30 13:20:55 +01:00
xx = ( float ) ( 1.0f / tanf ( f ) ) ; ;
yy = ( float ) ( 1.0f / tanf ( f * aspect ) ) ;
zz = Q ;
wz = - Q * near_plane ;
zw = 1.0f ;
2012-03-24 23:39:19 +01:00
}
void Matrix4x4 : : setOrtho ( float left , float right , float bottom , float top , float near , float far ) {
2012-10-30 13:20:55 +01:00
setIdentity ( ) ;
xx = 2.0f / ( right - left ) ;
yy = 2.0f / ( top - bottom ) ;
zz = 2.0f / ( far - near ) ;
wx = - ( right + left ) / ( right - left ) ;
wy = - ( top + bottom ) / ( top - bottom ) ;
wz = - ( far + near ) / ( far - near ) ;
2012-03-24 23:39:19 +01:00
}
2014-08-17 21:28:34 +02:00
void Matrix4x4 : : setOrthoD3D ( float left , float right , float bottom , float top , float near , float far ) {
setIdentity ( ) ;
xx = 2.0f / ( right - left ) ;
yy = 2.0f / ( top - bottom ) ;
zz = 1.0f / ( far - near ) ;
wx = - ( right + left ) / ( right - left ) ;
wy = - ( top + bottom ) / ( top - bottom ) ;
wz = - near / ( far - near ) ;
}
2012-03-24 23:39:19 +01:00
void Matrix4x4 : : setProjectionInf ( const float near_plane , const float fov_horiz , const float aspect ) {
2012-10-30 13:20:55 +01:00
empty ( ) ;
float f = fov_horiz * 0.5f ;
xx = 1.0f / tanf ( f ) ;
yy = 1.0f / tanf ( f * aspect ) ;
zz = 1 ;
wz = - near_plane ;
zw = 1.0f ;
2012-03-24 23:39:19 +01:00
}
void Matrix4x4 : : setRotationAxisAngle ( const Vec3 & axis , float angle ) {
2012-10-30 13:20:55 +01:00
Quaternion quat ;
quat . setRotation ( axis , angle ) ;
quat . toMatrix ( this ) ;
2012-03-24 23:39:19 +01:00
}
// from a (Position, Rotation, Scale) vec3 quat vec3 tuple
Matrix4x4 Matrix4x4 : : fromPRS ( const Vec3 & positionv , const Quaternion & rotv , const Vec3 & scalev ) {
2012-10-30 13:20:55 +01:00
Matrix4x4 newM ;
newM . setIdentity ( ) ;
Matrix4x4 rot , scale ;
rotv . toMatrix ( & rot ) ;
scale . setScaling ( scalev ) ;
newM = rot * scale ;
newM . wx = positionv . x ;
newM . wy = positionv . y ;
newM . wz = positionv . z ;
return newM ;
2012-03-24 23:39:19 +01:00
}
# if _MSC_VER
# define snprintf _snprintf
# endif
void Matrix4x4 : : toText ( char * buffer , int len ) const {
2012-10-30 13:20:55 +01:00
snprintf ( buffer , len , " %f %f %f %f \n %f %f %f %f \n %f %f %f %f \n %f %f %f %f \n " ,
xx , xy , xz , xw ,
yx , yy , yz , yw ,
zx , zy , zz , zw ,
wx , wy , wz , ww ) ;
buffer [ len - 1 ] = ' \0 ' ;
2012-03-24 23:39:19 +01:00
}
void Matrix4x4 : : print ( ) const {
2012-10-30 13:20:55 +01:00
char buffer [ 256 ] ;
toText ( buffer , 256 ) ;
puts ( buffer ) ;
2012-03-24 23:39:19 +01:00
}