#pragma once

//! @file Mix/Scene/IDynamicsWorld.h
//! @brief ダイナミクスワールドインターフェースインクルードファイル

#include "Mix/Scene/IRendererObject.h"
#include "Mix/Scene/IDynamicsObject.h"

namespace Mix{ namespace Scene{

	//! @class IDynamicsWorld
	//! @brief ダイナミクスワールドインターフェース
	//! @note
	//! ダイナミクスオブジェクトであるフロア、ゴースト、<br>
	//! アクターモデル、テラインモデルのコライダー、センサーなどが配置される、物理ワールドになります。<br>
	//! また、それらに対して光線、スィープを使用して衝突テストをすることもできます。
	class IDynamicsWorld : public Mix::Scene::IRendererObject
	{
	public:
		//! @struct TEST_RESULT
		//! @brief テスト結果構造体
		struct TEST_RESULT
		{
			Mix::Scene::IDynamicsObject* pObject;	//!< ダイナミクスオブジェクトを表す Mix::Scene::IDynamicsObject インターフェースのポインタ
			Mix::Dynamics::MATERIAL material;		//!< マテリアルを表す Mix::Dynamics::MATERIAL 構造体
			Mix::Vector3 worldPos;					//!< ワールド座標を表す Mix::Vector3 クラス
			Mix::Vector3 worldNormal;				//!< ワールド法線を表す Mix::Vector3 クラス
		};

		//! @class TestCallback
		//! @brief テストコールバッククラス
		class TestCallback
		{
		public:
			//! @brief デストラクタ
			virtual ~TestCallback( void ) {}

		public:
			//! @brief ダイナミクスオブジェクトがヒットした際に呼び出されます
			//! @param[in] pObject ヒットしたオブジェクトを表す Mix::Scene::IDynamicsObject インターフェースのポインタ
			virtual Boolean OnHit( Mix::Scene::IDynamicsObject* pObject ) = 0;
		};

		//! @class TestWithoutSelfCallback
		//! @brief テストコールバッククラス(自身を除外)
		class TestWithoutSelfCallback : public Mix::Scene::IDynamicsWorld::TestCallback
		{
		private:
			Mix::Scene::IDynamicsObject* m_pSelfObject;

		public:
			//! @brief コンストラクタ
			//! @param[in] pSelfObject 自身を表す Mix::Scene::IDynamicsObject インターフェースのポインタ
			//! @note 渡したオブジェクトの参照は保持されます
			TestWithoutSelfCallback( Mix::Scene::IDynamicsObject* pSelfObject ) :
			m_pSelfObject( NULL )
			{
				MIX_ASSERT( pSelfObject != NULL );

				MIX_ADD_REF( pSelfObject );
				m_pSelfObject = pSelfObject;
			}

			//! @brief デストラクタ
			virtual ~TestWithoutSelfCallback( void )
			{
				MIX_RELEASE( m_pSelfObject );
			}

			//! @brief オブジェクトがヒットした際に呼び出されます
			//! @param[in] pObject ヒットしたオブジェクトを表す Mix::Scene::IDynamicsObject インターフェースのポインタ
			//! @return 自身として渡したオブジェクトではない場合は True を返します
			virtual Boolean OnHit( Mix::Scene::IDynamicsObject* pObject )
			{
				return ( m_pSelfObject != pObject );
			}
		};

	protected:
		//! @brief デストラクタ
		virtual ~IDynamicsWorld( void ) {}

	public:
		//! @brief 重力を取得します
		//! @return 重力を表す Mix::Vector3 クラスを返します
		virtual const Mix::Vector3& GetGravity( void ) const = 0;
		//! @brief 重力を設定します
		//! @param[in] gravity 重力を表す Mix::Vector3 クラス
		virtual void SetGravity( const Mix::Vector3& gravity ) = 0;

		//! @brief 全てのオブジェクトを活動状態にします
		//! @return 活動状態にできたオブジェクトの数を返します
		virtual UInt32 Activate( void ) = 0;
		//! @brief 全てのオブジェクトを非活動状態にします
		//! @return 非活動状態にできたオブジェクトの数を返します
		virtual UInt32 Deactivate( Boolean bForce = False ) = 0;

		//! @brief 光線でテストします
		//! @param[in] filterMask フィルターマスクを表す Mix::Dynamics::OBJECT_FILTER_FLAG 列挙定数の組み合わせ
		//! @param[in] fromWorldPos 光線の開始位置を表す Mix::Vector3 クラス
		//! @param[in] toWorldPos 光線の終了位置を表す Mix::Vector3 クラス
		//! @param[in] pCallback コールバックを表す Mix::Scene::IDynamicsWorld::TestCallback クラスのポインタ( NULL指定可能 )
		//! @param[out] result テスト結果を表す Mix::Scene::IDynamicsWorld::TEST_RESULT 構造体のアドレス
		//! @return 光線と交差するオブジェクトがあった場合は True を返します
		virtual Boolean TestRay(	UInt16 filterMask,
									const Mix::Vector3& fromWorldPos,
									const Mix::Vector3& toWorldPos,
									Mix::Scene::IDynamicsWorld::TestCallback* pCallback,
									Mix::Scene::IDynamicsWorld::TEST_RESULT& result ) = 0;

		//! @brief スイープでテストします
		//! @param[in] filterMask フィルターマスクを表す Mix::Dynamics::OBJECT_FILTER_FLAG 列挙定数の組み合わせ
		//! @param[in] pShape シェイプを表す Mix::Dynamics::IShape インターフェースのポインタ
		//! @param[in] fromWorldPos シェイプのスィープの開始位置を表す Mix::Vector3 クラス
		//! @param[in] toWorldPos シェイプのスィープの開始位置を表す Mix::Vector3 クラス
		//! @param[in] pCallback コールバックを表す Mix::Scene::IDynamicsWorld::TestCallback クラスのポインタ( NULL指定可能 )
		//! @param[out] result テスト結果を表す Mix::Scene::IDynamicsWorld::TEST_RESULT 構造体のアドレス
		//! @return シェイプと交差するオブジェクトがあった場合は True を返します
		virtual Boolean TestSweep(	UInt16 filterMask,
									Mix::Dynamics::IShape* pShape,
									const Mix::Vector3& fromWorldPos,
									const Mix::Vector3& toWorldPos,
									Mix::Scene::IDynamicsWorld::TestCallback* pCallback,
									Mix::Scene::IDynamicsWorld::TEST_RESULT& result ) = 0;
	};

}}
