aboutsummaryrefslogtreecommitdiff
path: root/dep/include/g3dlite/G3D/g3dmath.h
diff options
context:
space:
mode:
Diffstat (limited to 'dep/include/g3dlite/G3D/g3dmath.h')
-rw-r--r--dep/include/g3dlite/G3D/g3dmath.h633
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
-