Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarPeriodicFunction.hpp
blob: cb9e44402f5d2ea17d3d5bf4c4a3c8bd2151563b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#pragma once

#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];
}

}