//------------------------------------------------------------------------------
// 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 "Test/stdafx.h"
#include "Graphics/Camera/CameraTest.h"
#include "Graphics/System/LampGraphics.h"
#include "Graphics/Camera/CameraManager.h"

//------------------------------------------------------------------------------
// テストスィートの取得
Test* CameraTest::suite(){
	TestSuite* suite = new TestSuite("CameraTest");
	suite->addTest(new TestCaller(CameraTest, testData));
	suite->addTest(new TestCaller(CameraTest, testCopy));
	suite->addTest(new TestCaller(CameraTest, testProjection));
	suite->addTest(new TestCaller(CameraTest, testView));
	return suite;
}
//------------------------------------------------------------------------------
// データテスト
void CameraTest::testData(){
//	TestEquals(96, (int)sizeof(Camera));
	Scene* scene = LampGraphics::createScene("test");
	CameraManager* manager = scene->getCameraManager();
	Camera* camera0 = manager->createCamera("camera0");
	TestAssert(camera0->isCamera());
	// 名前
	TestEquals("camera0", camera0->getName());
	// 後始末
	manager->destroy(camera0);
	TestEquals(0, scene->clear());
	LampGraphics::destroyScene(scene);
}
//------------------------------------------------------------------------------
// コピーテスト
void CameraTest::testCopy(){
	Scene* scene = LampGraphics::createScene("test");
	CameraManager* manager = scene->getCameraManager();
	Camera* camera0 = manager->createCamera("camera0");

	Camera* copyCamera = camera0->copy();
	TestEquals("camera0_0", copyCamera->getName());

	// 後始末
	TestEquals(2, scene->clear());
	LampGraphics::destroyScene(scene);
}
//------------------------------------------------------------------------------
// 射影テスト
void CameraTest::testProjection(){
	Scene* scene = LampGraphics::createScene("test");
	CameraManager* manager = scene->getCameraManager();
	Camera* camera0 = manager->createCamera("camera0");
	D3DXMATRIXA16 d3dMatrix;
	D3DXMatrixPerspectiveFovRH(&d3dMatrix,
		Math::toRadian(60.f), 640.f / 480.f, 1.f, 10000.f);
//	camera0->setPerspectiveFovY(Math::toRadian(60.f), 640.f / 480.f, 1.f, 10000.f);
	TestAssert(d3dEpsilonEquals(
		d3dMatrix, camera0->getProjectionMatrix(), Math::epsilon));
	// setPerspectiveOffCenter
	D3DXMatrixPerspectiveOffCenterRH(&d3dMatrix,
		-1.f, 0.f, 0.f, 1.f, 2.f, 10.f);
	camera0->setPerspectiveOffCenter(-1.f, 0.f, 0.f, 1.f, 2.f, 10.f);
	TestAssert(d3dEquals(d3dMatrix, camera0->getProjectionMatrix()));
	TestEquals(-1.f, camera0->getLeft());
	TestEquals(0.f, camera0->getRight());
	TestEquals(0.f, camera0->getBottom());
	TestEquals(1.f, camera0->getTop());
	TestEquals(2.f, camera0->getNearClip());
	TestEquals(10.f, camera0->getFarClip());
	TestEquals(1.f, camera0->getWidth());
	TestEquals(1.f, camera0->getHeight());
	TestEquals(0.48995733f, camera0->getFovY());
	TestEquals(1.f, camera0->getAspect());
	// setPerspective
	D3DXMatrixPerspectiveRH(&d3dMatrix, 2.f, 2.f, 3.f, 9.f);
	camera0->setPerspective(2.f, 2.f, 3.f, 9.f);
	TestAssert(d3dEquals(d3dMatrix, camera0->getProjectionMatrix()));
	TestEquals(2.f, camera0->getWidth());
	TestEquals(2.f, camera0->getHeight());
	TestEquals(3.f, camera0->getNearClip());
	TestEquals(9.f, camera0->getFarClip());
	TestEquals(-1.f, camera0->getLeft());
	TestEquals(1.f, camera0->getRight());
	TestEquals(-1.f, camera0->getBottom());
	TestEquals(1.f, camera0->getTop());
	TestEquals(0.6435011f, camera0->getFovY());
	TestEquals(1.f, camera0->getAspect());
	// setPerspectiveFovY
	D3DXMatrixPerspectiveFovRH(&d3dMatrix,
		Math::quadrantPI, 1.33333f, 4.f, 8.f);
	camera0->setPerspectiveFovY(Math::quadrantPI, 1.33333f, 4.f, 8.f);
	TestAssert(d3dEquals(d3dMatrix, camera0->getProjectionMatrix()));
	TestEquals(Math::quadrantPI, camera0->getFovY());
	TestEquals(1.33333f, camera0->getAspect());
	TestEquals(4.f, camera0->getNearClip());
	TestEquals(8.f, camera0->getFarClip());
	TestEquals(-2.20913363f, camera0->getLeft());
	TestEquals(2.20913363f, camera0->getRight());
	TestEquals(-1.65685427f, camera0->getBottom());
	TestEquals(1.65685427f, camera0->getTop());
	TestEquals(4.41826725f, camera0->getWidth());
	TestEquals(3.31370854f, camera0->getHeight());
	// setOrthoOffCenter
	D3DXMatrixOrthoOffCenterRH(&d3dMatrix,
		-1.f, 0.f, 0.f, 1.f, 2.f, 10.f);
	camera0->setOrthoOffCenter(-1.f, 0.f, 0.f, 1.f, 2.f, 10.f);
	TestAssert(d3dEquals(d3dMatrix, camera0->getProjectionMatrix()));
	TestEquals(-1.f, camera0->getLeft());
	TestEquals(0.f, camera0->getRight());
	TestEquals(0.f, camera0->getBottom());
	TestEquals(1.f, camera0->getTop());
	TestEquals(2.f, camera0->getNearClip());
	TestEquals(10.f, camera0->getFarClip());
	TestEquals(1.f, camera0->getWidth());
	TestEquals(1.f, camera0->getHeight());
	TestEquals(0.f, camera0->getFovY());
	TestEquals(1.f, camera0->getAspect());
	// setOrtho
	D3DXMatrixOrthoRH(&d3dMatrix, 2.f, 2.f, 3.f, 9.f);
	camera0->setOrtho(2.f, 2.f, 3.f, 9.f);
	TestAssert(d3dEquals(d3dMatrix, camera0->getProjectionMatrix()));
	TestEquals(2.f, camera0->getWidth());
	TestEquals(2.f, camera0->getHeight());
	TestEquals(3.f, camera0->getNearClip());
	TestEquals(9.f, camera0->getFarClip());
	TestEquals(-1.f, camera0->getLeft());
	TestEquals(1.f, camera0->getRight());
	TestEquals(-1.f, camera0->getBottom());
	TestEquals(1.f, camera0->getTop());
	TestEquals(0.f, camera0->getFovY());
	TestEquals(1.f, camera0->getAspect());
	// 後始末
	TestEquals(1, scene->clear());
	LampGraphics::destroyScene(scene);
}
//------------------------------------------------------------------------------
// ビューテスト
void CameraTest::testView(){
	Scene* scene = LampGraphics::createScene("test");
	CameraManager* manager = scene->getCameraManager();
	Camera* camera0 = manager->createCamera("camera0");
	TestAssert(camera0->getViewMatrix() == Matrix44::unit);
	// setViewMatrix
	Matrix44 mat0;
	mat0.setRotationXYZ(Vector3(1.f, 2.f, 3.f));
	mat0.addTranslation(1.f, 2.f, 3.f);
	camera0->setViewMatrix(mat0);
	TestAssert(camera0->getViewMatrix() == mat0);
	// setTransformation
	camera0->setTransformation(Vector3(1.f, 2.f, 3.f), Vector3(1.f, 2.f, 3.f));
	Matrix44 viewMatrix;
	viewMatrix.setTranslation(Vector3(-1.f, -2.f, -3.f));
	viewMatrix.addRotationZYX(Vector3(-1.f, -2.f, -3.f));
	TestAssert(camera0->getViewMatrix() == viewMatrix);
	// setLookAt
	D3DXMATRIXA16 d3dMatrix;
	D3DXVECTOR3 eye(1.f, 2.f, 3.f);
	D3DXVECTOR3 at(0.f, 0.f, 0.f);
	D3DXVECTOR3 up(0.f, 1.f, 0.f);
	D3DXMatrixLookAtRH(&d3dMatrix, &eye, &at, &up);
	camera0->setLookAt(Vector3(1.f, 2.f, 3.f),
		Vector3(0.f, 0.f, 0.f), Vector3(0.f, 1.f, 0.f));
	TestAssert(d3dEpsilonEquals(
		d3dMatrix, camera0->getViewMatrix(), Math::epsilon));
	// 後始末
	TestEquals(1, scene->clear());
	LampGraphics::destroyScene(scene);
}
//------------------------------------------------------------------------------
// Direct3D行列との比較
bool CameraTest::d3dEquals(D3DXMATRIX& d3d, const Matrix44& mtx){
	return(
		(d3d.m[0][0] == mtx.m00) &&
		(d3d.m[0][1] == mtx.m10) &&
		(d3d.m[0][2] == mtx.m20) &&
		(d3d.m[0][3] == mtx.m30) &&
		(d3d.m[1][0] == mtx.m01) &&
		(d3d.m[1][1] == mtx.m11) &&
		(d3d.m[1][2] == mtx.m21) &&
		(d3d.m[1][3] == mtx.m31) &&
		(d3d.m[2][0] == mtx.m02) &&
		(d3d.m[2][1] == mtx.m12) &&
		(d3d.m[2][2] == mtx.m22) &&
		(d3d.m[2][3] == mtx.m32) &&
		(d3d.m[3][0] == mtx.m03) &&
		(d3d.m[3][1] == mtx.m13) &&
		(d3d.m[3][2] == mtx.m23) &&
		(d3d.m[3][3] == mtx.m33));
}
//------------------------------------------------------------------------------
// Direct3D行列との比較
bool CameraTest::d3dEpsilonEquals(
	D3DXMATRIX& d3d, const Matrix44& mtx, float epsilon){
	return(
		(Math::abs(d3d.m[0][0] - mtx.m00) <= epsilon) &&
		(Math::abs(d3d.m[0][1] - mtx.m10) <= epsilon) &&
		(Math::abs(d3d.m[0][2] - mtx.m20) <= epsilon) &&
		(Math::abs(d3d.m[0][3] - mtx.m30) <= epsilon) &&
		(Math::abs(d3d.m[1][0] - mtx.m01) <= epsilon) &&
		(Math::abs(d3d.m[1][1] - mtx.m11) <= epsilon) &&
		(Math::abs(d3d.m[1][2] - mtx.m21) <= epsilon) &&
		(Math::abs(d3d.m[1][3] - mtx.m31) <= epsilon) &&
		(Math::abs(d3d.m[2][0] - mtx.m02) <= epsilon) &&
		(Math::abs(d3d.m[2][1] - mtx.m12) <= epsilon) &&
		(Math::abs(d3d.m[2][2] - mtx.m22) <= epsilon) &&
		(Math::abs(d3d.m[2][3] - mtx.m32) <= epsilon) &&
		(Math::abs(d3d.m[3][0] - mtx.m03) <= epsilon) &&
		(Math::abs(d3d.m[3][1] - mtx.m13) <= epsilon) &&
		(Math::abs(d3d.m[3][2] - mtx.m23) <= epsilon) &&
		(Math::abs(d3d.m[3][3] - mtx.m33) <= epsilon));
}
//------------------------------------------------------------------------------
