/*!
 	@file
 	@brief	３次元ベクトルテンプレート
 */



#ifndef Vector3D_h
#define Vector3D_h

#include"../../Setup/CompileMode.h"

#include"Point3D.h"
#include"Vector4D.h"
#include"function.h"


namespace Maid
{ 
	/*!
	 	@brief	３次元ベクトルを保持する構造体
	 */
	template<typename TYPE>
	struct VECTOR3D_TEMPLATE
	{ 
		typedef VECTOR3D_TEMPLATE<TYPE> VECTOR;
		typedef POINT3D_TEMPLATE<TYPE>  POINT;

		TYPE	x;		//!<	横
		TYPE	y;		//!<	縦
		TYPE	z;		//!<	奥

		VECTOR3D_TEMPLATE(){}
		VECTOR3D_TEMPLATE( TYPE _x, TYPE _y, TYPE _z ): x(_x), y(_y), z(_z){}
		VECTOR3D_TEMPLATE( const POINT& Start, const POINT& End ) { Reset(Start,End); }

		//! 正規化する
		/*!
		*/
		const VECTOR& Normalize()
		{
			const TYPE f = Math<TYPE>::sqrt(x*x+y*y+z*z);
			*this /= f;
			return *this;
		}

		//! 座標をベクトルに変換する
		/*!
		 	@param	Start [i ]	ベクトルの開始座標
		 	@param	End   [i ]	ベクトルの終了座標
		 */
		void Reset( const POINT& Start, const POINT& End )
		{
			x = End.x-Start.x;
			y = End.y-Start.y;
			z = End.z-Start.z;
		}
		//! 座標をベクトルに変換する
		/*!
		 	@param	pos [i ]	ベクトルの開始座標
		 */
		void Reset( const POINT& pos )
		{
			x = pos.x;
			y = pos.y;
			z = pos.z;
		}

		VECTOR4D_TEMPLATE<TYPE> Convert4D()const
		{
			return VECTOR4D_TEMPLATE<TYPE>(x,y,z,1);
		}

		//	単項演算子
		VECTOR operator-() const{ return VECTOR(-x,-y,-z); }

		//	比較演算子
		bool operator==( const VECTOR& rha ) const{ return x==rha.x && y==rha.y && z==rha.z; }
		bool operator!=( const VECTOR& rha ) const{ return !(*this==rha); }

		//	再設定
		VECTOR& operator+=( const VECTOR& rha)	{ *this = *this+rha; return *this; }
		VECTOR& operator-=( const VECTOR& rha)	{ *this = *this-rha; return *this; }
		VECTOR& operator*=( const TYPE& val)	{ *this = *this*val; return *this; }
		VECTOR& operator/=( const TYPE& val)	{ *this = *this/val; return *this; }
	};


	//	二項演算子
	template<typename TYPE>
	VECTOR3D_TEMPLATE<TYPE> operator+( const VECTOR3D_TEMPLATE<TYPE>& lha, const VECTOR3D_TEMPLATE<TYPE>& rha )
	{
		return VECTOR3D_TEMPLATE<TYPE>( lha.x+rha.x, lha.y+rha.y, lha.z+rha.z); 
	}
	template<typename TYPE>
	VECTOR3D_TEMPLATE<TYPE> operator-( const VECTOR3D_TEMPLATE<TYPE>& lha, const VECTOR3D_TEMPLATE<TYPE>& rha )
	{
		return VECTOR3D_TEMPLATE<TYPE>( lha.x-rha.x, lha.y-rha.y, lha.z-rha.z); 
	}
	template<typename TYPE>
	VECTOR3D_TEMPLATE<TYPE> operator*( const VECTOR3D_TEMPLATE<TYPE>& lha, const TYPE& rha )
	{
		return VECTOR3D_TEMPLATE<TYPE>( lha.x*rha, lha.y*rha, lha.z*rha); 
	}
	template<typename TYPE>
	VECTOR3D_TEMPLATE<TYPE> operator/( const VECTOR3D_TEMPLATE<TYPE>& lha, const TYPE& rha )
	{
		return VECTOR3D_TEMPLATE<TYPE>( lha.x/rha, lha.y/rha, lha.z/rha); 
	}

	//! 内積を求める
	/*!
	 	@param	lha		[i ]	ベクトルその１
	 	@param	rha		[i ]	ベクトルその２
	 
	 	@return	内積の値
	 */
	template<typename TYPE>
	inline TYPE VectorDot( const VECTOR3D_TEMPLATE<TYPE>& lha, const VECTOR3D_TEMPLATE<TYPE>& rha )
	{
		return (lha.x*rha.x) + (lha.y*rha.y) + (lha.z*rha.z);
	}

	//! 外積を求める
	/*!
	 	左手座標系での計算です
	 	@param	lha		[i ]	ベクトルその１
	 	@param	rha		[i ]	ベクトルその２
	 
	 	@return	外積のベクトル
	 */
	template<typename TYPE>
	inline VECTOR3D_TEMPLATE<TYPE> VectorCross( const VECTOR3D_TEMPLATE<TYPE>& lha, const VECTOR3D_TEMPLATE<TYPE>& rha )
	{
		return VECTOR3D_TEMPLATE<TYPE>(
				(lha.y*rha.z) - (lha.z*rha.y),
				(lha.z*rha.x) - (lha.x*rha.z),
				(lha.x*rha.y) - (lha.y*rha.x)
			); 
	}


}
	//	Windows のときのみ DXLIB を使ったバージョンを存在させる
	#ifdef USE_DIRECT3DX9
		#include<d3dx9.h>
		#pragma comment( lib, "d3dx9.lib" )

		namespace Maid
		{
			const VECTOR3D_TEMPLATE<FLOAT>& VECTOR3D_TEMPLATE<FLOAT>::Normalize()
			{
				D3DXVec3Normalize( (D3DXVECTOR3*)this, (D3DXVECTOR3*)this );
				return *this;
			}

			inline FLOAT VectorDot( const VECTOR3D_TEMPLATE<FLOAT>& lha, const VECTOR3D_TEMPLATE<FLOAT>& rha )
			{
				return D3DXVec3Dot( (D3DXVECTOR3*)&lha, (D3DXVECTOR3*)&rha );
			}

			inline VECTOR3D_TEMPLATE<FLOAT> VectorCross( const VECTOR3D_TEMPLATE<FLOAT>& lha, const VECTOR3D_TEMPLATE<FLOAT>& rha )
			{
				VECTOR3D_TEMPLATE<FLOAT> tmp;
				D3DXVec3Cross( (D3DXVECTOR3*)&tmp, (D3DXVECTOR3*)&lha, (D3DXVECTOR3*)&rha );
				return tmp;
			}
		}
	#endif


#endif
