diff --git a/Cargo.lock b/Cargo.lock index fe2f223..34f09c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,8 +124,7 @@ checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" [[package]] name = "appit" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ed795976c3816aeceb52f1971d3e27f5403d58b16531edea7fe97f63e75f08" +source = "git+https://github.com/khonsulabs/appit#c985e024fc090e5764ff41b06d9dcc76ed5aedef" dependencies = [ "winit", ] @@ -1312,8 +1311,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "kludgine" version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ee58ce44762ccebb879d0df90c736336f6230e633702c7a24643dff1fca25c" +source = "git+https://github.com/khonsulabs/kludgine#eccacdaffe4a60d1887a201a68656f0058a12088" dependencies = [ "ahash", "alot", diff --git a/Cargo.toml b/Cargo.toml index 7d5480d..c7849e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,9 @@ tokio-multi-thread = ["tokio", "tokio/rt-multi-thread"] serde = ["dep:serde", "figures/serde"] [dependencies] -kludgine = { version = "0.11.0", features = ["app"] } +kludgine = { git = "https://github.com/khonsulabs/kludgine", features = [ + "app", +] } figures = { version = "0.4.0" } alot = "0.3" interner = "0.2.1" diff --git a/src/window.rs b/src/window.rs index 2e1b44d..3977b41 100644 --- a/src/window.rs +++ b/src/window.rs @@ -32,7 +32,7 @@ use kludgine::app::winit::keyboard::{ Key, KeyLocation, ModifiersState, NamedKey, NativeKeyCode, PhysicalKey, SmolStr, }; use kludgine::app::winit::window::{self, Cursor, Fullscreen, Icon, WindowButtons, WindowLevel}; -use kludgine::app::{winit, WindowAttributes, WindowBehavior as _}; +use kludgine::app::{winit, Resized, WindowAttributes, WindowBehavior as _}; use kludgine::cosmic_text::{fontdb, Family, FamilyOwned}; use kludgine::drawing::Drawing; use kludgine::shapes::Shape; @@ -1771,7 +1771,9 @@ where }; this.synchronize_platform_window(&mut window); - this.prepare(window, graphics); + + // Perform an initial layout. + let _result = this.prepare(window, graphics); this } @@ -1795,7 +1797,11 @@ where .new_frame(self.redraw_status.invalidations().drain()); } - fn prepare(&mut self, mut window: W, graphics: &mut kludgine::Graphics<'_>) + fn prepare( + &mut self, + mut window: W, + graphics: &mut kludgine::Graphics<'_>, + ) -> Result<(), Resized> where W: PlatformWindowImplementation, { @@ -1884,6 +1890,8 @@ where if let Some(new_size) = new_size { self.inner_size.set_and_read(new_size); self.outer_size.set(layout_context.window().outer_size()); + self.root.invalidate(); + return Err(Resized); } self.root.set_layout(Rect::from(render_size.into_signed())); @@ -1904,6 +1912,7 @@ where } else { layout_context.redraw(); } + Ok(()) } fn close_requested(&mut self, window: W, kludgine: &mut Kludgine) -> bool @@ -2487,8 +2496,8 @@ where &mut self, window: kludgine::app::Window<'_, WindowCommand>, graphics: &mut kludgine::Graphics<'_>, - ) { - self.prepare(window, graphics); + ) -> Result<(), Resized> { + self.prepare(window, graphics) } fn present_mode(&self) -> wgpu::PresentMode { @@ -3654,14 +3663,25 @@ pub struct CushyWindow { impl CushyWindow { /// Prepares all necessary resources and operations necessary to render the /// next frame. - pub fn prepare(&mut self, window: W, device: &wgpu::Device, queue: &wgpu::Queue) + /// + /// # Errors + /// + /// If during the preparation of rendering, the window is resized, + /// `Err(Resized)` is returned and Cushy will immediately resize the + /// graphics context and begin rendering again. + pub fn prepare( + &mut self, + window: W, + device: &wgpu::Device, + queue: &wgpu::Queue, + ) -> Result<(), Resized> where W: PlatformWindowImplementation, { self.window.prepare( window, &mut kludgine::Graphics::new(&mut self.kludgine, device, queue), - ); + ) } /// Renders this window in a wgpu render pass created from `pass`. @@ -3884,7 +3904,13 @@ pub struct VirtualWindow { impl VirtualWindow { /// Prepares all necessary resources and operations necessary to render the /// next frame. - pub fn prepare(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) { + /// + /// # Errors + /// + /// If during the preparation of rendering, the window is resized, + /// `Err(Resized)` is returned and Cushy will immediately resize the + /// graphics context and begin rendering again. + pub fn prepare(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) -> Result<(), Resized> { let now = Instant::now(); self.state.elapsed = self .last_rendered_at @@ -3892,7 +3918,7 @@ impl VirtualWindow { .unwrap_or_default(); self.last_rendered_at = Some(now); self.state.dynamic.redraw_target.set(RedrawTarget::Never); - self.cushy.prepare(&mut self.state, device, queue); + self.cushy.prepare(&mut self.state, device, queue) } /// Renders this window in a wgpu render pass created from `pass`. @@ -4466,50 +4492,55 @@ where } fn redraw(&mut self) { - let mut render_size = self.window.size().ceil(); - if self.window.state.size != render_size { - let current_scale = self.window.dpi_scale(); - self.window - .resize(self.window.state.size, current_scale, &self.queue); - render_size = self.window.state.size; - } - let bytes_per_row = copy_buffer_aligned_bytes_per_row(render_size.width.get() * 4); - let size = u64::from(bytes_per_row) * u64::from(render_size.height.get()); - self.recreate_buffers_if_needed(render_size, size, bytes_per_row); + loop { + let mut render_size = self.window.size().ceil(); + if self.window.state.size != render_size { + let current_scale = self.window.dpi_scale(); + self.window + .resize(self.window.state.size, current_scale, &self.queue); + render_size = self.window.state.size; + } + let bytes_per_row = copy_buffer_aligned_bytes_per_row(render_size.width.get() * 4); + let size = u64::from(bytes_per_row) * u64::from(render_size.height.get()); + self.recreate_buffers_if_needed(render_size, size, bytes_per_row); - let capture = self.capture.as_ref().assert("always initialized above"); + let capture = self.capture.as_ref().assert("always initialized above"); - if self.cursor_visible { - let mut gfx = self.window.graphics(&self.device, &self.queue); - let mut frame = self.cursor_graphic.new_frame(&mut gfx); - frame.draw_shape( - Shape::filled_circle(Px::new(4), Color::WHITE, Origin::Center) - .translate_by(self.cursor.get()), + if self.cursor_visible { + let mut gfx = self.window.graphics(&self.device, &self.queue); + let mut frame = self.cursor_graphic.new_frame(&mut gfx); + frame.draw_shape( + Shape::filled_circle(Px::new(4), Color::WHITE, Origin::Center) + .translate_by(self.cursor.get()), + ); + drop(frame); + } + + if let Err(Resized) = self.window.prepare(&self.device, &self.queue) { + continue; + } + + self.window.render_with( + &wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: capture.multisample.view(), + resolve_target: Some(capture.texture.view()), + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(Color::CLEAR_BLACK.into()), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }, + &self.device, + &self.queue, + self.cursor_visible.then_some(&self.cursor_graphic), ); - drop(frame); + return; } - - self.window.prepare(&self.device, &self.queue); - - self.window.render_with( - &wgpu::RenderPassDescriptor { - label: None, - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: capture.multisample.view(), - resolve_target: Some(capture.texture.view()), - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(Color::CLEAR_BLACK.into()), - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - timestamp_writes: None, - occlusion_query_set: None, - }, - &self.device, - &self.queue, - self.cursor_visible.then_some(&self.cursor_graphic), - ); } /// Redraws the contents.