summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-09-03 22:53:52 +0200
committerHampusM <hampus@hampusmat.com>2026-09-03 22:53:52 +0200
commit977c22a5118d26374017b61a329124ae9381557f (patch)
tree1229bcb2c95aa550cc6c288592a3fb8d8b4f4495
parent7a1932911a7d05e40bbfc1d1ef83a92945730118 (diff)
refactor(engine): split up main render pass fn into more functions
-rw-r--r--engine/src/rendering/main_render_pass.rs956
1 files 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::<ShaderModuleSource>(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::<u8>::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::<u8>::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<ShadersCreationStatus<'shader_ctx>, crate::Error>
+{
+ let main_3d_shader_asset = assets
+ .get_handle_to_loaded::<ShaderModuleSource>(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::<ShaderModuleSource>(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<Scene>, With<ActiveScene>), 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<Scene>, With<ActiveScene>), 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<Option<SkyBoxIds>, crate::Error>
{
- let Some(sky_box_shader_asset) = assets
- .get_handle_to_loaded::<ShaderModuleSource>(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(),
}))
}