abstract gamepad away from SDL
This commit is contained in:
parent
e74b586dd1
commit
2860938b9a
|
@ -95,6 +95,12 @@ pub trait BackendTexture {
|
||||||
fn as_any(&self) -> &dyn Any;
|
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)]
|
#[allow(unreachable_code)]
|
||||||
pub fn init_backend(headless: bool, size_hint: (u16, u16)) -> GameResult<Box<dyn Backend>> {
|
pub fn init_backend(headless: bool, size_hint: (u16, u16)) -> GameResult<Box<dyn Backend>> {
|
||||||
if headless {
|
if headless {
|
||||||
|
|
|
@ -22,13 +22,11 @@ use sdl2::video::Window;
|
||||||
use sdl2::video::WindowContext;
|
use sdl2::video::WindowContext;
|
||||||
|
|
||||||
use crate::common::{Color, Rect};
|
use crate::common::{Color, Rect};
|
||||||
use crate::framework::backend::{
|
use crate::framework::backend::{Backend, BackendEventLoop, BackendGamepad, BackendRenderer, BackendShader, BackendTexture, SpriteBatchCommand, VertexData};
|
||||||
Backend, BackendEventLoop, BackendRenderer, BackendShader, BackendTexture, SpriteBatchCommand, VertexData,
|
|
||||||
};
|
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::{GameError, GameResult};
|
use crate::framework::error::{GameError, GameResult};
|
||||||
use crate::framework::filesystem;
|
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::graphics::BlendMode;
|
||||||
use crate::framework::keyboard::ScanCode;
|
use crate::framework::keyboard::ScanCode;
|
||||||
use crate::framework::render_opengl::{GLContext, OpenGLRenderer};
|
use crate::framework::render_opengl::{GLContext, OpenGLRenderer};
|
||||||
|
@ -320,10 +318,10 @@ impl BackendEventLoop for SDL2EventLoop {
|
||||||
log::info!("Connected gamepad: {} (ID: {})", controller.name(), id);
|
log::info!("Connected gamepad: {} (ID: {})", controller.name(), id);
|
||||||
|
|
||||||
let axis_sensitivity = state.settings.get_gamepad_axis_sensitivity(which);
|
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 {
|
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);
|
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 {
|
struct SDL2Renderer {
|
||||||
refs: Rc<RefCell<SDL2Context>>,
|
refs: Rc<RefCell<SDL2Context>>,
|
||||||
imgui: Rc<RefCell<imgui::Context>>,
|
imgui: Rc<RefCell<imgui::Context>>,
|
||||||
|
|
|
@ -1,17 +1,57 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use sdl2::controller::GameController;
|
|
||||||
use serde::{Deserialize, Serialize};
|
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::framework::error::GameResult;
|
||||||
use crate::game::shared_game_state::SharedGameState;
|
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_LOW_FREQ: u16 = 0x3000;
|
||||||
const QUAKE_RUMBLE_HI_FREQ: u16 = 0;
|
const QUAKE_RUMBLE_HI_FREQ: u16 = 0;
|
||||||
const SUPER_QUAKE_RUMBLE_LOW_FREQ: u16 = 0x5000;
|
const SUPER_QUAKE_RUMBLE_LOW_FREQ: u16 = 0x5000;
|
||||||
const SUPER_QUAKE_RUMBLE_HI_FREQ: u16 = 0;
|
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)]
|
#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
pub enum Axis {
|
pub enum Axis {
|
||||||
|
@ -118,8 +158,8 @@ impl PlayerControllerInputType {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GamepadData {
|
pub struct GamepadData {
|
||||||
controller: GameController,
|
controller: Box<dyn BackendGamepad>,
|
||||||
controller_type: Option<sdl2_sys::SDL_GameControllerType>,
|
controller_type: GamepadType,
|
||||||
|
|
||||||
left_x: f64,
|
left_x: f64,
|
||||||
left_y: f64,
|
left_y: f64,
|
||||||
|
@ -135,10 +175,10 @@ pub struct GamepadData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
GamepadData {
|
||||||
controller: game_controller,
|
controller: game_controller,
|
||||||
controller_type: None,
|
controller_type: GamepadType::Unknown,
|
||||||
|
|
||||||
left_x: 0.0,
|
left_x: 0.0,
|
||||||
left_y: 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) {
|
pub(crate) fn set_gamepad_type(&mut self, controller_type: GamepadType) {
|
||||||
self.controller_type = Some(controller_type);
|
self.controller_type = controller_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_gamepad_sprite_offset(&self) -> usize {
|
pub(crate) fn get_gamepad_sprite_offset(&self) -> usize {
|
||||||
if let Some(controller_type) = self.controller_type {
|
match self.controller_type {
|
||||||
return match controller_type {
|
GamepadType::PS3 | GamepadType::PS4 | GamepadType::PS5 => 0,
|
||||||
sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_PS3
|
GamepadType::Xbox360 | GamepadType::XboxOne => 1,
|
||||||
| sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_PS4
|
GamepadType::NintendoSwitchPro
|
||||||
| sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_PS5 => 0,
|
| GamepadType::NintendoSwitchJoyConLeft
|
||||||
sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_XBOX360
|
| GamepadType::NintendoSwitchJoyConRight
|
||||||
| sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_XBOXONE => 1,
|
| GamepadType::NintendoSwitchJoyConPair => 3,
|
||||||
sdl2_sys::SDL_GameControllerType::SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO => 3,
|
_ => 1,
|
||||||
_ => 1,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gamepad_name(&self) -> String {
|
pub fn get_gamepad_name(&self) -> String {
|
||||||
let name = if let Some(controller_type) = self.controller_type {
|
self.controller_type.get_name().to_owned()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_rumble(&mut self, state: &SharedGameState, low_freq: u16, hi_freq: u16, ticks: u32) -> GameResult {
|
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;
|
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);
|
self.controller.set_rumble(low_freq, hi_freq, duration_ms)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +245,7 @@ impl GamepadContext {
|
||||||
self.gamepads.get_mut(gamepad_index)
|
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));
|
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);
|
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) {
|
if let Some(gamepad) = self.get_gamepad_mut(gamepad_id) {
|
||||||
gamepad.set_gamepad_type(controller_type);
|
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);
|
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);
|
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);
|
context.gamepad_context.set_gamepad_type(gamepad_id, controller_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,15 +24,15 @@ pub mod caret;
|
||||||
pub mod frame;
|
pub mod frame;
|
||||||
pub mod inventory;
|
pub mod inventory;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
|
pub mod npc;
|
||||||
pub mod physics;
|
pub mod physics;
|
||||||
|
pub mod player;
|
||||||
pub mod profile;
|
pub mod profile;
|
||||||
|
pub mod scripting;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod shared_game_state;
|
pub mod shared_game_state;
|
||||||
pub mod stage;
|
pub mod stage;
|
||||||
pub mod npc;
|
|
||||||
pub mod player;
|
|
||||||
pub mod weapon;
|
pub mod weapon;
|
||||||
pub mod scripting;
|
|
||||||
|
|
||||||
pub struct LaunchOptions {
|
pub struct LaunchOptions {
|
||||||
pub server_mode: bool,
|
pub server_mode: bool,
|
||||||
|
|
Loading…
Reference in New Issue