//////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 1998 - 2001 Microsoft Corporation.  All Rights Reserved.
//
//  File:       xgmath.inl
//  Content:    XG math inline functions
//
//////////////////////////////////////////////////////////////////////////////

#ifndef __XGMATH_INL__
#define __XGMATH_INL__

#pragma warning(disable:4035)

//===========================================================================
//
// Inline Class Methods
//
//===========================================================================

#ifdef __cplusplus

#include <malloc.h>

//--------------------------
// 2D Vector
//--------------------------

XGINLINE
XGVECTOR2::XGVECTOR2( CONST FLOAT *pf )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pf != NULL);
#endif

#endif

    x = pf[0];
    y = pf[1];
}

XGINLINE
XGVECTOR2::XGVECTOR2( FLOAT fx, FLOAT fy )
{
    x = fx;
    y = fy;
}

// casting
XGINLINE
XGVECTOR2::operator FLOAT* ()
{
    return (FLOAT *) &x;
}

XGINLINE
XGVECTOR2::operator CONST FLOAT* () const
{
    return (CONST FLOAT *) &x;
}

// assignment operators
XGINLINE XGVECTOR2&
XGVECTOR2::operator += ( CONST XGVECTOR2& v )
{
    x += v.x;
    y += v.y;
    return *this;
}

XGINLINE XGVECTOR2&
XGVECTOR2::operator -= ( CONST XGVECTOR2& v )
{
    x -= v.x;
    y -= v.y;
    return *this;
}

XGINLINE XGVECTOR2&
XGVECTOR2::operator *= ( FLOAT f )
{
    x *= f;
    y *= f;
    return *this;
}

XGINLINE XGVECTOR2&
XGVECTOR2::operator /= ( FLOAT f )
{
    FLOAT fInv = 1.0f / f;
    x *= fInv;
    y *= fInv;
    return *this;
}

// unary operators
XGINLINE XGVECTOR2
XGVECTOR2::operator + () const
{
    return *this;
}

XGINLINE XGVECTOR2
XGVECTOR2::operator - () const
{
    return XGVECTOR2(-x, -y);
}

// binary operators
XGINLINE XGVECTOR2
XGVECTOR2::operator + ( CONST XGVECTOR2& v ) const
{
    return XGVECTOR2(x + v.x, y + v.y);
}

XGINLINE XGVECTOR2
XGVECTOR2::operator - ( CONST XGVECTOR2& v ) const
{
    return XGVECTOR2(x - v.x, y - v.y);
}

XGINLINE XGVECTOR2
XGVECTOR2::operator * ( FLOAT f ) const
{
    return XGVECTOR2(x * f, y * f);
}

XGINLINE XGVECTOR2
XGVECTOR2::operator / ( FLOAT f ) const
{
    FLOAT fInv = 1.0f / f;
    return XGVECTOR2(x * fInv, y * fInv);
}


XGINLINE XGVECTOR2
operator * ( FLOAT f, CONST XGVECTOR2& v )
{
    return XGVECTOR2(f * v.x, f * v.y);
}

XGINLINE BOOL
XGVECTOR2::operator == ( CONST XGVECTOR2& v ) const
{
    return x == v.x && y == v.y;
}

XGINLINE BOOL
XGVECTOR2::operator != ( CONST XGVECTOR2& v ) const
{
    return x != v.x || y != v.y;
}




//--------------------------
// 3D Vector
//--------------------------
XGINLINE
XGVECTOR3::XGVECTOR3( CONST FLOAT *pf )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pf != NULL);
#endif

#endif

    x = pf[0];
    y = pf[1];
    z = pf[2];
}

XGINLINE
XGVECTOR3::XGVECTOR3( CONST D3DVECTOR& v )
{
    x = v.x;
    y = v.y;
    z = v.z;
}

XGINLINE
XGVECTOR3::XGVECTOR3( FLOAT fx, FLOAT fy, FLOAT fz )
{
    x = fx;
    y = fy;
    z = fz;
}


// casting
XGINLINE
XGVECTOR3::operator FLOAT* ()
{
    return (FLOAT *) &x;
}

XGINLINE
XGVECTOR3::operator CONST FLOAT* () const
{
    return (CONST FLOAT *) &x;
}


// assignment operators
XGINLINE XGVECTOR3&
XGVECTOR3::operator += ( CONST XGVECTOR3& v )
{
    x += v.x;
    y += v.y;
    z += v.z;
    return *this;
}

XGINLINE XGVECTOR3&
XGVECTOR3::operator -= ( CONST XGVECTOR3& v )
{
    x -= v.x;
    y -= v.y;
    z -= v.z;
    return *this;
}

XGINLINE XGVECTOR3&
XGVECTOR3::operator *= ( FLOAT f )
{
    x *= f;
    y *= f;
    z *= f;
    return *this;
}

XGINLINE XGVECTOR3&
XGVECTOR3::operator /= ( FLOAT f )
{
    FLOAT fInv = 1.0f / f;
    x *= fInv;
    y *= fInv;
    z *= fInv;
    return *this;
}


// unary operators
XGINLINE XGVECTOR3
XGVECTOR3::operator + () const
{
    return *this;
}

XGINLINE XGVECTOR3
XGVECTOR3::operator - () const
{
    return XGVECTOR3(-x, -y, -z);
}


// binary operators
XGINLINE XGVECTOR3
XGVECTOR3::operator + ( CONST XGVECTOR3& v ) const
{
    return XGVECTOR3(x + v.x, y + v.y, z + v.z);
}

XGINLINE XGVECTOR3
XGVECTOR3::operator - ( CONST XGVECTOR3& v ) const
{
    return XGVECTOR3(x - v.x, y - v.y, z - v.z);
}

XGINLINE XGVECTOR3
XGVECTOR3::operator * ( FLOAT f ) const
{
    return XGVECTOR3(x * f, y * f, z * f);
}

XGINLINE XGVECTOR3
XGVECTOR3::operator / ( FLOAT f ) const
{
    FLOAT fInv = 1.0f / f;
    return XGVECTOR3(x * fInv, y * fInv, z * fInv);
}


XGINLINE XGVECTOR3
operator * ( FLOAT f, CONST struct XGVECTOR3& v )
{
    return XGVECTOR3(f * v.x, f * v.y, f * v.z);
}


XGINLINE BOOL
XGVECTOR3::operator == ( CONST XGVECTOR3& v ) const
{
    return x == v.x && y == v.y && z == v.z;
}

XGINLINE BOOL
XGVECTOR3::operator != ( CONST XGVECTOR3& v ) const
{
    return x != v.x || y != v.y || z != v.z;
}



//--------------------------
// 4D Vector
//--------------------------
XGINLINE
XGVECTOR4::XGVECTOR4( CONST FLOAT *pf )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pf != NULL);
#endif

#endif

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

XGINLINE
XGVECTOR4::XGVECTOR4( FLOAT fx, FLOAT fy, FLOAT fz, FLOAT fw )
{
    x = fx;
    y = fy;
    z = fz;
    w = fw;
}


// casting
XGINLINE
XGVECTOR4::operator FLOAT* ()
{
    return (FLOAT *) &x;
}

XGINLINE
XGVECTOR4::operator CONST FLOAT* () const
{
    return (CONST FLOAT *) &x;
}


// assignment operators
XGINLINE XGVECTOR4&
XGVECTOR4::operator += ( CONST XGVECTOR4& v )
{
    x += v.x;
    y += v.y;
    z += v.z;
    w += v.w;
    return *this;
}

XGINLINE XGVECTOR4&
XGVECTOR4::operator -= ( CONST XGVECTOR4& v )
{
    x -= v.x;
    y -= v.y;
    z -= v.z;
    w -= v.w;
    return *this;
}

XGINLINE XGVECTOR4&
XGVECTOR4::operator *= ( FLOAT f )
{
    x *= f;
    y *= f;
    z *= f;
    w *= f;
    return *this;
}

XGINLINE XGVECTOR4&
XGVECTOR4::operator /= ( FLOAT f )
{
    FLOAT fInv = 1.0f / f;
    x *= fInv;
    y *= fInv;
    z *= fInv;
    w *= fInv;
    return *this;
}


// unary operators
XGINLINE XGVECTOR4
XGVECTOR4::operator + () const
{
    return *this;
}

XGINLINE XGVECTOR4
XGVECTOR4::operator - () const
{
    return XGVECTOR4(-x, -y, -z, -w);
}


// binary operators
XGINLINE XGVECTOR4
XGVECTOR4::operator + ( CONST XGVECTOR4& v ) const
{
    return XGVECTOR4(x + v.x, y + v.y, z + v.z, w + v.w);
}

XGINLINE XGVECTOR4
XGVECTOR4::operator - ( CONST XGVECTOR4& v ) const
{
    return XGVECTOR4(x - v.x, y - v.y, z - v.z, w - v.w);
}

XGINLINE XGVECTOR4
XGVECTOR4::operator * ( FLOAT f ) const
{
    return XGVECTOR4(x * f, y * f, z * f, w * f);
}

XGINLINE XGVECTOR4
XGVECTOR4::operator / ( FLOAT f ) const
{
    FLOAT fInv = 1.0f / f;
    return XGVECTOR4(x * fInv, y * fInv, z * fInv, w * fInv);
}


XGINLINE XGVECTOR4
operator * ( FLOAT f, CONST XGVECTOR4& v )
{
    return XGVECTOR4(f * v.x, f * v.y, f * v.z, f * v.w);
}


XGINLINE BOOL
XGVECTOR4::operator == ( CONST XGVECTOR4& v ) const
{
    return x == v.x && y == v.y && z == v.z && w == v.w;
}

XGINLINE BOOL
XGVECTOR4::operator != ( CONST XGVECTOR4& v ) const
{
    return x != v.x || y != v.y || z != v.z || w != v.w;
}


//--------------------------
// Matrix
//--------------------------
XGINLINE
XGMATRIX::XGMATRIX( CONST FLOAT* pf )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pf != NULL);
#endif

#endif

    memcpy(&_11, pf, sizeof(XGMATRIX));
}

XGINLINE
XGMATRIX::XGMATRIX( CONST D3DMATRIX& mat )
{
    memcpy(&_11, &mat, sizeof(XGMATRIX));
}

XGINLINE
XGMATRIX::XGMATRIX( FLOAT f11, FLOAT f12, FLOAT f13, FLOAT f14,
                        FLOAT f21, FLOAT f22, FLOAT f23, FLOAT f24,
                        FLOAT f31, FLOAT f32, FLOAT f33, FLOAT f34,
                        FLOAT f41, FLOAT f42, FLOAT f43, FLOAT f44 )
{
    _11 = f11; _12 = f12; _13 = f13; _14 = f14;
    _21 = f21; _22 = f22; _23 = f23; _24 = f24;
    _31 = f31; _32 = f32; _33 = f33; _34 = f34;
    _41 = f41; _42 = f42; _43 = f43; _44 = f44;
}


// access grants
XGINLINE FLOAT&
XGMATRIX::operator () ( UINT iRow, UINT iCol )
{
    return m[iRow][iCol];
}

XGINLINE FLOAT
XGMATRIX::operator () ( UINT iRow, UINT iCol ) const
{
    return m[iRow][iCol];
}


// casting operators
XGINLINE
XGMATRIX::operator FLOAT* ()
{
    return (FLOAT *) &_11;
}

XGINLINE
XGMATRIX::operator CONST FLOAT* () const
{
    return (CONST FLOAT *) &_11;
}


// assignment operators
XGINLINE XGMATRIX&
XGMATRIX::operator *= ( CONST XGMATRIX& mat )
{
    XGMatrixMultiply(this, this, &mat);
    return *this;
}

XGINLINE XGMATRIX&
XGMATRIX::operator += ( CONST XGMATRIX& mat )
{
    _11 += mat._11; _12 += mat._12; _13 += mat._13; _14 += mat._14;
    _21 += mat._21; _22 += mat._22; _23 += mat._23; _24 += mat._24;
    _31 += mat._31; _32 += mat._32; _33 += mat._33; _34 += mat._34;
    _41 += mat._41; _42 += mat._42; _43 += mat._43; _44 += mat._44;
    return *this;
}

XGINLINE XGMATRIX&
XGMATRIX::operator -= ( CONST XGMATRIX& mat )
{
    _11 -= mat._11; _12 -= mat._12; _13 -= mat._13; _14 -= mat._14;
    _21 -= mat._21; _22 -= mat._22; _23 -= mat._23; _24 -= mat._24;
    _31 -= mat._31; _32 -= mat._32; _33 -= mat._33; _34 -= mat._34;
    _41 -= mat._41; _42 -= mat._42; _43 -= mat._43; _44 -= mat._44;
    return *this;
}

XGINLINE XGMATRIX&
XGMATRIX::operator *= ( FLOAT f )
{
    _11 *= f; _12 *= f; _13 *= f; _14 *= f;
    _21 *= f; _22 *= f; _23 *= f; _24 *= f;
    _31 *= f; _32 *= f; _33 *= f; _34 *= f;
    _41 *= f; _42 *= f; _43 *= f; _44 *= f;
    return *this;
}

XGINLINE XGMATRIX&
XGMATRIX::operator /= ( FLOAT f )
{
    FLOAT fInv = 1.0f / f;
    _11 *= fInv; _12 *= fInv; _13 *= fInv; _14 *= fInv;
    _21 *= fInv; _22 *= fInv; _23 *= fInv; _24 *= fInv;
    _31 *= fInv; _32 *= fInv; _33 *= fInv; _34 *= fInv;
    _41 *= fInv; _42 *= fInv; _43 *= fInv; _44 *= fInv;
    return *this;
}


// unary operators
XGINLINE XGMATRIX
XGMATRIX::operator + () const
{
    return *this;
}

XGINLINE XGMATRIX
XGMATRIX::operator - () const
{
    return XGMATRIX(-_11, -_12, -_13, -_14,
                      -_21, -_22, -_23, -_24,
                      -_31, -_32, -_33, -_34,
                      -_41, -_42, -_43, -_44);
}


// binary operators
XGINLINE XGMATRIX
XGMATRIX::operator * ( CONST XGMATRIX& mat ) const
{
    XGMATRIX matT;
    XGMatrixMultiply(&matT, this, &mat);
    return matT;
}

XGINLINE XGMATRIX
XGMATRIX::operator + ( CONST XGMATRIX& mat ) const
{
    return XGMATRIX(_11 + mat._11, _12 + mat._12, _13 + mat._13, _14 + mat._14,
                      _21 + mat._21, _22 + mat._22, _23 + mat._23, _24 + mat._24,
                      _31 + mat._31, _32 + mat._32, _33 + mat._33, _34 + mat._34,
                      _41 + mat._41, _42 + mat._42, _43 + mat._43, _44 + mat._44);
}

XGINLINE XGMATRIX
XGMATRIX::operator - ( CONST XGMATRIX& mat ) const
{
    return XGMATRIX(_11 - mat._11, _12 - mat._12, _13 - mat._13, _14 - mat._14,
                      _21 - mat._21, _22 - mat._22, _23 - mat._23, _24 - mat._24,
                      _31 - mat._31, _32 - mat._32, _33 - mat._33, _34 - mat._34,
                      _41 - mat._41, _42 - mat._42, _43 - mat._43, _44 - mat._44);
}

XGINLINE XGMATRIX
XGMATRIX::operator * ( FLOAT f ) const
{
    return XGMATRIX(_11 * f, _12 * f, _13 * f, _14 * f,
                      _21 * f, _22 * f, _23 * f, _24 * f,
                      _31 * f, _32 * f, _33 * f, _34 * f,
                      _41 * f, _42 * f, _43 * f, _44 * f);
}

XGINLINE XGMATRIX
XGMATRIX::operator / ( FLOAT f ) const
{
    FLOAT fInv = 1.0f / f;
    return XGMATRIX(_11 * fInv, _12 * fInv, _13 * fInv, _14 * fInv,
                      _21 * fInv, _22 * fInv, _23 * fInv, _24 * fInv,
                      _31 * fInv, _32 * fInv, _33 * fInv, _34 * fInv,
                      _41 * fInv, _42 * fInv, _43 * fInv, _44 * fInv);
}


XGINLINE XGMATRIX
operator * ( FLOAT f, CONST XGMATRIX& mat )
{
    return XGMATRIX(f * mat._11, f * mat._12, f * mat._13, f * mat._14,
                      f * mat._21, f * mat._22, f * mat._23, f * mat._24,
                      f * mat._31, f * mat._32, f * mat._33, f * mat._34,
                      f * mat._41, f * mat._42, f * mat._43, f * mat._44);
}


XGINLINE BOOL
XGMATRIX::operator == ( CONST XGMATRIX& mat ) const
{
    return 0 == memcmp(this, &mat, sizeof(XGMATRIX));
}

XGINLINE BOOL
XGMATRIX::operator != ( CONST XGMATRIX& mat ) const
{
    return 0 != memcmp(this, &mat, sizeof(XGMATRIX));
}



//--------------------------
// Quaternion
//--------------------------

XGINLINE
XGQUATERNION::XGQUATERNION( CONST FLOAT* pf )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pf != NULL);
#endif

#endif

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

XGINLINE
XGQUATERNION::XGQUATERNION( FLOAT fx, FLOAT fy, FLOAT fz, FLOAT fw )
{
    x = fx;
    y = fy;
    z = fz;
    w = fw;
}


// casting
XGINLINE
XGQUATERNION::operator FLOAT* ()
{
    return (FLOAT *) &x;
}

XGINLINE
XGQUATERNION::operator CONST FLOAT* () const
{
    return (CONST FLOAT *) &x;
}


// assignment operators
XGINLINE XGQUATERNION&
XGQUATERNION::operator += ( CONST XGQUATERNION& q )
{
    x += q.x;
    y += q.y;
    z += q.z;
    w += q.w;
    return *this;
}

XGINLINE XGQUATERNION&
XGQUATERNION::operator -= ( CONST XGQUATERNION& q )
{
    x -= q.x;
    y -= q.y;
    z -= q.z;
    w -= q.w;
    return *this;
}

XGINLINE XGQUATERNION&
XGQUATERNION::operator *= ( CONST XGQUATERNION& q )
{
    XGQuaternionMultiply(this, this, &q);
    return *this;
}

XGINLINE XGQUATERNION&
XGQUATERNION::operator *= ( FLOAT f )
{
    x *= f;
    y *= f;
    z *= f;
    w *= f;
    return *this;
}

XGINLINE XGQUATERNION&
XGQUATERNION::operator /= ( FLOAT f )
{
    FLOAT fInv = 1.0f / f;
    x *= fInv;
    y *= fInv;
    z *= fInv;
    w *= fInv;
    return *this;
}


// unary operators
XGINLINE XGQUATERNION
XGQUATERNION::operator + () const
{
    return *this;
}

XGINLINE XGQUATERNION
XGQUATERNION::operator - () const
{
    return XGQUATERNION(-x, -y, -z, -w);
}


// binary operators
XGINLINE XGQUATERNION
XGQUATERNION::operator + ( CONST XGQUATERNION& q ) const
{
    return XGQUATERNION(x + q.x, y + q.y, z + q.z, w + q.w);
}

XGINLINE XGQUATERNION
XGQUATERNION::operator - ( CONST XGQUATERNION& q ) const
{
    return XGQUATERNION(x - q.x, y - q.y, z - q.z, w - q.w);
}

XGINLINE XGQUATERNION
XGQUATERNION::operator * ( CONST XGQUATERNION& q ) const
{
    XGQUATERNION qT;
    XGQuaternionMultiply(&qT, this, &q);
    return qT;
}

XGINLINE XGQUATERNION
XGQUATERNION::operator * ( FLOAT f ) const
{
    return XGQUATERNION(x * f, y * f, z * f, w * f);
}

XGINLINE XGQUATERNION
XGQUATERNION::operator / ( FLOAT f ) const
{
    FLOAT fInv = 1.0f / f;
    return XGQUATERNION(x * fInv, y * fInv, z * fInv, w * fInv);
}


XGINLINE XGQUATERNION
operator * (FLOAT f, CONST XGQUATERNION& q )
{
    return XGQUATERNION(f * q.x, f * q.y, f * q.z, f * q.w);
}


XGINLINE BOOL
XGQUATERNION::operator == ( CONST XGQUATERNION& q ) const
{
    return x == q.x && y == q.y && z == q.z && w == q.w;
}

XGINLINE BOOL
XGQUATERNION::operator != ( CONST XGQUATERNION& q ) const
{
    return x != q.x || y != q.y || z != q.z || w != q.w;
}




//--------------------------
// Plane
//--------------------------

XGINLINE
XGPLANE::XGPLANE( CONST FLOAT* pf )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pf != NULL);
#endif

#endif

    a = pf[0];
    b = pf[1];
    c = pf[2];
    d = pf[3];
}

XGINLINE
XGPLANE::XGPLANE( FLOAT fa, FLOAT fb, FLOAT fc, FLOAT fd )
{
    a = fa;
    b = fb;
    c = fc;
    d = fd;
}


// casting
XGINLINE
XGPLANE::operator FLOAT* ()
{
    return (FLOAT *) &a;
}

XGINLINE
XGPLANE::operator CONST FLOAT* () const
{
    return (CONST FLOAT *) &a;
}


// unary operators
XGINLINE XGPLANE
XGPLANE::operator + () const
{
    return *this;
}

XGINLINE XGPLANE
XGPLANE::operator - () const
{
    return XGPLANE(-a, -b, -c, -d);
}


// binary operators
XGINLINE BOOL
XGPLANE::operator == ( CONST XGPLANE& p ) const
{
    return a == p.a && b == p.b && c == p.c && d == p.d;
}

XGINLINE BOOL
XGPLANE::operator != ( CONST XGPLANE& p ) const
{
    return a != p.a || b != p.b || c != p.c || d != p.d;
}




//--------------------------
// Color
//--------------------------

XGINLINE
XGCOLOR::XGCOLOR( DWORD dw )
{
    CONST FLOAT f = 1.0f / 255.0f;
    r = f * (FLOAT) (unsigned char) (dw >> 16);
    g = f * (FLOAT) (unsigned char) (dw >>  8);
    b = f * (FLOAT) (unsigned char) (dw >>  0);
    a = f * (FLOAT) (unsigned char) (dw >> 24);
}

XGINLINE
XGCOLOR::XGCOLOR( CONST FLOAT* pf )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pf != NULL);
#endif

#endif

    r = pf[0];
    g = pf[1];
    b = pf[2];
    a = pf[3];
}

XGINLINE
XGCOLOR::XGCOLOR( CONST D3DCOLORVALUE& c )
{
    r = c.r;
    g = c.g;
    b = c.b;
    a = c.a;
}

XGINLINE
XGCOLOR::XGCOLOR( FLOAT fr, FLOAT fg, FLOAT fb, FLOAT fa )
{
    r = fr;
    g = fg;
    b = fb;
    a = fa;
}


// casting
XGINLINE
XGCOLOR::operator DWORD () const
{
    FLOAT R = r >= 1.0f ? 0xff : r <= 0.0f ? 0x00 : (r * 255.0f + 0.5f);
    FLOAT G = g >= 1.0f ? 0xff : g <= 0.0f ? 0x00 : (g * 255.0f + 0.5f);
    FLOAT B = b >= 1.0f ? 0xff : b <= 0.0f ? 0x00 : (b * 255.0f + 0.5f);
    FLOAT A = a >= 1.0f ? 0xff : a <= 0.0f ? 0x00 : (a * 255.0f + 0.5f);

    __asm {
        cvtss2si eax, B

        cvtss2si edx, A
        shl edx, 24
        or eax, edx

        cvtss2si edx, R
        shl edx, 16
        or eax, edx

        cvtss2si edx, G
        shl edx, 8
        or eax, edx
    }
}


XGINLINE
XGCOLOR::operator FLOAT * ()
{
    return (FLOAT *) &r;
}

XGINLINE
XGCOLOR::operator CONST FLOAT * () const
{
    return (CONST FLOAT *) &r;
}


XGINLINE
XGCOLOR::operator D3DCOLORVALUE * ()
{
    return (D3DCOLORVALUE *) &r;
}

XGINLINE
XGCOLOR::operator CONST D3DCOLORVALUE * () const
{
    return (CONST D3DCOLORVALUE *) &r;
}


XGINLINE
XGCOLOR::operator D3DCOLORVALUE& ()
{
    return *((D3DCOLORVALUE *) &r);
}

XGINLINE
XGCOLOR::operator CONST D3DCOLORVALUE& () const
{
    return *((CONST D3DCOLORVALUE *) &r);
}


// assignment operators
XGINLINE XGCOLOR&
XGCOLOR::operator += ( CONST XGCOLOR& c )
{
    r += c.r;
    g += c.g;
    b += c.b;
    a += c.a;
    return *this;
}

XGINLINE XGCOLOR&
XGCOLOR::operator -= ( CONST XGCOLOR& c )
{
    r -= c.r;
    g -= c.g;
    b -= c.b;
    a -= c.a;
    return *this;
}

XGINLINE XGCOLOR&
XGCOLOR::operator *= ( FLOAT f )
{
    r *= f;
    g *= f;
    b *= f;
    a *= f;
    return *this;
}

XGINLINE XGCOLOR&
XGCOLOR::operator /= ( FLOAT f )
{
    FLOAT fInv = 1.0f / f;
    r *= fInv;
    g *= fInv;
    b *= fInv;
    a *= fInv;
    return *this;
}


// unary operators
XGINLINE XGCOLOR
XGCOLOR::operator + () const
{
    return *this;
}

XGINLINE XGCOLOR
XGCOLOR::operator - () const
{
    return XGCOLOR(-r, -g, -b, -a);
}


// binary operators
XGINLINE XGCOLOR
XGCOLOR::operator + ( CONST XGCOLOR& c ) const
{
    return XGCOLOR(r + c.r, g + c.g, b + c.b, a + c.a);
}

XGINLINE XGCOLOR
XGCOLOR::operator - ( CONST XGCOLOR& c ) const
{
    return XGCOLOR(r - c.r, g - c.g, b - c.b, a - c.a);
}

XGINLINE XGCOLOR
XGCOLOR::operator * ( FLOAT f ) const
{
    return XGCOLOR(r * f, g * f, b * f, a * f);
}

XGINLINE XGCOLOR
XGCOLOR::operator / ( FLOAT f ) const
{
    FLOAT fInv = 1.0f / f;
    return XGCOLOR(r * fInv, g * fInv, b * fInv, a * fInv);
}


XGINLINE XGCOLOR
operator * (FLOAT f, CONST XGCOLOR& c )
{
    return XGCOLOR(f * c.r, f * c.g, f * c.b, f * c.a);
}


XGINLINE BOOL
XGCOLOR::operator == ( CONST XGCOLOR& c ) const
{
    return r == c.r && g == c.g && b == c.b && a == c.a;
}

XGINLINE BOOL
XGCOLOR::operator != ( CONST XGCOLOR& c ) const
{
    return r != c.r || g != c.g || b != c.b || a != c.a;
}

#endif //__cplusplus

//===========================================================================
//
// Inline functions
//
//===========================================================================


//--------------------------
// 2D Vector
//--------------------------

XGINLINE FLOAT XGVec2Length
    ( CONST XGVECTOR2 *pV )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV != NULL);
#endif

#endif

    __asm {
        mov     edx, pV
        movups  xmm1, [edx]
        movaps  xmm2, xmm1

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 1h
        addps   xmm1, xmm0

        sqrtss  xmm1, xmm1
        movss  [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGVec2LengthSq
    ( CONST XGVECTOR2 *pV )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV != NULL);
#endif

#endif

    __asm {
        mov     edx, pV
        movups  xmm1, [edx]
        movaps  xmm2, xmm1

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 1h
        addps   xmm1, xmm0

        movss  [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGVec2Dot
    ( CONST XGVECTOR2 *pV1, CONST XGVECTOR2 *pV2 )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pV1
        movlps  xmm1, [edx]

        mov     ecx, pV2
        movlps  xmm2, [ecx]

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 1h
        addps   xmm1, xmm0

        movss  [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGVec2CCW
    ( CONST XGVECTOR2 *pV1, CONST XGVECTOR2 *pV2 )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV1 != NULL && pV2 != NULL);
#endif

#endif

    return pV1->x * pV2->y - pV1->y * pV2->x;
}

XGINLINE XGVECTOR2* XGVec2Add
    ( XGVECTOR2 *pOut, CONST XGVECTOR2 *pV1, CONST XGVECTOR2 *pV2 )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pV1
        movlps  xmm1, [edx]

        mov     ecx, pV2
        movlps  xmm2, [ecx]

        addps   xmm1, xmm2

        mov     eax, pOut
        movlps  [eax], xmm1
    }
}

XGINLINE XGVECTOR2* XGVec2Subtract
    ( XGVECTOR2 *pOut, CONST XGVECTOR2 *pV1, CONST XGVECTOR2 *pV2 )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pV1
        movlps  xmm1, [edx]

        mov     ecx, pV2
        movlps  xmm2, [ecx]

        subps   xmm1, xmm2

        mov     eax, pOut
        movlps  [eax], xmm1
    }
}

XGINLINE XGVECTOR2* XGVec2Minimize
    ( XGVECTOR2 *pOut, CONST XGVECTOR2 *pV1, CONST XGVECTOR2 *pV2 )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov      ecx, pV1
        mov      edx, pV2
        movlps   xmm0, [ecx]
        movlps   xmm1, [edx]
        minps    xmm0, xmm1
        mov      eax, pOut
        movlps   [eax], xmm0
    }
}

XGINLINE XGVECTOR2* XGVec2Maximize
    ( XGVECTOR2 *pOut, CONST XGVECTOR2 *pV1, CONST XGVECTOR2 *pV2 )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov      ecx, pV1
        mov      edx, pV2
        movlps   xmm0, [ecx]
        movlps   xmm1, [edx]
        maxps    xmm0, xmm1
        mov      eax, pOut
        movlps   [eax], xmm0
    }
}

XGINLINE XGVECTOR2* XGVec2Scale
    ( XGVECTOR2 *pOut, CONST XGVECTOR2 *pV, FLOAT s )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV != NULL);
#endif

#endif

    __asm {
        movss   xmm0, s
        shufps  xmm0, xmm0, 0h

        mov     ecx, pV
        movlps  xmm1, [ecx]

        mulps   xmm0, xmm1

        mov     eax, pOut
        movlps  [eax], xmm0
    }
}

XGINLINE XGVECTOR2* XGVec2Lerp
    ( XGVECTOR2 *pOut, CONST XGVECTOR2 *pV1, CONST XGVECTOR2 *pV2,
      FLOAT s )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        movss   xmm0, s
        shufps  xmm0, xmm0, 0h

        mov     ecx, pV1
        movlps  xmm1, [ecx]

        mov     edx, pV2
        movlps  xmm2, [edx]

        subps   xmm2, xmm1
        mulps   xmm0, xmm2

        addps   xmm0, xmm1

        mov     eax, pOut
        movlps  [eax], xmm0
    }
}


//--------------------------
// 3D Vector
//--------------------------

XGINLINE FLOAT XGVec3Length
    ( CONST XGVECTOR3 *pV )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV != NULL);
#endif

#endif

    __asm {
        mov     edx, pV
        movss   xmm1, [edx]
        movhps  xmm1, [edx+4]

        movaps  xmm2, xmm1

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 32h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 32h
        addps   xmm1, xmm0

        sqrtss  xmm1, xmm1
        movss   [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGVec3LengthSq
    ( CONST XGVECTOR3 *pV )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV != NULL);
#endif

#endif

    __asm {
        mov     edx, pV
        movss   xmm1, [edx]
        movhps  xmm1, [edx+4]

        movaps  xmm2, xmm1

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 32h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 32h
        addps   xmm1, xmm0

        movss   [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGVec3Dot
    ( CONST XGVECTOR3 *pV1, CONST XGVECTOR3 *pV2 )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pV1
        movss   xmm1, [edx]
        movhps  xmm1, [edx+4]

        mov     edx, pV2
        movss   xmm2, [edx]
        movhps  xmm2, [edx+4]

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 32h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 32h
        addps   xmm1, xmm0

        movss   [res], xmm1
    }

    return res;
}

XGINLINE XGVECTOR3* XGVec3Cross
    ( XGVECTOR3 *pOut, CONST XGVECTOR3 *pV1, CONST XGVECTOR3 *pV2 )
{
    XGVECTOR3 v;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    v.x = pV1->y * pV2->z - pV1->z * pV2->y;
    v.y = pV1->z * pV2->x - pV1->x * pV2->z;
    v.z = pV1->x * pV2->y - pV1->y * pV2->x;

    *pOut = v;
    return pOut;
}

XGINLINE XGVECTOR3* XGVec3Add
    ( XGVECTOR3 *pOut, CONST XGVECTOR3 *pV1, CONST XGVECTOR3 *pV2 )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov      ecx, pV1
        movss    xmm0, [ecx]
        movhps   xmm0, [ecx+4]

        mov      edx, pV2
        movss    xmm1, [edx]
        movhps   xmm1, [edx+4]

        addps    xmm0, xmm1

        mov      eax, pOut
        movss    [eax], xmm0
        movhps   [eax+4], xmm0
    }
}

XGINLINE XGVECTOR3* XGVec3Subtract
    ( XGVECTOR3 *pOut, CONST XGVECTOR3 *pV1, CONST XGVECTOR3 *pV2 )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov      ecx, pV1
        movss    xmm0, [ecx]
        movhps   xmm0, [ecx+4]

        mov      edx, pV2
        movss    xmm1, [edx]
        movhps   xmm1, [edx+4]

        subps    xmm0, xmm1

        mov      eax, pOut
        movss    [eax], xmm0
        movhps   [eax+4], xmm0
    }
}

XGINLINE XGVECTOR3* XGVec3Minimize
    ( XGVECTOR3 *pOut, CONST XGVECTOR3 *pV1, CONST XGVECTOR3 *pV2 )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov      ecx, pV1
        movss    xmm0, [ecx]
        movhps   xmm0, [ecx+4]

        mov      edx, pV2
        movss    xmm1, [edx]
        movhps   xmm1, [edx+4]

        minps    xmm0, xmm1

        mov      eax, pOut
        movss    [eax], xmm0
        movhps   [eax+4], xmm0
    }
}

XGINLINE XGVECTOR3* XGVec3Maximize
    ( XGVECTOR3 *pOut, CONST XGVECTOR3 *pV1, CONST XGVECTOR3 *pV2 )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov      ecx, pV1
        movss    xmm0, [ecx]
        movhps   xmm0, [ecx+4]

        mov      edx, pV2
        movss    xmm1, [edx]
        movhps   xmm1, [edx+4]

        maxps    xmm0, xmm1

        mov      eax, pOut
        movss    [eax], xmm0
        movhps   [eax+4], xmm0
    }
}

XGINLINE XGVECTOR3* XGVec3Scale
    ( XGVECTOR3 *pOut, CONST XGVECTOR3 *pV, FLOAT s)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV != NULL);
#endif

#endif

    __asm {
        movss    xmm0, s
        shufps   xmm0, xmm0, 0h

        mov      edx, pV
        movss    xmm1, [edx]
        movhps   xmm1, [edx+4]

        mulps    xmm0, xmm1

        mov      eax, pOut
        movss    [eax], xmm0
        movhps   [eax+4], xmm0
    }
}

XGINLINE XGVECTOR3* XGVec3Lerp
    ( XGVECTOR3 *pOut, CONST XGVECTOR3 *pV1, CONST XGVECTOR3 *pV2,
      FLOAT s )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov      ecx, pV1
        movss    xmm1, [ecx]
        movhps   xmm1, [ecx+4]

        mov      edx, pV2
        movss    xmm2, [edx]
        movhps   xmm2, [edx+4]

        subps    xmm2, xmm1

        movss    xmm0, s
        shufps   xmm0, xmm0, 0h

        mulps    xmm0, xmm2
        
        addps    xmm0, xmm1

        mov      eax, pOut
        movss    [eax], xmm0
        movhps   [eax+4], xmm0
    }
}


//--------------------------
// 4D Vector
//--------------------------

XGINLINE FLOAT XGVec4Length
    ( CONST XGVECTOR4 *pV )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV != NULL);
#endif

#endif

    __asm {
        mov     edx, pV
        movups  xmm1, [edx]
        movaps  xmm2, xmm1

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        sqrtss  xmm1, xmm1
        movss  [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGVec4LengthSq
    ( CONST XGVECTOR4 *pV )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV != NULL);
#endif

#endif

    __asm {
        mov     edx, pV
        movups  xmm1, [edx]
        movaps  xmm2, xmm1

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        movss  [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGVec4Dot
    ( CONST XGVECTOR4 *pV1, CONST XGVECTOR4 *pV2 )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pV1
        movups  xmm1, [edx]

        mov     ecx, pV2
        movups  xmm2, [ecx]

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        movss  [res], xmm1
    }

    return res;
}

XGINLINE XGVECTOR4* XGVec4Add
    ( XGVECTOR4 *pOut, CONST XGVECTOR4 *pV1, CONST XGVECTOR4 *pV2)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pV1
        movups  xmm1, [edx]

        mov     ecx, pV2
        movups  xmm2, [ecx]

        addps   xmm1, xmm2

        mov     eax, pOut
        movups  [eax], xmm1
    }
}

XGINLINE XGVECTOR4* XGVec4Subtract
    ( XGVECTOR4 *pOut, CONST XGVECTOR4 *pV1, CONST XGVECTOR4 *pV2)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pV1
        movups  xmm1, [edx]

        mov     ecx, pV2
        movups  xmm2, [ecx]

        subps   xmm1, xmm2

        mov     eax, pOut
        movups  [eax], xmm1
    }
}

XGINLINE XGVECTOR4* XGVec4Minimize
    ( XGVECTOR4 *pOut, CONST XGVECTOR4 *pV1, CONST XGVECTOR4 *pV2)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov      ecx, pV1
        mov      edx, pV2
        movups   xmm0, [ecx]
        movups   xmm1, [edx]
        minps    xmm0, xmm1
        mov      eax, pOut
        movups   [eax], xmm0
    }
}

XGINLINE XGVECTOR4* XGVec4Maximize
    ( XGVECTOR4 *pOut, CONST XGVECTOR4 *pV1, CONST XGVECTOR4 *pV2)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        mov      ecx, pV1
        mov      edx, pV2
        movups   xmm0, [ecx]
        movups   xmm1, [edx]
        maxps    xmm0, xmm1
        mov      eax, pOut
        movups   [eax], xmm0
    }
}

XGINLINE XGVECTOR4* XGVec4Scale
    ( XGVECTOR4 *pOut, CONST XGVECTOR4 *pV, FLOAT s)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV);
#endif

#endif

    __asm {
        movss   xmm0, s
        shufps  xmm0, xmm0, 0h

        mov     ecx, pV
        movups  xmm1, [ecx]

        mulps   xmm0, xmm1

        mov     eax, pOut
        movups  [eax], xmm0
    }
}

XGINLINE XGVECTOR4* XGVec4Lerp
    ( XGVECTOR4 *pOut, CONST XGVECTOR4 *pV1, CONST XGVECTOR4 *pV2,
      FLOAT s )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pV1 != NULL && pV2 != NULL);
#endif

#endif

    __asm {
        movss   xmm0, s
        shufps  xmm0, xmm0, 0h

        mov     ecx, pV1
        movups  xmm1, [ecx]

        mov     edx, pV2
        movups  xmm2, [edx]

        subps   xmm2, xmm1
        mulps   xmm0, xmm2

        addps   xmm0, xmm1

        mov     eax, pOut
        movups  [eax], xmm0
    }
}


//--------------------------
// 4D Matrix
//--------------------------

XGINLINE XGMATRIX* XGMatrixIdentity
    ( XGMATRIX *pOut )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL);
#endif

#endif

    pOut->m[0][1] = pOut->m[0][2] = pOut->m[0][3] =
    pOut->m[1][0] = pOut->m[1][2] = pOut->m[1][3] =
    pOut->m[2][0] = pOut->m[2][1] = pOut->m[2][3] =
    pOut->m[3][0] = pOut->m[3][1] = pOut->m[3][2] = 0.0f;

    pOut->m[0][0] = pOut->m[1][1] = pOut->m[2][2] = pOut->m[3][3] = 1.0f;
    return pOut;
}


XGINLINE BOOL XGMatrixIsIdentity
    ( CONST XGMATRIX *pM )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pM != NULL);
#endif

#endif

    return pM->m[0][0] == 1.0f && pM->m[0][1] == 0.0f && pM->m[0][2] == 0.0f && pM->m[0][3] == 0.0f &&
           pM->m[1][0] == 0.0f && pM->m[1][1] == 1.0f && pM->m[1][2] == 0.0f && pM->m[1][3] == 0.0f &&
           pM->m[2][0] == 0.0f && pM->m[2][1] == 0.0f && pM->m[2][2] == 1.0f && pM->m[2][3] == 0.0f &&
           pM->m[3][0] == 0.0f && pM->m[3][1] == 0.0f && pM->m[3][2] == 0.0f && pM->m[3][3] == 1.0f;
}


//--------------------------
// Quaternion
//--------------------------

XGINLINE FLOAT XGQuaternionLength
    ( CONST XGQUATERNION *pQ )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pQ != NULL);
#endif

#endif

    __asm {
        mov     edx, pQ
        movups  xmm1, [edx]
        movaps  xmm2, xmm1

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        sqrtss  xmm1, xmm1
        movss  [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGQuaternionLengthSq
    ( CONST XGQUATERNION *pQ )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pQ != NULL);
#endif

#endif
    
    __asm {
        mov     edx, pQ
        movups  xmm1, [edx]
        movaps  xmm2, xmm1

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        movss  [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGQuaternionDot
    ( CONST XGQUATERNION *pQ1, CONST XGQUATERNION *pQ2 )
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pQ1 != NULL && pQ2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pQ1
        movups  xmm1, [edx]

        mov     ecx, pQ2
        movups  xmm2, [ecx]

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        movss  [res], xmm1
    }

    return res;
}

XGINLINE XGQUATERNION* XGQuaternionIdentity
    ( XGQUATERNION *pOut )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL);
#endif

#endif

    pOut->x = pOut->y = pOut->z = 0.0f;
    pOut->w = 1.0f;
    return pOut;
}

XGINLINE BOOL XGQuaternionIsIdentity
    ( CONST XGQUATERNION *pQ )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pQ != NULL);
#endif

#endif

    return pQ->x == 0.0f && pQ->y == 0.0f && pQ->z == 0.0f && pQ->w == 1.0f;
}


XGINLINE XGQUATERNION* XGQuaternionConjugate
    ( XGQUATERNION *pOut, CONST XGQUATERNION *pQ )
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pQ != NULL);
#endif

#endif

    pOut->x = -pQ->x;
    pOut->y = -pQ->y;
    pOut->z = -pQ->z;
    pOut->w =  pQ->w;
    return pOut;
}

//--------------------------
// Plane
//--------------------------

XGINLINE FLOAT XGPlaneDot
    ( CONST XGPLANE *pP, CONST XGVECTOR4 *pV)
{
    FLOAT res;

#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pP != NULL && pV != NULL);
#endif

#endif

    __asm {
        mov     edx, pP
        movups  xmm1, [edx]

        mov     ecx, pV
        movups  xmm2, [ecx]

        mulps   xmm1, xmm2

        movaps  xmm0, xmm1

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        shufps  xmm0, xmm0, 93h
        addps   xmm1, xmm0

        movss  [res], xmm1
    }

    return res;
}

XGINLINE FLOAT XGPlaneDotCoord
    ( CONST XGPLANE *pP, CONST XGVECTOR3 *pV)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pP != NULL && pV != NULL);
#endif

#endif

    return pP->a * pV->x + pP->b * pV->y + pP->c * pV->z + pP->d;
}

XGINLINE FLOAT XGPlaneDotNormal
    ( CONST XGPLANE *pP, CONST XGVECTOR3 *pV)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pP != NULL && pV != NULL);
#endif

#endif

    return pP->a * pV->x + pP->b * pV->y + pP->c * pV->z;
}


//--------------------------
// Color
//--------------------------

XGINLINE XGCOLOR* XGColorNegative
    (XGCOLOR *pOut, CONST XGCOLOR *pC)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pC != NULL);
#endif

#endif

    pOut->r = 1.0f - pC->r;
    pOut->g = 1.0f - pC->g;
    pOut->b = 1.0f - pC->b;
    pOut->a = pC->a;
    return pOut;
}

XGINLINE XGCOLOR* XGColorAdd
    (XGCOLOR *pOut, CONST XGCOLOR *pC1, CONST XGCOLOR *pC2)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pC1 != NULL && pC2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pC1
        movups  xmm1, [edx]

        mov     ecx, pC2
        movups  xmm2, [ecx]

        addps   xmm1, xmm2

        mov     eax, pOut
        movups  [eax], xmm1
    }
}

XGINLINE XGCOLOR* XGColorSubtract
    (XGCOLOR *pOut, CONST XGCOLOR *pC1, CONST XGCOLOR *pC2)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pC1 != NULL && pC2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pC1
        movups  xmm1, [edx]

        mov     ecx, pC2
        movups  xmm2, [ecx]

        subps   xmm1, xmm2

        mov     eax, pOut
        movups  [eax], xmm1
    }
}

XGINLINE XGCOLOR* XGColorScale
    (XGCOLOR *pOut, CONST XGCOLOR *pC, FLOAT s)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pC != NULL);
#endif

#endif

    __asm {
        movss   xmm0, s
        shufps  xmm0, xmm0, 0h

        mov     ecx, pC
        movups  xmm1, [ecx]

        mulps   xmm0, xmm1

        mov     eax, pOut
        movups  [eax], xmm0
    }
}

XGINLINE XGCOLOR* XGColorModulate
    (XGCOLOR *pOut, CONST XGCOLOR *pC1, CONST XGCOLOR *pC2)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pC1 != NULL && pC2 != NULL);
#endif

#endif

    __asm {
        mov     edx, pC1
        movups  xmm1, [edx]

        mov     ecx, pC2
        movups  xmm2, [ecx]

        mulps   xmm1, xmm2

        mov     eax, pOut
        movups  [eax], xmm1
    }
}

XGINLINE XGCOLOR* XGColorLerp
    (XGCOLOR *pOut, CONST XGCOLOR *pC1, CONST XGCOLOR *pC2, FLOAT s)
{
#ifdef _DEBUG

#ifdef ASSERT
    ASSERT(pOut != NULL && pC1 != NULL && pC2 != NULL);
#endif

#endif

    __asm {
        movss   xmm0, s
        shufps  xmm0, xmm0, 0h

        mov     ecx, pC1
        movups  xmm1, [ecx]

        mov     edx, pC2
        movups  xmm2, [edx]

        subps   xmm2, xmm1
        mulps   xmm0, xmm2

        addps   xmm0, xmm1

        mov     eax, pOut
        movups  [eax], xmm0
    }
}

#pragma warning(default:4035)

#endif // __XG8MATH_INL__
