diff -r c929e25a7da2 -r ff1432e873bd rust/lib-hedgewars-engine/src/render/gl.rs --- a/rust/lib-hedgewars-engine/src/render/gl.rs Thu Nov 12 00:24:58 2020 +0300 +++ b/rust/lib-hedgewars-engine/src/render/gl.rs Thu Nov 12 23:42:53 2020 +0300 @@ -32,7 +32,8 @@ #[derive(Debug)] pub struct Texture2D { - pub handle: Option, + handle: Option, + size: Size, } impl Drop for Texture2D { @@ -53,7 +54,7 @@ NonZeroU32::new(handle) } -fn tex_params(filter: u32) { +fn tex_params(filter: TextureFilter) { unsafe { gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32); @@ -62,8 +63,42 @@ } } +#[derive(Clone, Copy, Debug)] +pub enum TextureFormat { + Rgba = gl::RGBA as isize, +} + +#[derive(Clone, Copy, Debug)] +pub enum TextureInternalFormat { + Rgba8 = gl::RGBA as isize, +} + +#[derive(Clone, Copy, Debug)] +pub enum TextureDataType { + UnsignedByte = gl::UNSIGNED_BYTE as isize, +} + +#[derive(Clone, Copy, Debug)] +pub enum TextureFilter { + Nearest = gl::NEAREST as isize, + Linear = gl::LINEAR as isize, +} + +#[inline] +fn get_u32(value: Option) -> u32 { + value.map_or(0, |v| v.get()) +} + +fn is_out_of_bounds(data: &[u8], data_stride: Option, texture_size: Size) -> bool { + let data_stride = get_u32(data_stride); + data_stride == 0 && texture_size.area() * 4 > data.len() + || data_stride != 0 + && texture_size.width > data_stride as usize + && (texture_size.height * data_stride as usize) * 4 > data.len() +} + impl Texture2D { - pub fn new(size: Size, internal_format: u32, filter: u32) -> Self { + pub fn new(size: Size, internal_format: TextureInternalFormat, filter: TextureFilter) -> Self { if let Some(handle) = new_texture() { unsafe { gl::BindTexture(gl::TEXTURE_2D, handle.get()); @@ -74,8 +109,8 @@ size.width as i32, size.height as i32, 0, - gl::RGBA, - gl::UNSIGNED_BYTE, + TextureFormat::Rgba as u32, + TextureDataType::UnsignedByte as u32, std::ptr::null(), ) } @@ -83,25 +118,30 @@ tex_params(filter); Self { handle: Some(handle), + size, } } else { - Self { handle: None } + Self { handle: None, size } } } pub fn with_data( data: &[u8], - data_stride: u32, + data_stride: Option, size: Size, - internal_format: u32, - format: u32, - ty: u32, - filter: u32, + internal_format: TextureInternalFormat, + format: TextureFormat, + ty: TextureDataType, + filter: TextureFilter, ) -> Self { + if is_out_of_bounds(data, data_stride, size) { + return Self { handle: None, size }; + } + if let Some(handle) = new_texture() { unsafe { gl::BindTexture(gl::TEXTURE_2D, handle.get()); - gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32); + gl::PixelStorei(gl::UNPACK_ROW_LENGTH, get_u32(data_stride) as i32); gl::TexImage2D( gl::TEXTURE_2D, 0, @@ -110,7 +150,7 @@ size.height as i32, 0, format as u32, - ty, + ty as u32, data.as_ptr() as *const _, ) } @@ -118,42 +158,58 @@ tex_params(filter); Self { handle: Some(handle), + size, } } else { - Self { handle: None } + Self { handle: None, size } } } - pub fn update(&self, region: Rect, data: &[u8], data_stride: u32, format: u32, ty: u32) { + pub fn update( + &self, + region: Rect, + data: &[u8], + data_stride: Option, + format: TextureFormat, + ty: TextureDataType, + ) { + if is_out_of_bounds(data, data_stride, self.size) { + return; + } + if let Some(handle) = self.handle { unsafe { gl::BindTexture(gl::TEXTURE_2D, handle.get()); - gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32); + gl::PixelStorei(gl::UNPACK_ROW_LENGTH, get_u32(data_stride) as i32); gl::TexSubImage2D( gl::TEXTURE_2D, - 0, // texture level - region.left(), // texture region + 0, + region.left(), region.top(), region.width() as i32, region.height() as i32, - format, // data format - ty, // data type - data.as_ptr() as *const _, // data ptr + format as u32, + ty as u32, + data.as_ptr() as *const _, ); } } } pub fn retrieve(&self, data: &mut [u8]) { + if self.size.area() * 4 > data.len() { + return; + } + if let Some(handle) = self.handle { unsafe { gl::BindTexture(gl::TEXTURE_2D, handle.get()); gl::GetTexImage( gl::TEXTURE_2D, - 0, // texture level - gl::RGBA, // data format - gl::UNSIGNED_BYTE, // data type - data.as_mut_ptr() as *mut _, // data ptr + 0, + TextureFormat::Rgba as u32, + TextureDataType::UnsignedByte as u32, + data.as_mut_ptr() as *mut _, ); } }