Add Events. add WindowResize event to WgpuRenderer. remove Renderer from App

This commit is contained in:
Carter Anderson 2020-03-29 22:44:38 -07:00
parent 4435d536e8
commit 5eb789ff77
12 changed files with 248 additions and 37 deletions

View file

@ -1,4 +1,4 @@
use crate::{app::AppBuilder, core::Time, render::renderer::Renderer};
use crate::{app::AppBuilder, core::Time};
use legion::prelude::*;
pub struct App {
@ -6,7 +6,6 @@ pub struct App {
pub world: World,
pub resources: Resources,
pub run: Option<Box<dyn Fn(App)>>,
pub renderer: Option<Box<dyn Renderer>>,
pub schedule: Schedule,
}
@ -17,13 +16,11 @@ impl App {
resources: Resources,
schedule: Schedule,
run: Option<Box<dyn Fn(App)>>,
renderer: Option<Box<dyn Renderer>>,
) -> App {
App {
universe,
world,
schedule,
renderer,
run,
resources,
}
@ -39,10 +36,6 @@ impl App {
}
self.schedule.execute(&mut self.world, &mut self.resources);
if let Some(ref mut renderer) = self.renderer {
renderer.update(&mut self.world, &mut self.resources);
}
if let Some(mut time) = self.resources.get_mut::<Time>() {
time.stop();
}

View file

@ -3,10 +3,10 @@ use crate::{
plugin::{load_plugin, AppPlugin},
system_stage, App,
},
core::{winit::WinitPlugin, CorePlugin},
core::{winit::WinitPlugin, CorePlugin, Event},
legion::prelude::{Resources, Runnable, Schedulable, Schedule, Universe, World},
render::{
renderer::{renderers::wgpu_renderer::WgpuRendererPlugin, Renderer},
renderer::{renderers::wgpu_renderer::WgpuRendererPlugin},
RenderPlugin,
},
ui::UiPlugin,
@ -18,12 +18,13 @@ pub struct AppBuilder {
pub world: World,
pub resources: Resources,
pub universe: Universe,
pub renderer: Option<Box<dyn Renderer>>,
pub run: Option<Box<dyn Fn(App)>>,
pub schedule: Option<Schedule>,
pub setup_systems: Vec<Box<dyn Schedulable>>,
// TODO: these separate lists will produce incorrect ordering
pub system_stages: HashMap<String, Vec<Box<dyn Schedulable>>>,
pub runnable_stages: HashMap<String, Vec<Box<dyn Runnable>>>,
pub thread_local_stages: HashMap<String, Vec<Box<dyn FnMut(&mut World, &mut Resources)>>>,
pub stage_order: Vec<String>,
}
@ -36,12 +37,12 @@ impl AppBuilder {
universe,
world,
resources,
renderer: None,
run: None,
schedule: None,
setup_systems: Vec::new(),
system_stages: HashMap::new(),
runnable_stages: HashMap::new(),
thread_local_stages: HashMap::new(),
stage_order: Vec::new(),
}
}
@ -72,6 +73,16 @@ impl AppBuilder {
schedule_builder = schedule_builder.flush();
}
if let Some((_name, stage_thread_locals)) =
self.thread_local_stages.remove_entry(stage_name)
{
for system in stage_thread_locals {
schedule_builder = schedule_builder.add_thread_local_fn(system);
}
schedule_builder = schedule_builder.flush();
}
}
self.schedule = Some(schedule_builder.build());
@ -88,7 +99,6 @@ impl AppBuilder {
self.resources,
self.schedule.take().unwrap(),
self.run.take(),
self.renderer.take(),
)
}
@ -141,6 +151,28 @@ impl AppBuilder {
self
}
pub fn add_thread_local_to_stage(
mut self,
stage_name: &str,
f: impl FnMut(&mut World, &mut Resources) + 'static,
) -> Self {
if let None = self.thread_local_stages.get(stage_name) {
self.thread_local_stages
.insert(stage_name.to_string(), Vec::new());
// TODO: this is so broken
self.stage_order.push(stage_name.to_string());
}
let thread_local_stages = self.thread_local_stages.get_mut(stage_name).unwrap();
thread_local_stages.push(Box::new(f));
self
}
pub fn add_event<T>(self) -> Self where T: Send + Sync + 'static {
self.add_resource(Event::<T>::default())
.add_system_to_stage(system_stage::EVENT_UPDATE, Event::<T>::update_system())
}
pub fn add_resource<T>(mut self, resource: T) -> Self
where
T: Send + Sync + 'static,

View file

@ -1 +1,5 @@
pub const FIRST: &str = "first";
pub const EVENT_UPDATE: &str = "event_update";
pub const UPDATE: &str = "update";
pub const RENDER: &str = "render";
pub const LAST: &str = "last";

View file

@ -1,4 +1,4 @@
use super::{Time, Window};
use super::{Time, Window, WindowResize};
use crate::{app::{AppBuilder, plugin::AppPlugin}};
use bevy_transform::transform_system_bundle;
@ -11,7 +11,8 @@ impl AppPlugin for CorePlugin {
app = app.add_system(transform_system);
}
app.add_resource(Window::default())
app.add_event::<WindowResize>()
.add_resource(Window::default())
.add_resource(Time::new())
}

133
src/core/event.rs Normal file
View file

@ -0,0 +1,133 @@
use legion::prelude::{Schedulable, SystemBuilder};
use std::marker::PhantomData;
struct EventInstance<T> {
pub event_count: usize,
pub event: T,
}
enum State {
A,
B,
}
pub struct Event<T>
where
T: Send + Sync + 'static,
{
events_a: Vec<EventInstance<T>>,
events_b: Vec<EventInstance<T>>,
a_start_event_count: usize,
b_start_event_count: usize,
event_count: usize,
state: State,
}
impl<T> Default for Event<T>
where
T: Send + Sync + 'static,
{
fn default() -> Self {
Event {
a_start_event_count: 0,
b_start_event_count: 0,
event_count: 0,
events_a: Vec::new(),
events_b: Vec::new(),
state: State::A,
}
}
}
fn map_event_instance<T>(event_instance: &EventInstance<T>) -> &T
where
T: Send + Sync + 'static,
{
&event_instance.event
}
pub struct EventHandle<T> {
last_event_count: usize,
_marker: PhantomData<T>,
}
impl<T> Event<T>
where
T: Send + Sync + 'static,
{
pub fn raise(&mut self, event: T) {
let event_instance = EventInstance {
event,
event_count: self.event_count,
};
match self.state {
State::A => self.events_a.push(event_instance),
State::B => self.events_b.push(event_instance),
}
self.event_count += 1;
}
pub fn iter(&self, event_handle: &mut EventHandle<T>) -> impl Iterator<Item = &T> {
let a_index = self.a_start_event_count - event_handle.last_event_count;
let b_index = self.b_start_event_count - event_handle.last_event_count;
event_handle.last_event_count = self.event_count;
match self.state {
State::A => self
.events_b
.get(b_index..)
.unwrap_or_else(|| &[])
.iter()
.map(map_event_instance)
.chain(
self.events_a
.get(a_index..)
.unwrap_or_else(|| &[])
.iter()
.map(map_event_instance),
),
State::B => self
.events_a
.get(a_index..)
.unwrap_or_else(|| &[])
.iter()
.map(map_event_instance)
.chain(
self.events_b
.get(b_index..)
.unwrap_or_else(|| &[])
.iter()
.map(map_event_instance),
),
}
}
pub fn get_handle(&self) -> EventHandle<T> {
EventHandle {
last_event_count: self.event_count,
_marker: PhantomData,
}
}
pub fn update(&mut self) {
match self.state {
State::A => {
self.events_b = Vec::new();
self.state = State::B;
self.b_start_event_count = self.event_count;
}
State::B => {
self.events_a = Vec::new();
self.state = State::A;
self.a_start_event_count = self.event_count;
}
}
}
pub fn update_system() -> Box<dyn Schedulable> {
SystemBuilder::new(format!("EventUpdate::{}", std::any::type_name::<T>()))
.write_resource::<Self>()
.build(|_, _, event, _| event.update())
}
}

View file

@ -2,8 +2,10 @@ pub mod bytes;
mod time;
pub mod window;
mod core_plugin;
pub mod event;
pub use bytes::*;
pub use time::*;
pub use window::*;
pub use core_plugin::*;
pub use core_plugin::*;
pub use event::*;

View file

@ -13,6 +13,13 @@ pub struct Window {
pub vsync: bool,
}
#[derive(Debug, Clone)]
pub struct WindowResize {
pub id: Uuid,
pub width: u32,
pub height: u32,
}
impl Default for Window {
fn default() -> Self {
Window {

View file

@ -1,8 +1,6 @@
use crate::{
app::{App, AppBuilder}, app::plugin::AppPlugin,
};
use crate::{core::Event, app::{plugin::AppPlugin, App, AppBuilder}};
use super::Window;
use super::{Window, WindowResize};
use winit::{
event,
event::WindowEvent,
@ -52,15 +50,16 @@ pub fn get_winit_run() -> Box<dyn Fn(App) + Send + Sync> {
event: WindowEvent::Resized(size),
..
} => {
if let Some(ref mut renderer) = app.renderer {
{
let mut window = app.resources.get_mut::<Window>().unwrap();
window.width = size.width;
window.height = size.height;
}
let mut window = app.resources.get_mut::<Window>().unwrap();
window.width = size.width;
window.height = size.height;
renderer.resize(&mut app.world, &mut app.resources);
}
let mut resize_event = app.resources.get_mut::<Event<WindowResize>>().unwrap();
resize_event.raise(WindowResize {
id: window.id,
height: window.height,
width: window.width,
});
}
event::Event::WindowEvent { event, .. } => match event {
WindowEvent::KeyboardInput {

View file

@ -24,6 +24,7 @@ pub use bevy_transform::prelude::*;
pub use glam as math;
pub use legion::{
prelude::*,
prelude::Event as LegionEvent,
systems::{
schedule::{Builder, Schedulable},
SubWorld, SystemBuilder,

View file

@ -7,17 +7,31 @@ pub use wgpu_render_pass::*;
pub use wgpu_renderer::*;
pub use wgpu_resources::*;
use crate::{app::AppBuilder, app::plugin::AppPlugin};
use crate::{
app::{plugin::AppPlugin, AppBuilder, system_stage},
core::{Event, WindowResize},
render::renderer::Renderer,
};
use legion::prelude::*;
#[derive(Default)]
pub struct WgpuRendererPlugin;
impl AppPlugin for WgpuRendererPlugin {
fn build(&self, mut app: AppBuilder) -> AppBuilder {
app.renderer = Some(Box::new(WgpuRenderer::new()));
app
fn build(&self, app: AppBuilder) -> AppBuilder {
let render_system = wgpu_render_system(&app.resources);
app.add_thread_local_to_stage(system_stage::RENDER, render_system)
}
fn name(&self) -> &'static str {
"WgpuRenderer"
}
}
pub fn wgpu_render_system(resources: &Resources) -> impl FnMut(&mut World, &mut Resources) {
let window_resize_event = resources.get::<Event<WindowResize>>().unwrap();
let mut wgpu_renderer = WgpuRenderer::new(window_resize_event.get_handle());
move |world, resources| {
wgpu_renderer.update(world, resources);
}
}

View file

@ -1,7 +1,7 @@
use super::{wgpu_type_converter::OwnedWgpuVertexBufferDescriptor, WgpuRenderPass, WgpuResources};
use crate::{
asset::{AssetStorage, Handle},
core::Window,
core::{Event, EventHandle, Window, WindowResize},
legion::prelude::*,
render::{
pass::{
@ -28,11 +28,12 @@ pub struct WgpuRenderer {
pub encoder: Option<wgpu::CommandEncoder>,
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub wgpu_resources: WgpuResources,
pub window_resize_handle: EventHandle<WindowResize>,
pub intialized: bool,
}
impl WgpuRenderer {
pub fn new() -> Self {
pub fn new(window_resize_event: EventHandle<WindowResize>) -> Self {
let adapter = wgpu::Adapter::request(
&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::Default,
@ -53,6 +54,7 @@ impl WgpuRenderer {
queue,
surface: None,
encoder: None,
window_resize_handle: window_resize_event,
intialized: false,
wgpu_resources: WgpuResources::default(),
render_pipelines: HashMap::new(),
@ -366,7 +368,13 @@ impl Renderer for WgpuRenderer {
resources.insert(swap_chain);
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
for resource_provider in render_graph.resource_providers.iter_mut() {
resource_provider.resize(self, world, resources, swap_chain_descriptor.width, swap_chain_descriptor.height);
resource_provider.resize(
self,
world,
resources,
swap_chain_descriptor.width,
swap_chain_descriptor.height,
);
}
// consume current encoder
@ -380,6 +388,19 @@ impl Renderer for WgpuRenderer {
fn update(&mut self, world: &mut World, resources: &mut Resources) {
self.initialize(world, resources);
let resized =
resources
.get::<Event<WindowResize>>()
.unwrap()
.iter(&mut self.window_resize_handle)
.last()
.map(|_| ())
.is_some();
if resized {
self.resize(world, resources);
}
// TODO: this self.encoder handoff is a bit gross, but its here to give resource providers access to buffer copies without
// exposing the wgpu renderer internals to ResourceProvider traits. if this can be made cleaner that would be pretty cool.
self.encoder = Some(
@ -616,7 +637,11 @@ impl Renderer for WgpuRenderer {
render_resource_assignments,
);
} else {
log::trace!("reusing RenderResourceSet {:?} for bind group {}", render_resource_set_id, bind_group.index);
log::trace!(
"reusing RenderResourceSet {:?} for bind group {}",
render_resource_set_id,
bind_group.index
);
}
}
}

View file

@ -1,7 +1,7 @@
use crate::prelude::*;
pub fn ui_update_system() -> Box<dyn Schedulable> {
SystemBuilder::new("ui_update_system")
SystemBuilder::new("ui_update")
.read_resource::<Window>()
.with_query(<(Write<Node>,)>::query().filter(!component::<Parent>()))
.write_component::<Node>()