Core: Replace C math headers with C++ equivalents

- Minor restructuring to ensure `math_funcs.h` is the central point for math functions
This commit is contained in:
Thaddeus Crews
2025-03-19 14:18:09 -05:00
parent c5c1cd4440
commit ad40939b6f
101 changed files with 414 additions and 498 deletions

View File

@ -262,7 +262,7 @@ void Basis::scale_orthogonal(const Vector3 &p_scale) {
Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const {
Basis m = *this;
Vector3 s = Vector3(-1, -1, -1) + p_scale;
bool sign = signbit(s.x + s.y + s.z);
bool sign = std::signbit(s.x + s.y + s.z);
Basis b = m.orthonormalized();
s = b.xform_inv(s);
Vector3 dots;
@ -271,7 +271,7 @@ Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const {
dots[j] += s[i] * Math::abs(m.get_column(i).normalized().dot(b.get_column(j)));
}
}
if (sign != signbit(dots.x + dots.y + dots.z)) {
if (sign != std::signbit(dots.x + dots.y + dots.z)) {
dots = -dots;
}
m.scale_local(Vector3(1, 1, 1) + dots);
@ -477,7 +477,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
if (rows[1][0] == 0 && rows[0][1] == 0 && rows[1][2] == 0 && rows[2][1] == 0 && rows[1][1] == 1) {
// return the simplest form (human friendlier in editor and scripts)
euler.x = 0;
euler.y = atan2(rows[0][2], rows[0][0]);
euler.y = std::atan2(rows[0][2], rows[0][0]);
euler.z = 0;
} else {
euler.x = Math::atan2(-rows[1][2], rows[2][2]);
@ -542,22 +542,22 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// is this a pure X rotation?
if (rows[1][0] == 0 && rows[0][1] == 0 && rows[0][2] == 0 && rows[2][0] == 0 && rows[0][0] == 1) {
// return the simplest form (human friendlier in editor and scripts)
euler.x = atan2(-m12, rows[1][1]);
euler.x = std::atan2(-m12, rows[1][1]);
euler.y = 0;
euler.z = 0;
} else {
euler.x = asin(-m12);
euler.y = atan2(rows[0][2], rows[2][2]);
euler.z = atan2(rows[1][0], rows[1][1]);
euler.x = std::asin(-m12);
euler.y = std::atan2(rows[0][2], rows[2][2]);
euler.z = std::atan2(rows[1][0], rows[1][1]);
}
} else { // m12 == -1
euler.x = Math::PI * 0.5f;
euler.y = atan2(rows[0][1], rows[0][0]);
euler.y = std::atan2(rows[0][1], rows[0][0]);
euler.z = 0;
}
} else { // m12 == 1
euler.x = -Math::PI * 0.5f;
euler.y = -atan2(rows[0][1], rows[0][0]);
euler.y = -std::atan2(rows[0][1], rows[0][0]);
euler.z = 0;
}

View File

@ -34,37 +34,37 @@
#include "core/math/math_defs.h"
#include "core/typedefs.h"
#include <float.h>
#include <math.h>
#include <cfloat>
#include <cmath>
namespace Math {
_ALWAYS_INLINE_ double sin(double p_x) {
return ::sin(p_x);
return std::sin(p_x);
}
_ALWAYS_INLINE_ float sin(float p_x) {
return ::sinf(p_x);
return std::sin(p_x);
}
_ALWAYS_INLINE_ double cos(double p_x) {
return ::cos(p_x);
return std::cos(p_x);
}
_ALWAYS_INLINE_ float cos(float p_x) {
return ::cosf(p_x);
return std::cos(p_x);
}
_ALWAYS_INLINE_ double tan(double p_x) {
return ::tan(p_x);
return std::tan(p_x);
}
_ALWAYS_INLINE_ float tan(float p_x) {
return ::tanf(p_x);
return std::tan(p_x);
}
_ALWAYS_INLINE_ double sinh(double p_x) {
return ::sinh(p_x);
return std::sinh(p_x);
}
_ALWAYS_INLINE_ float sinh(float p_x) {
return ::sinhf(p_x);
return std::sinh(p_x);
}
_ALWAYS_INLINE_ double sinc(double p_x) {
@ -82,212 +82,156 @@ _ALWAYS_INLINE_ float sincn(float p_x) {
}
_ALWAYS_INLINE_ double cosh(double p_x) {
return ::cosh(p_x);
return std::cosh(p_x);
}
_ALWAYS_INLINE_ float cosh(float p_x) {
return ::coshf(p_x);
return std::cosh(p_x);
}
_ALWAYS_INLINE_ double tanh(double p_x) {
return ::tanh(p_x);
return std::tanh(p_x);
}
_ALWAYS_INLINE_ float tanh(float p_x) {
return ::tanhf(p_x);
return std::tanh(p_x);
}
// Always does clamping so always safe to use.
_ALWAYS_INLINE_ double asin(double p_x) {
return p_x < -1 ? (-PI / 2) : (p_x > 1 ? (PI / 2) : ::asin(p_x));
return p_x < -1 ? (-PI / 2) : (p_x > 1 ? (PI / 2) : std::asin(p_x));
}
_ALWAYS_INLINE_ float asin(float p_x) {
return p_x < -1 ? (-(float)PI / 2) : (p_x > 1 ? ((float)PI / 2) : ::asinf(p_x));
return p_x < -1 ? (-(float)PI / 2) : (p_x > 1 ? ((float)PI / 2) : std::asin(p_x));
}
// Always does clamping so always safe to use.
_ALWAYS_INLINE_ double acos(double p_x) {
return p_x < -1 ? PI : (p_x > 1 ? 0 : ::acos(p_x));
return p_x < -1 ? PI : (p_x > 1 ? 0 : std::acos(p_x));
}
_ALWAYS_INLINE_ float acos(float p_x) {
return p_x < -1 ? (float)PI : (p_x > 1 ? 0 : ::acosf(p_x));
return p_x < -1 ? (float)PI : (p_x > 1 ? 0 : std::acos(p_x));
}
_ALWAYS_INLINE_ double atan(double p_x) {
return ::atan(p_x);
return std::atan(p_x);
}
_ALWAYS_INLINE_ float atan(float p_x) {
return ::atanf(p_x);
return std::atan(p_x);
}
_ALWAYS_INLINE_ double atan2(double p_y, double p_x) {
return ::atan2(p_y, p_x);
return std::atan2(p_y, p_x);
}
_ALWAYS_INLINE_ float atan2(float p_y, float p_x) {
return ::atan2f(p_y, p_x);
return std::atan2(p_y, p_x);
}
_ALWAYS_INLINE_ double asinh(double p_x) {
return ::asinh(p_x);
return std::asinh(p_x);
}
_ALWAYS_INLINE_ float asinh(float p_x) {
return ::asinhf(p_x);
return std::asinh(p_x);
}
// Always does clamping so always safe to use.
_ALWAYS_INLINE_ double acosh(double p_x) {
return p_x < 1 ? 0 : ::acosh(p_x);
return p_x < 1 ? 0 : std::acosh(p_x);
}
_ALWAYS_INLINE_ float acosh(float p_x) {
return p_x < 1 ? 0 : ::acoshf(p_x);
return p_x < 1 ? 0 : std::acosh(p_x);
}
// Always does clamping so always safe to use.
_ALWAYS_INLINE_ double atanh(double p_x) {
return p_x <= -1 ? -INF : (p_x >= 1 ? INF : ::atanh(p_x));
return p_x <= -1 ? -INF : (p_x >= 1 ? INF : std::atanh(p_x));
}
_ALWAYS_INLINE_ float atanh(float p_x) {
return p_x <= -1 ? (float)-INF : (p_x >= 1 ? (float)INF : ::atanhf(p_x));
return p_x <= -1 ? (float)-INF : (p_x >= 1 ? (float)INF : std::atanh(p_x));
}
_ALWAYS_INLINE_ double sqrt(double p_x) {
return ::sqrt(p_x);
return std::sqrt(p_x);
}
_ALWAYS_INLINE_ float sqrt(float p_x) {
return ::sqrtf(p_x);
return std::sqrt(p_x);
}
_ALWAYS_INLINE_ double fmod(double p_x, double p_y) {
return ::fmod(p_x, p_y);
return std::fmod(p_x, p_y);
}
_ALWAYS_INLINE_ float fmod(float p_x, float p_y) {
return ::fmodf(p_x, p_y);
return std::fmod(p_x, p_y);
}
_ALWAYS_INLINE_ double modf(double p_x, double *r_y) {
return ::modf(p_x, r_y);
return std::modf(p_x, r_y);
}
_ALWAYS_INLINE_ float modf(float p_x, float *r_y) {
return ::modff(p_x, r_y);
return std::modf(p_x, r_y);
}
_ALWAYS_INLINE_ double floor(double p_x) {
return ::floor(p_x);
return std::floor(p_x);
}
_ALWAYS_INLINE_ float floor(float p_x) {
return ::floorf(p_x);
return std::floor(p_x);
}
_ALWAYS_INLINE_ double ceil(double p_x) {
return ::ceil(p_x);
return std::ceil(p_x);
}
_ALWAYS_INLINE_ float ceil(float p_x) {
return ::ceilf(p_x);
return std::ceil(p_x);
}
_ALWAYS_INLINE_ double pow(double p_x, double p_y) {
return ::pow(p_x, p_y);
return std::pow(p_x, p_y);
}
_ALWAYS_INLINE_ float pow(float p_x, float p_y) {
return ::powf(p_x, p_y);
return std::pow(p_x, p_y);
}
_ALWAYS_INLINE_ double log(double p_x) {
return ::log(p_x);
return std::log(p_x);
}
_ALWAYS_INLINE_ float log(float p_x) {
return ::logf(p_x);
return std::log(p_x);
}
_ALWAYS_INLINE_ double log1p(double p_x) {
return ::log1p(p_x);
return std::log1p(p_x);
}
_ALWAYS_INLINE_ float log1p(float p_x) {
return ::log1pf(p_x);
return std::log1p(p_x);
}
_ALWAYS_INLINE_ double log2(double p_x) {
return ::log2(p_x);
return std::log2(p_x);
}
_ALWAYS_INLINE_ float log2(float p_x) {
return ::log2f(p_x);
return std::log2(p_x);
}
_ALWAYS_INLINE_ double exp(double p_x) {
return ::exp(p_x);
return std::exp(p_x);
}
_ALWAYS_INLINE_ float exp(float p_x) {
return ::expf(p_x);
return std::exp(p_x);
}
_ALWAYS_INLINE_ bool is_nan(double p_val) {
#ifdef _MSC_VER
return _isnan(p_val);
#elif defined(__GNUC__) && __GNUC__ < 6
union {
uint64_t u;
double f;
} ieee754;
ieee754.f = p_val;
// (unsigned)(0x7ff0000000000001 >> 32) : 0x7ff00000
return ((((unsigned)(ieee754.u >> 32) & 0x7fffffff) + ((unsigned)ieee754.u != 0)) > 0x7ff00000);
#else
return isnan(p_val);
#endif
return std::isnan(p_val);
}
_ALWAYS_INLINE_ bool is_nan(float p_val) {
#ifdef _MSC_VER
return _isnan(p_val);
#elif defined(__GNUC__) && __GNUC__ < 6
union {
uint32_t u;
float f;
} ieee754;
ieee754.f = p_val;
// -----------------------------------
// (single-precision floating-point)
// NaN : s111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
// : (> 0x7f800000)
// where,
// s : sign
// x : non-zero number
// -----------------------------------
return ((ieee754.u & 0x7fffffff) > 0x7f800000);
#else
return isnan(p_val);
#endif
return std::isnan(p_val);
}
_ALWAYS_INLINE_ bool is_inf(double p_val) {
#ifdef _MSC_VER
return !_finite(p_val);
// use an inline implementation of isinf as a workaround for problematic libstdc++ versions from gcc 5.x era
#elif defined(__GNUC__) && __GNUC__ < 6
union {
uint64_t u;
double f;
} ieee754;
ieee754.f = p_val;
return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 &&
((unsigned)ieee754.u == 0);
#else
return isinf(p_val);
#endif
return std::isinf(p_val);
}
_ALWAYS_INLINE_ bool is_inf(float p_val) {
#ifdef _MSC_VER
return !_finite(p_val);
// use an inline implementation of isinf as a workaround for problematic libstdc++ versions from gcc 5.x era
#elif defined(__GNUC__) && __GNUC__ < 6
union {
uint32_t u;
float f;
} ieee754;
ieee754.f = p_val;
return (ieee754.u & 0x7fffffff) == 0x7f800000;
#else
return isinf(p_val);
#endif
return std::isinf(p_val);
}
// These methods assume (p_num + p_den) doesn't overflow.
@ -307,24 +251,17 @@ _ALWAYS_INLINE_ uint64_t division_round_up(uint64_t p_num, uint64_t p_den) {
}
_ALWAYS_INLINE_ bool is_finite(double p_val) {
return isfinite(p_val);
return std::isfinite(p_val);
}
_ALWAYS_INLINE_ bool is_finite(float p_val) {
return isfinite(p_val);
}
_ALWAYS_INLINE_ double absd(double p_value) {
return ::fabs(p_value);
}
_ALWAYS_INLINE_ float absf(float p_value) {
return ::fabsf(p_value);
return std::isfinite(p_val);
}
_ALWAYS_INLINE_ double abs(double p_value) {
return absd(p_value);
return std::abs(p_value);
}
_ALWAYS_INLINE_ float abs(float p_value) {
return absf(p_value);
return std::abs(p_value);
}
_ALWAYS_INLINE_ int8_t abs(int8_t p_value) {
return p_value > 0 ? p_value : -p_value;
@ -333,10 +270,10 @@ _ALWAYS_INLINE_ int16_t abs(int16_t p_value) {
return p_value > 0 ? p_value : -p_value;
}
_ALWAYS_INLINE_ int32_t abs(int32_t p_value) {
return ::abs(p_value);
return std::abs(p_value);
}
_ALWAYS_INLINE_ int64_t abs(int64_t p_value) {
return ::llabs(p_value);
return std::abs(p_value);
}
_ALWAYS_INLINE_ double fposmod(double p_x, double p_y) {
@ -686,10 +623,10 @@ _ALWAYS_INLINE_ float db_to_linear(float p_db) {
}
_ALWAYS_INLINE_ double round(double p_val) {
return ::round(p_val);
return std::round(p_val);
}
_ALWAYS_INLINE_ float round(float p_val) {
return ::roundf(p_val);
return std::round(p_val);
}
_ALWAYS_INLINE_ double wrapf(double p_value, double p_min, double p_max) {
@ -760,8 +697,7 @@ int random(int p_from, int p_to);
// This function should be as fast as possible and rounding mode should not matter.
_ALWAYS_INLINE_ int fast_ftoi(float p_value) {
// Assuming every supported compiler has `lrint()`.
return lrintf(p_value);
return std::rint(p_value);
}
_ALWAYS_INLINE_ uint32_t halfbits_to_floatbits(uint16_t p_half) {

View File

@ -282,7 +282,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
real_t left, right, modeltranslation, ymax, xmax, frustumshift;
ymax = p_z_near * tan(Math::deg_to_rad(p_fovy_degrees / 2.0));
ymax = p_z_near * std::tan(Math::deg_to_rad(p_fovy_degrees / 2.0));
xmax = ymax * p_aspect;
frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist;

View File

@ -148,7 +148,7 @@ Quaternion Quaternion::slerpni(const Quaternion &p_to, real_t p_weight) const {
real_t dot = from.dot(p_to);
if (Math::absf(dot) > 0.9999f) {
if (Math::abs(dot) > 0.9999f) {
return from;
}
@ -180,11 +180,11 @@ Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const
post_q = Basis(post_q).get_rotation_quaternion();
// Flip quaternions to shortest path if necessary.
bool flip1 = signbit(from_q.dot(pre_q));
bool flip1 = std::signbit(from_q.dot(pre_q));
pre_q = flip1 ? -pre_q : pre_q;
bool flip2 = signbit(from_q.dot(to_q));
bool flip2 = std::signbit(from_q.dot(to_q));
to_q = flip2 ? -to_q : to_q;
bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : signbit(to_q.dot(post_q));
bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : std::signbit(to_q.dot(post_q));
post_q = flip3 ? -post_q : post_q;
// Calc by Expmap in from_q space.
@ -231,11 +231,11 @@ Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b
post_q = Basis(post_q).get_rotation_quaternion();
// Flip quaternions to shortest path if necessary.
bool flip1 = signbit(from_q.dot(pre_q));
bool flip1 = std::signbit(from_q.dot(pre_q));
pre_q = flip1 ? -pre_q : pre_q;
bool flip2 = signbit(from_q.dot(to_q));
bool flip2 = std::signbit(from_q.dot(to_q));
to_q = flip2 ? -to_q : to_q;
bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : signbit(to_q.dot(post_q));
bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : std::signbit(to_q.dot(post_q));
post_q = flip3 ? -post_q : post_q;
// Calc by Expmap in from_q space.

View File

@ -30,12 +30,10 @@
#pragma once
#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
#include "thirdparty/misc/pcg.h"
#include <math.h>
#if defined(__GNUC__)
#define CLZ32(x) __builtin_clz(x)
#elif defined(_MSC_VER)
@ -46,16 +44,6 @@ static int __bsr_clz32(uint32_t x) {
return 31 - index;
}
#define CLZ32(x) __bsr_clz32(x)
#else
#endif
#if defined(__GNUC__)
#define LDEXP(s, e) __builtin_ldexp(s, e)
#define LDEXPF(s, e) __builtin_ldexpf(s, e)
#else
#include <math.h>
#define LDEXP(s, e) ldexp(s, e)
#define LDEXPF(s, e) ldexp(s, e)
#endif
template <typename T>
@ -110,7 +98,7 @@ public:
return 0;
}
uint64_t significand = (((uint64_t)rand()) << 32) | rand() | 0x8000000000000001U;
return LDEXP((double)significand, -64 - CLZ32(proto_exp_offset));
return std::ldexp((double)significand, -64 - CLZ32(proto_exp_offset));
#else
#pragma message("RandomPCG::randd - intrinsic clz is not available, falling back to bit truncation")
return (double)(((((uint64_t)rand()) << 32) | rand()) & 0x1FFFFFFFFFFFFFU) / (double)0x1FFFFFFFFFFFFFU;
@ -122,7 +110,7 @@ public:
if (unlikely(proto_exp_offset == 0)) {
return 0;
}
return LDEXPF((float)(rand() | 0x80000001), -32 - CLZ32(proto_exp_offset));
return std::ldexp((float)(rand() | 0x80000001), -32 - CLZ32(proto_exp_offset));
#else
#pragma message("RandomPCG::randf - intrinsic clz is not available, falling back to bit truncation")
return (float)(rand() & 0xFFFFFF) / (float)0xFFFFFF;
@ -134,14 +122,14 @@ public:
if (temp < CMP_EPSILON) {
temp += CMP_EPSILON; // To prevent generating of INF value in log function, resulting to return NaN value from this function.
}
return p_mean + p_deviation * (cos(Math::TAU * randd()) * sqrt(-2.0 * log(temp))); // Box-Muller transform.
return p_mean + p_deviation * (std::cos(Math::TAU * randd()) * std::sqrt(-2.0 * std::log(temp))); // Box-Muller transform.
}
_FORCE_INLINE_ float randfn(float p_mean, float p_deviation) {
float temp = randf();
if (temp < CMP_EPSILON) {
temp += CMP_EPSILON; // To prevent generating of INF value in log function, resulting to return NaN value from this function.
}
return p_mean + p_deviation * (cos((float)Math::TAU * randf()) * sqrt(-2.0 * log(temp))); // Box-Muller transform.
return p_mean + p_deviation * (std::cos((float)Math::TAU * randf()) * std::sqrt(-2.0 * std::log(temp))); // Box-Muller transform.
}
double random(double p_from, double p_to);