mirror of https://github.com/Leinnan/doppler.git
217 lines
8.6 KiB
Rust
217 lines
8.6 KiB
Rust
#![allow(non_snake_case)]
|
|
use std::ffi::{CStr, CString};
|
|
use std::fs::File;
|
|
use std::io::Read;
|
|
use std::ptr;
|
|
use std::str;
|
|
|
|
use gl;
|
|
use gl::types::*;
|
|
|
|
use cgmath::prelude::*;
|
|
use cgmath::{Matrix, Matrix4, Vector3};
|
|
|
|
pub struct Shader {
|
|
pub ID: u32,
|
|
}
|
|
|
|
/// NOTE: mixture of `shader_s.h` and `shader_m.h` (the latter just contains
|
|
/// a few more setters for uniforms)
|
|
#[allow(dead_code)]
|
|
impl Shader {
|
|
pub fn new(vShaderCode: CString, fShaderCode: CString) -> Shader {
|
|
let mut shader = Shader { ID: 0 };
|
|
|
|
// 2. compile shaders
|
|
unsafe {
|
|
// vertex shader
|
|
let vertex = gl::CreateShader(gl::VERTEX_SHADER);
|
|
gl::ShaderSource(vertex, 1, &vShaderCode.as_ptr(), ptr::null());
|
|
gl::CompileShader(vertex);
|
|
shader.checkCompileErrors(vertex, "VERTEX");
|
|
// fragment Shader
|
|
let fragment = gl::CreateShader(gl::FRAGMENT_SHADER);
|
|
gl::ShaderSource(fragment, 1, &fShaderCode.as_ptr(), ptr::null());
|
|
gl::CompileShader(fragment);
|
|
shader.checkCompileErrors(fragment, "FRAGMENT");
|
|
// shader Program
|
|
let ID = gl::CreateProgram();
|
|
gl::AttachShader(ID, vertex);
|
|
gl::AttachShader(ID, fragment);
|
|
gl::LinkProgram(ID);
|
|
shader.checkCompileErrors(ID, "PROGRAM");
|
|
// delete the shaders as they're linked into our program now and no longer necessary
|
|
gl::DeleteShader(vertex);
|
|
gl::DeleteShader(fragment);
|
|
shader.ID = ID;
|
|
}
|
|
|
|
shader
|
|
}
|
|
|
|
pub fn from_file(vertexPath: &str, fragmentPath: &str) -> Shader {
|
|
// 1. retrieve the vertex/fragment source code from filesystem
|
|
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();
|
|
|
|
Shader::new(vShaderCode, fShaderCode)
|
|
}
|
|
|
|
/// activate the shader
|
|
/// ------------------------------------------------------------------------
|
|
pub unsafe fn useProgram(&self) {
|
|
gl::UseProgram(self.ID)
|
|
}
|
|
|
|
/// utility uniform functions
|
|
/// ------------------------------------------------------------------------
|
|
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: &Vector3<f32>) {
|
|
gl::Uniform3fv(
|
|
gl::GetUniformLocation(self.ID, name.as_ptr()),
|
|
1,
|
|
value.as_ptr(),
|
|
);
|
|
}
|
|
/// ------------------------------------------------------------------------
|
|
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 setMat4(&self, name: &CStr, mat: &Matrix4<f32>) {
|
|
gl::UniformMatrix4fv(
|
|
gl::GetUniformLocation(self.ID, name.as_ptr()),
|
|
1,
|
|
gl::FALSE,
|
|
mat.as_ptr(),
|
|
);
|
|
}
|
|
|
|
/// utility function for checking shader compilation/linking errors.
|
|
/// ------------------------------------------------------------------------
|
|
unsafe fn checkCompileErrors(&self, shader: u32, type_: &str) {
|
|
let mut is_success = gl::FALSE as GLint;
|
|
let mut infoLog = Vec::with_capacity(1024);
|
|
infoLog.set_len(1024 - 1); // subtract 1 to skip the trailing null character
|
|
if type_ != "PROGRAM" {
|
|
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut is_success);
|
|
if is_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 is_success);
|
|
if is_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()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Only used in 4.9 Geometry shaders - ignore until then (shader.h in original C++)
|
|
pub fn with_geometry_shader(vertexPath: &str, fragmentPath: &str, geometryPath: &str) -> Self {
|
|
let mut shader = Shader { ID: 0 };
|
|
// 1. retrieve the vertex/fragment source code from filesystem
|
|
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();
|
|
|
|
// 2. compile shaders
|
|
unsafe {
|
|
// vertex shader
|
|
let vertex = gl::CreateShader(gl::VERTEX_SHADER);
|
|
gl::ShaderSource(vertex, 1, &vShaderCode.as_ptr(), ptr::null());
|
|
gl::CompileShader(vertex);
|
|
shader.checkCompileErrors(vertex, "VERTEX");
|
|
// fragment Shader
|
|
let fragment = gl::CreateShader(gl::FRAGMENT_SHADER);
|
|
gl::ShaderSource(fragment, 1, &fShaderCode.as_ptr(), ptr::null());
|
|
gl::CompileShader(fragment);
|
|
shader.checkCompileErrors(fragment, "FRAGMENT");
|
|
// geometry shader
|
|
let geometry = gl::CreateShader(gl::GEOMETRY_SHADER);
|
|
gl::ShaderSource(geometry, 1, &gShaderCode.as_ptr(), ptr::null());
|
|
gl::CompileShader(geometry);
|
|
shader.checkCompileErrors(geometry, "GEOMETRY");
|
|
|
|
// shader Program
|
|
let ID = gl::CreateProgram();
|
|
gl::AttachShader(ID, vertex);
|
|
gl::AttachShader(ID, fragment);
|
|
gl::AttachShader(ID, geometry);
|
|
gl::LinkProgram(ID);
|
|
shader.checkCompileErrors(ID, "PROGRAM");
|
|
// delete the shaders as they're linked into our program now and no longer necessary
|
|
gl::DeleteShader(vertex);
|
|
gl::DeleteShader(fragment);
|
|
gl::DeleteShader(geometry);
|
|
shader.ID = ID;
|
|
}
|
|
|
|
shader
|
|
}
|
|
}
|