diff --git a/src/common/Endian.h b/src/common/Endian.h index 05282ce260..284e595631 100644 --- a/src/common/Endian.h +++ b/src/common/Endian.h @@ -166,15 +166,9 @@ inline uint64_t USwap64(uint64_t x) inline float SwapFloat(float x) { - union - { - float f; - int i; - unsigned int ui; - } fi; - fi.f = x; - fi.i = Swap32(fi.i); - return fi.f; + int32_t bits = Util::bit_cast(x); + bits = Swap32(bits); + return Util::bit_cast(bits); } #ifdef Q3_LITTLE_ENDIAN diff --git a/src/common/Util.h b/src/common/Util.h index 6bc3dec58d..b2e321ba43 100644 --- a/src/common/Util.h +++ b/src/common/Util.h @@ -44,6 +44,17 @@ char *PRINTF_LIKE(1) va( const char *format, ... ); namespace Util { +// C++20 std::bit_cast +template +ToT bit_cast(FromT from) +{ + static_assert(sizeof(ToT) == sizeof(FromT), "bit_cast: sizes must be equal"); + + ToT to; + memcpy(&to, &from, sizeof(to)); + return to; +} + // Binary search function which returns an iterator to the result or end if not found template Iter binary_find(Iter begin, Iter end, const T& value) diff --git a/src/engine/qcommon/q_shared.h b/src/engine/qcommon/q_shared.h index 9d4649a90d..4d903933b5 100644 --- a/src/engine/qcommon/q_shared.h +++ b/src/engine/qcommon/q_shared.h @@ -144,13 +144,6 @@ void ignore_result(T) {} using uint = unsigned int; enum class qtrinary {qno, qyes, qmaybe}; - union floatint_t - { - float f; - int i; - uint ui; - }; - //============================================================= #include "common/Platform.h" @@ -351,22 +344,6 @@ extern const quat_t quatIdentity; #define Q_ftol(x) ((long)(x)) - inline unsigned int Q_floatBitsToUint( float number ) - { - floatint_t t; - - t.f = number; - return t.ui; - } - - inline float Q_uintBitsToFloat( unsigned int number ) - { - floatint_t t; - - t.ui = number; - return t.f; - } - // Overall relative error bound (ignoring unknown powerpc case): 5 * 10^-6 // https://en.wikipedia.org/wiki/Fast_inverse_square_root#/media/File:2nd-iter.png inline float Q_rsqrt( float number ) @@ -379,7 +356,7 @@ extern const quat_t quatIdentity; // SSE rsqrt relative error bound: 3.7 * 10^-4 _mm_store_ss( &y, _mm_rsqrt_ss( _mm_load_ss( &number ) ) ); #else - y = Q_uintBitsToFloat( 0x5f3759df - (Q_floatBitsToUint( number ) >> 1) ); + y = Util::bit_cast( 0x5f3759df - ( Util::bit_cast( number ) >> 1 ) ); y *= ( 1.5f - ( x * y * y ) ); // initial iteration // relative error bound after the initial iteration: 1.8 * 10^-3 #endif diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 9c75fa9c1c..8f663b6e25 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -125,11 +125,10 @@ static inline void snorm16ToFloat( const i16vec4_t in, vec4_t out ) static inline f16_t floatToHalf( float in ) { static float scale = powf(2.0f, 15 - 127); - floatint_t fi; - fi.f = in * scale; + uint32_t ui = Util::bit_cast( in * scale ); - return { uint16_t(((fi.ui & 0x80000000) >> 16) | ((fi.ui & 0x0fffe000) >> 13)) }; + return { uint16_t(((ui & 0x80000000) >> 16) | ((ui & 0x0fffe000) >> 13)) }; } static inline void floatToHalf( const vec4_t in, f16vec4_t out ) { @@ -140,10 +139,9 @@ static inline void floatToHalf( const vec4_t in, f16vec4_t out ) } static inline float halfToFloat( f16_t in ) { static float scale = powf(2.0f, 127 - 15); - floatint_t fi; - fi.ui = (((unsigned int)in.bits & 0x8000) << 16) | (((unsigned int)in.bits & 0x7fff) << 13); - return fi.f * scale; + uint32_t ui = (((unsigned int)in.bits & 0x8000) << 16) | (((unsigned int)in.bits & 0x7fff) << 13); + return Util::bit_cast(ui) * scale; } static inline void halfToFloat( const f16vec4_t in, vec4_t out ) {