@itwin/core-frontend
Version:
iTwin.js frontend components
110 lines • 4.81 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 { assert, Id64, lowerBound } from "@itwin/core-bentley";
/**
* Assigns a transient, unique 32-bit integer ID to each Batch in a RenderCommands.
* A batch ID of 0 means "no batch".
* The first batch gets batch ID of 1.
* The next batch gets the previous batch's ID plus the number of features in the previous batch's feature table
* (or 1, if empty feature table).
* The IDs are set temporarily as members on the Batch objects and reset to 0 immediately after rendering.
* The currentBatch member identifies the batch containing primitives currently being drawn.
* The combination of the current batch's ID (passed as uniform to shader) and the index of a given Feature within
* its batch's FeatureTable (stored in vertex table) produce a unique ID for every feature rendered during a frame.
* During rendering, the feature IDs are written to the "feature ID" color attachment.
* The batch IDs remain valid during a call to Target.readPixels() so that they can be used to extract
* Features from the Batch's FeatureTables.
* @internal
*/
export class BatchState {
_stack;
_batches = []; // NB: this list is ordered - but *not* indexed - by batch ID.
_curBatch;
constructor(stack) {
this._stack = stack;
}
get currentBatch() { return this._curBatch; }
get currentBatchId() { return undefined !== this._curBatch ? this._curBatch.batchId : 0; }
get currentBatchIModel() { return undefined !== this._curBatch ? this._curBatch.batchIModel : undefined; }
get isEmpty() { return 0 === this._batches.length; }
push(batch, allowAdd) {
assert(undefined === this.currentBatch, "batches cannot nest");
this.getBatchId(batch, allowAdd);
this._curBatch = batch;
}
pop() {
assert(undefined !== this.currentBatch);
this._curBatch = undefined;
}
reset() {
assert(undefined === this.currentBatch);
for (const batch of this._batches)
batch.resetContext();
this._batches.length = 0;
this._curBatch = undefined;
}
static _scratchElementIdPair = { lower: 0, upper: 0 };
getElementId(featureId) {
const batch = this.find(featureId);
if (undefined === batch)
return Id64.invalid;
const featureIndex = featureId - batch.batchId;
assert(featureIndex >= 0);
const parts = batch.featureTable.getElementIdPair(featureIndex, BatchState._scratchElementIdPair);
return Id64.fromUint32Pair(parts.lower, parts.upper);
}
getFeature(featureId, result) {
const batch = this.find(featureId);
if (undefined === batch)
return undefined;
const featureIndex = featureId - batch.batchId;
assert(featureIndex >= 0);
return batch.featureTable.findFeature(featureIndex, result);
}
get numFeatureIds() { return this.nextBatchId; }
get numBatches() { return this._batches.length; }
findBatchId(featureId) {
const batch = this.find(featureId);
return undefined !== batch ? batch.batchId : 0;
}
get nextBatchId() {
if (this.isEmpty)
return 1;
const prev = this._batches[this._batches.length - 1];
assert(0 !== prev.batchId);
let prevNumFeatures = prev.featureTable.numFeatures;
if (0 === prevNumFeatures)
prevNumFeatures = 1;
return prev.batchId + prevNumFeatures;
}
getBatchId(batch, allowAdd) {
if (allowAdd && 0 === batch.batchId) {
batch.setContext(this.nextBatchId, this._stack.top);
this._batches.push(batch);
}
return batch.batchId;
}
indexOf(featureId) {
if (featureId <= 0)
return -1;
const found = lowerBound(featureId, this._batches, (lhs, rhs) => {
// Determine if the requested feature ID is within the range of this batch.
if (lhs < rhs.batchId)
return -1;
const numFeatures = rhs.featureTable.numFeatures;
const nextBatchId = rhs.batchId + (numFeatures > 0 ? numFeatures : 1);
return lhs < nextBatchId ? 0 : 1;
});
return found.index < this._batches.length ? found.index : -1;
}
find(featureId) {
const index = this.indexOf(featureId);
return -1 !== index ? this._batches[index] : undefined;
}
}
//# sourceMappingURL=BatchState.js.map