|
@@ -1,9 +1,77 @@
|
|
|
/**
|
|
|
* @author Richard M. / https://github.com/richardmonette
|
|
|
+ *
|
|
|
+ * OpenEXR loader which, currently, supports reading 16 bit half data, in either
|
|
|
+ * uncompressed or PIZ wavelet compressed form.
|
|
|
+ *
|
|
|
+ * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
|
|
|
+ * implementation, so I have preserved their copyright notices.
|
|
|
*/
|
|
|
|
|
|
-// https://github.com/mrdoob/three.js/issues/10652
|
|
|
-// https://en.wikipedia.org/wiki/OpenEXR
|
|
|
+// /*
|
|
|
+// Copyright (c) 2014 - 2017, Syoyo Fujita
|
|
|
+// All rights reserved.
|
|
|
+
|
|
|
+// Redistribution and use in source and binary forms, with or without
|
|
|
+// modification, are permitted provided that the following conditions are met:
|
|
|
+// * Redistributions of source code must retain the above copyright
|
|
|
+// notice, this list of conditions and the following disclaimer.
|
|
|
+// * Redistributions in binary form must reproduce the above copyright
|
|
|
+// notice, this list of conditions and the following disclaimer in the
|
|
|
+// documentation and/or other materials provided with the distribution.
|
|
|
+// * Neither the name of the Syoyo Fujita nor the
|
|
|
+// names of its contributors may be used to endorse or promote products
|
|
|
+// derived from this software without specific prior written permission.
|
|
|
+
|
|
|
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
+// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
|
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
+// */
|
|
|
+
|
|
|
+// // TinyEXR contains some OpenEXR code, which is licensed under ------------
|
|
|
+
|
|
|
+// ///////////////////////////////////////////////////////////////////////////
|
|
|
+// //
|
|
|
+// // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
|
|
|
+// // Digital Ltd. LLC
|
|
|
+// //
|
|
|
+// // All rights reserved.
|
|
|
+// //
|
|
|
+// // Redistribution and use in source and binary forms, with or without
|
|
|
+// // modification, are permitted provided that the following conditions are
|
|
|
+// // met:
|
|
|
+// // * Redistributions of source code must retain the above copyright
|
|
|
+// // notice, this list of conditions and the following disclaimer.
|
|
|
+// // * Redistributions in binary form must reproduce the above
|
|
|
+// // copyright notice, this list of conditions and the following disclaimer
|
|
|
+// // in the documentation and/or other materials provided with the
|
|
|
+// // distribution.
|
|
|
+// // * Neither the name of Industrial Light & Magic nor the names of
|
|
|
+// // its contributors may be used to endorse or promote products derived
|
|
|
+// // from this software without specific prior written permission.
|
|
|
+// //
|
|
|
+// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
+// // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
+// // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
+// // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
+// // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
+// // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
+// // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
+// // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
+// // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
+// // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
+// // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
+// //
|
|
|
+// ///////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// // End of OpenEXR license -------------------------------------------------
|
|
|
|
|
|
THREE.EXRLoader = function ( manager ) {
|
|
|
|
|
@@ -15,6 +83,495 @@ THREE.EXRLoader.prototype = Object.create( THREE.DataTextureLoader.prototype );
|
|
|
|
|
|
THREE.EXRLoader.prototype._parser = function ( buffer ) {
|
|
|
|
|
|
+ const USHORT_RANGE = (1 << 16);
|
|
|
+ const BITMAP_SIZE = (USHORT_RANGE >> 3);
|
|
|
+
|
|
|
+ const HUF_ENCBITS = 16; // literal (value) bit length
|
|
|
+ const HUF_DECBITS = 14; // decoding bit size (>= 8)
|
|
|
+
|
|
|
+ const HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1; // encoding table size
|
|
|
+ const HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size
|
|
|
+ const HUF_DECMASK = HUF_DECSIZE - 1;
|
|
|
+
|
|
|
+ const SHORT_ZEROCODE_RUN = 59;
|
|
|
+ const LONG_ZEROCODE_RUN = 63;
|
|
|
+ const SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
|
|
|
+ const LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN;
|
|
|
+
|
|
|
+ const BYTES_PER_HALF = 2;
|
|
|
+
|
|
|
+ function reverseLutFromBitmap(bitmap, lut) {
|
|
|
+ var k = 0;
|
|
|
+
|
|
|
+ for (var i = 0; i < USHORT_RANGE; ++i) {
|
|
|
+ if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) {
|
|
|
+ lut[k++] = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var n = k - 1;
|
|
|
+
|
|
|
+ while (k < USHORT_RANGE) lut[k++] = 0;
|
|
|
+
|
|
|
+ return n;
|
|
|
+ }
|
|
|
+
|
|
|
+ function hufClearDecTable(hdec) {
|
|
|
+ for (var i = 0; i < HUF_DECSIZE; i++) {
|
|
|
+ hdec[i] = {}
|
|
|
+ hdec[i].len = 0;
|
|
|
+ hdec[i].lit = 0;
|
|
|
+ hdec[i].p = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function getBits(nBits, c, lc, inBuffer, inOffset) {
|
|
|
+ while (lc < nBits) {
|
|
|
+ c = (c << 8) | parseUint8(inBuffer, inOffset);
|
|
|
+ lc += 8;
|
|
|
+ }
|
|
|
+
|
|
|
+ lc -= nBits;
|
|
|
+
|
|
|
+ return { l: (c >> lc) & ((1 << nBits) - 1), c: c, lc: lc };
|
|
|
+ }
|
|
|
+
|
|
|
+ function hufCanonicalCodeTable(hcode) {
|
|
|
+ var n = new Array(59);
|
|
|
+
|
|
|
+ for (var i = 0; i <= 58; ++i) n[i] = 0;
|
|
|
+
|
|
|
+ for (var i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1;
|
|
|
+
|
|
|
+ var c = 0;
|
|
|
+
|
|
|
+ for (var i = 58; i > 0; --i) {
|
|
|
+ var nc = ((c + n[i]) >> 1);
|
|
|
+ n[i] = c;
|
|
|
+ c = nc;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (var i = 0; i < HUF_ENCSIZE; ++i) {
|
|
|
+ var l = hcode[i];
|
|
|
+
|
|
|
+ if (l > 0) hcode[i] = l | (n[l]++ << 6);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function hufUnpackEncTable(inBuffer, inOffset, ni, im, iM, hcode) {
|
|
|
+ var p = inOffset;
|
|
|
+ var c = 0;
|
|
|
+ var lc = 0;
|
|
|
+
|
|
|
+ for (; im <= iM; im++) {
|
|
|
+ if (p.value - inOffset.value > ni) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ var bits = getBits(6, c, lc, inBuffer, p);
|
|
|
+ var l = bits.l;
|
|
|
+ c = bits.c;
|
|
|
+ lc = bits.lc;
|
|
|
+ hcode[im] = l;
|
|
|
+
|
|
|
+ if (l == LONG_ZEROCODE_RUN) {
|
|
|
+ if (p.value - inOffset.value > ni) {
|
|
|
+ throw 'Something wrong with hufUnpackEncTable';
|
|
|
+ }
|
|
|
+
|
|
|
+ var bits = getBits(8, c, lc, inBuffer, p);
|
|
|
+ var zerun = bits.l + SHORTEST_LONG_RUN;
|
|
|
+ c = bits.c;
|
|
|
+ lc = bits.lc;
|
|
|
+
|
|
|
+ if (im + zerun > iM + 1) {
|
|
|
+ throw 'Something wrong with hufUnpackEncTable';
|
|
|
+ }
|
|
|
+
|
|
|
+ while (zerun--) hcode[im++] = 0;
|
|
|
+
|
|
|
+ im--;
|
|
|
+ } else if (l >= SHORT_ZEROCODE_RUN) {
|
|
|
+ var zerun = l - SHORT_ZEROCODE_RUN + 2;
|
|
|
+
|
|
|
+ if (im + zerun > iM + 1) {
|
|
|
+ throw 'Something wrong with hufUnpackEncTable';
|
|
|
+ }
|
|
|
+
|
|
|
+ while (zerun--) hcode[im++] = 0;
|
|
|
+
|
|
|
+ im--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ hufCanonicalCodeTable(hcode);
|
|
|
+ }
|
|
|
+
|
|
|
+ function hufLength(code) { return code & 63; }
|
|
|
+
|
|
|
+ function hufCode(code) { return code >> 6; }
|
|
|
+
|
|
|
+ function hufBuildDecTable(hcode, im, iM, hdecod) {
|
|
|
+ for (; im <= iM; im++) {
|
|
|
+ var c = hufCode(hcode[im]);
|
|
|
+ var l = hufLength(hcode[im]);
|
|
|
+
|
|
|
+ if (c >> l) {
|
|
|
+ throw 'Invalid table entry';
|
|
|
+ }
|
|
|
+
|
|
|
+ if (l > HUF_DECBITS) {
|
|
|
+ var pl = hdecod[(c >> (l - HUF_DECBITS))];
|
|
|
+
|
|
|
+ if (pl.len) {
|
|
|
+ throw 'Invalid table entry';
|
|
|
+ }
|
|
|
+
|
|
|
+ pl.lit++;
|
|
|
+
|
|
|
+ if (pl.p) {
|
|
|
+ var p = pl.p;
|
|
|
+ pl.p = new Array(pl.lit);
|
|
|
+
|
|
|
+ for (var i = 0; i < pl.lit - 1; ++i) {
|
|
|
+ pl.p[i] = p[i];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ pl.p = new Array(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ pl.p[pl.lit - 1] = im;
|
|
|
+ } else if (l) {
|
|
|
+ var plOffset = 0;
|
|
|
+
|
|
|
+ for (var i = 1 << (HUF_DECBITS - l); i > 0; i--) {
|
|
|
+ var pl = hdecod[(c << (HUF_DECBITS - l)) + plOffset];
|
|
|
+
|
|
|
+ if (pl.len || pl.p) {
|
|
|
+ throw 'Invalid table entry';
|
|
|
+ }
|
|
|
+
|
|
|
+ pl.len = l;
|
|
|
+ pl.lit = im;
|
|
|
+
|
|
|
+ plOffset++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ function getChar(c, lc, inBuffer, inOffset) {
|
|
|
+ c = (c << 8) | parseUint8(inBuffer, inOffset);
|
|
|
+ lc += 8;
|
|
|
+
|
|
|
+ return { c: c, lc: lc };
|
|
|
+ }
|
|
|
+
|
|
|
+ function getCode(po, rlc, c, lc, inBuffer, inOffset, outBuffer, outBufferOffset, outBufferEndOffset) {
|
|
|
+ if (po == rlc) {
|
|
|
+ if (lc < 8) {
|
|
|
+ var temp = getChar(c, lc, inBuffer, inOffset);
|
|
|
+ c = temp.c;
|
|
|
+ lc = temp.lc;
|
|
|
+ }
|
|
|
+
|
|
|
+ lc -= 8;
|
|
|
+
|
|
|
+ var cs = (c >> lc);
|
|
|
+
|
|
|
+ if (out + cs > oe) {
|
|
|
+ throw 'Issue with getCode';
|
|
|
+ }
|
|
|
+
|
|
|
+ var s = out[-1];
|
|
|
+
|
|
|
+ while (cs-- > 0) {
|
|
|
+ outBuffer[outBufferOffset.value++] = s;
|
|
|
+ }
|
|
|
+ } else if (outBufferOffset.value < outBufferEndOffset) {
|
|
|
+ outBuffer[outBufferOffset.value++] = po;
|
|
|
+ } else {
|
|
|
+ throw 'Issue with getCode';
|
|
|
+ }
|
|
|
+
|
|
|
+ return { c: c, lc: lc };
|
|
|
+ }
|
|
|
+
|
|
|
+ var NBITS = 16;
|
|
|
+ var A_OFFSET = 1 << (NBITS - 1);
|
|
|
+ var M_OFFSET = 1 << (NBITS - 1);
|
|
|
+ var MOD_MASK = (1 << NBITS) - 1;
|
|
|
+
|
|
|
+ function wdec14(l, h) {
|
|
|
+ var ls = (new Int16Array([l]))[0];
|
|
|
+ var hs = (new Int16Array([h]))[0];
|
|
|
+
|
|
|
+ var hi = hs;
|
|
|
+ var ai = ls + (hi & 1) + (hi >> 1);
|
|
|
+
|
|
|
+ var as = ai;
|
|
|
+ var bs = ai - hi;
|
|
|
+
|
|
|
+ return {a: as, b: bs}
|
|
|
+ }
|
|
|
+
|
|
|
+ function wav2Decode(j, buffer, nx, ox, ny, oy, mx) {
|
|
|
+ var n = (nx > ny) ? ny : nx;
|
|
|
+ var p = 1;
|
|
|
+ var p2;
|
|
|
+
|
|
|
+ while (p <= n) p <<= 1;
|
|
|
+
|
|
|
+ p >>= 1;
|
|
|
+ p2 = p;
|
|
|
+ p >>= 1;
|
|
|
+
|
|
|
+ while (p >= 1) {
|
|
|
+ var py = 0;
|
|
|
+ var ey = py + oy * (ny - p2);
|
|
|
+ var oy1 = oy * p;
|
|
|
+ var oy2 = oy * p2;
|
|
|
+ var ox1 = ox * p;
|
|
|
+ var ox2 = ox * p2;
|
|
|
+ var i00, i01, i10, i11;
|
|
|
+
|
|
|
+ for (; py <= ey; py += oy2) {
|
|
|
+ var px = py;
|
|
|
+ var ex = py + ox * (nx - p2);
|
|
|
+
|
|
|
+ for (; px <= ex; px += ox2) {
|
|
|
+ var p01 = px + ox1;
|
|
|
+ var p10 = px + oy1;
|
|
|
+ var p11 = p10 + ox1;
|
|
|
+
|
|
|
+ var tmp = wdec14(buffer[px + j], buffer[p10 + j]);
|
|
|
+ i00 = tmp.a;
|
|
|
+ i10 = tmp.b;
|
|
|
+
|
|
|
+ var tmp = wdec14(buffer[p01 + j], buffer[p11 + j]);
|
|
|
+ i01 = tmp.a;
|
|
|
+ i11 = tmp.b;
|
|
|
+
|
|
|
+ var tmp = wdec14(i00, i01);
|
|
|
+ buffer[px + j] = tmp.a;
|
|
|
+ buffer[p01 + j] = tmp.b;
|
|
|
+
|
|
|
+ var tmp = wdec14(i10, i11);
|
|
|
+ buffer[p10 + j] = tmp.a;
|
|
|
+ buffer[p11 + j] = tmp.b;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nx & p) {
|
|
|
+ var p10 = px + oy1;
|
|
|
+
|
|
|
+ var tmp = wdec14(buffer[px + j], buffer[p10 + j]);
|
|
|
+ i00 = tmp.a;
|
|
|
+ buffer[p10 + j] = tmp.b;
|
|
|
+
|
|
|
+ buffer[px + j] = i00;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ny & p) {
|
|
|
+ var px = py;
|
|
|
+ var ex = py + ox * (nx - p2);
|
|
|
+
|
|
|
+ for (; px <= ex; px += ox2) {
|
|
|
+ var p01 = px + ox1;
|
|
|
+
|
|
|
+ var tmp = wdec14(buffer[px + j], buffer[p01 + j]);
|
|
|
+ i00 = tmp.a;
|
|
|
+ buffer[p01 + j] = tmp.b;
|
|
|
+
|
|
|
+ buffer[px + j] = i00;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ p2 = p;
|
|
|
+ p >>= 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return py;
|
|
|
+ }
|
|
|
+
|
|
|
+ function hufDecode(encodingTable, decodingTable, inBuffer, inOffset, ni, rlc, no, outBuffer, outOffset) {
|
|
|
+ var c = 0;
|
|
|
+ var lc = 0;
|
|
|
+ var outBufferEndOffset = no;
|
|
|
+ var inOffsetEnd = parseInt(inOffset.value + (ni + 7) / 8);
|
|
|
+
|
|
|
+ while (inOffset.value < inOffsetEnd) {
|
|
|
+ var temp = getChar(c, lc, inBuffer, inOffset);
|
|
|
+ c = temp.c;
|
|
|
+ lc = temp.lc;
|
|
|
+
|
|
|
+ while (lc >= HUF_DECBITS) {
|
|
|
+ var index = (c >> (lc - HUF_DECBITS)) & HUF_DECMASK;
|
|
|
+ var pl = decodingTable[index];
|
|
|
+
|
|
|
+ if (pl.len) {
|
|
|
+ lc -= pl.len;
|
|
|
+ var temp = getCode(pl.lit, rlc, c, lc, inBuffer, inOffset, outBuffer, outOffset, outBufferEndOffset);
|
|
|
+ c = temp.c;
|
|
|
+ lc = temp.lc;
|
|
|
+ } else {
|
|
|
+ if (!pl.p) {
|
|
|
+ throw 'hufDecode issues';
|
|
|
+ }
|
|
|
+
|
|
|
+ var j;
|
|
|
+
|
|
|
+ for (j = 0; j < pl.lit; j++) {
|
|
|
+ var l = hufLength(encodingTable[pl.p[j]]);
|
|
|
+
|
|
|
+ while (lc < l && inOffset.value < inOffsetEnd) {
|
|
|
+ var temp = getChar(c, lc, inBuffer, inOffset);
|
|
|
+ c = temp.c;
|
|
|
+ lc = temp.lc;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lc >= l) {
|
|
|
+ if (hufCode(encodingTable[pl.p[j]]) ==
|
|
|
+ ((c >> (lc - l)) & ((1 << l) - 1))) {
|
|
|
+
|
|
|
+ lc -= l;
|
|
|
+ var temp = getCode(pl.p[j], rlc, c, lc, inBuffer, inOffset, outBuffer, outOffset, outBufferEndOffset);
|
|
|
+ c = temp.c;
|
|
|
+ lc = temp.lc;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (j == pl.lit) {
|
|
|
+ throw 'hufDecode issues';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var i = (8 - ni) & 7;
|
|
|
+ c >>= i;
|
|
|
+ lc -= i;
|
|
|
+
|
|
|
+ while (lc > 0) {
|
|
|
+ var pl = decodingTable[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
|
|
|
+
|
|
|
+ if (pl.len) {
|
|
|
+ lc -= pl.len;
|
|
|
+ var temp = getCode(pl.lit, rlc, c, lc, inBuffer, inOffset, outBuffer, outOffset, outBufferEndOffset);
|
|
|
+ c = temp.c;
|
|
|
+ lc = temp.lc;
|
|
|
+ } else {
|
|
|
+ throw 'hufDecode issues';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ function hufUncompress(inBuffer, inOffset, nCompressed, outBuffer, outOffset, nRaw) {
|
|
|
+ var initialInOffset = inOffset.value;
|
|
|
+
|
|
|
+ var im = parseUint32(inBuffer, inOffset);
|
|
|
+ var iM = parseUint32(inBuffer, inOffset);
|
|
|
+ inOffset.value += 4;
|
|
|
+ var nBits = parseUint32(inBuffer, inOffset);
|
|
|
+ inOffset.value += 4;
|
|
|
+
|
|
|
+ if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) {
|
|
|
+ throw 'Something wrong with HUF_ENCSIZE';
|
|
|
+ }
|
|
|
+
|
|
|
+ var freq = new Array(HUF_ENCSIZE);
|
|
|
+ var hdec = new Array(HUF_DECSIZE);
|
|
|
+
|
|
|
+ hufClearDecTable(hdec);
|
|
|
+
|
|
|
+ var ni = nCompressed - (inOffset.value - initialInOffset);
|
|
|
+
|
|
|
+ hufUnpackEncTable(inBuffer, inOffset, ni, im, iM, freq);
|
|
|
+
|
|
|
+ if (nBits > 8 * (nCompressed - (inOffset.value - initialInOffset))) {
|
|
|
+ throw 'Something wrong with hufUncompress';
|
|
|
+ }
|
|
|
+
|
|
|
+ hufBuildDecTable(freq, im, iM, hdec);
|
|
|
+
|
|
|
+ hufDecode(freq, hdec, inBuffer, inOffset, nBits, iM, nRaw, outBuffer, outOffset);
|
|
|
+ }
|
|
|
+
|
|
|
+ function applyLut(lut, data, nData) {
|
|
|
+ for (var i = 0; i < nData; ++i) {
|
|
|
+ data[i] = lut[data[i]];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function decompressPIZ(outBuffer, outOffset, inBuffer, inOffset, tmpBufSize, num_channels, exrChannelInfos, dataWidth, num_lines) {
|
|
|
+ var bitmap = new Uint8Array(BITMAP_SIZE);
|
|
|
+
|
|
|
+ var minNonZero = parseUint16(inBuffer, inOffset);
|
|
|
+ var maxNonZero = parseUint16(inBuffer, inOffset);
|
|
|
+
|
|
|
+ if (maxNonZero >= BITMAP_SIZE) {
|
|
|
+ throw 'Something is wrong with PIZ_COMPRESSION BITMAP_SIZE'
|
|
|
+ }
|
|
|
+
|
|
|
+ if (minNonZero <= maxNonZero) {
|
|
|
+ for (var i = 0; i < maxNonZero - minNonZero + 1; i++) {
|
|
|
+ bitmap[i + minNonZero] = parseUint8(inBuffer, inOffset);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var lut = new Uint16Array(USHORT_RANGE);
|
|
|
+ var maxValue = reverseLutFromBitmap(bitmap, lut);
|
|
|
+
|
|
|
+ var length = parseUint32(inBuffer, inOffset);
|
|
|
+
|
|
|
+ hufUncompress(inBuffer, inOffset, length, outBuffer, outOffset, tmpBufSize);
|
|
|
+
|
|
|
+ var pizChannelData = new Array(num_channels);
|
|
|
+
|
|
|
+ var outBufferEnd = 0
|
|
|
+
|
|
|
+ for (var i = 0; i < num_channels; i++) {
|
|
|
+ var exrChannelInfo = exrChannelInfos[i];
|
|
|
+
|
|
|
+ var pixelSize = 2; // assumes HALF_FLOAT
|
|
|
+
|
|
|
+ pizChannelData[i] = {};
|
|
|
+ pizChannelData[i]['start'] = outBufferEnd;
|
|
|
+ pizChannelData[i]['end'] = pizChannelData[i]['start'];
|
|
|
+ pizChannelData[i]['nx'] = dataWidth;
|
|
|
+ pizChannelData[i]['ny'] = num_lines;
|
|
|
+ pizChannelData[i]['size'] = 1;
|
|
|
+
|
|
|
+ outBufferEnd += pizChannelData[i].nx * pizChannelData[i].ny * pizChannelData[i].size;
|
|
|
+ }
|
|
|
+
|
|
|
+ var fooOffset = 0;
|
|
|
+
|
|
|
+ for (var i = 0; i < num_channels; i++) {
|
|
|
+ for (var j = 0; j < pizChannelData[i].size; ++j) {
|
|
|
+ fooOffset += wav2Decode(
|
|
|
+ j + fooOffset,
|
|
|
+ outBuffer,
|
|
|
+ pizChannelData[i].nx,
|
|
|
+ pizChannelData[i].size,
|
|
|
+ pizChannelData[i].ny,
|
|
|
+ pizChannelData[i].nx * pizChannelData[i].size,
|
|
|
+ maxValue
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ applyLut(lut, outBuffer, outBufferEnd);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
function parseNullTerminatedString( buffer, offset ) {
|
|
|
|
|
|
var uintBuffer = new Uint8Array( buffer );
|
|
@@ -106,13 +663,19 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function parseFloat16( buffer, offset ) {
|
|
|
+ function parseUint16( buffer, offset ) {
|
|
|
|
|
|
- var float = new DataView( buffer.slice( offset.value, offset.value + 2 ) ).getUint16( 0, true );
|
|
|
+ var Uint16 = new DataView( buffer.slice( offset.value, offset.value + 2 ) ).getUint16( 0, true );
|
|
|
|
|
|
offset.value += 2;
|
|
|
|
|
|
- return decodeFloat16( float );
|
|
|
+ return Uint16;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function parseFloat16( buffer, offset ) {
|
|
|
+
|
|
|
+ return decodeFloat16( parseUint16( buffer, offset) );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -165,6 +728,9 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
|
|
|
|
|
|
var compressionCodes = [
|
|
|
'NO_COMPRESSION',
|
|
|
+ 'RLE_COMPRESSION',
|
|
|
+ 'ZIPS_COMPRESSION',
|
|
|
+ 'ZIP_COMPRESSION',
|
|
|
'PIZ_COMPRESSION'
|
|
|
];
|
|
|
|
|
@@ -283,7 +849,10 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
|
|
|
// offsets
|
|
|
|
|
|
var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
|
|
|
- var scanlineBlockSize = 1; // 1 for no compression, 32 for PIZ
|
|
|
+ var scanlineBlockSize = 1; // 1 for NO_COMPRESSION
|
|
|
+ if (EXRHeader.compression == 'PIZ_COMPRESSION') {
|
|
|
+ scanlineBlockSize = 32;
|
|
|
+ }
|
|
|
var numBlocks = dataWindowHeight / scanlineBlockSize;
|
|
|
|
|
|
for ( var i = 0; i < numBlocks; i ++ ) {
|
|
@@ -307,33 +876,84 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
|
|
|
A: 3
|
|
|
};
|
|
|
|
|
|
- for ( var y = 0; y < height; y ++ ) {
|
|
|
+ if (EXRHeader.compression == 'NO_COMPRESSION') {
|
|
|
+
|
|
|
+ for ( var y = 0; y < height; y ++ ) {
|
|
|
+
|
|
|
+ var y_scanline = parseUint32( buffer, offset );
|
|
|
+ var dataSize = parseUint32( buffer, offset );
|
|
|
+
|
|
|
+ for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
|
|
|
|
|
|
- var y_scanline = parseUint32( buffer, offset );
|
|
|
- var dataSize = parseUint32( buffer, offset );
|
|
|
+ if ( EXRHeader.channels[ channelID ].pixelType == 1 ) {
|
|
|
|
|
|
- for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
|
|
|
+ // HALF
|
|
|
+ for ( var x = 0; x < width; x ++ ) {
|
|
|
|
|
|
- if ( EXRHeader.channels[ channelID ].pixelType == 1 ) {
|
|
|
+ var val = parseFloat16( buffer, offset );
|
|
|
+ var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
|
|
|
|
|
|
- // HALF
|
|
|
- for ( var x = 0; x < width; x ++ ) {
|
|
|
+ byteArray[ ( ( ( width - y_scanline ) * ( height * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
|
|
|
|
|
|
- var val = parseFloat16( buffer, offset );
|
|
|
- var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
|
|
|
+ }
|
|
|
|
|
|
- byteArray[ ( ( ( width - y_scanline ) * ( height * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ throw 'Only supported pixel format is HALF';
|
|
|
|
|
|
}
|
|
|
|
|
|
- } else {
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (EXRHeader.compression == 'PIZ_COMPRESSION') {
|
|
|
+
|
|
|
+ for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx++ ) {
|
|
|
+
|
|
|
+ var line_no = parseUint32( buffer, offset );
|
|
|
+ var data_len = parseUint32( buffer, offset );
|
|
|
+
|
|
|
+ var tmpBufferSize = width * scanlineBlockSize * (EXRHeader.channels.length * BYTES_PER_HALF);
|
|
|
+ var tmpBuffer = new Uint16Array(tmpBufferSize);
|
|
|
+ var tmpOffset = { value: 0 };
|
|
|
+
|
|
|
+ decompressPIZ(tmpBuffer, tmpOffset, buffer, offset, tmpBufferSize, numChannels, EXRHeader.channels, width, scanlineBlockSize);
|
|
|
+
|
|
|
+ for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
|
|
|
+
|
|
|
+ for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
|
|
|
|
|
|
- throw 'Only supported pixel format is HALF';
|
|
|
+ if ( EXRHeader.channels[ channelID ].pixelType == 1 ) {
|
|
|
+
|
|
|
+ // HALF
|
|
|
+ for ( var x = 0; x < width; x ++ ) {
|
|
|
+
|
|
|
+ var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
|
|
|
+ var val = decodeFloat16(tmpBuffer[ (channelID * (scanlineBlockSize * width)) + (line_y * width) + x ]);
|
|
|
+
|
|
|
+ var true_y = line_y + (scanlineBlockIdx * scanlineBlockSize);
|
|
|
+
|
|
|
+ byteArray[ ( ( (height - true_y) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ throw 'Only supported pixel format is HALF';
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
+ } else {
|
|
|
+
|
|
|
+ throw 'Cannot decompress unsupported compression';
|
|
|
+
|
|
|
}
|
|
|
|
|
|
return {
|
|
@@ -341,7 +961,7 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
|
|
|
width: width,
|
|
|
height: height,
|
|
|
data: byteArray,
|
|
|
- format: THREE.RGBAFormat,
|
|
|
+ format: THREE.RGBFormat,
|
|
|
type: THREE.FloatType
|
|
|
};
|
|
|
|