diff options
| author | HampusM <hampus@hampusmat.com> | 2026-08-19 22:34:34 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-08-19 22:34:34 +0200 |
| commit | bcc91b3db8cd50795c21860cd7797581199d5589 (patch) | |
| tree | 78893f00f0894ebf17e756ab05a9093be10ec0e4 /engine/src | |
| parent | aa4892e301c54fa02b2f81473c5ab3c14d88f9ae (diff) | |
refactor(engine): move default shader bindings system to main_render_pass mod
Diffstat (limited to 'engine/src')
| -rw-r--r-- | engine/src/material.rs | 7 | ||||
| -rw-r--r-- | engine/src/rendering.rs | 8 | ||||
| -rw-r--r-- | engine/src/rendering/main_render_pass.rs | 394 | ||||
| -rw-r--r-- | engine/src/rendering/shader.rs | 18 | ||||
| -rw-r--r-- | engine/src/rendering/shader/default.rs | 405 |
5 files changed, 334 insertions, 498 deletions
diff --git a/engine/src/material.rs b/engine/src/material.rs index dd5a460..af982f4 100644 --- a/engine/src/material.rs +++ b/engine/src/material.rs @@ -26,6 +26,13 @@ impl Material { Builder::new() } + + pub fn textures(&self) -> impl Iterator<Item = &AssetHandle<Texture>> + { + [&self.ambient_map, &self.diffuse_map, &self.specular_map] + .into_iter() + .flatten() + } } impl Default for Material diff --git a/engine/src/rendering.rs b/engine/src/rendering.rs index c5a4da6..d41257c 100644 --- a/engine/src/rendering.rs +++ b/engine/src/rendering.rs @@ -556,14 +556,6 @@ fn handle_window_removed( } } -// TODO: Maybe move this struct to somewhere more appropriate -#[derive(Default, Clone, Component)] -pub struct PendingShaderBindings -{ - pub bindings: Vec<ShaderBinding>, - pub surface_specific_bindings: Vec<(SurfaceId, ShaderBinding)>, -} - #[derive(Debug, Default, Clone, Component)] struct ActiveDrawProperties { diff --git a/engine/src/rendering/main_render_pass.rs b/engine/src/rendering/main_render_pass.rs index c3278fa..225b89a 100644 --- a/engine/src/rendering/main_render_pass.rs +++ b/engine/src/rendering/main_render_pass.rs @@ -14,7 +14,12 @@ 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::lighting::{ + DirectionalLight, + Environmental as EnvironmentalLighting, + PointLight, +}; +use crate::material::{Flags as MaterialFlags, Material}; use crate::mesh::Mesh; use crate::model::{MaterialSearchResult, Model}; use crate::projection::ClipVolume as ProjectionClipVolume; @@ -24,12 +29,11 @@ use crate::rendering::shader::cursor::{ BindingValue as ShaderBindingValue, Cursor as ShaderCursor, }; -use crate::rendering::shader::default::ASSET_LABEL as DEFAULT_SHADER_ASSET_LABEL; use crate::rendering::shader::{ Context as ShaderContext, EntrypointFlags as ShaderEntrypointFlags, ModuleSource as ShaderModuleSource, - Shader, + Program as ShaderProgram, }; use crate::rendering::{ AssetOrValue, @@ -40,7 +44,6 @@ use crate::rendering::{ DrawProperties, DrawPropertiesUpdateFlags, MeshUsage, - PendingShaderBindings, RenderPass, RenderPasses, SurfaceSpec, @@ -63,9 +66,9 @@ use crate::windowing::window::Window; type RenderableEntity<'a> = ( &'a Model, Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, + Option<&'a MaterialFlags>, + Option<&'a Transform>, Option<&'a DrawFlags>, - Option<&'a Shader>, - Option<&'a mut PendingShaderBindings>, Without<NoDraw>, ); @@ -75,6 +78,12 @@ pub static SKY_BOX_SHADER_ASSET_LABEL: LazyLock<AssetLabel> = name: Some("sky_box_shader".into()), }); +pub static MAIN_3D_SHADER_ASSET_LABEL: LazyLock<AssetLabel> = + LazyLock::new(|| AssetLabel { + path: Path::new("").into(), + name: Some("main_3d_shader".into()), + }); + struct SkyBoxIds { texture_object: ObjectId, @@ -94,11 +103,21 @@ pub fn add_main_render_pass( )>, window_query: Query<(&Window, &SurfaceSpec, With<TargetWindow>)>, scene_query: Query<( + Option<&EnvironmentalLighting>, Option<&SkyBox>, Option<&SkyBoxState>, With<Scene>, With<ActiveScene>, )>, + point_light_query: Query<( + &PointLight, + &Transform, + Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, + )>, + directional_light_query: Query<( + &DirectionalLight, + Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, + )>, shader_context: Single<ShaderContext>, mut assets: Single<Assets>, mut render_passes: Single<RenderPasses>, @@ -111,7 +130,7 @@ pub fn add_main_render_pass( let render_passes = render_passes.get_mut()?; let object_store = object_store.get_mut()?; - let Some((scene_ent_id, (scene_skybox, scene_skybox_stuff))) = + let Some((scene_ent_id, (scene_env_lighting, scene_skybox, scene_skybox_state))) = scene_query.iter_with_euids().next() else { return Ok(()); @@ -122,10 +141,23 @@ pub fn add_main_render_pass( return Ok(()); }; - let Some(default_shader_asset) = assets - .get_handle_to_loaded::<ShaderModuleSource>(DEFAULT_SHADER_ASSET_LABEL.clone()) + let Some(main_3d_shader_asset) = assets + .get_handle_to_loaded::<ShaderModuleSource>(MAIN_3D_SHADER_ASSET_LABEL.clone()) else { - return Err(error!("Default shader asset is not loaded")); + 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 { @@ -157,7 +189,7 @@ pub fn add_main_render_pass( load_sky_box( scene_ent_id, &scene_skybox, - scene_skybox_stuff.as_deref(), + scene_skybox_state.as_deref(), assets, object_store, shader_context, @@ -176,23 +208,7 @@ pub fn add_main_render_pass( .commands .push(Command::ClearBuffers(buf_clear_mask)); - for (model, draw_flags, shader, mut pending_shader_bindings) in &renderable_query - { - let shader_asset = match &shader { - Some(shader) => &shader.asset_handle, - None => &default_shader_asset, - }; - - let Some(pending_shader_bindings) = pending_shader_bindings.as_mut() else { - continue; - }; - - if pending_shader_bindings.bindings.is_empty() - && pending_shader_bindings.surface_specific_bindings.is_empty() - { - continue; - } - + for (model, material_flags, transform, draw_flags) in &renderable_query { let Some(model_spec) = assets.get(&model.spec_asset) else { continue; }; @@ -207,45 +223,53 @@ pub fn add_main_render_pass( debug_assert!(model_spec.material_names.len() <= 1); - let model_material_asset = match model_spec.find_first_material(&assets) { + let model_material = match model_spec.find_first_material(&assets) { MaterialSearchResult::Found(model_material_asset) => { - model_material_asset.clone() - // Some(model_material_asset.clone()) + let Some(model_material) = assets.get(&model_material_asset) else { + continue; + }; + + model_material } - MaterialSearchResult::NotFound | MaterialSearchResult::NoMaterials => { - // MaterialSearchResult::NotFound => { + MaterialSearchResult::NotFound => { continue; - } // MaterialSearchResult::NoMaterials => None, + } + MaterialSearchResult::NoMaterials => &Material::builder().build(), }; - if !object_store - .contains_maybe_pending_with_id(&ObjectId::Asset(shader_asset.id())) + if model_material + .textures() + .any(|texture_asset| !assets.is_loaded_and_has_type(&texture_asset)) { - let Some(shader_program) = shader_context.get_program(&shader_asset.id()) - else { - tracing::error!( - "Shader context doesn't have a program for shader asset {:?}", - assets.get_label(&shader_asset) - ); - continue; - }; + continue; + } - object_store.insert_pending(ObjectId::Asset(shader_asset.id())); + 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(shader_asset.id()), + ObjectId::Asset(main_3d_shader_asset.id()), shader_program.clone(), )); } render_pass .commands - .push(Command::ActivateShader(ObjectId::Asset(shader_asset.id()))); - - let Some(model_material) = assets.get(&model_material_asset) else { - // TODO: Handle this case since it may occur - unreachable!(); - }; + .push(Command::ActivateShader(ObjectId::Asset( + main_3d_shader_asset.id(), + ))); for texture_asset in [ &model_material.ambient_map, @@ -267,23 +291,21 @@ pub fn add_main_render_pass( } } - for shader_binding in &pending_shader_bindings.bindings { - render_pass - .commands - .push(Command::SetShaderBinding(shader_binding.clone())); - } - - for (shader_binding_surface_id, shader_binding) in - &pending_shader_bindings.surface_specific_bindings - { - if *shader_binding_surface_id != surface_spec.id { - continue; - } - - render_pass - .commands - .push(Command::SetShaderBinding(shader_binding.clone())); - } + add_set_3d_shader_bindings( + render_pass, + ( + model_material, + material_flags.as_deref(), + transform.as_deref(), + ), + scene_env_lighting.as_deref(), + (&camera, &camera_transform), + &window, + &point_light_query, + &directional_light_query, + assets, + shader_program, + )?; if let Some(draw_flags) = draw_flags.as_deref().and_then(|draw_flags| { if draw_flags.polygon_mode_config != PolygonModeConfig::default() { @@ -403,6 +425,240 @@ pub fn add_main_render_pass( Ok(()) } +fn add_set_3d_shader_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<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, + )>, + directional_light_query: &Query<( + &DirectionalLight, + Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, + )>, + assets: &Assets, + shader_program: &ShaderProgram, +) -> Result<(), crate::Error> +{ + let (material, material_flags, transform) = renderable; + + let shader_cursor = ShaderCursor::new( + shader_program + .reflection(0) + .unwrap() + .global_params_var_layout() + .unwrap(), + ); + + let transform = match transform.as_deref() { + Some(transform) => transform, + None => &Transform::default(), + }; + + let model_matrix = transform.to_matrix(); + let inverted_model_matrix = model_matrix.inverse(); + + let material_flags = material_flags + .as_deref() + .unwrap_or(&const { MaterialFlags::builder().build() }); + + let env_lighting = match &scene_env_lighting { + Some(env_lighting) => &env_lighting, + 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"); + + render_pass.commands.extend( + [ + model_3d_shader_cursor + .field("model") + .binding(model_matrix.into())?, + 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 + } + .clone()) + .into(), + )?, + material_shader_cursor + .field("diffuse") + .binding(material.diffuse.clone().into())?, + material_shader_cursor + .field("specular") + .binding(material.specular.clone().into())?, + shader_cursor + .field("ambient_map") + .binding(ShaderBindingValue::Texture( + material + .ambient_map + .as_ref() + .map(|ambient_map| ambient_map.clone()) + .unwrap_or_else(|| { + assets + .get_handle_to_loaded( + TEXTURE_WHITE_1X1_ASSET_LABEL.clone(), + ) + .expect("Not possible") + }) + .id() + .into(), + ShaderBindingTextureKind::Texture2D, + ))?, + shader_cursor + .field("diffuse_map") + .binding(ShaderBindingValue::Texture( + material + .diffuse_map + .as_ref() + .map(|diffuse_map| diffuse_map.clone()) + .unwrap_or_else(|| { + assets + .get_handle_to_loaded( + TEXTURE_WHITE_1X1_ASSET_LABEL.clone(), + ) + .expect("Not possible") + }) + .id() + .into(), + ShaderBindingTextureKind::Texture2D, + ))?, + shader_cursor + .field("specular_map") + .binding(ShaderBindingValue::Texture( + material + .specular_map + .as_ref() + .map(|specular_map| specular_map.clone()) + .unwrap_or_else(|| { + assets + .get_handle_to_loaded( + TEXTURE_WHITE_1X1_ASSET_LABEL.clone(), + ) + .expect("Not possible") + }) + .id() + .into(), + 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(Command::SetShaderBinding), + ); + + render_pass + .commands + .reserve(point_light_query.iter().count() * 6); + + 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.clone().into())?, + phong_shader_cursor + .field("specular") + .binding(point_light.specular.clone().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(Command::SetShaderBinding), + ); + } + + 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); + + let phong_shader_cursor = directional_light_shader_cursor.field("phong"); + + render_pass.commands.extend( + [ + phong_shader_cursor + .field("diffuse") + .binding(directional_light.diffuse.clone().into())?, + phong_shader_cursor + .field("specular") + .binding(directional_light.specular.clone().into())?, + directional_light_shader_cursor + .field("direction") + .binding(directional_light.direction.into())?, + ] + .map(Command::SetShaderBinding), + ); + } + + Ok(()) +} + fn load_sky_box( scene_ent_id: Uid, sky_box: &SkyBox, diff --git a/engine/src/rendering/shader.rs b/engine/src/rendering/shader.rs index 6f50a79..12fc9c1 100644 --- a/engine/src/rendering/shader.rs +++ b/engine/src/rendering/shader.rs @@ -31,25 +31,18 @@ use crate::asset::{ }; use crate::builder; use crate::ecs::pair::ChildOf; -use crate::ecs::phase::{Phase, POST_UPDATE as POST_UPDATE_PHASE}; +use crate::ecs::phase::Phase; use crate::ecs::sole::Single; -use crate::ecs::{declare_entity, pair, Component, Sole}; +use crate::ecs::{declare_entity, pair, Sole}; use crate::mesh::vertex_buffer::VertexLabel; pub mod cursor; -pub mod default; pub const STD_VERTEX_INPUT_SEMANTIC_NAME_POSITION: &str = "STD_POSITION"; pub const STD_VERTEX_INPUT_SEMANTIC_NAME_NORMAL: &str = "STD_NORMAL"; pub const STD_VERTEX_INPUT_SEMANTIC_NAME_UV: &str = "STD_UV"; pub const STD_VERTEX_INPUT_SEMANTIC_NAME_COLOR: &str = "STD_COLOR"; -#[derive(Debug, Clone, Component)] -pub struct Shader -{ - pub asset_handle: AssetHandle<ModuleSource>, -} - /// Shader module. #[derive(Debug)] pub struct ModuleSource @@ -1319,13 +1312,6 @@ pub(super) fn prepare(collector: &mut crate::ecs::extension::Collector<'_>) collector.add_system(*INIT_PHASE, initialize); collector.add_system(*IMPORT_SHADERS_PHASE, load_modules); - - collector.add_system(*INIT_PHASE, crate::rendering::shader::default::initialize); - - collector.add_system( - *POST_UPDATE_PHASE, - crate::rendering::shader::default::enqueue_set_shader_bindings, - ); } fn initialize(mut assets: Single<Assets>) -> Result<(), crate::Error> diff --git a/engine/src/rendering/shader/default.rs b/engine/src/rendering/shader/default.rs deleted file mode 100644 index 59d0c9e..0000000 --- a/engine/src/rendering/shader/default.rs +++ /dev/null @@ -1,405 +0,0 @@ -use std::path::Path; -use std::sync::LazyLock; - -use crate::asset::{Assets, Label as AssetLabel}; -use crate::camera::{Active as ActiveCamera, Camera}; -use crate::draw_flags::NoDraw; -use crate::ecs::actions::Actions; -use crate::ecs::pair::ChildOf; -use crate::ecs::query::term::{Traverse, TraverseUp, With, Without}; -use crate::ecs::sole::Single; -use crate::ecs::Query; -use crate::lighting::{ - DirectionalLight, - Environmental as EnvironmentalLighting, - PointLight, -}; -use crate::material::{Flags as MaterialFlags, Material}; -use crate::model::{MaterialSearchResult, Model}; -use crate::projection::ClipVolume as ProjectionClipVolume; -use crate::rendering::shader::cursor::{ - BindingTextureKind as ShaderBindingTextureKind, - BindingValue as ShaderBindingValue, - Cursor as ShaderCursor, -}; -use crate::rendering::shader::{ - Context as ShaderContext, - EntrypointFlags as ShaderEntrypointFlags, - ModuleSource as ShaderModuleSource, - Shader, -}; -use crate::rendering::{ - PendingShaderBindings, - SurfaceSpec, - TargetWindow as RenderingTargetWindow, -}; -use crate::scene::{Active as ActiveScene, Scene}; -use crate::texture::WHITE_1X1_ASSET_LABEL as TEXTURE_WHITE_1X1_ASSET_LABEL; -use crate::transform::Transform; -use crate::windowing::window::Window; - -pub static ASSET_LABEL: LazyLock<AssetLabel> = LazyLock::new(|| AssetLabel { - path: Path::new("").into(), - name: Some("default_shader".into()), -}); - -pub fn initialize(mut assets: Single<Assets>) -> Result<(), crate::Error> -{ - assets.get_mut()?.store_with_label( - ASSET_LABEL.clone(), - ShaderModuleSource { - name: "default_shader.slang".into(), - file_path: Path::new("@engine/default_shader").into(), - source: include_str!("../../../res/default_shader.slang").into(), - link_entrypoints: ShaderEntrypointFlags::VERTEX - | ShaderEntrypointFlags::FRAGMENT, - }, - ); - - Ok(()) -} - -pub fn enqueue_set_shader_bindings( - renderable_query: Query<RenderableEntity<'_>>, - camera_query: Query<( - &Camera, - &Transform, - &ActiveCamera, - Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, - )>, - window_query: Query<(&Window, &SurfaceSpec, With<RenderingTargetWindow>)>, - point_light_query: Query<( - &PointLight, - &Transform, - Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, - )>, - directional_light_query: Query<( - &DirectionalLight, - Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>, - )>, - assets: Single<Assets>, - shader_context: Single<ShaderContext>, - mut actions: Actions, -) -> Result<(), crate::Error> -{ - let assets = assets.get()?; - let shader_context = shader_context.get()?; - - let Some((camera, camera_transform, _)) = camera_query.iter().next() else { - tracing::trace!("No active camera"); - return Ok(()); - }; - - let default_shader_asset = assets - .get_handle_to_loaded::<ShaderModuleSource>(ASSET_LABEL.clone()) - .unwrap(); - - for ( - entity_id, - ( - model, - environmental_lighting, - material_flags, - transform, - shader, - mut pending_shader_bindings, - ), - ) in renderable_query.iter_with_euids() - { - let shader_asset = match &shader { - Some(shader) => &shader.asset_handle, - None => &default_shader_asset, - }; - - if shader_asset.id() != default_shader_asset.id() { - continue; - } - - let has_pending_shader_bindings_comp = pending_shader_bindings.is_some(); - - let shader_bindings = match pending_shader_bindings.as_deref_mut() { - Some(pending_shader_bindings) => pending_shader_bindings, - None => &mut PendingShaderBindings::default(), - }; - - // Bindings are cleared to prevent them from growing infinitely - shader_bindings.bindings.clear(); - shader_bindings.surface_specific_bindings.clear(); - - let Some(shader_program) = shader_context.get_program(&shader_asset.id()) else { - continue; - }; - - let Some(model_spec) = assets.get(&model.spec_asset) else { - continue; - }; - - let shader_cursor = ShaderCursor::new( - shader_program - .reflection(0) - .unwrap() - .global_params_var_layout() - .unwrap(), - ); - - let transform = match transform.as_deref() { - Some(transform) => transform, - None => &Transform::default(), - }; - - let model_matrix = transform.to_matrix(); - let inverted_model_matrix = model_matrix.inverse(); - - 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; - }; - - model_material - } - MaterialSearchResult::NotFound => { - continue; - } - MaterialSearchResult::NoMaterials => &Material::builder().build(), - }; - - if [ - &model_material.ambient_map, - &model_material.diffuse_map, - &model_material.specular_map, - ] - .into_iter() - .flatten() - .any(|texture_asset| !assets.is_loaded_and_has_type(&texture_asset)) - { - continue; - } - - let material_flags = material_flags - .as_deref() - .unwrap_or(&const { MaterialFlags::builder().build() }); - - let env_lighting = match &environmental_lighting { - Some(env_lighting) => &env_lighting, - 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 view = camera.to_view_matrix(camera_transform.position); - - shader_bindings.bindings.extend([ - model_3d_shader_cursor - .field("model") - .binding(model_matrix.into())?, - model_3d_shader_cursor - .field("model_inverted") - .binding(inverted_model_matrix.into())?, - model_3d_shader_cursor.field("view").binding(view.into())?, - lighting_shader_cursor - .field("view_pos") - .binding(camera_transform.position.into())?, - material_shader_cursor.field("ambient").binding( - (if material_flags.use_ambient_color { - &model_material.ambient - } else { - &env_lighting.ambient_color - } - .clone()) - .into(), - )?, - material_shader_cursor - .field("diffuse") - .binding(model_material.diffuse.clone().into())?, - material_shader_cursor - .field("specular") - .binding(model_material.specular.clone().into())?, - material_shader_cursor - .field("shininess") - .binding(model_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(), - )?, - ]); - - for (window, window_surface_spec) in &window_query { - shader_bindings.surface_specific_bindings.push(( - window_surface_spec.id, - model_3d_shader_cursor.field("projection").binding( - camera - .projection - .to_matrix_rh( - window.inner_size, - ProjectionClipVolume::NegOneToOne, - ) - .into(), - )?, - )); - } - - shader_bindings - .bindings - .reserve(point_light_query.iter().count() * 6); - - 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"); - - shader_bindings.bindings.extend([ - phong_shader_cursor - .field("diffuse") - .binding(point_light.diffuse.clone().into())?, - phong_shader_cursor - .field("specular") - .binding(point_light.specular.clone().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())?, - ]); - } - - shader_bindings - .bindings - .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); - - let phong_shader_cursor = directional_light_shader_cursor.field("phong"); - - shader_bindings.bindings.extend([ - phong_shader_cursor - .field("diffuse") - .binding(directional_light.diffuse.clone().into())?, - phong_shader_cursor - .field("specular") - .binding(directional_light.specular.clone().into())?, - directional_light_shader_cursor - .field("direction") - .binding(directional_light.direction.into())?, - ]); - } - - shader_bindings.bindings.push( - shader_cursor - .field("ambient_map") - .binding(ShaderBindingValue::Texture( - model_material - .ambient_map - .as_ref() - .map(|ambient_map| ambient_map.clone()) - .unwrap_or_else(|| { - assets - .get_handle_to_loaded( - TEXTURE_WHITE_1X1_ASSET_LABEL.clone(), - ) - .expect("Not possible") - }) - .id() - .into(), - ShaderBindingTextureKind::Texture2D, - ))?, - ); - - shader_bindings.bindings.push( - shader_cursor - .field("diffuse_map") - .binding(ShaderBindingValue::Texture( - model_material - .diffuse_map - .as_ref() - .map(|diffuse_map| diffuse_map.clone()) - .unwrap_or_else(|| { - assets - .get_handle_to_loaded( - TEXTURE_WHITE_1X1_ASSET_LABEL.clone(), - ) - .expect("Not possible") - }) - .id() - .into(), - ShaderBindingTextureKind::Texture2D, - ))?, - ); - - shader_bindings.bindings.push( - shader_cursor - .field("specular_map") - .binding(ShaderBindingValue::Texture( - model_material - .specular_map - .as_ref() - .map(|specular_map| specular_map.clone()) - .unwrap_or_else(|| { - assets - .get_handle_to_loaded( - TEXTURE_WHITE_1X1_ASSET_LABEL.clone(), - ) - .expect("Not possible") - }) - .id() - .into(), - ShaderBindingTextureKind::Texture2D, - ))?, - ); - - if !has_pending_shader_bindings_comp { - actions.add_components(entity_id, (shader_bindings.clone(),)); - } - } - - Ok(()) -} - -type RenderableEntity<'a> = ( - &'a Model, - Traverse< - ( - Option<&'a EnvironmentalLighting>, - With<Scene>, - With<ActiveScene>, - ), - TraverseUp, - ChildOf, - >, - Option<&'a MaterialFlags>, - Option<&'a Transform>, - Option<&'a Shader>, - Option<&'a mut PendingShaderBindings>, - Without<NoDraw>, -); |
