//------------------------------------------------------------------------------
// 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 "Graphics2D/Sprite/Sprite.h"
#include "Graphics2D/Renderer/SpriteRenderState.h"
#include "Graphics2D/Sprite/SpritePictureRGBA8.h"
#include "Graphics2D/Sprite/SpritePictureRGB8.h"
#include "Core/InputOutput/FilePath.h"
#include "Core/Codec/Tga/TargaLoader.h"

namespace Lamp{

//------------------------------------------------------------------------------
// 生成、破棄
//------------------------------------------------------------------------------
// コンストラクタ
Sprite::Sprite() : SpriteRequest(), picture_(NULL),
	rectangle_(RectangleF::zero), imageRectangle_(RectangleF::unit),
	align_(alignNone), fit_(fitNone), enabled_(true){
}
//------------------------------------------------------------------------------
// コピーコンストラクタ
Sprite::Sprite(const Sprite& copy) : SpriteRequest(copy), picture_(NULL),
	rectangle_(copy.rectangle_), imageRectangle_(copy.imageRectangle_),
	align_(copy.align_), fit_(copy.fit_), enabled_(copy.enabled_){
	// ピクチャのコピー
	setPicture(copy.picture_);
}
//------------------------------------------------------------------------------
// 代入コピー
Sprite& Sprite::operator =(const Sprite& copy){
	// 自分自身ならリターン
	if(this == &copy){ return *this; }
	// 親クラスのコピー
	SpriteRequest::operator =(copy);
	// ピクチャのコピー
	setPicture(copy.picture_);
	// メンバコピー
	rectangle_ = copy.rectangle_;
	imageRectangle_ = copy.imageRectangle_;
	align_ = copy.align_;
	fit_ = copy.fit_;
	enabled_ = copy.enabled_;
	return *this;
}
//------------------------------------------------------------------------------
// デストラクタ
Sprite::~Sprite(){
	// ピクチャを解放
	setPicture(NULL);
}
//------------------------------------------------------------------------------
// レンダリング
//------------------------------------------------------------------------------
// レンダリング
void Sprite::render(SpriteRenderState* renderState){
	// 無効チェック
	if(!enabled_){ return; }

	// 矩形の算出
	RectangleF rectangle(rectangle_);
	const DimensionF& renderTargetSize = renderState->getRenderTargetSize();
	// フィットの適用
	if(fit_ != fitNone){
		rectangle = applyFit(rectangle, renderTargetSize);
	}
	// アラインの適用
	if(align_ != alignNone){
		rectangle = applyAlign(rectangle, renderTargetSize);
	}

	// 位置の算出
	Point2f minPosition(rectangle.x, rectangle.y);
	Point2f maxPosition(rectangle.x + rectangle.width,
		rectangle.y + rectangle.height);

	// UVの算出
	TexCoord2 minUV(imageRectangle_.x, imageRectangle_.y);
	TexCoord2 maxUV(imageRectangle_.x + imageRectangle_.width,
		imageRectangle_.y + imageRectangle_.height);

	// 半ピクセルずらし
	// 半ピクセルを出すにはUV範囲、スプライトサイズが必要
	// ミップマップの場合、テクスチャサイズは関係無くなる
	TexCoord2 halfPixel(
		(imageRectangle_.width) * 0.5f / rectangle.width,
		(imageRectangle_.height) * 0.5f / rectangle.height);
	minUV += halfPixel;
	maxUV += halfPixel;

	// 描画
	renderState->request(picture_, minPosition, maxPosition, minUV, maxUV);
}
//------------------------------------------------------------------------------
// フィットの適用
RectangleF Sprite::applyFit(const RectangleF& rectangle,
	const DimensionF& renderTargetSize){
	RectangleF result(rectangle);
	if((fit_ == fitScreen) || (fit_ == fitScreenWidth)){
		result.width = renderTargetSize.width;
	}
	if((fit_ == fitScreen) || (fit_ == fitScreenHeight)){
		result.height = renderTargetSize.height;
	}
// 画像のアスペクト比の保持をおこなうかどうか
	return result;
}
//------------------------------------------------------------------------------
// アラインの適用
RectangleF Sprite::applyAlign(const RectangleF& rectangle,
	const DimensionF& renderTargetSize){
	RectangleF result(rectangle);
	// Xアライン
	if((align_ == alignTop) || (align_ == alignCenter) ||
		(align_ == alignBottom)){
		result.x += (renderTargetSize.width - rectangle.width) * 0.5f;
	}else if((align_ == alignTopRight) || (align_ == alignRight) ||
		(align_ == alignBottomRight)){
		result.x += renderTargetSize.width - rectangle.width;
	}

	// Yアライン
	if((align_ == alignLeft) || (align_ == alignCenter) ||
		(align_ == alignRight)){
		result.y += (renderTargetSize.height - rectangle.height) * 0.5f;
	}else if((align_ == alignBottomLeft) || (align_ == alignBottom) ||
		(align_ == alignBottomRight)){
		result.y += renderTargetSize.height - rectangle.height;
	}
	return result;
}
//------------------------------------------------------------------------------
// ピクチャ
//------------------------------------------------------------------------------
// ピクチャのロード
bool Sprite::loadPicture(const String& fileName){
	// ピクチャのロード
	SpritePicture* picture;
	// ファイルの有無をチェック
	FilePath filePath(fileName);
	if(!filePath.existFile()){ return false; }
	// 拡張子チェック
	String extension = filePath.getExtension();
	if(extension == "tga"){
		TargaLoader loader(filePath.getPath());
		loader.loadHeader();
		if(loader.hasAlpha()){
			SpritePictureRGBA8* pictureRGBA8 = new SpritePictureRGBA8();
			pictureRGBA8->setSize(loader.getSize());
			loader.loadImage(pictureRGBA8->getImageBuffer());
			picture = pictureRGBA8;
		}else{
			SpritePictureRGB8* pictureRGB8 = new SpritePictureRGB8();
			pictureRGB8->setSize(loader.getSize());
			loader.loadImage(pictureRGB8->getImageBuffer());
			picture = pictureRGB8;
		}
	}else{
		return false;
	}
	// ピクチャの設定
	setPicture(picture);
	return true;
}
//------------------------------------------------------------------------------
// ピクチャの設定
void Sprite::setPicture(SpritePicture* picture){
	// ピクチャを解放
	if(picture_ != NULL){
		if(picture_->removeReference() == 0){ SafeDelete(picture_); }
	}
	// ピクチャを設定
	picture_ = picture;
	if(picture != NULL){ picture_->addReference(); }
}
//------------------------------------------------------------------------------
// イメージ矩形
//------------------------------------------------------------------------------
// アニメーションの設定
void Sprite::setAnimation(const DimensionI& animationDivision,
	int animation, const RectangleF& imageRectangle){
	int animationCount = animationDivision.width * animationDivision.height;
	Assert((animation >= 0) && (animation < animationCount));
	int xIndex = animation % animationDivision.width;
	int yIndex = animation / animationDivision.width;
	float xScale = imageRectangle.width / animationDivision.width;
	float yScale = imageRectangle.height / animationDivision.height;

	RectangleF result;
	result.x = imageRectangle.x + xIndex * xScale;
	result.y = imageRectangle.y + yIndex * yScale;
	result.width = xScale;
	result.height = yScale;
	setImageRectangle(result);
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
