"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.ThematicUniforms = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const RenderFlags_1 = require("./RenderFlags");
const Sync_1 = require("./Sync");
const Texture_1 = require("./Texture");
const ThematicSensors_1 = require("./ThematicSensors");
const core_geometry_1 = require("@itwin/core-geometry");
const System_1 = require("./System");
const FloatRGBA_1 = require("./FloatRGBA");
/** Maintains state for uniforms related to thematic display.
 * @internal
 */
class ThematicUniforms {
    constructor() {
        this._range = new Float32Array(2);
        this._colorMix = 0.0;
        this._axis = new Float32Array(3);
        this._sunDirection = new Float32Array(3);
        this._marginColor = new FloatRGBA_1.FloatRgba();
        this._displayMode = new Float32Array(1);
        this._fragSettings = new Float32Array(4); // gradientMode, distanceCutoff, stepCount, > 0.0 if multiply gradient alpha
        this._numSensors = 0;
        this._gradientDimension = _getGradientDimension();
        this.syncKey = 0;
        this._scratchVector = new core_geometry_1.Vector3d();
    }
    get _distanceCutoff() { return this._fragSettings[1]; }
    get thematicDisplay() {
        return this._thematicDisplay;
    }
    get wantIsoLines() {
        if (undefined !== this.thematicDisplay)
            return core_common_1.ThematicDisplayMode.Height === this._displayMode[0] && core_common_1.ThematicGradientMode.IsoLines === this.thematicDisplay.gradientSettings.mode;
        return false;
    }
    get wantSlopeMode() {
        return (undefined !== this.thematicDisplay) ? core_common_1.ThematicDisplayMode.Slope === this._displayMode[0] : false;
    }
    get wantHillShadeMode() {
        return (undefined !== this.thematicDisplay) ? core_common_1.ThematicDisplayMode.HillShade === this._displayMode[0] : false;
    }
    get wantGlobalSensorTexture() {
        return !(this._distanceCutoff > 0);
    }
    get bytesUsed() {
        return this._sensors ? this._sensors.bytesUsed : 0;
    }
    _updateAxis(axis, viewMatrix) {
        const tAxis = (viewMatrix !== undefined) ? viewMatrix.multiplyVector(axis, this._scratchVector) : axis;
        tAxis.normalizeInPlace();
        this._axis[0] = tAxis.x;
        this._axis[1] = tAxis.y;
        this._axis[2] = tAxis.z;
    }
    _updateSunDirection(sunDir, viewMatrix) {
        viewMatrix.multiplyVector(sunDir, this._scratchVector);
        this._scratchVector.negate(this._scratchVector);
        this._scratchVector.normalizeInPlace();
        this._sunDirection[0] = this._scratchVector.x;
        this._sunDirection[1] = this._scratchVector.y;
        this._sunDirection[2] = this._scratchVector.z;
    }
    update(target) {
        const plan = target.plan;
        if (this.thematicDisplay && plan.thematic && this.thematicDisplay.equals(plan.thematic) && this._texture) {
            if (undefined !== this._sensors)
                this._sensors.update(target.uniforms.frustum.viewMatrix);
            if (core_common_1.ThematicDisplayMode.Slope === this.thematicDisplay.displayMode) {
                this._updateAxis(this.thematicDisplay.axis, target.uniforms.frustum.viewMatrix);
                (0, Sync_1.desync)(this);
            }
            else if (core_common_1.ThematicDisplayMode.HillShade === this.thematicDisplay.displayMode) {
                this._updateSunDirection(this.thematicDisplay.sunDirection, target.uniforms.frustum.viewMatrix);
                (0, Sync_1.desync)(this);
            }
            return;
        }
        (0, Sync_1.desync)(this);
        this._thematicDisplay = plan.thematic;
        this._texture = (0, core_bentley_1.dispose)(this._texture);
        if (!this.thematicDisplay)
            return;
        if (core_common_1.ThematicDisplayMode.Slope === this.thematicDisplay.displayMode) {
            this._range[0] = core_geometry_1.Angle.degreesToRadians(this.thematicDisplay.range.low);
            this._range[1] = core_geometry_1.Angle.degreesToRadians(this.thematicDisplay.range.high);
        }
        else {
            this._range[0] = this.thematicDisplay.range.low;
            this._range[1] = this.thematicDisplay.range.high;
        }
        this._colorMix = this.thematicDisplay.gradientSettings.colorMix;
        this._updateAxis(this.thematicDisplay.axis, (core_common_1.ThematicDisplayMode.Slope === this.thematicDisplay.displayMode) ? target.uniforms.frustum.viewMatrix : undefined);
        if (core_common_1.ThematicDisplayMode.HillShade === this.thematicDisplay.displayMode)
            this._updateSunDirection(this.thematicDisplay.sunDirection, target.uniforms.frustum.viewMatrix);
        this._marginColor.setColorDef(this.thematicDisplay.gradientSettings.marginColor);
        this._displayMode[0] = this.thematicDisplay.displayMode;
        this._fragSettings[0] = this.thematicDisplay.gradientSettings.mode;
        const sensorSettings = this.thematicDisplay.sensorSettings;
        this._fragSettings[1] = (undefined === sensorSettings) ? 0 : this.thematicDisplay.sensorSettings.distanceCutoff;
        this._fragSettings[2] = Math.min(this.thematicDisplay.gradientSettings.stepCount, this._gradientDimension);
        this._fragSettings[3] = this.thematicDisplay.gradientSettings.transparencyMode === core_common_1.ThematicGradientTransparencyMode.SurfaceOnly ? 0.0 : 1.0;
        // If we want sensors and have no distance cutoff, then create a global shared sensor texture.
        if (target.wantThematicSensors && !(this._distanceCutoff > 0)) {
            this._numSensors = sensorSettings.sensors.length;
            this._sensors = (0, core_bentley_1.dispose)(this._sensors);
            this._sensors = ThematicSensors_1.ThematicSensors.create(target, core_geometry_1.Range3d.createNull());
        }
        const symb = core_common_1.Gradient.Symb.createThematic(this.thematicDisplay.gradientSettings);
        const image = symb.getThematicImageForRenderer(this._gradientDimension);
        this._texture = Texture_1.TextureHandle.createForImageBuffer(image, core_common_1.RenderTexture.Type.ThematicGradient);
    }
    bindRange(uniform) {
        if (!(0, Sync_1.sync)(this, uniform))
            uniform.setUniform2fv(this._range);
    }
    bindAxis(uniform) {
        if (!(0, Sync_1.sync)(this, uniform))
            uniform.setUniform3fv(this._axis);
    }
    bindSunDirection(uniform) {
        if (!(0, Sync_1.sync)(this, uniform))
            uniform.setUniform3fv(this._sunDirection);
    }
    bindMarginColor(uniform) {
        if (!(0, Sync_1.sync)(this, uniform))
            this._marginColor.bind(uniform);
    }
    bindDisplayMode(uniform) {
        if (!(0, Sync_1.sync)(this, uniform))
            uniform.setUniform1fv(this._displayMode);
    }
    bindFragSettings(uniform) {
        if (!(0, Sync_1.sync)(this, uniform))
            uniform.setUniform4fv(this._fragSettings);
    }
    bindTexture(uniform, unit) {
        (0, core_bentley_1.assert)(undefined !== this._texture);
        this._texture.bindSampler(uniform, unit);
    }
    bindNumSensors(uniform) {
        if (!(0, Sync_1.sync)(this, uniform))
            uniform.setUniform1i(this._numSensors);
    }
    bindSensors(uniform) {
        (0, core_bentley_1.assert)(undefined !== this._sensors);
        this._sensors.texture.bindSampler(uniform, RenderFlags_1.TextureUnit.ThematicSensors);
    }
    get isDisposed() {
        return undefined === this._texture && undefined === this._sensors;
    }
    dispose() {
        this._texture = (0, core_bentley_1.dispose)(this._texture);
        this._sensors = (0, core_bentley_1.dispose)(this._sensors);
    }
}
exports.ThematicUniforms = ThematicUniforms;
function _getGradientDimension() {
    const preferDimension = 8192;
    const maxDimension = System_1.System.instance.maxTextureSize;
    return (preferDimension > maxDimension) ? maxDimension : preferDimension;
}
//# sourceMappingURL=ThematicUniforms.js.map