diff options
-rw-r--r-- | engine/src/lib.rs | 1 | ||||
-rw-r--r-- | engine/src/opengl/shader.rs | 17 | ||||
-rw-r--r-- | engine/src/renderer/opengl.rs | 99 | ||||
-rw-r--r-- | engine/src/renderer/opengl/glsl/fragment.glsl (renamed from engine/fragment.glsl) | 0 | ||||
-rw-r--r-- | engine/src/renderer/opengl/glsl/light.glsl (renamed from engine/light.glsl) | 0 | ||||
-rw-r--r-- | engine/src/renderer/opengl/glsl/vertex.glsl (renamed from engine/vertex.glsl) | 0 | ||||
-rw-r--r-- | engine/src/renderer/opengl/glsl/vertex_data.glsl (renamed from engine/vertex_data.glsl) | 0 | ||||
-rw-r--r-- | engine/src/shader.rs | 188 |
8 files changed, 76 insertions, 229 deletions
diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 555e1ed..07b2f8d 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -37,7 +37,6 @@ pub mod mesh; pub mod performance; pub mod projection; pub mod renderer; -pub mod shader; pub mod texture; pub mod transform; pub mod vertex; diff --git a/engine/src/opengl/shader.rs b/engine/src/opengl/shader.rs index 070897e..36dc1a4 100644 --- a/engine/src/opengl/shader.rs +++ b/engine/src/opengl/shader.rs @@ -2,7 +2,6 @@ use std::ffi::CStr; use std::ptr::null_mut; use crate::matrix::Matrix; -use crate::shader::Kind; use crate::vector::Vec3; #[derive(Debug)] @@ -20,7 +19,7 @@ impl Shader Self { shader } } - pub fn set_source(&self, source: &str) -> Result<(), Error> + pub fn set_source(&mut self, source: &str) -> Result<(), Error> { if !source.is_ascii() { return Err(Error::SourceNotAscii); @@ -39,7 +38,7 @@ impl Shader Ok(()) } - pub fn compile(&self) -> Result<(), Error> + pub fn compile(&mut self) -> Result<(), Error> { unsafe { gl::CompileShader(self.shader); @@ -90,6 +89,14 @@ impl Drop for Shader } } +/// Shader kind. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Kind +{ + Vertex, + Fragment, +} + impl Kind { fn into_gl(self) -> gl::types::GLenum @@ -117,14 +124,14 @@ impl Program Self { program } } - pub fn attach(&self, shader: &Shader) + pub fn attach(&mut self, shader: &Shader) { unsafe { gl::AttachShader(self.program, shader.shader); } } - pub fn link(&self) -> Result<(), Error> + pub fn link(&mut self) -> Result<(), Error> { unsafe { gl::LinkProgram(self.program); diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs index 6e6347b..deb26a8 100644 --- a/engine/src/renderer/opengl.rs +++ b/engine/src/renderer/opengl.rs @@ -2,7 +2,9 @@ use std::collections::HashMap; use std::ffi::{c_void, CString}; +use std::io::{Error as IoError, ErrorKind as IoErrorKind}; use std::ops::Deref; +use std::path::Path; use std::process::abort; use ecs::actions::Actions; @@ -24,8 +26,13 @@ use crate::mesh::Mesh; use crate::opengl::buffer::{Buffer, Usage as BufferUsage}; #[cfg(feature = "debug")] use crate::opengl::debug::{MessageSeverity, MessageSource, MessageType}; +use crate::opengl::glsl::{ + preprocess as glsl_preprocess, + PreprocessingError as GlslPreprocessingError, +}; use crate::opengl::shader::{ Error as GlShaderError, + Kind as ShaderKind, Program as GlShaderProgram, Shader as GlShader, }; @@ -41,7 +48,6 @@ use crate::opengl::vertex_array::{ }; use crate::opengl::{clear_buffers, enable, BufferClearMask, Capability}; use crate::projection::{new_perspective_matrix, Projection}; -use crate::shader::Program as ShaderProgram; use crate::texture::{Id as TextureId, Texture}; use crate::transform::{Position, Scale}; use crate::util::NeverDrop; @@ -51,7 +57,6 @@ use crate::window::Window; type RenderableEntity = ( Mesh, - ShaderProgram, Material, Option<MaterialFlags>, Option<Position>, @@ -137,34 +142,24 @@ fn render( let directional_lights = directional_lights.iter().collect::<Vec<_>>(); let GlobalGlObjects { - shader_programs: gl_shader_programs, + shader_program, textures: gl_textures, } = &mut *gl_objects; + let shader_program = + shader_program.get_or_insert_with(|| create_default_shader_program().unwrap()); + clear_buffers(BufferClearMask::COLOR | BufferClearMask::DEPTH); for ( entity_index, - ( - mesh, - shader_program, - material, - material_flags, - position, - scale, - draw_flags, - gl_objects, - ), + (mesh, material, material_flags, position, scale, draw_flags, gl_objects), ) in query.iter().enumerate() { let material_flags = material_flags .map(|material_flags| material_flags.clone()) .unwrap_or_default(); - let shader_program = gl_shader_programs - .entry(shader_program.u64_hash()) - .or_insert_with(|| create_gl_shader_program(&shader_program).unwrap()); - let new_gl_objects; let gl_objects = if let Some(gl_objects) = gl_objects.as_deref() { @@ -248,7 +243,7 @@ fn render( #[derive(Debug, Default, Component)] struct GlobalGlObjects { - shader_programs: HashMap<u64, GlShaderProgram>, + shader_program: Option<GlShaderProgram>, textures: HashMap<TextureId, GlTexture>, } @@ -300,34 +295,68 @@ fn create_gl_texture(texture: &Texture) -> GlTexture gl_texture } -fn create_gl_shader_program( - shader_program: &ShaderProgram, -) -> Result<GlShaderProgram, GlShaderError> +const VERTEX_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/vertex.glsl"); +const FRAGMENT_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/fragment.glsl"); + +const VERTEX_DATA_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/vertex_data.glsl"); +const LIGHT_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/light.glsl"); + +fn create_default_shader_program() -> Result<GlShaderProgram, CreateShaderError> { - let gl_shaders = shader_program - .shaders() - .iter() - .map(|shader| { - let gl_shader = GlShader::new(shader.kind()); + let mut vertex_shader = GlShader::new(ShaderKind::Vertex); - gl_shader.set_source(shader.source())?; - gl_shader.compile()?; + vertex_shader.set_source(&*glsl_preprocess( + VERTEX_GLSL_SHADER_SRC, + &get_glsl_shader_content, + )?)?; - Ok(gl_shader) - }) - .collect::<Result<Vec<_>, _>>()?; + vertex_shader.compile()?; - let gl_shader_program = GlShaderProgram::new(); + let mut fragment_shader = GlShader::new(ShaderKind::Fragment); - for gl_shader in &gl_shaders { - gl_shader_program.attach(gl_shader); - } + fragment_shader.set_source(&*glsl_preprocess( + FRAGMENT_GLSL_SHADER_SRC, + &get_glsl_shader_content, + )?)?; + + fragment_shader.compile()?; + + let mut gl_shader_program = GlShaderProgram::new(); + + gl_shader_program.attach(&vertex_shader); + gl_shader_program.attach(&fragment_shader); gl_shader_program.link()?; Ok(gl_shader_program) } +#[derive(Debug, thiserror::Error)] +enum CreateShaderError +{ + #[error(transparent)] + ShaderError(#[from] GlShaderError), + + #[error(transparent)] + PreprocessingError(#[from] GlslPreprocessingError), +} + +fn get_glsl_shader_content(path: &Path) -> Result<Vec<u8>, std::io::Error> +{ + if path == Path::new("vertex_data.glsl") { + return Ok(VERTEX_DATA_GLSL_SHADER_SRC.as_bytes().to_vec()); + } + + if path == Path::new("light.glsl") { + return Ok(LIGHT_GLSL_SHADER_SRC.as_bytes().to_vec()); + } + + Err(IoError::new( + IoErrorKind::NotFound, + format!("Content for shader file {} not found", path.display()), + )) +} + #[derive(Debug, Component)] struct GlObjects { diff --git a/engine/fragment.glsl b/engine/src/renderer/opengl/glsl/fragment.glsl index 5bf5ff2..5bf5ff2 100644 --- a/engine/fragment.glsl +++ b/engine/src/renderer/opengl/glsl/fragment.glsl diff --git a/engine/light.glsl b/engine/src/renderer/opengl/glsl/light.glsl index 1bc23a4..1bc23a4 100644 --- a/engine/light.glsl +++ b/engine/src/renderer/opengl/glsl/light.glsl diff --git a/engine/vertex.glsl b/engine/src/renderer/opengl/glsl/vertex.glsl index b57caa6..b57caa6 100644 --- a/engine/vertex.glsl +++ b/engine/src/renderer/opengl/glsl/vertex.glsl diff --git a/engine/vertex_data.glsl b/engine/src/renderer/opengl/glsl/vertex_data.glsl index 486d445..486d445 100644 --- a/engine/vertex_data.glsl +++ b/engine/src/renderer/opengl/glsl/vertex_data.glsl diff --git a/engine/src/shader.rs b/engine/src/shader.rs deleted file mode 100644 index b43d538..0000000 --- a/engine/src/shader.rs +++ /dev/null @@ -1,188 +0,0 @@ -use std::collections::hash_map::DefaultHasher; -use std::fs::read_to_string; -use std::hash::{Hash, Hasher}; -use std::path::{Path, PathBuf}; - -use ecs::Component; - -use crate::opengl::glsl::{ - preprocess as glsl_preprocess, - PreprocessingError as GlslPreprocessingError, -}; - -const VERTEX_SHADER_FILE: &str = "vertex.glsl"; -const FRAGMENT_SHADER_FILE: &str = "fragment.glsl"; - -const SHADER_DIR: &str = "engine"; - -/// Shader program -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Component)] -pub struct Program -{ - shaders: Vec<Shader>, -} - -impl Program -{ - /// Creates a new shader program with the default shaders. - /// - /// # Errors - /// Returns `Err` if: - /// - Reading a default shader file Fails - /// - Preprocessing a shader fails. - pub fn new() -> Result<Self, Error> - { - let mut program = Self { shaders: Vec::new() }; - - program.push_shader( - Shader::read_shader_file( - Kind::Vertex, - &Path::new(SHADER_DIR).join(VERTEX_SHADER_FILE), - )? - .preprocess()?, - ); - - program.push_shader( - Shader::read_shader_file( - Kind::Fragment, - &Path::new(SHADER_DIR).join(FRAGMENT_SHADER_FILE), - )? - .preprocess()?, - ); - - Ok(program) - } - - pub fn push_shader(&mut self, shader: Shader) - { - self.shaders.push(shader); - } - - pub fn append_shaders(&mut self, shaders: impl IntoIterator<Item = Shader>) - { - self.shaders.extend(shaders); - } - - #[must_use] - pub fn shaders(&self) -> &[Shader] - { - &self.shaders - } - - pub(crate) fn u64_hash(&self) -> u64 - { - let mut hasher = DefaultHasher::new(); - - self.hash(&mut hasher); - - hasher.finish() - } -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct Shader -{ - kind: Kind, - source: String, - file: PathBuf, -} - -impl Shader -{ - /// Reads a shader from the specified source file. - /// - /// # Errors - /// Will return `Err` if: - /// - Reading the file fails - /// - The shader source is not ASCII - pub fn read_shader_file(kind: Kind, shader_file: &Path) -> Result<Self, Error> - { - let source = read_to_string(shader_file).map_err(|err| Error::ReadFailed { - source: err, - shader_file: shader_file.to_path_buf(), - })?; - - if !source.is_ascii() { - return Err(Error::SourceNotAscii); - } - - Ok(Self { - kind, - source, - file: shader_file.to_path_buf(), - }) - } - - /// Preprocesses the shaders. - /// - /// # Errors - /// Returns `Err` if preprocessing fails. - pub fn preprocess(self) -> Result<Self, Error> - { - let parent_dir = self - .file - .parent() - .ok_or(Error::SourcePathHasNoParent)? - .to_path_buf(); - - let source_preprocessed = - glsl_preprocess(self.source, &|path| std::fs::read(parent_dir.join(path))) - .map_err(|err| Error::PreprocessFailed { - source: err, - shader_file: self.file.clone(), - })?; - - Ok(Self { - kind: self.kind, - source: source_preprocessed.into_owned(), - file: self.file.clone(), - }) - } - - #[must_use] - pub fn kind(&self) -> Kind - { - self.kind - } - - #[must_use] - pub fn source(&self) -> &str - { - &self.source - } -} - -/// Shader kind. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Kind -{ - Vertex, - Fragment, -} - -/// Shader error -#[derive(Debug, thiserror::Error)] -pub enum Error -{ - #[error("Failed to read shader {}", shader_file.display())] - ReadFailed - { - #[source] - source: std::io::Error, - shader_file: PathBuf, - }, - - #[error("Shader source is not ASCII")] - SourceNotAscii, - - #[error("Failed to preprocess shader {}", shader_file.display())] - PreprocessFailed - { - #[source] - source: GlslPreprocessingError, - shader_file: PathBuf, - }, - - #[error("Shader source path has no parent")] - SourcePathHasNoParent, -} |