import { assert } from "../assert.js";

/**
 * Convert uint16 encoded half float (float16) value to a full 32bit float
 * Useful for decoding 16bit packed data, such as that from serialized files of GPU textures
 * Reverse of {@link to_half_float_uint16}
 * @param {number} uint16val
 * @returns {number} decoded float
 */
export function half_to_float_uint16(uint16val) {
    assert.isNonNegativeInteger(uint16val, 'uint16val');

    // See https://en.wikipedia.org/wiki/Half-precision_floating-point_format for details
    // see https://stackoverflow.com/questions/5678432/decompressing-half-precision-floats-in-javascript

    // PORTED from https://github.com/YoYoGames/GameMaker-HTML5/blob/ada1ca2188b2145f222a8d6f9dda01b6d4770aca/scripts/libWebGL/libWebGL.js#L1808
    // which is Apache 2.0 licensed

    let ret = 0.0;
    const exponent = (uint16val & 0x7C00) >> 10;
    const fraction = uint16val & 0x03FF;
    let sign = 1.0;

    if ((uint16val >> 15) !== 0) {
        sign = -1.0;
    }

    if (exponent !== 0) {

        if (exponent === 0x1f) {

            if (fraction !== 0) {
                ret = NaN;
            } else {
                ret = sign * Infinity;
            }

        } else {

            ret = sign * Math.pow(2, exponent - 15) * (1 + (fraction / 0x400));

        }

    } else {
        // 0.00006103515625 is the minimum exponent value (2 to the power -14)
        ret = sign * (0.00006103515625 * (fraction / 0x400));
    }

    return ret;
}