//------------------------------------------------------------------------------
// 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 "LampBasic.h"
#include "Collision/Converter/CollisionConverter.h"

#include "Graphics/Scene/Scene.h"
#include "Graphics/SceneNode/SceneNode.h"
#include "Graphics/Model/Model.h"
#include "Graphics/Mesh/Mesh.h"
#include "Graphics/Material/Material.h"

#include "Collision/System/CollisionScene.h"
#include "Collision/System/CollisionNode.h"
#include "Collision/Leaf/StaticDeformedMeshCollision.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
CollisionConverter::CollisionConverter(){
}
//------------------------------------------------------------------------------
// デストラクタ
CollisionConverter::~CollisionConverter(){
}
//------------------------------------------------------------------------------
// コンバート
bool CollisionConverter::convert(Scene* scene, CollisionScene* collisionScene){
	Assert((scene != NULL) && (collisionScene != NULL));
	collisionScene_ = collisionScene;
	SceneNode* sceneNode = scene->getRootNode();
	CollisionNode* collisionNode = collisionScene_->getRootNode();
	// 子ノードループ
	int nodeCount = sceneNode->getSceneNodeCount();
	for(int i = 0; i < nodeCount; i++){
		if(!convertNode(collisionNode, sceneNode->getSceneNode(i))){
			return false;
		}
	}
	// 子リーフループ
	int leafCount = sceneNode->getSceneLeafCount();
	for(int i = 0; i < leafCount; i++){
		if(!convertLeaf(collisionNode, sceneNode->getSceneLeaf(i))){
			return false;
		}
	}
	return true;
}
//------------------------------------------------------------------------------
// ノードのコンバート
bool CollisionConverter::convertNode(
	CollisionNode* parentCollisionNode, SceneNode* sceneNode){
	// ノードのコンバート
	CollisionNode* collisionNode =
		collisionScene_->createCollisionNode(sceneNode->getName());
	parentCollisionNode->addChild(collisionNode);
	collisionNode->setEnabled(sceneNode->isEnabled());
	collisionNode->setScale(sceneNode->getScale());
	collisionNode->setRotationXYZ(sceneNode->getRotationXYZ());
	collisionNode->setTranslation(sceneNode->getTranslation());

	// 子ノードループ
	int nodeCount = sceneNode->getSceneNodeCount();
	for(int i = 0; i < nodeCount; i++){
		if(!convertNode(collisionNode, sceneNode->getSceneNode(i))){
			return false;
		}
	}
	// 子リーフループ
	int leafCount = sceneNode->getSceneLeafCount();
	for(int i = 0; i < leafCount; i++){
		if(!convertLeaf(collisionNode, sceneNode->getSceneLeaf(i))){
			return false;
		}
	}
	return true;
}
//------------------------------------------------------------------------------
// リーフのコンバート
bool CollisionConverter::convertLeaf(
	CollisionNode* parentCollisionNode, SceneLeaf* sceneLeaf){
	// モデルでなかったら無視する
	if(!sceneLeaf->isModel()){ return true; }
	Model* model = sceneLeaf->castModel();
	int meshCount = model->getMeshCount();
	for(int i = 0; i < meshCount; i++){
		Mesh* mesh = model->getMesh(i);
		// コンバート対象の振り分けを行う
		convertStaticDeformedMesh(parentCollisionNode, mesh);
	}
	return true;
}
//------------------------------------------------------------------------------
// 静的変形メッシュのコンバート
bool CollisionConverter::convertStaticDeformedMesh(
	CollisionNode* parentCollisionNode, Mesh* mesh){
	// メッシュのコンバート
	StaticDeformedMeshCollision* collisionMesh =
		collisionScene_->createStaticDeformedMeshCollision(mesh->getName());
	if(!setCollisionLeafData(parentCollisionNode, mesh, collisionMesh)){
		return false;
	}

	// 静的変形メッシュのコンバート
	Mesh::PrimitiveType type = mesh->getPrimitiveType();
	if((type != Mesh::triangleList) && (type != Mesh::indexedTriangleList)){
		ErrorOut("CollisionConverter::convertStaticDeformedMesh() "
			"サポートされていないプリミティブタイプです %s",
			mesh->getName().getBytes());
		return false;
	}

	// バウンディング
	collisionMesh->setBoundingBox(mesh->getBoundingBox());
	collisionMesh->setBoundingSphere(mesh->getBoundingSphere());

	// 三角の取得
	int triangleCount = mesh->getPrimitiveCount();
	collisionMesh->setTriangleCount(triangleCount);
	for(int i = 0; i < triangleCount; i++){
		collisionMesh->setTriangle(i, mesh->getTriangle(i));
	}
	return true;
}
//------------------------------------------------------------------------------
// コリジョンリーフデータ設定
bool CollisionConverter::setCollisionLeafData(
	CollisionNode* parentCollisionNode, Mesh* mesh,
	CollisionLeaf* collisionLeaf){
	parentCollisionNode->addChild(collisionLeaf);
	// 有効、無効はメッシュから取得
	collisionLeaf->setEnabled(mesh->isEnabled());
	// コリジョンマスクはライトマスクから取得
	Material* material = mesh->getMaterial();
	if(material == NULL){
		ErrorOut("CollisionConverter::setCollisionLeafData() "
			"マテリアルが設定されていません %s", mesh->getName().getBytes());
		return false;
	}
	collisionLeaf->setCollisionMask(material->getLightMask());
	return true;
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
