From 2860938b9abb7300ff00527fb23116d44844b8b1 Mon Sep 17 00:00:00 2001 From: Alula <6276139+alula@users.noreply.github.com> Date: Mon, 21 Nov 2022 15:12:45 +0100 Subject: [PATCH] abstract gamepad away from SDL --- src/framework/backend.rs | 6 ++ src/framework/backend_sdl2.rs | 50 ++++++++++++++-- src/framework/gamepad.rs | 105 ++++++++++++++++++++-------------- src/game/mod.rs | 6 +- 4 files changed, 115 insertions(+), 52 deletions(-) diff --git a/src/framework/backend.rs b/src/framework/backend.rs index f1b1886..cad83d5 100644 --- a/src/framework/backend.rs +++ b/src/framework/backend.rs @@ -95,6 +95,12 @@ pub trait BackendTexture { fn as_any(&self) -> &dyn Any; } +pub trait BackendGamepad { + fn set_rumble(&mut self, low_freq: u16, high_freq: u16, duration_ms: u32) -> GameResult; + + fn instance_id(&self) -> u32; +} + #[allow(unreachable_code)] pub fn init_backend(headless: bool, size_hint: (u16, u16)) -> GameResult> { if headless { diff --git a/src/framework/backend_sdl2.rs b/src/framework/backend_sdl2.rs index cdb8192..1d122c2 100644 --- a/src/framework/backend_sdl2.rs +++ b/src/framework/backend_sdl2.rs @@ -22,13 +22,11 @@ use sdl2::video::Window; use sdl2::video::WindowContext; use crate::common::{Color, Rect}; -use crate::framework::backend::{ - Backend, BackendEventLoop, BackendRenderer, BackendShader, BackendTexture, SpriteBatchCommand, VertexData, -}; +use crate::framework::backend::{Backend, BackendEventLoop, BackendGamepad, BackendRenderer, BackendShader, BackendTexture, SpriteBatchCommand, VertexData}; use crate::framework::context::Context; use crate::framework::error::{GameError, GameResult}; use crate::framework::filesystem; -use crate::framework::gamepad::{Axis, Button}; +use crate::framework::gamepad::{Axis, Button, GamepadType}; use crate::framework::graphics::BlendMode; use crate::framework::keyboard::ScanCode; use crate::framework::render_opengl::{GLContext, OpenGLRenderer}; @@ -320,10 +318,10 @@ impl BackendEventLoop for SDL2EventLoop { log::info!("Connected gamepad: {} (ID: {})", controller.name(), id); let axis_sensitivity = state.settings.get_gamepad_axis_sensitivity(which); - ctx.gamepad_context.add_gamepad(controller, axis_sensitivity); + ctx.gamepad_context.add_gamepad(SDL2Gamepad::new(controller), axis_sensitivity); unsafe { - let controller_type = sdl2_sys::SDL_GameControllerTypeForIndex(id as _); + let controller_type = get_game_controller_type(sdl2_sys::SDL_GameControllerTypeForIndex(id as _)); ctx.gamepad_context.set_gamepad_type(id, controller_type); } } @@ -471,6 +469,46 @@ impl BackendEventLoop for SDL2EventLoop { } } +fn get_game_controller_type(ctype: sdl2_sys::SDL_GameControllerType) -> GamepadType { + match ctype as i32 { + 1 => GamepadType::Xbox360, + 2 => GamepadType::XboxOne, + 3 => GamepadType::PS3, + 4 => GamepadType::PS4, + 5 => GamepadType::NintendoSwitchPro, + 6 => GamepadType::Virtual, + 7 => GamepadType::PS5, + 8 => GamepadType::AmazonLuma, + 9 => GamepadType::GoogleStadia, + 10 => GamepadType::NVIDIAShield, + 11 => GamepadType::NintendoSwitchJoyConLeft, + 12 => GamepadType::NintendoSwitchJoyConRight, + 13 => GamepadType::NintendoSwitchJoyConPair, + _ => GamepadType::Unknown, + } +} + +struct SDL2Gamepad { + inner: GameController, +} + +impl SDL2Gamepad { + pub fn new(inner: GameController) -> Box { + Box::new(SDL2Gamepad { inner }) + } +} + +impl BackendGamepad for SDL2Gamepad { + fn set_rumble(&mut self, low_freq: u16, high_freq: u16, duration_ms: u32) -> GameResult { + self.inner.set_rumble(low_freq, high_freq, duration_ms) + .map_err(|e| GameError::GamepadError(e.to_string())) + } + + fn instance_id(&self) -> u32 { + self.inner.instance_id() + } +} + struct SDL2Renderer { refs: Rc>, imgui: Rc>, diff --git a/src/framework/gamepad.rs b/src/framework/gamepad.rs index 384761e..ca0ca0e 100644 --- a/src/framework/gamepad.rs +++ b/src/framework/gamepad.rs @@ -1,17 +1,57 @@ use std::collections::{HashMap, HashSet}; -use sdl2::controller::GameController; use serde::{Deserialize, Serialize}; -use crate::{common::Rect, engine_constants::EngineConstants, framework::context::Context}; +use crate::framework::backend::BackendGamepad; use crate::framework::error::GameResult; use crate::game::shared_game_state::SharedGameState; +use crate::{common::Rect, engine_constants::EngineConstants, framework::context::Context}; const QUAKE_RUMBLE_LOW_FREQ: u16 = 0x3000; const QUAKE_RUMBLE_HI_FREQ: u16 = 0; const SUPER_QUAKE_RUMBLE_LOW_FREQ: u16 = 0x5000; const SUPER_QUAKE_RUMBLE_HI_FREQ: u16 = 0; +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] +#[repr(u32)] +pub enum GamepadType { + Unknown, + Xbox360, + XboxOne, + PS3, + PS4, + NintendoSwitchPro, + Virtual, + PS5, + AmazonLuma, + GoogleStadia, + NVIDIAShield, + NintendoSwitchJoyConLeft, + NintendoSwitchJoyConRight, + NintendoSwitchJoyConPair, +} + +impl GamepadType { + pub fn get_name(&self) -> &str { + match self { + GamepadType::Unknown => "Unknown controller", + GamepadType::Xbox360 => "Xbox 360 controller", + GamepadType::XboxOne => "Xbox One controller", + GamepadType::PS3 => "PlayStation 3 controller", + GamepadType::PS4 => "PlayStation 4 controller", + GamepadType::NintendoSwitchPro => "Nintendo Switch Pro controller", + GamepadType::Virtual => "Virtual controller", + GamepadType::PS5 => "PlayStation 5 controller", + GamepadType::AmazonLuma => "Amazon Luma controller", + GamepadType::GoogleStadia => "Google Stadia controller", + GamepadType::NVIDIAShield => "NVIDIA Shield controller", + GamepadType::NintendoSwitchJoyConLeft => "Nintendo Switch Joy-Con (left)", + GamepadType::NintendoSwitchJoyConRight => "Nintendo Switch Joy-Con (right)", + GamepadType::NintendoSwitchJoyConPair => "Nintendo Switch Joy-Con (pair)", + } + } +} + #[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] #[repr(u32)] pub enum Axis { @@ -118,8 +158,8 @@ impl PlayerControllerInputType { } pub struct GamepadData { - controller: GameController, - controller_type: Option, + controller: Box, + controller_type: GamepadType, left_x: f64, left_y: f64, @@ -135,10 +175,10 @@ pub struct GamepadData { } impl GamepadData { - pub(crate) fn new(game_controller: GameController, axis_sensitivity: f64) -> Self { + pub(crate) fn new(game_controller: Box, axis_sensitivity: f64) -> Self { GamepadData { controller: game_controller, - controller_type: None, + controller_type: GamepadType::Unknown, left_x: 0.0, left_y: 0.0, @@ -154,50 +194,29 @@ impl GamepadData { } } - pub(crate) fn set_gamepad_type(&mut self, controller_type: sdl2_sys::SDL_GameControllerType) { - self.controller_type = Some(controller_type); + pub(crate) fn set_gamepad_type(&mut self, controller_type: GamepadType) { + self.controller_type = controller_type; } pub(crate) fn get_gamepad_sprite_offset(&self) -> usize { - if let Some(controller_type) = self.controller_type { - return match controller_type { - sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_PS3 - | sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_PS4 - | sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_PS5 => 0, - sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_XBOX360 - | sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_XBOXONE => 1, - sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO => 3, - _ => 1, - }; + match self.controller_type { + GamepadType::PS3 | GamepadType::PS4 | GamepadType::PS5 => 0, + GamepadType::Xbox360 | GamepadType::XboxOne => 1, + GamepadType::NintendoSwitchPro + | GamepadType::NintendoSwitchJoyConLeft + | GamepadType::NintendoSwitchJoyConRight + | GamepadType::NintendoSwitchJoyConPair => 3, + _ => 1, } - - 1 } pub fn get_gamepad_name(&self) -> String { - let name = if let Some(controller_type) = self.controller_type { - match controller_type { - sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_PS3 - | sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_PS4 - | sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_PS5 => "PlayStation Controller".to_string(), - sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_XBOX360 - | sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_XBOXONE => "Xbox Controller".to_string(), - sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO => { - "Nintendo Switch Controller".to_string() - } - _ => "Unknown Controller".to_string(), - } - } else { - "Unknown controller".to_string() - }; - - name + self.controller_type.get_name().to_owned() } pub fn set_rumble(&mut self, state: &SharedGameState, low_freq: u16, hi_freq: u16, ticks: u32) -> GameResult { let duration_ms = (ticks as f32 / state.settings.timing_mode.get_tps() as f32 * 1000.0) as u32; - self.controller.set_rumble(low_freq, hi_freq, duration_ms); - Ok(()) + self.controller.set_rumble(low_freq, hi_freq, duration_ms) } } @@ -226,7 +245,7 @@ impl GamepadContext { self.gamepads.get_mut(gamepad_index) } - pub(crate) fn add_gamepad(&mut self, game_controller: GameController, axis_sensitivity: f64) { + pub(crate) fn add_gamepad(&mut self, game_controller: Box, axis_sensitivity: f64) { self.gamepads.push(GamepadData::new(game_controller, axis_sensitivity)); } @@ -234,7 +253,7 @@ impl GamepadContext { self.gamepads.retain(|data| data.controller.instance_id() != gamepad_id); } - pub(crate) fn set_gamepad_type(&mut self, gamepad_id: u32, controller_type: sdl2_sys::SDL_GameControllerType) { + pub(crate) fn set_gamepad_type(&mut self, gamepad_id: u32, controller_type: GamepadType) { if let Some(gamepad) = self.get_gamepad_mut(gamepad_id) { gamepad.set_gamepad_type(controller_type); } @@ -377,7 +396,7 @@ impl Default for GamepadContext { } } -pub fn add_gamepad(context: &mut Context, game_controller: GameController, axis_sensitivity: f64) { +pub fn add_gamepad(context: &mut Context, game_controller: Box, axis_sensitivity: f64) { context.gamepad_context.add_gamepad(game_controller, axis_sensitivity); } @@ -385,7 +404,7 @@ pub fn remove_gamepad(context: &mut Context, gamepad_id: u32) { context.gamepad_context.remove_gamepad(gamepad_id); } -pub fn set_gamepad_type(context: &mut Context, gamepad_id: u32, controller_type: sdl2_sys::SDL_GameControllerType) { +pub fn set_gamepad_type(context: &mut Context, gamepad_id: u32, controller_type: GamepadType) { context.gamepad_context.set_gamepad_type(gamepad_id, controller_type); } diff --git a/src/game/mod.rs b/src/game/mod.rs index 7b0254a..9a85a22 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -24,15 +24,15 @@ pub mod caret; pub mod frame; pub mod inventory; pub mod map; +pub mod npc; pub mod physics; +pub mod player; pub mod profile; +pub mod scripting; pub mod settings; pub mod shared_game_state; pub mod stage; -pub mod npc; -pub mod player; pub mod weapon; -pub mod scripting; pub struct LaunchOptions { pub server_mode: bool,