@@ -1,7 +1,10 @@ | |||
use std::io::Error as IoError; | |||
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 serde_json::Error as JsonError; | |||
use space_crush_common::{misc::VfsError, Error as CommonError}; | |||
@@ -24,6 +27,9 @@ pub enum Error { | |||
#[error("glutin Creation Error: {0}")] | |||
GlutinCreationError(GlutinCreationError), | |||
#[error("glutin External Error: {0}")] | |||
GlutinExternalError(GlutinExternalError), | |||
#[error("Invalid Font: {0}")] | |||
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 { | |||
fn from(err: InvalidFont) -> Self { | |||
Self::InvalidFont(err) | |||
@@ -26,7 +26,7 @@ pub struct App<'a, 'b> { | |||
impl<'a, 'b> App<'a, 'b> { | |||
pub fn new(world: &mut World) -> Result<Self, Error> { | |||
let config = Config::new(world)?; | |||
let events = Events::new(world); | |||
let events = Events::new(world)?; | |||
let window = Window::new(events.handle(), &config)?; | |||
let state = State::default(); | |||
@@ -67,7 +67,7 @@ impl<'a, 'b> App<'a, 'b> { | |||
} | |||
pub fn process(&mut self, world: &World) -> Result<(), Error> { | |||
self.events.process(world); | |||
self.events.process(world, &self.window); | |||
self.dispatcher.dispatch(world); | |||
self.window.swap_buffers()?; | |||
@@ -7,26 +7,38 @@ use glutin::{ | |||
event_loop::{ControlFlow, EventLoop}, | |||
platform::desktop::EventLoopExtDesktop, | |||
}; | |||
use shrev::EventChannel; | |||
use shrev::{EventChannel, ReaderId}; | |||
use space_crush_common::misc::{LogResult, WorldHelper}; | |||
use specs::World; | |||
use crate::{misc::Window, Error}; | |||
pub use glutin::event::{MouseButton, VirtualKeyCode}; | |||
pub struct Events { | |||
keys: HashSet<VirtualKeyCode>, | |||
event_loop: EventLoop<()>, | |||
mouse_pos: Option<(f64, f64)>, | |||
mouse_lock: Option<(f64, f64)>, | |||
control_event_id: ReaderId<ControlEvent>, | |||
} | |||
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::<WindowEvent>::default()); | |||
world.insert(EventChannel::<KeyboardEvent>::default()); | |||
Self { | |||
let control_event_id = world.register_event_reader::<ControlEvent>()?; | |||
Ok(Self { | |||
keys: HashSet::new(), | |||
event_loop: EventLoop::new(), | |||
} | |||
mouse_pos: None, | |||
mouse_lock: None, | |||
control_event_id, | |||
}) | |||
} | |||
} | |||
@@ -35,14 +47,36 @@ impl Events { | |||
&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 window_events = world.fetch_mut::<EventChannel<WindowEvent>>(); | |||
let mut keyboard_events = world.fetch_mut::<EventChannel<KeyboardEvent>>(); | |||
let keys = &mut self.keys; | |||
let mouse_pos = &mut self.mouse_pos; | |||
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| { | |||
*flow_control = ControlFlow::Poll; | |||
@@ -53,8 +87,20 @@ impl Events { | |||
Event::WindowEvent { event, .. } => match event { | |||
/* Mouse Events */ | |||
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 { | |||
state: ElementState::Pressed, | |||
@@ -82,6 +128,9 @@ impl Events { | |||
mouse_events.single_write(MouseEvent::ScrollY(y)); | |||
} | |||
} | |||
GlutinWindowEvent::CursorLeft { .. } => { | |||
*mouse_pos = None; | |||
} | |||
/* Key Event */ | |||
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 { | |||
Resize(u32, u32), | |||
Close, | |||
@@ -137,6 +198,7 @@ pub enum WindowEvent { | |||
pub enum MouseEvent { | |||
Move(f32, f32), | |||
Delta(f32, f32), | |||
ButtonDown(MouseButton), | |||
ButtonUp(MouseButton), | |||
ScrollX(f32), | |||
@@ -3,7 +3,9 @@ mod text; | |||
mod window; | |||
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 window::Window; | |||
pub use world::WorldHelper; |
@@ -99,6 +99,7 @@ impl Window { | |||
(monitor_size.width - window_size.width) / 2, | |||
(monitor_size.height - window_size.height) / 2, | |||
)); | |||
window.set_cursor_grab(true).unwrap(); | |||
let context = unsafe { context.make_current().unwrap() }; | |||
gl::load_with(|s| context.get_proc_address(s)); | |||
@@ -116,4 +117,25 @@ impl Window { | |||
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::{ | |||
constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||
misc::{MouseEvent, WorldHelper}, | |||
misc::{ControlEvent, MouseButton, MouseEvent, WorldHelper}, | |||
resources::{Camera, Config, Geometry, State, Uniform}, | |||
Error, | |||
}; | |||
@@ -52,6 +52,8 @@ impl Init { | |||
pub struct InitData<'a> { | |||
camera: WriteExpect<'a, Camera>, | |||
uniform: WriteExpect<'a, Uniform>, | |||
control_events: WriteExpect<'a, EventChannel<ControlEvent>>, | |||
state: ReadExpect<'a, State>, | |||
global: ReadExpect<'a, Global>, | |||
config: ReadExpect<'a, Config>, | |||
@@ -66,6 +68,7 @@ impl<'a> System<'a> for Init { | |||
let InitData { | |||
mut camera, | |||
mut uniform, | |||
mut control_events, | |||
state, | |||
global, | |||
config, | |||
@@ -87,27 +90,43 @@ impl<'a> System<'a> for Init { | |||
/* zoom */ | |||
let events = mouse_events.read(&mut self.mouse_event_id); | |||
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 */ | |||
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 { | |||
let s = config.input.speed_camera_move * global.delta; | |||
let s = config.input.camera_move_speed * global.delta; | |||
let translate = Vector3f::new( | |||
if left { s } else { 0.0 } + if right { -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 specs::World; | |||
use crate::{misc::VirtualKeyCode, Error}; | |||
use crate::{ | |||
misc::{MouseButton, VirtualKeyCode}, | |||
Error, | |||
}; | |||
#[derive(Debug, Default, Serialize, Deserialize)] | |||
pub struct Config { | |||
@@ -30,19 +33,22 @@ pub struct Video { | |||
#[derive(Debug, Serialize, Deserialize)] | |||
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]>; | |||
@@ -80,13 +86,15 @@ impl Default for Video { | |||
impl Default for Input { | |||
fn default() -> 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 | |||
} | |||
pub fn key_camera_move_up() -> VirtualKeyCodes { | |||
pub fn camera_move_key_up() -> VirtualKeyCodes { | |||
smallvec![VirtualKeyCode::W, VirtualKeyCode::Up] | |||
} | |||
pub fn key_camera_move_down() -> VirtualKeyCodes { | |||
pub fn camera_move_key_down() -> VirtualKeyCodes { | |||
smallvec![VirtualKeyCode::S, VirtualKeyCode::Down] | |||
} | |||
pub fn key_camera_move_left() -> VirtualKeyCodes { | |||
pub fn camera_move_key_left() -> VirtualKeyCodes { | |||
smallvec![VirtualKeyCode::A, VirtualKeyCode::Left] | |||
} | |||
pub fn key_camera_move_right() -> VirtualKeyCodes { | |||
pub fn camera_move_key_right() -> VirtualKeyCodes { | |||
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 | |||
} | |||
pub fn speed_camera_zoom() -> f32 { | |||
pub fn camera_zoom_speed() -> f32 { | |||
100.0 | |||
} | |||
} |