"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module WebGL
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.RenderCommands = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_geometry_1 = require("@itwin/core-geometry");
const core_common_1 = require("@itwin/core-common");
const SurfaceParams_1 = require("../../common/internal/render/SurfaceParams");
const DrawCommand_1 = require("./DrawCommand");
const Graphic_1 = require("./Graphic");
const LayerCommands_1 = require("./LayerCommands");
const Mesh_1 = require("./Mesh");
const RenderFlags_1 = require("./RenderFlags");
/** A list of DrawCommands to be rendered, ordered by render pass.
 * @internal
 */
class RenderCommands {
    get target() { return this._target; }
    [Symbol.iterator]() {
        return this._commands[Symbol.iterator]();
    }
    get isEmpty() {
        for (const commands of this._commands)
            if (0 < commands.length)
                return false;
        return true;
    }
    get isDrawingLayers() {
        switch (this._forcedRenderPass) {
            case 1 /* RenderPass.OpaqueLayers */:
            case 7 /* RenderPass.TranslucentLayers */:
            case 11 /* RenderPass.OverlayLayers */:
                return true;
            default:
                return false;
        }
    }
    get currentViewFlags() { return this._stack.top.viewFlags; }
    get compositeFlags() {
        let flags = 0 /* CompositeFlags.None */;
        if (this.hasCommands(8 /* RenderPass.Translucent */))
            flags |= 1 /* CompositeFlags.Translucent */;
        if (this.hasCommands(10 /* RenderPass.Hilite */) || this.hasCommands(16 /* RenderPass.HiliteClassification */) || this.hasCommands(18 /* RenderPass.HilitePlanarClassification */))
            flags |= 2 /* CompositeFlags.Hilite */;
        if (this.target.wantAmbientOcclusion)
            flags |= 4 /* CompositeFlags.AmbientOcclusion */;
        return flags;
    }
    get _curBatch() { return this._batchState.currentBatch; }
    hasCommands(pass) { return 0 !== this.getCommands(pass).length; }
    isOpaquePass(pass) { return pass >= 2 /* RenderPass.OpaqueLinear */ && pass <= 5 /* RenderPass.OpaqueGeneral */; }
    constructor(target, stack, batchState) {
        this._scratchFrustum = new core_common_1.Frustum();
        this._scratchRange = new core_geometry_1.Range3d();
        this._commands = new Array(21 /* RenderPass.COUNT */);
        this._forcedRenderPass = 255 /* RenderPass.None */;
        this._addLayersAsNormalGraphics = false;
        this._opaqueOverrides = false;
        this._translucentOverrides = false;
        this._addTranslucentAsOpaque = false; // true when rendering for _ReadPixels to force translucent items to be drawn in opaque pass.
        this._target = target;
        this._stack = stack;
        this._batchState = batchState;
        this._layers = new LayerCommands_1.LayerCommandLists(this);
        for (let i = 0; i < 21 /* RenderPass.COUNT */; ++i)
            this._commands[i] = [];
    }
    reset(target, stack, batchState) {
        this._target = target;
        this._stack = stack;
        this._batchState = batchState;
        this.clear();
    }
    collectGraphicsForPlanarProjection(scene) {
        (0, core_bentley_1.assert)(this._forcedRenderPass === 255 /* RenderPass.None */);
        (0, core_bentley_1.assert)(!this._addLayersAsNormalGraphics);
        this._addLayersAsNormalGraphics = true;
        this.addGraphics(scene);
        this._addLayersAsNormalGraphics = false;
    }
    addGraphics(scene, forcedPass = 255 /* RenderPass.None */) {
        this._forcedRenderPass = forcedPass;
        scene.forEach((entry) => entry.addCommands(this));
        this._forcedRenderPass = 255 /* RenderPass.None */;
    }
    /** Add backgroundMap graphics to their own render pass. */
    addBackgroundMapGraphics(backgroundMapGraphics) {
        this._forcedRenderPass = 15 /* RenderPass.BackgroundMap */;
        backgroundMapGraphics.forEach((entry) => entry.addCommands(this));
        this._forcedRenderPass = 255 /* RenderPass.None */;
    }
    /** Add overlay graphics to the world overlay pass */
    addOverlayGraphics(overlayGraphics) {
        this._forcedRenderPass = 12 /* RenderPass.WorldOverlay */;
        overlayGraphics.forEach((entry) => entry.addCommands(this));
        this._forcedRenderPass = 255 /* RenderPass.None */;
    }
    addDecorations(dec, forcedPass = 255 /* RenderPass.None */) {
        this._forcedRenderPass = forcedPass;
        for (const entry of dec) {
            entry.addCommands(this);
        }
        this._forcedRenderPass = 255 /* RenderPass.None */;
    }
    addWorldDecorations(decs) {
        const world = this.target.getWorldDecorations(decs);
        this.pushAndPopBranch(world, () => {
            for (const entry of world.branch.entries) {
                entry.addCommands(this);
            }
        });
    }
    addPickableDecorations(decs) {
        if (undefined !== decs.normal) {
            for (const normal of decs.normal) {
                const gf = normal;
                if (gf.isPickable)
                    gf.addCommands(this);
            }
        }
        if (undefined !== decs.world) {
            const world = this.target.getWorldDecorations(decs.world);
            this.pushAndPopBranch(world, () => {
                for (const gf of world.branch.entries) {
                    if (gf.isPickable)
                        gf.addCommands(this);
                }
            });
        }
    }
    addBackground(gf) {
        if (undefined === gf)
            return;
        (0, core_bentley_1.assert)(255 /* RenderPass.None */ === this._forcedRenderPass);
        this._forcedRenderPass = 0 /* RenderPass.Background */;
        this.pushAndPopState(this.target.decorationsState, () => gf.addCommands(this));
        this._forcedRenderPass = 255 /* RenderPass.None */;
    }
    addSkyBox(gf) {
        if (undefined === gf)
            return;
        (0, core_bentley_1.assert)(255 /* RenderPass.None */ === this._forcedRenderPass);
        this._forcedRenderPass = 14 /* RenderPass.SkyBox */;
        this.pushAndPopState(this.target.decorationsState, () => gf.addCommands(this));
        this._forcedRenderPass = 255 /* RenderPass.None */;
    }
    addPrimitiveCommand(command, pass) {
        if (undefined === pass)
            pass = command.getPass(this.target);
        if ("none" === pass) // Edges will return none if they don't want to draw at all (edges not turned on).
            return;
        if (255 /* RenderPass.None */ !== this._forcedRenderPass) {
            // Add the command to the forced render pass (background).
            this.getCommands(this._forcedRenderPass).push(command);
            return;
        }
        if (!command.hasFeatures) {
            // Draw in general opaque pass so they are not in pick data.
            switch (pass) {
                case "opaque-linear":
                case "opaque-planar":
                    pass = "opaque";
                    break;
                case "opaque-planar-translucent":
                    pass = "opaque-translucent";
                    break;
            }
        }
        const haveFeatureOverrides = (this._opaqueOverrides || this._translucentOverrides) && command.opcode && command.hasFeatures;
        if (RenderFlags_1.Pass.rendersTranslucent(pass) && this._addTranslucentAsOpaque) {
            switch (command.renderOrder) {
                case 12 /* RenderOrder.PlanarLitSurface */:
                case 11 /* RenderOrder.PlanarUnlitSurface */:
                case 2 /* RenderOrder.BlankingRegion */:
                    pass = "opaque-planar";
                    break;
                case 4 /* RenderOrder.LitSurface */:
                case 3 /* RenderOrder.UnlitSurface */:
                    pass = "opaque";
                    break;
                default:
                    pass = "opaque-linear";
                    break;
            }
        }
        const isDoublePass = RenderFlags_1.Pass.rendersOpaqueAndTranslucent(pass);
        const renderTranslucentDuringOpaque = isDoublePass || (this._opaqueOverrides && haveFeatureOverrides);
        if (renderTranslucentDuringOpaque && RenderFlags_1.Pass.rendersTranslucent(pass) && !command.primitive.cachedGeometry.alwaysRenderTranslucent) {
            let opaquePass;
            if (RenderFlags_1.Pass.rendersOpaqueAndTranslucent(pass)) {
                opaquePass = RenderFlags_1.Pass.toOpaquePass(pass);
            }
            else {
                switch (command.renderOrder) {
                    case 12 /* RenderOrder.PlanarLitSurface */:
                    case 11 /* RenderOrder.PlanarUnlitSurface */:
                    case 2 /* RenderOrder.BlankingRegion */:
                        opaquePass = 3 /* RenderPass.OpaquePlanar */;
                        break;
                    case 4 /* RenderOrder.LitSurface */:
                    case 3 /* RenderOrder.UnlitSurface */:
                        opaquePass = 5 /* RenderPass.OpaqueGeneral */;
                        break;
                    default:
                        opaquePass = 2 /* RenderPass.OpaqueLinear */;
                        break;
                }
            }
            this.getCommands(opaquePass).push(command);
        }
        const renderOpaqueDuringTranslucent = isDoublePass || (this._translucentOverrides && haveFeatureOverrides);
        if (renderOpaqueDuringTranslucent && RenderFlags_1.Pass.rendersOpaque(pass) && !this._addTranslucentAsOpaque)
            this.getCommands(8 /* RenderPass.Translucent */).push(command);
        if (!RenderFlags_1.Pass.rendersOpaqueAndTranslucent(pass))
            this.getCommands(RenderFlags_1.Pass.toRenderPass(pass)).push(command);
    }
    getCommands(pass) {
        let idx = pass;
        (0, core_bentley_1.assert)(idx < this._commands.length);
        if (idx >= this._commands.length)
            idx -= 1;
        return this._commands[idx];
    }
    replaceCommands(pass, cmds) {
        const idx = pass;
        this._commands[idx].splice(0);
        this._commands[idx] = cmds;
    }
    addHiliteBranch(branch, pass) {
        this.pushAndPopBranchForPass(pass, branch, () => {
            branch.branch.entries.forEach((entry) => entry.addHiliteCommands(this, pass));
        });
    }
    processLayers(container) {
        (0, core_bentley_1.assert)(255 /* RenderPass.None */ === this._forcedRenderPass);
        if (255 /* RenderPass.None */ !== this._forcedRenderPass)
            return;
        this._forcedRenderPass = container.renderPass;
        this._layers.processLayers(container, () => container.graphic.addCommands(this));
        this._forcedRenderPass = 255 /* RenderPass.None */;
    }
    addLayerCommands(layer) {
        if (this._addLayersAsNormalGraphics) {
            // GraphicsCollectorDrawArgs wants to collect graphics to project to a plane for masking.
            // It bypasses PlanProjectionTreeReference.createDrawArgs which would otherwise wrap the graphics in a LayerContainer.
            (0, core_bentley_1.assert)(this._forcedRenderPass === 255 /* RenderPass.None */);
            this._forcedRenderPass = 5 /* RenderPass.OpaqueGeneral */;
            layer.graphic.addCommands(this);
            this._forcedRenderPass = 255 /* RenderPass.None */;
            return;
        }
        (0, core_bentley_1.assert)(this.isDrawingLayers);
        if (!this.isDrawingLayers)
            return;
        // Let the graphic add its commands. Afterward, pull them out and add them to the LayerCommands.
        this._layers.currentLayer = layer;
        layer.graphic.addCommands(this);
        const cmds = this.getCommands(this._forcedRenderPass);
        this._layers.addCommands(cmds);
        cmds.length = 0;
        this._layers.currentLayer = undefined;
    }
    addHiliteLayerCommands(graphic, pass) {
        (0, core_bentley_1.assert)(this.isDrawingLayers || this._addLayersAsNormalGraphics);
        if (!this.isDrawingLayers && !this._addLayersAsNormalGraphics)
            return;
        const prevPass = this._forcedRenderPass;
        this._forcedRenderPass = 255 /* RenderPass.None */;
        graphic.addHiliteCommands(this, pass);
        this._forcedRenderPass = prevPass;
    }
    getAnimationBranchState(branch) {
        const animId = branch.branch.animationId;
        return undefined !== animId ? this.target.animationBranches?.branchStates.get(animId) : undefined;
    }
    pushAndPopBranchForPass(pass, branch, func) {
        (0, core_bentley_1.assert)(!this.isDrawingLayers);
        const animState = this.getAnimationBranchState(branch);
        if (animState?.omit)
            return;
        (0, core_bentley_1.assert)(255 /* RenderPass.None */ !== pass);
        this._stack.pushBranch(branch);
        if (branch.planarClassifier)
            branch.planarClassifier.pushBatchState(this._batchState);
        if (branch.secondaryClassifiers)
            branch.secondaryClassifiers.forEach((classifier) => classifier.pushBatchState(this._batchState));
        const cmds = this.getCommands(pass);
        const clip = animState?.clip;
        const pushClip = undefined !== clip ? new DrawCommand_1.PushClipCommand(clip) : undefined;
        if (pushClip)
            cmds.push(pushClip);
        const push = new DrawCommand_1.PushBranchCommand(branch);
        cmds.push(push);
        func();
        this._stack.pop();
        if (cmds[cmds.length - 1] === push) {
            cmds.pop();
            if (pushClip)
                cmds.pop();
        }
        else {
            cmds.push(DrawCommand_1.PopBranchCommand.instance);
            if (pushClip)
                cmds.push(DrawCommand_1.PopClipCommand.instance);
        }
    }
    pushAndPop(push, pop, func) {
        if (this.isDrawingLayers) {
            this._commands[10 /* RenderPass.Hilite */].push(push);
            this._layers.pushAndPop(push, pop, func);
            const cmds = this._commands[10 /* RenderPass.Hilite */];
            if (0 < cmds.length && cmds[cmds.length - 1] === push)
                cmds.pop();
            else
                cmds.push(pop);
            return;
        }
        if (255 /* RenderPass.None */ === this._forcedRenderPass) {
            // Need to make sure the push command precedes any subsequent commands added to any render pass.
            for (const cmds of this._commands)
                cmds.push(push);
        }
        else {
            // May want to add hilite commands as well - add the push command to that pass.
            this._commands[this._forcedRenderPass].push(push);
            this._commands[10 /* RenderPass.Hilite */].push(push);
        }
        func();
        // Remove push command from any passes that didn't receive any commands; add the pop command to any passes that did.
        if (255 /* RenderPass.None */ === this._forcedRenderPass) {
            for (const cmds of this._commands) {
                (0, core_bentley_1.assert)(0 < cmds.length);
                if (0 < cmds.length && cmds[cmds.length - 1] === push)
                    cmds.pop();
                else
                    cmds.push(pop);
            }
        }
        else {
            (0, core_bentley_1.assert)(0 < this._commands[this._forcedRenderPass].length);
            (0, core_bentley_1.assert)(0 < this._commands[10 /* RenderPass.Hilite */].length);
            let cmds = this._commands[this._forcedRenderPass];
            if (cmds[cmds.length - 1] === push)
                cmds.pop();
            else
                cmds.push(pop);
            cmds = this._commands[10 /* RenderPass.Hilite */];
            if (cmds[cmds.length - 1] === push)
                cmds.pop();
            else
                cmds.push(pop);
        }
    }
    pushAndPopBranch(branch, func) {
        const animState = this.getAnimationBranchState(branch);
        if (animState?.omit)
            return;
        if (animState?.clip)
            this.pushAndPop(new DrawCommand_1.PushClipCommand(animState.clip), DrawCommand_1.PopClipCommand.instance, () => this._pushAndPopBranch(branch, func));
        else
            this._pushAndPopBranch(branch, func);
    }
    _pushAndPopBranch(branch, func) {
        this._stack.pushBranch(branch);
        if (branch.planarClassifier)
            branch.planarClassifier.pushBatchState(this._batchState);
        if (branch.secondaryClassifiers)
            branch.secondaryClassifiers.forEach((classifier) => classifier.pushBatchState(this._batchState));
        this.pushAndPop(new DrawCommand_1.PushBranchCommand(branch), DrawCommand_1.PopBranchCommand.instance, func);
        this._stack.pop();
    }
    pushAndPopState(state, func) {
        this._stack.pushState(state);
        this.pushAndPop(new DrawCommand_1.PushStateCommand(state), DrawCommand_1.PopBranchCommand.instance, func);
        this._stack.pop();
    }
    clear() {
        (0, core_bentley_1.assert)(this._batchState.isEmpty);
        this._clearCommands();
    }
    _clearCommands() {
        this._commands.forEach((cmds) => cmds.splice(0));
        this._layers.clear();
    }
    initForPickOverlayDecorations(overlays) {
        for (const overlay of overlays) {
            const gf = overlay;
            if (gf.isPickable)
                gf.addCommands(this);
        }
    }
    initForPickOverlays(sceneOverlays, worldOverlayDecorations, viewOverlayDecorations) {
        this._clearCommands();
        this._addTranslucentAsOpaque = true;
        for (const sceneGf of sceneOverlays)
            sceneGf.addCommands(this);
        if (worldOverlayDecorations?.length) {
            this.pushAndPopState(this.target.decorationsState, () => {
                this.initForPickOverlayDecorations(worldOverlayDecorations);
            });
        }
        if (viewOverlayDecorations?.length) {
            this.pushAndPopState(this.target.decorationsState.withViewCoords(), () => {
                this.initForPickOverlayDecorations(viewOverlayDecorations);
            });
        }
        this._addTranslucentAsOpaque = false;
    }
    initForReadPixels(gfx) {
        this.clear();
        // Set flag to force translucent geometry to be put into the opaque pass.
        this._addTranslucentAsOpaque = true;
        // Add the scene graphics.
        this.addGraphics(gfx.foreground);
        // Also add any pickable decorations.
        if (undefined !== gfx.decorations)
            this.addPickableDecorations(gfx.decorations);
        // Also background map is pickable
        this.addBackgroundMapGraphics(gfx.background);
        this._addTranslucentAsOpaque = false;
        this.setupClassificationByVolume();
        this._layers.outputCommands();
    }
    initForRender(gfx) {
        this.clear();
        this.addGraphics(gfx.foreground);
        this.addBackgroundMapGraphics(gfx.background);
        this.addOverlayGraphics(gfx.overlays);
        const dynamics = gfx.dynamics;
        if (dynamics && dynamics.length > 0)
            this.addDecorations(dynamics);
        const dec = gfx.decorations;
        if (undefined !== dec) {
            this.addBackground(dec.viewBackground);
            this.addSkyBox(dec.skyBox);
            if (undefined !== dec.normal && 0 < dec.normal.length)
                this.addGraphics(dec.normal);
            if (undefined !== dec.world && 0 < dec.world.length)
                this.addWorldDecorations(dec.world);
            this.pushAndPopState(this.target.decorationsState, () => {
                if (undefined !== dec.viewOverlay && 0 < dec.viewOverlay.length)
                    this.addDecorations(dec.viewOverlay, 13 /* RenderPass.ViewOverlay */);
                if (undefined !== dec.worldOverlay && 0 < dec.worldOverlay.length)
                    this.addDecorations(dec.worldOverlay, 12 /* RenderPass.WorldOverlay */);
            });
        }
        this.setupClassificationByVolume();
        this._layers.outputCommands();
    }
    addPrimitive(prim) {
        // ###TODO Would be nice if we could detect outside active volume here, but active volume only applies to specific render passes
        // if (this.target.isGeometryOutsideActiveVolume(prim.cachedGeometry))
        //   return;
        if (undefined !== this._frustumPlanes) { // See if we can cull this primitive.
            if ("classification" === prim.getPass(this.target)) {
                const geom = prim.cachedGeometry;
                geom.computeRange(this._scratchRange);
                let frustum = core_common_1.Frustum.fromRange(this._scratchRange, this._scratchFrustum);
                frustum = frustum.transformBy(this.target.currentTransform, frustum);
                if (core_common_1.FrustumPlanes.Containment.Outside === this._frustumPlanes.computeFrustumContainment(frustum)) {
                    return;
                }
            }
        }
        const command = new DrawCommand_1.PrimitiveCommand(prim);
        this.addPrimitiveCommand(command);
        if (255 /* RenderPass.None */ === this._forcedRenderPass && prim.isEdge) {
            const vf = this.target.currentViewFlags;
            if (vf.renderMode !== core_common_1.RenderMode.Wireframe && vf.hiddenEdges)
                this.getCommands(9 /* RenderPass.HiddenEdge */).push(command);
        }
    }
    addBranch(branch) {
        this.pushAndPopBranch(branch, () => {
            branch.branch.entries.forEach((entry) => entry.addCommands(this));
        });
    }
    computeBatchHiliteRenderPass(batch) {
        let pass = 10 /* RenderPass.Hilite */;
        if (batch.graphic instanceof Mesh_1.MeshGraphic) {
            const mg = batch.graphic;
            if (SurfaceParams_1.SurfaceType.VolumeClassifier === mg.surfaceType)
                pass = 16 /* RenderPass.HiliteClassification */;
        }
        else if (batch.graphic instanceof Graphic_1.GraphicsArray) {
            const ga = batch.graphic;
            if (ga.graphics[0] instanceof Mesh_1.MeshGraphic) {
                const mg = ga.graphics[0];
                if (SurfaceParams_1.SurfaceType.VolumeClassifier === mg.surfaceType)
                    pass = 16 /* RenderPass.HiliteClassification */;
            }
            else if (ga.graphics[0] instanceof Graphic_1.Branch) {
                const b = ga.graphics[0];
                if (b.branch.entries.length > 0 && b.branch.entries[0] instanceof Mesh_1.MeshGraphic) {
                    const mg = b.branch.entries[0];
                    if (SurfaceParams_1.SurfaceType.VolumeClassifier === mg.surfaceType)
                        pass = 16 /* RenderPass.HiliteClassification */;
                }
            }
        }
        return pass;
    }
    addBatch(batch) {
        if (batch.locateOnly && !this.target.isReadPixelsInProgress)
            return;
        // Batches (aka element tiles) should only draw during ordinary (translucent or opaque) passes.
        // They may draw during both, or neither.
        // NB: This is no longer true - pickable overlay decorations are defined as Batches. Problem?
        // assert(RenderPass.None === this._forcedRenderPass);
        (0, core_bentley_1.assert)(!this._opaqueOverrides && !this._translucentOverrides);
        (0, core_bentley_1.assert)(undefined === this._curBatch);
        // If all features are overridden to be invisible, draw no graphics in this batch
        const overrides = batch.getOverrides(this.target);
        if (overrides.allHidden)
            return;
        if (!batch.range.isNull) {
            // ###TODO Would be nice if we could detect outside active volume here, but active volume only applies to specific render passes
            // if (this.target.isRangeOutsideActiveVolume(batch.range))
            //   return;
            if (undefined !== this._frustumPlanes) {
                let frustum = core_common_1.Frustum.fromRange(batch.range, this._scratchFrustum);
                frustum = frustum.transformBy(this.target.currentTransform, frustum);
                if (core_common_1.FrustumPlanes.Containment.Outside === this._frustumPlanes.computeFrustumContainment(frustum)) {
                    return;
                }
            }
        }
        const classifier = this._stack.top.planarClassifier;
        this._batchState.push(batch, true);
        this.pushAndPop(new DrawCommand_1.PushBatchCommand(batch), DrawCommand_1.PopBatchCommand.instance, () => {
            if (this.currentViewFlags.transparency || overrides.anyViewIndependentTranslucent) {
                this._opaqueOverrides = overrides.anyOpaque;
                this._translucentOverrides = overrides.anyTranslucent;
                if (undefined !== classifier) {
                    this._opaqueOverrides = this._opaqueOverrides || classifier.anyOpaque;
                    this._translucentOverrides = this._translucentOverrides || classifier.anyTranslucent;
                }
            }
            // If we have an active volume classifier then force all batches for the reality data being classified into a special render pass.
            let savedForcedRenderPass = 255 /* RenderPass.None */;
            if (undefined !== this.target.activeVolumeClassifierModelId && batch.featureTable.batchModelId === this.target.activeVolumeClassifierModelId) {
                savedForcedRenderPass = this._forcedRenderPass;
                this._forcedRenderPass = 20 /* RenderPass.VolumeClassifiedRealityData */;
            }
            batch.graphic.addCommands(this);
            if (20 /* RenderPass.VolumeClassifiedRealityData */ === this._forcedRenderPass)
                this._forcedRenderPass = savedForcedRenderPass;
            // If the batch contains hilited features, need to render them in the hilite pass
            const anyHilited = overrides.anyHilited;
            const planarClassifierHilited = undefined !== classifier && classifier.anyHilited;
            if (anyHilited || planarClassifierHilited)
                batch.graphic.addHiliteCommands(this, planarClassifierHilited ? 18 /* RenderPass.HilitePlanarClassification */ : this.computeBatchHiliteRenderPass(batch));
        });
        this._opaqueOverrides = this._translucentOverrides = false;
        this._batchState.pop();
    }
    // Define a culling frustum. Commands associated with Graphics whose ranges do not intersect the frustum will be skipped.
    setCheckRange(frustum) { this._frustumPlanes = core_common_1.FrustumPlanes.fromFrustum(frustum); }
    // Clear the culling frustum.
    clearCheckRange() { this._frustumPlanes = undefined; }
    setupClassificationByVolume() {
        // To make it easier to process the classifiers individually, set up a secondary command list for them where they
        // are each separated by their own pushes & pops so that they can easily be drawn individually.  This now supports
        // nested branches and batches.
        const groupedCmds = this._commands[6 /* RenderPass.Classification */];
        const byIndexCmds = this._commands[17 /* RenderPass.ClassificationByIndex */];
        const pushCommands = []; // will contain current set of pushes ahead of a primitive
        for (const cmd of groupedCmds) {
            switch (cmd.opcode) {
                case "pushBranch":
                case "pushBatch":
                case "pushState":
                    pushCommands.push(cmd);
                    break;
                case "drawPrimitive":
                    for (const pushCmd of pushCommands) {
                        byIndexCmds.push(pushCmd);
                    }
                    byIndexCmds.push(cmd);
                    for (let i = pushCommands.length - 1; i >= 0; --i) {
                        if ("pushBatch" === pushCommands[i].opcode)
                            byIndexCmds.push(DrawCommand_1.PopBatchCommand.instance);
                        else // should be eith pushBranch or pushState opcode
                            byIndexCmds.push(DrawCommand_1.PopBranchCommand.instance);
                    }
                    break;
                case "popBatch":
                case "popBranch":
                    pushCommands.pop();
                    break;
            }
        }
    }
    dump() {
        const dump = [
            { name: "Primitives", count: 0 },
            { name: "Batches", count: 0 },
            { name: "Branches", count: 0 },
        ];
        for (const cmds of this._commands) {
            for (const cmd of cmds) {
                let index;
                switch (cmd.opcode) {
                    case "drawPrimitive":
                        index = 0;
                        break;
                    case "pushBatch":
                        index = 1;
                        break;
                    case "pushBranch":
                        index = 2;
                        break;
                    default:
                        continue;
                }
                dump[index].count++;
            }
        }
        return dump;
    }
}
exports.RenderCommands = RenderCommands;
//# sourceMappingURL=RenderCommands.js.map