mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Document and test Events. Rename EventHandle to EventReader. Fix buffer indexing. Customizable bevy path for proc macros
This commit is contained in:
parent
8a759d3b18
commit
f6f8ba2cb6
16 changed files with 285 additions and 100 deletions
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
});
|
||||
|
|
|
@ -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>>()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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::{
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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],
|
||||
|
|
Loading…
Reference in a new issue