123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- /**
- * @file llmath.h
- * @brief Useful math constants and macros.
- *
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #ifndef LLMATH_H
- #define LLMATH_H
- #include <cmath>
- #include <cstdlib>
- #include <limits>
- #include <vector>
- #if !LL_WINDOWS
- # include <stdint.h>
- #endif
- #include "hbintrinsics.h" // Includes appropriate intrinsics headers. HB
- // llsd.cpp uses llisnan() and llsdutil.cpp uses is_approx_equal_fraction(),
- // so these were moved from llmath.h into llcommonmath.h so that llcommon does
- // not depend on llmath. HB
- #include "llcommonmath.h"
- constexpr F32 GRAVITY = -9.8f;
- // Mathematical constants
- constexpr F32 F_PI = 3.1415926535897932384626433832795f;
- constexpr F32 F_TWO_PI = 6.283185307179586476925286766559f;
- constexpr F32 F_PI_BY_TWO = 1.5707963267948966192313216916398f;
- constexpr F32 F_SQRT_TWO_PI = 2.506628274631000502415765284811f;
- constexpr F32 F_E = 2.71828182845904523536f;
- constexpr F32 F_SQRT2 = 1.4142135623730950488016887242097f;
- constexpr F32 F_SQRT3 = 1.73205080756888288657986402541f;
- constexpr F32 OO_SQRT2 = 0.7071067811865475244008443621049f;
- constexpr F32 DEG_TO_RAD = 0.017453292519943295769236907684886f;
- constexpr F32 RAD_TO_DEG = 57.295779513082320876798154814105f;
- constexpr F32 F_LN10 = 2.3025850929940456840179914546844f;
- constexpr F32 OO_LN10 = 0.43429448190325182765112891891661f;
- constexpr F32 F_LN2 = 0.69314718056f;
- constexpr F32 OO_LN2 = 1.4426950408889634073599246810019f;
- constexpr F32 F_APPROXIMATELY_ZERO = 0.00001f;
- constexpr F32 F_ALMOST_ZERO = 0.0001f;
- constexpr F32 F_ALMOST_ONE = 1.f - F_ALMOST_ZERO;
- // Sets the gimballock threshold 0.025 away from +/-90 degrees.
- // Formula: GIMBAL_THRESHOLD = sinf(DEG_TO_RAD * gimbal_threshold_angle);
- constexpr F32 GIMBAL_THRESHOLD = 0.000436f;
- // BUG: Eliminate in favor of F_APPROXIMATELY_ZERO above ?
- constexpr F32 FP_MAG_THRESHOLD = 0.0000001f;
- // *TODO: replace with logic like is_approx_equal
- LL_INLINE bool is_approx_zero(F32 f)
- {
- return -F_APPROXIMATELY_ZERO < f && f < F_APPROXIMATELY_ZERO;
- }
- // These functions work by interpreting sign+exp+mantissa as an unsigned
- // integer.
- // For example:
- // x = <sign>1 <exponent>00000010 <mantissa>00000000000000000000000
- // y = <sign>1 <exponent>00000001 <mantissa>11111111111111111111111
- //
- // interpreted as ints =
- // x = 10000001000000000000000000000000
- // y = 10000000111111111111111111111111
- // which is clearly a different of 1 in the least significant bit.
- // Values with the same exponent can be trivially shown to work.
- //
- // WARNING: Denormals of opposite sign do not work
- // x = <sign>1 <exponent>00000000 <mantissa>00000000000000000000001
- // y = <sign>0 <exponent>00000000 <mantissa>00000000000000000000001
- // Although these values differ by 2 in the LSB, the sign bit makes the int
- // comparison fail.
- //
- // WARNING: NaNs can compare equal
- // There is no special treatment of exceptional values like NaNs
- //
- // WARNING: Infinity is comparable with F32_MAX and negative infinity is
- // comparable with F32_MIN
- LL_INLINE bool is_zero(F32 x)
- {
- return (*(U32*)(&x) & 0x7fffffff) == 0;
- }
- LL_INLINE bool is_approx_equal(F32 x, F32 y)
- {
- constexpr S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02;
- return (std::abs((S32)((U32&)x - (U32&)y)) < COMPARE_MANTISSA_UP_TO_BIT);
- }
- LL_INLINE bool is_approx_equal(F64 x, F64 y)
- {
- constexpr S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02;
- return (std::abs((S32)((U64&)x - (U64&)y)) < COMPARE_MANTISSA_UP_TO_BIT);
- }
- LL_INLINE S32 lltrunc(F32 f)
- {
- return (S32)f;
- }
- LL_INLINE S32 lltrunc(F64 f)
- {
- return (S32)f;
- }
- LL_INLINE S32 llfloor(F32 f)
- {
- return (S32)floorf(f);
- }
- LL_INLINE S32 llceil(F32 f)
- {
- // This could probably be optimized, but this works.
- return (S32)ceilf(f);
- }
- // Does an arithmetic round (0.5 always rounds up)
- LL_INLINE S32 ll_round(F32 val)
- {
- return llfloor(val + 0.5f);
- }
- LL_INLINE F32 ll_round(F32 val, F32 nearest)
- {
- return F32(floorf(val * (1.f / nearest) + 0.5f)) * nearest;
- }
- LL_INLINE F64 ll_round(F64 val, F64 nearest)
- {
- return F64(floor(val * (1.0 / nearest) + 0.5)) * nearest;
- }
- LL_INLINE S32 ll_roundp(F32 val)
- {
- return val + 0.5f;
- }
- LL_INLINE S32 ll_roundp(F64 val)
- {
- return val + 0.5;
- }
- LL_INLINE F32 snap_to_sig_figs(F32 foo, S32 sig_figs)
- {
- // compute the power of ten
- F32 bar = 1.f;
- for (S32 i = 0; i < sig_figs; ++i)
- {
- bar *= 10.f;
- }
- #if 0 // The ll_round() implementation sucks. Do not use it.
- F32 new_foo = (F32)ll_round(foo * bar);
- #else
- F32 sign = (foo > 0.f) ? 1.f : -1.f;
- F32 new_foo = F32(S64(foo * bar + sign * 0.5f));
- new_foo /= bar;
- #endif
- return new_foo;
- }
- LL_INLINE F32 lerp(F32 a, F32 b, F32 u)
- {
- return a + (b - a) * u;
- }
- LL_INLINE F32 ramp(F32 x, F32 a, F32 b)
- {
- return a == b ? 0.f : (a - x) / (a - b);
- }
- LL_INLINE F32 rescale(F32 x, F32 x1, F32 x2, F32 y1, F32 y2)
- {
- return lerp(y1, y2, ramp(x, x1, x2));
- }
- LL_INLINE F32 clamp_rescale(F32 x, F32 x1, F32 x2, F32 y1, F32 y2)
- {
- if (y1 < y2)
- {
- return llclamp(rescale(x, x1, x2, y1, y2), y1, y2);
- }
- return llclamp(rescale(x, x1, x2, y1, y2), y2, y1);
- }
- LL_INLINE F32 cubic_step(F32 x)
- {
- x = llclampf(x);
- return (x * x) * (3.f - 2.f * x);
- }
- // SDK - Renamed this to get_lower_power_two, since this is what this actually
- // does.
- LL_INLINE U32 get_lower_power_two(U32 val, U32 max_power_two)
- {
- if (!max_power_two)
- {
- max_power_two = 1 << 31;
- }
- if (max_power_two & (max_power_two - 1))
- {
- return 0;
- }
- for ( ; val < max_power_two; max_power_two >>= 1) ;
- return max_power_two;
- }
- // Calculate next highest power of two, limited by max_power_two. This is taken
- // from a brilliant little code snipped on:
- // http://acius2.blogspot.fr/2007/11/calculating-next-power-of-2.html
- // Basically we convert the binary to a solid string of 1's with the same
- // number of digits, then add one. We subtract 1 initially to handle the case
- // where the number passed in is actually a power of two.
- // WARNING: this only works with 32 bits integers.
- LL_INLINE U32 get_next_power_two(U32 val, U32 max_power_two)
- {
- if (!max_power_two)
- {
- max_power_two = 1 << 31;
- }
- if (val >= max_power_two)
- {
- return max_power_two;
- }
- --val;
- val = (val >> 1) | val;
- val = (val >> 2) | val;
- val = (val >> 4) | val;
- val = (val >> 8) | val;
- val = (val >> 16) | val;
- return ++val;
- }
- // Get the gaussian value given the linear distance from axis x and guassian
- // value o
- LL_INLINE F32 llgaussian(F32 x, F32 o)
- {
- return 1.f / (F_SQRT_TWO_PI * o) * powf(F_E, - (x * x) / (2 * o * o));
- }
- // This converts a linear value to a SRGB non-linear value. Useful for gamma
- // correction and such.
- LL_INLINE F32 linearToSRGB(F32 val)
- {
- if (val < 0.0031308f)
- {
- return val * 12.92f;
- }
- return 1.055f * powf(val, 1.f / 2.4f) - 0.055f;
- }
- // This converts a linear value to a SRGB non-linear value. Useful for gamma
- // correction and such.
- LL_INLINE F32 sRGBtoLinear(F32 val)
- {
- if (val < 0.04045f)
- {
- constexpr F32 k1 = 1.f / 12.92f;
- return val * k1;
- }
- constexpr F32 k2 = 1.f / 1.055f;
- return powf((val + 0.055f) * k2, 2.4f);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Fast exp
- // Implementation of fast expf() approximation (from a paper by Nicol N.
- // Schraudolph: http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf
- #ifndef LL_BIG_ENDIAN
- # error Unknown endianness. Did you omit to include llpreprocessor.h ?
- #endif
- static union
- {
- double d;
- struct
- {
- #if LL_BIG_ENDIAN
- S32 i, j;
- #else
- S32 j, i;
- #endif
- } n;
- } LLECO; // Not sure what the name means
- #define LL_EXP_A (1048576 * OO_LN2) // Use 1512775 for integer
- #define LL_EXP_C (60801) // This value of C good for -4 < y < 4
- #define LL_FAST_EXP(y) (LLECO.n.i = ll_round(F32(LL_EXP_A*(y))) + (1072693248 - LL_EXP_C), LLECO.d)
- LL_INLINE F32 llfastpow(F32 x, F32 y)
- {
- return (F32)(LL_FAST_EXP(y * logf(x)));
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Include the simd math headers
- #if LL_GNUC
- // gcc v5.0+ spews stupid warnings about "maybe uninitialized" variables
- # pragma GCC diagnostic push
- # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
- #endif
- #include "llsimdtypes.h"
- #include "llquaternion.h"
- #include "llvector4logical.h"
- #include "llvector4a.h"
- #include "llmatrix3a.h"
- #include "llmatrix3.h"
- #include "llquaternion2.h"
- #define LL_INL_INCLUDE
- #include "llvector4a.inl"
- #include "llmatrix3a.inl"
- #include "llquaternion2.inl"
- #undef LL_INL_INCLUDE
- #if LL_GNUC
- # pragma GCC diagnostic pop
- #endif
- #endif // LLMATH_H
|