#include "StdAfx.h"
#include "EVector.h"

#include "EMath.h"
#include "math.h"

///////////////////////////////////////////////////////////////////////////////

/**
 * \brief Constructs a 4-vector; no initialization is done, for speed
 * \return 
 */
CEVector4::CEVector4()
{
	
}

/**
 * \return 
 */
CEVector4::~CEVector4()
{
}

/**
 * \brief Copy constructor
 * \param val Vector to copy
 * \return 
 */
CEVector4::CEVector4(const CEVector4& val)
{
	x = val.x; 
	y = val.y; 
	z = val.z; 
	w = val.w; 
}

/**
 * \brief Constructs a vector from components
 * \param valX x component
 * \param valY y component
 * \param valZ z component
 * \param valW w component
 * \return 
 */
CEVector4::CEVector4(GLfloat valX, GLfloat valY, GLfloat valZ, GLfloat valW)
{ 
	x = valX; 
	y = valY; 
	z = valZ; 
	w = valW; 
}

/**
 * \brief constructs a vector from an array of components
 * \param *val pointer to array of components, GLfloat[4]
 * \return 
 */
CEVector4::CEVector4(GLfloat *val) 
{ 
	x = val[0]; 
	y = val[1]; 
	z = val[2]; 
	w = val[3]; 
}


/**
 * \brief Sets components from individual components
 * \param valX x component
 * \param valY y component
 * \param valZ z component
 * \param valW w component
 */
void CEVector4::Set(GLfloat valX, GLfloat valY, GLfloat valZ, GLfloat valW)
{ 
	x = valX; 
	y = valY; 
	z = valZ; 
	w = valW; 
}

/**
 * \brief Sets components from array of components
 * \param *val pointer to array of components, GLfloat[4]
 */
void CEVector4::Set(GLfloat *val) 
{ 
	x = val[0]; 
	y = val[1]; 
	z = val[2]; 
	w = val[3]; 
}

// operators
/**
 * \brief assignment
 * \param val vector to assign
 * \return 
 */
CEVector4& CEVector4::operator=(const CEVector4& val)
{ 
	x = val.x;
	y = val.y;
	z = val.z;
	w = val.w;
	return *this;
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector4 CEVector4::operator-(const CEVector4& val) const
{ 
	return CEVector4( x - val.x, y - val.y, z - val.z, w - val.w ); 
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector4& CEVector4::operator-=(const GLfloat val) 
{ 
	x -= val;
	y -= val;
	z -= val;
	w -= val;
	return *this; 
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector4 CEVector4::operator+(const CEVector4& val)  const
{ 
	return CEVector4( x + val.x, y + val.y, z + val.z, w + val.w ); 
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector4& CEVector4::operator+=(const GLfloat val) 
{ 
	x += val;
	y += val;
	z += val;
	w += val;
	return *this; 
}

/**
 * 
 * \param scalar 
 * \return 
 */
CEVector4 CEVector4::operator*(const GLfloat scalar)  const
{ 
	return CEVector4( x * scalar, y * scalar, z * scalar, w * scalar ); 
}

/**
 * 
 * \param scalar 
 * \return 
 */
CEVector4& CEVector4::operator*=(const GLfloat scalar) 
{ 
	x *= scalar;
	y *= scalar;
	z *= scalar;
	w *= scalar;

	return *this; 
}

/**
 * \note checks for divide-by-zero
 * \param scalar 
 * \return 
 */
CEVector4 CEVector4::operator/(const GLfloat scalar)  const
{ 
	if ( scalar != 0.0f )
		return CEVector4( x / scalar, y / scalar, z / scalar, w / scalar ); 
	else
		return CEVector4( 0.0f, 0.0f, 0.0f, 0.0f );
}

/**
 * 
 * \param scalar 
 * \return 
 */
CEVector4& CEVector4::operator/=(const GLfloat scalar) 
{ 
	if ( scalar != 0.0f )
	{
		x /= scalar;
		y /= scalar;
		z /= scalar;
		w /= scalar;
	}

	return *this; 
}

// equality operators
/**
 * 
 * \param val 
 * \return 
*/
bool CEVector4::operator==(const CEVector4& val) const
{
	return ( (x == val.x) && (y == val.y) && (z == val.z) && (w == val.w) );
}

/**
 * 
 * \param val 
 * \return 
 */
bool CEVector4::operator!=(const CEVector4& val) const
{
	return ( (x != val.x) || (y != val.y) || (z != val.z) || (w != val.w) );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector4::operator>=(const CEVector4& val) const
{
	return ( Length() >= val.Length() );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector4::operator<=(const CEVector4& val) const
{
	return ( Length() <= val.Length() );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector4::operator>(const CEVector4& val) const
{
	return ( Length() > val.Length() );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector4::operator<(const CEVector4& val) const
{
	return ( Length() < val.Length() );
}


// pseudo-operators
/**
 * \brief Multiplies each component by a scalar
 * \param scalar 
 */
void CEVector4::Scale(GLfloat scalar) 
{ 
	x *= scalar; 
	y *= scalar; 
	z *= scalar; 
	w *= scalar; 
}

// casting operators
/**
 * \brief operator to access individual component
 * \param i component to access
 * \return component
 * \warning assumes no virtual functions and data is packed in a 4*sizeof(GLfloat) memory block
 */
GLfloat& CEVector4::operator[] (int i) const
{
    return ((GLfloat*)this)[i];
}

/**
 * \brief casts to array of GLfloat[4]
 * \return pointer to array of GLfloat[4]
 * \warning assumes no virtual functions and data is packed in a 4*sizeof(GLfloat) memory block
 */
CEVector4::operator GLfloat* ()
{
    return (GLfloat*)this;
}


// operations
/**
 * \brief Computes length of vector
 * \return Length
 */
GLfloat CEVector4::Length() const
{
	return (GLfloat)sqrt( x*x + y*y + z*z + w*w );
}

/**
 * \brief Computes dot product of this vector and another
 * \param val other vector
 * \return Dot product
 * \warning Does this even make sense for a 4-vector? 
 */
GLfloat CEVector4::Dot(const CEVector4& val)
{
	return ( x*val.x + y*val.y + z*val.z + w*val.w );
}

/**
 * \brief Computes cross product of this vector and another vector
 * \param val other vector
 * \return Cross product
 * \warning This is not a real 4-vector cross product
 */
CEVector4 CEVector4::Cross(const CEVector4& val)
{
	return CEVector4( y*val.z-z*val.y, z*val.x-x*val.z, x*val.y-y*val.x, 0.0f);
}

/**
 * \brief Normalizes (unitizes) a vector
 */
void CEVector4::Normalize()
{
	GLfloat len = Length();

	if (len > 0.0f)
	{
		GLfloat invlength = 1.0f / len;

		x *= invlength;
		y *= invlength;
		z *= invlength;
		w *= invlength;
	}
}

/**
 * \brief Gets a normalized (unitized) version of the vector
 * \return Normalized vector, CEVector4
 */
CEVector4 CEVector4::GetNormalized()
{
	GLfloat len = Length();

	if (len > 0.0f)
	{
		GLfloat invlength = 1.0f / len;

		return CEVector4( x *= invlength, y *= invlength, z *= invlength, w *= invlength );
	} // if (len > 0.0f){
	else
		return CEVector4(0.0f, 0.0f, 0.0f, 0.0f);
}



///////////////////////////////////////////////////////////////////////////////

/**
 * \brief Constructs a 3-vector; no initialization is done, for speed
 * \return 
 */
CEVector3::CEVector3()
{
	
}

/**
 * \return 
 */
CEVector3::~CEVector3()
{
}

/**
 * \brief Copy constructor
 * \param val Vector to copy
 * \return 
 */
CEVector3::CEVector3(const CEVector3& val)
{
	x = val.x; 
	y = val.y; 
	z = val.z; 
}

/**
 * \brief Constructs a vector from components
 * \param valX x component
 * \param valY y component
 * \param valZ z component
 * \return 
 */
CEVector3::CEVector3(GLfloat valX, GLfloat valY, GLfloat valZ)
{ 
	x = valX; 
	y = valY; 
	z = valZ; 
}

/**
 * \brief constructs a vector from an array of components
 * \param *val pointer to array of components, GLfloat[3]
 * \return 
 */
CEVector3::CEVector3(GLfloat *val) 
{ 
	x = val[0]; 
	y = val[1]; 
	z = val[2]; 
}


/**
 * \brief Sets components from individual components
 * \param valX x component
 * \param valY y component
 * \param valZ z component
 */
void CEVector3::Set(GLfloat valX, GLfloat valY, GLfloat valZ)
{ 
	x = valX; 
	y = valY; 
	z = valZ; 
}

/**
 * \brief Sets components from array of components
 * \param *val pointer to array of components, GLfloat[3]
 */
void CEVector3::Set(GLfloat *val) 
{ 
	x = val[0]; 
	y = val[1]; 
	z = val[2]; 
}

// operators
/**
 * \brief assignment
 * \param val vector to assign
 * \return 
 */
CEVector3& CEVector3::operator=(const CEVector3& val)
{ 
	x = val.x;
	y = val.y;
	z = val.z;
	return *this;
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector3 CEVector3::operator-(const CEVector3& val) const
{ 
	return CEVector3( x - val.x, y - val.y, z - val.z ); 
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector3& CEVector3::operator-=(const GLfloat val) 
{ 
	x -= val;
	y -= val;
	z -= val;
	return *this; 
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector3 CEVector3::operator+(const CEVector3& val) const
{ 
	return CEVector3( x + val.x, y + val.y, z + val.z ); 
}

CEVector3 CEVector3::operator+(const GLfloat val) const
{ 
	return CEVector3( x + val, y + val, z + val ); 
}


/**
 * 
 * \param val 
 * \return 
 */
CEVector3& CEVector3::operator+=(const GLfloat val) 
{ 
	x += val;
	y += val;
	z += val;
	return *this; 
}

/**
 * 
 * \param scalar 
 * \return 
 */
CEVector3 CEVector3::operator*(const GLfloat scalar) const
{ 
	return CEVector3( x * scalar, y * scalar, z * scalar ); 
}

/**
 * 
 * \param scalar 
 * \return 
 */
CEVector3& CEVector3::operator*=(const GLfloat scalar) 
{ 
	x *= scalar;
	y *= scalar;
	z *= scalar;

	return *this; 
}

/**
 * \note checks for divide-by-zero
 * \param scalar 
 * \return 
 */
CEVector3 CEVector3::operator/(const GLfloat scalar) const
{ 
	if ( scalar != 0.0f )
		return CEVector3( x / scalar, y / scalar, z / scalar ); 
	else
		return CEVector3( 0.0f, 0.0f, 0.0f );
}

/**
 * 
 * \param scalar 
 * \return 
 */
CEVector3& CEVector3::operator/=(const GLfloat scalar) 
{ 
	if ( scalar != 0.0f )
	{
		x /= scalar;
		y /= scalar;
		z /= scalar;
	}

	return *this; 
}

// equality operators
/**
 * 
 * \param val 
 * \return 
*/
bool CEVector3::operator==(const CEVector3& val) const
{
	return ( (x == val.x) && (y == val.y) && (z == val.z) );
}

/**
 * 
 * \param val 
 * \return 
 */
bool CEVector3::operator!=(const CEVector3& val) const
{
	return ( (x != val.x) || (y != val.y) || (z != val.z) );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector3::operator>=(const CEVector3& val) const
{
	return ( Length() >= val.Length() );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector3::operator<=(const CEVector3& val) const
{
	return ( Length() <= val.Length() );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector3::operator>(const CEVector3& val) const
{
	return ( Length() > val.Length() );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector3::operator<(const CEVector3& val) const
{
	return ( Length() < val.Length() );
}


// pseudo-operators
/**
 * \brief Multiplies each component by a scalar
 * \param scalar 
 */
void CEVector3::Scale(GLfloat scalar) 
{ 
	x *= scalar; 
	y *= scalar; 
	z *= scalar; 
}

/**
 * \brief Rotates a point around another point given an axis of rotation
 * \param axis of rotation
 * \param pt point to rotate around
 */
void CEVector3::RotateAboutPoint(const float angle, CEVector3 axis, const CEVector3& pt)
{
	GLfloat costheta,sintheta,theta;
	theta = EDeg2Rad(angle);
	CEVector3 result;	
	result.Set( 0, 0, 0 );

	CEVector3 naxis = axis.GetNormalized();

	costheta = (GLfloat)cos(theta);
	sintheta = (GLfloat)sin(theta);

	result.x += (costheta + (1 - costheta) * naxis.x * naxis.x) * x;
	result.x += ((1 - costheta) * naxis.x * naxis.y - naxis.z * sintheta) * y;
	result.x += ((1 - costheta) * naxis.x * naxis.z + naxis.y * sintheta) * z;

	result.y += ((1 - costheta) * naxis.x * naxis.y + naxis.z * sintheta) * x;
	result.y += (costheta + (1 - costheta) * naxis.y * naxis.y) * y;
	result.y += ((1 - costheta) * naxis.y * naxis.z - naxis.x * sintheta) * z;

	result.z += ((1 - costheta) * naxis.x * naxis.z - naxis.y * sintheta) * x;
	result.z += ((1 - costheta) * naxis.y * naxis.z + naxis.x * sintheta) * y;
	result.z += (costheta + (1 - costheta) * naxis.z * naxis.z) * z;

	Set( result.x, result.z, result.z );
}

// casting operators
/**
 * \brief operator to access individual component
 * \param i component to access
 * \return component
 * \warning assumes no virtual functions and data is packed in a 3*sizeof(GLfloat) memory block
 */
GLfloat& CEVector3::operator[] (int i) const
{
    return ((GLfloat*)this)[i];
}

/**
 * \brief casts to array of GLfloat[3]
 * \return pointer to array of GLfloat[3]
 * \warning assumes no virtual functions and data is packed in a 3*sizeof(GLfloat) memory block
 */
CEVector3::operator GLfloat* ()
{
    return (GLfloat*)this;
}


// operations
/**
 * \brief Computes length of vector
 * \return Length
 */
GLfloat CEVector3::Length() const
{
	return (GLfloat)sqrt( x*x + y*y + z*z );
}

/**
 * \brief Computes dot product of this vector and another
 * \param val other vector
 * \return Dot product
 */
GLfloat CEVector3::Dot(const CEVector3& val)
{
	return ( x*val.x + y*val.y + z*val.z );
}

/**
 * \brief Computes cross product of this vector and another vector
 * \param val other vector
 * \return Cross product
 */
CEVector3 CEVector3::Cross(const CEVector3& val)
{
	return CEVector3( y*val.z-z*val.y, z*val.x-x*val.z, x*val.y-y*val.x );
}

/**
 * \brief Normalizes (unitizes) a vector
 */
void CEVector3::Normalize()
{
	GLfloat len = Length();

	if (len > 0.0f)
	{
		GLfloat invlength = 1.0f / len;

		x *= invlength;
		y *= invlength;
		z *= invlength;
	}
}

/**
 * \brief Gets a normalized (unitized) version of the vector
 * \return Normalized vector
 */
CEVector3 CEVector3::GetNormalized()
{
	GLfloat len = Length();

	if (len > 0.0f)
	{
		GLfloat invlength = 1.0f / len;

		return CEVector3( x *= invlength, y *= invlength, z *= invlength );
	} // if (len > 0.0f){
	else
		return CEVector3( 0.0f, 0.0f, 0.0f );
}




///////////////////////////////////////////////////////////////////////////////

/**
 * \brief Constructs a 2-vector; no initialization is done, for speed
 * \return 
 */
CEVector2::CEVector2()
{
	
}

/**
 * \return 
 */
CEVector2::~CEVector2()
{
}

/**
 * \brief Copy constructor
 * \param val Vector to copy
 * \return 
 */
CEVector2::CEVector2(const CEVector2& val)
{
	x = val.x; 
	y = val.y; 
}

/**
 * \brief Constructs a vector from components
 * \param valX x component
 * \param valY y component
 * \return 
 */
CEVector2::CEVector2(GLfloat valX, GLfloat valY)
{ 
	x = valX; 
	y = valY; 
}

/**
 * \brief constructs a vector from an array of components
 * \param *val pointer to array of components, GLfloat[2]
 * \return 
 */
CEVector2::CEVector2(GLfloat *val) 
{ 
	x = val[0]; 
	y = val[1]; 
}


/**
 * \brief Sets components from individual components
 * \param valX x component
 * \param valY y component
 */
void CEVector2::Set(GLfloat valX, GLfloat valY)
{ 
	x = valX; 
	y = valY; 
}

/**
 * \brief Sets components from array of components
 * \param *val pointer to array of components, GLfloat[2]
 */
void CEVector2::Set(GLfloat *val) 
{ 
	x = val[0]; 
	y = val[1]; 
}

// operators
/**
 * \brief assignment
 * \param val vector to assign
 * \return 
 */
CEVector2& CEVector2::operator=(const CEVector2& val)
{ 
	x = val.x;
	y = val.y;
	return *this;
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector2 CEVector2::operator-(const CEVector2& val) const
{ 
	return CEVector2( x - val.x, y - val.y ); 
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector2& CEVector2::operator-=(const GLfloat val) 
{ 
	x -= val;
	y -= val;
	return *this; 
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector2 CEVector2::operator+(const CEVector2& val)  const
{ 
	return CEVector2( x + val.x, y + val.y ); 
}

/**
 * 
 * \param val 
 * \return 
 */
CEVector2& CEVector2::operator+=(const GLfloat val) 
{ 
	x += val;
	y += val;
	return *this; 
}

/**
 * 
 * \param scalar 
 * \return 
 */
CEVector2 CEVector2::operator*(const GLfloat scalar)  const
{ 
	return CEVector2( x * scalar, y * scalar ); 
}

/**
 * 
 * \param scalar 
 * \return 
 */
CEVector2& CEVector2::operator*=(const GLfloat scalar) 
{ 
	x *= scalar;
	y *= scalar;

	return *this; 
}

/**
 * \note checks for divide-by-zero
 * \param scalar 
 * \return 
 */
CEVector2 CEVector2::operator/(const GLfloat scalar)  const
{ 
	if ( scalar != 0.0f )
		return CEVector2( x / scalar, y / scalar ); 
	else
		return CEVector2( 0.0f, 0.0f );
}

/**
 * 
 * \param scalar 
 * \return 
 */
CEVector2& CEVector2::operator/=(const GLfloat scalar) 
{ 
	if ( scalar != 0.0f )
	{
		x /= scalar;
		y /= scalar;
	}

	return *this; 
}

// equality operators
/**
 * 
 * \param val 
 * \return 
*/
bool CEVector2::operator==(const CEVector2& val) const
{
	return ( (x == val.x) && (y == val.y) );
}

/**
 * 
 * \param val 
 * \return 
 */
bool CEVector2::operator!=(const CEVector2& val) const
{
	return ( (x != val.x) || (y != val.y) );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector2::operator>=(const CEVector2& val) const
{
	return ( Length() >= val.Length() );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector2::operator<=(const CEVector2& val) const
{
	return ( Length() <= val.Length() );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector2::operator>(const CEVector2& val) const
{
	return ( Length() > val.Length() );
}

/**
 * 
 * \param val 
 * \return 
 * \warning is length the right way to compare?
 */
bool CEVector2::operator<(const CEVector2& val) const
{
	return ( Length() < val.Length() );
}


// pseudo-operators
/**
 * \brief Multiplies each component by a scalar
 * \param scalar 
 */
void CEVector2::Scale(GLfloat scalar) 
{ 
	x *= scalar; 
	y *= scalar; 
}

// casting operators
/**
 * \brief operator to access individual component
 * \param i component to access
 * \return component
 * \warning assumes no virtual functions and data is packed in a 2*sizeof(GLfloat) memory block
 */
GLfloat& CEVector2::operator[] (int i) const
{
    return ((GLfloat*)this)[i];
}

/**
 * \brief casts to array of GLfloat[2]
 * \return pointer to array of GLfloat[2]
 * \warning assumes no virtual functions and data is packed in a 2*sizeof(GLfloat) memory block
 */
CEVector2::operator GLfloat* ()
{
    return (GLfloat*)this;
}


// operations
/**
 * \brief Computes length of vector
 * \return Length
 */
GLfloat CEVector2::Length() const
{
	return (GLfloat)sqrt( x*x + y*y );
}


/**
 * \brief Normalizes (unitizes) a vector
 */
void CEVector2::Normalize()
{
	GLfloat len = Length();

	if (len > 0.0f)
	{
		GLfloat invlength = 1.0f / len;

		x *= invlength;
		y *= invlength;
	}
}

/**
 * \brief Gets a normalized (unitized) version of the vector
 * \return Normalized vector, CEVector2
 */
CEVector2 CEVector2::GetNormalized()
{
	GLfloat len = Length();

	if (len > 0.0f)
	{
		GLfloat invlength = 1.0f / len;

		return CEVector2( x *= invlength, y *= invlength );
	} // if (len > 0.0f){
	else
		return CEVector2( 0.0f, 0.0f );
}





