1use crate::{
2 error::{get_error, SdlError},
3 init::SdlInit,
4 Sdl,
5};
6use alloc::sync::Arc;
7use core::ptr::NonNull;
8use fermium::prelude::*;
9use pixel_formats::r8g8b8a8_Srgb;
10
11#[repr(C)]
12pub struct Surface {
13 pub(crate) surf: NonNull<SDL_Surface>,
14 pub(crate) parent: Arc<SdlInit>,
15}
16impl Drop for Surface {
17 #[inline]
18 fn drop(&mut self) {
19 unsafe { SDL_FreeSurface(self.surf.as_ptr()) };
20 }
21}
22impl Sdl {
23 #[inline]
24 pub fn create_surface_from(
25 &self, pixels: &[r8g8b8a8_Srgb], width: i32, height: i32,
26 ) -> Result<Surface, SdlError> {
27 if width <= 0
28 || height <= 0
29 || width.checked_mul(height).unwrap_or_default() as usize != pixels.len()
30 {
31 return Err(SdlError::new("illegal input dimensions"));
32 }
33 let depth = 32;
34 let pitch = width * 4;
35 const R_MASK: u32 = unsafe { core::mem::transmute(r8g8b8a8_Srgb { r: 255, g: 0, b: 0, a: 0 }) };
36 const G_MASK: u32 = unsafe { core::mem::transmute(r8g8b8a8_Srgb { g: 255, r: 0, b: 0, a: 0 }) };
37 const B_MASK: u32 = unsafe { core::mem::transmute(r8g8b8a8_Srgb { b: 255, g: 0, r: 0, a: 0 }) };
38 const A_MASK: u32 = unsafe { core::mem::transmute(r8g8b8a8_Srgb { a: 255, g: 0, b: 0, r: 0 }) };
39 let p = unsafe {
40 SDL_CreateRGBSurfaceFrom(
41 pixels.as_ptr() as *mut c_void,
42 width,
43 height,
44 depth,
45 pitch,
46 R_MASK,
47 G_MASK,
48 B_MASK,
49 A_MASK,
50 )
51 };
52 match NonNull::new(p) {
53 Some(surf) => Ok(Surface { surf, parent: self.init.clone() }),
54 None => Err(get_error()),
55 }
56 }
57}