Skip to content

Commit

Permalink
Make ScalingMode more flexible (bevyengine#3253)
Browse files Browse the repository at this point in the history
Adds ability to specify scaling factor for `WindowSize`, size of the fixed axis for `FixedVertical` and `FixedHorizontal` and a new `ScalingMode` that is a mix of `FixedVertical` and `FixedHorizontal`

# The issue

Currently, only available options are to:

* Have one of the axes fixed to value 1
* Have viewport size match the window size
* Manually adjust viewport size

In most of the games these options are not enough and more advanced scaling methods have to be used

## Solution

The solution is to provide additional parameters to current scaling modes, like scaling factor for `WindowSize`. Additionally, a more advanced `Auto` mode is added, which dynamically switches between behaving like `FixedVertical` and `FixedHorizontal` depending on the window's aspect ratio.

Co-authored-by: Daniikk1012 <[email protected]>
  • Loading branch information
2 people authored and ItsDoot committed Feb 1, 2023
1 parent aa13bfd commit 3ec7f2a
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 44 deletions.
4 changes: 2 additions & 2 deletions crates/bevy_gltf/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,8 +716,8 @@ fn load_node(
let orthographic_projection: OrthographicProjection = OrthographicProjection {
far: orthographic.zfar(),
near: orthographic.znear(),
scaling_mode: ScalingMode::FixedHorizontal,
scale: xmag / 2.0,
scaling_mode: ScalingMode::FixedHorizontal(1.0),
scale: xmag,
..Default::default()
};

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_render/src/camera/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub struct OrthographicCameraBundle<M: Component> {
impl OrthographicCameraBundle<Camera3d> {
pub fn new_3d() -> Self {
let orthographic_projection = OrthographicProjection {
scaling_mode: ScalingMode::FixedVertical,
scaling_mode: ScalingMode::FixedVertical(2.0),
depth_calculation: DepthCalculation::Distance,
..Default::default()
};
Expand Down
86 changes: 45 additions & 41 deletions crates/bevy_render/src/camera/projection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,15 @@ pub enum ScalingMode {
None,
/// Match the window size. 1 world unit = 1 pixel.
WindowSize,
/// Use minimal possible viewport size while keeping the aspect ratio.
/// Arguments are in world units.
Auto { min_width: f32, min_height: f32 },
/// Keep vertical axis constant; resize horizontal with aspect ratio.
FixedVertical,
/// The argument is the desired height of the viewport in world units.
FixedVertical(f32),
/// Keep horizontal axis constant; resize vertical with aspect ratio.
FixedHorizontal,
/// The argument is the desired width of the viewport in world units.
FixedHorizontal(f32),
}

#[derive(Component, Debug, Clone, Reflect)]
Expand Down Expand Up @@ -102,52 +107,51 @@ impl CameraProjection for OrthographicProjection {
}

fn update(&mut self, width: f32, height: f32) {
match (&self.scaling_mode, &self.window_origin) {
(ScalingMode::WindowSize, WindowOrigin::Center) => {
let half_width = (width / 2.0).round();
let half_height = (height / 2.0).round();
// Assign left and bottom such that (right-left)==width and (top-bottom)==height
// still hold with with rounded half_width and half_height
self.left = half_width - width;
self.right = half_width;
self.top = half_height;
self.bottom = half_height - height;
let (viewport_width, viewport_height) = match self.scaling_mode {
ScalingMode::WindowSize => (width, height),
ScalingMode::Auto {
min_width,
min_height,
} => {
if width * min_height > min_width * height {
(width * min_height / height, min_height)
} else {
(min_width, height * min_width / width)
}
}
(ScalingMode::WindowSize, WindowOrigin::BottomLeft) => {
self.left = 0.0;
self.right = width;
self.top = height;
self.bottom = 0.0;
ScalingMode::FixedVertical(viewport_height) => {
(width * viewport_height / height, viewport_height)
}
(ScalingMode::FixedVertical, WindowOrigin::Center) => {
let aspect_ratio = width / height;
self.left = -aspect_ratio;
self.right = aspect_ratio;
self.top = 1.0;
self.bottom = -1.0;
ScalingMode::FixedHorizontal(viewport_width) => {
(viewport_width, height * viewport_width / width)
}
(ScalingMode::FixedVertical, WindowOrigin::BottomLeft) => {
let aspect_ratio = width / height;
self.left = 0.0;
self.right = aspect_ratio;
self.top = 1.0;
self.bottom = 0.0;
}
(ScalingMode::FixedHorizontal, WindowOrigin::Center) => {
let aspect_ratio = height / width;
self.left = -1.0;
self.right = 1.0;
self.top = aspect_ratio;
self.bottom = -aspect_ratio;
ScalingMode::None => return,
};

match self.window_origin {
WindowOrigin::Center => {
let half_width = viewport_width / 2.0;
let half_height = viewport_height / 2.0;
self.left = -half_width;
self.bottom = -half_height;
self.right = half_width;
self.top = half_height;

if let ScalingMode::WindowSize = self.scaling_mode {
if self.scale == 1.0 {
self.left = self.left.floor();
self.bottom = self.bottom.floor();
self.right = self.right.floor();
self.top = self.top.floor();
}
}
}
(ScalingMode::FixedHorizontal, WindowOrigin::BottomLeft) => {
let aspect_ratio = height / width;
WindowOrigin::BottomLeft => {
self.left = 0.0;
self.right = 1.0;
self.top = aspect_ratio;
self.bottom = 0.0;
self.right = viewport_width;
self.top = viewport_height;
}
(ScalingMode::None, _) => {}
}
}

Expand Down

0 comments on commit 3ec7f2a

Please sign in to comment.