"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Atmosphere = void 0;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module DisplayStyles
 */
const core_bentley_1 = require("@itwin/core-bentley");
/** Namespace containing types controlling how atmospheric scattering should be rendered.
 * @beta
 * The techniques used to render the atmosphere approximate the physical behavior of light when interacting with particles in the air (Rayleigh Scattering and Mie Scattering)
 * Presently, only Rayleigh Scattering is implemented here
 *
 * In a nutshell, this implementation samples atmospheric density along rays cast from the view and uses the samples to simulate the scattering of light toward the camera.
 * The amount of light scattered toward the camera is dependent on the amount of light scattered away from its original path from the sun, so rays must also be cast from the sample points to the sun.
 *
 * The effect can be computed on vertices (the default for the background map) and fragments (the default for the skybox, which is a ViewportQuad).
 * All coordinates are in view space.
 *
 * This implementation is adapted from equations outlined in "Display of Clouds Taking into Account Multiple Anisotropic Scattering and Sky Light", Nishita et al. 1993
 *   which are further refined for use in GPU shaders in "Photorealistic Real-Time Outdoor Light Scattering", Hoffman and Preetham 2002.
 * These sources are also compiled in Chapter 16 of NVIDIA's "GPU Gems 2", which can be found online here:
 *   https://developer.nvidia.com/gpugems/gpugems2/part-ii-shading-lighting-and-shadows/chapter-16-accurate-atmospheric-scattering
 *
 * This implementation is also highly inspired by Sebastian Lague's Solar System project: https://github.com/SebLague/Solar-System/ and video: https://www.youtube.com/watch?v=DxfEbulyFcY
 *   along with this ShaderToy replica: https://www.shadertoy.com/view/fltXD2.
 * Both of which are inspired by this Nvidia article on atmospheric scattering: https://developer.nvidia.com/gpugems/gpugems2/part-ii-shading-lighting-and-shadows/chapter-16-accurate-atmospheric-scattering.
 */
var Atmosphere;
(function (Atmosphere) {
    /** @internal An immutable container of wavelength values for the red, green and blue pixel components. Values are in nanometers. */
    class Wavelengths {
        r;
        g;
        b;
        /** Constructs from red, green, and blue wavelength values.
         * @param r Wavelength value for red
         * @param g Wavelength value for green
         * @param b Wavelength value for blue
         */
        constructor(props) {
            this.r = Math.max(0, props.r);
            this.g = Math.max(0, props.g);
            this.b = Math.max(0, props.b);
        }
        equals(other) {
            return this.r === other.r && this.g === other.g && this.b === other.b;
        }
        toJSON() {
            return { r: this.r, g: this.g, b: this.b };
        }
        static fromJSON(json) {
            let r = 0;
            let g = 0;
            let b = 0;
            if (undefined !== json) {
                if (typeof json.r === "number")
                    r = json.r;
                if (typeof json.g === "number")
                    g = json.g;
                if (typeof json.b === "number")
                    b = json.b;
            }
            return new Wavelengths({ r, g, b });
        }
    }
    Atmosphere.Wavelengths = Wavelengths;
    /** Describes the properties with which the atmospheric scattering effect should be drawn. Theses properties correspond to a physics-based approximation of atmospheric scattering phenomenons. */
    class Settings {
        static _defaultAtmosphereHeightAboveEarth = 100000.0;
        static _defaultExposure = 2.0;
        static _defaultDensityFalloff = 10.0;
        static _defaultMinDensityHeightBelowEarth;
        static _defaultScatteringStrength = 100;
        static _defaultWavelengths = new Wavelengths({ r: 700.0, g: 530.0, b: 440.0 });
        static _defaultNumViewRaySamples = 10;
        static _highQualityNumViewRaySamples = 20;
        static _defaultNumSunRaySamples = 5;
        static defaults = new Settings({});
        static highQuality = new Settings({ numViewRaySamples: this._highQualityNumViewRaySamples });
        /** @internal If defined, corresponds to the height in meters above the earth's pole at which the atmosphere terminates. Physically, this is the point at which there are no more air molecules to interfere with light transmission. Defaults to 100_000.0. */
        atmosphereHeightAboveEarth;
        /** If defined, this value is used to simulate the aperture of a camera. Higher values allow more light in. This value might need to be adjusted slightly in situations without much sunlight (like sunset) to brighten the image. Defaults to 2.0 */
        exposure;
        /** @internal If defined, controls the rate at which the air density decreases between the point it is the highest and the point is is the lowest. A higher value means a faster decrease in air density. Defaults to 10.0. */
        densityFalloff;
        /** @internal If defined, corresponds to the height in meters below the earth's pole at which the atmosphere is at its densest. Physically, this is the point at which there is the most air molecules to interfere with light transmission. Defaults to 0.0. */
        depthBelowEarthForMaxDensity;
        /** If defined, corresponds to the number of atmospheric density samples used to compute the amount of light scattered along each view ray. For each sample point, another ray will be cast toward the sun to compute the amount of light reaching the sample point. Higher values increase fidelity, but greatly decrease performance because sun rays must be cast from each additional sample point. The range is 1 to 40. Defaults to 10. */
        numViewRaySamples;
        /** If defined, corresponds to the number of atmospheric density samples uses to compute the amount of light scattered along each sun ray. Higher values increase fidelity slightly but greatly decrease performance. Minimal improvement is observable with values above 5. The range is 1 to 40. Defaults to 5. */
        numSunRaySamples;
        /** @internal If defined, controls how strongly the atmosphere's air diverts light. Higher values increase scattering intensity. Defaults to 100.0. */
        scatteringStrength;
        /** @internal If defined, corresponds the wavelengths of the red, green and blue color components in nanometers used to simulate how the atmosphere's air molecules affects light transmission. (See Rayleigh Scattering) Thus, a value of 470 for the red wavelength will make the red light component scatter as if it physically were a cyan light ray. The default value is {r:700.0, g:530.0, b:440.0}. */
        wavelengths;
        equals(other) {
            if (this.atmosphereHeightAboveEarth !== other.atmosphereHeightAboveEarth)
                return false;
            if (this.exposure !== other.exposure)
                return false;
            if (this.densityFalloff !== other.densityFalloff)
                return false;
            if (this.depthBelowEarthForMaxDensity !== other.depthBelowEarthForMaxDensity)
                return false;
            if (this.numViewRaySamples !== other.numViewRaySamples)
                return false;
            if (this.numSunRaySamples !== other.numSunRaySamples)
                return false;
            if (this.scatteringStrength !== other.scatteringStrength)
                return false;
            if (!this.wavelengths.equals(other.wavelengths))
                return false;
            return true;
        }
        constructor(json) {
            this.atmosphereHeightAboveEarth = core_bentley_1.JsonUtils.asDouble(json.atmosphereHeightAboveEarth, Settings._defaultAtmosphereHeightAboveEarth);
            this.exposure = core_bentley_1.JsonUtils.asDouble(json.exposure, Settings._defaultExposure);
            this.densityFalloff = core_bentley_1.JsonUtils.asDouble(json.densityFalloff, Settings._defaultDensityFalloff);
            this.depthBelowEarthForMaxDensity = core_bentley_1.JsonUtils.asDouble(json.depthBelowEarthForMaxDensity, Settings._defaultMinDensityHeightBelowEarth);
            this.numViewRaySamples = core_bentley_1.JsonUtils.asDouble(json.numViewRaySamples, Settings._defaultNumViewRaySamples);
            this.numSunRaySamples = core_bentley_1.JsonUtils.asDouble(json.numSunRaySamples, Settings._defaultNumSunRaySamples);
            this.scatteringStrength = core_bentley_1.JsonUtils.asDouble(json.scatteringStrength, Settings._defaultScatteringStrength);
            this.wavelengths = Wavelengths.fromJSON(core_bentley_1.JsonUtils.asObject(json.wavelengths) ?? Settings._defaultWavelengths);
        }
        static fromJSON(json) {
            if (undefined === json)
                return this.defaults;
            return new Settings(json);
        }
        toJSON(display) {
            const json = {
                atmosphereHeightAboveEarth: this.atmosphereHeightAboveEarth,
                exposure: this.exposure,
                densityFalloff: this.densityFalloff,
                depthBelowEarthForMaxDensity: this.depthBelowEarthForMaxDensity,
                numViewRaySamples: this.numViewRaySamples,
                numSunRaySamples: this.numSunRaySamples,
                scatteringStrength: this.scatteringStrength,
                wavelengths: this.wavelengths.toJSON(),
            };
            if (undefined !== display)
                json.display = display;
            return json;
        }
    }
    Atmosphere.Settings = Settings;
})(Atmosphere || (exports.Atmosphere = Atmosphere = {}));
//# sourceMappingURL=Atmosphere.js.map