#ifndef _MATH_H_
#define _MATH_H_

const float DEG2RAD = 0.01745329251994329576923690768f;
const float RAD2DEG = 57.2957795130823208767981548141f;

inline float ToRadian(const float Degree) {
	return (Degree * DEG2RAD);
}

inline float ToDegree(const float Radian) {
	return (Radian * RAD2DEG);
}

template<class T>
struct Vec4 {
	T x, y, z, w;
	template<class P>
	Vec4(P x, P y, P z, P w) : x(x), y(y), z(z), w(w) {}
	template<class P>
	Vec4(P all) : x(all), y(all), z(all), w(all) {}
	Vec4() : x(0), y(0), z(0), w(0) {}
	inline Vec4& dot(const Vec4<T>& v) {
		return (x * v.x + y * v.y + z * v.z + w * v.w);
	}
	inline const Vec4& operator+() {
		return *this;
	}
	inline Vec4& operator-() {
		return Vec4<T>(-x, -y, -z, -w);
	}
	inline Vec4& operator+(const Vec4<T>& v) {
		return new Vec4(x + v.x, y + v.y, z + v.z, w + v.w);
	}
	inline Vec4& operator-(const Vec4<T>& v) {
		return new Vec4(x - v.x, y - v.y, z - v.z, w - v.w);
	}	
	inline Vec4& operator*(const Vec4<T>& v) {
		return new Vec4(x * v.x, y * v.y, z * v.z, w * v.w);
	}
	inline Vec4& operator/(const Vec4<T>& v) {
		return new Vec4(x / v.x, y / v.y, z / v.z, w / v.w);
	}
	inline Vec4& operator+=(const Vec4<T>& v) {
		x+=v.x; y+=v.y; z+=v.z; w+=v.w;
		return *this;
	}
	inline Vec4& operator-=(const Vec4<T>& v) {
		x-=v.x; y-=v.y; z-=v.z; w-=v.w;
		return *this;
	}
	inline Vec4& operator*=(const Vec4<T>& v) {
		x*=v.x; y*=v.y; z*=v.z; w*=v.w;
		return *this;
	}
	inline Vec4& operator/=(const Vec4<T>& v) {
		x/=v.x; y/=v.y; z/=v.z; w/=v.w;
		return *this;
	}
	template<class P>
	inline Vec4& operator+=(P s) {
		x+=s; y+=s; z+=s; w+=s;
		return *this;
	}
	template<class P>
	inline Vec4& operator-=(P s) {
		x-=s; y-=s; z-=s; w-=s;
		return *this;
	}
	template<class P>
	inline Vec4& operator*=(P s) {
		x*=s; y*=s; z*=s; w*=s;
		return *this;
	}
	template<class P>
	inline Vec4& operator/=(P s) {
		x/=s; y/=s; z/=s; w/=s;
		return *this;
	}
};

template<class T>
struct Vec3 {
	T x, y, z;
	template<class P>
	Vec3(P x, P y, P z) : x(x), y(y), z(z) {}
	template<class P>
	Vec3(P all) : x(all), y(all), z(all) {}
	Vec3() : x(0), y(0), z(0) {}
	inline Vec3& cross(const Vec3<T>& v) {
		return new Vec3(
			(y * v.z - z * v.y),
			(x * v.z - z * v.x),
			(x * v.y - y * v.x)
		);
	}
	inline Vec3& dot(const Vec3<T>& v) {
		return (x * v.x + y * v.y + z * v.z);
	}
	inline const Vec3& operator+() {
		return *this;
	}
	inline Vec3& operator-() {
		return Vec3<T>(-x, -y, -z);
	}
	inline Vec3& operator+(const Vec3<T>& v) {
		return new Vec3(x + v.x, y + v.y, z + v.z);
	}
	inline Vec3& operator-(const Vec3<T>& v) {
		return new Vec3(x - v.x, y - v.y, z - v.z);
	}	
	inline Vec3& operator*(const Vec3<T>& v) {
		return new Vec3(x * v.x, y * v.y, z * v.z);
	}
	inline Vec3& operator/(const Vec3<T>& v) {
		return new Vec3(x / v.x, y / v.y, z / v.z);
	}
	inline Vec3& operator+=(const Vec3<T>& v) {
		x+=v.x; y+=v.y; z+=v.z;
		return *this;
	}
	inline Vec3& operator-=(const Vec3<T>& v) {
		x-=v.x; y-=v.y; z-=v.z;
		return *this;
	}
	inline Vec3& operator*=(const Vec3<T>& v) {
		x*=v.x; y*=v.y; z*=v.z;
		return *this;
	}
	inline Vec3& operator/=(const Vec3<T>& v) {
		x/=v.x; y/=v.y; z/=v.z;
		return *this;
	}
	template<class P>
	inline Vec3& operator+=(P s) {
		x+=s; y+=s; z+=s;
		return *this;
	}
	template<class P>
	inline Vec3& operator-=(P s) {
		x-=s; y-=s; z-=s;
		return *this;
	}
	template<class P>
	inline Vec3& operator*=(P s) {
		x*=s; y*=s; z*=s;
		return *this;
	}
	template<class P>
	inline Vec3& operator/=(P s) {
		x/=s; y/=s; z/=s;
		return *this;
	}
};

template<class T>
struct Vec2 {
	T x, y;
	template<class P>
	Vec2(P x, P y) : x(x), y(y) {}
	template<class P>
	Vec2(P all) : x(all), y(all) {}
	Vec2() : x(0), y(0) {}
		inline const Vec2& operator+() {
		return *this;
	}
	inline Vec2& dot(const Vec3<T>& v) {
		return (x * v.x + y * v.y);
	}
	inline Vec2& operator-() {
		return Vec3<T>(-x, -y);
	}
	inline Vec2& operator+(const Vec2<T>& v) {
		return new Vec2(x + v.x, y + v.y);
	}
	inline Vec2& operator-(const Vec2<T>& v) {
		return new Vec2(x - v.x, y - v.y);
	}	
	inline Vec2& operator*(const Vec2<T>& v) {
		return new Vec2(x * v.x, y * v.y);
	}
	inline Vec2& operator/(const Vec2<T>& v) {
		return new Vec2(x / v.x, y / v.y);
	}
	inline Vec2& operator+=(const Vec2<T>& v) {
		x+=v.x; y+=v.y;
		return *this;
	}
	inline Vec2& operator-=(const Vec2<T>& v) {
		x-=v.x; y-=v.y;
		return *this;
	}
	inline Vec2& operator*=(const Vec2<T>& v) {
		x*=v.x; y*=v.y;
		return *this;
	}
	inline Vec2& operator/=(const Vec2<T>& v) {
		x/=v.x; y/=v.y;
		return *this;
	}
	template<class P>
	inline Vec2& operator+=(P s) {
		x+=s; y+=s;
		return *this;
	}
	template<class P>
	inline Vec2& operator-=(P s) {
		x-=s; y-=s;
		return *this;
	}
	template<class P>
	inline Vec2& operator*=(P s) {
		x*=s; y*=s;
		return *this;
	}
	template<class P>
	inline Vec2& operator/=(P s) {
		x/=s; y/=s;
		return *this;
	}
};

#endif
