@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
88 lines (72 loc) • 2.51 kB
JavaScript
import { assert } from "../../assert.js";
import { msb_32 } from "../msb_32.js";
// TODO this has some overlap with `frexp` function behavior, perhaps we can generalize
/*
largely a port from https://github.com/sebbbi/OffsetAllocator
*/
const MANTISSA_BITS = 3;
const MANTISSA_VALUE = 1 << MANTISSA_BITS;
const MANTISSA_MASK = MANTISSA_VALUE - 1;
/**
* Bin sizes follow floating point (exponent + mantissa) distribution (piecewise linear log approx)
* This ensures that for each size class, the average overhead percentage stays the same
* @param {number} size
* @returns {number} uint32
*/
export function uintToFloatRoundUp(size) {
let exp = 0;
let mantissa = 0;
if (size < MANTISSA_VALUE) {
// Denorm: 0..(MANTISSA_VALUE-1)
mantissa = size;
} else {
// Normalized: Hidden high bit always 1. Not stored. Just like float.
const highestSetBit = msb_32(size);
const mantissaStartBit = highestSetBit - MANTISSA_BITS;
exp = mantissaStartBit + 1;
mantissa = (size >>> mantissaStartBit) & MANTISSA_MASK;
const lowBitsMask = (1 << mantissaStartBit) - 1;
// Round up!
if ((size & lowBitsMask) !== 0) {
mantissa++;
}
}
return (exp << MANTISSA_BITS) + mantissa; // + allows mantissa->exp overflow for round up
}
/**
*
* @param {number} size
* @return {number}
*/
export function uintToFloatRoundDown(size) {
let exp = 0;
let mantissa = 0;
if (size < MANTISSA_VALUE) {
// Denorm: 0..(MANTISSA_VALUE-1)
mantissa = size;
} else {
// Normalized: Hidden high bit always 1. Not stored. Just like float.
const highestSetBit = msb_32(size);
const mantissaStartBit = highestSetBit - MANTISSA_BITS;
exp = mantissaStartBit + 1;
mantissa = (size >>> mantissaStartBit) & MANTISSA_MASK;
}
return (exp << MANTISSA_BITS) | mantissa;
}
/**
*
* @param {number} floatValue
* @return {number}
*/
export function floatToUint(floatValue) {
assert.isNonNegativeInteger(floatValue, 'floatValue');
let exponent = floatValue >>> MANTISSA_BITS;
let mantissa = floatValue & MANTISSA_MASK;
if (exponent === 0) {
// Denorms
return mantissa;
} else {
const x = (mantissa | MANTISSA_VALUE) << (exponent - 1);
return x >>> 0; // convert to unsigned in case of sign overflow
}
}