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


void r_camera_base_look_at(r_camera_base *c, v3 target)
{
	c->direction = normalize(target - c->position);
}

m4 r_camera_base_view(r_camera_base *c)
{
	return r_view_matrix(c->position, c->direction, c->up);
}


void r_camera_fps_look_at(r_camera_fps *c, v3 target)
{
	v3 direction = normalize(target - c->position);
	c->pitch = degrees(asin(direction.z));
	direction = normalize(v3{direction.x, direction.y, 0});
	c->yaw = degrees(asin(direction.y));
	if(direction.x < 0)
		c->yaw = 180 - c->yaw;
}

m4 r_camera_fps_view(r_camera_fps *c)
{
	v3 up;
	v3 direction;

	up = r_camera_up_vector;
	direction = r_camera_fps_direction(c);

	return r_view_matrix(c->position, direction, up);
}

v3 r_camera_fps_direction(r_camera_fps *c)
{
	v3 direction;
	direction.x = cos(radians(c->yaw)) * cos(radians(c->pitch));
	direction.y = sin(radians(c->yaw)) * cos(radians(c->pitch));
	direction.z = sin(radians(c->pitch));
	return direction;
}


m4 r_view_matrix(v3 position, v3 direction, v3 up)
{
	v3 right     = normalize(cross(up, -direction));
	v3 camera_up = normalize(cross(-direction, right));

	m4 result = m4_identity;

	// new X axis
	result.E[0][0] = right.x;
	result.E[0][1] = right.y;
	result.E[0][2] = right.z;

	// new Y axis
	result.E[1][0] = camera_up.x;
	result.E[1][1] = camera_up.y;
	result.E[1][2] = camera_up.z;

	// new Z axis
	result.E[2][0] = -direction.x;
	result.E[2][1] = -direction.y;
	result.E[2][2] = -direction.z;

	// translation
	result.E[0][3] = -dot(right    , position);
	result.E[1][3] = -dot(camera_up, position);
	result.E[2][3] = -dot(-direction, position);

	return result;
}

m4 r_perspective_matrix(f32 fov, f32 aspect_ratio, f32 near_plane, f32 far_plane)
{
	m4 result = m4_zero;

	f32 tanf2 = tan(radians(fov) / 2.0);

	result.E[0][0] = 1.0 / (aspect_ratio * tanf2);
	result.E[1][1] = 1.0 / tanf2;
	result.E[2][2] = - (far_plane + near_plane) / (far_plane - near_plane);

	result.E[2][3] = -2.0 * far_plane * near_plane / (far_plane - near_plane);
	result.E[3][2] = -1.0;

	return result;
}

m4 r_orthographic_matrix(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far)
{
	m4 result = m4_zero;

	result.E[0][0] =  2 / (right - left);
	result.E[1][1] =  2 / (top - bottom);
	result.E[2][2] = -2 / (far - near);
	result.E[3][3] =  1;

	result.E[0][3] = - (right + left) / (right - left);
	result.E[1][3] = - (top + bottom) / (top - bottom);
	result.E[2][3] = - (far + near) / (far - near);

	return result;
}
