use std::string::String;
use crate::draw::gl;
pub struct Shader {
vertex_shader: gl::types::GLuint,
fragment_shader: gl::types::GLuint,
program: gl::types::GLuint
}
fn compile_shader(source: &[u8], type_: u32) -> Result<u32, String> {
unsafe {
gl_check!(let shader = gl::CreateShader(type_));
gl_check!(gl::ShaderSource(
shader,
1,
[source.as_ptr() as *const _].as_ptr(),
std::ptr::null(),
));
gl_check!(gl::CompileShader(shader));
let mut success = 0;
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success);
if success == gl::FALSE as _ {
let mut length: i32 = 0;
let mut info_log: [u8; 1024] = [0; 1024];
gl::GetShaderInfoLog(shader,
1024,
&mut length,
info_log.as_mut_ptr() as *mut _
);
assert_ne!(length, 0);
Err(String::from_utf8_unchecked(info_log.split_at(length as usize).0.to_vec()))
}
else {
Ok(shader)
}
}
}
fn make_program(shaders: Vec<u32>) -> Result<u32, String> {
unsafe {
gl_check!(let program = gl::CreateProgram());
for shader in shaders.iter() {
gl_check!(gl::AttachShader(program, *shader));
}
gl_check!(gl::LinkProgram(program));
let mut success = 0;
gl_check!(gl::GetProgramiv(program, gl::LINK_STATUS, &mut success));
if success == gl::FALSE as _ {
let mut length: i32 = 0;
let mut info_log: [u8; 1024] = [0; 1024];
gl_check!(gl::GetProgramInfoLog(program,
1024,
&mut length,
info_log.as_mut_ptr() as *mut _
));
assert_ne!(length, 0);
Err(String::from_utf8_unchecked(info_log.split_at(length as usize).0.to_vec()))
}
else {
Ok(program)
}
}
}
impl Shader {
pub fn new(vertex_shader_src: &[u8], fragment_shader_src: &[u8]) -> Shader {
let vertex_shader = compile_shader(vertex_shader_src, gl::VERTEX_SHADER)
.expect("Failed to compile the vertex shader");
let fragment_shader = compile_shader(fragment_shader_src, gl::FRAGMENT_SHADER)
.expect("Failed to compile the fragment shader");
let program = make_program(vec![vertex_shader, fragment_shader])
.expect("Failed to make the shader program");
Shader {
vertex_shader: vertex_shader,
fragment_shader: fragment_shader,
program: program
}
}
pub fn bind(&self) {
unsafe {
gl::UseProgram(self.program);
}
}
}