UNPKG

three

Version:

JavaScript 3D library

217 lines (146 loc) 4.53 kB
import { clamp } from '../math/MathUtils.js'; // Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf const _tables = /*@__PURE__*/ _generateTables(); function _generateTables() { // float32 to float16 helpers const buffer = new ArrayBuffer( 4 ); const floatView = new Float32Array( buffer ); const uint32View = new Uint32Array( buffer ); 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 < - 27 ) { 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; } } return { floatView: floatView, uint32View: uint32View, baseTable: baseTable, shiftTable: shiftTable, mantissaTable: mantissaTable, exponentTable: exponentTable, offsetTable: offsetTable }; } /** * Returns a half precision floating point value (FP16) from the given single * precision floating point value (FP32). * * @param {number} val - A single precision floating point value. * @return {number} The FP16 value. */ function toHalfFloat( val ) { if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' ); val = clamp( val, - 65504, 65504 ); _tables.floatView[ 0 ] = val; const f = _tables.uint32View[ 0 ]; const e = ( f >> 23 ) & 0x1ff; return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] ); } /** * Returns a single precision floating point value (FP32) from the given half * precision floating point value (FP16). * * @param {number} val - A half precision floating point value. * @return {number} The FP32 value. */ function fromHalfFloat( val ) { const m = val >> 10; _tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ]; return _tables.floatView[ 0 ]; } /** * A class containing utility functions for data. * * @hideconstructor */ class DataUtils { /** * Returns a half precision floating point value (FP16) from the given single * precision floating point value (FP32). * * @param {number} val - A single precision floating point value. * @return {number} The FP16 value. */ static toHalfFloat( val ) { return toHalfFloat( val ); } /** * Returns a single precision floating point value (FP32) from the given half * precision floating point value (FP16). * * @param {number} val - A half precision floating point value. * @return {number} The FP32 value. */ static fromHalfFloat( val ) { return fromHalfFloat( val ); } } export { toHalfFloat, fromHalfFloat, DataUtils };