

#include <allegro_flare/camera.h>




projected_point_data::projected_point_data(float x, float y, float scale)
	: x(x), y(y), scale(scale)
{}





Camera::Camera(float x, float y, float width, float height) : x(x), y(y), w(width), h(height), align_x(0.5), align_y(0.5), scale_x(1), scale_y(1), rotation(0),
	overlay_opacity(0), overlay_color(al_map_rgb(0,0,0)), depth(512), home_z(512), z(512)
{
	//depth = 128;  // the bigger this number, the less apparent the depth effect
	//depth = 512;  // 512 is an accurate balance to where moving right 100px feels
		            // proportionally the same distance as moving forward 100px
}


void Camera::start_transform()
{
	al_store_state(&previous_state, ALLEGRO_STATE_TRANSFORM);

	/*
	al_build_transform(&transform, -x + w*align_x, -y + h*align_y, scale_x, scale_y, rotation);
	al_use_transform(&transform);
	*/

	//al_identity_transform(&transform);
	al_copy_transform(&transform, al_get_current_transform());

	al_translate_transform(&transform, -x, -y);
	al_scale_transform(&transform, scale_x, scale_y);
	al_rotate_transform(&transform, rotation);
	al_translate_transform(&transform, w*align_x, h*align_y);

	al_use_transform(&transform);
}


void Camera::restore_transform()
{
	al_restore_state(&previous_state);
}


void Camera::target(float x, float y)
{
	this->x = x;
	this->y = y;
}


void Camera::translate_screen_to_world(vec2d *vec)
{
	translate_screen_to_world(&vec->x, &vec->y);
}


void Camera::translate_screen_to_world(float *x, float *y)
{
	ALLEGRO_TRANSFORM trans;

	al_identity_transform(&trans);
	al_translate_transform(&trans, -this->x, -this->y);
	al_scale_transform(&trans, scale_x, scale_y);
	al_rotate_transform(&trans, rotation);
	al_translate_transform(&trans, w*align_x, h*align_y);

	al_invert_transform(&trans);

	al_transform_coordinates(&trans, x, y);
}


void Camera::translate_world_to_screen(vec2d *vec)
	// has not been tested
{
	this->start_transform();
	al_transform_coordinates(&this->transform, &vec->x, &vec->y);
	this->restore_transform();
}



float Camera::get_scale(float world_z)
{
	float distance_from_camera = z - world_z;
	if (distance_from_camera <= 0) return 0;
	if (depth <= 0) return 0;

	return depth / distance_from_camera;
}


projected_point_data Camera::get_projected_point(float world_x, float world_y, float world_z)
{
	float scale = get_scale(z);
	return projected_point_data((x-this->x)*scale, (y-this->y)*scale, scale);
}