use std::convert::TryInto; use std::ffi::{CStr, CString}; pub struct ShaderObject { id: u32, } impl ShaderObject { pub fn id (&self) -> u32 { self.id } pub fn from_source (shader_type: u32, source: &[u8]) -> Result { let id = unsafe { gl::CreateShader (shader_type) }; let sources = [ source.as_ptr () as *const i8, ]; let lengths = [ source.len ().try_into ().unwrap (), ]; let success = unsafe { gl::ShaderSource (id, sources.len ().try_into ().unwrap (), sources.as_ptr (), lengths.as_ptr ()); gl::CompileShader (id); let mut success = 0; gl::GetShaderiv (id, gl::COMPILE_STATUS, &mut success); success == 1 }; if success { Ok (ShaderObject { id, }) } else { let mut info_log = vec! [0u8; 4096]; let mut log_length = 0; unsafe { gl::GetShaderInfoLog (id, (info_log.len () - 1).try_into ().unwrap (), &mut log_length, info_log.as_mut_ptr () as *mut i8); } info_log.truncate (log_length.try_into ().unwrap ()); let info = String::from_utf8 (info_log).unwrap (); Err (info) } } pub fn from_file

(shader_type: u32, filename: P) -> Result where P: AsRef { let src = crate::file::load_small_file (filename, 1024 * 1024).unwrap (); Self::from_source (shader_type, &src) } } impl Drop for ShaderObject { fn drop (&mut self) { unsafe { gl::DeleteShader (self.id); } } } #[derive (PartialEq, Eq)] pub struct ShaderProgram { id: u32, } impl ShaderProgram { pub fn new (vert: &ShaderObject, frag: &ShaderObject) -> Result { let id = unsafe { gl::CreateProgram () }; unsafe { gl::AttachShader (id, vert.id ()); gl::AttachShader (id, frag.id ()); gl::LinkProgram (id); } let success = unsafe { let mut success = 0; gl::GetProgramiv (id, gl::LINK_STATUS, &mut success); success == 1 }; if success { Ok (ShaderProgram { id, }) } else { let mut info_log = vec! [0u8; 4096]; let mut log_length = 0; unsafe { gl::GetProgramInfoLog (id, (info_log.len () - 1).try_into ().unwrap (), &mut log_length, info_log.as_mut_ptr () as *mut i8); } info_log.truncate (log_length.try_into ().unwrap ()); let info = String::from_utf8 (info_log).unwrap (); Err (info) } } pub fn get_id (&self) -> u32 { self.id } // 'use' is a keyword pub fn use_program (&self) { unsafe { gl::UseProgram (self.id); } } pub fn get_uniform_location (&self, name: &CStr) -> i32 { self.use_program (); unsafe { gl::GetUniformLocation (self.id, name.as_ptr ()) } } pub fn get_uniform_locations <'a, I> (&self, names: I) -> Vec where I: Iterator { self.use_program (); names .map (|name| { let c_str = CString::new (name.as_bytes ()).unwrap (); let loc = unsafe { gl::GetUniformLocation (self.id, c_str.as_ptr ()) }; loc }) .collect () } pub fn get_attribute_location (&self, name: &CStr) -> i32 { self.use_program (); unsafe { gl::GetAttribLocation (self.id, name.as_ptr ()) } } // This could be an iterator adapter but the code is too long // and it's only called during startup so I don't care. pub fn get_attribute_locations <'a, I> (&self, names: I) -> Vec

(vert: P, frag: P) -> ShaderProgram where P: AsRef { let vert_shader = ShaderObject::from_file (gl::VERTEX_SHADER, vert).unwrap (); let frag_shader = ShaderObject::from_file (gl::FRAGMENT_SHADER, frag).unwrap (); ShaderProgram::new (&vert_shader, &frag_shader).unwrap () }