use std::ffi::{CString, CStr};
use std::fs::File;
use std::io::Read;
use std::ptr;
use std::str;
use gl::{self, GetUniformLocation, UniformMatrix4fv, FALSE};
use gl::types::*;
use glam::{vec3, Vec3, Vec4};
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct Shader {
pub ID: u32,
}
#[allow(dead_code)]
impl Shader {
pub fn new(vertexPath: &str, fragmentPath: &str) -> Shader {
let mut shader = Shader { ID: 0 };
let mut vShaderFile = File::open(vertexPath)
.unwrap_or_else(|_| panic!("Failed to open {}", vertexPath));
let mut fShaderFile = File::open(fragmentPath)
.unwrap_or_else(|_| panic!("Failed to open {}", fragmentPath));
let mut vertexCode = String::new();
let mut fragmentCode = String::new();
vShaderFile
.read_to_string(&mut vertexCode)
.expect("Failed to read vertex shader");
fShaderFile
.read_to_string(&mut fragmentCode)
.expect("Failed to read fragment shader");
let vShaderCode = CString::new(vertexCode.as_bytes()).unwrap();
let fShaderCode = CString::new(fragmentCode.as_bytes()).unwrap();
unsafe {
let vertex = gl::CreateShader(gl::VERTEX_SHADER);
gl::ShaderSource(vertex, 1, &vShaderCode.as_ptr(), ptr::null());
gl::CompileShader(vertex);
shader.checkCompileErrors(vertex, "VERTEX");
let fragment = gl::CreateShader(gl::FRAGMENT_SHADER);
gl::ShaderSource(fragment, 1, &fShaderCode.as_ptr(), ptr::null());
gl::CompileShader(fragment);
shader.checkCompileErrors(fragment, "FRAGMENT");
let ID = gl::CreateProgram();
gl::AttachShader(ID, vertex);
gl::AttachShader(ID, fragment);
gl::LinkProgram(ID);
shader.checkCompileErrors(ID, "PROGRAM");
gl::DeleteShader(vertex);
gl::DeleteShader(fragment);
shader.ID = ID;
}
shader
}
pub unsafe fn useProgram(&self) {
gl::UseProgram(self.ID)
}
pub unsafe fn setBool(&self, name: &CStr, value: bool) {
gl::Uniform1i(gl::GetUniformLocation(self.ID, name.as_ptr()), value as i32);
}
pub unsafe fn setInt(&self, name: &CStr, value: i32) {
gl::Uniform1i(gl::GetUniformLocation(self.ID, name.as_ptr()), value);
}
pub unsafe fn setFloat(&self, name: &CStr, value: f32) {
gl::Uniform1f(gl::GetUniformLocation(self.ID, name.as_ptr()), value);
}
pub unsafe fn setVector3(&self, name: &CStr, value: &Vec3) {
gl::Uniform3f(gl::GetUniformLocation(self.ID, name.as_ptr()), value.x, value.y, value.z);
}
pub unsafe fn setVec3(&self, name: &CStr, x: f32, y: f32, z: f32) {
gl::Uniform3f(gl::GetUniformLocation(self.ID, name.as_ptr()), x, y, z);
}
pub unsafe fn setVector4(&self, name: &CStr, value: &Vec4) {
gl::Uniform4f(gl::GetUniformLocation(self.ID, name.as_ptr()), value.x, value.y, value.z, value.w);
}
pub unsafe fn uniform_mat4fv(&self, name: &CStr, mat: &[f32; 16]) {
UniformMatrix4fv(
GetUniformLocation(self.ID, name.as_ptr()),
1,
FALSE,
mat as *const f32
);
}
unsafe fn checkCompileErrors(&self, shader: u32, type_: &str) {
let mut success = gl::FALSE as GLint;
let mut infoLog = Vec::with_capacity(1024);
infoLog.set_len(712 - 1); if type_ != "PROGRAM" {
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success);
if success != gl::TRUE as GLint {
gl::GetShaderInfoLog(shader, 1024, ptr::null_mut(), infoLog.as_mut_ptr() as *mut GLchar);
println!("ERROR::SHADER_COMPILATION_ERROR of type: {}\n{}\n \
-- --------------------------------------------------- -- ",
type_,
str::from_utf8(&infoLog).unwrap());
}
} else {
gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success);
if success != gl::TRUE as GLint {
gl::GetProgramInfoLog(shader, 1024, ptr::null_mut(), infoLog.as_mut_ptr() as *mut GLchar);
println!("ERROR::PROGRAM_LINKING_ERROR of type: {}\n{}\n \
-- --------------------------------------------------- -- ",
type_,
str::from_utf8(&infoLog).unwrap());
}
}
}
pub fn with_geometry_shader(vertexPath: &str, fragmentPath: &str, geometryPath: &str) -> Self {
let mut shader = Shader { ID: 0 };
let mut vShaderFile = File::open(vertexPath)
.unwrap_or_else(|_| panic!("Failed to open {}", vertexPath));
let mut fShaderFile = File::open(fragmentPath)
.unwrap_or_else(|_| panic!("Failed to open {}", fragmentPath));
let mut gShaderFile = File::open(geometryPath)
.unwrap_or_else(|_| panic!("Failed to open {}", geometryPath));
let mut vertexCode = String::new();
let mut fragmentCode = String::new();
let mut geometryCode = String::new();
vShaderFile
.read_to_string(&mut vertexCode)
.expect("Failed to read vertex shader");
fShaderFile
.read_to_string(&mut fragmentCode)
.expect("Failed to read fragment shader");
gShaderFile
.read_to_string(&mut geometryCode)
.expect("Failed to read geometry shader");
let vShaderCode = CString::new(vertexCode.as_bytes()).unwrap();
let fShaderCode = CString::new(fragmentCode.as_bytes()).unwrap();
let gShaderCode = CString::new(geometryCode.as_bytes()).unwrap();
unsafe {
let vertex = gl::CreateShader(gl::VERTEX_SHADER);
gl::ShaderSource(vertex, 1, &vShaderCode.as_ptr(), ptr::null());
gl::CompileShader(vertex);
shader.checkCompileErrors(vertex, "VERTEX");
let fragment = gl::CreateShader(gl::FRAGMENT_SHADER);
gl::ShaderSource(fragment, 1, &fShaderCode.as_ptr(), ptr::null());
gl::CompileShader(fragment);
shader.checkCompileErrors(fragment, "FRAGMENT");
let geometry = gl::CreateShader(gl::GEOMETRY_SHADER);
gl::ShaderSource(geometry, 1, &gShaderCode.as_ptr(), ptr::null());
gl::CompileShader(geometry);
shader.checkCompileErrors(geometry, "GEOMETRY");
let ID = gl::CreateProgram();
gl::AttachShader(ID, vertex);
gl::AttachShader(ID, fragment);
gl::AttachShader(ID, geometry);
gl::LinkProgram(ID);
shader.checkCompileErrors(ID, "PROGRAM");
gl::DeleteShader(vertex);
gl::DeleteShader(fragment);
gl::DeleteShader(geometry);
shader.ID = ID;
}
shader
}
}