summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rwxr-xr-xindra/newview/app_settings/settings.xml26
-rw-r--r--indra/newview/lldrawpoolavatar.cpp135
-rw-r--r--indra/newview/llviewermenu.cpp59
-rwxr-xr-xindra/newview/llvoavatar.cpp221
-rw-r--r--indra/newview/llvoavatar.h29
-rw-r--r--indra/newview/pipeline.cpp14
-rw-r--r--indra/newview/skins/default/xui/en/menu_attachment_other.xml35
-rw-r--r--indra/newview/skins/default/xui/en/menu_avatar_other.xml39
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml9
9 files changed, 440 insertions, 127 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index d2c3c6089c..21c278fd3b 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9370,7 +9370,7 @@
<key>RenderAutoMuteRenderCostLimit</key>
<map>
<key>Comment</key>
- <string>Maximum render cost before an avatar is automatically visually muted (0 for no limit).</string>
+ <string>Maximum render weight before an avatar is automatically visually muted (0 to not use this limit).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -9381,7 +9381,7 @@
<key>RenderAutoMuteSurfaceAreaLimit</key>
<map>
<key>Comment</key>
- <string>Maximum surface area of attachments before an avatar is automatically visually muted (0 for no limit).</string>
+ <string>Maximum surface area of attachments before an avatar is automatically visually muted (0 to not use this limit).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -9389,6 +9389,28 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>RenderAutoMuteEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Apply visual muting to high cost, non-friends, not in IM, or somewhat distant avatars</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderAutoMuteVisibilityRank</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of avatars to show normally for visual muting mode.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>RenderAutoHideSurfaceAreaLimit</key>
<map>
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index d5afa25c9c..3d7407ab54 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1163,88 +1163,85 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
}
else if (pass >= 3 && pass <= 9)
{ //render rigged attachments
- if (!avatarp->isVisuallyMuted())
+ if (!avatarp->isVisuallyMuted()) // These details are skipped for visually muted (plain imposter) avatars
{
- if (pass == 3)
- {
- if (is_deferred_render)
- {
- renderDeferredRiggedSimple(avatarp);
- }
- else
- {
- renderRiggedSimple(avatarp);
- }
- }
+ if (pass == 3) // To do - use switch statement
+ {
+ if (is_deferred_render)
+ {
+ renderDeferredRiggedSimple(avatarp);
+ }
+ else
+ {
+ renderRiggedSimple(avatarp);
+ }
+ }
else if (pass == 4)
- {
- if (is_deferred_render)
- {
- renderDeferredRiggedBump(avatarp);
- }
- else
- {
- renderRiggedFullbright(avatarp);
- }
- }
+ {
+ if (is_deferred_render)
+ {
+ renderDeferredRiggedBump(avatarp);
+ }
+ else
+ {
+ renderRiggedFullbright(avatarp);
+ }
+ }
else if (pass == 5)
- {
- renderRiggedShinySimple(avatarp);
- }
+ {
+ renderRiggedShinySimple(avatarp);
+ }
else if (pass == 6)
- {
- renderRiggedFullbrightShiny(avatarp);
- }
- else if (pass >= 7 && pass < 9)
- {
- if (pass == 7)
- {
- renderRiggedAlpha(avatarp);
- }
- else if (pass == 8)
- {
- renderRiggedFullbrightAlpha(avatarp);
- }
- }
+ {
+ renderRiggedFullbrightShiny(avatarp);
+ }
+ else if (pass == 7)
+ {
+ renderRiggedAlpha(avatarp);
+ }
+ else if (pass == 8)
+ {
+ renderRiggedFullbrightAlpha(avatarp);
+ }
else if (pass == 9)
- {
- renderRiggedGlow(avatarp);
- }
+ {
+ renderRiggedGlow(avatarp);
+ }
}
}
else
{
- if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
- {
- LLMatrix4 rot_mat;
- LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat);
- LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
- rot_mat *= cfr;
+ if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
+ {
+ LLMatrix4 rot_mat;
+ LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat);
+ LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
+ rot_mat *= cfr;
- LLVector4 wind;
- wind.setVec(avatarp->mWindVec);
- wind.mV[VW] = 0;
- wind = wind * rot_mat;
- wind.mV[VW] = avatarp->mWindVec.mV[VW];
-
- sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_WIND, 1, wind.mV);
- F32 phase = -1.f * (avatarp->mRipplePhase);
-
- F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f);
- LLVector4 sin_params(freq, freq, freq, phase);
- sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_SINWAVE, 1, sin_params.mV);
-
- LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f);
- gravity = gravity * rot_mat;
- sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_GRAVITY, 1, gravity.mV);
- }
+ LLVector4 wind;
+ wind.setVec(avatarp->mWindVec);
+ wind.mV[VW] = 0;
+ wind = wind * rot_mat;
+ wind.mV[VW] = avatarp->mWindVec.mV[VW];
+
+ sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_WIND, 1, wind.mV);
+ F32 phase = -1.f * (avatarp->mRipplePhase);
+
+ F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f);
+ LLVector4 sin_params(freq, freq, freq, phase);
+ sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_SINWAVE, 1, sin_params.mV);
+
+ LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f);
+ gravity = gravity * rot_mat;
+ sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_GRAVITY, 1, gravity.mV);
+ }
- if( !single_avatar || (avatarp == single_avatar) )
- {
- avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
+ if( !single_avatar || (avatarp == single_avatar) )
+ {
+ avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
+ }
}
}
-}
void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
{
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 4c99e65c99..aab4d93882 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -2934,6 +2934,63 @@ bool enable_object_unmute()
}
}
+
+// 0 = normal, 1 = always, 2 = never
+class LLAvatarCheckImposterMode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object) return false;
+
+ LLVOAvatar* avatar = find_avatar_from_object(object);
+ if (!avatar) return false;
+
+ U32 mode = userdata.asInteger();
+ switch (mode)
+ {
+ case 0:
+ return (avatar->getVisualMuteSettings() == LLVOAvatar::VISUAL_MUTE_NOT_SET);
+ case 1:
+ return (avatar->getVisualMuteSettings() == LLVOAvatar::ALWAYS_VISUAL_MUTE);
+ case 2:
+ return (avatar->getVisualMuteSettings() == LLVOAvatar::NEVER_VISUAL_MUTE);
+ default:
+ return false;
+ }
+ } // handleEvent()
+};
+
+// 0 = normal, 1 = always, 2 = never
+class LLAvatarSetImposterMode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object) return false;
+
+ LLVOAvatar* avatar = find_avatar_from_object(object);
+ if (!avatar) return false;
+
+ U32 mode = userdata.asInteger();
+ switch (mode)
+ {
+ case 0:
+ avatar->setVisualMuteSettings(LLVOAvatar::VISUAL_MUTE_NOT_SET);
+ return true;
+ case 1:
+ avatar->setVisualMuteSettings(LLVOAvatar::VISUAL_MUTE_NOT_SET);
+ return true;
+ case 2:
+ avatar->setVisualMuteSettings(LLVOAvatar::NEVER_VISUAL_MUTE);
+ return true;
+ default:
+ return false;
+ }
+ } // handleEvent()
+};
+
+
class LLObjectMute : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -8644,6 +8701,8 @@ void initialize_menus()
view_listener_t::addMenu( new LLCheckPanelPeopleTab(), "SideTray.CheckPanelPeopleTab");
// Avatar pie menu
+ view_listener_t::addMenu(new LLAvatarCheckImposterMode(), "Avatar.CheckImposterMode");
+ view_listener_t::addMenu(new LLAvatarSetImposterMode(), "Avatar.SetImposterMode");
view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute");
view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend");
view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact");
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 7d099d690a..cce4925e0a 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -62,6 +62,7 @@
#include "llhudmanager.h"
#include "llhudnametag.h"
#include "llhudtext.h" // for mText/mDebugText
+#include "llimview.h"
#include "llinitparam.h"
#include "llkeyframefallmotion.h"
#include "llkeyframestandmotion.h"
@@ -784,6 +785,13 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mLastPelvisToFoot = 0.0f;
mPelvisFixup = 0.0f;
mLastPelvisFixup = 0.0f;
+
+ 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
@@ -3435,24 +3443,82 @@ void LLVOAvatar::slamPosition()
mRoot.updateWorldMatrixChildren();
}
-bool LLVOAvatar::isVisuallyMuted() const
+bool LLVOAvatar::isVisuallyMuted()
{
- bool ret = false;
+ 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
+ // * 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
if (!isSelf())
{
+ static LLCachedControl<bool> render_mute_enabled(gSavedSettings, "RenderAutoMuteEnabled");
static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit");
static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit");
static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderCostLimit");
-
- U32 max_cost = (U32) (max_render_cost*(LLVOAvatar::sLODFactor+0.5));
+ static LLCachedControl<U32> visibility_rank(gSavedSettings, "RenderAutoMuteVisibilityRank");
+
+ if (mVisuallyMuteSetting == ALWAYS_VISUAL_MUTE)
+ { // Always want to see this AV as an imposter
+ muted = true;
+ }
+ else if (mVisuallyMuteSetting == NEVER_VISUAL_MUTE)
+ { // Never show as imposter
+ muted = false;
+ }
+ else if (render_mute_enabled)
+ {
+ 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));
- ret = LLMuteList::getInstance()->isMuted(getID()) ||
- (mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f) ||
- (mVisualComplexity > max_cost && max_render_cost > 0);
+ muted = LLMuteList::getInstance()->isMuted(getID()) ||
+ (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 (visibility_rank > 0)
+ { // They are above the visibilty rank - mute them
+ muted = (mVisibilityRank > visibility_rank);
+ }
+
+ if (muted || // Don't mute friends or IMs
+ visibility_rank == 0)
+ {
+ 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;
+ }
+ }
}
- return ret;
+ return muted;
}
//------------------------------------------------------------------------
@@ -3509,7 +3575,8 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
// the rest should only be done occasionally for far away avatars
//--------------------------------------------------------------------
- if (visible && (!isSelf() || isVisuallyMuted()) && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter)
+ bool visually_muted = isVisuallyMuted();
+ if (visible && (!isSelf() || visually_muted) && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter)
{
const LLVector4a* ext = mDrawable->getSpatialExtents();
LLVector4a size;
@@ -3518,8 +3585,8 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f);
- if (isVisuallyMuted())
- { // muted avatars update at 16 hz
+ if (visually_muted)
+ { // visually muted avatars update at 16 hz
mUpdatePeriod = 16;
}
else if (mVisibilityRank <= LLVOAvatar::sMaxVisible ||
@@ -4295,23 +4362,23 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
BOOL first_pass = TRUE;
if (!LLDrawPoolAvatar::sSkipOpaque)
{
- bool muted = isVisuallyMuted();
+ bool visually_muted = isVisuallyMuted();
if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
{
- if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy || muted)
+ if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy || visually_muted)
{
num_indices += mMeshLOD[MESH_ID_HEAD]->render(mAdjustedPixelArea, TRUE, mIsDummy);
first_pass = FALSE;
}
}
- if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy || muted)
+ if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy || visually_muted)
{
num_indices += mMeshLOD[MESH_ID_UPPER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
first_pass = FALSE;
}
- if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy || muted)
+ if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy || visually_muted)
{
num_indices += mMeshLOD[MESH_ID_LOWER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
first_pass = FALSE;
@@ -8396,7 +8463,7 @@ void LLVOAvatar::updateImpostors()
LLCharacter::sAllowInstancesChange = TRUE ;
}
-BOOL LLVOAvatar::isImpostor() const
+BOOL LLVOAvatar::isImpostor()
{
return sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE;
}
@@ -8441,15 +8508,13 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d
angle.mV[2] = da;
}
+
void LLVOAvatar::idleUpdateRenderCost()
{
static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderCostLimit");
- static const U32 ARC_BODY_PART_COST = 200;
static const U32 ARC_LIMIT = 20000;
- static std::set<LLUUID> all_textures;
-
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));
@@ -8460,6 +8525,69 @@ void LLVOAvatar::idleUpdateRenderCost()
return;
}
+ calculateUpdateRenderCost(); // Update mVisualComplexity if needed
+
+ doRenderCostNagging(max_render_cost); // Remind the user their AV is too complex
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
+ {
+ 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));
+ }
+}
+
+
+// Remind the user about their expensive avatar
+void LLVOAvatar::doRenderCostNagging(U32 max_render_cost)
+{
+ if (isSelf())
+ {
+ static S32 sOldComplexity = 0;
+ static F64 sLastRenderCostNagTime = 0.0;
+
+ const F64 RENDER_NAG_INTERVAL = 60.0;
+
+ F64 now = LLFrameTimer::getTotalSeconds();
+ if (sLastRenderCostNagTime > 0.0 &&
+ (now - sLastRenderCostNagTime) > RENDER_NAG_INTERVAL &&
+ sOldComplexity != mVisualComplexity)
+ {
+ sOldComplexity = mVisualComplexity;
+
+ if (max_render_cost > 0)
+ { //pop up notification that you have exceeded a render cost limit
+ if (mVisualComplexity > max_render_cost+max_render_cost/2)
+ {
+ LLNotificationsUtil::add("ExceededHighDetailRenderCost");
+ sLastRenderCostNagTime = now;
+ }
+ else if (mVisualComplexity > max_render_cost)
+ {
+ LLNotificationsUtil::add("ExceededMidDetailRenderCost");
+ sLastRenderCostNagTime = now;
+ }
+ else if (mVisualComplexity > max_render_cost/2)
+ {
+ LLNotificationsUtil::add("ExceededLowDetailRenderCost");
+ sLastRenderCostNagTime = now;
+ }
+ }
+ }
+ }
+}
+
+
+// Calculations for mVisualComplexity value
+void LLVOAvatar::calculateUpdateRenderCost()
+{
+ static const U32 ARC_BODY_PART_COST = 200;
+
+ // Diagnostic list of all textures on our avatar
+ static std::set<LLUUID> all_textures;
+
if (mVisualComplexityStale)
{
mVisualComplexityStale = FALSE;
@@ -8526,8 +8654,6 @@ void LLVOAvatar::idleUpdateRenderCost()
}
-
-
// Diagnostic output to identify all avatar-related textures.
// Does not affect rendering cost calculation.
// Could be wrapped in a debug option if output becomes problematic.
@@ -8568,34 +8694,37 @@ void LLVOAvatar::idleUpdateRenderCost()
}
}
- if (isSelf() && max_render_cost > 0 && mVisualComplexity != cost)
- { //pop up notification that you have exceeded a render cost limit
- if (cost > max_render_cost+max_render_cost/2)
- {
- LLNotificationsUtil::add("ExceededHighDetailRenderCost");
- }
- else if (cost > max_render_cost)
- {
- LLNotificationsUtil::add("ExceededMidDetailRenderCost");
- }
- else if (cost > max_render_cost/2)
- {
- LLNotificationsUtil::add("ExceededLowDetailRenderCost");
- }
- }
-
mVisualComplexity = cost;
}
+}
-
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
- {
- 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));
- }
+
+// static
+LLColor4 LLVOAvatar::calcMutedAVColor(F32 value, S32 range_low, S32 range_high)
+{
+ 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
+
+ // 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)
+
+ LLColor4 new_color = lerp(*spectrum_color[spectrum_index_1], *spectrum_color[spectrum_index_2], fractBetween);
+ //new_color.normalize();
+
+ //llinfos << "From value " << std::setprecision(3) << value << " returning color " << new_color
+ // << " using indexes " << spectrum_index_1 << ", " << spectrum_index_2
+ // << " and fractBetween " << fractBetween
+ // << llendl;
+
+ return new_color;
}
// static
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 386d9d7746..0e7bf7a6c9 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -253,7 +253,14 @@ public:
static void invalidateNameTags();
void addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font);
void idleUpdateRenderCost();
+ void doRenderCostNagging(U32 max_render_cost);
+ void calculateUpdateRenderCost();
void updateVisualComplexity() { mVisualComplexityStale = TRUE; }
+
+ S32 getVisualComplexity() { return mVisualComplexity; };
+ S32 getUpdatePeriod() { return mUpdatePeriod; };
+ const LLColor4 & getMutedAVColor() { return mMutedAVColor; };
+
void idleUpdateBelowWater();
//--------------------------------------------------------------------
@@ -304,11 +311,14 @@ public:
return mPhases;
}
+ static LLColor4 calcMutedAVColor(F32 value, S32 range_low, S32 range_high);
+
protected:
BOOL updateIsFullyLoaded();
BOOL processFullyLoadedChange(bool loading);
void updateRuthTimer(bool loading);
F32 calcMorphAmount();
+
private:
BOOL mFirstFullyVisible;
BOOL mFullyLoaded;
@@ -317,6 +327,7 @@ private:
S32 mFullyLoadedFrameCounter;
S32 mVisualComplexity;
BOOL mVisualComplexityStale;
+ LLColor4 mMutedAVColor;
LLFrameTimer mFullyLoadedTimer;
LLFrameTimer mRuthTimer;
@@ -437,7 +448,16 @@ private:
public:
U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0);
- bool isVisuallyMuted() const;
+ bool isVisuallyMuted();
+
+ enum VisualMuteSettings
+ {
+ VISUAL_MUTE_NOT_SET = 0,
+ ALWAYS_VISUAL_MUTE = 1,
+ NEVER_VISUAL_MUTE = 2
+ };
+ void setVisualMuteSettings(VisualMuteSettings set) { mVisuallyMuteSetting = set; };
+ VisualMuteSettings getVisualMuteSettings() { return mVisuallyMuteSetting; };
U32 renderRigid();
U32 renderSkinned(EAvatarRenderPass pass);
@@ -461,6 +481,11 @@ private:
S32 mUpdatePeriod;
S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer.
+ bool mCachedVisualMute; // cached return value for isVisuallyMuted()
+ F64 mCachedVisualMuteUpdateTime; // Time to update mCachedVisualMute
+
+ VisualMuteSettings mVisuallyMuteSetting; // Always or never visually mute this AV
+
//--------------------------------------------------------------------
// Morph masks
//--------------------------------------------------------------------
@@ -493,7 +518,7 @@ private:
// Impostors
//--------------------------------------------------------------------
public:
- BOOL isImpostor() const;
+ BOOL isImpostor();
BOOL needsImpostorUpdate() const;
const LLVector3& getImpostorOffset() const;
const LLVector2& getImpostorDim() const;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index df7a3c7593..61e42bbcee 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2862,7 +2862,7 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
llassert(vobj); // trying to catch a bad assumption
if (vobj) // this test may not be needed, see above
{
- const LLVOAvatar* av = vobj->asAvatar();
+ LLVOAvatar* av = vobj->asAvatar();
if (av && av->isImpostor())
{
return;
@@ -10103,11 +10103,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
assertInitialized();
- bool muted = avatar->isVisuallyMuted();
+ bool visually_muted = avatar->isVisuallyMuted();
pushRenderTypeMask();
- if (muted)
+ if (visually_muted)
{
andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
}
@@ -10251,7 +10251,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
F32 old_alpha = LLDrawPoolAvatar::sMinimumAlpha;
- if (muted)
+ if (visually_muted)
{ //disable alpha masking for muted avatars (get whole skin silhouette)
LLDrawPoolAvatar::sMinimumAlpha = 0.f;
}
@@ -10282,7 +10282,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
LLGLDisable blend(GL_BLEND);
- if (muted)
+ if (visually_muted)
{
gGL.setColorMask(true, true);
@@ -10317,8 +10317,8 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
gGL.diffuseColor4ub(64,64,64,255);
}
else
- { //blue visually muted avatar
- gGL.diffuseColor4ub(72,61,139,255);
+ { // Visually muted avatar
+ gGL.diffuseColor4fv( avatar->getMutedAVColor().mV );
}
{
diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml
index 00d4b1dab1..87fa7c3f00 100644
--- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml
@@ -104,8 +104,43 @@
<menu_item_call.on_enable
function="Object.EnableInspect" />
</menu_item_call>
+
+ <menu_item_separator />
+
+ <menu_item_check
+ name="Normal"
+ label="Normal">
+ <menu_item_check.on_check
+ function="Avatar.CheckImposterMode"
+ parameter="0" />
+ <menu_item_check.on_click
+ function="Avatar.SetImposterMode"
+ parameter="0" />
+ </menu_item_check>
+ <menu_item_check
+ name="Always use imposter"
+ label="Always use imposter">
+ <menu_item_check.on_check
+ function="Avatar.CheckImposterMode"
+ parameter="1" />
+ <menu_item_check.on_click
+ function="Avatar.SetImposterMode"
+ parameter="1" />
+ </menu_item_check>
+ <menu_item_check
+ name="Never use imposter"
+ label="Never use imposter">
+ <menu_item_check.on_check
+ function="Avatar.CheckImposterMode"
+ parameter="2" />
+ <menu_item_check.on_click
+ function="Avatar.SetImposterMode"
+ parameter="2" />
+ </menu_item_check>
+
<menu_item_separator
layout="topleft" />
+
<menu_item_call
enabled="false"
label="Mute Particle Owner"
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml
index 73fa086f28..60b7e3e77c 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml
@@ -39,8 +39,10 @@
<menu_item_call.on_click
function="Avatar.InviteToGroup" />
</menu_item_call>
+
<menu_item_separator />
- <menu_item_call
+
+ <menu_item_call
enabled="false"
label="Block"
name="Avatar Mute">
@@ -95,8 +97,43 @@
<menu_item_call.on_enable
function="EnablePayAvatar" />
</menu_item_call>
+
+ <menu_item_separator />
+
+ <menu_item_check
+ name="Normal"
+ label="Normal">
+ <menu_item_check.on_check
+ function="Avatar.CheckImposterMode"
+ parameter="0" />
+ <menu_item_check.on_click
+ function="Avatar.SetImposterMode"
+ parameter="0" />
+ </menu_item_check>
+ <menu_item_check
+ name="Always use imposter"
+ label="Always use imposter">
+ <menu_item_check.on_check
+ function="Avatar.CheckImposterMode"
+ parameter="1" />
+ <menu_item_check.on_click
+ function="Avatar.SetImposterMode"
+ parameter="1" />
+ </menu_item_check>
+ <menu_item_check
+ name="Never use imposter"
+ label="Never use imposter">
+ <menu_item_check.on_check
+ function="Avatar.CheckImposterMode"
+ parameter="2" />
+ <menu_item_check.on_click
+ function="Avatar.SetImposterMode"
+ parameter="2" />
+ </menu_item_check>
+
<menu_item_separator
layout="topleft" />
+
<menu_item_call
enabled="false"
label="Mute Particle Owner"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 544f06ac0c..4646d307aa 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -543,6 +543,15 @@
<menu_item_check.on_check
control="NavBarShowParcelProperties" />
</menu_item_check>
+ <menu_item_check
+ label="Simple Imposters"
+ name="RenderAutoMuteEnabled">
+ <menu_item_check.on_check
+ control="RenderAutoMuteEnabled" />
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="RenderAutoMuteEnabled" />
+ </menu_item_check>
<menu_item_separator />
<menu_item_check
label="Advanced Menu"