/****************************************************************************
 *
 *	Copyright (c) 1999-2012, Fine Kernel Project, All rights reserved.
 *
 *	Redistribution and use in source and binary forms,
 *	with or without modification, are permitted provided that the
 *	following conditions are met:
 *
 *		- Redistributions of source code must retain the above
 *			copyright notice, this list of conditions and the
 *			following disclaimer.
 *
 *		- Redistributions in binary form must reproduce the above
 *			copyright notice, this list of conditions and the
 *			following disclaimer in the documentation and/or
 *			other materials provided with the distribution.
 *
 *		- Neither the name of the copyright holders nor the names
 *			of its contributors may be used to endorse or promote
 *			products derived from this software without specific
 *			prior written permission.
 *
 *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *	LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *	FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *	COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *	SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 *	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 *	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *	POSSIBILITY OF SUCH DAMAGE. 
 *
 ****************************************************************************/
/****************************************************************************
 *
 *	Copyright (c) 1999-2012, Fine Kernel Project, All rights reserved.
 *
 *	本ソフトウェアおよびソースコードのライセンスは、基本的に
 *	「修正 BSD ライセンス」に従います。以下にその詳細を記します。
 *
 *	ソースコード形式かバイナリ形式か、変更するかしないかを問わず、
 *	以下の条件を満たす場合に限り、再頒布および使用が許可されます。
 *
 *	- ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、
 *		および下記免責条項を含めること。
 *
 *	- バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の
 *		資料に、上記の著作権表示、本条件一覧、および下記免責条項を
 *		含めること。
 *
 *	- 書面による特別の許可なしに、本ソフトウェアから派生した製品の
 *		宣伝または販売促進に、本ソフトウェアの著作権者の名前または
 *		コントリビューターの名前を使用してはならない。
 *
 *	本ソフトウェアは、著作権者およびコントリビューターによって「現
 *	状のまま」提供されており、明示黙示を問わず、商業的な使用可能性、
 *	および特定の目的に対する適合性に関す暗黙の保証も含め、またそれ
 *	に限定されない、いかなる保証もないものとします。著作権者もコン
 *	トリビューターも、事由のいかんを問わず、損害発生の原因いかんを
 *	問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その
 *	他の)不法行為であるかを問わず、仮にそのような損害が発生する可
 *	能性を知らされていたとしても、本ソフトウェアの使用によって発生
 *	した(代替品または代用サービスの調達、使用の喪失、データの喪失、
 *	利益の喪失、業務の中断も含め、またそれに限定されない)直接損害、
 *	間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害に
 *	ついて、一切責任を負わないものとします。
 *
 ****************************************************************************/
#ifndef __FK_MODEL_HEADER__
#define __FK_MODEL_HEADER__

#include <FK/MatAdmin.h>
#include <FK/Palette.h>
#include <FK/Angle.h>

class fk_Material;
class fk_Shape;
class fk_TreeData;

typedef unsigned int fk_DrawMode;

const fk_DrawMode FK_NONEMODE			= 0x0000;
const fk_DrawMode FK_POINTMODE			= 0x0001;
const fk_DrawMode FK_LINEMODE			= 0x0002;
const fk_DrawMode FK_POLYMODE			= 0x0004;
const fk_DrawMode FK_BACK_POLYMODE		= (0x0008 | FK_POLYMODE);
const fk_DrawMode FK_FRONTBACK_POLYMODE	= (0x0010 | FK_POLYMODE);
const fk_DrawMode FK_TEXTUREMODE		= 0x0020;

#ifndef FK_DOXYGEN_USER_PROCESS

enum fk_BoundaryMode {
	FK_SPHERE_B,
	FK_BOX_B,
	FK_CAPSULE_B
};

#endif

//! モデルを生成、管理するクラス
/*!
 *	このクラスは、「モデル」を制御する機能を提供します。
 *	FK における「モデル」とは、位置や方向を持ったオブジェクトのことを指します。
 *	利用者は、このクラスを通じてカメラを含むオブジェクトの位置や姿勢を制御していきます。
 *	従って、このクラスは FK システムにおいて最も中心的な存在であると言えます。
 *	位置や姿勢を制御するための関数の多くは、 fk_MatrixAdmin クラスから継承しています。
 *	(ただし、後述する「親子関係」に関連する機能は本クラス自体が持っています。)
 *	fk_MatrixAdmin クラスの説明も合わせて参照して下さい。
 *
 *	FK において、モデルと形状は別の存在として扱います。
 *	形状は別のクラスで作成しておき、モデルに対して形状をリンクするという考え方です。
 *	このような設計になっている利点は、
 *	まず第1に1つのモデルが複数の形状を使い分けられるということがあります。
 *	第2に、1つの形状を複数のモデルで共有することでメモリ利用量を削減できます。
 *	形状については fk_Shape クラスおよびその派生クラスを参照して下さい。
 *
 *	位置や姿勢の制御と共に、このクラスの重要な機能の1つが「親子関係」です。
 *	あるモデルを別のモデルに「子モデル」として登録したとします。
 *	親モデルの位置や姿勢を制御すると、
 *	子モデルの形状は親モデル内の形状と同じように追従するようになります。
 *	例えば、車を車体モデルとタイヤモデルで別々に作成し、
 *	タイヤモデルを車体モデルの子モデルとして登録しておけば、
 *	車体モデルの位置移動にあわせてタイヤモデルも位置関係を維持しながら一緒に移動します。
 *	マテリアルや頂点色、稜線色については、
 *	何も設定しない場合は親モデルの設定が用いられます。
 *	それぞれのモデルにマテリアルや色属性を設定した場合、
 *	そのモデルについては個々の設定が利用されるようになります。
 *
 *	\sa fk_MatrixAdmin, fk_Shape, fk_Scene, fk_DisplayLink
 */

class fk_Model : public fk_MatrixAdmin {

 private:
	fk_Material			*material;
	fk_Color			*pointColor;
	fk_Color			*lineColor;
	fk_Shape			*shape;
	fk_Model			*parent;
	fk_TreeData			*treeData;
	bool				materialFlag;
	fk_DrawMode			drawMode;
	fk_MaterialMode		materialMode;
	double				drawSize;
	double				drawWidth;
	bool				pickFlag;
	bool				smoothFlag;
	bool				reverseFlag;
	bool				treeFlag;
	unsigned int		_modelID;

	fk_BoundaryMode		boundaryMode;

	fk_HVector			snapPos;
	fk_HVector			snapInhPos;
	fk_Angle			snapAngle;
	bool				snapFlag;

	double				sbRadius;

	void				EntryTree(void);
	void				DeleteTree(void);
	fk_TreeData *		GetTreeData(fk_Model *);

 public:

	//! コンストラクタ
	/*!
	 *	\param[in]	shape
	 *		形状インスタンスのポインタ。
	 *		NULL を代入した場合や引数を省略した場合は、
	 *		初期形状が無い状態になります。
	 */
	fk_Model(fk_Shape *shape = (fk_Shape *)NULL);

	//! デストラクタ
	virtual ~fk_Model();


	//! ID参照関数
	/*!
	 *	モデルの固有IDを取得します。
	 *	IDの最小値は 1 で、
	 *	同一プロセス中では同じ ID が別のモデルに割り振られることはありません。
	 *
	 *	\return		固有モデルID
	 */
	unsigned int			getID(void) const;

	//! \name 形状データ制御関数
	//@(

	//! 形状設定関数
	/*!
	 *	モデルの形状を設定します。
	 *	形状は、 fk_Shape クラスの派生クラスであれば設定可能です。
	 *	なお、呼ぶ前に形状が設定されていた場合、前の設定は破棄されます。
	 *
	 *	設定した形状インスタンスは、モデルに設定した状態で解放しないようにしてください。
	 *	もし解放された場合、プログラムが誤動作を起こします。
	 *
	 *	\param[in]	shape		形状インスタンスのポインタ

	 */
	void					setShape(fk_Shape *shape);

	//! 形状参照関数
	/*!
	 *	現在設定されている形状を取得します。
	 *	形状が設定されていない場合は NULL を返します。
	 *
	 *	\return		形状インスタンスのポインタ
	 */
	fk_Shape *				getShape(void) const;

	//@)

	//! \name マテリアル属性設定関数
	//@(
	//! マテリアル設定関数
	/*!
	 *	モデルの基本マテリアルを設定します。
	 *	マテリアルに関しての詳細は、
	 *	fk_Material の説明およびユーザーズマニュアルを参照して下さい。
	 *
	 *	\note
	 *	稜線の色は setLineColor(), 
	 *	頂点の色は setPointColor() を利用して設定して下さい。
	 *	個別位相要素のマテリアルとの制御については、
	 *	setMaterialMode() を参照して下さい。
	 *	テクスチャを描画する際には、テクスチャモードによって混合の仕方が異なりますので、
	 *	fk_Texture::setTextureMode() を参照して下さい。
	 *
	 *	\param[in]	mat		マテリアル
	 *
	 *	\sa fk_Material, setLineColor(), setPointColor(), fk_Texture::setTextureMode()
	 */
	void					setMaterial(const fk_Material &mat);

	//! 頂点色設定関数1
	/*!
	 *	モデルの頂点色を設定します。
	 *	頂点は、光源による陰影の影響はなく、常に設定色で表示されます。
	 *
	 *	\param[in]	col		頂点色のポインタ
	 *
	 *	\sa fk_Color
	 */
	void					setPointColor(fk_Color *col);

	//! 頂点色設定関数2
	/*!
	 *	モデルの頂点色を設定します。
	 *	頂点は、光源による陰影の影響はなく、常に設定色で表示されます。
	 *	各色要素は 0 から 1 までの値を取ります。
	 *	それ以外の値が与えられた場合、0 以下なら 0 に、1 以上なら 1 に丸められます。
	 *
	 *	\param[in]	r		頂点色の赤要素
	 *	\param[in]	g		頂点色の緑要素
	 *	\param[in]	b		頂点色の青要素
	 */
	void					setPointColor(float r, float g, float b);

	//! 稜線色設定関数1
	/*!
	 *	モデルの稜線色を設定します。
	 *	稜線は、光源による陰影の影響はなく、常に設定色で表示されます。
	 *
	 *	\param[in]	col		稜線色のポインタ
	 *
	 *	\sa fk_Color
	 */
	void					setLineColor(fk_Color *col);

	//! 稜線色設定関数2
	/*!
	 *	モデルの稜線色を設定します。
	 *	稜線は、光源による陰影の影響はなく、常に設定色で表示されます。
	 *	各色要素は 0 から 1 までの値を取ります。
	 *	それ以外の値が与えられた場合、0 以下なら 0 に、1 以上なら 1 に丸められます。
	 *
	 *	\param[in]	r		稜線色の赤要素
	 *	\param[in]	g		稜線色の緑要素
	 *	\param[in]	b		稜線色の青要素
	 */
	void					setLineColor(float r, float g, float b);

	//! 基本マテリアル削除関数
	/*!
	 *	基本マテリアル設定を削除します。
	 *	これにより、親モデルが存在する場合は親モデルの基本マテリアルを継承します。
	 *	親モデルが存在しない場合は、システムのデフォルトマテリアルが採用されます。
	 */
	void					deleteMaterial(void);

	//! 頂点色削除関数
	/*!
	 *	頂点色設定を削除します。
	 *	これにより、親モデルが存在する場合は親モデルの頂点色を継承します。
	 *	親モデルが存在しない場合は、システムのデフォルト頂点色が採用されます。
	 */
	void					deletePointColor(void);

	//! 稜線色削除関数
	/*!
	 *	稜線色設定を削除します。
	 *	これにより、親モデルが存在する場合は親モデルの稜線色を継承します。
	 *	親モデルが存在しない場合は、システムのデフォルト稜線色が採用されます。
	 */
	void					deleteLineColor(void);
	//@)

	//! \name マテリアル属性参照関数
	//@(
	//! マテリアル参照関数
	/*!
	 *	現在モデルに設定されている基本マテリアルを参照します。
	 *	モデルにマテリアルが設定されていない場合は NULL を返します。
	 *
	 *	\return		基本マテリアルのポインタ
	 *
	 *	\sa fk_Material, setMaterial(), getInhMaterial()
	 */
	fk_Material *			getMaterial(void);

	//! 継承マテリアル参照関数
	/*!
	 *	親子関係を踏まえた基本マテリアルを参照します。
	 *	当モデルにマテリアルが設定されている場合、そのマテリアルを返します。
	 *	当モデルにマテリアルが設定されていない場合は、親モデルのマテリアルを返します。
	 *
	 *	\return		継承マテリアルのポインタ
	 *
	 *	\sa fk_Material, setMaterial(), getMaterial()
	 */
	fk_Material *			getInhMaterial(void);

	//! 頂点色参照関数
	/*!
	 *	現在モデルに設定されている頂点色を参照します。
	 *	モデルに頂点色が設定されていない場合は NULL を返します。
	 *
	 *	\return		頂点色のポインタ
	 *
	 *	\sa fk_Color, setPointColor(), getInhPointColor()
	 */
	fk_Color *				getPointColor(void);

	//! 継承頂点色参照関数
	/*!
	 *	親子関係を踏まえた頂点色を参照します。
	 *	当モデルに頂点色が設定されている場合、その頂点色を返します。
	 *	当モデルに頂点色が設定されていない場合は、親モデルの頂点色を返します。
	 *
	 *	\return		頂点色のポインタ
	 *
	 *	\sa fk_Color, setPintColor(), getPointColor()
	 */
	fk_Color *				getInhPointColor(void);

	//! 稜線色参照関数
	/*!
	 *	現在モデルに設定されている稜線色を参照します。
	 *	モデルに稜線色が設定されていない場合は NULL を返します。
	 *
	 *	\return		稜線色のポインタ
	 *
	 *	\sa fk_Color, setLineColor(), getInhLineColor()
	 */
	fk_Color *				getLineColor(void);

	//! 継承稜線色参照関数
	/*!
	 *	親子関係を踏まえた稜線色を参照します。
	 *	当モデルに稜線色が設定されている場合、その稜線色を返します。
	 *	当モデルに稜線色が設定されていない場合は、親モデルの稜線色を返します。
	 *
	 *	\return		稜線色のポインタ
	 *
	 *	\sa fk_Color, setLineColor(), getLineColor()
	 */
	fk_Color *				getInhLineColor(void);
	//@)

	//! \name 描画属性制御関数
	//@(

	//! 頂点描画サイズ設定関数
	/*!
	 *	頂点の描画サイズを設定します。
	 *	単位はピクセルです。整数以外も設定可能です。
	 *
	 *	/param[in]	size	頂点描画サイズ
	 */
	void					setSize(const double size);

	//! 稜線描画幅設定関数
	/*!
	 *	稜線の描画幅を設定します。
	 *	単位はピクセルです。整数以外も設定可能です。
	 *
	 *	\param[in]	width	稜線幅
	 */
	void					setWidth(const double width);

	//! 頂点描画サイズ参照関数
	/*!
	 *	頂点の描画サイズを取得します。
	 *
	 *	\return		頂点描画サイズ
	 */
	double					getSize(void) const;

	//! 稜線描画幅設定関数
	/*!
	 *	稜線の描画幅を取得します。
	 *
	 *	\return		稜線幅
	 */
	double					getWidth(void) const;
	//@)

	//! \name 描画モード制御関数
	//@(

	//! 描画モード設定関数
	/*!
	 *	モデルの描画モードを設定します。
	 *	描画モードとは、
	 *	面、稜線、頂点のそれぞれを描画するかどうかを制御するものです。
	 *	描画モードには以下のようなものがあります。
	 *	- FK_NONEMODE:				何も描画しません。
	 *	- FK_POINTMODE:				頂点を描画します。
	 *	- FK_LINEMODE:				稜線を描画します。
	 *	- FK_POLYMODE:				面の表を描画します。
	 *	- FK_BACK_POLYMODE:			面の裏を描画します。
	 *	- FK_FRONTBACK_POLYMODE:	面の表と裏を描画します。
	 *	- FK_TEXTUREMODE:			テクスチャを描画します。
	 *	.
	 *	これらの描画モードは、
	 *	ビット論理和を用いて複数のものを同時に指定することが可能です。
	 *	以下のコードは、頂点、稜線、面の表をすべて描画するように設定します。
	 *	\code
	 *	fk_Model		model;
	 *
	 *	model.setDrawMode(FK_POINTMODE | FK_LINEMODE | FK_POLYMODE);
	 *	\endcode
	 *
	 *	\param[in]	mode	描画モード
	 */
	void					setDrawMode(const fk_DrawMode mode);

	//! 描画モード参照関数
	/*!
	 *	現在の描画モードを参照します。
	 *
	 *	\return		描画モード
	 *
	 *	\sa setDrawMode()
	 */
	fk_DrawMode				getDrawMode(void) const;

	//! マテリアルモード設定関数
	/*!
	 *	形状中の各要素を描画する際に、どの要素のマテリアルを採用するかを設定します。
	 *	マテリアルの採用は、以下のような優先順で決定します。
	 *	-# fk_Model のマテリアルモードが FK_CHILD_MODE の場合、
	 *		モデルのマテリアルが採用されます。
	 *		FK_NONE_MODE の場合は描画されません。
	 *		FK_PARENT_MODE の場合は以下の条件に従います。
	 *	-# fk_Shape の派生クラスにてマテリアルモードが
	 *		FK_CHILD_MODE になっている場合、形状のマテリアルが採用されます。
	 *		FK_NONE_MODE の場合は描画されません。
	 *		FK_PARENT_MODE の場合は以下の条件に従います。
	 *		(fk_Shape::setMaterialMode() を参照して下さい。)
	 *	-# 各位相要素でのマテリアルモードが、
	 *		FK_CHILD_MODE になっている場合は個別のマテリアルが採用されます。
	 *		FK_NONE_MODE の場合は描画されません。
	 *		FK_PARENT_MODE の場合はモデルのマテリアルが採用されます。
	 *		(fk_TopologyMaterial::setElemMaterialMode() を参照して下さい。)
	 *
	 *	\param[in]	mode
	 *		マテリアルモードを設定します。与えられる値は以下の3種類です。
	 *		\arg FK_CHILD_MODE
	 *		\arg FK_PARENT_MODE
	 *		\arg FK_NONE_MODE
	 *
	 *	\sa getMaterialMode(), fk_Shape::setMaterialMode(), fk_TopologyMaterial::setElemMaterialMode()
	 */
	void					setMaterialMode(const fk_MaterialMode mode);

	//! マテリアルモード参照関数
	/*!
	 *	モデルのマテリアルモードを取得します。
	 *
	 *	\return		マテリアルモード
	 *
	 *	\sa setMaterialMode()
	 */
	fk_MaterialMode			getMaterialMode(void) const;

	//! ピックモード設定関数
	/*!
	 *	モデルのピックモードを設定します。
	 *	ピックモードとは、
	 *	モデルをピックによる取得操作の対象とするかどうかを制御するものです。
	 *	ピックモードが有効である場合、モデルはピック取得の候補となります。
	 *	デフォルトでは無効となっています。
	 *
	 *	\param[in]	mode	true である場合、ピックモードが有効となります。
	 *		false である場合は無効となります。
	 *
	 *	\sa fk_Window::getPickModel(), fk_PickData
	 */
	void					setPickMode(const bool mode);

	//! ピックモード参照関数
	/*!
	 *	現在のピックモードを取得します。
	 *
	 *	\return		有効である場合 true を、無効である場合 false を返します。
	 *
	 *	\sa setPickMode(), fk_Window::getPickModel(), fk_PickData
	 */
	bool					getPickMode(void) const;

	//! スムースモード設定関数
	/*!
	 *	モデルのスムースモードを設定します。
	 *	スムースモードを有効にすると、
	 *	形状の隣り合う面同士の法線ベクトルが補間され、
	 *	擬似的に滑らかな曲面として表示を行うようになります。
	 *
	 *	\param[in]	mode	true である場合、スムースモードを有効とします。
	 *		false である場合無効とします。
	 */
	void					setSmoothMode(const bool mode);

	//! スムースモード参照関数
	/*!
	 *	現在のモデルのスムースモードを取得します。
	 *
	 *	\return		有効である場合 true を、無効である場合 false を返します。
	 *
	 *	\sa setSmoothMode()
	 */
	bool					getSmoothMode(void) const;

	//! 描画順序制御関数
	/*!
	 *	この関数では、モデルの持つ位相要素の描画順序を制御します。
	 *	モデルの各位相要素が同一平面上にあり、描画順序を逆にしたい場合に用います。
	 *
	 *	\param[in]	mode
	 *		true の場合、モデル内の描画が通常と逆順になります。
	 *		false の場合、順序を通常の状態に戻します。
	 */
	void					setReverseDrawMode(const bool mode);

	//! 描画順序参照関数
	/*!
	 *	setReverseDrawMode() で設定した描画順序を取得します。
	 *
	 *	\return		逆順である場合 true を、正順である場合 false を返します。
	 *
	 *	\sa setReverseDrawMode()
	 */
	bool					getReverseDrawMode(void) const;
	//@)

	//! \name 座標系情報参照関数
	//@(

	//! 継承変換行列取得関数
	/*!
	 *	モデルの位置と姿勢を表す変換行列を取得します。
	 *	当モデルに親モデルがあった場合、
	 *	その親モデルの変換行列と当モデルの変換行列の積が返されます。
	 *	結果として、この関数を用いることでグローバル座標系における
	 *	当モデルの変換行列を得ることができます。
	 *	親モデルが設定されていない場合は、
	 *	fk_MatrixAdmin::getMatrix() と結果が同じとなります。
	 *
	 *	\return		モデルの継承変換行列
	 *
	 *	\sa fk_MatrixAdmin::getMatrix(), getInhInvMatrix()
	 */
	fk_Matrix				getInhMatrix(void) const;

	//! 継承逆変換行列取得関数
	/*!
	 *	モデルの位置と姿勢を表す変換行列の、逆行列を取得します。
	 *	これは、 getInhMatrix() で得られる行列の逆行列となります。
	 *	当モデルに親モデルがあった場合、
	 *	その親モデルの逆変換行列と当モデルの逆変換行列の積が返されます。
	 *	結果として、この関数を用いることでグローバル座標系における
	 *	当モデルの逆変換行列を得ることができます。
	 *	親モデルが設定されていない場合は、
	 *	fk_MatrixAdmin::getInvMatrix() と結果が同じとなります。
	 *
	 *	\return		モデルの継承逆変換行列
	 *
	 *	\sa fk_MatrixAdmin::getInvMatrix(), getInhMatrix()
	 */
	fk_Matrix				getInhInvMatrix(void) const;

	//! 継承移動・回転要素変換行列取得関数
	/*!
	 *	モデルの持つ変換要素のうち、
	 *	位置と姿勢のみを反映した、
	 *	すなわち拡大縮小の要素を省いた変換行列を取得します。
	 *	当モデルに親モデルがあった場合、
	 *	その親モデルの変換行列と当モデルの変換行列の積が返されます。
	 *	その結果として、この関数を用いることでグローバル座標系における
	 *	当モデルの変換行列を得ることができます。
	 *	親モデルが設定されていない場合は、
	 *	fk_MatrixAdmin::getBaseMatrix() と結果が同じとなります。
	 *
	 *	\return		モデルの継承移動・回転要素変換行列
	 *
	 *	\sa fk_MatrixAdmin::getBaseMatrix(), getInhMatrix(), getInhInvBaseMatrix()
	 */
	fk_OrthoMatrix			getInhBaseMatrix(void) const;

	//! 継承移動・回転要素逆変換行列取得関数
	/*!
	 *	モデルの持つ変換要素のうち、
	 *	位置と姿勢のみを反映した、
	 *	すなわち拡大縮小の要素を省いた変換行列の逆行列を取得します。
	 *	当モデルに親モデルがあった場合、
	 *	その親モデルの逆変換行列と当モデルの逆変換行列の積が返されます。
	 *	その結果として、この関数を用いることでグローバル座標系における
	 *	当モデルの逆変換行列を得ることができます。
	 *	親モデルが設定されていない場合は、
	 *	fk_MatrixAdmin::getInvBaseMatrix() と結果が同じとなります。
	 *
	 *	\return		モデルの継承移動・回転要素逆変換行列
	 *
	 *	\sa fk_MatrixAdmin::getInvBaseMatrix(), getInhInvMatrix(), getInhBaseMatrix()
	 */
	fk_OrthoMatrix			getInhInvBaseMatrix(void) const;

	//! 継承位置ベクトル参照関数
	/*!
	 *	モデルの位置ベクトルを取得します。
	 *	本関数は、親モデルの有無にかかわらずグローバル座標系の位置ベクトルを返します。
	 *
	 *	\return		グローバル座標系での位置ベクトル
	 *
	 *	\sa getInhVec(), getInhUpvec(), getInhAngle(), fk_MatrixAdmin::getPosition()
	 */
	fk_Vector				getInhPosition(void) const;

	//! 継承方向ベクトル参照関数
	/*!
	 *	モデルの方向ベクトルを取得します。
	 *	本関数は、親モデルの有無にかかわらずグローバル座標系の方向ベクトルを返します。
	 *
	 *	\return		グローバル座標系での方向ベクトル
	 *
	 *	\sa getInhPosition(), getInhUpvec(), getInhAngle(), fk_MatrixAdmin::getVec()
	 */
	fk_Vector				getInhVec(void) const;

	//! 継承アップベクトル参照関数
	/*!
	 *	モデルのアップベクトルを取得します。
	 *	本関数は、親モデルの有無にかかわらずグローバル座標系のアップベクトルを返します。
	 *
	 *	\return		グローバル座標系でのアップベクトル
	 *
	 *	\sa getInhPosition(), getInhVec(), getInhAngle(), fk_MatrixAdmin::getUpvec()
	 */
	fk_Vector				getInhUpvec(void) const;

#ifndef FK_DOXYGEN_USER_PROCESS
	fk_Vector				getInhUpVec(void) const;
#endif

	//! 継承オイラー角参照関数
	/*!
	 *	モデルのオイラー角を取得します。
	 *	本関数は、親モデルの有無にかかわらずグローバル座標系のオイラー角を返します。
	 *	オイラー角の詳細については、 fk_Angle の説明を参照して下さい。
	 *
	 *	\return		グローバル座標系でのオイラー角
	 *
	 *	\sa getInhPosition(), getInhVec(), getInhUpvec(), fk_MatrixAdmin::getAngle(), fk_Angle
	 */
	fk_Angle				getInhAngle(void) const;
	//@)

	//! \name 親子関係制御関数
	//@(

	//! 親モデル設定関数
	/*!
	 *	親モデルを設定します。
	 *	親モデルは 1 個しか設定できません。
	 *	前に設定されていた場合は、前のモデル設定は破棄されます。
	 *
	 *	\param[in]		model		親モデルインスタンスのポインタ
	 *	\param[in]		setMode
	 *		true の場合、現在のグローバル座標系の位置と姿勢を、
	 *		親モデル設定後も保持します。
	 *		false の場合は、当モデルでの位置と姿勢を親モデルからの
	 *		相対的な位置、姿勢として扱います。
	 *		そのため、設定後にグローバル座標系での位置や姿勢は変化することになります。
	 *		この引数を省略した場合は false と同様の挙動となります。
	 *
	 *	\return		設定に成功すれば true を、失敗すれば false を返します。
	 *
	 *	\sa deleteParent(), getParent(), entryChild()
	 */
	bool					setParent(fk_Model *model, bool setMode = false);

	//! 親モデル解除関数
	/*!
	 *	親モデルの設定を解除します。
	 *
	 *	\param[in]		setMode
	 *		true の場合、現在のグローバル座標系の位置と姿勢を、
	 *		親モデル解除後も保持します。
	 *		false の場合は、親モデルからの相対的な位置と姿勢を、
	 *		解除後のグローバル座標系に設定します。
	 *		この引数を省略した場合は false と同様の挙動となります。
	 *
	 *	\sa setParent(), getParent(), deleteChild()
	 */
	void					deleteParent(bool setMode = false);

	//! 親モデル参照関数
	/*!
	 *	親モデルを取得します。
	 *
	 *	\return		親モデルインスタンスのポインタ。
	 *		親モデルが設定されていない場合は NULL を返します。
	 *
	 *	\sa setParent(), deleteParent()
	 */
	fk_Model *				getParent(void) const;

	//! 子モデル設定関数
	/*!
	 *	子モデルを設定します。
	 *	子モデルは複数持つことが可能なので、
	 *	既に子モデルが登録されている場合でも、その設定は破棄されません。
	 *
	 *	\param[in]		model		子モデルインスタンスのポインタ
	 *	\param[in]		setMode
	 *		true の場合、子モデルの現在のグローバル座標系の位置と姿勢を、
	 *		設定後も保持します。
	 *		false の場合は、子モデルでの位置と姿勢を当モデルからの
	 *		相対的な位置、姿勢として扱います。
	 *		そのため、設定後にグローバル座標系での位置や姿勢は変化することになります。
	 *		この引数を省略した場合は false と同様の挙動となります。
	 *
	 *	\return		設定に成功すれば true を、失敗すれば false を返します。
	 *
	 *	\sa setParent(), deleteChild(), deleteChildren(), foreachChild()
	 */
	bool					entryChild(fk_Model *model, bool setMode = false);

	//! 子モデル解除関数
	/*!
	 *	子モデルの設定を解除します。
	 *
	 *	\param[in]		model
	 *		子モデルインスタンスのポインタ。
	 *		もし model が子モデルの中に存在しない場合は、false を返します。
	 *	\param[in]		setMode
	 *		true の場合、子モデルのグローバル座標系の位置と姿勢を、
	 *		解除後も保持します。
	 *		false の場合は、親モデルからの相対的な位置と姿勢を、
	 *		解除後のグローバル座標系に設定します。
	 *		この引数を省略した場合は false と同様の挙動となります。
	 *
	 *	\return		解除に成功すれば true を、失敗すれば false を返します。
	 *
	 *	\sa entryChild(), deleteChildren(), foreachChild()
	 */
	bool					deleteChild(fk_Model *model, bool setMode = false);

	//! 全子モデル解除関数
	/*!
	 *	当モデルの全ての子モデルの設定を解除します。
	 *
	 *	\param[in]		setMode
	 *		true の場合、子モデルのグローバル座標系の位置と姿勢を、
	 *		解除後も保持します。
	 *		false の場合は、親モデルからの相対的な位置と姿勢を、
	 *		解除後のグローバル座標系に設定します。
	 *		この引数を省略した場合は false と同様の挙動となります。
	 *
	 *	\sa entryChild(), deleteChild(), foreachChild()
	 */
	void					deleteChildren(bool setMode = false);

	//! 子モデル逐次参照関数
	/*!
	 *	当モデルに設定されている子モデルを順番に帰します。
	 *	まず、引数に NULL を渡したとき、1番目の子モデルを返します。
	 *	子モデルが存在しない場合は、その時点で NULL を返します。
	 *	次に、1番目に帰ってきたモデルを引数として渡したとき、
	 *	2番目の子モデルを返します。
	 *	このように、設定されている子モデルを順番に参照することができます。
	 *	最後の子モデルが引数として渡されたとき、NULL を返します。
	 *
	 *	以下のコードは、「parent」の全ての子モデルに対し、
	 *	描画モードを FK_LINEMODE に設定する例です。
	 *	\code
	 *	fk_Model	parentModel, *childModel;
	 *
	 *	for(childModel = parentModel.foreachChild(NULL);
	 *		childModel != NULL;
	 *		childModel = parentModel.foreachChild(childModel)) {
	 *
	 *		childModel->setDrawMode(FK_LINEMODE);
	 *	}
	 *	\endcode
	 *
	 *	\param[in]		model		順番に渡す子モデルインスタンスのポインタ
	 *
	 *	\return		次にあたる子モデルインスタンスのポインタ。
	 *		引数に最後の子モデルが渡された場合、NULL を返します。
	 *
	 *	\sa entryChild(), deleteChild(), deleteChildren()
	 */
	fk_Model *				foreachChild(fk_Model *model);

	//@)

	//! \name 状態保存制御関数
	//@(

	//! 位置・姿勢保存関数
	/*!
	 *	現時点でのモデルの位置と姿勢を保存します。
	 *	restore() 関数を用いることで復元します。
	 *
	 *	\sa restore()
	 */
	void					snapShot(void);

	//! 位置・姿勢復元関数
	/*!
	 *	snapShot() 関数によって保存した位置・姿勢を復元します。
	 *
	 *	\return		復元に成功すれば true を、失敗すれば false を返します。
	 */
	bool					restore(void);

	//! 位置・姿勢途中復元関数
	/*!
	 *	snapShot() 関数によって保存した位置・姿勢に対し、
	 *	現在の位置・姿勢と線形補間した状態にします。
	 *
	 *	\param[in]	t
	 *		線形補間パラメータ。
	 *		0 を snapShot() 関数による保存時、
	 *		1 を現時点とし、
	 *		与えられた実数によって線形補間した位置と姿勢に設定します。
	 *
	 *	\return		設定に成功すれば true を、失敗すれば false を返します。
	 */
	bool					restore(double t);

	//@)

	//! \name 描画制御用関数
	//@(

	//! 描画処理事前関数
	/*!
	 *	この関数は、
	 *	描画エンジン内部でモデルが実際に描画される前に自動的に呼び出されます。
	 *	デフォルトの状態では中身は空ですが、
	 *	fk_Model クラスの派生クラスを作成した上で、
	 *	この関数を上書きすることにより、
	 *	描画処理前の時点の処理を記述することが可能です。
	 *	主な利用用途はシェーダプログラミングやデバッグ、
	 *	あるいは独自形状描画などが考えられます。
	 *
	 *	本関数を利用するには、FK の描画エンジン内部に精通している必要があります。
	 *	ソースコードを解析し、内部処理を理解した上で利用することを推奨します。
	 */
	virtual void			preShader(void) {};

	//! 描画処理事後関数
	/*!
	 *	この関数は、
	 *	描画エンジン内部でモデルが実際に描画された後に自動的に呼び出されます。
	 *	デフォルトの状態では中身は空ですが、
	 *	fk_Model クラスの派生クラスを作成した上で、
	 *	この関数を上書きすることにより、
	 *	描画処理後の時点の処理を記述することが可能です。
	 *	主な利用用途はシェーダプログラミングやデバッグ、
	 *	あるいは独自形状描画などが考えられます。
	 *
	 *	本関数を利用するには、FK の描画エンジン内部に精通している必要があります。
	 *	ソースコードを解析し、内部処理を理解した上で利用することを推奨します。
	 */
	virtual void			postShader(void) {};
	//@)

#ifndef FK_DOXYGEN_USER_PROCESS

	void					setBoundaryMode(fk_BoundaryMode);
	fk_BoundaryMode			getBoundaryMode(void);
	void					setSBRadius(double);
	double					getSBRadius(void);
	bool					isInterference(fk_Model *);
	bool					isCollision(fk_Model *);
	double					getCollisionTime(fk_Model *);


	// rita_ext: カスタムテクスチャ描画用エントリポイント
	virtual void			connectShader(unsigned int) {};

	void					TreePrint(void);
#endif
};

#endif // !__FK_MODEL_HEADER__
