import { aB as PrecisionDate, ad as AbstractEngine, aC as IsDocumentAvailable, c as EngineStore, aD as IsWindowObjectExist, C as Constants, aq as HasStencilAspect } from './index-Cl9U4nB-.esm.js';
import { _ as _GetCompatibleTextureLoader } from './textureLoaderManager-CqUNzDyY.esm.js';

/**
 * Performance monitor tracks rolling average frame-time and frame-time variance over a user defined sliding-window
 */
class PerformanceMonitor {
    /**
     * constructor
     * @param frameSampleSize The number of samples required to saturate the sliding window
     */
    constructor(frameSampleSize = 30) {
        this._enabled = true;
        this._rollingFrameTime = new RollingAverage(frameSampleSize);
    }
    /**
     * Samples current frame
     * @param timeMs A timestamp in milliseconds of the current frame to compare with other frames
     */
    sampleFrame(timeMs = PrecisionDate.Now) {
        if (!this._enabled) {
            return;
        }
        if (this._lastFrameTimeMs != null) {
            const dt = timeMs - this._lastFrameTimeMs;
            this._rollingFrameTime.add(dt);
        }
        this._lastFrameTimeMs = timeMs;
    }
    /**
     * Returns the average frame time in milliseconds over the sliding window (or the subset of frames sampled so far)
     */
    get averageFrameTime() {
        return this._rollingFrameTime.average;
    }
    /**
     * Returns the variance frame time in milliseconds over the sliding window (or the subset of frames sampled so far)
     */
    get averageFrameTimeVariance() {
        return this._rollingFrameTime.variance;
    }
    /**
     * Returns the frame time of the most recent frame
     */
    get instantaneousFrameTime() {
        return this._rollingFrameTime.history(0);
    }
    /**
     * Returns the average framerate in frames per second over the sliding window (or the subset of frames sampled so far)
     */
    get averageFPS() {
        return 1000.0 / this._rollingFrameTime.average;
    }
    /**
     * Returns the average framerate in frames per second using the most recent frame time
     */
    get instantaneousFPS() {
        const history = this._rollingFrameTime.history(0);
        if (history === 0) {
            return 0;
        }
        return 1000.0 / history;
    }
    /**
     * Returns true if enough samples have been taken to completely fill the sliding window
     */
    get isSaturated() {
        return this._rollingFrameTime.isSaturated();
    }
    /**
     * Enables contributions to the sliding window sample set
     */
    enable() {
        this._enabled = true;
    }
    /**
     * Disables contributions to the sliding window sample set
     * Samples will not be interpolated over the disabled period
     */
    disable() {
        this._enabled = false;
        //clear last sample to avoid interpolating over the disabled period when next enabled
        this._lastFrameTimeMs = null;
    }
    /**
     * Returns true if sampling is enabled
     */
    get isEnabled() {
        return this._enabled;
    }
    /**
     * Resets performance monitor
     */
    reset() {
        //clear last sample to avoid interpolating over the disabled period when next enabled
        this._lastFrameTimeMs = null;
        //wipe record
        this._rollingFrameTime.reset();
    }
}
/**
 * RollingAverage
 *
 * Utility to efficiently compute the rolling average and variance over a sliding window of samples
 */
class RollingAverage {
    /**
     * constructor
     * @param length The number of samples required to saturate the sliding window
     */
    constructor(length) {
        this._samples = new Array(length);
        this.reset();
    }
    /**
     * Adds a sample to the sample set
     * @param v The sample value
     */
    add(v) {
        //http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
        let delta;
        //we need to check if we've already wrapped round
        if (this.isSaturated()) {
            //remove bottom of stack from mean
            const bottomValue = this._samples[this._pos];
            delta = bottomValue - this.average;
            this.average -= delta / (this._sampleCount - 1);
            this._m2 -= delta * (bottomValue - this.average);
        }
        else {
            this._sampleCount++;
        }
        //add new value to mean
        delta = v - this.average;
        this.average += delta / this._sampleCount;
        this._m2 += delta * (v - this.average);
        //set the new variance
        this.variance = this._m2 / (this._sampleCount - 1);
        this._samples[this._pos] = v;
        this._pos++;
        this._pos %= this._samples.length; //positive wrap around
    }
    /**
     * Returns previously added values or null if outside of history or outside the sliding window domain
     * @param i Index in history. For example, pass 0 for the most recent value and 1 for the value before that
     * @returns Value previously recorded with add() or null if outside of range
     */
    history(i) {
        if (i >= this._sampleCount || i >= this._samples.length) {
            return 0;
        }
        const i0 = this._wrapPosition(this._pos - 1.0);
        return this._samples[this._wrapPosition(i0 - i)];
    }
    /**
     * Returns true if enough samples have been taken to completely fill the sliding window
     * @returns true if sample-set saturated
     */
    isSaturated() {
        return this._sampleCount >= this._samples.length;
    }
    /**
     * Resets the rolling average (equivalent to 0 samples taken so far)
     */
    reset() {
        this.average = 0;
        this.variance = 0;
        this._sampleCount = 0;
        this._pos = 0;
        this._m2 = 0;
    }
    /**
     * Wraps a value around the sample range boundaries
     * @param i Position in sample range, for example if the sample length is 5, and i is -3, then 2 will be returned.
     * @returns Wrapped position in sample range
     */
    _wrapPosition(i) {
        const max = this._samples.length;
        return ((i % max) + max) % max;
    }
}

/** @internal */
function DisableTouchAction(canvas) {
    if (!canvas || !canvas.setAttribute) {
        return;
    }
    canvas.setAttribute("touch-action", "none");
    canvas.style.touchAction = "none";
    canvas.style.webkitTapHighlightColor = "transparent";
}
/** @internal */
function _CommonInit(commonEngine, canvas, creationOptions) {
    commonEngine._onCanvasFocus = () => {
        commonEngine.onCanvasFocusObservable.notifyObservers(commonEngine);
    };
    commonEngine._onCanvasBlur = () => {
        commonEngine.onCanvasBlurObservable.notifyObservers(commonEngine);
    };
    commonEngine._onCanvasContextMenu = (evt) => {
        if (commonEngine.disableContextMenu) {
            evt.preventDefault();
        }
    };
    canvas.addEventListener("focus", commonEngine._onCanvasFocus);
    canvas.addEventListener("blur", commonEngine._onCanvasBlur);
    canvas.addEventListener("contextmenu", commonEngine._onCanvasContextMenu);
    commonEngine._onBlur = () => {
        if (commonEngine.disablePerformanceMonitorInBackground) {
            commonEngine.performanceMonitor.disable();
        }
        commonEngine._windowIsBackground = true;
    };
    commonEngine._onFocus = () => {
        if (commonEngine.disablePerformanceMonitorInBackground) {
            commonEngine.performanceMonitor.enable();
        }
        commonEngine._windowIsBackground = false;
    };
    commonEngine._onCanvasPointerOut = (ev) => {
        // Check that the element at the point of the pointer out isn't the canvas and if it isn't, notify observers
        // Note: This is a workaround for a bug with Safari
        if (document.elementFromPoint(ev.clientX, ev.clientY) !== canvas) {
            commonEngine.onCanvasPointerOutObservable.notifyObservers(ev);
        }
    };
    const hostWindow = commonEngine.getHostWindow(); // it calls IsWindowObjectExist()
    if (hostWindow && typeof hostWindow.addEventListener === "function") {
        hostWindow.addEventListener("blur", commonEngine._onBlur);
        hostWindow.addEventListener("focus", commonEngine._onFocus);
    }
    canvas.addEventListener("pointerout", commonEngine._onCanvasPointerOut);
    if (!creationOptions.doNotHandleTouchAction) {
        DisableTouchAction(canvas);
    }
    // Create Audio Engine if needed.
    if (!AbstractEngine.audioEngine && creationOptions.audioEngine && AbstractEngine.AudioEngineFactory) {
        AbstractEngine.audioEngine = AbstractEngine.AudioEngineFactory(commonEngine.getRenderingCanvas(), commonEngine.getAudioContext(), commonEngine.getAudioDestination());
    }
    if (IsDocumentAvailable()) {
        // Fullscreen
        commonEngine._onFullscreenChange = () => {
            commonEngine.isFullscreen = !!document.fullscreenElement;
            // Pointer lock
            if (commonEngine.isFullscreen && commonEngine._pointerLockRequested && canvas) {
                RequestPointerlock(canvas);
            }
        };
        document.addEventListener("fullscreenchange", commonEngine._onFullscreenChange, false);
        document.addEventListener("webkitfullscreenchange", commonEngine._onFullscreenChange, false);
        // Pointer lock
        commonEngine._onPointerLockChange = () => {
            commonEngine.isPointerLock = document.pointerLockElement === canvas;
        };
        document.addEventListener("pointerlockchange", commonEngine._onPointerLockChange, false);
        document.addEventListener("webkitpointerlockchange", commonEngine._onPointerLockChange, false);
    }
    commonEngine.enableOfflineSupport = AbstractEngine.OfflineProviderFactory !== undefined;
    commonEngine._deterministicLockstep = !!creationOptions.deterministicLockstep;
    commonEngine._lockstepMaxSteps = creationOptions.lockstepMaxSteps || 0;
    commonEngine._timeStep = creationOptions.timeStep || 1 / 60;
}
/** @internal */
function _CommonDispose(commonEngine, canvas) {
    // Release audio engine
    if (EngineStore.Instances.length === 1 && AbstractEngine.audioEngine) {
        AbstractEngine.audioEngine.dispose();
        AbstractEngine.audioEngine = null;
    }
    // Events
    const hostWindow = commonEngine.getHostWindow(); // it calls IsWindowObjectExist()
    if (hostWindow && typeof hostWindow.removeEventListener === "function") {
        hostWindow.removeEventListener("blur", commonEngine._onBlur);
        hostWindow.removeEventListener("focus", commonEngine._onFocus);
    }
    if (canvas) {
        canvas.removeEventListener("focus", commonEngine._onCanvasFocus);
        canvas.removeEventListener("blur", commonEngine._onCanvasBlur);
        canvas.removeEventListener("pointerout", commonEngine._onCanvasPointerOut);
        canvas.removeEventListener("contextmenu", commonEngine._onCanvasContextMenu);
    }
    if (IsDocumentAvailable()) {
        document.removeEventListener("fullscreenchange", commonEngine._onFullscreenChange);
        document.removeEventListener("mozfullscreenchange", commonEngine._onFullscreenChange);
        document.removeEventListener("webkitfullscreenchange", commonEngine._onFullscreenChange);
        document.removeEventListener("msfullscreenchange", commonEngine._onFullscreenChange);
        document.removeEventListener("pointerlockchange", commonEngine._onPointerLockChange);
        document.removeEventListener("mspointerlockchange", commonEngine._onPointerLockChange);
        document.removeEventListener("mozpointerlockchange", commonEngine._onPointerLockChange);
        document.removeEventListener("webkitpointerlockchange", commonEngine._onPointerLockChange);
    }
}
/**
 * Get Font size information
 * @param font font name
 * @returns an object containing ascent, height and descent
 */
function GetFontOffset(font) {
    const text = document.createElement("span");
    text.textContent = "Hg";
    text.style.font = font;
    const block = document.createElement("div");
    block.style.display = "inline-block";
    block.style.width = "1px";
    block.style.height = "0px";
    block.style.verticalAlign = "bottom";
    const div = document.createElement("div");
    div.style.whiteSpace = "nowrap";
    div.appendChild(text);
    div.appendChild(block);
    document.body.appendChild(div);
    let fontAscent;
    let fontHeight;
    try {
        fontHeight = block.getBoundingClientRect().top - text.getBoundingClientRect().top;
        block.style.verticalAlign = "baseline";
        fontAscent = block.getBoundingClientRect().top - text.getBoundingClientRect().top;
    }
    finally {
        document.body.removeChild(div);
    }
    return { ascent: fontAscent, height: fontHeight, descent: fontHeight - fontAscent };
}
/** @internal */
async function CreateImageBitmapFromSource(engine, imageSource, options) {
    return await new Promise((resolve, reject) => {
        const image = new Image();
        image.onload = () => {
            // eslint-disable-next-line @typescript-eslint/no-floating-promises, github/no-then
            image.decode().then(() => {
                // eslint-disable-next-line @typescript-eslint/no-floating-promises, github/no-then
                engine.createImageBitmap(image, options).then((imageBitmap) => {
                    resolve(imageBitmap);
                });
            });
        };
        image.onerror = () => {
            // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
            reject(`Error loading image ${image.src}`);
        };
        image.src = imageSource;
    });
}
/** @internal */
function ResizeImageBitmap(engine, image, bufferWidth, bufferHeight) {
    const canvas = engine.createCanvas(bufferWidth, bufferHeight);
    const context = canvas.getContext("2d");
    if (!context) {
        throw new Error("Unable to get 2d context for resizeImageBitmap");
    }
    context.drawImage(image, 0, 0);
    // Create VertexData from map data
    // Cast is due to wrong definition in lib.d.ts from ts 1.3 - https://github.com/Microsoft/TypeScript/issues/949
    const buffer = context.getImageData(0, 0, bufferWidth, bufferHeight).data;
    return buffer;
}
/**
 * Ask the browser to promote the current element to fullscreen rendering mode
 * @param element defines the DOM element to promote
 */
function RequestFullscreen(element) {
    const requestFunction = element.requestFullscreen || element.webkitRequestFullscreen;
    if (!requestFunction) {
        return;
    }
    void requestFunction.call(element);
}
/**
 * Asks the browser to exit fullscreen mode
 */
function ExitFullscreen() {
    const anyDoc = document;
    if (document.exitFullscreen) {
        // eslint-disable-next-line @typescript-eslint/no-floating-promises
        document.exitFullscreen();
    }
    else if (anyDoc.webkitCancelFullScreen) {
        anyDoc.webkitCancelFullScreen();
    }
}
/**
 * Ask the browser to promote the current element to pointerlock mode
 * @param element defines the DOM element to promote
 */
function RequestPointerlock(element) {
    if (element.requestPointerLock) {
        // In some browsers, requestPointerLock returns a promise.
        // Handle possible rejections to avoid an unhandled top-level exception.
        const promise = element.requestPointerLock();
        if (promise instanceof Promise) {
            promise
                // eslint-disable-next-line github/no-then
                .then(() => {
                element.focus();
            })
                // eslint-disable-next-line github/no-then
                .catch(() => { });
        }
        else {
            element.focus();
        }
    }
}
/**
 * Asks the browser to exit pointerlock mode
 */
function ExitPointerlock() {
    if (document.exitPointerLock) {
        document.exitPointerLock();
    }
}

AbstractEngine.prototype.displayLoadingUI = function () {
    if (!IsWindowObjectExist()) {
        return;
    }
    const loadingScreen = this.loadingScreen;
    if (loadingScreen) {
        loadingScreen.displayLoadingUI();
    }
};
AbstractEngine.prototype.hideLoadingUI = function () {
    if (!IsWindowObjectExist()) {
        return;
    }
    const loadingScreen = this._loadingScreen;
    if (loadingScreen) {
        loadingScreen.hideLoadingUI();
    }
};
Object.defineProperty(AbstractEngine.prototype, "loadingScreen", {
    get: function () {
        if (!this._loadingScreen && this._renderingCanvas) {
            this._loadingScreen = AbstractEngine.DefaultLoadingScreenFactory(this._renderingCanvas);
        }
        return this._loadingScreen;
    },
    set: function (value) {
        this._loadingScreen = value;
    },
    enumerable: true,
    configurable: true,
});
Object.defineProperty(AbstractEngine.prototype, "loadingUIText", {
    set: function (value) {
        this.loadingScreen.loadingUIText = value;
    },
    enumerable: true,
    configurable: true,
});
Object.defineProperty(AbstractEngine.prototype, "loadingUIBackgroundColor", {
    set: function (value) {
        this.loadingScreen.loadingUIBackgroundColor = value;
    },
    enumerable: true,
    configurable: true,
});

AbstractEngine.prototype.getInputElement = function () {
    return this._renderingCanvas;
};
AbstractEngine.prototype.getRenderingCanvasClientRect = function () {
    if (!this._renderingCanvas) {
        return null;
    }
    return this._renderingCanvas.getBoundingClientRect();
};
AbstractEngine.prototype.getInputElementClientRect = function () {
    if (!this._renderingCanvas) {
        return null;
    }
    return this.getInputElement().getBoundingClientRect();
};
AbstractEngine.prototype.getAspectRatio = function (viewportOwner, useScreen = false) {
    const viewport = viewportOwner.viewport;
    return (this.getRenderWidth(useScreen) * viewport.width) / (this.getRenderHeight(useScreen) * viewport.height);
};
AbstractEngine.prototype.getScreenAspectRatio = function () {
    return this.getRenderWidth(true) / this.getRenderHeight(true);
};
AbstractEngine.prototype._verifyPointerLock = function () {
    this._onPointerLockChange?.();
};

AbstractEngine.prototype.setAlphaEquation = function (equation, targetIndex = 0) {
    if (this._alphaEquation[targetIndex] === equation) {
        return;
    }
    switch (equation) {
        case Constants.ALPHA_EQUATION_ADD:
            this._alphaState.setAlphaEquationParameters(Constants.GL_ALPHA_EQUATION_ADD, Constants.GL_ALPHA_EQUATION_ADD, targetIndex);
            break;
        case Constants.ALPHA_EQUATION_SUBSTRACT:
            this._alphaState.setAlphaEquationParameters(Constants.GL_ALPHA_EQUATION_SUBTRACT, Constants.GL_ALPHA_EQUATION_SUBTRACT, targetIndex);
            break;
        case Constants.ALPHA_EQUATION_REVERSE_SUBTRACT:
            this._alphaState.setAlphaEquationParameters(Constants.GL_ALPHA_EQUATION_REVERSE_SUBTRACT, Constants.GL_ALPHA_EQUATION_REVERSE_SUBTRACT, targetIndex);
            break;
        case Constants.ALPHA_EQUATION_MAX:
            this._alphaState.setAlphaEquationParameters(Constants.GL_ALPHA_EQUATION_MAX, Constants.GL_ALPHA_EQUATION_MAX, targetIndex);
            break;
        case Constants.ALPHA_EQUATION_MIN:
            this._alphaState.setAlphaEquationParameters(Constants.GL_ALPHA_EQUATION_MIN, Constants.GL_ALPHA_EQUATION_MIN, targetIndex);
            break;
        case Constants.ALPHA_EQUATION_DARKEN:
            this._alphaState.setAlphaEquationParameters(Constants.GL_ALPHA_EQUATION_MIN, Constants.GL_ALPHA_EQUATION_ADD, targetIndex);
            break;
    }
    this._alphaEquation[targetIndex] = equation;
};

AbstractEngine.prototype.getInputElement = function () {
    return this._renderingCanvas;
};
AbstractEngine.prototype.getDepthFunction = function () {
    return this._depthCullingState.depthFunc;
};
AbstractEngine.prototype.setDepthFunction = function (depthFunc) {
    this._depthCullingState.depthFunc = depthFunc;
};
AbstractEngine.prototype.setDepthFunctionToGreater = function () {
    this.setDepthFunction(Constants.GREATER);
};
AbstractEngine.prototype.setDepthFunctionToGreaterOrEqual = function () {
    this.setDepthFunction(Constants.GEQUAL);
};
AbstractEngine.prototype.setDepthFunctionToLess = function () {
    this.setDepthFunction(Constants.LESS);
};
AbstractEngine.prototype.setDepthFunctionToLessOrEqual = function () {
    this.setDepthFunction(Constants.LEQUAL);
};
AbstractEngine.prototype.getDepthWrite = function () {
    return this._depthCullingState.depthMask;
};
AbstractEngine.prototype.setDepthWrite = function (enable) {
    this._depthCullingState.depthMask = enable;
};
AbstractEngine.prototype.setAlphaConstants = function (r, g, b, a) {
    this._alphaState.setAlphaBlendConstants(r, g, b, a);
};
AbstractEngine.prototype.getAlphaMode = function (targetIndex = 0) {
    return this._alphaMode[targetIndex];
};
AbstractEngine.prototype.getAlphaEquation = function (targetIndex = 0) {
    return this._alphaEquation[targetIndex];
};

AbstractEngine.prototype.getStencilBuffer = function () {
    return this._stencilState.stencilTest;
};
AbstractEngine.prototype.setStencilBuffer = function (enable) {
    this._stencilState.stencilTest = enable;
};
AbstractEngine.prototype.getStencilMask = function () {
    return this._stencilState.stencilMask;
};
AbstractEngine.prototype.setStencilMask = function (mask) {
    this._stencilState.stencilMask = mask;
};
AbstractEngine.prototype.getStencilFunction = function () {
    return this._stencilState.stencilFunc;
};
AbstractEngine.prototype.getStencilBackFunction = function () {
    return this._stencilState.stencilBackFunc;
};
AbstractEngine.prototype.getStencilFunctionReference = function () {
    return this._stencilState.stencilFuncRef;
};
AbstractEngine.prototype.getStencilFunctionMask = function () {
    return this._stencilState.stencilFuncMask;
};
AbstractEngine.prototype.setStencilFunction = function (stencilFunc) {
    this._stencilState.stencilFunc = stencilFunc;
};
AbstractEngine.prototype.setStencilBackFunction = function (stencilFunc) {
    this._stencilState.stencilBackFunc = stencilFunc;
};
AbstractEngine.prototype.setStencilFunctionReference = function (reference) {
    this._stencilState.stencilFuncRef = reference;
};
AbstractEngine.prototype.setStencilFunctionMask = function (mask) {
    this._stencilState.stencilFuncMask = mask;
};
AbstractEngine.prototype.getStencilOperationFail = function () {
    return this._stencilState.stencilOpStencilFail;
};
AbstractEngine.prototype.getStencilBackOperationFail = function () {
    return this._stencilState.stencilBackOpStencilFail;
};
AbstractEngine.prototype.getStencilOperationDepthFail = function () {
    return this._stencilState.stencilOpDepthFail;
};
AbstractEngine.prototype.getStencilBackOperationDepthFail = function () {
    return this._stencilState.stencilBackOpDepthFail;
};
AbstractEngine.prototype.getStencilOperationPass = function () {
    return this._stencilState.stencilOpStencilDepthPass;
};
AbstractEngine.prototype.getStencilBackOperationPass = function () {
    return this._stencilState.stencilBackOpStencilDepthPass;
};
AbstractEngine.prototype.setStencilOperationFail = function (operation) {
    this._stencilState.stencilOpStencilFail = operation;
};
AbstractEngine.prototype.setStencilBackOperationFail = function (operation) {
    this._stencilState.stencilBackOpStencilFail = operation;
};
AbstractEngine.prototype.setStencilOperationDepthFail = function (operation) {
    this._stencilState.stencilOpDepthFail = operation;
};
AbstractEngine.prototype.setStencilBackOperationDepthFail = function (operation) {
    this._stencilState.stencilBackOpDepthFail = operation;
};
AbstractEngine.prototype.setStencilOperationPass = function (operation) {
    this._stencilState.stencilOpStencilDepthPass = operation;
};
AbstractEngine.prototype.setStencilBackOperationPass = function (operation) {
    this._stencilState.stencilBackOpStencilDepthPass = operation;
};
AbstractEngine.prototype.cacheStencilState = function () {
    this._cachedStencilBuffer = this.getStencilBuffer();
    this._cachedStencilFunction = this.getStencilFunction();
    this._cachedStencilMask = this.getStencilMask();
    this._cachedStencilOperationPass = this.getStencilOperationPass();
    this._cachedStencilOperationFail = this.getStencilOperationFail();
    this._cachedStencilOperationDepthFail = this.getStencilOperationDepthFail();
    this._cachedStencilReference = this.getStencilFunctionReference();
};
AbstractEngine.prototype.restoreStencilState = function () {
    this.setStencilFunction(this._cachedStencilFunction);
    this.setStencilMask(this._cachedStencilMask);
    this.setStencilBuffer(this._cachedStencilBuffer);
    this.setStencilOperationPass(this._cachedStencilOperationPass);
    this.setStencilOperationFail(this._cachedStencilOperationFail);
    this.setStencilOperationDepthFail(this._cachedStencilOperationDepthFail);
    this.setStencilFunctionReference(this._cachedStencilReference);
};

AbstractEngine.prototype.getRenderPassNames = function () {
    return this._renderPassNames;
};
AbstractEngine.prototype.getCurrentRenderPassName = function () {
    return this._renderPassNames[this.currentRenderPassId];
};
AbstractEngine.prototype.createRenderPassId = function (name) {
    // Note: render pass id == 0 is always for the main render pass
    const id = ++AbstractEngine._RenderPassIdCounter;
    this._renderPassNames[id] = name ?? "NONAME";
    return id;
};
AbstractEngine.prototype.releaseRenderPassId = function (id) {
    this._renderPassNames[id] = undefined;
    for (let s = 0; s < this.scenes.length; ++s) {
        const scene = this.scenes[s];
        for (let m = 0; m < scene.meshes.length; ++m) {
            const mesh = scene.meshes[m];
            mesh._releaseRenderPassId(id);
            if (mesh.subMeshes) {
                for (let b = 0; b < mesh.subMeshes.length; ++b) {
                    const subMesh = mesh.subMeshes[b];
                    subMesh._removeDrawWrapper(id);
                }
            }
        }
    }
};

AbstractEngine.prototype._loadFileAsync = async function (url, offlineProvider, useArrayBuffer) {
    return await new Promise((resolve, reject) => {
        this._loadFile(url, (data) => {
            resolve(data);
        }, undefined, offlineProvider, useArrayBuffer, (request, exception) => {
            // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
            reject(exception);
        });
    });
};

AbstractEngine.GetCompatibleTextureLoader = _GetCompatibleTextureLoader;

/**
 * Wrapper around a render target (either single or multi textures)
 */
class RenderTargetWrapper {
    /**
     * Gets the depth/stencil texture
     */
    get depthStencilTexture() {
        return this._depthStencilTexture;
    }
    /**
     * Sets the depth/stencil texture
     * @param texture The depth/stencil texture to set
     * @param disposeExisting True to dispose the existing depth/stencil texture (if any) before replacing it (default: true)
     */
    setDepthStencilTexture(texture, disposeExisting = true) {
        if (disposeExisting && this._depthStencilTexture) {
            this._depthStencilTexture.dispose();
        }
        this._depthStencilTexture = texture;
        this._generateDepthBuffer = this._generateStencilBuffer = this._depthStencilTextureWithStencil = false;
        if (texture) {
            this._generateDepthBuffer = true;
            this._generateStencilBuffer = this._depthStencilTextureWithStencil = HasStencilAspect(texture.format);
        }
    }
    /**
     * Indicates if the depth/stencil texture has a stencil aspect
     */
    get depthStencilTextureWithStencil() {
        return this._depthStencilTextureWithStencil;
    }
    /**
     * Defines if the render target wrapper is for a cube texture or if false a 2d texture
     */
    get isCube() {
        return this._isCube;
    }
    /**
     * Defines if the render target wrapper is for a single or multi target render wrapper
     */
    get isMulti() {
        return this._isMulti;
    }
    /**
     * Defines if the render target wrapper is for a single or an array of textures
     */
    get is2DArray() {
        return this.layers > 0;
    }
    /**
     * Defines if the render target wrapper is for a 3D texture
     */
    get is3D() {
        return this.depth > 0;
    }
    /**
     * Gets the size of the render target wrapper (used for cubes, as width=height in this case)
     */
    get size() {
        return this.width;
    }
    /**
     * Gets the width of the render target wrapper
     */
    get width() {
        return this._size.width ?? this._size;
    }
    /**
     * Gets the height of the render target wrapper
     */
    get height() {
        return this._size.height ?? this._size;
    }
    /**
     * Gets the number of layers of the render target wrapper (only used if is2DArray is true and wrapper is not a multi render target)
     */
    get layers() {
        return this._size.layers || 0;
    }
    /**
     * Gets the depth of the render target wrapper (only used if is3D is true and wrapper is not a multi render target)
     */
    get depth() {
        return this._size.depth || 0;
    }
    /**
     * Gets the render texture. If this is a multi render target, gets the first texture
     */
    get texture() {
        return this._textures?.[0] ?? null;
    }
    /**
     * Gets the list of render textures. If we are not in a multi render target, the list will be null (use the texture getter instead)
     */
    get textures() {
        return this._textures;
    }
    /**
     * Gets the face indices that correspond to the list of render textures. If we are not in a multi render target, the list will be null
     */
    get faceIndices() {
        return this._faceIndices;
    }
    /**
     * Gets the layer indices that correspond to the list of render textures. If we are not in a multi render target, the list will be null
     */
    get layerIndices() {
        return this._layerIndices;
    }
    /**
     * Gets the base array layer of a texture in the textures array
     * This is an number that is calculated based on the layer and face indices set for this texture at that index
     * @param index The index of the texture in the textures array to get the base array layer for
     * @returns the base array layer of the texture at the given index
     */
    getBaseArrayLayer(index) {
        if (!this._textures) {
            return -1;
        }
        const texture = this._textures[index];
        const layerIndex = this._layerIndices?.[index] ?? 0;
        const faceIndex = this._faceIndices?.[index] ?? 0;
        return texture.isCube ? layerIndex * 6 + faceIndex : texture.is3D ? 0 : layerIndex;
    }
    /**
     * Gets the sample count of the render target
     */
    get samples() {
        return this._samples;
    }
    /**
     * Sets the sample count of the render target
     * @param value sample count
     * @param initializeBuffers If set to true, the engine will make an initializing call to drawBuffers (only used when isMulti=true).
     * @param force true to force calling the update sample count engine function even if the current sample count is equal to value
     * @returns the sample count that has been set
     */
    setSamples(value, initializeBuffers = true, force = false) {
        if (this.samples === value && !force) {
            return value;
        }
        const result = this._isMulti
            ? this._engine.updateMultipleRenderTargetTextureSampleCount(this, value, initializeBuffers)
            : this._engine.updateRenderTargetTextureSampleCount(this, value);
        this._samples = value;
        return result;
    }
    /**
     * Resolves the MSAA textures into their non-MSAA version.
     * Note that if samples equals 1 (no MSAA), no resolve is performed.
     */
    resolveMSAATextures() {
        if (this.isMulti) {
            this._engine.resolveMultiFramebuffer(this);
        }
        else {
            this._engine.resolveFramebuffer(this);
        }
    }
    /**
     * Generates mipmaps for each texture of the render target
     */
    generateMipMaps() {
        if (this._engine._currentRenderTarget === this) {
            if (this.isMulti) {
                this._engine.unBindMultiColorAttachmentFramebuffer(this, true);
            }
            else {
                this._engine.unBindFramebuffer(this, true);
            }
        }
        if (this.isMulti) {
            this._engine.generateMipMapsMultiFramebuffer(this);
        }
        else {
            this._engine.generateMipMapsFramebuffer(this);
        }
    }
    /**
     * Initializes the render target wrapper
     * @param isMulti true if the wrapper is a multi render target
     * @param isCube true if the wrapper should render to a cube texture
     * @param size size of the render target (width/height/layers)
     * @param engine engine used to create the render target
     * @param label defines the label to use for the wrapper (for debugging purpose only)
     */
    constructor(isMulti, isCube, size, engine, label) {
        this._textures = null;
        this._faceIndices = null;
        this._layerIndices = null;
        /** @internal */
        this._samples = 1;
        /** @internal */
        this._attachments = null;
        /** @internal */
        this._generateStencilBuffer = false;
        /** @internal */
        this._generateDepthBuffer = false;
        /** @internal */
        this._depthStencilTextureWithStencil = false;
        /**
         * Sets this property to true to disable the automatic MSAA resolve that happens when the render target wrapper is unbound (default is false)
         */
        this.disableAutomaticMSAAResolve = false;
        /**
         * Indicates if MSAA color texture(s) should be resolved when a resolve occur (either automatically by the engine or manually by the user) (default is true)
         * Note that you can trigger a MSAA resolve at any time by calling resolveMSAATextures()
         */
        this.resolveMSAAColors = true;
        /**
         * Indicates if MSAA depth texture should be resolved when a resolve occur (either automatically by the engine or manually by the user) (default is false)
         */
        this.resolveMSAADepth = false;
        /**
         * Indicates if MSAA stencil texture should be resolved when a resolve occur (either automatically by the engine or manually by the user) (default is false)
         */
        this.resolveMSAAStencil = false;
        /**
         * Indicates if the depth texture is in read-only mode (may allow some optimizations in WebGPU)
         */
        this.depthReadOnly = false;
        /**
         * Indicates if the stencil texture is in read-only mode (may allow some optimizations in WebGPU)
         */
        this.stencilReadOnly = false;
        this._isMulti = isMulti;
        this._isCube = isCube;
        this._size = size;
        this._engine = engine;
        this._depthStencilTexture = null;
        this.label = label;
    }
    /**
     * Sets the render target texture(s)
     * @param textures texture(s) to set
     */
    setTextures(textures) {
        if (Array.isArray(textures)) {
            this._textures = textures;
        }
        else if (textures) {
            this._textures = [textures];
        }
        else {
            this._textures = null;
        }
    }
    /**
     * 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) {
        if (!this._textures) {
            this._textures = [];
        }
        if (this._textures[index] === texture) {
            return;
        }
        if (this._textures[index] && disposePrevious) {
            this._textures[index].dispose();
        }
        this._textures[index] = texture;
    }
    /**
     * Sets the layer and face indices of every render target texture bound to each color attachment
     * @param layers The layers of each texture to be set
     * @param faces The faces of each texture to be set
     */
    setLayerAndFaceIndices(layers, faces) {
        this._layerIndices = layers;
        this._faceIndices = faces;
    }
    /**
     * Sets the layer and face indices of a texture in the textures array that should be bound to each color attachment
     * @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) {
        if (!this._layerIndices) {
            this._layerIndices = [];
        }
        if (!this._faceIndices) {
            this._faceIndices = [];
        }
        if (layer !== undefined && layer >= 0) {
            this._layerIndices[index] = layer;
        }
        if (face !== undefined && face >= 0) {
            this._faceIndices[index] = face;
        }
    }
    /**
     * 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 Not used anymore. "format" will be used to determine if stencil should be created
     * @param samples sample count to use when creating the texture (default: 1)
     * @param format format of the depth texture (default: Constants.TEXTUREFORMAT_DEPTH32_FLOAT)
     * @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) {
        this._depthStencilTexture?.dispose();
        this._depthStencilTextureWithStencil = generateStencil;
        this._depthStencilTextureLabel = label;
        this._depthStencilTexture = this._engine.createDepthStencilTexture(this._size, {
            bilinearFiltering,
            comparisonFunction,
            generateStencil,
            isCube: this._isCube,
            samples,
            depthTextureFormat: format,
            label,
        }, this);
        return this._depthStencilTexture;
    }
    /**
     * @deprecated Use shareDepth instead
     * @param renderTarget Destination renderTarget
     */
    _shareDepth(renderTarget) {
        this.shareDepth(renderTarget);
    }
    /**
     * Shares the depth buffer of this render target with another render target.
     * @param renderTarget Destination renderTarget
     */
    shareDepth(renderTarget) {
        if (this._depthStencilTexture) {
            if (renderTarget._depthStencilTexture) {
                renderTarget._depthStencilTexture.dispose();
            }
            renderTarget._depthStencilTexture = this._depthStencilTexture;
            renderTarget._depthStencilTextureWithStencil = this._depthStencilTextureWithStencil;
            this._depthStencilTexture.incrementReferences();
        }
    }
    /**
     * @internal
     */
    _swapAndDie(target) {
        if (this.texture) {
            this.texture._swapAndDie(target);
        }
        this._textures = null;
        this.dispose(true);
    }
    _cloneRenderTargetWrapper() {
        let rtw = null;
        if (this._isMulti) {
            const textureArray = this.textures;
            if (textureArray && textureArray.length > 0) {
                let generateDepthTexture = false;
                let textureCount = textureArray.length;
                let depthTextureFormat = -1;
                const lastTextureSource = textureArray[textureArray.length - 1]._source;
                if (lastTextureSource === 14 /* InternalTextureSource.Depth */ || lastTextureSource === 12 /* InternalTextureSource.DepthStencil */) {
                    generateDepthTexture = true;
                    depthTextureFormat = textureArray[textureArray.length - 1].format;
                    textureCount--;
                }
                const samplingModes = [];
                const types = [];
                const formats = [];
                const targetTypes = [];
                const faceIndex = [];
                const layerIndex = [];
                const layerCounts = [];
                const internalTexture2Index = {};
                for (let i = 0; i < textureCount; ++i) {
                    const texture = textureArray[i];
                    samplingModes.push(texture.samplingMode);
                    types.push(texture.type);
                    formats.push(texture.format);
                    const index = internalTexture2Index[texture.uniqueId];
                    if (index !== undefined) {
                        targetTypes.push(-1);
                        layerCounts.push(0);
                    }
                    else {
                        internalTexture2Index[texture.uniqueId] = i;
                        if (texture.is2DArray) {
                            targetTypes.push(Constants.TEXTURE_2D_ARRAY);
                            layerCounts.push(texture.depth);
                        }
                        else if (texture.isCube) {
                            targetTypes.push(Constants.TEXTURE_CUBE_MAP);
                            layerCounts.push(0);
                        } /*else if (texture.isCubeArray) {
                            targetTypes.push(Constants.TEXTURE_CUBE_MAP_ARRAY);
                            layerCounts.push(texture.depth);
                        }*/
                        else if (texture.is3D) {
                            targetTypes.push(Constants.TEXTURE_3D);
                            layerCounts.push(texture.depth);
                        }
                        else {
                            targetTypes.push(Constants.TEXTURE_2D);
                            layerCounts.push(0);
                        }
                    }
                    if (this._faceIndices) {
                        faceIndex.push(this._faceIndices[i] ?? 0);
                    }
                    if (this._layerIndices) {
                        layerIndex.push(this._layerIndices[i] ?? 0);
                    }
                }
                const optionsMRT = {
                    samplingModes,
                    generateMipMaps: textureArray[0].generateMipMaps,
                    generateDepthBuffer: this._generateDepthBuffer,
                    generateStencilBuffer: this._generateStencilBuffer,
                    generateDepthTexture,
                    depthTextureFormat,
                    types,
                    formats,
                    textureCount,
                    targetTypes,
                    faceIndex,
                    layerIndex,
                    layerCounts,
                    label: this.label,
                };
                const size = {
                    width: this.width,
                    height: this.height,
                    depth: this.depth,
                };
                rtw = this._engine.createMultipleRenderTarget(size, optionsMRT);
                for (let i = 0; i < textureCount; ++i) {
                    if (targetTypes[i] !== -1) {
                        continue;
                    }
                    const index = internalTexture2Index[textureArray[i].uniqueId];
                    rtw.setTexture(rtw.textures[index], i);
                }
            }
        }
        else {
            const options = {};
            options.generateDepthBuffer = this._generateDepthBuffer;
            options.generateMipMaps = this.texture?.generateMipMaps ?? false;
            options.generateStencilBuffer = this._generateStencilBuffer;
            options.samplingMode = this.texture?.samplingMode;
            options.type = this.texture?.type;
            options.format = this.texture?.format;
            options.noColorAttachment = !this._textures;
            options.label = this.label;
            if (this.isCube) {
                rtw = this._engine.createRenderTargetCubeTexture(this.width, options);
            }
            else {
                const size = {
                    width: this.width,
                    height: this.height,
                    layers: this.is2DArray || this.is3D ? this.texture?.depth : undefined,
                };
                rtw = this._engine.createRenderTargetTexture(size, options);
            }
            if (rtw.texture) {
                rtw.texture.isReady = true;
            }
        }
        return rtw;
    }
    _swapRenderTargetWrapper(target) {
        if (this._textures && target._textures) {
            for (let i = 0; i < this._textures.length; ++i) {
                this._textures[i]._swapAndDie(target._textures[i], false);
                target._textures[i].isReady = true;
            }
        }
        if (this._depthStencilTexture && target._depthStencilTexture) {
            this._depthStencilTexture._swapAndDie(target._depthStencilTexture);
            target._depthStencilTexture.isReady = true;
        }
        this._textures = null;
        this._depthStencilTexture = null;
    }
    /** @internal */
    _rebuild() {
        const rtw = this._cloneRenderTargetWrapper();
        if (!rtw) {
            return;
        }
        if (this._depthStencilTexture) {
            const samplingMode = this._depthStencilTexture.samplingMode;
            const format = this._depthStencilTexture.format;
            const bilinear = samplingMode === Constants.TEXTURE_BILINEAR_SAMPLINGMODE ||
                samplingMode === Constants.TEXTURE_TRILINEAR_SAMPLINGMODE ||
                samplingMode === Constants.TEXTURE_LINEAR_LINEAR_MIPNEAREST;
            rtw.createDepthStencilTexture(this._depthStencilTexture._comparisonFunction, bilinear, this._depthStencilTextureWithStencil, this._depthStencilTexture.samples, format, this._depthStencilTextureLabel);
        }
        if (this.samples > 1) {
            rtw.setSamples(this.samples);
        }
        rtw._swapRenderTargetWrapper(this);
        rtw.dispose();
    }
    /**
     * Releases the internal render textures
     */
    releaseTextures() {
        if (this._textures) {
            for (let i = 0; i < this._textures.length; ++i) {
                this._textures[i].dispose();
            }
        }
        this._textures = null;
    }
    /**
     * Disposes the whole render target wrapper
     * @param disposeOnlyFramebuffers true if only the frame buffers should be released (used for the WebGL engine). If false, all the textures will also be released
     */
    dispose(disposeOnlyFramebuffers = false) {
        if (!disposeOnlyFramebuffers) {
            this._depthStencilTexture?.dispose();
            this._depthStencilTexture = null;
            this.releaseTextures();
        }
        this._engine._releaseRenderTargetWrapper(this);
    }
}

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);
    }
};

export { CreateImageBitmapFromSource as C, ExitFullscreen as E, GetFontOffset as G, PerformanceMonitor as P, RenderTargetWrapper as R, _CommonInit as _, ResizeImageBitmap as a, RequestFullscreen as b, RequestPointerlock as c, ExitPointerlock as d, _CommonDispose as e };
//# sourceMappingURL=abstractEngine.texture-DjMsYTgb.esm.js.map
