#include "BaseGL.h"
#include "Camera.h"

float degree = 3.14159265f / 180.0f;

Camera::Camera()
{
	cameramode = 4;
	cameramodecounter = 0;
	model = NULL;
	camdistance = 0;
	camheight = 0;
	camRotX = 0;
	camRotY = 0;
	CAMSTEP = 2;
}

Camera::~Camera()
{

}

void Camera::Init()
{
	m_pos[0] = 0;
	m_pos[1] = 1.7f;
	m_pos[2] = 0;
	m_pos[1] = 1;
	m_xz = 0;
	m_yz = 0;
	Set();
}

void Camera::Set()
{
	if (model != NULL) {
		SbVec3f modelFw = model->driver->GetForward();
		SbVec3f modelRight = model->driver->GetRight();
		SbVec3f modelPos = model->driver->GetPosition();
		SbVec3f cameraPos;
		SbVec3f distCamModel;
		SbVec3f tangent;
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		switch (cameramode) {
			// Shooter like mode
			case 0:
				glRotatef(-m_yz,1,0,0);
				glRotatef(-m_xz,0,1,0);
				glTranslatef(-m_pos[0],-m_pos[1],-m_pos[2]);
				break;
			// Behind View
			case 1:
				cameraPos = modelPos - modelFw*150 + modelFw*(float)camdistance;
				cameraPos[1] += 70 + camheight;
				gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2],
					modelPos[0], modelPos[1], modelPos[2], 0.0f, 1.0f, 0.0f);
				break;
			// View from right
			case 2:
				cameraPos = modelPos + modelRight*170 - modelRight*(float)camdistance;
				cameraPos[1] += 20 + camheight;
				gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2],
					modelPos[0], modelPos[1], modelPos[2], 0.0f, 1.0f, 0.0f);
				break;
			// View from front
			case 3:
				cameraPos = modelPos + modelFw*150 - modelFw*(float)camdistance;
				cameraPos[1] += 20 + camheight;
				gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2],
					modelPos[0], modelPos[1], modelPos[2], 0.0f, 1.0f, 0.0f);
				break;
				// View from behind, rotation in all directions
			case 4:
				cameraPos = modelPos - modelFw*150 + modelFw*(float)camdistance;
				cameraPos[1] += 70 + camheight;
				distCamModel = (modelPos - cameraPos);
				distCamModel[1] = 0;		// project to floor
				tangent = distCamModel.cross(*(new SbVec3f(0.0f, 1.0f, 0.0f)));	// tangent of circle at position of the camera, m=model, r=distCamModel,
				tangent.normalize();
				cameraPos += m_stsin * tangent * distCamModel.length();		// Rotate Camera
				cameraPos += -m_stcos * distCamModel + distCamModel;
				gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2],
					modelPos[0], modelPos[1], modelPos[2], 0.0f, 1.0f, 0.0f);
				break;
			default: ;
		}
	}
}

void Camera::MoveForward()
{
	switch (cameramode) {
		case 0:
			m_pos[0] -= m_stsin;
			m_pos[2] -= m_stcos;
			break;
		default:
			camdistance += CAMSTEP;
	}
}

void Camera::MoveBackward()
{
	switch (cameramode) {
		case 0:
			m_pos[0] += m_stsin;
			m_pos[2] += m_stcos;
		default:
			camdistance -= CAMSTEP;
	}
}

void Camera::MoveLeft()
{
	if (cameramode != 0) return;
	m_pos[0] -= m_stcos;
	m_pos[2] -= -m_stsin;
}

void Camera::MoveRight()
{
	if (cameramode != 0) return;
	m_pos[0] -= -m_stcos;
	m_pos[2] -= m_stsin;
}

void Camera::MoveUp()
{
	m_pos[1] += 0.5f;
}

void Camera::MoveDown()
{
	m_pos[1] -= 0.5f;
}

void Camera::TurnHorizontal(float spin)
{
	m_xz -= spin;
	m_stsin = (float)sin(m_xz*degree);
	m_stcos = (float)cos(m_xz*degree);
}

void Camera::TurnVertical(float spin)
{
	switch (cameramode) {
		case 0:
			m_yz = max(-90,m_yz)*degree;
			m_yz = min(90,m_yz)*degree;
			break;
		default:
			camheight += (int)(CAMSTEP*spin);
	}
}

void Camera::SetPos(float *p)
{
	m_pos[0] = p[0];
	m_pos[1] = p[1];
	m_pos[2] = p[2];
	m_pos[3] = p[3];
}

void Camera::NextCameraMode()
{
	if (cameramodecounter++ == 6) {
		cameramodecounter = 0;
		camdistance = 0;		// set to initial distance
		camheight = 0;
		m_xz = 0;
		m_stsin = 0;
		m_stcos = 0;
		if (cameramode++ == 4) {
			SbVec3f position = model->driver->GetPosition();
			cameramode = 0;
			m_pos[0] = position[0];	// when returning to shooter-view, set camera to model-center
			m_pos[2] = position[2];
		}
	}
}

void Camera::Follow(Tetobject* model)	// set the model to follow
{
	this->model = model;
}
