diff --git a/Cargo.toml b/Cargo.toml index 85dc5c30d4..dc68fbd242 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ tracing = { version = "0.1.40", default-features = false } # Dev dependencies. image = { version = "0.25.0", default-features = false } -softbuffer = { version = "0.4.6", default-features = false, features = [ +softbuffer = { git = "https://github.com/rust-windowing/softbuffer", branch = "master", default-features = false, features = [ "x11", "x11-dlopen", "wayland", diff --git a/winit/examples/application.rs b/winit/examples/application.rs index bc8d7dee69..475af8e565 100644 --- a/winit/examples/application.rs +++ b/winit/examples/application.rs @@ -964,32 +964,36 @@ impl WindowState { return Ok(()); } - let mut buffer = self.surface.buffer_mut()?; + let mut buffer = self.surface.next_buffer()?; // Draw a different color inside the safe area let surface_size = self.window.surface_size(); let insets = self.window.safe_area(); - for y in 0..surface_size.height { - for x in 0..surface_size.width { - let index = y as usize * surface_size.width as usize + x as usize; - if insets.left <= x - && x <= (surface_size.width - insets.right) - && insets.top <= y - && y <= (surface_size.height - insets.bottom) - { - // In safe area - buffer[index] = match self.theme { - Theme::Light => 0xffe8e8e8, // Light gray - Theme::Dark => 0xff525252, // Medium gray - }; - } else { - // Outside safe area - buffer[index] = match self.theme { - Theme::Light => 0xffffffff, // White - Theme::Dark => 0xff181818, // Dark gray - }; + for (x, y, pixel) in buffer.pixels_iter() { + let is_inside_safe_area = insets.left <= x + && x <= (surface_size.width - insets.right) + && insets.top <= y + && y <= (surface_size.height - insets.bottom); + + let color: u32 = if is_inside_safe_area { + // In safe area + match self.theme { + Theme::Light => 0xffe8e8e8, // Light gray + Theme::Dark => 0xff525252, // Medium gray } - } + } else { + // Outside safe area + match self.theme { + Theme::Light => 0xffffffff, // White + Theme::Dark => 0xff181818, // Dark gray + } + }; + + let red = ((color >> 16) & 0xff) as u8; + let green = ((color >> 8) & 0xff) as u8; + let blue = (color & 0xff) as u8; + + *pixel = softbuffer::Pixel::new_rgb(red, green, blue); } // Present the buffer diff --git a/winit/examples/util/fill.rs b/winit/examples/util/fill.rs index 0b1a4fb06a..ad9b488eb9 100644 --- a/winit/examples/util/fill.rs +++ b/winit/examples/util/fill.rs @@ -97,8 +97,15 @@ mod platform { surface.resize(width, height).expect("Failed to resize the softbuffer surface"); - let mut buffer = surface.buffer_mut().expect("Failed to get the softbuffer buffer"); - buffer.fill(color); + let mut buffer = surface.next_buffer().expect("Failed to get the softbuffer buffer"); + + for (_, _, pixel) in buffer.pixels_iter() { + let red = ((color >> 16) & 0xff) as u8; + let green = ((color >> 8) & 0xff) as u8; + let blue = (color & 0xff) as u8; + + *pixel = softbuffer::Pixel::new_rgb(red, green, blue); + } buffer.present().expect("Failed to present the softbuffer buffer"); }) } diff --git a/winit/examples/win_with_soft.rs b/winit/examples/win_with_soft.rs new file mode 100644 index 0000000000..167a1a8210 --- /dev/null +++ b/winit/examples/win_with_soft.rs @@ -0,0 +1,104 @@ +#![cfg(not(target_os = "android"))] + +use std::error::Error; +use std::num::NonZeroU32; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +use softbuffer::{Context, Surface}; +use winit::application::ApplicationHandler; +use winit::event::WindowEvent; +use winit::event_loop::{ActiveEventLoop, EventLoop}; +use winit::window::{Window, WindowAttributes, WindowId}; + +struct App { + window: Option>, + surface: Option, Arc>>, + frame_count: u32, + last_fps_print: Instant, +} + +impl App { + fn new() -> Self { + Self { window: None, surface: None, frame_count: 0, last_fps_print: Instant::now() } + } +} + +impl ApplicationHandler for App { + fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { + let attributes = WindowAttributes::default().with_title("framebuffer test"); + let window: Arc = Arc::from(event_loop.create_window(attributes).unwrap()); + + let context = Context::new(window.clone()).expect("context except"); + let surface = Surface::new(&context, window.clone()).expect("surface except"); + + self.window = Some(window); + self.surface = Some(surface); + } + + fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) { + if let Some(window) = self.window.as_ref() { + window.request_redraw(); + } + } + + fn window_event( + &mut self, + event_loop: &dyn ActiveEventLoop, + _id: WindowId, + event: WindowEvent, + ) { + match event { + WindowEvent::CloseRequested => event_loop.exit(), + + WindowEvent::SurfaceResized(size) => { + if let Some(surface) = self.surface.as_mut() { + let w = NonZeroU32::new(size.width.max(1)).unwrap(); + let h = NonZeroU32::new(size.height.max(1)).unwrap(); + surface.resize(w, h).unwrap(); + } + }, + + WindowEvent::RedrawRequested => { + if let Some(surface) = self.surface.as_mut() { + let mut buffer = surface.next_buffer().expect("buffer except"); + + for (x, y, pixel) in buffer.pixels_iter() { + let red = (x % 255) as u8; + let green = (y % 255) as u8; + let blue = ((x * y) % 255) as u8; + + *pixel = softbuffer::Pixel::new_rgb(red, green, blue); + } + + buffer.present().unwrap(); + + let now = Instant::now(); + self.frame_count += 1; + + if now.duration_since(self.last_fps_print) >= Duration::from_secs(1) { + let fps = self.frame_count; + println!("FPS: {}", fps); + + self.frame_count = 0; + self.last_fps_print = now; + } + } + }, + _ => (), + } + } +} + +fn main() -> Result<(), Box> { + let event_loop = EventLoop::new()?; + + let app = Box::leak(Box::new(App::new())); + + event_loop.run_app(app)?; + + Ok(()) +} + +#[cfg(target_os = "android")] +fn main() {} diff --git a/winit/examples/win_with_soft_2.rs b/winit/examples/win_with_soft_2.rs new file mode 100644 index 0000000000..94447d09e6 --- /dev/null +++ b/winit/examples/win_with_soft_2.rs @@ -0,0 +1,120 @@ +#![cfg(not(target_os = "android"))] + +use std::error::Error; +use std::num::NonZeroU32; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +use softbuffer::{Context, Pixel, Surface}; +use winit::application::ApplicationHandler; +use winit::event::WindowEvent; +use winit::event_loop::{ActiveEventLoop, EventLoop}; +use winit::window::{Window, WindowAttributes, WindowId}; + +struct App { + window: Option>, + surface: Option, Arc>>, + start_time: Instant, + frame_count: u32, + last_fps_print: Instant, + total_frame_count: u64, +} + +impl ApplicationHandler for App { + fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { + let window: Arc = + Arc::from(event_loop.create_window(WindowAttributes::default()).unwrap()); + self.surface = + Some(Surface::new(&Context::new(window.clone()).unwrap(), window.clone()).unwrap()); + self.window = Some(window); + } + + fn about_to_wait(&mut self, _: &dyn ActiveEventLoop) { + if let Some(w) = self.window.as_ref() { + w.request_redraw(); + } + } + + fn window_event( + &mut self, + event_loop: &dyn ActiveEventLoop, + _id: WindowId, + event: WindowEvent, + ) { + match event { + WindowEvent::CloseRequested => event_loop.exit(), + WindowEvent::SurfaceResized(size) => { + if let Some(s) = self.surface.as_mut() { + s.resize( + NonZeroU32::new(size.width.max(1)).unwrap(), + NonZeroU32::new(size.height.max(1)).unwrap(), + ) + .unwrap(); + } + }, + WindowEvent::RedrawRequested => { + if let (Some(window), Some(surface)) = (&self.window, self.surface.as_mut()) { + let mut buffer = surface.next_buffer().unwrap(); + let size = window.outer_size(); + let elapsed = self.start_time.elapsed(); + let t = elapsed.as_secs_f32(); + let total_secs = elapsed.as_secs(); + + let ball_x = ((t * 1.5).sin() * 0.5 + 0.5) * size.width as f32; + let ball_y = ((t * 2.1).cos() * 0.5 + 0.5) * size.height as f32; + + for (x, y, pixel) in buffer.pixels_iter() { + let dx = x as f32 - ball_x; + let dy = y as f32 - ball_y; + let dist = (dx * dx + dy * dy).sqrt(); + + let p1 = (x as f32 * 0.01 + t).sin(); + let p2 = (y as f32 * 0.01 + t * 0.5).cos(); + let p3 = ((x as f32 + y as f32) * 0.005 + t).sin(); + let plasma = (p1 + p2 + p3) * 0.33; + + if dist < 50.0 { + *pixel = Pixel::new_rgb(255, 255, 255); + } else if (y as f32 + t * 50.0) % 20.0 < 2.0 { + *pixel = Pixel::new_rgb(0, 0, 0); + } else { + let r = ((plasma + 1.0) * 127.0) as u8; + let g = (x % 255) as u8; + let b = (y % 255).wrapping_add((t * 20.0) as u32) as u8; + *pixel = Pixel::new_rgb(r, g, b); + } + } + buffer.present().unwrap(); + + self.frame_count += 1; + self.total_frame_count += 1; + if self.last_fps_print.elapsed() >= Duration::from_secs(1) { + let avg = self.total_frame_count as f64 / elapsed.as_secs_f64(); + window.set_title(&format!( + "FPS: {} | AVG: {:.2} | TIME: {}s | {}x{}", + self.frame_count, avg, total_secs, size.width, size.height + )); + self.frame_count = 0; + self.last_fps_print = Instant::now(); + } + } + }, + _ => (), + } + } +} + +fn main() -> Result<(), Box> { + let app = App { + window: None, + surface: None, + start_time: Instant::now(), + frame_count: 0, + last_fps_print: Instant::now(), + total_frame_count: 0, + }; + EventLoop::new()?.run_app(app).map_err(Into::into) +} + +#[cfg(target_os = "android")] +fn main() {}