/*
	Twilight Prophecy 3D/Multimedia SDK
	A multi-platform development system for virtual reality and multimedia.

	Copyright (C) 1997-2001 by Twilight 3D Finland Oy Ltd.
*/
#ifndef PRMATH_VECTOR4_HPP
#define PRMATH_VECTOR4_HPP



namespace prmath
{

	struct Vector4
	{
		// members
		union {	float x, r; };
		union {	float y, g; };
		union {	float z, b; };
		union {	float w, a; };
		
		// constructors
inline	Vector4() {}
inline	Vector4(float x, float y, float z, float w);
inline	Vector4(const float v[]);
inline	Vector4(const Vector4& v);

		// operators
inline	Vector4			operator +  () const;
inline	Vector4			operator -  () const;
inline	Vector4			operator +  (const Vector4& v) const;
inline	Vector4			operator -  (const Vector4& v) const;
inline	Vector4			operator *  (const Vector4& v) const;
inline	Vector4			operator *  (const float& s) const;
inline	Vector4			operator /  (const float& s) const;
inline	Vector4&		operator += (const Vector4& v);
inline	Vector4&		operator -= (const Vector4& v);
inline	Vector4&		operator *= (const Vector4& v);
inline	Vector4&		operator *= (const float& s);
inline	Vector4&		operator /= (const float& s);
inline	void			operator  = (const Vector4& v);
inline	bool			operator == (const Vector4& v) const;
inline	bool			operator != (const Vector4& v) const;
inline	const float&	operator [] (int index) const;
inline	float&			operator [] (int index);
inline					operator const float* () const;
inline					operator float* ();
	};


	// functions

inline	float		DotProduct(const Vector4& a, const Vector4& b);
inline	Vector4		Lerp(const Vector4& a, const Vector4& b, float t);
inline	Vector4		operator * (float s, const Vector4& v);


	// implementation

inline Vector4::Vector4(float vx, float vy, float vz, float vw)
: x(vx), y(vy), z(vz), w(vw)
{
}

inline Vector4::Vector4(const float v[])
: x(v[0]), y(v[1]), z(v[2]), w(v[3])
{
}

inline Vector4::Vector4(const Vector4& v)
: x(v.x), y(v.y), z(v.z), w(v.w)
{
}

inline Vector4 Vector4::operator + () const
{
	return *this;
}

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

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

inline Vector4 Vector4::operator - (const Vector4& v) const
{
	return Vector4(
		x - v.x,
		y - v.y,
		z - v.z,
		w - v.w );
}

inline Vector4 Vector4::operator * (const Vector4& v) const
{
	return Vector4(
		x * v.x,
		y * v.y,
		z * v.z,
		w * v.w );
}

inline Vector4 Vector4::operator * (const float& s) const
{
	return Vector4(
		x * s,
		y * s,
		z * s,
		w * s );
}

inline Vector4 Vector4::operator / (const float& s) const
{
	assert( s );
	float is = 1 / s;
	return Vector4(
		x * is,
		y * is,
		z * is,
		w * is );
}

inline Vector4& Vector4::operator += (const Vector4& v)
{
	x += v.x;
	y += v.y;
	z += v.z;
	w += v.w;
	return *this;
}

inline Vector4& Vector4::operator -= (const Vector4& v)
{
	x -= v.x;
	y -= v.y;
	z -= v.z;
	w -= v.w;
	return *this;
}

inline Vector4& Vector4::operator *= (const Vector4& v)
{
	x *= v.x;
	y *= v.y;
	z *= v.z;
	w *= v.w;
	return *this;
}

inline Vector4& Vector4::operator *= (const float& s)
{
	x *= s;
	y *= s;
	z *= s;
	w *= s;
	return *this;
}

inline Vector4& Vector4::operator /= (const float& s)
{
	assert( s );
	float is = 1 / s;
	x *= is;
	y *= is;
	z *= is;
	w *= is;
	return *this;
}

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

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

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

inline const float& Vector4::operator [] (int index) const
{
	assert( index >= 0 && index <= 3 );
	return reinterpret_cast<const float*>(this)[index];
}

inline float& Vector4::operator [] (int index)
{
	assert( index >= 0 && index <= 3 );
	return reinterpret_cast<float*>(this)[index];
}

inline Vector4::operator const float* () const
{
	return reinterpret_cast<const float*>(this);
}

inline Vector4::operator float* ()
{
	return reinterpret_cast<float*>(this);
}

inline float DotProduct(const Vector4& a, const Vector4& b)
{
	return 
		a.x * b.x +
		a.y * b.y +
		a.z * b.z +
		a.w * b.w;
}

inline Vector4 Lerp(const Vector4& a, const Vector4& b, float t)
{
	return Vector4(
		a.x + (b.x - a.x) * t,
		a.y + (b.y - a.y) * t,
		a.z + (b.z - a.z) * t,
		a.w + (b.w - a.w) * t );
}

inline Vector4 operator * (float s, const Vector4& v)
{
	return Vector4(
		v.x * s,
		v.y * s,
		v.z * s,
		v.w * s );
}

} // namespace prmath



#endif