diff options
Diffstat (limited to 'engine/src/renderer')
-rw-r--r-- | engine/src/renderer/mod.rs | 102 |
1 files changed, 83 insertions, 19 deletions
diff --git a/engine/src/renderer/mod.rs b/engine/src/renderer/mod.rs index c72e1ce..64d5e3c 100644 --- a/engine/src/renderer/mod.rs +++ b/engine/src/renderer/mod.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::ffi::{c_void, CString}; use std::process::abort; @@ -18,11 +19,16 @@ use crate::opengl::buffer::{ use crate::opengl::currently_bound::CurrentlyBound; #[cfg(feature = "debug")] use crate::opengl::debug::{MessageSeverity, MessageSource, MessageType}; -use crate::opengl::shader::Program as ShaderProgram; +use crate::opengl::shader::{ + Error as GlShaderError, + Program as GlShaderProgram, + Shader as GlShader, +}; use crate::opengl::texture::{set_active_texture_unit, TextureUnit}; use crate::opengl::vertex_array::{PrimitiveKind, VertexArray}; use crate::opengl::{clear_buffers, enable, BufferClearMask, Capability}; use crate::projection::new_perspective; +use crate::shader::Program as ShaderProgram; use crate::vector::{Vec2, Vec3}; use crate::vertex::Vertex; @@ -30,6 +36,7 @@ use crate::vertex::Vertex; pub struct Renderer<CameraT> { camera: CameraT, + shader_programs: HashMap<u64, GlShaderProgram>, } impl<CameraT> Renderer<CameraT> @@ -63,7 +70,44 @@ where enable(Capability::DepthTest); - Ok(Self { camera }) + Ok(Self { + camera, + shader_programs: HashMap::new(), + }) + } + + pub fn create_shader_programs<'program>( + &mut self, + programs: impl IntoIterator<Item = &'program ShaderProgram>, + ) -> Result<(), Error> + { + for program in programs { + let gl_shaders = program + .shaders() + .iter() + .map(|shader| { + let gl_shader = GlShader::new(shader.kind()); + + gl_shader.set_source(shader.source())?; + gl_shader.compile()?; + + Ok::<_, Error>(gl_shader) + }) + .collect::<Result<Vec<_>, _>>()?; + + let gl_shader_program = GlShaderProgram::new(); + + for gl_shader in &gl_shaders { + gl_shader_program.attach(gl_shader); + } + + gl_shader_program.link()?; + + self.shader_programs + .insert(program.u64_hash(), gl_shader_program); + } + + Ok(()) } pub fn render<'obj>( @@ -76,15 +120,27 @@ where clear_buffers(BufferClearMask::COLOR | BufferClearMask::DEPTH); for obj in objects { - obj.shader().activate(|shader_program_curr_bound| { + let shader_program = self + .shader_programs + .get(&obj.shader().u64_hash()) + .ok_or(Error::MissingShaderProgram)?; + + shader_program.activate(|shader_program_curr_bound| { apply_transformation_matrices( obj, + shader_program, &self.camera, window_size, &shader_program_curr_bound, ); - apply_light(obj, light_source, &self.camera, &shader_program_curr_bound); + apply_light( + obj, + shader_program, + light_source, + &self.camera, + &shader_program_curr_bound, + ); for (texture_id, texture) in obj.textures() { let texture_unit = TextureUnit::from_texture_id(*texture_id) @@ -97,7 +153,7 @@ where Self::draw_object(obj); - Ok(()) + Ok::<_, Error>(()) })?; } @@ -220,16 +276,23 @@ pub enum Error #[error("Texture ID is a invalid texture unit")] TextureIdIsInvalidTextureUnit, + + #[error(transparent)] + GlShader(#[from] GlShaderError), + + #[error("No shader program object was found for object")] + MissingShaderProgram, } fn apply_transformation_matrices( object: &Object, + gl_shader_program: &GlShaderProgram, camera: &impl Camera, window_size: &WindowSize, - shader_program_curr_bound: &CurrentlyBound<ShaderProgram>, + shader_program_curr_bound: &CurrentlyBound<GlShaderProgram>, ) { - object.shader().set_uniform_matrix_4fv( + gl_shader_program.set_uniform_matrix_4fv( shader_program_curr_bound, cstr!("model"), &object.transform().as_matrix(), @@ -237,7 +300,7 @@ fn apply_transformation_matrices( let view = create_view(camera); - object.shader().set_uniform_matrix_4fv( + gl_shader_program.set_uniform_matrix_4fv( shader_program_curr_bound, cstr!("view"), &view, @@ -251,7 +314,7 @@ fn apply_transformation_matrices( 0.1, ); - object.shader().set_uniform_matrix_4fv( + gl_shader_program.set_uniform_matrix_4fv( shader_program_curr_bound, cstr!("projection"), &projection, @@ -260,12 +323,13 @@ fn apply_transformation_matrices( fn apply_light( obj: &Object, + gl_shader_program: &GlShaderProgram, light_source: Option<&LightSource>, camera: &impl Camera, - shader_program_curr_bound: &CurrentlyBound<ShaderProgram>, + shader_program_curr_bound: &CurrentlyBound<GlShaderProgram>, ) { - obj.shader().set_uniform_vec_3fv( + gl_shader_program.set_uniform_vec_3fv( shader_program_curr_bound, cstr!("light.position"), &light_source.map_or_else(Vec3::default, |light_source| { @@ -273,7 +337,7 @@ fn apply_light( }), ); - obj.shader().set_uniform_vec_3fv( + gl_shader_program.set_uniform_vec_3fv( shader_program_curr_bound, cstr!("light.ambient"), &light_source @@ -283,7 +347,7 @@ fn apply_light( .into(), ); - obj.shader().set_uniform_vec_3fv( + gl_shader_program.set_uniform_vec_3fv( shader_program_curr_bound, cstr!("light.diffuse"), &light_source @@ -293,7 +357,7 @@ fn apply_light( .into(), ); - obj.shader().set_uniform_vec_3fv( + gl_shader_program.set_uniform_vec_3fv( shader_program_curr_bound, cstr!("light.specular"), &light_source @@ -304,33 +368,33 @@ fn apply_light( ); #[allow(clippy::cast_possible_wrap)] - obj.shader().set_uniform_1i( + gl_shader_program.set_uniform_1i( shader_program_curr_bound, cstr!("material.ambient"), obj.material().ambient_map().into_inner() as i32, ); #[allow(clippy::cast_possible_wrap)] - obj.shader().set_uniform_1i( + gl_shader_program.set_uniform_1i( shader_program_curr_bound, cstr!("material.diffuse"), obj.material().diffuse_map().into_inner() as i32, ); #[allow(clippy::cast_possible_wrap)] - obj.shader().set_uniform_1i( + gl_shader_program.set_uniform_1i( shader_program_curr_bound, cstr!("material.specular"), obj.material().specular_map().into_inner() as i32, ); - obj.shader().set_uniform_1fv( + gl_shader_program.set_uniform_1fv( shader_program_curr_bound, cstr!("material.shininess"), obj.material().shininess(), ); - obj.shader().set_uniform_vec_3fv( + gl_shader_program.set_uniform_vec_3fv( shader_program_curr_bound, cstr!("view_pos"), &camera.position(), |