update wgpu and winit to latest versions

need to make a WinitPlugin though, so no window currently
This commit is contained in:
SeanOMik 2024-09-18 19:47:55 -04:00
parent 2b44d7f354
commit 45fd190409
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
39 changed files with 7232 additions and 1647 deletions

2658
Cargo.lock generated

File diff suppressed because it is too large Load Diff

4999
Cargo.lock.old Normal file

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@ use tracing::info;
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let action_handler_plugin = |game: &mut Game| { let action_handler_plugin = |app: &mut App| {
let action_handler = ActionHandler::builder() let action_handler = ActionHandler::builder()
.add_layout(LayoutId::from(0)) .add_layout(LayoutId::from(0))
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis)) .add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
@ -105,7 +105,7 @@ async fn main() {
.await; .await;
} }
fn setup_scene_plugin(game: &mut Game) { fn setup_scene_plugin(app: &mut App) {
let world = game.world_mut(); let world = game.world_mut();
let resman = world.get_resource_mut::<ResourceManager>(); let resman = world.get_resource_mut::<ResourceManager>();
let camera_gltf = resman let camera_gltf = resman

View File

@ -18,7 +18,7 @@ use lyra_engine::{
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let action_handler_plugin = |game: &mut Game| { let action_handler_plugin = |app: &mut App| {
let action_handler = ActionHandler::builder() let action_handler = ActionHandler::builder()
.add_layout(LayoutId::from(0)) .add_layout(LayoutId::from(0))
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis)) .add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
@ -99,7 +99,7 @@ async fn main() {
.await; .await;
} }
fn setup_scene_plugin(game: &mut Game) { fn setup_scene_plugin(app: &mut App) {
let world = game.world_mut(); let world = game.world_mut();
let resman = world.get_resource_mut::<ResourceManager>(); let resman = world.get_resource_mut::<ResourceManager>();
let camera_gltf = resman let camera_gltf = resman
@ -136,7 +136,7 @@ fn setup_scene_plugin(game: &mut Game) {
world.spawn((camera, FreeFlyCamera::default())); world.spawn((camera, FreeFlyCamera::default()));
} }
fn setup_script_plugin(game: &mut Game) { fn setup_script_plugin(app: &mut App) {
game.with_plugin(LuaScriptingPlugin); game.with_plugin(LuaScriptingPlugin);
let world = game.world_mut(); let world = game.world_mut();

View File

@ -21,7 +21,7 @@ const POINT_LIGHT_MIN_Z: f32 = -5.0;
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let action_handler_plugin = |game: &mut Game| { let action_handler_plugin = |app: &mut App| {
let action_handler = ActionHandler::builder() let action_handler = ActionHandler::builder()
.add_layout(LayoutId::from(0)) .add_layout(LayoutId::from(0))
@ -80,7 +80,7 @@ async fn main() {
.run().await; .run().await;
} }
fn setup_scene_plugin(game: &mut Game) { fn setup_scene_plugin(app: &mut App) {
let fps_counter = |mut counter: ResMut<fps_counter::FPSCounter>, delta: Res<DeltaTime>| -> anyhow::Result<()> { let fps_counter = |mut counter: ResMut<fps_counter::FPSCounter>, delta: Res<DeltaTime>| -> anyhow::Result<()> {
let tick = counter.tick(); let tick = counter.tick();
@ -174,7 +174,7 @@ fn setup_scene_plugin(game: &mut Game) {
world.spawn(( camera, FreeFlyCamera::default() )); world.spawn(( camera, FreeFlyCamera::default() ));
} }
fn camera_debug_plugin(game: &mut Game) { fn camera_debug_plugin(app: &mut App) {
let sys = |handler: Res<ActionHandler>, view: View<&mut CameraComponent>| -> anyhow::Result<()> { let sys = |handler: Res<ActionHandler>, view: View<&mut CameraComponent>| -> anyhow::Result<()> {
if handler.was_action_just_pressed("Debug") { if handler.was_action_just_pressed("Debug") {
for mut cam in view.into_iter() { for mut cam in view.into_iter() {

View File

@ -19,7 +19,7 @@ use lyra_engine::{
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let action_handler_plugin = |game: &mut Game| { let action_handler_plugin = |app: &mut App| {
let action_handler = ActionHandler::builder() let action_handler = ActionHandler::builder()
.add_layout(LayoutId::from(0)) .add_layout(LayoutId::from(0))
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis)) .add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
@ -99,7 +99,7 @@ async fn main() {
.await; .await;
} }
fn setup_scene_plugin(game: &mut Game) { fn setup_scene_plugin(app: &mut App) {
let world = game.world_mut(); let world = game.world_mut();
let resman = world.get_resource_mut::<ResourceManager>(); let resman = world.get_resource_mut::<ResourceManager>();

View File

@ -1,6 +1,6 @@
use lyra_engine::{ use lyra_engine::{
assets::{gltf::Gltf, ResourceManager}, assets::{gltf::Gltf, ResourceManager},
game::Game, game::App,
input::{ input::{
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput, InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput,
@ -16,7 +16,7 @@ use lyra_engine::{
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let action_handler_plugin = |game: &mut Game| { let action_handler_plugin = |app: &mut App| {
let action_handler = ActionHandler::builder() let action_handler = ActionHandler::builder()
.add_layout(LayoutId::from(0)) .add_layout(LayoutId::from(0))
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis)) .add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
@ -31,61 +31,61 @@ async fn main() {
.bind( .bind(
ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_FORWARD_BACKWARD,
&[ &[
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::KeyW).into_binding_modifier(1.0),
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::KeyS).into_binding_modifier(-1.0),
], ],
) )
.bind( .bind(
ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_LEFT_RIGHT,
&[ &[
ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::KeyA).into_binding_modifier(-1.0),
ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::KeyD).into_binding_modifier(1.0),
], ],
) )
.bind( .bind(
ACTLBL_MOVE_UP_DOWN, ACTLBL_MOVE_UP_DOWN,
&[ &[
ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::KeyC).into_binding_modifier(1.0),
ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::KeyZ).into_binding_modifier(-1.0),
], ],
) )
.bind( .bind(
ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_LEFT_RIGHT,
&[ &[
ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(), ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(),
ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::ArrowLeft).into_binding_modifier(-1.0),
ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::ArrowRight).into_binding_modifier(1.0),
], ],
) )
.bind( .bind(
ACTLBL_LOOK_UP_DOWN, ACTLBL_LOOK_UP_DOWN,
&[ &[
ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(), ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(),
ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::ArrowUp).into_binding_modifier(-1.0),
ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::ArrowDown).into_binding_modifier(1.0),
], ],
) )
.bind( .bind(
ACTLBL_LOOK_ROLL, ACTLBL_LOOK_ROLL,
&[ &[
ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::KeyE).into_binding_modifier(-1.0),
ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::KeyQ).into_binding_modifier(1.0),
], ],
) )
.bind( .bind(
"Debug", "Debug",
&[ActionSource::Keyboard(KeyCode::B).into_binding()], &[ActionSource::Keyboard(KeyCode::KeyB).into_binding()],
) )
.finish(), .finish(),
) )
.finish(); .finish();
let world = game.world_mut(); let world = app.world_mut();
world.add_resource(action_handler); world.add_resource(action_handler);
game.with_plugin(InputActionPlugin); app.with_plugin(InputActionPlugin);
}; };
Game::initialize() App::initialize()
.await .await
.with_plugin(lyra_engine::DefaultPlugins) .with_plugin(lyra_engine::DefaultPlugins)
.with_plugin(setup_scene_plugin) .with_plugin(setup_scene_plugin)
@ -96,7 +96,7 @@ async fn main() {
.await; .await;
} }
fn setup_scene_plugin(game: &mut Game) { fn setup_scene_plugin(app: &mut App) {
let world = game.world_mut(); let world = game.world_mut();
let resman = world.get_resource_mut::<ResourceManager>(); let resman = world.get_resource_mut::<ResourceManager>();

View File

@ -260,7 +260,7 @@ async fn main() {
Ok(()) Ok(())
}; };
let camera_debug_plugin = move |game: &mut Game| { let camera_debug_plugin = move |app: &mut App| {
let sys = |handler: Res<ActionHandler>, view: View<&mut CameraComponent>| -> anyhow::Result<()> { let sys = |handler: Res<ActionHandler>, view: View<&mut CameraComponent>| -> anyhow::Result<()> {
if handler.was_action_just_pressed("Debug") { if handler.was_action_just_pressed("Debug") {
for mut cam in view.into_iter() { for mut cam in view.into_iter() {
@ -275,7 +275,7 @@ async fn main() {
game.with_system("update_world_transforms", scene::system_update_world_transforms, &[]); game.with_system("update_world_transforms", scene::system_update_world_transforms, &[]);
}; };
let action_handler_plugin = |game: &mut Game| { let action_handler_plugin = |app: &mut App| {
let action_handler = ActionHandler::builder() let action_handler = ActionHandler::builder()
.add_layout(LayoutId::from(0)) .add_layout(LayoutId::from(0))
@ -327,7 +327,7 @@ async fn main() {
game.with_plugin(InputActionPlugin); game.with_plugin(InputActionPlugin);
}; };
/* let script_test_plugin = |game: &mut Game| { /* let script_test_plugin = |app: &mut App| {
game.with_plugin(LuaScriptingPlugin); game.with_plugin(LuaScriptingPlugin);
let world = game.world_mut(); let world = game.world_mut();

View File

@ -197,11 +197,9 @@ mod tests {
let mut view_iter = view.into_iter(); let mut view_iter = view.into_iter();
while let Some((_e, view_row)) = view_iter.next(&world) { while let Some((_e, view_row)) = view_iter.next(&world) {
assert_eq!(view_row.len(), 1); assert_eq!(view_row.len(), 1);
let mut row_iter = view_row.iter();
let mut row_iter = view_row.row.iter();
let dynamic_type = row_iter.next().unwrap(); let dynamic_type = row_iter.next().unwrap();
let component_data = unsafe { dynamic_type.ptr.cast::<u32>().as_ref() }; let component_data = unsafe { dynamic_type.ptr.cast::<u32>().as_ref() };
assert_eq!(*component_data, 50); assert_eq!(*component_data, 50);
} }
@ -226,11 +224,9 @@ mod tests {
for (_e, view_row) in view.into_iter() { for (_e, view_row) in view.into_iter() {
assert_eq!(view_row.len(), 1); assert_eq!(view_row.len(), 1);
let mut row_iter = view_row.iter();
let mut row_iter = view_row.row.iter();
let dynamic_type = row_iter.next().unwrap(); let dynamic_type = row_iter.next().unwrap();
let component_data = unsafe { dynamic_type.ptr.cast::<u32>().as_ref() }; let component_data = unsafe { dynamic_type.ptr.cast::<u32>().as_ref() };
assert_eq!(*component_data, 50); assert_eq!(*component_data, 50);
} }

View File

@ -12,31 +12,30 @@ lyra-math = { path = "../lyra-math" }
lyra-scene = { path = "../lyra-scene" } lyra-scene = { path = "../lyra-scene" }
wgsl_preprocessor = { path = "../wgsl-preprocessor" } wgsl_preprocessor = { path = "../wgsl-preprocessor" }
winit = "0.28.1" winit = "0.30.5"
wgpu = { version = "0.15.1", features = [ "expose-ids"] } wgpu = { version = "22.1.0" }
tracing = "0.1.37" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.16", features = [ "tracing-log" ] } tracing-subscriber = { version = "0.3.16", features = [ "tracing-log" ] }
tracing-log = "0.1.3" tracing-log = "0.2.0"
tracing-appender = "0.2.2" tracing-appender = "0.2.2"
tracing-tracy = { version = "0.11.0", optional = true } tracing-tracy = { version = "0.11.0", optional = true }
async-std = { version = "1.12.0", features = [ "unstable", "attributes" ] } async-std = { version = "1.12.0", features = [ "unstable", "attributes" ] }
cfg-if = "1" cfg-if = "1"
bytemuck = { version = "1.12", features = [ "derive", "min_const_generics" ] } bytemuck = { version = "1.12", features = [ "derive", "min_const_generics" ] }
image = { version = "0.24", default-features = false, features = ["png", "jpeg"] } image = "0.25.2"
anyhow = "1.0" anyhow = "1.0"
instant = "0.1" instant = "0.1"
async-trait = "0.1.65" async-trait = "0.1.65"
glam = { version = "0.24.0", features = ["bytemuck", "debug-glam-assert"] } glam = { version = "0.29.0", features = ["bytemuck", "debug-glam-assert"] }
gilrs-core = "0.5.6"
syn = "2.0.26" syn = "2.0.26"
quote = "1.0.29" quote = "1.0.29"
uuid = { version = "1.5.0", features = ["v4", "fast-rng"] } uuid = { version = "1.5.0", features = ["v4", "fast-rng"] }
itertools = "0.11.0" itertools = "0.13.0"
thiserror = "1.0.56" thiserror = "1.0.56"
unique = "0.9.1" unique = "0.9.1"
rustc-hash = "1.1.0" rustc-hash = "2.0.0"
petgraph = { version = "0.6.5", features = ["matrix_graph"] } 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"

View File

@ -42,8 +42,8 @@ pub fn delta_time_system(world: &mut World) -> anyhow::Result<()> {
pub struct DeltaTimePlugin; pub struct DeltaTimePlugin;
impl Plugin for DeltaTimePlugin { impl Plugin for DeltaTimePlugin {
fn setup(&self, game: &mut crate::game::Game) { fn setup(&self, app: &mut crate::game::App) {
game.world_mut().add_resource(DeltaTime(0.0, None)); app.world.add_resource(DeltaTime(0.0, None));
game.add_system_to_stage(GameStages::First, "delta_time", delta_time_system, &[]); app.add_system_to_stage(GameStages::First, "delta_time", delta_time_system, &[]);
} }
} }

View File

@ -196,7 +196,7 @@ impl<E: Event> Iterator for EventReader<E> {
pub struct EventsPlugin; pub struct EventsPlugin;
impl Plugin for EventsPlugin { impl Plugin for EventsPlugin {
fn setup(&self, game: &mut crate::game::Game) { fn setup(&self, app: &mut crate::game::App) {
game.world_mut().add_resource(EventQueue::new()); app.world.add_resource(EventQueue::new());
} }
} }

View File

@ -1,9 +1,9 @@
use std::{sync::Arc, collections::VecDeque, ptr::NonNull}; use std::{cell::OnceCell, collections::VecDeque, ptr::NonNull, sync::Arc};
use async_std::task::block_on; use lyra_ecs::{system::{IntoSystem, System}, ResourceObject, World};
use lyra_math::{IVec2, Vec2};
use lyra_ecs::{World, system::{System, IntoSystem}}; use rustc_hash::FxHashMap;
use tracing::{error, info, Level}; use tracing::{debug, debug_span, info, Level};
use tracing_appender::non_blocking; use tracing_appender::non_blocking;
use tracing_subscriber::{ use tracing_subscriber::{
layer::SubscriberExt, layer::SubscriberExt,
@ -11,7 +11,7 @@ use tracing_subscriber::{
util::SubscriberInitExt, fmt, util::SubscriberInitExt, fmt,
}; };
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, DeviceEvent}, event_loop::{EventLoop, ControlFlow}}; use winit::{application::ApplicationHandler, event::{DeviceEvent, ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, keyboard::{Key, NamedKey}, window::{Window, WindowId}};
use crate::{render::{renderer::{Renderer, BasicRenderer}, window::WindowOptions}, input::InputEvent, plugin::Plugin, change_tracker::Ct, EventQueue, StagedExecutor, Stage}; use crate::{render::{renderer::{Renderer, BasicRenderer}, window::WindowOptions}, input::InputEvent, plugin::Plugin, change_tracker::Ct, EventQueue, StagedExecutor, Stage};
@ -37,8 +37,13 @@ pub struct Controls<'a> {
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct WindowState { pub struct WindowState {
pub is_focused: bool, /// Indicates if the window is currently focused.
pub is_cursor_inside_window: bool, pub focused: bool,
/// Indicates if the window is currently occluded.
pub occluded: bool,
/// Indicates if the cursor is inside of the window.
pub cursor_inside_window: bool,
pub position: IVec2,
} }
impl WindowState { impl WindowState {
@ -47,216 +52,41 @@ impl WindowState {
} }
} }
struct GameLoop { pub struct App {
window: Arc<Window>, windows: FxHashMap<WindowId, Arc<Window>>,
renderer: Box<dyn Renderer>, renderer: OnceCell<Box<dyn Renderer>>,
pub world: World,
world: World, plugins: VecDeque<Box<dyn Plugin>>,
startup_systems: VecDeque<Box<dyn System>>,
staged_exec: StagedExecutor, staged_exec: StagedExecutor,
run_fn: OnceCell<Box<dyn FnOnce(App)>>,
} }
impl GameLoop { impl App {
pub async fn new(window: Arc<Window>, mut world: World, staged_exec: StagedExecutor) -> Self { pub fn new() -> Self {
let renderer = BasicRenderer::create_with_window(&mut world, window.clone()).await;
Self { Self {
window: Arc::clone(&window), windows: FxHashMap::default(),
renderer: Box::new(renderer), renderer: OnceCell::new(),
world: World::new(),
world, plugins: Default::default(),
staged_exec, startup_systems: Default::default(),
staged_exec: StagedExecutor::new(),
run_fn: OnceCell::new(),
} }
} }
pub async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) { fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
self.renderer.on_resize(&mut self.world, new_size); self.renderer.get_mut()
} .expect("renderer was not initialized")
.on_resize(&mut self.world, new_size);
pub async fn on_init(&mut self) {
// Create the EventQueue resource in the world
self.world.add_resource(self.window.clone());
}
pub fn run_sync(&mut self, event: Event<()>, control_flow: &mut ControlFlow) {
block_on(self.run_event_loop(event, control_flow))
}
async fn update(&mut self) {
let world_ptr = NonNull::from(&self.world);
if let Err(e) = self.staged_exec.execute(world_ptr, true) {
error!("Error when executing staged systems: '{}'", e);
}
}
async fn input_update(&mut self, event: &InputEvent) -> Option<ControlFlow> {
match event {
InputEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
..
} => {
self.on_exit();
Some(ControlFlow::Exit)
},
_ => {
//debug!("Got unhandled input event: \"{:?}\"", event);
None
}
}
} }
fn on_exit(&mut self) { fn on_exit(&mut self) {
info!("On exit!"); info!("On exit!");
} }
pub async fn run_event_loop(&mut self, event: Event<'_, ()>, control_flow: &mut ControlFlow) { pub fn add_resource<T: ResourceObject>(&mut self, data: T) {
*control_flow = ControlFlow::Poll; self.world.add_resource(data);
match event {
Event::DeviceEvent { device_id, event: DeviceEvent::MouseMotion { delta } } => {
//debug!("motion: {delta:?}");
// convert a MouseMotion event to an InputEvent
// make sure that the mouse is inside the window and the mouse has focus before reporting mouse motion
/* let trigger = matches!(self.world.get_resource::<WindowState>(), Some(window_state)
if window_state.is_focused && window_state.is_cursor_inside_window); */
let trigger = matches!(self.world.try_get_resource::<Ct<WindowOptions>>(), Some(window)
if window.focused && window.cursor_inside_window);
if trigger {
let mut event_queue = self.world.try_get_resource_mut::<EventQueue>().unwrap();
let input_event = InputEvent::MouseMotion { device_id, delta, };
event_queue.trigger_event(input_event);
}
},
Event::WindowEvent {
ref event,
window_id,
} if window_id == self.window.id() => {
// If try_from failed, that means that the WindowEvent is not an
// input related event.
if let Ok(input_event) = InputEvent::try_from(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_event.clone());
};
}
if let Some(new_control) = self.input_update(&input_event).await {
*control_flow = new_control;
}
} else {
match event {
WindowEvent::CloseRequested => {
self.on_exit();
*control_flow = ControlFlow::Exit
},
WindowEvent::Resized(physical_size) => {
self.on_resize(*physical_size).await;
},
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
self.on_resize(**new_inner_size).await;
},
WindowEvent::Focused(is_focused) => {
let mut state = self.world.get_resource_or_else(WindowState::new);
state.is_focused = *is_focused;
},
_ => {}
}
}
},
Event::RedrawRequested(window_id) if window_id == self.window.id() => {
// Update the world
self.update().await;
/* self.fps_counter.tick();
if let Some(fps) = self.fps_counter.get_change() {
debug!("FPS: {}fps, {:.2}ms/frame", fps, self.fps_counter.get_tick_time());
} */
self.renderer.as_mut().prepare(&mut self.world);
if let Some(mut event_queue) = self.world.try_get_resource_mut::<EventQueue>() {
event_queue.update_events();
}
match self.renderer.as_mut().render() {
Ok(_) => {}
// Reconfigure the surface if lost
Err(wgpu::SurfaceError::Lost) => self.on_resize(self.renderer.as_ref().surface_size()).await,
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
// All other errors (Outdated, Timeout) should be resolved by the next frame
Err(e) => eprintln!("{:?}", e),
}
},
Event::MainEventsCleared => {
self.window.request_redraw();
},
_ => {}
}
}
}
pub struct Game {
world: Option<World>,
plugins: VecDeque<Box<dyn Plugin>>,
system_exec: Option<StagedExecutor>,
startup_systems: VecDeque<Box<dyn System>>,
}
impl Default for Game {
fn default() -> Self {
let mut staged = StagedExecutor::new();
staged.add_stage(GameStages::First);
staged.add_stage_after(GameStages::First, GameStages::PreUpdate);
staged.add_stage_after(GameStages::PreUpdate, GameStages::Update);
staged.add_stage_after(GameStages::Update, GameStages::PostUpdate);
staged.add_stage_after(GameStages::PostUpdate, GameStages::Last);
Self {
world: Some(World::new()),
plugins: VecDeque::new(),
system_exec: Some(staged),
startup_systems: VecDeque::new(),
}
}
}
impl Game {
pub async fn initialize() -> Game {
Self::default()
}
/// Get the world of this game
pub fn world_mut(&mut self) -> &mut World {
// world is always `Some`, so unwrapping is safe
self.world.as_mut().unwrap()
}
/// Get the world of this game
pub fn world(&self) -> &World {
// world is always `Some`, so unwrapping is safe
self.world.as_ref().unwrap()
} }
/// Add a system to the ecs world /// Add a system to the ecs world
@ -265,8 +95,7 @@ impl Game {
S: IntoSystem<A>, S: IntoSystem<A>,
<S as IntoSystem<A>>::System: 'static <S as IntoSystem<A>>::System: 'static
{ {
let system_dispatcher = self.system_exec.as_mut().unwrap(); self.staged_exec.add_system_to_stage(GameStages::Update, name, system.into_system(), depends);
system_dispatcher.add_system_to_stage(GameStages::Update, name, system.into_system(), depends);
self self
} }
@ -275,8 +104,7 @@ impl Game {
/// ///
/// This stage could run at any moment if nothing is dependent on it. /// This stage could run at any moment if nothing is dependent on it.
pub fn add_stage<T: Stage>(&mut self, stage: T) -> &mut Self { pub fn add_stage<T: Stage>(&mut self, stage: T) -> &mut Self {
let system_dispatcher = self.system_exec.as_mut().unwrap(); self.staged_exec.add_stage(stage);
system_dispatcher.add_stage(stage);
self self
} }
@ -287,8 +115,7 @@ impl Game {
/// * `before` - The stage that will run before `after`. /// * `before` - The stage that will run before `after`.
/// * `after` - The stage that will run after `before`. /// * `after` - The stage that will run after `before`.
pub fn add_stage_after<T: Stage, U: Stage>(&mut self, before: T, after: U) -> &mut Self { pub fn add_stage_after<T: Stage, U: Stage>(&mut self, before: T, after: U) -> &mut Self {
let system_dispatcher = self.system_exec.as_mut().unwrap(); self.staged_exec.add_stage_after(before, after);
system_dispatcher.add_stage_after(before, after);
self self
} }
@ -304,8 +131,7 @@ impl Game {
S: IntoSystem<A>, S: IntoSystem<A>,
<S as IntoSystem<A>>::System: 'static <S as IntoSystem<A>>::System: 'static
{ {
let system_dispatcher = self.system_exec.as_mut().unwrap(); self.staged_exec.add_system_to_stage(stage, name, system.into_system(), depends);
system_dispatcher.add_system_to_stage(stage, name, system.into_system(), depends);
self self
} }
@ -337,53 +163,85 @@ impl Game {
/// ///
/// This isn't recommended, you should create a startup system and add it to `with_startup_system` /// This isn't recommended, you should create a startup system and add it to `with_startup_system`
pub fn with_world(&mut self, world: World) -> &mut Self { pub fn with_world(&mut self, world: World) -> &mut Self {
self.world = Some(world); self.world = world;
self self
} }
/// Start the game fn set_run_fn<F>(&self, f: F)
pub async fn run(&mut self) { where
// init logging F: FnOnce(App) + 'static
let (stdout_layer, _stdout_nb) = non_blocking(std::io::stdout());
{ {
let t = tracing_subscriber::registry() // ignore if a runner function was already set
.with(fmt::layer().with_writer(stdout_layer)); let _ = self.run_fn.set(Box::new(f));
#[cfg(feature = "tracy")]
let t = t.with(tracing_tracy::TracyLayer::default());
t.with(filter::Targets::new()
// done by prefix, so it includes all lyra subpackages
.with_target("lyra", Level::DEBUG)
.with_target("wgsl_preprocessor", Level::DEBUG)
.with_target("wgpu", Level::WARN)
.with_target("winit", Level::DEBUG)
.with_default(Level::INFO))
.init();
} }
fn run(mut self) {
let world = self.world.take().unwrap_or_default(); let f = self.run_fn.take()
.expect("No run function set");
// run startup systems f(self);
while let Some(mut startup) = self.startup_systems.pop_front() { }
let startup = startup.as_mut(); }
let world_ptr = NonNull::from(&world);
startup.setup(world_ptr).expect("World returned an error!"); impl ApplicationHandler for App {
startup.execute(world_ptr).expect("World returned an error!"); fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
} debug!("Resumed");
}
// start winit event loops
let event_loop = EventLoop::new(); fn window_event(
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap()); &mut self,
event_loop: &winit::event_loop::ActiveEventLoop,
let system_dispatcher = self.system_exec.take().unwrap(); window_id: winit::window::WindowId,
let mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatcher).await; event: WindowEvent,
g_loop.on_init().await; ) {
//let _e = debug_span!("window_event", window=window_id).entered();
event_loop.run(move |event, _, control_flow| { let window = match self.windows.get_mut(&window_id) {
g_loop.run_sync(event, control_flow); Some(w) => w,
}); None => return,
};
// 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) => todo!(),
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 => todo!(),
_ => {}
}
}
} }
} }

View File

@ -597,7 +597,7 @@ fn actions_system(world: &mut World) -> anyhow::Result<()> {
pub struct InputActionPlugin; pub struct InputActionPlugin;
impl Plugin for InputActionPlugin { impl Plugin for InputActionPlugin {
fn setup(&self, game: &mut crate::game::Game) { fn setup(&self, app: &mut crate::game::App) {
game.add_system_to_stage(GameStages::PreUpdate, "input_actions", actions_system, &[]); app.add_system_to_stage(GameStages::PreUpdate, "input_actions", actions_system, &[]);
} }
} }

View File

@ -88,6 +88,8 @@ pub enum MouseButton {
Left, Left,
Right, Right,
Middle, Middle,
Back,
Forward,
Other(u16), Other(u16),
} }

View File

@ -1,4 +1,4 @@
use winit::{event::{DeviceId, KeyboardInput, ModifiersState, MouseScrollDelta, TouchPhase, MouseButton, AxisId, Touch, WindowEvent, ElementState}, dpi::PhysicalPosition}; use winit::{dpi::PhysicalPosition, event::{AxisId, DeviceId, ElementState, KeyEvent, MouseButton, MouseScrollDelta, Touch, TouchPhase, WindowEvent}};
/// Wrapper around events from `winit::WindowEvent` that are specific to input related events. /// Wrapper around events from `winit::WindowEvent` that are specific to input related events.
/// ///
@ -19,7 +19,7 @@ pub enum InputEvent {
/// An event from the keyboard has been received. /// An event from the keyboard has been received.
KeyboardInput { KeyboardInput {
device_id: DeviceId, device_id: DeviceId,
input: KeyboardInput, event: KeyEvent,
/// If true, the event was generated synthetically by winit in one of the following circumstances: /// If true, the event was generated synthetically by winit in one of the following circumstances:
/// Synthetic key press events are generated for all keys pressed when a window gains focus. /// Synthetic key press events are generated for all keys pressed when a window gains focus.
@ -28,20 +28,10 @@ pub enum InputEvent {
is_synthetic: bool, is_synthetic: bool,
}, },
/// Change in physical position of a pointing device.
/// This represents raw, unfiltered physical motion.
///
/// This is from winit's `DeviceEvent::MouseMotion`
MouseMotion {
device_id: DeviceId,
delta: (f64, f64),
},
/// The cursor has moved on the window. /// The cursor has moved on the window.
CursorMoved { CursorMoved {
device_id: DeviceId, device_id: DeviceId,
position: PhysicalPosition<f64>, position: PhysicalPosition<f64>,
modifiers: ModifiersState,
}, },
/// The cursor has entered the window. /// The cursor has entered the window.
@ -59,8 +49,6 @@ pub enum InputEvent {
device_id: DeviceId, device_id: DeviceId,
delta: MouseScrollDelta, delta: MouseScrollDelta,
phase: TouchPhase, phase: TouchPhase,
/// Deprecated in favor of WindowEvent::ModifiersChanged
modifiers: ModifiersState,
}, },
/// An mouse button press has been received. /// An mouse button press has been received.
@ -68,51 +56,6 @@ pub enum InputEvent {
device_id: DeviceId, device_id: DeviceId,
state: ElementState, state: ElementState,
button: MouseButton, button: MouseButton,
#[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
modifiers: ModifiersState,
},
/// Touchpad magnification event with two-finger pinch gesture.
/// Positive delta values indicate magnification (zooming in) and negative delta values indicate shrinking (zooming out).
///
/// Note: Only available on macOS
TouchpadMagnify {
device_id: DeviceId,
delta: f64,
phase: TouchPhase,
},
/// Smart magnification event.
///
/// On a Mac, smart magnification is triggered by a double tap with two fingers
/// on the trackpad and is commonly used to zoom on a certain object
/// (e.g. a paragraph of a PDF) or (sort of like a toggle) to reset any zoom.
/// The gesture is also supported in Safari, Pages, etc.
///
/// The event is general enough that its generating gesture is allowed to vary
/// across platforms. It could also be generated by another device.
///
/// Unfortunatly, neither [Windows](https://support.microsoft.com/en-us/windows/touch-gestures-for-windows-a9d28305-4818-a5df-4e2b-e5590f850741)
/// nor [Wayland](https://wayland.freedesktop.org/libinput/doc/latest/gestures.html)
/// support this gesture or any other gesture with the same effect.
///
/// ## Platform-specific
///
/// - Only available on **macOS 10.8** and later.
SmartMagnify { device_id: DeviceId },
/// Touchpad rotation event with two-finger rotation gesture.
///
/// Positive delta values indicate rotation counterclockwise and
/// negative delta values indicate rotation clockwise.
///
/// ## Platform-specific
///
/// - Only available on **macOS**.
TouchpadRotate {
device_id: DeviceId,
delta: f32,
phase: TouchPhase,
}, },
/// Touchpad pressure event. /// Touchpad pressure event.
@ -136,89 +79,62 @@ pub enum InputEvent {
/// Touch event has been received /// Touch event has been received
/// ///
/// ## Platform-specific /// ## Platform-specific
/// /// - **Web**: Doesnt take into account CSS border, padding, or transform.
/// - **macOS:** Unsupported. /// - **macOS:** Unsupported.
Touch(Touch), Touch(Touch),
} }
#[derive(Debug, PartialEq)] impl InputEvent {
pub enum InputEventConversionError<'a> { pub fn from_window_event(value: &WindowEvent) -> Option<Self> {
FromError(&'a WindowEvent<'a>)
}
impl<'a> TryFrom<&'a WindowEvent<'a>> for InputEvent {
type Error = InputEventConversionError<'a>;
fn try_from(value: &'a WindowEvent<'a>) -> Result<Self, Self::Error> {
match value { match value {
WindowEvent::KeyboardInput { device_id, input, is_synthetic } => WindowEvent::KeyboardInput { device_id, event, is_synthetic } =>
Ok(InputEvent::KeyboardInput { Some(InputEvent::KeyboardInput {
device_id: *device_id, device_id: *device_id,
input: *input, event: event.clone(),
is_synthetic: *is_synthetic is_synthetic: *is_synthetic
}), }),
#[allow(deprecated, reason="Compatibility")] #[allow(deprecated, reason="Compatibility")]
WindowEvent::CursorMoved { device_id, position, modifiers } => WindowEvent::CursorMoved { device_id, position, } =>
Ok(InputEvent::CursorMoved { Some(InputEvent::CursorMoved {
device_id: *device_id, device_id: *device_id,
position: *position, position: *position,
modifiers: *modifiers
}), }),
WindowEvent::CursorEntered { device_id } => WindowEvent::CursorEntered { device_id } =>
Ok(InputEvent::CursorEntered { Some(InputEvent::CursorEntered {
device_id: *device_id device_id: *device_id
}), }),
WindowEvent::CursorLeft { device_id } => WindowEvent::CursorLeft { device_id } =>
Ok(InputEvent::CursorLeft { Some(InputEvent::CursorLeft {
device_id: *device_id device_id: *device_id
}), }),
#[allow(deprecated, reason="Compatibility")] #[allow(deprecated, reason="Compatibility")]
WindowEvent::MouseWheel { device_id, delta, phase, modifiers } => WindowEvent::MouseWheel { device_id, delta, phase } =>
Ok(InputEvent::MouseWheel { Some(InputEvent::MouseWheel {
device_id: *device_id, device_id: *device_id,
delta: *delta, delta: *delta,
phase: *phase, phase: *phase,
modifiers: *modifiers
}), }),
#[allow(deprecated, reason="Compatibility")] #[allow(deprecated, reason="Compatibility")]
WindowEvent::MouseInput { device_id, state, button, modifiers } => WindowEvent::MouseInput { device_id, state, button } =>
Ok(InputEvent::MouseInput { Some(InputEvent::MouseInput {
device_id: *device_id, device_id: *device_id,
state: *state, state: *state,
button: *button, button: *button,
modifiers: *modifiers
}),
WindowEvent::TouchpadMagnify { device_id, delta, phase } =>
Ok(InputEvent::TouchpadMagnify {
device_id: *device_id,
delta: *delta,
phase: *phase
}),
WindowEvent::SmartMagnify { device_id } =>
Ok(InputEvent::SmartMagnify {
device_id: *device_id
}),
WindowEvent::TouchpadRotate { device_id, delta, phase } =>
Ok(InputEvent::TouchpadRotate {
device_id: *device_id,
delta: *delta,
phase: *phase
}), }),
WindowEvent::TouchpadPressure { device_id, pressure, stage } => WindowEvent::TouchpadPressure { device_id, pressure, stage } =>
Ok(InputEvent::TouchpadPressure { Some(InputEvent::TouchpadPressure {
device_id: *device_id, device_id: *device_id,
pressure: *pressure, pressure: *pressure,
stage: *stage stage: *stage
}), }),
WindowEvent::AxisMotion { device_id, axis, value } => WindowEvent::AxisMotion { device_id, axis, value } =>
Ok(InputEvent::AxisMotion { Some(InputEvent::AxisMotion {
device_id: *device_id, device_id: *device_id,
axis: *axis, axis: *axis,
value: *value value: *value
}), }),
WindowEvent::Touch(t) => Ok(InputEvent::Touch(*t)), WindowEvent::Touch(t) => Some(InputEvent::Touch(*t)),
_ => None,
_ => Err(InputEventConversionError::FromError(value))
} }
} }
} }

View File

@ -13,7 +13,7 @@ pub use buttons::*;
pub mod action; pub mod action;
pub use action::*; pub use action::*;
pub type KeyCode = winit::event::VirtualKeyCode; pub type KeyCode = winit::keyboard::KeyCode;
/// Parses a [`KeyCode`] from a [`&str`]. /// Parses a [`KeyCode`] from a [`&str`].
/// ///
@ -24,42 +24,42 @@ pub fn keycode_from_str(s: &str) -> Option<KeyCode> {
let s = s.as_str(); let s = s.as_str();
match s { match s {
"1" => Some(KeyCode::Key1), "1" => Some(KeyCode::Digit1),
"2" => Some(KeyCode::Key2), "2" => Some(KeyCode::Digit2),
"3" => Some(KeyCode::Key3), "3" => Some(KeyCode::Digit3),
"4" => Some(KeyCode::Key4), "4" => Some(KeyCode::Digit4),
"5" => Some(KeyCode::Key5), "5" => Some(KeyCode::Digit5),
"6" => Some(KeyCode::Key6), "6" => Some(KeyCode::Digit6),
"7" => Some(KeyCode::Key7), "7" => Some(KeyCode::Digit7),
"8" => Some(KeyCode::Key8), "8" => Some(KeyCode::Digit8),
"9" => Some(KeyCode::Key9), "9" => Some(KeyCode::Digit9),
"0" => Some(KeyCode::Key0), "0" => Some(KeyCode::Digit0),
"a" => Some(KeyCode::A), "a" => Some(KeyCode::KeyA),
"b" => Some(KeyCode::B), "b" => Some(KeyCode::KeyB),
"c" => Some(KeyCode::C), "c" => Some(KeyCode::KeyC),
"d" => Some(KeyCode::D), "d" => Some(KeyCode::KeyD),
"e" => Some(KeyCode::E), "e" => Some(KeyCode::KeyE),
"f" => Some(KeyCode::F), "f" => Some(KeyCode::KeyF),
"g" => Some(KeyCode::G), "g" => Some(KeyCode::KeyG),
"h" => Some(KeyCode::H), "h" => Some(KeyCode::KeyH),
"i" => Some(KeyCode::I), "i" => Some(KeyCode::KeyI),
"j" => Some(KeyCode::J), "j" => Some(KeyCode::KeyJ),
"k" => Some(KeyCode::K), "k" => Some(KeyCode::KeyK),
"l" => Some(KeyCode::L), "l" => Some(KeyCode::KeyL),
"m" => Some(KeyCode::M), "m" => Some(KeyCode::KeyM),
"n" => Some(KeyCode::N), "n" => Some(KeyCode::KeyN),
"o" => Some(KeyCode::O), "o" => Some(KeyCode::KeyO),
"p" => Some(KeyCode::P), "p" => Some(KeyCode::KeyP),
"q" => Some(KeyCode::Q), "q" => Some(KeyCode::KeyQ),
"r" => Some(KeyCode::R), "r" => Some(KeyCode::KeyR),
"s" => Some(KeyCode::S), "s" => Some(KeyCode::KeyS),
"t" => Some(KeyCode::T), "t" => Some(KeyCode::KeyT),
"u" => Some(KeyCode::U), "u" => Some(KeyCode::KeyU),
"v" => Some(KeyCode::V), "v" => Some(KeyCode::KeyV),
"w" => Some(KeyCode::W), "w" => Some(KeyCode::KeyW),
"x" => Some(KeyCode::X), "x" => Some(KeyCode::KeyX),
"y" => Some(KeyCode::Y), "y" => Some(KeyCode::KeyY),
"z" => Some(KeyCode::Z), "z" => Some(KeyCode::KeyZ),
"escape" => Some(KeyCode::Escape), "escape" => Some(KeyCode::Escape),
"f1" => Some(KeyCode::F1), "f1" => Some(KeyCode::F1),
"f2" => Some(KeyCode::F2), "f2" => Some(KeyCode::F2),
@ -85,25 +85,23 @@ pub fn keycode_from_str(s: &str) -> Option<KeyCode> {
"f22" => Some(KeyCode::F22), "f22" => Some(KeyCode::F22),
"f23" => Some(KeyCode::F23), "f23" => Some(KeyCode::F23),
"f24" => Some(KeyCode::F24), "f24" => Some(KeyCode::F24),
"snapshot" => Some(KeyCode::Snapshot), "print_screen" => Some(KeyCode::PrintScreen),
"scroll" => Some(KeyCode::Scroll), "scroll_lock" => Some(KeyCode::ScrollLock),
"pause" => Some(KeyCode::Pause), "pause" => Some(KeyCode::Pause),
"insert" => Some(KeyCode::Insert), "insert" => Some(KeyCode::Insert),
"home" => Some(KeyCode::Home), "home" => Some(KeyCode::Home),
"delete" => Some(KeyCode::Delete), "delete" => Some(KeyCode::Delete),
"end" => Some(KeyCode::End), "end" => Some(KeyCode::End),
"pagedown" => Some(KeyCode::PageDown), "page_down" => Some(KeyCode::PageDown),
"pageup" => Some(KeyCode::PageUp), "page_up" => Some(KeyCode::PageUp),
"left" => Some(KeyCode::Left), "left" => Some(KeyCode::ArrowLeft),
"up" => Some(KeyCode::Up), "up" => Some(KeyCode::ArrowUp),
"right" => Some(KeyCode::Right), "right" => Some(KeyCode::ArrowRight),
"down" => Some(KeyCode::Down), "down" => Some(KeyCode::ArrowDown),
"back" => Some(KeyCode::Back), "backspace" => Some(KeyCode::Backspace),
"return" => Some(KeyCode::Return), "enter" => Some(KeyCode::Enter),
"space" => Some(KeyCode::Space), "space" => Some(KeyCode::Space),
"compose" => Some(KeyCode::Compose), "numlock" => Some(KeyCode::NumLock),
"caret" => Some(KeyCode::Caret),
"numlock" => Some(KeyCode::Numlock),
"numpad0" => Some(KeyCode::Numpad0), "numpad0" => Some(KeyCode::Numpad0),
"numpad1" => Some(KeyCode::Numpad1), "numpad1" => Some(KeyCode::Numpad1),
"numpad2" => Some(KeyCode::Numpad2), "numpad2" => Some(KeyCode::Numpad2),
@ -114,76 +112,62 @@ pub fn keycode_from_str(s: &str) -> Option<KeyCode> {
"numpad7" => Some(KeyCode::Numpad7), "numpad7" => Some(KeyCode::Numpad7),
"numpad8" => Some(KeyCode::Numpad8), "numpad8" => Some(KeyCode::Numpad8),
"numpad9" => Some(KeyCode::Numpad9), "numpad9" => Some(KeyCode::Numpad9),
"numpadadd" => Some(KeyCode::NumpadAdd), "numpad_add" => Some(KeyCode::NumpadAdd),
"numpaddivide" => Some(KeyCode::NumpadDivide), "numpad_divide" => Some(KeyCode::NumpadDivide),
"numpaddecimal" => Some(KeyCode::NumpadDecimal), "numpad_decimal" => Some(KeyCode::NumpadDecimal),
"numpadcomma" => Some(KeyCode::NumpadComma), "numpad_comma" => Some(KeyCode::NumpadComma),
"numpadenter" => Some(KeyCode::NumpadEnter), "numpad_enter" => Some(KeyCode::NumpadEnter),
"numpadequals" => Some(KeyCode::NumpadEquals), "numpad_multiply" => Some(KeyCode::NumpadMultiply),
"numpadmultiply" => Some(KeyCode::NumpadMultiply), "numpad_subtract" => Some(KeyCode::NumpadSubtract),
"numpadsubtract" => Some(KeyCode::NumpadSubtract), "numpad_star" => Some(KeyCode::NumpadStar),
"abntc1" => Some(KeyCode::AbntC1), "quote" => Some(KeyCode::Quote),
"abntc2" => Some(KeyCode::AbntC2), "launch_app1" => Some(KeyCode::LaunchApp1),
"apostrophe" => Some(KeyCode::Apostrophe), "launch_app1" => Some(KeyCode::LaunchApp2),
"apps" => Some(KeyCode::Apps),
"asterisk" => Some(KeyCode::Asterisk),
"at" => Some(KeyCode::At),
"ax" => Some(KeyCode::Ax),
"backslash" => Some(KeyCode::Backslash), "backslash" => Some(KeyCode::Backslash),
"calculator" => Some(KeyCode::Calculator), "caps_lock" => Some(KeyCode::CapsLock),
"capital" => Some(KeyCode::Capital),
"colon" => Some(KeyCode::Colon),
"comma" => Some(KeyCode::Comma), "comma" => Some(KeyCode::Comma),
"convert" => Some(KeyCode::Convert), "convert" => Some(KeyCode::Convert),
"equals" => Some(KeyCode::Equals), "equal" => Some(KeyCode::Equal),
"grave" => Some(KeyCode::Grave), "grave" | "backquote" => Some(KeyCode::Backquote),
"kana" => Some(KeyCode::Kana), "kana_mode" => Some(KeyCode::KanaMode),
"kanji" => Some(KeyCode::Kanji), "katakana" => Some(KeyCode::Katakana),
"lalt" => Some(KeyCode::LAlt), "alt_left" => Some(KeyCode::AltLeft),
"lbracket" => Some(KeyCode::LBracket), "alt_right" => Some(KeyCode::AltRight),
"lcontrol" => Some(KeyCode::LControl), "bracket_left" => Some(KeyCode::BracketLeft),
"lshift" => Some(KeyCode::LShift), "bracket_right" => Some(KeyCode::BracketRight),
"lwin" => Some(KeyCode::LWin), "control_left" => Some(KeyCode::ControlLeft),
"mail" => Some(KeyCode::Mail), "control-right" => Some(KeyCode::ControlRight),
"mediaselect" => Some(KeyCode::MediaSelect), "shift_left" => Some(KeyCode::ShiftLeft),
"mediastop" => Some(KeyCode::MediaStop), "shift_right" => Some(KeyCode::ShiftRight),
"meta" => Some(KeyCode::Meta),
"mail" => Some(KeyCode::LaunchMail),
"media_select" => Some(KeyCode::MediaSelect),
"media_stop" => Some(KeyCode::MediaStop),
"stop" => Some(KeyCode::MediaStop),
"track_next" => Some(KeyCode::MediaTrackNext),
"track_prev" => Some(KeyCode::MediaTrackPrevious),
"minus" => Some(KeyCode::Minus), "minus" => Some(KeyCode::Minus),
"mute" => Some(KeyCode::Mute), "mute" => Some(KeyCode::AudioVolumeMute),
"mycomputer" => Some(KeyCode::MyComputer), "browser_forward" => Some(KeyCode::BrowserForward),
"navigateforward" => Some(KeyCode::NavigateForward), "browser_back" => Some(KeyCode::BrowserBack),
"navigatebackward" => Some(KeyCode::NavigateBackward), "webfavorites" => Some(KeyCode::BrowserFavorites),
"nexttrack" => Some(KeyCode::NextTrack), "webhome" => Some(KeyCode::BrowserHome),
"noconvert" => Some(KeyCode::NoConvert), "webrefresh" => Some(KeyCode::BrowserRefresh),
"oem102" => Some(KeyCode::OEM102), "websearch" => Some(KeyCode::BrowserSearch),
"webstop" => Some(KeyCode::BrowserStop),
"non_convert" => Some(KeyCode::NonConvert),
"period" => Some(KeyCode::Period), "period" => Some(KeyCode::Period),
"playpause" => Some(KeyCode::PlayPause), "play_pause" => Some(KeyCode::MediaPlayPause),
"plus" => Some(KeyCode::Plus), "plus" => Some(KeyCode::NumpadAdd),
"power" => Some(KeyCode::Power), "power" => Some(KeyCode::Power),
"prevtrack" => Some(KeyCode::PrevTrack),
"ralt" => Some(KeyCode::RAlt),
"rbracket" => Some(KeyCode::RBracket),
"rcontrol" => Some(KeyCode::RControl),
"rshift" => Some(KeyCode::RShift),
"rwin" => Some(KeyCode::RWin),
"semicolon" => Some(KeyCode::Semicolon), "semicolon" => Some(KeyCode::Semicolon),
"slash" => Some(KeyCode::Slash), "slash" => Some(KeyCode::Slash),
"sleep" => Some(KeyCode::Sleep), "sleep" => Some(KeyCode::Sleep),
"stop" => Some(KeyCode::Stop),
"sysrq" => Some(KeyCode::Sysrq),
"tab" => Some(KeyCode::Tab), "tab" => Some(KeyCode::Tab),
"underline" => Some(KeyCode::Underline), "volume_down" => Some(KeyCode::AudioVolumeDown),
"unlabeled" => Some(KeyCode::Unlabeled), "volume_up" => Some(KeyCode::AudioVolumeUp),
"volumedown" => Some(KeyCode::VolumeDown), "wake_up" => Some(KeyCode::WakeUp),
"volumeup" => Some(KeyCode::VolumeUp), "yen" => Some(KeyCode::IntlYen),
"wake" => Some(KeyCode::Wake),
"webback" => Some(KeyCode::WebBack),
"webfavorites" => Some(KeyCode::WebFavorites),
"webforward" => Some(KeyCode::WebForward),
"webhome" => Some(KeyCode::WebHome),
"webrefresh" => Some(KeyCode::WebRefresh),
"websearch" => Some(KeyCode::WebSearch),
"webstop" => Some(KeyCode::WebStop),
"yen" => Some(KeyCode::Yen),
"copy" => Some(KeyCode::Copy), "copy" => Some(KeyCode::Copy),
"paste" => Some(KeyCode::Paste), "paste" => Some(KeyCode::Paste),
"cut" => Some(KeyCode::Cut), "cut" => Some(KeyCode::Cut),

View File

@ -2,7 +2,7 @@ use std::ptr::NonNull;
use glam::Vec2; use glam::Vec2;
use lyra_ecs::{World, system::IntoSystem}; use lyra_ecs::{World, system::IntoSystem};
use winit::event::MouseScrollDelta; use winit::{event::MouseScrollDelta, keyboard::PhysicalKey};
use crate::{EventQueue, plugin::Plugin, game::GameStages}; use crate::{EventQueue, plugin::Plugin, game::GameStages};
@ -20,21 +20,14 @@ impl InputSystem {
let mut event_queue = event_queue.unwrap(); let mut event_queue = event_queue.unwrap();
match event { match event {
InputEvent::KeyboardInput { input, .. } => { InputEvent::KeyboardInput { device_id, event, .. } => {
if let Some(code) = input.virtual_keycode { if let PhysicalKey::Code(code) = event.physical_key {
drop(event_queue); drop(event_queue);
let mut e = world.get_resource_or_else(InputButtons::<winit::event::VirtualKeyCode>::new); let mut e = world.get_resource_or_else(InputButtons::<winit::keyboard::KeyCode>::new);
//let mut e = with_resource_mut(world, || InputButtons::<KeyCode>::new()); //let mut e = with_resource_mut(world, || InputButtons::<KeyCode>::new());
e.add_input_from_winit(code, input.state); e.add_input_from_winit(code, event.state);
} }
}, },
InputEvent::MouseMotion { delta, .. } => {
let delta = MouseMotion {
delta: Vec2::new(delta.0 as f32, delta.1 as f32)
};
event_queue.trigger_event(delta);
},
InputEvent::CursorMoved { position, .. } => { InputEvent::CursorMoved { position, .. } => {
let exact = MouseExact { let exact = MouseExact {
pos: Vec2::new(position.x as f32, position.y as f32) pos: Vec2::new(position.x as f32, position.y as f32)
@ -67,6 +60,8 @@ impl InputSystem {
winit::event::MouseButton::Left => MouseButton::Left, winit::event::MouseButton::Left => MouseButton::Left,
winit::event::MouseButton::Right => MouseButton::Right, winit::event::MouseButton::Right => MouseButton::Right,
winit::event::MouseButton::Middle => MouseButton::Middle, winit::event::MouseButton::Middle => MouseButton::Middle,
winit::event::MouseButton::Back => MouseButton::Back,
winit::event::MouseButton::Forward => MouseButton::Forward,
winit::event::MouseButton::Other(v) => MouseButton::Other(*v), winit::event::MouseButton::Other(v) => MouseButton::Other(*v),
}; };
@ -102,7 +97,7 @@ impl crate::ecs::system::System for InputSystem {
let queue = world.try_get_resource_mut::<EventQueue>() let queue = world.try_get_resource_mut::<EventQueue>()
.and_then(|q| q.read_events::<InputEvent>()); .and_then(|q| q.read_events::<InputEvent>());
let mut e = world.get_resource_or_else(InputButtons::<winit::event::VirtualKeyCode>::new); let mut e = world.get_resource_or_else(InputButtons::<winit::keyboard::KeyCode>::new);
e.update(); e.update();
drop(e); drop(e);
@ -140,7 +135,7 @@ impl IntoSystem<()> for InputSystem {
pub struct InputPlugin; pub struct InputPlugin;
impl Plugin for InputPlugin { impl Plugin for InputPlugin {
fn setup(&self, game: &mut crate::game::Game) { fn setup(&self, app: &mut crate::game::App) {
game.add_system_to_stage(GameStages::PreUpdate, "input", InputSystem, &[]); app.add_system_to_stage(GameStages::PreUpdate, "input", InputSystem, &[]);
} }
} }

View File

@ -1,35 +1,53 @@
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_ecs::CommandQueue;
use lyra_resource::ResourceManager; use lyra_resource::ResourceManager;
use crate::game::App;
use crate::EventsPlugin; use crate::EventsPlugin;
use crate::DeltaTimePlugin; use crate::DeltaTimePlugin;
use crate::game::Game;
use crate::input::InputPlugin; use crate::input::InputPlugin;
use crate::render::window::WindowPlugin; use crate::render::window::WindowPlugin;
/// A Plugin is something you can add to a `Game` that can be used to define systems, or spawn initial entities. /// A Plugin is something you can add to a `Game` that can be used to define systems, or spawn initial entities.
pub trait Plugin { pub trait Plugin {
/// Setup this plugin. This runs before the game has started /// Setup this plugin. This runs before the app has started
fn setup(&self, game: &mut Game); fn setup(&self, app: &mut App);
fn is_ready(&self, _game: &mut Game) -> bool { fn is_ready(&self, app: &mut App) -> bool {
true true
} }
fn complete(&self, _game: &mut Game) { fn complete(&self, _app: &mut App) {
} }
fn cleanup(&self, _game: &mut Game) { fn cleanup(&self, _app: &mut App) {
} }
} }
impl<P> Plugin for P impl<P> Plugin for P
where P: Fn(&mut Game) where P: Fn(&mut App)
{ {
fn setup(&self, game: &mut Game) { fn setup(&self, app: &mut App) {
self(game); self(app);
}
}
/// 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));
} }
} }
@ -56,9 +74,9 @@ impl PluginSet {
} }
impl Plugin for PluginSet { impl Plugin for PluginSet {
fn setup(&self, game: &mut Game) { fn setup(&self, app: &mut App) {
for plugin in self.plugins.iter() { for plugin in self.plugins.iter() {
plugin.setup(game); plugin.setup(app);
} }
} }
} }
@ -98,8 +116,8 @@ impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6)
pub struct ResourceManagerPlugin; pub struct ResourceManagerPlugin;
impl Plugin for ResourceManagerPlugin { impl Plugin for ResourceManagerPlugin {
fn setup(&self, game: &mut Game) { fn setup(&self, app: &mut App) {
game.world_mut().add_resource(ResourceManager::new()); app.world.add_resource(ResourceManager::new());
} }
} }
@ -108,13 +126,13 @@ impl Plugin for ResourceManagerPlugin {
pub struct DefaultPlugins; pub struct DefaultPlugins;
impl Plugin for DefaultPlugins { impl Plugin for DefaultPlugins {
fn setup(&self, game: &mut Game) { fn setup(&self, app: &mut App) {
CommandQueuePlugin.setup(game); CommandQueuePlugin.setup(app);
EventsPlugin.setup(game); EventsPlugin.setup(app);
InputPlugin.setup(game); InputPlugin.setup(app);
ResourceManagerPlugin.setup(game); ResourceManagerPlugin.setup(app);
WindowPlugin::default().setup(game); WindowPlugin::default().setup(app);
DeltaTimePlugin.setup(game); DeltaTimePlugin.setup(app);
} }
} }
@ -124,7 +142,7 @@ impl Plugin for DefaultPlugins {
pub struct CommandQueuePlugin; pub struct CommandQueuePlugin;
impl Plugin for CommandQueuePlugin { impl Plugin for CommandQueuePlugin {
fn setup(&self, game: &mut Game) { fn setup(&self, app: &mut App) {
game.world_mut().add_resource(CommandQueue::default()); app.world.add_resource(CommandQueue::default());
} }
} }

View File

@ -22,7 +22,7 @@ pub struct RenderGraphContext<'a> {
pub device: Arc<wgpu::Device>, pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>, pub queue: Arc<wgpu::Queue>,
pub(crate) buffer_writes: VecDeque<GraphBufferWrite>, pub(crate) buffer_writes: VecDeque<GraphBufferWrite>,
renderpass_desc: Vec<wgpu::RenderPassDescriptor<'a, 'a>>, renderpass_desc: Vec<wgpu::RenderPassDescriptor<'a>>,
/// The label of this Node. /// The label of this Node.
pub label: RenderGraphLabelValue, pub label: RenderGraphLabelValue,
} }
@ -41,7 +41,7 @@ impl<'a> RenderGraphContext<'a> {
pub fn begin_render_pass( pub fn begin_render_pass(
&'a mut self, &'a mut self,
desc: wgpu::RenderPassDescriptor<'a, 'a>, desc: wgpu::RenderPassDescriptor<'a>,
) -> wgpu::RenderPass { ) -> wgpu::RenderPass {
self.encoder self.encoder
.as_mut() .as_mut()

View File

@ -17,7 +17,7 @@ pub struct FxaaPass {
/// Store bind groups for the input textures. /// Store bind groups for the input textures.
/// The texture may change due to resizes, or changes to the view target chain /// The texture may change due to resizes, or changes to the view target chain
/// from other nodes. /// from other nodes.
bg_cache: HashMap<wgpu::Id, wgpu::BindGroup>, bg_cache: HashMap<wgpu::Id<wgpu::TextureView>, wgpu::BindGroup>,
} }
impl FxaaPass { impl FxaaPass {
@ -157,10 +157,12 @@ impl Node for FxaaPass {
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Load, load: wgpu::LoadOp::Load,
store: true, store: wgpu::StoreOp::Store,
}, },
})], })],
depth_stencil_attachment: None, depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None, // TODO: occlusion queries
}); });
pass.set_pipeline(pipeline.as_render()); pass.set_pipeline(pipeline.as_render());

View File

@ -235,6 +235,8 @@ impl Node for LightCullComputePass {
], ],
shader, shader,
shader_entry_point: "cs_main".into(), shader_entry_point: "cs_main".into(),
cache: None,
compilation_options: Default::default(),
}); });
self.pipeline = Some(pipeline); self.pipeline = Some(pipeline);
@ -251,6 +253,7 @@ impl Node for LightCullComputePass {
let mut pass = context.begin_compute_pass(&wgpu::ComputePassDescriptor { let mut pass = context.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("light_cull_pass"), label: Some("light_cull_pass"),
..Default::default()
}); });
pass.set_pipeline(pipeline); pass.set_pipeline(pipeline);

View File

@ -604,8 +604,8 @@ impl GpuMaterial {
&img.to_rgba8(), &img.to_rgba8(),
wgpu::ImageDataLayout { wgpu::ImageDataLayout {
offset: 0, offset: 0,
bytes_per_row: std::num::NonZeroU32::new(4 * dim.0), bytes_per_row: Some(4 * dim.0),
rows_per_image: std::num::NonZeroU32::new(dim.1), rows_per_image: Some(dim.1),
}, },
wgpu::Extent3d { wgpu::Extent3d {
width: dim.0, width: dim.0,

View File

@ -420,7 +420,7 @@ impl Node for MeshPass {
b: 0.3, b: 0.3,
a: 1.0, a: 1.0,
}), }),
store: true, store: wgpu::StoreOp::Store,
}, },
})], })],
// enable depth buffer // enable depth buffer
@ -428,10 +428,11 @@ impl Node for MeshPass {
view: depth_view, view: depth_view,
depth_ops: Some(wgpu::Operations { depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0), load: wgpu::LoadOp::Clear(1.0),
store: true, store: wgpu::StoreOp::Store,
}), }),
stencil_ops: None, stencil_ops: None,
}), }),
..Default::default()
}); });
pass.set_pipeline(pipeline); pass.set_pipeline(pipeline);

View File

@ -865,10 +865,11 @@ impl Node for ShadowMapsPass {
view: atlas.view(), view: atlas.view(),
depth_ops: Some(wgpu::Operations { depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0), load: wgpu::LoadOp::Clear(1.0),
store: true, store: wgpu::StoreOp::Store,
}), }),
stencil_ops: None, stencil_ops: None,
}), }),
..Default::default()
}); });
for light_depth_map in self.depth_maps.values() { for light_depth_map in self.depth_maps.values() {

View File

@ -17,7 +17,7 @@ pub struct TintPass {
/// Store bind groups for the input textures. /// Store bind groups for the input textures.
/// The texture may change due to resizes, or changes to the view target chain /// The texture may change due to resizes, or changes to the view target chain
/// from other nodes. /// from other nodes.
bg_cache: HashMap<wgpu::Id, wgpu::BindGroup>, bg_cache: HashMap<wgpu::Id<wgpu::TextureView>, wgpu::BindGroup>,
} }
impl TintPass { impl TintPass {
@ -152,10 +152,12 @@ impl Node for TintPass {
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Load, load: wgpu::LoadOp::Load,
store: true, store: wgpu::StoreOp::Store,
}, },
})], })],
depth_stencil_attachment: None, depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
}); });
pass.set_pipeline(pipeline.as_render()); pass.set_pipeline(pipeline.as_render());

View File

@ -6,10 +6,19 @@ use crate::math;
enum RenderTargetInner { enum RenderTargetInner {
Surface { Surface {
surface: wgpu::Surface, /// The surface that will be rendered to.
///
/// You can create a new surface with a `'static` lifetime if you have an `Arc<Window>`:
/// ```nobuild
/// let window = Arc::new(window);
/// let surface = instance.create_surface(Arc::clone(&window))?;
/// ```
surface: wgpu::Surface<'static>,
/// the configuration of the surface render target..
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
}, },
Texture { Texture {
/// The texture that will be rendered to.
texture: Arc<wgpu::Texture>, texture: Arc<wgpu::Texture>,
} }
} }
@ -25,7 +34,7 @@ impl From<wgpu::Texture> for RenderTarget {
} }
impl RenderTarget { impl RenderTarget {
pub fn from_surface(surface: wgpu::Surface, config: wgpu::SurfaceConfiguration) -> Self { pub fn from_surface(surface: wgpu::Surface<'static>, config: wgpu::SurfaceConfiguration) -> Self {
Self(RenderTargetInner::Surface { surface, config }) Self(RenderTargetInner::Surface { surface, config })
} }

View File

@ -1,4 +1,4 @@
use std::{mem, num::{NonZeroU32, NonZeroU8}}; use std::mem;
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct TextureViewDescriptor { pub struct TextureViewDescriptor {
@ -16,13 +16,13 @@ pub struct TextureViewDescriptor {
/// Mip level count. /// Mip level count.
/// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count. /// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count.
/// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total. /// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total.
pub mip_level_count: Option<NonZeroU32>, pub mip_level_count: Option<u32>,
/// Base array layer. /// Base array layer.
pub base_array_layer: u32, pub base_array_layer: u32,
/// Layer count. /// Layer count.
/// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count. /// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count.
/// If `None`, considered to include the rest of the array layers, but at least 1 in total. /// If `None`, considered to include the rest of the array layers, but at least 1 in total.
pub array_layer_count: Option<NonZeroU32>, pub array_layer_count: Option<u32>,
} }
impl TextureViewDescriptor { impl TextureViewDescriptor {
@ -79,7 +79,7 @@ pub struct SamplerDescriptor {
/// If this is enabled, this is a comparison sampler using the given comparison function. /// If this is enabled, this is a comparison sampler using the given comparison function.
pub compare: Option<wgpu::CompareFunction>, pub compare: Option<wgpu::CompareFunction>,
/// Valid values: 1, 2, 4, 8, and 16. /// Valid values: 1, 2, 4, 8, and 16.
pub anisotropy_clamp: Option<NonZeroU8>, pub anisotropy_clamp: u16,
/// Border color to use when address_mode is [`AddressMode::ClampToBorder`] /// Border color to use when address_mode is [`AddressMode::ClampToBorder`]
pub border_color: Option<wgpu::SamplerBorderColor>, pub border_color: Option<wgpu::SamplerBorderColor>,
} }

View File

@ -75,10 +75,11 @@ impl BasicRenderer {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(), backends: wgpu::Backends::all(),
dx12_shader_compiler: Default::default(), dx12_shader_compiler: Default::default(),
flags: wgpu::InstanceFlags::default(),
gles_minor_version: wgpu::Gles3MinorVersion::Automatic,
}); });
// This should be safe since surface will live as long as the window that created it let surface: wgpu::Surface::<'static> = instance.create_surface(window.clone()).unwrap();
let surface = unsafe { instance.create_surface(window.as_ref()) }.unwrap();
let adapter = instance.request_adapter( let adapter = instance.request_adapter(
&wgpu::RequestAdapterOptions { &wgpu::RequestAdapterOptions {
@ -90,11 +91,12 @@ impl BasicRenderer {
let (device, queue) = adapter.request_device( let (device, queue) = adapter.request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
features: wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES | wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER, label: None,
required_features: wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES | wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
// WebGL does not support all wgpu features. // WebGL does not support all wgpu features.
// Not sure if the engine will ever completely support WASM, // Not sure if the engine will ever completely support WASM,
// but its here just in case // but its here just in case
limits: if cfg!(target_arch = "wasm32") { required_limits: if cfg!(target_arch = "wasm32") {
wgpu::Limits::downlevel_webgl2_defaults() wgpu::Limits::downlevel_webgl2_defaults()
} else { } else {
wgpu::Limits { wgpu::Limits {
@ -102,7 +104,7 @@ impl BasicRenderer {
..Default::default() ..Default::default()
} }
}, },
label: None, memory_hints: wgpu::MemoryHints::MemoryUsage,
}, },
None, None,
).await.unwrap(); ).await.unwrap();
@ -113,7 +115,7 @@ impl BasicRenderer {
let surface_format = surface_caps.formats.iter() let surface_format = surface_caps.formats.iter()
.copied() .copied()
.find(|f| f.describe().srgb) .find(|f| f.is_srgb())
.unwrap_or(surface_caps.formats[0]); .unwrap_or(surface_caps.formats[0]);
let config = wgpu::SurfaceConfiguration { let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST, usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
@ -122,6 +124,7 @@ impl BasicRenderer {
height: size.height, height: size.height,
present_mode: wgpu::PresentMode::default(), //wgpu::PresentMode::Mailbox, // "Fast Vsync" present_mode: wgpu::PresentMode::default(), //wgpu::PresentMode::Mailbox, // "Fast Vsync"
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
desired_maximum_frame_latency: 2,
view_formats: vec![], view_formats: vec![],
}; };
surface.configure(&device, &config); surface.configure(&device, &config);

View File

@ -2,19 +2,25 @@ use std::{ops::Deref, rc::Rc, sync::Arc};
use wgpu::PipelineLayout; use wgpu::PipelineLayout;
use super::Shader; use super::{PipelineCompilationOptions, Shader};
//#[derive(Debug, Clone)] //#[derive(Debug, Clone)]
pub struct ComputePipelineDescriptor { pub struct ComputePipelineDescriptor {
pub label: Option<String>, pub label: Option<String>,
pub layouts: Vec<Arc<wgpu::BindGroupLayout>>, pub layouts: Vec<Arc<wgpu::BindGroupLayout>>,
pub push_constant_ranges: Vec<wgpu::PushConstantRange>,
// TODO: make this a ResHandle<Shader> // TODO: make this a ResHandle<Shader>
/// The compiled shader module for the stage. /// The compiled shader module for the stage.
pub shader: Rc<Shader>, pub shader: Rc<Shader>,
/// The entry point in the compiled shader. /// The entry point in the compiled shader.
/// There must be a function in the shader with the same name. /// There must be a function in the shader with the same name.
pub shader_entry_point: String, pub shader_entry_point: String,
/// Advanced options for when this pipeline is compiled
///
/// This implements `Default`, and for most users can be set to `Default::default()`
pub compilation_options: PipelineCompilationOptions,
pub push_constant_ranges: Vec<wgpu::PushConstantRange>,
/// The pipeline cache to use when creating this pipeline.
pub cache: Option<Arc<wgpu::PipelineCache>>,
} }
impl ComputePipelineDescriptor { impl ComputePipelineDescriptor {
@ -85,6 +91,8 @@ impl ComputePipeline {
layout: layout.as_ref(), layout: layout.as_ref(),
module: &compiled_shader, module: &compiled_shader,
entry_point: &desc.shader_entry_point, entry_point: &desc.shader_entry_point,
cache: desc.cache.as_ref().map(|c| &**c),
compilation_options: desc.compilation_options.as_wgpu(),
}; };
let pipeline = device.create_compute_pipeline(&desc); let pipeline = device.create_compute_pipeline(&desc);

View File

@ -1,4 +1,6 @@
mod shader; mod shader;
use std::collections::HashMap;
pub use shader::*; pub use shader::*;
mod pipeline; mod pipeline;
@ -12,3 +14,20 @@ pub use render_pipeline::*;
mod pass; mod pass;
pub use pass::*; pub use pass::*;
#[derive(Default, Clone)]
pub struct PipelineCompilationOptions {
pub constants: HashMap<String, f64>,
pub zero_initialize_workgroup_memory: bool,
pub vertex_pulling_transform: bool,
}
impl PipelineCompilationOptions {
pub fn as_wgpu(&self) -> wgpu::PipelineCompilationOptions {
wgpu::PipelineCompilationOptions {
constants: &self.constants,
zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
vertex_pulling_transform: self.vertex_pulling_transform,
}
}
}

View File

@ -97,6 +97,7 @@ impl RenderPipeline {
module: &vrtx_shad, module: &vrtx_shad,
entry_point: &desc.vertex.entry_point, entry_point: &desc.vertex.entry_point,
buffers: &vrtx_buffs, buffers: &vrtx_buffs,
compilation_options: Default::default(),
}; };
let frag_module = desc.fragment.as_ref().map(|f| { let frag_module = desc.fragment.as_ref().map(|f| {
@ -115,6 +116,7 @@ impl RenderPipeline {
module: fm.unwrap(), module: fm.unwrap(),
entry_point: &f.entry_point, entry_point: &f.entry_point,
targets: &f.targets, targets: &f.targets,
compilation_options: Default::default(),
}); });
let render_desc = wgpu::RenderPipelineDescriptor { let render_desc = wgpu::RenderPipelineDescriptor {
@ -126,6 +128,7 @@ impl RenderPipeline {
multisample: desc.multisample, multisample: desc.multisample,
fragment: fstate, fragment: fstate,
multiview: desc.multiview, multiview: desc.multiview,
cache: None,
}; };
let render_pipeline = device.create_render_pipeline(&render_desc); let render_pipeline = device.create_render_pipeline(&render_desc);

View File

@ -105,8 +105,8 @@ impl RenderTexture {
&rgba, &rgba,
wgpu::ImageDataLayout { wgpu::ImageDataLayout {
offset: 0, offset: 0,
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0), bytes_per_row: Some(4 * dimensions.0),
rows_per_image: std::num::NonZeroU32::new(dimensions.1), rows_per_image: Some(dimensions.1),
}, },
size, size,
); );
@ -169,8 +169,8 @@ impl RenderTexture {
&rgba, &rgba,
wgpu::ImageDataLayout { wgpu::ImageDataLayout {
offset: 0, offset: 0,
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0), bytes_per_row: Some(4 * dimensions.0),
rows_per_image: std::num::NonZeroU32::new(dimensions.1), rows_per_image: Some(dimensions.1),
}, },
size, size,
); );
@ -247,8 +247,8 @@ impl RenderTexture {
&rgba, &rgba,
wgpu::ImageDataLayout { wgpu::ImageDataLayout {
offset: 0, offset: 0,
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0), bytes_per_row: Some(4 * dimensions.0),
rows_per_image: std::num::NonZeroU32::new(dimensions.1), rows_per_image: Some(dimensions.1),
}, },
size, size,
); );

View File

@ -1,13 +1,17 @@
use std::sync::Arc; use std::sync::Arc;
use glam::{Vec2, IVec2}; use glam::{IVec2, Vec2};
use lyra_ecs::World; use lyra_ecs::World;
use tracing::{warn, error}; use tracing::{error, warn};
use winit::{window::{Window, Fullscreen}, dpi::{LogicalPosition, LogicalSize, PhysicalPosition}, error::ExternalError}; use winit::{
dpi::{LogicalPosition, LogicalSize, PhysicalPosition},
error::ExternalError,
window::{Fullscreen, Window},
};
pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel}; pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel};
use crate::{plugin::Plugin, change_tracker::Ct, input::InputEvent, EventQueue}; use crate::{change_tracker::Ct, input::InputEvent, plugin::Plugin, EventQueue};
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub enum WindowMode { pub enum WindowMode {
@ -20,6 +24,75 @@ pub enum WindowMode {
Windowed, Windowed,
} }
#[derive(Default, Clone, Copy)]
pub struct Area {
position: Position,
size: Size,
}
#[derive(Clone, Copy)]
pub enum Size {
Physical { x: i32, y: i32 },
Logical { x: f64, y: f64 },
}
impl Default for Size {
fn default() -> Self {
Self::Physical { x: 0, y: 0 }
}
}
impl Into<winit::dpi::Size> for Size {
fn into(self) -> winit::dpi::Size {
match self {
Size::Physical { x, y } => winit::dpi::PhysicalSize::new(x, y).into(),
Size::Logical { x, y } => winit::dpi::LogicalSize::new(x, y).into(),
}
}
}
impl Size {
pub fn new_physical(x: i32, y: i32) -> Self {
Self::Physical { x, y }
}
pub fn new_logical(x: f64, y: f64) -> Self {
Self::Logical { x, y }
}
}
#[derive(Clone, Copy)]
pub enum Position {
Physical { x: i32, y: i32 },
Logical { x: f64, y: f64 },
}
impl Default for Position {
fn default() -> Self {
Self::Physical { x: 0, y: 0 }
}
}
impl Into<winit::dpi::Position> for Position {
fn into(self) -> winit::dpi::Position {
match self {
Position::Physical { x, y } => winit::dpi::PhysicalPosition::new(x, y).into(),
Position::Logical { x, y } => winit::dpi::LogicalPosition::new(x, y).into(),
}
}
}
impl Position {
pub fn new_physical(x: i32, y: i32) -> Self {
Self::Physical { x, y }
}
pub fn new_logical(x: f64, y: f64) -> Self {
Self::Logical { x, y }
}
}
/// Options that the window will be created with. /// Options that the window will be created with.
#[derive(Clone)] #[derive(Clone)]
pub struct WindowOptions { pub struct WindowOptions {
@ -43,11 +116,13 @@ pub struct WindowOptions {
/// * iOS / Android / Web / X11 / Orbital: Unsupported. /// * iOS / Android / Web / X11 / Orbital: Unsupported.
pub cursor_hittest: bool, pub cursor_hittest: bool,
/// The cursor icon of the window. /// Modifies the cursor icon of the window.
/// ///
/// Platform-specific /// Platform-specific:
/// * iOS / Android / Orbital: Unsupported. /// * iOS / Android / Orbital: Unsupported.
pub cursor_icon: CursorIcon, /// * Web: Custom cursors have to be loaded and decoded first, until then the previous
/// cursor is shown.
pub cursor: winit::window::Cursor,
/// The cursors visibility. /// The cursors visibility.
/// If false, this will hide the cursor. If true, this will show the cursor. /// If false, this will hide the cursor. If true, this will show the cursor.
@ -87,30 +162,42 @@ pub struct WindowOptions {
/// * iOS / Android / Web / Orbital: Unsupported. /// * iOS / Android / Web / Orbital: Unsupported.
pub ime_allowed: bool, pub ime_allowed: bool,
/// Sets location of IME candidate box in client area coordinates relative to the top left. /// Set the IME cursor editing area, where the `position` is the top left corner of that
/// area and `size` is the size of this area starting from the position. An example of such
/// area could be a input field in the UI or line in the editor.
/// ///
/// This is the window / popup / overlay that allows you to select the desired characters. /// The windowing system could place a candidate box close to that area, but try to not
/// The look of this box may differ between input devices, even on the same platform. /// obscure the specified area, so the user input to it stays visible.
pub ime_position: Vec2, ///
/// The candidate box is the window / popup / overlay that allows you to select the desired
/// characters. The look of this box may differ between input devices, even on the same
/// platform.
///
/// (Apples official term is “candidate window”, see their chinese and japanese guides).
///
/// Platform-specific
/// * **X11:** - area is not supported, only position.
/// * **iOS / Android / Web / Orbital:** Unsupported.
pub ime_cursor_area: Area,
/// Modifies the inner size of the window. /// Modifies the inner size of the window.
/// ///
/// Platform-specific: /// Platform-specific:
/// * iOS / Android: Unsupported. /// * iOS / Android: Unsupported.
/// * Web: Sets the size of the canvas element. /// * Web: Sets the size of the canvas element.
pub inner_size: IVec2, pub inner_size: Size,
/// Sets a maximum dimension size for the window. /// Sets a maximum dimension size for the window.
/// ///
/// Platform-specific: /// Platform-specific:
/// * iOS / Android / Web / Orbital: Unsupported. /// * iOS / Android / Web / Orbital: Unsupported.
pub max_inner_size: Option<IVec2>, pub max_inner_size: Option<Size>,
/// Sets a minimum dimension size for the window. /// Sets a minimum dimension size for the window.
/// ///
/// Platform-specific: /// Platform-specific:
/// * iOS / Android / Web / Orbital: Unsupported. /// * iOS / Android / Web / Orbital: Unsupported.
pub min_inner_size: Option<IVec2>, pub min_inner_size: Option<Size>,
/// Sets the window to maximized or back. /// Sets the window to maximized or back.
/// ///
@ -186,14 +273,14 @@ impl Default for WindowOptions {
content_protected: false, content_protected: false,
cursor_grab: CursorGrabMode::None, cursor_grab: CursorGrabMode::None,
cursor_hittest: true, cursor_hittest: true,
cursor_icon: CursorIcon::Default, cursor: Default::default(),
cursor_visible: true, cursor_visible: true,
decorations: true, decorations: true,
enabled_buttons: WindowButtons::all(), enabled_buttons: WindowButtons::all(),
mode: WindowMode::Windowed, mode: WindowMode::Windowed,
ime_allowed: false, ime_allowed: false,
ime_position: Default::default(), ime_cursor_area: Area::default(),
inner_size: glam::i32::IVec2::new(800, 600), inner_size: Size::new_physical(800, 600),
max_inner_size: None, max_inner_size: None,
min_inner_size: None, min_inner_size: None,
maximized: false, maximized: false,
@ -224,7 +311,10 @@ fn vec2_to_logical_pos(pos: Vec2) -> LogicalPosition<f32> {
/// Convert an IVec2 to a LogicalSize<i32> /// Convert an IVec2 to a LogicalSize<i32>
fn ivec2_to_logical_size(size: IVec2) -> LogicalSize<i32> { fn ivec2_to_logical_size(size: IVec2) -> LogicalSize<i32> {
LogicalSize { width: size.x, height: size.y } LogicalSize {
width: size.x,
height: size.y,
}
} }
/// Convert an Option<IVec2> to an Option<LogicalSize<i32>> /// Convert an Option<IVec2> to an Option<LogicalSize<i32>>
@ -234,7 +324,10 @@ fn ivec2_to_logical_size_op(size: Option<IVec2>) -> Option<LogicalSize<i32>> {
/// Convert an Option<Vec2> to an Option<LogicalSize<f32>> /// Convert an Option<Vec2> to an Option<LogicalSize<f32>>
fn vec2_to_logical_size_op(size: Option<Vec2>) -> Option<LogicalSize<f32>> { fn vec2_to_logical_size_op(size: Option<Vec2>) -> Option<LogicalSize<f32>> {
size.map(|size| LogicalSize { width: size.x, height: size.y } ) size.map(|size| LogicalSize {
width: size.x,
height: size.y,
})
} }
/// Set the cursor grab of a window depending on the platform. /// Set the cursor grab of a window depending on the platform.
@ -250,9 +343,13 @@ fn set_cursor_grab(window: &Window, grab: &mut CursorGrabMode) -> anyhow::Result
*grab = CursorGrabMode::Confined; // NOTE: May support Locked later *grab = CursorGrabMode::Confined; // NOTE: May support Locked later
} else if cfg!(target_os = "macos") { } else if cfg!(target_os = "macos") {
*grab = CursorGrabMode::Locked; // NOTE: May support Confined later *grab = CursorGrabMode::Locked; // NOTE: May support Confined later
} else if cfg!(any(target_os = "android", target_os = "ios", target_os = "orbital")) { } else if cfg!(any(
target_os = "android",
target_os = "ios",
target_os = "orbital"
)) {
warn!("CursorGrabMode is not supported on Android, IOS, or Oribital, skipping"); warn!("CursorGrabMode is not supported on Android, IOS, or Oribital, skipping");
return Ok(()) return Ok(());
} }
} }
@ -264,8 +361,8 @@ fn set_cursor_grab(window: &Window, grab: &mut CursorGrabMode) -> anyhow::Result
/// if the window is set to confine the cursor, the cursor is invisible, /// if the window is set to confine the cursor, the cursor is invisible,
/// and the window is focused, set the cursor position to the center of the screen. /// and the window is focused, set the cursor position to the center of the screen.
fn center_mouse(window: &Window, options: &WindowOptions) { fn center_mouse(window: &Window, options: &WindowOptions) {
if options.cursor_grab == CursorGrabMode::Confined && !options.cursor_visible if options.cursor_grab == CursorGrabMode::Confined && !options.cursor_visible && options.focused
&& options.focused { {
let size = window.inner_size(); let size = window.inner_size();
let middle = PhysicalPosition { let middle = PhysicalPosition {
x: size.width / 2, x: size.width / 2,
@ -276,7 +373,10 @@ fn center_mouse(window: &Window, options: &WindowOptions) {
} }
fn window_updater_system(world: &mut World) -> anyhow::Result<()> { fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
if let (Some(window), Some(opts)) = (world.try_get_resource::<Arc<Window>>(), world.try_get_resource::<Ct<WindowOptions>>()) { if let (Some(window), Some(opts)) = (
world.try_get_resource::<Arc<Window>>(),
world.try_get_resource::<Ct<WindowOptions>>(),
) {
// if the options changed, update the window // if the options changed, update the window
if opts.peek_changed() { if opts.peek_changed() {
drop(opts); // drop the Ref, we're about to get a RefMut drop(opts); // drop the Ref, we're about to get a RefMut
@ -290,24 +390,30 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
window.set_content_protected(opts.content_protected); window.set_content_protected(opts.content_protected);
set_cursor_grab(&window, &mut opts.cursor_grab)?; set_cursor_grab(&window, &mut opts.cursor_grab)?;
match window.set_cursor_hittest(opts.cursor_hittest) { match window.set_cursor_hittest(opts.cursor_hittest) {
Ok(()) => {}, Ok(()) => {}
Err(ExternalError::NotSupported(_)) => { /* ignore */ }, Err(ExternalError::NotSupported(_)) => { /* ignore */ }
Err(e) => { Err(e) => {
error!("OS error when setting cursor hittest: {:?}", e); error!("OS error when setting cursor hittest: {:?}", e);
} }
} }
window.set_cursor_icon(opts.cursor_icon); // TODO: Handle unsupported platforms window.set_cursor(opts.cursor.clone()); // TODO: Handle unsupported platforms
window.set_cursor_visible(opts.cursor_visible); // TODO: Handle unsupported platforms window.set_cursor_visible(opts.cursor_visible); // TODO: Handle unsupported platforms
window.set_decorations(opts.decorations); // TODO: Handle unsupported platforms window.set_decorations(opts.decorations); // TODO: Handle unsupported platforms
window.set_enabled_buttons(opts.enabled_buttons); // TODO: Handle unsupported platforms window.set_enabled_buttons(opts.enabled_buttons); // TODO: Handle unsupported platforms
// Update the window mode. can only be done if the monitor is found // Update the window mode. can only be done if the monitor is found
if let Some(monitor) = window.current_monitor() if let Some(monitor) = window
.current_monitor()
.or_else(|| window.primary_monitor()) .or_else(|| window.primary_monitor())
.or_else(|| window.available_monitors().next()) { .or_else(|| window.available_monitors().next())
{
match opts.mode { match opts.mode {
WindowMode::Borderless => window.set_fullscreen(Some(Fullscreen::Borderless(Some(monitor)))), WindowMode::Borderless => {
WindowMode::Fullscreen => window.set_fullscreen(Some(Fullscreen::Exclusive(monitor.video_modes().next().unwrap()))), window.set_fullscreen(Some(Fullscreen::Borderless(Some(monitor))))
}
WindowMode::Fullscreen => window.set_fullscreen(Some(Fullscreen::Exclusive(
monitor.video_modes().next().unwrap(),
))),
WindowMode::Windowed => window.set_fullscreen(None), WindowMode::Windowed => window.set_fullscreen(None),
} }
} else { } else {
@ -315,13 +421,13 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
} }
window.set_ime_allowed(opts.ime_allowed); window.set_ime_allowed(opts.ime_allowed);
window.set_ime_position(vec2_to_logical_pos(opts.ime_position)); window.set_ime_cursor_area(opts.ime_cursor_area.position, opts.ime_cursor_area.size);
window.set_inner_size(ivec2_to_logical_size(opts.inner_size)); window.request_inner_size(opts.inner_size);
if opts.max_inner_size.is_some() { if opts.max_inner_size.is_some() {
window.set_max_inner_size(ivec2_to_logical_size_op(opts.max_inner_size)); window.set_max_inner_size(opts.max_inner_size);
} }
if opts.min_inner_size.is_some() { if opts.min_inner_size.is_some() {
window.set_min_inner_size(ivec2_to_logical_size_op(opts.min_inner_size)); window.set_min_inner_size(opts.min_inner_size);
} }
window.set_maximized(opts.maximized); window.set_maximized(opts.maximized);
window.set_minimized(opts.minimized); window.set_minimized(opts.minimized);
@ -346,11 +452,11 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
match ev { match ev {
InputEvent::CursorEntered { .. } => { InputEvent::CursorEntered { .. } => {
opts.cursor_inside_window = true; opts.cursor_inside_window = true;
}, }
InputEvent::CursorLeft { .. } => { InputEvent::CursorLeft { .. } => {
opts.cursor_inside_window = false; opts.cursor_inside_window = false;
}, }
_ => {}, _ => {}
} }
} }
} }
@ -370,10 +476,10 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
} }
impl Plugin for WindowPlugin { impl Plugin for WindowPlugin {
fn setup(&self, game: &mut crate::game::Game) { fn setup(&self, app: &mut crate::game::App) {
let window_options = WindowOptions::default(); let window_options = WindowOptions::default();
game.world_mut().add_resource(Ct::new(window_options)); app.world.add_resource(Ct::new(window_options));
game.with_system("window_updater", window_updater_system, &[]); app.with_system("window_updater", window_updater_system, &[]);
} }
} }

View File

@ -1,7 +1,7 @@
use glam::{EulerRot, Quat, Vec3}; use glam::{EulerRot, Quat, Vec3};
use lyra_ecs::{query::{Res, View}, Component}; use lyra_ecs::{query::{Res, View}, Component};
use crate::{game::Game, input::ActionHandler, plugin::Plugin, DeltaTime}; use crate::{game::App, input::ActionHandler, plugin::Plugin, DeltaTime};
use super::CameraComponent; use super::CameraComponent;
@ -97,7 +97,7 @@ pub fn free_fly_camera_controller(delta_time: Res<DeltaTime>, handler: Res<Actio
pub struct FreeFlyCameraPlugin; pub struct FreeFlyCameraPlugin;
impl Plugin for FreeFlyCameraPlugin { impl Plugin for FreeFlyCameraPlugin {
fn setup(&self, game: &mut Game) { fn setup(&self, app: &mut App) {
game.with_system("free_fly_camera_system", free_fly_camera_controller, &[]); app.with_system("free_fly_camera_system", free_fly_camera_controller, &[]);
} }
} }

View File

@ -6,4 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
glam = { version = "0.24.0" } glam = { version = "0.29.0" }

View File

@ -13,9 +13,9 @@ lyra-scene = { path = "../lyra-scene" }
anyhow = "1.0.75" anyhow = "1.0.75"
base64 = "0.21.4" base64 = "0.21.4"
crossbeam = { version = "0.8.4", features = [ "crossbeam-channel" ] } crossbeam = { version = "0.8.4", features = [ "crossbeam-channel" ] }
glam = "0.24.1" glam = "0.29.0"
gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness", "KHR_materials_specular"] } gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness", "KHR_materials_specular"] }
image = "0.24.7" image = "0.25.2"
# not using custom matcher, or file type from file path # not using custom matcher, or file type from file path
infer = { version = "0.15.0", default-features = false } infer = { version = "0.15.0", default-features = false }
mime = "0.3.17" mime = "0.3.17"

@ -1 +1 @@
Subproject commit 54c9926a04cdef657289fd67730c0b85d1bdda3e Subproject commit a761f4094bc18190285b4687ec804161fea874b6

View File

@ -1,4 +1,5 @@
[toolchain] [toolchain]
channel = "nightly-2023-11-21" #channel = "nightly-2023-11-21"
channel = "nightly"
#date = "2023-11-21" #date = "2023-11-21"
targets = [ "x86_64-unknown-linux-gnu" ] targets = [ "x86_64-unknown-linux-gnu" ]