1 | // tFundamentals.h  |
2 | //  |
3 | // Core math functions needed by the rest or of the module as well as for external use. Functions include trigonometric  |
4 | // functions, intervals, angle manipulation, power functions, and other analytic functions.  |
5 | //  |
6 | // Copyright (c) 2004, 2017, 2019, 2020 Tristan Grimmer.  |
7 | // Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby  |
8 | // granted, provided that the above copyright notice and this permission notice appear in all copies.  |
9 | //  |
10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL  |
11 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,  |
12 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  |
13 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR  |
14 | // PERFORMANCE OF THIS SOFTWARE.  |
15 |   |
16 | #pragma once  |
17 | #include <math.h>  |
18 | #include <functional>  |
19 | #include "Foundation/tPlatform.h"  |
20 | #include "Foundation/tConstants.h"  |
21 | namespace tMath  |
22 | {  |
23 |   |
24 |   |
25 | enum class tAngleMode  |
26 | {  |
27 | Radians, // Circle divided into 2Pi angle units.  |
28 | Degrees, // Circle divided into 360 angle units.  |
29 | Norm256, // Circle divided into 256 angle units.  |
30 | NormOne, // Circle divided into one angle unit.  |
31 | Default = Radians,  |
32 | };  |
33 |   |
34 |   |
35 | // Interval Notation. When you see [a,b] or (a,b) the square bracket means include the endpoint and the rounded brackets  |
36 | // mean exclude. See http://www.coolmath.com/algebra/07-solving-inequalities/03-interval-notation-01. When a function  |
37 | // takes a bias argument, a Low bias will cause the return value to include the lower extent of the interval and exclude  |
38 | // the high extent. A High bias will exclude the low end and include the high end. As a notational convenience When a  |
39 | // function takes a bias argument, we'll write the interval as [(a,b)] and the table below shows how to interpret it:  |
40 | //  |
41 | // Bias Interval  |
42 | // Full/Outer [a,b]  |
43 | // Low/Left [a,b)  |
44 | // High/Right (a,b]  |
45 | // Center/Inner (a,b)  |
46 | enum class tIntervalBias  |
47 | {  |
48 | Full, Outer = Full,  |
49 | Low, Left = Low,  |
50 | High, Right = High,  |
51 | Center, Inner = Center  |
52 | };  |
53 |   |
54 | // These are handy functions that return appropriate comparison operators when computing biased intervals.  |
55 | std::function<bool(float,float)> tBiasLess(tIntervalBias);  |
56 | std::function<bool(float,float)> tBiasGreater(tIntervalBias);  |
57 |   |
58 | inline int tAbs(int val) { return (val < 0) ? -val : val; }  |
59 | inline float tAbs(float val) { return (val < 0.0f) ? -val : val; }  |
60 | inline double tAbs(double val) { return (val < 0.0) ? -val : val; }  |
61 |   |
62 | // A mathematical modulo. Does not just return remainder like the % operator. i.e. Handles negatives 'properly'.  |
63 | // The & and fmod functions are also here but called more appropriately tRem (for remainder).   |
64 | inline int tMod(int n, int d) { int m = n % d; if (m < 0) m = (d < 0) ? m - d : m + d; return m; }  |
65 | inline float tMod(float n, float d) { float m = fmod(n, d); if (m < 0.0f) m = (d < 0.0f) ? m - d : m + d; return m; }  |
66 | inline int tRem(int n, int d) { return n % d; }  |
67 | inline float tRem(float n, float d) { return fmodf(n, d); }  |
68 |   |
69 | template<typename T> inline T tMin(const T& a, const T& b) { return a < b ? a : b; }  |
70 | template<typename T> inline T tMax(const T& a, const T& b) { return a > b ? a : b; }  |
71 | template<typename T> inline T tMin(const T& a, const T& b, const T& c) { T ab = a < b ? a : b; return ab < c ? ab : c; }  |
72 | template<typename T> inline T tMax(const T& a, const T& b, const T& c) { T ab = a > b ? a : b; return ab > c ? ab : c; }  |
73 | template<typename T> inline T tMin(const T& a, const T& b, const T& c, const T& d) { T ab = a < b ? a : b; T cd = c < d ? c : d; return ab < cd ? ab : cd; }  |
74 | template<typename T> inline T tMax(const T& a, const T& b, const T& c, const T& d) { T ab = a > b ? a : b; T cd = c > d ? c : d; return ab > cd ? ab : cd; }  |
75 | template<typename T> inline T tClamp(T val, T min, T max) { return (val < min) ? min : ((val > max) ? max : val); }  |
76 | template<typename T> inline T tClampMin(T val, T min) { return (val < min) ? min : val; }  |
77 | template<typename T> inline T tClampMax(T val, T max) { return (val > max) ? max : val; }  |
78 | template<typename T> inline T tSaturate(T val) { return (val < T(0)) ? T(0) : ((val > T(1)) ? T(1) : val); }  |
79 | template<typename T> inline bool tInIntervalII(const T val, const T min, const T max) { if ((val >= min) && (val <= max)) return true; return false; } // Implements val E [min, max]  |
80 | template<typename T> inline bool tInIntervalIE(const T val, const T min, const T max) { if ((val >= min) && (val < max)) return true; return false; } // Implements val E [min, max)  |
81 | template<typename T> inline bool tInIntervalEI(const T val, const T min, const T max) { if ((val > min) && (val <= max)) return true; return false; } // Implements val E (min, max]  |
82 | template<typename T> inline bool tInIntervalEE(const T val, const T min, const T max) { if ((val > min) && (val < max)) return true; return false; } // Implements val E (min, max)  |
83 | template<typename T> inline bool tInInterval(const T val, const T min, const T max) /* Returns val E [min, max] */ { return tInIntervalII(val, min, max); }  |
84 | template<typename T> inline bool tInRange(const T val, const T min, const T max) /* Returns val E [min, max] */ { return tInIntervalII(val, min, max); }  |
85 | template<typename T> inline T tSign(T val) { return val < T(0) ? T(-1) : val > T(0) ? T(1) : T(0); }  |
86 | template<typename T> inline T tBinarySign(T val) { return val < T(0) ? T(-1) : T(1); } // Same as Sign but does not return 0 ever. Two return values only.  |
87 | template<typename T> inline bool tIsZero(T a) { return (a == 0); }  |
88 | template<typename T> inline bool tApproxEqual(T a, T b, float e = Epsilon) { return (tAbs(a-b) < e); }  |
89 | template<typename T> inline bool tEquals(T a, T b) { return a == b; }  |
90 | template<typename T> inline bool tNotEqual(T a, T b) { return a != b; }  |
91 |   |
92 | // For the 'ti' versions of the below functions, the 'i' means 'in-place' (ref var). Supports chaining.  |
93 | template<typename T> inline T& tiClamp(T& val, T min, T max) { val = (val < min) ? min : ((val > max) ? max : val); return val; }  |
94 | template<typename T> inline T& tiClampMin(T& val, T min) { val = (val < min) ? min : val; return val; }  |
95 | template<typename T> inline T& tiClampMax(T& val, T max) { val = (val > max) ? max : val; return val; }  |
96 | template<typename T> inline T& tiSaturate(T& val) { val = (val < T(0)) ? T(0) : ((val > T(1)) ? T(1) : val); return val; }  |
97 |   |
98 | struct tDivt { int Quotient; int Remainder; };  |
99 | tDivt tDiv(int numerator, int denominator);  |
100 | struct tDiv32t { int32 Quotient; int32 Remainder; };  |
101 | tDiv32t tDiv32(int32 numerator, int32 denominator);  |
102 | struct tDivU32t { uint32 Quotient; uint32 Remainder; };  |
103 | tDivU32t tDivU32(uint32 numerator, uint32 denominator);  |
104 | struct tDiv64t { int64 Quotient; int64 Remainder; };  |
105 | tDiv64t tDiv64(int64 numerator, int64 denominator);  |
106 | struct tDivU64t { uint64 Quotient; uint64 Remainder; };  |
107 | tDivU64t tDivU64(uint64 numerator, uint64 denominator);  |
108 |   |
109 | // Use this instead of casting to int. The only difference is it rounds instead of truncating and is way faster -- The  |
110 | // FPU stays in rounding mode so pipeline not flushed.  |
111 | inline int tFloatToInt(float val) { return int(val + 0.5f); }  |
112 |   |
113 | // tCeiling and tFloor both need to change the FPU from round mode to truncate. Could have performance hit.  |
114 | inline float tCeiling(float v) { return ceilf(v); }  |
115 | inline float tFloor(float v) { return floorf(v); }  |
116 | inline float tRound(float v) { return floorf(v + 0.5f); }  |
117 |   |
118 | // This round lets you say round to the nearest [value]. For example, tRound(5.17f, 0.2f) = 5.2f  |
119 | float tRound(float v, float nearest);  |
120 |   |
121 | // For the 'ti' versions of the below functions, the 'i' means 'in-place' (ref var). A ref is also returned so it's  |
122 | // easy to chain calls.  |
123 | inline float& tiCeiling(float& v) { v = ceilf(v); return v; }  |
124 | inline float& tiFloor(float& v) { v = floorf(v); return v; }  |
125 | inline float& tiRound(float& v) { v = floorf(v + 0.5f); return v; }  |
126 | inline float& tiRound(float& v, float nearest) { v = tRound(v, nearest); return v; }  |
127 | inline int& tiAbs(int& v) { v = (v < 0) ? -v : v; return v; }  |
128 | inline float& tiAbs(float& v) { v = (v < 0.0f) ? -v : v; return v; }  |
129 | inline double& tiAbs(double& v) { v = (v < 0.0) ? -v : v; return v; }  |
130 |   |
131 | // The following Abs function deserves a little explanation. Some linear algebra texts use the term absolute value and  |
132 | // norm interchangeably. Others suggest that the absolute value of a matrix is the matrix with each component  |
133 | // being the absolute value of the original. This is what the following template function returns -- not the L2 norm  |
134 | // (scalar length).  |
135 | template <typename T> inline T tAbs(T v) { T result; for (int c = 0; c < T::GetNumComponents(); c++) result[c] = tAbs(v[c]); return result; }  |
136 | inline float tFrac(float val) { return tAbs(val - float(int(val))); }  |
137 | inline float tSquare(float v) { return v*v; }  |
138 | inline float tCube(float v) { return v*v*v; }  |
139 | inline float tSqrt(float x) { return sqrtf(x); }  |
140 | float tSqrtFast(float x);  |
141 | inline float tRecipSqrt(float x) { return 1.0f/sqrtf(x); }  |
142 | float tRecipSqrtFast(float x);  |
143 |   |
144 | inline float tDegToRad(float deg) { return deg * Pi / 180.0f; }  |
145 | inline float tRadToDeg(float rad) { return rad * 180.0f / Pi; }  |
146 | inline float tSin(float x) { return sinf(x); }  |
147 | inline float tSinFast(float x); // For x E [0, Pi/2].  |
148 | inline float tCos(float x) { return cosf(x); }  |
149 | inline float tCosFast(float x) /* For x E [0, Pi/2]. */ { float s = tSinFast(x); return tSqrtFast(1.0f - s*s); }  |
150 | inline void tCosSin(float& cos, float& sin, float x);  |
151 | inline void tCosSinFast(float& cos, float& sin, float x); // For x E [0, Pi/2].  |
152 | inline float tTan(float x) { return tanf(x); }  |
153 | inline float tArcSin(float x) { return asinf(x); }  |
154 | inline float tArcCos(float x) { return acosf(x); }  |
155 | inline float tArcTan(float y, float x) /* Order is y, x. Returns angle of a slope (rise/run). */ { return atan2f(y, x); }  |
156 | inline float tArcTan(float m) { return atanf(m); }  |
157 | inline float tExp(float x) { return expf(x); }  |
158 | inline float tLog(float x) /* Natural logarithm. */ { return logf(x); }  |
159 | inline float tSa(float x) /* Unnormalized (sampling) sinc. */ { if (x == 0.0f) return 1.0f; return tSin(x) / x; }  |
160 | inline float tSinc(float x) /* Normalized sinc. */ { if (x == 0.0f) return 1.0f; float pix = Pi*x; return tSin(pix) / pix; }  |
161 |   |
162 | // For the 'ti' versions of the below functions, the 'i' means 'in-place' (ref var).  |
163 | inline float& tiDegToRad(float& ang) { ang = ang * Pi / 180.0f; return ang; }  |
164 | inline float& tiRadToDeg(float& ang) { ang = ang * 180.0f / Pi; return ang; }  |
165 |   |
166 | inline float tPow(float a, float b) { return powf(a, b); }  |
167 | inline double tPow(double a, double b) { return pow(a, b); }  |
168 |   |
169 | // Returns integral base 2 logarithm. If v is <= 0 returns MinInt32. If v is a power of 2 you will get an exact  |
170 | // result. If v is not a power of two it will return the logarithm of the next lowest power of 2. For example,  |
171 | // Log2(2) = 1, Log2(3) = 1, and Log2(4) = 2.  |
172 | inline int tLog2(int v);  |
173 |   |
174 | // For the 'ti' versions of the functions, the 'i' means 'in-place' (ref var).  |
175 | inline bool tIsPower2(int v) { if (v < 1) return false; return (v & (v-1)) ? false : true; }  |
176 | inline uint& tiNextLowerPower2(uint& v) { uint pow2 = 1; while (pow2 < v) pow2 <<= 1; pow2 >>= 1; v = pow2 ? pow2 : 1; return v; }  |
177 | inline uint tNextLowerPower2(uint v) { uint pow2 = 1; while (pow2 < v) pow2 <<= 1; pow2 >>= 1; return pow2 ? pow2 : 1; }  |
178 | inline uint& tiNextHigherPower2(uint& v) { uint pow2 = 1; while (pow2 <= v) pow2 <<= 1; v = pow2; return v; }  |
179 | inline uint tNextHigherPower2(uint v) { uint pow2 = 1; while (pow2 <= v) pow2 <<= 1; return pow2; }  |
180 | inline uint& tiClosestPower2(uint& v) { if (tIsPower2(v)) return v; int h = tNextHigherPower2(v); int l = tNextLowerPower2(v); v = ((h - v) < (v - l)) ? h : l; return v; }  |
181 | inline uint tClosestPower2(uint v) { if (tIsPower2(v)) return v; int h = tNextHigherPower2(v); int l = tNextLowerPower2(v); return ((h - v) < (v - l)) ? h : l; }  |
182 | float& tiNormalizeAngle(float& angle, tIntervalBias = tIntervalBias::Low); // Results in angle E [(-Pi,Pi)].  |
183 | inline float tNormalizedAngle(float angle, tIntervalBias bias = tIntervalBias::Low) { tiNormalizeAngle(angle, bias); return angle; }  |
184 | float& tiNormalizeAngle2Pi(float& angle, tIntervalBias = tIntervalBias::Low); // Results in angle E [(0,2Pi)].  |
185 | inline float tNormalizedAngle2Pi(float angle, tIntervalBias bias = tIntervalBias::Low) { tiNormalizeAngle2Pi(angle, bias); return angle; }  |
186 |   |
187 | // Gets the range (y) value of a normal distribution with mean = 0, and given variance. Pass in the domain (x) value.  |
188 | inline float tNormalDist(float variance, float x) { return tPow(2*Pi*variance, -0.5f) * tExp(-tPow(x, 2.0f) / (2.0f*variance)); }  |
189 |   |
190 | // These functions compute f(x) with x E [0, 1]. When not flipped f(0) = 0 and f(1) = 1. Furthermore, 0 <= f(x) <= 1.  |
191 | // Curve shape may be controlled by one or more constant (c) arguments. These functions always exist in the unit square,  |
192 | // even when flipped. Essentially flipping in x flips around the x=1/2 line, and y about the y=1/2 line.  |
193 | enum tUnitFlip  |
194 | {  |
195 | tUnitFlip_None = 0x00000000,  |
196 | tUnitFlip_X = 0x00000001,  |
197 | tUnitFlip_Y = 0x00000002,  |
198 | tUnitFlip_XY = tUnitFlip_X | tUnitFlip_Y  |
199 | };  |
200 |   |
201 | // Plot: http://www.wolframalpha.com/input/?i=Plot%5B%28Sin%28x*pi-pi%2F2%29%2B1%29%2F2%2C+%7Bx%2C0%2C1%7D%5D  |
202 | float tUnitSin(float x, uint32 = tUnitFlip_None);  |
203 |   |
204 | // Plot: http://www.wolframalpha.com/input/?i=Plot%5BSin%28x*pi%2F2%29%2C+%7Bx%2C0%2C1%7D%5D  |
205 | float tUnitSinHalf(float x, uint32 = tUnitFlip_None);  |
206 |   |
207 | // Plot: http://www.wolframalpha.com/input/?i=Plot%5Bpow%28x%2C+c%29%2C+%7Bx%2C0%2C1%7D%2C+%7Bc%2C0.1%2C3%7D%5D  |
208 | // c E (0, inf). c < 1 pulls towards top left. c > 1 pulls towards bottom right.  |
209 | float tUnitPow(float x, float c = 1.0f, uint32 = tUnitFlip_None);  |
210 |   |
211 | // Plot: http://www.wolframalpha.com/input/?i=Plot+Piecewise%5B%7B%7Bpow%282x%2C+3%29%2F2%2C+x%3C0.5%7D%2C+%7B1+-+%28pow%281-2%28x-1%2F2%29%2C+3%29%29%2F2%2C+x%3E0.5%7D%7D%5D%2C+%7Bx%2C0%2C1%7D  |
212 | float tUnitPowPlateau(float x, float c = 1.0f, uint32 = tUnitFlip_None);  |
213 |   |
214 | // Plot: http://www.wolframalpha.com/input/?i=Plot+sqrt%281+-+%281-x%29%5E2%29%2C+%7Bx%2C0%2C1%7D  |
215 | float tUnitArc(float x, uint32 = tUnitFlip_None);   |
216 |   |
217 |   |
218 | }  |
219 |   |
220 |   |
221 | // Implementation below this line.  |
222 |   |
223 |   |
224 | inline std::function<bool(float,float)> tMath::tBiasLess(tIntervalBias bias)  |
225 | {  |
226 | switch (bias)  |
227 | {  |
228 | case tIntervalBias::Right:  |
229 | case tIntervalBias::Outer:  |
230 | return [](float a, float b) { return a <= b; };  |
231 |   |
232 | case tIntervalBias::Left:  |
233 | case tIntervalBias::Inner:  |
234 | default:  |
235 | return [](float a, float b) { return a < b; };  |
236 | }  |
237 | }  |
238 |   |
239 |   |
240 | inline std::function<bool(float,float)> tMath::tBiasGreater(tIntervalBias bias)  |
241 | {  |
242 | switch (bias)  |
243 | {  |
244 | case tIntervalBias::Left:  |
245 | case tIntervalBias::Outer:  |
246 | return [](float a, float b) { return a >= b; };  |
247 |   |
248 | case tIntervalBias::Right:  |
249 | case tIntervalBias::Inner:  |
250 | default:  |
251 | return [](float a, float b) { return a > b; };  |
252 | }  |
253 | }  |
254 |   |
255 |   |
256 | inline tMath::tDivt tMath::tDiv(int numerator, int denominator)  |
257 | {  |
258 | div_t d = div(numerator, denominator);  |
259 | tDivt r;  |
260 | r.Quotient = d.quot;  |
261 | r.Remainder = d.rem;  |
262 | return r;  |
263 | }  |
264 |   |
265 |   |
266 | inline tMath::tDiv32t tMath::tDiv32(int32 numerator, int32 denominator)  |
267 | {  |
268 | div_t d = div(numerator, denominator);  |
269 | tDiv32t r;  |
270 | r.Quotient = d.quot;  |
271 | r.Remainder = d.rem;  |
272 | return r;  |
273 | }  |
274 |   |
275 |   |
276 | inline tMath::tDivU32t tMath::tDivU32(uint32 numerator, uint32 denominator)  |
277 | {  |
278 | tDivU32t r;  |
279 | r.Quotient = numerator/denominator;  |
280 | r.Remainder = numerator - r.Quotient*denominator;  |
281 | return r;  |
282 | }  |
283 |   |
284 |   |
285 | inline tMath::tDiv64t tMath::tDiv64(int64 numerator, int64 denominator)  |
286 | {  |
287 | lldiv_t d = div(numerator, denominator);  |
288 | tDiv64t r;  |
289 | r.Quotient = d.quot;  |
290 | r.Remainder = d.rem;  |
291 | return r;  |
292 | }  |
293 |   |
294 |   |
295 | inline tMath::tDivU64t tMath::tDivU64(uint64 numerator, uint64 denominator)  |
296 | {  |
297 | tDivU64t r;  |
298 | r.Quotient = numerator/denominator;  |
299 | r.Remainder = numerator - r.Quotient*denominator;  |
300 | return r;  |
301 | }  |
302 |   |
303 |   |
304 | inline float tMath::tRound(float v, float nearest)  |
305 | {  |
306 | if (tApproxEqual(nearest, 0.0f))  |
307 | return v;  |
308 |   |
309 | tiClamp(nearest, 0.000001f, 1000000.0f);  |
310 | float numNearests = v/nearest;  |
311 | float rnded = tRound(numNearests);  |
312 | return rnded * nearest;  |
313 | }  |
314 |   |
315 |   |
316 | inline int tMath::tLog2(int x)  |
317 | {  |
318 | if (x <= 0)  |
319 | return 0x80000000;  |
320 |   |
321 | float f = float(x);  |
322 | return ((( *(uint32*)((void*)&f) ) & 0x7f800000) >> 23) - 127;  |
323 | }  |
324 |   |
325 |   |
326 | inline float tMath::tSqrtFast(float x)  |
327 | {  |
328 | #ifdef PLATFORM_WINDOWS  |
329 | __m128 in = _mm_set_ss(x);  |
330 | __m128 out = _mm_sqrt_ss(in);  |
331 | return *(float*)(&out);  |
332 | #else  |
333 | return tSqrt(x);  |
334 | #endif  |
335 | }  |
336 |   |
337 |   |
338 | inline float tMath::tRecipSqrtFast(float x)  |
339 | {  |
340 | #ifdef PLATFORM_WINDOWS  |
341 | __m128 in = _mm_set_ss(x);  |
342 | __m128 out = _mm_rsqrt_ss(in);  |
343 | return *(float*)(&out);  |
344 | #else  |
345 | return (1.0f / tSqrt(x));  |
346 | #endif  |
347 | }  |
348 |   |
349 |   |
350 | inline float tMath::tSinFast(float x)  |
351 | {  |
352 | float x2 = x*x;  |
353 | float r = 7.61e-03f;  |
354 | r *= x2;  |
355 | r -= 1.6605e-01f;  |
356 | r *= x2;  |
357 | r += 1.0f;  |
358 | r *= x;  |
359 |   |
360 | return r;  |
361 | }  |
362 |   |
363 |   |
364 | inline void tMath::tCosSin(float& c, float& s, float x)  |
365 | {  |
366 | // We can make a faster version by using pythagoras: cos^2 + sin^2 = 1. However, I don't feel like dealing with the negative roots right  |
367 | // now, so it's implemented naively.  |
368 | c = tCos(x);  |
369 | s = tSin(x);  |
370 | }  |
371 |   |
372 |   |
373 | inline void tMath::tCosSinFast(float& c, float& s, float x)  |
374 | {  |
375 | // The fast versions are domain limited so we can use pythagoras without worrying about the negative roots.  |
376 | s = tSinFast(x);  |
377 | c = tSqrtFast(1.0f - s*s);  |
378 | }  |
379 |   |
380 |   |
381 | inline float& tMath::tiNormalizeAngle(float& a, tIntervalBias bias)  |
382 | {  |
383 | std::function<bool(float,float)> less = tBiasLess(bias);  |
384 | std::function<bool(float,float)> greater = tBiasGreater(bias);  |
385 | while (less(a, -Pi)) a += TwoPi;  |
386 | while (greater(a, Pi)) a -= TwoPi;  |
387 | return a;  |
388 | }  |
389 |   |
390 |   |
391 | inline float& tMath::tiNormalizeAngle2Pi(float& a, tIntervalBias bias)  |
392 | {  |
393 | std::function<bool(float,float)> less = tBiasLess(bias);  |
394 | std::function<bool(float,float)> greater = tBiasGreater(bias);  |
395 | while (less(a, 0.0f)) a += TwoPi;  |
396 | while (greater(a, TwoPi)) a -= TwoPi;  |
397 | return a;  |
398 | }  |
399 |   |
400 |   |
401 | inline float tMath::tUnitSin(float x, uint32 flip)  |
402 | {  |
403 | tiClamp(x, 0.0f, 1.0f);  |
404 | x = (flip & tUnitFlip_X) ? 1.0f-x : x;  |
405 | float y = (tSin(x*Pi - PiOver2) + 1.0f)/2.0f;  |
406 | y = (flip & tUnitFlip_Y) ? 1.0f-y : y;  |
407 | return y;  |
408 | }  |
409 |   |
410 |   |
411 | inline float tMath::tUnitSinHalf(float x, uint32 flip)  |
412 | {  |
413 | tiClamp(x, 0.0f, 1.0f);  |
414 | x = (flip & tUnitFlip_X) ? 1.0f-x : x;  |
415 | float y = tSin(x*PiOver2);  |
416 | y = (flip & tUnitFlip_Y) ? 1.0f-y : y;  |
417 | return y;  |
418 | }  |
419 |   |
420 |   |
421 | inline float tMath::tUnitPow(float x, float c, uint32 flip)  |
422 | {  |
423 | tiClamp(x, 0.0f, 1.0f);  |
424 | x = (flip & tUnitFlip_X) ? 1.0f-x : x;  |
425 | float y = tPow(x, c);  |
426 | y = (flip & tUnitFlip_Y) ? 1.0f-y : y;  |
427 | return y;  |
428 | }  |
429 |   |
430 |   |
431 | inline float tMath::tUnitPowPlateau(float x, float c, uint32 flip)  |
432 | {  |
433 | tiClamp(x, 0.0f, 1.0f);  |
434 | x = (flip & tUnitFlip_X) ? 1.0f-x : x;  |
435 |   |
436 | float y = 0.0f;  |
437 | if (x < 0.5f)  |
438 | y = 0.5f*tUnitPow(2.0f*x, c);  |
439 | else  |
440 | y = 0.5f + 0.5f*tUnitPow(2.0f*(x-0.5f), c, tUnitFlip_XY);  |
441 |   |
442 | y = (flip & tUnitFlip_Y) ? 1.0f-y : y;  |
443 | return y;  |
444 | }  |
445 |   |
446 |   |
447 | inline float tMath::tUnitArc(float x, uint32 flip)  |
448 | {  |
449 | tiClamp(x, 0.0f, 1.0f);  |
450 | x = (flip & tUnitFlip_X) ? 1.0f-x : x;  |
451 | float y = tSqrt(1.0f - (1.0f-x)*(1.0f-x));  |
452 | y = (flip & tUnitFlip_Y) ? 1.0f-y : y;  |
453 | return y;  |
454 | }  |
455 | |