"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.Contours = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const GL_1 = require("./GL");
const RenderFlags_1 = require("./RenderFlags");
const System_1 = require("./System");
const Texture_1 = require("./Texture");
const VertexTable_1 = require("../../common/internal/render/VertexTable");
const scratchPackedFeature = core_common_1.PackedFeature.createWithIndex();
/** @internal */
class Contours {
    get byteLength() { return undefined !== this._lut ? this._lut.bytesUsed : 0; }
    matchesTargetAndFeatureCount(target, map) {
        // checking for target change or texture size requirement change
        return target === this.target && this._numFeatures === map.numFeatures;
    }
    matchesSubCategories() {
        if (this._contours === undefined && this.target.plan.contours === undefined)
            return true;
        if (this._contours === undefined || this.target.plan.contours === undefined)
            return false;
        if (this._contours.groups.length !== this.target.plan.contours.groups.length)
            return false;
        for (let index = 0, len = this._contours.groups.length; index < len && index < core_common_1.ContourDisplay.maxContourGroups; ++index) {
            if (!this._contours.groups[index].subCategoriesEqual(this.target.plan.contours.groups[index]))
                return false;
        }
        return true;
    }
    _initialize(map) {
        (0, core_bentley_1.assert)(0 < map.numFeatures);
        this._numFeatures = map.numFeatures;
        const dims = (0, VertexTable_1.computeDimensions)(this._numFeatures, 1 / 8, 0, System_1.System.instance.maxTextureSize);
        const width = dims.width;
        const height = dims.height;
        (0, core_bentley_1.assert)(width * height * 8 >= this._numFeatures);
        const data = new Uint8Array(width * height * 4);
        const creator = new Texture_1.Texture2DDataUpdater(data);
        this.buildLookupTable(creator, map, this.target.plan.contours);
        this._lut = Texture_1.TextureHandle.createForData(width, height, data, true, GL_1.GL.Texture.WrapMode.ClampToEdge);
        this._lutWidth = width;
    }
    _update(map, lut) {
        (0, core_bentley_1.assert)(this._numFeatures === map.numFeatures);
        const updater = new Texture_1.Texture2DDataUpdater(lut.dataBytes);
        this.buildLookupTable(updater, map, this.target.plan.contours);
        lut.update(updater);
    }
    buildLookupTable(data, map, contours) {
        // setup an efficient way to compare feature subcategories with lists in terrains
        const subCatMap = new core_bentley_1.Id64.Uint32Map();
        let defaultNdx = 0xf; // default for unmatched subcategories is to not show contours
        // NB: index also has to be a max of 14 - has to fit in 4 bits with value 15 reserved for no terrain def
        for (let index = 0, len = contours.groups.length; index < len && index < core_common_1.ContourDisplay.maxContourGroups; ++index) {
            const subCats = contours.groups[index].subCategories;
            if (core_bentley_1.OrderedId64Iterable.isEmptySet(subCats)) {
                defaultNdx = index; // change default for unmatched subcategories to this definition
            }
            else {
                for (const subCat of subCats)
                    subCatMap.setById(subCat, index);
            }
        }
        // NB: We currently use 1/2 of one component of RGBA value per feature as follows:
        //   [0] R/G/B/A = index pair - lower 4 bits = ndx n, upper 4 bits = ndx n+1
        let even = false;
        let byteOut = 0;
        let dataIndex = 0;
        for (const feature of map.iterable(scratchPackedFeature)) {
            dataIndex = Math.floor(feature.index * 0.5);
            even = (feature.index & 1) === 0;
            const terrainNdx = subCatMap.get(feature.subCategoryId.lower, feature.subCategoryId.upper) ?? defaultNdx;
            if (even)
                byteOut = terrainNdx;
            else
                data.setByteAtIndex(dataIndex, (terrainNdx << 4) | byteOut);
        }
        if (even) // not written
            data.setByteAtIndex(dataIndex, byteOut);
    }
    constructor(target, options) {
        this._lutWidth = 0;
        this._numFeatures = 0;
        this.target = target;
        this._options = options;
        this._contours = target.plan.contours;
    }
    static createFromTarget(target, options) {
        return new Contours(target, options);
    }
    get isDisposed() { return undefined === this._lut; }
    dispose() {
        this._lut = (0, core_bentley_1.dispose)(this._lut);
        return undefined;
    }
    initFromMap(map) {
        this._lut = (0, core_bentley_1.dispose)(this._lut);
        this._initialize(map);
    }
    update(features) {
        if (this.matchesSubCategories())
            return;
        this._contours = this.target.plan.contours;
        // _lut can be undefined if context was lost, (gl.createTexture returns null)
        if (this._lut) {
            this._update(features, this._lut);
        }
    }
    bindContourLUTWidth(uniform) {
        uniform.setUniform1ui(this._lutWidth);
    }
    bindContourLUT(uniform) {
        if (this._lut)
            this._lut.bindSampler(uniform, RenderFlags_1.TextureUnit.Contours);
    }
}
exports.Contours = Contours;
//# sourceMappingURL=Contours.js.map