#![feature(link_args)]
extern crate gl;
extern crate gl_helpers;
extern crate glutin;
extern crate main_loop;
use gl::types::*;
use glutin::{Api, GlContext, GlRequest};
use gl_helpers::*;
#[cfg(target_os = "emscripten")]
#[allow(unused_attributes)]
#[link_args = "-s OFFSCREENCANVAS_SUPPORT=1"]
extern "C" {}
static FB_DATA: [GLfloat; 16] = [
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 = "
attribute vec2 position;
attribute vec2 uv;
varying vec2 v_uv;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
v_uv = uv;
}
";
#[cfg(any(target_os = "emscripten", target_os = "android"))]
static FB_FRAGMENT: &'static str = "
precision mediump float;
uniform sampler2D diffuse;
varying vec2 v_uv;
void main() {
gl_FragColor = texture2D(diffuse, v_uv);
}
";
#[cfg(not(any(target_os = "emscripten", target_os = "android")))]
static FB_FRAGMENT: &'static str = "
uniform sampler2D diffuse;
varying vec2 v_uv;
void main() {
gl_FragColor = texture2D(diffuse, v_uv);
}
";
static TR_VERTEX: &'static str = "
uniform vec2 offset;
attribute vec2 position;
void main() {
gl_Position = vec4(position + offset, 0, 1.0);
}
";
#[cfg(any(target_os = "emscripten", target_os = "android"))]
static TR_FRAGMENT: &'static str = "
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
";
#[cfg(not(any(target_os = "emscripten", target_os = "android")))]
static TR_FRAGMENT: &'static str = "
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_maximized(true);
let context = {
let builder = glutin::ContextBuilder::new().with_vsync(true);
if cfg!(target_os = "android") {
builder.with_gl(GlRequest::Specific(Api::OpenGlEs, (2, 0)))
} else {
builder
}
};
let gl_window = glutin::GlWindow::new(window, context, &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();
if let Some(logical_size) = gl_window.get_inner_size() {
let physical_size = logical_size.to_physical(gl_window.get_hidpi_factor());
screen_width = physical_size.width as usize;
screen_height = physical_size.height as usize;
gl_window.resize(physical_size);
gl_set_viewport(0, 0, screen_width, screen_height);
}
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,
InternalFormat::RGBA,
DataFormat::RGBA,
DataKind::UnsignedByte,
FilterMode::None,
Wrap::Clamp,
false,
);
let fb_framebuffer = GLFramebuffer::new(&fb_texture, &[Attachment::Color(0)], 0);
let fb_renderbuffer = GLRenderbuffer::new(
InternalFormat::DepthComponent16,
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 offset = [1f32; 2];
main_loop::glutin::run(&mut events_loop, move |events, ms_f64| {
let ms = ms_f64 as f32;
for event in events {
match event {
glutin::Event::WindowEvent {
event: glutin::WindowEvent::CloseRequested,
..
} => {
return main_loop::ControlFlow::Break;
}
glutin::Event::WindowEvent {
event: glutin::WindowEvent::Resized(logical_size),
..
} => {
let physical_size = logical_size.to_physical(gl_window.get_hidpi_factor());
gl_window.resize(physical_size);
screen_width = physical_size.width as usize;
screen_height = physical_size.height as usize;
fb_texture.resize_null_2d(screen_width / SIZE, screen_height / SIZE);
fb_framebuffer.set(&fb_texture, &[Attachment::Color(0)], 0);
fb_renderbuffer.set(
InternalFormat::DepthComponent16,
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();
main_loop::ControlFlow::Continue
});
}