//------------------------------------------------------------------------------
// 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 "Framework/Utility/FirstPersonCameraController.h"
#include "Graphics/Camera/Camera.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
FirstPersonCameraController::FirstPersonCameraController(){
	camera_ = NULL;
	cameraPosition_ = Vector3::zero;
	cameraRotation_ = Vector3::zero;
	fovY_ = 60.f;
	cameraPositionSensibility_ = 0.05f;
	cameraRotationSensibility_ = 0.005f;
	keyboardSensibility_ = 25.f;
	mouseXPosition_ = 0;
	mouseYPosition_ = 0;
}
//------------------------------------------------------------------------------
// デストラクタ
FirstPersonCameraController::~FirstPersonCameraController(){
}
//------------------------------------------------------------------------------
// セットアップ
void FirstPersonCameraController::setup(
	float nearClip, float farClip, float aspect){
	if(camera_ == NULL){ return; }
	camera_->setPerspectiveFovY(
		Math::toRadian(fovY_), aspect, nearClip, farClip);
	camera_->setTransformation(cameraRotation_, cameraPosition_);
	informationString_.format(
		"pos { %.1f, %.1f, %.1f } rot { %.1f, %.1f, %.1f } "
		"near %.1f far %.1f fovY %.1f aspect %.2f",
		cameraPosition_.x, cameraPosition_.y, cameraPosition_.z,
		cameraRotation_.x, cameraRotation_.y, cameraRotation_.z,
		nearClip, farClip, fovY_, aspect);
}
//------------------------------------------------------------------------------
// ウィンドウプロシージャ
LRESULT FirstPersonCameraController::windowProcedure(
	HWND windowHandle, u_int message, WPARAM wParam, LPARAM lParam){
	if(camera_ == NULL){ return 0; }
	bool cameraChanged = false;
	Vector3 cameraAddRotation(0.f, 0.f, 0.f);
	Vector3 cameraAddTranslation(0.f, 0.f, 0.f);
	switch(message){
	// キー入力に対応
	case WM_KEYDOWN:
		switch(wParam){
		case 'F':
			cameraAddTranslation.x += cameraPositionSensibility_;
			cameraChanged = true;
			break;
		case 'S':
			cameraAddTranslation.x -= cameraPositionSensibility_;
			cameraChanged = true;
			break;
		case 'R':
			cameraAddTranslation.y += cameraPositionSensibility_;
			cameraChanged = true;
			break;
		case 'V':
			cameraAddTranslation.y -= cameraPositionSensibility_;
			cameraChanged = true;
			break;
		case 'D':
			cameraAddTranslation.z += cameraPositionSensibility_;
			cameraChanged = true;
			break;
		case 'E':
			cameraAddTranslation.z -= cameraPositionSensibility_;
			cameraChanged = true;
			break;
		}
		if(cameraChanged){
			cameraAddTranslation *= keyboardSensibility_;
			if(::GetKeyState(VK_SHIFT) < 0){ cameraAddTranslation *= 0.1f; }
			Matrix33 rotationMatrix;
			rotationMatrix.setRotationXYZ(cameraRotation_);
			cameraAddTranslation = rotationMatrix * cameraAddTranslation;
			cameraPosition_ += cameraAddTranslation;
		}
		break;
	case WM_MOUSEWHEEL:
		{
			int wheelMove = (int)(((short)HIWORD(wParam)) / WHEEL_DELTA);
			fovY_ += wheelMove * -3.f;
			if(fovY_ > 179.f){ fovY_ = 179.f; }
			else if(fovY_ < 1.f){ fovY_ = 1.f; }
			break;
		}
	case WM_MOUSEMOVE:
		// マウス移動値取得
		u_int xPosition = LOWORD(lParam);
		u_int yPosition = HIWORD(lParam);
		int xPositionDistance = xPosition - mouseXPosition_;
		int yPositionDistance = yPosition - mouseYPosition_;
		if((xPositionDistance == 0) && (yPositionDistance == 0)){ break; }
		// カメラパラメータ変更値の算出
		bool shift = ((wParam & MK_SHIFT) != 0);
		if((wParam & MK_LBUTTON) != 0){
			float xDistance = xPositionDistance * cameraRotationSensibility_;
			float yDistance = yPositionDistance * cameraRotationSensibility_;
			cameraAddRotation.x += -yDistance;
			cameraAddRotation.y += -xDistance;
			cameraChanged = true;
		}else if((wParam & MK_RBUTTON) != 0){
			float xDistance = xPositionDistance * cameraPositionSensibility_;
			float yDistance = yPositionDistance * cameraPositionSensibility_;
			if(shift){
				cameraAddTranslation.x += xDistance;
				cameraAddTranslation.z += yDistance;
			}else{
				cameraAddTranslation.x += xDistance;
				cameraAddTranslation.y += -yDistance;
			}
			cameraChanged = true;
		}
		mouseXPosition_ = xPosition;
		mouseYPosition_ = yPosition;
		if(cameraChanged){
			// カメラパラメータの変更
			cameraRotation_ += cameraAddRotation;
			Matrix33 rotationMatrix;
			rotationMatrix.setRotationXYZ(cameraRotation_);
			cameraAddTranslation = rotationMatrix * cameraAddTranslation;
			cameraPosition_ += cameraAddTranslation;
		}
		break;
	}
	return 0;
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
