UNPKG

@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,614 lines 66 kB
import { aS as FromHalfFloat, aT as ToHalfFloat, j as Clamp, cc as MaxHalfFloat, y as Logger, aY as Tools, C as Constants } from './index-HyNDfLMI.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 -------------------------------------------------
/**
 * Create a decoder for the exr file
 * @param header header of the exr file
 * @param dataView dataview of the exr file
 * @param offset current offset
 * @param outputType expected output type (float or half float)
 * @returns a promise that resolves with the decoder
 */
async function CreateDecoderAsync(header, dataView, offset, outputType) {
    const decoder = {
        size: 0,
        viewer: dataView,
        array: new Uint8Array(dataView.buffer),
        offset: offset,
        width: header.dataWindow.xMax - header.dataWindow.xMin + 1,
        height: header.dataWindow.yMax - header.dataWindow.yMin + 1,
        channels: header.channels.length,
        channelLineOffsets: {},
        scanOrder: () => 0,
        bytesPerLine: 0,
        outLineWidth: 0,
        lines: 0,
        scanlineBlockSize: 0,
        inputSize: null,
        type: 0,
        uncompress: null,
        getter: () => 0,
        format: Constants.TEXTUREFORMAT_RGBA,
        outputChannels: 0,
        decodeChannels: {},
        blockCount: null,
        byteArray: null,
        linearSpace: false,
        textureType: 0,
    };
    switch (header.compression) {
        case CompressionCodes.NO_COMPRESSION:
            decoder.lines = 1;
            decoder.uncompress = UncompressRAW;
            break;
        case CompressionCodes.RLE_COMPRESSION:
            decoder.lines = 1;
            decoder.uncompress = UncompressRLE;
            break;
        case CompressionCodes.ZIPS_COMPRESSION:
            decoder.lines = 1;
            decoder.uncompress = UncompressZIP;
            await Tools.LoadScriptAsync(ExrLoaderGlobalConfiguration.FFLATEUrl);
            break;
        case CompressionCodes.ZIP_COMPRESSION:
            decoder.lines = 16;
            decoder.uncompress = UncompressZIP;
            await Tools.LoadScriptAsync(ExrLoaderGlobalConfiguration.FFLATEUrl);
            break;
        case CompressionCodes.PIZ_COMPRESSION:
            decoder.lines = 32;
            decoder.uncompress = UncompressPIZ;
            break;
        case CompressionCodes.PXR24_COMPRESSION:
            decoder.lines = 16;
            decoder.uncompress = UncompressPXR;
            await Tools.LoadScriptAsync(ExrLoaderGlobalConfiguration.FFLATEUrl);
            break;
        default:
            throw new Error(CompressionCodes[header.compression] + " is unsupported");
    }
    decoder.scanlineBlockSize = decoder.lines;
    const channels = {};
    for (const channel of header.channels) {
        switch (channel.name) {
            case "R":
            case "G":
            case "B":
            case "A":
                channels[channel.name] = true;
                decoder.type = channel.pixelType;
                break;
            case "Y":
                channels[channel.name] = true;
                decoder.type = channel.pixelType;
                // Note: 'Y' is deprecated in OpenGL 3.0+; prefer 'R' for single-channel EXRs.
                break;
        }
    }
    // RGB images will be converted to RGBA format, preventing software emulation in select devices.
    let fillAlpha = false;
    if (channels.R && channels.G && channels.B && channels.A) {
        decoder.outputChannels = 4;
        decoder.decodeChannels = { R: 0, G: 1, B: 2, A: 3 };
    }
    else if (channels.R && channels.G && channels.B) {
        fillAlpha = true;
        decoder.outputChannels = 4;
        decoder.decodeChannels = { R: 0, G: 1, B: 2, A: 3 };
    }
    else if (channels.R && channels.G) {
        decoder.outputChannels = 2;
        decoder.decodeChannels = { R: 0, G: 1 };
    }
    else if (channels.R) {
        decoder.outputChannels = 1;
        decoder.decodeChannels = { R: 0 };
    }
    else if (channels.Y) {
        decoder.outputChannels = 1;
        decoder.decodeChannels = { Y: 0 };
        // Note: Supporting 'Y' channel for legacy compatibility; prefer 'R' in new EXRs.
    }
    else {
        throw new Error("EXRLoader.parse: file contains unsupported data channels.");
    }
    if (decoder.type === 1) {
        // half
        switch (outputType) {
            case EXROutputType.Float:
                decoder.getter = ParseFloat16;
                decoder.inputSize = INT16_SIZE;
                break;
            case EXROutputType.HalfFloat:
                decoder.getter = ParseUint16;
                decoder.inputSize = INT16_SIZE;
                break;
        }
    }
    else if (decoder.type === 2) {
        // float
        switch (outputType) {
            case EXROutputType.Float:
                decoder.getter = ParseFloat32;
                decoder.inputSize = FLOAT32_SIZE;
                break;
            case EXROutputType.HalfFloat:
                decoder.getter = DecodeFloat32;
                decoder.inputSize = FLOAT32_SIZE;
        }
    }
    else {
        throw new Error("Unsupported pixelType " + decoder.type + " for " + header.compression);
    }
    decoder.blockCount = decoder.height / decoder.scanlineBlockSize;
    for (let i = 0; i < decoder.blockCount; i++) {
        ParseInt64(dataView, offset); // scanlineOffset
    }
    // we should be passed the scanline offset table, ready to start reading pixel data.
    const size = decoder.width * decoder.height * decoder.outputChannels;
    switch (outputType) {
        case EXROutputType.Float:
            decoder.byteArray = new Float32Array(size);
            decoder.textureType = Constants.TEXTURETYPE_FLOAT;
            // Fill initially with 1s for the alpha value if the texture is not RGBA, RGB values will be overwritten
            if (fillAlpha) {
                decoder.byteArray.fill(1, 0, size);
            }
            break;
        case EXROutputType.HalfFloat:
            decoder.byteArray = new Uint16Array(size);
            decoder.textureType = Constants.TEXTURETYPE_HALF_FLOAT;
            if (fillAlpha) {
                decoder.byteArray.fill(0x3c00, 0, size); // Uint16Array holds half float data, 0x3C00 is 1
            }
            break;
        default:
            throw new Error("Unsupported type: " + outputType);
    }
    let byteOffset = 0;
    for (const channel of header.channels) {
        if (decoder.decodeChannels[channel.name] !== undefined) {
            decoder.channelLineOffsets[channel.name] = byteOffset * decoder.width;
        }
        byteOffset += channel.pixelType * 2;
    }
    decoder.bytesPerLine = decoder.width * byteOffset;
    decoder.outLineWidth = decoder.width * decoder.outputChannels;
    if (header.lineOrder === "INCREASING_Y") {
        decoder.scanOrder = (y) => y;
    }
    else {
        decoder.scanOrder = (y) => decoder.height - 1 - y;
    }
    if (decoder.outputChannels == 4) {
        decoder.format = Constants.TEXTUREFORMAT_RGBA;
        decoder.linearSpace = true;
    }
    else {
        decoder.format = Constants.TEXTUREFORMAT_R;
        decoder.linearSpace = false;
    }
    return decoder;
}
/**
 * Scan the data of the exr file
 * @param decoder decoder to use
 * @param header header of the exr file
 * @param dataView dataview of the exr file
 * @param offset current offset
 */
function ScanData(decoder, header, dataView, offset) {
    const tmpOffset = { value: 0 };
    for (let scanlineBlockIdx = 0; scanlineBlockIdx < decoder.height / decoder.scanlineBlockSize; scanlineBlockIdx++) {
        const line = ParseInt32(dataView, offset) - header.dataWindow.yMin; // line_no
        decoder.size = ParseUint32(dataView, offset); // data_len
        decoder.lines = line + decoder.scanlineBlockSize > decoder.height ? decoder.height - line : decoder.scanlineBlockSize;
        const isCompressed = decoder.size < decoder.lines * decoder.bytesPerLine;
        const viewer = isCompressed && decoder.uncompress ? decoder.uncompress(decoder) : UncompressRAW(decoder);
        offset.value += decoder.size;
        for (let lineY = 0; lineY < decoder.scanlineBlockSize; lineY++) {
            const scanY = scanlineBlockIdx * decoder.scanlineBlockSize;
            const trueY = lineY + decoder.scanOrder(scanY);
            if (trueY >= decoder.height) {
                continue;
            }
            const lineOffset = lineY * decoder.bytesPerLine;
            const outLineOffset = (decoder.height - 1 - trueY) * decoder.outLineWidth;
            for (let channelID = 0; channelID < decoder.channels; channelID++) {
                const name = header.channels[channelID].name;
                const lOff = decoder.channelLineOffsets[name];
                const cOff = decoder.decodeChannels[name];
                if (cOff === undefined) {
                    continue;
                }
                tmpOffset.value = lineOffset + lOff;
                for (let x = 0; x < decoder.width; x++) {
                    const outIndex = outLineOffset + x * decoder.outputChannels + cOff;
                    if (decoder.byteArray) {
                        decoder.byteArray[outIndex] = decoder.getter(viewer, tmpOffset);
                    }
                }
            }
        }
    }
}

/**
 * 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 -------------------------------------------------
/**
 * Loader for .exr file format
 * @see [PIZ compression](https://playground.babylonjs.com/#4RN0VF#151)
 * @see [ZIP compression](https://playground.babylonjs.com/#4RN0VF#146)
 * @see [RLE compression](https://playground.babylonjs.com/#4RN0VF#149)
 * @see [PXR24 compression](https://playground.babylonjs.com/#4RN0VF#150)
 * @internal
 */
// eslint-disable-next-line @typescript-eslint/naming-convention
class _ExrTextureLoader {
    constructor() {
        /**
         * Defines whether the loader supports cascade loading the different faces.
         */
        this.supportCascades = false;
    }
    /**
     * Uploads the cube texture data to the WebGL texture. It has already been bound.
     * @param _data contains the texture data
     * @param _texture defines the BabylonJS internal texture
     * @param _createPolynomials will be true if polynomials have been requested
     * @param _onLoad defines the callback to trigger once the texture is ready
     * @param _onError defines the callback to trigger in case of error
     * Cube texture are not supported by .exr files
     */
    loadCubeData(_data, _texture, _createPolynomials, _onLoad, _onError) {
        // eslint-disable-next-line no-throw-literal
        throw ".exr not supported in Cube.";
    }
    /**
     * Uploads the 2D texture data to the WebGL texture. It has already been bound once in the callback.
     * @param data contains the texture data
     * @param texture defines the BabylonJS internal texture
     * @param callback defines the method to call once ready to upload
     */
    // eslint-disable-next-line @typescript-eslint/naming-convention
    loadData(data, texture, callback) {
        const dataView = new DataView(data.buffer);
        const offset = { value: 0 };
        const header = GetExrHeader(dataView, offset);
        CreateDecoderAsync(header, dataView, offset, ExrLoaderGlobalConfiguration.DefaultOutputType)
            // eslint-disable-next-line github/no-then
            .then((decoder) => {
            ScanData(decoder, header, dataView, offset);
            // Updating texture
            const width = header.dataWindow.xMax - header.dataWindow.xMin + 1;
            const height = header.dataWindow.yMax - header.dataWindow.yMin + 1;
            callback(width, height, texture.generateMipMaps, false, () => {
                const engine = texture.getEngine();
                texture.format = header.format;
                texture.type = decoder.textureType;
                texture.invertY = false;
                texture._gammaSpace = !header.linearSpace;
                if (decoder.byteArray) {
                    engine._uploadDataToTextureDirectly(texture, decoder.byteArray, 0, 0, undefined, true);
                }
            });
        })
            // eslint-disable-next-line github/no-then
            .catch((error) => {
            Logger.Error("Failed to load EXR texture: ", error);
        });
    }
}

export { _ExrTextureLoader };
//# sourceMappingURL=exrTextureLoader-BmijWxe-.esm.js.map