From 8443733a084a006a12d1f1fb4b868899d44aa501 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Tue, 25 Feb 2014 18:25:45 +0000 Subject: [PATCH] math: add GLSL-inherited degrees() and radians() conversion functions. --- src/camera.cpp | 4 ++-- src/easymesh/easymesh.cpp | 2 +- src/lol/math/functions.h | 49 +++++++++++++++++++++++++++++++++++++++ src/lol/math/half.h | 2 ++ src/lol/math/real.h | 6 +++++ src/lol/math/vector.h | 18 ++++++++++++++ src/math/real.cpp | 14 +++++++++++ src/math/vector.cpp | 37 ++++++++++++----------------- test/unit/trig.cpp | 15 ++++++++++++ 9 files changed, 122 insertions(+), 25 deletions(-) diff --git a/src/camera.cpp b/src/camera.cpp index b90bd6e1..ffa9d3e5 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -225,13 +225,13 @@ quat Camera::GetRotation() const // Calculate the frustum height at a given distance from the camera. float Camera::GetFrustumHeightAtDistance(float distance, float fov) const { - return 2.f * distance * lol::tan(fov * .5f * (F_PI / 180.f)); + return 2.f * distance * lol::tan(radians(fov * .5f)); } // Calculate the FOV needed to get a given frustum height at a given distance. float Camera::GetFOVForHeightAndDistance(float distance, float height) const { - return 2.f * lol::atan(height * .5f / distance) * (180.f / F_PI); + return 2.f * radians(lol::atan(height * .5f / distance)); } void Camera::TickGame(float seconds) diff --git a/src/easymesh/easymesh.cpp b/src/easymesh/easymesh.cpp index d660b663..86215812 100644 --- a/src/easymesh/easymesh.cpp +++ b/src/easymesh/easymesh.cpp @@ -1450,7 +1450,7 @@ void EasyMesh::AppendCapsule(int ndivisions, float h, float d) /* Fill in the icosahedron vertices, rotating them so that there * is a vertex at [0 1 0] and [0 -1 0] after normalisation. */ float phi = 0.5f + 0.5f * sqrt(5.f); - mat3 mat = mat3::rotate(asin(1.f / sqrt(2.f + phi)) * (180.f / F_PI), + mat3 mat = mat3::rotate(degrees(asin(1.f / sqrt(2.f + phi))), vec3(0.f, 0.f, 1.f)); for (int i = 0; i < 4; i++) { diff --git a/src/lol/math/functions.h b/src/lol/math/functions.h index 5f692456..fe1a9688 100644 --- a/src/lol/math/functions.h +++ b/src/lol/math/functions.h @@ -84,6 +84,55 @@ static inline void sincos(float const &x, float *s, float *c) *c = std::cos(x); } +/* Inherited from GLSL */ +static inline float degrees(float radians) +{ + return radians * (180.0f / F_PI); +} + +static inline double degrees(double radians) +{ + return radians * (180.0 / D_PI); +} + +static inline ldouble degrees(ldouble radians) +{ + return radians * (180.0L / LD_PI); +} + +static inline int8_t degrees(int8_t x) { return degrees((float)x); } +static inline uint8_t degrees(uint8_t x) { return degrees((float)x); } +static inline int16_t degrees(int16_t x) { return degrees((float)x); } +static inline uint16_t degrees(uint16_t x) { return degrees((float)x); } +static inline int32_t degrees(int32_t x) { return degrees((double)x); } +static inline uint32_t degrees(uint32_t x) { return degrees((double)x); } +static inline int64_t degrees(int64_t x) { return degrees((ldouble)x); } +static inline uint64_t degrees(uint64_t x) { return degrees((ldouble)x); } + +static inline float radians(float degrees) +{ + return degrees * (F_PI / 180.0f); +} + +static inline double radians(double degrees) +{ + return degrees * (D_PI / 180.0); +} + +static inline ldouble radians(ldouble degrees) +{ + return degrees * (LD_PI / 180.0L); +} + +static inline int8_t radians(int8_t x) { return radians((float)x); } +static inline uint8_t radians(uint8_t x) { return radians((float)x); } +static inline int16_t radians(int16_t x) { return radians((float)x); } +static inline uint16_t radians(uint16_t x) { return radians((float)x); } +static inline int32_t radians(int32_t x) { return radians((double)x); } +static inline uint32_t radians(uint32_t x) { return radians((double)x); } +static inline int64_t radians(int64_t x) { return radians((ldouble)x); } +static inline uint64_t radians(uint64_t x) { return radians((ldouble)x); } + static inline float lerp(float const &a, float const &b, float const &x) { return a + (b - a) * x; diff --git a/src/lol/math/half.h b/src/lol/math/half.h index 27b7bb73..39cffab5 100644 --- a/src/lol/math/half.h +++ b/src/lol/math/half.h @@ -124,6 +124,8 @@ static inline float fmod(half a, half b) return fmod((float)a, (float)b); } static inline float fract(half a) { return fract((float)a); } +static inline float degrees(half a) { return degrees((float)a); } +static inline float radians(half a) { return radians((float)a); } static inline half abs(half a) { return half::makebits(a.bits & 0x7fffu); } static inline half clamp(half x, half a, half b) diff --git a/src/lol/math/real.h b/src/lol/math/real.h index c4cb5929..69628bdd 100644 --- a/src/lol/math/real.h +++ b/src/lol/math/real.h @@ -125,6 +125,8 @@ public: /* Functions inherited from GLSL */ template friend Real abs(Real const &x); template friend Real fract(Real const &x); + template friend Real degrees(Real const &x); + template friend Real radians(Real const &x); void hexprint() const; void print(int ndigits = 150) const; @@ -276,6 +278,8 @@ template Real round(Real const &x); template Real fmod(Real const &x, Real const &y); template Real abs(Real const &x); template Real fract(Real const &x); +template Real degrees(Real const &x); +template Real radians(Real const &x); template<> real min(real const &a, real const &b); template<> real max(real const &a, real const &b); @@ -314,6 +318,8 @@ template<> real round(real const &x); template<> real fmod(real const &x, real const &y); template<> real abs(real const &x); template<> real fract(real const &x); +template<> real degrees(real const &x); +template<> real radians(real const &x); template<> void real::hexprint() const; template<> void real::print(int ndigits) const; diff --git a/src/lol/math/vector.h b/src/lol/math/vector.h index ac5ea0d3..ea0af7a1 100644 --- a/src/lol/math/vector.h +++ b/src/lol/math/vector.h @@ -1399,6 +1399,24 @@ extern Quat slerp(Quat const &qa, Quat const &qb, T f); for (size_t n = 0; n < sizeof(a) / sizeof(type); n++) \ ret[n] = lol::abs(a[n]); \ return ret; \ + } \ + \ + tprefix \ + inline tname degrees(tname const &a) \ + { \ + tname ret; \ + for (size_t n = 0; n < sizeof(a) / sizeof(type); n++) \ + ret[n] = lol::degrees(a[n]); \ + return ret; \ + } \ + \ + tprefix \ + inline tname radians(tname const &a) \ + { \ + tname ret; \ + for (size_t n = 0; n < sizeof(a) / sizeof(type); n++) \ + ret[n] = lol::radians(a[n]); \ + return ret; \ } #define LOL_BINARY_NONVECTOR_FUNS(tname, tprefix, type) \ diff --git a/src/math/real.cpp b/src/math/real.cpp index 0e38ace5..b300b698 100644 --- a/src/math/real.cpp +++ b/src/math/real.cpp @@ -820,6 +820,20 @@ template<> real fract(real const &x) return x - floor(x); } +template<> real degrees(real const &x) +{ + static real mul = real(180) * real::R_1_PI(); + + return x * mul; +} + +template<> real radians(real const &x) +{ + static real mul = real::R_PI() / real(180); + + return x * mul; +} + static real fast_log(real const &x) { /* This fast log method is tuned to work on the [1..2] range and diff --git a/src/math/vector.cpp b/src/math/vector.cpp index 35137793..2ea3a6bf 100644 --- a/src/math/vector.cpp +++ b/src/math/vector.cpp @@ -352,10 +352,8 @@ template<> mat4 mat4::translate(vec3 v) template<> mat2 mat2::rotate(float degrees) { - degrees *= (F_PI / 180.0f); - - float st = sin(degrees); - float ct = cos(degrees); + float st = sin(radians(degrees)); + float ct = cos(radians(degrees)); mat2 ret; @@ -370,10 +368,8 @@ template<> mat2 mat2::rotate(float degrees) template<> mat3 mat3::rotate(float degrees, float x, float y, float z) { - degrees *= (F_PI / 180.0f); - - float st = sin(degrees); - float ct = cos(degrees); + float st = sin(radians(degrees)); + float ct = cos(radians(degrees)); float len = std::sqrt(x * x + y * y + z * z); float invlen = len ? 1.0f / len : 0.0f; @@ -489,11 +485,11 @@ template<> quat::Quat(mat4 const &m) template<> quat quat::rotate(float degrees, vec3 const &v) { - degrees *= (F_PI / 360.0f); + float half_angle = radians(degrees) * 0.5f; - vec3 tmp = normalize(v) * sin(degrees); + vec3 tmp = normalize(v) * sin(half_angle); - return quat(cos(degrees), tmp.x, tmp.y, tmp.z); + return quat(cos(half_angle), tmp.x, tmp.y, tmp.z); } template<> quat quat::rotate(float degrees, float x, float y, float z) @@ -563,17 +559,17 @@ static inline vec3 quat_toeuler_generic(quat const &q, int i, int j, int k) 1.f - 2.f * (sq(q[1 + k]) + sq(q[1 + j]))); } - return (180.0f / F_PI / n) * ret; + return degrees(ret / n); } static inline mat3 mat3_fromeuler_generic(vec3 const &v, int i, int j, int k) { mat3 ret; - vec3 const radians = (F_PI / 180.0f) * v; - float const s0 = sin(radians[0]), c0 = cos(radians[0]); - float const s1 = sin(radians[1]), c1 = cos(radians[1]); - float const s2 = sin(radians[2]), c2 = cos(radians[2]); + vec3 const w = radians(v); + float const s0 = sin(w[0]), c0 = cos(w[0]); + float const s1 = sin(w[1]), c1 = cos(w[1]); + float const s2 = sin(w[2]), c2 = cos(w[2]); /* (2 + i - j) % 3 means x-y-z direct order; otherwise indirect */ float const sign = ((2 + i - j) % 3) ? 1.f : -1.f; @@ -616,7 +612,7 @@ static inline mat3 mat3_fromeuler_generic(vec3 const &v, int i, int j, int k) static inline quat quat_fromeuler_generic(vec3 const &v, int i, int j, int k) { - vec3 const half_angles = (F_PI / 360.0f) * v; + vec3 const half_angles = radians(v * 0.5f); float const s0 = sin(half_angles[0]), c0 = cos(half_angles[0]); float const s1 = sin(half_angles[1]), c1 = cos(half_angles[1]); float const s2 = sin(half_angles[2]), c2 = cos(half_angles[2]); @@ -771,9 +767,7 @@ template<> mat4 mat4::frustum(float left, float right, float bottom, template<> mat4 mat4::perspective(float fov_y, float width, float height, float near, float far) { - fov_y *= (F_PI / 180.0f); - - float t2 = lol::tan(fov_y * 0.5f); + float t2 = lol::tan(radians(fov_y) * 0.5f); float t1 = t2 * width / height; return frustum(-near * t1, near * t1, -near * t2, near * t2, near, far); @@ -783,8 +777,7 @@ template<> mat4 mat4::perspective(float fov_y, float width, template<> mat4 mat4::shifted_perspective(float fov_y, float screen_size, float screen_ratio_yx, float near, float far) { - float new_fov_y = fov_y * (F_PI / 180.0f); - float tan_y = tanf(new_fov_y * .5f); + float tan_y = tanf(radians(fov_y) * .5f); ASSERT(tan_y > 0.000001f); float dist_scr = (screen_size * screen_ratio_yx * .5f) / tan_y; diff --git a/test/unit/trig.cpp b/test/unit/trig.cpp index 0854f023..b00121c2 100644 --- a/test/unit/trig.cpp +++ b/test/unit/trig.cpp @@ -22,6 +22,21 @@ namespace lol LOLUNIT_FIXTURE(TrigTest) { + LOLUNIT_TEST(AngleConversions) + { + LOLUNIT_ASSERT_DOUBLES_EQUAL(D_PI, radians(180.0), 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(D_PI_2, radians(90.0), 1e-5); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(F_PI, radians(180.0f), 1e-5f); + LOLUNIT_ASSERT_DOUBLES_EQUAL(F_PI_2, radians(90.0f), 1e-5f); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(180.0, degrees(D_PI), 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(90.0, degrees(D_PI_2), 1e-5); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(180.0f, degrees(F_PI), 1e-5f); + LOLUNIT_ASSERT_DOUBLES_EQUAL(90.0f, degrees(F_PI_2), 1e-5f); + } + LOLUNIT_TEST(Sin) { using std::fabs;