diff options
Diffstat (limited to 'engine/src/renderer/main_render_pass.rs')
| -rw-r--r-- | engine/src/renderer/main_render_pass.rs | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/engine/src/renderer/main_render_pass.rs b/engine/src/renderer/main_render_pass.rs new file mode 100644 index 0000000..7492379 --- /dev/null +++ b/engine/src/renderer/main_render_pass.rs @@ -0,0 +1,241 @@ +use ecs::Query; +use ecs::query::term::{With, Without}; +use ecs::sole::Single; + +use crate::asset::Assets; +use crate::draw_flags::{DrawFlags, NoDraw, PolygonModeConfig}; +use crate::model::{MaterialSearchResult, Model}; +use crate::renderer::object::{Id as RendererObjectId, Store as RendererObjectStore}; +use crate::renderer::{ + BufferClearMask as RendererBufferClearMask, + Command as RendererCommand, + DrawMeshOptions as RendererDrawMeshOptions, + DrawProperties as RendererDrawProperties, + DrawPropertiesUpdateFlags as RendererDrawPropertiesUpdateFlags, + MeshUsage as RendererMeshUsage, + PendingShaderBindings, + RenderPass, + RenderPasses as RendererRenderPasses, + SurfaceSpec, +}; +use crate::shader::default::ASSET_LABEL as DEFAULT_SHADER_ASSET_LABEL; +use crate::shader::{ + Context as ShaderContext, + ModuleSource as ShaderModuleSource, + Shader, +}; +use crate::texture::{Texture, WHITE_1X1_ASSET_LABEL as TEXTURE_WHITE_1X1_ASSET_LABEL}; +use crate::windowing::window::Window; + +type RenderableEntity<'a> = ( + &'a Model, + Option<&'a DrawFlags>, + Option<&'a Shader>, + Option<&'a mut PendingShaderBindings>, +); + +#[tracing::instrument(skip_all)] +pub fn add_main_render_passes( + renderable_query: Query<RenderableEntity<'_>, (Without<NoDraw>,)>, + window_surface_spec_query: Query<(&SurfaceSpec,), (With<Window>,)>, + assets: Single<Assets>, + shader_context: Single<ShaderContext>, + mut render_passes: Single<RendererRenderPasses>, + mut object_store: Single<RendererObjectStore>, +) +{ + let Some(default_shader_asset) = assets + .get_handle_to_loaded::<ShaderModuleSource>(DEFAULT_SHADER_ASSET_LABEL.clone()) + else { + tracing::error!("Default shader asset is not loaded"); + return; + }; + + for (surface_spec,) in &window_surface_spec_query { + let render_pass = render_passes.passes.push_front_mut(RenderPass { + surface_id: surface_spec.id, + commands: Vec::with_capacity(30), + draw_properties: RendererDrawProperties::default(), + }); + + let default_texture_asset = assets + .get_handle_to_loaded::<Texture>(TEXTURE_WHITE_1X1_ASSET_LABEL.clone()) + .expect("Not possible"); + + if !object_store.contains_maybe_pending_with_id(&RendererObjectId::Asset( + default_texture_asset.id(), + )) { + object_store + .insert_pending(RendererObjectId::Asset(default_texture_asset.id())); + + render_pass + .commands + .push(RendererCommand::CreateTexture(default_texture_asset)); + } + + render_pass.commands.push(RendererCommand::ClearBuffers( + RendererBufferClearMask::COLOR | RendererBufferClearMask::DEPTH, + )); + + 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; + } + + let Some(model_spec) = assets.get(&model.spec_asset) else { + continue; + }; + + let Some(mesh_asset) = &model_spec.mesh_asset else { + continue; + }; + + if assets.get(mesh_asset).is_none() { + continue; + } + + debug_assert!(model_spec.material_names.len() <= 1); + + let model_material_asset = match model_spec.find_first_material(&assets) { + MaterialSearchResult::Found(model_material_asset) => { + model_material_asset.clone() + // Some(model_material_asset.clone()) + } + MaterialSearchResult::NotFound | MaterialSearchResult::NoMaterials => { + // MaterialSearchResult::NotFound => { + continue; + } // MaterialSearchResult::NoMaterials => None, + }; + + if !object_store.contains_maybe_pending_with_id(&RendererObjectId::Asset( + shader_asset.id(), + )) { + 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; + }; + + object_store.insert_pending(RendererObjectId::Asset(shader_asset.id())); + + render_pass + .commands + .push(RendererCommand::CreateShaderProgram( + RendererObjectId::Asset(shader_asset.id()), + shader_program.clone(), + )); + } + + render_pass.commands.push(RendererCommand::ActivateShader( + RendererObjectId::Asset(shader_asset.id()), + )); + + let Some(model_material) = assets.get(&model_material_asset) else { + // TODO: Handle this case since it may occur + unreachable!(); + }; + + for texture_asset in [ + &model_material.ambient_map, + &model_material.diffuse_map, + &model_material.specular_map, + ] + .into_iter() + .flatten() + { + if !object_store.contains_maybe_pending_with_id(&RendererObjectId::Asset( + texture_asset.id(), + )) { + object_store + .insert_pending(RendererObjectId::Asset(texture_asset.id())); + + render_pass + .commands + .push(RendererCommand::CreateTexture(texture_asset.clone())); + } + } + + for (shader_binding_loc, shader_binding_val) in + &pending_shader_bindings.bindings + { + render_pass.commands.push(RendererCommand::SetShaderBinding( + shader_binding_loc.clone(), + shader_binding_val.clone(), + )); + } + + for (shader_binding_surface_id, shader_binding_loc, shader_binding_val) in + &pending_shader_bindings.surface_specific_bindings + { + if *shader_binding_surface_id != surface_spec.id { + continue; + } + + render_pass.commands.push(RendererCommand::SetShaderBinding( + shader_binding_loc.clone(), + shader_binding_val.clone(), + )); + } + + if let Some(draw_flags) = draw_flags.as_deref() + && draw_flags.polygon_mode_config != PolygonModeConfig::default() + { + render_pass + .commands + .push(RendererCommand::UpdateDrawProperties( + RendererDrawProperties { + polygon_mode_config: draw_flags.polygon_mode_config.clone(), + ..Default::default() + }, + RendererDrawPropertiesUpdateFlags::POLYGON_MODE_CONFIG, + )); + } + + if !object_store + .contains_maybe_pending_with_id(&RendererObjectId::Asset(mesh_asset.id())) + { + object_store.insert_pending(RendererObjectId::Asset(mesh_asset.id())); + + render_pass.commands.push(RendererCommand::CreateMesh { + obj_id: RendererObjectId::Asset(mesh_asset.id()), + mesh: None, + usage: RendererMeshUsage::Static, + }); + } + + render_pass.commands.push(RendererCommand::DrawMesh( + RendererObjectId::Asset(mesh_asset.id()), + RendererDrawMeshOptions::default(), + )); + + if let Some(draw_flags) = draw_flags.as_deref() + && draw_flags.polygon_mode_config != PolygonModeConfig::default() + { + render_pass + .commands + .push(RendererCommand::UpdateDrawProperties( + RendererDrawProperties { + polygon_mode_config: PolygonModeConfig::default(), + ..Default::default() + }, + RendererDrawPropertiesUpdateFlags::POLYGON_MODE_CONFIG, + )); + } + } + } +} |
