diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 708745239e0a69818ddf760f25e8c63498059790..66f1ffd41b227c44491dcb6e67a2505b9eec6b0a 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -85,6 +85,22 @@ std::vector<LLMutex*> LLCurl::sSSLMutex;
 std::string LLCurl::sCAPath;
 std::string LLCurl::sCAFile;
 
+void check_curl_code(CURLcode code)
+{
+	if (code != CURLE_OK)
+	{
+		llerrs << "curl error detected: " << curl_easy_strerror(code) << llendl;
+	}
+}
+
+void check_curl_multi_code(CURLMcode code)
+{
+	if (code != CURLM_OK)
+	{
+		llerrs << "curl multi error detected: " << curl_multi_strerror(code) << llendl;
+	}
+}
+
 //static
 void LLCurl::setCAPath(const std::string& path)
 {
@@ -333,8 +349,9 @@ LLCurl::Easy* LLCurl::Easy::getEasy()
 	
 	// set no DNS caching as default for all easy handles. This prevents them adopting a
 	// multi handles cache if they are added to one.
-	curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
-
+	CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
+	check_curl_code(result);
+	
 	++gCurlEasyCount;
 	return easy;
 }
@@ -400,9 +417,9 @@ void LLCurl::Easy::setHeaders()
 
 void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
 {
-	curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload);
-	curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime);
-	curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload);
+	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload));
+	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime));
+	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));
 }
 
 U32 LLCurl::Easy::report(CURLcode code)
@@ -412,7 +429,7 @@ U32 LLCurl::Easy::report(CURLcode code)
 	
 	if (code == CURLE_OK)
 	{
-		curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode);
+		check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode));
 		//*TODO: get reason from first line of mHeaderOutput
 	}
 	else
@@ -435,17 +452,20 @@ U32 LLCurl::Easy::report(CURLcode code)
 // Note: these all assume the caller tracks the value (i.e. keeps it persistant)
 void LLCurl::Easy::setopt(CURLoption option, S32 value)
 {
-	curl_easy_setopt(mCurlEasyHandle, option, value);
+	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
+	check_curl_code(result);
 }
 
 void LLCurl::Easy::setopt(CURLoption option, void* value)
 {
-	curl_easy_setopt(mCurlEasyHandle, option, value);
+	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
+	check_curl_code(result);
 }
 
 void LLCurl::Easy::setopt(CURLoption option, char* value)
 {
-	curl_easy_setopt(mCurlEasyHandle, option, value);
+	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
+	check_curl_code(result);
 }
 
 // Note: this copies the string so that the caller does not have to keep it around
@@ -454,7 +474,8 @@ void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
 	char* tstring = new char[value.length()+1];
 	strcpy(tstring, value.c_str());
 	mStrings.push_back(tstring);
-	curl_easy_setopt(mCurlEasyHandle, option, tstring);
+	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, tstring);
+	check_curl_code(result);
 }
 
 void LLCurl::Easy::slist_append(const char* str)
@@ -593,12 +614,12 @@ LLCurl::Multi::Multi()
 	  mErrorCount(0)
 {
 	mCurlMultiHandle = curl_multi_init();
-	
 	if (!mCurlMultiHandle)
 	{
 		llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
 		mCurlMultiHandle = curl_multi_init();
 	}
+	
 	llassert_always(mCurlMultiHandle);
 	++gCurlMultiCount;
 }
@@ -610,7 +631,7 @@ LLCurl::Multi::~Multi()
 		iter != mEasyActiveList.end(); ++iter)
 	{
 		Easy* easy = *iter;
-		curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
+		check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
 		delete easy;
 	}
 	mEasyActiveList.clear();
@@ -620,7 +641,7 @@ LLCurl::Multi::~Multi()
 	for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());	
 	mEasyFreeList.clear();
 
-	curl_multi_cleanup(mCurlMultiHandle);
+	check_curl_multi_code(curl_multi_cleanup(mCurlMultiHandle));
 	--gCurlMultiCount;
 }
 
@@ -641,8 +662,10 @@ S32 LLCurl::Multi::perform()
 		CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
 		if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
 		{
+			check_curl_multi_code(code);
 			break;
 		}
+	
 	}
 	mQueued = q;
 	return q;
@@ -709,11 +732,12 @@ LLCurl::Easy* LLCurl::Multi::allocEasy()
 bool LLCurl::Multi::addEasy(Easy* easy)
 {
 	CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle());
-	if (mcode != CURLM_OK)
-	{
-		llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
-		return false;
-	}
+	check_curl_multi_code(mcode);
+	//if (mcode != CURLM_OK)
+	//{
+	//	llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
+	//	return false;
+	//}
 	return true;
 }
 
@@ -734,7 +758,7 @@ void LLCurl::Multi::easyFree(Easy* easy)
 
 void LLCurl::Multi::removeEasy(Easy* easy)
 {
-	curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
+	check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
 	easyFree(easy);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
index 1626e21cd883c4b0b53a351333801c7764eab04c..5ae41cb73093d99f0e6c5ba60f3c109729057c6d 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
@@ -1,5 +1,5 @@
 /** 
- * @file diffuseSkinnedV.glsl
+ * @file attachmentShadowV.glsl
  *
  * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
  * $License$
@@ -21,5 +21,7 @@ void main()
 	
 	gl_FrontColor = gl_Color;
 	
-	gl_Position = gl_ProjectionMatrix*vec4(pos, 1.0);
+	vec4 p = gl_ProjectionMatrix * vec4(pos, 1.0);
+	p.z = max(p.z, -p.w+0.01);
+	gl_Position = p;
 }
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 72019d8de8329bcece292ca632c32ceb430e6736..1885b48812fb0308984d13ea7f6729f2f3ee5007 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -645,7 +645,7 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id)
 	
 	if (gAgent.getRegion())
 	{
-		http_url = gAgent.getRegion()->getCapability("GetMesh");
+		http_url = gMeshRepo.mGetMeshCapability; 
 		scrub_host_name(http_url, gAgent.getRegionHost());
 	}
 
@@ -2275,6 +2275,12 @@ void LLMeshRepository::notifyLoadedMeshes()
 		return;
 	}
 
+	if (gAgent.getRegion())
+	{ //update capability url 
+		//TODO: only do this when region changes
+		mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh");
+	}
+
 	LLFastTimer t(FTM_MESH_UPDATE);
 
 	{
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 427bcb8a756f61f3bc7a611826cca02052da72b6..df00c6c7aab7fb9ac5578b319683294811288cf0 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -526,6 +526,8 @@ class LLMeshRepository
 	void uploadError(LLSD& args);
 	void updateInventory(inventory_data data);
 
+	std::string mGetMeshCapability;
+
 };
 
 extern LLMeshRepository gMeshRepo;
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index e763f92fab63a5d622f91652afc663f97cece823..c23756611dcb621201cc482b6c734f59a6852c0c 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -3195,6 +3195,31 @@ void renderPhysicsShapes(LLSpatialGroup* group)
 				renderPhysicsShape(drawable, volume);
 			}
 		}
+		else
+		{
+			LLViewerObject* object = drawable->getVObj();
+			if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
+			{
+				//push face vertices for terrain
+				for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+				{
+					LLFace* face = drawable->getFace(i);
+					LLVertexBuffer* buff = face->mVertexBuffer;
+					if (buff)
+					{
+						glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+						buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+						glColor3f(0.2f, 0.5f, 0.3f);
+						buff->draw(LLRender::TRIANGLES, buff->getRequestedIndices(), 0);
+									
+						glColor3f(0.2f, 1.f, 0.3f);
+						glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+						buff->draw(LLRender::TRIANGLES, buff->getRequestedIndices(), 0);
+					}
+				}
+			}
+		}
 	}
 }
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 870dd74fc5ff572dedd4efc41981a7da1f445c45..9dc3cb9ce14f73a9caa12af7b9d5e8e7e61fd8c0 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -238,6 +238,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
 	mPhysicsCost(0.f),
 	mLinksetPhysicsCost(0.f),
 	mCostStale(true),
+	mPhysicsShapeUnknown(true),
 	mAttachmentItemID(LLUUID::null)
 {
 	if (!is_global)
@@ -5186,6 +5187,7 @@ BOOL LLViewerObject::setFlags(U32 flags, BOOL state)
 
 void LLViewerObject::setPhysicsShapeType(U8 type)
 {
+	mPhysicsShapeUnknown = false;
 	mPhysicsShapeType = type;
 }
 
@@ -5209,6 +5211,17 @@ void LLViewerObject::setPhysicsRestitution(F32 restitution)
 	mPhysicsRestitution = restitution;
 }
 
+U8 LLViewerObject::getPhysicsShapeType() const
+{ 
+	if (mPhysicsShapeUnknown)
+	{
+		mPhysicsShapeUnknown = false;
+		gObjectList.updatePhysicsFlags(this);
+	}
+
+	return mPhysicsShapeType; 
+}
+
 void LLViewerObject::applyAngularVelocity(F32 dt)
 {
 	//do target omega here
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index bd0d831d91168f86252aab5f582532abf2f51b90..59510bff1a0d7383e53d0259c61b74ba5bb1a208 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -470,7 +470,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	inline BOOL		flagCameraDecoupled() const		{ return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); }
 	inline BOOL		flagObjectMove() const			{ return ((mFlags & FLAGS_OBJECT_MOVE) != 0); }
 
-	inline U8       getPhysicsShapeType() const     { return mPhysicsShapeType; }
+	U8       getPhysicsShapeType() const;
 	inline F32      getPhysicsGravity() const       { return mPhysicsGravity; }
 	inline F32      getPhysicsFriction() const      { return mPhysicsFriction; }
 	inline F32      getPhysicsDensity() const       { return mPhysicsDensity; }
@@ -703,6 +703,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	F32 mLinksetPhysicsCost;
 
 	bool mCostStale;
+	mutable bool mPhysicsShapeUnknown;
 
 	static			U32			sNumZombieObjects;			// Objects which are dead, but not deleted
 
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 2caf984f94793a8d0cb0c2903af145caf0386ff4..0b64b204ee1aeab4346face82f5ad50ec29298ef 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -675,7 +675,7 @@ class LLObjectCostResponder : public LLCurl::Responder
 
 	void error(U32 statusNum, const std::string& reason)
 	{
-		lldebugs
+		llwarns
 			<< "Transport error requesting object cost "
 			<< "HTTP status: " << statusNum << ", reason: "
 			<< reason << "." << llendl;
@@ -691,7 +691,7 @@ class LLObjectCostResponder : public LLCurl::Responder
 		{
 			// Improper response or the request had an error,
 			// show an error to the user?
-			lldebugs
+			llwarns
 				<< "Application level error when fetching object "
 				<< "cost.  Message: " << content["error"]["message"].asString()
 				<< ", identifier: " << content["error"]["identifier"].asString()
@@ -739,6 +739,102 @@ class LLObjectCostResponder : public LLCurl::Responder
 	LLSD mObjectIDs;
 };
 
+
+class LLPhysicsFlagsResponder : public LLCurl::Responder
+{
+public:
+	LLPhysicsFlagsResponder(const LLSD& object_ids)
+		: mObjectIDs(object_ids)
+	{
+	}
+
+	// Clear's the global object list's pending
+	// request list for all objects requested
+	void clear_object_list_pending_requests()
+	{
+		// TODO*: No more hard coding
+		for (
+			LLSD::array_iterator iter = mObjectIDs.beginArray();
+			iter != mObjectIDs.endArray();
+			++iter)
+		{
+			gObjectList.onPhysicsFlagsFetchFailure(iter->asUUID());
+		}
+	}
+
+	void error(U32 statusNum, const std::string& reason)
+	{
+		llwarns
+			<< "Transport error requesting object physics flags "
+			<< "HTTP status: " << statusNum << ", reason: "
+			<< reason << "." << llendl;
+
+		// TODO*: Error message to user
+		// For now just clear the request from the pending list
+		clear_object_list_pending_requests();
+	}
+
+	void result(const LLSD& content)
+	{
+		if ( !content.isMap() || content.has("error") )
+		{
+			// Improper response or the request had an error,
+			// show an error to the user?
+			llwarns
+				<< "Application level error when fetching object "
+				<< "physics flags.  Message: " << content["error"]["message"].asString()
+				<< ", identifier: " << content["error"]["identifier"].asString()
+				<< llendl;
+
+			// TODO*: Adaptively adjust request size if the
+			// service says we've requested too many and retry
+
+			// TODO*: Error message if not retrying
+			clear_object_list_pending_requests();
+			return;
+		}
+
+		// Success, grab the resource cost and linked set costs
+		// for an object if one was returned
+		for (
+			LLSD::array_iterator iter = mObjectIDs.beginArray();
+			iter != mObjectIDs.endArray();
+			++iter)
+		{
+			LLUUID object_id = iter->asUUID();
+
+			// Check to see if the request contains data for the object
+			if ( content.has(iter->asString()) )
+			{
+				const LLSD& data = content[iter->asString()];
+
+				S32 shape_type = data["PhysicsShapeType"].asInteger();
+
+				gObjectList.updatePhysicsShapeType(object_id, shape_type);
+
+				if (data.has("Density"))
+				{
+					F32 density = data["Density"].asReal();
+					F32 friction = data["Friction"].asReal();
+					F32 restitution = data["Restitution"].asReal();
+					F32 gravity_multiplier = data["GravityMultiplier"].asReal();
+					
+					gObjectList.updatePhysicsProperties(object_id, 
+						density, friction, restitution, gravity_multiplier);
+				}
+			}
+			else
+			{
+				// TODO*: Give user feedback about the missing data?
+				gObjectList.onPhysicsFlagsFetchFailure(object_id);
+			}
+		}
+	}
+
+private:
+	LLSD mObjectIDs;
+};
+
 void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 {
 	LLMemType mt(LLMemType::MTYPE_OBJECT);
@@ -835,61 +931,8 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 		}
 	}
 
-	// issue http request for stale object physics costs
-	if (!mStaleObjectCost.empty())
-	{
-		LLViewerRegion* regionp = gAgent.getRegion();
-
-		if (regionp)
-		{
-			std::string url = regionp->getCapability("GetObjectCost");
-
-			if (!url.empty())
-			{
-				LLSD id_list;
-				U32 object_index = 0;
-
-				for (
-					std::set<LLUUID>::iterator iter = mStaleObjectCost.begin();
-					iter != mStaleObjectCost.end();
-					++iter)
-				{
-					// Check to see if a request for this object
-					// has already been made.
-					if ( mPendingObjectCost.find(*iter) ==
-						 mPendingObjectCost.end() )
-					{
-						// Why is this line here if
-						// we set mPendingObjectCost to be
-						// mStaleObjectCost below?
-						mPendingObjectCost.insert(*iter);
-						id_list[object_index++] = *iter;
-					}
-				}
-
-				// id_list should now contain all
-				// requests in mStaleObjectCost before, so clear
-				// it now
-				mStaleObjectCost.clear();
-
-				if ( id_list.size() > 0 )
-				{
-					LLSD post_data = LLSD::emptyMap();
-
-					post_data["object_ids"] = id_list;
-					LLHTTPClient::post(
-						url,
-						post_data,
-						new LLObjectCostResponder(id_list));
-				}
-			}
-			else
-			{
-				mStaleObjectCost.clear();
-				mPendingObjectCost.clear();
-			}
-		}
-	}
+	fetchObjectCosts();
+	fetchPhysicsFlags();
 
 	mNumSizeCulled = 0;
 	mNumVisCulled = 0;
@@ -956,6 +999,119 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 	LLViewerStats::getInstance()->mNumVisCulledStat.addValue(mNumVisCulled);
 }
 
+void LLViewerObjectList::fetchObjectCosts()
+{
+	// issue http request for stale object physics costs
+	if (!mStaleObjectCost.empty())
+	{
+		LLViewerRegion* regionp = gAgent.getRegion();
+
+		if (regionp)
+		{
+			std::string url = regionp->getCapability("GetObjectCost");
+
+			if (!url.empty())
+			{
+				LLSD id_list;
+				U32 object_index = 0;
+
+				for (
+					std::set<LLUUID>::iterator iter = mStaleObjectCost.begin();
+					iter != mStaleObjectCost.end();
+					++iter)
+				{
+					// Check to see if a request for this object
+					// has already been made.
+					if ( mPendingObjectCost.find(*iter) ==
+						 mPendingObjectCost.end() )
+					{
+						mPendingObjectCost.insert(*iter);
+						id_list[object_index++] = *iter;
+					}
+				}
+
+				// id_list should now contain all
+				// requests in mStaleObjectCost before, so clear
+				// it now
+				mStaleObjectCost.clear();
+
+				if ( id_list.size() > 0 )
+				{
+					LLSD post_data = LLSD::emptyMap();
+
+					post_data["object_ids"] = id_list;
+					LLHTTPClient::post(
+						url,
+						post_data,
+						new LLObjectCostResponder(id_list));
+				}
+			}
+			else
+			{
+				mStaleObjectCost.clear();
+				mPendingObjectCost.clear();
+			}
+		}
+	}
+}
+
+void LLViewerObjectList::fetchPhysicsFlags()
+{
+	// issue http request for stale object physics flags
+	if (!mStalePhysicsFlags.empty())
+	{
+		LLViewerRegion* regionp = gAgent.getRegion();
+
+		if (regionp)
+		{
+			std::string url = regionp->getCapability("GetObjectPhysicsData");
+
+			if (!url.empty())
+			{
+				LLSD id_list;
+				U32 object_index = 0;
+
+				for (
+					std::set<LLUUID>::iterator iter = mStalePhysicsFlags.begin();
+					iter != mStalePhysicsFlags.end();
+					++iter)
+				{
+					// Check to see if a request for this object
+					// has already been made.
+					if ( mPendingPhysicsFlags.find(*iter) ==
+						 mPendingPhysicsFlags.end() )
+					{
+						mPendingPhysicsFlags.insert(*iter);
+						id_list[object_index++] = *iter;
+					}
+				}
+
+				// id_list should now contain all
+				// requests in mStalePhysicsFlags before, so clear
+				// it now
+				mStalePhysicsFlags.clear();
+
+				if ( id_list.size() > 0 )
+				{
+					LLSD post_data = LLSD::emptyMap();
+
+					post_data["object_ids"] = id_list;
+					LLHTTPClient::post(
+						url,
+						post_data,
+						new LLPhysicsFlagsResponder(id_list));
+				}
+			}
+			else
+			{
+				mStalePhysicsFlags.clear();
+				mPendingPhysicsFlags.clear();
+			}
+		}
+	}
+}
+
+
 void LLViewerObjectList::clearDebugText()
 {
 	for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)
@@ -1184,7 +1340,7 @@ void LLViewerObjectList::updateObjectCost(LLViewerObject* object)
 	mStaleObjectCost.insert(object->getID());
 }
 
-void LLViewerObjectList::updateObjectCost(LLUUID object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost)
+void LLViewerObjectList::updateObjectCost(const LLUUID& object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost)
 {
 	mPendingObjectCost.erase(object_id);
 
@@ -1198,11 +1354,51 @@ void LLViewerObjectList::updateObjectCost(LLUUID object_id, F32 object_cost, F32
 	}
 }
 
-void LLViewerObjectList::onObjectCostFetchFailure(LLUUID object_id)
+void LLViewerObjectList::onObjectCostFetchFailure(const LLUUID& object_id)
 {
+	llwarns << "Failed to fetch object cost for object: " << object_id << llendl;
 	mPendingObjectCost.erase(object_id);
 }
 
+void LLViewerObjectList::updatePhysicsFlags(const LLViewerObject* object)
+{
+	mStalePhysicsFlags.insert(object->getID());
+}
+
+void LLViewerObjectList::updatePhysicsShapeType(const LLUUID& object_id, S32 type)
+{
+	mPendingPhysicsFlags.erase(object_id);
+	LLViewerObject* object = findObject(object_id);
+	if (object)
+	{
+		object->setPhysicsShapeType(type);
+	}
+}
+
+void LLViewerObjectList::updatePhysicsProperties(const LLUUID& object_id, 
+												F32 density,
+												F32 friction,
+												F32 restitution,
+												F32 gravity_multiplier)
+{
+	mPendingPhysicsFlags.erase(object_id);
+
+	LLViewerObject* object = findObject(object_id);
+	if (object)
+	{
+		object->setPhysicsDensity(density);
+		object->setPhysicsFriction(friction);
+		object->setPhysicsGravity(gravity_multiplier);
+		object->setPhysicsRestitution(restitution);
+	}
+}
+
+void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id)
+{
+	llwarns << "Failed to fetch physics flags for object: " << object_id << llendl;
+	mPendingPhysicsFlags.erase(object_id);
+}
+
 void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 {
 	// This is called when we shift our origin when we cross region boundaries...
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 2881ba6f8ff39a173ff3e8b039e443d10eea53b1..64034091d322385dc11ea2e4a703622b004ad963 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -85,9 +85,21 @@ class LLViewerObjectList
 	void updateApparentAngles(LLAgent &agent);
 	void update(LLAgent &agent, LLWorld &world);
 
+	void fetchObjectCosts();
+	void fetchPhysicsFlags();
+
 	void updateObjectCost(LLViewerObject* object);
-	void updateObjectCost(LLUUID object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost);
-	void onObjectCostFetchFailure(LLUUID object_id);
+	void updateObjectCost(const LLUUID& object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost);
+	void onObjectCostFetchFailure(const LLUUID& object_id);
+
+	void updatePhysicsFlags(const LLViewerObject* object);
+	void onPhysicsFlagsFetchFailure(const LLUUID& object_id);
+	void updatePhysicsShapeType(const LLUUID& object_id, S32 type);
+	void updatePhysicsProperties(const LLUUID& object_id,
+									F32 density,
+									F32 friction,
+									F32 restitution,
+									F32 gravity_multiplier);
 
 	void shiftObjects(const LLVector3 &offset);
 
@@ -194,6 +206,10 @@ class LLViewerObjectList
 	std::set<LLUUID> mStaleObjectCost;
 	std::set<LLUUID> mPendingObjectCost;
 
+	//set of objects that need to update their physics flags
+	std::set<LLUUID> mStalePhysicsFlags;
+	std::set<LLUUID> mPendingPhysicsFlags;
+
 	std::vector<LLDebugBeacon> mDebugBeacons;
 
 	S32 mCurLazyUpdateIndex;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 22a17d5b7e41ed4341a18b802925d00ee7e0c938..6deaca3819c0f3a2e4f19934630f625f86cd0c57 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1383,6 +1383,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("GetTexture");
 	capabilityNames.append("GetMesh");
 	capabilityNames.append("GetObjectCost");
+	capabilityNames.append("GetObjectPhysicsData");
 	capabilityNames.append("GroupProposalBallot");
 	capabilityNames.append("HomeLocation");
 	capabilityNames.append("LandResources");