|
@@ -1269,18 +1269,18 @@ class EXRLoader extends DataTextureLoader {
|
|
|
const inDataView = info.viewer;
|
|
|
const inOffset = { value: info.offset.value };
|
|
|
|
|
|
- const outBuffer = new Uint16Array( info.width * info.scanlineBlockSize * ( info.channels * info.type ) );
|
|
|
+ const outBuffer = new Uint16Array( info.columns * info.lines * ( info.inputChannels.length * info.type ) );
|
|
|
const bitmap = new Uint8Array( BITMAP_SIZE );
|
|
|
|
|
|
// Setup channel info
|
|
|
let outBufferEnd = 0;
|
|
|
- const pizChannelData = new Array( info.channels );
|
|
|
- for ( let i = 0; i < info.channels; i ++ ) {
|
|
|
+ const pizChannelData = new Array( info.inputChannels.length );
|
|
|
+ for ( let i = 0, il = info.inputChannels.length; i < il; i ++ ) {
|
|
|
|
|
|
pizChannelData[ i ] = {};
|
|
|
pizChannelData[ i ][ 'start' ] = outBufferEnd;
|
|
|
pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ];
|
|
|
- pizChannelData[ i ][ 'nx' ] = info.width;
|
|
|
+ pizChannelData[ i ][ 'nx' ] = info.columns;
|
|
|
pizChannelData[ i ][ 'ny' ] = info.lines;
|
|
|
pizChannelData[ i ][ 'size' ] = info.type;
|
|
|
|
|
@@ -1319,7 +1319,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
hufUncompress( info.array, inDataView, inOffset, length, outBuffer, outBufferEnd );
|
|
|
|
|
|
// Wavelet decoding
|
|
|
- for ( let i = 0; i < info.channels; ++ i ) {
|
|
|
+ for ( let i = 0; i < info.inputChannels.length; ++ i ) {
|
|
|
|
|
|
const cd = pizChannelData[ i ];
|
|
|
|
|
@@ -1347,7 +1347,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
const tmpBuffer = new Uint8Array( outBuffer.buffer.byteLength );
|
|
|
for ( let y = 0; y < info.lines; y ++ ) {
|
|
|
|
|
|
- for ( let c = 0; c < info.channels; c ++ ) {
|
|
|
+ for ( let c = 0; c < info.inputChannels.length; c ++ ) {
|
|
|
|
|
|
const cd = pizChannelData[ c ];
|
|
|
|
|
@@ -1372,8 +1372,9 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
const rawBuffer = fflate.unzlibSync( compressed );
|
|
|
|
|
|
- const sz = info.lines * info.channels * info.width;
|
|
|
- const tmpBuffer = ( info.type == 1 ) ? new Uint16Array( sz ) : new Uint32Array( sz );
|
|
|
+ const byteSize = info.inputChannels.length * info.lines * info.columns * info.totalBytes;
|
|
|
+ const tmpBuffer = new ArrayBuffer( byteSize );
|
|
|
+ const viewer = new DataView( tmpBuffer );
|
|
|
|
|
|
let tmpBufferEnd = 0;
|
|
|
let writePtr = 0;
|
|
@@ -1381,26 +1382,27 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
for ( let y = 0; y < info.lines; y ++ ) {
|
|
|
|
|
|
- for ( let c = 0; c < info.channels; c ++ ) {
|
|
|
+ for ( let c = 0; c < info.inputChannels.length; c ++ ) {
|
|
|
|
|
|
let pixel = 0;
|
|
|
|
|
|
- switch ( info.type ) {
|
|
|
+ const type = info.inputChannels[ c ].pixelType;
|
|
|
+ switch ( type ) {
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
ptr[ 0 ] = tmpBufferEnd;
|
|
|
- ptr[ 1 ] = ptr[ 0 ] + info.width;
|
|
|
- tmpBufferEnd = ptr[ 1 ] + info.width;
|
|
|
+ ptr[ 1 ] = ptr[ 0 ] + info.columns;
|
|
|
+ tmpBufferEnd = ptr[ 1 ] + info.columns;
|
|
|
|
|
|
- for ( let j = 0; j < info.width; ++ j ) {
|
|
|
+ for ( let j = 0; j < info.columns; ++ j ) {
|
|
|
|
|
|
const diff = ( rawBuffer[ ptr[ 0 ] ++ ] << 8 ) | rawBuffer[ ptr[ 1 ] ++ ];
|
|
|
|
|
|
pixel += diff;
|
|
|
|
|
|
- tmpBuffer[ writePtr ] = pixel;
|
|
|
- writePtr ++;
|
|
|
+ viewer.setUint16( writePtr, pixel, true );
|
|
|
+ writePtr += 2;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1409,18 +1411,18 @@ class EXRLoader extends DataTextureLoader {
|
|
|
case 2:
|
|
|
|
|
|
ptr[ 0 ] = tmpBufferEnd;
|
|
|
- ptr[ 1 ] = ptr[ 0 ] + info.width;
|
|
|
- ptr[ 2 ] = ptr[ 1 ] + info.width;
|
|
|
- tmpBufferEnd = ptr[ 2 ] + info.width;
|
|
|
+ ptr[ 1 ] = ptr[ 0 ] + info.columns;
|
|
|
+ ptr[ 2 ] = ptr[ 1 ] + info.columns;
|
|
|
+ tmpBufferEnd = ptr[ 2 ] + info.columns;
|
|
|
|
|
|
- for ( let j = 0; j < info.width; ++ j ) {
|
|
|
+ for ( let j = 0; j < info.columns; ++ j ) {
|
|
|
|
|
|
const diff = ( rawBuffer[ ptr[ 0 ] ++ ] << 24 ) | ( rawBuffer[ ptr[ 1 ] ++ ] << 16 ) | ( rawBuffer[ ptr[ 2 ] ++ ] << 8 );
|
|
|
|
|
|
pixel += diff;
|
|
|
|
|
|
- tmpBuffer[ writePtr ] = pixel;
|
|
|
- writePtr ++;
|
|
|
+ viewer.setUint32( writePtr, pixel, true );
|
|
|
+ writePtr += 4;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1432,7 +1434,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
}
|
|
|
|
|
|
- return new DataView( tmpBuffer.buffer );
|
|
|
+ return viewer;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1440,7 +1442,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
const inDataView = info.viewer;
|
|
|
const inOffset = { value: info.offset.value };
|
|
|
- const outBuffer = new Uint8Array( info.width * info.lines * ( info.channels * info.type * INT16_SIZE ) );
|
|
|
+ const outBuffer = new Uint8Array( info.columns * info.lines * ( info.inputChannels.length * info.type * INT16_SIZE ) );
|
|
|
|
|
|
// Read compression header information
|
|
|
const dwaHeader = {
|
|
@@ -1488,9 +1490,9 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
// Classify channels
|
|
|
const channels = EXRHeader.channels;
|
|
|
- const channelData = new Array( info.channels );
|
|
|
+ const channelData = new Array( info.inputChannels.length );
|
|
|
|
|
|
- for ( let i = 0; i < info.channels; ++ i ) {
|
|
|
+ for ( let i = 0; i < info.inputChannels.length; ++ i ) {
|
|
|
|
|
|
const cd = channelData[ i ] = {};
|
|
|
const channel = channels[ i ];
|
|
@@ -1500,7 +1502,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
cd.decoded = false;
|
|
|
cd.type = channel.pixelType;
|
|
|
cd.pLinear = channel.pLinear;
|
|
|
- cd.width = info.width;
|
|
|
+ cd.width = info.columns;
|
|
|
cd.height = info.lines;
|
|
|
|
|
|
}
|
|
@@ -1509,7 +1511,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
idx: new Array( 3 )
|
|
|
};
|
|
|
|
|
|
- for ( let offset = 0; offset < info.channels; ++ offset ) {
|
|
|
+ for ( let offset = 0; offset < info.inputChannels.length; ++ offset ) {
|
|
|
|
|
|
const cd = channelData[ offset ];
|
|
|
|
|
@@ -1899,7 +1901,8 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
const lineOrders = [
|
|
|
'INCREASING_Y',
|
|
|
- 'DECREASING_Y'
|
|
|
+ 'DECREASING_Y',
|
|
|
+ 'RANDOM_Y',
|
|
|
];
|
|
|
|
|
|
const lineOrder = parseUint8( dataView, offset );
|
|
@@ -1908,6 +1911,45 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function parseEnvmap( dataView, offset ) {
|
|
|
+
|
|
|
+ const envmaps = [
|
|
|
+ 'ENVMAP_LATLONG',
|
|
|
+ 'ENVMAP_CUBE'
|
|
|
+ ];
|
|
|
+
|
|
|
+ const envmap = parseUint8( dataView, offset );
|
|
|
+
|
|
|
+ return envmaps[ envmap ];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function parseTiledesc( dataView, offset ) {
|
|
|
+
|
|
|
+ const levelModes = [
|
|
|
+ 'ONE_LEVEL',
|
|
|
+ 'MIPMAP_LEVELS',
|
|
|
+ 'RIPMAP_LEVELS',
|
|
|
+ ];
|
|
|
+
|
|
|
+ const roundingModes = [
|
|
|
+ 'ROUND_DOWN',
|
|
|
+ 'ROUND_UP',
|
|
|
+ ];
|
|
|
+
|
|
|
+ const xSize = parseUint32( dataView, offset );
|
|
|
+ const ySize = parseUint32( dataView, offset );
|
|
|
+ const modes = parseUint8( dataView, offset );
|
|
|
+
|
|
|
+ return {
|
|
|
+ xSize: xSize,
|
|
|
+ ySize: ySize,
|
|
|
+ levelMode: levelModes[ modes & 0xf ],
|
|
|
+ roundingMode: roundingModes[ modes >> 4 ]
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
function parseV2f( dataView, offset ) {
|
|
|
|
|
|
const x = parseFloat32( dataView, offset );
|
|
@@ -1949,6 +1991,14 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
return parseBox2i( dataView, offset );
|
|
|
|
|
|
+ } else if ( type === 'envmap' ) {
|
|
|
+
|
|
|
+ return parseEnvmap( dataView, offset );
|
|
|
+
|
|
|
+ } else if ( type === 'tiledesc' ) {
|
|
|
+
|
|
|
+ return parseTiledesc( dataView, offset );
|
|
|
+
|
|
|
} else if ( type === 'lineOrder' ) {
|
|
|
|
|
|
return parseLineOrder( dataView, offset );
|
|
@@ -1991,6 +2041,163 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function roundLog2( x, mode ) {
|
|
|
+
|
|
|
+ const log2 = Math.log2( x );
|
|
|
+ return mode == 'ROUND_DOWN' ? Math.floor( log2 ) : Math.ceil( log2 );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function calculateTileLevels( tiledesc, w, h ) {
|
|
|
+
|
|
|
+ let num = 0;
|
|
|
+
|
|
|
+ switch ( tiledesc.levelMode ) {
|
|
|
+
|
|
|
+ case 'ONE_LEVEL':
|
|
|
+ num = 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'MIPMAP_LEVELS':
|
|
|
+ num = roundLog2( Math.max( w, h ), tiledesc.roundingMode ) + 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'RIPMAP_LEVELS':
|
|
|
+ throw new Error( 'THREE.EXRLoader: RIPMAP_LEVELS tiles currently unsupported.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return num;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function calculateTiles( count, dataSize, size, roundingMode ) {
|
|
|
+
|
|
|
+ const tiles = new Array( count );
|
|
|
+
|
|
|
+ for ( let i = 0; i < count; i ++ ) {
|
|
|
+
|
|
|
+ const b = ( 1 << i );
|
|
|
+ let s = ( dataSize / b ) | 0;
|
|
|
+
|
|
|
+ if ( roundingMode == 'ROUND_UP' && s * b < dataSize ) s += 1;
|
|
|
+
|
|
|
+ const l = Math.max( s, 1 );
|
|
|
+
|
|
|
+ tiles[ i ] = ( ( l + size - 1 ) / size ) | 0;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return tiles;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function parseTiles() {
|
|
|
+
|
|
|
+ const EXRDecoder = this;
|
|
|
+ const offset = EXRDecoder.offset;
|
|
|
+ const tmpOffset = { value: 0 };
|
|
|
+
|
|
|
+ for ( let tile = 0; tile < EXRDecoder.tileCount; tile ++ ) {
|
|
|
+
|
|
|
+ const tileX = parseInt32( EXRDecoder.viewer, offset );
|
|
|
+ const tileY = parseInt32( EXRDecoder.viewer, offset );
|
|
|
+ offset.value += 8; // skip levels - only parsing top-level
|
|
|
+ EXRDecoder.size = parseUint32( EXRDecoder.viewer, offset );
|
|
|
+
|
|
|
+ const startX = tileX * EXRDecoder.blockWidth;
|
|
|
+ const startY = tileY * EXRDecoder.blockHeight;
|
|
|
+ EXRDecoder.columns = ( startX + EXRDecoder.blockWidth > EXRDecoder.width ) ? EXRDecoder.width - startX : EXRDecoder.blockWidth;
|
|
|
+ EXRDecoder.lines = ( startY + EXRDecoder.blockHeight > EXRDecoder.height ) ? EXRDecoder.height - startY : EXRDecoder.blockHeight;
|
|
|
+
|
|
|
+ const bytesBlockLine = EXRDecoder.columns * EXRDecoder.totalBytes;
|
|
|
+ const isCompressed = EXRDecoder.size < EXRDecoder.lines * bytesBlockLine;
|
|
|
+ const viewer = isCompressed ? EXRDecoder.uncompress( EXRDecoder ) : uncompressRAW( EXRDecoder );
|
|
|
+
|
|
|
+ offset.value += EXRDecoder.size;
|
|
|
+
|
|
|
+ for ( let line = 0; line < EXRDecoder.lines; line ++ ) {
|
|
|
+
|
|
|
+ const lineOffset = line * EXRDecoder.columns * EXRDecoder.totalBytes;
|
|
|
+
|
|
|
+ for ( let channelID = 0; channelID < EXRDecoder.inputChannels.length; channelID ++ ) {
|
|
|
+
|
|
|
+ const name = EXRHeader.channels[ channelID ].name;
|
|
|
+ const lOff = EXRDecoder.channelByteOffsets[ name ] * EXRDecoder.columns;
|
|
|
+ const cOff = EXRDecoder.decodeChannels[ name ];
|
|
|
+
|
|
|
+ if ( cOff === undefined ) continue;
|
|
|
+
|
|
|
+ tmpOffset.value = lineOffset + lOff;
|
|
|
+ const outLineOffset = ( EXRDecoder.height - ( 1 + startY + line ) ) * EXRDecoder.outLineWidth;
|
|
|
+
|
|
|
+ for ( let x = 0; x < EXRDecoder.columns; x ++ ) {
|
|
|
+
|
|
|
+ const outIndex = outLineOffset + ( x + startX ) * EXRDecoder.outputChannels + cOff;
|
|
|
+ EXRDecoder.byteArray[ outIndex ] = EXRDecoder.getter( viewer, tmpOffset );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function parseScanline() {
|
|
|
+
|
|
|
+ const EXRDecoder = this;
|
|
|
+ const offset = EXRDecoder.offset;
|
|
|
+ const tmpOffset = { value: 0 };
|
|
|
+
|
|
|
+ for ( let scanlineBlockIdx = 0; scanlineBlockIdx < EXRDecoder.height / EXRDecoder.blockHeight; scanlineBlockIdx ++ ) {
|
|
|
+
|
|
|
+ const line = parseInt32( EXRDecoder.viewer, offset ) - EXRHeader.dataWindow.yMin; // line_no
|
|
|
+ EXRDecoder.size = parseUint32( EXRDecoder.viewer, offset ); // data_len
|
|
|
+ EXRDecoder.lines = ( ( line + EXRDecoder.blockHeight > EXRDecoder.height ) ? ( EXRDecoder.height - line ) : EXRDecoder.blockHeight );
|
|
|
+
|
|
|
+ const bytesPerLine = EXRDecoder.columns * EXRDecoder.totalBytes;
|
|
|
+ const isCompressed = EXRDecoder.size < EXRDecoder.lines * bytesPerLine;
|
|
|
+ const viewer = isCompressed ? EXRDecoder.uncompress( EXRDecoder ) : uncompressRAW( EXRDecoder );
|
|
|
+
|
|
|
+ offset.value += EXRDecoder.size;
|
|
|
+
|
|
|
+ for ( let line_y = 0; line_y < EXRDecoder.blockHeight; line_y ++ ) {
|
|
|
+
|
|
|
+ const scan_y = scanlineBlockIdx * EXRDecoder.blockHeight;
|
|
|
+ const true_y = line_y + EXRDecoder.scanOrder( scan_y );
|
|
|
+ if ( true_y >= EXRDecoder.height ) continue;
|
|
|
+
|
|
|
+ const lineOffset = line_y * bytesPerLine;
|
|
|
+ const outLineOffset = ( EXRDecoder.height - 1 - true_y ) * EXRDecoder.outLineWidth;
|
|
|
+
|
|
|
+ for ( let channelID = 0; channelID < EXRDecoder.inputChannels.length; channelID ++ ) {
|
|
|
+
|
|
|
+ const name = EXRHeader.channels[ channelID ].name;
|
|
|
+ const lOff = EXRDecoder.channelByteOffsets[ name ] * EXRDecoder.columns;
|
|
|
+ const cOff = EXRDecoder.decodeChannels[ name ];
|
|
|
+
|
|
|
+ if ( cOff === undefined ) continue;
|
|
|
+
|
|
|
+ tmpOffset.value = lineOffset + lOff;
|
|
|
+
|
|
|
+ for ( let x = 0; x < EXRDecoder.columns; x ++ ) {
|
|
|
+
|
|
|
+ const outIndex = outLineOffset + x * EXRDecoder.outputChannels + cOff;
|
|
|
+ EXRDecoder.byteArray[ outIndex ] = EXRDecoder.getter( viewer, tmpOffset );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
function parseHeader( dataView, buffer, offset ) {
|
|
|
|
|
|
const EXRHeader = {};
|
|
@@ -2046,7 +2253,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( ( spec & ~ 0x04 ) != 0 ) { // unsupported tiled, deep-image, multi-part
|
|
|
+ if ( ( spec & ~ 0x06 ) != 0 ) { // unsupported deep-image, multi-part
|
|
|
|
|
|
console.error( 'THREE.EXRHeader:', EXRHeader );
|
|
|
throw new Error( 'THREE.EXRLoader: Provided file is currently unsupported.' );
|
|
@@ -2066,12 +2273,12 @@ class EXRLoader extends DataTextureLoader {
|
|
|
offset: offset,
|
|
|
width: EXRHeader.dataWindow.xMax - EXRHeader.dataWindow.xMin + 1,
|
|
|
height: EXRHeader.dataWindow.yMax - EXRHeader.dataWindow.yMin + 1,
|
|
|
- channels: EXRHeader.channels.length,
|
|
|
- channelLineOffsets: {},
|
|
|
+ inputChannels: EXRHeader.channels,
|
|
|
+ channelByteOffsets: {},
|
|
|
scanOrder: null,
|
|
|
- bytesPerLine: null,
|
|
|
+ totalBytes: null,
|
|
|
+ columns: null,
|
|
|
lines: null,
|
|
|
- inputSize: null,
|
|
|
type: null,
|
|
|
uncompress: null,
|
|
|
getter: null,
|
|
@@ -2082,42 +2289,42 @@ class EXRLoader extends DataTextureLoader {
|
|
|
switch ( EXRHeader.compression ) {
|
|
|
|
|
|
case 'NO_COMPRESSION':
|
|
|
- EXRDecoder.lines = 1;
|
|
|
+ EXRDecoder.blockHeight = 1;
|
|
|
EXRDecoder.uncompress = uncompressRAW;
|
|
|
break;
|
|
|
|
|
|
case 'RLE_COMPRESSION':
|
|
|
- EXRDecoder.lines = 1;
|
|
|
+ EXRDecoder.blockHeight = 1;
|
|
|
EXRDecoder.uncompress = uncompressRLE;
|
|
|
break;
|
|
|
|
|
|
case 'ZIPS_COMPRESSION':
|
|
|
- EXRDecoder.lines = 1;
|
|
|
+ EXRDecoder.blockHeight = 1;
|
|
|
EXRDecoder.uncompress = uncompressZIP;
|
|
|
break;
|
|
|
|
|
|
case 'ZIP_COMPRESSION':
|
|
|
- EXRDecoder.lines = 16;
|
|
|
+ EXRDecoder.blockHeight = 16;
|
|
|
EXRDecoder.uncompress = uncompressZIP;
|
|
|
break;
|
|
|
|
|
|
case 'PIZ_COMPRESSION':
|
|
|
- EXRDecoder.lines = 32;
|
|
|
+ EXRDecoder.blockHeight = 32;
|
|
|
EXRDecoder.uncompress = uncompressPIZ;
|
|
|
break;
|
|
|
|
|
|
case 'PXR24_COMPRESSION':
|
|
|
- EXRDecoder.lines = 16;
|
|
|
+ EXRDecoder.blockHeight = 16;
|
|
|
EXRDecoder.uncompress = uncompressPXR;
|
|
|
break;
|
|
|
|
|
|
case 'DWAA_COMPRESSION':
|
|
|
- EXRDecoder.lines = 32;
|
|
|
+ EXRDecoder.blockHeight = 32;
|
|
|
EXRDecoder.uncompress = uncompressDWA;
|
|
|
break;
|
|
|
|
|
|
case 'DWAB_COMPRESSION':
|
|
|
- EXRDecoder.lines = 256;
|
|
|
+ EXRDecoder.blockHeight = 256;
|
|
|
EXRDecoder.uncompress = uncompressDWA;
|
|
|
break;
|
|
|
|
|
@@ -2126,8 +2333,6 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
}
|
|
|
|
|
|
- EXRDecoder.scanlineBlockSize = EXRDecoder.lines;
|
|
|
-
|
|
|
const channels = {};
|
|
|
for ( const channel of EXRHeader.channels ) {
|
|
|
|
|
@@ -2172,12 +2377,10 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
case FloatType:
|
|
|
EXRDecoder.getter = parseFloat16;
|
|
|
- EXRDecoder.inputSize = INT16_SIZE;
|
|
|
break;
|
|
|
|
|
|
case HalfFloatType:
|
|
|
EXRDecoder.getter = parseUint16;
|
|
|
- EXRDecoder.inputSize = INT16_SIZE;
|
|
|
break;
|
|
|
|
|
|
}
|
|
@@ -2189,12 +2392,10 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
case FloatType:
|
|
|
EXRDecoder.getter = parseFloat32;
|
|
|
- EXRDecoder.inputSize = FLOAT32_SIZE;
|
|
|
break;
|
|
|
|
|
|
case HalfFloatType:
|
|
|
EXRDecoder.getter = decodeFloat32;
|
|
|
- EXRDecoder.inputSize = FLOAT32_SIZE;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -2204,13 +2405,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
}
|
|
|
|
|
|
- EXRDecoder.blockCount = EXRDecoder.height / EXRDecoder.scanlineBlockSize;
|
|
|
-
|
|
|
- for ( let i = 0; i < EXRDecoder.blockCount; i ++ )
|
|
|
- parseInt64( dataView, offset ); // scanlineOffset
|
|
|
-
|
|
|
- // we should be passed the scanline offset table, ready to start reading pixel data.
|
|
|
-
|
|
|
+ EXRDecoder.columns = EXRDecoder.width;
|
|
|
const size = EXRDecoder.width * EXRDecoder.height * EXRDecoder.outputChannels;
|
|
|
|
|
|
switch ( outputType ) {
|
|
@@ -2243,7 +2438,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
if ( EXRDecoder.decodeChannels[ channel.name ] !== undefined ) {
|
|
|
|
|
|
- EXRDecoder.channelLineOffsets[ channel.name ] = byteOffset * EXRDecoder.width;
|
|
|
+ EXRDecoder.channelByteOffsets[ channel.name ] = byteOffset;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -2251,7 +2446,7 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
}
|
|
|
|
|
|
- EXRDecoder.bytesPerLine = EXRDecoder.width * byteOffset;
|
|
|
+ EXRDecoder.totalBytes = byteOffset;
|
|
|
EXRDecoder.outLineWidth = EXRDecoder.width * EXRDecoder.outputChannels;
|
|
|
|
|
|
if ( EXRHeader.lineOrder === 'INCREASING_Y' ) {
|
|
@@ -2276,66 +2471,55 @@ class EXRLoader extends DataTextureLoader {
|
|
|
|
|
|
}
|
|
|
|
|
|
- return EXRDecoder;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- // start parsing file [START]
|
|
|
-
|
|
|
- const bufferDataView = new DataView( buffer );
|
|
|
- const uInt8Array = new Uint8Array( buffer );
|
|
|
- const offset = { value: 0 };
|
|
|
-
|
|
|
- // get header information and validate format.
|
|
|
- const EXRHeader = parseHeader( bufferDataView, buffer, offset );
|
|
|
-
|
|
|
- // get input compression information and prepare decoding.
|
|
|
- const EXRDecoder = setupDecoder( EXRHeader, bufferDataView, uInt8Array, offset, this.type );
|
|
|
-
|
|
|
- const tmpOffset = { value: 0 };
|
|
|
+ if ( EXRHeader.spec.singleTile ) {
|
|
|
|
|
|
- for ( let scanlineBlockIdx = 0; scanlineBlockIdx < EXRDecoder.height / EXRDecoder.scanlineBlockSize; scanlineBlockIdx ++ ) {
|
|
|
+ EXRDecoder.blockHeight = EXRHeader.tiles.ySize;
|
|
|
+ EXRDecoder.blockWidth = EXRHeader.tiles.xSize;
|
|
|
|
|
|
- const line = parseInt32( bufferDataView, offset ) - EXRHeader.dataWindow.yMin; // line_no
|
|
|
- EXRDecoder.size = parseUint32( bufferDataView, offset ); // data_len
|
|
|
- EXRDecoder.lines = ( ( line + EXRDecoder.scanlineBlockSize > EXRDecoder.height ) ? ( EXRDecoder.height - line ) : EXRDecoder.scanlineBlockSize );
|
|
|
+ const numXLevels = calculateTileLevels( EXRHeader.tiles, EXRDecoder.width, EXRDecoder.height );
|
|
|
+ // const numYLevels = calculateTileLevels( EXRHeader.tiles, EXRDecoder.width, EXRDecoder.height );
|
|
|
|
|
|
- const isCompressed = EXRDecoder.size < EXRDecoder.lines * EXRDecoder.bytesPerLine;
|
|
|
- const viewer = isCompressed ? EXRDecoder.uncompress( EXRDecoder ) : uncompressRAW( EXRDecoder );
|
|
|
+ const numXTiles = calculateTiles( numXLevels, EXRDecoder.width, EXRHeader.tiles.xSize, EXRHeader.tiles.roundingMode );
|
|
|
+ const numYTiles = calculateTiles( numXLevels, EXRDecoder.height, EXRHeader.tiles.ySize, EXRHeader.tiles.roundingMode );
|
|
|
|
|
|
- offset.value += EXRDecoder.size;
|
|
|
+ EXRDecoder.tileCount = numXTiles[ 0 ] * numYTiles[ 0 ];
|
|
|
|
|
|
- for ( let line_y = 0; line_y < EXRDecoder.scanlineBlockSize; line_y ++ ) {
|
|
|
+ for ( let l = 0; l < numXLevels; l ++ )
|
|
|
+ for ( let y = 0; y < numYTiles[ l ]; y ++ )
|
|
|
+ for ( let x = 0; x < numXTiles[ l ]; x ++ )
|
|
|
+ parseInt64( dataView, offset ); // tileOffset
|
|
|
|
|
|
- const scan_y = scanlineBlockIdx * EXRDecoder.scanlineBlockSize;
|
|
|
- const true_y = line_y + EXRDecoder.scanOrder( scan_y );
|
|
|
- if ( true_y >= EXRDecoder.height ) continue;
|
|
|
+ EXRDecoder.decode = parseTiles.bind( EXRDecoder );
|
|
|
|
|
|
- const lineOffset = line_y * EXRDecoder.bytesPerLine;
|
|
|
- const outLineOffset = ( EXRDecoder.height - 1 - true_y ) * EXRDecoder.outLineWidth;
|
|
|
+ } else {
|
|
|
|
|
|
- for ( let channelID = 0; channelID < EXRDecoder.channels; channelID ++ ) {
|
|
|
+ EXRDecoder.blockWidth = EXRDecoder.width;
|
|
|
+ const blockCount = Math.ceil( EXRDecoder.height / EXRDecoder.blockHeight );
|
|
|
|
|
|
- const name = EXRHeader.channels[ channelID ].name;
|
|
|
- const lOff = EXRDecoder.channelLineOffsets[ name ];
|
|
|
- const cOff = EXRDecoder.decodeChannels[ name ];
|
|
|
+ for ( let i = 0; i < blockCount; i ++ )
|
|
|
+ parseInt64( dataView, offset ); // scanlineOffset
|
|
|
|
|
|
- if ( cOff === undefined ) continue;
|
|
|
+ EXRDecoder.decode = parseScanline.bind( EXRDecoder );
|
|
|
|
|
|
- tmpOffset.value = lineOffset + lOff;
|
|
|
+ }
|
|
|
|
|
|
- for ( let x = 0; x < EXRDecoder.width; x ++ ) {
|
|
|
+ return EXRDecoder;
|
|
|
|
|
|
- const outIndex = outLineOffset + x * EXRDecoder.outputChannels + cOff;
|
|
|
- EXRDecoder.byteArray[ outIndex ] = EXRDecoder.getter( viewer, tmpOffset );
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ // start parsing file [START]
|
|
|
+ const offset = { value: 0 };
|
|
|
+ const bufferDataView = new DataView( buffer );
|
|
|
+ const uInt8Array = new Uint8Array( buffer );
|
|
|
|
|
|
- }
|
|
|
+ // get header information and validate format.
|
|
|
+ const EXRHeader = parseHeader( bufferDataView, buffer, offset );
|
|
|
|
|
|
- }
|
|
|
+ // get input compression information and prepare decoding.
|
|
|
+ const EXRDecoder = setupDecoder( EXRHeader, bufferDataView, uInt8Array, offset, this.type );
|
|
|
|
|
|
- }
|
|
|
+ // parse input data
|
|
|
+ EXRDecoder.decode();
|
|
|
|
|
|
return {
|
|
|
header: EXRHeader,
|