From 977c22a5118d26374017b61a329124ae9381557f Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 3 Sep 2026 22:53:52 +0200 Subject: refactor(engine): split up main render pass fn into more functions --- engine/src/rendering/main_render_pass.rs | 956 ++++++++++++++++++------------- 1 file changed, 556 insertions(+), 400 deletions(-) diff --git a/engine/src/rendering/main_render_pass.rs b/engine/src/rendering/main_render_pass.rs index 3748d2e..7364024 100644 --- a/engine/src/rendering/main_render_pass.rs +++ b/engine/src/rendering/main_render_pass.rs @@ -3,12 +3,13 @@ use std::sync::LazyLock; use ecs::actions::Actions; use ecs::component::local::Local; +use ecs::error::Context as _; use ecs::pair::ChildOf; use ecs::query::term::{Traverse, TraverseUp}; use ecs::uid::Uid; use ecs::Component; -use crate::asset::{Assets, Id as AssetId, Label as AssetLabel}; +use crate::asset::{Assets, Label as AssetLabel}; use crate::camera::{Active as ActiveCamera, Camera}; use crate::color::Rgba; use crate::data_types::dimens::{Dimens, Dimens3}; @@ -16,6 +17,7 @@ use crate::draw_flags::{DrawFlags, NoDraw, PolygonModeConfig}; use crate::ecs::query::term::{With, Without}; use crate::ecs::sole::Single; use crate::ecs::Query; +use crate::error; use crate::image::Image; use crate::lighting::{ DirectionalLight, @@ -92,8 +94,6 @@ struct SkyBoxIds { texture_object: ObjectId, mesh_object: ObjectId, - shader_object: ObjectId, - shader_asset: AssetId, } #[derive(Debug, Default, Component)] @@ -152,81 +152,73 @@ pub fn add_main_render_pass( return Ok(()); }; - let Some(main_3d_shader_asset) = assets - .get_handle_to_loaded::(MAIN_3D_SHADER_ASSET_LABEL.clone()) - else { - assets.store_with_label( - MAIN_3D_SHADER_ASSET_LABEL.clone(), - ShaderModuleSource { - name: "main_3d_shader.slang".into(), - file_path: Path::new("@engine/main_3d_shader").into(), - source: include_str!("../../res/main_3d_shader.slang").into(), - link_entrypoints: ShaderEntrypointFlags::VERTEX - | ShaderEntrypointFlags::FRAGMENT, - }, - ); - - // shader has to be processed - - return Ok(()); - }; - let render_pass = render_passes.passes.push_front_mut(RenderPass { commands: Vec::with_capacity(30), draw_properties: DrawProperties::default(), }); - for (window, window_surface) in &window_query { - render_pass - .commands - .push(Command::MakeCurrent(window_surface.id)); + for (model, ..) in &renderable_query { + add_renderable_creation_commands(assets, object_store, render_pass, &model); + } - let white_1x1_tex_obj_id = - *misc_object_ids.white_1x1_tex_obj_id.get_or_insert_with(|| { - let white_1x1_tex_obj_id = ObjectId::new_sequential(); + let shaders = + match get_or_create_shaders(assets, shader_context, object_store, render_pass) { + Ok(ShadersCreationStatus::Ready(ready_shaders)) => ready_shaders, + Ok(ShadersCreationStatus::ProcessingRequired) => return Ok(()), + Err(err) => { + tracing::error!("Failed to create shaders: {err}"); + return Ok(()); + } + }; - object_store.insert_pending(white_1x1_tex_obj_id); + let white_1x1_tex_obj_id = + *misc_object_ids.white_1x1_tex_obj_id.get_or_insert_with(|| { + create_white_1x1_texture_object(object_store, render_pass) + }); - render_pass.commands.push(Command::CreateTexture { - obj_id: white_1x1_tex_obj_id, - pixel_data_format: TexturePixelDataFormat::Rgba( - RgbaTextureDataType::UnsignedByte, - ), - creation: TextureCreation::Texture2D { - size: Dimens { width: 1, height: 1 }, - image: Some( - Image::from_color( - Rgba::::white(), - Dimens { width: 1, height: 1 }, - ) - .into_bytes() - .into_boxed_slice(), - ), - }, - properties: TextureProperties::default(), - }); + let main_3d_shader_cursor = ShaderCursor::new( + shaders + .main_3d_shader_program + .reflection(0) + .context("Unable to get reflection for main 3D shader")? + .global_params_var_layout() + .ok_or_else(|| { + crate::Error::message( + "Unable to get reflection for main 3D shader's global parameters", + ) + })?, + ); - white_1x1_tex_obj_id - }); + add_set_3d_shader_point_light_bindings( + render_pass, + &point_light_query, + shaders.main_3d_shader_obj_id, + &main_3d_shader_cursor, + )?; - let sky_box_ids = if let Some(scene_skybox) = &scene_skybox { - load_sky_box( - scene_ent_id, - &scene_skybox, - scene_skybox_state.as_deref(), - assets, - object_store, - shader_context, - render_pass, - &mut actions, - )? - } else { - None - }; + add_set_3d_shader_dir_lights_bindings( + render_pass, + &directional_light_query, + shaders.main_3d_shader_obj_id, + &main_3d_shader_cursor, + )?; + + for (window, window_surface) in &window_query { + render_pass + .commands + .push(Command::MakeCurrent(window_surface.id)); + + add_set_3d_shader_camera_bindings( + render_pass, + (&camera, &camera_transform), + &window, + shaders.main_3d_shader_obj_id, + &main_3d_shader_cursor, + )?; let mut buf_clear_mask = BufferClearMask::DEPTH; - buf_clear_mask.set(BufferClearMask::COLOR, sky_box_ids.is_none()); + buf_clear_mask.set(BufferClearMask::COLOR, scene_skybox.is_none()); render_pass .commands @@ -245,17 +237,13 @@ pub fn add_main_render_pass( continue; } - debug_assert!(model_spec.material_names.len() <= 1); - let model_material = match model_spec.find_first_material(&assets) { - MaterialSearchResult::Found(model_material_asset) => { - let Some(model_material) = assets.get(&model_material_asset) else { - continue; - }; - + MaterialSearchResult::Found(model_material_asset) + if let Some(model_material) = assets.get(&model_material_asset) => + { model_material } - MaterialSearchResult::NotFound => { + MaterialSearchResult::Found(_) | MaterialSearchResult::NotFound => { continue; } MaterialSearchResult::NoMaterials => &Material::builder().build(), @@ -268,83 +256,7 @@ pub fn add_main_render_pass( continue; } - let Some(shader_program) = - shader_context.get_program(&main_3d_shader_asset.id()) - else { - tracing::error!( - "Shader context doesn't have a program for shader asset {:?}", - assets.get_label(&main_3d_shader_asset) - ); - continue; - }; - - if !object_store.contains_maybe_pending_with_id(&ObjectId::Asset( - main_3d_shader_asset.id(), - )) { - object_store.insert_pending(ObjectId::Asset(main_3d_shader_asset.id())); - - render_pass.commands.push(Command::CreateShaderProgram( - ObjectId::Asset(main_3d_shader_asset.id()), - shader_program.clone(), - )); - } - - render_pass - .commands - .push(Command::ActivateShader(ObjectId::Asset( - main_3d_shader_asset.id(), - ))); - - for texture_asset in [ - &model_material.ambient_map, - &model_material.diffuse_map, - &model_material.specular_map, - ] - .into_iter() - .flatten() - { - let Some(texture) = assets.get(texture_asset) else { - continue; - }; - - let Texture::Texture2D(texture) = texture else { - tracing::error!( - texture_asset_id = ?texture_asset.id(), - texture_asset_label = ?assets.get_label(texture_asset), - "Material texture map is not 2D" - ); - continue; - }; - - let texture_object_id = ObjectId::Asset(texture_asset.id()); - - if object_store.contains_maybe_pending_with_id(&texture_object_id) { - continue; - } - - let Some(tex_pixel_data_format) = - TexturePixelDataFormat::for_image(&texture.image) - else { - tracing::error!( - "No texture pixel data format is available for image" - ); - continue; - }; - - object_store.insert_pending(texture_object_id); - - render_pass.commands.push(Command::CreateTexture { - obj_id: texture_object_id, - pixel_data_format: tex_pixel_data_format, - creation: TextureCreation::Texture2D { - size: texture.image.dimensions(), - image: Some(texture.image.as_bytes().to_vec().into_boxed_slice()), - }, - properties: texture.properties.clone(), - }); - } - - add_set_3d_shader_bindings( + add_set_3d_shader_renderable_bindings( render_pass, ( model_material, @@ -352,15 +264,15 @@ pub fn add_main_render_pass( transform.as_deref(), ), scene_env_lighting.as_deref(), - (&camera, &camera_transform), - &window, - &point_light_query, - &directional_light_query, - shader_program, - ObjectId::Asset(main_3d_shader_asset.id()), + shaders.main_3d_shader_obj_id, + &main_3d_shader_cursor, white_1x1_tex_obj_id, )?; + render_pass + .commands + .push(Command::ActivateShader(shaders.main_3d_shader_obj_id)); + if let Some(draw_flags) = draw_flags.as_deref().and_then(|draw_flags| { if draw_flags.polygon_mode_config != PolygonModeConfig::default() { Some(draw_flags) @@ -377,18 +289,6 @@ pub fn add_main_render_pass( )); } - if !object_store - .contains_maybe_pending_with_id(&ObjectId::Asset(mesh_asset.id())) - { - object_store.insert_pending(ObjectId::Asset(mesh_asset.id())); - - render_pass.commands.push(Command::CreateMesh { - obj_id: ObjectId::Asset(mesh_asset.id()), - mesh: AssetOrValue::Asset(mesh_asset.clone()), - usage: MeshUsage::Static, - }); - } - render_pass.commands.push(Command::DrawMesh( ObjectId::Asset(mesh_asset.id()), DrawMeshOptions::default(), @@ -407,117 +307,425 @@ pub fn add_main_render_pass( } } - if let Some(sky_box_ids) = &sky_box_ids { - render_pass - .commands - .push(Command::ActivateShader(sky_box_ids.shader_object)); - - let Some(sky_box_shader_program) = - shader_context.get_program(&sky_box_ids.shader_asset) + if let Some(scene_skybox) = &scene_skybox { + let Some(sky_box_ids) = load_sky_box( + scene_ent_id, + &scene_skybox, + scene_skybox_state.as_deref(), + assets, + object_store, + render_pass, + &mut actions, + )? else { - unreachable!(); + continue; }; - let sky_box_shader_cursor = ShaderCursor::new( - sky_box_shader_program - .reflection(0) - .unwrap() - .global_params_var_layout() - .unwrap(), - ); + add_sky_box_commands( + render_pass, + &sky_box_ids, + &camera, + &camera_transform, + &window, + shaders.sky_box_shader_obj_id, + shaders.sky_box_shader_program, + )?; + } + } - let mut view = camera.to_view_matrix(camera_transform.position); - - view.translate(&Vec3 { x: 0.0, y: 0.0, z: 0.0 }); - - let sky_box_shader_bindings = [ - sky_box_shader_cursor - .field("Uniforms") - .field("projection") - .binding( - (match camera.projection { - Projection::Perspective(_) => camera.projection.to_matrix_rh( - window.inner_size, - ProjectionClipVolume::NegOneToOne, - ), - Projection::Orthographic(_) => { - // A orthographic projection cannot be used for a sky box - Perspective::default().to_matrix_rh( - window.inner_size.width as f32 - / window.inner_size.height as f32, - ProjectionClipVolume::NegOneToOne, - ) - } - }) - .into(), - )?, - sky_box_shader_cursor - .field("Uniforms") - .field("view") - .binding(view.into())?, - sky_box_shader_cursor.field("cube_texture").binding( - ShaderBindingValue::Texture( - sky_box_ids.texture_object, - ShaderBindingTextureKind::Cube, - ), - )?, - ]; + Ok(()) +} - for binding in sky_box_shader_bindings { - render_pass.commands.push(Command::SetShaderBinding( - sky_box_ids.shader_object, - binding, - )); - } +fn create_white_1x1_texture_object( + object_store: &mut ObjectStore, + render_pass: &mut RenderPass, +) -> ObjectId +{ + let white_1x1_tex_obj_id = ObjectId::new_sequential(); + + object_store.insert_pending(white_1x1_tex_obj_id); + + render_pass.commands.push(Command::CreateTexture { + obj_id: white_1x1_tex_obj_id, + pixel_data_format: TexturePixelDataFormat::Rgba( + RgbaTextureDataType::UnsignedByte, + ), + creation: TextureCreation::Texture2D { + size: Dimens { width: 1, height: 1 }, + image: Some( + Image::from_color(Rgba::::white(), Dimens { width: 1, height: 1 }) + .into_bytes() + .into_boxed_slice(), + ), + }, + properties: TextureProperties::default(), + }); + + white_1x1_tex_obj_id +} + +#[derive(Debug)] +enum ShadersCreationStatus<'shader_ctx> +{ + ProcessingRequired, + Ready(ReadyShaders<'shader_ctx>), +} + +#[derive(Debug)] +struct ReadyShaders<'shader_ctx> +{ + main_3d_shader_obj_id: ObjectId, + main_3d_shader_program: &'shader_ctx ShaderProgram, + sky_box_shader_obj_id: ObjectId, + sky_box_shader_program: &'shader_ctx ShaderProgram, +} + +fn get_or_create_shaders<'shader_ctx>( + assets: &mut Assets, + shader_context: &'shader_ctx ShaderContext, + object_store: &mut ObjectStore, + render_pass: &mut RenderPass, +) -> Result, crate::Error> +{ + let main_3d_shader_asset = assets + .get_handle_to_loaded::(MAIN_3D_SHADER_ASSET_LABEL.clone()) + .or_else(|| { + assets.store_with_label( + MAIN_3D_SHADER_ASSET_LABEL.clone(), + ShaderModuleSource { + name: "main_3d_shader.slang".into(), + file_path: Path::new("@engine/main_3d_shader").into(), + source: include_str!("../../res/main_3d_shader.slang").into(), + link_entrypoints: ShaderEntrypointFlags::VERTEX + | ShaderEntrypointFlags::FRAGMENT, + }, + ); - render_pass.commands.push(Command::UpdateDrawProperties( - DrawProperties { - depth_function: DepthFunction::LessOrEqual, - ..Default::default() + None + }); + + let sky_box_shader_asset = assets + .get_handle_to_loaded::(SKY_BOX_SHADER_ASSET_LABEL.clone()) + .or_else(|| { + assets.store_with_label( + SKY_BOX_SHADER_ASSET_LABEL.clone(), + ShaderModuleSource { + name: "sky_box_shader.slang".into(), + file_path: Path::new("@engine/sky_box_shader").into(), + source: include_str!("../../res/sky_box_shader.slang").into(), + link_entrypoints: ShaderEntrypointFlags::VERTEX + | ShaderEntrypointFlags::FRAGMENT, }, - DrawPropertiesUpdateFlags::DEPTH_FUNCTION, - )); + ); + None + }); - render_pass.commands.push(Command::DrawMesh( - sky_box_ids.mesh_object, - DrawMeshOptions::default(), - )); + let (Some(main_3d_shader_asset), Some(sky_box_shader_asset)) = + (main_3d_shader_asset, sky_box_shader_asset) + else { + return Ok(ShadersCreationStatus::ProcessingRequired); + }; + + let main_3d_shader_program = shader_context.get_program(&main_3d_shader_asset.id()); + + let main_3d_shader_program = main_3d_shader_program.ok_or_else(|| { + error!("Shader context doesn't have a program for main 3D shader") + })?; + + let main_3d_shader_obj_id = ObjectId::Asset(main_3d_shader_asset.id()); + + if !object_store.contains_maybe_pending_with_id(&main_3d_shader_obj_id) { + object_store.insert_pending(main_3d_shader_obj_id); + + render_pass.commands.push(Command::CreateShaderProgram( + main_3d_shader_obj_id, + main_3d_shader_program.clone(), + )); + } + + let sky_box_shader_program = shader_context.get_program(&sky_box_shader_asset.id()); + + let sky_box_shader_program = sky_box_shader_program.ok_or_else(|| { + error!("Shader context doesn't have a program for sky box shader") + })?; + + let sky_box_shader_obj_id = ObjectId::Asset(sky_box_shader_asset.id()); + + if !object_store.contains_maybe_pending_with_id(&sky_box_shader_obj_id) { + object_store.insert_pending(sky_box_shader_obj_id); + + render_pass.commands.push(Command::CreateShaderProgram( + sky_box_shader_obj_id, + sky_box_shader_program.clone(), + )); + } + + Ok(ShadersCreationStatus::Ready(ReadyShaders { + main_3d_shader_obj_id, + main_3d_shader_program, + sky_box_shader_obj_id, + sky_box_shader_program, + })) +} + +fn add_renderable_creation_commands( + assets: &Assets, + object_store: &mut ObjectStore, + render_pass: &mut RenderPass, + model: &Model, +) +{ + let Some(model_spec) = assets.get(&model.spec_asset) else { + return; + }; + + let Some(mesh_asset) = &model_spec.mesh_asset else { + return; + }; + + if assets.get(mesh_asset).is_none() { + return; + } + + debug_assert!(model_spec.material_names.len() <= 1); + + let model_material = match model_spec.find_first_material(&assets) { + MaterialSearchResult::Found(model_material_asset) => { + let Some(model_material) = assets.get(&model_material_asset) else { + return; + }; + + model_material + } + MaterialSearchResult::NotFound => { + return; + } + MaterialSearchResult::NoMaterials => &Material::builder().build(), + }; + + for texture_asset in model_material.textures() { + let Some(texture) = assets.get(texture_asset) else { + return; + }; + + let Texture::Texture2D(texture) = texture else { + tracing::error!( + texture_asset_id = ?texture_asset.id(), + texture_asset_label = ?assets.get_label(texture_asset), + "Material texture map is not 2D" + ); + return; + }; + + let texture_object_id = ObjectId::Asset(texture_asset.id()); + + if object_store.contains_maybe_pending_with_id(&texture_object_id) { + return; } + + let Some(tex_pixel_data_format) = + TexturePixelDataFormat::for_image(&texture.image) + else { + tracing::error!("No texture pixel data format is available for image"); + return; + }; + + object_store.insert_pending(texture_object_id); + + render_pass.commands.push(Command::CreateTexture { + obj_id: texture_object_id, + pixel_data_format: tex_pixel_data_format, + creation: TextureCreation::Texture2D { + size: texture.image.dimensions(), + image: Some(texture.image.as_bytes().to_vec().into_boxed_slice()), + }, + properties: texture.properties.clone(), + }); } - Ok(()) + if !object_store.contains_maybe_pending_with_id(&ObjectId::Asset(mesh_asset.id())) { + object_store.insert_pending(ObjectId::Asset(mesh_asset.id())); + + render_pass.commands.push(Command::CreateMesh { + obj_id: ObjectId::Asset(mesh_asset.id()), + mesh: AssetOrValue::Asset(mesh_asset.clone()), + usage: MeshUsage::Static, + }); + } } -fn add_set_3d_shader_bindings( +fn add_set_3d_shader_point_light_bindings( render_pass: &mut RenderPass, - renderable: (&Material, Option<&MaterialFlags>, Option<&Transform>), - scene_env_lighting: Option<&EnvironmentalLighting>, - (camera, camera_transform): (&Camera, &Transform), - window: &Window, point_light_query: &Query<( &PointLight, &Transform, Traverse<(With, With), TraverseUp, ChildOf>, )>, + main_3d_shader_obj_id: ObjectId, + main_3d_shader_cursor: &ShaderCursor<'_>, +) -> Result<(), crate::Error> +{ + let lighting_shader_cursor = + main_3d_shader_cursor.field("Uniforms").field("lighting"); + + render_pass + .commands + .reserve(1 + point_light_query.iter().count() * 6); + + render_pass.commands.push(Command::SetShaderBinding( + main_3d_shader_obj_id, + lighting_shader_cursor.field("point_light_cnt").binding( + u32::try_from(point_light_query.iter().count()) + .expect("Point light count does not fit in 32-bit unsigned integer") + .into(), + )?, + )); + + for (point_light_index, (point_light, point_light_transform)) in + point_light_query.iter().enumerate() + { + let point_light_shader_cursor = lighting_shader_cursor + .field("point_lights") + .element(point_light_index); + + let phong_shader_cursor = point_light_shader_cursor.field("phong"); + + let attenuation_props_shader_cursor = + point_light_shader_cursor.field("attenuation_props"); + + render_pass.commands.extend( + [ + phong_shader_cursor + .field("diffuse") + .binding(point_light.diffuse.to_rgb_lossy().into())?, + phong_shader_cursor + .field("specular") + .binding(point_light.specular.to_rgb_lossy().into())?, + point_light_shader_cursor.field("position").binding( + (point_light_transform.position + point_light.local_position).into(), + )?, + attenuation_props_shader_cursor + .field("constant") + .binding(point_light.attenuation_params.constant.into())?, + attenuation_props_shader_cursor + .field("linear") + .binding(point_light.attenuation_params.linear.into())?, + attenuation_props_shader_cursor + .field("quadratic") + .binding(point_light.attenuation_params.quadratic.into())?, + ] + .map(|binding| Command::SetShaderBinding(main_3d_shader_obj_id, binding)), + ); + } + + Ok(()) +} + +fn add_set_3d_shader_dir_lights_bindings( + render_pass: &mut RenderPass, directional_light_query: &Query<( &DirectionalLight, Traverse<(With, With), TraverseUp, ChildOf>, )>, - shader_program: &ShaderProgram, - shader_object_id: ObjectId, - white_1x1_tex_obj_id: ObjectId, + main_3d_shader_obj_id: ObjectId, + main_3d_shader_cursor: &ShaderCursor<'_>, ) -> Result<(), crate::Error> { - let (material, material_flags, transform) = renderable; + let lighting_shader_cursor = + main_3d_shader_cursor.field("Uniforms").field("lighting"); - let shader_cursor = ShaderCursor::new( - shader_program - .reflection(0) - .unwrap() - .global_params_var_layout() - .unwrap(), + render_pass + .commands + .reserve(1 + directional_light_query.iter().count() * 3); + + render_pass.commands.push(Command::SetShaderBinding( + main_3d_shader_obj_id, + lighting_shader_cursor + .field("directional_light_cnt") + .binding( + u32::try_from(directional_light_query.iter().count()) + .expect( + "Directional light count does not fit in 32-bit unsigned integer", + ) + .into(), + )?, + )); + + for (directional_light_index, (directional_light,)) in + directional_light_query.iter().enumerate() + { + let directional_light_shader_cursor = lighting_shader_cursor + .field("directional_lights") + .element(directional_light_index); + + let phong_shader_cursor = directional_light_shader_cursor.field("phong"); + + render_pass.commands.extend( + [ + phong_shader_cursor + .field("diffuse") + .binding(directional_light.diffuse.to_rgb_lossy().into())?, + phong_shader_cursor + .field("specular") + .binding(directional_light.specular.to_rgb_lossy().into())?, + directional_light_shader_cursor + .field("direction") + .binding(directional_light.direction.into())?, + ] + .map(|binding| Command::SetShaderBinding(main_3d_shader_obj_id, binding)), + ); + } + + Ok(()) +} + +fn add_set_3d_shader_camera_bindings( + render_pass: &mut RenderPass, + (camera, camera_transform): (&Camera, &Transform), + window: &Window, + main_3d_shader_obj_id: ObjectId, + main_3d_shader_cursor: &ShaderCursor<'_>, +) -> Result<(), crate::Error> +{ + let model_3d_shader_cursor = + main_3d_shader_cursor.field("Uniforms").field("model_3d"); + + let lighting_shader_cursor = + main_3d_shader_cursor.field("Uniforms").field("lighting"); + + render_pass.commands.extend( + [ + model_3d_shader_cursor + .field("view") + .binding(camera.to_view_matrix(camera_transform.position).into())?, + model_3d_shader_cursor.field("projection").binding( + camera + .projection + .to_matrix_rh(window.inner_size, ProjectionClipVolume::NegOneToOne) + .into(), + )?, + lighting_shader_cursor + .field("view_pos") + .binding(camera_transform.position.into())?, + ] + .into_iter() + .map(|binding| Command::SetShaderBinding(main_3d_shader_obj_id, binding)), ); + Ok(()) +} + +fn add_set_3d_shader_renderable_bindings( + render_pass: &mut RenderPass, + renderable: (&Material, Option<&MaterialFlags>, Option<&Transform>), + scene_env_lighting: Option<&EnvironmentalLighting>, + main_3d_shader_obj_id: ObjectId, + main_3d_shader_cursor: &ShaderCursor<'_>, + white_1x1_tex_obj_id: ObjectId, +) -> Result<(), crate::Error> +{ + let (material, material_flags, transform) = renderable; + let transform = match transform.as_deref() { Some(transform) => transform, None => &Transform::default(), @@ -535,9 +743,13 @@ fn add_set_3d_shader_bindings( None => &EnvironmentalLighting::default(), }; - let model_3d_shader_cursor = shader_cursor.field("Uniforms").field("model_3d"); - let lighting_shader_cursor = shader_cursor.field("Uniforms").field("lighting"); - let material_shader_cursor = lighting_shader_cursor.field("material"); + let model_3d_shader_cursor = + main_3d_shader_cursor.field("Uniforms").field("model_3d"); + + let material_shader_cursor = main_3d_shader_cursor + .field("Uniforms") + .field("lighting") + .field("material"); render_pass.commands.extend( [ @@ -547,26 +759,13 @@ fn add_set_3d_shader_bindings( model_3d_shader_cursor .field("model_inverted") .binding(inverted_model_matrix.into())?, - model_3d_shader_cursor - .field("view") - .binding(camera.to_view_matrix(camera_transform.position).into())?, - model_3d_shader_cursor.field("projection").binding( - camera - .projection - .to_matrix_rh(window.inner_size, ProjectionClipVolume::NegOneToOne) - .into(), - )?, - lighting_shader_cursor - .field("view_pos") - .binding(camera_transform.position.into())?, material_shader_cursor.field("ambient").binding( - (if material_flags.use_ambient_color { - &material.ambient - } else { - &env_lighting.ambient_color - } - .to_rgb_lossy()) - .into(), + material_flags + .use_ambient_color + .then_some(&material.ambient) + .unwrap_or(&env_lighting.ambient_color) + .to_rgb_lossy() + .into(), )?, material_shader_cursor .field("diffuse") @@ -574,127 +773,124 @@ fn add_set_3d_shader_bindings( material_shader_cursor .field("specular") .binding(material.specular.to_rgb_lossy().into())?, - shader_cursor - .field("ambient_map") - .binding(ShaderBindingValue::Texture( + main_3d_shader_cursor.field("ambient_map").binding( + ShaderBindingValue::Texture( material .ambient_map .as_ref() .map(|ambient_map| ObjectId::Asset(ambient_map.id())) .unwrap_or(white_1x1_tex_obj_id), ShaderBindingTextureKind::Texture2D, - ))?, - shader_cursor - .field("diffuse_map") - .binding(ShaderBindingValue::Texture( + ), + )?, + main_3d_shader_cursor.field("diffuse_map").binding( + ShaderBindingValue::Texture( material .diffuse_map .as_ref() .map(|diffuse_map| ObjectId::Asset(diffuse_map.id())) .unwrap_or(white_1x1_tex_obj_id), ShaderBindingTextureKind::Texture2D, - ))?, - shader_cursor - .field("specular_map") - .binding(ShaderBindingValue::Texture( + ), + )?, + main_3d_shader_cursor.field("specular_map").binding( + ShaderBindingValue::Texture( material .specular_map .as_ref() .map(|specular_map| ObjectId::Asset(specular_map.id())) .unwrap_or(white_1x1_tex_obj_id), ShaderBindingTextureKind::Texture2D, - ))?, + ), + )?, material_shader_cursor .field("shininess") .binding(material.shininess.into())?, - lighting_shader_cursor - .field("directional_light_cnt") - .binding( - u32::try_from(directional_light_query.iter().count()) - .expect( - "Directional light count does not fit in 32-bit unsigned integer", - ) - .into(), - )?, - lighting_shader_cursor.field("point_light_cnt").binding( - u32::try_from(point_light_query.iter().count()) - .expect("Point light count does not fit in 32-bit unsigned integer") - .into(), - )?, ] .into_iter() - .map(|binding| Command::SetShaderBinding(shader_object_id, binding)), + .map(|binding| Command::SetShaderBinding(main_3d_shader_obj_id, binding)), ); + Ok(()) +} + +fn add_sky_box_commands( + render_pass: &mut RenderPass, + sky_box_ids: &SkyBoxIds, + camera: &Camera, + camera_transform: &Transform, + window: &Window, + sky_box_shader_obj_id: ObjectId, + sky_box_shader_program: &ShaderProgram, +) -> Result<(), crate::Error> +{ render_pass .commands - .reserve(point_light_query.iter().count() * 6); + .push(Command::ActivateShader(sky_box_shader_obj_id)); - for (point_light_index, (point_light, point_light_transform)) in - point_light_query.iter().enumerate() - { - let point_light_shader_cursor = lighting_shader_cursor - .field("point_lights") - .element(point_light_index); + let sky_box_shader_cursor = ShaderCursor::new( + sky_box_shader_program + .reflection(0) + .unwrap() + .global_params_var_layout() + .unwrap(), + ); - let phong_shader_cursor = point_light_shader_cursor.field("phong"); + let mut view = camera.to_view_matrix(camera_transform.position); - let attenuation_props_shader_cursor = - point_light_shader_cursor.field("attenuation_props"); + view.translate(&Vec3 { x: 0.0, y: 0.0, z: 0.0 }); - render_pass.commands.extend( - [ - phong_shader_cursor - .field("diffuse") - .binding(point_light.diffuse.to_rgb_lossy().into())?, - phong_shader_cursor - .field("specular") - .binding(point_light.specular.to_rgb_lossy().into())?, - point_light_shader_cursor.field("position").binding( - (point_light_transform.position + point_light.local_position).into(), - )?, - attenuation_props_shader_cursor - .field("constant") - .binding(point_light.attenuation_params.constant.into())?, - attenuation_props_shader_cursor - .field("linear") - .binding(point_light.attenuation_params.linear.into())?, - attenuation_props_shader_cursor - .field("quadratic") - .binding(point_light.attenuation_params.quadratic.into())?, - ] - .map(|binding| Command::SetShaderBinding(shader_object_id, binding)), - ); + let sky_box_shader_bindings = [ + sky_box_shader_cursor + .field("Uniforms") + .field("projection") + .binding( + (match camera.projection { + Projection::Perspective(_) => camera.projection.to_matrix_rh( + window.inner_size, + ProjectionClipVolume::NegOneToOne, + ), + Projection::Orthographic(_) => { + // A orthographic projection cannot be used for a sky box + Perspective::default().to_matrix_rh( + window.inner_size.width as f32 + / window.inner_size.height as f32, + ProjectionClipVolume::NegOneToOne, + ) + } + }) + .into(), + )?, + sky_box_shader_cursor + .field("Uniforms") + .field("view") + .binding(view.into())?, + sky_box_shader_cursor.field("cube_texture").binding( + ShaderBindingValue::Texture( + sky_box_ids.texture_object, + ShaderBindingTextureKind::Cube, + ), + )?, + ]; + + for binding in sky_box_shader_bindings { + render_pass + .commands + .push(Command::SetShaderBinding(sky_box_shader_obj_id, binding)); } - render_pass - .commands - .reserve(directional_light_query.iter().count() * 3); - - for (directional_light_index, (directional_light,)) in - directional_light_query.iter().enumerate() - { - let directional_light_shader_cursor = lighting_shader_cursor - .field("directional_lights") - .element(directional_light_index); + render_pass.commands.push(Command::UpdateDrawProperties( + DrawProperties { + depth_function: DepthFunction::LessOrEqual, + ..Default::default() + }, + DrawPropertiesUpdateFlags::DEPTH_FUNCTION, + )); - let phong_shader_cursor = directional_light_shader_cursor.field("phong"); - - render_pass.commands.extend( - [ - phong_shader_cursor - .field("diffuse") - .binding(directional_light.diffuse.to_rgb_lossy().into())?, - phong_shader_cursor - .field("specular") - .binding(directional_light.specular.to_rgb_lossy().into())?, - directional_light_shader_cursor - .field("direction") - .binding(directional_light.direction.into())?, - ] - .map(|binding| Command::SetShaderBinding(shader_object_id, binding)), - ); - } + render_pass.commands.push(Command::DrawMesh( + sky_box_ids.mesh_object, + DrawMeshOptions::default(), + )); Ok(()) } @@ -705,48 +901,10 @@ fn load_sky_box( sky_box_state: Option<&SkyBoxState>, assets: &mut Assets, object_store: &mut ObjectStore, - shader_context: &ShaderContext, render_pass: &mut RenderPass, actions: &mut Actions, ) -> Result, crate::Error> { - let Some(sky_box_shader_asset) = assets - .get_handle_to_loaded::(SKY_BOX_SHADER_ASSET_LABEL.clone()) - else { - assets.store_with_label( - SKY_BOX_SHADER_ASSET_LABEL.clone(), - ShaderModuleSource { - name: "sky_box_shader.slang".into(), - file_path: Path::new("@engine/sky_box_shader").into(), - source: include_str!("../../res/sky_box_shader.slang").into(), - link_entrypoints: ShaderEntrypointFlags::VERTEX - | ShaderEntrypointFlags::FRAGMENT, - }, - ); - - // shader has to be processed - return Ok(None); - }; - - if !object_store - .contains_maybe_pending_with_id(&ObjectId::Asset(sky_box_shader_asset.id())) - { - let Some(shader_program) = shader_context.get_program(&sky_box_shader_asset.id()) - else { - tracing::error!( - "Shader context doesn't have a program for sky box shader asset", - ); - return Ok(None); - }; - - object_store.insert_pending(ObjectId::Asset(sky_box_shader_asset.id())); - - render_pass.commands.push(Command::CreateShaderProgram( - ObjectId::Asset(sky_box_shader_asset.id()), - shader_program.clone(), - )); - } - let mesh_object_id = match &sky_box_state { Some(sky_box_state) => sky_box_state.mesh_object_id, None => { @@ -835,8 +993,6 @@ fn load_sky_box( Ok(Some(SkyBoxIds { texture_object: texture_object_id, mesh_object: mesh_object_id, - shader_object: ObjectId::Asset(sky_box_shader_asset.id()), - shader_asset: sky_box_shader_asset.id(), })) } -- cgit v1.2.3-18-g5258