use glow::HasContext; use super::shader::Shader; use super::snippets::{CodeType, Snippet}; use crate::graphics::transforms::{viewport::Viewport, Transform}; #[derive(Debug)] pub struct Program { version: &'static str, vertex: Shader, fragment: Shader, geometry: Option, pub native_program: Option<::Program>, } impl Program { pub fn new( vertex: Shader, fragment: Shader, geometry: Option, version: &'static str, ) -> Self { let res = Self { version, vertex, fragment, geometry, native_program: None, }; res } pub fn vertex(&self) -> &Shader { &self.vertex } pub fn fragment(&self) -> &Shader { &self.fragment } pub fn set_hook(&mut self, hook: &str, code: &Snippet) { self.vertex.set_hook(hook, code); self.fragment.set_hook(hook, code); } pub fn set_transform(&mut self, value: &T) { self.set_hook("transform", value.snippet()); } pub fn set_viewport(&mut self, viewport: &Viewport) { self.set_hook("viewport", viewport.snippet()); } pub fn compile(&mut self, gl: &glow::Context) -> crate::errors::Result<()> { use crate::errors::Error; unsafe { // let vertex_array = gl // .create_vertex_array() // .expect("Cannot create vertex array"); let program = gl.create_program().map_err(|e| Error::InvalidProgram(e))?; let vertex_shader = self.create_shader(gl, &self.vertex.to_string(),self.version, glow::VERTEX_SHADER); let fragment_shader = self.create_shader(gl, &self.fragment.to_string(),self.version, glow::FRAGMENT_SHADER); gl.link_program(program); if !gl.get_program_link_status(program) { return Err(Error::InvalidProgram(gl.get_program_info_log(program))); } gl.detach_shader(program, vertex_shader); gl.detach_shader(program, fragment_shader); self.native_program = Some(program); } Ok(()) } fn create_shader( &self, gl: &glow::Context, code: &str, version: &'static str, shader_type: u32, ) -> ::Shader { let shader = unsafe { let shader = gl .create_shader(glow::VERTEX_SHADER) .expect("Cannot create shader"); gl.shader_source( shader, &format!("{}\n{}", &format!("#version {}", self.version), code), ); gl.compile_shader(shader); if !gl.get_shader_compile_status(shader) { panic!("{}", gl.get_shader_info_log(shader)) } shader }; shader } pub fn destroy(&self, gl: &glow::Context) { unsafe { self.native_program.map(|p| gl.delete_program(p)); } } pub fn render(&self, gl: &glow::Context) { unsafe { gl.clear_color(0.05, 0.05, 0.1, 1.0); gl.clear(glow::COLOR_BUFFER_BIT); gl.use_program(self.native_program); } } } mod test { use super::*; #[test] fn test_program() { let vertex = Shader::new( glow::VERTEX_SHADER, CodeType::<&'static str>::Path("agg-fast-path.vert".into()), ) .unwrap(); let fragment = Shader::new( glow::FRAGMENT_SHADER, CodeType::<&'static str>::Path("agg-fast-path.frag".into()), ) .unwrap(); let program = Program::new(vertex, fragment, None, "330 core"); } }