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(e, m)           ((e << 6) | (m))
31#define UF11_EXPONENT_BIAS   15
32#define UF11_EXPONENT_BITS   0x1F
33#define UF11_EXPONENT_SHIFT  6
34#define UF11_MANTISSA_BITS   0x3F
35#define UF11_MANTISSA_SHIFT  (23 - UF11_EXPONENT_SHIFT)
36#define UF11_MAX_EXPONENT    (UF11_EXPONENT_BITS << UF11_EXPONENT_SHIFT)
37
38#define UF10(e, m)           ((e << 5) | (m))
39#define UF10_EXPONENT_BIAS   15
40#define UF10_EXPONENT_BITS   0x1F
41#define UF10_EXPONENT_SHIFT  5
42#define UF10_MANTISSA_BITS   0x1F
43#define UF10_MANTISSA_SHIFT  (23 - UF10_EXPONENT_SHIFT)
44#define UF10_MAX_EXPONENT    (UF10_EXPONENT_BITS << UF10_EXPONENT_SHIFT)
45
46#define F32_INFINITY         0x7f800000
47
48static INLINE unsigned f32_to_uf11(float val)
49{
50   union {
51      float f;
52      uint32_t ui;
53   } f32 = {val};
54
55   uint16_t uf11 = 0;
56
57   /* Decode little-endian 32-bit floating-point value */
58   int sign = (f32.ui >> 16) & 0x8000;
59   /* Map exponent to the range [-127,128] */
60   int exponent = ((f32.ui >> 23) & 0xff) - 127;
61   int mantissa = f32.ui & 0x007fffff;
62
63   if (exponent == 128) { /* Infinity or NaN */
64      /* From the GL_EXT_packed_float spec:
65       *
66       *     "Additionally: negative infinity is converted to zero; positive
67       *      infinity is converted to positive infinity; and both positive and
68       *      negative NaN are converted to positive NaN."
69       */
70      uf11 = UF11_MAX_EXPONENT;
71      if (mantissa) {
72	 uf11 |= 1; /* NaN */
73      } else {
74	 if (sign)
75	    uf11 = 0; /* 0.0 */
76      }
77   } else if (sign) {
78      return 0;
79   } else if (val > 65024.0f) {
80      /* From the GL_EXT_packed_float spec:
81       *
82       *     "Likewise, finite positive values greater than 65024 (the maximum
83       *      finite representable unsigned 11-bit floating-point value) are
84       *      converted to 65024."
85       */
86      uf11 = UF11(30, 63);
87   }
88   else if (exponent > -15) { /* Representable value */
89      exponent += UF11_EXPONENT_BIAS;
90      mantissa >>= UF11_MANTISSA_SHIFT;
91      uf11 = exponent << UF11_EXPONENT_SHIFT | mantissa;
92   }
93
94   return uf11;
95}
96
97static INLINE float uf11_to_f32(uint16_t val)
98{
99   union {
100      float f;
101      uint32_t ui;
102   } f32;
103
104   int exponent = (val & 0x07c0) >> UF11_EXPONENT_SHIFT;
105   int mantissa = (val & 0x003f);
106
107   f32.f = 0.0;
108
109   if (exponent == 0) {
110      if (mantissa != 0) {
111         const float scale = 1.0 / (1 << 20);
112         f32.f = scale * mantissa;
113      }
114   }
115   else if (exponent == 31) {
116      f32.ui = F32_INFINITY | mantissa;
117   }
118   else {
119      float scale, decimal;
120      exponent -= 15;
121      if (exponent < 0) {
122         scale = 1.0f / (1 << -exponent);
123      }
124      else {
125         scale = (float) (1 << exponent);
126      }
127      decimal = 1.0f + (float) mantissa / 64;
128      f32.f = scale * decimal;
129   }
130
131   return f32.f;
132}
133
134static INLINE unsigned f32_to_uf10(float val)
135{
136   union {
137      float f;
138      uint32_t ui;
139   } f32 = {val};
140
141   uint16_t uf10 = 0;
142
143   /* Decode little-endian 32-bit floating-point value */
144   int sign = (f32.ui >> 16) & 0x8000;
145   /* Map exponent to the range [-127,128] */
146   int exponent = ((f32.ui >> 23) & 0xff) - 127;
147   int mantissa = f32.ui & 0x007fffff;
148
149   if (exponent == 128) {
150      /* From the GL_EXT_packed_float spec:
151       *
152       *     "Additionally: negative infinity is converted to zero; positive
153       *      infinity is converted to positive infinity; and both positive and
154       *      negative NaN are converted to positive NaN."
155       */
156      uf10 = UF10_MAX_EXPONENT;
157      if (mantissa) {
158	 uf10 |= 1; /* NaN */
159      } else {
160	 if (sign)
161	    uf10 = 0; /* 0.0 */
162      }
163   } else if (sign) {
164      return 0;
165   } else if (val > 64512.0f) { /* Overflow - flush to Infinity */
166      /* From the GL_EXT_packed_float spec:
167       *
168       *     "Likewise, finite positive values greater than 64512 (the maximum
169       *      finite representable unsigned 10-bit floating-point value) are
170       *      converted to 64512."
171       */
172      uf10 = UF10(30, 31);
173   }
174   else if (exponent > -15) { /* Representable value */
175      exponent += UF10_EXPONENT_BIAS;
176      mantissa >>= UF10_MANTISSA_SHIFT;
177      uf10 = exponent << UF10_EXPONENT_SHIFT | mantissa;
178   }
179
180   return uf10;
181}
182
183static INLINE float uf10_to_f32(uint16_t val)
184{
185   union {
186      float f;
187      uint32_t ui;
188   } f32;
189
190   int exponent = (val & 0x03e0) >> UF10_EXPONENT_SHIFT;
191   int mantissa = (val & 0x001f);
192
193   f32.f = 0.0;
194
195   if (exponent == 0) {
196      if (mantissa != 0) {
197         const float scale = 1.0 / (1 << 20);
198         f32.f = scale * mantissa;
199      }
200   }
201   else if (exponent == 31) {
202      f32.ui = F32_INFINITY | mantissa;
203   }
204   else {
205      float scale, decimal;
206      exponent -= 15;
207      if (exponent < 0) {
208         scale = 1.0 / (1 << -exponent);
209      }
210      else {
211         scale = (float) (1 << exponent);
212      }
213      decimal = 1.0f + (float) mantissa / 32;
214      f32.f = scale * decimal;
215   }
216
217   return f32.f;
218}
219
220static INLINE unsigned float3_to_r11g11b10f(const float rgb[3])
221{
222   return ( f32_to_uf11(rgb[0]) & 0x7ff) |
223          ((f32_to_uf11(rgb[1]) & 0x7ff) << 11) |
224          ((f32_to_uf10(rgb[2]) & 0x3ff) << 22);
225}
226
227static INLINE void r11g11b10f_to_float3(unsigned rgb, float retval[3])
228{
229   retval[0] = uf11_to_f32( rgb        & 0x7ff);
230   retval[1] = uf11_to_f32((rgb >> 11) & 0x7ff);
231   retval[2] = uf10_to_f32((rgb >> 22) & 0x3ff);
232}
233