Skip to content

Commit a09b6d7

Browse files
committed
Add Pixel struct
This is much more intuitive to use than manually bit-packing into a u32.
1 parent 211b059 commit a09b6d7

27 files changed

+322
-201
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Added `Buffer::pixels_iter()` for iterating over each pixel with its associated `x`/`y` coordinate.
66
- **Breaking:** Removed generic type parameters `D` and `W` from `Buffer<'_>` struct.
77
- **Breaking:** Removed `Deref[Mut]` implementation on `Buffer<'_>`. Use `Buffer::pixels()` instead.
8+
- **Breaking:** Add `Pixel` struct, and use that for pixels instead of `u32`.
89
- **Breaking:** Removed unintentional Cargo features for Softbuffer's optional dependencies.
910
- **Breaking:** Disable the DRM/KMS backend by default.
1011
- **Breaking:** Removed `DamageOutOfRange` error case. If the damage value is greater than the backend supports, it is instead clamped to an appropriate value.

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ To run the Android-specific example on an Android phone: `cargo apk r --example
6767
```rust,no_run
6868
use std::num::NonZeroU32;
6969
use std::rc::Rc;
70+
use softbuffer::{Context, Pixel, Surface};
7071
use winit::event::{Event, WindowEvent};
7172
use winit::event_loop::{ControlFlow, EventLoop};
7273
use winit::window::Window;
@@ -76,14 +77,14 @@ mod util;
7677
7778
fn main() {
7879
let event_loop = EventLoop::new().unwrap();
79-
let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap();
80+
let context = Context::new(event_loop.owned_display_handle()).unwrap();
8081
8182
let mut app = util::WinitAppBuilder::with_init(
8283
|elwt| {
8384
let window = elwt.create_window(Window::default_attributes());
8485
Rc::new(window.unwrap())
8586
},
86-
|_elwt, window| softbuffer::Surface::new(&context, window.clone()).unwrap(),
87+
|_elwt, window| Surface::new(&context, window.clone()).unwrap(),
8788
)
8889
.with_event_handler(|window, surface, window_id, event, elwt| {
8990
elwt.set_control_flow(ControlFlow::Wait);
@@ -108,11 +109,11 @@ fn main() {
108109
109110
let mut buffer = surface.buffer_mut().unwrap();
110111
for (x, y, pixel) in buffer.pixels_iter() {
111-
let red = x % 255;
112-
let green = y % 255;
113-
let blue = (x * y) % 255;
112+
let red = (x % 255) as u8;
113+
let green = (y % 255) as u8;
114+
let blue = ((x * y) % 255) as u8;
114115
115-
*pixel = blue | (green << 8) | (red << 16);
116+
*pixel = Pixel::new_rgb(red, green, blue);
116117
}
117118
118119
buffer.present().unwrap();

benches/buffer_mut.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
)))]
88
fn buffer_mut(c: &mut criterion::Criterion) {
99
use criterion::black_box;
10-
use softbuffer::{Context, Surface};
10+
use softbuffer::{Context, Pixel, Surface};
1111
use std::num::NonZeroU32;
1212
use winit::event_loop::ControlFlow;
1313
use winit::platform::run_on_demand::EventLoopExtRunOnDemand;
@@ -43,16 +43,16 @@ fn buffer_mut(c: &mut criterion::Criterion) {
4343
c.bench_function("pixels()", |b| {
4444
let mut buffer = surface.buffer_mut().unwrap();
4545
b.iter(|| {
46-
let pixels: &mut [u32] = buffer.pixels();
46+
let pixels: &mut [Pixel] = buffer.pixels();
4747
black_box(pixels);
4848
});
4949
});
5050

51-
c.bench_function("fill u32", |b| {
51+
c.bench_function("fill pixels", |b| {
5252
let mut buffer = surface.buffer_mut().unwrap();
5353
b.iter(|| {
5454
let buffer = black_box(&mut buffer);
55-
buffer.pixels().fill(0x00000000);
55+
buffer.pixels().fill(Pixel::default());
5656
});
5757
});
5858

@@ -64,7 +64,7 @@ fn buffer_mut(c: &mut criterion::Criterion) {
6464
let red = (x & 0xff) ^ (y & 0xff);
6565
let green = (x & 0x7f) ^ (y & 0x7f);
6666
let blue = (x & 0x3f) ^ (y & 0x3f);
67-
*pixel = blue | (green << 8) | (red << 16);
67+
*pixel = Pixel::new_rgb(red as u8, green as u8, blue as u8);
6868
}
6969
});
7070
});

examples/animation.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#[cfg(not(target_family = "wasm"))]
22
use rayon::prelude::*;
3+
use softbuffer::{Context, Pixel, Surface};
34
use std::f64::consts::PI;
45
use std::num::NonZeroU32;
56
use web_time::Instant;
@@ -15,7 +16,7 @@ fn main() {
1516
let event_loop = EventLoop::new().unwrap();
1617
let start = Instant::now();
1718

18-
let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap();
19+
let context = Context::new(event_loop.owned_display_handle()).unwrap();
1920

2021
let app = util::WinitAppBuilder::with_init(
2122
|event_loop| {
@@ -26,9 +27,7 @@ fn main() {
2627

2728
(window, old_size, frames)
2829
},
29-
move |_elwft, (window, _old_size, _frames)| {
30-
softbuffer::Surface::new(&context, window.clone()).unwrap()
31-
},
30+
move |_elwft, (window, _old_size, _frames)| Surface::new(&context, window.clone()).unwrap(),
3231
)
3332
.with_event_handler(move |state, surface, window_id, event, elwt| {
3433
let (window, old_size, frames) = state;
@@ -95,7 +94,7 @@ fn main() {
9594
util::run_app(event_loop, app);
9695
}
9796

98-
fn pre_render_frames(width: u32, height: u32) -> Vec<Vec<u32>> {
97+
fn pre_render_frames(width: u32, height: u32) -> Vec<Vec<Pixel>> {
9998
let render = |frame_id| {
10099
let elapsed = ((frame_id as f64) / (60.0)) * 2.0 * PI;
101100

@@ -104,14 +103,11 @@ fn pre_render_frames(width: u32, height: u32) -> Vec<Vec<u32>> {
104103
.map(|(x, y)| {
105104
let y = (y as f64) / (height as f64);
106105
let x = (x as f64) / (width as f64);
107-
let red =
108-
((((y + elapsed).sin() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);
109-
let green =
110-
((((x + elapsed).sin() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);
111-
let blue =
112-
((((y - elapsed).cos() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);
113-
114-
blue | (green << 8) | (red << 16)
106+
let r = ((((y + elapsed).sin() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);
107+
let g = ((((x + elapsed).sin() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);
108+
let b = ((((y - elapsed).cos() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);
109+
110+
Pixel::new_rgb(r as u8, g as u8, b as u8)
115111
})
116112
.collect::<Vec<_>>()
117113
};

examples/drm.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ mod imple {
1717
use drm::Device;
1818

1919
use raw_window_handle::{DisplayHandle, DrmDisplayHandle, DrmWindowHandle, WindowHandle};
20-
use softbuffer::{Context, Surface};
20+
use softbuffer::{Context, Pixel, Surface};
2121

2222
use std::num::NonZeroU32;
2323
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd};
@@ -161,16 +161,15 @@ mod imple {
161161
Ok(())
162162
}
163163

164-
fn draw_to_buffer(buf: &mut [u32], tick: usize) {
164+
fn draw_to_buffer(buf: &mut [Pixel], tick: usize) {
165165
let scale = colorous::SINEBOW;
166166
let mut i = (tick as f64) / 20.0;
167167
while i > 1.0 {
168168
i -= 1.0;
169169
}
170170

171171
let color = scale.eval_continuous(i);
172-
let pixel = ((color.r as u32) << 16) | ((color.g as u32) << 8) | (color.b as u32);
173-
buf.fill(pixel);
172+
buf.fill(Pixel::new_rgb(color.r, color.g, color.b));
174173
}
175174

176175
struct Card(std::fs::File);

examples/fruit.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use image::GenericImageView;
2+
use softbuffer::{Context, Pixel, Surface};
23
use std::num::NonZeroU32;
34
use winit::event::{KeyEvent, WindowEvent};
45
use winit::event_loop::{ControlFlow, EventLoop};
@@ -14,7 +15,7 @@ fn main() {
1415
let (width, height) = (fruit.width(), fruit.height());
1516

1617
let event_loop = EventLoop::new().unwrap();
17-
let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap();
18+
let context = Context::new(event_loop.owned_display_handle()).unwrap();
1819

1920
let app = util::WinitAppBuilder::with_init(
2021
move |elwt| {
@@ -23,7 +24,7 @@ fn main() {
2324
})
2425
},
2526
move |_elwt, window| {
26-
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
27+
let mut surface = Surface::new(&context, window.clone()).unwrap();
2728
// Intentionally only set the size of the surface once, at creation.
2829
// This is needed if the window chooses to ignore the size we passed in above, and for the
2930
// platforms softbuffer supports that don't yet extract the size from the window.
@@ -53,12 +54,8 @@ fn main() {
5354
let mut buffer = surface.buffer_mut().unwrap();
5455
let width = fruit.width();
5556
for (x, y, pixel) in fruit.pixels() {
56-
let red = pixel.0[0] as u32;
57-
let green = pixel.0[1] as u32;
58-
let blue = pixel.0[2] as u32;
59-
60-
let color = blue | (green << 8) | (red << 16);
61-
buffer.pixels()[(y * width + x) as usize] = color;
57+
let pixel = Pixel::new_rgb(pixel.0[0], pixel.0[1], pixel.0[2]);
58+
buffer.pixels()[(y * width + x) as usize] = pixel;
6259
}
6360

6461
buffer.present().unwrap();

examples/libxcb.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod example {
1717
DisplayHandle, RawDisplayHandle, RawWindowHandle, WindowHandle, XcbDisplayHandle,
1818
XcbWindowHandle,
1919
};
20+
use softbuffer::{Context, Pixel, Surface};
2021
use std::{env, num::NonZeroU32, ptr::NonNull};
2122
use x11rb::{
2223
connection::Connection,
@@ -27,8 +28,6 @@ mod example {
2728
xcb_ffi::XCBConnection,
2829
};
2930

30-
const RED: u32 = 255 << 16;
31-
3231
pub(crate) fn run() {
3332
// Create a new XCB connection
3433
let (conn, screen) = XCBConnection::connect(None).expect("Failed to connect to X server");
@@ -78,8 +77,8 @@ mod example {
7877
unsafe { DisplayHandle::borrow_raw(RawDisplayHandle::Xcb(display_handle)) };
7978
let window_handle =
8079
unsafe { WindowHandle::borrow_raw(RawWindowHandle::Xcb(window_handle)) };
81-
let context = softbuffer::Context::new(display_handle).unwrap();
82-
let mut surface = softbuffer::Surface::new(&context, window_handle).unwrap();
80+
let context = Context::new(display_handle).unwrap();
81+
let mut surface = Surface::new(&context, window_handle).unwrap();
8382

8483
// Register an atom for closing the window.
8584
let wm_protocols_atom = conn
@@ -124,7 +123,7 @@ mod example {
124123
)
125124
.unwrap();
126125
let mut buffer = surface.buffer_mut().unwrap();
127-
buffer.pixels().fill(RED);
126+
buffer.pixels().fill(Pixel::new_rgb(0xff, 0, 0));
128127
buffer.present().unwrap();
129128
}
130129
Event::ConfigureNotify(configure_notify) => {

examples/raytracing/game.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::time::{Duration, Instant};
22

33
use rand::rngs::SmallRng;
44
use rand::{Rng, SeedableRng};
5-
use softbuffer::Buffer;
5+
use softbuffer::{Buffer, Pixel};
66

77
use crate::camera::Camera;
88
use crate::vec3::{Color, Point3, Vec3};
@@ -71,9 +71,9 @@ impl Game {
7171
dist_to_focus,
7272
);
7373

74-
let mut pixels = vec![0; width as usize * height as usize];
74+
let mut pixels = vec![Pixel::default(); width as usize * height as usize];
7575

76-
let each_pixel = |rng: &mut SmallRng, i, pixel: &mut u32| {
76+
let each_pixel = |rng: &mut SmallRng, i, pixel: &mut Pixel| {
7777
let y = i % (width as usize);
7878
let x = i / (width as usize);
7979
let mut pixel_color = Color::default();
@@ -125,7 +125,7 @@ impl Game {
125125
right: f32,
126126
top: f32,
127127
bottom: f32,
128-
color: u32,
128+
color: Pixel,
129129
}
130130

131131
let width = buffer.width().get() as f32 / scale_factor;
@@ -136,14 +136,14 @@ impl Game {
136136
right: width - 10.0,
137137
top: height - 90.0,
138138
bottom: height - 10.0,
139-
color: 0x00eeaaaa,
139+
color: Pixel::new_rgb(0xee, 0xaa, 0xaa),
140140
},
141141
Rect {
142142
left: 30.0,
143143
right: 70.0,
144144
top: height - 70.0,
145145
bottom: height - 30.0,
146-
color: 0x00aaaaee,
146+
color: Pixel::new_rgb(0xaa, 0xaa, 0xee),
147147
},
148148
];
149149

@@ -193,7 +193,7 @@ impl Game {
193193
}
194194
}
195195

196-
fn color_to_pixel(pixel_color: Color, samples_per_pixel: i32) -> u32 {
196+
fn color_to_pixel(pixel_color: Color, samples_per_pixel: i32) -> Pixel {
197197
let mut r = pixel_color.x;
198198
let mut g = pixel_color.y;
199199
let mut b = pixel_color.z;
@@ -203,7 +203,9 @@ fn color_to_pixel(pixel_color: Color, samples_per_pixel: i32) -> u32 {
203203
g = f32::sqrt(scale * g);
204204
b = f32::sqrt(scale * b);
205205

206-
(256.0 * b.clamp(0.0, 0.999)) as u32
207-
| (((256.0 * g.clamp(0.0, 0.999)) as u32) << 8)
208-
| (((256.0 * r.clamp(0.0, 0.999)) as u32) << 16)
206+
Pixel::new_rgb(
207+
(256.0 * r.clamp(0.0, 0.999)) as u8,
208+
(256.0 * g.clamp(0.0, 0.999)) as u8,
209+
(256.0 * b.clamp(0.0, 0.999)) as u8,
210+
)
209211
}

examples/raytracing/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! Note that this is quite slow, you probably don't want to do realtime CPU raytracing in practice.
44
//!
55
//! [Ray Tracing in One Weekend]: https://raytracing.github.io/books/RayTracingInOneWeekend.html
6+
use softbuffer::{Context, Surface};
67
use std::num::NonZeroU32;
78
use winit::event::{DeviceEvent, ElementState, KeyEvent, WindowEvent};
89
use winit::event_loop::EventLoop;
@@ -25,12 +26,12 @@ fn main() {
2526
util::setup();
2627

2728
let event_loop = EventLoop::new().unwrap();
28-
let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap();
29+
let context = Context::new(event_loop.owned_display_handle()).unwrap();
2930

3031
let app = util::WinitAppBuilder::with_init(
3132
|elwt| util::make_window(elwt, |w| w),
3233
move |_elwt, window| {
33-
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
34+
let mut surface = Surface::new(&context, window.clone()).unwrap();
3435
surface
3536
.resize(
3637
NonZeroU32::new(window.inner_size().width).unwrap(),

examples/rectangle.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use softbuffer::Buffer;
1+
use softbuffer::{Buffer, Context, Pixel, Surface};
22
use std::num::NonZeroU32;
33
use winit::event::{ElementState, KeyEvent, WindowEvent};
44
use winit::event_loop::{ControlFlow, EventLoop};
@@ -11,12 +11,12 @@ fn redraw(buffer: &mut Buffer<'_>, flag: bool) {
1111
let height = buffer.height().get();
1212
for (x, y, pixel) in buffer.pixels_iter() {
1313
*pixel = if flag && x >= 100 && x < width - 100 && y >= 100 && y < height - 100 {
14-
0x00ffffff
14+
Pixel::new_rgb(0xff, 0xff, 0xff)
1515
} else {
1616
let red = (x & 0xff) ^ (y & 0xff);
1717
let green = (x & 0x7f) ^ (y & 0x7f);
1818
let blue = (x & 0x3f) ^ (y & 0x3f);
19-
blue | (green << 8) | (red << 16)
19+
Pixel::new_rgb(red as u8, green as u8, blue as u8)
2020
};
2121
}
2222
}
@@ -25,7 +25,7 @@ fn main() {
2525
util::setup();
2626

2727
let event_loop = EventLoop::new().unwrap();
28-
let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap();
28+
let context = Context::new(event_loop.owned_display_handle()).unwrap();
2929

3030
let app = util::WinitAppBuilder::with_init(
3131
|elwt| {
@@ -37,7 +37,7 @@ fn main() {
3737

3838
(window, flag)
3939
},
40-
move |_elwt, (window, _flag)| softbuffer::Surface::new(&context, window.clone()).unwrap(),
40+
move |_elwt, (window, _flag)| Surface::new(&context, window.clone()).unwrap(),
4141
)
4242
.with_event_handler(|state, surface, window_id, event, elwt| {
4343
let (window, flag) = state;

0 commit comments

Comments
 (0)