exit events and systems

This commit is contained in:
Carter Anderson 2020-04-19 12:13:04 -07:00
parent 649ffebb7f
commit e59693fe67
22 changed files with 222 additions and 107 deletions

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
plugin::{load_plugin, AppPlugin}, plugin::{load_plugin, AppPlugin},
schedule_plan::{SchedulePlan, System}, schedule_plan::{SchedulePlan, System},
stage, App, Events, stage, App, Events, AppExit,
}; };
use legion::prelude::{Resources, Universe, World}; use legion::prelude::{Resources, Universe, World};
@ -23,6 +23,7 @@ impl Default for AppBuilder {
}; };
app_builder.add_default_stages(); app_builder.add_default_stages();
app_builder.add_event::<AppExit>();
app_builder app_builder
} }
} }

View 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;

View File

@ -1,4 +1,5 @@
use super::{App, AppBuilder, AppPlugin}; use super::{App, AppBuilder, AppPlugin, GetEventReader};
use crate::{AppExit, Events};
use std::{thread, time::Duration}; use std::{thread, time::Duration};
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -21,20 +22,29 @@ pub struct ScheduleRunnerPlugin {
impl AppPlugin for ScheduleRunnerPlugin { impl AppPlugin for ScheduleRunnerPlugin {
fn build(&self, app: &mut AppBuilder) { fn build(&self, app: &mut AppBuilder) {
let run_mode = self.run_mode; let run_mode = self.run_mode;
app.set_runner(move |mut app: App| match run_mode { app.set_runner(move |mut app: App| {
RunMode::Once => { let mut app_exit_event_reader = app.resources.get_event_reader::<AppExit>();
if let Some(ref mut schedule) = app.schedule { match run_mode {
schedule.execute(&mut app.world, &mut app.resources); 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);
}
if let Some(wait) = wait {
thread::sleep(wait);
}
},
} }
RunMode::Loop { wait } => loop {
if let Some(ref mut schedule) = app.schedule {
schedule.execute(&mut app.world, &mut app.resources);
}
if let Some(wait) = wait {
thread::sleep(wait);
}
},
}); });
} }
} }

View File

@ -6,3 +6,4 @@ edition = "2018"
[dependencies] [dependencies]
bevy_app = { path = "../bevy_app" } bevy_app = { path = "../bevy_app" }
legion = { path = "../bevy_legion" }

View File

@ -5,7 +5,7 @@ pub struct KeyboardInput {
pub state: ElementState, pub state: ElementState,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Eq, PartialEq)]
pub enum ElementState { pub enum ElementState {
Pressed, Pressed,
Released, Released,

View File

@ -1,5 +1,6 @@
pub mod keyboard; pub mod keyboard;
pub mod mouse; pub mod mouse;
pub mod system;
use bevy_app::{AppBuilder, AppPlugin}; use bevy_app::{AppBuilder, AppPlugin};
use keyboard::KeyboardInput; use keyboard::KeyboardInput;

19
bevy_input/src/system.rs Normal file
View 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);
}
}
}
})
}

View File

@ -9,11 +9,9 @@ use crate::{
}, },
renderer_2::RenderContext, renderer_2::RenderContext,
}; };
use bevy_asset::{Asset, Handle}; use bevy_asset::Handle;
use legion::prelude::*; use legion::prelude::*;
use zerocopy::AsBytes;
#[derive(Default)] #[derive(Default)]
pub struct UiDrawTarget { pub struct UiDrawTarget {
pub mesh_vertex_buffer: Option<RenderResource>, pub mesh_vertex_buffer: Option<RenderResource>,
@ -86,15 +84,17 @@ impl DrawTarget for UiDrawTarget {
let quad = Mesh::from(Quad { let quad = Mesh::from(Quad {
size: glam::vec2(1.0, 1.0), size: glam::vec2(1.0, 1.0),
}); });
let vertex_buffer_bytes = quad.get_vertex_buffer_bytes( let vertex_buffer_bytes = quad
pipeline_descriptor .get_vertex_buffer_bytes(
.get_layout() pipeline_descriptor
.unwrap() .get_layout()
.vertex_buffer_descriptors .unwrap()
.first() .vertex_buffer_descriptors
.as_ref() .first()
.unwrap(), .as_ref()
).unwrap(); .unwrap(),
)
.unwrap();
self.mesh_vertex_buffer = Some(render_context.resources_mut().create_buffer_with_data( self.mesh_vertex_buffer = Some(render_context.resources_mut().create_buffer_with_data(
BufferInfo { BufferInfo {
buffer_usage: BufferUsage::VERTEX, buffer_usage: BufferUsage::VERTEX,
@ -103,7 +103,9 @@ impl DrawTarget for UiDrawTarget {
&vertex_buffer_bytes, &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( self.mesh_index_buffer = Some(render_context.resources_mut().create_buffer_with_data(
BufferInfo { BufferInfo {
buffer_usage: BufferUsage::INDEX, buffer_usage: BufferUsage::INDEX,

View File

@ -4,9 +4,9 @@ use crate::{
VertexBufferDescriptor, VertexFormat, VertexBufferDescriptor, VertexFormat,
}, },
render_resource::AssetBatchers, render_resource::AssetBatchers,
Renderable, Vertex, Renderable,
}; };
use bevy_asset::{Asset, Handle}; use bevy_asset::Handle;
use glam::*; use glam::*;
use legion::prelude::*; use legion::prelude::*;
use std::borrow::Cow; use std::borrow::Cow;
@ -301,8 +301,9 @@ pub mod shape {
impl From<Plane> for Mesh { impl From<Plane> for Mesh {
fn from(plane: Plane) -> Self { fn from(plane: Plane) -> Self {
Quad { Quad {
size: Vec2::new(plane.size, plane.size) size: Vec2::new(plane.size, plane.size),
}.into() }
.into()
} }
} }
} }

View File

@ -53,4 +53,5 @@ void main() {
} }
// multiply the light by material color // multiply the light by material color
o_Target = vec4(color, 1.0) * albedo; o_Target = vec4(color, 1.0) * albedo;
o_Target = vec4(v_Normal, 1.0);
} }

View File

@ -1,4 +1,3 @@
use std::convert::From;
use zerocopy::{AsBytes, FromBytes}; use zerocopy::{AsBytes, FromBytes};
use bevy_asset; use bevy_asset;

View File

@ -6,4 +6,5 @@ edition = "2018"
[dependencies] [dependencies]
bevy_app = { path = "../bevy_app" } bevy_app = { path = "../bevy_app" }
legion = { path = "../bevy_legion" }
uuid = { version = "0.8", features = ["v4", "serde"] } uuid = { version = "0.8", features = ["v4", "serde"] }

37
bevy_window/src/event.rs Normal file
View 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,
}

View File

@ -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,
}

View File

@ -1,8 +1,10 @@
mod events; mod event;
mod system;
mod window; mod window;
mod windows; mod windows;
pub use events::*; pub use event::*;
pub use system::*;
pub use window::*; pub use window::*;
pub use windows::*; pub use windows::*;
@ -10,12 +12,14 @@ use bevy_app::{AppBuilder, AppPlugin, Events};
pub struct WindowPlugin { pub struct WindowPlugin {
pub primary_window: Option<WindowDescriptor>, pub primary_window: Option<WindowDescriptor>,
pub exit_on_close: bool,
} }
impl Default for WindowPlugin { impl Default for WindowPlugin {
fn default() -> Self { fn default() -> Self {
WindowPlugin { WindowPlugin {
primary_window: Some(WindowDescriptor::default()), primary_window: Some(WindowDescriptor::default()),
exit_on_close: true,
} }
} }
} }
@ -25,6 +29,8 @@ impl AppPlugin for WindowPlugin {
app.add_event::<WindowResized>() app.add_event::<WindowResized>()
.add_event::<CreateWindow>() .add_event::<CreateWindow>()
.add_event::<WindowCreated>() .add_event::<WindowCreated>()
.add_event::<WindowCloseRequested>()
.add_event::<CloseWindow>()
.add_resource(Windows::default()); .add_resource(Windows::default());
if let Some(ref primary_window_descriptor) = self.primary_window { if let Some(ref primary_window_descriptor) = self.primary_window {
@ -34,5 +40,10 @@ impl AppPlugin for WindowPlugin {
descriptor: primary_window_descriptor.clone(), 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
View 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);
}
}
}
})
}

View File

@ -29,6 +29,12 @@ impl Windows {
.and_then(|primary| self.windows.get(&primary)) .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> { pub fn iter(&self) -> impl Iterator<Item = &Window> {
self.windows.values() self.windows.values()
} }

View File

@ -7,8 +7,10 @@ use bevy_input::{
mouse::{MouseButtonInput, MouseMotion}, mouse::{MouseButtonInput, MouseMotion},
}; };
use bevy_app::{App, AppBuilder, AppPlugin, EventReader, Events, GetEventReader}; use bevy_app::{App, AppBuilder, AppExit, AppPlugin, EventReader, Events, GetEventReader};
use bevy_window::{CreateWindow, Window, WindowCreated, WindowResized, Windows}; use bevy_window::{
CreateWindow, Window, WindowCloseRequested, WindowCreated, WindowResized, Windows,
};
use legion::prelude::*; use legion::prelude::*;
use winit::{ use winit::{
event, event,
@ -33,6 +35,7 @@ impl AppPlugin for WinitPlugin {
pub fn winit_runner(mut app: App) { pub fn winit_runner(mut app: App) {
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let mut create_window_event_reader = app.resources.get_event_reader::<CreateWindow>(); 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( handle_create_window_events(
&mut app.resources, &mut app.resources,
@ -47,6 +50,13 @@ pub fn winit_runner(mut app: App) {
} else { } else {
ControlFlow::Poll 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 { match event {
event::Event::WindowEvent { event::Event::WindowEvent {
event: WindowEvent::Resized(size), 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 winit_windows = app.resources.get_mut::<WinitWindows>().unwrap();
let mut windows = app.resources.get_mut::<Windows>().unwrap(); let mut windows = app.resources.get_mut::<Windows>().unwrap();
let window_id = winit_windows.get_window_id(winit_window_id).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(); let mut window = windows.get_mut(window_id).unwrap();
window.width = size.width; window.width = size.width;
window.height = size.height; window.height = size.height;
let mut resize_event = app.resources.get_mut::<Events<WindowResized>>().unwrap(); let mut resize_events = app.resources.get_mut::<Events<WindowResized>>().unwrap();
resize_event.send(WindowResized { resize_events.send(WindowResized {
id: window_id, id: window_id,
height: window.height, height: window.height,
width: window.width, 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 => { 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, .. } => { WindowEvent::KeyboardInput { ref input, .. } => {
let mut keyboard_input_events = let mut keyboard_input_events =
@ -126,13 +146,9 @@ fn handle_create_window_events(
winit_windows.create_window(event_loop, &window); winit_windows.create_window(event_loop, &window);
let window_id = window.id; let window_id = window.id;
windows.add(window); windows.add(window);
let is_primary = windows
.get_primary()
.map(|primary| primary.id == window_id)
.unwrap_or(false);
window_created_events.send(WindowCreated { window_created_events.send(WindowCreated {
id: window_id, id: window_id,
is_primary, is_primary: windows.is_primary(window_id),
}); });
} }
} }

View File

@ -4,6 +4,7 @@ fn main() {
App::build() App::build()
.add_default_plugins() .add_default_plugins()
.add_startup_system(setup) .add_startup_system(setup)
.add_system_init(bevy::input::system::exit_on_esc_system)
.run(); .run();
} }

View 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
}
}

View File

@ -34,7 +34,9 @@
#![feature(min_specialization)] #![feature(min_specialization)]
pub mod prelude; pub mod prelude;
mod add_default_plugins;
pub use add_default_plugins::*;
pub use bevy_app as app; pub use bevy_app as app;
pub use glam as math; pub use glam as math;
pub use legion; pub use legion;
@ -60,39 +62,4 @@ pub use bevy_transform as transform;
#[cfg(feature = "ui")] #[cfg(feature = "ui")]
pub use bevy_ui as ui; pub use bevy_ui as ui;
#[cfg(feature = "window")] #[cfg(feature = "window")]
pub use bevy_window as 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
}
}