diff options
Diffstat (limited to 'engine/src')
| -rw-r--r-- | engine/src/rendering.rs | 35 | ||||
| -rw-r--r-- | engine/src/rendering/backend/opengl.rs | 327 |
2 files changed, 265 insertions, 97 deletions
diff --git a/engine/src/rendering.rs b/engine/src/rendering.rs index 7a46b29..5219d0a 100644 --- a/engine/src/rendering.rs +++ b/engine/src/rendering.rs @@ -19,6 +19,7 @@ use crate::ecs::system::initializable::Initializable; use crate::ecs::system::observer::Observe; use crate::ecs::system::Into; use crate::ecs::{declare_entity, pair, Component, Query, Sole}; +use crate::image::{ColorType as ImageColorType, Image}; use crate::mesh::Mesh; use crate::rendering::blending::Config as BlendingConfig; use crate::rendering::object::{Id as ObjectId, Store as ObjectStore}; @@ -556,35 +557,35 @@ struct ActiveDrawProperties pub draw_properties: DrawProperties, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[non_exhaustive] pub enum RgbTextureDataType { UnsignedByte, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[non_exhaustive] pub enum RgbaTextureDataType { UnsignedByte, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[non_exhaustive] pub enum SrgbTextureDataType { UnsignedByte, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[non_exhaustive] pub enum SrgbaTextureDataType { UnsignedByte, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[non_exhaustive] pub enum TexturePixelDataFormat { @@ -593,3 +594,27 @@ pub enum TexturePixelDataFormat Srgb(SrgbTextureDataType), Srgba(SrgbaTextureDataType), } + +impl TexturePixelDataFormat +{ + pub fn for_image(image: &Image) -> Option<Self> + { + let is_srgb = image.color_space_is_srgb(); + + match image.color_type() { + ImageColorType::Rgb8 if is_srgb => Some(TexturePixelDataFormat::Srgb( + SrgbTextureDataType::UnsignedByte, + )), + ImageColorType::Rgb8 => Some(TexturePixelDataFormat::Rgb( + RgbTextureDataType::UnsignedByte, + )), + ImageColorType::Rgba8 if is_srgb => Some(TexturePixelDataFormat::Srgba( + SrgbaTextureDataType::UnsignedByte, + )), + ImageColorType::Rgba8 => Some(TexturePixelDataFormat::Rgba( + RgbaTextureDataType::UnsignedByte, + )), + _ => None, + } + } +} diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs index 5ffcc4a..2ee4a1a 100644 --- a/engine/src/rendering/backend/opengl.rs +++ b/engine/src/rendering/backend/opengl.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use std::collections::HashMap; +use std::hint::cold_path; use std::num::NonZero; use ecs::query::term::With; @@ -180,6 +181,19 @@ enum GraphicsContextObject program: GlShaderProgram, program_metadata: ShaderProgramMetadata, }, + Texture + { + texture: GlTexture, + pixel_data_format: TexturePixelDataFormat, + metadata: TextureKind, + }, +} + +#[derive(Debug)] +enum TextureKind +{ + Texture2D, + CubeMap, } #[derive(Debug, Default)] @@ -707,7 +721,29 @@ fn handle_commands( continue; } - let gl_texture = GlTexture::from_raw(texture_obj.as_raw()); + let Some(texture_graphics_ctx_obj) = + graphics_ctx_objects.get(&texture_obj.as_raw()) + else { + cold_path(); + tracing::error!( + ?texture_object_id, + key = texture_obj.as_raw(), + "Graphics context does not contain a object with this key" + ); + continue; + }; + + let GraphicsContextObject::Texture { texture: gl_texture, .. } = + texture_graphics_ctx_obj + else { + cold_path(); + tracing::error!( + ?texture_object_id, + key = texture_obj.as_raw(), + "Graphics context object with this key is not a texture" + ); + continue; + }; gl_texture .bind_to_texture_unit(gl_context, binding_location.binding_index); @@ -794,15 +830,37 @@ fn handle_commands( .unwrap(); } Command::CreateTexture(texture_object_id, texture) => { - if let Err(err) = create_texture_object( - gl_context, - object_store, - assets, - texture_object_id, - texture, - ) { - tracing::error!("Failed to create texture object: {err}"); + if object_store.contains_non_pending_with_id(&texture_object_id) { + tracing::error!( + texture_object_id=?texture_object_id, + "Object store already contains object with this ID" + ); + continue; } + + let Ok((gl_texture, texture_pixel_data_format, texture_kind)) = + create_texture_object(gl_context, assets, texture) + else { + continue; + }; + + let key = *next_graphics_ctx_object_key; + + graphics_ctx_objects.insert( + key, + GraphicsContextObject::Texture { + texture: gl_texture, + pixel_data_format: texture_pixel_data_format, + metadata: texture_kind, + }, + ); + + object_store.insert( + texture_object_id, + Object::from_raw(key, ObjectKind::Texture), + ); + + *next_graphics_ctx_object_key += 1; } Command::UpdateTexture { obj_id, @@ -810,10 +868,79 @@ fn handle_commands( pixel_data_format, update, } => { + let Some(texture_obj) = object_store.get_obj(&obj_id) else { + cold_path(); + tracing::error!( + texture_object_id=?obj_id, + "Object store does not contain a object with this ID" + ); + continue; + }; + + if texture_obj.kind() != ObjectKind::Texture { + cold_path(); + tracing::error!( + texture_object_id=?obj_id, + "Object with this ID is not a texture" + ); + continue; + } + + let Some(texture_graphics_ctx_obj) = + graphics_ctx_objects.get(&texture_obj.as_raw()) + else { + cold_path(); + tracing::error!( + texture_object_id=?obj_id, + key=texture_obj.as_raw(), + "Graphics context does not contain a object with this key" + ); + continue; + }; + + let GraphicsContextObject::Texture { + texture: gl_texture, + pixel_data_format: tex_pixel_data_format, + metadata: tex_metadata, + } = texture_graphics_ctx_obj + else { + cold_path(); + tracing::error!( + object_id=?obj_id, + key=texture_obj.as_raw(), + "Graphics context object with this key is not a texture" + ); + continue; + }; + + if !matches!( + (&update, tex_metadata), + (TextureUpdate::Texture2D { .. }, TextureKind::Texture2D) + | (TextureUpdate::CubeMap { .. }, TextureKind::CubeMap) + ) { + tracing::error!( + texture_object_id = ?obj_id, + key = texture_obj.as_raw(), + "Texture is of incorrect kind" + ); + continue; + } + + if &pixel_data_format != tex_pixel_data_format { + cold_path(); + tracing::error!( + texture_object_id = ?obj_id, + key = texture_obj.as_raw(), + expected_pixel_data_format = ?*tex_pixel_data_format, + found_pixel_data_format = ?pixel_data_format, + "Texture has incorrect pixel data format" + ); + continue; + } + if let Err(err) = update_texture_object( gl_context, - object_store, - obj_id, + gl_texture, pixels, pixel_data_format, update, @@ -822,17 +949,50 @@ fn handle_commands( } } Command::RemoveTexture(texture_object_id) => { + if let Some(obj) = object_store.get_obj(&texture_object_id) { + if obj.kind() != ObjectKind::Texture { + cold_path(); + tracing::error!( + ?texture_object_id, + "Object with this ID is not a texture" + ); + continue; + } + } + let Some(texture_object) = object_store.remove(&texture_object_id).flatten() else { tracing::error!( - object_id=?texture_object_id, - "Object store does not contain a texture object with this ID" + texture_object_id=?texture_object_id, + "Object store does not contain a object with this ID" ); continue; }; - let gl_texture = GlTexture::from_raw(texture_object.as_raw()); + let Some(texture_graphics_ctx_obj) = + graphics_ctx_objects.remove(&texture_object.as_raw()) + else { + cold_path(); + tracing::error!( + ?texture_object_id, + key = texture_object.as_raw(), + "Graphics context does not contain a object with this key" + ); + continue; + }; + + let GraphicsContextObject::Texture { texture: gl_texture, .. } = + texture_graphics_ctx_obj + else { + cold_path(); + tracing::error!( + object_id = ?texture_object_id, + key = texture_object.as_raw(), + "Graphics context object with this key is not a texture" + ); + continue; + }; gl_texture.delete(gl_context); } @@ -1286,20 +1446,10 @@ fn convert_textures_if_unaligned<const IMAGE_CNT: usize, Extra>( #[tracing::instrument(skip_all)] fn create_texture_object( curr_gl_ctx: &MaybeCurrentContextWithFns, - object_store: &mut ObjectStore, assets: &Assets, - texture_object_id: ObjectId, texture: AssetOrValue<Texture>, -) -> Result<(), GlTextureError> +) -> Result<(GlTexture, TexturePixelDataFormat, TextureKind), ()> { - if object_store.contains_non_pending_with_id(&texture_object_id) { - tracing::error!( - texture_object_id=?texture_object_id, - "Object store already contains object with this ID" - ); - return Ok(()); - } - let texture = match &texture { AssetOrValue::Asset(texture_asset) => { let Some(texture) = assets.get(&texture_asset) else { @@ -1307,7 +1457,7 @@ fn create_texture_object( texture_asset_id=?texture_asset.id(), "Texture asset does not exist" ); - return Ok(()); + return Err(()); }; texture @@ -1315,90 +1465,83 @@ fn create_texture_object( 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(), - ); + let (texture_things, texture_properties, texture_pixel_data_format, texture_kind) = + 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 tex_pixel_data_format = TexturePixelDataFormat::for_image(&image) + .expect("No pixel data format is available for image"); + + ( + TextureCreationData::Texture2D { image }, + &texture.properties, + tex_pixel_data_format, + TextureKind::Texture2D, + ) } + Texture::CubeMap(texture) => { + if !validate_cube_map_texture(texture) { + return Err(()); + } - 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 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]; + 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, - ); + (*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, - ) - } - }; + let tex_pixel_data_format = + TexturePixelDataFormat::for_image(&images[0].1) + .expect("No pixel data format is available for image"); - object_store.insert( - texture_object_id, - Object::from_raw( - create_gl_texture(curr_gl_ctx, texture_things, texture_properties)? - .into_raw(), - ObjectKind::Texture, - ), - ); + ( + TextureCreationData::CubeMap { + images, + color_type: first_image_color_type, + is_srgb: first_image_is_srgb, + size: first_image_size, + }, + &texture.properties, + tex_pixel_data_format, + TextureKind::CubeMap, + ) + } + }; - Ok(()) + let gl_texture = + match create_gl_texture(curr_gl_ctx, texture_things, texture_properties) { + Ok(gl_texture) => gl_texture, + Err(err) => { + tracing::error!("Failed to create texture object: {err}"); + return Err(()); + } + }; + + Ok((gl_texture, texture_pixel_data_format, texture_kind)) } #[tracing::instrument(skip_all)] fn update_texture_object( curr_gl_ctx: &MaybeCurrentContextWithFns, - object_store: &mut ObjectStore, - texture_object_id: ObjectId, + gl_texture: &GlTexture, pixels: Box<[u8]>, pixel_data_format: TexturePixelDataFormat, update: TextureUpdate, ) -> Result<(), GlTextureError> { - let Some(texture_obj) = object_store.get_obj(&texture_object_id) else { - tracing::error!( - texture_object_id=?texture_object_id, - "Object store does not contain a object with this ID" - ); - return Ok(()); - }; - - if texture_obj.kind() != ObjectKind::Texture { - tracing::error!( - texture_object_id=?texture_object_id, - "Object with this ID is not a texture" - ); - return Ok(()); - } - - let gl_texture = GlTexture::from_raw(texture_obj.as_raw()); - match update { TextureUpdate::Texture2D { size, offset } => { gl_texture.store_image_2d( |
