未验证 提交 d23e67e7 编写于 作者: W WestLangley 提交者: GitHub

Merge pull request #17904 from sciecode/dev-exrloader

EXRLoader: RLE support and uncompress refactor.
/**
* @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 compressed = info.viewer.buffer.slice( info.offset.value, info.offset.value + info.size );
var raw;
var rawBuffer = new Uint8Array( decodeRunLength( compressed ) );
var tmpBuffer = new Uint8Array( rawBuffer.length );
predictor( rawBuffer ); // revert predictor
interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
return new DataView( tmpBuffer.buffer );
var compressed = new Uint8Array( inDataView.buffer.slice( offset.value, offset.value + compressedSize ) );
}
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
interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
interleave_scalar( rawBuffer, tmpBuffer ); // interleave pixels
return new DataView( tmpBuffer.buffer );
if ( pixelType == 1 ) {
}
function uncompressPIZ( info ) {
raw = new Uint16Array( tmpBuffer.buffer );
var inDataView = info.viewer;
var inOffset = { value: info.offset.value };
} else if ( pixelType == 2 ) {
var tmpBufSize = info.width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
var outBuffer = new Uint16Array( tmpBufSize );
var outOffset = { value: 0 };
raw = new Float32Array( tmpBuffer.buffer );
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,92 @@ 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;
var scanlineBlockSize;
switch ( EXRHeader.compression ) {
if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
case 'NO_COMPRESSION':
scanlineBlockSize = 32;
scanlineBlockSize = 1;
uncompress = uncompressRaw;
break;
} else if ( EXRHeader.compression === 'ZIP_COMPRESSION' ) {
case 'RLE_COMPRESSION':
scanlineBlockSize = 1;
uncompress = uncompressRLE;
break;
scanlineBlockSize = 16;
case 'ZIPS_COMPRESSION':
scanlineBlockSize = 1;
uncompress = uncompressZIP;
break;
case 'ZIP_COMPRESSION':
scanlineBlockSize = 16;
uncompress = uncompressZIP;
break;
case 'PIZ_COMPRESSION':
scanlineBlockSize = 32;
uncompress = uncompressPIZ;
break;
default:
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 ' + pixelType + ' for ' + EXRHeader.compression + '.';
}
......@@ -1196,168 +1352,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
var compressionInfo = {
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 ++ ) {
array: uInt8Array,
viewer: bufferDataView,
offset: offset,
channels: EXRHeader.channels.length,
width: width,
lines: scanlineBlockSize,
size: 0
switch ( this.type ) {
case THREE.FloatType:
var val = parseFloat16( bufferDataView, offset );
break;
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 + '.';
}
};
}
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:
var val = decodeFloat16( tmpBuffer[ idx ] );
break;
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 + '.';
}
}
}
size = parseUint32( bufferDataView, offset ); // data_len
}
compressionInfo.offset = offset;
compressionInfo.size = size;
} else if ( EXRHeader.compression === 'ZIP_COMPRESSION' ||
EXRHeader.compression === 'ZIPS_COMPRESSION' ) {
viewer = uncompress( compressionInfo );
for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
parseUint32( bufferDataView, offset ); // line_no
var compressedSize = parseUint32( bufferDataView, offset ); // data_len
offset.value += size;
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 THREE.FloatType:
var val = decodeFloat16( raw[ idx ] );
break;
case THREE.HalfFloatType:
var val = raw[ idx ];
break;
}
var val = getValue( viewer, tmpOffset );
} else if ( EXRHeader.channels[ channelID ].pixelType === 2 ) { // float
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 +1413,6 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
}
} else {
throw 'EXRLoader.parse: ' + EXRHeader.compression + ' is unsupported';
}
return {
......@@ -1425,4 +1467,4 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
}
} );
} );
\ No newline at end of file
/**
* @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 compressed = info.viewer.buffer.slice( info.offset.value, info.offset.value + info.size );
var raw;
var rawBuffer = new Uint8Array( decodeRunLength( compressed ) );
var tmpBuffer = new Uint8Array( rawBuffer.length );
predictor( rawBuffer ); // revert predictor
interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
return new DataView( tmpBuffer.buffer );
var compressed = new Uint8Array( inDataView.buffer.slice( offset.value, offset.value + compressedSize ) );
}
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
interleave_scalar( rawBuffer, tmpBuffer ); // interleave pixels
return new DataView( tmpBuffer.buffer );
if ( pixelType == 1 ) {
}
function uncompressPIZ( info ) {
raw = new Uint16Array( tmpBuffer.buffer );
var inDataView = info.viewer;
var inOffset = { value: info.offset.value };
} else if ( pixelType == 2 ) {
var tmpBufSize = info.width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
var outBuffer = new Uint16Array( tmpBufSize );
var outOffset = { value: 0 };
raw = new Float32Array( tmpBuffer.buffer );
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 ) {
......@@ -1135,17 +1216,92 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
}
// offsets
var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
var scanlineBlockSize = 1; // 1 for NO_COMPRESSION
var uncompress;
var scanlineBlockSize;
switch ( EXRHeader.compression ) {
if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
case 'NO_COMPRESSION':
scanlineBlockSize = 32;
scanlineBlockSize = 1;
uncompress = uncompressRaw;
break;
} else if ( EXRHeader.compression === 'ZIP_COMPRESSION' ) {
case 'RLE_COMPRESSION':
scanlineBlockSize = 1;
uncompress = uncompressRLE;
break;
scanlineBlockSize = 16;
case 'ZIPS_COMPRESSION':
scanlineBlockSize = 1;
uncompress = uncompressZIP;
break;
case 'ZIP_COMPRESSION':
scanlineBlockSize = 16;
uncompress = uncompressZIP;
break;
case 'PIZ_COMPRESSION':
scanlineBlockSize = 32;
uncompress = uncompressPIZ;
break;
default:
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 ' + pixelType + ' for ' + EXRHeader.compression + '.';
}
......@@ -1207,168 +1363,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;
}
byteArray[ ( ( ( height - y_scanline ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
}
} else {
throw 'EXRLoader.parse: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + ' for ' + EXRHeader.compression + '.';
var compressionInfo = {
}
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 FloatType:
size = parseUint32( bufferDataView, offset ); // data_len
var val = decodeFloat16( tmpBuffer[ idx ] );
break;
compressionInfo.offset = offset;
compressionInfo.size = size;
case 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 FloatType:
var val = decodeFloat16( raw[ idx ] );
break;
case HalfFloatType:
var val = raw[ idx ];
break;
}
} else if ( EXRHeader.channels[ channelID ].pixelType === 2 ) { // float
var val = getValue( viewer, tmpOffset );
switch ( this.type ) {
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 +1424,6 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
}
} else {
throw 'EXRLoader.parse: ' + EXRHeader.compression + ' is unsupported';
}
return {
......@@ -1437,5 +1479,4 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
}
} );
export { EXRLoader };
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册