#ifndef __SSVECTOR_HPP
#define __SSVECTOR_HPP

#if !defined (__SSDEFS_HPP)
#	include "ssDefs.hpp"
#endif

#include <cmath>				// sqrt()

namespace SS
{

class Matrix3x4;
class Matrix4x4;
class Matrix3x3;
class Matrix2x2;


/******************************************************************************
 *
 * Class:			SS::Vector2
 *
 * Description:		Two-component vector 
 *
 *****************************************************************************/

class Vector2
{
public:
	float x,y;	
inline 					Vector2			(void)							: x(0.0f),y(0.0f)		{}
inline 					Vector2			(float cx, float cy)			: x(cx),y(cy) {}
inline  const float&	operator[]		(int i) const					{ SS_ASSERT (i>=0 && i < 2); return ((const float*)this)[i]; }
inline  float&			operator[]		(int i)							{ SS_ASSERT (i>=0 && i < 2); return ((float*)this)[i]; }
inline 	Vector2&		clear			(void)							{ x = 0.0f; y = 0.0f; return *this; }
inline 	Vector2&		set				(float cx, float cy)			{ x = cx;  y = cy; return *this;	}
inline  bool			operator==		(const Vector2& s) const		{ return (x==s.x)&&(y==s.y); }
inline  bool			operator!=		(const Vector2& s) const		{ return (x!=s.x)||(y!=s.y); }
inline 	float			length			(void) const					{ return (float)sqrt(x*x+y*y); }
inline 	float			lengthSqr		(void) const					{ return (x*x+y*y); }
inline 	Vector2&		normalize		(float len = 1.0f)				{ double l = x*x+y*y; if(l!=0.0) { l = len / sqrt(l); x = (float)(x*l); y = (float)(y*l); } return *this; }
inline 	void			scale			(const Vector2& v)				{ x*=v.x, y*=v.y; }
inline 	Vector2&		operator+=		(const Vector2& v)				{ x += v.x, y += v.y; return *this; }
inline 	Vector2&		operator-=		(const Vector2& v)				{ x -= v.x, y -= v.y; return *this; }
inline 	Vector2&		operator*=		(float s)						{ x = (x*s),   y = (y*s); return *this; }
inline 	Vector2&		operator/=		(float s)						{ s = (1.0f/s); x = (x*s), y = (y*s); return *this; }
inline 	Vector2&		operator*=		(const Matrix2x2& m);

};

inline 	Vector2			operator+			(const Vector2& v1,	const Vector2& v2)		{ return Vector2(v1.x+v2.x, v1.y+v2.y); }
inline 	Vector2			operator-			(const Vector2& v1,	const Vector2& v2)		{ return Vector2(v1.x-v2.x, v1.y-v2.y); }
inline 	Vector2			operator*			(const Vector2& v,	const float s)			{ return Vector2(v.x*s, v.y*s); }
inline 	Vector2			operator*			(const float s,		const Vector2& v)		{ return Vector2(v.x*s, v.y*s); }
inline 	Vector2			operator/			(const Vector2& v,	const float s)			{ return v*(1.0f/s); }
inline 	Vector2			operator-			(const Vector2& v)							{ return Vector2(-v.x, -v.y); }
		Vector2			operator*			(const Vector2& v,  const Matrix2x2& m);
inline 	float			dot					(const Vector2& v1,	const Vector2& v2) 		{ return (v1.x*v2.x + v1.y*v2.y); }

/******************************************************************************
 *
 * Class:			SS::Vector3
 *
 * Description:		Three-component vector
 *
 *****************************************************************************/

class Vector3 
{
public:
	float	x,y,z;

inline 					Vector3		(void) : x(0.0f),y(0.0f),z(0.0f)		{}
inline 					Vector3		(const Vector3& s)						{ x = s.x; y = s.y; z = s.z; }
inline 					Vector3		(float cx, float cy, float cz)			: x(cx),y(cy),z(cz) {}
inline 	const float&	operator[]	(int i) const							{ SS_ASSERT (i>=0 && i < 3); return ((const float*)this)[i]; }
inline 	float&			operator[]	(int i)									{ SS_ASSERT (i>=0 && i < 3); return ((float*)this)[i]; }
inline 	Vector3&		clear		(void)									{ x = 0.0f; y = 0.0f; z = 0.0f; return *this; }
inline 	Vector3&		set			(float cx, float cy, float cz)			{ x = cx;  y = cy;  z = cz; return *this;	}
inline 	Vector3&		operator+=	(const Vector3& v)						{ x += v.x, y += v.y, z += v.z; return *this; }
inline 	Vector3&		operator-=	(const Vector3& v)						{ x -= v.x, y -= v.y, z -= v.z; return *this; }
inline 	Vector3&		operator*=	(float s)								{ x = (x*s),   y = (y*s), z = (z*s); return *this; }
inline 	Vector3&		operator/=	(float s)								{ s = (1.0f/s); x = (x*s), y = (y*s), z = (z*s); return *this; }
inline 	Vector3&		operator*=	(const Matrix3x3& m);
inline 	float			operator|=	(const Vector3& v) const		 		{ return (x*v.x + y*v.y + z*v.z); }
inline 	bool			operator==	(const Vector3& v) const				{ return (x == v.x && y == v.y && z == v.z);	}
inline 	bool			operator!=	(const Vector3& v) const				{ return !(x == v.x && y == v.y && z == v.z);	}
inline 	float			length		(void) const							{ return (float)sqrt(x*x+y*y+z*z); }
inline 	float			lengthSqr	(void) const							{ return (x*x+y*y+z*z); }
inline 	Vector3&		normalize	(float len = 1.0f)						{ double l = x*x+y*y+z*z; if(l!=0.0) { l = len / sqrt(l); x = (float)(x*l); y = (float)(y*l); z = (float)(z*l); } return *this; }
inline 	void			scale		(const Vector3& v)						{ x*=v.x, y*=v.y, z*=v.z; }


//inline 	Vector3&		operator*=	(const Vector3& v)						{ x = (x*v.x), y = (y*v.y), z = (z*v.z); return *this; }
//inline 	Vector3&		operator/=	(const Vector3& v)						{ x = (x/v.x), y = (y/v.y), z = (z/v.z); return *this; }
};

inline 	Vector3			operator+			(const Vector3& v1,	const Vector3& v2)		{ return Vector3(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z); }
inline 	Vector3			operator-			(const Vector3& v1,	const Vector3& v2)		{ return Vector3(v1.x-v2.x, v1.y-v2.y, v1.z-v2.z); }
inline 	Vector3			operator*			(const Vector3& v,	const float s)			{ return Vector3(v.x*s, v.y*s, v.z*s); }
inline 	Vector3			operator*			(const float s,		const Vector3& v)		{ return Vector3(v.x*s, v.y*s, v.z*s); }
inline 	Vector3			operator/			(const Vector3& v,	const float s)			{ return v*(1.0f/s); }
inline 	Vector3			operator-			(const Vector3& v)							{ return Vector3(-v.x, -v.y, -v.z); }
inline 	Vector3			cross				(const Vector3& v1,	const Vector3& v2)		{ return Vector3 ((v1.y*v2.z)-(v1.z*v2.y), (v1.z*v2.x)-(v1.x*v2.z), (v1.x*v2.y)-(v1.y*v2.x)); }
		Vector3			operator*			(const Vector3& v,  const Matrix3x3& m);
inline 	float			dot					(const Vector3& v1,	const Vector3& v2) 		{ return (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); }


/******************************************************************************
 *
 * Class:			SS::Vector4
 *
 * Description:		Four-component vector 
 *
 *****************************************************************************/

class Vector4
{
public:
	float x,y,z,w;

inline 					Vector4		(void)											: x(0),y(0),z(0),w(0)			{}
inline 					Vector4		(float cx, float cy, float cz, float cw)		: x(cx),y(cy),z(cz),w(cw)		{}
inline 					Vector4		(const Vector3& s, float cw)					: x(s.x),y(s.y),z(s.z),w(cw)	{}
inline 					Vector4		(const Vector4& s)								: x(s.x),y(s.y),z(s.z),w(s.w)	{}
inline 	Vector4&		clear		(void)											{ x = (0); y = (0); z = (0); w = (0); return *this; }
inline 	Vector4&		set			(float cx, float cy, float cz, float cw)		{ x = (cx), y = (cy), z = (cz), w = (cw); return *this; }
inline 	const float&	operator[]	(int i) const									{ SS_ASSERT (i>=0 && i < 4); return ((const float*)this)[i]; }
inline 	float&			operator[]	(int i)											{ SS_ASSERT (i>=0 && i < 4); return ((float*)this)[i]; }
inline 	bool			operator==	(const Vector4& v) const						{ return (x == v.x && y == v.y && z == v.z && w == v.w);	}
inline 	bool			operator!=	(const Vector4& v) const						{ return !(x == v.x && y == v.y && z == v.z && w == v.w);	}
inline 	Vector4&		operator+=	(const Vector4& v)								{ x += v.x, y += v.y, z += v.z, w += v.w; return *this;		}
inline 	Vector4&		operator-=	(const Vector4& v)								{ x -= v.x, y -= v.y, z -= v.z, w -= v.w; return *this;		}
inline 	Vector4&		operator*=	(float s)										{ x = (x*s), y = (y*s), z = (z*s), w = (w*s); return *this; }
inline 	Vector4&		operator/=	(float s)										{ s = (1.0f/s); x = (x*s), y = (y*s), z = (z*s); w = (w*s); return *this; }
inline 	Vector4&		operator*=	(const Matrix4x4& m);
inline 	float			operator|=	(const Vector4& v) const					 	{ return x*v.x + y*v.y + z*v.z + w*v.w; }
inline 	float			length		(void) const									{ return (float)sqrt( x*x+y*y+z*z+w*w ); }
inline 	float			lengthSqr	(void) const									{ return ( x*x+y*y+z*z+w*w ); }
inline 	Vector4&		normalize	(double len = 1.0)								{ float l = length();	if(l!=0.0) *this *= ((float)(len/l)); return *this; }
inline 	void			scale		(const Vector4& v)								{ x = (x*v.x), y = (y*v.y), z = (z*v.z); w = (w*v.w); }

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

inline  Vector4			operator+	(const Vector4& v1, const Vector4& v2)	{ return Vector4(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z, v1.w+v2.w); }
inline  Vector4			operator-	(const Vector4& v1, const Vector4& v2)	{ return Vector4(v1.x-v2.x, v1.y-v2.y, v1.z-v2.z, v1.w-v2.w); }
inline 	Vector4			operator*	(const Vector4& v,	float s)			{ return Vector4(v.x*s, v.y*s, v.z*s, v.w*s); }
inline 	Vector4			operator*	(float s,			const Vector4& v)	{ return v*s; }
inline 	Vector4			operator/	(const Vector4& v,	float s)			{ SS_ASSERT(s!=0.0f); float r = 1.0f/s; return v*r; }
inline 	Vector4			operator-	(const Vector4& v)						{ return Vector4(-v.x, -v.y, -v.z, -v.w); }
		Vector4			operator*	(const Vector4& v,  const Matrix4x4& m);
inline 	float			dot			(const Vector4& v1, const Vector4& v2) 	{ return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w; }

} // SS

//------------------------------------------------------------------------
#endif // __SSVECTOR_HPP
