//------------------------------------------------------------------------------
// 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 "System/MayaTypeID.h"
#include "Material/Basic/LampBasicMaterial.h"
#include "Material/Utility/LampMaterialUtility.h"
#include "Texture/MayaTextureManager.h"

namespace LampForMaya{

/// 型識別ID
const MTypeId LampBasicMaterial::id(MayaTypeID::basicMaterial);

//------------------------------------------------------------------------------
// コンストラクタ
LampBasicMaterial::LampBasicMaterial(){
}
//------------------------------------------------------------------------------
// デストラクタ
LampBasicMaterial::~LampBasicMaterial(){
}
//------------------------------------------------------------------------------
// コンストラクタ前処理
void LampBasicMaterial::postConstructor(){
	// マルチプロセッサ対応なし
	setMPSafe(false);
}
//------------------------------------------------------------------------------
// 初期化
MStatus LampBasicMaterial::initialize(){
	// マテリアルの初期化
	LampMaterial::materialInitialize();
	// ベーステクスチャアトリビュートの作成
	LampMaterialUtility::addBaseTextureAttribute();
	// 光沢テクスチャアトリビュートの作成
	LampMaterialUtility::addGlossTextureAttribute();
	// ライトテクスチャアトリビュートの作成
	LampMaterialUtility::addLightTextureAttribute();
	// 汚れテクスチャアトリビュートの作成
	LampMaterialUtility::addStainTextureAttribute();
	// ディフューズアトリビュートの作成
	LampMaterialUtility::addDiffuseAttribute();
	// スペキュラアトリビュートの作成
	LampMaterialUtility::addSpecularAttribute();
	// アンビエントアトリビュートの作成
	LampMaterialUtility::addAmbientAttribute();
	// エミッシブアトリビュートの作成
	LampMaterialUtility::addEmissiveAttribute();
	return MS::kSuccess;
}
//------------------------------------------------------------------------------
// 描画
//------------------------------------------------------------------------------
// ソフトウェアレンダリング
MStatus LampBasicMaterial::compute(const MPlug& plug, MDataBlock& dataBlock){
	return uiShader(plug, dataBlock);
}
//------------------------------------------------------------------------------
// 透明度を持つかどうか
bool LampBasicMaterial::hasTransparency(){ return isBlendEnabled(); }
//------------------------------------------------------------------------------
// 頂点あたりいくつの法泉を必要とするか
int LampBasicMaterial::normalsPerVertex(){ return 1; }
//------------------------------------------------------------------------------
// 頂点あたりいくつのカラーを必要とするか
int LampBasicMaterial::colorsPerVertex(){ return 0; }
//------------------------------------------------------------------------------
// 頂点あたりいくつのUVを必要とするか
int LampBasicMaterial::texCoordsPerVertex(){
	int maxTexCoord = 0;
	if(getBaseUVIndex() > maxTexCoord){ maxTexCoord = getBaseUVIndex(); }
//	if(getGlossUVIndex() > maxTexCoord){ maxTexCoord = getGlossUVIndex(); }
//	if(getLightUVIndex() > maxTexCoord){ maxTexCoord = getLightUVIndex(); }
//	if(getStainUVIndex() > maxTexCoord){ maxTexCoord = getStainUVIndex(); }
	return maxTexCoord + 1;
}
//------------------------------------------------------------------------------
// 描画
MStatus LampBasicMaterial::glGeometry(
	const MDagPath& shapePath, int prim, u_int writable,
	int indexCount, const u_int* indexArray,
	int vertexCount, const int* vertexIDs, const float* vertexArray,
	int normalCount, const float** normalArrays,
	int colorCount, const float** colorArrays,
	int texCoordCount, const float** texCoordArrays){
	MStatus result;

	// スタックにアトリビュートを退避
	glPushAttrib(GL_ALL_ATTRIB_BITS);
	glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);

	// マテリアルのセットアップ
	materialSetup();

	// 位置の設定
	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(3, GL_FLOAT, 0, vertexArray);

	// 法線の設定
	if(normalCount > 0){
		glEnableClientState(GL_NORMAL_ARRAY);
		glNormalPointer(GL_FLOAT, 0, normalArrays[0]);
	}else{
		glDisableClientState(GL_NORMAL_ARRAY);
		glNormal3f(0.f, 0.f, 1.f);
	}

	// テクスチャ
	if(MayaTextureManager::bind(getBaseTexture())){
		// UVの設定
		// 複数UVに対応する場合はgetTexCoordSetNamesとか使う? 
		int baseUVIndex = getBaseUVIndex();
		if(texCoordCount > baseUVIndex){
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glTexCoordPointer(2, GL_FLOAT, 0, texCoordArrays[baseUVIndex]);
		}else{
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		}
	}

	// ディフューズ
	Color4f diffuse(getDiffuseColor());
	diffuse.a = getAlpha();
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse.array);

	// スペキュラ
	Color4f specular(getSpecularColor());
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular.array);
	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, getSpecularPower());

	// アンビエント
	Color4f ambient(getAmbientColor());
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient.array);

	// エミッシブ
	Color4f emissive(getEmissiveColor());
	if(colorCount > 0){
		// 頂点カラーをエミッションとして扱う
		glEnableClientState(GL_COLOR_ARRAY);
		glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
		glEnable(GL_COLOR_MATERIAL);
		if(writable & kWriteColorArrays){
			float* colors = (float*)colorArrays[0];
			for(int i = 0; i < vertexCount; i++){
				colors[0] = colors[0] + emissive.r;
				colors[1] = colors[1] + emissive.g;
				colors[2] = colors[2] + emissive.b;
				colors[3] = colors[3];
				colors += 4;
			}
		}
		glColorPointer(4, GL_FLOAT, 0, colorArrays[0]);
	}else{
		// colorsPerVertex()が1を返す場合、こちらにはこない
		glDisableClientState(GL_COLOR_ARRAY);
		glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emissive.array);
	}

	// 描画
	glDrawElements(prim, indexCount, GL_UNSIGNED_INT, indexArray);

	glPopClientAttrib();
	glPopAttrib();

	MayaStatusCheck(result);
	MayaOpenGLCheck();
	return result;
}
//------------------------------------------------------------------------------
// アトリビュートアクセサ
//------------------------------------------------------------------------------
// ベーステクスチャの取得
MObject LampBasicMaterial::getBaseTexture() const{
	return LampMaterialUtility::getTexture(thisMObject(), "color");
}
//------------------------------------------------------------------------------
// ベーステクスチャ名の取得
String LampBasicMaterial::getBaseTextureName() const{
	return LampMaterialUtility::getTextureName(thisMObject(), "color");
}
//------------------------------------------------------------------------------
// ベースUVインデックスの取得
int LampBasicMaterial::getBaseUVIndex() const{
	return MayaAttributeUtility::getInt(thisMObject(), "baseUVIndex");
}
//------------------------------------------------------------------------------
// 光沢テクスチャの取得
MObject LampBasicMaterial::getGlossTexture() const{
	return LampMaterialUtility::getTexture(thisMObject(), "glossTexture");
}
//------------------------------------------------------------------------------
// 光沢テクスチャ名の取得
String LampBasicMaterial::getGlossTextureName() const{
	return LampMaterialUtility::getTextureName(thisMObject(), "glossTexture");
}
//------------------------------------------------------------------------------
// 光沢UVインデックスの取得
int LampBasicMaterial::getGlossUVIndex() const{
	return MayaAttributeUtility::getInt(thisMObject(), "glossUVIndex");
}
//------------------------------------------------------------------------------
// ライトテクスチャの取得
MObject LampBasicMaterial::getLightTexture() const{
	return LampMaterialUtility::getTexture(thisMObject(), "lightTexture");
}
//------------------------------------------------------------------------------
// ライトテクスチャ名の取得
String LampBasicMaterial::getLightTextureName() const{
	return LampMaterialUtility::getTextureName(thisMObject(), "lightTexture");
}
//------------------------------------------------------------------------------
// ライトUVインデックスの取得
int LampBasicMaterial::getLightUVIndex() const{
	return MayaAttributeUtility::getInt(thisMObject(), "lightUVIndex");
}
//------------------------------------------------------------------------------
// 汚れテクスチャの取得
MObject LampBasicMaterial::getStainTexture() const{
	return LampMaterialUtility::getTexture(thisMObject(), "stainTexture");
}
//------------------------------------------------------------------------------
// 汚れテクスチャ名の取得
String LampBasicMaterial::getStainTextureName() const{
	return LampMaterialUtility::getTextureName(thisMObject(), "stainTexture");
}
//------------------------------------------------------------------------------
// 汚れUVインデックスの取得
int LampBasicMaterial::getStainUVIndex() const{
	return MayaAttributeUtility::getInt(thisMObject(), "stainUVIndex");
}
//------------------------------------------------------------------------------
// ディフューズカラーの取得
Color3f LampBasicMaterial::getDiffuseColor() const{
	return MayaAttributeUtility::getColor3f(thisMObject(), "diffuseColor");
}
//------------------------------------------------------------------------------
// スペキュラカラーの取得
Color3f LampBasicMaterial::getSpecularColor() const{
	return MayaAttributeUtility::getColor3f(thisMObject(), "specularColor");
}
//------------------------------------------------------------------------------
// スペキュラパワーーの取得
float LampBasicMaterial::getSpecularPower() const{
	return MayaAttributeUtility::getFloat(thisMObject(), "specularPower");
}
//------------------------------------------------------------------------------
// アンビエントカラーの取得
Color3f LampBasicMaterial::getAmbientColor() const{
	return MayaAttributeUtility::getColor3f(thisMObject(), "ambientColor");
}
//------------------------------------------------------------------------------
// エミッシブカラーの取得
Color3f LampBasicMaterial::getEmissiveColor() const{
	return MayaAttributeUtility::getColor3f(thisMObject(), "emissiveColor");
}
//------------------------------------------------------------------------------
} // End of namespace LampForMaya
//------------------------------------------------------------------------------
