diff options
Diffstat (limited to 'indra/newview/llvoavatar.cpp')
-rw-r--r-- | indra/newview/llvoavatar.cpp | 951 |
1 files changed, 606 insertions, 345 deletions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 3f021d1f84..c31714de5a 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2,31 +2,25 @@ * @File llvoavatar.cpp * @brief Implementation of LLVOAvatar class which is a derivation of LLViewerObject * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -68,6 +62,7 @@ #include "llmoveview.h" #include "llnotificationsutil.h" #include "llquantize.h" +#include "llrand.h" #include "llregionhandle.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -95,6 +90,12 @@ #include "llvoiceclient.h" #include "llvoicevisualizer.h" // Ventrella +#include "lldebugmessagebox.h" +extern F32 SPEED_ADJUST_MAX; +extern F32 SPEED_ADJUST_MAX_SEC; +extern F32 ANIM_SPEED_MAX; +extern F32 ANIM_SPEED_MIN; + #if LL_MSVC // disable boost::lexical_cast warning #pragma warning (disable:4702) @@ -102,8 +103,6 @@ #include <boost/lexical_cast.hpp> -#define DISPLAY_AVATAR_LOAD_TIMES - using namespace LLVOAvatarDefines; //----------------------------------------------------------------------------- @@ -177,7 +176,7 @@ const F32 TIME_BEFORE_MESH_CLEANUP = 5.f; // seconds const S32 AVATAR_RELEASE_THRESHOLD = 10; // number of avatar instances before releasing memory const F32 FOOT_GROUND_COLLISION_TOLERANCE = 0.25f; const F32 AVATAR_LOD_TWEAK_RANGE = 0.7f; -const S32 MAX_BUBBLE_CHAT_LENGTH = 1023; +const S32 MAX_BUBBLE_CHAT_LENGTH = DB_CHAT_MSG_STR_LEN; const S32 MAX_BUBBLE_CHAT_UTTERANCES = 12; const F32 CHAT_FADE_TIME = 8.0; const F32 BUBBLE_CHAT_TIME = CHAT_FADE_TIME * 3.f; @@ -590,7 +589,7 @@ LLVOAvatarSkeletonInfo* LLVOAvatar::sAvatarSkeletonInfo = NULL; LLVOAvatar::LLVOAvatarXmlInfo* LLVOAvatar::sAvatarXmlInfo = NULL; LLVOAvatarDictionary *LLVOAvatar::sAvatarDictionary = NULL; S32 LLVOAvatar::sFreezeCounter = 0; -S32 LLVOAvatar::sMaxVisible = 50; +U32 LLVOAvatar::sMaxVisible = 12; F32 LLVOAvatar::sRenderDistance = 256.f; S32 LLVOAvatar::sNumVisibleAvatars = 0; S32 LLVOAvatar::sNumLODChangesThisFrame = 0; @@ -669,8 +668,11 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mTexEyeColor( NULL ), mNeedsSkin(FALSE), mUpdatePeriod(1), + mFullyLoaded(FALSE), + mPreviousFullyLoaded(FALSE), mFullyLoadedInitialized(FALSE), - mSupportsAlphaLayers(FALSE) + mSupportsAlphaLayers(FALSE), + mLoadedCallbacksPaused(FALSE) { LLMemType mt(LLMemType::MTYPE_AVATAR); //VTResume(); // VTune @@ -694,10 +696,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mBakedTextureDatas[i].mTextureIndex = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)i); } - mDirtyMesh = TRUE; // Dirty geometry, need to regenerate. + mDirtyMesh = 2; // Dirty geometry, need to regenerate. mMeshTexturesDirty = FALSE; - mShadow0Facep = NULL; - mShadow1Facep = NULL; mHeadp = NULL; mIsBuilt = FALSE; @@ -733,12 +733,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mRippleTimeLast = 0.f; - mShadowImagep = LLViewerTextureManager::getFetchedTextureFromFile("foot_shadow.j2c"); - - // GL NOT ACTIVE HERE - //gGL.getTexUnit(0)->bind(mShadowImagep.get()); - //mShadowImagep->setAddressMode(LLTexUnit::TAM_CLAMP); - mInAir = FALSE; mStepOnLand = TRUE; @@ -748,8 +742,11 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mOohMorph = NULL; mAahMorph = NULL; - mCurrentGesticulationLevel = 0; + mCurrentGesticulationLevel = 0; + mRuthTimer.reset(); + mRuthDebugTimer.reset(); + mDebugExistenceTimer.reset(); } //------------------------------------------------------------------------ @@ -757,6 +754,27 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, //------------------------------------------------------------------------ LLVOAvatar::~LLVOAvatar() { + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (!mFullyLoaded) + { + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args); + } + else + { + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezLeftNotification",args); + } + + } lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; mRoot.removeAllChildren(); @@ -803,6 +821,7 @@ LLVOAvatar::~LLVOAvatar() mDead = TRUE; mAnimationSources.clear(); + LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ; lldebugs << "LLVOAvatar Destructor end" << llendl; } @@ -816,6 +835,7 @@ void LLVOAvatar::markDead() sNumVisibleChatBubbles--; } mVoiceVisualizer->markDead(); + LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ; LLViewerObject::markDead(); } @@ -828,7 +848,7 @@ BOOL LLVOAvatar::isFullyBaked() for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { if (!isTextureDefined(mBakedTextureDatas[i].mTextureIndex) - && ( (i != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT) ) ) + && ( (i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ) ) { return FALSE; } @@ -1114,6 +1134,17 @@ void LLVOAvatar::initClass() { llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; } + + gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise"); + gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot"); + gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING,"editing"); + gAnimLibrary.animStateSetString(ANIM_AGENT_EYE,"eye"); + gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST,"fly_adjust"); + gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION,"hand_motion"); + gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT,"head_rot"); + gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix"); + gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target"); + gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust"); } @@ -1225,7 +1256,11 @@ void LLVOAvatar::initInstance(void) registerMotion( ANIM_AGENT_EXPRESS_TOOTHSMILE, LLEmote::create ); registerMotion( ANIM_AGENT_EXPRESS_WINK, LLEmote::create ); registerMotion( ANIM_AGENT_EXPRESS_WORRY, LLEmote::create ); + registerMotion( ANIM_AGENT_FEMALE_RUN_NEW, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_FEMALE_WALK_NEW, LLKeyframeWalkMotion::create ); registerMotion( ANIM_AGENT_RUN, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_RUN_NEW, LLKeyframeWalkMotion::create ); registerMotion( ANIM_AGENT_STAND, LLKeyframeStandMotion::create ); registerMotion( ANIM_AGENT_STAND_1, LLKeyframeStandMotion::create ); registerMotion( ANIM_AGENT_STAND_2, LLKeyframeStandMotion::create ); @@ -1235,6 +1270,7 @@ void LLVOAvatar::initInstance(void) registerMotion( ANIM_AGENT_TURNLEFT, LLKeyframeWalkMotion::create ); registerMotion( ANIM_AGENT_TURNRIGHT, LLKeyframeWalkMotion::create ); registerMotion( ANIM_AGENT_WALK, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_WALK_NEW, LLKeyframeWalkMotion::create ); // motions without a start/stop bit registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); @@ -1270,7 +1306,8 @@ void LLVOAvatar::initInstance(void) //VTPause(); // VTune - mVoiceVisualizer->setVoiceEnabled( gVoiceClient->getVoiceEnabled( mID ) ); + mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) ); + } const LLVector3 LLVOAvatar::getRenderPosition() const @@ -1924,7 +1961,7 @@ void LLVOAvatar::updateMeshData() } if(num_vertices < 1)//skip empty meshes { - break ; + continue ; } if(last_v_num > 0)//put the last inserted part into next vertex buffer. { @@ -1946,6 +1983,8 @@ void LLVOAvatar::updateMeshData() // resize immediately facep->setSize(num_vertices, num_indices); + bool terse_update = false; + if(facep->mVertexBuffer.isNull()) { facep->mVertexBuffer = new LLVertexBufferAvatar(); @@ -1953,8 +1992,16 @@ void LLVOAvatar::updateMeshData() } else { + if (facep->mVertexBuffer->getRequestedIndices() == num_indices && + facep->mVertexBuffer->getRequestedVerts() == num_vertices) + { + terse_update = true; + } + else + { facep->mVertexBuffer->resizeBuffer(num_vertices, num_indices) ; } + } facep->setGeomIndex(0); facep->setIndicesIndex(0); @@ -1968,7 +2015,7 @@ void LLVOAvatar::updateMeshData() for(S32 k = j ; k < part_index ; k++) { - mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR); + mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR, terse_update); } stop_glerror(); @@ -2028,7 +2075,8 @@ void LLVOAvatar::computeBodySize() ankle.mV[VZ] * knee_scale.mV[VZ] - foot.mV[VZ] * ankle_scale.mV[VZ]; - mBodySize.mV[VZ] = mPelvisToFoot + + LLVector3 new_body_size; + new_body_size.mV[VZ] = mPelvisToFoot + // the sqrt(2) correction below is an approximate // correction to get to the top of the head F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + @@ -2038,8 +2086,19 @@ void LLVOAvatar::computeBodySize() torso.mV[VZ] * pelvis_scale.mV[VZ]; // TODO -- measure the real depth and width - mBodySize.mV[VX] = DEFAULT_AGENT_DEPTH; - mBodySize.mV[VY] = DEFAULT_AGENT_WIDTH; + new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; + new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; + + if (new_body_size != mBodySize) + { + mBodySize = new_body_size; + + if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF()) + { // notify simulator of change in size + // but not if we are in the middle of updating appearance + gAgent.sendAgentSetAppearance(); + } + } /* debug spam std::cout << "skull = " << skull << std::endl; // adebug @@ -2078,9 +2137,24 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, LLMemType mt(LLMemType::MTYPE_AVATAR); LLVector3 old_vel = getVelocity(); + const BOOL has_name = !getNVPair("FirstName"); + // Do base class updates... U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); + // Print out arrival information once we have name of avatar. + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (has_name && getNVPair("FirstName")) + { + mDebugExistenceTimer.reset(); + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezArrivedNotification",args); + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl; + } + } if(retval & LLViewerObject::INVALID_UPDATE) { if (isSelf()) @@ -2116,6 +2190,33 @@ static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar"); static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints"); //------------------------------------------------------------------------ +// LLVOAvatar::dumpAnimationState() +//------------------------------------------------------------------------ +void LLVOAvatar::dumpAnimationState() +{ + llinfos << "==============================================" << llendl; + for (LLVOAvatar::AnimIterator it = mSignaledAnimations.begin(); it != mSignaledAnimations.end(); ++it) + { + LLUUID id = it->first; + std::string playtag = ""; + if (mPlayingAnimations.find(id) != mPlayingAnimations.end()) + { + playtag = "*"; + } + llinfos << gAnimLibrary.animationName(id) << playtag << llendl; + } + for (LLVOAvatar::AnimIterator it = mPlayingAnimations.begin(); it != mPlayingAnimations.end(); ++it) + { + LLUUID id = it->first; + bool is_signaled = mSignaledAnimations.find(id) != mSignaledAnimations.end(); + if (!is_signaled) + { + llinfos << gAnimLibrary.animationName(id) << "!S" << llendl; + } + } +} + +//------------------------------------------------------------------------ // idleUpdate() //------------------------------------------------------------------------ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) @@ -2127,12 +2228,14 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { llinfos << "Warning! Idle on dead avatar" << llendl; return TRUE; - } + } if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) { return TRUE; } + + checkTextureLoading() ; // force immediate pixel area update on avatars using last frames data (before drawable or camera updates) setPixelAreaAndAngle(gAgent); @@ -2201,8 +2304,8 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) } static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false); - bool voice_enabled = (visualizers_in_calls || gVoiceClient->inProximalChannel()) && - gVoiceClient->getVoiceEnabled(mID); + bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) && + LLVoiceClient::getInstance()->getVoiceEnabled(mID); idleUpdateVoiceVisualizer( voice_enabled ); idleUpdateMisc( detailed_update ); @@ -2217,7 +2320,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) idleUpdateNameTag( root_pos_last ); idleUpdateRenderCost(); - idleUpdateTractorBeam(); + return TRUE; } @@ -2265,7 +2368,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) // Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been // "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking. //----------------------------------------------------------------------------------------------------------------- - if (gVoiceClient->getIsSpeaking( mID )) + if (LLVoiceClient::getInstance()->getIsSpeaking( mID )) { if (!mVoiceVisualizer->getCurrentlySpeaking()) { @@ -2274,7 +2377,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) //printf( "gAwayTimer.reset();\n" ); } - mVoiceVisualizer->setSpeakingAmplitude( gVoiceClient->getCurrentPower( mID ) ); + mVoiceVisualizer->setSpeakingAmplitude( LLVoiceClient::getInstance()->getCurrentPower( mID ) ); if( isSelf() ) { @@ -2321,12 +2424,6 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) LLJoint::sNumUpdates = 0; LLJoint::sNumTouches = 0; - // *NOTE: this is necessary for the floating name text above your head. - if (mDrawable.notNull()) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_SHADOW, TRUE); - } - BOOL visible = isVisible() || mNeedsAnimUpdate; // update attachments positions @@ -2437,7 +2534,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation() param; param = getNextVisualParam()) { - if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) + if (param->isTweakable()) { param->stopAnimating(FALSE); } @@ -2460,7 +2557,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation() param; param = getNextVisualParam()) { - if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) + if (param->isTweakable()) { param->animate(morph_amt, FALSE); } @@ -2503,7 +2600,7 @@ F32 LLVOAvatar::calcMorphAmount() void LLVOAvatar::idleUpdateLipSync(bool voice_enabled) { // Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync - if ( voice_enabled && (gVoiceClient->lipSyncEnabled()) && gVoiceClient->getIsSpeaking( mID ) ) + if ( voice_enabled && (LLVoiceClient::getInstance()->lipSyncEnabled()) && LLVoiceClient::getInstance()->getIsSpeaking( mID ) ) { F32 ooh_morph_amount = 0.0f; F32 aah_morph_amount = 0.0f; @@ -2649,7 +2746,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) { // update chat bubble //-------------------------------------------------------------------- - // draw text label over characters head + // draw text label over character's head //-------------------------------------------------------------------- if (mChatTimer.getElapsedTimeF32() > BUBBLE_CHAT_TIME) { @@ -2774,6 +2871,29 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) const BOOL is_muted = isSelf() ? FALSE : LLMuteList::getInstance()->isMuted(getID()); const BOOL is_cloud = getIsCloud(); + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (is_appearance != mNameAppearance) + { + if (is_appearance) + { + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args); + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' entered appearance mode." << llendl; + } + else + { + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args); + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left appearance mode." << llendl; + } + } + } + if (mNameString.empty() || new_name || (!title && !mTitle.empty()) || @@ -2954,14 +3074,6 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) } } -//-------------------------------------------------------------------- -// draw tractor beam when editing objects -//-------------------------------------------------------------------- -// virtual -void LLVOAvatar::idleUpdateTractorBeam() -{ -} - void LLVOAvatar::idleUpdateBelowWater() { F32 avatar_height = (F32)(getPositionGlobal().mdV[VZ]); @@ -3006,14 +3118,16 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) if (motionp->getName().empty()) { output = llformat("%s - %d", - motionp->getID().asString().c_str(), - (U32)motionp->getPriority()); + gAgent.isGodlikeWithoutAdminMenuFakery() ? + motionp->getID().asString().c_str() : + LLUUID::null.asString().c_str(), + (U32)motionp->getPriority()); } else { output = llformat("%s - %d", - motionp->getName().c_str(), - (U32)motionp->getPriority()); + motionp->getName().c_str(), + (U32)motionp->getPriority()); } addDebugText(output); } @@ -3059,35 +3173,35 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) { // muted avatars update at 16 hz mUpdatePeriod = 16; } - else if (visible && mVisibilityRank <= LLVOAvatar::sMaxVisible * 0.25f) + else if (mVisibilityRank <= LLVOAvatar::sMaxVisible) { //first 25% of max visible avatars are not impostored mUpdatePeriod = 1; } - else if (visible && mVisibilityRank > LLVOAvatar::sMaxVisible * 0.75f) - { //back 25% of max visible avatars are slow updating impostors - mUpdatePeriod = 8; - } - else if (visible && mVisibilityRank > (U32) LLVOAvatar::sMaxVisible) + else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4) { //background avatars are REALLY slow updating impostors mUpdatePeriod = 16; } - else if (visible && mImpostorPixelArea <= impostor_area) + else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 3) + { //back 25% of max visible avatars are slow updating impostors + mUpdatePeriod = 8; + } + else if (mImpostorPixelArea <= impostor_area) { // stuff in between gets an update period based on pixel area mUpdatePeriod = llclamp((S32) sqrtf(impostor_area*4.f/mImpostorPixelArea), 2, 8); } - else if (visible && mVisibilityRank > LLVOAvatar::sMaxVisible * 0.25f) - { // force nearby impostors in ultra crowded areas - mUpdatePeriod = 2; - } else - { // not impostored - mUpdatePeriod = 1; + { + //nearby avatars, update the impostors more frequently. + mUpdatePeriod = 4; } visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE; } - if (!visible) + // 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; @@ -3437,7 +3551,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) // AUDIO_STEP_LO_SPEED, AUDIO_STEP_HI_SPEED, // AUDIO_STEP_LO_GAIN, AUDIO_STEP_HI_GAIN ); - const F32 STEP_VOLUME = 0.5f; + const F32 STEP_VOLUME = 0.1f; const LLUUID& step_sound_id = getStepSound(); LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent); @@ -3654,13 +3768,20 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) return num_indices; } - if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY)) + LLFace* face = mDrawable->getFace(0); + + bool needs_rebuild = !face || face->mVertexBuffer.isNull() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY); + + if (needs_rebuild || mDirtyMesh) { //LOD changed or new mesh created, allocate new vertex buffer if needed + if (needs_rebuild || mDirtyMesh >= 2 || mVisibilityRank <= 4) + { updateMeshData(); - mDirtyMesh = FALSE; + mDirtyMesh = 0; mNeedsSkin = TRUE; mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); } + } if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0) { @@ -3670,7 +3791,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) mMeshLOD[MESH_ID_LOWER_BODY]->updateJointGeometry(); mMeshLOD[MESH_ID_UPPER_BODY]->updateJointGeometry(); - if( isWearingWearableType( WT_SKIRT ) ) + if( isWearingWearableType( LLWearableType::WT_SKIRT ) ) { mMeshLOD[MESH_ID_SKIRT]->updateJointGeometry(); } @@ -3830,7 +3951,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) U32 LLVOAvatar::renderTransparent(BOOL first_pass) { U32 num_indices = 0; - if( isWearingWearableType( WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) ) + if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) ) { gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f); num_indices += mMeshLOD[MESH_ID_SKIRT]->render(mAdjustedPixelArea, FALSE); @@ -3907,54 +4028,6 @@ U32 LLVOAvatar::renderRigid() return num_indices; } -U32 LLVOAvatar::renderFootShadows() -{ - U32 num_indices = 0; - - if (!mIsBuilt) - { - return 0; - } - - if (isSelf() && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead())) - { - return 0; - } - - if (!mIsBuilt) - { - return 0; - } - - // Don't render foot shadows if your lower body is completely invisible. - // (non-humanoid avatars rule!) - if (!isTextureVisible(TEX_LOWER_BAKED)) - { - return 0; - } - - // Update the shadow, tractor, and text label geometry. - if (mDrawable->isState(LLDrawable::REBUILD_SHADOW) && !isImpostor()) - { - updateShadowFaces(); - mDrawable->clearState(LLDrawable::REBUILD_SHADOW); - } - - U32 foot_mask = LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_TEXCOORD0; - - LLGLDepthTest test(GL_TRUE, GL_FALSE); - //render foot shadows - LLGLEnable blend(GL_BLEND); - gGL.getTexUnit(0)->bind(mShadowImagep, TRUE); - glColor4fv(mShadow0Facep->getRenderColor().mV); - mShadow0Facep->renderIndexed(foot_mask); - glColor4fv(mShadow1Facep->getRenderColor().mV); - mShadow1Facep->renderIndexed(foot_mask); - - return num_indices; -} - U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) { if (!mImpostor.isComplete()) @@ -4009,7 +4082,12 @@ void LLVOAvatar::updateTextures() } else { - render_avatar = isVisible() && !mCulled; + if(!isVisible()) + { + return ;//do not update for invisible avatar. + } + + render_avatar = !mCulled; //visible and not culled. } std::vector<BOOL> layer_baked; @@ -4033,7 +4111,7 @@ void LLVOAvatar::updateTextures() mHasGrey = FALSE; // debug for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++) { - EWearableType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)texture_index); + LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)texture_index); U32 num_wearables = gAgentWearables.getWearableCount(wearable_type); const LLTextureEntry *te = getTE(texture_index); const F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); @@ -4051,7 +4129,7 @@ void LLVOAvatar::updateTextures() } } } - if (isIndexBakedTexture((ETextureIndex) texture_index)) + if (isIndexBakedTexture((ETextureIndex) texture_index) && render_avatar) { const S32 boost_level = getAvatarBakedBoostLevel(); imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); @@ -4067,7 +4145,7 @@ void LLVOAvatar::updateTextures() << " on host " << getRegion()->getHost() << llendl; } - addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); } } @@ -4075,11 +4153,6 @@ void LLVOAvatar::updateTextures() { setDebugText(llformat("%4.0f:%4.0f", fsqrtf(mMinPixelArea),fsqrtf(mMaxPixelArea))); } - - if( render_avatar ) - { - mShadowImagep->addTextureStats(mPixelArea); - } } @@ -4090,13 +4163,91 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture return; } - +const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames. +const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames +void LLVOAvatar::checkTextureLoading() +{ + static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds + + BOOL pause = !isVisible() ; + if(!pause) + { + mInvisibleTimer.reset() ; + } + if(mLoadedCallbacksPaused == pause) + { + return ; + } + + if(mCallbackTextureList.empty()) //when is self or no callbacks. Note: this list for self is always empty. + { + mLoadedCallbacksPaused = pause ; + return ; //nothing to check. + } + + if(pause && mInvisibleTimer.getElapsedTimeF32() < MAX_INVISIBLE_WAITING_TIME) + { + return ; //have not been invisible for enough time. + } + + for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin(); + iter != mCallbackTextureList.end(); ++iter) + { + LLViewerFetchedTexture* tex = gTextureList.findImage(*iter) ; + if(tex) + { + if(pause)//pause texture fetching. + { + tex->pauseLoadedCallbacks(&mCallbackTextureList) ; + + //set to terminate texture fetching after MAX_TEXTURE_UPDATE_INTERVAL frames. + tex->setMaxVirtualSizeResetInterval(MAX_TEXTURE_UPDATE_INTERVAL); + tex->resetMaxVirtualSizeResetCounter() ; + } + else//unpause + { + static const F32 START_AREA = 100.f ; + + tex->unpauseLoadedCallbacks(&mCallbackTextureList) ; + tex->addTextureStats(START_AREA); //jump start the fetching again + } + } + } + + if(!pause) + { + updateTextures() ; //refresh texture stats. + } + mLoadedCallbacksPaused = pause ; + return ; +} + +const F32 SELF_ADDITIONAL_PRI = 0.75f ; +const F32 ADDITIONAL_PRI = 0.5f; void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) { + //Note: + //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames, + //the texture pipeline will stop fetching this texture. + + imagep->resetTextureStats(); + imagep->setCanUseHTTP(false) ; //turn off http fetching for baked textures. + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->resetMaxVirtualSizeResetCounter() ; + mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); - mMinPixelArea = llmin(pixel_area, mMinPixelArea); + mMinPixelArea = llmin(pixel_area, mMinPixelArea); imagep->addTextureStats(pixel_area / texel_area_ratio); imagep->setBoostLevel(boost_level); + + if(boost_level != LLViewerTexture::BOOST_AVATAR_BAKED_SELF) + { + imagep->setAdditionalDecodePriority(ADDITIONAL_PRI) ; + } + else + { + imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; + } } //virtual @@ -4369,34 +4520,79 @@ void LLVOAvatar::resetAnimations() flushAllMotions(); } -//----------------------------------------------------------------------------- -// startMotion() -// id is the asset if of the animation to start -// time_offset is the offset into the animation at which to start playing -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) +// Override selectively based on avatar sex and whether we're using new +// animations. +LLUUID LLVOAvatar::remapMotionID(const LLUUID& id) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - + BOOL use_new_walk_run = gSavedSettings.getBOOL("UseNewWalkRun"); + LLUUID result = id; + // start special case female walk for female avatars if (getSex() == SEX_FEMALE) { if (id == ANIM_AGENT_WALK) { - return LLCharacter::startMotion(ANIM_AGENT_FEMALE_WALK, time_offset); + if (use_new_walk_run) + result = ANIM_AGENT_FEMALE_WALK_NEW; + else + result = ANIM_AGENT_FEMALE_WALK; + } + else if (id == ANIM_AGENT_RUN) + { + // There is no old female run animation, so only override + // in one case. + if (use_new_walk_run) + result = ANIM_AGENT_FEMALE_RUN_NEW; } else if (id == ANIM_AGENT_SIT) { - return LLCharacter::startMotion(ANIM_AGENT_SIT_FEMALE, time_offset); + result = ANIM_AGENT_SIT_FEMALE; } } + else + { + // Male avatar. + if (id == ANIM_AGENT_WALK) + { + if (use_new_walk_run) + result = ANIM_AGENT_WALK_NEW; + } + else if (id == ANIM_AGENT_RUN) + { + if (use_new_walk_run) + result = ANIM_AGENT_RUN_NEW; + } + + } + + return result; + +} + +//----------------------------------------------------------------------------- +// startMotion() +// id is the asset if of the animation to start +// time_offset is the offset into the animation at which to start playing +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl; - if (isSelf() && id == ANIM_AGENT_AWAY) + LLUUID remap_id = remapMotionID(id); + + if (remap_id != id) + { + lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl; + } + + if (isSelf() && remap_id == ANIM_AGENT_AWAY) { gAgent.setAFK(); } - return LLCharacter::startMotion(id, time_offset); + return LLCharacter::startMotion(remap_id, time_offset); } //----------------------------------------------------------------------------- @@ -4404,21 +4600,21 @@ BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) //----------------------------------------------------------------------------- BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) { - if (isSelf()) - { - gAgent.onAnimStop(id); - } + lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl; - if (id == ANIM_AGENT_WALK) + LLUUID remap_id = remapMotionID(id); + + if (remap_id != id) { - LLCharacter::stopMotion(ANIM_AGENT_FEMALE_WALK, stop_immediate); + lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl; } - else if (id == ANIM_AGENT_SIT) + + if (isSelf()) { - LLCharacter::stopMotion(ANIM_AGENT_SIT_FEMALE, stop_immediate); + gAgent.onAnimStop(remap_id); } - return LLCharacter::stopMotion(id, stop_immediate); + return LLCharacter::stopMotion(remap_id, stop_immediate); } //----------------------------------------------------------------------------- @@ -4821,7 +5017,7 @@ BOOL LLVOAvatar::loadAvatar() } // Uncomment to enable avatar_lad.xml debugging. -/* std::ofstream file; + std::ofstream file; file.open("avatar_lad.log"); for( LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam(); param; @@ -4831,7 +5027,7 @@ BOOL LLVOAvatar::loadAvatar() file << std::endl; } - file.close();*/ + file.close(); return TRUE; } @@ -5223,7 +5419,7 @@ BOOL LLVOAvatar::updateJointLODs() if (res) { sNumLODChangesThisFrame++; - dirtyMesh(); + dirtyMesh(2); return TRUE; } } @@ -5247,18 +5443,9 @@ LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline) mDrawable->addFace(poolp, NULL); mDrawable->setRenderType(LLPipeline::RENDER_TYPE_AVATAR); - LLFace *facep; - - // Add faces for the foot shadows - facep = mDrawable->addFace((LLFacePool*) NULL, mShadowImagep); - mShadow0Facep = facep; - - facep = mDrawable->addFace((LLFacePool*) NULL, mShadowImagep); - mShadow1Facep = facep; - mNumInitFaces = mDrawable->getNumFaces() ; - dirtyMesh(); + dirtyMesh(2); return mDrawable; } @@ -5298,107 +5485,6 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) } //----------------------------------------------------------------------------- -// updateShadowFaces() -//----------------------------------------------------------------------------- -void LLVOAvatar::updateShadowFaces() -{ - LLFace *face0p = mShadow0Facep; - LLFace *face1p = mShadow1Facep; - - // - // render avatar shadows - // - if (mInAir || mUpdatePeriod >= IMPOSTOR_PERIOD) - { - face0p->setSize(0, 0); - face1p->setSize(0, 0); - return; - } - - LLSprite sprite(mShadowImagep.notNull() ? mShadowImagep->getID() : LLUUID::null); - sprite.setFollow(FALSE); - const F32 cos_angle = gSky.getSunDirection().mV[2]; - F32 cos_elev = sqrt(1 - cos_angle * cos_angle); - if (cos_angle < 0) cos_elev = -cos_elev; - sprite.setSize(0.4f + cos_elev * 0.8f, 0.3f); - LLVector3 sun_vec = gSky.mVOSkyp ? gSky.mVOSkyp->getToSun() : LLVector3(0.f, 0.f, 0.f); - - if (mShadowImagep->hasGLTexture()) - { - LLVector3 normal; - LLVector3d shadow_pos; - LLVector3 shadow_pos_agent; - F32 foot_height; - - if (mFootLeftp) - { - LLVector3 joint_world_pos = mFootLeftp->getWorldPosition(); - // this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now - // but we make an explicit ray trace call in expectation of future improvements - resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos), - gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal); - shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos); - foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ]; - - // Pull sprite in direction of surface normal - shadow_pos_agent += normal * SHADOW_OFFSET_AMT; - - // Render sprite - sprite.setNormal(normal); - if (isSelf() && gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) - { - sprite.setColor(0.f, 0.f, 0.f, 0.f); - } - else - { - sprite.setColor(0.f, 0.f, 0.f, clamp_rescale(foot_height, MIN_SHADOW_HEIGHT, MAX_SHADOW_HEIGHT, 0.5f, 0.f)); - } - sprite.setPosition(shadow_pos_agent); - - LLVector3 foot_to_knee = mKneeLeftp->getWorldPosition() - joint_world_pos; - //foot_to_knee.normalize(); - foot_to_knee -= projected_vec(foot_to_knee, sun_vec); - sprite.setYaw(azimuth(sun_vec - foot_to_knee)); - - sprite.updateFace(*face0p); - } - - if (mFootRightp) - { - LLVector3 joint_world_pos = mFootRightp->getWorldPosition(); - // this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now - // but we make an explicit ray trace call in expectation of future improvements - resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos), - gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal); - shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos); - foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ]; - - // Pull sprite in direction of surface normal - shadow_pos_agent += normal * SHADOW_OFFSET_AMT; - - // Render sprite - sprite.setNormal(normal); - if (isSelf() && gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) - { - sprite.setColor(0.f, 0.f, 0.f, 0.f); - } - else - { - sprite.setColor(0.f, 0.f, 0.f, clamp_rescale(foot_height, MIN_SHADOW_HEIGHT, MAX_SHADOW_HEIGHT, 0.5f, 0.f)); - } - sprite.setPosition(shadow_pos_agent); - - LLVector3 foot_to_knee = mKneeRightp->getWorldPosition() - joint_world_pos; - //foot_to_knee.normalize(); - foot_to_knee -= projected_vec(foot_to_knee, sun_vec); - sprite.setYaw(azimuth(sun_vec - foot_to_knee)); - - sprite.updateFace(*face1p); - } - } -} - -//----------------------------------------------------------------------------- // updateSexDependentLayerSets() //----------------------------------------------------------------------------- void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake ) @@ -5413,9 +5499,12 @@ void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake ) //----------------------------------------------------------------------------- void LLVOAvatar::dirtyMesh() { - mDirtyMesh = TRUE; + dirtyMesh(1); +} +void LLVOAvatar::dirtyMesh(S32 priority) +{ + mDirtyMesh = llmax(mDirtyMesh, priority); } - //----------------------------------------------------------------------------- // hideSkirt() //----------------------------------------------------------------------------- @@ -5449,6 +5538,7 @@ BOOL LLVOAvatar::setParent(LLViewerObject* parent) void LLVOAvatar::addChild(LLViewerObject *childp) { + childp->extractAttachmentItemID(); // find the inventory item this object is associated with. LLViewerObject::addChild(childp); if (childp->mDrawable) { @@ -5473,11 +5563,20 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi { S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState()); + // This should never happen unless the server didn't process the attachment point + // correctly, but putting this check in here to be safe. + if (attachmentID & ATTACHMENT_ADD) + { + llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl; + attachmentID &= ~ATTACHMENT_ADD; + } + LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); if (!attachment) { llwarns << "Object attachment point invalid: " << attachmentID << llendl; + attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest) } return attachment; @@ -5529,6 +5628,15 @@ BOOL LLVOAvatar::canAttachMoreObjects() const } //----------------------------------------------------------------------------- +// canAttachMoreObjects() +// Returns true if we can attach <n> more objects. +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const +{ + return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS; +} + +//----------------------------------------------------------------------------- // lazyAttach() //----------------------------------------------------------------------------- void LLVOAvatar::lazyAttach() @@ -5855,20 +5963,28 @@ void LLVOAvatar::updateRuthTimer(bool loading) if (mPreviousFullyLoaded) { mRuthTimer.reset(); + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezCloudNotification",args); + } mRuthDebugTimer.reset(); } - const F32 LOADING_TIMEOUT = 120.f; - if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT) + const F32 LOADING_TIMEOUT__SECONDS = 120.f; + if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT__SECONDS) { - /* llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) " << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) " << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) " << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )." << llendl; - */ + LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); mRuthTimer.reset(); } @@ -5884,16 +6000,18 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE); -#ifdef DISPLAY_AVATAR_LOAD_TIMES - if (!mPreviousFullyLoaded && !loading && mFullyLoaded) + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) { - llinfos << "Avatar '" << getFullname() << "' resolved in " << mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; - LLSD args; - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezNotification",args); + if (!mPreviousFullyLoaded && !loading && mFullyLoaded) + { + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezNotification",args); + } } -#endif // did our loading state "change" from last call? const S32 UPDATE_RATE = 30; @@ -5947,6 +6065,13 @@ void LLVOAvatar::updateMeshTextures() const BOOL self_customizing = isSelf() && gAgentCamera.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures const BOOL other_culled = !isSelf() && mCulled; + LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ; + BOOL paused = FALSE; + if(!isSelf()) + { + src_callback_list = &mCallbackTextureList ; + paused = mLoadedCallbacksPaused ; + } std::vector<BOOL> is_layer_baked; is_layer_baked.resize(mBakedTextureDatas.size(), false); @@ -5963,10 +6088,14 @@ void LLVOAvatar::updateMeshTextures() // When an avatar is changing clothes and not in Appearance mode, // use the last-known good baked texture until it finish the first // render of the new layerset. + + const BOOL layerset_invalid = mBakedTextureDatas[i].mTexLayerSet + && ( !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized() + || !mBakedTextureDatas[i].mTexLayerSet->isLocalTextureDataAvailable() ); + use_lkg_baked_layer[i] = (!is_layer_baked[i] && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR) - && mBakedTextureDatas[i].mTexLayerSet - && !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized()); + && layerset_invalid); if (use_lkg_baked_layer[i]) { mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(TRUE); @@ -6017,10 +6146,12 @@ void LLVOAvatar::updateMeshTextures() { mBakedTextureDatas[i].mIsLoaded = FALSE; if ( (baked_img->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) ) - { - baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID )); + { + baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), + src_callback_list, paused); } - baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ) ); + baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), + src_callback_list, paused ); } } else if (mBakedTextureDatas[i].mTexLayerSet @@ -6198,7 +6329,7 @@ void LLVOAvatar::releaseComponentTextures() const LLVOAvatarDictionary::BakedEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); // skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID if (!isTextureDefined(bakedDicEntry->mTextureIndex) - && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT) )) + && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) )) { continue; } @@ -6271,6 +6402,14 @@ BOOL LLVOAvatar::teToColorParams( ETextureIndex te, U32 *param_name ) param_name[2] = 923; //"skirt_blue"; break; + case TEX_HEAD_TATTOO: + case TEX_LOWER_TATTOO: + case TEX_UPPER_TATTOO: + param_name[0] = 1071; //"tattoo_red"; + param_name[1] = 1072; //"tattoo_green"; + param_name[2] = 1073; //"tattoo_blue"; + break; + default: llassert(0); return FALSE; @@ -6311,16 +6450,13 @@ LLColor4 LLVOAvatar::getDummyColor() void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const { - /* const char* te_name[] = { - "TEX_HEAD_BODYPAINT ", - "TEX_UPPER_SHIRT ", */ llinfos << (isSelf() ? "Self: " : "Other: ") << context << llendl; for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); ++iter) { const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; - // TODO: handle multiple textures for self + // TODO: MULTI-WEARABLE: handle multiple textures for self const LLViewerTexture* te_image = getImage(iter->first,0); if( !te_image ) { @@ -6346,23 +6482,23 @@ void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const } // Unlike most wearable functions, this works for both self and other. -BOOL LLVOAvatar::isWearingWearableType(EWearableType type) const +BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const { if (mIsDummy) return TRUE; switch(type) { - case WT_SHAPE: - case WT_SKIN: - case WT_HAIR: - case WT_EYES: + case LLWearableType::WT_SHAPE: + case LLWearableType::WT_SKIN: + case LLWearableType::WT_HAIR: + case LLWearableType::WT_EYES: return TRUE; // everyone has all bodyparts default: break; // Do nothing } /* switch(type) - case WT_SHIRT: + case LLWearableType::WT_SHIRT: indicator_te = TEX_UPPER_SHIRT; */ for (LLVOAvatarDictionary::Textures::const_iterator tex_iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); tex_iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); @@ -6475,6 +6611,14 @@ void LLVOAvatar::onFirstTEMessageReceived() { mFirstTEMessageReceived = TRUE; + LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ; + BOOL paused = FALSE ; + if(!isSelf()) + { + src_callback_list = &mCallbackTextureList ; + paused = mLoadedCallbacksPaused ; + } + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { const BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); @@ -6488,9 +6632,11 @@ void LLVOAvatar::onFirstTEMessageReceived() // If we have more than one texture for the other baked layers, we'll want to call this for them too. if ( (image->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) ) { - image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID )); + image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), + src_callback_list, paused); } - image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ) ); + image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), + src_callback_list, paused ); } } @@ -6500,6 +6646,41 @@ void LLVOAvatar::onFirstTEMessageReceived() } //----------------------------------------------------------------------------- +// bool visualParamWeightsAreDefault() +//----------------------------------------------------------------------------- +bool LLVOAvatar::visualParamWeightsAreDefault() +{ + bool rtn = true; + + bool is_wearing_skirt = isWearingWearableType(LLWearableType::WT_SKIRT); + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + if (param->isTweakable()) + { + LLViewerVisualParam* vparam = dynamic_cast<LLViewerVisualParam*>(param); + llassert(vparam); + bool is_skirt_param = vparam && + LLWearableType::WT_SKIRT == vparam->getWearableType(); + if (param->getWeight() != param->getDefaultWeight() && + // we have to not care whether skirt weights are default, if we're not actually wearing a skirt + (is_wearing_skirt || !is_skirt_param)) + { + //llinfos << "param '" << param->getName() << "'=" << param->getWeight() << " which differs from default=" << param->getDefaultWeight() << llendl; + rtn = false; + break; + } + } + } + + //llinfos << "params are default ? " << int(rtn) << llendl; + + return rtn; +} + + +//----------------------------------------------------------------------------- // processAvatarAppearance() //----------------------------------------------------------------------------- void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) @@ -6567,16 +6748,17 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) { releaseComponentTextures(); } - - + // parse visual params S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam); - if( num_blocks > 1 ) + bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing + if( num_blocks > 1 && !drop_visual_params_debug) { BOOL params_changed = FALSE; BOOL interp_params = FALSE; LLVisualParam* param = getFirstVisualParam(); + llassert(param); // if this ever fires, we should do the same as when num_blocks<=1 if (!param) { llwarns << "No visual params!" << llendl; @@ -6585,15 +6767,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) { for( S32 i = 0; i < num_blocks; i++ ) { - while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) + while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT { param = getNextVisualParam(); } if( !param ) { - llwarns << "Number of params in AvatarAppearance msg does not match number of params in avatar xml file." << llendl; - return; + // more visual params supplied than expected - just process what we know about + break; } U8 value; @@ -6618,14 +6800,10 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } } - while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) + const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + if (num_blocks != expected_tweakable_count) { - param = getNextVisualParam(); - } - if( param ) - { - llwarns << "Number of params in AvatarAppearance msg does not match number of params in avatar xml file." << llendl; - return; + llinfos << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl; } if (params_changed) @@ -6642,16 +6820,39 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) updateSexDependentLayerSets( FALSE ); } } + + llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) ); } else { - llwarns << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl; + // AvatarAppearance message arrived without visual params + if (drop_visual_params_debug) + { + llinfos << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << llendl; + } + else + { + llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl; + } + + const F32 LOADING_TIMEOUT_SECONDS = 60.f; + // this isn't really a problem if we already have a non-default shape + if (visualParamWeightsAreDefault() && mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT_SECONDS) + { + // re-request appearance, hoping that it comes back with a shape next time + llinfos << "Re-requesting AvatarAppearance for object: " << getID() << llendl; + LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); + mRuthTimer.reset(); + } + else + { + llinfos << "That's okay, we already have a non-default shape for object: " << getID() << llendl; + // we don't really care. + } } setCompositeUpdatesEnabled( TRUE ); - llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) ); - // If all of the avatars are completely baked, release the global image caches to conserve memory. LLVOAvatar::cullAvatarsByPixelArea(); @@ -6879,16 +7080,16 @@ void LLVOAvatar::dumpArchetypeXML( void* ) apr_file_printf( file, "\n\t<archetype name=\"???\">\n" ); // only body parts, not clothing. - for (S32 type = WT_SHAPE; type <= WT_EYES; type++) + for (S32 type = LLWearableType::WT_SHAPE; type <= LLWearableType::WT_EYES; type++) { - const std::string& wearable_name = LLWearableDictionary::getTypeName((EWearableType)type); + const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type); apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() ); for (LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam()) { LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; if( (viewer_param->getWearableType() == type) && - (viewer_param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) ) + (viewer_param->isTweakable() ) ) { apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\"/>\n", viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getWeight()); @@ -6961,7 +7162,7 @@ void LLVOAvatar::cullAvatarsByPixelArea() std::sort(LLCharacter::sInstances.begin(), LLCharacter::sInstances.end(), CompareScreenAreaGreater()); // Update the avatars that have changed status - U32 rank = 0; + U32 rank = 2; //1 is reserved for self. for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); iter != LLCharacter::sInstances.end(); ++iter) { @@ -6985,7 +7186,7 @@ void LLVOAvatar::cullAvatarsByPixelArea() if (inst->isSelf()) { - inst->setVisibilityRank(0); + inst->setVisibilityRank(1); } else if (inst->mDrawable.notNull() && inst->mDrawable->isVisible()) { @@ -7584,18 +7785,15 @@ BOOL LLVOAvatar::updateLOD() BOOL res = updateJointLODs(); LLFace* facep = mDrawable->getFace(0); - if (facep->mVertexBuffer.isNull() || - (LLVertexBuffer::sEnableVBOs && - ((facep->mVertexBuffer->getUsage() == GL_STATIC_DRAW ? TRUE : FALSE) != - (facep->getPool()->getVertexShaderLevel() > 0 ? TRUE : FALSE)))) + if (facep->mVertexBuffer.isNull()) { - mDirtyMesh = TRUE; + dirtyMesh(2); } - if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY)) + if (mDirtyMesh >= 2 || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY)) { //LOD changed or new mesh created, allocate new vertex buffer if needed updateMeshData(); - mDirtyMesh = FALSE; + mDirtyMesh = 0; mNeedsSkin = TRUE; mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); } @@ -7675,6 +7873,8 @@ void LLVOAvatar::idleUpdateRenderCost() static const U32 ARC_BODY_PART_COST = 20; static const U32 ARC_LIMIT = 2048; + static std::set<LLUUID> all_textures; + if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME)) { return; @@ -7687,7 +7887,7 @@ void LLVOAvatar::idleUpdateRenderCost() { const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); ETextureIndex tex_index = baked_dict->mTextureIndex; - if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(WT_SKIRT))) + if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT))) { if (isTextureVisible(tex_index)) { @@ -7720,7 +7920,45 @@ void LLVOAvatar::idleUpdateRenderCost() } } } + // Diagnostic output to identify all avatar-related textures. + // Does not affect rendering cost calculation. + // Could be wrapped in a debug option if output becomes problematic. + if (isSelf()) + { + // print any attachment textures we didn't already know about. + for (std::set<LLUUID>::iterator it = textures.begin(); it != textures.end(); ++it) + { + LLUUID image_id = *it; + if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) + continue; + if (all_textures.find(image_id) == all_textures.end()) + { + // attachment texture not previously seen. + llinfos << "attachment_texture: " << image_id.asString() << llendl; + all_textures.insert(image_id); + } + } + // print any avatar textures we didn't already know about + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + ++iter) + { + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + // TODO: MULTI-WEARABLE: handle multiple textures for self + const LLViewerTexture* te_image = getImage(iter->first,0); + if (!te_image) + continue; + LLUUID image_id = te_image->getID(); + if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) + continue; + if (all_textures.find(image_id) == all_textures.end()) + { + llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl; + all_textures.insert(image_id); + } + } + } cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST; setDebugText(llformat("%d", cost)); @@ -7795,3 +8033,26 @@ BOOL LLVOAvatar::isTextureDefined(LLVOAvatarDefines::ETextureIndex te, U32 index getImage(te, index)->getID() != IMG_DEFAULT); } +//virtual +BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index) const +{ + if (isIndexLocalTexture(type)) + { + return isTextureDefined(type, index); + } + else + { + // baked textures can use TE images directly + return ((isTextureDefined(type) || isSelf()) + && (getTEImage(type)->getID() != IMG_INVISIBLE + || LLDrawPoolAlpha::sShowDebugAlpha)); + } +} + +//virtual +BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const +{ + // non-self avatars don't have wearables + return FALSE; +} + |