From 6a6025f55783ad4b37a2f79f120a31208919177e Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sun, 27 Sep 2015 00:34:03 +0200 Subject: [PATCH] Implemented force feedback --- src/app/app.cpp | 43 ++++++++++++++++++++++++++++++++++ src/app/app.h | 5 ++++ src/graphics/engine/camera.cpp | 21 +++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/src/app/app.cpp b/src/app/app.cpp index 502e60a4..6186e9b2 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -91,6 +91,8 @@ struct ApplicationPrivate SDL_Joystick *joystick; //! Id of joystick timer SDL_TimerID joystickTimer; + //! Haptic subsystem for the joystick + SDL_Haptic *haptic; ApplicationPrivate() { @@ -100,6 +102,7 @@ struct ApplicationPrivate glcontext = nullptr; joystick = nullptr; joystickTimer = 0; + haptic = nullptr; } }; @@ -516,6 +519,10 @@ bool CApplication::Create() { GetLogger()->Warn("Joystick subsystem init failed\nJoystick(s) will not be available\n"); } + if (SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0) + { + GetLogger()->Warn("Joystick haptic subsystem init failed\nForce feedback will not be available\n"); + } if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0) { @@ -725,6 +732,20 @@ bool CApplication::OpenJoystick() // Create a timer for polling joystick state m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, nullptr); + // Initialize haptic subsystem + m_private->haptic = SDL_HapticOpenFromJoystick(m_private->joystick); + if (m_private->haptic == nullptr) + { + GetLogger()->Warn("Haptic subsystem open failed\n"); + return true; + } + + if (SDL_HapticRumbleInit(m_private->haptic) != 0) + { + GetLogger()->Warn("Haptic rumble effect init failed\n"); + return true; + } + return true; } @@ -734,6 +755,11 @@ void CApplication::CloseJoystick() GetLogger()->Info("Closing joystick\n"); + StopForceFeedbackEffect(); + + SDL_HapticClose(m_private->haptic); + m_private->haptic = nullptr; + SDL_JoystickClose(m_private->joystick); m_private->joystick = nullptr; } @@ -1784,3 +1810,20 @@ void CApplication::SetTextInput(bool textInputEnabled) SDL_StopTextInput(); } } + +void CApplication::PlayForceFeedbackEffect(float strength, int length) +{ + if (m_private->haptic == nullptr) return; + + GetLogger()->Trace("Force feedback! length = %d ms, strength = %.2f\n", length, strength); + if (SDL_HapticRumblePlay(m_private->haptic, strength, length) != 0) + { + GetLogger()->Debug("Failed to play haptic effect\n"); + } +} + +void CApplication::StopForceFeedbackEffect() +{ + if (m_private->haptic == nullptr) return; + SDL_HapticRumbleStop(m_private->haptic); +} diff --git a/src/app/app.h b/src/app/app.h index e8294813..962bf30c 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -314,6 +314,11 @@ public: //! Renders the image in window if needed void RenderIfNeeded(int updateRate); + //! Starts a force feedback effect on the joystick + void PlayForceFeedbackEffect(float strength = 1.0f, int length = 999999); + //! Stops a force feedback effect on the joystick + void StopForceFeedbackEffect(); + protected: //! Creates the window's SDL_Surface bool CreateVideoSurface(); diff --git a/src/graphics/engine/camera.cpp b/src/graphics/engine/camera.cpp index df92d6a8..400b256b 100644 --- a/src/graphics/engine/camera.cpp +++ b/src/graphics/engine/camera.cpp @@ -570,6 +570,8 @@ void CCamera::FlushEffect() m_effectForce = 0.0f; m_effectProgress = 0.0f; m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); + + CApplication::GetInstancePointer()->StopForceFeedbackEffect(); } void CCamera::StartEffect(CameraEffect effect, Math::Vector pos, float force) @@ -655,6 +657,25 @@ void CCamera::EffectFrame(const Event &event) force *= 1.0f-dist; m_effectOffset *= force; + float forceFeedback = force; + if (m_effectType == CAM_EFFECT_VIBRATION) + { + forceFeedback *= 0.5f; + } + if (m_effectType == CAM_EFFECT_PET) + { + forceFeedback *= 0.75f; + } + if (m_effectType == CAM_EFFECT_EXPLO) + { + forceFeedback *= 3.0f; + } + if (forceFeedback > 1.0f) forceFeedback = 1.0f; + if (forceFeedback >= 0.1f) + { + CApplication::GetInstancePointer()->PlayForceFeedbackEffect(forceFeedback); + } + if (m_effectProgress >= 1.0f) FlushEffect(); }