Browse Source

exr piz wavelet decompression

Richard Monette 7 years ago
parent
commit
801a3872d4

+ 639 - 19
examples/js/loaders/EXRLoader.js

@@ -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
 	};
 

BIN
examples/textures/piz_compressed.exr


+ 1 - 1
examples/webgl_loader_texture_exr.html

@@ -111,7 +111,7 @@
 
 				var loader = new THREE.EXRLoader();
 
-				var texture = loader.load( "textures/uncompressed.exr", function( texture, textureData ){
+				var texture = loader.load( "textures/piz_compressed.exr", function( texture, textureData ){
 					console.log( textureData.header ); // exr header
 
 					texture.minFilter = THREE.NearestFilter;