// This code is in the public domain -- castanyo@yahoo.es #pragma once #include "nvcore/nvcore.h" #include "nvcore/Debug.h" // nvDebugCheck #include "nvcore/Utils.h" // max, clamp #include #if NV_OS_WIN32 || NV_OS_XBOX #include // finite, isnan #endif // Set some reasonable defaults. #ifndef NV_USE_ALTIVEC # define NV_USE_ALTIVEC NV_CPU_PPC //# define NV_USE_ALTIVEC defined(__VEC__) #endif #ifndef NV_USE_SSE // 1=SSE, 2=SSE2 # if NV_CPU_X86_64 // x64 always supports at least SSE2 # define NV_USE_SSE 2 # elif NV_CC_MSVC && defined(_M_IX86_FP) // Also on x86 with the /arch:SSE flag in MSVC. # define NV_USE_SSE _M_IX86_FP # elif defined(__SSE2__) # define NV_USE_SSE 2 # elif defined(__SSE__) # define NV_USE_SSE 1 # else // Otherwise we assume no SSE. # define NV_USE_SSE 0 # endif #endif // Internally set NV_USE_SIMD when either altivec or sse is available. #if NV_USE_ALTIVEC && NV_USE_SSE # error "Cannot enable both altivec and sse!" #endif #ifndef PI #define PI float(3.1415926535897932384626433833) #endif #define NV_EPSILON (0.0001f) #define NV_NORMAL_EPSILON (0.001f) /* #define SQ(r) ((r)*(r)) #define SIGN_BITMASK 0x80000000 /// Integer representation of a floating-point value. #define IR(x) ((uint32 &)(x)) /// Absolute integer representation of a floating-point value #define AIR(x) (IR(x) & 0x7fffffff) /// Floating-point representation of an integer value. #define FR(x) ((float&)(x)) /// Integer-based comparison of a floating point value. /// Don't use it blindly, it can be faster or slower than the FPU comparison, depends on the context. #define IS_NEGATIVE_FLOAT(x) (IR(x)&SIGN_BITMASK) */ extern "C" inline double sqrt_assert(const double f) { nvDebugCheck(f >= 0.0f); return sqrt(f); } inline float sqrtf_assert(const float f) { nvDebugCheck(f >= 0.0f); return sqrtf(f); } extern "C" inline double acos_assert(const double f) { nvDebugCheck(f >= -1.0f && f <= 1.0f); return acos(f); } inline float acosf_assert(const float f) { nvDebugCheck(f >= -1.0f && f <= 1.0f); return acosf(f); } extern "C" inline double asin_assert(const double f) { nvDebugCheck(f >= -1.0f && f <= 1.0f); return asin(f); } inline float asinf_assert(const float f) { nvDebugCheck(f >= -1.0f && f <= 1.0f); return asinf(f); } // Replace default functions with asserting ones. #if !NV_CC_MSVC || (NV_CC_MSVC && (_MSC_VER < 1700)) // IC: Apparently this was causing problems in Visual Studio 2012. See Issue 194: https://code.google.com/p/nvidia-texture-tools/issues/detail?id=194 #define sqrt sqrt_assert #define sqrtf sqrtf_assert #define acos acos_assert #define acosf acosf_assert #define asin asin_assert #define asinf asinf_assert #endif #if NV_CC_MSVC NV_FORCEINLINE float log2f(float x) { nvCheck(x >= 0); return logf(x) / logf(2.0f); } NV_FORCEINLINE float exp2f(float x) { return powf(2.0f, x); } #endif namespace nv { inline float toRadian(float degree) { return degree * (PI / 180.0f); } inline float toDegree(float radian) { return radian * (180.0f / PI); } // Robust floating point comparisons: // http://realtimecollisiondetection.net/blog/?p=89 inline bool equal(const float f0, const float f1, const float epsilon = NV_EPSILON) { //return fabs(f0-f1) <= epsilon; return fabs(f0-f1) <= epsilon * max3(1.0f, fabsf(f0), fabsf(f1)); } inline bool isZero(const float f, const float epsilon = NV_EPSILON) { return fabs(f) <= epsilon; } inline bool isFinite(const float f) { #if NV_OS_WIN32 || NV_OS_XBOX return _finite(f) != 0; #elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_NETBSD || NV_OS_OPENBSD || NV_OS_ORBIS return isfinite(f); #elif NV_OS_LINUX return finitef(f); #else # error "isFinite not supported" #endif //return std::isfinite (f); //return finite (f); } inline bool isNan(const float f) { #if NV_OS_WIN32 || NV_OS_XBOX return _isnan(f) != 0; #elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_NETBSD || NV_OS_OPENBSD || NV_OS_ORBIS || NV_OS_LINUX return isnan(f); #else # error "isNan not supported" #endif } inline uint log2(uint32 i) { uint32 value = 0; while( i >>= 1 ) value++; return value; } inline uint log2(uint64 i) { uint64 value = 0; while (i >>= 1) value++; return U32(value); } inline float lerp(float f0, float f1, float t) { const float s = 1.0f - t; return f0 * s + f1 * t; } inline float square(float f) { return f * f; } inline int square(int i) { return i * i; } inline float cube(float f) { return f * f * f; } inline int cube(int i) { return i * i * i; } inline float frac(float f) { return f - floorf(f); } inline float floatRound(float f) { return floorf(f + 0.5f); } // Eliminates negative zeros from a float array. inline void floatCleanup(float * fp, int n) { for (int i = 0; i < n; i++) { //nvDebugCheck(isFinite(fp[i])); union { float f; uint32 i; } x = { fp[i] }; if (x.i == 0x80000000) fp[i] = 0.0f; } } inline float saturate(float f) { return clamp(f, 0.0f, 1.0f); } inline float linearstep(float edge0, float edge1, float x) { // Scale, bias and saturate x to 0..1 range return saturate((x - edge0) / (edge1 - edge0)); } inline float smoothstep(float edge0, float edge1, float x) { x = linearstep(edge0, edge1, x); // Evaluate polynomial return x*x*(3 - 2*x); } inline int sign(float a) { return (a > 0) - (a < 0); //if (a > 0.0f) return 1; //if (a < 0.0f) return -1; //return 0; } union Float754 { unsigned int raw; float value; struct { #if NV_BIG_ENDIAN unsigned int negative:1; unsigned int biasedexponent:8; unsigned int mantissa:23; #else unsigned int mantissa:23; unsigned int biasedexponent:8; unsigned int negative:1; #endif } field; }; // Return the exponent of x ~ Floor(Log2(x)) inline int floatExponent(float x) { Float754 f; f.value = x; return (f.field.biasedexponent - 127); } // FloatRGB9E5 union Float3SE { uint32 v; struct { #if NV_BIG_ENDIAN uint32 e : 5; uint32 zm : 9; uint32 ym : 9; uint32 xm : 9; #else uint32 xm : 9; uint32 ym : 9; uint32 zm : 9; uint32 e : 5; #endif }; }; // FloatR11G11B10 union Float3PK { uint32 v; struct { #if NV_BIG_ENDIAN uint32 ze : 5; uint32 zm : 5; uint32 ye : 5; uint32 ym : 6; uint32 xe : 5; uint32 xm : 6; #else uint32 xm : 6; uint32 xe : 5; uint32 ym : 6; uint32 ye : 5; uint32 zm : 5; uint32 ze : 5; #endif }; }; } // nv