summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorBrad Payne (Vir Linden) <vir@lindenlab.com>2017-09-22 18:04:03 +0100
committerBrad Payne (Vir Linden) <vir@lindenlab.com>2017-09-22 18:04:03 +0100
commita6068419e7fe1a5a0eda007b2e989769c0a92262 (patch)
tree8faf3e8004b6ec1e79d611a86e9c9c131f156702 /indra/newview
parenta634d878098cff98b0622d492f5454a1bd41cff6 (diff)
SL-794, SL-790 - viewer-side enforcement in UI for various animated object limits that are also enforced on the server.
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llmeshrepository.cpp27
-rw-r--r--indra/newview/llmeshrepository.h1
-rw-r--r--indra/newview/llselectmgr.cpp29
-rw-r--r--indra/newview/llselectmgr.h3
-rw-r--r--indra/newview/llviewerobject.cpp33
-rw-r--r--indra/newview/llviewerobject.h3
-rw-r--r--indra/newview/llvoavatar.cpp21
-rw-r--r--indra/newview/llvoavatar.h1
-rw-r--r--indra/newview/llvovolume.cpp26
-rw-r--r--indra/newview/llvovolume.h1
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml23
11 files changed, 159 insertions, 9 deletions
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"