From ea6118cb6fa033efdfb83abdbe164e3ff46c047b Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Tue, 7 Jun 2022 15:23:45 +0000 Subject: [PATCH] Refactor `Camera` methods and add viewport rect (#4948) While working on a refactor of `bevy_mod_picking` to include viewport-awareness, I found myself writing these functions to test if a cursor coordinate was inside the camera's rendered area. # Objective - Simplify conversion from physical to logical pixels - Add methods that returns the dimensions of the viewport as a min-max rect --- ## Changelog - Added `Camera::to_logical` - Added `Camera::physical_viewport_rect` - Added `Camera::logical_viewport_rect` --- crates/bevy_render/src/camera/camera.rs | 51 +++++++++++++++++-------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 83f2a75a0ec079..00db5f8401f734 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -104,21 +104,42 @@ impl Default for Camera { } impl Camera { + /// Converts a physical size in this `Camera` to a logical size. + #[inline] + pub fn to_logical(&self, physical_size: UVec2) -> Option { + let scale = self.computed.target_info.as_ref()?.scale_factor; + Some((physical_size.as_dvec2() / scale).as_vec2()) + } + + /// The rendered physical bounds (minimum, maximum) of the camera. If the `viewport` field is + /// set to [`Some`], this will be the rect of that custom viewport. Otherwise it will default to + /// the full physical rect of the current [`RenderTarget`]. + #[inline] + pub fn physical_viewport_rect(&self) -> Option<(UVec2, UVec2)> { + let min = self.viewport.as_ref()?.physical_position; + let max = min + self.physical_viewport_size()?; + Some((min, max)) + } + + /// The rendered logical bounds (minimum, maximum) of the camera. If the `viewport` field is set + /// to [`Some`], this will be the rect of that custom viewport. Otherwise it will default to the + /// full logical rect of the current [`RenderTarget`]. + #[inline] + pub fn logical_viewport_rect(&self) -> Option<(Vec2, Vec2)> { + let (min, max) = self.physical_viewport_rect()?; + Some((self.to_logical(min)?, self.to_logical(max)?)) + } + /// The logical size of this camera's viewport. If the `viewport` field is set to [`Some`], this - /// will be the size of that custom viewport. Otherwise it will default to the full logical size of - /// the current [`RenderTarget`]. - /// For logic that requires the full logical size of the [`RenderTarget`], prefer [`Camera::logical_target_size`]. + /// will be the size of that custom viewport. Otherwise it will default to the full logical size + /// of the current [`RenderTarget`]. + /// For logic that requires the full logical size of the + /// [`RenderTarget`], prefer [`Camera::logical_target_size`]. #[inline] pub fn logical_viewport_size(&self) -> Option { - let target_info = self.computed.target_info.as_ref()?; self.viewport .as_ref() - .map(|v| { - Vec2::new( - (v.physical_size.x as f64 / target_info.scale_factor) as f32, - (v.physical_size.y as f64 / target_info.scale_factor) as f32, - ) - }) + .and_then(|v| self.to_logical(v.physical_size)) .or_else(|| self.logical_target_size()) } @@ -139,12 +160,10 @@ impl Camera { /// For logic that requires the size of the actually rendered area, prefer [`Camera::logical_viewport_size`]. #[inline] pub fn logical_target_size(&self) -> Option { - self.computed.target_info.as_ref().map(|t| { - Vec2::new( - (t.physical_size.x as f64 / t.scale_factor) as f32, - (t.physical_size.y as f64 / t.scale_factor) as f32, - ) - }) + self.computed + .target_info + .as_ref() + .and_then(|t| self.to_logical(t.physical_size)) } /// The full physical size of this camera's [`RenderTarget`], ignoring custom `viewport` configuration.