summaryrefslogtreecommitdiff
path: root/indra/newview/lllegacyatmospherics.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/lllegacyatmospherics.cpp')
-rw-r--r--indra/newview/lllegacyatmospherics.cpp1598
1 files changed, 799 insertions, 799 deletions
diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp
index a30b0625ae..1403845d07 100644
--- a/indra/newview/lllegacyatmospherics.cpp
+++ b/indra/newview/lllegacyatmospherics.cpp
@@ -1,799 +1,799 @@
-/**
- * @file lllegacyatmospherics.cpp
- * @brief LLAtmospherics class implementation
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "lllegacyatmospherics.h"
-
-#include "llfeaturemanager.h"
-#include "llviewercontrol.h"
-#include "llframetimer.h"
-
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "lldrawable.h"
-#include "llface.h"
-#include "llglheaders.h"
-#include "llsky.h"
-#include "llviewercamera.h"
-#include "llviewertexturelist.h"
-#include "llviewerobjectlist.h"
-#include "llviewerregion.h"
-#include "llworld.h"
-#include "pipeline.h"
-#include "v3colorutil.h"
-
-#include "llsettingssky.h"
-#include "llenvironment.h"
-#include "lldrawpoolwater.h"
-
-class LLFastLn
-{
-public:
- LLFastLn()
- {
- mTable[0] = 0;
- for( S32 i = 1; i < 257; i++ )
- {
- mTable[i] = log((F32)i);
- }
- }
-
- F32 ln( F32 x )
- {
- const F32 OO_255 = 0.003921568627450980392156862745098f;
- const F32 LN_255 = 5.5412635451584261462455391880218f;
-
- if( x < OO_255 )
- {
- return log(x);
- }
- else
- if( x < 1 )
- {
- x *= 255.f;
- S32 index = llfloor(x);
- F32 t = x - index;
- F32 low = mTable[index];
- F32 high = mTable[index + 1];
- return low + t * (high - low) - LN_255;
- }
- else
- if( x <= 255 )
- {
- S32 index = llfloor(x);
- F32 t = x - index;
- F32 low = mTable[index];
- F32 high = mTable[index + 1];
- return low + t * (high - low);
- }
- else
- {
- return log( x );
- }
- }
-
- F32 pow( F32 x, F32 y )
- {
- return (F32)LL_FAST_EXP(y * ln(x));
- }
-
-
-private:
- F32 mTable[257]; // index 0 is unused
-};
-
-static LLFastLn gFastLn;
-
-
-// Functions used a lot.
-
-inline F32 LLHaze::calcPhase(const F32 cos_theta) const
-{
- const F32 g2 = mG * mG;
- const F32 den = 1 + g2 - 2 * mG * cos_theta;
- return (1 - g2) * gFastLn.pow(den, -1.5);
-}
-
-inline void color_pow(LLColor3 &col, const F32 e)
-{
- col.mV[0] = gFastLn.pow(col.mV[0], e);
- col.mV[1] = gFastLn.pow(col.mV[1], e);
- col.mV[2] = gFastLn.pow(col.mV[2], e);
-}
-
-inline LLColor3 color_norm(const LLColor3 &col)
-{
- const F32 m = color_max(col);
- if (m > 1.f)
- {
- return 1.f/m * col;
- }
- else return col;
-}
-
-inline void color_gamma_correct(LLColor3 &col)
-{
- const F32 gamma_inv = 1.f/1.2f;
- if (col.mV[0] != 0.f)
- {
- col.mV[0] = gFastLn.pow(col.mV[0], gamma_inv);
- }
- if (col.mV[1] != 0.f)
- {
- col.mV[1] = gFastLn.pow(col.mV[1], gamma_inv);
- }
- if (col.mV[2] != 0.f)
- {
- col.mV[2] = gFastLn.pow(col.mV[2], gamma_inv);
- }
-}
-
-static LLColor3 calc_air_sca_sea_level()
-{
- static LLColor3 WAVE_LEN(675, 520, 445);
- static LLColor3 refr_ind = refr_ind_calc(WAVE_LEN);
- static LLColor3 n21 = refr_ind * refr_ind - LLColor3(1, 1, 1);
- static LLColor3 n4 = n21 * n21;
- static LLColor3 wl2 = WAVE_LEN * WAVE_LEN * 1e-6f;
- static LLColor3 wl4 = wl2 * wl2;
- static LLColor3 mult_const = fsigma * 2.0f/ 3.0f * 1e24f * (F_PI * F_PI) * n4;
- static F32 dens_div_N = F32( ATM_SEA_LEVEL_NDENS / Ndens2);
- return dens_div_N * mult_const.divide(wl4);
-}
-
-// static constants.
-LLColor3 const LLHaze::sAirScaSeaLevel = calc_air_sca_sea_level();
-F32 const LLHaze::sAirScaIntense = color_intens(LLHaze::sAirScaSeaLevel);
-F32 const LLHaze::sAirScaAvg = LLHaze::sAirScaIntense / 3.f;
-
-/***************************************
- Atmospherics
-***************************************/
-
-LLAtmospherics::LLAtmospherics()
-: mCloudDensity(0.2f),
- mWind(0.f),
- mWorldScale(1.f)
-{
- /// WL PARAMS
- mInitialized = false;
- mAmbientScale = gSavedSettings.getF32("SkyAmbientScale");
- mNightColorShift = gSavedSettings.getColor3("SkyNightColorShift");
- mFogColor.mV[VRED] = mFogColor.mV[VGREEN] = mFogColor.mV[VBLUE] = 0.5f;
- mFogColor.mV[VALPHA] = 0.0f;
- mFogRatio = 1.2f;
- mHazeConcentration = 0.f;
- mInterpVal = 0.f;
-}
-
-
-LLAtmospherics::~LLAtmospherics()
-{
-}
-
-void LLAtmospherics::init()
-{
- const F32 haze_int = color_intens(mHaze.calcSigSca(0));
- mHazeConcentration = haze_int / (color_intens(mHaze.calcAirSca(0)) + haze_int);
- mInitialized = true;
-}
-
-// This cubemap is used as "environmentMap" in indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
-LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny, bool low_end)
-{
- const F32 sky_saturation = 0.25f;
- const F32 land_saturation = 0.1f;
-
- if (isShiny && dir.mV[VZ] < -0.02f)
- {
- LLColor4 col;
- LLColor3 desat_fog = LLColor3(mFogColor);
- F32 brightness = desat_fog.brightness();// NOTE: Linear brightness!
- // So that shiny somewhat shows up at night.
- if (brightness < 0.15f)
- {
- brightness = 0.15f;
- desat_fog = smear(0.15f);
- }
- F32 greyscale_sat = brightness * (1.0f - land_saturation);
- desat_fog = desat_fog * land_saturation + smear(greyscale_sat);
- if (low_end)
- {
- col = LLColor4(desat_fog, 0.f);
- }
- else
- {
- col = LLColor4(desat_fog * 0.5f, 0.f);
- }
- float x = 1.0f-fabsf(-0.1f-dir.mV[VZ]);
- x *= x;
- col.mV[0] *= x*x;
- col.mV[1] *= powf(x, 2.5f);
- col.mV[2] *= x*x*x;
- return col;
- }
-
- // undo OGL_TO_CFR_ROTATION and negate vertical direction.
- LLVector3 Pn = LLVector3(-dir[1] , -dir[2], -dir[0]);
-
- //calculates hazeColor
- calcSkyColorWLVert(psky, Pn, vars);
-
- if (isShiny)
- {
- F32 brightness = vars.hazeColor.brightness();
- F32 greyscale_sat = brightness * (1.0f - sky_saturation);
- LLColor3 sky_color = vars.hazeColor * sky_saturation + smear(greyscale_sat);
- //sky_color *= (0.5f + 0.5f * brightness); // SL-12574 EEP sky is being attenuated too much
- return LLColor4(sky_color, 0.0f);
- }
-
- LLColor3 sky_color = low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f, vars.gamma);
-
- return LLColor4(sky_color, 0.0f);
-}
-
-// NOTE: Keep these in sync!
-// indra\newview\app_settings\shaders\class1\deferred\skyV.glsl
-// indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl
-// indra\newview\lllegacyatmospherics.cpp
-void LLAtmospherics::calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars)
-{
- const LLColor3 blue_density = vars.blue_density;
- const LLColor3 blue_horizon = vars.blue_horizon;
- const F32 haze_horizon = vars.haze_horizon;
- const F32 haze_density = vars.haze_density;
- const F32 density_multiplier = vars.density_multiplier;
-
- F32 max_y = vars.max_y;
- LLVector4 sun_norm = vars.sun_norm;
-
- // project the direction ray onto the sky dome.
- F32 phi = acos(Pn[1]);
- F32 sinA = sin(F_PI - phi);
- if (fabsf(sinA) < 0.01f)
- { //avoid division by zero
- sinA = 0.01f;
- }
-
- F32 Plen = vars.dome_radius * sin(F_PI + phi + asin(vars.dome_offset * sinA)) / sinA;
-
- Pn *= Plen;
-
- // Set altitude
- if (Pn[1] > 0.f)
- {
- Pn *= (max_y / Pn[1]);
- }
- else
- {
- Pn *= (-32000.f / Pn[1]);
- }
-
- Plen = Pn.length();
- Pn /= Plen;
-
- // Initialize temp variables
- LLColor3 sunlight = vars.sunlight;
- LLColor3 ambient = vars.ambient;
-
- LLColor3 glow = vars.glow;
- F32 cloud_shadow = vars.cloud_shadow;
-
- // Sunlight attenuation effect (hue and brightness) due to atmosphere
- // this is used later for sunlight modulation at various altitudes
- LLColor3 light_atten = vars.light_atten;
- LLColor3 light_transmittance = psky->getLightTransmittanceFast(vars.total_density, vars.density_multiplier, Plen);
- (void)light_transmittance; // silence Clang warn-error
-
- // Calculate relative weights
- LLColor3 temp2(0.f, 0.f, 0.f);
- LLColor3 temp1 = vars.total_density;
-
- LLColor3 blue_weight = componentDiv(blue_density, temp1);
- LLColor3 blue_factor = blue_horizon * blue_weight;
- LLColor3 haze_weight = componentDiv(smear(haze_density), temp1);
- LLColor3 haze_factor = haze_horizon * haze_weight;
-
-
- // Compute sunlight from P & lightnorm (for long rays like sky)
- temp2.mV[1] = llmax(F_APPROXIMATELY_ZERO, llmax(0.f, Pn[1]) * 1.0f + sun_norm.mV[1] );
-
- temp2.mV[1] = 1.f / temp2.mV[1];
- componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
- componentMultBy(sunlight, light_transmittance);
-
- // Distance
- temp2.mV[2] = Plen * density_multiplier;
-
- // Transparency (-> temp1)
- temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]);
-
- // Compute haze glow
- temp2.mV[0] = Pn * LLVector3(sun_norm);
-
- temp2.mV[0] = 1.f - temp2.mV[0];
- // temp2.x is 0 at the sun and increases away from sun
- temp2.mV[0] = llmax(temp2.mV[0], .001f);
- // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
-
- // Higher glow.x gives dimmer glow (because next step is 1 / "angle")
- temp2.mV[0] *= glow.mV[0];
-
- temp2.mV[0] = pow(temp2.mV[0], glow.mV[2]);
- // glow.z should be negative, so we're doing a sort of (1 / "angle") function
-
- // Add "minimum anti-solar illumination"
- temp2.mV[0] += .25f;
-
-
- // Haze color above cloud
- vars.hazeColor = (blue_factor * (sunlight + ambient) + componentMult(haze_factor, sunlight * temp2.mV[0] + ambient));
-
- // Increase ambient when there are more clouds
- LLColor3 tmpAmbient = ambient + (LLColor3::white - ambient) * cloud_shadow * 0.5f;
-
- // Dim sunlight by cloud shadow percentage
- sunlight *= (1.f - cloud_shadow);
-
- // Haze color below cloud
- vars.hazeColorBelowCloud = (blue_factor * (sunlight + tmpAmbient) + componentMult(haze_factor, sunlight * temp2.mV[0] + tmpAmbient));
-
- // Final atmosphere additive
- componentMultBy(vars.hazeColor, LLColor3::white - temp1);
-
-/*
- // SL-12574
-
- // Attenuate cloud color by atmosphere
- temp1 = componentSqrt(temp1); //less atmos opacity (more transparency) below clouds
-
- // At horizon, blend high altitude sky color towards the darker color below the clouds
- vars.hazeColor += componentMult(vars.hazeColorBelowCloud - vars.hazeColor, LLColor3::white - componentSqrt(temp1));
-*/
-}
-
-void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
-{
- LLVector3 tosun = tosun_in;
-
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG))
- {
- return;
- }
-
- LLColor4 target_fog(0.f, 0.2f, 0.5f, 0.f);
-
- const F32 water_height = gAgent.getRegion() ? gAgent.getRegion()->getWaterHeight() : 0.f;
- // LLWorld::getInstance()->getWaterHeight();
- F32 camera_height = gAgentCamera.getCameraPositionAgent().mV[2];
-
- F32 near_clip_height = LLViewerCamera::getInstance()->getAtAxis().mV[VZ] * LLViewerCamera::getInstance()->getNear();
- camera_height += near_clip_height;
-
- F32 fog_distance = 0.f;
- LLColor3 res_color[3];
-
- LLColor3 sky_fog_color = LLColor3::white;
- LLColor3 render_fog_color = LLColor3::white;
-
- const F32 tosun_z = tosun.mV[VZ];
- tosun.mV[VZ] = 0.f;
- tosun.normalize();
- LLVector3 perp_tosun;
- perp_tosun.mV[VX] = -tosun.mV[VY];
- perp_tosun.mV[VY] = tosun.mV[VX];
- LLVector3 tosun_45 = tosun + perp_tosun;
- tosun_45.normalize();
-
- F32 delta = 0.06f;
- tosun.mV[VZ] = delta;
- perp_tosun.mV[VZ] = delta;
- tosun_45.mV[VZ] = delta;
- tosun.normalize();
- perp_tosun.normalize();
- tosun_45.normalize();
-
- // Sky colors, just slightly above the horizon in the direction of the sun, perpendicular to the sun, and at a 45 degree angle to the sun.
- AtmosphericsVars vars;
-
- LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-
- // NOTE: This is very similar to LLVOSky::cacheEnvironment()
- // Differences:
- // vars.sun_norm
- // vars.sunlight
- // invariants across whole sky tex process...
- vars.blue_density = psky->getBlueDensity();
- vars.blue_horizon = psky->getBlueHorizon();
- vars.haze_density = psky->getHazeDensity();
- vars.haze_horizon = psky->getHazeHorizon();
- vars.density_multiplier = psky->getDensityMultiplier();
- vars.distance_multiplier = psky->getDistanceMultiplier();
- vars.max_y = psky->getMaxY();
- vars.sun_norm = LLEnvironment::instance().getSunDirectionCFR();
- vars.sunlight = psky->getSunlightColor();
- vars.ambient = psky->getAmbientColor();
- vars.glow = psky->getGlow();
- vars.cloud_shadow = psky->getCloudShadow();
- vars.dome_radius = psky->getDomeRadius();
- vars.dome_offset = psky->getDomeOffset();
- vars.light_atten = psky->getLightAttenuation(vars.max_y);
- vars.light_transmittance = psky->getLightTransmittance(vars.max_y);
- vars.total_density = psky->getTotalDensity();
- vars.gamma = psky->getGamma();
-
- res_color[0] = calcSkyColorInDir(psky, vars, tosun);
- res_color[1] = calcSkyColorInDir(psky, vars, perp_tosun);
- res_color[2] = calcSkyColorInDir(psky, vars, tosun_45);
-
- sky_fog_color = color_norm(res_color[0] + res_color[1] + res_color[2]);
-
- F32 full_off = -0.25f;
- F32 full_on = 0.00f;
- F32 on = (tosun_z - full_off) / (full_on - full_off);
- on = llclamp(on, 0.01f, 1.f);
- sky_fog_color *= 0.5f * on;
-
-
- // We need to clamp these to non-zero, in order for the gamma correction to work. 0^y = ???
- S32 i;
- for (i = 0; i < 3; i++)
- {
- sky_fog_color.mV[i] = llmax(0.0001f, sky_fog_color.mV[i]);
- }
-
- color_gamma_correct(sky_fog_color);
-
- render_fog_color = sky_fog_color;
-
- fog_distance = mFogRatio * distance;
-
- if (camera_height > water_height)
- {
- LLColor4 fog(render_fog_color);
- mGLFogCol = fog;
- }
- else
- {
- LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
- F32 depth = water_height - camera_height;
- LLColor4 water_fog_color(pwater->getWaterFogColor());
-
- // adjust the color based on depth. We're doing linear approximations
- float depth_scale = gSavedSettings.getF32("WaterGLFogDepthScale");
- float depth_modifier = 1.0f - llmin(llmax(depth / depth_scale, 0.01f),
- gSavedSettings.getF32("WaterGLFogDepthFloor"));
-
- LLColor4 fogCol = water_fog_color * depth_modifier;
- fogCol.setAlpha(1);
-
- // set the gl fog color
- mGLFogCol = fogCol;
- }
-
- mFogColor = sky_fog_color;
- mFogColor.setAlpha(1);
-
- LLDrawPoolWater::sWaterFogEnd = fog_distance*2.2f;
-
- stop_glerror();
-}
-
-// Functions used a lot.
-F32 color_norm_pow(LLColor3& col, F32 e, bool postmultiply)
-{
- F32 mv = color_max(col);
- if (0 == mv)
- {
- return 0;
- }
-
- col *= 1.f / mv;
- color_pow(col, e);
- if (postmultiply)
- {
- col *= mv;
- }
- return mv;
-}
-
-// Returns angle (RADIANs) between the horizontal projection of "v" and the x_axis.
-// Range of output is 0.0f to 2pi //359.99999...f
-// Returns 0.0f when "v" = +/- z_axis.
-F32 azimuth(const LLVector3 &v)
-{
- F32 azimuth = 0.0f;
- if (v.mV[VX] == 0.0f)
- {
- if (v.mV[VY] > 0.0f)
- {
- azimuth = F_PI * 0.5f;
- }
- else if (v.mV[VY] < 0.0f)
- {
- azimuth = F_PI * 1.5f;// 270.f;
- }
- }
- else
- {
- azimuth = (F32) atan(v.mV[VY] / v.mV[VX]);
- if (v.mV[VX] < 0.0f)
- {
- azimuth += F_PI;
- }
- else if (v.mV[VY] < 0.0f)
- {
- azimuth += F_PI * 2;
- }
- }
- return azimuth;
-}
-
-bool operator==(const AtmosphericsVars& a, const AtmosphericsVars& b)
-{
- if (a.hazeColor != b.hazeColor)
- {
- return false;
- }
-
- if (a.hazeColorBelowCloud != b.hazeColorBelowCloud)
- {
- return false;
- }
-
- if (a.cloudColorSun != b.cloudColorSun)
- {
- return false;
- }
-
- if (a.cloudColorAmbient != b.cloudColorAmbient)
- {
- return false;
- }
-
- if (a.cloudDensity != b.cloudDensity)
- {
- return false;
- }
-
- if (a.density_multiplier != b.density_multiplier)
- {
- return false;
- }
-
- if (a.haze_horizon != b.haze_horizon)
- {
- return false;
- }
-
- if (a.haze_density != b.haze_density)
- {
- return false;
- }
-
- if (a.blue_horizon != b.blue_horizon)
- {
- return false;
- }
-
- if (a.blue_density != b.blue_density)
- {
- return false;
- }
-
- if (a.dome_offset != b.dome_offset)
- {
- return false;
- }
-
- if (a.dome_radius != b.dome_radius)
- {
- return false;
- }
-
- if (a.cloud_shadow != b.cloud_shadow)
- {
- return false;
- }
-
- if (a.glow != b.glow)
- {
- return false;
- }
-
- if (a.ambient != b.ambient)
- {
- return false;
- }
-
- if (a.sunlight != b.sunlight)
- {
- return false;
- }
-
- if (a.sun_norm != b.sun_norm)
- {
- return false;
- }
-
- if (a.gamma != b.gamma)
- {
- return false;
- }
-
- if (a.max_y != b.max_y)
- {
- return false;
- }
-
- if (a.distance_multiplier != b.distance_multiplier)
- {
- return false;
- }
-
- // light_atten, light_transmittance, total_density
- // are ignored as they always change when the values above do
- // they're just shared calc across the sky map generation to save cycles
-
- return true;
-}
-
-bool approximatelyEqual(const F32 &a, const F32 &b, const F32 &fraction_treshold)
-{
- F32 diff = fabs(a - b);
- if (diff < F_APPROXIMATELY_ZERO || diff < llmax(fabs(a), fabs(b)) * fraction_treshold)
- {
- return true;
- }
- return false;
-}
-
-bool approximatelyEqual(const LLColor3 &a, const LLColor3 &b, const F32 &fraction_treshold)
-{
- return approximatelyEqual(a.mV[0], b.mV[0], fraction_treshold)
- && approximatelyEqual(a.mV[1], b.mV[1], fraction_treshold)
- && approximatelyEqual(a.mV[2], b.mV[2], fraction_treshold);
-}
-
-bool approximatelyEqual(const LLVector4 &a, const LLVector4 &b, const F32 &fraction_treshold)
-{
- return approximatelyEqual(a.mV[0], b.mV[0], fraction_treshold)
- && approximatelyEqual(a.mV[1], b.mV[1], fraction_treshold)
- && approximatelyEqual(a.mV[2], b.mV[2], fraction_treshold)
- && approximatelyEqual(a.mV[3], b.mV[3], fraction_treshold);
-}
-
-bool approximatelyEqual(const AtmosphericsVars& a, const AtmosphericsVars& b, const F32 fraction_treshold)
-{
- if (!approximatelyEqual(a.hazeColor, b.hazeColor, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.hazeColorBelowCloud, b.hazeColorBelowCloud, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.cloudColorSun, b.cloudColorSun, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.cloudColorAmbient, b.cloudColorAmbient, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.cloudDensity, b.cloudDensity, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.density_multiplier, b.density_multiplier, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.haze_horizon, b.haze_horizon, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.haze_density, b.haze_density, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.blue_horizon, b.blue_horizon, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.blue_density, b.blue_density, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.dome_offset, b.dome_offset, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.dome_radius, b.dome_radius, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.cloud_shadow, b.cloud_shadow, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.glow, b.glow, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.ambient, b.ambient, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.sunlight, b.sunlight, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.sun_norm, b.sun_norm, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.gamma, b.gamma, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.max_y, b.max_y, fraction_treshold))
- {
- return false;
- }
-
- if (!approximatelyEqual(a.distance_multiplier, b.distance_multiplier, fraction_treshold))
- {
- return false;
- }
-
- // light_atten, light_transmittance, total_density
- // are ignored as they always change when the values above do
- // they're just shared calc across the sky map generation to save cycles
-
- return true;
-}
-
+/**
+ * @file lllegacyatmospherics.cpp
+ * @brief LLAtmospherics class implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lllegacyatmospherics.h"
+
+#include "llfeaturemanager.h"
+#include "llviewercontrol.h"
+#include "llframetimer.h"
+
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "lldrawable.h"
+#include "llface.h"
+#include "llglheaders.h"
+#include "llsky.h"
+#include "llviewercamera.h"
+#include "llviewertexturelist.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llworld.h"
+#include "pipeline.h"
+#include "v3colorutil.h"
+
+#include "llsettingssky.h"
+#include "llenvironment.h"
+#include "lldrawpoolwater.h"
+
+class LLFastLn
+{
+public:
+ LLFastLn()
+ {
+ mTable[0] = 0;
+ for( S32 i = 1; i < 257; i++ )
+ {
+ mTable[i] = log((F32)i);
+ }
+ }
+
+ F32 ln( F32 x )
+ {
+ const F32 OO_255 = 0.003921568627450980392156862745098f;
+ const F32 LN_255 = 5.5412635451584261462455391880218f;
+
+ if( x < OO_255 )
+ {
+ return log(x);
+ }
+ else
+ if( x < 1 )
+ {
+ x *= 255.f;
+ S32 index = llfloor(x);
+ F32 t = x - index;
+ F32 low = mTable[index];
+ F32 high = mTable[index + 1];
+ return low + t * (high - low) - LN_255;
+ }
+ else
+ if( x <= 255 )
+ {
+ S32 index = llfloor(x);
+ F32 t = x - index;
+ F32 low = mTable[index];
+ F32 high = mTable[index + 1];
+ return low + t * (high - low);
+ }
+ else
+ {
+ return log( x );
+ }
+ }
+
+ F32 pow( F32 x, F32 y )
+ {
+ return (F32)LL_FAST_EXP(y * ln(x));
+ }
+
+
+private:
+ F32 mTable[257]; // index 0 is unused
+};
+
+static LLFastLn gFastLn;
+
+
+// Functions used a lot.
+
+inline F32 LLHaze::calcPhase(const F32 cos_theta) const
+{
+ const F32 g2 = mG * mG;
+ const F32 den = 1 + g2 - 2 * mG * cos_theta;
+ return (1 - g2) * gFastLn.pow(den, -1.5);
+}
+
+inline void color_pow(LLColor3 &col, const F32 e)
+{
+ col.mV[0] = gFastLn.pow(col.mV[0], e);
+ col.mV[1] = gFastLn.pow(col.mV[1], e);
+ col.mV[2] = gFastLn.pow(col.mV[2], e);
+}
+
+inline LLColor3 color_norm(const LLColor3 &col)
+{
+ const F32 m = color_max(col);
+ if (m > 1.f)
+ {
+ return 1.f/m * col;
+ }
+ else return col;
+}
+
+inline void color_gamma_correct(LLColor3 &col)
+{
+ const F32 gamma_inv = 1.f/1.2f;
+ if (col.mV[0] != 0.f)
+ {
+ col.mV[0] = gFastLn.pow(col.mV[0], gamma_inv);
+ }
+ if (col.mV[1] != 0.f)
+ {
+ col.mV[1] = gFastLn.pow(col.mV[1], gamma_inv);
+ }
+ if (col.mV[2] != 0.f)
+ {
+ col.mV[2] = gFastLn.pow(col.mV[2], gamma_inv);
+ }
+}
+
+static LLColor3 calc_air_sca_sea_level()
+{
+ static LLColor3 WAVE_LEN(675, 520, 445);
+ static LLColor3 refr_ind = refr_ind_calc(WAVE_LEN);
+ static LLColor3 n21 = refr_ind * refr_ind - LLColor3(1, 1, 1);
+ static LLColor3 n4 = n21 * n21;
+ static LLColor3 wl2 = WAVE_LEN * WAVE_LEN * 1e-6f;
+ static LLColor3 wl4 = wl2 * wl2;
+ static LLColor3 mult_const = fsigma * 2.0f/ 3.0f * 1e24f * (F_PI * F_PI) * n4;
+ static F32 dens_div_N = F32( ATM_SEA_LEVEL_NDENS / Ndens2);
+ return dens_div_N * mult_const.divide(wl4);
+}
+
+// static constants.
+LLColor3 const LLHaze::sAirScaSeaLevel = calc_air_sca_sea_level();
+F32 const LLHaze::sAirScaIntense = color_intens(LLHaze::sAirScaSeaLevel);
+F32 const LLHaze::sAirScaAvg = LLHaze::sAirScaIntense / 3.f;
+
+/***************************************
+ Atmospherics
+***************************************/
+
+LLAtmospherics::LLAtmospherics()
+: mCloudDensity(0.2f),
+ mWind(0.f),
+ mWorldScale(1.f)
+{
+ /// WL PARAMS
+ mInitialized = false;
+ mAmbientScale = gSavedSettings.getF32("SkyAmbientScale");
+ mNightColorShift = gSavedSettings.getColor3("SkyNightColorShift");
+ mFogColor.mV[VRED] = mFogColor.mV[VGREEN] = mFogColor.mV[VBLUE] = 0.5f;
+ mFogColor.mV[VALPHA] = 0.0f;
+ mFogRatio = 1.2f;
+ mHazeConcentration = 0.f;
+ mInterpVal = 0.f;
+}
+
+
+LLAtmospherics::~LLAtmospherics()
+{
+}
+
+void LLAtmospherics::init()
+{
+ const F32 haze_int = color_intens(mHaze.calcSigSca(0));
+ mHazeConcentration = haze_int / (color_intens(mHaze.calcAirSca(0)) + haze_int);
+ mInitialized = true;
+}
+
+// This cubemap is used as "environmentMap" in indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny, bool low_end)
+{
+ const F32 sky_saturation = 0.25f;
+ const F32 land_saturation = 0.1f;
+
+ if (isShiny && dir.mV[VZ] < -0.02f)
+ {
+ LLColor4 col;
+ LLColor3 desat_fog = LLColor3(mFogColor);
+ F32 brightness = desat_fog.brightness();// NOTE: Linear brightness!
+ // So that shiny somewhat shows up at night.
+ if (brightness < 0.15f)
+ {
+ brightness = 0.15f;
+ desat_fog = smear(0.15f);
+ }
+ F32 greyscale_sat = brightness * (1.0f - land_saturation);
+ desat_fog = desat_fog * land_saturation + smear(greyscale_sat);
+ if (low_end)
+ {
+ col = LLColor4(desat_fog, 0.f);
+ }
+ else
+ {
+ col = LLColor4(desat_fog * 0.5f, 0.f);
+ }
+ float x = 1.0f-fabsf(-0.1f-dir.mV[VZ]);
+ x *= x;
+ col.mV[0] *= x*x;
+ col.mV[1] *= powf(x, 2.5f);
+ col.mV[2] *= x*x*x;
+ return col;
+ }
+
+ // undo OGL_TO_CFR_ROTATION and negate vertical direction.
+ LLVector3 Pn = LLVector3(-dir[1] , -dir[2], -dir[0]);
+
+ //calculates hazeColor
+ calcSkyColorWLVert(psky, Pn, vars);
+
+ if (isShiny)
+ {
+ F32 brightness = vars.hazeColor.brightness();
+ F32 greyscale_sat = brightness * (1.0f - sky_saturation);
+ LLColor3 sky_color = vars.hazeColor * sky_saturation + smear(greyscale_sat);
+ //sky_color *= (0.5f + 0.5f * brightness); // SL-12574 EEP sky is being attenuated too much
+ return LLColor4(sky_color, 0.0f);
+ }
+
+ LLColor3 sky_color = low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f, vars.gamma);
+
+ return LLColor4(sky_color, 0.0f);
+}
+
+// NOTE: Keep these in sync!
+// indra\newview\app_settings\shaders\class1\deferred\skyV.glsl
+// indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl
+// indra\newview\lllegacyatmospherics.cpp
+void LLAtmospherics::calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars)
+{
+ const LLColor3 blue_density = vars.blue_density;
+ const LLColor3 blue_horizon = vars.blue_horizon;
+ const F32 haze_horizon = vars.haze_horizon;
+ const F32 haze_density = vars.haze_density;
+ const F32 density_multiplier = vars.density_multiplier;
+
+ F32 max_y = vars.max_y;
+ LLVector4 sun_norm = vars.sun_norm;
+
+ // project the direction ray onto the sky dome.
+ F32 phi = acos(Pn[1]);
+ F32 sinA = sin(F_PI - phi);
+ if (fabsf(sinA) < 0.01f)
+ { //avoid division by zero
+ sinA = 0.01f;
+ }
+
+ F32 Plen = vars.dome_radius * sin(F_PI + phi + asin(vars.dome_offset * sinA)) / sinA;
+
+ Pn *= Plen;
+
+ // Set altitude
+ if (Pn[1] > 0.f)
+ {
+ Pn *= (max_y / Pn[1]);
+ }
+ else
+ {
+ Pn *= (-32000.f / Pn[1]);
+ }
+
+ Plen = Pn.length();
+ Pn /= Plen;
+
+ // Initialize temp variables
+ LLColor3 sunlight = vars.sunlight;
+ LLColor3 ambient = vars.ambient;
+
+ LLColor3 glow = vars.glow;
+ F32 cloud_shadow = vars.cloud_shadow;
+
+ // Sunlight attenuation effect (hue and brightness) due to atmosphere
+ // this is used later for sunlight modulation at various altitudes
+ LLColor3 light_atten = vars.light_atten;
+ LLColor3 light_transmittance = psky->getLightTransmittanceFast(vars.total_density, vars.density_multiplier, Plen);
+ (void)light_transmittance; // silence Clang warn-error
+
+ // Calculate relative weights
+ LLColor3 temp2(0.f, 0.f, 0.f);
+ LLColor3 temp1 = vars.total_density;
+
+ LLColor3 blue_weight = componentDiv(blue_density, temp1);
+ LLColor3 blue_factor = blue_horizon * blue_weight;
+ LLColor3 haze_weight = componentDiv(smear(haze_density), temp1);
+ LLColor3 haze_factor = haze_horizon * haze_weight;
+
+
+ // Compute sunlight from P & lightnorm (for long rays like sky)
+ temp2.mV[1] = llmax(F_APPROXIMATELY_ZERO, llmax(0.f, Pn[1]) * 1.0f + sun_norm.mV[1] );
+
+ temp2.mV[1] = 1.f / temp2.mV[1];
+ componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
+ componentMultBy(sunlight, light_transmittance);
+
+ // Distance
+ temp2.mV[2] = Plen * density_multiplier;
+
+ // Transparency (-> temp1)
+ temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]);
+
+ // Compute haze glow
+ temp2.mV[0] = Pn * LLVector3(sun_norm);
+
+ temp2.mV[0] = 1.f - temp2.mV[0];
+ // temp2.x is 0 at the sun and increases away from sun
+ temp2.mV[0] = llmax(temp2.mV[0], .001f);
+ // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+
+ // Higher glow.x gives dimmer glow (because next step is 1 / "angle")
+ temp2.mV[0] *= glow.mV[0];
+
+ temp2.mV[0] = pow(temp2.mV[0], glow.mV[2]);
+ // glow.z should be negative, so we're doing a sort of (1 / "angle") function
+
+ // Add "minimum anti-solar illumination"
+ temp2.mV[0] += .25f;
+
+
+ // Haze color above cloud
+ vars.hazeColor = (blue_factor * (sunlight + ambient) + componentMult(haze_factor, sunlight * temp2.mV[0] + ambient));
+
+ // Increase ambient when there are more clouds
+ LLColor3 tmpAmbient = ambient + (LLColor3::white - ambient) * cloud_shadow * 0.5f;
+
+ // Dim sunlight by cloud shadow percentage
+ sunlight *= (1.f - cloud_shadow);
+
+ // Haze color below cloud
+ vars.hazeColorBelowCloud = (blue_factor * (sunlight + tmpAmbient) + componentMult(haze_factor, sunlight * temp2.mV[0] + tmpAmbient));
+
+ // Final atmosphere additive
+ componentMultBy(vars.hazeColor, LLColor3::white - temp1);
+
+/*
+ // SL-12574
+
+ // Attenuate cloud color by atmosphere
+ temp1 = componentSqrt(temp1); //less atmos opacity (more transparency) below clouds
+
+ // At horizon, blend high altitude sky color towards the darker color below the clouds
+ vars.hazeColor += componentMult(vars.hazeColorBelowCloud - vars.hazeColor, LLColor3::white - componentSqrt(temp1));
+*/
+}
+
+void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
+{
+ LLVector3 tosun = tosun_in;
+
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG))
+ {
+ return;
+ }
+
+ LLColor4 target_fog(0.f, 0.2f, 0.5f, 0.f);
+
+ const F32 water_height = gAgent.getRegion() ? gAgent.getRegion()->getWaterHeight() : 0.f;
+ // LLWorld::getInstance()->getWaterHeight();
+ F32 camera_height = gAgentCamera.getCameraPositionAgent().mV[2];
+
+ F32 near_clip_height = LLViewerCamera::getInstance()->getAtAxis().mV[VZ] * LLViewerCamera::getInstance()->getNear();
+ camera_height += near_clip_height;
+
+ F32 fog_distance = 0.f;
+ LLColor3 res_color[3];
+
+ LLColor3 sky_fog_color = LLColor3::white;
+ LLColor3 render_fog_color = LLColor3::white;
+
+ const F32 tosun_z = tosun.mV[VZ];
+ tosun.mV[VZ] = 0.f;
+ tosun.normalize();
+ LLVector3 perp_tosun;
+ perp_tosun.mV[VX] = -tosun.mV[VY];
+ perp_tosun.mV[VY] = tosun.mV[VX];
+ LLVector3 tosun_45 = tosun + perp_tosun;
+ tosun_45.normalize();
+
+ F32 delta = 0.06f;
+ tosun.mV[VZ] = delta;
+ perp_tosun.mV[VZ] = delta;
+ tosun_45.mV[VZ] = delta;
+ tosun.normalize();
+ perp_tosun.normalize();
+ tosun_45.normalize();
+
+ // Sky colors, just slightly above the horizon in the direction of the sun, perpendicular to the sun, and at a 45 degree angle to the sun.
+ AtmosphericsVars vars;
+
+ LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+
+ // NOTE: This is very similar to LLVOSky::cacheEnvironment()
+ // Differences:
+ // vars.sun_norm
+ // vars.sunlight
+ // invariants across whole sky tex process...
+ vars.blue_density = psky->getBlueDensity();
+ vars.blue_horizon = psky->getBlueHorizon();
+ vars.haze_density = psky->getHazeDensity();
+ vars.haze_horizon = psky->getHazeHorizon();
+ vars.density_multiplier = psky->getDensityMultiplier();
+ vars.distance_multiplier = psky->getDistanceMultiplier();
+ vars.max_y = psky->getMaxY();
+ vars.sun_norm = LLEnvironment::instance().getSunDirectionCFR();
+ vars.sunlight = psky->getSunlightColor();
+ vars.ambient = psky->getAmbientColor();
+ vars.glow = psky->getGlow();
+ vars.cloud_shadow = psky->getCloudShadow();
+ vars.dome_radius = psky->getDomeRadius();
+ vars.dome_offset = psky->getDomeOffset();
+ vars.light_atten = psky->getLightAttenuation(vars.max_y);
+ vars.light_transmittance = psky->getLightTransmittance(vars.max_y);
+ vars.total_density = psky->getTotalDensity();
+ vars.gamma = psky->getGamma();
+
+ res_color[0] = calcSkyColorInDir(psky, vars, tosun);
+ res_color[1] = calcSkyColorInDir(psky, vars, perp_tosun);
+ res_color[2] = calcSkyColorInDir(psky, vars, tosun_45);
+
+ sky_fog_color = color_norm(res_color[0] + res_color[1] + res_color[2]);
+
+ F32 full_off = -0.25f;
+ F32 full_on = 0.00f;
+ F32 on = (tosun_z - full_off) / (full_on - full_off);
+ on = llclamp(on, 0.01f, 1.f);
+ sky_fog_color *= 0.5f * on;
+
+
+ // We need to clamp these to non-zero, in order for the gamma correction to work. 0^y = ???
+ S32 i;
+ for (i = 0; i < 3; i++)
+ {
+ sky_fog_color.mV[i] = llmax(0.0001f, sky_fog_color.mV[i]);
+ }
+
+ color_gamma_correct(sky_fog_color);
+
+ render_fog_color = sky_fog_color;
+
+ fog_distance = mFogRatio * distance;
+
+ if (camera_height > water_height)
+ {
+ LLColor4 fog(render_fog_color);
+ mGLFogCol = fog;
+ }
+ else
+ {
+ LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
+ F32 depth = water_height - camera_height;
+ LLColor4 water_fog_color(pwater->getWaterFogColor());
+
+ // adjust the color based on depth. We're doing linear approximations
+ float depth_scale = gSavedSettings.getF32("WaterGLFogDepthScale");
+ float depth_modifier = 1.0f - llmin(llmax(depth / depth_scale, 0.01f),
+ gSavedSettings.getF32("WaterGLFogDepthFloor"));
+
+ LLColor4 fogCol = water_fog_color * depth_modifier;
+ fogCol.setAlpha(1);
+
+ // set the gl fog color
+ mGLFogCol = fogCol;
+ }
+
+ mFogColor = sky_fog_color;
+ mFogColor.setAlpha(1);
+
+ LLDrawPoolWater::sWaterFogEnd = fog_distance*2.2f;
+
+ stop_glerror();
+}
+
+// Functions used a lot.
+F32 color_norm_pow(LLColor3& col, F32 e, bool postmultiply)
+{
+ F32 mv = color_max(col);
+ if (0 == mv)
+ {
+ return 0;
+ }
+
+ col *= 1.f / mv;
+ color_pow(col, e);
+ if (postmultiply)
+ {
+ col *= mv;
+ }
+ return mv;
+}
+
+// Returns angle (RADIANs) between the horizontal projection of "v" and the x_axis.
+// Range of output is 0.0f to 2pi //359.99999...f
+// Returns 0.0f when "v" = +/- z_axis.
+F32 azimuth(const LLVector3 &v)
+{
+ F32 azimuth = 0.0f;
+ if (v.mV[VX] == 0.0f)
+ {
+ if (v.mV[VY] > 0.0f)
+ {
+ azimuth = F_PI * 0.5f;
+ }
+ else if (v.mV[VY] < 0.0f)
+ {
+ azimuth = F_PI * 1.5f;// 270.f;
+ }
+ }
+ else
+ {
+ azimuth = (F32) atan(v.mV[VY] / v.mV[VX]);
+ if (v.mV[VX] < 0.0f)
+ {
+ azimuth += F_PI;
+ }
+ else if (v.mV[VY] < 0.0f)
+ {
+ azimuth += F_PI * 2;
+ }
+ }
+ return azimuth;
+}
+
+bool operator==(const AtmosphericsVars& a, const AtmosphericsVars& b)
+{
+ if (a.hazeColor != b.hazeColor)
+ {
+ return false;
+ }
+
+ if (a.hazeColorBelowCloud != b.hazeColorBelowCloud)
+ {
+ return false;
+ }
+
+ if (a.cloudColorSun != b.cloudColorSun)
+ {
+ return false;
+ }
+
+ if (a.cloudColorAmbient != b.cloudColorAmbient)
+ {
+ return false;
+ }
+
+ if (a.cloudDensity != b.cloudDensity)
+ {
+ return false;
+ }
+
+ if (a.density_multiplier != b.density_multiplier)
+ {
+ return false;
+ }
+
+ if (a.haze_horizon != b.haze_horizon)
+ {
+ return false;
+ }
+
+ if (a.haze_density != b.haze_density)
+ {
+ return false;
+ }
+
+ if (a.blue_horizon != b.blue_horizon)
+ {
+ return false;
+ }
+
+ if (a.blue_density != b.blue_density)
+ {
+ return false;
+ }
+
+ if (a.dome_offset != b.dome_offset)
+ {
+ return false;
+ }
+
+ if (a.dome_radius != b.dome_radius)
+ {
+ return false;
+ }
+
+ if (a.cloud_shadow != b.cloud_shadow)
+ {
+ return false;
+ }
+
+ if (a.glow != b.glow)
+ {
+ return false;
+ }
+
+ if (a.ambient != b.ambient)
+ {
+ return false;
+ }
+
+ if (a.sunlight != b.sunlight)
+ {
+ return false;
+ }
+
+ if (a.sun_norm != b.sun_norm)
+ {
+ return false;
+ }
+
+ if (a.gamma != b.gamma)
+ {
+ return false;
+ }
+
+ if (a.max_y != b.max_y)
+ {
+ return false;
+ }
+
+ if (a.distance_multiplier != b.distance_multiplier)
+ {
+ return false;
+ }
+
+ // light_atten, light_transmittance, total_density
+ // are ignored as they always change when the values above do
+ // they're just shared calc across the sky map generation to save cycles
+
+ return true;
+}
+
+bool approximatelyEqual(const F32 &a, const F32 &b, const F32 &fraction_treshold)
+{
+ F32 diff = fabs(a - b);
+ if (diff < F_APPROXIMATELY_ZERO || diff < llmax(fabs(a), fabs(b)) * fraction_treshold)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool approximatelyEqual(const LLColor3 &a, const LLColor3 &b, const F32 &fraction_treshold)
+{
+ return approximatelyEqual(a.mV[0], b.mV[0], fraction_treshold)
+ && approximatelyEqual(a.mV[1], b.mV[1], fraction_treshold)
+ && approximatelyEqual(a.mV[2], b.mV[2], fraction_treshold);
+}
+
+bool approximatelyEqual(const LLVector4 &a, const LLVector4 &b, const F32 &fraction_treshold)
+{
+ return approximatelyEqual(a.mV[0], b.mV[0], fraction_treshold)
+ && approximatelyEqual(a.mV[1], b.mV[1], fraction_treshold)
+ && approximatelyEqual(a.mV[2], b.mV[2], fraction_treshold)
+ && approximatelyEqual(a.mV[3], b.mV[3], fraction_treshold);
+}
+
+bool approximatelyEqual(const AtmosphericsVars& a, const AtmosphericsVars& b, const F32 fraction_treshold)
+{
+ if (!approximatelyEqual(a.hazeColor, b.hazeColor, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.hazeColorBelowCloud, b.hazeColorBelowCloud, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.cloudColorSun, b.cloudColorSun, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.cloudColorAmbient, b.cloudColorAmbient, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.cloudDensity, b.cloudDensity, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.density_multiplier, b.density_multiplier, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.haze_horizon, b.haze_horizon, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.haze_density, b.haze_density, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.blue_horizon, b.blue_horizon, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.blue_density, b.blue_density, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.dome_offset, b.dome_offset, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.dome_radius, b.dome_radius, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.cloud_shadow, b.cloud_shadow, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.glow, b.glow, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.ambient, b.ambient, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.sunlight, b.sunlight, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.sun_norm, b.sun_norm, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.gamma, b.gamma, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.max_y, b.max_y, fraction_treshold))
+ {
+ return false;
+ }
+
+ if (!approximatelyEqual(a.distance_multiplier, b.distance_multiplier, fraction_treshold))
+ {
+ return false;
+ }
+
+ // light_atten, light_transmittance, total_density
+ // are ignored as they always change when the values above do
+ // they're just shared calc across the sky map generation to save cycles
+
+ return true;
+}
+