#include "rwtest.h"

using namespace std;

void
Camera::look(void)
{
	projMat = Mat4::perspective(fov, aspectRatio, n, f);
	viewMat = Mat4::lookat(position, target, up);

//	state->mat4(PMAT,true)->val = Mat4::perspective(fov, aspectRatio, n, f);
//	Mat4 mv = Mat4::lookat(position, target, up);
//	state->mat4(MVMAT, true)->val = mv;
//	state->mat3(NORMALMAT, true)->val = Mat3(mv);
}

void
Camera::setPosition(Vec3 q)
{
	position = q;
}

Vec3
Camera::getPosition(void)
{
	return position;
}

void
Camera::setTarget(Vec3 q)
{
	position -= target - q;
	target = q;
}

Vec3
Camera::getTarget(void)
{
	return target;
}

float
Camera::getHeading(void)
{
	Vec3 dir = target - position;
	float a = atan2(dir.y, dir.x)-PI/2.0f;
	return local_up.z < 0.0f ? a-PI : a;
}

void
Camera::turn(float yaw, float pitch)
{
	yaw /= 2.0f;
	pitch /= 2.0f;
	Quat dir = Quat(target - position);
	Quat r(cos(yaw), 0.0f, 0.0f, sin(yaw));
	dir = r*dir*r.K();
	local_up = Vec3(r*Quat(local_up)*r.K());

	Quat right = dir.wedge(Quat(local_up)).U();
	r = Quat(cos(pitch), right*sin(pitch));
	dir = r*dir*r.K();
	local_up = Vec3(right.wedge(dir).U());
	if(local_up.z >=0) up.z = 1;
	else up.z = -1;

	target = position + Vec3(dir);
}

void
Camera::orbit(float yaw, float pitch)
{
	yaw /= 2.0f;
	pitch /= 2.0f;
	Quat dir = Quat(target - position);
	Quat r(cos(yaw), 0.0f, 0.0f, sin(yaw));
	dir = r*dir*r.K();
	local_up = Vec3(r*Quat(local_up)*r.K());

	Quat right = dir.wedge(Quat(local_up)).U();
	r = Quat(cos(-pitch), right*sin(-pitch));
	dir = r*dir*r.K();
	local_up = Vec3(right.wedge(dir).U());
	if(local_up.z >=0) up.z = 1;
	else up.z = -1;

	position = target - Vec3(dir);
}

void
Camera::dolly(float dist)
{
	Vec3 dir = (target - position).normalized()*dist;
	position += dir;
	target += dir;
}

void
Camera::zoom(float dist)
{
	Vec3 dir = target - position;
	float curdist = dir.norm();
	if(dist >= curdist)
		dist = curdist-0.01f;
	dir = dir.normalized()*dist;
	position += dir;
}

void
Camera::pan(float x, float y)
{
	Vec3 dir = (target-position).normalized();
	Vec3 right = dir.cross(up).normalized();
//	Vec3 local_up = right.cross(dir).normalized();
	dir = right*x + local_up*y;
	position += dir;
	target += dir;

}

float
Camera::sqDistanceTo(Vec3 q)
{
	return (position - q).normsq();
}

float
Camera::distanceTo(Vec3 q)
{
	return (position - q).norm();
}

void
Camera::setFov(float f)
{
	fov = f;
}

float
Camera::getFov(void)
{
	return fov;
}

void
Camera::setAspectRatio(float r)
{
	aspectRatio = r;
}

void
Camera::setNearFar(float n, float f)
{
	this->n = n;
	this->f = f;
}

Camera::Camera()
{
	position = Vec3(0.0f, 6.0f, 0.0f);
	target = Vec3(0.0f, 0.0f, 0.0f);
	local_up = up = Vec3(0.0f, 0.0f, 1.0f);
	fov = 55.0f;
	aspectRatio = 1.0f;
	n = 0.1f;
	f = 100.0f;
}