add support for multiple windows

This commit is contained in:
Carter Anderson 2020-03-30 14:53:32 -07:00
parent 7c121563db
commit 29bbc05eae
13 changed files with 266 additions and 55 deletions

View file

@ -21,7 +21,7 @@ fn event_trigger_system() -> Box<dyn Schedulable> {
.build(move |_, _, (time, my_event), _| { .build(move |_, _, (time, my_event), _| {
elapsed += time.delta_seconds; elapsed += time.delta_seconds;
if elapsed > 1.0 { if elapsed > 1.0 {
my_event.raise(MyEvent { my_event.send(MyEvent {
message: "Hello World".to_string(), message: "Hello World".to_string(),
}); });
@ -31,8 +31,7 @@ fn event_trigger_system() -> Box<dyn Schedulable> {
} }
fn event_listener_system(resources: &mut Resources) -> Box<dyn Schedulable> { fn event_listener_system(resources: &mut Resources) -> Box<dyn Schedulable> {
let my_event = resources.get::<Event<MyEvent>>().unwrap(); let mut my_event_handle = resources.get_event_handle::<MyEvent>();
let mut my_event_handle = my_event.get_handle();
SystemBuilder::new("EventListener") SystemBuilder::new("EventListener")
.read_resource::<Event<MyEvent>>() .read_resource::<Event<MyEvent>>()
.build(move |_, _, my_events, _| { .build(move |_, _, my_events, _| {

View file

@ -0,0 +1,18 @@
use bevy::prelude::*;
use bevy::core::window::CreateWindow;
fn main() {
App::build().add_defaults().setup(setup).run();
}
fn setup(_world: &mut World, resources: &mut Resources) {
let mut create_window_events = resources.get_mut::<Event<CreateWindow>>().unwrap();
create_window_events.send(CreateWindow {
descriptor: WindowDescriptor {
width: 800,
height: 600,
vsync: false,
title: "another window".to_string(),
}
});
}

View file

@ -1,9 +1,18 @@
use super::{Time, Window, WindowResize}; use super::{CreateWindow, Time, WindowCreated, WindowResize, Windows, Event, WindowDescriptor};
use crate::{app::{AppBuilder, plugin::AppPlugin}}; use crate::app::{plugin::AppPlugin, AppBuilder};
use bevy_transform::transform_system_bundle; use bevy_transform::transform_system_bundle;
#[derive(Default)] pub struct CorePlugin {
pub struct CorePlugin; pub primary_window: Option<WindowDescriptor>,
}
impl Default for CorePlugin {
fn default() -> Self {
CorePlugin {
primary_window: Some(WindowDescriptor::default()),
}
}
}
impl AppPlugin for CorePlugin { impl AppPlugin for CorePlugin {
fn build(&self, mut app: AppBuilder) -> AppBuilder { fn build(&self, mut app: AppBuilder) -> AppBuilder {
@ -11,9 +20,20 @@ impl AppPlugin for CorePlugin {
app = app.add_system(transform_system); app = app.add_system(transform_system);
} }
app.add_event::<WindowResize>() app = app.add_event::<WindowResize>()
.add_resource(Window::default()) .add_event::<CreateWindow>()
.add_resource(Time::new()) .add_event::<WindowCreated>()
.add_resource(Windows::default())
.add_resource(Time::new());
if let Some(ref primary_window_descriptor) = self.primary_window {
let mut create_window_event = app.resources.get_mut::<Event<CreateWindow>>().unwrap();
create_window_event.send(CreateWindow {
descriptor: primary_window_descriptor.clone(),
});
}
app
} }
fn name(&self) -> &'static str { fn name(&self) -> &'static str {

View file

@ -1,3 +1,4 @@
use crate::prelude::Resources;
use legion::prelude::{Schedulable, SystemBuilder}; use legion::prelude::{Schedulable, SystemBuilder};
use std::marker::PhantomData; use std::marker::PhantomData;
@ -55,7 +56,7 @@ impl<T> Event<T>
where where
T: Send + Sync + 'static, T: Send + Sync + 'static,
{ {
pub fn raise(&mut self, event: T) { pub fn send(&mut self, event: T) {
let event_instance = EventInstance { let event_instance = EventInstance {
event, event,
event_count: self.event_count, event_count: self.event_count,
@ -105,7 +106,7 @@ where
pub fn get_handle(&self) -> EventHandle<T> { pub fn get_handle(&self) -> EventHandle<T> {
EventHandle { EventHandle {
last_event_count: self.event_count, last_event_count: 0,
_marker: PhantomData, _marker: PhantomData,
} }
} }
@ -131,3 +132,21 @@ where
.build(|_, _, event, _| event.update()) .build(|_, _, event, _| event.update())
} }
} }
pub trait GetEventHandle {
fn get_event_handle<T>(&self) -> EventHandle<T>
where
T: Send + Sync + 'static;
}
impl GetEventHandle for Resources {
fn get_event_handle<T>(&self) -> EventHandle<T>
where
T: Send + Sync + 'static,
{
let my_event = self
.get::<Event<T>>()
.unwrap_or_else(|| panic!("Event does not exist: {}", std::any::type_name::<T>()));
my_event.get_handle()
}
}

18
src/core/window/events.rs Normal file
View file

@ -0,0 +1,18 @@
use super::{WindowDescriptor, WindowId};
#[derive(Debug, Clone)]
pub struct WindowResize {
pub id: WindowId,
pub width: u32,
pub height: u32,
}
#[derive(Debug, Clone)]
pub struct CreateWindow {
pub descriptor: WindowDescriptor,
}
#[derive(Debug, Clone)]
pub struct WindowCreated {
pub id: WindowId,
}

View file

@ -1,29 +1,47 @@
#[cfg(feature = "winit")] #[cfg(feature = "winit")]
pub mod winit; pub mod winit;
mod events;
mod windows;
pub use events::*;
pub use windows::*;
use uuid::Uuid; use uuid::Uuid;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct WindowId(Uuid); pub struct WindowId(Uuid);
pub struct Window { pub struct Window {
pub id: Uuid, pub id: WindowId,
pub width: u32, pub width: u32,
pub height: u32, pub height: u32,
pub title: String, pub title: String,
pub vsync: bool, pub vsync: bool,
} }
#[derive(Debug, Clone)] impl Window {
pub struct WindowResize { pub fn new(window_descriptor: &WindowDescriptor) -> Self {
pub id: Uuid, Window {
pub width: u32, id: WindowId(Uuid::new_v4()),
pub height: u32, height: window_descriptor.height,
width: window_descriptor.width,
title: window_descriptor.title.clone(),
vsync: window_descriptor.vsync,
}
}
} }
impl Default for Window { #[derive(Debug, Clone)]
pub struct WindowDescriptor {
pub width: u32,
pub height: u32,
pub title: String,
pub vsync: bool,
}
impl Default for WindowDescriptor {
fn default() -> Self { fn default() -> Self {
Window { WindowDescriptor {
id: Uuid::new_v4(),
title: "bevy".to_string(), title: "bevy".to_string(),
width: 1280, width: 1280,
height: 720, height: 720,

View file

@ -0,0 +1,35 @@
use super::{Window, WindowId};
use std::collections::HashMap;
#[derive(Default)]
pub struct Windows {
windows: HashMap<WindowId, Window>,
primary_window: Option<WindowId>,
}
impl Windows {
pub fn add(&mut self, window: Window) {
if let None = self.primary_window {
self.primary_window = Some(window.id);
};
self.windows.insert(window.id, window);
}
pub fn get(&self, id: WindowId) -> Option<&Window> {
self.windows.get(&id)
}
pub fn get_mut(&mut self, id: WindowId) -> Option<&mut Window> {
self.windows.get_mut(&id)
}
pub fn get_primary(&self) -> Option<&Window> {
self.primary_window
.and_then(|primary| self.windows.get(&primary))
}
pub fn iter(&self) -> impl Iterator<Item = &Window> {
self.windows.values()
}
}

View file

@ -1,13 +1,13 @@
use crate::{ mod winit_windows;
app::{plugin::AppPlugin, App, AppBuilder}, pub use winit_windows::*;
core::Event,
};
use super::{Window, WindowResize}; use crate::prelude::*;
use super::{CreateWindow, Window, WindowCreated, WindowResize, Windows};
use winit::{ use winit::{
event, event,
event::WindowEvent, event::WindowEvent,
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
}; };
#[derive(Default)] #[derive(Default)]
@ -15,7 +15,9 @@ pub struct WinitPlugin;
impl AppPlugin for WinitPlugin { impl AppPlugin for WinitPlugin {
fn build(&self, app: AppBuilder) -> AppBuilder { fn build(&self, app: AppBuilder) -> AppBuilder {
app.set_runner(winit_runner) app
.add_resource(WinitWindows::default())
.set_runner(winit_runner)
} }
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
@ -26,18 +28,16 @@ impl AppPlugin for WinitPlugin {
pub fn winit_runner(mut app: App) { pub fn winit_runner(mut app: App) {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let winit_window = { let mut create_window_event_handle = app.resources.get_event_handle::<CreateWindow>();
let window = app.resources.get::<Window>().unwrap();
let winit_window = winit::window::Window::new(&event_loop).unwrap();
winit_window.set_title(&window.title);
winit_window.set_inner_size(winit::dpi::PhysicalSize::new(window.width, window.height));
winit_window
};
app.resources.insert(winit_window); handle_create_window_events(
&mut app.resources,
&event_loop,
&mut create_window_event_handle,
);
log::debug!("Entering render loop"); log::debug!("Entering render loop");
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, event_loop, control_flow| {
*control_flow = if cfg!(feature = "metal-auto-capture") { *control_flow = if cfg!(feature = "metal-auto-capture") {
ControlFlow::Exit ControlFlow::Exit
} else { } else {
@ -46,15 +46,19 @@ pub fn winit_runner(mut app: App) {
match event { match event {
event::Event::WindowEvent { event::Event::WindowEvent {
event: WindowEvent::Resized(size), event: WindowEvent::Resized(size),
window_id: winit_window_id,
.. ..
} => { } => {
let mut window = app.resources.get_mut::<Window>().unwrap(); 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 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::<Event<WindowResize>>().unwrap(); let mut resize_event = app.resources.get_mut::<Event<WindowResize>>().unwrap();
resize_event.raise(WindowResize { resize_event.send(WindowResize {
id: window.id, id: window_id,
height: window.height, height: window.height,
width: window.width, width: window.width,
}); });
@ -75,9 +79,45 @@ pub fn winit_runner(mut app: App) {
_ => {} _ => {}
}, },
event::Event::MainEventsCleared => { event::Event::MainEventsCleared => {
handle_create_window_events(
&mut app.resources,
event_loop,
&mut create_window_event_handle,
);
app.update(); app.update();
} }
_ => (), _ => (),
} }
}); });
} }
fn handle_create_window_events(
resources: &mut Resources,
event_loop: &EventLoopWindowTarget<()>,
create_window_event_handle: &mut EventHandle<CreateWindow>,
) {
let mut winit_windows = resources.get_mut::<WinitWindows>().unwrap();
let mut windows = resources.get_mut::<Windows>().unwrap();
let create_window_events = resources.get::<Event<CreateWindow>>().unwrap();
let mut window_created_events = resources.get_mut::<Event<WindowCreated>>().unwrap();
for create_window_event in create_window_events.iter(create_window_event_handle) {
let window = Window::new(&create_window_event.descriptor);
create_window(
&event_loop,
&mut window_created_events,
&mut winit_windows,
&window,
);
windows.add(window);
}
}
pub fn create_window(
event_loop: &EventLoopWindowTarget<()>,
window_created_events: &mut Event<WindowCreated>,
winit_windows: &mut WinitWindows,
window: &Window,
) {
winit_windows.create_window(event_loop, &window);
window_created_events.send(WindowCreated { id: window.id });
}

View file

@ -0,0 +1,36 @@
use crate::{core::WindowId, prelude::*};
use std::collections::HashMap;
#[derive(Default)]
pub struct WinitWindows {
pub windows: HashMap<winit::window::WindowId, winit::window::Window>,
pub window_id_to_winit: HashMap<WindowId, winit::window::WindowId>,
pub winit_to_window_id: HashMap<winit::window::WindowId, WindowId>,
}
impl WinitWindows {
pub fn create_window(
&mut self,
event_loop: &winit::event_loop::EventLoopWindowTarget<()>,
window: &Window,
) {
let winit_window = winit::window::Window::new(&event_loop).unwrap();
self.window_id_to_winit.insert(window.id, winit_window.id());
self.winit_to_window_id.insert(winit_window.id(), window.id);
winit_window.set_title(&window.title);
winit_window.set_inner_size(winit::dpi::PhysicalSize::new(window.width, window.height));
self.windows.insert(winit_window.id(), winit_window);
}
pub fn get_window(&self, id: WindowId) -> Option<&winit::window::Window> {
self.window_id_to_winit
.get(&id)
.and_then(|id| self.windows.get(id))
}
pub fn get_window_id(&self, id: winit::window::WindowId) -> Option<WindowId> {
self.winit_to_window_id.get(&id).cloned()
}
}

View file

@ -1,23 +1,25 @@
pub use crate::{ pub use crate::{
app::{App, AppBuilder, plugin::AppPlugin}, app::{plugin::AppPlugin, App, AppBuilder},
asset::{Asset, AssetStorage, Handle}, asset::{Asset, AssetStorage, Handle},
core::{Time, Window, Event, EventHandle}, core::{Event, EventHandle, GetEventHandle, Time, Window, Windows, WindowDescriptor},
diagnostic::DiagnosticsPlugin,
ecs, ecs,
ecs::{ ecs::{
default_archetypes::*, CommandBufferBuilderSource, EntityArchetype, WorldBuilder, default_archetypes::*, CommandBufferBuilderSource, EntityArchetype, WorldBuilder,
WorldBuilderSource WorldBuilderSource,
}, },
render::{ render::{
mesh::{Mesh, MeshType}, mesh::{Mesh, MeshType},
pipeline::PipelineDescriptor, pipeline::PipelineDescriptor,
render_resource::{resource_name, resource_providers::UniformResourceProvider, AssetBatchers},
render_graph::RenderGraph, render_graph::RenderGraph,
render_resource::{
resource_name, resource_providers::UniformResourceProvider, AssetBatchers,
},
shader::{uniforms::StandardMaterial, Shader, ShaderDefSuffixProvider, ShaderStage}, shader::{uniforms::StandardMaterial, Shader, ShaderDefSuffixProvider, ShaderStage},
texture::{Texture, TextureType}, texture::{Texture, TextureType},
ActiveCamera, ActiveCamera2d, Camera, CameraType, Color, ColorSource, Light, Renderable, ActiveCamera, ActiveCamera2d, Camera, CameraType, Color, ColorSource, Light, Renderable,
}, },
ui::{Anchors, Margins, Node}, ui::{Anchors, Margins, Node},
diagnostic::DiagnosticsPlugin,
}; };
pub use bevy_derive::*; pub use bevy_derive::*;
pub use bevy_transform::prelude::*; pub use bevy_transform::prelude::*;
@ -28,12 +30,12 @@ pub use legion::{
event::Event as LegionEvent, event::Event as LegionEvent,
filter::filter_fns::*, filter::filter_fns::*,
query::{IntoQuery, Query, Read, Tagged, TryRead, TryWrite, Write}, query::{IntoQuery, Query, Read, Tagged, TryRead, TryWrite, Write},
world::{Universe, World},
systems::{ systems::{
bit_set::BitSet, bit_set::BitSet,
resource::{ResourceSet, Resources}, resource::{ResourceSet, Resources},
schedule::{Executor, Runnable, Schedulable, Schedule}, schedule::{Executor, Runnable, Schedulable, Schedule},
System, SystemBuilder, SubWorld SubWorld, System, SystemBuilder,
}, },
world::{Universe, World},
}; };
pub use math::{Mat3, Mat4, Quat, Vec2, Vec3, Vec4}; pub use math::{Mat3, Mat4, Quat, Vec2, Vec3, Vec4};

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
core::Window, core::Windows,
prelude::World, prelude::World,
render::{ render::{
render_resource::{RenderResourceAssignments, ResourceProvider}, render_resource::{RenderResourceAssignments, ResourceProvider},
@ -23,7 +23,8 @@ impl FrameTextureResourceProvider {
} }
pub fn update(&mut self, renderer: &mut dyn Renderer, _world: &World, resources: &Resources) { pub fn update(&mut self, renderer: &mut dyn Renderer, _world: &World, resources: &Resources) {
let window = resources.get::<Window>().unwrap(); let windows = resources.get::<Windows>().unwrap();
let window = windows.get_primary().unwrap();
self.descriptor.size.width = window.width; self.descriptor.size.width = window.width;
self.descriptor.size.height = window.height; self.descriptor.size.height = window.height;

View file

@ -1,7 +1,7 @@
use super::{wgpu_type_converter::OwnedWgpuVertexBufferDescriptor, WgpuRenderPass, WgpuResources}; use super::{wgpu_type_converter::OwnedWgpuVertexBufferDescriptor, WgpuRenderPass, WgpuResources};
use crate::{ use crate::{
asset::{AssetStorage, Handle}, asset::{AssetStorage, Handle},
core::{Event, EventHandle, Window, WindowResize}, core::{Event, EventHandle, WindowResize, winit::WinitWindows, Windows},
legion::prelude::*, legion::prelude::*,
render::{ render::{
pass::{ pass::{
@ -345,8 +345,11 @@ impl WgpuRenderer {
pub fn create_surface(&mut self, resources: &Resources) { pub fn create_surface(&mut self, resources: &Resources) {
#[cfg(feature = "winit")] #[cfg(feature = "winit")]
{ {
let window = resources.get::<winit::window::Window>().unwrap(); let winit_windows = resources.get::<WinitWindows>().unwrap();
let surface = wgpu::Surface::create(window.deref()); let windows = resources.get::<Windows>().unwrap();
let primary_window = windows.get_primary().unwrap();
let primary_winit_window = winit_windows.get_window(primary_window.id).unwrap();
let surface = wgpu::Surface::create(primary_winit_window.deref());
self.surface = Some(surface); self.surface = Some(surface);
} }
} }
@ -361,7 +364,8 @@ impl Renderer for WgpuRenderer {
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }), .create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }),
); );
let swap_chain_descriptor: wgpu::SwapChainDescriptor = { let swap_chain_descriptor: wgpu::SwapChainDescriptor = {
let window: &Window = &resources.get::<Window>().unwrap(); let windows = resources.get::<Windows>().unwrap();
let window = windows.get_primary().unwrap();
window.into() window.into()
}; };

View file

@ -2,11 +2,12 @@ use crate::prelude::*;
pub fn ui_update_system() -> Box<dyn Schedulable> { pub fn ui_update_system() -> Box<dyn Schedulable> {
SystemBuilder::new("ui_update") SystemBuilder::new("ui_update")
.read_resource::<Window>() .read_resource::<Windows>()
.with_query(<(Write<Node>,)>::query().filter(!component::<Parent>())) .with_query(<(Write<Node>,)>::query().filter(!component::<Parent>()))
.write_component::<Node>() .write_component::<Node>()
.read_component::<Children>() .read_component::<Children>()
.build(move |_, world, window, node_query| { .build(move |_, world, windows, node_query| {
let window = windows.get_primary().unwrap();
let parent_size = math::vec2(window.width as f32, window.height as f32); let parent_size = math::vec2(window.width as f32, window.height as f32);
let parent_position = math::vec2(0.0, 0.0); let parent_position = math::vec2(0.0, 0.0);
for (entity, _) in node_query.iter_entities_mut(world) { for (entity, _) in node_query.iter_entities_mut(world) {