//------------------------------------------------------------------------------
// 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/Camera/TranslationCamera.h"
#include "Translator/Camera/TranslationCameraManager.h"
#include "Translator/Model/TranslationModelManager.h"
#include "Translator/Animation/TranslationAnimationUtility.h"
#include "Graphics/Scene/Scene.h"
#include "Graphics/Camera/CameraManager.h"
#include "Graphics/Model/ModelManager.h"
#include "Animation/VectorInterpolator/VectorArrayInterpolator.h"
#include "Animation/RotationInterpolator/EulerArrayInterpolator.h"
#include "Animation/System/AnimationManager.h"
#include "Animation/System/AnimationSet.h"
#include "Animation/Camera/CameraAnimation.h"

namespace LampForMaya{

//------------------------------------------------------------------------------
// コンストラクタ
TranslationCamera::TranslationCamera(
	const MDagPath& initializePath, const String& initializeName) :
	dagPath_(initializePath), name_(initializeName),
	rotationAnimation_(NULL), translationAnimation_(NULL),
	hasAnimation_(false){
	MStatus result;
	// オブジェクトの取得
	object_ = dagPath_.node(&result);
	MayaStatusCheck(result);
}
//------------------------------------------------------------------------------
// デストラクタ
TranslationCamera::~TranslationCamera(){
	SafeDelete(translationAnimation_);
	SafeDelete(rotationAnimation_);
}
//------------------------------------------------------------------------------
// 分析
bool TranslationCamera::analyze(){
	MStatus result;
	String errorString;
	MFnDagNode dagNode(dagPath_, &result);
	MayaStatusCheck(result);

	// トランスフォーム初期化
	MFnTransform transform(dagPath_.transform(), &result);
	MayaStatusCheck(result);

	// スケールピボット移動値が0であるかチェック
	MPoint scalePivotTrans =
		transform.scalePivotTranslation(MSpace::kTransform, &result);
	MayaStatusCheck(result);
	if(!zeroCheck(scalePivotTrans)){
		errorString.format("TranslationCamera::analyze() "
			"scalePivotTranslationが0でない ( %8f, %8f, %8f ) %s",
			scalePivotTrans.x, scalePivotTrans.y, scalePivotTrans.z,
			name_.getBytes());
		MayaErrorOut(errorString);
		return false;
	}

	// 回転ピボット移動値が0であるかチェック
	MPoint rotationPivotTrans =
		transform.rotatePivotTranslation(MSpace::kTransform, &result);
	MayaStatusCheck(result);
	if(!zeroCheck(rotationPivotTrans)){
		errorString.format("TranslationCamera::analyze() "
			"rotationPivotTransが0でない ( %8f, %8f, %8f ) %s",
			rotationPivotTrans.x, rotationPivotTrans.y,
			rotationPivotTrans.z, name_.getBytes());
		MayaErrorOut(errorString);
		return false;
	}

	// シアーが0であるかチェック
	double shearArray[3];
	result = transform.getShear(shearArray);
	MPoint shear(shearArray);
	if(!zeroCheck(shear)){
		errorString.format("TranslationCamera::analyze() "
			"shearが0でない ( %8f, %8f, %8f ) %s",
			shear.x, shear.y, shear.z, name_.getBytes());
		MayaErrorOut(errorString);
		return false;
	}

	// スケールピボットが0であるかチェック
	MPoint scalePivot = transform.scalePivot(MSpace::kTransform, &result);
	MayaStatusCheck(result);
	if(!zeroCheck(scalePivot)){
		errorString.format("TranslationCamera::analyze() "
			"scalePivotが0でない ( %8f, %8f, %8f ) %s",
			scalePivot.x, scalePivot.y, scalePivot.z,
			name_.getBytes());
		MayaErrorOut(errorString);
		return false;
	}

	// 回転ピボットが0であるかチェック
	MPoint rotationPivot = transform.rotatePivot(MSpace::kTransform, &result);
	MayaStatusCheck(result);
	if(!zeroCheck(rotationPivot)){
		errorString.format("TranslationCamera::analyze() "
			"rotationPivotTransが0でない ( %8f, %8f, %8f ) %s",
			rotationPivot.x, rotationPivot.y,
			rotationPivot.z, name_.getBytes());
		MayaErrorOut(errorString);
		return false;
	}

	// スケールが1であるかチェック
	double scale[3];
	result = transform.getScale(scale);
	MayaStatusCheck(result);
	if((scale[0] != 1.0) || (scale[1] != 1.0) || (scale[2] != 1.0)){
		errorString.format("TranslationCamera::analyze() "
			"scaleが1でない ( %8f, %8f, %8f ) %s",
			(float)scale[0], (float)scale[1], (float)scale[2],
			name_.getBytes());
		MayaErrorOut(errorString);
		return false;
	}

	// 回転
	MEulerRotation rotation;
	result = transform.getRotation(rotation);
	MayaStatusCheck(result);
	if(rotation.order != MEulerRotation::kXYZ){
		errorString.format("TranslationCamera::analyze() "
			"回転順序はXYZしかサポートしていません %s", name_.getBytes());
		MayaErrorOut(errorString);
		return false;
	}
	rotation_.set((float)rotation.x, (float)rotation.y, (float)rotation.z);

	// 移動
	MVector translation = transform.translation(MSpace::kTransform, &result);
	MayaStatusCheck(result);
	translation_.set(
		(float)translation.x, (float)translation.y, (float)translation.z);

// nearClippingPlane , farClippingPlane
//angle of view = 2 * atan(apertureVertical * 25.4/(2*focal_length))

//	DebugOut("\n%s\n", name_.getBytes());
//	DebugOut("rotation %s\n", rotation_.toString().getBytes());
//	DebugOut("translation %s\n", translation_.toString().getBytes());
	return true;
}
//------------------------------------------------------------------------------
// ゼロチェック
bool TranslationCamera::zeroCheck(const MPoint& point){
	if(	(Math::abs((float)point.x) > Math::epsilon) ||
		(Math::abs((float)point.y) > Math::epsilon) ||
		(Math::abs((float)point.z) > Math::epsilon)){
		return false;
	}
	return true;
}
//------------------------------------------------------------------------------
// アニメーションの分析
bool TranslationCamera::analyzeAnimation(){
	hasAnimation_ = false;
	// シーケンスの分析、シーケンスが無ければアニメーション無し
	if(!sequence_.analyze(object_)){ return true; }
	int startTime = sequence_.getStartTime(0);
	int endTime = sequence_.getEndTime(sequence_.getSequenceCount() - 1);
	// 回転アニメーション
	// LookAtは回転がLookAtノードに接続されているのでアニメーションカーブ取得できず
	// アトリビュートをevaluteするような形に持っていきたい
	rotationAnimation_ =
		TranslationAnimationUtility::analyzeRotationAnimation(
		dagPath_.transform(), "rotate", rotation_, startTime, endTime);
	if(rotationAnimation_ != NULL){ hasAnimation_ = true; }
	// 移動アニメーション
	translationAnimation_ =
		TranslationAnimationUtility::analyzeVectorAnimation(
		dagPath_.transform(), "translate", translation_, startTime, endTime);
	if(translationAnimation_ != NULL){ hasAnimation_ = true; }
//	DebugOut("\nanim %s\n", name_.getBytes());
//	DebugOut("%d  %d\n", startTime, endTime);
//	DebugOut("%x  %x\n", rotationAnimation_, translationAnimation_);
	return true;
}
//------------------------------------------------------------------------------
// Lampへの変換
bool TranslationCamera::convertToLamp(Scene* scene){
	CameraManager* cameraManager = scene->getCameraManager();
	camera_ = cameraManager->createCamera(name_);
	camera_->setTransformation(rotation_, translation_);
	return true;
}
//------------------------------------------------------------------------------
// アニメーションの変換
bool TranslationCamera::convertAnimation(
	AnimationManager* animationManager, AnimationSet* animationSet){
	if(!hasAnimation_){ return true; }
	if(!sequence_.hasSequence()){ return true; }
	CameraAnimation* animation = animationManager->createCamera(name_);
	if(animation->getName() != name_){
		MayaErrorOut(String("TranslationCamera::convertAnimation() ") +
			name_ + "の名前が重複しています ");
		return false;
	}
	CameraAnimationData* data =
		animationManager->createCameraData(name_);
	if(data->getName() != name_){
		MayaErrorOut(String("TranslationCamera::convertAnimation() ") +
			name_ + "の名前が重複しています ");
		return false;
	}
	// アニメーションの設定
	animation->setTargetName(name_);
	animation->setCameraAnimationData(data);
	animationSet->addAnimation(animation);
	// アニメーションデータの設定
	int sequenceCount = sequence_.getSequenceCount();
	data->setSequenceCount(sequenceCount);
	for(int i = 0; i < sequenceCount; i++){
		int startTime = sequence_.getStartTime(i);
		int endTime = sequence_.getEndTime(i);
		int size = endTime - startTime + 1;
		// 回転アニメーションの準備
		EulerArrayInterpolator* rotation = NULL;
		if(rotationAnimation_ != NULL){
			rotation = new EulerArrayInterpolator();
			rotation->setSize(size);
			for(int j = 0; j < size; j++){
				rotation->setValue(j,
					rotationAnimation_->getValue(startTime + j));
			}
		}
		// 移動アニメーションの準備
		VectorArrayInterpolator* translation = NULL;
		if(translationAnimation_ != NULL){
			translation = new VectorArrayInterpolator();
			translation->setSize(size);
			for(int j = 0; j < size; j++){
				translation->setValue(j,
					translationAnimation_->getValue(startTime + j));
			}
		}
		// データの設定
		if(rotation != NULL){ data->setRotation(i, rotation); }
		if(translation != NULL){
			data->setTranslation(i, translation);
		}
		data->setLooped(i, sequence_.isLooped(i));
	}
	return true;
}
//------------------------------------------------------------------------------
} // End of namespace LampForMaya
//------------------------------------------------------------------------------
