@babylonjs/viewer
Version:
The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.
1,250 lines (1,242 loc) • 66 kB
JavaScript
import { aS as FromHalfFloat, aT as ToHalfFloat, j as Clamp, cc as MaxHalfFloat, y as Logger, aY as Tools, C as Constants } from './index-MZPybX0H.esm.js';
const INT32_SIZE = 4;
const FLOAT32_SIZE = 4;
const INT8_SIZE = 1;
const INT16_SIZE = 2;
const ULONG_SIZE = 8;
const USHORT_RANGE = 1 << 16;
const BITMAP_SIZE = USHORT_RANGE >> 3;
const HUF_ENCBITS = 16;
const HUF_DECBITS = 14;
const HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1;
const HUF_DECSIZE = 1 << HUF_DECBITS;
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;
/**
* Inspired by https://github.com/sciecode/three.js/blob/dev/examples/jsm/loaders/EXRLoader.js
* Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
* implementation.
*/
// /*
// 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 -------------------------------------------------
var CompressionCodes;
(function (CompressionCodes) {
CompressionCodes[CompressionCodes["NO_COMPRESSION"] = 0] = "NO_COMPRESSION";
CompressionCodes[CompressionCodes["RLE_COMPRESSION"] = 1] = "RLE_COMPRESSION";
CompressionCodes[CompressionCodes["ZIPS_COMPRESSION"] = 2] = "ZIPS_COMPRESSION";
CompressionCodes[CompressionCodes["ZIP_COMPRESSION"] = 3] = "ZIP_COMPRESSION";
CompressionCodes[CompressionCodes["PIZ_COMPRESSION"] = 4] = "PIZ_COMPRESSION";
CompressionCodes[CompressionCodes["PXR24_COMPRESSION"] = 5] = "PXR24_COMPRESSION";
})(CompressionCodes || (CompressionCodes = {}));
var LineOrders;
(function (LineOrders) {
LineOrders[LineOrders["INCREASING_Y"] = 0] = "INCREASING_Y";
LineOrders[LineOrders["DECREASING_Y"] = 1] = "DECREASING_Y";
})(LineOrders || (LineOrders = {}));
/**
* Parse a null terminated string from the buffer
* @param buffer buffer to read from
* @param offset current offset in the buffer
* @returns a string
*/
function ParseNullTerminatedString(buffer, offset) {
const uintBuffer = new Uint8Array(buffer);
let endOffset = 0;
while (uintBuffer[offset.value + endOffset] != 0) {
endOffset += 1;
}
const stringValue = new TextDecoder().decode(uintBuffer.slice(offset.value, offset.value + endOffset));
offset.value = offset.value + endOffset + 1;
return stringValue;
}
/**
* Parse an int32 from the buffer
* @param dataView dataview on the data
* @param offset current offset in the data view
* @returns an int32
*/
function ParseInt32(dataView, offset) {
const value = dataView.getInt32(offset.value, true);
offset.value += INT32_SIZE;
return value;
}
/**
* Parse an uint32 from the buffer
* @param dataView data view to read from
* @param offset offset in the data view
* @returns an uint32
*/
function ParseUint32(dataView, offset) {
const value = dataView.getUint32(offset.value, true);
offset.value += INT32_SIZE;
return value;
}
/**
* Parse an uint8 from the buffer
* @param dataView dataview on the data
* @param offset current offset in the data view
* @returns an uint8
*/
function ParseUint8(dataView, offset) {
const value = dataView.getUint8(offset.value);
offset.value += INT8_SIZE;
return value;
}
/**
* Parse an uint16 from the buffer
* @param dataView dataview on the data
* @param offset current offset in the data view
* @returns an uint16
*/
function ParseUint16(dataView, offset) {
const value = dataView.getUint16(offset.value, true);
offset.value += INT16_SIZE;
return value;
}
/**
* Parse an uint8 from an array buffer
* @param array array buffer
* @param offset current offset in the data view
* @returns an uint16
*/
function ParseUint8Array(array, offset) {
const value = array[offset.value];
offset.value += INT8_SIZE;
return value;
}
/**
* Parse an int64 from the buffer
* @param dataView dataview on the data
* @param offset current offset in the data view
* @returns an int64
*/
function ParseInt64(dataView, offset) {
let int;
if ("getBigInt64" in DataView.prototype) {
int = Number(dataView.getBigInt64(offset.value, true));
}
else {
int = dataView.getUint32(offset.value + 4, true) + Number(dataView.getUint32(offset.value, true) << 32);
}
offset.value += ULONG_SIZE;
return int;
}
/**
* Parse a float32 from the buffer
* @param dataView dataview on the data
* @param offset current offset in the data view
* @returns a float32
*/
function ParseFloat32(dataView, offset) {
const value = dataView.getFloat32(offset.value, true);
offset.value += FLOAT32_SIZE;
return value;
}
/**
* Parse a float16 from the buffer
* @param dataView dataview on the data
* @param offset current offset in the data view
* @returns a float16
*/
function ParseFloat16(dataView, offset) {
return FromHalfFloat(ParseUint16(dataView, offset));
}
/**
* Decode a float32 from the buffer
* @param dataView dataview on the data
* @param offset current offset in the data view
* @returns a float16
*/
function DecodeFloat32(dataView, offset) {
// EXR FLOAT channels are HDR and can exceed the half-float range. Clamp to the largest finite half
return ToHalfFloat(Clamp(ParseFloat32(dataView, offset), -MaxHalfFloat, MaxHalfFloat));
}
function ParseFixedLengthString(buffer, offset, size) {
const stringValue = new TextDecoder().decode(new Uint8Array(buffer).slice(offset.value, offset.value + size));
offset.value = offset.value + size;
return stringValue;
}
function ParseRational(dataView, offset) {
const x = ParseInt32(dataView, offset);
const y = ParseUint32(dataView, offset);
return [x, y];
}
function ParseTimecode(dataView, offset) {
const x = ParseUint32(dataView, offset);
const y = ParseUint32(dataView, offset);
return [x, y];
}
function ParseV2f(dataView, offset) {
const x = ParseFloat32(dataView, offset);
const y = ParseFloat32(dataView, offset);
return [x, y];
}
function ParseV3f(dataView, offset) {
const x = ParseFloat32(dataView, offset);
const y = ParseFloat32(dataView, offset);
const z = ParseFloat32(dataView, offset);
return [x, y, z];
}
function ParseChlist(dataView, offset, size) {
const startOffset = offset.value;
const channels = [];
while (offset.value < startOffset + size - 1) {
const name = ParseNullTerminatedString(dataView.buffer, offset);
const pixelType = ParseInt32(dataView, offset);
const pLinear = ParseUint8(dataView, offset);
offset.value += 3; // reserved, three chars
const xSampling = ParseInt32(dataView, offset);
const ySampling = ParseInt32(dataView, offset);
channels.push({
name: name,
pixelType: pixelType,
pLinear: pLinear,
xSampling: xSampling,
ySampling: ySampling,
});
}
offset.value += 1;
return channels;
}
function ParseChromaticities(dataView, offset) {
const redX = ParseFloat32(dataView, offset);
const redY = ParseFloat32(dataView, offset);
const greenX = ParseFloat32(dataView, offset);
const greenY = ParseFloat32(dataView, offset);
const blueX = ParseFloat32(dataView, offset);
const blueY = ParseFloat32(dataView, offset);
const whiteX = ParseFloat32(dataView, offset);
const whiteY = ParseFloat32(dataView, offset);
return { redX: redX, redY: redY, greenX: greenX, greenY: greenY, blueX: blueX, blueY: blueY, whiteX: whiteX, whiteY: whiteY };
}
function ParseCompression(dataView, offset) {
return ParseUint8(dataView, offset);
}
function ParseBox2i(dataView, offset) {
const xMin = ParseInt32(dataView, offset);
const yMin = ParseInt32(dataView, offset);
const xMax = ParseInt32(dataView, offset);
const yMax = ParseInt32(dataView, offset);
return { xMin: xMin, yMin: yMin, xMax: xMax, yMax: yMax };
}
function ParseLineOrder(dataView, offset) {
const lineOrder = ParseUint8(dataView, offset);
return LineOrders[lineOrder];
}
/**
* Parse a value from the data view
* @param dataView defines the data view to read from
* @param offset defines the current offset in the data view
* @param type defines the type of the value to read
* @param size defines the size of the value to read
* @returns the parsed value
*/
function ParseValue(dataView, offset, type, size) {
switch (type) {
case "string":
case "stringvector":
case "iccProfile":
return ParseFixedLengthString(dataView.buffer, offset, size);
case "chlist":
return ParseChlist(dataView, offset, size);
case "chromaticities":
return ParseChromaticities(dataView, offset);
case "compression":
return ParseCompression(dataView, offset);
case "box2i":
return ParseBox2i(dataView, offset);
case "lineOrder":
return ParseLineOrder(dataView, offset);
case "float":
return ParseFloat32(dataView, offset);
case "v2f":
return ParseV2f(dataView, offset);
case "v3f":
return ParseV3f(dataView, offset);
case "int":
return ParseInt32(dataView, offset);
case "rational":
return ParseRational(dataView, offset);
case "timecode":
return ParseTimecode(dataView, offset);
case "preview":
offset.value += size;
return "skipped";
default:
offset.value += size;
return undefined;
}
}
/**
* Revert the endianness of the data
* @param source defines the source
*/
function Predictor(source) {
for (let t = 1; t < source.length; t++) {
const d = source[t - 1] + source[t] - 128;
source[t] = d;
}
}
/**
* Interleave pixels
* @param source defines the data source
* @param out defines the output
*/
function InterleaveScalar(source, out) {
let t1 = 0;
let t2 = Math.floor((source.length + 1) / 2);
let s = 0;
const stop = source.length - 1;
// eslint-disable-next-line no-constant-condition
while (true) {
if (s > stop) {
break;
}
out[s++] = source[t1++];
if (s > stop) {
break;
}
out[s++] = source[t2++];
}
}
/* eslint-disable @typescript-eslint/naming-convention */
/**
* Inspired by https://github.com/sciecode/three.js/blob/dev/examples/jsm/loaders/EXRLoader.js
* Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
* implementation.
*/
// /*
// 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 -------------------------------------------------
const EXR_MAGIC = 20000630;
/**
* Gets the EXR header
* @param dataView defines the data view to read from
* @param offset defines the offset to start reading from
* @returns the header
*/
function GetExrHeader(dataView, offset) {
if (dataView.getUint32(0, true) != EXR_MAGIC) {
throw new Error("Incorrect OpenEXR format");
}
const version = dataView.getUint8(4);
const specData = dataView.getUint8(5); // fullMask
const spec = {
singleTile: !!(specData & 2),
longName: !!(specData & 4),
deepFormat: !!(specData & 8),
multiPart: !!(specData & 16),
};
offset.value = 8;
const headerData = {};
let keepReading = true;
while (keepReading) {
const attributeName = ParseNullTerminatedString(dataView.buffer, offset);
if (!attributeName) {
keepReading = false;
}
else {
const attributeType = ParseNullTerminatedString(dataView.buffer, offset);
const attributeSize = ParseUint32(dataView, offset);
const attributeValue = ParseValue(dataView, offset, attributeType, attributeSize);
if (attributeValue === undefined) {
Logger.Warn(`Unknown header attribute type ${attributeType}'.`);
}
else {
headerData[attributeName] = attributeValue;
}
}
}
if ((specData & -5) != 0) {
throw new Error("Unsupported file format");
}
return { version: version, spec: spec, ...headerData };
}
/**
* Inspired by https://github.com/sciecode/three.js/blob/dev/examples/jsm/loaders/EXRLoader.js
* Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
* implementation.
*/
// /*
// 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 -------------------------------------------------
const NBITS = 16;
const A_OFFSET = 1 << (NBITS - 1);
const MOD_MASK = (1 << NBITS) - 1;
/** @internal */
function ReverseLutFromBitmap(bitmap, lut) {
let k = 0;
for (let i = 0; i < USHORT_RANGE; ++i) {
if (i == 0 || bitmap[i >> 3] & (1 << (i & 7))) {
lut[k++] = i;
}
}
const n = k - 1;
while (k < USHORT_RANGE) {
lut[k++] = 0;
}
return n;
}
function HufClearDecTable(hdec) {
for (let 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, array, offset) {
while (lc < nBits) {
c = (c << 8) | ParseUint8Array(array, offset);
lc += 8;
}
lc -= nBits;
return {
l: (c >> lc) & ((1 << nBits) - 1),
c,
lc,
};
}
function GetChar(c, lc, array, offset) {
c = (c << 8) | ParseUint8Array(array, offset);
lc += 8;
return {
c,
lc,
};
}
function GetCode(po, rlc, c, lc, array, offset, outBuffer, outBufferOffset, outBufferEndOffset) {
if (po == rlc) {
if (lc < 8) {
const gc = GetChar(c, lc, array, offset);
c = gc.c;
lc = gc.lc;
}
lc -= 8;
let cs = c >> lc;
cs = new Uint8Array([cs])[0];
if (outBufferOffset.value + cs > outBufferEndOffset) {
return null;
}
const s = outBuffer[outBufferOffset.value - 1];
while (cs-- > 0) {
outBuffer[outBufferOffset.value++] = s;
}
}
else if (outBufferOffset.value < outBufferEndOffset) {
outBuffer[outBufferOffset.value++] = po;
}
else {
return null;
}
return { c, lc };
}
const HufTableBuffer = new Array(59);
function HufCanonicalCodeTable(hcode) {
for (let i = 0; i <= 58; ++i) {
HufTableBuffer[i] = 0;
}
for (let i = 0; i < HUF_ENCSIZE; ++i) {
HufTableBuffer[hcode[i]] += 1;
}
let c = 0;
for (let i = 58; i > 0; --i) {
const nc = (c + HufTableBuffer[i]) >> 1;
HufTableBuffer[i] = c;
c = nc;
}
for (let i = 0; i < HUF_ENCSIZE; ++i) {
const l = hcode[i];
if (l > 0) {
hcode[i] = l | (HufTableBuffer[l]++ << 6);
}
}
}
function HufUnpackEncTable(array, offset, ni, im, iM, hcode) {
const p = offset;
let c = 0;
let lc = 0;
for (; im <= iM; im++) {
if (p.value - offset.value > ni) {
return;
}
let gb = GetBits(6, c, lc, array, p);
const l = gb.l;
c = gb.c;
lc = gb.lc;
hcode[im] = l;
if (l == LONG_ZEROCODE_RUN) {
if (p.value - offset.value > ni) {
throw new Error("Error in HufUnpackEncTable");
}
gb = GetBits(8, c, lc, array, p);
let zerun = gb.l + SHORTEST_LONG_RUN;
c = gb.c;
lc = gb.lc;
if (im + zerun > iM + 1) {
throw new Error("Error in HufUnpackEncTable");
}
while (zerun--) {
hcode[im++] = 0;
}
im--;
}
else if (l >= SHORT_ZEROCODE_RUN) {
let zerun = l - SHORT_ZEROCODE_RUN + 2;
if (im + zerun > iM + 1) {
throw new Error("Error in 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++) {
const c = HufCode(hcode[im]);
const l = HufLength(hcode[im]);
if (c >> l) {
throw new Error("Invalid table entry");
}
if (l > HUF_DECBITS) {
const pl = hdecod[c >> (l - HUF_DECBITS)];
if (pl.len) {
throw new Error("Invalid table entry");
}
pl.lit++;
if (pl.p) {
const p = pl.p;
pl.p = new Array(pl.lit);
for (let 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) {
let plOffset = 0;
for (let i = 1 << (HUF_DECBITS - l); i > 0; i--) {
const pl = hdecod[(c << (HUF_DECBITS - l)) + plOffset];
if (pl.len || pl.p) {
throw new Error("Invalid table entry");
}
pl.len = l;
pl.lit = im;
plOffset++;
}
}
}
return true;
}
function HufDecode(encodingTable, decodingTable, array, offset, ni, rlc, no, outBuffer, outOffset) {
let c = 0;
let lc = 0;
const outBufferEndOffset = no;
const inOffsetEnd = Math.trunc(offset.value + (ni + 7) / 8);
while (offset.value < inOffsetEnd) {
let gc = GetChar(c, lc, array, offset);
c = gc.c;
lc = gc.lc;
while (lc >= HUF_DECBITS) {
const index = (c >> (lc - HUF_DECBITS)) & HUF_DECMASK;
const pl = decodingTable[index];
if (pl.len) {
lc -= pl.len;
const gCode = GetCode(pl.lit, rlc, c, lc, array, offset, outBuffer, outOffset, outBufferEndOffset);
if (gCode) {
c = gCode.c;
lc = gCode.lc;
}
}
else {
if (!pl.p) {
throw new Error("hufDecode issues");
}
let j;
for (j = 0; j < pl.lit; j++) {
const l = HufLength(encodingTable[pl.p[j]]);
while (lc < l && offset.value < inOffsetEnd) {
gc = GetChar(c, lc, array, offset);
c = gc.c;
lc = gc.lc;
}
if (lc >= l) {
if (HufCode(encodingTable[pl.p[j]]) == ((c >> (lc - l)) & ((1 << l) - 1))) {
lc -= l;
const gCode = GetCode(pl.p[j], rlc, c, lc, array, offset, outBuffer, outOffset, outBufferEndOffset);
if (gCode) {
c = gCode.c;
lc = gCode.lc;
}
break;
}
}
}
if (j == pl.lit) {
throw new Error("HufDecode issues");
}
}
}
}
const i = (8 - ni) & 7;
c >>= i;
lc -= i;
while (lc > 0) {
const pl = decodingTable[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
if (pl.len) {
lc -= pl.len;
const gCode = GetCode(pl.lit, rlc, c, lc, array, offset, outBuffer, outOffset, outBufferEndOffset);
if (gCode) {
c = gCode.c;
lc = gCode.lc;
}
}
else {
throw new Error("HufDecode issues");
}
}
return true;
}
/** @internal */
function HufUncompress(array, dataView, offset, nCompressed, outBuffer, nRaw) {
const outOffset = { value: 0 };
const initialInOffset = offset.value;
const im = ParseUint32(dataView, offset);
const iM = ParseUint32(dataView, offset);
offset.value += 4;
const nBits = ParseUint32(dataView, offset);
offset.value += 4;
if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) {
throw new Error("Wrong HUF_ENCSIZE");
}
const freq = new Array(HUF_ENCSIZE);
const hdec = new Array(HUF_DECSIZE);
HufClearDecTable(hdec);
const ni = nCompressed - (offset.value - initialInOffset);
HufUnpackEncTable(array, offset, ni, im, iM, freq);
if (nBits > 8 * (nCompressed - (offset.value - initialInOffset))) {
throw new Error("Wrong hufUncompress");
}
HufBuildDecTable(freq, im, iM, hdec);
HufDecode(freq, hdec, array, offset, nBits, iM, nRaw, outBuffer, outOffset);
}
function UInt16(value) {
return value & 0xffff;
}
function Int16(value) {
const ref = UInt16(value);
return ref > 0x7fff ? ref - 0x10000 : ref;
}
function Wdec14(l, h) {
const ls = Int16(l);
const hs = Int16(h);
const hi = hs;
const ai = ls + (hi & 1) + (hi >> 1);
const as = ai;
const bs = ai - hi;
return { a: as, b: bs };
}
function Wdec16(l, h) {
const m = UInt16(l);
const d = UInt16(h);
const bb = (m - (d >> 1)) & MOD_MASK;
const aa = (d + bb - A_OFFSET) & MOD_MASK;
return { a: aa, b: bb };
}
/** @internal */
function Wav2Decode(buffer, j, nx, ox, ny, oy, mx) {
const w14 = mx < 1 << 14;
const n = nx > ny ? ny : nx;
let p = 1;
let p2;
let py;
while (p <= n) {
p <<= 1;
}
p >>= 1;
p2 = p;
p >>= 1;
while (p >= 1) {
py = 0;
const ey = py + oy * (ny - p2);
const oy1 = oy * p;
const oy2 = oy * p2;
const ox1 = ox * p;
const ox2 = ox * p2;
let i00, i01, i10, i11;
for (; py <= ey; py += oy2) {
let px = py;
const ex = py + ox * (nx - p2);
for (; px <= ex; px += ox2) {
const p01 = px + ox1;
const p10 = px + oy1;
const p11 = p10 + ox1;
if (w14) {
let result = Wdec14(buffer[px + j], buffer[p10 + j]);
i00 = result.a;
i10 = result.b;
result = Wdec14(buffer[p01 + j], buffer[p11 + j]);
i01 = result.a;
i11 = result.b;
result = Wdec14(i00, i01);
buffer[px + j] = result.a;
buffer[p01 + j] = result.b;
result = Wdec14(i10, i11);
buffer[p10 + j] = result.a;
buffer[p11 + j] = result.b;
}
else {
let result = Wdec16(buffer[px + j], buffer[p10 + j]);
i00 = result.a;
i10 = result.b;
result = Wdec16(buffer[p01 + j], buffer[p11 + j]);
i01 = result.a;
i11 = result.b;
result = Wdec16(i00, i01);
buffer[px + j] = result.a;
buffer[p01 + j] = result.b;
result = Wdec16(i10, i11);
buffer[p10 + j] = result.a;
buffer[p11 + j] = result.b;
}
}
if (nx & p) {
const p10 = px + oy1;
let result;
if (w14) {
result = Wdec14(buffer[px + j], buffer[p10 + j]);
}
else {
result = Wdec16(buffer[px + j], buffer[p10 + j]);
}
i00 = result.a;
buffer[p10 + j] = result.b;
buffer[px + j] = i00;
}
}
if (ny & p) {
let px = py;
const ex = py + ox * (nx - p2);
for (; px <= ex; px += ox2) {
const p01 = px + ox1;
let result;
if (w14) {
result = Wdec14(buffer[px + j], buffer[p01 + j]);
}
else {
result = Wdec16(buffer[px + j], buffer[p01 + j]);
}
i00 = result.a;
buffer[p01 + j] = result.b;
buffer[px + j] = i00;
}
}
p2 = p;
p >>= 1;
}
return py;
}
/** @internal */
function ApplyLut(lut, data, nData) {
for (let i = 0; i < nData; ++i) {
data[i] = lut[data[i]];
}
}
/**
* Inspired by https://github.com/sciecode/three.js/blob/dev/examples/jsm/loaders/EXRLoader.js
* Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
* implementation.
*/
// /*
// 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 -------------------------------------------------
/** @internal */
function DecodeRunLength(source) {
let size = source.byteLength;
const out = [];
let p = 0;
const reader = new DataView(source);
while (size > 0) {
const l = reader.getInt8(p++);
if (l < 0) {
const count = -l;
size -= count + 1;
for (let i = 0; i < count; i++) {
out.push(reader.getUint8(p++));
}
}
else {
const count = l;
size -= 2;
const value = reader.getUint8(p++);
for (let i = 0; i < count + 1; i++) {
out.push(value);
}
}
}
return out;
}
/**
* No compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
function UncompressRAW(decoder) {
return new DataView(decoder.array.buffer, decoder.offset.value, decoder.size);
}
/**
* RLE compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
function UncompressRLE(decoder) {
const compressed = decoder.viewer.buffer.slice(decoder.offset.value, decoder.offset.value + decoder.size);
const rawBuffer = new Uint8Array(DecodeRunLength(compressed));
const tmpBuffer = new Uint8Array(rawBuffer.length);
Predictor(rawBuffer);
InterleaveScalar(rawBuffer, tmpBuffer);
return new DataView(tmpBuffer.buffer);
}
/**
* Zip compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
function UncompressZIP(decoder) {
const compressed = decoder.array.slice(decoder.offset.value, decoder.offset.value + decoder.size);
const rawBuffer = fflate.unzlibSync(compressed);
const tmpBuffer = new Uint8Array(rawBuffer.length);
Predictor(rawBuffer);
InterleaveScalar(rawBuffer, tmpBuffer);
return new DataView(tmpBuffer.buffer);
}
/**
* PXR compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
function UncompressPXR(decoder) {
const compressed = decoder.array.slice(decoder.offset.value, decoder.offset.value + decoder.size);
const rawBuffer = fflate.unzlibSync(compressed);
const sz = decoder.lines * decoder.channels * decoder.width;
const tmpBuffer = decoder.type == 1 ? new Uint16Array(sz) : new Uint32Array(sz);
let tmpBufferEnd = 0;
let writePtr = 0;
const ptr = new Array(4);
for (let y = 0; y < decoder.lines; y++) {
for (let c = 0; c < decoder.channels; c++) {
let pixel = 0;
switch (decoder.type) {
case 1:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + decoder.width;
tmpBufferEnd = ptr[1] + decoder.width;
for (let j = 0; j < decoder.width; ++j) {
const diff = (rawBuffer[ptr[0]++] << 8) | rawBuffer[ptr[1]++];
pixel += diff;
tmpBuffer[writePtr] = pixel;
writePtr++;
}
break;
case 2:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + decoder.width;
ptr[2] = ptr[1] + decoder.width;
tmpBufferEnd = ptr[2] + decoder.width;
for (let j = 0; j < decoder.width; ++j) {
const diff = (rawBuffer[ptr[0]++] << 24) | (rawBuffer[ptr[1]++] << 16) | (rawBuffer[ptr[2]++] << 8);
pixel += diff;
tmpBuffer[writePtr] = pixel;
writePtr++;
}
break;
}
}
}
return new DataView(tmpBuffer.buffer);
}
/**
* PIZ compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
function UncompressPIZ(decoder) {
const inDataView = decoder.viewer;
const inOffset = { value: decoder.offset.value };
const outBuffer = new Uint16Array(decoder.width * decoder.scanlineBlockSize * (decoder.channels * decoder.type));
const bitmap = new Uint8Array(BITMAP_SIZE);
// Setup channel info
let outBufferEnd = 0;
const pizChannelData = new Array(decoder.channels);
for (let i = 0; i < decoder.channels; i++) {
pizChannelData[i] = {};
pizChannelData[i]["start"] = outBufferEnd;
pizChannelData[i]["end"] = pizChannelData[i]["start"];
pizChannelData[i]["nx"] = decoder.width;
pizChannelData[i]["ny"] = decoder.lines;
pizChannelData[i]["size"] = decoder.type;
outBufferEnd += pizChannelData[i].nx * pizChannelData[i].ny * pizChannelData[i].size;
}
// Read range compression data
const minNonZero = ParseUint16(inDataView, inOffset);
const maxNonZero = ParseUint16(inDataView, inOffset);
if (maxNonZero >= BITMAP_SIZE) {
throw new Error("Wrong PIZ_COMPRESSION BITMAP_SIZE");
}
if (minNonZero <= maxNonZero) {
for (let i = 0; i < maxNonZero - minNonZero + 1; i++) {
bitmap[i + minNonZero] = ParseUint8(inDataView, inOffset);
}
}
// Reverse LUT
const lut = new Uint16Array(USHORT_RANGE);
const maxValue = ReverseLutFromBitmap(bitmap, lut);
const length = ParseUint32(inDataView, inOffset);
// Huffman decoding
HufUncompress(decoder.array, inDataView, inOffset, length, outBuffer, outBufferEnd);
// Wavelet decoding
for (let i = 0; i < decoder.channels; ++i) {
const cd = pizChannelData[i];
for (let j = 0; j < pizChannelData[i].size; ++j) {
Wav2Decode(outBuffer, cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, maxValue);
}
}
// Expand the pixel data to their original range
ApplyLut(lut, outBuffer, outBufferEnd);
// Rearrange the pixel data into the format expected by the caller.
let tmpOffset = 0;
const tmpBuffer = new Uint8Array(outBuffer.buffer.byteLength);
for (let y = 0; y < decoder.lines; y++) {
for (let c = 0; c < decoder.channels; c++) {
const cd = pizChannelData[c];
const n = cd.nx * cd.size;
const cp = new Uint8Array(outBuffer.buffer, cd.end * INT16_SIZE, n * INT16_SIZE);
tmpBuffer.set(cp, tmpOffset);
tmpOffset += n * INT16_SIZE;
cd.end += n;
}
}
return new DataView(tmpBuffer.buffer);
}
var EXROutputType;
(function (EXROutputType) {
EXROutputType[EXROutputType["Float"] = 0] = "Float";
EXROutputType[EXROutputType["HalfFloat"] = 1] = "HalfFloat";
})(EXROutputType || (EXROutputType = {}));
/**
* Class used to store configuration of the exr loader
*/
class ExrLoaderGlobalConfiguration {
}
/**
* Defines the default output type to use (Half float by default)
*/
ExrLoaderGlobalConfiguration.DefaultOutputType = EXROutputType.HalfFloat;
/**
* Url to use to load the fflate library (for zip decompression)
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
ExrLoaderGlobalConfiguration.FFLATEUrl = "https://unpkg.com/fflate@0.8.2";
/**
* Inspired by https://github.com/sciecode/three.js/blob/dev/examples/jsm/loaders/EXRLoader.js
* Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
* implementation.
*/
// /*
// 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 ---------------------------