/*
	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_VECTOR2_HPP
#define PRMATH_VECTOR2_HPP



namespace prmath
{
	
	struct Vector2
	{
		// members
		float	x;
		float	y;
		
		// constructors
inline	Vector2() {}
inline	Vector2(float x, float y);
inline	Vector2(const float v[]);
inline	Vector2(const Vector2& v);

		// operators
inline	Vector2			operator +	() const;
inline	Vector2			operator -	() const;
inline	Vector2			operator +	(const Vector2& v) const;
inline	Vector2			operator -	(const Vector2& v) const;
inline	Vector2			operator *	(const Vector2& v) const;
inline	Vector2			operator *	(const float& s) const;
inline	Vector2			operator /	(const float& s) const;
inline	Vector2&		operator +=	(const Vector2& v);
inline	Vector2&		operator -=	(const Vector2& v);
inline	Vector2&		operator *=	(const Vector2& v);
inline	Vector2&		operator *=	(const float& s);
inline	Vector2&		operator /=	(const float& s);
inline	void			operator  =	(const Vector2& v);
inline	bool			operator == (const Vector2& v) const;
inline	bool			operator != (const Vector2& 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		LengthSquared(const Vector2& v);
inline	float		Length(const Vector2& v);
inline	float		DotProduct(const Vector2& a, const Vector2& b);
inline	Vector2		CrossProduct(const Vector2& v);
inline	Vector2		Normalize(const Vector2& v);
inline	Vector2		RotateZ(const Vector2& v, float angle);
inline	Vector2		Lerp(const Vector2& a, const Vector2& b, float t);
inline	Vector2		operator * (float s, const Vector2& v);


	// implementation

inline Vector2::Vector2(float vx, float vy)
: x(vx), y(vy)
{
}

inline Vector2::Vector2(const float v[])
: x(v[0]), y(v[1])
{
}

inline Vector2::Vector2(const Vector2& v)
: x(v.x), y(v.y)
{
}

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

inline Vector2 Vector2::operator - () const
{
	return Vector2(
		-x,
		-y );
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

inline float LengthSquared(const Vector2& v)
{
	return v.x*v.x + v.y*v.y;
}

inline float Length(const Vector2& v)
{
	return (float)sqrt(v.x*v.x + v.y*v.y);
}

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

inline Vector2 CrossProduct(const Vector2& v)
{
	return Vector2(
		-v.y,
		v.x );
}

inline Vector2 Normalize(const Vector2& v)
{
	float s = (float)sqrt( v.x*v.x + v.y*v.y );
	if ( s )
		s = 1 / s;
		
	return Vector2(
		v.x * s,
		v.y * s );
}

inline Vector2 RotateZ(const Vector2& v, float angle)
{
	float cosa = (float)cos( angle );
	float sina = (float)sin( angle );
	return Vector2(
		cosa * v.x - sina * v.y,
		sina * v.x + cosa * v.y );
}

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

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

} // namespace prmath



#endif