radar-gi/src/components/program.rs
2024-07-10 23:48:28 +08:00

143 lines
3.7 KiB
Rust

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<Shader>,
pub native_program: Option<<glow::Context as HasContext>::Program>,
}
impl Program {
pub fn new(
vertex: Shader,
fragment: Shader,
geometry: Option<Shader>,
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<T: 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,
) -> <glow::Context as HasContext>::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");
}
}