gdritter repos outlander / master src / graphics.rs
master

Tree @master (Download .tar.gz)

graphics.rs @master

3a60013
 
 
 
0bab597
 
497535d
 
 
 
63e8bb0
 
497535d
 
 
0bab597
63e8bb0
 
497535d
63e8bb0
497535d
63e8bb0
497535d
 
 
 
 
 
63e8bb0
 
497535d
 
 
 
63e8bb0
497535d
 
 
63e8bb0
497535d
0bab597
63e8bb0
497535d
 
63e8bb0
3a60013
 
 
 
 
 
 
 
 
497535d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0bab597
497535d
3a60013
497535d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0bab597
497535d
3a60013
497535d
3a60013
 
 
497535d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0bab597
497535d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0bab597
497535d
 
 
 
 
 
 
 
 
 
 
 
 
0bab597
497535d
 
 
 
0bab597
3a60013
 
497535d
 
 
0bab597
497535d
 
 
0bab597
497535d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0bab597
497535d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0bab597
 
 
 
 
 
 
 
 
 
 
 
497535d
 
 
0bab597
 
 
 
497535d
 
 
 
 
 
 
 
 
 
 
 
0bab597
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3a60013
 
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();
        }
    }
}