update wgpu and winit to latest versions
need to make a WinitPlugin though, so no window currently
This commit is contained in:
parent
2b44d7f354
commit
45fd190409
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_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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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());
|
{
|
||||||
{
|
// ignore if a runner function was already set
|
||||||
let t = tracing_subscriber::registry()
|
let _ = self.run_fn.set(Box::new(f));
|
||||||
.with(fmt::layer().with_writer(stdout_layer));
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tracy")]
|
fn run(mut self) {
|
||||||
let t = t.with(tracing_tracy::TracyLayer::default());
|
let f = self.run_fn.take()
|
||||||
|
.expect("No run function set");
|
||||||
t.with(filter::Targets::new()
|
f(self);
|
||||||
// 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)
|
impl ApplicationHandler for App {
|
||||||
.with_target("winit", Level::DEBUG)
|
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||||
.with_default(Level::INFO))
|
debug!("Resumed");
|
||||||
.init();
|
}
|
||||||
}
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
let world = self.world.take().unwrap_or_default();
|
event_loop: &winit::event_loop::ActiveEventLoop,
|
||||||
|
window_id: winit::window::WindowId,
|
||||||
// run startup systems
|
event: WindowEvent,
|
||||||
while let Some(mut startup) = self.startup_systems.pop_front() {
|
) {
|
||||||
let startup = startup.as_mut();
|
//let _e = debug_span!("window_event", window=window_id).entered();
|
||||||
let world_ptr = NonNull::from(&world);
|
let window = match self.windows.get_mut(&window_id) {
|
||||||
startup.setup(world_ptr).expect("World returned an error!");
|
Some(w) => w,
|
||||||
startup.execute(world_ptr).expect("World returned an error!");
|
None => return,
|
||||||
}
|
};
|
||||||
|
|
||||||
// start winit event loops
|
// If try_from failed, that means that the WindowEvent is not an
|
||||||
let event_loop = EventLoop::new();
|
// input related event.
|
||||||
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
|
if let Some(input_ev) = InputEvent::from_window_event(&event) {
|
||||||
|
// Its possible to receive multiple input events before the update event for
|
||||||
let system_dispatcher = self.system_exec.take().unwrap();
|
// the InputSystem is called, so we must use a queue for the events.
|
||||||
let mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatcher).await;
|
if let Some(mut event_queue) = self.world.try_get_resource_mut::<EventQueue>() {
|
||||||
g_loop.on_init().await;
|
event_queue.trigger_event(input_ev.clone());
|
||||||
|
}
|
||||||
event_loop.run(move |event, _, control_flow| {
|
} else {
|
||||||
g_loop.run_sync(event, control_flow);
|
|
||||||
});
|
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;
|
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, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -88,6 +88,8 @@ pub enum MouseButton {
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
Middle,
|
Middle,
|
||||||
|
Back,
|
||||||
|
Forward,
|
||||||
Other(u16),
|
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.
|
/// 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**: Doesn’t 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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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),
|
||||||
|
|
|
@ -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, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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()
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
|
@ -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 cursor’s visibility.
|
/// The cursor’s 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.
|
||||||
|
///
|
||||||
|
/// (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.
|
/// 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
|
||||||
.or_else(|| window.primary_monitor())
|
.current_monitor()
|
||||||
.or_else(|| window.available_monitors().next()) {
|
.or_else(|| window.primary_monitor())
|
||||||
|
.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, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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" }
|
|
@ -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
|
|
@ -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" ]
|
Loading…
Reference in New Issue