|
| 1 | +// Adapted from winit's examples/util/fill.rs. |
| 2 | + |
| 3 | +//! Fill the window buffer with a solid color. |
| 4 | +//! |
| 5 | +//! Launching a window without drawing to it has unpredictable results varying from platform to |
| 6 | +//! platform. In order to have well-defined examples, this module provides an easy way to |
| 7 | +//! fill the window buffer with a solid color. |
| 8 | +//! |
| 9 | +//! The `softbuffer` crate is used, largely because of its ease of use. `glutin` or `wgpu` could |
| 10 | +//! also be used to fill the window buffer, but they are more complicated to use. |
| 11 | +
|
| 12 | +pub use platform::cleanup_window; |
| 13 | +pub use platform::fill_window; |
| 14 | + |
| 15 | +#[cfg(not(any(target_os = "android", target_os = "ios")))] |
| 16 | +mod platform { |
| 17 | + use std::cell::RefCell; |
| 18 | + use std::collections::HashMap; |
| 19 | + use std::mem; |
| 20 | + use std::mem::ManuallyDrop; |
| 21 | + use std::num::NonZeroU32; |
| 22 | + |
| 23 | + use softbuffer::{Context, Surface}; |
| 24 | + use winit::window::{Window, WindowId}; |
| 25 | + |
| 26 | + thread_local! { |
| 27 | + // NOTE: You should never do things like that, create context and drop it before |
| 28 | + // you drop the event loop. We do this for brevity to not blow up examples. We use |
| 29 | + // ManuallyDrop to prevent destructors from running. |
| 30 | + // |
| 31 | + // A static, thread-local map of graphics contexts to open windows. |
| 32 | + static GC: ManuallyDrop<RefCell<Option<GraphicsContext>>> = const { ManuallyDrop::new(RefCell::new(None)) }; |
| 33 | + } |
| 34 | + |
| 35 | + /// The graphics context used to draw to a window. |
| 36 | + struct GraphicsContext { |
| 37 | + /// The global softbuffer context. |
| 38 | + context: RefCell<Context<&'static Window>>, |
| 39 | + |
| 40 | + /// The hash map of window IDs to surfaces. |
| 41 | + surfaces: HashMap<WindowId, Surface<&'static Window, &'static Window>>, |
| 42 | + } |
| 43 | + |
| 44 | + impl GraphicsContext { |
| 45 | + fn new(w: &Window) -> Self { |
| 46 | + Self { |
| 47 | + context: RefCell::new( |
| 48 | + Context::new(unsafe { mem::transmute::<&'_ Window, &'static Window>(w) }) |
| 49 | + .expect("Failed to create a softbuffer context"), |
| 50 | + ), |
| 51 | + surfaces: HashMap::new(), |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + fn create_surface( |
| 56 | + &mut self, |
| 57 | + window: &Window, |
| 58 | + ) -> &mut Surface<&'static Window, &'static Window> { |
| 59 | + self.surfaces.entry(window.id()).or_insert_with(|| { |
| 60 | + Surface::new(&self.context.borrow(), unsafe { |
| 61 | + mem::transmute::<&'_ Window, &'static Window>(window) |
| 62 | + }) |
| 63 | + .expect("Failed to create a softbuffer surface") |
| 64 | + }) |
| 65 | + } |
| 66 | + |
| 67 | + fn destroy_surface(&mut self, window: &Window) { |
| 68 | + self.surfaces.remove(&window.id()); |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + pub fn fill_window(window: &Window) { |
| 73 | + GC.with(|gc| { |
| 74 | + let size = window.inner_size(); |
| 75 | + let (Some(width), Some(height)) = |
| 76 | + (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) |
| 77 | + else { |
| 78 | + return; |
| 79 | + }; |
| 80 | + |
| 81 | + // Either get the last context used or create a new one. |
| 82 | + let mut gc = gc.borrow_mut(); |
| 83 | + let surface = gc |
| 84 | + .get_or_insert_with(|| GraphicsContext::new(window)) |
| 85 | + .create_surface(window); |
| 86 | + |
| 87 | + // Fill a buffer with a solid color. |
| 88 | + const DARK_GRAY: u32 = 0xff181818; |
| 89 | + |
| 90 | + surface |
| 91 | + .resize(width, height) |
| 92 | + .expect("Failed to resize the softbuffer surface"); |
| 93 | + |
| 94 | + let mut buffer = surface |
| 95 | + .buffer_mut() |
| 96 | + .expect("Failed to get the softbuffer buffer"); |
| 97 | + buffer.fill(DARK_GRAY); |
| 98 | + buffer |
| 99 | + .present() |
| 100 | + .expect("Failed to present the softbuffer buffer"); |
| 101 | + }) |
| 102 | + } |
| 103 | + |
| 104 | + pub fn cleanup_window(window: &Window) { |
| 105 | + GC.with(|gc| { |
| 106 | + let mut gc = gc.borrow_mut(); |
| 107 | + if let Some(context) = gc.as_mut() { |
| 108 | + context.destroy_surface(window); |
| 109 | + } |
| 110 | + }); |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +#[cfg(any(target_os = "android", target_os = "ios"))] |
| 115 | +mod platform { |
| 116 | + pub fn fill_window(_window: &winit::window::Window) { |
| 117 | + // No-op on mobile platforms. |
| 118 | + } |
| 119 | + |
| 120 | + pub fn cleanup_window(_window: &winit::window::Window) { |
| 121 | + // No-op on mobile platforms. |
| 122 | + } |
| 123 | +} |
0 commit comments