Move SMaterial std::hash impl to its header
[minetest.git] / irr / include / irrMath.h
blob3a1471a02c9ac6971eda4f8c6dc23cb0e244e88b
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
5 #pragma once
7 #include "irrTypes.h"
8 #include <cmath>
9 #include <cfloat>
10 #include <cstdlib> // for abs() etc.
11 #include <climits> // For INT_MAX / UINT_MAX
12 #include <type_traits>
14 namespace irr
16 namespace core
19 //! Rounding error constant often used when comparing f32 values.
21 const f32 ROUNDING_ERROR_f32 = 0.000001f;
22 const f64 ROUNDING_ERROR_f64 = 0.00000001;
24 #ifdef PI // make sure we don't collide with a define
25 #undef PI
26 #endif
27 //! Constant for PI.
28 const f32 PI = 3.14159265359f;
30 //! Constant for reciprocal of PI.
31 const f32 RECIPROCAL_PI = 1.0f / PI;
33 //! Constant for half of PI.
34 const f32 HALF_PI = PI / 2.0f;
36 #ifdef PI64 // make sure we don't collide with a define
37 #undef PI64
38 #endif
39 //! Constant for 64bit PI.
40 const f64 PI64 = 3.1415926535897932384626433832795028841971693993751;
42 //! Constant for 64bit reciprocal of PI.
43 const f64 RECIPROCAL_PI64 = 1.0 / PI64;
45 //! 32bit Constant for converting from degrees to radians
46 const f32 DEGTORAD = PI / 180.0f;
48 //! 32bit constant for converting from radians to degrees (formally known as GRAD_PI)
49 const f32 RADTODEG = 180.0f / PI;
51 //! 64bit constant for converting from degrees to radians (formally known as GRAD_PI2)
52 const f64 DEGTORAD64 = PI64 / 180.0;
54 //! 64bit constant for converting from radians to degrees
55 const f64 RADTODEG64 = 180.0 / PI64;
57 //! Utility function to convert a radian value to degrees
58 /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X
59 \param radians The radians value to convert to degrees.
61 inline f32 radToDeg(f32 radians)
63 return RADTODEG * radians;
66 //! Utility function to convert a radian value to degrees
67 /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X
68 \param radians The radians value to convert to degrees.
70 inline f64 radToDeg(f64 radians)
72 return RADTODEG64 * radians;
75 //! Utility function to convert a degrees value to radians
76 /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X
77 \param degrees The degrees value to convert to radians.
79 inline f32 degToRad(f32 degrees)
81 return DEGTORAD * degrees;
84 //! Utility function to convert a degrees value to radians
85 /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X
86 \param degrees The degrees value to convert to radians.
88 inline f64 degToRad(f64 degrees)
90 return DEGTORAD64 * degrees;
93 //! returns minimum of two values. Own implementation to get rid of the STL (VS6 problems)
94 template <class T>
95 inline const T &min_(const T &a, const T &b)
97 return a < b ? a : b;
100 //! returns minimum of three values. Own implementation to get rid of the STL (VS6 problems)
101 template <class T>
102 inline const T &min_(const T &a, const T &b, const T &c)
104 return a < b ? min_(a, c) : min_(b, c);
107 //! returns maximum of two values. Own implementation to get rid of the STL (VS6 problems)
108 template <class T>
109 inline const T &max_(const T &a, const T &b)
111 return a < b ? b : a;
114 //! returns maximum of three values. Own implementation to get rid of the STL (VS6 problems)
115 template <class T>
116 inline const T &max_(const T &a, const T &b, const T &c)
118 return a < b ? max_(b, c) : max_(a, c);
121 //! returns abs of two values. Own implementation to get rid of STL (VS6 problems)
122 template <class T>
123 inline T abs_(const T &a)
125 return a < (T)0 ? -a : a;
128 //! returns linear interpolation of a and b with ratio t
129 //! \return: a if t==0, b if t==1, and the linear interpolation else
130 template <class T>
131 inline T lerp(const T &a, const T &b, const f32 t)
133 return (T)(a * (1.f - t)) + (b * t);
136 //! clamps a value between low and high
137 template <class T>
138 inline const T clamp(const T &value, const T &low, const T &high)
140 return min_(max_(value, low), high);
143 //! swaps the content of the passed parameters
144 // Note: We use the same trick as boost and use two template arguments to
145 // avoid ambiguity when swapping objects of an Irrlicht type that has not
146 // it's own swap overload. Otherwise we get conflicts with some compilers
147 // in combination with stl.
148 template <class T1, class T2>
149 inline void swap(T1 &a, T2 &b)
151 T1 c(a);
152 a = b;
153 b = c;
156 template <class T>
157 inline T roundingError();
159 template <>
160 inline f32 roundingError()
162 return ROUNDING_ERROR_f32;
165 template <>
166 inline f64 roundingError()
168 return ROUNDING_ERROR_f64;
171 template <class T>
172 inline T relativeErrorFactor()
174 return 1;
177 template <>
178 inline f32 relativeErrorFactor()
180 return 4;
183 template <>
184 inline f64 relativeErrorFactor()
186 return 8;
189 //! returns if a equals b, for types without rounding errors
190 template <class T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
191 inline bool equals(const T a, const T b)
193 return a == b;
196 //! returns if a equals b, taking possible rounding errors into account
197 template <class T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
198 inline bool equals(const T a, const T b, const T tolerance = roundingError<T>())
200 return std::abs(a - b) <= tolerance;
203 //! returns if a equals b, taking relative error in form of factor
204 //! this particular function does not involve any division.
205 template <class T>
206 inline bool equalsRelative(const T a, const T b, const T factor = relativeErrorFactor<T>())
208 // https://eagergames.wordpress.com/2017/04/01/fast-parallel-lines-and-vectors-test/
210 const T maxi = max_(a, b);
211 const T mini = min_(a, b);
212 const T maxMagnitude = max_(maxi, -mini);
214 return (maxMagnitude * factor + maxi) == (maxMagnitude * factor + mini); // MAD Wise
217 union FloatIntUnion32
219 FloatIntUnion32(float f1 = 0.0f) :
220 f(f1) {}
221 // Portable sign-extraction
222 bool sign() const { return (i >> 31) != 0; }
224 irr::s32 i;
225 irr::f32 f;
228 //! We compare the difference in ULP's (spacing between floating-point numbers, aka ULP=1 means there exists no float between).
229 //\result true when numbers have a ULP <= maxUlpDiff AND have the same sign.
230 inline bool equalsByUlp(f32 a, f32 b, int maxUlpDiff)
232 // Based on the ideas and code from Bruce Dawson on
233 // http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/
234 // When floats are interpreted as integers the two nearest possible float numbers differ just
235 // by one integer number. Also works the other way round, an integer of 1 interpreted as float
236 // is for example the smallest possible float number.
238 const FloatIntUnion32 fa(a);
239 const FloatIntUnion32 fb(b);
241 // Different signs, we could maybe get difference to 0, but so close to 0 using epsilons is better.
242 if (fa.sign() != fb.sign()) {
243 // Check for equality to make sure +0==-0
244 if (fa.i == fb.i)
245 return true;
246 return false;
249 // Find the difference in ULPs.
250 const int ulpsDiff = abs_(fa.i - fb.i);
251 if (ulpsDiff <= maxUlpDiff)
252 return true;
254 return false;
257 //! returns if a equals zero, taking rounding errors into account
258 inline bool iszero(const f64 a, const f64 tolerance = ROUNDING_ERROR_f64)
260 return fabs(a) <= tolerance;
263 //! returns if a equals zero, taking rounding errors into account
264 inline bool iszero(const f32 a, const f32 tolerance = ROUNDING_ERROR_f32)
266 return fabsf(a) <= tolerance;
269 //! returns if a equals not zero, taking rounding errors into account
270 inline bool isnotzero(const f32 a, const f32 tolerance = ROUNDING_ERROR_f32)
272 return fabsf(a) > tolerance;
275 //! returns if a equals zero, taking rounding errors into account
276 inline bool iszero(const s32 a, const s32 tolerance = 0)
278 return (a & 0x7ffffff) <= tolerance;
281 //! returns if a equals zero, taking rounding errors into account
282 inline bool iszero(const u32 a, const u32 tolerance = 0)
284 return a <= tolerance;
287 //! returns if a equals zero, taking rounding errors into account
288 inline bool iszero(const s64 a, const s64 tolerance = 0)
290 return abs_(a) <= tolerance;
293 inline s32 s32_min(s32 a, s32 b)
295 return min_(a, b);
298 inline s32 s32_max(s32 a, s32 b)
300 return max_(a, b);
303 inline s32 s32_clamp(s32 value, s32 low, s32 high)
305 return clamp(value, low, high);
309 float IEEE-754 bit representation
311 0 0x00000000
312 1.0 0x3f800000
313 0.5 0x3f000000
314 3 0x40400000
315 +inf 0x7f800000
316 -inf 0xff800000
317 +NaN 0x7fc00000 or 0x7ff00000
318 in general: number = (sign ? -1:1) * 2^(exponent) * 1.(mantissa bits)
321 typedef union
323 u32 u;
324 s32 s;
325 f32 f;
326 } inttofloat;
328 #define F32_AS_S32(f) (*((s32 *)&(f)))
329 #define F32_AS_U32(f) (*((u32 *)&(f)))
330 #define F32_AS_U32_POINTER(f) (((u32 *)&(f)))
332 #define F32_VALUE_0 0x00000000
333 #define F32_VALUE_1 0x3f800000
335 //! code is taken from IceFPU
336 //! Integer representation of a floating-point value.
337 inline u32 IR(f32 x)
339 inttofloat tmp;
340 tmp.f = x;
341 return tmp.u;
344 //! Floating-point representation of an integer value.
345 inline f32 FR(u32 x)
347 inttofloat tmp;
348 tmp.u = x;
349 return tmp.f;
351 inline f32 FR(s32 x)
353 inttofloat tmp;
354 tmp.s = x;
355 return tmp.f;
358 #define F32_LOWER_0(n) ((n) < 0.0f)
359 #define F32_LOWER_EQUAL_0(n) ((n) <= 0.0f)
360 #define F32_GREATER_0(n) ((n) > 0.0f)
361 #define F32_GREATER_EQUAL_0(n) ((n) >= 0.0f)
362 #define F32_EQUAL_1(n) ((n) == 1.0f)
363 #define F32_EQUAL_0(n) ((n) == 0.0f)
364 #define F32_A_GREATER_B(a, b) ((a) > (b))
366 #ifndef REALINLINE
367 #ifdef _MSC_VER
368 #define REALINLINE __forceinline
369 #else
370 #define REALINLINE inline
371 #endif
372 #endif
374 // NOTE: This is not as exact as the c99/c++11 round function, especially at high numbers starting with 8388609
375 // (only low number which seems to go wrong is 0.49999997 which is rounded to 1)
376 // 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)
377 inline f32 round_(f32 x)
379 return floorf(x + 0.5f);
382 // calculate: sqrt ( x )
383 REALINLINE f32 squareroot(const f32 f)
385 return sqrtf(f);
388 // calculate: sqrt ( x )
389 REALINLINE f64 squareroot(const f64 f)
391 return sqrt(f);
394 // calculate: sqrt ( x )
395 REALINLINE s32 squareroot(const s32 f)
397 return static_cast<s32>(squareroot(static_cast<f32>(f)));
400 // calculate: sqrt ( x )
401 REALINLINE s64 squareroot(const s64 f)
403 return static_cast<s64>(squareroot(static_cast<f64>(f)));
406 // calculate: 1 / sqrt ( x )
407 REALINLINE f64 reciprocal_squareroot(const f64 x)
409 return 1.0 / sqrt(x);
412 // calculate: 1 / sqrtf ( x )
413 REALINLINE f32 reciprocal_squareroot(const f32 f)
415 return 1.f / sqrtf(f);
418 // calculate: 1 / sqrtf( x )
419 REALINLINE s32 reciprocal_squareroot(const s32 x)
421 return static_cast<s32>(reciprocal_squareroot(static_cast<f32>(x)));
424 // calculate: 1 / x
425 REALINLINE f32 reciprocal(const f32 f)
427 return 1.f / f;
430 // calculate: 1 / x
431 REALINLINE f64 reciprocal(const f64 f)
433 return 1.0 / f;
436 // calculate: 1 / x, low precision allowed
437 REALINLINE f32 reciprocal_approxim(const f32 f)
439 return 1.f / f;
442 REALINLINE s32 floor32(f32 x)
444 return (s32)floorf(x);
447 REALINLINE s32 ceil32(f32 x)
449 return (s32)ceilf(x);
452 // NOTE: Please check round_ documentation about some inaccuracies in this compared to standard library round function.
453 REALINLINE s32 round32(f32 x)
455 return (s32)round_(x);
458 inline f32 f32_max3(const f32 a, const f32 b, const f32 c)
460 return a > b ? (a > c ? a : c) : (b > c ? b : c);
463 inline f32 f32_min3(const f32 a, const f32 b, const f32 c)
465 return a < b ? (a < c ? a : c) : (b < c ? b : c);
468 inline f32 fract(f32 x)
470 return x - floorf(x);
473 } // end namespace core
474 } // end namespace irr
476 using irr::core::FR;
477 using irr::core::IR;