@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
131 lines • 4.67 kB
JavaScript
let Tables = null;
/**
* Returns the conversion tables, building them lazily on first use.
* Generation is deferred so that importing this module allocates nothing: tree-shaken code paths
* that never convert a half float pay no cost, keeping the module side-effect free at import time.
* @returns the shared conversion tables
*/
// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf
function GenerateTables() {
if (Tables) {
return Tables;
}
const buffer = new ArrayBuffer(4);
const floatView = new Float32Array(buffer);
const uint32View = new Uint32Array(buffer);
// float32 to float16 helpers
const baseTable = new Uint32Array(512);
const shiftTable = new Uint32Array(512);
for (let i = 0; i < 256; ++i) {
const e = i - 127;
// very small number (0, -0)
if (e < -24) {
baseTable[i] = 0x0000;
baseTable[i | 0x100] = 0x8000;
shiftTable[i] = 24;
shiftTable[i | 0x100] = 24;
// small number (denorm)
}
else if (e < -14) {
baseTable[i] = 0x0400 >> (-e - 14);
baseTable[i | 0x100] = (0x0400 >> (-e - 14)) | 0x8000;
shiftTable[i] = -e - 1;
shiftTable[i | 0x100] = -e - 1;
// normal number
}
else if (e <= 15) {
baseTable[i] = (e + 15) << 10;
baseTable[i | 0x100] = ((e + 15) << 10) | 0x8000;
shiftTable[i] = 13;
shiftTable[i | 0x100] = 13;
// large number (Infinity, -Infinity)
}
else if (e < 128) {
baseTable[i] = 0x7c00;
baseTable[i | 0x100] = 0xfc00;
shiftTable[i] = 24;
shiftTable[i | 0x100] = 24;
// stay (NaN, Infinity, -Infinity)
}
else {
baseTable[i] = 0x7c00;
baseTable[i | 0x100] = 0xfc00;
shiftTable[i] = 13;
shiftTable[i | 0x100] = 13;
}
}
// float16 to float32 helpers
const mantissaTable = new Uint32Array(2048);
const exponentTable = new Uint32Array(64);
const offsetTable = new Uint32Array(64);
for (let i = 1; i < 1024; ++i) {
let m = i << 13; // zero pad mantissa bits
let e = 0; // zero exponent
// normalized
while ((m & 0x00800000) === 0) {
m <<= 1;
e -= 0x00800000; // decrement exponent
}
m &= ~0x00800000; // clear leading 1 bit
e += 0x38800000; // adjust bias
mantissaTable[i] = m | e;
}
for (let i = 1024; i < 2048; ++i) {
mantissaTable[i] = 0x38000000 + ((i - 1024) << 13);
}
for (let i = 1; i < 31; ++i) {
exponentTable[i] = i << 23;
}
exponentTable[31] = 0x47800000;
exponentTable[32] = 0x80000000;
for (let i = 33; i < 63; ++i) {
exponentTable[i] = 0x80000000 + ((i - 32) << 23);
}
exponentTable[63] = 0xc7800000;
for (let i = 1; i < 64; ++i) {
if (i !== 32) {
offsetTable[i] = 1024;
}
}
Tables = {
floatView,
uint32View,
baseTable,
shiftTable,
mantissaTable,
exponentTable,
offsetTable,
};
return Tables;
}
/**
* The largest finite magnitude representable by a 16-bit half-float (binary16): 65504.
* Use this to clamp values into the half-float range before conversion instead of hardcoding the literal.
*/
export const MaxHalfFloat = 65504;
/**
* Converts a 32-bit float to its 16-bit half-float bit pattern.
* @param value the float to convert
* @returns the half-float bit pattern, in the range 0..65535
*/
export function ToHalfFloat(value) {
// For now this truncates toward zero (drops the extra mantissa bits instead of rounding).
// TODO: replace with the native Float16Array / Math.f16round once Node 24 is the minimum version;
// those round to nearest-even, so some results will change.
const tables = GenerateTables();
tables.floatView[0] = value;
const f = tables.uint32View[0];
const e = (f >> 23) & 0x1ff;
return tables.baseTable[e] + ((f & 0x007fffff) >> tables.shiftTable[e]);
}
/**
* Converts a 16-bit half-float bit pattern back to a 32-bit float.
* @param value the half-float bit pattern, in the range 0..65535
* @returns the decoded float
*/
export function FromHalfFloat(value) {
const tables = GenerateTables();
tables.uint32View[0] = tables.mantissaTable[tables.offsetTable[value >> 10] + (value & 0x03ff)] + tables.exponentTable[value >> 10];
return tables.floatView[0];
}
//# sourceMappingURL=halfFloat.js.map