From 99effd37ab6cc6611f75cdca9146cc3c46a86482 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 13 Jul 2017 20:50:38 +0100 Subject: SL-714 - pause animations when animated objects are right clicked, generate rigged volume for wireframe. --- indra/newview/llselectmgr.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 983a7ca1ae..4a12d03f74 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -46,6 +46,7 @@ #include "llundo.h" #include "lluuid.h" #include "llvolume.h" +#include "llcontrolavatar.h" #include "message.h" #include "object_flags.h" #include "llquaternion.h" @@ -6660,7 +6661,15 @@ void LLSelectMgr::updateSelectionCenter() } else { - mPauseRequest = NULL; + LLVOVolume *volp = dynamic_cast(object); + if (volp && volp->isAnimatedObject() && volp->getControlAvatar()) + { + mPauseRequest = volp->getControlAvatar()->requestPause(); + } + else + { + mPauseRequest = NULL; + } } if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid()) -- cgit v1.3 From c4bc677a407049e406bde925df1537f157bda0c3 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 17 Jul 2017 21:02:16 +0100 Subject: SL-714 - pause associated avatar when an animated object is selected. Handles the possibility that multiple avatars need to be paused. --- indra/newview/llselectmgr.cpp | 63 +++++++++++++++++++++++++++++-------------- indra/newview/llselectmgr.h | 4 ++- 2 files changed, 46 insertions(+), 21 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 4a12d03f74..7bf60d6ffb 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -6629,7 +6629,10 @@ S32 get_family_count(LLViewerObject *parent) //----------------------------------------------------------------------------- // updateSelectionCenter -//----------------------------------------------------------------------------- +// +// FIXME this is a grab bag of functionality only some of which has to do +// with the selection center +// ----------------------------------------------------------------------------- void LLSelectMgr::updateSelectionCenter() { const F32 MOVE_SELECTION_THRESHOLD = 1.f; // Movement threshold in meters for updating selection @@ -6647,31 +6650,12 @@ void LLSelectMgr::updateSelectionCenter() mSelectionCenterGlobal.clearVec(); mShowSelection = FALSE; mSelectionBBox = LLBBox(); - mPauseRequest = NULL; resetAgentHUDZoom(); - } else { mSelectedObjects->mSelectType = getSelectTypeForObject(object); - if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid() && object->getParent() != NULL) - { - mPauseRequest = gAgentAvatarp->requestPause(); - } - else - { - LLVOVolume *volp = dynamic_cast(object); - if (volp && volp->isAnimatedObject() && volp->getControlAvatar()) - { - mPauseRequest = volp->getControlAvatar()->requestPause(); - } - else - { - mPauseRequest = NULL; - } - } - if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid()) { // reset hud ZOOM @@ -6748,6 +6732,45 @@ void LLSelectMgr::updateSelectionCenter() { gEditMenuHandler = NULL; } + + pauseAssociatedAvatars(); +} + +//----------------------------------------------------------------------------- +// pauseAssociatedAvatars +// +// If the selection includes an attachment or an animated object, the +// associated avatars should pause their animations until they are no +// longer selected. +//----------------------------------------------------------------------------- +void LLSelectMgr::pauseAssociatedAvatars() +{ + mPauseRequests.clear(); + + for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); + iter != mSelectedObjects->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if (!object) + continue; + + mSelectedObjects->mSelectType = getSelectTypeForObject(object); + + if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && + isAgentAvatarValid() && object->getParent() != NULL) + { + mPauseRequests.push_back(gAgentAvatarp->requestPause()); + } + else + { + LLVOVolume *volp = dynamic_cast(object); + if (volp && volp->isAnimatedObject() && volp->getControlAvatar()) + { + mPauseRequests.push_back(volp->getControlAvatar()->requestPause()); + } + } + } } void LLSelectMgr::updatePointAt() diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 7ef0032645..fc4b920c51 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -742,6 +742,8 @@ public: LLVector3d getSelectionCenterGlobal() const { return mSelectionCenterGlobal; } void updateSelectionCenter(); + void pauseAssociatedAvatars(); + void resetAgentHUDZoom(); void setAgentHUDZoom(F32 target_zoom, F32 current_zoom); void getAgentHUDZoom(F32 &target_zoom, F32 ¤t_zoom) const; @@ -843,7 +845,7 @@ private: LLFrameTimer mEffectsTimer; BOOL mForceSelection; - LLAnimPauseRequest mPauseRequest; + std::vector mPauseRequests; }; // *DEPRECATED: For callbacks or observers, use -- cgit v1.3 From 5610444d6450d5eb2e203be527116fe01d2d436a Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 19 Jul 2017 22:21:08 +0100 Subject: SL-714 - fixes to get wireframes to display consistently when right-clicking on animated objects. --- indra/newview/llcontrolavatar.cpp | 24 +++++++++++++++++++++++- indra/newview/lldrawable.cpp | 3 ++- indra/newview/llselectmgr.cpp | 5 ++--- indra/newview/llviewerobject.cpp | 6 ++++++ indra/newview/llviewerobject.h | 4 +++- 5 files changed, 36 insertions(+), 6 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 94e5666a70..e9df81e255 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -194,7 +194,29 @@ void LLControlAvatar::updateDebugText() std::vector volumes; getAnimatedVolumes(volumes); S32 animated_volume_count = volumes.size(); - addDebugText(llformat("CAV obj %d anim %d", total_linkset_count, animated_volume_count)); + std::string active_string; + for (std::vector::iterator it = volumes.begin(); + it != volumes.end(); ++it) + { + LLVOVolume *volp = *it; + if (volp && volp->mDrawable) + { + if (volp->mDrawable->isActive()) + { + active_string += "A"; + } + else + { + active_string += "S"; + } + } + else + { + active_string += "-"; + } + } + addDebugText(llformat("CAV obj %d anim %d active %s", + total_linkset_count, animated_volume_count, active_string.c_str())); #if 0 // AXON - detailed rigged mesh info for (std::vector::iterator it = volumes.begin(); diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index f956023358..61ebf947dd 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -550,7 +550,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled) if (isState(ACTIVE) && !isState(ACTIVE_CHILD) && !mVObjp->isAttachment() && - !mVObjp->isFlexible()) + !mVObjp->isFlexible() && + !mVObjp->isAnimatedObject()) { clearState(ACTIVE | ANIMATED_CHILD); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 7bf60d6ffb..b6b7d5265b 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -6764,10 +6764,9 @@ void LLSelectMgr::pauseAssociatedAvatars() } else { - LLVOVolume *volp = dynamic_cast(object); - if (volp && volp->isAnimatedObject() && volp->getControlAvatar()) + if (object && object->isAnimatedObject() && object->getControlAvatar()) { - mPauseRequests.push_back(volp->getControlAvatar()->requestPause()); + mPauseRequests.push_back(object->getControlAvatar()->requestPause()); } } } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index c6051650cf..cb9f9e0455 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -2965,6 +2965,12 @@ void LLViewerObject::unlinkControlAvatar() // automatically remove the control avatar connection. } +// virtual +bool LLViewerObject::isAnimatedObject() const +{ + return false; +} + struct LLFilenameAndTask { LLUUID mTaskID; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 1967841fd9..c79ff7bb74 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -693,7 +693,9 @@ public: void linkControlAvatar(); // Remove any reference to control av for this prim void unlinkControlAvatar(); - + + virtual bool isAnimatedObject() const; + protected: LLPointer mControlAvatar; -- cgit v1.3 From 72010fba4d07c768b0f5edd5dc56bf89a98a9985 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 4 Aug 2017 16:20:04 +0100 Subject: SL-718 - bug fixes for animated objects as attachments: Pause all associated avatars when selecting/editing. Don't apply joint positions to the attached avatar on login. --- indra/newview/llappearancemgr.cpp | 5 ++++- indra/newview/llselectmgr.cpp | 17 ++++++++++++++++- indra/newview/llvovolume.cpp | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index c928cf0601..d58d03d68d 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -880,7 +880,10 @@ void LLWearableHoldingPattern::onAllComplete() ++it) { LLViewerObject *objectp = *it; - gAgentAvatarp->addAttachmentOverridesForObject(objectp); + if (!objectp->isAnimatedObject()) + { + gAgentAvatarp->addAttachmentOverridesForObject(objectp); + } } // Add new attachments to match those requested. diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index b6b7d5265b..3e8d8883e0 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -6760,12 +6760,27 @@ void LLSelectMgr::pauseAssociatedAvatars() if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid() && object->getParent() != NULL) { - mPauseRequests.push_back(gAgentAvatarp->requestPause()); + if (object->isAnimatedObject()) + { + // Is an animated object attachment. + // Pause both the control avatar and the avatar it's attached to. + if (object->getControlAvatar()) + { + mPauseRequests.push_back(object->getControlAvatar()->requestPause()); + } + mPauseRequests.push_back(gAgentAvatarp->requestPause()); + } + else + { + // Is a regular attachment. Pause the avatar it's attached to. + mPauseRequests.push_back(gAgentAvatarp->requestPause()); + } } else { if (object && object->isAnimatedObject() && object->getControlAvatar()) { + // Is a non-attached animated object. Pause the control avatar. mPauseRequests.push_back(object->getControlAvatar()->requestPause()); } } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 04e2827182..15fc995ecf 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5023,7 +5023,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool is_rigged = false; // AXON handle NPC case - if (rigged && pAvatarVO) + if (rigged && pAvatarVO && !vobj->isAnimatedObject()) { pAvatarVO->addAttachmentOverridesForObject(vobj); if (!LLApp::isExiting() && pAvatarVO->isSelf() && debugLoggingEnabled("AvatarAttachments")) -- cgit v1.3 From a6068419e7fe1a5a0eda007b2e989769c0a92262 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 22 Sep 2017 18:04:03 +0100 Subject: SL-794, SL-790 - viewer-side enforcement in UI for various animated object limits that are also enforced on the server. --- indra/llcommon/indra_constants.h | 1 - indra/newview/llmeshrepository.cpp | 27 ++++++++++++++++++ indra/newview/llmeshrepository.h | 1 + indra/newview/llselectmgr.cpp | 29 +++++++++++++++++++ indra/newview/llselectmgr.h | 3 ++ indra/newview/llviewerobject.cpp | 33 +++++++++++++++++++++- indra/newview/llviewerobject.h | 3 ++ indra/newview/llvoavatar.cpp | 21 +++++++++++++- indra/newview/llvoavatar.h | 1 + indra/newview/llvovolume.cpp | 26 ++++++++++++----- indra/newview/llvovolume.h | 1 + .../newview/skins/default/xui/en/notifications.xml | 23 +++++++++++++++ 12 files changed, 159 insertions(+), 10 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 99ad5f2473..fda84aa5a8 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -154,7 +154,6 @@ const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; // attachment constants const S32 MAX_AGENT_ATTACHMENTS = 38; -const S32 MAX_AGENT_ANIMATED_OBJECT_ATTACHMENTS = 1; const U8 ATTACHMENT_ADD = 0x80; // god levels diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index c2a0393170..92c2be4a8b 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4021,6 +4021,33 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } +F32 LLMeshRepository::getEstTrianglesHigh(LLUUID mesh_id) +{ + F32 triangles_high = 0.f; + if (mThread && mesh_id.notNull()) + { + LLMutexLock lock(mThread->mHeaderMutex); + LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); + if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + { + LLSD& header = iter->second; + if (header.has("404") + || !header.has("lowest_lod") + || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)) + { + return 0.f; + } + + S32 bytes_high = header["high_lod"]["size"].asInteger(); + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" + F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + } + } + return triangles_high; +} + F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { if (mThread && mesh_id.notNull()) diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 23af837f6f..28f037b85e 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -472,6 +472,7 @@ public: static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events + F32 getEstTrianglesHigh(LLUUID mesh_id); F32 getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 3e8d8883e0..d3f240ac91 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -663,6 +663,10 @@ void LLSelectMgr::confirmUnlinkObjects(const LLSD& notification, const LLSD& res // otherwise. this allows the handle_link method to more finely check // the selection and give an error message when the uer has a // reasonable expectation for the link to work, but it will fail. +// +// AXON - additional check that if the selection includes at least one +// animated object, the total mesh triangle count cannot exceed the +// designated limit. bool LLSelectMgr::enableLinkObjects() { bool new_value = false; @@ -687,6 +691,10 @@ bool LLSelectMgr::enableLinkObjects() new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); } } + if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectEstTris()) + { + new_value = false; + } return new_value; } @@ -7421,6 +7429,27 @@ bool LLObjectSelection::applyToObjects(LLSelectedObjectFunctor* func) return result; } +bool LLObjectSelection::checkAnimatedObjectEstTris() +{ + F32 est_tris = 0; + F32 max_tris = 0; + S32 anim_count = 0; + for (root_iterator iter = root_begin(); iter != root_end(); ) + { + root_iterator nextiter = iter++; + LLViewerObject* object = (*nextiter)->getObject(); + if (!object) + continue; + if (object->isAnimatedObject()) + { + anim_count++; + } + est_tris += object->recursiveGetEstTrianglesHigh(); + max_tris = llmax((F32)max_tris,(F32)object->getAnimatedObjectMaxTris()); + } + return anim_count==0 || est_tris <= max_tris; +} + bool LLObjectSelection::applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly) { bool result = firstonly ? false : true; diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index fc4b920c51..4e79cb003d 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -339,6 +339,9 @@ public: // returns TRUE is any node is currenly worn as an attachment BOOL isAttachment(); + // AXON validate a potential link against limits + bool checkAnimatedObjectEstTris(); + // Apply functors to various subsets of the selected objects // If firstonly is FALSE, returns the AND of all apply() calls. // Else returns TRUE immediately if any apply() call succeeds (i.e. OR with early exit) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 34e7bc0fad..0140a63e73 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3580,6 +3580,38 @@ F32 LLViewerObject::getLinksetPhysicsCost() return mLinksetPhysicsCost; } +F32 LLViewerObject::recursiveGetEstTrianglesHigh() const +{ + F32 est_tris = getEstTrianglesHigh(); + for (child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + const LLViewerObject* child = *iter; + est_tris += child->recursiveGetEstTrianglesHigh(); + } + return est_tris; +} + +S32 LLViewerObject::getAnimatedObjectMaxTris() const +{ + S32 max_tris = 0; + LLSD features; + if (getRegion()) + { + getRegion()->getSimulatorFeatures(features); + if (features.has("AnimatedObjects")) + { + max_tris = features["AnimatedObjects"]["AnimatedObjectMaxTris"].asInteger(); + } + } + return max_tris; +} + +F32 LLViewerObject::getEstTrianglesHigh() const +{ + return 0.f; +} + F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const { return 0.f; @@ -3698,7 +3730,6 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) } } - void LLViewerObject::setLineWidthForWindowSize(S32 window_width) { if (window_width < 700) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index c79ff7bb74..a1a7eed002 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -357,6 +357,9 @@ public: virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); + S32 getAnimatedObjectMaxTris() const; + F32 recursiveGetEstTrianglesHigh() const; + virtual F32 getEstTrianglesHigh() const; virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; virtual U32 getTriangleCount(S32* vcount = NULL) const; virtual U32 getHighLODTriangleCount(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 5e0c5d6858..ac5d1b335c 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -6602,13 +6602,32 @@ U32 LLVOAvatar::getNumAnimatedObjectAttachments() const return num_attachments; } +//----------------------------------------------------------------------------- +// getMaxAnimatedObjectAttachments() +// Gets from simulator feature if available, otherwise 0. +//----------------------------------------------------------------------------- +S32 LLVOAvatar::getMaxAnimatedObjectAttachments() const +{ + S32 max_attach = 0; + LLSD features; + if (getRegion()) + { + getRegion()->getSimulatorFeatures(features); + if (features.has("AnimatedObjects")) + { + max_attach = features["AnimatedObjects"]["MaxAgentAnimatedObjectAttachments"].asInteger(); + } + } + return max_attach; +} + //----------------------------------------------------------------------------- // canAttachMoreAnimatedObjects() // Returns true if we can attach more animated objects. //----------------------------------------------------------------------------- BOOL LLVOAvatar::canAttachMoreAnimatedObjects(U32 n) const { - return (getNumAnimatedObjectAttachments() + n) <= MAX_AGENT_ANIMATED_OBJECT_ATTACHMENTS; + return (getNumAnimatedObjectAttachments() + n) <= getMaxAnimatedObjectAttachments(); } //----------------------------------------------------------------------------- diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 1a87a62946..5a40a45eae 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -778,6 +778,7 @@ public: LLBBox getHUDBBox() const; void resetHUDAttachments(); BOOL canAttachMoreObjects(U32 n=1) const; + S32 getMaxAnimatedObjectAttachments() const; BOOL canAttachMoreAnimatedObjects(U32 n=1) const; protected: U32 getNumAttachments() const; // O(N), not O(1) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 403bff5a9e..07032ca0ae 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3349,22 +3349,25 @@ bool LLVOVolume::canBeAnimatedObject() const { return false; } -// AXON remove this check if animated object attachments are allowed -#if 0 - if (isAttachment()) - { - return false; - } -#endif if (!getVolume()) { return false; } + if (!isRootEdit()) + { + return false; + } const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this); if (!skin) { return false; } + F32 est_tris = recursiveGetEstTrianglesHigh(); + if (est_tris > getAnimatedObjectMaxTris()) + { + LL_INFOS() << "est_tris " << est_tris << " exceeds limit " << getAnimatedObjectMaxTris() << LL_ENDL; + return false; + } return true; } @@ -3833,6 +3836,15 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const return (U32)shame; } +F32 LLVOVolume::getEstTrianglesHigh() const +{ + if (isMesh()) + { + return gMeshRepo.getEstTrianglesHigh(getVolume()->getParams().getSculptID()); + } + return 0.f; +} + F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const { F32 radius = getScale().length()*0.5f; diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index c972d7770e..5891b36da8 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -134,6 +134,7 @@ public: /*virtual*/ const LLMatrix4 getRenderMatrix() const; typedef std::map texture_cost_t; U32 getRenderCost(texture_cost_t &textures) const; + /*virtual*/ F32 getEstTrianglesHigh() const; F32 getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const; /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL) { return getStreamingCost(bytes, visible_bytes, NULL); } diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 50013656ca..0223d20f0f 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -10620,6 +10620,29 @@ You are not allowed to change this shape. Operation would cause the number of attached animated objects to exceed the limit. + + fail +Can't link these objects because the resulting animated object would exceed the size limit. + + + + fail +Can't make this object into an animated object because it would exceed the size limit. + + + + fail +Server error: cannot complete this operation because mesh data is not loaded. + Date: Fri, 29 Sep 2017 19:08:41 +0100 Subject: SL-794 - use largest LOD for est tri count, instead of trusting that it's always the high LOD --- indra/newview/llmeshrepository.cpp | 13 +++++++++---- indra/newview/llmeshrepository.h | 3 ++- indra/newview/llselectmgr.cpp | 2 +- indra/newview/llviewerobject.cpp | 8 ++++---- indra/newview/llviewerobject.h | 4 ++-- indra/newview/llvovolume.cpp | 19 +++++++++++-------- indra/newview/llvovolume.h | 2 +- 7 files changed, 30 insertions(+), 21 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 92c2be4a8b..093afdb880 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4021,9 +4021,9 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } -F32 LLMeshRepository::getEstTrianglesHigh(LLUUID mesh_id) +F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) { - F32 triangles_high = 0.f; + F32 triangles_max = 0.f; if (mThread && mesh_id.notNull()) { LLMutexLock lock(mThread->mHeaderMutex); @@ -4039,13 +4039,18 @@ F32 LLMeshRepository::getEstTrianglesHigh(LLUUID mesh_id) } S32 bytes_high = header["high_lod"]["size"].asInteger(); + S32 bytes_med = header["medium_lod"]["size"].asInteger(); + S32 bytes_low = header["low_lod"]["size"].asInteger(); + S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + S32 bytes_max = llmax(bytes_high, bytes_med, bytes_low, bytes_lowest); + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); - triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + triangles_max = llmax((F32) bytes_max-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; } } - return triangles_high; + return triangles_max; } F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 28f037b85e..d2eac449f7 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -472,7 +472,8 @@ public: static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events - F32 getEstTrianglesHigh(LLUUID mesh_id); + // Estimated triangle count of the largest LOD + F32 getEstTrianglesMax(LLUUID mesh_id); F32 getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index d3f240ac91..81fd228997 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -7444,7 +7444,7 @@ bool LLObjectSelection::checkAnimatedObjectEstTris() { anim_count++; } - est_tris += object->recursiveGetEstTrianglesHigh(); + est_tris += object->recursiveGetEstTrianglesMax(); max_tris = llmax((F32)max_tris,(F32)object->getAnimatedObjectMaxTris()); } return anim_count==0 || est_tris <= max_tris; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 99c68dab10..616db8ae2f 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3580,14 +3580,14 @@ F32 LLViewerObject::getLinksetPhysicsCost() return mLinksetPhysicsCost; } -F32 LLViewerObject::recursiveGetEstTrianglesHigh() const +F32 LLViewerObject::recursiveGetEstTrianglesMax() const { - F32 est_tris = getEstTrianglesHigh(); + F32 est_tris = getEstTrianglesMax(); for (child_list_t::const_iterator iter = mChildList.begin(); iter != mChildList.end(); iter++) { const LLViewerObject* child = *iter; - est_tris += child->recursiveGetEstTrianglesHigh(); + est_tris += child->recursiveGetEstTrianglesMax(); } return est_tris; } @@ -3607,7 +3607,7 @@ S32 LLViewerObject::getAnimatedObjectMaxTris() const return max_tris; } -F32 LLViewerObject::getEstTrianglesHigh() const +F32 LLViewerObject::getEstTrianglesMax() const { return 0.f; } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index a1a7eed002..345fd1fb27 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -358,8 +358,8 @@ public: virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); S32 getAnimatedObjectMaxTris() const; - F32 recursiveGetEstTrianglesHigh() const; - virtual F32 getEstTrianglesHigh() const; + F32 recursiveGetEstTrianglesMax() const; + virtual F32 getEstTrianglesMax() const; virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; virtual U32 getTriangleCount(S32* vcount = NULL) const; virtual U32 getHighLODTriangleCount(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 121fb9c11e..efddc9235e 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3376,7 +3376,7 @@ bool LLVOVolume::canBeAnimatedObject() const { return false; } - F32 est_tris = recursiveGetEstTrianglesHigh(); + F32 est_tris = recursiveGetEstTrianglesMax(); if (est_tris > getAnimatedObjectMaxTris()) { LL_INFOS() << "est_tris " << est_tris << " exceeds limit " << getAnimatedObjectMaxTris() << LL_ENDL; @@ -3388,12 +3388,15 @@ bool LLVOVolume::canBeAnimatedObject() const bool LLVOVolume::isAnimatedObject() const { LLVOVolume *root_vol = (LLVOVolume*)getRootEdit(); - bool can_be_animated = canBeAnimatedObject(); - bool root_can_be_animated = root_vol->canBeAnimatedObject(); - bool root_is_animated = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; - if (can_be_animated && root_can_be_animated && root_is_animated) + bool root_is_animated_flag = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + if (root_is_animated_flag) { - return true; + bool root_can_be_animated = root_vol->canBeAnimatedObject(); + bool this_can_be_animated = ((root_vol == this) && root_can_be_animated) || canBeAnimatedObject(); + if (this_can_be_animated && root_can_be_animated) + { + return true; + } } return false; } @@ -3852,11 +3855,11 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const return (U32)shame; } -F32 LLVOVolume::getEstTrianglesHigh() const +F32 LLVOVolume::getEstTrianglesMax() const { if (isMesh()) { - return gMeshRepo.getEstTrianglesHigh(getVolume()->getParams().getSculptID()); + return gMeshRepo.getEstTrianglesMax(getVolume()->getParams().getSculptID()); } return 0.f; } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 5891b36da8..24bcf41c74 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -134,7 +134,7 @@ public: /*virtual*/ const LLMatrix4 getRenderMatrix() const; typedef std::map texture_cost_t; U32 getRenderCost(texture_cost_t &textures) const; - /*virtual*/ F32 getEstTrianglesHigh() const; + /*virtual*/ F32 getEstTrianglesMax() const; F32 getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const; /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL) { return getStreamingCost(bytes, visible_bytes, NULL); } -- cgit v1.3 From ae40b68ba7fb9ea9c308c0dcb01d19e3d218aeaa Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 1 Nov 2017 22:07:42 +0100 Subject: SL-830, SL-831 - no linking if any of the roots is animated object. isAnimatedObject() just uses check against extended mesh flag of the root. On select, LLVOVolume marks whole linkset for update if animated object. --- indra/newview/llselectmgr.cpp | 21 +++++++++++++++++---- indra/newview/llselectmgr.h | 1 + indra/newview/llviewermessage.cpp | 2 +- indra/newview/llvovolume.cpp | 18 ++++++++++++++---- 4 files changed, 33 insertions(+), 9 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 81fd228997..e8b2d1ec8c 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -691,7 +691,7 @@ bool LLSelectMgr::enableLinkObjects() new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); } } - if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectEstTris()) + if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable()) { new_value = false; } @@ -7434,10 +7434,9 @@ bool LLObjectSelection::checkAnimatedObjectEstTris() F32 est_tris = 0; F32 max_tris = 0; S32 anim_count = 0; - for (root_iterator iter = root_begin(); iter != root_end(); ) + for (root_iterator iter = root_begin(); iter != root_end(); ++iter) { - root_iterator nextiter = iter++; - LLViewerObject* object = (*nextiter)->getObject(); + LLViewerObject* object = (*iter)->getObject(); if (!object) continue; if (object->isAnimatedObject()) @@ -7450,6 +7449,20 @@ bool LLObjectSelection::checkAnimatedObjectEstTris() return anim_count==0 || est_tris <= max_tris; } +bool LLObjectSelection::checkAnimatedObjectLinkable() +{ + // Can't link if any of the roots is currently an animated object + for (root_iterator iter = root_begin(); iter != root_end(); ++iter) + { + LLViewerObject* objectp = (*iter)->getObject(); + if (objectp && objectp->isAnimatedObject()) + { + return false; + } + } + return true; +} + bool LLObjectSelection::applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly) { bool result = firstonly ? false : true; diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 4e79cb003d..fcbfd5fccd 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -341,6 +341,7 @@ public: // AXON validate a potential link against limits bool checkAnimatedObjectEstTris(); + bool checkAnimatedObjectLinkable(); // Apply functors to various subsets of the selected objects // If firstonly is FALSE, returns the AND of all apply() calls. diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 3834082f78..0f567ba5ac 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5113,7 +5113,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); LL_DEBUGS("AXON") << "processing object animation requests, num_blocks " << num_blocks << LL_ENDL; -#if 0 +#if 1 if (!avatarp->mPlaying) { avatarp->mPlaying = true; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 004f335a5a..bb28d5d83e 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3413,6 +3413,8 @@ bool LLVOVolume::isAnimatedObject() const { LLVOVolume *root_vol = (LLVOVolume*)getRootEdit(); bool root_is_animated_flag = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + return root_is_animated_flag; +#if 0 if (root_is_animated_flag) { bool root_can_be_animated = root_vol->canBeAnimatedObject(); @@ -3423,6 +3425,7 @@ bool LLVOVolume::isAnimatedObject() const } } return false; +#endif } // Make sure animated objects in a linkset are consistent. The rules are: @@ -4008,10 +4011,17 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u void LLVOVolume::setSelected(BOOL sel) { LLViewerObject::setSelected(sel); - if (mDrawable.notNull()) - { - markForUpdate(TRUE); - } + if (isAnimatedObject()) + { + getRootEdit()->recursiveMarkForUpdate(TRUE); + } + else + { + if (mDrawable.notNull()) + { + markForUpdate(TRUE); + } + } } void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) -- cgit v1.3 From c7a0b25977a5ca30fc1726370f6363349ff9f836 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 8 Nov 2017 19:56:09 +0000 Subject: SL-831 - animesh objects are not required to have any tris. If they have no tris, we don't bother making a control avatar for them. --- indra/newview/llselectmgr.cpp | 3 ++- indra/newview/llvovolume.cpp | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index e8b2d1ec8c..f666f447cb 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -691,7 +691,7 @@ bool LLSelectMgr::enableLinkObjects() new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); } } - if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable()) + if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectEstTris()) { new_value = false; } @@ -7451,6 +7451,7 @@ bool LLObjectSelection::checkAnimatedObjectEstTris() bool LLObjectSelection::checkAnimatedObjectLinkable() { + LL_ERRS() << "Not using this restriction" << LL_ENDL; // Can't link if any of the roots is currently an animated object for (root_iterator iter = root_begin(); iter != root_end(); ++iter) { diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 9d98822082..54029f75fd 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3410,9 +3410,9 @@ void LLVOVolume::setExtendedMeshFlags(U32 flags) bool LLVOVolume::canBeAnimatedObject() const { F32 est_tris = recursiveGetEstTrianglesMax(); - if (est_tris <= 0 || est_tris > getAnimatedObjectMaxTris()) + if (est_tris < 0 || est_tris > getAnimatedObjectMaxTris()) { - LL_DEBUGS("AXON") << "est_tris " << est_tris << " is outside limit of 1-" << getAnimatedObjectMaxTris() << LL_ENDL; + LL_DEBUGS("AXON") << "est_tris " << est_tris << " is outside limit of 0-" << getAnimatedObjectMaxTris() << LL_ENDL; return false; } return true; @@ -5138,8 +5138,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (!vobj->getControlAvatar()) { - LL_DEBUGS("AXON") << vobj_name << " calling linkControlAvatar()" << LL_ENDL; - vobj->linkControlAvatar(); + F32 tri_count = vobj->getRootEdit()->recursiveGetEstTrianglesMax(); + if (tri_count <= 0.f) + { + LL_DEBUGS("AXON") << vobj_name << " not calling linkControlAvatar(), because no tris" << LL_ENDL; + } + else + { + LL_DEBUGS("AXON") << vobj_name << " calling linkControlAvatar()" << LL_ENDL; + vobj->linkControlAvatar(); + } } if (vobj->getControlAvatar()) { -- cgit v1.3 From 2f1b75f03e8066b54d9dae16ab29095752c4ee8a Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 16 Nov 2017 19:24:53 +0000 Subject: SL-704 - first pass cleaning up comments. Also added LLControlAvatar::initInstance() as a potential hook for optimizations. --- indra/newview/llcontrolavatar.cpp | 8 +++++++- indra/newview/llcontrolavatar.h | 1 + indra/newview/lldrawpoolavatar.cpp | 1 - indra/newview/llpanelobject.cpp | 3 ++- indra/newview/llpanelvolume.cpp | 3 --- indra/newview/llselectmgr.cpp | 6 +++--- indra/newview/llviewermessage.cpp | 13 +++++++------ indra/newview/llviewerobject.cpp | 2 +- indra/newview/llvoavatar.cpp | 22 +++++++++++----------- indra/newview/llvograss.cpp | 1 - indra/newview/llvovolume.cpp | 17 ++++------------- indra/newview/llvovolume.h | 3 --- indra/newview/pipeline.cpp | 1 - 13 files changed, 36 insertions(+), 45 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 848a8b0d40..afa6be188d 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -49,6 +49,13 @@ LLControlAvatar::~LLControlAvatar() { } +// virtual +void LLControlAvatar::initInstance() +{ + // AXON - potential optimizations here - avoid creating system avatar mesh since it's not used. + LLVOAvatar::initInstance(); +} + void LLControlAvatar::matchVolumeTransform() { if (mRootVolp) @@ -173,7 +180,6 @@ void LLControlAvatar::updateVolumeGeom() LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj) { - // AXON Lifted from LLPreviewAnimation LLControlAvatar *cav = (LLControlAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), CO_FLAG_CONTROL_AVATAR); cav->mRootVolp = obj; diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h index 308d431615..a0f7912d24 100644 --- a/indra/newview/llcontrolavatar.h +++ b/indra/newview/llcontrolavatar.h @@ -37,6 +37,7 @@ class LLControlAvatar: public: LLControlAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); + virtual void initInstance(); // Called after construction to initialize the class. virtual ~LLControlAvatar(); void matchVolumeTransform(); diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 30560eeb7b..206d4f4c7a 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -467,7 +467,6 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) } LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); -// AXON fix if (avatarp->isDead() || (avatarp->mIsDummy && !avatarp->isControlAvatar()) || avatarp->mDrawable.isNull()) { return; diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 43d6245a63..8f2cf5bb89 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -343,7 +343,8 @@ void LLPanelObject::getState( ) // can move or rotate only linked group with move permissions, or sub-object with move and modify perms - // AXON it's not entirely clear what the motivation is to have 3 + // AXON REVIEW BEFORE RELEASE, behavior during edit is glitchy. + // it's not entirely clear what the motivation is to have 3 // different rules for enablement. At least the difference between // move and rotate looks like just a parens error, have updated accordingly. BOOL enable_move = objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && ((objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts")); diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 6a71da3918..5c4c430f83 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -361,9 +361,6 @@ void LLPanelVolume::getState( ) // Animated Mesh BOOL is_animated_mesh = single_root_volume && root_volobjp && root_volobjp->isAnimatedObject(); getChild("Animated Mesh Checkbox Ctrl")->setValue(is_animated_mesh); - // AXON FIXME CHECK FOR SKIN INFO ALSO - // WHAT ABOUT isPermanentEnforced? - // What about linksets with some skinned objects? BOOL enabled_animated_object_box = FALSE; if (root_volobjp && root_volobjp == volobjp) { diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index f666f447cb..473d7e5b5f 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -664,9 +664,9 @@ void LLSelectMgr::confirmUnlinkObjects(const LLSD& notification, const LLSD& res // the selection and give an error message when the uer has a // reasonable expectation for the link to work, but it will fail. // -// AXON - additional check that if the selection includes at least one -// animated object, the total mesh triangle count cannot exceed the -// designated limit. +// For animated objects, there's additional check that if the +// selection includes at least one animated object, the total mesh +// triangle count cannot exceed the designated limit. bool LLSelectMgr::enableLinkObjects() { bool new_value = false; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 0b2931886a..7260d7f928 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5106,7 +5106,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) LLControlAvatar *avatarp = volp->getControlAvatar(); if (!avatarp) { - LL_WARNS() << "AXON no control avatar, ignoring" << LL_ENDL; + LL_WARNS("Messaging") << "AXON no control avatar, ignoring" << LL_ENDL; return; } @@ -5120,17 +5120,19 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) if (!avatarp->mPlaying) { avatarp->mPlaying = true; - avatarp->updateVolumeGeom(); - avatarp->mRootVolp->recursiveMarkForUpdate(TRUE); + if (!avatarp->mRootVolp->isAnySelected()) + { + avatarp->updateVolumeGeom(); + avatarp->mRootVolp->recursiveMarkForUpdate(TRUE); + } } #else - // AXON + // AXON REMOVE BEFORE RELEASE? // In this block we switch back into static mode when no animations are // playing. This is mostly useful for debugging. if (num_blocks > 0 && !avatarp->mPlaying) { avatarp->mPlaying = true; - // AXON need to update all objects in the linkset, not just the one where animation is playing if (!avatarp->mRootVolp->isAnySelected()) { avatarp->updateVolumeGeom(); @@ -5140,7 +5142,6 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) else if (num_blocks == 0 && avatarp->mPlaying) { avatarp->mPlaying = false; - // AXON need to update all objects in the linkset, not just the one where animation is playing if (!avatarp->mRootVolp->isAnySelected()) { avatarp->updateVolumeGeom(); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 3435217fa4..7d370aff35 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3609,7 +3609,7 @@ F32 LLViewerObject::recursiveGetEstTrianglesMax() const S32 LLViewerObject::getAnimatedObjectMaxTris() const { S32 max_tris = 0; - // AXON remove after server testing done + // AXON REMOVE AFTER SERVER TESTING DONE if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) { max_tris = S32_MAX; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index cdbe87de75..ea7214d937 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1108,7 +1108,7 @@ void LLVOAvatar::cleanupClass() } // virtual -void LLVOAvatar::initInstance(void) +void LLVOAvatar::initInstance() { //------------------------------------------------------------------------- // register motions @@ -3470,7 +3470,7 @@ void LLVOAvatar::updateDebugText() LLVOVolume *volp = control_av->mRootVolp; if (volp) { - volp->requestInventory(); // AXON should be a no-op if already requested or fetched? + volp->requestInventory(); LLViewerInventoryItem* item = volp->getInventoryItemByAsset(motionp->getID()); if (item) { @@ -3658,10 +3658,9 @@ void LLVOAvatar::updateFootstepSounds() void LLVOAvatar::computeUpdatePeriod() { bool visually_muted = isVisuallyMuted(); - // AXON FIXME this expression is a crawling horror if (mDrawable.notNull() && isVisible() - && (!isSelf() || visually_muted) // AXON would the self ever be visually muted? + && (!isSelf() || visually_muted) && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate @@ -3881,7 +3880,8 @@ void LLVOAvatar::updateTimeStep() bool is_pure_dummy = mIsDummy && !isControlAvatar(); if (!isSelf() && !is_pure_dummy) // ie, non-self avatars, and animated objects will be affected. { - // AXON note that sInstances counts animated objects and standard avatars in the same bucket. Is this desirable? + // AXON note that sInstances counts animated objects and + // standard avatars in the same bucket. Is this desirable? F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f); F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f); F32 time_step = time_quantum * pixel_area_scale; @@ -3999,7 +3999,9 @@ void LLVOAvatar::updateRootPositionAndRotation(LLAgent& agent, F32 speed, bool w //-------------------------------------------------------------------- if (!isControlAvatar() && !isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS)) { - // AXON - should we always skip for control avatars? Rotation fixups for avatars in motion, some may be relevant. + // AXON - should we always skip for control avatars? + // Rotation fixups for avatars in motion, some may be + // relevant. updateOrientation(agent, speed, delta_time); } } @@ -5999,7 +6001,6 @@ void LLVOAvatar::showAttachmentOverrides(bool verbose) const //----------------------------------------------------------------------------- // removeAttachmentOverridesForObject //----------------------------------------------------------------------------- -// AXON handle NPC case void LLVOAvatar::removeAttachmentOverridesForObject(LLViewerObject *vo) { if (vo->getAvatar() != this && vo->getAvatarAncestor() != this) @@ -6028,7 +6029,6 @@ void LLVOAvatar::removeAttachmentOverridesForObject(LLViewerObject *vo) //----------------------------------------------------------------------------- // removeAttachmentOverridesForObject //----------------------------------------------------------------------------- -// AXON handle NPC case void LLVOAvatar::removeAttachmentOverridesForObject(const LLUUID& mesh_id) { //Subsequent joints are relative to pelvis @@ -6107,7 +6107,7 @@ void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_age LLVector3d z_vec(0.0f, 0.0f, 1.0f); LLVector3d p0_global, p1_global; - // AXON update for control avs? + // AXON UPDATE FOR CONTROL AVS? if (mIsDummy) { outNorm.setVec(z_vec); @@ -6137,7 +6137,7 @@ F32 LLVOAvatar::getTimeDilation() //----------------------------------------------------------------------------- F32 LLVOAvatar::getPixelArea() const { - // AXON update for control avatars + // AXON UPDATE FOR CONTROL AVATARS if (mIsDummy) { return 100000.f; @@ -6675,7 +6675,7 @@ U32 LLVOAvatar::getNumAnimatedObjectAttachments() const S32 LLVOAvatar::getMaxAnimatedObjectAttachments() const { S32 max_attach = 0; - // AXON remove after server testing done + // AXON REMOVE AFTER SERVER TESTING DONE if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) { max_attach = MAX_AGENT_ATTACHMENTS; diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 337f969f3d..5def0f0c0f 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -92,7 +92,6 @@ LLVOGrass::~LLVOGrass() void LLVOGrass::updateSpecies() { - // AXON is grass still even supported? This use of state seems odd. mSpecies = getAttachmentState(); if (!sSpeciesTable.count(mSpecies)) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 54029f75fd..96f2255265 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -91,7 +91,6 @@ U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 1; BOOL gAnimateTextures = TRUE; //extern BOOL gHideSelectedObjects; -// AXON TEMP S32 LLVOVolume::sForceLOD = -1; F32 LLVOVolume::sLODFactor = 1.f; F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop @@ -1234,7 +1233,7 @@ void LLVOVolume::sculpt() S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius) { S32 cur_detail; - // AXON TEMP + // AXON TEMP REMOVE if (LLVOVolume::sForceLOD>=0 && LLVOVolume::sForceLOD<=3) { cur_detail = LLVOVolume::sForceLOD; @@ -3341,8 +3340,6 @@ BOOL LLVOVolume::isRiggedMesh() const } //---------------------------------------------------------------------------- -// AXON - methods related to extended mesh flags - U32 LLVOVolume::getExtendedMeshFlags() const { const LLExtendedMeshParams *param_block = @@ -3412,7 +3409,6 @@ bool LLVOVolume::canBeAnimatedObject() const F32 est_tris = recursiveGetEstTrianglesMax(); if (est_tris < 0 || est_tris > getAnimatedObjectMaxTris()) { - LL_DEBUGS("AXON") << "est_tris " << est_tris << " is outside limit of 0-" << getAnimatedObjectMaxTris() << LL_ENDL; return false; } return true; @@ -3441,6 +3437,8 @@ bool LLVOVolume::isAnimatedObject() const // Only the root of a linkset can have the animated object flag set // Only the root of a linkset can have a control avatar (iff the animated object flag is set) // Only skinned mesh volumes can have the animated object flag set, or a control avatar +// +// AXON REVIEW BASED ON FINAL RULES bool LLVOVolume::isAnimatedObjectStateConsistent() const { if (!canBeAnimatedObject()) @@ -3486,16 +3484,9 @@ void LLVOVolume::updateAnimatedObjectStateOnReparent(LLViewerObject *old_parent, // AXON - depending on whether animated objects can be attached, // we may want to include or remove the isAvatar() check. + // BUG?? if (new_parent && !new_parent->isAvatar()) { -#if 0 // AXON - MAINT-7819 - // Object should inherit control avatar and animated mesh flag - // from parent, so clear them out from our own state - if (getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG) - { - setExtendedMeshFlags(getExtendedMeshFlags() & ~LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG); - } -#endif if (mControlAvatar.notNull()) { LLControlAvatar *av = mControlAvatar; diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index f12eb168f6..afeb1c852b 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -281,9 +281,6 @@ public: bool isAnimatedObjectStateConsistent() const; void updateAnimatedObjectStateOnReparent(LLViewerObject *old_parent, LLViewerObject *new_parent); - // AXON For animated objects, we need to track animations requested - // per-object, then reconcile those to manage the control avatar - // animation state. std::map mObjectSignaledAnimations; // requested state of Animation name/value // Functions that deal with media, or media navigation diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 436c0cbf43..bab81f4294 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3352,7 +3352,6 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f { #if 1 // AXON debugging - LLVOVolume *vol_obj = drawablep->getVOVolume(); if (vol_obj && vol_obj->isAnimatedObject() && vol_obj->isRiggedMesh()) { -- cgit v1.3 From 64e5cfc05452993bf15a31d9d4a0deeb1414edf0 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 16 Nov 2017 20:00:38 +0000 Subject: SL-704 - more cleanup, including releaseMeshData() for control avatars, which don't need mesh data. --- indra/newview/llcontrolavatar.cpp | 3 ++- indra/newview/llselectmgr.cpp | 14 ++------------ indra/newview/llselectmgr.h | 1 - indra/newview/llviewermessage.cpp | 3 +-- indra/newview/llviewerobject.cpp | 3 +-- indra/newview/llvoavatar.cpp | 12 ++++++------ 6 files changed, 12 insertions(+), 24 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index afa6be188d..7600bc6959 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -52,7 +52,8 @@ LLControlAvatar::~LLControlAvatar() // virtual void LLControlAvatar::initInstance() { - // AXON - potential optimizations here - avoid creating system avatar mesh since it's not used. + // AXON - potential optimizations here - avoid creating system + // avatar mesh since it's not used. LLVOAvatar::initInstance(); } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 473d7e5b5f..2e489fbc09 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -691,7 +691,7 @@ bool LLSelectMgr::enableLinkObjects() new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); } } - if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectEstTris()) + if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable()) { new_value = false; } @@ -7451,17 +7451,7 @@ bool LLObjectSelection::checkAnimatedObjectEstTris() bool LLObjectSelection::checkAnimatedObjectLinkable() { - LL_ERRS() << "Not using this restriction" << LL_ENDL; - // Can't link if any of the roots is currently an animated object - for (root_iterator iter = root_begin(); iter != root_end(); ++iter) - { - LLViewerObject* objectp = (*iter)->getObject(); - if (objectp && objectp->isAnimatedObject()) - { - return false; - } - } - return true; + return checkAnimatedObjectEstTris(); } bool LLObjectSelection::applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly) diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index fcbfd5fccd..eaeeba576c 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -339,7 +339,6 @@ public: // returns TRUE is any node is currenly worn as an attachment BOOL isAttachment(); - // AXON validate a potential link against limits bool checkAnimatedObjectEstTris(); bool checkAnimatedObjectLinkable(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7260d7f928..ae9798b5d5 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5126,8 +5126,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) avatarp->mRootVolp->recursiveMarkForUpdate(TRUE); } } -#else - // AXON REMOVE BEFORE RELEASE? +#else// AXON REMOVE BEFORE RELEASE? // In this block we switch back into static mode when no animations are // playing. This is mostly useful for debugging. if (num_blocks > 0 && !avatarp->mPlaying) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 7d370aff35..6fff3b0afd 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3609,8 +3609,7 @@ F32 LLViewerObject::recursiveGetEstTrianglesMax() const S32 LLViewerObject::getAnimatedObjectMaxTris() const { S32 max_tris = 0; - // AXON REMOVE AFTER SERVER TESTING DONE - if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) + if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) // AXON REMOVE AFTER SERVER TESTING DONE { max_tris = S32_MAX; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index ea7214d937..b1ae7f543a 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1976,9 +1976,8 @@ void LLVOAvatar::resetSkeleton(bool reset_animations) //----------------------------------------------------------------------------- void LLVOAvatar::releaseMeshData() { - // AXON what should we be doing here for control avs? Why are - // dummies treated differently in the first place? - if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy) + if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || + (mIsDummy && !isControlAvatar())) { return; } @@ -2781,8 +2780,8 @@ void LLVOAvatar::idleUpdateLoadingEffect() LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK | LLPartData::LL_PART_TARGET_POS_MASK ); - // AXON skip cloud effects for dummy avs as well - if (!mIsDummy && !isTooComplex()) // do not generate particles for overly-complex avatars + // do not generate particles for dummy or overly-complex avatars + if (!mIsDummy && !isTooComplex()) { setParticleSource(particle_parameters, getID()); } @@ -4393,7 +4392,8 @@ void LLVOAvatar::updateVisibility() } else { - if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP) + if (mMeshValid && + (isControlAvatar() || mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP)) { releaseMeshData(); } -- cgit v1.3 From 7d91a263a8a634b0148fcd9b1a3af28f7b58ca1c Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 25 Apr 2018 17:10:21 +0100 Subject: MAINT-8549 - more on animesh ARC and associated refactoring --- indra/newview/llfloatermodelpreview.cpp | 6 +- indra/newview/llmeshrepository.cpp | 156 ++++++++++++++++++-------------- indra/newview/llmeshrepository.h | 52 +++++++---- indra/newview/llsceneview.cpp | 19 ++-- indra/newview/llselectmgr.cpp | 12 ++- indra/newview/llviewerobject.cpp | 11 ++- indra/newview/llviewerobject.h | 5 +- indra/newview/llviewerwindow.cpp | 9 +- indra/newview/llvovolume.cpp | 82 ++++++++++++----- indra/newview/llvovolume.h | 4 +- 10 files changed, 231 insertions(+), 125 deletions(-) (limited to 'indra/newview/llselectmgr.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 168fb13d11..1667f01272 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1360,7 +1360,11 @@ U32 LLModelPreview::calcResourceCost() F32 radius = scale.length()*0.5f*debug_scale; - streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); + LLMeshCostData costs; + if (gMeshRepo.getCostData(ret, costs)) + { + streaming_cost += costs.getRadiusBasedStreamingCost(radius); + } } } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 9687376cff..215cdf3394 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4062,53 +4062,12 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } -bool LLMeshRepository::getLODSizes(LLSD& header, std::vector& lod_byte_sizes, std::vector& lod_tri_counts) -{ - lod_byte_sizes.resize(4); - lod_tri_counts.resize(4); - - std::fill(lod_byte_sizes.begin(), lod_byte_sizes.end(), 0); - std::fill(lod_tri_counts.begin(), lod_tri_counts.end(), 0.f); - - S32 bytes_high = header["high_lod"]["size"].asInteger(); - S32 bytes_med = header["medium_lod"]["size"].asInteger(); - if (bytes_med == 0) - { - bytes_med = bytes_high; - } - S32 bytes_low = header["low_lod"]["size"].asInteger(); - if (bytes_low == 0) - { - bytes_low = bytes_med; - } - S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); - if (bytes_lowest == 0) - { - bytes_lowest = bytes_low; - } - lod_byte_sizes[0] = bytes_lowest; - lod_byte_sizes[1] = bytes_low; - lod_byte_sizes[2] = bytes_med; - lod_byte_sizes[3] = bytes_high; - - F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead - F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" - F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); - - for (S32 i=0; i<4; i++) - { - lod_tri_counts[i] = llmax((F32) lod_byte_sizes[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; - } - - return true; -} - F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) { LLMeshCostData costs; if (getCostData(mesh_id, costs)) { - return costs.mEstTrisMax; + return costs.getEstTrisMax(); } else { @@ -4121,7 +4080,7 @@ F32 LLMeshRepository::getEstTrianglesStreamingCost(LLUUID mesh_id) LLMeshCostData costs; if (getCostData(mesh_id, costs)) { - return costs.computeEstTrisForStreamingCost(); + return costs.getEstTrisForStreamingCost(); } else { @@ -4130,7 +4089,7 @@ F32 LLMeshRepository::getEstTrianglesStreamingCost(LLUUID mesh_id) } // FIXME replace with calc based on LLMeshCostData -F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { F32 result = 0.f; if (mThread && mesh_id.notNull()) @@ -4139,7 +4098,7 @@ F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) { - result = getStreamingCost(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); + result = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); } } if (result > 0.f) @@ -4147,8 +4106,8 @@ F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S LLMeshCostData data; if (getCostData(mesh_id, data)) { - F32 ref_streaming_cost = data.computeRadiusBasedStreamingCost(radius); - F32 ref_weighted_tris = data.computeRadiusWeightedTris(radius); + F32 ref_streaming_cost = data.getRadiusBasedStreamingCost(radius); + F32 ref_weighted_tris = data.getRadiusWeightedTris(radius); if (!is_approx_equal(ref_streaming_cost,result)) { LL_WARNS() << mesh_id << "streaming mismatch " << result << " " << ref_streaming_cost << LL_ENDL; @@ -4157,13 +4116,13 @@ F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S { LL_WARNS() << mesh_id << "weighted_tris mismatch " << *unscaled_value << " " << ref_weighted_tris << LL_ENDL; } - if (bytes && (*bytes != data.mSizeTotal)) + if (bytes && (*bytes != data.getSizeTotal())) { - LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.mSizeTotal << LL_ENDL; + LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.getSizeTotal() << LL_ENDL; } - if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.mSizeByLOD[lod])) + if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.getSizeByLOD(lod))) { - LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.mSizeByLOD[lod] << LL_ENDL; + LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.getSizeByLOD(lod) << LL_ENDL; } } else @@ -4176,7 +4135,7 @@ F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S // FIXME replace with calc based on LLMeshCostData //static -F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { if (header.has("404") || !header.has("lowest_lod") @@ -4287,12 +4246,79 @@ LLMeshCostData::LLMeshCostData() std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); +} + +bool LLMeshCostData::init(const LLSD& header) +{ + mSizeByLOD.resize(4); + mEstTrisByLOD.resize(4); + + std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); + std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); - mSizeTotal = 0; - mEstTrisMax = 0; + S32 bytes_high = header["high_lod"]["size"].asInteger(); + S32 bytes_med = header["medium_lod"]["size"].asInteger(); + if (bytes_med == 0) + { + bytes_med = bytes_high; + } + S32 bytes_low = header["low_lod"]["size"].asInteger(); + if (bytes_low == 0) + { + bytes_low = bytes_med; + } + S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + if (bytes_lowest == 0) + { + bytes_lowest = bytes_low; + } + mSizeByLOD[0] = bytes_lowest; + mSizeByLOD[1] = bytes_low; + mSizeByLOD[2] = bytes_med; + mSizeByLOD[3] = bytes_high; + + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" + F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + + for (S32 i=0; i<4; i++) + { + mEstTrisByLOD[i] = llmax((F32) mSizeByLOD[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + } + + return true; } -F32 LLMeshCostData::computeRadiusWeightedTris(F32 radius) + +S32 LLMeshCostData::getSizeByLOD(S32 lod) +{ + if (llclamp(lod,0,3) != lod) + { + return 0; + } + return mSizeByLOD[lod]; +} + +S32 LLMeshCostData::getSizeTotal() +{ + return mSizeByLOD[0] + mSizeByLOD[1] + mSizeByLOD[2] + mSizeByLOD[3]; +} + +F32 LLMeshCostData::getEstTrisByLOD(S32 lod) +{ + if (llclamp(lod,0,3) != lod) + { + return 0.f; + } + return mEstTrisByLOD[lod]; +} + +F32 LLMeshCostData::getEstTrisMax() +{ + return llmax(mEstTrisByLOD[0], mEstTrisByLOD[1], mEstTrisByLOD[2], mEstTrisByLOD[3]); +} + +F32 LLMeshCostData::getRadiusWeightedTris(F32 radius) { F32 max_distance = 512.f; @@ -4336,7 +4362,7 @@ F32 LLMeshCostData::computeRadiusWeightedTris(F32 radius) return weighted_avg; } -F32 LLMeshCostData::computeEstTrisForStreamingCost() +F32 LLMeshCostData::getEstTrisForStreamingCost() { LL_DEBUGS("StreamingCost") << "tris_by_lod: " << mEstTrisByLOD[0] << ", " @@ -4363,14 +4389,14 @@ F32 LLMeshCostData::computeEstTrisForStreamingCost() return charged_tris; } -F32 LLMeshCostData::computeRadiusBasedStreamingCost(F32 radius) +F32 LLMeshCostData::getRadiusBasedStreamingCost(F32 radius) { - return computeRadiusWeightedTris(radius)/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; + return getRadiusWeightedTris(radius)/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; } -F32 LLMeshCostData::computeTriangleBasedStreamingCost() +F32 LLMeshCostData::getTriangleBasedStreamingCost() { - F32 result = ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * computeEstTrisForStreamingCost()/0.06; + F32 result = ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * getEstTrisForStreamingCost(); return result; } @@ -4391,7 +4417,7 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)); if (!header_invalid) { - return getCostData(header, mesh_id, data); + return getCostData(header, data); } return true; @@ -4400,19 +4426,15 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) return false; } -bool LLMeshRepository::getCostData(LLSD& header, LLUUID mesh_id, LLMeshCostData& data) +bool LLMeshRepository::getCostData(LLSD& header, LLMeshCostData& data) { data = LLMeshCostData(); - if (!getLODSizes(header, data.mSizeByLOD, data.mEstTrisByLOD)) + if (!data.init(header)) { return false; } - data.mEstTrisMax = llmax(data.mEstTrisByLOD[0], data.mEstTrisByLOD[1], data.mEstTrisByLOD[2], data.mEstTrisByLOD[3]); - - data.mSizeTotal = data.mSizeByLOD[0] + data.mSizeByLOD[1] + data.mSizeByLOD[2] + data.mSizeByLOD[3]; - return true; } diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index e43f719471..9bf12e9e41 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -452,42 +452,57 @@ private: }; // Params related to streaming cost, render cost, and scene complexity tracking. -struct LLMeshCostData +class LLMeshCostData { +public: LLMeshCostData(); - // From the "size" field of the mesh header. LOD 0=lowest, 3=highest. - std::vector mSizeByLOD; + bool init(const LLSD& header); + + // Size for given LOD + S32 getSizeByLOD(S32 lod); - // Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest. - std::vector mEstTrisByLOD; + // Sum of all LOD sizes. + S32 getSizeTotal(); + // Estimated triangle counts for the given LOD. + F32 getEstTrisByLOD(S32 lod); + // Estimated triangle counts for the largest LOD. Typically this // is also the "high" LOD, but not necessarily. - F32 mEstTrisMax; - - // Sum of all LOD sizes. - S32 mSizeTotal; - - // Helper functions for building data + F32 getEstTrisMax(); // Triangle count as computed by original streaming cost // formula. Triangles in each LOD are weighted based on how // frequently they will be seen. // This was called "unscaled_value" in the original getStreamingCost() functions. - F32 computeRadiusWeightedTris(F32 radius); + F32 getRadiusWeightedTris(F32 radius); // Triangle count used by triangle-based cost formula. Based on // triangles in highest LOD plus potentially partial charges for // lower LODs depending on complexity. - F32 computeEstTrisForStreamingCost(); + F32 getEstTrisForStreamingCost(); // Streaming cost. This should match the server-side calculation // for the corresponding volume. - F32 computeRadiusBasedStreamingCost(F32 radius); + F32 getRadiusBasedStreamingCost(F32 radius); // New streaming cost formula, currently only used for animated objects. - F32 computeTriangleBasedStreamingCost(); + F32 getTriangleBasedStreamingCost(); + +private: + // From the "size" field of the mesh header. LOD 0=lowest, 3=highest. + std::vector mSizeByLOD; + + // Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest. + std::vector mEstTrisByLOD; + + // Estimated triangle counts for the largest LOD. Typically this + // is also the "high" LOD, but not necessarily. + F32 mEstTrisMax; + + // Sum of all LOD sizes. + S32 mSizeTotal; }; class LLMeshRepository @@ -511,14 +526,13 @@ public: static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events - bool getLODSizes(LLSD& header, std::vector& lod_byte_sizes, std::vector& lod_tri_counts); // Estimated triangle count of the largest LOD F32 getEstTrianglesMax(LLUUID mesh_id); F32 getEstTrianglesStreamingCost(LLUUID mesh_id); - F32 getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); - static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + F32 getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + static F32 getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); bool getCostData(LLUUID mesh_id, LLMeshCostData& data); - bool getCostData(LLSD& header, LLUUID mesh_id, LLMeshCostData& data); + bool getCostData(LLSD& header, LLMeshCostData& data); LLMeshRepository(); diff --git a/indra/newview/llsceneview.cpp b/indra/newview/llsceneview.cpp index 112fa5b4e1..f7aa63e34d 100644 --- a/indra/newview/llsceneview.cpp +++ b/indra/newview/llsceneview.cpp @@ -33,6 +33,7 @@ #include "llviewerregion.h" #include "llagent.h" #include "llvolumemgr.h" +#include "llmeshrepository.h" LLSceneView* gSceneView = NULL; @@ -129,17 +130,23 @@ void LLSceneView::draw() visible_triangles[idx].push_back(visible); triangles[idx].push_back(high_triangles); - S32 bytes = 0; - S32 visible_bytes = 0; - - F32 streaming = object->getStreamingCost(&bytes, &visible_bytes); - total_streaming[idx] += streaming; - streaming_cost[idx].push_back(streaming); + F32 streaming = object->getStreamingCost(); + total_streaming[idx] += streaming; + streaming_cost[idx].push_back(streaming); F32 physics = object->getPhysicsCost(); total_physics[idx] += physics; physics_cost[idx].push_back(physics); + S32 bytes = 0; + S32 visible_bytes = 0; + LLMeshCostData costs; + if (object->getCostData(costs)) + { + bytes = costs.getSizeTotal(); + visible_bytes = costs.getSizeByLOD(object->getLOD()); + } + total_bytes[idx] += bytes; total_visible_bytes[idx] += visible_bytes; } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index d29a06f7e5..ce5fc7a71e 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -7252,10 +7252,16 @@ F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* vis if (object) { - S32 bytes = 0; - S32 visible = 0; - cost += object->getStreamingCost(&bytes, &visible); + cost += object->getStreamingCost(); + S32 bytes = 0; + S32 visible = 0; + LLMeshCostData costs; + if (object->getCostData(costs)) + { + bytes = costs.getSizeTotal(); + visible = costs.getSizeByLOD(object->getLOD()); + } if (total_bytes) { *total_bytes += bytes; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 72cb1d4cf6..32a1ccd852 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -106,6 +106,7 @@ #include "llvocache.h" #include "llcleanup.h" #include "llcallstack.h" +#include "llmeshrepository.h" //#define DEBUG_UPDATE_TYPE @@ -3698,11 +3699,19 @@ F32 LLViewerObject::getEstTrianglesStreamingCost() const return 0.f; } -F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +// virtual +F32 LLViewerObject::getStreamingCost() const { return 0.f; } +// virtual +bool LLViewerObject::getCostData(LLMeshCostData& costs) const +{ + costs = LLMeshCostData(); + return false; +} + U32 LLViewerObject::getTriangleCount(S32* vcount) const { return 0; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 2fe14c2fcf..9552d4e99e 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -68,6 +68,8 @@ class LLViewerRegion; class LLViewerTexture; class LLWorld; +class LLMeshCostData; + typedef enum e_object_update_type { OUT_FULL, @@ -366,7 +368,8 @@ public: F32 recursiveGetEstTrianglesMax() const; virtual F32 getEstTrianglesMax() const; virtual F32 getEstTrianglesStreamingCost() const; - virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; + virtual F32 getStreamingCost() const; + virtual bool getCostData(LLMeshCostData& costs) const; virtual U32 getTriangleCount(S32* vcount = NULL) const; virtual U32 getHighLODTriangleCount(); F32 recursiveGetScaledSurfaceArea() const; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index b87a6d14e5..467b0c6fcb 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -546,7 +546,14 @@ public: object_count++; S32 bytes = 0; S32 visible = 0; - cost += object->getStreamingCost(&bytes, &visible); + cost += object->getStreamingCost(); + LLMeshCostData costs; + if (object->getCostData(costs)) + { + bytes = costs.getSizeTotal(); + visible = costs.getSizeByLOD(object->getLOD()); + } + S32 vt = 0; count += object->getTriangleCount(&vt); vcount += vt; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 9db4b3de0c..88f2ba34d3 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3691,16 +3691,25 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const path_params = volume_params.getPathParams(); profile_params = volume_params.getProfileParams(); - F32 weighted_triangles = -1.0; - getStreamingCost(NULL, NULL, &weighted_triangles); - - if (weighted_triangles > 0.0) + LLMeshCostData costs; + if (getCostData(costs)) { - num_triangles = (U32)(weighted_triangles); + if (isAnimatedObject() && isRiggedMesh()) + { + // AXON Scaling here is to make animated object vs + // non-animated object ARC proportional to the + // corresponding calculations for streaming cost. + num_triangles = (ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * costs.getEstTrisForStreamingCost())/0.06; + } + else + { + F32 radius = getScale().length()*0.5f; + num_triangles = costs.getRadiusWeightedTris(radius); + } } } - if (num_triangles == 0) + if (num_triangles <= 0) { num_triangles = 4; } @@ -3888,6 +3897,14 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const shame += media_faces * ARC_MEDIA_FACE_COST; } + // AXON streaming cost for animated objects includes a fixed cost + // per linkset. Add a corresponding charge here translated into + // triangles, but not weighted by any graphics properties. + if (isAnimatedObject() && isRootEdit()) + { + shame += (ANIMATED_OBJECT_BASE_COST/0.06) * 5.0f; + } + if (shame > mRenderComplexity_current) { mRenderComplexity_current = (S32)shame; @@ -3914,33 +3931,50 @@ F32 LLVOVolume::getEstTrianglesStreamingCost() const return 0.f; } -F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +F32 LLVOVolume::getStreamingCost() const { F32 radius = getScale().length()*0.5f; - F32 linkset_base_cost = 0.f; - if (isAnimatedObject() && isRootEdit()) + + LLMeshCostData costs; + if (getCostData(costs)) { - // Root object of an animated object has this to account for skeleton overhead. - linkset_base_cost = ANIMATED_OBJECT_BASE_COST; - } - if (isMesh()) - { - if (isAnimatedObject() && isRiggedMesh()) + if (isAnimatedObject() && isRootEdit()) + { + // Root object of an animated object has this to account for skeleton overhead. + linkset_base_cost = ANIMATED_OBJECT_BASE_COST; + } + if (isMesh()) { - if (unscaled_value) + if (isAnimatedObject() && isRiggedMesh()) { - *unscaled_value = (linkset_base_cost + ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * getEstTrianglesStreamingCost())/0.06; + return linkset_base_cost + costs.getTriangleBasedStreamingCost(); + } + else + { + return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); } - return linkset_base_cost + ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * getEstTrianglesStreamingCost(); } else { - return linkset_base_cost + gMeshRepo.getStreamingCost(getVolume()->getParams().getSculptID(), radius, bytes, visible_bytes, mLOD, unscaled_value); + return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); } - } - else - { + } + else + { + return 0.f; + } +} + +// virtual +bool LLVOVolume::getCostData(LLMeshCostData& costs) const +{ + if (isMesh()) + { + return gMeshRepo.getCostData(getVolume()->getParams().getSculptID(), costs); + } + else + { LLVolume* volume = getVolume(); S32 counts[4]; LLVolume::getLoDTriangleCounts(volume->getParams(), counts); @@ -3951,8 +3985,8 @@ F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_v header["medium_lod"]["size"] = counts[2] * 10; header["high_lod"]["size"] = counts[3] * 10; - return linkset_base_cost + LLMeshRepository::getStreamingCost(header, radius, NULL, NULL, -1, unscaled_value); - } + return gMeshRepo.getCostData(header, costs); + } } //static diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index f6738945d8..3ffb7c140a 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -136,8 +136,8 @@ public: U32 getRenderCost(texture_cost_t &textures) const; /*virtual*/ F32 getEstTrianglesMax() const; /*virtual*/ F32 getEstTrianglesStreamingCost() const; - F32 getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const; - /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL) { return getStreamingCost(bytes, visible_bytes, NULL); } + /* virtual*/ F32 getStreamingCost() const; + /*virtual*/ bool getCostData(LLMeshCostData& costs) const; /*virtual*/ U32 getTriangleCount(S32* vcount = NULL) const; /*virtual*/ U32 getHighLODTriangleCount(); -- cgit v1.3