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