Skip to content

Commit

Permalink
Adding an additional format that mirrors the windows/mac os format
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jaysonmaw committed Sep 12, 2024
1 parent e15f9ad commit 710d249
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 77 deletions.
196 changes: 120 additions & 76 deletions src/backend_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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;
}
77 changes: 77 additions & 0 deletions src/formats.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)]
Expand All @@ -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)]
Expand All @@ -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)
}
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 710d249

Please sign in to comment.