2019-01-07 21:10:31 +00:00
|
|
|
use crate::{
|
2020-03-10 21:00:13 +00:00
|
|
|
controller::*,
|
2019-05-06 16:27:21 +00:00
|
|
|
render::{Renderer, WinColorFmt, WinDepthFmt},
|
2020-04-08 17:36:37 +00:00
|
|
|
settings::{ControlSettings, Settings},
|
2019-04-29 20:37:19 +00:00
|
|
|
ui, Error,
|
2019-01-07 21:10:31 +00:00
|
|
|
};
|
2020-03-10 21:00:13 +00:00
|
|
|
use gilrs::{EventType, Gilrs};
|
2019-08-11 19:52:23 +00:00
|
|
|
use hashbrown::HashMap;
|
2020-04-08 23:23:51 +00:00
|
|
|
|
2019-06-06 14:48:41 +00:00
|
|
|
use log::{error, warn};
|
2019-05-25 14:39:27 +00:00
|
|
|
use serde_derive::{Deserialize, Serialize};
|
2020-01-20 04:08:04 +00:00
|
|
|
use std::fmt;
|
2019-04-02 04:54:27 +00:00
|
|
|
use vek::*;
|
2019-01-02 21:25:01 +00:00
|
|
|
|
2020-03-10 21:00:13 +00:00
|
|
|
/// Represents a key that the game recognises after input mapping.
|
2020-04-08 17:36:37 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
|
2019-05-25 14:39:27 +00:00
|
|
|
pub enum GameInput {
|
2019-08-30 22:13:45 +00:00
|
|
|
Primary,
|
|
|
|
Secondary,
|
2020-04-11 06:33:06 +00:00
|
|
|
Slot1,
|
2020-04-09 01:15:54 +00:00
|
|
|
Slot2,
|
|
|
|
Slot3,
|
|
|
|
Slot4,
|
|
|
|
Slot5,
|
|
|
|
Slot6,
|
|
|
|
Slot7,
|
|
|
|
Slot8,
|
|
|
|
Slot9,
|
|
|
|
Slot10,
|
2019-05-25 14:39:27 +00:00
|
|
|
ToggleCursor,
|
|
|
|
MoveForward,
|
|
|
|
MoveBack,
|
|
|
|
MoveLeft,
|
|
|
|
MoveRight,
|
|
|
|
Jump,
|
2019-09-09 19:11:40 +00:00
|
|
|
Sit,
|
2019-05-25 14:39:27 +00:00
|
|
|
Glide,
|
2019-09-09 19:11:40 +00:00
|
|
|
Climb,
|
|
|
|
ClimbDown,
|
2020-04-08 23:23:51 +00:00
|
|
|
//WallLeap,
|
2020-05-04 15:15:31 +00:00
|
|
|
ToggleLantern,
|
2019-09-09 19:11:40 +00:00
|
|
|
Mount,
|
2019-05-25 14:39:27 +00:00
|
|
|
Enter,
|
2019-07-05 16:21:11 +00:00
|
|
|
Command,
|
2019-05-25 14:39:27 +00:00
|
|
|
Escape,
|
|
|
|
Map,
|
|
|
|
Bag,
|
|
|
|
Social,
|
|
|
|
Spellbook,
|
|
|
|
Settings,
|
|
|
|
ToggleInterface,
|
|
|
|
Help,
|
|
|
|
ToggleDebug,
|
|
|
|
Fullscreen,
|
|
|
|
Screenshot,
|
|
|
|
ToggleIngameUi,
|
2019-06-11 04:08:55 +00:00
|
|
|
Roll,
|
2019-05-25 14:39:27 +00:00
|
|
|
Respawn,
|
2019-07-29 16:19:08 +00:00
|
|
|
Interact,
|
2019-11-29 15:20:35 +00:00
|
|
|
ToggleWield,
|
2020-04-08 23:23:51 +00:00
|
|
|
//Charge,
|
2020-03-21 17:26:38 +00:00
|
|
|
SwapLoadout,
|
2020-03-26 21:22:21 +00:00
|
|
|
FreeLook,
|
2019-05-25 14:39:27 +00:00
|
|
|
}
|
|
|
|
|
2020-04-08 17:36:37 +00:00
|
|
|
impl GameInput {
|
|
|
|
pub fn get_localization_key(&self) -> &str {
|
|
|
|
match *self {
|
|
|
|
GameInput::Primary => "gameinput.primary",
|
|
|
|
GameInput::Secondary => "gameinput.secondary",
|
|
|
|
GameInput::ToggleCursor => "gameinput.togglecursor",
|
|
|
|
GameInput::MoveForward => "gameinput.moveforward",
|
|
|
|
GameInput::MoveLeft => "gameinput.moveleft",
|
|
|
|
GameInput::MoveRight => "gameinput.moveright",
|
|
|
|
GameInput::MoveBack => "gameinput.moveback",
|
|
|
|
GameInput::Jump => "gameinput.jump",
|
|
|
|
GameInput::Sit => "gameinput.sit",
|
|
|
|
GameInput::Glide => "gameinput.glide",
|
|
|
|
GameInput::Climb => "gameinput.climb",
|
|
|
|
GameInput::ClimbDown => "gameinput.climbdown",
|
2020-04-08 23:23:51 +00:00
|
|
|
//GameInput::WallLeap => "gameinput.wallleap",
|
2020-05-04 15:15:31 +00:00
|
|
|
GameInput::ToggleLantern => "gameinput.togglelantern",
|
2020-04-08 17:36:37 +00:00
|
|
|
GameInput::Mount => "gameinput.mount",
|
|
|
|
GameInput::Enter => "gameinput.enter",
|
|
|
|
GameInput::Command => "gameinput.command",
|
|
|
|
GameInput::Escape => "gameinput.escape",
|
|
|
|
GameInput::Map => "gameinput.map",
|
|
|
|
GameInput::Bag => "gameinput.bag",
|
|
|
|
GameInput::Social => "gameinput.social",
|
|
|
|
GameInput::Spellbook => "gameinput.spellbook",
|
|
|
|
GameInput::Settings => "gameinput.settings",
|
|
|
|
GameInput::ToggleInterface => "gameinput.toggleinterface",
|
|
|
|
GameInput::Help => "gameinput.help",
|
|
|
|
GameInput::ToggleDebug => "gameinput.toggledebug",
|
|
|
|
GameInput::Fullscreen => "gameinput.fullscreen",
|
|
|
|
GameInput::Screenshot => "gameinput.screenshot",
|
|
|
|
GameInput::ToggleIngameUi => "gameinput.toggleingameui",
|
|
|
|
GameInput::Roll => "gameinput.roll",
|
|
|
|
GameInput::Respawn => "gameinput.respawn",
|
|
|
|
GameInput::Interact => "gameinput.interact",
|
|
|
|
GameInput::ToggleWield => "gameinput.togglewield",
|
2020-04-08 23:23:51 +00:00
|
|
|
//GameInput::Charge => "gameinput.charge",
|
2020-04-08 17:36:37 +00:00
|
|
|
GameInput::FreeLook => "gameinput.freelook",
|
2020-04-11 06:33:06 +00:00
|
|
|
GameInput::Slot1 => "gameinput.slot1",
|
2020-04-09 01:15:54 +00:00
|
|
|
GameInput::Slot2 => "gameinput.slot2",
|
|
|
|
GameInput::Slot3 => "gameinput.slot3",
|
|
|
|
GameInput::Slot4 => "gameinput.slot4",
|
|
|
|
GameInput::Slot5 => "gameinput.slot5",
|
|
|
|
GameInput::Slot6 => "gameinput.slot6",
|
|
|
|
GameInput::Slot7 => "gameinput.slot7",
|
|
|
|
GameInput::Slot8 => "gameinput.slot8",
|
|
|
|
GameInput::Slot9 => "gameinput.slot9",
|
|
|
|
GameInput::Slot10 => "gameinput.slot10",
|
2020-04-08 17:36:37 +00:00
|
|
|
GameInput::SwapLoadout => "gameinput.swaploadout",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-10 21:00:13 +00:00
|
|
|
/// Represents a key that the game menus recognise after input mapping
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
|
|
|
pub enum MenuInput {
|
|
|
|
Up,
|
|
|
|
Down,
|
|
|
|
Left,
|
|
|
|
Right,
|
|
|
|
ScrollUp,
|
|
|
|
ScrollDown,
|
|
|
|
ScrollLeft,
|
|
|
|
ScrollRight,
|
|
|
|
Home,
|
|
|
|
End,
|
|
|
|
Apply,
|
|
|
|
Back,
|
|
|
|
Exit,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
|
|
|
pub enum AnalogMenuInput {
|
|
|
|
MoveX(f32),
|
|
|
|
MoveY(f32),
|
|
|
|
ScrollX(f32),
|
|
|
|
ScrollY(f32),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
|
|
|
pub enum AnalogGameInput {
|
|
|
|
MovementX(f32),
|
|
|
|
MovementY(f32),
|
|
|
|
CameraX(f32),
|
|
|
|
CameraY(f32),
|
|
|
|
}
|
|
|
|
|
2019-05-25 14:39:27 +00:00
|
|
|
/// Represents an incoming event from the window.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub enum Event {
|
|
|
|
/// The window has been requested to close.
|
|
|
|
Close,
|
|
|
|
/// The window has been resized.
|
|
|
|
Resize(Vec2<u32>),
|
|
|
|
/// A key has been typed that corresponds to a specific character.
|
|
|
|
Char(char),
|
|
|
|
/// The cursor has been panned across the screen while grabbed.
|
|
|
|
CursorPan(Vec2<f32>),
|
2019-09-18 16:46:12 +00:00
|
|
|
/// The cursor has been moved across the screen while ungrabbed.
|
|
|
|
CursorMove(Vec2<f32>),
|
|
|
|
/// A mouse button has been pressed or released
|
|
|
|
MouseButton(MouseButton, PressState),
|
2019-05-25 14:39:27 +00:00
|
|
|
/// The camera has been requested to zoom.
|
|
|
|
Zoom(f32),
|
|
|
|
/// A key that the game recognises has been pressed or released.
|
|
|
|
InputUpdate(GameInput, bool),
|
|
|
|
/// Event that the ui uses.
|
|
|
|
Ui(ui::Event),
|
2019-06-05 15:57:48 +00:00
|
|
|
/// The view distance has changed.
|
2019-05-25 14:39:27 +00:00
|
|
|
ViewDistanceChanged(u32),
|
|
|
|
/// Game settings have changed.
|
|
|
|
SettingsChanged,
|
2019-06-29 01:39:47 +00:00
|
|
|
/// The window is (un)focused
|
|
|
|
Focused(bool),
|
2020-03-10 21:00:13 +00:00
|
|
|
/// A key that the game recognises for menu navigation has been pressed or
|
|
|
|
/// released
|
|
|
|
MenuInput(MenuInput, bool),
|
|
|
|
/// Update of the analog inputs recognized by the menus
|
|
|
|
AnalogMenuInput(AnalogMenuInput),
|
|
|
|
/// Update of the analog inputs recognized by the game
|
|
|
|
AnalogGameInput(AnalogGameInput),
|
2019-05-25 14:39:27 +00:00
|
|
|
}
|
|
|
|
|
2019-09-18 16:46:12 +00:00
|
|
|
pub type MouseButton = winit::MouseButton;
|
|
|
|
pub type PressState = winit::ElementState;
|
|
|
|
|
2019-05-25 14:39:27 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
|
|
|
pub enum KeyMouse {
|
|
|
|
Key(glutin::VirtualKeyCode),
|
|
|
|
Mouse(glutin::MouseButton),
|
|
|
|
}
|
2019-05-25 12:53:44 +00:00
|
|
|
|
2020-01-20 04:08:04 +00:00
|
|
|
impl fmt::Display for KeyMouse {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
use self::KeyMouse::*;
|
|
|
|
use glutin::{MouseButton, VirtualKeyCode::*};
|
2020-02-01 20:39:39 +00:00
|
|
|
write!(f, "{}", match self {
|
|
|
|
Key(Key1) => "1",
|
|
|
|
Key(Key2) => "2",
|
|
|
|
Key(Key3) => "3",
|
|
|
|
Key(Key4) => "4",
|
|
|
|
Key(Key5) => "5",
|
|
|
|
Key(Key6) => "6",
|
|
|
|
Key(Key7) => "7",
|
|
|
|
Key(Key8) => "8",
|
|
|
|
Key(Key9) => "9",
|
|
|
|
Key(Key0) => "0",
|
|
|
|
Key(A) => "A",
|
|
|
|
Key(B) => "B",
|
|
|
|
Key(C) => "C",
|
|
|
|
Key(D) => "D",
|
|
|
|
Key(E) => "E",
|
|
|
|
Key(F) => "F",
|
|
|
|
Key(G) => "G",
|
|
|
|
Key(H) => "H",
|
|
|
|
Key(I) => "I",
|
|
|
|
Key(J) => "J",
|
|
|
|
Key(K) => "K",
|
|
|
|
Key(L) => "L",
|
|
|
|
Key(M) => "M",
|
|
|
|
Key(N) => "N",
|
|
|
|
Key(O) => "O",
|
|
|
|
Key(P) => "P",
|
|
|
|
Key(Q) => "Q",
|
|
|
|
Key(R) => "R",
|
|
|
|
Key(S) => "S",
|
|
|
|
Key(T) => "T",
|
|
|
|
Key(U) => "U",
|
|
|
|
Key(V) => "V",
|
|
|
|
Key(W) => "W",
|
|
|
|
Key(X) => "X",
|
|
|
|
Key(Y) => "Y",
|
|
|
|
Key(Z) => "Z",
|
|
|
|
Key(Escape) => "ESC",
|
|
|
|
Key(F1) => "F1",
|
|
|
|
Key(F2) => "F2",
|
|
|
|
Key(F3) => "F3",
|
|
|
|
Key(F4) => "F4",
|
|
|
|
Key(F5) => "F5",
|
|
|
|
Key(F6) => "F6",
|
|
|
|
Key(F7) => "F7",
|
|
|
|
Key(F8) => "F8",
|
|
|
|
Key(F9) => "F9",
|
|
|
|
Key(F10) => "F10",
|
|
|
|
Key(F11) => "F11",
|
|
|
|
Key(F12) => "F12",
|
|
|
|
Key(F13) => "F13",
|
|
|
|
Key(F14) => "F14",
|
|
|
|
Key(F15) => "F15",
|
|
|
|
Key(F16) => "F16",
|
|
|
|
Key(F17) => "F17",
|
|
|
|
Key(F18) => "F18",
|
|
|
|
Key(F19) => "F19",
|
|
|
|
Key(F20) => "F20",
|
|
|
|
Key(F21) => "F21",
|
|
|
|
Key(F22) => "F22",
|
|
|
|
Key(F23) => "F23",
|
|
|
|
Key(F24) => "F24",
|
|
|
|
Key(Snapshot) => "Print Screen",
|
|
|
|
Key(Scroll) => "Scroll Lock",
|
|
|
|
Key(Pause) => "Pause/Break",
|
|
|
|
Key(Insert) => "Insert",
|
|
|
|
Key(Home) => "Home",
|
|
|
|
Key(Delete) => "Delete",
|
|
|
|
Key(End) => "End",
|
|
|
|
Key(PageDown) => "PageDown",
|
|
|
|
Key(PageUp) => "PageUp",
|
|
|
|
Key(Left) => "Left Arrow",
|
|
|
|
Key(Up) => "Up Arrow",
|
|
|
|
Key(Right) => "Right Arrow",
|
|
|
|
Key(Down) => "Down Arrow",
|
|
|
|
Key(Back) => "Backspace",
|
|
|
|
Key(Return) => "Enter",
|
|
|
|
Key(Space) => "Space",
|
|
|
|
Key(Compose) => "Compose",
|
|
|
|
Key(Caret) => "^",
|
|
|
|
Key(Numlock) => "Numlock",
|
|
|
|
Key(Numpad0) => "Numpad 0",
|
|
|
|
Key(Numpad1) => "Numpad 1",
|
|
|
|
Key(Numpad2) => "Numpad 2",
|
|
|
|
Key(Numpad3) => "Numpad 3",
|
|
|
|
Key(Numpad4) => "Numpad 4",
|
|
|
|
Key(Numpad5) => "Numpad 5",
|
|
|
|
Key(Numpad6) => "Numpad 6",
|
|
|
|
Key(Numpad7) => "Numpad 7",
|
|
|
|
Key(Numpad8) => "Numpad 8",
|
|
|
|
Key(Numpad9) => "Numpad 9",
|
|
|
|
Key(AbntC1) => "Abnt C1",
|
|
|
|
Key(AbntC2) => "Abnt C2",
|
|
|
|
Key(Add) => "Numpad +",
|
|
|
|
Key(Apostrophe) => "'",
|
|
|
|
Key(Apps) => "Context Menu",
|
|
|
|
Key(At) => "@",
|
|
|
|
Key(Ax) => "Ax",
|
|
|
|
Key(Backslash) => "\\",
|
|
|
|
Key(Calculator) => "Calculator",
|
|
|
|
Key(Capital) => "Caps Lock",
|
|
|
|
Key(Colon) => ":",
|
|
|
|
Key(Comma) => ",",
|
|
|
|
Key(Convert) => "Convert",
|
|
|
|
Key(Decimal) => "Numpad .",
|
|
|
|
Key(Divide) => "Numpad /",
|
|
|
|
Key(Equals) => "=",
|
|
|
|
Key(Grave) => "`",
|
|
|
|
Key(Kana) => "Kana",
|
|
|
|
Key(Kanji) => "Kanji",
|
|
|
|
Key(LAlt) => "LAlt",
|
|
|
|
Key(LBracket) => "[",
|
|
|
|
Key(LControl) => "LControl",
|
|
|
|
Key(LShift) => "LShift",
|
|
|
|
Key(LWin) => "LWin",
|
|
|
|
Key(Mail) => "Mail",
|
|
|
|
Key(MediaSelect) => "MediaSelect",
|
|
|
|
Key(MediaStop) => "MediaStop",
|
|
|
|
Key(Minus) => "-",
|
|
|
|
Key(Multiply) => "Numpad *",
|
|
|
|
Key(Mute) => "Mute",
|
|
|
|
Key(MyComputer) => "My Computer",
|
|
|
|
Key(NavigateForward) => "Navigate Forward",
|
|
|
|
Key(NavigateBackward) => "Navigate Backward",
|
|
|
|
Key(NextTrack) => "Next Track",
|
|
|
|
Key(NoConvert) => "Non Convert",
|
2020-04-26 01:44:56 +00:00
|
|
|
Key(NumpadComma) => "Num ,",
|
|
|
|
Key(NumpadEnter) => "Num Enter",
|
|
|
|
Key(NumpadEquals) => "Num =",
|
|
|
|
Key(OEM102) => "<",
|
2020-02-01 20:39:39 +00:00
|
|
|
Key(Period) => ".",
|
|
|
|
Key(PlayPause) => "Play / Pause",
|
|
|
|
Key(Power) => "Power",
|
|
|
|
Key(PrevTrack) => "Prev Track",
|
|
|
|
Key(RAlt) => "RAlt",
|
|
|
|
Key(RBracket) => "]",
|
|
|
|
Key(RControl) => "RControl",
|
|
|
|
Key(RShift) => "RShift",
|
|
|
|
Key(RWin) => "RWin",
|
|
|
|
Key(Semicolon) => ";",
|
|
|
|
Key(Slash) => "/",
|
|
|
|
Key(Sleep) => "Sleep",
|
|
|
|
Key(Stop) => "Media Stop",
|
2020-04-26 01:44:56 +00:00
|
|
|
Key(Subtract) => "Num -",
|
2020-02-01 20:39:39 +00:00
|
|
|
Key(Sysrq) => "Sysrq",
|
|
|
|
Key(Tab) => "Tab",
|
|
|
|
Key(Underline) => "_",
|
|
|
|
Key(Unlabeled) => "No Name",
|
|
|
|
Key(VolumeDown) => "Volume Down",
|
|
|
|
Key(VolumeUp) => "Volume Up",
|
|
|
|
Key(Wake) => "Wake",
|
|
|
|
Key(WebBack) => "Browser Back",
|
|
|
|
Key(WebFavorites) => "Browser Favorites",
|
|
|
|
Key(WebForward) => "Browser Forward",
|
|
|
|
Key(WebHome) => "Browser Home",
|
|
|
|
Key(WebRefresh) => "Browser Refresh",
|
|
|
|
Key(WebSearch) => "Browser Search",
|
|
|
|
Key(WebStop) => "Browser Stop",
|
|
|
|
Key(Yen) => "Yen",
|
|
|
|
Key(Copy) => "Copy",
|
|
|
|
Key(Paste) => "Paste",
|
|
|
|
Key(Cut) => "Cut",
|
2020-04-09 01:15:54 +00:00
|
|
|
Mouse(MouseButton::Left) => "Mouse Left",
|
|
|
|
Mouse(MouseButton::Right) => "Mouse Right",
|
2020-04-26 01:44:56 +00:00
|
|
|
Mouse(MouseButton::Middle) => "Middle-Click",
|
2020-02-01 20:39:39 +00:00
|
|
|
Mouse(MouseButton::Other(button)) =>
|
|
|
|
return write!(f, "Unknown Mouse Button: {:?}", button),
|
|
|
|
})
|
2020-01-20 04:08:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-02 21:25:01 +00:00
|
|
|
pub struct Window {
|
2019-01-11 17:30:13 +00:00
|
|
|
events_loop: glutin::EventsLoop,
|
2019-01-07 21:10:31 +00:00
|
|
|
renderer: Renderer,
|
2019-07-28 15:47:14 +00:00
|
|
|
window: glutin::ContextWrapper<glutin::PossiblyCurrent, winit::Window>,
|
2019-01-23 22:21:47 +00:00
|
|
|
cursor_grabbed: bool,
|
2019-06-06 17:42:13 +00:00
|
|
|
pub pan_sensitivity: u32,
|
|
|
|
pub zoom_sensitivity: u32,
|
2019-10-02 12:44:41 +00:00
|
|
|
pub zoom_inversion: bool,
|
2019-12-06 22:49:17 +00:00
|
|
|
pub mouse_y_inversion: bool,
|
2019-05-18 21:16:35 +00:00
|
|
|
fullscreen: bool,
|
2019-03-28 04:42:04 +00:00
|
|
|
needs_refresh_resize: bool,
|
2019-06-30 04:20:50 +00:00
|
|
|
keypress_map: HashMap<GameInput, glutin::ElementState>,
|
2020-04-08 17:36:37 +00:00
|
|
|
pub remapping_keybindings: Option<GameInput>,
|
2019-04-25 15:32:59 +00:00
|
|
|
supplement_events: Vec<Event>,
|
2019-05-25 11:52:43 +00:00
|
|
|
focused: bool,
|
2020-03-10 21:00:13 +00:00
|
|
|
gilrs: Option<Gilrs>,
|
|
|
|
controller_settings: ControllerSettings,
|
|
|
|
cursor_position: winit::dpi::LogicalPosition,
|
|
|
|
mouse_emulation_vec: Vec2<f32>,
|
2019-01-02 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Window {
|
2019-04-15 17:51:26 +00:00
|
|
|
pub fn new(settings: &Settings) -> Result<Window, Error> {
|
2019-01-11 17:30:13 +00:00
|
|
|
let events_loop = glutin::EventsLoop::new();
|
2019-01-02 21:25:01 +00:00
|
|
|
|
2020-01-02 03:48:11 +00:00
|
|
|
let size = settings.graphics.window_size;
|
|
|
|
|
2019-01-11 17:30:13 +00:00
|
|
|
let win_builder = glutin::WindowBuilder::new()
|
2019-03-15 04:55:52 +00:00
|
|
|
.with_title("Veloren")
|
2020-01-02 03:48:11 +00:00
|
|
|
.with_dimensions(glutin::dpi::LogicalSize::new(
|
|
|
|
size[0] as f64,
|
|
|
|
size[1] as f64,
|
|
|
|
))
|
2019-03-15 04:55:52 +00:00
|
|
|
.with_maximized(true);
|
2019-01-11 17:30:13 +00:00
|
|
|
|
|
|
|
let ctx_builder = glutin::ContextBuilder::new()
|
|
|
|
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
|
2019-03-15 04:55:52 +00:00
|
|
|
.with_vsync(false);
|
2019-01-11 17:30:13 +00:00
|
|
|
|
2019-05-06 16:27:21 +00:00
|
|
|
let (window, device, factory, win_color_view, win_depth_view) =
|
|
|
|
gfx_window_glutin::init::<WinColorFmt, WinDepthFmt>(
|
2019-04-02 04:54:27 +00:00
|
|
|
win_builder,
|
|
|
|
ctx_builder,
|
|
|
|
&events_loop,
|
|
|
|
)
|
|
|
|
.map_err(|err| Error::BackendError(Box::new(err)))?;
|
2019-01-02 21:25:01 +00:00
|
|
|
|
2019-06-30 04:20:50 +00:00
|
|
|
let keypress_map = HashMap::new();
|
|
|
|
|
2020-03-10 21:00:13 +00:00
|
|
|
let gilrs = match Gilrs::new() {
|
|
|
|
Ok(gilrs) => Some(gilrs),
|
|
|
|
Err(gilrs::Error::NotImplemented(_dummy)) => {
|
|
|
|
warn!("Controller input is unsupported on this platform.");
|
|
|
|
None
|
|
|
|
},
|
|
|
|
Err(gilrs::Error::InvalidAxisToBtn) => {
|
|
|
|
error!(
|
|
|
|
"Invalid AxisToBtn controller mapping. Falling back to no controller support."
|
|
|
|
);
|
|
|
|
None
|
|
|
|
},
|
|
|
|
Err(gilrs::Error::Other(err)) => {
|
|
|
|
error!(
|
|
|
|
"Platform-specific error when creating a Gilrs instance: `{}`. Falling back \
|
|
|
|
to no controller support.",
|
|
|
|
err
|
|
|
|
);
|
|
|
|
None
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
let controller_settings = ControllerSettings::from(&settings.controller);
|
|
|
|
|
2020-01-02 03:48:11 +00:00
|
|
|
let mut this = Self {
|
2019-01-02 21:25:01 +00:00
|
|
|
events_loop,
|
2019-09-26 07:28:40 +00:00
|
|
|
renderer: Renderer::new(
|
|
|
|
device,
|
|
|
|
factory,
|
|
|
|
win_color_view,
|
|
|
|
win_depth_view,
|
|
|
|
settings.graphics.aa_mode,
|
2020-01-19 03:58:25 +00:00
|
|
|
settings.graphics.cloud_mode,
|
|
|
|
settings.graphics.fluid_mode,
|
2019-09-26 07:28:40 +00:00
|
|
|
)?,
|
2019-01-23 22:21:47 +00:00
|
|
|
window,
|
|
|
|
cursor_grabbed: false,
|
2019-06-05 15:57:48 +00:00
|
|
|
pan_sensitivity: settings.gameplay.pan_sensitivity,
|
|
|
|
zoom_sensitivity: settings.gameplay.zoom_sensitivity,
|
2019-10-02 12:44:41 +00:00
|
|
|
zoom_inversion: settings.gameplay.zoom_inversion,
|
2019-12-06 22:49:17 +00:00
|
|
|
mouse_y_inversion: settings.gameplay.mouse_y_inversion,
|
2019-05-18 21:16:35 +00:00
|
|
|
fullscreen: false,
|
2019-03-28 04:42:04 +00:00
|
|
|
needs_refresh_resize: false,
|
2019-06-30 04:20:50 +00:00
|
|
|
keypress_map,
|
2020-04-08 17:36:37 +00:00
|
|
|
remapping_keybindings: None,
|
2019-04-25 15:32:59 +00:00
|
|
|
supplement_events: vec![],
|
2019-05-25 11:52:43 +00:00
|
|
|
focused: true,
|
2020-03-10 21:00:13 +00:00
|
|
|
gilrs,
|
|
|
|
controller_settings,
|
|
|
|
cursor_position: winit::dpi::LogicalPosition::new(0.0, 0.0),
|
|
|
|
mouse_emulation_vec: Vec2::zero(),
|
2020-01-02 03:48:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
this.fullscreen(settings.graphics.fullscreen);
|
|
|
|
|
|
|
|
Ok(this)
|
2019-01-02 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn renderer(&self) -> &Renderer { &self.renderer }
|
|
|
|
|
|
|
|
pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer }
|
2019-01-02 22:08:13 +00:00
|
|
|
|
2020-01-02 03:48:11 +00:00
|
|
|
pub fn fetch_events(&mut self, settings: &mut Settings) -> Vec<Event> {
|
2019-03-30 02:15:27 +00:00
|
|
|
let mut events = vec![];
|
2019-04-25 15:32:59 +00:00
|
|
|
events.append(&mut self.supplement_events);
|
2019-03-28 04:42:04 +00:00
|
|
|
// Refresh ui size (used when changing playstates)
|
|
|
|
if self.needs_refresh_resize {
|
|
|
|
events.push(Event::Ui(ui::Event::new_resize(self.logical_size())));
|
|
|
|
self.needs_refresh_resize = false;
|
|
|
|
}
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
// Copy data that is needed by the events closure to avoid lifetime errors.
|
|
|
|
// TODO: Remove this if/when the compiler permits it.
|
2019-01-23 22:21:47 +00:00
|
|
|
let cursor_grabbed = self.cursor_grabbed;
|
2019-01-23 22:39:31 +00:00
|
|
|
let renderer = &mut self.renderer;
|
|
|
|
let window = &mut self.window;
|
2020-04-08 17:36:37 +00:00
|
|
|
let remapping_keybindings = &mut self.remapping_keybindings;
|
2019-05-25 11:52:43 +00:00
|
|
|
let focused = &mut self.focused;
|
2020-04-08 17:36:37 +00:00
|
|
|
let controls = &mut settings.controls;
|
2019-07-02 21:29:38 +00:00
|
|
|
let keypress_map = &mut self.keypress_map;
|
2019-05-25 02:30:56 +00:00
|
|
|
let pan_sensitivity = self.pan_sensitivity;
|
|
|
|
let zoom_sensitivity = self.zoom_sensitivity;
|
2019-10-02 12:44:41 +00:00
|
|
|
let zoom_inversion = match self.zoom_inversion {
|
|
|
|
true => -1.0,
|
|
|
|
false => 1.0,
|
|
|
|
};
|
2019-12-06 22:49:17 +00:00
|
|
|
let mouse_y_inversion = match self.mouse_y_inversion {
|
|
|
|
true => -1.0,
|
|
|
|
false => 1.0,
|
|
|
|
};
|
2019-05-18 21:16:35 +00:00
|
|
|
let mut toggle_fullscreen = false;
|
|
|
|
let mut take_screenshot = false;
|
2020-03-10 21:00:13 +00:00
|
|
|
let mut cursor_position = None;
|
2019-01-23 22:21:47 +00:00
|
|
|
|
2019-03-22 03:55:42 +00:00
|
|
|
self.events_loop.poll_events(|event| {
|
2019-05-17 09:22:32 +00:00
|
|
|
// Get events for ui.
|
2019-07-28 15:47:14 +00:00
|
|
|
if let Some(event) = ui::Event::try_from(event.clone(), window) {
|
2019-03-22 03:55:42 +00:00
|
|
|
events.push(Event::Ui(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
match event {
|
|
|
|
glutin::Event::WindowEvent { event, .. } => match event {
|
|
|
|
glutin::WindowEvent::CloseRequested => events.push(Event::Close),
|
|
|
|
glutin::WindowEvent::Resized(glutin::dpi::LogicalSize { width, height }) => {
|
2019-05-07 11:27:40 +00:00
|
|
|
let (mut color_view, mut depth_view) = renderer.win_views_mut();
|
2019-07-28 15:47:14 +00:00
|
|
|
gfx_window_glutin::update_views(window, &mut color_view, &mut depth_view);
|
2019-05-06 08:22:47 +00:00
|
|
|
renderer.on_resize().unwrap();
|
2019-03-22 03:55:42 +00:00
|
|
|
events.push(Event::Resize(Vec2::new(width as u32, height as u32)));
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2019-03-22 03:55:42 +00:00
|
|
|
glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)),
|
2019-09-18 16:46:12 +00:00
|
|
|
glutin::WindowEvent::MouseInput { button, state, .. } => {
|
2020-04-08 21:46:42 +00:00
|
|
|
if let (true, Some(game_inputs)) = (
|
|
|
|
cursor_grabbed,
|
|
|
|
Window::map_input(
|
|
|
|
KeyMouse::Mouse(button),
|
|
|
|
controls,
|
|
|
|
remapping_keybindings,
|
|
|
|
),
|
2020-04-08 17:36:37 +00:00
|
|
|
) {
|
2019-08-27 11:42:17 +00:00
|
|
|
for game_input in game_inputs {
|
|
|
|
events.push(Event::InputUpdate(
|
|
|
|
*game_input,
|
|
|
|
state == glutin::ElementState::Pressed,
|
|
|
|
));
|
|
|
|
}
|
2019-05-25 14:39:27 +00:00
|
|
|
}
|
2020-04-09 16:43:12 +00:00
|
|
|
events.push(Event::MouseButton(button, state));
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2020-04-08 17:36:37 +00:00
|
|
|
glutin::WindowEvent::KeyboardInput { input, .. } => {
|
|
|
|
if let Some(key) = input.virtual_keycode {
|
|
|
|
if let Some(game_inputs) = Window::map_input(
|
|
|
|
KeyMouse::Key(key),
|
|
|
|
controls,
|
|
|
|
remapping_keybindings,
|
|
|
|
) {
|
2019-08-27 11:42:17 +00:00
|
|
|
for game_input in game_inputs {
|
|
|
|
match game_input {
|
|
|
|
GameInput::Fullscreen => {
|
|
|
|
if input.state == glutin::ElementState::Pressed
|
|
|
|
&& !Self::is_pressed(
|
|
|
|
keypress_map,
|
|
|
|
GameInput::Fullscreen,
|
|
|
|
)
|
|
|
|
{
|
|
|
|
toggle_fullscreen = !toggle_fullscreen;
|
|
|
|
}
|
|
|
|
Self::set_pressed(
|
|
|
|
keypress_map,
|
|
|
|
GameInput::Fullscreen,
|
|
|
|
input.state,
|
|
|
|
);
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2019-08-27 11:42:17 +00:00
|
|
|
GameInput::Screenshot => {
|
|
|
|
take_screenshot = input.state
|
|
|
|
== glutin::ElementState::Pressed
|
|
|
|
&& !Self::is_pressed(
|
|
|
|
keypress_map,
|
|
|
|
GameInput::Screenshot,
|
|
|
|
);
|
|
|
|
Self::set_pressed(
|
|
|
|
keypress_map,
|
|
|
|
GameInput::Screenshot,
|
|
|
|
input.state,
|
|
|
|
);
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2019-08-27 11:42:17 +00:00
|
|
|
_ => events.push(Event::InputUpdate(
|
|
|
|
*game_input,
|
|
|
|
input.state == glutin::ElementState::Pressed,
|
|
|
|
)),
|
|
|
|
}
|
2019-05-18 21:16:35 +00:00
|
|
|
}
|
2019-06-30 04:20:50 +00:00
|
|
|
}
|
2020-04-08 17:36:37 +00:00
|
|
|
}
|
2019-03-02 03:48:30 +00:00
|
|
|
},
|
2020-04-08 17:36:37 +00:00
|
|
|
|
2019-06-29 01:39:47 +00:00
|
|
|
glutin::WindowEvent::Focused(state) => {
|
|
|
|
*focused = state;
|
|
|
|
events.push(Event::Focused(state));
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2020-03-10 21:00:13 +00:00
|
|
|
glutin::WindowEvent::CursorMoved { position, .. } => {
|
|
|
|
cursor_position = Some(position);
|
|
|
|
},
|
2020-02-01 20:39:39 +00:00
|
|
|
_ => {},
|
2019-02-02 20:18:40 +00:00
|
|
|
},
|
|
|
|
glutin::Event::DeviceEvent { event, .. } => match event {
|
2019-04-15 17:51:26 +00:00
|
|
|
glutin::DeviceEvent::MouseMotion {
|
|
|
|
delta: (dx, dy), ..
|
2019-09-18 16:46:12 +00:00
|
|
|
} if *focused => {
|
|
|
|
let delta = Vec2::new(
|
|
|
|
dx as f32 * (pan_sensitivity as f32 / 100.0),
|
2019-12-06 22:49:17 +00:00
|
|
|
dy as f32 * (pan_sensitivity as f32 * mouse_y_inversion / 100.0),
|
2019-09-18 16:46:12 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
if cursor_grabbed {
|
|
|
|
events.push(Event::CursorPan(delta));
|
|
|
|
} else {
|
|
|
|
events.push(Event::CursorMove(delta));
|
|
|
|
}
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2020-01-20 04:08:04 +00:00
|
|
|
glutin::DeviceEvent::MouseWheel { delta, .. } if cursor_grabbed && *focused => {
|
|
|
|
events.push(Event::Zoom({
|
|
|
|
let y = match delta {
|
|
|
|
glutin::MouseScrollDelta::LineDelta(_x, y) => y,
|
|
|
|
// TODO: Check to see if there is a better way to find the "line
|
|
|
|
// height" than just hardcoding 16.0 pixels. Alternately we could
|
|
|
|
// get rid of this and have the user set zoom sensitivity, since
|
|
|
|
// it's unlikely people would expect a configuration file to work
|
|
|
|
// across operating systems.
|
|
|
|
glutin::MouseScrollDelta::PixelDelta(pos) => (pos.y / 16.0) as f32,
|
|
|
|
};
|
|
|
|
y * (zoom_sensitivity as f32 / 100.0) * zoom_inversion
|
|
|
|
}))
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
|
|
|
_ => {},
|
2019-03-22 03:55:42 +00:00
|
|
|
},
|
2020-02-01 20:39:39 +00:00
|
|
|
_ => {},
|
2019-03-22 03:55:42 +00:00
|
|
|
}
|
2019-01-02 21:25:01 +00:00
|
|
|
});
|
2019-05-18 21:16:35 +00:00
|
|
|
|
2020-03-10 21:00:13 +00:00
|
|
|
if let Some(pos) = cursor_position {
|
|
|
|
self.cursor_position = pos;
|
|
|
|
}
|
|
|
|
|
2019-05-18 21:16:35 +00:00
|
|
|
if take_screenshot {
|
2020-03-05 19:26:07 +00:00
|
|
|
self.take_screenshot(&settings);
|
2019-05-18 21:16:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if toggle_fullscreen {
|
2020-01-02 03:48:11 +00:00
|
|
|
self.toggle_fullscreen(settings);
|
2019-05-18 21:16:35 +00:00
|
|
|
}
|
|
|
|
|
2020-03-10 21:00:13 +00:00
|
|
|
if let Some(gilrs) = &mut self.gilrs {
|
|
|
|
while let Some(event) = gilrs.next_event() {
|
|
|
|
fn handle_buttons(
|
|
|
|
settings: &ControllerSettings,
|
|
|
|
events: &mut Vec<Event>,
|
|
|
|
button: &Button,
|
|
|
|
is_pressed: bool,
|
|
|
|
) {
|
|
|
|
if let Some(evs) = settings.game_button_map.get(button) {
|
|
|
|
for ev in evs {
|
|
|
|
events.push(Event::InputUpdate(*ev, is_pressed));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(evs) = settings.menu_button_map.get(button) {
|
|
|
|
for ev in evs {
|
|
|
|
events.push(Event::MenuInput(*ev, is_pressed));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match event.event {
|
|
|
|
EventType::ButtonPressed(button, code)
|
|
|
|
| EventType::ButtonRepeated(button, code) => {
|
|
|
|
handle_buttons(
|
|
|
|
&self.controller_settings,
|
|
|
|
&mut events,
|
|
|
|
&Button::from((button, code)),
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
},
|
|
|
|
EventType::ButtonReleased(button, code) => {
|
|
|
|
handle_buttons(
|
|
|
|
&self.controller_settings,
|
|
|
|
&mut events,
|
|
|
|
&Button::from((button, code)),
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
},
|
|
|
|
EventType::ButtonChanged(button, _value, code) => {
|
|
|
|
if let Some(actions) = self
|
|
|
|
.controller_settings
|
|
|
|
.game_analog_button_map
|
|
|
|
.get(&AnalogButton::from((button, code)))
|
|
|
|
{
|
|
|
|
for action in actions {
|
|
|
|
match *action {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(actions) = self
|
|
|
|
.controller_settings
|
|
|
|
.menu_analog_button_map
|
|
|
|
.get(&AnalogButton::from((button, code)))
|
|
|
|
{
|
|
|
|
for action in actions {
|
|
|
|
match *action {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
EventType::AxisChanged(axis, value, code) => {
|
|
|
|
let value = match self
|
|
|
|
.controller_settings
|
|
|
|
.inverted_axes
|
|
|
|
.contains(&Axis::from((axis, code)))
|
|
|
|
{
|
|
|
|
true => value * -1.0,
|
|
|
|
false => value,
|
|
|
|
};
|
|
|
|
|
|
|
|
let value = self
|
|
|
|
.controller_settings
|
|
|
|
.apply_axis_deadzone(&Axis::from((axis, code)), value);
|
|
|
|
|
|
|
|
if self.cursor_grabbed {
|
|
|
|
if let Some(actions) = self
|
|
|
|
.controller_settings
|
|
|
|
.game_axis_map
|
|
|
|
.get(&Axis::from((axis, code)))
|
|
|
|
{
|
|
|
|
for action in actions {
|
|
|
|
match *action {
|
|
|
|
AxisGameAction::MovementX => {
|
|
|
|
events.push(Event::AnalogGameInput(
|
|
|
|
AnalogGameInput::MovementX(value),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
AxisGameAction::MovementY => {
|
|
|
|
events.push(Event::AnalogGameInput(
|
|
|
|
AnalogGameInput::MovementY(value),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
AxisGameAction::CameraX => {
|
|
|
|
events.push(Event::AnalogGameInput(
|
|
|
|
AnalogGameInput::CameraX(
|
|
|
|
value
|
|
|
|
* self.controller_settings.pan_sensitivity
|
|
|
|
as f32
|
|
|
|
/ 100.0,
|
|
|
|
),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
AxisGameAction::CameraY => {
|
|
|
|
events.push(Event::AnalogGameInput(
|
|
|
|
AnalogGameInput::CameraY(
|
|
|
|
value
|
|
|
|
* self.controller_settings.pan_sensitivity
|
|
|
|
as f32
|
|
|
|
/ 100.0,
|
|
|
|
),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if let Some(actions) = self
|
|
|
|
.controller_settings
|
|
|
|
.menu_axis_map
|
|
|
|
.get(&Axis::from((axis, code)))
|
|
|
|
{
|
|
|
|
// TODO: possibly add sensitivity settings when this is used
|
|
|
|
for action in actions {
|
|
|
|
match *action {
|
|
|
|
AxisMenuAction::MoveX => {
|
|
|
|
events.push(Event::AnalogMenuInput(
|
|
|
|
AnalogMenuInput::MoveX(value),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
AxisMenuAction::MoveY => {
|
|
|
|
events.push(Event::AnalogMenuInput(
|
|
|
|
AnalogMenuInput::MoveY(value),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
AxisMenuAction::ScrollX => {
|
|
|
|
events.push(Event::AnalogMenuInput(
|
|
|
|
AnalogMenuInput::ScrollX(value),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
AxisMenuAction::ScrollY => {
|
|
|
|
events.push(Event::AnalogMenuInput(
|
|
|
|
AnalogMenuInput::ScrollY(value),
|
|
|
|
));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
EventType::Connected => {},
|
|
|
|
EventType::Disconnected => {},
|
|
|
|
EventType::Dropped => {},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mouse emulation for the menus, to be removed when a proper menu navigation
|
|
|
|
// system is available
|
|
|
|
if !self.cursor_grabbed {
|
|
|
|
events = events
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|event| match event {
|
|
|
|
Event::AnalogMenuInput(input) => match input {
|
|
|
|
AnalogMenuInput::MoveX(d) => {
|
|
|
|
self.mouse_emulation_vec.x = d;
|
|
|
|
None
|
|
|
|
},
|
|
|
|
AnalogMenuInput::MoveY(d) => {
|
|
|
|
// This just has to be inverted for some reason
|
|
|
|
self.mouse_emulation_vec.y = d * -1.0;
|
|
|
|
None
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
let event = Event::AnalogMenuInput(input);
|
|
|
|
Some(event)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Event::MenuInput(input, state) => match input {
|
|
|
|
MenuInput::Apply => Some(match state {
|
|
|
|
true => Event::Ui(ui::Event(conrod_core::event::Input::Press(
|
|
|
|
conrod_core::input::Button::Mouse(
|
|
|
|
conrod_core::input::state::mouse::Button::Left,
|
|
|
|
),
|
|
|
|
))),
|
|
|
|
false => Event::Ui(ui::Event(conrod_core::event::Input::Release(
|
|
|
|
conrod_core::input::Button::Mouse(
|
|
|
|
conrod_core::input::state::mouse::Button::Left,
|
|
|
|
),
|
|
|
|
))),
|
|
|
|
}),
|
|
|
|
_ => Some(event),
|
|
|
|
},
|
|
|
|
_ => Some(event),
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let sensitivity = self.controller_settings.mouse_emulation_sensitivity;
|
|
|
|
if self.mouse_emulation_vec != Vec2::zero() {
|
|
|
|
self.offset_cursor(self.mouse_emulation_vec * sensitivity as f32)
|
|
|
|
.unwrap_or(());
|
|
|
|
}
|
|
|
|
}
|
2019-01-07 21:10:31 +00:00
|
|
|
events
|
2019-01-02 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
2020-03-10 21:00:13 +00:00
|
|
|
/// Moves cursor by an offset
|
|
|
|
pub fn offset_cursor(&self, d: Vec2<f32>) -> Result<(), String> {
|
|
|
|
self.window
|
|
|
|
.window()
|
|
|
|
.set_cursor_position(winit::dpi::LogicalPosition::new(
|
|
|
|
d.x as f64 + self.cursor_position.x,
|
|
|
|
d.y as f64 + self.cursor_position.y,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2019-01-12 01:14:58 +00:00
|
|
|
pub fn swap_buffers(&self) -> Result<(), Error> {
|
2019-04-02 04:54:27 +00:00
|
|
|
self.window
|
|
|
|
.swap_buffers()
|
2019-01-11 23:18:34 +00:00
|
|
|
.map_err(|err| Error::BackendError(Box::new(err)))
|
2019-01-02 21:25:01 +00:00
|
|
|
}
|
2019-01-12 01:14:58 +00:00
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn is_cursor_grabbed(&self) -> bool { self.cursor_grabbed }
|
2019-01-12 01:14:58 +00:00
|
|
|
|
2019-01-23 22:21:47 +00:00
|
|
|
pub fn grab_cursor(&mut self, grab: bool) {
|
|
|
|
self.cursor_grabbed = grab;
|
2019-07-28 15:47:14 +00:00
|
|
|
self.window.window().hide_cursor(grab);
|
|
|
|
let _ = self.window.window().grab_cursor(grab);
|
2019-01-12 01:14:58 +00:00
|
|
|
}
|
2019-02-16 03:01:42 +00:00
|
|
|
|
2020-01-02 03:48:11 +00:00
|
|
|
pub fn toggle_fullscreen(&mut self, settings: &mut Settings) {
|
|
|
|
self.fullscreen(!self.is_fullscreen());
|
|
|
|
settings.graphics.fullscreen = self.is_fullscreen();
|
|
|
|
settings.save_to_file_warn();
|
|
|
|
}
|
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn is_fullscreen(&self) -> bool { self.fullscreen }
|
2019-05-18 21:16:35 +00:00
|
|
|
|
|
|
|
pub fn fullscreen(&mut self, fullscreen: bool) {
|
2019-07-28 15:47:14 +00:00
|
|
|
let window = self.window.window();
|
2019-05-18 21:16:35 +00:00
|
|
|
self.fullscreen = fullscreen;
|
|
|
|
if fullscreen {
|
2019-07-28 15:47:14 +00:00
|
|
|
window.set_fullscreen(Some(window.get_current_monitor()));
|
2019-05-18 21:16:35 +00:00
|
|
|
} else {
|
2019-07-28 15:47:14 +00:00
|
|
|
window.set_fullscreen(None);
|
2019-05-18 21:16:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn needs_refresh_resize(&mut self) { self.needs_refresh_resize = true; }
|
2019-03-28 04:42:04 +00:00
|
|
|
|
2019-03-03 23:55:07 +00:00
|
|
|
pub fn logical_size(&self) -> Vec2<f64> {
|
2019-04-02 04:54:27 +00:00
|
|
|
let (w, h) = self
|
|
|
|
.window
|
2019-07-28 15:47:14 +00:00
|
|
|
.window()
|
2019-04-02 04:54:27 +00:00
|
|
|
.get_inner_size()
|
|
|
|
.unwrap_or(glutin::dpi::LogicalSize::new(0.0, 0.0))
|
|
|
|
.into();
|
2019-03-03 23:55:07 +00:00
|
|
|
Vec2::new(w, h)
|
2019-02-16 03:01:42 +00:00
|
|
|
}
|
2019-05-01 22:15:43 +00:00
|
|
|
|
2020-01-02 03:48:11 +00:00
|
|
|
pub fn set_size(&mut self, new_size: Vec2<u16>) {
|
|
|
|
self.window
|
|
|
|
.window()
|
|
|
|
.set_inner_size(glutin::dpi::LogicalSize::new(
|
|
|
|
new_size.x as f64,
|
|
|
|
new_size.y as f64,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn send_supplement_event(&mut self, event: Event) { self.supplement_events.push(event) }
|
2019-05-18 21:16:35 +00:00
|
|
|
|
2020-03-05 19:26:07 +00:00
|
|
|
pub fn take_screenshot(&mut self, settings: &Settings) {
|
2019-05-18 21:16:35 +00:00
|
|
|
match self.renderer.create_screenshot() {
|
|
|
|
Ok(img) => {
|
2020-03-05 19:26:07 +00:00
|
|
|
let mut path = settings.screenshots_path.clone();
|
|
|
|
|
2019-05-18 21:16:35 +00:00
|
|
|
std::thread::spawn(move || {
|
2020-03-05 19:26:07 +00:00
|
|
|
use std::time::SystemTime;
|
2019-05-18 21:16:35 +00:00
|
|
|
// Check if folder exists and create it if it does not
|
|
|
|
if !path.exists() {
|
2020-03-05 19:26:07 +00:00
|
|
|
if let Err(err) = std::fs::create_dir_all(&path) {
|
2019-06-06 14:48:41 +00:00
|
|
|
warn!("Couldn't create folder for screenshot: {:?}", err);
|
2019-05-18 21:16:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
path.push(format!(
|
|
|
|
"screenshot_{}.png",
|
|
|
|
SystemTime::now()
|
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)
|
|
|
|
.map(|d| d.as_millis())
|
|
|
|
.unwrap_or(0)
|
|
|
|
));
|
|
|
|
if let Err(err) = img.save(&path) {
|
2019-06-06 14:48:41 +00:00
|
|
|
warn!("Couldn't save screenshot: {:?}", err);
|
2019-05-18 21:16:35 +00:00
|
|
|
}
|
|
|
|
});
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2019-06-06 14:48:41 +00:00
|
|
|
Err(err) => error!(
|
2019-05-31 01:43:52 +00:00
|
|
|
"Couldn't create screenshot due to renderer error: {:?}",
|
|
|
|
err
|
|
|
|
),
|
2019-05-18 21:16:35 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-30 04:20:50 +00:00
|
|
|
|
2019-08-27 11:15:26 +00:00
|
|
|
fn is_pressed(map: &mut HashMap<GameInput, glutin::ElementState>, input: GameInput) -> bool {
|
2019-06-30 04:20:50 +00:00
|
|
|
*(map.entry(input).or_insert(glutin::ElementState::Released))
|
|
|
|
== glutin::ElementState::Pressed
|
|
|
|
}
|
|
|
|
|
2019-08-27 11:15:26 +00:00
|
|
|
fn set_pressed(
|
2019-06-30 04:20:50 +00:00
|
|
|
map: &mut HashMap<GameInput, glutin::ElementState>,
|
|
|
|
input: GameInput,
|
|
|
|
state: glutin::ElementState,
|
|
|
|
) {
|
|
|
|
map.insert(input, state);
|
|
|
|
}
|
2020-04-08 17:36:37 +00:00
|
|
|
|
|
|
|
// Function used to handle Mouse and Key events. It first checks if we're in
|
|
|
|
// remapping mode for a specific GameInput. If we are, we modify the binding
|
|
|
|
// of that GameInput with the KeyMouse passed. Else, we return an iterator of
|
|
|
|
// the GameInputs for that KeyMouse.
|
|
|
|
fn map_input<'a>(
|
|
|
|
key_mouse: KeyMouse,
|
|
|
|
controls: &'a mut ControlSettings,
|
|
|
|
remapping: &mut Option<GameInput>,
|
|
|
|
) -> Option<impl Iterator<Item = &'a GameInput>> {
|
|
|
|
match *remapping {
|
|
|
|
Some(game_input) => {
|
|
|
|
controls.modify_binding(game_input, key_mouse);
|
|
|
|
*remapping = None;
|
|
|
|
None
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
if let Some(game_inputs) = controls.get_associated_game_inputs(&key_mouse) {
|
|
|
|
Some(game_inputs.iter())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_keybinding_mode(&mut self, game_input: GameInput) {
|
|
|
|
self.remapping_keybindings = Some(game_input);
|
|
|
|
}
|
2019-01-02 21:25:01 +00:00
|
|
|
}
|