summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-11-23 21:32:03 +0100
committerHampusM <hampus@hampusmat.com>2024-11-23 21:32:03 +0100
commitdaf280048d82eed42d44423ce50ae9e809ba91a9 (patch)
treefdd1580b3c50f2f7cebc5175b38777a7117c904f
parent999264a46f9a545771c6710b0893ca32cf6e7ee3 (diff)
refactor(engine): make shaders a renderer detail
-rw-r--r--engine/src/lib.rs1
-rw-r--r--engine/src/opengl/shader.rs17
-rw-r--r--engine/src/renderer/opengl.rs99
-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.rs188
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,
-}