diff --git a/build.sh b/build.sh
index c7c89fe3c2bdc40376b04230c94f1e8defe4937a..7c11308f0c8168ae52cd9f2e6266efb544c99987 100755
--- a/build.sh
+++ b/build.sh
@@ -132,10 +132,6 @@ if test -f scripts/update_version_files.py ; then
   end_section UpdateVer
 fi
 
-# Now retrieve the version for use in the version manager
-# First three parts only, $revision will be appended automatically.
-build_viewer_update_version_manager_version=`python scripts/get_version.py --viewer-version | sed 's/\.[0-9]*$//'`
-
 if [ -z "$AUTOBUILD" ]
 then
   export autobuild_dir="$here/../../../autobuild/bin/"
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 3851e62cfbdae7aa8137087a910a1adc6ae8fc21..5a24c43d5a8b4dd425a7afc315ccc549c12682f0 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -396,6 +396,8 @@ Frontera Thor
 Fury Rosewood
 Gaberoonie Zanzibar
 Ganymedes Costagravas
+Geenz Spad
+	STORM-1823
 Gene Frostbite
 GeneJ Composer
 Geneko Nemeth
@@ -622,6 +624,8 @@ Jonathan Yap
 	STORM-1796
 	STORM-1807
 	STORM-1808
+	STORM-637
+	STORM-1822
 	STORM-1809
 	STORM-1793
 	STORM-1810
@@ -868,6 +872,7 @@ Nicky Perian
 	OPEN-1
 	STORM-1087
 	STORM-1090
+	STORM-1828
 Nicoladie Gymnast
 Nounouch Hapmouche
 	VWR-238
@@ -1187,6 +1192,8 @@ Unlikely Quintessa
 UsikuFarasi Kanarik
 Vadim Bigbear
 	VWR-2681
+Vaalith Jinn
+    STORM-64
 Vector Hastings
 	VWR-8726
 Veritas Raymaker
diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp
index 8d493ecde0b6a9937a9624f6aa44efd1bf220811..294f68b1220cf0ad761a8f4daad227147007c9e0 100644
--- a/indra/llimage/llimagepng.cpp
+++ b/indra/llimage/llimagepng.cpp
@@ -60,6 +60,12 @@ BOOL LLImagePNG::updateData()
 
 	// Decode the PNG data and extract sizing information
 	LLPngWrapper pngWrapper;
+	if (!pngWrapper.isValidPng(getData()))
+	{
+		setLastError("LLImagePNG data does not have a valid PNG header!");
+		return FALSE;
+	}
+
 	LLPngWrapper::ImageInfo infop;
 	if (! pngWrapper.readPng(getData(), NULL, &infop))
 	{
@@ -90,6 +96,12 @@ BOOL LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time)
 
 	// Decode the PNG data into the raw image
 	LLPngWrapper pngWrapper;
+	if (!pngWrapper.isValidPng(getData()))
+	{
+		setLastError("LLImagePNG data does not have a valid PNG header!");
+		return FALSE;
+	}
+
 	if (! pngWrapper.readPng(getData(), raw_image))
 	{
 		setLastError(pngWrapper.getErrorMessage());
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 64fa35543d36abfd7fc0db8fa100cfbf6cb53701..7e6ffb35c3eb128d4f95528dded9df07bb340d37 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -303,6 +303,7 @@ set(viewer_SOURCE_FILES
     lllistbrowser.cpp
     lllistcontextmenu.cpp
     lllistview.cpp
+    lllocalbitmaps.cpp
     lllocaltextureobject.cpp
     lllocationhistory.cpp
     lllocationinputctrl.cpp
@@ -858,6 +859,7 @@ set(viewer_HEADER_FILES
     lllistbrowser.h
     lllistcontextmenu.h
     lllistview.h
+    lllocalbitmaps.h
     lllocaltextureobject.h
     lllocationhistory.h
     lllocationinputctrl.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 15da381e2f4042f96a451e523c1b430838884aae..05c05b9393e6ebe87e8a3a2a8f2f3ec458a2926d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8239,7 +8239,7 @@
     <key>Type</key>
     <string>U32</string>
     <key>Value</key>
-    <real>128</real>
+    <real>512</real>
   </map>
 
   <key>RenderSpecularResY</key>
@@ -8263,7 +8263,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>8</real>
+    <real>384</real>
   </map>
 
   <key>RenderDeferred</key>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
index 53a2a13392d9f134f1deadf578b418e666d53e66..4d01eeb64e581f09f23b19fa97722643e075d8fd 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -128,7 +128,7 @@ void main()
 				
 				if (sa > 0.0)
 				{
-					sa = texture2D(lightFunc,vec2(sa, spec.a)).r * min(dist_atten*4.0, 1.0);
+					sa = 6 * texture2D(lightFunc, vec2(sa, spec.a)).r * min(dist_atten*4.0, 1.0);
 					sa *= noise;
 					col += da*sa*light_col[i].rgb*spec.rgb;
 				}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
index a5e04fba575c0070c30588aee812ff9a64fca780..19800a8b8e16be7369e3c23376124c79dd45c2b2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -109,7 +109,7 @@ void main()
 		float sa = dot(normalize(lv-normalize(pos)),norm);
 		if (sa > 0.0)
 		{
-			sa = texture2D(lightFunc, vec2(sa, spec.a)).r * min(dist_atten*4.0, 1.0);
+			sa = 6 * texture2D(lightFunc, vec2(sa, spec.a)).r * min(dist_atten*4.0, 1.0);
 			sa *= noise;
 			col += da*sa*color.rgb*spec.rgb;
 		}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index b5501c28203d1a72d43d7355f8d2034fbf9d405e..66e3cf6d13f4a152594985e240743358ee1e6217 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -301,11 +301,11 @@ void main()
 			//
 			vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
 			float sa = dot(refnormpersp, sun_dir.xyz);
-			vec3 dumbshiny = vary_SunlitColor*texture2D(lightFunc, vec2(sa, spec.a)).r;
+			vec3 dumbshiny = vary_SunlitColor*(6 * texture2D(lightFunc, vec2(sa, spec.a)).r);
 			
 			// add the two types of shiny together
 			vec3 spec_contrib = dumbshiny * spec.rgb;
-			bloom = dot(spec_contrib, spec_contrib);
+			bloom = dot(spec_contrib, spec_contrib) / 4;
 			col += spec_contrib;
 
 			//add environmentmap
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 61a7f1e32fe59ea3580e228a05e388408826b4c6..a137bea30f1dc0202cf182c04e3003909fd1221e 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -309,11 +309,11 @@ void main()
 			//
 			vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
 			float sa = dot(refnormpersp, sun_dir.xyz);
-			vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).r;
+			vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*(6 * texture2D(lightFunc, vec2(sa, spec.a)).r);
 
 			// add the two types of shiny together
 			vec3 spec_contrib = dumbshiny * spec.rgb;
-			bloom = dot(spec_contrib, spec_contrib);
+			bloom = dot(spec_contrib, spec_contrib) / 4;
 			col += spec_contrib;
 
 			//add environmentmap
diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp
index 7e50098a173d847e51284c4129b88a63b8daf41b..f943759bb89c66fe1e27d633b60ea195ad307637 100644
--- a/indra/newview/llassetuploadqueue.cpp
+++ b/indra/newview/llassetuploadqueue.cpp
@@ -123,7 +123,9 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder
 			for(LLSD::array_const_iterator line	= compile_errors.beginArray();
 				line < compile_errors.endArray(); line++)
 			{
-				mSupplier->log(line->asString());
+				std::string str = line->asString();
+				str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
+				mSupplier->log(str);
 				llinfos << content["errors"] << llendl;
 			}
 		}
diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp
index a42677845ecc0b7c00254bcb580aba3bc531fdc4..4f5f9e22b69ddfe6ef1256d37bd945ec07b6789b 100644
--- a/indra/newview/llcompilequeue.cpp
+++ b/indra/newview/llcompilequeue.cpp
@@ -100,6 +100,7 @@ BOOL LLFloaterScriptQueue::postBuild()
 {
 	childSetAction("close",onCloseBtn,this);
 	getChildView("close")->setEnabled(FALSE);
+	setVisible(true);
 	return TRUE;
 }
 
@@ -158,7 +159,6 @@ void LLFloaterScriptQueue::addObject(const LLUUID& id)
 
 BOOL LLFloaterScriptQueue::start()
 {
-	//llinfos << "LLFloaterCompileQueue::start()" << llendl;
 	std::string buffer;
 
 	LLSelectMgr *mgr = LLSelectMgr::getInstance();
@@ -178,7 +178,7 @@ BOOL LLFloaterScriptQueue::start()
 	args["[COUNT]"] = llformat ("%d", mObjectIDs.count());
 	buffer = getString ("Starting", args);
 	
-	getChild<LLScrollListCtrl>("queue output")->setCommentText(buffer);
+	getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
 
 	return nextObject();
 }
@@ -211,7 +211,7 @@ BOOL LLFloaterScriptQueue::nextObject()
 	if(isDone() && !mDone)
 	{
 		mDone = true;
-		getChild<LLScrollListCtrl>("queue output")->setCommentText(getString("Done"));
+		getChild<LLScrollListCtrl>("queue output")->addSimpleElement(getString("Done"), ADD_BOTTOM);
 		getChildView("close")->setEnabled(TRUE);
 	}
 	return successful_start;
@@ -277,7 +277,7 @@ class LLCompileFloaterUploadQueueSupplier : public LLAssetUploadQueueSupplier
 			return;
 		}
 
-		queue->getChild<LLScrollListCtrl>("queue output")->setCommentText(message);
+		queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM);
 	}
 		
 private:
@@ -464,7 +464,7 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
 	}
 	if(queue && (buffer.size() > 0)) 
 	{
-		queue->getChild<LLScrollListCtrl>("queue output")->setCommentText(buffer);
+		queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
 	}
 	delete data;
 }
@@ -637,7 +637,7 @@ void LLFloaterResetQueue::handleInventory(LLViewerObject* viewer_obj,
 				LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it));
 				std::string buffer;
 				buffer = getString("Resetting") + (": ") + item->getName();
-				getChild<LLScrollListCtrl>("queue output")->setCommentText(buffer);
+				getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
 				LLMessageSystem* msg = gMessageSystem;
 				msg->newMessageFast(_PREHASH_ScriptReset);
 				msg->nextBlockFast(_PREHASH_AgentData);
@@ -690,7 +690,7 @@ void LLFloaterRunQueue::handleInventory(LLViewerObject* viewer_obj,
 				LLScrollListCtrl* list = getChild<LLScrollListCtrl>("queue output");
 				std::string buffer;
 				buffer = getString("Running") + (": ") + item->getName();
-				list->setCommentText(buffer);
+				list->addSimpleElement(buffer, ADD_BOTTOM);
 
 				LLMessageSystem* msg = gMessageSystem;
 				msg->newMessageFast(_PREHASH_SetScriptRunning);
@@ -745,7 +745,7 @@ void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj,
 				LLScrollListCtrl* list = getChild<LLScrollListCtrl>("queue output");
 				std::string buffer;
 				buffer = getString("NotRunning") + (": ") +item->getName();
-				list->setCommentText(buffer);
+				list->addSimpleElement(buffer, ADD_BOTTOM);
 	
 				LLMessageSystem* msg = gMessageSystem;
 				msg->newMessageFast(_PREHASH_SetScriptRunning);
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..459e52c4f4e6f7844b17e664d1e9aa20a738d888
--- /dev/null
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -0,0 +1,942 @@
+/** 
+ * @file lllocalbitmaps.cpp
+ * @author Vaalith Jinn
+ * @brief Local Bitmaps source
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+/* precompiled headers */
+#include "llviewerprecompiledheaders.h"
+
+/* own header */
+#include "lllocalbitmaps.h"
+
+/* boost: will not compile unless equivalent is undef'd, beware. */
+#ifdef equivalent
+#undef equivalent
+#endif 
+#include <boost/filesystem.hpp>
+
+/* image compression headers. */
+#include "llimagebmp.h"
+#include "llimagetga.h"
+#include "llimagejpeg.h"
+#include "llimagepng.h"
+
+/* time headers */
+#include <time.h>
+#include <ctime>
+
+/* misc headers */
+#include "llscrolllistctrl.h"
+#include "llfilepicker.h"
+#include "llviewertexturelist.h"
+#include "llviewerobjectlist.h"
+#include "llviewerobject.h"
+#include "llface.h"
+#include "llvoavatarself.h"
+#include "llwearable.h"
+#include "llagentwearables.h"
+#include "lltexlayerparams.h"
+#include "llvovolume.h"
+#include "llnotificationsutil.h"
+
+/*=======================================*/
+/*  Formal declarations, constants, etc. */
+/*=======================================*/ 
+std::list<LLLocalBitmap*>   LLLocalBitmapMgr::sBitmapList;
+LLLocalBitmapTimer          LLLocalBitmapMgr::sTimer;
+bool                        LLLocalBitmapMgr::sNeedsRebake;
+
+static const F32 LL_LOCAL_TIMER_HEARTBEAT   = 3.0;
+static const BOOL LL_LOCAL_USE_MIPMAPS      = true;
+static const S32 LL_LOCAL_DISCARD_LEVEL     = 0;
+static const U32 LL_LOCAL_TEXLAYER_FOR_IDX  = 0;
+static const bool LL_LOCAL_SLAM_FOR_DEBUG   = true;
+static const bool LL_LOCAL_REPLACE_ON_DEL   = true;
+static const S32 LL_LOCAL_UPDATE_RETRIES    = 5;
+
+/*=======================================*/
+/*  LLLocalBitmap: unit class            */
+/*=======================================*/ 
+LLLocalBitmap::LLLocalBitmap(std::string filename)
+	: mFilename(filename)
+	, mShortName(gDirUtilp->getBaseFileName(filename, true))
+	, mValid(false)
+	, mLastModified()
+	, mLinkStatus(LS_ON)
+	, mUpdateRetries(LL_LOCAL_UPDATE_RETRIES)
+{
+	mTrackingID.generate();
+
+	/* extension */
+	std::string temp_exten = gDirUtilp->getExtension(mFilename);
+
+	if (temp_exten == "bmp")
+	{ 
+		mExtension = ET_IMG_BMP;
+	}
+	else if (temp_exten == "tga")
+	{
+		mExtension = ET_IMG_TGA;
+	}
+	else if (temp_exten == "jpg" || temp_exten == "jpeg")
+	{
+		mExtension = ET_IMG_JPG;
+	}
+	else if (temp_exten == "png")
+	{
+		mExtension = ET_IMG_PNG;
+	}
+	else
+	{
+		llwarns << "File of no valid extension given, local bitmap creation aborted." << "\n"
+			    << "Filename: " << mFilename << llendl;
+		return; // no valid extension.
+	}
+
+	/* next phase of unit creation is nearly the same as an update cycle.
+	   we're running updateSelf as a special case with the optional UT_FIRSTUSE
+	   which omits the parts associated with removing the outdated texture */
+	mValid = updateSelf(UT_FIRSTUSE);
+}
+
+LLLocalBitmap::~LLLocalBitmap()
+{
+	// replace IDs with defaults, if set to do so.
+	if(LL_LOCAL_REPLACE_ON_DEL && mValid) // fix for STORM-1837
+	{
+		replaceIDs(mWorldID, IMG_DEFAULT);
+		LLLocalBitmapMgr::doRebake();
+	}
+
+	// delete self from gimagelist
+	LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID);
+	gTextureList.deleteImage(image);
+
+	if (image)
+	{
+		image->unref();
+	}
+}
+
+/* accessors */
+std::string LLLocalBitmap::getFilename()
+{
+	return mFilename;
+}
+
+std::string LLLocalBitmap::getShortName()
+{
+	return mShortName;
+}
+
+LLUUID LLLocalBitmap::getTrackingID()
+{
+	return mTrackingID;
+}
+
+LLUUID LLLocalBitmap::getWorldID()
+{
+	return mWorldID;
+}
+
+bool LLLocalBitmap::getValid()
+{
+	return mValid;
+}
+
+/* update functions */
+bool LLLocalBitmap::updateSelf(EUpdateType optional_firstupdate)
+{
+	bool updated = false;
+	
+	if (mLinkStatus == LS_ON)
+	{
+		// verifying that the file exists
+		if (gDirUtilp->fileExists(mFilename))
+		{
+			// verifying that the file has indeed been modified
+			const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename));
+			LLSD new_last_modified = asctime(localtime(&temp_time));
+
+			if (mLastModified.asString() != new_last_modified.asString())
+			{
+				/* loading the image file and decoding it, here is a critical point which,
+				   if fails, invalidates the whole update (or unit creation) process. */
+				LLPointer<LLImageRaw> raw_image = new LLImageRaw();
+				if (decodeBitmap(raw_image))
+				{
+					// decode is successful, we can safely proceed.
+					LLUUID old_id = LLUUID::null;
+					if (!(optional_firstupdate == UT_FIRSTUSE) && !mWorldID.isNull())
+					{
+						old_id = mWorldID;
+					}
+					mWorldID.generate();
+					mLastModified = new_last_modified;
+
+					LLPointer<LLViewerFetchedTexture> texture = new LLViewerFetchedTexture
+						("file://"+mFilename, mWorldID, LL_LOCAL_USE_MIPMAPS);
+
+					texture->createGLTexture(LL_LOCAL_DISCARD_LEVEL, raw_image);
+					texture->setCachedRawImage(LL_LOCAL_DISCARD_LEVEL, raw_image);
+					texture->ref(); 
+
+					gTextureList.addImage(texture);
+			
+					if (!optional_firstupdate == UT_FIRSTUSE)
+					{
+						// seek out everything old_id uses and replace it with mWorldID
+						replaceIDs(old_id, mWorldID);
+
+						// remove old_id from gimagelist
+						LLViewerFetchedTexture* image = gTextureList.findImage(old_id);
+						gTextureList.deleteImage(image);
+						image->unref();
+					}
+
+					mUpdateRetries = LL_LOCAL_UPDATE_RETRIES;
+					updated = true;
+				}
+
+				// if decoding failed, we get here and it will attempt to decode it in the next cycles
+				// until mUpdateRetries runs out. this is done because some software lock the bitmap while writing to it
+				else
+				{
+					if (mUpdateRetries)
+					{
+						mUpdateRetries--;
+					}
+					else
+					{
+						llwarns << "During the update process the following file was found" << "\n"
+							    << "but could not be opened or decoded for " << LL_LOCAL_UPDATE_RETRIES << " attempts." << "\n"
+								<< "Filename: " << mFilename << "\n"
+								<< "Disabling further update attempts for this file." << llendl;
+
+						LLSD notif_args;
+						notif_args["FNAME"] = mFilename;
+						notif_args["NRETRIES"] = LL_LOCAL_UPDATE_RETRIES;
+						LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args);
+
+						mLinkStatus = LS_BROKEN;
+					}
+				}		
+			}
+			
+		} // end if file exists
+
+		else
+		{
+			llwarns << "During the update process, the following file was not found." << "\n" 
+			        << "Filename: " << mFilename << "\n"
+				    << "Disabling further update attempts for this file." << llendl;
+
+			LLSD notif_args;
+			notif_args["FNAME"] = mFilename;
+			LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args);
+
+			mLinkStatus = LS_BROKEN;
+		}
+	}
+
+	return updated;
+}
+
+bool LLLocalBitmap::decodeBitmap(LLPointer<LLImageRaw> rawimg)
+{
+	bool decode_successful = false;
+
+	switch (mExtension)
+	{
+		case ET_IMG_BMP:
+		{
+			LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
+			if (bmp_image->load(mFilename) && bmp_image->decode(rawimg, 0.0f))
+			{
+				rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+				decode_successful = true;
+			}
+			break;
+		}
+
+		case ET_IMG_TGA:
+		{
+			LLPointer<LLImageTGA> tga_image = new LLImageTGA;
+			if ((tga_image->load(mFilename) && tga_image->decode(rawimg))
+			&& ((tga_image->getComponents() == 3) || (tga_image->getComponents() == 4)))
+			{
+				rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+				decode_successful = true;
+			}
+			break;
+		}
+
+		case ET_IMG_JPG:
+		{
+			LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG;
+			if (jpeg_image->load(mFilename) && jpeg_image->decode(rawimg, 0.0f))
+			{
+				rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+				decode_successful = true;
+			}
+			break;
+		}
+
+		case ET_IMG_PNG:
+		{
+			LLPointer<LLImagePNG> png_image = new LLImagePNG;
+			if (png_image->load(mFilename) && png_image->decode(rawimg, 0.0f))
+			{
+				rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+				decode_successful = true;
+			}
+			break;
+		}
+
+		default:
+		{
+			// separating this into -several- llwarns calls because in the extremely unlikely case that this happens
+			// accessing mFilename and any other object properties might very well crash the viewer.
+			// getting here should be impossible, or there's been a pretty serious bug.
+
+			llwarns << "During a decode attempt, the following local bitmap had no properly assigned extension." << llendl;
+			llwarns << "Filename: " << mFilename << llendl;
+		    llwarns << "Disabling further update attempts for this file." << llendl;
+			mLinkStatus = LS_BROKEN;
+		}
+	}
+
+	return decode_successful;
+}
+
+void LLLocalBitmap::replaceIDs(LLUUID old_id, LLUUID new_id)
+{
+	// checking for misuse.
+	if (old_id == new_id)
+	{
+		llinfos << "An attempt was made to replace a texture with itself. (matching UUIDs)" << "\n"
+			    << "Texture UUID: " << old_id.asString() << llendl;
+		return;
+	}
+
+	updateUserPrims(old_id, new_id);
+	updateUserSculpts(old_id, new_id); // isn't there supposed to be an IMG_DEFAULT_SCULPT or something?
+	
+	// default safeguard image for layers
+	if( new_id == IMG_DEFAULT )
+	{
+		new_id = IMG_DEFAULT_AVATAR;
+	}
+
+	/* It doesn't actually update all of those, it merely checks if any of them
+		contain the referenced ID and if so, updates. */
+	updateUserLayers(old_id, new_id, LLWearableType::WT_ALPHA);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_EYES);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_GLOVES);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_JACKET);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_PANTS);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_SHIRT);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_SHOES);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_SKIN);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_SKIRT);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_SOCKS);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_TATTOO);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERPANTS);
+	updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERSHIRT);
+}
+
+// this function sorts the faces from a getFaceList[getNumFaces] into a list of objects
+// in order to prevent multiple sendTEUpdate calls per object during updateUserPrims
+std::vector<LLViewerObject*> LLLocalBitmap::prepUpdateObjects(LLUUID old_id)
+{
+	std::vector<LLViewerObject*> obj_list;
+	LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id);
+
+	for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(); face_iterator++)
+	{
+		// getting an object from a face
+		LLFace* face_to_object = (*old_texture->getFaceList())[face_iterator];
+
+		if(face_to_object)
+		{
+			LLViewerObject* affected_object = face_to_object->getViewerObject();
+
+			if(affected_object)
+			{
+
+				// we have an object, we'll take it's UUID and compare it to
+				// whatever we already have in the returnable object list.
+				// if there is a match - we do not add (to prevent duplicates)
+				LLUUID mainlist_obj_id = affected_object->getID();
+				bool add_object = true;
+
+				// begin looking for duplicates
+				std::vector<LLViewerObject*>::iterator objlist_iter = obj_list.begin();
+				for(; (objlist_iter != obj_list.end()) && add_object; objlist_iter++)
+				{
+					LLViewerObject* obj = *objlist_iter;
+					if (obj->getID() == mainlist_obj_id)
+					{
+						add_object = false; // duplicate found.
+					}
+				}
+				// end looking for duplicates
+
+				if(add_object)
+				{
+					obj_list.push_back(affected_object);
+				}
+
+			}
+
+		}
+		
+	} // end of face-iterating for()
+
+	return obj_list;
+}
+
+void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id)
+{
+	std::vector<LLViewerObject*> objectlist = prepUpdateObjects(old_id);
+
+	for(std::vector<LLViewerObject*>::iterator object_iterator = objectlist.begin();
+		object_iterator != objectlist.end(); object_iterator++)
+	{
+		LLViewerObject* object = *object_iterator;
+
+		if(object)
+		{
+			bool update_obj = false;
+			S32 num_faces = object->getNumFaces();
+
+			for (U8 face_iter = 0; face_iter < num_faces; face_iter++)
+			{
+				if (object->mDrawable)
+				{
+					LLFace* face = object->mDrawable->getFace(face_iter);
+					if (face && face->getTexture() && face->getTexture()->getID() == old_id)
+					{
+						object->setTEImage(face_iter, LLViewerTextureManager::getFetchedTexture
+							(new_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
+
+						update_obj = true;
+					}
+				}
+			}
+			
+			if (update_obj)
+			{
+				object->sendTEUpdate();
+			}
+		}
+	}
+	
+}
+
+void LLLocalBitmap::updateUserSculpts(LLUUID old_id, LLUUID new_id)
+{
+	LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id);
+	for(U32 volume_iter = 0; volume_iter < old_texture->getNumVolumes(); volume_iter++)
+	{
+		LLVOVolume* volume_to_object = (*old_texture->getVolumeList())[volume_iter];
+		LLViewerObject* object = (LLViewerObject*)volume_to_object;
+	
+		if(object)
+		{
+			if (object->isSculpted() && object->getVolume() &&
+				object->getVolume()->getParams().getSculptID() == old_id)
+			{
+				LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+				LLSculptParams new_params(*old_params);
+				new_params.setSculptTexture(new_id);
+				object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE);
+			}
+		}
+	}
+}
+
+void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type)
+{
+	U32 count = gAgentWearables.getWearableCount(type);
+	for(U32 wearable_iter = 0; wearable_iter < count; wearable_iter++)
+	{
+		LLWearable* wearable = gAgentWearables.getWearable(type, wearable_iter);
+		if (wearable)
+		{
+			std::vector<LLLocalTextureObject*> texture_list = wearable->getLocalTextureListSeq();
+			for(std::vector<LLLocalTextureObject*>::iterator texture_iter = texture_list.begin();
+				texture_iter != texture_list.end(); texture_iter++)
+			{
+				LLLocalTextureObject* lto = *texture_iter;
+
+				if (lto && lto->getID() == old_id)
+				{
+					U32 local_texlayer_index = 0; /* can't keep that as static const, gives errors, so i'm leaving this var here */
+					LLVOAvatarDefines::EBakedTextureIndex baked_texind =
+						lto->getTexLayer(local_texlayer_index)->getTexLayerSet()->getBakedTexIndex();
+				
+					LLVOAvatarDefines::ETextureIndex reg_texind = getTexIndex(type, baked_texind);
+					if (reg_texind != LLVOAvatarDefines::TEX_NUM_INDICES)
+					{
+						U32 index = gAgentWearables.getWearableIndex(wearable);
+						gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index);
+						gAgentAvatarp->wearableUpdated(type, FALSE);
+
+						/* telling the manager to rebake once update cycle is fully done */
+						LLLocalBitmapMgr::setNeedsRebake();
+					}
+
+				}
+			}
+		}
+	}
+}
+
+LLVOAvatarDefines::ETextureIndex LLLocalBitmap::getTexIndex(
+	LLWearableType::EType type, LLVOAvatarDefines::EBakedTextureIndex baked_texind)
+{
+	LLVOAvatarDefines::ETextureIndex result = LLVOAvatarDefines::TEX_NUM_INDICES; // using as a default/fail return.
+
+	switch(type)
+	{
+		case LLWearableType::WT_ALPHA:
+		{
+			switch(baked_texind)
+			{
+				case LLVOAvatarDefines::BAKED_EYES:
+				{
+					result = LLVOAvatarDefines::TEX_EYES_ALPHA;
+					break;
+				}
+
+				case LLVOAvatarDefines::BAKED_HAIR:
+				{
+					result = LLVOAvatarDefines::TEX_HAIR_ALPHA;
+					break;
+				}
+
+				case LLVOAvatarDefines::BAKED_HEAD:
+				{
+					result = LLVOAvatarDefines::TEX_HEAD_ALPHA;
+					break;
+				}
+
+				case LLVOAvatarDefines::BAKED_LOWER:
+				{
+					result = LLVOAvatarDefines::TEX_LOWER_ALPHA;
+					break;
+				}
+				case LLVOAvatarDefines::BAKED_UPPER:
+				{
+					result = LLVOAvatarDefines::TEX_UPPER_ALPHA;
+					break;
+				}
+
+				default:
+				{
+					break;
+				}
+
+			}
+			break;
+
+		}
+
+		case LLWearableType::WT_EYES:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_EYES)
+			{
+				result = LLVOAvatarDefines::TEX_EYES_IRIS;
+			}
+
+			break;
+		}
+
+		case LLWearableType::WT_GLOVES:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_UPPER)
+			{
+				result = LLVOAvatarDefines::TEX_UPPER_GLOVES;
+			}
+
+			break;
+		}
+
+		case LLWearableType::WT_JACKET:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_LOWER)
+			{
+				result = LLVOAvatarDefines::TEX_LOWER_JACKET;
+			}
+			else if (baked_texind == LLVOAvatarDefines::BAKED_UPPER)
+			{
+				result = LLVOAvatarDefines::TEX_UPPER_JACKET;
+			}
+
+			break;
+		}
+
+		case LLWearableType::WT_PANTS:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_LOWER)
+			{
+				result = LLVOAvatarDefines::TEX_LOWER_PANTS;
+			}
+
+			break;
+		}
+
+		case LLWearableType::WT_SHIRT:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_UPPER)
+			{
+				result = LLVOAvatarDefines::TEX_UPPER_SHIRT;
+			}
+
+			break;
+		}
+
+		case LLWearableType::WT_SHOES:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_LOWER)
+			{
+				result = LLVOAvatarDefines::TEX_LOWER_SHOES;
+			}
+
+			break;
+		}
+
+		case LLWearableType::WT_SKIN:
+		{
+			switch(baked_texind)
+			{
+				case LLVOAvatarDefines::BAKED_HEAD:
+				{
+					result = LLVOAvatarDefines::TEX_HEAD_BODYPAINT;
+					break;
+				}
+
+				case LLVOAvatarDefines::BAKED_LOWER:
+				{
+					result = LLVOAvatarDefines::TEX_LOWER_BODYPAINT;
+					break;
+				}
+				case LLVOAvatarDefines::BAKED_UPPER:
+				{
+					result = LLVOAvatarDefines::TEX_UPPER_BODYPAINT;
+					break;
+				}
+
+				default:
+				{
+					break;
+				}
+
+			}
+			break;
+		}
+
+		case LLWearableType::WT_SKIRT:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_SKIRT)
+			{
+				result = LLVOAvatarDefines::TEX_SKIRT;
+			}
+
+			break;
+		}
+
+		case LLWearableType::WT_SOCKS:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_LOWER)
+			{
+				result = LLVOAvatarDefines::TEX_LOWER_SOCKS;
+			}
+
+			break;
+		}
+
+		case LLWearableType::WT_TATTOO:
+		{
+			switch(baked_texind)
+			{
+				case LLVOAvatarDefines::BAKED_HEAD:
+				{
+					result = LLVOAvatarDefines::TEX_HEAD_TATTOO;
+					break;
+				}
+
+				case LLVOAvatarDefines::BAKED_LOWER:
+				{
+					result = LLVOAvatarDefines::TEX_LOWER_TATTOO;
+					break;
+				}
+				case LLVOAvatarDefines::BAKED_UPPER:
+				{
+					result = LLVOAvatarDefines::TEX_UPPER_TATTOO;
+					break;
+				}
+
+				default:
+				{
+					break;
+				}
+
+			}
+			break;
+		}
+
+		case LLWearableType::WT_UNDERPANTS:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_LOWER)
+			{
+				result = LLVOAvatarDefines::TEX_LOWER_UNDERPANTS;
+			}
+
+			break;
+		}
+
+		case LLWearableType::WT_UNDERSHIRT:
+		{
+			if (baked_texind == LLVOAvatarDefines::BAKED_UPPER)
+			{
+				result = LLVOAvatarDefines::TEX_UPPER_UNDERSHIRT;
+			}
+
+			break;
+		}
+
+		default:
+		{
+			llwarns << "Unknown wearable type: " << (int)type << "\n"
+				    << "Baked Texture Index: " << (int)baked_texind << "\n"
+					<< "Filename: " << mFilename << "\n"
+					<< "TrackingID: " << mTrackingID << "\n"
+					<< "InworldID: " << mWorldID << llendl;
+		}
+
+	}
+	return result;
+}
+
+/*=======================================*/
+/*  LLLocalBitmapTimer: timer class      */
+/*=======================================*/ 
+LLLocalBitmapTimer::LLLocalBitmapTimer() : LLEventTimer(LL_LOCAL_TIMER_HEARTBEAT)
+{
+}
+
+LLLocalBitmapTimer::~LLLocalBitmapTimer()
+{
+}
+
+void LLLocalBitmapTimer::startTimer()
+{
+	mEventTimer.start();
+}
+
+void LLLocalBitmapTimer::stopTimer()
+{
+	mEventTimer.stop();
+}
+
+bool LLLocalBitmapTimer::isRunning()
+{
+	return mEventTimer.getStarted();
+}
+
+BOOL LLLocalBitmapTimer::tick()
+{
+	LLLocalBitmapMgr::doUpdates();
+	return FALSE;
+}
+
+/*=======================================*/
+/*  LLLocalBitmapMgr: manager class      */
+/*=======================================*/ 
+LLLocalBitmapMgr::LLLocalBitmapMgr()
+{
+	// The class is all made of static members, should i even bother instantiating?
+}
+
+LLLocalBitmapMgr::~LLLocalBitmapMgr()
+{
+}
+
+bool LLLocalBitmapMgr::addUnit()
+{
+	bool add_successful = false;
+
+	LLFilePicker& picker = LLFilePicker::instance();
+	if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE))
+	{
+		sTimer.stopTimer();
+
+		std::string filename = picker.getFirstFile();
+		while(!filename.empty())
+		{
+			LLLocalBitmap* unit = new LLLocalBitmap(filename);
+
+			if (unit->getValid())
+			{
+				sBitmapList.push_back(unit);
+				add_successful = true;
+			}
+			else
+			{
+				llwarns << "Attempted to add invalid or unreadable image file, attempt cancelled.\n"
+					    << "Filename: " << filename << llendl;
+
+				LLSD notif_args;
+				notif_args["FNAME"] = filename;
+				LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args);
+
+				delete unit;
+				unit = NULL;
+			}
+
+			filename = picker.getNextFile();
+		}
+		
+		sTimer.startTimer();
+	}
+
+	return add_successful;
+}
+
+void LLLocalBitmapMgr::delUnit(LLUUID tracking_id)
+{
+	if (!sBitmapList.empty())
+	{	
+		std::vector<LLLocalBitmap*> to_delete;
+		for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++)
+		{   /* finding which ones we want deleted and making a separate list */
+			LLLocalBitmap* unit = *iter;
+			if (unit->getTrackingID() == tracking_id)
+			{
+				to_delete.push_back(unit);
+			}
+		}
+
+		for(std::vector<LLLocalBitmap*>::iterator del_iter = to_delete.begin();
+			del_iter != to_delete.end(); del_iter++)
+		{   /* iterating over a temporary list, hence preserving the iterator validity while deleting. */
+			LLLocalBitmap* unit = *del_iter;
+			sBitmapList.remove(unit);
+			delete unit;
+			unit = NULL;
+		}
+	}
+}
+
+LLUUID LLLocalBitmapMgr::getWorldID(LLUUID tracking_id)
+{
+	LLUUID world_id = LLUUID::null;
+
+	for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++)
+	{
+		LLLocalBitmap* unit = *iter;
+		if (unit->getTrackingID() == tracking_id)
+		{
+			world_id = unit->getWorldID();
+		}
+	}
+
+	return world_id;
+}
+
+std::string LLLocalBitmapMgr::getFilename(LLUUID tracking_id)
+{
+	std::string filename = "";
+
+	for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++)
+	{
+		LLLocalBitmap* unit = *iter;
+		if (unit->getTrackingID() == tracking_id)
+		{
+			filename = unit->getFilename();
+		}
+	}
+
+	return filename;
+}
+
+void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl)
+{
+	if (ctrl)
+	{
+		ctrl->clearRows();
+
+		if (!sBitmapList.empty())
+		{
+			for (local_list_iter iter = sBitmapList.begin();
+				 iter != sBitmapList.end(); iter++)
+			{
+				LLSD element;
+				element["columns"][0]["column"] = "unit_name";
+				element["columns"][0]["type"]   = "text";
+				element["columns"][0]["value"]  = (*iter)->getShortName();
+
+				element["columns"][1]["column"] = "unit_id_HIDDEN";
+				element["columns"][1]["type"]   = "text";
+				element["columns"][1]["value"]  = (*iter)->getTrackingID();
+
+				ctrl->addElement(element);
+			}
+		}
+	}
+
+}
+
+void LLLocalBitmapMgr::doUpdates()
+{
+	// preventing theoretical overlap in cases with huge number of loaded images.
+	sTimer.stopTimer();
+	sNeedsRebake = false;
+
+	for (local_list_iter iter = sBitmapList.begin(); iter != sBitmapList.end(); iter++)
+	{
+		(*iter)->updateSelf();
+	}
+
+	doRebake();
+	sTimer.startTimer();
+}
+
+void LLLocalBitmapMgr::setNeedsRebake()
+{
+	sNeedsRebake = true;
+}
+
+void LLLocalBitmapMgr::doRebake()
+{ /* separated that from doUpdates to insure a rebake can be called separately during deletion */
+	if (sNeedsRebake)
+	{
+		gAgentAvatarp->forceBakeAllTextures(LL_LOCAL_SLAM_FOR_DEBUG);
+		sNeedsRebake = false;
+	}
+}
+
diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a23c7ef6e3d2a203b07b4137960f58e00fafd40
--- /dev/null
+++ b/indra/newview/lllocalbitmaps.h
@@ -0,0 +1,136 @@
+/** 
+ * @file lllocalbitmaps.h
+ * @author Vaalith Jinn
+ * @brief Local Bitmaps header
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LOCALBITMAPS_H
+#define LL_LOCALBITMAPS_H
+
+#include "lleventtimer.h"
+#include "llwearabletype.h"
+#include "llvoavatardefines.h"
+
+class LLScrollListCtrl;
+
+class LLLocalBitmap
+{
+	public: /* main */
+		LLLocalBitmap(std::string filename);
+		~LLLocalBitmap();
+
+	public: /* accessors */
+		std::string	getFilename();
+		std::string	getShortName();
+		LLUUID		getTrackingID();
+		LLUUID		getWorldID();
+		bool		getValid();
+
+	public: /* self update public section */
+		enum EUpdateType
+		{
+			UT_FIRSTUSE,
+			UT_REGUPDATE
+		};
+
+		bool updateSelf(EUpdateType = UT_REGUPDATE);
+
+	private: /* self update private section */
+		bool decodeBitmap(LLPointer<LLImageRaw> raw);
+		void replaceIDs(LLUUID old_id, LLUUID new_id);
+		std::vector<LLViewerObject*> prepUpdateObjects(LLUUID old_id);
+		void updateUserPrims(LLUUID old_id, LLUUID new_id);
+		void updateUserSculpts(LLUUID old_id, LLUUID new_id);
+		void updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type);
+		LLVOAvatarDefines::ETextureIndex getTexIndex(LLWearableType::EType type, LLVOAvatarDefines::EBakedTextureIndex baked_texind);
+
+	private: /* private enums */
+		enum ELinkStatus
+		{
+			LS_ON,
+			LS_BROKEN,
+		};
+
+		enum EExtension
+		{
+			ET_IMG_BMP,
+			ET_IMG_TGA,
+			ET_IMG_JPG,
+			ET_IMG_PNG
+		};
+
+	private: /* members */
+		std::string mFilename;
+		std::string mShortName;
+		LLUUID      mTrackingID;
+		LLUUID      mWorldID;
+		bool        mValid;
+		LLSD        mLastModified;
+		EExtension  mExtension;
+		ELinkStatus mLinkStatus;
+		S32         mUpdateRetries;
+
+};
+
+class LLLocalBitmapTimer : public LLEventTimer
+{
+	public:
+		LLLocalBitmapTimer();
+		~LLLocalBitmapTimer();
+
+	public:
+		void startTimer();
+		void stopTimer();
+		bool isRunning();
+		BOOL tick();
+
+};
+
+class LLLocalBitmapMgr
+{
+	public:
+		LLLocalBitmapMgr();
+		~LLLocalBitmapMgr();
+
+	public:
+		static bool         addUnit();
+		static void         delUnit(LLUUID tracking_id);
+
+		static LLUUID       getWorldID(LLUUID tracking_id);
+		static std::string  getFilename(LLUUID tracking_id);
+		
+		static void         feedScrollList(LLScrollListCtrl* ctrl);
+		static void         doUpdates();
+		static void         setNeedsRebake();
+		static void         doRebake();
+		
+	private:
+		static std::list<LLLocalBitmap*>    sBitmapList;
+		static LLLocalBitmapTimer           sTimer;
+		static bool                         sNeedsRebake;
+		typedef std::list<LLLocalBitmap*>::iterator local_list_iter;
+};
+
+#endif
+
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 19a944e88e9a9510e324cc3430e2ae50ff5d846d..ed9faa070601ea72801cee172df5fecdd9bd58fb 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -67,6 +67,9 @@
 #include "lluictrlfactory.h"
 #include "lltrans.h"
 
+#include "llradiogroup.h"
+#include "llfloaterreg.h"
+#include "lllocalbitmaps.h"
 
 static const S32 HPAD = 4;
 static const S32 VPAD = 4;
@@ -78,6 +81,8 @@ static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
 static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
 static const F32 CONTEXT_FADE_TIME = 0.08f;
 
+static const S32 LOCAL_TRACKING_ID_COLUMN = 1;
+
 //static const char CURRENT_IMAGE_NAME[] = "Current Texture";
 //static const char WHITE_IMAGE_NAME[] = "Blank Texture";
 //static const char NO_IMAGE_NAME[] = "None";
@@ -142,6 +147,12 @@ class LLFloaterTexturePicker : public LLFloater
 	static void		onApplyImmediateCheck(LLUICtrl* ctrl, void* userdata);
 		   void		onTextureSelect( const LLTextureEntry& te );
 
+	static void		onModeSelect(LLUICtrl* ctrl, void *userdata);
+	static void		onBtnAdd(void* userdata);
+	static void		onBtnRemove(void* userdata);
+	static void		onBtnUpload(void* userdata);
+	static void		onLocalScrollCommit(LLUICtrl* ctrl, void* userdata);
+
 protected:
 	LLPointer<LLViewerTexture> mTexturep;
 	LLTextureCtrl*		mOwner;
@@ -169,8 +180,10 @@ class LLFloaterTexturePicker : public LLFloater
 	BOOL				mNoCopyTextureSelected;
 	F32					mContextConeOpacity;
 	LLSaveFolderState	mSavedFolderState;
-
 	BOOL				mSelectedItemPinned;
+	
+	LLRadioGroup*		mModeSelector;
+	LLScrollListCtrl*	mLocalScrollCtrl;
 };
 
 LLFloaterTexturePicker::LLFloaterTexturePicker(	
@@ -437,6 +450,17 @@ BOOL LLFloaterTexturePicker::postBuild()
 		mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO);
 	}
 
+	mModeSelector = getChild<LLRadioGroup>("mode_selection");
+	mModeSelector->setCommitCallback(onModeSelect, this);
+	mModeSelector->setSelectedIndex(0, 0);
+
+	childSetAction("l_add_btn", LLFloaterTexturePicker::onBtnAdd, this);
+	childSetAction("l_rem_btn", LLFloaterTexturePicker::onBtnRemove, this);
+	childSetAction("l_upl_btn", LLFloaterTexturePicker::onBtnUpload, this);
+
+	mLocalScrollCtrl = getChild<LLScrollListCtrl>("l_name_list");
+	mLocalScrollCtrl->setCommitCallback(onLocalScrollCommit, this);
+	LLLocalBitmapMgr::feedScrollList(mLocalScrollCtrl);
 
 	mNoCopyTextureSelected = FALSE;
 
@@ -464,7 +488,6 @@ BOOL LLFloaterTexturePicker::postBuild()
 // virtual
 void LLFloaterTexturePicker::draw()
 {
-	S32 floater_header_size = getHeaderHeight();
 	if (mOwner)
 	{
 		// draw cone of context pointing back to texture swatch	
@@ -554,10 +577,7 @@ void LLFloaterTexturePicker::draw()
 		}
 
 		// Border
-		LLRect border( BORDER_PAD, 
-					   getRect().getHeight() - floater_header_size - BORDER_PAD, 
-					   ((getMinWidth() / 2) - TEXTURE_INVENTORY_PADDING - HPAD) - BORDER_PAD,
-					   BORDER_PAD + FOOTER_HEIGHT + (getRect().getHeight() - getMinHeight()));
+		LLRect border = getChildView("preview_widget")->getRect();
 		gl_rect_2d( border, LLColor4::black, FALSE );
 
 
@@ -748,7 +768,15 @@ void LLFloaterTexturePicker::onBtnSelect(void* userdata)
 	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 	if (self->mOwner)
 	{
-		self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_SELECT);
+		LLUUID local_id = LLUUID::null;
+
+		if (self->mLocalScrollCtrl->getVisible() && !self->mLocalScrollCtrl->getAllSelected().empty())
+		{
+			LLUUID temp_id = self->mLocalScrollCtrl->getFirstSelected()->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID();
+			local_id = LLLocalBitmapMgr::getWorldID(temp_id);
+		}
+
+		self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_SELECT, local_id);
 	}
 	self->closeFloater();
 }
@@ -791,6 +819,112 @@ void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem
 	}
 }
 
+// static
+void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata)
+{
+	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+	bool mode = (self->mModeSelector->getSelectedIndex() == 0);
+
+	self->getChild<LLButton>("Default")->setVisible(mode);
+	self->getChild<LLButton>("Blank")->setVisible(mode);
+	self->getChild<LLButton>("None")->setVisible(mode);
+	self->getChild<LLButton>("Pipette")->setVisible(mode);
+	self->getChild<LLFilterEditor>("inventory search editor")->setVisible(mode);
+	self->getChild<LLInventoryPanel>("inventory panel")->setVisible(mode);
+
+	/*self->getChild<LLCheckBox>("show_folders_check")->setVisible(mode);
+	  no idea under which conditions the above is even shown, needs testing. */
+
+	self->getChild<LLButton>("l_add_btn")->setVisible(!mode);
+	self->getChild<LLButton>("l_rem_btn")->setVisible(!mode);
+	self->getChild<LLButton>("l_upl_btn")->setVisible(!mode);
+	self->getChild<LLScrollListCtrl>("l_name_list")->setVisible(!mode);
+}
+
+// static
+void LLFloaterTexturePicker::onBtnAdd(void* userdata)
+{
+	if (LLLocalBitmapMgr::addUnit() == true)
+	{
+		LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+		LLLocalBitmapMgr::feedScrollList(self->mLocalScrollCtrl);
+	}
+}
+
+// static
+void LLFloaterTexturePicker::onBtnRemove(void* userdata)
+{
+	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+	std::vector<LLScrollListItem*> selected_items = self->mLocalScrollCtrl->getAllSelected();
+
+	if (!selected_items.empty())
+	{
+		for(std::vector<LLScrollListItem*>::iterator iter = selected_items.begin();
+			iter != selected_items.end(); iter++)
+		{
+			LLScrollListItem* list_item = *iter;
+			if (list_item)
+			{
+				LLUUID tracking_id = list_item->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID();
+				LLLocalBitmapMgr::delUnit(tracking_id);
+			}
+		}
+
+		self->getChild<LLButton>("l_rem_btn")->setEnabled(false);
+		self->getChild<LLButton>("l_upl_btn")->setEnabled(false);
+		LLLocalBitmapMgr::feedScrollList(self->mLocalScrollCtrl);
+	}
+
+}
+
+// static
+void LLFloaterTexturePicker::onBtnUpload(void* userdata)
+{
+	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+	std::vector<LLScrollListItem*> selected_items = self->mLocalScrollCtrl->getAllSelected();
+
+	if (selected_items.empty())
+	{
+		return;
+	}
+
+	/* currently only allows uploading one by one, picks the first item from the selection list.  (not the vector!)
+	   in the future, it might be a good idea to check the vector size and if more than one units is selected - opt for multi-image upload. */
+	
+	LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN);
+	std::string filename = LLLocalBitmapMgr::getFilename(tracking_id);
+
+	if (!filename.empty())
+	{
+		LLFloaterReg::showInstance("upload_image", LLSD(filename));
+	}
+
+}
+
+//static
+void LLFloaterTexturePicker::onLocalScrollCommit(LLUICtrl* ctrl, void* userdata)
+{
+	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+	std::vector<LLScrollListItem*> selected_items = self->mLocalScrollCtrl->getAllSelected();
+	bool has_selection = !selected_items.empty();
+
+	self->getChild<LLButton>("l_rem_btn")->setEnabled(has_selection);
+	self->getChild<LLButton>("l_upl_btn")->setEnabled(has_selection && (selected_items.size() < 2));
+	/* since multiple-localbitmap upload is not implemented, upl button gets disabled if more than one is selected. */
+
+	if (has_selection)
+	{
+		LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN); 
+		LLUUID inworld_id = LLLocalBitmapMgr::getWorldID(tracking_id);
+		self->mOwner->setImageAssetID(inworld_id);
+
+		if (self->childGetValue("apply_immediate_check").asBoolean())
+		{
+			self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CHANGE, inworld_id);
+		}
+	}
+}
+
 // static
 void LLFloaterTexturePicker::onShowFolders(LLUICtrl* ctrl, void *user_data)
 {
@@ -1133,7 +1267,7 @@ void LLTextureCtrl::onFloaterClose()
 	mFloaterHandle.markDead();
 }
 
-void LLTextureCtrl::onFloaterCommit(ETexturePickOp op)
+void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id)
 {
 	LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
 
@@ -1146,14 +1280,24 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op)
 		// (i.e. op == TEXTURE_SELECT) or texture changes via DnD.
 		else if (mCommitOnSelection || op == TEXTURE_SELECT)
 			mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
-			
-		if( floaterp->isDirty() )
+
+		if(floaterp->isDirty() || id.notNull()) // mModelView->setDirty does not work.
 		{
 			setTentative( FALSE );
-			mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE);
-			lldebugs << "mImageItemID: " << mImageItemID << llendl;
-			mImageAssetID = floaterp->getAssetID();
-			lldebugs << "mImageAssetID: " << mImageAssetID << llendl;
+
+			if (id.notNull())
+			{
+				mImageItemID = id;
+				mImageAssetID = id;
+			}
+			else
+			{
+				mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE);
+				lldebugs << "mImageItemID: " << mImageItemID << llendl;
+				mImageAssetID = floaterp->getAssetID();
+				lldebugs << "mImageAssetID: " << mImageAssetID << llendl;
+			}
+
 			if (op == TEXTURE_SELECT && mOnSelectCallback)
 			{
 				mOnSelectCallback( this, LLSD() );
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index b1312d641f64fe848d7e136be829db43576f43b0..3abe84dcc31a630ad2ea3c1903e37d9eb9d71c9c 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -157,7 +157,7 @@ class LLTextureCtrl
 	void			closeDependentFloater();
 
 	void			onFloaterClose();
-	void			onFloaterCommit(ETexturePickOp op);
+	void			onFloaterCommit(ETexturePickOp op, LLUUID id = LLUUID::null);
 
 	// This call is returned when a drag is detected. Your callback
 	// should return TRUE if the drag is acceptable.
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index de305bf3d9d3de96586d68e4c8fb7845509577c4..a8060649ba6789d0870d3bf9117f2d6e045594a9 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -243,8 +243,8 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_opt
 	mBtnCallbackData.push_back(userdata);
 
 	LLButton::Params p;
-	bool is_ignore_btn = form_element["index"].asInteger() == -1;
-	const LLFontGL* font = is_ignore_btn ? sFontSmall: sFont; // for ignore button in script dialog
+	bool make_small_btn = form_element["index"].asInteger() == -1 || form_element["index"].asInteger() == -2;
+	const LLFontGL* font = make_small_btn ? sFontSmall: sFont; // for block and ignore buttons in script dialog
 	p.name(form_element["name"].asString());
 	p.label(form_element["text"].asString());
 	p.font(font);
@@ -264,7 +264,7 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_opt
 		p.rect.width = 1;
 		p.auto_resize = true;
 	}
-	else if (mIsScriptDialog && is_ignore_btn)
+	else if (mIsScriptDialog && make_small_btn)
 	{
 		// this is ignore button, make it smaller
 		p.rect.height = BTN_HEIGHT_SMALL;
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 093b84413a03cd4555d90178374df2a74e7d6e6d..ab45aae5cc982517e0fd518ef8f57835eb2afe8e 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -181,6 +181,16 @@ static bool handleReleaseGLBufferChanged(const LLSD& newvalue)
 	return true;
 }
 
+static bool handleLUTBufferChanged(const LLSD& newvalue)
+{
+	if (gPipeline.isInit())
+	{
+		gPipeline.releaseLUTBuffers();
+		gPipeline.createLUTBuffers();
+	}
+	return true;
+}
+
 static bool handleAnisotropicChanged(const LLSD& newvalue)
 {
 	LLImageGL::sGlobalUseAnisotropic = newvalue.asBoolean();
@@ -569,9 +579,9 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
-	gSavedSettings.getControl("RenderSpecularResX")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
-	gSavedSettings.getControl("RenderSpecularResY")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
-	gSavedSettings.getControl("RenderSpecularExponent")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
+	gSavedSettings.getControl("RenderSpecularResX")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2));
+	gSavedSettings.getControl("RenderSpecularResY")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2));
+	gSavedSettings.getControl("RenderSpecularExponent")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2));
 	gSavedSettings.getControl("RenderAnisotropic")->getSignal()->connect(boost::bind(&handleAnisotropicChanged, _2));
 	gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 37cf916423638df79cc2728aef82617e507f247b..7481414b5c49771772f91844ba70798f06125183 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -6556,31 +6556,37 @@ class LLToolsSelectedScriptAction : public view_listener_t
 		std::string action = userdata.asString();
 		bool mono = false;
 		std::string msg, name;
+		std::string title;
 		if (action == "compile mono")
 		{
 			name = "compile_queue";
 			mono = true;
 			msg = "Recompile";
+			title = LLTrans::getString("CompileQueueTitle");
 		}
 		if (action == "compile lsl")
 		{
 			name = "compile_queue";
 			msg = "Recompile";
+			title = LLTrans::getString("CompileQueueTitle");
 		}
 		else if (action == "reset")
 		{
 			name = "reset_queue";
 			msg = "Reset";
+			title = LLTrans::getString("ResetQueueTitle");
 		}
 		else if (action == "start")
 		{
 			name = "start_queue";
 			msg = "SetRunning";
+			title = LLTrans::getString("RunQueueTitle");
 		}
 		else if (action == "stop")
 		{
 			name = "stop_queue";
 			msg = "SetRunningNot";
+			title = LLTrans::getString("NotRunQueueTitle");
 		}
 		LLUUID id; id.generate();
 		
@@ -6589,6 +6595,7 @@ class LLToolsSelectedScriptAction : public view_listener_t
 		{
 			queue->setMono(mono);
 			queue_actions(queue, msg);
+			queue->setTitle(title);
 		}
 		else
 		{
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index e0a362596d196a8f33c60f09a9259df7daaabbf2..b386c73d2a5ef876229f504ca26f884a721ded4b 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -65,6 +65,7 @@ class LLViewerTextureList
 
 	friend class LLTextureView;
 	friend class LLViewerTextureManager;
+	friend class LLLocalBitmap;
 	
 public:
 	static BOOL createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec);
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 413eab988831de576f828dbbaaeb7fe1cc21dd36..a7a4281860da8b1e5de1f67397f70dda29a98227 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -7537,12 +7537,16 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
 void LLVOAvatar::dumpArchetypeXML( void* )
 {
 	LLAPRFile outfile;
-	outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB );
-	apr_file_t* file = outfile.getFileHandle() ;
+	outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"new archetype.xml"), LL_APR_WB );
+	apr_file_t* file = outfile.getFileHandle();
 	if (!file)
 	{
 		return;
 	}
+	else
+	{
+		llinfos << "xmlfile write handle obtained : " << gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"new archetype.xml") << llendl;
+	}
 
 	apr_file_printf( file, "<?xml version=\"1.0\" encoding=\"US-ASCII\" standalone=\"yes\"?>\n" );
 	apr_file_printf( file, "<linden_genepool version=\"1.0\">\n" );
@@ -7582,6 +7586,11 @@ void LLVOAvatar::dumpArchetypeXML( void* )
 	}
 	apr_file_printf( file, "\t</archetype>\n" );
 	apr_file_printf( file, "\n</linden_genepool>\n" );
+	//explictly close the file if it is still open which it should be
+	if (file)
+	{
+		outfile.close();
+	}
 }
 
 
diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp
index 0f7f63061be64291f9f58b2aef42ba6b6a30b66c..402504933cd9e3ea8e4e5fdb5ccb5da7f94cceeb 100644
--- a/indra/newview/llwearable.cpp
+++ b/indra/newview/llwearable.cpp
@@ -810,6 +810,20 @@ const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const
 	return NULL;
 }
 
+std::vector<LLLocalTextureObject*> LLWearable::getLocalTextureListSeq()
+{
+	std::vector<LLLocalTextureObject*> result;
+
+	for(te_map_t::const_iterator iter = mTEMap.begin();
+		iter != mTEMap.end(); iter++)
+	{
+		LLLocalTextureObject* lto = iter->second;
+		result.push_back(lto);
+	}
+
+	return result;
+}
+
 void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject &lto)
 {
 	if( mTEMap.find(index) != mTEMap.end() )
diff --git a/indra/newview/llwearable.h b/indra/newview/llwearable.h
index fd614ade64b5b3c46d712df76d3c8b381aac3d25..3d8c53a755c3a17efe810d10d272b224f0d750f8 100644
--- a/indra/newview/llwearable.h
+++ b/indra/newview/llwearable.h
@@ -106,6 +106,7 @@ class LLWearable
 
 	LLLocalTextureObject* getLocalTextureObject(S32 index);
 	const LLLocalTextureObject* getLocalTextureObject(S32 index) const;
+	std::vector<LLLocalTextureObject*> getLocalTextureListSeq();
 
 	void				setLocalTextureObject(S32 index, LLLocalTextureObject &lto);
 	void				addVisualParam(LLVisualParam *param);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index e2cb22e30754141a01f5c5342526cecc93b4f461..ab994c71cbdf87cc7182dc7da89f09d91a10bdaa 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1035,11 +1035,7 @@ void LLPipeline::releaseGLBuffers()
 		mTrueNoiseMap = 0;
 	}
 
-	if (mLightFunc)
-	{
-		LLImageGL::deleteTextures(1, &mLightFunc);
-		mLightFunc = 0;
-	}
+	releaseLUTBuffers();
 
 	mWaterRef.release();
 	mWaterDis.release();
@@ -1055,6 +1051,15 @@ void LLPipeline::releaseGLBuffers()
 	LLVOAvatar::resetImpostors();
 }
 
+void LLPipeline::releaseLUTBuffers()
+{
+	if (mLightFunc)
+	{
+		LLImageGL::deleteTextures(1, &mLightFunc);
+		mLightFunc = 0;
+	}
+}
+
 void LLPipeline::releaseScreenBuffers()
 {
 	mUIScreen.release();
@@ -1150,50 +1155,69 @@ void LLPipeline::createGLBuffers()
 			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 		}
 
+		createLUTBuffers();
+	}
+
+	gBumpImageList.restoreGL();
+}
+
+void LLPipeline::createLUTBuffers()
+{
+	if (sRenderDeferred)
+	{
 		if (!mLightFunc)
 		{
 			U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
 			U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
-			U8* lg = new U8[lightResX*lightResY];
-
+			U8* ls = new U8[lightResX*lightResY];
+			F32 specExp = gSavedSettings.getF32("RenderSpecularExponent");
+            // Calculate the (normalized) Blinn-Phong specular lookup texture.
 			for (U32 y = 0; y < lightResY; ++y)
 			{
 				for (U32 x = 0; x < lightResX; ++x)
 				{
-					//spec func
+					ls[y*lightResX+x] = 0;
 					F32 sa = (F32) x/(lightResX-1);
 					F32 spec = (F32) y/(lightResY-1);
-					//lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255);
-
-					//F32 sp = acosf(sa)/(1.f-spec);
-
-					sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent"));
-					F32 a = acosf(sa*0.25f+0.75f);
-					F32 m = llmax(0.5f-spec*0.5f, 0.001f);
-					F32 t2 = tanf(a)/m;
-					t2 *= t2;
-
-					F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f;
-					F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2);
-
-					lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255);
+					F32 n = spec * spec * specExp;
+					
+					// Nothing special here.  Just your typical blinn-phong term.
+					spec = powf(sa, n);
+					
+					// Apply our normalization function.
+					// Note: This is the full equation that applies the full normalization curve, not an approximation.
+					// This is fine, given we only need to create our LUT once per buffer initialization.
+					// The only trade off is we have a really low dynamic range.
+					// This means we have to account for things not being able to exceed 0 to 1 in our shaders.
+					spec *= (((n + 2) * (n + 4)) / (8 * F_PI * (powf(2, -n/2) + n)));
+					
+					// Always sample at a 1.0/2.2 curve.
+					// This "Gamma corrects" our specular term, boosting our lower exponent reflections.
+					spec = powf(spec, 1.f/2.2f);
+					
+					// Easy fix for our dynamic range problem: divide by 6 here, multiply by 6 in our shaders.
+					// This allows for our specular term to exceed a value of 1 in our shaders.
+					// This is something that can be important for energy conserving specular models where higher exponents can result in highlights that exceed a range of 0 to 1.
+					// Technically, we could just use an R16F texture, but driver support for R16F textures can be somewhat spotty at times.
+					// This works remarkably well for higher specular exponents, though banding can sometimes be seen on lower exponents.
+					// Combined with a bit of noise and trilinear filtering, the banding is hardly noticable.
+					ls[y*lightResX+x] = (U8)(llclamp(spec * (1.f / 6), 0.f, 1.f) * 255);
 				}
 			}
-
+			
 			LLImageGL::generateTextures(1, &mLightFunc);
 			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
-			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, lg);
+			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, ls);
 			gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
-
-			delete [] lg;
+			
+			delete [] ls;
 		}
 	}
-
-	gBumpImageList.restoreGL();
 }
 
-void LLPipeline::restoreGL() 
+
+void LLPipeline::restoreGL()
 {
 	LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL);
 	assertInitialized();
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 3c4e389ce0c3fbab7032a1b1780c96190e58e776..b8b4f164fed2e1f709676d04b3adf1c9bc10e207 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -114,8 +114,10 @@ class LLPipeline
 	void doResetVertexBuffers();
 	void resizeScreenTexture();
 	void releaseGLBuffers();
+	void releaseLUTBuffers();
 	void releaseScreenBuffers();
 	void createGLBuffers();
+	void createLUTBuffers();
 
 	void allocateScreenBuffer(U32 resX, U32 resY);
 	bool allocateScreenBuffer(U32 resX, U32 resY, U32 samples);
diff --git a/indra/newview/skins/default/xui/en/floater_image_preview.xml b/indra/newview/skins/default/xui/en/floater_image_preview.xml
index 86232de1a4711d88783cf07120802a1139e97ee2..44d2c14cc8d1cbd2090e8bd3407900a222c73540 100644
--- a/indra/newview/skins/default/xui/en/floater_image_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_image_preview.xml
@@ -2,7 +2,7 @@
 <floater
  legacy_header_height="18"
  can_minimize="false"
- height="440"
+ height="460"
  layout="topleft"
  name="Image Preview"
  help_topic="image_preview"
@@ -108,7 +108,7 @@
     <text
      type="string"
      length="1"
-     bottom="225"
+     bottom="250"
      height="45"
      word_wrap="true"
      follows="top|left"
@@ -137,7 +137,7 @@ Try saving image as 24 bit Targa (.tga).
      layout="topleft"
      left="165"
      name="cancel_btn"
-     top="410"
+     top="430"
      width="125" />
     <button
      follows="bottom|left"
diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
index cad7d72ed7f913e6f342f137c53b4159ff64fb51..ffb8b842f0cbb3920eb1507d22de4fa25d5fc1cf 100644
--- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
+++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
@@ -3,15 +3,17 @@
  legacy_header_height="18"
  can_minimize="false"
  can_resize="true"
- height="290"
+ height="330"
  layout="topleft"
- min_height="290"
+ min_height="330"
  min_width="410"
  name="texture picker"
  help_topic="texture_picker"
  title="PICK: TEXTURE"
  width="410">
-    <floater.string
+ 
+<!--  top static -->
+ <floater.string
      name="choose_picture">
         Click to choose a picture
     </floater.string>
@@ -19,6 +21,16 @@
      name="pick title">
         Pick:
     </floater.string>
+
+    <view
+     left="4"
+     top="20"
+     name="preview_widget"
+     height="165"
+     width="165"
+     follows="left|top"
+    />
+  
     <text
      type="string"
      length="1"
@@ -34,70 +46,94 @@
      width="163">
         Multiple textures
     </text>
+	
+	<!-- mode selector -->
+	   <radio_group
+     control_name="mode_selection"
+     height="20"
+     layout="topleft"
+     left="18"
+     top_pad="80"
+     name="mode_selection"
+     follows="left|top">
+        <radio_item
+         label="Inventory"
+         name="inventory"
+         top_delta="20" 
+         layout="topleft"
+         height="16" 
+         left="0" 
+         value="0"
+         width="80" />
+        <radio_item
+         label="Local"
+         left_pad="0"
+         layout="topleft"
+         top_delta="0" 
+         height="16" 
+         name="local"
+         value="1"
+         width="75" />
+    </radio_group>
+	<!-- -->
+	
     <text
      type="string"
      length="1"
      follows="left|top"
      height="14"
      layout="topleft"
-     left_delta="0"
+     left_delta="-12"
      name="unknown"
-     top_pad="80"
-     width="163">
+     top_pad="4"
+     width="">
         Size: [DIMENSIONS]
     </text>
+    
+<!--  middle: inventory mode -->
+
     <button
      enabled="false"
-     follows="left|bottom"
-     height="20"
+     follows="left|top"
+     height="18"
      label="Default"
      label_selected="Default"
      layout="topleft"
-     left_delta="0"
      name="Default"
-     top_pad="4"
-     width="80" />
+     width="73"
+	 left="94"
+     top="215"/>
     <button
+     follows="left|top"
+     height="20"
+     label="Blank"
+     label_selected="Blank"
+     layout="topleft"
+     left_delta="0"
+     name="Blank"
+     top_pad="5"
+     width="73" />
+     <button
      enabled="false"
-     follows="left|bottom"
+     follows="left|top"
      height="20"
      label="None"
      label_selected="None"
      layout="topleft"
-     left_pad="4"
+     left_delta="0"
      name="None"
-     top_delta="0"
-     width="80" />
-    <button
-     follows="left|bottom"
-     height="20"
-     label="Blank"
-     label_selected="Blank"
-     layout="topleft"
-     left="4"
-     name="Blank"
      top_pad="5"
-     width="80" />
-         <button
-     follows="left|bottom"
+     width="73" />
+    <button
+     follows="left|top"
      height="28"
      image_selected="eye_button_active.tga"
      image_unselected="eye_button_inactive.tga"
      layout="topleft"
-     left_pad="50"
-     top_delta="3"
+     left_delta="-80"
+     top_delta="-25"
      name="Pipette"
      width="28" />
-   <check_box
-     follows="left|bottom"
-     height="20"
-     initial_value="true"
-     label="Apply now"
-     layout="topleft"
-     left="4"
-     name="apply_immediate_check"
-     top="262"
-     width="120" />
     <filter_editor
      follows="left|top|right"
      height="23"
@@ -113,7 +149,7 @@
      bg_alpha_color="DkGray2"
      border="false"
      follows="all"
-     height="200"
+     height="233"
      layout="topleft"
      left_delta="0"
      name="inventory panel"
@@ -128,23 +164,89 @@
      top_pad="0"
      left_delta="-3"
      width="200" />
-         <button
-     follows="right|bottom"
+
+<!--  middle: local mode -->
+    <button
+     follows="left|top"
+     height="18"
+     label="Add"
+     label_selected="Add"
+     layout="topleft"
+     left="94"
+     top="215"
+     name="l_add_btn"
+     width="73"
+     visible="false"/>
+    <button
+     enabled="false"
+     follows="left|top"
+     height="20"
+     label="Remove"
+     label_selected="Remove"
+     layout="topleft"
+     left_delta="0"
+     name="l_rem_btn"
+     top_pad="5"
+     width="73"
+     visible="false"/>
+    <button
+     enabled="false"
+     follows="left|top"
+     height="20"
+     label="Upload"
+     label_selected="Upload"
+     layout="topleft"
+     left_delta="0"
+     name="l_upl_btn"
+     top_pad="5"
+     width="73"
+     visible="false"/>
+    <scroll_list
+     name="l_name_list"
+     left="170"
+     top="22"
+     width="235"
+     height="260"
+     follows="left|top|right|bottom"
+     column_padding="0"
+     can_resize="false"
+     draw_heading="true"
+     multi_select="true"
+     search_column="1"
+     visible="false">
+        <column name="unit_name" label="Name" dynamicwidth="true" />
+        <column name="unit_id_HIDDEN" label="ID" width="0" />
+    </scroll_list>
+     
+<!-- bottom static -->
+    <button
+     follows="bottom"
      height="20"
      label="OK"
      label_selected="OK"
      layout="topleft"
-     right="-120"
+     left="95"
+     top="-30"
      name="Select"
      width="100" />
     <button
-     follows="right|bottom"
+     follows="bottom"
      height="20"
      label="Cancel"
      label_selected="Cancel"
      layout="topleft"
-     right="-10"
-     left_pad="5"
+     left_delta="120"
+     top_delta="0"
      name="Cancel"
      width="100" />
+    <check_box
+     follows="left|bottom"
+     height="20"
+     initial_value="true"
+     label="Apply now"
+     layout="topleft"
+     left="6"
+     name="apply_immediate_check"
+     top_delta="0"
+     width="120" />
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_window_size.xml b/indra/newview/skins/default/xui/en/floater_window_size.xml
index 355d25778542db0881796c7aa2f9412bc2ffd4a9..115fe413f3ca4e3dc96c1375ea660487cfed895f 100644
--- a/indra/newview/skins/default/xui/en/floater_window_size.xml
+++ b/indra/newview/skins/default/xui/en/floater_window_size.xml
@@ -28,22 +28,50 @@
      tool_tip="width x height"
      top_pad="5"
      width="179">
-        <combo_box.item
-         label="1000 x 700 (default)"
-         name="item0"
-         value="1000 x 700" />
-        <combo_box.item
-         label="1024 x 768"
-         name="item1"
-         value="1024 x 768" />
-        <combo_box.item
-         label="1280 x 720 (720p)"
-         name="item2"
-         value="1280 x 720" />
-        <combo_box.item
-         label="1920 x 1080 (1080p)"
-         name="item3"
-         value="1920 x 1080" />
+      <combo_box.item
+       label="1000 x 700 (default)"
+       name="item1"
+       value="1000 x 700" />
+      <combo_box.item
+       label="1024 x 768 (4:3 XGA)"
+       name="item2"
+       value="1024 x 768" />
+      <combo_box.item
+       label="1280 x 720 (16:9 HDTV)"
+       name="item3"
+       value="1280 x 720" />
+      <combo_box.item
+       label="1280 x 800 (5:8 WXGA)"
+       name="item4"
+       value="1280 x 800" />
+      <combo_box.item
+       label="1280 x 1024 (5:4 SXGA)"
+       name="item5"
+       value="1280 x 1024" />
+      <combo_box.item
+       label="1440 x 900 (8:5 WSXGA)"
+       name="item7"
+       value="1440 x 900" />
+      <combo_box.item
+       label="1600 x 900 (16:9 HD+)"
+       name="item8"
+       value="1600 x 900" />
+      <combo_box.item
+       label="1600 x 1200 (4:3 UXGA)"
+       name="item9"
+       value="1600 x 1200" />
+      <combo_box.item
+       label="1680 x 1050 (8:5 WSXGA+)"
+       name="item10"
+       value="1680 x 1050" />
+      <combo_box.item
+       label="1920 x 1080 (16:9 HDTV)"
+       name="item11"
+       value="1920 x 1080" />
+      <combo_box.item
+       label="1920 x 1200 (8:5 WUXGA)"
+       name="item12"
+       value="1920 x 1200" />
     </combo_box>
     <button
      follows="right|bottom"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 59dd17ea9d3e964e26df311cd178098e3ecf8ed5..afc5b916e77d5345896c82cf41587082bea2a0de 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -7696,4 +7696,31 @@ Otherwise, you can look at the Map and find places marked &quot;Infohub&quot;.
 You died and have been teleported to your home location.
   </global>
 
+  <notification
+   icon="alertmodal.tga"
+   name="LocalBitmapsUpdateFileNotFound"
+   persist="true"
+   type="notify">
+[FNAME] could not be updated because the file could no longer be found.
+Disabling future updates for this file.
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="LocalBitmapsUpdateFailedFinal"
+   persist="true"
+   type="notify">
+[FNAME] could not be opened or decoded for [NRETRIES] attempts, and is now considered broken.
+Disabling future updates for this file.
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="LocalBitmapsVerifyFail"
+   persist="true"
+   type="notify">
+Attempted to add an invalid or unreadable image file [FNAME] which could not be opened or decoded.
+Attempt cancelled.
+  </notification>
+  
 </notifications>