@itwin/core-frontend
Version:
iTwin.js frontend components
570 lines • 28.4 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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
*/
import { BeEvent, dispose } from "@itwin/core-bentley";
import { ColorDef, FrustumPlanes, RenderMode, RenderTexture, SpatialClassifierInsideDisplay, SpatialClassifierOutsideDisplay, TextureTransparency, } from "@itwin/core-common";
import { Matrix4d, Plane3dByOriginAndUnitNormal, Point3d, Range3d, Vector3d } from "@itwin/core-geometry";
import { GraphicsCollectorDrawArgs } from "../../../tile/internal";
import { RenderPlanarClassifier } from "../RenderPlanarClassifier";
import { BatchState } from "./BatchState";
import { BranchStack } from "./BranchStack";
import { Combine3TexturesGeometry, CombineTexturesGeometry, ViewportQuadGeometry } from "./CachedGeometry";
import { FrameBuffer } from "./FrameBuffer";
import { GL } from "./GL";
import { Batch, Branch } from "./Graphic";
import { PlanarTextureProjection } from "./PlanarTextureProjection";
import { RenderCommands } from "./RenderCommands";
import { RenderState } from "./RenderState";
import { getDrawParams } from "./ScratchDrawParams";
import { System } from "./System";
import { Texture, TextureHandle } from "./Texture";
export 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 || (PlanarClassifierContent = {}));
function createTexture(handle) {
return new Texture({
handle,
ownership: "external",
type: RenderTexture.Type.TileSection,
transparency: TextureTransparency.Opaque,
});
}
function createTextureHandle(width, height, heightMult = 1.0) {
return TextureHandle.createForAttachment(width, height * heightMult, GL.Texture.Format.Rgba, GL.Texture.DataType.UnsignedByte);
}
class ClassifierTextures {
color;
feature;
hilite;
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;
}
[Symbol.dispose]() {
dispose(this.color);
dispose(this.feature);
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 {
textures;
_hilite;
_fbo;
_clearGeom;
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;
}
[Symbol.dispose]() {
dispose(this._fbo);
dispose(this._clearGeom);
dispose(this.textures);
dispose(this._hilite);
}
draw(cmds, target) {
System.instance.frameBufferStack.execute(this._fbo, true, false, () => {
target.techniques.draw(getDrawParams(target, this._clearGeom));
target.techniques.execute(target, cmds, 19 /* RenderPass.PlanarClassification */);
});
}
drawHilite(cmds, target) {
const system = System.instance;
const gl = system.context;
system.frameBufferStack.execute(this._hilite, true, false, () => {
gl.clearColor(0, 0, 0, 0);
gl.clear(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.create([textures.hilite.texture]);
if (undefined === hiliteFbo)
return undefined;
const fbo = FrameBuffer.create([textures.color.texture, textures.feature.texture]);
if (undefined === fbo)
return undefined;
const geom = ViewportQuadGeometry.create(21 /* TechniqueId.ClearPickAndColor */);
return undefined !== geom ? new this(textures, hiliteFbo, fbo, geom) : undefined;
}
}
class SingleTextureFrameBuffer {
texture;
fbo;
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;
}
[Symbol.dispose]() {
dispose(this.texture);
dispose(this.fbo);
}
static createTextureAndFrameBuffer(width, height) {
const hTexture = TextureHandle.createForAttachment(width, height, GL.Texture.Format.Rgba, GL.Texture.DataType.UnsignedByte);
if (!hTexture)
return undefined;
const texture = new Texture({ type: RenderTexture.Type.TileSection, ownership: "external", handle: hTexture, transparency: TextureTransparency.Opaque });
if (!texture)
return undefined;
const fbo = 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.instance;
const gl = system.context;
system.frameBufferStack.execute(this.fbo, true, false, () => {
gl.clearColor(0, 0, 0, 0);
gl.clear(GL.BufferBit.Color);
target.techniques.execute(target, cmds, 19 /* RenderPass.PlanarClassification */);
});
}
}
class CombineTexturesFrameBuffer extends SingleTextureFrameBuffer {
_combineGeom;
_width;
_height;
_heightMult;
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.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.BufferBit.Color);
target.techniques.draw(getDrawParams(target, this._combineGeom));
});
}
}
class ClassifierCombinationBuffer extends CombineTexturesFrameBuffer {
static create(width, height, classifierColor, classifierFeature) {
const combineGeom = 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 = 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();
/** @internal */
export class PlanarClassifier extends RenderPlanarClassifier {
_classifierBuffers;
_maskBuffer;
_classifierCombinedBuffer;
_classifierAndMaskCombinedBuffer;
_projectionMatrix = Matrix4d.createIdentity();
_graphics;
_classifierGraphics = [];
_maskGraphics = [];
_frustum;
_width = 0;
_height = 0;
_baseBatchId = 0;
_anyHilited = false;
_anyOpaque = false;
_anyTranslucent = false;
_classifier;
_plane = Plane3dByOriginAndUnitNormal.create(new Point3d(0, 0, 0), new Vector3d(0, 0, 1)); // TBD -- Support other planes - default to X-Y for now.
_renderState = new RenderState();
_renderCommands;
_branchStack = new BranchStack();
_batchState;
_planarClipMask;
_classifierTreeRef;
_planarClipMaskOverrides;
_overridesDirty = true;
_contentMode = PlanarClassifierContent.None;
_removeMe;
_featureSymbologySource = {
onSourceDisposed: new BeEvent(),
};
;
static _postProjectionMatrix = Matrix4d.createRowValues(0, 1, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 1);
_debugFrustum;
_doDebugFrustum = false;
_debugFrustumGraphic = undefined;
_isClassifyingPointCloud; // we will detect this the first time we draw
_bgColor = ColorDef.from(0, 0, 0, 255);
constructor(classifier, target) {
super();
this._classifier = classifier;
const flags = this._renderState.flags;
flags.depthMask = flags.blend = flags.depthTest = false;
this._batchState = new BatchState(this._branchStack);
this._renderCommands = new 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 : SpatialClassifierInsideDisplay.Off; }
get outsideDisplay() { return this._classifier ? this._classifier.flags.outside : 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; }
[Symbol.dispose]() {
this._classifierBuffers = dispose(this._classifierBuffers);
this._maskBuffer = dispose(this._maskBuffer);
this._classifierCombinedBuffer = dispose(this._classifierCombinedBuffer);
this._classifierAndMaskCombinedBuffer = 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 Batch) {
batchState.push(graphic, true);
batchState.pop();
}
else if (graphic instanceof 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.instance.maxTexSizeAllow;
const requiredHeight = maxTextureSize;
const requiredWidth = maxTextureSize;
if (requiredWidth !== this._width || requiredHeight !== this._height)
this[Symbol.dispose]();
this._width = requiredWidth;
this._height = requiredHeight;
const maskRange = 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.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;
if (this._overridesDirty) {
this._overridesDirty = false;
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._overridesDirty = true;
context.viewport.requestRedraw();
});
}
const drawTree = (treeRef, graphics) => {
this._graphics = graphics;
const frustumPlanes = this._frustum ? FrustumPlanes.fromFrustum(this._frustum) : FrustumPlanes.createEmpty();
const drawArgs = 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 = dispose(this._debugFrustumGraphic);
const builder = context.createSceneGraphicBuilder();
builder.setSymbology(ColorDef.green, ColorDef.green, 2);
builder.addFrustum(context.viewingSpace.getFrustum());
builder.setSymbology(ColorDef.red, ColorDef.red, 2);
builder.addFrustum(this._debugFrustum);
builder.setSymbology(ColorDef.blue, ColorDef.blue, 2);
builder.addFrustum(this._frustum);
builder.setSymbology(ColorDef.from(0, 200, 0, 222), ColorDef.from(0, 200, 0, 222), 2);
builder.addFrustumSides(context.viewingSpace.getFrustum());
builder.setSymbology(ColorDef.from(200, 0, 0, 222), ColorDef.from(200, 0, 0, 222), 2);
builder.addFrustumSides(this._debugFrustum);
builder.setSymbology(ColorDef.from(0, 0, 200, 222), 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.instance;
const maskViewFlags = {
renderMode: 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, target.plan.contours);
const addCmds = (oldCmds, newCmds) => {
if (undefined === newCmds)
return oldCmds;
if (newCmds.length > 50000) {
// This method is slower for smaller array sizes, but when the size of newCmds gets larger it's performance is ok.
return oldCmds.concat(newCmds);
}
else {
// This method runs faster, but gets a stack overflow when the size of newCmds is too large.
oldCmds.push(...newCmds);
return oldCmds;
}
};
const renderCommands = this._renderCommands;
const getDrawCommands = (graphics) => {
this._batchState.reset();
renderCommands.reset(target, this._branchStack, this._batchState);
if (this._planarClipMask?.overridesModelVisibility) {
// We're using batched tiles and the mask is overriding which models are visible versus those visible in the view.
// We don't want the BatchedTileTreeReference to hide models that belong in the mask.
// The target's root branch's symbology overrides are set up correctly for the mask, and we never push branches to the target
// (we have a separate branch stack), so just use the root branch as the appearance provider instead of the branch stack.
// NOTE: this doesn't work if we're inside a GraphicalEditingScope displaying temporary graphics for some elements, because those
// elements are hidden in the tiles by a FeatureAppearanceProvider. But we'll never use a GraphicalEditingScope with batched tiles,
// and non-batched tiles never hide models using symbology overrides.
renderCommands.appearanceProvider = target.currentBranch;
}
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...
let 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 = addCmds(cmds, renderCommands.getCommands(5 /* RenderPass.OpaqueGeneral */));
cmds = addCmds(cmds, renderCommands.getCommands(2 /* RenderPass.OpaqueLinear */));
this._anyOpaque = cmds.length > 0;
const transCmds = renderCommands.getCommands(8 /* RenderPass.Translucent */);
if (transCmds.length > 0) {
cmds = addCmds(cmds, renderCommands.getCommands(8 /* RenderPass.Translucent */));
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);
this._branchStack.setSymbologyOverrides(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);
}
}
//# sourceMappingURL=PlanarClassifier.js.map