use std::ffi::CString;
use std::fs::File;
use std::io::Read;
use std::ptr;
use std::str;
use gl;
pub enum ShaderValue {
Bool(bool),
Int(i32),
Float(f32),
Vec3(glm::Vec3),
Mat4(glm::Mat4),
}
pub fn compile(vertex_path: &str, fragment_path: &str) -> u32 {
let vertex_shader_code = open_code_file(vertex_path);
let fragment_shader_code = open_code_file(fragment_path);
unsafe {
let vertex = compile_source(gl::VERTEX_SHADER, vertex_shader_code, "VERTEX");
let fragment = compile_source(gl::FRAGMENT_SHADER, fragment_shader_code, "FRAGMENT");
let id = generate_program_id(&vertex, &fragment);
gl::DeleteShader(vertex);
gl::DeleteShader(fragment);
return id;
}
}
pub unsafe fn delete_shader_program(shader_id: u32) {
gl::DeleteProgram(shader_id);
}
pub unsafe fn generate_program_id(vertex: &u32, fragment: &u32) -> u32 {
let id = gl::CreateProgram();
gl::AttachShader(id, *vertex);
gl::AttachShader(id, *fragment);
gl::LinkProgram(id);
check_compile_errors(id, "PROGRAM");
return id;
}
pub unsafe fn compile_source(shader_type: u32, shader_code: CString, shader_name: &str) -> u32 {
let shader_id = gl::CreateShader(shader_type);
gl::ShaderSource(shader_id, 1, &shader_code.as_ptr(), ptr::null());
gl::CompileShader(shader_id);
check_compile_errors(shader_id, shader_name);
return shader_id;
}
pub fn open_code_file(shader_path: &str) -> CString {
let mut shader_file =
File::open(shader_path).unwrap_or_else(|_| panic!("Failed to open file {}", shader_path));
let mut shader_code = String::new();
shader_file
.read_to_string(&mut shader_code)
.expect("Failed to read shader");
return CString::new(shader_code.as_bytes()).unwrap();
}
pub unsafe fn use_program(shader_id: u32) {
gl::UseProgram(shader_id);
}
pub unsafe fn set_value(shader_id: u32, name: &'static str, value: ShaderValue) {
let value_name = CString::new(name).unwrap();
match value {
ShaderValue::Bool(value) => gl::Uniform1i(
gl::GetUniformLocation(shader_id, value_name.as_ptr()),
value as i32,
),
ShaderValue::Int(value) => gl::Uniform1i(
gl::GetUniformLocation(shader_id, value_name.as_ptr()),
value,
),
ShaderValue::Float(value) => gl::Uniform1f(
gl::GetUniformLocation(shader_id, value_name.as_ptr()),
value,
),
ShaderValue::Vec3(value) => gl::Uniform3fv(
gl::GetUniformLocation(shader_id, value_name.as_ptr()),
1,
value.as_ptr(),
),
ShaderValue::Mat4(value) => gl::UniformMatrix4fv(
gl::GetUniformLocation(shader_id, value_name.as_ptr()),
1,
gl::FALSE,
value.as_ptr(),
),
}
}
unsafe fn check_compile_errors(shader: u32, type_: &str) {
let mut success = gl::FALSE as gl::types::GLint;
let mut info_log = Vec::with_capacity(1024);
info_log.set_len(1024 - 1);
if type_ != "PROGRAM" {
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success);
if success != gl::TRUE as gl::types::GLint {
gl::GetShaderInfoLog(
shader,
1024,
ptr::null_mut(),
info_log.as_mut_ptr() as *mut gl::types::GLchar,
);
println!(
"ERROR::SHADER_COMPILATION_ERROR of type: {}\n{}\n \
-- --------------------------------------------------- -- ",
type_,
String::from_utf8_lossy(&info_log)
);
}
} else {
gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success);
if success != gl::TRUE as gl::types::GLint {
gl::GetProgramInfoLog(
shader,
1024,
ptr::null_mut(),
info_log.as_mut_ptr() as *mut gl::types::GLchar,
);
println!(
"ERROR::PROGRAM_LINKING_ERROR of type: {}\n{}\n \
-- --------------------------------------------------- -- ",
type_,
String::from_utf8_lossy(&info_log)
);
}
}
}