summaryrefslogtreecommitdiff
path: root/engine/src/renderer/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/renderer/mod.rs')
-rw-r--r--engine/src/renderer/mod.rs354
1 files changed, 180 insertions, 174 deletions
diff --git a/engine/src/renderer/mod.rs b/engine/src/renderer/mod.rs
index 839c0d3..304c38b 100644
--- a/engine/src/renderer/mod.rs
+++ b/engine/src/renderer/mod.rs
@@ -1,15 +1,22 @@
use std::collections::HashMap;
-use std::ffi::{c_void, CString};
+use std::ffi::c_void;
use std::process::abort;
use cstr::cstr;
-use glfw::WindowSize;
+use ecs::component::local::Local;
+use ecs::sole::Single;
+use ecs::system::{Into as _, System};
+use ecs::{Component, Query};
+use tracing::warn;
use crate::camera::Camera;
use crate::color::Color;
+use crate::data_types::dimens::Dimens;
+use crate::event::{Present as PresentEvent, Start as StartEvent};
use crate::lighting::LightSource;
+use crate::material::Material;
use crate::matrix::Matrix;
-use crate::object::Object;
+use crate::mesh::Mesh;
use crate::opengl::buffer::{
ArrayKind as ArrayBufferKind,
Buffer,
@@ -33,168 +40,184 @@ 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::texture::{Id as TextureId, Texture};
+use crate::texture::{Id as TextureId, Map as TextureMap, Texture};
+use crate::transform::Transform;
use crate::vector::{Vec2, Vec3};
use crate::vertex::Vertex;
+use crate::window::Window;
-#[derive(Debug)]
-pub struct Renderer<CameraT>
+#[derive(Debug, Default)]
+pub struct Extension {}
+
+impl ecs::extension::Extension for Extension
{
- camera: CameraT,
- shader_programs: HashMap<u64, GlShaderProgram>,
- textures: HashMap<TextureId, GlTexture>,
+ fn collect(self, mut collector: ecs::extension::Collector<'_>)
+ {
+ collector.add_system(StartEvent, initialize);
+
+ collector.add_system(
+ PresentEvent,
+ render.into_system().initialize((GlObjects::default(),)),
+ );
+ }
}
-impl<CameraT> Renderer<CameraT>
-where
- CameraT: Camera,
+fn initialize(window: Single<Window>)
{
- pub fn new(window: &glfw::Window, camera: CameraT) -> Result<Self, Error>
- {
- gl::load_with(|symbol| {
- let proc_name = unsafe { CString::from_vec_unchecked(symbol.into()) };
-
- match window.get_proc_address(proc_name.as_c_str()) {
- Ok(addr) => addr as *const c_void,
- Err(err) => {
- println!(
- "FATAL ERROR: Failed to get adress of OpenGL function {}. {}",
- symbol, err
- );
-
- abort();
- }
- }
- });
+ window
+ .make_context_current()
+ .expect("Failed to make window context current");
+
+ gl::load_with(|symbol| match window.get_proc_address(symbol) {
+ Ok(addr) => addr as *const c_void,
+ Err(err) => {
+ println!(
+ "FATAL ERROR: Failed to get adress of OpenGL function {symbol}: {err}",
+ );
+
+ abort();
+ }
+ });
- #[cfg(feature = "debug")]
- Self::initialize_debug();
+ #[cfg(feature = "debug")]
+ initialize_debug();
- let window_size = window.size().map_err(Error::GetWindowSizeFailed)?;
+ let window_size = window.size().expect("Failed to get window size");
- Self::set_viewport(&Vec2 { x: 0, y: 0 }, &window_size);
+ set_viewport(&Vec2 { x: 0, y: 0 }, window_size);
- enable(Capability::DepthTest);
+ window.set_framebuffer_size_callback(|new_window_size| {
+ set_viewport(&Vec2::ZERO, new_window_size);
+ });
- Ok(Self {
- camera,
- shader_programs: HashMap::new(),
- textures: HashMap::new(),
- })
- }
+ enable(Capability::DepthTest);
+}
- pub fn render<'obj>(
- &mut self,
- objects: impl IntoIterator<Item = &'obj Object>,
- light_source: Option<&LightSource>,
- window_size: &WindowSize,
- ) -> Result<(), Error>
- {
- clear_buffers(BufferClearMask::COLOR | BufferClearMask::DEPTH);
-
- for obj in objects {
- let shader_program = self
- .shader_programs
- .entry(obj.shader().u64_hash())
- .or_insert_with(|| create_gl_shader_program(obj.shader()).unwrap());
-
- shader_program.activate(|shader_program_curr_bound| {
- apply_transformation_matrices(
- obj,
- shader_program,
- &self.camera,
- window_size,
- &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 gl_texture = self
- .textures
- .entry(*texture_id)
- .or_insert_with(|| create_gl_texture(texture));
-
- let texture_unit = TextureUnit::from_texture_id(*texture_id)
- .ok_or(Error::TextureIdIsInvalidTextureUnit)?;
-
- set_active_texture_unit(texture_unit);
-
- gl_texture.bind(|_| {});
- }
-
- Self::draw_object(obj);
-
- Ok::<_, Error>(())
- })?;
+fn render(
+ query: Query<(Mesh, TextureMap, ShaderProgram, Material, Transform)>,
+ light_source_query: Query<(LightSource,)>,
+ camera_query: Query<(Camera,)>,
+ window: Single<Window>,
+ mut gl_objects: Local<GlObjects>,
+)
+{
+ let Some(camera) = camera_query.iter().find_map(|(camera,)| {
+ if !camera.current {
+ return None;
}
- Ok(())
- }
+ Some(camera)
+ }) else {
+ warn!("No current camera. Nothing will be rendered");
+ return;
+ };
- pub fn set_viewport(position: &Vec2<u32>, size: &WindowSize)
- {
- crate::opengl::set_viewport(position, size);
- }
+ let light_source = light_source_query
+ .iter()
+ .next()
+ .map(|(light_source,)| light_source);
+
+ let GlObjects {
+ shader_programs: gl_shader_programs,
+ textures: gl_textures,
+ } = &mut *gl_objects;
+
+ clear_buffers(BufferClearMask::COLOR | BufferClearMask::DEPTH);
+
+ for (mesh, texture_map, shader_program, material, transform) in &query {
+ let shader_program = gl_shader_programs
+ .entry(shader_program.u64_hash())
+ .or_insert_with(|| create_gl_shader_program(&shader_program).unwrap());
+
+ shader_program.activate(|shader_program_curr_bound| {
+ apply_transformation_matrices(
+ &transform,
+ shader_program,
+ &camera,
+ window.size().expect("Failed to get window size"),
+ &shader_program_curr_bound,
+ );
+
+ apply_light(
+ &material,
+ shader_program,
+ light_source.as_deref(),
+ &camera,
+ &shader_program_curr_bound,
+ );
+
+ for (texture_id, texture) in &texture_map.inner {
+ let gl_texture = gl_textures
+ .entry(*texture_id)
+ .or_insert_with(|| create_gl_texture(texture));
+
+ let texture_unit = TextureUnit::from_texture_id(*texture_id)
+ .unwrap_or_else(|| {
+ panic!("Texture id {texture_id} is a invalid texture unit");
+ });
+
+ set_active_texture_unit(texture_unit);
+
+ gl_texture.bind(|_| {});
+ }
- #[must_use]
- pub fn camera(&self) -> &CameraT
- {
- &self.camera
+ draw_mesh(&mesh);
+ });
}
+}
- pub fn camera_mut(&mut self) -> &mut CameraT
- {
- &mut self.camera
- }
+#[derive(Debug, Default, Component)]
+struct GlObjects
+{
+ shader_programs: HashMap<u64, GlShaderProgram>,
+ textures: HashMap<TextureId, GlTexture>,
+}
- #[cfg(feature = "debug")]
- fn initialize_debug()
- {
- use crate::opengl::debug::{
- enable_debug_output,
- set_debug_message_callback,
- set_debug_message_control,
- MessageIdsAction,
- };
+fn set_viewport(position: &Vec2<u32>, size: Dimens<u32>)
+{
+ crate::opengl::set_viewport(position, size);
+}
- enable_debug_output();
+#[cfg(feature = "debug")]
+fn initialize_debug()
+{
+ use crate::opengl::debug::{
+ enable_debug_output,
+ set_debug_message_callback,
+ set_debug_message_control,
+ MessageIdsAction,
+ };
- set_debug_message_callback(opengl_debug_message_cb);
+ enable_debug_output();
- set_debug_message_control(None, None, None, &[], MessageIdsAction::Disable);
- }
+ set_debug_message_callback(opengl_debug_message_cb);
- fn draw_object(obj: &Object)
- {
- // TODO: Creating a new vertex buffer each draw is really dumb and slow this
- // should be rethinked
- let renderable = Renderable::new(obj.mesh().vertices(), obj.mesh().indices());
-
- renderable.vertex_arr.bind(|vert_arr_curr_bound| {
- if let Some(index_info) = &renderable.index_info {
- VertexArray::draw_elements(
- &vert_arr_curr_bound,
- PrimitiveKind::Triangles,
- 0,
- index_info.cnt,
- );
- } else {
- VertexArray::draw_arrays(
- &vert_arr_curr_bound,
- PrimitiveKind::Triangles,
- 0,
- 3,
- );
- }
- });
- }
+ set_debug_message_control(None, None, None, &[], MessageIdsAction::Disable);
+}
+
+fn draw_mesh(mesh: &Mesh)
+{
+ // TODO: Creating a new vertex buffer each draw is really dumb and slow this
+ // should be rethinked
+ let renderable = Renderable::new(mesh.vertices(), mesh.indices());
+
+ renderable.vertex_arr.bind(|vert_arr_curr_bound| {
+ if let Some(index_info) = &renderable.index_info {
+ VertexArray::draw_elements(
+ &vert_arr_curr_bound,
+ PrimitiveKind::Triangles,
+ 0,
+ index_info.cnt,
+ );
+ } else {
+ VertexArray::draw_arrays(
+ &vert_arr_curr_bound,
+ PrimitiveKind::Triangles,
+ 0,
+ 3,
+ );
+ }
+ });
}
fn create_gl_texture(texture: &Texture) -> GlTexture
@@ -204,7 +227,7 @@ fn create_gl_texture(texture: &Texture) -> GlTexture
gl_texture.bind(|texture_curr_bound| {
GlTexture::generate(
&texture_curr_bound,
- &texture.dimensions(),
+ texture.dimensions(),
texture.image().as_bytes(),
texture.pixel_data_format(),
);
@@ -244,7 +267,7 @@ fn create_gl_shader_program(
}
#[derive(Debug)]
-pub struct Renderable
+struct Renderable
{
vertex_arr: VertexArray,
@@ -255,7 +278,7 @@ pub struct Renderable
impl Renderable
{
- pub fn new(vertices: &[Vertex], indices: Option<&[u32]>) -> Self
+ fn new(vertices: &[Vertex], indices: Option<&[u32]>) -> Self
{
let vertex_arr = VertexArray::new();
let vertex_buffer = Buffer::new();
@@ -291,35 +314,18 @@ impl Renderable
}
}
-/// Renderer error.
-#[derive(Debug, thiserror::Error)]
-pub enum Error
-{
- #[error("Failed to get window size")]
- GetWindowSizeFailed(#[source] glfw::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,
+ transform: &Transform,
gl_shader_program: &GlShaderProgram,
- camera: &impl Camera,
- window_size: &WindowSize,
+ camera: &Camera,
+ window_size: Dimens<u32>,
shader_program_curr_bound: &CurrentlyBound<GlShaderProgram>,
)
{
gl_shader_program.set_uniform_matrix_4fv(
shader_program_curr_bound,
cstr!("model"),
- &object.transform().as_matrix(),
+ &transform.as_matrix(),
);
let view = create_view(camera);
@@ -346,10 +352,10 @@ fn apply_transformation_matrices(
}
fn apply_light(
- obj: &Object,
+ material: &Material,
gl_shader_program: &GlShaderProgram,
light_source: Option<&LightSource>,
- camera: &impl Camera,
+ camera: &Camera,
shader_program_curr_bound: &CurrentlyBound<GlShaderProgram>,
)
{
@@ -395,41 +401,41 @@ fn apply_light(
gl_shader_program.set_uniform_1i(
shader_program_curr_bound,
cstr!("material.ambient"),
- obj.material().ambient_map().into_inner() as i32,
+ material.ambient_map().into_inner() as i32,
);
#[allow(clippy::cast_possible_wrap)]
gl_shader_program.set_uniform_1i(
shader_program_curr_bound,
cstr!("material.diffuse"),
- obj.material().diffuse_map().into_inner() as i32,
+ material.diffuse_map().into_inner() as i32,
);
#[allow(clippy::cast_possible_wrap)]
gl_shader_program.set_uniform_1i(
shader_program_curr_bound,
cstr!("material.specular"),
- obj.material().specular_map().into_inner() as i32,
+ material.specular_map().into_inner() as i32,
);
gl_shader_program.set_uniform_1fv(
shader_program_curr_bound,
cstr!("material.shininess"),
- obj.material().shininess(),
+ material.shininess(),
);
gl_shader_program.set_uniform_vec_3fv(
shader_program_curr_bound,
cstr!("view_pos"),
- &camera.position(),
+ &camera.position,
);
}
-fn create_view(camera: &impl Camera) -> Matrix<f32, 4, 4>
+fn create_view(camera: &Camera) -> Matrix<f32, 4, 4>
{
let mut view = Matrix::new();
- view.look_at(&camera.position(), &camera.target(), &camera.global_up());
+ view.look_at(&camera.position, &camera.target, &camera.global_up);
view
}