diff --git a/core/math/math.h b/core/math/math.h index 49a24a5..74c9136 100644 --- a/core/math/math.h +++ b/core/math/math.h @@ -213,6 +213,110 @@ public: return isinf(p_val); #endif } + + // Taken from the Godot Engine (MIT License) + // Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. + // Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). + 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_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); + } + } + + // Taken from the Godot Engine (MIT License) + // Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. + // Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). + 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; + } + + // Taken from the Godot Engine (MIT License) + // Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. + // Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). + static _ALWAYS_INLINE_ float half_to_float(const uint16_t h) { + return halfptr_to_float(&h); + } + + // Taken from the Godot Engine (MIT License) + // Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. + // Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). + 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; + } + 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); + + 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); + } + + return hf; + } }; #ifndef ABS