abstract gamepad away from SDL

This commit is contained in:
Alula 2022-11-21 15:12:45 +01:00
parent e74b586dd1
commit 2860938b9a
No known key found for this signature in database
GPG Key ID: 3E00485503A1D8BA
4 changed files with 115 additions and 52 deletions

View File

@ -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<Box<dyn Backend>> {
if headless {

View File

@ -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<dyn BackendGamepad> {
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<RefCell<SDL2Context>>,
imgui: Rc<RefCell<imgui::Context>>,

View File

@ -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<sdl2_sys::SDL_GameControllerType>,
controller: Box<dyn BackendGamepad>,
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<dyn BackendGamepad>, 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<dyn BackendGamepad>, 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<dyn BackendGamepad>, 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);
}

View File

@ -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,