From 710d249674e261520608b95fb0ac816c5416d0b7 Mon Sep 17 00:00:00 2001 From: Jaysonmaw <55055180+jaysonmaw@users.noreply.github.com> Date: Wed, 11 Sep 2024 20:51:37 -0500 Subject: [PATCH] Adding an additional format that mirrors the windows/mac os format Added some documentation with examples to better show how different parts work together Added u32/8 conversions for formats and main RGBX/RGBA structs Refactored RGBFormat impl's into macro as it was a bunch of repeated code. --- src/backend_interface.rs | 196 ++++++++++++++++++++++++--------------- src/formats.rs | 77 +++++++++++++++ src/lib.rs | 2 +- 3 files changed, 198 insertions(+), 77 deletions(-) diff --git a/src/backend_interface.rs b/src/backend_interface.rs index 8d7573b..e954e10 100644 --- a/src/backend_interface.rs +++ b/src/backend_interface.rs @@ -64,6 +64,14 @@ macro_rules! define_rgbx_little_endian { $(#[$attr])* #[repr(C)] #[derive(Copy,Clone)] + /// If you want to modify an RGBX returned from a ```buffer[index]``` you can modify the r,g,b fields directly, as doing that is completely platform independent + /// # Example: + /// ```rust + /// let pixel = &mut buffer[index]; + /// pixel.r = 255; + /// pixel.g = 255; + /// pixel.b = 255; + /// ``` pub struct RGBX{ $forth_vis $forth: u8, $third_vis $third: u8, @@ -85,6 +93,15 @@ macro_rules! define_rgba_little_endian { $(#[$attr])* #[repr(C)] #[derive(Copy,Clone)] + /// If you want to modify an RGBA returned from a ```buffer[index]``` you can modify the r,g,b,a fields directly, as doing that is completely platform independent + /// # Example: + /// ```rust + /// let pixel = &mut buffer[index]; + /// pixel.r = 255; + /// pixel.g = 255; + /// pixel.b = 255; + /// pixel.a = 255; + /// ``` pub struct RGBA{ $forth_vis $forth: u8, $third_vis $third: u8, @@ -158,13 +175,32 @@ impl RGBX{ Self { r: r.as_(), g: g.as_(), b: b.as_(), x: 255 } } - // pub fn new_from_u32(u32: u32) -> Self{ - // todo!() - // } + /// Creates a RGBX from a u32 + /// It is not recommended to use this function as you need to ensure that the u32 matches the format expected by your target platform + /// + /// Instead it is better if you must create an RGBX from a u32, to instead use the ```softbuffer::formats::RGBFormat```, that way you can use a + /// specific format that is not platform dependent, and if using the correct format for your platform, this is a Zero Cost abstraction. + /// ```rust + /// RGBA::from_rgba_format(softbuffer::formats::RGBA::new_from_u32(u32_rgba)) + /// ``` + pub fn new_from_u32_platform_dependent(u32: u32) -> Self{ + unsafe{std::mem::transmute(u32)} + } - // pub fn as_u32(&self) -> &u32{ - // unsafe{std::mem::transmute(self)} - // } + /// Creates a u32 from a RGBX + /// It is not recommended to use this function as is will be in whatever format your platform uses + /// + /// If you want to modify an RGBX returned from a ```buffer[index]``` you can modify the r,g,b fields directly, as doing that is completely platform independent + /// # Example: + /// ```rust + /// let pixel = &mut buffer[index]; + /// pixel.r = 255; + /// pixel.g = 255; + /// pixel.b = 255; + /// ``` + pub fn as_u32(&self) -> &u32{ + unsafe{std::mem::transmute(self)} + } } impl RGBA{ @@ -195,81 +231,89 @@ impl RGBA{ { Self { r: r.as_(), g: g.as_(), b: b.as_(), a: a.as_() } } -} -impl RGBFormat for RGBA{ - fn to_rgba_format(self) -> crate::formats::RGBA { - crate::formats::RGBA{ - a: self.a, - b: self.b, - g: self.g, - r: self.r, - } - } - - fn from_rgba_format(rgba: crate::formats::RGBA) -> Self { - Self{ - b: rgba.b, - g: rgba.g, - r: rgba.r, - a: rgba.a, - } - } - - fn to_rgba_u8_format(self) -> crate::formats::RGBAu8 { - crate::formats::RGBAu8{ - a: self.a, - b: self.b, - g: self.g, - r: self.r, - } + /// Creates a RGBA from a u32 + /// It is not recommended to use this function as you need to ensure that the u32 matches the format expected by your target platform + /// + /// Instead it is better if you must create an RGBA from a u32, to instead use the ```softbuffer::formats::RGBFormat```, that way you can use a + /// specific format that is not platform dependent, and if using the correct format for your platform, this is a Zero Cost abstraction. + /// ```rust + /// RGBA::from_rgba_format(softbuffer::formats::RGBA::new_from_u32(u32_rgba)) + /// ``` + #[inline] + pub fn new_from_u32_platform_dependent(u32: u32) -> Self{ + unsafe{std::mem::transmute(u32)} } - - fn from_rgba_u8_format(rgba: crate::formats::RGBAu8) -> Self { - Self{ - b: rgba.b, - g: rgba.g, - r: rgba.r, - a: rgba.a, - } + + /// Creates a u32 from a RGBA + /// It is not recommended to use this function as is will be in whatever format your platform uses + /// + /// If you want to modify an RGBA returned from a ```buffer[index]``` you can modify the r,g,b fields directly, as doing that is completely platform independent + /// # Example: + /// ```rust + /// let pixel = &mut buffer[index]; + /// pixel.r = 255; + /// pixel.g = 255; + /// pixel.b = 255; + /// pixel.a = 255; + /// ``` + #[inline] + pub fn as_u32(&self) -> &u32{ + unsafe{std::mem::transmute(self)} } - } -impl RGBFormat for RGBX{ - fn to_rgba_format(self) -> crate::formats::RGBA { - crate::formats::RGBA{ - a: self.x, - b: self.b, - g: self.g, - r: self.r, - } - } - - fn from_rgba_format(rgba: crate::formats::RGBA) -> Self { - Self{ - b: rgba.b, - g: rgba.g, - r: rgba.r, - x: rgba.a, - } - } - - fn to_rgba_u8_format(self) -> crate::formats::RGBAu8 { - crate::formats::RGBAu8{ - a: self.x, - b: self.b, - g: self.g, - r: self.r, +macro_rules! impl_conversions { + ( + $( + $to_func: ident => $from_func: ident => $to_type:ident; + )* + ) => { + impl RGBFormat for RGBA{ + $( + fn $to_func(self) -> crate::formats::$to_type { + crate::formats::$to_type{ + a: self.a, + b: self.b, + g: self.g, + r: self.r, + } + } + fn $from_func(rgba: crate::formats::$to_type) -> Self { + Self{ + b: rgba.b, + g: rgba.g, + r: rgba.r, + a: rgba.a, + } + } + )* } - } - - fn from_rgba_u8_format(rgba: crate::formats::RGBAu8) -> Self { - Self{ - b: rgba.b, - g: rgba.g, - r: rgba.r, - x: rgba.a, + impl RGBFormat for RGBX{ + $( + fn $to_func(self) -> crate::formats::$to_type { + crate::formats::$to_type{ + a: self.x, + b: self.b, + g: self.g, + r: self.r, + } + } + fn $from_func(rgba: crate::formats::$to_type) -> Self { + Self{ + b: rgba.b, + g: rgba.g, + r: rgba.r, + x: rgba.a, + } + } + )* } - } + }; +} + +impl_conversions!{ + to_rgba_format => from_rgba_format => RGBA; + to_rgba_u8_format => from_rgba_u8_format => RGBAu8; + to_argb_format => from_argb_format => ARGB; } \ No newline at end of file diff --git a/src/formats.rs b/src/formats.rs index b279d38..4069b4c 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -1,8 +1,27 @@ +/// Used for converting to and from the ```softbuffer::RGBX``` or ```softbuffer::RGBA``` +/// in their platform specific formats, to a specific format when needed +/// +/// Keep in mind that platform endianness still maters when creating these format values +/// as they are backed by a u32 where endianness matters. A workaround for this is to use the u32::from_be_bytes as shown in the example. +/// +/// If wanting a completely non endian format, use one of the u8 based formats. +/// +/// # Example: +/// ```rust +/// let red = 255; +/// let green = 0; +/// let blue = 255; +/// let alpha = 255; +/// let purple_u32_rgba = u32::from_be_bytes([red, green, blue, alpha]); //ensures is platform independent +/// RGBA::from_rgba_format(softbuffer::formats::RGBA::new_from_u32(purple_u32_rgba)); +/// ``` pub trait RGBFormat{ fn to_rgba_format(self) -> crate::formats::RGBA; fn from_rgba_format(rgba: crate::formats::RGBA) -> Self; fn to_rgba_u8_format(self) -> crate::formats::RGBAu8; fn from_rgba_u8_format(rgba: crate::formats::RGBAu8) -> Self; + fn to_argb_format(self) -> crate::formats::ARGB; + fn from_argb_format(rgba: crate::formats::ARGB) -> Self; } //When wanting the bytes in a specific order by u8, you no longer care about endianness @@ -15,6 +34,26 @@ pub struct RGBAu8{ pub a: u8, } +impl RGBAu8{ + /// Creates a ```softbuffer::formats::RGBAu8``` from a ```[u8;4]```. + /// + /// To get a useable softbuffer::RGBA import the ```softbuffer::formats::RGBFormat``` trait, and then you can call + /// softbuffer::RGBA::from_rgba_u8_format() + pub fn new_from_u8_array(slice: [u8;4])->Self{ + unsafe{ + std::mem::transmute(slice) + } + } + + /// Converts a ```softbuffer::formats::RGBAu8``` into a ```[u8;4]``` + pub fn as_u8_array(self) -> [u8;4]{ + unsafe{ + std::mem::transmute(self) + } + } +} + + #[cfg(target_endian = "little")] #[repr(C)] #[derive(Copy, Clone)] @@ -35,6 +74,25 @@ pub struct RGBA{ pub a: u8, } +impl RGBA { + /// Creates a ```softbuffer::formats::RGBA``` from a u32. + /// + /// To get a useable softbuffer::RGBA import the ```softbuffer::formats::RGBFormat``` trait, and then you can call + /// softbuffer::RGBA::from_rgba_format() + pub fn new_from_u32(u32: u32)->Self{ + unsafe{ + std::mem::transmute(u32) + } + } + + /// Converts a ```softbuffer::formats::RGBA``` into a u32 + pub fn as_u32(self) -> u32{ + unsafe{ + std::mem::transmute(self) + } + } +} + #[cfg(target_endian = "little")] #[repr(C)] #[derive(Copy, Clone)] @@ -53,4 +111,23 @@ pub struct ARGB{ pub r: u8, pub g: u8, pub b: u8, +} + +impl ARGB { + /// Creates a ```softbuffer::formats::ARGB``` from a u32. + /// + /// To get a useable softbuffer::RGBA import the ```softbuffer::formats::RGBFormat``` trait, and then you can call + /// softbuffer::RGBA::from_argb_format() + pub fn new_from_u32(u32: u32)->Self{ + unsafe{ + std::mem::transmute(u32) + } + } + + /// Converts a ```softbuffer::formats::ARGB``` into a u32 + pub fn as_u32(self) -> u32{ + unsafe{ + std::mem::transmute(self) + } + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 689b114..57170df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ use backend_interface::*; use formats::RGBFormat; mod backends; mod error; -mod formats; +pub mod formats; mod util; use std::cell::Cell;