summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine/src/rendering.rs35
-rw-r--r--engine/src/rendering/backend/opengl.rs327
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(