Document and test Events. Rename EventHandle to EventReader. Fix buffer indexing. Customizable bevy path for proc macros

This commit is contained in:
Carter Anderson 2020-03-31 18:04:54 -07:00
parent 8a759d3b18
commit f6f8ba2cb6
16 changed files with 285 additions and 100 deletions

View file

@ -11,6 +11,7 @@ proc-macro = true
[dependencies]
syn = "1.0"
proc-macro2 = "1.0"
quote = "1.0"
Inflector = { version = "0.11.4", default-features = false }
darling = "0.10.2"

View file

@ -3,6 +3,7 @@ extern crate proc_macro;
use darling::FromMeta;
use inflector::Inflector;
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{format_ident, quote};
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, Ident, Type};
@ -82,12 +83,31 @@ struct UniformAttributeArgs {
pub instance: Option<bool>,
#[darling(default)]
pub vertex: Option<bool>,
#[darling(default)]
pub bevy_path: Option<String>,
}
#[proc_macro_derive(Uniforms, attributes(uniform))]
pub fn derive_uniforms(input: TokenStream) -> TokenStream {
static UNIFORM_ATTRIBUTE_NAME: &'static str = "uniform";
let ast = parse_macro_input!(input as DeriveInput);
let mut bevy_path_name = "bevy".to_string();
let struct_attribute_args = ast
.attrs
.iter()
.find(|a| a.path.get_ident().as_ref().unwrap().to_string() == UNIFORM_ATTRIBUTE_NAME)
.map(|a| {
UniformAttributeArgs::from_meta(&a.parse_meta().unwrap())
.unwrap_or_else(|_err| UniformAttributeArgs::default())
});
if let Some(struct_attribute_args) = struct_attribute_args {
if let Some(attribute_bevy_path) = struct_attribute_args.bevy_path {
bevy_path_name = attribute_bevy_path.to_string();
}
}
let bevy_path = Ident::new(&bevy_path_name, Span::call_site());
let fields = match &ast.data {
Data::Struct(DataStruct {
@ -195,20 +215,11 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
let vertex_buffer_field_names_pascal = vertex_buffer_fields
.map(|(f, (instance, _vertex))| {
let pascal_field = f.ident.as_ref().unwrap().to_string().to_pascal_case();
let pascal_field = f.ident.as_ref().unwrap().to_string().to_pascal_case();
if instance {
format!(
"I_{}_{}",
struct_name,
pascal_field
)
format!("I_{}_{}", struct_name, pascal_field)
} else {
format!(
"{}_{}",
struct_name,
pascal_field
)
format!("{}_{}", struct_name, pascal_field)
}
})
.collect::<Vec<String>>();
@ -242,7 +253,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
},
None => false,
};
quote!(bevy::render::shader::FieldInfo {
quote!(#bevy_path::render::shader::FieldInfo {
name: #field_name,
uniform_name: #uniform,
texture_name: #texture,
@ -252,13 +263,13 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
});
TokenStream::from(quote! {
static #field_infos_ident: &[bevy::render::shader::FieldInfo] = &[
static #field_infos_ident: &[#bevy_path::render::shader::FieldInfo] = &[
#(#field_infos,)*
];
static #vertex_buffer_descriptor_ident: bevy::once_cell::sync::Lazy<bevy::render::pipeline::VertexBufferDescriptor> =
bevy::once_cell::sync::Lazy::new(|| {
use bevy::render::pipeline::{VertexFormat, AsVertexFormats, VertexAttributeDescriptor};
static #vertex_buffer_descriptor_ident: #bevy_path::once_cell::sync::Lazy<#bevy_path::render::pipeline::VertexBufferDescriptor> =
#bevy_path::once_cell::sync::Lazy::new(|| {
use #bevy_path::render::pipeline::{VertexFormat, AsVertexFormats, VertexAttributeDescriptor};
let mut vertex_formats: Vec<(&str,&[VertexFormat])> = vec![
#((#vertex_buffer_field_names_pascal, <#vertex_buffer_field_types>::as_vertex_formats()),)*
@ -286,21 +297,21 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}).collect::<Vec<VertexAttributeDescriptor>>()
}).flatten().collect::<Vec<VertexAttributeDescriptor>>();
bevy::render::pipeline::VertexBufferDescriptor {
#bevy_path::render::pipeline::VertexBufferDescriptor {
attributes: vertex_attribute_descriptors,
name: #struct_name_string.to_string(),
step_mode: bevy::render::pipeline::InputStepMode::Instance,
step_mode: #bevy_path::render::pipeline::InputStepMode::Instance,
stride: offset,
}
});
impl bevy::render::shader::AsUniforms for #struct_name {
fn get_field_infos() -> &'static [bevy::render::shader::FieldInfo] {
impl #bevy_path::render::shader::AsUniforms for #struct_name {
fn get_field_infos() -> &'static [#bevy_path::render::shader::FieldInfo] {
#field_infos_ident
}
fn get_field_bind_type(&self, name: &str) -> Option<bevy::render::shader::FieldBindType> {
use bevy::render::shader::AsFieldBindType;
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_path::render::shader::FieldBindType> {
use #bevy_path::render::shader::AsFieldBindType;
match name {
#(#active_uniform_field_name_strings => self.#active_uniform_field_names.get_field_bind_type(),)*
_ => None,
@ -308,7 +319,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>> {
use bevy::core::bytes::GetBytes;
use #bevy_path::core::bytes::GetBytes;
match name {
#(#uniform_name_strings => Some(self.#active_uniform_field_names.get_bytes()),)*
_ => None,
@ -316,15 +327,15 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
}
fn get_uniform_bytes_ref(&self, name: &str) -> Option<&[u8]> {
use bevy::core::bytes::GetBytes;
use #bevy_path::core::bytes::GetBytes;
match name {
#(#uniform_name_strings => self.#active_uniform_field_names.get_bytes_ref(),)*
_ => None,
}
}
fn get_uniform_texture(&self, name: &str) -> Option<bevy::asset::Handle<bevy::render::texture::Texture>> {
use bevy::render::shader::GetTexture;
fn get_uniform_texture(&self, name: &str) -> Option<#bevy_path::asset::Handle<#bevy_path::render::texture::Texture>> {
use #bevy_path::render::shader::GetTexture;
match name {
#(#texture_and_sampler_name_strings => self.#texture_and_sampler_name_idents.get_texture(),)*
_ => None,
@ -335,7 +346,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
// TODO: this will be very allocation heavy. find a way to either make this allocation free
// or alternatively only run it when the shader_defs have changed
fn get_shader_defs(&self) -> Option<Vec<String>> {
use bevy::render::shader::ShaderDefSuffixProvider;
use #bevy_path::render::shader::ShaderDefSuffixProvider;
let mut potential_shader_defs: Vec<(&'static str, Option<&'static str>)> = vec![
#((#shader_def_field_names_screaming_snake, self.#shader_def_field_names.get_shader_def()),)*
];
@ -346,7 +357,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
.collect::<Vec<String>>())
}
fn get_vertex_buffer_descriptor() -> Option<&'static bevy::render::pipeline::VertexBufferDescriptor> {
fn get_vertex_buffer_descriptor() -> Option<&'static #bevy_path::render::pipeline::VertexBufferDescriptor> {
if #vertex_buffer_descriptor_ident.attributes.len() == 0 {
None
} else {

View file

@ -17,11 +17,11 @@ fn event_trigger_system() -> Box<dyn Schedulable> {
let mut elapsed = 0.0;
SystemBuilder::new("event_trigger")
.read_resource::<Time>()
.write_resource::<Event<MyEvent>>()
.build(move |_, _, (time, my_event), _| {
.write_resource::<Events<MyEvent>>()
.build(move |_, _, (time, my_events), _| {
elapsed += time.delta_seconds;
if elapsed > 1.0 {
my_event.send(MyEvent {
my_events.send(MyEvent {
message: "Hello World".to_string(),
});
@ -31,11 +31,11 @@ fn event_trigger_system() -> Box<dyn Schedulable> {
}
fn event_listener_system(resources: &mut Resources) -> Box<dyn Schedulable> {
let mut my_event_handle = resources.get_event_handle::<MyEvent>();
let mut my_event_reader = resources.get_event_reader::<MyEvent>();
SystemBuilder::new("event_listener")
.read_resource::<Event<MyEvent>>()
.read_resource::<Events<MyEvent>>()
.build(move |_, _, my_events, _| {
for my_event in my_events.iter(&mut my_event_handle) {
for my_event in my_events.iter(&mut my_event_reader) {
println!("{}", my_event.message);
}
})

View file

@ -3,7 +3,7 @@ use crate::{
plugin::{load_plugin, AppPlugin},
system_stage, App,
},
core::{CorePlugin, Event},
core::{CorePlugin, Events},
legion::prelude::{Resources, Runnable, Schedulable, Schedule, Universe, World},
render::RenderPlugin,
ui::UiPlugin,
@ -177,8 +177,8 @@ impl AppBuilder {
where
T: Send + Sync + 'static,
{
self.add_resource(Event::<T>::default())
.add_system_to_stage(system_stage::EVENT_UPDATE, Event::<T>::update_system())
self.add_resource(Events::<T>::default())
.add_system_to_stage(system_stage::EVENT_UPDATE, Events::<T>::build_update_system())
}
pub fn add_resource<T>(mut self, resource: T) -> Self

View file

@ -1,4 +1,4 @@
use super::{CreateWindow, Time, WindowCreated, WindowResized, Windows, Event, WindowDescriptor};
use super::{CreateWindow, Time, WindowCreated, WindowResized, Windows, Events, WindowDescriptor};
use crate::app::{plugin::AppPlugin, AppBuilder};
use bevy_transform::transform_system_bundle;
@ -27,7 +27,7 @@ impl AppPlugin for CorePlugin {
.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();
let mut create_window_event = app.resources.get_mut::<Events<CreateWindow>>().unwrap();
create_window_event.send(CreateWindow {
descriptor: primary_window_descriptor.clone(),
});

View file

@ -12,7 +12,49 @@ enum State {
B,
}
pub struct Event<T>
/// An event collection that represents the events that occurred within the last two [Events::update] calls. Events can be cheaply read using
/// an [EventReader]. This collection is meant to be paired with a system that calls [Events::update] exactly once per update/frame. [Events::build_update_system]
/// will produce a system that does this. [EventReader]s are expected to read events from this collection at least once per update/frame. If events are not handled
/// within one frame/update, they will be dropped.
///
/// # Example
/// ```
/// use bevy::core::event::Events;
///
/// struct MyEvent {
/// value: usize
/// }
///
/// // setup
/// let mut events = Events::<MyEvent>::default();
/// let mut reader = events.get_reader();
///
/// // run this once per update/frame
/// events.update();
///
/// // somewhere else: send an event
/// events.send(MyEvent { value: 1 });
///
/// // somewhere else: read the events
/// for event in events.iter(&mut reader) {
/// assert_eq!(event.value, 1)
/// }
///
/// // events are only processed once per reader
/// assert_eq!(events.iter(&mut reader).count(), 0);
/// ```
///
/// # Details
///
/// [Events] is implemented using a double buffer. Each call to [Events::update] swaps buffers and clears out the oldest buffer.
/// [EventReader]s that read at least once per update will never drop events. [EventReader]s that read once within two updates might
/// still receive some events. [EventReader]s that read after two updates are guaranteed to drop all events that occurred before those updates.
///
/// The buffers in [Events] will grow indefinitely if [Events::update] is never called.
///
/// An alternative call pattern would be to call [Events::update] manually across frames to control when events are cleared. However
/// this complicates consumption
pub struct Events<T>
where
T: Send + Sync + 'static,
{
@ -24,12 +66,12 @@ where
state: State,
}
impl<T> Default for Event<T>
impl<T> Default for Events<T>
where
T: Send + Sync + 'static,
{
fn default() -> Self {
Event {
Events {
a_start_event_count: 0,
b_start_event_count: 0,
event_count: 0,
@ -47,15 +89,16 @@ where
&event_instance.event
}
pub struct EventHandle<T> {
pub struct EventReader<T> {
last_event_count: usize,
_marker: PhantomData<T>,
}
impl<T> Event<T>
impl<T> Events<T>
where
T: Send + Sync + 'static,
{
/// "Sends" an `event` by writing it to the current event buffer. [EventReader]s can then read the event.
pub fn send(&mut self, event: T) {
let event_instance = EventInstance {
event,
@ -70,10 +113,21 @@ where
self.event_count += 1;
}
pub fn iter(&self, event_handle: &mut EventHandle<T>) -> impl DoubleEndedIterator<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;
/// Iterates over the events the `event_reader` has not seen yet.
pub fn iter(&self, event_reader: &mut EventReader<T>) -> impl DoubleEndedIterator<Item = &T> {
// if the reader has seen some of the events in a buffer, find the proper index offset.
// otherwise read all events in the buffer
let a_index = if event_reader.last_event_count > self.a_start_event_count {
event_reader.last_event_count - self.a_start_event_count
} else {
0
};
let b_index = if event_reader.last_event_count > self.b_start_event_count {
event_reader.last_event_count - self.b_start_event_count
} else {
0
};
event_reader.last_event_count = self.event_count;
match self.state {
State::A => self
.events_b
@ -104,13 +158,23 @@ where
}
}
pub fn get_handle(&self) -> EventHandle<T> {
EventHandle {
/// Gets a new [EventReader]. This will include all events already in the event buffers.
pub fn get_reader(&self) -> EventReader<T> {
EventReader {
last_event_count: 0,
_marker: PhantomData,
}
}
/// Gets a new [EventReader]. This will ignore all events already in the event buffers. It will read all future events.
pub fn get_reader_current(&self) -> EventReader<T> {
EventReader {
last_event_count: self.event_count,
_marker: PhantomData,
}
}
/// Swaps the event buffers and clears the oldest event buffer. In general, this should be called once per frame/update.
pub fn update(&mut self) {
match self.state {
State::A => {
@ -126,27 +190,136 @@ where
}
}
pub fn update_system() -> Box<dyn Schedulable> {
SystemBuilder::new(format!("EventUpdate::{}", std::any::type_name::<T>()))
/// Builds a system that calls [Events::update] once per frame.
pub fn build_update_system() -> Box<dyn Schedulable> {
SystemBuilder::new(format!("events_update::{}", std::any::type_name::<T>()))
.write_resource::<Self>()
.build(|_, _, event, _| event.update())
.build(|_, _, events, _| events.update())
}
}
pub trait GetEventHandle {
fn get_event_handle<T>(&self) -> EventHandle<T>
pub trait GetEventReader {
/// returns an [EventReader] of the given type
fn get_event_reader<T>(&self) -> EventReader<T>
where
T: Send + Sync + 'static;
}
impl GetEventHandle for Resources {
fn get_event_handle<T>(&self) -> EventHandle<T>
impl GetEventReader for Resources {
fn get_event_reader<T>(&self) -> EventReader<T>
where
T: Send + Sync + 'static,
{
let my_event = self
.get::<Event<T>>()
.get::<Events<T>>()
.unwrap_or_else(|| panic!("Event does not exist: {}", std::any::type_name::<T>()));
my_event.get_handle()
my_event.get_reader()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct TestEvent {
i: usize,
}
#[test]
fn test_events() {
let mut events = Events::<TestEvent>::default();
let event_0 = TestEvent { i: 0 };
let event_1 = TestEvent { i: 1 };
let event_2 = TestEvent { i: 2 };
// this reader will miss event_0 and event_1 because it wont read them over the course of two updates
let mut reader_missed = events.get_reader();
let mut reader_a = events.get_reader();
events.send(event_0);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_0],
"reader_a created before event receives event"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![],
"second iteration of reader_a created before event results in zero events"
);
let mut reader_b = events.get_reader();
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_0],
"reader_b created after event receives event"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![],
"second iteration of reader_b created after event results in zero events"
);
events.send(event_1);
let mut reader_c = events.get_reader();
assert_eq!(
get_events(&events, &mut reader_c),
vec![event_0, event_1],
"reader_c created after two events receives both events"
);
assert_eq!(
get_events(&events, &mut reader_c),
vec![],
"second iteration of reader_c created after two event results in zero events"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_1],
"reader_a receives next unread event"
);
events.update();
let mut reader_d = events.get_reader();
events.send(event_2);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_2],
"reader_a receives event created after update"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_1, event_2],
"reader_b receives events created before and after update"
);
assert_eq!(
get_events(&events, &mut reader_d),
vec![event_0, event_1, event_2],
"reader_d receives all events created before and after update"
);
events.update();
assert_eq!(
get_events(&events, &mut reader_missed),
vec![event_2],
"reader_missed missed events unread after to update() calls"
);
}
fn get_events(
events: &Events<TestEvent>,
reader: &mut EventReader<TestEvent>,
) -> Vec<TestEvent> {
events.iter(reader).cloned().collect::<Vec<TestEvent>>()
}
}

View file

@ -27,12 +27,12 @@ impl AppPlugin for WinitPlugin {
pub fn winit_runner(mut app: App) {
env_logger::init();
let event_loop = EventLoop::new();
let mut create_window_event_handle = app.resources.get_event_handle::<CreateWindow>();
let mut create_window_event_reader = app.resources.get_event_reader::<CreateWindow>();
handle_create_window_events(
&mut app.resources,
&event_loop,
&mut create_window_event_handle,
&mut create_window_event_reader,
);
log::debug!("Entering render loop");
@ -59,7 +59,7 @@ pub fn winit_runner(mut app: App) {
window.width = size.width;
window.height = size.height;
let mut resize_event = app.resources.get_mut::<Event<WindowResized>>().unwrap();
let mut resize_event = app.resources.get_mut::<Events<WindowResized>>().unwrap();
resize_event.send(WindowResized {
id: window_id,
height: window.height,
@ -86,7 +86,7 @@ pub fn winit_runner(mut app: App) {
handle_create_window_events(
&mut app.resources,
event_loop,
&mut create_window_event_handle,
&mut create_window_event_reader,
);
app.update();
}
@ -98,13 +98,13 @@ pub fn winit_runner(mut app: App) {
fn handle_create_window_events(
resources: &mut Resources,
event_loop: &EventLoopWindowTarget<()>,
create_window_event_handle: &mut EventHandle<CreateWindow>,
create_window_event_reader: &mut EventReader<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 create_window_events = resources.get::<Events<CreateWindow>>().unwrap();
let mut window_created_events = resources.get_mut::<Events<WindowCreated>>().unwrap();
for create_window_event in create_window_events.iter(create_window_event_reader) {
let window = Window::new(&create_window_event.descriptor);
winit_windows.create_window(event_loop, &window);
let window_id = window.id;

View file

@ -1,7 +1,7 @@
pub use crate::{
app::{plugin::AppPlugin, App, AppBuilder},
asset::{Asset, AssetStorage, Handle},
core::{Event, EventHandle, GetEventHandle, Time, Window, Windows, WindowDescriptor},
core::{Events, EventReader, GetEventReader, Time, Window, Windows, WindowDescriptor},
diagnostic::DiagnosticsPlugin,
ecs,
ecs::{

View file

@ -34,10 +34,10 @@ impl RenderPlugin {
.add_draw_target(AssignedMeshesDrawTarget::default())
.add_draw_target(UiDrawTarget::default())
.add_resource_provider(CameraResourceProvider::new(
app.resources.get_event_handle::<WindowResized>(),
app.resources.get_event_reader::<WindowResized>(),
))
.add_resource_provider(Camera2dResourceProvider::new(
app.resources.get_event_handle::<WindowResized>(),
app.resources.get_event_reader::<WindowResized>(),
))
.add_resource_provider(LightResourceProvider::new(10))
.add_resource_provider(UiResourceProvider::new())

View file

@ -13,15 +13,15 @@ use zerocopy::AsBytes;
pub struct Camera2dResourceProvider {
pub camera_buffer: Option<RenderResource>,
pub tmp_buffer: Option<RenderResource>,
pub window_resized_event_handle: EventHandle<WindowResized>,
pub window_resized_event_reader: EventReader<WindowResized>,
}
impl Camera2dResourceProvider {
pub fn new(window_resized_event_handle: EventHandle<WindowResized>) -> Self {
pub fn new(window_resized_event_reader: EventReader<WindowResized>) -> Self {
Camera2dResourceProvider {
camera_buffer: None,
tmp_buffer: None,
window_resized_event_handle,
window_resized_event_reader,
}
}
}
@ -46,9 +46,9 @@ impl ResourceProvider for Camera2dResourceProvider {
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
let window_resized_events = resources.get::<Event<WindowResized>>().unwrap();
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
let primary_window_resized_event = window_resized_events
.iter(&mut self.window_resized_event_handle)
.iter(&mut self.window_resized_event_reader)
.rev()
.filter(|event| event.is_primary)
.next();

View file

@ -15,15 +15,15 @@ use zerocopy::AsBytes;
pub struct CameraResourceProvider {
pub camera_buffer: Option<RenderResource>,
pub tmp_buffer: Option<RenderResource>,
pub window_resized_event_handle: EventHandle<WindowResized>,
pub window_resized_event_reader: EventReader<WindowResized>,
}
impl CameraResourceProvider {
pub fn new(window_resized_event_handle: EventHandle<WindowResized>) -> Self {
pub fn new(window_resized_event_reader: EventReader<WindowResized>) -> Self {
CameraResourceProvider {
camera_buffer: None,
tmp_buffer: None,
window_resized_event_handle,
window_resized_event_reader,
}
}
}
@ -48,9 +48,9 @@ impl ResourceProvider for CameraResourceProvider {
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
let window_resized_events = resources.get::<Event<WindowResized>>().unwrap();
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
let primary_window_resized_event = window_resized_events
.iter(&mut self.window_resized_event_handle)
.iter(&mut self.window_resized_event_reader)
.rev()
.filter(|event| event.is_primary)
.next();

View file

@ -1,4 +1,3 @@
use crate as bevy;
use crate::{
ecs,
prelude::Node,
@ -19,6 +18,7 @@ use zerocopy::{AsBytes, FromBytes};
#[repr(C)]
#[derive(Clone, Copy, Debug, AsBytes, FromBytes, Uniforms)]
#[uniform(bevy_path="crate")]
pub struct Rect {
#[uniform(instance)]
pub position: [f32; 2],

View file

@ -9,7 +9,7 @@ pub use wgpu_resources::*;
use crate::{
app::{plugin::AppPlugin, system_stage, AppBuilder},
core::{Event, WindowCreated, WindowResized},
core::{Events, WindowCreated, WindowResized},
render::renderer::Renderer,
};
@ -29,11 +29,11 @@ impl AppPlugin for WgpuRendererPlugin {
}
pub fn wgpu_render_system(resources: &Resources) -> impl FnMut(&mut World, &mut Resources) {
let window_resized_event = resources.get::<Event<WindowResized>>().unwrap();
let window_created_event = resources.get::<Event<WindowCreated>>().unwrap();
let window_resized_event = resources.get::<Events<WindowResized>>().unwrap();
let window_created_event = resources.get::<Events<WindowCreated>>().unwrap();
let mut wgpu_renderer = futures::executor::block_on(WgpuRenderer::new(
window_resized_event.get_handle(),
window_created_event.get_handle(),
window_resized_event.get_reader(),
window_created_event.get_reader(),
));
move |world, resources| {
wgpu_renderer.update(world, resources);

View file

@ -2,7 +2,7 @@ use super::{wgpu_type_converter::OwnedWgpuVertexBufferDescriptor, WgpuRenderPass
use crate::{
asset::{AssetStorage, Handle},
core::{
winit::WinitWindows, Event, EventHandle, Window, WindowCreated, WindowResized, Windows,
winit::WinitWindows, Events, EventReader, Window, WindowCreated, WindowResized, Windows,
},
legion::prelude::*,
render::{
@ -34,15 +34,15 @@ pub struct WgpuRenderer {
pub encoder: Option<wgpu::CommandEncoder>,
pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>,
pub wgpu_resources: WgpuResources,
pub window_resized_event_handle: EventHandle<WindowResized>,
pub window_created_event_handle: EventHandle<WindowCreated>,
pub window_resized_event_reader: EventReader<WindowResized>,
pub window_created_event_reader: EventReader<WindowCreated>,
pub intialized: bool,
}
impl WgpuRenderer {
pub async fn new(
window_resized_event_handle: EventHandle<WindowResized>,
window_created_event_handle: EventHandle<WindowCreated>,
window_resized_event_reader: EventReader<WindowResized>,
window_created_event_reader: EventReader<WindowCreated>,
) -> Self {
let adapter = wgpu::Adapter::request(
&wgpu::RequestAdapterOptions {
@ -66,8 +66,8 @@ impl WgpuRenderer {
device: Rc::new(RefCell::new(device)),
queue,
encoder: None,
window_resized_event_handle,
window_created_event_handle,
window_resized_event_reader,
window_created_event_reader,
intialized: false,
wgpu_resources: WgpuResources::default(),
render_pipelines: HashMap::new(),
@ -381,12 +381,12 @@ impl WgpuRenderer {
pub fn handle_window_resized_events(&mut self, resources: &mut Resources) {
let windows = resources.get::<Windows>().unwrap();
let window_resized_events = resources.get::<Event<WindowResized>>().unwrap();
let window_resized_events = resources.get::<Events<WindowResized>>().unwrap();
let mut handled_windows = HashSet::new();
// iterate in reverse order so we can handle the latest window resize event first for each window.
// we skip earlier events for the same window because it results in redundant work
for window_resized_event in window_resized_events
.iter(&mut self.window_resized_event_handle)
.iter(&mut self.window_resized_event_reader)
.rev()
{
if handled_windows.contains(&window_resized_event.id) {
@ -406,9 +406,9 @@ impl WgpuRenderer {
pub fn handle_window_created_events(&mut self, resources: &mut Resources) {
let windows = resources.get::<Windows>().unwrap();
let winit_windows = resources.get::<WinitWindows>().unwrap();
let window_created_events = resources.get::<Event<WindowCreated>>().unwrap();
let window_created_events = resources.get::<Events<WindowCreated>>().unwrap();
for window_created_event in
window_created_events.iter(&mut self.window_created_event_handle)
window_created_events.iter(&mut self.window_created_event_reader)
{
let window = windows
.get(window_created_event.id)

View file

@ -3,10 +3,10 @@ use crate::{
render::{texture::Texture, Color},
};
use crate as bevy; // for macro imports
use bevy_derive::Uniforms;
#[derive(Uniforms)]
#[uniform(bevy_path="crate")]
pub struct StandardMaterial {
#[uniform(instance)]
pub albedo: Color,

View file

@ -1,11 +1,11 @@
use std::convert::From;
use zerocopy::{AsBytes, FromBytes};
use crate as bevy;
use bevy_derive::Uniforms;
#[repr(C)]
#[derive(Clone, Copy, AsBytes, FromBytes, Uniforms)]
#[uniform(bevy_path="crate")]
pub struct Vertex {
#[uniform(vertex)]
pub position: [f32; 4],