1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//! Owned surface, created from raw pixel data.

use std::{os::raw::c_int, ptr::NonNull};

use super::Surface;
use crate::{
    bind,
    color::pixel::{kind::BppMask, PixelFormat},
    geo::Size,
    Result, Sdl, SdlError,
};

/// An owned [`Surface`] with raw pixel data.
#[derive(Debug)]
pub struct Owned {
    raw: NonNull<bind::SDL_Surface>,
}

impl Owned {
    /// Creates a new owned surface with its size and pixel format.
    ///
    /// # Errors
    ///
    /// Returns `Err` if failed to allocate the surface.
    pub fn new(size: Size, kind: &PixelFormat) -> Result<Self> {
        let BppMask {
            r_mask,
            g_mask,
            b_mask,
            a_mask,
            ..
        } = kind.kind().to_bpp_mask().unwrap_or_default();
        let ptr = unsafe {
            bind::SDL_CreateRGBSurface(
                0,
                size.width as c_int,
                size.height as c_int,
                kind.bits_per_pixel() as c_int,
                r_mask,
                g_mask,
                b_mask,
                a_mask,
            )
        };
        NonNull::new(ptr).map_or_else(
            || Err(SdlError::Others { msg: Sdl::error() }),
            |raw| Ok(Self { raw }),
        )
    }
}

impl Drop for Owned {
    fn drop(&mut self) {
        unsafe { bind::SDL_FreeSurface(self.raw.as_ptr()) }
    }
}

impl Surface for Owned {
    fn as_ptr(&self) -> std::ptr::NonNull<super::RawSurface> {
        self.raw
    }
}