//------------------------------------------------------------------------------
// 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 "System/stdafx.h"
#include "Translator/Model/TranslationStandardModel.h"
#include "Translator/Mesh/TranslationMeshManager.h"
#include "Graphics/Scene/Scene.h"
#include "Graphics/Model/ModelManager.h"
#include "Graphics/Mesh/MeshManager.h"

namespace LampForMaya{

//------------------------------------------------------------------------------
// コンストラクタ
TranslationStandardModel::TranslationStandardModel(
	const MObject& initializeObject, const String& initializeName) :
	TranslationModel(initializeObject, initializeName), transMeshes_(NULL){
}
//------------------------------------------------------------------------------
// デストラクタ
TranslationStandardModel::~TranslationStandardModel(){
	SafeArrayDelete(transMeshes_);
}
//------------------------------------------------------------------------------
// 分析
bool TranslationStandardModel::analyze(TranslationMeshManager* meshManager){
	// モデルの分析
	if(!analyzeModel()){ return false; }

	MStatus result;
	String errorString;
	MFnMesh fnMesh(object_, &result);
	MayaStatusCheck(result);

	// UVセット数の取得
	MStringArray uvSetNames;
	MayaStatusCheck(fnMesh.getUVSetNames(uvSetNames));
	int uvSetCount = uvSetNames.length();

	// シェーダ情報の取得
	MObjectArray shaders;
	MIntArray shaderIndices;
	// 常にインスタンス番号0番のモデルデータを使用する
	result = fnMesh.getConnectedShaders(0, shaders, shaderIndices);
	MayaStatusCheck(result);

	// シェーダが割り当てられていないポリゴンがあればエラー
	for(u_int i = 0; i < shaderIndices.length(); i++){
		if(shaderIndices[i] == -1){
			MIntArray vertexIndex;
			MayaStatusCheck(fnMesh.getPolygonVertices(i, vertexIndex));
			int vertexCount = vertexIndex.length();
			errorString.format("TranslationStandardModel::analyze() "
				"%sにシェーダの割り当てられいないポリゴンがあります ",
				name_.getBytes());
			for(int i = 0; i < vertexCount; i++){
				MPoint position;
				MayaStatusCheck(fnMesh.getPoint(vertexIndex[i], position));
				String temp;
				temp.format(" ( %.3f , %.3f , %.3f)",
					position.x, position.y, position.z);
				errorString += temp;
			}
			MayaErrorOut(errorString);
			return false;
		}
	}

	// シェーダの数だけメッシュを用意する
	int meshCount = shaders.length();
	int nameCount = 0;
	transMeshes_ = new TranslationRigidMesh*[meshCount];
	for(int i = 0; i < meshCount; i++){
		// 重複の無い名前を作成
		String meshName;
		while(true){
			meshName.format("%sM%d", name_.getBytes(), nameCount);
			nameCount++;
			TranslationMesh* exist = meshManager->search(meshName);
			if(exist == NULL){ break; }
		}
		transMeshes_[i] = meshManager->createRigidMesh(meshName);
		// モデルにメッシュを追加する
		meshes_.add(transMeshes_[i]);
		// UVセット数を設定する
		transMeshes_[i]->setUVSetCount(uvSetCount);
		// シェーダ名を設定する
		transMeshes_[i]->setMaterialName(getShaderName(shaders[i]));
	}

	// ポリゴンをメッシュに割り振る
	MItMeshPolygon polygonIterator(object_, &result);
	MayaStatusCheck(result);
	int polygonCount = 0;
	for( ; !polygonIterator.isDone(); polygonIterator.next()){
		int shaderIndex = shaderIndices[polygonCount];
		polygonCount++;
		TranslationRigidMesh* mesh = transMeshes_[shaderIndex];

		// 位置
		MPointArray positions;
		polygonIterator.getPoints(positions, MSpace::kObject, &result);
		MayaStatusCheck(result);
		bool isSquare = (positions.length() == 4);
		if((positions.length() != 3) && (!isSquare)){
			errorString.format("TranslationStandardModel::analyze() "
				"%sが三角、四角以外のポリゴン(%d角形)を持っています\n",
				name_.getBytes(), positions.length());
			for(u_int i = 0; i < positions.length(); i++){
				String temp;
				temp.format(" %d ( %.3f , %.3f , %.3f)",
					i, positions[i].x, positions[i].y, positions[i].z);
				errorString += temp;
			}
			MayaErrorOut(errorString);
			return false;
		}
		mesh->addPosition(Vector3((float)positions[0].x,
			(float)positions[0].y, (float)positions[0].z));
		mesh->addPosition(Vector3((float)positions[1].x,
			(float)positions[1].y, (float)positions[1].z));
		mesh->addPosition(Vector3((float)positions[2].x,
			(float)positions[2].y, (float)positions[2].z));
		if(isSquare){
			mesh->addPosition(Vector3((float)positions[0].x,
				(float)positions[0].y, (float)positions[0].z));
			mesh->addPosition(Vector3((float)positions[2].x,
				(float)positions[2].y, (float)positions[2].z));
			mesh->addPosition(Vector3((float)positions[3].x,
				(float)positions[3].y, (float)positions[3].z));
		}

		// 法線
		MVectorArray normals;
		result = polygonIterator.getNormals(normals, MSpace::kObject);
		MayaStatusCheck(result);
		mesh->addNormal(Vector3(
			(float)normals[0].x, (float)normals[0].y, (float)normals[0].z));
		mesh->addNormal(Vector3(
			(float)normals[1].x, (float)normals[1].y, (float)normals[1].z));
		mesh->addNormal(Vector3(
			(float)normals[2].x, (float)normals[2].y, (float)normals[2].z));
		if(isSquare){
			mesh->addNormal(Vector3(
				(float)normals[0].x, (float)normals[0].y, (float)normals[0].z));
			mesh->addNormal(Vector3(
				(float)normals[2].x, (float)normals[2].y, (float)normals[2].z));
			mesh->addNormal(Vector3(
				(float)normals[3].x, (float)normals[3].y, (float)normals[3].z));
		}

		// カラー
		bool hasColor = polygonIterator.hasColor(&result);
		MayaStatusCheck(result);
		if(hasColor){
			MColorArray colors;
			result = polygonIterator.getColors(colors);
			MayaStatusCheck(result);
			mesh->addColor(Color4f(
				colors[0].r, colors[0].g, colors[0].b, colors[0].a));
			mesh->addColor(Color4f(
				colors[1].r, colors[1].g, colors[1].b, colors[1].a));
			mesh->addColor(Color4f(
				colors[2].r, colors[2].g, colors[2].b, colors[2].a));
			if(isSquare){
				mesh->addColor(Color4f(
					colors[0].r, colors[0].g, colors[0].b, colors[0].a));
				mesh->addColor(Color4f(
					colors[2].r, colors[2].g, colors[2].b, colors[2].a));
				mesh->addColor(Color4f(
					colors[3].r, colors[3].g, colors[3].b, colors[3].a));
			}
		}

		// UV
		MFloatArray uArray, vArray;
		for(int i = 0; i < uvSetCount; i++){
			result = polygonIterator.getUVs(uArray, vArray, &uvSetNames[i]);
			if(!result){
				errorString.format("TranslationStandardModel::analyze "
					"UVの取得に失敗しました %s %s (%.2f, %.2f, %.2f) %s",
					name_.getBytes(), uvSetNames[i].asChar(),
					positions[0].x, positions[0].y, positions[0].z,
					result.errorString().asChar());
				MayaErrorOut(errorString);
				return false;
			}
			// V座標を反転する
			mesh->addUV(TexCoord2(uArray[0], (vArray[0] - 1.f) * -1.f));
			mesh->addUV(TexCoord2(uArray[1], (vArray[1] - 1.f) * -1.f));
			mesh->addUV(TexCoord2(uArray[2], (vArray[2] - 1.f) * -1.f));
		}
		if(isSquare){
			for(int i = 0; i < uvSetCount; i++){
				result = polygonIterator.getUVs(uArray, vArray, &uvSetNames[i]);
				if(!result){
					errorString.format("TranslationStandardModel::analyze "
						"UVの取得に失敗しました %s %s (%.2f, %.2f, %.2f) %s",
						name_.getBytes(), uvSetNames[i].asChar(),
						positions[0].x, positions[0].y, positions[0].z,
						result.errorString().asChar());
					MayaErrorOut(errorString);
					return false;
				}
				// V座標を反転する
				mesh->addUV(TexCoord2(uArray[0], (vArray[0] - 1.f) * -1.f));
				mesh->addUV(TexCoord2(uArray[2], (vArray[2] - 1.f) * -1.f));
				mesh->addUV(TexCoord2(uArray[3], (vArray[3] - 1.f) * -1.f));
			}
		}
	}

	// メッシュの論理チェック
	for(int i = 0; i < meshCount; i++){
		if(!transMeshes_[i]->logicalCheck()){ return false; }
	}
	return true;
}
//------------------------------------------------------------------------------
// Lampへの変換
bool TranslationStandardModel::convertToLamp(Scene* scene){
	ModelManager* modelManager = scene->getModelManager();
	StandardModel* model = modelManager->createStandardModel(name_);
	// 有効、無効フラグ
	model->setEnabled(visibility_);
	// メッシュとのリンク
	MeshManager* meshManager = scene->getMeshManager();
	int meshCount = meshes_.getCount();
	for(int i = 0; i < meshCount; i++){
		String meshName = meshes_.get(i)->getName();
		Mesh* mesh = meshManager->search(meshName);
		if(mesh == NULL){
			MayaErrorOut(String("TranslationStandardModel::convertToLamp() "
				"メッシュが見つかりません ") + meshName);
			return false;
		}
		model->addMesh(mesh);
	}
	return true;
}
//------------------------------------------------------------------------------
} // End of namespace LampForMaya
//------------------------------------------------------------------------------
