summaryrefslogtreecommitdiff
path: root/engine/src/renderer/main_render_pass.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/renderer/main_render_pass.rs')
-rw-r--r--engine/src/renderer/main_render_pass.rs241
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,
+ ));
+ }
+ }
+ }
+}