summaryrefslogtreecommitdiff
path: root/indra/newview/llvoavatar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llvoavatar.cpp')
-rwxr-xr-xindra/newview/llvoavatar.cpp564
1 files changed, 340 insertions, 224 deletions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index b97a1bde99..af87f064e9 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -43,6 +43,7 @@
#include "llanimationstates.h"
#include "llavatarnamecache.h"
#include "llavatarpropertiesprocessor.h"
+#include "llavatarrendernotifier.h"
#include "llexperiencecache.h"
#include "llphysicsmotion.h"
#include "llviewercontrol.h"
@@ -115,8 +116,6 @@ extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG;
const F32 MAX_HOVER_Z = 2.0;
const F32 MIN_HOVER_Z = -2.0;
-// #define OUTPUT_BREAST_DATA
-
using namespace LLAvatarAppearanceDefines;
//-----------------------------------------------------------------------------
@@ -186,6 +185,8 @@ const F32 NAMETAG_UPDATE_THRESHOLD = 0.3f;
const F32 NAMETAG_VERTICAL_SCREEN_OFFSET = 25.f;
const F32 NAMETAG_VERT_OFFSET_WEIGHT = 0.17f;
+const U32 LLVOAvatar::VISUAL_COMPLEXITY_UNKNOWN = 0;
+
enum ERenderName
{
RENDER_NAME_NEVER,
@@ -622,7 +623,7 @@ private:
//-----------------------------------------------------------------------------
LLAvatarAppearanceDictionary *LLVOAvatar::sAvatarDictionary = NULL;
S32 LLVOAvatar::sFreezeCounter = 0;
-U32 LLVOAvatar::sMaxVisible = 12;
+U32 LLVOAvatar::sMaxNonImpostors = 12; // overridden based on graphics setting
F32 LLVOAvatar::sRenderDistance = 256.f;
S32 LLVOAvatar::sNumVisibleAvatars = 0;
S32 LLVOAvatar::sNumLODChangesThisFrame = 0;
@@ -649,7 +650,7 @@ BOOL LLVOAvatar::sShowFootPlane = FALSE;
BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE;
F32 LLVOAvatar::sLODFactor = 1.f;
F32 LLVOAvatar::sPhysicsLODFactor = 1.f;
-BOOL LLVOAvatar::sUseImpostors = FALSE;
+bool LLVOAvatar::sUseImpostors = false; // overwridden by RenderAvatarMaxNonImpostors
BOOL LLVOAvatar::sJointDebug = FALSE;
F32 LLVOAvatar::sUnbakedTime = 0.f;
F32 LLVOAvatar::sUnbakedUpdateTime = 0.f;
@@ -670,9 +671,9 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
LLAvatarAppearance(&gAgentWearables),
LLViewerObject(id, pcode, regionp),
mSpecialRenderMode(0),
- mAttachmentGeometryBytes(-1),
- mAttachmentSurfaceArea(-1.f),
- mReportedVisualComplexity(-1),
+ mAttachmentGeometryBytes(0),
+ mAttachmentSurfaceArea(0.f),
+ mReportedVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
mTurning(FALSE),
mLastSkeletonSerialNum( 0 ),
mIsSitting(FALSE),
@@ -702,22 +703,24 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mNeedsSkin(FALSE),
mLastSkinTime(0.f),
mUpdatePeriod(1),
+ mVisualComplexityStale(true),
+ mVisuallyMuteSetting(AV_RENDER_NORMALLY),
+ mMutedAVColor(LLColor4::white /* used for "uninitialize" */),
mFirstFullyVisible(TRUE),
mFullyLoaded(FALSE),
mPreviousFullyLoaded(FALSE),
mFullyLoadedInitialized(FALSE),
- mVisualComplexity(0),
- mVisualComplexityStale(TRUE),
+ mVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
mLoadedCallbacksPaused(FALSE),
mRenderUnloadedAvatar(LLCachedControl<bool>(gSavedSettings, "RenderUnloadedAvatar", false)),
mLastRezzedStatus(-1),
mIsEditingAppearance(FALSE),
mUseLocalAppearance(FALSE),
mLastUpdateRequestCOFVersion(-1),
- mLastUpdateReceivedCOFVersion(-1),
- mCachedMuteListUpdateTime(0),
- mCachedInMuteList(false)
+ mLastUpdateReceivedCOFVersion(-1)
{
+ LL_DEBUGS("AvatarRender") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;
+
//VTResume(); // VTune
setHoverOffset(LLVector3(0.0, 0.0, 0.0));
@@ -726,7 +729,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim );
LL_DEBUGS("Avatar","Message") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;
-
mPelvisp = NULL;
mDirtyMesh = 2; // Dirty geometry, need to regenerate.
@@ -775,17 +777,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mDebugExistenceTimer.reset();
mLastAppearanceMessageTimer.reset();
- if(LLSceneMonitor::getInstance()->isEnabled())
+ if(LLSceneMonitor::getInstance()->isEnabled())
{
- LLSceneMonitor::getInstance()->freezeAvatar((LLCharacter*)this);
+ LLSceneMonitor::getInstance()->freezeAvatar((LLCharacter*)this);
}
-
- mCachedVisualMute = !isSelf();
- mCachedVisualMuteUpdateTime = LLFrameTimer::getTotalSeconds() + 5.0;
- mVisuallyMuteSetting = VISUAL_MUTE_NOT_SET;
-
- F32 color_value = (F32) (getID().mData[0]);
- mMutedAVColor = calcMutedAVColor(color_value, 0, 256);
}
std::string LLVOAvatar::avString() const
@@ -993,8 +988,8 @@ std::string LLVOAvatar::rezStatusToString(S32 rez_status)
{
if (rez_status==0) return "cloud";
if (rez_status==1) return "gray";
- if (rez_status==2) return "textured";
- if (rez_status==3) return "textured_and_downloaded";
+ if (rez_status==2) return "downloading";
+ if (rez_status==3) return "full";
return "unknown";
}
@@ -2154,7 +2149,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
}
idleUpdateNameTag( mLastRootPos );
- idleUpdateRenderCost();
+ idleUpdateRenderComplexity();
}
void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
@@ -2494,19 +2489,22 @@ void LLVOAvatar::idleUpdateLoadingEffect()
// update visibility when avatar is partially loaded
if (updateIsFullyLoaded()) // changed?
{
- if (isFullyLoaded() && mFirstFullyVisible && isSelf())
- {
- LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL;
- mFirstFullyVisible = FALSE;
- LLAppearanceMgr::instance().onFirstFullyVisible();
- }
- if (isFullyLoaded() && mFirstFullyVisible && !isSelf())
- {
- LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL;
- mFirstFullyVisible = FALSE;
- }
if (isFullyLoaded())
{
+ if (mFirstFullyVisible)
+ {
+ mFirstFullyVisible = FALSE;
+ if (isSelf())
+ {
+ LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL;
+ LLAppearanceMgr::instance().onFirstFullyVisible();
+ }
+ else
+ {
+ LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL;
+ }
+ }
+
deleteParticleSource();
updateLOD();
}
@@ -3085,108 +3083,35 @@ void LLVOAvatar::slamPosition()
mRoot->updateWorldMatrixChildren();
}
-bool LLVOAvatar::isVisuallyMuted()
+bool LLVOAvatar::isVisuallyMuted() const
{
bool muted = false;
+ // Priority order (highest priority first)
+ // * own avatar is never visually muted
+ // * if on the "always draw normally" list, draw them normally
+ // * if on the "always visually mute" list, mute them
+ // * check against the render cost and attachment limits
if (!isSelf())
{
- static LLCachedControl<U32> render_auto_mute_functions(gSavedSettings, "RenderAutoMuteFunctions", 0);
- if (render_auto_mute_functions) // Hacky debug switch for developing feature
+ if (mVisuallyMuteSetting == AV_ALWAYS_RENDER)
{
- // Priority order (highest priority first)
- // * own avatar is never visually muted
- // * if on the "always draw normally" list, draw them normally
- // * if on the "always visually mute" list, mute them
- // * draw them normally if they meet the following criteria:
- // - within the closest N avatars OR on friends list OR in an IM chat
- // - AND aren't over the thresholds
- // * otherwise visually mute all other avatars
-
- static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit", 0);
- static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 0.0);
- static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderWeightLimit", 0);
-
- if (mVisuallyMuteSetting == ALWAYS_VISUAL_MUTE)
- { // Always want to see this AV as an impostor
- muted = true;
- }
- else if (mVisuallyMuteSetting == NEVER_VISUAL_MUTE)
- { // Never show as impostor
- muted = false;
- }
- else
- {
- F64 now = LLFrameTimer::getTotalSeconds();
-
- if (now < mCachedVisualMuteUpdateTime)
- { // Use cached mute value
- muted = mCachedVisualMute;
- }
- else
- { // Determine if visually muted or not
-
- U32 max_cost = (U32) (max_render_cost*(LLVOAvatar::sLODFactor+0.5));
-
- muted = (mAttachmentGeometryBytes > max_attachment_bytes && max_attachment_bytes > 0) ||
- (mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f) ||
- (mVisualComplexity > max_cost && max_render_cost > 0);
-
- // Could be part of the grand || collection above, but yanked out to make the logic visible
- if (!muted)
- {
- if (sMaxVisible > 0)
- { // They are above the visibilty rank - mute them
- muted = (mVisibilityRank > sMaxVisible);
- }
-
- // Always draw friends or those in IMs. Needs UI?
- if ((render_auto_mute_functions & 0x02) &&
- (muted || sMaxVisible == 0)) // Don't mute friends or IMs
- {
- muted = !(LLAvatarTracker::instance().isBuddy(getID()));
- if (muted)
- { // Not a friend, so they are muted ... are they in an IM?
- LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL,getID());
- muted = !gIMMgr->hasSession(session_id);
- }
- }
- }
-
- // Save visual mute state and set interval for updating
- const F64 SECONDS_BETWEEN_RENDER_AUTO_MUTE_UPDATES = 1.5;
- mCachedVisualMuteUpdateTime = now + SECONDS_BETWEEN_RENDER_AUTO_MUTE_UPDATES;
- mCachedVisualMute = muted;
- }
- }
+ muted = false;
+ }
+ else if (mVisuallyMuteSetting == AV_DO_NOT_RENDER)
+ { // Always want to see this AV as an impostor
+ muted = true;
+ }
+ else if (LLMuteList::getInstance()->isMuted(getID()))
+ {
+ muted = true;
+ }
+ else
+ {
+ muted = isTooComplex();
}
}
- return muted || isInMuteList();
-}
-
-void LLVOAvatar::forceUpdateVisualMuteSettings()
-{
- // Set the cache time so it's updated ASAP
- mCachedVisualMuteUpdateTime = LLFrameTimer::getTotalSeconds() - 1.0;
-}
-
-bool LLVOAvatar::isInMuteList()
-{
- bool muted = false;
- F64 now = LLFrameTimer::getTotalSeconds();
- if (now < mCachedMuteListUpdateTime)
- {
- muted = mCachedInMuteList;
- }
- else
- {
- muted = LLMuteList::getInstance()->isMuted(getID());
-
- const F64 SECONDS_BETWEEN_MUTE_UPDATES = 1;
- mCachedMuteListUpdateTime = now + SECONDS_BETWEEN_MUTE_UPDATES;
- mCachedInMuteList = muted;
- }
return muted;
}
@@ -3333,18 +3258,18 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
{ // visually muted avatars update at 16 hz
mUpdatePeriod = 16;
}
- else if (mVisibilityRank <= LLVOAvatar::sMaxVisible ||
- mDrawable->mDistanceWRTCamera < 1.f + mag)
- { //first 25% of max visible avatars are not impostored
- //also, don't impostor avatars whose bounding box may be penetrating the
- //impostor camera near clip plane
+ else if ( ! shouldImpostor()
+ || mDrawable->mDistanceWRTCamera < 1.f + mag)
+ { // first 25% of max visible avatars are not impostored
+ // also, don't impostor avatars whose bounding box may be penetrating the
+ // impostor camera near clip plane
mUpdatePeriod = 1;
}
- else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4)
+ else if ( shouldImpostor(4) )
{ //background avatars are REALLY slow updating impostors
mUpdatePeriod = 16;
}
- else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 3)
+ else if ( shouldImpostor(3) )
{ //back 25% of max visible avatars are slow updating impostors
mUpdatePeriod = 8;
}
@@ -3928,6 +3853,10 @@ void LLVOAvatar::updateVisibility()
}
}
+ if ( visible != mVisible )
+ {
+ LL_DEBUGS("AvatarRender") << "visible was " << mVisible << " now " << visible << LL_ENDL;
+ }
mVisible = visible;
}
@@ -4200,8 +4129,8 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
}
// Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair)
// TODO: 1.25 will be able to switch this logic back to calling isTextureVisible();
- if ( ( getImage(TEX_HAIR_BAKED, 0) &&
- getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE ) || LLDrawPoolAlpha::sShowDebugAlpha)
+ if ( (getImage(TEX_HAIR_BAKED, 0) && getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE)
+ || LLDrawPoolAlpha::sShowDebugAlpha)
{
LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
if (hair_mesh)
@@ -5838,7 +5767,7 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o
return 0;
}
- mVisualComplexityStale = TRUE;
+ updateVisualComplexity();
if (viewer_object->isSelected())
{
@@ -5994,7 +5923,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
if (attachment->isObjectAttached(viewer_object))
{
- mVisualComplexityStale = TRUE;
+ updateVisualComplexity();
cleanupAttachedMesh( viewer_object );
attachment->removeObject(viewer_object);
@@ -6296,32 +6225,20 @@ BOOL LLVOAvatar::isVisible() const
}
// Determine if we have enough avatar data to render
-BOOL LLVOAvatar::getIsCloud() const
+bool LLVOAvatar::getIsCloud() const
{
- // Do we have a shape?
- if ((const_cast<LLVOAvatar*>(this))->visualParamWeightsAreDefault())
- {
- return TRUE;
- }
-
- if (!isTextureDefined(TEX_LOWER_BAKED) ||
- !isTextureDefined(TEX_UPPER_BAKED) ||
- !isTextureDefined(TEX_HEAD_BAKED))
- {
- return TRUE;
- }
-
- if (isTooComplex())
- {
- return TRUE;
- }
- return FALSE;
+ return ( ((const_cast<LLVOAvatar*>(this))->visualParamWeightsAreDefault())// Do we have a shape?
+ || ( !isTextureDefined(TEX_LOWER_BAKED)
+ || !isTextureDefined(TEX_UPPER_BAKED)
+ || !isTextureDefined(TEX_HEAD_BAKED)
+ )
+ );
}
void LLVOAvatar::updateRezzedStatusTimers()
{
// State machine for rezzed status. Statuses are -1 on startup, 0
- // = cloud, 1 = gray, 2 = textured, 3 = textured_and_downloaded.
+ // = cloud, 1 = gray, 2 = downloading, 3 = full.
// Purpose is to collect time data for each it takes avatar to reach
// various loading landmarks: gray, textured (partial), textured fully.
@@ -6361,6 +6278,8 @@ void LLVOAvatar::updateRezzedStatusTimers()
selfStopPhase("update_appearance_from_cof");
selfStopPhase("wear_inventory_category", false);
selfStopPhase("process_initial_wearables_update", false);
+
+ updateVisualComplexity();
}
}
mLastRezzedStatus = rez_status;
@@ -6493,7 +6412,7 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse
// returns true if the value has changed.
BOOL LLVOAvatar::updateIsFullyLoaded()
{
- const BOOL loading = getIsCloud();
+ const bool loading = getIsCloud();
updateRezzedStatusTimers();
updateRuthTimer(loading);
return processFullyLoadedChange(loading);
@@ -6554,6 +6473,12 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
mPreviousFullyLoaded = mFullyLoaded;
mFullyLoadedInitialized = TRUE;
mFullyLoadedFrameCounter++;
+
+ if (changed && isSelf())
+ {
+ // to know about outfit switching
+ LLAvatarRenderNotifier::getInstance()->updateNotificationState();
+ }
return changed;
}
@@ -6565,15 +6490,26 @@ BOOL LLVOAvatar::isFullyLoaded() const
bool LLVOAvatar::isTooComplex() const
{
- if (gSavedSettings.getS32("RenderAvatarComplexityLimit") > 0 && mVisualComplexity >= gSavedSettings.getS32("RenderAvatarComplexityLimit"))
+ bool too_complex;
+ if (isSelf() || mVisuallyMuteSetting == AV_ALWAYS_RENDER)
+ {
+ too_complex = false;
+ }
+ else
{
- return true;
+ // Determine if visually muted or not
+ static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U);
+ static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit", 0U);
+ static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1.0E6f);
+ too_complex = ((max_render_cost > 0 && mVisualComplexity > max_render_cost)
+ || (max_attachment_bytes > 0 && mAttachmentGeometryBytes > max_attachment_bytes)
+ || (max_attachment_area > 0.0f && mAttachmentSurfaceArea > max_attachment_area)
+ );
}
- return false;
+ return too_complex;
}
-
//-----------------------------------------------------------------------------
// findMotion()
//-----------------------------------------------------------------------------
@@ -7437,7 +7373,10 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
// appearance messages.
mLastUpdateReceivedCOFVersion = this_update_cof_version;
- applyParsedTEMessage(contents.mTEContents);
+ if (applyParsedTEMessage(contents.mTEContents) > 0 && isChanged(TEXTURE))
+ {
+ updateVisualComplexity();
+ }
// prevent the overwriting of valid baked textures with invalid baked textures
for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++)
@@ -7555,7 +7494,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
// Got an update for some other avatar
// Ignore updates for self, because we have a more authoritative value in the preferences.
setHoverOffset(contents.mHoverOffset);
- LL_INFOS("Avatar") << avString() << "setting hover from message" << contents.mHoverOffset[2] << LL_ENDL;
+ LL_INFOS("Avatar") << avString() << "setting hover to " << contents.mHoverOffset[2] << LL_ENDL;
}
if (!contents.mHoverOffsetWasSet && !isSelf())
@@ -8169,28 +8108,35 @@ U32 LLVOAvatar::getPartitionType() const
}
//static
-void LLVOAvatar::updateImpostors()
+void LLVOAvatar::updateImpostors()
{
- LLCharacter::sAllowInstancesChange = FALSE ;
+ LLCharacter::sAllowInstancesChange = FALSE;
for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
+ iter != LLCharacter::sInstances.end(); ++iter)
{
LLVOAvatar* avatar = (LLVOAvatar*) *iter;
- if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor())
+ if (!avatar->isDead() && avatar->isVisible()
+ && (avatar->isImpostor() && avatar->needsImpostorUpdate())
+ )
{
+ avatar->calcMutedAVColor();
gPipeline.generateImpostor(avatar);
}
}
- LLCharacter::sAllowInstancesChange = TRUE ;
+ LLCharacter::sAllowInstancesChange = TRUE;
}
BOOL LLVOAvatar::isImpostor()
{
- return (sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD))) || isInMuteList() ? TRUE : FALSE;
+ return sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE;
}
+BOOL LLVOAvatar::shouldImpostor(const U32 rank_factor) const
+{
+ return (!isSelf() && sUseImpostors && mVisibilityRank > (sMaxNonImpostors * rank_factor));
+}
BOOL LLVOAvatar::needsImpostorUpdate() const
{
@@ -8231,68 +8177,189 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d
angle.mV[2] = da;
}
+// static
+const U32 LLVOAvatar::IMPOSTORS_OFF = 66; /* Must equal the maximum allowed the RenderAvatarMaxNonImpostors
+ * slider in panel_preferences_graphics1.xml */
-void LLVOAvatar::idleUpdateRenderCost()
+// static
+void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue)
{
- static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderWeightLimit", 0);
- static const U32 ARC_LIMIT = 20000;
-
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES))
- { //set debug text to attachment geometry bytes here so render cost will override
- setDebugText(llformat("%.1f KB, %.2f m^2", mAttachmentGeometryBytes/1024.f, mAttachmentSurfaceArea));
+ U32 oldmax = sMaxNonImpostors;
+ bool oldflg = sUseImpostors;
+
+ if (IMPOSTORS_OFF <= newMaxNonImpostorsValue)
+ {
+ sMaxNonImpostors = 0;
}
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME) && max_render_cost == 0)
+ else
{
- return;
+ sMaxNonImpostors = newMaxNonImpostorsValue;
}
+ // the sUseImpostors flag depends on whether or not sMaxNonImpostors is set to the no-limit value (0)
+ sUseImpostors = (0 != sMaxNonImpostors);
+ if ( oldflg != sUseImpostors )
+ {
+ LL_DEBUGS("AvatarRender")
+ << "was " << (oldflg ? "use" : "don't use" ) << " impostors (max " << oldmax << "); "
+ << "now " << (sUseImpostors ? "use" : "don't use" ) << " impostors (max " << sMaxNonImpostors << "); "
+ << LL_ENDL;
+ }
+}
- calculateUpdateRenderCost(); // Update mVisualComplexity if needed
-
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
+
+void LLVOAvatar::idleUpdateRenderComplexity()
+{
+ // Render Complexity
+ calculateUpdateRenderComplexity(); // Update mVisualComplexity if needed
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_DRAW_INFO))
{
- std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus());
- setDebugText(llformat("%s %d", viz_string.c_str(), mVisualComplexity));
- F32 green = 1.f-llclamp(((F32) mVisualComplexity-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f);
- F32 red = llmin((F32) mVisualComplexity/(F32)ARC_LIMIT, 1.f);
- mText->setColor(LLColor4(red,green,0,1));
+ std::string info_line;
+ F32 red_level;
+ F32 green_level;
+ LLColor4 info_color;
+ LLFontGL::StyleFlags info_style;
+
+ if ( !mText )
+ {
+ initDebugTextHud();
+ mText->setFadeDistance(20.0, 5.0); // limit clutter in large crowds
+ }
+ else
+ {
+ mText->clearString(); // clear debug text
+ }
+
+ /*
+ * NOTE: the logic for whether or not each of the values below
+ * controls muting MUST match that in the isVisuallyMuted and isTooComplex methods.
+ */
+
+ static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0);
+ info_line = llformat("%d Complexity", mVisualComplexity);
+
+ if (max_render_cost != 0) // zero means don't care, so don't bother coloring based on this
+ {
+ green_level = 1.f-llclamp(((F32) mVisualComplexity-(F32)max_render_cost)/(F32)max_render_cost, 0.f, 1.f);
+ red_level = llmin((F32) mVisualComplexity/(F32)max_render_cost, 1.f);
+ info_color.set(red_level, green_level, 0.0, 1.0);
+ info_style = ( mVisualComplexity > max_render_cost
+ ? LLFontGL::BOLD : LLFontGL::NORMAL );
+ }
+ else
+ {
+ info_color.set(LLColor4::grey);
+ info_style = LLFontGL::NORMAL;
+ }
+ mText->addLine(info_line, info_color, info_style);
+
+ // Visual rank
+ info_line = llformat("%d rank", mVisibilityRank);
+ // Use grey for imposters, white for normal rendering or no impostors
+ info_color.set(isImpostor() ? LLColor4::grey : LLColor4::white);
+ info_style = LLFontGL::NORMAL;
+ mText->addLine(info_line, info_color, info_style);
+
+ // Attachment Surface Area
+ static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1.0E6f);
+ info_line = llformat("%.2f m^2", mAttachmentSurfaceArea);
+
+ if (max_attachment_area != 0) // zero means don't care, so don't bother coloring based on this
+ {
+ green_level = 1.f-llclamp((mAttachmentSurfaceArea-max_attachment_area)/max_attachment_area, 0.f, 1.f);
+ red_level = llmin(mAttachmentSurfaceArea/max_attachment_area, 1.f);
+ info_color.set(red_level, green_level, 0.0, 1.0);
+ info_style = ( mAttachmentSurfaceArea > max_attachment_area
+ ? LLFontGL::BOLD : LLFontGL::NORMAL );
+
+ }
+ else
+ {
+ info_color.set(LLColor4::grey);
+ info_style = LLFontGL::NORMAL;
+ }
+ mText->addLine(info_line, info_color, info_style);
+
+ // Attachment byte limit
+ static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit", 0);
+ info_line = llformat("%.1f KB", mAttachmentGeometryBytes/1024.f);
+ if (max_attachment_bytes != 0) // zero means don't care, so don't bother coloring based on this
+ {
+ green_level = 1.f-llclamp(((F32) mAttachmentGeometryBytes-(F32)max_attachment_bytes)/(F32)max_attachment_bytes, 0.f, 1.f);
+ red_level = llmin((F32) mAttachmentGeometryBytes/(F32)max_attachment_bytes, 1.f);
+ info_color.set(red_level, green_level, 0.0, 1.0);
+ info_style = ( mAttachmentGeometryBytes > max_attachment_bytes
+ ? LLFontGL::BOLD : LLFontGL::NORMAL );
+ }
+ else
+ {
+ info_color.set(LLColor4::grey);
+ info_style = LLFontGL::NORMAL;
+ }
+ mText->addLine(info_line, info_color, info_style);
+
+ updateText(); // corrects position
}
}
+void LLVOAvatar::addAttachmentSizes(U32 delta_bytes, F32 delta_area)
+{
+ mAttachmentGeometryBytes += delta_bytes;
+ mAttachmentSurfaceArea += delta_area;
+}
+
+void LLVOAvatar::subtractAttachmentSizes(U32 delta_bytes, F32 delta_area)
+{
+ mAttachmentGeometryBytes = delta_bytes > mAttachmentGeometryBytes ? 0 : mAttachmentGeometryBytes - delta_bytes;
+ mAttachmentSurfaceArea = delta_area > mAttachmentSurfaceArea ? 0.0 : mAttachmentSurfaceArea - delta_area;
+}
+
+void LLVOAvatar::updateVisualComplexity()
+{
+ LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL;
+ // Set the cache time to in the past so it's updated ASAP
+ mVisualComplexityStale = true;
+}
// Calculations for mVisualComplexity value
-void LLVOAvatar::calculateUpdateRenderCost()
+void LLVOAvatar::calculateUpdateRenderComplexity()
{
- static const U32 ARC_BODY_PART_COST = 200;
+ /*****************************************************************
+ * This calculation should not be modified by third party viewers,
+ * since it is used to limit rendering and should be uniform for
+ * everyone. If you have suggested improvements, submit them to
+ * the official viewer for consideration.
+ *****************************************************************/
+ static const U32 COMPLEXITY_BODY_PART_COST = 200;
// Diagnostic list of all textures on our avatar
static std::set<LLUUID> all_textures;
if (mVisualComplexityStale)
{
- mVisualComplexityStale = FALSE;
- U32 cost = 0;
+ U32 cost = VISUAL_COMPLEXITY_UNKNOWN;
LLVOVolume::texture_cost_t textures;
for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
{
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
+ const LLAvatarAppearanceDictionary::BakedEntry *baked_dict
+ = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
ETextureIndex tex_index = baked_dict->mTextureIndex;
if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT)))
{
if (isTextureVisible(tex_index))
{
- cost +=ARC_BODY_PART_COST;
+ cost +=COMPLEXITY_BODY_PART_COST;
}
}
}
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
+ for (attachment_map_t::const_iterator attachment_point = mAttachmentPoints.begin();
+ attachment_point != mAttachmentPoints.end();
+ ++attachment_point)
{
- LLViewerJointAttachment* attachment = iter->second;
+ LLViewerJointAttachment* attachment = attachment_point->second;
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
@@ -8322,10 +8389,12 @@ void LLVOAvatar::calculateUpdateRenderCost()
}
}
- for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
+ for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
+ volume_texture != textures.end();
+ ++volume_texture)
{
// add the cost of each individual texture in the linkset
- cost += iter->second;
+ cost += volume_texture->second;
}
}
}
@@ -8372,38 +8441,85 @@ void LLVOAvatar::calculateUpdateRenderCost()
}
}
+ if ( cost != mVisualComplexity )
+ {
+ LL_DEBUGS("AvatarRender") << "Avatar "<< getID()
+ << " complexity updated was " << mVisualComplexity << " now " << cost
+ << " reported " << mReportedVisualComplexity
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("AvatarRender") << "Avatar "<< getID()
+ << " complexity updated no change " << mVisualComplexity
+ << " reported " << mReportedVisualComplexity
+ << LL_ENDL;
+ }
mVisualComplexity = cost;
+ mVisualComplexityStale = false;
+
+ static LLCachedControl<U32> show_my_complexity_changes(gSavedSettings, "ShowMyComplexityChanges", 20);
+
+ if (isSelf() && show_my_complexity_changes)
+ {
+ LLAvatarRenderNotifier::getInstance()->updateNotificationAgent(mVisualComplexity);
+ }
}
}
+void LLVOAvatar::setVisualMuteSettings(VisualMuteSettings set)
+{
+ mVisuallyMuteSetting = set;
+ mNeedsImpostorUpdate = true;
+}
-// static
-LLColor4 LLVOAvatar::calcMutedAVColor(F32 value, S32 range_low, S32 range_high)
+
+void LLVOAvatar::calcMutedAVColor()
{
- F32 clamped_value = llmin(value, (F32) range_high);
- clamped_value = llmax(value, (F32) range_low);
- F32 spectrum = (clamped_value / range_high); // spectrum is between 0 and 1.f
+ LLColor4 new_color(mMutedAVColor);
+ std::string change_msg;
+ LLUUID av_id(getID());
- // Array of colors. These are arranged so only one RGB color changes between each step,
- // and it loops back to red so there is an even distribution. It is not a heat map
- const S32 NUM_SPECTRUM_COLORS = 7;
- static LLColor4 * spectrum_color[NUM_SPECTRUM_COLORS] = { &LLColor4::red, &LLColor4::magenta, &LLColor4::blue, &LLColor4::cyan, &LLColor4::green, &LLColor4::yellow, &LLColor4::red };
+ if (getVisualMuteSettings() == AV_DO_NOT_RENDER)
+ {
+ // explicitly not-rendered avatars are light grey
+ new_color = LLColor4::grey3;
+ change_msg = " not rendered: color is grey3";
+ }
+ else if (LLMuteList::getInstance()->isMuted(av_id)) // the user blocked them
+ {
+ // blocked avatars are dark grey
+ new_color = LLColor4::grey4;
+ change_msg = " blocked: color is grey4";
+ }
+ else if ( mMutedAVColor == LLColor4::white || mMutedAVColor == LLColor4::grey3 || mMutedAVColor == LLColor4::grey4 )
+ {
+ // select a color based on the first byte of the agents uuid so any muted agent is always the same color
+ F32 color_value = (F32) (av_id.mData[0]);
+ F32 spectrum = (color_value / 256.0); // spectrum is between 0 and 1.f
+
+ // Array of colors. These are arranged so only one RGB color changes between each step,
+ // and it loops back to red so there is an even distribution. It is not a heat map
+ const S32 NUM_SPECTRUM_COLORS = 7;
+ static LLColor4 * spectrum_color[NUM_SPECTRUM_COLORS] = { &LLColor4::red, &LLColor4::magenta, &LLColor4::blue, &LLColor4::cyan, &LLColor4::green, &LLColor4::yellow, &LLColor4::red };
- spectrum = spectrum * (NUM_SPECTRUM_COLORS - 1); // Scale to range of number of colors
- S32 spectrum_index_1 = floor(spectrum); // Desired color will be after this index
- S32 spectrum_index_2 = spectrum_index_1 + 1; // and before this index (inclusive)
- F32 fractBetween = spectrum - (F32)(spectrum_index_1); // distance between the two indexes (0-1)
+ spectrum = spectrum * (NUM_SPECTRUM_COLORS - 1); // Scale to range of number of colors
+ S32 spectrum_index_1 = floor(spectrum); // Desired color will be after this index
+ S32 spectrum_index_2 = spectrum_index_1 + 1; // and before this index (inclusive)
+ F32 fractBetween = spectrum - (F32)(spectrum_index_1); // distance between the two indexes (0-1)
- LLColor4 new_color = lerp(*spectrum_color[spectrum_index_1], *spectrum_color[spectrum_index_2], fractBetween);
- new_color.normalize();
- new_color *= 0.7f; // Tone it down a bit
+ new_color = lerp(*spectrum_color[spectrum_index_1], *spectrum_color[spectrum_index_2], fractBetween);
+ new_color.normalize();
+ new_color *= 0.28f; // Tone it down
- //LL_INFOS() << "From value " << std::setprecision(3) << value << " returning color " << new_color
- // << " using indexes " << spectrum_index_1 << ", " << spectrum_index_2
- // << " and fractBetween " << fractBetween
- // << LL_ENDL;
+ change_msg = " over limit color ";
+ }
- return new_color;
+ if (mMutedAVColor != new_color)
+ {
+ LL_DEBUGS("AvatarRender") << "avatar "<< av_id << change_msg << std::setprecision(3) << new_color << LL_ENDL;
+ mMutedAVColor = new_color;
+ }
}
// static