From 62a0d579b5eb23ea306ade07afba76f7cba685c7 Mon Sep 17 00:00:00 2001
From: "Graham Linden graham@lindenlab.com"
 <Graham Linden graham@lindenlab.com>
Date: Wed, 7 Mar 2018 18:37:09 +0000
Subject: [PATCH] Move legacy atmospherics code outside of llvosky (begin
 teasing apart).

---
 indra/llinventory/llsettingssky.cpp    |  57 +-
 indra/llmath/v3color.h                 |  17 +
 indra/newview/CMakeLists.txt           |   1 +
 indra/newview/llenvadapters.cpp        |  10 -
 indra/newview/llenvadapters.h          |  11 -
 indra/newview/llfloatereditsky.cpp     |  43 +-
 indra/newview/lllegacyatmospherics.cpp | 649 +++++++++++++++++++++
 indra/newview/lllegacyatmospherics.h   | 256 ++++++++
 indra/newview/llsettingsvo.cpp         |  13 +-
 indra/newview/llvosky.cpp              | 778 ++-----------------------
 indra/newview/llvosky.h                | 236 +-------
 11 files changed, 1012 insertions(+), 1059 deletions(-)
 create mode 100644 indra/newview/lllegacyatmospherics.cpp
 create mode 100644 indra/newview/lllegacyatmospherics.h

diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index cac363b5107..3366f1a20ab 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -383,29 +383,27 @@ LLSettingsSky::validation_list_t LLSettingsSky::validationList()
         // copy constructor for LLSDArray.  Directly binding the LLSDArray as 
         // a parameter without first wrapping it in a pure LLSD object will result 
         // in deeply nested arrays like this [[[[[[[[[[v1,v2,v3]]]]]]]]]]
-
-// LEGACY_ATMOSPHERICS
-        validation.push_back(Validator(SETTING_AMBIENT, true, LLSD::TypeArray,
-            boost::bind(&Validator::verifyVectorMinMax, _1,
-                LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
-                LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
-        validation.push_back(Validator(SETTING_BLUE_DENSITY,        true,  LLSD::TypeArray, 
+        validation.push_back(Validator(SETTING_BLUE_DENSITY,        false,  LLSD::TypeArray, 
             boost::bind(&Validator::verifyVectorMinMax, _1,
                 LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
                 LLSD(LLSDArray(2.0f)(2.0f)(2.0f)("*")))));
-        validation.push_back(Validator(SETTING_BLUE_HORIZON,        true,  LLSD::TypeArray, 
+        validation.push_back(Validator(SETTING_BLUE_HORIZON,        false,  LLSD::TypeArray, 
             boost::bind(&Validator::verifyVectorMinMax, _1,
                 LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
                 LLSD(LLSDArray(2.0f)(2.0f)(2.0f)("*")))));
-        validation.push_back(Validator(SETTING_DENSITY_MULTIPLIER,  true,  LLSD::TypeReal,  
-            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(0.0009f)))));
-        validation.push_back(Validator(SETTING_DISTANCE_MULTIPLIER, true,  LLSD::TypeReal,  
-            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(100.0f)))));
-        validation.push_back(Validator(SETTING_HAZE_DENSITY,        true,  LLSD::TypeReal,  
+        validation.push_back(Validator(SETTING_HAZE_DENSITY,        false,  LLSD::TypeReal,  
             boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(4.0f)))));
-        validation.push_back(Validator(SETTING_HAZE_HORIZON,        true,  LLSD::TypeReal,  
+        validation.push_back(Validator(SETTING_HAZE_HORIZON,        false,  LLSD::TypeReal,  
             boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+        validation.push_back(Validator(SETTING_AMBIENT, false, LLSD::TypeArray,
+            boost::bind(&Validator::verifyVectorMinMax, _1,
+                LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
+                LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
+        validation.push_back(Validator(SETTING_DENSITY_MULTIPLIER,  false,  LLSD::TypeReal,  
+            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(0.0009f)))));
+        validation.push_back(Validator(SETTING_DISTANCE_MULTIPLIER, false,  LLSD::TypeReal,  
 
+            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(100.0f)))));
         validation.push_back(Validator(SETTING_BLOOM_TEXTUREID,     true,  LLSD::TypeUUID));
         validation.push_back(Validator(SETTING_CLOUD_COLOR,         true,  LLSD::TypeArray, 
             boost::bind(&Validator::verifyVectorMinMax, _1,
@@ -614,21 +612,6 @@ LLSD LLSettingsSky::translateLegacySettings(LLSD legacy)
         newsettings[SETTING_HAZE_HORIZON] = LLSD::Real(legacy[SETTING_HAZE_HORIZON][0].asReal());
     }
 
-    if (!legacy.has(SETTING_RAYLEIGH_CONFIG))
-    {
-        newsettings[SETTING_RAYLEIGH_CONFIG].append(rayleighConfigDefault());
-    }
-
-    if (!legacy.has(SETTING_ABSORPTION_CONFIG))
-    {
-        newsettings[SETTING_ABSORPTION_CONFIG].append(absorptionConfigDefault());
-    }
-
-    if (!legacy.has(SETTING_MIE_CONFIG))
-    {
-        newsettings[SETTING_MIE_CONFIG].append(mieConfigDefault());
-    }
-
     if (legacy.has(SETTING_CLOUD_COLOR))
     {
         newsettings[SETTING_CLOUD_COLOR] = LLColor3(legacy[SETTING_CLOUD_COLOR]).getValue();
@@ -696,37 +679,21 @@ LLSD LLSettingsSky::translateLegacySettings(LLSD legacy)
     {
         newsettings[SETTING_PLANET_RADIUS] = LLSD::Real(legacy[SETTING_PLANET_RADIUS].asReal());
     }
-    else
-    {
-        newsettings[SETTING_PLANET_RADIUS] = 6360.0f;
-    }
 
     if (legacy.has(SETTING_SKY_BOTTOM_RADIUS))
     {
         newsettings[SETTING_SKY_BOTTOM_RADIUS] = LLSD::Real(legacy[SETTING_SKY_BOTTOM_RADIUS].asReal());
     }
-    else
-    {
-        newsettings[SETTING_SKY_BOTTOM_RADIUS] = 6360.0f;
-    }
 
     if (legacy.has(SETTING_SKY_TOP_RADIUS))
     {
         newsettings[SETTING_SKY_TOP_RADIUS] = LLSD::Real(legacy[SETTING_SKY_TOP_RADIUS].asReal());
     }
-    else
-    {
-        newsettings[SETTING_SKY_TOP_RADIUS] = 6420.0f;
-    }
 
     if (legacy.has(SETTING_SUN_ARC_RADIANS))
     {
         newsettings[SETTING_SUN_ARC_RADIANS] = LLSD::Real(legacy[SETTING_SUN_ARC_RADIANS].asReal());
     }
-    else
-    {
-        newsettings[SETTING_SUN_ARC_RADIANS] = 0.00935f / 2.0f;
-    }
 
     if (legacy.has(SETTING_LEGACY_EAST_ANGLE) && legacy.has(SETTING_LEGACY_SUN_ANGLE))
     {   // convert the east and sun angles into a quaternion.
diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h
index daf3a6857b4..41dbdb8cd50 100644
--- a/indra/llmath/v3color.h
+++ b/indra/llmath/v3color.h
@@ -100,6 +100,23 @@ class LLColor3
 
 	const LLColor3&	operator=(const LLColor4 &a);
 	
+    LL_FORCE_INLINE LLColor3 divide(const LLColor3 &col2)
+    {
+        return LLColor3(
+                mV[0] / col2.mV[0],
+                mV[1] / col2.mV[1],
+                mV[2] / col2.mV[2] );
+    }
+
+    LL_FORCE_INLINE LLColor3 color_norm()
+    {
+        F32 l = length();
+        return LLColor3(
+                mV[0] / l,
+                mV[1] / l,
+                mV[2] / l );
+    }
+
 	friend std::ostream&	 operator<<(std::ostream& s, const LLColor3 &a);		// Print a
 	friend LLColor3 operator+(const LLColor3 &a, const LLColor3 &b);	// Return vector a + b
 	friend LLColor3 operator-(const LLColor3 &a, const LLColor3 &b);	// Return vector a minus b
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1a19e81010e..a1fbcf9451c 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -365,6 +365,7 @@ set(viewer_SOURCE_FILES
     lljoystickbutton.cpp
     lllandmarkactions.cpp
     lllandmarklist.cpp
+    lllegacyatmospherics.cpp
     lllistbrowser.cpp
     lllistcontextmenu.cpp
     lllistview.cpp
diff --git a/indra/newview/llenvadapters.cpp b/indra/newview/llenvadapters.cpp
index 57c7a75d52e..fdbcf68fa44 100644
--- a/indra/newview/llenvadapters.cpp
+++ b/indra/newview/llenvadapters.cpp
@@ -33,16 +33,6 @@
 
 LLSkySettingsAdapter::LLSkySettingsAdapter():
     mWLGamma(1.0f, LLSettingsSky::SETTING_GAMMA),
-
-// LEGACY_ATMOSPHERICS
-    mAmbient(LLColor4(0.5f, 0.75f, 1.0f, 1.19f), LLSettingsSky::SETTING_AMBIENT, "WLAmbient"),
-    mBlueHorizon(LLColor4(0.25f, 0.25f, 1.0f, 1.0f), LLSettingsSky::SETTING_BLUE_HORIZON, "WLBlueHorizon"),
-    mBlueDensity(LLColor4(0.25f, 0.25f, 0.25f, 1.0f), LLSettingsSky::SETTING_BLUE_DENSITY, "WLBlueDensity"),
-    mHazeDensity(1.0f, LLSettingsSky::SETTING_HAZE_DENSITY),
-    mHazeHorizon(1.0f, LLSettingsSky::SETTING_HAZE_HORIZON),    
-    mDensityMult(1.0f, LLSettingsSky::SETTING_DENSITY_MULTIPLIER, 1000),
-    mDistanceMult(1.0f, LLSettingsSky::SETTING_DISTANCE_MULTIPLIER),
-    mMaxAlt(4000.0f, LLSettingsSky::SETTING_MAX_Y),
     
     // Lighting
     mLightnorm(LLColor4(0.f, 0.707f, -0.707f, 1.f), LLSettingsSky::SETTING_LIGHT_NORMAL),
diff --git a/indra/newview/llenvadapters.h b/indra/newview/llenvadapters.h
index c53423c5aeb..bd58db0589e 100644
--- a/indra/newview/llenvadapters.h
+++ b/indra/newview/llenvadapters.h
@@ -418,17 +418,6 @@ class LLSkySettingsAdapter
 
     WLFloatControl  mWLGamma;
 
-    /// Atmospherics
-// LEGACY_ATMOSPHERICS
-    WLColorControl  mAmbient;
-    WLColorControl  mBlueHorizon;
-    WLFloatControl  mHazeDensity;
-    WLColorControl  mBlueDensity;
-    WLFloatControl  mDensityMult;
-    WLFloatControl  mDistanceMult;
-    WLFloatControl  mHazeHorizon;
-    WLFloatControl  mMaxAlt;
-
     /// Lighting
     WLColorControl  mLightnorm;
     WLColorControl  mSunlight;    
diff --git a/indra/newview/llfloatereditsky.cpp b/indra/newview/llfloatereditsky.cpp
index 763f9e4d5ac..6bdc5ee8233 100644
--- a/indra/newview/llfloatereditsky.cpp
+++ b/indra/newview/llfloatereditsky.cpp
@@ -151,22 +151,6 @@ void LLFloaterEditSky::initCallbacks(void)
 	// Connect to region info updates.
 	LLRegionInfoModel::instance().setUpdateCallback(boost::bind(&LLFloaterEditSky::onRegionInfoUpdate, this));
 
-	//-------------------------------------------------------------------------
-// LEGACY_ATMOSPHERICS
-    // ambient
-    getChild<LLUICtrl>("WLAmbient")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, &mSkyAdapter->mAmbient));
-
-	// blue horizon/density
-	getChild<LLUICtrl>("WLBlueHorizon")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, &mSkyAdapter->mBlueHorizon));
-    getChild<LLUICtrl>("WLBlueDensity")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, &mSkyAdapter->mBlueDensity));
-
-	// haze density, horizon, mult, and altitude
-    getChild<LLUICtrl>("WLHazeDensity")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, &mSkyAdapter->mHazeDensity));
-    getChild<LLUICtrl>("WLHazeHorizon")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, &mSkyAdapter->mHazeHorizon));
-    getChild<LLUICtrl>("WLDensityMult")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, &mSkyAdapter->mDensityMult));
-    getChild<LLUICtrl>("WLDistanceMult")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, &mSkyAdapter->mDistanceMult));
-    getChild<LLUICtrl>("WLMaxAltitude")->setCommitCallback(boost::bind(&LLFloaterEditSky::onFloatControlMoved, this, _1, &mSkyAdapter->mMaxAlt));
-
 	// sunlight
     getChild<LLUICtrl>("WLSunlight")->setCommitCallback(boost::bind(&LLFloaterEditSky::onColorControlMoved, this, _1, &mSkyAdapter->mSunlight));
 
@@ -220,29 +204,6 @@ void LLFloaterEditSky::syncControls()
     mSkyPresetNameEditor->setText(name);
     mSkyPresetCombo->setValue(name);
 
-// LEGACY_ATMOSPHERICS
-    // ambient
-    mSkyAdapter->mAmbient.setColor3( psky->getAmbientColor() );
-	setColorSwatch("WLAmbient", mSkyAdapter->mAmbient, WL_SUN_AMBIENT_SLIDER_SCALE);
-
-	// blue horizon / density
-	mSkyAdapter->mBlueHorizon.setColor3( psky->getBlueHorizon() );
-	setColorSwatch("WLBlueHorizon", mSkyAdapter->mBlueHorizon, WL_BLUE_HORIZON_DENSITY_SCALE);
-    mSkyAdapter->mBlueDensity.setColor3( psky->getBlueDensity() );
-	setColorSwatch("WLBlueDensity", mSkyAdapter->mBlueDensity, WL_BLUE_HORIZON_DENSITY_SCALE);
-
-	// haze density, horizon, mult, and altitude
-    mSkyAdapter->mHazeDensity = psky->getHazeDensity();
-	childSetValue("WLHazeDensity", (F32) mSkyAdapter->mHazeDensity);
-    mSkyAdapter->mHazeHorizon = psky->getHazeHorizon();
-	childSetValue("WLHazeHorizon", (F32) mSkyAdapter->mHazeHorizon);
-    mSkyAdapter->mDensityMult = psky->getDensityMultiplier();
-	childSetValue("WLDensityMult", ((F32) mSkyAdapter->mDensityMult) * mSkyAdapter->mDensityMult.getMult());
-    mSkyAdapter->mMaxAlt = psky->getMaxY();
-    mSkyAdapter->mDistanceMult = psky->getDistanceMultiplier();
-	childSetValue("WLDistanceMult", (F32) mSkyAdapter->mDistanceMult);
-	childSetValue("WLMaxAltitude", (F32) mSkyAdapter->mMaxAlt);
-
 	// Lighting
 
 	// sunlight
@@ -254,9 +215,7 @@ void LLFloaterEditSky::syncControls()
 	childSetValue("WLGlowR", 2 - mSkyAdapter->mGlow.getRed() / 20.0f);
 	childSetValue("WLGlowB", -mSkyAdapter->mGlow.getBlue() / 5.0f);
 
-	
-
-//     LLSettingsSky::azimalt_t azal = psky->getSunRotationAzAl();
+// LLSettingsSky::azimalt_t azal = psky->getSunRotationAzAl();
 // 
 // 	F32 time24 = sun_pos_to_time24(azal.second / F_TWO_PI);
 // 	getChild<LLMultiSliderCtrl>("WLSunPos")->setCurSliderValue(time24, TRUE);
diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp
new file mode 100644
index 00000000000..a589ef0a68a
--- /dev/null
+++ b/indra/newview/lllegacyatmospherics.cpp
@@ -0,0 +1,649 @@
+/** 
+ * @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;
+	mUpdateTimer.reset();
+	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);
+	calc();
+	mInitialized = true;
+}
+
+LLColor4 LLAtmospherics::calcSkyColorInDir(const LLVector3 &dir, bool isShiny)
+{
+	F32 saturation = 0.3f;
+	if (dir.mV[VZ] < -0.02f)
+	{
+		LLColor4 col = LLColor4(llmax(mFogColor[0],0.2f), llmax(mFogColor[1],0.2f), llmax(mFogColor[2],0.22f),0.f);
+		if (isShiny)
+		{
+			LLColor3 desat_fog = LLColor3(mFogColor);
+			F32 brightness = desat_fog.brightness();
+			// So that shiny somewhat shows up at night.
+			if (brightness < 0.15f)
+			{
+				brightness = 0.15f;
+				desat_fog = smear(0.15f);
+			}
+			LLColor3 greyscale = smear(brightness);
+			desat_fog = desat_fog * saturation + greyscale * (1.0f - saturation);
+			if (!gPipeline.canUseWindLightShaders())
+			{
+				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]);
+
+    AtmosphericsVars vars;
+	calcSkyColorWLVert(Pn, vars);
+	
+	LLColor3 sky_color =  calcSkyColorWLFrag(Pn, vars);
+	if (isShiny)
+	{
+		F32 brightness = sky_color.brightness();
+		LLColor3 greyscale = smear(brightness);
+		sky_color = sky_color * saturation + greyscale * (1.0f - saturation);
+		sky_color *= (0.5f + 0.5f * brightness);
+	}
+	return LLColor4(sky_color, 0.0f);
+}
+
+void LLAtmospherics::calcSkyColorWLVert(LLVector3 & Pn, AtmosphericsVars& vars)
+{
+    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+
+    LLColor3    blue_density = psky->getBlueDensity();
+    F32         max_y = psky->getMaxY();
+    LLVector3   lightnorm = psky->getLightNormal();
+
+	// 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 = psky->getDomeRadius() * sin(F_PI + phi + asin(psky->getDomeOffset() * sinA)) / sinA;
+
+	Pn *= Plen;
+
+	vars.horizontalProjection[0] = LLVector2(Pn[0], Pn[2]);
+	vars.horizontalProjection[0] /= - 2.f * 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 = psky->getSunlightColor();
+    LLColor3 ambient = psky->getAmbientColor();
+    LLColor3 blue_horizon = psky->getBlueHorizon();
+    F32 haze_density = psky->getHazeDensity();
+    F32 haze_horizon = psky->getHazeHorizon();
+    F32 density_multiplier = psky->getDensityMultiplier();
+    LLColor3 glow = psky->getGlow();
+    F32 cloud_shadow = psky->getCloudShadow();
+
+	// Sunlight attenuation effect (hue and brightness) due to atmosphere
+	// this is used later for sunlight modulation at various altitudes
+	LLColor3 light_atten = (blue_density * 1.0 + smear(haze_density * 0.25f)) * (density_multiplier * max_y);
+
+	// Calculate relative weights
+	LLColor3 temp2(0.f, 0.f, 0.f);
+	LLColor3 temp1 = blue_density + smear(haze_density);
+	LLColor3 blue_weight = componentDiv(blue_density, temp1);
+	LLColor3 haze_weight = componentDiv(smear(haze_density), temp1);
+
+	// Compute sunlight from P & lightnorm (for long rays like sky)
+	temp2.mV[1] = llmax(F_APPROXIMATELY_ZERO, llmax(0.f, Pn[1]) * 1.0f + lightnorm[1] );
+
+	temp2.mV[1] = 1.f / temp2.mV[1];
+	componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
+
+	// Distance
+	temp2.mV[2] = Plen * density_multiplier;
+
+	// Transparency (-> temp1)
+	temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]);
+
+
+	// Compute haze glow
+	temp2.mV[0] = Pn * lightnorm;
+
+	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)
+	temp2.mV[0] *= glow.mV[0];
+		// Higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	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_horizon * blue_weight * (sunlight + ambient) + componentMult(haze_horizon * haze_weight, 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
+	LLColor3 additiveColorBelowCloud = (blue_horizon * blue_weight * (sunlight + tmpAmbient) + componentMult(haze_horizon * haze_weight, sunlight * temp2.mV[0] + tmpAmbient));	
+
+	// Final atmosphere additive
+	componentMultBy(vars.hazeColor, LLColor3::white - temp1);
+
+	sunlight = psky->getSunlightColor();
+	temp2.mV[1] = llmax(0.f, lightnorm[1] * 2.f);
+	temp2.mV[1] = 1.f / temp2.mV[1];
+	componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
+
+	// 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(additiveColorBelowCloud - vars.hazeColor, LLColor3::white - componentSqrt(temp1));
+		
+	if (Pn[1] < 0.f)
+	{
+		// Eric's original: 
+		// LLColor3 dark_brown(0.143f, 0.129f, 0.114f);
+		LLColor3 dark_brown(0.082f, 0.076f, 0.066f);
+		LLColor3 brown(0.430f, 0.386f, 0.322f);
+		LLColor3 sky_lighting = sunlight + ambient;
+		F32 haze_brightness = vars.hazeColor.brightness();
+
+		if (Pn[1] < -0.05f)
+		{
+			vars.hazeColor = colorMix(dark_brown, brown, -Pn[1] * 0.9f) * sky_lighting * haze_brightness;
+		}
+		
+		if (Pn[1] > -0.1f)
+		{
+			vars.hazeColor = colorMix(LLColor3::white * haze_brightness, vars.hazeColor, fabs((Pn[1] + 0.05f) * -20.f));
+		}
+	}
+}
+
+LLColor3 LLAtmospherics::calcSkyColorWLFrag(LLVector3 & Pn, AtmosphericsVars& vars)
+{
+    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+    F32 gamma = psky->getGamma();
+
+	LLColor3 res;
+	LLColor3 color0 = vars.hazeColor;
+	
+	if (!gPipeline.canUseWindLightShaders())
+	{
+		LLColor3 color1 = color0 * 2.0f;
+		color1 = smear(1.f) - componentSaturate(color1);
+		componentPow(color1, gamma);
+		res = smear(1.f) - color1;
+	} 
+	else 
+	{
+		res = color0;
+	}
+
+#	ifndef LL_RELEASE_FOR_DOWNLOAD
+
+	LLColor3 color2 = 2.f * color0;
+
+	LLColor3 color3 = LLColor3(1.f, 1.f, 1.f) - componentSaturate(color2);
+	componentPow(color3, gamma);
+	color3 = LLColor3(1.f, 1.f, 1.f) - color3;
+
+	static enum {
+		OUT_DEFAULT		= 0,
+		OUT_SKY_BLUE	= 1,
+		OUT_RED			= 2,
+		OUT_PN			= 3,
+		OUT_HAZE		= 4,
+	} debugOut = OUT_DEFAULT;
+
+	switch(debugOut) 
+	{
+		case OUT_DEFAULT:
+			break;
+		case OUT_SKY_BLUE:
+			res = LLColor3(0.4f, 0.4f, 0.9f);
+			break;
+		case OUT_RED:
+			res = LLColor3(1.f, 0.f, 0.f);
+			break;
+		case OUT_PN:
+			res = LLColor3(Pn[0], Pn[1], Pn[2]);
+			break;
+		case OUT_HAZE:
+			res = vars.hazeColor;
+			break;
+	}
+#	endif // LL_RELEASE_FOR_DOWNLOAD
+	return res;
+}
+
+void LLAtmospherics::calc()
+{
+
+}
+
+void LLAtmospherics::updateFog(const F32 distance, LLVector3& tosun)
+{
+	if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG))
+	{
+		if (!LLGLSLShader::sNoFixedFunction)
+		{
+			glFogf(GL_FOG_DENSITY, 0);
+			glFogfv(GL_FOG_COLOR, (F32 *) &LLColor4::white.mV);
+			glFogf(GL_FOG_END, 1000000.f);
+		}
+		return;
+	}
+
+	const BOOL hide_clip_plane = TRUE;
+	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.
+	res_color[0] = calcSkyColorInDir(tosun);
+	res_color[1] = calcSkyColorInDir(perp_tosun);
+	res_color[2] = calcSkyColorInDir(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;
+
+	F32 fog_density = 0.f;
+	fog_distance = mFogRatio * distance;
+	
+	if (camera_height > water_height)
+	{
+		LLColor4 fog(render_fog_color);
+		if (!LLGLSLShader::sNoFixedFunction)
+		{
+			glFogfv(GL_FOG_COLOR, fog.mV);
+		}
+		mGLFogCol = fog;
+
+		if (hide_clip_plane)
+		{
+			// For now, set the density to extend to the cull distance.
+			const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f)))
+			fog_density = f_log/fog_distance;
+			if (!LLGLSLShader::sNoFixedFunction)
+			{
+				glFogi(GL_FOG_MODE, GL_EXP2);
+			}
+		}
+		else
+		{
+			const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f))
+			fog_density = (f_log)/fog_distance;
+			if (!LLGLSLShader::sNoFixedFunction)
+			{
+				glFogi(GL_FOG_MODE, GL_EXP);
+			}
+		}
+	}
+	else
+	{
+        LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
+		F32 depth = water_height - camera_height;
+		
+		// get the water param manager variables
+        float water_fog_density = pwater->getFogDensity();
+		LLColor4 water_fog_color(pwater->getFogColor());
+		
+		// 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;
+
+		// set the density based on what the shaders use
+		fog_density = water_fog_density * gSavedSettings.getF32("WaterGLFogDensityScale");
+
+		if (!LLGLSLShader::sNoFixedFunction)
+		{
+			glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV);
+			glFogi(GL_FOG_MODE, GL_EXP2);
+		}
+	}
+
+	mFogColor = sky_fog_color;
+	mFogColor.setAlpha(1);
+
+	LLDrawPoolWater::sWaterFogEnd = fog_distance*2.2f;
+
+	if (!LLGLSLShader::sNoFixedFunction)
+	{
+		LLGLSFog gls_fog;
+		glFogf(GL_FOG_END, fog_distance*2.2f);
+		glFogf(GL_FOG_DENSITY, fog_density);
+		glHint(GL_FOG_HINT, GL_NICEST);
+	}
+	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;
+}
diff --git a/indra/newview/lllegacyatmospherics.h b/indra/newview/lllegacyatmospherics.h
new file mode 100644
index 00000000000..2f0c094c102
--- /dev/null
+++ b/indra/newview/lllegacyatmospherics.h
@@ -0,0 +1,256 @@
+/** 
+ * @file lllegacyatmospherics.h
+ * @brief LLVOSky class header file
+ *
+ * $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$
+ */
+
+#ifndef LL_LLLEGACYATMOSPHERICS_H
+#define LL_LLLEGACYATMOSPHERICS_H
+
+#include "stdtypes.h"
+#include "v3color.h"
+#include "v4coloru.h"
+#include "llviewertexture.h"
+#include "llviewerobject.h"
+#include "llframetimer.h"
+#include "v3colorutil.h"
+#include "llsettingssky.h"
+
+//////////////////////////////////
+//
+// Lots of constants
+//
+// Will clean these up at some point...
+//
+
+const F32 HORIZON_DIST      = 1024.0f;
+const F32 EARTH_RADIUS      = 6.4e6f;  // exact radius = 6.37 x 10^6 m
+const F32 ATM_EXP_FALLOFF   = 0.000126f;
+const F32 ATM_SEA_LEVEL_NDENS   = 2.55e25f;
+const F32 ATM_HEIGHT        = 100000.f;
+
+// constants used in calculation of scattering coeff of clear air
+const F32 sigma     = 0.035f;
+const F32 fsigma    = (6.f + 3.f * sigma) / (6.f-7.f*sigma);
+const F64 Ndens     = 2.55e25;
+const F64 Ndens2    = Ndens*Ndens;
+
+class LLFace;
+class LLHaze;
+
+LL_FORCE_INLINE LLColor3 refr_ind_calc(const LLColor3 &wave_length)
+{
+    LLColor3 refr_ind;
+    for (S32 i = 0; i < 3; ++i)
+    {
+        const F32 wl2 = wave_length.mV[i] * wave_length.mV[i] * 1e-6f;
+        refr_ind.mV[i] = 6.43e3f + ( 2.95e6f / ( 146.0f - 1.f/wl2 ) ) + ( 2.55e4f / ( 41.0f - 1.f/wl2 ) );
+        refr_ind.mV[i] *= 1.0e-8f;
+        refr_ind.mV[i] += 1.f;
+    }
+    return refr_ind;
+}
+
+
+class LLHaze
+{
+public:
+    LLHaze() : mG(0), mFalloff(1), mAbsCoef(0.f) {mSigSca.setToBlack();}
+    LLHaze(const F32 g, const LLColor3& sca, const F32 fo = 2.f) : 
+            mG(g), mSigSca(0.25f/F_PI * sca), mFalloff(fo), mAbsCoef(0.f)
+    {
+        mAbsCoef = color_intens(mSigSca) / sAirScaIntense;
+    }
+
+    LLHaze(const F32 g, const F32 sca, const F32 fo = 2.f) : mG(g),
+            mSigSca(0.25f/F_PI * LLColor3(sca, sca, sca)), mFalloff(fo)
+    {
+        mAbsCoef = 0.01f * sca / sAirScaAvg;
+    }
+
+/* Proportion of light that is scattered into 'path' from 'in' over distance dt. */
+/* assumes that vectors 'path' and 'in' are normalized. Scattering coef / 2pi */
+
+    LL_FORCE_INLINE LLColor3 calcAirSca(const F32 h)
+    {
+       return calcFalloff(h) * sAirScaSeaLevel;
+    }
+
+    LL_FORCE_INLINE void calcAirSca(const F32 h, LLColor3 &result)
+    {
+        result = sAirScaSeaLevel;
+        result *= calcFalloff(h);
+    }
+
+    F32 getG() const                { return mG; }
+
+    void setG(const F32 g)
+    {
+        mG = g;
+    }
+
+    const LLColor3& getSigSca() const // sea level
+    {
+        return mSigSca;
+    } 
+
+    void setSigSca(const LLColor3& s)
+    {
+        mSigSca = s;
+        mAbsCoef = 0.01f * color_intens(mSigSca) / sAirScaIntense;
+    }
+
+    void setSigSca(const F32 s0, const F32 s1, const F32 s2)
+    {
+        mSigSca = sAirScaAvg * LLColor3 (s0, s1, s2);
+        mAbsCoef = 0.01f * (s0 + s1 + s2) / 3;
+    }
+
+    F32 getFalloff() const
+    {
+        return mFalloff;
+    }
+
+    void setFalloff(const F32 fo)
+    {
+        mFalloff = fo;
+    }
+
+    F32 getAbsCoef() const
+    {
+        return mAbsCoef;
+    }
+
+    inline static F32 calcFalloff(const F32 h)
+    {
+        return (h <= 0) ? 1.0f : (F32)LL_FAST_EXP(-ATM_EXP_FALLOFF * h);
+    }
+
+    inline LLColor3 calcSigSca(const F32 h) const
+    {
+        return calcFalloff(h * mFalloff) * mSigSca;
+    }
+
+    inline void calcSigSca(const F32 h, LLColor3 &result) const
+    {
+        result = mSigSca;
+        result *= calcFalloff(h * mFalloff);
+    }
+
+    LLColor3 calcSigExt(const F32 h) const
+    {
+        return calcFalloff(h * mFalloff) * (1 + mAbsCoef) * mSigSca;
+    }
+
+    F32 calcPhase(const F32 cos_theta) const;
+
+private:
+    static LLColor3 const sAirScaSeaLevel;
+    static F32 const sAirScaIntense;
+    static F32 const sAirScaAvg;
+
+protected:
+    F32         mG;
+    LLColor3    mSigSca;
+    F32         mFalloff;   // 1 - slow, >1 - faster
+    F32         mAbsCoef;
+};
+
+
+class LLCubeMap;
+
+// turn on floating point precision
+// in vs2003 for this class.  Otherwise
+// black dots go everywhere from 7:10 - 8:50
+#if LL_MSVC && __MSVC_VER__ < 8
+#pragma optimize("p", on)       
+#endif
+
+class AtmosphericsVars
+{
+public:
+    AtmosphericsVars()
+    : hazeColor(0,0,0)
+    , cloudColorSun(0,0,0)
+    , cloudColorAmbient(0,0,0)
+    , cloudDensity(0.0f)
+    {
+        horizontalProjection[0] = LLVector2(0,0);
+        horizontalProjection[1] = LLVector2(0,0);
+    }
+
+    LLColor3  hazeColor;
+	LLColor3  cloudColorSun;
+	LLColor3  cloudColorAmbient;
+	F32       cloudDensity;
+	LLVector2 horizontalProjection[2];
+};
+
+class LLAtmospherics
+{
+public:    
+    LLAtmospherics();
+    ~LLAtmospherics();
+
+    void init();
+    void calc();
+    void updateFog(const F32 distance, LLVector3& tosun);
+
+    const LLHaze& getHaze() const                    { return mHaze; }
+    LLHaze& getHaze()                                { return mHaze; }
+    F32 getHazeConcentration() const                 { return mHazeConcentration; }
+    void setHaze(const LLHaze& h)                    { mHaze = h; }
+    void setFogRatio(const F32 fog_ratio)            { mFogRatio = fog_ratio; }
+
+    F32      getFogRatio() const                     { return mFogRatio; }
+    LLColor4 getFogColor() const                     { return mFogColor; }
+    LLColor4 getGLFogColor() const                   { return mGLFogCol; }
+
+    void setCloudDensity(F32 cloud_density)          { mCloudDensity = cloud_density; }
+    void setWind ( const LLVector3& wind )           { mWind = wind.length(); }
+
+    LLColor4 calcSkyColorInDir(const LLVector3& dir, bool isShiny = false);
+
+protected:    
+
+    void     calcSkyColorWLVert(LLVector3 & Pn, AtmosphericsVars& vars);
+    LLColor3 calcSkyColorWLFrag(LLVector3 & Pn, AtmosphericsVars& vars);
+
+    LLHaze              mHaze;
+    F32                 mHazeConcentration;
+    F32                 mCloudDensity;
+    F32                 mWind;
+    BOOL                mInitialized;
+    LLVector3           mLastLightingDirection;
+    LLColor3            mLastTotalAmbient;
+    F32                 mAmbientScale;
+    LLColor3            mNightColorShift;
+    F32                 mInterpVal;
+    LLColor4            mFogColor;
+    LLColor4            mGLFogCol;
+    F32                 mFogRatio;
+    F32                 mWorldScale;
+    LLFrameTimer        mUpdateTimer;
+};
+
+#endif
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 01d7ab3dcf5..8cacd6d0f98 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -430,7 +430,6 @@ LLSettingsSky::ptr_t LLSettingsVOSky::buildClone()
 
 void LLSettingsVOSky::convertAtmosphericsToLegacy(LLSD& legacy, LLSD& settings)
 {
-// LEGACY_ATMOSPHERICS
     // These will need to be inferred from new settings' density profiles
     legacy[SETTING_AMBIENT] = ensureArray4(settings[SETTING_AMBIENT], 1.0f);
     legacy[SETTING_BLUE_DENSITY] = ensureArray4(settings[SETTING_BLUE_DENSITY], 1.0);
@@ -439,14 +438,6 @@ void LLSettingsVOSky::convertAtmosphericsToLegacy(LLSD& legacy, LLSD& settings)
     legacy[SETTING_DISTANCE_MULTIPLIER] = LLSDArray(settings[SETTING_DISTANCE_MULTIPLIER].asReal())(0.0f)(0.0f)(1.0f);
     legacy[SETTING_HAZE_DENSITY] = LLSDArray(settings[SETTING_HAZE_DENSITY])(0.0f)(0.0f)(1.0f);
     legacy[SETTING_HAZE_HORIZON] = LLSDArray(settings[SETTING_HAZE_HORIZON])(0.0f)(0.0f)(1.0f);
-
-    //legacy[SETTING_AMBIENT]             = LLColor4::black.getValue();
-    //legacy[SETTING_BLUE_DENSITY]        = LLColor4(0.2447, 0.4487, 0.7599, 0.0).getValue();
-    //legacy[SETTING_BLUE_HORIZON]        = LLColor4(0.4954, 0.4954, 0.6399, 0.0).getValue();
-    //legacy[SETTING_HAZE_DENSITY]        = LLSDArray(0.6999f)(0.0f)(0.0f)(1.0f);
-    //legacy[SETTING_HAZE_HORIZON]        = LLSDArray(0.1899f)(0.0f)(0.0f)(1.0f);
-    //legacy[SETTING_DENSITY_MULTIPLIER]  = LLSDArray(0.0001f)(0.0f)(0.0f)(1.0f);LLSD::Real(0.0001);
-    //legacy[SETTING_DISTANCE_MULTIPLIER] = LLSDArray(0.8f)(0.0f)(0.0f)(1.0f);    
 }
 
 LLSD LLSettingsVOSky::convertToLegacy(const LLSettingsSky::ptr_t &psky, bool isAdvanced)
@@ -515,12 +506,12 @@ LLSettingsSky::parammapping_t LLSettingsVOSky::getParameterMap() const
 
     if (param_map.empty())
     {
-// LEGACY_ATMOSPHERICS
-        param_map[SETTING_AMBIENT] = LLShaderMgr::AMBIENT;
         param_map[SETTING_BLUE_DENSITY] = LLShaderMgr::BLUE_DENSITY;
         param_map[SETTING_BLUE_HORIZON] = LLShaderMgr::BLUE_HORIZON;
         param_map[SETTING_HAZE_DENSITY] = LLShaderMgr::HAZE_DENSITY;
         param_map[SETTING_HAZE_HORIZON] = LLShaderMgr::HAZE_HORIZON;
+
+        param_map[SETTING_AMBIENT] = LLShaderMgr::AMBIENT;
         param_map[SETTING_DENSITY_MULTIPLIER] = LLShaderMgr::DENSITY_MULTIPLIER;
         param_map[SETTING_DISTANCE_MULTIPLIER] = LLShaderMgr::DISTANCE_MULTIPLIER;
 
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 61500aebfea..950378c5670 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -75,127 +75,77 @@ static const LLVector2 TEX11 = LLVector2(1.f, 1.f);
 LLUUID gSunTextureID = IMG_SUN;
 LLUUID gMoonTextureID = IMG_MOON;
 
-class LLFastLn
+F32 clip_side_to_horizon(const LLVector3& V0, const LLVector3& V1, const F32 cos_max_angle)
 {
-public:
-	LLFastLn() 
+	const LLVector3 V = V1 - V0;
+	const F32 k2 = 1.f/(cos_max_angle * cos_max_angle) - 1;
+	const F32 A = V.mV[0] * V.mV[0] + V.mV[1] * V.mV[1] - k2 * V.mV[2] * V.mV[2];
+	const F32 B = V0.mV[0] * V.mV[0] + V0.mV[1] * V.mV[1] - k2 * V0.mV[2] * V.mV[2];
+	const F32 C = V0.mV[0] * V0.mV[0] + V0.mV[1] * V0.mV[1] - k2 * V0.mV[2] * V0.mV[2];
+
+	if (fabs(A) < 1e-7)
 	{
-		mTable[0] = 0;
-		for( S32 i = 1; i < 257; i++ )
-		{
-			mTable[i] = log((F32)i);
-		}
+		return -0.1f;	// v0 is cone origin and v1 is on the surface of the cone.
 	}
 
-	F32 ln( F32 x )
+	const F32 det = sqrt(B*B - A*C);
+	const F32 t1 = (-B - det) / A;
+	const F32 t2 = (-B + det) / A;
+	const F32 z1 = V0.mV[2] + t1 * V.mV[2];
+	const F32 z2 = V0.mV[2] + t2 * V.mV[2];
+	if (z1 * cos_max_angle < 0)
 	{
-		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 );
-		}
+		return t2;
 	}
-
-	F32 pow( F32 x, F32 y )
+	else if (z2 * cos_max_angle < 0)
 	{
-		return (F32)LL_FAST_EXP(y * ln(x));
+		return t1;
 	}
-
-
-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)
+	else if ((t1 < 0) || (t1 > 1))
 	{
-		return 1.f/m * col;
+		return t2;
+	}
+	else
+	{
+		return t1;
 	}
-	else return col;
 }
 
-inline void color_gamma_correct(LLColor3 &col)
+// Clips quads with top and bottom sides parallel to horizon.
+BOOL clip_quad_to_horizon(F32& t_left, F32& t_right, LLVector3 v_clipped[4],
+						  const LLVector3 v_corner[4], const F32 cos_max_angle)
 {
-	const F32 gamma_inv = 1.f/1.2f;
-	if (col.mV[0] != 0.f)
+	t_left = clip_side_to_horizon(v_corner[1], v_corner[0], cos_max_angle);
+	t_right = clip_side_to_horizon(v_corner[3], v_corner[2], cos_max_angle);
+
+	if ((t_left >= 1) || (t_right >= 1))
 	{
-		col.mV[0] = gFastLn.pow(col.mV[0], gamma_inv);
+		return FALSE;
 	}
-	if (col.mV[1] != 0.f)
+
+	//const BOOL left_clip = (t_left > 0);
+	//const BOOL right_clip = (t_right > 0);
+
+	//if (!left_clip && !right_clip)
 	{
-		col.mV[1] = gFastLn.pow(col.mV[1], gamma_inv);
+		for (S32 vtx = 0; vtx < 4; ++vtx)
+		{
+			v_clipped[vtx]  = v_corner[vtx];
+		}
 	}
-	if (col.mV[2] != 0.f)
+/*	else
 	{
-		col.mV[2] = gFastLn.pow(col.mV[2], gamma_inv);
-	}
-}
+		v_clipped[0] = v_corner[0];
+		v_clipped[1] = left_clip ? ((1 - t_left) * v_corner[1] + t_left * v_corner[0])
+									: v_corner[1];
+		v_clipped[2] = v_corner[2];
+		v_clipped[3] = right_clip ? ((1 - t_right) * v_corner[3] + t_right * v_corner[2])
+									: v_corner[3];
+	}*/
 
-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 * color_div ( mult_const, wl4 );
+	return TRUE;
 }
 
-// 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;
-
-
 /***************************************
 		SkyTex
 ***************************************/
@@ -356,11 +306,7 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 
         initSunDirection(LLVector3(mSunDefaultPosition.mV[2], mSunDefaultPosition.mV[0], mSunDefaultPosition.mV[1]), LLVector3(0, 0, 0));
 	}
-	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;
+	
 
 	mSun.setIntensity(SUN_INTENSITY);
 	mMoon.setIntensity(0.1f * SUN_INTENSITY);
@@ -376,8 +322,7 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	mHeavenlyBodyUpdated = FALSE ;
 
 	mDrawRefl = 0;
-	mHazeConcentration = 0.f;
-	mInterpVal = 0.f;
+    mInterpVal = 0.f;
 }
 
 
@@ -391,13 +336,8 @@ LLVOSky::~LLVOSky()
 
 void LLVOSky::init()
 {
-   	const F32 haze_int = color_intens(mHaze.calcSigSca(0));
-	mHazeConcentration = haze_int /
-		(color_intens(LLHaze::calcAirSca(0)) + haze_int);
-
 	calcAtmospherics();
 
-// LEGACY_ATMOSPHERICS
 	// Initialize the cached normalized direction vectors
 	for (S32 side = 0; side < 6; ++side)
 	{
@@ -468,7 +408,7 @@ void LLVOSky::restoreGL()
 	mBloomTexturep->setNoDelete() ;
 	mBloomTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 
-	calcAtmospherics();	
+	calcAtmospherics();
 
 	if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap
 	    && LLCubeMap::sUseCubeMaps)
@@ -495,7 +435,6 @@ void LLVOSky::restoreGL()
 
 }
 
-// LEGACY_ATMOSPHERICS
 void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile)
 {
 	S32 tile_x = tile % NUM_TILES_X;
@@ -541,287 +480,10 @@ void LLVOSky::createSkyTexture(const S32 side, const S32 tile)
 	{
 		for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x)
 		{
-			mSkyTex[side].setPixel(calcSkyColorInDir(mSkyTex[side].getDir(x, y)), x, y);
-			mShinyTex[side].setPixel(calcSkyColorInDir(mSkyTex[side].getDir(x, y), true), x, y);
-		}
-	}
-}
-
-LLColor4 LLVOSky::calcSkyColorInDir(const LLVector3 &dir, bool isShiny)
-{
-	F32 saturation = 0.3f;
-	if (dir.mV[VZ] < -0.02f)
-	{
-		LLColor4 col = LLColor4(llmax(mFogColor[0],0.2f), llmax(mFogColor[1],0.2f), llmax(mFogColor[2],0.22f),0.f);
-		if (isShiny)
-		{
-			LLColor3 desat_fog = LLColor3(mFogColor);
-			F32 brightness = desat_fog.brightness();
-			// So that shiny somewhat shows up at night.
-			if (brightness < 0.15f)
-			{
-				brightness = 0.15f;
-				desat_fog = smear(0.15f);
-			}
-			LLColor3 greyscale = smear(brightness);
-			desat_fog = desat_fog * saturation + greyscale * (1.0f - saturation);
-			if (!gPipeline.canUseWindLightShaders())
-			{
-				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]);
-
-	LLColor3 vary_HazeColor(0,0,0);
-	LLColor3 vary_CloudColorSun(0,0,0);
-	LLColor3 vary_CloudColorAmbient(0,0,0);
-	F32 vary_CloudDensity(0);
-	LLVector2 vary_HorizontalProjection[2];
-	vary_HorizontalProjection[0] = LLVector2(0,0);
-	vary_HorizontalProjection[1] = LLVector2(0,0);
-
-	calcSkyColorWLVert(Pn, vary_HazeColor, vary_CloudColorSun, vary_CloudColorAmbient,
-						vary_CloudDensity, vary_HorizontalProjection);
-	
-	LLColor3 sky_color =  calcSkyColorWLFrag(Pn, vary_HazeColor, vary_CloudColorSun, vary_CloudColorAmbient, 
-								vary_CloudDensity, vary_HorizontalProjection);
-	if (isShiny)
-	{
-		F32 brightness = sky_color.brightness();
-		LLColor3 greyscale = smear(brightness);
-		sky_color = sky_color * saturation + greyscale * (1.0f - saturation);
-		sky_color *= (0.5f + 0.5f * brightness);
-	}
-	return LLColor4(sky_color, 0.0f);
-}
-
-// turn on floating point precision
-// in vs2003 for this function.  Otherwise
-// sky is aliased looking 7:10 - 8:50
-#if LL_MSVC && __MSVC_VER__ < 8
-#pragma optimize("p", on)
-#endif
-
-void LLVOSky::calcSkyColorWLVert(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, 
-							LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, 
-							LLVector2 vary_HorizontalProjection[2])
-{
-    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-
-    LLColor3    blue_density = psky->getBlueDensity();
-    F32         max_y = psky->getMaxY();
-    LLVector3   lightnorm = psky->getLightNormal();
-
-	// 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 = psky->getDomeRadius() * sin(F_PI + phi + asin(psky->getDomeOffset() * sinA)) / sinA;
-
-	Pn *= Plen;
-
-	vary_HorizontalProjection[0] = LLVector2(Pn[0], Pn[2]);
-	vary_HorizontalProjection[0] /= - 2.f * 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 = psky->getSunlightColor();
-    LLColor3 ambient = psky->getAmbientColor();
-    LLColor3 blue_horizon = psky->getBlueHorizon();
-    F32 haze_density = psky->getHazeDensity();
-    F32 haze_horizon = psky->getHazeHorizon();
-    F32 density_multiplier = psky->getDensityMultiplier();
-    LLColor3 glow = psky->getGlow();
-    F32 cloud_shadow = psky->getCloudShadow();
-
-	// Sunlight attenuation effect (hue and brightness) due to atmosphere
-	// this is used later for sunlight modulation at various altitudes
-	LLColor3 light_atten = (blue_density * 1.0 + smear(haze_density * 0.25f)) * (density_multiplier * max_y);
-
-	// Calculate relative weights
-	LLColor3 temp2(0.f, 0.f, 0.f);
-	LLColor3 temp1 = blue_density + smear(haze_density);
-	LLColor3 blue_weight = componentDiv(blue_density, temp1);
-	LLColor3 haze_weight = componentDiv(smear(haze_density), temp1);
-
-	// Compute sunlight from P & lightnorm (for long rays like sky)
-	temp2.mV[1] = llmax(F_APPROXIMATELY_ZERO, llmax(0.f, Pn[1]) * 1.0f + lightnorm[1] );
-
-	temp2.mV[1] = 1.f / temp2.mV[1];
-	componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
-
-	// Distance
-	temp2.mV[2] = Plen * density_multiplier;
-
-	// Transparency (-> temp1)
-	temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]);
-
-
-	// Compute haze glow
-	temp2.mV[0] = Pn * lightnorm;
-
-	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)
-	temp2.mV[0] *= glow.mV[0];
-		// Higher glow.x gives dimmer glow (because next step is 1 / "angle")
-	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
-	vary_HazeColor = (blue_horizon * blue_weight * (sunlight + ambient) + componentMult(haze_horizon * haze_weight, 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
-	LLColor3 additiveColorBelowCloud = (blue_horizon * blue_weight * (sunlight + tmpAmbient) + componentMult(haze_horizon * haze_weight, sunlight * temp2.mV[0] + tmpAmbient));	
-
-	// Final atmosphere additive
-	componentMultBy(vary_HazeColor, LLColor3::white - temp1);
-
-	sunlight = psky->getSunlightColor();
-	temp2.mV[1] = llmax(0.f, lightnorm[1] * 2.f);
-	temp2.mV[1] = 1.f / temp2.mV[1];
-	componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
-
-	// 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
-	vary_HazeColor += componentMult(additiveColorBelowCloud - vary_HazeColor, LLColor3::white - componentSqrt(temp1));
-		
-	if (Pn[1] < 0.f)
-	{
-		// Eric's original: 
-		// LLColor3 dark_brown(0.143f, 0.129f, 0.114f);
-		LLColor3 dark_brown(0.082f, 0.076f, 0.066f);
-		LLColor3 brown(0.430f, 0.386f, 0.322f);
-		LLColor3 sky_lighting = sunlight + ambient;
-		F32 haze_brightness = vary_HazeColor.brightness();
-
-		if (Pn[1] < -0.05f)
-		{
-			vary_HazeColor = colorMix(dark_brown, brown, -Pn[1] * 0.9f) * sky_lighting * haze_brightness;
+			mSkyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(mSkyTex[side].getDir(x, y)), x, y);
+			mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(mSkyTex[side].getDir(x, y), true), x, y);
 		}
-		
-		if (Pn[1] > -0.1f)
-		{
-			vary_HazeColor = colorMix(LLColor3::white * haze_brightness, vary_HazeColor, fabs((Pn[1] + 0.05f) * -20.f));
-		}
-	}
-}
-
-#if LL_MSVC && __MSVC_VER__ < 8
-#pragma optimize("p", off)
-#endif
-
-LLColor3 LLVOSky::calcSkyColorWLFrag(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, 
-							LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, 
-							LLVector2 vary_HorizontalProjection[2])
-{
-    LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
-    F32 gamma = psky->getGamma();
-
-	LLColor3 res;
-	LLColor3 color0 = vary_HazeColor;
-	
-	if (!gPipeline.canUseWindLightShaders())
-	{
-		LLColor3 color1 = color0 * 2.0f;
-		color1 = smear(1.f) - componentSaturate(color1);
-		componentPow(color1, gamma);
-		res = smear(1.f) - color1;
-	} 
-	else 
-	{
-		res = color0;
-	}
-
-#	ifndef LL_RELEASE_FOR_DOWNLOAD
-
-	LLColor3 color2 = 2.f * color0;
-
-	LLColor3 color3 = LLColor3(1.f, 1.f, 1.f) - componentSaturate(color2);
-	componentPow(color3, gamma);
-	color3 = LLColor3(1.f, 1.f, 1.f) - color3;
-
-	static enum {
-		OUT_DEFAULT		= 0,
-		OUT_SKY_BLUE	= 1,
-		OUT_RED			= 2,
-		OUT_PN			= 3,
-		OUT_HAZE		= 4,
-	} debugOut = OUT_DEFAULT;
-
-	switch(debugOut) 
-	{
-		case OUT_DEFAULT:
-			break;
-		case OUT_SKY_BLUE:
-			res = LLColor3(0.4f, 0.4f, 0.9f);
-			break;
-		case OUT_RED:
-			res = LLColor3(1.f, 0.f, 0.f);
-			break;
-		case OUT_PN:
-			res = LLColor3(Pn[0], Pn[1], Pn[2]);
-			break;
-		case OUT_HAZE:
-			res = vary_HazeColor;
-			break;
 	}
-#	endif // LL_RELEASE_FOR_DOWNLOAD
-	return res;
-}
-
-
-LLColor3 LLVOSky::createDiffuseFromWL(LLColor3 diffuse, LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient)
-{
-	return componentMult(diffuse, sundiffuse) * 4.0f +
-			componentMult(ambient, sundiffuse) * 2.0f + sunambient;
-}
-
-LLColor3 LLVOSky::createAmbientFromWL(LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient)
-{
-	return (componentMult(ambient, sundiffuse) + sunambient) * 0.8f;
 }
 
 void LLVOSky::calcAtmospherics(void)
@@ -847,6 +509,7 @@ void LLVOSky::calcAtmospherics(void)
 	F32 sun_dynamic_range = llmax(gSavedSettings.getF32("RenderSunDynamicRange"), 0.0001f);
     LLEnvironment::instance().setSceneLightStrength(2.0f * (1.0f + sun_dynamic_range * dp));
 
+    m_legacyAtmospherics.calc();
 }
 
 void LLVOSky::idleUpdate(LLAgent &agent, const F64 &time)
@@ -874,7 +537,6 @@ BOOL LLVOSky::updateSky()
 		return TRUE;
 	}
 
-// LEGACY_ATMOSPHERICS
 	static S32 next_frame = 0;
 	const S32 total_no_tiles = 6 * NUM_TILES;
 	const S32 cycle_frame_no = total_no_tiles + 1;
@@ -1028,53 +690,6 @@ LLDrawable *LLVOSky::createDrawable(LLPipeline *pipeline)
 	return mDrawable;
 }
 
-//by bao
-//fake vertex buffer updating
-//to guarantee at least updating one VBO buffer every frame
-//to walk around the bug caused by ATI card --> DEV-3855
-//
-void LLVOSky::createDummyVertexBuffer()
-{
-	if(!mFace[FACE_DUMMY])
-	{
-		LLDrawPoolSky *poolp = (LLDrawPoolSky*) gPipeline.getPool(LLDrawPool::POOL_SKY);
-		mFace[FACE_DUMMY] = mDrawable->addFace(poolp, NULL);
-	}
-
-	if(!mFace[FACE_DUMMY]->getVertexBuffer())
-	{
-		LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB);
-		buff->allocateBuffer(1, 1, TRUE);
-		mFace[FACE_DUMMY]->setVertexBuffer(buff);
-	}
-}
-
-static LLTrace::BlockTimerStatHandle FTM_RENDER_FAKE_VBO_UPDATE("Fake VBO Update");
-
-void LLVOSky::updateDummyVertexBuffer()
-{	
-	if(!LLVertexBuffer::sEnableVBOs)
-		return ;
-
-	if(mHeavenlyBodyUpdated)
-	{
-		mHeavenlyBodyUpdated = FALSE ;
-		return ;
-	}
-
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_FAKE_VBO_UPDATE) ;
-
-	if(!mFace[FACE_DUMMY] || !mFace[FACE_DUMMY]->getVertexBuffer())
-		createDummyVertexBuffer() ;
-
-	LLStrider<LLVector3> vertices ;
-	mFace[FACE_DUMMY]->getVertexBuffer()->getVertexStrider(vertices,  0);
-	*vertices = mCameraPosAgent ;
-	mFace[FACE_DUMMY]->getVertexBuffer()->flush();
-}
-//----------------------------------
-//end of fake vertex buffer updating
-//----------------------------------
 static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Sky Geometry");
 
 BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
@@ -1344,83 +959,6 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons
 	return TRUE;
 }
 
-
-
-
-// Clips quads with top and bottom sides parallel to horizon.
-
-BOOL clip_quad_to_horizon(F32& t_left, F32& t_right, LLVector3 v_clipped[4],
-						  const LLVector3 v_corner[4], const F32 cos_max_angle)
-{
-	t_left = clip_side_to_horizon(v_corner[1], v_corner[0], cos_max_angle);
-	t_right = clip_side_to_horizon(v_corner[3], v_corner[2], cos_max_angle);
-
-	if ((t_left >= 1) || (t_right >= 1))
-	{
-		return FALSE;
-	}
-
-	//const BOOL left_clip = (t_left > 0);
-	//const BOOL right_clip = (t_right > 0);
-
-	//if (!left_clip && !right_clip)
-	{
-		for (S32 vtx = 0; vtx < 4; ++vtx)
-		{
-			v_clipped[vtx]  = v_corner[vtx];
-		}
-	}
-/*	else
-	{
-		v_clipped[0] = v_corner[0];
-		v_clipped[1] = left_clip ? ((1 - t_left) * v_corner[1] + t_left * v_corner[0])
-									: v_corner[1];
-		v_clipped[2] = v_corner[2];
-		v_clipped[3] = right_clip ? ((1 - t_right) * v_corner[3] + t_right * v_corner[2])
-									: v_corner[3];
-	}*/
-
-	return TRUE;
-}
-
-
-F32 clip_side_to_horizon(const LLVector3& V0, const LLVector3& V1, const F32 cos_max_angle)
-{
-	const LLVector3 V = V1 - V0;
-	const F32 k2 = 1.f/(cos_max_angle * cos_max_angle) - 1;
-	const F32 A = V.mV[0] * V.mV[0] + V.mV[1] * V.mV[1] - k2 * V.mV[2] * V.mV[2];
-	const F32 B = V0.mV[0] * V.mV[0] + V0.mV[1] * V.mV[1] - k2 * V0.mV[2] * V.mV[2];
-	const F32 C = V0.mV[0] * V0.mV[0] + V0.mV[1] * V0.mV[1] - k2 * V0.mV[2] * V0.mV[2];
-
-	if (fabs(A) < 1e-7)
-	{
-		return -0.1f;	// v0 is cone origin and v1 is on the surface of the cone.
-	}
-
-	const F32 det = sqrt(B*B - A*C);
-	const F32 t1 = (-B - det) / A;
-	const F32 t2 = (-B + det) / A;
-	const F32 z1 = V0.mV[2] + t1 * V.mV[2];
-	const F32 z2 = V0.mV[2] + t2 * V.mV[2];
-	if (z1 * cos_max_angle < 0)
-	{
-		return t2;
-	}
-	else if (z2 * cos_max_angle < 0)
-	{
-		return t1;
-	}
-	else if ((t1 < 0) || (t1 > 1))
-	{
-		return t2;
-	}
-	else
-	{
-		return t1;
-	}
-}
-
-
 void LLVOSky::updateSunHaloGeometry(LLDrawable *drawable )
 {
 #if 0
@@ -1732,7 +1270,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
         const F32 attenuation = min_attenuation
             + cos_angle_of_view * (max_attenuation - min_attenuation);
 
-        LLColor4 hb_refl_col = (1 - attenuation) * hb_col + attenuation * mFogColor;
+        LLColor4 hb_refl_col = (1 - attenuation) * hb_col + attenuation * getFogColor();
         face->setFaceColor(hb_refl_col);
 
         LLVector3 v_far[2];
@@ -1850,208 +1388,10 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
     }
 }
 
-
-
-
 void LLVOSky::updateFog(const F32 distance)
 {
-
-// LEGACY_ATMOSPHERICS
-	if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG))
-	{
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glFogf(GL_FOG_DENSITY, 0);
-			glFogfv(GL_FOG_COLOR, (F32 *) &LLColor4::white.mV);
-			glFogf(GL_FOG_END, 1000000.f);
-		}
-		return;
-	}
-
-	const BOOL hide_clip_plane = TRUE;
-	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;
-
-	LLVector3 tosun = getToSunLast();
-	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.
-	res_color[0] = calcSkyColorInDir(tosun);
-	res_color[1] = calcSkyColorInDir(perp_tosun);
-	res_color[2] = calcSkyColorInDir(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;
-
-	F32 fog_density = 0.f;
-	fog_distance = mFogRatio * distance;
-	
-	if (camera_height > water_height)
-	{
-		LLColor4 fog(render_fog_color);
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glFogfv(GL_FOG_COLOR, fog.mV);
-		}
-		mGLFogCol = fog;
-
-		if (hide_clip_plane)
-		{
-			// For now, set the density to extend to the cull distance.
-			const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f)))
-			fog_density = f_log/fog_distance;
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glFogi(GL_FOG_MODE, GL_EXP2);
-			}
-		}
-		else
-		{
-			const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f))
-			fog_density = (f_log)/fog_distance;
-			if (!LLGLSLShader::sNoFixedFunction)
-			{
-				glFogi(GL_FOG_MODE, GL_EXP);
-			}
-		}
-	}
-	else
-	{
-        LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
-		F32 depth = water_height - camera_height;
-		
-		// get the water param manager variables
-        float water_fog_density = pwater->getFogDensity();
-		LLColor4 water_fog_color(pwater->getFogColor());
-		
-		// 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;
-
-		// set the density based on what the shaders use
-		fog_density = water_fog_density * gSavedSettings.getF32("WaterGLFogDensityScale");
-
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
-			glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV);
-			glFogi(GL_FOG_MODE, GL_EXP2);
-		}
-	}
-
-	mFogColor = sky_fog_color;
-	mFogColor.setAlpha(1);
-	LLDrawPoolWater::sWaterFogEnd = fog_distance*2.2f;
-
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		LLGLSFog gls_fog;
-		glFogf(GL_FOG_END, fog_distance*2.2f);
-		glFogf(GL_FOG_DENSITY, fog_density);
-		glHint(GL_FOG_HINT, GL_NICEST);
-	}
-	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;
+    LLVector3 toSun = getToSunLast();
+    m_legacyAtmospherics.updateFog(distance, toSun);
 }
 
 void LLVOSky::initSunDirection(const LLVector3 &sun_dir, const LLVector3 &sun_ang_velocity)
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 2c253aed511..e4d99a5e8be 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -35,36 +35,12 @@
 #include "llframetimer.h"
 #include "v3colorutil.h"
 #include "llsettingssky.h"
+#include "lllegacyatmospherics.h"
 
-//////////////////////////////////
-//
-// Lots of constants
-//
-// Will clean these up at some point...
-//
-
-const F32 HORIZON_DIST			= 1024.0f;
 const F32 SKY_BOX_MULT			= 16.0f;
-const F32 HEAVENLY_BODY_DIST		= HORIZON_DIST - 10.f;
+const F32 HEAVENLY_BODY_DIST	= HORIZON_DIST - 10.f;
 const F32 HEAVENLY_BODY_FACTOR	= 0.1f;
 const F32 HEAVENLY_BODY_SCALE	= HEAVENLY_BODY_DIST * HEAVENLY_BODY_FACTOR;
-const F32 EARTH_RADIUS			= 6.4e6f;       // exact radius = 6.37 x 10^6 m
-const F32 ATM_EXP_FALLOFF		= 0.000126f;
-const F32 ATM_SEA_LEVEL_NDENS	= 2.55e25f;
-// Somewhat arbitrary:
-const F32 ATM_HEIGHT			= 100000.f;
-
-const F32 FIRST_STEP = 5000.f;
-const F32 INV_FIRST_STEP = 1.f/FIRST_STEP;
-const S32 NO_STEPS = 15;
-const F32 INV_NO_STEPS = 1.f/NO_STEPS;
-
-
-// constants used in calculation of scattering coeff of clear air
-const F32 sigma		= 0.035f;
-const F32 fsigma	= (6.f + 3.f * sigma) / (6.f-7.f*sigma);
-const F64 Ndens		= 2.55e25;
-const F64 Ndens2	= Ndens*Ndens;
 
 // HACK: Allow server to change sun and moon IDs.
 // I can't figure out how to pass the appropriate
@@ -72,25 +48,9 @@ const F64 Ndens2	= Ndens*Ndens;
 extern LLUUID gSunTextureID;
 extern LLUUID gMoonTextureID;
 
-
-LL_FORCE_INLINE LLColor3 color_div(const LLColor3 &col1, const LLColor3 &col2)
-{
-	return LLColor3( 
-		col1.mV[0] / col2.mV[0],
-		col1.mV[1] / col2.mV[1],
-		col1.mV[2] / col2.mV[2] );
-}
-
-LLColor3 color_norm(const LLColor3 &col);
-BOOL clip_quad_to_horizon(F32& t_left, F32& t_right, LLVector3 v_clipped[4],
-						  const LLVector3 v_corner[4], const F32 cos_max_angle);
-F32 clip_side_to_horizon(const LLVector3& v0, const LLVector3& v1, const F32 cos_max_angle);
-
-
 class LLFace;
 class LLHaze;
 
-
 class LLSkyTex
 {
 	friend class LLVOSky;
@@ -258,115 +218,6 @@ class LLHeavenBody
 	void setV(const LLVector3& v)						{ mV = v; }
 };
 
-
-LL_FORCE_INLINE LLColor3 refr_ind_calc(const LLColor3 &wave_length)
-{
-	LLColor3 refr_ind;
-	for (S32 i = 0; i < 3; ++i)
-	{
-		const F32 wl2 = wave_length.mV[i] * wave_length.mV[i] * 1e-6f;
-		refr_ind.mV[i] = 6.43e3f + ( 2.95e6f / ( 146.0f - 1.f/wl2 ) ) + ( 2.55e4f / ( 41.0f - 1.f/wl2 ) );
-		refr_ind.mV[i] *= 1.0e-8f;
-		refr_ind.mV[i] += 1.f;
-	}
-	return refr_ind;
-}
-
-
-class LLHaze
-{
-public:
-	LLHaze() : mG(0), mFalloff(1), mAbsCoef(0.f) {mSigSca.setToBlack();}
-	LLHaze(const F32 g, const LLColor3& sca, const F32 fo = 2.f) : 
-			mG(g), mSigSca(0.25f/F_PI * sca), mFalloff(fo), mAbsCoef(0.f)
-	{
-		mAbsCoef = color_intens(mSigSca) / sAirScaIntense;
-	}
-
-	LLHaze(const F32 g, const F32 sca, const F32 fo = 2.f) : mG(g),
-			mSigSca(0.25f/F_PI * LLColor3(sca, sca, sca)), mFalloff(fo)
-	{
-		mAbsCoef = 0.01f * sca / sAirScaAvg;
-	}
-
-	F32 getG() const				{ return mG; }
-
-	void setG(const F32 g)
-	{
-		mG = g;
-	}
-
-	const LLColor3& getSigSca() const // sea level
-	{
-		return mSigSca;
-	} 
-
-	void setSigSca(const LLColor3& s)
-	{
-		mSigSca = s;
-		mAbsCoef = 0.01f * color_intens(mSigSca) / sAirScaIntense;
-	}
-
-	void setSigSca(const F32 s0, const F32 s1, const F32 s2)
-	{
-		mSigSca = sAirScaAvg * LLColor3 (s0, s1, s2);
-		mAbsCoef = 0.01f * (s0 + s1 + s2) / 3;
-	}
-
-	F32 getFalloff() const
-	{
-		return mFalloff;
-	}
-
-	void setFalloff(const F32 fo)
-	{
-		mFalloff = fo;
-	}
-
-	F32 getAbsCoef() const
-	{
-		return mAbsCoef;
-	}
-
-	inline static F32 calcFalloff(const F32 h)
-	{
-		return (h <= 0) ? 1.0f : (F32)LL_FAST_EXP(-ATM_EXP_FALLOFF * h);
-	}
-
-	inline LLColor3 calcSigSca(const F32 h) const
-	{
-		return calcFalloff(h * mFalloff) * mSigSca;
-	}
-
-	inline void calcSigSca(const F32 h, LLColor3 &result) const
-	{
-		result = mSigSca;
-		result *= calcFalloff(h * mFalloff);
-	}
-
-	LLColor3 calcSigExt(const F32 h) const
-	{
-		return calcFalloff(h * mFalloff) * (1 + mAbsCoef) * mSigSca;
-	}
-
-	F32 calcPhase(const F32 cos_theta) const;
-
-	static inline LLColor3 calcAirSca(const F32 h);
-	static inline void calcAirSca(const F32 h, LLColor3 &result);
-
-private:
-	static LLColor3 const sAirScaSeaLevel;
-	static F32 const sAirScaIntense;
-	static F32 const sAirScaAvg;
-
-protected:
-	F32			mG;
-	LLColor3	mSigSca;
-	F32			mFalloff;	// 1 - slow, >1 - faster
-	F32			mAbsCoef;
-};
-
-
 class LLCubeMap;
 
 // turn on floating point precision
@@ -383,24 +234,6 @@ class LLVOSky : public LLStaticViewerObject
 public:
 	void calcAtmospherics(void);
 
-// LEGACY_ATMOSPHERICS
-	LLColor3 createDiffuseFromWL(LLColor3 diffuse, LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient);
-	LLColor3 createAmbientFromWL(LLColor3 ambient, LLColor3 sundiffuse, LLColor3 sunambient);
-
-	void calcSkyColorWLVert(LLVector3 & Pn, LLColor3 & vary_HazeColor, LLColor3 & vary_CloudColorSun, 
-							LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, 
-							LLVector2 vary_HorizontalProjection[2]);
-
-	LLColor3 calcSkyColorWLFrag(LLVector3 & Pn, LLColor3 & vary_HazeColor,	LLColor3 & vary_CloudColorSun, 
-							LLColor3 & vary_CloudColorAmbient, F32 & vary_CloudDensity, 
-							LLVector2 vary_HorizontalProjection[2]);
-    LLColor4 calcSkyColorInDir(const LLVector3& dir, bool isShiny = false);
-
-    LLColor3 calcRadianceAtPoint(const LLVector3& pos) const
-	{
-		F32 radiance = mBrightnessScaleGuess * mSun.getIntensity();
-		return LLColor3(radiance, radiance, radiance);
-	}
     void initSkyTextureDirs(const S32 side, const S32 tile);
 	void createSkyTexture(const S32 side, const S32 tile);
 
@@ -453,8 +286,6 @@ class LLVOSky : public LLStaticViewerObject
     LLColor4 getSunAmbientColor() const;
     LLColor4 getMoonAmbientColor() const;
     LLColor4 getTotalAmbientColor() const;
-	LLColor4 getFogColor() const							{ return mFogColor; }
-	LLColor4 getGLFogColor() const							{ return mGLFogCol; }
 	
 	BOOL isSameFace(S32 idx, const LLFace* face) const { return mFace[idx] == face; }
 
@@ -476,16 +307,18 @@ class LLVOSky : public LLStaticViewerObject
 	void updateReflectionGeometry(LLDrawable *drawable, F32 H, const LLHeavenBody& HB);
 
 	
-	const LLHaze& getHaze() const						{ return mHaze; }
-	LLHaze&	getHaze()									{ return mHaze; }
-	F32 getHazeConcentration() const					{ return mHazeConcentration; }
-	void setHaze(const LLHaze& h)						{ mHaze = h; }
 	F32 getWorldScale() const							{ return mWorldScale; }
 	void setWorldScale(const F32 s)						{ mWorldScale = s; }
 	void updateFog(const F32 distance);
-	void setFogRatio(const F32 fog_ratio)				{ mFogRatio = fog_ratio; }
+
+    void setFogRatio(const F32 fog_ratio)               { m_legacyAtmospherics.setFogRatio(fog_ratio); }
+    F32  getFogRatio() const                            { return m_legacyAtmospherics.getFogRatio(); }
+
+    LLColor4 getFogColor() const                        { return m_legacyAtmospherics.getFogColor(); }
+    LLColor4 getGLFogColor() const                      { return m_legacyAtmospherics.getGLFogColor(); }
+
     LLColor4U getFadeColor() const;
-    F32 getFogRatio() const								{ return mFogRatio; }
+
 	void setCloudDensity(F32 cloud_density)				{ mCloudDensity = cloud_density; }
 	void setWind ( const LLVector3& wind )				{ mWind = wind.length(); }
 
@@ -532,8 +365,6 @@ class LLVOSky : public LLStaticViewerObject
 	LLColor3			mBrightestPointNew;
 	F32					mBrightnessScaleGuess;
 	LLColor3			mBrightestPointGuess;
-	LLHaze				mHaze;
-	F32					mHazeConcentration;
 	BOOL				mWeatherChange;
 	F32					mCloudDensity;
 	F32					mWind;
@@ -545,53 +376,16 @@ class LLVOSky : public LLStaticViewerObject
 	F32					mAmbientScale;
 	LLColor3			mNightColorShift;
 	F32					mInterpVal;
-
-	LLColor4			mFogColor;
-	LLColor4			mGLFogCol;
-	
-	F32					mFogRatio;
 	F32					mWorldScale;
 
-	LLPointer<LLCubeMap>	mCubeMap;					// Cube map for the environment
-	S32					mDrawRefl;
+	LLPointer<LLCubeMap> mCubeMap;					// Cube map for the environment
+	S32					 mDrawRefl;
 
 	LLFrameTimer		mUpdateTimer;
 
-public:
-	//by bao
-	//fake vertex buffer updating
-	//to guarantee at least updating one VBO buffer every frame
-	//to work around the bug caused by ATI card --> DEV-3855
-	//
-	void createDummyVertexBuffer() ;
-	void updateDummyVertexBuffer() ;
-
-	BOOL mHeavenlyBodyUpdated ;
-};
-
-// turn it off
-#if LL_MSVC && __MSVC_VER__ < 8
-#pragma optimize("p", off)		
-#endif
-
-// Utility functions
-F32 azimuth(const LLVector3 &v);
-F32 color_norm_pow(LLColor3& col, F32 e, BOOL postmultiply = FALSE);
-
-
-/* Proportion of light that is scattered into 'path' from 'in' over distance dt. */
-/* assumes that vectors 'path' and 'in' are normalized. Scattering coef / 2pi */
-
-inline LLColor3 LLHaze::calcAirSca(const F32 h)
-{
-	return calcFalloff(h) * sAirScaSeaLevel;
-}
-
-inline void LLHaze::calcAirSca(const F32 h, LLColor3 &result)
-{
-	result = sAirScaSeaLevel;
-	result *= calcFalloff(h);
-}
+	BOOL                mHeavenlyBodyUpdated ;
 
+    LLAtmospherics      m_legacyAtmospherics;
+};
 
 #endif
-- 
GitLab