summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine/src/rendering.rs41
-rw-r--r--engine/src/rendering/backend/opengl.rs234
-rw-r--r--engine/src/rendering/shader/cursor.rs15
-rw-r--r--engine/src/texture.rs35
-rw-r--r--engine/src/ui/dear_imgui.rs6
-rw-r--r--opengl-bindings/Cargo.toml1
-rw-r--r--opengl-bindings/src/texture.rs300
7 files changed, 473 insertions, 159 deletions
diff --git a/engine/src/rendering.rs b/engine/src/rendering.rs
index dc3cb76..f40f774 100644
--- a/engine/src/rendering.rs
+++ b/engine/src/rendering.rs
@@ -216,6 +216,7 @@ pub enum Command
ActivateShader(ObjectId),
SetShaderBinding(ShaderBinding),
CreateTexture(ObjectId, AssetOrValue<Texture>),
+ // TODO: Make UpdateTexture command able to handle textures other than 2D textures
UpdateTexture
{
obj_id: ObjectId,
@@ -321,6 +322,37 @@ impl Default for ScissorBox
}
}
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
+pub enum DepthFunction
+{
+ /// Never passes.
+ Never,
+
+ /// Passes if the incoming depth value is less than the stored depth value.
+ #[default]
+ Less,
+
+ /// Passes if the incoming depth value is equal to the stored depth value.
+ Equal,
+
+ /// Passes if the incoming depth value is less than or equal to the stored depth
+ /// value.
+ LessOrEqual,
+
+ /// Passes if the incoming depth value is greater than the stored depth value.
+ Greater,
+
+ /// Passes if the incoming depth value is not equal to the stored depth value.
+ NotEqual,
+
+ /// Passes if the incoming depth value is greater than or equal to the stored depth
+ /// value.
+ GreaterOrEqual,
+
+ /// Always passes.
+ Always,
+}
+
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct DrawProperties
@@ -329,6 +361,7 @@ pub struct DrawProperties
pub blending_enabled: bool,
pub blending_config: BlendingConfig,
pub depth_test_enabled: bool,
+ pub depth_function: DepthFunction,
pub scissor_test_enabled: bool,
pub scissor_box: ScissorBox,
pub face_culling_enabled: bool,
@@ -343,6 +376,7 @@ impl Default for DrawProperties
blending_enabled: false,
blending_config: BlendingConfig::default(),
depth_test_enabled: true,
+ depth_function: DepthFunction::default(),
scissor_test_enabled: false,
scissor_box: ScissorBox::default(),
face_culling_enabled: false,
@@ -358,9 +392,10 @@ bitflags! {
const BLENDING_CONFIG = 1 << 1;
const BLENDING_ENABLED = 1 << 2;
const DEPTH_TEST_ENABLED = 1 << 3;
- const SCISSOR_TEST_ENABLED = 1 << 4;
- const SCISSOR_BOX = 1 << 5;
- const FACE_CULLING_ENABLED = 1 << 6;
+ const DEPTH_FUNCTION = 1 << 4;
+ const SCISSOR_TEST_ENABLED = 1 << 5;
+ const SCISSOR_BOX = 1 << 6;
+ const FACE_CULLING_ENABLED = 1 << 7;
}
}
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,
diff --git a/engine/src/rendering/shader/cursor.rs b/engine/src/rendering/shader/cursor.rs
index 169ad0b..5cc742d 100644
--- a/engine/src/rendering/shader/cursor.rs
+++ b/engine/src/rendering/shader/cursor.rs
@@ -275,15 +275,23 @@ impl BindingValue
(
Self::Texture(_, BindingTextureKind::Texture2D),
TypeKind::Resource,
- _,
- _,
- _,
+ ..,
Some(res_shape),
) if (res_shape & ResourceShape::BASE)
.contains(ResourceShape::TEXTURE_2D) =>
{
Ok(())
}
+ (
+ Self::Texture(_, BindingTextureKind::Cube),
+ TypeKind::Resource,
+ ..,
+ Some(res_shape),
+ ) if (res_shape & ResourceShape::BASE)
+ .contains(ResourceShape::TEXTURE_CUBE) =>
+ {
+ Ok(())
+ }
_ => {
cold_path();
Err(BindingError::IncorrectValueType {
@@ -356,6 +364,7 @@ pub struct Binding
pub enum BindingTextureKind
{
Texture2D,
+ Cube,
}
#[derive(Debug, thiserror::Error)]
diff --git a/engine/src/texture.rs b/engine/src/texture.rs
index af56e97..3bfe171 100644
--- a/engine/src/texture.rs
+++ b/engine/src/texture.rs
@@ -13,12 +13,37 @@ pub static WHITE_1X1_ASSET_LABEL: LazyLock<AssetLabel> = LazyLock::new(|| AssetL
});
#[derive(Debug, Clone)]
-pub struct Texture
+pub enum Texture
+{
+ Texture2D(Tex2D),
+ CubeMap(TexCubeMap),
+}
+
+#[derive(Debug, Clone)]
+pub struct Tex2D
{
pub image: Image,
pub properties: Properties,
}
+#[derive(Debug, Clone)]
+pub struct TexCubeMap
+{
+ pub images: [(CubeMapFace, Image); 6],
+ pub properties: Properties,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum CubeMapFace
+{
+ PositiveX,
+ NegativeX,
+ PositiveY,
+ NegativeY,
+ PositiveZ,
+ NegativeZ,
+}
+
builder! {
/// Texture properties
#[builder(name = PropertiesBuilder, derives=(Debug, Clone))]
@@ -110,10 +135,10 @@ pub(crate) fn initialize(assets: &mut Assets)
assets.store_with_label(
WHITE_1X1_ASSET_LABEL.clone(),
- Texture {
+ Texture::Texture2D(Tex2D {
image: Image::from_color(Rgba::<u8>::white(), Dimens { width: 1, height: 1 }),
properties: Properties::default(),
- },
+ }),
);
}
@@ -123,12 +148,12 @@ fn import(
settings: Option<&'_ ImportSettings>,
) -> Result<(), ImageError>
{
- asset_submitter.submit_store(Texture {
+ asset_submitter.submit_store(Texture::Texture2D(Tex2D {
image: Image::open(path)?,
properties: settings
.map(|settings| settings.properties.clone())
.unwrap_or_default(),
- });
+ }));
Ok(())
}
diff --git a/engine/src/ui/dear_imgui.rs b/engine/src/ui/dear_imgui.rs
index b9775ea..60067e1 100644
--- a/engine/src/ui/dear_imgui.rs
+++ b/engine/src/ui/dear_imgui.rs
@@ -74,7 +74,7 @@ use crate::rendering::{
SurfaceSpec,
PRE_RENDER_PHASE,
};
-use crate::texture::{Properties as TextureProperties, Texture};
+use crate::texture::{Properties as TextureProperties, Tex2D, Texture};
use crate::util::MapVec;
use crate::vector::Vec2;
use crate::windowing::dpi::PhysicalSize;
@@ -542,10 +542,10 @@ fn add_drawing_render_pass(
render_pass.commands.push(RenderingCommand::CreateTexture(
texture_object_id,
- AssetOrValue::Value(Texture {
+ AssetOrValue::Value(Texture::Texture2D(Tex2D {
image,
properties: TextureProperties::default(),
- }),
+ })),
));
let texture_lookup_id = TextureLookupId::new();
diff --git a/opengl-bindings/Cargo.toml b/opengl-bindings/Cargo.toml
index f2252a7..cabbf90 100644
--- a/opengl-bindings/Cargo.toml
+++ b/opengl-bindings/Cargo.toml
@@ -31,6 +31,7 @@ gl_commands = [
"BindVertexArray",
"TextureStorage2D",
"TextureSubImage2D",
+ "TextureSubImage3D",
"DeleteTextures",
"GenerateTextureMipmap",
"TextureParameteri",
diff --git a/opengl-bindings/src/texture.rs b/opengl-bindings/src/texture.rs
index be52135..c317c92 100644
--- a/opengl-bindings/src/texture.rs
+++ b/opengl-bindings/src/texture.rs
@@ -4,28 +4,15 @@ use crate::data_types::{Dimens, Vec2};
use crate::MaybeCurrentContextWithFns;
#[derive(Debug)]
-pub struct Builder<'image>
+pub struct Builder
{
- image: Cow<'image, [u8]>,
- pixel_data_format: PixelDataFormat,
size: Dimens<u32>,
color_space: ColorSpace,
mipmap_levels: u16,
}
-impl<'image> Builder<'image>
+impl Builder
{
- pub fn image(
- mut self,
- image: impl Into<Cow<'image, [u8]>>,
- pixel_data_format: PixelDataFormat,
- ) -> Self
- {
- self.image = image.into();
- self.pixel_data_format = pixel_data_format;
- self
- }
-
pub fn size(mut self, size: Dimens<u32>) -> Self
{
self.size = size;
@@ -45,51 +32,101 @@ impl<'image> Builder<'image>
}
#[must_use]
- pub fn create(
+ pub fn create_2d<'image>(
&self,
current_context: &MaybeCurrentContextWithFns,
+ image: impl Into<Cow<'image, [u8]>>,
+ pixel_data_format: PixelDataFormat,
) -> Result<Texture, Error>
{
+ let image = image.into();
+
check_image_buffer_len_correct_for_size(
- self.image.as_ref(),
- self.size,
- self.pixel_data_format,
+ image.as_ref(),
+ [self.size.width, self.size.height, 1],
+ pixel_data_format,
)?;
- let size = try_convert_size(self.size.clone())?;
+ let size = try_convert_size([self.size.width, self.size.height])?;
- let texture = Texture::new(current_context);
+ let texture = Texture::new(current_context, crate::sys::TEXTURE_2D);
- texture.alloc(
+ texture.alloc_2d(
current_context,
self.mipmap_levels,
- self.pixel_data_format,
+ pixel_data_format,
self.color_space,
size,
);
- texture.sub_image(
+ texture.sub_image_2d(
current_context,
0,
- Vec2 { x: 0, y: 0 },
+ [0, 0],
+ size,
+ pixel_data_format,
+ image.as_ref(),
+ );
+
+ texture.generate_mipmap(current_context);
+
+ Ok(texture)
+ }
+
+ #[must_use]
+ pub fn create_cube_map<'image, Image>(
+ &self,
+ current_context: &MaybeCurrentContextWithFns,
+ images: [(CubeMapFace, Image); 6],
+ pixel_data_format: PixelDataFormat,
+ ) -> Result<Texture, Error>
+ where
+ Image: Into<Cow<'image, [u8]>>,
+ {
+ let images = images.map(|(face, image)| (face, image.into()));
+
+ for (_, image) in &images {
+ check_image_buffer_len_correct_for_size(
+ image.as_ref(),
+ [self.size.width, self.size.height, 1],
+ pixel_data_format,
+ )?;
+ }
+
+ let size = try_convert_size([self.size.width, self.size.height])?;
+
+ let texture = Texture::new(current_context, crate::sys::TEXTURE_CUBE_MAP);
+
+ texture.alloc_2d(
+ current_context,
+ self.mipmap_levels,
+ pixel_data_format,
+ self.color_space,
size,
- self.pixel_data_format,
- self.image.as_ref(),
);
+ for (face, image) in images {
+ texture.sub_image_3d(
+ current_context,
+ 0,
+ [0, 0, face as crate::sys::types::GLint],
+ [size[0], size[1], 1],
+ pixel_data_format,
+ image.as_ref(),
+ );
+ }
+
texture.generate_mipmap(current_context);
Ok(texture)
}
}
-impl<'image> Default for Builder<'image>
+impl Default for Builder
{
fn default() -> Self
{
Self {
- image: Cow::Borrowed(&[]),
- pixel_data_format: PixelDataFormat::default(),
size: Dimens::default(),
color_space: ColorSpace::default(),
mipmap_levels: 1,
@@ -105,7 +142,7 @@ pub struct Texture
impl Texture
{
- pub fn builder<'image>() -> Builder<'image>
+ pub fn builder() -> Builder
{
Builder::default()
}
@@ -130,7 +167,7 @@ impl Texture
}
}
- pub fn store_image(
+ pub fn store_image_2d(
&self,
current_context: &MaybeCurrentContextWithFns,
mipmap_level: u16,
@@ -140,12 +177,43 @@ impl Texture
image: &[u8],
) -> Result<(), Error>
{
+ check_image_buffer_len_correct_for_size(
+ image,
+ [size.width, size.height, 1],
+ pixel_data_format,
+ )?;
+
+ let offset = try_convert_offset([offset.x, offset.y])?;
+ let size = try_convert_size([size.width, size.height])?;
+
+ self.sub_image_2d(
+ current_context,
+ mipmap_level,
+ offset,
+ size,
+ pixel_data_format,
+ image,
+ );
+
+ Ok(())
+ }
+
+ pub fn store_image_3d(
+ &self,
+ current_context: &MaybeCurrentContextWithFns,
+ mipmap_level: u16,
+ offset: [u32; 3],
+ size: [u32; 3],
+ pixel_data_format: PixelDataFormat,
+ image: &[u8],
+ ) -> Result<(), Error>
+ {
check_image_buffer_len_correct_for_size(image, size, pixel_data_format)?;
let offset = try_convert_offset(offset)?;
let size = try_convert_size(size)?;
- self.sub_image(
+ self.sub_image_3d(
current_context,
mipmap_level,
offset,
@@ -227,28 +295,29 @@ impl Texture
self.texture
}
- fn new(current_context: &MaybeCurrentContextWithFns) -> Self
+ fn new(
+ current_context: &MaybeCurrentContextWithFns,
+ target: crate::sys::types::GLenum,
+ ) -> Self
{
let mut texture = crate::sys::types::GLuint::default();
unsafe {
- current_context.fns().CreateTextures(
- crate::sys::TEXTURE_2D,
- 1,
- &raw mut texture,
- );
+ current_context
+ .fns()
+ .CreateTextures(target, 1, &raw mut texture);
};
Self { texture }
}
- fn alloc(
+ fn alloc_2d(
&self,
current_context: &MaybeCurrentContextWithFns,
mipmap_levels: u16,
pixel_data_format: PixelDataFormat,
color_space: ColorSpace,
- size: Dimens<crate::sys::types::GLsizei>,
+ size: [crate::sys::types::GLsizei; 2],
)
{
unsafe {
@@ -256,18 +325,18 @@ impl Texture
self.texture,
mipmap_levels.into(),
pixel_data_format.to_sized_internal_format(color_space),
- size.width,
- size.height,
+ size[0],
+ size[1],
);
}
}
- fn sub_image(
+ fn sub_image_2d(
&self,
current_context: &MaybeCurrentContextWithFns,
mipmap_level: u16,
- offset: Vec2<crate::sys::types::GLint>,
- size: Dimens<crate::sys::types::GLsizei>,
+ offset: [crate::sys::types::GLint; 2],
+ size: [crate::sys::types::GLsizei; 2],
pixel_data_format: PixelDataFormat,
image: &[u8],
)
@@ -276,10 +345,37 @@ impl Texture
current_context.fns().TextureSubImage2D(
self.texture,
mipmap_level.into(),
- offset.x,
- offset.y,
- size.width,
- size.height,
+ offset[0],
+ offset[1],
+ size[0],
+ size[1],
+ pixel_data_format.to_format(),
+ crate::sys::UNSIGNED_BYTE,
+ image.as_ptr().cast(),
+ );
+ }
+ }
+
+ fn sub_image_3d(
+ &self,
+ current_context: &MaybeCurrentContextWithFns,
+ mipmap_level: u16,
+ offset: [crate::sys::types::GLint; 3],
+ size: [crate::sys::types::GLsizei; 3],
+ pixel_data_format: PixelDataFormat,
+ image: &[u8],
+ )
+ {
+ unsafe {
+ current_context.fns().TextureSubImage3D(
+ self.texture,
+ mipmap_level.into(),
+ offset[0],
+ offset[1],
+ offset[2],
+ size[0],
+ size[1],
+ size[2],
pixel_data_format.to_format(),
crate::sys::UNSIGNED_BYTE,
image.as_ptr().cast(),
@@ -365,33 +461,37 @@ pub enum ColorSpace
Srgb,
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum CubeMapFace
+{
+ PositiveX = 0,
+ NegativeX = 1,
+ PositiveY = 2,
+ NegativeY = 3,
+ PositiveZ = 4,
+ NegativeZ = 5,
+}
+
#[derive(Debug, thiserror::Error)]
pub enum Error
{
- #[error("Size width value ({value}) is too large. Must be < {max_value}")]
- SizeWidthValueTooLarge
- {
- value: u32, max_value: u32
- },
- #[error("Size height value ({value}) is too large. Must be < {max_value}")]
- SizeHeightValueTooLarge
+ #[error("Size value ({value}) is too large. Must be < {max_value}")]
+ ValueInSizeIsTooLarge
{
value: u32, max_value: u32
},
- #[error("Offset X value ({value}) is too large. Must be < {max_value}")]
- OffsetXValueTooLarge
- {
- value: u32, max_value: u32
- },
- #[error("Offset Y value ({value}) is too large. Must be < {max_value}")]
- OffsetYValueTooLarge
+ #[error("Offset value ({value}) is too large. Must be < {max_value}")]
+ ValueInOffsetIsTooLarge
{
value: u32, max_value: u32
},
#[error(
- "Incorrect image buffer length for size {size}. Expected {}, found {}",
+ "Incorrect image buffer length for size {}x{}x{}. Expected {}, found {}",
+ size[0],
+ size[1],
+ size[2],
expected_buffer_len,
buffer_len
)]
@@ -399,62 +499,56 @@ pub enum Error
{
expected_buffer_len: usize,
buffer_len: usize,
- size: Dimens<u32>,
+ size: [u32; 3],
},
}
-fn try_convert_size(
- size: Dimens<u32>,
-) -> Result<Dimens<crate::sys::types::GLsizei>, Error>
+fn try_convert_size<const LEN: usize>(
+ size: [u32; LEN],
+) -> Result<[crate::sys::types::GLsizei; LEN], Error>
{
- Ok(Dimens::<crate::sys::types::GLsizei> {
- width: size
- .width
- .try_into()
- .map_err(|_| Error::SizeWidthValueTooLarge {
- value: size.width,
- max_value: crate::sys::types::GLsizei::MAX as u32,
- })?,
- height: size
- .height
- .try_into()
- .map_err(|_| Error::SizeHeightValueTooLarge {
- value: size.height,
- max_value: crate::sys::types::GLsizei::MAX as u32,
- })?,
- })
+ let mut output = [0; LEN];
+
+ for (value, output_val) in size.into_iter().zip(&mut output) {
+ *output_val = value.try_into().map_err(|_| Error::ValueInSizeIsTooLarge {
+ value: value,
+ max_value: crate::sys::types::GLsizei::MAX as u32,
+ })?;
+ }
+
+ Ok(output)
}
-fn try_convert_offset(offset: Vec2<u32>)
- -> Result<Vec2<crate::sys::types::GLint>, Error>
+fn try_convert_offset<const LEN: usize>(
+ offset: [u32; LEN],
+) -> Result<[crate::sys::types::GLint; LEN], Error>
{
- Ok(Vec2::<crate::sys::types::GLint> {
- x: offset
- .x
- .try_into()
- .map_err(|_| Error::OffsetXValueTooLarge {
- value: offset.x,
- max_value: crate::sys::types::GLint::MAX as u32,
- })?,
- y: offset
- .y
+ let mut output = [0; LEN];
+
+ for (value, output_val) in offset.into_iter().zip(&mut output) {
+ *output_val = value
.try_into()
- .map_err(|_| Error::OffsetYValueTooLarge {
- value: offset.y,
+ .map_err(|_| Error::ValueInOffsetIsTooLarge {
+ value: value,
max_value: crate::sys::types::GLint::MAX as u32,
- })?,
- })
+ })?;
+ }
+
+ Ok(output)
}
fn check_image_buffer_len_correct_for_size(
image: &[u8],
- size: Dimens<u32>,
+ size: [u32; 3],
pixel_data_format: PixelDataFormat,
) -> Result<(), Error>
{
let pixel_width = pixel_data_format.pixel_width();
- let expected_buffer_len = size.width as usize * size.height as usize * pixel_width;
+ let [width, height, depth] = size;
+
+ let expected_buffer_len =
+ width as usize * height as usize * depth as usize * pixel_width;
if expected_buffer_len != image.len() {
return Err(Error::IncorrectImageBufferLengthForSize {