Frontend: Rumble support

This commit is contained in:
Connor McLaughlin 2019-12-15 23:24:34 +10:00
parent cbcb9b02b0
commit 6f7154fbef
3 changed files with 113 additions and 52 deletions

View file

@ -24,7 +24,7 @@ static int NoGUITest()
static int Run(int argc, char* argv[])
{
// init sdl
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER) < 0)
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) < 0)
{
Panic("SDL initialization failed");
return -1;
@ -51,8 +51,8 @@ static int Run(int argc, char* argv[])
}
// create display and host interface
std::unique_ptr<SDLHostInterface> host_interface =
SDLHostInterface::Create(filename, exp1_filename, state_filename.IsEmpty() ? nullptr : state_filename.GetCharArray());
std::unique_ptr<SDLHostInterface> host_interface = SDLHostInterface::Create(
filename, exp1_filename, state_filename.IsEmpty() ? nullptr : state_filename.GetCharArray());
if (!host_interface)
{
Panic("Failed to create host interface");
@ -83,8 +83,8 @@ int main(int argc, char* argv[])
#else
g_pLog->SetConsoleOutputParams(true, nullptr, LOGLEVEL_DEBUG);
// g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL SPU Pad DigitalController", LOGLEVEL_DEBUG);
// g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL Pad DigitalController MemoryCard InterruptController SPU MDEC", LOGLEVEL_DEBUG);
// g_pLog->SetFilterLevel(LOGLEVEL_TRACE);
// g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL Pad DigitalController MemoryCard InterruptController SPU
// MDEC", LOGLEVEL_DEBUG); g_pLog->SetFilterLevel(LOGLEVEL_TRACE);
g_pLog->SetFilterLevel(LOGLEVEL_DEBUG);
// g_pLog->SetFilterLevel(LOGLEVEL_DEV);
#endif

View file

@ -130,30 +130,6 @@ bool SDLHostInterface::CreateAudioStream()
return m_audio_stream->Reconfigure(44100, 2);
}
void SDLHostInterface::OpenGameControllers()
{
for (int i = 0; i < SDL_NumJoysticks(); i++)
{
SDL_GameController* gcontroller = SDL_GameControllerOpen(i);
if (gcontroller)
{
Log_InfoPrintf("Opened controller %d: %s", i, SDL_GameControllerName(gcontroller));
m_sdl_controllers.emplace(i, gcontroller);
}
else
{
Log_WarningPrintf("Failed to open controller %d", i);
}
}
}
void SDLHostInterface::CloseGameControllers()
{
for (auto& it : m_sdl_controllers)
SDL_GameControllerClose(it.second);
m_sdl_controllers.clear();
}
void SDLHostInterface::SaveSettings()
{
m_settings.Save(m_settings_filename.c_str());
@ -252,7 +228,6 @@ std::unique_ptr<SDLHostInterface> SDLHostInterface::Create(const char* filename
ImGui::NewFrame();
intf->UpdateSpeedLimiterState();
intf->OpenGameControllers();
const bool boot = (filename != nullptr || exp1_filename != nullptr || save_state_filename != nullptr);
if (boot)
@ -313,28 +288,15 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
case SDL_CONTROLLERDEVICEADDED:
{
auto iter = m_sdl_controllers.find(event->cdevice.which);
if (iter == m_sdl_controllers.end())
{
SDL_GameController* gcontroller = SDL_GameControllerOpen(event->cdevice.which);
if (gcontroller)
{
Log_InfoPrintf("Controller %s inserted", SDL_GameControllerName(gcontroller));
m_sdl_controllers.emplace(event->cdevice.which, gcontroller);
}
}
Log_InfoPrintf("Controller %d inserted", event->cdevice.which);
OpenGameController(event->cdevice.which);
}
break;
case SDL_CONTROLLERDEVICEREMOVED:
{
auto iter = m_sdl_controllers.find(event->cdevice.which);
if (iter != m_sdl_controllers.end())
{
Log_InfoPrintf("Controller %s removed", SDL_GameControllerName(iter->second));
SDL_GameControllerClose(iter->second);
m_sdl_controllers.erase(iter);
}
Log_InfoPrintf("Controller %d removed", event->cdevice.which);
CloseGameController(event->cdevice.which);
}
break;
@ -562,6 +524,61 @@ bool SDLHostInterface::HandleSDLKeyEventForController(const SDL_Event* event)
return false;
}
bool SDLHostInterface::OpenGameController(int index)
{
if (m_sdl_controllers.find(index) != m_sdl_controllers.end())
CloseGameController(index);
SDL_GameController* gcontroller = SDL_GameControllerOpen(index);
if (!gcontroller)
{
Log_WarningPrintf("Failed to open controller %d", index);
return false;
}
Log_InfoPrintf("Opened controller %d: %s", index, SDL_GameControllerName(gcontroller));
ControllerData cd = {};
cd.controller = gcontroller;
SDL_Joystick* joystick = SDL_GameControllerGetJoystick(gcontroller);
if (joystick)
{
SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joystick);
if (SDL_HapticRumbleSupported(haptic) && SDL_HapticRumbleInit(haptic) == 0)
cd.haptic = haptic;
else
SDL_HapticClose(haptic);
}
if (cd.haptic)
Log_InfoPrintf("Rumble is supported on '%s'", SDL_GameControllerName(gcontroller));
else
Log_WarningPrintf("Rumble is not supported on '%s'", SDL_GameControllerName(gcontroller));
m_sdl_controllers.emplace(index, cd);
return true;
}
void SDLHostInterface::CloseGameControllers()
{
while (!m_sdl_controllers.empty())
CloseGameController(m_sdl_controllers.begin()->first);
}
bool SDLHostInterface::CloseGameController(int index)
{
auto it = m_sdl_controllers.find(index);
if (it == m_sdl_controllers.end())
return false;
if (it->second.haptic)
SDL_HapticClose(it->second.haptic);
SDL_GameControllerClose(it->second.controller);
return true;
}
void SDLHostInterface::UpdateControllerControllerMapping()
{
m_controller_axis_mapping.fill(-1);
@ -667,6 +684,38 @@ void SDLHostInterface::HandleSDLControllerButtonEventForController(const SDL_Eve
controller->SetButtonState(m_controller_button_mapping[ev->cbutton.button], ev->cbutton.state == SDL_PRESSED);
}
void SDLHostInterface::UpdateControllerRumble()
{
for (auto& it : m_sdl_controllers)
{
ControllerData& cd = it.second;
if (!cd.haptic)
continue;
float new_strength = 0.0f;
if (m_system)
{
Controller* controller = m_system->GetController(cd.controller_index);
if (controller)
{
const u32 motor_count = controller->GetVibrationMotorCount();
for (u32 i = 0; i < motor_count; i++)
new_strength = std::max(new_strength, controller->GetVibrationMotorStrength(i));
}
}
if (cd.last_rumble_strength == new_strength)
continue;
if (new_strength > 0.01f)
SDL_HapticRumblePlay(cd.haptic, new_strength, 100000);
else
SDL_HapticRumbleStop(cd.haptic);
cd.last_rumble_strength = new_strength;
}
}
void SDLHostInterface::DrawImGui()
{
DrawMainMenuBar();
@ -1118,7 +1167,8 @@ void SDLHostInterface::DrawSettingsWindow()
ImGui::Text("Controller:");
ImGui::SameLine(indent);
int controller_type = static_cast<int>((i == 0) ? m_settings.controller_1_type : m_settings.controller_2_type);
int controller_type =
static_cast<int>((i == 0) ? m_settings.controller_1_type : m_settings.controller_2_type);
if (ImGui::Combo(
"##controller_type", &controller_type,
[](void*, int index, const char** out_text) {
@ -1542,6 +1592,8 @@ void SDLHostInterface::Run()
}
}
UpdateControllerRumble();
// rendering
{
DrawImGui();

View file

@ -55,6 +55,14 @@ private:
using KeyboardControllerActionMap = std::array<s32, static_cast<int>(KeyboardControllerAction::Count)>;
struct ControllerData
{
SDL_GameController* controller;
SDL_Haptic* haptic;
u32 controller_index;
float last_rumble_strength;
};
static constexpr u32 NUM_QUICK_SAVE_STATES = 10;
static constexpr char RESUME_SAVESTATE_FILENAME[] = "savestate_resume.bin";
@ -73,9 +81,6 @@ private:
void CreateImGuiContext();
bool CreateAudioStream();
void OpenGameControllers();
void CloseGameControllers();
void SaveSettings();
void QueueSwitchGPURenderer();
@ -104,9 +109,13 @@ private:
void UpdateKeyboardControllerMapping();
bool HandleSDLKeyEventForController(const SDL_Event* event);
bool OpenGameController(int index);
bool CloseGameController(int index);
void CloseGameControllers();
void UpdateControllerControllerMapping();
void HandleSDLControllerAxisEventForController(const SDL_Event* event);
void HandleSDLControllerButtonEventForController(const SDL_Event* event);
void UpdateControllerRumble();
void DrawMainMenuBar();
void DrawQuickSettingsMenu();
@ -124,7 +133,7 @@ private:
KeyboardControllerActionMap m_keyboard_button_mapping;
std::map<int, SDL_GameController*> m_sdl_controllers;
std::map<int, ControllerData> m_sdl_controllers;
std::array<s32, SDL_CONTROLLER_AXIS_MAX> m_controller_axis_mapping;
std::array<s32, SDL_CONTROLLER_BUTTON_MAX> m_controller_button_mapping;