"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.BatchState = void 0;
const core_bentley_1 = require("@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
 */
class BatchState {
    constructor(stack) {
        this._batches = []; // NB: this list is ordered - but *not* indexed - by batch ID.
        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) {
        (0, core_bentley_1.assert)(undefined === this.currentBatch, "batches cannot nest");
        this.getBatchId(batch, allowAdd);
        this._curBatch = batch;
    }
    pop() {
        (0, core_bentley_1.assert)(undefined !== this.currentBatch);
        this._curBatch = undefined;
    }
    reset() {
        (0, core_bentley_1.assert)(undefined === this.currentBatch);
        for (const batch of this._batches)
            batch.resetContext();
        this._batches.length = 0;
        this._curBatch = undefined;
    }
    getElementId(featureId) {
        const batch = this.find(featureId);
        if (undefined === batch)
            return core_bentley_1.Id64.invalid;
        const featureIndex = featureId - batch.batchId;
        (0, core_bentley_1.assert)(featureIndex >= 0);
        const parts = batch.featureTable.getElementIdPair(featureIndex, BatchState._scratchElementIdPair);
        return core_bentley_1.Id64.fromUint32Pair(parts.lower, parts.upper);
    }
    getFeature(featureId, result) {
        const batch = this.find(featureId);
        if (undefined === batch)
            return undefined;
        const featureIndex = featureId - batch.batchId;
        (0, core_bentley_1.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];
        (0, core_bentley_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 = (0, core_bentley_1.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;
    }
}
exports.BatchState = BatchState;
BatchState._scratchElementIdPair = { lower: 0, upper: 0 };
//# sourceMappingURL=BatchState.js.map