diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1f4302d870e9eb1c55609fd68f90b6537ee44086..533eea742098e961542a7e0616fe15e440f08e30 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -139,6 +139,7 @@ set(viewer_SOURCE_FILES
     lldrawpoolwlsky.cpp
     lldriverparam.cpp
     lldynamictexture.cpp
+    llenvmanager.cpp
     llemote.cpp
     lleventinfo.cpp
     lleventnotifier.cpp
@@ -562,6 +563,7 @@ set(viewer_SOURCE_FILES
     llwind.cpp
     llwlanimator.cpp
     llwldaycycle.cpp
+    llwlhandlers.cpp
     llwlparammanager.cpp
     llwlparamset.cpp
     llworld.cpp
@@ -670,6 +672,7 @@ set(viewer_HEADER_FILES
     lldriverparam.h
     lldynamictexture.h
     llemote.h
+    llenvmanager.h
     lleventinfo.h
     lleventnotifier.h
     lleventpoll.h
@@ -1088,6 +1091,7 @@ set(viewer_HEADER_FILES
     llwind.h
     llwlanimator.h
     llwldaycycle.h
+    llwlhandlers.h
     llwlparammanager.h
     llwlparamset.h
     llworld.h
@@ -1933,6 +1937,23 @@ if (LL_TESTS)
   #ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
   #ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer)
 
+include(LLAddBuildTest)
+SET(viewer_TEST_SOURCE_FILES
+  llagentaccess.cpp
+  llwlparammanager.cpp
+  # Not *actually* a unit test, it's an integration test.
+  # Because it won't work in the new unit test iface, i've commented out
+  # and notified Nat. Delete this when it's replaced!
+  # + poppy & brad 2009-06-05
+  # llcapabilitylistener.cpp
+  )
+set_source_files_properties(
+  ${viewer_TEST_SOURCE_FILES}
+  PROPERTIES
+    LL_TEST_ADDITIONAL_SOURCE_FILES llviewerprecompiledheaders.cpp
+  )
+LL_ADD_PROJECT_UNIT_TESTS(${VIEWER_BINARY_NAME} "${viewer_TEST_SOURCE_FILES}")
+
 endif (LL_TESTS)
 
 
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 742a20a8491b6b1a0acddfa6ecdcf1c19375ddbc..d21e978ca59199852b5c1dc1e0132be55b89834e 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11046,6 +11046,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>UseEnvironmentFromRegion</key>
+    <map>
+      <key>Comment</key>
+      <string>Choose whether to use the region's environment settings, or override them with the local settings.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>UseExternalBrowser</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 721fe81a3c1c76fb9704260933b209f89cf3e118..173e81733c79cacb2ef6bb06184c90ed0d7abc8c 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 23
+version 24
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt
index 1bad7e5260ba4f486f5038c891577de75515aa4a..602f62cf69657fc29196d61e1d5df8db6fe6e28f 100644
--- a/indra/newview/featuretable_linux.txt
+++ b/indra/newview/featuretable_linux.txt
@@ -1,4 +1,4 @@
-version 22
+version 23
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 4fba47e3df7e527a494f110705048c067938d24a..bbe63be5ae343043db15c00ff08966f15892fb4e 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 22
+version 23
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index c9bd7851ed5c610a046130665cea1e94f8de9b79..56d2c76dc7ee941d70bdfebb542f4703abddc771 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -36,8 +36,10 @@
 #include "llanimationstates.h"
 #include "llbottomtray.h"
 #include "llcallingcard.h"
+#include "llcapabilitylistener.h"
 #include "llchannelmanager.h"
 #include "llconsole.h"
+#include "llenvmanager.h"
 #include "llfirstuse.h"
 #include "llfloatercamera.h"
 #include "llfloaterreg.h"
@@ -76,6 +78,7 @@
 #include "llwindow.h"
 #include "llworld.h"
 #include "llworldmap.h"
+#include "stringize.h"
 
 using namespace LLVOAvatarDefines;
 
@@ -620,6 +623,16 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
 				gSky.mVOGroundp->setRegion(regionp);
 			}
 
+			// Notify windlight managers
+			bool teleport = (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE);
+			if (teleport)
+			{
+				LLEnvManager::getInstance()->notifyTP();
+			}
+			else
+			{
+				LLEnvManager::getInstance()->notifyCrossing();
+			}
 		}
 		else
 		{
@@ -636,6 +649,9 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
 
 			// Update all of the regions.
 			LLWorld::getInstance()->updateAgentOffset(mAgentOriginGlobal);
+
+			// Notify windlight managers about login
+			LLEnvManager::getInstance()->notifyLogin();
 		}
 	}
 	mRegionp = regionp;
@@ -653,6 +669,9 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
 	LLSelectMgr::getInstance()->updateSelectionCenter();
 
 	LLFloaterMove::sUpdateFlyingStatus();
+
+       // notify EnvManager that a refresh is needed
+       LLEnvManager::instance().refreshFromStorage(LLEnvKey::SCOPE_REGION);
 }
 
 
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 41a299151e1c08e55a2ea82f7847d38a2ec9fef2..0910d920f2697e74029f645cb1093c0c7571e8ce 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -34,6 +34,8 @@
 #include "llviewercamera.h"
 #include "llimage.h"
 #include "llwlparammanager.h"
+#include "llviewershadermgr.h"
+#include "llglslshader.h"
 #include "llsky.h"
 #include "llvowlsky.h"
 #include "llviewerregion.h"
@@ -66,7 +68,7 @@ LLDrawPoolWLSky::LLDrawPoolWLSky(void) :
 
 	sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
 
-	LLWLParamManager::instance()->propagateParameters();
+	LLWLParamManager::getInstance()->propagateParameters();
 }
 
 LLDrawPoolWLSky::~LLDrawPoolWLSky()
@@ -161,7 +163,7 @@ void LLDrawPoolWLSky::renderStars(void) const
 	// clamping and allow the star_alpha param to brighten the stars.
 	bool error;
 	LLColor4 star_alpha(LLColor4::black);
-	star_alpha.mV[3] = LLWLParamManager::instance()->mCurParams.getFloat("star_brightness", error) / 2.f;
+	star_alpha.mV[3] = LLWLParamManager::getInstance()->mCurParams.getFloat("star_brightness", error) / 2.f;
 	llassert_always(!error);
 
 	gGL.getTexUnit(0)->bind(gSky.mVOSkyp->getBloomTex());
@@ -254,7 +256,7 @@ void LLDrawPoolWLSky::render(S32 pass)
 	}
 	LLFastTimer ftm(FTM_RENDER_WL_SKY);
 
-	const F32 camHeightLocal = LLWLParamManager::instance()->getDomeOffset() * LLWLParamManager::instance()->getDomeRadius();
+	const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius();
 
 	LLGLSNoFog disableFog;
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
diff --git a/indra/newview/llenvmanager.cpp b/indra/newview/llenvmanager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f551aa6c8ad6cb641b713259ca1611b00145cc79
--- /dev/null
+++ b/indra/newview/llenvmanager.cpp
@@ -0,0 +1,474 @@
+/**
+ * @file llenvmanager.cpp
+ * @brief Implementation of classes managing WindLight and water settings.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llenvmanager.h"
+
+#include "llagent.h"
+#include "llviewerregion.h"
+
+#include "llfloaterwindlight.h"
+#include "llfloaterwater.h"
+#include "llfloaterenvsettings.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llfloaterregioninfo.h"
+#include "llwindlightscrubbers.h"
+#include "llwlhandlers.h"
+
+extern LLControlGroup gSavedSettings;
+
+/*virtual*/ void LLEnvManager::initSingleton()
+{
+	mOrigSettingStore[LLEnvKey::SCOPE_LOCAL] = lindenDefaults();
+	mCurNormalScope = (gSavedSettings.getBOOL("UseEnvironmentFromRegion") ? LLEnvKey::SCOPE_REGION : LLEnvKey::SCOPE_LOCAL);
+	mInterpNextChangeMessage = true;
+	mPendingOutgoingMessage = false;
+	mIsEditing = false;
+}
+
+/*******
+ * Region Changes
+ *******/
+
+void LLEnvManager::notifyLogin()
+{
+	changedRegion(false);
+}
+void LLEnvManager::notifyCrossing()
+{
+	changedRegion(true);
+}
+void LLEnvManager::notifyTP()
+{
+	changedRegion(false);
+}
+void LLEnvManager::changedRegion(bool interp)
+{
+	mInterpNextChangeMessage = interp;
+	mPendingOutgoingMessage = false;
+
+	LLFloaterEnvSettings::instance()->close();
+
+	resetInternalsToDefault(LLEnvKey::SCOPE_REGION);
+
+	maybeClearEditingScope(LLEnvKey::SCOPE_REGION, true, false);
+}
+
+/*******
+ * Editing settings / UI mode
+ *******/
+
+void LLEnvManager::startEditingScope(LLEnvKey::EScope scope)
+{
+	if (mIsEditing)
+	{
+		LL_WARNS("Windlight") << "Tried to start editing windlight settings while already editing some settings (possibly others)!  Ignoring..." << LL_ENDL;
+		return;
+	}
+	if (!canEdit(scope))
+	{
+		LL_WARNS("Windlight") << "Tried to start editing windlight settings while not allowed to!  Ignoring..." << LL_ENDL;
+		return;
+	}
+
+	mIsEditing = true;
+	mCurEditingScope = scope;
+
+	// show scope being edited
+	loadSettingsIntoManagers(scope, false);
+	
+	switch (scope)
+	{
+	case LLEnvKey::SCOPE_LOCAL:
+		// not implemented here (yet)
+		return;
+	case LLEnvKey::SCOPE_REGION:
+		LLPanelRegionTerrainInfo::instance()->setCommitControls(true);
+		break;
+	default:
+		return;
+	}
+}
+
+void LLEnvManager::maybeClearEditingScope(LLEnvKey::EScope scope, bool user_initiated, bool was_commit)
+{
+	if (mIsEditing && mCurEditingScope == scope)
+	{
+		maybeClearEditingScope(user_initiated, was_commit); // handles UI, updating managers, etc.
+	}
+}
+
+void LLEnvManager::maybeClearEditingScope(bool user_initiated, bool was_commit)
+{
+	bool clear_now = true;
+	if (mIsEditing && !was_commit)
+	{
+		if(user_initiated)
+		{
+			LLSD args;
+			args["SCOPE"] = getScopeString(mCurEditingScope);
+			LLNotifications::instance().add("EnvEditUnsavedChangesCancel", args, LLSD(),
+								boost::bind(&LLEnvManager::clearEditingScope, this, _1, _2));
+			clear_now = false;
+		}
+		else
+		{
+			LLNotifications::instance().add("EnvEditExternalCancel", LLSD());
+		}
+	}
+
+	if(clear_now)
+	{
+		clearEditingScope(LLSD(), LLSD());
+	}
+}
+
+void LLEnvManager::clearEditingScope(const LLSD& notification, const LLSD& response)
+{
+	if(notification.isDefined() && response.isDefined() && LLNotification::getSelectedOption(notification, response) != 0)
+	{
+		// *TODO: select terrain panel here
+		mIsEditing = false;
+		LLFloaterRegionInfo::showInstance();
+		return;
+	}
+
+	mIsEditing = false;
+
+	updateUIFromEditability();
+	LLPanelRegionTerrainInfo::instance()->cancelChanges();
+
+	loadSettingsIntoManagers(mCurNormalScope, true);
+}
+
+void LLEnvManager::updateUIFromEditability()
+{
+	// *TODO When the checkbox from LLFloaterEnvSettings is moved elsewhere, opening the local environment settings window should auto-display local settings
+	// Currently, disable all editing to ensure region settings are hidden from those that can't edit them (to preserve possibility of future tradable assets)
+	// Remove "!gSavedSettings.getBOOL(...)" when the desired behavior is implemented
+	LLFloaterEnvSettings::instance()->setControlsEnabled(canEdit(LLEnvKey::SCOPE_LOCAL) && !gSavedSettings.getBOOL("UseEnvironmentFromRegion"));
+	LLPanelRegionTerrainInfo::instance()->setEnvControls(canEdit(LLEnvKey::SCOPE_REGION));
+	// enable estate UI iff canEdit(LLEnvKey::SCOPE_ESTATE), etc.
+}
+
+bool LLEnvManager::regionCapable()
+{
+	return !gAgent.getRegion()->getCapability("EnvironmentSettings").empty();
+}
+
+const std::string LLEnvManager::getScopeString(LLEnvKey::EScope scope)
+{
+	switch(scope)
+	{
+		case LLEnvKey::SCOPE_LOCAL:
+			return LLTrans::getString("LocalSettings");
+		case LLEnvKey::SCOPE_REGION:
+			return LLTrans::getString("RegionSettings");
+		default:
+			return " (?)";
+	}
+}
+
+bool LLEnvManager::canEdit(LLEnvKey::EScope scope)
+{
+	// can't edit while a message is being sent or if already editing
+	if (mPendingOutgoingMessage || mIsEditing)
+	{
+		return false;
+	}
+
+	// check permissions and caps
+	switch (scope)
+	{
+	case LLEnvKey::SCOPE_LOCAL:
+		return true; // always permitted to edit local
+	case LLEnvKey::SCOPE_REGION:
+		bool owner_or_god_or_manager;
+		{
+			LLViewerRegion* region = gAgent.getRegion();
+			if (NULL == region || region->getCapability("EnvironmentSettings").empty())
+			{
+				// not a windlight-aware region
+				return false;
+			}
+			owner_or_god_or_manager = gAgent.isGodlike()
+				|| (region && (region->getOwner() == gAgent.getID()))
+				|| (region && region->isEstateManager());
+		}
+		return owner_or_god_or_manager;
+	default:
+		return false;
+	}
+}
+
+/*******
+ * Incoming Messaging
+ *******/
+
+void LLEnvManager::refreshFromStorage(LLEnvKey::EScope scope)
+{
+	switch (scope)
+	{
+	case LLEnvKey::SCOPE_LOCAL:
+		break;
+	case LLEnvKey::SCOPE_REGION:
+		if (!LLEnvironmentRequestResponder::initiateRequest())
+		{
+			// don't have a cap for this, presume invalid response
+			processIncomingMessage(LLSD(), scope);
+		}
+		break;
+	default:
+		processIncomingMessage(LLSD(), scope);
+		break;
+	}
+}
+
+bool LLEnvManager::processIncomingMessage(const LLSD& unvalidated_content, const LLEnvKey::EScope scope)
+{
+	if (scope != LLEnvKey::SCOPE_REGION)
+	{
+		return false;
+	}
+
+	// Start out with defaults
+	resetInternalsToDefault(scope);
+	updateUIFromEditability();
+
+	// Validate
+	std::set<std::string> empty_set;
+	LLWLPacketScrubber scrubber(scope, empty_set);
+	LLSD windlight_llsd = scrubber.scrub(unvalidated_content);
+
+	bool valid = windlight_llsd.isDefined(); // successful scrub
+
+	mLastReceivedID = unvalidated_content[0]["messageID"].asUUID();		// if the message was valid, grab the UUID from it and save it for next outbound update message
+
+	if (valid)
+	{
+		F32 sun_hour = LLPanelRegionTerrainInfo::instance()->getSunHour();	// this slider is kept up to date
+		LLWLParamManager::getInstance()->addAllSkies(scope, windlight_llsd[2]);
+		LLEnvironmentSettings newSettings(windlight_llsd[1], windlight_llsd[2], windlight_llsd[3], sun_hour);
+		mOrigSettingStore[scope] = newSettings;
+	}
+	else
+	{
+		LL_WARNS("Windlight Sync") << "Failed to parse windlight settings!" << LL_ENDL;
+		// presume defaults (already reset above)
+	}
+
+	maybeClearEditingScope(scope, false, false);
+
+	// refresh display with new settings, if applicable
+	if (mCurNormalScope == scope && !mIsEditing) // if mIsEditing still, must be editing some other scope, so don't load
+	{
+		loadSettingsIntoManagers(scope, mInterpNextChangeMessage);
+	}
+
+	mInterpNextChangeMessage = true; // reset flag
+
+	return valid;
+}
+
+
+/*******
+ * Outgoing Messaging
+ *******/
+
+void LLEnvManager::commitSettings(LLEnvKey::EScope scope)
+{
+	bool success = true;
+	switch (scope)
+	{
+	case (LLEnvKey::SCOPE_LOCAL):
+		// not implemented - LLWLParamManager and LLWaterParamManager currently manage local storage themselves
+		break;
+	case (LLEnvKey::SCOPE_REGION):
+		mPendingOutgoingMessage = true;
+		LLSD metadata(LLSD::emptyMap());
+		metadata["regionID"] = gAgent.getRegion()->getRegionID();
+		metadata["messageID"] = mLastReceivedID;			// add last received update ID to outbound message so simulator can handle concurrent updates
+
+		saveSettingsFromManagers(scope);	// save current settings into settings store before grabbing from settings store and sending
+		success = LLEnvironmentApplyResponder::initiateRequest(makePacket(LLEnvKey::SCOPE_REGION, metadata));
+		if(success)
+		{
+			// while waiting for the return message, render old settings
+			// (as of Aug 09, we should get an updated RegionInfo packet, which triggers a re-request of Windlight data, which causes us to show new settings)
+			loadSettingsIntoManagers(LLEnvKey::SCOPE_REGION, true);
+		}
+		break;
+	}
+
+	if(success)
+	{
+		// with mPendingOutgoingMessage = true, nothing is editable
+		updateUIFromEditability();
+		maybeClearEditingScope(true, true);
+	}
+	else
+	{
+		mPendingOutgoingMessage = false;
+	}
+}
+
+LLSD LLEnvManager::makePacket(LLEnvKey::EScope scope, const LLSD& metadata)
+{
+	return mOrigSettingStore[scope].makePacket(metadata);
+}
+
+void LLEnvManager::commitSettingsFinished(LLEnvKey::EScope scope)
+{
+	mPendingOutgoingMessage = false;
+
+	updateUIFromEditability();
+}
+
+/*******
+ * Loading defaults
+ *******/
+
+void LLEnvManager::resetInternalsToDefault(LLEnvKey::EScope scope)
+{
+	if (LLEnvKey::SCOPE_LOCAL != scope)
+	{
+		LLWLParamManager::getInstance()->clearParamSetsOfScope(scope);
+	}
+
+	mOrigSettingStore[scope] = lindenDefaults();
+	LLWLParamManager::getInstance()->mAnimator.setTimeType(LLWLAnimator::TIME_LINDEN);
+}
+
+const LLEnvironmentSettings& LLEnvManager::lindenDefaults()
+{
+	static bool loaded = false;
+	static LLEnvironmentSettings defSettings;
+
+	if (!loaded)
+	{
+		LLWaterParamSet defaultWater;
+		LLWaterParamManager::instance().getParamSet("default", defaultWater);
+
+		// *TODO save default skies (remove hack in LLWLDayCycle::loadDayCycle when this is done)
+
+		defSettings.saveParams(
+			LLWLDayCycle::loadCycleDataFromFile("default.xml"), // frames will refer to local presets, which is okay
+			LLSD(LLSD::emptyMap()), // should never lose the default sky presets (read-only)
+			defaultWater.getAll(),
+			0.0);
+
+		loaded = true;
+	}
+
+	return defSettings;
+}
+
+/*******
+ * Manipulation of Param Managers
+ *******/
+
+void LLEnvManager::loadSettingsIntoManagers(LLEnvKey::EScope scope, bool interpolate)
+{
+	LLEnvironmentSettings settings = mOrigSettingStore[scope];
+
+	if(interpolate)
+	{
+		LLWLParamManager::getInstance()->mAnimator.startInterpolation(settings.getWaterParams());
+	}
+
+	LLWLParamManager::getInstance()->addAllSkies(scope, settings.getSkyMap());
+	LLWLParamManager::getInstance()->mDay.loadDayCycle(settings.getWLDayCycle(), scope);
+	LLWLParamManager::getInstance()->resetAnimator(settings.getDayTime(), true);
+
+	LLWaterParamManager::getInstance()->mCurParams.setAll(settings.getWaterParams());
+}
+
+void LLEnvManager::saveSettingsFromManagers(LLEnvKey::EScope scope)
+{
+	switch (scope)
+	{
+	case LLEnvKey::SCOPE_LOCAL:
+		mOrigSettingStore[scope].saveParams(
+							LLWLParamManager::getInstance()->mDay.asLLSD(),
+							LLSD(LLSD::emptyMap()), // never overwrite
+							LLWaterParamManager::getInstance()->mCurParams.getAll(),
+							LLWLParamManager::getInstance()->mAnimator.mDayTime);
+		break;
+	case LLEnvKey::SCOPE_REGION:
+		{
+			// ensure only referenced region-scope skies are saved, resolve naming collisions, etc.
+			std::map<LLWLParamKey, LLWLParamSet> final_references = LLWLParamManager::getInstance()->finalizeFromDayCycle(scope);
+			LLSD referenced_skies = LLWLParamManager::getInstance()->createSkyMap(final_references);
+			mOrigSettingStore[scope].saveParams(
+								LLWLParamManager::getInstance()->mDay.asLLSD(),
+								referenced_skies,
+								LLWaterParamManager::getInstance()->mCurParams.getAll(),
+								LLWLParamManager::getInstance()->mAnimator.mDayTime);
+		}
+		break;
+	default:
+		return;
+	}
+}
+
+/*******
+ * Setting desired display level
+ *******/
+
+void LLEnvManager::setNormallyDisplayedScope(LLEnvKey::EScope new_scope)
+{
+	// temp, just save the scope directly as a value in the future when there's more than two
+	bool want_region = (LLEnvKey::SCOPE_REGION == new_scope);
+	gSavedSettings.setBOOL("UseEnvironmentFromRegion", want_region);
+
+	if (mCurNormalScope != new_scope)
+	{
+		mCurNormalScope = new_scope;
+		notifyOptInChange();
+	}
+}
+
+void LLEnvManager::notifyOptInChange()
+{
+	bool opt_in = gSavedSettings.getBOOL("UseEnvironmentFromRegion");
+
+	// Save local settings if switching to region
+	if(opt_in)
+	{
+		LL_INFOS("Windlight") << "Saving currently-displayed settings as current local settings..." << LL_ENDL;
+		saveSettingsFromManagers(LLEnvKey::SCOPE_LOCAL);
+	}
+
+	maybeClearEditingScope(true, false);
+}
diff --git a/indra/newview/llenvmanager.h b/indra/newview/llenvmanager.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ff465400371e00fe125d69473392f7c31f5e02e
--- /dev/null
+++ b/indra/newview/llenvmanager.h
@@ -0,0 +1,214 @@
+/**
+ * @file llenvmanager.h
+ * @brief Declaration of classes managing WindLight and water settings.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLENVMANAGER_H
+#define LL_LLENVMANAGER_H
+
+#include "llmemory.h"
+#include "llsd.h"
+
+class LLWLParamManager;
+class LLWaterParamManager;
+class LLWLAnimator;
+
+// generic key
+struct LLEnvKey
+{
+public:
+	// Note: enum ordering is important; for example, a region-level floater (1) will see local and region (all values that are <=)
+	typedef enum e_scope
+	{
+		SCOPE_LOCAL,				// 0
+		SCOPE_REGION//,				// 1
+		// SCOPE_ESTATE,			// 2
+		// etc.
+	} EScope;
+};
+
+class LLEnvironmentSettings
+{
+public:
+	LLEnvironmentSettings() :
+		mWLDayCycle(LLSD::emptyMap()),
+		mSkyMap(LLSD::emptyMap()),
+		mWaterParams(LLSD::emptyMap()),
+		mDayTime(0.f)
+	{}
+	LLEnvironmentSettings(const LLSD& dayCycle, const LLSD& skyMap, const LLSD& waterParams, F64 dayTime) :
+		mWLDayCycle(dayCycle),
+		mSkyMap(skyMap),
+		mWaterParams(waterParams),
+		mDayTime(dayTime)
+	{}
+	~LLEnvironmentSettings() {}
+
+	void saveParams(const LLSD& dayCycle, const LLSD& skyMap, const LLSD& waterParams, F64 dayTime)
+	{
+		mWLDayCycle = dayCycle;
+		mSkyMap = skyMap;
+		mWaterParams = waterParams;
+		mDayTime = dayTime;
+	}
+
+	LLSD& getWLDayCycle()
+	{
+		return mWLDayCycle;
+	}
+
+	LLSD& getWaterParams()
+	{
+		return mWaterParams;
+	}
+
+	LLSD& getSkyMap()
+	{
+		return mSkyMap;
+	}
+
+	F64 getDayTime()
+	{
+		return mDayTime;
+	}
+
+	LLSD makePacket(const LLSD& metadata)
+	{
+		LLSD full_packet = LLSD::emptyArray();
+
+		// 0: metadata
+		full_packet.append(metadata);
+
+		// 1: day cycle
+		full_packet.append(mWLDayCycle);
+
+		// 2: map of sky setting names to sky settings (as LLSD)
+		full_packet.append(mSkyMap);
+
+		// 3: water params
+		full_packet.append(mWaterParams);
+
+		return full_packet;
+	}
+
+private:
+	LLSD mWLDayCycle, mWaterParams, mSkyMap;
+	F64 mDayTime;
+};
+
+// not thread-safe
+class LLEnvManager : public LLSingleton<LLEnvManager>
+{
+public:
+	// sets scopes (currently, only region-scope) to startup states
+	// delay calling these until as close as possible to knowing whether the remote service is capable of holding windlight settings
+	void notifyCrossing();
+	// these avoid interpolation on the next incoming message (if it comes)
+	void notifyLogin();
+	void notifyTP();
+
+	// request settings again from remote storage (currently implemented only for region)
+	void refreshFromStorage(LLEnvKey::EScope scope);
+	// stores settings and starts transitions (as necessary)
+	// validates packet and returns whether it was valid
+	// loads defaults if not valid
+	// returns whether or not arguments were valid
+	bool processIncomingMessage(const LLSD& packet, LLEnvKey::EScope scope);
+	// saves settings in the given scope to persistent storage appropriate for that scope
+	void commitSettings(LLEnvKey::EScope scope);
+	// called back when the commit finishes
+	void commitSettingsFinished(LLEnvKey::EScope scope);
+
+	/* 
+	 * notify of changes in god/not-god mode, estate ownership, etc.
+	 * should be called every time after entering new region (after receiving new caps)
+	 */
+	void notifyPermissionChange();
+
+	bool regionCapable();
+	static const std::string getScopeString(LLEnvKey::EScope scope);
+	bool canEdit(LLEnvKey::EScope scope);
+	// enables and populates UI
+	// populates display (param managers) with scope's settings
+	// silently fails if canEdit(scope) is false!
+	void startEditingScope(LLEnvKey::EScope scope);
+	// cancel and close UI as necessary
+	// reapplies unedited settings
+	// displays the settings from the scope that user has set (i.e. opt-in setting for now)
+	void maybeClearEditingScope(bool user_initiated, bool was_commit);
+	// clear the scope only if was editing that scope
+	void maybeClearEditingScope(LLEnvKey::EScope scope, bool user_initiated, bool was_commit);
+	// actually do the clearing
+	void clearEditingScope(const LLSD& notification, const LLSD& response);
+
+	// clear and reload defaults into scope
+	void resetInternalsToDefault(LLEnvKey::EScope scope);
+
+	// sets which scope is to be displayed
+	// fix me if/when adding more levels of scope
+	void setNormallyDisplayedScope(LLEnvKey::EScope scope);
+
+private:
+	// overriden initializer
+	friend class LLSingleton<LLEnvManager>;
+	virtual void initSingleton();
+	// helper function (when region changes, but before caps are received)
+	void changedRegion(bool interpolate);
+	// apply to current display and UI
+	void loadSettingsIntoManagers(LLEnvKey::EScope scope, bool interpolate);
+	// save from current display and UI into memory (mOrigSettingStore)
+	void saveSettingsFromManagers(LLEnvKey::EScope scope);
+
+	// Save copy of settings from the current ones in the param managers
+	LLEnvironmentSettings collateFromParamManagers();
+	// bundle settings (already committed from UI) into an LLSD
+	LLSD makePacket(LLEnvKey::EScope scope, const LLSD& metadata);
+
+	void updateUIFromEditability();
+
+	// only call when setting *changes*, not just when it might have changed
+	// saves local settings into mOrigSettingStore when necessary
+	void notifyOptInChange();
+
+	// calculate Linden default settings
+	static const LLEnvironmentSettings& lindenDefaults();
+
+	std::map<LLEnvKey::EScope, LLEnvironmentSettings> mOrigSettingStore; // settings which have been committed from UI
+
+	bool mInterpNextChangeMessage;
+	bool mPendingOutgoingMessage;
+	bool mIsEditing;
+	LLEnvKey::EScope mCurNormalScope; // scope being displayed when not editing (i.e. most of the time)
+	LLEnvKey::EScope mCurEditingScope;
+	LLUUID mLastReceivedID;
+};
+
+#endif // LL_LLENVMANAGER_H
+
diff --git a/indra/newview/llfloaterdaycycle.cpp b/indra/newview/llfloaterdaycycle.cpp
index 22816ee8025267173335cef4236107832c039eeb..efaac5cfc568cbde917c441e9f8af187524003a8 100644
--- a/indra/newview/llfloaterdaycycle.cpp
+++ b/indra/newview/llfloaterdaycycle.cpp
@@ -2,25 +2,31 @@
  * @file llfloaterdaycycle.cpp
  * @brief LLFloaterDayCycle class definition
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
  * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
 
@@ -51,34 +57,23 @@
 #include "llwlparammanager.h"
 #include "llpostprocess.h"
 #include "llfloaterwindlight.h"
+#include "llwindlightscrubbers.h"
+#include "llenvmanager.h"
 
-
-std::map<std::string, LLWLSkyKey> LLFloaterDayCycle::sSliderToKey;
+LLFloaterDayCycle* LLFloaterDayCycle::sDayCycle = NULL;
 const F32 LLFloaterDayCycle::sHoursPerDay = 24.0f;
+std::map<std::string, LLWLCycleSliderKey> LLFloaterDayCycle::sSliderToKey;
+LLEnvKey::EScope LLFloaterDayCycle::sScope;
+std::string LLFloaterDayCycle::sOriginalTitle;
+LLWLAnimator::ETime LLFloaterDayCycle::sPreviousTimeType = LLWLAnimator::TIME_LINDEN;
 
-LLFloaterDayCycle::LLFloaterDayCycle(const LLSD& key)	
-: LLFloater(key)
+LLFloaterDayCycle::LLFloaterDayCycle() : LLFloater(std::string("Day Cycle Floater"))
 {
-}
+	LLUICtrlFactory::getInstance()->buildFloater(this, "floater_day_cycle_options.xml", NULL, FALSE);
+	sOriginalTitle = getTitle();
 
-BOOL LLFloaterDayCycle::postBuild()
-{
-	// add the combo boxes
-	LLComboBox* keyCombo = getChild<LLComboBox>("WLKeyPresets");
-
-	if(keyCombo != NULL) 
-	{
-		keyCombo->removeall();
-		std::map<std::string, LLWLParamSet>::iterator mIt = 
-			LLWLParamManager::instance()->mParamList.begin();
-		for(; mIt != LLWLParamManager::instance()->mParamList.end(); mIt++) 
-		{
-			keyCombo->add(std::string(mIt->first));
-		}
-
-		// set defaults on combo boxes
-		keyCombo->selectFirstItem();
-	}
+	llassert(MAX_LOCAL_KEY_FRAMES <= getChild<LLMultiSliderCtrl>("WLDayCycleKeys")->getMaxSliderCount() &&
+		     MAX_REGION_KEYFRAMES <= getChild<LLMultiSliderCtrl>("WLDayCycleKeys")->getMaxSliderCount());
 
 	// add the time slider
 	LLMultiSliderCtrl* sldr = getChild<LLMultiSliderCtrl>("WLTimeSlider");
@@ -87,57 +82,67 @@ BOOL LLFloaterDayCycle::postBuild()
 
 	// load it up
 	initCallbacks();
-
-	syncMenu();
-	syncSliderTrack();
-	
-	return TRUE;
 }
 
 LLFloaterDayCycle::~LLFloaterDayCycle()
 {
 }
 
+void LLFloaterDayCycle::onClickHelp(void* data)
+{
+	LLFloaterDayCycle* self = LLFloaterDayCycle::instance();
+
+	std::string xml_alert = *(std::string *) data;
+	LLNotifications::instance().add(self->contextualNotification(xml_alert));
+}
+
+void LLFloaterDayCycle::initHelpBtn(const std::string& name, const std::string& xml_alert)
+{
+	childSetAction(name, onClickHelp, new std::string(xml_alert));
+}
+
 void LLFloaterDayCycle::initCallbacks(void) 
 {
+	initHelpBtn("WLDayCycleHelp", "HelpDayCycle");
+
 	// WL Day Cycle
-	getChild<LLUICtrl>("WLTimeSlider")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onTimeSliderMoved, this, _1));
-	getChild<LLUICtrl>("WLDayCycleKeys")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onKeyTimeMoved, this, _1));
-	getChild<LLUICtrl>("WLCurKeyHour")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onKeyTimeChanged, this, _1));
-	getChild<LLUICtrl>("WLCurKeyMin")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onKeyTimeChanged, this, _1));
-	getChild<LLUICtrl>("WLKeyPresets")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onKeyPresetChanged, this, _1));
-
-	getChild<LLUICtrl>("WLLengthOfDayHour")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onTimeRateChanged, this, _1));
-	getChild<LLUICtrl>("WLLengthOfDayMin")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onTimeRateChanged, this, _1));
-	getChild<LLUICtrl>("WLLengthOfDaySec")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onTimeRateChanged, this, _1));
-	getChild<LLUICtrl>("WLUseLindenTime")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onUseLindenTime, this, _1));
-	getChild<LLUICtrl>("WLAnimSky")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onRunAnimSky, this, _1));
-	getChild<LLUICtrl>("WLStopAnimSky")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onStopAnimSky, this, _1));
-
-	getChild<LLUICtrl>("WLLoadDayCycle")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onLoadDayCycle, this, _1));
-	getChild<LLUICtrl>("WLSaveDayCycle")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onSaveDayCycle, this, _1));
-
-	getChild<LLUICtrl>("WLAddKey")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onAddKey, this, _1));
-	getChild<LLUICtrl>("WLDeleteKey")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onDeleteKey, this, _1));
+	childSetCommitCallback("WLTimeSlider", onTimeSliderMoved, NULL);
+	childSetCommitCallback("WLDayCycleKeys", onKeyTimeMoved, NULL);
+	childSetCommitCallback("WLCurKeyHour", onKeyTimeChanged, NULL);
+	childSetCommitCallback("WLCurKeyMin", onKeyTimeChanged, NULL);
+	childSetCommitCallback("WLKeyPresets", onKeyPresetChanged, NULL);
+
+	childSetCommitCallback("WLLengthOfDayHour", onTimeRateChanged, NULL);
+	childSetCommitCallback("WLLengthOfDayMin", onTimeRateChanged, NULL);
+	childSetCommitCallback("WLLengthOfDaySec", onTimeRateChanged, NULL);
+	childSetAction("WLUseLindenTime", onUseLindenTime, NULL);
+	childSetAction("WLAnimSky", onRunAnimSky, NULL);
+	childSetAction("WLStopAnimSky", onStopAnimSky, NULL);
+
+	childSetAction("WLLoadDayCycle", onLoadDayCycle, NULL);
+	childSetAction("WLSaveDayCycle", onSaveDayCycle, NULL);
+
+	childSetAction("WLAddKey", onAddKey, NULL);
+	childSetAction("WLDeleteKey", onDeleteKey, NULL);
 }
 
 void LLFloaterDayCycle::syncMenu()
 {
-//	std::map<std::string, LLVector4> & currentParams = LLWLParamManager::instance()->mCurParams.mParamValues;
+//	std::map<std::string, LLVector4> & currentParams = LLWLParamManager::getInstance()->mCurParams.mParamValues;
 	
 	// set time
-	LLMultiSliderCtrl* sldr = getChild<LLMultiSliderCtrl>("WLTimeSlider");
-	sldr->setCurSliderValue((F32)LLWLParamManager::instance()->mAnimator.getDayTime() * sHoursPerDay);
+	LLMultiSliderCtrl* sldr = LLFloaterDayCycle::sDayCycle->getChild<LLMultiSliderCtrl>("WLTimeSlider");
+	sldr->setCurSliderValue((F32)LLWLParamManager::getInstance()->mAnimator.getDayTime() * sHoursPerDay);
 
-	LLSpinCtrl* secSpin = getChild<LLSpinCtrl>("WLLengthOfDaySec");
-	LLSpinCtrl* minSpin = getChild<LLSpinCtrl>("WLLengthOfDayMin");
-	LLSpinCtrl* hourSpin = getChild<LLSpinCtrl>("WLLengthOfDayHour");
+	LLSpinCtrl* secSpin = sDayCycle->getChild<LLSpinCtrl>("WLLengthOfDaySec");
+	LLSpinCtrl* minSpin = sDayCycle->getChild<LLSpinCtrl>("WLLengthOfDayMin");
+	LLSpinCtrl* hourSpin = sDayCycle->getChild<LLSpinCtrl>("WLLengthOfDayHour");
 
 	F32 curRate;
 	F32 hours, min, sec;
 
 	// get the current rate
-	curRate = LLWLParamManager::instance()->mDay.mDayRate;
+	curRate = LLWLParamManager::getInstance()->mDay.mDayRate;
 	hours = (F32)((int)(curRate / 60 / 60));
 	curRate -= (hours * 60 * 60);
 	min = (F32)((int)(curRate / 60));
@@ -149,28 +154,28 @@ void LLFloaterDayCycle::syncMenu()
 	secSpin->setValue(sec);
 
 	// turn off Use Estate Time button if it's already being used
-	if(	LLWLParamManager::instance()->mAnimator.mUseLindenTime == true)
+	if(	LLWLParamManager::getInstance()->mAnimator.getUseLindenTime())
 	{
-		getChildView("WLUseLindenTime")->setEnabled(FALSE);
+		LLFloaterDayCycle::sDayCycle->childDisable("WLUseLindenTime");
 	} 
 	else 
 	{
-		getChildView("WLUseLindenTime")->setEnabled(TRUE);
+		LLFloaterDayCycle::sDayCycle->childEnable("WLUseLindenTime");
 	}
 }
 
 void LLFloaterDayCycle::syncSliderTrack()
 {
 	// clear the slider
-	LLMultiSliderCtrl* kSldr = getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
+	LLMultiSliderCtrl* kSldr = sDayCycle->getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
 
 	kSldr->clear();
 	sSliderToKey.clear();
 
 	// add sliders
-	std::map<F32, std::string>::iterator mIt = 
-		LLWLParamManager::instance()->mDay.mTimeMap.begin();
-	for(; mIt != LLWLParamManager::instance()->mDay.mTimeMap.end(); mIt++) 
+	std::map<F32, LLWLParamKey>::iterator mIt = 
+		LLWLParamManager::getInstance()->mDay.mTimeMap.begin();
+	for(; mIt != LLWLParamManager::getInstance()->mDay.mTimeMap.end(); mIt++) 
 	{
 		addSliderKey(mIt->first * sHoursPerDay, mIt->second);
 	}
@@ -185,34 +190,115 @@ void LLFloaterDayCycle::syncTrack()
 	}
 	
 	LLMultiSliderCtrl* sldr;
-	sldr = getChild<LLMultiSliderCtrl>( 
+	sldr = sDayCycle->getChild<LLMultiSliderCtrl>( 
 		"WLDayCycleKeys");
 	llassert_always(sSliderToKey.size() == sldr->getValue().size());
 	
 	LLMultiSliderCtrl* tSldr;
-	tSldr = getChild<LLMultiSliderCtrl>( 
+	tSldr = sDayCycle->getChild<LLMultiSliderCtrl>( 
 		"WLTimeSlider");
 
 	// create a new animation track
-	LLWLParamManager::instance()->mDay.clearKeys();
+	LLWLParamManager::getInstance()->mDay.clearKeyframes();
 	
 	// add the keys one by one
-	std::map<std::string, LLWLSkyKey>::iterator mIt = sSliderToKey.begin();
+	std::map<std::string, LLWLCycleSliderKey>::iterator mIt = sSliderToKey.begin();
 	for(; mIt != sSliderToKey.end(); mIt++) 
 	{
-		LLWLParamManager::instance()->mDay.addKey(mIt->second.time / sHoursPerDay, 
-			mIt->second.presetName);
+		LLWLParamManager::getInstance()->mDay.addKeyframe(mIt->second.time / sHoursPerDay, 
+			mIt->second.keyframe);
 	}
 	
 	// set the param manager's track to the new one
-	LLWLParamManager::instance()->resetAnimator(
+	LLWLParamManager::getInstance()->resetAnimator(
 		tSldr->getCurSliderValue() / sHoursPerDay, false);
 
-	LLWLParamManager::instance()->mAnimator.update(
-		LLWLParamManager::instance()->mCurParams);
+	LLWLParamManager::getInstance()->mAnimator.update(
+		LLWLParamManager::getInstance()->mCurParams);
+}
+
+void LLFloaterDayCycle::refreshPresetsFromParamManager()
+{
+	LLComboBox* keyCombo = sDayCycle->getChild<LLComboBox>("WLKeyPresets");
+
+	if(keyCombo != NULL) 
+	{
+		std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = 
+			LLWLParamManager::getInstance()->mParamList.begin();
+		for(; mIt != LLWLParamManager::getInstance()->mParamList.end(); mIt++) 
+		{
+			if(mIt->first.scope <= sScope)
+			{
+				llinfos << "Adding key: " << mIt->first.toString() << llendl;
+				keyCombo->add(mIt->first.toString(), LLSD(mIt->first.toStringVal()));
+			}
+		}
+
+		// set defaults on combo boxes
+		keyCombo->selectFirstItem();
+	}
 }
 
-void LLFloaterDayCycle::onRunAnimSky(LLUICtrl* ctrl)
+// static
+LLFloaterDayCycle* LLFloaterDayCycle::instance()
+{
+	if (!sDayCycle)
+	{
+		sDayCycle = new LLFloaterDayCycle();
+		// sDayCycle->open();
+		// sDayCycle->setFocus(TRUE);
+	}
+	return sDayCycle;
+}
+
+bool LLFloaterDayCycle::isOpen()
+{
+	if (sDayCycle != NULL) 
+	{
+		return true;
+	}
+	return false;
+}
+
+void LLFloaterDayCycle::show(LLEnvKey::EScope scope)
+{
+	LLFloaterDayCycle* dayCycle = instance();
+	if(scope != sScope && ((LLView*)dayCycle)->getVisible())
+	{
+		LLNotifications::instance().add("EnvOtherScopeAlreadyOpen", LLSD());
+		return;
+	}
+	sScope = scope;
+	std::string title = sOriginalTitle + " (" + LLEnvManager::getScopeString(sScope) + ")";
+	dayCycle->setTitle(title);
+	refreshPresetsFromParamManager();
+	dayCycle->syncMenu();
+	syncSliderTrack();
+
+	// set drop-down menu to match preset of currently-selected keyframe (one is automatically selected initially)
+	const std::string& curSldr = sDayCycle->getChild<LLMultiSliderCtrl>("WLDayCycleKeys")->getCurSlider();
+	if(strlen(curSldr.c_str()) > 0)	// only do this if there is a curSldr, otherwise we put an invalid entry into the map
+	{	
+		sDayCycle->getChild<LLComboBox>("WLKeyPresets")->selectByValue(sSliderToKey[curSldr].keyframe.toStringVal());
+	}
+
+	// comment in if you want the menu to rebuild each time
+	//LLUICtrlFactory::getInstance()->buildFloater(dayCycle, "floater_day_cycle_options.xml");
+	//dayCycle->initCallbacks();
+
+	dayCycle->open();
+}
+
+// virtual
+void LLFloaterDayCycle::onClose(bool app_quitting)
+{
+	if (sDayCycle)
+	{
+		sDayCycle->setVisible(FALSE);
+	}
+}
+
+void LLFloaterDayCycle::onRunAnimSky(void* userData)
 {
 	// if no keys, do nothing
 	if(sSliderToKey.size() == 0) 
@@ -221,46 +307,47 @@ void LLFloaterDayCycle::onRunAnimSky(LLUICtrl* ctrl)
 	}
 	
 	LLMultiSliderCtrl* sldr;
-	sldr = getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
+	sldr = sDayCycle->getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
 	llassert_always(sSliderToKey.size() == sldr->getValue().size());
 
-	LLMultiSliderCtrl* tSldr;
-	tSldr = getChild<LLMultiSliderCtrl>("WLTimeSlider");
+	LLMultiSliderCtrl* tSldr = sDayCycle->getChild<LLMultiSliderCtrl>("WLTimeSlider");
+
+	sPreviousTimeType = LLWLParamManager::getInstance()->mAnimator.getTimeType();
 
 	// turn off linden time
-	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+	LLWLParamManager::getInstance()->mAnimator.setTimeType(LLWLAnimator::TIME_CUSTOM);
 
 	// set the param manager's track to the new one
-	LLWLParamManager::instance()->resetAnimator(
-		tSldr->getCurSliderValue() / sHoursPerDay, true);
+	LLWLParamManager::getInstance()->resetAnimator(tSldr->getCurSliderValue() / sHoursPerDay, true);
 
-	llassert_always(LLWLParamManager::instance()->mAnimator.mTimeTrack.size() == sldr->getValue().size());
+	llassert_always(LLWLParamManager::getInstance()->mAnimator.mTimeTrack.size() == sldr->getValue().size());
 }
 
-void LLFloaterDayCycle::onStopAnimSky(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onStopAnimSky(void* userData)
 {
 	// if no keys, do nothing
 	if(sSliderToKey.size() == 0) {
 		return;
 	}
 
-	// turn off animation and using linden time
-	LLWLParamManager::instance()->mAnimator.mIsRunning = false;
-	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+	LLWLParamManager::getInstance()->mAnimator.deactivate();	// turn off animation and using linden time
+	LLMultiSliderCtrl* tSldr = sDayCycle->getChild<LLMultiSliderCtrl>("WLTimeSlider");
+	LLWLParamManager::getInstance()->resetAnimator(tSldr->getCurSliderValue() / sHoursPerDay, false);
+	LLWLParamManager::getInstance()->mAnimator.setTimeType(sPreviousTimeType);
 }
 
-void LLFloaterDayCycle::onUseLindenTime(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onUseLindenTime(void* userData)
 {
-	LLComboBox* box = getChild<LLComboBox>("WLPresetsCombo");
+	LLFloaterWindLight* wl = LLFloaterWindLight::instance();
+	LLComboBox* box = wl->getChild<LLComboBox>("WLPresetsCombo");
 	box->selectByValue("");	
 
-	LLWLParamManager::instance()->mAnimator.mIsRunning = true;
-	LLWLParamManager::instance()->mAnimator.mUseLindenTime = true;	
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 }
 
-void LLFloaterDayCycle::onLoadDayCycle(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onLoadDayCycle(void* userData)
 {
-	LLWLParamManager::instance()->mDay.loadDayCycle("Default.xml");
+	LLWLParamManager::getInstance()->mDay.loadDayCycleFromFile("Default.xml");
 	
 	// sync it all up
 	syncSliderTrack();
@@ -268,46 +355,45 @@ void LLFloaterDayCycle::onLoadDayCycle(LLUICtrl* ctrl)
 
 	// set the param manager's track to the new one
 	LLMultiSliderCtrl* tSldr;
-	tSldr = getChild<LLMultiSliderCtrl>( 
+	tSldr = sDayCycle->getChild<LLMultiSliderCtrl>( 
 		"WLTimeSlider");
-	LLWLParamManager::instance()->resetAnimator(
+	LLWLParamManager::getInstance()->resetAnimator(
 		tSldr->getCurSliderValue() / sHoursPerDay, false);
 
 	// and draw it
-	LLWLParamManager::instance()->mAnimator.update(
-		LLWLParamManager::instance()->mCurParams);
+	LLWLParamManager::getInstance()->mAnimator.update(
+		LLWLParamManager::getInstance()->mCurParams);
 }
 
-void LLFloaterDayCycle::onSaveDayCycle(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onSaveDayCycle(void* userData)
 {
-	LLWLParamManager::instance()->mDay.saveDayCycle("Default.xml");
+	LLWLParamManager::getInstance()->mDay.saveDayCycle("Default.xml");
 }
 
 
-void LLFloaterDayCycle::onTimeSliderMoved(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onTimeSliderMoved(LLUICtrl* ctrl, void* userData)
 {
-	LLMultiSliderCtrl* sldr = getChild<LLMultiSliderCtrl>( 
+	LLMultiSliderCtrl* sldr = sDayCycle->getChild<LLMultiSliderCtrl>( 
 		"WLTimeSlider");
 
 	/// get the slider value
 	F32 val = sldr->getCurSliderValue() / sHoursPerDay;
 	
 	// set the value, turn off animation
-	LLWLParamManager::instance()->mAnimator.setDayTime((F64)val);
-	LLWLParamManager::instance()->mAnimator.mIsRunning = false;
-	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+	LLWLParamManager::getInstance()->mAnimator.setDayTime((F64)val);
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	// then call update once
-	LLWLParamManager::instance()->mAnimator.update(
-		LLWLParamManager::instance()->mCurParams);
+	LLWLParamManager::getInstance()->mAnimator.update(
+		LLWLParamManager::getInstance()->mCurParams);
 }
 
-void LLFloaterDayCycle::onKeyTimeMoved(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onKeyTimeMoved(LLUICtrl* ctrl, void* userData)
 {
-	LLComboBox* comboBox = getChild<LLComboBox>("WLKeyPresets");
-	LLMultiSliderCtrl* sldr = getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
-	LLSpinCtrl* hourSpin = getChild<LLSpinCtrl>("WLCurKeyHour");
-	LLSpinCtrl* minSpin = getChild<LLSpinCtrl>("WLCurKeyMin");
+	LLComboBox* comboBox = sDayCycle->getChild<LLComboBox>("WLKeyPresets");
+	LLMultiSliderCtrl* sldr = sDayCycle->getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
+	LLSpinCtrl* hourSpin = sDayCycle->getChild<LLSpinCtrl>("WLCurKeyHour");
+	LLSpinCtrl* minSpin = sDayCycle->getChild<LLSpinCtrl>("WLCurKeyMin");
 
 	if(sldr->getValue().size() == 0) {
 		return;
@@ -322,11 +408,11 @@ void LLFloaterDayCycle::onKeyTimeMoved(LLUICtrl* ctrl)
 	F32 time = sldr->getCurSliderValue();
 
 	// check to see if a key exists
-	std::string presetName = sSliderToKey[curSldr].presetName;
+	LLWLParamKey key = sSliderToKey[curSldr].keyframe;
 	sSliderToKey[curSldr].time = time;
 
 	// if it exists, turn on check box
-	comboBox->selectByValue(presetName);
+	comboBox->selectByValue(key.toStringVal());
 
 	// now set the spinners
 	F32 hour = (F32)((S32)time);
@@ -345,18 +431,18 @@ void LLFloaterDayCycle::onKeyTimeMoved(LLUICtrl* ctrl)
 
 }
 
-void LLFloaterDayCycle::onKeyTimeChanged(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onKeyTimeChanged(LLUICtrl* ctrl, void* userData)
 {
 	// if no keys, skipped
 	if(sSliderToKey.size() == 0) {
 		return;
 	}
 
-	LLMultiSliderCtrl* sldr = getChild<LLMultiSliderCtrl>( 
+	LLMultiSliderCtrl* sldr = sDayCycle->getChild<LLMultiSliderCtrl>( 
 		"WLDayCycleKeys");
-	LLSpinCtrl* hourSpin = getChild<LLSpinCtrl>( 
+	LLSpinCtrl* hourSpin = sDayCycle->getChild<LLSpinCtrl>( 
 		"WLCurKeyHour");
-	LLSpinCtrl* minSpin = getChild<LLSpinCtrl>( 
+	LLSpinCtrl* minSpin = sDayCycle->getChild<LLSpinCtrl>( 
 		"WLCurKeyMin");
 
 	F32 hour = hourSpin->get();
@@ -368,18 +454,17 @@ void LLFloaterDayCycle::onKeyTimeChanged(LLUICtrl* ctrl)
 	F32 time = sldr->getCurSliderValue() / sHoursPerDay;
 
 	// now set the key's time in the sliderToKey map
-	std::string presetName = sSliderToKey[curSldr].presetName;
 	sSliderToKey[curSldr].time = time;
 
 	syncTrack();
 }
 
-void LLFloaterDayCycle::onKeyPresetChanged(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onKeyPresetChanged(LLUICtrl* ctrl, void* userData)
 {
 	// get the time
-	LLComboBox* comboBox = getChild<LLComboBox>( 
+	LLComboBox* comboBox = sDayCycle->getChild<LLComboBox>( 
 		"WLKeyPresets");
-	LLMultiSliderCtrl* sldr = getChild<LLMultiSliderCtrl>( 
+	LLMultiSliderCtrl* sldr = sDayCycle->getChild<LLMultiSliderCtrl>( 
 		"WLDayCycleKeys");
 
 	// do nothing if no sliders
@@ -388,7 +473,9 @@ void LLFloaterDayCycle::onKeyPresetChanged(LLUICtrl* ctrl)
 	}
 
 	// change the map
-	std::string newPreset(comboBox->getSelectedValue().asString());
+
+	std::string stringVal = comboBox->getSelectedValue().asString();
+	LLWLParamKey newKey(stringVal);
 	const std::string& curSldr = sldr->getCurSlider();
 
 	// if null, don't use
@@ -396,21 +483,21 @@ void LLFloaterDayCycle::onKeyPresetChanged(LLUICtrl* ctrl)
 		return;
 	}
 
-	sSliderToKey[curSldr].presetName = newPreset;
+	sSliderToKey[curSldr].keyframe = newKey;
 
 	syncTrack();
 }
 
-void LLFloaterDayCycle::onTimeRateChanged(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onTimeRateChanged(LLUICtrl* ctrl, void* userData)
 {
 	// get the time
-	LLSpinCtrl* secSpin = getChild<LLSpinCtrl>( 
+	LLSpinCtrl* secSpin = sDayCycle->getChild<LLSpinCtrl>( 
 		"WLLengthOfDaySec");
 
-	LLSpinCtrl* minSpin = getChild<LLSpinCtrl>( 
+	LLSpinCtrl* minSpin = sDayCycle->getChild<LLSpinCtrl>( 
 		"WLLengthOfDayMin");
 
-	LLSpinCtrl* hourSpin = getChild<LLSpinCtrl>( 
+	LLSpinCtrl* hourSpin = sDayCycle->getChild<LLSpinCtrl>( 
 		"WLLengthOfDayHour");
 
 	F32 hour;
@@ -424,34 +511,57 @@ void LLFloaterDayCycle::onTimeRateChanged(LLUICtrl* ctrl)
 	if(time <= 0) {
 		time = 1;
 	}
-	LLWLParamManager::instance()->mDay.mDayRate = time;
+	LLWLParamManager::getInstance()->mDay.mDayRate = time;
 
 	syncTrack();
 }
 
-void LLFloaterDayCycle::onAddKey(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onAddKey(void* userData)
 {
-	LLComboBox* comboBox = getChild<LLComboBox>( 
+	LLComboBox* comboBox = sDayCycle->getChild<LLComboBox>( 
 		"WLKeyPresets");
-	LLMultiSliderCtrl* kSldr = getChild<LLMultiSliderCtrl>( 
+	LLMultiSliderCtrl* kSldr = sDayCycle->getChild<LLMultiSliderCtrl>( 
 		"WLDayCycleKeys");
-	LLMultiSliderCtrl* tSldr = getChild<LLMultiSliderCtrl>( 
+	LLMultiSliderCtrl* tSldr = sDayCycle->getChild<LLMultiSliderCtrl>( 
 		"WLTimeSlider");
 	
 	llassert_always(sSliderToKey.size() == kSldr->getValue().size());
 
+	S32 max_sliders;
+	switch(sScope)
+	{
+		case LLEnvKey::SCOPE_LOCAL:
+			max_sliders = LLWLPacketScrubber::MAX_LOCAL_KEY_FRAMES;
+			break;
+		case LLEnvKey::SCOPE_REGION:
+			max_sliders = LLWLPacketScrubber::MAX_REGION_KEY_FRAMES;
+			break;
+		default:
+			max_sliders = kSldr->getMaxSliderCount();
+			break;
+	}
+
+	if(kSldr->getSliderCount() >= max_sliders)
+	{
+		LLSD args;
+		args["SCOPE"] = LLEnvManager::getScopeString(sScope);
+		args["MAX"] = max_sliders;
+		LLNotifications::instance().add("DayCycleTooManyKeyframes", args);
+		return;
+	}
+
 	// get the values
-	std::string newPreset(comboBox->getSelectedValue().asString());
+	LLWLParamKey newKeyframe(comboBox->getSelectedValue());
 
 	// add the slider key
-	addSliderKey(tSldr->getCurSliderValue(), newPreset);
+	addSliderKey(tSldr->getCurSliderValue(), newKeyframe);
 
 	syncTrack();
 }
 
-void LLFloaterDayCycle::addSliderKey(F32 time, const std::string & presetName)
+void LLFloaterDayCycle::addSliderKey(F32 time, LLWLParamKey keyframe)
 {
-	LLMultiSliderCtrl* kSldr = getChild<LLMultiSliderCtrl>( 
+	LLMultiSliderCtrl* kSldr = sDayCycle->getChild<LLMultiSliderCtrl>( 
 		"WLDayCycleKeys");
 
 	// make a slider
@@ -461,30 +571,28 @@ void LLFloaterDayCycle::addSliderKey(F32 time, const std::string & presetName)
 	}
 
 	// set the key
-	LLWLSkyKey newKey;
-	newKey.presetName = presetName;
-	newKey.time = kSldr->getCurSliderValue();
+	LLWLCycleSliderKey newKey(keyframe, kSldr->getCurSliderValue());
 
 	llassert_always(sldrName != LLStringUtil::null);
 
 	// add to map
-	sSliderToKey.insert(std::pair<std::string, LLWLSkyKey>(sldrName, newKey));
+	sSliderToKey.insert(std::pair<std::string, LLWLCycleSliderKey>(sldrName, newKey));
 
 	llassert_always(sSliderToKey.size() == kSldr->getValue().size());
 
 }
 
-void LLFloaterDayCycle::deletePreset(std::string& presetName)
+void LLFloaterDayCycle::deletePreset(LLWLParamKey keyframe)
 {
-	LLMultiSliderCtrl* sldr = getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
+	LLMultiSliderCtrl* sldr = sDayCycle->getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
 
 	/// delete any reference
-	std::map<std::string, LLWLSkyKey>::iterator curr_preset, next_preset;
+	std::map<std::string, LLWLCycleSliderKey>::iterator curr_preset, next_preset;
 	for(curr_preset = sSliderToKey.begin(); curr_preset != sSliderToKey.end(); curr_preset = next_preset)
 	{
 		next_preset = curr_preset;
 		++next_preset;
-		if (curr_preset->second.presetName == presetName)
+		if (curr_preset->second.keyframe == keyframe)
 		{
 			sldr->deleteSlider(curr_preset->first);
 			sSliderToKey.erase(curr_preset);
@@ -492,19 +600,25 @@ void LLFloaterDayCycle::deletePreset(std::string& presetName)
 	}
 }
 
-void LLFloaterDayCycle::onDeleteKey(LLUICtrl* ctrl)
+void LLFloaterDayCycle::onDeleteKey(void* userData)
 {
-	if(sSliderToKey.size() == 0) {
+	if(sSliderToKey.size() == 0)
+	{
+		return;
+	}
+	else if(sSliderToKey.size() == 1)
+	{
+		LLNotifications::instance().add("EnvCannotDeleteLastDayCycleKey", LLSD());
 		return;
 	}
 
-	LLComboBox* comboBox = getChild<LLComboBox>( 
+	LLComboBox* comboBox = sDayCycle->getChild<LLComboBox>( 
 		"WLKeyPresets");
-	LLMultiSliderCtrl* sldr = getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
+	LLMultiSliderCtrl* sldr = sDayCycle->getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
 
 	// delete from map
 	const std::string& sldrName = sldr->getCurSlider();
-	std::map<std::string, LLWLSkyKey>::iterator mIt = sSliderToKey.find(sldrName);
+	std::map<std::string, LLWLCycleSliderKey>::iterator mIt = sSliderToKey.find(sldrName);
 	sSliderToKey.erase(mIt);
 
 	sldr->deleteCurSlider();
@@ -514,11 +628,11 @@ void LLFloaterDayCycle::onDeleteKey(LLUICtrl* ctrl)
 	}
 
 	const std::string& name = sldr->getCurSlider();
-	comboBox->selectByValue(sSliderToKey[name].presetName);
+	comboBox->selectByValue(sSliderToKey[name].keyframe.toLLSD());
 	F32 time = sSliderToKey[name].time;
 
-	LLSpinCtrl* hourSpin = getChild<LLSpinCtrl>("WLCurKeyHour");
-	LLSpinCtrl* minSpin = getChild<LLSpinCtrl>("WLCurKeyMin");
+	LLSpinCtrl* hourSpin = sDayCycle->getChild<LLSpinCtrl>("WLCurKeyHour");
+	LLSpinCtrl* minSpin = sDayCycle->getChild<LLSpinCtrl>("WLCurKeyMin");
 
 	// now set the spinners
 	F32 hour = (F32)((S32)time);
diff --git a/indra/newview/llfloaterdaycycle.h b/indra/newview/llfloaterdaycycle.h
index 993ddb8f074808d5a540c28a795750df65c50023..1c021f0c6a475edd8609764b4a00586db4b15797 100644
--- a/indra/newview/llfloaterdaycycle.h
+++ b/indra/newview/llfloaterdaycycle.h
@@ -2,25 +2,31 @@
  * @file llfloaterdaycycle.h
  * @brief LLFloaterDayCycle class definition
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
  * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
 
@@ -32,15 +38,19 @@
 #include <vector>
 #include "llwlparamset.h"
 #include "llwlanimator.h"
+#include "llwlparammanager.h"
 
 struct WLColorControl;
 struct WLFloatControl;
 
-/// convenience class for holding keys mapped to sliders
-struct LLWLSkyKey
+/// convenience class for holding keyframes mapped to sliders
+struct LLWLCycleSliderKey
 {
 public:
-	std::string presetName;
+	LLWLCycleSliderKey(LLWLParamKey kf, F32 t) : keyframe(kf), time(t) {}
+	LLWLCycleSliderKey() : keyframe(), time(0.f) {} // Don't use this default constructor
+	
+	LLWLParamKey keyframe;
 	F32 time;
 };
 
@@ -49,71 +59,94 @@ struct LLWLSkyKey
 class LLFloaterDayCycle : public LLFloater
 {
 public:
-
-	LLFloaterDayCycle(const LLSD& key);
+	LLFloaterDayCycle();
 	virtual ~LLFloaterDayCycle();
-	/*virtual*/	BOOL	postBuild();
+
+	// map of sliders to parameters
+	static std::map<std::string, LLWLCycleSliderKey> sSliderToKey;
+
+	/// help button stuff
+	static void onClickHelp(void* data);
+	void initHelpBtn(const std::string& name, const std::string& xml_alert);
 
 	/// initialize all
 	void initCallbacks(void);
 
+	/// one and one instance only
+	static LLFloaterDayCycle* instance();
+
 	/// on time slider moved
-	void onTimeSliderMoved(LLUICtrl* ctrl);
+	static void onTimeSliderMoved(LLUICtrl* ctrl, void* userData);
 
 	/// what happens when you move the key frame
-	void onKeyTimeMoved(LLUICtrl* ctrl);
+	static void onKeyTimeMoved(LLUICtrl* ctrl, void* userData);
 
 	/// what happens when you change the key frame's time
-	void onKeyTimeChanged(LLUICtrl* ctrl);
+	static void onKeyTimeChanged(LLUICtrl* ctrl, void* userData);
 
 	/// if you change the combo box, change the frame
-	void onKeyPresetChanged(LLUICtrl* ctrl);
+	static void onKeyPresetChanged(LLUICtrl* ctrl, void* userData);
 	
 	/// run this when user says to run the sky animation
-	void onRunAnimSky(LLUICtrl* ctrl);
+	static void onRunAnimSky(void* userData);
 
 	/// run this when user says to stop the sky animation
-	void onStopAnimSky(LLUICtrl* ctrl);
+	static void onStopAnimSky(void* userData);
 
 	/// if you change the combo box, change the frame
-	void onTimeRateChanged(LLUICtrl* ctrl);
+	static void onTimeRateChanged(LLUICtrl* ctrl, void* userData);
 
 	/// add a new key on slider
-	void onAddKey(LLUICtrl* ctrl);
+	static void onAddKey(void* userData);
 
 	/// delete any and all reference to a preset
-	void deletePreset(std::string& presetName);
+	void deletePreset(LLWLParamKey keyframe);
 
 	/// delete a key frame
-	void onDeleteKey(LLUICtrl* ctrl);
+	static void onDeleteKey(void* userData);
 
 	/// button to load day
-	void onLoadDayCycle(LLUICtrl* ctrl);
+	static void onLoadDayCycle(void* userData);
 
 	/// button to save day
-	void onSaveDayCycle(LLUICtrl* ctrl);
+	static void onSaveDayCycle(void* userData);
 
 	/// toggle for Linden time
-	void onUseLindenTime(LLUICtrl* ctrl);
+	static void onUseLindenTime(void* userData);
+
+
+	//// menu management
+
+	/// show off our menu
+	static void show(LLEnvKey::EScope scope = LLEnvKey::SCOPE_LOCAL);
+
+	/// return if the menu exists or not
+	static bool isOpen();
+
+	/// stuff to do on exit
+	virtual void onClose(bool app_quitting);
 
 	/// sync up sliders with day cycle structure
-	void syncMenu();
+	static void syncMenu();
 
 	// 	makes sure key slider has what's in day cycle
-	void syncSliderTrack();
+	static void syncSliderTrack();
 
 	/// makes sure day cycle data structure has what's in menu
-	void syncTrack();
+	static void syncTrack();
+
+	/// refresh combox box from param manager
+	static void refreshPresetsFromParamManager();
 
 	/// add a slider to the track
-	void addSliderKey(F32 time, const std::string& presetName);
+	static void addSliderKey(F32 time, LLWLParamKey keyframe);
 
 private:
-
-	// map of sliders to parameters
-	static std::map<std::string, LLWLSkyKey> sSliderToKey;
-
+	static LLFloaterDayCycle* sDayCycle;	// one instance on the inside
 	static const F32 sHoursPerDay;
+	static LLEnvKey::EScope sScope;
+	static std::string sOriginalTitle;
+	static LLWLAnimator::ETime sPreviousTimeType;
 };
 
 
diff --git a/indra/newview/llfloaterenvsettings.cpp b/indra/newview/llfloaterenvsettings.cpp
index fcaef1f34be8bc0603be9cbe4d0b573caa784214..6d1b27db0732516e44850b4e7f23b557f204d88d 100644
--- a/indra/newview/llfloaterenvsettings.cpp
+++ b/indra/newview/llfloaterenvsettings.cpp
@@ -2,25 +2,31 @@
  * @file llfloaterenvsettings.cpp
  * @brief LLFloaterEnvSettings class definition
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
  * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
 
@@ -28,9 +34,10 @@
 
 #include "llfloaterenvsettings.h"
 
-#include "llfloaterreg.h"
 #include "llfloaterwindlight.h"
 #include "llfloaterwater.h"
+#include "llfloaterdaycycle.h"
+#include "llfloaterregioninfo.h"
 #include "lluictrlfactory.h"
 #include "llsliderctrl.h"
 #include "llcombobox.h"
@@ -42,57 +49,89 @@
 #include "llwaterparammanager.h"
 #include "llmath.h"
 #include "llviewerwindow.h"
+#include "llviewercontrol.h"
+
+#include "llcheckboxctrl.h"
 
 #include "pipeline.h"
 
 #include <sstream>
 
-LLFloaterEnvSettings::LLFloaterEnvSettings(const LLSD& key)
-  : LLFloater(key)
+LLFloaterEnvSettings* LLFloaterEnvSettings::sEnvSettings = NULL;
+
+LLFloaterEnvSettings::LLFloaterEnvSettings() : LLFloater(std::string("Environment Settings Floater"))
 {
+	LLUICtrlFactory::getInstance()->buildFloater(this, "floater_env_settings.xml", NULL, FALSE);
+	
+	// load it up
+	initCallbacks();
 }
-// virtual
+
 LLFloaterEnvSettings::~LLFloaterEnvSettings()
 {
 }
-// virtual
-BOOL LLFloaterEnvSettings::postBuild()
-{	
-	// load it up
-	initCallbacks();
-	syncMenu();
-	return TRUE;
+
+void LLFloaterEnvSettings::onClickHelp(void* data)
+{
+	LLFloaterEnvSettings* self = (LLFloaterEnvSettings*)data;
+	LLNotifications::instance().add(self->contextualNotification("EnvSettingsHelpButton"));
+}
+
+void LLFloaterEnvSettings::onUseRegionEnvironment(LLUICtrl* ctrl, void* data)
+{
+	LLFloaterEnvSettings* self = (LLFloaterEnvSettings*)data;
+	LLCheckBoxCtrl* checkbox = (LLCheckBoxCtrl*)self->getChildView("RegionWLOptIn");
+	setOptIn(checkbox->getValue().asBoolean());
+}
+
+void LLFloaterEnvSettings::setOptIn(bool opt_in)
+{
+	if (opt_in)
+	{
+		LLEnvManager::getInstance()->setNormallyDisplayedScope(LLEnvKey::SCOPE_REGION);
+	}
+	else
+	{
+		LLEnvManager::getInstance()->setNormallyDisplayedScope(LLEnvKey::SCOPE_LOCAL);
+	}
 }
 
 void LLFloaterEnvSettings::initCallbacks(void) 
 {
 	// our three sliders
-	getChild<LLUICtrl>("EnvTimeSlider")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onChangeDayTime, this, _1));
-	getChild<LLUICtrl>("EnvCloudSlider")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onChangeCloudCoverage, this, _1));
-	getChild<LLUICtrl>("EnvWaterFogSlider")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onChangeWaterFogDensity, this, _1, &LLWaterParamManager::instance()->mFogDensity));	
+	childSetCommitCallback("EnvTimeSlider", onChangeDayTime, NULL);
+	childSetCommitCallback("EnvCloudSlider", onChangeCloudCoverage, NULL);
+	childSetCommitCallback("EnvWaterFogSlider", onChangeWaterFogDensity, 
+		&LLWaterParamManager::getInstance()->mFogDensity);	
 
 	// color picker
-	getChild<LLUICtrl>("EnvWaterColor")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onChangeWaterColor, this, _1, &LLWaterParamManager::instance()->mFogColor));
+	childSetCommitCallback("EnvWaterColor", onChangeWaterColor, 
+		&LLWaterParamManager::getInstance()->mFogColor);
 
 	// WL Top
-	getChild<LLUICtrl>("EnvAdvancedSkyButton")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onOpenAdvancedSky, this));
- 	getChild<LLUICtrl>("EnvAdvancedWaterButton")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onOpenAdvancedWater, this));
-	getChild<LLUICtrl>("EnvUseEstateTimeButton")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onUseEstateTime, this));
+	childSetAction("EnvAdvancedSkyButton", onOpenAdvancedSky, NULL);
+	childSetAction("EnvAdvancedWaterButton", onOpenAdvancedWater, NULL);
+	childSetAction("EnvUseEstateTimeButton", onUseEstateTime, NULL);
+	childSetAction("EnvUseLocalTimeButton", onUseLocalTime, NULL);
+	childSetAction("EnvSettingsHelpButton", onClickHelp, this);
+
+	childSetCommitCallback("RegionWLOptIn", onUseRegionEnvironment, this);
 }
 
+
 // menu maintenance functions
 
 void LLFloaterEnvSettings::syncMenu()
 {
 	LLSliderCtrl* sldr;
-	sldr = getChild<LLSliderCtrl>("EnvTimeSlider");
+	sldr = sEnvSettings->getChild<LLSliderCtrl>("EnvTimeSlider");
 
 	// sync the clock
-	F32 val = (F32)LLWLParamManager::instance()->mAnimator.getDayTime();
-	std::string timeStr = timeToString(val);
+	F32 val = (F32)LLWLParamManager::getInstance()->mAnimator.getDayTime();
+	std::string timeStr = LLWLAnimator::timeToString(val);
 
 	LLTextBox* textBox;
-	textBox = getChild<LLTextBox>("EnvTimeText");
+	textBox = sEnvSettings->getChild<LLTextBox>("EnvTimeText");
 
 	textBox->setValue(timeStr);
 	
@@ -106,62 +145,159 @@ void LLFloaterEnvSettings::syncMenu()
 
 	// sync cloud coverage
 	bool err;
-	getChild<LLUICtrl>("EnvCloudSlider")->setValue(LLWLParamManager::instance()->mCurParams.getFloat("cloud_shadow", err));
+	childSetValue("EnvCloudSlider", LLWLParamManager::getInstance()->mCurParams.getFloat("cloud_shadow", err));
 
-	LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+	LLWaterParamManager * param_mgr = LLWaterParamManager::getInstance();
 	// sync water params
 	LLColor4 col = param_mgr->getFogColor();
-	LLColorSwatchCtrl* colCtrl = getChild<LLColorSwatchCtrl>("EnvWaterColor");
+	LLColorSwatchCtrl* colCtrl = sEnvSettings->getChild<LLColorSwatchCtrl>("EnvWaterColor");
 	col.mV[3] = 1.0f;
 	colCtrl->set(col);
 
-	getChild<LLUICtrl>("EnvWaterFogSlider")->setValue(param_mgr->mFogDensity.mExp);
+	childSetValue("EnvWaterFogSlider", param_mgr->mFogDensity.mExp);
 	param_mgr->setDensitySliderValue(param_mgr->mFogDensity.mExp);
 
-	// turn off Use Estate Time button if it's already being used
-	if(LLWLParamManager::instance()->mAnimator.mUseLindenTime)
+	// turn off Use Estate/Local Time buttons if already being used
+
+	if(LLWLParamManager::getInstance()->mAnimator.getUseLindenTime())
 	{
-		getChildView("EnvUseEstateTimeButton")->setEnabled(FALSE);
-	} else {
-		getChildView("EnvUseEstateTimeButton")->setEnabled(TRUE);
+		childDisable("EnvUseEstateTimeButton");
+	}
+	else
+	{
+		childEnable("EnvUseEstateTimeButton");
+	}
+
+	if(LLWLParamManager::getInstance()->mAnimator.getUseLocalTime())
+	{
+		childDisable("EnvUseLocalTimeButton");
+	}
+	else
+	{
+		childEnable("EnvUseLocalTimeButton");
 	}
 
 	if(!gPipeline.canUseVertexShaders())
 	{
-		getChildView("EnvWaterColor")->setEnabled(FALSE);
-		getChildView("EnvWaterColorText")->setEnabled(FALSE);
-		//getChildView("EnvAdvancedWaterButton")->setEnabled(FALSE);		
+		childDisable("EnvWaterColor");
+		childDisable("EnvWaterColorText");
+		//childDisable("EnvAdvancedWaterButton");		
 	}
 	else
 	{
-		getChildView("EnvWaterColor")->setEnabled(TRUE);
-		getChildView("EnvWaterColorText")->setEnabled(TRUE);
-		//getChildView("EnvAdvancedWaterButton")->setEnabled(TRUE);		
+		childEnable("EnvWaterColor");
+		childEnable("EnvWaterColorText");
+		//childEnable("EnvAdvancedWaterButton");		
 	}
 
 	// only allow access to these if they are using windlight
 	if(!gPipeline.canUseWindLightShaders())
 	{
 
-		getChildView("EnvCloudSlider")->setEnabled(FALSE);
-		getChildView("EnvCloudText")->setEnabled(FALSE);
-		//getChildView("EnvAdvancedSkyButton")->setEnabled(FALSE);
+		childDisable("EnvCloudSlider");
+		childDisable("EnvCloudText");
+		//childDisable("EnvAdvancedSkyButton");
+	}
+	else
+	{
+		childEnable("EnvCloudSlider");
+		childEnable("EnvCloudText");
+		//childEnable("EnvAdvancedSkyButton");
+	}
+}
+
+
+// static instance of it
+LLFloaterEnvSettings* LLFloaterEnvSettings::instance()
+{
+	if (!sEnvSettings)
+	{
+		sEnvSettings = new LLFloaterEnvSettings();
+		// sEnvSettings->open();
+		// sEnvSettings->setFocus(TRUE);
+	}
+	return sEnvSettings;
+}
+
+void LLFloaterEnvSettings::setControlsEnabled(bool enable)
+{
+	if(enable)
+	{
+		// reenable UI elements, resync sliders, and reload saved settings
+		childEnable("EnvAdvancedSkyButton");
+		childEnable("EnvAdvancedWaterButton");
+		childEnable("EnvUseEstateTimeButton");
+		childShow("EnvTimeText");
+		childShow("EnvWaterColor");
+		childShow("EnvTimeSlider");
+		childShow("EnvCloudSlider");
+		childShow("EnvWaterFogSlider");
+		syncMenu();
 	}
 	else
 	{
-		getChildView("EnvCloudSlider")->setEnabled(TRUE);
-		getChildView("EnvCloudText")->setEnabled(TRUE);
-		//getChildView("EnvAdvancedSkyButton")->setEnabled(TRUE);
+		// disable UI elements the user shouldn't be able to see to protect potentially proprietary WL region settings from being visible
+		LLFloaterWindLight::instance()->close();
+		LLFloaterWater::instance()->close();
+		LLFloaterDayCycle::instance()->close();
+		childDisable("EnvAdvancedSkyButton");
+		childDisable("EnvAdvancedWaterButton");
+		childDisable("EnvUseEstateTimeButton");
+		childHide("EnvTimeText");
+		childHide("EnvWaterColor");
+		childHide("EnvTimeSlider");
+		childHide("EnvCloudSlider");
+		childHide("EnvWaterFogSlider");
 	}
 }
 
-void LLFloaterEnvSettings::onChangeDayTime(LLUICtrl* ctrl)
+
+void LLFloaterEnvSettings::show()
+{
+	LLFloaterEnvSettings* envSettings = instance();
+	envSettings->syncMenu();
+
+	// comment in if you want the menu to rebuild each time
+	//LLUICtrlFactory::getInstance()->buildFloater(envSettings, "floater_env_settings.xml");
+	//envSettings->initCallbacks();
+
+	// Set environment opt-in checkbox based on saved value -- only need to do once, not every time syncMenu is called
+	
+	bool opt_in = gSavedSettings.getBOOL("UseEnvironmentFromRegion");
+
+	sEnvSettings->childSetVisible("RegionWLOptIn", LLEnvManager::getInstance()->regionCapable());
+	sEnvSettings->setOptIn(opt_in);		
+	sEnvSettings->getChildView("RegionWLOptIn")->setValue(LLSD::Boolean(opt_in));
+	sEnvSettings->getChildView("RegionWLOptIn")->setToolTip(sEnvSettings->getString("region_environment_tooltip"));
+	envSettings->open();
+}
+
+bool LLFloaterEnvSettings::isOpen()
 {
-	LLSliderCtrl* sldr = static_cast<LLSliderCtrl*>(ctrl);
+	if (sEnvSettings != NULL) 
+	{
+		return true;
+	}
+	return false;
+}
+
+// virtual
+void LLFloaterEnvSettings::onClose(bool app_quitting)
+{
+	if (sEnvSettings)
+	{
+		sEnvSettings->setVisible(FALSE);
+	}
+}
+
+
+void LLFloaterEnvSettings::onChangeDayTime(LLUICtrl* ctrl, void* userData)
+{
+	LLSliderCtrl* sldr;
+	sldr = sEnvSettings->getChild<LLSliderCtrl>("EnvTimeSlider");
 
 	// deactivate animator
-	LLWLParamManager::instance()->mAnimator.mIsRunning = false;
-	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	F32 val = sldr->getValueF32() + 0.25f;
 	if(val > 1.0) 
@@ -169,100 +305,81 @@ void LLFloaterEnvSettings::onChangeDayTime(LLUICtrl* ctrl)
 		val--;
 	}
 
-	LLWLParamManager::instance()->mAnimator.setDayTime((F64)val);
-	LLWLParamManager::instance()->mAnimator.update(
-		LLWLParamManager::instance()->mCurParams);
+	LLWLParamManager::getInstance()->mAnimator.setDayTime((F64)val);
+	LLWLParamManager::getInstance()->mAnimator.update(
+		LLWLParamManager::getInstance()->mCurParams);
 }
 
-void LLFloaterEnvSettings::onChangeCloudCoverage(LLUICtrl* ctrl)
+void LLFloaterEnvSettings::onChangeCloudCoverage(LLUICtrl* ctrl, void* userData)
 {
-	LLSliderCtrl* sldr = static_cast<LLSliderCtrl*>(ctrl);
+	LLSliderCtrl* sldr;
+	sldr = sEnvSettings->getChild<LLSliderCtrl>("EnvCloudSlider");
 	
 	// deactivate animator
-	//LLWLParamManager::instance()->mAnimator.mIsRunning = false;
-	//LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+	//LLWLParamManager::getInstance()->mAnimator.mIsRunning = false;
+	//LLWLParamManager::getInstance()->mAnimator.mUseLindenTime = false;
 
 	F32 val = sldr->getValueF32();
-	LLWLParamManager::instance()->mCurParams.set("cloud_shadow", val);
+	LLWLParamManager::getInstance()->mCurParams.set("cloud_shadow", val);
 }
 
-void LLFloaterEnvSettings::onChangeWaterFogDensity(LLUICtrl* ctrl, WaterExpFloatControl* expFloatControl)
+void LLFloaterEnvSettings::onChangeWaterFogDensity(LLUICtrl* ctrl, void* userData)
 {
 	LLSliderCtrl* sldr;
-	sldr = getChild<LLSliderCtrl>("EnvWaterFogSlider");
+	sldr = sEnvSettings->getChild<LLSliderCtrl>("EnvWaterFogSlider");
+	
+	if(NULL == userData)
+	{
+		return;
+	}
+
+	WaterExpFloatControl * expFloatControl = static_cast<WaterExpFloatControl *>(userData);
 	
 	F32 val = sldr->getValueF32();
 	expFloatControl->mExp = val;
-	LLWaterParamManager::instance()->setDensitySliderValue(val);
+	LLWaterParamManager::getInstance()->setDensitySliderValue(val);
 
-	expFloatControl->update(LLWaterParamManager::instance()->mCurParams);
-	LLWaterParamManager::instance()->propagateParameters();
+	expFloatControl->update(LLWaterParamManager::getInstance()->mCurParams);
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
-void LLFloaterEnvSettings::onChangeWaterColor(LLUICtrl* ctrl, WaterColorControl* colorControl)
+void LLFloaterEnvSettings::onChangeWaterColor(LLUICtrl* ctrl, void* userData)
 {
 	LLColorSwatchCtrl* swatch = static_cast<LLColorSwatchCtrl*>(ctrl);
+	WaterColorControl * colorControl = static_cast<WaterColorControl *>(userData);	
 	*colorControl = swatch->get();
 
-	colorControl->update(LLWaterParamManager::instance()->mCurParams);
-	LLWaterParamManager::instance()->propagateParameters();
+	colorControl->update(LLWaterParamManager::getInstance()->mCurParams);
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 
-void LLFloaterEnvSettings::onOpenAdvancedSky()
+void LLFloaterEnvSettings::onOpenAdvancedSky(void* userData)
 {
-	LLFloaterReg::showInstance("env_windlight");
+	LLFloaterWindLight::show();
 }
 
-void LLFloaterEnvSettings::onOpenAdvancedWater()
+void LLFloaterEnvSettings::onOpenAdvancedWater(void* userData)
 {
-	LLFloaterReg::showInstance("env_water");
+	LLFloaterWater::show();
 }
 
 
-void LLFloaterEnvSettings::onUseEstateTime()
+void LLFloaterEnvSettings::onUseEstateTime(void* userData)
 {
-	LLFloaterWindLight* wl = LLFloaterReg::findTypedInstance<LLFloaterWindLight>("env_windlight");
-	if(wl)
+	if(LLFloaterWindLight::isOpen())
 	{
+		// select the blank value in 
+		LLFloaterWindLight* wl = LLFloaterWindLight::instance();
 		LLComboBox* box = wl->getChild<LLComboBox>("WLPresetsCombo");
 		box->selectByValue("");
 	}
 
-	LLWLParamManager::instance()->mAnimator.mIsRunning = true;
-	LLWLParamManager::instance()->mAnimator.mUseLindenTime = true;
+	LLWLParamManager::getInstance()->mAnimator.activate(LLWLAnimator::TIME_LINDEN);
 }
 
-std::string LLFloaterEnvSettings::timeToString(F32 curTime)
+void LLFloaterEnvSettings::onUseLocalTime(void* userData)
 {
-	S32 hours;
-	S32 min;
-
-	// get hours and minutes
-	hours = (S32) (24.0 * curTime);
-	curTime -= ((F32) hours / 24.0f);
-	min = llround(24.0f * 60.0f * curTime);
-
-	// handle case where it's 60
-	if(min == 60) 
-	{
-		hours++;
-		min = 0;
-	}
-
-	std::string newTime = getString("timeStr");
-	struct tm * timeT;
-	time_t secT = time(0);
-	timeT = gmtime (&secT);
-
-	timeT->tm_hour = hours;
-	timeT->tm_min = min;
-	secT = mktime (timeT);
-	secT -= LLStringOps::getLocalTimeOffset ();
-
-	LLSD substitution;
-	substitution["datetime"] = (S32) secT;
-
-	LLStringUtil::format (newTime, substitution);
-	return newTime;
+	LLWLParamManager::getInstance()->mAnimator.setDayTime(LLWLAnimator::getLocalTime());
+	LLWLParamManager::getInstance()->mAnimator.activate(LLWLAnimator::TIME_LOCAL);
 }
diff --git a/indra/newview/llfloaterenvsettings.h b/indra/newview/llfloaterenvsettings.h
index a6280cfb973b8dc7bb0d401ee8936e1994b083d6..0bf3e48676f4c40eca0384fef00cf6fa6fef6c92 100644
--- a/indra/newview/llfloaterenvsettings.h
+++ b/indra/newview/llfloaterenvsettings.h
@@ -2,25 +2,31 @@
  * @file llfloaterskysettings.h
  * @brief LLFloaterEnvSettings class definition
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
  * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
 
@@ -33,50 +39,77 @@
 
 #include "llfloater.h"
 
-struct WaterColorControl;
-struct WaterExpFloatControl;
 
 /// Menuing system for all of windlight's functionality
 class LLFloaterEnvSettings : public LLFloater
 {
 public:
 
-	LLFloaterEnvSettings(const LLSD& key);
-	/*virtual*/ ~LLFloaterEnvSettings();
-	/*virtual*/	BOOL	postBuild();	
+	LLFloaterEnvSettings();
+	virtual ~LLFloaterEnvSettings();
+	
 	/// initialize all the callbacks for the menu
 	void initCallbacks(void);
 
+	/// one and one instance only
+	static LLFloaterEnvSettings* instance();
+	
+	/// callback for the menus help button
+	static void onClickHelp(void* data);
+	
 	/// handle if time of day is changed
-	void onChangeDayTime(LLUICtrl* ctrl);
+	static void onChangeDayTime(LLUICtrl* ctrl, void* userData);
 
 	/// handle if cloud coverage is changed
-	void onChangeCloudCoverage(LLUICtrl* ctrl);
+	static void onChangeCloudCoverage(LLUICtrl* ctrl, void* userData);
 
 	/// handle change in water fog density
-	void onChangeWaterFogDensity(LLUICtrl* ctrl, WaterExpFloatControl* expFloatControl);
+	static void onChangeWaterFogDensity(LLUICtrl* ctrl, void* userData);
+
+	/// handle change in under water fog density
+	static void onChangeUnderWaterFogMod(LLUICtrl* ctrl, void* userData);
 
 	/// handle change in water fog color
-	void onChangeWaterColor(LLUICtrl* ctrl, WaterColorControl* colorControl);
+	static void onChangeWaterColor(LLUICtrl* ctrl, void* userData);
 
 	/// open the advanced sky settings menu
-	void onOpenAdvancedSky();
+	static void onOpenAdvancedSky(void* userData);
 
 	/// open the advanced water settings menu
-	void onOpenAdvancedWater();
+	static void onOpenAdvancedWater(void* userData);
 
 	/// sync time with the server
-	void onUseEstateTime();
+	static void onUseEstateTime(void* userData);
+
+	/// sync time with local clock
+	static void onUseLocalTime(void* userData);
+
+	// opt-in for region Windlight settings
+	//static void onUseRegionEnvironment(LLUICtrl* ctrl, void* userData);
+	static void onUseRegionEnvironment(LLUICtrl*, void*);
 
 	//// menu management
 
+	/// enables or disable all controls
+	void setControlsEnabled(bool enable);
+
+	/// show off our menu
+	static void show();
+
+	/// return if the menu exists or not
+	static bool isOpen();
+
+	/// stuff to do on exit
+	virtual void onClose(bool app_quitting);
+
 	/// sync up sliders with parameters
 	void syncMenu();
 
-	/// convert the present time to a digital clock time
-	std::string timeToString(F32 curTime);
-
 private:
+	// one instance on the inside
+	static LLFloaterEnvSettings* sEnvSettings;
+
+	static void setOptIn(bool opt_in);
 };
 
 
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index ed81fdec1607cfb26f0e52697ad13171bb07dd75..f6377d50faf880b407a2e448d4760d6f3d69020b 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -40,6 +40,8 @@
 #include "llxfermanager.h"
 #include "indra_constants.h"
 #include "message.h"
+#include "llsd.h"
+#include "llsdserialize.h"
 
 #include "llagent.h"
 #include "llappviewer.h"
@@ -47,6 +49,7 @@
 #include "llbutton.h" 
 #include "llcheckboxctrl.h"
 #include "llcombobox.h"
+#include "llenvmanager.h"
 #include "llfilepicker.h"
 #include "llfloatergodtools.h"	// for send_sim_wide_deletes()
 #include "llfloatertopobjects.h" // added to fix SL-32336
@@ -81,6 +84,9 @@
 #include "lltrans.h"
 #include "llagentui.h"
 
+// contains includes needed for WL estate settings
+#include "llfloaterwater.h"
+
 const S32 TERRAIN_TEXTURE_COUNT = 4;
 const S32 CORNER_COUNT = 4;
 
@@ -287,6 +293,10 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
 		return;
 	}
 	
+
+	// currently, region can send this message when its windlight settings change
+	LLEnvManager::instance().refreshFromStorage(LLEnvKey::SCOPE_REGION);
+
 	LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels");
 
 	LLViewerRegion* region = gAgent.getRegion();
@@ -1144,9 +1154,32 @@ void LLPanelRegionTextureInfo::onClickDump(void* data)
 /////////////////////////////////////////////////////////////////////////////
 // LLPanelRegionTerrainInfo
 /////////////////////////////////////////////////////////////////////////////
+// Initialize statics
+LLPanelRegionTerrainInfo* LLPanelRegionTerrainInfo::sPanelRegionTerrainInfo = NULL;
+
+LLPanelRegionTerrainInfo* LLPanelRegionTerrainInfo::instance()
+{
+       if (!sPanelRegionTerrainInfo)
+       {
+               sPanelRegionTerrainInfo = new LLPanelRegionTerrainInfo();
+       }
+       return sPanelRegionTerrainInfo;
+}
+
+// virtual
+void LLPanelRegionTerrainInfo::close(bool app_quitting)
+{
+       if (sPanelRegionTerrainInfo)
+       {
+               sPanelRegionTerrainInfo = NULL;
+       }
+}
+
 BOOL LLPanelRegionTerrainInfo::postBuild()
 {
 	LLPanelRegionInfo::postBuild();
+	
+	sPanelRegionTerrainInfo = this; // singleton instance pointer
 
 	initCtrl("water_height_spin");
 	initCtrl("terrain_raise_spin");
@@ -1161,20 +1194,42 @@ BOOL LLPanelRegionTerrainInfo::postBuild()
 	childSetAction("upload_raw_btn", onClickUploadRaw, this);
 	childSetAction("bake_terrain_btn", onClickBakeTerrain, this);
 
+       // WL advanced buttons
+       childSetAction("EnvAdvancedSkyButton", onOpenAdvancedSky, this);
+       childSetAction("EnvAdvancedWaterButton", onOpenAdvancedWater, this);
+       childSetAction("EnvUseEstateTimeButton", onUseEstateTime, this);
+
+       // Commit, cancel, and default
+       childSetAction("WLRegionApply", onCommitRegionWL, this);
+       childSetAction("WLRegionCancel", onCancelRegionWL, this);
+       childSetAction("WLRegionDefault", onSetRegionToDefaultWL, this);
+
 	return TRUE;
 }
 
+F32 LLPanelRegionTerrainInfo::getSunHour()
+{
+       if (childIsEnabled("sun_hour_slider"))
+       {
+               return (F32)childGetValue("sun_hour_slider").asReal();
+       }
+       return 0.f;
+}
+
 // virtual
 bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
 {
-	llinfos << "LLPanelRegionTerrainInfo::refreshFromRegion" << llendl;
-
 	BOOL owner_or_god = gAgent.isGodlike() 
 						|| (region && (region->getOwner() == gAgent.getID()));
 	BOOL owner_or_god_or_manager = owner_or_god
 						|| (region && region->isEstateManager());
 	setCtrlsEnabled(owner_or_god_or_manager);
+
+	// Disable select children
+       LLPanelRegionTerrainInfo::instance()->setCommitControls(false);
+       LLPanelRegionTerrainInfo::instance()->setEnvControls(LLEnvManager::getInstance()->regionCapable());
 	getChildView("apply_btn")->setEnabled(FALSE);
+	LLEnvManager::instance().maybeClearEditingScope(LLEnvKey::SCOPE_REGION, false, false);
 
 	getChildView("download_raw_btn")->setEnabled(owner_or_god);
 	getChildView("upload_raw_btn")->setEnabled(owner_or_god);
@@ -1183,6 +1238,24 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
 	return LLPanelRegionInfo::refreshFromRegion(region);
 }
 
+void LLPanelRegionTerrainInfo::setEnvControls(bool available)
+{
+	getChildView("EnvUseEstateTimeButton")->setVisible(available);
+	getChildView("EnvAdvancedSkyButton")->setVisible(available);
+	getChildView("EnvAdvancedWaterButton")->setVisible(available);
+	getChildView("WLRegionApply")->setVisible(available);
+	getChildView("WLRegionCancel")->setVisible(available);
+	getChildView("WLRegionDefault")->setVisible(available);
+	getChildView("wl_settings_unavailable")->setVisible(!available);
+}
+
+void LLPanelRegionTerrainInfo::setCommitControls(bool available)
+{
+	getChildView("WLRegionApply")->setEnabled(available);
+	getChildView("WLRegionCancel")->setEnabled(available);
+	refresh();
+}
+
 // virtual
 BOOL LLPanelRegionTerrainInfo::sendUpdate()
 {
@@ -1320,9 +1393,70 @@ bool LLPanelRegionTerrainInfo::callbackBakeTerrain(const LLSD& notification, con
 	strings.push_back("bake");
 	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
 	sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings);
+
 	return false;
 }
 
+///////////////////////////////////////////////////////////////
+// Callbacks for WindLight additions to Region terrain panel
+
+void LLPanelRegionTerrainInfo::onOpenAdvancedSky(void* userData)
+{
+	LLFloaterWindLight::show(LLEnvKey::SCOPE_REGION);
+}
+
+void LLPanelRegionTerrainInfo::onOpenAdvancedWater(void* userData)
+{
+	LLFloaterWater::show(LLEnvKey::SCOPE_REGION);
+}
+
+
+void LLPanelRegionTerrainInfo::onUseEstateTime(void* userData)
+{
+	if(LLFloaterWindLight::isOpen())
+	{
+		// select the blank value in
+		LLFloaterWindLight* wl = LLFloaterWindLight::instance();
+		LLComboBox* box = wl->getChild<LLComboBox>("WLPresetsCombo");
+		box->selectByValue("");
+	}
+
+	LLWLParamManager::getInstance()->mAnimator.activate(LLWLAnimator::TIME_LINDEN);
+}
+
+///////////////////////////////////////////////////////
+// Advanced handling for WL region estate integration
+
+// Handle commit of WL settings to region
+void LLPanelRegionTerrainInfo::onCommitRegionWL(void* userData)
+{
+	LLEnvManager::getInstance()->commitSettings(LLEnvKey::SCOPE_REGION);
+	LLEnvManager::getInstance()->maybeClearEditingScope(LLEnvKey::SCOPE_REGION, true, false);
+}
+
+// Handle cancel of WL settings for region
+void LLPanelRegionTerrainInfo::onCancelRegionWL(void* userData)
+{
+	LLEnvManager::getInstance()->maybeClearEditingScope(LLEnvKey::SCOPE_REGION, true, false);
+}
+
+// Handle reversion of region WL settings to default
+void LLPanelRegionTerrainInfo::onSetRegionToDefaultWL(void* userData)
+{
+	LLEnvManager::instance().resetInternalsToDefault(LLEnvKey::SCOPE_REGION);
+	LLEnvManager::instance().startEditingScope(LLEnvKey::SCOPE_REGION);
+}
+
+void LLPanelRegionTerrainInfo::cancelChanges()
+{
+	LLFloaterWindLight::instance()->close();
+	LLFloaterWater::instance()->close();
+	LLFloaterDayCycle::instance()->close();
+
+	// disable commmit and cancel
+	LLPanelRegionTerrainInfo::instance()->setCommitControls(false);
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // LLPanelEstateInfo
 //
@@ -1996,6 +2130,16 @@ bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region)
 	return rv;
 }
 
+void LLFloaterRegionInfo::close(bool app_quitting)
+{
+	if(!app_quitting)
+	{
+		LLEnvManager::getInstance()->maybeClearEditingScope(true, false);
+		LLPanelRegionTerrainInfo::close(app_quitting);
+	}
+	LLFloater::close(app_quitting);
+}
+
 void LLPanelEstateInfo::updateChild(LLUICtrl* child_ctrl)
 {
 	if (checkRemovalButton(child_ctrl->getName()))
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index 2393c74c4509243c6c0886a774397e1e90aacd63..2fdec5a94432f305734fd2721226c31965054a41 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -57,6 +57,13 @@ class LLPanelRegionTerrainInfo;
 class LLPanelEstateInfo;
 class LLPanelEstateCovenant;
 
+class LLEventTimer;
+class LLEnvironmentSettings;
+class LLWLParamManager;
+class LLWaterParamManager;
+class LLWLParamSet;
+class LLWaterParamSet;
+
 class LLFloaterRegionInfo : public LLFloater
 {
 	friend class LLFloaterReg;
@@ -221,19 +228,27 @@ class LLPanelRegionTextureInfo : public LLPanelRegionInfo
 };
 
 /////////////////////////////////////////////////////////////////////////////
-
 class LLPanelRegionTerrainInfo : public LLPanelRegionInfo
 {
 public:
-	LLPanelRegionTerrainInfo()
-		:	LLPanelRegionInfo() {}
+	LLPanelRegionTerrainInfo() : LLPanelRegionInfo() {}
 	~LLPanelRegionTerrainInfo() {}
-	// LLPanel
-	virtual BOOL postBuild();
 	
-	virtual bool refreshFromRegion(LLViewerRegion* region);
+	static LLPanelRegionTerrainInfo* instance();
+	virtual BOOL postBuild();												// LLPanel
+	static void close(bool app_quitting);
+	
+	F32 getSunHour();
+	virtual bool refreshFromRegion(LLViewerRegion* region);					// refresh local settings from region update from simulator
+	void setEnvControls(bool available);									// Whether environment settings are available for this region
+	void setCommitControls(bool available);									// Whether user can currently commit (whether they changed anything)
+	void cancelChanges();													// cancels changes, reverts local settings, and resyncs UI
+
+	//static void onChangeAnything(LLUICtrl* ctrl, void* userData);			// callback for any change, to enable commit button
 	
 protected:
+	static LLPanelRegionTerrainInfo* sPanelRegionTerrainInfo;				// static instance pointer for singleton
+
 	virtual BOOL sendUpdate();
 
 	void onChangeUseEstateTime();
@@ -244,6 +259,13 @@ class LLPanelRegionTerrainInfo : public LLPanelRegionInfo
 	static void onClickUploadRaw(void*);
 	static void onClickBakeTerrain(void*);
 	bool callbackBakeTerrain(const LLSD& notification, const LLSD& response);
+
+	static void onOpenAdvancedSky(void* userData);							// open the advanced sky settings menu
+	static void onOpenAdvancedWater(void* userData);						// open the advanced water settings menu
+	static void onUseEstateTime(void* userData);							// sync time with the server
+	static void onCommitRegionWL(void* userData);							// commit region information to server
+	static void onCancelRegionWL(void* userData);							// cancel changes to region
+	static void onSetRegionToDefaultWL(void* userData);						// revert region WL settings to default
 };
 
 /////////////////////////////////////////////////////////////////////////////
@@ -332,6 +354,7 @@ class LLPanelEstateInfo : public LLPanelRegionInfo
 	// are ignored, so must disable UI.
 	void setAccessAllowedEnabled(bool enable_agent, bool enable_group, bool enable_ban);
 
+	virtual void close(bool app_quitting = false);
 protected:
 	virtual BOOL sendUpdate();
 	// confirmation dialog callback
diff --git a/indra/newview/llfloaterwater.cpp b/indra/newview/llfloaterwater.cpp
index be4b144f41a7f6374462f584a01c1f02ad13d0d0..a443b788fba16c9de8fce0c52a1c2c86a5a3cd2d 100644
--- a/indra/newview/llfloaterwater.cpp
+++ b/indra/newview/llfloaterwater.cpp
@@ -59,6 +59,8 @@
 #undef max
 
 std::set<std::string> LLFloaterWater::sDefaultPresets;
+LLEnvKey::EScope LLFloaterWater::sScope;
+std::string LLFloaterWater::sOriginalTitle;
 
 LLFloaterWater::LLFloaterWater(const LLSD& key)
   : LLFloater(key)
@@ -70,7 +72,7 @@ LLFloaterWater::~LLFloaterWater()
 }
 BOOL LLFloaterWater::postBuild()
 {
-
+	sOriginalTitle=getTitle();
 	std::string def_water = getString("WLDefaultWaterNames");
 
 	// no editing or deleting of the blank string
@@ -88,8 +90,8 @@ BOOL LLFloaterWater::postBuild()
 	if(comboBox != NULL) {
 
 		std::map<std::string, LLWaterParamSet>::iterator mIt = 
-			LLWaterParamManager::instance()->mParamList.begin();
-		for(; mIt != LLWaterParamManager::instance()->mParamList.end(); mIt++) 
+			LLWaterParamManager::getInstance()->mParamList.begin();
+		for(; mIt != LLWaterParamManager::getInstance()->mParamList.end(); mIt++) 
 		{
 			comboBox->add(mIt->first);
 		}
@@ -104,7 +106,7 @@ BOOL LLFloaterWater::postBuild()
 }
 void LLFloaterWater::initCallbacks(void) {
 
-	LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+	LLWaterParamManager * param_mgr = LLWaterParamManager::getInstance();
 
 	getChild<LLUICtrl>("WaterFogColor")->setCommitCallback(boost::bind(&LLFloaterWater::onWaterFogColorMoved, this, _1, &param_mgr->mFogColor));
 
@@ -163,7 +165,7 @@ bool LLFloaterWater::newPromptCallback(const LLSD& notification, const LLSD& res
 	if(option == 0) {
 		LLComboBox* comboBox = getChild<LLComboBox>( "WaterPresetsCombo");
 
-		LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+		LLWaterParamManager * param_mgr = LLWaterParamManager::getInstance();
 
 		// add the current parameters to the list
 		// see if it's there first
@@ -195,7 +197,7 @@ void LLFloaterWater::syncMenu()
 {
 	bool err;
 
-	LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+	LLWaterParamManager * param_mgr = LLWaterParamManager::getInstance();
 
 	LLWaterParamSet & current_params = param_mgr->mCurParams;
 
@@ -262,9 +264,9 @@ void LLFloaterWater::onVector3ControlXMoved(LLUICtrl* ctrl, WaterVector3Control*
 
 	vectorControl->mX = sldrCtrl->getValueF32();
 
-	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+	vectorControl->update(LLWaterParamManager::getInstance()->mCurParams);
 
-	LLWaterParamManager::instance()->propagateParameters();
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 // vector control callbacks
@@ -274,9 +276,9 @@ void LLFloaterWater::onVector3ControlYMoved(LLUICtrl* ctrl, WaterVector3Control*
 
 	vectorControl->mY = sldrCtrl->getValueF32();
 
-	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+	vectorControl->update(LLWaterParamManager::getInstance()->mCurParams);
 
-	LLWaterParamManager::instance()->propagateParameters();
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 // vector control callbacks
@@ -286,9 +288,9 @@ void LLFloaterWater::onVector3ControlZMoved(LLUICtrl* ctrl, WaterVector3Control*
 
 	vectorControl->mZ = sldrCtrl->getValueF32();
 
-	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+	vectorControl->update(LLWaterParamManager::getInstance()->mCurParams);
 
-	LLWaterParamManager::instance()->propagateParameters();
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 
@@ -299,9 +301,9 @@ void LLFloaterWater::onVector2ControlXMoved(LLUICtrl* ctrl, WaterVector2Control*
 
 	vectorControl->mX = sldrCtrl->getValueF32();
 
-	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+	vectorControl->update(LLWaterParamManager::getInstance()->mCurParams);
 
-	LLWaterParamManager::instance()->propagateParameters();
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 // vector control callbacks
@@ -311,9 +313,9 @@ void LLFloaterWater::onVector2ControlYMoved(LLUICtrl* ctrl, WaterVector2Control*
 
 	vectorControl->mY = sldrCtrl->getValueF32();
 
-	vectorControl->update(LLWaterParamManager::instance()->mCurParams);
+	vectorControl->update(LLWaterParamManager::getInstance()->mCurParams);
 
-	LLWaterParamManager::instance()->propagateParameters();
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 // color control callbacks
@@ -335,9 +337,9 @@ void LLFloaterWater::onColorControlRMoved(LLUICtrl* ctrl, WaterColorControl* col
 		getChild<LLUICtrl>(name)->setValue(colorControl->mR);
 	}
 
-	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+	colorControl->update(LLWaterParamManager::getInstance()->mCurParams);
 
-	LLWaterParamManager::instance()->propagateParameters();
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 void LLFloaterWater::onColorControlGMoved(LLUICtrl* ctrl, WaterColorControl* colorControl)
@@ -359,9 +361,9 @@ void LLFloaterWater::onColorControlGMoved(LLUICtrl* ctrl, WaterColorControl* col
 
 	}
 
-	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+	colorControl->update(LLWaterParamManager::getInstance()->mCurParams);
 
-	LLWaterParamManager::instance()->propagateParameters();
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 void LLFloaterWater::onColorControlBMoved(LLUICtrl* ctrl, WaterColorControl* colorControl)
@@ -382,9 +384,9 @@ void LLFloaterWater::onColorControlBMoved(LLUICtrl* ctrl, WaterColorControl* col
 		getChild<LLUICtrl>(name)->setValue(colorControl->mB);
 	}
 
-	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+	colorControl->update(LLWaterParamManager::getInstance()->mCurParams);
 
-	LLWaterParamManager::instance()->propagateParameters();
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 void LLFloaterWater::onColorControlAMoved(LLUICtrl* ctrl, WaterColorControl* colorControl)
@@ -393,9 +395,9 @@ void LLFloaterWater::onColorControlAMoved(LLUICtrl* ctrl, WaterColorControl* col
 
 	colorControl->mA = sldrCtrl->getValueF32();
 
-	colorControl->update(LLWaterParamManager::instance()->mCurParams);
+	colorControl->update(LLWaterParamManager::getInstance()->mCurParams);
 
-	LLWaterParamManager::instance()->propagateParameters();
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 
@@ -454,8 +456,8 @@ void LLFloaterWater::onColorControlIMoved(LLUICtrl* ctrl, WaterColorControl* col
 	}
 
 	// now update the current parameters and send them to shaders
-	colorControl->update(LLWaterParamManager::instance()->mCurParams);
-	LLWaterParamManager::instance()->propagateParameters();
+	colorControl->update(LLWaterParamManager::getInstance()->mCurParams);
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 void LLFloaterWater::onExpFloatControlMoved(LLUICtrl* ctrl, WaterExpFloatControl* expFloatControl)
@@ -464,10 +466,10 @@ void LLFloaterWater::onExpFloatControlMoved(LLUICtrl* ctrl, WaterExpFloatControl
 
 	F32 val = sldrCtrl->getValueF32();
 	expFloatControl->mExp = val;
-	LLWaterParamManager::instance()->setDensitySliderValue(val);
+	LLWaterParamManager::getInstance()->setDensitySliderValue(val);
 
-	expFloatControl->update(LLWaterParamManager::instance()->mCurParams);
-	LLWaterParamManager::instance()->propagateParameters();
+	expFloatControl->update(LLWaterParamManager::getInstance()->mCurParams);
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 void LLFloaterWater::onFloatControlMoved(LLUICtrl* ctrl, WaterFloatControl* floatControl)
@@ -476,23 +478,23 @@ void LLFloaterWater::onFloatControlMoved(LLUICtrl* ctrl, WaterFloatControl* floa
 
 	floatControl->mX = sldrCtrl->getValueF32() / floatControl->mMult;
 
-	floatControl->update(LLWaterParamManager::instance()->mCurParams);
-	LLWaterParamManager::instance()->propagateParameters();
+	floatControl->update(LLWaterParamManager::getInstance()->mCurParams);
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 void LLFloaterWater::onWaterFogColorMoved(LLUICtrl* ctrl, WaterColorControl* colorControl)
 {
 	LLColorSwatchCtrl* swatch = static_cast<LLColorSwatchCtrl*>(ctrl);
 	*colorControl = swatch->get();
 
-	colorControl->update(LLWaterParamManager::instance()->mCurParams);
-	LLWaterParamManager::instance()->propagateParameters();
+	colorControl->update(LLWaterParamManager::getInstance()->mCurParams);
+	LLWaterParamManager::getInstance()->propagateParameters();
 }
 
 void LLFloaterWater::onNormalMapPicked(LLUICtrl* ctrl)
 {
 	LLTextureCtrl* textCtrl = static_cast<LLTextureCtrl*>(ctrl);
 	LLUUID textID = textCtrl->getImageAssetID();
-	LLWaterParamManager::instance()->setNormalMapID(textID);
+	LLWaterParamManager::getInstance()->setNormalMapID(textID);
 }
 
 void LLFloaterWater::onNewPreset()
@@ -511,7 +513,7 @@ void LLFloaterWater::onSavePreset()
 		return;
 	}
 
-	LLWaterParamManager::instance()->mCurParams.mName = 
+	LLWaterParamManager::getInstance()->mCurParams.mName = 
 		comboBox->getSelectedItemLabel();
 
 	// check to see if it's a default and shouldn't be overwritten
@@ -532,7 +534,7 @@ bool LLFloaterWater::saveAlertCallback(const LLSD& notification, const LLSD& res
 	// if they choose save, do it.  Otherwise, don't do anything
 	if(option == 0) 
 	{
-		LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
+		LLWaterParamManager * param_mgr = LLWaterParamManager::getInstance();
 
 		param_mgr->setParamSet(
 			param_mgr->mCurParams.mName, 
@@ -583,7 +585,7 @@ bool LLFloaterWater::deleteAlertCallback(const LLSD& notification, const LLSD& r
 			return false;
 		}
 
-		LLWaterParamManager::instance()->removeParamSet(name, true);
+		LLWaterParamManager::getInstance()->removeParamSet(name, true);
 		
 		// remove and choose another
 		S32 new_index = combo_box->getCurrentIndex();
@@ -594,8 +596,8 @@ bool LLFloaterWater::deleteAlertCallback(const LLSD& notification, const LLSD& r
 		{
 			key_combo->remove(name);
 
-			// remove from slider, as well
-			day_cycle->deletePreset(name);
+			// water is not part of day cycles, yet
+			//day_cycle->deletePreset(name);
 		}
 
 		// pick the previously selected index after delete
diff --git a/indra/newview/llfloaterwater.h b/indra/newview/llfloaterwater.h
index e3db91e80def4bb59a4193a33ff1d980472d02f5..57fb9745b1939e41a29c591f409b24aec7a75fb3 100644
--- a/indra/newview/llfloaterwater.h
+++ b/indra/newview/llfloaterwater.h
@@ -101,6 +101,8 @@ class LLFloaterWater : public LLFloater
 
 private:
 	static std::set<std::string> sDefaultPresets;
+        static LLEnvKey::EScope sScope;
+        static std::string sOriginalTitle;
 };
 
 
diff --git a/indra/newview/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp
index ae98b2cf999e8747e1f4705caede6e0f7d4ecb7b..960a552b3d6c3a5e7e49f23a3234e35475b7ee73 100644
--- a/indra/newview/llfloaterwindlight.cpp
+++ b/indra/newview/llfloaterwindlight.cpp
@@ -2,25 +2,31 @@
  * @file llfloaterwindlight.cpp
  * @brief LLFloaterWindLight class definition
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
  * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
 
@@ -31,11 +37,9 @@
 #include "pipeline.h"
 #include "llsky.h"
 
-#include "llfloaterreg.h"
 #include "llsliderctrl.h"
 #include "llmultislider.h"
 #include "llmultisliderctrl.h"
-#include "llnotificationsutil.h"
 #include "llspinctrl.h"
 #include "llcheckboxctrl.h"
 #include "lluictrlfactory.h"
@@ -54,48 +58,31 @@
 #include "llwlparamset.h"
 #include "llwlparammanager.h"
 #include "llpostprocess.h"
-#include "lltabcontainer.h"
-
 
 #undef max
 
-std::set<std::string> LLFloaterWindLight::sDefaultPresets;
+LLFloaterWindLight* LLFloaterWindLight::sWindLight = NULL;
+std::set<LLWLParamKey> LLFloaterWindLight::sDefaultPresets;
+LLEnvKey::EScope LLFloaterWindLight::sScope;
+std::string LLFloaterWindLight::sOriginalTitle;
 
 static const F32 WL_SUN_AMBIENT_SLIDER_SCALE = 3.0f;
 
-LLFloaterWindLight::LLFloaterWindLight(const LLSD& key)
-  : LLFloater(key)
+LLFloaterWindLight::LLFloaterWindLight() : LLFloater(std::string("windlight floater"))
 {
-}
-
-LLFloaterWindLight::~LLFloaterWindLight()
-{
-}
-
-BOOL LLFloaterWindLight::postBuild()
-{
-	// add the list of presets
-	std::string def_days = getString("WLDefaultSkyNames");
-
-	// no editing or deleting of the blank string
-	sDefaultPresets.insert("");
-	boost_tokenizer tokens(def_days, boost::char_separator<char>(":"));
-	for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
-	{
-		std::string tok(*token_iter);
-		sDefaultPresets.insert(tok);
-	}
-
+	LLUICtrlFactory::getInstance()->buildFloater(this, "floater_windlight_options.xml", NULL, FALSE);
+	sOriginalTitle = getTitle();
+	
 	// add the combo boxes
 	LLComboBox* comboBox = getChild<LLComboBox>("WLPresetsCombo");
 
 	if(comboBox != NULL) {
-
-		std::map<std::string, LLWLParamSet>::iterator mIt = 
-			LLWLParamManager::instance()->mParamList.begin();
-		for(; mIt != LLWLParamManager::instance()->mParamList.end(); mIt++) 
+		
+		std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = 
+			LLWLParamManager::getInstance()->mParamList.begin();
+		for(; mIt != LLWLParamManager::getInstance()->mParamList.end(); mIt++) 
 		{
-			comboBox->add(mIt->first);
+			comboBox->add(mIt->first.toString(), mIt->first.toLLSD());
 		}
 
 		// entry for when we're in estate time
@@ -104,107 +91,167 @@ BOOL LLFloaterWindLight::postBuild()
 		// set defaults on combo boxes
 		comboBox->selectByValue(LLSD("Default"));
 	}
+
+	// add the list of presets
+	std::string def_days = getString("WLDefaultSkyNames");
+
+	// no editing or deleting of the blank string
+	LLWLParamKey blank("", LLEnvKey::SCOPE_LOCAL);
+	sDefaultPresets.insert(blank);
+	boost_tokenizer tokens(def_days, boost::char_separator<char>(":"));
+	for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
+	{
+		std::string tok(*token_iter);
+		LLWLParamKey key(tok, LLEnvKey::SCOPE_LOCAL);
+		sDefaultPresets.insert(key);
+	}
+
 	// load it up
 	initCallbacks();
+}
 
-	syncMenu();
-	
-	return TRUE;
+LLFloaterWindLight::~LLFloaterWindLight()
+{
 }
+
 void LLFloaterWindLight::initCallbacks(void) {
 
-	LLWLParamManager * param_mgr = LLWLParamManager::instance();
+	// help buttons
+	initHelpBtn("WLBlueHorizonHelp", "HelpBlueHorizon");
+	initHelpBtn("WLHazeHorizonHelp", "HelpHazeHorizon");
+	initHelpBtn("WLBlueDensityHelp", "HelpBlueDensity");
+	initHelpBtn("WLHazeDensityHelp", "HelpHazeDensity");
+
+	initHelpBtn("WLDensityMultHelp", "HelpDensityMult");
+	initHelpBtn("WLDistanceMultHelp", "HelpDistanceMult");
+	initHelpBtn("WLMaxAltitudeHelp", "HelpMaxAltitude");
+
+	initHelpBtn("WLSunlightColorHelp", "HelpSunlightColor");
+	initHelpBtn("WLAmbientHelp", "HelpSunAmbient");
+	initHelpBtn("WLSunGlowHelp", "HelpSunGlow");
+	initHelpBtn("WLTimeOfDayHelp", "HelpTimeOfDay");
+	initHelpBtn("WLEastAngleHelp", "HelpEastAngle");
+
+	initHelpBtn("WLSceneGammaHelp", "HelpSceneGamma");
+	initHelpBtn("WLStarBrightnessHelp", "HelpStarBrightness");
+
+	initHelpBtn("WLCloudColorHelp", "HelpCloudColor");
+	initHelpBtn("WLCloudDetailHelp", "HelpCloudDetail");
+	initHelpBtn("WLCloudDensityHelp", "HelpCloudDensity");
+	initHelpBtn("WLCloudCoverageHelp", "HelpCloudCoverage");
+
+	initHelpBtn("WLCloudScaleHelp", "HelpCloudScale");
+	initHelpBtn("WLCloudScrollXHelp", "HelpCloudScrollX");
+	initHelpBtn("WLCloudScrollYHelp", "HelpCloudScrollY");
+
+	initHelpBtn("WLClassicCloudsHelp", "HelpClassicClouds");
+
+	LLWLParamManager * param_mgr = LLWLParamManager::getInstance();
 
 	// blue horizon
-	getChild<LLUICtrl>("WLBlueHorizonR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, &param_mgr->mBlueHorizon));
-	getChild<LLUICtrl>("WLBlueHorizonG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, &param_mgr->mBlueHorizon));
-	getChild<LLUICtrl>("WLBlueHorizonB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, &param_mgr->mBlueHorizon));
-	getChild<LLUICtrl>("WLBlueHorizonI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, &param_mgr->mBlueHorizon));
+	childSetCommitCallback("WLBlueHorizonR", onColorControlRMoved, &param_mgr->mBlueHorizon);
+	childSetCommitCallback("WLBlueHorizonG", onColorControlGMoved, &param_mgr->mBlueHorizon);
+	childSetCommitCallback("WLBlueHorizonB", onColorControlBMoved, &param_mgr->mBlueHorizon);
+	childSetCommitCallback("WLBlueHorizonI", onColorControlIMoved, &param_mgr->mBlueHorizon);
 
 	// haze density, horizon, mult, and altitude
-	getChild<LLUICtrl>("WLHazeDensity")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, &param_mgr->mHazeDensity));
-	getChild<LLUICtrl>("WLHazeHorizon")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, &param_mgr->mHazeHorizon));
-	getChild<LLUICtrl>("WLDensityMult")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, &param_mgr->mDensityMult));
-	getChild<LLUICtrl>("WLMaxAltitude")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, &param_mgr->mMaxAlt));
+	childSetCommitCallback("WLHazeDensity", onColorControlRMoved, &param_mgr->mHazeDensity);
+	childSetCommitCallback("WLHazeHorizon", onColorControlRMoved, &param_mgr->mHazeHorizon);
+	childSetCommitCallback("WLDensityMult", onFloatControlMoved, &param_mgr->mDensityMult);
+	childSetCommitCallback("WLMaxAltitude", onFloatControlMoved, &param_mgr->mMaxAlt);
 
 	// blue density
-	getChild<LLUICtrl>("WLBlueDensityR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, &param_mgr->mBlueDensity));
-	getChild<LLUICtrl>("WLBlueDensityG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, &param_mgr->mBlueDensity));
-	getChild<LLUICtrl>("WLBlueDensityB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, &param_mgr->mBlueDensity));
-	getChild<LLUICtrl>("WLBlueDensityI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, &param_mgr->mBlueDensity));
+	childSetCommitCallback("WLBlueDensityR", onColorControlRMoved, &param_mgr->mBlueDensity);
+	childSetCommitCallback("WLBlueDensityG", onColorControlGMoved, &param_mgr->mBlueDensity);
+	childSetCommitCallback("WLBlueDensityB", onColorControlBMoved, &param_mgr->mBlueDensity);
+	childSetCommitCallback("WLBlueDensityI", onColorControlIMoved, &param_mgr->mBlueDensity);
 
 	// Lighting
 	
 	// sunlight
-	getChild<LLUICtrl>("WLSunlightR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, &param_mgr->mSunlight));
-	getChild<LLUICtrl>("WLSunlightG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, &param_mgr->mSunlight));
-	getChild<LLUICtrl>("WLSunlightB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, &param_mgr->mSunlight));
-	getChild<LLUICtrl>("WLSunlightI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, &param_mgr->mSunlight));
+	childSetCommitCallback("WLSunlightR", onColorControlRMoved, &param_mgr->mSunlight);
+	childSetCommitCallback("WLSunlightG", onColorControlGMoved, &param_mgr->mSunlight);
+	childSetCommitCallback("WLSunlightB", onColorControlBMoved, &param_mgr->mSunlight);
+	childSetCommitCallback("WLSunlightI", onColorControlIMoved, &param_mgr->mSunlight);
 
 	// glow
-	getChild<LLUICtrl>("WLGlowR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onGlowRMoved, this, _1, &param_mgr->mGlow));
-	getChild<LLUICtrl>("WLGlowB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onGlowBMoved, this, _1, &param_mgr->mGlow));
+	childSetCommitCallback("WLGlowR", onGlowRMoved, &param_mgr->mGlow);
+	childSetCommitCallback("WLGlowB", onGlowBMoved, &param_mgr->mGlow);
 
 	// ambient
-	getChild<LLUICtrl>("WLAmbientR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, &param_mgr->mAmbient));
-	getChild<LLUICtrl>("WLAmbientG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, &param_mgr->mAmbient));
-	getChild<LLUICtrl>("WLAmbientB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, &param_mgr->mAmbient));
-	getChild<LLUICtrl>("WLAmbientI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, &param_mgr->mAmbient));
+	childSetCommitCallback("WLAmbientR", onColorControlRMoved, &param_mgr->mAmbient);
+	childSetCommitCallback("WLAmbientG", onColorControlGMoved, &param_mgr->mAmbient);
+	childSetCommitCallback("WLAmbientB", onColorControlBMoved, &param_mgr->mAmbient);
+	childSetCommitCallback("WLAmbientI", onColorControlIMoved, &param_mgr->mAmbient);
 
 	// time of day
-	getChild<LLUICtrl>("WLSunAngle")->setCommitCallback(boost::bind(&LLFloaterWindLight::onSunMoved, this, _1, &param_mgr->mLightnorm));
-	getChild<LLUICtrl>("WLEastAngle")->setCommitCallback(boost::bind(&LLFloaterWindLight::onSunMoved, this, _1, &param_mgr->mLightnorm));
+	childSetCommitCallback("WLSunAngle", onSunMoved, &param_mgr->mLightnorm);
+	childSetCommitCallback("WLEastAngle", onSunMoved, &param_mgr->mLightnorm);
 
 	// Clouds
 
 	// Cloud Color
-	getChild<LLUICtrl>("WLCloudColorR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, &param_mgr->mCloudColor));
-	getChild<LLUICtrl>("WLCloudColorG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, &param_mgr->mCloudColor));
-	getChild<LLUICtrl>("WLCloudColorB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, &param_mgr->mCloudColor));
-	getChild<LLUICtrl>("WLCloudColorI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, &param_mgr->mCloudColor));
+	childSetCommitCallback("WLCloudColorR", onColorControlRMoved, &param_mgr->mCloudColor);
+	childSetCommitCallback("WLCloudColorG", onColorControlGMoved, &param_mgr->mCloudColor);
+	childSetCommitCallback("WLCloudColorB", onColorControlBMoved, &param_mgr->mCloudColor);
+	childSetCommitCallback("WLCloudColorI", onColorControlIMoved, &param_mgr->mCloudColor);
 
 	// Cloud
-	getChild<LLUICtrl>("WLCloudX")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, &param_mgr->mCloudMain));
-	getChild<LLUICtrl>("WLCloudY")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, &param_mgr->mCloudMain));
-	getChild<LLUICtrl>("WLCloudDensity")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, &param_mgr->mCloudMain));
+	childSetCommitCallback("WLCloudX", onColorControlRMoved, &param_mgr->mCloudMain);
+	childSetCommitCallback("WLCloudY", onColorControlGMoved, &param_mgr->mCloudMain);
+	childSetCommitCallback("WLCloudDensity", onColorControlBMoved, &param_mgr->mCloudMain);
 
 	// Cloud Detail
-	getChild<LLUICtrl>("WLCloudDetailX")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, &param_mgr->mCloudDetail));
-	getChild<LLUICtrl>("WLCloudDetailY")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, &param_mgr->mCloudDetail));
-	getChild<LLUICtrl>("WLCloudDetailDensity")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, &param_mgr->mCloudDetail));
+	childSetCommitCallback("WLCloudDetailX", onColorControlRMoved, &param_mgr->mCloudDetail);
+	childSetCommitCallback("WLCloudDetailY", onColorControlGMoved, &param_mgr->mCloudDetail);
+	childSetCommitCallback("WLCloudDetailDensity", onColorControlBMoved, &param_mgr->mCloudDetail);
 
 	// Cloud extras
-	getChild<LLUICtrl>("WLCloudCoverage")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, &param_mgr->mCloudCoverage));
-	getChild<LLUICtrl>("WLCloudScale")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, &param_mgr->mCloudScale));
-	getChild<LLUICtrl>("WLCloudLockX")->setCommitCallback(boost::bind(&LLFloaterWindLight::onCloudScrollXToggled, this, _1));
-	getChild<LLUICtrl>("WLCloudLockY")->setCommitCallback(boost::bind(&LLFloaterWindLight::onCloudScrollYToggled, this, _1));
-	getChild<LLUICtrl>("WLCloudScrollX")->setCommitCallback(boost::bind(&LLFloaterWindLight::onCloudScrollXMoved, this, _1));
-	getChild<LLUICtrl>("WLCloudScrollY")->setCommitCallback(boost::bind(&LLFloaterWindLight::onCloudScrollYMoved, this, _1));
-	getChild<LLUICtrl>("WLDistanceMult")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, &param_mgr->mDistanceMult));
-	getChild<LLUICtrl>("DrawClassicClouds")->setCommitCallback(boost::bind(LLSavedSettingsGlue::setBOOL, _1, "SkyUseClassicClouds"));
+	childSetCommitCallback("WLCloudCoverage", onFloatControlMoved, &param_mgr->mCloudCoverage);
+	childSetCommitCallback("WLCloudScale", onFloatControlMoved, &param_mgr->mCloudScale);
+	childSetCommitCallback("WLCloudLockX", onCloudScrollXToggled, NULL);
+	childSetCommitCallback("WLCloudLockY", onCloudScrollYToggled, NULL);
+	childSetCommitCallback("WLCloudScrollX", onCloudScrollXMoved, NULL);
+	childSetCommitCallback("WLCloudScrollY", onCloudScrollYMoved, NULL);
+	childSetCommitCallback("WLDistanceMult", onFloatControlMoved, &param_mgr->mDistanceMult);
+	childSetCommitCallback("DrawClassicClouds", LLSavedSettingsGlue::setBOOL, (void*)"SkyUseClassicClouds");
 
 	// WL Top
-	getChild<LLUICtrl>("WLDayCycleMenuButton")->setCommitCallback(boost::bind(&LLFloaterWindLight::onOpenDayCycle, this));
+	childSetAction("WLDayCycleMenuButton", onOpenDayCycle, NULL);
 	// Load/save
 	LLComboBox* comboBox = getChild<LLComboBox>("WLPresetsCombo");
 
 	//childSetAction("WLLoadPreset", onLoadPreset, comboBox);
-	getChild<LLUICtrl>("WLNewPreset")->setCommitCallback(boost::bind(&LLFloaterWindLight::onNewPreset, this));
-	getChild<LLUICtrl>("WLSavePreset")->setCommitCallback(boost::bind(&LLFloaterWindLight::onSavePreset, this));
-	getChild<LLUICtrl>("WLDeletePreset")->setCommitCallback(boost::bind(&LLFloaterWindLight::onDeletePreset, this));
+	childSetAction("WLNewPreset", onNewPreset, comboBox);
+	childSetAction("WLSavePreset", onSavePreset, comboBox);
+	childSetAction("WLDeletePreset", onDeletePreset, comboBox);
 
-	comboBox->setCommitCallback(boost::bind(&LLFloaterWindLight::onChangePresetName, this, _1));
+	comboBox->setCommitCallback(onChangePresetName);
 
 
 	// Dome
-	getChild<LLUICtrl>("WLGamma")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, &param_mgr->mWLGamma));
-	getChild<LLUICtrl>("WLStarAlpha")->setCommitCallback(boost::bind(&LLFloaterWindLight::onStarAlphaMoved, this, _1));
+	childSetCommitCallback("WLGamma", onFloatControlMoved, &param_mgr->mWLGamma);
+	childSetCommitCallback("WLStarAlpha", onStarAlphaMoved, NULL);
+}
+
+void LLFloaterWindLight::onClickHelp(void* data)
+{
+	LLFloaterWindLight* self = LLFloaterWindLight::instance();
+
+	const std::string xml_alert = *(std::string*)data;
+	LLNotifications::instance().add(self->contextualNotification(xml_alert));
+}
+
+void LLFloaterWindLight::initHelpBtn(const std::string& name, const std::string& xml_alert)
+{
+	childSetAction(name, onClickHelp, new std::string(xml_alert));
 }
 
 bool LLFloaterWindLight::newPromptCallback(const LLSD& notification, const LLSD& response)
 {
 	std::string text = response["message"].asString();
-	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+	LLWLParamKey newKey(text, LLEnvKey::SCOPE_LOCAL);
+	S32 option = LLNotification::getSelectedOption(notification, response);
 
 	if(text == "")
 	{
@@ -212,26 +259,29 @@ bool LLFloaterWindLight::newPromptCallback(const LLSD& notification, const LLSD&
 	}
 
 	if(option == 0) {
-		LLComboBox* comboBox = getChild<LLComboBox>("WLPresetsCombo");
+		LLComboBox* comboBox = sWindLight->getChild<LLComboBox>( 
+			"WLPresetsCombo");
 
-		LLFloaterDayCycle* day_cycle = LLFloaterReg::findTypedInstance<LLFloaterDayCycle>("env_day_cycle");
+		LLFloaterDayCycle* sDayCycle = NULL;
 		LLComboBox* keyCombo = NULL;
-		if(day_cycle) 
+		if(LLFloaterDayCycle::isOpen()) 
 		{
-			keyCombo = day_cycle->getChild<LLComboBox>("WLKeyPresets");
+			sDayCycle = LLFloaterDayCycle::instance();
+			keyCombo = sDayCycle->getChild<LLComboBox>( 
+				"WLKeyPresets");
 		}
 
 		// add the current parameters to the list
 		// see if it's there first
-		std::map<std::string, LLWLParamSet>::iterator mIt = 
-			LLWLParamManager::instance()->mParamList.find(text);
+		std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = 
+			LLWLParamManager::getInstance()->mParamList.find(newKey);
 
 		// if not there, add a new one
-		if(mIt == LLWLParamManager::instance()->mParamList.end()) 
+		if(mIt == LLWLParamManager::getInstance()->mParamList.end()) 
 		{
-			LLWLParamManager::instance()->addParamSet(text, 
-				LLWLParamManager::instance()->mCurParams);
-			comboBox->add(text);
+			LLWLParamManager::getInstance()->addParamSet(newKey, 
+				LLWLParamManager::getInstance()->mCurParams);
+			comboBox->add(newKey.toString(), newKey.toLLSD());
 			comboBox->sortByName();
 
 			// add a blank to the bottom
@@ -243,18 +293,18 @@ bool LLFloaterWindLight::newPromptCallback(const LLSD& notification, const LLSD&
 			comboBox->add(LLStringUtil::null);
 
 			comboBox->setSelectedByValue(text, true);
-			if(keyCombo) 
+			if(LLFloaterDayCycle::isOpen()) 
 			{
 				keyCombo->add(text);
 				keyCombo->sortByName();
 			}
-			LLWLParamManager::instance()->savePreset(text);
+			LLWLParamManager::getInstance()->savePreset(newKey);
 
 		// otherwise, send a message to the user
 		} 
 		else 
 		{
-			LLNotificationsUtil::add("ExistsSkyPresetAlert");
+			LLNotifications::instance().add("ExistsSkyPresetAlert");
 		}
 	}
 	return false;
@@ -264,38 +314,38 @@ void LLFloaterWindLight::syncMenu()
 {
 	bool err;
 
-	LLWLParamManager * param_mgr = LLWLParamManager::instance();
+	LLWLParamManager * param_mgr = LLWLParamManager::getInstance();
 
 	LLWLParamSet& currentParams = param_mgr->mCurParams;
 	//std::map<std::string, LLVector4> & currentParams = param_mgr->mCurParams.mParamValues;
 
 	// blue horizon
 	param_mgr->mBlueHorizon = currentParams.getVector(param_mgr->mBlueHorizon.mName, err);
-	getChild<LLUICtrl>("WLBlueHorizonR")->setValue(param_mgr->mBlueHorizon.r / 2.0);
-	getChild<LLUICtrl>("WLBlueHorizonG")->setValue(param_mgr->mBlueHorizon.g / 2.0);
-	getChild<LLUICtrl>("WLBlueHorizonB")->setValue(param_mgr->mBlueHorizon.b / 2.0);
-	getChild<LLUICtrl>("WLBlueHorizonI")->setValue(
+	childSetValue("WLBlueHorizonR", param_mgr->mBlueHorizon.r / 2.0);
+	childSetValue("WLBlueHorizonG", param_mgr->mBlueHorizon.g / 2.0);
+	childSetValue("WLBlueHorizonB", param_mgr->mBlueHorizon.b / 2.0);
+	childSetValue("WLBlueHorizonI", 
 		std::max(param_mgr->mBlueHorizon.r / 2.0, 
 			std::max(param_mgr->mBlueHorizon.g / 2.0, 
 				param_mgr->mBlueHorizon.b / 2.0)));
 
 	// haze density, horizon, mult, and altitude
 	param_mgr->mHazeDensity = currentParams.getVector(param_mgr->mHazeDensity.mName, err);
-	getChild<LLUICtrl>("WLHazeDensity")->setValue(param_mgr->mHazeDensity.r);
+	childSetValue("WLHazeDensity", param_mgr->mHazeDensity.r);
 	param_mgr->mHazeHorizon = currentParams.getVector(param_mgr->mHazeHorizon.mName, err);
-	getChild<LLUICtrl>("WLHazeHorizon")->setValue(param_mgr->mHazeHorizon.r);
+	childSetValue("WLHazeHorizon", param_mgr->mHazeHorizon.r);
 	param_mgr->mDensityMult = currentParams.getVector(param_mgr->mDensityMult.mName, err);
-	getChild<LLUICtrl>("WLDensityMult")->setValue(param_mgr->mDensityMult.x * 
+	childSetValue("WLDensityMult", param_mgr->mDensityMult.x * 
 		param_mgr->mDensityMult.mult);
 	param_mgr->mMaxAlt = currentParams.getVector(param_mgr->mMaxAlt.mName, err);
-	getChild<LLUICtrl>("WLMaxAltitude")->setValue(param_mgr->mMaxAlt.x);
+	childSetValue("WLMaxAltitude", param_mgr->mMaxAlt.x);
 
 	// blue density
 	param_mgr->mBlueDensity = currentParams.getVector(param_mgr->mBlueDensity.mName, err);
-	getChild<LLUICtrl>("WLBlueDensityR")->setValue(param_mgr->mBlueDensity.r / 2.0);
-	getChild<LLUICtrl>("WLBlueDensityG")->setValue(param_mgr->mBlueDensity.g / 2.0);
-	getChild<LLUICtrl>("WLBlueDensityB")->setValue(param_mgr->mBlueDensity.b / 2.0);
-	getChild<LLUICtrl>("WLBlueDensityI")->setValue(
+	childSetValue("WLBlueDensityR", param_mgr->mBlueDensity.r / 2.0);
+	childSetValue("WLBlueDensityG", param_mgr->mBlueDensity.g / 2.0);
+	childSetValue("WLBlueDensityB", param_mgr->mBlueDensity.b / 2.0);
+	childSetValue("WLBlueDensityI", 
 		std::max(param_mgr->mBlueDensity.r / 2.0, 
 		std::max(param_mgr->mBlueDensity.g / 2.0, param_mgr->mBlueDensity.b / 2.0)));
 
@@ -303,107 +353,161 @@ void LLFloaterWindLight::syncMenu()
 	
 	// sunlight
 	param_mgr->mSunlight = currentParams.getVector(param_mgr->mSunlight.mName, err);
-	getChild<LLUICtrl>("WLSunlightR")->setValue(param_mgr->mSunlight.r / WL_SUN_AMBIENT_SLIDER_SCALE);
-	getChild<LLUICtrl>("WLSunlightG")->setValue(param_mgr->mSunlight.g / WL_SUN_AMBIENT_SLIDER_SCALE);
-	getChild<LLUICtrl>("WLSunlightB")->setValue(param_mgr->mSunlight.b / WL_SUN_AMBIENT_SLIDER_SCALE);
-	getChild<LLUICtrl>("WLSunlightI")->setValue(
+	childSetValue("WLSunlightR", param_mgr->mSunlight.r / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLSunlightG", param_mgr->mSunlight.g / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLSunlightB", param_mgr->mSunlight.b / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLSunlightI", 
 		std::max(param_mgr->mSunlight.r / WL_SUN_AMBIENT_SLIDER_SCALE, 
 		std::max(param_mgr->mSunlight.g / WL_SUN_AMBIENT_SLIDER_SCALE, param_mgr->mSunlight.b / WL_SUN_AMBIENT_SLIDER_SCALE)));
 
 	// glow
 	param_mgr->mGlow = currentParams.getVector(param_mgr->mGlow.mName, err);
-	getChild<LLUICtrl>("WLGlowR")->setValue(2 - param_mgr->mGlow.r / 20.0f);
-	getChild<LLUICtrl>("WLGlowB")->setValue(-param_mgr->mGlow.b / 5.0f);
+	childSetValue("WLGlowR", 2 - param_mgr->mGlow.r / 20.0f);
+	childSetValue("WLGlowB", -param_mgr->mGlow.b / 5.0f);
 		
 	// ambient
 	param_mgr->mAmbient = currentParams.getVector(param_mgr->mAmbient.mName, err);
-	getChild<LLUICtrl>("WLAmbientR")->setValue(param_mgr->mAmbient.r / WL_SUN_AMBIENT_SLIDER_SCALE);
-	getChild<LLUICtrl>("WLAmbientG")->setValue(param_mgr->mAmbient.g / WL_SUN_AMBIENT_SLIDER_SCALE);
-	getChild<LLUICtrl>("WLAmbientB")->setValue(param_mgr->mAmbient.b / WL_SUN_AMBIENT_SLIDER_SCALE);
-	getChild<LLUICtrl>("WLAmbientI")->setValue(
+	childSetValue("WLAmbientR", param_mgr->mAmbient.r / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLAmbientG", param_mgr->mAmbient.g / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLAmbientB", param_mgr->mAmbient.b / WL_SUN_AMBIENT_SLIDER_SCALE);
+	childSetValue("WLAmbientI", 
 		std::max(param_mgr->mAmbient.r / WL_SUN_AMBIENT_SLIDER_SCALE, 
 		std::max(param_mgr->mAmbient.g / WL_SUN_AMBIENT_SLIDER_SCALE, param_mgr->mAmbient.b / WL_SUN_AMBIENT_SLIDER_SCALE)));		
 
-	getChild<LLUICtrl>("WLSunAngle")->setValue(param_mgr->mCurParams.getFloat("sun_angle",err) / F_TWO_PI);
-	getChild<LLUICtrl>("WLEastAngle")->setValue(param_mgr->mCurParams.getFloat("east_angle",err) / F_TWO_PI);
+	childSetValue("WLSunAngle", param_mgr->mCurParams.getFloat("sun_angle",err) / F_TWO_PI);
+	childSetValue("WLEastAngle", param_mgr->mCurParams.getFloat("east_angle",err) / F_TWO_PI);
 
 	// Clouds
 
 	// Cloud Color
 	param_mgr->mCloudColor = currentParams.getVector(param_mgr->mCloudColor.mName, err);
-	getChild<LLUICtrl>("WLCloudColorR")->setValue(param_mgr->mCloudColor.r);
-	getChild<LLUICtrl>("WLCloudColorG")->setValue(param_mgr->mCloudColor.g);
-	getChild<LLUICtrl>("WLCloudColorB")->setValue(param_mgr->mCloudColor.b);
-	getChild<LLUICtrl>("WLCloudColorI")->setValue(
+	childSetValue("WLCloudColorR", param_mgr->mCloudColor.r);
+	childSetValue("WLCloudColorG", param_mgr->mCloudColor.g);
+	childSetValue("WLCloudColorB", param_mgr->mCloudColor.b);
+	childSetValue("WLCloudColorI", 
 		std::max(param_mgr->mCloudColor.r, 
 		std::max(param_mgr->mCloudColor.g, param_mgr->mCloudColor.b)));
 
 	// Cloud
 	param_mgr->mCloudMain = currentParams.getVector(param_mgr->mCloudMain.mName, err);
-	getChild<LLUICtrl>("WLCloudX")->setValue(param_mgr->mCloudMain.r);
-	getChild<LLUICtrl>("WLCloudY")->setValue(param_mgr->mCloudMain.g);
-	getChild<LLUICtrl>("WLCloudDensity")->setValue(param_mgr->mCloudMain.b);
+	childSetValue("WLCloudX", param_mgr->mCloudMain.r);
+	childSetValue("WLCloudY", param_mgr->mCloudMain.g);
+	childSetValue("WLCloudDensity", param_mgr->mCloudMain.b);
 
 	// Cloud Detail
 	param_mgr->mCloudDetail = currentParams.getVector(param_mgr->mCloudDetail.mName, err);
-	getChild<LLUICtrl>("WLCloudDetailX")->setValue(param_mgr->mCloudDetail.r);
-	getChild<LLUICtrl>("WLCloudDetailY")->setValue(param_mgr->mCloudDetail.g);
-	getChild<LLUICtrl>("WLCloudDetailDensity")->setValue(param_mgr->mCloudDetail.b);
+	childSetValue("WLCloudDetailX", param_mgr->mCloudDetail.r);
+	childSetValue("WLCloudDetailY", param_mgr->mCloudDetail.g);
+	childSetValue("WLCloudDetailDensity", param_mgr->mCloudDetail.b);
 
 	// Cloud extras
 	param_mgr->mCloudCoverage = currentParams.getVector(param_mgr->mCloudCoverage.mName, err);
 	param_mgr->mCloudScale = currentParams.getVector(param_mgr->mCloudScale.mName, err);
-	getChild<LLUICtrl>("WLCloudCoverage")->setValue(param_mgr->mCloudCoverage.x);
-	getChild<LLUICtrl>("WLCloudScale")->setValue(param_mgr->mCloudScale.x);
+	childSetValue("WLCloudCoverage", param_mgr->mCloudCoverage.x);
+	childSetValue("WLCloudScale", param_mgr->mCloudScale.x);
 
 	// cloud scrolling
 	bool lockX = !param_mgr->mCurParams.getEnableCloudScrollX();
 	bool lockY = !param_mgr->mCurParams.getEnableCloudScrollY();
-	getChild<LLUICtrl>("WLCloudLockX")->setValue(lockX);
-	getChild<LLUICtrl>("WLCloudLockY")->setValue(lockY);
-	getChild<LLUICtrl>("DrawClassicClouds")->setValue(gSavedSettings.getBOOL("SkyUseClassicClouds"));
+	childSetValue("WLCloudLockX", lockX);
+	childSetValue("WLCloudLockY", lockY);
+	childSetValue("DrawClassicClouds", gSavedSettings.getBOOL("SkyUseClassicClouds"));
 	
 	// disable if locked, enable if not
 	if(lockX) 
 	{
-		getChildView("WLCloudScrollX")->setEnabled(FALSE);
+		childDisable("WLCloudScrollX");
 	} else {
-		getChildView("WLCloudScrollX")->setEnabled(TRUE);
+		childEnable("WLCloudScrollX");
 	}
 	if(lockY)
 	{
-		getChildView("WLCloudScrollY")->setEnabled(FALSE);
+		childDisable("WLCloudScrollY");
 	} else {
-		getChildView("WLCloudScrollY")->setEnabled(TRUE);
+		childEnable("WLCloudScrollY");
 	}
 
 	// *HACK cloud scrolling is off my an additive of 10
-	getChild<LLUICtrl>("WLCloudScrollX")->setValue(param_mgr->mCurParams.getCloudScrollX() - 10.0f);
-	getChild<LLUICtrl>("WLCloudScrollY")->setValue(param_mgr->mCurParams.getCloudScrollY() - 10.0f);
+	childSetValue("WLCloudScrollX", param_mgr->mCurParams.getCloudScrollX() - 10.0f);
+	childSetValue("WLCloudScrollY", param_mgr->mCurParams.getCloudScrollY() - 10.0f);
 
 	param_mgr->mDistanceMult = currentParams.getVector(param_mgr->mDistanceMult.mName, err);
-	getChild<LLUICtrl>("WLDistanceMult")->setValue(param_mgr->mDistanceMult.x);
+	childSetValue("WLDistanceMult", param_mgr->mDistanceMult.x);
 
 	// Tweak extras
 
 	param_mgr->mWLGamma = currentParams.getVector(param_mgr->mWLGamma.mName, err);
-	getChild<LLUICtrl>("WLGamma")->setValue(param_mgr->mWLGamma.x);
+	childSetValue("WLGamma", param_mgr->mWLGamma.x);
 
-	getChild<LLUICtrl>("WLStarAlpha")->setValue(param_mgr->mCurParams.getStarBrightness());
+	childSetValue("WLStarAlpha", param_mgr->mCurParams.getStarBrightness());
+}
 
-	LLTabContainer* tab = getChild<LLTabContainer>("WindLight Tabs");
-	LLPanel* panel = getChild<LLPanel>("Scattering");
 
-	tab->enableTabButton(tab->getIndexForPanel(panel), gSavedSettings.getBOOL("RenderDeferredGI"));
+// static
+LLFloaterWindLight* LLFloaterWindLight::instance()
+{
+	if (!sWindLight)
+	{
+		sWindLight = new LLFloaterWindLight();
+	}
+	return sWindLight;
+}
+void LLFloaterWindLight::show(LLEnvKey::EScope scope)
+{
+	LLFloaterWindLight* windLight = instance();
+	if(scope != sScope && ((LLView*)windLight)->getVisible())
+	{
+		LLNotifications::instance().add("EnvOtherScopeAlreadyOpen", LLSD());
+		return;
+	}
+	sScope = scope;
+	std::string scope_str = "";
+	switch(sScope)
+	{
+		case LLEnvKey::SCOPE_LOCAL:
+			scope_str = LLTrans::getString("LocalSettings");
+			break;
+		case LLEnvKey::SCOPE_REGION:
+			scope_str = LLTrans::getString("RegionSettings");
+			break;
+	}
+	std::string title = sOriginalTitle + " (" + scope_str + ")";
+	windLight->setTitle(title);
+	windLight->syncMenu();
+
+	LLEnvManager::instance().startEditingScope(scope);
+
+	// comment in if you want the menu to rebuild each time
+	//LLUICtrlFactory::getInstance()->buildFloater(windLight, "floater_windlight_options.xml");
+	//windLight->initCallbacks();
+
+	windLight->open();
 }
 
+bool LLFloaterWindLight::isOpen()
+{
+	if (sWindLight != NULL) {
+		return true;
+	}
+	return false;
+}
+
+// virtual
+void LLFloaterWindLight::onClose(bool app_quitting)
+{
+	if (sWindLight)
+	{
+		sWindLight->setVisible(FALSE);
+	}
+}
 
 // color control callbacks
-void LLFloaterWindLight::onColorControlRMoved(LLUICtrl* ctrl, WLColorControl* colorControl)
+void LLFloaterWindLight::onColorControlRMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
 
 	colorControl->r = sldrCtrl->getValueF32();
 	if(colorControl->isSunOrAmbientColor) {
@@ -421,24 +525,25 @@ void LLFloaterWindLight::onColorControlRMoved(LLUICtrl* ctrl, WLColorControl* co
 		name.append("I");
 		
 		if(colorControl->isSunOrAmbientColor) {
-			getChild<LLUICtrl>(name)->setValue(colorControl->r / 3);
+			sWindLight->childSetValue(name, colorControl->r / 3);
 		} else if(colorControl->isBlueHorizonOrDensity) {
-			getChild<LLUICtrl>(name)->setValue(colorControl->r / 2);
+			sWindLight->childSetValue(name, colorControl->r / 2);
 		} else {
-			getChild<LLUICtrl>(name)->setValue(colorControl->r);
+			sWindLight->childSetValue(name, colorControl->r);
 		}
 	}
 
-	colorControl->update(LLWLParamManager::instance()->mCurParams);
+	colorControl->update(LLWLParamManager::getInstance()->mCurParams);
 
-	LLWLParamManager::instance()->propagateParameters();
+	LLWLParamManager::getInstance()->propagateParameters();
 }
 
-void LLFloaterWindLight::onColorControlGMoved(LLUICtrl* ctrl, WLColorControl* colorControl)
+void LLFloaterWindLight::onColorControlGMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
 
 	colorControl->g = sldrCtrl->getValueF32();
 	if(colorControl->isSunOrAmbientColor) {
@@ -456,24 +561,25 @@ void LLFloaterWindLight::onColorControlGMoved(LLUICtrl* ctrl, WLColorControl* co
 		name.append("I");
 
 		if(colorControl->isSunOrAmbientColor) {
-			getChild<LLUICtrl>(name)->setValue(colorControl->g / 3);
+			sWindLight->childSetValue(name, colorControl->g / 3);
 		} else if(colorControl->isBlueHorizonOrDensity) {
-			getChild<LLUICtrl>(name)->setValue(colorControl->g / 2);
+			sWindLight->childSetValue(name, colorControl->g / 2);
 		} else {
-			getChild<LLUICtrl>(name)->setValue(colorControl->g);
+			sWindLight->childSetValue(name, colorControl->g);
 		}
 	}
 
-	colorControl->update(LLWLParamManager::instance()->mCurParams);
+	colorControl->update(LLWLParamManager::getInstance()->mCurParams);
 
-	LLWLParamManager::instance()->propagateParameters();
+	LLWLParamManager::getInstance()->propagateParameters();
 }
 
-void LLFloaterWindLight::onColorControlBMoved(LLUICtrl* ctrl, WLColorControl* colorControl)
+void LLFloaterWindLight::onColorControlBMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
 
 	colorControl->b = sldrCtrl->getValueF32();
 	if(colorControl->isSunOrAmbientColor) {
@@ -491,24 +597,25 @@ void LLFloaterWindLight::onColorControlBMoved(LLUICtrl* ctrl, WLColorControl* co
 		name.append("I");
 
 		if(colorControl->isSunOrAmbientColor) {
-			getChild<LLUICtrl>(name)->setValue(colorControl->b / 3);
+			sWindLight->childSetValue(name, colorControl->b / 3);
 		} else if(colorControl->isBlueHorizonOrDensity) {
-			getChild<LLUICtrl>(name)->setValue(colorControl->b / 2);
+			sWindLight->childSetValue(name, colorControl->b / 2);
 		} else {
-			getChild<LLUICtrl>(name)->setValue(colorControl->b);
+			sWindLight->childSetValue(name, colorControl->b);
 		}
 	}
 
-	colorControl->update(LLWLParamManager::instance()->mCurParams);
+	colorControl->update(LLWLParamManager::getInstance()->mCurParams);
 
-	LLWLParamManager::instance()->propagateParameters();
+	LLWLParamManager::getInstance()->propagateParameters();
 }
 
-void LLFloaterWindLight::onColorControlIMoved(LLUICtrl* ctrl, WLColorControl* colorControl)
+void LLFloaterWindLight::onColorControlIMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
 
 	colorControl->i = sldrCtrl->getValueF32();
 	
@@ -565,84 +672,100 @@ void LLFloaterWindLight::onColorControlIMoved(LLUICtrl* ctrl, WLColorControl* co
 		// divide sun color vals by three
 		if(colorControl->isSunOrAmbientColor) 
 		{
-			getChild<LLUICtrl>(rName)->setValue(colorControl->r/3);
-			getChild<LLUICtrl>(gName)->setValue(colorControl->g/3);
-			getChild<LLUICtrl>(bName)->setValue(colorControl->b/3);	
+			sWindLight->childSetValue(rName, colorControl->r/3);
+			sWindLight->childSetValue(gName, colorControl->g/3);
+			sWindLight->childSetValue(bName, colorControl->b/3);	
 		
 		} 
 		else if(colorControl->isBlueHorizonOrDensity) 
 		{
-			getChild<LLUICtrl>(rName)->setValue(colorControl->r/2);
-			getChild<LLUICtrl>(gName)->setValue(colorControl->g/2);
-			getChild<LLUICtrl>(bName)->setValue(colorControl->b/2);	
+			sWindLight->childSetValue(rName, colorControl->r/2);
+			sWindLight->childSetValue(gName, colorControl->g/2);
+			sWindLight->childSetValue(bName, colorControl->b/2);	
 		
 		} 
 		else 
 		{
 			// set the sliders to the new vals
-			getChild<LLUICtrl>(rName)->setValue(colorControl->r);
-			getChild<LLUICtrl>(gName)->setValue(colorControl->g);
-			getChild<LLUICtrl>(bName)->setValue(colorControl->b);
+			sWindLight->childSetValue(rName, colorControl->r);
+			sWindLight->childSetValue(gName, colorControl->g);
+			sWindLight->childSetValue(bName, colorControl->b);
 		}
 	}
 
 	// now update the current parameters and send them to shaders
-	colorControl->update(LLWLParamManager::instance()->mCurParams);
-	LLWLParamManager::instance()->propagateParameters();
+	colorControl->update(LLWLParamManager::getInstance()->mCurParams);
+	LLWLParamManager::getInstance()->propagateParameters();
 }
 
 /// GLOW SPECIFIC CODE
-void LLFloaterWindLight::onGlowRMoved(LLUICtrl* ctrl, WLColorControl* colorControl)
+void LLFloaterWindLight::onGlowRMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
 
 	// scaled by 20
 	colorControl->r = (2 - sldrCtrl->getValueF32()) * 20;
 
-	colorControl->update(LLWLParamManager::instance()->mCurParams);
-	LLWLParamManager::instance()->propagateParameters();
+	colorControl->update(LLWLParamManager::getInstance()->mCurParams);
+	LLWLParamManager::getInstance()->propagateParameters();
 }
 
 /// \NOTE that we want NEGATIVE (-) B
-void LLFloaterWindLight::onGlowBMoved(LLUICtrl* ctrl, WLColorControl* colorControl)
+void LLFloaterWindLight::onGlowBMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
 
 	/// \NOTE that we want NEGATIVE (-) B and NOT by 20 as 20 is too big
 	colorControl->b = -sldrCtrl->getValueF32() * 5;
 
-	colorControl->update(LLWLParamManager::instance()->mCurParams);
-	LLWLParamManager::instance()->propagateParameters();
+	colorControl->update(LLWLParamManager::getInstance()->mCurParams);
+	LLWLParamManager::getInstance()->propagateParameters();
 }
 
-void LLFloaterWindLight::onFloatControlMoved(LLUICtrl* ctrl, WLFloatControl* floatControl)
+void LLFloaterWindLight::onFloatControlMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	WLFloatControl * floatControl = static_cast<WLFloatControl *>(userData);
 
 	floatControl->x = sldrCtrl->getValueF32() / floatControl->mult;
 
-	floatControl->update(LLWLParamManager::instance()->mCurParams);
-	LLWLParamManager::instance()->propagateParameters();
+	floatControl->update(LLWLParamManager::getInstance()->mCurParams);
+	LLWLParamManager::getInstance()->propagateParameters();
+}
+
+void LLFloaterWindLight::onBoolToggle(LLUICtrl* ctrl, void* userData)
+{
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
+
+	LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl);
+
+	bool value = cbCtrl->get();
+	(*(static_cast<BOOL *>(userData))) = value;
 }
 
+
 // Lighting callbacks
 
 // time of day
-void LLFloaterWindLight::onSunMoved(LLUICtrl* ctrl, WLColorControl* colorControl)
+void LLFloaterWindLight::onSunMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
-	LLSliderCtrl* sunSldr = getChild<LLSliderCtrl>("WLSunAngle");
-	LLSliderCtrl* eastSldr = getChild<LLSliderCtrl>("WLEastAngle");
+	LLSliderCtrl* sunSldr = sWindLight->getChild<LLSliderCtrl>("WLSunAngle");
+	LLSliderCtrl* eastSldr = sWindLight->getChild<LLSliderCtrl>("WLEastAngle");
 
+	WLColorControl * colorControl = static_cast<WLColorControl *>(userData);
+	
 	// get the two angles
-	LLWLParamManager * param_mgr = LLWLParamManager::instance();
+	LLWLParamManager * param_mgr = LLWLParamManager::getInstance();
 
 	param_mgr->mCurParams.setSunAngle(F_TWO_PI * sunSldr->getValueF32());
 	param_mgr->mCurParams.setEastAngle(F_TWO_PI * eastSldr->getValueF32());
@@ -659,24 +782,35 @@ void LLFloaterWindLight::onSunMoved(LLUICtrl* ctrl, WLColorControl* colorControl
 	param_mgr->propagateParameters();
 }
 
-void LLFloaterWindLight::onStarAlphaMoved(LLUICtrl* ctrl)
+void LLFloaterWindLight::onFloatTweakMoved(LLUICtrl* ctrl, void* userData)
+{
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
+
+	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
+	F32 * tweak = static_cast<F32 *>(userData);
+
+	(*tweak) = sldrCtrl->getValueF32();
+	LLWLParamManager::getInstance()->propagateParameters();
+}
+
+void LLFloaterWindLight::onStarAlphaMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
 
-	LLWLParamManager::instance()->mCurParams.setStarBrightness(sldrCtrl->getValueF32());
+	LLWLParamManager::getInstance()->mCurParams.setStarBrightness(sldrCtrl->getValueF32());
 }
 
-void LLFloaterWindLight::onNewPreset()
+void LLFloaterWindLight::onNewPreset(void* userData)
 {
-	LLNotificationsUtil::add("NewSkyPreset", LLSD(), LLSD(), boost::bind(&LLFloaterWindLight::newPromptCallback, this, _1, _2));
+	LLNotifications::instance().add("NewSkyPreset", LLSD(), LLSD(), newPromptCallback);
 }
 
-void LLFloaterWindLight::onSavePreset()
+void LLFloaterWindLight::onSavePreset(void* userData)
 {
 	// get the name
-	LLComboBox* comboBox = getChild<LLComboBox>( 
+	LLComboBox* comboBox = sWindLight->getChild<LLComboBox>( 
 		"WLPresetsCombo");
 
 	// don't save the empty name
@@ -686,90 +820,98 @@ void LLFloaterWindLight::onSavePreset()
 	}
 
 	// check to see if it's a default and shouldn't be overwritten
-	std::set<std::string>::iterator sIt = sDefaultPresets.find(
-		comboBox->getSelectedItemLabel());
+	std::set<LLWLParamKey>::iterator sIt = sDefaultPresets.find(
+		LLWLParamKey(comboBox->getSelectedValue()));
 	if(sIt != sDefaultPresets.end() && !gSavedSettings.getBOOL("SkyEditPresets")) 
 	{
-		LLNotificationsUtil::add("WLNoEditDefault");
+		LLNotifications::instance().add("WLNoEditDefault");
 		return;
 	}
 
-	LLWLParamManager::instance()->mCurParams.mName = 
+	LLWLParamManager::getInstance()->mCurParams.mName = 
 		comboBox->getSelectedItemLabel();
 
-	LLNotificationsUtil::add("WLSavePresetAlert", LLSD(), LLSD(), boost::bind(&LLFloaterWindLight::saveAlertCallback, this, _1, _2));
+	LLNotifications::instance().add("WLSavePresetAlert", LLSD(), LLSD(), saveAlertCallback);
 }
 
 bool LLFloaterWindLight::saveAlertCallback(const LLSD& notification, const LLSD& response)
 {
-	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+	S32 option = LLNotification::getSelectedOption(notification, response);
 	// if they choose save, do it.  Otherwise, don't do anything
 	if(option == 0) 
 	{
-		LLWLParamManager * param_mgr = LLWLParamManager::instance();
+		LLWLParamManager * param_mgr = LLWLParamManager::getInstance();
+
+		// we should only "save" local presets; those with other scopes should be "save as"
+		LLWLParamKey key(param_mgr->mCurParams.mName, LLEnvKey::SCOPE_LOCAL);
 
-		param_mgr->setParamSet(param_mgr->mCurParams.mName, param_mgr->mCurParams);
+		param_mgr->setParamSet(key, param_mgr->mCurParams);
 		
 		// comment this back in to save to file
-		param_mgr->savePreset(param_mgr->mCurParams.mName);
+		param_mgr->savePreset(key);
 	}
 	return false;
 }
 
-void LLFloaterWindLight::onDeletePreset()
+void LLFloaterWindLight::onDeletePreset(void* userData)
 {
-	LLComboBox* combo_box = getChild<LLComboBox>( 
+	LLComboBox* combo_box = sWindLight->getChild<LLComboBox>( 
 		"WLPresetsCombo");
 
-	if(combo_box->getSelectedValue().asString() == "")
+	if(combo_box->getSelectedValue().isUndefined())
 	{
 		return;
 	}
 
 	LLSD args;
-	args["SKY"] = combo_box->getSelectedValue().asString();
-	LLNotificationsUtil::add("WLDeletePresetAlert", args, LLSD(), 
-									boost::bind(&LLFloaterWindLight::deleteAlertCallback, this, _1, _2));
+	args["SKY"] = combo_box->getSelectedValue()[0].asString();
+	LLNotifications::instance().add("WLDeletePresetAlert", args, LLSD(), 
+									boost::bind(&LLFloaterWindLight::deleteAlertCallback, sWindLight, _1, _2));
 }
 
 bool LLFloaterWindLight::deleteAlertCallback(const LLSD& notification, const LLSD& response)
 {
-	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+	S32 option = LLNotification::getSelectedOption(notification, response);
 
 	// if they choose delete, do it.  Otherwise, don't do anything
 	if(option == 0) 
 	{
-		LLComboBox* combo_box = getChild<LLComboBox>("WLPresetsCombo");
-		LLFloaterDayCycle* day_cycle = LLFloaterReg::findTypedInstance<LLFloaterDayCycle>("env_day_cycle");
+		LLComboBox* combo_box = getChild<LLComboBox>( 
+			"WLPresetsCombo");
+		LLFloaterDayCycle* day_cycle = NULL;
 		LLComboBox* key_combo = NULL;
+		LLMultiSliderCtrl* mult_sldr = NULL;
 
-		if (day_cycle) 
+		if(LLFloaterDayCycle::isOpen()) 
 		{
-			key_combo = day_cycle->getChild<LLComboBox>("WLKeyPresets");
+			day_cycle = LLFloaterDayCycle::instance();
+			key_combo = day_cycle->getChild<LLComboBox>( 
+				"WLKeyPresets");
+			mult_sldr = day_cycle->getChild<LLMultiSliderCtrl>("WLDayCycleKeys");
 		}
 
-		std::string name(combo_box->getSelectedValue().asString());
+		LLWLParamKey key(combo_box->getSelectedValue());
 
 		// check to see if it's a default and shouldn't be deleted
-		std::set<std::string>::iterator sIt = sDefaultPresets.find(name);
+		std::set<LLWLParamKey>::iterator sIt = sDefaultPresets.find(key);
 		if(sIt != sDefaultPresets.end()) 
 		{
-			LLNotificationsUtil::add("WLNoEditDefault");
+			LLNotifications::instance().add("WLNoEditDefault");
 			return false;
 		}
 
-		LLWLParamManager::instance()->removeParamSet(name, true);
+		LLWLParamManager::getInstance()->removeParamSet(key, true);
 		
 		// remove and choose another
 		S32 new_index = combo_box->getCurrentIndex();
 
-		combo_box->remove(name);
+		combo_box->remove(key.toString());
 		if(key_combo != NULL) 
 		{
-			key_combo->remove(name);
+			key_combo->remove(key.toString());
 
 			// remove from slider, as well
-			day_cycle->deletePreset(name);
+			day_cycle->deletePreset(key);
 		}
 
 		// pick the previously selected index after delete
@@ -787,53 +929,56 @@ bool LLFloaterWindLight::deleteAlertCallback(const LLSD& notification, const LLS
 }
 
 
-void LLFloaterWindLight::onChangePresetName(LLUICtrl* ctrl)
+void LLFloaterWindLight::onChangePresetName(LLUICtrl* ctrl, void * userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
-	std::string data = ctrl->getValue().asString();
-	if(!data.empty())
+	LLComboBox * combo_box = static_cast<LLComboBox*>(ctrl);
+	
+	if(combo_box->getSimple() == "")
 	{
-		LLWLParamManager::instance()->loadPreset( data);
-		syncMenu();
+		return;
 	}
+	
+	LLWLParamManager::getInstance()->loadPreset(LLWLParamKey(combo_box->getSelectedValue()));
+	sWindLight->syncMenu();
 }
 
-void LLFloaterWindLight::onOpenDayCycle()
+void LLFloaterWindLight::onOpenDayCycle(void* userData)
 {
-	LLFloaterReg::showInstance("env_day_cycle");
+	LLFloaterDayCycle::show(sScope);
 }
 
 // Clouds
-void LLFloaterWindLight::onCloudScrollXMoved(LLUICtrl* ctrl)
+void LLFloaterWindLight::onCloudScrollXMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
 	// *HACK  all cloud scrolling is off by an additive of 10. 
-	LLWLParamManager::instance()->mCurParams.setCloudScrollX(sldrCtrl->getValueF32() + 10.0f);
+	LLWLParamManager::getInstance()->mCurParams.setCloudScrollX(sldrCtrl->getValueF32() + 10.0f);
 }
 
-void LLFloaterWindLight::onCloudScrollYMoved(LLUICtrl* ctrl)
+void LLFloaterWindLight::onCloudScrollYMoved(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
 
 	// *HACK  all cloud scrolling is off by an additive of 10. 
-	LLWLParamManager::instance()->mCurParams.setCloudScrollY(sldrCtrl->getValueF32() + 10.0f);
+	LLWLParamManager::getInstance()->mCurParams.setCloudScrollY(sldrCtrl->getValueF32() + 10.0f);
 }
 
-void LLFloaterWindLight::onCloudScrollXToggled(LLUICtrl* ctrl)
+void LLFloaterWindLight::onCloudScrollXToggled(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl);
 
 	bool lock = cbCtrl->get();
-	LLWLParamManager::instance()->mCurParams.setEnableCloudScrollX(!lock);
+	LLWLParamManager::getInstance()->mCurParams.setEnableCloudScrollX(!lock);
 
-	LLSliderCtrl* sldr = getChild<LLSliderCtrl>( 
+	LLSliderCtrl* sldr = sWindLight->getChild<LLSliderCtrl>( 
 		"WLCloudScrollX");
 
 	if(cbCtrl->get()) 
@@ -847,15 +992,15 @@ void LLFloaterWindLight::onCloudScrollXToggled(LLUICtrl* ctrl)
 
 }
 
-void LLFloaterWindLight::onCloudScrollYToggled(LLUICtrl* ctrl)
+void LLFloaterWindLight::onCloudScrollYToggled(LLUICtrl* ctrl, void* userData)
 {
-	deactivateAnimator();
+	LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 	LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl);
 	bool lock = cbCtrl->get();
-	LLWLParamManager::instance()->mCurParams.setEnableCloudScrollY(!lock);
+	LLWLParamManager::getInstance()->mCurParams.setEnableCloudScrollY(!lock);
 
-	LLSliderCtrl* sldr = getChild<LLSliderCtrl>( 
+	LLSliderCtrl* sldr = sWindLight->getChild<LLSliderCtrl>( 
 		"WLCloudScrollY");
 
 	if(cbCtrl->get()) 
@@ -867,9 +1012,3 @@ void LLFloaterWindLight::onCloudScrollYToggled(LLUICtrl* ctrl)
 		sldr->setEnabled(true);
 	}
 }
-
-void LLFloaterWindLight::deactivateAnimator()
-{
-	LLWLParamManager::instance()->mAnimator.mIsRunning = false;
-	LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
-}
diff --git a/indra/newview/llfloaterwindlight.h b/indra/newview/llfloaterwindlight.h
index b43edc2c11e8813a0ce9b43193c1148189b17e94..c0fea2558ccbe7a7a2205e74c4d50c459975d9b6 100644
--- a/indra/newview/llfloaterwindlight.h
+++ b/indra/newview/llfloaterwindlight.h
@@ -2,25 +2,31 @@
  * @file llfloaterwindlight.h
  * @brief LLFloaterWindLight class definition
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
  * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
 
@@ -35,77 +41,98 @@
 
 #include <vector>
 #include "llwlparamset.h"
+#include "llwlparammanager.h"
 
 struct WLColorControl;
 struct WLFloatControl;
 
-
 /// Menuing system for all of windlight's functionality
 class LLFloaterWindLight : public LLFloater
 {
 public:
-
-	LLFloaterWindLight(const LLSD& key);
+	LLFloaterWindLight();
 	virtual ~LLFloaterWindLight();
-	/*virtual*/	BOOL	postBuild();	
+	
 	/// initialize all
 	void initCallbacks(void);
 
-	bool newPromptCallback(const LLSD& notification, const LLSD& response);
+	/// one and one instance only
+	static LLFloaterWindLight* instance();
+
+	// help button stuff
+	static void onClickHelp(void* data);
+	void initHelpBtn(const std::string& name, const std::string& xml_alert);
+
+	static bool newPromptCallback(const LLSD& notification, const LLSD& response);
 
 	/// general purpose callbacks for dealing with color controllers
-	void onColorControlRMoved(LLUICtrl* ctrl, WLColorControl* userData);
-	void onColorControlGMoved(LLUICtrl* ctrl, WLColorControl* userData);
-	void onColorControlBMoved(LLUICtrl* ctrl, WLColorControl* userData);
-	void onColorControlIMoved(LLUICtrl* ctrl, WLColorControl* userData);
-	void onFloatControlMoved(LLUICtrl* ctrl, WLFloatControl* userData);
+	static void onColorControlRMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlGMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlBMoved(LLUICtrl* ctrl, void* userData);
+	static void onColorControlIMoved(LLUICtrl* ctrl, void* userData);
+	static void onFloatControlMoved(LLUICtrl* ctrl, void* userData);
+	static void onBoolToggle(LLUICtrl* ctrl, void* userData);
 
 	/// lighting callbacks for glow
-	void onGlowRMoved(LLUICtrl* ctrl, WLColorControl* userData);
+	static void onGlowRMoved(LLUICtrl* ctrl, void* userData);
 	//static void onGlowGMoved(LLUICtrl* ctrl, void* userData);
-	void onGlowBMoved(LLUICtrl* ctrl, WLColorControl* userData);
+	static void onGlowBMoved(LLUICtrl* ctrl, void* userData);
 
 	/// lighting callbacks for sun
-	void onSunMoved(LLUICtrl* ctrl, WLColorControl* userData);
+	static void onSunMoved(LLUICtrl* ctrl, void* userData);
+
+	/// handle if float is changed
+	static void onFloatTweakMoved(LLUICtrl* ctrl, void* userData);
 
 	/// for handling when the star slider is moved to adjust the alpha
-	void onStarAlphaMoved(LLUICtrl* ctrl);
+	static void onStarAlphaMoved(LLUICtrl* ctrl, void* userData);
 
 	/// when user hits the load preset button
-	void onNewPreset();
+	static void onNewPreset(void* userData);
 
 	/// when user hits the save preset button
-	void onSavePreset();
+	static void onSavePreset(void* userData);
 
 	/// prompts a user when overwriting a preset
-	bool saveAlertCallback(const LLSD& notification, const LLSD& response);
+	static bool saveAlertCallback(const LLSD& notification, const LLSD& response);
 
 	/// when user hits the save preset button
-	void onDeletePreset();
+	static void onDeletePreset(void* userData);
 
 	/// prompts a user when overwriting a preset
 	bool deleteAlertCallback(const LLSD& notification, const LLSD& response);
 
 	/// what to do when you change the preset name
-	void onChangePresetName(LLUICtrl* ctrl);
+	static void onChangePresetName(LLUICtrl* ctrl, void* userData);
 
 	/// when user hits the save preset button
-	void onOpenDayCycle();
+	static void onOpenDayCycle(void* userData);
 
 	/// handle cloud scrolling
-	void onCloudScrollXMoved(LLUICtrl* ctrl);
-	void onCloudScrollYMoved(LLUICtrl* ctrl);
-	void onCloudScrollXToggled(LLUICtrl* ctrl);
-	void onCloudScrollYToggled(LLUICtrl* ctrl);
+	static void onCloudScrollXMoved(LLUICtrl* ctrl, void* userData);
+	static void onCloudScrollYMoved(LLUICtrl* ctrl, void* userData);
+	static void onCloudScrollXToggled(LLUICtrl* ctrl, void* userData);
+	static void onCloudScrollYToggled(LLUICtrl* ctrl, void* userData);
+
+	//// menu management
+
+	/// show off our menu
+	static void show(LLEnvKey::EScope scope = LLEnvKey::SCOPE_LOCAL);
+
+	/// return if the menu exists or not
+	static bool isOpen();
+
+	/// stuff to do on exit
+	virtual void onClose(bool app_quitting);
 
 	/// sync up sliders with parameters
 	void syncMenu();
 
-	/// turn off animated skies
-	static void deactivateAnimator();
-
 private:
-	static std::set<std::string> sDefaultPresets;
+	static LLFloaterWindLight* sWindLight;	// one instance on the inside
+	static std::set<LLWLParamKey> sDefaultPresets;
+	static LLEnvKey::EScope sScope;
+	static std::string sOriginalTitle;
 };
 
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index c56cacd12ba6c71139f15b2e522e4b554e3cdb28..7fa78ab386ec3dc0062044014de33f19ffa2f498 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1153,8 +1153,6 @@ bool idle_startup()
 
 		// init the shader managers
 		LLPostProcess::initClass();
-		LLWLParamManager::initClass();
-		LLWaterParamManager::initClass();
 
 		LLViewerObject::initVOClasses();
 
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 916cbe226774b842ebbd803aa33b431263df062f..5b0cf72ac51a3eb59d3b01001ccc9de70afe6823 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -178,8 +178,8 @@ void display_update_camera()
 	gViewerWindow->setup3DRender();
 	
 	// update all the sky/atmospheric/water settings
-	LLWLParamManager::instance()->update(LLViewerCamera::getInstance());
-	LLWaterParamManager::instance()->update(LLViewerCamera::getInstance());
+	LLWLParamManager::getInstance()->update(LLViewerCamera::getInstance());
+	LLWaterParamManager::getInstance()->update(LLViewerCamera::getInstance());
 
 	// Update land visibility too
 	LLWorld::getInstance()->setLandFarClip(final_far);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index d4af5048c3461c0ac26aaf876ec90388da69f074..614eb6ed881027d3482a9948fa691e1fb2d073a7 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7628,55 +7628,56 @@ class LLWorldEnvSettings : public view_listener_t
 			LLFloaterReg::toggleInstance("env_settings");
 			return true;
 		}
-		
+		else if(gSavedSettings.getBOOL("UseEnvironmentFromRegion"))
+		{
+			LLNotifications::instance().add("EnvLockedUsingRegion", LLSD());
+		}
+		else
+		{
 		if (tod == "sunrise")
 		{
 			// set the value, turn off animation
-			LLWLParamManager::instance()->mAnimator.setDayTime(0.25);
-			LLWLParamManager::instance()->mAnimator.mIsRunning = false;
-			LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+				LLWLParamManager::getInstance()->mAnimator.setDayTime(0.25);
+				LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 			// then call update once
-			LLWLParamManager::instance()->mAnimator.update(
-				LLWLParamManager::instance()->mCurParams);
+				LLWLParamManager::getInstance()->mAnimator.update(
+					LLWLParamManager::getInstance()->mCurParams);
 		}
 		else if (tod == "noon")
 		{
 			// set the value, turn off animation
-			LLWLParamManager::instance()->mAnimator.setDayTime(0.567);
-			LLWLParamManager::instance()->mAnimator.mIsRunning = false;
-			LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+				LLWLParamManager::getInstance()->mAnimator.setDayTime(0.567);
+				LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 			// then call update once
-			LLWLParamManager::instance()->mAnimator.update(
-				LLWLParamManager::instance()->mCurParams);
+				LLWLParamManager::getInstance()->mAnimator.update(
+					LLWLParamManager::getInstance()->mCurParams);
 		}
 		else if (tod == "sunset")
 		{
 			// set the value, turn off animation
-			LLWLParamManager::instance()->mAnimator.setDayTime(0.75);
-			LLWLParamManager::instance()->mAnimator.mIsRunning = false;
-			LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+				LLWLParamManager::getInstance()->mAnimator.setDayTime(0.75);
+				LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 			// then call update once
-			LLWLParamManager::instance()->mAnimator.update(
-				LLWLParamManager::instance()->mCurParams);
+				LLWLParamManager::getInstance()->mAnimator.update(
+					LLWLParamManager::getInstance()->mCurParams);
 		}
 		else if (tod == "midnight")
 		{
 			// set the value, turn off animation
-			LLWLParamManager::instance()->mAnimator.setDayTime(0.0);
-			LLWLParamManager::instance()->mAnimator.mIsRunning = false;
-			LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+				LLWLParamManager::getInstance()->mAnimator.setDayTime(0.0);
+				LLWLParamManager::getInstance()->mAnimator.deactivate();
 
 			// then call update once
-			LLWLParamManager::instance()->mAnimator.update(
-				LLWLParamManager::instance()->mCurParams);
+				LLWLParamManager::getInstance()->mAnimator.update(
+					LLWLParamManager::getInstance()->mCurParams);
 		}
 		else
 		{
-			LLWLParamManager::instance()->mAnimator.mIsRunning = true;
-			LLWLParamManager::instance()->mAnimator.mUseLindenTime = true;	
+				LLWLParamManager::getInstance()->mAnimator.activate(LLWLAnimator::TIME_LINDEN);
+			}
 		}
 		return true;
 	}
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 98f16757b2b49a4c6d2819398b634ce62a9340cb..0ed254bbc5843dafe1bcb777962be4066147e399 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1365,6 +1365,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("DispatchRegionInfo");
 	capabilityNames.append("EstateChangeInfo");
 	capabilityNames.append("EventQueueGet");
+	capabilityNames.append("EnvironmentSettings");
 	capabilityNames.append("FetchInventory");
 	capabilityNames.append("ObjectMedia");
 	capabilityNames.append("ObjectMediaNavigate");
@@ -1494,3 +1495,8 @@ std::string LLViewerRegion::getDescription() const
 {
     return stringize(*this);
 }
+
+std::string LLViewerRegion::getDescription() const
+{
+    return stringize(*this);
+}
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 038c831e59dd1b9b6cfa9091573f4d02f5d8591f..307e2cf3a27e75de730089ca4e12ab48a440b69c 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -405,6 +405,11 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
     /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
     LLCapabilityListener mCapabilityListener;
 
+	/// Post an event to this LLCapabilityListener to invoke a capability message on
+	/// this LLViewerRegion's server
+	/// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
+	LLCapabilityListener mCapabilityListener;
+
 private:
 	bool	mAlive;					// can become false if circuit disconnects
 
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index d078c153160eabfa54a62f52213620296b4a1495..fa30c1ae9edd8b680a40dd4b05a00409f13549e1 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -1492,6 +1492,16 @@ std::string LLViewerShaderMgr::getShaderDirPrefix(void)
 
 void LLViewerShaderMgr::updateShaderUniforms(LLGLSLShader * shader)
 {
-	LLWLParamManager::instance()->updateShaderUniforms(shader);
-	LLWaterParamManager::instance()->updateShaderUniforms(shader);
+	LLWLParamManager::getInstance()->updateShaderUniforms(shader);
+	LLWaterParamManager::getInstance()->updateShaderUniforms(shader);
+}
+
+LLViewerShaderMgr::shader_iter LLViewerShaderMgr::beginShaders() const
+{
+	return mShaderList.begin();
+}
+
+LLViewerShaderMgr::shader_iter LLViewerShaderMgr::endShaders() const
+{
+	return mShaderList.end();
 }
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index db880fded6ff5dce412325f67af363d3165c6c67..e958cf1172670c36a35d942c7950882dd15af6cd 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -240,20 +240,12 @@ class LLViewerShaderMgr: public LLShaderMgr
 		base_iter_t mIter;
 	};
 
-	shader_iter beginShaders() const
-	{
-		return mShaderList.begin();
-	}
-
-	shader_iter endShaders() const
-	{
-		return mShaderList.end();
-	}
-
+	shader_iter beginShaders() const;
+	shader_iter endShaders() const;
 
-	/* virtual */ std::string getShaderDirPrefix(void); // Virtual
+	/* virtual */ std::string getShaderDirPrefix(void);
 
-	/* virtual */ void updateShaderUniforms(LLGLSLShader * shader); // Virtual
+	/* virtual */ void updateShaderUniforms(LLGLSLShader * shader);
 
 private:
 	
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 7ae8c2c07d93c8cff8ea54f5c4110dd02385e5e2..a6465f1c4f24d8e8626e9b15b5ec8977a996f8d9 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -356,7 +356,7 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	mAtmHeight = ATM_HEIGHT;
 	mEarthCenter = LLVector3(mCameraPosAgent.mV[0], mCameraPosAgent.mV[1], -EARTH_RADIUS);
 
-	mSunDefaultPosition = LLVector3(LLWLParamManager::instance()->mCurParams.getVector("lightnorm", error));
+	mSunDefaultPosition = LLVector3(LLWLParamManager::getInstance()->mCurParams.getVector("lightnorm", error));
 	if (gSavedSettings.getBOOL("SkyOverrideSimSunPosition"))
 	{
 		initSunDirection(mSunDefaultPosition, LLVector3(0, 0, 0));
@@ -638,24 +638,24 @@ void LLVOSky::initAtmospherics(void)
 	bool error;
 	
 	// uniform parameters for convenience
-	dome_radius = LLWLParamManager::instance()->getDomeRadius();
-	dome_offset_ratio = LLWLParamManager::instance()->getDomeOffset();
-	sunlight_color = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("sunlight_color", error));
-	ambient = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("ambient", error));
-	//lightnorm = LLWLParamManager::instance()->mCurParams.getVector("lightnorm", error);
-	gamma = LLWLParamManager::instance()->mCurParams.getVector("gamma", error)[0];
-	blue_density = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("blue_density", error));
-	blue_horizon = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("blue_horizon", error));
-	haze_density = LLWLParamManager::instance()->mCurParams.getVector("haze_density", error)[0];
-	haze_horizon = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("haze_horizon", error));
-	density_multiplier = LLWLParamManager::instance()->mCurParams.getVector("density_multiplier", error)[0];
-	max_y = LLWLParamManager::instance()->mCurParams.getVector("max_y", error)[0];
-	glow = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("glow", error));
-	cloud_shadow = LLWLParamManager::instance()->mCurParams.getVector("cloud_shadow", error)[0];
-	cloud_color = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("cloud_color", error));
-	cloud_scale = LLWLParamManager::instance()->mCurParams.getVector("cloud_scale", error)[0];
-	cloud_pos_density1 = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("cloud_pos_density1", error));
-	cloud_pos_density2 = LLColor3(LLWLParamManager::instance()->mCurParams.getVector("cloud_pos_density2", error));
+	dome_radius = LLWLParamManager::getInstance()->getDomeRadius();
+	dome_offset_ratio = LLWLParamManager::getInstance()->getDomeOffset();
+	sunlight_color = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("sunlight_color", error));
+	ambient = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("ambient", error));
+	//lightnorm = LLWLParamManager::getInstance()->mCurParams.getVector("lightnorm", error);
+	gamma = LLWLParamManager::getInstance()->mCurParams.getVector("gamma", error)[0];
+	blue_density = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("blue_density", error));
+	blue_horizon = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("blue_horizon", error));
+	haze_density = LLWLParamManager::getInstance()->mCurParams.getVector("haze_density", error)[0];
+	haze_horizon = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("haze_horizon", error));
+	density_multiplier = LLWLParamManager::getInstance()->mCurParams.getVector("density_multiplier", error)[0];
+	max_y = LLWLParamManager::getInstance()->mCurParams.getVector("max_y", error)[0];
+	glow = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("glow", error));
+	cloud_shadow = LLWLParamManager::getInstance()->mCurParams.getVector("cloud_shadow", error)[0];
+	cloud_color = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("cloud_color", error));
+	cloud_scale = LLWLParamManager::getInstance()->mCurParams.getVector("cloud_scale", error)[0];
+	cloud_pos_density1 = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("cloud_pos_density1", error));
+	cloud_pos_density2 = LLColor3(LLWLParamManager::getInstance()->mCurParams.getVector("cloud_pos_density2", error));
 
 	// light norm is different.  We need the sun's direction, not the light direction
 	// which could be from the moon.  And we need to clamp it
@@ -1025,7 +1025,7 @@ void LLVOSky::calcAtmospherics(void)
 	// Since WL scales everything by 2, there should always be at least a 2:1 brightness ratio
 	// between sunlight and point lights in windlight to normalize point lights.
 	F32 sun_dynamic_range = llmax(gSavedSettings.getF32("RenderSunDynamicRange"), 0.0001f);
-	LLWLParamManager::instance()->mSceneLightStrength = 2.0f * (1.0f + sun_dynamic_range * dp);
+	LLWLParamManager::getInstance()->mSceneLightStrength = 2.0f * (1.0f + sun_dynamic_range * dp);
 
 	mSunDiffuse = vary_SunlightColor;
 	mSunAmbient = vary_AmbientColor;
@@ -2115,7 +2115,7 @@ void LLVOSky::updateFog(const F32 distance)
 		F32 depth = water_height - camera_height;
 		
 		// get the water param manager variables
-		float water_fog_density = LLWaterParamManager::instance()->getFogDensity();
+		float water_fog_density = LLWaterParamManager::getInstance()->getFogDensity();
 		LLColor4 water_fog_color = LLDrawPoolWater::sWaterFogColor.mV;
 		
 		// adjust the color based on depth.  We're doing linear approximations
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
index ca57c0144ba4616adf9cd2fd9b1fc28278da8d89..5cb61b87340111d302ded7cfaf3abb6aaacf1f02 100644
--- a/indra/newview/llvowlsky.cpp
+++ b/indra/newview/llvowlsky.cpp
@@ -568,7 +568,7 @@ void LLVOWLSky::buildFanBuffer(LLStrider<LLVector3> & vertices,
 							   LLStrider<LLVector2> & texCoords,
 							   LLStrider<U16> & indices)
 {
-	const F32 RADIUS = LLWLParamManager::instance()->getDomeRadius();
+	const F32 RADIUS = LLWLParamManager::getInstance()->getDomeRadius();
 
 	U32 i, num_slices;
 	F32 phi0, theta, x0, y0, z0;
@@ -629,7 +629,7 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, U32 end_stack,
 								  LLStrider<LLVector2> & texCoords,
 								  LLStrider<U16> & indices)
 {
-	const F32 RADIUS = LLWLParamManager::instance()->getDomeRadius();
+	const F32 RADIUS = LLWLParamManager::getInstance()->getDomeRadius();
 
 	U32 i, j, num_slices, num_stacks;
 	F32 phi0, theta, x0, y0, z0;
diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp
index 7314894c2eed659accf20e791cbdb5a46d2e1d6f..c9849383032a824d095c013efa1151ddf27c0cf6 100644
--- a/indra/newview/llwaterparammanager.cpp
+++ b/indra/newview/llwaterparammanager.cpp
@@ -57,8 +57,6 @@
 
 #include "curl/curl.h"
 
-LLWaterParamManager * LLWaterParamManager::sInstance = NULL;
-
 LLWaterParamManager::LLWaterParamManager() :
 	mFogColor(22.f/255.f, 43.f/255.f, 54.f/255.f, 0.0f, 0.0f, "waterFogColor", "WaterFogColor"),
 	mFogDensity(4, "waterFogDensity", 2),
@@ -246,7 +244,7 @@ void LLWaterParamManager::updateShaderUniforms(LLGLSLShader * shader)
 {
 	if (shader->mShaderGroup == LLGLSLShader::SG_WATER)
 	{
-		shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, LLWLParamManager::instance()->getRotatedLightDir().mV);
+		shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, LLWLParamManager::getInstance()->getRotatedLightDir().mV);
 		shader->uniform3fv("camPosLocal", 1, LLViewerCamera::getInstance()->getOrigin().mV);
 		shader->uniform4fv("waterFogColor", 1, LLDrawPoolWater::sWaterFogColor.mV);
 		shader->uniform4fv("waterPlane", 1, mWaterPlane.mV);
@@ -320,19 +318,6 @@ void LLWaterParamManager::update(LLViewerCamera * cam)
 	}
 }
 
-// static
-void LLWaterParamManager::initClass(void)
-{
-	instance();
-}
-
-// static
-void LLWaterParamManager::cleanupClass(void)
-{
-	delete sInstance;
-	sInstance = NULL;
-}
-
 bool LLWaterParamManager::addParamSet(const std::string& name, LLWaterParamSet& param)
 {
 	// add a new one if not one there already
@@ -439,17 +424,9 @@ F32 LLWaterParamManager::getFogDensity(void)
 	return fogDensity;
 }
 
-// static
-LLWaterParamManager * LLWaterParamManager::instance()
+// virtual static
+void LLWaterParamManager::initSingleton()
 {
-	if(NULL == sInstance)
-	{
-		sInstance = new LLWaterParamManager();
-
-		sInstance->loadAllPresets(LLStringUtil::null);
-
-		sInstance->getParamSet("Default", sInstance->mCurParams);
-	}
-
-	return sInstance;
+	loadAllPresets(LLStringUtil::null);
+	getParamSet("Default", mCurParams);
 }
diff --git a/indra/newview/llwaterparammanager.h b/indra/newview/llwaterparammanager.h
index c479f1861cc644a0e0c80584a22955dbfb007acd..d5919bbf68105b3c380785b1008000456f6a6a5d 100644
--- a/indra/newview/llwaterparammanager.h
+++ b/indra/newview/llwaterparammanager.h
@@ -212,13 +212,10 @@ struct WaterExpFloatControl
 
 
 /// WindLight parameter manager class - what controls all the wind light shaders
-class LLWaterParamManager
+class LLWaterParamManager : public LLSingleton<LLWaterParamManager>
 {
 public:
 
-	LLWaterParamManager();
-	~LLWaterParamManager();
-
 	/// load a preset file
 	void loadAllPresets(const std::string & fileName);
 
@@ -238,9 +235,6 @@ class LLWaterParamManager
 	/// Update shader uniforms that have changed.
 	void updateShaderUniforms(LLGLSLShader * shader);
 
-	/// Perform global initialization for this class.
-	static void initClass(void);
-
 	// Cleanup of global data that's only inited once per class.
 	static void cleanupClass();
 
@@ -281,9 +275,6 @@ class LLWaterParamManager
 	F32 getFogDensity(void);
 	LLColor4 getFogColor(void);
 
-	// singleton pattern implementation
-	static LLWaterParamManager * instance();
-
 public:
 
 	LLWaterParamSet mCurParams;
@@ -311,11 +302,13 @@ class LLWaterParamManager
 	F32 mDensitySliderValue;
 
 private:
+	friend class LLSingleton<LLWaterParamManager>;
+	/*virtual*/ void initSingleton();
+	LLWaterParamManager();
+	~LLWaterParamManager();
+
 	LLVector4 mWaterPlane;
 	F32 mWaterFogKS;
-
-	// our parameter manager singleton instance
-	static LLWaterParamManager * sInstance;
 };
 
 inline void LLWaterParamManager::setDensitySliderValue(F32 val)
diff --git a/indra/newview/llwaterparamset.cpp b/indra/newview/llwaterparamset.cpp
index 9457d631be759b82672523206f21770a5d7271c5..488b189e94116a60046fd20996f4b5c02a27bb52 100644
--- a/indra/newview/llwaterparamset.cpp
+++ b/indra/newview/llwaterparamset.cpp
@@ -224,3 +224,46 @@ F32 LLWaterParamSet::getFloat(const std::string& paramName, bool& error)
 	return 0;
 }
 
+// Added for interpolation effect in DEV-33645
+// Based on LLWLParamSet::mix, but written by Jacob without an intimate knowledge of how WindLight works.
+// The function definition existed in the header but was never implemented.  If you think there is something
+// wrong with this, you're probably right.  Ask Jacob, Q, or a member of the original WindLight team.
+void LLWaterParamSet::mix(LLWaterParamSet& src, LLWaterParamSet& dest, F32 weight)
+{
+	// Setup
+	LLSD srcVal, destVal;													// LLSD holders for get/set calls, reusable
+
+	// Iterate through values
+	for(LLSD::map_iterator iter = mParamValues.beginMap(); iter != mParamValues.endMap(); ++iter)
+	{
+		// If param exists in both src and dest, set the holder variables, otherwise skip
+		if(src.mParamValues.has(iter->first) && dest.mParamValues.has(iter->first))
+		{
+			srcVal = src.mParamValues[iter->first];
+			destVal = dest.mParamValues[iter->first];
+		}
+		else
+		{
+			continue;
+		}
+		
+		if(iter->second.isReal())									// If it's a real, interpolate directly
+		{
+			iter->second = srcVal.asReal() + ((destVal.asReal() - srcVal.asReal()) * weight);
+		}		
+		else if(iter->second.isArray() && iter->second[0].isReal()	// If it's an array of reals, loop through the reals and interpolate on those
+				&& iter->second.size() == srcVal.size() && iter->second.size() == destVal.size())
+		{
+			// Actually do interpolation: old value + (difference in values * factor)
+			for(int i=0; i < iter->second.size(); ++i) 
+			{
+				// iter->second[i] = (1.f-weight)*(F32)srcVal[i].asReal() + weight*(F32)destVal[i].asReal();	// old way of doing it -- equivalent but one more operation
+				iter->second[i] = srcVal[i].asReal() + ((destVal[i].asReal() - srcVal[i].asReal()) * weight);
+			}
+		}
+		else														// Else, skip
+		{
+			continue;
+		}
+	}
+}
diff --git a/indra/newview/llwlanimator.cpp b/indra/newview/llwlanimator.cpp
index a94a2e41aad960d4595610efdd0db8b09fae886a..2e249b970164393101445964105507a144fbf5ef 100644
--- a/indra/newview/llwlanimator.cpp
+++ b/indra/newview/llwlanimator.cpp
@@ -30,20 +30,31 @@
 #include "llsky.h"
 #include "pipeline.h"
 #include "llwlparammanager.h"
+#include "llwaterparammanager.h"
 
-LLWLAnimator::LLWLAnimator() : mStartTime(0), mDayRate(1), mDayTime(0),
-	mIsRunning(FALSE), mUseLindenTime(false)
+extern LLControlGroup gSavedSettings;
+
+F64 LLWLAnimator::INTERP_TOTAL_SECONDS = 3.f;
+
+LLWLAnimator::LLWLAnimator() : mStartTime(0.f), mDayRate(1.f), mDayTime(0.f),
+							mIsRunning(FALSE), mIsInterpolating(FALSE), mTimeType(TIME_LINDEN),
+							mInterpStartTime(), mInterpEndTime()
 {
-	mDayTime = 0;
+	mInterpBeginWL = new LLWLParamSet();
+	mInterpBeginWater = new LLWaterParamSet();
+	mInterpEndWater = new LLWaterParamSet();
 }
 
 void LLWLAnimator::update(LLWLParamSet& curParams)
 {
+	llassert(mUseLindenTime != mUseLocalTime);
+
 	F64 curTime;
 	curTime = getDayTime();
 
 	// don't do anything if empty
-	if(mTimeTrack.size() == 0) {
+	if(mTimeTrack.size() == 0)
+	{
 		return;
 	}
 
@@ -53,13 +64,15 @@ void LLWLAnimator::update(LLWLParamSet& curParams)
 	mSecondIt++;
 
 	// grab the two tween iterators
-	while(mSecondIt != mTimeTrack.end() && curTime > mSecondIt->first) {
+	while(mSecondIt != mTimeTrack.end() && curTime > mSecondIt->first)
+	{
 		mFirstIt++;
 		mSecondIt++;
 	}
 
 	// scroll it around when you get to the end
-	if(mSecondIt == mTimeTrack.end() || mFirstIt->first > curTime) {
+	if(mSecondIt == mTimeTrack.end() || mFirstIt->first > curTime)
+	{
 		mSecondIt = mTimeTrack.begin();
 		mFirstIt = mTimeTrack.end();
 		mFirstIt--;
@@ -67,70 +80,109 @@ void LLWLAnimator::update(LLWLParamSet& curParams)
 
 	F32 weight = 0;
 
-	if(mFirstIt->first < mSecondIt->first) {
+	if(mFirstIt->first < mSecondIt->first)
+	{
 	
 		// get the delta time and the proper weight
 		weight = F32 (curTime - mFirstIt->first) / 
 			(mSecondIt->first - mFirstIt->first);
 	
 	// handle the ends
-	} else if(mFirstIt->first > mSecondIt->first) {
+	}
+	else if(mFirstIt->first > mSecondIt->first)
+	{
 		
 		// right edge of time line
-		if(curTime >= mFirstIt->first) {
+		if(curTime >= mFirstIt->first)
+		{
 			weight = F32 (curTime - mFirstIt->first) /
 			((1 + mSecondIt->first) - mFirstIt->first);
-		
 		// left edge of time line
-		} else {
+		}
+		else
+		{
 			weight = F32 ((1 + curTime) - mFirstIt->first) /
 			((1 + mSecondIt->first) - mFirstIt->first);
 		}
 
-	
 	// handle same as whatever the last one is
-	} else {
+	}
+	else
+	{
 		weight = 1;
 	}
 
+	if(mIsInterpolating)
+	{
+		// *TODO_JACOB: this is kind of laggy.  Not sure why.  The part that lags is the curParams.mix call, and none of the other mixes.  It works, though.
+		clock_t current = clock();
+		if(current >= mInterpEndTime)
+		{
+			mIsInterpolating = false;
+			return;
+		}
+		
+		// determine moving target for final interpolation value
+		LLWLParamSet buf = LLWLParamSet();
+		buf.setAll(LLWLParamManager::getInstance()->mParamList[mFirstIt->second].getAll());	// just give it some values, otherwise it has no params to begin with (see comment in constructor)
+		buf.mix(LLWLParamManager::getInstance()->mParamList[mFirstIt->second], LLWLParamManager::getInstance()->mParamList[mSecondIt->second], weight);	// mix to determine moving target for interpolation finish (as below)
+
+		// mix from previous value to moving target
+		weight = (current - mInterpStartTime) / (INTERP_TOTAL_SECONDS * CLOCKS_PER_SEC);
+		curParams.mix(*mInterpBeginWL, buf, weight);
+		
+		// mix water
+		LLWaterParamManager::getInstance()->mCurParams.mix(*mInterpBeginWater, *mInterpEndWater, weight);
+	}
+	else
+	{
 	// do the interpolation and set the parameters
-	curParams.mix(LLWLParamManager::instance()->mParamList[mFirstIt->second], 
-		LLWLParamManager::instance()->mParamList[mSecondIt->second], weight);
+		curParams.mix(LLWLParamManager::getInstance()->mParamList[mFirstIt->second], LLWLParamManager::getInstance()->mParamList[mSecondIt->second], weight);
+	}
 }
 
 F64 LLWLAnimator::getDayTime()
 {
-	if(!mIsRunning) {
+	if(!mIsRunning)
+	{
 		return mDayTime;
 	}
-
-	if(mUseLindenTime) {
-
+	else if(mTimeType == TIME_LINDEN)
+	{
 		F32 phase = gSky.getSunPhase() / F_PI;
 
 		// we're not solving the non-linear equation that determines sun phase
 		// we're just linearly interpolating between the major points
 		if (phase <= 5.0 / 4.0) {
 			mDayTime = (1.0 / 3.0) * phase + (1.0 / 3.0);
-		} else {
+		}
+		else
+		{
 			mDayTime = phase - (1.0 / 2.0);
 		}
 
-		if(mDayTime > 1) {
+		if(mDayTime > 1)
+		{
 			mDayTime--;
 		}
 
 		return mDayTime;
 	}
+	else if(mTimeType == TIME_LOCAL)
+	{
+		return getLocalTime();
+	}
 
 	// get the time;
 	mDayTime = (LLTimer::getElapsedSeconds() - mStartTime) / mDayRate;
 
 	// clamp it
-	if(mDayTime < 0) {
+	if(mDayTime < 0)
+	{
 		mDayTime = 0;
 	} 
-	while(mDayTime > 1) {
+	while(mDayTime > 1)
+	{
 		mDayTime--;
 	}
 
@@ -144,15 +196,18 @@ void LLWLAnimator::setDayTime(F64 dayTime)
 	mDayTime = dayTime;
 
 	// clamp it
-	if(mDayTime < 0) {
+	if(mDayTime < 0)
+	{
 		mDayTime = 0;
-	} else if(mDayTime > 1) {
+	}
+	else if(mDayTime > 1)
+	{
 		mDayTime = 1;
 	}
 }
 
 
-void LLWLAnimator::setTrack(std::map<F32, std::string>& curTrack,
+void LLWLAnimator::setTrack(std::map<F32, LLWLParamKey>& curTrack,
 							F32 dayRate, F64 dayTime, bool run)
 {
 	mTimeTrack = curTrack;
@@ -161,3 +216,96 @@ void LLWLAnimator::setTrack(std::map<F32, std::string>& curTrack,
 
 	mIsRunning = run;
 }
+
+void LLWLAnimator::startInterpolation(LLSD& targetWater)
+{
+	mInterpBeginWL->setAll(LLWLParamManager::getInstance()->mCurParams.getAll());
+	mInterpBeginWater->setAll(LLWaterParamManager::getInstance()->mCurParams.getAll());
+	
+	mInterpStartTime = clock();
+	mInterpEndTime = mInterpStartTime + clock_t(INTERP_TOTAL_SECONDS) * CLOCKS_PER_SEC;
+
+	// Don't set any ending WL -- this is continuously calculated as the animator updates since it's a moving target
+	mInterpEndWater->setAll(targetWater);
+
+	mIsInterpolating = true;
+}
+
+std::string LLWLAnimator::timeToString(F32 curTime)
+{
+	S32 hours;
+	S32 min;
+	bool isPM = false;
+
+	// get hours and minutes
+	hours = (S32) (24.0 * curTime);
+	curTime -= ((F32) hours / 24.0f);
+	min = llround(24.0f * 60.0f * curTime);
+
+	// handle case where it's 60
+	if(min == 60) 
+	{
+		hours++;
+		min = 0;
+	}
+
+	// set for PM
+	if(hours >= 12 && hours < 24)
+	{
+		isPM = true;
+	}
+
+	// convert to non-military notation
+	if(hours >= 24) 
+	{
+		hours = 12;
+	} 
+	else if(hours > 12) 
+	{
+		hours -= 12;
+	} 
+	else if(hours == 0) 
+	{
+		hours = 12;
+	}
+
+	// make the string
+	std::stringstream newTime;
+	newTime << hours << ":";
+	
+	// double 0
+	if(min < 10) 
+	{
+		newTime << 0;
+	}
+	
+	// finish it
+	newTime << min << " ";
+	if(isPM) 
+	{
+		newTime << "PM";
+	} 
+	else 
+	{
+		newTime << "AM";
+	}
+
+	return newTime.str();
+}
+
+F64 LLWLAnimator::getLocalTime()
+{
+	char buffer[9];
+	time_t rawtime;
+	struct tm* timeinfo;
+
+	time(&rawtime);
+	timeinfo = localtime(&rawtime);
+	strftime(buffer, 9, "%H:%M:%S", timeinfo);
+	std::string timeStr(buffer);
+
+	F64 tod = ((F64)atoi(timeStr.substr(0,2).c_str())) / 24.f +
+			  ((F64)atoi(timeStr.substr(3,2).c_str())) / 1440.f + 
+			  ((F64)atoi(timeStr.substr(6,2).c_str())) / 86400.f;
+	return tod;
+}
diff --git a/indra/newview/llwlanimator.h b/indra/newview/llwlanimator.h
index 5677290213749948f5895242a522adf044d55c34..07c2fa2328a45453f4195842022db7a5329df8ed 100644
--- a/indra/newview/llwlanimator.h
+++ b/indra/newview/llwlanimator.h
@@ -28,28 +28,39 @@
 #define LL_WL_ANIMATOR_H
 
 #include "llwlparamset.h"
+#include "llwaterparamset.h"
 #include <string>
 #include <map>
 
+struct LLWLParamKey;
+
 class LLWLAnimator {
 public:
+	typedef enum e_time
+	{
+		TIME_LINDEN,
+		TIME_LOCAL,
+		TIME_CUSTOM
+	} ETime;
+
 	F64 mStartTime;
 	F32 mDayRate;
 	F64 mDayTime;
 	
 	// track to play
-	std::map<F32, std::string> mTimeTrack;
-	std::map<F32, std::string>::iterator mFirstIt, mSecondIt;
-
-	// params to use
-	//std::map<std::string, LLWLParamSet> mParamList;
-
-	bool mIsRunning;
-	bool mUseLindenTime;
+	std::map<F32, LLWLParamKey> mTimeTrack;
+	std::map<F32, LLWLParamKey>::iterator mFirstIt, mSecondIt;
 
 	// simple constructor
 	LLWLAnimator();
 
+	~LLWLAnimator()
+	{
+		delete mInterpBeginWL;
+		delete mInterpBeginWater;
+		delete mInterpEndWater;
+	}
+
 	// update the parameters
 	void update(LLWLParamSet& curParams);
 
@@ -63,9 +74,66 @@ class LLWLAnimator {
 	void setDayTime(F64 dayTime);
 
 	// set an animation track
-	void setTrack(std::map<F32, std::string>& track,
+	void setTrack(std::map<F32, LLWLParamKey>& track,
 		F32 dayRate, F64 dayTime = 0, bool run = true);
 
+	void deactivate()
+	{
+		mIsRunning = false;
+	}
+
+	void activate(ETime time)
+	{
+		mIsRunning = true;
+		mTimeType = time;
+	}
+
+	void startInterpolation(LLSD& targetWater);
+
+	bool getIsRunning()
+	{
+		return mIsRunning;
+	}
+
+	bool getUseCustomTime()
+	{
+		return mTimeType == TIME_CUSTOM;
+	}
+
+	bool getUseLocalTime()
+	{
+		return mTimeType == TIME_LOCAL;
+	}
+
+	bool getUseLindenTime()
+	{
+		return mTimeType == TIME_LINDEN;
+	}
+
+	void setTimeType(ETime time)
+	{
+		mTimeType = time;
+	}
+
+	ETime getTimeType()
+	{
+		return mTimeType;
+	}
+
+	/// convert the present time to a digital clock time
+	static std::string timeToString(F32 curTime);
+
+	/// get local time between 0 and 1
+	static F64 getLocalTime();
+
+private:
+	ETime mTimeType;
+	bool mIsRunning, mIsInterpolating;
+	LLWLParamSet *mInterpBeginWL;
+	LLWaterParamSet *mInterpBeginWater, *mInterpEndWater;
+	clock_t mInterpStartTime, mInterpEndTime;
+
+	static F64 INTERP_TOTAL_SECONDS;
 };
 
 #endif // LL_WL_ANIMATOR_H
diff --git a/indra/newview/llwldaycycle.cpp b/indra/newview/llwldaycycle.cpp
index 85b3d62a49b796b60c3331db4ff9c26751101272..52bbb4b5fc9af6b83e75098a84f69e666e590950 100644
--- a/indra/newview/llwldaycycle.cpp
+++ b/indra/newview/llwldaycycle.cpp
@@ -2,37 +2,42 @@
  * @file llwldaycycle.cpp
  * @brief Implementation for the LLWLDayCycle class.
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
  * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
 
 #include "llviewerprecompiledheaders.h"
 
 #include "llwldaycycle.h"
-
-#include "llnotificationsutil.h"
 #include "llsdserialize.h"
-#include "llxmlnode.h"
-
 #include "llwlparammanager.h"
+#include "llfloaterdaycycle.h"
+
+#include "llviewerwindow.h"
 
 #include <map>
 
@@ -45,85 +50,111 @@ LLWLDayCycle::~LLWLDayCycle()
 {
 }
 
-void LLWLDayCycle::loadDayCycle(const std::string & fileName)
+void LLWLDayCycle::loadDayCycle(const LLSD& day_data, LLWLParamKey::EScope scope)
 {
-	// clear the first few things
 	mTimeMap.clear();
 
-	// now load the file
-	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, 
-		"windlight/days", fileName));
-	llinfos << "Loading DayCycle settings from " << pathName << llendl;
-	
-	llifstream day_cycle_xml(pathName);
-	if (day_cycle_xml.is_open())
+	// add each key frame
+	for(S32 i = 0; i < day_data.size(); ++i)
 	{
-		// load and parse it
-		LLSD day_data(LLSD::emptyArray());
-		LLPointer<LLSDParser> parser = new LLSDXMLParser();
-		parser->parse(day_cycle_xml, day_data, LLSDSerialize::SIZE_UNLIMITED);
-
-		// add each key
-		for(S32 i = 0; i < day_data.size(); ++i)
+		// make sure it's a two array
+		if(day_data[i].size() != 2)
+		{
+			continue;
+		}
+		
+		// check each param key exists in param manager
+		bool success;
+		LLWLParamSet pset;
+		LLWLParamKey frame = LLWLParamKey(day_data[i][1].asString(), scope);
+		success =
+			LLWLParamManager::getInstance()->getParamSet(frame, pset);
+		if(!success)
 		{
-			// make sure it's a two array
-			if(day_data[i].size() != 2)
+			// *HACK try the local-scope ones for "A-something" defaults
+			// (because our envManager.lindenDefault() doesn't have the skies yet)
+			if (frame.name.find("A-") == 0)
 			{
-				continue;
+				frame.scope = LLEnvKey::SCOPE_LOCAL;
+				success = LLWLParamManager::getInstance()->getParamSet(frame, pset);
 			}
-			
-			// check each param name exists in param manager
-			bool success;
-			LLWLParamSet pset;
-			success = LLWLParamManager::instance()->getParamSet(day_data[i][1].asString(), pset);
-			if(!success)
+
+			if (!success)
 			{
 				// alert the user
 				LLSD args;
 				args["SKY"] = day_data[i][1].asString();
-				LLNotificationsUtil::add("WLMissingSky", args);
+				LLNotifications::instance().add("WLMissingSky", args);
 				continue;
 			}
-			
-			// then add the key
-			addKey((F32)day_data[i][0].asReal(), day_data[i][1].asString());
 		}
+		
+		// then add the keyframe
+		addKeyframe((F32)day_data[i][0].asReal(), frame);
+	}
+}
+
+void LLWLDayCycle::loadDayCycleFromFile(const std::string & fileName)
+{
+	loadDayCycle(loadCycleDataFromFile(fileName), LLWLParamKey::SCOPE_LOCAL);
+}
 
+/*static*/ LLSD LLWLDayCycle::loadCycleDataFromFile(const std::string & fileName)
+{
+	// now load the file
+	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, 
+		"windlight/days", fileName));
+	llinfos << "Loading DayCycle settings from " << pathName << llendl;
+	
+	llifstream day_cycle_xml(pathName);
+	if (day_cycle_xml.is_open())
+	{
+		// load and parse it
+		LLSD day_data(LLSD::emptyArray());
+		LLPointer<LLSDParser> parser = new LLSDXMLParser();
+		parser->parse(day_cycle_xml, day_data, LLSDSerialize::SIZE_UNLIMITED);
 		day_cycle_xml.close();
+		return day_data;
+	}
+	else
+	{
+		return LLSD();
 	}
 }
 
 void LLWLDayCycle::saveDayCycle(const std::string & fileName)
 {
-	LLSD day_data(LLSD::emptyArray());
+	LLSD day_data = asLLSD();
 
 	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/days", fileName));
 	//llinfos << "Saving WindLight settings to " << pathName << llendl;
 
-	for(std::map<F32, std::string>::const_iterator mIt = mTimeMap.begin();
-		mIt != mTimeMap.end();
-		++mIt) 
-	{
-		LLSD key(LLSD::emptyArray());
-		key.append(mIt->first);
-		key.append(mIt->second);
-		day_data.append(key);
-	}
-
 	llofstream day_cycle_xml(pathName);
 	LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
 	formatter->format(day_data, day_cycle_xml, LLSDFormatter::OPTIONS_PRETTY);
 	day_cycle_xml.close();
 }
 
+LLSD LLWLDayCycle::asLLSD()
+{
+	LLSD day_data(LLSD::emptyArray());
+	for(std::map<F32, LLWLParamKey>::const_iterator mIt = mTimeMap.begin(); mIt != mTimeMap.end(); ++mIt) 
+	{
+		LLSD key(LLSD::emptyArray());
+		key.append(mIt->first);
+		key.append(mIt->second.name);
+		day_data.append(key);
+	}
+	return day_data;
+}
 
-void LLWLDayCycle::clearKeys()
+void LLWLDayCycle::clearKeyframes()
 {
 	mTimeMap.clear();
 }
 
 
-bool LLWLDayCycle::addKey(F32 newTime, const std::string & paramName)
+bool LLWLDayCycle::addKeyframe(F32 newTime, LLWLParamKey frame)
 {
 	// no adding negative time
 	if(newTime < 0) 
@@ -134,7 +165,7 @@ bool LLWLDayCycle::addKey(F32 newTime, const std::string & paramName)
 	// if time not being used, add it and return true
 	if(mTimeMap.find(newTime) == mTimeMap.end()) 
 	{
-		mTimeMap.insert(std::pair<F32, std::string>(newTime, paramName));
+		mTimeMap.insert(std::pair<F32, LLWLParamKey>(newTime, frame));
 		return true;
 	}
 
@@ -142,40 +173,40 @@ bool LLWLDayCycle::addKey(F32 newTime, const std::string & paramName)
 	return false;
 }
 
-bool LLWLDayCycle::changeKeyTime(F32 oldTime, F32 newTime)
+bool LLWLDayCycle::changeKeyframeTime(F32 oldTime, F32 newTime)
 {
 	// just remove and add back
-	std::string name = mTimeMap[oldTime];
+	LLWLParamKey frame = mTimeMap[oldTime];
 
-	bool stat = removeKey(oldTime);
+	bool stat = removeKeyframe(oldTime);
 	if(stat == false) 
 	{
 		return stat;
 	}
 
-	return addKey(newTime, name);
+	return addKeyframe(newTime, frame);
 }
 
-bool LLWLDayCycle::changeKeyParam(F32 time, const std::string & name)
+bool LLWLDayCycle::changeKeyframeParam(F32 time, LLWLParamKey key)
 {
 	// just remove and add back
 	// make sure param exists
 	LLWLParamSet tmp;
-	bool stat = LLWLParamManager::instance()->getParamSet(name, tmp);
+	bool stat = LLWLParamManager::getInstance()->getParamSet(key, tmp);
 	if(stat == false) 
 	{
 		return stat;
 	}
 
-	mTimeMap[time] = name;
+	mTimeMap[time] = key;
 	return true;
 }
 
 
-bool LLWLDayCycle::removeKey(F32 time)
+bool LLWLDayCycle::removeKeyframe(F32 time)
 {
 	// look for the time.  If there, erase it
-	std::map<F32, std::string>::iterator mIt = mTimeMap.find(time);
+	std::map<F32, LLWLParamKey>::iterator mIt = mTimeMap.find(time);
 	if(mIt != mTimeMap.end()) 
 	{
 		mTimeMap.erase(mIt);
@@ -185,15 +216,15 @@ bool LLWLDayCycle::removeKey(F32 time)
 	return false;
 }
 
-bool LLWLDayCycle::getKey(const std::string & name, F32& key)
+bool LLWLDayCycle::getKeytime(LLWLParamKey frame, F32& key_time)
 {
-	// scroll through till we find the 
-	std::map<F32, std::string>::iterator mIt = mTimeMap.begin();
+	// scroll through till we find the correct value in the map
+	std::map<F32, LLWLParamKey>::iterator mIt = mTimeMap.begin();
 	for(; mIt != mTimeMap.end(); ++mIt) 
 	{
-		if(name == mIt->second) 
+		if(frame == mIt->second) 
 		{
-			key = mIt->first;
+			key_time = mIt->first;
 			return true;
 		}
 	}
@@ -204,10 +235,10 @@ bool LLWLDayCycle::getKey(const std::string & name, F32& key)
 bool LLWLDayCycle::getKeyedParam(F32 time, LLWLParamSet& param)
 {
 	// just scroll on through till you find it
-	std::map<F32, std::string>::iterator mIt = mTimeMap.find(time);
-	if(mIt != mTimeMap.end()) 
+	std::map<F32, LLWLParamKey>::iterator mIt = mTimeMap.find(time);
+	if(mIt != mTimeMap.end())
 	{
-		return LLWLParamManager::instance()->getParamSet(mIt->second, param);
+		return LLWLParamManager::getInstance()->getParamSet(mIt->second, param);
 	}
 
 	// return error if not found
@@ -217,13 +248,30 @@ bool LLWLDayCycle::getKeyedParam(F32 time, LLWLParamSet& param)
 bool LLWLDayCycle::getKeyedParamName(F32 time, std::string & name)
 {
 	// just scroll on through till you find it
-	std::map<F32, std::string>::iterator mIt = mTimeMap.find(time);
+	std::map<F32, LLWLParamKey>::iterator mIt = mTimeMap.find(time);
 	if(mIt != mTimeMap.end()) 
 	{
-		name = mTimeMap[time];
+		name = mTimeMap[time].name;
 		return true;
 	}
 
 	// return error if not found
 	return false;
 }
+
+void LLWLDayCycle::removeReferencesTo(const LLWLParamKey& keyframe)
+{
+	F32 keytime;
+	bool might_exist;
+	do 
+	{
+		// look for it
+		might_exist = getKeytime(keyframe, keytime);
+		if(!might_exist)
+		{
+			return;
+		}
+		might_exist = removeKeyframe(keytime);
+
+	} while(might_exist); // might be another one
+}
diff --git a/indra/newview/llwldaycycle.h b/indra/newview/llwldaycycle.h
index 5cbf72191ddbad4687d448045642e488f46dbb33..d56194a74a848f4fcc32353e7dc8ca12e02e1e48 100644
--- a/indra/newview/llwldaycycle.h
+++ b/indra/newview/llwldaycycle.h
@@ -34,13 +34,15 @@ class LLWLDayCycle;
 #include <string>
 #include "llwlparamset.h"
 #include "llwlanimator.h"
+struct LLWLParamKey;
+#include "llenvmanager.h" // for LLEnvKey::EScope
 
 class LLWLDayCycle
 {
 public:
 
 	// lists what param sets are used when during the day
-	std::map<F32, std::string> mTimeMap;
+	std::map<F32, LLWLParamKey> mTimeMap;
 
 	// how long is my day
 	F32 mDayRate;
@@ -54,35 +56,44 @@ class LLWLDayCycle
 	~LLWLDayCycle();
 
 	/// load a day cycle
-	void loadDayCycle(const std::string & fileName);
+	void loadDayCycle(const LLSD& llsd, LLEnvKey::EScope scope);
+
+	/// load a day cycle
+	void loadDayCycleFromFile(const std::string & fileName);
 
 	/// load a day cycle
 	void saveDayCycle(const std::string & fileName);
 
-	/// clear keys
-	void clearKeys();
+	/// load the LLSD data from a file (returns the undefined LLSD if not found)
+	static LLSD loadCycleDataFromFile(const std::string & fileName);
+
+	/// get the LLSD data for this day cycle
+	LLSD asLLSD();
+
+	/// clear keyframes
+	void clearKeyframes();
 
 	/// Getters and Setters
 	/// add a new key frame to the day cycle
 	/// returns true if successful
 	/// no negative time
-	bool addKey(F32 newTime, const std::string & paramName);
+	bool addKeyframe(F32 newTime, LLWLParamKey key);
 
-	/// adjust a key's placement in the day cycle
+	/// adjust a keyframe's placement in the day cycle
 	/// returns true if successful
-	bool changeKeyTime(F32 oldTime, F32 newTime);
+	bool changeKeyframeTime(F32 oldTime, F32 newTime);
 
-	/// adjust a key's parameter used
+	/// adjust a keyframe's parameter used
 	/// returns true if successful
-	bool changeKeyParam(F32 time, const std::string & paramName);
+	bool changeKeyframeParam(F32 time, LLWLParamKey key);
 
-	/// remove a key from the day cycle
+	/// remove a key frame from the day cycle
 	/// returns true if successful
-	bool removeKey(F32 time);
+	bool removeKeyframe(F32 time);
 
 	/// get the first key time for a parameter
 	/// returns false if not there
-	bool getKey(const std::string & name, F32& key);
+	bool getKeytime(LLWLParamKey keyFrame, F32& keyTime);
 
 	/// get the param set at a given time
 	/// returns true if found one
@@ -92,6 +103,9 @@ class LLWLDayCycle
 	/// returns true if it found one
 	bool getKeyedParamName(F32 time, std::string & name);
 
+	/// removes all references to the sky (paramkey)
+	/// does nothing if the sky doesn't exist in the day
+	void removeReferencesTo(const LLWLParamKey& keyframe);
 };
 
 
diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c4f11cf00ad772f80ff5d5baa0b748e08bf7fd65
--- /dev/null
+++ b/indra/newview/llwlhandlers.cpp
@@ -0,0 +1,159 @@
+/** 
+ * @file llwlhandlers.cpp
+ * @brief Various classes which handle Windlight-related messaging
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llwlhandlers.h"
+
+#include "llagent.h"
+#include "llviewerregion.h"
+#include "llenvmanager.h"
+
+/****
+ * LLEnvironmentRequestResponder
+ ****/
+int LLEnvironmentRequestResponder::sCount = 0; // init to 0
+
+/*static*/ bool LLEnvironmentRequestResponder::initiateRequest()
+{
+	std::string url = gAgent.getRegion()->getCapability("EnvironmentSettings");
+	if (url.empty())
+	{
+		LL_INFOS("WindlightCaps") << "Skipping windlight setting request - we don't have this capability" << LL_ENDL;
+		// region is apparently not capable of this; don't respond at all
+		return false;
+	}
+	else
+	{
+		LL_DEBUGS("WindlightCaps") << "Requesting windlight settings via " << url << LL_ENDL;
+		LLHTTPClient::get(url, new LLEnvironmentRequestResponder());
+		return true;
+	}
+}
+LLEnvironmentRequestResponder::LLEnvironmentRequestResponder()
+{
+	mID = ++sCount;
+}
+/*virtual*/ void LLEnvironmentRequestResponder::result(const LLSD& unvalidated_content)
+{
+	LL_DEBUGS("WindlightCaps") << "Receiving windlight settings..." << LL_ENDL;
+
+	if (mID != sCount)
+	{
+		LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL;
+		return;
+	}
+
+	if (unvalidated_content[0]["regionID"].asUUID() != gAgent.getRegion()->getRegionID())
+	{
+		LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting "
+			<< gAgent.getRegion()->getRegionID() << " but got " << unvalidated_content[0]["regionID"].asUUID()
+			<< ") - ignoring..." << LL_ENDL;
+		return;
+	}
+
+	LLEnvManager::getInstance()->processIncomingMessage(unvalidated_content, LLEnvKey::SCOPE_REGION);
+}
+/*virtual*/ void LLEnvironmentRequestResponder::error(U32 status, const std::string& reason)
+{
+	LL_INFOS("WindlightCaps") << "Got an error, not using region windlight..." << LL_ENDL;
+	// notify manager that region settings are undefined
+	LLEnvManager::getInstance()->processIncomingMessage(LLSD(), LLEnvKey::SCOPE_REGION);
+}
+
+
+/****
+ * LLEnvironmentApplyResponder
+ ****/
+clock_t LLEnvironmentApplyResponder::UPDATE_WAIT_SECONDS = clock_t(3.f);
+clock_t LLEnvironmentApplyResponder::sLastUpdate = clock_t(0.f);
+
+bool LLEnvironmentApplyResponder::initiateRequest(const LLSD& content)
+{
+	clock_t current = clock();
+	if(current >= sLastUpdate + (UPDATE_WAIT_SECONDS * CLOCKS_PER_SEC))
+	{
+		sLastUpdate = current;
+	}
+	else
+	{
+		LLSD args(LLSD::emptyMap());
+		args["WAIT"] = (F64)UPDATE_WAIT_SECONDS;
+		LLNotifications::instance().add("EnvUpdateRate", args);
+		return false;
+	}
+
+	std::string url = gAgent.getRegion()->getCapability("EnvironmentSettings");
+	if (!url.empty())
+	{
+		LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL;
+		LLHTTPClient::post(url, content, new LLEnvironmentApplyResponder());
+		return true;
+	}
+	return false;
+}
+/*virtual*/ void LLEnvironmentApplyResponder::result(const LLSD& content)
+{
+	if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID())
+	{
+		LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently "
+			<< gAgent.getRegion()->getRegionID() << ", reply is from " << content["regionID"].asUUID()
+			<< "); ignoring..." << LL_ENDL;
+		return;
+	}
+	else if (content["success"].asBoolean())
+	{
+		LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << content["regionID"].asUUID() << LL_ENDL;
+	}
+	else
+	{
+		LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings!  Reason from sim: " << content["fail_reason"].asString() << LL_ENDL;
+		LLSD args(LLSD::emptyMap());
+		args["FAIL_REASON"] = content["fail_reason"].asString();
+		LLNotifications::instance().add("WLRegionApplyFail", args);
+	}
+
+	LLEnvManager::getInstance()->commitSettingsFinished(LLEnvKey::SCOPE_REGION);
+}
+/*virtual*/ void LLEnvironmentApplyResponder::error(U32 status, const std::string& reason)
+{
+	std::stringstream msg;
+	msg << reason << " (Code " << status << ")";
+
+	LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region!  Reason: " << msg << LL_ENDL;
+
+	LLSD args(LLSD::emptyMap());
+	args["FAIL_REASON"] = msg.str();
+	LLNotifications::instance().add("WLRegionApplyFail", args);
+
+	LLEnvManager::getInstance()->commitSettingsFinished(LLEnvKey::SCOPE_REGION);
+}
diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h
new file mode 100644
index 0000000000000000000000000000000000000000..a50404f2e12e177910c1596e636c059313290883
--- /dev/null
+++ b/indra/newview/llwlhandlers.h
@@ -0,0 +1,89 @@
+/** 
+ * @file llwlhandlers.h
+ * @brief Headers for classes in llwlhandlers.cpp
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLWLHANDLERS_H
+#define LL_LLWLHANDLERS_H
+
+#include "llviewerprecompiledheaders.h"
+
+class LLEnvManager;
+
+class LLEnvironmentRequestResponder: public LLHTTPClient::Responder
+{
+public:
+	virtual void result(const LLSD& content);
+	virtual void error(U32 status, const std::string& reason);
+
+private:
+	friend class LLEnvManager;
+	// returns true if request was sucessfully sent
+	static bool initiateRequest();
+
+	LLEnvironmentRequestResponder();
+	static int sCount;
+	int mID;
+};
+
+class LLEnvironmentApplyResponder: public LLHTTPClient::Responder
+{
+public:
+	/*
+	 * Expecting reply from sim in form of:
+	 * {
+	 *   regionID : uuid,
+	 *   messageID: uuid,
+	 *   success : true
+	 * }
+	 * or
+	 * {
+	 *   regionID : uuid,
+	 *   success : false,
+	 *   fail_reason : string
+	 * }
+	 */
+	virtual void result(const LLSD& content);
+
+	virtual void error(U32 status, const std::string& reason); // non-200 errors only
+
+private:
+	friend class LLEnvManager;
+	
+	static clock_t sLastUpdate;
+	static clock_t UPDATE_WAIT_SECONDS;
+
+	// for format of packet expected, see llwlscrubbers.cpp in llmessage
+	static bool initiateRequest(const LLSD& packet);
+
+	LLEnvironmentApplyResponder() {}
+};
+
+#endif // LL_LLWLHANDLERS_H
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp
index 9b6047395ad22da0c81217525638d6aa6838d6d6..493d066942392c9df651de96974dd08a45428374 100644
--- a/indra/newview/llwlparammanager.cpp
+++ b/indra/newview/llwlparammanager.cpp
@@ -2,25 +2,31 @@
  * @file llwlparammanager.cpp
  * @brief Implementation for the LLWLParamManager class.
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
  * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
 
@@ -31,28 +37,34 @@
 #include "pipeline.h"
 #include "llsky.h"
 
-#include "llfloaterreg.h"
 #include "llsliderctrl.h"
 #include "llspinctrl.h"
 #include "llcheckboxctrl.h"
 #include "lluictrlfactory.h"
+#include "llviewercamera.h"
 #include "llcombobox.h"
 #include "lllineeditor.h"
 #include "llsdserialize.h"
 
 #include "v4math.h"
+#include "llviewerdisplay.h"
 #include "llviewercontrol.h"
+#include "llviewerwindow.h"
+#include "lldrawpoolwater.h"
+#include "llagent.h"
+#include "llviewerregion.h"
 
+#include "llenvmanager.h"
 #include "llwlparamset.h"
 #include "llpostprocess.h"
 #include "llfloaterwindlight.h"
 #include "llfloaterdaycycle.h"
 #include "llfloaterenvsettings.h"
+#include "llviewershadermgr.h"
+#include "llglslshader.h"
 
 #include "curl/curl.h"
-
-LLWLParamManager * LLWLParamManager::sInstance = NULL;
-static LLFastTimer::DeclareTimer FTM_UPDATE_WLPARAM("Update Windlight Params");
+#include "llstreamtools.h"
 
 LLWLParamManager::LLWLParamManager() :
 
@@ -95,19 +107,150 @@ LLWLParamManager::~LLWLParamManager()
 {
 }
 
+void LLWLParamManager::clearParamSetsOfScope(LLWLParamKey::EScope scope)
+{
+	if (LLWLParamKey::SCOPE_LOCAL == scope)
+	{
+		LL_WARNS("Windlight") << "Tried to clear windlight sky presets from local system!  This shouldn't be called..." << LL_ENDL;
+		return;
+	}
+
+	std::set<LLWLParamKey> to_remove;
+	for(std::map<LLWLParamKey, LLWLParamSet>::iterator iter = mParamList.begin(); iter != mParamList.end(); ++iter)
+	{
+		if(iter->first.scope == scope)
+		{
+			to_remove.insert(iter->first);
+		}
+	}
+
+	for(std::set<LLWLParamKey>::iterator iter = to_remove.begin(); iter != to_remove.end(); ++iter)
+	{
+		mParamList.erase(*iter);
+	}
+}
+
+// returns all skies referenced by the day cycle, with their final names
+// side effect: applies changes to all internal structures!
+std::map<LLWLParamKey, LLWLParamSet> LLWLParamManager::finalizeFromDayCycle(LLWLParamKey::EScope scope)
+{
+	std::map<LLWLParamKey, LLWLParamSet> final_references;
+
+	// Move all referenced to desired scope, renaming if necessary
+	// First, save skies referenced
+	std::map<LLWLParamKey, LLWLParamSet> current_references; // all skies referenced by the day cycle, with their current names
+	// guard against skies with same name and different scopes
+	std::set<std::string> inserted_names;
+	std::map<std::string, unsigned int> conflicted_names; // integer later used as a count, for uniquely renaming conflicts
+
+	LLWLDayCycle& cycle = mDay;
+	for(std::map<F32, LLWLParamKey>::iterator iter = cycle.mTimeMap.begin();
+		iter != cycle.mTimeMap.end();
+		++iter)
+	{
+		LLWLParamKey& key = iter->second;
+		std::string desired_name = key.name;
+		replace_newlines_with_whitespace(desired_name); // already shouldn't have newlines, but just in case
+		if(inserted_names.find(desired_name) == inserted_names.end())
+		{
+			inserted_names.insert(desired_name);
+		}
+		else
+		{
+			// make exist in map
+			conflicted_names[desired_name] = 0;
+		}
+		current_references[key] = mParamList[key];
+	}
+
+	// forget all old skies in target scope, and rebuild, renaming as needed
+	clearParamSetsOfScope(scope);
+	for(std::map<LLWLParamKey, LLWLParamSet>::iterator iter = current_references.begin(); iter != current_references.end(); ++iter)
+	{
+		const LLWLParamKey& old_key = iter->first;
+
+		std::string desired_name(old_key.name);
+		replace_newlines_with_whitespace(desired_name);
+
+		LLWLParamKey new_key(desired_name, scope); // name will be replaced later if necessary
+
+		// if this sky is one with a non-unique name, rename via appending a number
+		// an existing preset of the target scope gets to keep its name
+		if (scope != old_key.scope && conflicted_names.find(desired_name) != conflicted_names.end())
+		{
+			std::string& new_name = new_key.name;
+
+			do
+			{
+				// if this executes more than once, this is an absurdly pathological case
+				// (e.g. "x" repeated twice, but "x 1" already exists, so need to use "x 2")
+				std::stringstream temp;
+				temp << desired_name << " " << (++conflicted_names[desired_name]);
+				new_name = temp.str();
+			} while (inserted_names.find(new_name) != inserted_names.end());
+
+			// yay, found one that works
+			inserted_names.insert(new_name); // track names we consume here; shouldn't be necessary due to ++int? but just in case
+
+			// *TODO factor out below into a rename()?
+
+			LL_INFOS("Windlight") << "Renamed " << old_key.name << " (scope" << old_key.scope << ") to "
+				<< new_key.name << " (scope " << new_key.scope << ")" << LL_ENDL;
+
+			// update name in sky
+			iter->second.mName = new_name;
+
+			// update keys in day cycle
+			for(std::map<F32, LLWLParamKey>::iterator frame = cycle.mTimeMap.begin(); frame != cycle.mTimeMap.end(); ++frame)
+			{
+				if (frame->second == old_key)
+				{
+					frame->second = new_key;
+				}
+			}
+
+			// add to master sky map
+			mParamList[new_key] = iter->second;
+		}
+
+		final_references[new_key] = iter->second;
+	}
+
+	return final_references;
+}
+
+LLSD LLWLParamManager::createSkyMap(std::map<LLWLParamKey, LLWLParamSet> refs)
+{
+	LLSD skies = LLSD::emptyMap();
+	for(std::map<LLWLParamKey, LLWLParamSet>::iterator iter = refs.begin(); iter != refs.end(); ++iter)
+	{
+		skies.insert(iter->first.name, iter->second.getAll());
+	}
+	return skies;
+}
+
+void LLWLParamManager::addAllSkies(const LLWLParamKey::EScope scope, const LLSD& sky_presets)
+{
+	for(LLSD::map_const_iterator iter = sky_presets.beginMap(); iter != sky_presets.endMap(); ++iter)
+	{
+		LLWLParamSet set;
+		set.setAll(iter->second);
+		mParamList[LLWLParamKey(iter->first, scope)] = set;
+	}
+}
+
 void LLWLParamManager::loadPresets(const std::string& file_name)
 {
 	std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", ""));
-	LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL;
-			
-	bool found = true;			
+	LL_INFOS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL;
+	
+	bool found = true;
 	while(found) 
 	{
 		std::string name;
 		found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name, false);
 		if(found)
 		{
-
 			name=name.erase(name.length()-4);
 
 			// bugfix for SL-46920: preventing filenames that break stuff.
@@ -117,16 +260,16 @@ void LLWLParamManager::loadPresets(const std::string& file_name)
 			curl_str = NULL;
 
 			LL_DEBUGS2("AppInit", "Shaders") << "name: " << name << LL_ENDL;
-			loadPreset(unescaped_name,FALSE);
+			loadPreset(LLWLParamKey(unescaped_name, LLWLParamKey::SCOPE_LOCAL),FALSE);
 		}
 	}
 
 	// And repeat for user presets, note the user presets will modify any system presets already loaded
 
 	std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));
-	LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL;
-			
-	found = true;			
+	LL_INFOS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL;
+	
+	found = true;
 	while(found) 
 	{
 		std::string name;
@@ -142,12 +285,14 @@ void LLWLParamManager::loadPresets(const std::string& file_name)
 			curl_str = NULL;
 
 			LL_DEBUGS2("AppInit", "Shaders") << "name: " << name << LL_ENDL;
-			loadPreset(unescaped_name,FALSE);
+			loadPreset(LLWLParamKey(unescaped_name,LLWLParamKey::SCOPE_LOCAL),FALSE);
 		}
 	}
 
 }
 
+// untested and unmaintained!  sanity-check me before using
+/*
 void LLWLParamManager::savePresets(const std::string & fileName)
 {
 	//Nobody currently calls me, but if they did, then its reasonable to write the data out to the user's folder
@@ -157,11 +302,11 @@ void LLWLParamManager::savePresets(const std::string & fileName)
 	
 	std::string pathName(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", fileName));
 
-	for(std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.begin();
+	for(std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = mParamList.begin();
 		mIt != mParamList.end();
 		++mIt) 
 	{
-		paramsData[mIt->first] = mIt->second.getAll();
+		paramsData[mIt->first.name] = mIt->second.getAll();
 	}
 
 	llofstream presetsXML(pathName);
@@ -172,70 +317,78 @@ void LLWLParamManager::savePresets(const std::string & fileName)
 
 	presetsXML.close();
 }
+*/
 
-void LLWLParamManager::loadPreset(const std::string & name,bool propagate)
+void LLWLParamManager::loadPreset(const LLWLParamKey key, bool propagate)
 {
-	
-	// bugfix for SL-46920: preventing filenames that break stuff.
-	char * curl_str = curl_escape(name.c_str(), name.size());
-	std::string escaped_filename(curl_str);
-	curl_free(curl_str);
-	curl_str = NULL;
-
-	escaped_filename += ".xml";
-
-	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", escaped_filename));
-	LL_DEBUGS2("AppInit", "Shaders") << "Loading WindLight sky setting from " << pathName << LL_ENDL;
-
-	llifstream presetsXML;
-	presetsXML.open(pathName.c_str());
-
-	// That failed, try loading from the users area instead.
-	if(!presetsXML)
+	if(mParamList.find(key) == mParamList.end())			// key does not already exist in mapping
 	{
-		pathName=gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", escaped_filename);
-		LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight sky setting from " << pathName << LL_ENDL;
-		presetsXML.clear();
-        presetsXML.open(pathName.c_str());
-	}
+		if(key.scope == LLWLParamKey::SCOPE_LOCAL)			// local scope, so try to load from file
+		{
+			// bugfix for SL-46920: preventing filenames that break stuff.
+			char * curl_str = curl_escape(key.name.c_str(), key.name.size());
+			std::string escaped_filename(curl_str);
+			curl_free(curl_str);
+			curl_str = NULL;
 
-	if (presetsXML)
-	{
-		LLSD paramsData(LLSD::emptyMap());
+			escaped_filename += ".xml";
 
-		LLPointer<LLSDParser> parser = new LLSDXMLParser();
+			std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", escaped_filename));
+			llinfos << "Loading WindLight sky setting from " << pathName << llendl;
 
-		parser->parse(presetsXML, paramsData, LLSDSerialize::SIZE_UNLIMITED);
+			llifstream presetsXML;
+			presetsXML.open(pathName.c_str());
 
-		std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name);
-		if(mIt == mParamList.end())
-		{
-			addParamSet(name, paramsData);
+			// That failed, try loading from the users area instead.
+			if(!presetsXML)
+			{
+				pathName=gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", escaped_filename);
+				llinfos << "Loading User WindLight sky setting from " << pathName << llendl;
+				presetsXML.open(pathName.c_str());
+			}
+
+			if (presetsXML)
+			{
+				loadPresetFromXML(key, presetsXML);
+				presetsXML.close();
+			} 
+			else 
+			{
+				llwarns << "Could not load local WindLight sky setting " << key.toString() << llendl;
+				return;
+			}
 		}
-		else 
+		else
 		{
-			setParamSet(name, paramsData);
-		}
-		presetsXML.close();
-	} 
-	else 
-	{
-		llwarns << "Can't find " << name << llendl;
-		return;
+			llwarns << "Attempted to load non-local WindLight sky settings " << key.toString() << "; not found in parameter mapping." << llendl;
+			return;
+		}		
 	}
 
-	
 	if(propagate)
 	{
-		getParamSet(name, mCurParams);
+		getParamSet(key, mCurParams);
 		propagateParameters();
 	}
-}	
+}
 
-void LLWLParamManager::savePreset(const std::string & name)
+void LLWLParamManager::loadPresetFromXML(LLWLParamKey key, std::istream & presetsXML)
+{
+	LLSD paramsData(LLSD::emptyMap());
+	LLPointer<LLSDParser> parser = new LLSDXMLParser();
+
+	parser->parse(presetsXML, paramsData, LLSDSerialize::SIZE_UNLIMITED);
+
+	std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = mParamList.find(key);
+
+	if(mIt == mParamList.end()) addParamSet(key, paramsData);
+	else setParamSet(key, paramsData);
+}
+
+void LLWLParamManager::savePreset(LLWLParamKey key)
 {
 	// bugfix for SL-46920: preventing filenames that break stuff.
-	char * curl_str = curl_escape(name.c_str(), name.size());
+	char * curl_str = curl_escape(key.name.c_str(), key.name.size());
 	std::string escaped_filename(curl_str);
 	curl_free(curl_str);
 	curl_str = NULL;
@@ -247,7 +400,7 @@ void LLWLParamManager::savePreset(const std::string & name)
 	std::string pathName(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", escaped_filename));
 
 	// fill it with LLSD windlight params
-	paramsData = mParamList[name].getAll();
+	paramsData = mParamList[key].getAll();
 
 	// write to file
 	llofstream presetsXML(pathName);
@@ -282,7 +435,7 @@ void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader)
 
 void LLWLParamManager::propagateParameters(void)
 {
-	LLFastTimer ftm(FTM_UPDATE_WLPARAM);
+	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM);
 	
 	LLVector4 sunDir;
 	LLVector4 moonDir;
@@ -306,7 +459,7 @@ void LLWLParamManager::propagateParameters(void)
 	{
 		mLightDir = sunDir;
 	}
-	else if(sunDir.mV[1] < 0 && sunDir.mV[1] > LLSky::NIGHTTIME_ELEVATION_COS)
+	else if(sunDir.mV[1] < 0 && sunDir.mV[1] > NIGHTTIME_ELEVATION_COS)
 	{
 		// clamp v1 to 0 so sun never points up and causes weirdness on some machines
 		LLVector3 vec(sunDir.mV[0], sunDir.mV[1], sunDir.mV[2]);
@@ -353,13 +506,13 @@ void LLWLParamManager::propagateParameters(void)
 
 void LLWLParamManager::update(LLViewerCamera * cam)
 {
-	LLFastTimer ftm(FTM_UPDATE_WLPARAM);
+	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM);
 	
 	// update clouds, sun, and general
 	mCurParams.updateCloudScrolling();
 	
 	// update only if running
-	if(mAnimator.mIsRunning) 
+	if(mAnimator.getIsRunning()) 
 	{
 		mAnimator.update(mCurParams);
 	}
@@ -368,30 +521,29 @@ void LLWLParamManager::update(LLViewerCamera * cam)
 	propagateParameters();
 	
 	// sync menus if they exist
-	LLFloaterWindLight* wlfloater = LLFloaterReg::findTypedInstance<LLFloaterWindLight>("env_windlight");
-	if (wlfloater)
+	if(LLFloaterWindLight::isOpen()) 
 	{
-		wlfloater->syncMenu();
+		LLFloaterWindLight::instance()->syncMenu();
 	}
-	LLFloaterDayCycle* dlfloater = LLFloaterReg::findTypedInstance<LLFloaterDayCycle>("env_day_cycle");
-	if (dlfloater)
+	if(LLFloaterDayCycle::isOpen()) 
 	{
-		dlfloater->syncMenu();
+		LLFloaterDayCycle::instance()->syncMenu();
 	}
-	LLFloaterEnvSettings* envfloater = LLFloaterReg::findTypedInstance<LLFloaterEnvSettings>("env_settings");
-	if (envfloater)
+	if(LLFloaterEnvSettings::isOpen()) 
 	{
-		envfloater->syncMenu();
+		LLFloaterEnvSettings::instance()->syncMenu();
 	}
 
 	F32 camYaw = cam->getYaw();
 
+	stop_glerror();
+
 	// *TODO: potential optimization - this block may only need to be
 	// executed some of the time.  For example for water shaders only.
 	{
 		F32 camYawDelta = mSunDeltaYaw * DEG_TO_RAD;
 		
-		LLVector3 lightNorm3(mLightDir);	
+		LLVector3 lightNorm3(mLightDir);
 		lightNorm3 *= LLQuaternion(-(camYaw + camYawDelta), LLVector3(0.f, 1.f, 0.f));
 		mRotatedLightDir = LLVector4(lightNorm3, 0.f);
 
@@ -409,19 +561,6 @@ void LLWLParamManager::update(LLViewerCamera * cam)
 	}
 }
 
-// static
-void LLWLParamManager::initClass(void)
-{
-	instance();
-}
-
-// static
-void LLWLParamManager::cleanupClass()
-{
-	delete sInstance;
-	sInstance = NULL;
-}
-
 void LLWLParamManager::resetAnimator(F32 curTime, bool run)
 {
 	mAnimator.setTrack(mDay.mTimeMap, mDay.mDayRate, 
@@ -429,26 +568,27 @@ void LLWLParamManager::resetAnimator(F32 curTime, bool run)
 
 	return;
 }
-bool LLWLParamManager::addParamSet(const std::string& name, LLWLParamSet& param)
+
+bool LLWLParamManager::addParamSet(const LLWLParamKey& key, LLWLParamSet& param)
 {
 	// add a new one if not one there already
-	std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name);
+	std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = mParamList.find(key);
 	if(mIt == mParamList.end()) 
 	{	
-		mParamList[name] = param;
+		mParamList[key] = param;
 		return true;
 	}
 
 	return false;
 }
 
-BOOL LLWLParamManager::addParamSet(const std::string& name, LLSD const & param)
+BOOL LLWLParamManager::addParamSet(const LLWLParamKey& key, LLSD const & param)
 {
 	// add a new one if not one there already
-	std::map<std::string, LLWLParamSet>::const_iterator finder = mParamList.find(name);
+	std::map<LLWLParamKey, LLWLParamSet>::const_iterator finder = mParamList.find(key);
 	if(finder == mParamList.end())
 	{
-		mParamList[name].setAll(param);
+		mParamList[key].setAll(param);
 		return TRUE;
 	}
 	else
@@ -457,105 +597,88 @@ BOOL LLWLParamManager::addParamSet(const std::string& name, LLSD const & param)
 	}
 }
 
-bool LLWLParamManager::getParamSet(const std::string& name, LLWLParamSet& param)
+bool LLWLParamManager::getParamSet(const LLWLParamKey& key, LLWLParamSet& param)
 {
 	// find it and set it
-	std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name);
+	std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = mParamList.find(key);
 	if(mIt != mParamList.end()) 
 	{
-		param = mParamList[name];
-		param.mName = name;
+		param = mParamList[key];
+		param.mName = key.name;
 		return true;
 	}
 
 	return false;
 }
 
-bool LLWLParamManager::setParamSet(const std::string& name, LLWLParamSet& param)
+bool LLWLParamManager::setParamSet(const LLWLParamKey& key, LLWLParamSet& param)
 {
-	mParamList[name] = param;
+	mParamList[key] = param;
 
 	return true;
 }
 
-bool LLWLParamManager::setParamSet(const std::string& name, const LLSD & param)
+bool LLWLParamManager::setParamSet(const LLWLParamKey& key, const LLSD & param)
 {
 	// quick, non robust (we won't be working with files, but assets) check
+	// this might not actually be true anymore....
 	if(!param.isMap()) 
 	{
 		return false;
 	}
 	
-	mParamList[name].setAll(param);
+	mParamList[key].setAll(param);
 
 	return true;
 }
 
-bool LLWLParamManager::removeParamSet(const std::string& name, bool delete_from_disk)
+void LLWLParamManager::removeParamSet(const LLWLParamKey& key, bool delete_from_disk)
 {
 	// remove from param list
-	std::map<std::string, LLWLParamSet>::iterator mIt = mParamList.find(name);
+	std::map<LLWLParamKey, LLWLParamSet>::iterator mIt = mParamList.find(key);
 	if(mIt != mParamList.end()) 
 	{
 		mParamList.erase(mIt);
 	}
-
-	F32 key;
-
-	// remove all references
-	bool stat = true;
-	do 
+	else
 	{
-		// get it
-		stat = mDay.getKey(name, key);
-		if(stat == false) 
-		{
-			break;
-		}
+		LL_WARNS("WindLight") << "Unable to delete key " << key.toString() << "; not found." << LL_ENDL;
+	}
 
-		// and remove
-		stat = mDay.removeKey(key);
+	mDay.removeReferencesTo(key);
 
-	} while(stat == true);
-	
-	if(delete_from_disk)
+	if(delete_from_disk && key.scope == LLWLParamKey::SCOPE_LOCAL)
 	{
 		std::string path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));
 		
 		// use full curl escaped name
-		char * curl_str = curl_escape(name.c_str(), name.size());
+		char * curl_str = curl_escape(key.name.c_str(), key.name.size());
 		std::string escaped_name(curl_str);
 		curl_free(curl_str);
 		curl_str = NULL;
 		
-		gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml");
+		if(gDirUtilp->deleteFilesInDir(path_name, escaped_name + ".xml") < 1)
+		{
+			LL_WARNS("WindLight") << "Unable to delete key " << key.toString() << " from disk; not found." << LL_ENDL;
+		}
 	}
-
-	return true;
 }
 
 
-// static
-LLWLParamManager * LLWLParamManager::instance()
+// virtual static
+void LLWLParamManager::initSingleton()
 {
-	if(NULL == sInstance)
-	{
-		sInstance = new LLWLParamManager();
+	loadPresets(LLStringUtil::null);
 
-		sInstance->loadPresets(LLStringUtil::null);
+	// load the day
+	mDay.loadDayCycleFromFile(std::string("Default.xml"));
 
-		// load the day
-		sInstance->mDay.loadDayCycle(std::string("Default.xml"));
+	// *HACK - sets cloud scrolling to what we want... fix this better in the future
+	getParamSet(LLWLParamKey("Default", LLWLParamKey::SCOPE_LOCAL), mCurParams);
 
-		// *HACK - sets cloud scrolling to what we want... fix this better in the future
-		sInstance->getParamSet("Default", sInstance->mCurParams);
-
-		// set it to noon
-		sInstance->resetAnimator(0.5, true);
-
-		// but use linden time sets it to what the estate is
-		sInstance->mAnimator.mUseLindenTime = true;
-	}
+	// set it to noon
+	resetAnimator(0.5, true);
 
-	return sInstance;
+	// but use linden time sets it to what the estate is
+	mAnimator.setTimeType(LLWLAnimator::TIME_LINDEN);
 }
diff --git a/indra/newview/llwlparammanager.h b/indra/newview/llwlparammanager.h
index 8c6329e7697884a959b2b524c8967f997314b3a0..1951366939826e0204efc234fe222bc7b97d3a88 100644
--- a/indra/newview/llwlparammanager.h
+++ b/indra/newview/llwlparammanager.h
@@ -2,25 +2,31 @@
  * @file llwlparammanager.h
  * @brief Implementation for the LLWLParamManager class.
  *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
  * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  */
 
@@ -29,10 +35,12 @@
 
 #include <vector>
 #include <map>
+#include "llenvmanager.h"
 #include "llwlparamset.h"
 #include "llwlanimator.h"
 #include "llwldaycycle.h"
 #include "llviewercamera.h"
+#include "lltrans.h"
 
 class LLGLSLShader;
  
@@ -72,7 +80,7 @@ struct WLColorControl {
 		r = val.mV[0];
 		g = val.mV[1];
 		b = val.mV[2];
-		i = val.mV[3];		
+		i = val.mV[3];
 		return *this;
 	}
 
@@ -115,25 +123,110 @@ struct WLFloatControl {
 	}
 };
 
-/// WindLight parameter manager class - what controls all the wind light shaders
-class LLWLParamManager
+struct LLWLParamKey : LLEnvKey
 {
 public:
+	// scope and source of a param set (WL sky preset)
+	std::string name;
+	EScope scope;
 
-	LLWLParamManager();
-	~LLWLParamManager();
+	// for conversion from LLSD
+	static const int NAME_IDX = 0;
+	static const int SCOPE_IDX = 1;
+
+	inline LLWLParamKey(const std::string& n, EScope s)
+		: name(n), scope(s)
+	{
+	}
 
+	inline LLWLParamKey(LLSD llsd)
+		: name(llsd[NAME_IDX].asString()), scope(EScope(llsd[SCOPE_IDX].asInteger()))
+	{
+	}
+
+	inline LLWLParamKey() // NOT really valid, just so std::maps can return a default of some sort
+		: name(NULL), scope(SCOPE_LOCAL)
+	{
+	}
+
+	inline LLWLParamKey(std::string& stringVal)
+		: name(stringVal.substr(0, stringVal.length()-1)),
+		  scope((EScope)atoi(stringVal.substr(stringVal.length()-1, stringVal.length()).c_str()))
+	{
+	}
+
+	inline std::string toStringVal() const
+	{
+		std::stringstream str;
+		str << name << scope;
+		return str.str();
+	}
+
+	inline LLSD toLLSD() const
+	{
+		LLSD llsd = LLSD::emptyArray();
+		llsd.append(LLSD(name));
+		llsd.append(LLSD(scope));
+		return llsd;
+	}
+
+	inline bool operator <(const LLWLParamKey other) const
+	{
+		if (name < other.name)
+		{	
+			return true;
+		}
+		else if (name > other.name)
+		{
+			return false;
+		}
+		else
+		{
+			return scope < other.scope;
+		}
+	}
+
+	inline bool operator ==(const LLWLParamKey other) const
+	{
+		return (name == other.name) && (scope == other.scope);
+	}
+
+	inline std::string toString() const
+	{
+		switch (scope)
+		{
+		case SCOPE_LOCAL:
+			return name + std::string(" (") + LLTrans::getString("Local") + std::string(")");
+			break;
+		case SCOPE_REGION:
+			return name + std::string(" (") + LLTrans::getString("Region") + std::string(")");
+			break;
+		default:
+			return name + " (?)";
+		}
+	}
+};
+
+/// WindLight parameter manager class - what controls all the wind light shaders
+class LLWLParamManager : public LLSingleton<LLWLParamManager>
+{
+public:
 	/// load a preset file
 	void loadPresets(const std::string & fileName);
 
 	/// save the preset file
+	// the implementation of this method was unmaintained and is commented out
+	// *NOTE test and sanity-check before uncommenting and using!
 	void savePresets(const std::string & fileName);
 
 	/// load an individual preset into the sky
-	void loadPreset(const std::string & name,bool propogate=true);
+	void loadPreset(const LLWLParamKey key, bool propogate=true);
+
+	/// load an individual preset from a stream of XML
+	void loadPresetFromXML(const LLWLParamKey key, std::istream & presetXML);
 
 	/// save the parameter presets to file
-	void savePreset(const std::string & name);
+	void savePreset(const LLWLParamKey key);
 
 	/// Set shader uniforms dirty, so they'll update automatically.
 	void propagateParameters(void);
@@ -161,36 +254,38 @@ class LLWLParamManager
 
 	/// get the radius of the dome
 	inline F32 getDomeRadius(void) const;
-
-	/// Perform global initialization for this class.
-	static void initClass(void);
-
-	// Cleanup of global data that's only inited once per class.
-	static void cleanupClass();
 	
-	/// add a param to the list
-	bool addParamSet(const std::string& name, LLWLParamSet& param);
+	/// add a param set (preset) to the list
+	bool addParamSet(const LLWLParamKey& key, LLWLParamSet& param);
 
-	/// add a param to the list
-	BOOL addParamSet(const std::string& name, LLSD const & param);
+	/// add a param set (preset) to the list
+	BOOL addParamSet(const LLWLParamKey& key, LLSD const & param);
 
-	/// get a param from the list
-	bool getParamSet(const std::string& name, LLWLParamSet& param);
+	/// get a param set (preset) from the list
+	bool getParamSet(const LLWLParamKey& key, LLWLParamSet& param);
 
 	/// set the param in the list with a new param
-	bool setParamSet(const std::string& name, LLWLParamSet& param);
+	bool setParamSet(const LLWLParamKey& key, LLWLParamSet& param);
 	
 	/// set the param in the list with a new param
-	bool setParamSet(const std::string& name, LLSD const & param);	
-
+	bool setParamSet(const LLWLParamKey& key, LLSD const & param);
+	
 	/// gets rid of a parameter and any references to it
-	/// returns true if successful
-	bool removeParamSet(const std::string& name, bool delete_from_disk);
+	/// ignores "delete_from_disk" if the scope is not local
+	void removeParamSet(const LLWLParamKey& key, bool delete_from_disk);
 
-	// singleton pattern implementation
-	static LLWLParamManager * instance();
+	/// clear parameter mapping of a given scope
+	void clearParamSetsOfScope(LLEnvKey::EScope scope);
 
-public:
+	/// add all skies in LLSD using the given scope
+	void addAllSkies(LLEnvKey::EScope scope, const LLSD& preset_map);
+
+	// returns all skies referenced by the current day cycle (in mDay), with their final names
+	// side effect: applies changes to all internal structures!  (trashes all unreferenced skies in scope, keys in day cycle rescoped to scope, etc.)
+	std::map<LLWLParamKey, LLWLParamSet> finalizeFromDayCycle(LLWLParamKey::EScope scope);
+
+	// returns all skies in map (intended to be called with output from a finalize)
+	LLSD createSkyMap(std::map<LLWLParamKey, LLWLParamSet> map);
 
 	// helper variables
 	LLWLAnimator mAnimator;
@@ -244,13 +339,13 @@ class LLWLParamManager
 	F32 mDomeRadius;
 	
 	// list of all the parameters, listed by name
-	std::map<std::string, LLWLParamSet> mParamList;
-	
+	std::map<LLWLParamKey, LLWLParamSet> mParamList;
 	
 private:
-	// our parameter manager singleton instance
-	static LLWLParamManager * sInstance;
-
+	friend class LLSingleton<LLWLParamManager>;
+	/*virtual*/ void initSingleton();
+	LLWLParamManager();
+	~LLWLParamManager();
 };
 
 inline F32 LLWLParamManager::getDomeOffset(void) const
diff --git a/indra/newview/llwlparamset.cpp b/indra/newview/llwlparamset.cpp
index cf06766d7373a2f8204105240f429abf9cea4946..a027d635e61f9558352da5020a3b8ce3ad4f7a8d 100644
--- a/indra/newview/llwlparamset.cpp
+++ b/indra/newview/llwlparamset.cpp
@@ -31,6 +31,7 @@
 
 #include "llfloaterwindlight.h"
 #include "llwlparammanager.h"
+#include "llglslshader.h"
 #include "lluictrlfactory.h"
 #include "llsliderctrl.h"
 
@@ -94,7 +95,7 @@ void LLWLParamSet::update(LLGLSLShader * shader) const
 			
 			shader->uniform4fv(param, 1, val.mV);	
 		} 
-		else 
+		else // param is the uniform name
 		{
 			LLVector4 val;
 			
@@ -119,7 +120,6 @@ void LLWLParamSet::update(LLGLSLShader * shader) const
 				val.mV[0] = i->second.asBoolean();
 			}
 			
-			
 			shader->uniform4fv(param, 1, val.mV);
 		}
 	}
@@ -260,7 +260,6 @@ void LLWLParamSet::setEastAngle(float val)
 void LLWLParamSet::mix(LLWLParamSet& src, LLWLParamSet& dest, F32 weight)
 {
 	// set up the iterators
-	LLSD::map_iterator cIt = mParamValues.beginMap();
 
 	// keep cloud positions and coverage the same
 	/// TODO masking will do this later
@@ -273,55 +272,39 @@ void LLWLParamSet::mix(LLWLParamSet& src, LLWLParamSet& dest, F32 weight)
 	LLSD srcVal;
 	LLSD destVal;
 
-	// do the interpolation for all the ones saved as vectors
-	// skip the weird ones
-	for(; cIt != mParamValues.endMap(); cIt++) {
+	// Iterate through values
+	for(LLSD::map_iterator iter = mParamValues.beginMap(); iter != mParamValues.endMap(); ++iter)
+	{
 
-		// check params to make sure they're actually there
-		if(src.mParamValues.has(cIt->first))
+		// If param exists in both src and dest, set the holder variables, otherwise skip
+		if(src.mParamValues.has(iter->first) && dest.mParamValues.has(iter->first))
 		{
-			srcVal = src.mParamValues[cIt->first];
+			srcVal = src.mParamValues[iter->first];
+			destVal = dest.mParamValues[iter->first];
 		}
 		else
 		{
 			continue;
 		}
 		
-		if(dest.mParamValues.has(cIt->first))
+		if(iter->second.isReal())									// If it's a real, interpolate directly
 		{
-			destVal = dest.mParamValues[cIt->first];
+			iter->second = srcVal.asReal() + ((destVal.asReal() - srcVal.asReal()) * weight);
 		}
-		else
-		{
-			continue;
-		}		
-				
-		// skip if not a vector
-		if(!cIt->second.isArray()) 
-		{
-			continue;
-		}
-
-		// only Real vectors allowed
-		if(!cIt->second[0].isReal()) 
+		else if(iter->second.isArray() && iter->second[0].isReal()	// If it's an array of reals, loop through the reals and interpolate on those
+				&& iter->second.size() == srcVal.size() && iter->second.size() == destVal.size())
 		{
-			continue;
+			// Actually do interpolation: old value + (difference in values * factor)
+			for(int i=0; i < iter->second.size(); ++i) 
+			{
+				// iter->second[i] = (1.f-weight)*(F32)srcVal[i].asReal() + weight*(F32)destVal[i].asReal();	// old way of doing it -- equivalent but one more operation
+				iter->second[i] = srcVal[i].asReal() + ((destVal[i].asReal() - srcVal[i].asReal()) * weight);
+			}
 		}
-		
-		// make sure all the same size
-		if(	cIt->second.size() != srcVal.size() ||
-			cIt->second.size() != destVal.size())
+		else														// Else, skip
 		{
 			continue;
-		}
-		
-		// more error checking might be necessary;
-		
-		for(int i=0; i < cIt->second.size(); ++i) 
-		{
-			cIt->second[i] = (1.0f - weight) * (F32) srcVal[i].asReal() + 
-				weight * (F32) destVal[i].asReal();
-		}
+		}		
 	}
 
 	// now mix the extra parameters
diff --git a/indra/newview/llwlparamset.h b/indra/newview/llwlparamset.h
index 487e2bf9225bdfc6c99515b98313399575b7d3bd..13585020328431b501eaa9f6037d564e85525c3b 100644
--- a/indra/newview/llwlparamset.h
+++ b/indra/newview/llwlparamset.h
@@ -32,10 +32,10 @@
 
 #include "v4math.h"
 #include "v4color.h"
-#include "llviewershadermgr.h"
 
 class LLFloaterWindLight;
 class LLWLParamSet;
+class LLGLSLShader;
 
 /// A class representing a set of parameter values for the WindLight shaders.
 class LLWLParamSet {
diff --git a/indra/newview/tests/lldir_stub.cpp b/indra/newview/tests/lldir_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6646860b5e3014dedc9be556caa4f286eee1f1dd
--- /dev/null
+++ b/indra/newview/tests/lldir_stub.cpp
@@ -0,0 +1,45 @@
+/** 
+ * @file lldir_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Use me only if you need to stub out some helper functions, not if you e.g. need sane numbers from countFilesInDir
+
+LLDir::LLDir() {}
+LLDir::~LLDir() {}
+BOOL LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) { return true; }
+void LLDir::setChatLogsDir(const std::string &path) {}
+void LLDir::setPerAccountChatLogsDir(const std::string &first, const std::string &last) {}
+void LLDir::setLindenUserDir(const std::string &first, const std::string &last) {}
+void LLDir::setSkinFolder(const std::string &skin_folder) {}
+bool LLDir::setCacheDir(const std::string &path) { return true; }
+void LLDir::dumpCurrentDirectories() {}
+
+class LLDir_stub : public LLDir
+{
+public:
+	LLDir_stub() {}
+	~LLDir_stub() {}
+
+	/*virtual*/ void initAppDirs(const std::string &app_name) {}
+
+	/*virtual*/ std::string getCurPath() { return "CUR_PATH_FROM_LLDIR"; }
+	/*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask) { return 42; }
+	/*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap) { fname = fname + "_NEXT"; return false; }
+	/*virtual*/ void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) { fname = "RANDOM_FILE"; }
+	/*virtual*/ BOOL fileExists(const std::string &filename) const { return false; }
+};
+
+LLDir_stub gDirUtil;
+
+LLDir* gDirUtilp = &gDirUtil;
+
+std::string LLDir::getExpandedFilename(ELLPath loc, const std::string& subdir, const std::string& filename) const
+{
+	return subdir + " --- " + filename + " --- expanded!";
+}
+
diff --git a/indra/newview/tests/llfloaterdaycycle_stub.cpp b/indra/newview/tests/llfloaterdaycycle_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e6b145bcfc0068a3edde317d6ac1d14f34d4584a
--- /dev/null
+++ b/indra/newview/tests/llfloaterdaycycle_stub.cpp
@@ -0,0 +1,20 @@
+/** 
+ * @file llfloaterdaycycle_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+class LLFloaterDayCycle
+{
+public:
+	static bool isOpen(void);
+	static LLFloaterDayCycle* instance(void);
+	static void syncMenu(void);
+};
+
+bool LLFloaterDayCycle::isOpen() { return true; }
+LLFloaterDayCycle* LLFloaterDayCycle::instance() { return NULL; }
+void LLFloaterDayCycle::syncMenu(void) {}
diff --git a/indra/newview/tests/llfloaterenvsettings_stub.cpp b/indra/newview/tests/llfloaterenvsettings_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e9e792521f7281478eddc5b83131b51143b82b44
--- /dev/null
+++ b/indra/newview/tests/llfloaterenvsettings_stub.cpp
@@ -0,0 +1,20 @@
+/** 
+ * @file llfloaterenvsettings_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+class LLFloaterEnvSettings
+{
+public:
+	static bool isOpen(void);
+	static LLFloaterEnvSettings* instance(void);
+	void syncMenu(void);
+};
+
+bool LLFloaterEnvSettings::isOpen() { return true; }
+LLFloaterEnvSettings* LLFloaterEnvSettings::instance() { return NULL; }
+void LLFloaterEnvSettings::syncMenu(void) {}
diff --git a/indra/newview/tests/llfloaterwindlight_stub.cpp b/indra/newview/tests/llfloaterwindlight_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f1891eaf21724f4f9d1706c7e97f8ebc4bf032e6
--- /dev/null
+++ b/indra/newview/tests/llfloaterwindlight_stub.cpp
@@ -0,0 +1,20 @@
+/** 
+ * @file llfloaterwindlight_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+class LLFloaterWindLight
+{
+public:
+	static bool isOpen(void);
+	static LLFloaterWindLight* instance(void);
+	void syncMenu(void);
+};
+
+bool LLFloaterWindLight::isOpen() { return true; }
+LLFloaterWindLight* LLFloaterWindLight::instance() { return NULL; }
+void LLFloaterWindLight::syncMenu(void) {}
diff --git a/indra/newview/tests/llglslshader_stub.cpp b/indra/newview/tests/llglslshader_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5333c8a361331a5e9f6f8cf3973b97d29f442d2a
--- /dev/null
+++ b/indra/newview/tests/llglslshader_stub.cpp
@@ -0,0 +1,22 @@
+/** 
+ * @file llglslshader_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "llglslshader.h"
+
+void LLGLSLShader::uniform1f(const std::string& uniform, F32 num)
+{
+}
+
+void LLGLSLShader::uniform3fv(const std::string& uniform, U32 count, const GLfloat *v)
+{
+}
+
+void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v)
+{
+}
diff --git a/indra/newview/tests/llpipeline_stub.cpp b/indra/newview/tests/llpipeline_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..85bf0ae3fb3540282f4a81188dcda97f56d132ca
--- /dev/null
+++ b/indra/newview/tests/llpipeline_stub.cpp
@@ -0,0 +1,15 @@
+/** 
+ * @file llpipeline_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+class LLPipeline
+{
+public: BOOL canUseWindLightShaders() const;
+};
+BOOL LLPipeline::canUseWindLightShaders() const {return TRUE;}
+LLPipeline gPipeline;
diff --git a/indra/newview/tests/llsky_stub.cpp b/indra/newview/tests/llsky_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..35f4944a950199705c4a330079230a4f9cc4bedc
--- /dev/null
+++ b/indra/newview/tests/llsky_stub.cpp
@@ -0,0 +1,20 @@
+/**
+ * @file llsky_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+class LLSky
+{
+public:
+	void setOverrideSun(BOOL override);
+	void setSunDirection(const LLVector3 &sun_direction, const LLVector3 &sun_ang_velocity);
+};
+
+void LLSky::setOverrideSun(BOOL override) {}
+void LLSky::setSunDirection(const LLVector3 &sun_direction, const LLVector3 &sun_ang_velocity) {}
+
+LLSky gSky;
diff --git a/indra/newview/tests/llviewershadermgr_stub.cpp b/indra/newview/tests/llviewershadermgr_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0dae527035bb05fbf01f6d6895a06eee58532b8d
--- /dev/null
+++ b/indra/newview/tests/llviewershadermgr_stub.cpp
@@ -0,0 +1,33 @@
+/** 
+ * @file llglslshader_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "../llviewershadermgr.h"
+
+LLShaderMgr::LLShaderMgr() {}
+LLShaderMgr::~LLShaderMgr() {}
+
+LLViewerShaderMgr::LLViewerShaderMgr() {}
+LLViewerShaderMgr::~LLViewerShaderMgr() {}
+
+LLViewerShaderMgr* stub_instance = NULL;
+
+LLViewerShaderMgr* LLViewerShaderMgr::instance() {
+	if(NULL == stub_instance)
+	{
+		stub_instance = new LLViewerShaderMgr();
+	}
+
+	return stub_instance;
+}
+LLViewerShaderMgr::shader_iter fake_iter;
+LLViewerShaderMgr::shader_iter LLViewerShaderMgr::beginShaders() const {return fake_iter;}
+LLViewerShaderMgr::shader_iter LLViewerShaderMgr::endShaders() const {return fake_iter;}
+
+void LLViewerShaderMgr::updateShaderUniforms(LLGLSLShader* shader) {return;}
+std::string LLViewerShaderMgr::getShaderDirPrefix() {return "SHADER_DIR_PREFIX-";}
diff --git a/indra/newview/tests/llwlanimator_stub.cpp b/indra/newview/tests/llwlanimator_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4d1bb85544a0d1bb7528af3cbc62a11c231834fe
--- /dev/null
+++ b/indra/newview/tests/llwlanimator_stub.cpp
@@ -0,0 +1,12 @@
+/** 
+ * @file llwlanimator_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+LLWLAnimator::LLWLAnimator(void) {}
+void LLWLAnimator::update(LLWLParamSet& set) {}
+void LLWLAnimator::setTrack(std::map<F32, LLWLParamKey>& track, F32 dayRate, F64 dayTime, bool run) {}
diff --git a/indra/newview/tests/llwldaycycle_stub.cpp b/indra/newview/tests/llwldaycycle_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d98c9614b40f9beecad4fb4122d88c2510530ef3
--- /dev/null
+++ b/indra/newview/tests/llwldaycycle_stub.cpp
@@ -0,0 +1,35 @@
+/** 
+ * @file llwldaycycle_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+LLWLDayCycle::LLWLDayCycle(void)
+{
+}
+
+LLWLDayCycle::~LLWLDayCycle(void)
+{
+}
+
+bool LLWLDayCycle::getKeytime(LLWLParamKey keyFrame, F32& keyTime)
+{
+	keyTime = 0.5;
+	return true;
+}
+
+bool LLWLDayCycle::removeKeyframe(F32 time)
+{
+	return true;
+}
+
+void LLWLDayCycle::loadDayCycleFromFile(const std::string& fileName)
+{
+}
+
+void LLWLDayCycle::removeReferencesTo(const LLWLParamKey &keyframe)
+{
+}
diff --git a/indra/newview/tests/llwlparammanager_test.cpp b/indra/newview/tests/llwlparammanager_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3d3156733560ad705685e9502bc2761877a25409
--- /dev/null
+++ b/indra/newview/tests/llwlparammanager_test.cpp
@@ -0,0 +1,257 @@
+/** 
+ * @file llwlparammanager_test.cpp
+ * @brief LLWLParamManager tests
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled headers
+#include "../llviewerprecompiledheaders.h"
+
+// Class to test
+#include "../llwlparammanager.h"
+
+// Dependencies
+#include "linden_common.h"
+
+// TUT header
+#include "lltut.h"
+
+// Stubs
+#include "llwldaycycle_stub.cpp"
+#include "llwlparamset_stub.cpp"
+#include "llwlanimator_stub.cpp"
+#include "llglslshader_stub.cpp"
+#include "lldir_stub.cpp"
+#include "llsky_stub.cpp"
+#include "llfloaterdaycycle_stub.cpp"
+#include "llfloaterenvsettings_stub.cpp"
+#include "llfloaterwindlight_stub.cpp"
+#include "llpipeline_stub.cpp"
+#include "llviewershadermgr_stub.cpp"
+
+void assert_glerror(void) {}
+LLViewerCamera::LLViewerCamera() {}
+void LLViewerCamera::setView(F32 vertical_fov_rads) {}
+std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args) { return std::string(""); }
+
+char* curl_unescape(const char* c_str, int length)
+{
+	char* copy = new char[length+4];
+	memcpy(copy, c_str, length);
+	copy[length+0] = 'E';
+	copy[length+1] = 'S';
+	copy[length+2] = 'C';
+	copy[length+3] = '\0';
+	return copy;
+}
+void curl_free(void* p) {delete[] ((char*)p);}
+char* curl_escape(const char* c_str, int length) {
+	char* copy = new char[length+6];
+	memcpy(copy, c_str, length);
+	copy[length+0] = 'U';
+	copy[length+1] = 'N';
+	copy[length+2] = 'E';
+	copy[length+3] = 'S';
+	copy[length+4] = 'C';
+	copy[length+5] = '\0';
+	return copy;
+}
+
+namespace tut
+{
+	// Main Setup
+	struct LLWLParamManagerFixture
+	{
+		class LLWLParamManagerTest
+		{
+		};
+
+		LLWLParamManager* mTestManager;
+
+		LLWLParamManagerFixture()
+			: mTestManager(LLWLParamManager::getInstance())
+		{
+		}
+
+		~LLWLParamManagerFixture()
+		{
+		}
+	};
+	typedef test_group<LLWLParamManagerFixture> factory;
+	typedef factory::object object;
+	factory tf("LLWLParamManager test");
+
+	// Tests
+	template<> template<>
+	void object::test<1>()
+	{
+		try
+		{
+			std::string preset =
+			"<llsd>\
+				<map>\
+				<key>ambient</key>\
+					<array>\
+						<real>1.0499999523162842</real>\
+						<real>1.0499999523162842</real>\
+						<real>1.0499999523162842</real>\
+						<real>0.34999999403953552</real>\
+					</array>\
+				<key>blue_density</key>\
+					<array>\
+						<real>0.2447581488182351</real>\
+						<real>0.44872328639030457</real>\
+						<real>0.75999999046325684</real>\
+						<real>0.38000004053115788</real>\
+					</array>\
+				<key>blue_horizon</key>\
+					<array>\
+						<real>0.49548382097675159</real>\
+						<real>0.49548381382419748</real>\
+						<real>0.63999999284744291</real>\
+						<real>0.31999999642372146</real>\
+					</array>\
+				<key>cloud_color</key>\
+					<array>\
+						<real>0.40999999165535073</real>\
+						<real>0.40999999165535073</real>\
+						<real>0.40999999165535073</real>\
+						<real>0.40999999165535073</real>\
+					</array>\
+				<key>cloud_pos_density1</key>\
+					<array>\
+						<real>1.6884100437164307</real>\
+						<real>0.52609699964523315</real>\
+						<real>0.99999999999999289</real>\
+						<real>1</real>\
+					</array>\
+				<key>cloud_pos_density2</key>\
+					<array>\
+						<real>1.6884100437164307</real>\
+						<real>0.52609699964523315</real>\
+						<real>0.125</real>\
+						<real>1</real>\
+					</array>\
+				<key>cloud_scale</key>\
+					<array>\
+						<real>0.4199999868869746</real>\
+						<real>0</real>\
+						<real>0</real>\
+						<real>1</real>\
+					</array>\
+				<key>cloud_scroll_rate</key>\
+					<array>\
+						<real>10.199999809265137</real>\
+						<real>10.01099967956543</real>\
+					</array>\
+				<key>cloud_shadow</key>\
+					<array>\
+						<real>0.26999998092651367</real>\
+						<real>0</real>\
+						<real>0</real>\
+						<real>1</real>\
+					</array>\
+				<key>density_multiplier</key>\
+					<array>\
+						<real>0.00017999998817685818</real>\
+						<real>0</real>\
+						<real>0</real>\
+						<real>1</real>\
+					</array>\
+				<key>distance_multiplier</key>\
+					<array>\
+						<real>0.80000001192093606</real>\
+						<real>0</real>\
+						<real>0</real>\
+						<real>1</real>\
+					</array>\
+				<key>east_angle</key>\
+					<real>0</real>\
+				<key>enable_cloud_scroll</key>\
+					<array>\
+						<boolean>1</boolean>\
+						<boolean>1</boolean>\
+					</array>\
+				<key>gamma</key>\
+					<array>\
+						<real>1</real>\
+						<real>0</real>\
+						<real>0</real>\
+						<real>1</real>\
+					</array>\
+				<key>glow</key>\
+					<array>\
+						<real>5</real>\
+						<real>0.0010000000474974513</real>\
+						<real>-0.47999998927116394</real>\
+						<real>1</real>\
+					</array>\
+				<key>haze_density</key>\
+					<array>\
+						<real>0.69999998807907104</real>\
+						<real>0</real>\
+						<real>0</real>\
+						<real>1</real>\
+					</array>\
+				<key>haze_horizon</key>\
+					<array>\
+						<real>0.18999999761581243</real>\
+						<real>0.19915600121021271</real>\
+						<real>0.19915600121021271</real>\
+						<real>1</real>\
+					</array>\
+				<key>lightnorm</key>\
+					<array>\
+						<real>0</real>\
+						<real>0.70710659027099609</real>\
+						<real>-0.70710694789886475</real>\
+						<real>0</real>\
+					</array>\
+				<key>max_y</key>\
+					<array>\
+						<real>1605</real>\
+						<real>0</real>\
+						<real>0</real>\
+						<real>1</real>\
+					</array>\
+				<key>preset_num</key>\
+					<integer>22</integer>\
+				<key>star_brightness</key>\
+					<real>0</real>\
+				<key>sun_angle</key>\
+					<real>2.3561947345733643</real>\
+				<key>sunlight_color</key>\
+					<array>\
+						<real>0.73421055078505759</real>\
+						<real>0.78157895803450828</real>\
+						<real>0.89999997615813498</real>\
+						<real>0.29999998211860301</real>\
+					</array>\
+				</map>\
+			</llsd>";
+
+			std::stringstream preset_stream(preset);
+			mTestManager->loadPresetFromXML(LLWLParamKey("test1", LLWLParamKey::SCOPE_LOCAL), preset_stream);
+			LLWLParamSet dummy;
+			ensure("Couldn't get ParamSet after loading it", mTestManager->getParamSet(LLWLParamKey("test1", LLWLParamKey::SCOPE_LOCAL), dummy));
+		}
+		catch (...)
+		{
+			fail("loadPresetFromXML test crashed!");
+		}
+	}
+
+	template<> template<>
+	void object::test<2>()
+	{
+		mTestManager->propagateParameters();
+		ensure_equals("Wrong value from getDomeOffset()", mTestManager->getDomeOffset(), 0.96f);
+		ensure_equals("Wrong value from getDomeRadius()", mTestManager->getDomeRadius(), 15000.f);
+		ensure_equals("Wrong value from getLightDir()", mTestManager->getLightDir(), LLVector4(-0,0,1,0));
+		ensure_equals("Wrong value from getClampedLightDir()", mTestManager->getClampedLightDir(), LLVector4(-0,0,1,0));
+		ensure_equals("Wrong value from getRotatedLightDir()", mTestManager->getRotatedLightDir(), LLVector4(0,0,0,1));
+	}
+}
diff --git a/indra/newview/tests/llwlparamset_stub.cpp b/indra/newview/tests/llwlparamset_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ce4b5827d71e7a346d85713d8215b294f2a7cfd
--- /dev/null
+++ b/indra/newview/tests/llwlparamset_stub.cpp
@@ -0,0 +1,24 @@
+/** 
+ * @file llwlparamset_stub.cpp
+ * @brief  stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+LLWLParamSet::LLWLParamSet(void)
+{
+}
+
+void LLWLParamSet::updateCloudScrolling()
+{
+}
+
+void LLWLParamSet::set(const std::string& name, const LLVector4& val)
+{
+}
+
+void LLWLParamSet::update(LLGLSLShader *shader) const
+{
+}