"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.ContourUniforms = void 0;
const core_common_1 = require("@itwin/core-common");
const Sync_1 = require("./Sync");
const LineCode_1 = require("./LineCode");
/** Maintains state for uniforms related to contour display.
 * @internal
 */
class ContourUniforms {
    // We use 1.5x ContourDisplay.maxContourGroups of indexable vec4 uniforms, also limited to 14 by the feature lookup texture packing scheme
    _contourDefsSize = Math.ceil(core_common_1.ContourDisplay.maxContourGroups * 1.5);
    _contourDefs = new Float32Array(this._contourDefsSize * 4);
    _contourDisplay;
    syncKey = 0;
    get contourDisplay() {
        return this._contourDisplay;
    }
    packColor(startNdx, majorColor, minorColor) {
        // pack 2 bytes major (upper) minor (lower) into each float
        this._contourDefs[startNdx] = majorColor.r * 256 + minorColor.r;
        this._contourDefs[startNdx + 1] = majorColor.g * 256 + minorColor.g;
        this._contourDefs[startNdx + 2] = majorColor.b * 256 + minorColor.b;
    }
    packPatWidth(startNdx, majorPattern, minorPattern, majorWidth, minorWidth, showGeometry) {
        // pack 2 bytes into this float, which is 4th float of vec4
        //   width is a 4-bit value that is biased by 1.0 and has 3-bits value with one fraction bit, so range is 1.0 to 8.5
        //   pattern is a line code index 0 to 10 (0 is solid)
        //   pack major into upper byte (upper nibble -> pattern, lower nibble -> 4-bit encoded width)
        //   pack minor into lower byte (upper nibble -> pattern, lower nibble -> 4-bit encoded width)
        // NB: showGeometry flag is packed into bit 16 (above major pattern)
        const majWt = Math.floor((Math.min(8.5, Math.max(1.0, majorWidth)) - 1.0) * 2 + 0.5);
        const minWt = Math.floor((Math.min(8.5, Math.max(1.0, minorWidth)) - 1.0) * 2 + 0.5);
        this._contourDefs[startNdx + 3] = (showGeometry ? 65536 : 0) + majorPattern * 4096 + majWt * 256 + minorPattern * 16 + minWt;
    }
    packIntervals(startNdx, even, minorInterval, majorIntervalCount) {
        // minorInterval is a float of interval in meters, majorIntervalCount is an int > 0 count of minor inteverals per major interval
        // minorInterval is stored in r or b (0 or 2) and majorIntervalCount is stored in g or a (1 or 3) depending on even or odd index
        const offset = (even ? 0 : 1) * 2;
        this._contourDefs[startNdx + offset] = minorInterval <= 0.0 ? 1.0 : minorInterval;
        majorIntervalCount = Math.floor(majorIntervalCount + 0.5);
        this._contourDefs[startNdx + offset + 1] = majorIntervalCount < 1.0 ? 1.0 : majorIntervalCount;
    }
    update(target) {
        if (this.contourDisplay && target.currentContours && this.contourDisplay.equals(target.currentContours)) {
            return;
        }
        (0, Sync_1.desync)(this);
        this._contourDisplay = target.currentContours;
        if (undefined === this.contourDisplay)
            return;
        /* uniform packing for contourDefs:
            The line pattern code is put into 4 bits, and the width is packed into 4 bits, so together with the pattern use 8 bits.
            This and the color bytes are then packed 2 bytes per float component, major in upper, as a float (e.g.: majorByte * 256 + minorByte)
            The minorInterval and majorCount each take a full float component, so they are combined with a second entry to use a full vec4
              Because of this, the overal indexing for a given contourDef is a bit different
            E.g.: the first 2 contour definitions (if both used) are packed into the first 3 vec4 uniform indexes like so:
              0.r = majCol[0].r << 8 | minCol[0].r  (0 to 65535 as float)
              0.g = majCol[0].g << 8 | minCol[0].g  (0 to 65535 as float)
              0.r = majCol[0].b << 8 | minCol[0].b  (0 to 65535 as float)
              0.r = (majPat[0] << 12 | majW[0] << 8) | (minPat[0] << 4 | minW[0])  (0 to 65535 as float)
              1.r = minorInterval[0]  (as float)
              1.g = majorCount[0]  (int, as float)
              1.b = minorInterval[1]  (as float)
              1.a = majorCount[1]  (int, as float)
              2.r = majCol[1].r << 8 | minCol[1].r  (0 to 65535 as float)
              2.g = majCol[1].g << 8 | minCol[1].g  (0 to 65535 as float)
              2.r = majCol[1].b << 8 | minCol[1].b  (0 to 65535 as float)
              2.r = (majPat[1] << 12 | majW[1] << 8) | (minPat[1] << 4 | minW[1])  (0 to 65535 as float)
            Then this usage pattern repeats the same way with every 2 contour definitions used taking 3 vec4 uniforms.
               (If just 1 contour def remains then it takes 2 vec4 uniforms, of which 1.5 is actually used.)
        */
        for (let index = 0, len = this.contourDisplay.groups.length; index < len && index < core_common_1.ContourDisplay.maxContourGroups; ++index) {
            const contourDef = this.contourDisplay.groups[index].contourDef;
            const even = (index & 1) === 0;
            const colorDefsNdx = (even ? index * 1.5 : (index - 1) * 1.5 + 2) * 4;
            this.packColor(colorDefsNdx, contourDef.majorStyle.color, contourDef.minorStyle.color);
            this.packPatWidth(colorDefsNdx, LineCode_1.LineCode.valueFromLinePixels(contourDef.majorStyle.pattern), LineCode_1.LineCode.valueFromLinePixels(contourDef.minorStyle.pattern), contourDef.majorStyle.pixelWidth, contourDef.minorStyle.pixelWidth, contourDef.showGeometry);
            const intervalsPairNdx = (Math.floor(index * 0.5) * 3 + 1) * 4;
            this.packIntervals(intervalsPairNdx, even, contourDef.minorInterval, contourDef.majorIntervalCount);
        }
    }
    bindcontourDefs(uniform) {
        if (!(0, Sync_1.sync)(this, uniform))
            uniform.setUniform4fv(this._contourDefs);
    }
}
exports.ContourUniforms = ContourUniforms;
//# sourceMappingURL=ContourUniforms.js.map