use crate::get_error;
use crate::sys;
use crate::Error;
use std::convert::{TryFrom, TryInto};
use std::ffi::c_int;
use std::fmt::Debug;
use std::ptr::null;
use sys::pixels;
use sys::pixels::SDL_PixelFormat;
pub struct Palette {
raw: *mut pixels::SDL_Palette,
}
impl Palette {
#[inline]
#[doc(alias = "SDL_CreatePalette")]
pub fn new(mut capacity: usize) -> Result<Self, Error> {
use crate::common::*;
let ncolors = {
let u32_max = u32::MAX as usize;
if capacity > u32_max {
capacity = u32_max;
}
match validate_int(capacity as u32, "capacity") {
Ok(len) => len,
Err(e) => {
return Err(match e {
IntegerOrSdlError::SdlError(e) => e,
o => Error(o.to_string()),
})
}
}
};
let raw = unsafe { pixels::SDL_CreatePalette(ncolors) };
if raw.is_null() {
Err(get_error())
} else {
Ok(Palette { raw })
}
}
#[doc(alias = "SDL_SetPaletteColors")]
pub fn with_colors(colors: &[Color]) -> Result<Self, Error> {
let pal = Self::new(colors.len())?;
let ncolors = colors.len() as ::libc::c_int;
let result = unsafe {
let mut raw_colors: Vec<pixels::SDL_Color> =
colors.iter().map(|color| color.raw()).collect();
let pal_ptr = (&mut raw_colors[0]) as *mut pixels::SDL_Color;
pixels::SDL_SetPaletteColors(pal.raw, pal_ptr, 0, ncolors)
};
if !result {
Err(get_error())
} else {
Ok(pal)
}
}
pub fn len(&self) -> usize {
unsafe { (*self.raw).ncolors as usize }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl Drop for Palette {
#[doc(alias = "SDL_DestroyPalette")]
fn drop(&mut self) {
unsafe {
pixels::SDL_DestroyPalette(self.raw);
}
}
}
impl_raw_accessors!((Palette, *mut pixels::SDL_Palette));
#[test]
fn create_palette() {
let colors: Vec<_> = (0..0xff).map(|u| Color::RGB(u, 0, 0xff - u)).collect();
let palette = Palette::with_colors(&colors).unwrap();
assert!(palette.len() == 255);
}
#[test]
fn pixel_format_is_alpha() {
assert!(PixelFormat::RGBA8888.is_alpha());
assert!(PixelFormat::ARGB2101010.is_alpha());
assert!(!PixelFormat::RGB24.is_alpha());
}
#[test]
fn pixel_format_details_basic() {
let fmt: PixelFormat = PixelFormat::RGB24;
let det = fmt.details();
assert_eq!(det.format, fmt);
assert_eq!(det.bits_per_pixel, 24);
assert_eq!(det.bytes_per_pixel, 3);
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
#[repr(C)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Color {
#[inline]
#[allow(non_snake_case)]
pub const fn RGB(r: u8, g: u8, b: u8) -> Color {
Color { r, g, b, a: 0xff }
}
#[inline]
#[allow(non_snake_case)]
pub const fn RGBA(r: u8, g: u8, b: u8, a: u8) -> Color {
Color { r, g, b, a }
}
#[doc(alias = "SDL_MapRGBA")]
pub fn to_u32(self, format: &PixelFormat) -> u32 {
unsafe {
pixels::SDL_MapRGBA(
format.pixel_format_details(),
null(),
self.r,
self.g,
self.b,
self.a,
)
}
}
#[doc(alias = "SDL_GetRGBA")]
pub fn from_u32(format: &PixelFormat, pixel: u32) -> Color {
let (mut r, mut g, mut b, mut a) = (0, 0, 0, 0);
unsafe {
pixels::SDL_GetRGBA(
pixel,
format.pixel_format_details(),
null(),
&mut r,
&mut g,
&mut b,
&mut a,
)
};
Color::RGBA(r, g, b, a)
}
pub fn invert(self) -> Color {
Color::RGBA(255 - self.r, 255 - self.g, 255 - self.b, 255 - self.a)
}
#[inline]
pub const fn rgb(self) -> (u8, u8, u8) {
(self.r, self.g, self.b)
}
#[inline]
pub const fn rgba(self) -> (u8, u8, u8, u8) {
(self.r, self.g, self.b, self.a)
}
#[inline]
const fn raw(self) -> pixels::SDL_Color {
pixels::SDL_Color {
r: self.r,
g: self.g,
b: self.b,
a: self.a,
}
}
pub const WHITE: Color = Color::RGBA(255, 255, 255, 255);
pub const BLACK: Color = Color::RGBA(0, 0, 0, 255);
pub const GRAY: Color = Color::RGBA(128, 128, 128, 255);
pub const GREY: Color = Color::GRAY;
pub const RED: Color = Color::RGBA(255, 0, 0, 255);
pub const GREEN: Color = Color::RGBA(0, 255, 0, 255);
pub const BLUE: Color = Color::RGBA(0, 0, 255, 255);
pub const MAGENTA: Color = Color::RGBA(255, 0, 255, 255);
pub const YELLOW: Color = Color::RGBA(255, 255, 0, 255);
pub const CYAN: Color = Color::RGBA(0, 255, 255, 255);
}
impl From<Color> for pixels::SDL_Color {
fn from(val: Color) -> Self {
val.raw()
}
}
impl From<pixels::SDL_Color> for Color {
fn from(raw: pixels::SDL_Color) -> Color {
Color::RGBA(raw.r, raw.g, raw.b, raw.a)
}
}
impl From<(u8, u8, u8)> for Color {
fn from((r, g, b): (u8, u8, u8)) -> Color {
Color::RGB(r, g, b)
}
}
impl From<(u8, u8, u8, u8)> for Color {
fn from((r, g, b, a): (u8, u8, u8, u8)) -> Color {
Color::RGBA(r, g, b, a)
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(C)]
pub struct FColor {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
impl FColor {
#[inline]
#[allow(non_snake_case)]
pub const fn RGB(r: f32, g: f32, b: f32) -> FColor {
FColor { r, g, b, a: 1. }
}
#[inline]
#[allow(non_snake_case)]
pub const fn RGBA(r: f32, g: f32, b: f32, a: f32) -> FColor {
FColor { r, g, b, a }
}
pub fn invert(self) -> FColor {
FColor::RGBA(1. - self.r, 1. - self.g, 1. - self.b, 1. - self.a)
}
#[inline]
pub const fn rgb(self) -> (f32, f32, f32) {
(self.r, self.g, self.b)
}
#[inline]
pub const fn rgba(self) -> (f32, f32, f32, f32) {
(self.r, self.g, self.b, self.a)
}
#[inline]
const fn raw(self) -> sys::pixels::SDL_FColor {
sys::pixels::SDL_FColor {
r: self.r,
g: self.g,
b: self.b,
a: self.a,
}
}
pub const WHITE: FColor = FColor::RGBA(1., 1., 1., 1.);
pub const BLACK: FColor = FColor::RGBA(0., 0., 0., 1.);
pub const GRAY: FColor = FColor::RGBA(0.5, 0.5, 0.5, 1.);
pub const GREY: FColor = FColor::GRAY;
pub const RED: FColor = FColor::RGBA(1., 0., 0., 1.);
pub const GREEN: FColor = FColor::RGBA(0., 1., 0., 1.);
pub const BLUE: FColor = FColor::RGBA(0., 0., 1., 1.);
pub const MAGENTA: FColor = FColor::RGBA(1., 0., 1., 1.);
pub const YELLOW: FColor = FColor::RGBA(1., 1., 0., 1.);
pub const CYAN: FColor = FColor::RGBA(0., 1., 1., 1.);
}
impl From<FColor> for sys::pixels::SDL_FColor {
fn from(val: FColor) -> Self {
val.raw()
}
}
impl From<sys::pixels::SDL_FColor> for FColor {
fn from(raw: sys::pixels::SDL_FColor) -> FColor {
FColor::RGBA(raw.r, raw.g, raw.b, raw.a)
}
}
impl From<(f32, f32, f32)> for FColor {
fn from((r, g, b): (f32, f32, f32)) -> FColor {
FColor::RGB(r, g, b)
}
}
impl From<(f32, f32, f32, f32)> for FColor {
fn from((r, g, b, a): (f32, f32, f32, f32)) -> FColor {
FColor::RGBA(r, g, b, a)
}
}
impl From<Color> for FColor {
fn from(val: Color) -> FColor {
FColor {
r: val.r as f32 / 255.,
g: val.g as f32 / 255.,
b: val.b as f32 / 255.,
a: val.a as f32 / 255.,
}
}
}
impl From<FColor> for Color {
fn from(val: FColor) -> Color {
Color {
r: (val.r * 255.).round().clamp(0., 255.) as u8,
g: (val.g * 255.).round().clamp(0., 255.) as u8,
b: (val.b * 255.).round().clamp(0., 255.) as u8,
a: (val.a * 255.).round().clamp(0., 255.) as u8,
}
}
}
pub struct PixelMasks {
pub bpp: u8,
pub rmask: u32,
pub gmask: u32,
pub bmask: u32,
pub amask: u32,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct PixelFormatDetails {
pub format: PixelFormat,
pub bits_per_pixel: u8,
pub bytes_per_pixel: u8,
pub r_mask: u32,
pub g_mask: u32,
pub b_mask: u32,
pub a_mask: u32,
pub r_bits: u8,
pub g_bits: u8,
pub b_bits: u8,
pub a_bits: u8,
pub r_shift: u8,
pub g_shift: u8,
pub b_shift: u8,
pub a_shift: u8,
}
impl PixelFormatDetails {
pub unsafe fn from_ll(details: *const pixels::SDL_PixelFormatDetails) -> Self {
let d = *details;
PixelFormatDetails {
format: PixelFormat::from_ll(d.format),
bits_per_pixel: d.bits_per_pixel,
bytes_per_pixel: d.bytes_per_pixel,
r_mask: d.Rmask,
g_mask: d.Gmask,
b_mask: d.Bmask,
a_mask: d.Amask,
r_bits: d.Rbits,
g_bits: d.Gbits,
b_bits: d.Bbits,
a_bits: d.Abits,
r_shift: d.Rshift,
g_shift: d.Gshift,
b_shift: d.Bshift,
a_shift: d.Ashift,
}
}
}
macro_rules! pixel_formats {
($($id:ident),+) => {$(
pub const $id: Self = PixelFormat {
raw: SDL_PixelFormat::$id,
};
)+};
}
impl PixelFormat {
pixel_formats!(
UNKNOWN,
INDEX1LSB,
INDEX1MSB,
INDEX2LSB,
INDEX2MSB,
INDEX4LSB,
INDEX4MSB,
INDEX8,
RGB332,
XRGB4444,
XBGR4444,
XRGB1555,
XBGR1555,
ARGB4444,
RGBA4444,
ABGR4444,
BGRA4444,
ARGB1555,
RGBA5551,
ABGR1555,
BGRA5551,
RGB565,
BGR565,
RGB24,
BGR24,
XRGB8888,
RGBX8888,
XBGR8888,
BGRX8888,
ARGB8888,
RGBA8888,
ABGR8888,
BGRA8888,
XRGB2101010,
XBGR2101010,
ARGB2101010,
ABGR2101010,
RGB48,
BGR48,
RGBA64,
ARGB64,
BGRA64,
ABGR64,
RGB48_FLOAT,
BGR48_FLOAT,
RGBA64_FLOAT,
ARGB64_FLOAT,
BGRA64_FLOAT,
ABGR64_FLOAT,
RGB96_FLOAT,
BGR96_FLOAT,
RGBA128_FLOAT,
ARGB128_FLOAT,
BGRA128_FLOAT,
ABGR128_FLOAT,
YV12,
IYUV,
YUY2,
UYVY,
YVYU,
NV12,
NV21,
P010,
EXTERNAL_OES,
MJPG,
RGBA32,
ARGB32,
BGRA32,
ABGR32,
RGBX32,
XRGB32,
BGRX32,
XBGR32
);
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct PixelFormat {
raw: pixels::SDL_PixelFormat,
}
impl_raw_accessors!((PixelFormat, pixels::SDL_PixelFormat));
impl_raw_constructor!((PixelFormat, PixelFormat(raw: pixels::SDL_PixelFormat )));
impl Debug for PixelFormat {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "PixelFormat({:?})", self.raw.0)
}
}
impl PixelFormat {
#[doc(alias = "SDL_GetPixelFormatDetails")]
pub unsafe fn pixel_format_details(&self) -> *const pixels::SDL_PixelFormatDetails {
pixels::SDL_GetPixelFormatDetails(self.raw)
}
#[doc(alias = "SDL_GetPixelFormatDetails")]
pub fn details(&self) -> PixelFormatDetails {
unsafe {
let ptr = pixels::SDL_GetPixelFormatDetails(self.raw);
assert!(
!ptr.is_null(),
"SDL_GetPixelFormatDetails returned null for format: {self:?}"
);
let d = *ptr;
PixelFormatDetails {
format: PixelFormat::from_ll(d.format),
bits_per_pixel: d.bits_per_pixel,
bytes_per_pixel: d.bytes_per_pixel,
r_mask: d.Rmask,
g_mask: d.Gmask,
b_mask: d.Bmask,
a_mask: d.Amask,
r_bits: d.Rbits,
g_bits: d.Gbits,
b_bits: d.Bbits,
a_bits: d.Abits,
r_shift: d.Rshift,
g_shift: d.Gshift,
b_shift: d.Bshift,
a_shift: d.Ashift,
}
}
}
#[doc(alias = "SDL_GetPixelFormatForMasks")]
pub fn from_masks(masks: PixelMasks) -> PixelFormat {
unsafe {
PixelFormat::from_ll(pixels::SDL_GetPixelFormatForMasks(
masks.bpp as i32,
masks.rmask,
masks.gmask,
masks.bmask,
masks.amask,
))
}
}
#[doc(alias = "SDL_GetMasksForPixelFormat")]
pub fn into_masks(self) -> Result<PixelMasks, Error> {
let mut bpp = 0;
let mut rmask = 0;
let mut gmask = 0;
let mut bmask = 0;
let mut amask = 0;
let result = unsafe {
pixels::SDL_GetMasksForPixelFormat(
self.raw, &mut bpp, &mut rmask, &mut gmask, &mut bmask, &mut amask,
)
};
if !result {
Err(get_error())
} else {
Ok(PixelMasks {
bpp: bpp as u8,
rmask,
gmask,
bmask,
amask,
})
}
}
pub fn byte_size_from_pitch_and_height(self, pitch: usize, height: usize) -> usize {
match self.raw {
pixels::SDL_PixelFormat::YV12 | pixels::SDL_PixelFormat::IYUV => {
pitch * height + 2 * (pitch / 2 * height / 2)
}
_ => pitch * height,
}
}
pub fn is_fourcc(self) -> bool {
pixels::SDL_ISPIXELFORMAT_FOURCC(self.raw)
}
pub fn bits_per_pixel(self) -> u8 {
pixels::SDL_BITSPERPIXEL(self.raw)
}
pub fn is_indexed(self) -> bool {
pixels::SDL_ISPIXELFORMAT_INDEXED(self.raw)
}
pub fn is_packed(self) -> bool {
pixels::SDL_ISPIXELFORMAT_PACKED(self.raw)
}
pub fn is_array(self) -> bool {
pixels::SDL_ISPIXELFORMAT_ARRAY(self.raw)
}
pub fn is_float(self) -> bool {
pixels::SDL_ISPIXELFORMAT_FLOAT(self.raw)
}
pub fn is_alpha(self) -> bool {
pixels::SDL_ISPIXELFORMAT_ALPHA(self.raw)
}
pub fn is_10bit(self) -> bool {
pixels::SDL_ISPIXELFORMAT_10BIT(self.raw)
}
pub fn bytes_per_pixel(self) -> usize {
pixels::SDL_BYTESPERPIXEL(self.raw) as usize
}
}
impl From<PixelFormat> for pixels::SDL_PixelFormat {
fn from(pf: PixelFormat) -> pixels::SDL_PixelFormat {
pf.raw
}
}
impl From<i64> for PixelFormat {
fn from(format: i64) -> PixelFormat {
let format_c_int: c_int = format
.try_into()
.expect("Pixel format value out of range for c_int");
let pixel_format = pixels::SDL_PixelFormat(format_c_int);
PixelFormat { raw: pixel_format }
}
}
impl TryFrom<pixels::SDL_PixelFormat> for PixelFormat {
type Error = Error;
#[doc(alias = "SDL_GetPixelFormatDetails")]
fn try_from(format: pixels::SDL_PixelFormat) -> Result<Self, Self::Error> {
unsafe {
let pf_ptr = pixels::SDL_GetPixelFormatDetails(format);
if pf_ptr.is_null() {
Err(get_error())
} else {
Ok(PixelFormat::from_ll((*pf_ptr).format))
}
}
}
}