diff options
Diffstat (limited to 'indra/newview/llvoavatar.cpp')
-rwxr-xr-x | indra/newview/llvoavatar.cpp | 333 |
1 files changed, 234 insertions, 99 deletions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 1a050800b4..1aa38e6bfa 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -58,6 +58,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" @@ -668,6 +669,9 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mSpecialRenderMode(0), mAttachmentGeometryBytes(0), mAttachmentSurfaceArea(0.f), + mReportedVisualComplexity(-1), + mReportedAttachmentGeometryBytes(-1), + mReportedAttachmentSurfaceArea(-1.f), mTurning(FALSE), mLastSkeletonSerialNum( 0 ), mIsSitting(FALSE), @@ -701,6 +705,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mFullyLoaded(FALSE), mPreviousFullyLoaded(FALSE), mFullyLoadedInitialized(FALSE), + mVisualComplexity(0), + mVisualComplexityStale(TRUE), mLoadedCallbacksPaused(FALSE), mHasPelvisOffset( FALSE ), mRenderUnloadedAvatar(LLCachedControl<bool>(gSavedSettings, "RenderUnloadedAvatar")), @@ -769,6 +775,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 @@ -2972,14 +2985,83 @@ void LLVOAvatar::slamPosition() mRoot->updateWorldMatrixChildren(); } -bool LLVOAvatar::isVisuallyMuted() const +bool LLVOAvatar::isVisuallyMuted() { - static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit"); - static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit"); - - return LLMuteList::getInstance()->isMuted(getID()) - || (mAttachmentGeometryBytes > max_attachment_bytes && max_attachment_bytes > 0) - || (mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f); + 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<F32> render_mute_threshold(gSavedSettings, "RenderAutoMuteThreshold"); + static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit"); + static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit"); + static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderCostLimit"); + + 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 (LLVOAvatar::sLODFactor <= render_mute_threshold) + { + 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 = 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 (sMaxVisible > 0) + { // They are above the visibilty rank - mute them + muted = (mVisibilityRank > sMaxVisible); + } + + /* Not used - always draw friends or those in IMs. Works nicely, needs UI? + if (muted || // Don't mute friends or IMs + sMaxVisible == 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 muted; } //------------------------------------------------------------------------ @@ -3077,7 +3159,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; @@ -3086,8 +3169,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 || @@ -3887,9 +3970,11 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) BOOL first_pass = TRUE; if (!LLDrawPoolAvatar::sSkipOpaque) { + bool visually_muted = isVisuallyMuted(); + if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) { - if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy) + if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy || visually_muted) { LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD); if (head_mesh) @@ -3899,7 +3984,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) first_pass = FALSE; } } - if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy) + if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy || visually_muted) { LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY); if (upper_mesh) @@ -3909,7 +3994,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) first_pass = FALSE; } - if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy) + if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy || visually_muted) { LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY); if (lower_mesh) @@ -5481,6 +5566,8 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o return 0; } + mVisualComplexityStale = TRUE; + if (viewer_object->isSelected()) { LLSelectMgr::getInstance()->updateSelectionCenter(); @@ -5628,6 +5715,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) if (attachment->isObjectAttached(viewer_object)) { + mVisualComplexityStale = TRUE; cleanupAttachedMesh( viewer_object ); attachment->removeObject(viewer_object); lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl; @@ -7734,9 +7822,9 @@ void LLVOAvatar::updateImpostors() LLCharacter::sAllowInstancesChange = TRUE ; } -BOOL LLVOAvatar::isImpostor() const +BOOL LLVOAvatar::isImpostor() { - return (isVisuallyMuted() || (sUseImpostors && mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE; + return sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE; } @@ -7779,135 +7867,182 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d angle.mV[2] = da; } + void LLVOAvatar::idleUpdateRenderCost() { - static const U32 ARC_BODY_PART_COST = 200; - static const U32 ARC_LIMIT = 20000; + static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderCostLimit"); - static std::set<LLUUID> all_textures; + 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)); } - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME)) + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME) && max_render_cost == 0) { return; } - U32 cost = 0; - LLVOVolume::texture_cost_t textures; + calculateUpdateRenderCost(); // Update mVisualComplexity if needed + + 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)); + } +} - for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) + +// 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) { - 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))) + mVisualComplexityStale = FALSE; + U32 cost = 0; + LLVOVolume::texture_cost_t textures; + + for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { - if (isTextureVisible(tex_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))) { - cost +=ARC_BODY_PART_COST; + if (isTextureVisible(tex_index)) + { + cost +=ARC_BODY_PART_COST; + } } } - } - for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && !attached_object->isHUDAttachment()) + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - textures.clear(); - const LLDrawable* drawable = attached_object->mDrawable; - if (drawable) + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && !attached_object->isHUDAttachment()) { - const LLVOVolume* volume = drawable->getVOVolume(); - if (volume) + textures.clear(); + const LLDrawable* drawable = attached_object->mDrawable; + if (drawable) { - cost += volume->getRenderCost(textures); - - const_child_list_t children = volume->getChildren(); - for (const_child_list_t::const_iterator child_iter = children.begin(); - child_iter != children.end(); - ++child_iter) + const LLVOVolume* volume = drawable->getVOVolume(); + if (volume) { - LLViewerObject* child_obj = *child_iter; - LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj ); - if (child) + cost += volume->getRenderCost(textures); + + const_child_list_t children = volume->getChildren(); + for (const_child_list_t::const_iterator child_iter = children.begin(); + child_iter != children.end(); + ++child_iter) { - cost += child->getRenderCost(textures); + LLViewerObject* child_obj = *child_iter; + LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj ); + if (child) + { + cost += child->getRenderCost(textures); + } } - } - for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) - { - // add the cost of each individual texture in the linkset - cost += iter->second; + for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) + { + // add the cost of each individual texture in the linkset + cost += iter->second; + } } } } } - } - - } - + } - // 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. - if (isSelf()) - { - // print any attachment textures we didn't already know about. - for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) + // 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. + if (isSelf()) { - LLUUID image_id = it->first; - if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) - continue; - if (all_textures.find(image_id) == all_textures.end()) + // print any attachment textures we didn't already know about. + for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) { - // attachment texture not previously seen. - llinfos << "attachment_texture: " << image_id.asString() << llendl; - all_textures.insert(image_id); + LLUUID image_id = it->first; + if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) + continue; + if (all_textures.find(image_id) == all_textures.end()) + { + // attachment texture not previously seen. + llinfos << "attachment_texture: " << image_id.asString() << llendl; + all_textures.insert(image_id); + } } - } - // print any avatar textures we didn't already know about - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); + // print any avatar textures we didn't already know about + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); - ++iter) - { - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; - // TODO: MULTI-WEARABLE: handle multiple textures for self - const LLViewerTexture* te_image = getImage(iter->first,0); - if (!te_image) - continue; - LLUUID image_id = te_image->getID(); - if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) - continue; - if (all_textures.find(image_id) == all_textures.end()) + ++iter) { - llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl; - all_textures.insert(image_id); + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; + // TODO: MULTI-WEARABLE: handle multiple textures for self + const LLViewerTexture* te_image = getImage(iter->first,0); + if (!te_image) + continue; + LLUUID image_id = te_image->getID(); + if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) + continue; + if (all_textures.find(image_id) == all_textures.end()) + { + llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl; + all_textures.insert(image_id); + } } } + + mVisualComplexity = cost; } +} - - std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); - setDebugText(llformat("%s %d", viz_string.c_str(), cost)); - mVisualComplexity = cost; - F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f); - F32 red = llmin((F32) cost/(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(); + new_color *= 0.9f; + + //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 |