mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
165 lines
5.3 KiB
Rust
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);
|
|
}
|
|
}
|
|
} |