//------------------------------------------------------------------------------
// 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
 * Mayaテクスチャ実装
 * @author Junpee
 */

#include "System/stdafx.h"
#include "Texture/MayaTexture.h"
#include "Texture/MayaTextureManager.h"
#include "Core/Codec/LinearMinificationFilter/LinearMinificationFilter.h"

namespace LampForMaya{

//------------------------------------------------------------------------------
// コンストラクタ
MayaTexture::MayaTexture(const MObject& node, const String& name) :
	node_(node), name_(name), textureID_(0), images_(NULL), mipmapLevel_(0),
	width_(0), height_(0), renameCallbackID_(0), dirtyCallbackID_(0),
	loaded_(false){
	MStatus result;
	// テクスチャID取得
	glGenTextures(1, &textureID_);
	MayaOpenGLCheck();
	// コールバック登録
	renameCallbackID_ = MNodeMessage::addNameChangedCallback(
		node_, MayaTextureManager::renameCallback, this, &result);
	MayaStatusCheck(result);
	dirtyCallbackID_ = MNodeMessage::addNodeDirtyCallback(
		node_, MayaTextureManager::dirtyCallback, this, &result);
	MayaStatusCheck(result);
}
//------------------------------------------------------------------------------
// デストラクタ
MayaTexture::~MayaTexture(){
	clear();
	// コールバック削除
	MayaStatusCheck(MMessage::removeCallback(dirtyCallbackID_));
	MayaStatusCheck(MMessage::removeCallback(renameCallbackID_));
	// テクスチャID解放
	glDeleteTextures(1, &textureID_);
	MayaOpenGLCheck();
}
//------------------------------------------------------------------------------
// クリア
void MayaTexture::clear(){
	if(images_ != NULL){
		for(int i = 0; i < mipmapLevel_; i++){
			SafeArrayDelete(images_[i]);
		}
		mipmapLevel_ = 0;
		SafeArrayDelete(images_);
	}
}
//------------------------------------------------------------------------------
// テクスチャのロード
bool MayaTexture::load(){
	if(loaded_){ return true; }
	MStatus result;
	// イメージの取得
	MImage image;
	String fileName =
		MayaAttributeUtility::getString(node_, "fileTextureName");
	if(fileName.isEmpty()){ return false; }
	MayaStatusCheck(image.readFromFile(fileName.getBytes()));
	MayaStatusCheck(image.getSize(width_, height_));
	// 2の累乗にリサイズ
	u_int widthLevel = highestPowerOf2(width_);
	bool widthResize = (width_ != (1 << widthLevel));
	u_int heightLevel = highestPowerOf2(height_);
	bool heightResize = (height_ != (1 << heightLevel));
	if(widthResize || heightResize){
		if(widthResize){
			widthLevel++;
			width_ = (1 << widthLevel);
		}
		if(heightResize){
			heightLevel++;
			height_ = (1 << heightLevel);
		}
		MayaStatusCheck(image.resize(width_, height_, false));
	}

	// ミップマップレベルの算出
	mipmapLevel_ = Math::maximum(widthLevel, heightLevel) + 1;

	// データ領域確保
	Assert(images_ == NULL);
	images_ = new u_char*[mipmapLevel_];
	for(int i = 0; i < mipmapLevel_; i++){
		images_[i] = new u_char[getWidth(i) * getHeight(i) * bytesPerPixel_];
	}

	// 0レベル画像の取得
	::memcpy(images_[0], image.pixels(), width_ * height_ * bytesPerPixel_);

	// ミップマップ生成
	for(int level = 1; level < mipmapLevel_; level++){
		int sourceLevel = level - 1;
		DimensionI sourceSize(getWidth(sourceLevel), getHeight(sourceLevel));
		DimensionI targetSize(getWidth(level), getHeight(level));
		LinearMinificationFilter::filter(
			(Color4c*)images_[sourceLevel], sourceSize,
			(Color4c*)images_[level], targetSize);
	}

	// テクスチャ登録
	for(int i = 0; i < mipmapLevel_; i++){
		glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA8, getWidth(i), getHeight(i), 0,
			GL_RGBA, GL_UNSIGNED_BYTE, images_[i]);
		MayaOpenGLCheck();
	}

	loaded_ = true;
	return true;
}
//------------------------------------------------------------------------------
// テクスチャのバインド
bool MayaTexture::bind(){
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, textureID_);
	MayaOpenGLCheck();

	// データのロード
	if(!load()){ return false; }

	glTexParameteri(GL_TEXTURE_2D,
		GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	MayaOpenGLCheck();
	return true;
}
//------------------------------------------------------------------------------
} // End of namespace LampForMaya
//------------------------------------------------------------------------------
