diff options
Diffstat (limited to 'source/core/StarPeriodicFunction.hpp')
-rw-r--r-- | source/core/StarPeriodicFunction.hpp | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/source/core/StarPeriodicFunction.hpp b/source/core/StarPeriodicFunction.hpp new file mode 100644 index 0000000..ee74808 --- /dev/null +++ b/source/core/StarPeriodicFunction.hpp @@ -0,0 +1,82 @@ +#ifndef STAR_PERIODIC_FUNCTION_HPP +#define STAR_PERIODIC_FUNCTION_HPP + +#include "StarInterpolation.hpp" +#include "StarRandom.hpp" + +namespace Star { + +// Repeating, periodic function with optional period and magnitude variance. +// Each cycle of the function will randomize the min and max values of the +// function by the magnitude variance, and the period by the period variance. +// Can approximate a randomized sin wave, triangle wave, square wave, etc based +// on the weight operator provided to the value method. +template <typename Float> +class PeriodicFunction { +public: + PeriodicFunction( + Float period = 1, Float min = 0, Float max = 1, Float periodVariance = 0, Float magnitudeVariance = 0); + + void update(Float delta); + + template <typename WeightOperator> + Float value(WeightOperator weightOperator) const; + +private: + Float m_halfPeriod; + Float m_min; + Float m_max; + Float m_halfPeriodVariance; + Float m_magnitudeVariance; + + Float m_timerMax; + Float m_timer; + Float m_source; + Float m_target; + bool m_targetMode; +}; + +template <typename Float> +PeriodicFunction<Float>::PeriodicFunction( + Float period, Float min, Float max, Float periodVariance, Float magnitudeVariance) { + m_halfPeriod = period / 2; + m_min = min; + m_max = max; + m_halfPeriodVariance = periodVariance / 2; + m_magnitudeVariance = magnitudeVariance; + + m_timerMax = m_halfPeriod; + m_timer = 0; + m_source = m_max + Random::randf(-1, 1) * m_magnitudeVariance; + m_target = m_min + Random::randf(-1, 1) * m_magnitudeVariance; + m_targetMode = true; +} + +template <typename Float> +void PeriodicFunction<Float>::update(Float delta) { + m_timer -= delta; + + // Only bring the timer forward once, rather than doing this in a loop. This + // makes the function behave somewhat differently than it would for deltas + // which are greater than the period, but it avoids infinite looping + if (m_timer <= 0.0f) { + m_source = m_target; + m_target = (m_targetMode ? m_max : m_min) + Random::randf(-1, 1) * m_magnitudeVariance; + m_targetMode = !m_targetMode; + m_timerMax = m_halfPeriod + Random::randf(-1, 1) * m_halfPeriodVariance; + m_timer = max(0.0f, m_timer + m_timerMax); + } +} + +template <typename Float> +template <typename WeightOperator> +Float PeriodicFunction<Float>::value(WeightOperator weightOperator) const { + // This is inverted, m_timer goes from m_timerMax to 0 as the value should go + // from m_source to m_target + auto wvec = weightOperator(m_timer / m_timerMax); + return m_target * wvec[0] + m_source * wvec[1]; +} + +} + +#endif |