diff options
Diffstat (limited to 'engine/src/rendering/backend/opengl.rs')
| -rw-r--r-- | engine/src/rendering/backend/opengl.rs | 234 |
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, |
