#pragma once

//! @file Mix/Dynamics/IRigidBody.h
//! @brief リジッドボディインターフェースインクルードファイル

#include "Mix/Dynamics/IObject.h"

namespace Mix{ namespace Dynamics{

	//! @class IRigidBody
	//! @brief リジッドボディインターフェース
	//! @note
	//! リジッドボディとはワールドに配置することができるオブジェクトであり、種類によって影響の仕方が変わります。<br>
	//! <br>
	//! <b>ダイナミック( Mix::Dynamics::RIGIDBODY_TYPE_DYNAMIC )</b><br>
	//! 質量があり、毎フレームごとに姿勢が更新されます。<br>
	//! <br>
	//! <b>スタティック( Mix::Dynamics::RIGIDBODY_TYPE_STATIC )</b><br>
	//! 質量が 0 であり、衝突はしますが、動くことはありません。<br>
	//! <br>
	//! <b>キネマティック( Mix::Dynamics::RIGIDBODY_TYPE_KINEMATIC )</b><br>
	//! 質量が 0 であり、ダイナミックリジッドボディを押したりすることはできますが、<br>
	//! 他のダイナミックリジッドボディからの影響を受けることはありません。( 押されたりすることはない )<br>
	//! <br>
	//! <b>トリガー( Mix::Dynamics::RIGIDBODY_TYPE_TRIGGER )</b><br>
	//! 質量が 0 であり、他のリジッドボディと衝突することはありません。<br>
	//! <br>
	//! このうち「スタティック」「キネマティック」「トリガー」では以下のメソッドは機能しません。<br>
	//! <br>
	//! SetAlwaysActive
	//! Activate<br>
	//! SetGravityAcceleration<br>
	//! SetLinearDamping<br>
	//! SetAngularDamping<br>
	//! SetLinearVelocity<br>
	//! SetAngularVelocity<br>
	//! ApplyCentralForce<br>
	//! ApplyForce<br>
	//! ApplyTorque<br>
	//! ApplyCentralImpulse<br>
	//! ApplyTorqueImpulse<br>
	//! ApplyImpulse<br>
	//! ClearForces<br>
	//! <br>
	//! これは質量が 0 であることから、無限質量物体として扱われ、何かしらの力が加わっても動かないということを意味します。
	class IRigidBody : public Mix::Dynamics::IObject
	{
	public:
		//! @enum STATUS
		//! @brief ステータス列挙定数
		enum STATUS
		{
			//! @brief デフォルト
			//! @note 「衝突」「応答」を行う、質量を持った物体を表します。
			DEFAULT		= 0,

			//! @brief スタティック
			//! @note 「衝突」のみを行う、動かすことができない質量を持たない物体を表します。
			STATIC		= 1,

			//! @brief キネマティック
			//! @note 「衝突」のみを行う、動かすことができる質量を持たない物体を表します。
			KINEMATIC	= 2,
		};

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

	public:
		//! @brief シミュレーションが有効かどうかを取得します
		//! @return 有効な場合は True を返します
		virtual Boolean IsSimulationEnabled( void ) const = 0;
		//! @brief シミュレーションを有効にするかどうかを設定します
		//! @param[in] state 有効にする場合は True
		virtual void SetSimulationEnabled( Boolean state ) = 0;

		//! @brief 質量を取得します
		//! @return 質量を取得します
		virtual Float32 GetMass( void ) const = 0;
		//! @brief 質量を設定します
		//! @param[in] mass 質量( mass >= 0.0f )
		//! @note
		//! SetStatus で Mix::Dynamics::RIGIDBODY_DEFAULT に設定されている場合に 0.0f 以下の値を設定すると、<br>
		//! 自動的に Mix::Dynamics::RIGIDBODY_STATIC に切り替わります。<br>
		//! また Mix::Dynamics::RIGIDBODY_STATIC に設定されている場合に 0.0f より大きい値が設定されると、
		//! Mix::Dynamics::RIGIDBODY_DEFAULT に切り替わります。<br>
		//! <br>
		//! ※Mix::Dynamics::RIGIDBODY_KINEMATIC に設定されている場合、<br>
		//! GetMass は設定された値を返しますが、内部的には無限質量物体( 質量=0 )のままになります。<br>
		//! SetType で Mix::Dynamics::RIGIDBODY_DEFAULT を設定しない限り、質量物体にはなりません。
		virtual void SetMass( Float32 mass ) = 0;

		//! @brief 状態を取得します
		//! @return 状態を表す Mix::Dynamics::IRigidBody::STATUS 列挙定数を返します
		virtual Mix::Dynamics::IRigidBody::STATUS GetStatus( void ) const = 0;
		//! @brief 状態を設定します
		//! @param[in] status 状態を表す Mix::Dynamics::IRigidBody::STATUS 列挙定数
		//! @return 成功した場合は True を返します
		//! @note 質量が０の状態でステータスをデフォルトに設定しようとした場合、このメソッドは False を返します
		virtual Boolean SetStatus( Mix::Dynamics::IRigidBody::STATUS status ) = 0;

		//! @brief 活動設定を取得します
		//! @return 常に活動状態に設定されている場合は True を返します
		virtual Boolean IsAlwaysActive( void ) const = 0;
		//! @brief 活動設定をします
		//! @param[in] state 常に活動状態にする場合は True
		//! @return 成功した場合は True を返します
		//! @note ステータスが「スタティック」の場合、このメソッドは False を返します
		virtual Boolean SetAlwaysActive( Boolean state ) = 0;

		//! @brief 活動状態を取得します
		//! @return 活動状態の場合は True を返します
		virtual Boolean IsActive( void ) const = 0;
		//! @brief 活動状態にします
		//! @return 成功した場合は True を返します
		//! @note ステータスが「スタティック」の場合、このメソッドは False を返します
		virtual Boolean Activate( void ) = 0;
		//! @brief 非活動状態にします
		//! @param[in] bFroce 強制的に非活動状態にする場合は True
		//! @return 成功した場合は True を返します
		//! @note ステータスが「スタティック」「キネマティック」の場合、このメソッドは False を返します
		virtual Boolean Deactivate( Boolean bFroce = False ) = 0;

		//! @brief 移動のファクタを設定します
		//! @return 移動のファクタを表す Mix::Vector3 クラスを返します
		virtual Mix::Vector3 GetLinearFactor( void ) const = 0;
		//! @brief 移動のファクタを設定します
		//! @param[in] factor 移動のファクタを表す Mix::Vector3 クラス
		//! @note Mix::Vector3( 0.0f, 0.0f, 0.0f ) を指定すると移動しなくなります
		virtual void SetLinearFactor( const Mix::Vector3& factor ) = 0;

		//! @brief 移動の減衰値を取得します
		//! @return 移動の減衰値を返します
		virtual Float32 GetLinearDamping( void ) const = 0;
		//! @brief 移動の減衰値を設定します
		//! @param[in] damping 移動における減衰値( 0.0f <= damping < 1.0f )
		virtual void SetLinearDamping( Float32 damping ) = 0;

		//! @brief 移動速度を取得します
		//! @return 移動速度を表す Mix::Vector3 クラスを返します
		virtual Mix::Vector3 GetLinearVelocity( void ) = 0;
		//! @brief 移動速度を設定します
		//! @param[in] velocity 線形速度を表す Mix::Vector3 クラス
		virtual Boolean SetLinearVelocity( const Mix::Vector3& velocity ) = 0;

		//! @brief 移動を停止する速度を取得します
		//! @return 移動を停止する速度を返します
		virtual Float32 GetLinearSleepingThresholds( void ) const = 0;
		//! @brief 移動を停止する速度を設定します
		//! @param[in] thresholds 移動を停止する速度
		virtual void SetLinearSleepingThresholds( Float32 thresholds ) = 0;

		//! @brief 回転のファクタを設定します
		//! @return 回転のファクタを表す Mix::Vector3 クラスを返します
		virtual Mix::Vector3 GetAngularFactor( void ) const = 0;
		//! @brief 回転のファクタを設定します
		//! @param[in] factor 回転のファクタを表す Mix::Vector3 クラス
		//! @note Mix::Vector3( 0.0f, 0.0f, 0.0f ) を設定すると回転しなくなります
		virtual void SetAngularFactor( const Mix::Vector3& factor ) = 0;

		//! @brief 回転の減衰値を取得します
		//! @return 回転の減衰値を返します
		virtual Float32 GetAngularDamping( void ) const = 0;
		//! @brief 回転の減衰値を設定します
		//! @param[in] damping 回転運動における減衰値( 0.0f <= damping < 1.0f )
		virtual void SetAngularDamping( Float32 damping ) = 0;

		//! @brief 回転速度を取得します
		//! @return 回転速度を表す Mix::Vector3 クラスを返します
		virtual Mix::Vector3 GetAngularVelocity( void ) = 0;
		//! @brief 回転速度を設定します
		//! @param[in] velocity 回転速度を表す Mix::Vector3 クラス
		virtual Boolean SetAngularVelocity( const Mix::Vector3& velocity ) = 0;

		//! @brief 回転を停止する速度を取得します
		//! @return 回転を停止する速度を返します
		virtual Float32 GetAngularSleepingThresholds( void ) const = 0;
		//! @brief 回転を停止する速度を設定します
		//! @param[in] thresholds 回転を停止する速度
		virtual void SetAngularSleepingThresholds( Float32 thresholds ) = 0;

		//! @brief 移動に撃力を適用します
		//! @param[in] impulse 適用する撃力を表す Mix::Vector3 クラス
		virtual Boolean ApplyLinearImpulse( const Mix::Vector3& impulse ) = 0;
		//! @brief 回転に撃力を適用します
		//! @param[in] impulse 適用する撃力を表す Mix::Vector3 クラス
		virtual Boolean ApplyAngularImpulse( const Mix::Vector3& impulse ) = 0;
		//! @brief 指定した位置に撃力を適用します
		//! @param[in] impulse 適用する撃力を表す Mix::Vector3 クラス
		//! @param[in] pos 撃力を適用する位置を表す Mix::Vector3 クラス
		virtual Boolean ApplyImpulse( const Mix::Vector3& impulse, const Mix::Vector3& pos ) = 0;

		//! @brief 移動に適用されている力を取得します
		//! @return 力を表す Mix::Vector3 クラスを返します
		virtual Mix::Vector3 GetTotalLinearForce( void ) = 0;
		//! @brief 回転に適用されている力を取得します
		//! @return 力を表す Mix::Vector3 クラスを返します
		virtual Mix::Vector3 GetTotalAngularForce( void ) = 0;
		//! @brief 移動に力を適用します
		//! @param[in] force 適用する力を表す Mix::Vector3 クラス
		virtual Boolean ApplyLinearForce( const Mix::Vector3& force ) = 0;
		//! @brief 回転に力を適用します
		//! @param[in] force 適用する力を表す Mix::Vector3 クラス
		virtual Boolean ApplyAngularForce( const Mix::Vector3& force ) = 0;
		//! @brief 指定した位置に力を適用します
		//! @param[in] force 適用する力を表す Mix::Vector3 クラス
		//! @param[in] pos 力を適用する位置を表す Mix::Vector3 クラス
		virtual Boolean ApplyForce( const Mix::Vector3& force, const Mix::Vector3& pos ) = 0;
		//! @brief 適用されている力をクリアします
		virtual void ClearForce( void ) = 0;

		//! @brief モーションをクリアします
		//! @note 全ての速度、全てのフォース、補間用パラメータをクリアします
		virtual void ClearMotion( void ) = 0;
		//! @brief モーションをクリアします
		//! @param[in] rot クリア後の回転を表す Mix::Quaternion クラス
		//! @param[in] pos クリア後の位置を表す Mix::Vector3 クラス
		virtual void ClearMotion( const Mix::Quaternion& rot, const Mix::Vector3& pos ) = 0;

		//! @brief 慣性テンソルを更新します
		//! @return 成功した場合は True を返します
		//! @note
		//! 形状が変化するシェイプ、主にコンパウンドシェイプ( Mix::Dynamics::ICompoundShape ) に子を追加した際に使用します。<br>
		//! また GetStatus で返される値が Mix::Dynamics::RIGIDBODY_STATIC もしくわ  Mix::Dynamics::RIGIDBODY_KINEMATIC の場合は、常に False を返します。<br>
		virtual Boolean UpdateLocalInertia( void ) = 0;
	};

}}
