diff options
-rw-r--r-- | indra/llcommon/indra_constants.h | 1 | ||||
-rw-r--r-- | indra/newview/llmeshrepository.cpp | 27 | ||||
-rw-r--r-- | indra/newview/llmeshrepository.h | 1 | ||||
-rw-r--r-- | indra/newview/llselectmgr.cpp | 29 | ||||
-rw-r--r-- | indra/newview/llselectmgr.h | 3 | ||||
-rw-r--r-- | indra/newview/llviewerobject.cpp | 33 | ||||
-rw-r--r-- | indra/newview/llviewerobject.h | 3 | ||||
-rw-r--r-- | indra/newview/llvoavatar.cpp | 21 | ||||
-rw-r--r-- | indra/newview/llvoavatar.h | 1 | ||||
-rw-r--r-- | indra/newview/llvovolume.cpp | 26 | ||||
-rw-r--r-- | indra/newview/llvovolume.h | 1 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/notifications.xml | 23 |
12 files changed, 159 insertions, 10 deletions
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 @@ -6603,12 +6603,31 @@ U32 LLVOAvatar::getNumAnimatedObjectAttachments() const } //----------------------------------------------------------------------------- +// 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 <n> 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<LLUUID, S32> 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. </notification> + <notification + icon="alertmodal.tga" + name="NoPermsLinkAnimatedObjectTooLarge" + type="notify"> + <tag>fail</tag> +Can't link these objects because the resulting animated object would exceed the size limit. + </notification> + + <notification + icon="alertmodal.tga" + name="NoPermsSetFlagAnimatedObjectTooLarge" + type="notify"> + <tag>fail</tag> +Can't make this object into an animated object because it would exceed the size limit. + </notification> + + <notification + icon="alertmodal.tga" + name="ErrorNoMeshData" + type="notify"> + <tag>fail</tag> +Server error: cannot complete this operation because mesh data is not loaded. + </notification> <notification icon="alertmodal.tga" |