| @@ -1,5 +1,6 @@ | |||||
| #![allow(dead_code)] | #![allow(dead_code)] | ||||
| use std::borrow::Borrow; | |||||
| use std::convert::{AsMut, AsRef}; | use std::convert::{AsMut, AsRef}; | ||||
| use std::fmt::{Debug, Formatter, Result as FmtResult}; | use std::fmt::{Debug, Formatter, Result as FmtResult}; | ||||
| use std::ops::{Deref, DerefMut, Mul}; | use std::ops::{Deref, DerefMut, Mul}; | ||||
| @@ -432,7 +433,7 @@ where | |||||
| Matrix4::new( | Matrix4::new( | ||||
| Vector4::new(two / (right - left), zero, zero, zero), | Vector4::new(two / (right - left), zero, zero, zero), | ||||
| Vector4::new(zero, two / (top - bottom), 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( | Vector4::new( | ||||
| -(right + left) / (right - left), | -(right + left) / (right - left), | ||||
| -(top + bottom) / (top - bottom), | -(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 | where | ||||
| T: Element, | T: Element, | ||||
| M: Borrow<Matrix4<T>>, | |||||
| { | { | ||||
| type Output = Self; | 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> { | impl<T> From<($($T,)+)> for $Name<T> { | ||||
| #[inline] | #[inline] | ||||
| fn from(($($f,)+): ($($T,)+)) -> Self { | fn from(($($f,)+): ($($T,)+)) -> Self { | ||||
| @@ -16,7 +16,7 @@ num_cpus = "1.13" | |||||
| ordered-float = "2.0" | ordered-float = "2.0" | ||||
| rand = "0.7" | rand = "0.7" | ||||
| serde_yaml = "0.8" | serde_yaml = "0.8" | ||||
| shred = "0.10" | |||||
| shred = { version = "0.10", features = [ "shred-derive" ] } | |||||
| shrev = "1.1" | shrev = "1.1" | ||||
| specs = "0.16" | specs = "0.16" | ||||
| thiserror = "1.0" | thiserror = "1.0" | ||||
| @@ -1,27 +1,17 @@ | |||||
| #version 450 core | #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; | out vec4 color; | ||||
| const float NOISE_RANGE = 0.05; | const float NOISE_RANGE = 0.05; | ||||
| const float NOISE_BASE = 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() { | 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 (location = 0) in vec3 position; | ||||
| layout (std140, binding = 0) uniform Camera { | layout (std140, binding = 0) uniform Camera { | ||||
| mat4 proj_world; | |||||
| mat4 proj_ui; | |||||
| mat4 projection; | |||||
| mat4 view; | mat4 view; | ||||
| vec2 size; | |||||
| } camera; | } camera; | ||||
| layout (location = 1) uniform mat4 model; | layout (location = 1) uniform mat4 model; | ||||
| @@ -16,5 +16,5 @@ out FragmentData { | |||||
| void main() { | void main() { | ||||
| data.tex_coords = position.xy + vec2(0.5); | 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 (location = 4) in vec4 color; | ||||
| layout (std140, binding = 0) uniform Camera { | layout (std140, binding = 0) uniform Camera { | ||||
| mat4 proj_world; | |||||
| mat4 proj_ui; | |||||
| mat4 projection; | |||||
| mat4 view; | mat4 view; | ||||
| vec2 size; | |||||
| } camera; | } camera; | ||||
| layout (location = 1) uniform mat4 model; | layout (location = 1) uniform mat4 model; | ||||
| @@ -45,7 +45,14 @@ void main() { | |||||
| break; | 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.tex_coord = tex_coord; | ||||
| data.color = color; | data.color = color; | ||||
| @@ -1,20 +1,30 @@ | |||||
| use std::collections::HashSet; | |||||
| use glutin::{ | use glutin::{ | ||||
| event::{Event, WindowEvent as GlutinWindowEvent}, | |||||
| event::{ | |||||
| ElementState, Event, KeyboardInput, MouseScrollDelta, WindowEvent as GlutinWindowEvent, | |||||
| }, | |||||
| event_loop::{ControlFlow, EventLoop}, | event_loop::{ControlFlow, EventLoop}, | ||||
| platform::desktop::EventLoopExtDesktop, | platform::desktop::EventLoopExtDesktop, | ||||
| }; | }; | ||||
| use shrev::EventChannel; | use shrev::EventChannel; | ||||
| use specs::World; | use specs::World; | ||||
| pub use glutin::event::{MouseButton, VirtualKeyCode}; | |||||
| pub struct Events { | pub struct Events { | ||||
| keys: HashSet<VirtualKeyCode>, | |||||
| event_loop: EventLoop<()>, | event_loop: EventLoop<()>, | ||||
| } | } | ||||
| impl Events { | impl Events { | ||||
| pub fn new(world: &mut World) -> Self { | pub fn new(world: &mut World) -> Self { | ||||
| world.insert(EventChannel::<MouseEvent>::default()); | |||||
| world.insert(EventChannel::<WindowEvent>::default()); | world.insert(EventChannel::<WindowEvent>::default()); | ||||
| world.insert(EventChannel::<KeyboardEvent>::default()); | |||||
| Self { | Self { | ||||
| keys: HashSet::new(), | |||||
| event_loop: EventLoop::new(), | event_loop: EventLoop::new(), | ||||
| } | } | ||||
| } | } | ||||
| @@ -26,9 +36,14 @@ impl Events { | |||||
| } | } | ||||
| pub fn process(&mut self, world: &World) { | 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; | *flow_control = ControlFlow::Poll; | ||||
| match event { | match event { | ||||
| @@ -36,12 +51,77 @@ impl Events { | |||||
| *flow_control = ControlFlow::Exit; | *flow_control = ControlFlow::Exit; | ||||
| } | } | ||||
| Event::WindowEvent { event, .. } => match event { | 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) => { | GlutinWindowEvent::Resized(pos) => { | ||||
| channel.single_write(WindowEvent::Resize(pos.width, pos.height)); | |||||
| window_events.single_write(WindowEvent::Resize(pos.width, pos.height)); | |||||
| } | } | ||||
| GlutinWindowEvent::CloseRequested => { | GlutinWindowEvent::CloseRequested => { | ||||
| channel.single_write(WindowEvent::Close); | |||||
| window_events.single_write(WindowEvent::Close); | |||||
| } | } | ||||
| /* Ignore */ | |||||
| _ => (), | _ => (), | ||||
| }, | }, | ||||
| _ => (), | _ => (), | ||||
| @@ -54,3 +134,17 @@ pub enum WindowEvent { | |||||
| Resize(u32, u32), | Resize(u32, u32), | ||||
| Close, | 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 window; | ||||
| mod world; | mod world; | ||||
| pub use events::{Events, WindowEvent}; | |||||
| pub use events::{Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent}; | |||||
| pub use text::{Text, TextCache, TextManager}; | pub use text::{Text, TextCache, TextManager}; | ||||
| pub use window::Window; | pub use window::Window; | ||||
| pub use world::WorldHelper; | pub use world::WorldHelper; | ||||
| @@ -56,6 +56,7 @@ impl Window { | |||||
| gl::disable(gl::CULL_FACE); | gl::disable(gl::CULL_FACE); | ||||
| gl::disable(gl::DEPTH_TEST); | gl::disable(gl::DEPTH_TEST); | ||||
| gl::clear_color(0.1, 0.1, 0.1, 1.0); | |||||
| gl::pixel_store_i(gl::UNPACK_ALIGNMENT, 1); | gl::pixel_store_i(gl::UNPACK_ALIGNMENT, 1); | ||||
| Ok(Self { context }) | Ok(Self { context }) | ||||
| @@ -1,20 +1,24 @@ | |||||
| use glc::{ | use glc::{ | ||||
| matrix::Matrix4f, | |||||
| misc::Bindable, | misc::Bindable, | ||||
| shader::{Program, Type}, | shader::{Program, Type}, | ||||
| vector::Vector3f, | |||||
| }; | }; | ||||
| use log::error; | use log::error; | ||||
| use specs::{ReadExpect, System, World, WriteExpect}; | |||||
| use shrev::{EventChannel, ReaderId}; | |||||
| use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; | |||||
| use crate::Error; | use crate::Error; | ||||
| use super::super::{ | use super::super::{ | ||||
| misc::WorldHelper, | |||||
| misc::{MouseEvent, VirtualKeyCode, WorldHelper}, | |||||
| resources::{Camera, Geometry, State}, | resources::{Camera, Geometry, State}, | ||||
| }; | }; | ||||
| pub struct Init { | pub struct Init { | ||||
| program: Program, | program: Program, | ||||
| resolution: (u32, u32), | resolution: (u32, u32), | ||||
| mouse_event_id: ReaderId<MouseEvent>, | |||||
| } | } | ||||
| impl Init { | impl Init { | ||||
| @@ -23,22 +27,37 @@ impl Init { | |||||
| (Type::Vertex, "resources/shader/noise.vert"), | (Type::Vertex, "resources/shader/noise.vert"), | ||||
| (Type::Fragment, "resources/shader/noise.frag"), | (Type::Fragment, "resources/shader/noise.frag"), | ||||
| ])?; | ])?; | ||||
| let resolution = (0, 0); | |||||
| let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | |||||
| Ok(Self { | Ok(Self { | ||||
| program, | 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 { | 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 { | if self.resolution != state.resolution { | ||||
| 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 _) { | if let Err(err) = camera.resize(self.resolution.0 as _, self.resolution.1 as _) { | ||||
| error!("Error while updating camera: {}", err); | 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(); | self.program.bind(); | ||||
| geometry.render_quad(); | geometry.render_quad(); | ||||
| self.program.unbind(); | 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}, | array_buffer::{ArrayBuffer, Target, Usage}, | ||||
| error::Error, | error::Error, | ||||
| matrix::Matrix4f, | matrix::Matrix4f, | ||||
| vector::Vector2f, | |||||
| }; | }; | ||||
| pub struct Camera { | pub struct Camera { | ||||
| @@ -16,9 +17,9 @@ impl Camera { | |||||
| buffer.buffer_data( | buffer.buffer_data( | ||||
| Usage::StaticDraw, | Usage::StaticDraw, | ||||
| &[Data { | &[Data { | ||||
| proj_world: Matrix4f::identity(), | |||||
| proj_ui: Matrix4f::identity(), | |||||
| projection: Matrix4f::identity(), | |||||
| view: 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> { | pub fn resize(&mut self, w: f32, h: f32) -> Result<(), Error> { | ||||
| let mut data = self.buffer.map_mut::<Data>(true)?; | 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(()) | Ok(()) | ||||
| } | } | ||||
| @@ -41,7 +61,7 @@ impl Camera { | |||||
| #[repr(C, packed)] | #[repr(C, packed)] | ||||
| struct Data { | struct Data { | ||||
| proj_world: Matrix4f, | |||||
| proj_ui: Matrix4f, | |||||
| projection: Matrix4f, | |||||
| view: Matrix4f, | view: Matrix4f, | ||||
| size: Vector2f, | |||||
| } | } | ||||
| @@ -1,6 +1,45 @@ | |||||
| #![allow(dead_code)] | |||||
| use std::collections::HashSet; | |||||
| use super::super::misc::{MouseButton, VirtualKeyCode}; | |||||
| #[derive(Default)] | #[derive(Default)] | ||||
| pub struct State { | pub struct State { | ||||
| pub mouse_pos: (f32, f32), | |||||
| pub resolution: (u32, u32), | pub resolution: (u32, u32), | ||||
| pub close_requested: bool, | 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 shrev::{EventChannel, ReaderId}; | ||||
| use specs::{ReadExpect, System, World, Write}; | |||||
| use specs::{prelude::*, ReadExpect, System, World, Write}; | |||||
| use crate::Error; | use crate::Error; | ||||
| use super::super::{ | use super::super::{ | ||||
| misc::{WindowEvent, WorldHelper}, | |||||
| misc::{KeyboardEvent, MouseEvent, WindowEvent, WorldHelper}, | |||||
| resources::State, | resources::State, | ||||
| }; | }; | ||||
| pub struct StateUpdate { | pub struct StateUpdate { | ||||
| mouse_event_id: ReaderId<MouseEvent>, | |||||
| window_events_id: ReaderId<WindowEvent>, | window_events_id: ReaderId<WindowEvent>, | ||||
| keyboard_events_id: ReaderId<KeyboardEvent>, | |||||
| } | } | ||||
| impl StateUpdate { | impl StateUpdate { | ||||
| pub fn new(world: &mut World) -> Result<Self, Error> { | 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 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 { | 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); | let events = window_events.read(&mut self.window_events_id); | ||||
| for event in events { | for event in events { | ||||
| match event { | 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), | |||||
| _ => (), | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||