"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlanarClassifier = exports.PlanarClassifierContent = void 0;
/** @packageDocumentation
 * @module WebGL
 */
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const core_geometry_1 = require("@itwin/core-geometry");
const internal_1 = require("../../tile/internal");
const RenderPlanarClassifier_1 = require("../RenderPlanarClassifier");
const BatchState_1 = require("./BatchState");
const BranchStack_1 = require("./BranchStack");
const CachedGeometry_1 = require("./CachedGeometry");
const FrameBuffer_1 = require("./FrameBuffer");
const GL_1 = require("./GL");
const Graphic_1 = require("./Graphic");
const PlanarTextureProjection_1 = require("./PlanarTextureProjection");
const RenderCommands_1 = require("./RenderCommands");
const RenderState_1 = require("./RenderState");
const ScratchDrawParams_1 = require("./ScratchDrawParams");
const System_1 = require("./System");
const Texture_1 = require("./Texture");
var PlanarClassifierContent;
(function (PlanarClassifierContent) {
    PlanarClassifierContent[PlanarClassifierContent["None"] = 0] = "None";
    PlanarClassifierContent[PlanarClassifierContent["MaskOnly"] = 1] = "MaskOnly";
    PlanarClassifierContent[PlanarClassifierContent["ClassifierOnly"] = 2] = "ClassifierOnly";
    PlanarClassifierContent[PlanarClassifierContent["ClassifierAndMask"] = 3] = "ClassifierAndMask";
})(PlanarClassifierContent || (exports.PlanarClassifierContent = PlanarClassifierContent = {}));
function createTexture(handle) {
    return new Texture_1.Texture({
        handle,
        ownership: "external",
        type: core_common_1.RenderTexture.Type.TileSection,
        transparency: core_common_1.TextureTransparency.Opaque,
    });
}
function createTextureHandle(width, height, heightMult = 1.0) {
    return Texture_1.TextureHandle.createForAttachment(width, height * heightMult, GL_1.GL.Texture.Format.Rgba, GL_1.GL.Texture.DataType.UnsignedByte);
}
class ClassifierTextures {
    constructor(color, feature, hilite) {
        this.color = color;
        this.feature = feature;
        this.hilite = hilite;
    }
    get isDisposed() {
        return this.color.isDisposed
            && this.feature.isDisposed
            && this.hilite.isDisposed;
    }
    dispose() {
        (0, core_bentley_1.dispose)(this.color);
        (0, core_bentley_1.dispose)(this.feature);
        (0, core_bentley_1.dispose)(this.hilite);
    }
    collectStatistics(stats) {
        stats.addPlanarClassifier(this.color.bytesUsed);
        stats.addPlanarClassifier(this.feature.bytesUsed);
        stats.addPlanarClassifier(this.hilite.bytesUsed);
    }
    static create(width, height) {
        const hColor = createTextureHandle(width, height);
        const hFeature = createTextureHandle(width, height);
        const hHilite = createTextureHandle(width, height);
        if (!hColor || !hFeature || !hHilite)
            return undefined;
        const color = createTexture(hColor);
        const feature = createTexture(hFeature);
        const hilite = createTexture(hHilite);
        if (!color || !feature || !hilite)
            return undefined;
        return new ClassifierTextures(color, feature, hilite);
    }
}
class ClassifierFrameBuffers {
    constructor(textures, _hilite, _fbo, _clearGeom) {
        this.textures = textures;
        this._hilite = _hilite;
        this._fbo = _fbo;
        this._clearGeom = _clearGeom;
    }
    get isDisposed() {
        return this.textures.isDisposed && this._hilite.isDisposed && this._fbo.isDisposed && this._clearGeom.isDisposed;
    }
    dispose() {
        (0, core_bentley_1.dispose)(this._fbo);
        (0, core_bentley_1.dispose)(this._clearGeom);
        (0, core_bentley_1.dispose)(this.textures);
        (0, core_bentley_1.dispose)(this._hilite);
    }
    draw(cmds, target) {
        System_1.System.instance.frameBufferStack.execute(this._fbo, true, false, () => {
            target.techniques.draw((0, ScratchDrawParams_1.getDrawParams)(target, this._clearGeom));
            target.techniques.execute(target, cmds, 19 /* RenderPass.PlanarClassification */);
        });
    }
    drawHilite(cmds, target) {
        const system = System_1.System.instance;
        const gl = system.context;
        system.frameBufferStack.execute(this._hilite, true, false, () => {
            gl.clearColor(0, 0, 0, 0);
            gl.clear(GL_1.GL.BufferBit.Color);
            target.techniques.execute(target, cmds, 10 /* RenderPass.Hilite */);
        });
    }
    static create(width, height) {
        const textures = ClassifierTextures.create(width, height);
        if (undefined === textures)
            return undefined;
        const hiliteFbo = FrameBuffer_1.FrameBuffer.create([textures.hilite.texture]);
        if (undefined === hiliteFbo)
            return undefined;
        const fbo = FrameBuffer_1.FrameBuffer.create([textures.color.texture, textures.feature.texture]);
        if (undefined === fbo)
            return undefined;
        const geom = CachedGeometry_1.ViewportQuadGeometry.create(21 /* TechniqueId.ClearPickAndColor */);
        return undefined !== geom ? new this(textures, hiliteFbo, fbo, geom) : undefined;
    }
}
class SingleTextureFrameBuffer {
    get isDisposed() { return this.texture.isDisposed && this.fbo.isDisposed; }
    collectStatistics(stats) { stats.addPlanarClassifier(this.texture.bytesUsed); }
    constructor(textureAndFbo) {
        this.texture = textureAndFbo.texture;
        this.fbo = textureAndFbo.fbo;
    }
    dispose() {
        (0, core_bentley_1.dispose)(this.texture);
        (0, core_bentley_1.dispose)(this.fbo);
    }
    static createTextureAndFrameBuffer(width, height) {
        const hTexture = Texture_1.TextureHandle.createForAttachment(width, height, GL_1.GL.Texture.Format.Rgba, GL_1.GL.Texture.DataType.UnsignedByte);
        if (!hTexture)
            return undefined;
        const texture = new Texture_1.Texture({ type: core_common_1.RenderTexture.Type.TileSection, ownership: "external", handle: hTexture, transparency: core_common_1.TextureTransparency.Opaque });
        if (!texture)
            return undefined;
        const fbo = FrameBuffer_1.FrameBuffer.create([texture.texture]);
        if (undefined === fbo)
            return undefined;
        return { texture, fbo };
    }
}
class MaskFrameBuffer extends SingleTextureFrameBuffer {
    static create(width, height) {
        const textureFbo = SingleTextureFrameBuffer.createTextureAndFrameBuffer(width, height);
        return undefined === textureFbo ? undefined : new MaskFrameBuffer(textureFbo);
    }
    draw(cmds, target) {
        const system = System_1.System.instance;
        const gl = system.context;
        system.frameBufferStack.execute(this.fbo, true, false, () => {
            gl.clearColor(0, 0, 0, 0);
            gl.clear(GL_1.GL.BufferBit.Color);
            target.techniques.execute(target, cmds, 19 /* RenderPass.PlanarClassification */);
        });
    }
}
class CombineTexturesFrameBuffer extends SingleTextureFrameBuffer {
    constructor(textureAndFbo, _combineGeom, _width, _height, _heightMult) {
        super(textureAndFbo);
        this._combineGeom = _combineGeom;
        this._width = _width;
        this._height = _height;
        this._heightMult = _heightMult;
    }
    compose(target) {
        const system = System_1.System.instance;
        const gl = system.context;
        system.context.viewport(0, 0, this._width, this._heightMult * this._height);
        system.frameBufferStack.execute(this.fbo, true, false, () => {
            gl.clearColor(0, 0, 0, 0);
            gl.clear(GL_1.GL.BufferBit.Color);
            target.techniques.draw((0, ScratchDrawParams_1.getDrawParams)(target, this._combineGeom));
        });
    }
}
class ClassifierCombinationBuffer extends CombineTexturesFrameBuffer {
    static create(width, height, classifierColor, classifierFeature) {
        const combineGeom = CachedGeometry_1.CombineTexturesGeometry.createGeometry(classifierColor.texture.getHandle(), classifierFeature.texture.getHandle());
        if (undefined === combineGeom)
            return undefined;
        const textureFbo = SingleTextureFrameBuffer.createTextureAndFrameBuffer(width, 2 * height);
        return undefined === textureFbo ? undefined : new ClassifierCombinationBuffer(textureFbo, combineGeom, width, height, 2);
    }
}
class ClassifierAndMaskCombinationBuffer extends CombineTexturesFrameBuffer {
    static create(width, height, classifierColor, classifierFeature, mask) {
        const combineGeom = CachedGeometry_1.Combine3TexturesGeometry.createGeometry(classifierColor.texture.getHandle(), classifierFeature.texture.getHandle(), mask.texture.getHandle());
        if (undefined === combineGeom)
            return undefined;
        const textureFbo = SingleTextureFrameBuffer.createTextureAndFrameBuffer(width, 3 * height);
        return undefined === textureFbo ? undefined : new ClassifierAndMaskCombinationBuffer(textureFbo, combineGeom, width, height, 3);
    }
}
const scratchPrevRenderState = new RenderState_1.RenderState();
/** @internal */
class PlanarClassifier extends RenderPlanarClassifier_1.RenderPlanarClassifier {
    ;
    constructor(classifier, target) {
        super();
        this._projectionMatrix = core_geometry_1.Matrix4d.createIdentity();
        this._classifierGraphics = [];
        this._maskGraphics = [];
        this._width = 0;
        this._height = 0;
        this._baseBatchId = 0;
        this._anyHilited = false;
        this._anyOpaque = false;
        this._anyTranslucent = false;
        this._plane = core_geometry_1.Plane3dByOriginAndUnitNormal.create(new core_geometry_1.Point3d(0, 0, 0), new core_geometry_1.Vector3d(0, 0, 1)); // TBD -- Support other planes - default to X-Y for now.
        this._renderState = new RenderState_1.RenderState();
        this._branchStack = new BranchStack_1.BranchStack();
        this._contentMode = PlanarClassifierContent.None;
        this._featureSymbologySource = {
            onSourceDisposed: new core_bentley_1.BeEvent(),
        };
        this._doDebugFrustum = false;
        this._debugFrustumGraphic = undefined;
        this._bgColor = core_common_1.ColorDef.from(0, 0, 0, 255);
        this._classifier = classifier;
        const flags = this._renderState.flags;
        flags.depthMask = flags.blend = flags.depthTest = false;
        this._batchState = new BatchState_1.BatchState(this._branchStack);
        this._renderCommands = new RenderCommands_1.RenderCommands(target, this._branchStack, this._batchState);
    }
    get textureImageCount() { return this._contentMode; }
    getParams(params) {
        params[0] = this.insideDisplay;
        params[1] = this.outsideDisplay;
        params[2] = this._contentMode;
        if (this._planarClipMask?.settings.invert) // If the mask sense is inverted, negate the contentMode to indicate this to the shader.
            params[2] = -params[2];
        params[3] = (this._planarClipMask?.settings.transparency === undefined) ? -1 : this._planarClipMask.settings.transparency;
    }
    get hiliteTexture() { return undefined !== this._classifierBuffers ? this._classifierBuffers.textures.hilite : undefined; }
    get projectionMatrix() { return this._projectionMatrix; }
    // public get properties(): SpatialClassifier { return this._classifier; }
    get baseBatchId() { return this._baseBatchId; }
    get anyHilited() { return this._anyHilited; }
    get anyOpaque() { return this._anyOpaque; }
    get anyTranslucent() { return this._anyTranslucent; }
    get insideDisplay() { return this._classifier ? this._classifier.flags.inside : core_common_1.SpatialClassifierInsideDisplay.Off; }
    get outsideDisplay() { return this._classifier ? this._classifier.flags.outside : core_common_1.SpatialClassifierOutsideDisplay.On; }
    get isClassifyingPointCloud() { return true === this._isClassifyingPointCloud; }
    addGraphic(graphic) {
        this._graphics.push(graphic);
    }
    static create(properties, target) {
        return new PlanarClassifier(properties, target);
    }
    collectStatistics(stats) {
        if (undefined !== this._classifierBuffers)
            this._classifierBuffers.textures.collectStatistics(stats);
        if (undefined !== this._maskBuffer)
            this._maskBuffer.collectStatistics(stats);
        if (undefined !== this._classifierCombinedBuffer)
            this._classifierCombinedBuffer.collectStatistics(stats);
        if (undefined !== this._classifierAndMaskCombinedBuffer)
            this._classifierAndMaskCombinedBuffer.collectStatistics(stats);
    }
    get isDisposed() { return undefined === this._classifierBuffers; }
    dispose() {
        this._classifierBuffers = (0, core_bentley_1.dispose)(this._classifierBuffers);
        this._maskBuffer = (0, core_bentley_1.dispose)(this._maskBuffer);
        this._classifierCombinedBuffer = (0, core_bentley_1.dispose)(this._classifierCombinedBuffer);
        this._classifierAndMaskCombinedBuffer = (0, core_bentley_1.dispose)(this._classifierAndMaskCombinedBuffer);
        if (this._removeMe) {
            this._removeMe();
            this._removeMe = undefined;
        }
        this._featureSymbologySource.onSourceDisposed.raiseEvent();
    }
    get texture() {
        switch (this._contentMode) {
            case PlanarClassifierContent.None:
                return undefined;
            case PlanarClassifierContent.ClassifierOnly:
                return this._classifierCombinedBuffer?.texture;
            case PlanarClassifierContent.MaskOnly:
                return this._maskBuffer?.texture;
            case PlanarClassifierContent.ClassifierAndMask:
                return this._classifierAndMaskCombinedBuffer?.texture;
        }
    }
    getOrCreateClassifierTexture() {
        if (undefined === this._classifierBuffers)
            this._classifierBuffers = ClassifierFrameBuffers.create(this._width, this._height);
        if (undefined !== this._classifierBuffers && undefined === this._classifierCombinedBuffer)
            this._classifierCombinedBuffer = ClassifierCombinationBuffer.create(this._width, this._height, this._classifierBuffers.textures.color, this._classifierBuffers.textures.feature);
        return this._classifierCombinedBuffer?.texture;
    }
    pushBatches(batchState, graphics) {
        graphics.forEach((graphic) => {
            if (graphic instanceof Graphic_1.Batch) {
                batchState.push(graphic, true);
                batchState.pop();
            }
            else if (graphic instanceof Graphic_1.Branch) {
                this.pushBatches(batchState, graphic.branch.entries);
            }
        });
    }
    get sourceTransparency() {
        return this._classifierTreeRef?.transparency;
    }
    pushBatchState(batchState) {
        this._baseBatchId = batchState.nextBatchId - 1;
        if (undefined !== this._classifierGraphics)
            this.pushBatches(batchState, this._classifierGraphics);
    }
    setSource(classifierTreeRef, planarClipMask) {
        this._classifierTreeRef = classifierTreeRef;
        this._classifier = classifierTreeRef?.activeClassifier;
        this._planarClipMask = planarClipMask;
    }
    collectGraphics(context, target) {
        this._classifierGraphics.length = this._maskGraphics.length = 0;
        if (undefined === context.viewingSpace)
            return;
        const viewState = context.viewingSpace.view;
        if (!viewState.isSpatialView())
            return;
        this._doDebugFrustum = context.target.debugControl?.displayMaskFrustum ?? false;
        const maxTextureSize = System_1.System.instance.maxTexSizeAllow;
        const requiredHeight = maxTextureSize;
        const requiredWidth = maxTextureSize;
        if (requiredWidth !== this._width || requiredHeight !== this._height)
            this.dispose();
        this._width = requiredWidth;
        this._height = requiredHeight;
        const maskRange = core_geometry_1.Range3d.createNull();
        const maskTrees = this._planarClipMask?.getTileTrees(context, target.modelId, maskRange);
        if (!maskTrees && !this._classifierTreeRef)
            return;
        const allTrees = maskTrees ? maskTrees.slice() : new Array();
        if (this._classifierTreeRef)
            allTrees.push(this._classifierTreeRef);
        const projection = PlanarTextureProjection_1.PlanarTextureProjection.computePlanarTextureProjection(this._plane, context, target, allTrees, viewState, this._width, this._height, maskRange);
        if (!projection.textureFrustum || !projection.projectionMatrix || !projection.worldToViewMap)
            return;
        this._projectionMatrix = projection.projectionMatrix;
        this._frustum = projection.textureFrustum;
        this._debugFrustum = projection.debugFrustum;
        this._planarClipMaskOverrides = this._planarClipMask?.getPlanarClipMaskSymbologyOverrides(context, this._featureSymbologySource);
        if (!this._planarClipMask?.usingViewportOverrides && this._removeMe) {
            this._removeMe();
            this._removeMe = undefined;
        }
        else if (this._planarClipMask?.usingViewportOverrides && !this._removeMe) {
            this._removeMe = context.viewport.onFeatureOverridesChanged.addListener(() => {
                this._planarClipMaskOverrides = this._planarClipMask?.getPlanarClipMaskSymbologyOverrides(context, this._featureSymbologySource);
                context.viewport.requestRedraw();
            });
        }
        const drawTree = (treeRef, graphics) => {
            this._graphics = graphics;
            const frustumPlanes = this._frustum ? core_common_1.FrustumPlanes.fromFrustum(this._frustum) : core_common_1.FrustumPlanes.createEmpty();
            const drawArgs = internal_1.GraphicsCollectorDrawArgs.create(context, this, treeRef, frustumPlanes, projection.worldToViewMap);
            if (undefined !== drawArgs)
                treeRef.draw(drawArgs);
            this._graphics = undefined;
        };
        if (this._classifierTreeRef)
            drawTree(this._classifierTreeRef, this._classifierGraphics);
        if (maskTrees)
            maskTrees.forEach((maskTree) => drawTree(maskTree, this._maskGraphics));
        // Shader behaves slightly differently when classifying surfaces vs point clouds.
        this._isClassifyingPointCloud = target.isPointCloud;
        if (this._doDebugFrustum) {
            this._debugFrustumGraphic = (0, core_bentley_1.dispose)(this._debugFrustumGraphic);
            const builder = context.createSceneGraphicBuilder();
            builder.setSymbology(core_common_1.ColorDef.green, core_common_1.ColorDef.green, 2);
            builder.addFrustum(context.viewingSpace.getFrustum());
            builder.setSymbology(core_common_1.ColorDef.red, core_common_1.ColorDef.red, 2);
            builder.addFrustum(this._debugFrustum);
            builder.setSymbology(core_common_1.ColorDef.blue, core_common_1.ColorDef.blue, 2);
            builder.addFrustum(this._frustum);
            builder.setSymbology(core_common_1.ColorDef.from(0, 200, 0, 222), core_common_1.ColorDef.from(0, 200, 0, 222), 2);
            builder.addFrustumSides(context.viewingSpace.getFrustum());
            builder.setSymbology(core_common_1.ColorDef.from(200, 0, 0, 222), core_common_1.ColorDef.from(200, 0, 0, 222), 2);
            builder.addFrustumSides(this._debugFrustum);
            builder.setSymbology(core_common_1.ColorDef.from(0, 0, 200, 222), core_common_1.ColorDef.from(0, 0, 200, 222), 2);
            builder.addFrustumSides(this._frustum);
            this._debugFrustumGraphic = builder.finish();
            context.outputGraphic(this._debugFrustumGraphic);
        }
    }
    draw(target) {
        if (undefined === this._frustum)
            return;
        this._contentMode = PlanarClassifierContent.None;
        let combinationBuffer;
        if (this._classifierGraphics.length === 0) {
            if (this._maskGraphics.length === 0) {
                return;
            }
            else {
                if (undefined === this._maskBuffer) {
                    this._maskBuffer = MaskFrameBuffer.create(this._width, this._height);
                    if (undefined === this._maskBuffer)
                        return;
                }
                this._contentMode = PlanarClassifierContent.MaskOnly;
            }
        }
        else {
            if (undefined === this._classifierBuffers) {
                this._classifierBuffers = ClassifierFrameBuffers.create(this._width, this._height);
                if (undefined === this._classifierBuffers)
                    return;
            }
            if (this._maskGraphics.length === 0) {
                if (undefined === this._classifierCombinedBuffer) {
                    combinationBuffer = this._classifierCombinedBuffer = ClassifierCombinationBuffer.create(this._width, this._height, this._classifierBuffers.textures.color, this._classifierBuffers.textures.feature);
                    if (undefined === this._classifierCombinedBuffer)
                        return;
                }
                this._contentMode = PlanarClassifierContent.ClassifierOnly;
                combinationBuffer = this._classifierCombinedBuffer;
            }
            else {
                if (undefined === this._maskBuffer) {
                    this._maskBuffer = MaskFrameBuffer.create(this._width, this._height);
                    if (undefined === this._maskBuffer)
                        return;
                }
                if (undefined === this._classifierAndMaskCombinedBuffer) {
                    combinationBuffer = this._classifierAndMaskCombinedBuffer = ClassifierAndMaskCombinationBuffer.create(this._width, this._height, this._classifierBuffers.textures.color, this._classifierBuffers.textures.feature, this._maskBuffer.texture);
                    if (undefined === this._classifierAndMaskCombinedBuffer)
                        return;
                }
                combinationBuffer = this._classifierAndMaskCombinedBuffer;
                this._contentMode = PlanarClassifierContent.ClassifierAndMask;
            }
        }
        // Temporarily override the Target's state.
        const system = System_1.System.instance;
        const maskViewFlags = {
            renderMode: core_common_1.RenderMode.SmoothShade,
            wiremesh: false,
            transparency: !this.isClassifyingPointCloud, // point clouds don't support transparency.
            textures: false,
            lighting: false,
            shadows: false,
            monochrome: false,
            materials: false,
            ambientOcclusion: false,
            visibleEdges: false,
            hiddenEdges: false,
        };
        const prevState = system.currentRenderState.clone(scratchPrevRenderState);
        system.context.viewport(0, 0, this._width, this._height);
        const vf = target.currentViewFlags.copy(this._classifierTreeRef ? this._classifierTreeRef.viewFlags : maskViewFlags);
        system.applyRenderState(this._renderState);
        const prevPlan = target.plan;
        const prevOverrides = target.currentFeatureSymbologyOverrides;
        target.uniforms.style.changeBackgroundColor(this._bgColor); // Avoid white on white reversal. Will be reset in changeRenderPlan below.
        target.changeFrustum(this._frustum, this._frustum.getFraction(), true);
        this._anyTranslucent = false;
        const prevProjMatrix = target.uniforms.frustum.projectionMatrix;
        target.uniforms.frustum.changeProjectionMatrix(PlanarClassifier._postProjectionMatrix.multiplyMatrixMatrix(prevProjMatrix));
        target.uniforms.branch.changeRenderPlan(vf, target.plan.is3d, target.plan.hline);
        const renderCommands = this._renderCommands;
        const getDrawCommands = (graphics) => {
            this._batchState.reset();
            renderCommands.reset(target, this._branchStack, this._batchState);
            renderCommands.collectGraphicsForPlanarProjection(graphics);
            // Draw the classifiers into our attachments.
            // When using Display.ElementColor, the color and transparency come from the classifier geometry. Therefore we may need to draw the classified geometry
            // in a different pass - or both passes - depending on the transparency of the classifiers.
            // NB: "Outside" geometry by definition cannot take color/transparency from element...
            const cmds = renderCommands.getCommands(3 /* RenderPass.OpaquePlanar */);
            // NB: We don't strictly require the classifier geometry to be planar, and sometimes (e.g., "planar" polyface/bspsurf) we do not detect planarity.
            cmds.push(...renderCommands.getCommands(5 /* RenderPass.OpaqueGeneral */));
            cmds.push(...renderCommands.getCommands(2 /* RenderPass.OpaqueLinear */));
            this._anyOpaque = cmds.length > 0;
            const transCmds = renderCommands.getCommands(8 /* RenderPass.Translucent */);
            if (transCmds.length > 0) {
                cmds.push(...transCmds);
                this._anyTranslucent = true;
            }
            return cmds;
        };
        if (this._classifierGraphics.length > 0 && this._classifierBuffers) {
            this._classifierBuffers.draw(getDrawCommands(this._classifierGraphics), target);
            // Draw any hilited classifiers.
            const hiliteCommands = renderCommands.getCommands(10 /* RenderPass.Hilite */);
            this._anyHilited = 0 !== hiliteCommands.length;
            if (this._anyHilited)
                this._classifierBuffers.drawHilite(hiliteCommands, target);
        }
        if (this._maskGraphics.length > 0 && this._maskBuffer) {
            if (this._planarClipMaskOverrides)
                target.overrideFeatureSymbology(this._planarClipMaskOverrides);
            if (this._planarClipMask && this._planarClipMask.settings.transparency !== undefined && this._planarClipMask.settings.transparency > 0.0)
                this._anyTranslucent = true;
            this._maskBuffer.draw(getDrawCommands(this._maskGraphics), target);
        }
        if (combinationBuffer)
            combinationBuffer.compose(target);
        this._batchState.reset();
        target.changeRenderPlan(prevPlan);
        target.overrideFeatureSymbology(prevOverrides);
        system.applyRenderState(prevState);
        system.context.viewport(0, 0, target.viewRect.width, target.viewRect.height);
    }
}
exports.PlanarClassifier = PlanarClassifier;
PlanarClassifier._postProjectionMatrix = core_geometry_1.Matrix4d.createRowValues(0, 1, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 1);
//# sourceMappingURL=PlanarClassifier.js.map