| @@ -1,5 +1,6 @@ | |||
| #![allow(dead_code)] | |||
| use std::borrow::Borrow; | |||
| use std::convert::{AsMut, AsRef}; | |||
| use std::fmt::{Debug, Formatter, Result as FmtResult}; | |||
| use std::ops::{Deref, DerefMut, Mul}; | |||
| @@ -432,7 +433,7 @@ where | |||
| Matrix4::new( | |||
| Vector4::new(two / (right - left), zero, zero, zero), | |||
| Vector4::new(zero, two / (top - bottom), zero, zero), | |||
| Vector4::new(zero, zero, -zero / (far - near), zero), | |||
| Vector4::new(zero, zero, -two / (far - near), zero), | |||
| Vector4::new( | |||
| -(right + left) / (right - left), | |||
| -(top + bottom) / (top - bottom), | |||
| @@ -467,25 +468,15 @@ where | |||
| } | |||
| } | |||
| impl<T> Mul<Matrix4<T>> for Matrix4<T> | |||
| impl<T, M> Mul<M> for Matrix4<T> | |||
| where | |||
| T: Element, | |||
| M: Borrow<Matrix4<T>>, | |||
| { | |||
| type Output = Self; | |||
| fn mul(self, rhs: Self) -> Self::Output { | |||
| self.multiply(&rhs) | |||
| } | |||
| } | |||
| impl<T> Mul<Vector4<T>> for Matrix4<T> | |||
| where | |||
| T: Element, | |||
| { | |||
| type Output = Vector4<T>; | |||
| fn mul(self, rhs: Vector4<T>) -> Self::Output { | |||
| self.transform(&rhs) | |||
| fn mul(self, rhs: M) -> Self::Output { | |||
| self.multiply(rhs.borrow()) | |||
| } | |||
| } | |||
| @@ -135,6 +135,18 @@ macro_rules! define_vec { | |||
| } | |||
| } | |||
| impl<T> From<T> for $Name<T> | |||
| where | |||
| T: Copy, | |||
| { | |||
| #[inline] | |||
| fn from(value: T) -> Self { | |||
| Self { | |||
| $($f: value,)+ | |||
| } | |||
| } | |||
| } | |||
| impl<T> From<($($T,)+)> for $Name<T> { | |||
| #[inline] | |||
| fn from(($($f,)+): ($($T,)+)) -> Self { | |||
| @@ -16,7 +16,7 @@ num_cpus = "1.13" | |||
| ordered-float = "2.0" | |||
| rand = "0.7" | |||
| serde_yaml = "0.8" | |||
| shred = "0.10" | |||
| shred = { version = "0.10", features = [ "shred-derive" ] } | |||
| shrev = "1.1" | |||
| specs = "0.16" | |||
| thiserror = "1.0" | |||
| @@ -1,27 +1,17 @@ | |||
| #version 450 core | |||
| in vec4 gl_FragCoord; | |||
| layout (std140, binding = 0) uniform Camera { | |||
| mat4 proj_world; | |||
| mat4 proj_ui; | |||
| mat4 view; | |||
| } camera; | |||
| out vec4 color; | |||
| const float NOISE_RANGE = 0.05; | |||
| const float NOISE_BASE = 0.05; | |||
| float random (vec2 st) { | |||
| return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123); | |||
| float random(vec4 seed) { | |||
| return fract(sin(dot(seed, vec4(12.9898, 78.233, 45.164, 53.1324))) * 43758.5453); | |||
| } | |||
| void main() { | |||
| vec4 pos = inverse(camera.view) * gl_FragCoord; | |||
| vec2 ipos = floor(pos.xy); | |||
| vec3 rbg = vec3(NOISE_BASE + NOISE_RANGE * random(ipos)); | |||
| float rnd = random(gl_FragCoord); | |||
| vec3 rgb = vec3(NOISE_BASE + NOISE_RANGE * rnd); | |||
| color = vec4(rbg, 1.0); | |||
| color = vec4(rgb, 1.0); | |||
| } | |||
| @@ -3,9 +3,9 @@ | |||
| layout (location = 0) in vec3 position; | |||
| layout (std140, binding = 0) uniform Camera { | |||
| mat4 proj_world; | |||
| mat4 proj_ui; | |||
| mat4 projection; | |||
| mat4 view; | |||
| vec2 size; | |||
| } camera; | |||
| layout (location = 1) uniform mat4 model; | |||
| @@ -16,5 +16,5 @@ out FragmentData { | |||
| void main() { | |||
| data.tex_coords = position.xy + vec2(0.5); | |||
| gl_Position = camera.proj_world * camera.view * model * vec4(position, 1.0); | |||
| gl_Position = camera.projection * camera.view * model * vec4(position, 1.0); | |||
| } | |||
| @@ -7,9 +7,9 @@ layout (location = 3) in vec2 tex_max; | |||
| layout (location = 4) in vec4 color; | |||
| layout (std140, binding = 0) uniform Camera { | |||
| mat4 proj_world; | |||
| mat4 proj_ui; | |||
| mat4 projection; | |||
| mat4 view; | |||
| vec2 size; | |||
| } camera; | |||
| layout (location = 1) uniform mat4 model; | |||
| @@ -45,7 +45,14 @@ void main() { | |||
| break; | |||
| } | |||
| gl_Position = camera.proj_ui * vec4(position, 0.0, 1.0); | |||
| mat4 ortho = mat4( | |||
| vec4(2.0 / camera.size.x, 0.0, 0.0, 0.0), | |||
| vec4(0.0, -2.0 / camera.size.y, 0.0, 0.0), | |||
| vec4(0.0, 0.0, 1.0, 0.0), | |||
| vec4(-1.0, 1.0, 1.0, 1.0) | |||
| ); | |||
| gl_Position = ortho * vec4(position, 0.0, 1.0); | |||
| data.tex_coord = tex_coord; | |||
| data.color = color; | |||
| @@ -1,20 +1,30 @@ | |||
| use std::collections::HashSet; | |||
| use glutin::{ | |||
| event::{Event, WindowEvent as GlutinWindowEvent}, | |||
| event::{ | |||
| ElementState, Event, KeyboardInput, MouseScrollDelta, WindowEvent as GlutinWindowEvent, | |||
| }, | |||
| event_loop::{ControlFlow, EventLoop}, | |||
| platform::desktop::EventLoopExtDesktop, | |||
| }; | |||
| use shrev::EventChannel; | |||
| use specs::World; | |||
| pub use glutin::event::{MouseButton, VirtualKeyCode}; | |||
| pub struct Events { | |||
| keys: HashSet<VirtualKeyCode>, | |||
| event_loop: EventLoop<()>, | |||
| } | |||
| impl Events { | |||
| pub fn new(world: &mut World) -> Self { | |||
| world.insert(EventChannel::<MouseEvent>::default()); | |||
| world.insert(EventChannel::<WindowEvent>::default()); | |||
| world.insert(EventChannel::<KeyboardEvent>::default()); | |||
| Self { | |||
| keys: HashSet::new(), | |||
| event_loop: EventLoop::new(), | |||
| } | |||
| } | |||
| @@ -26,9 +36,14 @@ impl Events { | |||
| } | |||
| pub fn process(&mut self, world: &World) { | |||
| let mut channel = world.fetch_mut::<EventChannel<WindowEvent>>(); | |||
| let mut mouse_events = world.fetch_mut::<EventChannel<MouseEvent>>(); | |||
| let mut window_events = world.fetch_mut::<EventChannel<WindowEvent>>(); | |||
| let mut keyboard_events = world.fetch_mut::<EventChannel<KeyboardEvent>>(); | |||
| let keys = &mut self.keys; | |||
| let event_loop = &mut self.event_loop; | |||
| self.event_loop.run_return(|event, _target, flow_control| { | |||
| event_loop.run_return(|event, _target, flow_control| { | |||
| *flow_control = ControlFlow::Poll; | |||
| match event { | |||
| @@ -36,12 +51,77 @@ impl Events { | |||
| *flow_control = ControlFlow::Exit; | |||
| } | |||
| Event::WindowEvent { event, .. } => match event { | |||
| /* Mouse Events */ | |||
| GlutinWindowEvent::CursorMoved { position, .. } => { | |||
| mouse_events | |||
| .single_write(MouseEvent::Move(position.x as _, position.y as _)); | |||
| } | |||
| GlutinWindowEvent::MouseInput { | |||
| state: ElementState::Pressed, | |||
| button, | |||
| .. | |||
| } => { | |||
| mouse_events.single_write(MouseEvent::ButtonDown(button)); | |||
| } | |||
| GlutinWindowEvent::MouseInput { | |||
| state: ElementState::Released, | |||
| button, | |||
| .. | |||
| } => { | |||
| mouse_events.single_write(MouseEvent::ButtonUp(button)); | |||
| } | |||
| GlutinWindowEvent::MouseWheel { | |||
| delta: MouseScrollDelta::LineDelta(x, y), | |||
| .. | |||
| } => { | |||
| if x != 0.0 { | |||
| mouse_events.single_write(MouseEvent::ScrollX(x)); | |||
| } | |||
| if y != 0.0 { | |||
| mouse_events.single_write(MouseEvent::ScrollY(y)); | |||
| } | |||
| } | |||
| /* Key Event */ | |||
| GlutinWindowEvent::KeyboardInput { | |||
| input: | |||
| KeyboardInput { | |||
| state: ElementState::Pressed, | |||
| virtual_keycode: Some(key), | |||
| .. | |||
| }, | |||
| .. | |||
| } => { | |||
| if keys.insert(key) { | |||
| keyboard_events.single_write(KeyboardEvent::KeyDown(key)); | |||
| } | |||
| keyboard_events.single_write(KeyboardEvent::KeyPress(key)); | |||
| } | |||
| GlutinWindowEvent::KeyboardInput { | |||
| input: | |||
| KeyboardInput { | |||
| state: ElementState::Released, | |||
| virtual_keycode: Some(key), | |||
| .. | |||
| }, | |||
| .. | |||
| } => { | |||
| if keys.remove(&key) { | |||
| keyboard_events.single_write(KeyboardEvent::KeyUp(key)); | |||
| } | |||
| } | |||
| /* Window Event */ | |||
| GlutinWindowEvent::Resized(pos) => { | |||
| channel.single_write(WindowEvent::Resize(pos.width, pos.height)); | |||
| window_events.single_write(WindowEvent::Resize(pos.width, pos.height)); | |||
| } | |||
| GlutinWindowEvent::CloseRequested => { | |||
| channel.single_write(WindowEvent::Close); | |||
| window_events.single_write(WindowEvent::Close); | |||
| } | |||
| /* Ignore */ | |||
| _ => (), | |||
| }, | |||
| _ => (), | |||
| @@ -54,3 +134,17 @@ pub enum WindowEvent { | |||
| Resize(u32, u32), | |||
| Close, | |||
| } | |||
| pub enum MouseEvent { | |||
| Move(f32, f32), | |||
| ButtonDown(MouseButton), | |||
| ButtonUp(MouseButton), | |||
| ScrollX(f32), | |||
| ScrollY(f32), | |||
| } | |||
| pub enum KeyboardEvent { | |||
| KeyUp(VirtualKeyCode), | |||
| KeyDown(VirtualKeyCode), | |||
| KeyPress(VirtualKeyCode), | |||
| } | |||
| @@ -3,7 +3,7 @@ mod text; | |||
| mod window; | |||
| mod world; | |||
| pub use events::{Events, WindowEvent}; | |||
| pub use events::{Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent}; | |||
| pub use text::{Text, TextCache, TextManager}; | |||
| pub use window::Window; | |||
| pub use world::WorldHelper; | |||
| @@ -56,6 +56,7 @@ impl Window { | |||
| gl::disable(gl::CULL_FACE); | |||
| gl::disable(gl::DEPTH_TEST); | |||
| gl::clear_color(0.1, 0.1, 0.1, 1.0); | |||
| gl::pixel_store_i(gl::UNPACK_ALIGNMENT, 1); | |||
| Ok(Self { context }) | |||
| @@ -1,20 +1,24 @@ | |||
| use glc::{ | |||
| matrix::Matrix4f, | |||
| misc::Bindable, | |||
| shader::{Program, Type}, | |||
| vector::Vector3f, | |||
| }; | |||
| use log::error; | |||
| use specs::{ReadExpect, System, World, WriteExpect}; | |||
| use shrev::{EventChannel, ReaderId}; | |||
| use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; | |||
| use crate::Error; | |||
| use super::super::{ | |||
| misc::WorldHelper, | |||
| misc::{MouseEvent, VirtualKeyCode, WorldHelper}, | |||
| resources::{Camera, Geometry, State}, | |||
| }; | |||
| pub struct Init { | |||
| program: Program, | |||
| resolution: (u32, u32), | |||
| mouse_event_id: ReaderId<MouseEvent>, | |||
| } | |||
| impl Init { | |||
| @@ -23,22 +27,37 @@ impl Init { | |||
| (Type::Vertex, "resources/shader/noise.vert"), | |||
| (Type::Fragment, "resources/shader/noise.frag"), | |||
| ])?; | |||
| let resolution = (0, 0); | |||
| let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | |||
| Ok(Self { | |||
| program, | |||
| resolution: (0, 0), | |||
| resolution, | |||
| mouse_event_id, | |||
| }) | |||
| } | |||
| } | |||
| #[derive(SystemData)] | |||
| pub struct InitData<'a> { | |||
| camera: WriteExpect<'a, Camera>, | |||
| state: ReadExpect<'a, State>, | |||
| geometry: ReadExpect<'a, Geometry>, | |||
| mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>, | |||
| } | |||
| impl<'a> System<'a> for Init { | |||
| type SystemData = ( | |||
| WriteExpect<'a, Camera>, | |||
| ReadExpect<'a, State>, | |||
| ReadExpect<'a, Geometry>, | |||
| ); | |||
| type SystemData = InitData<'a>; | |||
| fn run(&mut self, (mut camera, state, geometry): Self::SystemData) { | |||
| fn run(&mut self, data: Self::SystemData) { | |||
| let InitData { | |||
| mut camera, | |||
| state, | |||
| geometry, | |||
| mouse_events, | |||
| } = data; | |||
| /* screen size */ | |||
| if self.resolution != state.resolution { | |||
| self.resolution = state.resolution; | |||
| @@ -46,12 +65,61 @@ impl<'a> System<'a> for Init { | |||
| if let Err(err) = camera.resize(self.resolution.0 as _, self.resolution.1 as _) { | |||
| error!("Error while updating camera: {}", err); | |||
| panic!("Error while updating camera: {}", err); | |||
| } | |||
| } | |||
| /* zoom */ | |||
| let events = mouse_events.read(&mut self.mouse_event_id); | |||
| for event in events { | |||
| if let MouseEvent::ScrollY(delta) = event { | |||
| let z = CAMERA_ZOOM_SPEED / (CAMERA_ZOOM_SPEED - delta); | |||
| let m = Matrix4f::translate((state.mouse_pos.0, state.mouse_pos.1, 0.0).into()) | |||
| * Matrix4f::scale(z.into()) | |||
| * Matrix4f::translate((-state.mouse_pos.0, -state.mouse_pos.1, 0.0).into()); | |||
| if let Err(err) = camera.update_with(move |v| m * v) { | |||
| error!("Error while zooming camera: {}", err); | |||
| } | |||
| } | |||
| } | |||
| /* move camera */ | |||
| let up = state.key_state(KEY_CAMERA_UP) || state.key_state(KEY_CAMERA_UP_ALT); | |||
| let down = state.key_state(KEY_CAMERA_DOWN) || state.key_state(KEY_CAMERA_DOWN_ALT); | |||
| let left = state.key_state(KEY_CAMERA_LEFT) || state.key_state(KEY_CAMERA_LEFT_ALT); | |||
| let right = state.key_state(KEY_CAMERA_RIGHT) || state.key_state(KEY_CAMERA_RIGHT_ALT); | |||
| let translate = Vector3f::new( | |||
| if left { CAMERA_MOVE_SPEED_KEY } else { 0.0 } | |||
| + if right { -CAMERA_MOVE_SPEED_KEY } else { 0.0 }, | |||
| if up { -CAMERA_MOVE_SPEED_KEY } else { 0.0 } | |||
| + if down { CAMERA_MOVE_SPEED_KEY } else { 0.0 }, | |||
| 0.0, | |||
| ); | |||
| if up || down || left || right { | |||
| let m = Matrix4f::translate(translate); | |||
| if let Err(err) = camera.update_with(move |v| m * v) { | |||
| error!("Error while moving camera: {}", err); | |||
| } | |||
| } | |||
| /* render background */ | |||
| self.program.bind(); | |||
| geometry.render_quad(); | |||
| self.program.unbind(); | |||
| } | |||
| } | |||
| const CAMERA_MOVE_SPEED_KEY: f32 = 2.0; | |||
| const CAMERA_ZOOM_SPEED: f32 = 100.0; | |||
| const KEY_CAMERA_UP: VirtualKeyCode = VirtualKeyCode::Up; | |||
| const KEY_CAMERA_DOWN: VirtualKeyCode = VirtualKeyCode::Down; | |||
| const KEY_CAMERA_LEFT: VirtualKeyCode = VirtualKeyCode::Left; | |||
| const KEY_CAMERA_RIGHT: VirtualKeyCode = VirtualKeyCode::Right; | |||
| const KEY_CAMERA_UP_ALT: VirtualKeyCode = VirtualKeyCode::W; | |||
| const KEY_CAMERA_DOWN_ALT: VirtualKeyCode = VirtualKeyCode::S; | |||
| const KEY_CAMERA_LEFT_ALT: VirtualKeyCode = VirtualKeyCode::A; | |||
| const KEY_CAMERA_RIGHT_ALT: VirtualKeyCode = VirtualKeyCode::D; | |||
| @@ -4,6 +4,7 @@ use glc::{ | |||
| array_buffer::{ArrayBuffer, Target, Usage}, | |||
| error::Error, | |||
| matrix::Matrix4f, | |||
| vector::Vector2f, | |||
| }; | |||
| pub struct Camera { | |||
| @@ -16,9 +17,9 @@ impl Camera { | |||
| buffer.buffer_data( | |||
| Usage::StaticDraw, | |||
| &[Data { | |||
| proj_world: Matrix4f::identity(), | |||
| proj_ui: Matrix4f::identity(), | |||
| projection: Matrix4f::identity(), | |||
| view: Matrix4f::identity(), | |||
| size: Vector2f::default(), | |||
| }], | |||
| )?; | |||
| @@ -28,8 +29,27 @@ impl Camera { | |||
| pub fn resize(&mut self, w: f32, h: f32) -> Result<(), Error> { | |||
| let mut data = self.buffer.map_mut::<Data>(true)?; | |||
| data[0].proj_world = Matrix4f::ortho(-w / 2.0, w / 2.0, -h / 2.0, h / 2.0, -100.0, 100.0); | |||
| data[0].proj_ui = Matrix4f::ortho(0.0, w, h, 0.0, -100.0, 100.0); | |||
| data[0].projection = Matrix4f::ortho(-w / 2.0, w / 2.0, -h / 2.0, h / 2.0, -100.0, 100.0); | |||
| data[0].size = (w, h).into(); | |||
| Ok(()) | |||
| } | |||
| pub fn update(&mut self, view: Matrix4f) -> Result<(), Error> { | |||
| let mut data = self.buffer.map_mut::<Data>(true)?; | |||
| data[0].view = data[0].view * view; | |||
| Ok(()) | |||
| } | |||
| pub fn update_with<F>(&mut self, f: F) -> Result<(), Error> | |||
| where | |||
| F: FnOnce(&Matrix4f) -> Matrix4f, | |||
| { | |||
| let mut data = self.buffer.map_mut::<Data>(true)?; | |||
| data[0].view = f(&data[0].view); | |||
| Ok(()) | |||
| } | |||
| @@ -41,7 +61,7 @@ impl Camera { | |||
| #[repr(C, packed)] | |||
| struct Data { | |||
| proj_world: Matrix4f, | |||
| proj_ui: Matrix4f, | |||
| projection: Matrix4f, | |||
| view: Matrix4f, | |||
| size: Vector2f, | |||
| } | |||
| @@ -1,6 +1,45 @@ | |||
| #![allow(dead_code)] | |||
| use std::collections::HashSet; | |||
| use super::super::misc::{MouseButton, VirtualKeyCode}; | |||
| #[derive(Default)] | |||
| pub struct State { | |||
| pub mouse_pos: (f32, f32), | |||
| pub resolution: (u32, u32), | |||
| pub close_requested: bool, | |||
| pub key_states: HashSet<KeyState>, | |||
| } | |||
| #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] | |||
| pub enum KeyState { | |||
| KeyCode(VirtualKeyCode), | |||
| MouseButton(MouseButton), | |||
| } | |||
| impl State { | |||
| pub fn key_state(&self, code: VirtualKeyCode) -> bool { | |||
| self.key_states.contains(&KeyState::KeyCode(code)) | |||
| } | |||
| pub fn button_state(&self, button: MouseButton) -> bool { | |||
| self.key_states.contains(&KeyState::MouseButton(button)) | |||
| } | |||
| pub fn set_key_state(&mut self, code: VirtualKeyCode, value: bool) { | |||
| if value { | |||
| self.key_states.insert(KeyState::KeyCode(code)); | |||
| } else { | |||
| self.key_states.remove(&KeyState::KeyCode(code)); | |||
| } | |||
| } | |||
| pub fn set_button_state(&mut self, button: MouseButton, value: bool) { | |||
| if value { | |||
| self.key_states.insert(KeyState::MouseButton(button)); | |||
| } else { | |||
| self.key_states.remove(&KeyState::MouseButton(button)); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,29 +1,67 @@ | |||
| use shrev::{EventChannel, ReaderId}; | |||
| use specs::{ReadExpect, System, World, Write}; | |||
| use specs::{prelude::*, ReadExpect, System, World, Write}; | |||
| use crate::Error; | |||
| use super::super::{ | |||
| misc::{WindowEvent, WorldHelper}, | |||
| misc::{KeyboardEvent, MouseEvent, WindowEvent, WorldHelper}, | |||
| resources::State, | |||
| }; | |||
| pub struct StateUpdate { | |||
| mouse_event_id: ReaderId<MouseEvent>, | |||
| window_events_id: ReaderId<WindowEvent>, | |||
| keyboard_events_id: ReaderId<KeyboardEvent>, | |||
| } | |||
| impl StateUpdate { | |||
| pub fn new(world: &mut World) -> Result<Self, Error> { | |||
| let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | |||
| let window_events_id = world.register_event_reader::<WindowEvent>()?; | |||
| let keyboard_events_id = world.register_event_reader::<KeyboardEvent>()?; | |||
| Ok(Self { window_events_id }) | |||
| Ok(Self { | |||
| mouse_event_id, | |||
| window_events_id, | |||
| keyboard_events_id, | |||
| }) | |||
| } | |||
| } | |||
| #[derive(SystemData)] | |||
| pub struct StateUpdateData<'a> { | |||
| state: Write<'a, State>, | |||
| mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>, | |||
| window_events: ReadExpect<'a, EventChannel<WindowEvent>>, | |||
| keyboard_events: ReadExpect<'a, EventChannel<KeyboardEvent>>, | |||
| } | |||
| impl<'a> System<'a> for StateUpdate { | |||
| type SystemData = (Write<'a, State>, ReadExpect<'a, EventChannel<WindowEvent>>); | |||
| type SystemData = StateUpdateData<'a>; | |||
| fn run(&mut self, data: Self::SystemData) { | |||
| let StateUpdateData { | |||
| mut state, | |||
| mouse_events, | |||
| window_events, | |||
| keyboard_events, | |||
| } = data; | |||
| let events = mouse_events.read(&mut self.mouse_event_id); | |||
| for event in events { | |||
| match event { | |||
| MouseEvent::Move(x, y) => { | |||
| let x = *x - state.resolution.0 as f32 / 2.0; | |||
| let y = state.resolution.1 as f32 / 2.0 - *y; | |||
| state.mouse_pos = (x, y); | |||
| } | |||
| MouseEvent::ButtonUp(button) => state.set_button_state(*button, false), | |||
| MouseEvent::ButtonDown(button) => state.set_button_state(*button, true), | |||
| _ => (), | |||
| } | |||
| } | |||
| fn run(&mut self, (mut state, window_events): Self::SystemData) { | |||
| let events = window_events.read(&mut self.window_events_id); | |||
| for event in events { | |||
| match event { | |||
| @@ -35,5 +73,14 @@ impl<'a> System<'a> for StateUpdate { | |||
| } | |||
| } | |||
| } | |||
| let events = keyboard_events.read(&mut self.keyboard_events_id); | |||
| for event in events { | |||
| match event { | |||
| KeyboardEvent::KeyUp(code) => state.set_key_state(*code, false), | |||
| KeyboardEvent::KeyDown(code) => state.set_key_state(*code, true), | |||
| _ => (), | |||
| } | |||
| } | |||
| } | |||
| } | |||