summaryrefslogtreecommitdiff
path: root/opengl-bindings/src/texture.rs
diff options
context:
space:
mode:
Diffstat (limited to 'opengl-bindings/src/texture.rs')
-rw-r--r--opengl-bindings/src/texture.rs236
1 files changed, 236 insertions, 0 deletions
diff --git a/opengl-bindings/src/texture.rs b/opengl-bindings/src/texture.rs
new file mode 100644
index 0000000..1859beb
--- /dev/null
+++ b/opengl-bindings/src/texture.rs
@@ -0,0 +1,236 @@
+use crate::data_types::Dimens;
+use crate::CurrentContextWithFns;
+
+#[derive(Debug)]
+pub struct Texture
+{
+ texture: crate::sys::types::GLuint,
+}
+
+impl Texture
+{
+ #[must_use]
+ pub fn new(current_context: &CurrentContextWithFns<'_>) -> Self
+ {
+ let mut texture = crate::sys::types::GLuint::default();
+
+ unsafe {
+ current_context.fns().CreateTextures(
+ crate::sys::TEXTURE_2D,
+ 1,
+ &raw mut texture,
+ );
+ };
+
+ Self { texture }
+ }
+
+ pub fn bind_to_texture_unit(
+ &self,
+ current_context: &CurrentContextWithFns<'_>,
+ texture_unit: u32,
+ )
+ {
+ unsafe {
+ current_context
+ .fns()
+ .BindTextureUnit(texture_unit, self.texture);
+ }
+ }
+
+ /// Allocates the texture storage, stores pixel data & generates a mipmap.
+ ///
+ /// # Errors
+ /// Returns `Err` if any value in `size` does not fit into a `i32`.
+ pub fn generate(
+ &self,
+ current_context: &CurrentContextWithFns<'_>,
+ size: &Dimens<u32>,
+ data: &[u8],
+ pixel_data_format: PixelDataFormat,
+ ) -> Result<(), GenerateError>
+ {
+ let size = Dimens::<crate::sys::types::GLsizei> {
+ width: size.width.try_into().map_err(|_| {
+ GenerateError::SizeWidthValueTooLarge {
+ value: size.width,
+ max_value: crate::sys::types::GLsizei::MAX as u32,
+ }
+ })?,
+ height: size.height.try_into().map_err(|_| {
+ GenerateError::SizeHeightValueTooLarge {
+ value: size.height,
+ max_value: crate::sys::types::GLsizei::MAX as u32,
+ }
+ })?,
+ };
+
+ self.alloc_image(current_context, pixel_data_format, &size, data);
+
+ unsafe {
+ current_context.fns().GenerateTextureMipmap(self.texture);
+ }
+
+ Ok(())
+ }
+
+ pub fn set_wrap(
+ &self,
+ current_context: &CurrentContextWithFns<'_>,
+ wrapping: Wrapping,
+ )
+ {
+ unsafe {
+ current_context.fns().TextureParameteri(
+ self.texture,
+ crate::sys::TEXTURE_WRAP_S,
+ wrapping as i32,
+ );
+
+ current_context.fns().TextureParameteri(
+ self.texture,
+ crate::sys::TEXTURE_WRAP_T,
+ wrapping as i32,
+ );
+ }
+ }
+
+ pub fn set_magnifying_filter(
+ &self,
+ current_context: &CurrentContextWithFns<'_>,
+ filtering: Filtering,
+ )
+ {
+ unsafe {
+ current_context.fns().TextureParameteri(
+ self.texture,
+ crate::sys::TEXTURE_MAG_FILTER,
+ filtering as i32,
+ );
+ }
+ }
+
+ pub fn set_minifying_filter(
+ &self,
+ current_context: &CurrentContextWithFns<'_>,
+ filtering: Filtering,
+ )
+ {
+ unsafe {
+ current_context.fns().TextureParameteri(
+ self.texture,
+ crate::sys::TEXTURE_MIN_FILTER,
+ filtering as i32,
+ );
+ }
+ }
+
+ pub fn delete(self, current_context: &CurrentContextWithFns<'_>)
+ {
+ unsafe {
+ current_context
+ .fns()
+ .DeleteTextures(1, &raw const self.texture);
+ }
+ }
+
+ fn alloc_image(
+ &self,
+ current_context: &CurrentContextWithFns<'_>,
+ pixel_data_format: PixelDataFormat,
+ size: &Dimens<crate::sys::types::GLsizei>,
+ data: &[u8],
+ )
+ {
+ unsafe {
+ current_context.fns().TextureStorage2D(
+ self.texture,
+ 1,
+ pixel_data_format.to_sized_internal_format(),
+ size.width,
+ size.height,
+ );
+
+ current_context.fns().TextureSubImage2D(
+ self.texture,
+ 0,
+ 0,
+ 0,
+ size.width,
+ size.height,
+ pixel_data_format.to_format(),
+ crate::sys::UNSIGNED_BYTE,
+ data.as_ptr().cast(),
+ );
+ }
+ }
+}
+
+const fn try_cast_u32_to_i32(val: u32) -> i32
+{
+ assert!(val <= i32::MAX as u32);
+
+ val.cast_signed()
+}
+
+/// Texture wrapping.
+#[derive(Debug, Clone, Copy)]
+#[repr(i32)]
+pub enum Wrapping
+{
+ Repeat = const { try_cast_u32_to_i32(crate::sys::REPEAT) },
+ MirroredRepeat = const { try_cast_u32_to_i32(crate::sys::MIRRORED_REPEAT) },
+ ClampToEdge = const { try_cast_u32_to_i32(crate::sys::CLAMP_TO_EDGE) },
+ ClampToBorder = const { try_cast_u32_to_i32(crate::sys::CLAMP_TO_BORDER) },
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(i32)]
+pub enum Filtering
+{
+ Nearest = const { try_cast_u32_to_i32(crate::sys::NEAREST) },
+ Linear = const { try_cast_u32_to_i32(crate::sys::LINEAR) },
+}
+
+/// Texture pixel data format.
+#[derive(Debug, Clone, Copy)]
+pub enum PixelDataFormat
+{
+ Rgb8,
+ Rgba8,
+}
+
+impl PixelDataFormat
+{
+ fn to_sized_internal_format(self) -> crate::sys::types::GLenum
+ {
+ match self {
+ Self::Rgb8 => crate::sys::RGB8,
+ Self::Rgba8 => crate::sys::RGBA8,
+ }
+ }
+
+ fn to_format(self) -> crate::sys::types::GLenum
+ {
+ match self {
+ Self::Rgb8 => crate::sys::RGB,
+ Self::Rgba8 => crate::sys::RGBA,
+ }
+ }
+}
+
+/// Error generating texture.
+#[derive(Debug, thiserror::Error)]
+pub enum GenerateError
+{
+ #[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
+ {
+ value: u32, max_value: u32
+ },
+}