metaforce/Runtime/Input/CRumbleVoice.hpp

98 lines
2.8 KiB
C++

#pragma once
#include "RetroTypes.hpp"
namespace urde {
enum class ERumbleFxId {
Zero = 0,
One = 1,
CameraShake = 6,
EscapeSequenceShake = 7,
PlayerBump = 11,
PlayerGunCharge = 12,
PlayerMissileFire = 13,
PlayerGrappleFire = 14,
PlayerLand = 15,
PlayerGrappleSwoosh = 17,
IntroBossProjectile = 19,
Twenty = 20,
TwentyOne = 21,
TwentyTwo = 22,
TwentyThree = 23
};
enum class ERumblePriority { None = 0, One = 1, Two = 2, Three = 3 };
struct SAdsrData {
float x0_attackGain = 0.f;
float x4_autoReleaseDur = 0.f;
float x8_attackDur = 0.f;
float xc_decayDur = 0.f;
float x10_sustainGain = 0.f;
float x14_releaseDur = 0.f;
union {
struct {
bool x18_24_hasSustain : 1;
bool x18_25_autoRelease : 1;
};
u8 dummy = 0;
};
constexpr SAdsrData() noexcept = default;
constexpr SAdsrData(float attackGain, float autoReleaseDur, float attackDur, float decayDur, float sustainGain,
float releaseDur, bool hasSustain, bool autoRelease) noexcept
: x0_attackGain(attackGain)
, x4_autoReleaseDur(autoReleaseDur)
, x8_attackDur(attackDur)
, xc_decayDur(decayDur)
, x10_sustainGain(sustainGain)
, x14_releaseDur(releaseDur) {
x18_24_hasSustain = hasSustain;
x18_25_autoRelease = autoRelease;
}
};
struct SAdsrDelta {
enum class EPhase { Stop, PrePulse, Attack, Decay, Sustain, Release };
float x0_curIntensity = 0.f;
float x4_attackTime = 0.f;
float x8_decayTime = 0.f;
float xc_releaseTime = 0.f;
float x10_autoReleaseTime = 0.f;
float x14_attackIntensity = 0.f;
float x18_sustainIntensity = 0.f;
ERumblePriority x1c_priority;
EPhase x20_phase;
constexpr SAdsrDelta(EPhase phase, ERumblePriority priority) noexcept
: x0_curIntensity(phase == EPhase::PrePulse ? 2.f : 0.f), x1c_priority(priority), x20_phase(phase) {}
constexpr SAdsrDelta(EPhase phase) noexcept : x1c_priority(ERumblePriority::None), x20_phase(phase) {}
static constexpr SAdsrDelta Stopped() noexcept { return SAdsrDelta(EPhase::Stop); }
static constexpr SAdsrDelta Start(ERumblePriority priority, bool prePulse) noexcept {
return SAdsrDelta(prePulse ? EPhase::PrePulse : EPhase::Attack, priority);
}
};
class CRumbleVoice {
std::vector<SAdsrData> x0_datas;
std::vector<SAdsrDelta> x10_deltas;
rstl::reserved_vector<s16, 4> x20_handleIds;
s16 x2c_usedChannels = 0;
u8 x2e_lastId = 0;
bool UpdateChannel(SAdsrDelta& delta, const SAdsrData& data, float dt);
public:
CRumbleVoice();
s16 CreateRumbleHandle(s16 idx);
bool OwnsSustained(s16 id) const;
s16 GetFreeChannel() const;
float GetIntensity() const;
bool Update(float dt);
void HardReset();
s16 Activate(const SAdsrData& data, s16 idx, float gain, ERumblePriority prio);
void Deactivate(s16 id, bool b1);
ERumblePriority GetPriority(s16 idx) const { return x10_deltas[idx].x1c_priority; }
};
} // namespace urde