//------------------------------------------------------------------------------
// 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
 */

#include "LampBasic.h"
#include "Graphics/PrimitiveRenderer/PrimitiveDrawRequest.h"
#include "Graphics/Renderer/RenderingDevice.h"
#include "Graphics/System/LampGraphics.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
PrimitiveDrawRequest::PrimitiveDrawRequest(){
	data_ = new Data();
}
//------------------------------------------------------------------------------
// コピーコンストラクタ
PrimitiveDrawRequest::PrimitiveDrawRequest(const PrimitiveDrawRequest& copy){
	data_ = copy.data_;
	data_->addReference();
}
//------------------------------------------------------------------------------
// 代入コピー
PrimitiveDrawRequest& PrimitiveDrawRequest::operator =(
	const PrimitiveDrawRequest& copy){
	// 自分自身なら無視
	if(this == &copy){ return *this; }
	// リファレンスの削除
	removeReference();
	// データの代入
	data_ = copy.data_;
	data_->addReference();
	return *this;
}
//------------------------------------------------------------------------------
// デストラクタ
PrimitiveDrawRequest::~PrimitiveDrawRequest(){
	// リファレンスの削除
	removeReference();
}
//------------------------------------------------------------------------------
// リファレンスの削除
int PrimitiveDrawRequest::removeReference(){
	int referenceCount = data_->removeReference();
	Assert(referenceCount >= 0);
	if(referenceCount == 0){ SafeDelete(data_); }
	return referenceCount;
}
//------------------------------------------------------------------------------
// 頂点
//------------------------------------------------------------------------------
// 頂点数の設定
void PrimitiveDrawRequest::setVertexCount(int vertexCount){
	Assert(vertexCount >= 0);
	if(data_->vertexCount_ == vertexCount){ return; }
	bool useColor = hasColor();
	data_->vertexCount_ = vertexCount;
	// 頂点バッファの解放
	SafeRelease(data_->vertexBuffer_);
	SafeArrayDelete(data_->colors_);
	SafeArrayDelete(data_->positions_);
	if(vertexCount == 0){ return; }
	data_->positions_ = new Vector3[vertexCount];
	if(useColor){ data_->colors_ = new Color4c[vertexCount]; }
	// 頂点バッファを解放する
	SafeRelease(data_->vertexBuffer_);
}
//------------------------------------------------------------------------------
// カラー
//------------------------------------------------------------------------------
// カラーを有効にするかどうか
void PrimitiveDrawRequest::enableColor(bool colorFlag){
	if(hasColor() == colorFlag){ return; }
	// 頂点バッファの解放
	SafeRelease(data_->vertexBuffer_);
	SafeArrayDelete(data_->colors_);
	Assert(data_->vertexCount_ != 0);
	if(colorFlag){ data_->colors_ = new Color4c[data_->vertexCount_]; }
	// 頂点バッファを解放する
	SafeRelease(data_->vertexBuffer_);
}
//------------------------------------------------------------------------------
// 頂点インデックス
//------------------------------------------------------------------------------
// 頂点インデックス数の設定
void PrimitiveDrawRequest::setVertexIndexCount(int vertexIndexCount){
	SafeRelease(data_->indexBuffer_);
	SafeArrayDelete(data_->vertexIndices_);
	data_->vertexIndexCount_ = vertexIndexCount;
	if(vertexIndexCount == 0){ return; }
	data_->vertexIndices_ = new u_short[vertexIndexCount];
	// インデックスバッファを解放する
	SafeRelease(data_->indexBuffer_);
}
//------------------------------------------------------------------------------
// グラフィックスオブジェクト
//------------------------------------------------------------------------------
// 頂点バッファの取得
Direct3DVertexBuffer* PrimitiveDrawRequest::getVertexBuffer(){
	RenderingDevice* device = RenderingDevice::getInstance();
	int bufferSize = getVertexCount() * getVertexSize();
	// 頂点バッファが無ければ作成する
	if(data_->vertexBuffer_ == NULL){
		data_->vertexBuffer_ = device->createDynamicVertexBuffer(bufferSize);
		data_->vertexBufferChanged_ = true;
	}
	// 頂点バッファデータが変更されていれば書き込む
	if(data_->vertexBufferChanged_){
		Assert(data_->vertexBuffer_ != NULL);
		device->writeDynamicVertexBuffer(data_->vertexBuffer_, bufferSize,
			getVertexCount(), data_->positions_, 0, NULL, 0, NULL, NULL,
			getColorArray(), 0, NULL, NULL);
		data_->vertexBufferChanged_ = false;
	}
	return data_->vertexBuffer_;
}
//------------------------------------------------------------------------------
// インデックスバッファの取得
Direct3DIndexBuffer* PrimitiveDrawRequest::getIndexBuffer(){
	Assert(hasVertexIndices());
	RenderingDevice* device = RenderingDevice::getInstance();
	int bufferSize = getVertexIndexCount() * sizeof(u_short);
	// インデックスバッファが無ければ作成する
	if(data_->indexBuffer_ == NULL){
		data_->indexBuffer_ = device->createDynamicIndexBuffer(bufferSize);
		data_->indexBufferChanged_ = true;
	}
	// インデックスバッファデータが変更されていれば書き込む
	if(data_->indexBufferChanged_){
		Assert(data_->indexBuffer_ != NULL);
		device->writeDynamicIndexBuffer(
			data_->indexBuffer_, getVertexIndexArray(), bufferSize);
		data_->indexBufferChanged_ = false;
	}
	return data_->indexBuffer_;
}
//------------------------------------------------------------------------------
// データ
//------------------------------------------------------------------------------
// コンストラクタ
PrimitiveDrawRequest::Data::Data() : vertexCount_(0), positions_(NULL),
	colors_(NULL), vertexIndexCount_(0), vertexIndices_(NULL),
	vertexBuffer_(NULL), indexBuffer_(NULL), referenceCount_(1),
	vertexBufferChanged_(true), indexBufferChanged_(true){
	LampGraphics::addDeviceObjectHolder(this);
}
//------------------------------------------------------------------------------
// デストラクタ
PrimitiveDrawRequest::Data::~Data(){
	Assert(referenceCount_ == 0);
	LampGraphics::removeDeviceObjectHolder(this);
	invalidateGraphicsDeviceObjects();
	SafeArrayDelete(vertexIndices_);
	SafeArrayDelete(colors_);
	SafeArrayDelete(positions_);
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
