engine: move winit ApplicationHandler to winit plugin

This commit is contained in:
SeanOMik 2024-09-19 17:30:30 -04:00
parent 8b1077cab7
commit 2107b8f7b0
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
3 changed files with 115 additions and 158 deletions

View File

@ -1,10 +1,8 @@
use std::{cell::OnceCell, collections::VecDeque, ptr::NonNull, sync::Arc};
use std::{cell::OnceCell, collections::VecDeque, ptr::NonNull};
use async_std::task::block_on;
use lyra_ecs::{system::{IntoSystem, System}, ResourceObject, World};
use lyra_math::{IVec2, Vec2};
use rustc_hash::FxHashMap;
use tracing::{debug, debug_span, info, warn, error, Level};
use lyra_math::IVec2;
use tracing::{info, error, Level};
use tracing_appender::non_blocking;
use tracing_subscriber::{
layer::SubscriberExt,
@ -12,9 +10,7 @@ use tracing_subscriber::{
util::SubscriberInitExt, fmt,
};
use winit::{application::ApplicationHandler, event::{DeviceEvent, ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, keyboard::{Key, NamedKey}, window::{Window, WindowId}};
use crate::{change_tracker::Ct, input::InputEvent, plugin::Plugin, render::{renderer::{BasicRenderer, Renderer}, window::{PrimaryWindow, WindowOptions}}, winit::WinitWindows, EventQueue, Stage, StagedExecutor};
use crate::{plugin::Plugin, render::renderer::Renderer, Stage, StagedExecutor};
#[derive(Clone, Copy, Hash, Debug)]
pub enum GameStages {
@ -54,8 +50,7 @@ impl WindowState {
}
pub struct App {
windows: FxHashMap<WindowId, Arc<Window>>,
renderer: OnceCell<Box<dyn Renderer>>,
pub(crate) renderer: OnceCell<Box<dyn Renderer>>,
pub world: World,
plugins: VecDeque<Box<dyn Plugin>>,
startup_systems: VecDeque<Box<dyn System>>,
@ -97,7 +92,6 @@ impl App {
staged.add_stage_after(GameStages::PostUpdate, GameStages::Last);
Self {
windows: FxHashMap::default(),
renderer: OnceCell::new(),
world,
plugins: Default::default(),
@ -115,13 +109,13 @@ impl App {
}
}
fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
pub(crate) fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
self.renderer.get_mut()
.expect("renderer was not initialized")
.on_resize(&mut self.world, new_size);
}
fn on_exit(&mut self) {
pub(crate) fn on_exit(&mut self) {
info!("On exit!");
}
@ -221,109 +215,3 @@ impl App {
f(self);
}
}
impl ApplicationHandler for App {
fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
debug!("update now");
self.update();
let renderer = self.renderer.get_mut().expect("renderer was not initialized");
renderer.prepare(&mut self.world);
if let Some(mut event_queue) = self.world.try_get_resource_mut::<EventQueue>() {
event_queue.update_events();
}
match renderer.render() {
Ok(_) => {}
// Reconfigure the surface if lost
//Err(wgpu::SurfaceError::Lost) => self.on_resize(.surface_size()),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
error!("OOM");
event_loop.exit();
}
// All other errors (Outdated, Timeout) should be resolved by the next frame
Err(e) => eprintln!("{:?}", e),
}
}
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
let world = &mut self.world;
let en = world.spawn((WindowOptions::default(), PrimaryWindow));
let attr = Window::default_attributes();
let mut windows = world.get_resource_mut::<WinitWindows>();
let wid = windows.create_window(event_loop, en, attr).unwrap();
let window = windows.windows.get(&wid).unwrap().clone();
drop(windows);
let renderer = block_on(BasicRenderer::create_with_window(world, window));
if self.renderer.set(Box::new(renderer)).is_err() {
warn!("renderer was re-initialized");
}
}
fn window_event(
&mut self,
event_loop: &winit::event_loop::ActiveEventLoop,
window_id: winit::window::WindowId,
event: WindowEvent,
) {
//let _e = debug_span!("window_event", window=window_id).entered();
let windows = self.world.get_resource::<WinitWindows>();
let window = match windows.windows.get(&window_id) {
Some(w) => w.clone(),
None => return,
};
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.world.try_get_resource_mut::<EventQueue>() {
event_queue.trigger_event(input_ev.clone());
}
} else {
match event {
WindowEvent::ActivationTokenDone { serial, token } => todo!(),
WindowEvent::Resized(physical_size) => {
self.on_resize(physical_size);
},
WindowEvent::Moved(physical_position) => {
let mut state = self.world.get_resource_or_else(WindowState::new);
state.position = IVec2::new(physical_position.x, physical_position.y);
},
WindowEvent::CloseRequested => {
self.on_exit();
event_loop.exit();
},
WindowEvent::Destroyed => todo!(),
WindowEvent::DroppedFile(path_buf) => todo!(),
WindowEvent::HoveredFile(path_buf) => todo!(),
WindowEvent::HoveredFileCancelled => todo!(),
WindowEvent::Focused(focused) => {
let mut state = self.world.get_resource_or_else(WindowState::new);
state.focused = focused;
},
WindowEvent::ModifiersChanged(modifiers) => debug!("modifiers changed: {:?}", modifiers),
WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer } => {
info!("changed scale to {scale_factor}");
},
WindowEvent::ThemeChanged(theme) => todo!(),
WindowEvent::Occluded(occ) => {
let mut state = self.world.get_resource_or_else(WindowState::new);
state.occluded = occ;
},
WindowEvent::RedrawRequested => {
debug!("should redraw");
},
_ => {}
}
}
}
}

View File

@ -1,9 +1,3 @@
use std::cell::Cell;
use std::cell::OnceCell;
use std::cell::RefCell;
use std::ptr::NonNull;
use lyra_ecs::system::System;
use lyra_ecs::CommandQueue;
use lyra_resource::ResourceManager;
@ -41,18 +35,6 @@ impl<P> Plugin for P
}
}
/// An ECS system converted to a plugin.
///
/// The system is executed in plugin setup phase.
pub(crate) struct SystemPlugin<S: System>(pub RefCell<S>);
impl<S: System> Plugin for SystemPlugin<S> {
fn setup(&self, app: &mut App) {
let mut s = self.0.borrow_mut();
s.execute(NonNull::from(&app.world));
}
}
/// Represents a set of plugins that will be executed in order they are supplied.
#[derive(Default)]
pub struct PluginSet {

View File

@ -1,11 +1,13 @@
use std::sync::Arc;
use async_std::task::block_on;
use glam::IVec2;
use lyra_ecs::Entity;
use rustc_hash::FxHashMap;
use tracing::debug;
use winit::{application::ApplicationHandler, event_loop::{ActiveEventLoop, EventLoop}, window::{Window, WindowAttributes, WindowId}};
use tracing::{debug, error, info, warn};
use winit::{application::ApplicationHandler, event::WindowEvent, event_loop::{ActiveEventLoop, EventLoop}, window::{Window, WindowAttributes, WindowId}};
use crate::{game::App, plugin::Plugin, render::window::WindowOptions};
use crate::{game::{App, WindowState}, input::InputEvent, plugin::Plugin, render::{renderer::BasicRenderer, window::{PrimaryWindow, WindowOptions}}, EventQueue};
#[derive(Default)]
pub struct WinitPlugin;
@ -16,15 +18,15 @@ impl Plugin for WinitPlugin {
app.add_resource(WinitWindows::default());
}
fn is_ready(&self, app: &mut crate::game::App) -> bool {
fn is_ready(&self, _app: &mut crate::game::App) -> bool {
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) {
}
}
@ -52,37 +54,122 @@ impl WinitWindows {
}
}
pub fn winit_app_runner(mut app: App) {
pub fn winit_app_runner(app: App) {
let evloop = EventLoop::new()
.expect("failed to create winit EventLoop");
evloop.run_app(&mut app)
let mut winit_runner = WinitRunner {
app,
};
evloop.run_app(&mut winit_runner)
.expect("loop error");
}
/* struct WinitRunner {
struct WinitRunner {
app: App
}
impl ApplicationHandler for WinitRunner {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
debug!("resumed")
fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
debug!("update now");
self.app.update();
let renderer = self.app.renderer.get_mut().expect("renderer was not initialized");
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() {
Ok(_) => {}
// Reconfigure the surface if lost
//Err(wgpu::SurfaceError::Lost) => self.on_resize(.surface_size()),
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
error!("OOM");
event_loop.exit();
}
// All other errors (Outdated, Timeout) should be resolved by the next frame
Err(e) => eprintln!("{:?}", e),
}
}
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
let world = &mut self.app.world;
let en = world.spawn((WindowOptions::default(), PrimaryWindow));
let attr = Window::default_attributes();
let mut windows = world.get_resource_mut::<WinitWindows>();
let wid = windows.create_window(event_loop, en, attr).unwrap();
let window = windows.windows.get(&wid).unwrap().clone();
drop(windows);
let renderer = block_on(BasicRenderer::create_with_window(world, window));
if self.app.renderer.set(Box::new(renderer)).is_err() {
warn!("renderer was re-initialized");
}
}
fn window_event(
&mut self,
event_loop: &ActiveEventLoop,
window_id: WindowId,
event: winit::event::WindowEvent,
event_loop: &winit::event_loop::ActiveEventLoop,
window_id: winit::window::WindowId,
event: WindowEvent,
) {
let world = &mut self.app.world;
let mut windows = world.get_resource_mut::<WinitWindows>();
let window = match windows.windows.get_mut(&window_id) {
Some(w) => w,
let windows = self.app.world.get_resource::<WinitWindows>();
let window = match windows.windows.get(&window_id) {
Some(w) => w.clone(),
None => return,
};
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 {
match event {
WindowEvent::ActivationTokenDone { serial, token } => todo!(),
WindowEvent::Resized(physical_size) => {
self.app.on_resize(physical_size);
},
WindowEvent::Moved(physical_position) => {
let mut state = self.app.world.get_resource_or_else(WindowState::new);
state.position = IVec2::new(physical_position.x, physical_position.y);
},
WindowEvent::CloseRequested => {
self.app.on_exit();
event_loop.exit();
},
WindowEvent::Destroyed => todo!(),
WindowEvent::DroppedFile(path_buf) => todo!(),
WindowEvent::HoveredFile(path_buf) => todo!(),
WindowEvent::HoveredFileCancelled => todo!(),
WindowEvent::Focused(focused) => {
let mut state = self.app.world.get_resource_or_else(WindowState::new);
state.focused = focused;
},
WindowEvent::ModifiersChanged(modifiers) => debug!("modifiers changed: {:?}", modifiers),
WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer } => {
info!("changed scale to {scale_factor}");
},
WindowEvent::ThemeChanged(theme) => todo!(),
WindowEvent::Occluded(occ) => {
let mut state = self.app.world.get_resource_or_else(WindowState::new);
state.occluded = occ;
},
WindowEvent::RedrawRequested => {
debug!("should redraw");
},
_ => {}
}
}
}
}
} */