From b414b3e2ce8ea515915dc8798790d37b57d81441 Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 23 May 2024 19:12:53 +0200 Subject: refactor(engine): rename renderer module to opengl.rs --- engine/src/renderer.rs | 1 + engine/src/renderer/mod.rs | 529 ----------------------------------------- engine/src/renderer/opengl.rs | 531 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 532 insertions(+), 529 deletions(-) create mode 100644 engine/src/renderer.rs delete mode 100644 engine/src/renderer/mod.rs create mode 100644 engine/src/renderer/opengl.rs (limited to 'engine/src') diff --git a/engine/src/renderer.rs b/engine/src/renderer.rs new file mode 100644 index 0000000..2544919 --- /dev/null +++ b/engine/src/renderer.rs @@ -0,0 +1 @@ +pub mod opengl; 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 - .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, - Transform, - )>, - point_light_query: Query<(PointLight, Transform)>, - camera_query: Query<(Camera,)>, - window: Single, - global_light: Single, - mut gl_objects: Local, -) -{ - 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::>(); - - 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, - textures: HashMap, -} - -fn set_viewport(position: Vec2, size: Dimens) -{ - 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 -{ - 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::, _>>()?; - - 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, - index_info: Option, -} - -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, -) -{ - 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 -{ - 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, - cnt: u32, -} diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs new file mode 100644 index 0000000..c97d8dd --- /dev/null +++ b/engine/src/renderer/opengl.rs @@ -0,0 +1,531 @@ +//! OpenGL renderer. + +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 + .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, + Transform, + )>, + point_light_query: Query<(PointLight, Transform)>, + camera_query: Query<(Camera,)>, + window: Single, + global_light: Single, + mut gl_objects: Local, +) +{ + 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::>(); + + 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, + textures: HashMap, +} + +fn set_viewport(position: Vec2, size: Dimens) +{ + 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 +{ + 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::, _>>()?; + + 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, + index_info: Option, +} + +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, +) +{ + 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 +{ + 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, + cnt: u32, +} -- cgit v1.2.3-18-g5258