Documentation
extern crate gl;
extern crate glutin;
extern crate time;
extern crate gl_helpers;


use glutin::GlContext;
use gl::types::*;

use gl_helpers::*;


static FB_DATA: [GLfloat; 16] = [
    // position     uv
     1f32,  1f32,   1f32, 1f32,
    -1f32,  1f32,   0f32, 1f32,
     1f32, -1f32,   1f32, 0f32,
    -1f32, -1f32,   0f32, 0f32
];

static TR_DATA: [GLfloat; 6] = [
    0.0,  0.5,
    -0.5, -0.5,
    0.5, -0.5
];

static FB_VERTEX:  &'static str = "
    #version 120

    attribute vec2 position;
    attribute vec2 uv;

    varying vec2 v_uv;

    void main() {
        gl_Position = vec4(position, 0.0, 1.0);
        v_uv = uv;
    }
";
static FB_FRAGMENT:  &'static str = "
    #version 120

    uniform sampler2D diffuse;

    varying vec2 v_uv;

    void main() {
        gl_FragColor = texture2D(diffuse, v_uv);
    }
";

static TR_VERTEX: &'static str = "
    #version 120

    uniform vec2 offset;

    attribute vec2 position;

    void main() {
        gl_Position = vec4(position + offset, 0, 1.0);
    }
";

static TR_FRAGMENT: &'static str = "
    #version 120

    void main() {
        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
";

fn main() {
    let mut screen_width = 1024_usize;
    let mut screen_height = 768_usize;

    let mut events_loop = glutin::EventsLoop::new();
    let window = glutin::WindowBuilder::new()
        .with_title("Framebuffer")
        .with_dimensions(screen_width as u32, screen_height as u32);
    let gl_window = glutin::GlWindow::new(
        window,
        glutin::ContextBuilder::new()
            .with_vsync(true),
        &events_loop
    ).unwrap();

    unsafe {
        gl_window.make_current().unwrap();
    }

    gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);

    let gl_info = GLInfo::new();
    println!("{}", gl_info.version());
    println!(
        "OpenGL version: {:?}.{:?}, GLSL version {:?}.{:?}0",
        gl_info.major(), gl_info.minor(), gl_info.glsl_major(), gl_info.glsl_minor()
    );

    gl_set_defaults();

    static SIZE: usize = 8_usize;
    let fb_program = GLProgram::new(FB_VERTEX, FB_FRAGMENT);

    let mut fb_texture = GLTexture::new_null_2d(
        screen_width / SIZE,
        screen_height / SIZE,
        DataFormat::RGBA,
        DataKind::UnsignedByte,
        FilterMode::None,
        Wrap::Clamp,
        false
    );

    let fb_framebuffer = GLFramebuffer::new(&fb_texture, &[Attachment::Color], 0);
    let fb_renderbuffer = GLRenderbuffer::new(DataFormat::DepthComponent, Attachment::Depth, screen_width / SIZE, screen_height / SIZE);

    let fb_buffer = GLBuffer::new(BufferTarget::Array, 4, Usage::StaticDraw, &FB_DATA);

    let mut fb_vertex_array = GLVertexArray::new();
    fb_vertex_array.bind();
    fb_buffer.bind();
    fb_vertex_array.add_attribute(&fb_buffer, fb_program.get_attribute("position"), 0);
    fb_vertex_array.add_attribute(&fb_buffer, fb_program.get_attribute("uv"), 2);


    let tr_program = GLProgram::new(TR_VERTEX, TR_FRAGMENT);

    let tr_buffer = GLBuffer::new(BufferTarget::Array, 0, Usage::StaticDraw, &TR_DATA);

    let mut tr_vertex_array = GLVertexArray::new();
    tr_vertex_array.bind();
    tr_buffer.bind();
    tr_vertex_array.add_attribute(&tr_buffer, tr_program.get_attribute("position"), 0);


    let mut playing = true;

    let start_time = time::now();
    let mut last_time = start_time;
    let mut current_time;
    let mut ms = 0f32;
    let mut dt;

    let mut offset = [1f32; 2];

    while playing {
        current_time = time::now();
        dt = (current_time - last_time).num_nanoseconds().unwrap() as f32 * 0.000001f32;
        ms += dt;
        last_time = current_time;

        events_loop.poll_events(|event| {
            match event {
                glutin::Event::WindowEvent { event: glutin::WindowEvent::Closed, .. } => {
                    playing = false;
                },
                glutin::Event::WindowEvent { event: glutin::WindowEvent::Resized(w, h), .. } => {
                    gl_window.resize(w, h);

                    screen_width = w as usize;
                    screen_height = h as usize;

                    fb_texture.resize_null_2d(screen_width / SIZE,screen_height / SIZE);
                    fb_framebuffer.set(&fb_texture, &[Attachment::Color], 0);
                    fb_renderbuffer.set(DataFormat::DepthComponent, Attachment::Depth, screen_width / SIZE, screen_height / SIZE);
                },
                _ => (),
            }
        });

        fb_framebuffer.bind();
        fb_renderbuffer.bind();

        gl_set_viewport(0, 0, screen_width / SIZE, screen_height / SIZE);
        gl_set_clear_color(&[0.3, 0.3, 0.3, 1.0]);
        gl_clear(true, true, true);

        tr_program.bind();

        tr_vertex_array.bind();
        tr_vertex_array.enable_attributes();

        offset[0] = (ms * 0.001_f32).cos() * 0.5_f32;
        offset[1] = (ms * 0.001_f32).sin() * 0.5_f32;

        tr_program.get_uniform("offset").set_2f(&offset);

        gl_draw_arrays(DrawMode::Triangles, 0, 3);

        fb_framebuffer.unbind();
        fb_renderbuffer.unbind();


        gl_set_viewport(0, 0, screen_width, screen_height);
        gl_set_clear_color(&[0.3, 0.3, 0.3, 1.0]);
        gl_clear(true, true, true);

        fb_program.bind();
        fb_vertex_array.bind();
        fb_vertex_array.enable_attributes();

        fb_program.get_uniform("diffuse").set_sampler_2d(&fb_texture, 0);

        gl_draw_arrays(DrawMode::TriangleStrip, 0, 4);


        gl_window.swap_buffers().unwrap();
    }
}