use std::collections::*; 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 new (shader_type: u32, source: &str) -> 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) } } } impl Drop for ShaderObject { fn drop (&mut self) { unsafe { gl::DeleteShader (self.id); } } } 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_uniform_location (&self, name: &CStr) -> i32 { unsafe { gl::UseProgram (self.id); gl::GetUniformLocation (self.id, name.as_ptr ()) } } pub fn get_uniform_locations <'a, I> (&self, names: I) -> HashMap where I: Iterator { unsafe { gl::UseProgram (self.id); } names .map (|name| { let mut s = String::from ("uni_"); s.push_str (name); let c_str = CString::new (s.as_bytes ()).unwrap (); let loc = unsafe { gl::GetUniformLocation (self.id, c_str.as_ptr ()) }; (String::from (name), loc) }) .collect () } pub fn get_attribute_location (&self, name: &CStr) -> i32 { unsafe { gl::UseProgram (self.id); gl::GetAttribLocation (self.id, name.as_ptr ()) } } pub fn get_attribute_locations <'a, I> (&self, names: I) -> HashMap > where I: Iterator { unsafe { gl::UseProgram (self.id); } names .map (|name| { let mut s = String::from ("attr_"); s.push_str (name); let c_str = CString::new (s.as_bytes ()).unwrap (); let loc = unsafe { gl::GetAttribLocation (self.id, c_str.as_ptr ()) }; let loc = match loc.try_into () { Ok (loc) => Some (loc), _ => None, }; (String::from (name), loc) }) .collect () } } impl Drop for ShaderProgram { fn drop (&mut self) { unsafe { gl::DeleteProgram (self.id); } } }