void keyboard(unsigned char key)
{
	if(key == 'r')
		options.session->reset(session_buffer_params(), options.session_params.samples);
	else if(key == 27) // escape
		options.session->progress.set_cancel("Cancelled");
}
static void motion(int x, int y, int button)
{
	if(options.interactive) {
		Transform matrix = options.session->scene->camera->matrix;

		/* Translate */
		if(button == 0) {
			float3 translate = make_float3(x * 0.01f, -(y * 0.01f), 0.0f);
			matrix = matrix * transform_translate(translate);
		}

		/* Rotate */
		else if(button == 2) {
			float4 r1 = make_float4((float)x * 0.1f, 0.0f, 1.0f, 0.0f);
			matrix = matrix * transform_rotate(DEG2RADF(r1.x), make_float3(r1.y, r1.z, r1.w));

			float4 r2 = make_float4(y * 0.1f, 1.0f, 0.0f, 0.0f);
			matrix = matrix * transform_rotate(DEG2RADF(r2.x), make_float3(r2.y, r2.z, r2.w));
		}

		/* Update and Reset */
		options.session->scene->camera->matrix = matrix;
		options.session->scene->camera->need_update = true;
		options.session->scene->camera->need_device_update = true;

		options.session->reset(session_buffer_params(), options.session_params.samples);
	}
}
static void keyboard(unsigned char key)
{
	/* Toggle help */
	if(key == 'h')
		options.show_help = !(options.show_help);

	/* Reset */
	else if(key == 'r')
		options.session->reset(session_buffer_params(), options.session_params.samples);

	/* Cancel */
	else if(key == 27) // escape
		options.session->progress.set_cancel("Canceled");

	/* Pause */
	else if(key == 'p') {
		options.pause = !options.pause;
		options.session->set_pause(options.pause);
	}

	/* Interactive Mode */
	else if(key == 'i')
		options.interactive = !(options.interactive);

	else if(options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) {
		Transform matrix = options.session->scene->camera->matrix;
		float3 translate;

		if(key == 'w')
			translate = make_float3(0.0f, 0.0f, 0.1f);
		else if(key == 's')
			translate = make_float3(0.0f, 0.0f, -0.1f);
		else if(key == 'a')
			translate = make_float3(-0.1f, 0.0f, 0.0f);
		else if(key == 'd')
			translate = make_float3(0.1f, 0.0f, 0.0f);

		matrix = matrix * transform_translate(translate);

		/* Update and Reset */
		options.session->scene->camera->matrix = matrix;
		options.session->scene->camera->need_update = true;
		options.session->scene->camera->need_device_update = true;

		options.session->reset(session_buffer_params(), options.session_params.samples);
	}
}
static void display()
{
	static DeviceDrawParams draw_params = DeviceDrawParams();

	options.session->draw(session_buffer_params(), draw_params);

	display_info(options.session->progress);
}
static void resize(int width, int height)
{
	options.width = width;
	options.height = height;

	if(options.session)
		options.session->reset(session_buffer_params(), options.session_params.samples);
}
static void session_init()
{
	options.session = new Session(options.session_params);
	options.session->reset(session_buffer_params(), options.session_params.samples);
	options.session->scene = options.scene;
	
	if(options.session_params.background && !options.quiet)
		options.session->progress.set_update_callback(function_bind(&session_print_status));
	else
		options.session->progress.set_update_callback(function_bind(&view_redraw));

	options.session->start();

	options.scene = NULL;
}
static void resize(int width, int height)
{
	options.width = width;
	options.height = height;

	if(options.session) {
		/* Update camera */
		options.session->scene->camera->width = width;
		options.session->scene->camera->height = height;
		options.session->scene->camera->compute_auto_viewplane();
		options.session->scene->camera->need_update = true;
		options.session->scene->camera->need_device_update = true;

		options.session->reset(session_buffer_params(), options.session_params.samples);
	}
}
static void keyboard(unsigned char key)
{
	/* Toggle help */
	if(key == 'h')
		options.show_help = !(options.show_help);

	/* Reset */
	else if(key == 'r')
		options.session->reset(session_buffer_params(), options.session_params.samples);

	/* Cancel */
	else if(key == 27) // escape
		options.session->progress.set_cancel("Canceled");

	/* Pause */
	else if(key == 'p') {
		options.pause = !options.pause;
		options.session->set_pause(options.pause);
	}

	/* Interactive Mode */
	else if(key == 'i')
		options.interactive = !(options.interactive);

	/* Navigation */
	else if(options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) {
		Transform matrix = options.session->scene->camera->matrix;
		float3 translate;

		if(key == 'w')
			translate = make_float3(0.0f, 0.0f, 0.1f);
		else if(key == 's')
			translate = make_float3(0.0f, 0.0f, -0.1f);
		else if(key == 'a')
			translate = make_float3(-0.1f, 0.0f, 0.0f);
		else if(key == 'd')
			translate = make_float3(0.1f, 0.0f, 0.0f);

		matrix = matrix * transform_translate(translate);

		/* Update and Reset */
		options.session->scene->camera->matrix = matrix;
		options.session->scene->camera->need_update = true;
		options.session->scene->camera->need_device_update = true;

		options.session->reset(session_buffer_params(), options.session_params.samples);
	}

	/* Set Max Bounces */
	else if(options.interactive && (key == '0' || key == '1' || key == '2' || key == '3')) {
		int bounce;
		switch(key) {
			case '0': bounce = 0; break;
			case '1': bounce = 1; break;
			case '2': bounce = 2; break;
			case '3': bounce = 3; break;
			default: bounce = 0; break;
		}

		options.session->scene->integrator->max_bounce = bounce;

		/* Update and Reset */
		options.session->scene->integrator->need_update = true;

		options.session->reset(session_buffer_params(), options.session_params.samples);
	}
}
static void display()
{
	options.session->draw(session_buffer_params());

	display_info(options.session->progress);
}