rust/lib-hedgewars-engine/src/render/gl.rs
changeset 15760 ff1432e873bd
parent 15289 fd20e0a134af
child 15761 e7eb0cd5b0e4
equal deleted inserted replaced
15759:c929e25a7da2 15760:ff1432e873bd
    30     }
    30     }
    31 }
    31 }
    32 
    32 
    33 #[derive(Debug)]
    33 #[derive(Debug)]
    34 pub struct Texture2D {
    34 pub struct Texture2D {
    35     pub handle: Option<NonZeroU32>,
    35     handle: Option<NonZeroU32>,
       
    36     size: Size,
    36 }
    37 }
    37 
    38 
    38 impl Drop for Texture2D {
    39 impl Drop for Texture2D {
    39     fn drop(&mut self) {
    40     fn drop(&mut self) {
    40         if let Some(handle) = self.handle {
    41         if let Some(handle) = self.handle {
    51         gl::GenTextures(1, &mut handle);
    52         gl::GenTextures(1, &mut handle);
    52     }
    53     }
    53     NonZeroU32::new(handle)
    54     NonZeroU32::new(handle)
    54 }
    55 }
    55 
    56 
    56 fn tex_params(filter: u32) {
    57 fn tex_params(filter: TextureFilter) {
    57     unsafe {
    58     unsafe {
    58         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
    59         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
    59         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
    60         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
    60         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, filter as i32);
    61         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, filter as i32);
    61         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, filter as i32);
    62         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, filter as i32);
    62     }
    63     }
    63 }
    64 }
    64 
    65 
       
    66 #[derive(Clone, Copy, Debug)]
       
    67 pub enum TextureFormat {
       
    68     Rgba = gl::RGBA as isize,
       
    69 }
       
    70 
       
    71 #[derive(Clone, Copy, Debug)]
       
    72 pub enum TextureInternalFormat {
       
    73     Rgba8 = gl::RGBA as isize,
       
    74 }
       
    75 
       
    76 #[derive(Clone, Copy, Debug)]
       
    77 pub enum TextureDataType {
       
    78     UnsignedByte = gl::UNSIGNED_BYTE as isize,
       
    79 }
       
    80 
       
    81 #[derive(Clone, Copy, Debug)]
       
    82 pub enum TextureFilter {
       
    83     Nearest = gl::NEAREST as isize,
       
    84     Linear = gl::LINEAR as isize,
       
    85 }
       
    86 
       
    87 #[inline]
       
    88 fn get_u32(value: Option<NonZeroU32>) -> u32 {
       
    89     value.map_or(0, |v| v.get())
       
    90 }
       
    91 
       
    92 fn is_out_of_bounds(data: &[u8], data_stride: Option<NonZeroU32>, texture_size: Size) -> bool {
       
    93     let data_stride = get_u32(data_stride);
       
    94     data_stride == 0 && texture_size.area() * 4 > data.len()
       
    95         || data_stride != 0
       
    96             && texture_size.width > data_stride as usize
       
    97             && (texture_size.height * data_stride as usize) * 4 > data.len()
       
    98 }
       
    99 
    65 impl Texture2D {
   100 impl Texture2D {
    66     pub fn new(size: Size, internal_format: u32, filter: u32) -> Self {
   101     pub fn new(size: Size, internal_format: TextureInternalFormat, filter: TextureFilter) -> Self {
    67         if let Some(handle) = new_texture() {
   102         if let Some(handle) = new_texture() {
    68             unsafe {
   103             unsafe {
    69                 gl::BindTexture(gl::TEXTURE_2D, handle.get());
   104                 gl::BindTexture(gl::TEXTURE_2D, handle.get());
    70                 gl::TexImage2D(
   105                 gl::TexImage2D(
    71                     gl::TEXTURE_2D,
   106                     gl::TEXTURE_2D,
    72                     0,
   107                     0,
    73                     internal_format as i32,
   108                     internal_format as i32,
    74                     size.width as i32,
   109                     size.width as i32,
    75                     size.height as i32,
   110                     size.height as i32,
    76                     0,
   111                     0,
    77                     gl::RGBA,
   112                     TextureFormat::Rgba as u32,
    78                     gl::UNSIGNED_BYTE,
   113                     TextureDataType::UnsignedByte as u32,
    79                     std::ptr::null(),
   114                     std::ptr::null(),
    80                 )
   115                 )
    81             }
   116             }
    82 
   117 
    83             tex_params(filter);
   118             tex_params(filter);
    84             Self {
   119             Self {
    85                 handle: Some(handle),
   120                 handle: Some(handle),
       
   121                 size,
    86             }
   122             }
    87         } else {
   123         } else {
    88             Self { handle: None }
   124             Self { handle: None, size }
    89         }
   125         }
    90     }
   126     }
    91 
   127 
    92     pub fn with_data(
   128     pub fn with_data(
    93         data: &[u8],
   129         data: &[u8],
    94         data_stride: u32,
   130         data_stride: Option<NonZeroU32>,
    95         size: Size,
   131         size: Size,
    96         internal_format: u32,
   132         internal_format: TextureInternalFormat,
    97         format: u32,
   133         format: TextureFormat,
    98         ty: u32,
   134         ty: TextureDataType,
    99         filter: u32,
   135         filter: TextureFilter,
   100     ) -> Self {
   136     ) -> Self {
       
   137         if is_out_of_bounds(data, data_stride, size) {
       
   138             return Self { handle: None, size };
       
   139         }
       
   140 
   101         if let Some(handle) = new_texture() {
   141         if let Some(handle) = new_texture() {
   102             unsafe {
   142             unsafe {
   103                 gl::BindTexture(gl::TEXTURE_2D, handle.get());
   143                 gl::BindTexture(gl::TEXTURE_2D, handle.get());
   104                 gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32);
   144                 gl::PixelStorei(gl::UNPACK_ROW_LENGTH, get_u32(data_stride) as i32);
   105                 gl::TexImage2D(
   145                 gl::TexImage2D(
   106                     gl::TEXTURE_2D,
   146                     gl::TEXTURE_2D,
   107                     0,
   147                     0,
   108                     internal_format as i32,
   148                     internal_format as i32,
   109                     size.width as i32,
   149                     size.width as i32,
   110                     size.height as i32,
   150                     size.height as i32,
   111                     0,
   151                     0,
   112                     format as u32,
   152                     format as u32,
   113                     ty,
   153                     ty as u32,
   114                     data.as_ptr() as *const _,
   154                     data.as_ptr() as *const _,
   115                 )
   155                 )
   116             }
   156             }
   117 
   157 
   118             tex_params(filter);
   158             tex_params(filter);
   119             Self {
   159             Self {
   120                 handle: Some(handle),
   160                 handle: Some(handle),
       
   161                 size,
   121             }
   162             }
   122         } else {
   163         } else {
   123             Self { handle: None }
   164             Self { handle: None, size }
   124         }
   165         }
   125     }
   166     }
   126 
   167 
   127     pub fn update(&self, region: Rect, data: &[u8], data_stride: u32, format: u32, ty: u32) {
   168     pub fn update(
       
   169         &self,
       
   170         region: Rect,
       
   171         data: &[u8],
       
   172         data_stride: Option<NonZeroU32>,
       
   173         format: TextureFormat,
       
   174         ty: TextureDataType,
       
   175     ) {
       
   176         if is_out_of_bounds(data, data_stride, self.size) {
       
   177             return;
       
   178         }
       
   179 
   128         if let Some(handle) = self.handle {
   180         if let Some(handle) = self.handle {
   129             unsafe {
   181             unsafe {
   130                 gl::BindTexture(gl::TEXTURE_2D, handle.get());
   182                 gl::BindTexture(gl::TEXTURE_2D, handle.get());
   131                 gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32);
   183                 gl::PixelStorei(gl::UNPACK_ROW_LENGTH, get_u32(data_stride) as i32);
   132                 gl::TexSubImage2D(
   184                 gl::TexSubImage2D(
   133                     gl::TEXTURE_2D,
   185                     gl::TEXTURE_2D,
   134                     0,             // texture level
   186                     0,
   135                     region.left(), // texture region
   187                     region.left(),
   136                     region.top(),
   188                     region.top(),
   137                     region.width() as i32,
   189                     region.width() as i32,
   138                     region.height() as i32,
   190                     region.height() as i32,
   139                     format,                    // data format
   191                     format as u32,
   140                     ty,                        // data type
   192                     ty as u32,
   141                     data.as_ptr() as *const _, // data ptr
   193                     data.as_ptr() as *const _,
   142                 );
   194                 );
   143             }
   195             }
   144         }
   196         }
   145     }
   197     }
   146 
   198 
   147     pub fn retrieve(&self, data: &mut [u8]) {
   199     pub fn retrieve(&self, data: &mut [u8]) {
       
   200         if self.size.area() * 4 > data.len() {
       
   201             return;
       
   202         }
       
   203 
   148         if let Some(handle) = self.handle {
   204         if let Some(handle) = self.handle {
   149             unsafe {
   205             unsafe {
   150                 gl::BindTexture(gl::TEXTURE_2D, handle.get());
   206                 gl::BindTexture(gl::TEXTURE_2D, handle.get());
   151                 gl::GetTexImage(
   207                 gl::GetTexImage(
   152                     gl::TEXTURE_2D,
   208                     gl::TEXTURE_2D,
   153                     0,                           // texture level
   209                     0,
   154                     gl::RGBA,                    // data format
   210                     TextureFormat::Rgba as u32,
   155                     gl::UNSIGNED_BYTE,           // data type
   211                     TextureDataType::UnsignedByte as u32,
   156                     data.as_mut_ptr() as *mut _, // data ptr
   212                     data.as_mut_ptr() as *mut _,
   157                 );
   213                 );
   158             }
   214             }
   159         }
   215         }
   160     }
   216     }
   161 }
   217 }