Files
Fyrox/src/renderer/gpu_program.rs
T
2019-12-23 20:45:05 +03:00

165 lines
5.3 KiB
Rust

use std::ffi::CStr;
use crate::{
core::{
math::{
vec4::Vec4,
mat4::Mat4,
vec3::Vec3,
vec2::Vec2,
},
},
renderer::{
error::RendererError,
gl::types::GLuint,
gl,
gl::types::GLint,
gl::types::GLfloat
},
utils::log::Log
};
pub struct GpuProgram {
id: GLuint,
name_buf: Vec<u8>,
}
#[derive(Copy, Clone)]
pub struct UniformLocation {
id: GLint
}
impl GpuProgram {
fn create_shader(name: String, actual_type: GLuint, source: &CStr) -> Result<GLuint, RendererError> {
unsafe {
let shader = gl::CreateShader(actual_type);
gl::ShaderSource(shader, 1, &source.as_ptr(), std::ptr::null());
gl::CompileShader(shader);
let mut status = 1;
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
if status == 0 {
let mut log_len = 0;
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
let mut buffer: Vec<u8> = Vec::with_capacity(log_len as usize);
buffer.set_len(log_len as usize);
gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(), buffer.as_mut_ptr() as *mut i8);
let compilation_message = String::from_utf8_unchecked(buffer);
Log::writeln(format!("Failed to compile {} shader: {}", name, compilation_message));
Err(RendererError::ShaderCompilationFailed {
shader_name: name,
error_message: compilation_message,
})
} else {
Log::writeln(format!("Shader {} compiled!", name));
Ok(shader)
}
}
}
pub fn from_source(name: &str, vertex_source: &CStr, fragment_source: &CStr) -> Result<GpuProgram, RendererError> {
unsafe {
let vertex_shader = Self::create_shader(format!("{}_VertexShader", name), gl::VERTEX_SHADER, vertex_source)?;
let fragment_shader = Self::create_shader(format!("{}_FragmentShader", name), gl::FRAGMENT_SHADER, fragment_source)?;
let program: GLuint = gl::CreateProgram();
gl::AttachShader(program, vertex_shader);
gl::DeleteShader(vertex_shader);
gl::AttachShader(program, fragment_shader);
gl::DeleteShader(fragment_shader);
gl::LinkProgram(program);
let mut status = 1;
gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
if status == 0 {
let mut log_len = 0;
gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut log_len);
let mut buffer: Vec<u8> = Vec::with_capacity(log_len as usize);
gl::GetProgramInfoLog(program, log_len, std::ptr::null_mut(), buffer.as_mut_ptr() as *mut i8);
Err(RendererError::ShaderLinkingFailed {
shader_name: name.to_owned(),
error_message: String::from_utf8_unchecked(buffer),
})
} else {
Ok(Self {
id: program,
name_buf: Vec::new(),
})
}
}
}
pub fn get_uniform_location(&mut self, name: &str) -> Result<UniformLocation, RendererError> {
// Form c string in special buffer to reduce memory allocations
let buf = &mut self.name_buf;
buf.clear();
buf.extend_from_slice(name.as_bytes());
buf.push(0);
unsafe {
let id = gl::GetUniformLocation(self.id, buf.as_ptr() as *const i8);
if id < 0 {
Err(RendererError::UnableToFindShaderUniform(name.to_owned()))
} else {
Ok(UniformLocation { id })
}
}
}
pub fn bind(&self) {
unsafe {
gl::UseProgram(self.id);
}
}
pub fn set_mat4(&self, location: UniformLocation, mat: &Mat4) {
unsafe {
gl::UniformMatrix4fv(location.id, 1, gl::FALSE, &mat.f as *const GLfloat);
}
}
pub fn set_mat4_array(&self, location: UniformLocation, mat: &[Mat4]) {
unsafe {
gl::UniformMatrix4fv(location.id, mat.len() as i32, gl::FALSE, mat[0].f.as_ptr() as *const GLfloat);
}
}
pub fn set_int(&self, location: UniformLocation, value: i32) {
unsafe {
gl::Uniform1i(location.id, value);
}
}
pub fn set_vec4(&self, location: UniformLocation, value: &Vec4) {
unsafe {
gl::Uniform4f(location.id, value.x, value.y, value.z, value.w);
}
}
pub fn set_bool(&self, location: UniformLocation, value: bool) {
self.set_int(location, i32::from(if value { gl::TRUE } else { gl::FALSE }))
}
pub fn set_float(&self, location: UniformLocation, value: f32) {
unsafe {
gl::Uniform1f(location.id, value)
}
}
pub fn set_vec3(&self, location: UniformLocation, value: &Vec3) {
unsafe {
gl::Uniform3f(location.id, value.x, value.y, value.z)
}
}
pub fn set_vec2(&self, location: UniformLocation, value: Vec2) {
unsafe {
gl::Uniform2f(location.id, value.x, value.y)
}
}
}
impl Drop for GpuProgram {
fn drop(&mut self) {
unsafe {
gl::DeleteProgram(self.id);
}
}
}