diff --git a/SConstruct b/SConstruct index 49ee6dc..75ce25d 100644 --- a/SConstruct +++ b/SConstruct @@ -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() diff --git a/core/error_list.h b/core/error_list.h new file mode 100644 index 0000000..777d787 --- /dev/null +++ b/core/error_list.h @@ -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 diff --git a/core/int_types.h b/core/int_types.h new file mode 100644 index 0000000..8007906 --- /dev/null +++ b/core/int_types.h @@ -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 + +#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 +#endif + +#endif diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.c similarity index 71% rename from core/math/math_funcs.cpp rename to core/math/math_funcs.c index 21c4e16..242119c 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.c @@ -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; } diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 93e2423..583acbc 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -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 #include -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 diff --git a/core/math/vector2.h b/core/math/vector2.h index b8965a0..3839e2d 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -32,7 +32,6 @@ #define VECTOR2_H #include "core/math/math_funcs.h" -#include "core/ustring.h" struct Vector2i; diff --git a/core/typedefs.h b/core/typedefs.h new file mode 100644 index 0000000..1667fab --- /dev/null +++ b/core/typedefs.h @@ -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 + +/** + * 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 +T *_nullptr() { + T *t = NULL; + return t; +} + +#define OFFSET_OF(st, m) \ + ((size_t)((char *)&(_nullptr()->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 +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 +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 +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