diff options
Diffstat (limited to 'dep/include/g3dlite/G3D/g3dmath.h')
-rw-r--r-- | dep/include/g3dlite/G3D/g3dmath.h | 633 |
1 files changed, 479 insertions, 154 deletions
diff --git a/dep/include/g3dlite/G3D/g3dmath.h b/dep/include/g3dlite/G3D/g3dmath.h index ecf355157c1..d16214ebb37 100644 --- a/dep/include/g3dlite/G3D/g3dmath.h +++ b/dep/include/g3dlite/G3D/g3dmath.h @@ -1,20 +1,20 @@ /** @file g3dmath.h - + Math util class. - - @maintainer Morgan McGuire, matrix@graphics3d.com + + @maintainer Morgan McGuire, http://graphics.cs.williams.edu @cite highestBit by Jukka Liimatta - + @created 2001-06-02 - @edited 2006-01-16 + @edited 2009-04-07 Copyright 2000-2006, Morgan McGuire. All rights reserved. */ -#ifndef G3DMATH_H -#define G3DMATH_H +#ifndef G3D_g3dmath_h +#define G3D_g3dmath_h #ifdef _MSC_VER // Disable conditional expression is constant, which occurs incorrectly on inlined functions @@ -26,13 +26,22 @@ #include "G3D/platform.h" #include <ctype.h> -#include <string> #include <float.h> #include <limits> +#include <stdlib.h> + +#ifdef _MSC_VER + // Visual Studio is missing inttypes.h +# ifndef PRId64 +# define PRId64 "I64d" +# endif +#else +#include <inttypes.h> +#endif /*These defines enable functionality introduced with the 1999 ISO C **standard. They must be defined before the inclusion of math.h to -**engage them. If optimisation is enabled, these functions will be +**engage them. If optimisation is enabled, these functions will be **inlined. With optimisation switched off, you have to link in the **maths library using -lm. */ @@ -51,20 +60,23 @@ namespace G3D { -#if defined(_MSC_VER) +#ifdef _MSC_VER +inline double __fastcall drand48() { + return ::rand() / double(RAND_MAX); +} #if !defined(_WIN64) /** Win32 implementation of the C99 fast rounding routines. - + @cite routines are Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com> - - Permission to use, copy, modify, distribute, and sell this file for any - purpose is hereby granted without fee, provided that the above copyright + + Permission to use, copy, modify, distribute, and sell this file for any + purpose is hereby granted without fee, provided that the above copyright and this permission notice appear in all copies. No representations are - made about the suitability of this software for any purpose. It is + made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. */ @@ -104,83 +116,50 @@ __inline long int lrintf(float flt) { #endif -const double fuzzyEpsilon = 0.00001; -/** Returns a reference to a static double. +#define fuzzyEpsilon (0.00001f) +/** This value should not be tested against directly, instead G3D::isNan() and G3D::isFinite() will return reliable results. */ -inline const double& inf() { +double inf(); -// We already have <limits> included but -// not using it in older gcc for safe compilations -#if (__GNUC__ == 2) - static const double i = 1.0/sin(0.0); -#else - // double is a standard type and should have infinity - static const double i = std::numeric_limits<double>::infinity(); -#endif - return i; -} - -/** Returns a reference to a static double. - This value should not be tested against directly, instead +/** This value should not be tested against directly, instead G3D::isNan() and G3D::isFinite() will return reliable results. */ -inline const double& nan() { +double nan(); -// We already have <limits> included but -// not using it in older gcc for safe compilations -#if (__GNUC__ == 2) - static const double n = 0.0/sin(0.0); -#else - // double is a standard type and should have quiet NaN - static const double n = std::numeric_limits<double>::quiet_NaN(); -#endif - return n; -} +float finf(); -/** Returns a reference to a static double. Use instead of G3D_PI. */ -inline const double& pi() { - static const double p = 3.1415926535898; - return p; -} +float fnan(); -/** Returns a reference to a static double. Use instead of G3D_HALF_PI. */ -inline const double& halfPi() { - static const double p = 1.5707963267949; - return p; +inline double pi() { + return 3.1415926535898; } -/** Returns a reference to a static double. Use instead of G3D_TWO_PI. */ -inline const double& twoPi() { - static const double p = 6.283185; - return p; +inline double halfPi() { + return 1.57079633; } -/** @def G3D_PI - @deprecated Use G3D::pi() instead. */ -#define G3D_PI (3.1415926535898) -/** @def G3D_HALF_PI - @deprecated Use G3D::halfPi() instead. */ -#define G3D_HALF_PI (1.5707963267949) -/** @def G3D_TWO_PI - @deprecated Use G3D::twoPi() instead. */ -#define G3D_TWO_PI (6.283185) +inline double twoPi() { + return 6.28318531; +} typedef signed char int8; -typedef unsigned char uint8; +typedef unsigned char uint8; typedef short int16; typedef unsigned short uint16; typedef int int32; typedef unsigned int uint32; #ifdef _MSC_EXTENSIONS - typedef __int64 int64; - typedef unsigned __int64 uint64; + typedef __int64 int64; + typedef unsigned __int64 uint64; +#elif ! defined(_MSC_VER) + typedef int64_t int64; + typedef uint64_t uint64; #else - typedef long long int64; - typedef unsigned long long uint64; + typedef long long int64; + typedef unsigned long long uint64; #endif -typedef unsigned int uint; typedef float float32; typedef double float64; @@ -192,6 +171,7 @@ int iCeil(double fValue); Clamps the value to the range [low, hi] (inclusive) */ int iClamp(int val, int low, int hi); +int16 iClamp(int16 val, int16 low, int16 hi); double clamp(double val, double low, double hi); float clamp(float val, float low, float hi); @@ -223,7 +203,8 @@ inline int iSign(float f) { return iSign((double)f); } -/** + +/** Fast round to integer using the lrint routine. Typically 6x faster than casting to integer. */ @@ -231,7 +212,7 @@ inline int iRound(double fValue) { return lrint(fValue); } -/** +/** Fast round to integer using the lrint routine. Typically 6x faster than casting to integer. */ @@ -242,6 +223,7 @@ inline int iRound(float f) { /** Returns a random number uniformly at random between low and hi (inclusive). + @deprecated Use Random::integer */ int iRandom(int low, int hi); @@ -264,6 +246,11 @@ bool isFinite(double x); comparisons against nan return false. */ bool isNaN(double x); +bool isNaN(float x); +inline bool isNaN(int x) { + (void)x; + return false; +} /** Computes x % 3. @@ -271,77 +258,58 @@ bool isNaN(double x); int iMod3(int x); /** - [0, 1] - @deprecated use uniformRandom() - */ -double unitRandom (); - -/** - Uniform random number between low and hi, inclusive. - @deprecated use uniformRandom() - */ -double random(double low, double hi); - -/** - [-1, 1] - @deprecated use uniformRandom() - */ -double symmetricRandom (); - -/** Uniform random number between low and hi, inclusive. [low, hi] + @deprecated + @sa Random::uniform */ float uniformRandom(float low = 0.0f, float hi = 1.0f); /** - Normally distributed random number. + Normally distributed random number. + + @deprecated + @sa Random::gaussian */ float gaussRandom(float mean = 0.0f, float stdev = 1.0f); -#if defined(_MSC_VER) && (_MSC_VER <= 1200) - - /** VC6 lacks std::min and std::max */ - inline double min(double x, double y) { - return std::_cpp_min(x, y); - } - /** VC6 lacks std::min and std::max */ - inline float min(float x, float y) { - return std::_cpp_min(x, y); - } +/** Returns x<sup>5</sup> */ +template <class T> +inline T pow5(T x) { + const T y = x * x; + return y * y * x; +} - /** VC6 lacks std::min and std::max */ - inline int min(int x, int y) { - return std::_cpp_min(x, y); - } - /** VC6 lacks std::min and std::max */ - inline double max(double x, double y) { - return std::_cpp_max(x, y); - } +template <class T> +inline T min(const T& x, const T& y) { + return std::min<T>(x, y); +} - /** VC6 lacks std::min and std::max */ - inline float max(float x, float y) { - return std::_cpp_max(x, y); - } +template <class T> +inline T min(const T& x, const T& y, const T& z) { + return std::min<T>(std::min<T>(x, y), z); +} - /** VC6 lacks std::min and std::max */ - inline int max(int x, int y) { - return std::_cpp_max(x, y); - } +template <class T> +inline T min(const T& x, const T& y, const T& z, const T& w) { + return std::min<T>(std::min<T>(x, y), std::min<T>(z, w)); +} -#else - template <class T> - inline T min(const T& x, const T& y) { - return std::min<T>(x, y); - } +template <class T> +inline T max(const T& x, const T& y) { + return std::max<T>(x, y); +} - template <class T> - inline T max(const T& x, const T& y) { - return std::max<T>(x, y); - } +template <class T> +inline T max(const T& x, const T& y, const T& z) { + return std::max<T>(std::max<T>(x, y), z); +} -#endif +template <class T> +inline T max(const T& x, const T& y, const T& z, const T& w) { + return std::max<T>(std::max<T>(x, y), std::max<T>(z, w)); +} int iMin(int x, int y); int iMax(int x, int y); @@ -357,7 +325,7 @@ double distance(double x, double y, double z); the left. -1 means the number was 0. @cite Based on code by jukka@liimatta.org - */ + */ int highestBit(uint32 x); /** @@ -367,8 +335,8 @@ int highestBit(uint32 x); */ bool fuzzyEq(double a, double b); -/** True if a is definitely not equal to b. - Guaranteed false if a == b. +/** True if a is definitely not equal to b. + Guaranteed false if a == b. Possibly false when a != b.*/ bool fuzzyNe(double a, double b); @@ -393,30 +361,30 @@ inline float rsq(float x) { } /** - Uses SSE to implement rsq. - @cite Nick nicolas@capens.net - */ -inline float SSErsq(float x) { - - #if defined(SSE) && defined(G3D_WIN32) && !defined(_WIN64) - __asm { - movss xmm0, x - rsqrtss xmm0, xmm0 - movss x, xmm0 - } - return x; - #else - return 1.0f / sqrt(x); - #endif -} - -/** Return the next power of 2 higher than the input - If the input is already a power of 2, the output will be the same + If the input is already a power of 2, the output will be the same as the input. */ int ceilPow2(unsigned int in); +/** Returns 2^x */ +inline int pow2(unsigned int x) { + return 1 << x; +} + +inline double log2(double x) { + return ::log(x) * 1.442695; +} + +inline float log2(float x) { + return ::logf(x) * 1.442695f; +} + +inline double log2(int x) { + return log2((double)x); +} + + /** * True if num is a power of two. */ @@ -456,6 +424,7 @@ inline float dot(float a, float b) { return a * b; } + /** a * b (for DirectX/Cg support) */ @@ -470,10 +439,21 @@ inline double exp2(double x) { return pow(2.0, x); } +inline float exp2(float x) { + return powf(2.0f, x); +} + +/** @deprecated Use rsq */ inline double rsqrt(double x) { return 1.0 / sqrt(x); } +/** @deprecated Use rsq */ +inline float rsqrt(float x) { + // TODO: default this to using the SSE2 instruction + return 1.0 / sqrtf(x); +} + /** sin(x)/x */ @@ -490,6 +470,19 @@ inline double sinc(double x) { /** Computes a floating point modulo; the result is t wrapped to the range [lo, hi). */ +inline float wrap(float t, float lo, float hi) { + if ((t >= lo) && (t < hi)) { + return t; + } + + debugAssert(hi > lo); + + float interval = hi - lo; + + return t - interval * iFloor((t - lo) / interval); +} + + inline double wrap(double t, double lo, double hi) { if ((t >= lo) && (t < hi)) { return t; @@ -500,21 +493,353 @@ inline double wrap(double t, double lo, double hi) { double interval = hi - lo; return t - interval * iFloor((t - lo) / interval); - } inline double wrap(double t, double hi) { - return wrap(t, 0, hi); + return wrap(t, 0.0, hi); +} + + +inline bool isFinite(double x) { + return ! isNaN(x) && (x < G3D::inf()) && (x > -G3D::inf()); +} + +inline bool isFinite(float x) { + return ! isNaN(x) && (x < G3D::finf()) && (x > -G3D::finf()); +} + +//---------------------------------------------------------------------------- +inline int iAbs (int iValue) { + return ( iValue >= 0 ? iValue : -iValue ); +} + +//---------------------------------------------------------------------------- +inline int iCeil (double fValue) { + return int(::ceil(fValue)); +} + +//---------------------------------------------------------------------------- + +inline int iClamp(int val, int low, int hi) { + debugAssert(low <= hi); + if (val <= low) { + return low; + } else if (val >= hi) { + return hi; + } else { + return val; + } +} + +//---------------------------------------------------------------------------- + +inline int16 iClamp(int16 val, int16 low, int16 hi) { + debugAssert(low <= hi); + if (val <= low) { + return low; + } else if (val >= hi) { + return hi; + } else { + return val; + } +} + +//---------------------------------------------------------------------------- + +inline double clamp(double val, double low, double hi) { + debugAssert(low <= hi); + if (val <= low) { + return low; + } else if (val >= hi) { + return hi; + } else { + return val; + } +} + +inline float clamp(float val, float low, float hi) { + debugAssert(low <= hi); + if (val <= low) { + return low; + } else if (val >= hi) { + return hi; + } else { + return val; + } +} +//---------------------------------------------------------------------------- + +inline int iWrap(int val, int hi) { + if (val < 0) { + return ((val % hi) + hi) % hi; + } else { + return val % hi; + } +} + +//---------------------------------------------------------------------------- +inline int iFloor (double fValue) { + return int(::floor(fValue)); +} + +//---------------------------------------------------------------------------- +inline int iSign (int iValue) { + return ( iValue > 0 ? + 1 : ( iValue < 0 ? -1 : 0 ) ); } +inline int iSign (double fValue) { + return ( fValue > 0.0 ? + 1 : ( fValue < 0.0 ? -1 : 0 ) ); +} + +//---------------------------------------------------------------------------- +inline double abs (double fValue) { + return double(::fabs(fValue)); +} + +//---------------------------------------------------------------------------- +inline double aCos (double fValue) { + if ( -1.0 < fValue ) { + if ( fValue < 1.0 ) + return double(::acos(fValue)); + else + return 0.0; + } else { + return pi(); + } +} + +//---------------------------------------------------------------------------- +inline double aSin (double fValue) { + if ( -1.0 < fValue ) { + if ( fValue < 1.0 ) { + return double(::asin(fValue)); + } else { + return -halfPi(); + } + } else { + return halfPi(); + } +} + +//---------------------------------------------------------------------------- +inline double aTan (double fValue) { + return double(::atan(fValue)); +} + +//---------------------------------------------------------------------------- +inline double aTan2 (double fY, double fX) { + return double(::atan2(fY, fX)); +} + +//---------------------------------------------------------------------------- +inline double sign (double fValue) { + if (fValue > 0.0) { + return 1.0; + } + + if (fValue < 0.0) { + return -1.0; + } + + return 0.0; +} + +inline float sign (float fValue) { + if (fValue > 0.0f) { + return 1.0f; + } + + if (fValue < 0.0f) { + return -1.0f; + } + + return 0.0f; +} + + +inline float uniformRandom(float low, float hi) { + return (hi - low) * float(::rand()) / float(RAND_MAX) + low; +} + +inline double square(double x) { + return x * x; +} + +inline float square(float x) { + return x * x; +} + +inline int square(int x) { + return x * x; +} + +//---------------------------------------------------------------------------- +inline double sumSquares(double x, double y) { + return x*x + y*y; +} + +//---------------------------------------------------------------------------- +inline float sumSquares(float x, float y) { + return x*x + y*y; +} + +//---------------------------------------------------------------------------- +inline double sumSquares(double x, double y, double z) { + return x*x + y*y + z*z; +} + +//---------------------------------------------------------------------------- +inline float sumSquares(float x, float y, float z) { + return x*x + y*y + z*z; +} + +//---------------------------------------------------------------------------- +inline double distance(double x, double y) { + return sqrt(sumSquares(x, y)); +} + +//---------------------------------------------------------------------------- +inline float distance(float x, float y) { + return sqrt(sumSquares(x, y)); +} + +//---------------------------------------------------------------------------- +inline double distance(double x, double y, double z) { + return sqrt(sumSquares(x, y, z)); +} + +//---------------------------------------------------------------------------- +inline float distance(float x, float y, float z) { + return sqrt(sumSquares(x, y, z)); +} + +//---------------------------------------------------------------------------- + +/** @deprecated use G3D::min */ +inline int iMin(int x, int y) { + return (x >= y) ? y : x; +} + +//---------------------------------------------------------------------------- +/** @deprecated use G3D::min */ +inline int iMax(int x, int y) { + return (x >= y) ? x : y; +} + +//---------------------------------------------------------------------------- +inline int ceilPow2(unsigned int in) { + in -= 1; + + in |= in >> 16; + in |= in >> 8; + in |= in >> 4; + in |= in >> 2; + in |= in >> 1; + + return in + 1; +} + +inline bool isPow2(int num) { + return ((num & -num) == num); +} + +inline bool isOdd(int num) { + return (num & 1) == 1; +} + +inline bool isEven(int num) { + return (num & 1) == 0; +} + +inline double toRadians(double deg) { + return deg * pi() / 180.0; +} + +inline double toDegrees(double rad) { + return rad * 180.0 / pi(); +} + +inline float toRadians(float deg) { + return deg * (float)pi() / 180.0f; +} + +inline float toDegrees(float rad) { + return rad * 180.0f / (float)pi(); +} + +inline float toRadians(int deg) { + return deg * (float)pi() / 180.0f; +} + +inline float toDegrees(int rad) { + return rad * 180.0f / (float)pi(); +} +/** + Computes an appropriate epsilon for comparing a and b. + */ +inline double eps(double a, double b) { + // For a and b to be nearly equal, they must have nearly + // the same magnitude. This means that we can ignore b + // since it either has the same magnitude or the comparison + // will fail anyway. + (void)b; + const double aa = abs(a) + 1.0; + if (aa == inf()) { + return fuzzyEpsilon; + } else { + return fuzzyEpsilon * aa; + } +} + +inline bool fuzzyEq(double a, double b) { + return (a == b) || (abs(a - b) <= eps(a, b)); +} + +inline bool fuzzyNe(double a, double b) { + return ! fuzzyEq(a, b); +} + +inline bool fuzzyGt(double a, double b) { + return a > b + eps(a, b); +} + +inline bool fuzzyGe(double a, double b) { + return a > b - eps(a, b); +} + +inline bool fuzzyLt(double a, double b) { + return a < b - eps(a, b); +} + +inline bool fuzzyLe(double a, double b) { + return a < b + eps(a, b); +} + +inline int iMod3(int x) { + return x % 3; +} + +/** + Given a 32-bit integer, returns the integer with the bytes in the opposite order. + */ +inline uint32 flipEndian32(const uint32 x) { + return (x << 24) | ((x & 0xFF00) << 8) | + ((x & 0xFF0000) >> 8) | ((x & 0xFF000000) >> 24); +} + +/** + Given a 16-bit integer, returns the integer with the bytes in the opposite order. + */ +inline uint16 flipEndian16(const uint16 x) { + return (x << 8) | ((x & 0xFF00) >> 8); +} + + } // namespace #ifdef _MSC_VER # pragma warning (pop) #endif -#include "g3dmath.inl" - #endif - |