/* An example demonstrating how to use ALLEGRO_TRANSFORM to represent a 3D
* camera.
*/
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_color.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_image.h>
#include <stdio.h>
#include <math.h>


#define pi ALLEGRO_PI

typedef struct {
	float x, y, z;
} Vector;

typedef struct {
	Vector position;
	Vector xaxis; /* This represent the direction looking to the right. */
	Vector yaxis; /* This is the up direction. */
	Vector zaxis; /* This is the direction towards the viewer ('backwards'). */
	double vertical_field_of_view; /* In radians. */
} Camera;

typedef struct {
	Camera camera;

	/* controls sensitivity */
	double mouse_look_speed;
	double movement_speed;

	/* keyboard and mouse state */
	int button[10];
	int key[ALLEGRO_KEY_MAX];
	int keystate[ALLEGRO_KEY_MAX];
	int mouse_dx, mouse_dy;

	/* control scheme selection */
	int control_scheme;
	char const *controls_names[3];

	/* the vertex data */
	int n, v_size;
	ALLEGRO_VERTEX *v;

	/* used to draw some info text */
	ALLEGRO_FONT *font;

	/* Skybox maps */
	ALLEGRO_BITMAP *front;
	ALLEGRO_BITMAP *right;
	ALLEGRO_BITMAP *left;
	ALLEGRO_BITMAP *back;
	ALLEGRO_BITMAP *up;
	ALLEGRO_BITMAP *down;
	ALLEGRO_BITMAP *skybox;

} border;

border starfield;

/* Calculate the dot product between two vectors. This corresponds to the
* angle between them times their lengths.
*/
static double vector_dot_product(Vector a, Vector b)
{
	return a.x * b.x + a.y * b.y + a.z * b.z;
}

/* Calculate the cross product of two vectors. This produces a normal to the
* plane containing the operands.
*/
static Vector vector_cross_product(Vector a, Vector b)
{
	Vector v = { a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x };
	return v;
}

/* Return a vector multiplied by a scalar. */
static Vector vector_mul(Vector a, float s)
{
	Vector v = { a.x * s, a.y * s, a.z * s };
	return v;
}

/* Return the vector norm (length). */
static double vector_norm(Vector a)
{
	return sqrt(vector_dot_product(a, a));
}

/* Return a normalized version of the given vector. */
static Vector vector_normalize(Vector a)
{
	double s = vector_norm(a);
	if (s == 0)
		return a;
	return vector_mul(a, 1 / s);
}

/* In-place add another vector to a vector. */
static void vector_iadd(Vector *a, Vector b)
{
	a->x += b.x;
	a->y += b.y;
	a->z += b.z;
}

/* Rotate the camera around the given axis. */
static void camera_rotate_around_axis(Camera *c, Vector axis, double radians)
{
	ALLEGRO_TRANSFORM t;
	al_identity_transform(&t);
	al_rotate_transform_3d(&t, axis.x, axis.y, axis.z, radians);
	al_transform_coordinates_3d(&t, &c->yaxis.x, &c->yaxis.y, &c->yaxis.z);
	al_transform_coordinates_3d(&t, &c->zaxis.x, &c->zaxis.y, &c->zaxis.z);

	/* Make sure the axes remain orthogonal to each other. */
	c->zaxis = vector_normalize(c->zaxis);
	c->xaxis = vector_cross_product(c->yaxis, c->zaxis);
	c->xaxis = vector_normalize(c->xaxis);
	c->yaxis = vector_cross_product(c->zaxis, c->xaxis);
}

/* Move the camera along its x axis and z axis (which corresponds to
* right and backwards directions).
*/
static void camera_move_along_direction(Camera *camera, double right,
	double forward)
{
	vector_iadd(&camera->position, vector_mul(camera->xaxis, right));
	vector_iadd(&camera->position, vector_mul(camera->zaxis, -forward));
}

/* Get a vector with y = 0 looking in the opposite direction as the camera z
* axis. If looking straight up or down returns a 0 vector instead.
*/
static Vector get_ground_forward_vector(Camera *camera)
{
	Vector move = vector_mul(camera->zaxis, -1);
	move.y = 0;
	return vector_normalize(move);
}

/* Get a vector with y = 0 looking in the same direction as the camera x axis.
* If looking straight up or down returns a 0 vector instead.
*/
static Vector get_ground_right_vector(Camera *camera)
{
	Vector move = camera->xaxis;
	move.y = 0;
	return vector_normalize(move);
}

/* Like camera_move_along_direction but moves the camera along the ground plane
* only.
*/
static void camera_move_along_ground(Camera *camera, double right,
	double forward)
{
	Vector f = get_ground_forward_vector(camera);
	Vector r = get_ground_right_vector(camera);
	camera->position.x += f.x * forward + r.x * right;
	camera->position.z += f.z * forward + r.z * right;
}

/* Calculate the pitch of the camera. This is the angle between the z axis
* vector and our direction vector on the y = 0 plane.
*/
static double get_pitch(Camera *c)
{
	Vector f = get_ground_forward_vector(c);
	return asin(vector_dot_product(f, c->yaxis));
}

/* Calculate the yaw of the camera. This is basically the compass direction.
*/
static double get_yaw(Camera *c)
{
	return atan2(c->zaxis.x, c->zaxis.z);
}

/* Calculate the roll of the camera. This is the angle between the x axis
* vector and its project on the y = 0 plane.
*/
static double get_roll(Camera *c)
{
	Vector r = get_ground_right_vector(c);
	return asin(vector_dot_product(r, c->yaxis));
}

/* Set up a perspective transform. We make the screen span
* 2 vertical units (-1 to +1) with square pixel aspect and the camera's
* vertical field of view. Clip distance is always set to 1.
*/
static void setup_3d_projection(void)
{
	ALLEGRO_TRANSFORM projection;
	ALLEGRO_DISPLAY *display = al_get_current_display();
	double dw = al_get_display_width(display);
	double dh = al_get_display_height(display);
	double f;
	al_identity_transform(&projection);
	al_translate_transform_3d(&projection, 0, 0, -1);
	f = tan(starfield.camera.vertical_field_of_view / 2);
	al_perspective_transform(&projection, -1 * dw / dh * f, f,
		1,
		f * dw / dh, -f, 1000);
	al_use_projection_transform(&projection);
}

/* Adds a new vertex to our scene. */
static void add_vertex(double x, double y, double z, double u, double v,
	ALLEGRO_COLOR color)
{
	int i = starfield.n++;
	if (i >= starfield.v_size) {
		starfield.v_size += 1;
		starfield.v_size *= 2;
		starfield.v = realloc(starfield.v, starfield.v_size * sizeof *starfield.v);
	}
	starfield.v[i].x = x;
	starfield.v[i].y = y;
	starfield.v[i].z = z;
	starfield.v[i].u = u;
	starfield.v[i].v = v;
	starfield.v[i].color = color;
}

/* Adds two triangles (6 vertices) to the scene. */
static void add_quad(double x, double y, double z, double u, double v,
	double ux, double uy, double uz, double uu, double uv,
	double vx, double vy, double vz, double vu, double vv,
	ALLEGRO_COLOR c1, ALLEGRO_COLOR c2)
{
	add_vertex(x, y, z, u, v, c1);
	add_vertex(x + ux, y + uy, z + uz, u + uu, v + uv, c1);
	add_vertex(x + vx, y + vy, z + vz, u + vu, v + vv, c2);
	add_vertex(x + vx, y + vy, z + vz, u + vu, v + vv, c2);
	add_vertex(x + ux, y + uy, z + uz, u + uu, v + uv, c1);
	add_vertex(x + ux + vx, y + uy + vy, z + uz + vz, u + uu + vu,
		v + uv + vv, c2);
}


/* Create a skybox. This is simply 5 quads with a fixed distance to the
* camera.
*/
static void add_skybox(void)
{
	Vector pos = starfield.camera.position;
	ALLEGRO_COLOR color1 = al_color_name("black");
	ALLEGRO_COLOR color2 = al_color_name("blue");
	ALLEGRO_COLOR color3 = al_color_name("white");

	double tex_size = 0;
	if (starfield.front) {
		tex_size = al_get_bitmap_width(starfield.front);
		color1 = color2 = color3;
	}

	/* Front skybox wall. */
	add_quad(-50, -50, -50, tex_size, 0,
		100, 0, 0, -tex_size, 0,
		0, 100, 0, 0, -tex_size,
		color1, color2);
	

	/* Right skybox wall. */
	add_quad(50, -50, -50, tex_size, 0,
		0, 0, 100, -tex_size, 0,
		0, 100, 0, 0, -tex_size,
		color1, color2);

	/* Back skybox wall. */
	add_quad(-50, -50, 50, 0, tex_size,
		100, 0, 0, tex_size, 0,
		0, 100, 0, 0, -tex_size,
		color1, color2);

	/* Left skybox wall. */
	add_quad(-50, -50, -50, 0, tex_size,
		0, 0, 100, tex_size, 0,
		0, 100, 0, 0, -tex_size,
		color1, color2);

	/* Top skybox wall. */
	add_vertex(-50, 50, -50, 0, 0, color2);
	add_vertex(50, 50, -50, -tex_size, 0, color2);
	add_vertex(50, 50, 50, -tex_size, -tex_size, color2);

	add_vertex(50, 50, 50, -tex_size, -tex_size, color2);
	add_vertex(-50, 50, 50, 0, -tex_size, color2);
	add_vertex(-50, 50, -50, 0, 0, color2);


	/* Bottom skybox wall. */

	add_vertex(-50, -50, 50, 0, 0, color2);
	add_vertex(50, -50, 50, -tex_size, -0, color2);
	add_vertex(50, -50, -50, -tex_size, -tex_size, color2);

	add_vertex(50, -50, -50, -tex_size, -tex_size, color2);
	add_vertex(-50, -50, -50, 0, -tex_size, color2);
	add_vertex(-50, -50, 50, 0, 0, color2);


}

static void draw_scene(void)
{
	Camera *c = &starfield.camera;
	/* We save Allegro's projection so we can restore it for drawing text. */
	ALLEGRO_TRANSFORM projection = *al_get_current_projection_transform();
	ALLEGRO_TRANSFORM t;
	ALLEGRO_COLOR back = al_color_name("black");
	ALLEGRO_COLOR front = al_color_name("white");
	int th;
	double pitch, yaw, roll;

	setup_3d_projection();
	al_clear_to_color(back);

	/* We use a depth buffer. */
	al_set_render_state(ALLEGRO_DEPTH_TEST, 1);
	al_clear_depth_buffer(1);

	/* Recreate the entire scene geometry - this is only a very small example
	* so this is fine.
	*/
	starfield.n = 0;

	add_skybox();

	/* Construct a transform corresponding to our camera. This is an inverse
	* translation by the camera position, followed by an inverse rotation
	* from the camera orientation.
	*/
	al_build_camera_transform(&t,
		starfield.camera.position.x, starfield.camera.position.y, starfield.camera.position.z,
		starfield.camera.position.x - starfield.camera.zaxis.x,
		starfield.camera.position.y - starfield.camera.zaxis.y,
		starfield.camera.position.z - starfield.camera.zaxis.z,
		starfield.camera.yaxis.x, starfield.camera.yaxis.y, starfield.camera.yaxis.z);
	al_use_transform(&t);

	al_draw_prim(starfield.v, NULL, starfield.front, 0, 3, ALLEGRO_PRIM_TRIANGLE_LIST);  //front
    al_draw_prim(starfield.v, NULL, starfield.front, 3, 6, ALLEGRO_PRIM_TRIANGLE_LIST);  //front
	al_draw_prim(starfield.v, NULL, starfield.right, 6, 9, ALLEGRO_PRIM_TRIANGLE_LIST);  //right
	al_draw_prim(starfield.v, NULL, starfield.right, 9, 12, ALLEGRO_PRIM_TRIANGLE_LIST);  //right
	al_draw_prim(starfield.v, NULL, starfield.back, 12, 15, ALLEGRO_PRIM_TRIANGLE_LIST);  //back
	al_draw_prim(starfield.v, NULL, starfield.back, 15, 18, ALLEGRO_PRIM_TRIANGLE_LIST);  //back
	al_draw_prim(starfield.v, NULL, starfield.left, 18, 21, ALLEGRO_PRIM_TRIANGLE_LIST);  //left
	al_draw_prim(starfield.v, NULL, starfield.left, 21, 24, ALLEGRO_PRIM_TRIANGLE_LIST);  //left
	al_draw_prim(starfield.v, NULL, starfield.up, 24, 27, ALLEGRO_PRIM_TRIANGLE_LIST);  //up
	al_draw_prim(starfield.v, NULL, starfield.up, 27, 30, ALLEGRO_PRIM_TRIANGLE_LIST);  //up
	al_draw_prim(starfield.v, NULL, starfield.down, 30, 33, ALLEGRO_PRIM_TRIANGLE_LIST);  //down
	al_draw_prim(starfield.v, NULL, starfield.down, 33, 36, ALLEGRO_PRIM_TRIANGLE_LIST);  //down

	//al_draw_prim(starfield.v, NULL, starfield.skybox, 0, 3, ALLEGRO_PRIM_TRIANGLE_LIST);  //front
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 3, 6, ALLEGRO_PRIM_TRIANGLE_LIST);  //front
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 6, 9, ALLEGRO_PRIM_TRIANGLE_LIST);  //right
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 9, 12, ALLEGRO_PRIM_TRIANGLE_LIST);  //right
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 12, 15, ALLEGRO_PRIM_TRIANGLE_LIST);  //back
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 15, 18, ALLEGRO_PRIM_TRIANGLE_LIST);  //back
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 18, 21, ALLEGRO_PRIM_TRIANGLE_LIST);  //left
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 21, 24, ALLEGRO_PRIM_TRIANGLE_LIST);  //left
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 24, 27, ALLEGRO_PRIM_TRIANGLE_LIST);  //up
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 27, 30, ALLEGRO_PRIM_TRIANGLE_LIST);  //up
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 30, 33, ALLEGRO_PRIM_TRIANGLE_LIST);  //down
	//al_draw_prim(starfield.v, NULL, starfield.skybox, 33, 36, ALLEGRO_PRIM_TRIANGLE_LIST);  //down



	/* Restore projection. */
	al_identity_transform(&t);
	al_use_transform(&t);
	al_use_projection_transform(&projection);
	al_set_render_state(ALLEGRO_DEPTH_TEST, 0);

	/* Draw some text. */
	th = al_get_font_line_height(starfield.font);
	al_draw_textf(starfield.font, front, 0, th * 0, 0,
		"look: %+3.1f/%+3.1f/%+3.1f (change with left mouse button and drag)",
		-c->zaxis.x, -c->zaxis.y, -c->zaxis.z);
	pitch = get_pitch(c) * 180 / pi;
	yaw = get_yaw(c) * 180 / pi;
	roll = get_roll(c) * 180 / pi;
	al_draw_textf(starfield.font, front, 0, th * 1, 0,
		"pitch: %+4.0f yaw: %+4.0f roll: %+4.0f", pitch, yaw, roll);
	al_draw_textf(starfield.font, front, 0, th * 2, 0,
		"vertical field of view: %3.1f (change with Z/X)",
		c->vertical_field_of_view * 180 / pi);
	al_draw_textf(starfield.font, front, 0, th * 3, 0, "move with WASD or cursor");
	al_draw_textf(starfield.font, front, 0, th * 4, 0, "control style: %s (space to change)",
		starfield.controls_names[starfield.control_scheme]);
}

static void setup_scene(void)
{
	starfield.camera.xaxis.x = 1;
	starfield.camera.yaxis.y = 1;
	starfield.camera.zaxis.z = 1;
	starfield.camera.position.y = 2;
	starfield.camera.vertical_field_of_view = 60 * pi / 180;

	starfield.mouse_look_speed = 0.03;
	starfield.movement_speed = 0.1;

	starfield.controls_names[0] = "FPS";
	starfield.controls_names[1] = "airplane";
	starfield.controls_names[2] = "spaceship";
	starfield.control_scheme = 0;


	starfield.font = al_create_builtin_font();
}

static void handle_input(void)
{
	double x = 0, y = 0;
	double xy;
	if (starfield.key[ALLEGRO_KEY_A] || starfield.key[ALLEGRO_KEY_LEFT]) x = -1;
	if (starfield.key[ALLEGRO_KEY_S] || starfield.key[ALLEGRO_KEY_DOWN]) y = -1;
	if (starfield.key[ALLEGRO_KEY_D] || starfield.key[ALLEGRO_KEY_RIGHT]) x = 1;
	if (starfield.key[ALLEGRO_KEY_W] || starfield.key[ALLEGRO_KEY_UP]) y = 1;

	///* Change field of view with Z/X. */
	if (starfield.key[ALLEGRO_KEY_Z]) {
		double m = 20 * pi / 180;
		starfield.camera.vertical_field_of_view -= 0.01;
		if (starfield.camera.vertical_field_of_view < m)
			starfield.camera.vertical_field_of_view = m;
	}
	if (starfield.key[ALLEGRO_KEY_X]) {
		double m = 120 * pi / 180;
		starfield.camera.vertical_field_of_view += 0.01;
		if (starfield.camera.vertical_field_of_view > m)
			starfield.camera.vertical_field_of_view = m;
	}

	/* In FPS style, always move the camera to height 2. */
	if (starfield.control_scheme == 0) {
		if (starfield.camera.position.y > 2)
			starfield.camera.position.y -= 0.1;
		if (starfield.camera.position.y < 2)
			starfield.camera.position.y = 2;
	}

	/* Set the roll (leaning) angle to 0 if not in airplane style. */
	if (starfield.control_scheme == 0 || starfield.control_scheme == 2) {
		double roll = get_roll(&starfield.camera);
		//roll = .01;
		camera_rotate_around_axis(&starfield.camera, starfield.camera.zaxis, roll / 60);
	}

	/* Move the camera, either freely or along the ground. */
	xy = sqrt(x * x + y * y);
	if (xy > 0) {
		x /= xy;
		y /= xy;
		if (starfield.control_scheme == 0) {
			camera_move_along_ground(&starfield.camera, starfield.movement_speed * x,
				starfield.movement_speed * y);
		}
		if (starfield.control_scheme == 1 || starfield.control_scheme == 2) {
			camera_move_along_direction(&starfield.camera, starfield.movement_speed * x,
				starfield.movement_speed * y);
		}
	}


	//camera_rotate_around_axis(&starfield.camera, starfield.camera.xaxis, .0001);
	//camera_rotate_around_axis(&starfield.camera, starfield.camera.yaxis, .0001);
	//camera_rotate_around_axis(&starfield.camera, starfield.camera.zaxis, .0001);

	/* Rotate the camera, either freely or around world up only. */
	if (starfield.button[1]) {
		if (starfield.control_scheme == 0 || starfield.control_scheme == 2) {
			Vector up = { 0, 1, 0 };
			camera_rotate_around_axis(&starfield.camera, starfield.camera.xaxis,
				-starfield.mouse_look_speed * starfield.mouse_dy);
			camera_rotate_around_axis(&starfield.camera, up,
				-starfield.mouse_look_speed * starfield.mouse_dx);
		}
		if (starfield.control_scheme == 1) {
			camera_rotate_around_axis(&starfield.camera, starfield.camera.xaxis,
				-starfield.mouse_look_speed * starfield.mouse_dy);
			camera_rotate_around_axis(&starfield.camera, starfield.camera.zaxis,
				-starfield.mouse_look_speed * starfield.mouse_dx);
		}
	}
}

int main(int argc, char **argv)
{
	ALLEGRO_DISPLAY *display;
	ALLEGRO_TIMER *timer;
	ALLEGRO_EVENT_QUEUE *queue;
	int redraw = 0;

	if (!al_init()) {
		printf("Could not init Allegro.\n");
		exit(1);
	}
	al_init_font_addon();
	al_init_primitives_addon();
	al_install_keyboard();
	al_install_mouse();

	al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST);
	al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST);
	al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 16, ALLEGRO_SUGGEST);
	al_set_new_display_flags(ALLEGRO_RESIZABLE);
	display = al_create_display(1280,800);
	if (!display) {
		printf("Error creating display\n");
		exit(1);
	}

		al_init_image_addon();
		starfield.front = al_load_bitmap("border_front.png");
		if (starfield.front) {
			printf("Loaded skybox front: %d x %d\n", 
				al_get_bitmap_width(starfield.front),
				al_get_bitmap_height(starfield.front));
		}
		else {
			printf("Failed loading front skybox\n");
		}

		starfield.right = al_load_bitmap("border_right.png");
		if (starfield.right) {
			printf("Loaded skybox right: %d x %d\n",
				al_get_bitmap_width(starfield.right),
				al_get_bitmap_height(starfield.right));
		}
		else {
			printf("Failed loading right skybox\n");
		}

		starfield.back = al_load_bitmap("border_back.png");
		if (starfield.back) {
			printf("Loaded skybox back: %d x %d\n",
				al_get_bitmap_width(starfield.back),
				al_get_bitmap_height(starfield.back));
		}
		else {
			printf("Failed loading back skybox\n");
		}

		starfield.left = al_load_bitmap("border_left.png");
		if (starfield.left) {
			printf("Loaded skybox left: %d x %d\n",
				al_get_bitmap_width(starfield.left),
				al_get_bitmap_height(starfield.left));
		}
		else {
			printf("Failed loading left skybox\n");
		}

		starfield.up = al_load_bitmap("border_up.png");
		if (starfield.up) {
			printf("Loaded skybox up: %d x %d\n",
				al_get_bitmap_width(starfield.up),
				al_get_bitmap_height(starfield.up));
		}
		else {
			printf("Failed loading up skybox\n");
		}

		starfield.down = al_load_bitmap("border_down.png");
		if (starfield.down) {
			printf("Loaded skybox down: %d x %d\n",
				al_get_bitmap_width(starfield.down),
				al_get_bitmap_height(starfield.down));
		}
		else {
			printf("Failed loading down skybox\n");
		}

		starfield.skybox = al_load_bitmap("border_skybox.png");
		if (starfield.skybox) {
			printf("Loaded test skybox: %d x %d\n",
				al_get_bitmap_width(starfield.skybox),
				al_get_bitmap_height(starfield.skybox));
		}
		else {
			printf("Failed loading test skybox\n");
		}



	timer = al_create_timer(1.0 / 60);

	queue = al_create_event_queue();
	al_register_event_source(queue, al_get_keyboard_event_source());
	al_register_event_source(queue, al_get_mouse_event_source());
	al_register_event_source(queue, al_get_display_event_source(display));
	al_register_event_source(queue, al_get_timer_event_source(timer));

	setup_scene();

	al_start_timer(timer);
	while (true) {
		ALLEGRO_EVENT event;

		al_wait_for_event(queue, &event);
		if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
			break;
		else if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) {
			al_acknowledge_resize(display);
		}
		else if (event.type == ALLEGRO_EVENT_KEY_DOWN) {
			if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
				break;
			if (event.keyboard.keycode == ALLEGRO_KEY_SPACE) {
				starfield.control_scheme++;
				starfield.control_scheme %= 3;
			}
			starfield.key[event.keyboard.keycode] = 1;
			starfield.keystate[event.keyboard.keycode] = 1;
		}
		else if (event.type == ALLEGRO_EVENT_KEY_UP) {
			/* In case a key gets pressed and immediately released, we will still
			* have set starfield.key so it is not lost.
			*/
			starfield.keystate[event.keyboard.keycode] = 0;
		}
		else if (event.type == ALLEGRO_EVENT_TIMER) {
			int i;
			handle_input();
			redraw = 1;

			/* Reset keyboard state for keys not held down anymore. */
			for (i = 0; i < ALLEGRO_KEY_MAX; i++) {
				if (starfield.keystate[i] == 0)
					starfield.key[i] = 0;
			}
			starfield.mouse_dx = 0;
			starfield.mouse_dy = 0;
		}
		else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
			starfield.button[event.mouse.button] = 1;
		}
		else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
			starfield.button[event.mouse.button] = 0;
		}
		else if (event.type == ALLEGRO_EVENT_MOUSE_AXES) {
			starfield.mouse_dx += event.mouse.dx;
			starfield.mouse_dy += event.mouse.dy;
		}

		if (redraw  && al_is_event_queue_empty(queue)) {
			draw_scene();

			al_flip_display();
			redraw = 0;
		}
	}

	return 0;
}
