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