game: improve event handling, update input systems to use new event handling
CI / build (push) Failing after 12m37s
Details
CI / build (push) Failing after 12m37s
Details
This commit is contained in:
parent
9125b91977
commit
9b1cc8c364
|
@ -2107,6 +2107,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-std",
|
"async-std",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"atomic_refcell",
|
||||||
"bind_match",
|
"bind_match",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
|
|
@ -40,6 +40,7 @@ petgraph = { version = "0.6.5", features = ["matrix_graph"] }
|
||||||
bind_match = "0.1.2"
|
bind_match = "0.1.2"
|
||||||
round_mult = "0.1.3"
|
round_mult = "0.1.3"
|
||||||
fast_poisson = { version = "1.0.0", features = ["single_precision"] }
|
fast_poisson = { version = "1.0.0", features = ["single_precision"] }
|
||||||
|
atomic_refcell = "0.1.13"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
tracy = ["dep:tracing-tracy"]
|
tracy = ["dep:tracing-tracy"]
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use atomic_refcell::AtomicRefCell;
|
||||||
|
use lyra_ecs::{query::{ResMut, WorldTick}, system::FnArgFetcher, Tick};
|
||||||
|
|
||||||
|
pub trait Event: Clone + Send + Sync + 'static {}
|
||||||
|
impl<T: Clone + Send + Sync + 'static> Event for T {}
|
||||||
|
|
||||||
|
pub struct Events<T: Event> {
|
||||||
|
events: Arc<AtomicRefCell<Vec<T>>>,
|
||||||
|
last_updated_tick: Option<Tick>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Event> Default for Events<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { events: Default::default(), last_updated_tick: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Event> Events<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_event(&mut self, event: T) {
|
||||||
|
let mut events = self.events.borrow_mut();
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reader(&self) -> EventReader<T> {
|
||||||
|
EventReader {
|
||||||
|
events: self.events.clone(),
|
||||||
|
cursor: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn writer(&self) -> EventWriter<T> {
|
||||||
|
EventWriter {
|
||||||
|
events: self.events.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventReader<T: Event> {
|
||||||
|
events: Arc<AtomicRefCell<Vec<T>>>,
|
||||||
|
cursor: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Event> EventReader<T> {
|
||||||
|
pub fn read(&mut self) -> Option<atomic_refcell::AtomicRef<T>> {
|
||||||
|
let events = self.events.borrow();
|
||||||
|
|
||||||
|
if self.cursor >= events.len() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let e = atomic_refcell::AtomicRef::map(events,
|
||||||
|
|e| e.get(self.cursor).unwrap());
|
||||||
|
self.cursor += 1;
|
||||||
|
Some(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventWriter<T: Event> {
|
||||||
|
events: Arc<AtomicRefCell<Vec<T>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Event> EventWriter<T> {
|
||||||
|
pub fn write(&mut self, event: T) {
|
||||||
|
let mut events = self.events.borrow_mut();
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clean events of event type `T` every 2 ticks.
|
||||||
|
pub fn event_cleaner_system<T>(tick: WorldTick, mut events: ResMut<Events<T>>) -> anyhow::Result<()>
|
||||||
|
where
|
||||||
|
T: Event
|
||||||
|
{
|
||||||
|
let last_tick = *events.last_updated_tick.unwrap_or(*tick);
|
||||||
|
let world_tick = **tick;
|
||||||
|
|
||||||
|
if last_tick + 2 < world_tick {
|
||||||
|
events.last_updated_tick = Some(*tick);
|
||||||
|
|
||||||
|
let mut events = events.events.borrow_mut();
|
||||||
|
events.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Event> FnArgFetcher for EventReader<T> {
|
||||||
|
type State = usize;
|
||||||
|
|
||||||
|
type Arg<'a, 'state> = EventReader<T>;
|
||||||
|
|
||||||
|
fn create_state(_: std::ptr::NonNull<lyra_ecs::World>) -> Self::State {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get<'a, 'state>(state: &'state mut Self::State, world: std::ptr::NonNull<lyra_ecs::World>) -> Self::Arg<'a, 'state> {
|
||||||
|
let world = world.as_ref();
|
||||||
|
let events = world.get_resource::<Events<T>>();
|
||||||
|
|
||||||
|
// reset the reader cursor when the events are cleared
|
||||||
|
let world_tick = world.current_tick();
|
||||||
|
if world_tick == events.last_updated_tick.unwrap_or(world_tick) {
|
||||||
|
*state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut reader = events.reader();
|
||||||
|
reader.cursor = *state;
|
||||||
|
|
||||||
|
reader
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_deferred(_: Self::State, _: std::ptr::NonNull<lyra_ecs::World>) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Event> FnArgFetcher for EventWriter<T> {
|
||||||
|
type State = ();
|
||||||
|
|
||||||
|
type Arg<'a, 'state> = EventWriter<T>;
|
||||||
|
|
||||||
|
fn create_state(_: std::ptr::NonNull<lyra_ecs::World>) -> Self::State {
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get<'a, 'state>(_: &'state mut Self::State, world: std::ptr::NonNull<lyra_ecs::World>) -> Self::Arg<'a, 'state> {
|
||||||
|
let world = world.as_ref();
|
||||||
|
let events = world.get_resource::<Events<T>>();
|
||||||
|
events.writer()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_deferred(_: Self::State, _: std::ptr::NonNull<lyra_ecs::World>) { }
|
||||||
|
}
|
|
@ -1,202 +0,0 @@
|
||||||
use std::{any::{Any, TypeId}, collections::{HashMap, VecDeque}, marker::PhantomData, mem::{self, MaybeUninit}, ops::Range};
|
|
||||||
|
|
||||||
use crate::plugin::Plugin;
|
|
||||||
|
|
||||||
pub trait Event: Clone + Send + Sync + 'static {}
|
|
||||||
impl<T: Clone + Send + Sync + 'static> Event for T {}
|
|
||||||
|
|
||||||
pub type Events<T> = VecDeque<T>;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct TypeErasedBuffer {
|
|
||||||
type_id: TypeId,
|
|
||||||
item_size: usize,
|
|
||||||
data: Vec<MaybeUninit<u8>>,
|
|
||||||
fn_drop_item: fn(item: *mut ()),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for TypeErasedBuffer {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let range = self.data.as_mut_ptr_range();
|
|
||||||
let mut current = range.start;
|
|
||||||
let end = range.end;
|
|
||||||
|
|
||||||
while current < end {
|
|
||||||
// SAFETY: current pointer will either be the start of the buffer, or at the start of
|
|
||||||
// the next item
|
|
||||||
(self.fn_drop_item)(current.cast());
|
|
||||||
|
|
||||||
// SAFETY: the items are placed right after eachother
|
|
||||||
current = unsafe { current.add(self.item_size) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Safety: all of the events were just dropped
|
|
||||||
unsafe { self.data.set_len(0) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeErasedBuffer {
|
|
||||||
pub fn new<T: 'static>() -> Self {
|
|
||||||
Self {
|
|
||||||
type_id: TypeId::of::<T>(),
|
|
||||||
item_size: mem::size_of::<T>(),
|
|
||||||
data: Default::default(),
|
|
||||||
// dropped immediately after the read
|
|
||||||
fn_drop_item: |item| unsafe { item.cast::<T>().drop_in_place() },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push<T: 'static>(&mut self, value: T) {
|
|
||||||
debug_assert!(TypeId::of::<T>() == self.type_id, "The type of the buffer does not match the type that was added to it");
|
|
||||||
|
|
||||||
// reserve enough bytes to store T
|
|
||||||
let old_len = self.data.len();
|
|
||||||
self.data.reserve(mem::size_of::<T>());
|
|
||||||
|
|
||||||
// Get a pointer to the end of the data.
|
|
||||||
// SAFETY: we just reserved enough memory to store the data.
|
|
||||||
let end_ptr = unsafe { self.data.as_mut_ptr().add(old_len) };
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// write the command and its runner into the buffer
|
|
||||||
end_ptr.cast::<T>()
|
|
||||||
// written unaligned to keep everything packed
|
|
||||||
.write_unaligned(value);
|
|
||||||
|
|
||||||
// we wrote to the vec's buffer without using its api, so we need manually
|
|
||||||
// set the length of the vec.
|
|
||||||
self.data.set_len(old_len + mem::size_of::<T>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.data.len() / self.item_size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EventQueue {
|
|
||||||
events: HashMap<TypeId, TypeErasedBuffer>,
|
|
||||||
event_write_queue: HashMap<TypeId, TypeErasedBuffer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for EventQueue {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventQueue {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
event_write_queue: HashMap::new(),
|
|
||||||
events: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trigger an event
|
|
||||||
pub fn trigger_event<E>(&mut self, event: E)
|
|
||||||
where
|
|
||||||
E: Event
|
|
||||||
{
|
|
||||||
// the compiler wants me to explicit right here for some reason
|
|
||||||
/* let default = || RefCell::new(Box::<Events::<E>>::default() as Box<dyn AsSyncAny>);
|
|
||||||
|
|
||||||
// Get, or create, a list of events of this type
|
|
||||||
let type_id = event.type_id();
|
|
||||||
let mut events = self.event_write_queue.entry(type_id)
|
|
||||||
.or_insert_with(default)
|
|
||||||
.borrow_mut();
|
|
||||||
|
|
||||||
// downcast resource as an events storage
|
|
||||||
let e: &mut Events<E> = events.as_mut().as_any_mut().downcast_mut().unwrap();
|
|
||||||
e.push_back(event); */
|
|
||||||
|
|
||||||
let type_id = event.type_id();
|
|
||||||
let events = self.event_write_queue.entry(type_id)
|
|
||||||
.or_insert_with(|| TypeErasedBuffer::new::<E>());
|
|
||||||
|
|
||||||
events.push(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear events, this should happen at the start of every tick since events are cloned
|
|
||||||
// before being given to the reader.
|
|
||||||
pub fn update_events(&mut self) {
|
|
||||||
self.events.clear();
|
|
||||||
|
|
||||||
// get all keys of events
|
|
||||||
let keys: Vec<TypeId> = self.event_write_queue.keys().copied().collect();
|
|
||||||
|
|
||||||
// remove all elements from self.event_write_queue and insert them to events
|
|
||||||
for k in keys.into_iter() {
|
|
||||||
let v = self.event_write_queue.remove(&k).unwrap();
|
|
||||||
self.events.insert(k, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_events<E>(&self) -> Option<EventReader<E>>
|
|
||||||
where
|
|
||||||
E: Event
|
|
||||||
{
|
|
||||||
self.events.get(&TypeId::of::<E>())
|
|
||||||
.map(|event| EventReader::new(event.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EventReader<E: Event> {
|
|
||||||
buf: TypeErasedBuffer,
|
|
||||||
range: Option<Range<*mut MaybeUninit<u8>>>,
|
|
||||||
_marker: PhantomData<E>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Event> EventReader<E> {
|
|
||||||
fn new(buffer: TypeErasedBuffer) -> Self {
|
|
||||||
Self {
|
|
||||||
buf: buffer,
|
|
||||||
range: None,
|
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.buf.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.len() == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Event> Iterator for EventReader<E> {
|
|
||||||
type Item = E;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.range.is_none() {
|
|
||||||
self.range = Some(self.buf.data.as_mut_ptr_range());
|
|
||||||
}
|
|
||||||
|
|
||||||
let range = self.range.as_mut().unwrap();
|
|
||||||
|
|
||||||
if range.start < range.end {
|
|
||||||
// Retrieve the event in the buffer.
|
|
||||||
// SAFETY: current pointer will either be the start of the buffer, or at the start
|
|
||||||
// of the next event.
|
|
||||||
let event = unsafe { range.start.cast::<E>().read_unaligned() };
|
|
||||||
|
|
||||||
// Advance the pointer to be after this event.
|
|
||||||
range.start = unsafe { range.start.add(mem::size_of::<E>()) };
|
|
||||||
|
|
||||||
Some(event)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct EventsPlugin;
|
|
||||||
|
|
||||||
impl Plugin for EventsPlugin {
|
|
||||||
fn setup(&mut self, app: &mut crate::game::App) {
|
|
||||||
app.world.add_resource(EventQueue::new());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@ use tracing_subscriber::{
|
||||||
util::SubscriberInitExt, fmt,
|
util::SubscriberInitExt, fmt,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{plugin::Plugin, render::renderer::Renderer, Stage, StagedExecutor};
|
use crate::{event_cleaner_system, plugin::Plugin, render::renderer::Renderer, Event, Events, Stage, StagedExecutor};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, Debug)]
|
#[derive(Clone, Copy, Hash, Debug)]
|
||||||
pub enum GameStages {
|
pub enum GameStages {
|
||||||
|
@ -214,4 +214,21 @@ impl App {
|
||||||
.expect("No run function set");
|
.expect("No run function set");
|
||||||
f(self);
|
f(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn register_event<T: Event>(&mut self) {
|
||||||
|
let world = &mut self.world;
|
||||||
|
// only register the event if it isn't already registered.
|
||||||
|
if !world.has_resource::<Events<T>>() {
|
||||||
|
world.add_resource_default::<Events<T>>();
|
||||||
|
let sys_name = format!("{}_event_cleaner_system", std::any::type_name::<T>().to_lowercase());
|
||||||
|
self.add_system_to_stage(GameStages::First, &sys_name, event_cleaner_system::<T>, &[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_event<T: Event>(&mut self, event: T) {
|
||||||
|
let world = &mut self.world;
|
||||||
|
let mut events = world.try_get_resource_mut::<Events<T>>()
|
||||||
|
.expect("missing events for event type! Must use `App::register_event` first");
|
||||||
|
events.push_event(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::{collections::HashMap, ops::Deref, hash::{Hash, DefaultHasher, Hasher}, fmt::Debug};
|
use std::{collections::HashMap, hash::{Hash, DefaultHasher, Hasher}, fmt::Debug};
|
||||||
|
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use lyra_ecs::World;
|
use lyra_ecs::query::{Res, ResMut};
|
||||||
use lyra_reflect::Reflect;
|
use lyra_reflect::Reflect;
|
||||||
|
|
||||||
use crate::{plugin::Plugin, game::GameStages, EventQueue};
|
use crate::{game::GameStages, plugin::Plugin, EventReader};
|
||||||
|
|
||||||
use super::{Button, InputButtons, KeyCode, MouseButton, MouseMotion};
|
use super::{Button, InputButtons, KeyCode, MouseButton, MouseMotion};
|
||||||
|
|
||||||
|
@ -497,64 +497,64 @@ impl ActionHandlerBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn actions_system(world: &mut World) -> anyhow::Result<()> {
|
//fn actions_system(world: &mut World) -> anyhow::Result<()> {
|
||||||
let keys = world.try_get_resource::<InputButtons<KeyCode>>()
|
fn actions_system(
|
||||||
.map(|r| r.deref().clone());
|
input_btns: Res<InputButtons<KeyCode>>,
|
||||||
let mouse_events = world
|
mut mouse_ev: EventReader<MouseMotion>,
|
||||||
.try_get_resource::<EventQueue>()
|
mut handler: ResMut<ActionHandler>,
|
||||||
.and_then(|q| q.read_events::<MouseMotion>());
|
) -> anyhow::Result<()> {
|
||||||
//let mouse = world.try_get_resource()
|
|
||||||
|
|
||||||
// clear the states of all axises each frame
|
// clear the states of all axises each frame
|
||||||
{
|
|
||||||
let mut handler = world.try_get_resource_mut::<ActionHandler>()
|
|
||||||
.expect("No Input Action handler was created in the world!");
|
|
||||||
|
|
||||||
let layout = handler.layouts.get(&handler.current_layout).expect("No active layout");
|
let layout = handler.layouts.get(&handler.current_layout).expect("No active layout");
|
||||||
let mapping = layout.mappings.get(&layout.active_mapping).expect("No active mapping");
|
let mapping = layout.mappings.get(&layout.active_mapping).expect("No active mapping");
|
||||||
|
|
||||||
for (action, _) in mapping.action_binds.clone().iter() {
|
for (action, _) in mapping.action_binds.clone().iter() {
|
||||||
let action = handler.actions.get_mut(action).expect("Action name for binding is invalid!");
|
let action = handler.actions.get_mut(action).expect("Action name for binding is invalid!");
|
||||||
if action.kind == ActionKind::Axis {
|
if action.kind == ActionKind::Axis {
|
||||||
action.state = ActionState::Axis(0.0);
|
action.state = ActionState::Axis(0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let motion_avg = if let Some(mouse_events) = mouse_events {
|
// collect all events to a list
|
||||||
|
let mouse_events = {
|
||||||
|
let mut evs = vec![];
|
||||||
|
while let Some(ev) = mouse_ev.read() {
|
||||||
|
evs.push(ev.clone());
|
||||||
|
}
|
||||||
|
evs
|
||||||
|
};
|
||||||
|
|
||||||
|
// get the average motion from the events that were collected last frame
|
||||||
|
let motion_avg = if !mouse_events.is_empty() {
|
||||||
let count = mouse_events.len();
|
let count = mouse_events.len();
|
||||||
let mut sum = Vec2::ZERO;
|
let mut sum = Vec2::ZERO;
|
||||||
|
|
||||||
for mm in mouse_events {
|
for mm in mouse_events {
|
||||||
sum += mm.delta;
|
sum += mm.delta;
|
||||||
}
|
}
|
||||||
Some(sum / count as f32)
|
|
||||||
} else { None };
|
|
||||||
|
|
||||||
let mut handler = world.try_get_resource_mut::<ActionHandler>()
|
sum / count as f32
|
||||||
.expect("No Input Action handler was created in the world!");
|
} else { Vec2::new(0.0, 0.0) };
|
||||||
|
|
||||||
let layout = handler.layouts.get(&handler.current_layout).expect("No active layout");
|
let layout = handler.layouts.get(&handler.current_layout).expect("No active layout");
|
||||||
let mapping = layout.mappings.get(&layout.active_mapping).expect("No active mapping");
|
let mapping = layout.mappings.get(&layout.active_mapping).expect("No active mapping");
|
||||||
|
|
||||||
for (action_lbl, binds) in mapping.action_binds.clone().iter() {
|
for (action_lbl, binds) in mapping.action_binds.clone().iter() {
|
||||||
let action = handler.actions.get_mut(action_lbl).expect("Action name for binding is invalid!");
|
let action = handler.actions.get_mut(action_lbl).expect("Action name for binding is invalid!");
|
||||||
let mut new_state = None;
|
let mut new_state = None;
|
||||||
|
|
||||||
for bind in binds.iter() {
|
for bind in binds.iter() {
|
||||||
match bind.source {
|
match bind.source {
|
||||||
ActionSource::Keyboard(key) => if let Some(keys) = &keys {
|
ActionSource::Keyboard(key) => {
|
||||||
// JustPressed needs to be first, since is_pressed includes buttons that
|
// JustPressed needs to be first, since is_pressed includes buttons that
|
||||||
// were just pressed.
|
// were just pressed.
|
||||||
match action.kind {
|
match action.kind {
|
||||||
ActionKind::Button => {
|
ActionKind::Button => {
|
||||||
if keys.was_just_pressed(key) {
|
if input_btns.was_just_pressed(key) {
|
||||||
new_state = Some(ActionState::JustPressed(bind.modifier));
|
new_state = Some(ActionState::JustPressed(bind.modifier));
|
||||||
} else if keys.is_pressed(key) {
|
} else if input_btns.is_pressed(key) {
|
||||||
new_state = Some(ActionState::Pressed(bind.modifier));
|
new_state = Some(ActionState::Pressed(bind.modifier));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ActionKind::Axis => {
|
ActionKind::Axis => {
|
||||||
if keys.is_pressed(key) {
|
if input_btns.is_pressed(key) {
|
||||||
new_state = Some(ActionState::Axis(bind.modifier));
|
new_state = Some(ActionState::Axis(bind.modifier));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -564,7 +564,7 @@ fn actions_system(world: &mut World) -> anyhow::Result<()> {
|
||||||
ActionSource::Gamepad(_, _) => todo!(),
|
ActionSource::Gamepad(_, _) => todo!(),
|
||||||
ActionSource::Mouse(m) => match m {
|
ActionSource::Mouse(m) => match m {
|
||||||
MouseInput::Button(_) => todo!(),
|
MouseInput::Button(_) => todo!(),
|
||||||
MouseInput::Axis(a) => if let Some(motion_avg) = motion_avg {
|
MouseInput::Axis(a) => {
|
||||||
match a {
|
match a {
|
||||||
MouseAxis::X => {
|
MouseAxis::X => {
|
||||||
new_state = Some(ActionState::Axis(motion_avg.x));
|
new_state = Some(ActionState::Axis(motion_avg.x));
|
||||||
|
|
|
@ -1,49 +1,14 @@
|
||||||
use std::ptr::NonNull;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use lyra_ecs::{World, system::IntoSystem};
|
use lyra_ecs::query::ResMut;
|
||||||
use winit::{event::MouseScrollDelta, keyboard::PhysicalKey};
|
use winit::{event::{MouseScrollDelta, WindowEvent}, keyboard::PhysicalKey};
|
||||||
|
|
||||||
use crate::{EventQueue, plugin::Plugin, game::GameStages};
|
use crate::{game::GameStages, plugin::Plugin, winit::DeviceEventPair, EventReader, EventWriter};
|
||||||
|
|
||||||
use super::{events::*, InputButtons, InputEvent};
|
use super::{events::*, InputButtons, InputEvent};
|
||||||
|
|
||||||
#[derive(Default)]
|
fn write_scroll_delta(mouse_scroll_ev: &mut EventWriter<MouseScroll>, delta: &MouseScrollDelta) {
|
||||||
pub struct InputSystem;
|
|
||||||
|
|
||||||
impl InputSystem {
|
|
||||||
pub fn process_event(&mut self, world: &mut World, event: &InputEvent) -> bool {
|
|
||||||
let event_queue = world.try_get_resource_mut::<EventQueue>();
|
|
||||||
if event_queue.is_none() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let mut event_queue = event_queue.unwrap();
|
|
||||||
|
|
||||||
match event {
|
|
||||||
InputEvent::KeyboardInput { device_id, event, .. } => {
|
|
||||||
if let PhysicalKey::Code(code) = event.physical_key {
|
|
||||||
drop(event_queue);
|
|
||||||
let mut e = world.get_resource_or_else(InputButtons::<winit::keyboard::KeyCode>::new);
|
|
||||||
//let mut e = with_resource_mut(world, || InputButtons::<KeyCode>::new());
|
|
||||||
e.add_input_from_winit(code, event.state);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
InputEvent::CursorMoved { position, .. } => {
|
|
||||||
let exact = MouseExact {
|
|
||||||
pos: Vec2::new(position.x as f32, position.y as f32)
|
|
||||||
};
|
|
||||||
|
|
||||||
event_queue.trigger_event(exact);
|
|
||||||
},
|
|
||||||
InputEvent::CursorEntered { .. } => {
|
|
||||||
let event = CursorEnteredWindow {};
|
|
||||||
event_queue.trigger_event(event);
|
|
||||||
},
|
|
||||||
InputEvent::CursorLeft { .. } => {
|
|
||||||
let event = CursorLeftWindow {};
|
|
||||||
event_queue.trigger_event(event);
|
|
||||||
},
|
|
||||||
InputEvent::MouseWheel { delta, .. } => {
|
|
||||||
let event = match delta {
|
let event = match delta {
|
||||||
MouseScrollDelta::LineDelta(x, y) => MouseScroll {
|
MouseScrollDelta::LineDelta(x, y) => MouseScroll {
|
||||||
unit: MouseScrollUnit::Line(Vec2::new(*x, *y)),
|
unit: MouseScrollUnit::Line(Vec2::new(*x, *y)),
|
||||||
|
@ -53,9 +18,46 @@ impl InputSystem {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
event_queue.trigger_event(event);
|
mouse_scroll_ev.write(event);
|
||||||
}, //MouseButton
|
}
|
||||||
InputEvent::MouseInput { button, state, .. } => {
|
|
||||||
|
pub fn input_system(
|
||||||
|
mut key_code_res: ResMut<InputButtons<winit::keyboard::KeyCode>>,
|
||||||
|
mut mouse_btn_res: ResMut<InputButtons<MouseButton>>,
|
||||||
|
mut touches_res: ResMut<Touches>,
|
||||||
|
mut window_ev: EventReader<WindowEvent>,
|
||||||
|
mut device_ev: EventReader<DeviceEventPair>,
|
||||||
|
mut mouse_scroll_ev: EventWriter<MouseScroll>,
|
||||||
|
mut mouse_btn_ev: EventWriter<MouseButton>,
|
||||||
|
mut mouse_exact_ev: EventWriter<MouseExact>,
|
||||||
|
mut mouse_entered_ev: EventWriter<CursorEnteredWindow>,
|
||||||
|
mut mouse_left_ev: EventWriter<CursorLeftWindow>,
|
||||||
|
mut mouse_motion_ev: EventWriter<MouseMotion>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
while let Some(event) = window_ev.read() {
|
||||||
|
match event.deref() {
|
||||||
|
WindowEvent::KeyboardInput { event, .. } => {
|
||||||
|
if let PhysicalKey::Code(code) = event.physical_key {
|
||||||
|
key_code_res.add_input_from_winit(code, event.state);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
|
let exact = MouseExact {
|
||||||
|
pos: Vec2::new(position.x as f32, position.y as f32)
|
||||||
|
};
|
||||||
|
|
||||||
|
mouse_exact_ev.write(exact);
|
||||||
|
},
|
||||||
|
WindowEvent::CursorEntered { .. } => {
|
||||||
|
mouse_entered_ev.write(CursorEnteredWindow);
|
||||||
|
},
|
||||||
|
WindowEvent::CursorLeft { .. } => {
|
||||||
|
mouse_left_ev.write(CursorLeftWindow);
|
||||||
|
},
|
||||||
|
WindowEvent::MouseWheel { delta, .. } => {
|
||||||
|
write_scroll_delta(&mut mouse_scroll_ev, delta);
|
||||||
|
},
|
||||||
|
WindowEvent::MouseInput { button, state, .. } => {
|
||||||
let button_event = match button {
|
let button_event = match button {
|
||||||
winit::event::MouseButton::Left => MouseButton::Left,
|
winit::event::MouseButton::Left => MouseButton::Left,
|
||||||
winit::event::MouseButton::Right => MouseButton::Right,
|
winit::event::MouseButton::Right => MouseButton::Right,
|
||||||
|
@ -65,15 +67,10 @@ impl InputSystem {
|
||||||
winit::event::MouseButton::Other(v) => MouseButton::Other(*v),
|
winit::event::MouseButton::Other(v) => MouseButton::Other(*v),
|
||||||
};
|
};
|
||||||
|
|
||||||
event_queue.trigger_event(button_event);
|
mouse_btn_ev.write(button_event);
|
||||||
drop(event_queue);
|
mouse_btn_res.add_input_from_winit(button_event, *state);
|
||||||
|
|
||||||
let mut e = world.get_resource_or_else(InputButtons::<MouseButton>::new);
|
|
||||||
e.add_input_from_winit(button_event, *state);
|
|
||||||
},
|
},
|
||||||
InputEvent::Touch(t) => {
|
WindowEvent::Touch(t) => {
|
||||||
drop(event_queue);
|
|
||||||
|
|
||||||
let touch = Touch {
|
let touch = Touch {
|
||||||
phase: TouchPhase::from(t.phase),
|
phase: TouchPhase::from(t.phase),
|
||||||
location: Vec2::new(t.location.x as f32, t.location.y as f32),
|
location: Vec2::new(t.location.x as f32, t.location.y as f32),
|
||||||
|
@ -81,61 +78,55 @@ impl InputSystem {
|
||||||
finger_id: t.id,
|
finger_id: t.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut touches = world.get_resource_or_else(Touches::new);
|
touches_res.touches.push(touch);
|
||||||
touches.touches.push(touch);
|
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::ecs::system::System for InputSystem {
|
while let Some(device) = device_ev.read() {
|
||||||
fn execute(&mut self, mut world: NonNull<World>) -> anyhow::Result<()> {
|
match &device.event {
|
||||||
let world = unsafe { world.as_mut() };
|
winit::event::DeviceEvent::Motion { .. } => {
|
||||||
let queue = world.try_get_resource_mut::<EventQueue>()
|
// TODO: handle device motion events
|
||||||
.and_then(|q| q.read_events::<InputEvent>());
|
// A todo! isn't used since these are triggered alongside MouseMotion events
|
||||||
|
|
||||||
let mut e = world.get_resource_or_else(InputButtons::<winit::keyboard::KeyCode>::new);
|
|
||||||
e.update();
|
|
||||||
drop(e);
|
|
||||||
|
|
||||||
if queue.is_none() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
winit::event::DeviceEvent::MouseMotion { delta } => {
|
||||||
|
let delta = MouseMotion {
|
||||||
|
delta: Vec2::new(delta.0 as f32, delta.1 as f32)
|
||||||
|
};
|
||||||
|
|
||||||
let events = queue.unwrap();
|
mouse_motion_ev.write(delta);
|
||||||
for event in events {
|
},
|
||||||
self.process_event(world, &event);
|
winit::event::DeviceEvent::MouseWheel { delta } => {
|
||||||
|
write_scroll_delta(&mut mouse_scroll_ev, delta);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
todo!("unhandled device event: {:?}", device.event);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn world_access(&self) -> lyra_ecs::Access {
|
|
||||||
lyra_ecs::Access::Write
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_deferred(&mut self, _: NonNull<World>) -> anyhow::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSystem<()> for InputSystem {
|
|
||||||
type System = Self;
|
|
||||||
|
|
||||||
fn into_system(self) -> Self::System {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Plugin that runs InputSystem
|
/// Plugin that runs InputSystem
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct InputPlugin;
|
pub struct InputPlugin;
|
||||||
|
|
||||||
impl Plugin for InputPlugin {
|
impl Plugin for InputPlugin {
|
||||||
fn setup(&mut self, app: &mut crate::game::App) {
|
fn setup(&mut self, app: &mut crate::game::App) {
|
||||||
app.add_system_to_stage(GameStages::PreUpdate, "input", InputSystem, &[]);
|
app.add_resource(InputButtons::<winit::keyboard::KeyCode>::default());
|
||||||
|
app.add_resource(InputButtons::<MouseButton>::default());
|
||||||
|
app.add_resource(Touches::default());
|
||||||
|
|
||||||
|
app.register_event::<InputEvent>();
|
||||||
|
app.register_event::<MouseScroll>();
|
||||||
|
app.register_event::<MouseButton>();
|
||||||
|
app.register_event::<MouseMotion>();
|
||||||
|
app.register_event::<MouseExact>();
|
||||||
|
app.register_event::<CursorEnteredWindow>();
|
||||||
|
app.register_event::<CursorLeftWindow>();
|
||||||
|
|
||||||
|
app.add_system_to_stage(GameStages::PreUpdate, "input", input_system, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
#![feature(hash_extract_if)]
|
#![feature(hash_extract_if)]
|
||||||
#![feature(lint_reasons)]
|
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
#![feature(map_many_mut)]
|
#![feature(map_many_mut)]
|
||||||
|
|
||||||
|
@ -14,8 +13,8 @@ pub mod as_any;
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
pub mod change_tracker;
|
pub mod change_tracker;
|
||||||
|
|
||||||
pub mod events;
|
mod event;
|
||||||
pub use events::*;
|
pub use event::*;
|
||||||
|
|
||||||
pub mod stage;
|
pub mod stage;
|
||||||
pub use stage::*;
|
pub use stage::*;
|
||||||
|
|
|
@ -3,7 +3,6 @@ use lyra_resource::ResourceManager;
|
||||||
|
|
||||||
use crate::game::App;
|
use crate::game::App;
|
||||||
use crate::winit::WinitPlugin;
|
use crate::winit::WinitPlugin;
|
||||||
use crate::EventsPlugin;
|
|
||||||
use crate::DeltaTimePlugin;
|
use crate::DeltaTimePlugin;
|
||||||
use crate::input::InputPlugin;
|
use crate::input::InputPlugin;
|
||||||
use crate::render::window::WindowPlugin;
|
use crate::render::window::WindowPlugin;
|
||||||
|
@ -113,7 +112,6 @@ impl Plugin for DefaultPlugins {
|
||||||
fn setup(&mut self, app: &mut App) {
|
fn setup(&mut self, app: &mut App) {
|
||||||
WinitPlugin::default().setup(app);
|
WinitPlugin::default().setup(app);
|
||||||
CommandQueuePlugin.setup(app);
|
CommandQueuePlugin.setup(app);
|
||||||
EventsPlugin.setup(app);
|
|
||||||
InputPlugin.setup(app);
|
InputPlugin.setup(app);
|
||||||
ResourceManagerPlugin.setup(app);
|
ResourceManagerPlugin.setup(app);
|
||||||
WindowPlugin::default().setup(app);
|
WindowPlugin::default().setup(app);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use lyra_ecs::{query::{filter::Changed, Entities, ResMut}, Component, World};
|
use lyra_ecs::{query::{filter::Changed, Entities, Res, View}, Component};
|
||||||
use lyra_resource::Image;
|
use lyra_resource::Image;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use winit::window::{CustomCursor, Fullscreen, Window};
|
use winit::window::{CustomCursor, Fullscreen, Window};
|
||||||
|
|
||||||
pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel};
|
pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel};
|
||||||
|
|
||||||
use crate::{change_tracker::Ct, plugin::Plugin, winit::WinitWindows};
|
use crate::{plugin::Plugin, winit::WinitWindows};
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy, PartialEq)]
|
#[derive(Default, Clone, Copy, PartialEq)]
|
||||||
pub struct Area {
|
pub struct Area {
|
||||||
|
@ -485,8 +485,12 @@ impl WindowOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The state of the window last time it was changed.
|
||||||
|
///
|
||||||
|
/// This is used in [`window_sync_system`] to see what fields of [`WindowOptions`] changed
|
||||||
|
/// when syncing the winit window with the component.
|
||||||
#[derive(Clone, Component)]
|
#[derive(Clone, Component)]
|
||||||
struct LastWindow {
|
pub struct LastWindow {
|
||||||
last: WindowOptions,
|
last: WindowOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,8 +515,8 @@ pub struct WindowPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A system that syncs Winit Windows with [`WindowOptions`] components.
|
/// A system that syncs Winit Windows with [`WindowOptions`] components.
|
||||||
pub fn window_sync_system(world: &mut World) -> anyhow::Result<()> {
|
pub fn window_sync_system(windows: Res<WinitWindows>, view: View<(Entities, &WindowOptions, &mut LastWindow), Changed<WindowOptions>>) -> anyhow::Result<()> {
|
||||||
for (entity, opts, mut last, windows) in world.filtered_view_iter::<(Entities, &WindowOptions, &mut LastWindow, ResMut<WinitWindows>), Changed<WindowOptions>>() {
|
for (entity, opts, mut last) in view.iter() {
|
||||||
let window = windows.get_entity_window(entity)
|
let window = windows.get_entity_window(entity)
|
||||||
.expect("entity's window is missing");
|
.expect("entity's window is missing");
|
||||||
|
|
||||||
|
@ -644,9 +648,6 @@ pub fn window_sync_system(world: &mut World) -> anyhow::Result<()> {
|
||||||
|
|
||||||
impl Plugin for WindowPlugin {
|
impl Plugin for WindowPlugin {
|
||||||
fn setup(&mut self, app: &mut crate::game::App) {
|
fn setup(&mut self, app: &mut crate::game::App) {
|
||||||
let window_options = WindowOptions::default();
|
|
||||||
|
|
||||||
app.world.add_resource(Ct::new(window_options));
|
|
||||||
app.with_system("window_sync", window_sync_system, &[]);
|
app.with_system("window_sync", window_sync_system, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,30 @@ use async_std::task::block_on;
|
||||||
use glam::IVec2;
|
use glam::IVec2;
|
||||||
use lyra_ecs::Entity;
|
use lyra_ecs::Entity;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, warn};
|
||||||
use winit::{application::ApplicationHandler, event::WindowEvent, event_loop::{ActiveEventLoop, EventLoop}, window::{Window, WindowAttributes, WindowId}};
|
use winit::{
|
||||||
|
application::ApplicationHandler,
|
||||||
|
event::WindowEvent,
|
||||||
|
event_loop::{ActiveEventLoop, EventLoop},
|
||||||
|
window::{Window, WindowAttributes, WindowId},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{game::{App, WindowState}, input::InputEvent, plugin::Plugin, render::{renderer::BasicRenderer, window::{PrimaryWindow, Size, WindowOptions}}, EventQueue};
|
use crate::{
|
||||||
|
game::{App, WindowState},
|
||||||
|
plugin::Plugin,
|
||||||
|
render::{
|
||||||
|
renderer::BasicRenderer,
|
||||||
|
window::{PrimaryWindow, Size, WindowOptions},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A struct that contains a [`DeviceEvent`](winit::event::DeviceEvent) with its source
|
||||||
|
/// [`DeviceId`](winit::event::DeviceId).
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DeviceEventPair {
|
||||||
|
pub device_src: winit::event::DeviceId,
|
||||||
|
pub event: winit::event::DeviceEvent,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WinitPlugin {
|
pub struct WinitPlugin {
|
||||||
/// The primary window that will be created.
|
/// The primary window that will be created.
|
||||||
|
@ -20,13 +40,17 @@ pub struct WinitPlugin {
|
||||||
|
|
||||||
impl Default for WinitPlugin {
|
impl Default for WinitPlugin {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { primary_window: Some(WindowOptions::default()) }
|
Self {
|
||||||
|
primary_window: Some(WindowOptions::default()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for WinitPlugin {
|
impl Plugin for WinitPlugin {
|
||||||
fn setup(&mut self, app: &mut crate::game::App) {
|
fn setup(&mut self, app: &mut crate::game::App) {
|
||||||
app.set_run_fn(winit_app_runner);
|
app.set_run_fn(winit_app_runner);
|
||||||
|
app.register_event::<WindowEvent>();
|
||||||
|
app.register_event::<DeviceEventPair>();
|
||||||
|
|
||||||
if let Some(prim) = self.primary_window.take() {
|
if let Some(prim) = self.primary_window.take() {
|
||||||
app.add_resource(WinitWindows::with_window(prim));
|
app.add_resource(WinitWindows::with_window(prim));
|
||||||
|
@ -39,13 +63,9 @@ impl Plugin for WinitPlugin {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete(&self, _app: &mut crate::game::App) {
|
fn complete(&self, _app: &mut crate::game::App) {}
|
||||||
|
|
||||||
}
|
fn cleanup(&self, _app: &mut crate::game::App) {}
|
||||||
|
|
||||||
fn cleanup(&self, _app: &mut crate::game::App) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -65,7 +85,12 @@ impl WinitWindows {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_window(&mut self, event_loop: &ActiveEventLoop, entity: Entity, attr: WindowAttributes) -> Result<WindowId, winit::error::OsError> {
|
pub fn create_window(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
entity: Entity,
|
||||||
|
attr: WindowAttributes,
|
||||||
|
) -> Result<WindowId, winit::error::OsError> {
|
||||||
let win = event_loop.create_window(attr)?;
|
let win = event_loop.create_window(attr)?;
|
||||||
let id = win.id();
|
let id = win.id();
|
||||||
|
|
||||||
|
@ -77,37 +102,34 @@ impl WinitWindows {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_entity_window(&self, entity: Entity) -> Option<&Arc<Window>> {
|
pub fn get_entity_window(&self, entity: Entity) -> Option<&Arc<Window>> {
|
||||||
self.entity_to_window.get(&entity)
|
self.entity_to_window
|
||||||
|
.get(&entity)
|
||||||
.and_then(|id| self.windows.get(id))
|
.and_then(|id| self.windows.get(id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn winit_app_runner(app: App) {
|
pub fn winit_app_runner(app: App) {
|
||||||
let evloop = EventLoop::new()
|
let evloop = EventLoop::new().expect("failed to create winit EventLoop");
|
||||||
.expect("failed to create winit EventLoop");
|
|
||||||
|
|
||||||
let mut winit_runner = WinitRunner {
|
let mut winit_runner = WinitRunner { app };
|
||||||
app,
|
evloop.run_app(&mut winit_runner).expect("loop error");
|
||||||
};
|
|
||||||
evloop.run_app(&mut winit_runner)
|
|
||||||
.expect("loop error");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WinitRunner {
|
struct WinitRunner {
|
||||||
app: App
|
app: App,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler for WinitRunner {
|
impl ApplicationHandler for WinitRunner {
|
||||||
fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||||
self.app.update();
|
self.app.update();
|
||||||
|
|
||||||
let renderer = self.app.renderer.get_mut().expect("renderer was not initialized");
|
let renderer = self
|
||||||
|
.app
|
||||||
|
.renderer
|
||||||
|
.get_mut()
|
||||||
|
.expect("renderer was not initialized");
|
||||||
renderer.prepare(&mut self.app.world);
|
renderer.prepare(&mut self.app.world);
|
||||||
|
|
||||||
if let Some(mut event_queue) = self.app.world.try_get_resource_mut::<EventQueue>() {
|
|
||||||
event_queue.update_events();
|
|
||||||
}
|
|
||||||
|
|
||||||
match renderer.render() {
|
match renderer.render() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
// Reconfigure the surface if lost
|
// Reconfigure the surface if lost
|
||||||
|
@ -149,86 +171,107 @@ impl ApplicationHandler for WinitRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn device_event(
|
||||||
|
&mut self,
|
||||||
|
_: &ActiveEventLoop,
|
||||||
|
device_src: winit::event::DeviceId,
|
||||||
|
event: winit::event::DeviceEvent,
|
||||||
|
) {
|
||||||
|
self.app.push_event(DeviceEventPair { device_src, event });
|
||||||
|
}
|
||||||
|
|
||||||
fn window_event(
|
fn window_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
event_loop: &winit::event_loop::ActiveEventLoop,
|
event_loop: &winit::event_loop::ActiveEventLoop,
|
||||||
window_id: winit::window::WindowId,
|
window_id: winit::window::WindowId,
|
||||||
event: WindowEvent,
|
event: WindowEvent,
|
||||||
) {
|
) {
|
||||||
let windows = self.app.world.get_resource::<WinitWindows>();
|
/* let windows = self.app.world.get_resource::<WinitWindows>();
|
||||||
let window = match windows.windows.get(&window_id) {
|
let window = match windows.windows.get(&window_id) {
|
||||||
Some(w) => w.clone(),
|
Some(w) => w.clone(),
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
drop(windows);
|
drop(windows); */
|
||||||
|
|
||||||
// If try_from failed, that means that the WindowEvent is not an
|
|
||||||
// input related event.
|
|
||||||
if let Some(input_ev) = InputEvent::from_window_event(&event) {
|
|
||||||
// Its possible to receive multiple input events before the update event for
|
|
||||||
// the InputSystem is called, so we must use a queue for the events.
|
|
||||||
if let Some(mut event_queue) = self.app.world.try_get_resource_mut::<EventQueue>() {
|
|
||||||
event_queue.trigger_event(input_ev.clone());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
self.app.push_event(event.clone());
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::ActivationTokenDone { serial, token } => todo!(),
|
WindowEvent::ActivationTokenDone { .. } => todo!(),
|
||||||
WindowEvent::Resized(physical_size) => {
|
WindowEvent::Resized(physical_size) => {
|
||||||
self.app.on_resize(physical_size);
|
self.app.on_resize(physical_size);
|
||||||
|
|
||||||
let mut window_opts = self.app.world.get_resource::<WinitWindows>()
|
let mut window_opts = self
|
||||||
.window_to_entity.get(&window_id)
|
.app
|
||||||
|
.world
|
||||||
|
.get_resource::<WinitWindows>()
|
||||||
|
.window_to_entity
|
||||||
|
.get(&window_id)
|
||||||
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
window_opts.size = Size::new_physical(physical_size.width, physical_size.height);
|
window_opts.size = Size::new_physical(physical_size.width, physical_size.height);
|
||||||
},
|
}
|
||||||
WindowEvent::Moved(physical_position) => {
|
WindowEvent::Moved(physical_position) => {
|
||||||
let mut state = self.app.world.get_resource_or_else(WindowState::new);
|
let mut state = self.app.world.get_resource_or_else(WindowState::new);
|
||||||
state.position = IVec2::new(physical_position.x, physical_position.y);
|
state.position = IVec2::new(physical_position.x, physical_position.y);
|
||||||
},
|
}
|
||||||
WindowEvent::CloseRequested => {
|
WindowEvent::CloseRequested => {
|
||||||
self.app.on_exit();
|
self.app.on_exit();
|
||||||
event_loop.exit();
|
event_loop.exit();
|
||||||
},
|
}
|
||||||
WindowEvent::Destroyed => todo!(),
|
WindowEvent::Destroyed => todo!(),
|
||||||
WindowEvent::DroppedFile(path_buf) => todo!(),
|
WindowEvent::DroppedFile(_path_buf) => todo!(),
|
||||||
WindowEvent::HoveredFile(path_buf) => todo!(),
|
WindowEvent::HoveredFile(_path_buf) => todo!(),
|
||||||
WindowEvent::HoveredFileCancelled => todo!(),
|
WindowEvent::HoveredFileCancelled => todo!(),
|
||||||
WindowEvent::Focused(focused) => {
|
WindowEvent::Focused(focused) => {
|
||||||
let mut window_opts = self.app.world.get_resource::<WinitWindows>()
|
let mut window_opts = self
|
||||||
.window_to_entity.get(&window_id)
|
.app
|
||||||
|
.world
|
||||||
|
.get_resource::<WinitWindows>()
|
||||||
|
.window_to_entity
|
||||||
|
.get(&window_id)
|
||||||
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
window_opts.focused = focused;
|
window_opts.focused = focused;
|
||||||
},
|
}
|
||||||
WindowEvent::ModifiersChanged(modifiers) => debug!("modifiers changed: {:?}", modifiers),
|
WindowEvent::ModifiersChanged(modifiers) => {
|
||||||
|
debug!("modifiers changed: {:?}", modifiers)
|
||||||
|
}
|
||||||
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
|
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
|
||||||
let mut window_opts = self.app.world.get_resource::<WinitWindows>()
|
let mut window_opts = self
|
||||||
.window_to_entity.get(&window_id)
|
.app
|
||||||
|
.world
|
||||||
|
.get_resource::<WinitWindows>()
|
||||||
|
.window_to_entity
|
||||||
|
.get(&window_id)
|
||||||
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
window_opts.scale_factor = scale_factor;
|
window_opts.scale_factor = scale_factor;
|
||||||
},
|
}
|
||||||
WindowEvent::ThemeChanged(theme) => {
|
WindowEvent::ThemeChanged(theme) => {
|
||||||
let mut window_opts = self.app.world.get_resource::<WinitWindows>()
|
let mut window_opts = self
|
||||||
.window_to_entity.get(&window_id)
|
.app
|
||||||
|
.world
|
||||||
|
.get_resource::<WinitWindows>()
|
||||||
|
.window_to_entity
|
||||||
|
.get(&window_id)
|
||||||
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
window_opts.theme = Some(theme);
|
window_opts.theme = Some(theme);
|
||||||
},
|
}
|
||||||
WindowEvent::Occluded(occ) => {
|
WindowEvent::Occluded(occ) => {
|
||||||
let mut window_opts = self.app.world.get_resource::<WinitWindows>()
|
let mut window_opts = self
|
||||||
.window_to_entity.get(&window_id)
|
.app
|
||||||
|
.world
|
||||||
|
.get_resource::<WinitWindows>()
|
||||||
|
.window_to_entity
|
||||||
|
.get(&window_id)
|
||||||
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
window_opts.occluded = occ;
|
window_opts.occluded = occ;
|
||||||
},
|
}
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
//debug!("should redraw");
|
//debug!("should redraw");
|
||||||
},
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
Loading…
Reference in New Issue