use std::{
ffi::CString
};
#[derive(Debug)]
pub enum ShaderType {
Vertex,
Fragment,
}
pub struct Shader {
pub (crate) id: u32,
pub typ: (ShaderType, gl::types::GLenum)
}
impl Shader {
pub fn load(shader_str: &str, shader_type: ShaderType) -> Result<Self, String> {
let shader_type = match shader_type {
ShaderType::Vertex => { (ShaderType::Vertex, gl::VERTEX_SHADER) }
ShaderType::Fragment => { (ShaderType::Fragment, gl::FRAGMENT_SHADER) }
};
let shader_str = std::ffi::CString::new(shader_str).unwrap();
let shader: u32 = unsafe { gl::CreateShader(shader_type.1) };
unsafe {
gl::ShaderSource(shader.clone(), 1, &shader_str.as_ptr(), std::ptr::null_mut());
gl::CompileShader(shader.clone());
}
let res = check_compilation(&shader);
if let Err(msg) = res {
eprint!("Failed to compile shader: {:?}", msg);
return Err(msg);
}
return Ok(Self { id: shader, typ: shader_type });
}
}
impl Drop for Shader {
fn drop(&mut self) {
unsafe { gl::DeleteShader(self.id); }
}
}
fn check_compilation(shader: &u32) -> Result<(), String> {
let mut success: i32 = 0;
unsafe { gl::GetShaderiv(*shader, gl::COMPILE_STATUS, &mut success) };
let mut len: gl::types::GLint = 0;
unsafe { gl::GetShaderiv(*shader, gl::INFO_LOG_LENGTH, &mut len); }
let buffer: Vec<u8> = Vec::with_capacity(len as usize + 1);
let log: CString = unsafe { CString::from_vec_unchecked(buffer) };
if success == 0 {
unsafe {
gl::GetShaderInfoLog(*shader, len, std::ptr::null_mut(), log.as_ptr() as *mut gl::types::GLchar);
}
let log = log.to_str().unwrap();
return Err(String::from(log));
}
return Ok(());
}