Files
tech5/source/shared/idlib/math/curve.h
T
2026-08-08 19:30:03 -07:00

142 lines
4.6 KiB
C++

#pragma once
#include "angles.h"
#include "vector.h"
#include "../containers/list.h"
template<class type_t>
class alignas(4) idCurve {
public:
idCurve() : times(), values(), currentIndex(-1), changed(true) {}
virtual ~idCurve() = default;
virtual int AddValue(float time, const type_t& value) {
int index = 0;
while (index < times.Num() && times[index] < time) ++index;
times.Insert(time, index);
values.Insert(value, index);
changed = true;
currentIndex = -1;
return index;
}
virtual void RemoveIndex(int index) {
if (index < 0 || index >= times.Num()) return;
times.RemoveIndex(index);
values.RemoveIndex(index);
changed = true;
currentIndex = -1;
}
virtual void Clear() {
times.Clear();
values.Clear();
currentIndex = -1;
changed = true;
}
virtual void SetNumValues(int count) {
times.SetNum(count);
values.SetNum(count);
currentIndex = -1;
changed = true;
}
virtual type_t GetCurrentValue(float time) const {
if (values.Num() == 0) return type_t();
return values[IndexForTime(time)];
}
virtual type_t GetCurrentFirstDerivative(float) const { return type_t(); }
virtual type_t GetCurrentSecondDerivative(float) const { return type_t(); }
virtual bool IsDone(float time) const {
return times.Num() == 0 || time >= times[times.Num() - 1];
}
virtual float GetLengthForTime(float time) const {
return EstimateLengthForTime(time);
}
virtual float EstimateLengthForTime(float) const { return 0.0f; }
int GetNumValues() const { return values.Num(); }
float GetTime(int index) const { return times[index]; }
const type_t& GetValue(int index) const { return values[index]; }
type_t& GetValue(int index) { changed = true; return values[index]; }
void SetTime(int index, float time) { times[index] = time; changed = true; }
void SetValue(int index, const type_t& value) {
values[index] = value;
changed = true;
}
void ShiftTime(float delta) {
for (int index = 0; index < times.Num(); ++index) times[index] += delta;
changed = true;
}
void MakeUniform(float totalTime) {
const int count = times.Num();
if (count <= 1) return;
const float step = totalTime / static_cast<float>(count - 1);
for (int index = 0; index < count; ++index) times[index] = step * index;
changed = true;
}
float MakeUniformMoveSpeed(float totalTime) {
MakeUniform(totalTime);
return totalTime;
}
void SetConstantSpeed(float totalTime) { MakeUniform(totalTime); }
float GetLengthBetweenKnots(int, int) const { return 0.0f; }
float GetTimeForLength(float length, float epsilon = 0.1f) const {
return EstimateTimeForLength(length, epsilon);
}
float EstimateTimeForLength(float length, float) const { return length; }
void GetBatchValues(const float* timesIn, type_t* valuesOut,
type_t* derivativesOut, int count) const {
for (int index = 0; index < count; ++index) {
valuesOut[index] = GetCurrentValue(timesIn[index]);
if (derivativesOut != nullptr) {
derivativesOut[index] = GetCurrentFirstDerivative(timesIn[index]);
}
}
}
idList<float, 116> times;
idList<type_t, 116> values;
mutable int currentIndex;
mutable bool changed;
protected:
virtual idCurve<type_t>* CreateNewCurve() const {
return new idCurve<type_t>();
}
int IndexForTime(float time) const {
if (times.Num() <= 1) return 0;
int low = 0;
int high = times.Num();
while (low < high) {
const int middle = (low + high) / 2;
if (times[middle] <= time) low = middle + 1;
else high = middle;
}
currentIndex = low > 0 ? low - 1 : 0;
return currentIndex;
}
float RombergIntegral(float, float, int) const { return 0.0f; }
};
template<class type_t>
class idCurve_Spline : public idCurve<type_t> {
public:
idCurve_Spline() = default;
~idCurve_Spline() override = default;
};
#if INTPTR_MAX == INT32_MAX
static_assert(sizeof(idCurve<idVec4>) == 44,
"Recovered idCurve<idVec4> ABI changed");
static_assert(sizeof(idCurve<idVec3>) == 44,
"Recovered idCurve<idVec3> ABI changed");
static_assert(sizeof(idCurve<idAngles>) == 44,
"Recovered idCurve<idAngles> ABI changed");
static_assert(sizeof(idCurve<idVec1>) == 44,
"Recovered idCurve<idVec1> ABI changed");
#endif