/*---------------------------------------------------------------------------------------------
* 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 { PointCloudDisplaySettings } from "@itwin/core-common";
import { desync, sync } from "./Sync";
import { Vector3d } from "@itwin/core-geometry";
/** A Target keeps track of the current settings for drawing point clouds.
 * Pushing a Branch may *replace* the current settings. Popping the Branch does not reset them. It is expected that every Branch containing
 * a point cloud will also specify the settings for drawing that point cloud.
 * This permits the same point cloud graphics to be rendered differently in different viewports.
 * In future these uniforms will include eye-dome lighting.
 * @internal
 */
export class PointCloudUniforms {
    constructor() {
        this.syncKey = 0;
        this._settings = PointCloudDisplaySettings.defaults;
        this._scaleFactor = 8.0;
        this._is3d = true;
        // vec3 u_pointSize
        // x = fixed point size in pixels if > 0, else scale applied to voxel size (negated).
        // y = minimum size in pixels if using voxel size.
        // z = maximum size in pixels if using voxel size
        // w = 1.0 if drawing square points, 0.0 if round.
        this._vec4 = new Float32Array(4);
        // x = strength - 0.0 disables EDL
        // y = radius
        // z =
        // w =
        this._edl1 = new Float32Array(4);
        this._edl2 = new Float32Array(4);
        this.initialize(this._settings);
    }
    update(settings) {
        if (this._settings.equals(settings))
            return;
        this._settings = settings;
        desync(this);
        this.initialize(settings);
    }
    updateRange(range, target, xform, is3d) {
        let rangeFactor = 8.0; // default to min scale factor of 8
        const near = target.uniforms.frustum.nearPlane;
        const far = target.uniforms.frustum.farPlane;
        const viewDepth = far - near;
        if (range !== undefined) {
            const scale = xform.matrix;
            // calculate a "normalized" strength factor based on the size of the point cloud versus the current viewing depth
            //   from the matrix, only care about scaling factor here (entries 0,4,8) to scale the range lengths
            //   then use the largest length component as the reference for the size of the point cloud
            const rangeScale = Vector3d.create(scale.coffs[0] * range.xLength(), scale.coffs[4] * range.xLength(), scale.coffs[8] * range.xLength()).maxAbs();
            // limit the viewDepth/rangeScale ratio to min of 10 to still get reasonable factors when close to and inside the model
            rangeFactor = Math.log(Math.max(10, viewDepth / rangeScale));
        }
        const zoomFactor = Math.log(far / near); // compensate for zoom level
        const winSizeFactor = Math.pow(1.8440033, Math.log2(2226 / target.uniforms.viewRect.width)); // compensate for window size
        const scaleFactor = (rangeFactor + zoomFactor) / winSizeFactor;
        if (this._scaleFactor === scaleFactor && this._is3d === is3d)
            return;
        this._scaleFactor = scaleFactor;
        this._is3d = is3d;
        desync(this);
        this.initialize(this._settings);
    }
    bind(uniform) {
        if (!sync(this, uniform))
            uniform.setUniform4fv(this._vec4);
    }
    bindEDL1(uniform) {
        if (!sync(this, uniform))
            uniform.setUniform4fv(this._edl1);
    }
    bindEDL2(uniform) {
        if (!sync(this, uniform))
            uniform.setUniform4fv(this._edl2);
    }
    initialize(settings) {
        this._vec4[0] = "pixel" === settings.sizeMode ? settings.pixelSize : -settings.voxelScale;
        this._vec4[1] = settings.minPixelsPerVoxel;
        this._vec4[2] = settings.maxPixelsPerVoxel;
        this._vec4[3] = "square" === settings.shape ? 1 : 0;
        this._edl1[0] = settings.edlStrength;
        this._edl1[1] = settings.edlRadius;
        this._edl1[2] = this._scaleFactor;
        this._edl1[3] = this._is3d ? 1 : 0;
        this._edl2[0] = settings?.edlMixWts1 ?? 1.0;
        this._edl2[1] = settings?.edlMixWts2 ?? 0.5;
        this._edl2[2] = settings?.edlMixWts4 ?? 0.25;
        this._edl2[3] = 0;
    }
}
/** Uniforms affecting how reality models are drawn.
 * Pushing a Branch may *replace* the current settings. Popping the Branch does not reset them. It is expected that every Branch containing
 * a reality model will also specify the settings for drawing that reality model.
 * This permits the same reality model graphics to be rendered differently in different viewports.
 * In future these uniforms may include additional settings for reality meshes - currently only the override color ratio applies to them.
 * @internal
 */
export class RealityModelUniforms {
    constructor() {
        // ###TODO when we need it: public readonly mesh = new RealityMeshUniforms();
        this.pointCloud = new PointCloudUniforms();
        this._overrideColorMix = 0.5;
    }
    update(settings) {
        this._overrideColorMix = settings.overrideColorRatio;
        this.pointCloud.update(settings.pointCloud);
    }
    bindOverrideColorMix(uniform) {
        uniform.setUniform1f(this._overrideColorMix);
    }
}
//# sourceMappingURL=RealityModelUniforms.js.map