use std::ffi::{CStr, CString};
pub struct Shader {
id: gl::types::GLuint,
}
impl Shader {
pub fn from_source(source: &CStr, kind: gl::types::GLenum) -> Result<Shader, String> {
let id = shader_from_source(source, kind)?;
Ok(Shader { id })
}
pub fn from_vert_str(src: &str) -> Result<Shader, String> {
Shader::from_source(&CString::new(src).unwrap(), gl::VERTEX_SHADER)
}
pub fn from_frag_str(src: &str) -> Result<Shader, String> {
Shader::from_source(&CString::new(src).unwrap(), gl::FRAGMENT_SHADER)
}
pub fn id(&self) -> gl::types::GLuint {
self.id
}
}
impl Drop for Shader {
fn drop(&mut self) {
unsafe {
gl::DeleteShader(self.id);
}
}
}
fn shader_from_source(source: &CStr, kind: gl::types::GLenum) -> Result<gl::types::GLuint, String> {
let id = unsafe { gl::CreateShader(kind) };
unsafe {
gl::ShaderSource(id, 1, &source.as_ptr(), std::ptr::null());
gl::CompileShader(id);
}
let mut success: gl::types::GLint = gl::FALSE as gl::types::GLint;
unsafe {
gl::GetShaderiv(id, gl::COMPILE_STATUS, &mut success);
}
if success != (gl::TRUE as gl::types::GLint) {
let mut len: gl::types::GLint = 0;
unsafe {
gl::GetShaderiv(id, gl::INFO_LOG_LENGTH, &mut len);
}
let error = crate::utils::ffi_utils::create_whitespace_cstring_with_len(len as usize);
unsafe {
gl::GetShaderInfoLog(
id,
len,
std::ptr::null_mut(),
error.as_ptr() as *mut gl::types::GLchar,
);
}
return Err(error.to_string_lossy().into_owned());
}
Ok(id)
}