1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
#include "RumbleProcessor.h"
#include "ControlScheme.h"
#include "../PreferencesCache.h"
#include "../../nCine/Application.h"
#include "../../nCine/Base/FrameTimer.h"
#include "../../nCine/Input/IInputManager.h"
using namespace nCine;
namespace Jazz2::Input
{
RumbleProcessor::RumbleProcessor()
{
}
RumbleProcessor::~RumbleProcessor()
{
CancelAllEffects();
}
void RumbleProcessor::CancelAllEffects()
{
if (_activeRumble.empty()) {
return;
}
auto& inputManager = theApplication().GetInputManager();
for (std::int32_t j = 0; j < ControlScheme::MaxConnectedGamepads; j++) {
inputManager.joystickRumble(j, 0.0f, 0.0f, 0);
inputManager.joystickRumbleTriggers(j, 0.0f, 0.0f, 0);
}
}
void RumbleProcessor::ExecuteEffect(std::int32_t joyId, const std::shared_ptr<RumbleDescription>& desc)
{
if (PreferencesCache::GamepadRumble == 0) {
return;
}
auto& inputManager = theApplication().GetInputManager();
if (!inputManager.isJoyPresent(joyId)) {
return;
}
for (auto& rumble : _activeRumble) {
if (rumble.JoyId == joyId) {
// Already playing
return;
}
}
_activeRumble.emplace_back(joyId, desc);
}
void RumbleProcessor::OnEndFrame(float timeMult)
{
if (PreferencesCache::GamepadRumble == 0) {
_activeRumble.clear();
return;
}
auto& inputManager = theApplication().GetInputManager();
if (_activeRumble.empty()) {
return;
}
for (std::int32_t j = 0; j < ControlScheme::MaxConnectedGamepads; j++) {
if (!inputManager.isJoyPresent(j)) {
// Allow rumble only for connected gamepads
for (std::size_t i = 0; i < _activeRumble.size(); i++) {
if (_activeRumble[i].JoyId == j) {
// Remove playing effects for disconnected gamepads
_activeRumble.eraseUnordered(i);
i--;
}
}
continue;
}
float gains[4] = {};
float timeLeft = 0.0f;
for (std::size_t i = 0; i < _activeRumble.size(); i++) {
auto& rumble = _activeRumble[i];
if (rumble.JoyId != j) {
continue;
}
std::size_t timelineIndex = 0;
while (timelineIndex < rumble.Desc->_timeline.size() && rumble.Desc->_timeline[timelineIndex].EndTime <= rumble.Progress) {
timelineIndex++;
}
if (timelineIndex >= rumble.Desc->_timeline.size()) {
_activeRumble.eraseUnordered(i);
i--;
continue;
}
auto& t = rumble.Desc->_timeline[timelineIndex];
gains[0] = std::max(gains[0], t.LowFrequency);
gains[1] = std::max(gains[1], t.HighFrequency);
gains[2] = std::max(gains[2], t.LeftTrigger);
gains[3] = std::max(gains[3], t.RightTrigger);
auto& last = rumble.Desc->_timeline[rumble.Desc->_timeline.size() - 1];
float tl = (last.EndTime - rumble.Progress);
timeLeft = std::max(timeLeft, tl);
rumble.Progress += timeMult;
}
if (timeLeft > 0.0f) {
std::uint32_t timeLeftMs = (std::uint32_t)(timeLeft * 1000 * FrameTimer::SecondsPerFrame);
if (timeLeftMs > 10) {
// Reduce gain if weak is selected
if (PreferencesCache::GamepadRumble == 1) {
for (auto& gain : gains) {
gain *= 0.666f;
}
}
if (gains[0] > 0.0f || gains[1] > 0.0f) {
inputManager.joystickRumble(j, gains[0], gains[1], timeLeftMs);
}
if (gains[2] > 0.0f || gains[3] > 0.0f) {
inputManager.joystickRumbleTriggers(j, gains[2], gains[3], timeLeftMs);
}
}
}
}
}
RumbleProcessor::ActiveRumble::ActiveRumble(std::int32_t joyId, std::shared_ptr<RumbleDescription> desc)
: Desc(std::move(desc)), JoyId(joyId), Progress(0.0f)
{
}
}
|