diff options
Diffstat (limited to 'engine')
| -rw-r--r-- | engine/src/rendering.rs | 41 | ||||
| -rw-r--r-- | engine/src/rendering/backend/opengl.rs | 234 | ||||
| -rw-r--r-- | engine/src/rendering/shader/cursor.rs | 15 | ||||
| -rw-r--r-- | engine/src/texture.rs | 35 | ||||
| -rw-r--r-- | engine/src/ui/dear_imgui.rs | 6 |
5 files changed, 275 insertions, 56 deletions
diff --git a/engine/src/rendering.rs b/engine/src/rendering.rs index dc3cb76..f40f774 100644 --- a/engine/src/rendering.rs +++ b/engine/src/rendering.rs @@ -216,6 +216,7 @@ pub enum Command ActivateShader(ObjectId), SetShaderBinding(ShaderBinding), CreateTexture(ObjectId, AssetOrValue<Texture>), + // TODO: Make UpdateTexture command able to handle textures other than 2D textures UpdateTexture { obj_id: ObjectId, @@ -321,6 +322,37 @@ impl Default for ScissorBox } } +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub enum DepthFunction +{ + /// Never passes. + Never, + + /// Passes if the incoming depth value is less than the stored depth value. + #[default] + Less, + + /// Passes if the incoming depth value is equal to the stored depth value. + Equal, + + /// Passes if the incoming depth value is less than or equal to the stored depth + /// value. + LessOrEqual, + + /// Passes if the incoming depth value is greater than the stored depth value. + Greater, + + /// Passes if the incoming depth value is not equal to the stored depth value. + NotEqual, + + /// Passes if the incoming depth value is greater than or equal to the stored depth + /// value. + GreaterOrEqual, + + /// Always passes. + Always, +} + #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] pub struct DrawProperties @@ -329,6 +361,7 @@ pub struct DrawProperties pub blending_enabled: bool, pub blending_config: BlendingConfig, pub depth_test_enabled: bool, + pub depth_function: DepthFunction, pub scissor_test_enabled: bool, pub scissor_box: ScissorBox, pub face_culling_enabled: bool, @@ -343,6 +376,7 @@ impl Default for DrawProperties blending_enabled: false, blending_config: BlendingConfig::default(), depth_test_enabled: true, + depth_function: DepthFunction::default(), scissor_test_enabled: false, scissor_box: ScissorBox::default(), face_culling_enabled: false, @@ -358,9 +392,10 @@ bitflags! { const BLENDING_CONFIG = 1 << 1; const BLENDING_ENABLED = 1 << 2; const DEPTH_TEST_ENABLED = 1 << 3; - const SCISSOR_TEST_ENABLED = 1 << 4; - const SCISSOR_BOX = 1 << 5; - const FACE_CULLING_ENABLED = 1 << 6; + const DEPTH_FUNCTION = 1 << 4; + const SCISSOR_TEST_ENABLED = 1 << 5; + const SCISSOR_BOX = 1 << 6; + const FACE_CULLING_ENABLED = 1 << 7; } } diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs index dc636ef..12aaaf0 100644 --- a/engine/src/rendering/backend/opengl.rs +++ b/engine/src/rendering/backend/opengl.rs @@ -35,10 +35,12 @@ use opengl_bindings::misc::{ define_scissor_box as gl_define_scissor_box, enable, get_viewport as gl_get_viewport, + set_depth_function as gl_set_depth_function, set_enabled, set_viewport as gl_set_viewport, BufferClearMask as GlBufferClearMask, Capability, + DepthFunction as GlDepthFunction, }; use opengl_bindings::shader::{ Error as GlShaderError, @@ -49,6 +51,7 @@ use opengl_bindings::shader::{ }; use opengl_bindings::texture::{ ColorSpace as GlTextureColorSpace, + CubeMapFace as GlCubeMapTextureFace, Error as GlTextureError, Filtering as GlTextureFiltering, PixelDataFormat as GlTexturePixelDataFormat, @@ -108,6 +111,7 @@ use crate::rendering::{ BufferClearMask, Command, CommandQueue, + DepthFunction, DrawMeshOptions, DrawPropertiesUpdateFlags, GraphicsProperties, @@ -118,8 +122,10 @@ use crate::rendering::{ RENDER_PHASE, }; use crate::texture::{ + CubeMapFace as CubeMapTextureFace, Filtering as TextureFiltering, Properties as TextureProperties, + TexCubeMap, Texture, Wrapping as TextureWrapping, }; @@ -1033,6 +1039,26 @@ fn handle_commands( } if draw_props_update_flags + .contains(DrawPropertiesUpdateFlags::DEPTH_FUNCTION) + { + gl_set_depth_function( + gl_context, + match draw_props.depth_function { + DepthFunction::Never => GlDepthFunction::Never, + DepthFunction::Less => GlDepthFunction::Less, + DepthFunction::Equal => GlDepthFunction::Equal, + DepthFunction::LessOrEqual => GlDepthFunction::LessOrEqual, + DepthFunction::Greater => GlDepthFunction::Greater, + DepthFunction::NotEqual => GlDepthFunction::NotEqual, + DepthFunction::GreaterOrEqual => { + GlDepthFunction::GreaterOrEqual + } + DepthFunction::Always => GlDepthFunction::Always, + }, + ); + } + + if draw_props_update_flags .contains(DrawPropertiesUpdateFlags::SCISSOR_TEST_ENABLED) { set_enabled( @@ -1118,28 +1144,64 @@ enum CreateGlContextError MakeContextCurrent(#[source] GlMakeContextCurrentError), } -fn retrieve_texture<'a>( - assets: &'a Assets, - texture: &'a AssetOrValue<Texture>, -) -> Option<(BorrowedOrOwned<'a, Image>, &'a TextureProperties)> +enum TextureCreationData<'a> { - let Texture { image, properties } = match &texture { - AssetOrValue::Asset(texture_asset) => { - let Some(texture) = assets.get(&texture_asset) else { - tracing::error!( - texture_asset_id=?texture_asset.id(), - "Texture asset does not exist" - ); - return None; - }; + Texture2D + { + image: BorrowedOrOwned<'a, Image> + }, + CubeMap + { + images: [(CubeMapTextureFace, BorrowedOrOwned<'a, Image>); 6], + color_type: ImageColorType, + is_srgb: bool, + size: Dimens<u32>, + }, +} - texture - } - AssetOrValue::Value(texture) => texture, - }; +fn validate_cube_map_texture(texture: &TexCubeMap) -> bool +{ + let first_image_color_type = texture.images[0].1.color_type(); + + if !texture.images[1..] + .into_iter() + .all(|(_, image)| image.color_type() == first_image_color_type) + { + tracing::error!("All texture images must have same color type"); + return false; + } + + let first_image_size = texture.images[0].1.dimensions(); + + if !texture.images[1..] + .into_iter() + .all(|(_, image)| image.dimensions() == first_image_size) + { + tracing::error!("All texture images must have same dimensions"); + return false; + } + + let first_image_is_srgb = texture.images[0].1.color_space_is_srgb(); + + if !texture.images[1..] + .into_iter() + .all(|(_, image)| image.color_space_is_srgb() == first_image_is_srgb) + { + tracing::error!("All texture images must have same color space"); + return false; + } + + true +} - let texture_image = match image.color_type() { - ImageColorType::Rgb8 if (image.dimensions().width * 3) % 4 != 0 => { +fn convert_textures_if_unaligned<const IMAGE_CNT: usize, Extra>( + images: [(Extra, &Image); IMAGE_CNT], + color_type: ImageColorType, + size: Dimens<u32>, +) -> [(Extra, BorrowedOrOwned<'_, Image>); IMAGE_CNT] +{ + match color_type { + ImageColorType::Rgb8 if (size.width * 3) % 4 != 0 => { // The texture will be corrupted if the alignment of each horizontal line of // the texture pixel array is not multiple of 4. // @@ -1156,12 +1218,10 @@ fn retrieve_texture<'a>( "texture image's pixel format to RGBA8" )); - BorrowedOrOwned::Owned(image.to_rgba8()) + images.map(|(extra, image)| (extra, BorrowedOrOwned::Owned(image.to_rgba8()))) } - _ => BorrowedOrOwned::Borrowned(image), - }; - - Some((texture_image, properties)) + _ => images.map(|(extra, image)| (extra, BorrowedOrOwned::Borrowned(image))), + } } #[tracing::instrument(skip_all)] @@ -1181,15 +1241,69 @@ fn create_texture_object( return Ok(()); } - let Some((texture_image, texture_properties)) = retrieve_texture(assets, &texture) - else { - return Ok(()); + let texture = match &texture { + AssetOrValue::Asset(texture_asset) => { + let Some(texture) = assets.get(&texture_asset) else { + tracing::error!( + texture_asset_id=?texture_asset.id(), + "Texture asset does not exist" + ); + return Ok(()); + }; + + texture + } + AssetOrValue::Value(texture) => texture, + }; + + let (texture_things, texture_properties) = match texture { + Texture::Texture2D(texture) => { + let [(_, image)] = convert_textures_if_unaligned( + [((), &texture.image)], + texture.image.color_type(), + texture.image.dimensions(), + ); + + ( + TextureCreationData::Texture2D { image }, + &texture.properties, + ) + } + Texture::CubeMap(texture) => { + if !validate_cube_map_texture(texture) { + return Ok(()); + } + + let first_image_color_type = texture.images[0].1.color_type(); + let first_image_size = texture.images[0].1.dimensions(); + let first_image_is_srgb = texture.images[0].1.color_space_is_srgb(); + + let images = convert_textures_if_unaligned( + std::array::from_fn::<_, 6, _>(|index| { + let (face, image) = &texture.images[index]; + + (*face, image) + }), + first_image_color_type, + first_image_size, + ); + + ( + TextureCreationData::CubeMap { + images, + color_type: first_image_color_type, + is_srgb: first_image_is_srgb, + size: first_image_size, + }, + &texture.properties, + ) + } }; object_store.insert( texture_object_id, Object::from_raw( - create_gl_texture(curr_gl_ctx, &*texture_image, texture_properties)? + create_gl_texture(curr_gl_ctx, texture_things, texture_properties)? .into_raw(), ObjectKind::Texture, ), @@ -1225,12 +1339,12 @@ fn update_texture_object( let gl_texture = GlTexture::from_raw(texture_obj.as_raw()); - gl_texture.store_image( + gl_texture.store_image_2d( curr_gl_ctx, 0, offset.into(), texture_image.dimensions().into(), - get_image_pixel_data_format(&texture_image), + color_type_to_pixel_data_format(texture_image.color_type()), texture_image.as_bytes(), )?; @@ -1269,9 +1383,10 @@ fn draw_mesh( Ok(()) } -fn get_image_pixel_data_format(image: &Image) -> GlTexturePixelDataFormat +fn color_type_to_pixel_data_format(color_type: ImageColorType) + -> GlTexturePixelDataFormat { - match image.color_type() { + match color_type { ImageColorType::Rgb8 => GlTexturePixelDataFormat::Rgb8, ImageColorType::Rgba8 => GlTexturePixelDataFormat::Rgba8, _ => { @@ -1282,19 +1397,42 @@ fn get_image_pixel_data_format(image: &Image) -> GlTexturePixelDataFormat fn create_gl_texture( curr_gl_context: &MaybeCurrentContextWithFns, - image: &Image, + texture_things: TextureCreationData<'_>, texture_properties: &TextureProperties, ) -> Result<GlTexture, GlTextureError> { - let gl_texture = GlTexture::builder() - .image(image.as_bytes(), get_image_pixel_data_format(image)) - .size(image.dimensions().into()) - .color_space(if image.color_space_is_srgb() { - GlTextureColorSpace::Srgb - } else { - GlTextureColorSpace::Linear - }) - .create(curr_gl_context)?; + let gl_texture = match texture_things { + TextureCreationData::Texture2D { image } => GlTexture::builder() + .size(image.dimensions().into()) + .color_space(if image.color_space_is_srgb() { + GlTextureColorSpace::Srgb + } else { + GlTextureColorSpace::Linear + }) + .create_2d( + curr_gl_context, + image.as_bytes(), + color_type_to_pixel_data_format(image.color_type()), + ), + TextureCreationData::CubeMap { images, color_type, is_srgb, size } => { + GlTexture::builder() + .size(size.into()) + .color_space(if is_srgb { + GlTextureColorSpace::Srgb + } else { + GlTextureColorSpace::Linear + }) + .create_cube_map( + curr_gl_context, + std::array::from_fn::<_, 6, _>(|index| { + let (face, image) = &images[index]; + + (cube_map_texture_face_to_gl(*face), image.as_bytes()) + }), + color_type_to_pixel_data_format(color_type), + ) + } + }?; gl_texture.set_wrap( curr_gl_context, @@ -1314,6 +1452,18 @@ fn create_gl_texture( Ok(gl_texture) } +fn cube_map_texture_face_to_gl(face: CubeMapTextureFace) -> GlCubeMapTextureFace +{ + match face { + CubeMapTextureFace::PositiveX => GlCubeMapTextureFace::PositiveX, + CubeMapTextureFace::NegativeX => GlCubeMapTextureFace::NegativeX, + CubeMapTextureFace::PositiveY => GlCubeMapTextureFace::PositiveY, + CubeMapTextureFace::NegativeY => GlCubeMapTextureFace::NegativeY, + CubeMapTextureFace::PositiveZ => GlCubeMapTextureFace::PositiveZ, + CubeMapTextureFace::NegativeZ => GlCubeMapTextureFace::NegativeZ, + } +} + fn create_shader_program( current_context: &MaybeCurrentContextWithFns, shader_program: &ShaderProgram, diff --git a/engine/src/rendering/shader/cursor.rs b/engine/src/rendering/shader/cursor.rs index 169ad0b..5cc742d 100644 --- a/engine/src/rendering/shader/cursor.rs +++ b/engine/src/rendering/shader/cursor.rs @@ -275,15 +275,23 @@ impl BindingValue ( Self::Texture(_, BindingTextureKind::Texture2D), TypeKind::Resource, - _, - _, - _, + .., Some(res_shape), ) if (res_shape & ResourceShape::BASE) .contains(ResourceShape::TEXTURE_2D) => { Ok(()) } + ( + Self::Texture(_, BindingTextureKind::Cube), + TypeKind::Resource, + .., + Some(res_shape), + ) if (res_shape & ResourceShape::BASE) + .contains(ResourceShape::TEXTURE_CUBE) => + { + Ok(()) + } _ => { cold_path(); Err(BindingError::IncorrectValueType { @@ -356,6 +364,7 @@ pub struct Binding pub enum BindingTextureKind { Texture2D, + Cube, } #[derive(Debug, thiserror::Error)] diff --git a/engine/src/texture.rs b/engine/src/texture.rs index af56e97..3bfe171 100644 --- a/engine/src/texture.rs +++ b/engine/src/texture.rs @@ -13,12 +13,37 @@ pub static WHITE_1X1_ASSET_LABEL: LazyLock<AssetLabel> = LazyLock::new(|| AssetL }); #[derive(Debug, Clone)] -pub struct Texture +pub enum Texture +{ + Texture2D(Tex2D), + CubeMap(TexCubeMap), +} + +#[derive(Debug, Clone)] +pub struct Tex2D { pub image: Image, pub properties: Properties, } +#[derive(Debug, Clone)] +pub struct TexCubeMap +{ + pub images: [(CubeMapFace, Image); 6], + pub properties: Properties, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum CubeMapFace +{ + PositiveX, + NegativeX, + PositiveY, + NegativeY, + PositiveZ, + NegativeZ, +} + builder! { /// Texture properties #[builder(name = PropertiesBuilder, derives=(Debug, Clone))] @@ -110,10 +135,10 @@ pub(crate) fn initialize(assets: &mut Assets) assets.store_with_label( WHITE_1X1_ASSET_LABEL.clone(), - Texture { + Texture::Texture2D(Tex2D { image: Image::from_color(Rgba::<u8>::white(), Dimens { width: 1, height: 1 }), properties: Properties::default(), - }, + }), ); } @@ -123,12 +148,12 @@ fn import( settings: Option<&'_ ImportSettings>, ) -> Result<(), ImageError> { - asset_submitter.submit_store(Texture { + asset_submitter.submit_store(Texture::Texture2D(Tex2D { image: Image::open(path)?, properties: settings .map(|settings| settings.properties.clone()) .unwrap_or_default(), - }); + })); Ok(()) } diff --git a/engine/src/ui/dear_imgui.rs b/engine/src/ui/dear_imgui.rs index b9775ea..60067e1 100644 --- a/engine/src/ui/dear_imgui.rs +++ b/engine/src/ui/dear_imgui.rs @@ -74,7 +74,7 @@ use crate::rendering::{ SurfaceSpec, PRE_RENDER_PHASE, }; -use crate::texture::{Properties as TextureProperties, Texture}; +use crate::texture::{Properties as TextureProperties, Tex2D, Texture}; use crate::util::MapVec; use crate::vector::Vec2; use crate::windowing::dpi::PhysicalSize; @@ -542,10 +542,10 @@ fn add_drawing_render_pass( render_pass.commands.push(RenderingCommand::CreateTexture( texture_object_id, - AssetOrValue::Value(Texture { + AssetOrValue::Value(Texture::Texture2D(Tex2D { image, properties: TextureProperties::default(), - }), + })), )); let texture_lookup_id = TextureLookupId::new(); |
