#![allow(
clippy::needless_question_mark,
clippy::too_many_arguments,
clippy::type_complexity,
clippy::module_inception,
clippy::single_match,
clippy::match_like_matches_macro
)]
mod converters;
mod pipeline_sync_data;
mod vulkano_windows;
use bevy::{
app::{App, AppExit, CoreStage, Plugin},
ecs::event::{Events, ManualEventReader},
input::{
keyboard::KeyboardInput,
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
touch::TouchInput,
},
math::{ivec2, DVec2, Vec2},
prelude::*,
window::{
CreateWindow, CursorEntered, CursorLeft, CursorMoved, FileDragAndDrop, ModifiesWindows,
ReceivedCharacter, WindowBackendScaleFactorChanged, WindowCloseRequested, WindowClosed,
WindowCreated, WindowFocused, WindowId, WindowMoved, WindowResized,
WindowScaleFactorChanged, Windows,
},
};
#[cfg(feature = "gui")]
pub use egui_winit_vulkano;
pub use pipeline_sync_data::*;
use vulkano_util::context::{VulkanoConfig, VulkanoContext};
pub use vulkano_windows::*;
use winit::{
dpi::{LogicalSize, PhysicalPosition},
event::{self, DeviceEvent, Event, WindowEvent},
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
window::CursorGrabMode,
};
pub struct VulkanoWinitConfig {
pub return_from_run: bool,
pub vulkano_config: VulkanoConfig,
pub is_gui_overlay: bool,
pub add_primary_window: bool,
}
impl Default for VulkanoWinitConfig {
fn default() -> Self {
VulkanoWinitConfig {
return_from_run: false,
vulkano_config: VulkanoConfig::default(),
is_gui_overlay: true,
add_primary_window: true,
}
}
}
#[derive(Resource)]
pub struct BevyVulkanoContext {
pub context: VulkanoContext,
}
#[derive(Default)]
pub struct VulkanoWinitPlugin {
pub window_descriptor: WindowDescriptor,
}
impl Plugin for VulkanoWinitPlugin {
fn build(&self, app: &mut App) {
let event_loop = EventLoop::new();
let config = if app
.world
.get_non_send_resource::<VulkanoWinitConfig>()
.is_none()
{
VulkanoWinitConfig::default()
} else {
app.world
.remove_non_send_resource::<VulkanoWinitConfig>()
.unwrap()
};
let VulkanoWinitConfig {
vulkano_config, ..
} = config;
let vulkano_context = VulkanoContext::new(vulkano_config);
let new_config = VulkanoWinitConfig {
vulkano_config: VulkanoConfig::default(),
..config
};
app.insert_non_send_resource(new_config);
let window_plugin = bevy::window::WindowPlugin {
exit_on_all_closed: false,
add_primary_window: config.add_primary_window,
window: self.window_descriptor.clone(),
..default()
};
app.add_plugin(window_plugin)
.init_non_send_resource::<BevyVulkanoWindows>()
.init_resource::<PipelineSyncData>()
.insert_resource(BevyVulkanoContext {
context: vulkano_context,
});
handle_initial_window_events(&mut app.world, &event_loop);
app.insert_non_send_resource(event_loop)
.set_runner(winit_runner)
.add_system_to_stage(CoreStage::PreUpdate, update_on_resize_system)
.add_system_to_stage(CoreStage::PreUpdate, exit_on_window_close_system)
.add_system_to_stage(CoreStage::PostUpdate, change_window.label(ModifiesWindows));
#[cfg(feature = "gui")]
{
app.add_system_to_stage(CoreStage::PreUpdate, begin_egui_frame_system);
}
}
}
fn update_on_resize_system(
mut pipeline_data: ResMut<PipelineSyncData>,
mut windows: NonSendMut<BevyVulkanoWindows>,
mut window_resized_events: EventReader<WindowResized>,
mut window_created_events: EventReader<WindowCreated>,
) {
let mut changed_window_ids = Vec::new();
for event in window_resized_events.iter().rev() {
if changed_window_ids.contains(&event.id) {
continue;
}
changed_window_ids.push(event.id);
}
for event in window_created_events.iter().rev() {
if changed_window_ids.contains(&event.id) {
continue;
}
changed_window_ids.push(event.id);
}
for id in changed_window_ids {
#[cfg(not(feature = "gui"))]
if let Some(window_renderer) = windows.get_window_renderer_mut(id) {
window_renderer.resize();
pipeline_data.add(SyncData {
window_id: id,
before: None,
after: None,
});
}
#[cfg(feature = "gui")]
if let Some((window_renderer, _)) = windows.get_window_renderer_mut(id) {
window_renderer.resize();
pipeline_data.add(SyncData {
window_id: id,
before: None,
after: None,
});
}
}
}
fn change_window(world: &mut World) {
let world = world.cell();
let mut vulkano_winit_windows = world
.get_non_send_resource_mut::<BevyVulkanoWindows>()
.unwrap();
let mut pipeline_sync_data = world
.get_non_send_resource_mut::<PipelineSyncData>()
.unwrap();
let mut windows = world.get_resource_mut::<Windows>().unwrap();
let mut removed_windows = vec![];
for bevy_window in windows.iter_mut() {
let id = bevy_window.id();
for command in bevy_window.drain_commands() {
match command {
bevy::window::WindowCommand::SetWindowMode {
mode,
resolution,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
match mode {
bevy::window::WindowMode::BorderlessFullscreen => {
window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(None)))
}
bevy::window::WindowMode::Fullscreen => {
window.set_fullscreen(Some(winit::window::Fullscreen::Exclusive(
get_best_videomode(&window.current_monitor().unwrap()),
)))
}
bevy::window::WindowMode::SizedFullscreen => window.set_fullscreen(Some(
winit::window::Fullscreen::Exclusive(get_fitting_videomode(
&window.current_monitor().unwrap(),
resolution.x,
resolution.y,
)),
)),
bevy::window::WindowMode::Windowed => window.set_fullscreen(None),
}
}
bevy::window::WindowCommand::SetTitle {
title,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window.set_title(&title);
}
bevy::window::WindowCommand::SetScaleFactor {
scale_factor,
} => {
let mut window_dpi_changed_events = world
.get_resource_mut::<Events<WindowScaleFactorChanged>>()
.unwrap();
window_dpi_changed_events.send(WindowScaleFactorChanged {
id,
scale_factor,
});
}
bevy::window::WindowCommand::SetResolution {
logical_resolution,
scale_factor,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window.set_inner_size(
winit::dpi::LogicalSize::new(logical_resolution.x, logical_resolution.y)
.to_physical::<f64>(scale_factor),
);
}
bevy::window::WindowCommand::SetPresentMode {
present_mode,
} => {
let present_mode = match present_mode {
bevy::window::PresentMode::AutoVsync => {
vulkano::swapchain::PresentMode::FifoRelaxed
}
bevy::window::PresentMode::AutoNoVsync => {
vulkano::swapchain::PresentMode::Immediate
}
bevy::window::PresentMode::Fifo => vulkano::swapchain::PresentMode::Fifo,
bevy::window::PresentMode::Immediate => {
vulkano::swapchain::PresentMode::Immediate
}
bevy::window::PresentMode::Mailbox => {
vulkano::swapchain::PresentMode::Mailbox
}
};
let wr = {
#[cfg(not(feature = "gui"))]
let wr = vulkano_winit_windows.get_window_renderer_mut(id).unwrap();
#[cfg(feature = "gui")]
let (wr, _) = vulkano_winit_windows.get_window_renderer_mut(id).unwrap();
wr
};
wr.set_present_mode(present_mode);
}
bevy::window::WindowCommand::SetResizable {
resizable,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window.set_resizable(resizable);
}
bevy::window::WindowCommand::SetDecorations {
decorations,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window.set_decorations(decorations);
}
bevy::window::WindowCommand::SetCursorIcon {
icon,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window.set_cursor_icon(converters::convert_cursor_icon(icon));
}
bevy::window::WindowCommand::SetCursorGrabMode {
grab_mode,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window
.set_cursor_grab(match grab_mode {
bevy::window::CursorGrabMode::Confined => CursorGrabMode::Confined,
bevy::window::CursorGrabMode::Locked => CursorGrabMode::Locked,
bevy::window::CursorGrabMode::None => CursorGrabMode::None,
})
.unwrap_or_else(|e| error!("Unable to un/grab cursor: {}", e));
}
bevy::window::WindowCommand::SetCursorVisibility {
visible,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window.set_cursor_visible(visible);
}
bevy::window::WindowCommand::SetCursorPosition {
position,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
let inner_size = window.inner_size().to_logical::<f32>(window.scale_factor());
window
.set_cursor_position(winit::dpi::LogicalPosition::new(
position.x,
inner_size.height - position.y,
))
.unwrap_or_else(|e| error!("Unable to set cursor position: {}", e));
}
bevy::window::WindowCommand::SetMaximized {
maximized,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window.set_maximized(maximized)
}
bevy::window::WindowCommand::SetMinimized {
minimized,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window.set_minimized(minimized)
}
bevy::window::WindowCommand::SetPosition {
monitor_selection: _,
position,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
window.set_outer_position(PhysicalPosition {
x: position[0],
y: position[1],
});
}
bevy::window::WindowCommand::Center(monitor_selection) => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
let maybe_monitor = match monitor_selection {
bevy::window::MonitorSelection::Current => window.current_monitor(),
bevy::window::MonitorSelection::Primary => window.primary_monitor(),
bevy::window::MonitorSelection::Index(n) => {
window.available_monitors().nth(n)
}
};
if let Some(monitor) = maybe_monitor {
let screen_size = monitor.size();
let window_size = window.outer_size();
window.set_outer_position(PhysicalPosition {
x: screen_size.width.saturating_sub(window_size.width) as f64 / 2.
+ monitor.position().x as f64,
y: screen_size.height.saturating_sub(window_size.height) as f64 / 2.
+ monitor.position().y as f64,
});
} else {
warn!("Couldn't get monitor selected with: {monitor_selection:?}");
}
}
bevy::window::WindowCommand::SetResizeConstraints {
resize_constraints,
} => {
let window = vulkano_winit_windows.get_winit_window(id).unwrap();
let constraints = resize_constraints.check_constraints();
let min_inner_size = LogicalSize {
width: constraints.min_width,
height: constraints.min_height,
};
let max_inner_size = LogicalSize {
width: constraints.max_width,
height: constraints.max_height,
};
window.set_min_inner_size(Some(min_inner_size));
if constraints.max_width.is_finite() && constraints.max_height.is_finite() {
window.set_max_inner_size(Some(max_inner_size));
}
}
bevy::window::WindowCommand::Close => {
removed_windows.push(id);
break;
}
}
}
}
if !removed_windows.is_empty() {
let mut app_exit_events = world.resource_mut::<Events<AppExit>>();
let mut window_close_events = world.resource_mut::<Events<WindowClosed>>();
for id in removed_windows {
let (app_close, window_close) =
close_window(id, &mut vulkano_winit_windows, &mut pipeline_sync_data);
if app_close {
app_exit_events.send(AppExit);
} else if window_close {
window_close_events.send(WindowClosed {
id,
})
}
}
}
}
fn run<F>(event_loop: EventLoop<()>, event_handler: F) -> !
where
F: 'static + FnMut(Event<'_, ()>, &EventLoopWindowTarget<()>, &mut ControlFlow),
{
event_loop.run(event_handler)
}
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
fn run_return<F>(event_loop: &mut EventLoop<()>, event_handler: F) -> i32
where
F: FnMut(Event<'_, ()>, &EventLoopWindowTarget<()>, &mut ControlFlow),
{
use winit::platform::run_return::EventLoopExtRunReturn;
event_loop.run_return(event_handler)
}
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)))]
fn run_return<F>(_event_loop: &mut EventLoop<()>, _event_handler: F)
where
F: FnMut(Event<'_, ()>, &EventLoopWindowTarget<()>, &mut ControlFlow),
{
panic!("Run return is not supported on this platform!")
}
pub fn winit_runner(app: App) {
winit_runner_with(app);
}
pub fn winit_runner_with(mut app: App) {
let mut event_loop = app
.world
.remove_non_send_resource::<EventLoop<()>>()
.unwrap();
let mut create_window_event_reader = ManualEventReader::<CreateWindow>::default();
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
app.world
.insert_non_send_resource(event_loop.create_proxy());
trace!("Entering winit event loop");
let should_return_from_run = app
.world
.get_non_send_resource::<VulkanoWinitConfig>()
.map_or(false, |config| config.return_from_run);
let mut active = true;
let event_handler = move |event: Event<()>,
event_loop: &EventLoopWindowTarget<()>,
control_flow: &mut ControlFlow| {
*control_flow = ControlFlow::Poll;
if let Some(app_exit_events) = app.world.get_resource_mut::<Events<AppExit>>() {
if app_exit_event_reader
.iter(&app_exit_events)
.next_back()
.is_some()
{
*control_flow = ControlFlow::Exit;
}
}
#[cfg(feature = "gui")]
let mut skip_window_event = false;
#[cfg(not(feature = "gui"))]
let skip_window_event = false;
#[cfg(feature = "gui")]
{
match &event {
event::Event::WindowEvent {
event: window_event,
window_id: winit_window_id,
..
} => {
let world = app.world.cell();
let mut vulkano_winit_windows = world
.get_non_send_resource_mut::<BevyVulkanoWindows>()
.unwrap();
let window_id = if let Some(window_id) =
vulkano_winit_windows.get_window_id(*winit_window_id)
{
window_id
} else {
return;
};
if let Some((_, gui)) = vulkano_winit_windows.get_window_renderer_mut(window_id)
{
skip_window_event = gui.update(window_event);
}
}
_ => (),
}
}
match &event {
event::Event::WindowEvent {
event,
window_id: winit_window_id,
..
} => {
let world = app.world.cell();
let vulkano_winit_windows =
world.get_non_send_resource::<BevyVulkanoWindows>().unwrap();
let mut windows = world.get_resource_mut::<Windows>().unwrap();
let window_id = if let Some(window_id) =
vulkano_winit_windows.get_window_id(*winit_window_id)
{
window_id
} else {
warn!(
"Skipped event for unknown winit Window Id {:?}",
winit_window_id
);
return;
};
let window = if let Some(window) = windows.get_mut(window_id) {
window
} else {
warn!("Skipped event for unknown Window Id {:?}", winit_window_id);
return;
};
match event {
WindowEvent::Touch(touch) => {
let mut touch_input_events =
world.get_resource_mut::<Events<TouchInput>>().unwrap();
let mut location = touch.location.to_logical(window.scale_factor());
if cfg!(target_os = "android") || cfg!(target_os = "ios") {
let window_height = windows.get_primary().unwrap().height();
location.y = window_height - location.y;
}
let mut touch = converters::convert_touch_input(*touch, location);
if cfg!(feature = "gui") && skip_window_event {
touch.phase = bevy::input::touch::TouchPhase::Cancelled;
touch_input_events.send(touch);
} else {
touch_input_events.send(touch);
}
}
_ => (),
}
}
_ => (),
};
if !skip_window_event {
match event {
event::Event::WindowEvent {
event,
window_id: winit_window_id,
..
} => {
let world = app.world.cell();
let vulkano_winit_windows =
world.get_non_send_resource::<BevyVulkanoWindows>().unwrap();
let mut windows = world.get_resource_mut::<Windows>().unwrap();
let window_id = if let Some(window_id) =
vulkano_winit_windows.get_window_id(winit_window_id)
{
window_id
} else {
warn!(
"Skipped event for unknown winit Window Id {:?}",
winit_window_id
);
return;
};
let window = if let Some(window) = windows.get_mut(window_id) {
window
} else {
warn!("Skipped event for unknown Window Id {:?}", winit_window_id);
return;
};
match event {
WindowEvent::Resized(size) => {
window.update_actual_size_from_backend(size.width, size.height);
let mut resize_events =
world.get_resource_mut::<Events<WindowResized>>().unwrap();
resize_events.send(WindowResized {
id: window_id,
width: window.width(),
height: window.height(),
});
}
WindowEvent::CloseRequested => {
let mut window_close_requested_events = world
.get_resource_mut::<Events<WindowCloseRequested>>()
.unwrap();
window_close_requested_events.send(WindowCloseRequested {
id: window_id,
});
}
WindowEvent::KeyboardInput {
ref input, ..
} => {
let mut keyboard_input_events =
world.get_resource_mut::<Events<KeyboardInput>>().unwrap();
keyboard_input_events.send(converters::convert_keyboard_input(input));
}
WindowEvent::CursorMoved {
position, ..
} => {
let mut cursor_moved_events =
world.get_resource_mut::<Events<CursorMoved>>().unwrap();
let winit_window =
vulkano_winit_windows.get_winit_window(window_id).unwrap();
let inner_size = winit_window.inner_size();
let y_position = inner_size.height as f64 - position.y;
let physical_position = DVec2::new(position.x, y_position);
window.update_cursor_physical_position_from_backend(Some(
physical_position,
));
cursor_moved_events.send(CursorMoved {
id: window_id,
position: (physical_position / window.scale_factor()).as_vec2(),
});
}
WindowEvent::CursorEntered {
..
} => {
let mut cursor_entered_events =
world.get_resource_mut::<Events<CursorEntered>>().unwrap();
cursor_entered_events.send(CursorEntered {
id: window_id,
});
}
WindowEvent::CursorLeft {
..
} => {
let mut cursor_left_events =
world.get_resource_mut::<Events<CursorLeft>>().unwrap();
window.update_cursor_physical_position_from_backend(None);
cursor_left_events.send(CursorLeft {
id: window_id,
});
}
WindowEvent::MouseInput {
state,
button,
..
} => {
let mut mouse_button_input_events = world
.get_resource_mut::<Events<MouseButtonInput>>()
.unwrap();
mouse_button_input_events.send(MouseButtonInput {
button: converters::convert_mouse_button(button),
state: converters::convert_element_state(state),
});
}
WindowEvent::MouseWheel {
delta, ..
} => match delta {
event::MouseScrollDelta::LineDelta(x, y) => {
let mut mouse_wheel_input_events =
world.get_resource_mut::<Events<MouseWheel>>().unwrap();
mouse_wheel_input_events.send(MouseWheel {
unit: MouseScrollUnit::Line,
x,
y,
});
}
event::MouseScrollDelta::PixelDelta(p) => {
let mut mouse_wheel_input_events =
world.get_resource_mut::<Events<MouseWheel>>().unwrap();
mouse_wheel_input_events.send(MouseWheel {
unit: MouseScrollUnit::Pixel,
x: p.x as f32,
y: p.y as f32,
});
}
},
WindowEvent::ReceivedCharacter(c) => {
let mut char_input_events = world
.get_resource_mut::<Events<ReceivedCharacter>>()
.unwrap();
char_input_events.send(ReceivedCharacter {
id: window_id,
char: c,
})
}
WindowEvent::ScaleFactorChanged {
scale_factor,
new_inner_size,
} => {
let mut backend_scale_factor_change_events = world
.get_resource_mut::<Events<WindowBackendScaleFactorChanged>>()
.unwrap();
backend_scale_factor_change_events.send(
WindowBackendScaleFactorChanged {
id: window_id,
scale_factor,
},
);
let prior_factor = window.scale_factor();
window.update_scale_factor_from_backend(scale_factor);
let new_factor = window.scale_factor();
if let Some(forced_factor) = window.scale_factor_override() {
*new_inner_size = winit::dpi::LogicalSize::new(
window.requested_width(),
window.requested_height(),
)
.to_physical::<u32>(forced_factor);
} else if approx::relative_ne!(new_factor, prior_factor) {
let mut scale_factor_change_events = world
.get_resource_mut::<Events<WindowScaleFactorChanged>>()
.unwrap();
scale_factor_change_events.send(WindowScaleFactorChanged {
id: window_id,
scale_factor,
});
}
let new_logical_width = new_inner_size.width as f64 / new_factor;
let new_logical_height = new_inner_size.height as f64 / new_factor;
if approx::relative_ne!(window.width() as f64, new_logical_width)
|| approx::relative_ne!(window.height() as f64, new_logical_height)
{
let mut resize_events =
world.get_resource_mut::<Events<WindowResized>>().unwrap();
resize_events.send(WindowResized {
id: window_id,
width: new_logical_width as f32,
height: new_logical_height as f32,
});
}
window.update_actual_size_from_backend(
new_inner_size.width,
new_inner_size.height,
);
}
WindowEvent::Focused(focused) => {
window.update_focused_status_from_backend(focused);
let mut focused_events =
world.get_resource_mut::<Events<WindowFocused>>().unwrap();
focused_events.send(WindowFocused {
id: window_id,
focused,
});
}
WindowEvent::DroppedFile(path_buf) => {
let mut events =
world.get_resource_mut::<Events<FileDragAndDrop>>().unwrap();
events.send(FileDragAndDrop::DroppedFile {
id: window_id,
path_buf,
});
}
WindowEvent::HoveredFile(path_buf) => {
let mut events =
world.get_resource_mut::<Events<FileDragAndDrop>>().unwrap();
events.send(FileDragAndDrop::HoveredFile {
id: window_id,
path_buf,
});
}
WindowEvent::HoveredFileCancelled => {
let mut events =
world.get_resource_mut::<Events<FileDragAndDrop>>().unwrap();
events.send(FileDragAndDrop::HoveredFileCancelled {
id: window_id,
});
}
WindowEvent::Moved(position) => {
let position = ivec2(position.x, position.y);
window.update_actual_position_from_backend(position);
let mut events =
world.get_resource_mut::<Events<WindowMoved>>().unwrap();
events.send(WindowMoved {
id: window_id,
position,
});
}
_ => {}
}
}
event::Event::DeviceEvent {
event:
DeviceEvent::MouseMotion {
delta,
},
..
} => {
let mut mouse_motion_events =
app.world.get_resource_mut::<Events<MouseMotion>>().unwrap();
mouse_motion_events.send(MouseMotion {
delta: Vec2::new(delta.0 as f32, delta.1 as f32),
});
}
event::Event::Suspended => {
active = false;
}
event::Event::Resumed => {
active = true;
}
event::Event::MainEventsCleared => {
handle_create_window_events(
&mut app.world,
event_loop,
&mut create_window_event_reader,
);
if active {
app.update();
}
}
_ => (),
}
}
};
if should_return_from_run {
let _exit_code = run_return(&mut event_loop, event_handler);
} else {
run(event_loop, event_handler);
}
}
fn handle_create_window_events(
world: &mut World,
event_loop: &EventLoopWindowTarget<()>,
create_window_event_reader: &mut ManualEventReader<CreateWindow>,
) {
let world = world.cell();
let vulkano_config = world.get_non_send_resource::<VulkanoWinitConfig>().unwrap();
let vulkano_context = world.get_resource::<BevyVulkanoContext>().unwrap();
let mut vulkano_winit_windows = world
.get_non_send_resource_mut::<BevyVulkanoWindows>()
.unwrap();
let mut windows = world.get_resource_mut::<Windows>().unwrap();
let create_window_events = world.get_resource::<Events<CreateWindow>>().unwrap();
let mut window_created_events = world.get_resource_mut::<Events<WindowCreated>>().unwrap();
for create_window_event in create_window_event_reader.iter(&create_window_events) {
let window = vulkano_winit_windows.create_window(
event_loop,
create_window_event.id,
&create_window_event.descriptor,
&vulkano_context.context,
&vulkano_config,
);
windows.add(window);
window_created_events.send(WindowCreated {
id: create_window_event.id,
});
}
}
fn handle_initial_window_events(world: &mut World, event_loop: &EventLoop<()>) {
let world = world.cell();
let vulkano_config = world.get_non_send_resource::<VulkanoWinitConfig>().unwrap();
let vulkano_context = world.get_resource::<BevyVulkanoContext>().unwrap();
let mut vulkano_winit_windows = world
.get_non_send_resource_mut::<BevyVulkanoWindows>()
.unwrap();
let mut windows = world.get_resource_mut::<Windows>().unwrap();
let mut create_window_events = world.get_resource_mut::<Events<CreateWindow>>().unwrap();
let mut window_created_events = world.get_resource_mut::<Events<WindowCreated>>().unwrap();
for create_window_event in create_window_events.drain() {
let window = vulkano_winit_windows.create_window(
event_loop,
create_window_event.id,
&create_window_event.descriptor,
&vulkano_context.context,
&vulkano_config,
);
windows.add(window);
window_created_events.send(WindowCreated {
id: create_window_event.id,
});
}
}
pub fn exit_on_window_close_system(
mut app_exit_events: EventWriter<AppExit>,
mut window_close_events: EventWriter<WindowClosed>,
mut window_close_requested_events: EventReader<WindowCloseRequested>,
mut windows: NonSendMut<BevyVulkanoWindows>,
mut pipeline_data: ResMut<PipelineSyncData>,
) {
for event in window_close_requested_events.iter() {
let (app_close, window_close) = close_window(event.id, &mut windows, &mut pipeline_data);
if app_close {
app_exit_events.send(AppExit);
} else if window_close {
window_close_events.send(WindowClosed {
id: event.id,
})
}
}
}
fn close_window(
window_id: bevy::window::WindowId,
windows: &mut BevyVulkanoWindows,
pipeline_data: &mut PipelineSyncData,
) -> (bool, bool) {
if window_id == WindowId::primary() {
(true, false)
}
else {
pipeline_data.remove(window_id);
let winit_id = if let Some(winit_window) = windows.get_winit_window(window_id) {
winit_window.id()
} else {
return (false, false);
};
windows.windows.remove(&winit_id);
(false, true)
}
}
#[cfg(feature = "gui")]
pub fn begin_egui_frame_system(mut vulkano_windows: NonSendMut<BevyVulkanoWindows>) {
for (_, (_, g)) in vulkano_windows.windows.iter_mut() {
g.begin_frame();
}
}