use glow::*; use std::fs; use std::ffi::{CString, CStr}; use std::rc::Rc; use std::str; use cgmath::prelude::*; /// Shader Struct for creating and using shaders in the Context of engine /// pub struct shader { pub ID: NativeProgram, gl: Rc } impl shader { /// 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" pub fn new(path: &str, gl: Rc) -> shader { //read file contents let VERT_SHADER = fs::read_to_string(format!("resources/shaders/{path}/shader.vert")).unwrap(); let FRAG_SHADER = fs::read_to_string(format!("resources/shaders/{path}/shader.frag")).unwrap(); //create vertex shader let vertex_shader = unsafe {gl.create_shader(glow::VERTEX_SHADER).unwrap() }; unsafe { gl.shader_source(vertex_shader, &VERT_SHADER); gl.compile_shader(vertex_shader); } // 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)); } let shader_program = gl.create_program().unwrap(); 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)); } gl.detach_shader(shader_program, vertex_shader); gl.detach_shader(shader_program, fragment_shader); gl.delete_shader(vertex_shader); gl.delete_shader(fragment_shader); shader { ID: shader_program, gl: Rc::clone(&gl), }; } } // return program /// uses Shader pub fn Use(&self, gl: glow::Context) { unsafe {gl.use_program(Some(self.ID));} } // BOILERPLATE JUMPSCARE /* 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);}} 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);}} pub fn setVector2(&self, name: &str, value: cgmath::Vector2 ) {unsafe {self.gl.uniform_2_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), value[0], value[1]);}} 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);}} pub fn setVector3(&self, name: &str, value: cgmath::Vector3 ) {unsafe {self.gl.uniform_3_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), value[0], value[1], value[2]);}} 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);}} pub fn setVector4(&self, name: &str, value: &cgmath::Vector4 ) {unsafe {self.gl.uniform_4_f32(self.gl.get_uniform_location(self.ID, name).as_ref(), value[0], value[1], value[2], value[3]);}} 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);}} //pub fn setMat2(&self, name: &str, value: cgmath::Matrix2) pub fn setMat3(&self, name: &str, value: cgmath::Matrix3) { 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) { 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()); } } } #[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(); } }