diff --git a/src/events.rs b/src/events.rs new file mode 100644 index 0000000..bab5db7 --- /dev/null +++ b/src/events.rs @@ -0,0 +1,55 @@ +use glam::UVec2; +use shipyard::{World, Component, AllStoragesViewMut, SparseSet}; +use glium::glutin::event::{Event, DeviceEvent, DeviceId, WindowEvent}; + +#[derive(Component, Clone, Copy, Debug, Default)] +pub struct EventComponent; + +#[derive(Component, Clone, Copy, Debug, Default)] +pub struct OnBeforeExitEvent; + +#[derive(Component, Clone, Debug)] +pub struct InputDeviceEvent{ + pub device_id: DeviceId, + pub event: DeviceEvent +} + +#[derive(Component, Clone, Copy, Debug, Default)] +pub struct WindowResizedEvent(UVec2); + +pub fn process_glutin_events(world: &mut World, event: &Event<'_, ()>) { + #[allow(clippy::collapsible_match, clippy::single_match)] + match event { + Event::WindowEvent { window_id: _, event } => match event { + WindowEvent::Resized(size) => { + world.add_entity(( + EventComponent, + WindowResizedEvent(UVec2::new(size.width as _, size.height as _)) + )); + }, + _ => () + }, + Event::DeviceEvent { device_id, event } => { + world.add_entity(( + EventComponent, + InputDeviceEvent { + device_id: *device_id, + event: event.clone() + } + )); + }, + Event::LoopDestroyed => { + world.add_entity(( + EventComponent, + OnBeforeExitEvent + )); + }, + _ => (), + } +} + +pub fn clear_events( + mut all_storages: AllStoragesViewMut, +) { + all_storages.delete_any::>(); +} diff --git a/src/input.rs b/src/input.rs index 1d0736b..eb5031e 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,6 +1,73 @@ -use glium::glutin::event::VirtualKeyCode; -use shipyard::{AllStoragesView, Unique}; -use hashbrown::HashMap; +use glam::{Vec2, DVec2}; +use glium::glutin::event::{DeviceEvent, VirtualKeyCode, ElementState}; +use hashbrown::HashSet; use nohash_hasher::BuildNoHashHasher; +use shipyard::{AllStoragesView, Unique, View, IntoIter, UniqueViewMut, Workload, IntoWorkload, UniqueView}; +use crate::events::InputDeviceEvent; -//todo +#[derive(Unique, Clone, Copy, Default, Debug)] +pub struct Inputs { + pub movement: Vec2, + pub look: Vec2, + pub action_a: bool, + pub action_b: bool, +} + +#[derive(Unique, Clone, Default, Debug)] +pub struct RawInputState { + pub keyboard_state: HashSet>, + pub mouse_delta: DVec2 +} + +pub fn process_events( + device_events: View, + mut input_state: UniqueViewMut, +) { + input_state.mouse_delta = DVec2::ZERO; + for event in device_events.iter() { + match event.event { + DeviceEvent::MouseMotion { delta } => { + input_state.mouse_delta = DVec2::from(delta); + }, + DeviceEvent::Key(input) => { + if let Some(keycode) = input.virtual_keycode { + match input.state { + ElementState::Pressed => input_state.keyboard_state.insert(keycode), + ElementState::Released => input_state.keyboard_state.remove(&keycode), + }; + } + }, + DeviceEvent::Button { button, state } => { + println!("Button {button} {state:?}"); + }, + _ => () + } + } +} + +pub fn update_input_states ( + raw_inputs: UniqueView, + mut inputs: UniqueViewMut, +) { + inputs.movement = Vec2::new( + raw_inputs.keyboard_state.contains(&VirtualKeyCode::D) as u32 as f32 - + raw_inputs.keyboard_state.contains(&VirtualKeyCode::A) as u32 as f32, + raw_inputs.keyboard_state.contains(&VirtualKeyCode::W) as u32 as f32 - + raw_inputs.keyboard_state.contains(&VirtualKeyCode::S) as u32 as f32 + ).normalize_or_zero(); + inputs.look = raw_inputs.mouse_delta.as_vec2(); +} + +pub fn init_input ( + storages: AllStoragesView +) { + storages.add_unique(Inputs::default()); + storages.add_unique(RawInputState::default()); +} + +pub fn process_inputs() -> Workload { + ( + process_events, + update_input_states + ).into_workload() +} diff --git a/src/main.rs b/src/main.rs index cf209f1..d9f3243 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,28 +20,36 @@ pub(crate) mod prefabs; pub(crate) mod transform; pub(crate) mod settings; pub(crate) mod camera; +pub(crate) mod events; pub(crate) mod input; pub(crate) mod fly_controller; use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background}; -use world::{loading::update_loaded_world_around_player, render::draw_world, init_world}; +use world::{loading::update_loaded_world_around_player, render::draw_world, init_game_world}; use player::spawn_player; use prefabs::load_prefabs; use settings::GameSettings; use camera::compute_cameras; +use events::{clear_events, process_glutin_events}; +use input::{init_input, process_inputs}; #[derive(Unique)] pub(crate) struct DeltaTime(Duration); fn startup() -> Workload { ( + load_prefabs, + init_input, + init_game_world, spawn_player, ).into_workload() } fn update() -> Workload { ( + process_inputs, update_loaded_world_around_player, compute_cameras, + clear_events ).into_workload() } fn render() -> Workload { @@ -58,15 +66,13 @@ fn main() { let event_loop = EventLoop::new(); //Create a shipyard world - let world = World::new(); + let mut world = World::new(); //Add systems and uniques, Init and load things world.add_unique_non_send_sync(Renderer::init(&event_loop)); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); world.add_unique(DeltaTime(Duration::default())); world.add_unique(GameSettings::default()); - load_prefabs(&world); - init_world(&world); //Register workloads world.add_workload(startup); @@ -80,6 +86,7 @@ fn main() { let mut last_update = Instant::now(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; + process_glutin_events(&mut world, &event); match event { Event::WindowEvent { event, .. } => match event { WindowEvent::Resized(_size) => { diff --git a/src/prefabs.rs b/src/prefabs.rs index f215f50..6043bcf 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -1,4 +1,4 @@ -use shipyard::{World, NonSendSync, UniqueView, Unique}; +use shipyard::{NonSendSync, UniqueView, Unique, AllStoragesView}; use glium::{texture::{SrgbTexture2dArray, MipmapsOption}, Program}; use strum::EnumIter; use crate::rendering::Renderer; @@ -56,16 +56,18 @@ pub struct BlockTexturesPrefab(pub SrgbTexture2dArray); #[derive(Unique)] pub struct ChunkShaderPrefab(pub Program); -pub fn load_prefabs(world: &World) { - let renderer = world.borrow::>>().unwrap(); - world.add_unique_non_send_sync(BlockTexturesPrefab( +pub fn load_prefabs( + storages: AllStoragesView, + renderer: NonSendSync> +) { + storages.add_unique_non_send_sync(BlockTexturesPrefab( load_texture2darray_prefab::( "./assets/blocks/".into(), &renderer.display, MipmapsOption::AutoGeneratedMipmaps ) )); - world.add_unique_non_send_sync(ChunkShaderPrefab( + storages.add_unique_non_send_sync(ChunkShaderPrefab( include_shader_prefab!( "../shaders/world.vert", "../shaders/world.frag", diff --git a/src/world.rs b/src/world.rs index a4281e3..2f3ace1 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,5 +1,5 @@ use nohash_hasher::BuildNoHashHasher; -use shipyard::{Unique, World}; +use shipyard::{Unique, AllStoragesView}; use glam::IVec3; use hashbrown::HashMap; use anyhow::{Result, Context}; @@ -66,8 +66,10 @@ impl ChunkMeshStorage { } } -pub fn init_world(world: &World) { - world.add_unique_non_send_sync(ChunkMeshStorage::new()); - world.add_unique(ChunkStorage::new()); - world.add_unique(ChunkTaskManager::new()); +pub fn init_game_world( + storages: AllStoragesView, +) { + storages.add_unique_non_send_sync(ChunkMeshStorage::new()); + storages.add_unique(ChunkStorage::new()); + storages.add_unique(ChunkTaskManager::new()); }