]> git.lizzy.rs Git - irrlicht.git/blob - include/irrMath.h
Reduce IrrCompileConfig usage to files that actually need it
[irrlicht.git] / include / irrMath.h
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #ifndef __IRR_MATH_H_INCLUDED__\r
6 #define __IRR_MATH_H_INCLUDED__\r
7 \r
8 #include "irrTypes.h"\r
9 #include <math.h>\r
10 #include <float.h>\r
11 #include <stdlib.h> // for abs() etc.\r
12 #include <limits.h> // For INT_MAX / UINT_MAX\r
13 \r
14 namespace irr\r
15 {\r
16 namespace core\r
17 {\r
18 \r
19         //! Rounding error constant often used when comparing f32 values.\r
20 \r
21         const s32 ROUNDING_ERROR_S32 = 0;\r
22 \r
23         const s64 ROUNDING_ERROR_S64 = 0;\r
24         const f32 ROUNDING_ERROR_f32 = 0.000001f;\r
25         const f64 ROUNDING_ERROR_f64 = 0.00000001;\r
26 \r
27 #ifdef PI // make sure we don't collide with a define\r
28 #undef PI\r
29 #endif\r
30         //! Constant for PI.\r
31         const f32 PI = 3.14159265359f;\r
32 \r
33         //! Constant for reciprocal of PI.\r
34         const f32 RECIPROCAL_PI = 1.0f/PI;\r
35 \r
36         //! Constant for half of PI.\r
37         const f32 HALF_PI = PI/2.0f;\r
38 \r
39 #ifdef PI64 // make sure we don't collide with a define\r
40 #undef PI64\r
41 #endif\r
42         //! Constant for 64bit PI.\r
43         const f64 PI64 = 3.1415926535897932384626433832795028841971693993751;\r
44 \r
45         //! Constant for 64bit reciprocal of PI.\r
46         const f64 RECIPROCAL_PI64 = 1.0/PI64;\r
47 \r
48         //! 32bit Constant for converting from degrees to radians\r
49         const f32 DEGTORAD = PI / 180.0f;\r
50 \r
51         //! 32bit constant for converting from radians to degrees (formally known as GRAD_PI)\r
52         const f32 RADTODEG   = 180.0f / PI;\r
53 \r
54         //! 64bit constant for converting from degrees to radians (formally known as GRAD_PI2)\r
55         const f64 DEGTORAD64 = PI64 / 180.0;\r
56 \r
57         //! 64bit constant for converting from radians to degrees\r
58         const f64 RADTODEG64 = 180.0 / PI64;\r
59 \r
60         //! Utility function to convert a radian value to degrees\r
61         /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X\r
62         \param radians The radians value to convert to degrees.\r
63         */\r
64         inline f32 radToDeg(f32 radians)\r
65         {\r
66                 return RADTODEG * radians;\r
67         }\r
68 \r
69         //! Utility function to convert a radian value to degrees\r
70         /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X\r
71         \param radians The radians value to convert to degrees.\r
72         */\r
73         inline f64 radToDeg(f64 radians)\r
74         {\r
75                 return RADTODEG64 * radians;\r
76         }\r
77 \r
78         //! Utility function to convert a degrees value to radians\r
79         /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X\r
80         \param degrees The degrees value to convert to radians.\r
81         */\r
82         inline f32 degToRad(f32 degrees)\r
83         {\r
84                 return DEGTORAD * degrees;\r
85         }\r
86 \r
87         //! Utility function to convert a degrees value to radians\r
88         /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X\r
89         \param degrees The degrees value to convert to radians.\r
90         */\r
91         inline f64 degToRad(f64 degrees)\r
92         {\r
93                 return DEGTORAD64 * degrees;\r
94         }\r
95 \r
96         //! returns minimum of two values. Own implementation to get rid of the STL (VS6 problems)\r
97         template<class T>\r
98         inline const T& min_(const T& a, const T& b)\r
99         {\r
100                 return a < b ? a : b;\r
101         }\r
102 \r
103         //! returns minimum of three values. Own implementation to get rid of the STL (VS6 problems)\r
104         template<class T>\r
105         inline const T& min_(const T& a, const T& b, const T& c)\r
106         {\r
107                 return a < b ? min_(a, c) : min_(b, c);\r
108         }\r
109 \r
110         //! returns maximum of two values. Own implementation to get rid of the STL (VS6 problems)\r
111         template<class T>\r
112         inline const T& max_(const T& a, const T& b)\r
113         {\r
114                 return a < b ? b : a;\r
115         }\r
116 \r
117         //! returns maximum of three values. Own implementation to get rid of the STL (VS6 problems)\r
118         template<class T>\r
119         inline const T& max_(const T& a, const T& b, const T& c)\r
120         {\r
121                 return a < b ? max_(b, c) : max_(a, c);\r
122         }\r
123 \r
124         //! returns abs of two values. Own implementation to get rid of STL (VS6 problems)\r
125         template<class T>\r
126         inline T abs_(const T& a)\r
127         {\r
128                 return a < (T)0 ? -a : a;\r
129         }\r
130 \r
131         //! returns linear interpolation of a and b with ratio t\r
132         //! \return: a if t==0, b if t==1, and the linear interpolation else\r
133         template<class T>\r
134         inline T lerp(const T& a, const T& b, const f32 t)\r
135         {\r
136                 return (T)(a*(1.f-t)) + (b*t);\r
137         }\r
138 \r
139         //! clamps a value between low and high\r
140         template <class T>\r
141         inline const T clamp (const T& value, const T& low, const T& high)\r
142         {\r
143                 return min_ (max_(value,low), high);\r
144         }\r
145 \r
146         //! swaps the content of the passed parameters\r
147         // Note: We use the same trick as boost and use two template arguments to\r
148         // avoid ambiguity when swapping objects of an Irrlicht type that has not\r
149         // it's own swap overload. Otherwise we get conflicts with some compilers\r
150         // in combination with stl.\r
151         template <class T1, class T2>\r
152         inline void swap(T1& a, T2& b)\r
153         {\r
154                 T1 c(a);\r
155                 a = b;\r
156                 b = c;\r
157         }\r
158 \r
159         template <class T>\r
160         inline T roundingError();\r
161 \r
162         template <>\r
163         inline f32 roundingError()\r
164         {\r
165                 return ROUNDING_ERROR_f32;\r
166         }\r
167 \r
168         template <>\r
169         inline f64 roundingError()\r
170         {\r
171                 return ROUNDING_ERROR_f64;\r
172         }\r
173 \r
174         template <>\r
175         inline s32 roundingError()\r
176         {\r
177                 return ROUNDING_ERROR_S32;\r
178         }\r
179 \r
180         template <>\r
181         inline u32 roundingError()\r
182         {\r
183                 return ROUNDING_ERROR_S32;\r
184         }\r
185 \r
186         template <>\r
187         inline s64 roundingError()\r
188         {\r
189                 return ROUNDING_ERROR_S64;\r
190         }\r
191 \r
192         template <>\r
193         inline u64 roundingError()\r
194         {\r
195                 return ROUNDING_ERROR_S64;\r
196         }\r
197 \r
198         template <class T>\r
199         inline T relativeErrorFactor()\r
200         {\r
201                 return 1;\r
202         }\r
203 \r
204         template <>\r
205         inline f32 relativeErrorFactor()\r
206         {\r
207                 return 4;\r
208         }\r
209 \r
210         template <>\r
211         inline f64 relativeErrorFactor()\r
212         {\r
213                 return 8;\r
214         }\r
215 \r
216         //! returns if a equals b, taking possible rounding errors into account\r
217         template <class T>\r
218         inline bool equals(const T a, const T b, const T tolerance = roundingError<T>())\r
219         {\r
220                 return (a + tolerance >= b) && (a - tolerance <= b);\r
221         }\r
222 \r
223 \r
224         //! returns if a equals b, taking relative error in form of factor\r
225         //! this particular function does not involve any division.\r
226         template <class T>\r
227         inline bool equalsRelative( const T a, const T b, const T factor = relativeErrorFactor<T>())\r
228         {\r
229                 //https://eagergames.wordpress.com/2017/04/01/fast-parallel-lines-and-vectors-test/\r
230 \r
231                 const T maxi = max_( a, b);\r
232                 const T mini = min_( a, b);\r
233                 const T maxMagnitude = max_( maxi, -mini);\r
234 \r
235                 return  (maxMagnitude*factor + maxi) == (maxMagnitude*factor + mini); // MAD Wise\r
236         }\r
237 \r
238         union FloatIntUnion32\r
239         {\r
240                 FloatIntUnion32(float f1 = 0.0f) : f(f1) {}\r
241                 // Portable sign-extraction\r
242                 bool sign() const { return (i >> 31) != 0; }\r
243 \r
244                 irr::s32 i;\r
245                 irr::f32 f;\r
246         };\r
247 \r
248         //! We compare the difference in ULP's (spacing between floating-point numbers, aka ULP=1 means there exists no float between).\r
249         //\result true when numbers have a ULP <= maxUlpDiff AND have the same sign.\r
250         inline bool equalsByUlp(f32 a, f32 b, int maxUlpDiff)\r
251         {\r
252                 // Based on the ideas and code from Bruce Dawson on\r
253                 // http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/\r
254                 // When floats are interpreted as integers the two nearest possible float numbers differ just\r
255                 // by one integer number. Also works the other way round, an integer of 1 interpreted as float\r
256                 // is for example the smallest possible float number.\r
257 \r
258                 const FloatIntUnion32 fa(a);\r
259                 const FloatIntUnion32 fb(b);\r
260 \r
261                 // Different signs, we could maybe get difference to 0, but so close to 0 using epsilons is better.\r
262                 if ( fa.sign() != fb.sign() )\r
263                 {\r
264                         // Check for equality to make sure +0==-0\r
265                         if (fa.i == fb.i)\r
266                                 return true;\r
267                         return false;\r
268                 }\r
269 \r
270                 // Find the difference in ULPs.\r
271                 const int ulpsDiff = abs_(fa.i- fb.i);\r
272                 if (ulpsDiff <= maxUlpDiff)\r
273                         return true;\r
274 \r
275                 return false;\r
276         }\r
277 \r
278         //! returns if a equals zero, taking rounding errors into account\r
279         inline bool iszero(const f64 a, const f64 tolerance = ROUNDING_ERROR_f64)\r
280         {\r
281                 return fabs(a) <= tolerance;\r
282         }\r
283 \r
284         //! returns if a equals zero, taking rounding errors into account\r
285         inline bool iszero(const f32 a, const f32 tolerance = ROUNDING_ERROR_f32)\r
286         {\r
287                 return fabsf(a) <= tolerance;\r
288         }\r
289 \r
290         //! returns if a equals not zero, taking rounding errors into account\r
291         inline bool isnotzero(const f32 a, const f32 tolerance = ROUNDING_ERROR_f32)\r
292         {\r
293                 return fabsf(a) > tolerance;\r
294         }\r
295 \r
296         //! returns if a equals zero, taking rounding errors into account\r
297         inline bool iszero(const s32 a, const s32 tolerance = 0)\r
298         {\r
299                 return ( a & 0x7ffffff ) <= tolerance;\r
300         }\r
301 \r
302         //! returns if a equals zero, taking rounding errors into account\r
303         inline bool iszero(const u32 a, const u32 tolerance = 0)\r
304         {\r
305                 return a <= tolerance;\r
306         }\r
307 \r
308         //! returns if a equals zero, taking rounding errors into account\r
309         inline bool iszero(const s64 a, const s64 tolerance = 0)\r
310         {\r
311                 return abs_(a) <= tolerance;\r
312         }\r
313 \r
314         inline s32 s32_min(s32 a, s32 b)\r
315         {\r
316                 return min_(a, b);\r
317         }\r
318 \r
319         inline s32 s32_max(s32 a, s32 b)\r
320         {\r
321                 return max_(a, b);\r
322         }\r
323 \r
324         inline s32 s32_clamp (s32 value, s32 low, s32 high)\r
325         {\r
326                 return clamp(value, low, high);\r
327         }\r
328 \r
329         /*\r
330                 float IEEE-754 bit representation\r
331 \r
332                 0      0x00000000\r
333                 1.0    0x3f800000\r
334                 0.5    0x3f000000\r
335                 3      0x40400000\r
336                 +inf   0x7f800000\r
337                 -inf   0xff800000\r
338                 +NaN   0x7fc00000 or 0x7ff00000\r
339                 in general: number = (sign ? -1:1) * 2^(exponent) * 1.(mantissa bits)\r
340         */\r
341 \r
342         typedef union { u32 u; s32 s; f32 f; } inttofloat;\r
343 \r
344         #define F32_AS_S32(f)           (*((s32 *) &(f)))\r
345         #define F32_AS_U32(f)           (*((u32 *) &(f)))\r
346         #define F32_AS_U32_POINTER(f)   ( ((u32 *) &(f)))\r
347 \r
348         #define F32_VALUE_0             0x00000000\r
349         #define F32_VALUE_1             0x3f800000\r
350 \r
351         //! code is taken from IceFPU\r
352         //! Integer representation of a floating-point value.\r
353         inline u32 IR(f32 x) {inttofloat tmp; tmp.f=x; return tmp.u;}\r
354 \r
355         //! Floating-point representation of an integer value.\r
356         inline f32 FR(u32 x) {inttofloat tmp; tmp.u=x; return tmp.f;}\r
357         inline f32 FR(s32 x) {inttofloat tmp; tmp.s=x; return tmp.f;}\r
358 \r
359         #define F32_LOWER_0(n)          ((n) <  0.0f)\r
360         #define F32_LOWER_EQUAL_0(n)    ((n) <= 0.0f)\r
361         #define F32_GREATER_0(n)        ((n) >  0.0f)\r
362         #define F32_GREATER_EQUAL_0(n)  ((n) >= 0.0f)\r
363         #define F32_EQUAL_1(n)          ((n) == 1.0f)\r
364         #define F32_EQUAL_0(n)          ((n) == 0.0f)\r
365         #define F32_A_GREATER_B(a,b)    ((a) > (b))\r
366 \r
367 #ifndef REALINLINE\r
368         #ifdef _MSC_VER\r
369                 #define REALINLINE __forceinline\r
370         #else\r
371                 #define REALINLINE inline\r
372         #endif\r
373 #endif\r
374 \r
375 \r
376         // NOTE: This is not as exact as the c99/c++11 round function, especially at high numbers starting with 8388609\r
377         //       (only low number which seems to go wrong is 0.49999997 which is rounded to 1)\r
378         //      Also negative 0.5 is rounded up not down unlike with the standard function (p.E. input -0.5 will be 0 and not -1)\r
379         inline f32 round_( f32 x )\r
380         {\r
381                 return floorf( x + 0.5f );\r
382         }\r
383 \r
384         // calculate: sqrt ( x )\r
385         REALINLINE f32 squareroot(const f32 f)\r
386         {\r
387                 return sqrtf(f);\r
388         }\r
389 \r
390         // calculate: sqrt ( x )\r
391         REALINLINE f64 squareroot(const f64 f)\r
392         {\r
393                 return sqrt(f);\r
394         }\r
395 \r
396         // calculate: sqrt ( x )\r
397         REALINLINE s32 squareroot(const s32 f)\r
398         {\r
399                 return static_cast<s32>(squareroot(static_cast<f32>(f)));\r
400         }\r
401 \r
402         // calculate: sqrt ( x )\r
403         REALINLINE s64 squareroot(const s64 f)\r
404         {\r
405                 return static_cast<s64>(squareroot(static_cast<f64>(f)));\r
406         }\r
407 \r
408         // calculate: 1 / sqrt ( x )\r
409         REALINLINE f64 reciprocal_squareroot(const f64 x)\r
410         {\r
411                 return 1.0 / sqrt(x);\r
412         }\r
413 \r
414         // calculate: 1 / sqrtf ( x )\r
415         REALINLINE f32 reciprocal_squareroot(const f32 f)\r
416         {\r
417                 return 1.f / sqrtf(f);\r
418         }\r
419 \r
420         // calculate: 1 / sqrtf( x )\r
421         REALINLINE s32 reciprocal_squareroot(const s32 x)\r
422         {\r
423                 return static_cast<s32>(reciprocal_squareroot(static_cast<f32>(x)));\r
424         }\r
425 \r
426         // calculate: 1 / x\r
427         REALINLINE f32 reciprocal( const f32 f )\r
428         {\r
429                 return 1.f / f;\r
430         }\r
431 \r
432         // calculate: 1 / x\r
433         REALINLINE f64 reciprocal ( const f64 f )\r
434         {\r
435                 return 1.0 / f;\r
436         }\r
437 \r
438 \r
439         // calculate: 1 / x, low precision allowed\r
440         REALINLINE f32 reciprocal_approxim ( const f32 f )\r
441         {\r
442                 return 1.f / f;\r
443         }\r
444 \r
445         REALINLINE s32 floor32(f32 x)\r
446         {\r
447                 return (s32) floorf ( x );\r
448         }\r
449 \r
450         REALINLINE s32 ceil32 ( f32 x )\r
451         {\r
452                 return (s32) ceilf ( x );\r
453         }\r
454 \r
455         // NOTE: Please check round_ documentation about some inaccuracies in this compared to standard library round function.\r
456         REALINLINE s32 round32(f32 x)\r
457         {\r
458                 return (s32) round_(x);\r
459         }\r
460 \r
461         inline f32 f32_max3(const f32 a, const f32 b, const f32 c)\r
462         {\r
463                 return a > b ? (a > c ? a : c) : (b > c ? b : c);\r
464         }\r
465 \r
466         inline f32 f32_min3(const f32 a, const f32 b, const f32 c)\r
467         {\r
468                 return a < b ? (a < c ? a : c) : (b < c ? b : c);\r
469         }\r
470 \r
471         inline f32 fract ( f32 x )\r
472         {\r
473                 return x - floorf ( x );\r
474         }\r
475 \r
476 } // end namespace core\r
477 } // end namespace irr\r
478 \r
479 using irr::core::IR;\r
480 using irr::core::FR;\r
481 \r
482 #endif\r