123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708 |
- //
- // FloatConversion.h
- // cocos2d_libs
- //
- // Created by 徐俊杰 on 2020/5/15.
- //
- #ifndef FloatConversion_h
- #define FloatConversion_h
- #include "rparticle/Macros/RParticleMacros.h"
- #include <algorithm>
- #include <cmath>
- #include <limits>
- #include <math.h>
- #if !UNITY_EXTERNAL_TOOL
- //#include "LogAssert.h"
- #endif
- #if defined(SN_TARGET_PS3)
- # include <ppu_intrinsics.h>
- #elif defined(__GNUC__) && defined(__ppc__)
- # include <ppc_intrinsics.h>
- #endif
- #ifndef kPI
- #define kPI 3.14159265358979323846264338327950288419716939937510F
- #endif
- NS_RRP_BEGIN
- const float kBiggestFloatSmallerThanOne = 0.99999994f;
- const double kBiggestDoubleSmallerThanOne = 0.99999999999999989;
- #if defined(_XBOX)
- #define __FSELF __fself
- #elif defined(SN_TARGET_PS3)
- #define __FSELF __fsels
- #endif
- inline float FloatMin(float a, float b)
- {
- #if defined(_XBOX) || defined(SN_TARGET_PS3)
- return __FSELF((a)-(b), b, a);
- #else
- return std::min(a, b);
- #endif
- }
- inline float FloatMax(float a, float b)
- {
- #if defined(_XBOX) || defined(SN_TARGET_PS3)
- return __FSELF((a)-(b), a, b);
- #else
- return std::max(a, b);
- #endif
- }
- inline float Abs (float v)
- {
- #if defined(__ppc__) && (defined(__MWERKS__) || defined(SN_TARGET_PS3))
- return __fabsf(v);
- #elif defined(_XBOX)
- return __fabs(v);
- #else
- return v < 0.0F ? -v : v;
- #endif
- }
- inline double Abs (double v)
- {
- return v < 0.0 ? -v : v;
- }
- inline int Abs (int v)
- {
- return v < 0 ? -v : v;
- }
- // Floor, ceil and round functions.
- //
- // When changing or implementing these functions, make sure the tests in MathTest.cpp
- // still pass.
- //
- // Floor: rounds to the largest integer smaller than or equal to the input parameter.
- // Ceil: rounds to the smallest integer larger than or equal to the input parameter.
- // Round: rounds to the nearest integer. Ties (0.5) are rounded up to the smallest integer
- // larger than or equal to the input parameter.
- // Chop/truncate: use a normal integer cast.
- //
- // Windows:
- // Casts are as fast as a straight fistp on an SSE equipped CPU. This is by far the most common
- // scenario and will result in the best code for most users. fistp will use the rounding mode set
- // in the control register (round to nearest by default), and needs fiddling to work properly.
- // This actually makes code that attempt to use fistp slower than a cast.
- // Unless we want round to nearest, in which case fistp should be the best choice, right? But
- // it is not. The default rounding mode is round to nearest, but in case of a tie (0.5), round to
- // nearest even is used. Thus 0.5 is rounded down to 0, 1.5 is rounded up to 2.
- // Conclusion - fistp is useless without stupid fiddling around that actually makes is slower than
- // an SSE cast.
- //
- // OS X Intel:
- // Needs investigating
- //
- // OS X PowerPC:
- // Needs investigating
- //
- // Xbox 360:
- // Needs investigating
- //
- // PS3:
- // Needs investigating
- //
- // iPhone:
- // Needs investigating
- //
- // Android:
- // Needs investigating
- inline int FloorfToInt (float f)
- {
- DebugAssertIf (f < INT_MIN || f > INT_MAX);
- return f >= 0 ? (int)f : (int)(f - kBiggestFloatSmallerThanOne);
- }
- inline UInt32 FloorfToIntPos (float f)
- {
- DebugAssertIf (f < 0 || f > UINT_MAX);
- return (UInt32)f;
- }
- inline float Floorf (float f)
- {
- // Use std::floor().
- // We are interested in reliable functions that do not lose precision.
- // Casting to int and back to float would not be helpful.
- return floor (f);
- }
- inline double Floord (double f)
- {
- // Use std::floor().
- // We are interested in reliable functions that do not lose precision.
- // Casting to int and back to float would not be helpful.
- return floor (f);
- }
- inline int CeilfToInt (float f)
- {
- DebugAssertIf (f < INT_MIN || f > INT_MAX);
- return f >= 0 ? (int)(f + kBiggestFloatSmallerThanOne) : (int)(f);
- }
- inline UInt32 CeilfToIntPos (float f)
- {
- DebugAssertIf (f < 0 || f > UINT_MAX);
- return (UInt32)(f + kBiggestFloatSmallerThanOne);
- }
- inline float Ceilf (float f)
- {
- // Use std::ceil().
- // We are interested in reliable functions that do not lose precision.
- // Casting to int and back to float would not be helpful.
- return ceil (f);
- }
- inline double Ceild (double f)
- {
- // Use std::ceil().
- // We are interested in reliable functions that do not lose precision.
- // Casting to int and back to float would not be helpful.
- return ceil (f);
- }
- inline int RoundfToInt (float f)
- {
- return FloorfToInt (f + 0.5F);
- }
- inline UInt32 RoundfToIntPos (float f)
- {
- return FloorfToIntPos (f + 0.5F);
- }
- inline float Roundf (float f)
- {
- return Floorf (f + 0.5F);
- }
- inline double Roundf (double f)
- {
- return Floord (f + 0.5);
- }
- /// Fast conversion of float [0...1] to 0 ... 65535
- inline int NormalizedToWord (float f)
- {
- f = FloatMax (f, 0.0F);
- f = FloatMin (f, 1.0F);
- return RoundfToIntPos (f * 65535.0f);
- }
- /// Fast conversion of float [0...1] to 0 ... 65535
- inline float WordToNormalized (int p)
- {
- AssertIf(p < 0 || p > 65535);
- return (float)p / 65535.0F;
- }
- /// Fast conversion of float [0...1] to 0 ... 255
- inline int NormalizedToByte (float f)
- {
- f = FloatMax (f, 0.0F);
- f = FloatMin (f, 1.0F);
- return RoundfToIntPos (f * 255.0f);
- }
- /// Fast conversion of float [0...1] to 0 ... 255
- inline float ByteToNormalized (int p)
- {
- AssertIf(p < 0 || p > 255);
- return (float)p / 255.0F;
- }
- // Returns float remainder for t / length
- inline float Repeat (float t, float length)
- {
- return t - Floorf (t / length) * length;
- }
- // Returns double remainder for t / length
- inline double RepeatD (double t, double length)
- {
- return t - floor (t / length) * length;
- }
- // Returns relative angle on the interval (-pi, pi]
- inline float DeltaAngleRad (float current, float target)
- {
- float delta = Repeat ((target - current), 2 * kPI);
- if (delta > kPI)
- delta -= 2 * kPI;
- return delta;
- }
- // Returns true if the distance between f0 and f1 is smaller than epsilon
- inline bool CompareApproximately (float f0, float f1, float epsilon = 0.000001F)
- {
- float dist = (f0 - f1);
- dist = Abs (dist);
- return dist < epsilon;
- }
- /// CopySignf () returns x with its sign changed to y's.
- inline float CopySignf (float x, float y)
- {
- union
- {
- float f;
- UInt32 i;
- } u, u0, u1;
- u0.f = x; u1.f = y;
- UInt32 a = u0.i;
- UInt32 b = u1.i;
- SInt32 mask = 1 << 31;
- UInt32 sign = b & mask;
- a &= ~mask;
- a |= sign;
-
- u.i = a;
- return u.f;
- }
- inline int CompareFloatRobustSignUtility (float A)
- {
- // The sign bit of a number is the high bit.
- union
- {
- float f;
- int i;
- } u;
- u.f = A;
- return (u.i) & 0x80000000;
- }
- inline bool CompareFloatRobust (float f0, float f1, int maxUlps = 10)
- {
- // After adjusting floats so their representations are lexicographically
- // ordered as twos-complement integers a very small positive number
- // will compare as 'close' to a very small negative number. If this is
- // not desireable, and if you are on a platform that supports
- // subnormals (which is the only place the problem can show up) then
- // you need this check.
- // The check for A == B is because zero and negative zero have different
- // signs but are equal to each other.
- if (CompareFloatRobustSignUtility(f0) != CompareFloatRobustSignUtility(f1))
- return f0 == f1;
-
- union
- {
- float f;
- int i;
- } u0, u1;
- u0.f = f0;
- u1.f = f1;
- int aInt = u0.i;
- // Make aInt lexicographically ordered as a twos-complement int
- if (aInt < 0)
- aInt = 0x80000000 - aInt;
- // Make bInt lexicographically ordered as a twos-complement int
- int bInt = u1.i;
- if (bInt < 0)
- bInt = 0x80000000 - bInt;
-
- // Now we can compare aInt and bInt to find out how far apart A and B
- // are.
- int intDiff = Abs (aInt - bInt);
- if (intDiff <= maxUlps)
- return true;
- return false;
- }
- // Returns the t^2
- template<class T>
- T Sqr (const T& t)
- {
- return t * t;
- }
- #define kDeg2Rad (2.0F * kPI / 360.0F)
- #define kRad2Deg (1.F / kDeg2Rad)
- inline float Deg2Rad (float deg)
- {
- // TODO : should be deg * kDeg2Rad, but can't be changed,
- // because it changes the order of operations and that affects a replay in some RegressionTests
- return deg / 360.0F * 2.0F * kPI;
- }
- inline float Rad2Deg (float rad)
- {
- // TODO : should be rad * kRad2Deg, but can't be changed,
- // because it changes the order of operations and that affects a replay in some RegressionTests
- return rad / 2.0F / kPI * 360.0F;
- }
- inline float Lerp (float from, float to, float t)
- {
- return to * t + from * (1.0F - t);
- }
- inline bool IsNAN (float value)
- {
- #if defined __APPLE_CC__
- return value != value;
- #elif _MSC_VER
- return _isnan(value) != 0;
- #else
- return std::isnan (value);
- #endif
- }
- inline bool IsNAN (double value)
- {
- #if defined __APPLE_CC__
- return value != value;
- #elif _MSC_VER
- return _isnan(value) != 0;
- #else
- return std::isnan (value);
- #endif
- }
- inline bool IsPlusInf(float value) { return value == std::numeric_limits<float>::infinity (); }
- inline bool IsMinusInf(float value) { return value == -std::numeric_limits<float>::infinity (); }
- inline bool IsFinite(const float& value)
- {
- // Returns false if value is NaN or +/- infinity
- UInt32 intval = *reinterpret_cast<const UInt32*>(&value);
- return (intval & 0x7f800000) != 0x7f800000;
- }
- inline bool IsFinite(const double& value)
- {
- // Returns false if value is NaN or +/- infinity
- UInt64 intval = *reinterpret_cast<const UInt64*>(&value);
- return (intval & 0x7ff0000000000000LL) != 0x7ff0000000000000LL;
- }
- inline float InvSqrt (float p) { return 1.0F / sqrt (p); }
- inline float Sqrt (float p) { return sqrt (p); }
- /// - Almost highest precision sqrt
- /// - Returns 0 if value is 0 or -1
- /// inline float FastSqrt (float value)
- /// - Almost highest precision inv sqrt
- /// - if value == 0 or -0 it returns 0.
- /// inline float FastInvSqrt (float value)
- /// - Low precision inv sqrt approximately
- /// - if value == 0 or -0 it returns nan or undefined
- /// inline float FastestInvSqrt (float value)
- #if defined(__ppc__) || defined(SN_TARGET_PS3)
- #if UNITY_WII
- // Copied from <CodeWarrior>\PowerPC_EABI_Support\MSL\MSL_C\PPC_EABI\Include\math_ppc_inlines.h
- // Requires hardware floating to be enabled
- // P.S I've also profiled with function below which uses fabs(x) == 0.0F, it's two times slower than this one
- inline float FastSqrt (float x)
- {
- static const double _half=.5f;
- static const double _three=3.0f;
-
- if(x > 0.0f)
- {
- double xd = (double)x;
- double guess = __frsqrte(xd); /* returns an approximation to */
- guess = _half*guess*(_three - guess*guess*xd); /* now have 12 sig bits */
- guess = _half*guess*(_three - guess*guess*xd); /* now have 24 sig bits */
- return (float)(xd * guess);
- }
- else if (x < 0.0)
- return NAN;
- else
- return x;
- }
- #else
- /// - Accurate to 1 bit precision
- /// - returns zero if x is zero
- inline float FastSqrt (float x)
- {
- const float half = 0.5;
- const float one = 1.0;
- float B, y0, y1;
-
- // This'll NaN if it hits frsqrte. Handle both +0.0 and -0.0
- if (fabs(x) == 0.0F)
- return x;
-
- B = x;
-
- #if defined(__GNUC__) && !defined(SN_TARGET_PS3)
- y0 = __frsqrtes(B);
- #else
- y0 = __frsqrte(B);
- #endif
- // First refinement step
-
- y1 = y0 + half*y0*(one - B*y0*y0);
-
- // Second refinement step -- copy the output of the last step to the input of this step
-
- y0 = y1;
- y1 = y0 + half*y0*(one - B*y0*y0);
-
- // Get sqrt(x) from x * 1/sqrt(x)
- return x * y1;
- }
- #endif
- /// - Accurate to 1 bit precision
- /// - returns zero if f is zero
- inline float FastInvSqrt( float f )
- {
- float result;
- float estimate, estimate2;
- float oneHalf = 0.5f;
- float one = oneHalf + oneHalf;
- //Calculate a 5 bit starting estimate for the reciprocal sqrt
- #if defined(__GNUC__) && !defined(SN_TARGET_PS3)
- estimate = estimate2 = __frsqrtes ( f );
- #else
- estimate = estimate2 = __frsqrte ( f );
- #endif
-
- //if you require less precision, you may reduce the number of loop iterations
- estimate = estimate + oneHalf * estimate * ( one - f * estimate * estimate );
- estimate = estimate + oneHalf * estimate * ( one - f * estimate * estimate );
-
- #if defined(__GNUC__) && !defined(SN_TARGET_PS3)
- result = __fsels( -f, estimate2, estimate );
- #else
- result = __fsel( -f, estimate2, estimate );
- #endif
- return result;
- }
- /// Fast inverse sqrt function
- inline float FastestInvSqrt (float value)
- {
- #if defined (__ppc__) && (defined (__MWERKS__) || defined(SN_TARGET_PS3))
- return (float)__frsqrte (value);
- #elif defined (__ppc__)
- return (float)__frsqrtes(value);
- #else
- return 1.0F / sqrtf (value);
- #endif
- }
- #else
- inline float FastSqrt (float value)
- {
- return sqrtf (value);
- }
- inline float FastInvSqrt( float f )
- {
- // The Newton iteration trick used in FastestInvSqrt is a bit faster on
- // Pentium4 / Windows, but lower precision. Doing two iterations is precise enough,
- // but actually a bit slower.
- if (fabs(f) == 0.0F)
- return f;
- return 1.0F / sqrtf (f);
- }
- inline float FastestInvSqrt( float f )
- {
- union
- {
- float f;
- int i;
- } u;
- float fhalf = 0.5f*f;
- u.f = f;
- int i = u.i;
- i = 0x5f3759df - (i>>1);
- u.i = i;
- f = u.f;
- f = f*(1.5f - fhalf*f*f);
- // f = f*(1.5f - fhalf*f*f); // uncommenting this would be two iterations
- return f;
- }
- #endif
- inline float SqrtImpl (float f)
- {
- #if UNITY_WII || UNITY_FLASH
- return FastSqrt (f);
- #else
- return sqrt (f);
- #endif
- }
- inline float Sin (float f)
- {
- return sinf (f);
- }
- inline float Pow (float f, float f2)
- {
- return powf (f, f2);
- }
- inline float Cos (float f)
- {
- return cosf (f);
- }
- inline float Sign (float f)
- {
- #if defined(_XBOX)
- return __fsel(f, 1.0f, -1.0f);
- #else
- if (f < 0.0F)
- return -1.0F;
- else
- return 1.0;
- #endif
- }
- #if UNITY_EDITOR
- class FloatToHalfConverter
- {
- public:
- FloatToHalfConverter();
-
- void Convert(const float& src, UInt16& dest)
- {
- UInt32 bits = *reinterpret_cast<const UInt32*>(&src);
- UInt8 index = UInt8(bits >> 23);
- UInt32 sign = bits & 0x80000000;
- UInt32 mantissa = bits & 0x007fffff;
- dest = (sign >> 16) | m_ExponentTable[index] | (mantissa >> m_MantissaShift[index]);
- }
-
- private:
- UInt16 m_ExponentTable[256];
- UInt8 m_MantissaShift[256];
- };
- extern FloatToHalfConverter g_FloatToHalf;
- #endif // UNITY_EDITOR
- #if UNITY_SUPPORTS_SSE
- #include "Runtime/Math/Simd/SimdMath.h"
- #define SSE_CONST4(name, val) static const ALIGN16 UInt32 name[4] = { (val), (val), (val), (val) }
- #define CONST_M128I(name) *(const __m128i *)&name
- static ALIGN16 UInt16 source[] = {0,0,0,0,0,0,0,0};
- static ALIGN16 float destination[] = {0.0,0.0,0.0,0.0};
- static void HalfToFloat(UInt16 src, float& dest)
- {
- SSE_CONST4(mask_nosign, 0x7fff);
- SSE_CONST4(smallest_normal, 0x0400);
- SSE_CONST4(infinity, 0x7c00);
- SSE_CONST4(expadjust_normal, (127 - 15) << 23);
- SSE_CONST4(magic_denorm, 113 << 23);
-
- source[0] = src;
- __m128i in = _mm_loadu_si128(reinterpret_cast<const __m128i*>(source));
- __m128i mnosign = CONST_M128I(mask_nosign);
- __m128i eadjust = CONST_M128I(expadjust_normal);
- __m128i smallest = CONST_M128I(smallest_normal);
- __m128i infty = CONST_M128I(infinity);
- __m128i expmant = _mm_and_si128(mnosign, in);
- __m128i justsign = _mm_xor_si128(in, expmant);
- __m128i b_notinfnan = _mm_cmpgt_epi32(infty, expmant);
- __m128i b_isdenorm = _mm_cmpgt_epi32(smallest, expmant);
- __m128i shifted = _mm_slli_epi32(expmant, 13);
- __m128i adj_infnan = _mm_andnot_si128(b_notinfnan, eadjust);
- __m128i adjusted = _mm_add_epi32(eadjust, shifted);
- __m128i den1 = _mm_add_epi32(shifted, CONST_M128I(magic_denorm));
- __m128i adjusted2 = _mm_add_epi32(adjusted, adj_infnan);
- __m128 den2 = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm);
- __m128 adjusted3 = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm));
- __m128 adjusted4 = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2));
- __m128 adjusted5 = _mm_or_ps(adjusted3, adjusted4);
- __m128i sign = _mm_slli_epi32(justsign, 16);
- __m128 out = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));
- _mm_storeu_ps(destination, out);
- dest = destination[0];
- #undef SSE_CONST4
- #undef CONST_M128I
- }
- #else
- static void HalfToFloat(UInt16 src, float& dest)
- {
- // Integer alias
- UInt32& bits = *reinterpret_cast<UInt32*>(&dest);
-
- // Based on Fabian Giesen's public domain half_to_float_fast3
- static const UInt32 magic = { 113 << 23 };
- const float& magicFloat = *reinterpret_cast<const float*>(&magic);
- static const UInt32 shiftedExp = 0x7c00 << 13; // exponent mask after shift
-
- // Mask out sign bit
- bits = src & 0x7fff;
- if (bits)
- {
- // Move exponent + mantissa to correct bits
- bits <<= 13;
- UInt32 exponent = bits & shiftedExp;
- if (exponent == 0)
- {
- // Handle denormal
- bits += magic;
- dest -= magicFloat;
- }
- else if (exponent == shiftedExp) // Inf/NaN
- bits += (255 - 31) << 23;
- else
- bits += (127 - 15) << 23;
- }
-
- // Copy sign bit
- bits |= (src & 0x8000) << 16;
- }
- #endif
- using std::cos;
- using std::pow;
- using std::atan2;
- using std::acos;
- using std::sin;
- using std::sqrt;
- using std::log;
- using std::exp;
- // On non-C99 platforms log2 is not available, so approximate it.
- #if UNITY_WIN || UNITY_XENON || UNITY_ANDROID || UNITY_FLASH || UNITY_WEBGL
- #define kNaturalLogarithm2 0.693147180559945309417
- #define Log2(x) (logf(x) / kNaturalLogarithm2)
- #else
- #define Log2(x) log2f(x)
- #endif
- NS_RRP_END
- #endif /* FloatConversion_h */
|