summaryrefslogtreecommitdiff
path: root/engine/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-08-19 22:34:34 +0200
committerHampusM <hampus@hampusmat.com>2026-08-19 22:34:34 +0200
commitbcc91b3db8cd50795c21860cd7797581199d5589 (patch)
tree78893f00f0894ebf17e756ab05a9093be10ec0e4 /engine/src
parentaa4892e301c54fa02b2f81473c5ab3c14d88f9ae (diff)
refactor(engine): move default shader bindings system to main_render_pass mod
Diffstat (limited to 'engine/src')
-rw-r--r--engine/src/material.rs7
-rw-r--r--engine/src/rendering.rs8
-rw-r--r--engine/src/rendering/main_render_pass.rs394
-rw-r--r--engine/src/rendering/shader.rs18
-rw-r--r--engine/src/rendering/shader/default.rs405
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>,
-);