trait Sealed {} #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[repr(u8)] pub enum PixelFormat { A8, Abgr32, Bgr24, Bgr32, Rgb24, Rgb32, Rgba32, } pub(crate) const NUM_PIXEL_FORMATS: usize = 7; pub(crate) const MAX_PIXEL_WIDTH: usize = 4; #[derive(Clone, PartialEq, Debug, Default)] pub struct PackedLocation(Option); impl PackedLocation { const fn empty() -> Self { Self(None) } const fn select_byte(index: u8) -> Self { Self(Some(index)) } pub const fn index(&self) -> Option { self.0 } } #[allow(private_bounds)] pub trait PixelFormatSpec: Sealed + Clone + Copy + PartialEq { const FORMAT_ENUM: PixelFormat; const CHANNELS: usize; const PIXEL_WIDTH: usize; const NAME: &'static str; const RED_PACK: PackedLocation; const GREEN_PACK: PackedLocation; const BLUE_PACK: PackedLocation; const ALPHA_PACK: PackedLocation; } //----------------------------------------------------------------------------- // Pixel formats //----------------------------------------------------------------------------- /// 8-bit alpha map #[derive(Clone, Copy, PartialEq)] pub struct A8; impl Sealed for A8 {} impl PixelFormatSpec for A8 { const FORMAT_ENUM: PixelFormat = PixelFormat::A8; const CHANNELS: usize = 1; const PIXEL_WIDTH: usize = 1; const NAME: &'static str = "A8"; const RED_PACK: PackedLocation = PackedLocation::empty(); const GREEN_PACK: PackedLocation = PackedLocation::empty(); const BLUE_PACK: PackedLocation = PackedLocation::empty(); const ALPHA_PACK: PackedLocation = PackedLocation::select_byte(0); } /// RGBA with 8 bits per channel, stored big-endian /// /// This assumes the following memory layout: /// ```text /// 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ... /// ---+---+---+---+---+---+---+---+--- /// A | B | G | R | A | B | G | R | ... /// ``` #[derive(Clone, Copy, PartialEq)] pub struct Abgr32; impl Sealed for Abgr32 {} impl PixelFormatSpec for Abgr32 { const FORMAT_ENUM: PixelFormat = PixelFormat::Abgr32; const CHANNELS: usize = 4; const PIXEL_WIDTH: usize = 4; const NAME: &'static str = "Abgr32"; const RED_PACK: PackedLocation = PackedLocation::select_byte(3); const GREEN_PACK: PackedLocation = PackedLocation::select_byte(2); const BLUE_PACK: PackedLocation = PackedLocation::select_byte(1); const ALPHA_PACK: PackedLocation = PackedLocation::select_byte(0); } /// 24bpp colour densly packed into 24-bit words /// /// This assumes the following memory layout: /// /// ```text /// 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ... /// ---+---+---+---+---+---+---+---+--- /// R | G | B | R | G | B | R | G | ... /// ``` #[derive(Clone, Copy, PartialEq)] pub struct Bgr24; impl Sealed for Bgr24 {} impl PixelFormatSpec for Bgr24 { const FORMAT_ENUM: PixelFormat = PixelFormat::Bgr24; const CHANNELS: usize = 3; const PIXEL_WIDTH: usize = 3; const NAME: &'static str = "Bgr24"; const RED_PACK: PackedLocation = PackedLocation::select_byte(0); const GREEN_PACK: PackedLocation = PackedLocation::select_byte(1); const BLUE_PACK: PackedLocation = PackedLocation::select_byte(2); const ALPHA_PACK: PackedLocation = PackedLocation::empty(); } /// 24bpp colour packed into 32-bit words /// /// This assumes the following memory layout: /// /// ```text /// 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ... /// ---+---+---+---+---+---+---+---+--- /// R | G | B | - | R | G | B | - | ... /// ``` #[derive(Clone, Copy, PartialEq)] pub struct Bgr32; impl Sealed for Bgr32 {} impl PixelFormatSpec for Bgr32 { const FORMAT_ENUM: PixelFormat = PixelFormat::Bgr32; const CHANNELS: usize = 3; const PIXEL_WIDTH: usize = 4; const NAME: &'static str = "Bgr32"; const RED_PACK: PackedLocation = PackedLocation::select_byte(2); const GREEN_PACK: PackedLocation = PackedLocation::select_byte(1); const BLUE_PACK: PackedLocation = PackedLocation::select_byte(0); const ALPHA_PACK: PackedLocation = PackedLocation::empty(); } /// 24bpp colour densly packed into 24-bit words /// /// This assumes the following memory layout: /// /// ```text /// 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ... /// ---+---+---+---+---+---+---+---+--- /// B | G | R | B | G | R | B | G | ... /// ``` #[derive(Clone, Copy, PartialEq)] pub struct Rgb24; impl Sealed for Rgb24 {} impl PixelFormatSpec for Rgb24 { const FORMAT_ENUM: PixelFormat = PixelFormat::Rgb24; const CHANNELS: usize = 3; const PIXEL_WIDTH: usize = 3; const NAME: &'static str = "Rgb24"; const RED_PACK: PackedLocation = PackedLocation::select_byte(2); const GREEN_PACK: PackedLocation = PackedLocation::select_byte(1); const BLUE_PACK: PackedLocation = PackedLocation::select_byte(0); const ALPHA_PACK: PackedLocation = PackedLocation::empty(); } /// 24bpp colour packed into 32-bit words /// /// This assumes the following memory layout: /// /// ```text /// 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ... /// ---+---+---+---+---+---+---+---+--- /// B | G | R | - | B | G | R | - | ... /// ``` #[derive(Clone, Copy, PartialEq)] pub struct Rgb32; impl Sealed for Rgb32 {} impl PixelFormatSpec for Rgb32 { const FORMAT_ENUM: PixelFormat = PixelFormat::Rgb32; const CHANNELS: usize = 3; const PIXEL_WIDTH: usize = 4; const NAME: &'static str = "Rgb32"; const RED_PACK: PackedLocation = PackedLocation::select_byte(2); const GREEN_PACK: PackedLocation = PackedLocation::select_byte(1); const BLUE_PACK: PackedLocation = PackedLocation::select_byte(0); const ALPHA_PACK: PackedLocation = PackedLocation::empty(); } /// RGBA with 8 bits per channel, stored little-endian /// /// This assumes the following memory layout: /// ```text /// 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ... /// ---+---+---+---+---+---+---+---+--- /// R | G | B | A | R | G | B | A | ... /// ``` #[derive(Clone, Copy, PartialEq)] pub struct Rgba32; impl Sealed for Rgba32 {} impl PixelFormatSpec for Rgba32 { const FORMAT_ENUM: PixelFormat = PixelFormat::Rgba32; const CHANNELS: usize = 4; const PIXEL_WIDTH: usize = 4; const NAME: &'static str = "Rgba32"; const RED_PACK: PackedLocation = PackedLocation::select_byte(0); const GREEN_PACK: PackedLocation = PackedLocation::select_byte(1); const BLUE_PACK: PackedLocation = PackedLocation::select_byte(2); const ALPHA_PACK: PackedLocation = PackedLocation::select_byte(3); }