1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef BASE_MATH_H
4#define BASE_MATH_H
5
6#include <algorithm>
7#include <cmath>
8#include <concepts>
9#include <cstdlib>
10
11template<typename T>
12concept Numeric = std::integral<T> || std::floating_point<T>;
13
14constexpr float pi = 3.1415926535897932384626433f;
15constexpr float normalized_golden_angle = 137.50776f / 360.0f;
16
17constexpr int round_to_int(float f)
18{
19 return f > 0 ? (int)(f + 0.5f) : (int)(f - 0.5f);
20}
21
22constexpr int round_truncate(float f)
23{
24 return (int)f;
25}
26
27template<typename T, typename TB>
28constexpr T mix(const T a, const T b, TB amount)
29{
30 return a + (b - a) * amount;
31}
32
33template<typename T, typename TB>
34constexpr T bezier(const T p0, const T p1, const T p2, const T p3, TB amount)
35{
36 // De-Casteljau Algorithm
37 const T c10 = mix(p0, p1, amount);
38 const T c11 = mix(p1, p2, amount);
39 const T c12 = mix(p2, p3, amount);
40
41 const T c20 = mix(c10, c11, amount);
42 const T c21 = mix(c11, c12, amount);
43
44 return mix(c20, c21, amount); // c30
45}
46
47template<typename T, typename TB>
48constexpr T mix_polynomial(const TB time[], const T data[], int samples, TB amount, T init)
49{
50 T result = init;
51 for(int i = 0; i < samples; i++)
52 {
53 T term = data[i];
54 for(int j = 0; j < samples; j++)
55 if(j != i)
56 term = term * (amount - time[j]) / TB(time[i] - time[j]);
57 result += term;
58 }
59 return result;
60}
61
62inline float random_float()
63{
64 return rand() / (float)(RAND_MAX);
65}
66
67inline float random_float(float min, float max)
68{
69 return min + random_float() * (max - min);
70}
71
72inline float random_float(float max)
73{
74 return random_float(min: 0.0f, max);
75}
76
77inline float random_angle()
78{
79 return 2.0f * pi * (rand() / std::nextafter(x: (float)RAND_MAX, y: std::numeric_limits<float>::max()));
80}
81
82constexpr int fxpscale = 1 << 10;
83
84// float to fixed
85constexpr int f2fx(float v)
86{
87 return round_to_int(f: v * fxpscale);
88}
89constexpr float fx2f(int v)
90{
91 return v / (float)fxpscale;
92}
93
94// int to fixed
95constexpr int i2fx(int v)
96{
97 return v * fxpscale;
98}
99constexpr int fx2i(int v)
100{
101 return v / fxpscale;
102}
103
104class fxp
105{
106 int value;
107
108public:
109 constexpr void set(int v)
110 {
111 value = v;
112 }
113 constexpr int get() const
114 {
115 return value;
116 }
117 constexpr fxp &operator=(int v)
118 {
119 value = i2fx(v);
120 return *this;
121 }
122 constexpr fxp &operator=(float v)
123 {
124 value = f2fx(v);
125 return *this;
126 }
127 constexpr operator int() const
128 {
129 return fx2i(v: value);
130 }
131 constexpr operator float() const
132 {
133 return fx2f(v: value);
134 }
135};
136
137template<Numeric T>
138constexpr T minimum(T a, T b)
139{
140 return std::min(a, b);
141}
142template<Numeric T>
143constexpr T minimum(T a, T b, T c)
144{
145 return std::min(std::min(a, b), c);
146}
147template<Numeric T>
148constexpr T maximum(T a, T b)
149{
150 return std::max(a, b);
151}
152template<Numeric T>
153constexpr T maximum(T a, T b, T c)
154{
155 return std::max(std::max(a, b), c);
156}
157template<typename T>
158constexpr T absolute(T a)
159{
160 return a < T(0) ? -a : a;
161}
162
163template<Numeric T>
164constexpr bool in_range(T a, T lower, T upper)
165{
166 return lower <= a && a <= upper;
167}
168template<Numeric T>
169constexpr bool in_range(T a, T upper)
170{
171 return in_range(a, 0, upper);
172}
173
174#endif // BASE_MATH_H
175