I adapted these 2 functions to JavaScript. They seem to work
From here
var toHalf = (function() { var floatView = new Float32Array(1); var int32View = new Int32Array(floatView.buffer); return function toHalf(val) { floatView[0] = val; var x = int32View[0]; var bits = (x >> 16) & 0x8000; var m = (x >> 12) & 0x07ff; var e = (x >> 23) & 0xff; if (e < 103) { return bits; } if (e > 142) { bits |= 0x7c00; bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff); return bits; } if (e < 113) { m |= 0x0800; bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1); return bits; } bits |= ((e - 112) << 10) | (m >> 1); bits += m & 1; return bits; }; }());
From here
var toHalf = (function() { var floatView = new Float32Array(1); var int32View = new Int32Array(floatView.buffer); return function toHalf( fval ) { floatView[0] = fval; var fbits = int32View[0]; var sign = (fbits >> 16) & 0x8000; // sign only var val = ( fbits & 0x7fffffff ) + 0x1000; // rounded value if( val >= 0x47800000 ) { // might be or become NaN/Inf if( ( fbits & 0x7fffffff ) >= 0x47800000 ) { // is or must become NaN/Inf if( val < 0x7f800000 ) { // was value but too large return sign | 0x7c00; // make it +/-Inf } return sign | 0x7c00 | // remains +/-Inf or NaN ( fbits & 0x007fffff ) >> 13; // keep NaN (and Inf) bits } return sign | 0x7bff; // unrounded not quite Inf } if( val >= 0x38800000 ) { // remains normalized value return sign | val - 0x38000000 >> 13; // exp - 127 + 15 } if( val < 0x33000000 ) { // too small for subnormal return sign; // becomes +/-0 } val = ( fbits & 0x7fffffff ) >> 23; // tmp exp for subnormal calc return sign | ( ( fbits & 0x7fffff | 0x800000 ) // add subnormal bit + ( 0x800000 >>> val - 102 ) // round depending on cut off >> 126 - val ); // div by 2^(1-(exp-127+15)) and >> 13 | exp=0 }; }());
Usage example
var tex = new Uint16Array(4); tex[0] = toHalf(0.5); tex[1] = toHalf(1); tex[2] = toHalf(123); tex[3] = toHalf(-13);
Here is an example of using the first with WebGL
var toHalf = (function() { var floatView = new Float32Array(1); var int32View = new Int32Array(floatView.buffer); return function toHalf(val) { floatView[0] = val; var x = int32View[0]; var bits = (x >> 16) & 0x8000; var m = (x >> 12) & 0x07ff; var e = (x >> 23) & 0xff; if (e < 103) { return bits; } if (e > 142) { bits |= 0x7c00; bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff); return bits; } if (e < 113) { m |= 0x0800; bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1); return bits; } bits |= ((e - 112) << 10) | (m >> 1); bits += m & 1; return bits; }; }()); (function() { twgl.setAttributePrefix("a_"); var m4 = twgl.m4; var gl = document.getElementById("c").getContext("webgl"); var ext = gl.getExtension("OES_texture_half_float"); if (!ext) { alert("no support for OES_texture_half_float on this device"); return; } var onePointProgramInfo = twgl.createProgramInfo(gl, ["vs", "fs"]); var shapes = [ twgl.primitives.createCubeBufferInfo(gl, 2), ]; function rand(min, max) { if (max === undefined) { max = min; min = 0; } return min + Math.random() * (max - min); }
body { margin: 0; font-family: monospace; } canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script> <canvas id="c"></canvas> <script id="vs" type="notjs"> uniform mat4 u_worldViewProjection; attribute vec4 a_position; attribute vec2 a_texcoord; varying vec4 v_position; varying vec2 v_texCoord; void main() { v_texCoord = a_texcoord; gl_Position = u_worldViewProjection * a_position; } </script> <script id="fs" type="notjs"> precision mediump float; varying vec2 v_texCoord; uniform sampler2D u_diffuse; void main() { gl_FragColor = texture2D(u_diffuse, v_texCoord) / vec4(400.0, 400.0, 400.0, 1.0); } </script>
Note that although this works if you are loading image textures, it might be better to do this conversion offline. You can then save them as binary and load using XMLHttpRequest. You can compress them with gzip (much like png), and while your server sends the correct headers telling the browser that the file was gzipped, it should be automatically unpacked for you.
gman
source share