/***************************************************************/
//
//
//		DirectX	[ game_equation.h ]
//
//										Author	kazuki tanaka
//										Date	2016 06/19
/*---------------------------------------------------------------
■Update : 2016/06/19
			config.hの作成

■Update : 2016/07/10
			hファイルの中身を一新
			game_equation.h に名称の変更

■Update : 2016/07/10
			矩形と矩形の判定の追加
			円と円の判定の追加

■Update : 2016/07/20
			球と球の当たり判定の追加
			( 3D用 )

■Update : 2016/08/11
			オブジェクトの画面外を
			判定する処理を追加
			( 2D用 );

/*---------------------------------------------------------------
	インクルードファイル
---------------------------------------------------------------*/
#ifndef _GAME_EQUATION_H_

#define _GAME_EQUATION_H_

#include "window.h"
#include "system_component.h"
#include "rendererdx9.h"
#include <stdlib.h>

/*---------------------------------------------------------------
	マクロ定義
---------------------------------------------------------------*/

#define RADIAN(arc) (((arc) * D3DX_PI ) / 180)		// ラジアンの計算に必要

#define LIMIT_MAX(a,b) ( a>b ? b : a )				// 最大値の設定( 低い値を返す )
#define LIMIT_MIM(a,b) ( a>b ? a : b )				// 最小値の設定( 高い値を返す )

// アフィン変換
#define AFFINE_TRANSFORM_X( radiusX, radiusY, theta ) \
(( radiusX ) * cosf( RADIAN( theta )) - ( radiusY ) * sinf( RADIAN( theta )))

#define AFFINE_TRANSFORM_Y( radiusX, radiusY, theta ) \
(( radiusX ) * sinf( RADIAN( theta )) + ( radiusY ) * cosf( RADIAN( theta )))



/*---------------------------------------------------------------
	サブルーチン( インライン関数 )
---------------------------------------------------------------*/

// 矩形と矩形のあたり判定
inline bool __CollisionObjectSquare( const LPD3DXVECTOR2 objectA_s ,const LPD3DXVECTOR2 objectA_e, const LPD3DXVECTOR2 objectB_s, const LPD3DXVECTOR2 objectB_e )
{

	// CollisionRectAngle
	if( ( objectA_s->x < objectB_e->x )
		&& ( objectA_e->x > objectB_s->x )
		&& ( objectA_s->y < objectB_e->y )
		&& ( objectA_e->y > objectB_s->y )){
		return true;
	}

	return false;
}

template<class T>inline bool __CollisionObjectSquare( const T objectA_s ,const T objectA_e, const T objectB_s, const T objectB_e )
{

	// CollisionRectAngle
	if( (    objectA_s.x < objectB_e.x )
		&& ( objectA_e.x > objectB_s.x )
		&& ( objectA_s.z < objectB_e.z )
		&& ( objectA_e.z > objectB_s.z )){
		return true;
	}

	return false;
}

template<class T>inline bool __CollisionObjectSquare( const T objectA_s ,const T objectA_e, const T objectB, const float radiusB )
{

	// CollisionRectAngle
	if( (    objectA_s.x < objectB.x + radiusB )
		&& ( objectA_e.x > objectB.x - radiusB )
		&& ( objectA_s.z < objectB.z + radiusB )
		&& ( objectA_e.z > objectB.z - radiusB ) ){
		return true;
	}

	return false;
}

inline bool __CollisionObjectSquareField( const LPD3DXVECTOR3 objPosA, const float radiusA, const LPD3DXVECTOR3 objPosB, const float radiusB )
{

	// 
	D3DXVECTOR2 startA, endA, startB, endB;

	startA = D3DXVECTOR2( objPosA->x - radiusA , objPosA->z - radiusA );
	endA   = D3DXVECTOR2( objPosA->x + radiusA , objPosA->z + radiusA );
	startB = D3DXVECTOR2( objPosB->x - radiusB , objPosB->z - radiusB );
	endB   = D3DXVECTOR2( objPosB->x + radiusB , objPosB->z + radiusB );

	// CollisionRectAngle
	if( ( startA.x < endB.x )
		&& ( endA.x > startB.x )
		&& ( startA.y < endB.y )
		&& ( endA.y > startB.y )){
		return true;
	}

	return false;
}


// 円と円のあたり判定
inline bool __CollisionObjectCircle( const LPD3DXVECTOR2 object_centerA, const LPD3DXVECTOR2 object_centerB,const LPD3DXVECTOR2 object_radiusA, const LPD3DXVECTOR2 object_radiusB )
{


	D3DXVECTOR2 difference;					//XYの差
	float       distance;					//距離



	// オブジェクトA,BのX,Yの差の計算
	difference.x = ( object_centerA->x - object_centerB->x ) * ( object_centerA->x - object_centerB->x );	//x2
	difference.y = ( object_centerA->y - object_centerB->y ) * ( object_centerA->y - object_centerB->y );	//y2


	// オブジェクトAとオブジェクトBの距離測定
	distance = ( ( difference.x ) + ( difference.y ) );			// rの２乗 : r2 = x2 + y2 ;

	// 判定
	if( distance < ( object_radiusA->x + object_radiusB->x ) * ( object_radiusA->x + object_radiusB->x ) ){
		return true;	//接している
	}

	return false;	//接していない

}

// 球と球のあたり判定
inline bool __CollisionObjectSphere( const LPD3DXVECTOR3 object_centerA, const LPD3DXVECTOR3 object_centerB,const float radiusA, const float radiusB )
{

	D3DXVECTOR3 difference;					//XYの差
	float       distance;					//距離


	// オブジェクトA,BのX,Yの差の計算
	difference.x = ( object_centerA->x - object_centerB->x ) * ( object_centerA->x - object_centerB->x );	//x2
	difference.y = ( object_centerA->y - object_centerB->y ) * ( object_centerA->y - object_centerB->y );	//y2
	difference.z = ( object_centerA->z - object_centerB->z ) * ( object_centerA->z - object_centerB->z );	//z2

	// オブジェクトAとオブジェクトBの距離測定
	distance = ( ( difference.x ) + ( difference.y ) + ( difference.z ) );			// rの２乗 : r2 = x2 + y2 + z2 ;

	// 判定
	if( distance < ( radiusA + radiusB ) * ( radiusA + radiusB ) ){
		return true;	//接している
	}
	return false;	//接していない

}

// 画面外を判定( 2Dゲーム用 )
inline bool __ObjectScreenOut(  const LPD3DXVECTOR2 object_center, const LPD3DXVECTOR2 radius )
{

	// 画面外計算
	if( !( object_center->y + radius->y > 0 &&
		object_center->x + radius->x > 0 &&
		object_center->y - radius->y < Window::SCREEN_HEIGHT &&
		object_center->x - radius->x < Window::SCREEN_WIDTH ) ){
		// 画面外
		return true;
	}

	// 画面内
	return false;
}

inline bool __ObjectScreenOut(  const LPD3DXVECTOR2 object_center, const float radius )
{

	// 画面外計算
	if( !( object_center->y + radius > 0 &&
		object_center->x + radius > 0 &&
		object_center->y - radius < Window::SCREEN_HEIGHT &&
		object_center->x - radius < Window::SCREEN_WIDTH ) ){

		// 画面外
		return true;
	}


	// 画面内
	return false;

}

// 画面外を判定( 2Dゲーム用 ) -> よりシンプルに改良( プレイヤーとかはこっちかな... )
inline bool __ObjectScreenOutSimple( const LPD3DXVECTOR2 object_center )
{

	// 画面外計算
	if( !( object_center->y > 0 &&
		object_center->x > 0 &&
		object_center->y < Window::SCREEN_HEIGHT &&
		object_center->x < Window::SCREEN_WIDTH ) ){

		// 画面外
		return true;
	}


	// 画面内
	return false;

}

// フィールド外を判定(2D&3D)
inline bool __ObjectFieldOut( const float vertical, const float horizonal, const LPD3DXVECTOR3 center, const float radius , LPD3DXVECTOR3 vector )
{
	
	// vertical Process
	if( !( center->x - radius > - vertical &&
		center ->x + radius < vertical ) ){
		vector->x = 0.0f;
	}
	// horizonal Process
	if( !( center->z - radius > - horizonal &&
		center ->z + radius < horizonal ) ){
		vector->z = 0.0f;
	}

	return false;
}

// フィールド外を判定(2D&3D)
inline bool __ObjectFieldOut( const float vertical, const float horizonal, const LPD3DXVECTOR3 center, const float radius )
{
	
	// vertical Process
	if( !( center->x - radius > - vertical &&
		center ->x + radius < vertical ) ){
		return true;
	}
	// horizonal Process
	if( !( center->z - radius > - horizonal &&
		center ->z + radius < horizonal ) ){
		return true;
	}

	return false;
}

// 点と円のあたり判定( 2D用 )
inline bool __ObjectTouchSphere( const LPD3DXVECTOR2 objectCenter, const float objectRadius, const LPD3DXVECTOR2 pos )
{

	float       distance;					//距離
	distance = ( objectCenter->x - pos->x ) * ( objectCenter->x - pos->x ) + ( objectCenter->y - pos->y ) * ( objectCenter->y - pos->y );

	// あたり判定
	if( distance < objectRadius * objectRadius ){
		// 当たっている
		return true;
	}

	// 当たっていない
	return false;

}

// 点と矩形のあたり判定( 2D用 )
inline bool __ObjectTouchSquare( const LPD3DXVECTOR2 object_start, const LPD3DXVECTOR2 object_end, const LPD3DXVECTOR2 point )
{

	// 当たり判定
	if( object_start->x < point->x && object_start->y < point->y 
		&& object_end->x > point->x && object_end->y > point ->y ){
	
		// 当たっている
		return true;
	}

	// 当たっていない
	return false;


}

// 回転行列用ベクトルの線形補間
inline D3DXVECTOR3 __ObjectAngleLinear( LPD3DXVECTOR3 pOut, const LPD3DXVECTOR3 start, const LPD3DXVECTOR3 end, const int LinearFrame )
{


	D3DXMATRIX startMtx, endMtx;

	// 行列の算出
	D3DXMatrixRotationYawPitchRoll( &startMtx, start->y, start->x, start->z );
	D3DXMatrixRotationYawPitchRoll( &endMtx, end->y, end->x, end->z );

	// 行列からベクトルの算出
	D3DXVECTOR3 source = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
	D3DXVECTOR3 vecStart,vecEnd;

	D3DXVec3TransformCoord( &vecStart, &source, &startMtx );
	D3DXVec3TransformCoord( &vecEnd  , &source, &endMtx );

	// ベクトルの単位ベクトル化
	// ベクトルの大きさを算出
	float vecLengthStart = D3DXVec3Length( &vecStart );
	float vecLengthEnd   = D3DXVec3Length( &vecEnd );

	// ベクトルの内積算出
	float dot = D3DXVec3Dot( &vecStart, &vecEnd );

	// ベクトルのなす角算出
	float arc = acosf( dot/( vecLengthStart * vecLengthEnd ) );
	
	float confirm = vecLengthStart*vecLengthEnd*cosf( arc );

	float a = 0;

	return source;

}

// 回転行列用ベクトルの線形補間
inline D3DXVECTOR3 __KFA_AngleLinearInterpolation( LPD3DXVECTOR3 pOut, const LPD3DXVECTOR3 start, const LPD3DXVECTOR3 end, const int LinearFrame, const int currentFrame )
{

	// 補間ベクトルの作成
	D3DXVECTOR3 linear = *end - *start;

	// 範囲外回転処理
	if( linear.y > D3DX_PI ){
		
		linear.y = linear.y - ( D3DX_PI * 2 );
	}
	if( linear.x > D3DX_PI ){
	
		linear.y = linear.y - ( D3DX_PI * 2 );
	}
	if( linear.z > D3DX_PI ){
	
		linear.y = linear.y - ( D3DX_PI * 2 );
	}
	if( linear.y < -D3DX_PI ){
		
		linear.y = linear.y + ( D3DX_PI * 2 );
	}
	if( linear.x < -D3DX_PI ){
	
		linear.y = linear.y + ( D3DX_PI * 2 );
	}
	if( linear.z < -D3DX_PI ){
	
		linear.y = linear.y + ( D3DX_PI * 2 );
	}

	//linear /= LinearFrame;

	*pOut = *start + ((linear/LinearFrame)*currentFrame);

	return *pOut;
}


#endif	//_GAME_EQUATION_H_



