//------------------------------------------------------------------------------
// 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
 * Lampマテリアル実装
 * @author Junpee
 */

#include "System/stdafx.h"
#include "Material/System/LampMaterial.h"
#include "Graphics/Material/Material.h"
#include "Texture/MayaTextureManager.h"

namespace LampForMaya{

// アルファテスト境界
const float LampMaterial::alphaTestBorder_ = (4.f / 255.f);

/// ブレンドテーブル
const u_int LampMaterial::blendTable_[blendTableSize_] = {
	GL_ZERO,
	GL_ONE,
	GL_SRC_COLOR,
	GL_ONE_MINUS_SRC_COLOR,
	GL_SRC_ALPHA,
	GL_ONE_MINUS_SRC_ALPHA,
	GL_SRC_ALPHA_SATURATE,
	GL_DST_COLOR,
	GL_ONE_MINUS_DST_COLOR,
	GL_DST_ALPHA,
	GL_ONE_MINUS_DST_ALPHA,
};

//------------------------------------------------------------------------------
// 初期化
//------------------------------------------------------------------------------
// コンストラクタ
LampMaterial::LampMaterial(){
	MayaTextureManager::addReference();
}
//------------------------------------------------------------------------------
// デストラクタ
LampMaterial::~LampMaterial(){
	MayaTextureManager::removeReference();
}
//------------------------------------------------------------------------------
// マテリアル初期化
void LampMaterial::materialInitialize(){
	const MObject& outColor = MPxHwShaderNode::outColor;
	MStatus result;
	MFnNumericAttribute attribute;
	// ブレンドモードアトリビュートの作成
	MObject blendMode = attribute.create(
		"blendMode", "bm", MFnNumericData::kInt, 0, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(attribute.setMax(5));
	MayaStatusCheck(attribute.setMin(0));
	MayaStatusCheck(MPxNode::addAttribute(blendMode));
	MayaStatusCheck(MPxNode::attributeAffects(blendMode, outColor));

	// アルファアトリビュートの作成
	MObject alpha = attribute.create(
		"alpha", "a", MFnNumericData::kFloat, 1.f, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(attribute.setMax(1.f));
	MayaStatusCheck(attribute.setMin(0.f));
	MayaStatusCheck(MPxNode::addAttribute(alpha));
	MayaStatusCheck(MPxNode::attributeAffects(alpha, outColor));

	// ブレンドソースアトリビュートの作成
	MObject blendSource = attribute.create(
		"blendSource", "bs", MFnNumericData::kInt, 4, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(attribute.setMax(blendTableSize_ - 1));
	MayaStatusCheck(attribute.setMin(0));
	MayaStatusCheck(MPxNode::addAttribute(blendSource));
	MayaStatusCheck(MPxNode::attributeAffects(blendSource, outColor));

	// ブレンドデスティネーションアトリビュートの作成
	MObject blendDestination = attribute.create(
		"blendDestination", "bd", MFnNumericData::kInt, 5, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(attribute.setMax(blendTableSize_ - 1));
	MayaStatusCheck(attribute.setMin(0));
	MayaStatusCheck(MPxNode::addAttribute(blendDestination));
	MayaStatusCheck(MPxNode::attributeAffects(blendDestination, outColor));

	// ユーザインターフェースカラーの作成
	MObject uiColor = attribute.createColor("uiColor", "uic", &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setDefault(1.f, 1.f, 1.f));
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(MPxNode::addAttribute(uiColor));
	MayaStatusCheck(MPxNode::attributeAffects(uiColor, outColor));

	// Z書き込みアトリビュートの作成
	MObject zWrite = attribute.create(
		"zWrite", "zwt", MFnNumericData::kBoolean, 1, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(MPxNode::addAttribute(zWrite));
	MayaStatusCheck(MPxNode::attributeAffects(zWrite, outColor));

	// Zテストアトリビュートの作成
	MObject zTest = attribute.create(
		"zTest", "zte", MFnNumericData::kBoolean, 1, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(MPxNode::addAttribute(zTest));
	MayaStatusCheck(MPxNode::attributeAffects(zTest, outColor));

	// フォグオプションアトリビュートの作成
	MObject fogOption = attribute.create(
		"fogOption", "fgo", MFnNumericData::kInt, 0, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(attribute.setMax(2));
	MayaStatusCheck(attribute.setMin(0));
	MayaStatusCheck(MPxNode::addAttribute(fogOption));
	MayaStatusCheck(MPxNode::attributeAffects(fogOption, outColor));

	// ライトマスクアトリビュートの作成
	MObject lightMask = attribute.create(
		"lightMask", "lgm", MFnNumericData::kInt, 1, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(attribute.setMax(65535));
	MayaStatusCheck(attribute.setMin(0));
	MayaStatusCheck(MPxNode::addAttribute(lightMask));
	MayaStatusCheck(MPxNode::attributeAffects(lightMask, outColor));

	// 優先度アトリビュートの作成
	MObject priority = attribute.create(
		"priority", "pri", MFnNumericData::kInt, 0, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(attribute.setConnectable(false));
	MayaStatusCheck(attribute.setMax(Limit::shortMax));
	MayaStatusCheck(attribute.setMin(Limit::shortMin));
	MayaStatusCheck(MPxNode::addAttribute(priority));
	MayaStatusCheck(MPxNode::attributeAffects(priority, outColor));

	// 透明度アトリビュートの隠蔽
	MFnNumericAttribute outTransparencyAttribute(
		MPxHwShaderNode::outTransparency, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(outTransparencyAttribute.setWritable(false));
	MayaStatusCheck(outTransparencyAttribute.setStorable(false));

	// マットチャンネルアトリビュートの隠蔽
	MFnNumericAttribute outMatteOpacityAttribute(
		MPxHwShaderNode::outMatteOpacity, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(outMatteOpacityAttribute.setWritable(false));
	MayaStatusCheck(outMatteOpacityAttribute.setStorable(false));

	// グロウカラーアトリビュートの隠蔽
	MFnNumericAttribute outGlowColorAttribute(
		MPxHwShaderNode::outGlowColor, &result);
	MayaStatusCheck(result);
	MayaStatusCheck(outGlowColorAttribute.setWritable(false));
	MayaStatusCheck(outGlowColorAttribute.setStorable(false));
}
//------------------------------------------------------------------------------
// 描画
//------------------------------------------------------------------------------
// マテリアルのセットアップ
void LampMaterial::materialSetup(){
	// ライティングを有効にする
	glEnable(GL_LIGHTING);

	// アルファテストを行う
	glEnable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GEQUAL, alphaTestBorder_);

	// アルファブレンド
	if(getBlendMode() != 0){
		// glBlendEquation()でモード設定できる
		glEnable(GL_BLEND);
		// OpenGLではblendDestinationにSrcAlphaSaturateを指定するとエラーになる
		u_int destination = blendTable_[getBlendDestination()];
		if(destination == GL_SRC_ALPHA_SATURATE){ destination = GL_ZERO; }
		glBlendFunc(blendTable_[getBlendSource()], destination);
	}else{
		glDisable(GL_BLEND);
	}

	// Z書き込み
	glDepthMask(useZWrite());

	// Zテスト
	if(useZTest()){
		glEnable(GL_DEPTH_TEST);
	}else{
		glDisable(GL_DEPTH_TEST);
	}

	// フォグが有効かどうか
	MStatus result;
	int fogEnabled;
	result = MGlobal::executeCommand(MString(
		"modelEditor -q -fogging modelPanel4;"), fogEnabled, false, false);
	MayaStatusCheck(result);
	if(fogEnabled != 0){
		int fogOption = getFogOption();
		if(fogOption == 1){
			// フォグを無効にする
			glDisable(GL_FOG);
		}else if(fogOption == 2){
			// フォグ色を黒にする
			glFogfv(GL_FOG_COLOR, Color4f::black.array);
		}
	}
	MayaOpenGLCheck();
}
//------------------------------------------------------------------------------
// ユーザインターフェースシェーダ
MStatus LampMaterial::uiShader(const MPlug& plug, MDataBlock& dataBlock){
	MStatus result;
	const MObject& outColor = MPxHwShaderNode::outColor;
	if((plug != outColor) && (plug.parent() != outColor)){
		return MS::kUnknownParameter;
	}
	// 出力アドレスの取得
	MDataHandle outColorHandle = dataBlock.outputValue(outColor, &result);
	MayaStatusCheck(result);
	MFloatVector& outputColor = outColorHandle.asFloatVector();
	// 色を出力
	Color3f uiColor = getUIColor();
	outputColor.x = uiColor.r;
	outputColor.y = uiColor.g;
	outputColor.z = uiColor.b;
	outColorHandle.setClean();
	return MS::kSuccess;
}
//------------------------------------------------------------------------------
// アトリビュートアクセサ
//------------------------------------------------------------------------------
// ブレンドモードの取得
int LampMaterial::getBlendMode() const{
	return MayaAttributeUtility::getInt(thisMObject(), "blendMode");
}
//------------------------------------------------------------------------------
// アルファの取得
float LampMaterial::getAlpha() const{
	return MayaAttributeUtility::getFloat(thisMObject(), "alpha");
}
//------------------------------------------------------------------------------
// ブレンドソースの取得
int LampMaterial::getBlendSource() const{
	return MayaAttributeUtility::getInt(thisMObject(), "blendSource");
}
//------------------------------------------------------------------------------
// ブレンドデスティネーションの取得
int LampMaterial::getBlendDestination() const{
	return MayaAttributeUtility::getInt(thisMObject(), "blendDestination");
}
//------------------------------------------------------------------------------
// ユーザインターフェースカラーの取得
Color3f LampMaterial::getUIColor() const{
	return MayaAttributeUtility::getColor3f(thisMObject(), "uiColor");
}
//------------------------------------------------------------------------------
// Z書き込みの取得
bool LampMaterial::useZWrite() const{
	return MayaAttributeUtility::getBool(thisMObject(), "zWrite");
}
//------------------------------------------------------------------------------
// Zテストの取得
bool LampMaterial::useZTest() const{
	return MayaAttributeUtility::getBool(thisMObject(), "zTest");
}
//------------------------------------------------------------------------------
// フォグオプションの取得
int LampMaterial::getFogOption() const{
	return MayaAttributeUtility::getInt(thisMObject(), "fogOption");
}
//------------------------------------------------------------------------------
// ライトマスクの取得
u_int LampMaterial::getLightMask() const{
	return MayaAttributeUtility::getInt(thisMObject(), "lightMask");
}
//------------------------------------------------------------------------------
// 優先度の取得
int LampMaterial::getPriority() const{
	return MayaAttributeUtility::getInt(thisMObject(), "priority");
}
//------------------------------------------------------------------------------
} // End of namespace LampForMaya
//------------------------------------------------------------------------------
