#pragma once #include "angles.h" #include "vector.h" #include "../containers/list.h" template 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(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 times; idList values; mutable int currentIndex; mutable bool changed; protected: virtual idCurve* CreateNewCurve() const { return new idCurve(); } 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 idCurve_Spline : public idCurve { public: idCurve_Spline() = default; ~idCurve_Spline() override = default; }; #if INTPTR_MAX == INT32_MAX static_assert(sizeof(idCurve) == 44, "Recovered idCurve ABI changed"); static_assert(sizeof(idCurve) == 44, "Recovered idCurve ABI changed"); static_assert(sizeof(idCurve) == 44, "Recovered idCurve ABI changed"); static_assert(sizeof(idCurve) == 44, "Recovered idCurve ABI changed"); #endif