@itwin/core-frontend
Version:
iTwin.js frontend components
635 lines • 29.7 kB
JavaScript
"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 {
_frustumPlanes;
_scratchFrustum = new core_common_1.Frustum();
_scratchRange = new core_geometry_1.Range3d();
_commands = new Array(21 /* RenderPass.COUNT */);
_target;
_stack; // refers to the Target's BranchStack
_batchState; // refers to the Target's BatchState
_forcedRenderPass = 255 /* RenderPass.None */;
_addLayersAsNormalGraphics = false;
_opaqueOverrides = false;
_translucentOverrides = false;
_addTranslucentAsOpaque = false; // true when rendering for _ReadPixels to force translucent items to be drawn in opaque pass.
_layers;
appearanceProvider;
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._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.appearanceProvider = undefined;
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);
this.addGraphics(gfx.foregroundDynamics);
this.addOverlayGraphics(gfx.overlayDynamics);
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, this.appearanceProvider ?? this._stack.top);
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