summaryrefslogtreecommitdiff
path: root/engine/src/rendering/backend/opengl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/rendering/backend/opengl.rs')
-rw-r--r--engine/src/rendering/backend/opengl.rs234
1 files changed, 192 insertions, 42 deletions
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,