|
| 1 | +Advanced Introduction to `softbuffer-quickstart` |
| 2 | +================================================ |
| 3 | +<small>a.k.a, "Well, what *more* can I do?"</small> |
| 4 | + |
| 5 | +> [!NOTE] |
| 6 | +> This assumes that you've read the basic introduction first. If you haven't taken a look at it--and you have time--I encourage you to do so!` |
| 7 | +
|
| 8 | +`softbuffer_quickstart`, at its core, actually provides utility functions for people who want to implement their own Winit windows. Let's work backwards. Say you want to implement your own Winit window. Then you'd certainly implement [`ApplicationHandler`](https://rust-windowing.github.io/winit/winit/application/trait.ApplicationHandler.html): |
| 9 | + |
| 10 | +```rust |
| 11 | +use winit::application::ApplicationHandler; |
| 12 | +use winit::event::WindowEvent; |
| 13 | +use winit::event_loop::ActiveEventLoop; |
| 14 | +use winit::window::WindowId; |
| 15 | + |
| 16 | + |
| 17 | +use softbuffer_quickstart::{init, WindowProperties}; |
| 18 | + |
| 19 | +struct MyWindow {} |
| 20 | + |
| 21 | +impl ApplicationHandler for MyWindow { |
| 22 | + fn resumed(&mut self, event_loop: &ActiveEventLoop) { |
| 23 | + todo!() |
| 24 | + } |
| 25 | + |
| 26 | + fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent) { |
| 27 | + todo!() |
| 28 | + } |
| 29 | +} |
| 30 | +``` |
| 31 | + |
| 32 | +But wait! How does `softbuffer_quickstart` fit into this? Well, let's take a look at those TODOs. |
| 33 | + |
| 34 | +## 1. Initializing `softbuffer_quickstart` |
| 35 | + |
| 36 | +Initializing `softbuffer_quickstart` is simple. We'll call `init` with the given event loop and a set of initial window properties (remember `WindowProperties`?), which will give us a `RawWindow` and `RawSurface` to store ourselves: |
| 37 | + |
| 38 | +```rust |
| 39 | +use winit::application::ApplicationHandler; |
| 40 | +use winit::event::WindowEvent; |
| 41 | +use winit::event_loop::ActiveEventLoop; |
| 42 | +use winit::window::WindowId; |
| 43 | + |
| 44 | + |
| 45 | +use softbuffer_quickstart::{init, RawSurface, RawWindow, WindowProperties}; |
| 46 | + |
| 47 | +struct MyWindow { |
| 48 | + window: RawWindow, |
| 49 | + surface: RawSurface |
| 50 | +} |
| 51 | + |
| 52 | +impl ApplicationHandler for MyWindow { |
| 53 | + fn resumed(&mut self, event_loop: &ActiveEventLoop) { |
| 54 | + (self.window, self.surface) = init(event_loop, &WindowProperties::default()); |
| 55 | + } |
| 56 | + |
| 57 | + fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent) { |
| 58 | + todo!() |
| 59 | + } |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +## 2. Drawing to a window (and other handy functions) |
| 64 | + |
| 65 | +Under `window_event` we're given free rein to handle anything. There are two handy functions that can make handling some events simpler: |
| 66 | +- `softbuffer_quickstart::close(&event_loop, &event)` checks to see if a "close" event has been signalled, and closes the window if it has. |
| 67 | +- `softbuffer_quickstart::resize(&event, &mut surface)` check to see if a "resize" event has been signalled, and resizes the underlying buffer. |
| 68 | + |
| 69 | +We can of course omit these and implement those checks ourselves, if we'd like. (However, no one probably wants to unwrap and clone and get references a bunch of times.) |
| 70 | + |
| 71 | +Everything else is stupid simple. We update the buffer how we want, and then call `redraw` once we're done. |
| 72 | +- `softbuffer_quickstart::buffer_mut(surface: &mut RawSurface)` returns a mutable reference to a `RawSurface`. (Hey, just like in the basic tutorial!) |
| 73 | +- `softbuffer_quickstart::redraw(window: &mut RawWindow, surface: &mut RawSurface)` presents the `RawSurface` to the screen, using the `RawWindow`. |
| 74 | + |
| 75 | +The final piece of the puzzle is *running* the thing. All we have to do is call `softbuffer_quickstart::run()` with a mutable reference to our window. |
| 76 | + |
| 77 | +So if we recreated the code in the basic introduction, it'd look like this: |
| 78 | + |
| 79 | +```rust |
| 80 | +use winit::application::ApplicationHandler; |
| 81 | +use winit::event::WindowEvent; |
| 82 | +use winit::event_loop::ActiveEventLoop; |
| 83 | +use winit::window::WindowId; |
| 84 | + |
| 85 | + |
| 86 | +use softbuffer_quickstart::{init, RawSurface, RawWindow, WindowProperties}; |
| 87 | + |
| 88 | +fn main() { |
| 89 | + let mut window = MyWindow { |
| 90 | + window: None, |
| 91 | + surface: None, |
| 92 | + size: (800, 600) |
| 93 | + }; |
| 94 | + softbuffer_quickstart::run(&mut window).expect("Window can't run"); |
| 95 | +} |
| 96 | + |
| 97 | +struct MyWindow { |
| 98 | + window: RawWindow, |
| 99 | + surface: RawSurface, |
| 100 | + size: (usize, usize) |
| 101 | +} |
| 102 | + |
| 103 | +impl ApplicationHandler for MyWindow { |
| 104 | + fn resumed(&mut self, event_loop: &ActiveEventLoop) { |
| 105 | + (self.window, self.surface) = init(event_loop, &WindowProperties::default()); |
| 106 | + } |
| 107 | + |
| 108 | + fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent) { |
| 109 | + softbuffer_quickstart::close(event_loop, &event); |
| 110 | + softbuffer_quickstart::resize(&event, &mut self.surface); |
| 111 | + |
| 112 | + match event { |
| 113 | + WindowEvent::Resized(size) => { |
| 114 | + self.size = (size.width as usize, size.height as usize); |
| 115 | + } |
| 116 | + WindowEvent::RedrawRequested => { |
| 117 | + let (width, height) = self.size; |
| 118 | + let mut buffer = softbuffer_quickstart::buffer_mut(&mut self.surface); |
| 119 | + for index in 0..(width * height) { |
| 120 | + let y = index / width; |
| 121 | + let x = index % width; |
| 122 | + let red = x % 255; |
| 123 | + let green = y % 255; |
| 124 | + let blue = (255 - (red + green).min(255)) % 255; |
| 125 | + |
| 126 | + buffer[index] = (blue | (green << 8) | (red << 16)).try_into().unwrap(); |
| 127 | + } |
| 128 | + softbuffer_quickstart::redraw(&mut self.window, &mut self.surface); |
| 129 | + } |
| 130 | + _ => (), |
| 131 | + } |
| 132 | + } |
| 133 | +} |
| 134 | +``` |
0 commit comments