u_format_r11g11b10f.h revision 3d7477206d7a345eb53df5c1288a5b34e83bc2d8
1/* 2 * Copyright (C) 2011 Marek Olšák <maraeo@gmail.com> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24/* Based on code from The OpenGL Programming Guide / 7th Edition, Appendix J. 25 * Available here: http://www.opengl-redbook.com/appendices/ 26 * The algorithm in the book contains a bug though, which is fixed in the code 27 * below. 28 */ 29 30#define UF11_EXPONENT_BIAS 15 31#define UF11_EXPONENT_BITS 0x1F 32#define UF11_EXPONENT_SHIFT 6 33#define UF11_MANTISSA_BITS 0x3F 34#define UF11_MANTISSA_SHIFT (23 - UF11_EXPONENT_SHIFT) 35#define UF11_MAX_EXPONENT (UF11_EXPONENT_BITS << UF11_EXPONENT_SHIFT) 36 37#define UF10_EXPONENT_BIAS 15 38#define UF10_EXPONENT_BITS 0x1F 39#define UF10_EXPONENT_SHIFT 5 40#define UF10_MANTISSA_BITS 0x1F 41#define UF10_MANTISSA_SHIFT (23 - UF10_EXPONENT_SHIFT) 42#define UF10_MAX_EXPONENT (UF10_EXPONENT_BITS << UF10_EXPONENT_SHIFT) 43 44#define F32_INFINITY 0x7f800000 45 46static INLINE unsigned f32_to_uf11(float val) 47{ 48 union { 49 float f; 50 uint32_t ui; 51 } f32 = {val}; 52 53 uint16_t uf11 = 0; 54 55 /* Decode little-endian 32-bit floating-point value */ 56 int sign = (f32.ui >> 16) & 0x8000; 57 /* Map exponent to the range [-127,128] */ 58 int exponent = ((f32.ui >> 23) & 0xff) - 127; 59 int mantissa = f32.ui & 0x007fffff; 60 61 if (sign) return 0; 62 63 if (exponent == 128) { /* Infinity or NaN */ 64 uf11 = UF11_MAX_EXPONENT; 65 if (mantissa) uf11 |= (mantissa & UF11_MANTISSA_BITS); 66 } 67 else if (exponent > 15) { /* Overflow - flush to Infinity */ 68 uf11 = UF11_MAX_EXPONENT; 69 } 70 else if (exponent > -15) { /* Representable value */ 71 exponent += UF11_EXPONENT_BIAS; 72 mantissa >>= UF11_MANTISSA_SHIFT; 73 uf11 = exponent << UF11_EXPONENT_SHIFT | mantissa; 74 } 75 76 return uf11; 77} 78 79static INLINE float uf11_to_f32(uint16_t val) 80{ 81 union { 82 float f; 83 uint32_t ui; 84 } f32; 85 86 int exponent = (val & 0x07c0) >> UF11_EXPONENT_SHIFT; 87 int mantissa = (val & 0x003f); 88 89 f32.f = 0.0; 90 91 if (exponent == 0) { 92 if (mantissa != 0) { 93 const float scale = 1.0 / (1 << 20); 94 f32.f = scale * mantissa; 95 } 96 } 97 else if (exponent == 31) { 98 f32.ui = F32_INFINITY | mantissa; 99 } 100 else { 101 float scale, decimal; 102 exponent -= 15; 103 if (exponent < 0) { 104 scale = 1.0 / (1 << -exponent); 105 } 106 else { 107 scale = 1 << exponent; 108 } 109 decimal = 1.0 + (float) mantissa / 64; 110 f32.f = scale * decimal; 111 } 112 113 return f32.f; 114} 115 116static INLINE unsigned f32_to_uf10(float val) 117{ 118 union { 119 float f; 120 uint32_t ui; 121 } f32 = {val}; 122 123 uint16_t uf10 = 0; 124 125 /* Decode little-endian 32-bit floating-point value */ 126 int sign = (f32.ui >> 16) & 0x8000; 127 /* Map exponent to the range [-127,128] */ 128 int exponent = ((f32.ui >> 23) & 0xff) - 127; 129 int mantissa = f32.ui & 0x007fffff; 130 131 if (sign) return 0; 132 133 if (exponent == 128) { /* Infinity or NaN */ 134 uf10 = UF10_MAX_EXPONENT; 135 if (mantissa) uf10 |= (mantissa & UF10_MANTISSA_BITS); 136 } 137 else if (exponent > 15) { /* Overflow - flush to Infinity */ 138 uf10 = UF10_MAX_EXPONENT; 139 } 140 else if (exponent > -15) { /* Representable value */ 141 exponent += UF10_EXPONENT_BIAS; 142 mantissa >>= UF10_MANTISSA_SHIFT; 143 uf10 = exponent << UF10_EXPONENT_SHIFT | mantissa; 144 } 145 146 return uf10; 147} 148 149static INLINE float uf10_to_f32(uint16_t val) 150{ 151 union { 152 float f; 153 uint32_t ui; 154 } f32; 155 156 int exponent = (val & 0x03e0) >> UF10_EXPONENT_SHIFT; 157 int mantissa = (val & 0x001f); 158 159 f32.f = 0.0; 160 161 if (exponent == 0) { 162 if (mantissa != 0) { 163 const float scale = 1.0 / (1 << 20); 164 f32.f = scale * mantissa; 165 } 166 } 167 else if (exponent == 31) { 168 f32.ui = F32_INFINITY | mantissa; 169 } 170 else { 171 float scale, decimal; 172 exponent -= 15; 173 if (exponent < 0) { 174 scale = 1.0 / (1 << -exponent); 175 } 176 else { 177 scale = 1 << exponent; 178 } 179 decimal = 1.0 + (float) mantissa / 32; 180 f32.f = scale * decimal; 181 } 182 183 return f32.f; 184} 185 186static INLINE unsigned float3_to_r11g11b10f(const float rgb[3]) 187{ 188 return ( f32_to_uf11(rgb[0]) & 0x7ff) | 189 ((f32_to_uf11(rgb[1]) & 0x7ff) << 11) | 190 ((f32_to_uf10(rgb[2]) & 0x3ff) << 22); 191} 192 193static INLINE void r11g11b10f_to_float3(unsigned rgb, float retval[3]) 194{ 195 retval[0] = uf11_to_f32( rgb & 0x7ff); 196 retval[1] = uf11_to_f32((rgb >> 11) & 0x7ff); 197 retval[2] = uf10_to_f32((rgb >> 22) & 0x3ff); 198} 199