summaryrefslogtreecommitdiff
path: root/engine/src
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src')
-rw-r--r--engine/src/lib.rs1
-rw-r--r--engine/src/rendering.rs2
-rw-r--r--engine/src/rendering/main_render_pass.rs313
-rw-r--r--engine/src/sky_box.rs11
4 files changed, 316 insertions, 11 deletions
diff --git a/engine/src/lib.rs b/engine/src/lib.rs
index f8b91a1..36affff 100644
--- a/engine/src/lib.rs
+++ b/engine/src/lib.rs
@@ -26,6 +26,7 @@ pub mod projection;
pub mod reflection;
pub mod rendering;
pub mod scene;
+pub mod sky_box;
pub mod texture;
pub mod transform;
pub mod ui;
diff --git a/engine/src/rendering.rs b/engine/src/rendering.rs
index f40f774..c5a4da6 100644
--- a/engine/src/rendering.rs
+++ b/engine/src/rendering.rs
@@ -77,7 +77,7 @@ impl crate::ecs::extension::Extension for Extension
let _ = collector.add_sole(self.graphics_props);
- collector.add_system(*PRE_RENDER_PHASE, main_render_pass::add_main_render_passes);
+ collector.add_system(*PRE_RENDER_PHASE, main_render_pass::add_main_render_pass);
collector.add_system(
*RENDER_PHASE,
diff --git a/engine/src/rendering/main_render_pass.rs b/engine/src/rendering/main_render_pass.rs
index 60bed03..622a087 100644
--- a/engine/src/rendering/main_render_pass.rs
+++ b/engine/src/rendering/main_render_pass.rs
@@ -1,17 +1,33 @@
+use std::path::Path;
+use std::sync::LazyLock;
+
+use ecs::actions::Actions;
use ecs::pair::ChildOf;
use ecs::query::term::{Traverse, TraverseUp};
+use ecs::uid::Uid;
+use ecs::Component;
-use crate::asset::Assets;
+use crate::asset::{Assets, Id as AssetId, Label as AssetLabel};
+use crate::camera::{Active as ActiveCamera, Camera};
+use crate::data_types::dimens::Dimens3;
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::mesh::Mesh;
use crate::model::{MaterialSearchResult, Model};
+use crate::projection::ClipVolume as ProjectionClipVolume;
use crate::rendering::object::{Id as ObjectId, Store as ObjectStore};
+use crate::rendering::shader::cursor::{
+ BindingTextureKind as ShaderBindingTextureKind,
+ 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,
};
@@ -19,6 +35,7 @@ use crate::rendering::{
AssetOrValue,
BufferClearMask,
Command,
+ DepthFunction,
DrawMeshOptions,
DrawProperties,
DrawPropertiesUpdateFlags,
@@ -30,7 +47,17 @@ use crate::rendering::{
TargetWindow,
};
use crate::scene::{Active as ActiveScene, Scene};
-use crate::texture::{Texture, WHITE_1X1_ASSET_LABEL as TEXTURE_WHITE_1X1_ASSET_LABEL};
+use crate::sky_box::SkyBox;
+use crate::texture::{
+ Filtering as TextureFiltering,
+ Properties as TextureProperties,
+ TexCubeMap,
+ Texture,
+ Wrapping as TextureWrapping,
+ WHITE_1X1_ASSET_LABEL as TEXTURE_WHITE_1X1_ASSET_LABEL,
+};
+use crate::transform::WorldPosition;
+use crate::vector::Vec3;
use crate::windowing::window::Window;
type RenderableEntity<'a> = (
@@ -42,21 +69,59 @@ type RenderableEntity<'a> = (
Without<NoDraw>,
);
+pub static SKY_BOX_SHADER_ASSET_LABEL: LazyLock<AssetLabel> =
+ LazyLock::new(|| AssetLabel {
+ path: Path::new("").into(),
+ name: Some("sky_box_shader".into()),
+ });
+
+struct SkyBoxIds
+{
+ texture_object: ObjectId,
+ mesh_object: ObjectId,
+ shader_object: ObjectId,
+ shader_asset: AssetId,
+}
+
#[tracing::instrument(skip_all)]
-pub fn add_main_render_passes(
+pub fn add_main_render_pass(
renderable_query: Query<RenderableEntity<'_>>,
- window_surface_spec_query: Query<(&SurfaceSpec, With<Window>, With<TargetWindow>)>,
- assets: Single<Assets>,
+ camera_query: Query<(
+ &Camera,
+ &WorldPosition,
+ &ActiveCamera,
+ Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>,
+ )>,
+ window_query: Query<(&Window, &SurfaceSpec, With<TargetWindow>)>,
+ scene_query: Query<(
+ Option<&SkyBox>,
+ Option<&SkyBoxState>,
+ With<Scene>,
+ With<ActiveScene>,
+ )>,
shader_context: Single<ShaderContext>,
+ mut assets: Single<Assets>,
mut render_passes: Single<RenderPasses>,
mut object_store: Single<ObjectStore>,
+ mut actions: Actions,
) -> Result<(), crate::Error>
{
- let assets = assets.get()?;
+ let assets = assets.get_mut()?;
let shader_context = shader_context.get()?;
let render_passes = render_passes.get_mut()?;
let object_store = object_store.get_mut()?;
+ let Some((scene_ent_id, (scene_skybox, scene_skybox_stuff))) =
+ scene_query.iter_with_euids().next()
+ else {
+ return Ok(());
+ };
+
+ let Some((camera, camera_world_pos, _)) = camera_query.iter().next() else {
+ tracing::trace!("No active camera");
+ return Ok(());
+ };
+
let Some(default_shader_asset) = assets
.get_handle_to_loaded::<ShaderModuleSource>(DEFAULT_SHADER_ASSET_LABEL.clone())
else {
@@ -68,7 +133,7 @@ pub fn add_main_render_passes(
draw_properties: DrawProperties::default(),
});
- for (surface_spec,) in &window_surface_spec_query {
+ for (window, surface_spec) in &window_query {
render_pass
.commands
.push(Command::MakeCurrent(surface_spec.id));
@@ -88,9 +153,28 @@ pub fn add_main_render_passes(
));
}
- render_pass.commands.push(Command::ClearBuffers(
- BufferClearMask::COLOR | BufferClearMask::DEPTH,
- ));
+ let sky_box_ids = if let Some(scene_skybox) = &scene_skybox {
+ load_sky_box(
+ scene_ent_id,
+ &scene_skybox,
+ scene_skybox_stuff.as_deref(),
+ assets,
+ object_store,
+ shader_context,
+ render_pass,
+ &mut actions,
+ )?
+ } else {
+ None
+ };
+
+ let mut buf_clear_mask = BufferClearMask::DEPTH;
+
+ buf_clear_mask.set(BufferClearMask::COLOR, sky_box_ids.is_none());
+
+ render_pass
+ .commands
+ .push(Command::ClearBuffers(buf_clear_mask));
for (model, draw_flags, shader, mut pending_shader_bindings) in &renderable_query
{
@@ -246,7 +330,216 @@ pub fn add_main_render_passes(
));
}
}
+
+ 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)
+ else {
+ unreachable!();
+ };
+
+ let sky_box_shader_cursor = ShaderCursor::new(
+ sky_box_shader_program
+ .reflection(0)
+ .unwrap()
+ .global_params_var_layout()
+ .unwrap(),
+ );
+
+ let mut view = camera.to_view_matrix(camera_world_pos.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(
+ camera
+ .projection
+ .to_matrix_rh(
+ window.inner_size,
+ 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(binding));
+ }
+
+ render_pass.commands.push(Command::UpdateDrawProperties(
+ DrawProperties {
+ depth_function: DepthFunction::LessOrEqual,
+ ..Default::default()
+ },
+ DrawPropertiesUpdateFlags::DEPTH_FUNCTION,
+ ));
+
+ render_pass.commands.push(Command::DrawMesh(
+ sky_box_ids.mesh_object,
+ DrawMeshOptions::default(),
+ ));
+ }
}
Ok(())
}
+
+fn load_sky_box(
+ scene_ent_id: Uid,
+ sky_box: &SkyBox,
+ 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 => {
+ let sky_box_mesh =
+ Mesh::cube(Dimens3 { width: 1.0, height: 1.0, depth: 1.0 });
+
+ let mesh_object_id = ObjectId::new_sequential();
+
+ object_store.insert_pending(mesh_object_id);
+
+ render_pass.commands.push(Command::CreateMesh {
+ obj_id: mesh_object_id,
+ mesh: AssetOrValue::Value(sky_box_mesh),
+ usage: MeshUsage::Static,
+ });
+
+ mesh_object_id
+ }
+ };
+
+ let texture_object_id = match &sky_box {
+ SkyBox::AssetPerCubeMapFace(cube_map_part_assets) => {
+ if let Some(sky_box_state) = sky_box_state {
+ sky_box_state.texture_object_id
+ } else {
+ let Some(part_images) = cube_map_part_assets
+ .iter()
+ .map_while(|(face, part_texture_asset)| {
+ let part_texture = assets.get(part_texture_asset)?;
+
+ match part_texture {
+ Texture::Texture2D(part_texture) => {
+ Some((*face, &part_texture.image))
+ }
+ Texture::CubeMap(_) => {
+ tracing::warn!(
+ "Cube map texture cannot be used as cube map part"
+ );
+
+ None
+ }
+ }
+ })
+ .collect::<Vec<_>>()
+ .as_array::<6>()
+ .cloned()
+ else {
+ return Ok(None);
+ };
+
+ let texture_object_id = ObjectId::new_sequential();
+
+ object_store.insert_pending(texture_object_id);
+
+ render_pass.commands.push(Command::CreateTexture(
+ texture_object_id,
+ AssetOrValue::Value(Texture::CubeMap(TexCubeMap {
+ images: part_images.map(|(face, image)| (face, image.clone())),
+ properties: TextureProperties::builder()
+ .minifying_filter(TextureFiltering::Linear)
+ .magnifying_filter(TextureFiltering::Linear)
+ .wrap(TextureWrapping::ClampToEdge)
+ .build(),
+ })),
+ ));
+
+ texture_object_id
+ }
+ }
+ };
+
+ if sky_box_state.is_none() {
+ actions.add_components(
+ scene_ent_id,
+ (SkyBoxState { texture_object_id, mesh_object_id },),
+ );
+ }
+
+ 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(),
+ }))
+}
+
+#[derive(Debug, Component)]
+pub struct SkyBoxState
+{
+ texture_object_id: ObjectId,
+ mesh_object_id: ObjectId,
+}
diff --git a/engine/src/sky_box.rs b/engine/src/sky_box.rs
new file mode 100644
index 0000000..ceb82df
--- /dev/null
+++ b/engine/src/sky_box.rs
@@ -0,0 +1,11 @@
+use crate::asset::Handle as AssetHandle;
+use crate::ecs::Component;
+use crate::reflection::Reflection;
+use crate::texture::{CubeMapFace, Texture};
+
+#[derive(Debug, Clone, Component, Reflection)]
+#[non_exhaustive]
+pub enum SkyBox
+{
+ AssetPerCubeMapFace([(CubeMapFace, AssetHandle<Texture>); 6]),
+}