
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_PlatformMaths.h (PS3 version)
// Author : Andy Tate
// Date   : 20-Jun-2005
//
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
	#pragma once
#endif   // ifdef ASURA_USE_PRAGMA_ONCE

#ifndef __ASURA_PLATFORMMATHS_H__
#define __ASURA_PLATFORMMATHS_H__

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include <limits.h>

#ifdef SPU
#include <math.h>
#else
#include <fastmath.h>
#endif

////////////////////////////////////////////////////////////////////////////////
// Inlined function definitions...
////////////////////////////////////////////////////////////////////////////////

// return x raised to the y'th power
static inline float Asura_Maths::Power(float x, float y)
{
	// assume powf exists. if not then that platform is going to have to come up with an alternative
	return powf(x, y);
}

static inline Asura_Angle Asura_Maths::DegToRad(float fDeg)
{ 
    return (fDeg * DegToRadConstant); 
}

static inline float Asura_Maths::RadToDeg(Asura_Angle fRad)
{ 
    return (fRad * RadToDegConstant); 
}

// Kevin Lea - 10/09/2001 10:38:13 - max & min inlines
template< typename T >
static inline T Asura_Maths::Max( const T& tA, const T& tB )
{
	return tA > tB ? tA : tB;
}

template< typename T >
static inline T Asura_Maths::Min( const T& tA, const T& tB )
{
	return tA < tB ? tA : tB;
}


static inline float Asura_Maths::Abs(float f)
{
    return fabsf( f );
}


static inline int Asura_Maths::Abs(int a)
{
#if 0
    return( (a ^ (a >> 31)) - (a >> 31) );
#else
    // GCC appears to compile this version to equivalent code to the above
    // anyway so probably best to leave it to its own devices.
    if (a<0)
    {
        return -a;
    }
    else
    {
        return a;
    }
#endif
}


static inline float Asura_Maths::Sign(float a)
{
    if (a>0)
    {
        return +1.0f;
    }
    else if (a<0)
    {
        return -1.0f;
    }
    else
    {
        return 0.0f;
    }
}


static inline int Asura_Maths::Sign( int i )
{
    if( i )
    {
        return( 1 + ((i >> 31) << 1) );
    }
    else
    {
        return 0;
    }
}


static inline u_int Asura_Maths::GetFloorLog2( u_int uValue )
{
    u_int uLog2 = 0;
    u_int uNext = 2;

    while( uNext <= uValue )
    {
        uNext <<= 1;
        ++uLog2;
    }
    
    return uLog2;
}

static inline u_int Asura_Maths::GetCeilLog2( u_int uValue )
{
    u_int uLog2 = 0;
    u_int uCmp  = 1;

    while( uCmp < uValue )
    {
        uCmp <<= 1;
        ++uLog2;
    }
    
    return uLog2;
}

static inline u_int Asura_Maths::GetFloorPow2( u_int uValueOld )
{
	if( uValueOld <= 1)
	{
		return( uValueOld);
	}

	u_int uNShift = 0;
	u_int uValue = uValueOld;

	for( ; uValue != 0; uValue >>= 1, uNShift++);

	u_int uValueNew = 1 << (uNShift - 1);
	if( uValueOld < uValueNew)
	{
		uValueNew >>= 1;
	}

	return( uValueNew);
}

static inline u_int Asura_Maths::GetCeilPow2( u_int uValueOld )
{
	if( uValueOld <= 1)
	{
		return( uValueOld);
	}

	u_int uNShift = 0;
	u_int uValue = uValueOld;

	for( ; uValue != 0; uValue >>= 1, uNShift++);

	u_int uValueNew = 1 << (uNShift - 1);
	if( uValueNew < uValueOld)
	{
		uValueNew <<= 1;
	}

	return( uValueNew);
}

/// David Evans - 22/08/2002 16:10:20 -  Mathematical functions, moved from Asura_Maths.cpp

static inline float Asura_Maths::Sine(Asura_Angle fAngle)
{
    return sinf(fAngle);
}

static inline float Asura_Maths::Cosine(Asura_Angle fAngle)
{
    return cosf(fAngle);
}

static inline float Asura_Maths::Tangent(Asura_Angle fAngle)
{
    return tanf(fAngle);
}

static inline Asura_Angle Asura_Maths::ArcSine(float fSine)
{
    return asinf(fSine);
}
static inline Asura_Angle Asura_Maths::ArcCosine(float fCosine)
{
    return acosf(fCosine);
}
static inline Asura_Angle Asura_Maths::ArcTangent(float fX, float fY)
{
    return atan2f(fX, fY);
}

void Asura_Maths::SinCos(Asura_Angle fAngle, float& fOutputSine, float& fOutputCos)
{
	fOutputSine	= Sine (fAngle);
	fOutputCos	= Cosine (fAngle);
}

void Asura_Maths::SinCos2(  Asura_Angle fAngle1, Asura_Angle fAngle2, float& fOutputSine1, 
							float& fOutputCos1, float& fOutputSine2, float& fOutputCos2)
{
	Asura_Maths::SinCos(fAngle1, fOutputSine1, fOutputCos1);
	Asura_Maths::SinCos(fAngle2, fOutputSine2, fOutputCos2);
}


static inline float Asura_Maths::Sqrt(float f)
{
    return sqrtf(f);
}
static inline float Asura_Maths::InvSqrt(float f)
{
    float m = sqrtf(f);
    return 1.0f/m;
}

/// David Evans - 22/08/2002 15:36:03 - Conversion functions - moved from Asura_Maths.cpp

static __inline int Asura_Maths::FloatToInt(float fInputVal)
{
    return static_cast< int >( fInputVal > 0.0f ? fInputVal + 0.5f : fInputVal - 0.5f );
}

static inline int Asura_Maths::FloatToInt_Near(float fInputVal)
{
    return static_cast< int >( fInputVal > 0.0f ? fInputVal + 0.5f : fInputVal - 0.5f );
}

/// David Evans - 22/08/2002 10:14:09 - Returns the integer part of the float
static inline int Asura_Maths::FloatToInt_Chop(float f)
{
    return (int)f;
}

// JG - 19 November 2008 - Returns a round up integer approximation of the float
static inline int Asura_Maths::FloatToInt_Ceil(float f)
{
    return static_cast<int>( ceilf(f) );
}

// (MH - 18.04.2002) - since vararg functions implicitly convert floats to doubles,
// (as well as chars to ints) centralise the conversion here. This prevents a warning
// every time vararg functions are used in the code.
static __inline double Asura_Maths::FtoD(float f)
{
    return (double)f;
}

static inline float Asura_Maths::CalculateTriArea( const Asura_Vector_3& xV0, const Asura_Vector_3& xV1, const Asura_Vector_3& xV2 )
{
    return( 0.5f * ((xV1 - xV0) ^ (xV2 - xV0)).Magnitude() );
}

// KOR - 28/11/2005 - floating point modulo (remainder of fX/fY); should be fmod() on most platforms
static inline float Asura_Maths::FloatMod(float fX, float fY)
{
	return fmodf(fX, fY);
}

// KOR - 28/11/2005 - Returns f where f is in the range [fMin, fMax) and f = fAngle mod (fMax - fMin)
static inline float Asura_Maths::AngleToRange(float fAngle, float fMin, float fMax)
{
	// Get the range
	const float fRange = fMax - fMin;
	// This gets us a fReturnAngle in the range (-fRange, fRange) where fReturnAngle = fAngle mod fRange
	const float fReturnAngle = FloatMod(fAngle, fRange);
	// This deals with fReturnAngle in (-fRange, fMin)
	if(fReturnAngle < fMin) return fReturnAngle + fRange;
	// This deals with fReturnAngle in [fMax, fRange)
	if(fReturnAngle >= fMax) return fReturnAngle - fRange;
	// Otherwise fReturnAngle is in [fMin, fMax) as desired.
	return fReturnAngle;
}

static inline float Asura_Maths::RadiansToZeroCentredRange(float fRadians)
{
	return AngleToRange(fRadians, -Pi, Pi);
}

static inline float Asura_Maths::RadiansToZeroMinimumRange(float fRadians)
{
	return AngleToRange(fRadians, 0.f, Pi * 2.f);
}

static inline bool Asura_Maths::IsNaN ( const float fNum )
{
	return ( fNum != fNum );
}

// A S U R A _ M A T R I X _ 3 X 3 ///////////////////////////////////////////
inline void Asura_Matrix_3x3::Transpose(void)
{
    float t;
    
    t = e12;
    e12 = e21;
    e21 = t;
        
    t = e13;
    e13 = e31;
    e31 = t;    
    
    t = e23;
    e23 = e32;
    e32 = t;    
}

inline Asura_Vector_3 Asura_Matrix_3x3::ApplyTranspose( const Asura_Vector_3& xVec ) const
{
    return Asura_Vector_3( e11 * xVec.x + e21 * xVec.y + e31 * xVec.z,
                           e12 * xVec.x + e22 * xVec.y + e32 * xVec.z,
                           e13 * xVec.x + e23 * xVec.y + e33 * xVec.z );
}

inline void Asura_Matrix_3x3::Identity(void)
{
    e11=e22=e33=1.0f;
    e12=e13=e21=e23=e31=e32=0.0f;
}

inline Asura_Matrix_3x3 Asura_Matrix_3x3::operator * ( const Asura_Matrix_3x3& m) const
{
    class Asura_Matrix_3x3 result;

    result.e11 = e11 * m.e11 + e12 * m.e21 + e13 * m.e31;
    result.e21 = e21 * m.e11 + e22 * m.e21 + e23 * m.e31;
    result.e31 = e31 * m.e11 + e32 * m.e21 + e33 * m.e31;

    result.e12 = e11 * m.e12 + e12 * m.e22 + e13 * m.e32;
    result.e22 = e21 * m.e12 + e22 * m.e22 + e23 * m.e32;
    result.e32 = e31 * m.e12 + e32 * m.e22 + e33 * m.e32;

    result.e13 = e11 * m.e13 + e12 * m.e23 + e13 * m.e33;
    result.e23 = e21 * m.e13 + e22 * m.e23 + e23 * m.e33;
    result.e33 = e31 * m.e13 + e32 * m.e23 + e33 * m.e33;

    return result;
}

inline Asura_Matrix_3x3 Asura_Matrix_3x3::operator * ( const float s) const
{
    class Asura_Matrix_3x3 result;

    result.e11 = e11 * s;
    result.e21 = e21 * s;
    result.e31 = e31 * s;

    result.e12 = e12 * s;
    result.e22 = e22 * s;
    result.e32 = e32 * s;

    result.e13 = e13 * s;
    result.e23 = e23 * s;
    result.e33 = e33 * s;

    return result;
}


// A S U R A _ V E C T O R _ 2 ///////////////////////////////////////////////
inline Asura_Vector_2::Asura_Vector_2(const Asura_Vector_2& v)
{   
    x = v.x;
    y = v.y;
}

inline Asura_Vector_2::Asura_Vector_2(float x0, float y0)
{
    x = x0;
    y = y0;
}

// binary ops

inline Asura_Vector_2 Asura_Vector_2::operator * ( float fScale ) const
{
    return Asura_Vector_2( this->x * fScale, this->y * fScale );
}

inline Asura_Vector_2 Asura_Vector_2::operator + ( const Asura_Vector_2& v) const
{
    return Asura_Vector_2(x + v.x, y + v.y);
}
inline void Asura_Vector_2::operator += ( const Asura_Vector_2& v)
{
    x += v.x;
    y += v.y;
}

inline Asura_Vector_2 Asura_Vector_2::operator - ( const Asura_Vector_2& v) const
{
    return Asura_Vector_2(x - v.x, y - v.y);
}
inline void Asura_Vector_2::operator -= ( const Asura_Vector_2& v)
{
    x -= v.x;
    y -= v.y;
}

inline void Asura_Vector_2::operator *= ( float s )
{
    x *= s;
    y *= s;
}

inline void Asura_Vector_2::operator /= ( float f)
{
    float fInv = 1.0f / f;
    x *= fInv;
    y *= fInv;

}

inline bool Asura_Vector_2::operator == ( const Asura_Vector_2& v) const
{
    return x == v.x && y == v.y;
}

inline bool Asura_Vector_2::operator != ( const Asura_Vector_2& v) const
{
    return x != v.x || y != v.y;
}

//dot product
inline float  Asura_Vector_2::operator * ( const Asura_Vector_2& v) const
{
    return (x*v.x + y*v.y);
}

//Pics a random vector in the plane, with random length [0..1] and
//random direction (with symmetrical distribution)
inline Asura_Vector_2& Asura_Vector_2::RandomVector(Asura_RandomGenerator* pxRNG)
{
    //Choose random elements for x and y, until the squared length is
    //within the unit circle.
    do
    {
        x = pxRNG->GetFloat( -1.0f, 1.0f );
        y = pxRNG->GetFloat( -1.0f, 1.0f );
    }
    while(x * x + y * y > 1.f);

    //Return the resulting vector
    return *this;
}


inline Asura_Vector_2& Asura_Vector_2::RandomDirection(Asura_RandomGenerator* pxRNG)
{
    float fLength2;

    //Choose random elements for x and y, until 
    //the squared length is within the unit circle, but large
    //enough that the normalisation won't result in poor conditioning.
    do
    {
        x = pxRNG->GetFloat( -1.0f, 1.0f );
        y = pxRNG->GetFloat( -1.0f, 1.0f );

        fLength2 = x * x + y * y;
    }
    while(fLength2 > 1.f || fLength2 < 0.01f);

    fLength2 = 1.f / Asura_Maths::Sqrt(fLength2);

    x *= fLength2;
    y *= fLength2;

    //Return the resulting vector
    return *this;
}


inline float Asura_Vector_2::Normalise(void)
{
    const float m = Magnitude();

    if (m==0.0f)    return m;

    const float rm = 1.0f/m;
    x *= rm;
    y *= rm;

    return m;
}

inline float Asura_Vector_2::Magnitude( void ) const
{   
    return Asura_Maths::Sqrt((x*x) + (y*y));
}

inline float Asura_Vector_2::MagnitudeSquared( void ) const
{   
    return ((x*x) + (y*y));
}

inline void Asura_Vector_2::Zero(void)
{
    x=y=0.0f;
}


// A S U R A _ V E C T O R _ 3 ///////////////////////////////////////////////
inline Asura_Vector_3::Asura_Vector_3(const float * fPtr)
{
    x = fPtr[0];
    y = fPtr[1];
    z = fPtr[2];
}

inline Asura_Vector_3::Asura_Vector_3(const Asura_Vector_3& v)
{   
    x = v.x;
    y = v.y;
    z = v.z;
}

inline Asura_Vector_3::Asura_Vector_3(float x0, float y0, float z0)
{
    x = x0;
    y = y0;
    z = z0;
}

// assignment operators
inline void Asura_Vector_3::operator = ( const Asura_Vector_3& v )
{
	x = v.x;
	y = v.y;
	z = v.z;
}

inline void Asura_Vector_3::operator += ( const Asura_Vector_3& v)
{
    x += v.x;
    y += v.y;
    z += v.z;
}

inline void Asura_Vector_3::operator -= ( const Asura_Vector_3& v)
{
    x -= v.x;
    y -= v.y;
    z -= v.z;
}

inline void Asura_Vector_3::operator *= ( float f)
{
    x *= f;
    y *= f;
    z *= f;
}

inline void Asura_Vector_3::operator /= ( float f)
{
    float fInv = 1.0f / f;
    x *= fInv;
    y *= fInv;
    z *= fInv;
}

// unary operators
inline Asura_Vector_3 Asura_Vector_3::operator - () const
{
    return Asura_Vector_3(-x, -y, -z);
}

// binary operators
inline Asura_Vector_3 Asura_Vector_3::operator + ( const Asura_Vector_3& v) const
{
    return Asura_Vector_3(x + v.x, y + v.y, z + v.z);
}
inline Asura_Vector_3 Asura_Vector_3::operator - ( const Asura_Vector_3& v) const
{
    return Asura_Vector_3(x - v.x, y - v.y, z - v.z);
}
inline Asura_Vector_3 Asura_Vector_3::operator * ( float f) const
{
    return Asura_Vector_3(x * f, y * f, z * f);
}
inline Asura_Vector_3 Asura_Vector_3::operator / ( float f) const
{
    float fInv = 1.0f / f;
    return Asura_Vector_3(x * fInv, y * fInv, z * fInv);
}                                               

inline Asura_Vector_3 Asura_Vector_3::operator ^ ( const Asura_Vector_3& v) const
{
    return Asura_Vector_3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
}

inline float  Asura_Vector_3::operator * ( const Asura_Vector_3& v) const
{
    return (x*v.x + y*v.y + z*v.z);
}

inline Asura_Vector_3 Asura_Vector_3::operator * ( const Asura_Matrix_3x3& m) const
{
    class Asura_Vector_3 result;

    result.x = m.e11 * x + m.e12 * y + m.e13 * z;
    result.y = m.e21 * x + m.e22 * y + m.e23 * z;
    result.z = m.e31 * x + m.e32 * y + m.e33 * z;

    return result;
}

inline bool Asura_Vector_3::operator == ( const Asura_Vector_3& v) const
{
    return x == v.x && y == v.y && z == v.z;
}

inline bool Asura_Vector_3::ApproximatelyEquals(const Asura_Vector_3& v, float epsilon /*= 1.0e-6f*/) const
{
    Asura_Vector_3 delta;
    delta.x = x-v.x;
    delta.y = y-v.y;
    delta.z = z-v.z;

    return ((delta.x*delta.x+delta.y*delta.y+delta.z*delta.z)<epsilon);
    
}
inline bool Asura_Vector_3::operator != ( const Asura_Vector_3& v) const
{
    return x != v.x || y != v.y || z != v.z;
}

inline Asura_Vector_3 Asura_Vector_3::Vector_Multiply( const Asura_Vector_3& v1 ) const
{
	return Asura_Vector_3( v1.x * x, v1.y * y, v1.z * z );
}

// useful operations
//Picks a random vector in the plane, with a length of 1
//in a random direction. The distribution is symmetrical
inline Asura_Vector_3& Asura_Vector_3::RandomDirection(Asura_RandomGenerator* pxRNG)
{
    float fLength2;

    //Choose random elements for x and y, until 
    //the squared length is within the unit sphere, but large
    //enough that the normalisation won't result in poor conditioning.
    do
    {
        x = pxRNG->GetFloat( -1.0f, 1.0f );
        y = pxRNG->GetFloat( -1.0f, 1.0f );
        z = pxRNG->GetFloat( -1.0f, 1.0f );

        fLength2 = x * x + y * y + z * z;
    }
    while(fLength2 > 1.f || fLength2 < 0.01f);

    fLength2 = 1.f / Asura_Maths::Sqrt(fLength2);

    x *= fLength2;
    y *= fLength2;
    z *= fLength2;

    //Return the resulting vector
    return *this;
}


//Pics a random vector in a sphere, with random length [0..1] and
//random direction (with symmetrical distribution)
inline Asura_Vector_3& Asura_Vector_3::RandomVector(Asura_RandomGenerator* pxRNG)
{
    //Choose random elements for x, y and z, until the squared length is
    //within the unit sphere.
    do
    {
        x = pxRNG->GetFloat( -1.0f, 1.0f );
        y = pxRNG->GetFloat( -1.0f, 1.0f );
        z = pxRNG->GetFloat( -1.0f, 1.0f );
    }
    while(x * x + y * y + z * z > 1.f);

    //Return the resulting vector
    return *this;
}

inline float Asura_Vector_3::MagnitudeSquared(void) const
{   
    return ((x*x) + (y*y) + (z*z));
}

inline float Asura_Vector_3::Magnitude(void) const
{   
    return Asura_Maths::Sqrt((x*x) + (y*y) + (z*z));
}

inline float Asura_Vector_3::Normalise(void)
{
    const float m = Magnitude();
    
    if (m==0.0f)    return m;

    const float rm = 1.0f/m;
    x *= rm;
    y *= rm;
    z *= rm;

    return m;
}       

inline void Asura_Vector_3::Zero(void)
{
    x=y=z=0.0f;
}

// A S U R A _ E U L E R _ 3 /////////////////////////////////////////////////
inline Asura_Euler_3::Asura_Euler_3(float x0, float y0, float z0)
{
    x = x0;
    y = y0;
    z = z0;
}

// assignment operators
inline void Asura_Euler_3::operator += ( const Asura_Euler_3& xEuler)
{
    x += xEuler.x;
    y += xEuler.y;
    z += xEuler.z;
}
inline void Asura_Euler_3::operator -= ( const Asura_Euler_3& xEuler)
{
    x -= xEuler.x;
    y -= xEuler.y;
    z -= xEuler.z;
}
inline void Asura_Euler_3::operator *= ( float f)
{
    x *= f;
    y *= f;
    z *= f;
}
inline void Asura_Euler_3::operator /= ( float f)
{
    float fInv = 1.0f / f;
    x *= fInv;
    y *= fInv;
    z *= fInv;
}

// unary operators
inline Asura_Euler_3 Asura_Euler_3::operator - () const
{
    return Asura_Euler_3(-x, -y, -z);
}

// binary operators
inline Asura_Euler_3 Asura_Euler_3::operator + ( const Asura_Euler_3& xEuler) const
{
    return Asura_Euler_3(x + xEuler.x, y + xEuler.y, z + xEuler.z);
}
inline Asura_Euler_3 Asura_Euler_3::operator - ( const Asura_Euler_3& xEuler) const
{
    return Asura_Euler_3(x - xEuler.x, y - xEuler.y, z - xEuler.z);
}
inline Asura_Euler_3 Asura_Euler_3::operator * ( float f) const
{
    return Asura_Euler_3(x * f, y * f, z * f);
}
inline Asura_Euler_3 Asura_Euler_3::operator / ( float f) const
{
    float fInv = 1.0f / f;
    return Asura_Euler_3(x * fInv, y * fInv, z * fInv);
}                                           

inline void Asura_Euler_3::ToMatrix(Asura_Matrix_3x3& m) const
{
    float c1 = Asura_Maths::Cosine(x);
    float s1 = Asura_Maths::Sine(x);
    float c2 = Asura_Maths::Cosine(y);
    float s2 = Asura_Maths::Sine(y);
    float c3 = Asura_Maths::Cosine(z);
    float s3 = Asura_Maths::Sine(z);

    m.e11 = c2*c3+s1*s2*s3;
    m.e12 = -c2*s3+s1*s2*c3;
    m.e13 = c1*s2;

    m.e21 = c1*s3;
    m.e22 = c1*c3;
    m.e23 = -s1;

    m.e31 = -s2*c3 + s1*c2*s3;
    m.e32 = s2*s3 + s1*c2*c3;
    m.e33 = c1*c2;
}

inline void Asura_Euler_3::FromMatrix(const Asura_Matrix_3x3& m)
{
    float sx = -m.e23;

    if (sx < 1.0f)
    {
        if (sx > -1.0f)
        {
            // cx is non-zero then
            x = Asura_Maths::ArcSine(sx);
            y = Asura_Maths::ArcTangent(m.e13,m.e33);
            z = Asura_Maths::ArcTangent(m.e21,m.e22);
        }
        else
        {
            // non-unique

            // -e31 = s(y)c(z)+c(y)s(z) = s(y+z)
            // e11  = c(y)c(z)-s(y)s(z) = c(y+z))
            // y+z  = atan(-e31/e11)
            // if choose z to be zero

            x = -Asura_Maths::Pi*0.5f;
            y = Asura_Maths::ArcTangent(-m.e31,m.e11);
            z = 0;
        }
    }
    else
    {
        // non-unique

            // e12 = s(y)c(z)-c(y)s(z) = s(y-z)
            // e32 = s(y)s(z)+c(y)c(z) = c(y-z)
            // y-z = atan(e12/e32)
            // if choose z to be zero

            x = Asura_Maths::Pi*0.5f;
            y = Asura_Maths::ArcTangent(m.e12,m.e32);
            z = 0;
    }
}

inline void Asura_Euler_3::Zero(void)
{
    x=y=z=0.0f;
}



// A S U R A _ Q U A T ///////////////////////////////////////////////////////

inline Asura_Quat::Asura_Quat(float x0, float y0, float z0, float w0)
{
    x = x0;
    y = y0;
    z = z0;
    w = w0;
}

inline void Asura_Quat::Identity( void )
{
    x = 0.0f;
    y = 0.0f;
    z = 0.0f;
    w = 1.0f;
}

inline void Asura_Quat::Invert( void )
{
    x = -x;
    y = -y;
    z = -z;
}

inline Asura_Quat Asura_Quat::operator * ( float f) const
{
    return Asura_Quat(x*f, y*f, z*f, w*f);
}

inline Asura_Quat Asura_Quat::operator - () const
{
    return Asura_Quat(-x, -y, -z, -w);
}

inline Asura_Quat Asura_Quat::operator + ( const Asura_Quat& q) const
{
    return Asura_Quat(x+q.x, y+q.y, z+q.z, w+q.w);
}

inline bool Asura_Quat::ApproximatelyEquals(const Asura_Quat& q, float epsilon /*= 1.0e-6f*/) const
{
	float cos_omega = q.w*w + q.x*x + q.y*y + q.z*z;
    return( Asura_Maths::Abs(cos_omega) >= 1.0f - epsilon );
}

inline bool Asura_Quat::operator == ( const Asura_Quat& q) const
{
    return x == q.x && y == q.y && z == q.z && w == q.w;
}

inline float Asura_Quat::MagnitudeSquared(void) const
{
    return x*x+y*y+z*z+w*w;
}

inline void Asura_Quat::ToMatrix(Asura_Matrix_3x3& m) const
{
    /* Implementation from Graphics Gems IV */

    float s = 2.0f;///Magnitude();      

    float xs = x*s;
    float ys = y*s;
    float zs = z*s;
    
    float wx = w*xs;
    float wy = w*ys;
    float wz = w*zs;

    float xx = x*xs;
    float xy = x*ys;
    float xz = x*zs;

    float yy = y*ys;
    float yz = y*zs;
    float zz = z*zs;
        
    m.e11 = 1.0f - (yy+zz);
    m.e21 = xy + wz;
    m.e31 = xz - wy;

    m.e12 = xy - wz;
    m.e22 = 1.0f - (xx + zz);
    m.e32 = yz + wx;

    m.e13 = xz + wy;
    m.e23 = yz - wx;
    m.e33 = 1.0f - (xx+yy);
}

inline void Asura_Quat::ToEuler(Asura_Euler_3& xEuler) const
{
    // KJL - 14/05/2003 13:02:02 - quat to euler. This should return exactly the same results
    // as quat->matrix->euler, except where we have an ambiguity in the euler formulation and 
    // lose a degree of freedom ('gimbal lock' due to 90 degree rotations etc)

    float fXX = x*x;
    float fYY = y*y;
    float fZZ = z*z;

    float fXY = x*y;
    float fXZ = x*z;
    float fYZ = y*z;
    float fWX = w*x;
    float fWY = w*y;
    float fWZ = w*z;

    // KJL - 14/05/2003 12:54:43 - inverse sine is only defined for values in the range -1 to +1 
    // (simply because -1 <= sine(x) <= 1 for all x). At the -1 & +1 points the euler notation 
    // breaks down because there is an infinite number of solutions (gimbal lock etc)

    float fSineX = 2.0f*(fWX-fYZ);

    if (fSineX <= -1.0f)
    {
        xEuler.x = -Asura_Maths::Pi*0.5f;
    }
    else if (fSineX >= +1.0f)
    {
        xEuler.x = Asura_Maths::Pi*0.5f;
    }
    else
    {
        xEuler.x = Asura_Maths::ArcSine(fSineX);
    }

    // KJL - 14/05/2003 12:59:49 - arc tangent is well defined, so we'll let it look after itself

    xEuler.y = Asura_Maths::ArcTangent( 2.0F*(fXZ+fWY), 1.0F-2.0F*(fXX+fYY) );

    xEuler.z = Asura_Maths::ArcTangent( 2.0F*(fXY+fWZ), 1.0F-2.0F*(fXX+fZZ) );
}


inline void Asura_Quat::FromEuler(const Asura_Euler_3& e) 
{
    float fCx = Asura_Maths::Cosine(e.x/2.0f);
    float fCy = Asura_Maths::Cosine(e.y/2.0f);
    float fCz = Asura_Maths::Cosine(e.z/2.0f);

    // KJL - 14/05/2003 16:56:21 -  the sines below could be calculated from the cosines above
    // by using sin^2+cos^2 == 1. Probably be faster on the PS2 which has a fast square root,
    // may be faster on the PC also.
    float fSx = Asura_Maths::Sine(e.x/2.0f);
    float fSy = Asura_Maths::Sine(e.y/2.0f);
    float fSz = Asura_Maths::Sine(e.z/2.0f);

    // KJL - 14/05/2003 16:57:56 - you know your maths is right when the ocde makes pretty patterns
    w = fCx * fCy * fCz + fSx * fSy * fSz;
    x = fSx * fCy * fCz + fCx * fSy * fSz;
    y = fCx * fSy * fCz - fSx * fCy * fSz;
    z = fCx * fCy * fSz - fSx * fSy * fCz;
	Normalise();
}


// (MH - 15.07.2002) adapted this from 3dc tools chunk lib.
// See also, Game Programming Gems I p.202.
inline void Asura_Quat::FromMatrix(const Asura_Matrix_3x3 & m)
{
    const int X=0;
    const int Y=1;
    const int Z=2;
    const int W=3;

    int const nxt[3] = 
    {
        Y,Z,X
    };
    
    float trace,s;
    
    trace = m[0][0] + m[1][1] + m[2][2];
    
    if (trace > 0.0f)
    {
        s = Asura_Maths::Sqrt(trace + 1.0f);
        w = s * 0.5f;
        s = 0.5f / s;
        
        x = (m[2][1] - m[1][2]) * s;
        y = (m[0][2] - m[2][0]) * s;
        z = (m[1][0] - m[0][1]) * s;
    }
    else
    {
        int i,j,k;
        float q[4];

        i = X;
        if (m[Y][Y] > m[X][X]) i = Y;
        if (m[Z][Z] > m[i][i]) i = Z;
        j = nxt[i]; 
        k = nxt[j];
        
        s = Asura_Maths::Sqrt((m[i][i] - (m[j][j]+m[k][k])) + 1.0f);
        
        q[i] = s * 0.5f;
        s = 0.5f / s;
        q[W] = (m[k][j] - m[j][k]) * s;
        q[j] = (m[j][i] + m[i][j]) * s;
        q[k] = (m[k][i] + m[i][k]) * s;

        x = q[0];
        y = q[1];
        z = q[2];
        w = q[3];
    }
    
}

// creates a quaternion from an angle and axis of rotation
inline void Asura_Quat::FromRotation(Asura_Angle angle, const Asura_Vector_3 & axis)
{
    angle *= 0.5f;
    float s = Asura_Maths::Sine(angle);
    x = axis.x * s;
    y = axis.y * s;
    z = axis.z * s;
    w = Asura_Maths::Cosine(angle);
	Normalise();
}

inline Asura_Vector_3 Asura_Quat::RotateVector(const Asura_Vector_3& xPoint) const
{
    //-----------------------------------------------------
    // 
    // This function rotates a vector p by the quaternion q
    // The formula is:
    //                  p' = (q)(p)(q*)
    //
    // but we calculate it using a vector formula which is an
    // expansion of this that Kev worked out.
    // for q = (v,w)
    // v' = 2w(v^p) + (2(v.p)v + (w^2-v^2)p
	//
	// KOR 2004/03/24 - Further optimisation
	//    = 2w(v^p) + 2(v.p)v + (2w^2 - 1)p
	//    = 2 ( w(v^p) + (v.p)v + (w^2 - 0.5)p)
    //
    //--------------------------------------------------------

    const Asura_Vector_3 xQuatVector(x,y,z); // the vector part of q
    return (( (xQuatVector ^ xPoint) * w + (xQuatVector * (xQuatVector * xPoint)) + (xPoint * (w * w - 0.5f))) * 2.0f);
}

inline Asura_Quat Asura_Quat::operator *(const Asura_Quat& q) const
{
    Asura_Vector_3 v1(x,y,z);
    Asura_Vector_3 v2(q.x, q.y, q.z);
    Asura_Vector_3 temp = v1*q.w + v2*w + (v1^v2);

    return Asura_Quat(temp.x, temp.y, temp.z, w*q.w - v1*v2);
}

inline void Asura_Quat::Normalise(void)
{
    const float fMag = Asura_Maths::Sqrt((x*x)+(y*y)+(z*z)+(w*w));
    
    if ( fMag != 0.0f )
	{
		const float fInvMag = 1.0f / fMag;
		x *= fInvMag;
		y *= fInvMag;
		z *= fInvMag;
		w *= fInvMag;
	}
}

inline float Asura_Quat::Dot(const Asura_Quat& q2) const
{
    return x*q2.x+y*q2.y+z*q2.z+w*q2.w;
}


inline void Asura_Quat::Slerp(const Asura_Quat& input1, const Asura_Quat& input2, float l)
{
    float sclp,sclq;
    
    float cosom;
    float omega, sinom;
	bool bNegateInput2;

    cosom=input1.Dot(input2);

    if (cosom>0.0f)
    {
        bNegateInput2 = false;
		
    }
    else
    {
        bNegateInput2 = true;
        cosom =-cosom;
    }

    if(cosom<65500.0f/65536.0f)
    {
        omega=Asura_Maths::ArcCosine(cosom);
        sinom=Asura_Maths::Sine(omega);

        sclp= Asura_Maths::Sine((1.0f-l)*omega)/sinom;
        sclq= Asura_Maths::Sine((l)*omega)/sinom;

    }
    else
    {
        sclp=1.0f - l;
        sclq=l;
    }
	
	if(bNegateInput2) sclq = -sclq;

    *this = input1*sclp + input2*sclq;
    this->Normalise();

}

inline void Asura_Quat::NLerp(const Asura_Quat& xInput1, const Asura_Quat& xInput2, float fDist)
{
	// need cosine of angle between quats to determine shortest path. If cos is
	// negative, invert the second input.
	float fCosOmega = xInput1.Dot(xInput2);
	float fSign = fCosOmega >= 0.0f ? 1.0f : -1.0f;
	*this = xInput1 * (1.0f - fDist) + xInput2 * (fDist * fSign);
	this->Normalise();
}

/// ASURA_COMP_QUAT. /////////////////////////
// KOR - 17/06/2003 11:42:29
// Game Programming Gems 3, section 2.4, suggests this 32-bit quat format:
//
// 3 bits - signs of x, y, z components.
// If w is negative, negate all the other signs, because rotating
// through a negated value through a negated axis is the same as the original rotation
// 9 bits - yaw
// 9 bits - pitch
// Generate these from a normalised (abs(x), abs(y), abs(z))
// Because we are taking the absolute values of x, y, z, we have 0 <= yaw, pitch <= pi/2
// and can rescale to 9 bits appropriately.
// The other advantage to this range is that apparently order 5 Taylor or Lagrange trig.
// approximations are sufficient. I have not implemented these yet; we shall have to see
// how performance is affected.
// 11 bits - w - just rescale by 1024
//
// From these values, we can extract the normalised quat

#define PI_OVER_2 1.57080f
#define PI_OVER_512 0.0061359231f
#define ONE_OVER_1024 0.0009765625f

inline void Asura_Comp_Quat::ToQuat( Asura_Quat& xQuat ) const
{
	float yaw	= (float)((m_uBits & 0x1FF00000) >> 20) * PI_OVER_512;
	if(yaw > PI_OVER_2) yaw = PI_OVER_2;
	float pitch	= (float)((m_uBits & 0x000FF800) >> 11) * PI_OVER_512;
	if(pitch > PI_OVER_2) pitch = PI_OVER_2;
	xQuat.w	= (float)((m_uBits & 0x000007FF)) * ONE_OVER_1024;
	if(xQuat.w >= 1.0f)
	{
		xQuat.x = 0.0f;
		xQuat.y = 0.0f;
		xQuat.z = 0.0f;
		xQuat.w = 1.0f;
	}
	else
	{
		float fCosPitch = Asura_Maths::Cosine(pitch);
		xQuat.x = fCosPitch * Asura_Maths::Sine(yaw);
		xQuat.y = Asura_Maths::Sine(pitch);
		xQuat.z = fCosPitch * Asura_Maths::Cosine(yaw);
		if(m_uBits & 0x80000000) xQuat.x = -xQuat.x;
		if(m_uBits & 0x40000000) xQuat.y = -xQuat.y;
		if(m_uBits & 0x20000000) xQuat.z = -xQuat.z;
		float length = Asura_Maths::Sqrt(1.0f - xQuat.w * xQuat.w);
		xQuat.x *= length;
		xQuat.y *= length;
		xQuat.z *= length;
	}
}

#define F512_OVER_PI 162.97466f

inline void Asura_Comp_Quat::FromQuat( const Asura_Quat& xQuat )
{
	Asura_Vector_3 v;
	v.x = xQuat.x;
	v.y = xQuat.y;
	v.z = xQuat.z;
	v.Normalise();
	// Signs
	if(xQuat.w > 0.0f)
	{
		m_uBits  = ((xQuat.x > 0.0f) ? 0 : 1) << 31;
		m_uBits |= ((xQuat.y > 0.0f) ? 0 : 1) << 30;
		m_uBits |= ((xQuat.z > 0.0f) ? 0 : 1) << 29;
	}
	else
	{
		m_uBits  = ((xQuat.x < 0.0f) ? 0 : 1) << 31;
		m_uBits |= ((xQuat.y < 0.0f) ? 0 : 1) << 30;
		m_uBits |= ((xQuat.z < 0.0f) ? 0 : 1) << 29;
	}
	// Yaw = atan(x, z)
	unsigned int yaw = Asura_Maths::FloatToInt_Near(F512_OVER_PI * Asura_Maths::ArcTangent(Asura_Maths::Abs(v.x), Asura_Maths::Abs(v.z)));
	m_uBits |= ((yaw << 20) & 0x1FF00000);
	// Pitch = asin(y)
	unsigned int pitch = Asura_Maths::FloatToInt_Near(F512_OVER_PI * Asura_Maths::ArcSine(Asura_Maths::Abs(v.y)));
	m_uBits |= ((pitch << 11) & 0x000FF800);
	// W
	unsigned int w = Asura_Maths::FloatToInt_Near(1024.0f * Asura_Maths::Abs(xQuat.w));
	m_uBits |= (w & 0x000007FF);
}

// KOR - 8/11/2005 - This is an implementation of the "smallest three" quaternion compression method
// detailed in Game Programming Gems 3. It appears to be just as accurate as the polar co-ordinate method,
// and much faster to decompress.
const float fSQRT_2 = (1.4142135623730950488016887242097f);
const float fONE_OVER_SQRT_2  = (1.f / fSQRT_2);

void Asura_Comp_Quat_Fast::ToQuat( Asura_Quat& xQuat ) const
{
	// Bottom two bits house the offset to the largest element (0 = w, 1 = x, 2 = y, 3 = z).
	const u_int uOffset = m_uBits & 0x03;
	// Extract the three smallest values.
	const float fValue0 = static_cast<float>( (m_uBits & 0xFFC00000) >> 22) * (fONE_OVER_SQRT_2 * 2.f / 1022.f) - fONE_OVER_SQRT_2;
	const float fValue1 = static_cast<float>( (m_uBits & 0x003FF000) >> 12) * (fONE_OVER_SQRT_2 * 2.f / 1022.f) - fONE_OVER_SQRT_2;
	const float fValue2 = static_cast<float>( (m_uBits & 0x00000FFC) >>  2) * (fONE_OVER_SQRT_2 * 2.f / 1022.f) - fONE_OVER_SQRT_2;
	// Calculate the largest value using the knowledge that the quat is normalised.
	const float fValue3Squared = 1.f - (fValue0 * fValue0) - (fValue1 * fValue1) - (fValue2 * fValue2);
	const float fValue3 = fValue3Squared > 0.f ? Asura_Maths::Sqrt(fValue3Squared) : 0.f;
	// Put the values in the correct places.
	float* const pfArray = reinterpret_cast<float*>(&xQuat);
	pfArray[(0 + uOffset) & 0x03] = fValue0;
	pfArray[(1 + uOffset) & 0x03] = fValue1;
	pfArray[(2 + uOffset) & 0x03] = fValue2;
	pfArray[(3 + uOffset) & 0x03] = fValue3;
}

void Asura_Comp_Quat_Fast::FromQuat( const Asura_Quat& xQuat )
{
#ifdef ASURA_ASSERT
	const float fEpsilon = 0.01f;
	const float fMagnitudeSquared = xQuat.MagnitudeSquared();
	Asura_Assert((1.f - fEpsilon) < fMagnitudeSquared && fMagnitudeSquared < (1.f + fEpsilon), "Quat must be normalised");
#endif
	// Find the offset of the largest value (0 = w, 1 = x, 2 = y, 3 = z). Slightly clunky way of doing it.
	Asura_Quat xAbsQuat(Asura_Maths::Abs(xQuat.x), Asura_Maths::Abs(xQuat.y), Asura_Maths::Abs(xQuat.z), Asura_Maths::Abs(xQuat.w));
	const float fLargestValue = Asura_Maths::Max(Asura_Maths::Max(xAbsQuat.x, xAbsQuat.y), Asura_Maths::Max(xAbsQuat.z, xAbsQuat.w));
	if(fLargestValue == xAbsQuat.x)			m_uBits = 1;
	else if(fLargestValue == xAbsQuat.y)	m_uBits = 2;
	else if(fLargestValue == xAbsQuat.z)	m_uBits = 3;
	else	                                m_uBits = 0;
	// We store 0, 1, 2, and calculate 3 (the largest)
	float fValue0, fValue1, fValue2, fValue3;
	const float* pfArray = reinterpret_cast<const float*>(&xQuat);
	fValue0 = pfArray[(0 + m_uBits) & 0x03];
	fValue1 = pfArray[(1 + m_uBits) & 0x03];
	fValue2 = pfArray[(2 + m_uBits) & 0x03];
	fValue3 = pfArray[(3 + m_uBits) & 0x03];
	// If the largest is negative, we negate all the other elements using the fact that q = -q
	if(fValue3 < 0.f)
	{
		fValue0 = -fValue0;
		fValue1 = -fValue1;
		fValue2 = -fValue2;
	}
	// Pack the three smallest values into the remaining 30 bits (10 bits each)
	// Using a range of 1022 so that we can get exactly zero while allowing the maximum and minimum values
	// Regarding use of FloatToInt_Near, I tried doing a RMS comparison of either side of each float to int,
	// but it made no discernable difference, so I dropped it.
	m_uBits |= Asura_Maths::FloatToInt_Near( (fONE_OVER_SQRT_2 + fValue0) * (fSQRT_2 * 1022.f / 2.f) ) << 22;
	m_uBits |= Asura_Maths::FloatToInt_Near( (fONE_OVER_SQRT_2 + fValue1) * (fSQRT_2 * 1022.f / 2.f) ) << 12;
	m_uBits |= Asura_Maths::FloatToInt_Near( (fONE_OVER_SQRT_2 + fValue2) * (fSQRT_2 * 1022.f / 2.f) ) <<  2;
}

// A S U R A _ B O U N D I N G _ R E C T A N G L E . /////////////////////////
inline void Asura_Bounding_Rectangle::Reset(void)
{
    // set to exaggeratedly large values
    MinX = Asura_Maths::LargeFloat;
    MinY = Asura_Maths::LargeFloat;

    MaxX = -Asura_Maths::LargeFloat;
    MaxY = -Asura_Maths::LargeFloat;
}

inline void Asura_Bounding_Rectangle::Set( const Asura_Vector_2& v )
{
    if (v.x > MaxX) MaxX = v.x;
    if (v.y > MaxY) MaxY = v.y;

    if (v.x < MinX) MinX = v.x;
    if (v.y < MinY) MinY = v.y;
}

inline bool Asura_Bounding_Rectangle::Intersects(const Asura_Bounding_Rectangle& xRect) const
{
    if ( ((MaxX >= xRect.MinX) && (MinX <= xRect.MaxX))
      && ((MaxY >= xRect.MinY) && (MinY <= xRect.MaxY)) )
    {
        return true;
    }
    else return false;
}

inline bool Asura_Bounding_Rectangle::Contains( const Asura_Vector_2& point) const
{
    if ((point.x>=MinX && point.x<=MaxX)
      &&(point.y>=MinY && point.y<=MaxY))
    {
        return true;
    }
    return false;
}

inline Asura_Vector_2 Asura_Bounding_Rectangle::CalculateCentre(void) const
{
	return Asura_Vector_2( (MinX + MaxX) * 0.5f, 
						   (MinY + MaxY) * 0.5f );
}

inline void Asura_Bounding_Rectangle::Displace( const Asura_Vector_2& xDisp )
{
	MinX += xDisp.x; 
	MaxX += xDisp.x; 
	MinY += xDisp.y; 
	MaxY += xDisp.y;	
}

// A S U R A _ B O U N D I N G _ B O X ///////////////////////////////////////
inline void Asura_Bounding_Box::Reset(void)
{
    // set to exaggeratedly large values
    MinX = Asura_Maths::LargeFloat;
    MinY = Asura_Maths::LargeFloat;
    MinZ = Asura_Maths::LargeFloat;

    MaxX = -Asura_Maths::LargeFloat;
    MaxY = -Asura_Maths::LargeFloat;
    MaxZ = -Asura_Maths::LargeFloat;
}

inline void Asura_Bounding_Box::Set(const class Asura_Vector_3& v)
{
    if (v.x > MaxX) MaxX = v.x;
    if (v.y > MaxY) MaxY = v.y;
    if (v.z > MaxZ) MaxZ = v.z;

    if (v.x < MinX) MinX = v.x;
    if (v.y < MinY) MinY = v.y;
    if (v.z < MinZ) MinZ = v.z;
}

inline void Asura_Bounding_Box::Set(const Asura_Bounding_Box& bb)
{
    if (bb.MaxX > MaxX) MaxX = bb.MaxX;
    if (bb.MaxY > MaxY) MaxY = bb.MaxY;
    if (bb.MaxZ > MaxZ) MaxZ = bb.MaxZ;

    if (bb.MinX < MinX) MinX = bb.MinX;
    if (bb.MinY < MinY) MinY = bb.MinY;
    if (bb.MinZ < MinZ) MinZ = bb.MinZ;
}

inline Asura_Vector_3 Asura_Bounding_Box::CalculateCentre(void) const
{
    return Asura_Vector_3( (MinX + MaxX) * 0.5f,
                           (MinY + MaxY) * 0.5f,
                           (MinZ + MaxZ) * 0.5f );
}

inline Asura_Vector_3 Asura_Bounding_Box::CalculateExtents( void ) const
{
    return Asura_Vector_3( MaxX - MinX, MaxY - MinY, MaxZ - MinZ );
}

inline float Asura_Bounding_Box::GetVolume(void) const 
{
    float x = MaxX-MinX;
    float y = MaxY-MinY;
    float z = MaxZ-MinZ;
    return x*y*z;
}

inline bool Asura_Bounding_Box::Intersects(const Asura_Bounding_Box& b) const
{
    if ( ((MaxX >= b.MinX) && (MinX <= b.MaxX))
      && ((MaxY >= b.MinY) && (MinY <= b.MaxY))
      && ((MaxZ >= b.MinZ) && (MinZ <= b.MaxZ)) )
    {
        return true;
    }
    else return false;
}


inline bool Asura_Bounding_Box::Intersects(const Asura_Bounding_Box& b, const Asura_Vector_3 & offset) const
{
    if ( ((MaxX >= b.MinX+offset.x) && (MinX <= b.MaxX+offset.x))
      && ((MaxY >= b.MinY+offset.y) && (MinY <= b.MaxY+offset.y))
      && ((MaxZ >= b.MinZ+offset.z) && (MinZ <= b.MaxZ+offset.z)) )
    {
        return true;
    }
    else return false;
}

inline bool Asura_Bounding_Box::IntersectsSphere(const Asura_Vector_3& centre, const float radius) const
{
    if ( ((MaxX>=centre.x-radius) && (MinX <= centre.x+radius))
      && ((MaxY>=centre.y-radius) && (MinY <= centre.y+radius))
      && ((MaxZ>=centre.z-radius) && (MinZ <= centre.z+radius)) )
    {
        return true;
    }
    else return false;
}

inline bool Asura_Bounding_Box::Contains(const Asura_Vector_3& point) const 
{
    if ((point.x>=MinX && point.x<=MaxX)
      &&(point.y>=MinY && point.y<=MaxY)
      &&(point.z>=MinZ && point.z<=MaxZ))
        return true;

    return false;

}

inline bool Asura_Bounding_Box::Contains(const Asura_Bounding_Box& b) const
{
    if ((b.MinX>=MinX && b.MaxX<=MaxX)
      &&(b.MinY>=MinY && b.MaxY<=MaxY)
      &&(b.MinZ>=MinZ && b.MaxZ<=MaxZ))
    {
        return true;
    }

    return false;
}

inline void Asura_Bounding_Box::Displace(const Asura_Vector_3& displacement)
{
    MaxX += displacement.x;
    MinX += displacement.x;
    MaxY += displacement.y;
    MinY += displacement.y;
    MaxZ += displacement.z;
    MinZ += displacement.z;
}

//
// Asura_Random.
//

inline float Asura_RandomGenerator::GetFloat( void )
{
    return( static_cast<int>(GetIntU()) / static_cast<float>(INT_MAX) );
}

inline float Asura_RandomGenerator::GetFloat( float fMin, float fMax )
{
    return( fMin + GetFloat() * (fMax - fMin) );
}

inline int Asura_RandomGenerator::GetInt( int iMin, int iMax )
{
    // Doing something like (iMin + GetFloat() * (iMax - iMin)) would
    // actually be faster but leads to gaps in the output with really large
    // ranges. While this probably won't ever be an issue, nor should the
    // performance, and so the more robust implementation is probably a 
    // better choice.
    return( iMin + GetIntU() % (iMax - iMin + 1) );
}

inline u_int Asura_RandomGenerator::GetIntU( u_int uMin, u_int uMax )
{
    // This is ok since unsigned range only goes up to INT_MAX as well.
    return GetInt( uMin, uMax );
}

//
// Asura_Complex.
//

inline Asura_Complex& Asura_Complex::operator*=( const Asura_Complex& xOther )
{
    // (a + ib) * (c + id)
    float fAC = m_fR * xOther.m_fR;
    float fAD = m_fR * xOther.m_fI;
    float fBC = m_fI * xOther.m_fR;
    float fBD = m_fI * xOther.m_fI;
    m_fR = fAC - fBD;
    m_fI = fAD + fBC;
    return *this;
}

inline Asura_Complex& Asura_Complex::operator+=( const Asura_Complex& xOther )
{
    m_fR += xOther.m_fR;
    m_fI += xOther.m_fI;
    return *this;
}

inline Asura_Complex& Asura_Complex::operator-=( const Asura_Complex& xOther )
{
    m_fR -= xOther.m_fR;
    m_fI -= xOther.m_fI;
    return *this;
}

inline Asura_Complex Asura_Complex::operator*( const Asura_Complex& xOther ) const
{
    return Asura_Complex( m_fR * xOther.m_fR - m_fI * xOther.m_fI, m_fR * xOther.m_fI + m_fI * xOther.m_fR );
}

inline Asura_Complex Asura_Complex::operator+( const Asura_Complex& xOther ) const
{
    return Asura_Complex( m_fR + xOther.m_fR, m_fI + xOther.m_fI );
}

inline Asura_Complex Asura_Complex::operator-( const Asura_Complex& xOther ) const
{
    return Asura_Complex( m_fR - xOther.m_fR, m_fI - xOther.m_fI );
}

#ifdef ASURA_USE_PLATFORM_VECTORS
#ifdef SPU
#include <vmx2spu.h>
#endif
#include "Core/Asura_PS3_VectorMaths.h"
#endif // #if ASURA_USE_PLATFORM_VECTORS


#endif   // ifndef __ASURA_PLATFORMMATHS_H__
/// End of file. ///
