//------------------------------------------------------------------------------
// 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 RENDERING_DEVICE_H_
#define RENDERING_DEVICE_H_

namespace Lamp{

class GraphicsDeviceCapacity;
class Fog;
class DirectionalLight;
class PointLight;
class Texture;

//------------------------------------------------------------------------------
/**
 * レンダリングデバイス
 */
class RenderingDevice{
friend class LampGraphics;
public:
	/// 最大アクティブライト数
	static const int maxActiveLightCount_;

	//--------------------------------------------------------------------------
	/**
	 * インスタンス取得
	 * @return インスタンス
	 */
	static RenderingDevice* getInstance(){
		Assert(instance_ != NULL);
		return instance_;
	}

	//--------------------------------------------------------------------------
	// ステート設定
	//--------------------------------------------------------------------------
	/**
	 * レンダーステートの設定
	 * @param type レンダーステートタイプ
	 * @param state レンダーステート
	 */
	virtual void setRenderState(D3DRENDERSTATETYPE type, u_int state);

	/**
	 * テクスチャステートの設定
	 * @param stage ステージ
	 * @param type テクスチャステートタイプ
	 * @param state テクスチャステート
	 */
	virtual void setTextureState(
		u_int stage, D3DTEXTURESTAGESTATETYPE type, u_int state);

	/**
	 * サンプラステートの設定
	 * @param stage ステージ
	 * @param type サンプラステートタイプ
	 * @param state サンプラステート
	 */
	virtual void setSamplerState(
		u_int stage, D3DSAMPLERSTATETYPE type, u_int state);

	//--------------------------------------------------------------------------
	// ステートブロック関連
	//--------------------------------------------------------------------------
	/**
	 * ステートブロックの開始
	 */
	virtual void beginStateBlock();

	/**
	 * ステートブロックの終了
	 * @return ステートブロック
	 */
	virtual Direct3DStateBlock* endStateBlock();

	/**
	 * ステートブロックの適用
	 * @param stateBlock ステートブロック
	 */
	virtual void applyStateBlock(Direct3DStateBlock* stateBlock);

	/**
	 * デフォルトステートブロックの適用
	 */
	virtual void applyDefaultStateBlock(){
		applyStateBlock(defaultStateBlock_);
	}

	//--------------------------------------------------------------------------
	// レンダーターゲット
	//--------------------------------------------------------------------------
	/**
	 * レンダーターゲットサイズの取得
	 * @return レンダーターゲットサイズ
	 */
	virtual DimensionI getRenderTargetSize();

	//--------------------------------------------------------------------------
	// シーン関連
	//--------------------------------------------------------------------------
	/**
	 * シーンの開始
	 * @return 成功すればtrueを返す
	 */
	virtual bool beginScene();

	/**
	 * シーンの終了
	 */
	virtual void endScene();

	//--------------------------------------------------------------------------
	// 行列関連
	//--------------------------------------------------------------------------
	/**
	 * 投影行列の設定
	 * @param projectionMatrix 投影行列
	 */
	virtual void setProjectionMatrix(const Matrix44& projectionMatrix);

	/**
	 * ビュー行列の設定
	 * @param viewMatrix ビュー行列
	 */
	virtual void setViewMatrix(const Matrix44& viewMatrix);

	/**
	 * ワールド行列の設定
	 * @param worldMatrix ワールド行列
	 */
	virtual void setWorldMatrix(const Matrix34& worldMatrix);

	/**
	 * テクスチャトランスフォーム設定
	 * @param stage テクスチャステージ
	 * @param repeat リピート
	 * @param offset オフセット
	 */
	virtual void setTextureTransform2(u_int stage,
		const TexCoord2& repeat, const TexCoord2& offset);

	//--------------------------------------------------------------------------
	// ビューポート
	//--------------------------------------------------------------------------
	/**
	 * ビューポートの設定
	 * @param rectangle 矩形
	 */
	virtual void setViewport(const RectangleI& rectangle);

	/**
	 * ビューポートのリセット
	 */
	virtual void resetViewport();

	//--------------------------------------------------------------------------
	// ライティング関連
	//--------------------------------------------------------------------------
	/**
	 * ライティングの設定
	 * @param lighting ライティングを行うならtrue
	 */
	virtual void setLighting(bool lighting);

	/**
	 * アンビエントカラーの設定
	 * @param ambientColor アンビエントカラー
	 */
	virtual void setAmbientColor(const Color3f& ambientColor);

	/**
	 * ディレクショナルライトを有効にする
	 * @param lightIndex ライトインデックス
	 * @param directionalLight ディレクショナルライト
	 */
	virtual void enableDirectionalLight(
		int lightIndex, DirectionalLight* directionalLight);

	/**
	 * ポイントライトを有効にする
	 * @param lightIndex ライトインデックス
	 * @param pointLight ポイントライト
	 */
	virtual void enablePointLight(int lightIndex, PointLight* pointLight);

	/**
	 * ライトを閉じる
	 * @param lightIndex ライトインデックス
	 */
	virtual void closeLight(int lightIndex);

	//--------------------------------------------------------------------------
	// マテリアル関連
	//--------------------------------------------------------------------------
	/**
	 * マテリアルの設定
	 * @param diffuseColor ディフューズカラー
	 * @param specularColor スペキュラカラー
	 * @param ambientColor アンビエントカラー
	 * @param emissiveColor エミッシブカラー
	 * @param specularPower スペキュラパワー
	 * @param alpha アルファ
	 */
	virtual void setMaterial(
		const Color3f& diffuseColor, const Color3f& specularColor,
		const Color3f& ambientColor, const Color3f& emissiveColor,
		float specularPower, float alpha);

	//--------------------------------------------------------------------------
	/**
	 * ブレンディングの設定
	 * @param blendingFlag ブレンディングフラグ
	 */
	virtual void setBlending(bool blendingFlag);

	/**
	 * ブレンドモードの設定
	 * @param mode ブレンドモード
	 * @param source ブレンドソース
	 * @param destination ブレンドデスティネーション
	 */
	virtual void setBlendMode(int mode, int source, int destination);

	//--------------------------------------------------------------------------
	// テクスチャ関連
	//--------------------------------------------------------------------------
	/**
	 * テクスチャの設定
	 * @param textureStage テクスチャステージ
	 * @param texture テクスチャ
	 */
	virtual void setTexture(int textureStage, Texture* texture);

	/**
	 * テクスチャの設定
	 * @param textureStage テクスチャステージ
	 * @param texture Direct3Dテクスチャ
	 */
	virtual void setTexture(int textureStage, Direct3DTexture* texture);

	/**
	 * テクスチャアドレスモードの設定
	 * @param textureStage テクスチャステージ
	 * @param addressModeU アドレスモードU
	 * @param addressModeV アドレスモードV
	 */
	virtual void setTextureAddressMode2(int textureStage,
		int addressModeU, int addressModeV);

	/**
	 * テクスチャの作成
	 * @param format フォーマット
	 * @param width 幅
	 * @param height 高さ
	 * @return テクスチャ
	 */
	virtual Direct3DTexture* createTexture(
		D3DFORMAT format, int width, int height);

	/**
	 * テクスチャのロック
	 * @param texture テクスチャ
	 * @param mipmapLevel ミップマップレベル
	 * @return ロックされた矩形
	 */
	virtual D3DLOCKED_RECT lockTexture(
		Direct3DTexture* texture, int mipmapLevel);

	/**
	 * テクスチャのアンロック
	 * @param texture テクスチャ
	 * @param mipmapLevel ミップマップレベル
	 */
	virtual void unlockTexture(Direct3DTexture* texture, int mipmapLevel);

	//--------------------------------------------------------------------------
	// テクスチャステージ関連
	//--------------------------------------------------------------------------
	/**
	 * カラーテクスチャステージ設定
	 * @param colorStage カラーステージ
	 * @param operation ステージの操作
	 * @param arg1 第一引数
	 * @param arg2 第二引数
	 * @param uvIndex UVインデックス
	 */
	virtual void setColorTextureStage(int colorStage,
		D3DTEXTUREOP operation, u_int arg1, u_int arg2, int uvIndex);

	/**
	 * カラーテクスチャステージを閉じる
	 * @param colorStage カラーステージ
	 */
	virtual void closeColorTextureStage(int colorStage);

	/**
	 * アルファテクスチャステージ設定
	 * @param alphaTextureStage アルファテクスチャステージ
	 */
	virtual void setAlphaTextureStage(int alphaTextureStage);

	//--------------------------------------------------------------------------
	// フォグ
	//--------------------------------------------------------------------------
	/**
	 * フォグの設定
	 * @param fog フォグ
	 */
	virtual void setFog(Fog* fog);

	//--------------------------------------------------------------------------
	// Zテスト
	//--------------------------------------------------------------------------
	/**
	 * Zテストの設定
	 * @param zTest Zテストを行うならtrue
	 */
	virtual void setZTest(bool zTest);

	//--------------------------------------------------------------------------
	// インデックスバッファ
	//--------------------------------------------------------------------------
	/**
	 * 静的インデックスバッファの構築
	 * @param bufferSize バッファサイズ
	 * @return 静的インデックスバッファ
	 */
	virtual Direct3DIndexBuffer* createStaticIndexBuffer(int bufferSize);

	/**
	 * 静的インデックスバッファのロック
	 * @param indexBuffer インデックスバッファ
	 * @param offset オフセット
	 * @param size サイズ
	 * @return 書き込みアドレス
	 */
	virtual u_char* lockStaticIndexBuffer(
		Direct3DIndexBuffer* indexBuffer, int offset, int size);

	/**
	 * 静的インデックスバッファのアンロック
	 * @param indexBuffer インデックスバッファ
	 */
	virtual void unlockStaticIndexBuffer(Direct3DIndexBuffer* indexBuffer);

	/**
	 * 静的インデックスバッファの書き込み
	 * @param indexBuffer インデックスバッファ
	 * @param data データ
	 * @param dataSize データサイズ
	 */
	virtual void writeStaticIndexBuffer(
		Direct3DIndexBuffer* indexBuffer, const void* data, int dataSize);

	/**
	 * 動的インデックスバッファの構築
	 * @param bufferSize バッファサイズ
	 * @return 動的インデックスバッファ
	 */
	virtual Direct3DIndexBuffer* createDynamicIndexBuffer(int bufferSize);

	/**
	 * 動的インデックスバッファの書き込み
	 * @param indexBuffer インデックスバッファ
	 * @param data データ
	 * @param dataSize データサイズ
	 */
	virtual void writeDynamicIndexBuffer(
		Direct3DIndexBuffer* indexBuffer, const void* data, int dataSize);

	/**
	 * インデックスバッファの設定
	 * @param indexBuffer インデックスバッファ
	 */
	virtual void setIndexBuffer(Direct3DIndexBuffer* indexBuffer);

	//--------------------------------------------------------------------------
	// 頂点記述
	//--------------------------------------------------------------------------
	/**
	 * 頂点記述の構築
	 * @param vertexDeclaration [out] 頂点記述
	 * @param hasPosition 位置を持つか
	 * @param weightsPerVertex 頂点あたりウェイト数
	 * @param bonesPerVertex 頂点あたりボーン数
	 * @param hasNormal 法線を持つか
	 * @param hasColor 頂点カラーを持つか
	 * @param texCoordSetCount テクスチャ座標セット数
	 * @param texCoordTypeArray テクスチャ座標タイプ配列
	 * @return 頂点サイズ
	 */
	virtual int createVertexDeclaration(
		Direct3DVertexDeclaration** vertexDeclaration, bool hasPosition,
		int weightsPerVertex, int bonesPerVertex, bool hasNormal,
		bool hasColor, int texCoordSetCount,
		const TexCoord::Type* texCoordTypeArray);

	/**
	 * 頂点記述の設定
	 * @param vertexDeclaration 頂点記述
	 */
	virtual void setVertexDeclaration(
		Direct3DVertexDeclaration* vertexDeclaration);

	//--------------------------------------------------------------------------
	// 頂点バッファ
	//--------------------------------------------------------------------------
	/**
	 * 静的頂点バッファの構築
	 * @param bufferSize バッファサイズ
	 * @return 静的頂点バッファ
	 */
	virtual Direct3DVertexBuffer* createStaticVertexBuffer(int bufferSize);

	/**
	 * 静的頂点バッファの書き込み
	 * @param vertexBuffer 静的頂点バッファ
	 * @param bufferSize バッファサイズ
	 * @param vertexCount 頂点数
	 * @param positions 位置配列
	 * @param weightsPerVertex 頂点あたりウェイト数
	 * @param weights ウェイト配列
	 * @param bonesBerVertex 頂点あたりボーン数
	 * @param boneIndices ボーンインデックス配列
	 * @param normals 法線配列
	 * @param colors 頂点カラー配列
	 * @param texCoordSetCount テクスチャ座標セット数
	 * @param texCoordTypeArray テクスチャ座標タイプ配列
	 * @param texCoords テクスチャ座標配列
	 */
	virtual void writeStaticVertexBuffer(
		Direct3DVertexBuffer* vertexBuffer, int bufferSize, int vertexCount,
		const Vector3* positions, int weightsPerVertex, const float* weights,
		int bonesBerVertex, const u_char* boneIndices, const Vector3* normals,
		const Color4c* colors, int texCoordSetCount,
		const TexCoord::Type* texCoordTypeArray, const float* const* texCoords);

	/**
	 * 動的頂点バッファの構築
	 * @param bufferSize バッファサイズ
	 * @return 動的頂点バッファ
	 */
	virtual Direct3DVertexBuffer* createDynamicVertexBuffer(int bufferSize);

	/**
	 * 動的頂点バッファのロック
	 * @param vertexBuffer 動的頂点バッファ
	 * @param offset オフセット
	 * @param size サイズ
	 * @return 書き込みアドレス
	 */
	virtual u_char* lockDynamicVertexBuffer(
		Direct3DVertexBuffer* vertexBuffer, int offset, int size);

	/**
	 * 動的頂点バッファのアンロック
	 * @param vertexBuffer 動的頂点バッファ
	 */
	virtual void unlockDynamicVertexBuffer(Direct3DVertexBuffer* vertexBuffer);

	/**
	 * 動的頂点バッファの書き込み
	 * @param vertexBuffer 動的頂点バッファ
	 * @param bufferSize バッファサイズ
	 * @param vertexCount 頂点数
	 * @param positions 位置配列
	 * @param weightsPerVertex 頂点あたりウェイト数
	 * @param weights ウェイト配列
	 * @param bonesBerVertex 頂点あたりボーン数
	 * @param boneIndices ボーンインデックス配列
	 * @param normals 法線配列
	 * @param colors 頂点カラー配列
	 * @param texCoordSetCount テクスチャ座標セット数
	 * @param texCoordTypeArray テクスチャ座標タイプ配列
	 * @param texCoords テクスチャ座標配列
	 */
	virtual void writeDynamicVertexBuffer(
		Direct3DVertexBuffer* vertexBuffer, int bufferSize, int vertexCount,
		const Vector3* positions, int weightsPerVertex, const float* weights,
		int bonesBerVertex, const u_char* boneIndices, const Vector3* normals,
		const Color4c* colors, int texCoordSetCount,
		const TexCoord::Type* texCoordTypeArray, const float* const* texCoords);

	/**
	 * 頂点バッファの設定
	 * @param vertexBuffer 頂点バッファ
	 * @param vertexSize 頂点サイズ
	 */
	virtual void setVertexBuffer(
		Direct3DVertexBuffer* vertexBuffer, int vertexSize);

	//--------------------------------------------------------------------------
	// 描画
	//--------------------------------------------------------------------------
	/**
	 * 三角リスト描画
	 * @param primitiveCount プリミティブ数
	 */
	virtual void drawTriangleList(int primitiveCount);

	/**
	 * インデックス三角リスト描画
	 * @param vertexCount 頂点数
	 * @param primitiveCount プリミティブ数
	 */
	virtual void drawIndexedTriangleList(int vertexCount, int primitiveCount);

	/**
	 * インデックス三角リスト描画
	 * @param baseVertexIndex 頂点インデックスオフセット
	 * @param minIndex 最小インデックス
	 * @param vertexCount 頂点数
	 * @param startIndex 開始インデックス
	 * @param primitiveCount プリミティブ数
	 */
	virtual void drawIndexedTriangleList(int baseVertexIndex,
		int minIndex, int vertexCount, int startIndex, int primitiveCount);

	//--------------------------------------------------------------------------
	/**
	 * ラインリスト描画
	 * @param primitiveCount プリミティブ数
	 */
	virtual void drawLineList(int primitiveCount);

	/**
	 * インデックスラインリスト描画
	 * @param vertexCount 頂点数
	 * @param primitiveCount プリミティブ数
	 */
	virtual void drawIndexedLineList(int vertexCount, int primitiveCount);

	//--------------------------------------------------------------------------
	// カウンタ関連
	//--------------------------------------------------------------------------
	/**
	 * カウンタのリセット
	 */
	virtual void resetCounter(){
		drawPrimitiveCount_ = 0;
		drawPolygonCount_ = 0;
		drawVertexCount_ = 0;
	}

	/**
	 * 頂点カウントの追加
	 * @param drawPolygonCount 描画ポリゴンカウント
	 * @param drawVertexCount 描画頂点カウント
	 */
	virtual void addVertexCount(int drawPolygonCount, int drawVertexCount){
		drawPrimitiveCount_++;
		drawPolygonCount_ += drawPolygonCount;
		drawVertexCount_ += drawVertexCount;
	}

	/**
	 * DrawPrimitiveカウントの取得
	 * @return DrawPrimitiveカウント
	 */
	virtual int getDrawPrimitiveCount(){ return drawPrimitiveCount_; }

	/**
	 * 描画ポリゴンカウントの取得
	 * @return 描画ポリゴンカウント
	 */
	virtual int getDrawPolygonCount(){ return drawPolygonCount_; }

	/**
	 * 描画頂点カウント
	 * @return 描画頂点カウント
	 */
	virtual int getDrawVertexCount(){ return drawVertexCount_; }

protected:
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 * @param capacity デバイス能力
	 */
	RenderingDevice(GraphicsDeviceCapacity* capacity);

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

	//--------------------------------------------------------------------------
	// ユーティリティ
	//--------------------------------------------------------------------------
	/**
	 * 頂点データの書き込み
	 * @param buffer 書き込みバッファ
	 * @param bufferSize バッファサイズ
	 * @param vertexCount 頂点数
	 * @param positions 位置配列
	 * @param weightsPerVertex 頂点あたりウェイト数
	 * @param weights ウェイト配列
	 * @param bonesBerVertex 頂点あたりボーン数
	 * @param boneIndices ボーンインデックス配列
	 * @param normals 法線配列
	 * @param colors 頂点カラー配列
	 * @param texCoordSetCount テクスチャ座標セット数
	 * @param texCoordTypeArray テクスチャ座標タイプ配列
	 * @param texCoords テクスチャ座標配列
	 */
	virtual void writeVertices(u_char* buffer, int bufferSize, int vertexCount,
		const Vector3* positions, int weightsPerVertex, const float* weights,
		int bonesBerVertex, const u_char* boneIndices, const Vector3* normals,
		const Color4c* colors, int texCoordSetCount,
		const TexCoord::Type* texCoordTypeArray, const float* const* texCoords);

	/**
	 * D3Dベクトルの設定
	 * @param destination 設定先
	 * @param source 設定元
	 */
	virtual void setD3DVector(D3DVECTOR& destination, const Vector3& source);

	/**
	 * D3Dカラーの設定
	 * @param destination 設定先
	 * @param source 設定元
	 */
	virtual void setD3DColor(D3DCOLORVALUE& destination, const Color4f& source);

	/**
	 * D3Dカラーの設定
	 * @param destination 設定先
	 * @param source 設定元
	 */
	virtual void setD3DColor(D3DCOLORVALUE& destination, const Color3f& source);

	//--------------------------------------------------------------------------
	// ステートブロック関連
	//--------------------------------------------------------------------------
	/**
	 * デフォルトステートブロックのリストア
	 * @param direct3DDevice Direct3Dデバイス
	 */
	virtual void restoreDefaultStateBlock(Direct3DDevice* direct3DDevice);

	/**
	 * デフォルトステートブロックの無効化
	 */
	virtual void invalidateDefaultStateBlock(){
		SafeRelease(defaultStateBlock_);
	}

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

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

	//--------------------------------------------------------------------------
	// システム
	//--------------------------------------------------------------------------
	// デバイス能力
	GraphicsDeviceCapacity* capacity_;
	// Direct3Dデバイス
	Direct3DDevice* device_;
	// デフォルトステートブロック
	Direct3DStateBlock* defaultStateBlock_;

	//--------------------------------------------------------------------------
	// カウンタ関連
	//--------------------------------------------------------------------------
	// DrawPrimitiveカウント
	int drawPrimitiveCount_;
	// 描画ポリゴンカウント
	int drawPolygonCount_;
	// 描画頂点カウント
	int drawVertexCount_;

	//--------------------------------------------------------------------------
	// インスタンス
	static RenderingDevice* instance_;

};

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