You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1083 lines
31 KiB
1083 lines
31 KiB
/*******************************************************************************
|
|
* DXVector.h *
|
|
*------------*
|
|
* Description:
|
|
* This is the header file for the matrix classes.
|
|
*
|
|
*******************************************************************************/
|
|
#ifndef __DXTPRIV_H_
|
|
#define __DXTPRIV_H_
|
|
|
|
#ifndef _INC_MATH
|
|
#include <math.h>
|
|
#endif
|
|
|
|
#ifndef _INC_CRTDBG
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
//=== Class, Enum, Struct and Union Declarations ===================
|
|
class CDXMatrix4x4F;
|
|
|
|
//=== Enumerated Set Definitions ===================================
|
|
|
|
//=== Function Type Definitions ====================================
|
|
float det4x4( CDXMatrix4x4F *pIn );
|
|
float det3x3( float a1, float a2, float a3, float b1, float b2, float b3,
|
|
float c1, float c2, float c3 );
|
|
float det2x2( float a, float b, float c, float d );
|
|
|
|
/*** CDX2DXForm ************
|
|
* This class implements basic matrix operation based on the GDI XFORM
|
|
* structure.
|
|
*/
|
|
//const DX2DXFORM g_DX2DXFORMIdentity = { 1., 0., 0., 1., 0., 0., DX2DXO_IDENTITY };
|
|
|
|
class CDX2DXForm : public DX2DXFORM
|
|
{
|
|
/*=== Methods =======*/
|
|
public:
|
|
/*--- Constructors ---*/
|
|
CDX2DXForm() { SetIdentity(); }
|
|
CDX2DXForm( const CDX2DXForm& Other ) { memcpy( this, &Other, sizeof(*this) ); }
|
|
CDX2DXForm( const DX2DXFORM& Other ) { memcpy( this, &Other, sizeof(*this) ); }
|
|
|
|
/*--- methods ---*/
|
|
void DetermineOp( void );
|
|
void Set( const DX2DXFORM& Other ) { memcpy( this, &Other, sizeof(*this) ); DetermineOp(); }
|
|
void ZeroMatrix( void ) { memset( this, 0, sizeof( *this ) ); }
|
|
void SetIdentity( void ) {
|
|
eM11 = 1.;
|
|
eM12 = 0.;
|
|
eM21 = 0.;
|
|
eM22 = 1.;
|
|
eDx = 0.;
|
|
eDy = 0.;
|
|
eOp = DX2DXO_IDENTITY;
|
|
}
|
|
BOOL IsIdentity() const { return eOp == DX2DXO_IDENTITY; }
|
|
void Scale( float sx, float sy );
|
|
void Rotate( float Rotation );
|
|
void Translate( float dx, float dy );
|
|
BOOL Invert();
|
|
void TransformBounds( const DXBNDS& Bnds, DXBNDS& ResultBnds ) const;
|
|
void TransformPoints( const DXFPOINT InPnts[], DXFPOINT OutPnts[], ULONG ulCount ) const;
|
|
void GetMinMaxScales( float& MinScale, float& MaxScale );
|
|
|
|
/*--- operators ---*/
|
|
DXFPOINT operator*( const DXFPOINT& v ) const;
|
|
CDX2DXForm operator*( const CDX2DXForm& Other ) const;
|
|
};
|
|
|
|
//=== CDX2DXForm methods ==============================================================
|
|
inline void CDX2DXForm::DetermineOp( void )
|
|
{
|
|
if( ( eM12 == 0. ) && ( eM21 == 0. ) )
|
|
{
|
|
if( ( eM11 == 1. ) && ( eM22 == 1. ) )
|
|
{
|
|
eOp = ( ( eDx == 0 ) && ( eDy == 0 ) )?(DX2DXO_IDENTITY):(DX2DXO_TRANSLATE);
|
|
}
|
|
else
|
|
{
|
|
eOp = ( ( eDx == 0 ) && ( eDy == 0 ) )?(DX2DXO_SCALE):(DX2DXO_SCALE_AND_TRANS);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
eOp = ( ( eDx == 0 ) && ( eDy == 0 ) )?(DX2DXO_GENERAL):(DX2DXO_GENERAL_AND_TRANS);
|
|
}
|
|
} /* CDX2DXForm::DetermineOp */
|
|
|
|
inline float DXSq( float f ) { return f * f; }
|
|
|
|
// This function computes the Min and Max scale that a matrix represents.
|
|
// In other words, what is the maximum/minimum length that a line of length 1
|
|
// could get stretched/shrunk to if the line was transformed by this matrix.
|
|
//
|
|
// The function uses eigenvalues; and returns two float numbers. Both are
|
|
// non-negative; and MaxScale >= MinScale.
|
|
//
|
|
inline void CDX2DXForm::GetMinMaxScales( float& MinScale, float& MaxScale )
|
|
{
|
|
if( ( eM12 == 0. ) && ( eM21 == 0. ) )
|
|
{
|
|
// Let MinScale = abs(eM11)
|
|
if (eM11 < 0)
|
|
MinScale = -eM11;
|
|
else
|
|
MinScale = eM11;
|
|
|
|
// Let MaxScale = abs(eM22)
|
|
if (eM22 < 0)
|
|
MaxScale = -eM22;
|
|
else
|
|
MaxScale = eM22;
|
|
|
|
// Swap Min/Max if necessary
|
|
if (MinScale > MaxScale)
|
|
{
|
|
float flTemp = MinScale;
|
|
MinScale = MaxScale;
|
|
MaxScale = flTemp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float t1 = DXSq(eM11) + DXSq(eM12) + DXSq(eM21) + DXSq(eM22);
|
|
if( t1 == 0. )
|
|
{
|
|
MinScale = MaxScale = 0;
|
|
}
|
|
else
|
|
{
|
|
float t2 = (float)sqrt( (DXSq(eM12 + eM21) + DXSq(eM11 - eM22)) *
|
|
(DXSq(eM12 - eM21) + DXSq(eM11 + eM22)) );
|
|
|
|
// Due to floating point error; t1 may end up less than t2;
|
|
// but that would mean that the min scale was small (relative
|
|
// to max scale)
|
|
if (t1 <= t2)
|
|
MinScale = 0;
|
|
else
|
|
MinScale = (float)sqrt( (t1 - t2) * .5f );
|
|
|
|
MaxScale = (float)sqrt( (t1 + t2) * .5f );
|
|
}
|
|
}
|
|
} /* CDX2DXForm::GetMinMaxScales */
|
|
|
|
inline void CDX2DXForm::Rotate( float Rotation )
|
|
{
|
|
double Angle = Rotation * (3.1415926535/180.0);
|
|
float CosZ = (float)cos( Angle );
|
|
float SinZ = (float)sin( Angle );
|
|
if (CosZ > 0.0F && CosZ < 0.0000005F)
|
|
{
|
|
CosZ = .0F;
|
|
}
|
|
if (SinZ > -0.0000005F && SinZ < .0F)
|
|
{
|
|
SinZ = .0F;
|
|
}
|
|
|
|
float M11 = ( CosZ * eM11 ) + ( SinZ * eM21 );
|
|
float M21 = (-SinZ * eM11 ) + ( CosZ * eM21 );
|
|
float M12 = ( CosZ * eM12 ) + ( SinZ * eM22 );
|
|
float M22 = (-SinZ * eM12 ) + ( CosZ * eM22 );
|
|
eM11 = M11; eM21 = M21; eM12 = M12; eM22 = M22;
|
|
DetermineOp();
|
|
} /* CDX2DXForm::Rotate */
|
|
|
|
inline void CDX2DXForm::Scale( float sx, float sy )
|
|
{
|
|
eM11 *= sx;
|
|
eM12 *= sx;
|
|
eDx *= sx;
|
|
eM21 *= sy;
|
|
eM22 *= sy;
|
|
eDy *= sy;
|
|
DetermineOp();
|
|
} /* CDX2DXForm::Scale */
|
|
|
|
inline void CDX2DXForm::Translate( float dx, float dy )
|
|
{
|
|
eDx += dx;
|
|
eDy += dy;
|
|
DetermineOp();
|
|
} /* CDX2DXForm::Translate */
|
|
|
|
inline void CDX2DXForm::TransformBounds( const DXBNDS& Bnds, DXBNDS& ResultBnds ) const
|
|
{
|
|
ResultBnds = Bnds;
|
|
if( eOp != DX2DXO_IDENTITY )
|
|
{
|
|
ResultBnds.u.D[DXB_X].Min = (long)(( eM11 * Bnds.u.D[DXB_X].Min ) + ( eM12 * Bnds.u.D[DXB_Y].Min ) + eDx);
|
|
ResultBnds.u.D[DXB_X].Max = (long)(( eM11 * Bnds.u.D[DXB_X].Max ) + ( eM12 * Bnds.u.D[DXB_Y].Max ) + eDx);
|
|
ResultBnds.u.D[DXB_Y].Min = (long)(( eM21 * Bnds.u.D[DXB_X].Min ) + ( eM22 * Bnds.u.D[DXB_Y].Min ) + eDy);
|
|
ResultBnds.u.D[DXB_Y].Max = (long)(( eM21 * Bnds.u.D[DXB_X].Max ) + ( eM22 * Bnds.u.D[DXB_Y].Max ) + eDy);
|
|
}
|
|
} /* CDX2DXForm::TransformBounds */
|
|
|
|
inline void CDX2DXForm::TransformPoints( const DXFPOINT InPnts[], DXFPOINT OutPnts[], ULONG ulCount ) const
|
|
{
|
|
ULONG i;
|
|
switch( eOp )
|
|
{
|
|
case DX2DXO_IDENTITY:
|
|
memcpy( OutPnts, InPnts, ulCount * sizeof( DXFPOINT ) );
|
|
break;
|
|
case DX2DXO_TRANSLATE:
|
|
for( i = 0; i < ulCount; ++i )
|
|
{
|
|
OutPnts[i].x = InPnts[i].x + eDx;
|
|
OutPnts[i].y = InPnts[i].y + eDy;
|
|
}
|
|
break;
|
|
case DX2DXO_SCALE:
|
|
for( i = 0; i < ulCount; ++i )
|
|
{
|
|
OutPnts[i].x = InPnts[i].x * eM11;
|
|
OutPnts[i].y = InPnts[i].y * eM22;
|
|
}
|
|
break;
|
|
case DX2DXO_SCALE_AND_TRANS:
|
|
for( i = 0; i < ulCount; ++i )
|
|
{
|
|
OutPnts[i].x = (InPnts[i].x * eM11) + eDx;
|
|
OutPnts[i].y = (InPnts[i].y * eM22) + eDy;
|
|
}
|
|
break;
|
|
case DX2DXO_GENERAL:
|
|
for( i = 0; i < ulCount; ++i )
|
|
{
|
|
OutPnts[i].x = ( InPnts[i].x * eM11 ) + ( InPnts[i].y * eM12 );
|
|
OutPnts[i].y = ( InPnts[i].x * eM21 ) + ( InPnts[i].y * eM22 );
|
|
}
|
|
break;
|
|
case DX2DXO_GENERAL_AND_TRANS:
|
|
for( i = 0; i < ulCount; ++i )
|
|
{
|
|
OutPnts[i].x = ( InPnts[i].x * eM11 ) + ( InPnts[i].y * eM12 ) + eDx;
|
|
OutPnts[i].y = ( InPnts[i].x * eM21 ) + ( InPnts[i].y * eM22 ) + eDy;
|
|
}
|
|
break;
|
|
default:
|
|
_ASSERT( 0 ); // invalid operation id
|
|
}
|
|
} /* CDX2DXForm::TransformPoints */
|
|
|
|
inline DXFPOINT CDX2DXForm::operator*( const DXFPOINT& v ) const
|
|
{
|
|
DXFPOINT NewPnt;
|
|
NewPnt.x = ( v.x * eM11 ) + ( v.y * eM12 ) + eDx;
|
|
NewPnt.y = ( v.x * eM21 ) + ( v.y * eM22 ) + eDy;
|
|
return NewPnt;
|
|
} /* CDX2DXForm::operator* */
|
|
|
|
inline CDX2DXForm CDX2DXForm::operator*( const CDX2DXForm& Other ) const
|
|
{
|
|
DX2DXFORM x;
|
|
x.eM11 = ( eM11 * Other.eM11 ) + ( eM12 * Other.eM21 );
|
|
x.eM12 = ( eM11 * Other.eM12 ) + ( eM12 * Other.eM22 );
|
|
x.eDx = ( eM11 * Other.eDx ) + ( eM12 * Other.eDy ) + eDx;
|
|
|
|
x.eM21 = ( eM21 * Other.eM11 ) + ( eM22 * Other.eM21 );
|
|
x.eM22 = ( eM21 * Other.eM12 ) + ( eM22 * Other.eM22 );
|
|
x.eDy = ( eM21 * Other.eDx ) + ( eM22 * Other.eDy ) + eDy;
|
|
return x;
|
|
} /* CDX2DXForm::operator*= */
|
|
|
|
inline BOOL CDX2DXForm::Invert()
|
|
{
|
|
switch( eOp )
|
|
{
|
|
case DX2DXO_IDENTITY:
|
|
break;
|
|
case DX2DXO_TRANSLATE:
|
|
eDx = -eDx;
|
|
eDy = -eDy;
|
|
break;
|
|
case DX2DXO_SCALE:
|
|
|
|
if (eM11 == 0.0 || eM22 == 0.0)
|
|
return false;
|
|
eM11 = 1.0f / eM11;
|
|
eM22 = 1.0f / eM22;
|
|
break;
|
|
|
|
case DX2DXO_SCALE_AND_TRANS:
|
|
{
|
|
if (eM11 == 0.0f || eM22 == 0.0f)
|
|
return false;
|
|
|
|
// Our old equation was F = aG + b
|
|
// The inverse is G = F/a - b/a where a is eM11 and b is eDx
|
|
float flOneOverA = 1.0f / eM11;
|
|
eDx = -eDx * flOneOverA;
|
|
eM11 = flOneOverA;
|
|
|
|
// Our old equation was F = aG + b
|
|
// The inverse is G = F/a - b/a where a is eM22 and b is eDy
|
|
|
|
flOneOverA = 1.0f / eM22;
|
|
eDy = -eDy * flOneOverA;
|
|
eM22 = flOneOverA;
|
|
break;
|
|
}
|
|
|
|
case DX2DXO_GENERAL:
|
|
case DX2DXO_GENERAL_AND_TRANS:
|
|
{
|
|
// The inverse of A= |a b| is | d -c|*(1/Det) where Det is the determinant of A
|
|
// |c d| |-b a|
|
|
// Det(A) = ad - bc
|
|
|
|
// Compute determininant
|
|
float flDet = (eM11 * eM22 - eM12 * eM21);
|
|
if (flDet == 0.0f)
|
|
return FALSE;
|
|
|
|
float flCoef = 1.0f / flDet;
|
|
|
|
// Remember old value of eM11
|
|
float flM11Original = eM11;
|
|
|
|
eM11 = flCoef * eM22;
|
|
eM12 = -flCoef * eM12;
|
|
eM21 = -flCoef * eM21;
|
|
eM22 = flCoef * flM11Original;
|
|
|
|
// If we have a translation; then we need to
|
|
// compute new values for that translation
|
|
if (eOp == DX2DXO_GENERAL_AND_TRANS)
|
|
{
|
|
// Remember original value of eDx
|
|
float eDxOriginal = eDx;
|
|
|
|
eDx = -eM11 * eDx - eM12 * eDy;
|
|
eDy = -eM21 * eDxOriginal - eM22 * eDy;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
_ASSERT( 0 ); // invalid operation id
|
|
}
|
|
|
|
// We don't need to call DetermineOp here
|
|
// because the op doesn't change when inverted
|
|
// i.e. a scale remains a scale, etc.
|
|
|
|
return true;
|
|
} /* CDX2DXForm::Invert */
|
|
|
|
/*** CDXMatrix4x4F ************
|
|
* This class implements basic matrix operation based on a 4x4 array.
|
|
*/
|
|
//const float g_DXMat4X4Identity[4][4] =
|
|
//{
|
|
// { 1.0, 0. , 0. , 0. },
|
|
// { 0. , 1.0, 0. , 0. },
|
|
// { 0. , 0. , 1.0, 0. },
|
|
// { 0. , 0. , 0. , 1.0 }
|
|
//};
|
|
|
|
class CDXMatrix4x4F
|
|
{
|
|
public:
|
|
/*=== Member Data ===*/
|
|
float m_Coeff[4][4];
|
|
|
|
/*=== Methods =======*/
|
|
public:
|
|
/*--- Constructors ---*/
|
|
CDXMatrix4x4F() { SetIdentity(); }
|
|
CDXMatrix4x4F( const CDXMatrix4x4F& Other )
|
|
{ CopyMemory( (void *)&m_Coeff, (void *)&Other.m_Coeff, sizeof(m_Coeff) ); }
|
|
CDXMatrix4x4F( DX2DXFORM& XForm );
|
|
|
|
/*--- operations ---*/
|
|
void ZeroMatrix( void ) { memset( m_Coeff, 0, sizeof( m_Coeff ) ); }
|
|
void SetIdentity( void ) {
|
|
memset( m_Coeff, 0, sizeof( m_Coeff ) );
|
|
m_Coeff[0][0] = m_Coeff[1][1] = m_Coeff[2][2] = m_Coeff[3][3] = 1.0;
|
|
}
|
|
void SetCoefficients( float Coeff[4][4] ) { memcpy( m_Coeff, Coeff, sizeof( m_Coeff )); }
|
|
void GetCoefficients( float Coeff[4][4] ) { memcpy( Coeff, m_Coeff, sizeof( m_Coeff )); }
|
|
|
|
//BOOL IsIdentity();
|
|
void Scale( float sx, float sy, float sz );
|
|
void Rotate( float rx, float ry, float rz );
|
|
void Translate( float dx, float dy, float dz );
|
|
BOOL Invert();
|
|
BOOL GetInverse( CDXMatrix4x4F *pIn );
|
|
void Transpose();
|
|
void GetTranspose( CDXMatrix4x4F *pIn );
|
|
void GetAdjoint( CDXMatrix4x4F *pIn );
|
|
HRESULT InitFromSafeArray( SAFEARRAY *psa );
|
|
HRESULT GetSafeArray( SAFEARRAY **ppsa ) const;
|
|
void TransformBounds( DXBNDS& Bnds, DXBNDS& ResultBnds );
|
|
|
|
/*--- operators ---*/
|
|
CDXDVec operator*( CDXDVec& v) const;
|
|
CDXCVec operator*( CDXCVec& v) const;
|
|
CDXMatrix4x4F operator*(CDXMatrix4x4F Matrix) const;
|
|
void operator*=(CDXMatrix4x4F Matrix) const;
|
|
void CDXMatrix4x4F::operator=(const CDXMatrix4x4F srcMatrix);
|
|
void CDXMatrix4x4F::operator+=(const CDXMatrix4x4F otherMatrix);
|
|
void CDXMatrix4x4F::operator-=(const CDXMatrix4x4F otherMatrix);
|
|
BOOL CDXMatrix4x4F::operator==(const CDXMatrix4x4F otherMatrix) const;
|
|
BOOL CDXMatrix4x4F::operator!=(const CDXMatrix4x4F otherMatrix) const;
|
|
};
|
|
|
|
inline CDXMatrix4x4F::CDXMatrix4x4F( DX2DXFORM& XForm )
|
|
{
|
|
SetIdentity();
|
|
m_Coeff[0][0] = XForm.eM11;
|
|
m_Coeff[0][1] = XForm.eM12;
|
|
m_Coeff[1][0] = XForm.eM21;
|
|
m_Coeff[1][1] = XForm.eM22;
|
|
m_Coeff[0][3] = XForm.eDx;
|
|
m_Coeff[1][3] = XForm.eDy;
|
|
}
|
|
|
|
// Additional Operations
|
|
|
|
inline void CDXMatrix4x4F::operator=(const CDXMatrix4x4F srcMatrix)
|
|
{
|
|
CopyMemory( (void *)m_Coeff, (const void *)srcMatrix.m_Coeff, sizeof(srcMatrix.m_Coeff) );
|
|
} /* CDXMatrix4x4F::operator= */
|
|
|
|
inline BOOL CDXMatrix4x4F::operator==(const CDXMatrix4x4F otherMatrix) const
|
|
{
|
|
return !memcmp( (void *)m_Coeff, (const void *)otherMatrix.m_Coeff, sizeof(otherMatrix.m_Coeff) );
|
|
} /* CDXMatrix4x4F::operator== */
|
|
|
|
inline BOOL CDXMatrix4x4F::operator!=(const CDXMatrix4x4F otherMatrix) const
|
|
{
|
|
return memcmp( (void *)m_Coeff, (const void *)otherMatrix.m_Coeff, sizeof(otherMatrix.m_Coeff) );
|
|
} /* CDXMatrix4x4F::operator!= */
|
|
|
|
inline void CDXMatrix4x4F::operator+=(const CDXMatrix4x4F otherMatrix)
|
|
{
|
|
for( int i = 0; i < 4; i++ )
|
|
for( int j = 0; j < 4; j++ )
|
|
m_Coeff[i][j] += otherMatrix.m_Coeff[i][j];
|
|
} /* CDXMatrix4x4F::operator+= */
|
|
|
|
inline void CDXMatrix4x4F::operator-=(const CDXMatrix4x4F otherMatrix)
|
|
{
|
|
for( int i = 0; i < 4; i++ )
|
|
for( int j = 0; j < 4; j++ )
|
|
m_Coeff[i][j] -= otherMatrix.m_Coeff[i][j];
|
|
} /* CDXMatrix4x4F::operator-= */
|
|
|
|
inline CDXDVec CDXMatrix4x4F::operator*(CDXDVec& v) const
|
|
{
|
|
CDXDVec t;
|
|
float temp;
|
|
temp = v[0]*m_Coeff[0][0]+v[1]*m_Coeff[1][0]+v[2]*m_Coeff[2][0]+v[3]*m_Coeff[3][0];
|
|
t[0] = (long)((temp < 0) ? temp -= .5 : temp += .5);
|
|
temp = v[0]*m_Coeff[0][1]+v[1]*m_Coeff[1][1]+v[2]*m_Coeff[2][1]+v[3]*m_Coeff[3][1];
|
|
t[1] = (long)((temp < 0) ? temp -= .5 : temp += .5);
|
|
temp = v[0]*m_Coeff[0][2]+v[1]*m_Coeff[1][2]+v[2]*m_Coeff[2][2]+v[3]*m_Coeff[3][2];
|
|
t[2] = (long)((temp < 0) ? temp -= .5 : temp += .5);
|
|
temp = v[0]*m_Coeff[0][3]+v[1]*m_Coeff[1][3]+v[2]*m_Coeff[2][3]+v[3]*m_Coeff[3][3];
|
|
t[3] = (long)((temp < 0) ? temp -= .5 : temp += .5);
|
|
return t;
|
|
} /* CDXMatrix4x4F::operator*(DXDVEC) */
|
|
|
|
inline CDXCVec CDXMatrix4x4F::operator*(CDXCVec& v) const
|
|
{
|
|
CDXCVec t;
|
|
t[0] = v[0]*m_Coeff[0][0]+v[1]*m_Coeff[1][0]+v[2]*m_Coeff[2][0]+v[3]*m_Coeff[3][0];
|
|
t[1] = v[0]*m_Coeff[0][1]+v[1]*m_Coeff[1][1]+v[2]*m_Coeff[2][1]+v[3]*m_Coeff[3][1];
|
|
t[2] = v[0]*m_Coeff[0][2]+v[1]*m_Coeff[1][2]+v[2]*m_Coeff[2][2]+v[3]*m_Coeff[3][2];
|
|
t[3] = v[0]*m_Coeff[0][3]+v[1]*m_Coeff[1][3]+v[2]*m_Coeff[2][3]+v[3]*m_Coeff[3][3];
|
|
return t;
|
|
} /* CDXMatrix4x4F::operator*(DXCVEC) */
|
|
|
|
inline CDXMatrix4x4F CDXMatrix4x4F::operator*(CDXMatrix4x4F Mx) const
|
|
{
|
|
CDXMatrix4x4F t;
|
|
int i, j;
|
|
|
|
for( i = 0; i < 4; i++ )
|
|
{
|
|
for( j = 0; j < 4; j++ )
|
|
{
|
|
t.m_Coeff[i][j] = m_Coeff[i][0] * Mx.m_Coeff[0][j] +
|
|
m_Coeff[i][1] * Mx.m_Coeff[1][j] +
|
|
m_Coeff[i][2] * Mx.m_Coeff[2][j] +
|
|
m_Coeff[i][3] * Mx.m_Coeff[3][j];
|
|
}
|
|
}
|
|
|
|
return t;
|
|
} /* CDXMatrix4x4F::operator*(CDXMatrix4x4F) */
|
|
|
|
inline void CDXMatrix4x4F::operator*=(CDXMatrix4x4F Mx) const
|
|
{
|
|
CDXMatrix4x4F t;
|
|
int i, j;
|
|
|
|
for( i = 0; i < 4; i++ )
|
|
{
|
|
for( j = 0; j < 4; j++ )
|
|
{
|
|
t.m_Coeff[i][j] = m_Coeff[i][0] * Mx.m_Coeff[0][j] +
|
|
m_Coeff[i][1] * Mx.m_Coeff[1][j] +
|
|
m_Coeff[i][2] * Mx.m_Coeff[2][j] +
|
|
m_Coeff[i][3] * Mx.m_Coeff[3][j];
|
|
}
|
|
}
|
|
|
|
CopyMemory( (void *)m_Coeff, (void *)t.m_Coeff, sizeof(m_Coeff) );
|
|
} /* CDXMatrix4x4F::operator*=(CDXMatrix4x4F) */
|
|
|
|
|
|
inline void CDXMatrix4x4F::Scale( float sx, float sy, float sz )
|
|
{
|
|
if( sx != 1. )
|
|
{
|
|
m_Coeff[0][0] *= sx;
|
|
m_Coeff[0][1] *= sx;
|
|
m_Coeff[0][2] *= sx;
|
|
m_Coeff[0][3] *= sx;
|
|
}
|
|
if( sy != 1. )
|
|
{
|
|
m_Coeff[1][0] *= sy;
|
|
m_Coeff[1][1] *= sy;
|
|
m_Coeff[1][2] *= sy;
|
|
m_Coeff[1][3] *= sy;
|
|
}
|
|
if( sz != 1. )
|
|
{
|
|
m_Coeff[2][0] *= sz;
|
|
m_Coeff[2][1] *= sz;
|
|
m_Coeff[2][2] *= sz;
|
|
m_Coeff[2][3] *= sz;
|
|
}
|
|
} /* CDXMatrix4x4F::Scale */
|
|
|
|
inline void CDXMatrix4x4F::Translate( float dx, float dy, float dz )
|
|
{
|
|
float a, b, c, d;
|
|
a = b = c = d = 0;
|
|
if( dx != 0. )
|
|
{
|
|
a += m_Coeff[0][0]*dx;
|
|
b += m_Coeff[0][1]*dx;
|
|
c += m_Coeff[0][2]*dx;
|
|
d += m_Coeff[0][3]*dx;
|
|
}
|
|
if( dy != 0. )
|
|
{
|
|
a += m_Coeff[1][0]*dy;
|
|
b += m_Coeff[1][1]*dy;
|
|
c += m_Coeff[1][2]*dy;
|
|
d += m_Coeff[1][3]*dy;
|
|
}
|
|
if( dz != 0. )
|
|
{
|
|
a += m_Coeff[2][0]*dz;
|
|
b += m_Coeff[2][1]*dz;
|
|
c += m_Coeff[2][2]*dz;
|
|
d += m_Coeff[2][3]*dz;
|
|
}
|
|
m_Coeff[3][0] += a;
|
|
m_Coeff[3][1] += b;
|
|
m_Coeff[3][2] += c;
|
|
m_Coeff[3][3] += d;
|
|
} /* CDXMatrix4x4F::Translate */
|
|
|
|
inline void CDXMatrix4x4F::Rotate( float rx, float ry, float rz )
|
|
{
|
|
const float l_dfCte = (const float)(3.1415926535/180.0);
|
|
|
|
float lAngleY = 0.0;
|
|
float lAngleX = 0.0;
|
|
float lAngleZ = 0.0;
|
|
float lCosX = 1.0;
|
|
float lSinX = 0.0;
|
|
float lCosY = 1.0;
|
|
float lSinY = 0.0;
|
|
float lCosZ = 1.0;
|
|
float lSinZ = 0.0;
|
|
|
|
// calculate rotation angle sines and cosines
|
|
if( rx != 0 )
|
|
{
|
|
lAngleX = rx * l_dfCte;
|
|
lCosX = (float)cos(lAngleX);
|
|
lSinX = (float)sin(lAngleX);
|
|
if (lCosX > 0.0F && lCosX < 0.0000005F)
|
|
{
|
|
lCosX = .0F;
|
|
}
|
|
if (lSinX > -0.0000005F && lSinX < .0F)
|
|
{
|
|
lSinX = .0F;
|
|
}
|
|
}
|
|
if( ry != 0 )
|
|
{
|
|
lAngleY = ry * l_dfCte;
|
|
lCosY = (float)cos(lAngleY);
|
|
lSinY = (float)sin(lAngleY);
|
|
if (lCosY > 0.0F && lCosY < 0.0000005F)
|
|
{
|
|
lCosY = .0F;
|
|
}
|
|
if (lSinY > -0.0000005F && lSinY < .0F)
|
|
{
|
|
lSinY = .0F;
|
|
}
|
|
}
|
|
if( rz != 0 )
|
|
{
|
|
lAngleZ = rz * l_dfCte;
|
|
lCosZ = (float)cos(lAngleZ);
|
|
lSinZ = (float)sin(lAngleZ);
|
|
if (lCosZ > 0.0F && lCosZ < 0.0000005F)
|
|
{
|
|
lCosZ = .0F;
|
|
}
|
|
if (lSinZ > -0.0000005F && lSinZ < .0F)
|
|
{
|
|
lSinZ = .0F;
|
|
}
|
|
}
|
|
|
|
float u, v;
|
|
int i;
|
|
|
|
//--- X Rotation
|
|
for( i = 0; i < 4; i++ )
|
|
{
|
|
u = m_Coeff[1][i];
|
|
v = m_Coeff[2][i];
|
|
m_Coeff[1][i] = lCosX*u+lSinX*v;
|
|
m_Coeff[2][i] = -lSinX*u+lCosX*v;
|
|
}
|
|
|
|
//--- Y Rotation
|
|
for( i = 0; i < 4; i++ )
|
|
{
|
|
u = m_Coeff[0][i];
|
|
v = m_Coeff[2][i];
|
|
m_Coeff[0][i] = lCosY*u-lSinY*v;
|
|
m_Coeff[2][i] = lSinY*u+lCosY*v;
|
|
}
|
|
|
|
//--- Z Rotation
|
|
for( i = 0; i < 4; i++ )
|
|
{
|
|
u = m_Coeff[0][i];
|
|
v = m_Coeff[1][i];
|
|
m_Coeff[0][i] = lCosZ*u+lSinZ*v;
|
|
m_Coeff[1][i] = -lSinZ*u+lCosZ*v;
|
|
}
|
|
}
|
|
|
|
/*
|
|
inline BOOL CDXMatrix4x4F::IsIdentity()
|
|
{
|
|
return !memcmp( m_Coeff, g_DXMat4X4Identity, sizeof(g_DXMat4X4Identity) );
|
|
} /* CDXMatrix4x4F::IsIdentity */
|
|
|
|
|
|
/*
|
|
Uses Gaussian elimination to invert the 4 x 4 non-linear matrix in t and
|
|
return the result in Mx. The matrix t is destroyed in the process.
|
|
*/
|
|
inline BOOL CDXMatrix4x4F::Invert()
|
|
{
|
|
int i,j,k,Pivot;
|
|
float PValue;
|
|
CDXMatrix4x4F Mx;
|
|
Mx.SetIdentity();
|
|
|
|
/* Find pivot element. Use partial pivoting by row */
|
|
for( i = 0;i < 4; i++ )
|
|
{
|
|
Pivot = 0;
|
|
for( j = 0; j < 4; j++ )
|
|
{
|
|
if( fabs(m_Coeff[i][j]) > fabs(m_Coeff[i][Pivot]) ) Pivot = j;
|
|
}
|
|
|
|
if( m_Coeff[i][Pivot] == 0.0 )
|
|
{
|
|
ZeroMatrix(); /* Singular Matrix */
|
|
return FALSE;
|
|
}
|
|
|
|
/* Normalize */
|
|
PValue = m_Coeff[i][Pivot];
|
|
for( j = 0; j < 4; j++ )
|
|
{
|
|
m_Coeff[i][j] /= PValue;
|
|
Mx.m_Coeff[i][j] /= PValue;
|
|
}
|
|
|
|
/* Zeroing */
|
|
for( j = 0; j < 4; j++ )
|
|
{
|
|
if( j != i )
|
|
{
|
|
PValue = m_Coeff[j][Pivot];
|
|
for( k = 0; k < 4; k++ )
|
|
{
|
|
m_Coeff[j][k] -= PValue*m_Coeff[i][k];
|
|
Mx.m_Coeff[j][k] -= PValue*Mx.m_Coeff[i][k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Reorder rows */
|
|
for( i = 0; i < 4; i++ )
|
|
{
|
|
if( m_Coeff[i][i] != 1.0 )
|
|
{
|
|
for( j = i + 1; j < 4; j++ )
|
|
if( m_Coeff[j][i] == 1.0 ) break;
|
|
if( j >= 4 )
|
|
{
|
|
ZeroMatrix();
|
|
return FALSE;
|
|
}
|
|
|
|
//--- swap rows i and j of original
|
|
for( k = 0; k < 4; k++ )
|
|
{
|
|
m_Coeff[i][k] += m_Coeff[j][k];
|
|
m_Coeff[j][k] = m_Coeff[i][k] - m_Coeff[j][k];
|
|
m_Coeff[i][k] -= m_Coeff[j][k];
|
|
}
|
|
|
|
//--- swap rows i and j of result
|
|
for( k = 0; k < 4; k++ )
|
|
{
|
|
Mx.m_Coeff[i][k] += Mx.m_Coeff[j][k];
|
|
Mx.m_Coeff[j][k] = Mx.m_Coeff[i][k] - Mx.m_Coeff[j][k];
|
|
Mx.m_Coeff[i][k] -= Mx.m_Coeff[j][k];
|
|
}
|
|
}
|
|
}
|
|
*this = Mx;
|
|
return TRUE;
|
|
} /* CDXMatrix4x4F::Invert */
|
|
|
|
inline void CDXMatrix4x4F::Transpose()
|
|
{
|
|
float temp;
|
|
|
|
temp = m_Coeff[0][1];
|
|
m_Coeff[0][1] = m_Coeff[1][0];
|
|
m_Coeff[1][0] = temp;
|
|
|
|
temp = m_Coeff[0][2];
|
|
m_Coeff[0][2] = m_Coeff[2][0];
|
|
m_Coeff[2][0] = temp;
|
|
|
|
temp = m_Coeff[0][3];
|
|
m_Coeff[0][3] = m_Coeff[3][0];
|
|
m_Coeff[3][0] = temp;
|
|
|
|
temp = m_Coeff[1][2];
|
|
m_Coeff[1][2] = m_Coeff[2][1];
|
|
m_Coeff[2][1] = temp;
|
|
|
|
temp = m_Coeff[1][3];
|
|
m_Coeff[1][3] = m_Coeff[3][1];
|
|
m_Coeff[3][1] = temp;
|
|
|
|
temp = m_Coeff[2][3];
|
|
m_Coeff[2][3] = m_Coeff[3][2];
|
|
m_Coeff[3][2] = temp;
|
|
|
|
} /* CDXMatrix4x4F::Transpose */
|
|
|
|
inline void CDXMatrix4x4F::GetTranspose( CDXMatrix4x4F *m )
|
|
{
|
|
float temp;
|
|
|
|
(*this) = *m;
|
|
|
|
temp = m_Coeff[0][1];
|
|
m_Coeff[0][1] = m_Coeff[1][0];
|
|
m_Coeff[1][0] = temp;
|
|
|
|
temp = m_Coeff[0][2];
|
|
m_Coeff[0][2] = m_Coeff[2][0];
|
|
m_Coeff[2][0] = temp;
|
|
|
|
temp = m_Coeff[0][3];
|
|
m_Coeff[0][3] = m_Coeff[3][0];
|
|
m_Coeff[3][0] = temp;
|
|
|
|
temp = m_Coeff[1][2];
|
|
m_Coeff[1][2] = m_Coeff[2][1];
|
|
m_Coeff[2][1] = temp;
|
|
|
|
temp = m_Coeff[1][3];
|
|
m_Coeff[1][3] = m_Coeff[3][1];
|
|
m_Coeff[3][1] = temp;
|
|
|
|
temp = m_Coeff[2][3];
|
|
m_Coeff[2][3] = m_Coeff[3][2];
|
|
m_Coeff[3][2] = temp;
|
|
|
|
} /* CDXMatrix4x4F::Transpose */
|
|
|
|
|
|
/*
|
|
Matrix Inversion
|
|
by Richard Carling
|
|
from "Graphics Gems", Academic Press, 1990
|
|
*/
|
|
|
|
#define SMALL_NUMBER 1.e-8
|
|
/*
|
|
* inverse( original_matrix, inverse_matrix )
|
|
*
|
|
* calculate the inverse of a 4x4 matrix
|
|
*
|
|
* -1
|
|
* A = ___1__ adjoint A
|
|
* det A
|
|
*/
|
|
|
|
inline BOOL CDXMatrix4x4F::GetInverse( CDXMatrix4x4F *pIn )
|
|
{
|
|
int i, j;
|
|
float det;
|
|
|
|
/* calculate the adjoint matrix */
|
|
|
|
GetAdjoint( pIn );
|
|
|
|
/* calculate the 4x4 determinant
|
|
* if the determinant is zero,
|
|
* then the inverse matrix is not unique.
|
|
*/
|
|
|
|
det = det4x4( pIn );
|
|
|
|
if( fabs( det ) < SMALL_NUMBER )
|
|
{
|
|
// Non-singular matrix, no inverse!
|
|
return FALSE;;
|
|
}
|
|
|
|
/* scale the adjoint matrix to get the inverse */
|
|
|
|
for( i = 0; i < 4; i++ )
|
|
for( j = 0; j < 4; j++ )
|
|
m_Coeff[i][j] = m_Coeff[i][j] / det;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* adjoint( original_matrix, inverse_matrix )
|
|
*
|
|
* calculate the adjoint of a 4x4 matrix
|
|
*
|
|
* Let a denote the minor determinant of matrix A obtained by
|
|
* ij
|
|
*
|
|
* deleting the ith row and jth column from A.
|
|
*
|
|
* i+j
|
|
* Let b = (-1) a
|
|
* ij ji
|
|
*
|
|
* The matrix B = (b ) is the adjoint of A
|
|
* ij
|
|
*/
|
|
inline void CDXMatrix4x4F::GetAdjoint( CDXMatrix4x4F *pIn )
|
|
{
|
|
float a1, a2, a3, a4, b1, b2, b3, b4;
|
|
float c1, c2, c3, c4, d1, d2, d3, d4;
|
|
|
|
/* assign to individual variable names to aid */
|
|
/* selecting correct values */
|
|
|
|
a1 = pIn->m_Coeff[0][0]; b1 = pIn->m_Coeff[0][1];
|
|
c1 = pIn->m_Coeff[0][2]; d1 = pIn->m_Coeff[0][3];
|
|
|
|
a2 = pIn->m_Coeff[1][0]; b2 = pIn->m_Coeff[1][1];
|
|
c2 = pIn->m_Coeff[1][2]; d2 = pIn->m_Coeff[1][3];
|
|
|
|
a3 = pIn->m_Coeff[2][0]; b3 = pIn->m_Coeff[2][1];
|
|
c3 = pIn->m_Coeff[2][2]; d3 = pIn->m_Coeff[2][3];
|
|
|
|
a4 = pIn->m_Coeff[3][0]; b4 = pIn->m_Coeff[3][1];
|
|
c4 = pIn->m_Coeff[3][2]; d4 = pIn->m_Coeff[3][3];
|
|
|
|
|
|
/* row column labeling reversed since we transpose rows & columns */
|
|
|
|
m_Coeff[0][0] = det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4);
|
|
m_Coeff[1][0] = - det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4);
|
|
m_Coeff[2][0] = det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4);
|
|
m_Coeff[3][0] = - det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);
|
|
|
|
m_Coeff[0][1] = - det3x3( b1, b3, b4, c1, c3, c4, d1, d3, d4);
|
|
m_Coeff[1][1] = det3x3( a1, a3, a4, c1, c3, c4, d1, d3, d4);
|
|
m_Coeff[2][1] = - det3x3( a1, a3, a4, b1, b3, b4, d1, d3, d4);
|
|
m_Coeff[3][1] = det3x3( a1, a3, a4, b1, b3, b4, c1, c3, c4);
|
|
|
|
m_Coeff[0][2] = det3x3( b1, b2, b4, c1, c2, c4, d1, d2, d4);
|
|
m_Coeff[1][2] = - det3x3( a1, a2, a4, c1, c2, c4, d1, d2, d4);
|
|
m_Coeff[2][2] = det3x3( a1, a2, a4, b1, b2, b4, d1, d2, d4);
|
|
m_Coeff[3][2] = - det3x3( a1, a2, a4, b1, b2, b4, c1, c2, c4);
|
|
|
|
m_Coeff[0][3] = - det3x3( b1, b2, b3, c1, c2, c3, d1, d2, d3);
|
|
m_Coeff[1][3] = det3x3( a1, a2, a3, c1, c2, c3, d1, d2, d3);
|
|
m_Coeff[2][3] = - det3x3( a1, a2, a3, b1, b2, b3, d1, d2, d3);
|
|
m_Coeff[3][3] = det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3);
|
|
}
|
|
/*
|
|
* float = det4x4( matrix )
|
|
*
|
|
* calculate the determinant of a 4x4 matrix.
|
|
*/
|
|
inline float det4x4( CDXMatrix4x4F *pIn )
|
|
{
|
|
float ans;
|
|
float a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;
|
|
|
|
/* assign to individual variable names to aid selecting */
|
|
/* correct elements */
|
|
|
|
a1 = pIn->m_Coeff[0][0]; b1 = pIn->m_Coeff[0][1];
|
|
c1 = pIn->m_Coeff[0][2]; d1 = pIn->m_Coeff[0][3];
|
|
|
|
a2 = pIn->m_Coeff[1][0]; b2 = pIn->m_Coeff[1][1];
|
|
c2 = pIn->m_Coeff[1][2]; d2 = pIn->m_Coeff[1][3];
|
|
|
|
a3 = pIn->m_Coeff[2][0]; b3 = pIn->m_Coeff[2][1];
|
|
c3 = pIn->m_Coeff[2][2]; d3 = pIn->m_Coeff[2][3];
|
|
|
|
a4 = pIn->m_Coeff[3][0]; b4 = pIn->m_Coeff[3][1];
|
|
c4 = pIn->m_Coeff[3][2]; d4 = pIn->m_Coeff[3][3];
|
|
|
|
ans = a1 * det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4 )
|
|
- b1 * det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4 )
|
|
+ c1 * det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4 )
|
|
- d1 * det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4 );
|
|
return ans;
|
|
}
|
|
|
|
/*
|
|
* float = det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3 )
|
|
*
|
|
* calculate the determinant of a 3x3 matrix
|
|
* in the form
|
|
*
|
|
* | a1, b1, c1 |
|
|
* | a2, b2, c2 |
|
|
* | a3, b3, c3 |
|
|
*/
|
|
|
|
inline float det3x3( float a1, float a2, float a3,
|
|
float b1, float b2, float b3,
|
|
float c1, float c2, float c3 )
|
|
{
|
|
float ans;
|
|
|
|
ans = a1 * det2x2( b2, b3, c2, c3 )
|
|
- b1 * det2x2( a2, a3, c2, c3 )
|
|
+ c1 * det2x2( a2, a3, b2, b3 );
|
|
return ans;
|
|
}
|
|
|
|
/*
|
|
* float = det2x2( float a, float b, float c, float d )
|
|
*
|
|
* calculate the determinant of a 2x2 matrix.
|
|
*/
|
|
inline float det2x2( float a, float b, float c, float d )
|
|
{
|
|
float ans = a * d - b * c;
|
|
return ans;
|
|
}
|
|
|
|
inline HRESULT CDXMatrix4x4F::InitFromSafeArray( SAFEARRAY * /*pSA*/ )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
#if 0
|
|
long *pData;
|
|
|
|
if( !pSA || ( pSA->cDims != 1 ) ||
|
|
( pSA->cbElements != sizeof(float) ) ||
|
|
( pSA->rgsabound->lLbound != 1 ) ||
|
|
( pSA->rgsabound->cElements != 8 )
|
|
)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
hr = SafeArrayAccessData(pSA, (void **)&pData);
|
|
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
for( int i = 0; i < 4; ++i )
|
|
{
|
|
m_Bounds[i].Min = pData[i];
|
|
m_Bounds[i].Max = pData[i+4];
|
|
m_Bounds[i].SampleRate = SampleRate;
|
|
}
|
|
|
|
hr = SafeArrayUnaccessData( pSA );
|
|
}
|
|
}
|
|
#endif
|
|
return hr;
|
|
} /* CDXMatrix4x4F::InitFromSafeArray */
|
|
|
|
inline HRESULT CDXMatrix4x4F::GetSafeArray( SAFEARRAY ** /*ppSA*/ ) const
|
|
{
|
|
HRESULT hr = S_OK;
|
|
#if 0
|
|
SAFEARRAY *pSA;
|
|
|
|
if( !ppSA )
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
SAFEARRAYBOUND rgsabound;
|
|
rgsabound.lLbound = 1;
|
|
rgsabound.cElements = 16;
|
|
|
|
if( !(pSA = SafeArrayCreate( VT_I4, 1, &rgsabound ) ) )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
long *pData;
|
|
hr = SafeArrayAccessData( pSA, (void **)&pData );
|
|
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
for( int i = 0; i < 4; ++i )
|
|
{
|
|
pData[i] = m_Bounds[i].Min;
|
|
pData[i+4] = m_Bounds[i].Max;
|
|
}
|
|
|
|
hr = SafeArrayUnaccessData( pSA );
|
|
}
|
|
}
|
|
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
*ppSA = pSA;
|
|
}
|
|
}
|
|
#endif
|
|
return hr;
|
|
} /* CDXMatrix4x4F::GetSafeArray */
|
|
|
|
inline void CDXMatrix4x4F::TransformBounds( DXBNDS& /*Bnds*/, DXBNDS& /*ResultBnds*/ )
|
|
{
|
|
|
|
} /* CDXMatrix4x4F::TransformBounds */
|
|
|
|
|
|
|
|
#endif // __DXTPRIV_H_
|
|
|
|
|
|
|