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