mod gl {
pub use gl::types::*;
pub use gl::*;
}
use errors::Error;
use std::{ffi,mem,ptr};
//
pub struct Window {
events: glutin::event_loop::EventLoop<()>,
gl_window: glutin::WindowedContext<glutin::PossiblyCurrent>,
}
impl Window {
pub fn create() -> Result<Window, Error> {
let events = glutin::event_loop::EventLoop::new();
let wb = glutin::window::WindowBuilder::new();
let context = glutin::ContextBuilder::new();
let gl_window = context.build_windowed(wb, &events)?;
let gl_window = unsafe { gl_window.make_current() }.unwrap();
gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);
Ok(Window { events, gl_window })
}
pub fn run<F: 'static>(self, mut cb: F) -> Result<(), Error>
where F: for<'a> FnMut(glutin::event::Event<'a, ()>) -> glutin::event_loop::ControlFlow
{
let Window { mut events, gl_window } = self;
let mut result = Ok(());
events.run(move |ev, _, tgt| {
let r = cb(ev);
match gl_window.swap_buffers() {
Ok(()) => *tgt = r,
Err(ctx) => {
result = Err(Error::GlutinContext(ctx));
*tgt = glutin::event_loop::ControlFlow::Exit
}
}
})
}
}
pub struct Shader {
pub n: gl::GLuint,
}
impl Drop for Shader {
fn drop(&mut self) {
unsafe { gl::DeleteShader(self.n); }
}
}
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum ShaderType {
Fragment,
Vertex,
}
impl ShaderType {
fn to_glenum(&self) -> gl::GLenum {
match *self {
ShaderType::Fragment => gl::FRAGMENT_SHADER,
ShaderType::Vertex => gl::VERTEX_SHADER,
}
}
}
impl Shader {
pub fn compile(ty: ShaderType, src: &str) -> Result<Shader, Error> {
let shader;
unsafe {
shader = gl::CreateShader(ty.to_glenum());
let c_str = ffi::CString::new(src.as_bytes())?;
gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
gl::CompileShader(shader);
let mut status = gl::FALSE as gl::GLint;
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
if status != (gl::TRUE as gl::GLint) {
let mut len = 0;
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
let mut buf = Vec::with_capacity(len as usize);
buf.set_len((len as usize) - 1);
gl::GetShaderInfoLog(
shader,
len,
ptr::null_mut(),
buf.as_mut_ptr() as *mut gl::GLchar
);
return Err(Error::CompileError(String::from_utf8(buf)?));
}
}
Ok(Shader { n: shader })
}
}
//
pub struct Program {
pub p: gl::GLuint,
pub shaders: Vec<Shader>,
}
impl Drop for Program {
fn drop(&mut self) {
self.shaders = vec![];
unsafe {
gl::DeleteProgram(self.p)
}
}
}
impl Program {
pub fn link(shaders: Vec<Shader>) -> Result<Program, Error> {
unsafe {
let program = gl::CreateProgram();
for s in shaders.iter() {
gl::AttachShader(program, s.n);
}
gl::LinkProgram(program);
let mut status = gl::FALSE as gl::GLint;
gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
// Fail on error
if status != (gl::TRUE as gl::GLint) {
let mut len: gl::GLint = 0;
gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
let mut buf = Vec::with_capacity(len as usize);
buf.set_len((len as usize) - 1);
gl::GetProgramInfoLog(
program,
len,
ptr::null_mut(),
buf.as_mut_ptr() as *mut gl::GLchar,
);
return Err(Error::LinkError(String::from_utf8(buf)?));
}
Ok(Program {
p: program,
shaders: shaders,
})
}
}
pub fn use_program(&self) {
unsafe { gl::UseProgram(self.p); }
}
pub fn bind_frag_data_location(&self, idx: u32, s: &str) -> Result<(), Error> {
unsafe {
gl::BindFragDataLocation(
self.p,
idx,
ffi::CString::new(s)?.as_ptr(),
);
}
Ok(())
}
pub fn get_attrib_location(&self, s: &str) -> Result<i32, Error> {
Ok(unsafe {
gl::GetAttribLocation(
self.p,
ffi::CString::new(s)?.as_ptr(),
)
})
}
}
//
pub struct VertexArray {
idx: u32,
}
impl Drop for VertexArray {
fn drop(&mut self) {
unsafe { gl::DeleteVertexArrays(1, &self.idx); }
}
}
pub struct VertexBuffer {
idx: u32,
data: VertexArray,
}
impl Drop for VertexBuffer {
fn drop(&mut self) {
unsafe { gl::DeleteBuffers(1, &self.idx); }
}
}
impl VertexArray {
pub fn new() -> VertexArray {
let mut idx = 0;
unsafe {
gl::GenVertexArrays(1, &mut idx);
gl::BindVertexArray(idx);
}
VertexArray { idx }
}
pub fn bind(&self) {
unsafe {
gl::BindVertexArray(self.idx);
}
}
pub fn unbind(&self) {
unsafe {
gl::BindVertexArray(0);
}
}
}
impl VertexBuffer {
pub fn new_array_buffer(
data: VertexArray,
vertex_data: &[gl::GLfloat],
) -> VertexBuffer {
let mut idx = 0;
unsafe {
gl::GenBuffers(1, &mut idx);
gl::BindBuffer(gl::ARRAY_BUFFER, idx);
gl::BufferData(
gl::ARRAY_BUFFER,
(vertex_data.len() * mem::size_of::<gl::GLfloat>()) as gl::GLsizeiptr,
mem::transmute(&vertex_data[0]),
gl::STATIC_DRAW,
);
}
VertexBuffer { idx, data }
}
pub fn bind(&self) {
unsafe {
self.data.bind();
gl::BindBuffer(gl::ARRAY_BUFFER, self.idx);
}
}
pub fn unbind(&self) {
unsafe {
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
self.data.unbind();
}
}
}