diff options
Diffstat (limited to 'indra/newview/llvoavatar.cpp')
-rw-r--r-- | indra/newview/llvoavatar.cpp | 2507 |
1 files changed, 1688 insertions, 819 deletions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b221dc7c35..321f774210 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 ), @@ -625,6 +630,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mTyping(FALSE), mMeshValid(FALSE), mVisible(FALSE), + mLastImpostorUpdateFrameTime(0.f), mWindFreq(0.f), mRipplePhase( 0.f ), mBelowWater(FALSE), @@ -663,7 +669,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; @@ -689,6 +698,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNeedsImpostorUpdate = TRUE; mNeedsAnimUpdate = TRUE; + mNeedsExtentUpdate = true; + mImpostorDistance = 0; mImpostorPixelArea = 0; @@ -718,6 +729,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mCurrentGesticulationLevel = 0; + mRuthTimer.reset(); mRuthDebugTimer.reset(); mDebugExistenceTimer.reset(); @@ -733,8 +745,15 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, std::string LLVOAvatar::avString() const { - std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); - return " Avatar '" + getFullname() + "' " + viz_string + " "; + if (isControlAvatar()) + { + return getFullname(); + } + else + { + std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); + return " Avatar '" + getFullname() + "' " + viz_string + " "; + } } void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string comment) @@ -1091,6 +1110,8 @@ void LLVOAvatar::initClass() // Where should this be set initially? LLJoint::setDebugJointNames(gSavedSettings.getString("DebugAvatarJoints")); + + LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged); } @@ -1099,7 +1120,7 @@ void LLVOAvatar::cleanupClass() } // virtual -void LLVOAvatar::initInstance(void) +void LLVOAvatar::initInstance() { //------------------------------------------------------------------------- // register motions @@ -1170,6 +1191,8 @@ void LLVOAvatar::initInstance(void) //VTPause(); // VTune mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) ); + + mInitFlags |= 1<<1; } // virtual @@ -1222,8 +1245,6 @@ const LLVector3 LLVOAvatar::getRenderPosition() const { return getPosition() * mDrawable->getParent()->getRenderMatrix(); } - - } void LLVOAvatar::updateDrawable(BOOL force_damped) @@ -1240,6 +1261,29 @@ void LLVOAvatar::onShift(const LLVector4a& shift_vector) void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { + if (mDrawable.isNull()) + { + return; + } + + if (mNeedsExtentUpdate) + { + calculateSpatialExtents(newMin,newMax); + mLastAnimExtents[0].set(newMin.getF32ptr()); + mLastAnimExtents[1].set(newMax.getF32ptr()); + mLastAnimBasePos = mPelvisp->getWorldPosition(); + mNeedsExtentUpdate = false; + } + else + { + LLVector3 new_base_pos = mPelvisp->getWorldPosition(); + LLVector3 shift = new_base_pos-mLastAnimBasePos; + mLastAnimExtents[0] += shift; + mLastAnimExtents[1] += shift; + mLastAnimBasePos = new_base_pos; + + } + if (isImpostor() && !needsImpostorUpdate()) { LLVector3 delta = getRenderPosition() - @@ -1250,98 +1294,185 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) } else { - getSpatialExtents(newMin,newMax); - mLastAnimExtents[0].set(newMin.getF32ptr()); - mLastAnimExtents[1].set(newMax.getF32ptr()); + newMin.load3(mLastAnimExtents[0].mV); + newMax.load3(mLastAnimExtents[1].mV); LLVector4a pos_group; pos_group.setAdd(newMin,newMax); pos_group.mul(0.5f); mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition(); mDrawable->setPositionGroup(pos_group); } - - } -void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) + +static LLTrace::BlockTimerStatHandle FTM_AVATAR_EXTENT_UPDATE("Av Upd Extent"); + +void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { - LLVector4a buffer(0.25f); + LL_RECORD_BLOCK_TIME(FTM_AVATAR_EXTENT_UPDATE); + + S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity"); + + // FIXME the update_min_max function used below assumes there is a + // known starting point, but in general there isn't. Ideally the + // box update logic should be modified to handle the no-point-yet + // case. For most models, starting with the pelvis is safe though. + LLVector3 zero_pos; LLVector4a pos; - pos.load3(getRenderPosition().mV); - newMin.setSub(pos, buffer); - newMax.setAdd(pos, buffer); + if (dist_vec(zero_pos, mPelvisp->getWorldPosition())<0.001) + { + // Don't use pelvis until av initialized + pos.load3(getRenderPosition().mV); + } + else + { + pos.load3(mPelvisp->getWorldPosition().mV); + } + newMin = pos; + newMax = pos; - float max_attachment_span = get_default_max_prim_scale() * 5.0f; - - //stretch bounding box by joint positions - for (polymesh_map_t::iterator i = mPolyMeshes.begin(); i != mPolyMeshes.end(); ++i) - { - LLPolyMesh* mesh = i->second; - for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.size(); joint_num++) - { - LLVector4a trans; - trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV); - update_min_max(newMin, newMax, trans); - } - } + //stretch bounding box by joint positions. Doing this for + //control avs, where the polymeshes aren't maintained or + //displayed, can give inaccurate boxes due to joints stuck at (0,0,0). + if ((box_detail>=1) && !isControlAvatar()) + { + for (polymesh_map_t::iterator i = mPolyMeshes.begin(); i != mPolyMeshes.end(); ++i) + { + LLPolyMesh* mesh = i->second; + for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.size(); joint_num++) + { + LLVector4a trans; + trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV); + update_min_max(newMin, newMax, trans); + } + } - LLVector4a center, size; - center.setAdd(newMin, newMax); - center.mul(0.5f); + } - size.setSub(newMax,newMin); - size.mul(0.5f); + // Pad bounding box for starting joint, plus polymesh if + // applicable. Subsequent calcs should be accurate enough to not + // need padding. + LLVector4a padding(0.25); + newMin.sub(padding); + newMax.add(padding); - mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); - //stretch bounding box by attachments - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; + //stretch bounding box by static attachments + if (box_detail >= 2) + { + float max_attachment_span = get_default_max_prim_scale() * 5.0f; + + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; - if (attachment->getValid()) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && !attached_object->isHUDAttachment()) - { - LLDrawable* drawable = attached_object->mDrawable; - if (drawable && !drawable->isState(LLDrawable::RIGGED)) - { - LLSpatialBridge* bridge = drawable->getSpatialBridge(); - if (bridge) - { - const LLVector4a* ext = bridge->getSpatialExtents(); - LLVector4a distance; - distance.setSub(ext[1], ext[0]); - LLVector4a max_span(max_attachment_span); + if (attachment->getValid()) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + // Don't we need to look at children of attached_object as well? + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && !attached_object->isHUDAttachment()) + { + const LLVOVolume *vol = dynamic_cast<const LLVOVolume*>(attached_object); + if (vol && vol->isAnimatedObject()) + { + // Animated objects already have a bounding box in their control av, use that. + // Could lag by a frame if there's no guarantee on order of processing for avatars. + LLControlAvatar *cav = vol->getControlAvatar(); + if (cav) + { + LLVector4a cav_min; + cav_min.load3(cav->mLastAnimExtents[0].mV); + LLVector4a cav_max; + cav_max.load3(cav->mLastAnimExtents[1].mV); + update_min_max(newMin,newMax,cav_min); + update_min_max(newMin,newMax,cav_max); + continue; + } + } + if (vol && vol->isRiggedMesh()) + { + continue; + } + LLDrawable* drawable = attached_object->mDrawable; + if (drawable && !drawable->isState(LLDrawable::RIGGED)) + { + LLSpatialBridge* bridge = drawable->getSpatialBridge(); + if (bridge) + { + const LLVector4a* ext = bridge->getSpatialExtents(); + LLVector4a distance; + distance.setSub(ext[1], ext[0]); + LLVector4a max_span(max_attachment_span); - S32 lt = distance.lessThan(max_span).getGatheredBits() & 0x7; + S32 lt = distance.lessThan(max_span).getGatheredBits() & 0x7; - // Only add the prim to spatial extents calculations if it isn't a megaprim. - // max_attachment_span calculated at the start of the function - // (currently 5 times our max prim size) - if (lt == 0x7) - { - update_min_max(newMin,newMax,ext[0]); - update_min_max(newMin,newMax,ext[1]); - } - } - } - } - } - } - } + // Only add the prim to spatial extents calculations if it isn't a megaprim. + // max_attachment_span calculated at the start of the function + // (currently 5 times our max prim size) + if (lt == 0x7) + { + update_min_max(newMin,newMax,ext[0]); + update_min_max(newMin,newMax,ext[1]); + } + } + } + } + } + } + } + } - //pad bounding box + // Stretch bounding box by rigged mesh joint boxes + if (box_detail>=3) + { + updateRiggingInfo(); + for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) + { + LLJoint *joint = getJoint(joint_num); + LLJointRiggingInfo *rig_info = NULL; + if (joint_num < mJointRiggingInfoTab.size()) + { + rig_info = &mJointRiggingInfoTab[joint_num]; + } + + if (joint && rig_info && rig_info->isRiggedTo()) + { + LLViewerJointAttachment *as_joint_attach = dynamic_cast<LLViewerJointAttachment*>(joint); + if (as_joint_attach && as_joint_attach->getIsHUDAttachment()) + { + // Ignore bounding box of HUD joints + continue; + } + LLMatrix4a mat; + LLVector4a new_extents[2]; + mat.loadu(joint->getWorldMatrix()); + matMulBoundBox(mat, rig_info->getRiggedExtents(), new_extents); + update_min_max(newMin, newMax, new_extents[0]); + update_min_max(newMin, newMax, new_extents[1]); + //if (isSelf()) + //{ + // LL_INFOS() << joint->getName() << " extents " << new_extents[0] << "," << new_extents[1] << LL_ENDL; + // LL_INFOS() << joint->getName() << " av box is " << newMin << "," << newMax << LL_ENDL; + //} + } + } + } - newMin.sub(buffer); - newMax.add(buffer); + // Update pixel area + LLVector4a center, size; + center.setAdd(newMin, newMax); + center.mul(0.5f); + + size.setSub(newMax,newMin); + size.mul(0.5f); + + mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); } void render_sphere_and_line(const LLVector3& begin_pos, const LLVector3& end_pos, F32 sphere_scale, const LLVector3& occ_color, const LLVector3& visible_color) @@ -1404,13 +1535,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 +1569,6 @@ void LLVOAvatar::renderCollisionVolumes() mNameText->lineSegmentIntersect(unused, unused, unused, TRUE); } - - mDebugText.clear(); - addDebugText(ostr.str()); } void LLVOAvatar::renderBones() @@ -1467,7 +1611,7 @@ void LLVOAvatar::renderBones() } else { - if (jointIsRiggedTo(jointp->getName())) + if (jointIsRiggedTo(jointp)) { occ_color = RIGGED_COLOR_OCCLUDED; visible_color = RIGGED_COLOR_VISIBLE; @@ -1595,6 +1739,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 +1829,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 +1946,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 @@ -1856,7 +2010,7 @@ void LLVOAvatar::resetVisualParams() void LLVOAvatar::resetSkeleton(bool reset_animations) { LL_DEBUGS("Avatar") << avString() << " reset starts" << LL_ENDL; - if (!mLastProcessedAppearance) + if (!isControlAvatar() && !mLastProcessedAppearance) { LL_WARNS() << "Can't reset avatar; no appearance message has been received yet." << LL_ENDL; return; @@ -1910,12 +2064,15 @@ void LLVOAvatar::resetSkeleton(bool reset_animations) } // Reset tweakable params to preserved state - bool slam_params = true; - applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params); + if (mLastProcessedAppearance) + { + bool slam_params = true; + applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params); + } updateVisualParams(); // Restore attachment pos overrides - rebuildAttachmentOverrides(); + updateAttachmentOverrides(); // Animations if (reset_animations) @@ -1942,7 +2099,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 +2119,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 +2151,10 @@ void LLVOAvatar::releaseMeshData() void LLVOAvatar::restoreMeshData() { llassert(!isSelf()); + if (mDrawable.isNull()) + { + return; + } //LL_INFOS() << "Restoring" << LL_ENDL; mMeshValid = TRUE; @@ -2291,6 +2452,18 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) return; } + // Update should be happening max once per frame. + const S32 upd_freq = 4; // force update every upd_freq frames. + if ((mLastAnimExtents[0]==LLVector3())|| + (mLastAnimExtents[1])==LLVector3()) + { + mNeedsExtentUpdate = true; + } + else + { + mNeedsExtentUpdate = ((LLDrawable::getCurrentFrame()+mID.mData[0])%upd_freq==0); + } + LLScopedContextString str("avatar_idle_update " + getFullname()); checkTextureLoading() ; @@ -2303,7 +2476,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 +2642,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 ); @@ -2573,8 +2746,10 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) } else { - //VECTORIZE THIS - getSpatialExtents(ext[0], ext[1]); + ext[0].load3(mLastAnimExtents[0].mV); + ext[1].load3(mLastAnimExtents[1].mV); + // Expensive. Just call this once per frame, in updateSpatialExtents(); + //calculateSpatialExtents(ext[0], ext[1]); LLVector4a diff; diff.setSub(ext[1], mImpostorExtents[1]); if (diff.getLength3().getF32() > 0.05f) @@ -2593,13 +2768,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 +2938,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()); } @@ -3358,154 +3537,218 @@ bool LLVOAvatar::isInMuteList() return muted; } -void LLVOAvatar::updateDebugText() +void LLVOAvatar::updateAppearanceMessageDebugText() { - // clear debug text - mDebugText.clear(); + S32 central_bake_version = -1; + if (getRegion()) + { + central_bake_version = getRegion()->getCentralBakeVersion(); + } + bool all_baked_downloaded = allBakedTexturesCompletelyDownloaded(); + bool all_local_downloaded = allLocalTexturesCompletelyDownloaded(); + std::string debug_line = llformat("%s%s - mLocal: %d, mEdit: %d, mUSB: %d, CBV: %d", + isSelf() ? (all_local_downloaded ? "L" : "l") : "-", + all_baked_downloaded ? "B" : "b", + mUseLocalAppearance, mIsEditingAppearance, + 1, central_bake_version); + std::string origin_string = bakedTextureOriginInfo(); + debug_line += " [" + origin_string + "]"; + S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); + S32 last_request_cof_version = mLastUpdateRequestCOFVersion; + S32 last_received_cof_version = mLastUpdateReceivedCOFVersion; + if (isSelf()) + { + debug_line += llformat(" - cof: %d req: %d rcv:%d", + curr_cof_version, last_request_cof_version, last_received_cof_version); + if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) + { + debug_line += " FORCING ERRS"; + } + } + else + { + debug_line += llformat(" - cof rcv:%d", last_received_cof_version); + } + debug_line += llformat(" bsz-z: %.3f", mBodySize[2]); + if (mAvatarOffset[2] != 0.0f) + { + debug_line += llformat("avofs-z: %.3f", mAvatarOffset[2]); + } + bool hover_enabled = getRegion() && getRegion()->avatarHoverHeightEnabled(); + debug_line += hover_enabled ? " H" : " h"; + const LLVector3& hover_offset = getHoverOffset(); + if (hover_offset[2] != 0.0) + { + debug_line += llformat(" hov_z: %.3f", hover_offset[2]); + 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(); + LLVector3 normal; + LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; + resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); + F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); + debug_line += llformat(" relev %.3f", rightElev); - if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) - { - S32 central_bake_version = -1; - if (getRegion()) - { - central_bake_version = getRegion()->getCentralBakeVersion(); - } - bool all_baked_downloaded = allBakedTexturesCompletelyDownloaded(); - bool all_local_downloaded = allLocalTexturesCompletelyDownloaded(); - std::string debug_line = llformat("%s%s - mLocal: %d, mEdit: %d, mUSB: %d, CBV: %d", - isSelf() ? (all_local_downloaded ? "L" : "l") : "-", - all_baked_downloaded ? "B" : "b", - mUseLocalAppearance, mIsEditingAppearance, - 1, central_bake_version); - std::string origin_string = bakedTextureOriginInfo(); - debug_line += " [" + origin_string + "]"; - S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); - S32 last_request_cof_version = mLastUpdateRequestCOFVersion; - S32 last_received_cof_version = mLastUpdateReceivedCOFVersion; - if (isSelf()) - { - debug_line += llformat(" - cof: %d req: %d rcv:%d", - curr_cof_version, last_request_cof_version, last_received_cof_version); - if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) - { - debug_line += " FORCING ERRS"; - } - } - else - { - debug_line += llformat(" - cof rcv:%d", last_received_cof_version); - } - debug_line += llformat(" bsz-z: %.3f", mBodySize[2]); - if (mAvatarOffset[2] != 0.0f) + LLVector3 root_pos = mRoot->getPosition(); + 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); +} + +LLViewerInventoryItem* getObjectInventoryItem(LLViewerObject *vobj, LLUUID asset_id) +{ + LLViewerInventoryItem *item = NULL; + + if (vobj) + { + if (vobj->getInventorySerial()<=0) { - debug_line += llformat("avofs-z: %.3f", mAvatarOffset[2]); + vobj->requestInventory(); } - bool hover_enabled = getRegion() && getRegion()->avatarHoverHeightEnabled(); - debug_line += hover_enabled ? " H" : " h"; - const LLVector3& hover_offset = getHoverOffset(); - 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", (isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED) ? "G" : "-")); - } - LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); - LLVector3 normal; - LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; - resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); - F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); - debug_line += llformat(" relev %.3f", rightElev); + item = vobj->getInventoryItemByAsset(asset_id); + } + return item; +} - LLVector3 root_pos = mRoot->getPosition(); - LLVector3 pelvis_pos = mPelvisp->getPosition(); - debug_line += llformat(" rp %.3f pp %.3f", root_pos[2], pelvis_pos[2]); +LLViewerInventoryItem* recursiveGetObjectInventoryItem(LLViewerObject *vobj, LLUUID asset_id) +{ + LLViewerInventoryItem *item = getObjectInventoryItem(vobj, asset_id); + if (!item) + { + LLViewerObject::const_child_list_t& children = vobj->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); + it != children.end(); ++it) + { + LLViewerObject *childp = *it; + item = getObjectInventoryItem(childp, asset_id); + if (item) + { + break; + } + } + } + return item; +} - addDebugText(debug_line); +void LLVOAvatar::updateAnimationDebugText() +{ + for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); + iter != mMotionController.getActiveMotions().end(); ++iter) + { + LLMotion* motionp = *iter; + if (motionp->getMinPixelArea() < getPixelArea()) + { + std::string output; + 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; + LLViewerInventoryItem *item = recursiveGetObjectInventoryItem(volp,motionp->getID()); + if (item) + { + motion_name = item->getName(); + } + } + } + if (motion_name.empty()) + { + std::string name; + if (gAgent.isGodlikeWithoutAdminMenuFakery() || isSelf()) + { + name = motionp->getID().asString(); + LLVOAvatar::AnimSourceIterator anim_it = mAnimationSources.begin(); + for (; anim_it != mAnimationSources.end(); ++anim_it) + { + if (anim_it->second == motionp->getID()) + { + LLViewerObject* object = gObjectList.findObject(anim_it->first); + if (!object) + { + break; + } + if (object->isAvatar()) + { + if (mMotionController.mIsSelf) + { + // Searching inventory by asset id is really long + // so just mark as inventory + // Also item is likely to be named by LLPreviewAnim + name += "(inventory)"; + } + } + else + { + LLViewerInventoryItem* item = NULL; + if (!object->isInventoryDirty()) + { + item = object->getInventoryItemByAsset(motionp->getID()); + } + if (item) + { + name = item->getName(); + } + else if (object->isAttachment()) + { + name += "(" + getAttachmentItemName() + ")"; + } + else + { + // in-world object, name or content unknown + name += "(in-world)"; + } + } + break; + } + } + } + else + { + name = LLUUID::null.asString(); + } + output = llformat("%s - %d", + name.c_str(), + (U32)motionp->getPriority()); + } + else + { + output = llformat("%s - %d", + motion_name.c_str(), + (U32)motionp->getPriority()); + } + addDebugText(output); + } + } +} + +void LLVOAvatar::updateDebugText() +{ + // Leave mDebugText uncleared here, in case a derived class has added some state first + + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + { + updateAppearanceMessageDebugText(); } + 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(); - iter != mMotionController.getActiveMotions().end(); ++iter) - { - LLMotion* motionp = *iter; - if (motionp->getMinPixelArea() < getPixelArea()) - { - std::string output; - if (motionp->getName().empty()) - { - std::string name; - if (gAgent.isGodlikeWithoutAdminMenuFakery() || isSelf()) - { - name = motionp->getID().asString(); - LLVOAvatar::AnimSourceIterator anim_it = mAnimationSources.begin(); - for (; anim_it != mAnimationSources.end(); ++anim_it) - { - if (anim_it->second == motionp->getID()) - { - LLViewerObject* object = gObjectList.findObject(anim_it->first); - if (!object) - { - break; - } - if (object->isAvatar()) - { - if (mMotionController.mIsSelf) - { - // Searching inventory by asset id is really long - // so just mark as inventory - // Also item is likely to be named by LLPreviewAnim - name += "(inventory)"; - } - } - else - { - LLViewerInventoryItem* item = NULL; - if (!object->isInventoryDirty()) - { - item = object->getInventoryItemByAsset(motionp->getID()); - } - if (item) - { - name = item->getName(); - } - else if (object->isAttachment()) - { - name += "(" + getAttachmentItemName() + ")"; - } - else - { - // in-world object, name or content unknown - name += "(in-world)"; - } - } - break; - } - } - } - else - { - name = LLUUID::null.asString(); - } - - output = llformat("%s - %d", - name.c_str(), - (U32)motionp->getPriority()); - } - else - { - output = llformat("%s - %d", - motionp->getName().c_str(), - (U32)motionp->getPriority()); - } - addDebugText(output); - } - } + updateAnimationDebugText(); } if (!mDebugText.size() && mText.notNull()) @@ -3517,51 +3760,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 +3902,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 +4123,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 +4132,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 +4153,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 +4175,155 @@ 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) + { + // SL-1350: Moved to LLDrawable::updateXform() + 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 +4342,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 +4359,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 +4385,7 @@ void LLVOAvatar::updateHeadOffset() { midEyePt = midEyePt * ~mDrawable->getWorldRotation(); } - if (mIsSitting) + if (isSitting()) { mHeadOffset = midEyePt; } @@ -4115,7 +4481,7 @@ void LLVOAvatar::updateVisibility() if (mIsDummy) { - visible = TRUE; + visible = FALSE; } else if (mDrawable.isNull()) { @@ -4229,7 +4595,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 +4631,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 +4802,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 +4812,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 +4822,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 +4851,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 +4879,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 +4927,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); @@ -4596,22 +4965,53 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) left *= mImpostorDim.mV[0]; up *= mImpostorDim.mV[1]; - LLGLEnable test(GL_ALPHA_TEST); - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f); - - gGL.color4ubv(color.mV); - gGL.getTexUnit(diffuse_channel)->bind(&mImpostor); - gGL.begin(LLRender::QUADS); - gGL.texCoord2f(0,0); - gGL.vertex3fv((pos+left-up).mV); - gGL.texCoord2f(1,0); - gGL.vertex3fv((pos-left-up).mV); - gGL.texCoord2f(1,1); - gGL.vertex3fv((pos-left+up).mV); - gGL.texCoord2f(0,1); - gGL.vertex3fv((pos+left+up).mV); - gGL.end(); - gGL.flush(); + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_IMPOSTORS)) + { + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ADD); + gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); + + // gGL.begin(LLRender::QUADS); + // gGL.vertex3fv((pos+left-up).mV); + // gGL.vertex3fv((pos-left-up).mV); + // gGL.vertex3fv((pos-left+up).mV); + // gGL.vertex3fv((pos+left+up).mV); + // gGL.end(); + + + gGL.begin(LLRender::LINES); + gGL.color4f(1.f,1.f,1.f,1.f); + F32 thickness = llmax(F32(5.0f-5.0f*(gFrameTimeSeconds-mLastImpostorUpdateFrameTime)),1.0f); + glLineWidth(thickness); + gGL.vertex3fv((pos+left-up).mV); + gGL.vertex3fv((pos-left-up).mV); + gGL.vertex3fv((pos-left-up).mV); + gGL.vertex3fv((pos-left+up).mV); + gGL.vertex3fv((pos-left+up).mV); + gGL.vertex3fv((pos+left+up).mV); + gGL.vertex3fv((pos+left+up).mV); + gGL.vertex3fv((pos+left-up).mV); + gGL.end(); + gGL.flush(); + } + { + LLGLEnable test(GL_ALPHA_TEST); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f); + + gGL.color4ubv(color.mV); + gGL.getTexUnit(diffuse_channel)->bind(&mImpostor); + gGL.begin(LLRender::QUADS); + gGL.texCoord2f(0,0); + gGL.vertex3fv((pos+left-up).mV); + gGL.texCoord2f(1,0); + gGL.vertex3fv((pos-left-up).mV); + gGL.texCoord2f(1,1); + gGL.vertex3fv((pos-left+up).mV); + gGL.texCoord2f(0,1); + gGL.vertex3fv((pos+left+up).mV); + gGL.end(); + gGL.flush(); + } return 6; } @@ -5105,10 +5505,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 +5521,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 @@ -5488,72 +5897,30 @@ 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; - } - } - } - return false; -} - -bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name) -{ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && jointIsRiggedTo(joint_name, attached_object)) - { + { + mesh_id = pSkinData->mMeshID; return true; } - } + } } - return false; + return false; } -bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo) +bool LLVOAvatar::jointIsRiggedTo(const LLJoint *joint) const { - // Process all children - LLViewerObject::const_child_list_t& children = vo->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); - it != children.end(); ++it) - { - LLViewerObject *childp = *it; - if (jointIsRiggedTo(joint_name,childp)) - { - return true; - } - } - - const LLVOVolume *vobj = dynamic_cast<const LLVOVolume*>(vo); - if (!vobj) - { - return false; - } - - LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); - - if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData ) - { - if (std::find(pSkinData->mJointNames.begin(), pSkinData->mJointNames.end(), joint_name) != - pSkinData->mJointNames.end()) + if (joint) + { + const LLJointRiggingInfoTab& tab = mJointRiggingInfoTab; + S32 joint_num = joint->getJointNum(); + if (joint_num < tab.size() && tab[joint_num].isRiggedTo()) { return true; } } - return false; } @@ -5570,6 +5937,20 @@ 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(); + } + + mActiveOverrideMeshes.clear(); + onActiveOverrideMeshesChanged(); } //----------------------------------------------------------------------------- @@ -5579,7 +5960,25 @@ void LLVOAvatar::rebuildAttachmentOverrides() { LLScopedContextString str("rebuildAttachmentOverrides " + getFullname()); - // Attachment points + LL_DEBUGS("AnimatedObjects") << "rebuilding" << LL_ENDL; + dumpStack("AnimatedObjectsStack"); + + 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) + { + LL_DEBUGS("Avatar") << volp->getID() << " adding attachment overrides for root vol, prim count " + << (S32) (1+volp->numChildren()) << LL_ENDL; + addAttachmentOverridesForObject(volp); + } + } + + // Attached objects for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -5590,33 +5989,164 @@ 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 -//----------------------------------------------------------------------------- -void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) +// updateAttachmentOverrides +// +// This is intended to give the same results as +// rebuildAttachmentOverrides(), while avoiding redundant work. +// ----------------------------------------------------------------------------- +void LLVOAvatar::updateAttachmentOverrides() { - LLVOAvatar *av = vo->getAvatarAncestor(); - if (!av || (av != this)) + LLScopedContextString str("updateAttachmentOverrides " + getFullname()); + + LL_DEBUGS("AnimatedObjects") << "updating" << LL_ENDL; + dumpStack("AnimatedObjectsStack"); + + std::set<LLUUID> meshes_seen; + + // Handle the case that we're updating the skeleton of an animated object. + LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this); + if (control_av) + { + LLVOVolume *volp = control_av->mRootVolp; + if (volp) + { + LL_DEBUGS("Avatar") << volp->getID() << " adding attachment overrides for root vol, prim count " + << (S32) (1+volp->numChildren()) << LL_ENDL; + addAttachmentOverridesForObject(volp, &meshes_seen); + } + } + + // Attached objects + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { + LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin(); + at_it != attachment_pt->mAttachedObjects.end(); ++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, &meshes_seen); + } + } + } + } + // Remove meshes that are no longer present on the skeleton + + // have to work with a copy because removeAttachmentOverrides() will change mActiveOverrideMeshes. + std::set<LLUUID> active_override_meshes = mActiveOverrideMeshes; + for (std::set<LLUUID>::iterator it = active_override_meshes.begin(); it != active_override_meshes.end(); ++it) + { + if (meshes_seen.find(*it) == meshes_seen.end()) + { + removeAttachmentOverridesForObject(*it); + } + } + + +#ifdef ATTACHMENT_OVERRIDE_VALIDATION + { + std::vector<LLVector3OverrideMap> pos_overrides_by_joint; + std::vector<LLVector3OverrideMap> scale_overrides_by_joint; + LLVector3OverrideMap pelvis_fixups; + + // Capture snapshot of override state after update + for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) + { + LLVector3OverrideMap pos_overrides; + LLJoint *joint = getJoint(joint_num); + if (joint) + { + pos_overrides_by_joint.push_back(joint->m_attachmentPosOverrides); + scale_overrides_by_joint.push_back(joint->m_attachmentScaleOverrides); + } + else + { + // No joint, use default constructed empty maps + pos_overrides_by_joint.push_back(LLVector3OverrideMap()); + scale_overrides_by_joint.push_back(LLVector3OverrideMap()); + } + } + pelvis_fixups = mPelvisFixups; + //dumpArchetypeXML(getFullname() + "_paranoid_updated"); + + // Rebuild and compare + rebuildAttachmentOverrides(); + //dumpArchetypeXML(getFullname() + "_paranoid_rebuilt"); + bool mismatched = false; + for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) + { + LLJoint *joint = getJoint(joint_num); + if (joint) + { + if (pos_overrides_by_joint[joint_num] != joint->m_attachmentPosOverrides) + { + mismatched = true; + } + if (scale_overrides_by_joint[joint_num] != joint->m_attachmentScaleOverrides) + { + mismatched = true; + } + } + } + if (pelvis_fixups != mPelvisFixups) + { + mismatched = true; + } + if (mismatched) + { + LL_WARNS() << "MISMATCHED ATTACHMENT OVERRIDES" << LL_ENDL; + } + } +#endif +} + +//----------------------------------------------------------------------------- +// addAttachmentOverridesForObject +//----------------------------------------------------------------------------- +void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen, bool recursive) +{ + 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 " + getFullname()); + + LL_DEBUGS("AnimatedObjects") << "adding" << LL_ENDL; + dumpStack("AnimatedObjectsStack"); // Process all children - LLViewerObject::const_child_list_t& children = vo->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); - it != children.end(); ++it) - { - LLViewerObject *childp = *it; - addAttachmentOverridesForObject(childp); - } + if (recursive) + { + LLViewerObject::const_child_list_t& children = vo->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); + it != children.end(); ++it) + { + LLViewerObject *childp = *it; + addAttachmentOverridesForObject(childp, meshes_seen, true); + } + } LLVOVolume *vobj = dynamic_cast<LLVOVolume*>(vo); bool pelvisGotSet = false; @@ -5625,15 +6155,18 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) { return; } + + LLViewerObject *root_object = (LLViewerObject*)vobj->getRoot(); + LL_DEBUGS("AnimatedObjects") << "trying to add attachment overrides for root object " << root_object->getID() << " prim is " << vobj << LL_ENDL; if (vobj->isMesh() && ((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled())) { + LL_DEBUGS("AnimatedObjects") << "failed to add attachment overrides for root object " << root_object->getID() << " mesh asset not loaded" << LL_ENDL; 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(); @@ -5645,8 +6178,26 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) { const F32 pelvisZOffset = pSkinData->mPelvisOffset; const LLUUID& mesh_id = pSkinData->mMeshID; + + if (meshes_seen) + { + meshes_seen->insert(mesh_id); + } + bool mesh_overrides_loaded = (mActiveOverrideMeshes.find(mesh_id) != mActiveOverrideMeshes.end()); + if (mesh_overrides_loaded) + { + LL_DEBUGS("AnimatedObjects") << "skipping add attachment overrides for " << mesh_id + << " to root object " << root_object->getID() + << ", already loaded" + << LL_ENDL; + } + else + { + LL_DEBUGS("AnimatedObjects") << "adding attachment overrides for " << mesh_id + << " to root object " << root_object->getID() << LL_ENDL; + } bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false; - if ( fullRig ) + if ( fullRig && !mesh_overrides_loaded ) { for ( int i=0; i<jointCnt; ++i ) { @@ -5690,9 +6241,15 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) } } + mActiveOverrideMeshes.insert(mesh_id); + onActiveOverrideMeshesChanged(); } } } + else + { + LL_DEBUGS("AnimatedObjects") << "failed to add attachment overrides for root object " << root_object->getID() << " not mesh or no pSkinData" << LL_ENDL; + } //Rebuild body data if we altered joints/pelvis if ( pelvisGotSet ) @@ -5815,14 +6372,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 @@ -5831,37 +6388,32 @@ 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(); - avatar_joint_list_t::iterator end = mSkeleton.end(); - LLJoint* pJointPelvis = getJoint("mPelvis"); - - for (; iter != end; ++iter) - { - LLJoint* pJoint = (*iter); - //Reset joints except for pelvis + const std::string av_string = avString(); + for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) + { + LLJoint *pJoint = getJoint(joint_num); if ( pJoint ) { bool dummy; // unused - pJoint->removeAttachmentPosOverride(mesh_id, avString(),dummy); - pJoint->removeAttachmentScaleOverride(mesh_id, avString()); + pJoint->removeAttachmentPosOverride(mesh_id, av_string, dummy); + pJoint->removeAttachmentScaleOverride(mesh_id, av_string); } if ( pJoint && pJoint == pJointPelvis) { @@ -5872,6 +6424,9 @@ void LLVOAvatar::resetJointsOnDetach(const LLUUID& mesh_id) } postPelvisSetRecalc(); + + mActiveOverrideMeshes.erase(mesh_id); + onActiveOverrideMeshesChanged(); } //----------------------------------------------------------------------------- // getCharacterPosition() @@ -5923,7 +6478,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; @@ -5952,7 +6507,7 @@ F32 LLVOAvatar::getTimeDilation() //----------------------------------------------------------------------------- F32 LLVOAvatar::getPixelArea() const { - if (mIsDummy) + if (isUIAvatar()) { return 100000.f; } @@ -6386,7 +6941,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. @@ -6449,6 +7004,11 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o return 0; } + if (!viewer_object->isAnimatedObject()) + { + updateAttachmentOverrides(); + } + updateVisualComplexity(); if (viewer_object->isSelected()) @@ -6478,19 +7038,62 @@ 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; + 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(); } //----------------------------------------------------------------------------- @@ -6581,7 +7184,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(); @@ -6606,9 +7209,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) + { + updateAttachmentOverrides(); + } LL_DEBUGS() << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << LL_ENDL; return TRUE; } @@ -6742,7 +7349,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()) { @@ -6900,6 +7510,18 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color) updateMeshTextures(); } +// virtual +bool LLVOAvatar::shouldRenderRigged() const +{ + return true; +} + +// 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() @@ -6910,6 +7532,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) @@ -7189,9 +7816,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; @@ -8696,8 +9323,43 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara pelvis_fixup, mesh_id.asString().c_str()); } - apr_file_printf( file, "\t</archetype>\n" ); - apr_file_printf( file, "\n</linden_genepool>\n" ); + LLVector3 rp = getRootJoint()->getWorldPosition(); + LLVector4a rpv; + rpv.load3(rp.mV); + + for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) + { + LLJoint *joint = getJoint(joint_num); + if (joint_num < mJointRiggingInfoTab.size()) + { + LLJointRiggingInfo& rig_info = mJointRiggingInfoTab[joint_num]; + if (rig_info.isRiggedTo()) + { + LLMatrix4a mat; + LLVector4a new_extents[2]; + mat.loadu(joint->getWorldMatrix()); + matMulBoundBox(mat, rig_info.getRiggedExtents(), new_extents); + LLVector4a rrp[2]; + rrp[0].setSub(new_extents[0],rpv); + rrp[1].setSub(new_extents[1],rpv); + apr_file_printf( file, "\t\t<joint_rig_info num=\"%d\" name=\"%s\" min=\"%f %f %f\" max=\"%f %f %f\" tmin=\"%f %f %f\" tmax=\"%f %f %f\"/>\n", + joint_num, + joint->getName().c_str(), + rig_info.getRiggedExtents()[0][0], + rig_info.getRiggedExtents()[0][1], + rig_info.getRiggedExtents()[0][2], + rig_info.getRiggedExtents()[1][0], + rig_info.getRiggedExtents()[1][1], + rig_info.getRiggedExtents()[1][2], + rrp[0][0], + rrp[0][1], + rrp[0][2], + rrp[1][0], + rrp[1][1], + rrp[1][2] ); + } + } + } bool ultra_verbose = false; if (isSelf() && ultra_verbose) @@ -8705,6 +9367,10 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara // show the cloned params inside the wearables as well. gAgentAvatarp->dumpWearableInfo(outfile); } + + apr_file_printf( file, "\t</archetype>\n" ); + apr_file_printf( file, "\n</linden_genepool>\n" ); + LLSD args; args["PATH"] = fullpath; LLNotificationsUtil::add("AppearanceToXMLSaved", args); @@ -8836,6 +9502,7 @@ void LLVOAvatar::updateRegion(LLViewerRegion *regionp) LLViewerObject::updateRegion(regionp); } +// virtual std::string LLVOAvatar::getFullname() const { std::string name; @@ -8882,6 +9549,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; @@ -8907,11 +9579,156 @@ BOOL LLVOAvatar::updateLOD() return res; } -void LLVOAvatar::updateLODRiggedAttachments( void ) +void LLVOAvatar::updateLODRiggedAttachments() { updateLOD(); rebuildRiggedAttachments(); } + +void showRigInfoTabExtents(LLVOAvatar *avatar, LLJointRiggingInfoTab& tab, S32& count_rigged, S32& count_box) +{ + count_rigged = count_box = 0; + LLVector4a zero_vec; + zero_vec.clear(); + for (S32 i=0; i<tab.size(); i++) + { + if (tab[i].isRiggedTo()) + { + count_rigged++; + LLJoint *joint = avatar->getJoint(i); + LL_DEBUGS("RigSpam") << "joint " << i << " name " << joint->getName() << " box " + << tab[i].getRiggedExtents()[0] << ", " << tab[i].getRiggedExtents()[1] << LL_ENDL; + if ((!tab[i].getRiggedExtents()[0].equals3(zero_vec)) || + (!tab[i].getRiggedExtents()[1].equals3(zero_vec))) + { + count_box++; + } + } + } +} + +void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes) +{ + for ( LLVOAvatar::attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter ) + { + LLViewerJointAttachment* attachment = iter->second; + LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_end = attachment->mAttachedObjects.end(); + + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_iter = attachment->mAttachedObjects.begin(); + attach_iter != attach_end; ++attach_iter) + { + LLViewerObject* attached_object = *attach_iter; + LLVOVolume *volume = dynamic_cast<LLVOVolume*>(attached_object); + if (volume) + { + volumes.push_back(volume); + if (volume->isAnimatedObject()) + { + // For animated object attachment, don't need + // the children. Will just get bounding box + // from the control avatar. + continue; + } + } + LLViewerObject::const_child_list_t& children = attached_object->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); + it != children.end(); ++it) + { + LLViewerObject *childp = *it; + LLVOVolume *volume = dynamic_cast<LLVOVolume*>(childp); + if (volume) + { + volumes.push_back(volume); + } + } + } + } + + LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this); + if (control_av) + { + LLVOVolume *volp = control_av->mRootVolp; + if (volp) + { + volumes.push_back(volp); + LLViewerObject::const_child_list_t& children = volp->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); + it != children.end(); ++it) + { + LLViewerObject *childp = *it; + LLVOVolume *volume = dynamic_cast<LLVOVolume*>(childp); + if (volume) + { + volumes.push_back(volume); + } + } + } + } +} + +static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_INFO_UPDATE("Av Upd Rig Info"); +static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_KEY_UPDATE("Av Upd Rig Key"); +static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_AVOL_UPDATE("Av Upd Avol"); + +// virtual +void LLVOAvatar::updateRiggingInfo() +{ + LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_INFO_UPDATE); + + LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL; + + std::vector<LLVOVolume*> volumes; + + { + LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_AVOL_UPDATE); + getAssociatedVolumes(volumes); + } + + std::map<LLUUID,S32> curr_rigging_info_key; + { + LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_KEY_UPDATE); + // Get current rigging info key + for (std::vector<LLVOVolume*>::iterator it = volumes.begin(); it != volumes.end(); ++it) + { + LLVOVolume *vol = *it; + if (vol->isMesh() && vol->getVolume()) + { + const LLUUID& mesh_id = vol->getVolume()->getParams().getSculptID(); + S32 max_lod = llmax(vol->getLOD(), vol->mLastRiggingInfoLOD); + curr_rigging_info_key[mesh_id] = max_lod; + } + } + + // Check for key change, which indicates some change in volume composition or LOD. + if (curr_rigging_info_key == mLastRiggingInfoKey) + { + return; + } + } + + // Something changed. Update. + mLastRiggingInfoKey = curr_rigging_info_key; + mJointRiggingInfoTab.clear(); + for (std::vector<LLVOVolume*>::iterator it = volumes.begin(); it != volumes.end(); ++it) + { + LLVOVolume *vol = *it; + vol->updateRiggingInfo(); + mJointRiggingInfoTab.merge(vol->mJointRiggingInfoTab); + } + + //LL_INFOS() << "done update rig count is " << countRigInfoTab(mJointRiggingInfoTab) << LL_ENDL; + LL_DEBUGS("RigSpammish") << getFullname() << " after update rig tab:" << LL_ENDL; + S32 joint_count, box_count; + showRigInfoTabExtents(this, mJointRiggingInfoTab, joint_count, box_count); + LL_DEBUGS("RigSpammish") << "uses " << joint_count << " joints " << " nonzero boxes: " << box_count << LL_ENDL; +} + +// virtual +void LLVOAvatar::onActiveOverrideMeshesChanged() +{ + mJointRiggingInfoTab.setNeedsUpdate(true); +} + U32 LLVOAvatar::getPartitionType() const { // Avatars merely exist as drawables in the bridge partition @@ -8922,10 +9739,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() @@ -8941,6 +9758,7 @@ void LLVOAvatar::updateImpostors() LLCharacter::sAllowInstancesChange = TRUE; } +// virtual BOOL LLVOAvatar::isImpostor() { return sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE; @@ -9022,6 +9840,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 @@ -9069,10 +9898,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); @@ -9091,22 +9926,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; @@ -9114,6 +9940,135 @@ 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; + const F32 animated_object_attachment_surcharge = 1000; + + 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() { @@ -9152,7 +10107,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) @@ -9163,112 +10136,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); } } |