//------------------------------------------------------------------------------
// 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
 * RGBA8ビットピクチャ
 * @author Junpee
 */

#include "LampBasic.h"
#include "Graphics/Picture/PictureRGBA8.h"
#include "Graphics/Scene/Scene.h"
#include "Graphics/Picture/PictureManager.h"
#include "Graphics/Renderer/RenderingDevice.h"
#include "Core/Codec/LinearMinificationFilter/LinearMinificationFilter.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
PictureRGBA8::PictureRGBA8(const String& name, Scene* scene) :
	Picture(name, scene), d3dTexture_(NULL), image_(NULL){
}
//------------------------------------------------------------------------------
// デストラクタ
PictureRGBA8::~PictureRGBA8(){
	SafeArrayDelete(image_);
	SafeRelease(d3dTexture_);
}
//------------------------------------------------------------------------------
// コピー
PictureRGBA8* PictureRGBA8::copyPictureRGBA8() const{
	PictureManager* manager = scene_->getPictureManager();
	PictureRGBA8* copyPicture =
		manager->createPictureRGBA8(manager->rename(name_));
	copyPictureValue(copyPicture);
	copyPicture->setImage(getImage());
	return copyPicture;
}
//------------------------------------------------------------------------------
// D3Dテクスチャの取得
Direct3DTexture* PictureRGBA8::getD3DTexture(){
	if(d3dTexture_ == NULL){
		if(!compile()){ return NULL; }
	}
	return d3dTexture_;
}
//------------------------------------------------------------------------------
// コンパイル
bool PictureRGBA8::compile(){
	if(getImage() == NULL){
		ErrorOut("PictureRGBA8::compile() image is null");
		return false;
	}
	SafeRelease(d3dTexture_);
	// テクスチャ生成
	DimensionI size = getSize();
	d3dTexture_ = RenderingDevice::getInstance()->createTexture(
		D3DFMT_A8R8G8B8, size.width, size.height);
	// 書き込み
	if(!compileMipmap(getImage(), size, 0)){ return false; }
	return true;
}
//------------------------------------------------------------------------------
// イメージのコンパイル
bool PictureRGBA8::compileImage(
	const Color4c* image, const DimensionI& size, int mipmapLevel){
	RenderingDevice* device = RenderingDevice::getInstance();
	D3DLOCKED_RECT lockedRect = device->lockTexture(d3dTexture_, mipmapLevel);
	u_char* lineAddr = (u_char*)lockedRect.pBits;
	for(int i = 0; i < size.height; i++){
		u_int* writeAddr = (u_int*)lineAddr;
		int offset = i * size.width;
		for(int j = 0; j < size.width; j++){
			(*writeAddr) = image[offset + j].getARGB();
			writeAddr++;
		}
		lineAddr += lockedRect.Pitch;
	}
	device->unlockTexture(d3dTexture_, mipmapLevel);
	return true;
}
//------------------------------------------------------------------------------
// ミップマップのコンパイル
bool PictureRGBA8::compileMipmap(
	const Color4c* image, const DimensionI& size, int mipmapLevel){
	// イメージのコンパイル
	if(!compileImage(image, size, mipmapLevel)){ return false; }
	// ミップマップ再帰チェック
	mipmapLevel++;
	if((size.width == 1) && (size.height == 1)){
		Assert(d3dTexture_->GetLevelCount() == mipmapLevel);
		return true;
	}
	DimensionI nextSize = LinearMinificationFilter::getNextSize(size);
	Color4c* nextImage = new Color4c[nextSize.width * nextSize.height];
	// ブロックフィルタで縮小
	LinearMinificationFilter::filter(image, size, nextImage, nextSize);
	bool nextLevelResult = compileMipmap(nextImage, nextSize, mipmapLevel);
	delete[] nextImage;
	return nextLevelResult;
}
//------------------------------------------------------------------------------
// サイズの設定
void PictureRGBA8::setSize(const DimensionI& size){
	Picture::setSize(size);
	Assert(size.width > 0);
	Assert(size.height > 0);
	int pixelCount = size.width * size.height;
	SafeArrayDelete(image_);
	image_ = new Color4c[pixelCount];
	stateChanged();
}
//------------------------------------------------------------------------------
// イメージの設定
void PictureRGBA8::setImage(const Color4c* image){
	DimensionI size = getSize();
	Assert(size.width > 0);
	Assert(size.height > 0);
	std::memcpy(image_, image, sizeof(Color4c) * size.width * size.height);
	stateChanged();
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
