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 #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 
     48 static 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 
     97 static 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 
    134 static 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 
    183 static 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 
    220 static 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 
    227 static 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