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.rs529
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,
-}