summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt4
-rw-r--r--indra/newview/app_settings/logcontrol.xml1
-rw-r--r--indra/newview/app_settings/settings.xml44
-rw-r--r--indra/newview/llappearancemgr.cpp5
-rw-r--r--indra/newview/llappviewer.cpp1
-rw-r--r--indra/newview/llcontrolavatar.cpp407
-rw-r--r--indra/newview/llcontrolavatar.h83
-rw-r--r--indra/newview/lldrawable.cpp4
-rw-r--r--indra/newview/lldrawpool.cpp2
-rw-r--r--indra/newview/lldrawpoolavatar.cpp57
-rw-r--r--indra/newview/lldrawpoolavatar.h2
-rw-r--r--indra/newview/llface.cpp6
-rw-r--r--indra/newview/llfloaterbvhpreview.cpp8
-rw-r--r--indra/newview/llfloaterimagepreview.cpp9
-rw-r--r--indra/newview/llfloatermodelpreview.cpp19
-rw-r--r--indra/newview/llmeshrepository.cpp32
-rw-r--r--indra/newview/llmeshrepository.h2
-rw-r--r--indra/newview/llpanelobject.cpp16
-rw-r--r--indra/newview/llpanelvolume.cpp54
-rw-r--r--indra/newview/llpanelvolume.h1
-rw-r--r--indra/newview/llselectmgr.cpp103
-rw-r--r--indra/newview/llselectmgr.h7
-rw-r--r--indra/newview/llspatialpartition.cpp10
-rw-r--r--indra/newview/llspatialpartition.h2
-rw-r--r--indra/newview/llstartup.cpp1
-rw-r--r--indra/newview/lltooldraganddrop.cpp2
-rw-r--r--indra/newview/lltoolpie.cpp23
-rw-r--r--indra/newview/lltoolselect.cpp4
-rw-r--r--indra/newview/lltoolselectrect.cpp4
-rw-r--r--indra/newview/lluiavatar.cpp59
-rw-r--r--indra/newview/lluiavatar.h44
-rw-r--r--indra/newview/llviewercontrol.cpp7
-rw-r--r--indra/newview/llviewerjointattachment.cpp19
-rw-r--r--indra/newview/llviewerjointattachment.h1
-rw-r--r--indra/newview/llviewermenu.cpp6
-rw-r--r--indra/newview/llviewermessage.cpp106
-rw-r--r--indra/newview/llviewermessage.h1
-rw-r--r--indra/newview/llviewerobject.cpp269
-rw-r--r--indra/newview/llviewerobject.h41
-rw-r--r--indra/newview/llviewerobjectlist.cpp15
-rw-r--r--indra/newview/llviewerobjectlist.h2
-rw-r--r--indra/newview/llviewerregion.cpp1
-rw-r--r--indra/newview/llviewerwindow.cpp4
-rw-r--r--indra/newview/llvoavatar.cpp1408
-rw-r--r--indra/newview/llvoavatar.h45
-rw-r--r--indra/newview/llvoavatarself.cpp2
-rw-r--r--indra/newview/llvograss.cpp2
-rw-r--r--indra/newview/llvovolume.cpp438
-rw-r--r--indra/newview/llvovolume.h25
-rw-r--r--indra/newview/pipeline.cpp12
-rw-r--r--indra/newview/pipeline.h9
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml18
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml10
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml40
54 files changed, 2747 insertions, 750 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 2100c91cfe..e75ec7b8b7 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -150,6 +150,7 @@ set(viewer_SOURCE_FILES
llcommunicationchannel.cpp
llcompilequeue.cpp
llconfirmationmanager.cpp
+ llcontrolavatar.cpp
llconversationlog.cpp
llconversationloglist.cpp
llconversationloglistitem.cpp
@@ -601,6 +602,7 @@ set(viewer_SOURCE_FILES
lltransientfloatermgr.cpp
lltranslate.cpp
lltwitterconnect.cpp
+ lluiavatar.cpp
lluilistener.cpp
lluploaddialog.cpp
llurl.cpp
@@ -770,6 +772,7 @@ set(viewer_HEADER_FILES
llcommunicationchannel.h
llcompilequeue.h
llconfirmationmanager.h
+ llcontrolavatar.h
llconversationlog.h
llconversationloglist.h
llconversationloglistitem.h
@@ -1215,6 +1218,7 @@ set(viewer_HEADER_FILES
lltranslate.h
lltwitterconnect.h
lluiconstants.h
+ lluiavatar.h
lluilistener.h
lluploaddialog.h
lluploadfloaterobservers.h
diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index ecd7c4bc36..ae57e125bb 100644
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -51,6 +51,7 @@
<key>tags</key>
<array>
<!-- sample entry for debugging specific items
+ <string>AnimatedObjects</string>
<string>Avatar</string>
<string>Inventory</string>
<string>SceneLoadTiming</string>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 4a4f4bfc61..72e21437e7 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2182,6 +2182,39 @@
<key>Value</key>
<string />
</map>
+ <key>DebugAnimatedObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Show info related to animated objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AnimatedObjectsIgnoreLimits</key>
+ <map>
+ <key>Comment</key>
+ <string>Ignore server-enforced limits on animated objects. This is only useful for server testing.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AnimatedObjectsAllowLeftClick</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow left-click interaction with animated objects. Uncertain how much performance impact this will have.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>DebugAvatarAppearanceMessage</key>
<map>
<key>Comment</key>
@@ -10382,6 +10415,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>RenderForceVolumeLOD</key>
+ <map>
+ <key>Comment</key>
+ <string>Override for all volume LODs</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
<key>RenderVolumeLODFactor</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 0fb811a386..9f13a944ac 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/llappviewer.cpp b/indra/newview/llappviewer.cpp
index b33b3a6410..e74ee7154f 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -584,6 +584,7 @@ static void settings_to_globals()
LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures");
+ LLVOVolume::sForceLOD = gSavedSettings.getS32("RenderForceVolumeLOD");
LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor");
LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f;
LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
new file mode 100644
index 0000000000..7270cad0da
--- /dev/null
+++ b/indra/newview/llcontrolavatar.cpp
@@ -0,0 +1,407 @@
+/**
+ * @file llcontrolavatar.cpp
+ * @brief Implementation for special dummy avatar used to drive rigged meshes.
+ *
+ * $LicenseInfo:firstyear=2017&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2017, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llcontrolavatar.h"
+#include "llagent.h" // Get state values from here
+#include "llviewerobjectlist.h"
+#include "pipeline.h"
+#include "llanimationstates.h"
+#include "llviewercontrol.h"
+#include "llmeshrepository.h"
+#include "llviewerregion.h"
+
+LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) :
+ LLVOAvatar(id, pcode, regionp),
+ mPlaying(false),
+ mGlobalScale(1.0f),
+ mMarkedForDeath(false)
+{
+ mIsDummy = TRUE;
+ mIsControlAvatar = true;
+ mEnableDefaultMotions = false;
+}
+
+// virtual
+LLControlAvatar::~LLControlAvatar()
+{
+}
+
+// virtual
+void LLControlAvatar::initInstance()
+{
+ // Potential optimizations here: avoid creating system
+ // avatar mesh content since it's not used. For now we just clean some
+ // things up after the fact in releaseMeshData().
+ LLVOAvatar::initInstance();
+
+ createDrawable(&gPipeline);
+ updateJointLODs();
+ updateGeometry(mDrawable);
+ hideSkirt();
+}
+
+void LLControlAvatar::matchVolumeTransform()
+{
+ if (mRootVolp)
+ {
+ if (mRootVolp->isAttachment())
+ {
+ LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor();
+ if (attached_av)
+ {
+ LLViewerJointAttachment *attach = attached_av->getTargetAttachmentPoint(mRootVolp);
+ setPositionAgent(mRootVolp->getRenderPosition());
+ attach->updateWorldPRSParent();
+ LLVector3 joint_pos = attach->getWorldPosition();
+ LLQuaternion joint_rot = attach->getWorldRotation();
+ LLVector3 obj_pos = mRootVolp->mDrawable->getPosition();
+ LLQuaternion obj_rot = mRootVolp->mDrawable->getRotation();
+ obj_pos.rotVec(joint_rot);
+ mRoot->setWorldPosition(obj_pos + joint_pos);
+ mRoot->setWorldRotation(obj_rot * joint_rot);
+ setRotation(mRoot->getRotation());
+ }
+ else
+ {
+ LL_WARNS_ONCE() << "can't find attached av!" << LL_ENDL;
+ }
+ }
+ else
+ {
+ setPositionAgent(mRootVolp->getRenderPosition());
+ LLQuaternion obj_rot = mRootVolp->getRotation();
+ LLQuaternion result_rot = obj_rot;
+ setRotation(result_rot);
+ mRoot->setWorldRotation(result_rot);
+ mRoot->setPosition(mRootVolp->getRenderPosition());
+ }
+ }
+}
+
+void LLControlAvatar::setGlobalScale(F32 scale)
+{
+ if (scale <= 0.0)
+ {
+ LL_WARNS() << "invalid global scale " << scale << LL_ENDL;
+ return;
+ }
+ if (scale != mGlobalScale)
+ {
+ F32 adjust_scale = scale/mGlobalScale;
+ LL_INFOS() << "scale " << scale << " adjustment " << adjust_scale << LL_ENDL;
+ // should we be scaling from the pelvis or the root?
+ recursiveScaleJoint(mPelvisp,adjust_scale);
+ mGlobalScale = scale;
+ }
+}
+
+void LLControlAvatar::recursiveScaleJoint(LLJoint* joint, F32 factor)
+{
+ joint->setScale(factor * joint->getScale());
+
+ for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
+ iter != joint->mChildren.end(); ++iter)
+ {
+ LLJoint* child = *iter;
+ recursiveScaleJoint(child, factor);
+ }
+}
+
+// Based on LLViewerJointAttachment::setupDrawable(), without the attaching part.
+void LLControlAvatar::updateVolumeGeom()
+{
+ if (!mRootVolp->mDrawable)
+ return;
+ if (mRootVolp->mDrawable->isActive())
+ {
+ mRootVolp->mDrawable->makeStatic(FALSE);
+ }
+ mRootVolp->mDrawable->makeActive();
+ gPipeline.markMoved(mRootVolp->mDrawable);
+ gPipeline.markTextured(mRootVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD
+ mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
+
+ LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ LLViewerObject* childp = *iter;
+ if (childp && childp->mDrawable.notNull())
+ {
+ childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
+ gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD
+ gPipeline.markMoved(childp->mDrawable);
+ }
+ }
+
+ gPipeline.markRebuild(mRootVolp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+ mRootVolp->markForUpdate(TRUE);
+
+ // Note that attachment overrides aren't needed here, have already
+ // been applied at the time the mControlAvatar was created, in
+ // llvovolume.cpp.
+
+ matchVolumeTransform();
+
+ // Initial exploration of allowing scaling skeleton to match root
+ // prim bounding box. If enabled, would probably be controlled by
+ // an additional checkbox and default to off. Not enabled for
+ // initial release.
+
+ // What should the scale be? What we really want is the ratio
+ // between the scale at which the object was originally designed
+ // and rigged, and the scale to which it has been subsequently
+ // modified - for example, if the object has been scaled down by a
+ // factor of 2 then we should use 0.5 as the global scale. But we
+ // don't have the original scale stored anywhere, just the current
+ // scale. Possibilities - 1) remember the original scale
+ // somewhere, 2) add another field to let the user specify the
+ // global scale, 3) approximate the original scale by looking at
+ // the proportions of the skeleton after joint positions have
+ // been applied
+
+ //LLVector3 obj_scale = obj->getScale();
+ //F32 obj_scale_z = llmax(obj_scale[2],0.1f);
+ //setGlobalScale(obj_scale_z/2.0f); // roughly fit avatar height range (2m) into object height
+}
+
+LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj)
+{
+ LLControlAvatar *cav = (LLControlAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), CO_FLAG_CONTROL_AVATAR);
+
+ cav->mRootVolp = obj;
+
+ // Sync up position/rotation with object
+ cav->matchVolumeTransform();
+
+ return cav;
+}
+
+void LLControlAvatar::markForDeath()
+{
+ mMarkedForDeath = true;
+}
+
+void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time)
+{
+ if (mMarkedForDeath)
+ {
+ markDead();
+ mMarkedForDeath = false;
+ }
+ else
+ {
+ LLVOAvatar::idleUpdate(agent,time);
+ }
+}
+
+BOOL LLControlAvatar::updateCharacter(LLAgent &agent)
+{
+ return LLVOAvatar::updateCharacter(agent);
+}
+
+//virtual
+void LLControlAvatar::updateDebugText()
+{
+ if (gSavedSettings.getBOOL("DebugAnimatedObjects"))
+ {
+ S32 total_linkset_count = 0;
+ if (mRootVolp)
+ {
+ total_linkset_count = 1 + mRootVolp->getChildren().size();
+ }
+ std::vector<LLVOVolume*> volumes;
+ getAnimatedVolumes(volumes);
+ S32 animated_volume_count = volumes.size();
+ std::string active_string;
+ std::string type_string;
+ std::string lod_string;
+ S32 total_tris = 0;
+ S32 total_verts = 0;
+ S32 est_tris = 0;
+ for (std::vector<LLVOVolume*>::iterator it = volumes.begin();
+ it != volumes.end(); ++it)
+ {
+ LLVOVolume *volp = *it;
+ S32 verts = 0;
+ total_tris += volp->getTriangleCount(&verts);
+ total_verts += verts;
+ est_tris += volp->getEstTrianglesMax();
+ lod_string += llformat("%d",volp->getLOD());
+ if (volp && volp->mDrawable)
+ {
+ if (volp->mDrawable->isActive())
+ {
+ active_string += "A";
+ }
+ else
+ {
+ active_string += "S";
+ }
+ if (volp->isRiggedMesh())
+ {
+ // Rigged/animateable mesh
+ type_string += "R";
+ }
+ else if (volp->isMesh())
+ {
+ // Static mesh
+ type_string += "M";
+ }
+ else
+ {
+ // Any other prim
+ type_string += "P";
+ }
+ }
+ else
+ {
+ active_string += "-";
+ type_string += "-";
+ }
+ }
+ addDebugText(llformat("CAV obj %d anim %d active %s impost %d",
+ total_linkset_count, animated_volume_count, active_string.c_str(), (S32) isImpostor()));
+ addDebugText(llformat("types %s lods %s", type_string.c_str(), lod_string.c_str()));
+ addDebugText(llformat("tris %d (est %d), verts %d", total_tris, est_tris, total_verts));
+ addDebugText(llformat("pxarea %s", LLStringOps::getReadableNumber(getPixelArea()).c_str()));
+#if 0
+ std::string region_name = "no region";
+ if (mRootVolp->getRegion())
+ {
+ region_name = mRootVolp->getRegion()->getName();
+ }
+ std::string skel_region_name = "skel no region";
+ if (getRegion())
+ {
+ skel_region_name = getRegion()->getName();
+ }
+ addDebugText(llformat("region %x %s skel %x %s",
+ mRootVolp->getRegion(), region_name.c_str(),
+ getRegion(), skel_region_name.c_str()));
+#endif
+
+ }
+ LLVOAvatar::updateDebugText();
+}
+
+void LLControlAvatar::getAnimatedVolumes(std::vector<LLVOVolume*>& volumes)
+{
+ if (!mRootVolp)
+ {
+ return;
+ }
+
+ volumes.push_back(mRootVolp);
+
+ LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ LLViewerObject* childp = *iter;
+ LLVOVolume *child_volp = dynamic_cast<LLVOVolume*>(childp);
+ if (child_volp && child_volp->isAnimatedObject())
+ {
+ volumes.push_back(child_volp);
+ }
+ }
+}
+
+// This is called after an associated object receives an animation
+// message. Combine the signaled animations for all associated objects
+// and process any resulting state changes.
+void LLControlAvatar::updateAnimations()
+{
+ if (!mRootVolp)
+ {
+ LL_WARNS_ONCE("AnimatedObjects") << "No root vol" << LL_ENDL;
+ return;
+ }
+
+ std::vector<LLVOVolume*> volumes;
+ getAnimatedVolumes(volumes);
+
+ // Rebuild mSignaledAnimations from the associated volumes.
+ std::map<LLUUID, S32> anims;
+ for (std::vector<LLVOVolume*>::iterator vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it)
+ {
+ LLVOVolume *volp = *vol_it;
+ for (std::map<LLUUID,S32>::iterator anim_it = volp->mObjectSignaledAnimations.begin();
+ anim_it != volp->mObjectSignaledAnimations.end();
+ ++anim_it)
+ {
+ std::map<LLUUID,S32>::iterator found_anim_it = anims.find(anim_it->first);
+ if (found_anim_it != anims.end())
+ {
+ // Animation already present, use the larger sequence id
+ anims[anim_it->first] = llmax(found_anim_it->second, anim_it->second);
+ }
+ else
+ {
+ // Animation not already present, use this sequence id.
+ anims[anim_it->first] = anim_it->second;
+ }
+ }
+ }
+ mSignaledAnimations = anims;
+
+ processAnimationStateChanges();
+}
+
+// virtual
+LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
+ S32 face,
+ BOOL pick_transparent,
+ BOOL pick_rigged,
+ S32* face_hit,
+ LLVector4a* intersection,
+ LLVector2* tex_coord,
+ LLVector4a* normal,
+ LLVector4a* tangent)
+{
+ LLViewerObject* hit = NULL;
+
+ if (lineSegmentBoundingBox(start, end))
+ {
+ LLVector4a local_end = end;
+ LLVector4a local_intersection;
+
+ if (mRootVolp &&
+ mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent))
+ {
+ local_end = local_intersection;
+ if (intersection)
+ {
+ *intersection = local_intersection;
+ }
+
+ hit = mRootVolp;
+ }
+ }
+
+ return hit;
+}
diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h
new file mode 100644
index 0000000000..a0f7912d24
--- /dev/null
+++ b/indra/newview/llcontrolavatar.h
@@ -0,0 +1,83 @@
+/**
+ * @file llcontrolavatar.h
+ * @brief Special dummy avatar used to drive rigged meshes.
+ *
+ * $LicenseInfo:firstyear=2017&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2017, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_CONTROLAVATAR_H
+#define LL_CONTROLAVATAR_H
+
+#include "llvoavatar.h"
+#include "llvovolume.h"
+
+class LLControlAvatar:
+ public LLVOAvatar
+{
+ LOG_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();
+ void updateVolumeGeom();
+
+ void setGlobalScale(F32 scale);
+ void recursiveScaleJoint(LLJoint *joint, F32 factor);
+ static LLControlAvatar *createControlAvatar(LLVOVolume *obj);
+
+ // Delayed kill so we don't make graphics pipeline unhappy calling
+ // markDead() inside other graphics pipeline operations.
+ void markForDeath();
+
+ virtual void idleUpdate(LLAgent &agent, const F64 &time);
+ virtual BOOL updateCharacter(LLAgent &agent);
+
+ void getAnimatedVolumes(std::vector<LLVOVolume*>& volumes);
+ void updateAnimations();
+
+ virtual LLViewerObject* lineSegmentIntersectRiggedAttachments(
+ const LLVector4a& start, const LLVector4a& end,
+ S32 face = -1, // which face to check, -1 = ALL_SIDES
+ BOOL pick_transparent = FALSE,
+ BOOL pick_rigged = FALSE,
+ S32* face_hit = NULL, // which face was hit
+ LLVector4a* intersection = NULL, // return the intersection point
+ LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
+ LLVector4a* normal = NULL, // return the surface normal at the intersection point
+ LLVector4a* tangent = NULL); // return the surface tangent at the intersection point
+
+ virtual void updateDebugText();
+
+ bool mPlaying;
+
+ F32 mGlobalScale;
+
+ LLVOVolume *mRootVolp;
+
+ bool mMarkedForDeath;
+
+};
+
+#endif //LL_CONTROLAVATAR_H
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index f956023358..6799c3f862 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -50,6 +50,7 @@
#include "llviewerobjectlist.h"
#include "llviewerwindow.h"
#include "llvocache.h"
+#include "llcontrolavatar.h"
const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f;
@@ -550,7 +551,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/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index f74164aea6..1ec8d97f36 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -140,7 +140,7 @@ LLViewerTexture *LLDrawPool::getDebugTexture()
return NULL;
}
-//virtual
+//virtuals
void LLDrawPool::beginRenderPass( S32 pass )
{
}
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 8128790eb6..375704adff 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -109,6 +109,32 @@ LLDrawPoolAvatar::LLDrawPoolAvatar() :
{
}
+LLDrawPoolAvatar::~LLDrawPoolAvatar()
+{
+ if (!isDead())
+ {
+ LL_WARNS() << "Destroying avatar drawpool that still contains faces" << LL_ENDL;
+ }
+}
+
+// virtual
+BOOL LLDrawPoolAvatar::isDead()
+{
+ if (!LLFacePool::isDead())
+ {
+ return FALSE;
+ }
+
+ for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
+ {
+ if (mRiggedFace[i].size() > 0)
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
//-----------------------------------------------------------------------------
// instancePool()
//-----------------------------------------------------------------------------
@@ -467,7 +493,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
}
LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
- if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull())
+ if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull())
{
return;
}
@@ -1707,13 +1733,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
continue;
}
- LLUUID mesh_id = volume->getParams().getSculptID();
- if (mesh_id.isNull())
- {
- continue;
- }
-
- const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj);
+ const LLMeshSkinInfo* skin = vobj->getSkinInfo();
if (!skin)
{
continue;
@@ -1927,13 +1947,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
continue;
}
- LLUUID mesh_id = volume->getParams().getSculptID();
- if (mesh_id.isNull())
- {
- continue;
- }
-
- const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj);
+ const LLMeshSkinInfo* skin = vobj->getSkinInfo();
if (!skin)
{
continue;
@@ -2054,11 +2068,16 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
{
+ llassert (facep->isState(LLFace::RIGGED));
+ llassert(getType() == LLDrawPool::POOL_AVATAR);
+ if (facep->getPool() && facep->getPool() != this)
+ {
+ LL_ERRS() << "adding rigged face that's already in another pool" << LL_ENDL;
+ }
if (type >= NUM_RIGGED_PASSES)
{
LL_ERRS() << "Invalid rigged face type." << LL_ENDL;
}
-
if (facep->getRiggedIndex(type) != -1)
{
LL_ERRS() << "Tried to add a rigged face that's referenced elsewhere." << LL_ENDL;
@@ -2071,6 +2090,12 @@ void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)
{
+ llassert (facep->isState(LLFace::RIGGED));
+ llassert(getType() == LLDrawPool::POOL_AVATAR);
+ if (facep->getPool() != this)
+ {
+ LL_ERRS() << "Tried to remove a rigged face from the wrong pool" << LL_ENDL;
+ }
facep->setPool(NULL);
for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index b9d2204052..45b6d71110 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -60,6 +60,8 @@ public:
virtual S32 getVertexShaderLevel() const;
LLDrawPoolAvatar();
+ ~LLDrawPoolAvatar();
+ /*virtual*/ BOOL isDead();
static LLMatrix4& getModelView();
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 50a4925c37..0a7e0c92be 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -330,11 +330,7 @@ void LLFace::dirtyTexture()
{
vobj->mLODChanged = TRUE;
- LLVOAvatar* avatar = vobj->getAvatar();
- if (avatar)
- { //avatar render cost may have changed
- avatar->updateVisualComplexity();
- }
+ vobj->updateVisualComplexity();
}
gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE);
}
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index 5f606ec326..88c0d58081 100644
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -1042,14 +1042,8 @@ LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicT
mCameraPitch = 0.f;
mCameraZoom = 1.f;
- mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion());
- mDummyAvatar->createDrawable(&gPipeline);
- mDummyAvatar->mIsDummy = TRUE;
+ mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR);
mDummyAvatar->mSpecialRenderMode = 1;
- mDummyAvatar->setPositionAgent(LLVector3::zero);
- mDummyAvatar->slamPosition();
- mDummyAvatar->updateJointLODs();
- mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
mDummyAvatar->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET);
mDummyAvatar->hideSkirt();
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index a9e4d752ac..fbe78475df 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -566,15 +566,8 @@ LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLViewerDyna
mCameraPitch = 0.f;
mCameraZoom = 1.f;
- mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion());
- mDummyAvatar->createDrawable(&gPipeline);
- mDummyAvatar->mIsDummy = TRUE;
+ mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR);
mDummyAvatar->mSpecialRenderMode = 2;
- mDummyAvatar->setPositionAgent(LLVector3::zero);
- mDummyAvatar->slamPosition();
- mDummyAvatar->updateJointLODs();
- mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
- // gPipeline.markVisible(mDummyAvatar->mDrawable, *LLViewerCamera::getInstance());
mTextureName = 0;
}
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index da84a6b8f8..168fb13d11 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -1755,9 +1755,17 @@ void LLModelPreview::getJointAliases( JointMap& joint_map)
//Joint names and aliases come from avatar_skeleton.xml
joint_map = av->getJointAliases();
- for (S32 i = 0; i < av->mNumCollisionVolumes; i++)
+
+ std::vector<std::string> cv_names, attach_names;
+ av->getSortedJointNames(1, cv_names);
+ av->getSortedJointNames(2, attach_names);
+ for (std::vector<std::string>::iterator it = cv_names.begin(); it != cv_names.end(); ++it)
+ {
+ joint_map[*it] = *it;
+ }
+ for (std::vector<std::string>::iterator it = attach_names.begin(); it != attach_names.end(); ++it)
{
- joint_map[av->mCollisionVolumes[i].getName()] = av->mCollisionVolumes[i].getName();
+ joint_map[*it] = *it;
}
}
@@ -3443,16 +3451,11 @@ void LLModelPreview::update()
//-----------------------------------------------------------------------------
void LLModelPreview::createPreviewAvatar( void )
{
- mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion() );
+ mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR );
if ( mPreviewAvatar )
{
mPreviewAvatar->createDrawable( &gPipeline );
- mPreviewAvatar->mIsDummy = TRUE;
mPreviewAvatar->mSpecialRenderMode = 1;
- mPreviewAvatar->setPositionAgent( LLVector3::zero );
- mPreviewAvatar->slamPosition();
- mPreviewAvatar->updateJointLODs();
- mPreviewAvatar->updateGeometry( mPreviewAvatar->mDrawable );
mPreviewAvatar->startMotion( ANIM_AGENT_STAND );
mPreviewAvatar->hideSkirt();
}
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index df708013fc..7c48d9b233 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -4021,6 +4021,38 @@ void LLMeshRepository::uploadError(LLSD& args)
mUploadErrorQ.push(args);
}
+F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id)
+{
+ F32 triangles_max = 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();
+ 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_max = llmax((F32) bytes_max-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
+ }
+ }
+ return triangles_max;
+}
+
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..d2eac449f7 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -472,6 +472,8 @@ public:
static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events
+ // 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/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 0bf4d48421..cd00a6f98f 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -342,9 +342,19 @@ void LLPanelObject::getState( )
}
// can move or rotate only linked group with move permissions, or sub-object with move and modify perms
- BOOL enable_move = objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && !objectp->isAttachment() && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts"));
- BOOL enable_scale = objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && objectp->permModify();
- BOOL enable_rotate = objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && ( (objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts"));
+
+ // 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"));
+ BOOL enable_scale = objectp->permMove() && !objectp->isPermanentEnforced() &&
+ ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && objectp->permModify();
+ BOOL enable_rotate = objectp->permMove() && !objectp->isPermanentEnforced() &&
+ ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) &&
+ ((objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts"));
S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ))
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index b1895bfc9b..6c17fb9f8d 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -78,6 +78,8 @@
#include "llviewercontrol.h"
#include "llmeshrepository.h"
+#include "llvoavatarself.h"
+
#include <boost/bind.hpp>
// "Features" Tab
@@ -86,6 +88,7 @@ BOOL LLPanelVolume::postBuild()
{
// Flexible Objects Parameters
{
+ childSetCommitCallback("Animated Mesh Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitAnimatedMeshCheckbox, this, _1, _2), NULL);
childSetCommitCallback("Flexible1D Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitIsFlexible, this, _1, _2), NULL);
childSetCommitCallback("FlexNumSections",onCommitFlexible,this);
getChild<LLUICtrl>("FlexNumSections")->setValidateBeforeCommit(precommitValidate);
@@ -237,6 +240,11 @@ void LLPanelVolume::getState( )
{
volobjp = (LLVOVolume *)objectp;
}
+ LLVOVolume *root_volobjp = NULL;
+ if (root_objectp && (root_objectp->getPCode() == LL_PCODE_VOLUME))
+ {
+ root_volobjp = (LLVOVolume *)root_objectp;
+ }
if( !objectp )
{
@@ -260,6 +268,8 @@ void LLPanelVolume::getState( )
BOOL editable = root_objectp->permModify() && !root_objectp->isPermanentEnforced();
BOOL single_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )
&& LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1;
+ BOOL single_root_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ) &&
+ LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1;
// Select Single Message
if (single_volume)
@@ -347,7 +357,23 @@ void LLPanelVolume::getState( )
getChildView("Light Focus")->setEnabled(false);
getChildView("Light Ambiance")->setEnabled(false);
}
-
+
+ // Animated Mesh
+ BOOL is_animated_mesh = single_root_volume && root_volobjp && root_volobjp->isAnimatedObject();
+ getChild<LLUICtrl>("Animated Mesh Checkbox Ctrl")->setValue(is_animated_mesh);
+ BOOL enabled_animated_object_box = FALSE;
+ if (root_volobjp && root_volobjp == volobjp)
+ {
+ enabled_animated_object_box = single_root_volume && root_volobjp && root_volobjp->canBeAnimatedObject() && editable;
+ if (enabled_animated_object_box && !is_animated_mesh &&
+ root_volobjp->isAttachment() && !gAgentAvatarp->canAttachMoreAnimatedObjects())
+ {
+ // Turning this attachment animated would cause us to exceed the limit.
+ enabled_animated_object_box = false;
+ }
+ }
+ getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(enabled_animated_object_box);
+
// Flexible properties
BOOL is_flexible = volobjp && volobjp->isFlexible();
getChild<LLUICtrl>("Flexible1D Checkbox Ctrl")->setValue(is_flexible);
@@ -587,6 +613,7 @@ void LLPanelVolume::clearCtrls()
getChildView("Light Radius")->setEnabled(false);
getChildView("Light Falloff")->setEnabled(false);
+ getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false);
getChildView("Flexible1D Checkbox Ctrl")->setEnabled(false);
getChildView("FlexNumSections")->setEnabled(false);
getChildView("FlexGravity")->setEnabled(false);
@@ -896,6 +923,31 @@ void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata )
self->refresh();
}
+void LLPanelVolume::onCommitAnimatedMeshCheckbox(LLUICtrl *, void*)
+{
+ LLViewerObject* objectp = mObject;
+ if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME))
+ {
+ return;
+ }
+ LLVOVolume *volobjp = (LLVOVolume *)objectp;
+ BOOL animated_mesh = getChild<LLUICtrl>("Animated Mesh Checkbox Ctrl")->getValue();
+ U32 flags = volobjp->getExtendedMeshFlags();
+ U32 new_flags = flags;
+ if (animated_mesh)
+ {
+ new_flags |= LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG;
+ }
+ else
+ {
+ new_flags &= ~LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG;
+ }
+ if (new_flags != flags)
+ {
+ volobjp->setExtendedMeshFlags(new_flags);
+ }
+}
+
void LLPanelVolume::onCommitIsFlexible(LLUICtrl *, void*)
{
if (mObject->flagObjectPermanent())
diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h
index e3453ae99c..66117316cf 100644
--- a/indra/newview/llpanelvolume.h
+++ b/indra/newview/llpanelvolume.h
@@ -63,6 +63,7 @@ public:
static void onCommitLight( LLUICtrl* ctrl, void* userdata);
void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata);
static void onCommitFlexible( LLUICtrl* ctrl, void* userdata);
+ void onCommitAnimatedMeshCheckbox(LLUICtrl* ctrl, void* userdata);
static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata);
static void onCommitMaterial( LLUICtrl* ctrl, void* userdata);
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index c44aca6fa5..d29a06f7e5 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"
@@ -645,6 +646,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.
+//
+// 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;
@@ -669,6 +674,10 @@ bool LLSelectMgr::enableLinkObjects()
new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
}
}
+ if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable())
+ {
+ new_value = false;
+ }
return new_value;
}
@@ -6611,7 +6620,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
@@ -6629,23 +6641,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
- {
- mPauseRequest = NULL;
- }
-
if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid())
{
// reset hud ZOOM
@@ -6722,6 +6723,59 @@ 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)
+ {
+ 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());
+ }
+ }
+ }
}
void LLSelectMgr::updatePointAt()
@@ -7358,6 +7412,31 @@ 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(); ++iter)
+ {
+ LLViewerObject* object = (*iter)->getObject();
+ if (!object)
+ continue;
+ if (object->isAnimatedObject())
+ {
+ anim_count++;
+ }
+ est_tris += object->recursiveGetEstTrianglesMax();
+ max_tris = llmax((F32)max_tris,(F32)object->getAnimatedObjectMaxTris());
+ }
+ return anim_count==0 || est_tris <= max_tris;
+}
+
+bool LLObjectSelection::checkAnimatedObjectLinkable()
+{
+ return checkAnimatedObjectEstTris();
+}
+
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 e965dd80d5..a7c86e3ad3 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -340,6 +340,9 @@ public:
// returns TRUE is any node is currenly worn as an attachment
BOOL isAttachment();
+ bool checkAnimatedObjectEstTris();
+ bool checkAnimatedObjectLinkable();
+
// 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)
@@ -743,6 +746,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 &current_zoom) const;
@@ -844,7 +849,7 @@ private:
LLFrameTimer mEffectsTimer;
BOOL mForceSelection;
- LLAnimPauseRequest mPauseRequest;
+ std::vector<LLAnimPauseRequest> mPauseRequests;
};
// *DEPRECATED: For callbacks or observers, use
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index d2a87ee2af..d0328a7539 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -869,16 +869,6 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
}
}
- //clean up avatar attachment stats
- LLSpatialBridge* bridge = getSpatialPartition()->asBridge();
- if (bridge)
- {
- if (bridge->mAvatar.notNull())
- {
- bridge->mAvatar->subtractAttachmentArea(mSurfaceArea );
- }
- }
-
clearDrawMap();
mVertexBuffer = NULL;
mBufferMap.clear();
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 7633e46200..2594e3397c 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -466,8 +466,6 @@ public:
virtual LLCamera transformCamera(LLCamera& camera);
LLDrawable* mDrawable;
- LLPointer<LLVOAvatar> mAvatar;
-
};
class LLCullResult
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index ad9a554ef5..65cd5b58d0 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2386,6 +2386,7 @@ void register_viewer_callbacks(LLMessageSystem* msg)
msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value);
msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value);
msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation);
+ msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation);
msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance);
msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint);
msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response);
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index bd68d8c999..efbb8c856a 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -785,7 +785,7 @@ void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAccep
mDrop = drop;
if (mDrop)
{
- // don't allow drag and drop onto transparent objects
+ // don't allow drag and drop onto rigged or transparent objects
pick(gViewerWindow->pickImmediate(x, y, FALSE, FALSE));
}
else
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index f473000657..238e1d0306 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -111,9 +111,12 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
mMouseOutsideSlop = FALSE;
mMouseDownX = x;
mMouseDownY = y;
-
+ LLTimer pick_timer;
+ // AXON experimental feature
+ BOOL pick_rigged = gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
//left mouse down always picks transparent (but see handleMouseUp)
- mPick = gViewerWindow->pickImmediate(x, y, TRUE, FALSE);
+ mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged);
+ LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL;
mPick.mKeyMask = mask;
mMouseButtonDown = true;
@@ -128,7 +131,10 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
// don't pick transparent so users can't "pay" transparent objects
- mPick = gViewerWindow->pickImmediate(x, y, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ TRUE, /*BOOL pick_particle*/ TRUE);
+ mPick = gViewerWindow->pickImmediate(x, y,
+ /*BOOL pick_transparent*/ FALSE,
+ /*BOOL pick_rigged*/ TRUE,
+ /*BOOL pick_particle*/ TRUE);
mPick.mKeyMask = mask;
// claim not handled so UI focus stays same
@@ -538,7 +544,9 @@ void LLToolPie::selectionPropertiesReceived()
BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
{
- mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE);
+ // AXON experimental feature
+ BOOL pick_rigged = gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
+ mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged);
LLViewerObject *parent = NULL;
LLViewerObject *object = mHoverPick.getObject();
LLSelectMgr::getInstance()->setHoverObject(object, mHoverPick.mObjectFace);
@@ -584,7 +592,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
else
{
// perform a separate pick that detects transparent objects since they respond to 1-click actions
- LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE, FALSE);
+ LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged);
LLViewerObject* click_action_object = click_action_pick.getObject();
@@ -670,6 +678,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
LLPickInfo savedPick = mPick;
mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
FALSE /* ignore transparent */,
+ FALSE /* ignore rigged */,
FALSE /* ignore particles */);
if (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick
@@ -759,6 +768,7 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
LLPickInfo savedPick = mPick;
mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
FALSE /* ignore transparent */,
+ FALSE /* ignore rigged */,
FALSE /* ignore particles */);
if(mPick.mPickType == LLPickInfo::PICK_OBJECT)
@@ -1751,8 +1761,7 @@ BOOL LLToolPie::handleRightClickPick()
gMenuHolder->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
bool is_other_attachment = (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner());
- if (object->isAvatar()
- || is_other_attachment)
+ if (object->isAvatar() || is_other_attachment)
{
// Find the attachment's avatar
while( object && object->isAttachment())
diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp
index 1fcc9a0711..aa0e9f5c09 100644
--- a/indra/newview/lltoolselect.cpp
+++ b/indra/newview/lltoolselect.cpp
@@ -63,7 +63,9 @@ LLToolSelect::LLToolSelect( LLToolComposite* composite )
BOOL LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask)
{
// do immediate pick query
- mPick = gViewerWindow->pickImmediate(x, y, TRUE, FALSE);
+ // AXON experimental feature
+ BOOL pick_rigged = gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
+ mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged);
// Pass mousedown to agent
LLTool::handleMouseDown(x, y, mask);
diff --git a/indra/newview/lltoolselectrect.cpp b/indra/newview/lltoolselectrect.cpp
index 71dc8001d4..d655dd881e 100644
--- a/indra/newview/lltoolselectrect.cpp
+++ b/indra/newview/lltoolselectrect.cpp
@@ -71,7 +71,9 @@ void dialog_refresh_all(void);
BOOL LLToolSelectRect::handleMouseDown(S32 x, S32 y, MASK mask)
{
- handlePick(gViewerWindow->pickImmediate(x, y, TRUE, FALSE));
+ // AXON experimental feature
+ BOOL pick_rigged = gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
+ handlePick(gViewerWindow->pickImmediate(x, y, TRUE /* pick_transparent */, pick_rigged));
LLTool::handleMouseDown(x, y, mask);
diff --git a/indra/newview/lluiavatar.cpp b/indra/newview/lluiavatar.cpp
new file mode 100644
index 0000000000..6cc14fc49b
--- /dev/null
+++ b/indra/newview/lluiavatar.cpp
@@ -0,0 +1,59 @@
+/**
+ * @file lluiavatar.cpp
+ * @brief Implementation for special dummy avatar used in some UI views
+ *
+ * $LicenseInfo:firstyear=2017&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2017, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "lluiavatar.h"
+#include "llagent.h" // Get state values from here
+#include "llviewerobjectlist.h"
+#include "pipeline.h"
+#include "llanimationstates.h"
+#include "llviewercontrol.h"
+#include "llmeshrepository.h"
+#include "llviewerregion.h"
+
+LLUIAvatar::LLUIAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) :
+ LLVOAvatar(id, pcode, regionp)
+{
+ mIsDummy = TRUE;
+ mIsUIAvatar = true;
+}
+
+// virtual
+LLUIAvatar::~LLUIAvatar()
+{
+}
+
+// virtual
+void LLUIAvatar::initInstance()
+{
+ LLVOAvatar::initInstance();
+
+ createDrawable( &gPipeline );
+ setPositionAgent(LLVector3::zero);
+ slamPosition();
+ updateJointLODs();
+ updateGeometry(mDrawable);
+}
diff --git a/indra/newview/lluiavatar.h b/indra/newview/lluiavatar.h
new file mode 100644
index 0000000000..bcdffedef2
--- /dev/null
+++ b/indra/newview/lluiavatar.h
@@ -0,0 +1,44 @@
+/**
+ * @file lluiavatar.h
+ * @brief Special dummy avatar used in some UI views
+ *
+ * $LicenseInfo:firstyear=2017&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2017, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_UIAVATAR_H
+#define LL_UIAVATAR_H
+
+#include "llvoavatar.h"
+#include "llvovolume.h"
+
+class LLUIAvatar:
+ public LLVOAvatar
+{
+ LOG_CLASS(LLUIAvatar);
+
+public:
+ LLUIAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
+ virtual void initInstance(); // Called after construction to initialize the class.
+ virtual ~LLUIAvatar();
+};
+
+#endif //LL_CONTROLAVATAR_H
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index d9d66ef254..f281e1fb1b 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -207,6 +207,12 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
return true;
}
+static bool handleForceLODChanged(const LLSD& newvalue)
+{
+ LLVOVolume::sForceLOD = (F32) newvalue.asReal();
+ return true;
+}
+
static bool handleVolumeLODChanged(const LLSD& newvalue)
{
LLVOVolume::sLODFactor = (F32) newvalue.asReal();
@@ -612,6 +618,7 @@ void settings_setup_listeners()
gSavedSettings.getControl("RenderAvatarCloth")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("RenderGammaFull")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
+ gSavedSettings.getControl("RenderForceVolumeLOD")->getSignal()->connect(boost::bind(&handleForceLODChanged, _2));
gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _2));
gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _2));
gSavedSettings.getControl("RenderAvatarPhysicsLODFactor")->getSignal()->connect(boost::bind(&handleAvatarPhysicsLODChanged, _2));
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index 66e392ac42..cf9243a871 100644
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -357,6 +357,25 @@ void LLViewerJointAttachment::setOriginalPosition(LLVector3& position)
}
//-----------------------------------------------------------------------------
+// getNumAnimatedObjects()
+//-----------------------------------------------------------------------------
+S32 LLViewerJointAttachment::getNumAnimatedObjects() const
+{
+ S32 count = 0;
+ for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin();
+ iter != mAttachedObjects.end();
+ ++iter)
+ {
+ const LLViewerObject *attached_object = *iter;
+ if (attached_object->isAnimatedObject())
+ {
+ count++;
+ }
+ }
+ return count;
+}
+
+//-----------------------------------------------------------------------------
// clampObjectPosition()
//-----------------------------------------------------------------------------
void LLViewerJointAttachment::clampObjectPosition()
diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h
index 9addafaee1..9641ab4208 100644
--- a/indra/newview/llviewerjointattachment.h
+++ b/indra/newview/llviewerjointattachment.h
@@ -77,6 +77,7 @@ public:
S32 getGroup() const { return mGroup; }
S32 getPieSlice() const { return mPieSlice; }
S32 getNumObjects() const { return mAttachedObjects.size(); }
+ S32 getNumAnimatedObjects() const;
void clampObjectPosition();
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 5bbf5650ad..262bbd4d36 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1077,6 +1077,10 @@ U32 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY;
}
+ else if ("triangle count" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT;
+ }
else
{
LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL;
@@ -6892,7 +6896,7 @@ class LLAttachmentEnableDrop : public view_listener_t
// Do not enable drop if all faces of object are not enabled
if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))
{
- S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState());
+ S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState());
attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
if (attachment)
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 94a86a7831..31eda85828 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -55,6 +55,7 @@
#include "llagentcamera.h"
#include "llcallingcard.h"
#include "llbuycurrencyhtml.h"
+#include "llcontrolavatar.h"
#include "llfirstuse.h"
#include "llfloaterbump.h"
#include "llfloaterbuyland.h"
@@ -103,6 +104,7 @@
#include "llviewerwindow.h"
#include "llvlmanager.h"
#include "llvoavatarself.h"
+#include "llvovolume.h"
#include "llworld.h"
#include "pipeline.h"
#include "llfloaterworldmap.h"
@@ -4982,23 +4984,27 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
LLUUID animation_id;
LLUUID uuid;
S32 anim_sequence_id;
- LLVOAvatar *avatarp;
+ LLVOAvatar *avatarp = NULL;
mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
- //clear animation flags
- avatarp = (LLVOAvatar *)gObjectList.findObject(uuid);
+ LLViewerObject *objp = gObjectList.findObject(uuid);
+ if (objp)
+ {
+ avatarp = objp->asAvatar();
+ }
if (!avatarp)
{
// no agent by this ID...error?
- LL_WARNS("Messaging") << "Received animation state for unknown avatar" << uuid << LL_ENDL;
+ LL_WARNS("Messaging") << "Received animation state for unknown avatar " << uuid << LL_ENDL;
return;
}
S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList);
+ //clear animation flags
avatarp->mSignaledAnimations.clear();
if (avatarp->isSelf())
@@ -5069,6 +5075,98 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
}
}
+void process_object_animation(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLUUID animation_id;
+ LLUUID uuid;
+ S32 anim_sequence_id;
+
+ mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
+
+ LL_DEBUGS("AnimatedObjects") << "Received animation state for object " << uuid << LL_ENDL;
+
+ LLViewerObject *objp = gObjectList.findObject(uuid);
+ if (!objp)
+ {
+ LL_WARNS("Messaging") << "Received animation state for unknown object " << uuid << LL_ENDL;
+ return;
+ }
+
+ LLVOVolume *volp = dynamic_cast<LLVOVolume*>(objp);
+ if (!volp)
+ {
+ LL_WARNS("Messaging") << "Received animation state for non-volume object " << uuid << LL_ENDL;
+ return;
+ }
+
+ if (!volp->isAnimatedObject())
+ {
+ LL_WARNS("Messaging") << "Received animation state for non-animated object " << uuid << LL_ENDL;
+ return;
+ }
+
+ volp->updateControlAvatar();
+ LLControlAvatar *avatarp = volp->getControlAvatar();
+ if (!avatarp)
+ {
+ LL_WARNS("Messaging") << "Received animation request for object with no control avatar, ignoring" << LL_ENDL;
+ return;
+ }
+
+ S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
+ LL_DEBUGS("AnimatedObjects") << "processing object animation requests, num_blocks " << num_blocks << LL_ENDL;
+
+#if 1
+ // Here we go into skinned mode once, the first time we get an
+ // animation request, and then stay there. This is probably the
+ // normally desired behavior.
+ if (!avatarp->mPlaying)
+ {
+ avatarp->mPlaying = true;
+ if (!avatarp->mRootVolp->isAnySelected())
+ {
+ avatarp->updateVolumeGeom();
+ avatarp->mRootVolp->recursiveMarkForUpdate(TRUE);
+ }
+ }
+#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)
+ {
+ avatarp->mPlaying = true;
+ if (!avatarp->mRootVolp->isAnySelected())
+ {
+ avatarp->updateVolumeGeom();
+ avatarp->mRootVolp->recursiveMarkForUpdate(TRUE);
+ }
+ }
+ else if (num_blocks == 0 && avatarp->mPlaying)
+ {
+ avatarp->mPlaying = false;
+ if (!avatarp->mRootVolp->isAnySelected())
+ {
+ avatarp->updateVolumeGeom();
+ avatarp->mRootVolp->recursiveMarkForUpdate(TRUE);
+ }
+ }
+#endif
+
+ volp->mObjectSignaledAnimations.clear();
+
+ for( S32 i = 0; i < num_blocks; i++ )
+ {
+ mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
+ mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
+ volp->mObjectSignaledAnimations[animation_id] = anim_sequence_id;
+ LL_DEBUGS("AnimatedObjects") << "got object animation request for object "
+ << uuid << " animation id " << animation_id << LL_ENDL;
+ }
+
+ avatarp->updateAnimations();
+}
+
+
void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data)
{
LLUUID uuid;
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index b0eaa37541..cef6f79812 100644
--- a/indra/newview/llviewermessage.h
+++ b/indra/newview/llviewermessage.h
@@ -95,6 +95,7 @@ void process_health_message(LLMessageSystem *mesgsys, void **user_data);
void process_sim_stats(LLMessageSystem *mesgsys, void **user_data);
void process_shooter_agent_hit(LLMessageSystem* msg, void** user_data);
void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data);
+void process_object_animation(LLMessageSystem *mesgsys, void **user_data);
void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data);
void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data);
void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data);
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 6c2d4d7fea..c2922182d4 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -60,6 +60,7 @@
#include "llbbox.h"
#include "llbox.h"
#include "llcylinder.h"
+#include "llcontrolavatar.h"
#include "lldrawable.h"
#include "llface.h"
#include "llfloaterproperties.h"
@@ -69,6 +70,7 @@
#include "llselectmgr.h"
#include "llrendersphere.h"
#include "lltooldraganddrop.h"
+#include "lluiavatar.h"
#include "llviewercamera.h"
#include "llviewertexturelist.h"
#include "llviewerinventory.h"
@@ -138,7 +140,7 @@ const F32 PHYSICS_TIMESTEP = 1.f / 45.f;
static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object");
// static
-LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
+LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, S32 flags)
{
LLViewerObject *res = NULL;
LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT);
@@ -166,6 +168,18 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
}
res = gAgentAvatarp;
}
+ else if (flags & CO_FLAG_CONTROL_AVATAR)
+ {
+ LLControlAvatar *control_avatar = new LLControlAvatar(id, pcode, regionp);
+ control_avatar->initInstance();
+ res = control_avatar;
+ }
+ else if (flags & CO_FLAG_UI_AVATAR)
+ {
+ LLUIAvatar *ui_avatar = new LLUIAvatar(id, pcode, regionp);
+ ui_avatar->initInstance();
+ res = ui_avatar;
+ }
else
{
LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp);
@@ -235,6 +249,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mText(),
mHudText(""),
mHudTextColor(LLColor4::white),
+ mControlAvatar(NULL),
mLastInterpUpdateSecs(0.f),
mLastMessageUpdateSecs(0.f),
mLatestRecvPacketID(0),
@@ -259,7 +274,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mRotTime(0.f),
mAngularVelocityRot(),
mPreviousRotation(),
- mState(0),
+ mAttachmentState(0),
mMedia(NULL),
mClickAction(0),
mObjectCost(0),
@@ -363,17 +378,23 @@ void LLViewerObject::markDead()
//LL_INFOS() << "Marking self " << mLocalID << " as dead." << LL_ENDL;
// Root object of this hierarchy unlinks itself.
- LLVOAvatar *av = getAvatarAncestor();
if (getParent())
{
((LLViewerObject *)getParent())->removeChild(this);
}
LLUUID mesh_id;
- if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id))
- {
- // This case is needed for indirectly attached mesh objects.
- av->resetJointsOnDetach(mesh_id);
- }
+ {
+ LLVOAvatar *av = getAvatar();
+ if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id))
+ {
+ // This case is needed for indirectly attached mesh objects.
+ av->rebuildAttachmentOverrides();
+ }
+ }
+ if (getControlAvatar())
+ {
+ unlinkControlAvatar();
+ }
// Mark itself as dead
mDead = TRUE;
@@ -674,6 +695,18 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list)
}
}
+BOOL LLViewerObject::isAnySelected() const
+{
+ bool any_selected = isSelected();
+ for (child_list_t::const_iterator iter = mChildList.begin();
+ iter != mChildList.end(); iter++)
+ {
+ const LLViewerObject* child = *iter;
+ any_selected = any_selected || child->isSelected();
+ }
+ return any_selected;
+}
+
void LLViewerObject::setSelected(BOOL sel)
{
mUserSelected = sel;
@@ -1378,7 +1411,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
U8 state;
mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
- mState = state;
+ mAttachmentState = state;
// ...new objects that should come in selected need to be added to the selected list
mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
@@ -1648,7 +1681,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
U8 state;
mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
- mState = state;
+ mAttachmentState = state;
break;
}
@@ -1671,7 +1704,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
U8 state;
dp->unpackU8(state, "State");
- mState = state;
+ mAttachmentState = state;
switch(update_type)
{
@@ -2904,6 +2937,91 @@ void LLViewerObject::fetchInventoryFromServer()
}
}
+LLControlAvatar *LLViewerObject::getControlAvatar()
+{
+ return getRootEdit()->mControlAvatar.get();
+}
+
+LLControlAvatar *LLViewerObject::getControlAvatar() const
+{
+ return getRootEdit()->mControlAvatar.get();
+}
+
+void LLViewerObject::updateControlAvatar()
+{
+ LLViewerObject *root = getRootEdit();
+ if (root->isAnimatedObject() && !root->getControlAvatar())
+ {
+ bool any_mesh = root->isMesh();
+ LLViewerObject::const_child_list_t& child_list = root->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ const LLViewerObject* child = *iter;
+ any_mesh = any_mesh || child->isMesh();
+ }
+ if (any_mesh)
+ {
+ std::string vobj_name = llformat("Vol%u", (U32) root);
+ LL_DEBUGS("AnimatedObjects") << vobj_name << " calling linkControlAvatar()" << LL_ENDL;
+ root->linkControlAvatar();
+ }
+ }
+ if (!root->isAnimatedObject() && root->getControlAvatar())
+ {
+ std::string vobj_name = llformat("Vol%u", (U32) root);
+ LL_DEBUGS("AnimatedObjects") << vobj_name << " calling unlinkControlAvatar()" << LL_ENDL;
+ root->unlinkControlAvatar();
+ }
+}
+
+void LLViewerObject::linkControlAvatar()
+{
+ if (!getControlAvatar() && isRootEdit())
+ {
+ LLVOVolume *volp = dynamic_cast<LLVOVolume*>(this);
+ if (!volp)
+ {
+ LL_WARNS() << "called with null or non-volume object" << LL_ENDL;
+ return;
+ }
+ mControlAvatar = LLControlAvatar::createControlAvatar(volp);
+ }
+ if (getControlAvatar())
+ {
+ getControlAvatar()->rebuildAttachmentOverrides();
+ }
+ else
+ {
+ LL_WARNS() << "no control avatar found!" << LL_ENDL;
+ }
+}
+
+void LLViewerObject::unlinkControlAvatar()
+{
+ if (getControlAvatar())
+ {
+ getControlAvatar()->rebuildAttachmentOverrides();
+ }
+ if (isRootEdit())
+ {
+ // This will remove the entire linkset from the control avatar
+ if (mControlAvatar)
+ {
+ mControlAvatar->markForDeath();
+ mControlAvatar = NULL;
+ }
+ }
+ // For non-root prims, removing from the linkset will
+ // automatically remove the control avatar connection.
+}
+
+// virtual
+bool LLViewerObject::isAnimatedObject() const
+{
+ return false;
+}
+
struct LLFilenameAndTask
{
LLUUID mTaskID;
@@ -3513,6 +3631,45 @@ F32 LLViewerObject::getLinksetPhysicsCost()
return mLinksetPhysicsCost;
}
+F32 LLViewerObject::recursiveGetEstTrianglesMax() const
+{
+ F32 est_tris = getEstTrianglesMax();
+ for (child_list_t::const_iterator iter = mChildList.begin();
+ iter != mChildList.end(); iter++)
+ {
+ const LLViewerObject* child = *iter;
+ est_tris += child->recursiveGetEstTrianglesMax();
+ }
+ return est_tris;
+}
+
+S32 LLViewerObject::getAnimatedObjectMaxTris() const
+{
+ S32 max_tris = 0;
+ if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) // AXON REMOVE AFTER SERVER TESTING DONE
+ {
+ max_tris = S32_MAX;
+ }
+ else
+ {
+ if (gAgent.getRegion())
+ {
+ LLSD features;
+ gAgent.getRegion()->getSimulatorFeatures(features);
+ if (features.has("AnimatedObjects"))
+ {
+ max_tris = features["AnimatedObjects"]["AnimatedObjectMaxTris"].asInteger();
+ }
+ }
+ }
+ return max_tris;
+}
+
+F32 LLViewerObject::getEstTrianglesMax() const
+{
+ return 0.f;
+}
+
F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const
{
return 0.f;
@@ -3528,6 +3685,58 @@ U32 LLViewerObject::getHighLODTriangleCount()
return 0;
}
+U32 LLViewerObject::recursiveGetTriangleCount(S32* vcount) const
+{
+ S32 total_tris = getTriangleCount(vcount);
+ LLViewerObject::const_child_list_t& child_list = getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ LLViewerObject* childp = *iter;
+ if (childp)
+ {
+ total_tris += childp->getTriangleCount(vcount);
+ }
+ }
+ return total_tris;
+}
+
+// This is using the stored surface area for each volume (which
+// defaults to 1.0 for the case of everything except a sculpt) and
+// then scaling it linearly based on the largest dimension in the
+// prim's scale. Should revisit at some point.
+F32 LLViewerObject::recursiveGetScaledSurfaceArea() const
+{
+ F32 area = 0.f;
+ const LLDrawable* drawable = mDrawable;
+ if (drawable)
+ {
+ const LLVOVolume* volume = drawable->getVOVolume();
+ if (volume)
+ {
+ if (volume->getVolume())
+ {
+ const LLVector3& scale = volume->getScale();
+ area += volume->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
+ }
+ LLViewerObject::const_child_list_t children = volume->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator child_iter = children.begin();
+ child_iter != children.end();
+ ++child_iter)
+ {
+ LLViewerObject* child_obj = *child_iter;
+ LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
+ if (child && child->getVolume())
+ {
+ const LLVector3& scale = child->getScale();
+ area += child->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
+ }
+ }
+ }
+ }
+ return area;
+}
+
void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
{
LLVector4a center;
@@ -3631,7 +3840,6 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)
}
}
-
void LLViewerObject::setLineWidthForWindowSize(S32 window_width)
{
if (window_width < 700)
@@ -3859,7 +4067,7 @@ const LLVector3 LLViewerObject::getRenderPosition() const
if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
{
LLVOAvatar* avatar = getAvatar();
- if (avatar)
+ if (avatar && !getControlAvatar())
{
return avatar->getPositionAgent();
}
@@ -3883,7 +4091,7 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const
const LLQuaternion LLViewerObject::getRenderRotation() const
{
LLQuaternion ret;
- if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
+ if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED) && !isAnimatedObject())
{
return ret;
}
@@ -5121,7 +5329,13 @@ LLVOAvatar* LLViewerObject::asAvatar()
return NULL;
}
-// If this object is directly or indirectly parented by an avatar, return it.
+// If this object is directly or indirectly parented by an avatar,
+// return it. Normally getAvatar() is the correct function to call;
+// it will give the avatar used for skinning. The exception is with
+// animated objects that are also attachments; in that case,
+// getAvatar() will return the control avatar, used for skinning, and
+// getAvatarAncestor will return the avatar to which the object is
+// attached.
LLVOAvatar* LLViewerObject::getAvatarAncestor()
{
LLViewerObject *pobj = (LLViewerObject*) getParent();
@@ -5460,6 +5674,11 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para
new_block = new LLLightImageParams();
break;
}
+ case LLNetworkData::PARAMS_EXTENDED_MESH:
+ {
+ new_block = new LLExtendedMeshParams();
+ break;
+ }
default:
{
LL_INFOS() << "Unknown param type." << LL_ENDL;
@@ -5859,6 +6078,17 @@ void LLViewerObject::updateVolume(const LLVolumeParams& volume_params)
}
}
+void LLViewerObject::recursiveMarkForUpdate(BOOL priority)
+{
+ for (LLViewerObject::child_list_t::iterator iter = mChildList.begin();
+ iter != mChildList.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ child->markForUpdate(priority);
+ }
+ markForUpdate(priority);
+}
+
void LLViewerObject::markForUpdate(BOOL priority)
{
if (mDrawable.notNull())
@@ -5910,6 +6140,11 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp)
child->setRegion(regionp);
}
+ if (mControlAvatar)
+ {
+ mControlAvatar->setRegion(regionp);
+ }
+
setChanged(MOVED | SILHOUETTE);
updateDrawable(FALSE);
}
@@ -6358,6 +6593,10 @@ const std::string& LLViewerObject::getAttachmentItemName() const
//virtual
LLVOAvatar* LLViewerObject::getAvatar() const
{
+ if (getControlAvatar())
+ {
+ return getControlAvatar();
+ }
if (isAttachment())
{
LLViewerObject* vobj = (LLViewerObject*) getParent();
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 7a490f6957..237529f213 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -47,6 +47,7 @@ class LLAgent; // TODO: Get rid of this.
class LLAudioSource;
class LLAudioSourceVO;
class LLColor4;
+class LLControlAvatar;
class LLDataPacker;
class LLDataPackerBinaryBuffer;
class LLDrawable;
@@ -220,6 +221,8 @@ public:
LLViewerRegion* getRegion() const { return mRegionp; }
BOOL isSelected() const { return mUserSelected; }
+ // Check whole linkset
+ BOOL isAnySelected() const;
virtual void setSelected(BOOL sel);
const LLUUID &getID() const { return mID; }
@@ -231,6 +234,7 @@ public:
virtual BOOL isFlexible() const { return FALSE; }
virtual BOOL isSculpted() const { return FALSE; }
virtual BOOL isMesh() const { return FALSE; }
+ virtual BOOL isRiggedMesh() const { return FALSE; }
virtual BOOL hasLightTexture() const { return FALSE; }
// This method returns true if the object is over land owned by
@@ -356,9 +360,15 @@ public:
virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE);
+ S32 getAnimatedObjectMaxTris() 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();
+ F32 recursiveGetScaledSurfaceArea() const;
+
+ U32 recursiveGetTriangleCount(S32* vcount = NULL) const;
void setObjectCost(F32 cost);
F32 getObjectCost();
@@ -374,7 +384,7 @@ public:
void sendShapeUpdate();
- U8 getState() { return mState; }
+ U8 getAttachmentState() { return mAttachmentState; }
F32 getAppAngle() const { return mAppAngle; }
F32 getPixelArea() const { return mPixelArea; }
@@ -411,7 +421,8 @@ public:
void setIcon(LLViewerTexture* icon_image);
void clearIcon();
- void markForUpdate(BOOL priority);
+ void recursiveMarkForUpdate(BOOL priority);
+ virtual void markForUpdate(BOOL priority);
void updateVolume(const LLVolumeParams& volume_params);
virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max);
virtual F32 getBinRadius();
@@ -683,6 +694,27 @@ public:
static BOOL sUseSharedDrawables;
+public:
+ // Returns mControlAvatar for the edit root prim of this linkset
+ LLControlAvatar *getControlAvatar();
+ LLControlAvatar *getControlAvatar() const;
+
+ // Create or connect to an existing control av as applicable
+ void linkControlAvatar();
+ // Remove any reference to control av for this prim
+ void unlinkControlAvatar();
+ // Link or unlink as needed
+ void updateControlAvatar();
+
+ virtual bool isAnimatedObject() const;
+
+ // Flags for createObject
+ static const S32 CO_FLAG_CONTROL_AVATAR = 1 << 0;
+ static const S32 CO_FLAG_UI_AVATAR = 1 << 1;
+
+protected:
+ LLPointer<LLControlAvatar> mControlAvatar;
+
protected:
// delete an item in the inventory, but don't tell the
// server. This is used internally by remove, update, and
@@ -693,8 +725,7 @@ protected:
// updateInventory.
void doUpdateInventory(LLPointer<LLViewerInventoryItem>& item, U8 key, bool is_new);
-
- static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp);
+ static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0);
BOOL setData(const U8 *datap, const U32 data_size);
@@ -782,7 +813,7 @@ protected:
LLQuaternion mAngularVelocityRot; // accumulated rotation from the angular velocity computations
LLQuaternion mPreviousRotation;
- U8 mState; // legacy
+ U8 mAttachmentState; // this encodes the attachment id in a somewhat complex way. 0 if not an attachment.
LLViewerObjectMedia* mMedia; // NULL if no media associated
U8 mClickAction;
F32 mObjectCost; //resource cost of this object or -1 if unknown
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 3c83e3a006..27cab9d575 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -531,6 +531,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
// LL_INFOS() << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << LL_ENDL;
}
objectp = findObject(fullid);
+ LL_DEBUGS("AnimatedObjects") << "processObjectUpdate for uuid " << fullid << " objectp " << objectp << LL_ENDL;
if(update_cache)
{
@@ -606,6 +607,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
#endif
objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender());
+ LL_DEBUGS("AnimatedObjects") << "creating object " << fullid << " result " << objectp << LL_ENDL;
if (!objectp)
{
LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL;
@@ -862,8 +864,8 @@ void LLViewerObjectList::update(LLAgent &agent)
{
if (idle_count >= idle_list.size())
{
- idle_list.push_back( objectp );
- }
+ idle_list.push_back( objectp );
+ }
else
{
idle_list[idle_count] = objectp;
@@ -900,7 +902,7 @@ void LLViewerObjectList::update(LLAgent &agent)
{
objectp = *idle_iter;
llassert(objectp->isActive());
- objectp->idleUpdate(agent, frame_time);
+ objectp->idleUpdate(agent, frame_time);
}
//update flexible objects
@@ -1947,12 +1949,12 @@ void LLViewerObjectList::resetObjectBeacons()
mDebugBeacons.clear();
}
-LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp)
+LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags)
{
LLUUID fullid;
fullid.generate();
- LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp);
+ LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp, flags);
if (!objectp)
{
// LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << LL_ENDL;
@@ -1972,6 +1974,8 @@ LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, L
{
llassert_always(uuid.notNull());
+ LL_DEBUGS("AnimatedObjects") << "createObjectFromCache creating " << uuid << LL_ENDL;
+
LLViewerObject *objectp = LLViewerObject::createObject(uuid, pcode, regionp);
if (!objectp)
{
@@ -2005,6 +2009,7 @@ LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRe
{
fullid = uuid;
}
+ LL_DEBUGS("AnimatedObjects") << "createObject creating " << fullid << LL_ENDL;
LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp);
if (!objectp)
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 94c751acc6..72b2b99004 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -67,7 +67,7 @@ public:
inline LLViewerObject *getObject(const S32 index);
inline LLViewerObject *findObject(const LLUUID &id);
- LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp); // Create a viewer-side object
+ LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0); // Create a viewer-side object
LLViewerObject *createObjectFromCache(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id);
LLViewerObject *createObject(const LLPCode pcode, LLViewerRegion *regionp,
const LLUUID &uuid, const U32 local_id, const LLHost &sender);
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 5b61eab5f7..2da4f8e427 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -2861,6 +2861,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("MeshUploadFlag");
capabilityNames.append("NavMeshGenerationStatus");
capabilityNames.append("NewFileAgentInventory");
+ capabilityNames.append("ObjectAnimation");
capabilityNames.append("ObjectMedia");
capabilityNames.append("ObjectMediaNavigate");
capabilityNames.append("ObjectNavMeshProperties");
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 119c1a9db6..070a42e67f 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1158,7 +1158,9 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
if (prim_media_dnd_enabled)
{
- LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/, FALSE );
+ LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY,
+ TRUE /* pick_transparent */,
+ FALSE /* pick_rigged */);
LLUUID object_id = pick_info.getObjectID();
S32 object_face = pick_info.mObjectFace;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index eae8f2cc56..0688a57439 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -44,6 +44,7 @@
#include "llavatarnamecache.h"
#include "llavatarpropertiesprocessor.h"
#include "llavatarrendernotifier.h"
+#include "llcontrolavatar.h"
#include "llexperiencecache.h"
#include "llphysicsmotion.h"
#include "llviewercontrol.h"
@@ -109,6 +110,8 @@
#include "llcallstack.h"
#include "llrendersphere.h"
+#include <boost/lexical_cast.hpp>
+
extern F32 SPEED_ADJUST_MAX;
extern F32 SPEED_ADJUST_MAX_SEC;
extern F32 ANIM_SPEED_MAX;
@@ -142,7 +145,7 @@ const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df44
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
-const F32 DELTA_TIME_MIN = 0.01f; // we clamp measured deltaTime to this
+const F32 DELTA_TIME_MIN = 0.01f; // we clamp measured delta_time to this
const F32 DELTA_TIME_MAX = 0.2f; // range to insure stability of computations.
const F32 PELVIS_LAG_FLYING = 0.22f;// pelvis follow half life while flying
@@ -617,6 +620,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
LLViewerObject(id, pcode, regionp),
mSpecialRenderMode(0),
mAttachmentSurfaceArea(0.f),
+ mAttachmentVisibleTriangleCount(0),
+ mAttachmentEstTriangleCount(0.f),
mReportedVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
mTurning(FALSE),
mLastSkeletonSerialNum( 0 ),
@@ -663,7 +668,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mLastUpdateRequestCOFVersion(-1),
mLastUpdateReceivedCOFVersion(-1),
mCachedMuteListUpdateTime(0),
- mCachedInMuteList(false)
+ mCachedInMuteList(false),
+ mIsControlAvatar(false),
+ mIsUIAvatar(false),
+ mEnableDefaultMotions(true)
{
LL_DEBUGS("AvatarRender") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;
@@ -718,6 +726,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mCurrentGesticulationLevel = 0;
+
mRuthTimer.reset();
mRuthDebugTimer.reset();
mDebugExistenceTimer.reset();
@@ -1099,7 +1108,7 @@ void LLVOAvatar::cleanupClass()
}
// virtual
-void LLVOAvatar::initInstance(void)
+void LLVOAvatar::initInstance()
{
//-------------------------------------------------------------------------
// register motions
@@ -1222,8 +1231,6 @@ const LLVector3 LLVOAvatar::getRenderPosition() const
{
return getPosition() * mDrawable->getParent()->getRenderMatrix();
}
-
-
}
void LLVOAvatar::updateDrawable(BOOL force_damped)
@@ -1240,6 +1247,10 @@ void LLVOAvatar::onShift(const LLVector4a& shift_vector)
void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
{
+ if (mDrawable.isNull())
+ {
+ return;
+ }
if (isImpostor() && !needsImpostorUpdate())
{
LLVector3 delta = getRenderPosition() -
@@ -1404,13 +1415,29 @@ void LLVOAvatar::renderCollisionVolumes()
static F32 sphere_scale = 1.0f;
static F32 center_dot_scale = 0.05f;
- static LLVector3 CV_COLOR_OCCLUDED(0.0f, 0.0f, 1.0f);
- static LLVector3 CV_COLOR_VISIBLE(0.5f, 0.5f, 1.0f);
- static LLVector3 DOT_COLOR_OCCLUDED(1.0f, 1.0f, 1.0f);
- static LLVector3 DOT_COLOR_VISIBLE(1.0f, 1.0f, 1.0f);
+ static LLVector3 BLUE(0.0f, 0.0f, 1.0f);
+ static LLVector3 PASTEL_BLUE(0.5f, 0.5f, 1.0f);
+ static LLVector3 RED(1.0f, 0.0f, 0.0f);
+ static LLVector3 PASTEL_RED(1.0f, 0.5f, 0.5f);
+ static LLVector3 WHITE(1.0f, 1.0f, 1.0f);
+
- render_sphere_and_line(begin_pos, end_pos, sphere_scale, CV_COLOR_OCCLUDED, CV_COLOR_VISIBLE);
- render_sphere_and_line(begin_pos, end_pos, center_dot_scale, DOT_COLOR_OCCLUDED, DOT_COLOR_VISIBLE);
+ LLVector3 cv_color_occluded;
+ LLVector3 cv_color_visible;
+ LLVector3 dot_color_occluded(WHITE);
+ LLVector3 dot_color_visible(WHITE);
+ if (isControlAvatar())
+ {
+ cv_color_occluded = RED;
+ cv_color_visible = PASTEL_RED;
+ }
+ else
+ {
+ cv_color_occluded = BLUE;
+ cv_color_visible = PASTEL_BLUE;
+ }
+ render_sphere_and_line(begin_pos, end_pos, sphere_scale, cv_color_occluded, cv_color_visible);
+ render_sphere_and_line(begin_pos, end_pos, center_dot_scale, dot_color_occluded, dot_color_visible);
gGL.popMatrix();
}
@@ -1422,9 +1449,6 @@ void LLVOAvatar::renderCollisionVolumes()
mNameText->lineSegmentIntersect(unused, unused, unused, TRUE);
}
-
- mDebugText.clear();
- addDebugText(ostr.str());
}
void LLVOAvatar::renderBones()
@@ -1595,6 +1619,11 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
return FALSE;
}
+ if (isControlAvatar())
+ {
+ return FALSE;
+ }
+
if (lineSegmentBoundingBox(start, end))
{
for (S32 i = 0; i < mNumCollisionVolumes; ++i)
@@ -1680,6 +1709,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
return FALSE;
}
+// virtual
LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
S32 face,
BOOL pick_transparent,
@@ -1796,7 +1826,11 @@ void LLVOAvatar::buildCharacter()
mAahMorph = getVisualParam( "Express_Open_Mouth" );
}
- startDefaultMotions();
+ // Currently disabled for control avatars (animated objects), enabled for all others.
+ if (mEnableDefaultMotions)
+ {
+ startDefaultMotions();
+ }
//-------------------------------------------------------------------------
// restart any currently active motions
@@ -1942,7 +1976,7 @@ void LLVOAvatar::resetSkeleton(bool reset_animations)
//-----------------------------------------------------------------------------
void LLVOAvatar::releaseMeshData()
{
- if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy)
+ if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || isUIAvatar())
{
return;
}
@@ -1962,15 +1996,15 @@ void LLVOAvatar::releaseMeshData()
LLFace* facep = mDrawable->getFace(0);
if (facep)
{
- facep->setSize(0, 0);
- for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++)
- {
- facep = mDrawable->getFace(i);
+ facep->setSize(0, 0);
+ for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++)
+ {
+ facep = mDrawable->getFace(i);
if (facep)
{
- facep->setSize(0, 0);
- }
- }
+ facep->setSize(0, 0);
+ }
+ }
}
}
@@ -1994,6 +2028,10 @@ void LLVOAvatar::releaseMeshData()
void LLVOAvatar::restoreMeshData()
{
llassert(!isSelf());
+ if (mDrawable.isNull())
+ {
+ return;
+ }
//LL_INFOS() << "Restoring" << LL_ENDL;
mMeshValid = TRUE;
@@ -2303,7 +2341,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
{
LL_RECORD_BLOCK_TIME(FTM_JOINT_UPDATE);
- if (mIsSitting && getParent())
+ if (isSitting() && getParent())
{
LLViewerObject *root_object = (LLViewerObject*)getRoot();
LLDrawable* drawablep = root_object->mDrawable;
@@ -2469,7 +2507,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
// (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing)
//--------------------------------------------------------------------------------------------
- if ( mIsSitting )
+ if ( isSitting() )
{
LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] );
mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot->getWorldPosition() + headOffset );
@@ -2593,13 +2631,16 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
}
}
- mDrawable->movePartition();
-
- //force a move if sitting on an active object
- if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive())
- {
- gPipeline.markMoved(mDrawable, TRUE);
- }
+ if (mDrawable.notNull())
+ {
+ mDrawable->movePartition();
+
+ //force a move if sitting on an active object
+ if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive())
+ {
+ gPipeline.markMoved(mDrawable, TRUE);
+ }
+ }
}
void LLVOAvatar::idleUpdateAppearanceAnimation()
@@ -2760,7 +2801,8 @@ void LLVOAvatar::idleUpdateLoadingEffect()
LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK |
LLPartData::LL_PART_TARGET_POS_MASK );
- if (!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());
}
@@ -3360,8 +3402,7 @@ bool LLVOAvatar::isInMuteList()
void LLVOAvatar::updateDebugText()
{
- // clear debug text
- mDebugText.clear();
+ // Leave mDebugText uncleared here, in case a derived class has added some state first
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
@@ -3406,7 +3447,7 @@ void LLVOAvatar::updateDebugText()
if (hover_offset[2] != 0.0)
{
debug_line += llformat(" hov_z: %.3f", hover_offset[2]);
- debug_line += llformat(" %s", (mIsSitting ? "S" : "T"));
+ debug_line += llformat(" %s", (isSitting() ? "S" : "T"));
debug_line += llformat("%s", (isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED) ? "G" : "-"));
}
LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition();
@@ -3420,14 +3461,20 @@ void LLVOAvatar::updateDebugText()
LLVector3 pelvis_pos = mPelvisp->getPosition();
debug_line += llformat(" rp %.3f pp %.3f", root_pos[2], pelvis_pos[2]);
+ S32 is_visible = (S32) isVisible();
+ S32 is_m_visible = (S32) mVisible;
+ debug_line += llformat(" v %d/%d", is_visible, is_m_visible);
+
addDebugText(debug_line);
}
+
if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))
{
if (!mBakedTextureDebugText.empty())
addDebugText(mBakedTextureDebugText);
}
+ // Develop -> Avatar -> Animation Info
if (LLVOAvatar::sShowAnimationDebug)
{
for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin();
@@ -3437,8 +3484,30 @@ void LLVOAvatar::updateDebugText()
if (motionp->getMinPixelArea() < getPixelArea())
{
std::string output;
- if (motionp->getName().empty())
+ std::string motion_name = motionp->getName();
+ if (motion_name.empty())
{
+ if (isControlAvatar())
+ {
+ LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+ // Try to get name from inventory of associated object
+ LLVOVolume *volp = control_av->mRootVolp;
+ if (volp)
+ {
+ if (volp->getInventorySerial()<=0)
+ {
+ volp->requestInventory();
+ }
+ LLViewerInventoryItem* item = volp->getInventoryItemByAsset(motionp->getID());
+ if (item)
+ {
+ motion_name = item->getName();
+ }
+ }
+ }
+ }
+ if (motion_name.empty())
+ {
std::string name;
if (gAgent.isGodlikeWithoutAdminMenuFakery() || isSelf())
{
@@ -3492,7 +3561,6 @@ void LLVOAvatar::updateDebugText()
{
name = LLUUID::null.asString();
}
-
output = llformat("%s - %d",
name.c_str(),
(U32)motionp->getPriority());
@@ -3500,8 +3568,8 @@ void LLVOAvatar::updateDebugText()
else
{
output = llformat("%s - %d",
- motionp->getName().c_str(),
- (U32)motionp->getPriority());
+ motion_name.c_str(),
+ (U32)motionp->getPriority());
}
addDebugText(output);
}
@@ -3517,51 +3585,125 @@ void LLVOAvatar::updateDebugText()
{
setDebugText(mDebugText);
}
- mDebugText.clear();
-
+ mDebugText.clear();
}
//------------------------------------------------------------------------
-// updateCharacter()
-// called on both your avatar and other avatars
+// updateFootstepSounds
+// Factored out from updateCharacter()
+// Generate footstep sounds when feet hit the ground
//------------------------------------------------------------------------
-BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
-{
- updateDebugText();
-
- if (!mIsBuilt)
- {
- return FALSE;
- }
+void LLVOAvatar::updateFootstepSounds()
+{
+ if (mIsDummy)
+ {
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // Find the ground under each foot, these are used for a variety
+ // of things that follow
+ //-------------------------------------------------------------------------
+ LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition();
+ LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition();
- BOOL visible = isVisible();
+ LLVector3 ankle_left_ground_agent = ankle_left_pos_agent;
+ LLVector3 ankle_right_ground_agent = ankle_right_pos_agent;
+ LLVector3 normal;
+ resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal);
+ resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal);
- // For fading out the names above heads, only let the timer
- // run if we're visible.
- if (mDrawable.notNull() && !visible)
+ F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]);
+ F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]);
+
+ if (!isSitting())
{
- mTimeVisible.reset();
+ //-------------------------------------------------------------------------
+ // Figure out which foot is on ground
+ //-------------------------------------------------------------------------
+ if (!mInAir)
+ {
+ if ((leftElev < 0.0f) || (rightElev < 0.0f))
+ {
+ ankle_left_pos_agent = mFootLeftp->getWorldPosition();
+ ankle_right_pos_agent = mFootRightp->getWorldPosition();
+ leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ];
+ rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ];
+ }
+ }
}
+
+ const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND};
+ const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS);
- //--------------------------------------------------------------------
- // the rest should only be done occasionally for far away avatars
- //--------------------------------------------------------------------
+ if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) )
+ {
+ BOOL playSound = FALSE;
+ LLVector3 foot_pos_agent;
+ BOOL onGroundLeft = (leftElev <= 0.05f);
+ BOOL onGroundRight = (rightElev <= 0.05f);
+
+ // did left foot hit the ground?
+ if ( onGroundLeft && !mWasOnGroundLeft )
+ {
+ foot_pos_agent = ankle_left_pos_agent;
+ playSound = TRUE;
+ }
+
+ // did right foot hit the ground?
+ if ( onGroundRight && !mWasOnGroundRight )
+ {
+ foot_pos_agent = ankle_right_pos_agent;
+ playSound = TRUE;
+ }
+
+ mWasOnGroundLeft = onGroundLeft;
+ mWasOnGroundRight = onGroundRight;
+
+ if ( playSound )
+ {
+ const F32 STEP_VOLUME = 0.1f;
+ const LLUUID& step_sound_id = getStepSound();
+
+ LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent);
+
+ if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global)
+ && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds))
+ {
+ gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global);
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// computeUpdatePeriod()
+// Factored out from updateCharacter()
+// Set new value for mUpdatePeriod based on distance and various other factors.
+//------------------------------------------------------------------------
+void LLVOAvatar::computeUpdatePeriod()
+{
bool visually_muted = isVisuallyMuted();
- if (visible && (!isSelf() || visually_muted) && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter)
+ if (mDrawable.notNull()
+ && isVisible()
+ && (!isSelf() || visually_muted)
+ && !isUIAvatar()
+ && sUseImpostors
+ && !mNeedsAnimUpdate
+ && !sFreezeCounter)
{
const LLVector4a* ext = mDrawable->getSpatialExtents();
LLVector4a size;
size.setSub(ext[1],ext[0]);
F32 mag = size.getLength3().getF32()*0.5f;
-
F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f);
if (visually_muted)
{ // visually muted avatars update at 16 hz
mUpdatePeriod = 16;
}
- else if ( ! shouldImpostor()
+ else if (! shouldImpostor()
|| mDrawable->mDistanceWRTCamera < 1.f + mag)
{ // first 25% of max visible avatars are not impostored
// also, don't impostor avatars whose bounding box may be penetrating the
@@ -3585,63 +3727,214 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
//nearby avatars, update the impostors more frequently.
mUpdatePeriod = 4;
}
-
- visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE;
}
else
{
mUpdatePeriod = 1;
}
+}
- // don't early out for your own avatar, as we rely on your animations playing reliably
- // for example, the "turn around" animation when entering customize avatar needs to trigger
- // even when your avatar is offscreen
- if (!visible && !isSelf())
- {
- updateMotions(LLCharacter::HIDDEN_UPDATE);
- return FALSE;
- }
+//------------------------------------------------------------------------
+// updateOrientation()
+// Factored out from updateCharacter()
+// This is used by updateCharacter() to update the avatar's orientation:
+// - updates mTurning state
+// - updates rotation of the mRoot joint in the skeleton
+// - for self, calls setControlFlags() to notify the simulator about any turns
+//------------------------------------------------------------------------
+void LLVOAvatar::updateOrientation(LLAgent& agent, F32 speed, F32 delta_time)
+{
+ LLQuaternion iQ;
+ LLVector3 upDir( 0.0f, 0.0f, 1.0f );
+
+ // Compute a forward direction vector derived from the primitive rotation
+ // and the velocity vector. When walking or jumping, don't let body deviate
+ // more than 90 from the view, if necessary, flip the velocity vector.
- // change animation time quanta based on avatar render load
- if (!isSelf() && !mIsDummy)
+ LLVector3 primDir;
+ if (isSelf())
+ {
+ primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector());
+ primDir.normalize();
+ }
+ else
+ {
+ primDir = getRotation().getMatrix3().getFwdRow();
+ }
+ LLVector3 velDir = getVelocity();
+ velDir.normalize();
+ if ( mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end())
+ {
+ F32 vpD = velDir * primDir;
+ if (vpD < -0.5f)
+ {
+ velDir *= -1.0f;
+ }
+ }
+ LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f));
+ if (isSelf() && gAgentCamera.cameraMouselook())
+ {
+ // make sure fwdDir stays in same general direction as primdir
+ if (gAgent.getFlying())
+ {
+ fwdDir = LLViewerCamera::getInstance()->getAtAxis();
+ }
+ else
+ {
+ LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis();
+ LLVector3 up_vector = gAgent.getReferenceUpVector();
+ at_axis -= up_vector * (at_axis * up_vector);
+ at_axis.normalize();
+
+ F32 dot = fwdDir * at_axis;
+ if (dot < 0.f)
+ {
+ fwdDir -= 2.f * at_axis * dot;
+ fwdDir.normalize();
+ }
+ }
+ }
+
+ LLQuaternion root_rotation = mRoot->getWorldMatrix().quaternion();
+ F32 root_roll, root_pitch, root_yaw;
+ root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw);
+
+ // When moving very slow, the pelvis is allowed to deviate from the
+ // forward direction to allow it to hold its position while the torso
+ // and head turn. Once in motion, it must conform however.
+ BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook();
+
+ LLVector3 pelvisDir( mRoot->getWorldMatrix().getFwdRow4().mV );
+
+ static LLCachedControl<F32> s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow", 60.0);
+ static LLCachedControl<F32> s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast", 2.0);
+
+ F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, s_pelvis_rot_threshold_slow, s_pelvis_rot_threshold_fast);
+
+ if (self_in_mouselook)
+ {
+ pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR;
+ }
+ pelvis_rot_threshold *= DEG_TO_RAD;
+
+ F32 angle = angle_between( pelvisDir, fwdDir );
+
+ // The avatar's root is allowed to have a yaw that deviates widely
+ // from the forward direction, but if roll or pitch are off even
+ // a little bit we need to correct the rotation.
+ if(root_roll < 1.f * DEG_TO_RAD
+ && root_pitch < 5.f * DEG_TO_RAD)
+ {
+ // smaller correction vector means pelvis follows prim direction more closely
+ if (!mTurning && angle > pelvis_rot_threshold*0.75f)
+ {
+ mTurning = TRUE;
+ }
+
+ // use tighter threshold when turning
+ if (mTurning)
+ {
+ pelvis_rot_threshold *= 0.4f;
+ }
+
+ // am I done turning?
+ if (angle < pelvis_rot_threshold)
+ {
+ mTurning = FALSE;
+ }
+
+ LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f);
+ fwdDir += correction_vector;
+ }
+ else
+ {
+ mTurning = FALSE;
+ }
+
+ // Now compute the full world space rotation for the whole body (wQv)
+ LLVector3 leftDir = upDir % fwdDir;
+ leftDir.normalize();
+ fwdDir = leftDir % upDir;
+ LLQuaternion wQv( fwdDir, leftDir, upDir );
+
+ if (isSelf() && mTurning)
+ {
+ if ((fwdDir % pelvisDir) * upDir > 0.f)
+ {
+ gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT);
+ }
+ else
+ {
+ gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT);
+ }
+ }
+
+ // Set the root rotation, but do so incrementally so that it
+ // lags in time by some fixed amount.
+ //F32 u = LLSmoothInterpolation::getInterpolant(PELVIS_LAG);
+ F32 pelvis_lag_time = 0.f;
+ if (self_in_mouselook)
+ {
+ pelvis_lag_time = PELVIS_LAG_MOUSELOOK;
+ }
+ else if (mInAir)
+ {
+ pelvis_lag_time = PELVIS_LAG_FLYING;
+ // increase pelvis lag time when moving slowly
+ pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f);
+ }
+ else
+ {
+ pelvis_lag_time = PELVIS_LAG_WALKING;
+ }
+
+ F32 u = llclamp((delta_time / pelvis_lag_time), 0.0f, 1.0f);
+
+ mRoot->setWorldRotation( slerp(u, mRoot->getWorldRotation(), wQv) );
+}
+
+//------------------------------------------------------------------------
+// updateTimeStep()
+// Factored out from updateCharacter().
+//
+// Updates the time step used by the motion controller, based on area
+// and avatar count criteria. This will also stop the
+// ANIM_AGENT_WALK_ADJUST animation under some circumstances.
+// ------------------------------------------------------------------------
+void LLVOAvatar::updateTimeStep()
+{
+ if (!isSelf() && !isUIAvatar()) // ie, non-self avatars, and animated objects will be affected.
{
+ // 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;
+ // Extrema:
+ // If number of avs is 10 or less, time_step is unmodified (flagged with 0.0).
+ // If area of av is 5000 or greater, time_step is unmodified (flagged with 0.0).
+ // If number of avs is 35 or greater, and area of av is 100 or less,
+ // time_step takes the maximum possible value of 0.25.
+ // Other situations will give values within the (0, 0.25) range.
if (time_step != 0.f)
{
// disable walk motion servo controller as it doesn't work with motion timesteps
stopMotion(ANIM_AGENT_WALK_ADJUST);
removeAnimationData("Walk Speed");
}
+ // See SL-763 - playback with altered time step does not
+ // appear to work correctly, odd behavior for distant avatars.
+ // As of 11-2017, LLMotionController::updateMotions() will
+ // ignore the value here. Need to re-enable if it's every
+ // fixed.
mMotionController.setTimeStep(time_step);
- // LL_INFOS() << "Setting timestep to " << time_quantum * pixel_area_scale << LL_ENDL;
- }
-
- if (getParent() && !mIsSitting)
- {
- sitOnObject((LLViewerObject*)getParent());
- }
- else if (!getParent() && mIsSitting && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED))
- {
- getOffObject();
}
+}
- //--------------------------------------------------------------------
- // create local variables in world coords for region position values
- //--------------------------------------------------------------------
- F32 speed;
- LLVector3 normal;
-
- LLVector3 xyVel = getVelocity();
- xyVel.mV[VZ] = 0.0f;
- speed = xyVel.length();
- // remembering the value here prevents a display glitch if the
- // animation gets toggled during this update.
- bool was_sit_ground_constrained = isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED);
-
- if (!(mIsSitting && getParent()))
+void LLVOAvatar::updateRootPositionAndRotation(LLAgent& agent, F32 speed, bool was_sit_ground_constrained)
+{
+ if (!(isSitting() && getParent()))
{
// This case includes all configurations except sitting on an
// object, so does include ground sit.
@@ -3655,7 +3948,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
{
mTimeLast = animation_time;
- // put the pelvis at slaved position/mRotation
+ // Initially put the pelvis at slaved position/mRotation
// SL-315
mRoot->setWorldPosition( getPositionAgent() ); // first frame
mRoot->setWorldRotation( getRotation() );
@@ -3664,9 +3957,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
//--------------------------------------------------------------------
// dont' let dT get larger than 1/5th of a second
//--------------------------------------------------------------------
- F32 deltaTime = animation_time - mTimeLast;
+ F32 delta_time = animation_time - mTimeLast;
- deltaTime = llclamp( deltaTime, DELTA_TIME_MIN, DELTA_TIME_MAX );
+ delta_time = llclamp( delta_time, DELTA_TIME_MIN, DELTA_TIME_MAX );
mTimeLast = animation_time;
mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f);
@@ -3685,7 +3978,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition());
root_pos.mdV[VZ] += getVisualParamWeight(AVATAR_HOVER);
-
+ LLVector3 normal;
resolveHeightGlobal(root_pos, ground_under_pelvis, normal);
F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]);
BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) ||
@@ -3707,185 +4000,154 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
// correct for the fact that the pelvis is not necessarily the center
// of the agent's physical representation
root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot;
- if (!mIsSitting && !was_sit_ground_constrained)
+ if (!isSitting() && !was_sit_ground_constrained)
{
root_pos += LLVector3d(getHoverOffset());
}
-
- LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos);
-
-
- if (newPosition != mRoot->getXform()->getWorldPosition())
- {
- mRoot->touch();
- // SL-315
- mRoot->setWorldPosition( newPosition ); // regular update
- }
+ LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
+ if (cav)
+ {
+ cav->matchVolumeTransform();
+ }
+ else
+ {
+ LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos);
+ if (newPosition != mRoot->getXform()->getWorldPosition())
+ {
+ mRoot->touch();
+ // SL-315
+ mRoot->setWorldPosition( newPosition ); // regular update
+ }
+ }
//--------------------------------------------------------------------
// Propagate viewer object rotation to root of avatar
//--------------------------------------------------------------------
- if (!isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS))
+ if (!isControlAvatar() && !isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS))
{
- LLQuaternion iQ;
- LLVector3 upDir( 0.0f, 0.0f, 1.0f );
-
- // Compute a forward direction vector derived from the primitive rotation
- // and the velocity vector. When walking or jumping, don't let body deviate
- // more than 90 from the view, if necessary, flip the velocity vector.
-
- LLVector3 primDir;
- if (isSelf())
- {
- primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector());
- primDir.normalize();
- }
- else
- {
- primDir = getRotation().getMatrix3().getFwdRow();
- }
- LLVector3 velDir = getVelocity();
- velDir.normalize();
- if ( mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end())
- {
- F32 vpD = velDir * primDir;
- if (vpD < -0.5f)
- {
- velDir *= -1.0f;
- }
- }
- LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f));
- if (isSelf() && gAgentCamera.cameraMouselook())
- {
- // make sure fwdDir stays in same general direction as primdir
- if (gAgent.getFlying())
- {
- fwdDir = LLViewerCamera::getInstance()->getAtAxis();
- }
- else
- {
- LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis();
- LLVector3 up_vector = gAgent.getReferenceUpVector();
- at_axis -= up_vector * (at_axis * up_vector);
- at_axis.normalize();
-
- F32 dot = fwdDir * at_axis;
- if (dot < 0.f)
- {
- fwdDir -= 2.f * at_axis * dot;
- fwdDir.normalize();
- }
- }
- }
-
- LLQuaternion root_rotation = mRoot->getWorldMatrix().quaternion();
- F32 root_roll, root_pitch, root_yaw;
- root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw);
-
- // When moving very slow, the pelvis is allowed to deviate from the
- // forward direction to allow it to hold it's position while the torso
- // and head turn. Once in motion, it must conform however.
- BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook();
-
- LLVector3 pelvisDir( mRoot->getWorldMatrix().getFwdRow4().mV );
-
- static LLCachedControl<F32> s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow", 60.0);
- static LLCachedControl<F32> s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast", 2.0);
-
- F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, s_pelvis_rot_threshold_slow, s_pelvis_rot_threshold_fast);
-
- if (self_in_mouselook)
- {
- pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR;
- }
- pelvis_rot_threshold *= DEG_TO_RAD;
-
- F32 angle = angle_between( pelvisDir, fwdDir );
-
- // The avatar's root is allowed to have a yaw that deviates widely
- // from the forward direction, but if roll or pitch are off even
- // a little bit we need to correct the rotation.
- if(root_roll < 1.f * DEG_TO_RAD
- && root_pitch < 5.f * DEG_TO_RAD)
- {
- // smaller correction vector means pelvis follows prim direction more closely
- if (!mTurning && angle > pelvis_rot_threshold*0.75f)
- {
- mTurning = TRUE;
- }
-
- // use tighter threshold when turning
- if (mTurning)
- {
- pelvis_rot_threshold *= 0.4f;
- }
-
- // am I done turning?
- if (angle < pelvis_rot_threshold)
- {
- mTurning = FALSE;
- }
-
- LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f);
- fwdDir += correction_vector;
- }
- else
- {
- mTurning = FALSE;
- }
-
- // Now compute the full world space rotation for the whole body (wQv)
- LLVector3 leftDir = upDir % fwdDir;
- leftDir.normalize();
- fwdDir = leftDir % upDir;
- LLQuaternion wQv( fwdDir, leftDir, upDir );
-
- if (isSelf() && mTurning)
- {
- if ((fwdDir % pelvisDir) * upDir > 0.f)
- {
- gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT);
- }
- else
- {
- gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT);
- }
- }
-
- // Set the root rotation, but do so incrementally so that it
- // lags in time by some fixed amount.
- //F32 u = LLSmoothInterpolation::getInterpolant(PELVIS_LAG);
- F32 pelvis_lag_time = 0.f;
- if (self_in_mouselook)
- {
- pelvis_lag_time = PELVIS_LAG_MOUSELOOK;
- }
- else if (mInAir)
- {
- pelvis_lag_time = PELVIS_LAG_FLYING;
- // increase pelvis lag time when moving slowly
- pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f);
- }
- else
- {
- pelvis_lag_time = PELVIS_LAG_WALKING;
- }
-
- F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f);
-
- mRoot->setWorldRotation( slerp(u, mRoot->getWorldRotation(), wQv) );
-
+ // Rotation fixups for avatars in motion.
+ // Skip for animated objects.
+ updateOrientation(agent, speed, delta_time);
}
}
else if (mDrawable.notNull())
{
+ // Sitting on an object - mRoot is slaved to mDrawable orientation.
LLVector3 pos = mDrawable->getPosition();
pos += getHoverOffset() * mDrawable->getRotation();
// SL-315
mRoot->setPosition(pos);
mRoot->setRotation(mDrawable->getRotation());
}
+}
+
+//------------------------------------------------------------------------
+// updateCharacter()
+//
+// This is called for all avatars, so there are 4 possible situations:
+//
+// 1) Avatar is your own. In this case the class is LLVOAvatarSelf,
+// isSelf() is true, and agent specifies the corresponding agent
+// information for you. In all the other cases, agent is irrelevant
+// and it would be less confusing if it were null or something.
+//
+// 2) Avatar is controlled by another resident. Class is LLVOAvatar,
+// and isSelf() is false.
+//
+// 3) Avatar is the controller for an animated object. Class is
+// LLControlAvatar and mIsDummy is true. Avatar is a purely
+// viewer-side entity with no representation on the simulator.
+//
+// 4) Avatar is a UI avatar used in some areas of the UI, such as when
+// previewing uploaded animations. Class is LLUIAvatar, and mIsDummy
+// is true. Avatar is purely viewer-side with no representation on the
+// simulator.
+//
+//------------------------------------------------------------------------
+BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
+{
+ updateDebugText();
+
+ if (!mIsBuilt)
+ {
+ return FALSE;
+ }
+
+ BOOL visible = isVisible();
+ bool is_control_avatar = isControlAvatar(); // capture state to simplify tracing
+ bool is_attachment = false;
+ if (is_control_avatar)
+ {
+ LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
+ is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects
+ }
+
+ LLScopedContextString str("updateCharacter " + getFullname() + " is_control_avatar "
+ + boost::lexical_cast<std::string>(is_control_avatar)
+ + " is_attachment " + boost::lexical_cast<std::string>(is_attachment));
+
+ // For fading out the names above heads, only let the timer
+ // run if we're visible.
+ if (mDrawable.notNull() && !visible)
+ {
+ mTimeVisible.reset();
+ }
+
+ //--------------------------------------------------------------------
+ // The rest should only be done occasionally for far away avatars.
+ // Set mUpdatePeriod and visible based on distance and other criteria.
+ //--------------------------------------------------------------------
+ computeUpdatePeriod();
+ visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE;
+
+ //--------------------------------------------------------------------
+ // Early out if not visible and not self
+ // don't early out for your own avatar, as we rely on your animations playing reliably
+ // for example, the "turn around" animation when entering customize avatar needs to trigger
+ // even when your avatar is offscreen
+ //--------------------------------------------------------------------
+ if (!visible && !isSelf())
+ {
+ updateMotions(LLCharacter::HIDDEN_UPDATE);
+ return FALSE;
+ }
+
+ //--------------------------------------------------------------------
+ // change animation time quanta based on avatar render load
+ //--------------------------------------------------------------------
+ // SL-763 the time step quantization does not currently work.
+ //updateTimeStep();
+
+ //--------------------------------------------------------------------
+ // Update sitting state based on parent and active animation info.
+ //--------------------------------------------------------------------
+ if (getParent() && !isSitting())
+ {
+ sitOnObject((LLViewerObject*)getParent());
+ }
+ else if (!getParent() && isSitting() && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED))
+ {
+ getOffObject();
+ }
+
+ //--------------------------------------------------------------------
+ // create local variables in world coords for region position values
+ //--------------------------------------------------------------------
+ LLVector3 xyVel = getVelocity();
+ xyVel.mV[VZ] = 0.0f;
+ F32 speed = xyVel.length();
+ // remembering the value here prevents a display glitch if the
+ // animation gets toggled during this update.
+ bool was_sit_ground_constrained = isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED);
+
+ //--------------------------------------------------------------------
+ // This does a bunch of state updating, including figuring out
+ // whether av is in the air, setting mRoot position and rotation
+ // In some cases, calls updateOrientation() for a lot of the
+ // work
+ // --------------------------------------------------------------------
+ updateRootPositionAndRotation(agent, speed, was_sit_ground_constrained);
//-------------------------------------------------------------------------
// Update character motions
@@ -3904,7 +4166,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
}
// Special handling for sitting on ground.
- if (!getParent() && (mIsSitting || was_sit_ground_constrained))
+ if (!getParent() && (isSitting() || was_sit_ground_constrained))
{
F32 off_z = LLVector3d(getHoverOffset()).mdV[VZ];
@@ -3921,90 +4183,18 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
// update head position
updateHeadOffset();
- //-------------------------------------------------------------------------
- // Find the ground under each foot, these are used for a variety
- // of things that follow
- //-------------------------------------------------------------------------
- LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition();
- LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition();
-
- LLVector3 ankle_left_ground_agent = ankle_left_pos_agent;
- LLVector3 ankle_right_ground_agent = ankle_right_pos_agent;
- resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal);
- resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal);
-
- F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]);
- F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]);
-
- if (!mIsSitting)
- {
- //-------------------------------------------------------------------------
- // Figure out which foot is on ground
- //-------------------------------------------------------------------------
- if (!mInAir)
- {
- if ((leftElev < 0.0f) || (rightElev < 0.0f))
- {
- ankle_left_pos_agent = mFootLeftp->getWorldPosition();
- ankle_right_pos_agent = mFootRightp->getWorldPosition();
- leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ];
- rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ];
- }
- }
- }
-
- //-------------------------------------------------------------------------
// Generate footstep sounds when feet hit the ground
- //-------------------------------------------------------------------------
- const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND};
- const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS);
-
- if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) )
- {
- BOOL playSound = FALSE;
- LLVector3 foot_pos_agent;
-
- BOOL onGroundLeft = (leftElev <= 0.05f);
- BOOL onGroundRight = (rightElev <= 0.05f);
-
- // did left foot hit the ground?
- if ( onGroundLeft && !mWasOnGroundLeft )
- {
- foot_pos_agent = ankle_left_pos_agent;
- playSound = TRUE;
- }
-
- // did right foot hit the ground?
- if ( onGroundRight && !mWasOnGroundRight )
- {
- foot_pos_agent = ankle_right_pos_agent;
- playSound = TRUE;
- }
-
- mWasOnGroundLeft = onGroundLeft;
- mWasOnGroundRight = onGroundRight;
-
- if ( playSound )
- {
- const F32 STEP_VOLUME = 0.1f;
- const LLUUID& step_sound_id = getStepSound();
-
- LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent);
-
- if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global)
- && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds))
- {
- gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global);
- }
- }
- }
+ updateFootstepSounds();
+ // Update child joints as needed.
mRoot->updateWorldMatrixChildren();
- //mesh vertices need to be reskinned
- mNeedsSkin = TRUE;
+ // System avatar mesh vertices need to be reskinned.
+ mNeedsSkin = TRUE;
+
return TRUE;
}
+
//-----------------------------------------------------------------------------
// updateHeadOffset()
//-----------------------------------------------------------------------------
@@ -4019,7 +4209,7 @@ void LLVOAvatar::updateHeadOffset()
{
midEyePt = midEyePt * ~mDrawable->getWorldRotation();
}
- if (mIsSitting)
+ if (isSitting())
{
mHeadOffset = midEyePt;
}
@@ -4115,7 +4305,7 @@ void LLVOAvatar::updateVisibility()
if (mIsDummy)
{
- visible = TRUE;
+ visible = FALSE;
}
else if (mDrawable.isNull())
{
@@ -4229,7 +4419,8 @@ void LLVOAvatar::updateVisibility()
}
else
{
- if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP)
+ if (mMeshValid &&
+ (isControlAvatar() || mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP))
{
releaseMeshData();
}
@@ -4264,6 +4455,11 @@ U32 LLVOAvatar::renderSkinned()
return num_indices;
}
+ if (mDrawable.isNull())
+ {
+ return num_indices;
+ }
+
LLFace* face = mDrawable->getFace(0);
bool needs_rebuild = !face || !face->getVertexBuffer() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY);
@@ -4430,7 +4626,7 @@ U32 LLVOAvatar::renderSkinned()
{
if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
{
- if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_HEAD_BAKED) || isUIAvatar())
{
LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD);
if (head_mesh)
@@ -4440,7 +4636,7 @@ U32 LLVOAvatar::renderSkinned()
first_pass = FALSE;
}
}
- if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_UPPER_BAKED) || isUIAvatar())
{
LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY);
if (upper_mesh)
@@ -4450,7 +4646,7 @@ U32 LLVOAvatar::renderSkinned()
first_pass = FALSE;
}
- if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_LOWER_BAKED) || isUIAvatar())
{
LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY);
if (lower_mesh)
@@ -4479,7 +4675,7 @@ U32 LLVOAvatar::renderSkinned()
U32 LLVOAvatar::renderTransparent(BOOL first_pass)
{
U32 num_indices = 0;
- if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) )
+ if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) )
{
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT);
@@ -4507,18 +4703,15 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
}
first_pass = FALSE;
}
- // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair)
- // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible();
- if ( (getImage(TEX_HAIR_BAKED, 0) && getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE)
- || LLDrawPoolAlpha::sShowDebugAlpha)
- {
- LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
- if (hair_mesh)
- {
- num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
- }
- first_pass = FALSE;
- }
+ if (isTextureVisible(TEX_HAIR_BAKED))
+ {
+ LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
+ if (hair_mesh)
+ {
+ num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
+ }
+ first_pass = FALSE;
+ }
if (LLPipeline::sImpostorRender)
{
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
@@ -4558,7 +4751,7 @@ U32 LLVOAvatar::renderRigid()
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
}
- if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_EYES_BAKED) || isUIAvatar())
{
LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT);
LLViewerJoint* eyeball_right = getViewerJoint(MESH_ID_EYEBALL_RIGHT);
@@ -5105,10 +5298,13 @@ void LLVOAvatar::processAnimationStateChanges()
startMotion(ANIM_AGENT_WALK_ADJUST);
stopMotion(ANIM_AGENT_FLY_ADJUST);
}
- else if (mInAir && !mIsSitting)
+ else if (mInAir && !isSitting())
{
stopMotion(ANIM_AGENT_WALK_ADJUST);
- startMotion(ANIM_AGENT_FLY_ADJUST);
+ if (mEnableDefaultMotions)
+ {
+ startMotion(ANIM_AGENT_FLY_ADJUST);
+ }
}
else
{
@@ -5118,13 +5314,19 @@ void LLVOAvatar::processAnimationStateChanges()
if ( isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
{
- startMotion(ANIM_AGENT_TARGET);
+ if (mEnableDefaultMotions)
+ {
+ startMotion(ANIM_AGENT_TARGET);
+ }
stopMotion(ANIM_AGENT_BODY_NOISE);
}
else
{
stopMotion(ANIM_AGENT_TARGET);
- startMotion(ANIM_AGENT_BODY_NOISE);
+ if (mEnableDefaultMotions)
+ {
+ startMotion(ANIM_AGENT_BODY_NOISE);
+ }
}
// clear all current animations
@@ -5479,14 +5681,14 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id)
LLVOVolume* pVObj = pVO->mDrawable->getVOVolume();
if ( pVObj )
{
- const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj );
+ const LLMeshSkinInfo* pSkinData = pVObj->getSkinInfo();
if (pSkinData
&& pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG // full rig
&& pSkinData->mAlternateBindMatrix.size() > 0 )
- {
- mesh_id = pSkinData->mMeshID;
- return true;
- }
+ {
+ mesh_id = pSkinData->mMeshID;
+ return true;
+ }
}
}
return false;
@@ -5533,8 +5735,7 @@ bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name, const LLViewerOb
return false;
}
- LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
- const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
+ const LLMeshSkinInfo* pSkinData = vobj->getSkinInfo();
if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData )
{
@@ -5561,6 +5762,17 @@ void LLVOAvatar::clearAttachmentOverrides()
pJoint->clearAttachmentScaleOverrides();
}
}
+
+ if (mPelvisFixups.count()>0)
+ {
+ mPelvisFixups.clear();
+ LLJoint* pJointPelvis = getJoint("mPelvis");
+ if (pJointPelvis)
+ {
+ pJointPelvis->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) );
+ }
+ postPelvisSetRecalc();
+ }
}
//-----------------------------------------------------------------------------
@@ -5570,7 +5782,20 @@ void LLVOAvatar::rebuildAttachmentOverrides()
{
LLScopedContextString str("rebuildAttachmentOverrides " + getFullname());
- // Attachment points
+ clearAttachmentOverrides();
+
+ // Handle the case that we're resetting the skeleton of an animated object.
+ LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+ if (control_av)
+ {
+ LLVOVolume *volp = control_av->mRootVolp;
+ if (volp)
+ {
+ addAttachmentOverridesForObject(volp);
+ }
+ }
+
+ // Attached objects
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
@@ -5581,24 +5806,30 @@ void LLVOAvatar::rebuildAttachmentOverrides()
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin();
at_it != attachment_pt->mAttachedObjects.end(); ++at_it)
{
- addAttachmentOverridesForObject(*at_it);
+ LLViewerObject *vo = *at_it;
+ // Attached animated objects affect joints in their control
+ // avs, not the avs to which they are attached.
+ if (!vo->isAnimatedObject())
+ {
+ addAttachmentOverridesForObject(vo);
+ }
}
}
}
}
+
//-----------------------------------------------------------------------------
-// addAttachmentPosOverridesForObject
+// addAttachmentOverridesForObject
//-----------------------------------------------------------------------------
void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)
{
- LLVOAvatar *av = vo->getAvatarAncestor();
- if (!av || (av != this))
- {
+ if (vo->getAvatar() != this && vo->getAvatarAncestor() != this)
+ {
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
return;
- }
+ }
- LLScopedContextString str("addAttachmentOverridesForObject " + av->getFullname());
+ LLScopedContextString str("addAttachmentOverridesForObject " + vo->getAvatar()->getFullname());
// Process all children
LLViewerObject::const_child_list_t& children = vo->getChildren();
@@ -5621,10 +5852,9 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)
{
return;
}
- LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
- const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
+ const LLMeshSkinInfo* pSkinData = vobj->getSkinInfo();
- if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData )
+ if ( vobj && vobj->isMesh() && pSkinData )
{
const int bindCnt = pSkinData->mAlternateBindMatrix.size();
const int jointCnt = pSkinData->mJointNames.size();
@@ -5806,14 +6036,14 @@ void LLVOAvatar::showAttachmentOverrides(bool verbose) const
}
//-----------------------------------------------------------------------------
-// resetJointsOnDetach
+// removeAttachmentOverridesForObject
//-----------------------------------------------------------------------------
-void LLVOAvatar::resetJointsOnDetach(LLViewerObject *vo)
+void LLVOAvatar::removeAttachmentOverridesForObject(LLViewerObject *vo)
{
- LLVOAvatar *av = vo->getAvatarAncestor();
- if (!av || (av != this))
+ if (vo->getAvatar() != this && vo->getAvatarAncestor() != this)
{
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
+ return;
}
// Process all children
@@ -5822,21 +6052,21 @@ void LLVOAvatar::resetJointsOnDetach(LLViewerObject *vo)
it != children.end(); ++it)
{
LLViewerObject *childp = *it;
- resetJointsOnDetach(childp);
+ removeAttachmentOverridesForObject(childp);
}
// Process self.
LLUUID mesh_id;
if (getRiggedMeshID(vo,mesh_id))
{
- resetJointsOnDetach(mesh_id);
+ removeAttachmentOverridesForObject(mesh_id);
}
}
//-----------------------------------------------------------------------------
-// resetJointsOnDetach
+// removeAttachmentOverridesForObject
//-----------------------------------------------------------------------------
-void LLVOAvatar::resetJointsOnDetach(const LLUUID& mesh_id)
+void LLVOAvatar::removeAttachmentOverridesForObject(const LLUUID& mesh_id)
{
//Subsequent joints are relative to pelvis
avatar_joint_list_t::iterator iter = mSkeleton.begin();
@@ -5914,7 +6144,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;
- if (mIsDummy)
+ if (isUIAvatar())
{
outNorm.setVec(z_vec);
out_pos_agent = in_pos_agent;
@@ -5943,7 +6173,7 @@ F32 LLVOAvatar::getTimeDilation()
//-----------------------------------------------------------------------------
F32 LLVOAvatar::getPixelArea() const
{
- if (mIsDummy)
+ if (isUIAvatar())
{
return 100000.f;
}
@@ -6358,7 +6588,7 @@ void LLVOAvatar::removeChild(LLViewerObject *childp)
LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object)
{
- S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState());
+ S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getAttachmentState());
// This should never happen unless the server didn't process the attachment point
// correctly, but putting this check in here to be safe.
@@ -6421,6 +6651,11 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o
return 0;
}
+ if (!viewer_object->isAnimatedObject())
+ {
+ rebuildAttachmentOverrides();
+ }
+
updateVisualComplexity();
if (viewer_object->isSelected())
@@ -6450,19 +6685,63 @@ U32 LLVOAvatar::getNumAttachments() const
//-----------------------------------------------------------------------------
// canAttachMoreObjects()
+// Returns true if we can attach <n> more objects.
//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::canAttachMoreObjects() const
+BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const
{
- return (getNumAttachments() < MAX_AGENT_ATTACHMENTS);
+ return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS;
}
//-----------------------------------------------------------------------------
-// canAttachMoreObjects()
-// Returns true if we can attach <n> more objects.
+// getNumAnimatedObjectAttachments()
//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const
+U32 LLVOAvatar::getNumAnimatedObjectAttachments() const
{
- return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS;
+ U32 num_attachments = 0;
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ const LLViewerJointAttachment *attachment_pt = (*iter).second;
+ num_attachments += attachment_pt->getNumAnimatedObjects();
+ }
+ return num_attachments;
+}
+
+//-----------------------------------------------------------------------------
+// getMaxAnimatedObjectAttachments()
+// Gets from simulator feature if available, otherwise 0.
+//-----------------------------------------------------------------------------
+S32 LLVOAvatar::getMaxAnimatedObjectAttachments() const
+{
+ S32 max_attach = 0;
+ // AXON REMOVE AFTER SERVER TESTING DONE
+ if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits"))
+ {
+ max_attach = MAX_AGENT_ATTACHMENTS;
+ }
+ else
+ {
+ if (gAgent.getRegion())
+ {
+ LLSD features;
+ gAgent.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) <= getMaxAnimatedObjectAttachments();
}
//-----------------------------------------------------------------------------
@@ -6553,7 +6832,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
LLUUID mesh_id;
if (getRiggedMeshID(pVO, mesh_id))
{
- resetJointsOnDetach(mesh_id);
+ // FIXME this seems like an odd place for this code.
if ( gAgentCamera.cameraCustomizeAvatar() )
{
gAgent.unpauseAnimation();
@@ -6578,9 +6857,13 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
if (attachment->isObjectAttached(viewer_object))
{
updateVisualComplexity();
+ bool is_animated_object = viewer_object->isAnimatedObject();
cleanupAttachedMesh( viewer_object );
-
attachment->removeObject(viewer_object);
+ if (!is_animated_object)
+ {
+ rebuildAttachmentOverrides();
+ }
LL_DEBUGS() << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << LL_ENDL;
return TRUE;
}
@@ -6714,7 +6997,10 @@ void LLVOAvatar::getOffObject()
mRoot->setRotation(cur_rotation_world);
mRoot->getXform()->update();
- startMotion(ANIM_AGENT_BODY_NOISE);
+ if (mEnableDefaultMotions)
+ {
+ startMotion(ANIM_AGENT_BODY_NOISE);
+ }
if (isSelf())
{
@@ -6872,6 +7158,12 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
updateMeshTextures();
}
+// FIXME: We have an mVisible member, set in updateVisibility(), but this
+// function doesn't return it! isVisible() and mVisible are used
+// different places for different purposes. mVisible seems to be more
+// related to whether the actual avatar mesh is shown, and isVisible()
+// to whether anything about the avatar is displayed in the scene.
+// Maybe better naming could make this clearer?
BOOL LLVOAvatar::isVisible() const
{
return mDrawable.notNull()
@@ -6882,6 +7174,11 @@ BOOL LLVOAvatar::isVisible() const
// Determine if we have enough avatar data to render
bool LLVOAvatar::getIsCloud() const
{
+ if (mIsDummy)
+ {
+ return false;
+ }
+
return ( ((const_cast<LLVOAvatar*>(this))->visualParamWeightsAreDefault())// Do we have a shape?
|| ( !isTextureDefined(TEX_LOWER_BAKED)
|| !isTextureDefined(TEX_UPPER_BAKED)
@@ -7161,9 +7458,9 @@ bool LLVOAvatar::isTooComplex() const
// so that unlimited will completely disable the overly complex impostor rendering
// yes, this leaves them vulnerable to griefing objects... their choice
too_complex = ( max_render_cost > 0
- && ( mVisualComplexity > max_render_cost
- || (max_attachment_area > 0.0f && mAttachmentSurfaceArea > max_attachment_area)
- ));
+ && (mVisualComplexity > max_render_cost
+ || (max_attachment_area > 0.0f && mAttachmentSurfaceArea > max_attachment_area)
+ ));
}
return too_complex;
@@ -8846,6 +9143,11 @@ void LLVOAvatar::updateFreezeCounter(S32 counter)
BOOL LLVOAvatar::updateLOD()
{
+ if (mDrawable.isNull())
+ {
+ return FALSE;
+ }
+
if (isImpostor() && 0 != mDrawable->getNumFaces() && mDrawable->getFace(0)->hasGeometry())
{
return TRUE;
@@ -8886,10 +9188,10 @@ U32 LLVOAvatar::getPartitionType() const
void LLVOAvatar::updateImpostors()
{
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- LLCharacter::sAllowInstancesChange = FALSE;
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
+ std::vector<LLCharacter*> instances_copy = LLCharacter::sInstances;
+ for (std::vector<LLCharacter*>::iterator iter = instances_copy.begin();
+ iter != instances_copy.end(); ++iter)
{
LLVOAvatar* avatar = (LLVOAvatar*) *iter;
if (!avatar->isDead() && avatar->isVisible()
@@ -8986,6 +9288,17 @@ void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue)
void LLVOAvatar::idleUpdateRenderComplexity()
{
+ if (isControlAvatar())
+ {
+ LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
+ bool is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects
+ if (is_attachment)
+ {
+ // ARC for animated object attachments is accounted with the avatar they're attached to.
+ return;
+ }
+ }
+
// Render Complexity
calculateUpdateRenderComplexity(); // Update mVisualComplexity if needed
@@ -9033,10 +9346,16 @@ void LLVOAvatar::idleUpdateRenderComplexity()
// Visual rank
info_line = llformat("%d rank", mVisibilityRank);
// Use grey for imposters, white for normal rendering or no impostors
- info_color.set(isImpostor() ? LLColor4::grey : LLColor4::white);
+ info_color.set(isImpostor() ? LLColor4::grey : (isControlAvatar() ? LLColor4::yellow : LLColor4::white));
info_style = LLFontGL::NORMAL;
mText->addLine(info_line, info_color, info_style);
+ // Triangle count
+ mText->addLine(std::string("VisTris ") + LLStringOps::getReadableNumber(mAttachmentVisibleTriangleCount),
+ info_color, info_style);
+ mText->addLine(std::string("EstMaxTris ") + LLStringOps::getReadableNumber(mAttachmentEstTriangleCount),
+ info_color, info_style);
+
// Attachment Surface Area
static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f);
info_line = llformat("%.0f m^2", mAttachmentSurfaceArea);
@@ -9055,22 +9374,13 @@ void LLVOAvatar::idleUpdateRenderComplexity()
info_color.set(LLColor4::grey);
info_style = LLFontGL::NORMAL;
}
+
mText->addLine(info_line, info_color, info_style);
updateText(); // corrects position
}
}
-void LLVOAvatar::addAttachmentArea(F32 delta_area)
-{
- mAttachmentSurfaceArea += delta_area;
-}
-
-void LLVOAvatar::subtractAttachmentArea(F32 delta_area)
-{
- mAttachmentSurfaceArea = delta_area > mAttachmentSurfaceArea ? 0.0 : mAttachmentSurfaceArea - delta_area;
-}
-
void LLVOAvatar::updateVisualComplexity()
{
LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL;
@@ -9078,6 +9388,136 @@ void LLVOAvatar::updateVisualComplexity()
mVisualComplexityStale = true;
}
+// Account for the complexity of a single top-level object associated
+// with an avatar. This will be either an attached object or an animated
+// object.
+void LLVOAvatar::accountRenderComplexityForObject(
+ const LLViewerObject *attached_object,
+ const F32 max_attachment_complexity,
+ LLVOVolume::texture_cost_t& textures,
+ U32& cost,
+ hud_complexity_list_t& hud_complexity_list)
+{
+ if (attached_object && !attached_object->isHUDAttachment())
+ {
+ mAttachmentVisibleTriangleCount += attached_object->recursiveGetTriangleCount();
+ mAttachmentEstTriangleCount += attached_object->recursiveGetEstTrianglesMax();
+ mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea();
+
+ textures.clear();
+ const LLDrawable* drawable = attached_object->mDrawable;
+ if (drawable)
+ {
+ const LLVOVolume* volume = drawable->getVOVolume();
+ if (volume)
+ {
+ F32 attachment_total_cost = 0;
+ F32 attachment_volume_cost = 0;
+ F32 attachment_texture_cost = 0;
+ F32 attachment_children_cost = 0;
+ // AXON placeholder value, will revisit in testing.
+ const F32 animated_object_attachment_surcharge = 20000;
+
+ if (attached_object->isAnimatedObject())
+ {
+ attachment_volume_cost += animated_object_attachment_surcharge;
+ }
+ attachment_volume_cost += volume->getRenderCost(textures);
+
+ const_child_list_t children = volume->getChildren();
+ for (const_child_list_t::const_iterator child_iter = children.begin();
+ child_iter != children.end();
+ ++child_iter)
+ {
+ LLViewerObject* child_obj = *child_iter;
+ LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
+ if (child)
+ {
+ attachment_children_cost += child->getRenderCost(textures);
+ }
+ }
+
+ for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
+ volume_texture != textures.end();
+ ++volume_texture)
+ {
+ // add the cost of each individual texture in the linkset
+ attachment_texture_cost += volume_texture->second;
+ }
+ attachment_total_cost = attachment_volume_cost + attachment_texture_cost + attachment_children_cost;
+ LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID()
+ << " total: " << attachment_total_cost
+ << ", volume: " << attachment_volume_cost
+ << ", textures: " << attachment_texture_cost
+ << ", " << volume->numChildren()
+ << " children: " << attachment_children_cost
+ << LL_ENDL;
+ // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI
+ cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity);
+ }
+ }
+ }
+ if (isSelf()
+ && attached_object
+ && attached_object->isHUDAttachment()
+ && !attached_object->isTempAttachment()
+ && attached_object->mDrawable)
+ {
+ textures.clear();
+
+ mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea();
+
+ const LLVOVolume* volume = attached_object->mDrawable->getVOVolume();
+ if (volume)
+ {
+ LLHUDComplexity hud_object_complexity;
+ hud_object_complexity.objectName = attached_object->getAttachmentItemName();
+ hud_object_complexity.objectId = attached_object->getAttachmentItemID();
+ std::string joint_name;
+ gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name);
+ hud_object_complexity.jointName = joint_name;
+ // get cost and individual textures
+ hud_object_complexity.objectsCost += volume->getRenderCost(textures);
+ hud_object_complexity.objectsCount++;
+
+ LLViewerObject::const_child_list_t& child_list = attached_object->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ LLViewerObject* childp = *iter;
+ const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp);
+ if (chld_volume)
+ {
+ // get cost and individual textures
+ hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures);
+ hud_object_complexity.objectsCount++;
+ }
+ }
+
+ hud_object_complexity.texturesCount += textures.size();
+
+ for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
+ volume_texture != textures.end();
+ ++volume_texture)
+ {
+ // add the cost of each individual texture (ignores duplicates)
+ hud_object_complexity.texturesCost += volume_texture->second;
+ LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first);
+ if (tex)
+ {
+ // Note: Texture memory might be incorect since texture might be still loading.
+ hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory();
+ if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE)
+ {
+ hud_object_complexity.largeTexturesCount++;
+ }
+ }
+ }
+ hud_complexity_list.push_back(hud_object_complexity);
+ }
+ }
+}
+
// Calculations for mVisualComplexity value
void LLVOAvatar::calculateUpdateRenderComplexity()
{
@@ -9116,7 +9556,25 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
}
LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL;
+ mAttachmentVisibleTriangleCount = 0;
+ mAttachmentEstTriangleCount = 0.f;
+ mAttachmentSurfaceArea = 0.f;
+
+ // A standalone animated object needs to be accounted for
+ // using its associated volume. Attached animated objects
+ // will be covered by the subsequent loop over attachments.
+ LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+ if (control_av)
+ {
+ LLVOVolume *volp = control_av->mRootVolp;
+ if (volp && !volp->isAttachment())
+ {
+ accountRenderComplexityForObject(volp, max_attachment_complexity,
+ textures, cost, hud_complexity_list);
+ }
+ }
+ // Account for complexity of all attachments.
for (attachment_map_t::const_iterator attachment_point = mAttachmentPoints.begin();
attachment_point != mAttachmentPoints.end();
++attachment_point)
@@ -9127,112 +9585,8 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
++attachment_iter)
{
const LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object && !attached_object->isHUDAttachment())
- {
- textures.clear();
- const LLDrawable* drawable = attached_object->mDrawable;
- if (drawable)
- {
- const LLVOVolume* volume = drawable->getVOVolume();
- if (volume)
- {
- F32 attachment_total_cost = 0;
- F32 attachment_volume_cost = 0;
- F32 attachment_texture_cost = 0;
- F32 attachment_children_cost = 0;
-
- attachment_volume_cost += volume->getRenderCost(textures);
-
- const_child_list_t children = volume->getChildren();
- for (const_child_list_t::const_iterator child_iter = children.begin();
- child_iter != children.end();
- ++child_iter)
- {
- LLViewerObject* child_obj = *child_iter;
- LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
- if (child)
- {
- attachment_children_cost += child->getRenderCost(textures);
- }
- }
-
- for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
- volume_texture != textures.end();
- ++volume_texture)
- {
- // add the cost of each individual texture in the linkset
- attachment_texture_cost += volume_texture->second;
- }
- attachment_total_cost = attachment_volume_cost + attachment_texture_cost + attachment_children_cost;
- LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID()
- << " total: " << attachment_total_cost
- << ", volume: " << attachment_volume_cost
- << ", textures: " << attachment_texture_cost
- << ", " << volume->numChildren()
- << " children: " << attachment_children_cost
- << LL_ENDL;
- // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI
- cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity);
- }
- }
- }
- if (isSelf()
- && attached_object
- && attached_object->isHUDAttachment()
- && !attached_object->isTempAttachment()
- && attached_object->mDrawable)
- {
- textures.clear();
-
- const LLVOVolume* volume = attached_object->mDrawable->getVOVolume();
- if (volume)
- {
- LLHUDComplexity hud_object_complexity;
- hud_object_complexity.objectName = attached_object->getAttachmentItemName();
- hud_object_complexity.objectId = attached_object->getAttachmentItemID();
- std::string joint_name;
- gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name);
- hud_object_complexity.jointName = joint_name;
- // get cost and individual textures
- hud_object_complexity.objectsCost += volume->getRenderCost(textures);
- hud_object_complexity.objectsCount++;
-
- LLViewerObject::const_child_list_t& child_list = attached_object->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end(); ++iter)
- {
- LLViewerObject* childp = *iter;
- const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp);
- if (chld_volume)
- {
- // get cost and individual textures
- hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures);
- hud_object_complexity.objectsCount++;
- }
- }
-
- hud_object_complexity.texturesCount += textures.size();
-
- for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
- volume_texture != textures.end();
- ++volume_texture)
- {
- // add the cost of each individual texture (ignores duplicates)
- hud_object_complexity.texturesCost += volume_texture->second;
- LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first);
- if (tex)
- {
- // Note: Texture memory might be incorect since texture might be still loading.
- hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory();
- if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE)
- {
- hud_object_complexity.largeTexturesCount++;
- }
- }
- }
- hud_complexity_list.push_back(hud_object_complexity);
- }
- }
+ accountRenderComplexityForObject(attached_object, max_attachment_complexity,
+ textures, cost, hud_complexity_list);
}
}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index bd89d4ef23..de8da4f7ca 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -50,6 +50,8 @@
#include "llviewertexlayer.h"
#include "material_codes.h" // LL_MCODE_END
#include "llviewerstats.h"
+#include "llvovolume.h"
+#include "llavatarrendernotifier.h"
extern const LLUUID ANIM_AGENT_BODY_NOISE;
extern const LLUUID ANIM_AGENT_BREATHE_ROT;
@@ -169,7 +171,8 @@ public:
LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
LLVector4a* normal = NULL, // return the surface normal at the intersection point
LLVector4a* tangent = NULL); // return the surface tangent at the intersection point
- LLViewerObject* lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
+ virtual LLViewerObject* lineSegmentIntersectRiggedAttachments(
+ const LLVector4a& start, const LLVector4a& end,
S32 face = -1, // which face to check, -1 = ALL_SIDES
BOOL pick_transparent = FALSE,
BOOL pick_rigged = FALSE,
@@ -202,8 +205,8 @@ public:
LLJoint* getJoint(S32 num);
void addAttachmentOverridesForObject(LLViewerObject *vo);
- void resetJointsOnDetach(const LLUUID& mesh_id);
- void resetJointsOnDetach(LLViewerObject *vo);
+ void removeAttachmentOverridesForObject(const LLUUID& mesh_id);
+ void removeAttachmentOverridesForObject(LLViewerObject *vo);
bool jointIsRiggedTo(const std::string& joint_name);
bool jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo);
void clearAttachmentOverrides();
@@ -233,6 +236,9 @@ public:
public:
virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
+ virtual bool isControlAvatar() const { return mIsControlAvatar; } // True if this avatar is a control av (no associated user)
+ virtual bool isUIAvatar() const { return mIsUIAvatar; } // True if this avatar is a supplemental av used in some UI views (no associated user)
+
private: //aligned members
LL_ALIGN_16(LLVector4a mImpostorExtents[2]);
@@ -240,8 +246,14 @@ private: //aligned members
// Updates
//--------------------------------------------------------------------
public:
- void updateDebugText();
+ virtual void updateDebugText();
virtual BOOL updateCharacter(LLAgent &agent);
+ void updateFootstepSounds();
+ void computeUpdatePeriod();
+ void updateOrientation(LLAgent &agent, F32 speed, F32 delta_time);
+ void updateTimeStep();
+ void updateRootPositionAndRotation(LLAgent &agent, F32 speed, bool was_sit_ground_constrained);
+
void idleUpdateVoiceVisualizer(bool voice_enabled);
void idleUpdateMisc(bool detailed_update);
virtual void idleUpdateAppearanceAnimation();
@@ -259,14 +271,17 @@ public:
static void invalidateNameTags();
void addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font);
void idleUpdateRenderComplexity();
+ void accountRenderComplexityForObject(const LLViewerObject *attached_object,
+ const F32 max_attachment_complexity,
+ LLVOVolume::texture_cost_t& textures,
+ U32& cost,
+ hud_complexity_list_t& hud_complexity_list);
void calculateUpdateRenderComplexity();
static const U32 VISUAL_COMPLEXITY_UNKNOWN;
void updateVisualComplexity();
U32 getVisualComplexity() { return mVisualComplexity; }; // Numbers calculated here by rendering AV
F32 getAttachmentSurfaceArea() { return mAttachmentSurfaceArea; }; // estimated surface area of attachments
- void addAttachmentArea(F32 delta_area);
- void subtractAttachmentArea(F32 delta_area);
U32 getReportedVisualComplexity() { return mReportedVisualComplexity; }; // Numbers as reported by the SL server
void setReportedVisualComplexity(U32 value) { mReportedVisualComplexity = value; };
@@ -422,6 +437,8 @@ public:
private:
F32 mAttachmentSurfaceArea; //estimated surface area of attachments
+ U32 mAttachmentVisibleTriangleCount;
+ F32 mAttachmentEstTriangleCount;
bool shouldAlphaMask();
BOOL mNeedsSkin; // avatar has been animated and verts have not been updated
@@ -441,6 +458,14 @@ public:
VisualMuteSettings mVisuallyMuteSetting; // Always or never visually mute this AV
//--------------------------------------------------------------------
+ // animated object status
+ //--------------------------------------------------------------------
+public:
+ bool mIsControlAvatar;
+ bool mIsUIAvatar;
+ bool mEnableDefaultMotions;
+
+ //--------------------------------------------------------------------
// Morph masks
//--------------------------------------------------------------------
public:
@@ -739,9 +764,9 @@ public:
static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj);
/*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type ) const;
LLViewerObject * findAttachmentByID( const LLUUID & target_id ) const;
+ LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);
protected:
- LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);
void lazyAttach();
void rebuildRiggedAttachments( void );
@@ -761,10 +786,12 @@ public:
BOOL hasHUDAttachment() const;
LLBBox getHUDBBox() const;
void resetHUDAttachments();
- BOOL canAttachMoreObjects() const;
- BOOL canAttachMoreObjects(U32 n) const;
+ BOOL canAttachMoreObjects(U32 n=1) const;
+ S32 getMaxAnimatedObjectAttachments() const;
+ BOOL canAttachMoreAnimatedObjects(U32 n=1) const;
protected:
U32 getNumAttachments() const; // O(N), not O(1)
+ U32 getNumAnimatedObjectAttachments() const; // O(N), not O(1)
/** Wearables
** **
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 10af524ee7..a2144d6466 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2791,7 +2791,7 @@ BOOL LLVOAvatarSelf::needsRenderBeam()
// don't render selection beam on hud objects
is_touching_or_grabbing = FALSE;
}
- return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
+ return is_touching_or_grabbing || (getAttachmentState() & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
}
// static
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index de63a3963c..5def0f0c0f 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -92,7 +92,7 @@ LLVOGrass::~LLVOGrass()
void LLVOGrass::updateSpecies()
{
- mSpecies = mState;
+ mSpecies = getAttachmentState();
if (!sSpeciesTable.count(mSpecies))
{
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index f77b48ff80..588f57576e 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -76,8 +76,13 @@
#include "lldatapacker.h"
#include "llviewershadermgr.h"
#include "llvoavatar.h"
+#include "llcontrolavatar.h"
+#include "llvoavatarself.h"
#include "llvocache.h"
#include "llmaterialmgr.h"
+#include "llanimationstates.h"
+#include "llinventorytype.h"
+#include "llviewerinventory.h"
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
const F32 FORCE_CULL_AREA = 8.f;
@@ -86,6 +91,7 @@ U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 1;
BOOL gAnimateTextures = TRUE;
//extern BOOL gHideSelectedObjects;
+S32 LLVOVolume::sForceLOD = -1;
F32 LLVOVolume::sLODFactor = 1.f;
F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop
F32 LLVOVolume::sDistanceFactor = 1.0f;
@@ -1096,16 +1102,34 @@ void LLVOVolume::updateSculptTexture()
}
+void LLVOVolume::updateVisualComplexity()
+{
+ LLVOAvatar* avatar = getAvatarAncestor();
+ if (avatar)
+ {
+ avatar->updateVisualComplexity();
+ }
+ LLVOAvatar* rigged_avatar = getAvatar();
+ if(rigged_avatar && (rigged_avatar != avatar))
+ {
+ rigged_avatar->updateVisualComplexity();
+ }
+}
+
void LLVOVolume::notifyMeshLoaded()
{
mSculptChanged = TRUE;
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
- LLVOAvatar* avatar = getAvatar();
- if (avatar)
- {
- avatar->updateVisualComplexity();
- }
+ if (getAvatar() && !isAnimatedObject())
+ {
+ getAvatar()->addAttachmentOverridesForObject(this);
+ }
+ if (getControlAvatar() && isAnimatedObject())
+ {
+ getControlAvatar()->addAttachmentOverridesForObject(this);
+ }
+ updateVisualComplexity();
}
// sculpt replaces generate() for sculpted surfaces
@@ -1217,16 +1241,24 @@ void LLVOVolume::sculpt()
S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius)
{
S32 cur_detail;
- if (LLPipeline::sDynamicLOD)
- {
- // We've got LOD in the profile, and in the twist. Use radius.
- F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
- cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f));
- }
- else
- {
- cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);
- }
+ // AXON TEMP REMOVE
+ if (LLVOVolume::sForceLOD>=0 && LLVOVolume::sForceLOD<=3)
+ {
+ cur_detail = LLVOVolume::sForceLOD;
+ }
+ else
+ {
+ if (LLPipeline::sDynamicLOD)
+ {
+ // We've got LOD in the profile, and in the twist. Use radius.
+ F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
+ cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f));
+ }
+ else
+ {
+ cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);
+ }
+ }
return cur_detail;
}
@@ -1280,22 +1312,30 @@ BOOL LLVOVolume::calcLOD()
distance *= F_PI/3.f;
cur_detail = computeLODDetail(ll_round(distance, 0.01f),
- ll_round(radius, 0.01f));
-
+ ll_round(radius, 0.01f));
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT) && mDrawable->getFace(0))
+ {
+ if (isRootEdit())
+ {
+ S32 total_tris = recursiveGetTriangleCount();
+ S32 est_max_tris = recursiveGetEstTrianglesMax();
+ setDebugText(llformat("TRIS SHOWN %d EST %d", total_tris, est_max_tris));
+ }
+ }
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) &&
mDrawable->getFace(0))
{
- //setDebugText(llformat("%.2f:%.2f, %d", mDrawable->mDistanceWRTCamera, radius, cur_detail));
-
- setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex()));
+ // This is a debug display for LODs. Please don't put the texture index here.
+ setDebugText(llformat("%d", cur_detail));
}
if (cur_detail != mLOD)
{
mAppAngle = ll_round((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
mLOD = cur_detail;
- return TRUE;
+
+ return TRUE;
}
return FALSE;
@@ -1312,6 +1352,16 @@ BOOL LLVOVolume::updateLOD()
if (lod_changed)
{
+ if (debugLoggingEnabled("AnimatedObjectsLinkset"))
+ {
+ if (isAnimatedObject() && isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%u", (U32) this);
+ F32 est_tris = getEstTrianglesMax();
+ LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " updateLOD to " << getLOD() << ", tris " << est_tris << LL_ENDL;
+ }
+ }
+
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
mLODChanged = TRUE;
}
@@ -1386,7 +1436,8 @@ void LLVOVolume::updateFaceFlags()
BOOL LLVOVolume::setParent(LLViewerObject* parent)
{
BOOL ret = FALSE ;
- if (parent != getParent())
+ LLViewerObject *old_parent = (LLViewerObject*) getParent();
+ if (parent != old_parent)
{
ret = LLViewerObject::setParent(parent);
if (ret && mDrawable)
@@ -1394,6 +1445,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent)
gPipeline.markMoved(mDrawable);
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
}
+ updateAnimatedObjectStateOnReparent(old_parent, parent);
}
return ret ;
@@ -1651,6 +1703,11 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
if ((new_lod != old_lod) || mSculptChanged)
{
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ updateVisualComplexity();
+ }
+
compiled = TRUE;
sNumLODChanges += new_num_faces;
@@ -3269,6 +3326,138 @@ BOOL LLVOVolume::setIsFlexible(BOOL is_flexible)
return res;
}
+const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const
+{
+ if (getVolume())
+ {
+ return gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// virtual
+BOOL LLVOVolume::isRiggedMesh() const
+{
+ return isMesh() && getSkinInfo();
+}
+
+//----------------------------------------------------------------------------
+U32 LLVOVolume::getExtendedMeshFlags() const
+{
+ const LLExtendedMeshParams *param_block =
+ (const LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH);
+ if (param_block)
+ {
+ return param_block->getFlags();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void LLVOVolume::onSetExtendedMeshFlags(U32 flags)
+{
+
+ // The isAnySelected() check was needed at one point to prevent
+ // graphics problems. These are now believed to be fixed so the
+ // check has been disabled.
+ if (/*!getRootEdit()->isAnySelected() &&*/ mDrawable.notNull())
+ {
+ // Need to trigger rebuildGeom(), which is where control avatars get created/removed
+ getRootEdit()->recursiveMarkForUpdate(TRUE);
+ }
+ if (isAttachment() && getAvatarAncestor())
+ {
+ updateVisualComplexity();
+ if (flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG)
+ {
+ // Making a rigged mesh into an animated object
+ getAvatarAncestor()->rebuildAttachmentOverrides();
+ }
+ else
+ {
+ // Making an animated object into a rigged mesh
+ getAvatarAncestor()->rebuildAttachmentOverrides();
+ }
+ }
+}
+
+void LLVOVolume::setExtendedMeshFlags(U32 flags)
+{
+ U32 curr_flags = getExtendedMeshFlags();
+ if (curr_flags != flags)
+ {
+ bool in_use = true;
+ setParameterEntryInUse(LLNetworkData::PARAMS_EXTENDED_MESH, in_use, true);
+ LLExtendedMeshParams *param_block =
+ (LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH);
+ if (param_block)
+ {
+ param_block->setFlags(flags);
+ }
+ parameterChanged(LLNetworkData::PARAMS_EXTENDED_MESH, true);
+ LL_DEBUGS("AnimatedObjects") << (U32) this
+ << " new flags " << flags << " curr_flags " << curr_flags
+ << ", calling onSetExtendedMeshFlags()"
+ << LL_ENDL;
+ onSetExtendedMeshFlags(flags);
+ }
+}
+
+bool LLVOVolume::canBeAnimatedObject() const
+{
+ F32 est_tris = recursiveGetEstTrianglesMax();
+ if (est_tris < 0 || est_tris > getAnimatedObjectMaxTris())
+ {
+ return false;
+ }
+ return true;
+}
+
+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;
+}
+
+// Called any time parenting changes for a volume. Update flags and
+// control av accordingly. This is called after parent has been
+// changed to new_parent.
+void LLVOVolume::updateAnimatedObjectStateOnReparent(LLViewerObject *old_parent, LLViewerObject *new_parent)
+{
+ LLVOVolume *old_volp = dynamic_cast<LLVOVolume*>(old_parent);
+
+ if (new_parent && !new_parent->isAvatar())
+ {
+ if (mControlAvatar.notNull())
+ {
+ // Here an animated object is being made the child of some
+ // other prim. Should remove the control av from the child.
+ LLControlAvatar *av = mControlAvatar;
+ mControlAvatar = NULL;
+ av->markForDeath();
+ }
+ // If this succeeds now, it's because the new_parent is an animated object
+ if (isAnimatedObject() && getControlAvatar())
+ {
+ getControlAvatar()->addAttachmentOverridesForObject(this);
+ }
+ }
+ if (old_volp && old_volp->isAnimatedObject())
+ {
+ if (old_volp->getControlAvatar())
+ {
+ // We have been removed from an animated object, need to do cleanup.
+ old_volp->getControlAvatar()->rebuildAttachmentOverrides();
+ }
+ }
+}
+
//----------------------------------------------------------------------------
void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
@@ -3330,7 +3519,7 @@ void LLVOVolume::updateRadius()
BOOL LLVOVolume::isAttachment() const
{
- return mState != 0 ;
+ return mAttachmentState != 0 ;
}
BOOL LLVOVolume::isHUDAttachment() const
@@ -3338,7 +3527,7 @@ BOOL LLVOVolume::isHUDAttachment() const
// *NOTE: we assume hud attachment points are in defined range
// since this range is constant for backwards compatibility
// reasons this is probably a reasonable assumption to make
- S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState);
+ S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mAttachmentState);
return ( attachment_id >= 31 && attachment_id <= 38 );
}
@@ -3441,7 +3630,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(), getLOD());
if ( size > 0)
{
- if (gMeshRepo.getSkinInfo(volume_params.getSculptID(), this))
+ if (isRiggedMesh())
{
// weighted attachment - 1 point for every 3 bytes
weighted_mesh = 1;
@@ -3623,6 +3812,15 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
return (U32)shame;
}
+F32 LLVOVolume::getEstTrianglesMax() const
+{
+ if (isMesh() && getVolume())
+ {
+ return gMeshRepo.getEstTrianglesMax(getVolume()->getParams().getSculptID());
+ }
+ return 0.f;
+}
+
F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const
{
F32 radius = getScale().length()*0.5f;
@@ -3714,6 +3912,21 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u
{
mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin);
}
+ if (!local_origin && param_type == LLNetworkData::PARAMS_EXTENDED_MESH)
+ {
+ U32 extended_mesh_flags = getExtendedMeshFlags();
+ bool enabled = (extended_mesh_flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG);
+ bool was_enabled = (getControlAvatar() != NULL);
+ if (enabled != was_enabled)
+ {
+ LL_DEBUGS("AnimatedObjects") << (U32) this
+ << " calling onSetExtendedMeshFlags, enabled " << (U32) enabled
+ << " was_enabled " << (U32) was_enabled
+ << " local_origin " << (U32) local_origin
+ << LL_ENDL;
+ onSetExtendedMeshFlags(extended_mesh_flags);
+ }
+ }
if (mDrawable.notNull())
{
BOOL is_light = getIsLight();
@@ -3727,10 +3940,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)
@@ -3840,6 +4060,22 @@ const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const
return xform->getWorldMatrix();
}
+void LLVOVolume::markForUpdate(BOOL priority)
+{
+ if (debugLoggingEnabled("AnimatedObjectsLinkset"))
+ {
+ if (isAnimatedObject() && isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%u", (U32) this);
+ F32 est_tris = getEstTrianglesMax();
+ LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " markForUpdate, tris " << est_tris << LL_ENDL;
+ }
+ }
+
+ LLViewerObject::markForUpdate(priority);
+ mVolumeChanged = TRUE;
+}
+
LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const
{
LLVector3 ret = pos - getRenderPosition();
@@ -4092,9 +4328,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
bool LLVOVolume::treatAsRigged()
{
return isSelected() &&
- isAttachment() &&
- mDrawable.notNull() &&
- mDrawable->isState(LLDrawable::RIGGED);
+ (isAttachment() || isAnimatedObject()) &&
+ mDrawable.notNull() &&
+ mDrawable->isState(LLDrawable::RIGGED);
}
LLRiggedVolume* LLVOVolume::getRiggedVolume()
@@ -4124,9 +4360,7 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
}
LLVolume* volume = getVolume();
-
- const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this);
-
+ const LLMeshSkinInfo* skin = getSkinInfo();
if (!skin)
{
clearRiggedVolume();
@@ -4134,7 +4368,6 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
}
LLVOAvatar* avatar = getAvatar();
-
if (!avatar)
{
clearRiggedVolume();
@@ -4149,7 +4382,6 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
}
mRiggedVolume->update(skin, avatar, volume);
-
}
static LLTrace::BlockTimerStatHandle FTM_SKIN_RIGGED("Skin");
@@ -4179,6 +4411,21 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
{
copyVolumeFaces(volume);
}
+ else
+ {
+#if 1
+ bool is_paused = avatar && avatar->areAnimationsPaused();
+ if (is_paused)
+ {
+ S32 frames_paused = LLFrameTimer::getFrameCount() - avatar->getMotionController().getPausedFrame();
+ if (frames_paused > 2)
+ {
+ return;
+ }
+ }
+#endif
+ }
+
//build matrix palette
static const size_t kMaxJoints = LL_MAX_JOINTS_PER_MESH_OBJECT;
@@ -4187,6 +4434,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin);
LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar);
+ S32 rigged_vert_count = 0;
+ S32 rigged_face_count = 0;
+ LLVector4a box_min, box_max;
for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
{
const LLVolumeFace& vol_face = volume->getVolumeFace(i);
@@ -4208,6 +4458,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED);
U32 max_joints = LLSkinningUtil::getMaxJointCount();
+ rigged_vert_count += dst_face.mNumVertices;
+ rigged_face_count++;
for (U32 j = 0; j < dst_face.mNumVertices; ++j)
{
LLMatrix4a final_mat;
@@ -4227,12 +4479,19 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
min = pos[0];
max = pos[1];
+ if (i==0)
+ {
+ box_min = min;
+ box_max = max;
+ }
for (U32 j = 1; j < dst_face.mNumVertices; ++j)
{
min.setMin(min, pos[j]);
max.setMax(max, pos[j]);
}
+ box_min.setMin(min,box_min);
+ box_max.setMax(max,box_max);
dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
dst_face.mCenter->mul(0.5f);
@@ -4252,6 +4511,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
}
}
}
+ mExtraDebugText = llformat("rigged %d/%d - box (%f %f %f) (%f %f %f)",
+ rigged_face_count, rigged_vert_count,
+ box_min[0], box_min[1], box_min[2],
+ box_max[0], box_max[1], box_max[2]);
}
U32 LLVOVolume::getPartitionType() const
@@ -4643,8 +4906,6 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
-
-
if (group->changeLOD())
{
group->mLastUpdateDistance = group->mDistance;
@@ -4665,27 +4926,19 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
group->mBuilt = 1.f;
- LLVOAvatar* pAvatarVO = NULL;
-
LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
- if (bridge)
- {
- if (bridge->mAvatar.isNull())
- {
- LLViewerObject* vobj = bridge->mDrawable->getVObj();
- if (vobj)
- {
- bridge->mAvatar = vobj->getAvatar();
- }
- }
-
- pAvatarVO = bridge->mAvatar;
- }
+ LLViewerObject *vobj = NULL;
+ LLVOVolume *vol_obj = NULL;
- if (pAvatarVO)
+ if (bridge)
{
- pAvatarVO->subtractAttachmentArea( group->mSurfaceArea );
+ vobj = bridge->mDrawable->getVObj();
+ vol_obj = dynamic_cast<LLVOVolume*>(vobj);
}
+ if (vol_obj)
+ {
+ vol_obj->updateVisualComplexity();
+ }
group->mGeometryBytes = 0;
group->mSurfaceArea = 0;
@@ -4728,7 +4981,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST);
//get all the faces into a list
- for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
+ for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin();
+ drawable_iter != group->getDataEnd(); ++drawable_iter)
{
LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
@@ -4743,12 +4997,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
LLVOVolume* vobj = drawablep->getVOVolume();
-
+
if (!vobj)
{
continue;
}
+ std::string vobj_name = llformat("Vol%u", (U32) vobj);
+
if (vobj->isMesh() &&
((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))
{
@@ -4762,29 +5018,36 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
}
+ bool is_mesh = vobj->isMesh();
+ F32 est_tris = vobj->getEstTrianglesMax();
+
+ LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuilding, isAttachment: " << (U32) vobj->isAttachment()
+ << " is_mesh " << is_mesh
+ << " est_tris " << est_tris
+ << " is_animated " << vobj->isAnimatedObject()
+ << " can_animate " << vobj->canBeAnimatedObject()
+ << " cav " << vobj->getControlAvatar()
+ << " playing " << (U32) (vobj->getControlAvatar() ? vobj->getControlAvatar()->mPlaying : false)
+ << " frame " << LLFrameTimer::getFrameCount()
+ << LL_ENDL;
+
llassert_always(vobj);
vobj->updateTextureVirtualSize(true);
vobj->preRebuild();
drawablep->clearState(LLDrawable::HAS_ALPHA);
- bool rigged = vobj->isAttachment() &&
- vobj->isMesh() &&
- gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
+ // Standard rigged mesh attachments:
+ bool rigged = !vobj->isAnimatedObject() && vobj->isRiggedMesh() && vobj->isAttachment();
+ // Animated objects. Have to check for isRiggedMesh() to
+ // exclude static objects in animated object linksets.
+ rigged = rigged || (vobj->isAnimatedObject() && vobj->isRiggedMesh() &&
+ vobj->getControlAvatar() && vobj->getControlAvatar()->mPlaying);
+ vobj->updateControlAvatar();
+
bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
-
- bool is_rigged = false;
-
- if (rigged && pAvatarVO)
- {
- pAvatarVO->addAttachmentOverridesForObject(vobj);
- if (!LLApp::isExiting() && pAvatarVO->isSelf() && debugLoggingEnabled("AvatarAttachments"))
- {
- bool verbose = true;
- pAvatarVO->showAttachmentOverrides(verbose);
- }
- }
+ bool any_rigged_face = false;
//for each face
for (S32 i = 0; i < drawablep->getNumFaces(); i++)
@@ -4802,7 +5065,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
//sum up face verts and indices
drawablep->updateFaceSize(i);
- if (rigged)
+ if (rigged)
{
if (!facep->isState(LLFace::RIGGED))
{ //completely reset vertex buffer
@@ -4810,7 +5073,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
facep->setState(LLFace::RIGGED);
- is_rigged = true;
+ any_rigged_face = true;
//get drawpool of avatar with rigged face
LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
@@ -5154,7 +5417,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
- if (is_rigged)
+ if (any_rigged_face)
{
if (!drawablep->isState(LLDrawable::RIGGED))
{
@@ -5168,6 +5431,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
else
{
drawablep->clearState(LLDrawable::RIGGED);
+ vobj->updateRiggedVolume();
}
}
}
@@ -5221,9 +5485,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
if(drawablep)
{
- drawablep->clearState(LLDrawable::REBUILD_ALL);
- }
- }
+ drawablep->clearState(LLDrawable::REBUILD_ALL);
+ }
+ }
}
group->mLastUpdateTime = gFrameTimeSeconds;
@@ -5236,11 +5500,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
mFaceList.clear();
-
- if (pAvatarVO)
- {
- pAvatarVO->addAttachmentArea( group->mSurfaceArea );
- }
}
static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh");
@@ -5269,6 +5528,17 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
{
LLVOVolume* vobj = drawablep->getVOVolume();
+
+ if (debugLoggingEnabled("AnimatedObjectsLinkset"))
+ {
+ if (vobj->isAnimatedObject() && vobj->isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%u", (U32) vobj);
+ F32 est_tris = vobj->getEstTrianglesMax();
+ LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;
+ }
+ }
+
vobj->preRebuild();
if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index a331908320..afd6c234ee 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -62,6 +62,8 @@ public:
}
void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume);
+
+ std::string mExtraDebugText;
};
// Base class for implementations of the volume - Primitive, Flexible Object, etc.
@@ -132,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 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); }
@@ -159,7 +162,7 @@ public:
/*virtual*/ F32 getRadius() const { return mVObjRadius; };
const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const;
- void markForUpdate(BOOL priority) { LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; }
+ void markForUpdate(BOOL priority);
void faceMappingChanged() { mFaceMappingChanged=TRUE; };
/*virtual*/ void onShift(const LLVector4a &shift_vector); // Called when the drawable shifts
@@ -259,12 +262,26 @@ public:
virtual BOOL isFlexible() const;
virtual BOOL isSculpted() const;
virtual BOOL isMesh() const;
+ virtual BOOL isRiggedMesh() const;
virtual BOOL hasLightTexture() const;
+
BOOL isVolumeGlobal() const;
BOOL canBeFlexible() const;
BOOL setIsFlexible(BOOL is_flexible);
+ const LLMeshSkinInfo* getSkinInfo() const;
+
+ // Extended Mesh Properties
+ U32 getExtendedMeshFlags() const;
+ void onSetExtendedMeshFlags(U32 flags);
+ void setExtendedMeshFlags(U32 flags);
+ bool canBeAnimatedObject() const;
+ bool isAnimatedObject() const;
+ void updateAnimatedObjectStateOnReparent(LLViewerObject *old_parent, LLViewerObject *new_parent);
+
+ std::map<LLUUID, S32> mObjectSignaledAnimations; // requested state of Animation name/value
+
// Functions that deal with media, or media navigation
// Update this object's media data with the given media data array
@@ -298,7 +315,10 @@ public:
bool hasMedia() const;
LLVector3 getApproximateFaceNormal(U8 face_id);
-
+
+ // Flag any corresponding avatars as needing update.
+ void updateVisualComplexity();
+
void notifyMeshLoaded();
// Returns 'true' iff the media data for this object is in flight
@@ -379,6 +399,7 @@ private:
public:
static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop
static F32 sLODFactor; // LOD scale factor
+ static S32 sForceLOD; // LOD override
static F32 sDistanceFactor; // LOD distance factor
static LLPointer<LLObjectMediaDataClient> sObjectMediaClient;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 1d083bb2fd..dd136d2fb8 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3350,6 +3350,18 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f
{
if (drawablep && !drawablep->isDead() && assertInitialized())
{
+ if (debugLoggingEnabled("AnimatedObjectsLinkset"))
+ {
+ LLVOVolume *vol_obj = drawablep->getVOVolume();
+ if (vol_obj && vol_obj->isAnimatedObject() && vol_obj->isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%u", (U32) vol_obj);
+ F32 est_tris = vol_obj->getEstTrianglesMax();
+ LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " markRebuild, tris " << est_tris
+ << " priority " << (S32) priority << " flag " << std::hex << flag << LL_ENDL;
+ }
+ }
+
if (!drawablep->isState(LLDrawable::BUILT))
{
priority = true;
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index c9670a60f2..d7fbbdafb6 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -513,11 +513,11 @@ public:
RENDER_DEBUG_TEXTURE_AREA = 0x00000100,
RENDER_DEBUG_FACE_AREA = 0x00000200,
RENDER_DEBUG_PARTICLES = 0x00000400,
- RENDER_DEBUG_GLOW = 0x00000800,
+ RENDER_DEBUG_GLOW = 0x00000800, // not used
RENDER_DEBUG_TEXTURE_ANIM = 0x00001000,
RENDER_DEBUG_LIGHTS = 0x00002000,
RENDER_DEBUG_BATCH_SIZE = 0x00004000,
- RENDER_DEBUG_ALPHA_BINS = 0x00008000,
+ RENDER_DEBUG_ALPHA_BINS = 0x00008000, // not used
RENDER_DEBUG_RAYCAST = 0x00010000,
RENDER_DEBUG_AVATAR_DRAW_INFO = 0x00020000,
RENDER_DEBUG_SHADOW_FRUSTA = 0x00040000,
@@ -531,8 +531,9 @@ public:
RENDER_DEBUG_NORMALS = 0x04000000,
RENDER_DEBUG_LOD_INFO = 0x08000000,
RENDER_DEBUG_RENDER_COMPLEXITY = 0x10000000,
- RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000,
- RENDER_DEBUG_TEXEL_DENSITY = 0x40000000
+ RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used
+ RENDER_DEBUG_TEXEL_DENSITY = 0x40000000,
+ RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000
};
public:
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index ed3cc26851..63e2ed4bb9 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2,7 +2,7 @@
<floater
positioning="cascading"
legacy_header_height="18"
- height="590"
+ height="600"
layout="topleft"
bg_opaque_image="Window_NoTitle_Foreground"
bg_alpha_image="Window_NoTitle_Background"
@@ -2131,7 +2131,7 @@ even though the user gets a free copy.
<panel
border="false"
follows="all"
- height="367"
+ height="387"
label="Features"
layout="topleft"
left_delta="0"
@@ -2169,13 +2169,23 @@ even though the user gets a free copy.
Edit object features:
</text>
<check_box
- height="19"
+ height="15"
+ label="Animated Mesh"
+ layout="topleft"
+ left="10"
+ name="Animated Mesh Checkbox Ctrl"
+ tool_tip="Allows rigged mesh objects to be animated independently"
+ top_pad="10"
+ width="121" />
+ <check_box
+ height="10"
label="Flexible Path"
+ follows="left|top"
layout="topleft"
left="10"
name="Flexible1D Checkbox Ctrl"
tool_tip="Allows object to flex about the Z axis (Client-side only)"
- top_pad="20"
+ top_pad="15"
width="121" />
<spinner
follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 92511167c0..eea7124eb8 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2648,6 +2648,16 @@
parameter="lod info" />
</menu_item_check>
<menu_item_check
+ label="Triangle Count"
+ name="Triangle Count">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="triangle count" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="triangle count" />
+ </menu_item_check>
+ <menu_item_check
label="Build Queue"
name="Build Queue">
<menu_item_check.on_check
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index a0130b568a..8c9c03617a 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -10202,6 +10202,14 @@ You have been teleported by the object '[OBJECT_NAME]' owned by an unknown user.
Unable to create requested object. The region is full.
</notification>
+ <notification
+ icon="alertmodal.tga"
+ name="CantCreateAnimatedObjectTooLarge"
+ type="notify">
+ <tag>fail</tag>
+Unable to create requested animated object because it exceeds the size limit.
+ </notification>
+
<notification
icon="alertmodal.tga"
name="CantAttackMultipleObjOneSpot"
@@ -10332,6 +10340,38 @@ You are not allowed to change this shape.
<notification
icon="alertmodal.tga"
+ name="NoPermsTooManyAttachedAnimatedObjects"
+ type="notify">
+ <tag>fail</tag>
+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"
name="NoAccessToClaimObjects"
type="notify">
<tag>fail</tag>