Home | History | Annotate | Download | only in detail
      1 ///////////////////////////////////////////////////////////////////////////////////
      2 /// OpenGL Mathematics (glm.g-truc.net)
      3 ///
      4 /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net)
      5 ///
      6 /// This half implementation is based on OpenEXR which is Copyright (c) 2002, 
      7 /// Industrial Light & Magic, a division of Lucas Digital Ltd. LLC
      8 ///
      9 /// Permission is hereby granted, free of charge, to any person obtaining a copy
     10 /// of this software and associated documentation files (the "Software"), to deal
     11 /// in the Software without restriction, including without limitation the rights
     12 /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     13 /// copies of the Software, and to permit persons to whom the Software is
     14 /// furnished to do so, subject to the following conditions:
     15 /// 
     16 /// The above copyright notice and this permission notice shall be included in
     17 /// all copies or substantial portions of the Software.
     18 /// 
     19 /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     24 /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     25 /// THE SOFTWARE.
     26 ///
     27 /// @ref core
     28 /// @file glm/core/type_half.inl
     29 /// @date 2008-08-17 / 2011-06-15
     30 /// @author Christophe Riccio
     31 ///////////////////////////////////////////////////////////////////////////////////
     32 
     33 namespace glm{
     34 namespace detail
     35 {
     36 	GLM_FUNC_QUALIFIER float overflow()
     37 	{
     38 		volatile float f = 1e10;
     39 
     40 		for(int i = 0; i < 10; ++i)	
     41 			f *= f;             // this will overflow before
     42 								// the forloop terminates
     43 		return f;
     44 	}
     45 
     46 	union uif32
     47 	{
     48 		GLM_FUNC_QUALIFIER uif32() :
     49 			i(0)
     50 		{}
     51 
     52 		GLM_FUNC_QUALIFIER uif32(float f) :
     53 			f(f)
     54 		{}
     55 
     56 		GLM_FUNC_QUALIFIER uif32(uint32 i) :
     57 			i(i)
     58 		{}
     59 
     60 		float f;
     61 		uint32 i;
     62 	};
     63 
     64 	GLM_FUNC_QUALIFIER float toFloat32(hdata value)
     65 	{
     66 		int s = (value >> 15) & 0x00000001;
     67 		int e = (value >> 10) & 0x0000001f;
     68 		int m =  value        & 0x000003ff;
     69 
     70 		if(e == 0)
     71 		{
     72 			if(m == 0)
     73 			{
     74 				//
     75 				// Plus or minus zero
     76 				//
     77 
     78 				detail::uif32 result;
     79 				result.i = (unsigned int)(s << 31);
     80 				return result.f;
     81 			}
     82 			else
     83 			{
     84 				//
     85 				// Denormalized number -- renormalize it
     86 				//
     87 
     88 				while(!(m & 0x00000400))
     89 				{
     90 					m <<= 1;
     91 					e -=  1;
     92 				}
     93 
     94 				e += 1;
     95 				m &= ~0x00000400;
     96 			}
     97 		}
     98 		else if(e == 31)
     99 		{
    100 			if(m == 0)
    101 			{
    102 				//
    103 				// Positive or negative infinity
    104 				//
    105 
    106 				uif32 result;
    107 				result.i = (unsigned int)((s << 31) | 0x7f800000);
    108 				return result.f;
    109 			}
    110 			else
    111 			{
    112 				//
    113 				// Nan -- preserve sign and significand bits
    114 				//
    115 
    116 				uif32 result;
    117 				result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13));
    118 				return result.f;
    119 			}
    120 		}
    121 
    122 		//
    123 		// Normalized number
    124 		//
    125 
    126 		e = e + (127 - 15);
    127 		m = m << 13;
    128 
    129 		//
    130 		// Assemble s, e and m.
    131 		//
    132 
    133 		uif32 Result;
    134 		Result.i = (unsigned int)((s << 31) | (e << 23) | m);
    135 		return Result.f;
    136 	}
    137 
    138 	GLM_FUNC_QUALIFIER hdata toFloat16(float const & f)
    139 	{
    140 		uif32 Entry;
    141 		Entry.f = f;
    142 		int i = (int)Entry.i;
    143 
    144 		//
    145 		// Our floating point number, f, is represented by the bit
    146 		// pattern in integer i.  Disassemble that bit pattern into
    147 		// the sign, s, the exponent, e, and the significand, m.
    148 		// Shift s into the position where it will go in in the
    149 		// resulting half number.
    150 		// Adjust e, accounting for the different exponent bias
    151 		// of float and half (127 versus 15).
    152 		//
    153 
    154 		int s =  (i >> 16) & 0x00008000;
    155 		int e = ((i >> 23) & 0x000000ff) - (127 - 15);
    156 		int m =   i        & 0x007fffff;
    157 
    158 		//
    159 		// Now reassemble s, e and m into a half:
    160 		//
    161 
    162 		if(e <= 0)
    163 		{
    164 			if(e < -10)
    165 			{
    166 				//
    167 				// E is less than -10.  The absolute value of f is
    168 				// less than half_MIN (f may be a small normalized
    169 				// float, a denormalized float or a zero).
    170 				//
    171 				// We convert f to a half zero.
    172 				//
    173 
    174 				return hdata(s);
    175 			}
    176 
    177 			//
    178 			// E is between -10 and 0.  F is a normalized float,
    179 			// whose magnitude is less than __half_NRM_MIN.
    180 			//
    181 			// We convert f to a denormalized half.
    182 			// 
    183 
    184 			m = (m | 0x00800000) >> (1 - e);
    185 
    186 			//
    187 			// Round to nearest, round "0.5" up.
    188 			//
    189 			// Rounding may cause the significand to overflow and make
    190 			// our number normalized.  Because of the way a half's bits
    191 			// are laid out, we don't have to treat this case separately;
    192 			// the code below will handle it correctly.
    193 			// 
    194 
    195 			if(m & 0x00001000) 
    196 				m += 0x00002000;
    197 
    198 			//
    199 			// Assemble the half from s, e (zero) and m.
    200 			//
    201 
    202 			return hdata(s | (m >> 13));
    203 		}
    204 		else if(e == 0xff - (127 - 15))
    205 		{
    206 			if(m == 0)
    207 			{
    208 				//
    209 				// F is an infinity; convert f to a half
    210 				// infinity with the same sign as f.
    211 				//
    212 
    213 				return hdata(s | 0x7c00);
    214 			}
    215 			else
    216 			{
    217 				//
    218 				// F is a NAN; we produce a half NAN that preserves
    219 				// the sign bit and the 10 leftmost bits of the
    220 				// significand of f, with one exception: If the 10
    221 				// leftmost bits are all zero, the NAN would turn 
    222 				// into an infinity, so we have to set at least one
    223 				// bit in the significand.
    224 				//
    225 
    226 				m >>= 13;
    227 
    228 				return hdata(s | 0x7c00 | m | (m == 0));
    229 			}
    230 		}
    231 		else
    232 		{
    233 			//
    234 			// E is greater than zero.  F is a normalized float.
    235 			// We try to convert f to a normalized half.
    236 			//
    237 
    238 			//
    239 			// Round to nearest, round "0.5" up
    240 			//
    241 
    242 			if(m &  0x00001000)
    243 			{
    244 				m += 0x00002000;
    245 
    246 				if(m & 0x00800000)
    247 				{
    248 					m =  0;     // overflow in significand,
    249 					e += 1;     // adjust exponent
    250 				}
    251 			}
    252 
    253 			//
    254 			// Handle exponent overflow
    255 			//
    256 
    257 			if (e > 30)
    258 			{
    259 				overflow();        // Cause a hardware floating point overflow;
    260 
    261 				return hdata(s | 0x7c00);
    262 				// if this returns, the half becomes an
    263 			}   // infinity with the same sign as f.
    264 
    265 			//
    266 			// Assemble the half from s, e and m.
    267 			//
    268 
    269 			return hdata(s | (e << 10) | (m >> 13));
    270 		}
    271 	}
    272 
    273 }//namespace detail
    274 }//namespace glm
    275