Skip to content

Commit

Permalink
Make the rest of bevy work with multiple windows
Browse files Browse the repository at this point in the history
  • Loading branch information
DJMcNab committed Jan 6, 2022
1 parent 32e1bfd commit 6e63c0b
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 44 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_input/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bevy_app::AppExit;
use bevy_ecs::prelude::{EventReader, EventWriter};

/// Sends the `AppExit` event whenever the "esc" key is pressed.
pub fn exit_on_esc_system(
pub fn exit_app_on_esc(
mut keyboard_input_events: EventReader<KeyboardInput>,
mut app_exit_events: EventWriter<AppExit>,
) {
Expand Down
74 changes: 38 additions & 36 deletions crates/bevy_pbr/src/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,45 +361,47 @@ pub fn add_clusters(

pub fn update_clusters(windows: Res<Windows>, mut views: Query<(&Camera, &mut Clusters)>) {
for (camera, mut clusters) in views.iter_mut() {
let is_orthographic = camera.projection_matrix.w_axis.w == 1.0;
let inverse_projection = camera.projection_matrix.inverse();
let window = windows.get(camera.window).unwrap();
let screen_size_u32 = UVec2::new(window.physical_width(), window.physical_height());
// Don't update clusters if screen size is 0.
if screen_size_u32.x == 0 || screen_size_u32.y == 0 {
continue;
}
*clusters =
Clusters::from_screen_size_and_z_slices(screen_size_u32, clusters.axis_slices.z);
let screen_size = screen_size_u32.as_vec2();
let tile_size_u32 = clusters.tile_size;
let tile_size = tile_size_u32.as_vec2();

// Calculate view space AABBs
// NOTE: It is important that these are iterated in a specific order
// so that we can calculate the cluster index in the fragment shader!
// I (Rob Swain) choose to scan along rows of tiles in x,y, and for each tile then scan
// along z
let mut aabbs = Vec::with_capacity(
(clusters.axis_slices.y * clusters.axis_slices.x * clusters.axis_slices.z) as usize,
);
for y in 0..clusters.axis_slices.y {
for x in 0..clusters.axis_slices.x {
for z in 0..clusters.axis_slices.z {
aabbs.push(compute_aabb_for_cluster(
camera.near,
camera.far,
tile_size,
screen_size,
inverse_projection,
is_orthographic,
clusters.axis_slices,
UVec3::new(x, y, z),
));
// If the window doesn't exist, we won't render anything to it, so don't need to calculate the clusters for it
if let Some(window) = windows.get(camera.window) {
let is_orthographic = camera.projection_matrix.w_axis.w == 1.0;
let inverse_projection = camera.projection_matrix.inverse();
let screen_size_u32 = UVec2::new(window.physical_width(), window.physical_height());
// Don't update clusters if screen size is 0.
if screen_size_u32.x == 0 || screen_size_u32.y == 0 {
continue;
}
*clusters =
Clusters::from_screen_size_and_z_slices(screen_size_u32, clusters.axis_slices.z);
let screen_size = screen_size_u32.as_vec2();
let tile_size_u32 = clusters.tile_size;
let tile_size = tile_size_u32.as_vec2();

// Calculate view space AABBs
// NOTE: It is important that these are iterated in a specific order
// so that we can calculate the cluster index in the fragment shader!
// I (Rob Swain) choose to scan along rows of tiles in x,y, and for each tile then scan
// along z
let mut aabbs = Vec::with_capacity(
(clusters.axis_slices.y * clusters.axis_slices.x * clusters.axis_slices.z) as usize,
);
for y in 0..clusters.axis_slices.y {
for x in 0..clusters.axis_slices.x {
for z in 0..clusters.axis_slices.z {
aabbs.push(compute_aabb_for_cluster(
camera.near,
camera.far,
tile_size,
screen_size,
inverse_projection,
is_orthographic,
clusters.axis_slices,
UVec3::new(x, y, z),
));
}
}
}
clusters.aabbs = aabbs;
}
clusters.aabbs = aabbs;
}
}

Expand Down
11 changes: 9 additions & 2 deletions crates/bevy_render/src/view/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
use bevy_app::{App, Plugin};
use bevy_ecs::prelude::*;
use bevy_utils::{tracing::debug, HashMap, HashSet};
use bevy_window::{RawWindowHandleWrapper, WindowId, Windows};
use bevy_window::{RawWindowHandleWrapper, WindowClosed, WindowId, Windows};
use std::ops::{Deref, DerefMut};
use wgpu::TextureFormat;

Expand Down Expand Up @@ -65,7 +65,11 @@ impl DerefMut for ExtractedWindows {
}
}

fn extract_windows(mut render_world: ResMut<RenderWorld>, windows: Res<Windows>) {
fn extract_windows(
mut render_world: ResMut<RenderWorld>,
mut closed: EventReader<WindowClosed>,
windows: Res<Windows>,
) {
let mut extracted_windows = render_world.get_resource_mut::<ExtractedWindows>().unwrap();
for window in windows.iter() {
let (new_width, new_height) = (
Expand Down Expand Up @@ -103,6 +107,9 @@ fn extract_windows(mut render_world: ResMut<RenderWorld>, windows: Res<Windows>)
extracted_window.physical_height = new_height;
}
}
for closed_window in closed.iter() {
extracted_windows.remove(&closed_window.id);
}
}

#[derive(Default)]
Expand Down
24 changes: 21 additions & 3 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use bevy_math::{ivec2, DVec2, Vec2};
use bevy_utils::tracing::{error, trace, warn};
use bevy_window::{
CreateWindow, CursorEntered, CursorLeft, CursorMoved, FileDragAndDrop, ReceivedCharacter,
WindowBackendScaleFactorChanged, WindowCloseRequested, WindowCreated, WindowFocused,
WindowMoved, WindowResized, WindowScaleFactorChanged, Windows,
WindowBackendScaleFactorChanged, WindowCloseRequested, WindowClosed, WindowCreated,
WindowFocused, WindowMoved, WindowResized, WindowScaleFactorChanged, Windows,
};
use winit::{
dpi::PhysicalPosition,
Expand All @@ -43,8 +43,9 @@ impl Plugin for WinitPlugin {

fn change_window(world: &mut World) {
let world = world.cell();
let winit_windows = world.get_resource::<WinitWindows>().unwrap();
let mut winit_windows = world.get_resource_mut::<WinitWindows>().unwrap();
let mut windows = world.get_resource_mut::<Windows>().unwrap();
let mut removed_windows = Vec::new();

for bevy_window in windows.iter_mut() {
let id = bevy_window.id();
Expand Down Expand Up @@ -159,9 +160,26 @@ fn change_window(world: &mut World) {
window.set_max_inner_size(Some(max_inner_size));
}
}
bevy_window::WindowCommand::Close => {
let window = winit_windows.remove_window(id);
// Close the window
drop(window);
// Since we borrow `windows` here to iterate through them, we can't mutate it here.
// Add it to the queue to solve this
removed_windows.push(id);
// No need to run any further commands - this drops the rest of the commands, although the `bevy_window::Window` will be dropped later anyway
break;
}
}
}
}
if !removed_windows.is_empty() {
let mut events = world.get_resource_mut::<Events<WindowClosed>>().unwrap();
for id in removed_windows {
windows.remove(id);
events.send(WindowClosed { id });
}
}
}

fn run<F>(event_loop: EventLoop<()>, event_handler: F) -> !
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_winit/src/winit_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ impl WinitWindows {
pub fn get_window_id(&self, id: winit::window::WindowId) -> Option<WindowId> {
self.winit_to_window_id.get(&id).cloned()
}

pub fn remove_window(&mut self, id: WindowId) -> Option<winit::window::Window> {
let winit_id = self.window_id_to_winit.remove(&id)?;
self.winit_to_window_id.remove(&winit_id);
self.windows.remove(&winit_id)
}
}

pub fn get_fitting_videomode(
Expand Down
5 changes: 3 additions & 2 deletions examples/window/multiple_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ use bevy::{
renderer::RenderContext,
RenderApp, RenderStage,
},
window::{CreateWindow, WindowId},
window::{close_on_esc, CreateWindow, WindowId},
};

/// This example creates a second window and draws a mesh from two different cameras, one in each window
fn main() {
let mut app = App::new();
app.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_startup_system(create_new_window);
.add_startup_system(create_new_window)
.add_system(close_on_esc);

let render_app = app.sub_app_mut(RenderApp);
render_app.add_system_to_stage(RenderStage::Extract, extract_secondary_camera_phases);
Expand Down

0 comments on commit 6e63c0b

Please sign in to comment.