/*---------------------------------------------------------------------------------------------
* 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 { assert, dispose } from "@itwin/core-bentley";
import { Range3d, Transform } from "@itwin/core-geometry";
import { ThematicDisplaySensor } from "@itwin/core-common";
import { GL } from "./GL";
import { Texture2DHandle } from "./Texture";
import { TextureUnit } from "./RenderFlags";
/** Maintains a floating-point texture representing a list of thematic sensors.
 * @internal
 */
export class ThematicSensors {
    get numSensors() { return this._sensors.length; }
    matchesTarget(target) {
        return target === this.target && this.sensorSettings === target.plan.thematic?.sensorSettings;
    }
    static create(target, range) {
        let sensors = [];
        if (target.plan.thematic !== undefined) {
            sensors = _accumulateSensorsInRange(target.plan.thematic.sensorSettings.sensors, range, target.currentTransform, target.plan.thematic.sensorSettings.distanceCutoff);
        }
        const obj = this.createFloat(target, range, sensors);
        obj._update(obj.target.uniforms.frustum.viewMatrix);
        return obj;
    }
    get isDisposed() { return this._texture.handle.isDisposed; }
    dispose() {
        dispose(this._texture.handle);
    }
    bindNumSensors(uniform) {
        uniform.setUniform1i(this.numSensors);
    }
    bindTexture(uniform) {
        this._texture.handle.bindSampler(uniform, TextureUnit.ThematicSensors);
    }
    get bytesUsed() { return this._texture.handle.bytesUsed; }
    get texture() { return this._texture.handle; }
    _update(viewMatrix) {
        this._viewMatrix.setFrom(viewMatrix);
        this.reset();
        for (const sensor of this._sensors) {
            const position = this._viewMatrix.multiplyPoint3d(sensor.position);
            this.appendSensor(position, sensor.value);
        }
        this._texture.handle.replaceTextureData(this._texture.data);
    }
    update(viewMatrix) {
        if (!this._viewMatrix.isAlmostEqual(viewMatrix)) {
            this._update(viewMatrix);
        }
    }
    constructor(texture, target, range, sensors) {
        /** Position at which to write next texture data. */
        this._curPos = 0;
        this._viewMatrix = Transform.createIdentity();
        this.target = target;
        this.range = range;
        this.sensorSettings = target.plan.thematic?.sensorSettings;
        this._sensors = sensors;
        this._texture = texture;
        this._view = new DataView(texture.data.buffer);
    }
    static createFloat(target, range, sensors) {
        const data = new Float32Array(sensors.length * 4);
        const handle = Texture2DHandle.createForData(1, sensors.length, data, false, GL.Texture.WrapMode.ClampToEdge, GL.Texture.Format.Rgba);
        assert(undefined !== handle);
        return new this({ handle, data }, target, range, sensors);
    }
    append(value) { this.appendFloat(value); }
    appendFloat(value) {
        this._view.setFloat32(this._curPos, value, true);
        this.advance(4);
    }
    appendUint8(value) {
        this._view.setUint8(this._curPos, value);
        this.advance(1);
    }
    advance(numBytes) { this._curPos += numBytes; }
    reset() { this._curPos = 0; }
    appendValues(a, b, c, d) {
        this.append(a);
        this.append(b);
        this.append(c);
        this.append(d);
    }
    appendSensor(position, value) { this.appendValues(position.x, position.y, position.z, value); }
}
function _sensorRadiusAffectsRange(sensor, sensorRadius, range) {
    const distance = range.distanceToPoint(sensor.position);
    return !(distance > sensorRadius);
}
const scratchRange = Range3d.createNull();
function _accumulateSensorsInRange(sensors, range, transform, distanceCutoff) {
    const retSensors = [];
    transform.multiplyRange(range, scratchRange);
    for (const sensor of sensors) {
        const position = sensor.position;
        if (distanceCutoff <= 0 || _sensorRadiusAffectsRange(sensor, distanceCutoff, scratchRange)) {
            const value = sensor.value;
            retSensors.push(ThematicDisplaySensor.fromJSON({ position, value }));
        }
    }
    return retSensors;
}
//# sourceMappingURL=ThematicSensors.js.map