//FILE IS FROM GAMETUTORIALS.COM 

//This is the only source file in this application that has not been created by Rouslan Dimitrov.

#include "camera.h"
#include "windowing.h"

float kSpeed = 0.25f;									

CCamera::CCamera()
{
	//OpenFile();

	color = vector3(1.0f, 1.0f, 1.0f);
	vector3 vZero = vector3(0.0, 15.0, 0.0);		// Init a vVector to 0 0 0 for our position
	vector3 vView = vector3(0.0, 15.0, -1.0);		// Init a starting view vVector (looking up and out the screen) 
	vector3 vUp   = vector3(0.0, 1.0, 0.0);		// Init a standard up vVector (Rarely ever changes)

	position	= vZero;					// Init the position to zero
	view		= vView;					// Init the view to a std starting view
	upVector	= vUp;						// Init the UpVector
}


void CCamera::PositionCamera(float positionX, float positionY, float positionZ,
				  		     float viewX,     float viewY,     float viewZ,
							 float upVectorX, float upVectorY, float upVectorZ)
{
	vector3 vPosition	= vector3(positionX, positionY, positionZ);
	vector3 vView		= vector3(viewX, viewY, viewZ);
	vector3 vUpVector	= vector3(upVectorX, upVectorY, upVectorZ);

	// The code above just makes it cleaner to set the variables.
	// Otherwise we would have to set each variable x y and z.

	position = vPosition;					// Assign the position
	view     = vView;						// Assign the view
	upVector = vUpVector;					// Assign the up vector
}



void CCamera::SetViewByMouse()
{
	POINT mousePos;	
	int middleX = rWindowing::width  >> 1;
	int middleY = rWindowing::height >> 1;
	float angleY = 0.0f;
	float angleZ = 0.0f;
	static float currentRotX = 0.0f;

	// Get the mouse's current X,Y position
	GetCursorPos(&mousePos);						

	static float mov;
	static float accum;
	accum = 0.8f*accum + 0.2f*mov;
	if(accum > 0.01f)
	{
		if(accum > 0.9f)
			accum = 0.9f;
		g_Renderer->enableMotionBlur(1.0f - accum, accum);
	}else
		g_Renderer->disableMotionBlur();


	// If our cursor is still in the middle, we never moved... so don't update the screen
	if( (mousePos.x == middleX) && (mousePos.y == middleY) )
	{
		mov = 0;
		return;
	}

	// Set the mouse position to the middle of our window
	SetCursorPos(middleX, middleY);							

	// Get the direction the mouse moved in, but bring the number down to a reasonable amount
	angleY = (float)( (middleX - mousePos.x) ) / 500.0f;		
	angleZ = (float)( (middleY - mousePos.y) ) / 500.0f;		


	mov = 10.0f*(abs(angleY) + abs(angleZ));

	// Here we keep track of the current rotation (for up and down) so that
	// we can restrict the camera from doing a full 360 loop.
	currentRotX -= angleZ;  

	// If the current rotation (in radians) is greater than 1.0, we want to cap it.
	if(currentRotX > 1.5f)
		currentRotX = 1.5f;
	// Check if the rotation is below -1.0, if so we want to make sure it doesn't continue
	else if(currentRotX < -1.5f)
		currentRotX = -1.5f;
	// Otherwise, we can rotate the view around our position
	else
	{
		// To find the axis we need to rotate around for up and down
		// movements, we need to get a perpendicular vector from the
		// camera's view vector and up vector.  This will be the axis.
		vector3 vAxis = Cross(view - position, upVector);
		vAxis = Normalize(vAxis);

		// Rotate around our perpendicular axis and along the y-axis
		RotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);
		RotateView(angleY, 0, 1, 0);
	}
}


void CCamera::RotateView(float angle, float x, float y, float z)
{
	vector3 vNewView;

	// Get the view vector (The direction we are facing)
	vector3 vView = view - position;		

	// Calculate the sine and cosine of the angle once
	float cosTheta = (float)cos(angle);
	float sinTheta = (float)sin(angle);

	// Find the new x position for the new rotated point
	vNewView.x  = (cosTheta + (1 - cosTheta) * x * x)		* vView.x;
	vNewView.x += ((1 - cosTheta) * x * y - z * sinTheta)	* vView.y;
	vNewView.x += ((1 - cosTheta) * x * z + y * sinTheta)	* vView.z;

	// Find the new y position for the new rotated point
	vNewView.y  = ((1 - cosTheta) * x * y + z * sinTheta)	* vView.x;
	vNewView.y += (cosTheta + (1 - cosTheta) * y * y)		* vView.y;
	vNewView.y += ((1 - cosTheta) * y * z - x * sinTheta)	* vView.z;

	// Find the new z position for the new rotated point
	vNewView.z  = ((1 - cosTheta) * x * z - y * sinTheta)	* vView.x;
	vNewView.z += ((1 - cosTheta) * y * z + x * sinTheta)	* vView.y;
	vNewView.z += (cosTheta + (1 - cosTheta) * z * z)		* vView.z;

	// Now we just add the newly rotated vector to our position to set
	// our new rotated view of our camera.
	view = position + vNewView;
}


void CCamera::MoveCamera(float speed)
{
	vector3 deltha;
	// Get the current view vector (the direction we are looking)
	deltha = view - position;
	
	deltha = Normalize(deltha)*speed;

	// Try to move in the deltha direction
	m_vWantedMove = m_vWantedMove + deltha;
}

///////////////////////////////// STRAFE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
/////	This strafes the camera left and right depending on the speed (-/+)
/////
///////////////////////////////// STRAFE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

void CCamera::StrafeCamera(float speed)
{	
	// Try to move in that direction
	m_vWantedMove = m_vWantedMove + m_vStrafe*speed;
}

///////////////////////////////// MOVE TO \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
/////	This will move the camera to the new location
/////
///////////////////////////////// MOVE TO \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
void CCamera::MoveTo( vector3 NewPosition )
{
	view = view + NewPosition-position;
	// That's the same like:
	//		deltha = NewPosition - Position
	//		View  += deltha

	position = NewPosition;
}

void CCamera::CheckForMovement()
{	
	m_vWantedMove.x = 0.0f;
	m_vWantedMove.y = 0.0f;
	m_vWantedMove.z = 0.0f;
	// Check if we hit the Up arrow or the 'w' key
	if(GetKeyState(VK_UP) & 0x80 || GetKeyState('W') & 0x80) {				

		// Move our camera forward by a positive SPEED
		MoveCamera(kSpeed);				
	}

	// Check if we hit the Down arrow or the 's' key
	if(GetKeyState(VK_DOWN) & 0x80 || GetKeyState('S') & 0x80) {			

		// Move our camera backward by a negative SPEED
		MoveCamera(-kSpeed);				
	}

	// Check if we hit the Left arrow or the 'a' key
	if(GetKeyState(VK_LEFT) & 0x80 || GetKeyState('A') & 0x80) {			

		// Strafe the camera left
		StrafeCamera(-kSpeed);
	}

	// Check if we hit the Right arrow or the 'd' key
	if(GetKeyState(VK_RIGHT) & 0x80 || GetKeyState('D') & 0x80) {			

		// Strafe the camera right
		StrafeCamera(kSpeed);
	}	

	//if(GetKeyState(VK_RETURN))
	//{
	//	DumpPath();
	//}

	position = position + m_vWantedMove;
	view = view + m_vWantedMove;

}

void CCamera::Update() 
{
	if(m_bInteractive) {
		// Initialize a variable for the cross product result
		vector3 vCross = Cross(view - position, upVector);

		// Normalize the strafe vector
		m_vStrafe = Normalize(vCross);

		// Move the camera's view by the mouse
		SetViewByMouse();

		// This checks to see if the keyboard was pressed
		CheckForMovement();
	}
}

void CCamera::Look()
{
	
	glColor3f(color.x,color.y,color.z);
	gluLookAt(position.x,position.y, position.z,	
			  view.x,	 view.y,     view.z,	
			  upVector.x, upVector.y, upVector.z);
}
