//------------------------------------------------------------------------------
// 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/Mesh/TranslationCharacterMesh.h"
#include "Graphics/Scene/Scene.h"
#include "Graphics/Mesh/MeshManager.h"
#include "Graphics/MeshData/MeshDataManager.h"
#include "Graphics/Material/MaterialManager.h"

namespace LampForMaya{

//------------------------------------------------------------------------------
// コンストラクタ
TranslationCharacterMesh::TranslationCharacterMesh(
	const String& initializeName) :
	TranslationMesh(initializeName), maxWeightCount_(0),
	weights_(NULL), boneIndices_(NULL){
}
//------------------------------------------------------------------------------
// デストラクタ
TranslationCharacterMesh::~TranslationCharacterMesh(){
	SafeArrayDelete(weights_);
	SafeArrayDelete(boneIndices_);
}
//------------------------------------------------------------------------------
// ウェイトの設定
bool TranslationCharacterMesh::setWeights(
	int boneCount, float* weights, int* weightCounts){
	// メッシュにおける最大ウェイト数の算出
	maxWeightCount_ = 0;
	for(int i = 0; i < indices_.getCount(); i++){
		int index = indices_[i];
		if(weightCounts[indices_[i]] > maxWeightCount_){
			maxWeightCount_ = weightCounts[indices_[i]];
		}
	}
	if(maxWeightCount_ == 0){
		MayaErrorOut("TranslationCharacterMesh::setWeights() "
			"Weightがありません。");
	}

	// ウェイトの設定
	weights_ = new float[indices_.getCount() * maxWeightCount_];
	boneIndices_ = new int[indices_.getCount() * maxWeightCount_];
	// デスティネーション頂点ループ
	for(int i = 0; i < indices_.getCount(); i++){
		int destinationOffset = i * maxWeightCount_;
		int index = indices_.get(i);
		int sourceOffset = index * boneCount;
		int writeCount = 0;
		// ソースボーンループ
		for(int j = 0; j < boneCount; j++){
			if(weights[sourceOffset + j] != 0.f){
				weights_[destinationOffset + writeCount] =
					weights[sourceOffset + j];
				boneIndices_[destinationOffset + writeCount] = j;
				writeCount++;
			}
		}
		// 空きデータを埋める
		for(int j = writeCount; j < maxWeightCount_; j++){
			weights_[destinationOffset + j] = 0.f;
			boneIndices_[destinationOffset + j] = 0;
		}
	}
	return true;
}
//------------------------------------------------------------------------------
// 論理チェック
bool TranslationCharacterMesh::logicalCheck(){
	if(!vertexLogicalCheck()){ return false; }
	String errorString;
	int vertexCount = positions_.getCount();
	// インデックス
	if(indices_.getCount() != vertexCount){
		errorString.format("TranslationCharacterMesh::logicalCheck() "
			"%sの頂点数(%d)とインデックス数(%d)が違います",
			name_.getBytes(), vertexCount, indices_.getCount());
		MayaErrorOut(errorString);
		return false;
	}
	return true;
}
//------------------------------------------------------------------------------
// Lampへの変換
bool TranslationCharacterMesh::convertToLamp(Scene* scene){
	// キャラクタメッシュへの変換
	Mesh* mesh = convertCharacterMesh(scene);
	// マテリアルとのリンク
	MaterialManager* materialManager = scene->getMaterialManager();
	Material* material = materialManager->search(materialName_);
	if(material == NULL){
		MayaErrorOut(String("TranslationCharacterMesh::convertToLamp() ") +
			name_ + "に接続されているマテリアル" + materialName_ +
			"が見つかりません ");
		return false;
	}
	mesh->setMaterial(material);
	return true;
}
//------------------------------------------------------------------------------
// キャラクタメッシュへの変換
Mesh* TranslationCharacterMesh::convertCharacterMesh(Scene* scene){
	MeshManager* meshManager = scene->getMeshManager();
	CharacterMesh* mesh = meshManager->createCharacterMesh(name_);
	// メッシュデータ
	MeshDataManager* meshDataManager = scene->getMeshDataManager();
	String meshDataName(name_);
	meshDataName.append("d");
	MeshData* meshData = meshDataManager->createMeshData(meshDataName);
	mesh->setMeshData(meshData);
	// 情報設定
	mesh->setPrimitiveType(Mesh::triangleList);
	int vertexCount = positions_.getCount();
	mesh->setVertexCount(vertexCount);
	mesh->enableNormal(true);
	for(int i = 0; i < vertexCount; i++){
		mesh->setPosition(i, positions_[i]);
		mesh->setNormal(i, normals_[i]);
	}
	if(colors_.getCount() != 0){
		mesh->enableColor(true);
		for(int i = 0; i < vertexCount; i++){
			Color4c color(colors_[i]);
			mesh->setColor(i, color);
		}
	}
	if(uvs_.getCount() != 0){
		mesh->setTexCoordSetCount(uvSetCount_);
		for(int i = 0; i < uvSetCount_; i++){
			mesh->setTexCoordType(i, TexCoord::type2);
		}
		int uvIndex = 0;
		int polygonCount = vertexCount / 3;
		for(int i = 0; i < polygonCount; i++){
			int vertexOffset = i * 3;
			for(int j = 0; j < uvSetCount_; j++){
				mesh->setTexCoord2(vertexOffset + 0, j, uvs_[uvIndex]);
				uvIndex++;
				mesh->setTexCoord2(vertexOffset + 1, j, uvs_[uvIndex]);
				uvIndex++;
				mesh->setTexCoord2(vertexOffset + 2, j, uvs_[uvIndex]);
				uvIndex++;
			}
		}
	}
	mesh->setBonesPerVertex(maxWeightCount_);
	int boneCount = maxWeightCount_;
	int weightCount = mesh->getWeightsPerVertex();
	for(int i = 0; i < vertexCount; i++){
		int offset = i * maxWeightCount_;
		for(int j = 0; j < boneCount; j++){
			mesh->setBoneIndex(i, j, boneIndices_[offset + j]);
		}
		// 一番最後のWeightは捨てる
		for(int j = 0; j < weightCount; j++){
			mesh->setWeight(i, j, weights_[offset + j]);
		}
	}
	return mesh;
}
//------------------------------------------------------------------------------
} // End of namespace LampForMaya
//------------------------------------------------------------------------------
