|
@@ -0,0 +1,258 @@
|
|
|
+use bitvec::{field::BitField, order::Lsb0, view::BitView};
|
|
|
+
|
|
|
+trait Sealed {}
|
|
|
+
|
|
|
+#[derive(Clone, PartialEq, Debug, Default)]
|
|
|
+pub struct Mask(std::ops::Range<usize>);
|
|
|
+
|
|
|
+impl Mask {
|
|
|
+ const fn empty() -> Self {
|
|
|
+ Self(0..0)
|
|
|
+ }
|
|
|
+ const fn select_byte(index: usize) -> Self {
|
|
|
+ Self((index * 8)..(index * 8 + 8))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, enum_map::Enum)]
|
|
|
+pub enum DynamicPixelFormat {
|
|
|
+ A8,
|
|
|
+ Abgr32,
|
|
|
+ Bgr24,
|
|
|
+ Bgr32,
|
|
|
+ Rgb24,
|
|
|
+ Rgb32,
|
|
|
+ Rgba32,
|
|
|
+}
|
|
|
+
|
|
|
+macro_rules! masks_for {
|
|
|
+ ($n:ident) => {
|
|
|
+ ($n::RED_MASK, $n::GREEN_MASK, $n::BLUE_MASK, $n::ALPHA_MASK)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl DynamicPixelFormat {
|
|
|
+ pub fn pixel_width(&self) -> usize {
|
|
|
+ match self {
|
|
|
+ Self::A8 => A8::PIXEL_WIDTH,
|
|
|
+ Self::Bgr24 => Bgr24::PIXEL_WIDTH,
|
|
|
+ Self::Bgr32 => Bgr32::PIXEL_WIDTH,
|
|
|
+ Self::Abgr32 => Abgr32::PIXEL_WIDTH,
|
|
|
+ Self::Rgb24 => Rgb24::PIXEL_WIDTH,
|
|
|
+ Self::Rgb32 => Rgb32::PIXEL_WIDTH,
|
|
|
+ Self::Rgba32 => Rgba32::PIXEL_WIDTH,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub const fn masks(&self) -> (Mask, Mask, Mask, Mask) {
|
|
|
+ match self {
|
|
|
+ Self::A8 => masks_for!(A8),
|
|
|
+ Self::Abgr32 => masks_for!(Abgr32),
|
|
|
+ Self::Bgr24 => masks_for!(Bgr24),
|
|
|
+ Self::Bgr32 => masks_for!(Bgr32),
|
|
|
+ Self::Rgb24 => masks_for!(Rgb24),
|
|
|
+ Self::Rgb32 => masks_for!(Rgb32),
|
|
|
+ Self::Rgba32 => masks_for!(Rgba32),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn red_mask(&self) -> Mask {
|
|
|
+ self.masks().0
|
|
|
+ }
|
|
|
+ pub fn green_mask(&self) -> Mask {
|
|
|
+ self.masks().1
|
|
|
+ }
|
|
|
+ pub fn blue_mask(&self) -> Mask {
|
|
|
+ self.masks().2
|
|
|
+ }
|
|
|
+ pub fn alpha_mask(&self) -> Mask {
|
|
|
+ self.masks().3
|
|
|
+ }
|
|
|
+
|
|
|
+ /*pub fn write_colour(&self, c: Colour, to: &mut [u8]) {
|
|
|
+ let bits = to.view_bits_mut::<Lsb0>();
|
|
|
+ bits[self.masks().0.0].store_be::<u8>(c.r);
|
|
|
+ bits[self.masks().1.0].store_be::<u8>(c.g);
|
|
|
+ bits[self.masks().2.0].store_be::<u8>(c.b);
|
|
|
+ bits[self.masks().3.0].store_be::<u8>(c.a);
|
|
|
+ }*/
|
|
|
+}
|
|
|
+*/
|
|
|
+
|
|
|
+#[allow(private_bounds)]
|
|
|
+pub trait PixelFormat: Sealed + Clone + Copy {
|
|
|
+ const CHANNELS: usize;
|
|
|
+ const PIXEL_WIDTH: usize;
|
|
|
+
|
|
|
+ const NAME: &'static str;
|
|
|
+
|
|
|
+ const RED_MASK: Mask;
|
|
|
+ const GREEN_MASK: Mask;
|
|
|
+ const BLUE_MASK: Mask;
|
|
|
+ const ALPHA_MASK: Mask;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+// Pixel formats
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+/// 8-bit alpha map
|
|
|
+#[derive(Clone, Copy, PartialEq)]
|
|
|
+pub struct A8;
|
|
|
+impl Sealed for A8 {}
|
|
|
+impl PixelFormat for A8 {
|
|
|
+ const CHANNELS: usize = 1;
|
|
|
+ const PIXEL_WIDTH: usize = 1;
|
|
|
+
|
|
|
+ const NAME: &'static str = "A8";
|
|
|
+
|
|
|
+ const RED_MASK: Mask = Mask::empty();
|
|
|
+ const GREEN_MASK: Mask = Mask::empty();
|
|
|
+ const BLUE_MASK: Mask = Mask::empty();
|
|
|
+ const ALPHA_MASK: Mask = Mask::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 PixelFormat for Abgr32 {
|
|
|
+ const CHANNELS: usize = 4;
|
|
|
+ const PIXEL_WIDTH: usize = 4;
|
|
|
+
|
|
|
+ const NAME: &'static str = "Abgr32";
|
|
|
+
|
|
|
+ const RED_MASK: Mask = Mask::select_byte(3);
|
|
|
+ const GREEN_MASK: Mask = Mask::select_byte(2);
|
|
|
+ const BLUE_MASK: Mask = Mask::select_byte(1);
|
|
|
+ const ALPHA_MASK: Mask = Mask::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 PixelFormat for Bgr24 {
|
|
|
+ const CHANNELS: usize = 3;
|
|
|
+ const PIXEL_WIDTH: usize = 3;
|
|
|
+
|
|
|
+ const NAME: &'static str = "Bgr24";
|
|
|
+
|
|
|
+ const RED_MASK: Mask = Mask::select_byte(0);
|
|
|
+ const GREEN_MASK: Mask = Mask::select_byte(1);
|
|
|
+ const BLUE_MASK: Mask = Mask::select_byte(2);
|
|
|
+ const ALPHA_MASK: Mask = Mask::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 PixelFormat for Bgr32 {
|
|
|
+ const CHANNELS: usize = 3;
|
|
|
+ const PIXEL_WIDTH: usize = 4;
|
|
|
+
|
|
|
+ const NAME: &'static str = "Bgr32";
|
|
|
+
|
|
|
+ const RED_MASK: Mask = Mask::select_byte(2);
|
|
|
+ const GREEN_MASK: Mask = Mask::select_byte(1);
|
|
|
+ const BLUE_MASK: Mask = Mask::select_byte(0);
|
|
|
+ const ALPHA_MASK: Mask = Mask::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 PixelFormat for Rgb24 {
|
|
|
+ const CHANNELS: usize = 3;
|
|
|
+ const PIXEL_WIDTH: usize = 3;
|
|
|
+
|
|
|
+ const NAME: &'static str = "Rgb24";
|
|
|
+
|
|
|
+ const RED_MASK: Mask = Mask::select_byte(2);
|
|
|
+ const GREEN_MASK: Mask = Mask::select_byte(1);
|
|
|
+ const BLUE_MASK: Mask = Mask::select_byte(0);
|
|
|
+ const ALPHA_MASK: Mask = Mask::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 PixelFormat for Rgb32 {
|
|
|
+ const CHANNELS: usize = 3;
|
|
|
+ const PIXEL_WIDTH: usize = 4;
|
|
|
+
|
|
|
+ const NAME: &'static str = "Rgb32";
|
|
|
+
|
|
|
+ const RED_MASK: Mask = Mask::select_byte(2);
|
|
|
+ const GREEN_MASK: Mask = Mask::select_byte(1);
|
|
|
+ const BLUE_MASK: Mask = Mask::select_byte(0);
|
|
|
+ const ALPHA_MASK: Mask = Mask::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 PixelFormat for Rgba32 {
|
|
|
+ const CHANNELS: usize = 4;
|
|
|
+ const PIXEL_WIDTH: usize = 4;
|
|
|
+
|
|
|
+ const NAME: &'static str = "Rgba32";
|
|
|
+
|
|
|
+ const RED_MASK: Mask = Mask::select_byte(0);
|
|
|
+ const GREEN_MASK: Mask = Mask::select_byte(1);
|
|
|
+ const BLUE_MASK: Mask = Mask::select_byte(2);
|
|
|
+ const ALPHA_MASK: Mask = Mask::select_byte(3);
|
|
|
+}
|