mirror of
https://github.com/SamEyeBam/animate.git
synced 2026-02-05 18:00:05 +00:00
177 lines
3.4 KiB
JavaScript
177 lines
3.4 KiB
JavaScript
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
|
|
};
|
|
|
|
}
|
|
|
|
// float32 to float16
|
|
|
|
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 ] );
|
|
|
|
}
|
|
|
|
// float16 to float32
|
|
|
|
function fromHalfFloat( val ) {
|
|
|
|
const m = val >> 10;
|
|
_tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ];
|
|
return _tables.floatView[ 0 ];
|
|
|
|
}
|
|
|
|
const DataUtils = {
|
|
toHalfFloat: toHalfFloat,
|
|
fromHalfFloat: fromHalfFloat,
|
|
};
|
|
|
|
export {
|
|
toHalfFloat,
|
|
fromHalfFloat,
|
|
DataUtils
|
|
};
|