mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
1050 lines
30 KiB
C++
1050 lines
30 KiB
C++
|
/*****************************************************************************
|
|||
|
** **
|
|||
|
** Neversoft Entertainment **
|
|||
|
** **
|
|||
|
** Copyright (C) 1999 - All Rights Reserved **
|
|||
|
** **
|
|||
|
******************************************************************************
|
|||
|
** **
|
|||
|
** Project: Core Library **
|
|||
|
** **
|
|||
|
** Module: Math (MTH) **
|
|||
|
** **
|
|||
|
** File name: matrix.cpp **
|
|||
|
** **
|
|||
|
** Created by: 10/03/2000 - mjb **
|
|||
|
** **
|
|||
|
** Description: Matrix Math Library code **
|
|||
|
** **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** Includes **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
#include <core/defines.h>
|
|||
|
#include <core/math.h>
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** DBG Information **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
namespace Mth
|
|||
|
{
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** Externals **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** Defines **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** Private Types **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** Private Data **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** Public Data **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** Private Prototypes **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** Private Functions **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
** Public Functions **
|
|||
|
*****************************************************************************/
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
Matrix::Matrix( float p, float h, float r)
|
|||
|
{
|
|||
|
|
|||
|
// Algorithm from http://www.flipcode.com/documents/matrfaq.html#Q37
|
|||
|
float A,B,C,D,E,F,AD,BD;
|
|||
|
|
|||
|
A = cosf( p );
|
|||
|
B = sinf( p );
|
|||
|
C = cosf( h );
|
|||
|
D = sinf( h );
|
|||
|
E = cosf( r );
|
|||
|
F = sinf( r );
|
|||
|
|
|||
|
AD = A * D;
|
|||
|
BD = B * D;
|
|||
|
|
|||
|
row[0][0] = C * E;
|
|||
|
row[0][1] = -C * F;
|
|||
|
row[0][2] = -D;
|
|||
|
row[1][0] = -BD * E + A * F;
|
|||
|
row[1][1] = BD * F + A * E;
|
|||
|
row[1][2] = -B * C;
|
|||
|
row[2][0] = AD * E + B * F;
|
|||
|
row[2][1] = -AD * F + B * E;
|
|||
|
row[2][2] = A * C;
|
|||
|
|
|||
|
row[0][3] = row[1][3] = row[2][3] = row[3][0] = row[3][1] = row[3][2] = 0.0f;
|
|||
|
row[3][3] = 1.0f;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef __PLAT_NGPS__
|
|||
|
void xsceVu0MulMatrix(Mth::Matrix* m0, Mth::Matrix* m1, const Mth::Matrix* m2)
|
|||
|
{
|
|||
|
|
|||
|
asm __volatile__("
|
|||
|
lqc2 vf4,0x0(%2)
|
|||
|
lqc2 vf5,0x10(%2)
|
|||
|
lqc2 vf6,0x20(%2)
|
|||
|
lqc2 vf7,0x30(%2)
|
|||
|
li $7,4
|
|||
|
_loopMulMatrix:
|
|||
|
lqc2 vf8,0x0(%1)
|
|||
|
vmulax.xyzw ACC, vf4,vf8
|
|||
|
vmadday.xyzw ACC, vf5,vf8
|
|||
|
vmaddaz.xyzw ACC, vf6,vf8
|
|||
|
vmaddw.xyzw vf9,vf7,vf8
|
|||
|
sqc2 vf9,0x0(%0)
|
|||
|
addi $7,-1
|
|||
|
addi %1,0x10
|
|||
|
addi %0,0x10
|
|||
|
bne $0,$7,_loopMulMatrix
|
|||
|
": : "r" (m0), "r" (m2), "r" (m1) : "$7");
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
// Ken: Faster version of atan2f, using the same algorithm used by VU1
|
|||
|
// (Coeefficients got from the VU manual, from documentation of EATANxy function, p130
|
|||
|
// SPEEDOPT: This could probably be made even faster using a less accurate approx with few coeffs.
|
|||
|
float katan(float y, float x)
|
|||
|
{
|
|||
|
if (fabs(y)>fabs(x))
|
|||
|
{
|
|||
|
// The approximation only works for y<=x, bummer!
|
|||
|
return atan2f(y,x);
|
|||
|
}
|
|||
|
register bool x_negative=false;
|
|||
|
register bool y_negative=false;
|
|||
|
if (x<0.0f)
|
|||
|
{
|
|||
|
x=-x;
|
|||
|
x_negative=true;
|
|||
|
}
|
|||
|
if (y<=-0.0f)
|
|||
|
{
|
|||
|
y=-y;
|
|||
|
y_negative=true;
|
|||
|
}
|
|||
|
|
|||
|
// Use the non-ratio version, because the ratio version goes
|
|||
|
// all innaccurate for some values ... don't know why ...
|
|||
|
y=y/x;
|
|||
|
|
|||
|
register float t1=0.999999344348907f;
|
|||
|
register float t2=-0.333298563957214f;
|
|||
|
register float t3=0.199465364217758f;
|
|||
|
register float t4=-0.139085337519646f;
|
|||
|
register float t5=0.096420042216778f;
|
|||
|
register float t6=-0.055909886956215f;
|
|||
|
register float t7=0.021861229091883f;
|
|||
|
register float t8=-0.004054057877511f;
|
|||
|
|
|||
|
register float t=(y-1.0f)/(y+1.0f);
|
|||
|
register float tt=t*t;
|
|||
|
register float s=t8*t;
|
|||
|
s=s*tt+t7*t;
|
|||
|
s=s*tt+t6*t;
|
|||
|
s=s*tt+t5*t;
|
|||
|
s=s*tt+t4*t;
|
|||
|
s=s*tt+t3*t;
|
|||
|
s=s*tt+t2*t;
|
|||
|
s=s*tt+t1*t;
|
|||
|
if (x_negative)
|
|||
|
{
|
|||
|
if (y_negative)
|
|||
|
{
|
|||
|
return s+0.785398185253143f-3.141592653589793f;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return 3.141592653589793f-0.785398185253143f-s;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (y_negative)
|
|||
|
{
|
|||
|
return -0.785398185253143f-s;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return s+0.785398185253143f;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Matrix::GetEulers( Vector& euler ) const
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
// Algorithm from http://www.flipcode.com/documents/matrfaq.html#Q37
|
|||
|
float C, D;
|
|||
|
float tr_x, tr_y;
|
|||
|
|
|||
|
#ifdef __PLAT_NGC__
|
|||
|
float ang = row[0][2];
|
|||
|
if ( ang > 1.0f ) ang = 1.0f;
|
|||
|
if ( ang < -1.0f ) ang = -1.0f;
|
|||
|
euler[Y] = D = -asinf( ang ); /* Calculate Y-axis angle */
|
|||
|
#else
|
|||
|
float ang = row[0][2];
|
|||
|
if ( ang > 1.0f ) ang = 1.0f;
|
|||
|
if ( ang < -1.0f ) ang = -1.0f;
|
|||
|
euler[Y] = D = -asinf( ang ); /* Calculate Y-axis angle */
|
|||
|
// euler[Y] = D = -asinf( row[0][2]); /* Calculate Y-axis angle */
|
|||
|
#endif // __PLAT_NGC__
|
|||
|
C = cosf( euler[Y] );
|
|||
|
|
|||
|
if( fabsf( C ) > 0.005f ) /* Gimball lock? */
|
|||
|
{
|
|||
|
tr_x = row[2][2] / C; /* No, so get X-axis angle */
|
|||
|
tr_y = -row[1][2] / C;
|
|||
|
|
|||
|
euler[X] = katan( tr_y, tr_x );
|
|||
|
|
|||
|
tr_x = row[0][0] / C; /* Get Z-axis angle */
|
|||
|
tr_y = -row[0][1] / C;
|
|||
|
|
|||
|
euler[Z] = katan( tr_y, tr_x );
|
|||
|
}
|
|||
|
else /* Gimball lock has occurred */
|
|||
|
{
|
|||
|
euler[X] = 0; /* Set X-axis angle to zero */
|
|||
|
|
|||
|
tr_x = row[1][1]; /* And calculate Z-axis angle */
|
|||
|
tr_y = row[1][0];
|
|||
|
|
|||
|
euler[Z] = katan( tr_y, tr_x );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
void Matrix::PrintContents() const
|
|||
|
{
|
|||
|
printf( "-----------------\n" );
|
|||
|
printf( "%f %f %f %f\n", row[RIGHT][X], row[RIGHT][Y], row[RIGHT][Z], row[RIGHT][W] );
|
|||
|
printf( "%f %f %f %f\n", row[UP][X], row[UP][Y], row[UP][Z], row[UP][W] );
|
|||
|
printf( "%f %f %f %f\n", row[AT][X], row[AT][Y], row[AT][Z], row[AT][W] );
|
|||
|
printf( "%f %f %f %f\n", row[POS][X], row[POS][Y], row[POS][Z], row[POS][W] );
|
|||
|
printf( "-----------------\n" );
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
/*
|
|||
|
// Original source of the optimized fromToRoation function
|
|||
|
|
|||
|
#include <math.h>
|
|||
|
|
|||
|
#define EPSILON 0.000001
|
|||
|
|
|||
|
#define CROSS(dest, v1, v2){ \
|
|||
|
dest[0] = v1[1] * v2[2] - v1[2] * v2[1]; \
|
|||
|
dest[1] = v1[2] * v2[0] - v1[0] * v2[2]; \
|
|||
|
dest[2] = v1[0] * v2[1] - v1[1] * v2[0];}
|
|||
|
|
|||
|
#define DOT(v1, v2) (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2])
|
|||
|
|
|||
|
#define SUB(dest, v1, v2){ \
|
|||
|
dest[0] = v1[0] - v2[0]; \
|
|||
|
dest[1] = v1[1] - v2[1]; \
|
|||
|
dest[2] = v1[2] - v2[2];}
|
|||
|
|
|||
|
//
|
|||
|
// * A function for creating a rotation matrix that rotates a vector called
|
|||
|
// * "from" into another vector called "to".
|
|||
|
// * Input : from[3], to[3] which both must be *normalized* non-zero vectors
|
|||
|
// * Output: mtx[3][3] -- a 3x3 matrix in colum-major form
|
|||
|
// * Authors: Tomas M<>ller, John Hughes 1999
|
|||
|
//
|
|||
|
void fromToRotation(float from[3], float to[3], float mtx[3][3])
|
|||
|
{
|
|||
|
float v[3];
|
|||
|
float e, h, f;
|
|||
|
|
|||
|
CROSS(v, from, to);
|
|||
|
e = DOT(from, to);
|
|||
|
f = (e < 0)? -e:e;
|
|||
|
if (f > 1.0 - EPSILON) // "from" and "to"-vector almost parallel
|
|||
|
{
|
|||
|
float u[3], v[3]; // temporary storage vectors
|
|||
|
float x[3]; // vector most nearly orthogonal to "from"
|
|||
|
float c1, c2, c3; // coefficients for later use
|
|||
|
int i, j;
|
|||
|
|
|||
|
x[0] = (from[0] > 0.0)? from[0] : -from[0];
|
|||
|
x[1] = (from[1] > 0.0)? from[1] : -from[1];
|
|||
|
x[2] = (from[2] > 0.0)? from[2] : -from[2];
|
|||
|
|
|||
|
if (x[0] < x[1])
|
|||
|
{
|
|||
|
if (x[0] < x[2])
|
|||
|
{
|
|||
|
x[0] = 1.0; x[1] = x[2] = 0.0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
x[2] = 1.0; x[0] = x[1] = 0.0;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (x[1] < x[2])
|
|||
|
{
|
|||
|
x[1] = 1.0; x[0] = x[2] = 0.0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
x[2] = 1.0; x[0] = x[1] = 0.0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
u[0] = x[0] - from[0]; u[1] = x[1] - from[1]; u[2] = x[2] - from[2];
|
|||
|
v[0] = x[0] - to[0]; v[1] = x[1] - to[1]; v[2] = x[2] - to[2];
|
|||
|
|
|||
|
c1 = 2.0 / DOT(u, u);
|
|||
|
c2 = 2.0 / DOT(v, v);
|
|||
|
c3 = c1 * c2 * DOT(u, v);
|
|||
|
|
|||
|
for (i = 0; i < 3; i++) {
|
|||
|
for (j = 0; j < 3; j++) {
|
|||
|
mtx[i][j] = - c1 * u[i] * u[j]
|
|||
|
- c2 * v[i] * v[j]
|
|||
|
+ c3 * v[i] * u[j];
|
|||
|
}
|
|||
|
mtx[i][i] += 1.0;
|
|||
|
}
|
|||
|
}
|
|||
|
else // the most common case, unless "from"="to", or "from"=-"to"
|
|||
|
{
|
|||
|
#if 0
|
|||
|
// unoptimized version - a good compiler will optimize this.
|
|||
|
h = (1.0 - e)/DOT(v, v);
|
|||
|
mtx[0][0] = e + h * v[0] * v[0];
|
|||
|
mtx[0][1] = h * v[0] * v[1] - v[2];
|
|||
|
mtx[0][2] = h * v[0] * v[2] + v[1];
|
|||
|
|
|||
|
mtx[1][0] = h * v[0] * v[1] + v[2];
|
|||
|
mtx[1][1] = e + h * v[1] * v[1];
|
|||
|
mtx[1][2] = h * v[1] * v[2] - v[0];
|
|||
|
|
|||
|
mtx[2][0] = h * v[0] * v[2] - v[1];
|
|||
|
mtx[2][1] = h * v[1] * v[2] + v[0];
|
|||
|
mtx[2][2] = e + h * v[2] * v[2];
|
|||
|
#else
|
|||
|
// ...otherwise use this hand optimized version (9 mults less)
|
|||
|
float hvx, hvz, hvxy, hvxz, hvyz;
|
|||
|
h = (1.0 - e)/DOT(v, v);
|
|||
|
hvx = h * v[0];
|
|||
|
hvz = h * v[2];
|
|||
|
hvxy = hvx * v[1];
|
|||
|
hvxz = hvx * v[2];
|
|||
|
hvyz = hvz * v[1];
|
|||
|
mtx[0][0] = e + hvx * v[0];
|
|||
|
mtx[0][1] = hvxy - v[2];
|
|||
|
mtx[0][2] = hvxz + v[1];
|
|||
|
|
|||
|
mtx[1][0] = hvxy + v[2];
|
|||
|
mtx[1][1] = e + h * v[1] * v[1];
|
|||
|
mtx[1][2] = hvyz - v[0];
|
|||
|
|
|||
|
mtx[2][0] = hvxz - v[1];
|
|||
|
mtx[2][1] = hvyz + v[0];
|
|||
|
mtx[2][2] = e + hvz * v[2];
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
#define FROMTO_EPSILON 0.000001f
|
|||
|
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////////
|
|||
|
//Matrix& CreateFromToMatrix( Matrix &mtx, Vector from, Vector to )
|
|||
|
//
|
|||
|
// * A function for creating a rotation matrix that rotates a vector called
|
|||
|
// * "from" into another vector called "to".
|
|||
|
// * Input : from[3], to[3] which both must be *normalized* non-zero vectors
|
|||
|
// * Output: mtx[3][3] -- a 3x3 matrix in colum-major form
|
|||
|
// * Authors: Tomas M<>ller, John Hughes 1999
|
|||
|
//
|
|||
|
//
|
|||
|
// Micknote .. on testing this, it seems like it produces the inverse of what we want
|
|||
|
// possibly just need to swap the from/to vectors, but for now I'm just inverting it
|
|||
|
// at the end of the function, before it returns the matrix
|
|||
|
//
|
|||
|
// Sample usage:
|
|||
|
// Mth::Matrix rotate;
|
|||
|
// Mth::CreateFromToMatrix(rotate,m_matrix[Y],m_normal);
|
|||
|
// m_matrix *= rotate;
|
|||
|
//
|
|||
|
// will rotate m_matrix, so the Y component is coincident with m_normal
|
|||
|
// (this is used to align the skater to a surface, given the surface normal)
|
|||
|
//
|
|||
|
|
|||
|
Matrix& CreateFromToMatrix( Matrix &mtx, Vector from, Vector to )
|
|||
|
{
|
|||
|
Vector cross;
|
|||
|
float e, h, f;
|
|||
|
|
|||
|
|
|||
|
mtx.Ident(); // clean up W rows and cols
|
|||
|
|
|||
|
|
|||
|
cross = CrossProduct(from,to); // CROSS(v, from, to);
|
|||
|
e = DotProduct(from,to); // e = DOT(from, to);
|
|||
|
f = (e < 0.0f)? -e:e;
|
|||
|
if (f > 1.0f - FROMTO_EPSILON) // "from" and "to"-vector almost parallel
|
|||
|
{
|
|||
|
Vector u, v; // temporary storage vectors
|
|||
|
Vector x; // vector most nearly orthogonal to "from"
|
|||
|
float c1, c2, c3; // coefficients for later use
|
|||
|
int i, j;
|
|||
|
|
|||
|
x[0] = (from[0] >= 0.0f)? from[0] : -from[0];
|
|||
|
x[1] = (from[1] >= 0.0f)? from[1] : -from[1];
|
|||
|
x[2] = (from[2] >= 0.0f)? from[2] : -from[2];
|
|||
|
|
|||
|
if (x[0] < x[1])
|
|||
|
{
|
|||
|
if (x[0] < x[2])
|
|||
|
{
|
|||
|
x[0] = 1.0f; x[1] = x[2] = 0.0f;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
x[2] = 1.0f; x[0] = x[1] = 0.0f;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (x[1] < x[2])
|
|||
|
{
|
|||
|
x[1] = 1.0f; x[0] = x[2] = 0.0f;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
x[2] = 1.0f; x[0] = x[1] = 0.0f;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
u[0] = x[0] - from[0]; u[1] = x[1] - from[1]; u[2] = x[2] - from[2];
|
|||
|
v[0] = x[0] - to[0]; v[1] = x[1] - to[1]; v[2] = x[2] - to[2];
|
|||
|
|
|||
|
c1 = 2.0f / DotProduct(u, u);
|
|||
|
c2 = 2.0f / DotProduct(v, v);
|
|||
|
c3 = c1 * c2 * DotProduct(u, v);
|
|||
|
|
|||
|
for (i = 0; i < 3; i++)
|
|||
|
{
|
|||
|
for (j = 0; j < 3; j++)
|
|||
|
{
|
|||
|
mtx[i][j] = - c1 * u[i] * u[j]
|
|||
|
- c2 * v[i] * v[j]
|
|||
|
+ c3 * v[i] * u[j];
|
|||
|
}
|
|||
|
mtx[i][i] += 1.0f;
|
|||
|
}
|
|||
|
}
|
|||
|
else // the most common case, unless "from"="to", or "from"=-"to"
|
|||
|
{
|
|||
|
#if 0
|
|||
|
// unoptimized version - a good compiler will optimize this.
|
|||
|
h = (1.0f - e)/DOT(v, v);
|
|||
|
mtx[0][0] = e + h * v[0] * v[0];
|
|||
|
mtx[0][1] = h * v[0] * v[1] - v[2];
|
|||
|
mtx[0][2] = h * v[0] * v[2] + v[1];
|
|||
|
|
|||
|
mtx[1][0] = h * v[0] * v[1] + v[2];
|
|||
|
mtx[1][1] = e + h * v[1] * v[1];
|
|||
|
mtx[1][2] = h * v[1] * v[2] - v[0];
|
|||
|
|
|||
|
mtx[2][0] = h * v[0] * v[2] - v[1];
|
|||
|
mtx[2][1] = h * v[1] * v[2] + v[0];
|
|||
|
mtx[2][2] = e + h * v[2] * v[2];
|
|||
|
#else
|
|||
|
// ...otherwise use this hand optimized version (9 mults less)
|
|||
|
float hvx, hvz, hvxy, hvxz, hvyz;
|
|||
|
h = (1.0f - e)/DotProduct(cross, cross);
|
|||
|
hvx = h * cross[0];
|
|||
|
hvz = h * cross[2];
|
|||
|
hvxy = hvx * cross[1];
|
|||
|
hvxz = hvx * cross[2];
|
|||
|
hvyz = hvz * cross[1];
|
|||
|
mtx[0][0] = e + hvx * cross[0];
|
|||
|
mtx[0][1] = hvxy - cross[2];
|
|||
|
mtx[0][2] = hvxz + cross[1];
|
|||
|
|
|||
|
mtx[1][0] = hvxy + cross[2];
|
|||
|
mtx[1][1] = e + h * cross[1] * cross[1];
|
|||
|
mtx[1][2] = hvyz - cross[0];
|
|||
|
|
|||
|
mtx[2][0] = hvxz - cross[1];
|
|||
|
mtx[2][1] = hvyz + cross[0];
|
|||
|
mtx[2][2] = e + hvz * cross[2];
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
mtx.Invert(); // Micknote: not sure why we need to invert it, but let it be for now
|
|||
|
|
|||
|
|
|||
|
return mtx;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Matrix& CreateRotateMatrix ( Matrix& mat, const Vector& axis, const float angle )
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
Vector unitAxis = axis;
|
|||
|
unitAxis.Normalize();
|
|||
|
|
|||
|
float oneMinusCosine = 1.0f - cosf( angle );
|
|||
|
|
|||
|
Vector leading;
|
|||
|
|
|||
|
leading[X] = 1.0f - ( unitAxis[X] * unitAxis[X] );
|
|||
|
leading[Y] = 1.0f - ( unitAxis[Y] * unitAxis[Y] );
|
|||
|
leading[Z] = 1.0f - ( unitAxis[Z] * unitAxis[Z] );
|
|||
|
leading *= oneMinusCosine;
|
|||
|
|
|||
|
Vector crossed;
|
|||
|
|
|||
|
crossed[X] = ( unitAxis[Y] * unitAxis[Z] );
|
|||
|
crossed[Y] = ( unitAxis[Z] * unitAxis[X] );
|
|||
|
crossed[Z] = ( unitAxis[X] * unitAxis[Y] );
|
|||
|
crossed *= oneMinusCosine;
|
|||
|
|
|||
|
unitAxis *= sinf( angle );
|
|||
|
|
|||
|
mat[RIGHT][X] = 1.0f - leading[X];
|
|||
|
mat[RIGHT][Y] = crossed[Z] + unitAxis[Z];
|
|||
|
mat[RIGHT][Z] = crossed[Y] - unitAxis[Y];
|
|||
|
mat[RIGHT][W] = 0.0f;
|
|||
|
|
|||
|
mat[UP][X] = crossed[Z] - unitAxis[Z];
|
|||
|
mat[UP][Y] = 1.0f - leading[Y];
|
|||
|
mat[UP][Z] = crossed[X] + unitAxis[X];
|
|||
|
mat[UP][W] = 0.0f;
|
|||
|
|
|||
|
mat[AT][X] = crossed[Y] + unitAxis[Y];
|
|||
|
mat[AT][Y] = crossed[X] - unitAxis[X];
|
|||
|
mat[AT][Z] = 1.0f - leading[Z];
|
|||
|
mat[AT][W] = 0.0f;
|
|||
|
|
|||
|
mat[POS][X] = 0.0f;
|
|||
|
mat[POS][Y] = 0.0f;
|
|||
|
mat[POS][Z] = 0.0f;
|
|||
|
mat[POS][W] = 1.0f;
|
|||
|
|
|||
|
return mat;
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
Matrix& CreateRotateXMatrix( Matrix& rotX, float angle )
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
float s = sinf( angle );
|
|||
|
float c = cosf( angle );
|
|||
|
|
|||
|
rotX[RIGHT][X] = 1.0f;
|
|||
|
rotX[RIGHT][Y] = 0.0f;
|
|||
|
rotX[RIGHT][Z] = 0.0f;
|
|||
|
rotX[RIGHT][W] = 0.0f;
|
|||
|
|
|||
|
rotX[UP][X] = 0.0f;
|
|||
|
rotX[UP][Y] = c;
|
|||
|
rotX[UP][Z] = s;
|
|||
|
rotX[UP][W] = 0.0f;
|
|||
|
|
|||
|
rotX[AT][X] = 0.0f;
|
|||
|
rotX[AT][Y] = -s;
|
|||
|
rotX[AT][Z] = c;
|
|||
|
rotX[AT][W] = 0.0f;
|
|||
|
|
|||
|
rotX[POS][X] = 0.0f;
|
|||
|
rotX[POS][Y] = 0.0f;
|
|||
|
rotX[POS][Z] = 0.0f;
|
|||
|
rotX[POS][W] = 1.0f;
|
|||
|
|
|||
|
return rotX;
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
Matrix& CreateRotateYMatrix( Matrix& rotY, float angle )
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
float s = sinf( angle );
|
|||
|
float c = cosf( angle );
|
|||
|
|
|||
|
rotY[RIGHT][X] = c;
|
|||
|
rotY[RIGHT][Y] = 0.0f;
|
|||
|
rotY[RIGHT][Z] = -s;
|
|||
|
rotY[RIGHT][W] = 0.0f;
|
|||
|
|
|||
|
rotY[UP][X] = 0.0f;
|
|||
|
rotY[UP][Y] = 1.0f;
|
|||
|
rotY[UP][Z] = 0.0f;
|
|||
|
rotY[UP][W] = 0.0f;
|
|||
|
|
|||
|
rotY[AT][X] = s;
|
|||
|
rotY[AT][Y] = 0.0f;
|
|||
|
rotY[AT][Z] = c;
|
|||
|
rotY[AT][W] = 0.0f;
|
|||
|
|
|||
|
rotY[POS][X] = 0.0f;
|
|||
|
rotY[POS][Y] = 0.0f;
|
|||
|
rotY[POS][Z] = 0.0f;
|
|||
|
rotY[POS][W] = 1.0f;
|
|||
|
|
|||
|
return rotY;
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
Matrix& CreateRotateZMatrix( Matrix& rotZ, float angle )
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
float s = sinf( angle );
|
|||
|
float c = cosf( angle );
|
|||
|
|
|||
|
rotZ[RIGHT][X] = c;
|
|||
|
rotZ[RIGHT][Y] = s;
|
|||
|
rotZ[RIGHT][Z] = 0.0f;
|
|||
|
rotZ[RIGHT][W] = 0.0f;
|
|||
|
|
|||
|
rotZ[UP][X] = -s;
|
|||
|
rotZ[UP][Y] = c;
|
|||
|
rotZ[UP][Z] = 0;
|
|||
|
rotZ[UP][W] = 0.0f;
|
|||
|
|
|||
|
rotZ[AT][X] = 0.0f;
|
|||
|
rotZ[AT][Y] = 0.0f;
|
|||
|
rotZ[AT][Z] = 1.0f;
|
|||
|
rotZ[AT][W] = 0.0f;
|
|||
|
|
|||
|
rotZ[POS][X] = 0.0f;
|
|||
|
rotZ[POS][Y] = 0.0f;
|
|||
|
rotZ[POS][Z] = 0.0f;
|
|||
|
rotZ[POS][W] = 1.0f;
|
|||
|
|
|||
|
return rotZ;
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
Matrix& CreateRotateMatrix( Matrix &rot, int axis, const float angle )
|
|||
|
{
|
|||
|
int a = (axis + 1) % (Z + 1);
|
|||
|
int b = (axis + 2) % (Z + 1);
|
|||
|
|
|||
|
float s = sinf( angle );
|
|||
|
float c = cosf( angle );
|
|||
|
|
|||
|
rot.Ident();
|
|||
|
|
|||
|
rot[a][a] = c;
|
|||
|
rot[a][b] = s;
|
|||
|
rot[b][a] = -s;
|
|||
|
rot[b][b] = c;
|
|||
|
|
|||
|
return rot;
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
Matrix& CreateMatrixLookAt( Matrix& mat, const Vector& pos, const Vector& lookat, const Vector& up )
|
|||
|
{
|
|||
|
// Create Z axis
|
|||
|
Mth::Vector z_axis(lookat - pos);
|
|||
|
z_axis.Normalize();
|
|||
|
//mat[Z] = z_axis;
|
|||
|
|
|||
|
// Create X from Z and up (up assumed to be normalized)
|
|||
|
Mth::Vector x_axis(Mth::CrossProduct(z_axis, up));
|
|||
|
//mat[X] = x_axis;
|
|||
|
|
|||
|
// Create Y from Z and X
|
|||
|
Mth::Vector y_axis(Mth::CrossProduct(x_axis, z_axis));
|
|||
|
//mat[Y] = y_axis;
|
|||
|
|
|||
|
// Orientation needs transposing (since we want the inverse orientation)
|
|||
|
//mat.Transpose();
|
|||
|
mat[X][X] = x_axis[X];
|
|||
|
mat[Y][X] = x_axis[Y];
|
|||
|
mat[Z][X] = x_axis[Z];
|
|||
|
|
|||
|
mat[X][Y] = y_axis[X];
|
|||
|
mat[Y][Y] = y_axis[Y];
|
|||
|
mat[Z][Y] = y_axis[Z];
|
|||
|
|
|||
|
mat[X][Z] = z_axis[X];
|
|||
|
mat[Y][Z] = z_axis[Y];
|
|||
|
mat[Z][Z] = z_axis[Z];
|
|||
|
|
|||
|
// These may not be zero, but should be
|
|||
|
mat[X][W] = 0.0f;
|
|||
|
mat[Y][W] = 0.0f;
|
|||
|
mat[Z][W] = 0.0f;
|
|||
|
|
|||
|
// Create inverse translation
|
|||
|
mat[POS][X] = -Mth::DotProduct(x_axis, pos);
|
|||
|
mat[POS][Y] = -Mth::DotProduct(y_axis, pos);
|
|||
|
mat[POS][Z] = -Mth::DotProduct(z_axis, pos);
|
|||
|
mat[POS][W] = 1.0f;
|
|||
|
|
|||
|
//Dbg_Message("LookAt matrix:");
|
|||
|
//Dbg_Message("[ %f, %f, %f, %f ]", mat[X][X], mat[X][Y], mat[X][Z], mat[X][W]);
|
|||
|
//Dbg_Message("[ %f, %f, %f, %f ]", mat[Y][X], mat[Y][Y], mat[Y][Z], mat[Y][W]);
|
|||
|
//Dbg_Message("[ %f, %f, %f, %f ]", mat[Z][X], mat[Z][Y], mat[Z][Z], mat[Z][W]);
|
|||
|
//Dbg_Message("[ %f, %f, %f, %f ]", mat[W][X], mat[W][Y], mat[W][Z], mat[W][W]);
|
|||
|
|
|||
|
return mat;
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
Matrix& CreateMatrixOrtho( Matrix& mat, float width, float height, float f_near, float f_far )
|
|||
|
{
|
|||
|
mat[X] = Mth::Vector(2.0f / width, 0.0f, 0.0f, 0.0f);
|
|||
|
mat[Y] = Mth::Vector(0.0f, 2.0f / height, 0.0f, 0.0f);
|
|||
|
mat[Z] = Mth::Vector(0.0f, 0.0f, 2.0f / (f_far - f_near), 0.0f);
|
|||
|
mat[W] = Mth::Vector(0.0f, 0.0f, -(f_far + f_near) / (f_far - f_near), 1.0f);
|
|||
|
|
|||
|
//Dbg_Message("Orthographic matrix:");
|
|||
|
//Dbg_Message("[ %f, %f, %f, %f ]", mat[X][X], mat[X][Y], mat[X][Z], mat[X][W]);
|
|||
|
//Dbg_Message("[ %f, %f, %f, %f ]", mat[Y][X], mat[Y][Y], mat[Y][Z], mat[Y][W]);
|
|||
|
//Dbg_Message("[ %f, %f, %f, %f ]", mat[Z][X], mat[Z][Y], mat[Z][Z], mat[Z][W]);
|
|||
|
//Dbg_Message("[ %f, %f, %f, %f ]", mat[W][X], mat[W][Y], mat[W][Z], mat[W][W]);
|
|||
|
|
|||
|
return mat;
|
|||
|
}
|
|||
|
|
|||
|
// Orthonormalize a matrix keeping one row r0 unchanged
|
|||
|
// (Mick accepts responsibility for this).
|
|||
|
Matrix& Matrix::OrthoNormalizeAbout(int r0)
|
|||
|
{
|
|||
|
int r1, r2;
|
|||
|
r1 = r0+1;
|
|||
|
if (r1 == 3)
|
|||
|
{
|
|||
|
r1 = 0;
|
|||
|
}
|
|||
|
r2 = r1+1;
|
|||
|
if (r2 == 3)
|
|||
|
{
|
|||
|
r2 = 0;
|
|||
|
}
|
|||
|
// Now regarding Rows r0,r1,r2
|
|||
|
// r0 = r1 x r2 (implied)
|
|||
|
// r1 = r2 x r0 (calculate this)
|
|||
|
// r2 = r0 x r1 (and this)
|
|||
|
//
|
|||
|
// We need to recalculate rows r1 and r2 using the above cross produces
|
|||
|
// however if r0 is close to r2, then the calculation of r1 will be off
|
|||
|
// so it's better to calulate r2 and then r1
|
|||
|
// the first pair to do will be whichever has the smaller dot product
|
|||
|
|
|||
|
if (Abs(DotProduct(*(Vector*)(row[r2]),*(Vector*)(row[r0]))) < Abs(DotProduct(*(Vector*)(row[r0]),*(Vector*)(row[r1]))))
|
|||
|
{
|
|||
|
*(Vector*)(row[r1]) = Mth::CrossProduct(*(Vector*)(row[r2]),*(Vector*)(row[r0]));
|
|||
|
(*(Vector*)(row[r1])).Normalize();
|
|||
|
*(Vector*)(row[r2]) = Mth::CrossProduct(*(Vector*)(row[r0]),*(Vector*)(row[r1]));
|
|||
|
(*(Vector*)(row[r2])).Normalize();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
*(Vector*)(row[r2]) = Mth::CrossProduct(*(Vector*)(row[r0]),*(Vector*)(row[r1]));
|
|||
|
(*(Vector*)(row[r2])).Normalize();
|
|||
|
*(Vector*)(row[r1]) = Mth::CrossProduct(*(Vector*)(row[r2]),*(Vector*)(row[r0]));
|
|||
|
(*(Vector*)(row[r1])).Normalize();
|
|||
|
}
|
|||
|
|
|||
|
return *this;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
void Matrix::GetRotationAxisAndAngle( Vector* pAxis, float* pRadians )
|
|||
|
{
|
|||
|
// Given a transform matrix (end = start * xform)
|
|||
|
// this will return its rotation axis and angle
|
|||
|
|
|||
|
Dbg_Assert( pAxis );
|
|||
|
Dbg_Assert( pRadians );
|
|||
|
|
|||
|
float nTwoSinTheta, nTwoCosTheta;
|
|||
|
Mth::Vector vTwoSinThetaAxis;
|
|||
|
|
|||
|
nTwoCosTheta = row[Mth::RIGHT][X] + row[Mth::UP][Y] + row[Mth::AT][Z] - 1.0f;
|
|||
|
|
|||
|
vTwoSinThetaAxis[X] = row[Mth::UP][Z] - row[Mth::AT][Y];
|
|||
|
vTwoSinThetaAxis[Y] = row[Mth::AT][X] - row[Mth::RIGHT][Z];
|
|||
|
vTwoSinThetaAxis[Z] = row[Mth::RIGHT][Y] - row[Mth::UP][X];
|
|||
|
vTwoSinThetaAxis[W] = 1.0f;
|
|||
|
|
|||
|
// Gary: There used to be a magic patch added by Dave
|
|||
|
// (basically negating the axis) which made it work with
|
|||
|
// the RW-based Slerp object. This doesn't seem to be
|
|||
|
// necessary any more, but I'm going to leave it
|
|||
|
// in the code just in case our Slerp stops working...
|
|||
|
// vTwoSinThetaAxis[X] = row[Mth::AT][Y] - row[Mth::UP][Z];
|
|||
|
// vTwoSinThetaAxis[Y] = row[Mth::RIGHT][Z] - row[Mth::AT][X];
|
|||
|
// vTwoSinThetaAxis[Z] = row[Mth::UP][X] - row[Mth::RIGHT][Y];
|
|||
|
// vTwoSinThetaAxis[W] = 1.0f;
|
|||
|
|
|||
|
nTwoSinTheta = vTwoSinThetaAxis.Length();
|
|||
|
|
|||
|
if (nTwoSinTheta > 0.0f)
|
|||
|
{
|
|||
|
float recipLength = (1.0f / (nTwoSinTheta));
|
|||
|
|
|||
|
*pAxis = vTwoSinThetaAxis;
|
|||
|
pAxis->Scale( recipLength );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pAxis->Set( 0.0f, 0.0f, 0.0f );
|
|||
|
}
|
|||
|
|
|||
|
(*pRadians) = (float)atan2(nTwoSinTheta, nTwoCosTheta);
|
|||
|
if ((nTwoSinTheta <= 0.01f) && (nTwoCosTheta <= 0.0f))
|
|||
|
{
|
|||
|
/*
|
|||
|
* sin theta is 0; cos theta is -1; theta is 180 degrees
|
|||
|
* vTwoSinThetaAxis was degenerate
|
|||
|
* axis will have to be found another way.
|
|||
|
*/
|
|||
|
|
|||
|
//Vector vTwoSinThetaAxis;
|
|||
|
|
|||
|
/*
|
|||
|
* Matrix is:
|
|||
|
* [ [ 2 a_x^2 - 1, 2 a_x a_y, 2 a_x a_z, 0 ]
|
|||
|
* [ 2 a_x a_y, 2 a_y^2 - 1, 2 a_y a_z, 0 ]
|
|||
|
* [ 2 a_x a_z, 2 a_y a_z, 2 a_z^2 - 1, 0 ]
|
|||
|
* [ 0, 0, 0, 1 ] ]
|
|||
|
* Build axis scaled by 4 * component of maximum absolute value
|
|||
|
*/
|
|||
|
if (row[Mth::RIGHT][X] > row[Mth::UP][Y])
|
|||
|
{
|
|||
|
if (row[Mth::RIGHT][X] > row[Mth::AT][Z])
|
|||
|
{
|
|||
|
vTwoSinThetaAxis[X] = 1.0f + row[Mth::RIGHT][X];
|
|||
|
vTwoSinThetaAxis[X] = vTwoSinThetaAxis[X] + vTwoSinThetaAxis[X];
|
|||
|
vTwoSinThetaAxis[Y] = row[Mth::RIGHT][Y] + row[Mth::UP][X];
|
|||
|
vTwoSinThetaAxis[Z] = row[Mth::RIGHT][Z] + row[Mth::AT][X];
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
vTwoSinThetaAxis[Z] = 1.0f + row[Mth::AT][Z];
|
|||
|
vTwoSinThetaAxis[Z] = vTwoSinThetaAxis[Z] + vTwoSinThetaAxis[Z];
|
|||
|
vTwoSinThetaAxis[X] = row[Mth::AT][X] + row[Mth::RIGHT][Z];
|
|||
|
vTwoSinThetaAxis[Y] = row[Mth::AT][Y] + row[Mth::UP][Z];
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (row[Mth::UP][Y] > row[Mth::AT][Z])
|
|||
|
{
|
|||
|
vTwoSinThetaAxis[Y] = 1.0f + row[Mth::UP][Y];
|
|||
|
vTwoSinThetaAxis[Y] = vTwoSinThetaAxis[Y] + vTwoSinThetaAxis[Y];
|
|||
|
vTwoSinThetaAxis[Z] = row[Mth::UP][Z] + row[Mth::AT][Y];
|
|||
|
vTwoSinThetaAxis[X] = row[Mth::UP][X] + row[Mth::RIGHT][Y];
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
vTwoSinThetaAxis[Z] = 1.0f + row[Mth::AT][Z];
|
|||
|
vTwoSinThetaAxis[Z] = vTwoSinThetaAxis[Z] + vTwoSinThetaAxis[Z];
|
|||
|
vTwoSinThetaAxis[X] = row[Mth::AT][X] + row[Mth::RIGHT][Z];
|
|||
|
vTwoSinThetaAxis[Y] = row[Mth::AT][Y] + row[Mth::UP][Z];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* and normalize the axis
|
|||
|
*/
|
|||
|
|
|||
|
*pAxis = vTwoSinThetaAxis;
|
|||
|
pAxis->Normalize();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
void Matrix::RotateLocal( const Vector &rot )
|
|||
|
{
|
|||
|
if ( rot[ X ] )
|
|||
|
{
|
|||
|
RotateXLocal( rot[ X ] );
|
|||
|
}
|
|||
|
if ( rot[ Y ] )
|
|||
|
{
|
|||
|
RotateYLocal( rot[ Y ] );
|
|||
|
}
|
|||
|
if ( rot[ Z ] )
|
|||
|
{
|
|||
|
RotateZLocal( rot[ Z ] );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/******************************************************************/
|
|||
|
/* */
|
|||
|
/* */
|
|||
|
/******************************************************************/
|
|||
|
|
|||
|
bool Matrix::PatchOrthogonality ( )
|
|||
|
{
|
|||
|
// Given a matrix m which is assumed to be orthonormal, check to see if it is, and if not then fix it up
|
|||
|
// returns true if any patching was done
|
|||
|
|
|||
|
float lx,ly,lz;
|
|||
|
lx = (*(Vector*)(row[X])).Length();
|
|||
|
ly = (*(Vector*)(row[Y])).Length();
|
|||
|
lz = (*(Vector*)(row[Z])).Length();
|
|||
|
|
|||
|
const float near1 = 0.99;
|
|||
|
|
|||
|
if (lx < near1)
|
|||
|
{
|
|||
|
if (ly < near1)
|
|||
|
{
|
|||
|
if (lz < near1)
|
|||
|
{
|
|||
|
// everything collapsing to a point!!!
|
|||
|
// just reset to the identity matrix
|
|||
|
Ident();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// x and y have collapsed, but Z is okay
|
|||
|
Ident();
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (lz < near1)
|
|||
|
{
|
|||
|
// x and z have collapsed, y is okay (most likely situation)
|
|||
|
Ident();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// just x has collapsed, y and z are okay
|
|||
|
*(Vector*)(row[X]) = Mth::CrossProduct(*(Vector*)(row[Y]),*(Vector*)(row[Z]));
|
|||
|
(*(Vector*)(row[X])).Normalize();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (ly < near1)
|
|||
|
{
|
|||
|
if (lz < near1)
|
|||
|
{
|
|||
|
// y and z collapsed, x is okay
|
|||
|
Ident();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// y has collapsed, x and Z are okay
|
|||
|
*(Vector*)(row[Y]) = Mth::CrossProduct(*(Vector*)(row[Z]),*(Vector*)(row[X]));
|
|||
|
(*(Vector*)(row[Y])).Normalize();
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (lz < near1)
|
|||
|
{
|
|||
|
// just z has collapsed, x and y is okay
|
|||
|
*(Vector*)(row[Z]) = Mth::CrossProduct(*(Vector*)(row[X]),*(Vector*)(row[Y]));
|
|||
|
(*(Vector*)(row[Z])).Normalize();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// nothing has collapsed
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
} // namespace Mth
|
|||
|
|
|||
|
|