2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-06 10:13:01 +01:00
|
|
|
use glow::*;
|
2023-03-02 09:42:39 +01:00
|
|
|
use std::fs;
|
|
|
|
use std::ffi::{CString, CStr};
|
2023-03-08 10:19:23 +01:00
|
|
|
use std::rc::Rc;
|
2023-03-02 09:42:39 +01:00
|
|
|
use std::str;
|
|
|
|
use cgmath::prelude::*;
|
|
|
|
/// Shader Struct for creating and using shaders in the Context of engine
|
|
|
|
///
|
2023-03-08 10:19:23 +01:00
|
|
|
pub struct shader {
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
pub ID: NativeProgram,
|
|
|
|
gl: Rc<glow::Context>
|
2023-03-02 09:42:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
impl shader
|
2023-03-02 09:42:39 +01:00
|
|
|
{
|
|
|
|
/// Shader Constructor, will read, Compile and Create GLSL Program for use
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// `new(String::from("Example"))`
|
|
|
|
/// if the String given was "Example" the Program expects both shaders to be in the directory "resources/shaders/Example/"
|
|
|
|
/// with the vertex shader being called "shader.vert" and fragment "shader.frag"
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn new(path: &str, gl: Rc<glow::Context>) -> shader
|
2023-03-02 09:42:39 +01:00
|
|
|
{
|
|
|
|
//read file contents
|
|
|
|
let VERT_SHADER = fs::read_to_string(format!("resources/shaders/{path}/shader.vert")).unwrap();
|
2023-03-06 10:13:01 +01:00
|
|
|
let FRAG_SHADER = fs::read_to_string(format!("resources/shaders/{path}/shader.frag")).unwrap();
|
2023-03-02 09:42:39 +01:00
|
|
|
|
|
|
|
//create vertex shader
|
2023-03-06 10:13:01 +01:00
|
|
|
let vertex_shader = unsafe {gl.create_shader(glow::VERTEX_SHADER).unwrap() };
|
2023-03-02 09:42:39 +01:00
|
|
|
unsafe {
|
2023-03-06 10:13:01 +01:00
|
|
|
gl.shader_source(vertex_shader, &VERT_SHADER);
|
|
|
|
gl.compile_shader(vertex_shader);
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-06 10:13:01 +01:00
|
|
|
}
|
|
|
|
// create fragment shader
|
|
|
|
let fragment_shader = unsafe{gl.create_shader(glow::FRAGMENT_SHADER).unwrap()};
|
|
|
|
unsafe {
|
|
|
|
gl.shader_source(fragment_shader, &FRAG_SHADER);
|
|
|
|
gl.compile_shader(fragment_shader);
|
|
|
|
if !gl.get_shader_compile_status(fragment_shader) {
|
|
|
|
panic!("Error, Compiling Fragment Shader: {}", gl.get_shader_info_log(fragment_shader));
|
2023-03-02 09:42:39 +01:00
|
|
|
}
|
|
|
|
|
2023-03-06 10:13:01 +01:00
|
|
|
let shader_program = gl.create_program().unwrap();
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-06 10:13:01 +01:00
|
|
|
gl.attach_shader(shader_program, vertex_shader);
|
|
|
|
gl.attach_shader(shader_program, fragment_shader);
|
|
|
|
gl.link_program(shader_program);
|
|
|
|
if !gl.get_program_link_status(shader_program) {
|
|
|
|
panic!("Error, Linking Shader Program {}", gl.get_program_info_log(shader_program));
|
2023-03-02 09:42:39 +01:00
|
|
|
}
|
2023-03-06 10:13:01 +01:00
|
|
|
gl.detach_shader(shader_program, vertex_shader);
|
|
|
|
gl.detach_shader(shader_program, fragment_shader);
|
|
|
|
gl.delete_shader(vertex_shader);
|
|
|
|
gl.delete_shader(fragment_shader);
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-06 10:13:01 +01:00
|
|
|
shader {
|
|
|
|
ID: shader_program,
|
2023-03-08 10:19:23 +01:00
|
|
|
gl: Rc::clone(&gl),
|
2023-03-06 10:13:01 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2023-03-06 10:13:01 +01:00
|
|
|
// return program
|
|
|
|
|
2023-03-02 09:42:39 +01:00
|
|
|
/// uses Shader
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn Use(&self, gl: glow::Context)
|
2023-03-02 09:42:39 +01:00
|
|
|
{
|
2023-03-08 10:19:23 +01:00
|
|
|
unsafe {gl.use_program(Some(self.ID));}
|
2023-03-02 09:42:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// BOILERPLATE JUMPSCARE
|
2023-03-08 10:19:23 +01:00
|
|
|
/*
|
|
|
|
pub fn setBool(&self, name: &str, value: bool )
|
|
|
|
{unsafe {self.gl.uniform_1_bool(self.gl.get_uniform_location(self.ID, name).as_ref(), value);}}
|
|
|
|
*/
|
|
|
|
pub fn setInt(&self, name: &str, value: i32 )
|
|
|
|
{unsafe {self.gl.uniform_1_i32(self.gl.get_uniform_location(self.ID, name).as_ref(), value);}}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn setFloat(&self, name: &str, value: f32 )
|
|
|
|
{unsafe {self.gl.uniform_1_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), value);}}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn setVector2(&self, name: &str, value: cgmath::Vector2<f32> )
|
|
|
|
{unsafe {self.gl.uniform_2_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), value[0], value[1]);}}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn setVector2d(&self, name: &str, x: f32, y: f32)
|
|
|
|
{unsafe {self.gl.uniform_2_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), x, y);}}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn setVector3(&self, name: &str, value: cgmath::Vector3<f32> )
|
|
|
|
{unsafe {self.gl.uniform_3_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), value[0], value[1], value[2]);}}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn setVector3d(&self, name: &str, x: f32, y: f32, z: f32 )
|
|
|
|
{unsafe {self.gl.uniform_3_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), x, y, z);}}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn setVector4(&self, name: &str, value: &cgmath::Vector4<f32> )
|
|
|
|
{unsafe {self.gl.uniform_4_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), value[0], value[1], value[2], value[3]);}}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn setVector4d(&self, name: &str, x: f32, y: f32, z: f32, w: f32)
|
|
|
|
{unsafe {self.gl.uniform_4_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), x, y, z, w);}}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
//pub fn setMat2(&self, name: &str, value: cgmath::Matrix2<f32>)
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
pub fn setMat3(&self, name: &str, value: cgmath::Matrix3<f32>)
|
|
|
|
{
|
|
|
|
let nums = vec![value.x.x, value.x.y, value.x.z,
|
|
|
|
value.y.x, value.y.y, value.y.z,
|
|
|
|
value.z.x, value.z.y, value.z.z];
|
|
|
|
unsafe
|
|
|
|
{
|
|
|
|
self.gl.uniform_matrix_3_f32_slice(self.gl.get_uniform_location(self.ID, name).as_ref(), false, nums.as_ref());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn setMat4(&self, name: &str, value: &cgmath::Matrix4<f32>)
|
|
|
|
{
|
|
|
|
let nums = vec![value.x.x, value.x.y, value.x.z, value.x.w,
|
|
|
|
value.y.x, value.y.y, value.y.z, value.y.w,
|
|
|
|
value.z.x, value.z.y, value.z.z, value.z.w,
|
|
|
|
value.w.x, value.w.y, value.w.z, value.w.w];
|
|
|
|
unsafe
|
|
|
|
{
|
|
|
|
self.gl.uniform_matrix_4_f32_slice(self.gl.get_uniform_location(self.ID, name).as_ref(), false, nums.as_ref());
|
|
|
|
}
|
|
|
|
}
|
2023-03-02 09:42:39 +01:00
|
|
|
|
2023-03-08 10:19:23 +01:00
|
|
|
}
|
2023-03-02 09:42:39 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use glfw;
|
|
|
|
use glfw::Context;
|
|
|
|
use gl;
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn ShaderLoading() {
|
|
|
|
|
|
|
|
// initialize GLFW
|
|
|
|
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
|
|
|
|
// set window hints
|
|
|
|
glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
|
|
|
|
glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
|
|
|
|
glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
|
|
|
|
glfw.window_hint(glfw::WindowHint::Resizable(false));
|
|
|
|
|
|
|
|
//create Window
|
|
|
|
let (mut window, events) = glfw.create_window(480, 320, "Shader Test", glfw::WindowMode::Windowed).unwrap();
|
|
|
|
let (screen_width, screen_height) = window.get_framebuffer_size();
|
|
|
|
|
|
|
|
// setup window
|
|
|
|
window.make_current();
|
|
|
|
window.set_key_polling(true);
|
|
|
|
// initialize gl
|
|
|
|
gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
|
|
|
|
|
|
|
|
let Shader = shader::new("basic");
|
|
|
|
Shader.Use();
|
|
|
|
}
|
|
|
|
}
|