Created
December 16, 2013 07:03
-
-
Save JarrettBillingsley/7983334 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[feature(globs)]; | |
#[feature(macro_rules)]; | |
#[allow(dead_code)]; | |
#[allow(unused_mut)]; | |
#[allow(unused_variable)]; | |
#[allow(unused_imports)]; | |
extern mod gl; | |
extern mod glfw; | |
extern mod cgmath; | |
use std::c_str::{CString}; | |
use std::iter::{range_inclusive}; | |
use std::libc::{c_void}; | |
use std::mem::{size_of}; | |
use std::ptr::{null}; | |
use std::rand::*; | |
use std::vec::raw; | |
use std::vec; | |
use cgmath::angle::*; | |
use cgmath::matrix::*; | |
use cgmath::point::{Point3}; | |
use cgmath::projection::*; | |
use cgmath::ptr::*; | |
use cgmath::vector::{Vec2, Vec3}; | |
use gl::types::*; | |
#[link(name="glfw3")] | |
#[link(name="opengl32")] | |
#[link(name="gdi32")] | |
extern {} | |
#[start] | |
fn start(argc: int, argv: **u8) -> int | |
{ | |
std::rt::start_on_main_thread(argc, argv, main) | |
} | |
type VertexAttrib = (GLuint, GLint, GLenum, bool, uint, uint); | |
struct Vao | |
{ | |
handle: GLuint, | |
nelems: uint | |
} | |
impl Vao | |
{ | |
fn new(vbo: Vbo, ebo: Ebo, attribs: ~[VertexAttrib]) -> Vao | |
{ | |
let mut handle: GLuint = 0; | |
unsafe { gl::GenVertexArrays(1, &mut handle) }; | |
gl::BindVertexArray(handle); | |
vbo.bind(); | |
ebo.bind(); | |
for attrib in attribs.iter() | |
{ | |
gl::EnableVertexAttribArray(attrib.n0()); | |
unsafe | |
{ | |
gl::VertexAttribPointer( | |
attrib.n0(), | |
attrib.n1(), | |
attrib.n2(), | |
if attrib.n3() { gl::TRUE } else { gl::FALSE }, | |
attrib.n4() as GLsizei, | |
attrib.n5() as *c_void) | |
}; | |
} | |
let ret: Vao = Vao { handle: handle, nelems: ebo.num_elements() }; | |
gl::BindVertexArray(0); | |
ret | |
} | |
fn delete(&mut self) | |
{ | |
unsafe { gl::DeleteVertexArrays(1, &self.handle) }; | |
self.handle = 0; | |
} | |
fn bind(&self) | |
{ | |
gl::BindVertexArray(self.handle); | |
} | |
fn draw(&self) | |
{ | |
self.bind(); | |
unsafe { gl::DrawElements(gl::TRIANGLES, self.nelems as GLint, gl::UNSIGNED_INT, 0 as *GLvoid) }; | |
} | |
} | |
struct Vbo | |
{ | |
handle: GLuint | |
} | |
impl Vbo | |
{ | |
fn new<T>(vertices: ~[T]) -> Vbo | |
{ | |
let mut ret: GLuint = 0; | |
unsafe { gl::GenBuffers(1, &mut ret) }; | |
gl::BindBuffer(gl::ARRAY_BUFFER, ret); | |
let size = (vertices.len() * size_of::<T>()) as i32; | |
let ptr = raw::to_ptr(vertices) as *c_void; | |
unsafe { gl::BufferData(gl::ARRAY_BUFFER, size, ptr, gl::STATIC_DRAW) }; | |
Vbo { handle: ret } | |
} | |
fn delete(&mut self) | |
{ | |
unsafe { gl::DeleteBuffers(1, &self.handle) }; | |
self.handle = 0; | |
} | |
fn bind(&self) | |
{ | |
gl::BindBuffer(gl::ARRAY_BUFFER, self.handle); | |
} | |
} | |
struct Ebo | |
{ | |
handle: GLuint | |
} | |
impl Ebo | |
{ | |
fn new(elements: ~[u32]) -> Ebo | |
{ | |
let mut ret: GLuint = 0; | |
unsafe { gl::GenBuffers(1, &mut ret) }; | |
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ret); | |
let size = (elements.len() * size_of::<u32>()) as i32; | |
let ptr = raw::to_ptr(elements) as *c_void; | |
unsafe { gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, size, ptr, gl::STATIC_DRAW) }; | |
Ebo { handle: ret } | |
} | |
fn delete(&mut self) | |
{ | |
unsafe { gl::DeleteBuffers(1, &self.handle) }; | |
self.handle = 0; | |
} | |
fn bind(&self) | |
{ | |
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.handle); | |
} | |
fn num_elements(&self) -> uint | |
{ | |
self.bind(); | |
let mut size: GLint = 0; | |
unsafe { gl::GetBufferParameteriv(gl::ELEMENT_ARRAY_BUFFER, gl::BUFFER_SIZE, &mut size) }; | |
size as uint | |
} | |
} | |
struct Mesh | |
{ | |
vao: Vao, | |
vbo: Vbo, | |
ebo: Ebo | |
} | |
impl Mesh | |
{ | |
fn new<V>(vertices: ~[V], indices: ~[u32], attrs: ~[VertexAttrib]) -> Mesh | |
{ | |
let vbo = Vbo::new(vertices); | |
let ebo = Ebo::new(indices); | |
let vao = Vao::new(vbo, ebo, attrs); | |
Mesh | |
{ | |
vbo: vbo, | |
ebo: ebo, | |
vao: vao | |
} | |
} | |
fn draw(&self) | |
{ | |
self.vao.draw(); | |
} | |
} | |
impl Drop for Mesh | |
{ | |
fn drop(&mut self) | |
{ | |
self.vao.delete(); | |
self.vbo.delete(); | |
self.ebo.delete(); | |
} | |
} | |
fn compile_shader(source: &str, kind: GLuint) -> GLuint | |
{ | |
let ret = gl::CreateShader(kind); | |
let tmp = unsafe { source.to_c_str().unwrap() }; | |
unsafe { gl::ShaderSource(ret, 1, &tmp, null()) }; | |
gl::CompileShader(ret); | |
let mut status: GLint = 0; | |
unsafe { gl::GetShaderiv(ret, gl::COMPILE_STATUS, &mut status); } | |
if status == gl::FALSE as i32 | |
{ | |
let mut len: GLsizei = 0; | |
let mut msg = [0 as GLchar, ..512]; | |
unsafe { gl::GetShaderInfoLog(ret, msg.len() as i32, &mut len, raw::to_mut_ptr(msg)); } | |
let msgStr = unsafe { CString::new(raw::to_ptr(msg), false) }; | |
println!("Error compiling shader: {}", msgStr.as_str()); | |
} | |
ret | |
} | |
struct VertShader | |
{ | |
handle: GLuint | |
} | |
impl VertShader | |
{ | |
fn new(source: &str) -> VertShader | |
{ | |
VertShader { handle: compile_shader(source, gl::VERTEX_SHADER) } | |
} | |
fn delete(&mut self) | |
{ | |
gl::DeleteShader(self.handle); | |
self.handle = 0; | |
} | |
} | |
struct FragShader | |
{ | |
handle: GLuint | |
} | |
impl FragShader | |
{ | |
fn new(source: &str) -> FragShader | |
{ | |
FragShader { handle: compile_shader(source, gl::FRAGMENT_SHADER) } | |
} | |
fn delete(&mut self) | |
{ | |
gl::DeleteShader(self.handle); | |
self.handle = 0; | |
} | |
} | |
struct Program | |
{ | |
handle: GLuint, | |
vs: VertShader, | |
fs: FragShader | |
} | |
impl Program | |
{ | |
fn new(vs: VertShader, fs: FragShader, data: ~[(&str, GLuint)]) -> Program | |
{ | |
let ret = Program | |
{ | |
vs: vs, | |
fs: fs, | |
handle: gl::CreateProgram() | |
}; | |
gl::AttachShader(ret.handle, ret.vs.handle); | |
gl::AttachShader(ret.handle, ret.fs.handle); | |
for &(name, loc) in data.iter() | |
{ | |
unsafe { gl::BindFragDataLocation(ret.handle, loc, name.to_c_str().unwrap()) }; | |
} | |
gl::LinkProgram(ret.handle); | |
gl::UseProgram(ret.handle); | |
ret | |
} | |
fn delete(&mut self) | |
{ | |
gl::DeleteProgram(self.handle); | |
self.handle = 0; | |
} | |
fn get_uniform_location(&self, name: &str) -> GLint | |
{ | |
unsafe { gl::GetUniformLocation(self.handle, name.to_c_str().unwrap()) } | |
} | |
fn get_attrib_location(&self, name: &str) -> GLuint | |
{ | |
unsafe { gl::GetAttribLocation(self.handle, name.to_c_str().unwrap()) as GLuint } | |
} | |
fn bind(&self) | |
{ | |
gl::UseProgram(self.handle); | |
} | |
} | |
static vertexSource: &'static str = | |
"#version 150 core | |
in vec2 position; | |
uniform mat4 model, view, proj; | |
void main() | |
{ | |
gl_Position = proj * view * model * vec4(position, 0.0, 1.0); | |
}"; | |
static fragmentSource: &'static str = | |
"#version 150 core | |
uniform vec3 triangleColor; | |
out vec4 outColor; | |
void main() { | |
outColor = vec4(triangleColor, 1.0); | |
}"; | |
static fbVertexSource: &'static str = | |
"#version 150 core | |
in vec2 position; | |
in vec2 texCoord; | |
uniform vec2 shakePos; | |
// uniform float time; | |
out vec2 TexCoord; | |
// const float WiggleMag = 0.02; | |
void main() | |
{ | |
TexCoord = texCoord; | |
gl_Position = vec4(shakePos + position, 0.0, 1.0); | |
// float angle = (texCoord.x + texCoord.y + time) * 30; | |
// vec2 wiggle = vec2(sin(angle) * WiggleMag, cos(angle) * WiggleMag); | |
// TexCoord = texCoord + wiggle; | |
// gl_Position = vec4(position + shakePos + wiggle, 0.0, 1.0); | |
}"; | |
static fbFragmentSource: &'static str = | |
"#version 150 core | |
in vec2 TexCoord; | |
out vec4 outColor; | |
uniform sampler2D frameBuffer; | |
uniform float time; | |
// const float blurSizeH = 1.0 / 300.0; | |
// const float blurSizeV = 1.0 / 200.0; | |
// void main() { | |
// vec4 sum = vec4(0.0); | |
// for (int x = -4; x <= 4; x++) | |
// for (int y = -4; y <= 4; y++) | |
// sum += texture( | |
// frameBuffer, | |
// vec2(TexCoord.x + x * blurSizeH, TexCoord.y + y * blurSizeV) | |
// ) / 81.0; | |
// outColor = sum; | |
// } | |
const float WiggleMag = 0.01; | |
void main() | |
{ | |
float angle = ((TexCoord.x - TexCoord.y) + time) * 60; | |
vec2 wiggle = vec2(sin(angle) * WiggleMag, cos(angle) * WiggleMag); | |
outColor = texture(frameBuffer, TexCoord + wiggle); | |
// outColor = texture(frameBuffer, TexCoord); | |
}"; | |
fn makeScreenQuad(xdiv: uint, ydiv: uint) -> (Vbo, Ebo) | |
{ | |
assert!(xdiv >= 1 && ydiv >= 1, "nooope"); | |
let mut verts = vec::with_capacity::<f32>(4 * (xdiv + 1) * (ydiv + 1)); | |
for yi in range_inclusive(0, ydiv) | |
{ | |
for xi in range_inclusive(0, xdiv) | |
{ | |
let x = ((2. * xi as f32) / (xdiv as f32)) - 1.; | |
let y = 1. - ((2. * yi as f32) / (ydiv as f32)); | |
let u = (xi as f32) / (xdiv as f32); | |
let v = 1. - ((yi as f32) / (ydiv as f32)); | |
verts.push(x); | |
verts.push(y); | |
verts.push(u); | |
verts.push(v); | |
} | |
} | |
let mut indices = vec::with_capacity::<u32>((xdiv + 1) * (ydiv + 1)); | |
let stride = (xdiv + 1) as u32; | |
for yi in range(0, ydiv as u32) | |
{ | |
for xi in range(0, xdiv as u32) | |
{ | |
let a = ((yi * stride) + xi) as u32; | |
let b = (a + 1) as u32; | |
let c = (b + stride) as u32; | |
let d = (c - 1) as u32; | |
indices.push(a); indices.push(b); indices.push(c); | |
indices.push(c); indices.push(d); indices.push(a); | |
} | |
} | |
(Vbo::new(verts), Ebo::new(indices)) | |
} | |
static ShakeTime: f32 = 0.8f32; | |
static ShakeMagnitude: f32 = 0.1f32; | |
fn main() | |
{ | |
glfw::set_error_callback(~ErrorContext); | |
do glfw::start | |
{ | |
let window = glfw::Window::create(800, 600, "Hello yes this is dog", glfw::Windowed).expect("Failed to create GLFW window."); | |
window.make_context_current(); | |
gl::load_with(glfw::get_proc_address); | |
// Shaders | |
let mut vertexShader = VertShader::new(vertexSource); | |
let mut fragmentShader = FragShader::new(fragmentSource); | |
let mut shaderProgram = Program::new(vertexShader, fragmentShader, ~[("outColor", 0)]); | |
let posAttrib = shaderProgram.get_attrib_location("position"); | |
let uniColor = shaderProgram.get_uniform_location("triangleColor"); | |
let modelMat = shaderProgram.get_uniform_location("model"); | |
let viewMat = shaderProgram.get_uniform_location("view"); | |
let projMat = shaderProgram.get_uniform_location("proj"); | |
// View/proj matrices | |
let view: Mat4<f32> = Mat4::look_at( | |
&Point3::new(0f32, 1.2f32, 1.2f32), | |
&Point3::new(0.0f32, 0.0f32, 0.0f32), | |
&Vec3::new(0.0f32, 0.0f32, 1.0f32) | |
); | |
unsafe { gl::UniformMatrix4fv(viewMat, 1, gl::FALSE, view.ptr()) }; | |
let proj: Mat4<f32> = perspective(deg(45.0f32), 800.0f32 / 600.0f32, 1.0f32, 10.0f32); | |
unsafe { gl::UniformMatrix4fv(projMat, 1, gl::FALSE, proj.ptr()) }; | |
// Triangle | |
let triMesh = Mesh::new | |
( | |
~[ | |
0.0f32, 0.5f32, | |
0.5f32, -0.5f32, | |
-0.5f32, -0.5f32 | |
], | |
~[0, 1, 2], | |
~[(posAttrib, 2, gl::FLOAT, false, 0, 0)] | |
); | |
// VAO2 | |
let rectMesh = Mesh::new | |
( | |
~[ | |
-0.5f32, 1f32, | |
0.5f32, 1f32, | |
0.5f32, 0.5f32, | |
-0.5f32, 0.5f32, | |
], | |
~[0, 1, 2, 2, 3, 0], | |
~[(posAttrib, 2, gl::FLOAT, false, 0, 0)] | |
); | |
// Framebuffer shaders | |
let mut fbVertexShader = VertShader::new(fbVertexSource); | |
let mut fbFragmentShader = FragShader::new(fbFragmentSource); | |
let mut fbShaderProgram = Program::new(fbVertexShader, fbFragmentShader, ~[("outColor", 0)]); | |
let fbPosAttrib = fbShaderProgram.get_attrib_location("position"); | |
let fbTexCoordAttrib = fbShaderProgram.get_attrib_location("texCoord"); | |
let frameBufferSampler = fbShaderProgram.get_attrib_location("frameBuffer"); | |
let fbShakePos = fbShaderProgram.get_uniform_location("shakePos"); | |
let fbTime = fbShaderProgram.get_uniform_location("time"); | |
gl::Uniform1i(frameBufferSampler as i32, 0); | |
// Framebuffer VAO | |
let (mut fbvbo, mut fbebo) = makeScreenQuad(16, 12); | |
let mut fbvao = Vao::new(fbvbo, fbebo, ~[ | |
(fbPosAttrib, 2, gl::FLOAT, false, 4 * size_of::<GLfloat>(), 0), | |
(fbTexCoordAttrib, 2, gl::FLOAT, false, 4 * size_of::<GLfloat>(), 2 * size_of::<GLfloat>()) | |
]); | |
// Framebuffer render target | |
let mut fb: GLuint = 0; | |
unsafe { gl::GenFramebuffers(1, &mut fb); } | |
gl::BindFramebuffer(gl::FRAMEBUFFER, fb); | |
let mut fbColorBuffer: GLuint = 0; | |
unsafe { gl::GenTextures(1, &mut fbColorBuffer); } | |
gl::BindTexture(gl::TEXTURE_2D, fbColorBuffer); | |
unsafe { gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as i32, 800, 600, 0, gl::RGB, gl::UNSIGNED_BYTE, null()); } | |
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); | |
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); | |
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32); | |
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32); | |
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, fbColorBuffer, 0); | |
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); | |
let mut shakeTimer = 0f32; | |
let mut prevTime = glfw::get_time(); | |
let mut wireframe = false; | |
while !window.should_close() | |
{ | |
let time = glfw::get_time(); | |
let dt = time - prevTime; | |
prevTime = time; | |
gl::BindFramebuffer(gl::FRAMEBUFFER, fb); | |
gl::ClearColor(0.2, 0.2, 0.2, 1.); | |
gl::Clear(gl::COLOR_BUFFER_BIT); | |
shaderProgram.bind(); | |
let mut model: Mat4<f32> = Mat3::from_angle_z(deg(time as f32 * 30.).to_rad()).to_mat4(); | |
unsafe { gl::UniformMatrix4fv(modelMat, 1, gl::FALSE, model.ptr()) }; | |
gl::Uniform3f(uniColor, 1., 0., 0.); | |
triMesh.draw(); | |
model = Mat3::from_angle_z(deg(-time as f32 * 30.).to_rad()).to_mat4(); | |
unsafe { gl::UniformMatrix4fv(modelMat, 1, gl::FALSE, model.ptr()) }; | |
gl::Uniform3f(uniColor, 0., 1., 0.); | |
rectMesh.draw(); | |
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); | |
gl::ClearColor(0., 0., 0., 1.); | |
gl::Clear(gl::COLOR_BUFFER_BIT); | |
fbShaderProgram.bind(); | |
let shakePos = if shakeTimer > 0. | |
{ | |
let mag = shakeTimer / ShakeTime; | |
let xmag = mag * ((*random::<Closed01<f32>>() * 2. * ShakeMagnitude) - ShakeMagnitude); | |
let ymag = mag * ((*random::<Closed01<f32>>() * 2. * ShakeMagnitude) - ShakeMagnitude); | |
shakeTimer -= dt as f32; | |
Vec2::new(xmag, ymag) | |
} | |
else | |
{ | |
Vec2::new(0f32, 0f32) | |
}; | |
gl::Uniform2f(fbShakePos, shakePos.x, shakePos.y); | |
gl::Uniform1f(fbTime, (time / 2.) as f32); | |
gl::ActiveTexture(gl::TEXTURE0); | |
gl::BindTexture(gl::TEXTURE_2D, fbColorBuffer); | |
if wireframe { gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE); } | |
fbvao.draw(); | |
if wireframe { gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL); } | |
window.swap_buffers(); | |
glfw::poll_events(); | |
if window.get_key(glfw::KeyEscape) == glfw::Press | |
{ window.set_should_close(true); } | |
else if window.get_key(glfw::KeySpace) == glfw::Press && shakeTimer <= 0. | |
{ shakeTimer = ShakeTime; } | |
else if window.get_key(glfw::KeyW) == glfw::Press | |
{ wireframe = !wireframe; } | |
} | |
fbShaderProgram.delete(); | |
fbVertexShader.delete(); | |
fbFragmentShader.delete(); | |
shaderProgram.delete(); | |
fragmentShader.delete(); | |
vertexShader.delete(); | |
fbvbo.delete(); | |
fbebo.delete(); | |
fbvao.delete(); | |
unsafe { gl::DeleteTextures(1, &fbColorBuffer); } | |
unsafe { gl::DeleteFramebuffers(1, &fb); } | |
} | |
} | |
struct ErrorContext; | |
impl glfw::ErrorCallback for ErrorContext | |
{ | |
fn call(&self, _: glfw::Error, description: ~str) | |
{ | |
println!("GLFW Error: {:s}", description); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment