Exemple #1
0
void level_render_tiles(level* l, vec2 camera_position) {

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho(camera_position.x - graphics_viewport_width() / 2,
			camera_position.x + graphics_viewport_width() / 2,
			-camera_position.y + graphics_viewport_height() / 2,
			-camera_position.y - graphics_viewport_height() / 2
			, -1, 1);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	glEnable(GL_TEXTURE_2D);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	/* Start from 1, 0 is no tiles! */

	for(int i = 1; i < l->num_tile_sets; i++) {

		texture* tile_tex = tile_get_texture(i);
		glBindTexture(GL_TEXTURE_2D, texture_handle(tile_tex));
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);

		glBindBuffer(GL_ARRAY_BUFFER, l->tile_sets[i].positions_buffer);
		glVertexPointer(3, GL_FLOAT, 0, (void*)0);

		glBindBuffer(GL_ARRAY_BUFFER, l->tile_sets[i].texcoords_buffer);
		glTexCoordPointer(2, GL_FLOAT, 0, (void*)0);

		glDrawArrays(GL_QUADS, 0, l->tile_sets[i].num_tiles * 4);

		glBindBuffer(GL_ARRAY_BUFFER, 0);
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);

	}

	glDisable(GL_BLEND);
	glDisable(GL_TEXTURE_2D);

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();

}
void deferred_renderer_render_light(light* l) {
  
  matrix_4x4 viewm = camera_view_matrix(CAMERA);
  matrix_4x4 projm = camera_proj_matrix(CAMERA, graphics_viewport_ratio() );
  
  vector4 light_pos = v4(l->position.x, l->position.y, l->position.z, 1);
  light_pos = m44_mul_v4(viewm, light_pos);
  light_pos = m44_mul_v4(projm, light_pos);
  
  light_pos = v4_div(light_pos, light_pos.w);
  
  glUseProgram(shader_program_handle(PROGRAM_UI));
  
	glMatrixMode(GL_PROJECTION);
  glPushMatrix();
	glLoadIdentity();
	glOrtho(0, graphics_viewport_width(), graphics_viewport_height(), 0, -1, 1);
  
	glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
	glLoadIdentity();
  
  float top = ((-light_pos.y + 1) / 2) * graphics_viewport_height() - 8;
  float bot = ((-light_pos.y + 1) / 2) * graphics_viewport_height() + 8;
  float left = ((light_pos.x + 1) / 2) * graphics_viewport_width() - 8;
  float right = ((light_pos.x + 1) / 2) * graphics_viewport_width() + 8;
  
  texture* lightbulb = asset_load_get("$CORANGE/ui/lightbulb.dds");
  glActiveTexture(GL_TEXTURE0 + 0 );
  glBindTexture(GL_TEXTURE_2D, texture_handle(lightbulb));
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(shader_program_handle(PROGRAM_UI), "diffuse"), 0);
  
  glUniform1f(glGetUniformLocation(shader_program_handle(PROGRAM_UI), "alpha_test"), 0.5);
  
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(left, top, -light_pos.z);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(left,  bot, -light_pos.z);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(right,  bot, -light_pos.z);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(right, top, -light_pos.z);
	glEnd();
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glDisable(GL_TEXTURE_2D);
  
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();

  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();

  glUseProgram(0);

}
Exemple #3
0
ui_browser* ui_browser_new() {
  
  int width = graphics_viewport_width();
  int height = graphics_viewport_height();
  
  ui_browser* b = malloc(sizeof(ui_browser));
  
  b->outer = ui_rectangle_new();
  ui_rectangle_move(b->outer, vec2_new(width - 300, 10));
  ui_rectangle_resize(b->outer, vec2_new(280, height - 20));
  ui_rectangle_set_texture(b->outer, 
    asset_hndl_new_load(ui_style_current->box_back_image), 
    ui_style_current->box_back_width,
    ui_style_current->box_back_height,
    ui_style_current->box_back_tile);
  ui_rectangle_set_border(b->outer,
    ui_style_current->box_back_border_size,
    ui_style_current->box_back_border_color);
  ui_rectangle_set_glitch(b->outer, ui_style_current->box_glitch);
  ui_rectangle_set_color(b->outer, vec4_grey());
  
  b->inner = ui_listbox_new();
  ui_listbox_move(b->inner, vec2_new(width - 290, 20));
  ui_listbox_resize(b->inner, vec2_new(260, height - 40));
  
  strcpy(b->directory.ptr, SDL_GetWorkingDir());
  ui_browser_chdir(b, b->directory);
  
  b->active = true;
  
  return b;
  
}
Exemple #4
0
void coin_render(coin* c, vec2 camera_position) {

	glMatrixMode(GL_PROJECTION);
  glPushMatrix();
	glLoadIdentity();
	glOrtho(camera_position.x - graphics_viewport_width() / 2, 
          camera_position.x + graphics_viewport_width() / 2,
          -camera_position.y + graphics_viewport_height() / 2,
          -camera_position.y - graphics_viewport_height() / 2
          , 0, 1);
  
	glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
	glLoadIdentity();
  
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  
  glEnable(GL_TEXTURE_2D);
  
  texture* coin_tex = asset_get(P("./tiles/coin.dds"));
  glBindTexture(GL_TEXTURE_2D, *coin_tex);
  
  glBegin(GL_QUADS);
    
    glTexCoord2f(0, 1); glVertex3f(c->position.x, c->position.y + 32, 0);
    glTexCoord2f(1, 1); glVertex3f(c->position.x + 32, c->position.y + 32, 0);
    glTexCoord2f(1, 0); glVertex3f(c->position.x + 32, c->position.y, 0);
    glTexCoord2f(0, 0); glVertex3f(c->position.x, c->position.y, 0);
    
  glEnd();
  
  glDisable(GL_TEXTURE_2D);
  
  glDisable(GL_BLEND);
  
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  
	glMatrixMode(GL_MODELVIEW);
  glPopMatrix();

}
Exemple #5
0
void shadow_mapper_end() {
  
  glCullFace(GL_BACK);
  glDisable(GL_CULL_FACE);
  glDisable(GL_DEPTH_TEST);
  
  glViewport( 0, 0, graphics_viewport_width(), graphics_viewport_height());
  
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  
}
Exemple #6
0
void graphics_viewport_screenshot() {
  
  unsigned char* image_data = malloc( sizeof(unsigned char) * graphics_viewport_width() * graphics_viewport_height() * 4 );
  glReadPixels( 0, 0, graphics_viewport_width(), graphics_viewport_height(), GL_BGRA, GL_UNSIGNED_BYTE, image_data ); 
  
  image* i = image_new(graphics_viewport_width(), graphics_viewport_height(), image_data);
  
  free(image_data);
  
  timestamp(timestamp_string);

  screenshot_string[0] = '\0';
  strcat(screenshot_string, "./corange_");
  strcat(screenshot_string, timestamp_string);
  strcat(screenshot_string, ".tga");
  
  image_write_to_file(i, screenshot_string);
  
  image_delete(i);
  
}
Exemple #7
0
void level_render_background(level* l) {

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho(0, graphics_viewport_width(), 0, graphics_viewport_height(), -1, 1);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	glEnable(GL_TEXTURE_2D);

	texture* background = asset_get_load(P("./backgrounds/bluesky.dds"));
	glBindTexture(GL_TEXTURE_2D, texture_handle(background));

	glBegin(GL_QUADS);

	glVertex3f(0, graphics_viewport_height(), 0.0);
	glTexCoord2f(1, 0);
	glVertex3f(graphics_viewport_width(), graphics_viewport_height(), 0.0);
	glTexCoord2f(1, 1);
	glVertex3f(graphics_viewport_width(), 0, 0.0);
	glTexCoord2f(0, 1);
	glVertex3f(0, 0, 0.0);
	glTexCoord2f(0, 0);

	glEnd();

	glDisable(GL_TEXTURE_2D);

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();

}
Exemple #8
0
void ui_dialog_set_single_button(ui_dialog* d, bool single) { 

  int width  = graphics_viewport_width();
  int height = graphics_viewport_height();

  d->single_button = single;

  if (single) {
    ui_button_move(d->left, vec2_new(width/2 - 75, height/2 + 40));
    ui_button_set_active(d->right, false);
  } else {
    ui_button_move(d->left, vec2_new(width/2 - 175, height/2 + 40));
    ui_button_set_active(d->right, true);
  }

}
Exemple #9
0
ui_dialog* ui_dialog_new() {
  
  ui_dialog* d = malloc(sizeof(ui_dialog));
  
  int width  = graphics_viewport_width();
  int height = graphics_viewport_height();
  
  d->back = ui_button_new();
  ui_button_move(d->back, vec2_new(width/2 - 200, height/2 - 100));
  ui_button_resize(d->back, vec2_new(400, 200));
  ui_button_set_label(d->back, "");
  ui_button_disable(d->back);
  
  d->title = ui_text_new();
  ui_text_move(d->title, vec2_new(width/2, height/2 - 50));
  ui_text_align(d->title, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER);
  ui_text_set_scale(d->title, vec2_new(1.25, 1.25));
  ui_text_set_color(d->title, vec4_light_grey());
  ui_text_draw_string(d->title, "Title");
  
  d->contents = ui_text_new();
  ui_text_move(d->contents, vec2_new(width/2, height/2 - 00));
  ui_text_align(d->contents, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER);
  ui_text_set_color(d->contents, vec4_light_grey());
  ui_text_draw_string(d->contents, "Contents");
  
  d->left = ui_button_new();
  ui_button_move(d->left, vec2_new(width/2 - 175, height/2 + 40));
  ui_button_resize(d->left, vec2_new(150, 40));
  ui_button_set_label(d->left, "Left");
  
  d->right = ui_button_new();
  ui_button_move(d->right, vec2_new(width/2 + 20, height/2 + 40)); 
  ui_button_resize(d->right, vec2_new(150, 40));
  ui_button_set_label(d->right, "Right");
  
  dialog_count++;
  
  return d;
  
}
Exemple #10
0
void character_render(character* c, vector2 camera_position) {

	glMatrixMode(GL_PROJECTION);
  glPushMatrix();
	glLoadIdentity();
	glOrtho(camera_position.x - graphics_viewport_width() / 2, 
          camera_position.x + graphics_viewport_width() / 2,
          -camera_position.y + graphics_viewport_height() / 2,
          -camera_position.y - graphics_viewport_height() / 2
          , -1, 1);
  
	glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
	glLoadIdentity();
  
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  
  glEnable(GL_TEXTURE_2D);
  
  /* Conditional as to if we render flap or normal icon */
  texture* character_tex;
  if (c->flap_timer > 0.0) {
    character_tex = asset_get("./tiles/character_flap.dds");
  } else {
    character_tex = asset_get("./tiles/character.dds");
  }
  glBindTexture(GL_TEXTURE_2D, *character_tex);
  
  /* Swaps the direction of the uvs when facing the opposite direction */
  if (c->facing_left) {
  
    glBegin(GL_TRIANGLES);
      glTexCoord2f(1, 1); glVertex3f(c->position.x, c->position.y + 32, 0);
      glTexCoord2f(1, 0); glVertex3f(c->position.x, c->position.y, 0);
      glTexCoord2f(0, 0); glVertex3f(c->position.x + 32, c->position.y, 0);
      
      glTexCoord2f(1, 1); glVertex3f(c->position.x, c->position.y + 32, 0);
      glTexCoord2f(0, 1); glVertex3f(c->position.x + 32, c->position.y + 32, 0);
      glTexCoord2f(0, 0);glVertex3f(c->position.x + 32, c->position.y, 0);
    glEnd();
    
  } else {
  
    glBegin(GL_TRIANGLES);
      glTexCoord2f(0, 1); glVertex3f(c->position.x, c->position.y + 32, 0);
      glTexCoord2f(0, 0); glVertex3f(c->position.x, c->position.y, 0);
      glTexCoord2f(1, 0); glVertex3f(c->position.x + 32, c->position.y, 0);
      
      glTexCoord2f(0, 1); glVertex3f(c->position.x, c->position.y + 32, 0);
      glTexCoord2f(1, 1); glVertex3f(c->position.x + 32, c->position.y + 32, 0);
      glTexCoord2f(1, 0);glVertex3f(c->position.x + 32, c->position.y, 0);
    glEnd();
    
  }
  
  glDisable(GL_TEXTURE_2D);
  
  glDisable(GL_BLEND);
  
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  
	glMatrixMode(GL_MODELVIEW);
  glPopMatrix();

}
Exemple #11
0
void scotland_init() {
  
  graphics_viewport_set_dimensions(1280, 720);
  graphics_viewport_set_title("Scotland");
  
  ui_button* loading = ui_elem_new("loading", ui_button);
  ui_button_move(loading, vec2_new(graphics_viewport_width() / 2 - 40,graphics_viewport_height() / 2 - 13));
  ui_button_resize(loading, vec2_new(80,25));
  ui_button_set_label(loading, "Loading...");
  ui_button_disable(loading);
  
  ui_spinner* load_spinner = ui_elem_new("load_spinner", ui_spinner);
  load_spinner->color = vec4_white();
  load_spinner->top_left = vec2_new(graphics_viewport_width() / 2 + 50, graphics_viewport_height() / 2 - 13);
  load_spinner->bottom_right = vec2_add(load_spinner->top_left, vec2_new(24,24));
  
  ui_button* framerate = ui_elem_new("framerate", ui_button);
  ui_button_move(framerate, vec2_new(10,10));
  ui_button_resize(framerate, vec2_new(30,25));
  ui_button_set_label(framerate, "FRAMERATE");
  ui_button_disable(framerate);
  framerate->active = false;
  
  ui_button* wireframe = ui_elem_new("wireframe", ui_button);
  ui_button_move(wireframe, vec2_new(50,10));
  ui_button_resize(wireframe, vec2_new(80,25));
  ui_button_set_label(wireframe, "wireframe");
  wireframe->active = false;
  
  ui_elem_add_event("wireframe", toggle_wireframe);
  
  ui_button* freecam = ui_elem_new("freecam", ui_button);
  ui_button_move(freecam, vec2_new(140,10));
  ui_button_resize(freecam, vec2_new(65,25));
  ui_button_set_label(freecam, "freecam");
  freecam->active = false;
  
  ui_elem_add_event("freecam", toggle_freecam);
  
  loading_resources = true;
  SDL_Thread* load_thread = SDL_GL_CreateThread(load_resources, NULL);
  
  /* New Camera and light */
  
  camera* cam = entity_new("camera", camera);
  cam->position = vec3_new(512.0, 200.0, 512.0);
  cam->target =  vec3_new(0.0, 0.0, 0.0);
  
  light* sun = entity_new("sun", light);
  light_set_type(sun, light_type_sun);
  sun->position = vec3_new(0, 512, 0);
  sun->target = vec3_new(512, 0, 512);
  
  /* Renderer Setup */
  
  shadow_mapper_init(sun);
  
  forward_renderer_init();
  forward_renderer_set_camera(cam);
  forward_renderer_set_shadow_light(sun);
  forward_renderer_set_shadow_texture( shadow_mapper_depth_texture() );
  forward_renderer_add_light(sun);
  
}
Exemple #12
0
void ui_spinner_render(ui_spinner* s) {
  
  if (!s->active) return;
  
  vector2 top_left = s->top_left;
  vector2 top_right = v2(s->bottom_right.x, s->top_left.y);
  vector2 bot_left = v2(s->top_left.x, s->bottom_right.y);
  vector2 bot_right = s->bottom_right;
  
  vector2 center;
  center.x = (top_left.x + top_right.x) / 2;
  center.y = (top_left.y + bot_left.y) / 2;
  
  top_left = v2_sub(top_left, center);
  top_right = v2_sub(top_right, center);
  bot_left = v2_sub(bot_left, center);
  bot_right = v2_sub(bot_right, center);
  
  matrix_2x2 rot = m22_rotation(s->rotation);
  
  top_left = m22_mul_v2(rot, top_left);
  top_right = m22_mul_v2(rot, top_right);
  bot_left = m22_mul_v2(rot, bot_left);
  bot_right = m22_mul_v2(rot, bot_right);
  
  top_left = v2_add(top_left, center);
  top_right = v2_add(top_right, center);
  bot_left = v2_add(bot_left, center);
  bot_right = v2_add(bot_right, center);
  
	glMatrixMode(GL_PROJECTION);
  glPushMatrix();
	glLoadIdentity();
	glOrtho(0, graphics_viewport_width(), graphics_viewport_height(), 0, -1, 1);
  
	glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
	glLoadIdentity();
  
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, *(s->texture) );
  
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  
  glColor4f(s->color.r, s->color.g, s->color.b, s->color.a);
  
  glBegin(GL_QUADS);
    glTexCoord2f(0, 1); glVertex3f(top_left.x, top_left.y, 0);
    glTexCoord2f(1, 1); glVertex3f(bot_left.x, bot_left.y, 0);
    glTexCoord2f(1, 0); glVertex3f(bot_right.x, bot_right.y, 0);
    glTexCoord2f(0, 0); glVertex3f(top_right.x, top_right.y, 0);
  glEnd();
  
  glColor4f(1, 1, 1, 1);
  
  glDisable(GL_BLEND);
  
  glDisable(GL_TEXTURE_2D);
  
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  
	glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
  
}
Exemple #13
0
void ui_rectangle_render(ui_rectangle* r) {

    if(!r->active) {
        return;
    }

    int width = graphics_viewport_width();
    int height = graphics_viewport_height();

    asset_hndl mat = asset_hndl_new_load(P("$CORANGE/shaders/ui.mat"));
    shader_program* program_ui = material_get_entry(asset_hndl_ptr(&mat), 0)->program;

    shader_program_enable(program_ui);
    shader_program_set_mat4(program_ui, "world", mat4_id());
    shader_program_set_mat4(program_ui, "view", mat4_id());
    shader_program_set_mat4(program_ui, "proj", mat4_orthographic(0, width, height, 0, -1, 1));

    glEnable(GL_BLEND);
    glBlendFunc(r->blend_src, r->blend_dst);

    if (asset_hndl_isnull(&r->texture)) {
        shader_program_set_texture(program_ui, "diffuse", 0, asset_hndl_new_load(P("$CORANGE/textures/white.dds")));
    } else {
        shader_program_set_texture(program_ui, "diffuse", 0, r->texture);
    }

    shader_program_set_texture(program_ui, "random",  1, asset_hndl_new_load(P("$CORANGE/textures/random.dds")));

    shader_program_set_float(program_ui, "time", r->time);
    shader_program_set_float(program_ui, "glitch", r->glitch);

    float rect_colors[] = {
        r->color.x, r->color.y, r->color.z, r->color.w,
        r->color.x, r->color.y, r->color.z, r->color.w,
        r->color.x, r->color.y, r->color.z, r->color.w,
        r->color.x, r->color.y, r->color.z, r->color.w,
        r->color.x, r->color.y, r->color.z, r->color.w,
        r->color.x, r->color.y, r->color.z, r->color.w
    };

    float rect_positions[] = {
        r->top_left.x,     r->top_left.y,
        r->top_left.x,     r->bottom_right.y,
        r->bottom_right.x, r->bottom_right.y,
        r->top_left.x,     r->top_left.y,
        r->bottom_right.x, r->top_left.y,
        r->bottom_right.x, r->bottom_right.y,
    };

    float rect_texcoords[12];

    if (r->texture_tile) {

        float width = r->bottom_right.x - r->top_left.x;
        float height = r->bottom_right.y - r->top_left.y;

        rect_texcoords[0]  = 0;
        rect_texcoords[1]  = height / r->texture_height;
        rect_texcoords[2]  = width  / r->texture_width;
        rect_texcoords[3]  = height / r->texture_height;
        rect_texcoords[4]  = width  / r->texture_width;
        rect_texcoords[5]  = 0;
        rect_texcoords[6]  = 0;
        rect_texcoords[7]  = height / r->texture_height;
        rect_texcoords[8]  = 0;
        rect_texcoords[9]  = 0;
        rect_texcoords[10] = width  / r->texture_width;
        rect_texcoords[11] = 0;

    } else {

        rect_texcoords[0]  = 0;
        rect_texcoords[1]  = 0;
        rect_texcoords[2]  = 1;
        rect_texcoords[3]  = 0;
        rect_texcoords[4]  = 1;
        rect_texcoords[5]  = 1;
        rect_texcoords[6]  = 0;
        rect_texcoords[7]  = 0;
        rect_texcoords[8]  = 0;
        rect_texcoords[9]  = 1;
        rect_texcoords[10] = 1;
        rect_texcoords[11] = 1;

    }

    shader_program_enable_attribute(program_ui, "vPosition", 2, 2, rect_positions);
    shader_program_enable_attribute(program_ui, "vTexcoord", 2, 2, rect_texcoords);
    shader_program_enable_attribute(program_ui, "vColor", 4, 4, rect_colors);

    glDrawArrays(GL_TRIANGLES, 0, 6);

    shader_program_disable_attribute(program_ui, "vPosition");
    shader_program_disable_attribute(program_ui, "vTexcoord");
    shader_program_disable_attribute(program_ui, "vColor");

    if (r->border_size > 0) {

        glLineWidth(r->border_size);

        float border_colors[] = {
            r->border_color.x, r->border_color.y, r->border_color.z, r->border_color.w,
            r->border_color.x, r->border_color.y, r->border_color.z, r->border_color.w,
            r->border_color.x, r->border_color.y, r->border_color.z, r->border_color.w,
            r->border_color.x, r->border_color.y, r->border_color.z, r->border_color.w,
            r->border_color.x, r->border_color.y, r->border_color.z, r->border_color.w
        };

        float border_positions[] = {
            r->top_left.x,     r->top_left.y,
            r->bottom_right.x, r->top_left.y,
            r->bottom_right.x, r->bottom_right.y,
            r->top_left.x,     r->bottom_right.y,
            r->top_left.x,     r->top_left.y
        };

        float border_texcoord[] = {
            0, 0,  0, 0,  0, 0,  0, 0,  0, 0
        };

        shader_program_enable_attribute(program_ui, "vPosition", 2, 2, border_positions);
        shader_program_enable_attribute(program_ui, "vTexcoord", 2, 2, border_texcoord);
        shader_program_enable_attribute(program_ui, "vColor", 4, 4, border_colors);

        glDrawArrays(GL_LINE_STRIP, 0, 5);

        shader_program_disable_attribute(program_ui, "vPosition");
        shader_program_disable_attribute(program_ui, "vTexcoord");
        shader_program_disable_attribute(program_ui, "vColor");

        glLineWidth(1);
    }

    glDisable(GL_BLEND);

    shader_program_disable(program_ui);

}
void deferred_renderer_init() {
  
  num_lights = 0;
  
  EXPOSURE = 0.0;
  EXPOSURE_SPEED = 1.0;
  EXPOSURE_TARGET = 0.4;
  
  COLOR_CORRECTION = asset_load_get("$CORANGE/resources/identity.lut");
  RANDOM = asset_load_get("$CORANGE/resources/random.dds");
  ENVIRONMENT = asset_load_get("$CORANGE/resources/envmap.dds");
  VIGNETTING = asset_load_get("$CORANGE/resources/vignetting.dds");
  
  load_folder("$CORANGE/shaders/deferred/");
  
  PROGRAM_STATIC = asset_get("$CORANGE/shaders/deferred/static.prog");
  PROGRAM_ANIMATED = asset_get("$CORANGE/shaders/deferred/animated.prog");
  PROGRAM_CLEAR = asset_get("$CORANGE/shaders/deferred/clear.prog");
  PROGRAM_SSAO = asset_get("$CORANGE/shaders/deferred/ssao.prog");
  PROGRAM_TONEMAP = asset_get("$CORANGE/shaders/deferred/tonemap.prog");
  PROGRAM_COMPOSE = asset_get("$CORANGE/shaders/deferred/compose.prog");
  PROGRAM_POST = asset_get("$CORANGE/shaders/deferred/post.prog");
  PROGRAM_UI = asset_get("$CORANGE/shaders/deferred/ui.prog");
  
  NORMAL = glGetAttribLocation(shader_program_handle(PROGRAM_STATIC), "normal");
  TANGENT = glGetAttribLocation(shader_program_handle(PROGRAM_STATIC), "tangent");
  BINORMAL = glGetAttribLocation(shader_program_handle(PROGRAM_STATIC), "binormal");  
  
  NORMAL_ANIMATED = glGetAttribLocation(shader_program_handle(PROGRAM_ANIMATED), "normal");
  TANGENT_ANIMATED = glGetAttribLocation(shader_program_handle(PROGRAM_ANIMATED), "tangent");
  BINORMAL_ANIMATED = glGetAttribLocation(shader_program_handle(PROGRAM_ANIMATED), "binormal");  
  BONE_INDICIES = glGetAttribLocation(shader_program_handle(PROGRAM_ANIMATED), "bone_indicies");
  BONE_WEIGHTS = glGetAttribLocation(shader_program_handle(PROGRAM_ANIMATED), "bone_weights"); 
  
  int viewport_width = graphics_viewport_width();
  int viewport_height = graphics_viewport_height();
  
  glGenFramebuffers(1, &fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo);
  
  glGenRenderbuffers(1, &diffuse_buffer);
  glBindRenderbuffer(GL_RENDERBUFFER, diffuse_buffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, viewport_width, viewport_height);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, diffuse_buffer);   
  
  glGenRenderbuffers(1, &positions_buffer);
  glBindRenderbuffer(GL_RENDERBUFFER, positions_buffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, viewport_width, viewport_height);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, positions_buffer);  
  
  glGenRenderbuffers(1, &normals_buffer);  
  glBindRenderbuffer(GL_RENDERBUFFER, normals_buffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA16F, viewport_width, viewport_height);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, normals_buffer);  
  
  glGenRenderbuffers(1, &depth_buffer);
  glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, viewport_width, viewport_height);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer);  
  
  glGenTextures(1, &diffuse_texture);
  glBindTexture(GL_TEXTURE_2D, diffuse_texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, viewport_width, viewport_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, diffuse_texture, 0);
  
  glGenTextures(1, &positions_texture);
  glBindTexture(GL_TEXTURE_2D, positions_texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, viewport_width, viewport_height, 0, GL_RGBA, GL_FLOAT, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, positions_texture, 0);
  
  glGenTextures(1, &normals_texture);
  glBindTexture(GL_TEXTURE_2D, normals_texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, viewport_width, viewport_height, 0, GL_RGBA, GL_FLOAT, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normals_texture, 0);
  
  glGenTextures(1, &depth_texture);
  glBindTexture(GL_TEXTURE_2D, depth_texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, viewport_width, viewport_height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
  
  
  glGenFramebuffers(1, &ssao_fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, ssao_fbo);
  
  glGenRenderbuffers(1, &ssao_buffer);
  glBindRenderbuffer(GL_RENDERBUFFER, ssao_buffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, viewport_width / 2, viewport_height / 2);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ssao_buffer);   
  
  glGenTextures(1, &ssao_texture);
  glBindTexture(GL_TEXTURE_2D, ssao_texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, viewport_width / 2, viewport_height / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssao_texture, 0);
  
  glGenFramebuffers(1, &hdr_fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo);
  
  glGenRenderbuffers(1, &hdr_buffer);
  glBindRenderbuffer(GL_RENDERBUFFER, hdr_buffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA16F, viewport_width, viewport_height);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ldr_buffer);   
  
  glGenTextures(1, &hdr_texture);
  glBindTexture(GL_TEXTURE_2D, hdr_texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, viewport_width, viewport_height, 0, GL_RGBA, GL_FLOAT, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_texture, 0);
  
  glGenFramebuffers(1, &ldr_fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, ldr_fbo);
  
  glGenRenderbuffers(1, &ldr_buffer);
  glBindRenderbuffer(GL_RENDERBUFFER, ldr_buffer);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, viewport_width, viewport_height);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ldr_buffer);   
  
  glGenTextures(1, &ldr_texture);
  glBindTexture(GL_TEXTURE_2D, ldr_texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, viewport_width, viewport_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ldr_texture, 0);
  
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  
}
void deferred_renderer_end() {
  
  glDisable(GL_DEPTH_TEST);
  glDisable(GL_CULL_FACE);
  
  /* Render out ssao */
  
  glBindFramebuffer(GL_FRAMEBUFFER, ssao_fbo);
  
  glViewport(0, 0, graphics_viewport_width() / 2, graphics_viewport_height() / 2);
  
  GLuint ssao_handle = shader_program_handle(PROGRAM_SSAO);
  glUseProgram(ssao_handle);
  
	glMatrixMode(GL_PROJECTION);
  glPushMatrix();
	glLoadIdentity();
	glOrtho(-1.0, 1.0, -1.0, 1.0, -1, 1);
  
	glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
	glLoadIdentity();
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glBindTexture(GL_TEXTURE_2D, depth_texture);
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(ssao_handle, "depth_texture"), 0);
  
  glActiveTexture(GL_TEXTURE0 + 1 );
  glBindTexture(GL_TEXTURE_2D, texture_handle(RANDOM));
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(ssao_handle, "random_texture"), 1);
  
  float seed = CAMERA->position.x + CAMERA->position.y + CAMERA->position.z;
  glUniform1f(glGetUniformLocation(ssao_handle, "seed"), seed);
  
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0, -1.0,  0.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0, -1.0,  0.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0,  1.0,  0.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0,  1.0,  0.0f);
	glEnd();
  
  glActiveTexture(GL_TEXTURE0 + 1 );
  glDisable(GL_TEXTURE_2D);
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glDisable(GL_TEXTURE_2D);
  
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();

  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
  
  /* End */
  
  /* Render full screen quad to hdr fbo */
  
  glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo);
  
  glViewport(0, 0, graphics_viewport_width(), graphics_viewport_height());
  
  GLuint screen_handle = shader_program_handle(PROGRAM_COMPOSE);
  glUseProgram(screen_handle);
  
	glMatrixMode(GL_PROJECTION);
  glPushMatrix();
	glLoadIdentity();
	glOrtho(-1.0, 1.0, -1.0, 1.0, -1, 1);
  
	glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
	glLoadIdentity();
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glBindTexture(GL_TEXTURE_2D, diffuse_texture);
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_handle, "diffuse_texture"), 0);
  
  glActiveTexture(GL_TEXTURE0 + 1 );
  glBindTexture(GL_TEXTURE_2D, positions_texture);
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_handle, "positions_texture"), 1);
  
  glActiveTexture(GL_TEXTURE0 + 2 );
  glBindTexture(GL_TEXTURE_2D, normals_texture);
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_handle, "normals_texture"), 2);
  
  glActiveTexture(GL_TEXTURE0 + 3 );
  glBindTexture(GL_TEXTURE_2D, depth_texture);
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_handle, "depth_texture"), 3);
  
  glActiveTexture(GL_TEXTURE0 + 4 );
  glBindTexture(GL_TEXTURE_2D, texture_handle(SHADOW_TEX));
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_handle, "shadows_texture"), 4);
  
  glActiveTexture(GL_TEXTURE0 + 5 );
  glBindTexture(GL_TEXTURE_2D, ssao_texture);
  glEnable(GL_TEXTURE_2D);
  glGenerateMipmap(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_handle, "ssao_texture"), 5);
  
  glActiveTexture(GL_TEXTURE0 + 6 );
  glBindTexture(GL_TEXTURE_2D, texture_handle(ENVIRONMENT));
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_handle, "env_texture"), 6);
  
  GLint cam_position = glGetUniformLocation(screen_handle, "camera_position");
  glUniform3f(cam_position, CAMERA->position.x, CAMERA->position.y, CAMERA->position.z);
  
  GLint lproj_matrix_u = glGetUniformLocation(screen_handle, "light_proj");
  glUniformMatrix4fv(lproj_matrix_u, 1, 0, LIGHT_PROJ_MATRIX);
  
  GLint lview_matrix_u = glGetUniformLocation(screen_handle, "light_view");
  glUniformMatrix4fv(lview_matrix_u, 1, 0, LIGHT_VIEW_MATRIX);
  
  for(int i = 0; i < num_lights; i++) {
    light_power[i] = lights[i]->power;
    light_falloff[i] = lights[i]->falloff;
    light_position[i] = lights[i]->position;
    light_target[i] = lights[i]->target;
    light_diffuse[i] = lights[i]->diffuse_color;
    light_ambient[i] = lights[i]->ambient_color;
    light_specular[i] = lights[i]->specular_color;
  }
  
  glUniform1i(glGetUniformLocation(screen_handle, "num_lights"), num_lights);
  
  GLint light_power_u = glGetUniformLocation(screen_handle, "light_power");
  GLint light_falloff_u = glGetUniformLocation(screen_handle, "light_falloff");
  GLint light_position_u = glGetUniformLocation(screen_handle, "light_position");
  GLint light_target_u = glGetUniformLocation(screen_handle, "light_target");
  GLint light_diffuse_u = glGetUniformLocation(screen_handle, "light_diffuse");
  GLint light_ambient_u = glGetUniformLocation(screen_handle, "light_ambient");
  GLint light_specular_u = glGetUniformLocation(screen_handle, "light_specular");
  
  glUniform1fv(light_power_u, num_lights, (const GLfloat*)light_power);
  glUniform1fv(light_falloff_u, num_lights, (const GLfloat*)light_falloff);
  glUniform3fv(light_position_u, num_lights, (const GLfloat*)light_position);
  glUniform3fv(light_target_u, num_lights, (const GLfloat*)light_target);
  glUniform3fv(light_diffuse_u, num_lights, (const GLfloat*)light_diffuse);
  glUniform3fv(light_ambient_u, num_lights, (const GLfloat*)light_ambient);
  glUniform3fv(light_specular_u, num_lights, (const GLfloat*)light_specular);
  
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0, -1.0,  0.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0, -1.0,  0.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0,  1.0,  0.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0,  1.0,  0.0f);
	glEnd();
  
  glActiveTexture(GL_TEXTURE0 + 6 );
  glDisable(GL_TEXTURE_2D);
  
  glActiveTexture(GL_TEXTURE0 + 5 );
  glDisable(GL_TEXTURE_2D);
  
  glActiveTexture(GL_TEXTURE0 + 4 );
  glDisable(GL_TEXTURE_2D);
  
  glActiveTexture(GL_TEXTURE0 + 3 );
  glDisable(GL_TEXTURE_2D);
  
  glActiveTexture(GL_TEXTURE0 + 2 );
  glDisable(GL_TEXTURE_2D);
  
  glActiveTexture(GL_TEXTURE0 + 1 );
  glDisable(GL_TEXTURE_2D);
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glDisable(GL_TEXTURE_2D);
  
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();

  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
  
  glUseProgram(0);

  /* Render HDR to LDR buffer */
  
  glBindFramebuffer(GL_FRAMEBUFFER, ldr_fbo);
  
  GLuint screen_tonemap_handle = shader_program_handle(PROGRAM_TONEMAP);
  glUseProgram(screen_tonemap_handle);
  
	glMatrixMode(GL_PROJECTION);
  glPushMatrix();
	glLoadIdentity();
	glOrtho(-1.0, 1.0, -1.0, 1.0, -1, 1);
  
	glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
	glLoadIdentity();
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glBindTexture(GL_TEXTURE_2D, hdr_texture);
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_tonemap_handle, "hdr_texture"), 0);

  glUniform1f(glGetUniformLocation(screen_tonemap_handle, "exposure"), EXPOSURE);
  
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0, -1.0,  0.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0, -1.0,  0.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0,  1.0,  0.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0,  1.0,  0.0f);
	glEnd();
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glDisable(GL_TEXTURE_2D);
  
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();

  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
  
  glUseProgram(0);
  
  /* Generate Mipmaps, adjust exposure */
  
  unsigned char color[4] = {0,0,0,0};
  int level = -1;
  int width = 0;
  int height = 0;
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glBindTexture(GL_TEXTURE_2D, ldr_texture);
  glEnable(GL_TEXTURE_2D);
  
  glGenerateMipmap(GL_TEXTURE_2D);
  
  do {
    level++;
    glGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_WIDTH, &width);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_WIDTH, &height);
    
    if (level > 50) { error("Unable to find lowest mip level. Perhaps mipmaps were not generated"); }
    
  } while ((width > 1) || (height > 1));
  
  glGetTexImage(GL_TEXTURE_2D, level, GL_RGBA, GL_UNSIGNED_BYTE, color);
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glDisable(GL_TEXTURE_2D);
  
  float average = (float)(color[0] + color[1] + color[2]) / (3.0 * 255.0);
  
  EXPOSURE += (EXPOSURE_TARGET - average) * EXPOSURE_SPEED;
  
  /* Render final frame */
  
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  
  GLuint screen_post_handle = shader_program_handle(PROGRAM_POST);
  glUseProgram(screen_post_handle);
  
	glMatrixMode(GL_PROJECTION);
  glPushMatrix();
	glLoadIdentity();
	glOrtho(-1.0, 1.0, -1.0, 1.0, -1, 1);
  
	glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
	glLoadIdentity();
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glBindTexture(GL_TEXTURE_2D, ldr_texture);
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_post_handle, "diffuse_texture"), 0);
  
  glActiveTexture(GL_TEXTURE0 + 1 );
  glBindTexture(GL_TEXTURE_2D, texture_handle(VIGNETTING));
  glEnable(GL_TEXTURE_2D);
  glUniform1i(glGetUniformLocation(screen_post_handle, "vignetting_texture"), 1);
  
  glActiveTexture(GL_TEXTURE0 + 2 );
  glBindTexture(GL_TEXTURE_3D, texture_handle(COLOR_CORRECTION));
  glEnable(GL_TEXTURE_3D);
  glUniform1i(glGetUniformLocation(screen_post_handle, "lut"), 2);
  
  glUniform1i(glGetUniformLocation(screen_post_handle, "width"), graphics_viewport_width());
  glUniform1i(glGetUniformLocation(screen_post_handle, "height"), graphics_viewport_height());
  glUniform1i(glGetUniformLocation(screen_post_handle, "aa_type"), 1);
  
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0, -1.0,  0.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0, -1.0,  0.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0,  1.0,  0.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0,  1.0,  0.0f);
	glEnd();
  
  glActiveTexture(GL_TEXTURE0 + 2 );
  glDisable(GL_TEXTURE_3D);
  
  glActiveTexture(GL_TEXTURE0 + 1 );
  glDisable(GL_TEXTURE_2D);
  
  glActiveTexture(GL_TEXTURE0 + 0 );
  glDisable(GL_TEXTURE_2D);
  
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();

  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
  
  glUseProgram(0);
  
}