From d8dc74b83349752768d99b77c92a284955ee04e4 Mon Sep 17 00:00:00 2001
From: simon <none@none>
Date: Thu, 28 Mar 2013 16:06:07 -0700
Subject: [PATCH] MAINT-2426 : Viewer support for new simulator
 AvatarRenderInfo capability.  Reviewed by Kelly

---
 indra/newview/CMakeLists.txt                  |   2 +
 indra/newview/llappviewer.cpp                 |   4 +
 .../newview/llavatarrenderinfoaccountant.cpp  | 360 ++++++++++++++++++
 indra/newview/llavatarrenderinfoaccountant.h  |  54 +++
 indra/newview/llspatialpartition.cpp          |   2 +
 indra/newview/llviewerregion.cpp              |   5 +
 indra/newview/llviewerregion.h                |   4 +
 indra/newview/llvoavatar.cpp                  |   3 +
 indra/newview/llvoavatar.h                    |  23 +-
 indra/newview/llvovolume.cpp                  |   2 +
 10 files changed, 455 insertions(+), 4 deletions(-)
 create mode 100644 indra/newview/llavatarrenderinfoaccountant.cpp
 create mode 100644 indra/newview/llavatarrenderinfoaccountant.h

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index bd0169fb2fd..cb96dfeb48d 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -113,6 +113,7 @@ set(viewer_SOURCE_FILES
     llavatariconctrl.cpp
     llavatarlist.cpp
     llavatarlistitem.cpp
+    llavatarrenderinfoaccountant.cpp
     llavatarpropertiesprocessor.cpp
     llblockedlistitem.cpp
     llblocklist.cpp
@@ -702,6 +703,7 @@ set(viewer_HEADER_FILES
     llavatarlist.h
     llavatarlistitem.h
     llavatarpropertiesprocessor.h
+    llavatarrenderinfoaccountant.h
     llblockedlistitem.h
     llblocklist.h
     llbox.h
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 4745157c8b0..7404d2d228f 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -97,6 +97,7 @@
 #include "llupdaterservice.h"
 #include "llfloatertexturefetchdebugger.h"
 #include "llspellcheck.h"
+#include "llavatarrenderinfoaccountant.h"
 
 // Linden library includes
 #include "llavatarnamecache.h"
@@ -4587,6 +4588,9 @@ void LLAppViewer::idle()
 		gObjectList.updateApparentAngles(gAgent);
 	}
 
+	// Update AV render info
+	LLAvatarRenderInfoAccountant::idle();
+
 	{
 		LLFastTimer t(FTM_AUDIO_UPDATE);
 		
diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp
new file mode 100644
index 00000000000..04a79f7d4c0
--- /dev/null
+++ b/indra/newview/llavatarrenderinfoaccountant.cpp
@@ -0,0 +1,360 @@
+/**
+ * @file   llavatarrenderinfoaccountant.cpp
+ * @author Dave Simmons
+ * @date   2013-02-28
+ * @brief  
+ * 
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "llviewerprecompiledheaders.h"
+// associated header
+#include "llavatarrenderinfoaccountant.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llcharacter.h"
+#include "llhttpclient.h"
+#include "lltimer.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llvoavatar.h"
+#include "llworld.h"
+
+
+// Use this for debugging
+//#define LL_AVATAR_RENDER_INFO_LOG_SPAM
+
+static	const std::string KEY_AGENTS = "agents";			// map
+static 	const std::string KEY_WEIGHT = "weight";			// integer
+static	const std::string KEY_GEOMETRY = "geometry";		// integer
+static	const std::string KEY_SURFACE =	"surface";			// float
+
+static	const std::string KEY_IDENTIFIER = "identifier";
+static	const std::string KEY_MESSAGE = "message";
+static	const std::string KEY_ERROR = "error";
+
+
+// Send data updates about once per minute, only need per-frame resolution
+LLFrameTimer LLAvatarRenderInfoAccountant::sRenderInfoReportTimer;
+
+
+// HTTP responder class for GET request for avatar render weight information
+class LLAvatarRenderInfoGetResponder : public LLHTTPClient::Responder
+{
+public:
+	LLAvatarRenderInfoGetResponder(U64 region_handle) : mRegionHandle(region_handle)
+	{
+	}
+
+	virtual void error(U32 statusNum, const std::string& reason)
+	{
+		LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
+		if (regionp)
+		{
+			llwarns << "HTTP error result for avatar weight GET: " << statusNum 
+				<< ", " << reason
+				<< " returned by region " << regionp->getName()
+				<< llendl;
+		}
+		else
+		{
+			llwarns << "Avatar render weight GET error recieved but region not found for " 
+				<< mRegionHandle 
+				<< ", error " << statusNum 
+				<< ", " << reason
+				<< llendl;
+		}
+
+	}
+
+	virtual void result(const LLSD& content)
+	{
+		LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
+		if (regionp)
+		{
+			#ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM
+			llinfos << "Result for avatar weights request for region " << regionp->getName() << ":" << llendl;
+			#endif // LL_AVATAR_RENDER_INFO_LOG_SPAM
+
+			if (content.isMap())
+			{
+				if (content.has(KEY_AGENTS))
+				{
+					const LLSD & agents = content[KEY_AGENTS];
+					if (agents.isMap())
+					{
+						LLSD::map_const_iterator	report_iter = agents.beginMap();
+						while (report_iter != agents.endMap())
+						{
+							LLUUID target_agent_id = LLUUID(report_iter->first);
+							const LLSD & agent_info_map = report_iter->second;
+							LLViewerObject* avatarp = gObjectList.findObject(target_agent_id);
+							if (avatarp && 
+								avatarp->isAvatar() &&
+								agent_info_map.isMap())
+							{	// Extract the data for this avatar
+
+								#ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM
+								llinfos << " Agent " << target_agent_id 
+									<< ": " << agent_info_map << llendl;
+								#endif	// LL_AVATAR_RENDER_INFO_LOG_SPAM
+
+								if (agent_info_map.has(KEY_WEIGHT))
+								{
+									((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger());
+								}
+								if (agent_info_map.has(KEY_GEOMETRY))
+								{
+									((LLVOAvatar *) avatarp)->setReportedAttachmentGeometryBytes(agent_info_map[KEY_GEOMETRY].asInteger());
+								}
+								if (agent_info_map.has(KEY_SURFACE))
+								{
+									((LLVOAvatar *) avatarp)->setReportedAttachmentSurfaceArea((F32) agent_info_map[KEY_SURFACE].asReal());
+								}
+							}
+							report_iter++;
+						}
+					}
+				}	// has "agents"
+				else if (content.has(KEY_ERROR))
+				{
+					const LLSD & error = content[KEY_ERROR];
+					llwarns << "Avatar render info GET error: "
+						<< error[KEY_IDENTIFIER]
+						<< ": " << error[KEY_MESSAGE] 
+						<< " from region " << regionp->getName()
+						<< llendl;
+				}
+			}
+		}
+		else
+		{
+			llinfos << "Avatar render weight info recieved but region not found for " 
+				<< mRegionHandle << llendl;
+		}
+	}
+
+private:
+	U64		mRegionHandle;
+};
+
+
+// HTTP responder class for POST request for avatar render weight information
+class LLAvatarRenderInfoPostResponder : public LLHTTPClient::Responder
+{
+public:
+	LLAvatarRenderInfoPostResponder(U64 region_handle) : mRegionHandle(region_handle)
+	{
+	}
+
+	virtual void error(U32 statusNum, const std::string& reason)
+	{
+		LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
+		if (regionp)
+		{
+			llwarns << "HTTP error result for avatar weight POST: " << statusNum 
+				<< ", " << reason
+				<< " returned by region " << regionp->getName()
+				<< llendl;
+		}
+		else
+		{
+			llwarns << "Avatar render weight POST error recieved but region not found for " 
+				<< mRegionHandle 
+				<< ", error " << statusNum 
+				<< ", " << reason
+				<< llendl;
+		}
+	}
+
+	virtual void result(const LLSD& content)
+	{
+		LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
+		if (regionp)
+		{
+			#ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM
+			llinfos << "Result for avatar weights POST for region " << regionp->getName()
+				<< ": " << content << llendl;
+			#endif	// LL_AVATAR_RENDER_INFO_LOG_SPAM
+
+			if (content.isMap())
+			{
+				if (content.has(KEY_ERROR))
+				{
+					const LLSD & error = content[KEY_ERROR];
+					llwarns << "Avatar render info POST error: "
+						<< error[KEY_IDENTIFIER]
+						<< ": " << error[KEY_MESSAGE] 
+						<< " from region " << regionp->getName()
+						<< llendl;
+				}
+			}
+		}
+		else
+		{
+			llinfos << "Avatar render weight POST result recieved but region not found for " 
+				<< mRegionHandle << llendl;
+		}
+	}
+
+private:
+	U64		mRegionHandle;
+};
+
+
+// static 
+// Send request for one region, no timer checks
+void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regionp)
+{
+	std::string url = regionp->getCapability("AvatarRenderInfo");
+	if (!url.empty())
+	{
+		#ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM
+		llinfos << "Sending avatar render info to region "
+			<< regionp->getName() 
+			<< " from " << url
+			<< llendl;
+		#endif	// LL_AVATAR_RENDER_INFO_LOG_SPAM
+
+		// Build the render info to POST to the region
+		LLSD report = LLSD::emptyMap();
+		LLSD agents = LLSD::emptyMap();
+				
+		std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+		while( iter != LLCharacter::sInstances.end() )
+		{
+			LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*iter);
+			if (avatar &&
+				avatar->getRezzedStatus() == 2 &&					// Fully rezzed
+				!avatar->isDead() &&								// Not dead yet
+				avatar->getObjectHost() == regionp->getHost())		// Ensure it's on the same region
+			{
+				avatar->calculateUpdateRenderCost();			// Make sure the numbers are up-to-date
+
+				LLSD info = LLSD::emptyMap();
+				if (avatar->getVisualComplexity() > 0)
+				{
+					info[KEY_WEIGHT] = avatar->getVisualComplexity();
+				}
+				if (avatar->getAttachmentGeometryBytes() > 0)
+				{
+					info[KEY_GEOMETRY] = (S32) avatar->getAttachmentGeometryBytes();
+				}
+				if (avatar->getAttachmentSurfaceArea() > 0.f)
+				{
+					info[KEY_SURFACE] = avatar->getAttachmentSurfaceArea();
+				}
+				if (info.size() > 0)
+				{
+					agents[avatar->getID().asString()] = info;
+				}
+
+				#ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM
+				llinfos << "Sending avatar render info for " << avatar->getID()
+					<< ": " << info << llendl;
+				#endif		// LL_AVATAR_RENDER_INFO_LOG_SPAM
+			}
+			iter++;
+		}
+
+		report[KEY_AGENTS] = agents;
+		if (agents.size() > 0)
+		{
+			LLHTTPClient::post(url, report, new LLAvatarRenderInfoPostResponder(regionp->getHandle()));
+		}
+	}
+}
+
+
+
+
+// static 
+// Send request for one region, no timer checks
+void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regionp)
+{
+	std::string url = regionp->getCapability("AvatarRenderInfo");
+	if (!url.empty())
+	{
+		#ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM
+		llinfos << "Requesting avatar render info for region "
+			<< regionp->getName() 
+			<< " from " << url
+			<< llendl;
+		#endif	// LL_AVATAR_RENDER_INFO_LOG_SPAM
+
+		// First send a request to get the latest data
+		LLHTTPClient::get(url, new LLAvatarRenderInfoGetResponder(regionp->getHandle()));
+	}
+}
+
+
+// static
+// Called every frame - send render weight requests to every region
+void LLAvatarRenderInfoAccountant::idle()
+{
+	if (sRenderInfoReportTimer.hasExpired())
+	{
+		const F32 SECS_BETWEEN_REGION_SCANS   =  5.f;		// Scan the region list every 5 seconds
+		const F32 SECS_BETWEEN_REGION_REQUEST = 60.0;		// Update each region every 60 seconds
+	
+		S32 num_avs = LLCharacter::sInstances.size();
+
+		// Check all regions and see if it's time to fetch/send data
+		for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+				iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+		{
+			LLViewerRegion* regionp = *iter;
+			if (regionp &&
+				regionp->isAlive() &&
+				regionp->capabilitiesReceived() &&						// Region has capability URLs available
+				regionp->getRenderInfoRequestTimer().hasExpired())		// Time to make request
+			{
+				sendRenderInfoToRegion(regionp);
+				getRenderInfoFromRegion(regionp);
+
+				// Reset this regions timer, moving to longer intervals if there are lots of avatars around
+				regionp->getRenderInfoRequestTimer().resetWithExpiry(SECS_BETWEEN_REGION_REQUEST + (2.f * num_avs));
+			}
+		}
+
+		// We scanned all the regions, reset the request timer.
+		sRenderInfoReportTimer.resetWithExpiry(SECS_BETWEEN_REGION_SCANS);
+	}
+}
+
+
+// static
+// Make sRenderInfoReportTimer expire so the next call to idle() will scan and query a new region
+// called via LLViewerRegion::setCapabilitiesReceived() boost signals when the capabilities
+// are returned for a new LLViewerRegion, and is the earliest time to get render info
+void LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer()
+{
+	#ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM
+	llinfos << "Viewer has new region capabilities" << llendl;
+	#endif		// LL_AVATAR_RENDER_INFO_LOG_SPAM
+
+	sRenderInfoReportTimer.resetWithExpiry(0.f);
+}
+
diff --git a/indra/newview/llavatarrenderinfoaccountant.h b/indra/newview/llavatarrenderinfoaccountant.h
new file mode 100644
index 00000000000..5b4a4d3db28
--- /dev/null
+++ b/indra/newview/llavatarrenderinfoaccountant.h
@@ -0,0 +1,54 @@
+/**
+ * @file   llavatarrenderinfoaccountant.h
+ * @author Dave Simmons
+ * @date   2013-02-28
+ * @brief  
+ * 
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_llavatarrenderinfoaccountant_H)
+#define LL_llavatarrenderinfoaccountant_H
+
+class LLViewerRegion;
+
+// Class to gather avatar rendering information 
+// that is sent to or fetched from regions.
+class LLAvatarRenderInfoAccountant
+{
+public:
+	LLAvatarRenderInfoAccountant()	{};
+	~LLAvatarRenderInfoAccountant()	{};
+
+	static void sendRenderInfoToRegion(LLViewerRegion * regionp);
+	static void getRenderInfoFromRegion(LLViewerRegion * regionp);
+
+	static void expireRenderInfoReportTimer();
+
+    static void idle();
+
+private:
+	// Send data updates about once per minute, only need per-frame resolution
+	static LLFrameTimer sRenderInfoReportTimer;
+};
+
+#endif /* ! defined(LL_llavatarrenderinfoaccountant_H) */
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 759e1a7b4cb..1d30b19308b 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -1404,7 +1404,9 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 		if (bridge->mAvatar.notNull())
 		{
 			bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes;
+			bridge->mAvatar->mAttachmentGeometryBytes = llmax(bridge->mAvatar->mAttachmentGeometryBytes, 0);
 			bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea;
+			bridge->mAvatar->mAttachmentSurfaceArea = llmax(bridge->mAvatar->mAttachmentSurfaceArea, 0.f);
 		}
 	}
 
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index e4234a538d1..eb5a0b8d379 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -44,6 +44,7 @@
 
 #include "llagent.h"
 #include "llagentcamera.h"
+#include "llavatarrenderinfoaccountant.h"
 #include "llcallingcard.h"
 #include "llcaphttpsender.h"
 #include "llcapabilitylistener.h"
@@ -333,6 +334,9 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mImpl->mObjectPartition.push_back(new LLBridgePartition());	//PARTITION_BRIDGE
 	mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE
 	mImpl->mObjectPartition.push_back(NULL);						//PARTITION_NONE
+
+	mRenderInfoRequestTimer.resetWithExpiry(0.f);		// Set timer to be expired
+	setCapabilitiesReceivedCallback(boost::bind(&LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer));
 }
 
 
@@ -1514,6 +1518,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("AgentState");
 	capabilityNames.append("AttachmentResources");
 	capabilityNames.append("AvatarPickerSearch");
+	capabilityNames.append("AvatarRenderInfo");
 	capabilityNames.append("CharacterProperties");
 	capabilityNames.append("ChatSessionRequest");
 	capabilityNames.append("CopyInventoryFromNotecard");
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index c9fffaf30e4..2d3a622e421 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -365,6 +365,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	LLDynamicArray<U32> mMapAvatars;
 	LLDynamicArray<LLUUID> mMapAvatarIDs;
 
+	LLFrameTimer &	getRenderInfoRequestTimer()			{ return mRenderInfoRequestTimer;		};
+
 private:
 	LLViewerRegionImpl * mImpl;
 
@@ -421,6 +423,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	BOOL mReleaseNotesRequested;
 	
 	LLSD mSimulatorFeatures;
+
+	LLFrameTimer	mRenderInfoRequestTimer;
 };
 
 inline BOOL LLViewerRegion::getAllowDamage() const
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 9e5d44eb1f9..1fc20fd2078 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -662,6 +662,9 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mSpecialRenderMode(0),
 	mAttachmentGeometryBytes(0),
 	mAttachmentSurfaceArea(0.f),
+	mReportedVisualComplexity(-1),
+	mReportedAttachmentGeometryBytes(-1),
+	mReportedAttachmentSurfaceArea(-1.f),
 	mTurning(FALSE),
 	mPelvisToFoot(0.f),
 	mLastSkeletonSerialNum( 0 ),
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 0e7bf7a6c9e..495d3e94830 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -257,9 +257,20 @@ class LLVOAvatar :
 	void			calculateUpdateRenderCost();
 	void			updateVisualComplexity() { mVisualComplexityStale = TRUE; }
 	
-	S32				getVisualComplexity()		{ return mVisualComplexity;		};
-	S32				getUpdatePeriod()			{ return mUpdatePeriod;			};
-	const LLColor4 &  getMutedAVColor()			{ return mMutedAVColor;			};
+	S32				getVisualComplexity()			{ return mVisualComplexity;				};		// Numbers calculated here by rendering AV
+	S32				getAttachmentGeometryBytes()	{ return mAttachmentGeometryBytes;		};		// number of bytes in attached geometry
+	F32				getAttachmentSurfaceArea()		{ return mAttachmentSurfaceArea;		};		// estimated surface area of attachments
+
+	S32				getReportedVisualComplexity()					{ return mReportedVisualComplexity;				};	// Numbers as reported by the SL server
+	void			setReportedVisualComplexity(S32 value)			{ mReportedVisualComplexity = value;			};
+	S32				getReportedAttachmentGeometryBytes()			{ return mReportedAttachmentGeometryBytes;		};	//number of bytes in attached geometry
+	void			setReportedAttachmentGeometryBytes(S32 value)	{ mReportedAttachmentGeometryBytes = value;		};
+	F32				getReportedAttachmentSurfaceArea()		{ return mReportedAttachmentSurfaceArea;				};		//estimated surface area of attachments
+	void			setReportedAttachmentSurfaceArea(F32 value)		{ mReportedAttachmentSurfaceArea = value;		};
+	
+	S32				getUpdatePeriod()				{ return mUpdatePeriod;			};
+	const LLColor4 &  getMutedAVColor()				{ return mMutedAVColor;			};
+
 
 	void 			idleUpdateBelowWater();
 
@@ -469,9 +480,13 @@ class LLVOAvatar :
 	static void	restoreGL();
 	BOOL 		mIsDummy; // for special views
 	S32			mSpecialRenderMode; // special lighting
-	U32			mAttachmentGeometryBytes; //number of bytes in attached geometry
+	S32			mAttachmentGeometryBytes; //number of bytes in attached geometry
 	F32			mAttachmentSurfaceArea; //estimated surface area of attachments
 
+	S32			mReportedVisualComplexity;			// Numbers as reported by the SL server
+	S32			mReportedAttachmentGeometryBytes;	//number of bytes in attached geometry
+	F32			mReportedAttachmentSurfaceArea;		//estimated surface area of attachments
+
 private:
 	bool		shouldAlphaMask();
 
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 426ad8bc21f..71ee2da2160 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -4242,7 +4242,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	if (pAvatarVO)
 	{
 		pAvatarVO->mAttachmentGeometryBytes -= group->mGeometryBytes;
+		pAvatarVO->mAttachmentGeometryBytes = llmax(pAvatarVO->mAttachmentGeometryBytes, 0);
 		pAvatarVO->mAttachmentSurfaceArea -= group->mSurfaceArea;
+		pAvatarVO->mAttachmentSurfaceArea = llmax(pAvatarVO->mAttachmentSurfaceArea, 0.f);
 	}
 
 	group->mGeometryBytes = 0;
-- 
GitLab