Browse Source

EXRLoader: refactor

Guilherme Avila 5 years ago
parent
commit
343c6f1c71
2 changed files with 499 additions and 430 deletions
  1. 250 215
      examples/js/loaders/EXRLoader.js
  2. 249 215
      examples/jsm/loaders/EXRLoader.js

+ 250 - 215
examples/js/loaders/EXRLoader.js

@@ -1,8 +1,9 @@
 /**
  * @author Richard M. / https://github.com/richardmonette
+ * @author ScieCode / http://github.com/sciecode
  *
- * OpenEXR loader which, currently, supports reading 16 bit half data, in either
- * uncompressed or PIZ wavelet compressed form.
+ * OpenEXR loader which, currently, supports uncompressed, ZIP(S), RLE and PIZ wavelet compression.
+ * Supports reading 16 and 32 bit data format, except for PIZ compression which only reads 16-bit data.
  *
  * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
  * implementation, so I have preserved their copyright notices.
@@ -690,83 +691,106 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 		}
 
-		function decompressPIZ( outBuffer, outOffset, uInt8Array, inDataView, inOffset, tmpBufSize, num_channels, exrChannelInfos, dataWidth, num_lines ) {
+		function predictor( source ) {
 
-			var bitmap = new Uint8Array( BITMAP_SIZE );
+			for ( var t = 1; t < source.length; t ++ ) {
 
-			var minNonZero = parseUint16( inDataView, inOffset );
-			var maxNonZero = parseUint16( inDataView, inOffset );
+				var d = source[ t - 1 ] + source[ t ] - 128;
+				source[ t ] = d;
 
-			if ( maxNonZero >= BITMAP_SIZE ) {
+			}
 
-				throw 'Something is wrong with PIZ_COMPRESSION BITMAP_SIZE';
+		}
 
-			}
+		function interleaveScalar( source, out ) {
 
-			if ( minNonZero <= maxNonZero ) {
+			var t1 = 0;
+			var t2 = Math.floor( ( source.length + 1 ) / 2 );
+			var s = 0;
+			var stop = source.length - 1;
 
-				for ( var i = 0; i < maxNonZero - minNonZero + 1; i ++ ) {
+			while ( true ) {
 
-					bitmap[ i + minNonZero ] = parseUint8( inDataView, inOffset );
+				if ( s > stop ) break;
+				out[ s ++ ] = source[ t1 ++ ];
 
-				}
+				if ( s > stop ) break;
+				out[ s ++ ] = source[ t2 ++ ];
 
 			}
 
-			var lut = new Uint16Array( USHORT_RANGE );
-			reverseLutFromBitmap( bitmap, lut );
+		}
 
-			var length = parseUint32( inDataView, inOffset );
+		function decodeRunLength( source ) {
 
-			hufUncompress( uInt8Array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize );
+			var size = source.byteLength;
+			var out = new Array();
+			var p = 0;
 
-			var pizChannelData = new Array( num_channels );
+			var reader = new DataView( source );
 
-			var outBufferEnd = 0;
+			while ( size > 0 ) {
 
-			for ( var i = 0; i < num_channels; i ++ ) {
+				var l = reader.getInt8( p++ );
 
-				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;
+				if ( l < 0 ) {
 
-				outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size;
+					var count = -l;
+					size -= count + 1;
 
-			}
+					for ( var i = 0; i < count; i++ ) {
 
-			var fooOffset = 0;
+						out.push( reader.getUint8( p++ ) );
 
-			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
-					);
+				} else {
+
+					var count = l;
+					size -= 2;
+
+					var value = reader.getUint8( p++ );
+
+					for ( var i = 0; i < count+1; i++ ) {
+
+						out.push( value );
+
+					}
+
 
 				}
 
 			}
 
-			applyLut( lut, outBuffer, outBufferEnd );
+			return out;
 
-			return true;
+		}
+
+		function uncompressRaw( info ) {
+
+			return new DataView( info.array.buffer, info.offset.value, info.size ); // 
 
 		}
 
-		function decompressZIP( inDataView, offset, compressedSize, pixelType ) {
+		function uncompressRLE( info ) {
 
-			var raw;
+			var compressed = info.viewer.buffer.slice( info.offset.value, info.offset.value + info.size );
+
+			var rawBuffer = new Uint8Array( decodeRunLength( compressed ) );
+			var tmpBuffer = new Uint8Array( rawBuffer.length );
 
-			var compressed = new Uint8Array( inDataView.buffer.slice( offset.value, offset.value + compressedSize ) );
+			predictor( rawBuffer ); // revert predictor
+
+			interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
+
+			return new DataView( tmpBuffer.buffer );
+
+		}
+
+		function uncompressZIP( info ) {
+
+			var compressed = info.array.slice( info.offset.value, info.offset.value + info.size );
 
 			if ( typeof Zlib === 'undefined' ) {
 
@@ -779,52 +803,109 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 			var rawBuffer = new Uint8Array( inflate.decompress().buffer );
 			var tmpBuffer = new Uint8Array( rawBuffer.length );
 
-			reconstruct_scalar( rawBuffer ); // reorder pixels
+			predictor( rawBuffer ); // revert predictor
 
-			interleave_scalar( rawBuffer, tmpBuffer ); // interleave pixels
+			interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
 
-			if ( pixelType == 1 ) {
+			return new DataView( tmpBuffer.buffer );
+
+		}
 
-				raw = new Uint16Array( tmpBuffer.buffer );
+		function uncompressPIZ( info ) {
 
-			} else if ( pixelType == 2 ) {
+			var inDataView = info.viewer;
+			var inOffset = { value: info.offset.value };
 
-				raw = new Float32Array( tmpBuffer.buffer );
+			var tmpBufSize = info.width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
+			var outBuffer = new Uint16Array( tmpBufSize );
+			var outOffset = { value: 0 };
+
+			var bitmap = new Uint8Array( BITMAP_SIZE );
+
+			var minNonZero = parseUint16( inDataView, inOffset );
+			var maxNonZero = parseUint16( inDataView, inOffset );
+
+			if ( maxNonZero >= BITMAP_SIZE ) {
+
+				throw 'Something is wrong with PIZ_COMPRESSION BITMAP_SIZE';
 
 			}
 
-			return raw;
+			if ( minNonZero <= maxNonZero ) {
 
-		}
+				for ( var i = 0; i < maxNonZero - minNonZero + 1; i ++ ) {
 
-		function reconstruct_scalar( source ) {
+					bitmap[ i + minNonZero ] = parseUint8( inDataView, inOffset );
 
-			for ( let t = 1; t < source.length; t ++ ) {
+				}
 
-				var d = source[ t - 1 ] + source[ t ] - 128;
-				source[ t ] = d;
+			}
+
+			var lut = new Uint16Array( USHORT_RANGE );
+			reverseLutFromBitmap( bitmap, lut );
+
+			var length = parseUint32( inDataView, inOffset );
+
+			hufUncompress( info.array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize );
+
+			var pizChannelData = new Array( info.channels );
+
+			var outBufferEnd = 0;
+
+			for ( var i = 0; i < info.channels; i ++ ) {
+
+				pizChannelData[ i ] = {};
+				pizChannelData[ i ][ 'start' ] = outBufferEnd;
+				pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ];
+				pizChannelData[ i ][ 'nx' ] = info.width;
+				pizChannelData[ i ][ 'ny' ] = info.lines;
+				pizChannelData[ i ][ 'size' ] = 1;
+
+				outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size;
 
 			}
 
-		}
+			var fooOffset = 0;
 
-		function interleave_scalar( source, out ) {
+			for ( var i = 0; i < info.channels; i ++ ) {
 
-			var t1 = 0;
-			var t2 = Math.floor( ( source.length + 1 ) / 2 );
-			var s = 0;
-			var stop = source.length - 1;
+				for ( var j = 0; j < pizChannelData[ i ].size; ++ j ) {
 
-			while ( true ) {
+					fooOffset += wav2Decode(
+						j + fooOffset,
+						outBuffer,
+						pizChannelData[ i ].nx,
+						pizChannelData[ i ].size,
+						pizChannelData[ i ].ny,
+						pizChannelData[ i ].nx * pizChannelData[ i ].size
+					);
 
-				if ( s > stop ) break;
-				out[ s ++ ] = source[ t1 ++ ];
+				}
 
-				if ( s > stop ) break;
-				out[ s ++ ] = source[ t2 ++ ];
+			}
+
+			applyLut( lut, outBuffer, outBufferEnd );
+
+			var tmpBuffer = new Uint8Array( outBuffer.buffer.byteLength );
+			var tmpOffset = 0;
+			var n = info.width * 2;
+
+			for ( var y = 0; y < info.lines; y++ ) {
+
+				for ( var c = 0; c < info.channels; c++ ) {
+
+					var cd = pizChannelData[ c ];
+					var cp = new Uint8Array( outBuffer.buffer, cd.end * 2 + y * n, n );
+
+					tmpBuffer.set( cp, tmpOffset );
+					tmpOffset += n;
+
+				}
 
 			}
 
+			return new DataView( tmpBuffer.buffer );
+
 		}
 
 		function parseNullTerminatedString( buffer, offset ) {
@@ -1124,17 +1205,85 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 		}
 
 		// offsets
-
 		var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
 		var scanlineBlockSize = 1; // 1 for NO_COMPRESSION
+		
+		var uncompress;
 
-		if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
+		if ( EXRHeader.compression === 'NO_COMPRESSION' ) {
 
-			scanlineBlockSize = 32;
+			scanlineBlockSize = 1;
+			uncompress = uncompressRaw;
+
+		} else if ( EXRHeader.compression === 'RLE_COMPRESSION' ) {
+
+			scanlineBlockSize = 1;
+			uncompress = uncompressRLE;
+
+		} else if ( EXRHeader.compression === 'ZIPS_COMPRESSION' ) {
+
+			scanlineBlockSize = 1;
+			uncompress = uncompressZIP;
 
 		} else if ( EXRHeader.compression === 'ZIP_COMPRESSION' ) {
 
 			scanlineBlockSize = 16;
+			uncompress = uncompressZIP;
+
+		} else if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
+
+			scanlineBlockSize = 32;
+			uncompress = uncompressPIZ;
+
+		} else {
+
+			throw 'EXRLoader.parse: ' + EXRHeader.compression + ' is unsupported';
+
+		}
+
+		var size_t;
+		var getValue;
+
+		// mixed pixelType not supported
+		var pixelType = EXRHeader.channels[ 0 ].pixelType;
+
+		if ( pixelType === 1 ) { // half
+
+			switch ( this.type ) {
+
+				case THREE.FloatType:
+
+					getValue = parseFloat16;
+					size_t = INT16_SIZE;
+					break;
+
+				case THREE.HalfFloatType:
+
+					getValue = parseUint16;
+					size_t = INT16_SIZE;
+					break;
+
+			}
+
+		} else if ( pixelType === 2 ) { // float
+
+			switch ( this.type ) {
+
+				case THREE.FloatType:
+
+					getValue = parseFloat32;
+					size_t = FLOAT32_SIZE;
+					break;
+
+				case THREE.HalfFloatType:
+
+					throw 'EXRLoader.parse: unsupported HalfFloatType texture for FloatType image file.';
+
+			}
+
+		} else {
+
+			throw 'EXRLoader.parse: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + ' for ' + EXRHeader.compression + '.';
 
 		}
 
@@ -1196,168 +1345,58 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 			A: 3
 		};
 
-		if ( EXRHeader.compression === 'NO_COMPRESSION' ) {
-
-			for ( var y = 0; y < height; y ++ ) {
-
-				var y_scanline = parseUint32( bufferDataView, offset );
-				parseUint32( bufferDataView, offset ); // dataSize
-
-				for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
-
-					var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
-
-					if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
-
-						for ( var x = 0; x < width; x ++ ) {
-
-							switch ( this.type ) {
-
-								case THREE.FloatType:
-
-									var val = parseFloat16( bufferDataView, offset );
-									break;
+		var compressionInfo = {
 
-								case THREE.HalfFloatType:
-
-									var val = parseUint16( bufferDataView, offset );
-									break;
-
-							}
-
-							byteArray[ ( ( ( height - y_scanline ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
-
-						}
-
-					} else {
-
-						throw 'EXRLoader.parse: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + ' for ' + EXRHeader.compression + '.';
-
-					}
+			array: uInt8Array, 
+			viewer: bufferDataView, 
+			offset: offset, 
+			channels: EXRHeader.channels.length,
+			width: width, 
+			lines: scanlineBlockSize, 
+			size: 0
 
-				}
+		};
 
-			}
+		if ( EXRHeader.compression === 'NO_COMPRESSION'  ||
+			EXRHeader.compression === 'ZIP_COMPRESSION'  ||
+			EXRHeader.compression === 'ZIPS_COMPRESSION' || 
+			EXRHeader.compression === 'RLE_COMPRESSION'  ||
+			EXRHeader.compression === 'PIZ_COMPRESSION'  ) {
 
-		} else if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
+			var size;
+			var viewer;
+			var tmpOffset = { value: 0 };
 
 			for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
 
 				parseUint32( bufferDataView, offset ); // line_no
-				parseUint32( bufferDataView, offset ); // data_len
-
-				var tmpBufferSize = width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
-				var tmpBuffer = new Uint16Array( tmpBufferSize );
-				var tmpOffset = { value: 0 };
-
-				decompressPIZ( tmpBuffer, tmpOffset, uInt8Array, bufferDataView, offset, tmpBufferSize, EXRHeader.channels.length, EXRHeader.channels, width, scanlineBlockSize );
-
-				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
-
-					for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
-
-						var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
-
-						if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
-
-							for ( var x = 0; x < width; x ++ ) {
-
-								var idx = ( channelID * ( scanlineBlockSize * width ) ) + ( line_y * width ) + x;
-
-								switch ( this.type ) {
-
-									case THREE.FloatType:
+				size = parseUint32( bufferDataView, offset ); // data_len
 
-										var val = decodeFloat16( tmpBuffer[ idx ] );
-										break;
+				compressionInfo.offset = offset;
+				compressionInfo.size = size;
 
-									case THREE.HalfFloatType:
-
-										var val = tmpBuffer[ idx ];
-										break;
-
-								}
-
-								var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
-
-								byteArray[ ( ( ( height - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
-
-							}
-
-						} else {
-
-							throw 'EXRLoader.parse: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + ' for ' + EXRHeader.compression + '.';
-
-						}
-
-					}
-
-				}
-
-			}
+				viewer = uncompress( compressionInfo );
 
-		} else if ( EXRHeader.compression === 'ZIP_COMPRESSION' ||
-					EXRHeader.compression === 'ZIPS_COMPRESSION' ) {
+				offset.value += size;
 
-			for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
-
-				parseUint32( bufferDataView, offset ); // line_no
-				var compressedSize = parseUint32( bufferDataView, offset ); // data_len
+				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
 
-				var raw = decompressZIP( bufferDataView, offset, compressedSize, EXRHeader.channels[ 0 ].pixelType );
+					var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
 
-				offset.value += compressedSize;
-
-				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
+					if ( true_y >= height ) break;
 
 					for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
 
-						for ( var x = 0; x < width; x ++ ) {
+						var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
 
-							var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+						for ( var x = 0; x < width; x ++ ) {
 
 							var idx = ( line_y * ( EXRHeader.channels.length * width ) ) + ( channelID * width ) + x;
+							tmpOffset.value = idx * size_t;
 
-							if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
-
-								switch ( this.type ) {
-
-									case THREE.FloatType:
-
-										var val = decodeFloat16( raw[ idx ] );
-										break;
-
-									case THREE.HalfFloatType:
-
-										var val = raw[ idx ];
-										break;
-
-								}
-
-							} else if ( EXRHeader.channels[ channelID ].pixelType === 2 ) { // float
+							var val = getValue( viewer, tmpOffset );
 
-								switch ( this.type ) {
-
-									case THREE.FloatType:
-
-										var val = raw[ idx ];
-										break;
-
-									case THREE.HalfFloatType:
-
-										throw 'EXRLoader.parse: unsupported HalfFloatType texture for FloatType image file.';
-
-								}
-
-							} else {
-
-								throw 'EXRLoader.parse: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + ' for ' + EXRHeader.compression + '.';
-
-							}
-
-							var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
-
-							byteArray[ ( ( ( height - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+							byteArray[ ( ( ( height - 1 - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
 
 						}
 
@@ -1367,10 +1406,6 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 			}
 
-		} else {
-
-			throw 'EXRLoader.parse: ' + EXRHeader.compression + ' is unsupported';
-
 		}
 
 		return {
@@ -1425,4 +1460,4 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 	}
 
-} );
+} );

+ 249 - 215
examples/jsm/loaders/EXRLoader.js

@@ -1,8 +1,9 @@
 /**
  * @author Richard M. / https://github.com/richardmonette
+ * @author ScieCode / http://github.com/sciecode
  *
- * OpenEXR loader which, currently, supports reading 16 bit half data, in either
- * uncompressed or PIZ wavelet compressed form.
+ * OpenEXR loader which, currently, supports uncompressed, ZIP(S), RLE and PIZ wavelet compression.
+ * Supports reading 16 and 32 bit data format, except for PIZ compression which only reads 16-bit data.
  *
  * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
  * implementation, so I have preserved their copyright notices.
@@ -701,83 +702,106 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 		}
 
-		function decompressPIZ( outBuffer, outOffset, uInt8Array, inDataView, inOffset, tmpBufSize, num_channels, exrChannelInfos, dataWidth, num_lines ) {
+		function predictor( source ) {
 
-			var bitmap = new Uint8Array( BITMAP_SIZE );
+			for ( var t = 1; t < source.length; t ++ ) {
 
-			var minNonZero = parseUint16( inDataView, inOffset );
-			var maxNonZero = parseUint16( inDataView, inOffset );
+				var d = source[ t - 1 ] + source[ t ] - 128;
+				source[ t ] = d;
 
-			if ( maxNonZero >= BITMAP_SIZE ) {
+			}
 
-				throw 'Something is wrong with PIZ_COMPRESSION BITMAP_SIZE';
+		}
 
-			}
+		function interleaveScalar( source, out ) {
 
-			if ( minNonZero <= maxNonZero ) {
+			var t1 = 0;
+			var t2 = Math.floor( ( source.length + 1 ) / 2 );
+			var s = 0;
+			var stop = source.length - 1;
 
-				for ( var i = 0; i < maxNonZero - minNonZero + 1; i ++ ) {
+			while ( true ) {
 
-					bitmap[ i + minNonZero ] = parseUint8( inDataView, inOffset );
+				if ( s > stop ) break;
+				out[ s ++ ] = source[ t1 ++ ];
 
-				}
+				if ( s > stop ) break;
+				out[ s ++ ] = source[ t2 ++ ];
 
 			}
 
-			var lut = new Uint16Array( USHORT_RANGE );
-			reverseLutFromBitmap( bitmap, lut );
+		}
 
-			var length = parseUint32( inDataView, inOffset );
+		function decodeRunLength( source ) {
 
-			hufUncompress( uInt8Array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize );
+			var size = source.byteLength;
+			var out = new Array();
+			var p = 0;
 
-			var pizChannelData = new Array( num_channels );
+			var reader = new DataView( source );
 
-			var outBufferEnd = 0;
+			while ( size > 0 ) {
 
-			for ( var i = 0; i < num_channels; i ++ ) {
+				var l = reader.getInt8( p++ );
 
-				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;
+				if ( l < 0 ) {
 
-				outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size;
+					var count = -l;
+					size -= count + 1;
 
-			}
+					for ( var i = 0; i < count; i++ ) {
 
-			var fooOffset = 0;
+						out.push( reader.getUint8( p++ ) );
 
-			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
-					);
+				} else {
+
+					var count = l;
+					size -= 2;
+
+					var value = reader.getUint8( p++ );
+
+					for ( var i = 0; i < count+1; i++ ) {
+
+						out.push( value );
+
+					}
+
 
 				}
 
 			}
 
-			applyLut( lut, outBuffer, outBufferEnd );
+			return out;
 
-			return true;
+		}
+
+		function uncompressRaw( info ) {
+
+			return new DataView( info.array.buffer, info.offset.value, info.size ); // 
 
 		}
 
-		function decompressZIP( inDataView, offset, compressedSize, pixelType ) {
+		function uncompressRLE( info ) {
 
-			var raw;
+			var compressed = info.viewer.buffer.slice( info.offset.value, info.offset.value + info.size );
+
+			var rawBuffer = new Uint8Array( decodeRunLength( compressed ) );
+			var tmpBuffer = new Uint8Array( rawBuffer.length );
 
-			var compressed = new Uint8Array( inDataView.buffer.slice( offset.value, offset.value + compressedSize ) );
+			predictor( rawBuffer ); // revert predictor
+
+			interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
+
+			return new DataView( tmpBuffer.buffer );
+
+		}
+
+		function uncompressZIP( info ) {
+
+			var compressed = info.array.slice( info.offset.value, info.offset.value + info.size );
 
 			if ( typeof Zlib === 'undefined' ) {
 
@@ -790,52 +814,109 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 			var rawBuffer = new Uint8Array( inflate.decompress().buffer );
 			var tmpBuffer = new Uint8Array( rawBuffer.length );
 
-			reconstruct_scalar( rawBuffer ); // reorder pixels
+			predictor( rawBuffer ); // revert predictor
+
+			interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
+
+			return new DataView( tmpBuffer.buffer );
 
-			interleave_scalar( rawBuffer, tmpBuffer ); // interleave pixels
+		}
+
+		function uncompressPIZ( info ) {
 
-			if ( pixelType == 1 ) {
+			var inDataView = info.viewer;
+			var inOffset = { value: info.offset.value };
 
-				raw = new Uint16Array( tmpBuffer.buffer );
+			var tmpBufSize = info.width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
+			var outBuffer = new Uint16Array( tmpBufSize );
+			var outOffset = { value: 0 };
 
-			} else if ( pixelType == 2 ) {
+			var bitmap = new Uint8Array( BITMAP_SIZE );
 
-				raw = new Float32Array( tmpBuffer.buffer );
+			var minNonZero = parseUint16( inDataView, inOffset );
+			var maxNonZero = parseUint16( inDataView, inOffset );
+
+			if ( maxNonZero >= BITMAP_SIZE ) {
+
+				throw 'Something is wrong with PIZ_COMPRESSION BITMAP_SIZE';
 
 			}
 
-			return raw;
+			if ( minNonZero <= maxNonZero ) {
 
-		}
+				for ( var i = 0; i < maxNonZero - minNonZero + 1; i ++ ) {
 
-		function reconstruct_scalar( source ) {
+					bitmap[ i + minNonZero ] = parseUint8( inDataView, inOffset );
 
-			for ( let t = 1; t < source.length; t ++ ) {
+				}
 
-				var d = source[ t - 1 ] + source[ t ] - 128;
-				source[ t ] = d;
+			}
+
+			var lut = new Uint16Array( USHORT_RANGE );
+			reverseLutFromBitmap( bitmap, lut );
+
+			var length = parseUint32( inDataView, inOffset );
+
+			hufUncompress( info.array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize );
+
+			var pizChannelData = new Array( info.channels );
+
+			var outBufferEnd = 0;
+
+			for ( var i = 0; i < info.channels; i ++ ) {
+
+				pizChannelData[ i ] = {};
+				pizChannelData[ i ][ 'start' ] = outBufferEnd;
+				pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ];
+				pizChannelData[ i ][ 'nx' ] = info.width;
+				pizChannelData[ i ][ 'ny' ] = info.lines;
+				pizChannelData[ i ][ 'size' ] = 1;
+
+				outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size;
 
 			}
 
-		}
+			var fooOffset = 0;
 
-		function interleave_scalar( source, out ) {
+			for ( var i = 0; i < info.channels; i ++ ) {
 
-			var t1 = 0;
-			var t2 = Math.floor( ( source.length + 1 ) / 2 );
-			var s = 0;
-			var stop = source.length - 1;
+				for ( var j = 0; j < pizChannelData[ i ].size; ++ j ) {
 
-			while ( true ) {
+					fooOffset += wav2Decode(
+						j + fooOffset,
+						outBuffer,
+						pizChannelData[ i ].nx,
+						pizChannelData[ i ].size,
+						pizChannelData[ i ].ny,
+						pizChannelData[ i ].nx * pizChannelData[ i ].size
+					);
 
-				if ( s > stop ) break;
-				out[ s ++ ] = source[ t1 ++ ];
+				}
 
-				if ( s > stop ) break;
-				out[ s ++ ] = source[ t2 ++ ];
+			}
+
+			applyLut( lut, outBuffer, outBufferEnd );
+
+			var tmpBuffer = new Uint8Array( outBuffer.buffer.byteLength );
+			var tmpOffset = 0;
+			var n = info.width * 2;
+
+			for ( var y = 0; y < info.lines; y++ ) {
+
+				for ( var c = 0; c < info.channels; c++ ) {
+
+					var cd = pizChannelData[ c ];
+					var cp = new Uint8Array( outBuffer.buffer, cd.end * 2 + y * n, n );
+
+					tmpBuffer.set( cp, tmpOffset );
+					tmpOffset += n;
+
+				}
 
 			}
 
+			return new DataView( tmpBuffer.buffer );
+
 		}
 
 		function parseNullTerminatedString( buffer, offset ) {
@@ -1135,17 +1216,85 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 		}
 
 		// offsets
-
 		var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
 		var scanlineBlockSize = 1; // 1 for NO_COMPRESSION
+		
+		var uncompress;
 
-		if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
+		if ( EXRHeader.compression === 'NO_COMPRESSION' ) {
 
-			scanlineBlockSize = 32;
+			scanlineBlockSize = 1;
+			uncompress = uncompressRaw;
+
+		} else if ( EXRHeader.compression === 'RLE_COMPRESSION' ) {
+
+			scanlineBlockSize = 1;
+			uncompress = uncompressRLE;
+
+		} else if ( EXRHeader.compression === 'ZIPS_COMPRESSION' ) {
+
+			scanlineBlockSize = 1;
+			uncompress = uncompressZIP;
 
 		} else if ( EXRHeader.compression === 'ZIP_COMPRESSION' ) {
 
 			scanlineBlockSize = 16;
+			uncompress = uncompressZIP;
+
+		} else if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
+
+			scanlineBlockSize = 32;
+			uncompress = uncompressPIZ;
+
+		} else {
+
+			throw 'EXRLoader.parse: ' + EXRHeader.compression + ' is unsupported';
+
+		}
+
+		var size_t;
+		var getValue;
+
+		// mixed pixelType not supported
+		var pixelType = EXRHeader.channels[ 0 ].pixelType;
+
+		if ( pixelType === 1 ) { // half
+
+			switch ( this.type ) {
+
+				case FloatType:
+
+					getValue = parseFloat16;
+					size_t = INT16_SIZE;
+					break;
+
+				case HalfFloatType:
+
+					getValue = parseUint16;
+					size_t = INT16_SIZE;
+					break;
+
+			}
+
+		} else if ( pixelType === 2 ) { // float
+
+			switch ( this.type ) {
+
+				case FloatType:
+
+					getValue = parseFloat32;
+					size_t = FLOAT32_SIZE;
+					break;
+
+				case HalfFloatType:
+
+					throw 'EXRLoader.parse: unsupported HalfFloatType texture for FloatType image file.';
+
+			}
+
+		} else {
+
+			throw 'EXRLoader.parse: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + ' for ' + EXRHeader.compression + '.';
 
 		}
 
@@ -1207,168 +1356,58 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 			A: 3
 		};
 
-		if ( EXRHeader.compression === 'NO_COMPRESSION' ) {
-
-			for ( var y = 0; y < height; y ++ ) {
-
-				var y_scanline = parseUint32( bufferDataView, offset );
-				parseUint32( bufferDataView, offset ); // dataSize
-
-				for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
-
-					var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
-
-					if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
-
-						for ( var x = 0; x < width; x ++ ) {
-
-							switch ( this.type ) {
-
-								case FloatType:
-
-									var val = parseFloat16( bufferDataView, offset );
-									break;
-
-								case HalfFloatType:
-
-									var val = parseUint16( bufferDataView, offset );
-									break;
-
-							}
+		var compressionInfo = {
 
-							byteArray[ ( ( ( height - y_scanline ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+			array: uInt8Array, 
+			viewer: bufferDataView, 
+			offset: offset, 
+			channels: EXRHeader.channels.length,
+			width: width, 
+			lines: scanlineBlockSize, 
+			size: 0
 
-						}
-
-					} else {
-
-						throw 'EXRLoader.parse: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + ' for ' + EXRHeader.compression + '.';
-
-					}
-
-				}
+		};
 
-			}
+		if ( EXRHeader.compression === 'NO_COMPRESSION'  ||
+			EXRHeader.compression === 'ZIP_COMPRESSION'  ||
+			EXRHeader.compression === 'ZIPS_COMPRESSION' || 
+			EXRHeader.compression === 'RLE_COMPRESSION'  ||
+			EXRHeader.compression === 'PIZ_COMPRESSION'  ) {
 
-		} else if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
+			var size;
+			var viewer;
+			var tmpOffset = { value: 0 };
 
 			for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
 
 				parseUint32( bufferDataView, offset ); // line_no
-				parseUint32( bufferDataView, offset ); // data_len
-
-				var tmpBufferSize = width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
-				var tmpBuffer = new Uint16Array( tmpBufferSize );
-				var tmpOffset = { value: 0 };
-
-				decompressPIZ( tmpBuffer, tmpOffset, uInt8Array, bufferDataView, offset, tmpBufferSize, EXRHeader.channels.length, EXRHeader.channels, width, scanlineBlockSize );
-
-				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
-
-					for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
-
-						var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
-
-						if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
-
-							for ( var x = 0; x < width; x ++ ) {
-
-								var idx = ( channelID * ( scanlineBlockSize * width ) ) + ( line_y * width ) + x;
-
-								switch ( this.type ) {
-
-									case FloatType:
-
-										var val = decodeFloat16( tmpBuffer[ idx ] );
-										break;
+				size = parseUint32( bufferDataView, offset ); // data_len
 
-									case HalfFloatType:
+				compressionInfo.offset = offset;
+				compressionInfo.size = size;
 
-										var val = tmpBuffer[ idx ];
-										break;
+				viewer = uncompress( compressionInfo );
 
-								}
-
-								var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
-
-								byteArray[ ( ( ( height - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
-
-							}
-
-						} else {
-
-							throw 'EXRLoader.parse: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + ' for ' + EXRHeader.compression + '.';
-
-						}
+				offset.value += size;
 
-					}
-
-				}
-
-			}
-
-		} else if ( EXRHeader.compression === 'ZIP_COMPRESSION' ||
-					EXRHeader.compression === 'ZIPS_COMPRESSION' ) {
-
-			for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
-
-				parseUint32( bufferDataView, offset ); // line_no
-				var compressedSize = parseUint32( bufferDataView, offset ); // data_len
-
-				var raw = decompressZIP( bufferDataView, offset, compressedSize, EXRHeader.channels[ 0 ].pixelType );
+				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
 
-				offset.value += compressedSize;
+					var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
 
-				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
+					if ( true_y >= height ) break;
 
 					for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
 
-						for ( var x = 0; x < width; x ++ ) {
+						var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
 
-							var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+						for ( var x = 0; x < width; x ++ ) {
 
 							var idx = ( line_y * ( EXRHeader.channels.length * width ) ) + ( channelID * width ) + x;
+							tmpOffset.value = idx * size_t;
 
-							if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
-
-								switch ( this.type ) {
-
-									case FloatType:
-
-										var val = decodeFloat16( raw[ idx ] );
-										break;
-
-									case HalfFloatType:
-
-										var val = raw[ idx ];
-										break;
-
-								}
-
-							} else if ( EXRHeader.channels[ channelID ].pixelType === 2 ) { // float
-
-								switch ( this.type ) {
+							var val = getValue( viewer, tmpOffset );
 
-									case FloatType:
-
-										var val = raw[ idx ];
-										break;
-
-									case HalfFloatType:
-
-										throw 'EXRLoader.parse: unsupported HalfFloatType texture for FloatType image file.';
-
-								}
-
-							} else {
-
-								throw 'EXRLoader.parse: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + ' for ' + EXRHeader.compression + '.';
-
-							}
-
-							var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
-
-							byteArray[ ( ( ( height - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+							byteArray[ ( ( ( height - 1 - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
 
 						}
 
@@ -1378,10 +1417,6 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 			}
 
-		} else {
-
-			throw 'EXRLoader.parse: ' + EXRHeader.compression + ' is unsupported';
-
 		}
 
 		return {
@@ -1437,5 +1472,4 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 	}
 
 } );
-
 export { EXRLoader };