Fix compile for math funcs.

This commit is contained in:
Relintai 2022-03-13 16:01:22 +01:00
parent db8c5ac829
commit c6cec44559
7 changed files with 1134 additions and 411 deletions

View File

@ -66,6 +66,8 @@ env_base["x86_libtheora_opt_vc"] = False
# avoid issues when building with different versions of python out of the same directory
env_base.SConsignFile(".sconsign{0}.dblite".format(pickle.HIGHEST_PROTOCOL))
env_base.Prepend(CPPPATH=["#"])
# Build options
env = env_base.Clone()

93
core/error_list.h Normal file
View File

@ -0,0 +1,93 @@
/*************************************************************************/
/* error_list.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef ERROR_LIST_H
#define ERROR_LIST_H
/** Error List. Please never compare an error against FAILED
* Either do result != OK , or !result. This way, Error fail
* values can be more detailed in the future.
*
* This is a generic error list, mainly for organizing a language of returning errors.
*/
enum Error {
OK, // (0)
FAILED, ///< Generic fail error
ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
ERR_UNCONFIGURED, ///< The object being used hasn't been properly set up yet
ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
ERR_OUT_OF_MEMORY, ///< Out of memory
ERR_FILE_NOT_FOUND,
ERR_FILE_BAD_DRIVE,
ERR_FILE_BAD_PATH,
ERR_FILE_NO_PERMISSION, // (10)
ERR_FILE_ALREADY_IN_USE,
ERR_FILE_CANT_OPEN,
ERR_FILE_CANT_WRITE,
ERR_FILE_CANT_READ,
ERR_FILE_UNRECOGNIZED, // (15)
ERR_FILE_CORRUPT,
ERR_FILE_MISSING_DEPENDENCIES,
ERR_FILE_EOF,
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
ERR_CANT_CREATE, // (20)
ERR_QUERY_FAILED,
ERR_ALREADY_IN_USE,
ERR_LOCKED, ///< resource is locked
ERR_TIMEOUT,
ERR_CANT_CONNECT, // (25)
ERR_CANT_RESOLVE,
ERR_CONNECTION_ERROR,
ERR_CANT_ACQUIRE_RESOURCE,
ERR_CANT_FORK,
ERR_INVALID_DATA, ///< Data passed is invalid (30)
ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
ERR_ALREADY_EXISTS, ///< When adding, item already exists
ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, if item does not exist
ERR_DATABASE_CANT_READ, ///< database is full
ERR_DATABASE_CANT_WRITE, ///< database is full (35)
ERR_COMPILATION_FAILED,
ERR_METHOD_NOT_FOUND,
ERR_LINK_FAILED,
ERR_SCRIPT_FAILED,
ERR_CYCLIC_LINK, // (40)
ERR_INVALID_DECLARATION,
ERR_DUPLICATE_SYMBOL,
ERR_PARSE_ERROR,
ERR_BUSY,
ERR_SKIP, // (45)
ERR_HELP, ///< user requested help!!
ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
};
#endif

59
core/int_types.h Normal file
View File

@ -0,0 +1,59 @@
/*************************************************************************/
/* int_types.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include <stdbool.h>
#ifdef _MSC_VER
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#ifdef NO_STDINT_H
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
typedef unsigned int uint32_t;
typedef signed int int32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
#else
#include <stdint.h>
#endif
#endif

View File

@ -30,34 +30,38 @@
#include "math_funcs.h"
#include "core/error_macros.h"
//#include "core/error_macros.h"
RandomPCG Math::default_rand(RandomPCG::DEFAULT_SEED, RandomPCG::DEFAULT_INC);
//RandomPCG math_default_rand(RandomPCG::DEFAULT_SEED, RandomPCG::DEFAULT_INC);
#define PHI 0x9e3779b9
uint32_t Math::rand_from_seed(uint64_t *seed) {
uint32_t math_rand_from_seed(uint64_t *seed) {
/*
RandomPCG rng = RandomPCG(*seed, RandomPCG::DEFAULT_INC);
uint32_t r = rng.rand();
*seed = rng.get_seed();
return r;
*/
return 0;
}
void Math::seed(uint64_t x) {
default_rand.seed(x);
void math_seed(uint64_t x) {
//default_rand.seed(x);
}
void Math::randomize() {
default_rand.randomize();
void math_randomize() {
//default_rand.randomize();
}
uint32_t Math::rand() {
return default_rand.rand();
uint32_t math_rand() {
//return default_rand.rand();
return 0;
}
int Math::step_decimals(double p_step) {
int math_step_decimals(double p_step) {
static const int maxn = 10;
static const double sd[maxn] = {
static const double sd[10] = {
0.9999, // somehow compensate for floating point error
0.09999,
0.009999,
@ -70,7 +74,7 @@ int Math::step_decimals(double p_step) {
0.0000000009999
};
double abs = Math::abs(p_step);
double abs = math_absd(p_step);
double decs = abs - (int)abs; // Strip away integer part
for (int i = 0; i < maxn; i++) {
if (decs >= sd[i]) {
@ -83,17 +87,17 @@ int Math::step_decimals(double p_step) {
// Only meant for editor usage in float ranges, where a step of 0
// means that decimal digits should not be limited in String::num.
int Math::range_step_decimals(double p_step) {
int math_range_step_decimals(double p_step) {
if (p_step < 0.0000000000001) {
return 16; // Max value hardcoded in String::num
}
return step_decimals(p_step);
}
double Math::dectime(double p_value, double p_amount, double p_step) {
WARN_DEPRECATED_MSG("The `dectime()` function has been deprecated and will be removed in Godot 4.0. Use `move_toward()` instead.");
double math_dectime(double p_value, double p_amount, double p_step) {
//WARN_DEPRECATED_MSG("The `dectime()` function has been deprecated and will be removed in Godot 4.0. Use `move_toward()` instead.");
double sgn = p_value < 0 ? -1.0 : 1.0;
double val = Math::abs(p_value);
double val = math_absd(p_value);
val -= p_amount * p_step;
if (val < 0.0) {
val = 0.0;
@ -101,7 +105,7 @@ double Math::dectime(double p_value, double p_amount, double p_step) {
return val * sgn;
}
double Math::ease(double p_x, double p_c) {
double math_ease(double p_x, double p_c) {
if (p_x < 0) {
p_x = 0;
} else if (p_x > 1.0) {
@ -109,31 +113,38 @@ double Math::ease(double p_x, double p_c) {
}
if (p_c > 0) {
if (p_c < 1.0) {
return 1.0 - Math::pow(1.0 - p_x, 1.0 / p_c);
return 1.0 - math_powd(1.0 - p_x, 1.0 / p_c);
} else {
return Math::pow(p_x, p_c);
return math_powd(p_x, p_c);
}
} else if (p_c < 0) {
//inout ease
if (p_x < 0.5) {
return Math::pow(p_x * 2.0, -p_c) * 0.5;
return math_powd(p_x * 2.0, -p_c) * 0.5;
} else {
return (1.0 - Math::pow(1.0 - (p_x - 0.5) * 2.0, -p_c)) * 0.5 + 0.5;
return (1.0 - math_powd(1.0 - (p_x - 0.5) * 2.0, -p_c)) * 0.5 + 0.5;
}
} else {
return 0; // no ease (raw)
}
}
double Math::stepify(double p_value, double p_step) {
float math_stepifyf(float p_value, float p_step) {
if (p_step != 0) {
p_value = Math::floor(p_value / p_step + 0.5) * p_step;
p_value = math_floorf(p_value / p_step + 0.5) * p_step;
}
return p_value;
}
uint32_t Math::larger_prime(uint32_t p_val) {
double math_stepifyd(double p_value, double p_step) {
if (p_step != 0) {
p_value = math_floord(p_value / p_step + 0.5) * p_step;
}
return p_value;
}
uint32_t math_larger_prime(uint32_t p_val) {
static const uint32_t primes[] = {
5,
13,
@ -169,7 +180,7 @@ uint32_t Math::larger_prime(uint32_t p_val) {
int idx = 0;
while (true) {
ERR_FAIL_COND_V(primes[idx] == 0, 0);
//ERR_FAIL_COND_V(primes[idx] == 0, 0);
if (primes[idx] > p_val) {
return primes[idx];
}
@ -177,10 +188,14 @@ uint32_t Math::larger_prime(uint32_t p_val) {
}
}
double Math::random(double from, double to) {
return default_rand.random(from, to);
double math_randomd(double from, double to) {
//return default_rand.random(from, to);
return 0;
}
float Math::random(float from, float to) {
return default_rand.random(from, to);
float math_randomf(float from, float to) {
//return default_rand.random(from, to);
return 0;
}

View File

@ -32,466 +32,604 @@
#define MATH_FUNCS_H
#include "core/math/math_defs.h"
#include "core/math/random_pcg.h"
#include "core/typedefs.h"
#include "thirdparty/misc/pcg.h"
#include <float.h>
#include <math.h>
class Math {
static RandomPCG default_rand;
// Not using 'RANDOM_MAX' to avoid conflict with system headers on some OSes (at least NetBSD).
static const uint64_t MATH_RANDOM_32BIT_MAX = 0xFFFFFFFF;
public:
Math() {} // useless to instance
static _ALWAYS_INLINE_ double math_sind(double p_x) {
return sin(p_x);
}
static _ALWAYS_INLINE_ float math_sinf(float p_x) {
return sinf(p_x);
}
// Not using 'RANDOM_MAX' to avoid conflict with system headers on some OSes (at least NetBSD).
static const uint64_t RANDOM_32BIT_MAX = 0xFFFFFFFF;
static _ALWAYS_INLINE_ double math_cosd(double p_x) {
return cos(p_x);
}
static _ALWAYS_INLINE_ float math_cosf(float p_x) {
return cosf(p_x);
}
static _ALWAYS_INLINE_ double sin(double p_x) { return ::sin(p_x); }
static _ALWAYS_INLINE_ float sin(float p_x) { return ::sinf(p_x); }
static _ALWAYS_INLINE_ double math_tand(double p_x) {
return tan(p_x);
}
static _ALWAYS_INLINE_ float math_tanf(float p_x) {
return tanf(p_x);
}
static _ALWAYS_INLINE_ double cos(double p_x) { return ::cos(p_x); }
static _ALWAYS_INLINE_ float cos(float p_x) { return ::cosf(p_x); }
static _ALWAYS_INLINE_ double math_sinhd(double p_x) {
return sinh(p_x);
}
static _ALWAYS_INLINE_ float math_sinhf(float p_x) {
return sinhf(p_x);
}
static _ALWAYS_INLINE_ double tan(double p_x) { return ::tan(p_x); }
static _ALWAYS_INLINE_ float tan(float p_x) { return ::tanf(p_x); }
static _ALWAYS_INLINE_ float math_sincf(float p_x) {
return p_x == 0 ? 1 : sinf(p_x) / p_x;
}
static _ALWAYS_INLINE_ double math_sincd(double p_x) {
return p_x == 0 ? 1 : sin(p_x) / p_x;
}
static _ALWAYS_INLINE_ double sinh(double p_x) { return ::sinh(p_x); }
static _ALWAYS_INLINE_ float sinh(float p_x) { return ::sinhf(p_x); }
static _ALWAYS_INLINE_ float math_sincnf(float p_x) {
return math_sincf((float)Math_PI * p_x);
}
static _ALWAYS_INLINE_ double math_sincnd(double p_x) {
return math_sincd(Math_PI * p_x);
}
static _ALWAYS_INLINE_ float sinc(float p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
static _ALWAYS_INLINE_ double sinc(double p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
static _ALWAYS_INLINE_ double math_coshd(double p_x) {
return cosh(p_x);
}
static _ALWAYS_INLINE_ float math_coshf(float p_x) {
return coshf(p_x);
}
static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc((float)Math_PI * p_x); }
static _ALWAYS_INLINE_ double sincn(double p_x) { return sinc(Math_PI * p_x); }
static _ALWAYS_INLINE_ double math_tanhd(double p_x) {
return tanh(p_x);
}
static _ALWAYS_INLINE_ float math_tanhf(float p_x) {
return tanhf(p_x);
}
static _ALWAYS_INLINE_ double cosh(double p_x) { return ::cosh(p_x); }
static _ALWAYS_INLINE_ float cosh(float p_x) { return ::coshf(p_x); }
static _ALWAYS_INLINE_ double math_asind(double p_x) {
return asin(p_x);
}
static _ALWAYS_INLINE_ float math_asinf(float p_x) {
return asinf(p_x);
}
static _ALWAYS_INLINE_ double tanh(double p_x) { return ::tanh(p_x); }
static _ALWAYS_INLINE_ float tanh(float p_x) { return ::tanhf(p_x); }
static _ALWAYS_INLINE_ double math_acosd(double p_x) {
return acos(p_x);
}
static _ALWAYS_INLINE_ float math_acosf(float p_x) {
return acosf(p_x);
}
static _ALWAYS_INLINE_ double asin(double p_x) { return ::asin(p_x); }
static _ALWAYS_INLINE_ float asin(float p_x) { return ::asinf(p_x); }
static _ALWAYS_INLINE_ double math_atand(double p_x) {
return atan(p_x);
}
static _ALWAYS_INLINE_ float math_atanf(float p_x) {
return atanf(p_x);
}
static _ALWAYS_INLINE_ double acos(double p_x) { return ::acos(p_x); }
static _ALWAYS_INLINE_ float acos(float p_x) { return ::acosf(p_x); }
static _ALWAYS_INLINE_ double math_atan2d(double p_y, double p_x) {
return atan2(p_y, p_x);
}
static _ALWAYS_INLINE_ float math_atan2f(float p_y, float p_x) {
return atan2f(p_y, p_x);
}
static _ALWAYS_INLINE_ double atan(double p_x) { return ::atan(p_x); }
static _ALWAYS_INLINE_ float atan(float p_x) { return ::atanf(p_x); }
static _ALWAYS_INLINE_ double math_sqrtd(double p_x) {
return sqrt(p_x);
}
static _ALWAYS_INLINE_ float math_sqrtf(float p_x) {
return sqrtf(p_x);
}
static _ALWAYS_INLINE_ double atan2(double p_y, double p_x) { return ::atan2(p_y, p_x); }
static _ALWAYS_INLINE_ float atan2(float p_y, float p_x) { return ::atan2f(p_y, p_x); }
static _ALWAYS_INLINE_ double math_fmodd(double p_x, double p_y) {
return fmod(p_x, p_y);
}
static _ALWAYS_INLINE_ float math_fmodf(float p_x, float p_y) {
return fmodf(p_x, p_y);
}
static _ALWAYS_INLINE_ double sqrt(double p_x) { return ::sqrt(p_x); }
static _ALWAYS_INLINE_ float sqrt(float p_x) { return ::sqrtf(p_x); }
static _ALWAYS_INLINE_ double math_floord(double p_x) {
return floor(p_x);
}
static _ALWAYS_INLINE_ float math_floorf(float p_x) {
return floorf(p_x);
}
static _ALWAYS_INLINE_ double fmod(double p_x, double p_y) { return ::fmod(p_x, p_y); }
static _ALWAYS_INLINE_ float fmod(float p_x, float p_y) { return ::fmodf(p_x, p_y); }
static _ALWAYS_INLINE_ double math_ceild(double p_x) {
return ceil(p_x);
}
static _ALWAYS_INLINE_ float math_ceilf(float p_x) {
return ceilf(p_x);
}
static _ALWAYS_INLINE_ double floor(double p_x) { return ::floor(p_x); }
static _ALWAYS_INLINE_ float floor(float p_x) { return ::floorf(p_x); }
static _ALWAYS_INLINE_ double math_powd(double p_x, double p_y) {
return pow(p_x, p_y);
}
static _ALWAYS_INLINE_ float math_powf(float p_x, float p_y) {
return powf(p_x, p_y);
}
static _ALWAYS_INLINE_ double ceil(double p_x) { return ::ceil(p_x); }
static _ALWAYS_INLINE_ float ceil(float p_x) { return ::ceilf(p_x); }
static _ALWAYS_INLINE_ double math_logd(double p_x) {
return log(p_x);
}
static _ALWAYS_INLINE_ float math_logf(float p_x) {
return logf(p_x);
}
static _ALWAYS_INLINE_ double pow(double p_x, double p_y) { return ::pow(p_x, p_y); }
static _ALWAYS_INLINE_ float pow(float p_x, float p_y) { return ::powf(p_x, p_y); }
static _ALWAYS_INLINE_ double math_expd(double p_x) {
return exp(p_x);
}
static _ALWAYS_INLINE_ float math_expf(float p_x) {
return expf(p_x);
}
static _ALWAYS_INLINE_ double log(double p_x) { return ::log(p_x); }
static _ALWAYS_INLINE_ float log(float p_x) { return ::logf(p_x); }
static _ALWAYS_INLINE_ double exp(double p_x) { return ::exp(p_x); }
static _ALWAYS_INLINE_ float exp(float p_x) { return ::expf(p_x); }
static _ALWAYS_INLINE_ bool is_nan(double p_val) {
static _ALWAYS_INLINE_ bool math_is_nand(double p_val) {
#ifdef _MSC_VER
return _isnan(p_val);
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);
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);
return isnan(p_val);
#endif
}
}
static _ALWAYS_INLINE_ bool is_nan(float p_val) {
static _ALWAYS_INLINE_ bool math_is_nanf(float p_val) {
#ifdef _MSC_VER
return _isnan(p_val);
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);
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);
return isnan(p_val);
#endif
}
}
static _ALWAYS_INLINE_ bool is_inf(double p_val) {
static _ALWAYS_INLINE_ bool math_is_infd(double p_val) {
#ifdef _MSC_VER
return !_finite(p_val);
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);
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);
return isinf(p_val);
#endif
}
}
static _ALWAYS_INLINE_ bool is_inf(float p_val) {
static _ALWAYS_INLINE_ bool math_is_inff(float p_val) {
#ifdef _MSC_VER
return !_finite(p_val);
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;
union {
uint32_t u;
float f;
} ieee754;
ieee754.f = p_val;
return (ieee754.u & 0x7fffffff) == 0x7f800000;
#else
return isinf(p_val);
return isinf(p_val);
#endif
}
static _ALWAYS_INLINE_ float math_absf(float g) {
union {
float f;
uint32_t i;
} u;
u.f = g;
u.i &= 2147483647u;
return u.f;
}
static _ALWAYS_INLINE_ double math_absd(double g) {
union {
double d;
uint64_t i;
} u;
u.d = g;
u.i &= (uint64_t)9223372036854775807ll;
return u.d;
}
static _ALWAYS_INLINE_ int math_absi(int g) {
return g > 0 ? g : -g;
}
static _ALWAYS_INLINE_ int64_t math_absi64(int64_t g) {
return g > 0 ? g : -g;
}
static _ALWAYS_INLINE_ double math_fposmodd(double p_x, double p_y) {
double value = math_fmodd(p_x, p_y);
if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
static _ALWAYS_INLINE_ double abs(double g) { return absd(g); }
static _ALWAYS_INLINE_ float abs(float g) { return absf(g); }
static _ALWAYS_INLINE_ int abs(int g) { return g > 0 ? g : -g; }
static _ALWAYS_INLINE_ int64_t abs(int64_t g) { return g > 0 ? g : -g; }
static _ALWAYS_INLINE_ double fposmod(double p_x, double p_y) {
double value = Math::fmod(p_x, p_y);
if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
value += 0.0;
return value;
value += 0.0;
return value;
}
static _ALWAYS_INLINE_ float math_fposmodf(float p_x, float p_y) {
float value = math_fmodf(p_x, p_y);
if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
static _ALWAYS_INLINE_ float fposmod(float p_x, float p_y) {
float value = Math::fmod(p_x, p_y);
if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
value += 0.0f;
return value;
value += 0.0f;
return value;
}
static _ALWAYS_INLINE_ int64_t math_posmodi(int64_t p_x, int64_t p_y) {
int64_t value = p_x % p_y;
if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
static _ALWAYS_INLINE_ int64_t posmod(int64_t p_x, int64_t p_y) {
int64_t value = p_x % p_y;
if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) {
value += p_y;
}
return value;
return value;
}
static _ALWAYS_INLINE_ double math_deg2radd(double p_y) {
return p_y * Math_PI / 180.0;
}
static _ALWAYS_INLINE_ float math_deg2radf(float p_y) {
return p_y * (float)(Math_PI / 180.0);
}
static _ALWAYS_INLINE_ double math_rad2degd(double p_y) {
return p_y * 180.0 / Math_PI;
}
static _ALWAYS_INLINE_ float math_rad2degf(float p_y) {
return p_y * (float)(180.0 / Math_PI);
}
static _ALWAYS_INLINE_ double math_lerpd(double p_from, double p_to, double p_weight) {
return p_from + (p_to - p_from) * p_weight;
}
static _ALWAYS_INLINE_ float math_lerpf(float p_from, float p_to, float p_weight) {
return p_from + (p_to - p_from) * p_weight;
}
static _ALWAYS_INLINE_ double math_lerp_angled(double p_from, double p_to, double p_weight) {
double difference = fmod(p_to - p_from, Math_TAU);
double distance = fmod(2.0 * difference, Math_TAU) - difference;
return p_from + distance * p_weight;
}
static _ALWAYS_INLINE_ float math_lerp_anglef(float p_from, float p_to, float p_weight) {
float difference = fmodf(p_to - p_from, (float)Math_TAU);
float distance = fmodf(2.0f * difference, (float)Math_TAU) - difference;
return p_from + distance * p_weight;
}
static _ALWAYS_INLINE_ double math_inverse_lerpd(double p_from, double p_to, double p_value) {
return (p_value - p_from) / (p_to - p_from);
}
static _ALWAYS_INLINE_ float math_inverse_lerpf(float p_from, float p_to, float p_value) {
return (p_value - p_from) / (p_to - p_from);
}
static _ALWAYS_INLINE_ double math_range_lerpd(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
return math_lerpd(p_ostart, p_ostop, math_inverse_lerpd(p_istart, p_istop, p_value));
}
static _ALWAYS_INLINE_ float math_range_lerpf(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
return math_lerpf(p_ostart, p_ostop, math_inverse_lerpf(p_istart, p_istop, p_value));
}
static _ALWAYS_INLINE_ double math_linear2dbd(double p_linear) {
return math_logd(p_linear) * 8.6858896380650365530225783783321;
}
static _ALWAYS_INLINE_ float math_linear2dbf(float p_linear) {
return math_logf(p_linear) * (float)8.6858896380650365530225783783321;
}
static _ALWAYS_INLINE_ double math_db2lineard(double p_db) {
return math_expd(p_db * 0.11512925464970228420089957273422);
}
static _ALWAYS_INLINE_ float math_db2linearf(float p_db) {
return math_expf(p_db * (float)0.11512925464970228420089957273422);
}
static _ALWAYS_INLINE_ double math_roundd(double p_val) {
return round(p_val);
}
static _ALWAYS_INLINE_ float math_roundf(float p_val) {
return roundf(p_val);
}
// double only, as these functions are mainly used by the editor and not performance-critical,
static double ease(double p_x, double p_c);
int step_decimals(double p_step);
static int range_step_decimals(double p_step);
static double stepify(double p_value, double p_step);
static double dectime(double p_value, double p_amount, double p_step);
static uint32_t larger_prime(uint32_t p_val);
static void seed(uint64_t x);
static void randomize();
static uint32_t rand_from_seed(uint64_t *seed);
uint32_t rand();
static _ALWAYS_INLINE_ double randd() {
return (double)rand() / (double)MATH_RANDOM_32BIT_MAX;
}
static _ALWAYS_INLINE_ float randf() {
return (float)rand() / (float)MATH_RANDOM_32BIT_MAX;
}
static double math_randomd(double from, double to);
static float math_randomf(float from, float to);
static real_t math_randomr(int from, int to) {
return (real_t)math_randomf((real_t)from, (real_t)to);
}
static _ALWAYS_INLINE_ bool math_is_equal_approx_ratio(real_t a, real_t b) {
// this is an approximate way to check that numbers are close, as a ratio of their average size
// helps compare approximate numbers that may be very big or very small
real_t diff = math_absf(a - b);
if (diff == 0 || diff < CMP_EPSILON) {
return true;
}
real_t avg_size = (math_absf(a) + math_absf(b)) / 2;
diff /= avg_size;
return diff < CMP_EPSILON;
}
static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y * Math_PI / 180.0; }
static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * (float)(Math_PI / 180.0); }
static _ALWAYS_INLINE_ double rad2deg(double p_y) { return p_y * 180.0 / Math_PI; }
static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y * (float)(180.0 / Math_PI); }
static _ALWAYS_INLINE_ double lerp(double p_from, double p_to, double p_weight) { return p_from + (p_to - p_from) * p_weight; }
static _ALWAYS_INLINE_ float lerp(float p_from, float p_to, float p_weight) { return p_from + (p_to - p_from) * p_weight; }
static _ALWAYS_INLINE_ double lerp_angle(double p_from, double p_to, double p_weight) {
double difference = fmod(p_to - p_from, Math_TAU);
double distance = fmod(2.0 * difference, Math_TAU) - difference;
return p_from + distance * p_weight;
static _ALWAYS_INLINE_ bool math_is_equal_approx_ratioe(real_t a, real_t b, real_t epsilon) {
// this is an approximate way to check that numbers are close, as a ratio of their average size
// helps compare approximate numbers that may be very big or very small
real_t diff = math_absf(a - b);
if (diff == 0 || diff < CMP_EPSILON) {
return true;
}
static _ALWAYS_INLINE_ float lerp_angle(float p_from, float p_to, float p_weight) {
float difference = fmod(p_to - p_from, (float)Math_TAU);
float distance = fmod(2.0f * difference, (float)Math_TAU) - difference;
return p_from + distance * p_weight;
real_t avg_size = (math_absf(a) + math_absf(b)) / 2;
diff /= avg_size;
return diff < epsilon;
}
static _ALWAYS_INLINE_ bool math_is_equal_approx_ratioem(real_t a, real_t b, real_t epsilon, real_t min_epsilon) {
// this is an approximate way to check that numbers are close, as a ratio of their average size
// helps compare approximate numbers that may be very big or very small
real_t diff = math_absf(a - b);
if (diff == 0 || diff < min_epsilon) {
return true;
}
real_t avg_size = (math_absf(a) + math_absf(b)) / 2;
diff /= avg_size;
return diff < epsilon;
}
static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { return (p_value - p_from) / (p_to - p_from); }
static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { return (p_value - p_from) / (p_to - p_from); }
static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) {
if (is_equal_approx(p_from, p_to)) {
return p_from;
}
double s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0, 1.0);
return s * s * (3.0 - 2.0 * s);
static _ALWAYS_INLINE_ bool math_is_equal_approxf(float a, float b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_s) {
if (is_equal_approx(p_from, p_to)) {
return p_from;
}
float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f);
return s * s * (3.0f - 2.0f * s);
// Then check for approximate equality.
float tolerance = (float)CMP_EPSILON * math_absf(a);
if (tolerance < (float)CMP_EPSILON) {
tolerance = (float)CMP_EPSILON;
}
static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; }
static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; }
return math_absf(a - b) < tolerance;
}
static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
static _ALWAYS_INLINE_ double db2linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); }
static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); }
static _ALWAYS_INLINE_ int64_t wrapi(int64_t value, int64_t min, int64_t max) {
int64_t range = max - min;
return range == 0 ? min : min + ((((value - min) % range) + range) % range);
static _ALWAYS_INLINE_ bool math_is_equal_approxft(float a, float b, float tolerance) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) {
double range = max - min;
return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range));
// Then check for approximate equality.
return math_absf(a - b) < tolerance;
}
static _ALWAYS_INLINE_ bool math_is_zero_approxf(float s) {
return math_absf(s) < (float)CMP_EPSILON;
}
static _ALWAYS_INLINE_ bool math_is_equal_approxd(double a, double b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) {
float range = max - min;
return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range));
// Then check for approximate equality.
double tolerance = CMP_EPSILON * math_absd(a);
if (tolerance < CMP_EPSILON) {
tolerance = CMP_EPSILON;
}
return math_absd(a - b) < tolerance;
}
// double only, as these functions are mainly used by the editor and not performance-critical,
static double ease(double p_x, double p_c);
static int step_decimals(double p_step);
static int range_step_decimals(double p_step);
static double stepify(double p_value, double p_step);
static double dectime(double p_value, double p_amount, double p_step);
static uint32_t larger_prime(uint32_t p_val);
static void seed(uint64_t x);
static void randomize();
static uint32_t rand_from_seed(uint64_t *seed);
static uint32_t rand();
static _ALWAYS_INLINE_ double randd() { return (double)rand() / (double)Math::RANDOM_32BIT_MAX; }
static _ALWAYS_INLINE_ float randf() { return (float)rand() / (float)Math::RANDOM_32BIT_MAX; }
static double random(double from, double to);
static float random(float from, float to);
static real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); }
static _ALWAYS_INLINE_ bool is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON, real_t min_epsilon = CMP_EPSILON) {
// this is an approximate way to check that numbers are close, as a ratio of their average size
// helps compare approximate numbers that may be very big or very small
real_t diff = abs(a - b);
if (diff == 0 || diff < min_epsilon) {
return true;
}
real_t avg_size = (abs(a) + abs(b)) / 2;
diff /= avg_size;
return diff < epsilon;
static _ALWAYS_INLINE_ bool math_is_equal_approxdt(double a, double b, double tolerance) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
return math_absd(a - b) < tolerance;
}
static _ALWAYS_INLINE_ bool is_equal_approx(float a, float b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
float tolerance = (float)CMP_EPSILON * abs(a);
if (tolerance < (float)CMP_EPSILON) {
tolerance = (float)CMP_EPSILON;
}
return abs(a - b) < tolerance;
static _ALWAYS_INLINE_ bool math_is_zero_approxd(double s) {
return math_absd(s) < CMP_EPSILON;
}
static _ALWAYS_INLINE_ double math_smoothstepd(double p_from, double p_to, double p_s) {
if (math_is_equal_approxd(p_from, p_to)) {
return p_from;
}
static _ALWAYS_INLINE_ bool is_equal_approx(float a, float b, float tolerance) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
return abs(a - b) < tolerance;
double s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0, 1.0);
return s * s * (3.0 - 2.0 * s);
}
static _ALWAYS_INLINE_ float math_smoothstepf(float p_from, float p_to, float p_s) {
if (math_is_equal_approxf(p_from, p_to)) {
return p_from;
}
float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f);
return s * s * (3.0f - 2.0f * s);
}
static _ALWAYS_INLINE_ double math_move_towardd(double p_from, double p_to, double p_delta) {
return math_absd(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta;
}
static _ALWAYS_INLINE_ float math_move_towardf(float p_from, float p_to, float p_delta) {
return math_absf(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta;
}
static _ALWAYS_INLINE_ bool is_zero_approx(float s) {
return abs(s) < (float)CMP_EPSILON;
}
static _ALWAYS_INLINE_ int64_t math_wrapi(int64_t value, int64_t min, int64_t max) {
int64_t range = max - min;
return range == 0 ? min : min + ((((value - min) % range) + range) % range);
}
static _ALWAYS_INLINE_ double math_wrapd(double value, double min, double max) {
double range = max - min;
return math_is_zero_approxd(range) ? min : value - (range * math_floord((value - min) / range));
}
static _ALWAYS_INLINE_ float math_wrapf(float value, float min, float max) {
float range = max - min;
return math_is_zero_approxf(range) ? min : value - (range * math_floorf((value - min) / range));
}
static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
double tolerance = CMP_EPSILON * abs(a);
if (tolerance < CMP_EPSILON) {
tolerance = CMP_EPSILON;
}
return abs(a - b) < tolerance;
}
// This function should be as fast as possible and rounding mode should not matter.
static _ALWAYS_INLINE_ int math_fast_ftoi(float a) {
// Assuming every supported compiler has `lrint()`.
return lrintf(a);
}
static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b, double tolerance) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
return abs(a - b) < tolerance;
}
static _ALWAYS_INLINE_ uint32_t math_halfbits_to_floatbits(uint16_t h) {
uint16_t h_exp, h_sig;
uint32_t f_sgn, f_exp, f_sig;
static _ALWAYS_INLINE_ bool is_zero_approx(double s) {
return abs(s) < CMP_EPSILON;
}
static _ALWAYS_INLINE_ float absf(float g) {
union {
float f;
uint32_t i;
} u;
u.f = g;
u.i &= 2147483647u;
return u.f;
}
static _ALWAYS_INLINE_ double absd(double g) {
union {
double d;
uint64_t i;
} u;
u.d = g;
u.i &= (uint64_t)9223372036854775807ll;
return u.d;
}
// This function should be as fast as possible and rounding mode should not matter.
static _ALWAYS_INLINE_ int fast_ftoi(float a) {
// Assuming every supported compiler has `lrint()`.
return lrintf(a);
}
static _ALWAYS_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h) {
uint16_t h_exp, h_sig;
uint32_t f_sgn, f_exp, f_sig;
h_exp = (h & 0x7c00u);
f_sgn = ((uint32_t)h & 0x8000u) << 16;
switch (h_exp) {
case 0x0000u: /* 0 or subnormal */
h_sig = (h & 0x03ffu);
/* Signed zero */
if (h_sig == 0) {
return f_sgn;
}
/* Subnormal */
h_exp = (h & 0x7c00u);
f_sgn = ((uint32_t)h & 0x8000u) << 16;
switch (h_exp) {
case 0x0000u: /* 0 or subnormal */
h_sig = (h & 0x03ffu);
/* Signed zero */
if (h_sig == 0) {
return f_sgn;
}
/* Subnormal */
h_sig <<= 1;
while ((h_sig & 0x0400u) == 0) {
h_sig <<= 1;
while ((h_sig & 0x0400u) == 0) {
h_sig <<= 1;
h_exp++;
}
f_exp = ((uint32_t)(127 - 15 - h_exp)) << 23;
f_sig = ((uint32_t)(h_sig & 0x03ffu)) << 13;
return f_sgn + f_exp + f_sig;
case 0x7c00u: /* inf or NaN */
/* All-ones exponent and a copy of the significand */
return f_sgn + 0x7f800000u + (((uint32_t)(h & 0x03ffu)) << 13);
default: /* normalized */
/* Just need to adjust the exponent and shift */
return f_sgn + (((uint32_t)(h & 0x7fffu) + 0x1c000u) << 13);
}
}
static _ALWAYS_INLINE_ float halfptr_to_float(const uint16_t *h) {
union {
uint32_t u32;
float f32;
} u;
u.u32 = halfbits_to_floatbits(*h);
return u.f32;
}
static _ALWAYS_INLINE_ float half_to_float(const uint16_t h) {
return halfptr_to_float(&h);
}
static _ALWAYS_INLINE_ uint16_t make_half_float(float f) {
union {
float fv;
uint32_t ui;
} ci;
ci.fv = f;
uint32_t x = ci.ui;
uint32_t sign = (unsigned short)(x >> 31);
uint32_t mantissa;
uint32_t exp;
uint16_t hf;
// get mantissa
mantissa = x & ((1 << 23) - 1);
// get exponent bits
exp = x & (0xFF << 23);
if (exp >= 0x47800000) {
// check if the original single precision float number is a NaN
if (mantissa && (exp == (0xFF << 23))) {
// we have a single precision NaN
mantissa = (1 << 23) - 1;
} else {
// 16-bit half-float representation stores number as Inf
mantissa = 0;
h_exp++;
}
hf = (((uint16_t)sign) << 15) | (uint16_t)((0x1F << 10)) |
(uint16_t)(mantissa >> 13);
}
// check if exponent is <= -15
else if (exp <= 0x38000000) {
/*// store a denorm half-float value or zero
exp = (0x38000000 - exp) >> 23;
mantissa >>= (14 + exp);
f_exp = ((uint32_t)(127 - 15 - h_exp)) << 23;
f_sig = ((uint32_t)(h_sig & 0x03ffu)) << 13;
return f_sgn + f_exp + f_sig;
case 0x7c00u: /* inf or NaN */
/* All-ones exponent and a copy of the significand */
return f_sgn + 0x7f800000u + (((uint32_t)(h & 0x03ffu)) << 13);
default: /* normalized */
/* Just need to adjust the exponent and shift */
return f_sgn + (((uint32_t)(h & 0x7fffu) + 0x1c000u) << 13);
}
}
hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa);
*/
hf = 0; //denormals do not work for 3D, convert to zero
static _ALWAYS_INLINE_ float math_halfptr_to_float(const uint16_t *h) {
union {
uint32_t u32;
float f32;
} u;
u.u32 = math_halfbits_to_floatbits(*h);
return u.f32;
}
static _ALWAYS_INLINE_ float math_half_to_float(const uint16_t h) {
return math_halfptr_to_float(&h);
}
static _ALWAYS_INLINE_ uint16_t math_make_half_float(float f) {
union {
float fv;
uint32_t ui;
} ci;
ci.fv = f;
uint32_t x = ci.ui;
uint32_t sign = (unsigned short)(x >> 31);
uint32_t mantissa;
uint32_t exp;
uint16_t hf;
// get mantissa
mantissa = x & ((1 << 23) - 1);
// get exponent bits
exp = x & (0xFF << 23);
if (exp >= 0x47800000) {
// check if the original single precision float number is a NaN
if (mantissa && (exp == (0xFF << 23))) {
// we have a single precision NaN
mantissa = (1 << 23) - 1;
} else {
hf = (((uint16_t)sign) << 15) |
(uint16_t)((exp - 0x38000000) >> 13) |
(uint16_t)(mantissa >> 13);
// 16-bit half-float representation stores number as Inf
mantissa = 0;
}
hf = (((uint16_t)sign) << 15) | (uint16_t)((0x1F << 10)) |
(uint16_t)(mantissa >> 13);
}
// check if exponent is <= -15
else if (exp <= 0x38000000) {
/*// store a denorm half-float value or zero
exp = (0x38000000 - exp) >> 23;
mantissa >>= (14 + exp);
return hf;
hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa);
*/
hf = 0; //denormals do not work for 3D, convert to zero
} else {
hf = (((uint16_t)sign) << 15) |
(uint16_t)((exp - 0x38000000) >> 13) |
(uint16_t)(mantissa >> 13);
}
static _ALWAYS_INLINE_ float snap_scalar(float p_offset, float p_step, float p_target) {
return p_step != 0 ? Math::stepify(p_target - p_offset, p_step) + p_offset : p_target;
}
return hf;
}
static _ALWAYS_INLINE_ float snap_scalar_separation(float p_offset, float p_step, float p_target, float p_separation) {
if (p_step != 0) {
float a = Math::stepify(p_target - p_offset, p_step + p_separation) + p_offset;
float b = a;
if (p_target >= 0) {
b -= p_separation;
} else {
b += p_step;
}
return (Math::abs(p_target - a) < Math::abs(p_target - b)) ? a : b;
float math_stepifyf(float p_value, float p_step);
double math_stepifyd(double p_value, double p_step);
static _ALWAYS_INLINE_ float math_snap_scalar(float p_offset, float p_step, float p_target) {
return p_step != 0 ? math_stepifyf(p_target - p_offset, p_step) + p_offset : p_target;
}
static _ALWAYS_INLINE_ float math_snap_scalar_separation(float p_offset, float p_step, float p_target, float p_separation) {
if (p_step != 0) {
float a = math_stepifyf(p_target - p_offset, p_step + p_separation) + p_offset;
float b = a;
if (p_target >= 0) {
b -= p_separation;
} else {
b += p_step;
}
return p_target;
return (math_absf(p_target - a) < math_absf(p_target - b)) ? a : b;
}
};
return p_target;
}
#endif // MATH_FUNCS_H

View File

@ -32,7 +32,6 @@
#define VECTOR2_H
#include "core/math/math_funcs.h"
#include "core/ustring.h"
struct Vector2i;

417
core/typedefs.h Normal file
View File

@ -0,0 +1,417 @@
/*************************************************************************/
/* typedefs.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef TYPEDEFS_H
#define TYPEDEFS_H
#include <stddef.h>
/**
* Basic definitions and simple functions to be used everywhere.
*/
//#include "platform_config.h"
#ifndef _STR
#define _STR(m_x) #m_x
#define _MKSTR(m_x) _STR(m_x)
#endif
//should always inline no matter what
#ifndef _ALWAYS_INLINE_
#if defined(__GNUC__) && (__GNUC__ >= 4)
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
#elif defined(__llvm__)
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#define _ALWAYS_INLINE_ __forceinline
#else
#define _ALWAYS_INLINE_ inline
#endif
#endif
// Should always inline, except in dev builds because it makes debugging harder.
#ifndef _FORCE_INLINE_
#ifdef DEV_ENABLED
#define _FORCE_INLINE_ inline
#else
#define _FORCE_INLINE_ _ALWAYS_INLINE_
#endif
#endif
// No discard allows the compiler to flag warnings if we don't use the return value of functions / classes
#ifndef _NO_DISCARD_
// c++ 17 onwards
#if __cplusplus >= 201703L
#define _NO_DISCARD_ [[nodiscard]]
#else
// __warn_unused_result__ supported on clang and GCC
#if (defined(__clang__) || defined(__GNUC__)) && defined(__has_attribute)
#if __has_attribute(__warn_unused_result__)
#define _NO_DISCARD_ __attribute__((__warn_unused_result__))
#endif
#endif
// Visual Studio 2012 onwards
#if _MSC_VER >= 1700
#define _NO_DISCARD_ _Check_return_
#endif
// If nothing supported, just noop the macro
#ifndef _NO_DISCARD_
#define _NO_DISCARD_
#endif
#endif // not c++ 17
#endif // not defined _NO_DISCARD_
// In some cases _NO_DISCARD_ will get false positives,
// we can prevent the warning in specific cases by preceding the call with a cast.
#ifndef _ALLOW_DISCARD_
#define _ALLOW_DISCARD_ (void)
#endif
// GCC (prior to c++ 17) Does not seem to support no discard with classes, only functions.
// So we will use a specific macro for classes.
#ifndef _NO_DISCARD_CLASS_
#if (defined(__clang__) || defined(_MSC_VER))
#define _NO_DISCARD_CLASS_ _NO_DISCARD_
#else
#define _NO_DISCARD_CLASS_
#endif
#endif
//custom, gcc-safe offsetof, because gcc complains a lot.
/*
template <class T>
T *_nullptr() {
T *t = NULL;
return t;
}
#define OFFSET_OF(st, m) \
((size_t)((char *)&(_nullptr<st>()->m) - (char *)0))
*/
/**
* Some platforms (devices) don't define NULL
*/
#ifndef NULL
#define NULL 0
#endif
/**
* Windows badly defines a lot of stuff we'll never use. Undefine it.
*/
#ifdef _WIN32
#undef min // override standard definition
#undef max // override standard definition
#undef ERROR // override (really stupid) wingdi.h standard definition
#undef DELETE // override (another really stupid) winnt.h standard definition
#undef MessageBox // override winuser.h standard definition
#undef MIN // override standard definition
#undef MAX // override standard definition
#undef CLAMP // override standard definition
#undef Error
#undef OK
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#endif
#include "core/int_types.h"
#include "core/error_list.h"
/** Generic ABS function, for math uses please use Math::abs */
#ifndef ABS
#define ABS(m_v) (((m_v) < 0) ? (-(m_v)) : (m_v))
#endif
#define ABSDIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
#ifndef SGN
#define SGN(m_v) (((m_v) < 0) ? (-1.0f) : (+1.0f))
#endif
#ifndef MIN
#define MIN(m_a, m_b) (((m_a) < (m_b)) ? (m_a) : (m_b))
#endif
#ifndef MAX
#define MAX(m_a, m_b) (((m_a) > (m_b)) ? (m_a) : (m_b))
#endif
#ifndef CLAMP
#define CLAMP(m_a, m_min, m_max) (((m_a) < (m_min)) ? (m_min) : (((m_a) > (m_max)) ? m_max : m_a))
#endif
/** Generic swap template */
#ifndef SWAP
/*
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
y = aux;
}
*/
#define SWAP(type, a, b) \
{ \
type __swap_temp; \
__swap_temp = (b); \
(b) = (a); \
(a) = __swap_temp; \
}
#endif //swap
/* clang-format off */
#define HEX2CHR(m_hex) \
((m_hex >= '0' && m_hex <= '9') ? (m_hex - '0') : \
((m_hex >= 'A' && m_hex <= 'F') ? (10 + m_hex - 'A') : \
((m_hex >= 'a' && m_hex <= 'f') ? (10 + m_hex - 'a') : 0)))
/* clang-format on */
// Macro to check whether we are compiled by clang
// and we have a specific builtin
#if defined(__llvm__) && defined(__has_builtin)
#define _llvm_has_builtin(x) __has_builtin(x)
#else
#define _llvm_has_builtin(x) 0
#endif
#if (defined(__GNUC__) && (__GNUC__ >= 5)) || _llvm_has_builtin(__builtin_mul_overflow)
#define _mul_overflow __builtin_mul_overflow
#endif
#if (defined(__GNUC__) && (__GNUC__ >= 5)) || _llvm_has_builtin(__builtin_add_overflow)
#define _add_overflow __builtin_add_overflow
#endif
/** Function to find the next power of 2 to an integer */
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x - (x >> 1);
}
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
unsigned int nx = next_power_of_2(x);
unsigned int px = previous_power_of_2(x);
return (nx - x) > (x - px) ? px : nx;
}
// We need this definition inside the function below.
static inline int get_shift_from_power_of_2(unsigned int p_pixel);
/*
template <class T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x;
// The number of operations on x is the base two logarithm
// of the p_number of bits in the type. Add three to account
// for sizeof(T) being in bytes.
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
// If the compiler is smart, it unrolls this loop
// If its dumb, this is a bit slow.
for (size_t i = 0; i < num; i++) {
x |= x >> (1 << i);
}
return ++x;
}*/
/** Function to find the nearest (bigger) power of 2 to an integer */
static inline unsigned int nearest_shift(unsigned int p_number) {
for (int i = 30; i >= 0; i--) {
if (p_number & (1 << i)) {
return i + 1;
}
}
return 0;
}
/** get a shift value from a power of 2 */
static inline int get_shift_from_power_of_2(unsigned int p_pixel) {
// return a GL_TEXTURE_SIZE_ENUM
for (unsigned int i = 0; i < 32; i++) {
if (p_pixel == (unsigned int)(1 << i)) {
return i;
}
}
return -1;
}
/** Swap 16 bits value for endianness */
#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap16)
#define BSWAP16(x) __builtin_bswap16(x)
#else
static inline uint16_t BSWAP16(uint16_t x) {
return (x >> 8) | (x << 8);
}
#endif
/** Swap 32 bits value for endianness */
#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap32)
#define BSWAP32(x) __builtin_bswap32(x)
#else
static inline uint32_t BSWAP32(uint32_t x) {
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
}
#endif
/** Swap 64 bits value for endianness */
#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap64)
#define BSWAP64(x) __builtin_bswap64(x)
#else
static inline uint64_t BSWAP64(uint64_t x) {
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
#endif
/** When compiling with RTTI, we can add an "extra"
* layer of safeness in many operations, so dynamic_cast
* is used besides casting by enum.
*/
/*
template <class T>
struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};*/
void _global_lock();
void _global_unlock();
/*
struct _GlobalLock {
_GlobalLock() { _global_lock(); }
~_GlobalLock() { _global_unlock(); }
};
*/
#define GLOBAL_LOCK_FUNCTION _GlobalLock _global_lock_;
/*
#ifdef NO_SAFE_CAST
#define SAFE_CAST static_cast
#else
#define SAFE_CAST dynamic_cast
#endif
*/
#define MT_SAFE
#define __STRX(m_index) #m_index
#define __STR(m_index) __STRX(m_index)
#ifdef __GNUC__
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) x
#define unlikely(x) x
#endif
#if defined(__GNUC__)
#define _PRINTF_FORMAT_ATTRIBUTE_2_0 __attribute__((format(printf, 2, 0)))
#define _PRINTF_FORMAT_ATTRIBUTE_2_3 __attribute__((format(printf, 2, 3)))
#else
#define _PRINTF_FORMAT_ATTRIBUTE_2_0
#define _PRINTF_FORMAT_ATTRIBUTE_2_3
#endif
/** This is needed due to a strange OpenGL API that expects a pointer
* type for an argument that is actually an offset.
*/
#define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr))
/** Hint for compilers that this fallthrough in a switch is intentional.
* Can be replaced by [[fallthrough]] annotation if we move to C++17.
* Including conditional support for it for people who set -std=c++17
* themselves.
* Requires a trailing semicolon when used.
*/
#if __cplusplus >= 201703L
#define FALLTHROUGH [[fallthrough]]
#elif defined(__GNUC__) && __GNUC__ >= 7
#define FALLTHROUGH __attribute__((fallthrough))
#elif defined(__llvm__) && __cplusplus >= 201103L && defined(__has_feature)
#if __has_feature(cxx_attributes) && defined(__has_warning)
#if __has_warning("-Wimplicit-fallthrough")
#define FALLTHROUGH [[clang::fallthrough]]
#endif
#endif
#endif
#ifndef FALLTHROUGH
#define FALLTHROUGH
#endif
// Limit the depth of recursive algorithms when dealing with Array/Dictionary
#define MAX_RECURSION 100
#endif // TYPEDEFS_H