use std::ptr::NonNull;
use kind::PixelFormatKind;
use palette::Palette;
use static_assertions::assert_not_impl_all;
use crate::color::{Rgb, Rgba};
use crate::{bind, EnumInt, Result, Sdl, SdlError};
pub mod kind;
pub mod layout;
pub mod order;
pub mod palette;
pub mod ty;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[must_use]
pub struct Pixel {
pixel: u32,
}
impl Pixel {
#[must_use]
pub fn as_u32(self) -> u32 {
self.pixel
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PixelMask(pub u32);
#[derive(Debug)]
#[non_exhaustive]
pub enum PixelFormatProperty {
Palette(Palette),
TrueColor {
red: PixelMask,
green: PixelMask,
blue: PixelMask,
alpha: PixelMask,
},
}
pub struct PixelFormat {
format: NonNull<bind::SDL_PixelFormat>,
}
impl std::fmt::Debug for PixelFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PixelFormat")
.field("kind", &self.kind())
.finish()
}
}
assert_not_impl_all!(PixelFormat: Send, Sync);
impl PixelFormat {
pub fn new(kind: PixelFormatKind) -> Result<Self> {
NonNull::new(unsafe { bind::SDL_AllocFormat(kind.as_raw()) }).map_or_else(
|| {
let msg = Sdl::error();
Err(if msg == "Out of memory" {
SdlError::OutOfMemory
} else {
SdlError::Others { msg }
})
},
|format| Ok(Self { format }),
)
}
#[must_use]
pub fn kind(&self) -> PixelFormatKind {
PixelFormatKind::from_raw(unsafe { self.format.as_ref() }.format as EnumInt)
}
#[must_use]
pub fn bits_per_pixel(&self) -> u8 {
unsafe { self.format.as_ref() }.BitsPerPixel
}
#[must_use]
pub fn bytes_per_pixel(&self) -> u8 {
unsafe { self.format.as_ref() }.BytesPerPixel
}
#[must_use]
pub fn property(&self) -> PixelFormatProperty {
let raw = unsafe { self.format.as_ref() };
NonNull::new(raw.palette).map_or_else(
|| PixelFormatProperty::TrueColor {
red: PixelMask(raw.Rmask),
green: PixelMask(raw.Gmask),
blue: PixelMask(raw.Bmask),
alpha: PixelMask(raw.Amask),
},
|palette| PixelFormatProperty::Palette(Palette { palette }),
)
}
pub fn pixel_by_rgb(&self, Rgb { r, g, b }: Rgb) -> Pixel {
let pixel = unsafe { bind::SDL_MapRGB(self.format.as_ptr(), r, g, b) };
Pixel { pixel }
}
pub fn pixel_by_rgba(&self, Rgba { r, g, b, a }: Rgba) -> Pixel {
let pixel = unsafe { bind::SDL_MapRGBA(self.format.as_ptr(), r, g, b, a) };
Pixel { pixel }
}
pub fn rgb_from_pixel(&self, Pixel { pixel }: Pixel) -> Rgb {
let mut rgb = Rgb { r: 0, g: 0, b: 0 };
unsafe {
bind::SDL_GetRGB(
pixel,
self.format.as_ptr(),
&mut rgb.r,
&mut rgb.g,
&mut rgb.b,
);
}
rgb
}
pub fn rgba_from_pixel(&self, Pixel { pixel }: Pixel) -> Rgba {
let mut rgba = Rgba {
r: 0,
g: 0,
b: 0,
a: 0,
};
unsafe {
bind::SDL_GetRGBA(
pixel,
self.format.as_ptr(),
&mut rgba.r,
&mut rgba.g,
&mut rgba.b,
&mut rgba.a,
);
}
rgba
}
pub fn set_palette(&self, palette: &Palette) {
let ret =
unsafe { bind::SDL_SetPixelFormatPalette(self.format.as_ptr(), palette.as_ptr()) };
if ret != 0 {
Sdl::error_then_panic("Setting pixel format palette");
}
}
}
impl Drop for PixelFormat {
fn drop(&mut self) {
unsafe { bind::SDL_FreeFormat(self.format.as_ptr()) }
}
}