From 935f35455ac2e3547cdd21cd4596538958a7217e Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 26 Nov 2023 13:36:16 +0100 Subject: feat(engine): make textures clonable --- engine/src/opengl/texture.rs | 96 +++++++++++++++++++++++++++++++++++++------- engine/src/texture.rs | 27 ++++++++++++- 2 files changed, 107 insertions(+), 16 deletions(-) (limited to 'engine') diff --git a/engine/src/opengl/texture.rs b/engine/src/opengl/texture.rs index 68ac050..4186479 100644 --- a/engine/src/opengl/texture.rs +++ b/engine/src/opengl/texture.rs @@ -1,3 +1,5 @@ +use std::ptr::null; + use crate::opengl::currently_bound::CurrentlyBound; use crate::vector::Vec2; @@ -33,26 +35,15 @@ impl Texture } pub fn generate( - _: &CurrentlyBound, + curr_bound: &CurrentlyBound, dimens: &Vec2, data: &[u8], pixel_data_format: PixelDataFormat, ) { - #[allow(clippy::cast_possible_wrap)] - unsafe { - gl::TexImage2D( - gl::TEXTURE_2D, - 0, - pixel_data_format.to_gl() as i32, - dimens.x as i32, - dimens.y as i32, - 0, - pixel_data_format.to_gl(), - gl::UNSIGNED_BYTE, - data.as_ptr().cast(), - ); + Self::alloc_image(curr_bound, pixel_data_format, dimens, Some(data)); + unsafe { gl::GenerateMipmap(gl::TEXTURE_2D); } } @@ -95,6 +86,83 @@ impl Texture ); } } + + /// Creates a copy of the texture & the texture images. + /// + /// `src_offset` and `dst_offset` are source & destination offsets from the + /// bottom-left of the images. + /// + /// New mipmaps are generated using the largest mipmap. + pub fn copy( + &self, + dimensions: &Vec2, + pixel_data_format: PixelDataFormat, + src_offset: &Vec2, + dst_offset: &Vec2, + ) -> Self + { + let new_texture = Self::new(); + + new_texture.bind(|curr_bound| { + Self::alloc_image(&curr_bound, pixel_data_format, dimensions, None); + + // Mipmap have to be generated since CopyImageSubData demands that the + // destination texture is completed + unsafe { + gl::GenerateMipmap(gl::TEXTURE_2D); + } + }); + + #[allow(clippy::cast_possible_wrap)] + unsafe { + gl::CopyImageSubData( + self.texture, + gl::TEXTURE_2D, + 0, + src_offset.x as i32, + src_offset.y as i32, + 0, + new_texture.texture, + gl::TEXTURE_2D, + 0, + dst_offset.x as i32, + dst_offset.y as i32, + 0, + dimensions.x as i32, + dimensions.y as i32, + 1, + ); + } + + unsafe { + gl::GenerateMipmap(gl::TEXTURE_2D); + } + + new_texture + } + + fn alloc_image( + _: &CurrentlyBound, + pixel_data_format: PixelDataFormat, + dimens: &Vec2, + data: Option<&[u8]>, + ) + { + unsafe { + #[allow(clippy::cast_possible_wrap)] + gl::TexImage2D( + gl::TEXTURE_2D, + 0, + pixel_data_format.to_gl() as i32, + dimens.x as i32, + dimens.y as i32, + 0, + pixel_data_format.to_gl(), + gl::UNSIGNED_BYTE, + data.map_or_else(null, |data| data.as_ptr().cast()), + ); + } + } } impl Drop for Texture diff --git a/engine/src/texture.rs b/engine/src/texture.rs index bde3cd2..f32bc0a 100644 --- a/engine/src/texture.rs +++ b/engine/src/texture.rs @@ -17,6 +17,8 @@ pub use reexports::*; pub struct Texture { inner: InnerTexture, + pixel_data_format: PixelDataFormat, + dimensions: Vec2, } impl Texture @@ -45,16 +47,18 @@ impl Texture let inner = InnerTexture::new(); + let dimensions = Vec2 { x: image.width(), y: image.height() }; + inner.bind(|texture_curr_bound| { InnerTexture::generate( &texture_curr_bound, - &Vec2 { x: image.width(), y: image.height() }, + &dimensions, image.as_bytes(), pixel_data_format, ); }); - let me = Self { inner }; + let me = Self { inner, pixel_data_format, dimensions }; me.set_wrap(Wrapping::Repeat); me.set_magnifying_filter(Filtering::Linear); @@ -90,6 +94,25 @@ impl Texture } } +impl Clone for Texture +{ + fn clone(&self) -> Self + { + let inner = self.inner.copy( + &self.dimensions, + self.pixel_data_format, + &Vec2::ZERO, + &Vec2::ZERO, + ); + + Self { + inner, + pixel_data_format: self.pixel_data_format, + dimensions: self.dimensions.clone(), + } + } +} + /// Texture error. #[derive(Debug, thiserror::Error)] pub enum Error -- cgit v1.2.3-18-g5258