softbuffer
softbuffer copied to clipboard
WIP: Format API / Transparency
This is my answer to #17 and #98
WIP
I have only actually implemented the required changes for windows and mac os, as this was just an experiment to see if the idea I had would be doable. And those are the 2 platforms I have/use.
If you are on these platforms feel free to point your cargo.toml at the fork to try it out. (If you do want to try it out, keep in mind you have to disable the compatibility
feature in your cargo.toml that is enabled by default)
High level overview of changes:
- Added ability to tell backend that you want to use transparency/alpha channel
- Created RGBX/RGBA structs that can be used on every platform without needing to think about how the platform stores the u32 as the conversion to each of the platforms happens automatically
Essentially the changes are as follows:
- Added softbuffer::Surface::new_with_alpha() function that creates an alpha aware surface
- Created
RGBX
andRGBA
structs- Both structs have a
Self::new()
andSelf::new_unchecked()
-
new()
returns a result, with an error if any of the values passed in overflow a u8 -
new_unchecked()
returnsSelf
directly, silently ignoring any overflow, the same as if you had300u32 as u8
- The two functions take any primitive number type (u8,u16,u32,etc)
- I took a quick look at the machine code, when passing in a u8 or u32 it appears to be just as performant as doing bit shifts yourself (Obviously
new
has some extra jmp for the overflow checks butnew_unchecked
is very clean). In the case that you pass u8's intonew
it has the same machine code asnew_unchecked
- The structs are
#[Repr(C)]
with 4 u8's in them. I then change the ordering of the r,g,b,x/a properties based on the platform, and then inside the bufferImpl I can transmute the[u32]
to the appropriate type based on with/without alpha
-
- Both structs have a
- Depreciated old api where you get access to a raw
&mut [u32]
buffer- Added feature
compatibility
to allow the old deref to still point to&mut [u32]
buffer, enabled by default. - Without
compatibility
feature enabled, buffer now derefs to a&mut [RGBX]
when called on a surface created by callingSurface::new()
and&mut [RGBA]
when called on a surface created by callingSurface::new_with_alpha()
- Can call
buffer.pixels_mut()
function to access old style &mut [u32] even withcompatibility
feature disabled
- Added feature
- Changed the backend impl for windows and macos
- Added new_with_alpha method
- Made required changes to tell backend that we are using alpha channel if called with new api, but still run the old way otherwise
Example:
Taking the winit.rs example and changing the following relevant lines shows how this works:
let window = winit_app::make_window(elwt, |w| w.with_transparent(true));
let context = softbuffer::Context::new(window.clone()).unwrap();
let surface = softbuffer::Surface::new_with_alpha(&context, window.clone()).unwrap();
(window, surface)
let mut buffer = surface.buffer_mut().unwrap();
for y in 0..height.get() {
for x in 0..width.get() {
let red = x % 255;
let green = y % 255;
let blue = (x * y) % 255;
let alpha = x % 255;
let index = y as usize * width.get() as usize + x as usize;
// buffer[index] = blue | (green << 8) | (red << 16) | (alpha << 24); // <--- previous method
buffer[index] = softbuffer::RGBA::new_unchecked(red, green, blue, alpha);
//Using the RGBX type would not work, and would fail to compile as the rgb type is based on the surface constructor you called
//buffer[index] = softbuffer::RGBX::new_unchecked(red, green, blue); // <-- Would fail to compile
}
}
Final Thoughts:
This was just some testing I wanted to do for my own project, if this is not the direction this project wants to go that is absolutely fine, I just thought I would share my experiments on the subject. I only spent about a day on it so no hard feelings if this never gets used.
The rest of the backends I did not update to even compile with the changes I made, so as is even if you just want to use the old api, this will not work on this branch currently.
If you did go this direction, you would probably want some extra conversion functions on the new RGBX/A types to be able to set them directly with a u32. (At least I think? Maybe not?) Of course that has the same issue of before of having conversion/format issues, but you could definitely implement it in such a way that there is either no conversion and it is platform dependent, or there is auto conversions for platforms that don't match the norm. Or a mix of both.
You would also want to expose a buffer.pixels_rgb_mut()
function just as a shim so that you can access the new methods while having the compatibility
feature enabled, just to help the transition.
Side Note: Please excuse the horror I created in the backend_dispatch.rs
file. That could probably be cleaned up to be a bit nicer, I just wanted to get it working though.
Thanks for coming to my Ted talk ❤️