use dreamwell_engine::input::VirtualKey;
use dreamwell_fabric::FabricInput;
use dreamwell_gpu::camera::Camera;
use winit::event::{ElementState, KeyEvent, MouseButton, MouseScrollDelta};
use winit::keyboard::{KeyCode, PhysicalKey};
const SCROLL_DEAD_ZONE: f32 = 0.01;
const CURSOR_DEAD_ZONE: f32 = 0.1;
const PAN_SPEED: f32 = 0.5;
const SCROLL_SENSITIVITY: f32 = 0.5;
const PIXEL_SCROLL_SCALE: f32 = 0.01;
const ORBIT_YAW_SENSITIVITY: f32 = 0.005;
const ORBIT_PITCH_SENSITIVITY: f32 = 0.003;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RuntimeAction {
MoveIntent,
LookIntent,
BurstStart,
BurstEnd,
SetFormCohere,
SetFormWave,
GatherStart,
GatherEnd,
PrimaryActionStart,
PrimaryActionEnd,
Interact,
Jump,
CameraRecenter,
}
pub struct InputState {
pub fabric: FabricInput,
scroll_raw: f32,
active_touches: std::collections::HashMap<u64, [f32; 2]>,
pub orbit_dx: f32,
pub orbit_dy: f32,
pub scroll_delta: f32,
}
impl InputState {
pub fn new() -> Self {
Self {
fabric: FabricInput::new(),
scroll_raw: 0.0,
active_touches: std::collections::HashMap::new(),
orbit_dx: 0.0,
orbit_dy: 0.0,
scroll_delta: 0.0,
}
}
pub fn handle_keyboard(&mut self, event: &KeyEvent) {
if let PhysicalKey::Code(code) = event.physical_key {
if let Some(vk) = winit_to_virtual_key(code) {
match event.state {
ElementState::Pressed => self.fabric.key_down(vk),
ElementState::Released => self.fabric.key_up(vk),
}
}
}
}
pub fn handle_mouse_button(&mut self, button: MouseButton, state: ElementState) {
let vk = match button {
MouseButton::Left => VirtualKey::MouseLeft,
MouseButton::Right => VirtualKey::MouseRight,
MouseButton::Middle => VirtualKey::MouseMiddle,
MouseButton::Back => VirtualKey::MouseButton4,
MouseButton::Forward => VirtualKey::MouseButton5,
_ => return,
};
match state {
ElementState::Pressed => self.fabric.key_down(vk),
ElementState::Released => self.fabric.key_up(vk),
}
}
pub fn handle_cursor_move(&mut self, x: f32, y: f32) {
self.fabric.cursor_moved(x, y);
}
pub fn handle_scroll(&mut self, delta: &MouseScrollDelta) {
let y = match delta {
MouseScrollDelta::LineDelta(_, y) => *y,
MouseScrollDelta::PixelDelta(pos) => pos.y as f32 * PIXEL_SCROLL_SCALE,
};
self.scroll_raw = y;
self.fabric.scroll(y);
}
pub fn apply_to_camera(&mut self, camera: &mut Camera, dt: f32) {
let frame = self.fabric.build_frame();
let dt_pan = PAN_SPEED * dt * 60.0;
if self.scroll_raw.abs() > SCROLL_DEAD_ZONE {
camera.zoom(-self.scroll_raw * SCROLL_SENSITIVITY);
self.scroll_raw = 0.0;
}
if frame.has_action(dreamwell_engine::input::InputAction::CameraRotate) {
let [dx, dy] = frame.cursor_delta;
if dx.abs() > CURSOR_DEAD_ZONE || dy.abs() > CURSOR_DEAD_ZONE {
camera.rotate(dx, dy);
}
}
if frame.has_action(dreamwell_engine::input::InputAction::CameraPan) {
let [dx, dy] = frame.cursor_delta;
if dx.abs() > CURSOR_DEAD_ZONE || dy.abs() > CURSOR_DEAD_ZONE {
camera.pan(-dx, dy);
}
}
let [mx, my] = frame.movement;
if my > 0.0 {
camera.pan(0.0, dt_pan);
}
if my < 0.0 {
camera.pan(0.0, -dt_pan);
}
if mx < 0.0 {
camera.pan(dt_pan, 0.0);
}
if mx > 0.0 {
camera.pan(-dt_pan, 0.0);
}
}
pub fn apply_mouse_to_camera(&mut self, _camera: &mut Camera, _dt: f32) {
if self.scroll_raw.abs() > SCROLL_DEAD_ZONE {
self.scroll_delta += -self.scroll_raw * SCROLL_SENSITIVITY;
self.scroll_raw = 0.0;
}
let frame = self.fabric.build_frame();
if frame.has_action(dreamwell_engine::input::InputAction::CameraRotate) {
let [dx, dy] = frame.cursor_delta;
if dx.abs() > CURSOR_DEAD_ZONE {
self.orbit_dx += dx * ORBIT_YAW_SENSITIVITY;
}
if dy.abs() > CURSOR_DEAD_ZONE {
self.orbit_dy += dy * ORBIT_PITCH_SENSITIVITY;
}
}
}
#[cfg(feature = "gamepad")]
pub fn handle_gamepad(&mut self, gilrs: &mut gilrs::Gilrs, camera: &mut Camera) {
while let Some(event) = gilrs.next_event() {
let _ = event;
}
if let Some((_id, gamepad)) = gilrs.gamepads().next() {
let lx = gamepad.value(gilrs::Axis::LeftStickX);
let ly = gamepad.value(gilrs::Axis::LeftStickY);
let rx = gamepad.value(gilrs::Axis::RightStickX);
let ry = gamepad.value(gilrs::Axis::RightStickY);
const DEAD_ZONE: f32 = 0.15;
if lx.abs() > DEAD_ZONE || ly.abs() > DEAD_ZONE {
camera.pan(-lx * PAN_SPEED, ly * PAN_SPEED);
}
if rx.abs() > DEAD_ZONE || ry.abs() > DEAD_ZONE {
camera.rotate(rx * 2.0, ry * 2.0);
}
let lt = gamepad.value(gilrs::Axis::LeftZ);
let rt = gamepad.value(gilrs::Axis::RightZ);
let zoom_delta = rt - lt;
if zoom_delta.abs() > DEAD_ZONE {
camera.zoom(zoom_delta * SCROLL_SENSITIVITY);
}
}
}
pub fn handle_touch(&mut self, phase: TouchPhase, id: u64, x: f32, y: f32) {
match phase {
TouchPhase::Started => {
self.active_touches.insert(id, [x, y]);
}
TouchPhase::Moved => {
if let Some(prev) = self.active_touches.get_mut(&id) {
let dx = x - prev[0];
let dy = y - prev[1];
*prev = [x, y];
if self.active_touches.len() == 1 {
self.fabric.cursor_moved(dx, dy);
}
}
}
TouchPhase::Ended | TouchPhase::Cancelled => {
self.active_touches.remove(&id);
}
}
}
pub fn end_frame(&mut self) {
self.fabric.end_frame();
self.scroll_raw = 0.0;
self.orbit_dx = 0.0;
self.orbit_dy = 0.0;
self.scroll_delta = 0.0;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TouchPhase {
Started,
Moved,
Ended,
Cancelled,
}
impl Default for InputState {
fn default() -> Self {
Self::new()
}
}
fn winit_to_virtual_key(code: KeyCode) -> Option<VirtualKey> {
Some(match code {
KeyCode::KeyA => VirtualKey::A,
KeyCode::KeyB => VirtualKey::B,
KeyCode::KeyC => VirtualKey::C,
KeyCode::KeyD => VirtualKey::D,
KeyCode::KeyE => VirtualKey::E,
KeyCode::KeyF => VirtualKey::F,
KeyCode::KeyG => VirtualKey::G,
KeyCode::KeyH => VirtualKey::H,
KeyCode::KeyI => VirtualKey::I,
KeyCode::KeyJ => VirtualKey::J,
KeyCode::KeyK => VirtualKey::K,
KeyCode::KeyL => VirtualKey::L,
KeyCode::KeyM => VirtualKey::M,
KeyCode::KeyN => VirtualKey::N,
KeyCode::KeyO => VirtualKey::O,
KeyCode::KeyP => VirtualKey::P,
KeyCode::KeyQ => VirtualKey::Q,
KeyCode::KeyR => VirtualKey::R,
KeyCode::KeyS => VirtualKey::S,
KeyCode::KeyT => VirtualKey::T,
KeyCode::KeyU => VirtualKey::U,
KeyCode::KeyV => VirtualKey::V,
KeyCode::KeyW => VirtualKey::W,
KeyCode::KeyX => VirtualKey::X,
KeyCode::KeyY => VirtualKey::Y,
KeyCode::KeyZ => VirtualKey::Z,
KeyCode::Digit0 => VirtualKey::Num0,
KeyCode::Digit1 => VirtualKey::Num1,
KeyCode::Digit2 => VirtualKey::Num2,
KeyCode::Digit3 => VirtualKey::Num3,
KeyCode::Digit4 => VirtualKey::Num4,
KeyCode::Digit5 => VirtualKey::Num5,
KeyCode::Digit6 => VirtualKey::Num6,
KeyCode::Digit7 => VirtualKey::Num7,
KeyCode::Digit8 => VirtualKey::Num8,
KeyCode::Digit9 => VirtualKey::Num9,
KeyCode::ArrowUp => VirtualKey::ArrowUp,
KeyCode::ArrowDown => VirtualKey::ArrowDown,
KeyCode::ArrowLeft => VirtualKey::ArrowLeft,
KeyCode::ArrowRight => VirtualKey::ArrowRight,
KeyCode::ShiftLeft => VirtualKey::ShiftLeft,
KeyCode::ShiftRight => VirtualKey::ShiftRight,
KeyCode::ControlLeft => VirtualKey::CtrlLeft,
KeyCode::ControlRight => VirtualKey::CtrlRight,
KeyCode::AltLeft => VirtualKey::AltLeft,
KeyCode::AltRight => VirtualKey::AltRight,
KeyCode::Space => VirtualKey::Space,
KeyCode::Enter => VirtualKey::Enter,
KeyCode::Escape => VirtualKey::Escape,
KeyCode::Tab => VirtualKey::Tab,
KeyCode::Backspace => VirtualKey::Backspace,
KeyCode::Delete => VirtualKey::Delete,
KeyCode::Home => VirtualKey::Home,
KeyCode::End => VirtualKey::End,
KeyCode::PageUp => VirtualKey::PageUp,
KeyCode::PageDown => VirtualKey::PageDown,
KeyCode::F1 => VirtualKey::F1,
KeyCode::F2 => VirtualKey::F2,
KeyCode::F3 => VirtualKey::F3,
KeyCode::F4 => VirtualKey::F4,
KeyCode::F5 => VirtualKey::F5,
KeyCode::F6 => VirtualKey::F6,
KeyCode::F7 => VirtualKey::F7,
KeyCode::F8 => VirtualKey::F8,
KeyCode::F9 => VirtualKey::F9,
KeyCode::F10 => VirtualKey::F10,
KeyCode::F11 => VirtualKey::F11,
KeyCode::F12 => VirtualKey::F12,
_ => return None,
})
}