//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * プリミティブレンダラヘッダ
 * @author Junpee
 */

#ifndef PRIMITIVE_RENDERER_H_
#define PRIMITIVE_RENDERER_H_

#include <Graphics/System/GraphicsDeviceObjectHolder.h>
#include <Core/Container/ArrayList.h>
#include <Graphics/PrimitiveRenderer/PrimitiveDrawRequest.h>

namespace Lamp{

class Camera;

//------------------------------------------------------------------------------
/**
 * プリミティブレンダラ
 */
class PrimitiveRenderer : public GraphicsDeviceObjectHolder{
public:
	//--------------------------------------------------------------------------
	// 生成、破棄
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 */
	PrimitiveRenderer();

	/**
	 * デストラクタ
	 */
	virtual ~PrimitiveRenderer();

	//--------------------------------------------------------------------------
	// レンダリング
	//--------------------------------------------------------------------------
	/**
	 * レンダリング
	 * @param viewMatrix ビュー行列
	 * @param projectionMatrix 投影行列
	 */
	virtual void render(const Matrix44& viewMatrix,
		const Matrix44& projectionMatrix);

	/**
	 * レンダリング
	 * @param camera カメラ
	 */
	virtual void render(Camera* camera);

	//--------------------------------------------------------------------------
	// リクエスト
	//--------------------------------------------------------------------------
	/**
	 * リクエスト
	 * @param primitive プリミティブ
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void request(const PrimitiveDrawRequest& primitive,
		const Matrix34& matrix, Color4c color = Color4c::white,
		bool zTest = true);

	/**
	 * リクエスト
	 * @param primitive プリミティブ
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void request(const PrimitiveDrawRequest& primitive,
		const Vector3& scale, const Vector3& rotationXYZ,
		const Vector3 translation, Color4c color = Color4c::white,
		bool zTest = true){
		Matrix34 matrix;
		matrix.setTransformationXYZ(scale, rotationXYZ, translation);
		request(primitive, matrix, color, zTest);
	}

	/**
	 * リクエスト
	 * @param primitive プリミティブ
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void request(const PrimitiveDrawRequest& primitive,
		const Vector3& scale, const Quaternion& rotationQuaternion,
		const Vector3 translation, Color4c color = Color4c::white,
		bool zTest = true){
		Matrix34 matrix;
		matrix.setTransformationQuaternion(
			scale, rotationQuaternion, translation);
		request(primitive, matrix, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * 線のリクエスト
	 * @param vertexCount 頂点数
	 * @param positions 位置配列
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestLine(int vertexCount, Vector3* positions,
		const Matrix34& matrix, Color4c color = Color4c::white,
		bool zTest = true);

	/**
	 * 線のリクエスト
	 * @param vertexCount 頂点数
	 * @param positions 位置配列
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestLine(int vertexCount, Vector3* positions,
		const Vector3& scale, const Vector3& rotationXYZ,
		const Vector3 translation, Color4c color = Color4c::white,
		bool zTest = true){
		Matrix34 matrix;
		matrix.setTransformationXYZ(scale, rotationXYZ, translation);
		requestLine(vertexCount, positions, matrix, color, zTest);
	}

	/**
	 * 線のリクエスト
	 * @param vertexCount 頂点数
	 * @param positions 位置配列
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestLine(int vertexCount, Vector3* positions,
		const Vector3& scale, const Quaternion& rotationQuaternion,
		const Vector3 translation, Color4c color = Color4c::white,
		bool zTest = true){
		Matrix34 matrix;
		matrix.setTransformationQuaternion(
			scale, rotationQuaternion, translation);
		requestLine(vertexCount, positions, matrix, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * 線のリクエスト
	 * @param vertexCount 頂点数
	 * @param positions 位置配列
	 * @param colors 色配列
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestLine(int vertexCount, Vector3* positions,
		Color4c* colors, const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true);

	/**
	 * 線のリクエスト
	 * @param vertexCount 頂点数
	 * @param positions 位置配列
	 * @param colors 色配列
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestLine(int vertexCount, Vector3* positions,
		Color4c* colors, const Vector3& scale, const Vector3& rotationXYZ,
		const Vector3 translation, Color4c color = Color4c::white,
		bool zTest = true){
		Matrix34 matrix;
		matrix.setTransformationXYZ(scale, rotationXYZ, translation);
		requestLine(vertexCount, positions, colors, matrix, color, zTest);
	}

	/**
	 * 線のリクエスト
	 * @param vertexCount 頂点数
	 * @param positions 位置配列
	 * @param colors 色配列
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestLine(int vertexCount, Vector3* positions,
		Color4c* colors, const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		Matrix34 matrix;
		matrix.setTransformationQuaternion(
			scale, rotationQuaternion, translation);
		requestLine(vertexCount, positions, colors, matrix, color, zTest);
	}

	//--------------------------------------------------------------------------
	// プリミティブリクエスト
	//--------------------------------------------------------------------------
	/**
	 * ポイントのリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestPoint(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(point_, matrix, color, zTest);
	}

	/**
	 * ポイントのリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestPoint(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(point_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * ポイントのリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestPoint(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(point_, scale, rotationQuaternion, translation, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * 軸ポイントのリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestAxisPoint(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(axisAxisPoint_, matrix, color, zTest);
	}

	/**
	 * 軸ポイントのリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestAxisPoint(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(axisAxisPoint_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * 軸ポイントのリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestAxisPoint(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(axisAxisPoint_, scale, rotationQuaternion, translation, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * 軸のリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestAxis(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(axis_, matrix, color, zTest);
	}

	/**
	 * 軸のリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestAxis(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(axis_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * 軸のリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestAxis(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(axis_, scale, rotationQuaternion, translation, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * 矢印のリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestArrow(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(arrow_, matrix, color, zTest);
	}

	/**
	 * 矢印のリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestArrow(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(arrow_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * 矢印のリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestArrow(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(arrow_, scale, rotationQuaternion, translation, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * グリッドのリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestGrid(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(grid_, matrix, color, zTest);
	}

	/**
	 * グリッドのリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestGrid(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(grid_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * グリッドのリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestGrid(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(grid_, scale, rotationQuaternion, translation, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * 平面のリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestPlane(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(plane_, matrix, color, zTest);
	}

	/**
	 * 平面のリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestPlane(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(plane_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * 平面のリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestPlane(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(plane_, scale, rotationQuaternion, translation, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * 球のリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestSphere(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(sphere_, matrix, color, zTest);
	}

	/**
	 * 球のリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestSphere(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(sphere_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * 球のリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestSphere(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(sphere_, scale, rotationQuaternion, translation, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * 箱のリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestBox(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(box_, matrix, color, zTest);
	}

	/**
	 * 箱のリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestBox(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(box_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * 箱のリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestBox(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(box_, scale, rotationQuaternion, translation, color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * 円柱のリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestCylinder(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(cylinder_, matrix, color, zTest);
	}

	/**
	 * 円柱のリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestCylinder(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(cylinder_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * 円柱のリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestCylinder(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(cylinder_, scale, rotationQuaternion, translation,
			color, zTest);
	}

	//--------------------------------------------------------------------------
	/**
	 * コーンのリクエスト
	 * @param matrix 行列
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestCone(const Matrix34& matrix,
		Color4c color = Color4c::white, bool zTest = true){
		request(cone_, matrix, color, zTest);
	}

	/**
	 * コーンのリクエスト
	 * @param scale スケール
	 * @param rotationXYZ XYZ回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestCone(const Vector3& scale,
		const Vector3& rotationXYZ, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(cone_, scale, rotationXYZ, translation, color, zTest);
	}

	/**
	 * コーンのリクエスト
	 * @param scale スケール
	 * @param rotationQuaternion 四元数回転
	 * @param translation 移動
	 * @param color 色
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void requestCone(const Vector3& scale,
		const Quaternion& rotationQuaternion, const Vector3 translation,
		Color4c color = Color4c::white, bool zTest = true){
		request(cone_, scale, rotationQuaternion, translation, color, zTest);
	}

	//--------------------------------------------------------------------------
	// デバイスオブジェクト
	//--------------------------------------------------------------------------
	/**
	 * デバイスオブジェクトの初期化
	 * @return 成功したらtrueを返す
	 */
	virtual bool initializeGraphicsDeviceObjects(){ return true; }

	/**
	 * デバイスオブジェクトの削除
	 */
	virtual void deleteGraphicsDeviceObjects(){}

	/**
	 * デバイスオブジェクトのリストア
	 * @return 成功したらtrueを返す
	 */
	virtual bool restoreGraphicsDeviceObjects(){ return true; }

	/**
	 * デバイスオブジェクトの無効化
	 */
	virtual void invalidateGraphicsDeviceObjects();

protected:
	//--------------------------------------------------------------------------
	// リクエスト
	//--------------------------------------------------------------------------
	/**
	 * リクエスト
	 */
	class Request{
	public:
		/**
		 * コンストラクタ
		 */
		Request() : matrix_(Matrix34::unit), primitive_(),
			color_(Color4c::white), zTest_(true){}

		/**
		 * デストラクタ
		 */
		virtual ~Request(){}

		/// 行列
		Matrix34 matrix_;
		/// プリミティブ
		PrimitiveDrawRequest primitive_;
		/// 色
		Color4c color_;
		/// Zテストフラグ
		bool zTest_;
	};

	/**
	 * リクエストの描画
	 * @param request リクエスト
	 */
	virtual void renderRequest(Request& request);

	//--------------------------------------------------------------------------
	// 頂点記述
	//--------------------------------------------------------------------------
	/**
	 * 位置の頂点記述を設定
	 * @return 位置の頂点記述
	 */
	void setPositionVertexDeclaration();

	/**
	 * 位置とカラーの頂点記述を設定
	 * @return 位置の頂点記述
	 */
	void setPositionColorVertexDeclaration();

	/// リクエスト
	ArrayList<Request> requests_;
	/// 位置の頂点記述
	Direct3DVertexDeclaration* positionDeclaration_;
	/// 位置とカラーの頂点記述
	Direct3DVertexDeclaration* positionColorDeclaration_;
	/// ポイント
	PrimitiveDrawRequest point_;
	/// 軸ポイント
	PrimitiveDrawRequest axisAxisPoint_;
	/// 軸
	PrimitiveDrawRequest axis_;
	/// 矢印
	PrimitiveDrawRequest arrow_;
	/// グリッド
	PrimitiveDrawRequest grid_;
	/// 平面
	PrimitiveDrawRequest plane_;
	/// 球
	PrimitiveDrawRequest sphere_;
	/// 箱
	PrimitiveDrawRequest box_;
	/// 円柱
	PrimitiveDrawRequest cone_;
	/// コーン
	PrimitiveDrawRequest cylinder_;

private:
	// コピーコンストラクタの隠蔽
	PrimitiveRenderer(const PrimitiveRenderer& copy);

	// 代入コピーの隠蔽
	void operator =(const PrimitiveRenderer& copy);

};

//------------------------------------------------------------------------------
} // End of namespace Lamp
#endif // End of PRIMITIVE_RENDERER_H_
//------------------------------------------------------------------------------

