@@ -1,7 +1,10 @@ | |||||
use std::io::Error as IoError; | use std::io::Error as IoError; | ||||
use glc::error::Error as GlcError; | use glc::error::Error as GlcError; | ||||
use glutin::{ContextError as GlutinContextError, CreationError as GlutinCreationError}; | |||||
use glutin::{ | |||||
error::ExternalError as GlutinExternalError, ContextError as GlutinContextError, | |||||
CreationError as GlutinCreationError, | |||||
}; | |||||
use glyph_brush::ab_glyph::InvalidFont; | use glyph_brush::ab_glyph::InvalidFont; | ||||
use serde_json::Error as JsonError; | use serde_json::Error as JsonError; | ||||
use space_crush_common::{misc::VfsError, Error as CommonError}; | use space_crush_common::{misc::VfsError, Error as CommonError}; | ||||
@@ -24,6 +27,9 @@ pub enum Error { | |||||
#[error("glutin Creation Error: {0}")] | #[error("glutin Creation Error: {0}")] | ||||
GlutinCreationError(GlutinCreationError), | GlutinCreationError(GlutinCreationError), | ||||
#[error("glutin External Error: {0}")] | |||||
GlutinExternalError(GlutinExternalError), | |||||
#[error("Invalid Font: {0}")] | #[error("Invalid Font: {0}")] | ||||
InvalidFont(InvalidFont), | InvalidFont(InvalidFont), | ||||
@@ -73,6 +79,12 @@ impl From<GlutinCreationError> for Error { | |||||
} | } | ||||
} | } | ||||
impl From<GlutinExternalError> for Error { | |||||
fn from(err: GlutinExternalError) -> Self { | |||||
Self::GlutinExternalError(err) | |||||
} | |||||
} | |||||
impl From<InvalidFont> for Error { | impl From<InvalidFont> for Error { | ||||
fn from(err: InvalidFont) -> Self { | fn from(err: InvalidFont) -> Self { | ||||
Self::InvalidFont(err) | Self::InvalidFont(err) | ||||
@@ -26,7 +26,7 @@ pub struct App<'a, 'b> { | |||||
impl<'a, 'b> App<'a, 'b> { | impl<'a, 'b> App<'a, 'b> { | ||||
pub fn new(world: &mut World) -> Result<Self, Error> { | pub fn new(world: &mut World) -> Result<Self, Error> { | ||||
let config = Config::new(world)?; | let config = Config::new(world)?; | ||||
let events = Events::new(world); | |||||
let events = Events::new(world)?; | |||||
let window = Window::new(events.handle(), &config)?; | let window = Window::new(events.handle(), &config)?; | ||||
let state = State::default(); | let state = State::default(); | ||||
@@ -67,7 +67,7 @@ impl<'a, 'b> App<'a, 'b> { | |||||
} | } | ||||
pub fn process(&mut self, world: &World) -> Result<(), Error> { | pub fn process(&mut self, world: &World) -> Result<(), Error> { | ||||
self.events.process(world); | |||||
self.events.process(world, &self.window); | |||||
self.dispatcher.dispatch(world); | self.dispatcher.dispatch(world); | ||||
self.window.swap_buffers()?; | self.window.swap_buffers()?; | ||||
@@ -7,26 +7,38 @@ use glutin::{ | |||||
event_loop::{ControlFlow, EventLoop}, | event_loop::{ControlFlow, EventLoop}, | ||||
platform::desktop::EventLoopExtDesktop, | platform::desktop::EventLoopExtDesktop, | ||||
}; | }; | ||||
use shrev::EventChannel; | |||||
use shrev::{EventChannel, ReaderId}; | |||||
use space_crush_common::misc::{LogResult, WorldHelper}; | |||||
use specs::World; | use specs::World; | ||||
use crate::{misc::Window, Error}; | |||||
pub use glutin::event::{MouseButton, VirtualKeyCode}; | pub use glutin::event::{MouseButton, VirtualKeyCode}; | ||||
pub struct Events { | pub struct Events { | ||||
keys: HashSet<VirtualKeyCode>, | keys: HashSet<VirtualKeyCode>, | ||||
event_loop: EventLoop<()>, | event_loop: EventLoop<()>, | ||||
mouse_pos: Option<(f64, f64)>, | |||||
mouse_lock: Option<(f64, f64)>, | |||||
control_event_id: ReaderId<ControlEvent>, | |||||
} | } | ||||
impl Events { | impl Events { | ||||
pub fn new(world: &mut World) -> Self { | |||||
pub fn new(world: &mut World) -> Result<Self, Error> { | |||||
world.insert(EventChannel::<ControlEvent>::default()); | |||||
world.insert(EventChannel::<MouseEvent>::default()); | world.insert(EventChannel::<MouseEvent>::default()); | ||||
world.insert(EventChannel::<WindowEvent>::default()); | world.insert(EventChannel::<WindowEvent>::default()); | ||||
world.insert(EventChannel::<KeyboardEvent>::default()); | world.insert(EventChannel::<KeyboardEvent>::default()); | ||||
Self { | |||||
let control_event_id = world.register_event_reader::<ControlEvent>()?; | |||||
Ok(Self { | |||||
keys: HashSet::new(), | keys: HashSet::new(), | ||||
event_loop: EventLoop::new(), | event_loop: EventLoop::new(), | ||||
} | |||||
mouse_pos: None, | |||||
mouse_lock: None, | |||||
control_event_id, | |||||
}) | |||||
} | } | ||||
} | } | ||||
@@ -35,14 +47,36 @@ impl Events { | |||||
&self.event_loop | &self.event_loop | ||||
} | } | ||||
pub fn process(&mut self, world: &World) { | |||||
pub fn process(&mut self, world: &World, window: &Window) { | |||||
let control_events = world.fetch::<EventChannel<ControlEvent>>(); | |||||
let mut mouse_events = world.fetch_mut::<EventChannel<MouseEvent>>(); | let mut mouse_events = world.fetch_mut::<EventChannel<MouseEvent>>(); | ||||
let mut window_events = world.fetch_mut::<EventChannel<WindowEvent>>(); | let mut window_events = world.fetch_mut::<EventChannel<WindowEvent>>(); | ||||
let mut keyboard_events = world.fetch_mut::<EventChannel<KeyboardEvent>>(); | let mut keyboard_events = world.fetch_mut::<EventChannel<KeyboardEvent>>(); | ||||
let keys = &mut self.keys; | let keys = &mut self.keys; | ||||
let mouse_pos = &mut self.mouse_pos; | |||||
let event_loop = &mut self.event_loop; | let event_loop = &mut self.event_loop; | ||||
let mouse_lock = &mut self.mouse_lock; | |||||
let events = control_events.read(&mut self.control_event_id); | |||||
for event in events { | |||||
match event { | |||||
ControlEvent::LockMouse => { | |||||
*mouse_lock = *mouse_pos; | |||||
window | |||||
.set_mouse_locked(true) | |||||
.warn("Unable to lock mouse to window"); | |||||
} | |||||
ControlEvent::UnlockMouse => { | |||||
*mouse_lock = None; | |||||
window | |||||
.set_mouse_locked(false) | |||||
.warn("Unable to lock mouse to window"); | |||||
} | |||||
} | |||||
} | |||||
let mut has_mouse_moved = false; | |||||
event_loop.run_return(|event, _target, flow_control| { | event_loop.run_return(|event, _target, flow_control| { | ||||
*flow_control = ControlFlow::Poll; | *flow_control = ControlFlow::Poll; | ||||
@@ -53,8 +87,20 @@ impl Events { | |||||
Event::WindowEvent { event, .. } => match event { | Event::WindowEvent { event, .. } => match event { | ||||
/* Mouse Events */ | /* Mouse Events */ | ||||
GlutinWindowEvent::CursorMoved { position, .. } => { | GlutinWindowEvent::CursorMoved { position, .. } => { | ||||
mouse_events | |||||
.single_write(MouseEvent::Move(position.x as _, position.y as _)); | |||||
if mouse_lock.is_none() { | |||||
mouse_events | |||||
.single_write(MouseEvent::Move(position.x as _, position.y as _)); | |||||
} | |||||
if let Some((x, y)) = mouse_pos { | |||||
let dx = position.x - *x; | |||||
let dy = position.y - *y; | |||||
mouse_events.single_write(MouseEvent::Delta(dx as _, dy as _)); | |||||
} | |||||
has_mouse_moved = true; | |||||
*mouse_pos = Some((position.x as _, position.y as _)); | |||||
} | } | ||||
GlutinWindowEvent::MouseInput { | GlutinWindowEvent::MouseInput { | ||||
state: ElementState::Pressed, | state: ElementState::Pressed, | ||||
@@ -82,6 +128,9 @@ impl Events { | |||||
mouse_events.single_write(MouseEvent::ScrollY(y)); | mouse_events.single_write(MouseEvent::ScrollY(y)); | ||||
} | } | ||||
} | } | ||||
GlutinWindowEvent::CursorLeft { .. } => { | |||||
*mouse_pos = None; | |||||
} | |||||
/* Key Event */ | /* Key Event */ | ||||
GlutinWindowEvent::KeyboardInput { | GlutinWindowEvent::KeyboardInput { | ||||
@@ -127,9 +176,21 @@ impl Events { | |||||
_ => (), | _ => (), | ||||
} | } | ||||
}); | }); | ||||
if let Some((x, y)) = self.mouse_lock { | |||||
if has_mouse_moved { | |||||
window.set_mouse_pos(x, y).warn("Unable to set mouse pos"); | |||||
self.mouse_pos = Some((x, y)); | |||||
} | |||||
} | |||||
} | } | ||||
} | } | ||||
pub enum ControlEvent { | |||||
LockMouse, | |||||
UnlockMouse, | |||||
} | |||||
pub enum WindowEvent { | pub enum WindowEvent { | ||||
Resize(u32, u32), | Resize(u32, u32), | ||||
Close, | Close, | ||||
@@ -137,6 +198,7 @@ pub enum WindowEvent { | |||||
pub enum MouseEvent { | pub enum MouseEvent { | ||||
Move(f32, f32), | Move(f32, f32), | ||||
Delta(f32, f32), | |||||
ButtonDown(MouseButton), | ButtonDown(MouseButton), | ||||
ButtonUp(MouseButton), | ButtonUp(MouseButton), | ||||
ScrollX(f32), | ScrollX(f32), | ||||
@@ -3,7 +3,9 @@ mod text; | |||||
mod window; | mod window; | ||||
mod world; | mod world; | ||||
pub use events::{Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent}; | |||||
pub use events::{ | |||||
ControlEvent, 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; |
@@ -99,6 +99,7 @@ impl Window { | |||||
(monitor_size.width - window_size.width) / 2, | (monitor_size.width - window_size.width) / 2, | ||||
(monitor_size.height - window_size.height) / 2, | (monitor_size.height - window_size.height) / 2, | ||||
)); | )); | ||||
window.set_cursor_grab(true).unwrap(); | |||||
let context = unsafe { context.make_current().unwrap() }; | let context = unsafe { context.make_current().unwrap() }; | ||||
gl::load_with(|s| context.get_proc_address(s)); | gl::load_with(|s| context.get_proc_address(s)); | ||||
@@ -116,4 +117,25 @@ impl Window { | |||||
Ok(()) | Ok(()) | ||||
} | } | ||||
pub fn set_mouse_locked(&self, value: bool) -> Result<(), Error> { | |||||
let window = self.context.window(); | |||||
window.set_cursor_grab(value)?; | |||||
if !value { | |||||
window.set_cursor_visible(true); | |||||
} | |||||
Ok(()) | |||||
} | |||||
pub fn set_mouse_pos(&self, x: f64, y: f64) -> Result<(), Error> { | |||||
let window = self.context.window(); | |||||
window.set_cursor_visible(false); | |||||
window.set_cursor_position(PhysicalPosition { x, y })?; | |||||
Ok(()) | |||||
} | |||||
} | } |
@@ -13,7 +13,7 @@ use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; | |||||
use crate::{ | use crate::{ | ||||
constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | ||||
misc::{MouseEvent, WorldHelper}, | |||||
misc::{ControlEvent, MouseButton, MouseEvent, WorldHelper}, | |||||
resources::{Camera, Config, Geometry, State, Uniform}, | resources::{Camera, Config, Geometry, State, Uniform}, | ||||
Error, | Error, | ||||
}; | }; | ||||
@@ -52,6 +52,8 @@ impl Init { | |||||
pub struct InitData<'a> { | pub struct InitData<'a> { | ||||
camera: WriteExpect<'a, Camera>, | camera: WriteExpect<'a, Camera>, | ||||
uniform: WriteExpect<'a, Uniform>, | uniform: WriteExpect<'a, Uniform>, | ||||
control_events: WriteExpect<'a, EventChannel<ControlEvent>>, | |||||
state: ReadExpect<'a, State>, | state: ReadExpect<'a, State>, | ||||
global: ReadExpect<'a, Global>, | global: ReadExpect<'a, Global>, | ||||
config: ReadExpect<'a, Config>, | config: ReadExpect<'a, Config>, | ||||
@@ -66,6 +68,7 @@ impl<'a> System<'a> for Init { | |||||
let InitData { | let InitData { | ||||
mut camera, | mut camera, | ||||
mut uniform, | mut uniform, | ||||
mut control_events, | |||||
state, | state, | ||||
global, | global, | ||||
config, | config, | ||||
@@ -87,27 +90,43 @@ impl<'a> System<'a> for Init { | |||||
/* zoom */ | /* zoom */ | ||||
let events = mouse_events.read(&mut self.mouse_event_id); | let events = mouse_events.read(&mut self.mouse_event_id); | ||||
for event in events { | for event in events { | ||||
if let MouseEvent::ScrollY(delta) = event { | |||||
let s = config.input.speed_camera_zoom; | |||||
let z = s / (s - 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()); | |||||
camera | |||||
.update_with(move |v| m * v) | |||||
.error("Error while zooming camera"); | |||||
match event { | |||||
MouseEvent::ScrollY(delta) => { | |||||
let s = config.input.camera_zoom_speed; | |||||
let z = s / (s - 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()); | |||||
camera | |||||
.update_with(move |v| m * v) | |||||
.error("Error while zooming camera"); | |||||
} | |||||
MouseEvent::Delta(x, y) if state.button_state(&[MouseButton::Right]) => { | |||||
let m = Matrix4f::translate((*x, -*y, 0.0).into()); | |||||
camera | |||||
.update_with(move |v| m * v) | |||||
.error("Error while zooming camera"); | |||||
} | |||||
MouseEvent::ButtonDown(b) if b == &config.input.camera_move_button => { | |||||
control_events.single_write(ControlEvent::LockMouse); | |||||
} | |||||
MouseEvent::ButtonUp(b) if b == &config.input.camera_move_button => { | |||||
control_events.single_write(ControlEvent::UnlockMouse); | |||||
} | |||||
_ => (), | |||||
} | } | ||||
} | } | ||||
/* move camera */ | /* move camera */ | ||||
let up = state.key_state(&config.input.key_camera_move_up); | |||||
let down = state.key_state(&config.input.key_camera_move_down); | |||||
let left = state.key_state(&config.input.key_camera_move_left); | |||||
let right = state.key_state(&config.input.key_camera_move_right); | |||||
let up = state.key_state(&config.input.camera_move_key_up); | |||||
let down = state.key_state(&config.input.camera_move_key_down); | |||||
let left = state.key_state(&config.input.camera_move_key_left); | |||||
let right = state.key_state(&config.input.camera_move_key_right); | |||||
if up || down || left || right { | if up || down || left || right { | ||||
let s = config.input.speed_camera_move * global.delta; | |||||
let s = config.input.camera_move_speed * global.delta; | |||||
let translate = Vector3f::new( | let translate = Vector3f::new( | ||||
if left { s } else { 0.0 } + if right { -s } else { 0.0 }, | if left { s } else { 0.0 } + if right { -s } else { 0.0 }, | ||||
if up { -s } else { 0.0 } + if down { s } else { 0.0 }, | if up { -s } else { 0.0 } + if down { s } else { 0.0 }, | ||||
@@ -5,7 +5,10 @@ use smallvec::{smallvec, SmallVec}; | |||||
use space_crush_common::misc::{Vfs, WorldHelper as _}; | use space_crush_common::misc::{Vfs, WorldHelper as _}; | ||||
use specs::World; | use specs::World; | ||||
use crate::{misc::VirtualKeyCode, Error}; | |||||
use crate::{ | |||||
misc::{MouseButton, VirtualKeyCode}, | |||||
Error, | |||||
}; | |||||
#[derive(Debug, Default, Serialize, Deserialize)] | #[derive(Debug, Default, Serialize, Deserialize)] | ||||
pub struct Config { | pub struct Config { | ||||
@@ -30,19 +33,22 @@ pub struct Video { | |||||
#[derive(Debug, Serialize, Deserialize)] | #[derive(Debug, Serialize, Deserialize)] | ||||
pub struct Input { | pub struct Input { | ||||
#[serde(default = "defaults::key_camera_move_up")] | |||||
pub key_camera_move_up: VirtualKeyCodes, | |||||
#[serde(default = "defaults::key_camera_move_down")] | |||||
pub key_camera_move_down: VirtualKeyCodes, | |||||
#[serde(default = "defaults::key_camera_move_left")] | |||||
pub key_camera_move_left: VirtualKeyCodes, | |||||
#[serde(default = "defaults::key_camera_move_right")] | |||||
pub key_camera_move_right: VirtualKeyCodes, | |||||
#[serde(default = "defaults::speed_camera_move")] | |||||
pub speed_camera_move: f32, | |||||
#[serde(default = "defaults::speed_camera_zoom")] | |||||
pub speed_camera_zoom: f32, | |||||
#[serde(default = "defaults::camera_move_key_up")] | |||||
pub camera_move_key_up: VirtualKeyCodes, | |||||
#[serde(default = "defaults::camera_move_key_down")] | |||||
pub camera_move_key_down: VirtualKeyCodes, | |||||
#[serde(default = "defaults::camera_move_key_left")] | |||||
pub camera_move_key_left: VirtualKeyCodes, | |||||
#[serde(default = "defaults::camera_move_key_right")] | |||||
pub camera_move_key_right: VirtualKeyCodes, | |||||
#[serde(default = "defaults::camera_move_button")] | |||||
pub camera_move_button: MouseButton, | |||||
#[serde(default = "defaults::camera_move_speed")] | |||||
pub camera_move_speed: f32, | |||||
#[serde(default = "defaults::camera_zoom_speed")] | |||||
pub camera_zoom_speed: f32, | |||||
} | } | ||||
type VirtualKeyCodes = SmallVec<[VirtualKeyCode; 2]>; | type VirtualKeyCodes = SmallVec<[VirtualKeyCode; 2]>; | ||||
@@ -80,13 +86,15 @@ impl Default for Video { | |||||
impl Default for Input { | impl Default for Input { | ||||
fn default() -> Self { | fn default() -> Self { | ||||
Self { | Self { | ||||
key_camera_move_up: defaults::key_camera_move_up(), | |||||
key_camera_move_down: defaults::key_camera_move_down(), | |||||
key_camera_move_left: defaults::key_camera_move_left(), | |||||
key_camera_move_right: defaults::key_camera_move_right(), | |||||
camera_move_key_up: defaults::camera_move_key_up(), | |||||
camera_move_key_down: defaults::camera_move_key_down(), | |||||
camera_move_key_left: defaults::camera_move_key_left(), | |||||
camera_move_key_right: defaults::camera_move_key_right(), | |||||
speed_camera_move: defaults::speed_camera_move(), | |||||
speed_camera_zoom: defaults::speed_camera_zoom(), | |||||
camera_move_button: defaults::camera_move_button(), | |||||
camera_move_speed: defaults::camera_move_speed(), | |||||
camera_zoom_speed: defaults::camera_zoom_speed(), | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -110,27 +118,31 @@ mod defaults { | |||||
true | true | ||||
} | } | ||||
pub fn key_camera_move_up() -> VirtualKeyCodes { | |||||
pub fn camera_move_key_up() -> VirtualKeyCodes { | |||||
smallvec![VirtualKeyCode::W, VirtualKeyCode::Up] | smallvec![VirtualKeyCode::W, VirtualKeyCode::Up] | ||||
} | } | ||||
pub fn key_camera_move_down() -> VirtualKeyCodes { | |||||
pub fn camera_move_key_down() -> VirtualKeyCodes { | |||||
smallvec![VirtualKeyCode::S, VirtualKeyCode::Down] | smallvec![VirtualKeyCode::S, VirtualKeyCode::Down] | ||||
} | } | ||||
pub fn key_camera_move_left() -> VirtualKeyCodes { | |||||
pub fn camera_move_key_left() -> VirtualKeyCodes { | |||||
smallvec![VirtualKeyCode::A, VirtualKeyCode::Left] | smallvec![VirtualKeyCode::A, VirtualKeyCode::Left] | ||||
} | } | ||||
pub fn key_camera_move_right() -> VirtualKeyCodes { | |||||
pub fn camera_move_key_right() -> VirtualKeyCodes { | |||||
smallvec![VirtualKeyCode::D, VirtualKeyCode::Right] | smallvec![VirtualKeyCode::D, VirtualKeyCode::Right] | ||||
} | } | ||||
pub fn speed_camera_move() -> f32 { | |||||
pub fn camera_move_button() -> MouseButton { | |||||
MouseButton::Right | |||||
} | |||||
pub fn camera_move_speed() -> f32 { | |||||
500.0 | 500.0 | ||||
} | } | ||||
pub fn speed_camera_zoom() -> f32 { | |||||
pub fn camera_zoom_speed() -> f32 { | |||||
100.0 | 100.0 | ||||
} | } | ||||
} | } |