Update wgpu to 0.20.1 and winit to 0.30.3 #26
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -25,7 +25,7 @@ use tracing::info;
|
|||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let action_handler_plugin = |game: &mut Game| {
|
||||
let action_handler_plugin = |app: &mut App| {
|
||||
let action_handler = ActionHandler::builder()
|
||||
.add_layout(LayoutId::from(0))
|
||||
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
|
||||
|
@ -105,7 +105,7 @@ async fn main() {
|
|||
.await;
|
||||
}
|
||||
|
||||
fn setup_scene_plugin(game: &mut Game) {
|
||||
fn setup_scene_plugin(app: &mut App) {
|
||||
let world = game.world_mut();
|
||||
let resman = world.get_resource_mut::<ResourceManager>();
|
||||
let camera_gltf = resman
|
||||
|
|
|
@ -18,7 +18,7 @@ use lyra_engine::{
|
|||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let action_handler_plugin = |game: &mut Game| {
|
||||
let action_handler_plugin = |app: &mut App| {
|
||||
let action_handler = ActionHandler::builder()
|
||||
.add_layout(LayoutId::from(0))
|
||||
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
|
||||
|
@ -99,7 +99,7 @@ async fn main() {
|
|||
.await;
|
||||
}
|
||||
|
||||
fn setup_scene_plugin(game: &mut Game) {
|
||||
fn setup_scene_plugin(app: &mut App) {
|
||||
let world = game.world_mut();
|
||||
let resman = world.get_resource_mut::<ResourceManager>();
|
||||
let camera_gltf = resman
|
||||
|
@ -136,7 +136,7 @@ fn setup_scene_plugin(game: &mut Game) {
|
|||
world.spawn((camera, FreeFlyCamera::default()));
|
||||
}
|
||||
|
||||
fn setup_script_plugin(game: &mut Game) {
|
||||
fn setup_script_plugin(app: &mut App) {
|
||||
game.with_plugin(LuaScriptingPlugin);
|
||||
|
||||
let world = game.world_mut();
|
||||
|
|
|
@ -21,7 +21,7 @@ const POINT_LIGHT_MIN_Z: f32 = -5.0;
|
|||
#[async_std::main]
|
||||
async fn main() {
|
||||
|
||||
let action_handler_plugin = |game: &mut Game| {
|
||||
let action_handler_plugin = |app: &mut App| {
|
||||
let action_handler = ActionHandler::builder()
|
||||
.add_layout(LayoutId::from(0))
|
||||
|
||||
|
@ -80,7 +80,7 @@ async fn main() {
|
|||
.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 tick = counter.tick();
|
||||
|
||||
|
@ -174,7 +174,7 @@ fn setup_scene_plugin(game: &mut Game) {
|
|||
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<()> {
|
||||
if handler.was_action_just_pressed("Debug") {
|
||||
for mut cam in view.into_iter() {
|
||||
|
|
|
@ -19,7 +19,7 @@ use lyra_engine::{
|
|||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let action_handler_plugin = |game: &mut Game| {
|
||||
let action_handler_plugin = |app: &mut App| {
|
||||
let action_handler = ActionHandler::builder()
|
||||
.add_layout(LayoutId::from(0))
|
||||
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
|
||||
|
@ -99,7 +99,7 @@ async fn main() {
|
|||
.await;
|
||||
}
|
||||
|
||||
fn setup_scene_plugin(game: &mut Game) {
|
||||
fn setup_scene_plugin(app: &mut App) {
|
||||
let world = game.world_mut();
|
||||
let resman = world.get_resource_mut::<ResourceManager>();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use lyra_engine::{
|
||||
assets::{gltf::Gltf, ResourceManager},
|
||||
game::Game,
|
||||
game::App,
|
||||
input::{
|
||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
||||
InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput,
|
||||
|
@ -16,7 +16,7 @@ use lyra_engine::{
|
|||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let action_handler_plugin = |game: &mut Game| {
|
||||
let action_handler_plugin = |app: &mut App| {
|
||||
let action_handler = ActionHandler::builder()
|
||||
.add_layout(LayoutId::from(0))
|
||||
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
|
||||
|
@ -31,61 +31,61 @@ async fn main() {
|
|||
.bind(
|
||||
ACTLBL_MOVE_FORWARD_BACKWARD,
|
||||
&[
|
||||
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::KeyW).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::KeyS).into_binding_modifier(-1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_MOVE_LEFT_RIGHT,
|
||||
&[
|
||||
ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::KeyA).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::KeyD).into_binding_modifier(1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_MOVE_UP_DOWN,
|
||||
&[
|
||||
ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::KeyC).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::KeyZ).into_binding_modifier(-1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_LOOK_LEFT_RIGHT,
|
||||
&[
|
||||
ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(),
|
||||
ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::ArrowLeft).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::ArrowRight).into_binding_modifier(1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_LOOK_UP_DOWN,
|
||||
&[
|
||||
ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(),
|
||||
ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::ArrowUp).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::ArrowDown).into_binding_modifier(1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_LOOK_ROLL,
|
||||
&[
|
||||
ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::KeyE).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::KeyQ).into_binding_modifier(1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
"Debug",
|
||||
&[ActionSource::Keyboard(KeyCode::B).into_binding()],
|
||||
&[ActionSource::Keyboard(KeyCode::KeyB).into_binding()],
|
||||
)
|
||||
.finish(),
|
||||
)
|
||||
.finish();
|
||||
|
||||
let world = game.world_mut();
|
||||
let world = app.world_mut();
|
||||
world.add_resource(action_handler);
|
||||
game.with_plugin(InputActionPlugin);
|
||||
app.with_plugin(InputActionPlugin);
|
||||
};
|
||||
|
||||
Game::initialize()
|
||||
App::initialize()
|
||||
.await
|
||||
.with_plugin(lyra_engine::DefaultPlugins)
|
||||
.with_plugin(setup_scene_plugin)
|
||||
|
@ -96,7 +96,7 @@ async fn main() {
|
|||
.await;
|
||||
}
|
||||
|
||||
fn setup_scene_plugin(game: &mut Game) {
|
||||
fn setup_scene_plugin(app: &mut App) {
|
||||
let world = game.world_mut();
|
||||
let resman = world.get_resource_mut::<ResourceManager>();
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ async fn main() {
|
|||
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<()> {
|
||||
if handler.was_action_just_pressed("Debug") {
|
||||
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, &[]);
|
||||
};
|
||||
|
||||
let action_handler_plugin = |game: &mut Game| {
|
||||
let action_handler_plugin = |app: &mut App| {
|
||||
let action_handler = ActionHandler::builder()
|
||||
.add_layout(LayoutId::from(0))
|
||||
|
||||
|
@ -327,7 +327,7 @@ async fn main() {
|
|||
game.with_plugin(InputActionPlugin);
|
||||
};
|
||||
|
||||
/* let script_test_plugin = |game: &mut Game| {
|
||||
/* let script_test_plugin = |app: &mut App| {
|
||||
game.with_plugin(LuaScriptingPlugin);
|
||||
|
||||
let world = game.world_mut();
|
||||
|
|
|
@ -197,11 +197,9 @@ mod tests {
|
|||
let mut view_iter = view.into_iter();
|
||||
while let Some((_e, view_row)) = view_iter.next(&world) {
|
||||
assert_eq!(view_row.len(), 1);
|
||||
|
||||
let mut row_iter = view_row.row.iter();
|
||||
let mut row_iter = view_row.iter();
|
||||
|
||||
let dynamic_type = row_iter.next().unwrap();
|
||||
|
||||
let component_data = unsafe { dynamic_type.ptr.cast::<u32>().as_ref() };
|
||||
assert_eq!(*component_data, 50);
|
||||
}
|
||||
|
@ -226,11 +224,9 @@ mod tests {
|
|||
|
||||
for (_e, view_row) in view.into_iter() {
|
||||
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() };
|
||||
assert_eq!(*component_data, 50);
|
||||
}
|
||||
|
|
|
@ -12,31 +12,30 @@ lyra-math = { path = "../lyra-math" }
|
|||
lyra-scene = { path = "../lyra-scene" }
|
||||
wgsl_preprocessor = { path = "../wgsl-preprocessor" }
|
||||
|
||||
winit = "0.28.1"
|
||||
wgpu = { version = "0.15.1", features = [ "expose-ids"] }
|
||||
winit = "0.30.5"
|
||||
wgpu = { version = "22.1.0" }
|
||||
|
||||
tracing = "0.1.37"
|
||||
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-tracy = { version = "0.11.0", optional = true }
|
||||
|
||||
async-std = { version = "1.12.0", features = [ "unstable", "attributes" ] }
|
||||
cfg-if = "1"
|
||||
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"
|
||||
instant = "0.1"
|
||||
async-trait = "0.1.65"
|
||||
glam = { version = "0.24.0", features = ["bytemuck", "debug-glam-assert"] }
|
||||
gilrs-core = "0.5.6"
|
||||
glam = { version = "0.29.0", features = ["bytemuck", "debug-glam-assert"] }
|
||||
syn = "2.0.26"
|
||||
quote = "1.0.29"
|
||||
uuid = { version = "1.5.0", features = ["v4", "fast-rng"] }
|
||||
itertools = "0.11.0"
|
||||
itertools = "0.13.0"
|
||||
thiserror = "1.0.56"
|
||||
unique = "0.9.1"
|
||||
rustc-hash = "1.1.0"
|
||||
rustc-hash = "2.0.0"
|
||||
petgraph = { version = "0.6.5", features = ["matrix_graph"] }
|
||||
bind_match = "0.1.2"
|
||||
round_mult = "0.1.3"
|
||||
|
|
|
@ -42,8 +42,8 @@ pub fn delta_time_system(world: &mut World) -> anyhow::Result<()> {
|
|||
pub struct DeltaTimePlugin;
|
||||
|
||||
impl Plugin for DeltaTimePlugin {
|
||||
fn setup(&self, game: &mut crate::game::Game) {
|
||||
game.world_mut().add_resource(DeltaTime(0.0, None));
|
||||
game.add_system_to_stage(GameStages::First, "delta_time", delta_time_system, &[]);
|
||||
fn setup(&self, app: &mut crate::game::App) {
|
||||
app.world.add_resource(DeltaTime(0.0, None));
|
||||
app.add_system_to_stage(GameStages::First, "delta_time", delta_time_system, &[]);
|
||||
}
|
||||
}
|
|
@ -196,7 +196,7 @@ impl<E: Event> Iterator for EventReader<E> {
|
|||
pub struct EventsPlugin;
|
||||
|
||||
impl Plugin for EventsPlugin {
|
||||
fn setup(&self, game: &mut crate::game::Game) {
|
||||
game.world_mut().add_resource(EventQueue::new());
|
||||
fn setup(&self, app: &mut crate::game::App) {
|
||||
app.world.add_resource(EventQueue::new());
|
||||
}
|
||||
}
|
|
@ -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::{World, system::{System, IntoSystem}};
|
||||
use tracing::{error, info, Level};
|
||||
use lyra_ecs::{system::{IntoSystem, System}, ResourceObject, World};
|
||||
use lyra_math::{IVec2, Vec2};
|
||||
use rustc_hash::FxHashMap;
|
||||
use tracing::{debug, debug_span, info, Level};
|
||||
use tracing_appender::non_blocking;
|
||||
use tracing_subscriber::{
|
||||
layer::SubscriberExt,
|
||||
|
@ -11,7 +11,7 @@ use tracing_subscriber::{
|
|||
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};
|
||||
|
||||
|
@ -37,8 +37,13 @@ pub struct Controls<'a> {
|
|||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct WindowState {
|
||||
pub is_focused: bool,
|
||||
pub is_cursor_inside_window: bool,
|
||||
/// Indicates if the window is currently focused.
|
||||
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 {
|
||||
|
@ -47,216 +52,41 @@ impl WindowState {
|
|||
}
|
||||
}
|
||||
|
||||
struct GameLoop {
|
||||
window: Arc<Window>,
|
||||
renderer: Box<dyn Renderer>,
|
||||
|
||||
world: World,
|
||||
|
||||
pub struct App {
|
||||
windows: FxHashMap<WindowId, Arc<Window>>,
|
||||
renderer: OnceCell<Box<dyn Renderer>>,
|
||||
pub world: World,
|
||||
plugins: VecDeque<Box<dyn Plugin>>,
|
||||
startup_systems: VecDeque<Box<dyn System>>,
|
||||
staged_exec: StagedExecutor,
|
||||
run_fn: OnceCell<Box<dyn FnOnce(App)>>,
|
||||
}
|
||||
|
||||
impl GameLoop {
|
||||
pub async fn new(window: Arc<Window>, mut world: World, staged_exec: StagedExecutor) -> Self {
|
||||
let renderer = BasicRenderer::create_with_window(&mut world, window.clone()).await;
|
||||
|
||||
impl App {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
window: Arc::clone(&window),
|
||||
renderer: Box::new(renderer),
|
||||
|
||||
world,
|
||||
staged_exec,
|
||||
windows: FxHashMap::default(),
|
||||
renderer: OnceCell::new(),
|
||||
world: World::new(),
|
||||
plugins: Default::default(),
|
||||
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>) {
|
||||
self.renderer.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_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) {
|
||||
info!("On exit!");
|
||||
}
|
||||
|
||||
pub async fn run_event_loop(&mut self, event: Event<'_, ()>, control_flow: &mut ControlFlow) {
|
||||
*control_flow = ControlFlow::Poll;
|
||||
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()
|
||||
pub fn add_resource<T: ResourceObject>(&mut self, data: T) {
|
||||
self.world.add_resource(data);
|
||||
}
|
||||
|
||||
/// Add a system to the ecs world
|
||||
|
@ -265,8 +95,7 @@ impl Game {
|
|||
S: IntoSystem<A>,
|
||||
<S as IntoSystem<A>>::System: 'static
|
||||
{
|
||||
let system_dispatcher = self.system_exec.as_mut().unwrap();
|
||||
system_dispatcher.add_system_to_stage(GameStages::Update, name, system.into_system(), depends);
|
||||
self.staged_exec.add_system_to_stage(GameStages::Update, name, system.into_system(), depends);
|
||||
|
||||
self
|
||||
}
|
||||
|
@ -275,8 +104,7 @@ impl Game {
|
|||
///
|
||||
/// 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 {
|
||||
let system_dispatcher = self.system_exec.as_mut().unwrap();
|
||||
system_dispatcher.add_stage(stage);
|
||||
self.staged_exec.add_stage(stage);
|
||||
|
||||
self
|
||||
}
|
||||
|
@ -287,8 +115,7 @@ impl Game {
|
|||
/// * `before` - The stage that will run before `after`.
|
||||
/// * `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 {
|
||||
let system_dispatcher = self.system_exec.as_mut().unwrap();
|
||||
system_dispatcher.add_stage_after(before, after);
|
||||
self.staged_exec.add_stage_after(before, after);
|
||||
|
||||
self
|
||||
}
|
||||
|
@ -304,8 +131,7 @@ impl Game {
|
|||
S: IntoSystem<A>,
|
||||
<S as IntoSystem<A>>::System: 'static
|
||||
{
|
||||
let system_dispatcher = self.system_exec.as_mut().unwrap();
|
||||
system_dispatcher.add_system_to_stage(stage, name, system.into_system(), depends);
|
||||
self.staged_exec.add_system_to_stage(stage, name, system.into_system(), depends);
|
||||
|
||||
self
|
||||
}
|
||||
|
@ -337,53 +163,85 @@ impl Game {
|
|||
///
|
||||
/// 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 {
|
||||
self.world = Some(world);
|
||||
|
||||
self.world = world;
|
||||
self
|
||||
}
|
||||
|
||||
/// Start the game
|
||||
pub async fn run(&mut self) {
|
||||
// init logging
|
||||
let (stdout_layer, _stdout_nb) = non_blocking(std::io::stdout());
|
||||
{
|
||||
let t = tracing_subscriber::registry()
|
||||
.with(fmt::layer().with_writer(stdout_layer));
|
||||
|
||||
#[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();
|
||||
}
|
||||
|
||||
|
||||
let world = self.world.take().unwrap_or_default();
|
||||
|
||||
// run startup systems
|
||||
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!");
|
||||
startup.execute(world_ptr).expect("World returned an error!");
|
||||
}
|
||||
|
||||
// start winit event loops
|
||||
let event_loop = EventLoop::new();
|
||||
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
|
||||
|
||||
let system_dispatcher = self.system_exec.take().unwrap();
|
||||
let mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatcher).await;
|
||||
g_loop.on_init().await;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
g_loop.run_sync(event, control_flow);
|
||||
});
|
||||
fn set_run_fn<F>(&self, f: F)
|
||||
where
|
||||
F: FnOnce(App) + 'static
|
||||
{
|
||||
// ignore if a runner function was already set
|
||||
let _ = self.run_fn.set(Box::new(f));
|
||||
}
|
||||
}
|
||||
|
||||
fn run(mut self) {
|
||||
let f = self.run_fn.take()
|
||||
.expect("No run function set");
|
||||
f(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl ApplicationHandler for App {
|
||||
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||
debug!("Resumed");
|
||||
}
|
||||
|
||||
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 window = match self.windows.get_mut(&window_id) {
|
||||
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!(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -597,7 +597,7 @@ fn actions_system(world: &mut World) -> anyhow::Result<()> {
|
|||
pub struct InputActionPlugin;
|
||||
|
||||
impl Plugin for InputActionPlugin {
|
||||
fn setup(&self, game: &mut crate::game::Game) {
|
||||
game.add_system_to_stage(GameStages::PreUpdate, "input_actions", actions_system, &[]);
|
||||
fn setup(&self, app: &mut crate::game::App) {
|
||||
app.add_system_to_stage(GameStages::PreUpdate, "input_actions", actions_system, &[]);
|
||||
}
|
||||
}
|
|
@ -88,6 +88,8 @@ pub enum MouseButton {
|
|||
Left,
|
||||
Right,
|
||||
Middle,
|
||||
Back,
|
||||
Forward,
|
||||
Other(u16),
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
@ -19,7 +19,7 @@ pub enum InputEvent {
|
|||
/// An event from the keyboard has been received.
|
||||
KeyboardInput {
|
||||
device_id: DeviceId,
|
||||
input: KeyboardInput,
|
||||
event: KeyEvent,
|
||||
|
||||
/// 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.
|
||||
|
@ -28,20 +28,10 @@ pub enum InputEvent {
|
|||
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.
|
||||
CursorMoved {
|
||||
device_id: DeviceId,
|
||||
position: PhysicalPosition<f64>,
|
||||
modifiers: ModifiersState,
|
||||
},
|
||||
|
||||
/// The cursor has entered the window.
|
||||
|
@ -59,8 +49,6 @@ pub enum InputEvent {
|
|||
device_id: DeviceId,
|
||||
delta: MouseScrollDelta,
|
||||
phase: TouchPhase,
|
||||
/// Deprecated in favor of WindowEvent::ModifiersChanged
|
||||
modifiers: ModifiersState,
|
||||
},
|
||||
|
||||
/// An mouse button press has been received.
|
||||
|
@ -68,51 +56,6 @@ pub enum InputEvent {
|
|||
device_id: DeviceId,
|
||||
state: ElementState,
|
||||
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.
|
||||
|
@ -136,89 +79,62 @@ pub enum InputEvent {
|
|||
/// Touch event has been received
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Web**: Doesn’t take into account CSS border, padding, or transform.
|
||||
/// - **macOS:** Unsupported.
|
||||
Touch(Touch),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum InputEventConversionError<'a> {
|
||||
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> {
|
||||
impl InputEvent {
|
||||
pub fn from_window_event(value: &WindowEvent) -> Option<Self> {
|
||||
match value {
|
||||
WindowEvent::KeyboardInput { device_id, input, is_synthetic } =>
|
||||
Ok(InputEvent::KeyboardInput {
|
||||
WindowEvent::KeyboardInput { device_id, event, is_synthetic } =>
|
||||
Some(InputEvent::KeyboardInput {
|
||||
device_id: *device_id,
|
||||
input: *input,
|
||||
event: event.clone(),
|
||||
is_synthetic: *is_synthetic
|
||||
}),
|
||||
#[allow(deprecated, reason="Compatibility")]
|
||||
WindowEvent::CursorMoved { device_id, position, modifiers } =>
|
||||
Ok(InputEvent::CursorMoved {
|
||||
WindowEvent::CursorMoved { device_id, position, } =>
|
||||
Some(InputEvent::CursorMoved {
|
||||
device_id: *device_id,
|
||||
position: *position,
|
||||
modifiers: *modifiers
|
||||
}),
|
||||
WindowEvent::CursorEntered { device_id } =>
|
||||
Ok(InputEvent::CursorEntered {
|
||||
Some(InputEvent::CursorEntered {
|
||||
device_id: *device_id
|
||||
}),
|
||||
WindowEvent::CursorLeft { device_id } =>
|
||||
Ok(InputEvent::CursorLeft {
|
||||
Some(InputEvent::CursorLeft {
|
||||
device_id: *device_id
|
||||
}),
|
||||
#[allow(deprecated, reason="Compatibility")]
|
||||
WindowEvent::MouseWheel { device_id, delta, phase, modifiers } =>
|
||||
Ok(InputEvent::MouseWheel {
|
||||
WindowEvent::MouseWheel { device_id, delta, phase } =>
|
||||
Some(InputEvent::MouseWheel {
|
||||
device_id: *device_id,
|
||||
delta: *delta,
|
||||
phase: *phase,
|
||||
modifiers: *modifiers
|
||||
}),
|
||||
#[allow(deprecated, reason="Compatibility")]
|
||||
WindowEvent::MouseInput { device_id, state, button, modifiers } =>
|
||||
Ok(InputEvent::MouseInput {
|
||||
WindowEvent::MouseInput { device_id, state, button } =>
|
||||
Some(InputEvent::MouseInput {
|
||||
device_id: *device_id,
|
||||
state: *state,
|
||||
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 } =>
|
||||
Ok(InputEvent::TouchpadPressure {
|
||||
Some(InputEvent::TouchpadPressure {
|
||||
device_id: *device_id,
|
||||
pressure: *pressure,
|
||||
stage: *stage
|
||||
}),
|
||||
WindowEvent::AxisMotion { device_id, axis, value } =>
|
||||
Ok(InputEvent::AxisMotion {
|
||||
Some(InputEvent::AxisMotion {
|
||||
device_id: *device_id,
|
||||
axis: *axis,
|
||||
value: *value
|
||||
}),
|
||||
WindowEvent::Touch(t) => Ok(InputEvent::Touch(*t)),
|
||||
|
||||
_ => Err(InputEventConversionError::FromError(value))
|
||||
WindowEvent::Touch(t) => Some(InputEvent::Touch(*t)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ pub use buttons::*;
|
|||
pub mod action;
|
||||
pub use action::*;
|
||||
|
||||
pub type KeyCode = winit::event::VirtualKeyCode;
|
||||
pub type KeyCode = winit::keyboard::KeyCode;
|
||||
|
||||
/// Parses a [`KeyCode`] from a [`&str`].
|
||||
///
|
||||
|
@ -24,42 +24,42 @@ pub fn keycode_from_str(s: &str) -> Option<KeyCode> {
|
|||
let s = s.as_str();
|
||||
|
||||
match s {
|
||||
"1" => Some(KeyCode::Key1),
|
||||
"2" => Some(KeyCode::Key2),
|
||||
"3" => Some(KeyCode::Key3),
|
||||
"4" => Some(KeyCode::Key4),
|
||||
"5" => Some(KeyCode::Key5),
|
||||
"6" => Some(KeyCode::Key6),
|
||||
"7" => Some(KeyCode::Key7),
|
||||
"8" => Some(KeyCode::Key8),
|
||||
"9" => Some(KeyCode::Key9),
|
||||
"0" => Some(KeyCode::Key0),
|
||||
"a" => Some(KeyCode::A),
|
||||
"b" => Some(KeyCode::B),
|
||||
"c" => Some(KeyCode::C),
|
||||
"d" => Some(KeyCode::D),
|
||||
"e" => Some(KeyCode::E),
|
||||
"f" => Some(KeyCode::F),
|
||||
"g" => Some(KeyCode::G),
|
||||
"h" => Some(KeyCode::H),
|
||||
"i" => Some(KeyCode::I),
|
||||
"j" => Some(KeyCode::J),
|
||||
"k" => Some(KeyCode::K),
|
||||
"l" => Some(KeyCode::L),
|
||||
"m" => Some(KeyCode::M),
|
||||
"n" => Some(KeyCode::N),
|
||||
"o" => Some(KeyCode::O),
|
||||
"p" => Some(KeyCode::P),
|
||||
"q" => Some(KeyCode::Q),
|
||||
"r" => Some(KeyCode::R),
|
||||
"s" => Some(KeyCode::S),
|
||||
"t" => Some(KeyCode::T),
|
||||
"u" => Some(KeyCode::U),
|
||||
"v" => Some(KeyCode::V),
|
||||
"w" => Some(KeyCode::W),
|
||||
"x" => Some(KeyCode::X),
|
||||
"y" => Some(KeyCode::Y),
|
||||
"z" => Some(KeyCode::Z),
|
||||
"1" => Some(KeyCode::Digit1),
|
||||
"2" => Some(KeyCode::Digit2),
|
||||
"3" => Some(KeyCode::Digit3),
|
||||
"4" => Some(KeyCode::Digit4),
|
||||
"5" => Some(KeyCode::Digit5),
|
||||
"6" => Some(KeyCode::Digit6),
|
||||
"7" => Some(KeyCode::Digit7),
|
||||
"8" => Some(KeyCode::Digit8),
|
||||
"9" => Some(KeyCode::Digit9),
|
||||
"0" => Some(KeyCode::Digit0),
|
||||
"a" => Some(KeyCode::KeyA),
|
||||
"b" => Some(KeyCode::KeyB),
|
||||
"c" => Some(KeyCode::KeyC),
|
||||
"d" => Some(KeyCode::KeyD),
|
||||
"e" => Some(KeyCode::KeyE),
|
||||
"f" => Some(KeyCode::KeyF),
|
||||
"g" => Some(KeyCode::KeyG),
|
||||
"h" => Some(KeyCode::KeyH),
|
||||
"i" => Some(KeyCode::KeyI),
|
||||
"j" => Some(KeyCode::KeyJ),
|
||||
"k" => Some(KeyCode::KeyK),
|
||||
"l" => Some(KeyCode::KeyL),
|
||||
"m" => Some(KeyCode::KeyM),
|
||||
"n" => Some(KeyCode::KeyN),
|
||||
"o" => Some(KeyCode::KeyO),
|
||||
"p" => Some(KeyCode::KeyP),
|
||||
"q" => Some(KeyCode::KeyQ),
|
||||
"r" => Some(KeyCode::KeyR),
|
||||
"s" => Some(KeyCode::KeyS),
|
||||
"t" => Some(KeyCode::KeyT),
|
||||
"u" => Some(KeyCode::KeyU),
|
||||
"v" => Some(KeyCode::KeyV),
|
||||
"w" => Some(KeyCode::KeyW),
|
||||
"x" => Some(KeyCode::KeyX),
|
||||
"y" => Some(KeyCode::KeyY),
|
||||
"z" => Some(KeyCode::KeyZ),
|
||||
"escape" => Some(KeyCode::Escape),
|
||||
"f1" => Some(KeyCode::F1),
|
||||
"f2" => Some(KeyCode::F2),
|
||||
|
@ -85,25 +85,23 @@ pub fn keycode_from_str(s: &str) -> Option<KeyCode> {
|
|||
"f22" => Some(KeyCode::F22),
|
||||
"f23" => Some(KeyCode::F23),
|
||||
"f24" => Some(KeyCode::F24),
|
||||
"snapshot" => Some(KeyCode::Snapshot),
|
||||
"scroll" => Some(KeyCode::Scroll),
|
||||
"print_screen" => Some(KeyCode::PrintScreen),
|
||||
"scroll_lock" => Some(KeyCode::ScrollLock),
|
||||
"pause" => Some(KeyCode::Pause),
|
||||
"insert" => Some(KeyCode::Insert),
|
||||
"home" => Some(KeyCode::Home),
|
||||
"delete" => Some(KeyCode::Delete),
|
||||
"end" => Some(KeyCode::End),
|
||||
"pagedown" => Some(KeyCode::PageDown),
|
||||
"pageup" => Some(KeyCode::PageUp),
|
||||
"left" => Some(KeyCode::Left),
|
||||
"up" => Some(KeyCode::Up),
|
||||
"right" => Some(KeyCode::Right),
|
||||
"down" => Some(KeyCode::Down),
|
||||
"back" => Some(KeyCode::Back),
|
||||
"return" => Some(KeyCode::Return),
|
||||
"page_down" => Some(KeyCode::PageDown),
|
||||
"page_up" => Some(KeyCode::PageUp),
|
||||
"left" => Some(KeyCode::ArrowLeft),
|
||||
"up" => Some(KeyCode::ArrowUp),
|
||||
"right" => Some(KeyCode::ArrowRight),
|
||||
"down" => Some(KeyCode::ArrowDown),
|
||||
"backspace" => Some(KeyCode::Backspace),
|
||||
"enter" => Some(KeyCode::Enter),
|
||||
"space" => Some(KeyCode::Space),
|
||||
"compose" => Some(KeyCode::Compose),
|
||||
"caret" => Some(KeyCode::Caret),
|
||||
"numlock" => Some(KeyCode::Numlock),
|
||||
"numlock" => Some(KeyCode::NumLock),
|
||||
"numpad0" => Some(KeyCode::Numpad0),
|
||||
"numpad1" => Some(KeyCode::Numpad1),
|
||||
"numpad2" => Some(KeyCode::Numpad2),
|
||||
|
@ -114,76 +112,62 @@ pub fn keycode_from_str(s: &str) -> Option<KeyCode> {
|
|||
"numpad7" => Some(KeyCode::Numpad7),
|
||||
"numpad8" => Some(KeyCode::Numpad8),
|
||||
"numpad9" => Some(KeyCode::Numpad9),
|
||||
"numpadadd" => Some(KeyCode::NumpadAdd),
|
||||
"numpaddivide" => Some(KeyCode::NumpadDivide),
|
||||
"numpaddecimal" => Some(KeyCode::NumpadDecimal),
|
||||
"numpadcomma" => Some(KeyCode::NumpadComma),
|
||||
"numpadenter" => Some(KeyCode::NumpadEnter),
|
||||
"numpadequals" => Some(KeyCode::NumpadEquals),
|
||||
"numpadmultiply" => Some(KeyCode::NumpadMultiply),
|
||||
"numpadsubtract" => Some(KeyCode::NumpadSubtract),
|
||||
"abntc1" => Some(KeyCode::AbntC1),
|
||||
"abntc2" => Some(KeyCode::AbntC2),
|
||||
"apostrophe" => Some(KeyCode::Apostrophe),
|
||||
"apps" => Some(KeyCode::Apps),
|
||||
"asterisk" => Some(KeyCode::Asterisk),
|
||||
"at" => Some(KeyCode::At),
|
||||
"ax" => Some(KeyCode::Ax),
|
||||
"numpad_add" => Some(KeyCode::NumpadAdd),
|
||||
"numpad_divide" => Some(KeyCode::NumpadDivide),
|
||||
"numpad_decimal" => Some(KeyCode::NumpadDecimal),
|
||||
"numpad_comma" => Some(KeyCode::NumpadComma),
|
||||
"numpad_enter" => Some(KeyCode::NumpadEnter),
|
||||
"numpad_multiply" => Some(KeyCode::NumpadMultiply),
|
||||
"numpad_subtract" => Some(KeyCode::NumpadSubtract),
|
||||
"numpad_star" => Some(KeyCode::NumpadStar),
|
||||
"quote" => Some(KeyCode::Quote),
|
||||
"launch_app1" => Some(KeyCode::LaunchApp1),
|
||||
"launch_app1" => Some(KeyCode::LaunchApp2),
|
||||
"backslash" => Some(KeyCode::Backslash),
|
||||
"calculator" => Some(KeyCode::Calculator),
|
||||
"capital" => Some(KeyCode::Capital),
|
||||
"colon" => Some(KeyCode::Colon),
|
||||
"caps_lock" => Some(KeyCode::CapsLock),
|
||||
"comma" => Some(KeyCode::Comma),
|
||||
"convert" => Some(KeyCode::Convert),
|
||||
"equals" => Some(KeyCode::Equals),
|
||||
"grave" => Some(KeyCode::Grave),
|
||||
"kana" => Some(KeyCode::Kana),
|
||||
"kanji" => Some(KeyCode::Kanji),
|
||||
"lalt" => Some(KeyCode::LAlt),
|
||||
"lbracket" => Some(KeyCode::LBracket),
|
||||
"lcontrol" => Some(KeyCode::LControl),
|
||||
"lshift" => Some(KeyCode::LShift),
|
||||
"lwin" => Some(KeyCode::LWin),
|
||||
"mail" => Some(KeyCode::Mail),
|
||||
"mediaselect" => Some(KeyCode::MediaSelect),
|
||||
"mediastop" => Some(KeyCode::MediaStop),
|
||||
"equal" => Some(KeyCode::Equal),
|
||||
"grave" | "backquote" => Some(KeyCode::Backquote),
|
||||
"kana_mode" => Some(KeyCode::KanaMode),
|
||||
"katakana" => Some(KeyCode::Katakana),
|
||||
"alt_left" => Some(KeyCode::AltLeft),
|
||||
"alt_right" => Some(KeyCode::AltRight),
|
||||
"bracket_left" => Some(KeyCode::BracketLeft),
|
||||
"bracket_right" => Some(KeyCode::BracketRight),
|
||||
"control_left" => Some(KeyCode::ControlLeft),
|
||||
"control-right" => Some(KeyCode::ControlRight),
|
||||
"shift_left" => Some(KeyCode::ShiftLeft),
|
||||
"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),
|
||||
"mute" => Some(KeyCode::Mute),
|
||||
"mycomputer" => Some(KeyCode::MyComputer),
|
||||
"navigateforward" => Some(KeyCode::NavigateForward),
|
||||
"navigatebackward" => Some(KeyCode::NavigateBackward),
|
||||
"nexttrack" => Some(KeyCode::NextTrack),
|
||||
"noconvert" => Some(KeyCode::NoConvert),
|
||||
"oem102" => Some(KeyCode::OEM102),
|
||||
"mute" => Some(KeyCode::AudioVolumeMute),
|
||||
"browser_forward" => Some(KeyCode::BrowserForward),
|
||||
"browser_back" => Some(KeyCode::BrowserBack),
|
||||
"webfavorites" => Some(KeyCode::BrowserFavorites),
|
||||
"webhome" => Some(KeyCode::BrowserHome),
|
||||
"webrefresh" => Some(KeyCode::BrowserRefresh),
|
||||
"websearch" => Some(KeyCode::BrowserSearch),
|
||||
"webstop" => Some(KeyCode::BrowserStop),
|
||||
"non_convert" => Some(KeyCode::NonConvert),
|
||||
"period" => Some(KeyCode::Period),
|
||||
"playpause" => Some(KeyCode::PlayPause),
|
||||
"plus" => Some(KeyCode::Plus),
|
||||
"play_pause" => Some(KeyCode::MediaPlayPause),
|
||||
"plus" => Some(KeyCode::NumpadAdd),
|
||||
"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),
|
||||
"slash" => Some(KeyCode::Slash),
|
||||
"sleep" => Some(KeyCode::Sleep),
|
||||
"stop" => Some(KeyCode::Stop),
|
||||
"sysrq" => Some(KeyCode::Sysrq),
|
||||
"tab" => Some(KeyCode::Tab),
|
||||
"underline" => Some(KeyCode::Underline),
|
||||
"unlabeled" => Some(KeyCode::Unlabeled),
|
||||
"volumedown" => Some(KeyCode::VolumeDown),
|
||||
"volumeup" => Some(KeyCode::VolumeUp),
|
||||
"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),
|
||||
"volume_down" => Some(KeyCode::AudioVolumeDown),
|
||||
"volume_up" => Some(KeyCode::AudioVolumeUp),
|
||||
"wake_up" => Some(KeyCode::WakeUp),
|
||||
"yen" => Some(KeyCode::IntlYen),
|
||||
"copy" => Some(KeyCode::Copy),
|
||||
"paste" => Some(KeyCode::Paste),
|
||||
"cut" => Some(KeyCode::Cut),
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::ptr::NonNull;
|
|||
|
||||
use glam::Vec2;
|
||||
use lyra_ecs::{World, system::IntoSystem};
|
||||
use winit::event::MouseScrollDelta;
|
||||
use winit::{event::MouseScrollDelta, keyboard::PhysicalKey};
|
||||
|
||||
use crate::{EventQueue, plugin::Plugin, game::GameStages};
|
||||
|
||||
|
@ -20,21 +20,14 @@ impl InputSystem {
|
|||
let mut event_queue = event_queue.unwrap();
|
||||
|
||||
match event {
|
||||
InputEvent::KeyboardInput { input, .. } => {
|
||||
if let Some(code) = input.virtual_keycode {
|
||||
InputEvent::KeyboardInput { device_id, event, .. } => {
|
||||
if let PhysicalKey::Code(code) = event.physical_key {
|
||||
drop(event_queue);
|
||||
let mut e = world.get_resource_or_else(InputButtons::<winit::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());
|
||||
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, .. } => {
|
||||
let exact = MouseExact {
|
||||
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::Right => MouseButton::Right,
|
||||
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),
|
||||
};
|
||||
|
||||
|
@ -102,7 +97,7 @@ impl crate::ecs::system::System for InputSystem {
|
|||
let queue = world.try_get_resource_mut::<EventQueue>()
|
||||
.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();
|
||||
drop(e);
|
||||
|
||||
|
@ -140,7 +135,7 @@ impl IntoSystem<()> for InputSystem {
|
|||
pub struct InputPlugin;
|
||||
|
||||
impl Plugin for InputPlugin {
|
||||
fn setup(&self, game: &mut crate::game::Game) {
|
||||
game.add_system_to_stage(GameStages::PreUpdate, "input", InputSystem, &[]);
|
||||
fn setup(&self, app: &mut crate::game::App) {
|
||||
app.add_system_to_stage(GameStages::PreUpdate, "input", InputSystem, &[]);
|
||||
}
|
||||
}
|
|
@ -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_resource::ResourceManager;
|
||||
|
||||
use crate::game::App;
|
||||
use crate::EventsPlugin;
|
||||
use crate::DeltaTimePlugin;
|
||||
use crate::game::Game;
|
||||
use crate::input::InputPlugin;
|
||||
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.
|
||||
pub trait Plugin {
|
||||
/// Setup this plugin. This runs before the game has started
|
||||
fn setup(&self, game: &mut Game);
|
||||
/// Setup this plugin. This runs before the app has started
|
||||
fn setup(&self, app: &mut App);
|
||||
|
||||
fn is_ready(&self, _game: &mut Game) -> bool {
|
||||
fn is_ready(&self, app: &mut App) -> bool {
|
||||
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
|
||||
where P: Fn(&mut Game)
|
||||
where P: Fn(&mut App)
|
||||
{
|
||||
fn setup(&self, game: &mut Game) {
|
||||
self(game);
|
||||
fn setup(&self, app: &mut App) {
|
||||
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 {
|
||||
fn setup(&self, game: &mut Game) {
|
||||
fn setup(&self, app: &mut App) {
|
||||
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;
|
||||
|
||||
impl Plugin for ResourceManagerPlugin {
|
||||
fn setup(&self, game: &mut Game) {
|
||||
game.world_mut().add_resource(ResourceManager::new());
|
||||
fn setup(&self, app: &mut App) {
|
||||
app.world.add_resource(ResourceManager::new());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,13 +126,13 @@ impl Plugin for ResourceManagerPlugin {
|
|||
pub struct DefaultPlugins;
|
||||
|
||||
impl Plugin for DefaultPlugins {
|
||||
fn setup(&self, game: &mut Game) {
|
||||
CommandQueuePlugin.setup(game);
|
||||
EventsPlugin.setup(game);
|
||||
InputPlugin.setup(game);
|
||||
ResourceManagerPlugin.setup(game);
|
||||
WindowPlugin::default().setup(game);
|
||||
DeltaTimePlugin.setup(game);
|
||||
fn setup(&self, app: &mut App) {
|
||||
CommandQueuePlugin.setup(app);
|
||||
EventsPlugin.setup(app);
|
||||
InputPlugin.setup(app);
|
||||
ResourceManagerPlugin.setup(app);
|
||||
WindowPlugin::default().setup(app);
|
||||
DeltaTimePlugin.setup(app);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +142,7 @@ impl Plugin for DefaultPlugins {
|
|||
pub struct CommandQueuePlugin;
|
||||
|
||||
impl Plugin for CommandQueuePlugin {
|
||||
fn setup(&self, game: &mut Game) {
|
||||
game.world_mut().add_resource(CommandQueue::default());
|
||||
fn setup(&self, app: &mut App) {
|
||||
app.world.add_resource(CommandQueue::default());
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ pub struct RenderGraphContext<'a> {
|
|||
pub device: Arc<wgpu::Device>,
|
||||
pub queue: Arc<wgpu::Queue>,
|
||||
pub(crate) buffer_writes: VecDeque<GraphBufferWrite>,
|
||||
renderpass_desc: Vec<wgpu::RenderPassDescriptor<'a, 'a>>,
|
||||
renderpass_desc: Vec<wgpu::RenderPassDescriptor<'a>>,
|
||||
/// The label of this Node.
|
||||
pub label: RenderGraphLabelValue,
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ impl<'a> RenderGraphContext<'a> {
|
|||
|
||||
pub fn begin_render_pass(
|
||||
&'a mut self,
|
||||
desc: wgpu::RenderPassDescriptor<'a, 'a>,
|
||||
desc: wgpu::RenderPassDescriptor<'a>,
|
||||
) -> wgpu::RenderPass {
|
||||
self.encoder
|
||||
.as_mut()
|
||||
|
|
|
@ -17,7 +17,7 @@ pub struct FxaaPass {
|
|||
/// Store bind groups for the input textures.
|
||||
/// The texture may change due to resizes, or changes to the view target chain
|
||||
/// from other nodes.
|
||||
bg_cache: HashMap<wgpu::Id, wgpu::BindGroup>,
|
||||
bg_cache: HashMap<wgpu::Id<wgpu::TextureView>, wgpu::BindGroup>,
|
||||
}
|
||||
|
||||
impl FxaaPass {
|
||||
|
@ -157,10 +157,12 @@ impl Node for FxaaPass {
|
|||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
store: true,
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None, // TODO: occlusion queries
|
||||
});
|
||||
pass.set_pipeline(pipeline.as_render());
|
||||
|
||||
|
|
|
@ -235,6 +235,8 @@ impl Node for LightCullComputePass {
|
|||
],
|
||||
shader,
|
||||
shader_entry_point: "cs_main".into(),
|
||||
cache: None,
|
||||
compilation_options: Default::default(),
|
||||
});
|
||||
|
||||
self.pipeline = Some(pipeline);
|
||||
|
@ -251,6 +253,7 @@ impl Node for LightCullComputePass {
|
|||
|
||||
let mut pass = context.begin_compute_pass(&wgpu::ComputePassDescriptor {
|
||||
label: Some("light_cull_pass"),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
pass.set_pipeline(pipeline);
|
||||
|
|
|
@ -604,8 +604,8 @@ impl GpuMaterial {
|
|||
&img.to_rgba8(),
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: std::num::NonZeroU32::new(4 * dim.0),
|
||||
rows_per_image: std::num::NonZeroU32::new(dim.1),
|
||||
bytes_per_row: Some(4 * dim.0),
|
||||
rows_per_image: Some(dim.1),
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: dim.0,
|
||||
|
|
|
@ -420,7 +420,7 @@ impl Node for MeshPass {
|
|||
b: 0.3,
|
||||
a: 1.0,
|
||||
}),
|
||||
store: true,
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
// enable depth buffer
|
||||
|
@ -428,10 +428,11 @@ impl Node for MeshPass {
|
|||
view: depth_view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
store: wgpu::StoreOp::Store,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
pass.set_pipeline(pipeline);
|
||||
|
|
|
@ -865,10 +865,11 @@ impl Node for ShadowMapsPass {
|
|||
view: atlas.view(),
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
store: wgpu::StoreOp::Store,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
for light_depth_map in self.depth_maps.values() {
|
||||
|
|
|
@ -17,7 +17,7 @@ pub struct TintPass {
|
|||
/// Store bind groups for the input textures.
|
||||
/// The texture may change due to resizes, or changes to the view target chain
|
||||
/// from other nodes.
|
||||
bg_cache: HashMap<wgpu::Id, wgpu::BindGroup>,
|
||||
bg_cache: HashMap<wgpu::Id<wgpu::TextureView>, wgpu::BindGroup>,
|
||||
}
|
||||
|
||||
impl TintPass {
|
||||
|
@ -152,10 +152,12 @@ impl Node for TintPass {
|
|||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
store: true,
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
pass.set_pipeline(pipeline.as_render());
|
||||
|
||||
|
|
|
@ -6,10 +6,19 @@ use crate::math;
|
|||
|
||||
enum RenderTargetInner {
|
||||
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,
|
||||
},
|
||||
Texture {
|
||||
/// The texture that will be rendered to.
|
||||
texture: Arc<wgpu::Texture>,
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +34,7 @@ impl From<wgpu::Texture> for 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 })
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{mem, num::{NonZeroU32, NonZeroU8}};
|
||||
use std::mem;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TextureViewDescriptor {
|
||||
|
@ -16,13 +16,13 @@ pub struct TextureViewDescriptor {
|
|||
/// Mip level 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.
|
||||
pub mip_level_count: Option<NonZeroU32>,
|
||||
pub mip_level_count: Option<u32>,
|
||||
/// Base array layer.
|
||||
pub base_array_layer: u32,
|
||||
/// Layer 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.
|
||||
pub array_layer_count: Option<NonZeroU32>,
|
||||
pub array_layer_count: Option<u32>,
|
||||
}
|
||||
|
||||
impl TextureViewDescriptor {
|
||||
|
@ -79,7 +79,7 @@ pub struct SamplerDescriptor {
|
|||
/// If this is enabled, this is a comparison sampler using the given comparison function.
|
||||
pub compare: Option<wgpu::CompareFunction>,
|
||||
/// 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`]
|
||||
pub border_color: Option<wgpu::SamplerBorderColor>,
|
||||
}
|
||||
|
|
|
@ -75,10 +75,11 @@ impl BasicRenderer {
|
|||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: wgpu::Backends::all(),
|
||||
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 = unsafe { instance.create_surface(window.as_ref()) }.unwrap();
|
||||
let surface: wgpu::Surface::<'static> = instance.create_surface(window.clone()).unwrap();
|
||||
|
||||
let adapter = instance.request_adapter(
|
||||
&wgpu::RequestAdapterOptions {
|
||||
|
@ -90,11 +91,12 @@ impl BasicRenderer {
|
|||
|
||||
let (device, queue) = adapter.request_device(
|
||||
&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.
|
||||
// Not sure if the engine will ever completely support WASM,
|
||||
// but its here just in case
|
||||
limits: if cfg!(target_arch = "wasm32") {
|
||||
required_limits: if cfg!(target_arch = "wasm32") {
|
||||
wgpu::Limits::downlevel_webgl2_defaults()
|
||||
} else {
|
||||
wgpu::Limits {
|
||||
|
@ -102,7 +104,7 @@ impl BasicRenderer {
|
|||
..Default::default()
|
||||
}
|
||||
},
|
||||
label: None,
|
||||
memory_hints: wgpu::MemoryHints::MemoryUsage,
|
||||
},
|
||||
None,
|
||||
).await.unwrap();
|
||||
|
@ -113,7 +115,7 @@ impl BasicRenderer {
|
|||
|
||||
let surface_format = surface_caps.formats.iter()
|
||||
.copied()
|
||||
.find(|f| f.describe().srgb)
|
||||
.find(|f| f.is_srgb())
|
||||
.unwrap_or(surface_caps.formats[0]);
|
||||
let config = wgpu::SurfaceConfiguration {
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
||||
|
@ -122,6 +124,7 @@ impl BasicRenderer {
|
|||
height: size.height,
|
||||
present_mode: wgpu::PresentMode::default(), //wgpu::PresentMode::Mailbox, // "Fast Vsync"
|
||||
alpha_mode: surface_caps.alpha_modes[0],
|
||||
desired_maximum_frame_latency: 2,
|
||||
view_formats: vec![],
|
||||
};
|
||||
surface.configure(&device, &config);
|
||||
|
|
|
@ -2,19 +2,25 @@ use std::{ops::Deref, rc::Rc, sync::Arc};
|
|||
|
||||
use wgpu::PipelineLayout;
|
||||
|
||||
use super::Shader;
|
||||
use super::{PipelineCompilationOptions, Shader};
|
||||
|
||||
//#[derive(Debug, Clone)]
|
||||
pub struct ComputePipelineDescriptor {
|
||||
pub label: Option<String>,
|
||||
pub layouts: Vec<Arc<wgpu::BindGroupLayout>>,
|
||||
pub push_constant_ranges: Vec<wgpu::PushConstantRange>,
|
||||
// TODO: make this a ResHandle<Shader>
|
||||
/// The compiled shader module for the stage.
|
||||
pub shader: Rc<Shader>,
|
||||
/// The entry point in the compiled shader.
|
||||
/// There must be a function in the shader with the same name.
|
||||
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 {
|
||||
|
@ -28,7 +34,7 @@ impl ComputePipelineDescriptor {
|
|||
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: None, //self.label.as_ref().map(|s| format!("{}Layout", s)),
|
||||
bind_group_layouts: &bgs,
|
||||
bind_group_layouts: &bgs,
|
||||
push_constant_ranges: &self.push_constant_ranges,
|
||||
})
|
||||
}
|
||||
|
@ -85,6 +91,8 @@ impl ComputePipeline {
|
|||
layout: layout.as_ref(),
|
||||
module: &compiled_shader,
|
||||
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);
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
mod shader;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use shader::*;
|
||||
|
||||
mod pipeline;
|
||||
|
@ -11,4 +13,21 @@ mod render_pipeline;
|
|||
pub use render_pipeline::*;
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -97,6 +97,7 @@ impl RenderPipeline {
|
|||
module: &vrtx_shad,
|
||||
entry_point: &desc.vertex.entry_point,
|
||||
buffers: &vrtx_buffs,
|
||||
compilation_options: Default::default(),
|
||||
};
|
||||
|
||||
let frag_module = desc.fragment.as_ref().map(|f| {
|
||||
|
@ -115,6 +116,7 @@ impl RenderPipeline {
|
|||
module: fm.unwrap(),
|
||||
entry_point: &f.entry_point,
|
||||
targets: &f.targets,
|
||||
compilation_options: Default::default(),
|
||||
});
|
||||
|
||||
let render_desc = wgpu::RenderPipelineDescriptor {
|
||||
|
@ -126,6 +128,7 @@ impl RenderPipeline {
|
|||
multisample: desc.multisample,
|
||||
fragment: fstate,
|
||||
multiview: desc.multiview,
|
||||
cache: None,
|
||||
};
|
||||
|
||||
let render_pipeline = device.create_render_pipeline(&render_desc);
|
||||
|
|
|
@ -105,8 +105,8 @@ impl RenderTexture {
|
|||
&rgba,
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
|
||||
rows_per_image: std::num::NonZeroU32::new(dimensions.1),
|
||||
bytes_per_row: Some(4 * dimensions.0),
|
||||
rows_per_image: Some(dimensions.1),
|
||||
},
|
||||
size,
|
||||
);
|
||||
|
@ -169,8 +169,8 @@ impl RenderTexture {
|
|||
&rgba,
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
|
||||
rows_per_image: std::num::NonZeroU32::new(dimensions.1),
|
||||
bytes_per_row: Some(4 * dimensions.0),
|
||||
rows_per_image: Some(dimensions.1),
|
||||
},
|
||||
size,
|
||||
);
|
||||
|
@ -247,8 +247,8 @@ impl RenderTexture {
|
|||
&rgba,
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
|
||||
rows_per_image: std::num::NonZeroU32::new(dimensions.1),
|
||||
bytes_per_row: Some(4 * dimensions.0),
|
||||
rows_per_image: Some(dimensions.1),
|
||||
},
|
||||
size,
|
||||
);
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use glam::{Vec2, IVec2};
|
||||
use glam::{IVec2, Vec2};
|
||||
use lyra_ecs::World;
|
||||
use tracing::{warn, error};
|
||||
use winit::{window::{Window, Fullscreen}, dpi::{LogicalPosition, LogicalSize, PhysicalPosition}, error::ExternalError};
|
||||
use tracing::{error, warn};
|
||||
use winit::{
|
||||
dpi::{LogicalPosition, LogicalSize, PhysicalPosition},
|
||||
error::ExternalError,
|
||||
window::{Fullscreen, Window},
|
||||
};
|
||||
|
||||
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)]
|
||||
pub enum WindowMode {
|
||||
|
@ -20,6 +24,75 @@ pub enum WindowMode {
|
|||
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.
|
||||
#[derive(Clone)]
|
||||
pub struct WindowOptions {
|
||||
|
@ -43,11 +116,13 @@ pub struct WindowOptions {
|
|||
/// * iOS / Android / Web / X11 / Orbital: Unsupported.
|
||||
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.
|
||||
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 cursor’s visibility.
|
||||
/// 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.
|
||||
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 look of this box may differ between input devices, even on the same platform.
|
||||
pub ime_position: Vec2,
|
||||
/// The windowing system could place a candidate box close to that area, but try to not
|
||||
/// obscure the specified area, so the user input to it stays visible.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// (Apple’s 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.
|
||||
///
|
||||
/// Platform-specific:
|
||||
/// * iOS / Android: Unsupported.
|
||||
/// * Web: Sets the size of the canvas element.
|
||||
pub inner_size: IVec2,
|
||||
pub inner_size: Size,
|
||||
|
||||
/// Sets a maximum dimension size for the window.
|
||||
///
|
||||
/// Platform-specific:
|
||||
/// * 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.
|
||||
///
|
||||
/// Platform-specific:
|
||||
/// * iOS / Android / Web / Orbital: Unsupported.
|
||||
pub min_inner_size: Option<IVec2>,
|
||||
pub min_inner_size: Option<Size>,
|
||||
|
||||
/// Sets the window to maximized or back.
|
||||
///
|
||||
|
@ -186,14 +273,14 @@ impl Default for WindowOptions {
|
|||
content_protected: false,
|
||||
cursor_grab: CursorGrabMode::None,
|
||||
cursor_hittest: true,
|
||||
cursor_icon: CursorIcon::Default,
|
||||
cursor: Default::default(),
|
||||
cursor_visible: true,
|
||||
decorations: true,
|
||||
enabled_buttons: WindowButtons::all(),
|
||||
mode: WindowMode::Windowed,
|
||||
ime_allowed: false,
|
||||
ime_position: Default::default(),
|
||||
inner_size: glam::i32::IVec2::new(800, 600),
|
||||
ime_cursor_area: Area::default(),
|
||||
inner_size: Size::new_physical(800, 600),
|
||||
max_inner_size: None,
|
||||
min_inner_size: None,
|
||||
maximized: false,
|
||||
|
@ -224,7 +311,10 @@ fn vec2_to_logical_pos(pos: Vec2) -> LogicalPosition<f32> {
|
|||
|
||||
/// Convert an IVec2 to a 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>>
|
||||
|
@ -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>>
|
||||
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.
|
||||
|
@ -250,9 +343,13 @@ fn set_cursor_grab(window: &Window, grab: &mut CursorGrabMode) -> anyhow::Result
|
|||
*grab = CursorGrabMode::Confined; // NOTE: May support Locked later
|
||||
} else if cfg!(target_os = "macos") {
|
||||
*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");
|
||||
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,
|
||||
/// and the window is focused, set the cursor position to the center of the screen.
|
||||
fn center_mouse(window: &Window, options: &WindowOptions) {
|
||||
if options.cursor_grab == CursorGrabMode::Confined && !options.cursor_visible
|
||||
&& options.focused {
|
||||
if options.cursor_grab == CursorGrabMode::Confined && !options.cursor_visible && options.focused
|
||||
{
|
||||
let size = window.inner_size();
|
||||
let middle = PhysicalPosition {
|
||||
x: size.width / 2,
|
||||
|
@ -276,7 +373,10 @@ fn center_mouse(window: &Window, options: &WindowOptions) {
|
|||
}
|
||||
|
||||
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 opts.peek_changed() {
|
||||
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);
|
||||
set_cursor_grab(&window, &mut opts.cursor_grab)?;
|
||||
match window.set_cursor_hittest(opts.cursor_hittest) {
|
||||
Ok(()) => {},
|
||||
Err(ExternalError::NotSupported(_)) => { /* ignore */ },
|
||||
Ok(()) => {}
|
||||
Err(ExternalError::NotSupported(_)) => { /* ignore */ }
|
||||
Err(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_decorations(opts.decorations); // 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
|
||||
if let Some(monitor) = window.current_monitor()
|
||||
.or_else(|| window.primary_monitor())
|
||||
.or_else(|| window.available_monitors().next()) {
|
||||
if let Some(monitor) = window
|
||||
.current_monitor()
|
||||
.or_else(|| window.primary_monitor())
|
||||
.or_else(|| window.available_monitors().next())
|
||||
{
|
||||
match opts.mode {
|
||||
WindowMode::Borderless => window.set_fullscreen(Some(Fullscreen::Borderless(Some(monitor)))),
|
||||
WindowMode::Fullscreen => window.set_fullscreen(Some(Fullscreen::Exclusive(monitor.video_modes().next().unwrap()))),
|
||||
WindowMode::Borderless => {
|
||||
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),
|
||||
}
|
||||
} else {
|
||||
|
@ -315,13 +421,13 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
window.set_ime_allowed(opts.ime_allowed);
|
||||
window.set_ime_position(vec2_to_logical_pos(opts.ime_position));
|
||||
window.set_inner_size(ivec2_to_logical_size(opts.inner_size));
|
||||
window.set_ime_cursor_area(opts.ime_cursor_area.position, opts.ime_cursor_area.size);
|
||||
window.request_inner_size(opts.inner_size);
|
||||
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() {
|
||||
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_minimized(opts.minimized);
|
||||
|
@ -346,11 +452,11 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
|
|||
match ev {
|
||||
InputEvent::CursorEntered { .. } => {
|
||||
opts.cursor_inside_window = true;
|
||||
},
|
||||
}
|
||||
InputEvent::CursorLeft { .. } => {
|
||||
opts.cursor_inside_window = false;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -370,10 +476,10 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
game.world_mut().add_resource(Ct::new(window_options));
|
||||
game.with_system("window_updater", window_updater_system, &[]);
|
||||
app.world.add_resource(Ct::new(window_options));
|
||||
app.with_system("window_updater", window_updater_system, &[]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use glam::{EulerRot, Quat, Vec3};
|
||||
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;
|
||||
|
||||
|
@ -97,7 +97,7 @@ pub fn free_fly_camera_controller(delta_time: Res<DeltaTime>, handler: Res<Actio
|
|||
pub struct FreeFlyCameraPlugin;
|
||||
|
||||
impl Plugin for FreeFlyCameraPlugin {
|
||||
fn setup(&self, game: &mut Game) {
|
||||
game.with_system("free_fly_camera_system", free_fly_camera_controller, &[]);
|
||||
fn setup(&self, app: &mut App) {
|
||||
app.with_system("free_fly_camera_system", free_fly_camera_controller, &[]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
glam = { version = "0.24.0" }
|
||||
glam = { version = "0.29.0" }
|
|
@ -13,9 +13,9 @@ lyra-scene = { path = "../lyra-scene" }
|
|||
anyhow = "1.0.75"
|
||||
base64 = "0.21.4"
|
||||
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"] }
|
||||
image = "0.24.7"
|
||||
image = "0.25.2"
|
||||
# not using custom matcher, or file type from file path
|
||||
infer = { version = "0.15.0", default-features = false }
|
||||
mime = "0.3.17"
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 54c9926a04cdef657289fd67730c0b85d1bdda3e
|
||||
Subproject commit a761f4094bc18190285b4687ec804161fea874b6
|
|
@ -1,4 +1,5 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2023-11-21"
|
||||
#channel = "nightly-2023-11-21"
|
||||
channel = "nightly"
|
||||
#date = "2023-11-21"
|
||||
targets = [ "x86_64-unknown-linux-gnu" ]
|
Loading…
Reference in New Issue