Files
2026-08-08 19:30:03 -07:00

156 lines
5.7 KiB
C++

#pragma once
#include "vector.h"
#include <cmath>
enum extrapolation_t : int {
EXTRAPOLATION_NONE = 0x01,
EXTRAPOLATION_LINEAR = 0x02,
EXTRAPOLATION_ACCELLINEAR = 0x04,
EXTRAPOLATION_DECELLINEAR = 0x08,
EXTRAPOLATION_ACCELSINE = 0x10,
EXTRAPOLATION_DECELSINE = 0x20,
EXTRAPOLATION_NOSTOP = 0x40
};
template<class T>
class idExtrapolate {
public:
extrapolation_t extrapolationType;
float startTime;
float duration;
T startValue;
T baseSpeed;
T speed;
mutable float currentTime;
mutable T currentValue;
idExtrapolate()
: extrapolationType(EXTRAPOLATION_NONE), startTime(0.0f), duration(0.0f),
startValue(T()), baseSpeed(T()), speed(T()), currentTime(-1.0f),
currentValue(startValue) {
}
void Init(const float newStartTime, const float newDuration,
const T& newStartValue, const T& newBaseSpeed, const T& newSpeed,
const extrapolation_t newType) {
extrapolationType = newType;
startTime = newStartTime;
duration = newDuration;
startValue = newStartValue;
baseSpeed = newBaseSpeed;
speed = newSpeed;
currentTime = -1.0f;
currentValue = startValue;
}
T GetCurrentValue(float time) const {
if (time == currentTime) return currentValue;
currentTime = time;
if (time < startTime) {
currentValue = startValue;
return currentValue;
}
const int type = static_cast<int>(extrapolationType) & ~EXTRAPOLATION_NOSTOP;
if (duration == 0.0f
&& type != EXTRAPOLATION_NONE && type != EXTRAPOLATION_LINEAR) {
currentValue = startValue;
return currentValue;
}
if ((static_cast<int>(extrapolationType) & EXTRAPOLATION_NOSTOP) == 0
&& time > startTime + duration) {
time = startTime + duration;
}
const float elapsed = time - startTime;
const float elapsedSeconds = elapsed * 0.001f;
const float fraction = duration != 0.0f ? elapsed / duration : 0.0f;
switch (type) {
case EXTRAPOLATION_NONE:
currentValue = startValue + baseSpeed * elapsedSeconds;
break;
case EXTRAPOLATION_LINEAR:
currentValue = startValue + (baseSpeed + speed) * elapsedSeconds;
break;
case EXTRAPOLATION_ACCELLINEAR:
currentValue = startValue + baseSpeed * elapsedSeconds
+ speed * (0.5f * fraction * fraction * duration * 0.001f);
break;
case EXTRAPOLATION_DECELLINEAR:
currentValue = startValue + baseSpeed * elapsedSeconds
+ speed * ((-0.5f * fraction * fraction + fraction)
* duration * 0.001f);
break;
case EXTRAPOLATION_ACCELSINE:
currentValue = startValue + baseSpeed * elapsedSeconds
+ speed * ((1.0f - std::cos(fraction * HALF_PI))
* duration * SQRT_HALF * 0.001f);
break;
case EXTRAPOLATION_DECELSINE:
currentValue = startValue + baseSpeed * elapsedSeconds
+ speed * (std::sin(fraction * HALF_PI)
* duration * SQRT_HALF * 0.001f);
break;
default:
currentValue = startValue;
break;
}
return currentValue;
}
T GetCurrentSpeed(const float time) const {
if (time < startTime) return T();
const int type = static_cast<int>(extrapolationType) & ~EXTRAPOLATION_NOSTOP;
if (duration == 0.0f
&& type != EXTRAPOLATION_NONE && type != EXTRAPOLATION_LINEAR) {
return T();
}
if ((static_cast<int>(extrapolationType) & EXTRAPOLATION_NOSTOP) == 0
&& time > startTime + duration) {
return T();
}
const float fraction = duration != 0.0f
? (time - startTime) / duration : 0.0f;
switch (type) {
case EXTRAPOLATION_LINEAR: return baseSpeed + speed;
case EXTRAPOLATION_ACCELLINEAR: return baseSpeed + speed * fraction;
case EXTRAPOLATION_DECELLINEAR: return baseSpeed + speed * (1.0f - fraction);
case EXTRAPOLATION_ACCELSINE:
return baseSpeed + speed * std::sin(fraction * HALF_PI);
case EXTRAPOLATION_DECELSINE:
return baseSpeed + speed * std::cos(fraction * HALF_PI);
case EXTRAPOLATION_NONE:
default: return baseSpeed;
}
}
bool IsDone(const float time) const {
return (static_cast<int>(extrapolationType) & EXTRAPOLATION_NOSTOP) == 0
&& time >= startTime + duration;
}
void SetStartTime(const float value) { startTime = value; currentTime = -1.0f; }
void SetStartValue(const T& value) { startValue = value; currentTime = -1.0f; }
float GetStartTime() const { return startTime; }
float GetEndTime() const { return startTime + duration; }
float GetDuration() const { return duration; }
const T& GetStartValue() const { return startValue; }
const T& GetBaseSpeed() const { return baseSpeed; }
const T& GetSpeed() const { return speed; }
private:
static constexpr float HALF_PI = 1.57079632679489661923f;
static constexpr float SQRT_HALF = 0.70710678118654752440f;
};
static_assert(sizeof(idExtrapolate<float>) == 32,
"Recovered idExtrapolate<float> ABI changed");
static_assert(sizeof(idExtrapolate<idVec3>) == 64,
"Recovered idExtrapolate<idVec3> ABI changed");
static_assert(sizeof(idExtrapolate<idAngles>) == 64,
"Recovered idExtrapolate<idAngles> ABI changed");
static_assert(sizeof(idExtrapolate<idQuat>) == 80,
"Recovered idExtrapolate<idQuat> ABI changed");