From b36dc363061ec5bf6b092c14193198e9a5eef816 Mon Sep 17 00:00:00 2001
From: Josh Bell <josh@lindenlab.com>
Date: Fri, 9 Mar 2007 01:09:20 +0000
Subject: [PATCH] svn merge -r 58902:58986
 svn+ssh://svn.lindenlab.com/svn/linden/branches/maintenance --> release

---
 indra/llcommon/llavatarconstants.h      |   12 +-
 indra/llcommon/llbase64.cpp             |   86 +-
 indra/llcommon/llbase64.h               |   38 +-
 indra/llcommon/llfasttimer.h            |    1 +
 indra/llcommon/llliveappconfig.cpp      |   92 +-
 indra/llcommon/llliveappconfig.h        |   66 +-
 indra/llcommon/lluri.cpp                |    3 +-
 indra/llcommon/metaproperty.cpp         |    2 +-
 indra/llimage/llimageworker.cpp         |  330 +--
 indra/llimage/llimageworker.h           |  114 +-
 indra/llmath/lloctree.h                 |    4 +
 indra/llrender/llimagegl.cpp            |    2 +
 indra/llrender/llvertexbuffer.cpp       |   32 +-
 indra/llrender/llvertexbuffer.h         |    6 +-
 indra/llui/llctrlselectioninterface.cpp |   88 +-
 indra/llui/llctrlselectioninterface.h   |  168 +-
 indra/llui/llscrolllistctrl.cpp         |    9 +-
 indra/llui/llviewquery.cpp              |  252 +--
 indra/llui/llviewquery.h                |  178 +-
 indra/newview/lldrawable.cpp            |    4 +-
 indra/newview/llface.cpp                |   10 +-
 indra/newview/llfasttimerview.cpp       |    2 +-
 indra/newview/llflexibleobject.cpp      |   17 +-
 indra/newview/llfloaterinspect.cpp      |  441 ++--
 indra/newview/llfloaterinspect.h        |  100 +-
 indra/newview/llfloaterland.cpp         |    4 +-
 indra/newview/llfloaterpostcard.cpp     |    2 +-
 indra/newview/llfloaterproperties.cpp   |    4 +-
 indra/newview/llfloatertools.cpp        |    2 +-
 indra/newview/llgroupmgr.cpp            |    4 +-
 indra/newview/llinventorybridge.cpp     |    8 +-
 indra/newview/llmaniptranslate.cpp      |    2 +
 indra/newview/llpanelavatar.cpp         |   22 +-
 indra/newview/llpanelclassified.cpp     |    9 +-
 indra/newview/llpanelgroup.cpp          |    2 +-
 indra/newview/llpanelgrouproles.cpp     |    7 +-
 indra/newview/llpreview.cpp             |    2 +-
 indra/newview/llselectmgr.cpp           |    2 +-
 indra/newview/llspatialpartition.cpp    |  118 +-
 indra/newview/llspatialpartition.h      |    3 +
 indra/newview/lltexturecache.cpp        | 2730 +++++++++++------------
 indra/newview/lltexturecache.h          |  298 +--
 indra/newview/lltexturefetch.cpp        |    6 +-
 indra/newview/lltexturefetch.h          |    2 +-
 indra/newview/llviewerdisplay.cpp       |   10 +-
 indra/newview/llviewermenu.cpp          |    3 +
 indra/newview/llviewermessage.cpp       |    2 +-
 indra/newview/llviewernetwork.cpp       |    2 +-
 indra/newview/llviewerparcelmgr.cpp     |   10 +-
 indra/newview/llviewerwindow.cpp        |    7 -
 indra/newview/llvoavatar.cpp            |   10 +-
 indra/newview/llvovolume.cpp            |   64 +-
 indra/newview/llvovolume.h              |    2 +-
 indra/newview/pipeline.cpp              |   11 +-
 indra/newview/pipeline.h                |    3 +-
 55 files changed, 2754 insertions(+), 2654 deletions(-)

diff --git a/indra/llcommon/llavatarconstants.h b/indra/llcommon/llavatarconstants.h
index 67bd329732c..d66627c4b02 100644
--- a/indra/llcommon/llavatarconstants.h
+++ b/indra/llcommon/llavatarconstants.h
@@ -20,16 +20,16 @@ const char* const BLACKLIST_PROFILE_WEB_URL = "http://secondlife.com/app/webdisa
 // Maximum number of avatar picks
 const S32 MAX_AVATAR_PICKS = 10;
 
-// For Flags in AvatarPropertiesReply
-const U32 AVATAR_ALLOW_PUBLISH			= 0x1 << 0;	// whether profile is externally visible or not
-const U32 AVATAR_MATURE_PUBLISH			= 0x1 << 1;	// profile is "mature"
-const U32 AVATAR_IDENTIFIED				= 0x1 << 2;	// whether avatar has provided payment info
+// For Flags in AvatarPropertiesReply
+const U32 AVATAR_ALLOW_PUBLISH			= 0x1 << 0;	// whether profile is externally visible or not
+const U32 AVATAR_MATURE_PUBLISH			= 0x1 << 1;	// profile is "mature"
+const U32 AVATAR_IDENTIFIED				= 0x1 << 2;	// whether avatar has provided payment info
 const U32 AVATAR_TRANSACTED				= 0x1 << 3;	// whether avatar has actively used payment info
 const U32 AVATAR_ONLINE					= 0x1 << 4; // the online status of this avatar, if known.
 
-static const std::string VISIBILITY_DEFAULT("default");
+static const std::string VISIBILITY_DEFAULT("default");
 static const std::string VISIBILITY_HIDDEN("hidden");
-static const std::string VISIBILITY_VISIBLE("visible");
+static const std::string VISIBILITY_VISIBLE("visible");
 static const std::string VISIBILITY_INVISIBLE("invisible");
 
 #endif
diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp
index 88e9d960a26..6c4bc59e68c 100644
--- a/indra/llcommon/llbase64.cpp
+++ b/indra/llcommon/llbase64.cpp
@@ -1,43 +1,43 @@
-/** 
- * @file llbase64.cpp
- * @brief Wrapper for apr base64 encoding that returns a std::string
- * @author James Cook
- *
- * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#include "linden_common.h"
-
-#include "llbase64.h"
-
-#include <string>
-
-#include "apr-1/apr_base64.h"
-
-
-// static
-std::string LLBase64::encode(const U8* input, size_t input_size)
-{
-	std::string output;
-	if (input
-		&& input_size > 0)
-	{
-		// Yes, it returns int.
-		int b64_buffer_length = apr_base64_encode_len(input_size);
-		char* b64_buffer = new char[b64_buffer_length];
-		
-		// This is faster than apr_base64_encode() if you know
-		// you're not on an EBCDIC machine.  Also, the output is
-		// null terminated, even though the documentation doesn't
-		// specify.  See apr_base64.c for details. JC
-		b64_buffer_length = apr_base64_encode_binary(
-			b64_buffer,
-			input,
-			input_size);
-		output.assign(b64_buffer);
-		delete[] b64_buffer;
-	}
-	return output;
-}
-
+/** 
+ * @file llbase64.cpp
+ * @brief Wrapper for apr base64 encoding that returns a std::string
+ * @author James Cook
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llbase64.h"
+
+#include <string>
+
+#include "apr-1/apr_base64.h"
+
+
+// static
+std::string LLBase64::encode(const U8* input, size_t input_size)
+{
+	std::string output;
+	if (input
+		&& input_size > 0)
+	{
+		// Yes, it returns int.
+		int b64_buffer_length = apr_base64_encode_len(input_size);
+		char* b64_buffer = new char[b64_buffer_length];
+		
+		// This is faster than apr_base64_encode() if you know
+		// you're not on an EBCDIC machine.  Also, the output is
+		// null terminated, even though the documentation doesn't
+		// specify.  See apr_base64.c for details. JC
+		b64_buffer_length = apr_base64_encode_binary(
+			b64_buffer,
+			input,
+			input_size);
+		output.assign(b64_buffer);
+		delete[] b64_buffer;
+	}
+	return output;
+}
+
diff --git a/indra/llcommon/llbase64.h b/indra/llcommon/llbase64.h
index 6e8b817ba73..4f59ceded68 100644
--- a/indra/llcommon/llbase64.h
+++ b/indra/llcommon/llbase64.h
@@ -1,19 +1,19 @@
-/** 
- * @file llbase64.h
- * @brief Wrapper for apr base64 encoding that returns a std::string
- * @author James Cook
- *
- * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#ifndef LLBASE64_H
-#define LLBASE64_h
-
-class LLBase64
-{
-public:
-	static std::string encode(const U8* input, size_t input_size);
-};
-
-#endif
+/** 
+ * @file llbase64.h
+ * @brief Wrapper for apr base64 encoding that returns a std::string
+ * @author James Cook
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LLBASE64_H
+#define LLBASE64_h
+
+class LLBase64
+{
+public:
+	static std::string encode(const U8* input, size_t input_size);
+};
+
+#endif
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 16af098ed5a..3e88784d3c0 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -25,6 +25,7 @@ class LLFastTimer
 		FTM_UPDATE,
 		FTM_RENDER,
 		FTM_SWAP,
+		FTM_CLIENT_COPY,
 		FTM_IDLE,
 		FTM_SLEEP,
 
diff --git a/indra/llcommon/llliveappconfig.cpp b/indra/llcommon/llliveappconfig.cpp
index 8bcaeb898f1..b446c1f18ee 100644
--- a/indra/llcommon/llliveappconfig.cpp
+++ b/indra/llcommon/llliveappconfig.cpp
@@ -1,46 +1,46 @@
-/** 
- * @file llliveappconfig.cpp
- * @brief Configuration information for an LLApp that overrides indra.xml
- *
- * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#include "linden_common.h"
-
-#include "llliveappconfig.h"
-
-#include "llapp.h"
-#include "llsd.h"
-#include "llsdserialize.h"
-
-LLLiveAppConfig::LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period)
-:	LLLiveFile(filename, refresh_period),
-	mApp(app)
-{ }
-
-
-LLLiveAppConfig::~LLLiveAppConfig()
-{ }
-
-// virtual 
-void LLLiveAppConfig::loadFile()
-{
-	llinfos << "LLLiveAppConfig::loadFile(): reading from "
-		<< filename() << llendl;
-    llifstream file(filename().c_str());
-	LLSD config;
-    if (file.is_open())
-    {
-        LLSDSerialize::fromXML(config, file);
-		if(!config.isMap())
-		{
-			llinfos << "LLDataserverConfig::loadFile(): not an map!"
-				<< " Ignoring the data." << llendl;
-			return;
-		}
-		file.close();
-    }
-	mApp->setOptionData(
-		LLApp::PRIORITY_SPECIFIC_CONFIGURATION, config);
-}
+/** 
+ * @file llliveappconfig.cpp
+ * @brief Configuration information for an LLApp that overrides indra.xml
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llliveappconfig.h"
+
+#include "llapp.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+
+LLLiveAppConfig::LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period)
+:	LLLiveFile(filename, refresh_period),
+	mApp(app)
+{ }
+
+
+LLLiveAppConfig::~LLLiveAppConfig()
+{ }
+
+// virtual 
+void LLLiveAppConfig::loadFile()
+{
+	llinfos << "LLLiveAppConfig::loadFile(): reading from "
+		<< filename() << llendl;
+    llifstream file(filename().c_str());
+	LLSD config;
+    if (file.is_open())
+    {
+        LLSDSerialize::fromXML(config, file);
+		if(!config.isMap())
+		{
+			llinfos << "LLDataserverConfig::loadFile(): not an map!"
+				<< " Ignoring the data." << llendl;
+			return;
+		}
+		file.close();
+    }
+	mApp->setOptionData(
+		LLApp::PRIORITY_SPECIFIC_CONFIGURATION, config);
+}
diff --git a/indra/llcommon/llliveappconfig.h b/indra/llcommon/llliveappconfig.h
index ceceda5b180..8875f3adc36 100644
--- a/indra/llcommon/llliveappconfig.h
+++ b/indra/llcommon/llliveappconfig.h
@@ -1,33 +1,33 @@
-/** 
- * @file llliveappconfig.h
- * @brief Configuration information for an LLApp that overrides indra.xml
- *
- * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#ifndef LLLIVEAPPCONFIG_H
-#define LLLIVEAPPCONFIG_H
-
-#include "lllivefile.h"
-
-class LLApp;
-
-class LLLiveAppConfig : public LLLiveFile
-{
-public:
-	// To use this, instantiate a LLLiveAppConfig object inside your main loop.
-	// The traditional name for it is live_config.
-	// Be sure to call live_config.checkAndReload() periodically.
-
-	LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period);
-	~LLLiveAppConfig();
-
-protected:
-	/*virtual*/ void loadFile();
-
-private:
-	LLApp* mApp;
-};
-
-#endif
+/** 
+ * @file llliveappconfig.h
+ * @brief Configuration information for an LLApp that overrides indra.xml
+ *
+ * Copyright (c) 2003-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LLLIVEAPPCONFIG_H
+#define LLLIVEAPPCONFIG_H
+
+#include "lllivefile.h"
+
+class LLApp;
+
+class LLLiveAppConfig : public LLLiveFile
+{
+public:
+	// To use this, instantiate a LLLiveAppConfig object inside your main loop.
+	// The traditional name for it is live_config.
+	// Be sure to call live_config.checkAndReload() periodically.
+
+	LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period);
+	~LLLiveAppConfig();
+
+protected:
+	/*virtual*/ void loadFile();
+
+private:
+	LLApp* mApp;
+};
+
+#endif
diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp
index cf06fe3f40b..1f64c3bde30 100644
--- a/indra/llcommon/lluri.cpp
+++ b/indra/llcommon/lluri.cpp
@@ -359,8 +359,7 @@ LLURI LLURI::buildHTTP(const std::string& host_port,
 	LLURI result;
 	
 	// TODO: deal with '/' '?' '#' in host_port
-	S32 index = host_port.find("://");
-	if (index != host_port.npos)
+	if (host_port.find("://") != host_port.npos)
 	{
 		// The scheme is part of the host_port
 		result.mScheme = "";
diff --git a/indra/llcommon/metaproperty.cpp b/indra/llcommon/metaproperty.cpp
index befee61a8ac..adcda033894 100644
--- a/indra/llcommon/metaproperty.cpp
+++ b/indra/llcommon/metaproperty.cpp
@@ -25,7 +25,7 @@ const LLMetaClass& LLMetaProperty::getObjectMetaClass() const
 {
 	return mObjectClass;
 }
-
+
 void LLMetaProperty::checkObjectClass(const LLReflective* object) const
 {
 	if(! mObjectClass.isInstance(object))
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index b44bf19227f..297482a2229 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -1,165 +1,165 @@
-/** 
- * @file llimage.cpp
- * @brief Base class for images.
- *
- * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#include "linden_common.h"
-
-#include "llimageworker.h"
-#include "llimagedxt.h"
-
-//----------------------------------------------------------------------------
-
-//static
-LLWorkerThread* LLImageWorker::sWorkerThread = NULL;
-S32 LLImageWorker::sCount = 0;
-
-//static
-void LLImageWorker::initClass(LLWorkerThread* workerthread)
-{
-	sWorkerThread = workerthread;
-}
-
-//static
-void LLImageWorker::cleanupClass()
-{
-}
-
-//----------------------------------------------------------------------------
-
-LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder)
-	: LLWorkerClass(sWorkerThread, "Image"),
-	  mFormattedImage(image),
-	  mDecodedType(-1),
-	  mDiscardLevel(discard),
-	  mPriority(priority),
-	  mResponder(responder)
-{
-	++sCount;
-}
-
-LLImageWorker::~LLImageWorker()
-{
-	mDecodedImage = NULL;
-	mFormattedImage = NULL;
-	--sCount;
-}
-
-//----------------------------------------------------------------------------
-
-//virtual, main thread
-void LLImageWorker::startWork(S32 param)
-{
-	llassert_always(mDecodedImage.isNull());
-	mDecodedType = -1;
-}
-
-bool LLImageWorker::doWork(S32 param)
-{
-	bool decoded = false;
-	if(mDecodedImage.isNull())
-	{
-		if (!mFormattedImage->updateData())
-		{
-			mDecodedType = -2; // failed
-			return true;
-		}
-		if (mDiscardLevel >= 0)
-		{
-			mFormattedImage->setDiscardLevel(mDiscardLevel);
-		}
-		if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
-		{
-			decoded = true; // failed
-		}
-		else
-		{
-			S32 nc = param ? 1 : mFormattedImage->getComponents();
-			mDecodedImage = new LLImageRaw(mFormattedImage->getWidth(),
-										   mFormattedImage->getHeight(),
-										   nc);
-		}
-	}
-	if (!decoded)
-	{
-		if (param == 0)
-		{
-			// Decode primary channels
-			decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms
-		}
-		else
-		{
-			// Decode aux channel
-			decoded = mFormattedImage->decode(mDecodedImage, .1f, param, param); // 1ms
-		}
-	}
-	if (decoded)
-	{
-		// Call the callback immediately; endWork doesn't get called until ckeckWork
-		if (mResponder.notNull())
-		{
-			bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0);
-			mResponder->completed(success);
-		}
-	}
-	return decoded;
-}
-
-void LLImageWorker::endWork(S32 param, bool aborted)
-{
-	if (mDecodedType != -2)
-	{
-		mDecodedType = aborted ? -2 : param;
-	}
-}
-
-//----------------------------------------------------------------------------
-
-
-BOOL LLImageWorker::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard)
-{
-	// For most codecs, only mDiscardLevel data is available.
-	//  (see LLImageDXT for exception)
-	if (discard >= 0 && discard != mFormattedImage->getDiscardLevel())
-	{
-		llerrs << "Request for invalid discard level" << llendl;
-	}
-	checkWork();
-	if (mDecodedType == -2)
-	{
-		return TRUE; // aborted, done
-	}
-	if (mDecodedType != channel)
-	{
-		if (!haveWork())
-		{
-			addWork(channel, mPriority);
-		}
-		return FALSE;
-	}
-	else
-	{
-		llassert_always(!haveWork());
-		llassert_always(mDecodedType == channel);
-		raw = mDecodedImage; // smart pointer acquires ownership of data
-		mDecodedImage = NULL;
-		return TRUE;
-	}
-}
-
-BOOL LLImageWorker::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard)
-{
-	if (mFormattedImage->getCodec() == IMG_CODEC_DXT)
-	{
-		// special case
-		LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage);
-		return imagedxt->getMipData(raw, discard);
-	}
-	else
-	{
-		return requestDecodedAuxData(raw, 0, discard);
-	}
-}
+/** 
+ * @file llimage.cpp
+ * @brief Base class for images.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llimageworker.h"
+#include "llimagedxt.h"
+
+//----------------------------------------------------------------------------
+
+//static
+LLWorkerThread* LLImageWorker::sWorkerThread = NULL;
+S32 LLImageWorker::sCount = 0;
+
+//static
+void LLImageWorker::initClass(LLWorkerThread* workerthread)
+{
+	sWorkerThread = workerthread;
+}
+
+//static
+void LLImageWorker::cleanupClass()
+{
+}
+
+//----------------------------------------------------------------------------
+
+LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder)
+	: LLWorkerClass(sWorkerThread, "Image"),
+	  mFormattedImage(image),
+	  mDecodedType(-1),
+	  mDiscardLevel(discard),
+	  mPriority(priority),
+	  mResponder(responder)
+{
+	++sCount;
+}
+
+LLImageWorker::~LLImageWorker()
+{
+	mDecodedImage = NULL;
+	mFormattedImage = NULL;
+	--sCount;
+}
+
+//----------------------------------------------------------------------------
+
+//virtual, main thread
+void LLImageWorker::startWork(S32 param)
+{
+	llassert_always(mDecodedImage.isNull());
+	mDecodedType = -1;
+}
+
+bool LLImageWorker::doWork(S32 param)
+{
+	bool decoded = false;
+	if(mDecodedImage.isNull())
+	{
+		if (!mFormattedImage->updateData())
+		{
+			mDecodedType = -2; // failed
+			return true;
+		}
+		if (mDiscardLevel >= 0)
+		{
+			mFormattedImage->setDiscardLevel(mDiscardLevel);
+		}
+		if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
+		{
+			decoded = true; // failed
+		}
+		else
+		{
+			S32 nc = param ? 1 : mFormattedImage->getComponents();
+			mDecodedImage = new LLImageRaw(mFormattedImage->getWidth(),
+										   mFormattedImage->getHeight(),
+										   nc);
+		}
+	}
+	if (!decoded)
+	{
+		if (param == 0)
+		{
+			// Decode primary channels
+			decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms
+		}
+		else
+		{
+			// Decode aux channel
+			decoded = mFormattedImage->decode(mDecodedImage, .1f, param, param); // 1ms
+		}
+	}
+	if (decoded)
+	{
+		// Call the callback immediately; endWork doesn't get called until ckeckWork
+		if (mResponder.notNull())
+		{
+			bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0);
+			mResponder->completed(success);
+		}
+	}
+	return decoded;
+}
+
+void LLImageWorker::endWork(S32 param, bool aborted)
+{
+	if (mDecodedType != -2)
+	{
+		mDecodedType = aborted ? -2 : param;
+	}
+}
+
+//----------------------------------------------------------------------------
+
+
+BOOL LLImageWorker::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard)
+{
+	// For most codecs, only mDiscardLevel data is available.
+	//  (see LLImageDXT for exception)
+	if (discard >= 0 && discard != mFormattedImage->getDiscardLevel())
+	{
+		llerrs << "Request for invalid discard level" << llendl;
+	}
+	checkWork();
+	if (mDecodedType == -2)
+	{
+		return TRUE; // aborted, done
+	}
+	if (mDecodedType != channel)
+	{
+		if (!haveWork())
+		{
+			addWork(channel, mPriority);
+		}
+		return FALSE;
+	}
+	else
+	{
+		llassert_always(!haveWork());
+		llassert_always(mDecodedType == channel);
+		raw = mDecodedImage; // smart pointer acquires ownership of data
+		mDecodedImage = NULL;
+		return TRUE;
+	}
+}
+
+BOOL LLImageWorker::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard)
+{
+	if (mFormattedImage->getCodec() == IMG_CODEC_DXT)
+	{
+		// special case
+		LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage);
+		return imagedxt->getMipData(raw, discard);
+	}
+	else
+	{
+		return requestDecodedAuxData(raw, 0, discard);
+	}
+}
diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h
index cdd30417cef..6e9ecacc894 100644
--- a/indra/llimage/llimageworker.h
+++ b/indra/llimage/llimageworker.h
@@ -1,57 +1,57 @@
-/** 
- * @file llimageworker.h
- * @brief Object for managing images and their textures.
- *
- * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#ifndef LL_LLIMAGEWORKER_H
-#define LL_LLIMAGEWORKER_H
-
-#include "llimage.h"
-#include "llworkerthread.h"
-
-class LLImageWorker : public LLWorkerClass
-{
-public:
-	static void initClass(LLWorkerThread* workerthread);
-	static void cleanupClass();
-	static LLWorkerThread* getWorkerThread() { return sWorkerThread; }
-
-	// LLWorkerThread
-public:
-	LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder = NULL);
-	~LLImageWorker();
-
-	// called from WORKER THREAD, returns TRUE if done
-	/*virtual*/ bool doWork(S32 param);
-	
-	BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1);
-	BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard = -1);
-	void releaseDecodedData();
-	void cancelDecode();
-
-private:
-	// called from MAIN THREAD
-	/*virtual*/ void startWork(S32 param); // called from addWork()
-	/*virtual*/ void endWork(S32 param, bool aborted); // called from doWork()
-
-protected:
-	LLPointer<LLImageFormatted> mFormattedImage;
-	LLPointer<LLImageRaw> mDecodedImage;
-	S32 mDecodedType;
-	S32 mDiscardLevel;
-
-private:
-	U32 mPriority;
-	LLPointer<LLResponder> mResponder;
-	
-protected:
-	static LLWorkerThread* sWorkerThread;
-
-public:
-	static S32 sCount;
-};
-
-#endif
+/** 
+ * @file llimageworker.h
+ * @brief Object for managing images and their textures.
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLIMAGEWORKER_H
+#define LL_LLIMAGEWORKER_H
+
+#include "llimage.h"
+#include "llworkerthread.h"
+
+class LLImageWorker : public LLWorkerClass
+{
+public:
+	static void initClass(LLWorkerThread* workerthread);
+	static void cleanupClass();
+	static LLWorkerThread* getWorkerThread() { return sWorkerThread; }
+
+	// LLWorkerThread
+public:
+	LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, LLResponder* responder = NULL);
+	~LLImageWorker();
+
+	// called from WORKER THREAD, returns TRUE if done
+	/*virtual*/ bool doWork(S32 param);
+	
+	BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1);
+	BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard = -1);
+	void releaseDecodedData();
+	void cancelDecode();
+
+private:
+	// called from MAIN THREAD
+	/*virtual*/ void startWork(S32 param); // called from addWork()
+	/*virtual*/ void endWork(S32 param, bool aborted); // called from doWork()
+
+protected:
+	LLPointer<LLImageFormatted> mFormattedImage;
+	LLPointer<LLImageRaw> mDecodedImage;
+	S32 mDecodedType;
+	S32 mDiscardLevel;
+
+private:
+	U32 mPriority;
+	LLPointer<LLResponder> mResponder;
+	
+protected:
+	static LLWorkerThread* sWorkerThread;
+
+public:
+	static S32 sCount;
+};
+
+#endif
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index e5b2a5f3126..f7ad3632061 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -21,7 +21,11 @@
 #endif
 
 #define LL_OCTREE_PARANOIA_CHECK 0
+#if LL_DARWIN
+#define LL_OCTREE_MAX_CAPACITY 32
+#else
 #define LL_OCTREE_MAX_CAPACITY 256
+#endif
 
 template <class T> class LLOctreeState;
 template <class T> class LLOctreeNode;
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 9c1178b9f75..1196db18fac 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -713,6 +713,8 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 		if (!res) llerrs << "LLImageGL::setSubImage(): bindTexture failed" << llendl;
 		stop_glerror();
 
+		LLGLEnable tex( GL_TEXTURE_2D ); 
+
 		glTexSubImage2D(mTarget, 0, x_pos, y_pos, 
 						width, height, mFormatPrimary, mFormatType, datap);
 		stop_glerror();
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index d6477d69ec2..b94f593d7f8 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -12,8 +12,8 @@
 S32 LLVertexBuffer::sCount = 0;
 S32 LLVertexBuffer::sGLCount = 0;
 BOOL LLVertexBuffer::sEnableVBOs = TRUE;
-S32 LLVertexBuffer::sGLRenderBuffer = 0;
-S32 LLVertexBuffer::sGLRenderIndices = 0;
+U32 LLVertexBuffer::sGLRenderBuffer = 0;
+U32 LLVertexBuffer::sGLRenderIndices = 0;
 U32 LLVertexBuffer::sLastMask = 0;
 BOOL LLVertexBuffer::sVBOActive = FALSE;
 BOOL LLVertexBuffer::sIBOActive = FALSE;
@@ -92,7 +92,7 @@ void LLVertexBuffer::stopRender()
 	sRenderActive = FALSE;
 }
 
-void LLVertexBuffer::clientCopy()
+void LLVertexBuffer::clientCopy(F64 max_time)
 {
 	if (!sDeleteList.empty())
 	{
@@ -122,7 +122,7 @@ void LLVertexBuffer::clientCopy()
 			}
 			else
 			{
-				if (timer.getElapsedTimeF64() > 0.005)
+				if (timer.getElapsedTimeF64() > max_time)
 				{
 					break;
 				}
@@ -191,7 +191,10 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 	mNumVerts(0), mNumIndices(0), mUsage(usage), mGLBuffer(0), mGLIndices(0), 
 	mMappedData(NULL),
 	mMappedIndexData(NULL), mLocked(FALSE),
-	mResized(FALSE), mEmpty(TRUE), mFinal(FALSE), mFilthy(FALSE)
+	mFinal(FALSE),
+	mFilthy(FALSE),
+	mEmpty(TRUE),
+	mResized(FALSE)
 {
 	LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
 	if (!sEnableVBOs)
@@ -614,7 +617,6 @@ void LLVertexBuffer::unmapBuffer()
 						{
 							DirtyRegion& region = *i;
 							glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, region.mIndex*mStride, region.mCount*mStride, mMappedData + region.mIndex*mStride);
-							glFlush();
 						}
 					}
 				}
@@ -639,7 +641,6 @@ void LLVertexBuffer::unmapBuffer()
 							DirtyRegion& region = *i;
 							glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, region.mIndicesIndex*sizeof(U32), 
 								region.mIndicesCount*sizeof(U32), mMappedIndexData + region.mIndicesIndex*sizeof(U32));
-							glFlush();
 						}
 					}
 				}
@@ -786,13 +787,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 		unmapBuffer();
 	}
 	else
-	{
-		if (!mDirtyRegions.empty())
-		{
-			mFilthy = TRUE;
-			mDirtyRegions.clear();
-		}
-		
+	{		
 		if (mGLBuffer)
 		{
 			if (sEnableVBOs && sVBOActive)
@@ -890,6 +885,15 @@ void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index
 		if (!mDirtyRegions.empty())
 		{
 			DirtyRegion& region = *(mDirtyRegions.rbegin());
+			
+			if (region.mIndex+region.mCount > vert_index)
+			{
+				//this buffer has received multiple updates since the last copy, mark it filthy
+				mFilthy = TRUE;
+				mDirtyRegions.clear();
+				return;
+			}
+			
 			if (region.mIndex + region.mCount == vert_index &&
 				region.mIndicesIndex + region.mIndicesCount == indices_index)
 			{
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index e672321e761..b221d35ee3b 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -29,7 +29,7 @@ class LLVertexBuffer : public LLRefCount
 	static void cleanupClass();
  	static void startRender(); //between start and stop render, no client copies will occur
 	static void stopRender(); //any buffer not copied to GL will be rendered from client memory
-	static void clientCopy(); //copy data from client to GL
+	static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
 	static void unbind(); //unbind any bound vertex buffer
 
 	enum {
@@ -167,8 +167,8 @@ class LLVertexBuffer : public LLRefCount
 	
 	static BOOL sEnableVBOs;
 	static S32 sTypeOffsets[TYPE_MAX];
-	static S32 sGLRenderBuffer;
-	static S32 sGLRenderIndices;
+	static U32 sGLRenderBuffer;
+	static U32 sGLRenderIndices;
 	static BOOL sVBOActive;
 	static BOOL sIBOActive;
 	static U32 sLastMask;
diff --git a/indra/llui/llctrlselectioninterface.cpp b/indra/llui/llctrlselectioninterface.cpp
index a58fb88e757..61044aa7da7 100644
--- a/indra/llui/llctrlselectioninterface.cpp
+++ b/indra/llui/llctrlselectioninterface.cpp
@@ -1,44 +1,44 @@
-/** 
- * @file llctrlselectioninterface.cpp
- * @brief Programmatic selection of items in a list.
- *
- * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#include "llctrlselectioninterface.h"
-
-#include "llsd.h"
-
-// virtual
-LLCtrlSelectionInterface::~LLCtrlSelectionInterface()
-{ }
-
-BOOL LLCtrlSelectionInterface::selectByValue(LLSD value)
-{
-	return setSelectedByValue(value, TRUE);
-}
-
-BOOL LLCtrlSelectionInterface::deselectByValue(LLSD value)
-{ 
-	return setSelectedByValue(value, FALSE); 
-}
-
-
-// virtual
-LLCtrlListInterface::~LLCtrlListInterface()
-{ }
-
-LLScrollListItem* LLCtrlListInterface::addSimpleElement(const LLString& value)
-{
-	return addSimpleElement(value, ADD_BOTTOM, LLSD());
-}
-
-LLScrollListItem* LLCtrlListInterface::addSimpleElement(const LLString& value, EAddPosition pos)
-{
-	return addSimpleElement(value, pos, LLSD());
-}
-
-// virtual
-LLCtrlScrollInterface::~LLCtrlScrollInterface()
-{ }
+/** 
+ * @file llctrlselectioninterface.cpp
+ * @brief Programmatic selection of items in a list.
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llctrlselectioninterface.h"
+
+#include "llsd.h"
+
+// virtual
+LLCtrlSelectionInterface::~LLCtrlSelectionInterface()
+{ }
+
+BOOL LLCtrlSelectionInterface::selectByValue(LLSD value)
+{
+	return setSelectedByValue(value, TRUE);
+}
+
+BOOL LLCtrlSelectionInterface::deselectByValue(LLSD value)
+{ 
+	return setSelectedByValue(value, FALSE); 
+}
+
+
+// virtual
+LLCtrlListInterface::~LLCtrlListInterface()
+{ }
+
+LLScrollListItem* LLCtrlListInterface::addSimpleElement(const LLString& value)
+{
+	return addSimpleElement(value, ADD_BOTTOM, LLSD());
+}
+
+LLScrollListItem* LLCtrlListInterface::addSimpleElement(const LLString& value, EAddPosition pos)
+{
+	return addSimpleElement(value, pos, LLSD());
+}
+
+// virtual
+LLCtrlScrollInterface::~LLCtrlScrollInterface()
+{ }
diff --git a/indra/llui/llctrlselectioninterface.h b/indra/llui/llctrlselectioninterface.h
index 4e2807e9a1f..698d609593b 100644
--- a/indra/llui/llctrlselectioninterface.h
+++ b/indra/llui/llctrlselectioninterface.h
@@ -1,84 +1,84 @@
-/** 
- * @file llctrlselectioninterface.h
- * @brief Programmatic selection of items in a list.
- *
- * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#ifndef LLCTRLSELECTIONINTERFACE_H
-#define LLCTRLSELECTIONINTERFACE_H
-
-#include "stdtypes.h"
-#include "stdenums.h"
-#include "llstring.h"
-
-class LLSD;
-class LLUUID;
-class LLScrollListItem;
-
-class LLCtrlSelectionInterface
-{
-public:
-	virtual ~LLCtrlSelectionInterface();
-	
-	enum EOperation
-	{
-		OP_DELETE = 1,
-		OP_SELECT,
-		OP_DESELECT,
-	};
-
-	virtual BOOL	getCanSelect() const = 0;
-
-	virtual BOOL	selectFirstItem() = 0;
-	virtual BOOL	selectNthItem( S32 index ) = 0;
-
-	virtual S32		getFirstSelectedIndex() = 0;
-
-	// TomY TODO: Simply cast the UUIDs to LLSDs, using the selectByValue function
-	virtual BOOL	setCurrentByID( const LLUUID& id ) = 0;
-	virtual LLUUID	getCurrentID() = 0;
-
-			BOOL	selectByValue(LLSD value);
-			BOOL	deselectByValue(LLSD value);
-	virtual BOOL	setSelectedByValue(LLSD value, BOOL selected) = 0;
-	virtual LLSD	getSimpleSelectedValue() = 0;
-
-	virtual BOOL	isSelected(LLSD value) = 0;
-
-	virtual BOOL	operateOnSelection(EOperation op) = 0;
-	virtual BOOL	operateOnAll(EOperation op) = 0;
-};
-
-class LLCtrlListInterface : public LLCtrlSelectionInterface
-{
-public:
-	virtual ~LLCtrlListInterface();
-	
-	virtual S32 getItemCount() const = 0;
-	virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0;
-	virtual void clearColumns() = 0;
-	virtual void setColumnLabel(const LLString& column, const LLString& label) = 0;
-	// TomY TODO: Document this
-	virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) = 0;
-
-	LLScrollListItem* addSimpleElement(const LLString& value); // defaults to bottom
-	LLScrollListItem* addSimpleElement(const LLString& value, EAddPosition pos); // defaults to no LLSD() id
-	virtual LLScrollListItem* addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id) = 0;
-
-	virtual void clearRows() = 0;
-	virtual void sortByColumn(LLString name, BOOL ascending) = 0;
-};
-
-class LLCtrlScrollInterface
-{
-public:
-	virtual ~LLCtrlScrollInterface();
-	
-	virtual S32 getScrollPos() = 0;
-	virtual void setScrollPos( S32 pos ) = 0;
-	virtual void scrollToShowSelected() = 0;
-};
-
-#endif
+/** 
+ * @file llctrlselectioninterface.h
+ * @brief Programmatic selection of items in a list.
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LLCTRLSELECTIONINTERFACE_H
+#define LLCTRLSELECTIONINTERFACE_H
+
+#include "stdtypes.h"
+#include "stdenums.h"
+#include "llstring.h"
+
+class LLSD;
+class LLUUID;
+class LLScrollListItem;
+
+class LLCtrlSelectionInterface
+{
+public:
+	virtual ~LLCtrlSelectionInterface();
+	
+	enum EOperation
+	{
+		OP_DELETE = 1,
+		OP_SELECT,
+		OP_DESELECT,
+	};
+
+	virtual BOOL	getCanSelect() const = 0;
+
+	virtual BOOL	selectFirstItem() = 0;
+	virtual BOOL	selectNthItem( S32 index ) = 0;
+
+	virtual S32		getFirstSelectedIndex() = 0;
+
+	// TomY TODO: Simply cast the UUIDs to LLSDs, using the selectByValue function
+	virtual BOOL	setCurrentByID( const LLUUID& id ) = 0;
+	virtual LLUUID	getCurrentID() = 0;
+
+			BOOL	selectByValue(LLSD value);
+			BOOL	deselectByValue(LLSD value);
+	virtual BOOL	setSelectedByValue(LLSD value, BOOL selected) = 0;
+	virtual LLSD	getSimpleSelectedValue() = 0;
+
+	virtual BOOL	isSelected(LLSD value) = 0;
+
+	virtual BOOL	operateOnSelection(EOperation op) = 0;
+	virtual BOOL	operateOnAll(EOperation op) = 0;
+};
+
+class LLCtrlListInterface : public LLCtrlSelectionInterface
+{
+public:
+	virtual ~LLCtrlListInterface();
+	
+	virtual S32 getItemCount() const = 0;
+	virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0;
+	virtual void clearColumns() = 0;
+	virtual void setColumnLabel(const LLString& column, const LLString& label) = 0;
+	// TomY TODO: Document this
+	virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) = 0;
+
+	LLScrollListItem* addSimpleElement(const LLString& value); // defaults to bottom
+	LLScrollListItem* addSimpleElement(const LLString& value, EAddPosition pos); // defaults to no LLSD() id
+	virtual LLScrollListItem* addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id) = 0;
+
+	virtual void clearRows() = 0;
+	virtual void sortByColumn(LLString name, BOOL ascending) = 0;
+};
+
+class LLCtrlScrollInterface
+{
+public:
+	virtual ~LLCtrlScrollInterface();
+	
+	virtual S32 getScrollPos() = 0;
+	virtual void setScrollPos( S32 pos ) = 0;
+	virtual void scrollToShowSelected() = 0;
+};
+
+#endif
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index f2ae318dca9..35d5affa5d8 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -377,20 +377,21 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
 	mFgUnselectedColor( LLUI::sColorsGroup->getColor("ScrollUnselectedColor") ),
 	mFgDisabledColor( LLUI::sColorsGroup->getColor("ScrollDisabledColor") ),
 	mHighlightedColor( LLUI::sColorsGroup->getColor("ScrollHighlightedColor") ),
-	mHighlightedItem(-1),
 	mBorderThickness( 2 ),
 	mOnDoubleClickCallback( NULL ),
 	mOnMaximumSelectCallback( NULL ),
 	mOnSortChangedCallback( NULL ),
-	mDrewSelected(FALSE),
+	mHighlightedItem(-1),
 	mBorder(NULL),
-	mSearchColumn(0),
 	mDefaultColumn("SIMPLE"),
+	mSearchColumn(0),
 
 	mNumDynamicWidthColumns(0),
 	mTotalStaticColumnWidth(0),
 	mSortColumn(0),
-	mSortAscending(TRUE)
+	mSortAscending(TRUE),
+
+	mDrewSelected(FALSE)
 {
 	mItemListRect.setOriginAndSize(
 		mBorderThickness + LIST_BORDER_PAD,
diff --git a/indra/llui/llviewquery.cpp b/indra/llui/llviewquery.cpp
index 416ca623bcf..650125d4867 100644
--- a/indra/llui/llviewquery.cpp
+++ b/indra/llui/llviewquery.cpp
@@ -1,126 +1,126 @@
-/** 
- * @file llviewquery.cpp
- * @brief Implementation of view query class.
- *
- * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#include "llview.h"
-#include "lluictrl.h"
-#include "llviewquery.h"
-
-void LLQuerySorter::operator() (LLView * parent, viewList_t &children) const {}
-
-filterResult_t LLNoLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const 
-{
-	return filterResult_t(!(view->getChildList()->size() == 0), TRUE);
-}
-
-filterResult_t LLVisibleFilter::operator() (const LLView* const view, const viewList_t & children) const 
-{
-	return filterResult_t(view->getVisible(), view->getVisible());
-}
-filterResult_t LLEnabledFilter::operator() (const LLView* const view, const viewList_t & children) const 
-{
-	return filterResult_t(view->getEnabled(), view->getEnabled());
-}
-filterResult_t LLTabStopFilter::operator() (const LLView* const view, const viewList_t & children) const 
-{
-	return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl* const>(view)->hasTabStop(),
-						view->canFocusChildren());
-}
-
-// LLViewQuery
-
-LLViewQuery::LLViewQuery(): mPreFilters(), mPostFilters(), mSorterp() 
-{
-}
-
-void LLViewQuery::addPreFilter(const LLQueryFilter* prefilter) { mPreFilters.push_back(prefilter); }
-
-void LLViewQuery::addPostFilter(const LLQueryFilter* postfilter) {	mPostFilters.push_back(postfilter); }
-
-const LLViewQuery::filterList_t & LLViewQuery::getPreFilters() const { return mPreFilters; }
-
-const LLViewQuery::filterList_t & LLViewQuery::getPostFilters() const { return mPostFilters; }
-
-void LLViewQuery::setSorter(const LLQuerySorter* sorterp) { mSorterp = sorterp; }
-const LLQuerySorter* LLViewQuery::getSorter() const { return mSorterp; }
-
-viewList_t LLViewQuery::run(LLView * view) const
-{
-	viewList_t result;
-
-	filterResult_t pre = runFilters(view, viewList_t(), mPreFilters);
-	if(!pre.first && !pre.second)
-	{
-		// skip post filters completely if we're not including ourselves or the children
-		return result;
-	}
-	if(pre.second)
-	{
-		// run filters on children
-		viewList_t filtered_children;
-		filterChildren(view, filtered_children);
-		filterResult_t post = runFilters(view, filtered_children, mPostFilters);
-		if(pre.first && post.first)
-		{
-			result.push_back(view);
-		}
-		if(post.second)
-		{
-			result.insert(result.end(), filtered_children.begin(), filtered_children.end());
-		}
-	}
-	else 
-	{
-		if(pre.first) 
-		{
-			result.push_back(view);
-		}
-	}
-	return result;
-}
-
-void LLViewQuery::filterChildren(LLView * view, viewList_t & filtered_children) const
-{
-	LLView::child_list_t views(*(view->getChildList()));
-	(*mSorterp)(view, views); // sort the children per the sorter
-	for(LLView::child_list_iter_t iter = views.begin();
-			iter != views.end();
-			iter++)
-		{
-			viewList_t indiv_children = this->run(*iter);
-			filtered_children.insert(filtered_children.end(), indiv_children.begin(), indiv_children.end());
-		}
-}
-
-filterResult_t LLViewQuery::runFilters(LLView * view, const viewList_t children, const filterList_t filters) const
-{
-	filterResult_t result = filterResult_t(TRUE, TRUE);
-	for(filterList_const_iter_t iter = filters.begin();
-		iter != filters.end();
-		iter++)
-	{
-		filterResult_t filtered = (**iter)(view, children);
-		result.first = result.first && filtered.first;
-		result.second = result.second && filtered.second;
-	}
-	return result;
-}
-
-class SortByTabOrder : public LLQuerySorter, public LLSingleton<SortByTabOrder>
-{
-	/*virtual*/ void operator() (LLView * parent, LLView::child_list_t &children) const 
-	{
-		children.sort(LLCompareByTabOrder(parent->getCtrlOrder()));
-	}
-};
-
-LLCtrlQuery::LLCtrlQuery() : 
-	LLViewQuery()
-{
-	setSorter(SortByTabOrder::getInstance());
-}
-
+/** 
+ * @file llviewquery.cpp
+ * @brief Implementation of view query class.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llview.h"
+#include "lluictrl.h"
+#include "llviewquery.h"
+
+void LLQuerySorter::operator() (LLView * parent, viewList_t &children) const {}
+
+filterResult_t LLNoLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const 
+{
+	return filterResult_t(!(view->getChildList()->size() == 0), TRUE);
+}
+
+filterResult_t LLVisibleFilter::operator() (const LLView* const view, const viewList_t & children) const 
+{
+	return filterResult_t(view->getVisible(), view->getVisible());
+}
+filterResult_t LLEnabledFilter::operator() (const LLView* const view, const viewList_t & children) const 
+{
+	return filterResult_t(view->getEnabled(), view->getEnabled());
+}
+filterResult_t LLTabStopFilter::operator() (const LLView* const view, const viewList_t & children) const 
+{
+	return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl* const>(view)->hasTabStop(),
+						view->canFocusChildren());
+}
+
+// LLViewQuery
+
+LLViewQuery::LLViewQuery(): mPreFilters(), mPostFilters(), mSorterp() 
+{
+}
+
+void LLViewQuery::addPreFilter(const LLQueryFilter* prefilter) { mPreFilters.push_back(prefilter); }
+
+void LLViewQuery::addPostFilter(const LLQueryFilter* postfilter) {	mPostFilters.push_back(postfilter); }
+
+const LLViewQuery::filterList_t & LLViewQuery::getPreFilters() const { return mPreFilters; }
+
+const LLViewQuery::filterList_t & LLViewQuery::getPostFilters() const { return mPostFilters; }
+
+void LLViewQuery::setSorter(const LLQuerySorter* sorterp) { mSorterp = sorterp; }
+const LLQuerySorter* LLViewQuery::getSorter() const { return mSorterp; }
+
+viewList_t LLViewQuery::run(LLView * view) const
+{
+	viewList_t result;
+
+	filterResult_t pre = runFilters(view, viewList_t(), mPreFilters);
+	if(!pre.first && !pre.second)
+	{
+		// skip post filters completely if we're not including ourselves or the children
+		return result;
+	}
+	if(pre.second)
+	{
+		// run filters on children
+		viewList_t filtered_children;
+		filterChildren(view, filtered_children);
+		filterResult_t post = runFilters(view, filtered_children, mPostFilters);
+		if(pre.first && post.first)
+		{
+			result.push_back(view);
+		}
+		if(post.second)
+		{
+			result.insert(result.end(), filtered_children.begin(), filtered_children.end());
+		}
+	}
+	else 
+	{
+		if(pre.first) 
+		{
+			result.push_back(view);
+		}
+	}
+	return result;
+}
+
+void LLViewQuery::filterChildren(LLView * view, viewList_t & filtered_children) const
+{
+	LLView::child_list_t views(*(view->getChildList()));
+	(*mSorterp)(view, views); // sort the children per the sorter
+	for(LLView::child_list_iter_t iter = views.begin();
+			iter != views.end();
+			iter++)
+		{
+			viewList_t indiv_children = this->run(*iter);
+			filtered_children.insert(filtered_children.end(), indiv_children.begin(), indiv_children.end());
+		}
+}
+
+filterResult_t LLViewQuery::runFilters(LLView * view, const viewList_t children, const filterList_t filters) const
+{
+	filterResult_t result = filterResult_t(TRUE, TRUE);
+	for(filterList_const_iter_t iter = filters.begin();
+		iter != filters.end();
+		iter++)
+	{
+		filterResult_t filtered = (**iter)(view, children);
+		result.first = result.first && filtered.first;
+		result.second = result.second && filtered.second;
+	}
+	return result;
+}
+
+class SortByTabOrder : public LLQuerySorter, public LLSingleton<SortByTabOrder>
+{
+	/*virtual*/ void operator() (LLView * parent, LLView::child_list_t &children) const 
+	{
+		children.sort(LLCompareByTabOrder(parent->getCtrlOrder()));
+	}
+};
+
+LLCtrlQuery::LLCtrlQuery() : 
+	LLViewQuery()
+{
+	setSorter(SortByTabOrder::getInstance());
+}
+
diff --git a/indra/llui/llviewquery.h b/indra/llui/llviewquery.h
index ba59965c593..32852791af9 100644
--- a/indra/llui/llviewquery.h
+++ b/indra/llui/llviewquery.h
@@ -1,89 +1,89 @@
-/** 
- * @file llviewquery.h
- * @brief Query algorithm for flattening and filtering the view hierarchy.
- *
- * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#ifndef LL_LLVIEWQUERY_H
-#define LL_LLVIEWQUERY_H
-
-#include <list>	
-
-#include "llmemory.h"
-
-class LLView;
-
-typedef std::list<LLView *>			viewList_t;
-typedef std::pair<BOOL, BOOL>		filterResult_t;
-
-// Abstract base class for all filters.
-class LLQueryFilter : public LLRefCount
-{
-public:
-	virtual filterResult_t operator() (const LLView* const view, const viewList_t & children) const =0;
-};
-
-class LLQuerySorter : public LLRefCount
-{
-public:
-	virtual void operator() (LLView * parent, viewList_t &children) const;
-};
-
-class LLNoLeavesFilter : public LLQueryFilter, public LLSingleton<LLNoLeavesFilter>
-{
-	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
-};
-class LLVisibleFilter : public LLQueryFilter, public LLSingleton<LLVisibleFilter>
-{
-	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
-};
-class LLEnabledFilter : public LLQueryFilter, public LLSingleton<LLEnabledFilter>
-{
-	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
-};
-class LLTabStopFilter : public LLQueryFilter, public LLSingleton<LLTabStopFilter>
-{
-	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
-};
-
-// Algorithm for flattening
-class LLViewQuery
-{
-public:
-	typedef std::list<const LLQueryFilter*>		filterList_t;
-	typedef filterList_t::iterator				filterList_iter_t;
-	typedef filterList_t::const_iterator		filterList_const_iter_t;
-
-	LLViewQuery();
-	virtual ~LLViewQuery() {}
-
-	void addPreFilter(const LLQueryFilter* prefilter);
-	void addPostFilter(const LLQueryFilter* postfilter);
-	const filterList_t & getPreFilters() const;
-	const filterList_t & getPostFilters() const;
-
-	void setSorter(const LLQuerySorter* sorter);
-	const LLQuerySorter* getSorter() const;
-
-	viewList_t run(LLView * view) const;
-	// syntactic sugar
-	viewList_t operator () (LLView * view) const { return run(view); }
-protected:
-	// override this method to provide iteration over other types of children
-	virtual void filterChildren(LLView * view, viewList_t & filtered_children) const;
-	filterResult_t runFilters(LLView * view, const viewList_t children, const filterList_t filters) const;
-protected:
-	filterList_t mPreFilters;
-	filterList_t mPostFilters;
-	const LLQuerySorter* mSorterp;
-};
-
-class LLCtrlQuery : public LLViewQuery
-{
-public:
-	LLCtrlQuery();
-};
-
-#endif
+/** 
+ * @file llviewquery.h
+ * @brief Query algorithm for flattening and filtering the view hierarchy.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLVIEWQUERY_H
+#define LL_LLVIEWQUERY_H
+
+#include <list>	
+
+#include "llmemory.h"
+
+class LLView;
+
+typedef std::list<LLView *>			viewList_t;
+typedef std::pair<BOOL, BOOL>		filterResult_t;
+
+// Abstract base class for all filters.
+class LLQueryFilter : public LLRefCount
+{
+public:
+	virtual filterResult_t operator() (const LLView* const view, const viewList_t & children) const =0;
+};
+
+class LLQuerySorter : public LLRefCount
+{
+public:
+	virtual void operator() (LLView * parent, viewList_t &children) const;
+};
+
+class LLNoLeavesFilter : public LLQueryFilter, public LLSingleton<LLNoLeavesFilter>
+{
+	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+};
+class LLVisibleFilter : public LLQueryFilter, public LLSingleton<LLVisibleFilter>
+{
+	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+};
+class LLEnabledFilter : public LLQueryFilter, public LLSingleton<LLEnabledFilter>
+{
+	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+};
+class LLTabStopFilter : public LLQueryFilter, public LLSingleton<LLTabStopFilter>
+{
+	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+};
+
+// Algorithm for flattening
+class LLViewQuery
+{
+public:
+	typedef std::list<const LLQueryFilter*>		filterList_t;
+	typedef filterList_t::iterator				filterList_iter_t;
+	typedef filterList_t::const_iterator		filterList_const_iter_t;
+
+	LLViewQuery();
+	virtual ~LLViewQuery() {}
+
+	void addPreFilter(const LLQueryFilter* prefilter);
+	void addPostFilter(const LLQueryFilter* postfilter);
+	const filterList_t & getPreFilters() const;
+	const filterList_t & getPostFilters() const;
+
+	void setSorter(const LLQuerySorter* sorter);
+	const LLQuerySorter* getSorter() const;
+
+	viewList_t run(LLView * view) const;
+	// syntactic sugar
+	viewList_t operator () (LLView * view) const { return run(view); }
+protected:
+	// override this method to provide iteration over other types of children
+	virtual void filterChildren(LLView * view, viewList_t & filtered_children) const;
+	filterResult_t runFilters(LLView * view, const viewList_t children, const filterList_t filters) const;
+protected:
+	filterList_t mPreFilters;
+	filterList_t mPostFilters;
+	const LLQuerySorter* mSorterp;
+};
+
+class LLCtrlQuery : public LLViewQuery
+{
+public:
+	LLCtrlQuery();
+};
+
+#endif
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 868d61942d3..3418007d418 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -908,8 +908,8 @@ void LLDrawable::updateLightSet()
 		// mLightSet points to nearby lights
 		mLightSet.clear();
 		part->getLights(getPositionAgent(), getRadius(), mLightSet);
-		const S32 max_lights = 16;
-		if (mLightSet.size() > max_lights)
+		const drawable_set_t::size_type MAX_LIGHTS = 16;
+		if (mLightSet.size() > MAX_LIGHTS)
 		{
 			typedef std::set<std::pair<F32,LLPointer<LLDrawable> > > sorted_pair_set_t;
 			sorted_pair_set_t sorted_set;
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 64edcecdc65..bb76957da1b 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -711,11 +711,13 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 	const LLVolumeFace &face = volume.getVolumeFace(f);
 	
 	//get bounding box
-	if (mDrawablep->isState(LLDrawable::REBUILD_ALL))
+	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
 	{
-		//vertex buffer no longer valid
-		mVertexBuffer = NULL;
-		mLastVertexBuffer = NULL;
+		if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
+		{ //vertex buffer no longer valid
+			mVertexBuffer = NULL;
+			mLastVertexBuffer = NULL;
+		}
 
 		LLVector3 min,max;
 			
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 85b8bbebd43..cbcdfaa55cf 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -159,7 +159,7 @@ static struct ft_display_info ft_display_table[] =
 //	{ LLFastTimer::FTM_RENDER_FONTS,		"   Fonts",			&LLColor4::pink1, 0 },
 //	{ LLFastTimer::FTM_UPDATE_TEXTURES,		"  Textures",		&LLColor4::pink2, 0 },
 	{ LLFastTimer::FTM_SWAP,				"  Swap",			&LLColor4::pink1, 0 },
-// 	{ LLFastTimer::FTM_TEMP6,				"  Client Copy",	&LLColor4::red1, 1},
+	{ LLFastTimer::FTM_CLIENT_COPY,			"  Client Copy",	&LLColor4::red1, 1},
 	
 //	{ LLFastTimer::FTM_TEMP1,				" Temp1",			&LLColor4::red1, 0 },
 // 	{ LLFastTimer::FTM_TEMP2,				" Temp2",			&LLColor4::magenta1, 0 },
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
index 4e03e346632..020ce00bab8 100644
--- a/indra/newview/llflexibleobject.cpp
+++ b/indra/newview/llflexibleobject.cpp
@@ -216,12 +216,6 @@ void LLVolumeImplFlexible::setAttributesOfAllSections()
 
 void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, const S32 detail)
 {
-	if (mVO && mVO->mDrawable.notNull())
-	{
-		LLVOVolume* volume = (LLVOVolume*) mVO;
-		volume->regenFaces();
-	}
-
 	/*doIdleUpdate(gAgent, *gWorldp, 0.0);
 	if (mVO && mVO->mDrawable.notNull())
 	{
@@ -615,11 +609,19 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 	{
 		LLVolumeParams volume_params = volume->getVolume()->getParams();
 		volume->setVolume(volume_params, 0);
+		mUpdated = FALSE;
 	}
 
 	volume->updateRelativeXform();
 	doFlexibleUpdate();
-	if (!mUpdated || volume->mFaceMappingChanged)
+	
+	if (volume->mLODChanged || volume->mFaceMappingChanged ||
+		volume->mVolumeChanged)
+	{
+		volume->regenFaces();
+	}
+
+	if (!mUpdated || volume->mFaceMappingChanged || volume->mVolumeChanged)
 	{
 		doFlexibleRebuild();
 		volume->genBBoxes(isVolumeGlobal());
@@ -629,6 +631,7 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 	volume->mLODChanged = FALSE;
 	volume->mFaceMappingChanged = FALSE;
 
+
 	// clear UV flag
 	drawable->clearState(LLDrawable::UV);
 	
diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp
index 0b9d836a1a7..8bb73e3a9b5 100644
--- a/indra/newview/llfloaterinspect.cpp
+++ b/indra/newview/llfloaterinspect.cpp
@@ -1,220 +1,221 @@
-#include "llviewerprecompiledheaders.h"
-#include "llfloateravatarinfo.h"
-#include "llfloaterinspect.h"
-#include "llfloatertools.h"
-#include "llcachename.h"
-#include "llscrolllistctrl.h"
-#include "llselectmgr.h"
-#include "lltoolcomp.h"
-#include "lltoolmgr.h"
-#include "llviewercontrol.h"
-#include "llviewerobject.h"
-#include "llvieweruictrlfactory.h"
-
-LLFloaterInspect* LLFloaterInspect::sInstance = NULL;
-
-LLFloaterInspect::LLFloaterInspect(void) :
-	LLFloater("Inspect Object"),
-	mDirty(FALSE)
-{
-	sInstance = this;
-	gUICtrlFactory->buildFloater(this, "floater_inspect.xml");
-}
-
-LLFloaterInspect::~LLFloaterInspect(void)
-{
-	if(!gFloaterTools->getVisible())
-	{
-		if(gToolMgr->getBaseTool() == gToolInspect)
-		{
-			select_tool(gToolNull);
-		}
-		// Switch back to basic toolset
-		gToolMgr->setCurrentToolset(gBasicToolset);
-	}
-	else
-	{
-		gFloaterTools->setFocus(TRUE);
-	}
-	sInstance = NULL;
-}
-
-BOOL LLFloaterInspect::isVisible()
-{
-	return (!!sInstance);
-}
-
-void LLFloaterInspect::show(void* ignored)
-{
-	if(sInstance)
-	{
-		sInstance->open();
-	}
-	else
-	{
-		LLFloaterInspect* self = new LLFloaterInspect;
-		self->open();
-	}
-
-	sInstance->mObjectSelection = gSelectMgr->getSelection();
-	select_tool(gToolInspect);
-	sInstance->refresh();
-}
-
-void LLFloaterInspect::onClickCreatorProfile(void* ctrl)
-{
-	if(sInstance->mObjectList->getAllSelected().size() == 0) return;
-	LLSelectNode* obj = sInstance->mObjectSelection->getFirstNode();
-	LLUUID obj_id, creator_id;
-	obj_id = sInstance->mObjectList->getFirstSelected()->getUUID();
-	while(obj)
-	{
-		if(obj_id == obj->getObject()->getID())
-		{
-			creator_id = obj->mPermissions->getCreator();
-			break;
-		}
-		obj = sInstance->mObjectSelection->getNextNode();
-	}
-	if(obj)
-	{
-		LLFloaterAvatarInfo::showFromDirectory(creator_id);
-	}
-}
-
-void LLFloaterInspect::onClickOwnerProfile(void* ctrl)
-{
-	if(sInstance->mObjectList->getAllSelected().size() == 0) return;
-	LLSelectNode* obj = sInstance->mObjectSelection->getFirstNode();
-	LLUUID obj_id, owner_id;
-	obj_id = sInstance->mObjectList->getFirstSelected()->getUUID();
-	while(obj)
-	{
-		if(obj_id == obj->getObject()->getID())
-		{
-			owner_id = obj->mPermissions->getOwner();
-			break;
-		}
-		obj = sInstance->mObjectSelection->getNextNode();
-	}
-	if(obj)
-	{
-		LLFloaterAvatarInfo::showFromDirectory(owner_id);
-	}
-}
-
-BOOL LLFloaterInspect::postBuild()
-{
-	mObjectList = LLUICtrlFactory::getScrollListByName(this, "object_list");
-	childSetAction("button owner",onClickOwnerProfile, this);
-	childSetAction("button creator",onClickCreatorProfile, this);
-	childSetCommitCallback("object_list", onSelectObject);
-	return TRUE;
-}
-
-void LLFloaterInspect::onSelectObject(LLUICtrl* ctrl, void* user_data)
-{
-	if(LLFloaterInspect::getSelectedUUID() != LLUUID::null)
-	{
-		sInstance->childSetEnabled("button owner", true);
-		sInstance->childSetEnabled("button creator", true);
-	}
-}
-
-LLUUID LLFloaterInspect::getSelectedUUID()
-{
-	if(sInstance)
-	{
-		if(sInstance->mObjectList->getAllSelected().size() > 0) return sInstance->mObjectList->getFirstSelected()->getUUID();
-	}
-	return LLUUID::null;
-}
-
-void LLFloaterInspect::refresh()
-{
-	LLUUID creator_id;
-	LLString creator_name;
-	S32 pos = mObjectList->getScrollPos();
-	childSetEnabled("button owner", false);
-	childSetEnabled("button creator", false);
-	LLUUID selected_uuid;
-	S32 selected_index = mObjectList->getFirstSelectedIndex();
-	if(selected_index > -1) selected_uuid = mObjectList->getFirstSelected()->getUUID();
-	mObjectList->operateOnAll(LLScrollListCtrl::OP_DELETE);
-	//List all transient objects, then all linked objects
-	LLSelectNode* obj = mObjectSelection->getFirstNode();
-	LLSD row;
-	while(obj)
-	{
-		char owner_first_name[MAX_STRING], owner_last_name[MAX_STRING];
-		char creator_first_name[MAX_STRING], creator_last_name[MAX_STRING];
-		char time[MAX_STRING];
-		std::ostringstream owner_name, creator_name, date;
-		time_t timestamp = (time_t) (obj->mCreationDate/1000000);
-		LLString::copy(time, ctime(&timestamp), MAX_STRING);
-		time[24] = '\0';
-		date << obj->mCreationDate;
-		gCacheName->getName(obj->mPermissions->getOwner(), owner_first_name, owner_last_name);
-		owner_name << owner_first_name << " " << owner_last_name;
-		gCacheName->getName(obj->mPermissions->getCreator(), creator_first_name, creator_last_name);
-		creator_name << creator_first_name << " " << creator_last_name;
-		row["id"] = obj->getObject()->getID();
-		row["columns"][0]["column"] = "object_name";
-		row["columns"][0]["type"] = "text";
-		// make sure we're either at the top of the link chain
-		// or top of the editable chain, for attachments
-		if(!(obj->getObject()->isRoot() || obj->getObject()->isRootEdit()))
-		{
-			row["columns"][0]["value"] = LLString("   ") + obj->mName;
-		}
-		else
-		{
-			row["columns"][0]["value"] = obj->mName;
-		}
-		row["columns"][1]["column"] = "owner_name";
-		row["columns"][1]["type"] = "text";
-		row["columns"][1]["value"] = owner_name.str().c_str();
-		row["columns"][2]["column"] = "creator_name";
-		row["columns"][2]["type"] = "text";
-		row["columns"][2]["value"] = creator_name.str().c_str();
-		row["columns"][3]["column"] = "creation_date";
-		row["columns"][3]["type"] = "text";
-		row["columns"][3]["value"] = time;
-		mObjectList->addElement(row, ADD_TOP);
-		obj = mObjectSelection->getNextNode();
-	}
-	if(selected_index > -1 && mObjectList->getItemIndex(selected_uuid) == selected_index)
-	{
-		mObjectList->selectNthItem(selected_index);
-	}
-	else
-	{
-		mObjectList->selectNthItem(0);
-	}
-	onSelectObject(this, NULL);
-	mObjectList->setScrollPos(pos);
-}
-
-void LLFloaterInspect::onFocusReceived()
-{
-	select_tool(gToolInspect);
-}
-
-void LLFloaterInspect::dirty()
-{
-	if(sInstance)
-	{
-		sInstance->setDirty();
-	}
-}
-
-void LLFloaterInspect::draw()
-{
-	if (mDirty)
-	{
-		refresh();
-		mDirty = FALSE;
-	}
-
-	LLFloater::draw();
-}
\ No newline at end of file
+#include "llviewerprecompiledheaders.h"
+#include "llfloateravatarinfo.h"
+#include "llfloaterinspect.h"
+#include "llfloatertools.h"
+#include "llcachename.h"
+#include "llscrolllistctrl.h"
+#include "llselectmgr.h"
+#include "lltoolcomp.h"
+#include "lltoolmgr.h"
+#include "llviewercontrol.h"
+#include "llviewerobject.h"
+#include "llvieweruictrlfactory.h"
+
+LLFloaterInspect* LLFloaterInspect::sInstance = NULL;
+
+LLFloaterInspect::LLFloaterInspect(void) :
+	LLFloater("Inspect Object"),
+	mDirty(FALSE)
+{
+	sInstance = this;
+	gUICtrlFactory->buildFloater(this, "floater_inspect.xml");
+}
+
+LLFloaterInspect::~LLFloaterInspect(void)
+{
+	if(!gFloaterTools->getVisible())
+	{
+		if(gToolMgr->getBaseTool() == gToolInspect)
+		{
+			select_tool(gToolNull);
+		}
+		// Switch back to basic toolset
+		gToolMgr->setCurrentToolset(gBasicToolset);
+	}
+	else
+	{
+		gFloaterTools->setFocus(TRUE);
+	}
+	sInstance = NULL;
+}
+
+BOOL LLFloaterInspect::isVisible()
+{
+	return (!!sInstance);
+}
+
+void LLFloaterInspect::show(void* ignored)
+{
+	if(sInstance)
+	{
+		sInstance->open();
+	}
+	else
+	{
+		LLFloaterInspect* self = new LLFloaterInspect;
+		self->open();
+	}
+
+	sInstance->mObjectSelection = gSelectMgr->getSelection();
+	select_tool(gToolInspect);
+	sInstance->refresh();
+}
+
+void LLFloaterInspect::onClickCreatorProfile(void* ctrl)
+{
+	if(sInstance->mObjectList->getAllSelected().size() == 0) return;
+	LLSelectNode* obj = sInstance->mObjectSelection->getFirstNode();
+	LLUUID obj_id, creator_id;
+	obj_id = sInstance->mObjectList->getFirstSelected()->getUUID();
+	while(obj)
+	{
+		if(obj_id == obj->getObject()->getID())
+		{
+			creator_id = obj->mPermissions->getCreator();
+			break;
+		}
+		obj = sInstance->mObjectSelection->getNextNode();
+	}
+	if(obj)
+	{
+		LLFloaterAvatarInfo::showFromDirectory(creator_id);
+	}
+}
+
+void LLFloaterInspect::onClickOwnerProfile(void* ctrl)
+{
+	if(sInstance->mObjectList->getAllSelected().size() == 0) return;
+	LLSelectNode* obj = sInstance->mObjectSelection->getFirstNode();
+	LLUUID obj_id, owner_id;
+	obj_id = sInstance->mObjectList->getFirstSelected()->getUUID();
+	while(obj)
+	{
+		if(obj_id == obj->getObject()->getID())
+		{
+			owner_id = obj->mPermissions->getOwner();
+			break;
+		}
+		obj = sInstance->mObjectSelection->getNextNode();
+	}
+	if(obj)
+	{
+		LLFloaterAvatarInfo::showFromDirectory(owner_id);
+	}
+}
+
+BOOL LLFloaterInspect::postBuild()
+{
+	mObjectList = LLUICtrlFactory::getScrollListByName(this, "object_list");
+	childSetAction("button owner",onClickOwnerProfile, this);
+	childSetAction("button creator",onClickCreatorProfile, this);
+	childSetCommitCallback("object_list", onSelectObject);
+	return TRUE;
+}
+
+void LLFloaterInspect::onSelectObject(LLUICtrl* ctrl, void* user_data)
+{
+	if(LLFloaterInspect::getSelectedUUID() != LLUUID::null)
+	{
+		sInstance->childSetEnabled("button owner", true);
+		sInstance->childSetEnabled("button creator", true);
+	}
+}
+
+LLUUID LLFloaterInspect::getSelectedUUID()
+{
+	if(sInstance)
+	{
+		if(sInstance->mObjectList->getAllSelected().size() > 0) return sInstance->mObjectList->getFirstSelected()->getUUID();
+	}
+	return LLUUID::null;
+}
+
+void LLFloaterInspect::refresh()
+{
+	LLUUID creator_id;
+	LLString creator_name;
+	S32 pos = mObjectList->getScrollPos();
+	childSetEnabled("button owner", false);
+	childSetEnabled("button creator", false);
+	LLUUID selected_uuid;
+	S32 selected_index = mObjectList->getFirstSelectedIndex();
+	if(selected_index > -1) selected_uuid = mObjectList->getFirstSelected()->getUUID();
+	mObjectList->operateOnAll(LLScrollListCtrl::OP_DELETE);
+	//List all transient objects, then all linked objects
+	LLSelectNode* obj = mObjectSelection->getFirstNode();
+	LLSD row;
+	while(obj)
+	{
+		char owner_first_name[MAX_STRING], owner_last_name[MAX_STRING];
+		char creator_first_name[MAX_STRING], creator_last_name[MAX_STRING];
+		char time[MAX_STRING];
+		std::ostringstream owner_name, creator_name, date;
+		time_t timestamp = (time_t) (obj->mCreationDate/1000000);
+		LLString::copy(time, ctime(&timestamp), MAX_STRING);
+		time[24] = '\0';
+		date << obj->mCreationDate;
+		gCacheName->getName(obj->mPermissions->getOwner(), owner_first_name, owner_last_name);
+		owner_name << owner_first_name << " " << owner_last_name;
+		gCacheName->getName(obj->mPermissions->getCreator(), creator_first_name, creator_last_name);
+		creator_name << creator_first_name << " " << creator_last_name;
+		row["id"] = obj->getObject()->getID();
+		row["columns"][0]["column"] = "object_name";
+		row["columns"][0]["type"] = "text";
+		// make sure we're either at the top of the link chain
+		// or top of the editable chain, for attachments
+		if(!(obj->getObject()->isRoot() || obj->getObject()->isRootEdit()))
+		{
+			row["columns"][0]["value"] = LLString("   ") + obj->mName;
+		}
+		else
+		{
+			row["columns"][0]["value"] = obj->mName;
+		}
+		row["columns"][1]["column"] = "owner_name";
+		row["columns"][1]["type"] = "text";
+		row["columns"][1]["value"] = owner_name.str().c_str();
+		row["columns"][2]["column"] = "creator_name";
+		row["columns"][2]["type"] = "text";
+		row["columns"][2]["value"] = creator_name.str().c_str();
+		row["columns"][3]["column"] = "creation_date";
+		row["columns"][3]["type"] = "text";
+		row["columns"][3]["value"] = time;
+		mObjectList->addElement(row, ADD_TOP);
+		obj = mObjectSelection->getNextNode();
+	}
+	if(selected_index > -1 && mObjectList->getItemIndex(selected_uuid) == selected_index)
+	{
+		mObjectList->selectNthItem(selected_index);
+	}
+	else
+	{
+		mObjectList->selectNthItem(0);
+	}
+	onSelectObject(this, NULL);
+	mObjectList->setScrollPos(pos);
+}
+
+void LLFloaterInspect::onFocusReceived()
+{
+	select_tool(gToolInspect);
+}
+
+void LLFloaterInspect::dirty()
+{
+	if(sInstance)
+	{
+		sInstance->setDirty();
+	}
+}
+
+void LLFloaterInspect::draw()
+{
+	if (mDirty)
+	{
+		refresh();
+		mDirty = FALSE;
+	}
+
+	LLFloater::draw();
+}
+
diff --git a/indra/newview/llfloaterinspect.h b/indra/newview/llfloaterinspect.h
index 6a3f4949782..d221879d0eb 100644
--- a/indra/newview/llfloaterinspect.h
+++ b/indra/newview/llfloaterinspect.h
@@ -1,50 +1,50 @@
-/** 
-* @file llfloaterfriends.h
-* @author Cube
-* @date 2006-12-16
-* @brief Declaration of class for displaying object attributes
-*
-* Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
-* $License$
-*/
-
-#ifndef LL_LLFLOATERINSPECT_H
-#define LL_LLFLOATERINSPECT_H
-
-#include "llfloater.h"
-
-//class LLTool;
-class LLObjectSelection;
-class LLScrollListCtrl;
-class LLUICtrl;
-
-class LLFloaterInspect : public LLFloater
-{
-public:
-	virtual ~LLFloaterInspect(void);
-	static void show(void* ignored = NULL);
-	virtual BOOL postBuild();
-	static void dirty();
-	static LLUUID getSelectedUUID();
-	virtual void draw();
-	virtual void refresh();
-	static BOOL isVisible();
-	virtual void onFocusReceived();
-	static void onClickCreatorProfile(void* ctrl);
-	static void onClickOwnerProfile(void* ctrl);
-	static void onSelectObject(LLUICtrl* ctrl, void* user_data);
-	LLScrollListCtrl* mObjectList;
-protected:
-	// protected members
-	LLFloaterInspect();
-	void setDirty() { mDirty = TRUE; }
-	bool mDirty;
-
-private:
-	// static data
-	static LLFloaterInspect* sInstance;
-
-	LLHandle<LLObjectSelection> mObjectSelection;
-};
-
-#endif //LL_LLFLOATERINSPECT_H
\ No newline at end of file
+/** 
+* @file llfloaterfriends.h
+* @author Cube
+* @date 2006-12-16
+* @brief Declaration of class for displaying object attributes
+*
+* Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+* $License$
+*/
+
+#ifndef LL_LLFLOATERINSPECT_H
+#define LL_LLFLOATERINSPECT_H
+
+#include "llfloater.h"
+
+//class LLTool;
+class LLObjectSelection;
+class LLScrollListCtrl;
+class LLUICtrl;
+
+class LLFloaterInspect : public LLFloater
+{
+public:
+	virtual ~LLFloaterInspect(void);
+	static void show(void* ignored = NULL);
+	virtual BOOL postBuild();
+	static void dirty();
+	static LLUUID getSelectedUUID();
+	virtual void draw();
+	virtual void refresh();
+	static BOOL isVisible();
+	virtual void onFocusReceived();
+	static void onClickCreatorProfile(void* ctrl);
+	static void onClickOwnerProfile(void* ctrl);
+	static void onSelectObject(LLUICtrl* ctrl, void* user_data);
+	LLScrollListCtrl* mObjectList;
+protected:
+	// protected members
+	LLFloaterInspect();
+	void setDirty() { mDirty = TRUE; }
+	bool mDirty;
+
+private:
+	// static data
+	static LLFloaterInspect* sInstance;
+
+	LLHandle<LLObjectSelection> mObjectSelection;
+};
+
+#endif //LL_LLFLOATERINSPECT_H
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 6f698d2734c..3492f4fff84 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -346,8 +346,8 @@ void* LLFloaterLand::createPanelLandBan(void* data)
 
 LLPanelLandGeneral::LLPanelLandGeneral(LLParcelSelectionHandle& parcel)
 :	LLPanel("land_general_panel"),
-	mParcel(parcel),
-	mUncheckedSell(FALSE)
+	mUncheckedSell(FALSE),
+	mParcel(parcel)
 {
 }
 
diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp
index f6fcda29a3f..f82978c5fc9 100644
--- a/indra/newview/llfloaterpostcard.cpp
+++ b/indra/newview/llfloaterpostcard.cpp
@@ -51,8 +51,8 @@ LLLinkedList<LLFloaterPostcard> LLFloaterPostcard::sInstances;
 
 LLFloaterPostcard::LLFloaterPostcard(LLImageJPEG* jpeg, LLImageGL *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global)
 :	LLFloater("Postcard Floater"),
-	mViewerImage(img),
 	mJPEGImage(jpeg),
+	mViewerImage(img),
 	mImageScale(img_scale),
 	mPosTakenGlobal(pos_taken_global)
 {
diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp
index 793884e0081..feeedc5190d 100644
--- a/indra/newview/llfloaterproperties.cpp
+++ b/indra/newview/llfloaterproperties.cpp
@@ -214,7 +214,7 @@ void LLFloaterProperties::refresh()
 			"RadioSaleType",
 			"EditPrice"
 		};
-		for(int t=0;t<sizeof(enableNames)/sizeof(char*);t++)
+		for(size_t t=0; t<sizeof(enableNames)/sizeof(char*); ++t)
 		{
 			childSetEnabled(enableNames[t],false);
 		}
@@ -225,7 +225,7 @@ void LLFloaterProperties::refresh()
 			"EveryoneMaskDebug",
 			"NextMaskDebug"
 		};
-		for(int t=0;t<sizeof(hideNames)/sizeof(char*);t++)
+		for(size_t t=0; t<sizeof(hideNames)/sizeof(char*); ++t)
 		{
 			childSetVisible(hideNames[t],false);
 		}
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 34eb8415681..63b17346429 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -245,7 +245,7 @@ BOOL	LLFloaterTools::postBuild()
 			&LLToolPlacerPanel::sTriangleTorus,
 			&LLToolPlacerPanel::sTree,
 			&LLToolPlacerPanel::sGrass};
-	for(int t=0;t<sizeof(toolNames)/sizeof(toolNames[0]);t++)
+	for(size_t t=0; t<sizeof(toolNames)/sizeof(toolNames[0]); ++t)
 	{
 		LLButton *found = LLViewerUICtrlFactory::getButtonByName(this,toolNames[t]);
 		if(found)
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 33a675b59ed..00108650ef4 100644
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -843,7 +843,7 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
 		}
 	}
 
-	if (group_datap->mMembers.size() ==  group_datap->mMemberCount)
+	if (group_datap->mMembers.size() ==  (U32)group_datap->mMemberCount)
 	{
 		group_datap->mMemberDataComplete = TRUE;
 		group_datap->mMemberRequestID.setNull();
@@ -979,7 +979,7 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data)
 		group_data->mRoles[role_id] = rd;
 	}
 
-	if (group_data->mRoles.size() == group_data->mRoleCount)
+	if (group_data->mRoles.size() == (U32)group_data->mRoleCount)
 	{
 		group_data->mRoleDataComplete = TRUE;
 		group_data->mRoleDataRequestID.setNull();
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index f090cea5f20..4de746fd4f5 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -2174,6 +2174,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 		case LLAssetType::AT_CATEGORY:
 			is_movable = ( LLAssetType::AT_NONE == ((LLInventoryCategory*)inv_item)->getPreferredType() );
 			break;
+		default:
+			break;
 		}
 
 		LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
@@ -2190,6 +2192,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 			case LLAssetType::AT_OBJECT:
 				is_movable = !avatar->isWearingAttachment(inv_item->getUUID());
 				break;
+			default:
+				break;
 			}
 		}
  
@@ -2759,6 +2763,8 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
 				}
 				break;
 			}
+		default:
+			break;
 		}
 	}
 	return rv;
@@ -3407,8 +3413,8 @@ struct LLFoundData
 				LLAssetType::EType asset_type) :
 		mItemID(item_id),
 		mAssetID(asset_id),
-		mAssetType(asset_type),
 		mName(name),
+		mAssetType(asset_type),
 		mWearable( NULL ) {}
 	
 	LLUUID mItemID;
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 93ae74db22e..9e26d951bc4 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -1120,6 +1120,8 @@ void LLManipTranslate::renderSnapGuides()
 			inner_color.setVec(1,1,0,line_alpha);
 			mManipPart = LL_XY_PLANE;
 			break;
+		default:
+			break;
 		}
 
 		highlightIntersection(normal, selection_center, grid_rotation, inner_color);
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 810e026d2ac..3ec14b6117e 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -512,25 +512,25 @@ BOOL LLPanelAvatarPicks::postBuild(void)
 	return TRUE;
 }
 
-BOOL	LLPanelAvatarAdvanced::postBuild()
+BOOL LLPanelAvatarAdvanced::postBuild()
 {
-	for( S32 i = 0; i < kArraySize(mWantToCheck); i++ )
-		mWantToCheck[i] = NULL;
-	for( S32 i = 0; i < kArraySize(mSkillsCheck); i++ )
-		mSkillsCheck[i] = NULL;
+	for(size_t ii = 0; ii < kArraySize(mWantToCheck); ++ii)
+		mWantToCheck[ii] = NULL;
+	for(size_t ii = 0; ii < kArraySize(mSkillsCheck); ++ii)
+		mSkillsCheck[ii] = NULL;
 	mWantToCount = (8>kArraySize(mWantToCheck))?kArraySize(mWantToCheck):8;
-	for(int t=0;t < mWantToCount ;t++)
+	for(S32 tt=0; tt < mWantToCount; ++tt)
 	{	
-		LLString ctlname = llformat("chk%d",t);
-		mWantToCheck[t] = LLUICtrlFactory::getCheckBoxByName(this,ctlname);
+		LLString ctlname = llformat("chk%d", tt);
+		mWantToCheck[tt] = LLUICtrlFactory::getCheckBoxByName(this,ctlname);
 	}	
 	mSkillsCount = (6>kArraySize(mSkillsCheck))?kArraySize(mSkillsCheck):6;
 
-	for(int t=0;t<mSkillsCount;t++)
+	for(S32 tt=0; tt < mSkillsCount; ++tt)
 	{
 		//Find the Skills checkboxes and save off thier controls
-		LLString ctlname = llformat("schk%d",t);
-		mSkillsCheck[t] = LLUICtrlFactory::getCheckBoxByName(this,ctlname);
+		LLString ctlname = llformat("schk%d",tt);
+		mSkillsCheck[tt] = LLUICtrlFactory::getCheckBoxByName(this,ctlname);
 	}
 
 	mWantToEdit = LLUICtrlFactory::getLineEditorByName(this,"want_to_edit");
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp
index 2c6cbb9c08b..9adc737aab9 100644
--- a/indra/newview/llpanelclassified.cpp
+++ b/indra/newview/llpanelclassified.cpp
@@ -83,16 +83,17 @@ LLPanelClassified::LLPanelClassified(BOOL in_finder)
 	mDataRequested(FALSE),
 	mEnableCommit(FALSE),
 	mPaidFor(FALSE),
-	mParcelID(),
     mPosGlobal(),
     mSnapshotCtrl(NULL),
     mNameEditor(NULL),
-    mLocationEditor(NULL),
     mDescEditor(NULL),
+    mLocationEditor(NULL),
+	mCategoryCombo(NULL),
+	mUpdateBtn(NULL),
     mTeleportBtn(NULL),
     mMapBtn(NULL),
-    //mLandmarkBtn(NULL),
-    //mEnabledCheck(NULL),
+	mProfileBtn(NULL),
+	mInfoText(NULL),
 	mMatureCheck(NULL),
 	mAutoRenewCheck(NULL),
     mSetBtn(NULL),
diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp
index 9ad5855b8e2..121dc4c67ea 100644
--- a/indra/newview/llpanelgroup.cpp
+++ b/indra/newview/llpanelgroup.cpp
@@ -132,8 +132,8 @@ LLPanelGroup::LLPanelGroup(const std::string& filename,
 	mCurrentTab( NULL ),
 	mRequestedTab( NULL ),
 	mTabContainer( NULL ),
-	mForceClose( FALSE ),
 	mIgnoreTransition( FALSE ),
+	mForceClose( FALSE ),
 	mInitialTab(initial_tab_selected),
 	mAllowEdit( TRUE ),
 	mShowingNotifyDialog( FALSE )
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index 0e295df94a1..bda962ca563 100644
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -1101,7 +1101,10 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
 				check->setCommitCallback(onRoleCheck);
 				check->setCallbackUserData(this);
 				check->set( count > 0 );
-				check->setTentative(0 != count && selected_members.size() != count);
+				check->setTentative(
+					(0 != count)
+					&& (selected_members.size() !=
+						(std::vector<LLUUID>::size_type)count));
 
 				//NOTE: as of right now a user can break the group
 				//by removing himself from a role if he is the
@@ -1996,7 +1999,7 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc)
 
 		mRolesList->sortByColumn("name", TRUE);
 
-		if ( (gdatap->mRoles.size() < MAX_ROLES)
+		if ( (gdatap->mRoles.size() < (U32)MAX_ROLES)
 			&& gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CREATE) )
 		{
 			mCreateRoleButton->setEnabled(TRUE);
diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp
index c5e589529c9..91df61ca910 100644
--- a/indra/newview/llpreview.cpp
+++ b/indra/newview/llpreview.cpp
@@ -513,4 +513,4 @@ void LLMultiPreview::setAutoOpenInstance(LLMultiPreview* previewp, const LLUUID&
 	{
 		sAutoOpenPreviewHandles[id] = previewp->getHandle();
 	}
-}
\ No newline at end of file
+}
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 950ed61b253..3eddc04259b 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -5770,8 +5770,8 @@ BOOL LLSelectMgr::canSelectObject(LLViewerObject* object)
 LLObjectSelection::LLObjectSelection() : 
 	std::list<LLSelectNode*>(), 
 	LLRefCount(),
-	mCurrentTE(-1),
 	mCurrentNode(end()),
+	mCurrentTE(-1),
 	mSelectType(SELECT_TYPE_WORLD)
 {
 }
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 739d30bfe68..62903011cf1 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -289,6 +289,7 @@ void LLSpatialGroup::validateDrawMap()
 
 void LLSpatialGroup::makeStatic()
 {
+#if !LL_DARWIN
 	if (isState(GEOM_DIRTY | ALPHA_DIRTY))
 	{
 		return;
@@ -309,6 +310,7 @@ void LLSpatialGroup::makeStatic()
 		
 		mBuilt = 1.f;
 	}
+#endif
 }
 
 BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
@@ -318,7 +320,12 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
 	drawablep->updateSpatialExtents();
 	validate_drawable(drawablep);
 
-	if (mOctreeNode->isInside(drawablep) && mOctreeNode->contains(drawablep))
+	OctreeNode* parent = mOctreeNode->getOctParent();
+	
+	if (mOctreeNode->isInside(drawablep->getPositionGroup()) && 
+		(mOctreeNode->contains(drawablep) ||
+		 (drawablep->getBinRadius() > mOctreeNode->getSize().mdV[0] &&
+				parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY)))
 	{
 		unbound();
 		setState(OBJECT_DIRTY);
@@ -697,14 +704,21 @@ void LLSpatialGroup::clearState(U32 state, S32 mode)
 //		Octree Listener Implementation
 //======================================
 
-LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part)
-: mOctreeNode(node), mState(0), mSpatialPartition(part), mVertexBuffer(NULL), 
-  mDistance(0.f), mLastUpdateDistance(-1.f), 
-  mViewAngle(0.f), mLastUpdateViewAngle(-1.f), 
-  mDepth(0.f), mBuilt(0.f),
-  mLastUpdateTime(gFrameTimeSeconds), mLastRenderTime(gFrameTimeSeconds),
-  mLastAddTime(gFrameTimeSeconds),
-  mBufferUsage(GL_STATIC_DRAW_ARB)
+LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
+	mState(0),
+	mBuilt(0.f),
+	mOctreeNode(node),
+	mSpatialPartition(part),
+	mVertexBuffer(NULL), 
+	mBufferUsage(GL_STATIC_DRAW_ARB),
+	mDistance(0.f),
+	mDepth(0.f),
+	mLastUpdateDistance(-1.f), 
+	mLastUpdateTime(gFrameTimeSeconds),
+	mLastAddTime(gFrameTimeSeconds),
+	mLastRenderTime(gFrameTimeSeconds),
+	mViewAngle(0.f),
+	mLastUpdateViewAngle(-1.f)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 
@@ -898,6 +912,31 @@ void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNo
 	unbound();
 }
 
+void LLSpatialGroup::destroyGL() 
+{
+	setState(LLSpatialGroup::GEOM_DIRTY | 
+					LLSpatialGroup::OCCLUSION_DIRTY |
+					LLSpatialGroup::IMAGE_DIRTY);
+	mLastUpdateTime = gFrameTimeSeconds;
+	mVertexBuffer = NULL;
+	mBufferMap.clear();
+
+	mOcclusionVerts = NULL;
+	mReflectionMap = NULL;
+	clearDrawMap();
+
+	for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
+	{
+		LLDrawable* drawable = *i;
+		for (S32 j = 0; j < drawable->getNumFaces(); j++)
+		{
+			LLFace* facep = drawable->getFace(j);
+			facep->mVertexBuffer = NULL;
+			facep->mLastVertexBuffer = NULL;
+		}
+	}
+}
+
 BOOL LLSpatialGroup::rebound()
 {
 	if (!isState(DIRTY))
@@ -1423,28 +1462,11 @@ class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
 	virtual void visit(const LLOctreeState<LLDrawable>* state)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
+		group->destroyGL();
 
-		group->setState(LLSpatialGroup::GEOM_DIRTY | 
-						LLSpatialGroup::OCCLUSION_DIRTY |
-						LLSpatialGroup::IMAGE_DIRTY);
-		group->mLastUpdateTime = gFrameTimeSeconds;
-		group->mVertexBuffer = NULL;
-		group->mBufferMap.clear();
-
-		group->mOcclusionVerts = NULL;
-		group->mReflectionMap = NULL;
-		group->clearDrawMap();
-	
 		for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
 		{
 			LLDrawable* drawable = *i;
-			for (S32 j = 0; j < drawable->getNumFaces(); j++)
-			{
-				LLFace* facep = drawable->getFace(j);
-				facep->mVertexBuffer = NULL;
-				facep->mLastVertexBuffer = NULL;
-			}
-
 			if (drawable->getVObj() && !group->mSpatialPartition->mRenderByGroup)
 			{
 				gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE);
@@ -1458,6 +1480,7 @@ class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
 		}
 	}
 };
+
 void LLSpatialPartition::restoreGL()
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -1597,7 +1620,7 @@ void LLSpatialPartition::processGeometry(LLCamera* camera)
 	U32 process_count = 8;
 
 	LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
-	if (!root->isState(LLSpatialGroup::IN_GEOMETRY_QUEUE))
+	if (mUpdateQueue.empty())
 	{
 		root->setState(LLSpatialGroup::IN_GEOMETRY_QUEUE);
 		mUpdateQueue.push(root);
@@ -1628,18 +1651,19 @@ void LLSpatialPartition::processGeometry(LLCamera* camera)
 			}
 		}
 
-		if (!group->isDead() && 
-			!group->isVisible() && 
-			!group->isState(LLSpatialGroup::OBJECT_DIRTY) && 
-			group->mBufferUsage != GL_STREAM_DRAW_ARB)
+		if (!group->isDead() && !group->isVisible())
 		{
-			group->updateDistance(*camera);
-			for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+			if (!group->isState(LLSpatialGroup::OBJECT_DIRTY) && 
+				group->mBufferUsage != GL_STREAM_DRAW_ARB)
 			{
-				LLDrawable* drawablep = *i;
-				if (!drawablep->isDead())
+				group->updateDistance(*camera);
+				for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
 				{
-					drawablep->updateDistance(*camera);
+					LLDrawable* drawablep = *i;
+					if (!drawablep->isDead())
+					{
+						drawablep->updateDistance(*camera);
+					}
 				}
 			}
 		}
@@ -1703,7 +1727,7 @@ void LLSpatialPartition::processImagery(LLCamera* camera)
 			}
 
 			gPipeline.generateReflectionMap(gPipeline.mCubeBuffer, cube_cam, 128);
-			gPipeline.blurReflectionMap(gPipeline.mCubeBuffer, cube_map, 32);
+			gPipeline.blurReflectionMap(gPipeline.mCubeBuffer, cube_map, 64);
 			group->mReflectionMap = cube_map;
 			group->setState(LLSpatialGroup::GEOM_DIRTY);
 			gPipeline.markRebuild(group);
@@ -2821,11 +2845,19 @@ LLDrawable*	LLSpatialPartition::pickDrawable(const LLVector3& start, const LLVec
 LLDrawInfo::LLDrawInfo(U32 start, U32 end, U32 count, U32 offset, 
 					   LLViewerImage* texture, LLVertexBuffer* buffer,
 					   BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
-: mStart(start), mEnd(end), mCount(count), mOffset(offset), 
-  mTexture(texture), mVertexBuffer(buffer),
-  mFullbright(fullbright), mBump(bump),
-  mParticle(particle), mPartSize(part_size),
-  mVSize(0.f), mTextureMatrix(NULL)
+:
+	mVertexBuffer(buffer),
+	mTexture(texture),
+	mTextureMatrix(NULL),
+	mStart(start),
+	mEnd(end),
+	mCount(count),
+	mOffset(offset), 
+	mFullbright(fullbright),
+	mBump(bump),
+	mParticle(particle),
+	mPartSize(part_size),
+	mVSize(0.f)
 {
 }
 
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index ea0802985e3..6a795d4c6ca 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -173,6 +173,7 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	BOOL boundObjects(BOOL empty, LLVector3& newMin, LLVector3& newMax);
 	void unbound();
 	BOOL rebound();
+	void destroyGL();
 	
 	void updateDistance(LLCamera& camera);
 	BOOL changeLOD();
@@ -273,6 +274,8 @@ class LLSpatialPartition: public LLGeometryManager
 	BOOL isVolatile() const { return mVolatile; }
 
 	virtual LLSpatialBridge* asBridge() { return NULL; }
+	virtual BOOL isBridge() { return asBridge() != NULL; }
+
 	S32 getObjects(const LLVector3& pos,  F32 rad,  LLDrawable::drawable_set_t &results );
 	S32 getLights(const LLVector3& pos,  F32 rad,  LLDrawable::drawable_set_t &results );
 	
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 13efadf2139..cb846a43fe6 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -1,1365 +1,1365 @@
-/** 
- * @file texturecache.cpp
- * @brief Object which handles local texture caching
- *
- * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "lltexturecache.h"
-
-#include "llapr.h"
-#include "lldir.h"
-#include "llimage.h"
-#include "lllfsthread.h"
-#include "llviewercontrol.h"
-
-#define USE_LFS_READ 0
-#define USE_LFS_WRITE 0
-
-// Note: first 4 bytes store file size, rest is j2c data
-const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024;
-
-class LLTextureCacheWorker : public LLWorkerClass
-{
-	friend class LLTextureCache;
-
-private:
-	enum e_state
-	{
-		INIT = 0,
-		LOCAL = 1,
-		CACHE = 2,
-		HEADER = 3,
-		BODY = 4
-	};
-
-	class ReadResponder : public LLLFSThread::Responder
-	{
-	public:
-		ReadResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
-		~ReadResponder() {}
-		void completed(S32 bytes)
-		{
-			mCache->lockWorkers();
-			LLTextureCacheWorker* reader = mCache->getReader(mHandle);
-			if (reader) reader->ioComplete(bytes);
-			mCache->unlockWorkers();
-		}
-		LLTextureCache* mCache;
-		LLTextureCacheWorker::handle_t mHandle;
-	};
-
-	class WriteResponder : public LLLFSThread::Responder
-	{
-	public:
-		WriteResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
-		~WriteResponder() {}
-		void completed(S32 bytes)
-		{
-			mCache->lockWorkers();
-			LLTextureCacheWorker* writer = mCache->getWriter(mHandle);
-			if (writer) writer->ioComplete(bytes);
-			mCache->unlockWorkers();
-		}
-		LLTextureCache* mCache;
-		LLTextureCacheWorker::handle_t mHandle;
-	};
-	
-public:
-	LLTextureCacheWorker(LLTextureCache* cache, U32 priority, const LLUUID& id,
-						 U8* data, S32 datasize, S32 offset,
-						 S32 imagesize, // for writes
-						 LLTextureCache::Responder* responder)
-		: LLWorkerClass(cache, "LLTextureCacheWorker"),
-		  mCache(cache),
-		  mPriority(priority),
-		  mID(id),
-		  mState(INIT),
-		  mReadData(NULL),
-		  mWriteData(data),
-		  mDataSize(datasize),
-		  mOffset(offset),
-		  mImageSize(imagesize),
-		  mImageFormat(IMG_CODEC_J2C),
-		  mImageLocal(FALSE),
-		  mResponder(responder),
-		  mFileHandle(LLLFSThread::nullHandle()),
-		  mBytesToRead(0),
-		  mBytesRead(0)
-	{
-		mPriority &= LLWorkerThread::PRIORITY_LOWBITS;
-	}
-	~LLTextureCacheWorker()
-	{
-		llassert_always(!haveWork());
-		delete[] mReadData;
-	}
-
-	bool doRead();
-	bool doWrite();
-	virtual bool doWork(S32 param); // Called from LLWorkerThread::processRequest()
-
-	handle_t read() { addWork(0, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
-	handle_t write() { addWork(1, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
-	bool complete() { return checkWork(); }
-	void ioComplete(S32 bytes)
-	{
-		mBytesRead = bytes;
-		setPriority(LLWorkerThread::PRIORITY_HIGH | mPriority);
-	}
-	
-private:
-	virtual void startWork(S32 param); // called from addWork() (MAIN THREAD)
-	virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
-	virtual void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
-
-private:
-	LLTextureCache* mCache;
-	U32 mPriority;
-	LLUUID mID;
-	e_state mState;
-	
-	U8* mReadData;
-	U8* mWriteData;
-	S32 mDataSize;
-	S32 mOffset;
-	S32 mImageSize;
-	S32 mImageFormat;
-	BOOL mImageLocal;
-	LLPointer<LLTextureCache::Responder> mResponder;
-	LLLFSThread::handle_t mFileHandle;
-	S32 mBytesToRead;
-	LLAtomicS32 mBytesRead;
-};
-
-//virtual
-void LLTextureCacheWorker::startWork(S32 param)
-{
-}
-
-bool LLTextureCacheWorker::doRead()
-{
-	S32 local_size = 0;
-	std::string local_filename;
-	
-	if (mState == INIT)
-	{
-		std::string filename = mCache->getLocalFileName(mID);
-		local_filename = filename + ".j2c";
-		local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
-		if (local_size == 0)
-		{
-			local_filename = filename + ".tga";
-			local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
-			if (local_size > 0)
-			{
-				mImageFormat = IMG_CODEC_TGA;
-				mDataSize = local_size; // Only a complete .tga file is valid
-			}
-		}
-		if (local_size > 0)
-		{
-			mState = LOCAL;
-		}
-		else
-		{
-			mState = CACHE;
-		}
-	}
-
-	if (mState == LOCAL)
-	{
-#if USE_LFS_READ
-		if (mFileHandle == LLLFSThread::nullHandle())
-		{
-			mImageLocal = TRUE;
-			mImageSize = local_size;
-			if (!mDataSize || mDataSize + mOffset > local_size)
-			{
-				mDataSize = local_size - mOffset;
-			}
-			if (mDataSize <= 0)
-			{
-				// no more data to read
-				mDataSize = 0;
-				return true;
-			}
-			mReadData = new U8[mDataSize];
-			mBytesRead = -1;
-			mBytesToRead = mDataSize;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-			mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
-													new ReadResponder(mCache, mRequestHandle));
-			return false;
-		}
-		else
-		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-					llwarns << "Error reading file from local cache: " << local_filename
-							<< " Bytes: " << mDataSize << " Offset: " << mOffset
-							<< " / " << mDataSize << llendl;
-					mDataSize = 0; // failed
-					delete[] mReadData;
-					mReadData = NULL;
-				}
-				return true;
-			}
-			else
-			{
-				return false;
-			}
-		}
-#else
-		if (!mDataSize || mDataSize > local_size)
-		{
-			mDataSize = local_size;
-		}
-		mReadData = new U8[mDataSize];
-		S32 bytes_read = ll_apr_file_read_ex(local_filename, mCache->getFileAPRPool(),
-											 mReadData, mOffset, mDataSize);
-		if (bytes_read != mDataSize)
-		{
-			llwarns << "Error reading file from local cache: " << local_filename
-					<< " Bytes: " << mDataSize << " Offset: " << mOffset
-					<< " / " << mDataSize << llendl;
-			mDataSize = 0;
-			delete[] mReadData;
-			mReadData = NULL;
-		}
-		else
-		{
-			mImageSize = local_size;
-			mImageLocal = TRUE;
-		}
-		return true;
-#endif
-	}
-
-	S32 idx = -1;
-	
-	if (mState == CACHE)
-	{
-		llassert_always(mImageSize == 0);
-		idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize);
-		if (idx >= 0 && mImageSize > mOffset)
-		{
-			llassert_always(mImageSize > 0);
-			if (!mDataSize || mDataSize > mImageSize)
-			{
-				mDataSize = mImageSize;
-			}
-			mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
-		}
-		else
-		{
-			mDataSize = 0; // no data
-			return true;
-		}
-	}
-
-	if (mState == HEADER)
-	{
-#if USE_LFS_READ
-		if (mFileHandle == LLLFSThread::nullHandle())
-		{
-			llassert_always(idx >= 0);
-			llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
-			S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
-			S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-			llassert_always(mReadData == NULL);
-			mReadData = new U8[size];
-			mBytesRead = -1;
-			mBytesToRead = size;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-			mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName,
-													mReadData, offset, mBytesToRead,
-													new ReadResponder(mCache, mRequestHandle));
-			return false;
-		}
-		else
-		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-					llwarns << "LLTextureCacheWorker: "  << mID
-							<< " incorrect number of bytes read from header: " << mBytesRead
-							<< " != " << mBytesToRead << llendl;
-					mDataSize = -1; // failed
-					return true;
-				}
-				if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
-				{
-					return true; // done
-				}
-				else
-				{
-					mFileHandle = LLLFSThread::nullHandle();
-					mState = BODY;
-				}
-			}
-			else
-			{
-				return false;
-			}
-		}
-#else
-		llassert_always(idx >= 0);
-		llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
-		S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
-		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-		mReadData = new U8[size];
-		S32 bytes_read = ll_apr_file_read_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
-											 mReadData, offset, size);
-		if (bytes_read != size)
-		{
-			llwarns << "LLTextureCacheWorker: "  << mID
-					<< " incorrect number of bytes read from header: " << bytes_read
-					<< " / " << size << llendl;
-			mDataSize = -1; // failed
-			return true;
-		}
-		if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
-		{
-			return true; // done
-		}
-		else
-		{
-			mState = BODY;
-		}
-#endif
-	}
-
-	if (mState == BODY)
-	{
-#if USE_LFS_READ
-		if (mFileHandle == LLLFSThread::nullHandle())
-		{
-			std::string filename = mCache->getTextureFileName(mID);
-			S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
-			if (filesize > mOffset)
-			{
-				S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
-				mDataSize = llmin(datasize, mDataSize);
-				S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-				data_offset = llmax(data_offset, 0);
-				S32 file_size = mDataSize - data_offset;
-				S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
-				file_offset = llmax(file_offset, 0);
-
-				llassert_always(mDataSize > 0);
-				U8* data = new U8[mDataSize];
-				if (data_offset > 0)
-				{
-					llassert_always(mReadData);
-					llassert_always(data_offset <= mDataSize);
-					memcpy(data, mReadData, data_offset);
-					delete[] mReadData;
-					mReadData = NULL;
-				}
-				llassert_always(mReadData == NULL);
-				mReadData = data;
-
-				mBytesRead = -1;
-				mBytesToRead = file_size;
-				setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-				llassert_always(data_offset + mBytesToRead <= mDataSize);
-				mFileHandle = LLLFSThread::sLocal->read(filename,
-														mReadData + data_offset, file_offset, mBytesToRead,
-														new ReadResponder(mCache, mRequestHandle));
-				return false;
-			}
-			else
-			{
-				mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
-				return true; // done
-			}
-		}
-		else
-		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-					llwarns << "LLTextureCacheWorker: "  << mID
-							<< " incorrect number of bytes read from body: " << mBytesRead
-							<< " != " << mBytesToRead << llendl;
-					mDataSize = -1; // failed
-				}
-				return true;
-			}
-			else
-			{
-				return false;
-			}
-		}
-#else
-		std::string filename = mCache->getTextureFileName(mID);
-		S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
-		S32 bytes_read = 0;
-		if (filesize > mOffset)
-		{
-			S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
-			mDataSize = llmin(datasize, mDataSize);
-			S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-			data_offset = llmax(data_offset, 0);
-			S32 file_size = mDataSize - data_offset;
-			S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
-			file_offset = llmax(file_offset, 0);
-			
-			U8* data = new U8[mDataSize];
-			if (data_offset > 0)
-			{
-				llassert_always(mReadData);
-				memcpy(data, mReadData, data_offset);
-				delete[] mReadData;
-			}
-			mReadData = data;
-			bytes_read = ll_apr_file_read_ex(filename, mCache->getFileAPRPool(),
-											 mReadData + data_offset,
-											 file_offset, file_size);
-			if (bytes_read != file_size)
-			{
-				llwarns << "LLTextureCacheWorker: "  << mID
-						<< " incorrect number of bytes read from body: " << bytes_read
-						<< " / " << file_size << llendl;
-				mDataSize = -1; // failed
-				return true;
-			}
-		}
-		else
-		{
-			mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
-		}
-		
-		return true;
-#endif
-	}
-	
-	return false;
-}
-
-bool LLTextureCacheWorker::doWrite()
-{
-	S32 idx = -1;
-
-	if (mState == INIT)
-	{
-		llassert_always(mOffset == 0); // Currently don't support offsets
-		mState = CACHE;
-	}
-
-	// No LOCAL state for write()
-	
-	if (mState == CACHE)
-	{
-		S32 cur_imagesize = 0;
-		S32 offset = mOffset;
-		idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize);
-		if (idx >= 0 && cur_imagesize > 0)
-		{
-			offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header
-		}
-		idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry
-		if (idx >= 0)
-		{
-			llassert_always(cur_imagesize <= 0 || mImageSize == cur_imagesize);
-			mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
-		}
-		else
-		{
-			mDataSize = -1; // failed
-			return true;
-		}
-	}
-	
-	if (mState == HEADER)
-	{
-#if USE_LFS_WRITE
-		if (mFileHandle == LLLFSThread::nullHandle())
-		{
-			llassert_always(idx >= 0);
-			llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
-			S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
-			S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-			mBytesRead = -1;
-			mBytesToRead = size;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-			mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName,
-													 mWriteData, offset, mBytesToRead,
-													 new WriteResponder(mCache, mRequestHandle));
-			return false;
-		}
-		else
-		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-					llwarns << "LLTextureCacheWorker: "  << mID
-							<< " incorrect number of bytes written to header: " << mBytesRead
-							<< " != " << mBytesToRead << llendl;
-					mDataSize = -1; // failed
-					return true;
-				}
-				if (mDataSize <=  mBytesToRead)
-				{
-					return true; // done
-				}
-				else
-				{
-					mFileHandle = LLLFSThread::nullHandle();
-					mState = BODY;
-				}
-			}
-			else
-			{
-				return false;
-			}
-		}
-#else
-		llassert_always(idx >= 0);
-		llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
-		S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
-		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-		S32 bytes_written = ll_apr_file_write_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
-												 mWriteData, offset, size);
-
-		if (bytes_written <= 0)
-		{
-			llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl;
-			mDataSize = -1; // failed
-			return true;
-		}
-
-		if (mDataSize <= size)
-		{
-			return true; // done
-		}
-		else
-		{
-			mState = BODY;
-		}
-#endif
-	}
-	
-	if (mState == BODY)
-	{
-#if USE_LFS_WRITE
-		if (mFileHandle == LLLFSThread::nullHandle())
-		{
-			S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-			data_offset = llmax(data_offset, 0);
-			S32 file_size = mDataSize - data_offset;
-			S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
-			file_offset = llmax(file_offset, 0);
-			if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
-			{
-				std::string filename = mCache->getTextureFileName(mID);
-				mBytesRead = -1;
-				mBytesToRead = file_size;
-				setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-				mFileHandle = LLLFSThread::sLocal->write(filename,
-														 mWriteData + data_offset, file_offset, mBytesToRead,
-														 new WriteResponder(mCache, mRequestHandle));
-				return false;
-			}
-			else
-			{
-				mDataSize = 0; // no data written
-				return true; // done
-			}
-		}
-		else
-		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-					llwarns << "LLTextureCacheWorker: "  << mID
-							<< " incorrect number of bytes written to body: " << mBytesRead
-							<< " != " << mBytesToRead << llendl;
-					mDataSize = -1; // failed
-				}
-				return true;
-			}
-			else
-			{
-				return false;
-			}
-		}
-#else
-		S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-		data_offset = llmax(data_offset, 0);
-		S32 file_size = mDataSize - data_offset;
-		S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
-		file_offset = llmax(file_offset, 0);
-		S32 bytes_written = 0;
-		if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
-		{
-			std::string filename = mCache->getTextureFileName(mID);
-			bytes_written = ll_apr_file_write_ex(filename, mCache->getFileAPRPool(),
-												 mWriteData + data_offset,
-												 file_offset, file_size);
-			if (bytes_written <= 0)
-			{
-				mDataSize = -1; // failed
-			}
-		}
-		else
-		{
-			mDataSize = 0; // no data written
-		}
-
-		return true;
-#endif
-	}
-	
-	return false;
-}
-
-//virtual
-bool LLTextureCacheWorker::doWork(S32 param)
-{
-	bool res = false;
-	if (param == 0) // read
-	{
-		res = doRead();
-	}
-	else if (param == 1) // write
-	{
-		res = doWrite();
-	}
-	else
-	{
-		llassert_always(0);
-	}
-	return res;
-}
-
-//virtual (WORKER THREAD)
-void LLTextureCacheWorker::finishWork(S32 param, bool completed)
-{
-	if (mResponder.notNull())
-	{
-		bool success = (completed && mDataSize > 0);
-		if (param == 0)
-		{
-			// read
-			if (success)
-			{
-				mResponder->setData(mReadData, mDataSize, mImageSize, mImageFormat, mImageLocal);
-				mReadData = NULL; // responder owns data
-				mDataSize = 0;
-			}
-			else
-			{
-				delete[] mReadData;
-				mReadData = NULL;
-				
-			}
-		}
-		else
-		{
-			// write
-			mWriteData = NULL; // we never owned data
-			mDataSize = 0;
-		}
-		mResponder->completed(success);
-	}
-}
-
-//virtual (MAIN THREAD)
-void LLTextureCacheWorker::endWork(S32 param, bool aborted)
-{
-	if (aborted)
-	{
-		// Let the destructor handle any cleanup
-		return;
-	}
-	switch(param)
-	{
-	  default:
-	  case 0: // read
-	  case 1: // write
-	  {
-		  if (mDataSize < 0)
-		  {
-			  // failed
-			  mCache->removeFromCache(mID);
-		  }
-		  break;
-	  }
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-LLTextureCache::LLTextureCache(bool threaded)
-	: LLWorkerThread("TextureCache", threaded),
-	  mWorkersMutex(getAPRPool()),
-	  mHeaderMutex(getAPRPool()),
-	  mFileAPRPool(NULL),
-	  mReadOnly(FALSE),
-	  mTexturesSizeTotal(0),
-	  mDoPurge(FALSE)
-{
-	apr_pool_create(&mFileAPRPool, NULL);
-}
-
-LLTextureCache::~LLTextureCache()
-{
-	apr_pool_destroy(mFileAPRPool);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-//virtual
-S32 LLTextureCache::update(U32 max_time_ms)
-{
-	S32 res;
-	res = LLWorkerThread::update(max_time_ms);
-
-	lockWorkers();
-	for (std::vector<handle_t>::iterator iter1 = mPrioritizeWriteList.begin();
-		 iter1 != mPrioritizeWriteList.end(); ++iter1)
-	{
-		handle_t handle = *iter1;
-		handle_map_t::iterator iter2 = mWriters.find(handle);
-		if(iter2 != mWriters.end())
-		{
-			LLTextureCacheWorker* worker = iter2->second;
-			worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority);
-		}
-	}
-	mPrioritizeWriteList.clear();
-	unlockWorkers();
-	return res;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-std::string LLTextureCache::getLocalFileName(const LLUUID& id)
-{
-	// Does not include extension
-	std::string idstr = id.asString();
-	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", idstr);
-	return filename;
-}
-
-std::string LLTextureCache::getTextureFileName(const LLUUID& id)
-{
-	std::string idstr = id.asString();
-	std::string delem = gDirUtilp->getDirDelimiter();
-	std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr;
-	return filename;
-}
-
-bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
-{
-	bool res = false;
-	bool purge = false;
-	// Append UUID to end of texture entries
-	{
-		LLMutexLock lock(&mHeaderMutex);
-		size_map_t::iterator iter = mTexturesSizeMap.find(id);
-		if (iter == mTexturesSizeMap.end() || iter->second < bodysize)
-		{
-			llassert_always(bodysize > 0);
-			Entry* entry = new Entry(id, bodysize, time(NULL));
-			ll_apr_file_write_ex(mTexturesDirEntriesFileName, getFileAPRPool(),
-								 (U8*)entry, -1, 1*sizeof(Entry));
-			delete entry;
-			if (iter != mTexturesSizeMap.end())
-			{
-				mTexturesSizeTotal -= iter->second;
-			}
-			mTexturesSizeTotal += bodysize;
-			mTexturesSizeMap[id] = bodysize;
-			if (mTexturesSizeTotal > sCacheMaxTexturesSize)
-			{
-				purge = true;
-			}
-			res = true;
-		}
-	}
-	if (purge)
-	{
-		mDoPurge = TRUE;
-	}
-	return res;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-//static
-const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB
-F32 LLTextureCache::sHeaderCacheVersion = 1.0f;
-U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
-S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
-const char* entries_filename = "texture.entries";
-const char* cache_filename = "texture.cache";
-const char* textures_dirname = "textures";
-
-void LLTextureCache::setDirNames(ELLPath location)
-{
-	std::string delem = gDirUtilp->getDirDelimiter();
-	mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
-	mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
-	mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
-	mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
-}
-
-void LLTextureCache::purgeCache(ELLPath location)
-{
-	if (!mReadOnly)
-	{
-		setDirNames(location);
-	
-		ll_apr_file_remove(mHeaderEntriesFileName, NULL);
-		ll_apr_file_remove(mHeaderDataFileName, NULL);
-	}
-	purgeAllTextures(true);
-}
-
-S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
-{
-	mReadOnly = read_only;
-	
-	S64 header_size = (max_size * 2) / 10;
-	S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE;
-	sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries));
-	header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE;
-	max_size -= header_size;
-	if (sCacheMaxTexturesSize > 0)
-		sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size);
-	else
-		sCacheMaxTexturesSize = max_size;
-	max_size -= sCacheMaxTexturesSize;
-	
-	llinfos << "TEXTURE CACHE: Headers: " << sCacheMaxEntries
-			<< " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << llendl;
-
-	setDirNames(location);
-	
-	if (!mReadOnly)
-	{
-		LLFile::mkdir(mTexturesDirName.c_str());
-		const char* subdirs = "0123456789abcdef";
-		for (S32 i=0; i<16; i++)
-		{
-			std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i];
-			LLFile::mkdir(dirname.c_str());
-		}
-	}
-	readHeaderCache();
-	purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it
-
-	return max_size; // unused cache space
-}
-
-struct lru_data
-{
-	lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; }
-	U32 time;
-	S32 index;
-	LLUUID uuid;
-	struct Compare
-	{
-		// lhs < rhs
-		typedef const lru_data* lru_data_ptr;
-		bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const
-		{
-			if (!(a->time < b->time))
-				return true;
-			else if (!(b->time < a->time))
-				return false;
-			else
-				return a->index < b->index;
-		}
-	};				
-};
-
-// Called from either the main thread or the worker thread
-void LLTextureCache::readHeaderCache(apr_pool_t* poolp)
-{
-	LLMutexLock lock(&mHeaderMutex);
-	mHeaderEntriesInfo.mVersion = 0.f;
-	mHeaderEntriesInfo.mEntries = 0;
-	if (ll_apr_file_exists(mHeaderEntriesFileName, poolp))
-	{
-		ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
-							(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
-	}
-	if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
-	{
-		if (!mReadOnly)
-		{
-			// Info with 0 entries
-			mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
-			ll_apr_file_write_ex(mHeaderEntriesFileName, poolp,
-								 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
-		}
-	}
-	else
-	{
-		S32 num_entries = mHeaderEntriesInfo.mEntries;
-		if (num_entries)
-		{
-			Entry* entries = new Entry[num_entries];
-			ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
-								(U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry));
-			typedef std::set<lru_data*, lru_data::Compare> lru_set_t;
-			lru_set_t lru;
-			for (S32 i=0; i<num_entries; i++)
-			{
-				if (entries[i].mSize >= 0) // -1 indicates erased entry, skip
-				{
-					const LLUUID& id = entries[i].mID;
-					lru.insert(new lru_data(entries[i].mTime, i, id));
-					mHeaderIDMap[id] = i;
-				}
-			}
-			mLRU.clear();
-			S32 lru_entries = sCacheMaxEntries / 10;
-			for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter)
-			{
-				lru_data* data = *iter;
-				mLRU[data->index] = data->uuid;
-				if (--lru_entries <= 0)
-					break;
-			}
-			for_each(lru.begin(), lru.end(), DeletePointer());
-			delete[] entries;
-		}
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-void LLTextureCache::purgeAllTextures(bool purge_directories)
-{
-	if (!mReadOnly)
-	{
-		const char* subdirs = "0123456789abcdef";
-		std::string delem = gDirUtilp->getDirDelimiter();
-		std::string mask = delem + "*";
-		for (S32 i=0; i<16; i++)
-		{
-			std::string dirname = mTexturesDirName + delem + subdirs[i];
-			gDirUtilp->deleteFilesInDir(dirname.c_str(),mask);
-			if (purge_directories)
-			{
-				LLFile::rmdir(dirname.c_str());
-			}
-		}
-		ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
-		if (purge_directories)
-		{
-			LLFile::rmdir(mTexturesDirName.c_str());
-		}
-	}
-	mTexturesSizeMap.clear();
-}
-
-void LLTextureCache::purgeTextures(bool validate)
-{
-	if (mReadOnly)
-	{
-		return;
-	}
-
-	LLMutexLock lock(&mHeaderMutex);
-	
-	S32 filesize = ll_apr_file_size(mTexturesDirEntriesFileName, NULL);
-	S32 num_entries = filesize / sizeof(Entry);
-	if (num_entries * sizeof(Entry) != filesize)
-	{
-		llwarns << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << llendl;
-		purgeAllTextures(false);
-		return;
-	}
-	if (num_entries == 0)
-	{
-		return; // nothing to do
-	}
-	
-	Entry* entries = new Entry[num_entries];
-	S32 bytes_read = ll_apr_file_read_ex(mTexturesDirEntriesFileName, NULL,
-										 (U8*)entries, 0, num_entries*sizeof(Entry));
-	if (bytes_read != filesize)
-	{
-		llwarns << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << llendl;
-		purgeAllTextures(false);
-		return;
-	}
-	
-	llinfos << "TEXTURE CACHE: Reading Entries..." << llendl;
-	
-	std::map<LLUUID, S32> entry_idx_map;
-	S64 total_size = 0;
-	for (S32 idx=0; idx<num_entries; idx++)
-	{
-		const LLUUID& id = entries[idx].mID;
-// 		llinfos << "Entry: " << id << " Size: " << entries[i].mSize << " Time: " << entries[i].mTime << llendl;
-		std::map<LLUUID, S32>::iterator iter = entry_idx_map.find(id);
-		if (iter != entry_idx_map.end())
-		{
-			// Newer entry replacing older entry
-			S32 pidx = iter->second;
-			total_size -= entries[pidx].mSize;
-			entries[pidx].mSize = 0; // flag: skip older entry
-		}
-		entry_idx_map[id] = idx;
-		total_size += entries[idx].mSize;
-	}
-
-	U32 validate_idx = 0;
-	if (validate)
-	{
-		validate_idx = gSavedSettings.getU32("CacheValidateCounter");
-		U32 next_idx = (++validate_idx) % 256;
-		gSavedSettings.setU32("CacheValidateCounter", next_idx);
-		llinfos << "TEXTURE CACHE: Validating: " << validate_idx << llendl;
-	}
-	
-	S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10;
-	S32 purge_count = 0;
-	S32 next_idx = 0;
-	for (S32 idx=0; idx<num_entries; idx++)
-	{
-		if (entries[idx].mSize == 0)
-		{
-			continue;
-		}
-		bool purge_entry = false;
-		std::string filename = getTextureFileName(entries[idx].mID);
-		if (total_size >= min_cache_size)
-		{
-			purge_entry = true;
-		}
-		else if (validate)
-		{
-			// make sure file exists and is the correct size
-			S32 uuididx = entries[idx].mID.mData[0];
-			if (uuididx == validate_idx)
-			{
-// 				llinfos << "Validating: " << filename << "Size: " << entries[idx].mSize << llendl;
-				S32 bodysize = ll_apr_file_size(filename, NULL);
-				if (bodysize != entries[idx].mSize)
-				{
-					llwarns << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize
-							<< filename << llendl;
-					purge_entry = true;
-				}
-			}
-		}
-		if (purge_entry)
-		{
-			purge_count++;
-//	 		llinfos << "PURGING: " << filename << llendl;
-			ll_apr_file_remove(filename, NULL);
-			total_size -= entries[idx].mSize;
-			entries[idx].mSize = 0;
-		}
-		else
-		{
-			if (next_idx != idx)
-			{
-				entries[next_idx] = entries[idx];
-			}
-			++next_idx;
-		}
-	}
-	num_entries = next_idx;
-
-	llinfos << "TEXTURE CACHE: Writing Entries: " << num_entries << llendl;
-	
-	ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
-	ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL,
-						 (U8*)&entries[0], 0, num_entries*sizeof(Entry));
-	
-	mTexturesSizeTotal = 0;
-	mTexturesSizeMap.clear();
-	for (S32 idx=0; idx<num_entries; idx++)
-	{
-		mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
-		mTexturesSizeTotal += entries[idx].mSize;
-	}
-	llassert(mTexturesSizeTotal == total_size);
-	
-	delete[] entries;
-	
-	llinfos << "TEXTURE CACHE:"
-			<< " PURGED: " << purge_count
-			<< " ENTRIES: " << num_entries
-			<< " CACHE SIZE: " << total_size / 1024*1024 << " MB"
-			<< llendl;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-// call lockWorkers() first!
-LLTextureCacheWorker* LLTextureCache::getReader(handle_t handle)
-{
-	LLTextureCacheWorker* res = NULL;
-	handle_map_t::iterator iter = mReaders.find(handle);
-	if (iter != mReaders.end())
-	{
-		res = iter->second;
-	}
-	return res;
-}
-
-LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
-{
-	LLTextureCacheWorker* res = NULL;
-	handle_map_t::iterator iter = mWriters.find(handle);
-	if (iter != mWriters.end())
-	{
-		res = iter->second;
-	}
-	return res;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-// Called from work thread
-S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize)
-{
-	bool retry = false;
-	S32 idx = -1;
-
-	{
-		LLMutexLock lock(&mHeaderMutex);
-		id_map_t::iterator iter = mHeaderIDMap.find(id);
-		if (iter != mHeaderIDMap.end())
-		{
-			idx = iter->second;
-		}
-		else if (touch && !mReadOnly)
-		{
-			if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
-			{
-				// Add an entry
-				idx = mHeaderEntriesInfo.mEntries++;
-				mHeaderIDMap[id] = idx;
-				// Update Info
-				ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
-									(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
-			}
-			else if (!mLRU.empty())
-			{
-				idx = mLRU.begin()->first; // will be erased below
-				const LLUUID& oldid = mLRU.begin()->second;
-				mHeaderIDMap.erase(oldid);
-				mTexturesSizeMap.erase(oldid);
-				mHeaderIDMap[id] = idx;
-			}
-			else
-			{
-				idx = -1;
-				retry = true;
-			}
-		}
-		if (idx >= 0)
-		{
-			if (touch && !mReadOnly)
-			{
-				// Update the lru entry
-				mLRU.erase(idx);
-				llassert_always(imagesize && *imagesize > 0);
-				Entry* entry = new Entry(id, *imagesize, time(NULL));
-				S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
-				ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
-									 (U8*)entry, offset, sizeof(Entry));
-				delete entry;
-			}
-			else if (imagesize)
-			{
-				// Get the image size
-				Entry entry;
-				S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
-				ll_apr_file_read_ex(mHeaderEntriesFileName, getFileAPRPool(),
-									(U8*)&entry, offset, sizeof(Entry));
-				*imagesize = entry.mSize;
-			}
-		}
-	}
-	if (retry)
-	{
-		readHeaderCache(getFileAPRPool()); // updates the lru
-		llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
-		idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion
-	}
-	return idx;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-// Calls from texture pipeline thread (i.e. LLTextureFetch)
-
-LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 priority,
-													   S32 offset, S32 size, ReadResponder* responder)
-{
-	// Note: checking to see if an entry exists can cause a stall,
-	//  so let the thread handle it
-	LLMutexLock lock(&mWorkersMutex);
-	LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id,
-															NULL, size, offset, 0,
-															responder);
-	handle_t handle = worker->read();
-	mReaders[handle] = worker;
-	return handle;
-}
-
-bool LLTextureCache::readComplete(handle_t handle, bool abort)
-{
-	lockWorkers();
-	handle_map_t::iterator iter = mReaders.find(handle);
-	llassert_always(iter != mReaders.end());
-	LLTextureCacheWorker* worker = iter->second;
-	bool res = worker->complete();
-	if (res || abort)
-	{
-		mReaders.erase(handle);
-		unlockWorkers();
-		worker->scheduleDelete();
-		return true;
-	}
-	else
-	{
-		unlockWorkers();
-		return false;
-	}
-}
-
-LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority,
-													  U8* data, S32 datasize, S32 imagesize,
-													  WriteResponder* responder)
-{
-	if (mReadOnly)
-	{
-		return LLWorkerThread::nullHandle();
-	}
-	if (mDoPurge)
-	{
-		// NOTE: This may cause an occasional hiccup,
-		//  but it really needs to be done on the control thread
-		//  (i.e. here)
-		purgeTextures(false);
-		mDoPurge = FALSE;
-	}
-	if (datasize >= TEXTURE_CACHE_ENTRY_SIZE)
-	{
-		LLMutexLock lock(&mWorkersMutex);
-		llassert_always(imagesize > 0);
-		LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id,
-																data, datasize, 0,
-																imagesize, responder);
-		handle_t handle = worker->write();
-		mWriters[handle] = worker;
-		return handle;
-	}
-	return LLWorkerThread::nullHandle();
-}
-
-bool LLTextureCache::writeComplete(handle_t handle, bool abort)
-{
-	lockWorkers();
-	handle_map_t::iterator iter = mWriters.find(handle);
-	llassert_always(iter != mWriters.end());
-	LLTextureCacheWorker* worker = iter->second;
-	if (worker->complete() || abort)
-	{
-		mWriters.erase(handle);
-		unlockWorkers();
-		worker->scheduleDelete();
-		return true;
-	}
-	else
-	{
-		unlockWorkers();
-		return false;
-	}
-}
-
-void LLTextureCache::prioritizeWrite(handle_t handle)
-{
-	// Don't prioritize yet, we might be working on this now
-	//   which could create a deadlock
-	mPrioritizeWriteList.push_back(handle);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-// Called from MAIN thread (endWork())
-
-bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
-{
-	if (mReadOnly)
-	{
-		return false;
-	}
-	LLMutexLock lock(&mHeaderMutex);
-	id_map_t::iterator iter = mHeaderIDMap.find(id);
-	if (iter != mHeaderIDMap.end())
-	{
-		S32 idx = iter->second;
-		if (idx >= 0)
-		{
-			Entry* entry = new Entry(id, -1, time(NULL));
-			S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
-			ll_apr_file_write_ex(mHeaderEntriesFileName, NULL,
-								 (U8*)entry, offset, sizeof(Entry));
-			delete entry;
-			mLRU[idx] = id;
-			mHeaderIDMap.erase(id);
-			mTexturesSizeMap.erase(id);
-			return true;
-		}
-	}
-	return false;
-}
-
-void LLTextureCache::removeFromCache(const LLUUID& id)
-{
-	llwarns << "Removing texture from cache: " << id << llendl;
-	if (!mReadOnly)
-	{
-		removeHeaderCacheEntry(id);
-		ll_apr_file_remove(getTextureFileName(id), NULL);
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-LLTextureCache::ReadResponder::ReadResponder()
-	: mImageSize(0),
-	  mImageLocal(FALSE)
-{
-}
-
-void LLTextureCache::ReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal)
-{
-	if (mFormattedImage.notNull())
-	{
-		llassert_always(mFormattedImage->getCodec() == imageformat);
-		mFormattedImage->appendData(data, datasize);
-	}
-	else
-	{
-		mFormattedImage = LLImageFormatted::createFromType(imageformat);
-		mFormattedImage->setData(data,datasize);
-	}
-	mImageSize = imagesize;
-	mImageLocal = imagelocal;
-}
-
-//////////////////////////////////////////////////////////////////////////////
+/** 
+ * @file texturecache.cpp
+ * @brief Object which handles local texture caching
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltexturecache.h"
+
+#include "llapr.h"
+#include "lldir.h"
+#include "llimage.h"
+#include "lllfsthread.h"
+#include "llviewercontrol.h"
+
+#define USE_LFS_READ 0
+#define USE_LFS_WRITE 0
+
+// Note: first 4 bytes store file size, rest is j2c data
+const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024;
+
+class LLTextureCacheWorker : public LLWorkerClass
+{
+	friend class LLTextureCache;
+
+private:
+	enum e_state
+	{
+		INIT = 0,
+		LOCAL = 1,
+		CACHE = 2,
+		HEADER = 3,
+		BODY = 4
+	};
+
+	class ReadResponder : public LLLFSThread::Responder
+	{
+	public:
+		ReadResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
+		~ReadResponder() {}
+		void completed(S32 bytes)
+		{
+			mCache->lockWorkers();
+			LLTextureCacheWorker* reader = mCache->getReader(mHandle);
+			if (reader) reader->ioComplete(bytes);
+			mCache->unlockWorkers();
+		}
+		LLTextureCache* mCache;
+		LLTextureCacheWorker::handle_t mHandle;
+	};
+
+	class WriteResponder : public LLLFSThread::Responder
+	{
+	public:
+		WriteResponder(LLTextureCache* cache, handle_t handle) : mCache(cache), mHandle(handle) {}
+		~WriteResponder() {}
+		void completed(S32 bytes)
+		{
+			mCache->lockWorkers();
+			LLTextureCacheWorker* writer = mCache->getWriter(mHandle);
+			if (writer) writer->ioComplete(bytes);
+			mCache->unlockWorkers();
+		}
+		LLTextureCache* mCache;
+		LLTextureCacheWorker::handle_t mHandle;
+	};
+	
+public:
+	LLTextureCacheWorker(LLTextureCache* cache, U32 priority, const LLUUID& id,
+						 U8* data, S32 datasize, S32 offset,
+						 S32 imagesize, // for writes
+						 LLTextureCache::Responder* responder)
+		: LLWorkerClass(cache, "LLTextureCacheWorker"),
+		  mCache(cache),
+		  mPriority(priority),
+		  mID(id),
+		  mState(INIT),
+		  mReadData(NULL),
+		  mWriteData(data),
+		  mDataSize(datasize),
+		  mOffset(offset),
+		  mImageSize(imagesize),
+		  mImageFormat(IMG_CODEC_J2C),
+		  mImageLocal(FALSE),
+		  mResponder(responder),
+		  mFileHandle(LLLFSThread::nullHandle()),
+		  mBytesToRead(0),
+		  mBytesRead(0)
+	{
+		mPriority &= LLWorkerThread::PRIORITY_LOWBITS;
+	}
+	~LLTextureCacheWorker()
+	{
+		llassert_always(!haveWork());
+		delete[] mReadData;
+	}
+
+	bool doRead();
+	bool doWrite();
+	virtual bool doWork(S32 param); // Called from LLWorkerThread::processRequest()
+
+	handle_t read() { addWork(0, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
+	handle_t write() { addWork(1, LLWorkerThread::PRIORITY_HIGH | mPriority); return mRequestHandle; }
+	bool complete() { return checkWork(); }
+	void ioComplete(S32 bytes)
+	{
+		mBytesRead = bytes;
+		setPriority(LLWorkerThread::PRIORITY_HIGH | mPriority);
+	}
+	
+private:
+	virtual void startWork(S32 param); // called from addWork() (MAIN THREAD)
+	virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
+	virtual void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
+
+private:
+	LLTextureCache* mCache;
+	U32 mPriority;
+	LLUUID mID;
+	e_state mState;
+	
+	U8* mReadData;
+	U8* mWriteData;
+	S32 mDataSize;
+	S32 mOffset;
+	S32 mImageSize;
+	S32 mImageFormat;
+	BOOL mImageLocal;
+	LLPointer<LLTextureCache::Responder> mResponder;
+	LLLFSThread::handle_t mFileHandle;
+	S32 mBytesToRead;
+	LLAtomicS32 mBytesRead;
+};
+
+//virtual
+void LLTextureCacheWorker::startWork(S32 param)
+{
+}
+
+bool LLTextureCacheWorker::doRead()
+{
+	S32 local_size = 0;
+	std::string local_filename;
+	
+	if (mState == INIT)
+	{
+		std::string filename = mCache->getLocalFileName(mID);
+		local_filename = filename + ".j2c";
+		local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
+		if (local_size == 0)
+		{
+			local_filename = filename + ".tga";
+			local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
+			if (local_size > 0)
+			{
+				mImageFormat = IMG_CODEC_TGA;
+				mDataSize = local_size; // Only a complete .tga file is valid
+			}
+		}
+		if (local_size > 0)
+		{
+			mState = LOCAL;
+		}
+		else
+		{
+			mState = CACHE;
+		}
+	}
+
+	if (mState == LOCAL)
+	{
+#if USE_LFS_READ
+		if (mFileHandle == LLLFSThread::nullHandle())
+		{
+			mImageLocal = TRUE;
+			mImageSize = local_size;
+			if (!mDataSize || mDataSize + mOffset > local_size)
+			{
+				mDataSize = local_size - mOffset;
+			}
+			if (mDataSize <= 0)
+			{
+				// no more data to read
+				mDataSize = 0;
+				return true;
+			}
+			mReadData = new U8[mDataSize];
+			mBytesRead = -1;
+			mBytesToRead = mDataSize;
+			setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+			mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
+													new ReadResponder(mCache, mRequestHandle));
+			return false;
+		}
+		else
+		{
+			if (mBytesRead >= 0)
+			{
+				if (mBytesRead != mBytesToRead)
+				{
+					llwarns << "Error reading file from local cache: " << local_filename
+							<< " Bytes: " << mDataSize << " Offset: " << mOffset
+							<< " / " << mDataSize << llendl;
+					mDataSize = 0; // failed
+					delete[] mReadData;
+					mReadData = NULL;
+				}
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+#else
+		if (!mDataSize || mDataSize > local_size)
+		{
+			mDataSize = local_size;
+		}
+		mReadData = new U8[mDataSize];
+		S32 bytes_read = ll_apr_file_read_ex(local_filename, mCache->getFileAPRPool(),
+											 mReadData, mOffset, mDataSize);
+		if (bytes_read != mDataSize)
+		{
+			llwarns << "Error reading file from local cache: " << local_filename
+					<< " Bytes: " << mDataSize << " Offset: " << mOffset
+					<< " / " << mDataSize << llendl;
+			mDataSize = 0;
+			delete[] mReadData;
+			mReadData = NULL;
+		}
+		else
+		{
+			mImageSize = local_size;
+			mImageLocal = TRUE;
+		}
+		return true;
+#endif
+	}
+
+	S32 idx = -1;
+	
+	if (mState == CACHE)
+	{
+		llassert_always(mImageSize == 0);
+		idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize);
+		if (idx >= 0 && mImageSize > mOffset)
+		{
+			llassert_always(mImageSize > 0);
+			if (!mDataSize || mDataSize > mImageSize)
+			{
+				mDataSize = mImageSize;
+			}
+			mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
+		}
+		else
+		{
+			mDataSize = 0; // no data
+			return true;
+		}
+	}
+
+	if (mState == HEADER)
+	{
+#if USE_LFS_READ
+		if (mFileHandle == LLLFSThread::nullHandle())
+		{
+			llassert_always(idx >= 0);
+			llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
+			S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+			S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+			llassert_always(mReadData == NULL);
+			mReadData = new U8[size];
+			mBytesRead = -1;
+			mBytesToRead = size;
+			setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+			mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName,
+													mReadData, offset, mBytesToRead,
+													new ReadResponder(mCache, mRequestHandle));
+			return false;
+		}
+		else
+		{
+			if (mBytesRead >= 0)
+			{
+				if (mBytesRead != mBytesToRead)
+				{
+					llwarns << "LLTextureCacheWorker: "  << mID
+							<< " incorrect number of bytes read from header: " << mBytesRead
+							<< " != " << mBytesToRead << llendl;
+					mDataSize = -1; // failed
+					return true;
+				}
+				if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
+				{
+					return true; // done
+				}
+				else
+				{
+					mFileHandle = LLLFSThread::nullHandle();
+					mState = BODY;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+#else
+		llassert_always(idx >= 0);
+		llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
+		S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+		mReadData = new U8[size];
+		S32 bytes_read = ll_apr_file_read_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
+											 mReadData, offset, size);
+		if (bytes_read != size)
+		{
+			llwarns << "LLTextureCacheWorker: "  << mID
+					<< " incorrect number of bytes read from header: " << bytes_read
+					<< " / " << size << llendl;
+			mDataSize = -1; // failed
+			return true;
+		}
+		if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
+		{
+			return true; // done
+		}
+		else
+		{
+			mState = BODY;
+		}
+#endif
+	}
+
+	if (mState == BODY)
+	{
+#if USE_LFS_READ
+		if (mFileHandle == LLLFSThread::nullHandle())
+		{
+			std::string filename = mCache->getTextureFileName(mID);
+			S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
+			if (filesize > mOffset)
+			{
+				S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
+				mDataSize = llmin(datasize, mDataSize);
+				S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+				data_offset = llmax(data_offset, 0);
+				S32 file_size = mDataSize - data_offset;
+				S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+				file_offset = llmax(file_offset, 0);
+
+				llassert_always(mDataSize > 0);
+				U8* data = new U8[mDataSize];
+				if (data_offset > 0)
+				{
+					llassert_always(mReadData);
+					llassert_always(data_offset <= mDataSize);
+					memcpy(data, mReadData, data_offset);
+					delete[] mReadData;
+					mReadData = NULL;
+				}
+				llassert_always(mReadData == NULL);
+				mReadData = data;
+
+				mBytesRead = -1;
+				mBytesToRead = file_size;
+				setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+				llassert_always(data_offset + mBytesToRead <= mDataSize);
+				mFileHandle = LLLFSThread::sLocal->read(filename,
+														mReadData + data_offset, file_offset, mBytesToRead,
+														new ReadResponder(mCache, mRequestHandle));
+				return false;
+			}
+			else
+			{
+				mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
+				return true; // done
+			}
+		}
+		else
+		{
+			if (mBytesRead >= 0)
+			{
+				if (mBytesRead != mBytesToRead)
+				{
+					llwarns << "LLTextureCacheWorker: "  << mID
+							<< " incorrect number of bytes read from body: " << mBytesRead
+							<< " != " << mBytesToRead << llendl;
+					mDataSize = -1; // failed
+				}
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+#else
+		std::string filename = mCache->getTextureFileName(mID);
+		S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
+		S32 bytes_read = 0;
+		if (filesize > mOffset)
+		{
+			S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
+			mDataSize = llmin(datasize, mDataSize);
+			S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+			data_offset = llmax(data_offset, 0);
+			S32 file_size = mDataSize - data_offset;
+			S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+			file_offset = llmax(file_offset, 0);
+			
+			U8* data = new U8[mDataSize];
+			if (data_offset > 0)
+			{
+				llassert_always(mReadData);
+				memcpy(data, mReadData, data_offset);
+				delete[] mReadData;
+			}
+			mReadData = data;
+			bytes_read = ll_apr_file_read_ex(filename, mCache->getFileAPRPool(),
+											 mReadData + data_offset,
+											 file_offset, file_size);
+			if (bytes_read != file_size)
+			{
+				llwarns << "LLTextureCacheWorker: "  << mID
+						<< " incorrect number of bytes read from body: " << bytes_read
+						<< " / " << file_size << llendl;
+				mDataSize = -1; // failed
+				return true;
+			}
+		}
+		else
+		{
+			mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
+		}
+		
+		return true;
+#endif
+	}
+	
+	return false;
+}
+
+bool LLTextureCacheWorker::doWrite()
+{
+	S32 idx = -1;
+
+	if (mState == INIT)
+	{
+		llassert_always(mOffset == 0); // Currently don't support offsets
+		mState = CACHE;
+	}
+
+	// No LOCAL state for write()
+	
+	if (mState == CACHE)
+	{
+		S32 cur_imagesize = 0;
+		S32 offset = mOffset;
+		idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize);
+		if (idx >= 0 && cur_imagesize > 0)
+		{
+			offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header
+		}
+		idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry
+		if (idx >= 0)
+		{
+			llassert_always(cur_imagesize <= 0 || mImageSize == cur_imagesize);
+			mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
+		}
+		else
+		{
+			mDataSize = -1; // failed
+			return true;
+		}
+	}
+	
+	if (mState == HEADER)
+	{
+#if USE_LFS_WRITE
+		if (mFileHandle == LLLFSThread::nullHandle())
+		{
+			llassert_always(idx >= 0);
+			llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
+			S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+			S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+			mBytesRead = -1;
+			mBytesToRead = size;
+			setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+			mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName,
+													 mWriteData, offset, mBytesToRead,
+													 new WriteResponder(mCache, mRequestHandle));
+			return false;
+		}
+		else
+		{
+			if (mBytesRead >= 0)
+			{
+				if (mBytesRead != mBytesToRead)
+				{
+					llwarns << "LLTextureCacheWorker: "  << mID
+							<< " incorrect number of bytes written to header: " << mBytesRead
+							<< " != " << mBytesToRead << llendl;
+					mDataSize = -1; // failed
+					return true;
+				}
+				if (mDataSize <=  mBytesToRead)
+				{
+					return true; // done
+				}
+				else
+				{
+					mFileHandle = LLLFSThread::nullHandle();
+					mState = BODY;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+#else
+		llassert_always(idx >= 0);
+		llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
+		S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+		S32 bytes_written = ll_apr_file_write_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
+												 mWriteData, offset, size);
+
+		if (bytes_written <= 0)
+		{
+			llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl;
+			mDataSize = -1; // failed
+			return true;
+		}
+
+		if (mDataSize <= size)
+		{
+			return true; // done
+		}
+		else
+		{
+			mState = BODY;
+		}
+#endif
+	}
+	
+	if (mState == BODY)
+	{
+#if USE_LFS_WRITE
+		if (mFileHandle == LLLFSThread::nullHandle())
+		{
+			S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+			data_offset = llmax(data_offset, 0);
+			S32 file_size = mDataSize - data_offset;
+			S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+			file_offset = llmax(file_offset, 0);
+			if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
+			{
+				std::string filename = mCache->getTextureFileName(mID);
+				mBytesRead = -1;
+				mBytesToRead = file_size;
+				setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
+				mFileHandle = LLLFSThread::sLocal->write(filename,
+														 mWriteData + data_offset, file_offset, mBytesToRead,
+														 new WriteResponder(mCache, mRequestHandle));
+				return false;
+			}
+			else
+			{
+				mDataSize = 0; // no data written
+				return true; // done
+			}
+		}
+		else
+		{
+			if (mBytesRead >= 0)
+			{
+				if (mBytesRead != mBytesToRead)
+				{
+					llwarns << "LLTextureCacheWorker: "  << mID
+							<< " incorrect number of bytes written to body: " << mBytesRead
+							<< " != " << mBytesToRead << llendl;
+					mDataSize = -1; // failed
+				}
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+#else
+		S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+		data_offset = llmax(data_offset, 0);
+		S32 file_size = mDataSize - data_offset;
+		S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+		file_offset = llmax(file_offset, 0);
+		S32 bytes_written = 0;
+		if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
+		{
+			std::string filename = mCache->getTextureFileName(mID);
+			bytes_written = ll_apr_file_write_ex(filename, mCache->getFileAPRPool(),
+												 mWriteData + data_offset,
+												 file_offset, file_size);
+			if (bytes_written <= 0)
+			{
+				mDataSize = -1; // failed
+			}
+		}
+		else
+		{
+			mDataSize = 0; // no data written
+		}
+
+		return true;
+#endif
+	}
+	
+	return false;
+}
+
+//virtual
+bool LLTextureCacheWorker::doWork(S32 param)
+{
+	bool res = false;
+	if (param == 0) // read
+	{
+		res = doRead();
+	}
+	else if (param == 1) // write
+	{
+		res = doWrite();
+	}
+	else
+	{
+		llassert_always(0);
+	}
+	return res;
+}
+
+//virtual (WORKER THREAD)
+void LLTextureCacheWorker::finishWork(S32 param, bool completed)
+{
+	if (mResponder.notNull())
+	{
+		bool success = (completed && mDataSize > 0);
+		if (param == 0)
+		{
+			// read
+			if (success)
+			{
+				mResponder->setData(mReadData, mDataSize, mImageSize, mImageFormat, mImageLocal);
+				mReadData = NULL; // responder owns data
+				mDataSize = 0;
+			}
+			else
+			{
+				delete[] mReadData;
+				mReadData = NULL;
+				
+			}
+		}
+		else
+		{
+			// write
+			mWriteData = NULL; // we never owned data
+			mDataSize = 0;
+		}
+		mResponder->completed(success);
+	}
+}
+
+//virtual (MAIN THREAD)
+void LLTextureCacheWorker::endWork(S32 param, bool aborted)
+{
+	if (aborted)
+	{
+		// Let the destructor handle any cleanup
+		return;
+	}
+	switch(param)
+	{
+	  default:
+	  case 0: // read
+	  case 1: // write
+	  {
+		  if (mDataSize < 0)
+		  {
+			  // failed
+			  mCache->removeFromCache(mID);
+		  }
+		  break;
+	  }
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLTextureCache::LLTextureCache(bool threaded)
+	: LLWorkerThread("TextureCache", threaded),
+	  mWorkersMutex(getAPRPool()),
+	  mHeaderMutex(getAPRPool()),
+	  mFileAPRPool(NULL),
+	  mReadOnly(FALSE),
+	  mTexturesSizeTotal(0),
+	  mDoPurge(FALSE)
+{
+	apr_pool_create(&mFileAPRPool, NULL);
+}
+
+LLTextureCache::~LLTextureCache()
+{
+	apr_pool_destroy(mFileAPRPool);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+//virtual
+S32 LLTextureCache::update(U32 max_time_ms)
+{
+	S32 res;
+	res = LLWorkerThread::update(max_time_ms);
+
+	lockWorkers();
+	for (std::vector<handle_t>::iterator iter1 = mPrioritizeWriteList.begin();
+		 iter1 != mPrioritizeWriteList.end(); ++iter1)
+	{
+		handle_t handle = *iter1;
+		handle_map_t::iterator iter2 = mWriters.find(handle);
+		if(iter2 != mWriters.end())
+		{
+			LLTextureCacheWorker* worker = iter2->second;
+			worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mPriority);
+		}
+	}
+	mPrioritizeWriteList.clear();
+	unlockWorkers();
+	return res;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string LLTextureCache::getLocalFileName(const LLUUID& id)
+{
+	// Does not include extension
+	std::string idstr = id.asString();
+	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", idstr);
+	return filename;
+}
+
+std::string LLTextureCache::getTextureFileName(const LLUUID& id)
+{
+	std::string idstr = id.asString();
+	std::string delem = gDirUtilp->getDirDelimiter();
+	std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr;
+	return filename;
+}
+
+bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
+{
+	bool res = false;
+	bool purge = false;
+	// Append UUID to end of texture entries
+	{
+		LLMutexLock lock(&mHeaderMutex);
+		size_map_t::iterator iter = mTexturesSizeMap.find(id);
+		if (iter == mTexturesSizeMap.end() || iter->second < bodysize)
+		{
+			llassert_always(bodysize > 0);
+			Entry* entry = new Entry(id, bodysize, time(NULL));
+			ll_apr_file_write_ex(mTexturesDirEntriesFileName, getFileAPRPool(),
+								 (U8*)entry, -1, 1*sizeof(Entry));
+			delete entry;
+			if (iter != mTexturesSizeMap.end())
+			{
+				mTexturesSizeTotal -= iter->second;
+			}
+			mTexturesSizeTotal += bodysize;
+			mTexturesSizeMap[id] = bodysize;
+			if (mTexturesSizeTotal > sCacheMaxTexturesSize)
+			{
+				purge = true;
+			}
+			res = true;
+		}
+	}
+	if (purge)
+	{
+		mDoPurge = TRUE;
+	}
+	return res;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+//static
+const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB
+F32 LLTextureCache::sHeaderCacheVersion = 1.0f;
+U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
+S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
+const char* entries_filename = "texture.entries";
+const char* cache_filename = "texture.cache";
+const char* textures_dirname = "textures";
+
+void LLTextureCache::setDirNames(ELLPath location)
+{
+	std::string delem = gDirUtilp->getDirDelimiter();
+	mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
+	mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
+	mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
+	mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
+}
+
+void LLTextureCache::purgeCache(ELLPath location)
+{
+	if (!mReadOnly)
+	{
+		setDirNames(location);
+	
+		ll_apr_file_remove(mHeaderEntriesFileName, NULL);
+		ll_apr_file_remove(mHeaderDataFileName, NULL);
+	}
+	purgeAllTextures(true);
+}
+
+S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
+{
+	mReadOnly = read_only;
+	
+	S64 header_size = (max_size * 2) / 10;
+	S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE;
+	sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries));
+	header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE;
+	max_size -= header_size;
+	if (sCacheMaxTexturesSize > 0)
+		sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size);
+	else
+		sCacheMaxTexturesSize = max_size;
+	max_size -= sCacheMaxTexturesSize;
+	
+	llinfos << "TEXTURE CACHE: Headers: " << sCacheMaxEntries
+			<< " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << llendl;
+
+	setDirNames(location);
+	
+	if (!mReadOnly)
+	{
+		LLFile::mkdir(mTexturesDirName.c_str());
+		const char* subdirs = "0123456789abcdef";
+		for (S32 i=0; i<16; i++)
+		{
+			std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i];
+			LLFile::mkdir(dirname.c_str());
+		}
+	}
+	readHeaderCache();
+	purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it
+
+	return max_size; // unused cache space
+}
+
+struct lru_data
+{
+	lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; }
+	U32 time;
+	S32 index;
+	LLUUID uuid;
+	struct Compare
+	{
+		// lhs < rhs
+		typedef const lru_data* lru_data_ptr;
+		bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const
+		{
+			if (!(a->time < b->time))
+				return true;
+			else if (!(b->time < a->time))
+				return false;
+			else
+				return a->index < b->index;
+		}
+	};				
+};
+
+// Called from either the main thread or the worker thread
+void LLTextureCache::readHeaderCache(apr_pool_t* poolp)
+{
+	LLMutexLock lock(&mHeaderMutex);
+	mHeaderEntriesInfo.mVersion = 0.f;
+	mHeaderEntriesInfo.mEntries = 0;
+	if (ll_apr_file_exists(mHeaderEntriesFileName, poolp))
+	{
+		ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
+							(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
+	}
+	if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
+	{
+		if (!mReadOnly)
+		{
+			// Info with 0 entries
+			mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
+			ll_apr_file_write_ex(mHeaderEntriesFileName, poolp,
+								 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
+		}
+	}
+	else
+	{
+		S32 num_entries = mHeaderEntriesInfo.mEntries;
+		if (num_entries)
+		{
+			Entry* entries = new Entry[num_entries];
+			ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
+								(U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry));
+			typedef std::set<lru_data*, lru_data::Compare> lru_set_t;
+			lru_set_t lru;
+			for (S32 i=0; i<num_entries; i++)
+			{
+				if (entries[i].mSize >= 0) // -1 indicates erased entry, skip
+				{
+					const LLUUID& id = entries[i].mID;
+					lru.insert(new lru_data(entries[i].mTime, i, id));
+					mHeaderIDMap[id] = i;
+				}
+			}
+			mLRU.clear();
+			S32 lru_entries = sCacheMaxEntries / 10;
+			for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter)
+			{
+				lru_data* data = *iter;
+				mLRU[data->index] = data->uuid;
+				if (--lru_entries <= 0)
+					break;
+			}
+			for_each(lru.begin(), lru.end(), DeletePointer());
+			delete[] entries;
+		}
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void LLTextureCache::purgeAllTextures(bool purge_directories)
+{
+	if (!mReadOnly)
+	{
+		const char* subdirs = "0123456789abcdef";
+		std::string delem = gDirUtilp->getDirDelimiter();
+		std::string mask = delem + "*";
+		for (S32 i=0; i<16; i++)
+		{
+			std::string dirname = mTexturesDirName + delem + subdirs[i];
+			gDirUtilp->deleteFilesInDir(dirname.c_str(),mask);
+			if (purge_directories)
+			{
+				LLFile::rmdir(dirname.c_str());
+			}
+		}
+		ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
+		if (purge_directories)
+		{
+			LLFile::rmdir(mTexturesDirName.c_str());
+		}
+	}
+	mTexturesSizeMap.clear();
+}
+
+void LLTextureCache::purgeTextures(bool validate)
+{
+	if (mReadOnly)
+	{
+		return;
+	}
+
+	LLMutexLock lock(&mHeaderMutex);
+	
+	S32 filesize = ll_apr_file_size(mTexturesDirEntriesFileName, NULL);
+	S32 num_entries = filesize / sizeof(Entry);
+	if (num_entries * (S32)sizeof(Entry) != filesize)
+	{
+		llwarns << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << llendl;
+		purgeAllTextures(false);
+		return;
+	}
+	if (num_entries == 0)
+	{
+		return; // nothing to do
+	}
+	
+	Entry* entries = new Entry[num_entries];
+	S32 bytes_read = ll_apr_file_read_ex(mTexturesDirEntriesFileName, NULL,
+										 (U8*)entries, 0, num_entries*sizeof(Entry));
+	if (bytes_read != filesize)
+	{
+		llwarns << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << llendl;
+		purgeAllTextures(false);
+		return;
+	}
+	
+	llinfos << "TEXTURE CACHE: Reading Entries..." << llendl;
+	
+	std::map<LLUUID, S32> entry_idx_map;
+	S64 total_size = 0;
+	for (S32 idx=0; idx<num_entries; idx++)
+	{
+		const LLUUID& id = entries[idx].mID;
+// 		llinfos << "Entry: " << id << " Size: " << entries[i].mSize << " Time: " << entries[i].mTime << llendl;
+		std::map<LLUUID, S32>::iterator iter = entry_idx_map.find(id);
+		if (iter != entry_idx_map.end())
+		{
+			// Newer entry replacing older entry
+			S32 pidx = iter->second;
+			total_size -= entries[pidx].mSize;
+			entries[pidx].mSize = 0; // flag: skip older entry
+		}
+		entry_idx_map[id] = idx;
+		total_size += entries[idx].mSize;
+	}
+
+	U32 validate_idx = 0;
+	if (validate)
+	{
+		validate_idx = gSavedSettings.getU32("CacheValidateCounter");
+		U32 next_idx = (++validate_idx) % 256;
+		gSavedSettings.setU32("CacheValidateCounter", next_idx);
+		llinfos << "TEXTURE CACHE: Validating: " << validate_idx << llendl;
+	}
+	
+	S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10;
+	S32 purge_count = 0;
+	S32 next_idx = 0;
+	for (S32 idx=0; idx<num_entries; idx++)
+	{
+		if (entries[idx].mSize == 0)
+		{
+			continue;
+		}
+		bool purge_entry = false;
+		std::string filename = getTextureFileName(entries[idx].mID);
+		if (total_size >= min_cache_size)
+		{
+			purge_entry = true;
+		}
+		else if (validate)
+		{
+			// make sure file exists and is the correct size
+			S32 uuididx = entries[idx].mID.mData[0];
+			if (uuididx == validate_idx)
+			{
+// 				llinfos << "Validating: " << filename << "Size: " << entries[idx].mSize << llendl;
+				S32 bodysize = ll_apr_file_size(filename, NULL);
+				if (bodysize != entries[idx].mSize)
+				{
+					llwarns << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize
+							<< filename << llendl;
+					purge_entry = true;
+				}
+			}
+		}
+		if (purge_entry)
+		{
+			purge_count++;
+//	 		llinfos << "PURGING: " << filename << llendl;
+			ll_apr_file_remove(filename, NULL);
+			total_size -= entries[idx].mSize;
+			entries[idx].mSize = 0;
+		}
+		else
+		{
+			if (next_idx != idx)
+			{
+				entries[next_idx] = entries[idx];
+			}
+			++next_idx;
+		}
+	}
+	num_entries = next_idx;
+
+	llinfos << "TEXTURE CACHE: Writing Entries: " << num_entries << llendl;
+	
+	ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
+	ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL,
+						 (U8*)&entries[0], 0, num_entries*sizeof(Entry));
+	
+	mTexturesSizeTotal = 0;
+	mTexturesSizeMap.clear();
+	for (S32 idx=0; idx<num_entries; idx++)
+	{
+		mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
+		mTexturesSizeTotal += entries[idx].mSize;
+	}
+	llassert(mTexturesSizeTotal == total_size);
+	
+	delete[] entries;
+	
+	llinfos << "TEXTURE CACHE:"
+			<< " PURGED: " << purge_count
+			<< " ENTRIES: " << num_entries
+			<< " CACHE SIZE: " << total_size / 1024*1024 << " MB"
+			<< llendl;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// call lockWorkers() first!
+LLTextureCacheWorker* LLTextureCache::getReader(handle_t handle)
+{
+	LLTextureCacheWorker* res = NULL;
+	handle_map_t::iterator iter = mReaders.find(handle);
+	if (iter != mReaders.end())
+	{
+		res = iter->second;
+	}
+	return res;
+}
+
+LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
+{
+	LLTextureCacheWorker* res = NULL;
+	handle_map_t::iterator iter = mWriters.find(handle);
+	if (iter != mWriters.end())
+	{
+		res = iter->second;
+	}
+	return res;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Called from work thread
+S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize)
+{
+	bool retry = false;
+	S32 idx = -1;
+
+	{
+		LLMutexLock lock(&mHeaderMutex);
+		id_map_t::iterator iter = mHeaderIDMap.find(id);
+		if (iter != mHeaderIDMap.end())
+		{
+			idx = iter->second;
+		}
+		else if (touch && !mReadOnly)
+		{
+			if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
+			{
+				// Add an entry
+				idx = mHeaderEntriesInfo.mEntries++;
+				mHeaderIDMap[id] = idx;
+				// Update Info
+				ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
+									(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
+			}
+			else if (!mLRU.empty())
+			{
+				idx = mLRU.begin()->first; // will be erased below
+				const LLUUID& oldid = mLRU.begin()->second;
+				mHeaderIDMap.erase(oldid);
+				mTexturesSizeMap.erase(oldid);
+				mHeaderIDMap[id] = idx;
+			}
+			else
+			{
+				idx = -1;
+				retry = true;
+			}
+		}
+		if (idx >= 0)
+		{
+			if (touch && !mReadOnly)
+			{
+				// Update the lru entry
+				mLRU.erase(idx);
+				llassert_always(imagesize && *imagesize > 0);
+				Entry* entry = new Entry(id, *imagesize, time(NULL));
+				S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+				ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
+									 (U8*)entry, offset, sizeof(Entry));
+				delete entry;
+			}
+			else if (imagesize)
+			{
+				// Get the image size
+				Entry entry;
+				S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+				ll_apr_file_read_ex(mHeaderEntriesFileName, getFileAPRPool(),
+									(U8*)&entry, offset, sizeof(Entry));
+				*imagesize = entry.mSize;
+			}
+		}
+	}
+	if (retry)
+	{
+		readHeaderCache(getFileAPRPool()); // updates the lru
+		llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
+		idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion
+	}
+	return idx;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Calls from texture pipeline thread (i.e. LLTextureFetch)
+
+LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 priority,
+													   S32 offset, S32 size, ReadResponder* responder)
+{
+	// Note: checking to see if an entry exists can cause a stall,
+	//  so let the thread handle it
+	LLMutexLock lock(&mWorkersMutex);
+	LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id,
+															NULL, size, offset, 0,
+															responder);
+	handle_t handle = worker->read();
+	mReaders[handle] = worker;
+	return handle;
+}
+
+bool LLTextureCache::readComplete(handle_t handle, bool abort)
+{
+	lockWorkers();
+	handle_map_t::iterator iter = mReaders.find(handle);
+	llassert_always(iter != mReaders.end());
+	LLTextureCacheWorker* worker = iter->second;
+	bool res = worker->complete();
+	if (res || abort)
+	{
+		mReaders.erase(handle);
+		unlockWorkers();
+		worker->scheduleDelete();
+		return true;
+	}
+	else
+	{
+		unlockWorkers();
+		return false;
+	}
+}
+
+LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority,
+													  U8* data, S32 datasize, S32 imagesize,
+													  WriteResponder* responder)
+{
+	if (mReadOnly)
+	{
+		return LLWorkerThread::nullHandle();
+	}
+	if (mDoPurge)
+	{
+		// NOTE: This may cause an occasional hiccup,
+		//  but it really needs to be done on the control thread
+		//  (i.e. here)
+		purgeTextures(false);
+		mDoPurge = FALSE;
+	}
+	if (datasize >= TEXTURE_CACHE_ENTRY_SIZE)
+	{
+		LLMutexLock lock(&mWorkersMutex);
+		llassert_always(imagesize > 0);
+		LLTextureCacheWorker* worker = new LLTextureCacheWorker(this, priority, id,
+																data, datasize, 0,
+																imagesize, responder);
+		handle_t handle = worker->write();
+		mWriters[handle] = worker;
+		return handle;
+	}
+	return LLWorkerThread::nullHandle();
+}
+
+bool LLTextureCache::writeComplete(handle_t handle, bool abort)
+{
+	lockWorkers();
+	handle_map_t::iterator iter = mWriters.find(handle);
+	llassert_always(iter != mWriters.end());
+	LLTextureCacheWorker* worker = iter->second;
+	if (worker->complete() || abort)
+	{
+		mWriters.erase(handle);
+		unlockWorkers();
+		worker->scheduleDelete();
+		return true;
+	}
+	else
+	{
+		unlockWorkers();
+		return false;
+	}
+}
+
+void LLTextureCache::prioritizeWrite(handle_t handle)
+{
+	// Don't prioritize yet, we might be working on this now
+	//   which could create a deadlock
+	mPrioritizeWriteList.push_back(handle);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Called from MAIN thread (endWork())
+
+bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
+{
+	if (mReadOnly)
+	{
+		return false;
+	}
+	LLMutexLock lock(&mHeaderMutex);
+	id_map_t::iterator iter = mHeaderIDMap.find(id);
+	if (iter != mHeaderIDMap.end())
+	{
+		S32 idx = iter->second;
+		if (idx >= 0)
+		{
+			Entry* entry = new Entry(id, -1, time(NULL));
+			S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+			ll_apr_file_write_ex(mHeaderEntriesFileName, NULL,
+								 (U8*)entry, offset, sizeof(Entry));
+			delete entry;
+			mLRU[idx] = id;
+			mHeaderIDMap.erase(id);
+			mTexturesSizeMap.erase(id);
+			return true;
+		}
+	}
+	return false;
+}
+
+void LLTextureCache::removeFromCache(const LLUUID& id)
+{
+	llwarns << "Removing texture from cache: " << id << llendl;
+	if (!mReadOnly)
+	{
+		removeHeaderCacheEntry(id);
+		ll_apr_file_remove(getTextureFileName(id), NULL);
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LLTextureCache::ReadResponder::ReadResponder()
+	: mImageSize(0),
+	  mImageLocal(FALSE)
+{
+}
+
+void LLTextureCache::ReadResponder::setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal)
+{
+	if (mFormattedImage.notNull())
+	{
+		llassert_always(mFormattedImage->getCodec() == imageformat);
+		mFormattedImage->appendData(data, datasize);
+	}
+	else
+	{
+		mFormattedImage = LLImageFormatted::createFromType(imageformat);
+		mFormattedImage->setData(data,datasize);
+	}
+	mImageSize = imagesize;
+	mImageLocal = imagelocal;
+}
+
+//////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index 3b16b26b4a8..f9eb8cb1777 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -1,149 +1,149 @@
-/** 
- * @file lltexturecache.h
- * @brief Object for managing texture cachees.
- *
- * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
- * $License$
- */
-
-#ifndef LL_LLTEXTURECACHE_
-#define LL_LLTEXTURECACHE_H
-
-#include "lldir.h"
-#include "llstl.h"
-#include "llstring.h"
-#include "lluuid.h"
-
-#include "llworkerthread.h"
-
-class LLTextureCacheWorker;
-
-class LLTextureCache : public LLWorkerThread
-{
-	friend class LLTextureCacheWorker;
-
-public:
-
-	class Responder : public LLResponder
-	{
-	public:
-		virtual void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) = 0;
-	};
-	
-	class ReadResponder : public Responder
-	{
-	public:
-		ReadResponder();
-		void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal);
-		void setImage(LLImageFormatted* image) { mFormattedImage = image; }
-	protected:
-		LLPointer<LLImageFormatted> mFormattedImage;
-		S32 mImageSize;
-		BOOL mImageLocal;
-	};
-
-	class WriteResponder : public Responder
-	{
-		void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal)
-		{
-			// not used
-		}
-	};
-	
-	LLTextureCache(bool threaded);
-	~LLTextureCache();
-
-	/*virtual*/ S32 update(U32 max_time_ms);	
-	
-	void purgeCache(ELLPath location);
-	S64 initCache(ELLPath location, S64 maxsize, BOOL read_only);
-
-	handle_t readFromCache(const LLUUID& id, U32 priority, S32 offset, S32 size,
-						   ReadResponder* responder);
-	bool readComplete(handle_t handle, bool abort);
-	handle_t writeToCache(const LLUUID& id, U32 priority, U8* data, S32 datasize, S32 imagesize,
-						  WriteResponder* responder);
-	bool writeComplete(handle_t handle, bool abort = false);
-	void prioritizeWrite(handle_t handle);
-
-	void removeFromCache(const LLUUID& id);
-
-	// For LLTextureCacheWorker::Responder
-	LLTextureCacheWorker* getReader(handle_t handle);
-	LLTextureCacheWorker* getWriter(handle_t handle);
-	void lockWorkers() { mWorkersMutex.lock(); }
-	void unlockWorkers() { mWorkersMutex.unlock(); }
-
-	// debug
-	S32 getNumReads() { return mReaders.size(); }
-	S32 getNumWrites() { return mWriters.size(); }
-
-protected:
-	// Accessed by LLTextureCacheWorker
-	apr_pool_t* getFileAPRPool() { return mFileAPRPool; }
-	bool appendToTextureEntryList(const LLUUID& id, S32 size);
-	std::string getLocalFileName(const LLUUID& id);
-	std::string getTextureFileName(const LLUUID& id);
-	
-private:
-	void setDirNames(ELLPath location);
-	void readHeaderCache(apr_pool_t* poolp = NULL);
-	void purgeAllTextures(bool purge_directories);
-	void purgeTextures(bool validate);
-	S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL);
-	bool removeHeaderCacheEntry(const LLUUID& id);
-	void lockHeaders() { mHeaderMutex.lock(); }
-	void unlockHeaders() { mHeaderMutex.unlock(); }
-	
-private:
-	// Internal
-	LLMutex mWorkersMutex;
-	LLMutex mHeaderMutex;
-	apr_pool_t* mFileAPRPool;
-	
-	typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t;
-	handle_map_t mReaders;
-	handle_map_t mWriters;
-	std::vector<handle_t> mPrioritizeWriteList;
-	
-	BOOL mReadOnly;
-	
-	// Entries
-	struct EntriesInfo
-	{
-		F32 mVersion;
-		U32 mEntries;
-	};
-	struct Entry
-	{
-		Entry() {}
-		Entry(const LLUUID& id, S32 size, U32 time) : mID(id), mSize(size), mTime(time) {}
-		LLUUID mID; // 128 bits
-		S32 mSize; // total size of image if known (NOT size cached)
-		U32 mTime; // seconds since 1/1/1970
-	};
-
-	// HEADERS (Include first mip)
-	std::string mHeaderEntriesFileName;
-	std::string mHeaderDataFileName;
-	EntriesInfo mHeaderEntriesInfo;
-	typedef std::map<S32,LLUUID> index_map_t;
-	index_map_t mLRU; // index, id; stored as a map for fast removal
-	typedef std::map<LLUUID,S32> id_map_t;
-	id_map_t mHeaderIDMap;
-
-	// BODIES (TEXTURES minus headers)
-	std::string mTexturesDirName;
-	std::string mTexturesDirEntriesFileName;
-	typedef std::map<LLUUID,S32> size_map_t;
-	size_map_t mTexturesSizeMap;
-	S64 mTexturesSizeTotal;
-	LLAtomic32<BOOL> mDoPurge;
-	
-	// Statics
-	static F32 sHeaderCacheVersion;
-	static U32 sCacheMaxEntries;
-	static S64 sCacheMaxTexturesSize;
-};
-
-#endif // LL_LLTEXTURECACHE_H
+/** 
+ * @file lltexturecache.h
+ * @brief Object for managing texture cachees.
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLTEXTURECACHE_
+#define LL_LLTEXTURECACHE_H
+
+#include "lldir.h"
+#include "llstl.h"
+#include "llstring.h"
+#include "lluuid.h"
+
+#include "llworkerthread.h"
+
+class LLTextureCacheWorker;
+
+class LLTextureCache : public LLWorkerThread
+{
+	friend class LLTextureCacheWorker;
+
+public:
+
+	class Responder : public LLResponder
+	{
+	public:
+		virtual void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) = 0;
+	};
+	
+	class ReadResponder : public Responder
+	{
+	public:
+		ReadResponder();
+		void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal);
+		void setImage(LLImageFormatted* image) { mFormattedImage = image; }
+	protected:
+		LLPointer<LLImageFormatted> mFormattedImage;
+		S32 mImageSize;
+		BOOL mImageLocal;
+	};
+
+	class WriteResponder : public Responder
+	{
+		void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal)
+		{
+			// not used
+		}
+	};
+	
+	LLTextureCache(bool threaded);
+	~LLTextureCache();
+
+	/*virtual*/ S32 update(U32 max_time_ms);	
+	
+	void purgeCache(ELLPath location);
+	S64 initCache(ELLPath location, S64 maxsize, BOOL read_only);
+
+	handle_t readFromCache(const LLUUID& id, U32 priority, S32 offset, S32 size,
+						   ReadResponder* responder);
+	bool readComplete(handle_t handle, bool abort);
+	handle_t writeToCache(const LLUUID& id, U32 priority, U8* data, S32 datasize, S32 imagesize,
+						  WriteResponder* responder);
+	bool writeComplete(handle_t handle, bool abort = false);
+	void prioritizeWrite(handle_t handle);
+
+	void removeFromCache(const LLUUID& id);
+
+	// For LLTextureCacheWorker::Responder
+	LLTextureCacheWorker* getReader(handle_t handle);
+	LLTextureCacheWorker* getWriter(handle_t handle);
+	void lockWorkers() { mWorkersMutex.lock(); }
+	void unlockWorkers() { mWorkersMutex.unlock(); }
+
+	// debug
+	S32 getNumReads() { return mReaders.size(); }
+	S32 getNumWrites() { return mWriters.size(); }
+
+protected:
+	// Accessed by LLTextureCacheWorker
+	apr_pool_t* getFileAPRPool() { return mFileAPRPool; }
+	bool appendToTextureEntryList(const LLUUID& id, S32 size);
+	std::string getLocalFileName(const LLUUID& id);
+	std::string getTextureFileName(const LLUUID& id);
+	
+private:
+	void setDirNames(ELLPath location);
+	void readHeaderCache(apr_pool_t* poolp = NULL);
+	void purgeAllTextures(bool purge_directories);
+	void purgeTextures(bool validate);
+	S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL);
+	bool removeHeaderCacheEntry(const LLUUID& id);
+	void lockHeaders() { mHeaderMutex.lock(); }
+	void unlockHeaders() { mHeaderMutex.unlock(); }
+	
+private:
+	// Internal
+	LLMutex mWorkersMutex;
+	LLMutex mHeaderMutex;
+	apr_pool_t* mFileAPRPool;
+	
+	typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t;
+	handle_map_t mReaders;
+	handle_map_t mWriters;
+	std::vector<handle_t> mPrioritizeWriteList;
+	
+	BOOL mReadOnly;
+	
+	// Entries
+	struct EntriesInfo
+	{
+		F32 mVersion;
+		U32 mEntries;
+	};
+	struct Entry
+	{
+		Entry() {}
+		Entry(const LLUUID& id, S32 size, U32 time) : mID(id), mSize(size), mTime(time) {}
+		LLUUID mID; // 128 bits
+		S32 mSize; // total size of image if known (NOT size cached)
+		U32 mTime; // seconds since 1/1/1970
+	};
+
+	// HEADERS (Include first mip)
+	std::string mHeaderEntriesFileName;
+	std::string mHeaderDataFileName;
+	EntriesInfo mHeaderEntriesInfo;
+	typedef std::map<S32,LLUUID> index_map_t;
+	index_map_t mLRU; // index, id; stored as a map for fast removal
+	typedef std::map<LLUUID,S32> id_map_t;
+	id_map_t mHeaderIDMap;
+
+	// BODIES (TEXTURES minus headers)
+	std::string mTexturesDirName;
+	std::string mTexturesDirEntriesFileName;
+	typedef std::map<LLUUID,S32> size_map_t;
+	size_map_t mTexturesSizeMap;
+	S64 mTexturesSizeTotal;
+	LLAtomic32<BOOL> mDoPurge;
+	
+	// Statics
+	static F32 sHeaderCacheVersion;
+	static U32 sCacheMaxEntries;
+	static S64 sCacheMaxTexturesSize;
+};
+
+#endif // LL_LLTEXTURECACHE_H
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index db747c60fc8..4c90c3624b7 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1205,9 +1205,9 @@ bool LLTextureFetchWorker::writeToCacheComplete()
 LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded)
 	: LLWorkerThread("TextureFetch", threaded),
 	  mDebugCount(0),
-	  mDebugPause(0),
-	  mTextureCache(cache),
-	  mQueueMutex(getAPRPool())
+	  mDebugPause(FALSE),
+	  mQueueMutex(getAPRPool()),
+	  mTextureCache(cache)
 {
 }
 
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index b3510d9e823..7cf7cb45f22 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -82,4 +82,4 @@ class LLTextureFetch : public LLWorkerThread
 	LLFrameTimer mNetworkTimer;
 };
 
-#endif LL_LLTEXTUREFETCH_H
+#endif // LL_LLTEXTUREFETCH_H
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 837eaa90e92..f6fa23c6f60 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -582,6 +582,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 			gPipeline.stateSort(hud_cam);
 		}
 		
+		if (LLVertexBuffer::sEnableVBOs)
+		{
+			LLImageGL::sBoundTextureMemory += LLVertexBuffer::sAllocatedBytes;
+		}
+		
 		gPipeline.renderGeom(hud_cam);
 
 		//restore type mask
@@ -716,9 +721,10 @@ void render_ui_and_swap()
 		}
 
 		{
-// 			LLFastTimer ftm(LLFastTimer::FTM_TEMP6);
-			LLVertexBuffer::clientCopy();
+ 			LLFastTimer ftm(LLFastTimer::FTM_CLIENT_COPY);
+			LLVertexBuffer::clientCopy(0.016);
 		}
+
 	}
 }
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 275db0f9063..64560efd67c 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1134,6 +1134,9 @@ void init_debug_rendering_menu(LLMenuGL* menu)
 	sub_menu->append(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_TEXTURE_AREA));
+	sub_menu->append(new LLMenuItemCheckGL("Face Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL,
+													&LLPipeline::toggleRenderDebugControl,
+													(void*)LLPipeline::RENDER_DEBUG_FACE_AREA));
 	sub_menu->append(new LLMenuItemCheckGL("Pick Render",	&LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_PICKING));
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 8ed5406e856..6d4170e4377 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1357,7 +1357,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 			// Make sure the binary bucket is big enough to hold the header 
 			// and a null terminated item name.
-			if ( (binary_bucket_size < (sizeof(notice_bucket_header_t) + sizeof(U8)))
+			if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8))))
 				|| (binary_bucket[binary_bucket_size - 1] != '\0') )
 			{
 				llwarns << "Malformed group notice binary bucket" << llendl;
diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp
index b02985ddfa1..189b314e55a 100644
--- a/indra/newview/llviewernetwork.cpp
+++ b/indra/newview/llviewernetwork.cpp
@@ -71,4 +71,4 @@ F32 gPacketDropPercentage = 0.f;
 F32 gInBandwidth = 0.f;
 F32 gOutBandwidth = 0.f;
 
-unsigned char gMACAddress[MAC_ADDRESS_BYTES];		/* Flawfinder: ignore */
\ No newline at end of file
+unsigned char gMACAddress[MAC_ADDRESS_BYTES];		/* Flawfinder: ignore */
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index cd915317ba4..ee29876274e 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -2523,9 +2523,9 @@ LLParcelSelection::LLParcelSelection() :
 	mParcel(NULL),
 	mSelectedMultipleOwners(FALSE),
 	mWholeParcelSelected(FALSE),
-	mSelectedPublicCount(0),
 	mSelectedSelfCount(0),
-	mSelectedOtherCount(0)
+	mSelectedOtherCount(0),
+	mSelectedPublicCount(0)
 {
 }
 
@@ -2533,9 +2533,9 @@ LLParcelSelection::LLParcelSelection(LLParcel* parcel)  :
 	mParcel(parcel),
 	mSelectedMultipleOwners(FALSE),
 	mWholeParcelSelected(FALSE),
-	mSelectedPublicCount(0),
 	mSelectedSelfCount(0),
-	mSelectedOtherCount(0)
+	mSelectedOtherCount(0),
+	mSelectedPublicCount(0)
 {
 }
 
@@ -2570,4 +2570,4 @@ LLParcelSelection* get_null_parcel_selection()
 {
 	static LLParcelSelectionHandle null_ptr = new LLParcelSelection();
 	return null_ptr;
-}
\ No newline at end of file
+}
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index aebcfdb9ce2..36c08321ed9 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1842,13 +1842,6 @@ void LLViewerWindow::reshape(S32 width, S32 height)
 
 		gViewerStats->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
 		gViewerStats->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
-
-		//reposition HUD attachments
-		LLVOAvatar* avatarp = gAgent.getAvatarObject();
-		if (avatarp)
-		{
-			avatarp->resetHUDAttachments();
-		}
 	}
 }
 
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 507a1468c72..afeffa0aec4 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -748,9 +748,9 @@ LLVOAvatar::LLVOAvatar(
 	mLastSkirtBakedID( IMG_DEFAULT_AVATAR ),
 	mIsDummy(FALSE),
 	mSpecialRenderMode(0),
+	mTurning(FALSE),
 	mPelvisToFoot(0.f),
 	mLastSkeletonSerialNum( 0 ),
-	mTurning(FALSE),
 	mHeadOffset(),
 	mIsSitting(FALSE),
 	mTimeVisible(),
@@ -3005,8 +3005,12 @@ void LLVOAvatar::updateCharacter(LLAgent &agent)
 	{
 		F32 aspect = gCamera->getAspect();
 		LLVector3 scale(1.f, aspect, 1.f);
-		mScreenp->setScale(scale);
-		mScreenp->updateWorldMatrixChildren();
+		if (mScreenp->getScale() != scale)
+		{
+			mScreenp->setScale(scale);
+			mScreenp->updateWorldMatrixChildren();
+			resetHUDAttachments();
+		}
 	}
 
 	// clear debug text
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 2d898a1a5dc..d08c5311d7b 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -244,7 +244,7 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 		S32 result;
 		if (result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot))
 		{
-			mTexAnimMode = result | mTextureAnimp->mMode;
+			mTexAnimMode = mTextureAnimp->mMode | result;
 
 			S32 start, end;
 			if (mTextureAnimp->mFace == -1)
@@ -309,6 +309,13 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 				tex_mat.translate(trans);
 			}
 		}
+		else
+		{
+			if (mTextureAnimp->mRate == 0)
+			{
+				mTexAnimMode = 0;
+			}
+		}
 	}
 
 	// Dispatch to implementation
@@ -349,17 +356,18 @@ void LLVOVolume::updateTextures()
 
 	mTextureUpdateTimer.reset();
 	
+	F32 old_area = mPixelArea;
 	mPixelArea = 0.f;
-	const S32 num_faces = mDrawable->getNumFaces();
 
+	const S32 num_faces = mDrawable->getNumFaces();
 	F32 min_vsize=999999999.f, max_vsize=0.f;
 	for (S32 i = 0; i < num_faces; i++)
 	{
 		LLFace* face = mDrawable->getFace(i);
 		const LLTextureEntry *te = face->getTextureEntry();
 		LLViewerImage *imagep = face->getTexture();
-
-		if (!imagep || !te)
+		if (!imagep || !te ||
+			face->mExtents[0] == face->mExtents[1])
 		{
 			continue;
 		}
@@ -392,11 +400,12 @@ void LLVOVolume::updateTextures()
 			if (pri < min_vsize) min_vsize = pri;
 			if (pri > max_vsize) max_vsize = pri;
 		}
-	//	U8 bump = te->getBumpmap();
-	//	if( te && bump)
-	//	{
-	//		gBumpImageList.addTextureStats( bump, imagep->getID(), vsize, 1, 1);
-	//	}
+		else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
+		{
+			F32 pri = mPixelArea;
+			if (pri < min_vsize) min_vsize = pri;
+			if (pri > max_vsize) max_vsize = pri;
+		}	
 	}
 
 	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
@@ -407,15 +416,22 @@ void LLVOVolume::updateTextures()
 	{
 		setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
 	}
+	else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
+	{
+		setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+	}
+
+	if (mPixelArea == 0)
+	{ //flexi phasing issues make this happen
+		mPixelArea = old_area;
+	}
 }
 
 F32 LLVOVolume::getTextureVirtualSize(LLFace* face)
 {
 	//get area of circle around face
 	LLVector3 center = face->getPositionAgent();
-	LLVector3 size = //isFlexible() ? 
-					//	getScale()*3.f :
-						(face->mExtents[1] - face->mExtents[0]) * 0.5f;
+	LLVector3 size = (face->mExtents[1] - face->mExtents[0]) * 0.5f;
 	
 	F32 face_area = LLPipeline::calcPixelArea(center, size, *gCamera);
 
@@ -585,9 +601,6 @@ BOOL LLVOVolume::calcLOD()
 		return FALSE;
 	}
 
-	//update textures here as well
-	updateTextures();
-
 	S32 cur_detail = 0;
 	
 	F32 radius = mVolumep->mLODScaleBias.scaledVec(getScale()).magVec();
@@ -689,6 +702,17 @@ void LLVOVolume::updateFaceFlags()
 	}
 }
 
+void LLVOVolume::setParent(LLViewerObject* parent)
+{
+	LLViewerObject::setParent(parent);
+	if (mDrawable)
+	{
+		gPipeline.markMoved(mDrawable);
+		mVolumeChanged = TRUE;
+		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+	}
+}
+
 // NOTE: regenFaces() MUST be followed by genTriangles()!
 void LLVOVolume::regenFaces()
 {
@@ -748,6 +772,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 	{
 		mDrawable->setSpatialExtents(min,max);
 		mDrawable->setPositionGroup((min+max)*0.5f);	
+		//bounding boxes changed, update texture priorities
+		updateTextures();
 	}
 
 	updateRadius();
@@ -1918,8 +1944,10 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer &&
 		draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
 		draw_vec[idx]->mTexture == tex &&
-		//draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
-		//draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
+#if LL_DARWIN
+		draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
+		draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
+#endif
 		draw_vec[idx]->mFullbright == fullbright &&
 		draw_vec[idx]->mBump == bump &&
 		draw_vec[idx]->mTextureMatrix == tex_mat)
@@ -2220,7 +2248,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 					registerFace(group, facep, LLRenderPass::PASS_BUMP);
 				}
 
-				if (!force_simple && vobj->getIsLight())
+				if (vobj->getIsLight())
 				{
 					registerFace(group, facep, LLRenderPass::PASS_GLOW);
 				}
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 3eb8ad6c14c..76b469e6aa1 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -79,7 +79,7 @@ class LLVOVolume : public LLViewerObject
 	/*virtual*/ BOOL	isHUDAttachment() const;
 
 				void	generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point);
-
+	/*virtual*/	void	setParent(LLViewerObject* parent);
 				F32		getIndividualRadius()					{ return mRadius; }
 				S32		getLOD() const							{ return mLOD; }
 	const LLVector3		getPivotPositionAgent() const;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 250b9bc7dfe..d7abae32c89 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -212,6 +212,8 @@ BOOL	LLPipeline::sSkipUpdate = FALSE;
 BOOL	LLPipeline::sDynamicReflections = FALSE;
 
 LLPipeline::LLPipeline() :
+	mCubeBuffer(NULL),
+	mCubeList(0),
 	mVertexShadersEnabled(FALSE),
 	mVertexShadersLoaded(0),
 	mLastRebuildPool(NULL),
@@ -225,9 +227,7 @@ LLPipeline::LLPipeline() :
 	mSimplePool(NULL),
 	mBumpPool(NULL),
 	mLightMask(0),
-	mLightMovingMask(0),
-	mCubeBuffer(NULL),
-	mCubeList(0)
+	mLightMovingMask(0)
 {
 
 }
@@ -1710,7 +1710,6 @@ void LLPipeline::updateMove()
 F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera)
 {
 	LLVector3 lookAt = center - camera.getOrigin();
-	LLVector3 cross_vec = size * 2.f;	
 	F32 dist = lookAt.magVec();
 
 	//ramp down distance for nearby objects
@@ -1722,7 +1721,7 @@ F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera
 	}
 
 	//get area of circle around node
-	F32 app_angle = atanf((cross_vec*0.5f).magVec()/dist);
+	F32 app_angle = atanf(size.magVec()/dist);
 	F32 radius = app_angle*LLDrawable::sCurPixelAngle;
 	return radius*radius * 3.14159f;
 }
@@ -2196,10 +2195,12 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 		}
 	}
 	
+#if !LL_DARWIN
 	if (gFrameTimeSeconds - group->mLastUpdateTime > 4.f)
 	{
 		group->makeStatic();
 	}
+#endif
 }
 
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index c744a29beca..0fadae0a617 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -325,7 +325,8 @@ class LLPipeline
 		RENDER_DEBUG_POINTS				= 0x02000,
 		RENDER_DEBUG_TEXTURE_PRIORITY	= 0x04000,
 		RENDER_DEBUG_TEXTURE_AREA		= 0x08000,
-		RENDER_DEBUG_PARTICLES			= 0x10000,
+		RENDER_DEBUG_FACE_AREA			= 0x10000,
+		RENDER_DEBUG_PARTICLES			= 0x20000,
 	};
 
 	LLPointer<LLViewerImage>	mAlphaSizzleImagep;
-- 
GitLab