| 1 | namespace glm{ |
| 2 | namespace detail |
| 3 | { |
| 4 | #if (GLM_COMPILER & GLM_COMPILER_VC) |
| 5 | # pragma warning(push) |
| 6 | # pragma warning(disable: 4746) // volatile access of 'f' is subject to /volatile:<iso|ms> setting; consider using __iso_volatile_load/store intrinsic functions |
| 7 | #endif |
| 8 | |
| 9 | // This function cause a build error on Github C.I. |
| 10 | #if (!(GLM_COMPILER & GLM_COMPILER_VC) && (GLM_ARCH & GLM_ARCH_ARM_BIT)) |
| 11 | GLM_FUNC_QUALIFIER float overflow() |
| 12 | { |
| 13 | volatile float f = 1e10; |
| 14 | |
| 15 | for(int i = 0; i < 10; ++i) |
| 16 | f = f * f; // this will overflow before the for loop terminates |
| 17 | return f; |
| 18 | } |
| 19 | #else |
| 20 | GLM_FUNC_QUALIFIER float overflow() |
| 21 | { |
| 22 | return 0.0f; |
| 23 | } |
| 24 | #endif// |
| 25 | |
| 26 | #if (GLM_COMPILER & GLM_COMPILER_VC) |
| 27 | # pragma warning(pop) |
| 28 | #endif |
| 29 | |
| 30 | union uif32 |
| 31 | { |
| 32 | GLM_FUNC_QUALIFIER uif32() : |
| 33 | i(0) |
| 34 | {} |
| 35 | |
| 36 | GLM_FUNC_QUALIFIER uif32(float f_) : |
| 37 | f(f_) |
| 38 | {} |
| 39 | |
| 40 | GLM_FUNC_QUALIFIER uif32(unsigned int i_) : |
| 41 | i(i_) |
| 42 | {} |
| 43 | |
| 44 | float f; |
| 45 | unsigned int i; |
| 46 | }; |
| 47 | |
| 48 | GLM_FUNC_QUALIFIER float toFloat32(hdata value) |
| 49 | { |
| 50 | int s = (value >> 15) & 0x00000001; |
| 51 | int e = (value >> 10) & 0x0000001f; |
| 52 | int m = value & 0x000003ff; |
| 53 | |
| 54 | if(e == 0) |
| 55 | { |
| 56 | if(m == 0) |
| 57 | { |
| 58 | // |
| 59 | // Plus or minus zero |
| 60 | // |
| 61 | |
| 62 | detail::uif32 result; |
| 63 | result.i = static_cast<unsigned int>(s << 31); |
| 64 | return result.f; |
| 65 | } |
| 66 | else |
| 67 | { |
| 68 | // |
| 69 | // Denormalized number -- renormalize it |
| 70 | // |
| 71 | |
| 72 | while(!(m & 0x00000400)) |
| 73 | { |
| 74 | m <<= 1; |
| 75 | e -= 1; |
| 76 | } |
| 77 | |
| 78 | e += 1; |
| 79 | m &= ~0x00000400; |
| 80 | } |
| 81 | } |
| 82 | else if(e == 31) |
| 83 | { |
| 84 | if(m == 0) |
| 85 | { |
| 86 | // |
| 87 | // Positive or negative infinity |
| 88 | // |
| 89 | |
| 90 | uif32 result; |
| 91 | result.i = static_cast<unsigned int>((s << 31) | 0x7f800000); |
| 92 | return result.f; |
| 93 | } |
| 94 | else |
| 95 | { |
| 96 | // |
| 97 | // Nan -- preserve sign and significand bits |
| 98 | // |
| 99 | |
| 100 | uif32 result; |
| 101 | result.i = static_cast<unsigned int>((s << 31) | 0x7f800000 | (m << 13)); |
| 102 | return result.f; |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | // |
| 107 | // Normalized number |
| 108 | // |
| 109 | |
| 110 | e = e + (127 - 15); |
| 111 | m = m << 13; |
| 112 | |
| 113 | // |
| 114 | // Assemble s, e and m. |
| 115 | // |
| 116 | |
| 117 | uif32 Result; |
| 118 | Result.i = static_cast<unsigned int>((s << 31) | (e << 23) | m); |
| 119 | return Result.f; |
| 120 | } |
| 121 | |
| 122 | GLM_FUNC_QUALIFIER hdata toFloat16(float const& f) |
| 123 | { |
| 124 | uif32 Entry; |
| 125 | Entry.f = f; |
| 126 | int i = static_cast<int>(Entry.i); |
| 127 | |
| 128 | // |
| 129 | // Our floating point number, f, is represented by the bit |
| 130 | // pattern in integer i. Disassemble that bit pattern into |
| 131 | // the sign, s, the exponent, e, and the significand, m. |
| 132 | // Shift s into the position where it will go in the |
| 133 | // resulting half number. |
| 134 | // Adjust e, accounting for the different exponent bias |
| 135 | // of float and half (127 versus 15). |
| 136 | // |
| 137 | |
| 138 | int s = (i >> 16) & 0x00008000; |
| 139 | int e = ((i >> 23) & 0x000000ff) - (127 - 15); |
| 140 | int m = i & 0x007fffff; |
| 141 | |
| 142 | // |
| 143 | // Now reassemble s, e and m into a half: |
| 144 | // |
| 145 | |
| 146 | if(e <= 0) |
| 147 | { |
| 148 | if(e < -10) |
| 149 | { |
| 150 | // |
| 151 | // E is less than -10. The absolute value of f is |
| 152 | // less than half_MIN (f may be a small normalized |
| 153 | // float, a denormalized float or a zero). |
| 154 | // |
| 155 | // We convert f to a half zero. |
| 156 | // |
| 157 | |
| 158 | return hdata(s); |
| 159 | } |
| 160 | |
| 161 | // |
| 162 | // E is between -10 and 0. F is a normalized float, |
| 163 | // whose magnitude is less than __half_NRM_MIN. |
| 164 | // |
| 165 | // We convert f to a denormalized half. |
| 166 | // |
| 167 | |
| 168 | m = (m | 0x00800000) >> (1 - e); |
| 169 | |
| 170 | // |
| 171 | // Round to nearest, round "0.5" up. |
| 172 | // |
| 173 | // Rounding may cause the significand to overflow and make |
| 174 | // our number normalized. Because of the way a half's bits |
| 175 | // are laid out, we don't have to treat this case separately; |
| 176 | // the code below will handle it correctly. |
| 177 | // |
| 178 | |
| 179 | if(m & 0x00001000) |
| 180 | m += 0x00002000; |
| 181 | |
| 182 | // |
| 183 | // Assemble the half from s, e (zero) and m. |
| 184 | // |
| 185 | |
| 186 | return hdata(s | (m >> 13)); |
| 187 | } |
| 188 | else if(e == 0xff - (127 - 15)) |
| 189 | { |
| 190 | if(m == 0) |
| 191 | { |
| 192 | // |
| 193 | // F is an infinity; convert f to a half |
| 194 | // infinity with the same sign as f. |
| 195 | // |
| 196 | |
| 197 | return hdata(s | 0x7c00); |
| 198 | } |
| 199 | else |
| 200 | { |
| 201 | // |
| 202 | // F is a NAN; we produce a half NAN that preserves |
| 203 | // the sign bit and the 10 leftmost bits of the |
| 204 | // significand of f, with one exception: If the 10 |
| 205 | // leftmost bits are all zero, the NAN would turn |
| 206 | // into an infinity, so we have to set at least one |
| 207 | // bit in the significand. |
| 208 | // |
| 209 | |
| 210 | m >>= 13; |
| 211 | |
| 212 | return hdata(s | 0x7c00 | m | (m == 0)); |
| 213 | } |
| 214 | } |
| 215 | else |
| 216 | { |
| 217 | // |
| 218 | // E is greater than zero. F is a normalized float. |
| 219 | // We try to convert f to a normalized half. |
| 220 | // |
| 221 | |
| 222 | // |
| 223 | // Round to nearest, round "0.5" up |
| 224 | // |
| 225 | |
| 226 | if(m & 0x00001000) |
| 227 | { |
| 228 | m += 0x00002000; |
| 229 | |
| 230 | if(m & 0x00800000) |
| 231 | { |
| 232 | m = 0; // overflow in significand, |
| 233 | e += 1; // adjust exponent |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | // |
| 238 | // Handle exponent overflow |
| 239 | // |
| 240 | |
| 241 | if (e > 30) |
| 242 | { |
| 243 | overflow(); // Cause a hardware floating point overflow; |
| 244 | |
| 245 | return hdata(s | 0x7c00); |
| 246 | // if this returns, the half becomes an |
| 247 | } // infinity with the same sign as f. |
| 248 | |
| 249 | // |
| 250 | // Assemble the half from s, e and m. |
| 251 | // |
| 252 | |
| 253 | return hdata(s | (e << 10) | (m >> 13)); |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | }//namespace detail |
| 258 | }//namespace glm |