exit events and systems
This commit is contained in:
parent
649ffebb7f
commit
e59693fe67
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
plugin::{load_plugin, AppPlugin},
|
||||
schedule_plan::{SchedulePlan, System},
|
||||
stage, App, Events,
|
||||
stage, App, Events, AppExit,
|
||||
};
|
||||
|
||||
use legion::prelude::{Resources, Universe, World};
|
||||
@ -23,6 +23,7 @@ impl Default for AppBuilder {
|
||||
};
|
||||
|
||||
app_builder.add_default_stages();
|
||||
app_builder.add_event::<AppExit>();
|
||||
app_builder
|
||||
}
|
||||
}
|
||||
|
||||
5
bevy_app/src/event/mod.rs
Normal file
5
bevy_app/src/event/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
mod event;
|
||||
pub use event::*;
|
||||
|
||||
/// An event that indicates the app should exit. This will fully exit the app process.
|
||||
pub struct AppExit;
|
||||
@ -1,4 +1,5 @@
|
||||
use super::{App, AppBuilder, AppPlugin};
|
||||
use super::{App, AppBuilder, AppPlugin, GetEventReader};
|
||||
use crate::{AppExit, Events};
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -21,13 +22,21 @@ pub struct ScheduleRunnerPlugin {
|
||||
impl AppPlugin for ScheduleRunnerPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
let run_mode = self.run_mode;
|
||||
app.set_runner(move |mut app: App| match run_mode {
|
||||
app.set_runner(move |mut app: App| {
|
||||
let mut app_exit_event_reader = app.resources.get_event_reader::<AppExit>();
|
||||
match run_mode {
|
||||
RunMode::Once => {
|
||||
if let Some(ref mut schedule) = app.schedule {
|
||||
schedule.execute(&mut app.world, &mut app.resources);
|
||||
}
|
||||
}
|
||||
RunMode::Loop { wait } => loop {
|
||||
if let Some(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() {
|
||||
if app_exit_events.latest(&mut app_exit_event_reader).is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut schedule) = app.schedule {
|
||||
schedule.execute(&mut app.world, &mut app.resources);
|
||||
}
|
||||
@ -35,6 +44,7 @@ impl AppPlugin for ScheduleRunnerPlugin {
|
||||
thread::sleep(wait);
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,3 +6,4 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bevy_app = { path = "../bevy_app" }
|
||||
legion = { path = "../bevy_legion" }
|
||||
|
||||
@ -5,7 +5,7 @@ pub struct KeyboardInput {
|
||||
pub state: ElementState,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum ElementState {
|
||||
Pressed,
|
||||
Released,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod keyboard;
|
||||
pub mod mouse;
|
||||
pub mod system;
|
||||
|
||||
use bevy_app::{AppBuilder, AppPlugin};
|
||||
use keyboard::KeyboardInput;
|
||||
|
||||
19
bevy_input/src/system.rs
Normal file
19
bevy_input/src/system.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use bevy_app::{Events, GetEventReader, AppExit};
|
||||
use legion::prelude::*;
|
||||
use crate::keyboard::{VirtualKeyCode, KeyboardInput, ElementState};
|
||||
|
||||
pub fn exit_on_esc_system(resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||
let mut keyboard_input_event_reader = resources.get_event_reader::<KeyboardInput>();
|
||||
SystemBuilder::new("exit_on_esc")
|
||||
.read_resource::<Events<KeyboardInput>>()
|
||||
.write_resource::<Events<AppExit>>()
|
||||
.build(move |_, _, (ref keyboard_input_events, ref mut app_exit_events), _| {
|
||||
for event in keyboard_input_events.iter(&mut keyboard_input_event_reader) {
|
||||
if let Some(virtual_key_code) = event.virtual_key_code {
|
||||
if event.state == ElementState::Pressed && virtual_key_code == VirtualKeyCode::Escape {
|
||||
app_exit_events.send(AppExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -9,11 +9,9 @@ use crate::{
|
||||
},
|
||||
renderer_2::RenderContext,
|
||||
};
|
||||
use bevy_asset::{Asset, Handle};
|
||||
use bevy_asset::Handle;
|
||||
use legion::prelude::*;
|
||||
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UiDrawTarget {
|
||||
pub mesh_vertex_buffer: Option<RenderResource>,
|
||||
@ -86,7 +84,8 @@ impl DrawTarget for UiDrawTarget {
|
||||
let quad = Mesh::from(Quad {
|
||||
size: glam::vec2(1.0, 1.0),
|
||||
});
|
||||
let vertex_buffer_bytes = quad.get_vertex_buffer_bytes(
|
||||
let vertex_buffer_bytes = quad
|
||||
.get_vertex_buffer_bytes(
|
||||
pipeline_descriptor
|
||||
.get_layout()
|
||||
.unwrap()
|
||||
@ -94,7 +93,8 @@ impl DrawTarget for UiDrawTarget {
|
||||
.first()
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
self.mesh_vertex_buffer = Some(render_context.resources_mut().create_buffer_with_data(
|
||||
BufferInfo {
|
||||
buffer_usage: BufferUsage::VERTEX,
|
||||
@ -103,7 +103,9 @@ impl DrawTarget for UiDrawTarget {
|
||||
&vertex_buffer_bytes,
|
||||
));
|
||||
|
||||
let index_buffer_bytes = quad.get_index_buffer_bytes(pipeline_descriptor.index_format).unwrap();
|
||||
let index_buffer_bytes = quad
|
||||
.get_index_buffer_bytes(pipeline_descriptor.index_format)
|
||||
.unwrap();
|
||||
self.mesh_index_buffer = Some(render_context.resources_mut().create_buffer_with_data(
|
||||
BufferInfo {
|
||||
buffer_usage: BufferUsage::INDEX,
|
||||
|
||||
@ -4,9 +4,9 @@ use crate::{
|
||||
VertexBufferDescriptor, VertexFormat,
|
||||
},
|
||||
render_resource::AssetBatchers,
|
||||
Renderable, Vertex,
|
||||
Renderable,
|
||||
};
|
||||
use bevy_asset::{Asset, Handle};
|
||||
use bevy_asset::Handle;
|
||||
use glam::*;
|
||||
use legion::prelude::*;
|
||||
use std::borrow::Cow;
|
||||
@ -301,8 +301,9 @@ pub mod shape {
|
||||
impl From<Plane> for Mesh {
|
||||
fn from(plane: Plane) -> Self {
|
||||
Quad {
|
||||
size: Vec2::new(plane.size, plane.size)
|
||||
}.into()
|
||||
size: Vec2::new(plane.size, plane.size),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,4 +53,5 @@ void main() {
|
||||
}
|
||||
// multiply the light by material color
|
||||
o_Target = vec4(color, 1.0) * albedo;
|
||||
o_Target = vec4(v_Normal, 1.0);
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
use std::convert::From;
|
||||
use zerocopy::{AsBytes, FromBytes};
|
||||
|
||||
use bevy_asset;
|
||||
|
||||
@ -6,4 +6,5 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bevy_app = { path = "../bevy_app" }
|
||||
legion = { path = "../bevy_legion" }
|
||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
||||
37
bevy_window/src/event.rs
Normal file
37
bevy_window/src/event.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use super::{WindowDescriptor, WindowId};
|
||||
|
||||
/// A window event that is sent whenever a window has been resized.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowResized {
|
||||
pub id: WindowId,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub is_primary: bool,
|
||||
}
|
||||
|
||||
/// An event that indicates that a new window should be created.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CreateWindow {
|
||||
pub descriptor: WindowDescriptor,
|
||||
}
|
||||
|
||||
/// An event that indicates a window should be closed.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CloseWindow {
|
||||
pub id: WindowId,
|
||||
}
|
||||
|
||||
/// An event that is sent whenever a new window is created.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowCreated {
|
||||
pub id: WindowId,
|
||||
pub is_primary: bool,
|
||||
}
|
||||
|
||||
/// An event that is sent whenever a close was requested for a window. For example: when the "close" button
|
||||
/// is pressed on a window.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowCloseRequested {
|
||||
pub id: WindowId,
|
||||
pub is_primary: bool,
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
use super::{WindowDescriptor, WindowId};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowResized {
|
||||
pub id: WindowId,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub is_primary: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CreateWindow {
|
||||
pub descriptor: WindowDescriptor,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowCreated {
|
||||
pub id: WindowId,
|
||||
pub is_primary: bool,
|
||||
}
|
||||
@ -1,8 +1,10 @@
|
||||
mod events;
|
||||
mod event;
|
||||
mod system;
|
||||
mod window;
|
||||
mod windows;
|
||||
|
||||
pub use events::*;
|
||||
pub use event::*;
|
||||
pub use system::*;
|
||||
pub use window::*;
|
||||
pub use windows::*;
|
||||
|
||||
@ -10,12 +12,14 @@ use bevy_app::{AppBuilder, AppPlugin, Events};
|
||||
|
||||
pub struct WindowPlugin {
|
||||
pub primary_window: Option<WindowDescriptor>,
|
||||
pub exit_on_close: bool,
|
||||
}
|
||||
|
||||
impl Default for WindowPlugin {
|
||||
fn default() -> Self {
|
||||
WindowPlugin {
|
||||
primary_window: Some(WindowDescriptor::default()),
|
||||
exit_on_close: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -25,6 +29,8 @@ impl AppPlugin for WindowPlugin {
|
||||
app.add_event::<WindowResized>()
|
||||
.add_event::<CreateWindow>()
|
||||
.add_event::<WindowCreated>()
|
||||
.add_event::<WindowCloseRequested>()
|
||||
.add_event::<CloseWindow>()
|
||||
.add_resource(Windows::default());
|
||||
|
||||
if let Some(ref primary_window_descriptor) = self.primary_window {
|
||||
@ -34,5 +40,10 @@ impl AppPlugin for WindowPlugin {
|
||||
descriptor: primary_window_descriptor.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
if self.exit_on_close {
|
||||
let exit_on_close_system = exit_on_window_close_system(app.resources_mut(), None);
|
||||
app.add_system(exit_on_close_system);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
bevy_window/src/system.rs
Normal file
22
bevy_window/src/system.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use legion::prelude::*;
|
||||
use bevy_app::{Events, AppExit, GetEventReader};
|
||||
use crate::{WindowId, WindowCloseRequested};
|
||||
|
||||
pub fn exit_on_window_close_system(resources: &mut Resources, window_id: Option<WindowId>) -> Box<dyn Schedulable> {
|
||||
let mut window_close_requested_event_reader = resources.get_event_reader::<WindowCloseRequested>();
|
||||
SystemBuilder::new("exit_on_window_close")
|
||||
.read_resource::<Events<WindowCloseRequested>>()
|
||||
.write_resource::<Events<AppExit>>()
|
||||
.build(move |_, _, (ref window_close_requested_events, ref mut app_exit_events), _| {
|
||||
for window_close_requested_event in window_close_requested_events.iter(&mut window_close_requested_event_reader) {
|
||||
match window_id.as_ref() {
|
||||
Some(window_id) => if *window_id == window_close_requested_event.id {
|
||||
app_exit_events.send(AppExit);
|
||||
},
|
||||
None => if window_close_requested_event.is_primary {
|
||||
app_exit_events.send(AppExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -29,6 +29,12 @@ impl Windows {
|
||||
.and_then(|primary| self.windows.get(&primary))
|
||||
}
|
||||
|
||||
pub fn is_primary(&self, window_id: WindowId) -> bool {
|
||||
self.get_primary()
|
||||
.map(|primary_window| primary_window.id == window_id)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Window> {
|
||||
self.windows.values()
|
||||
}
|
||||
|
||||
@ -7,8 +7,10 @@ use bevy_input::{
|
||||
mouse::{MouseButtonInput, MouseMotion},
|
||||
};
|
||||
|
||||
use bevy_app::{App, AppBuilder, AppPlugin, EventReader, Events, GetEventReader};
|
||||
use bevy_window::{CreateWindow, Window, WindowCreated, WindowResized, Windows};
|
||||
use bevy_app::{App, AppBuilder, AppExit, AppPlugin, EventReader, Events, GetEventReader};
|
||||
use bevy_window::{
|
||||
CreateWindow, Window, WindowCloseRequested, WindowCreated, WindowResized, Windows,
|
||||
};
|
||||
use legion::prelude::*;
|
||||
use winit::{
|
||||
event,
|
||||
@ -33,6 +35,7 @@ impl AppPlugin for WinitPlugin {
|
||||
pub fn winit_runner(mut app: App) {
|
||||
let event_loop = EventLoop::new();
|
||||
let mut create_window_event_reader = app.resources.get_event_reader::<CreateWindow>();
|
||||
let mut app_exit_event_reader = app.resources.get_event_reader::<AppExit>();
|
||||
|
||||
handle_create_window_events(
|
||||
&mut app.resources,
|
||||
@ -47,6 +50,13 @@ pub fn winit_runner(mut app: App) {
|
||||
} else {
|
||||
ControlFlow::Poll
|
||||
};
|
||||
|
||||
if let Some(app_exit_events) = app.resources.get_mut::<Events<AppExit>>() {
|
||||
if app_exit_events.latest(&mut app_exit_event_reader).is_some() {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
}
|
||||
|
||||
match event {
|
||||
event::Event::WindowEvent {
|
||||
event: WindowEvent::Resized(size),
|
||||
@ -56,25 +66,35 @@ pub fn winit_runner(mut app: App) {
|
||||
let winit_windows = app.resources.get_mut::<WinitWindows>().unwrap();
|
||||
let mut windows = app.resources.get_mut::<Windows>().unwrap();
|
||||
let window_id = winit_windows.get_window_id(winit_window_id).unwrap();
|
||||
let is_primary = windows
|
||||
.get_primary()
|
||||
.map(|primary_window| primary_window.id == window_id)
|
||||
.unwrap_or(false);
|
||||
let mut window = windows.get_mut(window_id).unwrap();
|
||||
window.width = size.width;
|
||||
window.height = size.height;
|
||||
|
||||
let mut resize_event = app.resources.get_mut::<Events<WindowResized>>().unwrap();
|
||||
resize_event.send(WindowResized {
|
||||
let mut resize_events = app.resources.get_mut::<Events<WindowResized>>().unwrap();
|
||||
resize_events.send(WindowResized {
|
||||
id: window_id,
|
||||
height: window.height,
|
||||
width: window.width,
|
||||
is_primary,
|
||||
is_primary: windows.is_primary(window_id),
|
||||
});
|
||||
}
|
||||
event::Event::WindowEvent { event, .. } => match event {
|
||||
event::Event::WindowEvent {
|
||||
event,
|
||||
window_id: winit_window_id,
|
||||
..
|
||||
} => match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
let mut window_close_requested_events = app
|
||||
.resources
|
||||
.get_mut::<Events<WindowCloseRequested>>()
|
||||
.unwrap();
|
||||
let windows = app.resources.get_mut::<Windows>().unwrap();
|
||||
let winit_windows = app.resources.get_mut::<WinitWindows>().unwrap();
|
||||
let window_id = winit_windows.get_window_id(winit_window_id).unwrap();
|
||||
window_close_requested_events.send(WindowCloseRequested {
|
||||
id: window_id,
|
||||
is_primary: windows.is_primary(window_id),
|
||||
});
|
||||
}
|
||||
WindowEvent::KeyboardInput { ref input, .. } => {
|
||||
let mut keyboard_input_events =
|
||||
@ -126,13 +146,9 @@ fn handle_create_window_events(
|
||||
winit_windows.create_window(event_loop, &window);
|
||||
let window_id = window.id;
|
||||
windows.add(window);
|
||||
let is_primary = windows
|
||||
.get_primary()
|
||||
.map(|primary| primary.id == window_id)
|
||||
.unwrap_or(false);
|
||||
window_created_events.send(WindowCreated {
|
||||
id: window_id,
|
||||
is_primary,
|
||||
is_primary: windows.is_primary(window_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ fn main() {
|
||||
App::build()
|
||||
.add_default_plugins()
|
||||
.add_startup_system(setup)
|
||||
.add_system_init(bevy::input::system::exit_on_esc_system)
|
||||
.run();
|
||||
}
|
||||
|
||||
|
||||
34
src/add_default_plugins.rs
Normal file
34
src/add_default_plugins.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use crate::app::AppBuilder;
|
||||
|
||||
pub trait AddDefaultPlugins {
|
||||
fn add_default_plugins(&mut self) -> &mut Self;
|
||||
}
|
||||
|
||||
impl AddDefaultPlugins for AppBuilder {
|
||||
fn add_default_plugins(&mut self) -> &mut Self {
|
||||
#[cfg(feature = "core")]
|
||||
self.add_plugin(bevy_core::CorePlugin::default());
|
||||
|
||||
#[cfg(feature = "input")]
|
||||
self.add_plugin(bevy_input::InputPlugin::default());
|
||||
|
||||
#[cfg(feature = "window")]
|
||||
self.add_plugin(bevy_window::WindowPlugin::default());
|
||||
|
||||
#[cfg(feature = "render")]
|
||||
self.add_plugin(bevy_render::RenderPlugin::default());
|
||||
|
||||
#[cfg(feature = "ui")]
|
||||
self.add_plugin(bevy_ui::UiPlugin::default());
|
||||
|
||||
#[cfg(feature = "winit")]
|
||||
self.add_plugin(bevy_winit::WinitPlugin::default());
|
||||
#[cfg(not(feature = "winit"))]
|
||||
self.add_plugin(bevy_app::schedule_runner::ScheduleRunnerPlugin::default());
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
self.add_plugin(bevy_wgpu::WgpuPlugin::default());
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
37
src/lib.rs
37
src/lib.rs
@ -34,7 +34,9 @@
|
||||
#![feature(min_specialization)]
|
||||
|
||||
pub mod prelude;
|
||||
mod add_default_plugins;
|
||||
|
||||
pub use add_default_plugins::*;
|
||||
pub use bevy_app as app;
|
||||
pub use glam as math;
|
||||
pub use legion;
|
||||
@ -61,38 +63,3 @@ pub use bevy_transform as transform;
|
||||
pub use bevy_ui as ui;
|
||||
#[cfg(feature = "window")]
|
||||
pub use bevy_window as window;
|
||||
|
||||
use app::AppBuilder;
|
||||
|
||||
pub trait AddDefaultPlugins {
|
||||
fn add_default_plugins(&mut self) -> &mut Self;
|
||||
}
|
||||
|
||||
impl AddDefaultPlugins for AppBuilder {
|
||||
fn add_default_plugins(&mut self) -> &mut Self {
|
||||
#[cfg(feature = "core")]
|
||||
self.add_plugin(bevy_core::CorePlugin::default());
|
||||
|
||||
#[cfg(feature = "input")]
|
||||
self.add_plugin(bevy_input::InputPlugin::default());
|
||||
|
||||
#[cfg(feature = "window")]
|
||||
self.add_plugin(bevy_window::WindowPlugin::default());
|
||||
|
||||
#[cfg(feature = "render")]
|
||||
self.add_plugin(bevy_render::RenderPlugin::default());
|
||||
|
||||
#[cfg(feature = "ui")]
|
||||
self.add_plugin(ui::UiPlugin::default());
|
||||
|
||||
#[cfg(feature = "winit")]
|
||||
self.add_plugin(bevy_winit::WinitPlugin::default());
|
||||
#[cfg(not(feature = "winit"))]
|
||||
self.add_plugin(bevy_app::schedule_runner::ScheduleRunnerPlugin::default());
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
self.add_plugin(bevy_wgpu::WgpuPlugin::default());
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user