// This file is straight from Computer Graphics: Using OpenGL by F.S. Hill, Jr.
// The functions yaw and pitch were added but were only modified versions of the
// the function roll.  

#include "camera.h"
#include <iostream>

using namespace std;
//#include <GL/glut.h>


Vector3 Vector3::cross(Vector3 b) // return this cross b
{
	Vector3 c(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x);
	return c;
} // end of cross()

float Vector3::dot(Vector3 b) // return this dotted with b
{
	return x * b.x + y * b.y + z * b.z;
} // end of dot(...)

void Vector3::normalize() // adjust this vector to unit length
{
	double sizeSq = x * x + y * y + z * z;
	if(sizeSq < 0.0000001)
	{
		cerr << "\nnormalize() sees vector (0, 0, 0)!";
		return; // does nothing to zeor vectors
	}

	float scaleFactor = 1.0/(float)sqrt(sizeSq);
	x *= scaleFactor;
	y *= scaleFactor;
	z *= scaleFactor;

} // end of normalize()

Camera::Camera()
{

}

void Camera::setModelViewMatrix()
{ // load modelview matrix with existing camera values
	
	float m[16];
	Vector3 eVec(eye.x, eye.y, eye.z); // a vector version of eye
	m[0] = u.x; m[4] = u.y; m[8] = u.z; m[12] = -eVec.dot(u);
	m[1] = v.x; m[5] = v.y; m[9] = v.z; m[13] = -eVec.dot(v);
	m[2] = n.x; m[6] = n.y; m[10] = n.z; m[14] = -eVec.dot(n);
	m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1.0;
	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(m); // load OpenGL's modelview matrix
} // end of setModelViewMatrix()

void Camera::set(Point3 Eye, Point3 look, Vector3 up)
{
	eye.set(Eye); // store the given eye position
	//n.set(-eye.x + look.x, -eye.y + look.y, -eye.z + look.z); // make n
	
	n.set(eye.x - look.x, eye.y - look.y, eye.z - look.z); // make n
	u.set(up.cross(n)); // make u = up X n
	n.normalize(); u.normalize(); // make them unit length
	v.set(n.cross(u)); // make v = n X u
	//v.normalize();
	setModelViewMatrix(); // tell opengl

} // end of set(...)

void Camera::slide(float delU, float delV, float delN)
{
	eye.x += delU * u.x + delV * v.x + delN * n.x;
	eye.y += delU * u.y + delV * v.y + delN * n.y;
	eye.z += delU * u.z + delV * v.z + delN * n.z;
	setModelViewMatrix();

} // end of slide(...)

void Camera::roll(float angle)
{
	// roll the camera through angle degrees
	float cs = cos(3.14159265/180 * angle);
	float sn = sin(3.14159265/180 * angle);
	Vector3 t = u; // remember old u
	u.set(cs*t.x - sn*v.x, cs*t.y - sn*v.y, cs*t.z - sn*v.z);
	v.set(sn*t.x + cs*v.x, sn*t.y + cs*v.y, sn*t.z + cs*v.z);
	setModelViewMatrix();

}

void Camera::yaw(float angle)
{
	// yaw the camera through angle degrees
	float cs = cos(3.14159265/180 * angle);
	float sn = sin(3.14159265/180 * angle);
	Vector3 t = n; // remember old n
	n.set(cs*t.x - sn*u.x, cs*t.y - sn*u.y, cs*t.z - sn*u.z);
	u.set(sn*t.x + cs*u.x, sn*t.y + cs*u.y, sn*t.z + cs*u.z);
	setModelViewMatrix();

}

void Camera::pitch(float angle)
{
	// pitch the camera through angle degrees
	float cs = cos(3.14159265/180 * angle);
	float sn = sin(3.14159265/180 * angle);
	Vector3 t = n; // remember old n
	n.set(cs*t.x - sn*v.x, cs*t.y - sn*v.y, cs*t.z - sn*v.z);
	v.set(sn*t.x + cs*v.x, sn*t.y + cs*v.y, sn*t.z + cs*v.z);
	setModelViewMatrix();

}




