diff options
Diffstat (limited to 'engine/src/renderer/mod.rs')
-rw-r--r-- | engine/src/renderer/mod.rs | 529 |
1 files changed, 0 insertions, 529 deletions
diff --git a/engine/src/renderer/mod.rs b/engine/src/renderer/mod.rs deleted file mode 100644 index 485c0bb..0000000 --- a/engine/src/renderer/mod.rs +++ /dev/null @@ -1,529 +0,0 @@ -use std::collections::HashMap; -use std::ffi::{c_void, CString}; -use std::process::abort; - -use cstr::cstr; -use ecs::component::local::Local; -use ecs::sole::Single; -use ecs::system::{Into as _, System}; -use ecs::{Component, Query}; - -use crate::camera::Camera; -use crate::data_types::dimens::Dimens; -use crate::event::{Present as PresentEvent, Start as StartEvent}; -use crate::lighting::{GlobalLight, PointLight}; -use crate::material::{Flags as MaterialFlags, Material}; -use crate::matrix::Matrix; -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::shader::{ - Error as GlShaderError, - Program as GlShaderProgram, - Shader as GlShader, -}; -use crate::opengl::texture::{ - set_active_texture_unit, - Texture as GlTexture, - TextureUnit, -}; -use crate::opengl::vertex_array::{ - DataType as VertexArrayDataType, - PrimitiveKind, - VertexArray, -}; -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::Transform; -use crate::vector::Vec2; -use crate::vertex::{AttributeComponentType, Vertex}; -use crate::window::Window; - -#[derive(Debug, Default)] -pub struct Extension {} - -impl ecs::extension::Extension for Extension -{ - fn collect(self, mut collector: ecs::extension::Collector<'_>) - { - collector.add_system(StartEvent, initialize); - - collector.add_system( - PresentEvent, - render.into_system().initialize((GlObjects::default(),)), - ); - } -} - -fn initialize(window: Single<Window>) -{ - 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")] - initialize_debug(); - - let window_size = window.size().expect("Failed to get window size"); - - set_viewport(Vec2 { x: 0, y: 0 }, window_size); - - window.set_framebuffer_size_callback(|new_window_size| { - set_viewport(Vec2::ZERO, new_window_size); - }); - - enable(Capability::DepthTest); -} - -fn render( - query: Query<( - Mesh, - ShaderProgram, - Material, - Option<MaterialFlags>, - Transform, - )>, - point_light_query: Query<(PointLight, Transform)>, - camera_query: Query<(Camera,)>, - window: Single<Window>, - global_light: Single<GlobalLight>, - mut gl_objects: Local<GlObjects>, -) -{ - let Some(camera) = camera_query.iter().find_map(|(camera,)| { - if !camera.current { - return None; - } - - Some(camera) - }) else { - #[cfg(feature = "debug")] - tracing::warn!("No current camera. Nothing will be rendered"); - return; - }; - - // TODO: Maybe find a way to not clone here? Cloning here is needed since a transform - // can be in both the object query and the light source query - let point_lights = point_light_query - .iter() - .map(|(point_light, transform)| ((*point_light).clone(), (*transform).clone())) - .collect::<Vec<_>>(); - - let GlObjects { - shader_programs: gl_shader_programs, - textures: gl_textures, - } = &mut *gl_objects; - - clear_buffers(BufferClearMask::COLOR | BufferClearMask::DEPTH); - - for (mesh, shader_program, material, material_flags, transform) in &query { - 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()); - - apply_transformation_matrices( - &transform, - shader_program, - &camera, - window.size().expect("Failed to get window size"), - ); - - apply_light( - &material, - &material_flags, - &global_light, - shader_program, - point_lights.as_slice(), - &camera, - ); - - for texture in &material.textures { - 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 {} is a invalid texture unit", texture.id()); - }); - - set_active_texture_unit(texture_unit); - - gl_texture.bind(); - } - - shader_program.activate(); - - draw_mesh(&mesh); - } -} - -#[derive(Debug, Default, Component)] -struct GlObjects -{ - shader_programs: HashMap<u64, GlShaderProgram>, - textures: HashMap<TextureId, GlTexture>, -} - -fn set_viewport(position: Vec2<u32>, size: Dimens<u32>) -{ - crate::opengl::set_viewport(position, size); -} - -#[cfg(feature = "debug")] -fn initialize_debug() -{ - use crate::opengl::debug::{ - enable_debug_output, - set_debug_message_callback, - set_debug_message_control, - MessageIdsAction, - }; - - enable_debug_output(); - - set_debug_message_callback(opengl_debug_message_cb); - - 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(); - - if let Some(index_info) = &renderable.index_info { - VertexArray::draw_elements(PrimitiveKind::Triangles, 0, index_info.cnt); - } else { - VertexArray::draw_arrays(PrimitiveKind::Triangles, 0, 3); - } -} - -fn create_gl_texture(texture: &Texture) -> GlTexture -{ - let mut gl_texture = GlTexture::new(); - - gl_texture.generate( - *texture.dimensions(), - texture.image().as_bytes(), - texture.pixel_data_format(), - ); - - gl_texture.apply_properties(texture.properties()); - - gl_texture -} - -fn create_gl_shader_program( - shader_program: &ShaderProgram, -) -> Result<GlShaderProgram, GlShaderError> -{ - let gl_shaders = shader_program - .shaders() - .iter() - .map(|shader| { - let gl_shader = GlShader::new(shader.kind()); - - gl_shader.set_source(shader.source())?; - gl_shader.compile()?; - - Ok(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()?; - - Ok(gl_shader_program) -} - -#[derive(Debug)] -struct Renderable -{ - vertex_arr: VertexArray, - - /// Vertex and index buffer has to live as long as the vertex array - _vertex_buffer: Buffer<Vertex>, - index_info: Option<IndexInfo>, -} - -impl Renderable -{ - fn new(vertices: &[Vertex], indices: Option<&[u32]>) -> Self - { - let mut vertex_arr = VertexArray::new(); - let mut vertex_buffer = Buffer::new(); - - let mut index_info = None; - - vertex_buffer.store(vertices, BufferUsage::Static); - - vertex_arr.bind_vertex_buffer(0, &vertex_buffer, 0); - - let mut offset = 0u32; - - for attrib in Vertex::attrs() { - vertex_arr.enable_attrib(attrib.index); - - vertex_arr.set_attrib_format( - attrib.index, - match attrib.component_type { - AttributeComponentType::Float => VertexArrayDataType::Float, - }, - false, - offset, - ); - - vertex_arr.set_attrib_vertex_buf_binding(attrib.index, 0); - - offset += attrib.component_size * attrib.component_cnt as u32; - } - - if let Some(indices) = indices { - let mut index_buffer = Buffer::new(); - - index_buffer.store(indices, BufferUsage::Static); - - vertex_arr.bind_element_buffer(&index_buffer); - - index_info = Some(IndexInfo { - _buffer: index_buffer, - cnt: indices.len().try_into().unwrap(), - }); - } - - Self { - vertex_arr, - _vertex_buffer: vertex_buffer, - index_info, - } - } -} - -fn apply_transformation_matrices( - transform: &Transform, - gl_shader_program: &mut GlShaderProgram, - camera: &Camera, - window_size: Dimens<u32>, -) -{ - gl_shader_program.set_uniform_matrix_4fv(cstr!("model"), &transform.as_matrix()); - - let view = create_view(camera); - - gl_shader_program.set_uniform_matrix_4fv(cstr!("view"), &view); - - #[allow(clippy::cast_precision_loss)] - let projection = match &camera.projection { - Projection::Perspective(perspective) => new_perspective_matrix( - perspective, - window_size.width as f32 / window_size.height as f32, - ), - }; - - gl_shader_program.set_uniform_matrix_4fv(cstr!("projection"), &projection); -} - -fn apply_light( - material: &Material, - material_flags: &MaterialFlags, - global_light: &GlobalLight, - gl_shader_program: &mut GlShaderProgram, - point_lights: &[(PointLight, Transform)], - camera: &Camera, -) -{ - debug_assert!( - point_lights.len() < 64, - "Shader cannot handle more than 64 point lights" - ); - - for (point_light_index, (point_light, point_light_transform)) in - point_lights.iter().enumerate() - { - set_point_light_uniforms( - gl_shader_program, - point_light_index, - point_light, - point_light_transform, - ) - } - - gl_shader_program.set_uniform_1i(cstr!("point_light_cnt"), point_lights.len() as i32); - - gl_shader_program.set_uniform_vec_3fv( - cstr!("material.ambient"), - &if material_flags.use_ambient_color { - material.ambient.clone() - } else { - global_light.ambient.clone().into() - } - .into(), - ); - - gl_shader_program - .set_uniform_vec_3fv(cstr!("material.diffuse"), &material.diffuse.clone().into()); - - #[allow(clippy::cast_possible_wrap)] - gl_shader_program.set_uniform_vec_3fv( - cstr!("material.specular"), - &material.specular.clone().into(), - ); - - #[allow(clippy::cast_possible_wrap)] - gl_shader_program.set_uniform_1i( - cstr!("material.ambient_map"), - material.ambient_map.into_inner() as i32, - ); - - #[allow(clippy::cast_possible_wrap)] - gl_shader_program.set_uniform_1i( - cstr!("material.diffuse_map"), - material.diffuse_map.into_inner() as i32, - ); - - #[allow(clippy::cast_possible_wrap)] - gl_shader_program.set_uniform_1i( - cstr!("material.specular_map"), - material.specular_map.into_inner() as i32, - ); - - gl_shader_program.set_uniform_1fv(cstr!("material.shininess"), material.shininess); - - gl_shader_program.set_uniform_vec_3fv(cstr!("view_pos"), &camera.position); -} - -fn set_point_light_uniforms( - gl_shader_program: &mut GlShaderProgram, - point_light_index: usize, - point_light: &PointLight, - point_light_transform: &Transform, -) -{ - gl_shader_program.set_uniform_vec_3fv( - &create_point_light_uniform_name(point_light_index, "position"), - &point_light_transform.position, - ); - - gl_shader_program.set_uniform_vec_3fv( - &create_point_light_uniform_name(point_light_index, "diffuse"), - &point_light.diffuse.clone().into(), - ); - - gl_shader_program.set_uniform_vec_3fv( - &create_point_light_uniform_name(point_light_index, "specular"), - &point_light.specular.clone().into(), - ); - - gl_shader_program.set_uniform_1fv( - &create_point_light_uniform_name(point_light_index, "constant"), - point_light.attenuation_params.constant, - ); - - gl_shader_program.set_uniform_1fv( - &create_point_light_uniform_name(point_light_index, "linear"), - point_light.attenuation_params.linear, - ); - - gl_shader_program.set_uniform_1fv( - &create_point_light_uniform_name(point_light_index, "quadratic"), - point_light.attenuation_params.quadratic, - ); -} - -fn create_point_light_uniform_name( - point_light_index: usize, - point_light_field: &str, -) -> CString -{ - unsafe { - CString::from_vec_with_nul_unchecked( - format!("point_lights[{point_light_index}].{point_light_field}\0").into(), - ) - } -} - -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 -} - -#[cfg(feature = "debug")] -#[tracing::instrument(skip_all)] -fn opengl_debug_message_cb( - source: MessageSource, - ty: MessageType, - id: u32, - severity: MessageSeverity, - message: &str, -) -{ - use std::backtrace::{Backtrace, BacktraceStatus}; - - use tracing::{event, Level}; - - macro_rules! create_event { - ($level: expr) => { - event!($level, ?source, ?ty, id, ?severity, message); - }; - } - - if matches!(severity, MessageSeverity::Notification) { - return; - } - - match ty { - MessageType::Error => { - create_event!(Level::ERROR); - - let backtrace = Backtrace::capture(); - - if matches!(backtrace.status(), BacktraceStatus::Captured) { - event!(Level::TRACE, "{backtrace}"); - } - } - MessageType::Other => { - create_event!(Level::INFO); - } - _ => { - create_event!(Level::WARN); - } - }; -} - -#[derive(Debug)] -struct IndexInfo -{ - _buffer: Buffer<u32>, - cnt: u32, -} |