/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2009.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: sgx/include/sgx/core/math/points.hpp

*/

#ifndef SGX_CORE_MATH_POINTS_HPP
#define SGX_CORE_MATH_POINTS_HPP	1

typedef tINT32  tPOINT;
typedef tUINT32 tSCALAR;

template <typename T>
class sgxDimension2 {
public:
	T		width, height;

#if SGX_DEBUG
    sgxDimension2<T>() { width = height = SGX_SNAN; }
#else		
	sgxDimension2<T>() {}
#endif

	sgxDimension2<T>(tREAL32 vw, tREAL32 vh) { width=(T)vw; height=(T)vh; }
	sgxDimension2<T>(tINT32 vw, tINT32 vh) { width=(T)vw; height=(T)vh; }

};
typedef sgxDimension2<tSCALAR>	sgxDimension2i;
typedef sgxDimension2<tREAL32>	sgxDimension2f;


template <typename T>
class sgxDimension3 {
public:
	T		width, height, depth;

#if SGX_DEBUG
    sgxDimension3<T>() { width = height = depth = SGX_SNAN; }
#else		
	sgxDimension3<T>() {}
#endif

	sgxDimension3<T>(tREAL32 vw, tREAL32 vh, tREAL32 vd) { width=(T)vw; height=(T)vh; depth=(T)vd; }
	sgxDimension3<T>(tINT32 vw, tINT32 vh, tINT32 vd) { width=(T)vw; height=(T)vh; depth=(T)vd; }

};
typedef sgxDimension3<tINT32>	sgxDimension3i;
typedef sgxDimension3<tREAL32>	sgxDimension3f;


/**
A sgxPoint2 is essentially an integral version of sgxVector2. It is intended 
for GUI and surface bitmaps. Floats are supported

*/
template <typename T>
class sgxPoint2 {
public:
	T		x, y;
/*
	static sgxPoint2 Null;
	static sgxPoint2 Origin;
	static sgxPoint2 UnitX;
	static sgxPoint2 UnitY;
	static sgxPoint2 UnitMinusX;
	static sgxPoint2 UnitMinusY;
*/

#if SGX_DEBUG
    sgxPoint2<T>() { x = y = SGX_SNAN; }
#else		
	sgxPoint2<T>() {}
#endif

	sgxPoint2<T>(tREAL32 vx, tREAL32 vy) { x=(T)vx; y=(T)vy; }
	sgxPoint2<T>(tINT32 vx, tINT32 vy) { x=(T)vx; y=(T)vy; }

	SGX_INLINE	sgxPoint2<T>	operator-(void) { return sgxPoint2<T>(-x, -y); }
	SGX_INLINE	sgxPoint2<T>	operator+(const T &n) const { return sgxPoint2(x+n, y+n); }
	SGX_INLINE	sgxPoint2<T>	operator-(const T &n) const { return sgxPoint2(x-n, y-n); }
	SGX_INLINE	sgxPoint2<T>	operator*(const T &n) const { return sgxPoint2(x*n, y*n); }
	SGX_INLINE	sgxPoint2<T>	operator/(const T &n) const { return sgxPoint2(x/n, y/n); }
	SGX_INLINE	sgxPoint2<T>	operator+(const sgxPoint2<T> &v) const { return sgxPoint2(x+v.x, y+v.y); }
	SGX_INLINE	sgxPoint2<T>	operator-(const sgxPoint2<T> &v) const { return sgxPoint2(x-v.x, y-v.y); }
	SGX_INLINE	sgxPoint2<T>	operator*(const sgxPoint2<T> &v) const { return sgxPoint2(x*v.x, y*v.y); }
	SGX_INLINE	sgxPoint2<T>	operator/(const sgxPoint2<T> &v) const { return sgxPoint2(x/v.x, y/v.y); }
	SGX_INLINE	sgxPoint2<T>	operator+=(const T &n) { x+=n; y+=n; return *this; }
	SGX_INLINE	sgxPoint2<T>	operator-=(const T &n) { x-=n; y-=n; return *this; }
	SGX_INLINE	sgxPoint2<T>	operator*=(const T &n) { x*=n; y*=n; return *this; }
	SGX_INLINE	sgxPoint2<T>	operator/=(const T &n) { x/=n; y/=n; return *this; }
	SGX_INLINE	sgxPoint2<T>	operator+=(const sgxPoint2<T> &v) { x+=v.x; y+=v.y; return *this; }
	SGX_INLINE	sgxPoint2<T>	operator-=(const sgxPoint2<T> &v) { x-=v.x; y-=v.y; return *this; }
	SGX_INLINE	sgxPoint2<T>	operator*=(const sgxPoint2<T> &v) { x*=v.x; y*=v.y; return *this; }
	SGX_INLINE	sgxPoint2<T>	operator/=(const sgxPoint2<T> &v) { x/=v.x; y/=v.y; return *this; }
	SGX_INLINE	bool		operator==(const sgxPoint2<T> &r) { return x==r.x && y==r.y; }
	SGX_INLINE	bool		operator!=(const sgxPoint2<T> &r) { return x!=r.x || y!=r.y; }
};

template <> SGX_INLINE	bool sgxPoint2<tREAL32>::operator==(const sgxPoint2<tREAL32> &r) { return (sgxEq(x,r.x)&&sgxEq(y,r.y))?TRUE:FALSE; }
template <> SGX_INLINE	bool sgxPoint2<tREAL32>::operator!=(const sgxPoint2<tREAL32> &r) { return (sgxNeq(x,r.x)||sgxNeq(y,r.y))?TRUE:FALSE; }

typedef sgxPoint2<tINT32>	sgxPoint2i;
typedef sgxPoint2<tREAL32>	sgxPoint2f;

template <typename T>
class sgxRect {
public:
	T		left, right;
	T		top, bottom;

	sgxRect() {
		left = right = top = bottom = 0;
	}
	
	sgxRect(T l, T t, T r, T b) {
		left = l;
		right = r;
		top = t;
		bottom = b;
	}

	SGX_INLINE	sgxRect<T>	operator-=(const sgxPoint2<T> &v)	{ left-=v.x; right-=v.x; top-=v.y; bottom-=v.y; return *this; }
	SGX_INLINE	sgxRect<T>	operator-=(const sgxRect<T> &r)		{ left-=r.left; right-=r.right; top-=r.top; bottom-=r.bottom; return *this; }
	SGX_INLINE	sgxRect<T>	operator+=(const sgxPoint2<T> &v)	{ left+=v.x; right+=v.x; top+=v.y; bottom+=v.y; return *this; }
	SGX_INLINE	sgxRect<T>	operator+=(const sgxRect<T> &r)		{ left+=r.left; right+=r.right; top+=r.top; bottom+=r.bottom; return *this; }

	SGX_INLINE T	getWidth() const { return right - left; }
	SGX_INLINE T	getHeight() const { return bottom - top; }

	tBOOL isInside(const T x, const T y) {
		if (x < left || x > right || y < top || y > bottom) {
			return FALSE;
		} else {
			return TRUE;
		}
	}

	tBOOL isInside(const sgxPoint2i &pt) {
		if (pt.x < left || pt.x > right || pt.y < top || pt.y > bottom) {
			return FALSE;
		} else {
			return TRUE;
		}
	}

	tBOOL isInside(const sgxRect<T> &target) {
		if (!isInside(target.left, target.top)) {
			return FALSE;
		}
		if (!isInside(target.right, target.top)) {
			return FALSE;
		}
		if (!isInside(target.right, target.bottom)) {
			return FALSE;
		}
		if (!isInside(target.left, target.bottom)) {
			return FALSE;
		}
		return TRUE;
	}

	tBOOL intersects(const sgxRect<T> &target) {
		if (isInside(target.left, target.top) != isInside(target.right, target.top)) {
			return TRUE;
		}
		if (isInside(target.right, target.top) != isInside(target.right, target.bottom)) {
			return TRUE;
		}
		if (isInside(target.right, target.bottom) != isInside(target.left, target.bottom)) {
			return TRUE;
		}
		if (isInside(target.left, target.bottom) != isInside(target.left, target.top)) {
			return TRUE;
		}
		return FALSE;
	}

	tBOOL intersects(const sgxRect<T> &fromPoint, const sgxRect<T> &toPoint) {
		return isInside(fromPoint) != isInside(toPoint);
	}

	void flipVertical() {
		T temp(bottom);
		bottom = top;
		top = temp;
	}

	void flipHotizontal() {
		T temp(right);
		right = left;
		left = temp;
	}
};
typedef sgxRect<tINT32>		sgxRect2i;
typedef sgxRect<tREAL32>	sgxRect2f;

#endif /* SGX_CORE_MATH_POINTS_HPP */
