summaryrefslogtreecommitdiff
path: root/engine/src
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src')
-rw-r--r--engine/src/rendering.rs41
-rw-r--r--engine/src/rendering/backend/opengl.rs234
-rw-r--r--engine/src/rendering/shader/cursor.rs15
-rw-r--r--engine/src/texture.rs35
-rw-r--r--engine/src/ui/dear_imgui.rs6
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();