import { E as Engine } from './engine.pure-BKDuqv_s.esm.js';
import { o as ThinEngine, C as Constants, I as InternalTexture, L as Logger, bt as IsExponentOfTwo, cn as allocateAndCopyTypedBuffer, co as RegisterEngineDynamicBuffer, cp as GetExponentOfTwo, bT as HasStencilAspect, aP as BaseTexture, t as WebGLDataBuffer, p as AbstractEngine } from './index-BvJBnIUK.esm.js';
import { R as RenderTargetWrapper } from './renderTargetWrapper-CbtB23zJ.esm.js';
import { a as SphericalPolynomial } from './sphericalPolynomial.pure-D3WRmPNK.esm.js';
import './abstractEngine.dom.pure-Bni7lnbD.esm.js';
import './textureLoaderManager-B0s_1qUs.esm.js';

let _Registered$9 = false;
/**
 * Register side effects for enginesExtensionsEngineAlpha.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterEnginesExtensionsEngineAlpha() {
    if (_Registered$9) {
        return;
    }
    _Registered$9 = true;
    ThinEngine.prototype.setAlphaMode = function (mode, noDepthWriteChange = false, targetIndex = 0) {
        if (this._alphaMode[targetIndex] === mode) {
            if (!noDepthWriteChange) {
                // Make sure we still have the correct depth mask according to the alpha mode (a transparent material could have forced writting to the depth buffer, for instance)
                const depthMask = mode === Constants.ALPHA_DISABLE;
                if (this.depthCullingState.depthMask !== depthMask) {
                    this.depthCullingState.depthMask = depthMask;
                }
            }
            return;
        }
        const alphaBlendDisabled = mode === Constants.ALPHA_DISABLE;
        this._alphaState.setAlphaBlend(!alphaBlendDisabled, targetIndex);
        this._alphaState.setAlphaMode(mode, targetIndex);
        if (!noDepthWriteChange) {
            this.depthCullingState.depthMask = alphaBlendDisabled;
        }
        this._alphaMode[targetIndex] = mode;
    };
}

RegisterEnginesExtensionsEngineAlpha();

/** This file must only contain pure code and pure imports */
/**
 * @internal
 */
/**
 * Create a function for createRawTexture3D/createRawTexture2DArray
 * @param is3D true for TEXTURE_3D and false for TEXTURE_2D_ARRAY
 * @internal
 */
// eslint-disable-next-line @typescript-eslint/naming-convention
/**
 * Create a function for updateRawTexture3D/updateRawTexture2DArray
 * @param is3D true for TEXTURE_3D and false for TEXTURE_2D_ARRAY
 * @internal
 */
let _Registered$8 = false;
/**
 * Register side effects for enginesExtensionsEngineRawTexture.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterEnginesExtensionsEngineRawTexture() {
    if (_Registered$8) {
        return;
    }
    _Registered$8 = true;
    // eslint-disable-next-line @typescript-eslint/naming-convention
    function ConvertRGBtoRGBATextureData(rgbData, width, height, textureType) {
        // Create new RGBA data container.
        let rgbaData;
        let val1 = 1;
        if (textureType === Constants.TEXTURETYPE_FLOAT) {
            rgbaData = new Float32Array(width * height * 4);
        }
        else if (textureType === Constants.TEXTURETYPE_HALF_FLOAT) {
            rgbaData = new Uint16Array(width * height * 4);
            val1 = 15360; // 15360 is the encoding of 1 in half float
        }
        else if (textureType === Constants.TEXTURETYPE_UNSIGNED_INTEGER) {
            rgbaData = new Uint32Array(width * height * 4);
        }
        else {
            rgbaData = new Uint8Array(width * height * 4);
        }
        // Convert each pixel.
        for (let x = 0; x < width; x++) {
            for (let y = 0; y < height; y++) {
                const index = (y * width + x) * 3;
                const newIndex = (y * width + x) * 4;
                // Map Old Value to new value.
                rgbaData[newIndex + 0] = rgbData[index + 0];
                rgbaData[newIndex + 1] = rgbData[index + 1];
                rgbaData[newIndex + 2] = rgbData[index + 2];
                // Add fully opaque alpha channel.
                rgbaData[newIndex + 3] = val1;
            }
        }
        return rgbaData;
    }
    // eslint-disable-next-line @typescript-eslint/naming-convention
    function MakeCreateRawTextureFunction(is3D) {
        return function (data, width, height, depth, format, generateMipMaps, invertY, samplingMode, compression = null, textureType = Constants.TEXTURETYPE_UNSIGNED_BYTE) {
            const target = is3D ? this._gl.TEXTURE_3D : this._gl.TEXTURE_2D_ARRAY;
            const source = is3D ? 10 /* InternalTextureSource.Raw3D */ : 11 /* InternalTextureSource.Raw2DArray */;
            const texture = new InternalTexture(this, source);
            texture.baseWidth = width;
            texture.baseHeight = height;
            texture.baseDepth = depth;
            texture.width = width;
            texture.height = height;
            texture.depth = depth;
            texture.format = format;
            texture.type = textureType;
            texture.generateMipMaps = generateMipMaps;
            texture.samplingMode = samplingMode;
            if (is3D) {
                texture.is3D = true;
            }
            else {
                texture.is2DArray = true;
            }
            if (!this._doNotHandleContextLost) {
                texture._bufferView = data;
            }
            if (is3D) {
                this.updateRawTexture3D(texture, data, format, invertY, compression, textureType);
            }
            else {
                this.updateRawTexture2DArray(texture, data, format, invertY, compression, textureType);
            }
            this._bindTextureDirectly(target, texture, true);
            // Filters
            const filters = this._getSamplingParameters(samplingMode, generateMipMaps);
            this._gl.texParameteri(target, this._gl.TEXTURE_MAG_FILTER, filters.mag);
            this._gl.texParameteri(target, this._gl.TEXTURE_MIN_FILTER, filters.min);
            if (generateMipMaps) {
                this._gl.generateMipmap(target);
            }
            this._bindTextureDirectly(target, null);
            this._internalTexturesCache.push(texture);
            return texture;
        };
    }
    // eslint-disable-next-line @typescript-eslint/naming-convention
    function MakeUpdateRawTextureFunction(is3D) {
        return function (texture, data, format, invertY, compression = null, textureType = Constants.TEXTURETYPE_UNSIGNED_BYTE) {
            const target = is3D ? this._gl.TEXTURE_3D : this._gl.TEXTURE_2D_ARRAY;
            const internalType = this._getWebGLTextureType(textureType);
            const internalFormat = this._getInternalFormat(format);
            const internalSizedFomat = this._getRGBABufferInternalSizedFormat(textureType, format);
            this._bindTextureDirectly(target, texture, true);
            this._unpackFlipY(invertY === undefined ? true : invertY ? true : false);
            if (!this._doNotHandleContextLost) {
                texture._bufferView = data;
                texture.format = format;
                texture.invertY = invertY;
                texture._compression = compression;
            }
            if (texture.width % 4 !== 0) {
                this._gl.pixelStorei(this._gl.UNPACK_ALIGNMENT, 1);
            }
            if (compression && data) {
                this._gl.compressedTexImage3D(target, 0, this.getCaps().s3tc[compression], texture.width, texture.height, texture.depth, 0, data);
            }
            else {
                this._gl.texImage3D(target, 0, internalSizedFomat, texture.width, texture.height, texture.depth, 0, internalFormat, internalType, data);
            }
            if (texture.generateMipMaps) {
                this._gl.generateMipmap(target);
            }
            this._bindTextureDirectly(target, null);
            // this.resetTextureCache();
            texture.isReady = true;
        };
    }
    ThinEngine.prototype.updateRawTexture = function (texture, data, format, invertY, compression = null, type = Constants.TEXTURETYPE_UNSIGNED_BYTE, useSRGBBuffer = false) {
        if (!texture) {
            return;
        }
        // Babylon's internalSizedFomat but gl's texImage2D internalFormat
        const internalSizedFomat = this._getRGBABufferInternalSizedFormat(type, format, useSRGBBuffer);
        // Babylon's internalFormat but gl's texImage2D format
        const internalFormat = this._getInternalFormat(format);
        const textureType = this._getWebGLTextureType(type);
        this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
        this._unpackFlipY(invertY === undefined ? true : invertY ? true : false);
        if (!this._doNotHandleContextLost) {
            texture._bufferView = data;
            texture.format = format;
            texture.type = type;
            texture.invertY = invertY;
            texture._compression = compression;
        }
        if (texture.width % 4 !== 0) {
            this._gl.pixelStorei(this._gl.UNPACK_ALIGNMENT, 1);
        }
        if (compression && data) {
            this._gl.compressedTexImage2D(this._gl.TEXTURE_2D, 0, this.getCaps().s3tc[compression], texture.width, texture.height, 0, data);
        }
        else {
            this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalSizedFomat, texture.width, texture.height, 0, internalFormat, textureType, data);
        }
        if (texture.generateMipMaps) {
            this._gl.generateMipmap(this._gl.TEXTURE_2D);
        }
        this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
        //  this.resetTextureCache();
        texture.isReady = true;
    };
    ThinEngine.prototype.createRawTexture = function (data, width, height, format, generateMipMaps, invertY, samplingMode, compression = null, type = Constants.TEXTURETYPE_UNSIGNED_BYTE, 
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    creationFlags = 0, useSRGBBuffer = false) {
        const texture = new InternalTexture(this, 3 /* InternalTextureSource.Raw */);
        texture.baseWidth = width;
        texture.baseHeight = height;
        texture.width = width;
        texture.height = height;
        texture.format = format;
        texture.generateMipMaps = generateMipMaps;
        texture.samplingMode = samplingMode;
        texture.invertY = invertY;
        texture._compression = compression;
        texture.type = type;
        texture._useSRGBBuffer = this._getUseSRGBBuffer(useSRGBBuffer, !generateMipMaps);
        if (!this._doNotHandleContextLost) {
            texture._bufferView = data;
        }
        this.updateRawTexture(texture, data, format, invertY, compression, type, texture._useSRGBBuffer);
        this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
        // Filters
        const filters = this._getSamplingParameters(samplingMode, generateMipMaps);
        this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, filters.mag);
        this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, filters.min);
        if (generateMipMaps) {
            this._gl.generateMipmap(this._gl.TEXTURE_2D);
        }
        this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
        this._internalTexturesCache.push(texture);
        return texture;
    };
    ThinEngine.prototype.createRawCubeTexture = function (data, size, format, type, generateMipMaps, invertY, samplingMode, compression = null) {
        const gl = this._gl;
        const texture = new InternalTexture(this, 8 /* InternalTextureSource.CubeRaw */);
        texture.isCube = true;
        texture.format = format;
        texture.type = type;
        if (!this._doNotHandleContextLost) {
            texture._bufferViewArray = data;
        }
        const textureType = this._getWebGLTextureType(type);
        let internalFormat = this._getInternalFormat(format);
        if (internalFormat === gl.RGB) {
            internalFormat = gl.RGBA;
        }
        // Mipmap generation needs a sized internal format that is both color-renderable and texture-filterable
        if (textureType === gl.FLOAT && !this._caps.textureFloatLinearFiltering) {
            generateMipMaps = false;
            samplingMode = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
            Logger.Warn("Float texture filtering is not supported. Mipmap generation and sampling mode are forced to false and TEXTURE_NEAREST_SAMPLINGMODE, respectively.");
        }
        else if (textureType === this._gl.HALF_FLOAT_OES && !this._caps.textureHalfFloatLinearFiltering) {
            generateMipMaps = false;
            samplingMode = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
            Logger.Warn("Half float texture filtering is not supported. Mipmap generation and sampling mode are forced to false and TEXTURE_NEAREST_SAMPLINGMODE, respectively.");
        }
        else if (textureType === gl.FLOAT && !this._caps.textureFloatRender) {
            generateMipMaps = false;
            Logger.Warn("Render to float textures is not supported. Mipmap generation forced to false.");
        }
        else if (textureType === gl.HALF_FLOAT && !this._caps.colorBufferFloat) {
            generateMipMaps = false;
            Logger.Warn("Render to half float textures is not supported. Mipmap generation forced to false.");
        }
        const width = size;
        const height = width;
        texture.width = width;
        texture.height = height;
        texture.invertY = invertY;
        texture._compression = compression;
        // Double check on POT to generate Mips.
        const isPot = !this.needPOTTextures || (IsExponentOfTwo(texture.width) && IsExponentOfTwo(texture.height));
        if (!isPot) {
            generateMipMaps = false;
        }
        // Upload data if needed. The texture won't be ready until then.
        if (data) {
            this.updateRawCubeTexture(texture, data, format, type, invertY, compression);
        }
        else {
            const internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
            const level = 0;
            this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
            for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
                if (compression) {
                    gl.compressedTexImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, this.getCaps().s3tc[compression], texture.width, texture.height, 0, undefined);
                }
                else {
                    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, internalSizedFomat, texture.width, texture.height, 0, internalFormat, textureType, null);
                }
            }
            this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
        }
        this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture, true);
        // Filters
        if (data && generateMipMaps) {
            this._gl.generateMipmap(this._gl.TEXTURE_CUBE_MAP);
        }
        const filters = this._getSamplingParameters(samplingMode, generateMipMaps);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, filters.mag);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, filters.min);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
        texture.generateMipMaps = generateMipMaps;
        texture.samplingMode = samplingMode;
        texture.isReady = true;
        return texture;
    };
    ThinEngine.prototype.updateRawCubeTexture = function (texture, data, format, type, invertY, compression = null, level = 0) {
        texture._bufferViewArray = data;
        texture.format = format;
        texture.type = type;
        texture.invertY = invertY;
        texture._compression = compression;
        const gl = this._gl;
        const textureType = this._getWebGLTextureType(type);
        let internalFormat = this._getInternalFormat(format);
        const internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
        let needConversion = false;
        if (internalFormat === gl.RGB) {
            internalFormat = gl.RGBA;
            needConversion = true;
        }
        this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
        this._unpackFlipY(invertY === undefined ? true : invertY ? true : false);
        if (texture.width % 4 !== 0) {
            gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
        }
        // Data are known to be in +X +Y +Z -X -Y -Z
        for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
            let faceData = data[faceIndex];
            if (compression) {
                gl.compressedTexImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, this.getCaps().s3tc[compression], texture.width, texture.height, 0, faceData);
            }
            else {
                if (needConversion) {
                    faceData = ConvertRGBtoRGBATextureData(faceData, texture.width, texture.height, type);
                }
                gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, internalSizedFomat, texture.width, texture.height, 0, internalFormat, textureType, faceData);
            }
        }
        const isPot = !this.needPOTTextures || (IsExponentOfTwo(texture.width) && IsExponentOfTwo(texture.height));
        if (isPot && texture.generateMipMaps && level === 0) {
            this._gl.generateMipmap(this._gl.TEXTURE_CUBE_MAP);
        }
        this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
        // this.resetTextureCache();
        texture.isReady = true;
    };
    ThinEngine.prototype.createRawCubeTextureFromUrl = function (url, scene, size, format, type, noMipmap, callback, mipmapGenerator, onLoad = null, onError = null, samplingMode = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE, invertY = false) {
        const gl = this._gl;
        const texture = this.createRawCubeTexture(null, size, format, type, !noMipmap, invertY, samplingMode, null);
        scene?.addPendingData(texture);
        texture.url = url;
        texture.isReady = false;
        this._internalTexturesCache.push(texture);
        const onerror = (request, exception) => {
            scene?.removePendingData(texture);
            if (onError) {
                onError(request ? request.status + " " + request.statusText : "Failed to parse texture data", exception);
            }
        };
        const internalCallbackAsync = async (data) => {
            // If the texture has been disposed
            if (!texture._hardwareTexture) {
                return;
            }
            const faceDataArraysResult = callback(data);
            if (!faceDataArraysResult) {
                return;
            }
            const faceDataArrays = faceDataArraysResult instanceof Promise ? await faceDataArraysResult : faceDataArraysResult;
            const width = texture.width;
            if (mipmapGenerator) {
                const textureType = this._getWebGLTextureType(type);
                let internalFormat = this._getInternalFormat(format);
                const internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
                let needConversion = false;
                if (internalFormat === gl.RGB) {
                    internalFormat = gl.RGBA;
                    needConversion = true;
                }
                this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
                this._unpackFlipY(false);
                const mipData = mipmapGenerator(faceDataArrays);
                for (let level = 0; level < mipData.length; level++) {
                    const mipSize = width >> level;
                    for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
                        let mipFaceData = mipData[level][faceIndex];
                        if (needConversion) {
                            mipFaceData = ConvertRGBtoRGBATextureData(mipFaceData, mipSize, mipSize, type);
                        }
                        gl.texImage2D(faceIndex, level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipFaceData);
                    }
                }
                this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
            }
            else {
                this.updateRawCubeTexture(texture, faceDataArrays, format, type, invertY);
            }
            texture.isReady = true;
            // this.resetTextureCache();
            scene?.removePendingData(texture);
            texture.onLoadedObservable.notifyObservers(texture);
            texture.onLoadedObservable.clear();
            if (onLoad) {
                onLoad();
            }
        };
        this._loadFile(url, (data) => {
            // eslint-disable-next-line github/no-then
            internalCallbackAsync(data).catch((err) => {
                onerror(undefined, err);
            });
        }, undefined, scene?.offlineProvider, true, onerror);
        return texture;
    };
    ThinEngine.prototype.createRawTexture2DArray = MakeCreateRawTextureFunction(false);
    ThinEngine.prototype.createRawTexture3D = MakeCreateRawTextureFunction(true);
    ThinEngine.prototype.updateRawTexture2DArray = MakeUpdateRawTextureFunction(false);
    ThinEngine.prototype.updateRawTexture3D = MakeUpdateRawTextureFunction(true);
}

RegisterEnginesExtensionsEngineRawTexture();

/** This file must only contain pure code and pure imports */
let _Registered$7 = false;
/**
 * Register side effects for enginesExtensionsEngineReadTexture.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterEnginesExtensionsEngineReadTexture() {
    if (_Registered$7) {
        return;
    }
    _Registered$7 = true;
    ThinEngine.prototype._readTexturePixelsSync = function (texture, width, height, faceIndex = -1, level = 0, buffer = null, flushRenderer = true, noDataConversion = false, x = 0, y = 0) {
        const gl = this._gl;
        if (!gl) {
            throw new Error("Engine does not have gl rendering context.");
        }
        if (!this._dummyFramebuffer) {
            const dummy = gl.createFramebuffer();
            if (!dummy) {
                throw new Error("Unable to create dummy framebuffer");
            }
            this._dummyFramebuffer = dummy;
        }
        gl.bindFramebuffer(gl.FRAMEBUFFER, this._dummyFramebuffer);
        if (faceIndex > -1 && (texture.is2DArray || texture.is3D)) {
            gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture._hardwareTexture?.underlyingResource, level, faceIndex);
        }
        else if (faceIndex > -1) {
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._hardwareTexture?.underlyingResource, level);
        }
        else {
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._hardwareTexture?.underlyingResource, level);
        }
        let readType = texture.type !== undefined ? this._getWebGLTextureType(texture.type) : gl.UNSIGNED_BYTE;
        if (!noDataConversion) {
            switch (readType) {
                case gl.UNSIGNED_BYTE:
                    if (!buffer) {
                        buffer = new Uint8Array(4 * width * height);
                    }
                    readType = gl.UNSIGNED_BYTE;
                    break;
                default:
                    if (!buffer) {
                        buffer = new Float32Array(4 * width * height);
                    }
                    readType = gl.FLOAT;
                    break;
            }
        }
        else if (!buffer) {
            buffer = allocateAndCopyTypedBuffer(texture.type, 4 * width * height);
        }
        if (flushRenderer) {
            this.flushFramebuffer();
        }
        gl.readPixels(x, y, width, height, gl.RGBA, readType, buffer);
        gl.bindFramebuffer(gl.FRAMEBUFFER, this._currentFramebuffer);
        return buffer;
    };
    // eslint-disable-next-line @typescript-eslint/promise-function-async
    ThinEngine.prototype._readTexturePixels = function (texture, width, height, faceIndex = -1, level = 0, buffer = null, flushRenderer = true, noDataConversion = false, x = 0, y = 0) {
        return Promise.resolve(this._readTexturePixelsSync(texture, width, height, faceIndex, level, buffer, flushRenderer, noDataConversion, x, y));
    };
}

RegisterEnginesExtensionsEngineReadTexture();

RegisterEngineDynamicBuffer();

/** This file must only contain pure code and pure imports */
let _Registered$6 = false;
/**
 * Register side effects for enginesExtensionsEngineCubeTexture.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterEnginesExtensionsEngineCubeTexture() {
    if (_Registered$6) {
        return;
    }
    _Registered$6 = true;
    ThinEngine.prototype._createDepthStencilCubeTexture = function (size, options) {
        const internalTexture = new InternalTexture(this, 12 /* InternalTextureSource.DepthStencil */);
        internalTexture.isCube = true;
        if (this.webGLVersion === 1) {
            Logger.Error("Depth cube texture is not supported by WebGL 1.");
            return internalTexture;
        }
        const internalOptions = {
            bilinearFiltering: false,
            comparisonFunction: 0,
            generateStencil: false,
            ...options,
        };
        const gl = this._gl;
        this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, internalTexture, true);
        this._setupDepthStencilTexture(internalTexture, size, internalOptions.bilinearFiltering, internalOptions.comparisonFunction);
        // Create the depth/stencil buffer
        for (let face = 0; face < 6; face++) {
            if (internalOptions.generateStencil) {
                gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, gl.DEPTH24_STENCIL8, size, size, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null);
            }
            else {
                gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, gl.DEPTH_COMPONENT24, size, size, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
            }
        }
        this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
        this._internalTexturesCache.push(internalTexture);
        return internalTexture;
    };
    ThinEngine.prototype._setCubeMapTextureParams = function (texture, loadMipmap, maxLevel) {
        const gl = this._gl;
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, loadMipmap ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        texture.samplingMode = loadMipmap ? Constants.TEXTURE_TRILINEAR_SAMPLINGMODE : Constants.TEXTURE_LINEAR_LINEAR;
        if (loadMipmap && this.getCaps().textureMaxLevel && maxLevel !== undefined && maxLevel > 0) {
            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAX_LEVEL, maxLevel);
            texture._maxLodLevel = maxLevel;
        }
        this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
    };
    ThinEngine.prototype.createCubeTexture = function (rootUrl, scene, files, noMipmap, onLoad = null, onError = null, format, forcedExtension = null, createPolynomials = false, lodScale = 0, lodOffset = 0, fallback = null, loaderOptions, useSRGBBuffer = false, buffer = null) {
        const gl = this._gl;
        return this.createCubeTextureBase(rootUrl, scene, files, !!noMipmap, onLoad, onError, format, forcedExtension, createPolynomials, lodScale, lodOffset, fallback, (texture) => this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true), (texture, imgs) => {
            const width = this.needPOTTextures ? GetExponentOfTwo(imgs[0].width, this._caps.maxCubemapTextureSize) : imgs[0].width;
            const height = width;
            const faces = [
                gl.TEXTURE_CUBE_MAP_POSITIVE_X,
                gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
                gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
                gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
                gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
                gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
            ];
            this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
            this._unpackFlipY(false);
            const internalFormat = format
                ? this._getInternalFormat(format, texture._useSRGBBuffer)
                : texture._useSRGBBuffer
                    ? this._glSRGBExtensionValues.SRGB8_ALPHA8
                    : gl.RGBA;
            let texelFormat = format ? this._getInternalFormat(format) : gl.RGBA;
            if (texture._useSRGBBuffer && this.webGLVersion === 1) {
                texelFormat = internalFormat;
            }
            for (let index = 0; index < faces.length; index++) {
                if (imgs[index].width !== width || imgs[index].height !== height) {
                    this._prepareWorkingCanvas();
                    if (!this._workingCanvas || !this._workingContext) {
                        Logger.Warn("Cannot create canvas to resize texture.");
                        return;
                    }
                    this._workingCanvas.width = width;
                    this._workingCanvas.height = height;
                    this._workingContext.drawImage(imgs[index], 0, 0, imgs[index].width, imgs[index].height, 0, 0, width, height);
                    gl.texImage2D(faces[index], 0, internalFormat, texelFormat, gl.UNSIGNED_BYTE, this._workingCanvas);
                }
                else {
                    gl.texImage2D(faces[index], 0, internalFormat, texelFormat, gl.UNSIGNED_BYTE, imgs[index]);
                }
            }
            if (!noMipmap) {
                gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
            }
            this._setCubeMapTextureParams(texture, !noMipmap);
            texture.width = width;
            texture.height = height;
            texture.isReady = true;
            if (format) {
                texture.format = format;
            }
            texture.onLoadedObservable.notifyObservers(texture);
            texture.onLoadedObservable.clear();
            if (onLoad) {
                onLoad();
            }
        }, !!useSRGBBuffer, buffer);
    };
    ThinEngine.prototype.generateMipMapsForCubemap = function (texture, unbind = true) {
        if (texture.generateMipMaps) {
            const gl = this._gl;
            this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
            gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
            if (unbind) {
                this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
            }
        }
    };
}

RegisterEnginesExtensionsEngineCubeTexture();

/** @internal */
class WebGLRenderTargetWrapper extends RenderTargetWrapper {
    setDepthStencilTexture(texture, disposeExisting = true) {
        super.setDepthStencilTexture(texture, disposeExisting);
        if (!texture) {
            return;
        }
        const engine = this._engine;
        const gl = this._context;
        const hardwareTexture = texture._hardwareTexture;
        if (hardwareTexture && texture._autoMSAAManagement && this._MSAAFramebuffer) {
            const currentFb = engine._currentFramebuffer;
            engine._bindUnboundFramebuffer(this._MSAAFramebuffer);
            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, HasStencilAspect(texture.format) ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, hardwareTexture.getMSAARenderBuffer());
            engine._bindUnboundFramebuffer(currentFb);
        }
    }
    constructor(isMulti, isCube, size, engine, context) {
        super(isMulti, isCube, size, engine);
        /**
         * @internal
         */
        this._framebuffer = null;
        /**
         * @internal
         */
        this._depthStencilBuffer = null;
        // eslint-disable-next-line @typescript-eslint/naming-convention
        /**
         * @internal
         */
        // eslint-disable-next-line @typescript-eslint/naming-convention
        this._MSAAFramebuffer = null;
        // Multiview
        /**
         * @internal
         */
        this._colorTextureArray = null;
        /**
         * @internal
         */
        this._depthStencilTextureArray = null;
        /**
         * @internal
         */
        this._disposeOnlyFramebuffers = false;
        /**
         * @internal
         */
        this._currentLOD = 0;
        this._context = context;
    }
    _cloneRenderTargetWrapper() {
        let rtw;
        if (this._colorTextureArray && this._depthStencilTextureArray) {
            rtw = this._engine.createMultiviewRenderTargetTexture(this.width, this.height);
            rtw.texture.isReady = true;
        }
        else {
            rtw = super._cloneRenderTargetWrapper();
        }
        return rtw;
    }
    _swapRenderTargetWrapper(target) {
        super._swapRenderTargetWrapper(target);
        target._framebuffer = this._framebuffer;
        target._depthStencilBuffer = this._depthStencilBuffer;
        target._MSAAFramebuffer = this._MSAAFramebuffer;
        target._colorTextureArray = this._colorTextureArray;
        target._depthStencilTextureArray = this._depthStencilTextureArray;
        this._framebuffer = this._depthStencilBuffer = this._MSAAFramebuffer = this._colorTextureArray = this._depthStencilTextureArray = null;
    }
    /**
     * Creates the depth/stencil texture
     * @param comparisonFunction Comparison function to use for the texture
     * @param bilinearFiltering true if bilinear filtering should be used when sampling the texture
     * @param generateStencil true if the stencil aspect should also be created
     * @param samples sample count to use when creating the texture
     * @param format format of the depth texture
     * @param label defines the label to use for the texture (for debugging purpose only)
     * @returns the depth/stencil created texture
     */
    createDepthStencilTexture(comparisonFunction = 0, bilinearFiltering = true, generateStencil = false, samples = 1, format = Constants.TEXTUREFORMAT_DEPTH32_FLOAT, label) {
        if (this._depthStencilBuffer) {
            const engine = this._engine;
            // Dispose previous depth/stencil render buffers and clear the corresponding attachment.
            // Next time this framebuffer is bound, the new depth/stencil texture will be attached.
            const currentFrameBuffer = engine._currentFramebuffer;
            const gl = this._context;
            engine._bindUnboundFramebuffer(this._framebuffer);
            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, null);
            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null);
            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null);
            engine._bindUnboundFramebuffer(currentFrameBuffer);
            gl.deleteRenderbuffer(this._depthStencilBuffer);
            this._depthStencilBuffer = null;
        }
        return super.createDepthStencilTexture(comparisonFunction, bilinearFiltering, generateStencil, samples, format, label);
    }
    /**
     * Shares the depth buffer of this render target with another render target.
     * @param renderTarget Destination renderTarget
     */
    shareDepth(renderTarget) {
        super.shareDepth(renderTarget);
        const gl = this._context;
        const depthbuffer = this._depthStencilBuffer;
        const framebuffer = renderTarget._MSAAFramebuffer || renderTarget._framebuffer;
        const engine = this._engine;
        if (renderTarget._depthStencilBuffer && renderTarget._depthStencilBuffer !== depthbuffer) {
            gl.deleteRenderbuffer(renderTarget._depthStencilBuffer);
        }
        renderTarget._depthStencilBuffer = depthbuffer;
        const attachment = renderTarget._generateStencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
        engine._bindUnboundFramebuffer(framebuffer);
        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, depthbuffer);
        engine._bindUnboundFramebuffer(null);
    }
    /**
     * Binds a texture to this render target on a specific attachment
     * @param texture The texture to bind to the framebuffer
     * @param attachmentIndex Index of the attachment
     * @param faceIndexOrLayer The face or layer of the texture to render to in case of cube texture or array texture
     * @param lodLevel defines the lod level to bind to the frame buffer
     */
    _bindTextureRenderTarget(texture, attachmentIndex = 0, faceIndexOrLayer, lodLevel = 0) {
        const hardwareTexture = texture._hardwareTexture;
        if (!hardwareTexture) {
            return;
        }
        const framebuffer = this._framebuffer;
        const engine = this._engine;
        const currentFb = engine._currentFramebuffer;
        engine._bindUnboundFramebuffer(framebuffer);
        let attachment;
        if (engine.webGLVersion > 1) {
            const gl = this._context;
            attachment = gl["COLOR_ATTACHMENT" + attachmentIndex];
            if (texture.is2DArray || texture.is3D) {
                faceIndexOrLayer = faceIndexOrLayer ?? this.layerIndices?.[attachmentIndex] ?? 0;
                gl.framebufferTextureLayer(gl.FRAMEBUFFER, attachment, hardwareTexture.underlyingResource, lodLevel, faceIndexOrLayer);
            }
            else if (texture.isCube) {
                // if face index is not specified, try to query it from faceIndices
                // default is face 0
                faceIndexOrLayer = faceIndexOrLayer ?? this.faceIndices?.[attachmentIndex] ?? 0;
                gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndexOrLayer, hardwareTexture.underlyingResource, lodLevel);
            }
            else {
                gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, hardwareTexture.underlyingResource, lodLevel);
            }
        }
        else {
            // Default behavior (WebGL)
            const gl = this._context;
            attachment = gl["COLOR_ATTACHMENT" + attachmentIndex + "_WEBGL"];
            const target = faceIndexOrLayer !== undefined ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndexOrLayer : gl.TEXTURE_2D;
            gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, target, hardwareTexture.underlyingResource, lodLevel);
        }
        if (texture._autoMSAAManagement && this._MSAAFramebuffer) {
            const gl = this._context;
            engine._bindUnboundFramebuffer(this._MSAAFramebuffer);
            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, hardwareTexture.getMSAARenderBuffer());
        }
        engine._bindUnboundFramebuffer(currentFb);
    }
    /**
     * Set a texture in the textures array
     * @param texture the texture to set
     * @param index the index in the textures array to set
     * @param disposePrevious If this function should dispose the previous texture
     */
    setTexture(texture, index = 0, disposePrevious = true) {
        super.setTexture(texture, index, disposePrevious);
        this._bindTextureRenderTarget(texture, index);
    }
    /**
     * Sets the layer and face indices of every render target texture
     * @param layers The layer of the texture to be set (make negative to not modify)
     * @param faces The face of the texture to be set (make negative to not modify)
     */
    setLayerAndFaceIndices(layers, faces) {
        super.setLayerAndFaceIndices(layers, faces);
        if (!this.textures || !this.layerIndices || !this.faceIndices) {
            return;
        }
        // the length of this._attachments is the right one as it does not count the depth texture, in case we generated it
        const textureCount = this._attachments?.length ?? this.textures.length;
        for (let index = 0; index < textureCount; index++) {
            const texture = this.textures[index];
            if (!texture) {
                // The target type was probably -1 at creation time and setTexture has not been called yet for this index
                continue;
            }
            if (texture.is2DArray || texture.is3D) {
                this._bindTextureRenderTarget(texture, index, this.layerIndices[index]);
            }
            else if (texture.isCube) {
                this._bindTextureRenderTarget(texture, index, this.faceIndices[index]);
            }
            else {
                this._bindTextureRenderTarget(texture, index);
            }
        }
    }
    /**
     * Set the face and layer indices of a texture in the textures array
     * @param index The index of the texture in the textures array to modify
     * @param layer The layer of the texture to be set
     * @param face The face of the texture to be set
     */
    setLayerAndFaceIndex(index = 0, layer, face) {
        super.setLayerAndFaceIndex(index, layer, face);
        if (!this.textures || !this.layerIndices || !this.faceIndices) {
            return;
        }
        const texture = this.textures[index];
        if (texture.is2DArray || texture.is3D) {
            this._bindTextureRenderTarget(this.textures[index], index, this.layerIndices[index]);
        }
        else if (texture.isCube) {
            this._bindTextureRenderTarget(this.textures[index], index, this.faceIndices[index]);
        }
    }
    resolveMSAATextures() {
        const engine = this._engine;
        const currentFramebuffer = engine._currentFramebuffer;
        engine._bindUnboundFramebuffer(this._MSAAFramebuffer);
        super.resolveMSAATextures();
        engine._bindUnboundFramebuffer(currentFramebuffer);
    }
    dispose(disposeOnlyFramebuffers = this._disposeOnlyFramebuffers) {
        const gl = this._context;
        if (!disposeOnlyFramebuffers) {
            if (this._colorTextureArray) {
                this._context.deleteTexture(this._colorTextureArray);
                this._colorTextureArray = null;
            }
            if (this._depthStencilTextureArray) {
                this._context.deleteTexture(this._depthStencilTextureArray);
                this._depthStencilTextureArray = null;
            }
        }
        if (this._framebuffer) {
            gl.deleteFramebuffer(this._framebuffer);
            this._framebuffer = null;
        }
        if (this._depthStencilBuffer) {
            gl.deleteRenderbuffer(this._depthStencilBuffer);
            this._depthStencilBuffer = null;
        }
        if (this._MSAAFramebuffer) {
            gl.deleteFramebuffer(this._MSAAFramebuffer);
            this._MSAAFramebuffer = null;
        }
        super.dispose(disposeOnlyFramebuffers);
    }
}

/** This file must only contain pure code and pure imports */
let _Registered$5 = false;
/**
 * Register side effects for enginesExtensionsEngineRenderTarget.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterEnginesExtensionsEngineRenderTarget() {
    if (_Registered$5) {
        return;
    }
    _Registered$5 = true;
    ThinEngine.prototype._createHardwareRenderTargetWrapper = function (isMulti, isCube, size) {
        const rtWrapper = new WebGLRenderTargetWrapper(isMulti, isCube, size, this, this._gl);
        this._renderTargetWrapperCache.push(rtWrapper);
        return rtWrapper;
    };
    ThinEngine.prototype.createRenderTargetTexture = function (size, options) {
        const rtWrapper = this._createHardwareRenderTargetWrapper(false, false, size);
        let generateDepthBuffer = true;
        let generateStencilBuffer = false;
        let noColorAttachment = false;
        let colorAttachment = undefined;
        let samples = 1;
        let label = undefined;
        if (options !== undefined && typeof options === "object") {
            generateDepthBuffer = options.generateDepthBuffer ?? true;
            generateStencilBuffer = !!options.generateStencilBuffer;
            noColorAttachment = !!options.noColorAttachment;
            colorAttachment = options.colorAttachment;
            samples = options.samples ?? 1;
            label = options.label;
        }
        const texture = colorAttachment || (noColorAttachment ? null : this._createInternalTexture(size, options, true, 5 /* InternalTextureSource.RenderTarget */));
        const width = size.width || size;
        const height = size.height || size;
        const currentFrameBuffer = this._currentFramebuffer;
        const gl = this._gl;
        // Create the framebuffer
        const framebuffer = gl.createFramebuffer();
        this._bindUnboundFramebuffer(framebuffer);
        rtWrapper._depthStencilBuffer = this._setupFramebufferDepthAttachments(generateStencilBuffer, generateDepthBuffer, width, height);
        // No need to rebind on every frame
        if (texture && !texture.is2DArray && !texture.is3D) {
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._hardwareTexture.underlyingResource, 0);
        }
        this._bindUnboundFramebuffer(currentFrameBuffer);
        rtWrapper.label = label ?? "RenderTargetWrapper";
        rtWrapper._framebuffer = framebuffer;
        rtWrapper._generateDepthBuffer = generateDepthBuffer;
        rtWrapper._generateStencilBuffer = generateStencilBuffer;
        rtWrapper.setTextures(texture);
        if (!colorAttachment) {
            this.updateRenderTargetTextureSampleCount(rtWrapper, samples);
        }
        else {
            rtWrapper._samples = colorAttachment.samples;
            if (colorAttachment.samples > 1) {
                const msaaRenderBuffer = colorAttachment._hardwareTexture.getMSAARenderBuffer(0);
                rtWrapper._MSAAFramebuffer = gl.createFramebuffer();
                this._bindUnboundFramebuffer(rtWrapper._MSAAFramebuffer);
                gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msaaRenderBuffer);
                this._bindUnboundFramebuffer(null);
            }
        }
        return rtWrapper;
    };
    ThinEngine.prototype._createDepthStencilTexture = function (size, options, rtWrapper) {
        const gl = this._gl;
        const layers = size.layers || 0;
        const depth = size.depth || 0;
        let target = gl.TEXTURE_2D;
        if (layers !== 0) {
            target = gl.TEXTURE_2D_ARRAY;
        }
        else if (depth !== 0) {
            target = gl.TEXTURE_3D;
        }
        const internalTexture = new InternalTexture(this, 12 /* InternalTextureSource.DepthStencil */);
        internalTexture.label = options.label;
        if (!this._caps.depthTextureExtension) {
            Logger.Error("Depth texture is not supported by your browser or hardware.");
            return internalTexture;
        }
        const internalOptions = {
            bilinearFiltering: false,
            comparisonFunction: 0,
            generateStencil: false,
            ...options,
        };
        this._bindTextureDirectly(target, internalTexture, true);
        this._setupDepthStencilTexture(internalTexture, size, internalOptions.comparisonFunction === 0 ? false : internalOptions.bilinearFiltering, internalOptions.comparisonFunction, internalOptions.samples);
        if (internalOptions.depthTextureFormat !== undefined) {
            if (internalOptions.depthTextureFormat !== Constants.TEXTUREFORMAT_DEPTH16 &&
                internalOptions.depthTextureFormat !== Constants.TEXTUREFORMAT_DEPTH24 &&
                internalOptions.depthTextureFormat !== Constants.TEXTUREFORMAT_DEPTH24UNORM_STENCIL8 &&
                internalOptions.depthTextureFormat !== Constants.TEXTUREFORMAT_DEPTH24_STENCIL8 &&
                internalOptions.depthTextureFormat !== Constants.TEXTUREFORMAT_DEPTH32_FLOAT &&
                internalOptions.depthTextureFormat !== Constants.TEXTUREFORMAT_DEPTH32FLOAT_STENCIL8) {
                Logger.Error(`Depth texture ${internalOptions.depthTextureFormat} format is not supported.`);
                return internalTexture;
            }
            internalTexture.format = internalOptions.depthTextureFormat;
        }
        else {
            internalTexture.format = internalOptions.generateStencil ? Constants.TEXTUREFORMAT_DEPTH24_STENCIL8 : Constants.TEXTUREFORMAT_DEPTH24;
        }
        const hasStencil = HasStencilAspect(internalTexture.format);
        const type = this._getWebGLTextureTypeFromDepthTextureFormat(internalTexture.format);
        const format = hasStencil ? gl.DEPTH_STENCIL : gl.DEPTH_COMPONENT;
        const internalFormat = this._getInternalFormatFromDepthTextureFormat(internalTexture.format, true, hasStencil);
        if (internalTexture.is2DArray) {
            gl.texImage3D(target, 0, internalFormat, internalTexture.width, internalTexture.height, layers, 0, format, type, null);
        }
        else if (internalTexture.is3D) {
            gl.texImage3D(target, 0, internalFormat, internalTexture.width, internalTexture.height, depth, 0, format, type, null);
        }
        else {
            gl.texImage2D(target, 0, internalFormat, internalTexture.width, internalTexture.height, 0, format, type, null);
        }
        this._bindTextureDirectly(target, null);
        this._internalTexturesCache.push(internalTexture);
        if (rtWrapper._depthStencilBuffer) {
            gl.deleteRenderbuffer(rtWrapper._depthStencilBuffer);
            rtWrapper._depthStencilBuffer = null;
        }
        this._bindUnboundFramebuffer(rtWrapper._MSAAFramebuffer ?? rtWrapper._framebuffer);
        rtWrapper._generateStencilBuffer = hasStencil;
        rtWrapper._depthStencilTextureWithStencil = hasStencil;
        rtWrapper._depthStencilBuffer = this._setupFramebufferDepthAttachments(rtWrapper._generateStencilBuffer, rtWrapper._generateDepthBuffer, rtWrapper.width, rtWrapper.height, rtWrapper.samples, internalTexture.format);
        this._bindUnboundFramebuffer(null);
        return internalTexture;
    };
    ThinEngine.prototype.updateRenderTargetTextureSampleCount = function (rtWrapper, samples) {
        if (this.webGLVersion < 2 || !rtWrapper) {
            return 1;
        }
        if (rtWrapper.samples === samples) {
            return samples;
        }
        const gl = this._gl;
        samples = Math.min(samples, this.getCaps().maxMSAASamples);
        // Dispose previous render buffers
        if (rtWrapper._depthStencilBuffer) {
            gl.deleteRenderbuffer(rtWrapper._depthStencilBuffer);
            rtWrapper._depthStencilBuffer = null;
        }
        if (rtWrapper._MSAAFramebuffer) {
            gl.deleteFramebuffer(rtWrapper._MSAAFramebuffer);
            rtWrapper._MSAAFramebuffer = null;
        }
        const hardwareTexture = rtWrapper.texture?._hardwareTexture;
        hardwareTexture?.releaseMSAARenderBuffers();
        if (rtWrapper.texture && samples > 1 && typeof gl.renderbufferStorageMultisample === "function") {
            const framebuffer = gl.createFramebuffer();
            if (!framebuffer) {
                throw new Error("Unable to create multi sampled framebuffer");
            }
            rtWrapper._MSAAFramebuffer = framebuffer;
            this._bindUnboundFramebuffer(rtWrapper._MSAAFramebuffer);
            const colorRenderbuffer = this._createRenderBuffer(rtWrapper.texture.width, rtWrapper.texture.height, samples, -1 /* not used */, this._getRGBABufferInternalSizedFormat(rtWrapper.texture.type, rtWrapper.texture.format, rtWrapper.texture._useSRGBBuffer), gl.COLOR_ATTACHMENT0, false);
            if (!colorRenderbuffer) {
                throw new Error("Unable to create multi sampled framebuffer");
            }
            hardwareTexture?.addMSAARenderBuffer(colorRenderbuffer);
        }
        this._bindUnboundFramebuffer(rtWrapper._MSAAFramebuffer ?? rtWrapper._framebuffer);
        if (rtWrapper.texture) {
            rtWrapper.texture.samples = samples;
        }
        rtWrapper._samples = samples;
        const depthFormat = rtWrapper._depthStencilTexture ? rtWrapper._depthStencilTexture.format : undefined;
        rtWrapper._depthStencilBuffer = this._setupFramebufferDepthAttachments(rtWrapper._generateStencilBuffer, rtWrapper._generateDepthBuffer, rtWrapper.width, rtWrapper.height, samples, depthFormat);
        this._bindUnboundFramebuffer(null);
        return samples;
    };
    ThinEngine.prototype._setupDepthStencilTexture = function (internalTexture, size, bilinearFiltering, comparisonFunction, samples = 1) {
        const width = size.width ?? size;
        const height = size.height ?? size;
        const layers = size.layers || 0;
        const depth = size.depth || 0;
        internalTexture.baseWidth = width;
        internalTexture.baseHeight = height;
        internalTexture.width = width;
        internalTexture.height = height;
        internalTexture.is2DArray = layers > 0;
        internalTexture.depth = layers || depth;
        internalTexture.isReady = true;
        internalTexture.samples = samples;
        internalTexture.generateMipMaps = false;
        internalTexture.samplingMode = bilinearFiltering ? Constants.TEXTURE_BILINEAR_SAMPLINGMODE : Constants.TEXTURE_NEAREST_SAMPLINGMODE;
        internalTexture.type = Constants.TEXTURETYPE_UNSIGNED_BYTE;
        internalTexture._comparisonFunction = comparisonFunction;
        const gl = this._gl;
        const target = this._getTextureTarget(internalTexture);
        const samplingParameters = this._getSamplingParameters(internalTexture.samplingMode, false);
        gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, samplingParameters.mag);
        gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, samplingParameters.min);
        gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        // TEXTURE_COMPARE_FUNC/MODE are only availble in WebGL2.
        if (this.webGLVersion > 1) {
            if (comparisonFunction === 0) {
                gl.texParameteri(target, gl.TEXTURE_COMPARE_FUNC, Constants.LEQUAL);
                gl.texParameteri(target, gl.TEXTURE_COMPARE_MODE, gl.NONE);
            }
            else {
                gl.texParameteri(target, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
                gl.texParameteri(target, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
            }
        }
    };
}

RegisterEnginesExtensionsEngineRenderTarget();

/** This file must only contain pure code and pure imports */
let _Registered$4 = false;
/**
 * Register side effects for enginesExtensionsEngineRenderTargetTexture.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterEnginesExtensionsEngineRenderTargetTexture() {
    if (_Registered$4) {
        return;
    }
    _Registered$4 = true;
    ThinEngine.prototype.setDepthStencilTexture = function (channel, uniform, texture, name) {
        if (channel === undefined) {
            return;
        }
        if (uniform) {
            this._boundUniforms[channel] = uniform;
        }
        if (!texture || !texture.depthStencilTexture) {
            this._setTexture(channel, null, undefined, undefined, name);
        }
        else {
            this._setTexture(channel, texture, false, true, name);
        }
    };
}

RegisterEnginesExtensionsEngineRenderTargetTexture();

/** This file must only contain pure code and pure imports */
let _Registered$3 = false;
/**
 * Register side effects for enginesExtensionsEngineRenderTargetCube.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterEnginesExtensionsEngineRenderTargetCube() {
    if (_Registered$3) {
        return;
    }
    _Registered$3 = true;
    ThinEngine.prototype.createRenderTargetCubeTexture = function (size, options) {
        const rtWrapper = this._createHardwareRenderTargetWrapper(false, true, size);
        const fullOptions = {
            generateMipMaps: true,
            generateDepthBuffer: true,
            generateStencilBuffer: false,
            type: Constants.TEXTURETYPE_UNSIGNED_BYTE,
            samplingMode: Constants.TEXTURE_TRILINEAR_SAMPLINGMODE,
            format: Constants.TEXTUREFORMAT_RGBA,
            ...options,
        };
        fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && fullOptions.generateStencilBuffer;
        if (fullOptions.type === Constants.TEXTURETYPE_FLOAT && !this._caps.textureFloatLinearFiltering) {
            // if floating point linear (gl.FLOAT) then force to NEAREST_SAMPLINGMODE
            fullOptions.samplingMode = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
        }
        else if (fullOptions.type === Constants.TEXTURETYPE_HALF_FLOAT && !this._caps.textureHalfFloatLinearFiltering) {
            // if floating point linear (HALF_FLOAT) then force to NEAREST_SAMPLINGMODE
            fullOptions.samplingMode = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
        }
        const gl = this._gl;
        const texture = new InternalTexture(this, 5 /* InternalTextureSource.RenderTarget */);
        this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
        const filters = this._getSamplingParameters(fullOptions.samplingMode, fullOptions.generateMipMaps);
        if (fullOptions.type === Constants.TEXTURETYPE_FLOAT && !this._caps.textureFloat) {
            fullOptions.type = Constants.TEXTURETYPE_UNSIGNED_BYTE;
            Logger.Warn("Float textures are not supported. Cube render target forced to TEXTURETYPE_UNESIGNED_BYTE type");
        }
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, filters.mag);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, filters.min);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        for (let face = 0; face < 6; face++) {
            gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, this._getRGBABufferInternalSizedFormat(fullOptions.type, fullOptions.format), size, size, 0, this._getInternalFormat(fullOptions.format), this._getWebGLTextureType(fullOptions.type), null);
        }
        // Create the framebuffer
        const framebuffer = gl.createFramebuffer();
        this._bindUnboundFramebuffer(framebuffer);
        rtWrapper._depthStencilBuffer = this._setupFramebufferDepthAttachments(fullOptions.generateStencilBuffer, fullOptions.generateDepthBuffer, size, size);
        // MipMaps
        if (fullOptions.generateMipMaps) {
            gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
        }
        // Unbind
        this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
        this._bindUnboundFramebuffer(null);
        rtWrapper._framebuffer = framebuffer;
        rtWrapper._generateDepthBuffer = fullOptions.generateDepthBuffer;
        rtWrapper._generateStencilBuffer = fullOptions.generateStencilBuffer;
        texture.width = size;
        texture.height = size;
        texture.isReady = true;
        texture.isCube = true;
        texture.samples = 1;
        texture.generateMipMaps = fullOptions.generateMipMaps;
        texture.samplingMode = fullOptions.samplingMode;
        texture.type = fullOptions.type;
        texture.format = fullOptions.format;
        this._internalTexturesCache.push(texture);
        rtWrapper.setTextures(texture);
        return rtWrapper;
    };
}

RegisterEnginesExtensionsEngineRenderTargetCube();

/** This file must only contain pure code and pure imports */
let _Registered$2 = false;
/**
 * Register side effects for enginePrefilteredCubeTexture.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterEnginePrefilteredCubeTexture() {
    if (_Registered$2) {
        return;
    }
    _Registered$2 = true;
    ThinEngine.prototype.createPrefilteredCubeTexture = function (rootUrl, scene, lodScale, lodOffset, onLoad = null, onError = null, format, forcedExtension = null, createPolynomials = true) {
        const callbackAsync = async (loadData) => {
            if (!loadData) {
                if (onLoad) {
                    onLoad(null);
                }
                return;
            }
            const texture = loadData.texture;
            if (!createPolynomials) {
                texture._sphericalPolynomial = texture._sphericalPolynomial ?? new SphericalPolynomial();
            }
            else if (loadData.info.sphericalPolynomial) {
                texture._sphericalPolynomial = loadData.info.sphericalPolynomial;
            }
            texture._source = 9 /* InternalTextureSource.CubePrefiltered */;
            if (this.getCaps().textureLOD) {
                // Do not add extra process if texture lod is supported.
                if (onLoad) {
                    onLoad(texture);
                }
                return;
            }
            const mipSlices = 3;
            const gl = this._gl;
            const width = loadData.width;
            if (!width) {
                return;
            }
            const { DDSTools } = await import('./dds-Cu1yFSSS.esm.js');
            const textures = [];
            for (let i = 0; i < mipSlices; i++) {
                //compute LOD from even spacing in smoothness (matching shader calculation)
                const smoothness = i / (mipSlices - 1);
                const roughness = 1 - smoothness;
                const minLODIndex = lodOffset; // roughness = 0
                const maxLODIndex = Math.log2(width) * lodScale + lodOffset; // roughness = 1
                const lodIndex = minLODIndex + (maxLODIndex - minLODIndex) * roughness;
                const mipmapIndex = Math.round(Math.min(Math.max(lodIndex, 0), maxLODIndex));
                const glTextureFromLod = new InternalTexture(this, 2 /* InternalTextureSource.Temp */);
                glTextureFromLod.type = texture.type;
                glTextureFromLod.format = texture.format;
                glTextureFromLod.width = Math.pow(2, Math.max(Math.log2(width) - mipmapIndex, 0));
                glTextureFromLod.height = glTextureFromLod.width;
                glTextureFromLod.isCube = true;
                glTextureFromLod._cachedWrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;
                glTextureFromLod._cachedWrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;
                this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, glTextureFromLod, true);
                glTextureFromLod.samplingMode = Constants.TEXTURE_LINEAR_LINEAR;
                gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
                gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
                gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
                gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
                if (loadData.isDDS) {
                    const info = loadData.info;
                    const data = loadData.data;
                    this._unpackFlipY(info.isCompressed);
                    DDSTools.UploadDDSLevels(this, glTextureFromLod, data, info, true, 6, mipmapIndex);
                }
                else {
                    Logger.Warn("DDS is the only prefiltered cube map supported so far.");
                }
                this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
                // Wrap in a base texture for easy binding.
                const lodTexture = new BaseTexture(scene);
                lodTexture._isCube = true;
                lodTexture._texture = glTextureFromLod;
                glTextureFromLod.isReady = true;
                textures.push(lodTexture);
            }
            texture._lodTextureHigh = textures[2];
            texture._lodTextureMid = textures[1];
            texture._lodTextureLow = textures[0];
            if (onLoad) {
                onLoad(texture);
            }
        };
        // eslint-disable-next-line @typescript-eslint/no-misused-promises
        return this.createCubeTexture(rootUrl, scene, null, false, callbackAsync, onError, format, forcedExtension, createPolynomials, lodScale, lodOffset);
    };
}

RegisterEnginePrefilteredCubeTexture();

/** This file must only contain pure code and pure imports */
let _Registered$1 = false;
/**
 * Register side effects for engineUniformBuffer.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterEngineUniformBuffer() {
    if (_Registered$1) {
        return;
    }
    _Registered$1 = true;
    ThinEngine.prototype.createUniformBuffer = function (elements, _label) {
        const ubo = this._gl.createBuffer();
        if (!ubo) {
            throw new Error("Unable to create uniform buffer");
        }
        const result = new WebGLDataBuffer(ubo);
        this.bindUniformBuffer(result);
        if (elements instanceof Float32Array) {
            this._gl.bufferData(this._gl.UNIFORM_BUFFER, elements, this._gl.STATIC_DRAW);
        }
        else {
            this._gl.bufferData(this._gl.UNIFORM_BUFFER, new Float32Array(elements), this._gl.STATIC_DRAW);
        }
        this.bindUniformBuffer(null);
        result.references = 1;
        return result;
    };
    ThinEngine.prototype.createDynamicUniformBuffer = function (elements, _label) {
        const ubo = this._gl.createBuffer();
        if (!ubo) {
            throw new Error("Unable to create dynamic uniform buffer");
        }
        const result = new WebGLDataBuffer(ubo);
        this.bindUniformBuffer(result);
        if (elements instanceof Float32Array) {
            this._gl.bufferData(this._gl.UNIFORM_BUFFER, elements, this._gl.DYNAMIC_DRAW);
        }
        else {
            this._gl.bufferData(this._gl.UNIFORM_BUFFER, new Float32Array(elements), this._gl.DYNAMIC_DRAW);
        }
        this.bindUniformBuffer(null);
        result.references = 1;
        return result;
    };
    ThinEngine.prototype.updateUniformBuffer = function (uniformBuffer, elements, offset, count) {
        this.bindUniformBuffer(uniformBuffer);
        if (offset === undefined) {
            offset = 0;
        }
        if (count === undefined) {
            if (elements instanceof Float32Array) {
                this._gl.bufferSubData(this._gl.UNIFORM_BUFFER, offset, elements);
            }
            else {
                this._gl.bufferSubData(this._gl.UNIFORM_BUFFER, offset, new Float32Array(elements));
            }
        }
        else {
            if (elements instanceof Float32Array) {
                this._gl.bufferSubData(this._gl.UNIFORM_BUFFER, 0, elements.subarray(offset, offset + count));
            }
            else {
                this._gl.bufferSubData(this._gl.UNIFORM_BUFFER, 0, new Float32Array(elements).subarray(offset, offset + count));
            }
        }
        this.bindUniformBuffer(null);
    };
    ThinEngine.prototype.bindUniformBuffer = function (buffer) {
        this._gl.bindBuffer(this._gl.UNIFORM_BUFFER, buffer ? buffer.underlyingResource : null);
    };
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    ThinEngine.prototype.bindUniformBufferBase = function (buffer, location, name) {
        this._gl.bindBufferBase(this._gl.UNIFORM_BUFFER, location, buffer ? buffer.underlyingResource : null);
    };
    ThinEngine.prototype.bindUniformBlock = function (pipelineContext, blockName, index) {
        const program = pipelineContext.program;
        const uniformLocation = this._gl.getUniformBlockIndex(program, blockName);
        if (uniformLocation !== 0xffffffff) {
            this._gl.uniformBlockBinding(program, uniformLocation, index);
        }
    };
}

RegisterEngineUniformBuffer();

/** This file must only contain pure code and pure imports */
let _Registered = false;
/**
 * Register side effects for abstractEngineTexture.
 * Safe to call multiple times; only the first call has an effect.
 */
function RegisterAbstractEngineTexture() {
    if (_Registered) {
        return;
    }
    _Registered = true;
    AbstractEngine.prototype.createDepthStencilTexture = function (size, options, rtWrapper) {
        if (options.isCube) {
            const width = size.width || size;
            return this._createDepthStencilCubeTexture(width, options);
        }
        else {
            return this._createDepthStencilTexture(size, options, rtWrapper);
        }
    };
}

RegisterAbstractEngineTexture();

export { Engine };
//# sourceMappingURL=engine-D2ozhGPD.esm.js.map
