summaryrefslogtreecommitdiff
path: root/engine/src/rendering/backend/opengl.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-08-28 18:32:58 +0200
committerHampusM <hampus@hampusmat.com>2026-08-28 18:32:58 +0200
commitbe94cec078e86e643f52f0f3041a98b36e43ec8b (patch)
tree0e79657d85020e76b0dc3e0586f9dcdacbfcd14e /engine/src/rendering/backend/opengl.rs
parentd04bc21ac58a0bd8bcf8fa2fbb87f7b1dd4b140e (diff)
feat(engine): add ability to create textures without imagesHEADmaster
Diffstat (limited to 'engine/src/rendering/backend/opengl.rs')
-rw-r--r--engine/src/rendering/backend/opengl.rs295
1 files changed, 52 insertions, 243 deletions
diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs
index 755388c..4d2a74f 100644
--- a/engine/src/rendering/backend/opengl.rs
+++ b/engine/src/rendering/backend/opengl.rs
@@ -6,7 +6,6 @@ use std::hint::cold_path;
use std::num::NonZero;
use ecs::query::term::With;
-use ecs::util::BorrowedOrOwned;
use glutin::config::Config as GlutinConfig;
use glutin::display::GetGlDisplay;
use glutin::error::Error as GlutinError;
@@ -77,7 +76,6 @@ use crate::ecs::actions::Actions;
use crate::ecs::query::term::Without;
use crate::ecs::sole::Single;
use crate::ecs::{Component, Query, Sole};
-use crate::image::{ColorType as ImageColorType, Image};
use crate::reflection::EnumReflectionExt;
use crate::rendering::backend::opengl::glutin_compat::{
DisplayBuilder,
@@ -117,6 +115,7 @@ use crate::rendering::{
Surface,
SurfaceId,
TargetWindow,
+ TextureCreation,
TexturePixelDataFormat,
TextureUpdate,
POST_RENDER_PHASE,
@@ -126,8 +125,6 @@ use crate::texture::{
CubeMapFace as CubeMapTextureFace,
Filtering as TextureFiltering,
Properties as TextureProperties,
- TexCubeMap,
- Texture,
Wrapping as TextureWrapping,
};
use crate::util::{MapVec, OptionExt};
@@ -364,7 +361,7 @@ enum BackendResource
{
texture: GlTexture,
pixel_data_format: TexturePixelDataFormat,
- metadata: TextureKind,
+ kind: TextureKind,
},
}
@@ -953,22 +950,39 @@ fn handle_commands(
)
.unwrap();
}
- Command::CreateTexture(object_id, texture) => {
- let _ = backend_resources.try_create_resource::<()>(
- object_store,
- object_id,
- || {
- let (gl_texture, texture_pixel_data_format, texture_kind) =
- create_texture_object(gl_context, assets, texture)
- .map_err(|_| ())?;
-
- Ok(BackendResource::Texture {
- texture: gl_texture,
- pixel_data_format: texture_pixel_data_format,
- metadata: texture_kind,
- })
- },
- );
+ Command::CreateTexture {
+ obj_id,
+ pixel_data_format,
+ creation,
+ properties,
+ } => {
+ let kind = match &creation {
+ TextureCreation::Texture2D { .. } => TextureKind::Texture2D,
+ TextureCreation::CubeMap { .. } => TextureKind::CubeMap,
+ };
+
+ if let Err(err) = backend_resources
+ .try_create_resource::<opengl_bindings::texture::Error>(
+ object_store,
+ obj_id,
+ || {
+ let gl_texture = create_gl_texture(
+ gl_context,
+ creation,
+ pixel_data_format,
+ &properties,
+ )?;
+
+ Ok(BackendResource::Texture {
+ texture: gl_texture,
+ pixel_data_format,
+ kind,
+ })
+ },
+ )
+ {
+ tracing::error!("Failed to create texture: {err}");
+ }
}
Command::UpdateTexture {
obj_id,
@@ -987,7 +1001,7 @@ fn handle_commands(
let BackendResource::Texture {
texture: gl_texture,
pixel_data_format: tex_pixel_data_format,
- metadata: tex_metadata,
+ kind: tex_metadata,
} = texture_resource
else {
unreachable!();
@@ -1298,176 +1312,6 @@ enum CreateGlContextError
MakeContextCurrent(#[source] GlMakeContextCurrentError),
}
-enum TextureCreationData<'a>
-{
- Texture2D
- {
- image: BorrowedOrOwned<'a, Image>
- },
- CubeMap
- {
- images: [(CubeMapTextureFace, BorrowedOrOwned<'a, Image>); 6],
- color_type: ImageColorType,
- is_srgb: bool,
- size: Dimens<u32>,
- },
-}
-
-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
-}
-
-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.
- //
- // Read more about this at
- // wikis.khronos.org/opengl/Common_Mistakes#Texture_upload_and_pixel_reads
- //
- // To prevent this, the image is converted to RGBA8. RGBA8 images have a pixel
- // size of 4 bytes so they cannot have any alignment problems
-
- // TODO: Make it clearer in warning log which texture is being talked about
- tracing::warn!(concat!(
- "Converting texture image from RGB8 to RGBA8 to prevent alignment ",
- "problems. This conversion may be slow. Consider changing the ",
- "texture image's pixel format to RGBA8"
- ));
-
- images.map(|(extra, image)| (extra, BorrowedOrOwned::Owned(image.to_rgba8())))
- }
- _ => images.map(|(extra, image)| (extra, BorrowedOrOwned::Borrowned(image))),
- }
-}
-
-#[tracing::instrument(skip_all)]
-fn create_texture_object(
- curr_gl_ctx: &MaybeCurrentContextWithFns,
- assets: &Assets,
- texture: AssetOrValue<Texture>,
-) -> Result<(GlTexture, TexturePixelDataFormat, TextureKind), ()>
-{
- 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 Err(());
- };
-
- texture
- }
- AssetOrValue::Value(texture) => texture,
- };
-
- 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(),
- );
-
- 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 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,
- );
-
- let tex_pixel_data_format =
- TexturePixelDataFormat::for_image(&images[0].1)
- .expect("No pixel data format is available for image");
-
- (
- 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,
- )
- }
- };
-
- 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,
@@ -1540,12 +1384,6 @@ fn draw_mesh(
Ok(())
}
-struct ImageDataProperties
-{
- color_type: ImageColorType,
- is_srgb: bool,
-}
-
fn tex_pixel_data_format_into_gl(
tex_pixel_data_format: TexturePixelDataFormat,
) -> GlTexturePixelDataFormat
@@ -1582,59 +1420,30 @@ fn tex_pixel_data_format_into_gl(
}
}
-fn create_pixel_data_format(
- image_data_props: ImageDataProperties,
-) -> GlTexturePixelDataFormat
-{
- match image_data_props.color_type {
- ImageColorType::Rgb8 if image_data_props.is_srgb => {
- GlTexturePixelDataFormat::Srgb(
- opengl_bindings::texture::SrgbDataType::UnsignedByte,
- )
- }
- ImageColorType::Rgb8 => GlTexturePixelDataFormat::Rgb(
- opengl_bindings::texture::RgbDataType::UnsignedByte,
- ),
- ImageColorType::Rgba8 if image_data_props.is_srgb => {
- GlTexturePixelDataFormat::Srgba(
- opengl_bindings::texture::SrgbaDataType::UnsignedByte,
- )
- }
- ImageColorType::Rgba8 => GlTexturePixelDataFormat::Rgba(
- opengl_bindings::texture::RgbaDataType::UnsignedByte,
- ),
- _ => {
- unimplemented!();
- }
- }
-}
-
fn create_gl_texture(
curr_gl_context: &MaybeCurrentContextWithFns,
- texture_things: TextureCreationData<'_>,
+ texture_creation: TextureCreation,
+ texture_pixel_data_format: TexturePixelDataFormat,
texture_properties: &TextureProperties,
) -> Result<GlTexture, GlTextureError>
{
- let gl_texture = match texture_things {
- TextureCreationData::Texture2D { image } => GlTexture::builder()
- .size(image.dimensions().into())
- .create_2d(
+ let gl_texture = match texture_creation {
+ TextureCreation::Texture2D { size, image } => {
+ GlTexture::builder().size(size.into()).create_2d(
curr_gl_context,
- Some(image.as_bytes()),
- create_pixel_data_format(ImageDataProperties {
- color_type: image.color_type(),
- is_srgb: image.color_space_is_srgb(),
- }),
- ),
- TextureCreationData::CubeMap { images, color_type, is_srgb, size } => {
+ image.as_deref(),
+ tex_pixel_data_format_into_gl(texture_pixel_data_format),
+ )
+ }
+ TextureCreation::CubeMap { size, images } => {
GlTexture::builder().size(size.into()).create_cube_map(
curr_gl_context,
- Some(std::array::from_fn::<_, 6, _>(|index| {
- let (face, image) = &images[index];
-
- (cube_map_texture_face_to_gl(*face), image.as_bytes())
- })),
- create_pixel_data_format(ImageDataProperties { color_type, is_srgb }),
+ images.as_ref().map(|images| {
+ images.each_ref().map(|(face, image)| {
+ (cube_map_texture_face_to_gl(*face), &**image)
+ })
+ }),
+ tex_pixel_data_format_into_gl(texture_pixel_data_format),
)
}
}?;