MathDefs.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. /// \file
  4. #pragma once
  5. #ifdef _MSC_VER
  6. #pragma warning(push)
  7. #pragma warning(disable:4244) // Conversion from 'double' to 'float'
  8. #pragma warning(disable:4702) // unreachable code
  9. #endif
  10. #include "../Math/Random.h"
  11. #include <cstdlib>
  12. #include <cmath>
  13. #include <limits>
  14. #include <type_traits>
  15. namespace Urho3D
  16. {
  17. #undef M_PI
  18. inline constexpr float M_PI = 3.14159265358979323846264338327950288f;
  19. inline constexpr float M_HALF_PI = M_PI * 0.5f;
  20. // TODO: remove this
  21. inline constexpr i32 M_MIN_INT = 0x80000000;
  22. inline constexpr i32 M_MAX_INT = 0x7FFFFFFF;
  23. inline constexpr u32 M_MIN_UNSIGNED = 0x00000000;
  24. inline constexpr u32 M_MAX_UNSIGNED = 0xFFFFFFFF;
  25. inline constexpr i8 M_MIN_I8 = (i8)0x80; // -128
  26. inline constexpr i8 M_MAX_I8 = 0x7F; // 127
  27. inline constexpr u8 M_MIN_U8 = 0x00;
  28. inline constexpr u8 M_MAX_U8 = 0xFF; // 255
  29. inline constexpr i16 M_MIN_I16 = (i16)0x8000; // -32768
  30. inline constexpr i16 M_MAX_I16 = 0x7FFF; // 32767
  31. inline constexpr u16 M_MIN_U16 = 0x0000;
  32. inline constexpr u16 M_MAX_U16 = 0xFFFF; // 65535
  33. inline constexpr i32 M_MIN_I32 = (i32)0x80000000; // -2147483648
  34. inline constexpr i32 M_MAX_I32 = 0x7FFFFFFF; // 2147483647
  35. inline constexpr u32 M_MIN_U32 = 0x00000000;
  36. inline constexpr u32 M_MAX_U32 = 0xFFFFFFFF; // 4294967295
  37. inline constexpr i64 M_MIN_I64 = (i64)0x8000000000000000; // -9223372036854775808
  38. inline constexpr i64 M_MAX_I64 = 0x7FFFFFFFFFFFFFFF; // 9223372036854775807
  39. inline constexpr u64 M_MIN_U64 = 0x0000000000000000;
  40. inline constexpr u64 M_MAX_U64 = 0xFFFFFFFFFFFFFFFF; // 18446744073709551615
  41. inline constexpr i16 M_I16_MASK_ALL_BITS = (i16)0xFFFF; // -1
  42. inline constexpr u16 M_U16_MASK_ALL_BITS = 0xFFFF;
  43. inline constexpr i32 M_I32_MASK_ALL_BITS = (i32)0xFFFFFFFF; // -1
  44. inline constexpr u32 M_U32_MASK_ALL_BITS = 0xFFFFFFFF;
  45. inline constexpr float M_EPSILON = 0.000001f;
  46. inline constexpr float M_LARGE_EPSILON = 0.00005f;
  47. inline constexpr float M_MIN_NEARCLIP = 0.01f;
  48. inline constexpr float M_MAX_FOV = 160.0f;
  49. inline constexpr float M_LARGE_VALUE = 100000000.0f;
  50. inline constexpr float M_INFINITY = std::numeric_limits<float>::infinity();
  51. inline constexpr float M_DEGTORAD = M_PI / 180.0f;
  52. inline constexpr float M_DEGTORAD_2 = M_PI / 360.0f; // M_DEGTORAD / 2.f
  53. inline constexpr float M_RADTODEG = 1.0f / M_DEGTORAD;
  54. /// Intersection test result.
  55. enum Intersection
  56. {
  57. OUTSIDE,
  58. INTERSECTS,
  59. INSIDE
  60. };
  61. /// Check whether two floating point values are equal within accuracy.
  62. /// @specialization{float}
  63. template <class T>
  64. inline bool Equals(T lhs, T rhs) { return lhs + std::numeric_limits<T>::epsilon() >= rhs && lhs - std::numeric_limits<T>::epsilon() <= rhs; }
  65. /// Linear interpolation between two values.
  66. /// @specialization{float,float}
  67. template <class T, class U>
  68. inline T Lerp(T lhs, T rhs, U t) { return lhs * (1.0 - t) + rhs * t; }
  69. /// Inverse linear interpolation between two values.
  70. /// @specialization{float}
  71. template <class T>
  72. inline T InverseLerp(T lhs, T rhs, T x) { return (x - lhs) / (rhs - lhs); }
  73. /// Return the smaller of two values.
  74. /// @specialization{float,float} @specialization{int,int}
  75. template <class T, class U>
  76. inline T Min(T lhs, U rhs) { return lhs < rhs ? lhs : rhs; }
  77. /// Return the larger of two values.
  78. /// @specialization{float,float} @specialization{int,int}
  79. template <class T, class U>
  80. inline T Max(T lhs, U rhs) { return lhs > rhs ? lhs : rhs; }
  81. /// Return absolute value of a value.
  82. /// @specialization{float}
  83. template <class T>
  84. inline T Abs(T value) { return value >= 0.0 ? value : -value; }
  85. /// Return the sign of a float (-1, 0 or 1).
  86. /// @specialization{float}
  87. template <class T>
  88. inline T Sign(T value) { return value > 0.0 ? 1.0 : (value < 0.0 ? -1.0 : 0.0); }
  89. /// Convert degrees to radians.
  90. template <class T>
  91. inline T ToRadians(const T degrees) { return M_DEGTORAD * degrees; }
  92. /// Convert radians to degrees.
  93. template <class T>
  94. inline T ToDegrees(const T radians) { return M_RADTODEG * radians; }
  95. /// Return a representation of the specified floating-point value as a single format bit layout.
  96. inline unsigned FloatToRawIntBits(float value)
  97. {
  98. unsigned u = *((unsigned*)&value);
  99. return u;
  100. }
  101. /// Check whether a floating point value is NaN.
  102. /// @specialization{float} @specialization{double}
  103. template <class T> inline bool IsNaN(T value) { return std::isnan(value); }
  104. /// Check whether a floating point value is positive or negative infinity.
  105. template <class T> inline bool IsInf(T value) { return std::isinf(value); }
  106. /// Clamp a number to a range.
  107. /// @specialization{float} @specialization{int}
  108. template <class T>
  109. inline T Clamp(T value, T min, T max)
  110. {
  111. if (value < min)
  112. return min;
  113. else if (value > max)
  114. return max;
  115. else
  116. return value;
  117. }
  118. /// Smoothly damp between values.
  119. /// @specialization{float}
  120. template <class T>
  121. inline T SmoothStep(T lhs, T rhs, T t)
  122. {
  123. t = Clamp((t - lhs) / (rhs - lhs), T(0.0), T(1.0)); // Saturate t
  124. return t * t * (3.0 - 2.0 * t);
  125. }
  126. /// Return sine of an angle in degrees.
  127. /// @specialization{float}
  128. template <class T> inline T Sin(T angle) { return sin(angle * M_DEGTORAD); }
  129. /// Return cosine of an angle in degrees.
  130. /// @specialization{float}
  131. template <class T> inline T Cos(T angle) { return cos(angle * M_DEGTORAD); }
  132. /// Return tangent of an angle in degrees.
  133. /// @specialization{float}
  134. template <class T> inline T Tan(T angle) { return tan(angle * M_DEGTORAD); }
  135. /// Return arc sine in degrees.
  136. /// @specialization{float}
  137. template <class T> inline T Asin(T x) { return M_RADTODEG * asin(Clamp(x, T(-1.0), T(1.0))); }
  138. /// Return arc cosine in degrees.
  139. /// @specialization{float}
  140. template <class T> inline T Acos(T x) { return M_RADTODEG * acos(Clamp(x, T(-1.0), T(1.0))); }
  141. /// Return arc tangent in degrees.
  142. /// @specialization{float}
  143. template <class T> inline T Atan(T x) { return M_RADTODEG * atan(x); }
  144. /// Return arc tangent of y/x in degrees.
  145. /// @specialization{float}
  146. template <class T> inline T Atan2(T y, T x) { return M_RADTODEG * atan2(y, x); }
  147. /// Return X in power Y.
  148. /// @specialization{float}
  149. template <class T> inline T Pow(T x, T y) { return pow(x, y); }
  150. /// Return natural logarithm of X.
  151. /// @specialization{float}
  152. template <class T> inline T Ln(T x) { return log(x); }
  153. /// Return square root of X.
  154. /// @specialization{float}
  155. template <class T> inline T Sqrt(T x) { return sqrt(x); }
  156. /// Return remainder of X/Y for float values.
  157. template <class T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
  158. inline T Mod(T x, T y) { return fmod(x, y); }
  159. /// Return remainder of X/Y for integer values.
  160. template <class T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
  161. inline T Mod(T x, T y) { return x % y; }
  162. /// Return always positive remainder of X/Y.
  163. template <class T>
  164. inline T AbsMod(T x, T y)
  165. {
  166. const T result = Mod(x, y);
  167. return result < 0 ? result + y : result;
  168. }
  169. /// Return fractional part of passed value in range [0, 1).
  170. /// @specialization{float}
  171. template <class T> inline T Fract(T value) { return value - floor(value); }
  172. /// Round value down.
  173. /// @specialization{float}
  174. template <class T> inline T Floor(T x) { return floor(x); }
  175. /// Round value down. Returns integer value.
  176. /// @specialization{float}
  177. template <class T> inline int FloorToInt(T x) { return static_cast<int>(floor(x)); }
  178. /// Round value to nearest integer.
  179. /// @specialization{float}
  180. template <class T> inline T Round(T x) { return round(x); }
  181. /// Compute average value of the range.
  182. template <class Iterator> inline auto Average(Iterator begin, Iterator end) -> typename std::decay<decltype(*begin)>::type
  183. {
  184. using T = typename std::decay<decltype(*begin)>::type;
  185. T average{};
  186. unsigned size{};
  187. for (Iterator it = begin; it != end; ++it)
  188. {
  189. average += *it;
  190. ++size;
  191. }
  192. return size != 0 ? average / size : average;
  193. }
  194. /// Round value to nearest integer.
  195. /// @specialization{float}
  196. template <class T> inline int RoundToInt(T x) { return static_cast<int>(round(x)); }
  197. /// Round value to nearest multiple.
  198. template <class T> inline T RoundToNearestMultiple(T x, T multiple)
  199. {
  200. T mag = Abs(x);
  201. multiple = Abs(multiple);
  202. T remainder = Mod(mag, multiple);
  203. if (remainder >= multiple / 2)
  204. return (FloorToInt<T>(mag / multiple) * multiple + multiple) * Sign(x);
  205. else
  206. return (FloorToInt<T>(mag / multiple) * multiple) * Sign(x);
  207. }
  208. /// Round value up.
  209. /// @specialization{float}
  210. template <class T> inline T Ceil(T x) { return ceil(x); }
  211. /// Round value up.
  212. /// @specialization{float}
  213. template <class T> inline int CeilToInt(T x) { return static_cast<int>(ceil(x)); }
  214. /// Check whether an unsigned integer is a power of two.
  215. inline bool IsPowerOfTwo(unsigned value)
  216. {
  217. return !(value & (value - 1)) && value;
  218. }
  219. /// Round up to next power of two.
  220. inline unsigned NextPowerOfTwo(unsigned value)
  221. {
  222. // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
  223. --value;
  224. value |= value >> 1u;
  225. value |= value >> 2u;
  226. value |= value >> 4u;
  227. value |= value >> 8u;
  228. value |= value >> 16u;
  229. return ++value;
  230. }
  231. /// Round up or down to the closest power of two.
  232. inline unsigned ClosestPowerOfTwo(unsigned value)
  233. {
  234. const unsigned next = NextPowerOfTwo(value);
  235. const unsigned prev = next >> 1u;
  236. return (value - prev) > (next - value) ? next : prev;
  237. }
  238. /// Return log base two or the MSB position of the given value.
  239. inline unsigned LogBaseTwo(unsigned value)
  240. {
  241. // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
  242. unsigned ret = 0;
  243. while (value >>= 1) // Unroll for more speed...
  244. ++ret;
  245. return ret;
  246. }
  247. /// Count the number of set bits in a mask.
  248. inline i32 CountSetBits(u32 value)
  249. {
  250. // Brian Kernighan's method
  251. i32 count = 0;
  252. for (count = 0; value; count++)
  253. value &= value - 1;
  254. return count;
  255. }
  256. /// Update a hash with the given 8-bit value using the SDBM algorithm.
  257. inline constexpr hash32 SDBMHash(hash32 hash, u8 c) { return c + (hash << 6u) + (hash << 16u) - hash; }
  258. /// Update a hash with the given byte value using the SDBM algorithm.
  259. /// @nobind
  260. inline constexpr hash32 SDBMHash(hash32 hash, byte b) { return SDBMHash(hash, (u8)b); }
  261. /// Return a random float between 0.0 (inclusive) and 1.0 (exclusive).
  262. inline float Random() { return Rand() / 32768.0f; }
  263. /// Return a random float between 0.0 and range, inclusive from both ends.
  264. inline float Random(float range) { return Rand() * range / 32767.0f; }
  265. /// Return a random float between min and max, inclusive from both ends.
  266. inline float Random(float min, float max) { return Rand() * (max - min) / 32767.0f + min; }
  267. /// Return a random integer between 0 and range - 1.
  268. /// @alias{RandomInt}
  269. inline int Random(int range) { return (int)(Random() * range); }
  270. /// Return a random integer between min and max - 1.
  271. /// @alias{RandomInt}
  272. inline int Random(int min, int max) { auto range = (float)(max - min); return (int)(Random() * range) + min; }
  273. /// Return a random normal distributed number with the given mean value and variance.
  274. inline float RandomNormal(float meanValue, float variance) { return RandStandardNormal() * sqrtf(variance) + meanValue; }
  275. /// Convert float to half float. From https://gist.github.com/martinkallman/5049614
  276. inline unsigned short FloatToHalf(float value)
  277. {
  278. unsigned inu = FloatToRawIntBits(value);
  279. unsigned t1 = inu & 0x7fffffffu; // Non-sign bits
  280. unsigned t2 = inu & 0x80000000u; // Sign bit
  281. unsigned t3 = inu & 0x7f800000u; // Exponent
  282. t1 >>= 13; // Align mantissa on MSB
  283. t2 >>= 16; // Shift sign bit into position
  284. t1 -= 0x1c000; // Adjust bias
  285. t1 = (t3 < 0x38800000) ? 0 : t1; // Flush-to-zero
  286. t1 = (t3 > 0x47000000) ? 0x7bff : t1; // Clamp-to-max
  287. t1 = (t3 == 0 ? 0 : t1); // Denormals-as-zero
  288. t1 |= t2; // Re-insert sign bit
  289. return (unsigned short)t1;
  290. }
  291. /// Convert half float to float. From https://gist.github.com/martinkallman/5049614
  292. inline float HalfToFloat(unsigned short value)
  293. {
  294. unsigned t1 = value & 0x7fffu; // Non-sign bits
  295. unsigned t2 = value & 0x8000u; // Sign bit
  296. unsigned t3 = value & 0x7c00u; // Exponent
  297. t1 <<= 13; // Align mantissa on MSB
  298. t2 <<= 16; // Shift sign bit into position
  299. t1 += 0x38000000; // Adjust bias
  300. t1 = (t3 == 0 ? 0 : t1); // Denormals-as-zero
  301. t1 |= t2; // Re-insert sign bit
  302. float out;
  303. *((unsigned*)&out) = t1;
  304. return out;
  305. }
  306. /// Calculate both sine and cosine, with angle in degrees.
  307. URHO3D_API void SinCos(float angle, float& sin, float& cos);
  308. }
  309. #ifdef _MSC_VER
  310. #pragma warning(pop)
  311. #endif