diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 87898d4dc..dc12493b8 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -574,7 +574,6 @@ void LLAvatarAppearance::computeBodySize() mBodySize = new_body_size; compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState); - bodySizeChanged(); } } diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 2651106ca..3fa4c3513 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -164,7 +164,6 @@ protected: static BOOL parseSkeletonFile(const std::string& filename); virtual void buildCharacter(); virtual BOOL loadAvatar(); - virtual void bodySizeChanged() = 0; BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); BOOL allocateCharacterJoints(U32 num); diff --git a/indra/llappearance/llavatarjoint.h b/indra/llappearance/llavatarjoint.h index e4da9bb9a..95d5a124b 100644 --- a/indra/llappearance/llavatarjoint.h +++ b/indra/llappearance/llavatarjoint.h @@ -52,7 +52,7 @@ public: virtual ~LLAvatarJoint(); // Gets the validity of this joint - BOOL getValid() { return mValid; } + bool getValid() const { return mValid; } // Sets the validity of this joint virtual void setValid( BOOL valid, BOOL recursive=FALSE ); diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 98dbd90fe..7f3f486ca 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -491,7 +491,7 @@ void LLTexLayerParamColor::setWeight(F32 weight, bool upload_bake) { mCurWeight = new_weight; - const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); if (info->mNumColors <= 0) { diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index fc8fe1936..062fe50d6 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -38,7 +38,6 @@ LLStringTable LLCharacter::sVisualParamNames(1024); std::vector< LLCharacter* > LLCharacter::sInstances; -BOOL LLCharacter::sAllowInstancesChange = TRUE ; //----------------------------------------------------------------------------- // LLCharacter() @@ -51,7 +50,6 @@ LLCharacter::LLCharacter() mAppearanceSerialNum( 0 ), mSkeletonSerialNum( 0 ) { - llassert_always(sAllowInstancesChange) ; sInstances.push_back(this); mMotionController.setCharacter( this ); @@ -75,8 +73,6 @@ LLCharacter::~LLCharacter() bool erased = vector_replace_with_last(sInstances,this); llassert_always(erased) ; - - llassert_always(sAllowInstancesChange) ; } diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 93cf461c9..340b96a5e 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -267,7 +267,6 @@ public: void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; } static std::vector< LLCharacter* > sInstances; - static BOOL sAllowInstancesChange ; //debug use virtual void setHoverOffset(const LLVector3& hover_offset, bool send_update=true) { mHoverOffset = hover_offset; } const LLVector3& getHoverOffset() const { return mHoverOffset; } diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 86fbba80c..9936dfd33 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -32,15 +32,6 @@ class LLUUID; -// At 45 Hz collisions seem stable and objects seem -// to settle down at a reasonable rate. -// JC 3/18/2003 - -// const F32 PHYSICS_TIMESTEP = 1.f / 45.f; -// This must be a #define due to anal retentive restrictions on const expressions -// CG 2008-06-05 -#define PHYSICS_TIMESTEP (1.f / 45.f) - const F32 COLLISION_TOLERANCE = 0.1f; const F32 HALF_COLLISION_TOLERANCE = 0.05f; @@ -252,7 +243,7 @@ const U8 SIM_ACCESS_DOWN = 254; const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; // attachment constants -const S32 MAX_AGENT_ATTACHMENTS = 38; +const U32 MAX_AGENT_ATTACHMENTS = 38; const U8 ATTACHMENT_ADD = 0x80; // god levels diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 4f8ec6756..becf99092 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -265,10 +265,10 @@ int LLFile::remove_nowarn(const std::string& filename) return rc; } -int LLFile::remove(const std::string& filename) +int LLFile::remove(const std::string& filename, int supress_error) { int rc = LLFile::remove_nowarn(filename); - return warnif("remove", filename, rc); + return warnif("remove", filename, rc, supress_error); } int LLFile::rename_nowarn(const std::string& filename, const std::string& newname) @@ -285,10 +285,10 @@ int LLFile::rename_nowarn(const std::string& filename, const std::string& newnam return rc; } -int LLFile::rename(const std::string& filename, const std::string& newname) +int LLFile::rename(const std::string& filename, const std::string& newname, int supress_error) { int rc = LLFile::rename_nowarn(filename, newname); - return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc); + return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, supress_error); } int LLFile::stat(const std::string& filename, llstat* filestatus) diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index eacbacca1..f6bcf8728 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -45,6 +45,7 @@ typedef FILE LLFILE; typedef struct _stat llstat; #else typedef struct stat llstat; +#include #endif #ifndef S_ISREG @@ -77,8 +78,8 @@ public: static int mkdir(const std::string& filename, int perms = 0700); static int rmdir(const std::string& filename); - static int remove(const std::string& filename); - static int rename(const std::string& filename,const std::string& newname); + static int remove(const std::string& filename, int supress_error = 0); + static int rename(const std::string& filename,const std::string& newname, int supress_error = 0); static int stat(const std::string& filename,llstat* file_status); static bool isdir(const std::string& filename); static bool isfile(const std::string& filename); diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 30b4266b7..7203b4d6e 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -866,6 +866,26 @@ std::string LLStringOps::getDatetimeCode(const std::string& key) } +std::string LLStringOps::getReadableNumber(F64 num) +{ + if (fabs(num)>=1e9) + { + return llformat("%.2lfB", num / 1e9); + } + else if (fabs(num)>=1e6) + { + return llformat("%.2lfM", num / 1e6); + } + else if (fabs(num)>=1e3) + { + return llformat("%.2lfK", num / 1e3); + } + else + { + return llformat("%.2lf", num); + } +} + namespace LLStringFn { // NOTE - this restricts output to ascii diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 959833dd9..35407ca4e 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -214,6 +214,9 @@ public: static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} static std::string getDatetimeCode (const std::string& key); + + // Express a value like 1234567 as "1.23M" + static std::string getReadableNumber(F64 num); }; /** diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index 41d1fdee9..48cad96da 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -18,17 +18,18 @@ set(llmath_SOURCE_FILES llcoordframe.cpp llline.cpp llmatrix3a.cpp + llmatrix4a.cpp llmodularmath.cpp llperlin.cpp llquaternion.cpp + llrigginginfo.cpp llrect.cpp - llrigginginfo.cpp - llsdutil_math.cpp llsphere.cpp llvector4a.cpp llvolume.cpp llvolumemgr.cpp llvolumeoctree.cpp + llsdutil_math.cpp m3math.cpp m4math.cpp raytrace.cpp @@ -68,8 +69,7 @@ set(llmath_HEADER_FILES llquaternion2.h llquaternion2.inl llrect.h - llrigginginfo.h - llsdutil_math.h + llrigginginfo.h llsimdmath.h llsimdtypes.h llsimdtypes.inl @@ -81,6 +81,7 @@ set(llmath_HEADER_FILES llvolume.h llvolumemgr.h llvolumeoctree.h + llsdutil_math.h m3math.h m4math.h raytrace.h diff --git a/indra/llmath/llmatrix4a.cpp b/indra/llmath/llmatrix4a.cpp new file mode 100644 index 000000000..fe8f0b98f --- /dev/null +++ b/indra/llmath/llmatrix4a.cpp @@ -0,0 +1,80 @@ +/** +* @file llmatrix4a.cpp +* @brief Functions for vectorized matrix/vector operations +* +* $LicenseInfo:firstyear=2018&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llmath.h" +#include "llmatrix4a.h" + +// Convert a bounding box into other coordinate system. Should give +// the same results as transforming every corner of the bounding box +// and extracting the bounding box of that, although that's not +// necessarily the fastest way to implement. +void matMulBoundBox(const LLMatrix4a &mat, const LLVector4a *in_extents, LLVector4a *out_extents) +{ + //get 8 corners of bounding box + LLVector4Logical mask[6]; + + for (U32 i = 0; i < 6; ++i) + { + mask[i].clear(); + } + + mask[0].setElement<2>(); //001 + mask[1].setElement<1>(); //010 + mask[2].setElement<1>(); //011 + mask[2].setElement<2>(); + mask[3].setElement<0>(); //100 + mask[4].setElement<0>(); //101 + mask[4].setElement<2>(); + mask[5].setElement<0>(); //110 + mask[5].setElement<1>(); + + LLVector4a v[8]; + + v[6] = in_extents[0]; + v[7] = in_extents[1]; + + for (U32 i = 0; i < 6; ++i) + { + v[i].setSelectWithMask(mask[i], in_extents[0], in_extents[1]); + } + + LLVector4a tv[8]; + + //transform bounding box into drawable space + for (U32 i = 0; i < 8; ++i) + { + mat.affineTransform(v[i], tv[i]); + } + + //find bounding box + out_extents[0] = out_extents[1] = tv[0]; + + for (U32 i = 1; i < 8; ++i) + { + out_extents[0].setMin(out_extents[0], tv[i]); + out_extents[1].setMax(out_extents[1], tv[i]); + } +} diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index a0906af1a..562b45e31 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -544,7 +544,7 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 { // Generate an n-sided "circular" path. // 0 is (1,0), and we go counter-clockwise along a circular path from there. - const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; + static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; F32 scale = 0.5f; F32 t, t_step, t_first, t_fraction, ang, ang_step; LLVector4a pt1,pt2; diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index 43c94a5e5..88e91e8d1 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -369,3 +369,39 @@ BOOL LLVector3::parseVector3(const std::string& buf, LLVector3* value) return FALSE; } + +// Displacement from query point to nearest neighbor point on bounding box. +// Returns zero vector for points within or on the box. +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box) +{ + LLVector3 offset; + for (S32 k=0; k<3; k++) + { + offset[k] = 0; + if (pos[k] < box[0][k]) + { + offset[k] = pos[k] - box[0][k]; + } + else if (pos[k] > box[1][k]) + { + offset[k] = pos[k] - box[1][k]; + } + } + return offset; +} + +bool box_valid_and_non_zero(const LLVector3* box) +{ + if (!box[0].isFinite() || !box[1].isFinite()) + { + return false; + } + LLVector3 zero_vec; + zero_vec.clear(); + if ((box[0] != zero_vec) || (box[1] != zero_vec)) + { + return true; + } + return false; +} + diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 9403135a5..71ca661dd 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -163,6 +163,8 @@ LLVector3 inverse_projected_vec(const LLVector3 &a, const LLVector3 &b); // Retu LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b (same as projected_vec) LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b); // Returns component of vector a not parallel to vector b (same as projected_vec) LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box); // Displacement from query point to nearest point on bounding box. +bool box_valid_and_non_zero(const LLVector3* box); inline LLVector3::LLVector3(void) { diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index 4aba5cae7..f0d82bc3b 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -63,7 +63,6 @@ void LLXfer::init (S32 chunk_size) mXferSize = 0; mStatus = e_LL_XFER_UNINITIALIZED; - mNext = NULL; mWaitingForACK = FALSE; mCallback = NULL; @@ -99,7 +98,22 @@ void LLXfer::cleanup () S32 LLXfer::startSend (U64 xfer_id, const LLHost &remote_host) { - LL_WARNS() << "undifferentiated LLXfer::startSend for " << getFileName() << LL_ENDL; + LL_WARNS("Xfer") << "unexpected call to base class LLXfer::startSend for " << getFileName() << LL_ENDL; + return (-1); +} + +/////////////////////////////////////////////////////////// + +void LLXfer::closeFileHandle() +{ + LL_WARNS("Xfer") << "unexpected call to base class LLXfer::closeFileHandle for " << getFileName() << LL_ENDL; +} + +/////////////////////////////////////////////////////////// + +S32 LLXfer::reopenFileHandle() +{ + LL_WARNS("Xfer") << "unexpected call to base class LLXfer::reopenFileHandle for " << getFileName() << LL_ENDL; return (-1); } @@ -115,7 +129,7 @@ void LLXfer::setXferSize (S32 xfer_size) S32 LLXfer::startDownload() { - LL_WARNS() << "undifferentiated LLXfer::startDownload for " << getFileName() + LL_WARNS("Xfer") << "undifferentiated LLXfer::startDownload for " << getFileName() << LL_ENDL; return (-1); } @@ -140,7 +154,7 @@ S32 LLXfer::receiveData (char *datap, S32 data_size) } else { - LL_ERRS() << "NULL data passed in receiveData" << LL_ENDL; + LL_ERRS("Xfer") << "NULL data passed in receiveData" << LL_ENDL; } } @@ -163,7 +177,7 @@ S32 LLXfer::flush() S32 LLXfer::suck(S32 start_position) { - LL_WARNS() << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << LL_ENDL; + LL_WARNS("Xfer") << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << LL_ENDL; return (-1); } @@ -196,7 +210,7 @@ void LLXfer::sendPacket(S32 packet_num) if (fdata_size < 0) { - LL_WARNS() << "negative data size in xfer send, aborting" << LL_ENDL; + LL_WARNS("Xfer") << "negative data size in xfer send, aborting" << LL_ENDL; abort(LL_ERR_EOF); return; } @@ -248,7 +262,12 @@ void LLXfer::sendPacket(S32 packet_num) gMessageSystem->nextBlockFast(_PREHASH_DataPacket); gMessageSystem->addBinaryDataFast(_PREHASH_Data, &fdata_buf,fdata_size); - gMessageSystem->sendMessage(mRemoteHost); + S32 sent_something = gMessageSystem->sendMessage(mRemoteHost); + if (sent_something == 0) + { + abort(LL_ERR_CIRCUIT_GONE); + return; + } ACKTimer.reset(); mWaitingForACK = TRUE; @@ -289,12 +308,12 @@ S32 LLXfer::processEOF() if (LL_ERR_NOERR == mCallbackResult) { - LL_INFOS() << "xfer from " << mRemoteHost << " complete: " << getFileName() + LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " complete: " << getFileName() << LL_ENDL; } else { - LL_INFOS() << "xfer from " << mRemoteHost << " failed, code " + LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " failed, code " << mCallbackResult << ": " << getFileName() << LL_ENDL; } @@ -323,15 +342,18 @@ void LLXfer::abort (S32 result_code) { mCallbackResult = result_code; - LL_INFOS() << "Aborting xfer from " << mRemoteHost << " named " << getFileName() + LL_INFOS("Xfer") << "Aborting xfer from " << mRemoteHost << " named " << getFileName() << " - error: " << result_code << LL_ENDL; + if (result_code != LL_ERR_CIRCUIT_GONE) + { gMessageSystem->newMessageFast(_PREHASH_AbortXfer); gMessageSystem->nextBlockFast(_PREHASH_XferID); gMessageSystem->addU64Fast(_PREHASH_ID, mID); gMessageSystem->addS32Fast(_PREHASH_Result, result_code); gMessageSystem->sendMessage(mRemoteHost); + } mStatus = e_LL_XFER_ABORTED; } diff --git a/indra/llmessage/llxfer.h b/indra/llmessage/llxfer.h index edf5eeb82..064278afd 100644 --- a/indra/llmessage/llxfer.h +++ b/indra/llmessage/llxfer.h @@ -54,7 +54,6 @@ class LLXfer S32 mChunkSize; public: - LLXfer *mNext; U64 mID; S32 mPacketNum; @@ -90,7 +89,9 @@ class LLXfer void init(S32 chunk_size); virtual void cleanup(); - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); + virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); + virtual void closeFileHandle(); + virtual S32 reopenFileHandle(); virtual void sendPacket(S32 packet_num); virtual void sendNextPacket(); virtual void resendLastPacket(); diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index 257a13f27..41d7dcd6c 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -98,16 +98,16 @@ void LLXfer_File::cleanup () mFp = NULL; } - LLFile::remove(mTempFilename); + LLFile::remove(mTempFilename, ENOENT); if (mDeleteLocalOnCompletion) { - LL_DEBUGS() << "Removing file: " << mLocalFilename << LL_ENDL; - LLFile::remove(mLocalFilename); + LL_DEBUGS("Xfer") << "Removing file: " << mLocalFilename << LL_ENDL; + LLFile::remove(mLocalFilename, ENOENT); } else { - LL_DEBUGS() << "Keeping local file: " << mLocalFilename << LL_ENDL; + LL_DEBUGS("Xfer") << "Keeping local file: " << mLocalFilename << LL_ENDL; } LLXfer::cleanup(); @@ -139,7 +139,7 @@ S32 LLXfer_File::initializeRequest(U64 xfer_id, mCallbackDataHandle = user_data; mCallbackResult = LL_ERR_NOERR; - LL_INFOS() << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << LL_ENDL; + LL_INFOS("Xfer") << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << LL_ENDL; if (mBuffer) { @@ -182,7 +182,7 @@ S32 LLXfer_File::startDownload() } else { - LL_WARNS() << "Couldn't create file to be received!" << LL_ENDL; + LL_WARNS("Xfer") << "Couldn't create file to be received!" << LL_ENDL; retval = -1; } @@ -223,7 +223,7 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) } else { - LL_INFOS() << "Warning: " << mLocalFilename << " not found." << LL_ENDL; + LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found." << LL_ENDL; return (LL_ERR_FILE_NOT_FOUND); } @@ -232,6 +232,36 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) return (retval); } +/////////////////////////////////////////////////////////// +void LLXfer_File::closeFileHandle() +{ + if (mFp) + { + fclose(mFp); + mFp = NULL; + } +} + +/////////////////////////////////////////////////////////// + +S32 LLXfer_File::reopenFileHandle() +{ + S32 retval = LL_ERR_NOERR; // presume success + + if (mFp == NULL) + { + mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */ + if (mFp == NULL) + { + LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found when re-opening file" << LL_ENDL; + retval = LL_ERR_FILE_NOT_FOUND; + } + } + + return retval; +} + + /////////////////////////////////////////////////////////// S32 LLXfer_File::getMaxBufferSize () @@ -279,18 +309,21 @@ S32 LLXfer_File::flush() { if (mFp) { - LL_ERRS() << "Overwriting open file pointer!" << LL_ENDL; + LL_ERRS("Xfer") << "Overwriting open file pointer!" << LL_ENDL; } mFp = LLFile::fopen(mTempFilename,"a+b"); /* Flawfinder : ignore */ if (mFp) { - if (fwrite(mBuffer,1,mBufferLength,mFp) != mBufferLength) + S32 write_size = fwrite(mBuffer,1,mBufferLength,mFp); + if (write_size != mBufferLength) { - LL_WARNS() << "Short write" << LL_ENDL; + LL_WARNS("Xfer") << "Non-matching write size, requested " << mBufferLength + << " but wrote " << write_size + << LL_ENDL; } -// LL_INFOS() << "******* wrote " << mBufferLength << " bytes of file xfer" << LL_ENDL; +// LL_INFOS("Xfer") << "******* wrote " << mBufferLength << " bytes of file xfer" << LL_ENDL; fclose(mFp); mFp = NULL; @@ -298,7 +331,7 @@ S32 LLXfer_File::flush() } else { - LL_WARNS() << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << LL_ENDL; + LL_WARNS("Xfer") << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << LL_ENDL; retval = LL_ERR_CANNOT_OPEN_FILE; } } @@ -321,7 +354,7 @@ S32 LLXfer_File::processEOF() mCallbackResult = flushval; } - LLFile::remove(mLocalFilename); + LLFile::remove(mLocalFilename, ENOENT); if (!mCallbackResult) { @@ -329,18 +362,18 @@ S32 LLXfer_File::processEOF() { #if !LL_WINDOWS S32 error_number = errno; - LL_INFOS() << "Rename failure (" << error_number << ") - " + LL_INFOS("Xfer") << "Rename failure (" << error_number << ") - " << mTempFilename << " to " << mLocalFilename << LL_ENDL; if(EXDEV == error_number) { if(copy_file(mTempFilename, mLocalFilename) == 0) { - LL_INFOS() << "Rename across mounts; copying+unlinking the file instead." << LL_ENDL; + LL_INFOS("Xfer") << "Rename across mounts; copying+unlinking the file instead." << LL_ENDL; unlink(mTempFilename.c_str()); } else { - LL_WARNS() << "Copy failure - " << mTempFilename << " to " + LL_WARNS("Xfer") << "Copy failure - " << mTempFilename << " to " << mLocalFilename << LL_ENDL; } } @@ -354,11 +387,11 @@ S32 LLXfer_File::processEOF() //LL_WARNS() << "File " << mLocalFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); - LL_WARNS() << "Rename fatally failed, can only handle EXDEV (" + LL_WARNS("Xfer") << "Rename fatally failed, can only handle EXDEV (" << EXDEV << ")" << LL_ENDL; } #else - LL_WARNS() << "Rename failure - " << mTempFilename << " to " + LL_WARNS("Xfer") << "Rename failure - " << mTempFilename << " to " << mLocalFilename << LL_ENDL; #endif } diff --git a/indra/llmessage/llxfer_file.h b/indra/llmessage/llxfer_file.h index a37dda673..ab9374549 100644 --- a/indra/llmessage/llxfer_file.h +++ b/indra/llmessage/llxfer_file.h @@ -61,8 +61,10 @@ class LLXfer_File : public LLXfer virtual S32 startDownload(); virtual S32 processEOF(); - - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); + + virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); + virtual void closeFileHandle(); + virtual S32 reopenFileHandle(); virtual S32 suck(S32 start_position); virtual S32 flush(); diff --git a/indra/llmessage/llxfer_mem.cpp b/indra/llmessage/llxfer_mem.cpp index 3bea08f2e..78a3e4f55 100644 --- a/indra/llmessage/llxfer_mem.cpp +++ b/indra/llmessage/llxfer_mem.cpp @@ -80,28 +80,6 @@ void LLXfer_Mem::setXferSize (S32 xfer_size) /////////////////////////////////////////////////////////// -U64 LLXfer_Mem::registerXfer(U64 xfer_id, const void *datap, const S32 length) -{ - mID = xfer_id; - - if (datap) - { - setXferSize(length); - if (mBuffer) - { - memcpy(mBuffer,datap,length); /* Flawfinder : ignore */ - mBufferLength = length; - } - else - { - xfer_id = 0; - } - } - - mStatus = e_LL_XFER_REGISTERED; - return (xfer_id); -} - S32 LLXfer_Mem::startSend (U64 xfer_id, const LLHost &remote_host) { S32 retval = LL_ERR_NOERR; // presume success diff --git a/indra/llmessage/llxfer_mem.h b/indra/llmessage/llxfer_mem.h index b5adf837d..d07779de8 100644 --- a/indra/llmessage/llxfer_mem.h +++ b/indra/llmessage/llxfer_mem.h @@ -53,7 +53,6 @@ class LLXfer_Mem : public LLXfer virtual void cleanup(); virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); - virtual U64 registerXfer(U64 xfer_id, const void *datap, const S32 length); virtual void setXferSize (S32 data_size); virtual S32 initializeRequest(U64 xfer_id, diff --git a/indra/llmessage/llxfer_vfile.cpp b/indra/llmessage/llxfer_vfile.cpp index 4a378d1d3..988bb7513 100644 --- a/indra/llmessage/llxfer_vfile.cpp +++ b/indra/llmessage/llxfer_vfile.cpp @@ -79,8 +79,20 @@ void LLXfer_VFile::init (LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType void LLXfer_VFile::cleanup () { - LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); - file.remove(); + if (mTempID.notNull() && + mDeleteTempFile) + { + if (mVFS->getExists(mTempID, mType)) + { + LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); + file.remove(); + } + else + { + LL_WARNS("Xfer") << "LLXfer_VFile::cleanup() can't open to delete VFS file " << mTempID << "." << LLAssetType::lookup(mType) + << ", mRemoteID is " << mRemoteID << LL_ENDL; + } + } delete mVFile; mVFile = NULL; @@ -118,7 +130,7 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, mName = llformat("VFile %s:%s", id_string.c_str(), LLAssetType::lookup(mType)); - LL_INFOS() << "Requesting " << mName << LL_ENDL; + LL_INFOS("Xfer") << "Requesting " << mName << LL_ENDL; if (mBuffer) { @@ -131,6 +143,7 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, mBufferLength = 0; mPacketNum = 0; mTempID.generate(); + mDeleteTempFile = TRUE; mStatus = e_LL_XFER_PENDING; return retval; } @@ -140,7 +153,8 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, S32 LLXfer_VFile::startDownload() { S32 retval = 0; // presume success - LLVFile file(mVFS, mTempID, mType, LLVFile::APPEND); + + // Don't need to create the file here, it will happen when data arrives gMessageSystem->newMessageFast(_PREHASH_RequestXfer); gMessageSystem->nextBlockFast(_PREHASH_XferID); @@ -184,6 +198,8 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) if (mVFile->getSize() <= 0) { + LL_WARNS("Xfer") << "LLXfer_VFile::startSend() VFS file " << mLocalID << "." << LLAssetType::lookup(mType) + << " has unexpected file size of " << mVFile->getSize() << LL_ENDL; delete mVFile; mVFile = NULL; @@ -198,6 +214,7 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) } else { + LL_WARNS("Xfer") << "LLXfer_VFile::startSend() can't read VFS file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; retval = LL_ERR_FILE_NOT_FOUND; } @@ -205,6 +222,41 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) } /////////////////////////////////////////////////////////// + +void LLXfer_VFile::closeFileHandle() +{ + if (mVFile) + { + delete mVFile; + mVFile = NULL; + } +} + +/////////////////////////////////////////////////////////// + +S32 LLXfer_VFile::reopenFileHandle() +{ + S32 retval = LL_ERR_NOERR; // presume success + + if (mVFile == NULL) + { + if (mVFS->getExists(mLocalID, mType)) + { + mVFile = new LLVFile(mVFS, mLocalID, mType, LLVFile::READ); + } + else + { + LL_WARNS("Xfer") << "LLXfer_VFile::reopenFileHandle() can't read VFS file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; + retval = LL_ERR_FILE_NOT_FOUND; + } + } + + return retval; +} + + +/////////////////////////////////////////////////////////// + void LLXfer_VFile::setXferSize (S32 xfer_size) { LLXfer::setXferSize(xfer_size); @@ -236,8 +288,8 @@ S32 LLXfer_VFile::suck(S32 start_position) // grab a buffer from the right place in the file if (! mVFile->seek(start_position, 0)) { - LL_WARNS() << "VFile Xfer Can't seek to position " << start_position << ", file length " << mVFile->getSize() << LL_ENDL; - LL_WARNS() << "While sending file " << mLocalID << LL_ENDL; + LL_WARNS("Xfer") << "VFile Xfer Can't seek to position " << start_position << ", file length " << mVFile->getSize() << LL_ENDL; + LL_WARNS("Xfer") << "While sending file " << mLocalID << LL_ENDL; return -1; } @@ -288,12 +340,31 @@ S32 LLXfer_VFile::processEOF() if (!mCallbackResult) { - LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); - if (! file.rename(mLocalID, mType)) + if (mVFS->getExists(mTempID, mType)) { - LL_INFOS() << "copy from temp file failed: unable to rename to " << mLocalID << LL_ENDL; + LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); + if (!file.rename(mLocalID, mType)) + { + LL_WARNS("Xfer") << "VFS rename of temp file failed: unable to rename " << mTempID << " to " << mLocalID << LL_ENDL; + } + else + { + #ifdef VFS_SPAM + // Debugging spam + LL_INFOS("Xfer") << "VFS rename of temp file done: renamed " << mTempID << " to " << mLocalID + << " LLVFile size is " << file.getSize() + << LL_ENDL; + #endif + + // Rename worked: the original file is gone. Clear mDeleteTempFile + // so we don't attempt to delete the file in cleanup() + mDeleteTempFile = FALSE; + } + } + else + { + LL_WARNS("Xfer") << "LLXfer_VFile::processEOF() can't open for renaming VFS file " << mTempID << "." << LLAssetType::lookup(mType) << LL_ENDL; } - } if (mVFile) diff --git a/indra/llmessage/llxfer_vfile.h b/indra/llmessage/llxfer_vfile.h index 048bf49dc..5bf9a5cfb 100644 --- a/indra/llmessage/llxfer_vfile.h +++ b/indra/llmessage/llxfer_vfile.h @@ -47,6 +47,8 @@ class LLXfer_VFile : public LLXfer std::string mName; + BOOL mDeleteTempFile; + public: LLXfer_VFile (); LLXfer_VFile (LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType type); @@ -66,8 +68,10 @@ class LLXfer_VFile : public LLXfer virtual S32 startDownload(); virtual S32 processEOF(); - - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); + + virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); + virtual void closeFileHandle(); + virtual S32 reopenFileHandle(); virtual S32 suck(S32 start_position); virtual S32 flush(); diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 0ab67b8dd..4cea886c8 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -44,9 +44,15 @@ const S32 LL_PACKET_RETRY_LIMIT = 10; // packet retransmission limit const S32 LL_DEFAULT_MAX_SIMULTANEOUS_XFERS = 10; const S32 LL_DEFAULT_MAX_REQUEST_FIFO_XFERS = 1000; -#define LL_XFER_PROGRESS_MESSAGES 0 -#define LL_XFER_TEST_REXMIT 0 +// Kills the connection if a viewer download queue hits this many requests backed up +// Also set in simulator.xml at "hard_limit_outgoing_xfers_per_circuit" +const S32 LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS = 500; +// Use this to show sending some ConfirmXferPacket messages +//#define LL_XFER_PROGRESS_MESSAGES 1 + +// Use this for lots of diagnostic spam +//#define LL_XFER_DIAGNOISTIC_LOGGING 1 /////////////////////////////////////////////////////////// @@ -66,10 +72,10 @@ LLXferManager::~LLXferManager () void LLXferManager::init (LLVFS *vfs) { - mSendList = NULL; - mReceiveList = NULL; + cleanup(); setMaxOutgoingXfersPerCircuit(LL_DEFAULT_MAX_SIMULTANEOUS_XFERS); + setHardLimitOutgoingXfersPerCircuit(LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS); setMaxIncomingXfers(LL_DEFAULT_MAX_REQUEST_FIFO_XFERS); mVFS = vfs; @@ -83,29 +89,14 @@ void LLXferManager::init (LLVFS *vfs) void LLXferManager::cleanup () { - LLXfer *xferp; - LLXfer *delp; - for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer()); mOutgoingHosts.clear(); - delp = mSendList; - while (delp) - { - xferp = delp->mNext; - delete delp; - delp = xferp; - } - mSendList = NULL; + for_each(mSendList.begin(), mSendList.end(), DeletePointer()); + mSendList.clear(); - delp = mReceiveList; - while (delp) - { - xferp = delp->mNext; - delete delp; - delp = xferp; - } - mReceiveList = NULL; + for_each(mReceiveList.begin(), mReceiveList.end(), DeletePointer()); + mReceiveList.clear(); } /////////////////////////////////////////////////////////// @@ -122,6 +113,11 @@ void LLXferManager::setMaxOutgoingXfersPerCircuit(S32 max_num) mMaxOutgoingXfersPerCircuit = max_num; } +void LLXferManager::setHardLimitOutgoingXfersPerCircuit(S32 max_num) +{ + mHardLimitOutgoingXfersPerCircuit = max_num; +} + void LLXferManager::setUseAckThrottling(const BOOL use) { mUseAckThrottling = use; @@ -140,6 +136,11 @@ void LLXferManager::setAckThrottleBPS(const F32 bps) F32 actual_rate = llmax(min_bps*1.1f, bps); LL_DEBUGS("AppInit") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL; LL_DEBUGS("AppInit") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL; + #ifdef LL_XFER_DIAGNOISTIC_LOGGING + LL_INFOS("Xfer") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL; + LL_INFOS("Xfer") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL; + #endif // LL_XFER_DIAGNOISTIC_LOGGING + mAckThrottle.setRate(actual_rate); } @@ -148,45 +149,71 @@ void LLXferManager::setAckThrottleBPS(const F32 bps) void LLXferManager::updateHostStatus() { - LLXfer *xferp; - LLHostStatus *host_statusp = NULL; - + // Clear the outgoing host list for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer()); mOutgoingHosts.clear(); - - for (xferp = mSendList; xferp; xferp = xferp->mNext) + + // Loop through all outgoing xfers and re-build mOutgoingHosts + for (xfer_list_t::iterator send_iter = mSendList.begin(); + send_iter != mSendList.end(); ++send_iter) { + LLHostStatus *host_statusp = NULL; for (status_list_t::iterator iter = mOutgoingHosts.begin(); iter != mOutgoingHosts.end(); ++iter) { - host_statusp = *iter; - if (host_statusp->mHost == xferp->mRemoteHost) - { + if ((*iter)->mHost == (*send_iter)->mRemoteHost) + { // Already have this host + host_statusp = *iter; break; } } if (!host_statusp) - { + { // Don't have this host, so add it host_statusp = new LLHostStatus(); if (host_statusp) { - host_statusp->mHost = xferp->mRemoteHost; + host_statusp->mHost = (*send_iter)->mRemoteHost; mOutgoingHosts.push_front(host_statusp); } } if (host_statusp) - { - if (xferp->mStatus == e_LL_XFER_PENDING) + { // Do the accounting + if ((*send_iter)->mStatus == e_LL_XFER_PENDING) { host_statusp->mNumPending++; } - else if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) + else if ((*send_iter)->mStatus == e_LL_XFER_IN_PROGRESS) { host_statusp->mNumActive++; } } - } + +#ifdef LL_XFER_DIAGNOISTIC_LOGGING + for (xfer_list_t::iterator send_iter = mSendList.begin(); + send_iter != mSendList.end(); ++send_iter) + { + LLXfer * xferp = *send_iter; + LL_INFOS("Xfer") << "xfer to host " << xferp->mRemoteHost + << " is " << xferp->mXferSize << " bytes" + << ", status " << (S32)(xferp->mStatus) + << ", waiting for ACK: " << (S32)(xferp->mWaitingForACK) + << " in frame " << (S32) LLFrameTimer::getFrameCount() + << LL_ENDL; + } + + for (status_list_t::iterator iter = mOutgoingHosts.begin(); + iter != mOutgoingHosts.end(); ++iter) + { + LL_INFOS("Xfer") << "LLXfer host " << (*iter)->mHost.getIPandPort() + << " has " << (*iter)->mNumActive + << " active, " << (*iter)->mNumPending + << " pending" + << " in frame " << (S32) LLFrameTimer::getFrameCount() + << LL_ENDL; + } +#endif // LL_XFER_DIAGNOISTIC_LOGGING + } /////////////////////////////////////////////////////////// @@ -196,27 +223,28 @@ void LLXferManager::printHostStatus() LLHostStatus *host_statusp = NULL; if (!mOutgoingHosts.empty()) { - LL_INFOS() << "Outgoing Xfers:" << LL_ENDL; + LL_INFOS("Xfer") << "Outgoing Xfers:" << LL_ENDL; for (status_list_t::iterator iter = mOutgoingHosts.begin(); iter != mOutgoingHosts.end(); ++iter) { host_statusp = *iter; - LL_INFOS() << " " << host_statusp->mHost << " active: " << host_statusp->mNumActive << " pending: " << host_statusp->mNumPending << LL_ENDL; + LL_INFOS("Xfer") << " " << host_statusp->mHost << " active: " << host_statusp->mNumActive << " pending: " << host_statusp->mNumPending << LL_ENDL; } } } /////////////////////////////////////////////////////////// -LLXfer *LLXferManager::findXfer (U64 id, LLXfer *list_head) +LLXfer * LLXferManager::findXferByID(U64 id, xfer_list_t & xfer_list) { - LLXfer *xferp; - for (xferp = list_head; xferp; xferp = xferp->mNext) + for (xfer_list_t::iterator iter = xfer_list.begin(); + iter != xfer_list.end(); + ++iter) { - if (xferp->mID == id) + if ((*iter)->mID == id) { - return(xferp); + return(*iter); } } return(NULL); @@ -225,29 +253,34 @@ LLXfer *LLXferManager::findXfer (U64 id, LLXfer *list_head) /////////////////////////////////////////////////////////// -void LLXferManager::removeXfer (LLXfer *delp, LLXfer **list_head) +// WARNING: this invalidates iterators from xfer_list +void LLXferManager::removeXfer(LLXfer *delp, xfer_list_t & xfer_list) { - // This function assumes that delp will only occur in the list - // zero or one times. if (delp) - { - if (*list_head == delp) + { + std::string direction = "send"; + if (&xfer_list == &mReceiveList) { - *list_head = delp->mNext; - delete (delp); + direction = "receive"; } - else + + // This assumes that delp will occur in the list once at most + // Find the pointer in the list + for (xfer_list_t::iterator iter = xfer_list.begin(); + iter != xfer_list.end(); + ++iter) { - LLXfer *xferp = *list_head; - while (xferp->mNext) + if ((*iter) == delp) { - if (xferp->mNext == delp) - { - xferp->mNext = delp->mNext; - delete (delp); - break; - } - xferp = xferp->mNext; + LL_DEBUGS("Xfer") << "Deleting xfer to host " << (*iter)->mRemoteHost + << " of " << (*iter)->mXferSize << " bytes" + << ", status " << (S32)((*iter)->mStatus) + << " from the " << direction << " list" + << LL_ENDL; + + xfer_list.erase(iter); + delete (delp); + break; } } } @@ -255,24 +288,7 @@ void LLXferManager::removeXfer (LLXfer *delp, LLXfer **list_head) /////////////////////////////////////////////////////////// -U32 LLXferManager::numActiveListEntries(LLXfer *list_head) -{ - U32 num_entries = 0; - - while (list_head) - { - if (list_head->mStatus == e_LL_XFER_IN_PROGRESS) - { - num_entries++; - } - list_head = list_head->mNext; - } - return(num_entries); -} - -/////////////////////////////////////////////////////////// - -S32 LLXferManager::numPendingXfers(const LLHost &host) +LLHostStatus * LLXferManager::findHostStatus(const LLHost &host) { LLHostStatus *host_statusp = NULL; @@ -282,26 +298,32 @@ S32 LLXferManager::numPendingXfers(const LLHost &host) host_statusp = *iter; if (host_statusp->mHost == host) { - return (host_statusp->mNumPending); + return (host_statusp); } } return 0; } +/////////////////////////////////////////////////////////// + +S32 LLXferManager::numPendingXfers(const LLHost &host) +{ + LLHostStatus *host_statusp = findHostStatus(host); + if (host_statusp) + { + return host_statusp->mNumPending; + } + return 0; +} + /////////////////////////////////////////////////////////// S32 LLXferManager::numActiveXfers(const LLHost &host) { - LLHostStatus *host_statusp = NULL; - - for (status_list_t::iterator iter = mOutgoingHosts.begin(); - iter != mOutgoingHosts.end(); ++iter) + LLHostStatus *host_statusp = findHostStatus(host); + if (host_statusp) { - host_statusp = *iter; - if (host_statusp->mHost == host) - { - return (host_statusp->mNumActive); - } + return host_statusp->mNumActive; } return 0; } @@ -372,36 +394,7 @@ BOOL LLXferManager::isLastPacket(S32 packet_num) /////////////////////////////////////////////////////////// -U64 LLXferManager::registerXfer(const void *datap, const S32 length) -{ - LLXfer *xferp; - U64 xfer_id = getNextID(); - - xferp = (LLXfer *) new LLXfer_Mem(); - if (xferp) - { - xferp->mNext = mSendList; - mSendList = xferp; - - xfer_id = ((LLXfer_Mem *)xferp)->registerXfer(xfer_id, datap,length); - - if (!xfer_id) - { - removeXfer(xferp,&mSendList); - } - } - else - { - LL_ERRS() << "Xfer allocation error" << LL_ENDL; - xfer_id = 0; - } - - return(xfer_id); -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::requestFile(const std::string& local_filename, +U64 LLXferManager::requestFile(const std::string& local_filename, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, @@ -411,28 +404,34 @@ void LLXferManager::requestFile(const std::string& local_filename, BOOL is_priority, BOOL use_big_packets) { - LLXfer *xferp; + LLXfer_File* file_xfer_p = NULL; - for (xferp = mReceiveList; xferp ; xferp = xferp->mNext) + // First check to see if it's already requested + for (xfer_list_t::iterator iter = mReceiveList.begin(); + iter != mReceiveList.end(); ++iter) { - if (xferp->getXferTypeTag() == LLXfer::XFER_FILE - && (((LLXfer_File*)xferp)->matchesLocalFilename(local_filename)) - && (((LLXfer_File*)xferp)->matchesRemoteFilename(remote_filename, remote_path)) - && (remote_host == xferp->mRemoteHost) - && (callback == xferp->mCallback) - && (user_data == xferp->mCallbackDataHandle)) - + if ((*iter)->getXferTypeTag() == LLXfer::XFER_FILE) { - // cout << "requested a xfer already in progress" << endl; - return; + file_xfer_p = (LLXfer_File*)(*iter); + if (file_xfer_p->matchesLocalFilename(local_filename) + && file_xfer_p->matchesRemoteFilename(remote_filename, remote_path) + && (remote_host == file_xfer_p->mRemoteHost) + && (callback == file_xfer_p->mCallback) + && (user_data == file_xfer_p->mCallbackDataHandle)) + { + // Already have the request (already in progress) + return (*iter)->mID; + } } } + U64 xfer_id = 0; + S32 chunk_size = use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1; - xferp = (LLXfer *) new LLXfer_File(chunk_size); - if (xferp) + file_xfer_p = new LLXfer_File(chunk_size); + if (file_xfer_p) { - addToList(xferp, mReceiveList, is_priority); + addToList(file_xfer_p, mReceiveList, is_priority); // Remove any file by the same name that happens to be lying // around. @@ -441,10 +440,11 @@ void LLXferManager::requestFile(const std::string& local_filename, if(delete_remote_on_completion && (remote_filename.substr(remote_filename.length()-4) == ".tmp")) { - LLFile::remove(local_filename); + LLFile::remove(local_filename, ENOENT); } - ((LLXfer_File *)xferp)->initializeRequest( - getNextID(), + xfer_id = getNextID(); + file_xfer_p->initializeRequest( + xfer_id, local_filename, remote_filename, remote_path, @@ -455,36 +455,9 @@ void LLXferManager::requestFile(const std::string& local_filename, } else { - LL_ERRS() << "Xfer allocation error" << LL_ENDL; - } -} - -void LLXferManager::requestFile(const std::string& remote_filename, - ELLPath remote_path, - const LLHost& remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void*,S32,void**,S32,LLExtStat), - void** user_data, - BOOL is_priority) -{ - LLXfer *xferp; - - xferp = (LLXfer *) new LLXfer_Mem(); - if (xferp) - { - addToList(xferp, mReceiveList, is_priority); - ((LLXfer_Mem *)xferp)->initializeRequest(getNextID(), - remote_filename, - remote_path, - remote_host, - delete_remote_on_completion, - callback, user_data); - startPendingDownloads(); - } - else - { - LL_ERRS() << "Xfer allocation error" << LL_ENDL; + LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL; } + return xfer_id; } void LLXferManager::requestVFile(const LLUUID& local_id, @@ -495,28 +468,46 @@ void LLXferManager::requestVFile(const LLUUID& local_id, void** user_data, BOOL is_priority) { - LLXfer *xferp; - - for (xferp = mReceiveList; xferp ; xferp = xferp->mNext) - { - if (xferp->getXferTypeTag() == LLXfer::XFER_VFILE - && (((LLXfer_VFile*)xferp)->matchesLocalFile(local_id, type)) - && (((LLXfer_VFile*)xferp)->matchesRemoteFile(remote_id, type)) - && (remote_host == xferp->mRemoteHost) - && (callback == xferp->mCallback) - && (user_data == xferp->mCallbackDataHandle)) + LLXfer_VFile * xfer_p = NULL; + for (xfer_list_t::iterator iter = mReceiveList.begin(); + iter != mReceiveList.end(); ++iter) + { // Find any matching existing requests + if ((*iter)->getXferTypeTag() == LLXfer::XFER_VFILE) { - // cout << "requested a xfer already in progress" << endl; - return; + xfer_p = (LLXfer_VFile*) (*iter); + if (xfer_p->matchesLocalFile(local_id, type) + && xfer_p->matchesRemoteFile(remote_id, type) + && (remote_host == xfer_p->mRemoteHost) + && (callback == xfer_p->mCallback) + && (user_data == xfer_p->mCallbackDataHandle)) + + { // Have match, don't add a duplicate + #ifdef LL_XFER_DIAGNOISTIC_LOGGING + LL_INFOS("Xfer") << "Dropping duplicate xfer request for " << remote_id + << " on " << remote_host.getIPandPort() + << " local id " << local_id + << LL_ENDL; + #endif // LL_XFER_DIAGNOISTIC_LOGGING + + return; + } } } - xferp = (LLXfer *) new LLXfer_VFile(); - if (xferp) + xfer_p = new LLXfer_VFile(); + if (xfer_p) { - addToList(xferp, mReceiveList, is_priority); - ((LLXfer_VFile *)xferp)->initializeRequest(getNextID(), + #ifdef LL_XFER_DIAGNOISTIC_LOGGING + LL_INFOS("Xfer") << "Starting file xfer for " << remote_id + << " type " << LLAssetType::lookupHumanReadable(type) + << " from " << xfer_p->mRemoteHost.getIPandPort() + << ", local id " << local_id + << LL_ENDL; + #endif // LL_XFER_DIAGNOISTIC_LOGGING + + addToList(xfer_p, mReceiveList, is_priority); + ((LLXfer_VFile *)xfer_p)->initializeRequest(getNextID(), vfs, local_id, remote_id, @@ -528,78 +519,18 @@ void LLXferManager::requestVFile(const LLUUID& local_id, } else { - LL_ERRS() << "Xfer allocation error" << LL_ENDL; + LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL; } } -/* -void LLXferManager::requestXfer( - const std::string& local_filename, - BOOL delete_remote_on_completion, - U64 xfer_id, - const LLHost &remote_host, - void (*callback)(void **,S32), - void **user_data) -{ - LLXfer *xferp; - - for (xferp = mReceiveList; xferp ; xferp = xferp->mNext) - { - if (xferp->getXferTypeTag() == LLXfer::XFER_FILE - && (((LLXfer_File*)xferp)->matchesLocalFilename(local_filename)) - && (xfer_id == xferp->mID) - && (remote_host == xferp->mRemoteHost) - && (callback == xferp->mCallback) - && (user_data == xferp->mCallbackDataHandle)) - - { - // cout << "requested a xfer already in progress" << endl; - return; - } - } - - xferp = (LLXfer *) new LLXfer_File(); - if (xferp) - { - xferp->mNext = mReceiveList; - mReceiveList = xferp; - - ((LLXfer_File *)xferp)->initializeRequest(xfer_id,local_filename,"",LL_PATH_NONE,remote_host,delete_remote_on_completion,callback,user_data); - startPendingDownloads(); - } - else - { - LL_ERRS() << "Xfer allcoation error" << LL_ENDL; - } -} - -void LLXferManager::requestXfer(U64 xfer_id, const LLHost &remote_host, BOOL delete_remote_on_completion, void (*callback)(void *,S32,void **,S32),void **user_data) -{ - LLXfer *xferp; - - xferp = (LLXfer *) new LLXfer_Mem(); - if (xferp) - { - xferp->mNext = mReceiveList; - mReceiveList = xferp; - - ((LLXfer_Mem *)xferp)->initializeRequest(xfer_id,"",LL_PATH_NONE,remote_host,delete_remote_on_completion,callback,user_data); - startPendingDownloads(); - } - else - { - LL_ERRS() << "Xfer allcoation error" << LL_ENDL; - } -} -*/ /////////////////////////////////////////////////////////// void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user_data*/) { // there's sometimes an extra 4 bytes added to an xfer payload const S32 BUF_SIZE = LL_XFER_LARGE_PAYLOAD + 4; - char fdata_buf[LL_XFER_LARGE_PAYLOAD + 4]; /* Flawfinder : ignore */ + char fdata_buf[BUF_SIZE]; /* Flawfinder : ignore */ S32 fdata_size; U64 id; S32 packetnum; @@ -609,14 +540,24 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetnum); fdata_size = mesgsys->getSizeFast(_PREHASH_DataPacket,_PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_DataPacket, _PREHASH_Data, fdata_buf, 0, 0, BUF_SIZE); - - xferp = findXfer(id, mReceiveList); - - if (!xferp) + if (fdata_size < 0 || + fdata_size > BUF_SIZE) { char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_WARNS() << "received xfer data from " << mesgsys->getSender() + LL_WARNS("Xfer") << "Received invalid xfer data size of " << fdata_size + << " in packet number " << packetnum + << " from " << mesgsys->getSender() + << " for xfer id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) + << LL_ENDL; + return; + } + mesgsys->getBinaryDataFast(_PREHASH_DataPacket, _PREHASH_Data, fdata_buf, fdata_size, 0, BUF_SIZE); + + xferp = findXferByID(id, mReceiveList); + if (!xferp) + { + char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ + LL_WARNS("Xfer") << "received xfer data from " << mesgsys->getSender() << " for non-existent xfer id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << LL_ENDL; return; @@ -629,11 +570,11 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user // confirm it if it was a resend of the last one, since the confirmation might have gotten dropped if (decodePacketNum(packetnum) == (xferp->mPacketNum - 1)) { - LL_INFOS() << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet " << packetnum << LL_ENDL; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender()); + LL_INFOS("Xfer") << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet " << packetnum << LL_ENDL; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender()); } else { - LL_INFOS() << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << LL_ENDL; + LL_INFOS("Xfer") << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << LL_ENDL; } return; } @@ -658,7 +599,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user if (result == LL_ERR_CANNOT_OPEN_FILE) { xferp->abort(LL_ERR_CANNOT_OPEN_FILE); - removeXfer(xferp,&mReceiveList); + removeXfer(xferp,mReceiveList); startPendingDownloads(); return; } @@ -683,7 +624,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user if (isLastPacket(packetnum)) { xferp->processEOF(); - removeXfer(xferp,&mReceiveList); + removeXfer(xferp,mReceiveList); startPendingDownloads(); } } @@ -692,7 +633,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host) { -#if LL_XFER_PROGRESS_MESSAGES +#ifdef LL_XFER_PROGRESS_MESSAGES if (!(packetnum % 50)) { cout << "confirming xfer packet #" << packetnum << endl; @@ -703,6 +644,7 @@ void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 pac mesgsys->addU64Fast(_PREHASH_ID, id); mesgsys->addU32Fast(_PREHASH_Packet, packetnum); + // Ignore a circuit failure here, we'll catch it with another message mesgsys->sendMessage(remote_host); } @@ -741,6 +683,28 @@ bool LLXferManager::validateFileForTransfer(const std::string& filename) return find_and_remove(mExpectedTransfers, filename); } +/* Present in fireengine, not used by viewer +void LLXferManager::expectVFileForRequest(const std::string& filename) +{ + mExpectedVFileRequests.insert(filename); +} + +bool LLXferManager::validateVFileForRequest(const std::string& filename) +{ + return find_and_remove(mExpectedVFileRequests, filename); +} + +void LLXferManager::expectVFileForTransfer(const std::string& filename) +{ + mExpectedVFileTransfers.insert(filename); +} + +bool LLXferManager::validateVFileForTransfer(const std::string& filename) +{ + return find_and_remove(mExpectedVFileTransfers, filename); +} +*/ + static bool remove_prefix(std::string& filename, const std::string& prefix) { if (std::equal(prefix.begin(), prefix.end(), filename.begin())) @@ -802,7 +766,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_INFOS() << "xfer request id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) + LL_INFOS("Xfer") << "xfer request id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << " to " << mesgsys->getSender() << LL_ENDL; mesgsys->getStringFast(_PREHASH_XferID, _PREHASH_Filename, local_filename); @@ -820,36 +784,45 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user LLXfer *xferp; if (uuid != LLUUID::null) - { + { // Request for an asset - use a VFS file if(NULL == LLAssetType::lookup(type)) { - LL_WARNS() << "Invalid type for xfer request: " << uuid << ":" + LL_WARNS("Xfer") << "Invalid type for xfer request: " << uuid << ":" << type_s16 << " to " << mesgsys->getSender() << LL_ENDL; return; } - LL_INFOS() << "starting vfile transfer: " << uuid << "," << LLAssetType::lookup(type) << " to " << mesgsys->getSender() << LL_ENDL; - if (! mVFS) { - LL_WARNS() << "Attempt to send VFile w/o available VFS" << LL_ENDL; + LL_WARNS("Xfer") << "Attempt to send VFile w/o available VFS" << LL_ENDL; return; } + /* Present in fireengine, not used by viewer + if (!validateVFileForTransfer(uuid.asString())) + { + // it is up to the app sending the file to mark it for expected + // transfer before the request arrives or it will be dropped + LL_WARNS("Xfer") << "SECURITY: Unapproved VFile '" << uuid << "'" << LL_ENDL; + return; + } + */ + + LL_INFOS("Xfer") << "starting vfile transfer: " << uuid << "," << LLAssetType::lookup(type) << " to " << mesgsys->getSender() << LL_ENDL; + xferp = (LLXfer *)new LLXfer_VFile(mVFS, uuid, type); if (xferp) { - xferp->mNext = mSendList; - mSendList = xferp; + mSendList.push_front(xferp); result = xferp->startSend(id,mesgsys->getSender()); } else { - LL_ERRS() << "Xfer allcoation error" << LL_ENDL; + LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL; } } else if (!local_filename.empty()) - { + { // Was given a file name to send // See DEV-21775 for detailed security issues if (local_path == LL_PATH_NONE) @@ -868,7 +841,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user case LL_PATH_NONE: if(!validateFileForTransfer(local_filename)) { - LL_WARNS() << "SECURITY: Unapproved filename '" << local_filename << LL_ENDL; + LL_WARNS("Xfer") << "SECURITY: Unapproved filename '" << local_filename << LL_ENDL; return; } break; @@ -876,13 +849,13 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user case LL_PATH_CACHE: if(!verify_cache_filename(local_filename)) { - LL_WARNS() << "SECURITY: Illegal cache filename '" << local_filename << LL_ENDL; + LL_WARNS("Xfer") << "SECURITY: Illegal cache filename '" << local_filename << LL_ENDL; return; } break; default: - LL_WARNS() << "SECURITY: Restricted file dir enum: " << (U32)local_path << LL_ENDL; + LL_WARNS("Xfer") << "SECURITY: Restricted file dir enum: " << (U32)local_path << LL_ENDL; return; } @@ -897,7 +870,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user { expanded_filename = local_filename; } - LL_INFOS() << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << LL_ENDL; + LL_INFOS("Xfer") << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << LL_ENDL; BOOL delete_local_on_completion = FALSE; mesgsys->getBOOL("XferID", "DeleteOnCompletion", delete_local_on_completion); @@ -907,23 +880,22 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user if (xferp) { - xferp->mNext = mSendList; - mSendList = xferp; + mSendList.push_front(xferp); result = xferp->startSend(id,mesgsys->getSender()); } else { - LL_ERRS() << "Xfer allcoation error" << LL_ENDL; + LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL; } } else - { + { // no uuid or filename - use the ID sent char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_INFOS() << "starting memory transfer: " + LL_INFOS("Xfer") << "starting memory transfer: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << " to " << mesgsys->getSender() << LL_ENDL; - xferp = findXfer(id, mSendList); + xferp = findXferByID(id, mSendList); if (xferp) { @@ -931,7 +903,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user } else { - LL_INFOS() << "Warning: " << U64_BUF << " not found." << LL_ENDL; + LL_INFOS("Xfer") << "Warning: xfer ID " << U64_BUF << " not found." << LL_ENDL; result = LL_ERR_FILE_NOT_FOUND; } } @@ -941,11 +913,11 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user if (xferp) { xferp->abort(result); - removeXfer(xferp,&mSendList); + removeXfer(xferp, mSendList); } else // can happen with a memory transfer not found { - LL_INFOS() << "Aborting xfer to " << mesgsys->getSender() << " with error: " << result << LL_ENDL; + LL_INFOS("Xfer") << "Aborting xfer to " << mesgsys->getSender() << " with error: " << result << LL_ENDL; mesgsys->newMessageFast(_PREHASH_AbortXfer); mesgsys->nextBlockFast(_PREHASH_XferID); @@ -955,24 +927,86 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user mesgsys->sendMessage(mesgsys->getSender()); } } - else if(xferp && (numActiveXfers(xferp->mRemoteHost) < mMaxOutgoingXfersPerCircuit)) + else if(xferp) { - xferp->sendNextPacket(); - changeNumActiveXfers(xferp->mRemoteHost,1); -// LL_INFOS() << "***STARTING XFER IMMEDIATELY***" << LL_ENDL; - } - else - { - if(xferp) + // Figure out how many transfers the host has requested + LLHostStatus *host_statusp = findHostStatus(xferp->mRemoteHost); + if (host_statusp) { - LL_INFOS() << " queueing xfer request, " << numPendingXfers(xferp->mRemoteHost) << " ahead of this one" << LL_ENDL; + if (host_statusp->mNumActive < mMaxOutgoingXfersPerCircuit) + { // Not many transfers in progress already, so start immediately + xferp->sendNextPacket(); + changeNumActiveXfers(xferp->mRemoteHost,1); + LL_DEBUGS("Xfer") << "Starting xfer ID " << U64_to_str(id) << " immediately" << LL_ENDL; + } + else if (mHardLimitOutgoingXfersPerCircuit == 0 || + (host_statusp->mNumActive + host_statusp->mNumPending) < mHardLimitOutgoingXfersPerCircuit) + { // Must close the file handle and wait for earlier ones to complete + LL_INFOS("Xfer") << " queueing xfer request id " << U64_to_str(id) << ", " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << LL_ENDL; + xferp->closeFileHandle(); // Close the file handle until we're ready to send again + } + else if (mHardLimitOutgoingXfersPerCircuit > 0) + { // Way too many requested ... it's time to stop being nice and kill the circuit + xferp->closeFileHandle(); // Close the file handle in any case + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(xferp->mRemoteHost); + if (cdp) + { + if (cdp->getTrusted()) + { // Trusted internal circuit - don't kill it + LL_WARNS("Xfer") << "Trusted circuit to " << xferp->mRemoteHost << " has too many xfer requests in the queue " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << LL_ENDL; + } + else + { // Untrusted circuit - time to stop messing around and kill it + LL_WARNS("Xfer") << "Killing circuit to " << xferp->mRemoteHost << " for having too many xfer requests in the queue " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << LL_ENDL; + gMessageSystem->disableCircuit(xferp->mRemoteHost); + } + } + else + { // WTF? Why can't we find a circuit? Try to kill it off + LL_WARNS("Xfer") << "Backlog with circuit to " << xferp->mRemoteHost << " with too many xfer requests in the queue " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << " but no LLCircuitData found???" + << LL_ENDL; + gMessageSystem->disableCircuit(xferp->mRemoteHost); + } + } } else { - LL_WARNS() << "LLXferManager::processFileRequest() - no xfer found!" - << LL_ENDL; + LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no LLHostStatus found for id " << U64_to_str(id) + << " host " << xferp->mRemoteHost << LL_ENDL; } } + else + { + LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no xfer found for id " << U64_to_str(id) << LL_ENDL; + } +} + +/////////////////////////////////////////////////////////// + +// Return true if host is in a transfer-flood sitation. Same check for both internal and external hosts +bool LLXferManager::isHostFlooded(const LLHost & host) +{ + bool flooded = false; + LLHostStatus *host_statusp = findHostStatus(host); + if (host_statusp) + { + flooded = (mHardLimitOutgoingXfersPerCircuit > 0 && + (host_statusp->mNumActive + host_statusp->mNumPending) >= (S32)(mHardLimitOutgoingXfersPerCircuit * 0.8f)); + } + + return flooded; } @@ -986,7 +1020,7 @@ void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*use mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetNum); - LLXfer* xferp = findXfer(id, mSendList); + LLXfer* xferp = findXferByID(id, mSendList); if (xferp) { // cout << "confirmed packet #" << packetNum << " ping: "<< xferp->ACKTimer.getElapsedTimeF32() << endl; @@ -997,91 +1031,105 @@ void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*use } else { - removeXfer(xferp, &mSendList); + removeXfer(xferp, mSendList); } } } /////////////////////////////////////////////////////////// -void LLXferManager::retransmitUnackedPackets () +// Called from LLMessageSystem::processAcks() +void LLXferManager::retransmitUnackedPackets() { LLXfer *xferp; - LLXfer *delp; - xferp = mReceiveList; - while(xferp) + + xfer_list_t::iterator iter = mReceiveList.begin(); + while (iter != mReceiveList.end()) { + xferp = (*iter); if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) { // if the circuit dies, abort if (! gMessageSystem->mCircuitInfo.isCircuitAlive( xferp->mRemoteHost )) { - LL_INFOS() << "Xfer found in progress on dead circuit, aborting" << LL_ENDL; + LL_WARNS("Xfer") << "Xfer found in progress on dead circuit, aborting transfer to " + << xferp->mRemoteHost.getIPandPort() + << LL_ENDL; xferp->mCallbackResult = LL_ERR_CIRCUIT_GONE; xferp->processEOF(); - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mReceiveList); + + iter = mReceiveList.erase(iter); // iter is set to next one after the deletion point + delete (xferp); continue; } } - xferp = xferp->mNext; + ++iter; } - xferp = mSendList; + // Re-build mOutgoingHosts data updateHostStatus(); + F32 et; - while (xferp) + iter = mSendList.begin(); + while (iter != mSendList.end()) { + xferp = (*iter); if (xferp->mWaitingForACK && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_PACKET_TIMEOUT)) { if (xferp->mRetries > LL_PACKET_RETRY_LIMIT) { - LL_INFOS() << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet retransmit limit exceeded, xfer dropped" << LL_ENDL; + LL_INFOS("Xfer") << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet retransmit limit exceeded, xfer dropped" << LL_ENDL; xferp->abort(LL_ERR_TCP_TIMEOUT); - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mSendList); + iter = mSendList.erase(iter); + delete xferp; + continue; } else { - LL_INFOS() << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << LL_ENDL; + LL_INFOS("Xfer") << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << LL_ENDL; xferp->resendLastPacket(); - xferp = xferp->mNext; } } else if ((xferp->mStatus == e_LL_XFER_REGISTERED) && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_XFER_REGISTRATION_TIMEOUT)) { - LL_INFOS() << "registered xfer never requested, xfer dropped" << LL_ENDL; + LL_INFOS("Xfer") << "registered xfer never requested, xfer dropped" << LL_ENDL; xferp->abort(LL_ERR_TCP_TIMEOUT); - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mSendList); + iter = mSendList.erase(iter); + delete xferp; + continue; } else if (xferp->mStatus == e_LL_XFER_ABORTED) { - LL_WARNS() << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << LL_ENDL; - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mSendList); + LL_WARNS("Xfer") << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << LL_ENDL; + iter = mSendList.erase(iter); + delete xferp; + continue; } else if (xferp->mStatus == e_LL_XFER_PENDING) { -// LL_INFOS() << "*** numActiveXfers = " << numActiveXfers(xferp->mRemoteHost) << " mMaxOutgoingXfersPerCircuit = " << mMaxOutgoingXfersPerCircuit << LL_ENDL; +// LL_INFOS("Xfer") << "*** numActiveXfers = " << numActiveXfers(xferp->mRemoteHost) << " mMaxOutgoingXfersPerCircuit = " << mMaxOutgoingXfersPerCircuit << LL_ENDL; if (numActiveXfers(xferp->mRemoteHost) < mMaxOutgoingXfersPerCircuit) { -// LL_INFOS() << "bumping pending xfer to active" << LL_ENDL; - xferp->sendNextPacket(); - changeNumActiveXfers(xferp->mRemoteHost,1); - } - xferp = xferp->mNext; + if (xferp->reopenFileHandle()) + { + LL_WARNS("Xfer") << "Error re-opening file handle for xfer ID " << U64_to_str(xferp->mID) + << " to host " << xferp->mRemoteHost << LL_ENDL; + xferp->abort(LL_ERR_CANNOT_OPEN_FILE); + iter = mSendList.erase(iter); + delete xferp; + continue; + } + else + { // No error re-opening the file, send the first packet + LL_DEBUGS("Xfer") << "Moving pending xfer ID " << U64_to_str(xferp->mID) << " to active" << LL_ENDL; + xferp->sendNextPacket(); + changeNumActiveXfers(xferp->mRemoteHost,1); + } + } } - else - { - xferp = xferp->mNext; - } - } + ++iter; + } // end while() loop // // HACK - if we're using xfer confirm throttling, throttle our xfer confirms here @@ -1094,15 +1142,38 @@ void LLXferManager::retransmitUnackedPackets () { break; } - //LL_INFOS() << "Confirm packet queue length:" << mXferAckQueue.size() << LL_ENDL; + //LL_INFOS("Xfer") << "Confirm packet queue length:" << mXferAckQueue.size() << LL_ENDL; LLXferAckInfo ack_info = mXferAckQueue.front(); mXferAckQueue.pop_front(); - //LL_INFOS() << "Sending confirm packet" << LL_ENDL; + //LL_INFOS("Xfer") << "Sending confirm packet" << LL_ENDL; sendConfirmPacket(gMessageSystem, ack_info.mID, ack_info.mPacketNum, ack_info.mRemoteHost); mAckThrottle.throttleOverflow(1000.f*8.f); // Assume 1000 bytes/packet } } +/////////////////////////////////////////////////////////// + +void LLXferManager::abortRequestById(U64 xfer_id, S32 result_code) +{ + LLXfer * xferp = findXferByID(xfer_id, mReceiveList); + if (xferp) + { + if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) + { + // causes processAbort(); + xferp->abort(result_code); + } + else + { + xferp->mCallbackResult = result_code; + xferp->processEOF(); //should notify requester + removeXfer(xferp, mReceiveList); + } + // Since already removed or marked as aborted no need + // to wait for processAbort() to start new download + startPendingDownloads(); + } +} /////////////////////////////////////////////////////////// @@ -1115,12 +1186,12 @@ void LLXferManager::processAbort (LLMessageSystem *mesgsys, void ** /*user_data* mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Result, result_code); - xferp = findXfer(id, mReceiveList); + xferp = findXferByID(id, mReceiveList); if (xferp) { xferp->mCallbackResult = result_code; xferp->processEOF(); - removeXfer(xferp, &mReceiveList); + removeXfer(xferp, mReceiveList); startPendingDownloads(); } } @@ -1136,27 +1207,29 @@ void LLXferManager::startPendingDownloads() // requests get pushed toward the back. Thus, if we didn't do a // stateful iteration, it would be possible for old requests to // never start. - LLXfer* xferp = mReceiveList; + LLXfer* xferp; std::list pending_downloads; S32 download_count = 0; S32 pending_count = 0; - while(xferp) + for (xfer_list_t::iterator iter = mReceiveList.begin(); + iter != mReceiveList.end(); + ++iter) { + xferp = (*iter); if(xferp->mStatus == e_LL_XFER_PENDING) - { + { // Count and accumulate pending downloads ++pending_count; pending_downloads.push_front(xferp); } else if(xferp->mStatus == e_LL_XFER_IN_PROGRESS) - { + { // Count downloads in progress ++download_count; } - xferp = xferp->mNext; } S32 start_count = mMaxIncomingXfers - download_count; - LL_DEBUGS() << "LLXferManager::startPendingDownloads() - XFER_IN_PROGRESS: " + LL_DEBUGS("Xfer") << "LLXferManager::startPendingDownloads() - XFER_IN_PROGRESS: " << download_count << " XFER_PENDING: " << pending_count << " startring " << llmin(start_count, pending_count) << LL_ENDL; @@ -1181,29 +1254,15 @@ void LLXferManager::startPendingDownloads() /////////////////////////////////////////////////////////// -void LLXferManager::addToList(LLXfer* xferp, LLXfer*& head, BOOL is_priority) +void LLXferManager::addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority) { if(is_priority) { - xferp->mNext = NULL; - LLXfer* next = head; - if(next) - { - while(next->mNext) - { - next = next->mNext; - } - next->mNext = xferp; - } - else - { - head = xferp; - } + xfer_list.push_back(xferp); } else { - xferp->mNext = head; - head = xferp; + xfer_list.push_front(xferp); } } diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h index b3d110e7a..45ae2ffdd 100644 --- a/indra/llmessage/llxfermanager.h +++ b/indra/llmessage/llxfermanager.h @@ -77,6 +77,7 @@ class LLXferManager protected: S32 mMaxOutgoingXfersPerCircuit; + S32 mHardLimitOutgoingXfersPerCircuit; // At this limit, kill off the connection S32 mMaxIncomingXfers; BOOL mUseAckThrottling; // Use ack throttling to cap file xfer bandwidth @@ -92,19 +93,22 @@ class LLXferManager HIGH_PRIORITY = TRUE, }; - LLXfer *mSendList; - LLXfer *mReceiveList; + // Linked FIFO list, add to the front and pull from back + typedef std::deque xfer_list_t; + xfer_list_t mSendList; + xfer_list_t mReceiveList; typedef std::list status_list_t; status_list_t mOutgoingHosts; - private: protected: // implementation methods virtual void startPendingDownloads(); - virtual void addToList(LLXfer* xferp, LLXfer*& head, BOOL is_priority); + virtual void addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority); std::multiset mExpectedTransfers; // files that are authorized to transfer out std::multiset mExpectedRequests; // files that are authorized to be downloaded on top of + std::multiset mExpectedVFileTransfers; // files that are authorized to transfer out + std::multiset mExpectedVFileRequests; // files that are authorized to be downloaded on top of public: LLXferManager(LLVFS *vfs); @@ -117,14 +121,17 @@ class LLXferManager void setAckThrottleBPS(const F32 bps); // list management routines - virtual LLXfer *findXfer(U64 id, LLXfer *list_head); - virtual void removeXfer (LLXfer *delp, LLXfer **list_head); - virtual U32 numActiveListEntries(LLXfer *list_head); + virtual LLXfer *findXferByID(U64 id, xfer_list_t & xfer_list); + virtual void removeXfer (LLXfer *delp, xfer_list_t & xfer_list); + + LLHostStatus * findHostStatus(const LLHost &host); virtual S32 numActiveXfers(const LLHost &host); virtual S32 numPendingXfers(const LLHost &host); + virtual void changeNumActiveXfers(const LLHost &host, S32 delta); virtual void setMaxOutgoingXfersPerCircuit (S32 max_num); + virtual void setHardLimitOutgoingXfersPerCircuit(S32 max_num); virtual void setMaxIncomingXfers(S32 max_num); virtual void updateHostStatus(); virtual void printHostStatus(); @@ -136,11 +143,9 @@ class LLXferManager virtual S32 decodePacketNum(S32 packet_num); virtual BOOL isLastPacket(S32 packet_num); - virtual U64 registerXfer(const void *datap, const S32 length); - // file requesting routines // .. to file - virtual void requestFile(const std::string& local_filename, + virtual U64 requestFile(const std::string& local_filename, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, @@ -148,7 +153,7 @@ class LLXferManager void (*callback)(void**,S32,LLExtStat), void** user_data, BOOL is_priority = FALSE, BOOL use_big_packets = FALSE); - + /* // .. to memory virtual void requestFile(const std::string& remote_filename, ELLPath remote_path, @@ -157,7 +162,7 @@ class LLXferManager void (*callback)(void*, S32, void**, S32, LLExtStat), void** user_data, BOOL is_priority = FALSE); - + */ // vfile requesting // .. to vfile virtual void requestVFile(const LLUUID &local_id, const LLUUID& remote_id, @@ -180,18 +185,15 @@ class LLXferManager virtual void expectFileForRequest(const std::string& filename); virtual bool validateFileForRequest(const std::string& filename); -/* -// xfer request (may be memory or file) -// .. to file - virtual void requestXfer(const char *local_filename, U64 xfer_id, - BOOL delete_remote_on_completion, - const LLHost &remote_host, void (*callback)(void **,S32),void **user_data); -// .. to memory - virtual void requestXfer(U64 xfer_id, - const LLHost &remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void *, S32, void **, S32),void **user_data); -*/ + /** + Same idea but for VFiles, kept separate to avoid namespace overlap + */ + /* Present in fireengine, not used by viewer + virtual void expectVFileForTransfer(const std::string& filename); + virtual bool validateVFileForTransfer(const std::string& filename); + virtual void expectVFileForRequest(const std::string& filename); + virtual bool validateVFileForRequest(const std::string& filename); + */ virtual void processReceiveData (LLMessageSystem *mesgsys, void **user_data); virtual void sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host); @@ -202,7 +204,10 @@ class LLXferManager virtual void retransmitUnackedPackets (); // error handling + void abortRequestById(U64 xfer_id, S32 result_code); virtual void processAbort (LLMessageSystem *mesgsys, void **user_data); + + virtual bool isHostFlooded(const LLHost & host); }; extern LLXferManager* gXferManager; diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 4d91df196..1a588ae8d 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -817,6 +817,7 @@ char const* const _PREHASH_StateSave = LLMessageStringTable::getInstance()->getS char const* const _PREHASH_RoleData = LLMessageStringTable::getInstance()->getString("RoleData"); char const* const _PREHASH_AgentAnimation = LLMessageStringTable::getInstance()->getString("AgentAnimation"); char const* const _PREHASH_AvatarAnimation = LLMessageStringTable::getInstance()->getString("AvatarAnimation"); +char const* const _PREHASH_ObjectAnimation = LLMessageStringTable::getInstance()->getString("ObjectAnimation"); char const* const _PREHASH_LogDwellTime = LLMessageStringTable::getInstance()->getString("LogDwellTime"); char const* const _PREHASH_ParcelGodMarkAsContent = LLMessageStringTable::getInstance()->getString("ParcelGodMarkAsContent"); char const* const _PREHASH_UsePhysics = LLMessageStringTable::getInstance()->getString("UsePhysics"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 50f500f78..ec1f2da86 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -817,6 +817,7 @@ extern char const* const _PREHASH_StateSave; extern char const* const _PREHASH_RoleData; extern char const* const _PREHASH_AgentAnimation; extern char const* const _PREHASH_AvatarAnimation; +extern char const* const _PREHASH_ObjectAnimation; extern char const* const _PREHASH_LogDwellTime; extern char const* const _PREHASH_ParcelGodMarkAsContent; extern char const* const _PREHASH_UsePhysics; diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 7999d2b0f..a67a95f69 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -505,7 +505,7 @@ protected: U32 mMiscFlags; // home for misc bools static LLVolumeMgr* sVolumeManager; - +public: enum { NO_LOD = -1 diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 03e540f49..122ae7772 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -49,6 +49,7 @@ public: enum EBoostLevel { BOOST_NONE = 0, + BOOST_ALM , //acts like NONE when ALM is on, max discard when ALM is off BOOST_AVATAR_BAKED , BOOST_AVATAR , BOOST_CLOUDS , diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e4f17a7e6..6f338aa4c 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -143,6 +143,7 @@ set(viewer_SOURCE_FILES llcompilequeue.cpp llconfirmationmanager.cpp llconsole.cpp + llcontrolavatar.cpp llcrashlogger.cpp llcurrencyuimanager.cpp llcylinder.cpp @@ -442,6 +443,7 @@ set(viewer_SOURCE_FILES llsavedsettingsglue.cpp llscrollingpanelparam.cpp llscrollingpanelparambase.cpp + llsculptidsize.cpp llselectmgr.cpp llshareavatarhandler.cpp llskinningutil.cpp @@ -484,6 +486,7 @@ set(viewer_SOURCE_FILES lltoolselectrect.cpp lltoolview.cpp lltracker.cpp + lluiavatar.cpp lluploaddialog.cpp lluploadfloaterobservers.cpp llurl.cpp @@ -677,6 +680,7 @@ set(viewer_HEADER_FILES llcompilequeue.h llconfirmationmanager.h llconsole.h + llcontrolavatar.h llcrashlogger.h llcurrencyuimanager.h llcylinder.h @@ -978,6 +982,7 @@ set(viewer_HEADER_FILES llsavedsettingsglue.h llscrollingpanelparam.h llscrollingpanelparambase.h + llsculptidsize.h llselectmgr.h llsimplestat.h llskinningutil.h @@ -1023,6 +1028,7 @@ set(viewer_HEADER_FILES lltracker.h lltranslate.h lluiconstants.h + lluiavatar.h lluploaddialog.h lluploadfloaterobservers.h llurl.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index edcacdfdf..ad8787a7e 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5355,6 +5355,72 @@ This should be as low as possible, but too low may break functionality Value + AnimatedObjectsIgnoreLimits + + Comment + Ignore server-enforced limits on animated objects. This is only useful for server testing. + Persist + 1 + Type + Boolean + Value + 0 + + AnimatedObjectsAllowLeftClick + + Comment + Allow left-click interaction with animated objects. Uncertain how much performance impact this will have. + Persist + 1 + Type + Boolean + Value + 0 + + AnimatedObjectsGlobalScale + + Comment + Temporary testing: allow an extra scale factor to be forced on animated objects. + Persist + 1 + Type + F32 + Value + 1.00 + + AnimatedObjectsMaxLegalOffset + + Comment + Max visual offset between object position and rendered position + Persist + 1 + Type + F32 + Value + 3.0 + + AnimatedObjectsMaxLegalSize + + Comment + Max bounding box size for animated object's rendered position + Persist + 1 + Type + F32 + Value + 64.0 + + AvatarBoundingBoxComplexity + + Comment + How many aspects to consider for avatar bounding box + Persist + 1 + Type + S32 + Value + 3 + DebugAvatarAppearanceMessage Comment @@ -12614,6 +12680,17 @@ This should be as low as possible, but too low may break functionality Value 1 + AlwaysRenderFriends + + Comment + Always render friends regardless of max complexity + Persist + 1 + Type + Boolean + Value + 0 + RenderAvatarCloth Comment @@ -12929,7 +13006,7 @@ This should be as low as possible, but too low may break functionality RenderSSAOEffect Comment - Multiplier for (1) value for areas which are totally occluded. Blends with original color for partly-occluded areas. (Third component is unused.) + Multiplier for (1) value and (2) saturation (HSV definition), for areas which are totally occluded. Blends with original color for partly-occluded areas. (Third component is unused.) Persist 1 Type @@ -13417,13 +13494,13 @@ This should be as low as possible, but too low may break functionality Type F32 Value - 384 + 368.0 RenderDeferred Comment - Use deferred rendering pipeline. + Use deferred rendering pipeline (Advanced Lighting Model). Persist 1 Type @@ -13561,7 +13638,7 @@ This should be as low as possible, but too low may break functionality Type U32 Value - 4 + 4 RenderShadowBlurDistFactor @@ -14324,7 +14401,30 @@ This should be as low as possible, but too low may break functionality RenderAutoMuteByteLimit Comment - Maximum bytes of attachments before an avatar is automatically visually muted (0 for no limit). + If avatar attachment size exceed this value (in bytes) attachment will not be rendered. Excludes attachments worn by own avatar. + Persist + 1 + Type + U32 + Value + 0 + + MaxAttachmentComplexity + + Comment + Attachment's render weight limit + Persist + 1 + Type + F32 + Value + 1.0E6 + + RenderAvatarMaxComplexity + + Comment + Maximum Avatar Complexity; above this value, the avatar is + rendered as a solid color outline (0 to disable this limit). Persist 1 Type @@ -14335,15 +14435,16 @@ This should be as low as possible, but too low may break functionality RenderAutoMuteSurfaceAreaLimit Comment - Maximum surface area of attachments before an avatar is automatically visually muted (0 for no limit). + Maximum surface area of attachments before an avatar is + rendered as a simple impostor (to not use this limit, set to zero + or set RenderAvatarMaxComplexity to zero). Persist 1 Type F32 Value - 0 + 0 - RenderAutoMuteLogging Comment diff --git a/indra/newview/app_settings/settings_sh.xml b/indra/newview/app_settings/settings_sh.xml index e2c8a5fb7..f9b11e704 100644 --- a/indra/newview/app_settings/settings_sh.xml +++ b/indra/newview/app_settings/settings_sh.xml @@ -273,5 +273,16 @@ Value 0 + SHSkipResetVBOsOnTeleport + + Comment + Skip VBO auto-recreation upon teleport. Setting to true may help avoid attachments dissipearing on teleport. + Persist + 1 + Type + Boolean + Value + 0 + diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 87b1e4f99..457de28d5 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -935,6 +935,16 @@ void LLAgent::setRegion(LLViewerRegion *regionp) { gSky.mVOGroundp->setRegion(regionp); } + + if (regionp->capabilitiesReceived()) + { + regionp->requestSimulatorFeatures(); + } + else + { + regionp->setCapabilitiesReceivedCallback(boost::bind(&LLViewerRegion::requestSimulatorFeatures, regionp)); + } + } else { @@ -4003,12 +4013,16 @@ bool LLAgent::teleportCore(bool is_local) gTeleportDisplay = TRUE; gAgent.setTeleportState( LLAgent::TELEPORT_START ); - /*static const LLCachedControl hide_tp_screen("AscentDisableTeleportScreens",false); - if(!hide_tp_screen) + static const LLCachedControl hide_tp_screen("AscentDisableTeleportScreens",false); + static const LLCachedControl skip_reset_objects_on_teleport("SHSkipResetVBOsOnTeleport", false); + if(!hide_tp_screen && !skip_reset_objects_on_teleport) { + // AscentDisableTeleportScreens TRUE might be broken..*/ + //release geometry from old location gPipeline.resetVertexBuffers(); - }*/ + LLSpatialPartition::sTeleportRequested = TRUE; + } if (gSavedSettings.getBOOL("SpeedRez")) { @@ -4485,8 +4499,7 @@ void LLAgent::stopCurrentAnimations() // re-assert at least the default standing animation, because // viewers get confused by avs with no associated anims. - sendAnimationRequest(ANIM_AGENT_STAND, - ANIM_REQUEST_START); + sendAnimationRequest(ANIM_AGENT_STAND, ANIM_REQUEST_START); } } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 4e948c8c2..baa6809ea 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -863,8 +863,8 @@ void LLWearableHoldingPattern::onAllComplete() << mResolved << " wearable items " << LL_ENDL; LLAppearanceMgr::instance().updateAgentWearables(this); -// // Restore attachment pos overrides for the attachments that -// // are remaining in the outfit. + // Restore attachment pos overrides for the attachments that + // are remaining in the outfit. // for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); // it != objects_to_retain.end(); // ++it) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e0cfb0b66..a10b6a6e3 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -256,12 +256,12 @@ LLPumpIO* gServicePump = NULL; BOOL gPacificDaylightTime = FALSE; -U64 gFrameTime = 0; -F32 gFrameTimeSeconds = 0.f; -F32 gFrameIntervalSeconds = 0.f; +U64MicrosecondsImplicit gFrameTime = 0; +F32SecondsImplicit gFrameTimeSeconds = 0.f; +F32SecondsImplicit gFrameIntervalSeconds = 0.f; F32 gFPSClamped = 10.f; // Pretend we start at target rate. F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets -U64 gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds +U64MicrosecondsImplicit gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds U32 gFrameStalls = 0; const F64 FRAME_STALL_THRESHOLD = 1.0; @@ -1330,7 +1330,8 @@ bool LLAppViewer::mainLoop() || (!gFocusMgr.getAppHasFocus() && !AIFilePicker::activePicker) ) { // Sleep if we're not rendering, or the window is minimized. - S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000); + static LLCachedControl s_bacground_yeild_time(gSavedSettings, "BackgroundYieldTime", 40); + S32 milliseconds_to_sleep = llclamp((S32)s_bacground_yeild_time, 0, 1000); // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads // of equal priority on Windows if (milliseconds_to_sleep > 0) @@ -1357,7 +1358,7 @@ bool LLAppViewer::mainLoop() ms_sleep(500); } - const F64 max_idle_time = run_multiple_threads ? 0.0 : llmin(.005*10.0*gFrameIntervalSeconds, 0.005); // 50ms/second, no more than 5ms/frame + const F64 max_idle_time = run_multiple_threads ? 0.0 : llmin(.005*10.0*gFrameIntervalSeconds.value(), 0.005); // 50ms/second, no more than 5ms/frame idleTimer.reset(); while(1) { diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 777f06207..e646aa2b5 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -271,6 +271,7 @@ public: // consts from viewer.h const S32 AGENT_UPDATES_PER_SECOND = 10; +const S32 AGENT_FORCE_UPDATES_PER_SECOND = 1; // Globals with external linkage. From viewer.h // *NOTE:Mani - These will be removed as the Viewer App Cleanup project continues. @@ -303,13 +304,13 @@ extern LLPumpIO* gServicePump; // Is the Pacific time zone (aka server time zone) // currently in daylight savings time? extern BOOL gPacificDaylightTime; - -extern U64 gFrameTime; // The timestamp of the most-recently-processed frame -extern F32 gFrameTimeSeconds; // Loses msec precision after ~4.5 hours... -extern F32 gFrameIntervalSeconds; // Elapsed time between current and previous gFrameTimeSeconds +extern U64MicrosecondsImplicit gStartTime; +extern U64MicrosecondsImplicit gFrameTime; // The timestamp of the most-recently-processed frame +extern F32SecondsImplicit gFrameTimeSeconds; // Loses msec precision after ~4.5 hours... +extern F32SecondsImplicit gFrameIntervalSeconds; // Elapsed time between current and previous gFrameTimeSeconds extern F32 gFPSClamped; // Frames per second, smoothed, weighted toward last frame extern F32 gFrameDTClamped; -extern U64 gStartTime; + extern U32 gFrameStalls; extern LLTimer gRenderStartTime; diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp index 75842c378..dd83d68ab 100644 --- a/indra/newview/llavatarrenderinfoaccountant.cpp +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -47,12 +47,19 @@ static const std::string KEY_AGENTS = "agents"; // map static const std::string KEY_WEIGHT = "weight"; // integer +static const std::string KEY_TOO_COMPLEX = "tooComplex"; // bool +static const std::string KEY_OVER_COMPLEXITY_LIMIT = "overlimit"; // integer +static const std::string KEY_REPORTING_COMPLEXITY_LIMIT = "reportinglimit"; // integer static const std::string KEY_IDENTIFIER = "identifier"; static const std::string KEY_MESSAGE = "message"; static const std::string KEY_ERROR = "error"; +static const F32 SECS_BETWEEN_REGION_SCANS = 5.f; // Scan the region list every 5 seconds +static const F32 SECS_BETWEEN_REGION_REQUEST = 15.0; // Look for new avs every 15 seconds +static const F32 SECS_BETWEEN_REGION_REPORTS = 60.0; // Update each region every 60 seconds + // Send data updates about once per minute, only need per-frame resolution LLFrameTimer LLAvatarRenderInfoAccountant::sRenderInfoReportTimer; @@ -65,90 +72,9 @@ public: { } - virtual void httpFailure() - { - const S32 statusNum = getStatus(); - const std::string& reason = getReason(); - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - LL_WARNS() << "HTTP error result for avatar weight GET: " << statusNum - << ", " << reason - << " returned by region " << regionp->getName() - << LL_ENDL; - } - else - { - LL_WARNS() << "Avatar render weight GET error recieved but region not found for " - << mRegionHandle - << ", error " << statusNum - << ", " << reason - << LL_ENDL; - } + virtual void httpFailure(); - } - - virtual void httpSuccess() - { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - if (LLAvatarRenderInfoAccountant::logRenderInfo()) - { - LL_INFOS() << "LRI: Result for avatar weights request for region " << regionp->getName() << ":" << LL_ENDL; - } - - const LLSD& content = getContent(); - if (content.isMap()) - { - if (content.has(KEY_AGENTS)) - { - const LLSD & agents = content[KEY_AGENTS]; - if (agents.isMap()) - { - LLSD::map_const_iterator report_iter = agents.beginMap(); - while (report_iter != agents.endMap()) - { - LLUUID target_agent_id = LLUUID(report_iter->first); - const LLSD & agent_info_map = report_iter->second; - LLViewerObject* avatarp = gObjectList.findObject(target_agent_id); - if (avatarp && - avatarp->isAvatar() && - agent_info_map.isMap()) - { // Extract the data for this avatar - - if (LLAvatarRenderInfoAccountant::logRenderInfo()) - { - LL_INFOS() << "LRI: Agent " << target_agent_id - << ": " << agent_info_map << LL_ENDL; - } - - if (agent_info_map.has(KEY_WEIGHT)) - { - ((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); - } - } - report_iter++; - } - } - } // has "agents" - else if (content.has(KEY_ERROR)) - { - const LLSD & error = content[KEY_ERROR]; - LL_WARNS() << "Avatar render info GET error: " - << error[KEY_IDENTIFIER] - << ": " << error[KEY_MESSAGE] - << " from region " << regionp->getName() - << LL_ENDL; - } - } - } - else - { - LL_INFOS() << "Avatar render weight info recieved but region not found for " - << mRegionHandle << LL_ENDL; - } - } + virtual void httpSuccess(); /*virtual*/ char const* getName() const { return "This is dumb."; } private: @@ -156,6 +82,123 @@ private: }; +void LLAvatarRenderInfoGetResponder::httpFailure() +{ + const S32 statusNum = getStatus(); + const std::string& reason = getReason(); + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + LL_WARNS() << "HTTP error result for avatar weight GET: " << statusNum + << ", " << reason + << " returned by region " << regionp->getName() + << LL_ENDL; + } + else + { + LL_WARNS() << "Avatar render weight GET error recieved but region not found for " + << mRegionHandle + << ", error " << statusNum + << ", " << reason + << LL_ENDL; + } +} + + +void LLAvatarRenderInfoGetResponder::httpSuccess() +{ + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (!regionp) + { + LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight info received but region not found for " + << mRegionHandle << LL_ENDL; + return; + } + + if (LLAvatarRenderInfoAccountant::logRenderInfo()) + { + LL_INFOS() << "LRI: Result for avatar weights request for region " << regionp->getName() << ":" << LL_ENDL; + } + + const LLSD& result = getContent(); + if (result.isMap()) + { + if (result.has(KEY_AGENTS)) + { + const LLSD & agents = result[KEY_AGENTS]; + if (agents.isMap()) + { + for (LLSD::map_const_iterator agent_iter = agents.beginMap(); + agent_iter != agents.endMap(); + agent_iter++ + ) + { + LLUUID target_agent_id = LLUUID(agent_iter->first); + LLVOAvatar* avatarp = gObjectList.findAvatar(target_agent_id); + if (avatarp && + !avatarp->isControlAvatar() && + avatarp->isAvatar()) + + { + const LLSD & agent_info_map = agent_iter->second; + if (agent_info_map.isMap()) + { + // Extract the data for this avatar + if (LLAvatarRenderInfoAccountant::logRenderInfo()) + { + LL_INFOS() << "LRI: Agent " << target_agent_id + << ": " << agent_info_map << LL_ENDL; + } + if (agent_info_map.has(KEY_WEIGHT)) + { + avatarp->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); + } + } + else + { + LL_WARNS("AvatarRenderInfo") << "agent entry invalid" + << " agent " << target_agent_id + << " map " << agent_info_map + << LL_ENDL; + } + } + else + { + LL_DEBUGS("AvatarRenderInfo") << "Unknown agent " << target_agent_id << LL_ENDL; + } + } + } + else + { + LL_WARNS("AvatarRenderInfo") << "malformed get response '" << KEY_AGENTS << "' is not map" << LL_ENDL; + } + } + else + { + LL_INFOS("AvatarRenderInfo") << "no '" << KEY_AGENTS << "' key in get response" << LL_ENDL; + } + + if (result.has(KEY_REPORTING_COMPLEXITY_LIMIT) + && result.has(KEY_OVER_COMPLEXITY_LIMIT)) + { + U32 reporting = result[KEY_REPORTING_COMPLEXITY_LIMIT].asInteger(); + U32 overlimit = result[KEY_OVER_COMPLEXITY_LIMIT].asInteger(); + + LL_DEBUGS("AvatarRenderInfo") << "complexity limit: " << reporting << " reporting, " << overlimit << " over limit" << LL_ENDL; + } + if (result.has(KEY_ERROR)) + { + const LLSD & error = result[KEY_ERROR]; + LL_WARNS() << "Avatar render info GET error: " + << error[KEY_IDENTIFIER] + << ": " << error[KEY_MESSAGE] + << " from region " << regionp->getName() + << LL_ENDL; + } + } +} + + // HTTP responder class for POST request for avatar render weight information class LLAvatarRenderInfoPostResponder : public LLHTTPClient::ResponderWithResult { @@ -164,59 +207,9 @@ public: { } - virtual void httpFailure() - { - const S32 statusNum = getStatus(); - const std::string& reason = getReason(); - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - LL_WARNS() << "HTTP error result for avatar weight POST: " << statusNum - << ", " << reason - << " returned by region " << regionp->getName() - << LL_ENDL; - } - else - { - LL_WARNS() << "Avatar render weight POST error recieved but region not found for " - << mRegionHandle - << ", error " << statusNum - << ", " << reason - << LL_ENDL; - } - } + virtual void httpFailure(); - virtual void httpSuccess() - { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - const LLSD& content = getContent(); - if (LLAvatarRenderInfoAccountant::logRenderInfo()) - { - LL_INFOS() << "LRI: Result for avatar weights POST for region " << regionp->getName() - << ": " << content << LL_ENDL; - } - - if (content.isMap()) - { - if (content.has(KEY_ERROR)) - { - const LLSD & error = content[KEY_ERROR]; - LL_WARNS() << "Avatar render info POST error: " - << error[KEY_IDENTIFIER] - << ": " << error[KEY_MESSAGE] - << " from region " << regionp->getName() - << LL_ENDL; - } - } - } - else - { - LL_INFOS() << "Avatar render weight POST result recieved but region not found for " - << mRegionHandle << LL_ENDL; - } - } + virtual void httpSuccess(); /*virtual*/ char const* getName() const { return "This is also dumb."; } private: @@ -231,48 +224,55 @@ void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regio std::string url = regionp->getCapability("AvatarRenderInfo"); if (!url.empty()) { - if (logRenderInfo()) - { - LL_INFOS() << "LRI: Sending avatar render info to region " - << regionp->getName() - << " from " << url - << LL_ENDL; - } + if (logRenderInfo()) + { + LL_INFOS() << "LRI: Sending avatar render info to region " + << regionp->getName() + << " from " << url + << LL_ENDL; + } - // Build the render info to POST to the region - LLSD report = LLSD::emptyMap(); - LLSD agents = LLSD::emptyMap(); + U32 num_avs = 0; + // Build the render info to POST to the region + LLSD agents = LLSD::emptyMap(); - std::vector::iterator iter = LLCharacter::sInstances.begin(); - while( iter != LLCharacter::sInstances.end() ) + std::vector::iterator iter = LLCharacter::sInstances.begin(); + while( iter != LLCharacter::sInstances.end() ) + { + LLVOAvatar* avatar = dynamic_cast(*iter); + if (avatar && + avatar->getRezzedStatus() >= 2 && // Mostly rezzed (maybe without baked textures downloaded) + !avatar->isDead() && // Not dead yet + !avatar->isControlAvatar() && // Not part of an animated object + avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region { - LLVOAvatar* avatar = dynamic_cast(*iter); - if (avatar && - avatar->getRezzedStatus() >= 2 && // Mostly rezzed (maybe without baked textures downloaded) - !avatar->isDead() && // Not dead yet - avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region + avatar->calculateUpdateRenderComplexity(); // Make sure the numbers are up-to-date + + LLSD info = LLSD::emptyMap(); + U32 avatar_complexity = avatar->getVisualComplexity(); + if (avatar_complexity > 0) { - avatar->calculateUpdateRenderCost(); // Make sure the numbers are up-to-date - - LLSD info = LLSD::emptyMap(); - if (avatar->getVisualComplexity() > 0) + // the weight/complexity is unsigned, but LLSD only stores signed integers, + // so if it's over that (which would be ridiculously high), just store the maximum signed int value + info[KEY_WEIGHT] = (S32)(avatar_complexity < S32_MAX ? avatar_complexity : S32_MAX); + info[KEY_TOO_COMPLEX] = LLSD::Boolean(avatar->isTooComplex()); + agents[avatar->getID().asString()] = info; + + if (logRenderInfo()) { - info[KEY_WEIGHT] = avatar->getVisualComplexity(); - agents[avatar->getID().asString()] = info; - - if (logRenderInfo()) - { - LL_INFOS() << "LRI: Sending avatar render info for " << avatar->getID() + LL_INFOS("AvatarRenderInfo") << "Sending avatar render info for " << avatar->getID() << ": " << info << LL_ENDL; - LL_INFOS() << "LRI: other info geometry " << avatar->getAttachmentGeometryBytes() - << ", area " << avatar->getAttachmentSurfaceArea() - << LL_ENDL; - } } + num_avs++; } - iter++; } + iter++; + } + if (num_avs == 0) + return; // nothing to report + + LLSD report = LLSD::emptyMap(); report[KEY_AGENTS] = agents; if (agents.size() > 0) { @@ -281,8 +281,63 @@ void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regio } } +void LLAvatarRenderInfoPostResponder::httpSuccess() +{ + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (!regionp) + { + LL_INFOS("AvatarRenderInfoAccountant") << "Avatar render weight POST result received but region not found for " + << mRegionHandle << LL_ENDL; + return; + } + const LLSD& result = getContent(); + if (result.isMap()) + { + if (result.has(KEY_ERROR)) + { + const LLSD & error = result[KEY_ERROR]; + LL_WARNS("AvatarRenderInfoAccountant") << "POST error: " + << error[KEY_IDENTIFIER] + << ": " << error[KEY_MESSAGE] + << " from region " << regionp->getName() + << LL_ENDL; + } + else + { + LL_DEBUGS("AvatarRenderInfoAccountant") + << "POST result for region " << regionp->getName() + << ": " << result + << LL_ENDL; + } + } + else + { + LL_WARNS("AvatarRenderInfoAccountant") << "Malformed POST response from region '" << regionp->getName() + << LL_ENDL; + } +} - +void LLAvatarRenderInfoPostResponder::httpFailure() +{ + const S32 statusNum = getStatus(); + const std::string& reason = getReason(); + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + LL_WARNS() << "HTTP error result for avatar weight POST: " << statusNum + << ", " << reason + << " returned by region " << regionp->getName() + << LL_ENDL; + } + else + { + LL_WARNS() << "Avatar render weight POST error recieved but region not found for " + << mRegionHandle + << ", error " << statusNum + << ", " << reason + << LL_ENDL; + } +} // static // Send request for one region, no timer checks @@ -311,9 +366,6 @@ void LLAvatarRenderInfoAccountant::idle() { if (sRenderInfoReportTimer.hasExpired()) { - const F32 SECS_BETWEEN_REGION_SCANS = 5.f; // Scan the region list every 5 seconds - const F32 SECS_BETWEEN_REGION_REQUEST = 60.0; // Update each region every 60 seconds - S32 num_avs = LLCharacter::sInstances.size(); if (logRenderInfo()) diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp new file mode 100644 index 000000000..f11e228ba --- /dev/null +++ b/indra/newview/llcontrolavatar.cpp @@ -0,0 +1,641 @@ +/** + * @file llcontrolavatar.cpp + * @brief Implementation for special dummy avatar used to drive rigged meshes. + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llcontrolavatar.h" +#include "llagent.h" // Get state values from here +#include "llviewerobjectlist.h" +#include "pipeline.h" +#include "llanimationstates.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" +#include "llviewerregion.h" +#include "llskinningutil.h" + +//#pragma optimize("", off) + +const F32 LLControlAvatar::MAX_LEGAL_OFFSET = 3.0f; +const F32 LLControlAvatar::MAX_LEGAL_SIZE = 64.0f; + +//static +boost::signals2::connection LLControlAvatar::sRegionChangedSlot; + +LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) : + LLVOAvatar(id, pcode, regionp), + mPlaying(false), + mGlobalScale(1.0f), + mMarkedForDeath(false), + mRootVolp(NULL), + mScaleConstraintFixup(1.0), + mRegionChanged(false) +{ + mIsDummy = TRUE; + mIsControlAvatar = true; + mEnableDefaultMotions = false; +} + +// virtual +LLControlAvatar::~LLControlAvatar() +{ +} + +// virtual +void LLControlAvatar::initInstance() +{ + // Potential optimizations here: avoid creating system + // avatar mesh content since it's not used. For now we just clean some + // things up after the fact in releaseMeshData(). + LLVOAvatar::initInstance(); + + createDrawable(&gPipeline); + updateJointLODs(); + updateGeometry(mDrawable); + hideSkirt(); + + mInitFlags |= 1<<4; +} + +void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_scale_fixup) const +{ + + F32 max_legal_offset = MAX_LEGAL_OFFSET; + if (gSavedSettings.getControl("AnimatedObjectsMaxLegalOffset")) + { + max_legal_offset = gSavedSettings.getF32("AnimatedObjectsMaxLegalOffset"); + } + max_legal_offset = llmax(max_legal_offset,0.f); + + F32 max_legal_size = MAX_LEGAL_SIZE; + if (gSavedSettings.getControl("AnimatedObjectsMaxLegalSize")) + { + max_legal_size = gSavedSettings.getF32("AnimatedObjectsMaxLegalSize"); + } + max_legal_size = llmax(max_legal_size, 1.f); + + new_pos_fixup = LLVector3(); + new_scale_fixup = 1.0f; + LLVector3 vol_pos = mRootVolp->getRenderPosition(); + + // Fix up position if needed to prevent visual encroachment + if (box_valid_and_non_zero(getLastAnimExtents())) // wait for state to settle down + { + // The goal here is to ensure that the extent of the avatar's + // bounding box does not wander too far from the + // official position of the corresponding volume. We + // do this by tracking the distance and applying a + // correction to the control avatar position if + // needed. + const LLVector3 *extents = getLastAnimExtents(); + LLVector3 unshift_extents[2]; + unshift_extents[0] = extents[0] - mPositionConstraintFixup; + unshift_extents[1] = extents[1] - mPositionConstraintFixup; + LLVector3 box_dims = extents[1]-extents[0]; + F32 box_size = llmax(box_dims[0],box_dims[1],box_dims[2]); + + if (!mRootVolp->isAttachment()) + { + LLVector3 pos_box_offset = point_to_box_offset(vol_pos, unshift_extents); + F32 offset_dist = pos_box_offset.length(); + if (offset_dist > max_legal_offset && offset_dist > 0.f) + { + F32 target_dist = (offset_dist - max_legal_offset); + new_pos_fixup = (target_dist/offset_dist)*pos_box_offset; + } + if (new_pos_fixup != mPositionConstraintFixup) + { + LL_DEBUGS("ConstraintFix") << getFullname() << " pos fix, offset_dist " << offset_dist << " pos fixup " + << new_pos_fixup << " was " << mPositionConstraintFixup << LL_ENDL; + LL_DEBUGS("ConstraintFix") << "vol_pos " << vol_pos << LL_ENDL; + LL_DEBUGS("ConstraintFix") << "extents " << extents[0] << " " << extents[1] << LL_ENDL; + LL_DEBUGS("ConstraintFix") << "unshift_extents " << unshift_extents[0] << " " << unshift_extents[1] << LL_ENDL; + + } + } + /*if (box_size/mScaleConstraintFixup > max_legal_size) + { + new_scale_fixup = mScaleConstraintFixup*max_legal_size/box_size; + LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup " + << mScaleConstraintFixup << " max legal " << max_legal_size + << " -> new scale " << new_scale_fixup << LL_ENDL; + }*/ + } +} + +void LLControlAvatar::matchVolumeTransform() +{ + if (mRootVolp) + { + LLVector3 new_pos_fixup; + F32 new_scale_fixup; + if (mRegionChanged) + { + new_scale_fixup = mScaleConstraintFixup; + new_pos_fixup = mPositionConstraintFixup; + mRegionChanged = false; + } + else + { + getNewConstraintFixups(new_pos_fixup, new_scale_fixup); + } + mPositionConstraintFixup = new_pos_fixup; + mScaleConstraintFixup = new_scale_fixup; + + if (mRootVolp->isAttachment()) + { + LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); + if (attached_av) + { + LLViewerJointAttachment *attach = attached_av->getTargetAttachmentPoint(mRootVolp); + setPositionAgent(mRootVolp->getRenderPosition()); + attach->updateWorldPRSParent(); + LLVector3 joint_pos = attach->getWorldPosition(); + LLQuaternion joint_rot = attach->getWorldRotation(); + LLVector3 obj_pos = mRootVolp->mDrawable->getPosition(); + LLQuaternion obj_rot = mRootVolp->mDrawable->getRotation(); + obj_pos.rotVec(joint_rot); + mRoot->setWorldPosition(obj_pos + joint_pos); + mRoot->setWorldRotation(obj_rot * joint_rot); + setRotation(mRoot->getRotation()); + + F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale"); + setGlobalScale(global_scale * mScaleConstraintFixup); + } + else + { + LL_WARNS_ONCE() << "can't find attached av!" << LL_ENDL; + } + } + else + { + LLVector3 vol_pos = mRootVolp->getRenderPosition(); + + // FIXME: Currently if you're doing something like playing an + // animation that moves the pelvis (on an avatar or + // animated object), the name tag and debug text will be + // left behind. Ideally setPosition() would follow the + // skeleton around in a smarter way, so name tags, + // complexity info and such line up better. Should defer + // this until avatars also get fixed. + + LLQuaternion obj_rot; + if (mRootVolp->mDrawable) + { + obj_rot = mRootVolp->mDrawable->getRotation(); + } + else + { + obj_rot = mRootVolp->getRotation(); + } + + LLMatrix3 bind_mat; + + LLQuaternion bind_rot; +#define MATCH_BIND_SHAPE +#ifdef MATCH_BIND_SHAPE + // MAINT-8671 - based on a patch from Beq Janus + const LLMeshSkinInfo* skin_info = mRootVolp->getSkinInfo(); + if (skin_info) + { + LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL; + bind_rot = LLSkinningUtil::getUnscaledQuaternion(skin_info->mBindShapeMatrix); + } +#endif + setRotation(bind_rot*obj_rot); + mRoot->setWorldRotation(bind_rot*obj_rot); + setPositionAgent(vol_pos); + mRoot->setPosition(vol_pos + mPositionConstraintFixup); + + F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale"); + setGlobalScale(global_scale * mScaleConstraintFixup); + } + } +} + +void LLControlAvatar::setGlobalScale(F32 scale) +{ + if (scale <= 0.0) + { + LL_WARNS() << "invalid global scale " << scale << LL_ENDL; + return; + } + if (scale != mGlobalScale) + { + F32 adjust_scale = scale/mGlobalScale; + LL_INFOS() << "scale " << scale << " adjustment " << adjust_scale << LL_ENDL; + // should we be scaling from the pelvis or the root? + recursiveScaleJoint(mPelvisp,adjust_scale); + mGlobalScale = scale; + } +} + +void LLControlAvatar::recursiveScaleJoint(LLJoint* joint, F32 factor) +{ + joint->setScale(factor * joint->getScale()); + + for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); + iter != joint->mChildren.end(); ++iter) + { + LLJoint* child = *iter; + recursiveScaleJoint(child, factor); + } +} + +// Based on LLViewerJointAttachment::setupDrawable(), without the attaching part. +void LLControlAvatar::updateVolumeGeom() +{ + if (!mRootVolp->mDrawable) + return; + if (mRootVolp->mDrawable->isActive()) + { + mRootVolp->mDrawable->makeStatic(FALSE); + } + mRootVolp->mDrawable->makeActive(); + gPipeline.markMoved(mRootVolp->mDrawable); + gPipeline.markTextured(mRootVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD + mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); + + LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + LLViewerObject* childp = *iter; + if (childp && childp->mDrawable.notNull()) + { + childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); + gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD + gPipeline.markMoved(childp->mDrawable); + } + } + + gPipeline.markRebuild(mRootVolp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + mRootVolp->markForUpdate(TRUE); + + // Note that attachment overrides aren't needed here, have already + // been applied at the time the mControlAvatar was created, in + // llvovolume.cpp. + + matchVolumeTransform(); + + // Initial exploration of allowing scaling skeleton to match root + // prim bounding box. If enabled, would probably be controlled by + // an additional checkbox and default to off. Not enabled for + // initial release. + + // What should the scale be? What we really want is the ratio + // between the scale at which the object was originally designed + // and rigged, and the scale to which it has been subsequently + // modified - for example, if the object has been scaled down by a + // factor of 2 then we should use 0.5 as the global scale. But we + // don't have the original scale stored anywhere, just the current + // scale. Possibilities - 1) remember the original scale + // somewhere, 2) add another field to let the user specify the + // global scale, 3) approximate the original scale by looking at + // the proportions of the skeleton after joint positions have + // been applied + + //LLVector3 obj_scale = obj->getScale(); + //F32 obj_scale_z = llmax(obj_scale[2],0.1f); + //setGlobalScale(obj_scale_z/2.0f); // roughly fit avatar height range (2m) into object height +} + +LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj) +{ + LLControlAvatar *cav = (LLControlAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), CO_FLAG_CONTROL_AVATAR); + + cav->mRootVolp = obj; + + // Sync up position/rotation with object + cav->matchVolumeTransform(); + + return cav; +} + +void LLControlAvatar::markForDeath() +{ + mMarkedForDeath = true; +} + +void LLControlAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) +{ + if (mMarkedForDeath) + { + markDead(); + mMarkedForDeath = false; + } + else + { + LLVOAvatar::idleUpdate(agent, world,time); + } +} + +BOOL LLControlAvatar::updateCharacter(LLAgent &agent) +{ + return LLVOAvatar::updateCharacter(agent); +} + +//virtual +void LLControlAvatar::updateDebugText() +{ + /*if (gSavedSettings.getBOOL("DebugAnimatedObjects")) + { + S32 total_linkset_count = 0; + if (mRootVolp) + { + total_linkset_count = 1 + mRootVolp->getChildren().size(); + } + std::vector volumes; + getAnimatedVolumes(volumes); + S32 animated_volume_count = volumes.size(); + std::string active_string; + std::string type_string; + std::string lod_string; + std::string animated_object_flag_string; + S32 total_tris = 0; + S32 total_verts = 0; + F32 est_tris = 0.f; + F32 est_streaming_tris = 0.f; + F32 streaming_cost = 0.f; + std::string cam_dist_string = ""; + S32 cam_dist_count = 0; + F32 lod_radius = mRootVolp->mLODRadius; + + for (std::vector::iterator it = volumes.begin(); + it != volumes.end(); ++it) + { + LLVOVolume *volp = *it; + S32 verts = 0; + total_tris += volp->getTriangleCount(&verts); + total_verts += verts; + est_tris += volp->getEstTrianglesMax(); + est_streaming_tris += volp->getEstTrianglesStreamingCost(); + streaming_cost += volp->getStreamingCost(); + lod_string += llformat("%d",volp->getLOD()); + if (volp && volp->mDrawable) + { + bool is_animated_flag = volp->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + if (is_animated_flag) + { + animated_object_flag_string += "1"; + } + else + { + animated_object_flag_string += "0"; + } + if (volp->mDrawable->isActive()) + { + active_string += "A"; + } + else + { + active_string += "S"; + } + if (volp->isRiggedMesh()) + { + // Rigged/animatable mesh + type_string += "R"; + lod_radius = volp->mLODRadius; + } + else if (volp->isMesh()) + { + // Static mesh + type_string += "M"; + } + else + { + // Any other prim + type_string += "P"; + } + if (cam_dist_count < 4) + { + cam_dist_string += LLStringOps::getReadableNumber(volp->mLODDistance) + "/" + + LLStringOps::getReadableNumber(volp->mLODAdjustedDistance) + " "; + cam_dist_count++; + } + } + else + { + active_string += "-"; + type_string += "-"; + } + } + addDebugText(llformat("CAV obj %d anim %d active %s impost %d upprd %d strcst %f", + total_linkset_count, animated_volume_count, + active_string.c_str(), (S32) isImpostor(), getUpdatePeriod(), streaming_cost)); + addDebugText(llformat("types %s lods %s", type_string.c_str(), lod_string.c_str())); + addDebugText(llformat("flags %s", animated_object_flag_string.c_str())); + addDebugText(llformat("tris %d (est %.1f, streaming %.1f), verts %d", total_tris, est_tris, est_streaming_tris, total_verts)); + addDebugText(llformat("pxarea %s rank %d", LLStringOps::getReadableNumber(getPixelArea()).c_str(), getVisibilityRank())); + addDebugText(llformat("lod_radius %s dists %s", LLStringOps::getReadableNumber(lod_radius).c_str(),cam_dist_string.c_str())); + if (mPositionConstraintFixup.length() > 0.0f || mScaleConstraintFixup != 1.0f) + { + addDebugText(llformat("pos fix (%.1f %.1f %.1f) scale %f", + mPositionConstraintFixup[0], + mPositionConstraintFixup[1], + mPositionConstraintFixup[2], + mScaleConstraintFixup)); + } + +#if 0 + std::string region_name = "no region"; + if (mRootVolp->getRegion()) + { + region_name = mRootVolp->getRegion()->getName(); + } + std::string skel_region_name = "skel no region"; + if (getRegion()) + { + skel_region_name = getRegion()->getName(); + } + addDebugText(llformat("region %x %s skel %x %s", + mRootVolp->getRegion(), region_name.c_str(), + getRegion(), skel_region_name.c_str())); +#endif + + }*/ + LLVOAvatar::updateDebugText(); +} + +void LLControlAvatar::getAnimatedVolumes(std::vector& volumes) +{ + if (!mRootVolp) + { + return; + } + + volumes.push_back(mRootVolp); + + LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + LLViewerObject* childp = *iter; + LLVOVolume *child_volp = dynamic_cast(childp); + if (child_volp && child_volp->isAnimatedObject()) + { + volumes.push_back(child_volp); + } + } +} + +// This is called after an associated object receives an animation +// message. Combine the signaled animations for all associated objects +// and process any resulting state changes. +void LLControlAvatar::updateAnimations() +{ + if (!mRootVolp) + { + LL_WARNS_ONCE("AnimatedObjectsNotify") << "No root vol" << LL_ENDL; + return; + } + + std::vector volumes; + getAnimatedVolumes(volumes); + + // Rebuild mSignaledAnimations from the associated volumes. + std::map anims; + for (std::vector::iterator vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it) + { + LLVOVolume *volp = *vol_it; + //LL_INFOS("AnimatedObjects") << "updating anim for vol " << volp->getID() << " root " << mRootVolp->getID() << LL_ENDL; + signaled_animation_map_t& signaled_animations = LLObjectSignaledAnimationMap::instance().getMap()[volp->getID()]; + for (std::map::iterator anim_it = signaled_animations.begin(); + anim_it != signaled_animations.end(); + ++anim_it) + { + std::map::iterator found_anim_it = anims.find(anim_it->first); + if (found_anim_it != anims.end()) + { + // Animation already present, use the larger sequence id + anims[anim_it->first] = llmax(found_anim_it->second, anim_it->second); + } + else + { + // Animation not already present, use this sequence id. + anims[anim_it->first] = anim_it->second; + } + LL_DEBUGS("AnimatedObjectsNotify") << "found anim for vol " << volp->getID() << " anim " << anim_it->first << " root " << mRootVolp->getID() << LL_ENDL; + } + } + if (!mPlaying) + { + mPlaying = true; + //if (!mRootVolp->isAnySelected()) + { + updateVolumeGeom(); + mRootVolp->recursiveMarkForUpdate(TRUE); + } + } + + mSignaledAnimations = anims; + processAnimationStateChanges(); +} + +// virtual +LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end, + S32 face, + BOOL pick_transparent, + S32* face_hit, + LLVector4a* intersection, + LLVector2* tex_coord, + LLVector4a* normal, + LLVector4a* tangent) +{ + LLViewerObject* hit = NULL; + + if (lineSegmentBoundingBox(start, end)) + { + LLVector4a local_end = end; + LLVector4a local_intersection; + + if (mRootVolp && + mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, face_hit, &local_intersection, tex_coord, normal, tangent)) + { + local_end = local_intersection; + if (intersection) + { + *intersection = local_intersection; + } + + hit = mRootVolp; + } + } + + return hit; +} + +// virtual +std::string LLControlAvatar::getFullname() const +{ + if (mRootVolp) + { + return "AO_" + mRootVolp->getID().getString(); + } + else + { + return "AO_no_root_vol"; + } +} + +// virtual +bool LLControlAvatar::shouldRenderRigged() const +{ + if (mRootVolp && mRootVolp->isAttachment()) + { + LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); + if (attached_av) + { + return attached_av->shouldRenderRigged(); + } + } + return true; +} + +// virtual +BOOL LLControlAvatar::isImpostor() +{ + if (mRootVolp && mRootVolp->isAttachment()) + { + // Attached animated objects should match state of their attached av. + LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); + if (attached_av) + { + return attached_av->isImpostor(); + } + } + return LLVOAvatar::isImpostor(); +} + +//static +void LLControlAvatar::onRegionChanged() +{ + std::vector::iterator it = LLCharacter::sInstances.begin(); + for ( ; it != LLCharacter::sInstances.end(); ++it) + { + LLControlAvatar* cav = dynamic_cast(*it); + if (!cav) continue; + cav->mRegionChanged = true; + } +} diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h new file mode 100644 index 000000000..d8070b997 --- /dev/null +++ b/indra/newview/llcontrolavatar.h @@ -0,0 +1,112 @@ +/** + * @file llcontrolavatar.h + * @brief Special dummy avatar used to drive rigged meshes. + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_CONTROLAVATAR_H +#define LL_CONTROLAVATAR_H + +#include "llvoavatar.h" +#include "llvovolume.h" + +class LLControlAvatar: + public LLVOAvatar +{ + LOG_CLASS(LLControlAvatar); + +public: + LLControlAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); + virtual void initInstance(); // Called after construction to initialize the class. + virtual ~LLControlAvatar(); + + void getNewConstraintFixups(LLVector3& new_pos_constraint, F32& new_scale_constraint) const; + void matchVolumeTransform(); + void updateVolumeGeom(); + + void setGlobalScale(F32 scale); + void recursiveScaleJoint(LLJoint *joint, F32 factor); + static LLControlAvatar *createControlAvatar(LLVOVolume *obj); + + // Delayed kill so we don't make graphics pipeline unhappy calling + // markDead() inside other graphics pipeline operations. + void markForDeath(); + + virtual void idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + virtual BOOL updateCharacter(LLAgent &agent); + + void getAnimatedVolumes(std::vector& volumes); + void updateAnimations(); + + virtual LLViewerObject* lineSegmentIntersectRiggedAttachments( + const LLVector4a& start, const LLVector4a& end, + S32 face = -1, // which face to check, -1 = ALL_SIDES + BOOL pick_transparent = FALSE, + S32* face_hit = NULL, // which face was hit + LLVector4a* intersection = NULL, // return the intersection point + LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL); // return the surface tangent at the intersection point + + virtual void updateDebugText(); + + virtual std::string getFullname() const; + + virtual bool shouldRenderRigged() const; + + virtual BOOL isImpostor(); + + bool mPlaying; + + F32 mGlobalScale; + + LLVOVolume *mRootVolp; + + bool mMarkedForDeath; + + LLVector3 mPositionConstraintFixup; + F32 mScaleConstraintFixup; + + static const F32 MAX_LEGAL_OFFSET; + static const F32 MAX_LEGAL_SIZE; + + static void onRegionChanged(); + bool mRegionChanged; + static boost::signals2::connection sRegionChangedSlot; +}; + +typedef std::map signaled_animation_map_t; +typedef std::map object_signaled_animation_map_t; + +// Stores information about previously requested animations, by object id. +class LLObjectSignaledAnimationMap: public LLSingleton +{ +public: + LLObjectSignaledAnimationMap() {} + + object_signaled_animation_map_t mMap; + + object_signaled_animation_map_t& getMap() { return mMap; } +}; + +#endif //LL_CONTROLAVATAR_H diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 360c1d977..a254f3899 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -32,6 +32,7 @@ #include "material_codes.h" // viewer includes +#include "llagent.h" #include "llcriticaldamp.h" #include "llface.h" #include "lllightconstants.h" @@ -49,6 +50,8 @@ #include "llspatialpartition.h" #include "llviewerobjectlist.h" #include "llviewerwindow.h" +#include "llcontrolavatar.h" +#include "lldrawpoolavatar.h" const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f; const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f; @@ -113,6 +116,28 @@ void LLDrawable::init() initVisible(sCurVisible - 2);//invisible for the current frame and the last frame. } +void LLDrawable::unload() +{ + LLVOVolume *pVVol = getVOVolume(); + pVVol->setNoLOD(); + + for (S32 i = 0; i < getNumFaces(); i++) + { + LLFace* facep = getFace(i); + if (facep->isState(LLFace::RIGGED)) + { + LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*)facep->getPool(); + if (pool) { + pool->removeRiggedFace(facep); + } + facep->setVertexBuffer(NULL); + } + facep->clearState(LLFace::RIGGED); + } + + pVVol->markForUpdate(TRUE); +} + // static void LLDrawable::initClass() { @@ -512,7 +537,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled) if (isState(ACTIVE) && !isState(ACTIVE_CHILD) && !mVObjp->isAttachment() && - !mVObjp->isFlexible()) + !mVObjp->isFlexible() && + !mVObjp->isAnimatedObject()) { clearState(ACTIVE | ANIMATED_CHILD); @@ -604,6 +630,9 @@ F32 LLDrawable::updateXform(BOOL undamped) { // snap to final position (only if no target omega is applied) dist_squared = 0.0f; + //set target scale here, because of dist_squared = 0.0f remove object from move list + mCurrentScale = target_scale; // Animesh+ + if (getVOVolume() && !isRoot()) { //child prim snapping to some position, needs a rebuild gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); @@ -622,9 +651,15 @@ F32 LLDrawable::updateXform(BOOL undamped) LLVector3 vec = mCurrentScale-target_scale; + //It's a very important on each cycle on Drawable::update form(), when object remained in move + //, list update the CurrentScale member, because if do not do that, it remained in this list forever + //or when the delta time between two frames a become a sufficiently large (due to interpolation) + //for overcome the MIN_INTERPOLATE_DISTANCE_SQUARED. + mCurrentScale = target_scale; // Animesh+ + if (vec*vec > MIN_INTERPOLATE_DISTANCE_SQUARED) { //scale change requires immediate rebuild - mCurrentScale = target_scale; + //mCurrentScale = target_scale; // Animesh- gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); } else if (!isRoot() && @@ -655,6 +690,10 @@ F32 LLDrawable::updateXform(BOOL undamped) mXform.setRotation(target_rot); mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!) mXform.updateMatrix(); + if (isRoot() && mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) + { + mVObjp->getControlAvatar()->matchVolumeTransform(); + } if (mSpatialBridge) { @@ -724,7 +763,7 @@ BOOL LLDrawable::updateMoveUndamped() if (!isState(LLDrawable::INVISIBLE)) { - BOOL moved = (dist_squared > 0.001f); + BOOL moved = (dist_squared > 0.001f && dist_squared < 255.99f); // Animesh added 255.99f cap moveUpdatePipeline(moved); mVObjp->updateText(); } @@ -758,7 +797,7 @@ BOOL LLDrawable::updateMoveDamped() if (!isState(LLDrawable::INVISIBLE)) { - BOOL moved = (dist_squared > 0.001f); + BOOL moved = (dist_squared > 0.001f && dist_squared < 128.0f); // Animesh added 128.0f cap moveUpdatePipeline(moved); mVObjp->updateText(); } @@ -826,6 +865,28 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) } } } + + // MAINT-7926 Handle volumes in an animated object as a special case + // SL-937: add dynamic box handling for rigged mesh on regular avatars. + //if (volume->getAvatar() && volume->getAvatar()->isControlAvatar()) + if (volume->getAvatar()) + { + const LLVector3* av_box = volume->getAvatar()->getLastAnimExtents(); + LLVector3d cam_pos = gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin()); + LLVector3 cam_region_pos = LLVector3(cam_pos - volume->getRegion()->getOriginGlobal()); + + LLVector3 cam_to_box_offset = point_to_box_offset(cam_region_pos, av_box); + mDistanceWRTCamera = llmax(0.01f, ll_round(cam_to_box_offset.magVec(), 0.01f)); + LL_DEBUGS("DynamicBox") << volume->getAvatar()->getFullname() + << " pos (ignored) " << pos + << " cam pos " << cam_pos + << " cam region pos " << cam_region_pos + << " box " << av_box[0] << "," << av_box[1] + << " -> dist " << mDistanceWRTCamera + << LL_ENDL; + mVObjp->updateLOD(); + return; + } } else { @@ -939,9 +1000,7 @@ void LLDrawable::updateSpatialExtents() if (mVObjp) { const LLVector4a* exts = getSpatialExtents(); - LLVector4a extents[2]; - extents[0] = exts[0]; - extents[1] = exts[1]; + LLVector4a extents[2] = { exts[0], exts[1] }; mVObjp->updateSpatialExtents(extents[0], extents[1]); setSpatialExtents(extents[0], extents[1]); diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 2eb683290..1da98e315 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -98,7 +98,7 @@ public: void markDead(); // Mark this drawable as dead BOOL isDead() const { return isState(DEAD); } BOOL isNew() const { return !isState(BUILT); } - + BOOL isUnload() const { return isState(FOR_UNLOAD); } BOOL isLight() const; virtual void setVisible(LLCamera& camera_in, std::vector* results = NULL, BOOL for_select = FALSE); @@ -155,6 +155,7 @@ public: void mergeFaces(LLDrawable* src); void init(); + void unload(); void destroy(); void update(); @@ -296,6 +297,7 @@ public: PARTITION_MOVE = 0x10000000, ANIMATED_CHILD = 0x20000000, ACTIVE_CHILD = 0x40000000, + FOR_UNLOAD = 0x80000000, //should be unload from memory } EDrawableFlags; public: diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 8843dad39..64c69b76f 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -116,6 +116,32 @@ LLDrawPoolAvatar::LLDrawPoolAvatar() : { } +LLDrawPoolAvatar::~LLDrawPoolAvatar() +{ + if (!isDead()) + { + LL_WARNS() << "Destroying avatar drawpool that still contains faces" << LL_ENDL; + } +} + +// virtual +BOOL LLDrawPoolAvatar::isDead() +{ + if (!LLFacePool::isDead()) + { + return FALSE; + } + + for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i) + { + if (mRiggedFace[i].size() > 0) + { + return FALSE; + } + } + return TRUE; +} + //----------------------------------------------------------------------------- // instancePool() //----------------------------------------------------------------------------- @@ -460,7 +486,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) } LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); - if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull()) + if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull()) { return; } @@ -1479,7 +1505,7 @@ extern int sCurCacheHit; void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) { - if ((avatar->isSelf() && !gAgent.needsRenderAvatar()) || !gMeshRepo.meshRezEnabled()) + if (!avatar->shouldRenderRigged() || !gMeshRepo.meshRezEnabled()) { return; } @@ -1510,13 +1536,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) continue; } - LLUUID mesh_id = volume->getParams().getSculptID(); - if (mesh_id.isNull()) - { - continue; - } - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); + const LLMeshSkinInfo* skin = vobj->getSkinInfo(); if (!skin) { continue; @@ -1729,7 +1749,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) LLVOVolume* vobj = drawable->getVOVolume(); - if (!vobj) + if (!vobj || vobj->isNoLOD()) { continue; } @@ -1742,13 +1762,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) continue; } - LLUUID mesh_id = volume->getParams().getSculptID(); - if (mesh_id.isNull()) - { - continue; - } - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); + const LLMeshSkinInfo* skin = vobj->getSkinInfo(); if (!skin) { continue; diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index dba3c1633..acc11a95e 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -67,6 +67,8 @@ public: virtual S32 getVertexShaderLevel() const; LLDrawPoolAvatar(); + ~LLDrawPoolAvatar(); + /*virtual*/ BOOL isDead(); static const LLMatrix4a& getModelView(); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index b89053fa3..a09c7c8fe 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -59,6 +59,7 @@ #include "llviewershadermgr.h" #include "llviewertexture.h" #include "llvoavatar.h" +#include "llsculptidsize.h" #define LL_MAX_INDICES_COUNT 1000000 @@ -330,6 +331,8 @@ void LLFace::dirtyTexture() if (vobj) { vobj->mLODChanged = TRUE; + + vobj->updateVisualComplexity(); // Animmesh+ } gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE); } @@ -851,12 +854,6 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, //get bounding box if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED)) { - //VECTORIZE THIS - const LLMatrix4a& mat_vert = mat_vert_in; - //mat_vert.loadu(mat_vert_in); - - LLVector4a min,max; - if (f >= volume.getNumVolumeFaces()) { LL_WARNS() << "Generating bounding box for invalid face index!" << LL_ENDL; @@ -864,77 +861,42 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, } const LLVolumeFace &face = volume.getVolumeFace(f); - min = face.mExtents[0]; - max = face.mExtents[1]; - llassert(less_than_max_mag(min)); - llassert(less_than_max_mag(max)); - //min, max are in volume space, convert to drawable render space - - //get 8 corners of bounding box - LLVector4Logical mask[6]; - - for (U32 i = 0; i < 6; ++i) + // MAINT-8264 - stray vertices, especially in low LODs, cause bounding box errors. + if (face.mNumVertices < 3) { - mask[i].clear(); + LL_DEBUGS("RiggedBox") << "skipping face " << f << ", bad num vertices " + << face.mNumVertices << " " << face.mNumIndices << " " << face.mWeights << LL_ENDL; + return FALSE; } - mask[0].setElement<2>(); //001 - mask[1].setElement<1>(); //010 - mask[2].setElement<1>(); //011 - mask[2].setElement<2>(); - mask[3].setElement<0>(); //100 - mask[4].setElement<0>(); //101 - mask[4].setElement<2>(); - mask[5].setElement<0>(); //110 - mask[5].setElement<1>(); - - LLVector4a v[8]; + //VECTORIZE THIS + LLMatrix4a mat_vert = mat_vert_in; + LLVector4a new_extents[2]; - v[6] = min; - v[7] = max; + llassert(less_than_max_mag(face.mExtents[0])); + llassert(less_than_max_mag(face.mExtents[1])); - for (U32 i = 0; i < 6; ++i) - { - v[i].setSelectWithMask(mask[i], min, max); - } - - LLVector4a tv[8]; - - //transform bounding box into drawable space - for (U32 i = 0; i < 8; ++i) - { - mat_vert.affineTransform(v[i], tv[i]); - } - - //find bounding box - LLVector4a& newMin = mExtents[0]; - LLVector4a& newMax = mExtents[1]; - - newMin = newMax = tv[0]; - - for (U32 i = 1; i < 8; ++i) - { - newMin.setMin(newMin, tv[i]); - newMax.setMax(newMax, tv[i]); - } + matMulBoundBox(mat_vert, face.mExtents, mExtents); if (!mDrawablep->isActive()) { // Shift position for region LLVector4a offset; offset.load3(mDrawablep->getRegion()->getOriginAgent().mV); - newMin.add(offset); - newMax.add(offset); + mExtents[0].add(offset); + mExtents[1].add(offset); + LL_DEBUGS("RiggedBox") << "updating extents for face " << f + << " not active, added offset " << offset << LL_ENDL; } LLVector4a t; - t.setAdd(newMin,newMax); + t.setAdd(mExtents[0],mExtents[1]); t.mul(0.5f); mCenterLocal.set(t.getF32ptr()); - t.setSub(newMax,newMin); + t.setSub(mExtents[1],mExtents[0]); mBoundingSphereRadius = t.getLength3().getF32()*0.5f; updateCenterAgent(); @@ -2521,12 +2483,25 @@ LLViewerTexture* LLFace::getTexture(U32 ch) const void LLFace::setVertexBuffer(LLVertexBuffer* buffer) { + if (buffer) + { + LLSculptIDSize::instance().inc(mDrawablep, buffer->getSize() + buffer->getIndicesSize()); + } + + if (mVertexBuffer) + { + LLSculptIDSize::instance().dec(mDrawablep); + } mVertexBuffer = buffer; llassert(verify()); } void LLFace::clearVertexBuffer() { + if (mVertexBuffer) + { + LLSculptIDSize::instance().dec(mDrawablep); + } mVertexBuffer = NULL; } diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index c16c5739f..43ebdf14e 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -1308,17 +1308,10 @@ LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicT mCameraPitch = 0.f; mCameraZoom = 1.f; - mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion()); - mDummyAvatar->createDrawable(&gPipeline); - mDummyAvatar->mIsDummy = TRUE; + mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR); mDummyAvatar->mSpecialRenderMode = 1; - mDummyAvatar->setPositionAgent(LLVector3::zero); - mDummyAvatar->slamPosition(); - mDummyAvatar->updateJointLODs(); - mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable); mDummyAvatar->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET); mDummyAvatar->hideSkirt(); - //gPipeline.markVisible(mDummyAvatar->mDrawable, *LLViewerCamera::getInstance()); // stop extraneous animations mDummyAvatar->stopMotion( ANIM_AGENT_HEAD_ROT, TRUE ); diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 283ecb157..d44333f04 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -621,15 +621,8 @@ LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLViewerDyna mCameraPitch = 0.f; mCameraZoom = 1.f; - mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion()); - mDummyAvatar->createDrawable(&gPipeline); - mDummyAvatar->mIsDummy = TRUE; + mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR); mDummyAvatar->mSpecialRenderMode = 2; - mDummyAvatar->setPositionAgent(LLVector3::zero); - mDummyAvatar->slamPosition(); - mDummyAvatar->updateJointLODs(); - mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable); - // gPipeline.markVisible(mDummyAvatar->mDrawable, *LLViewerCamera::getInstance()); mTextureName = 0; } diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 9f798c68c..e5126bb45 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -500,7 +500,9 @@ void LLFloaterModelPreview::onClickCalculateBtn() mUploadModelUrl.clear(); gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, - childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mUploadModelUrl, false, + childGetValue("upload_textures").asBoolean(), + upload_skinweights, upload_joint_positions, + mUploadModelUrl, false, getWholeModelFeeObserverHandle()); toggleCalculateButton(false); @@ -1194,6 +1196,7 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex() , mLodsQuery() +, mLodsWithParsingError() , mPelvisZOffset( 0.0f ) , mLegacyRigValid( false ) , mRigValidJointUpload( false ) @@ -1258,6 +1261,10 @@ LLModelPreview::~LLModelPreview() // glod.dll!glodShutdown() + 0x77 bytes // //glodShutdown(); + if(mModelLoader) + { + mModelLoader->shutdown(); + } } U32 LLModelPreview::calcResourceCost() @@ -1352,7 +1359,11 @@ U32 LLModelPreview::calcResourceCost() F32 radius = scale.length()*0.5f*debug_scale; - streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); + LLMeshCostData costs; + if (LLMeshRepository::getCostData(ret, costs)) + { + streaming_cost += costs.getRadiusBasedStreamingCost(radius); + } } } @@ -1373,6 +1384,15 @@ void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z)); } +void LLFloaterModelPreview::setPreviewLOD(S32 lod) +{ + if (mModelPreview) + { + mModelPreview->setPreviewLOD(lod); + } +} + + void LLModelPreview::rebuildUploadData() { assert_main_thread(); @@ -1749,16 +1769,24 @@ void LLModelPreview::clearModel(S32 lod) void LLModelPreview::getJointAliases( JointMap& joint_map) { - // Get all standard skeleton joints from the preview avatar. - LLVOAvatar *av = getPreviewAvatar(); - - //Joint names and aliases come from avatar_skeleton.xml - - joint_map = av->getJointAliases(); - for (S32 i = 0; i < av->mCollisionVolumes.size(); i++) - { - joint_map[av->mCollisionVolumes[i]->getName()] = av->mCollisionVolumes[i]->getName(); - } + // Get all standard skeleton joints from the preview avatar. + LLVOAvatar *av = getPreviewAvatar(); + + //Joint names and aliases come from avatar_skeleton.xml + + joint_map = av->getJointAliases(); + + std::vector cv_names, attach_names; + av->getSortedJointNames(1, cv_names); + av->getSortedJointNames(2, attach_names); + for (std::vector::iterator it = cv_names.begin(); it != cv_names.end(); ++it) + { + joint_map[*it] = *it; + } + for (std::vector::iterator it = attach_names.begin(); it != attach_names.end(); ++it) + { + joint_map[*it] = *it; + } } void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable_slm) @@ -1785,8 +1813,9 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable // this is the initial file picking. Close the whole floater // if we don't have a base model to show for high LOD. mFMP->close(); - mLoading = false; + } + mLoading = false; return; } @@ -1937,7 +1966,14 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) { mLoading = false; mModelLoader = NULL; - return; + mLodsWithParsingError.push_back(loaded_lod); + return ; + } + + mLodsWithParsingError.erase(std::remove(mLodsWithParsingError.begin(), mLodsWithParsingError.end(), loaded_lod), mLodsWithParsingError.end()); + if(mLodsWithParsingError.empty()) + { + mFMP->childEnable( "calculate_btn" ); } // Copy determinations about rig so UI will reflect them @@ -3517,24 +3553,19 @@ LLVector3 LLModelPreview::getTranslationForJointOffset(std::string joint) //----------------------------------------------------------------------------- // createPreviewAvatar //----------------------------------------------------------------------------- -void LLModelPreview::createPreviewAvatar(void) +void LLModelPreview::createPreviewAvatar( void ) { - mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion() ); - if (mPreviewAvatar) + mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR ); + if ( mPreviewAvatar ) { - mPreviewAvatar->createDrawable(&gPipeline); - mPreviewAvatar->mIsDummy = TRUE; + mPreviewAvatar->createDrawable( &gPipeline ); mPreviewAvatar->mSpecialRenderMode = 1; - mPreviewAvatar->setPositionAgent(LLVector3::zero); - mPreviewAvatar->slamPosition(); - mPreviewAvatar->updateJointLODs(); - mPreviewAvatar->updateGeometry(mPreviewAvatar->mDrawable); - mPreviewAvatar->startMotion(ANIM_AGENT_STAND); + mPreviewAvatar->startMotion( ANIM_AGENT_STAND ); mPreviewAvatar->hideSkirt(); } else { - LL_INFOS() <<"Failed to create preview avatar for upload model window"<mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions); gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mp->mUploadModelUrl, + mp->childGetValue("upload_textures").asBoolean(), + upload_skinweights, upload_joint_positions, + mp->mUploadModelUrl, true, LLHandle(), mp->getWholeModelUploadObserverHandle()); } @@ -4614,3 +4647,13 @@ void LLFloaterModelPreview::setPermissonsErrorStatus(U32 status, const std::stri LLNotificationsUtil::add("MeshUploadPermError"); } + +bool LLFloaterModelPreview::isModelLoading() +{ + if(mModelPreview) + { + return mModelPreview->mLoading; + } + return false; +} + diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 796832a9b..7585dce93 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -91,7 +91,7 @@ public: static void setUploadAmount(S32 amount) { sUploadAmount = amount; } void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); - + void setPreviewLOD(S32 lod); void onBrowseLOD(S32 lod); static void onReset(void* data); @@ -111,6 +111,8 @@ public: void enableViewOption(const std::string& option); void disableViewOption(const std::string& option); + bool isModelLoading(); + // shows warning message if agent has no permissions to upload model /*virtual*/ void onPermissionsReceived(const LLSD& result); @@ -302,6 +304,7 @@ public: static bool sIgnoreLoadedCallback; std::vector mLodsQuery; + std::vector mLodsWithParsingError; protected: diff --git a/indra/newview/llfloaterscriptdebug.cpp b/indra/newview/llfloaterscriptdebug.cpp index 83404d746..ce70602a5 100644 --- a/indra/newview/llfloaterscriptdebug.cpp +++ b/indra/newview/llfloaterscriptdebug.cpp @@ -39,6 +39,7 @@ #include "llrect.h" #include "llerror.h" #include "llstring.h" +#include "llvoavatarself.h" #include "message.h" // project include @@ -127,10 +128,28 @@ void LLFloaterScriptDebug::addScriptLine(const std::string &utf8mesg, const std: LLViewerObject* objectp = gObjectList.findObject(source_id); std::string floater_label; + // Handle /me messages. + std::string prefix = utf8mesg.substr(0, 4); + std::string message = (prefix == "/me " || prefix == "/me'") ? user_name + utf8mesg.substr(3) : utf8mesg; + if (objectp) { - objectp->setIcon(LLViewerTextureManager::getFetchedTextureFromFile("script_error.j2c", FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI)); - floater_label = llformat("%s(%.2f, %.2f)", user_name.c_str(), objectp->getPositionRegion().mV[VX], objectp->getPositionRegion().mV[VY]); + if(objectp->isHUDAttachment()) + { + if (isAgentAvatarValid()) + { + ((LLViewerObject*)gAgentAvatarp)->setIcon(LLViewerTextureManager::getFetchedTextureFromFile("script_error.j2c", FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI)); + } + } + else + { + objectp->setIcon(LLViewerTextureManager::getFetchedTextureFromFile("script_error.j2c", FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI)); + } + floater_label = llformat("%s(%.0f, %.0f, %.0f)", + user_name.c_str(), + objectp->getPositionRegion().mV[VX], + objectp->getPositionRegion().mV[VY], + objectp->getPositionRegion().mV[VZ]); } else { @@ -142,11 +161,17 @@ void LLFloaterScriptDebug::addScriptLine(const std::string &utf8mesg, const std: // add to "All" floater LLFloaterScriptDebugOutput* floaterp = LLFloaterScriptDebugOutput::getFloaterByID(LLUUID::null); - floaterp->addLine(utf8mesg, user_name, color); - + if (floaterp) + { + floaterp->addLine(message, user_name, color); + } + // add to specific script instance floater floaterp = LLFloaterScriptDebugOutput::getFloaterByID(source_id); - floaterp->addLine(utf8mesg, floater_label, color); + if (floaterp) + { + floaterp->addLine(message, floater_label, color); + } } // diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index c23cdfc96..28303be2c 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2919,7 +2919,7 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id) { LLMutexLock lock(mHeaderMutex); mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); - if (iter != mMeshHeader.end()) + if (iter != mMeshHeader.end() && mMeshHeaderSize[mesh_id] > 0) { return iter->second; } @@ -2945,10 +2945,11 @@ void LLMeshRepository::uploadModel(std::vector& data, LLVector3 S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) { - if (mThread) + if (mThread && mesh_id.notNull() && LLPrimitive::NO_LOD != lod) { + LLMutexLock lock(mThread->mHeaderMutex); LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); - if (iter != mThread->mMeshHeader.end()) + if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) { LLSD& header = iter->second; @@ -3021,9 +3022,88 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } -//static -F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) { + LLMeshCostData costs; + if (getCostData(mesh_id, costs)) + { + return costs.getEstTrisMax(); + } + else + { + return 0.f; + } +} + +F32 LLMeshRepository::getEstTrianglesStreamingCost(LLUUID mesh_id) +{ + LLMeshCostData costs; + if (getCostData(mesh_id, costs)) + { + return costs.getEstTrisForStreamingCost(); + } + else + { + return 0.f; + } +} + +// FIXME replace with calc based on LLMeshCostData +F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +{ + F32 result = 0.f; + if (mThread && mesh_id.notNull()) + { + LLMutexLock lock(mThread->mHeaderMutex); + LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); + if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + { + result = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); + } + } + if (result > 0.f) + { + LLMeshCostData data; + if (getCostData(mesh_id, data)) + { + F32 ref_streaming_cost = data.getRadiusBasedStreamingCost(radius); + F32 ref_weighted_tris = data.getRadiusWeightedTris(radius); + if (!is_approx_equal(ref_streaming_cost,result)) + { + LL_WARNS() << mesh_id << "streaming mismatch " << result << " " << ref_streaming_cost << LL_ENDL; + } + if (unscaled_value && !is_approx_equal(ref_weighted_tris,*unscaled_value)) + { + LL_WARNS() << mesh_id << "weighted_tris mismatch " << *unscaled_value << " " << ref_weighted_tris << LL_ENDL; + } + if (bytes && (*bytes != data.getSizeTotal())) + { + LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.getSizeTotal() << LL_ENDL; + } + if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.getSizeByLOD(lod))) + { + LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.getSizeByLOD(lod) << LL_ENDL; + } + } + else + { + LL_WARNS() << "getCostData failed!!!" << LL_ENDL; + } + } + return result; +} + +// FIXME replace with calc based on LLMeshCostData +//static +F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +{ + if (header.has("404") + || !header.has("lowest_lod") + || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)) + { + return 0.f; + } + F32 max_distance = 512.f; F32 dlowest = llmin(radius/0.03f, max_distance); @@ -3088,7 +3168,7 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32 } } - F32 max_area = 102932.f; //area of circle that encompasses region + F32 max_area = 102944.f; //area of circle that encompasses region (see MAINT-6559) F32 min_area = 1.f; F32 high_area = llmin(F_PI*dmid*dmid, max_area); @@ -3124,7 +3204,205 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32 return weighted_avg/mesh_triangle_budget*15000.f; } +LLMeshCostData::LLMeshCostData() +{ + mSizeByLOD.resize(4); + mEstTrisByLOD.resize(4); + std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); + std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); +} + +bool LLMeshCostData::init(const LLSD& header) +{ + mSizeByLOD.resize(4); + mEstTrisByLOD.resize(4); + + std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); + std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); + + S32 bytes_high = header["high_lod"]["size"].asInteger(); + S32 bytes_med = header["medium_lod"]["size"].asInteger(); + if (bytes_med == 0) + { + bytes_med = bytes_high; + } + S32 bytes_low = header["low_lod"]["size"].asInteger(); + if (bytes_low == 0) + { + bytes_low = bytes_med; + } + S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + if (bytes_lowest == 0) + { + bytes_lowest = bytes_low; + } + mSizeByLOD[0] = bytes_lowest; + mSizeByLOD[1] = bytes_low; + mSizeByLOD[2] = bytes_med; + mSizeByLOD[3] = bytes_high; + + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" + F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + + for (S32 i=0; i<4; i++) + { + mEstTrisByLOD[i] = llmax((F32) mSizeByLOD[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + } + + return true; +} + + +S32 LLMeshCostData::getSizeByLOD(S32 lod) +{ + if (llclamp(lod,0,3) != lod) + { + return 0; + } + return mSizeByLOD[lod]; +} + +S32 LLMeshCostData::getSizeTotal() +{ + return mSizeByLOD[0] + mSizeByLOD[1] + mSizeByLOD[2] + mSizeByLOD[3]; +} + +F32 LLMeshCostData::getEstTrisByLOD(S32 lod) +{ + if (llclamp(lod,0,3) != lod) + { + return 0.f; + } + return mEstTrisByLOD[lod]; +} + +F32 LLMeshCostData::getEstTrisMax() +{ + return llmax(mEstTrisByLOD[0], mEstTrisByLOD[1], mEstTrisByLOD[2], mEstTrisByLOD[3]); +} + +F32 LLMeshCostData::getRadiusWeightedTris(F32 radius) +{ + F32 max_distance = 512.f; + + F32 dlowest = llmin(radius/0.03f, max_distance); + F32 dlow = llmin(radius/0.06f, max_distance); + F32 dmid = llmin(radius/0.24f, max_distance); + + F32 triangles_lowest = mEstTrisByLOD[0]; + F32 triangles_low = mEstTrisByLOD[1]; + F32 triangles_mid = mEstTrisByLOD[2]; + F32 triangles_high = mEstTrisByLOD[3]; + + F32 max_area = 102944.f; //area of circle that encompasses region (see MAINT-6559) + F32 min_area = 1.f; + + F32 high_area = llmin(F_PI*dmid*dmid, max_area); + F32 mid_area = llmin(F_PI*dlow*dlow, max_area); + F32 low_area = llmin(F_PI*dlowest*dlowest, max_area); + F32 lowest_area = max_area; + + lowest_area -= low_area; + low_area -= mid_area; + mid_area -= high_area; + + high_area = llclamp(high_area, min_area, max_area); + mid_area = llclamp(mid_area, min_area, max_area); + low_area = llclamp(low_area, min_area, max_area); + lowest_area = llclamp(lowest_area, min_area, max_area); + + F32 total_area = high_area + mid_area + low_area + lowest_area; + high_area /= total_area; + mid_area /= total_area; + low_area /= total_area; + lowest_area /= total_area; + + F32 weighted_avg = triangles_high*high_area + + triangles_mid*mid_area + + triangles_low*low_area + + triangles_lowest*lowest_area; + + return weighted_avg; +} + +F32 LLMeshCostData::getEstTrisForStreamingCost() +{ + LL_DEBUGS("StreamingCost") << "tris_by_lod: " + << mEstTrisByLOD[0] << ", " + << mEstTrisByLOD[1] << ", " + << mEstTrisByLOD[2] << ", " + << mEstTrisByLOD[3] << LL_ENDL; + + F32 charged_tris = mEstTrisByLOD[3]; + F32 allowed_tris = mEstTrisByLOD[3]; + const F32 ENFORCE_FLOOR = 64.0f; + for (S32 i=2; i>=0; i--) + { + // How many tris can we have in this LOD without affecting land impact? + // - normally an LOD should be at most half the size of the previous one. + // - once we reach a floor of ENFORCE_FLOOR, don't require LODs to get any smaller. + allowed_tris = llclamp(allowed_tris/2.0f,ENFORCE_FLOOR,mEstTrisByLOD[i]); + F32 excess_tris = mEstTrisByLOD[i]-allowed_tris; + if (excess_tris>0.f) + { + LL_DEBUGS("StreamingCost") << "excess tris in lod[" << i << "] " << excess_tris << " allowed " << allowed_tris << LL_ENDL; + charged_tris += excess_tris; + } + } + return charged_tris; +} + +F32 LLMeshCostData::getRadiusBasedStreamingCost(F32 radius) +{ + return getRadiusWeightedTris(radius)/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; +} + +F32 LLMeshCostData::getTriangleBasedStreamingCost() +{ + F32 result = ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * getEstTrisForStreamingCost(); + return result; +} + + +bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) +{ + data = LLMeshCostData(); + + if (mThread && mesh_id.notNull()) + { + LLMutexLock lock(mThread->mHeaderMutex); + LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); + if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + { + const LLSD& header = iter->second; + + bool header_invalid = (header.has("404") + || !header.has("lowest_lod") + || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)); + if (!header_invalid) + { + return getCostData(header, data); + } + + return true; + } + } + return false; +} + +bool LLMeshRepository::getCostData(LLSD& header, LLMeshCostData& data) +{ + data = LLMeshCostData(); + + if (!data.init(header)) + { + return false; + } + + return true; +} LLPhysicsDecomp::LLPhysicsDecomp() : LLThread("Physics Decomp") { diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index a3e3f22d2..9226c3c00 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -452,6 +452,53 @@ protected: /*virtual*/ void multiplex_impl(state_type run_state); }; +// Params related to streaming cost, render cost, and scene complexity tracking. +class LLMeshCostData +{ +public: + LLMeshCostData(); + + bool init(const LLSD& header); + + // Size for given LOD + S32 getSizeByLOD(S32 lod); + + // Sum of all LOD sizes. + S32 getSizeTotal(); + + // Estimated triangle counts for the given LOD. + F32 getEstTrisByLOD(S32 lod); + + // Estimated triangle counts for the largest LOD. Typically this + // is also the "high" LOD, but not necessarily. + F32 getEstTrisMax(); + + // Triangle count as computed by original streaming cost + // formula. Triangles in each LOD are weighted based on how + // frequently they will be seen. + // This was called "unscaled_value" in the original getStreamingCost() functions. + F32 getRadiusWeightedTris(F32 radius); + + // Triangle count used by triangle-based cost formula. Based on + // triangles in highest LOD plus potentially partial charges for + // lower LODs depending on complexity. + F32 getEstTrisForStreamingCost(); + + // Streaming cost. This should match the server-side calculation + // for the corresponding volume. + F32 getRadiusBasedStreamingCost(F32 radius); + + // New streaming cost formula, currently only used for animated objects. + F32 getTriangleBasedStreamingCost(); + +private: + // From the "size" field of the mesh header. LOD 0=lowest, 3=highest. + std::vector mSizeByLOD; + + // Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest. + std::vector mEstTrisByLOD; +}; + class LLMeshRepository { public: @@ -466,7 +513,13 @@ public: static U32 sCacheBytesWritten; static U32 sPeakKbps; - static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + // Estimated triangle count of the largest LOD + F32 getEstTrianglesMax(LLUUID mesh_id); + F32 getEstTrianglesStreamingCost(LLUUID mesh_id); + F32 getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + static F32 getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + bool getCostData(LLUUID mesh_id, LLMeshCostData& data); + static bool getCostData(LLSD& header, LLMeshCostData& data); LLMeshRepository(); @@ -569,4 +622,7 @@ public: extern LLMeshRepository gMeshRepo; +const F32 ANIMATED_OBJECT_BASE_COST = 15.0f; +const F32 ANIMATED_OBJECT_COST_PER_KTRI = 1.5f; + #endif diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index ab3feb724..4426a2846 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -84,6 +84,8 @@ #include "llviewercontrol.h" #include "llmeshrepository.h" +#include "llvoavatarself.h" + #include // "Features" Tab @@ -92,7 +94,8 @@ BOOL LLPanelVolume::postBuild() { // Flexible Objects Parameters { - getChild("Flexible1D Checkbox Ctrl")->setCommitCallback(boost::bind(&LLPanelVolume::onCommitIsFlexible, this, _1, _2), NULL); + childSetCommitCallback("Animated Mesh Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitAnimatedMeshCheckbox, this, _1, _2), NULL); + childSetCommitCallback("Flexible1D Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitIsFlexible, this, _1, _2), NULL); childSetCommitCallback("FlexNumSections",onCommitFlexible,this); getChild("FlexNumSections")->setValidateBeforeCommit(precommitValidate); childSetCommitCallback("FlexGravity",onCommitFlexible,this); @@ -228,6 +231,11 @@ void LLPanelVolume::getState( ) { volobjp = (LLVOVolume *)objectp; } + LLVOVolume *root_volobjp = NULL; + if (root_objectp && (root_objectp->getPCode() == LL_PCODE_VOLUME)) + { + root_volobjp = (LLVOVolume *)root_objectp; + } if( !objectp ) { @@ -251,6 +259,8 @@ void LLPanelVolume::getState( ) BOOL editable = root_objectp->permModify() && !root_objectp->isPermanentEnforced(); BOOL single_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ) && LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1; + BOOL single_root_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ) && + LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1; // Select Single Message if (single_volume) @@ -340,7 +350,35 @@ void LLPanelVolume::getState( ) getChildView("Light Focus")->setEnabled(false); getChildView("Light Ambiance")->setEnabled(false); } - + + // Animated Mesh + BOOL is_animated_mesh = single_root_volume && root_volobjp && root_volobjp->isAnimatedObject(); + getChild("Animated Mesh Checkbox Ctrl")->setValue(is_animated_mesh); + BOOL enabled_animated_object_box = FALSE; + if (root_volobjp && root_volobjp == volobjp) + { + enabled_animated_object_box = single_root_volume && root_volobjp && root_volobjp->canBeAnimatedObject() && editable; +#if 0 + if (!enabled_animated_object_box) + { + LL_INFOS() << "not enabled: srv " << single_root_volume << " root_volobjp " << (bool) root_volobjp << LL_ENDL; + if (root_volobjp) + { + LL_INFOS() << " cba " << root_volobjp->canBeAnimatedObject() + << " editable " << editable << " permModify() " << root_volobjp->permModify() + << " ispermenf " << root_volobjp->isPermanentEnforced() << LL_ENDL; + } + } +#endif + if (enabled_animated_object_box && !is_animated_mesh && + root_volobjp->isAttachment() && !gAgentAvatarp->canAttachMoreAnimatedObjects()) + { + // Turning this attachment animated would cause us to exceed the limit. + enabled_animated_object_box = false; + } + } + getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(enabled_animated_object_box); + // Flexible properties BOOL is_flexible = volobjp && volobjp->isFlexible(); getChild("Flexible1D Checkbox Ctrl")->setValue(is_flexible); @@ -764,6 +802,31 @@ void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata ) self->refresh(); } +void LLPanelVolume::onCommitAnimatedMeshCheckbox(LLUICtrl *, void*) +{ + LLViewerObject* objectp = mObject; + if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME)) + { + return; + } + LLVOVolume *volobjp = (LLVOVolume *)objectp; + BOOL animated_mesh = getChild("Animated Mesh Checkbox Ctrl")->getValue(); + U32 flags = volobjp->getExtendedMeshFlags(); + U32 new_flags = flags; + if (animated_mesh) + { + new_flags |= LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + } + else + { + new_flags &= ~LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + } + if (new_flags != flags) + { + volobjp->setExtendedMeshFlags(new_flags); + } +} + void LLPanelVolume::onCommitIsFlexible(LLUICtrl *, void*) { if (mObject->flagObjectPermanent()) diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index e81f43052..76a206f74 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -67,7 +67,8 @@ public: static void onCommitLight( LLUICtrl* ctrl, void* userdata); void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata); static void onCommitFlexible( LLUICtrl* ctrl, void* userdata); - static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata); + void onCommitAnimatedMeshCheckbox(LLUICtrl* ctrl, void* userdata); + static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata); void onLightCancelColor(const LLSD& data); void onLightSelectColor(const LLSD& data); diff --git a/indra/newview/llsculptidsize.cpp b/indra/newview/llsculptidsize.cpp new file mode 100644 index 000000000..9edd78bff --- /dev/null +++ b/indra/newview/llsculptidsize.cpp @@ -0,0 +1,154 @@ +/** +* @file llsculptidsize.cpp +* @brief LLSculptIDSize class implementation +* +* $LicenseInfo:firstyear=2002&license=viewerlgpl$ +* Second Life Viewer Source Code +* 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. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llsculptidsize.h" +#include "llvovolume.h" +#include "lldrawable.h" +#include "llvoavatar.h" +//boost +#include "boost/make_shared.hpp" + +//........... + +extern LLControlGroup gSavedSettings; + +//........... + +typedef std::pair pair_iter_iter_BY_SCULPT_ID_t; + +//........... + +void _nothing_to_do_func(int) { /*nothing todo here because of the size it's a shared member*/ } + +void LLSculptIDSize::inc(const LLDrawable *pdrawable, int sz) +{ + llassert(sz >= 0); + + if (!pdrawable) return; + LLVOVolume* vvol = pdrawable->getVOVolume(); + if (!vvol) return; + if (!vvol->isAttachment()) return; + if (!vvol->getAvatar()) return; + if (vvol->getAvatar()->isSelf()) return; + LLVolume *vol = vvol->getVolume(); + if (!vol) return; + + const LLUUID &sculptId = vol->getParams().getSculptID(); + if (sculptId.isNull()) return; + + unsigned int total_size = 0; + + pair_iter_iter_BY_SCULPT_ID_t itLU = mSizeInfo.get().equal_range(sculptId); + if (itLU.first == itLU.second) + { //register + llassert(mSizeInfo.get().end() == mSizeInfo.get().find(pdrawable)); + mSizeInfo.get().insert(Info(pdrawable, sz, boost::make_shared(sz), sculptId)); + total_size = sz; + } + else + { //update + register + Info &nfo = const_cast(*itLU.first); + //calc new size + total_size = nfo.getSizeSum() + sz; + nfo.mSharedSizeSum->mSizeSum = total_size; + nfo.mSize = sz; + //update size for all LLDrwable in range of sculptId + for (pair_iter_iter_BY_SCULPT_ID_t::first_type it = itLU.first; it != itLU.second; ++it) + { + mSizeInfo.get().modify_key(mSizeInfo.project(it), boost::bind(&_nothing_to_do_func, _1)); + } + + //trying insert the LLDrawable + mSizeInfo.get().insert(Info(pdrawable, sz, nfo.mSharedSizeSum, sculptId)); + } + + static LLCachedControl render_auto_mute_byte_limit(gSavedSettings, "RenderAutoMuteByteLimit", 0U); + + if (0 != render_auto_mute_byte_limit && total_size > render_auto_mute_byte_limit) + { + pair_iter_iter_BY_SCULPT_ID_t it_eqr = mSizeInfo.get().equal_range(sculptId); + for (; it_eqr.first != it_eqr.second; ++it_eqr.first) + { + const Info &i = *it_eqr.first; + LLVOVolume *pVVol = i.mDrawable->getVOVolume(); + if (pVVol + && !pVVol->isDead() + && pVVol->isAttachment() + && !pVVol->getAvatar()->isSelf() + && LLVOVolume::NO_LOD != pVVol->getLOD() + ) + { + addToUnloaded(sculptId); + //immediately + const_cast(i.mDrawable)->unload(); + } + } + } +} + +void LLSculptIDSize::dec(const LLDrawable *pdrawable) +{ + container_BY_DRAWABLE_view::iterator it = mSizeInfo.get().find(pdrawable); + if (mSizeInfo.get().end() == it) return; + + unsigned int size = it->getSizeSum() - it->getSize(); + + if (0 == size) + { + mSizeInfo.get().erase(it->getSculptId()); + } + else + { + Info &nfo = const_cast(*it); + nfo.mSize = 0; + pair_iter_iter_BY_SCULPT_ID_t itLU = mSizeInfo.get().equal_range(it->getSculptId()); + it->mSharedSizeSum->mSizeSum = size; + for (pair_iter_iter_BY_SCULPT_ID_t::first_type it = itLU.first; it != itLU.second; ++it) + { + mSizeInfo.get().modify_key(mSizeInfo.project(it), boost::bind(&_nothing_to_do_func, _1)); + } + } +} + +void LLSculptIDSize::rem(const LLUUID &sculptId) +{ + mSizeInfo.get().erase(sculptId); +} + +void LLSculptIDSize::resetSizeSum(const LLUUID &sculptId) +{ + const pair_iter_iter_BY_SCULPT_ID_t itLU = mSizeInfo.get().equal_range(sculptId); + + if (itLU.first != itLU.second) { + itLU.first->mSharedSizeSum->mSizeSum = 0; + } + + for (pair_iter_iter_BY_SCULPT_ID_t::first_type it = itLU.first, itE = itLU.second; it != itE; ++it) + { + mSizeInfo.get().modify_key(mSizeInfo.project(it), boost::bind(&_nothing_to_do_func, _1)); + } +} diff --git a/indra/newview/llsculptidsize.h b/indra/newview/llsculptidsize.h new file mode 100644 index 000000000..87ee417b8 --- /dev/null +++ b/indra/newview/llsculptidsize.h @@ -0,0 +1,134 @@ +/** +* @file llsculptidsize.h +* @brief LLSculptIDSize class definition +* +* $LicenseInfo:firstyear=2009&license=viewerlgpl$ +* Second Life Viewer Source Code +* 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. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_LLSCULPTIDSIZE_H +#define LL_LLSCULPTIDSIZE_H + +#include "lluuid.h" + +//std +#include +//boost +#include "boost/multi_index_container.hpp" +#include "boost/multi_index/ordered_index.hpp" +#include "boost/multi_index/mem_fun.hpp" + +class LLDrawable; + + +class LLSculptIDSize +{ +public: + struct SizeSum + { + SizeSum(int size) + : mSizeSum(size) + {} + unsigned int mSizeSum; + }; + + struct Info + { + typedef boost::shared_ptr PtrSizeSum; + + Info(const LLDrawable *drawable, int size, PtrSizeSum sizeInfo, LLUUID sculptId) + : mDrawable(drawable) + , mSize(size) + , mSharedSizeSum(sizeInfo) + , mSculptId(sculptId) + {} + + const LLDrawable *mDrawable; + unsigned int mSize; + PtrSizeSum mSharedSizeSum; + LLUUID mSculptId; + + inline const LLDrawable* getPtrLLDrawable() const { return mDrawable; } + inline unsigned int getSize() const { return mSize; } + inline unsigned int getSizeSum() const { return mSharedSizeSum->mSizeSum; } + inline LLUUID getSculptId() const { return mSculptId; } + PtrSizeSum getSizeInfo() { return mSharedSizeSum; } + }; + +public: + //tags + struct tag_BY_DRAWABLE {}; + struct tag_BY_SCULPT_ID {}; + struct tag_BY_SIZE {}; + + //container + typedef boost::multi_index_container < + Info, + boost::multi_index::indexed_by < + boost::multi_index::ordered_unique< boost::multi_index::tag + , boost::multi_index::const_mem_fun + > + , boost::multi_index::ordered_non_unique + , boost::multi_index::const_mem_fun + > + , boost::multi_index::ordered_non_unique < boost::multi_index::tag + , boost::multi_index::const_mem_fun < Info, unsigned int, &Info::getSizeSum > + > + > + > container; + + //views + typedef container::index::type container_BY_DRAWABLE_view; + typedef container::index::type container_BY_SCULPT_ID_view; + typedef container::index::type container_BY_SIZE_view; + +private: + LLSculptIDSize() + {} + +public: + static LLSculptIDSize & instance() + { + static LLSculptIDSize inst; + return inst; + } + +public: + void inc(const LLDrawable *pdrawable, int sz); + void dec(const LLDrawable *pdrawable); + void rem(const LLUUID &sculptId); + + inline void addToUnloaded(const LLUUID &sculptId) { mMarkAsUnloaded.insert(sculptId); } + inline void remFromUnloaded(const LLUUID &sculptId) { mMarkAsUnloaded.erase(sculptId); } + inline bool isUnloaded(const LLUUID &sculptId) const { return mMarkAsUnloaded.end() != mMarkAsUnloaded.find(sculptId); } + inline void clearUnloaded() { mMarkAsUnloaded.clear(); } + + void resetSizeSum(const LLUUID &sculptId); + + inline const container & getSizeInfo() const { return mSizeInfo; } + +private: + container mSizeInfo; + typedef std::set std_LLUUID; + std_LLUUID mMarkAsUnloaded; +}; + +#endif diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index c12ffbf71..6fa3882ea 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -46,6 +46,7 @@ #include "llundo.h" #include "lluuid.h" #include "llvolume.h" +#include "llcontrolavatar.h" #include "message.h" #include "object_flags.h" #include "llquaternion.h" @@ -372,7 +373,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S3 //----------------------------------------------------------------------------- // Select the object, parents and children. //----------------------------------------------------------------------------- -LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(LLViewerObject* obj, BOOL add_to_end) +LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(LLViewerObject* obj, BOOL add_to_end, BOOL ignore_select_owned) { llassert( obj ); @@ -389,7 +390,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(LLViewerObject* obj, return NULL; } - if (!canSelectObject(obj)) + if (!canSelectObject(obj,ignore_select_owned)) { //make_ui_sound("UISndInvalidOp"); return NULL; @@ -662,6 +663,10 @@ bool LLSelectMgr::enableLinkObjects() new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); } } + if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable()) + { + new_value = false; + } // [RLVa:KB] - Checked: 2011-03-19 (RLVa-1.3.0f) | Modified: RLVa-0.2.0g if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!RlvActions::canStand())) ) { @@ -1216,7 +1221,7 @@ void LLSelectMgr::setGridMode(EGridMode mode) updateSelectionCenter(); } -void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &scale) +void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &scale, bool for_snap_guides) { mGridObjects.cleanupNodes(); @@ -1241,7 +1246,15 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 & } else if (mGridMode == GRID_MODE_REF_OBJECT && first_grid_object && first_grid_object->mDrawable.notNull()) { - mGridRotation = first_grid_object->getRenderRotation(); + LLSelectNode *node = mSelectedObjects->findNode(first_grid_object); + if (!for_snap_guides && node) + { + mGridRotation = node->mSavedRotation; + } + else + { + mGridRotation = first_grid_object->getRenderRotation(); + } LLVector4a min_extents(F32_MAX); LLVector4a max_extents(-F32_MAX); @@ -6708,7 +6721,6 @@ void LLSelectMgr::updateSelectionCenter() mSelectionCenterGlobal.clearVec(); mShowSelection = FALSE; mSelectionBBox = LLBBox(); - mPauseRequests.clear(); resetAgentHUDZoom(); } @@ -6716,21 +6728,7 @@ void LLSelectMgr::updateSelectionCenter() { mSelectedObjects->mSelectType = getSelectTypeForObject(object); - if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid()) - { - // Freeze avatars with a selected attachment, and all avatars with synchronized motions, if any. - LLVOAvatar* avatar = object->getAvatar(); - // It is possible that 'avatar' is NULL despite this being an attachment because of some race condition. - // In that case just don't freeze the avatar. - if (avatar) - { - avatar->pauseAllSyncedCharacters(mPauseRequests); - } - } - else - { - mPauseRequests.clear(); - } + if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid()) { @@ -6808,6 +6806,68 @@ void LLSelectMgr::updateSelectionCenter() { gEditMenuHandler = NULL; } + + pauseAssociatedAvatars(); +} + +//----------------------------------------------------------------------------- +// pauseAssociatedAvatars +// +// If the selection includes an attachment or an animated object, the +// associated avatars should pause their animations until they are no +// longer selected. +//----------------------------------------------------------------------------- +void LLSelectMgr::pauseAssociatedAvatars() +{ + mPauseRequests.clear(); + + for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); + iter != mSelectedObjects->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if (!object) + continue; + + mSelectedObjects->mSelectType = getSelectTypeForObject(object); + + if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && + isAgentAvatarValid() && object->getParent() != NULL) + { + if (object->isAnimatedObject()) + { + // Is an animated object attachment. + // Pause both the control avatar and the avatar it's attached to. + if (object->getControlAvatar()) + { + object->getControlAvatar()->pauseAllSyncedCharacters(mPauseRequests); + } + LLVOAvatar* avatar = object->getAvatar(); + if (avatar) + { + avatar->pauseAllSyncedCharacters(mPauseRequests); + } + } + else + { + object->print(); + // Is a regular attachment. Pause the avatar it's attached to. + LLVOAvatar* avatar = object->getAvatar(); + if (avatar) + { + avatar->pauseAllSyncedCharacters(mPauseRequests); + } + } + } + else + { + if (object && object->isAnimatedObject() && object->getControlAvatar()) + { + // Is a non-attached animated object. Pause the control avatar. + object->getControlAvatar()->pauseAllSyncedCharacters(mPauseRequests); + } + } + } } void LLSelectMgr::updatePointAt() @@ -7017,7 +7077,7 @@ void LLSelectMgr::validateSelection() getSelection()->applyToObjects(&func); } -BOOL LLSelectMgr::canSelectObject(LLViewerObject* object) +BOOL LLSelectMgr::canSelectObject(LLViewerObject* object, BOOL ignore_select_owned) { // Never select dead objects if (!object || object->isDead()) @@ -7030,11 +7090,14 @@ BOOL LLSelectMgr::canSelectObject(LLViewerObject* object) return TRUE; } - if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !object->permYouOwner()) || - (gSavedSettings.getBOOL("SelectMovableOnly") && (!object->permMove() || object->isPermanentEnforced()))) + if(!ignore_select_owned) { - // only select my own objects - return FALSE; + if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !object->permYouOwner()) || + (gSavedSettings.getBOOL("SelectMovableOnly") && (!object->permMove() || object->isPermanentEnforced()))) + { + // only select my own objects + return FALSE; + } } // Can't select orphans @@ -7308,10 +7371,16 @@ F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* vis if (object) { + cost += object->getStreamingCost(); + S32 bytes = 0; S32 visible = 0; - cost += object->getStreamingCost(&bytes, &visible); - + LLMeshCostData costs; + if (object->getCostData(costs)) + { + bytes = costs.getSizeTotal(); + visible = costs.getSizeByLOD(object->getLOD()); + } if (total_bytes) { *total_bytes += bytes; @@ -7337,7 +7406,9 @@ U32 LLObjectSelection::getSelectedObjectTriangleCount(S32* vcount) if (object) { - count += object->getTriangleCount(vcount); + S32 vt = 0; + count += object->getTriangleCount(&vt); + *vcount += vt; } } @@ -7466,6 +7537,31 @@ bool LLObjectSelection::applyToObjects(LLSelectedObjectFunctor* func) return result; } +bool LLObjectSelection::checkAnimatedObjectEstTris() +{ + F32 est_tris = 0; + F32 max_tris = 0; + S32 anim_count = 0; + for (root_iterator iter = root_begin(); iter != root_end(); ++iter) + { + LLViewerObject* object = (*iter)->getObject(); + if (!object) + continue; + if (object->isAnimatedObject()) + { + anim_count++; + } + est_tris += object->recursiveGetEstTrianglesMax(); + max_tris = llmax((F32)max_tris,(F32)object->getAnimatedObjectMaxTris()); + } + return anim_count==0 || est_tris <= max_tris; +} + +bool LLObjectSelection::checkAnimatedObjectLinkable() +{ + return checkAnimatedObjectEstTris(); +} + bool LLObjectSelection::applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly) { bool result = firstonly ? false : true; diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 13eb4e1db..5252c5a17 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -315,6 +315,9 @@ public: // returns TRUE is any node is currenly worn as an attachment BOOL isAttachment(); + bool checkAnimatedObjectEstTris(); + bool checkAnimatedObjectLinkable(); + // Apply functors to various subsets of the selected objects // If firstonly is FALSE, returns the AND of all apply() calls. // Else returns TRUE immediately if any apply() call succeeds (i.e. OR with early exit) @@ -432,7 +435,7 @@ public: // // *NOTE: You must hold on to the object selection handle, otherwise // the objects will be automatically deselected in 1 frame. - LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, BOOL add_to_end = FALSE); + LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, BOOL add_to_end = FALSE, BOOL ignore_select_owned = FALSE); // For when you want just a child object. LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES); @@ -504,7 +507,7 @@ public: void clearGridObjects(); void setGridMode(EGridMode mode); EGridMode getGridMode() { return mGridMode; } - void getGrid(LLVector3& origin, LLQuaternion& rotation, LLVector3 &scale); + void getGrid(LLVector3& origin, LLQuaternion& rotation, LLVector3 &scale, bool for_snap_guides = false); BOOL getTEMode() { return mTEMode; } void setTEMode(BOOL b) { mTEMode = b; } @@ -588,7 +591,7 @@ public: void validateSelection(); // returns TRUE if it is possible to select this object - BOOL canSelectObject(LLViewerObject* object); + BOOL canSelectObject(LLViewerObject* object, BOOL ignore_select_owned = FALSE); // Returns TRUE if the viewer has information on all selected objects BOOL selectGetAllRootsValid(); @@ -717,6 +720,8 @@ public: LLVector3d getSelectionCenterGlobal() const { return mSelectionCenterGlobal; } void updateSelectionCenter(); + void pauseAssociatedAvatars(); + void resetAgentHUDZoom(); void setAgentHUDZoom(F32 target_zoom, F32 current_zoom); void getAgentHUDZoom(F32 &target_zoom, F32 ¤t_zoom) const; diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 842d5a137..71b9a5dcc 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -78,22 +78,24 @@ void LLSkinningUtil::initSkinningMatrixPalette( LLVOAvatar *avatar, bool relative_to_avatar) { + LLVector4a pos = LLVector4a::getZero(); + if (relative_to_avatar) + { + pos.load3(avatar->getPosition().mV); + pos.mul(-1.f); + } + initJointNums(const_cast(skin), avatar); for (U32 j = 0; j < (U32)count; ++j) { LLJoint *joint = avatar->getJoint(skin->mJointNums[j]); if (joint) { - LLMatrix4a bind; - bind.loadu((F32*)skin->mInvBindMatrix[j].mMatrix); - if (relative_to_avatar) - { - LLMatrix4a trans = joint->getWorldMatrix(); - trans.translate_affine(avatar->getPosition() * -1.f); - mat[j].setMul(trans, bind); - } - else - mat[j].setMul(joint->getWorldMatrix(), bind); + LLMatrix4a bind; + bind.loadu((F32*)skin->mInvBindMatrix[j].mMatrix); + LLMatrix4a world = joint->getWorldMatrix(); + world.getRow<3>().add(pos); // Append pos into world matrix. + mat[j].setMul(world, bind); } else { @@ -236,6 +238,95 @@ void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar) } } +static LLTrace::BlockTimerStatHandle FTM_FACE_RIGGING_INFO("Face Rigging Info"); + +// How many copies of the same code do we need, LL? +void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face) +{ + LL_RECORD_BLOCK_TIME(FTM_FACE_RIGGING_INFO); + + if (vol_face.mJointRiggingInfoTab.needsUpdate()) + { + S32 num_verts = vol_face.mNumVertices; + if (num_verts>0 && vol_face.mWeights && (skin->mJointNames.size()>0)) + { + initJointNums(const_cast(skin), avatar); + if (vol_face.mJointRiggingInfoTab.size()==0) + { + //std::set active_joints; + //S32 active_verts = 0; + vol_face.mJointRiggingInfoTab.resize(LL_CHARACTER_MAX_ANIMATED_JOINTS); + LLJointRiggingInfoTab &rig_info_tab = vol_face.mJointRiggingInfoTab; + for (S32 i=0; i 0.0f) + { + for (U32 k=0; k<4; ++k) + { + wght[k] /= scale; + } + } + for (U32 k=0; k<4; ++k) + { + S32 joint_index = idx[k]; + if (wght[k] > 0.0f) + { + S32 joint_num = skin->mJointNums[joint_index]; + if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS) + { + rig_info_tab[joint_num].setIsRiggedTo(true); + + // FIXME could precompute these matMuls. + LLMatrix4a bind_shape; + bind_shape.loadu(skin->mBindShapeMatrix); + LLMatrix4a inv_bind; + inv_bind.loadu(skin->mInvBindMatrix[joint_index]); + LLMatrix4a mat; + mat.setMul(bind_shape, inv_bind); + LLVector4a pos_joint_space; + mat.affineTransform(pos, pos_joint_space); + pos_joint_space.mul(wght[k]); + LLVector4a *extents = rig_info_tab[joint_num].getRiggedExtents(); + update_min_max(extents[0], extents[1], pos_joint_space); + } + } + } + } + //LL_DEBUGS("RigSpammish") << "built rigging info for vf " << &vol_face + // << " num_verts " << vol_face.mNumVertices + // << " active joints " << active_joints.size() + // << " active verts " << active_verts + // << LL_ENDL; + vol_face.mJointRiggingInfoTab.setNeedsUpdate(false); + } + } + if (vol_face.mJointRiggingInfoTab.size()!=0) + { + LL_DEBUGS("RigSpammish") << "we have rigging info for vf " << &vol_face + << " num_verts " << vol_face.mNumVertices << LL_ENDL; + } + else + { + LL_DEBUGS("RigSpammish") << "no rigging info for vf " << &vol_face + << " num_verts " << vol_face.mNumVertices << LL_ENDL; + } + + } +} + // This is used for extracting rotation from a bind shape matrix that // already has scales baked in LLQuaternion LLSkinningUtil::getUnscaledQuaternion(const LLMatrix4& mat4) diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h index c57050ded..fd4643feb 100644 --- a/indra/newview/llskinningutil.h +++ b/indra/newview/llskinningutil.h @@ -30,6 +30,7 @@ class LLVOAvatar; class LLMeshSkinInfo; class LLMatrix4a; +class LLVolumeFace; namespace LLSkinningUtil { @@ -42,6 +43,7 @@ namespace LLSkinningUtil void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); void getPerVertexSkinMatrix(const F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); void initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar); + void updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face); LLQuaternion getUnscaledQuaternion(const LLMatrix4& mat4); }; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index b10192ca9..f4c4bdb97 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -59,6 +59,7 @@ #include "llvolumemgr.h" #include "llglslshader.h" #include "llviewershadermgr.h" +#include "llcontrolavatar.h" static LLTrace::BlockTimerStatHandle FTM_FRUSTUM_CULL("Frustum Culling"); static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound"); @@ -76,6 +77,8 @@ BOOL LLSpatialGroup::sNoDelete = FALSE; static F32 sLastMaxTexPriority = 1.f; static F32 sCurMaxTexPriority = 1.f; +BOOL LLSpatialPartition::sTeleportRequested = FALSE; + //BOOL LLSpatialPartition::sFreezeState = FALSE; //static counter for frame to switch LOD on @@ -737,19 +740,6 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node) } } - //clean up avatar attachment stats - LLSpatialBridge* bridge = getSpatialPartition()->asBridge(); - if (bridge) - { - if (bridge->mAvatar.notNull()) - { - bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes; - bridge->mAvatar->mAttachmentGeometryBytes = llmax(bridge->mAvatar->mAttachmentGeometryBytes, 0); - bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea; - bridge->mAvatar->mAttachmentSurfaceArea = llmax(bridge->mAvatar->mAttachmentSurfaceArea, 0.f); - } - } - clearDrawMap(); mVertexBuffer = NULL; mBufferVec.clear(); @@ -1309,7 +1299,7 @@ void LLSpatialPartition::restoreGL() void LLSpatialPartition::resetVertexBuffers() { - LLOctreeDirty dirty; + LLOctreeDirty dirty(sTeleportRequested); dirty.traverse(mOctree); } @@ -1939,7 +1929,24 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) gGL.diffuseColor4f(0,0.5f,0,1); break; default: - gGL.diffuseColor4f(1,0,1,1); + LLControlAvatar *cav = dynamic_cast(drawable->getVObj()->asAvatar()); + if (cav) + { + bool has_pos_constraint = (cav->mPositionConstraintFixup != LLVector3()); + bool has_scale_constraint = (cav->mScaleConstraintFixup != 1.0f); + if (has_pos_constraint || has_scale_constraint) + { + gGL.diffuseColor4f(1,0,0,1); + } + else + { + gGL.diffuseColor4f(0,1,0.5,1); + } + } + else + { + gGL.diffuseColor4f(1,0,1,1); // magenta + } break; } } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index cd150d017..3563d1ee4 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -438,6 +438,8 @@ public: U32 mVertexDataMask; F32 mSlopRatio; //percentage distance must change before drawables receive LOD update (default is 0.25); BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering + + static BOOL sTeleportRequested; //started to issue a teleport request }; // class for creating bridges between spatial partitions @@ -468,7 +470,6 @@ public: virtual LLCamera transformCamera(LLCamera& camera); LLDrawable* mDrawable; - LLPointer mAvatar; }; class LLCullResult diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 56da45e7e..a3ce7c158 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3069,6 +3069,7 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); + msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse); msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures); diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 52727dd6c..9112aa9fd 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -44,7 +44,7 @@ #include "llperlin.h" extern bool gShiftFrame; -extern U64 gFrameTime; +extern U64MicrosecondsImplicit gFrameTime; extern LLPipeline gPipeline; LLSurfacePatch::LLSurfacePatch() diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 19d74fcba..47e473643 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -182,7 +182,7 @@ void LLTextureBar::draw() { color = LLColor4::green4; } - else if (mImagep->getBoostLevel() > LLGLTexture::BOOST_NONE) + else if (mImagep->getBoostLevel() > LLGLTexture::BOOST_ALM) { color = LLColor4::magenta; } diff --git a/indra/newview/lluiavatar.cpp b/indra/newview/lluiavatar.cpp new file mode 100644 index 000000000..e4e266c92 --- /dev/null +++ b/indra/newview/lluiavatar.cpp @@ -0,0 +1,61 @@ +/** + * @file lluiavatar.cpp + * @brief Implementation for special dummy avatar used in some UI views + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "lluiavatar.h" +#include "llagent.h" // Get state values from here +#include "llviewerobjectlist.h" +#include "pipeline.h" +#include "llanimationstates.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" +#include "llviewerregion.h" + +LLUIAvatar::LLUIAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) : + LLVOAvatar(id, pcode, regionp) +{ + mIsDummy = TRUE; + mIsUIAvatar = true; +} + +// virtual +LLUIAvatar::~LLUIAvatar() +{ +} + +// virtual +void LLUIAvatar::initInstance() +{ + LLVOAvatar::initInstance(); + + createDrawable( &gPipeline ); + setPositionAgent(LLVector3::zero); + slamPosition(); + updateJointLODs(); + updateGeometry(mDrawable); + + mInitFlags |= 1<<3; +} diff --git a/indra/newview/lluiavatar.h b/indra/newview/lluiavatar.h new file mode 100644 index 000000000..bcdffedef --- /dev/null +++ b/indra/newview/lluiavatar.h @@ -0,0 +1,44 @@ +/** + * @file lluiavatar.h + * @brief Special dummy avatar used in some UI views + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_UIAVATAR_H +#define LL_UIAVATAR_H + +#include "llvoavatar.h" +#include "llvovolume.h" + +class LLUIAvatar: + public LLVOAvatar +{ + LOG_CLASS(LLUIAvatar); + +public: + LLUIAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); + virtual void initInstance(); // Called after construction to initialize the class. + virtual ~LLUIAvatar(); +}; + +#endif //LL_CONTROLAVATAR_H diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index c13e2d9c1..f7f8d22cb 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -138,6 +138,16 @@ bool handleStateMachineMaxTimeChanged(const LLSD& newvalue) return true; } +extern bool sInwlfPanelUpdate; +static bool handleAvatarHoverOffsetChanged(const LLSD& newvalue) +{ + if (!sInwlfPanelUpdate && isAgentAvatarValid()) + { + gAgentAvatarp->setHoverIfRegionEnabled(); + } + return true; +} + static bool handleSetShaderChanged(const LLSD& newvalue) { // changing shader level may invalidate existing cached bump maps, as the shader type determines the format of the bump map it expects - clear and repopulate the bump cache @@ -671,7 +681,9 @@ void handleHighResChanged(const LLSD& val) gSavedSettings.setBOOL("RenderUIInSnapshot", false); } +void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value); //////////////////////////////////////////////////////////////////////////// + void settings_setup_listeners() { gSavedSettings.getControl("FirstPersonAvatarVisible")->getSignal()->connect(boost::bind(&handleRenderAvatarMouselookChanged, _2)); @@ -835,7 +847,8 @@ void settings_setup_listeners() gSavedSettings.getControl("SkyUseClassicClouds")->getSignal()->connect(boost::bind(&handleCloudSettingsChanged, _2)); gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2)); gSavedSettings.getControl("AlchemyWLCloudTexture")->getSignal()->connect(boost::bind(&handleWindlightCloudChanged, _2)); - + gSavedSettings.getControl("RenderAutoMuteByteLimit")->getSignal()->connect(boost::bind(&handleRenderAutoMuteByteLimitChanged, _2)); + gSavedPerAccountSettings.getControl("AvatarHoverOffsetZ")->getCommitSignal()->connect(boost::bind(&handleAvatarHoverOffsetChanged, _2)); gSavedSettings.getControl("AscentAvatarXModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2)); gSavedSettings.getControl("AscentAvatarYModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2)); gSavedSettings.getControl("AscentAvatarZModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2)); diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index c80963db3..1b118ec63 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -361,6 +361,25 @@ void LLViewerJointAttachment::setOriginalPosition(LLVector3& position) setPosition(position); } +//----------------------------------------------------------------------------- +// getNumAnimatedObjects() +//----------------------------------------------------------------------------- +S32 LLViewerJointAttachment::getNumAnimatedObjects() const +{ + S32 count = 0; + for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); + iter != mAttachedObjects.end(); + ++iter) + { + const LLViewerObject *attached_object = *iter; + if (attached_object->isAnimatedObject()) + { + count++; + } + } + return count; +} + //----------------------------------------------------------------------------- // clampObjectPosition() //----------------------------------------------------------------------------- diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h index bb94c3678..20eb42957 100644 --- a/indra/newview/llviewerjointattachment.h +++ b/indra/newview/llviewerjointattachment.h @@ -87,6 +87,7 @@ public: S32 getGroup() const { return mGroup; } S32 getPieSlice() const { return mPieSlice; } S32 getNumObjects() const { return mAttachedObjects.size(); } + S32 getNumAnimatedObjects() const; void clampObjectPosition(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 984875ff3..4b552ca10 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6085,24 +6085,33 @@ class LLAvatarAddFriend : public view_listener_t class LLAvatarResetSkeleton: public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLVOAvatar* avatar = NULL; + LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (obj) + { + avatar = obj->getAvatar(); + } if(avatar) - { - avatar->resetSkeleton(false); - } - return true; - } + { + avatar->resetSkeleton(false); + } + return true; + } }; - class LLAvatarResetSkeletonAndAnimations : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - if (avatar) + LLVOAvatar* avatar = NULL; + LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (obj) + { + avatar = obj->getAvatar(); + } + if(avatar) { avatar->resetSkeleton(true); } @@ -6110,6 +6119,19 @@ class LLAvatarResetSkeletonAndAnimations : public view_listener_t } }; +class LLAvatarEnableResetSkeleton: public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (obj && obj->getAvatar()) + { + return true; + } + return false; + } +}; + bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection) { S32 option = LLNotification::getSelectedOption(notification, response); @@ -6901,9 +6923,10 @@ class LLAttachmentEnableDrop : public view_listener_t LLViewerJointAttachment* attachment = NULL; LLInventoryItem* item = NULL; - if (object) + // Do not enable drop if all faces of object are not enabled + if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) { - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState()); + S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); if (attachment) @@ -9511,6 +9534,7 @@ void initialize_menus() addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); addMenu(new LLObjectEnableMute(), "Avatar.EnableMute"); addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); + addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); addMenu(new LLAvatarEnableFreezeEject(), "Avatar.EnableFreezeEject"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 6255a6366..65da02e4c 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -56,6 +56,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llcallingcard.h" +#include "llcontrolavatar.h" #include "llfirstuse.h" #include "llfloaterbump.h" #include "llfloaterbuycurrency.h" @@ -4544,6 +4545,8 @@ void process_teleport_finish(LLMessageSystem* msg, void**) // Teleport is finished; it can't be cancelled now. gViewerWindow->setProgressCancelButtonVisible(FALSE); + //gPipeline.doResetVertexBuffers(true); // Animesh+ + // Do teleport effect for where you're leaving // VEFFECT: TeleportStart LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); @@ -5773,7 +5776,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) LLUUID animation_id; LLUUID uuid; S32 anim_sequence_id; - + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); //clear animation flags @@ -5859,6 +5862,72 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) } } + +void process_object_animation(LLMessageSystem *mesgsys, void **user_data) +{ + LLUUID animation_id; + LLUUID uuid; + S32 anim_sequence_id; + + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); + + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for object " << uuid << LL_ENDL; + + signaled_animation_map_t signaled_anims; + S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); + LL_DEBUGS("AnimatedObjectsNotify") << "processing object animation requests, num_blocks " << num_blocks << " uuid " << uuid << LL_ENDL; + for( S32 i = 0; i < num_blocks; i++ ) + { + mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); + mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); + signaled_anims[animation_id] = anim_sequence_id; + LL_DEBUGS("AnimatedObjectsNotify") << "added signaled_anims animation request for object " + << uuid << " animation id " << animation_id << LL_ENDL; + } + LLObjectSignaledAnimationMap::instance().getMap()[uuid] = signaled_anims; + + LLViewerObject *objp = gObjectList.findObject(uuid); + if (!objp) + { + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for unknown object " << uuid << LL_ENDL; + return; + } + + LLVOVolume *volp = dynamic_cast(objp); + if (!volp) + { + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-volume object " << uuid << LL_ENDL; + return; + } + + if (!volp->isAnimatedObject()) + { + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-animated object " << uuid << LL_ENDL; + return; + } + + volp->updateControlAvatar(); + LLControlAvatar *avatarp = volp->getControlAvatar(); + if (!avatarp) + { + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation request for object with no control avatar, ignoring " << uuid << LL_ENDL; + return; + } + + if (!avatarp->mPlaying) + { + avatarp->mPlaying = true; + //if (!avatarp->mRootVolp->isAnySelected()) + { + avatarp->updateVolumeGeom(); + avatarp->mRootVolp->recursiveMarkForUpdate(TRUE); + } + } + + avatarp->updateAnimations(); +} + + void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) { LLUUID uuid; diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index ea3275cd7..2abbfbd69 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -102,6 +102,7 @@ void process_health_message(LLMessageSystem *mesgsys, void **user_data); void process_sim_stats(LLMessageSystem *mesgsys, void **user_data); void process_shooter_agent_hit(LLMessageSystem* msg, void** user_data); void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data); +void process_object_animation(LLMessageSystem *mesgsys, void **user_data); void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data); void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data); void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 15e194239..a050c5278 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewerobject.cpp * @brief Base class for viewer objects * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * 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. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,6 +59,7 @@ #include "llbbox.h" #include "llbox.h" #include "llcylinder.h" +#include "llcontrolavatar.h" #include "lldrawable.h" #include "llface.h" #include "llfloaterproperties.h" @@ -68,6 +69,7 @@ #include "llselectmgr.h" #include "llrendersphere.h" #include "lltooldraganddrop.h" +#include "lluiavatar.h" #include "llviewercamera.h" #include "llviewertexturelist.h" #include "llviewerinventory.h" @@ -98,7 +100,7 @@ #include "llvowlsky.h" #include "llmanip.h" #include "llmediaentry.h" - +#include "llmeshrepository.h" // [RLVa:KB] #include "rlvhandler.h" #include "rlvlocks.h" @@ -107,7 +109,7 @@ //#define DEBUG_UPDATE_TYPE BOOL LLViewerObject::sVelocityInterpolate = TRUE; -BOOL LLViewerObject::sPingInterpolate = TRUE; +BOOL LLViewerObject::sPingInterpolate = TRUE; U32 LLViewerObject::sNumZombieObjects = 0; S32 LLViewerObject::sNumObjects = 0; @@ -122,15 +124,27 @@ BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE F64Seconds LLViewerObject::sMaxUpdateInterpolationTime(3.0); // For motion interpolation: after X seconds with no updates, don't predict object motion F64Seconds LLViewerObject::sPhaseOutUpdateInterpolationTime(2.0); // For motion interpolation: after Y seconds with no updates, taper off motion prediction +std::map LLViewerObject::sObjectDataMap; + +// The maximum size of an object extra parameters binary (packed) block +#define MAX_OBJECT_PARAMS_SIZE 1024 + +// At 45 Hz collisions seem stable and objects seem +// to settle down at a reasonable rate. +// JC 3/18/2003 + +const F32 PHYSICS_TIMESTEP = 1.f / 45.f; +const U32 MAX_INV_FILE_READ_FAILS = 25; +const S32 MAX_OBJECT_BINARY_DATA_SIZE = 60 + 16; static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object"); // static -LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) +LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, S32 flags) { LLViewerObject *res = NULL; LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT); - + switch (pcode) { case LL_PCODE_VOLUME: @@ -145,7 +159,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco gAgentAvatarp->initInstance(); gAgentWearables.setAvatarObject(gAgentAvatarp); } - else + else { if (isAgentAvatarValid()) { @@ -154,9 +168,21 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco } res = gAgentAvatarp; } + else if (flags & CO_FLAG_CONTROL_AVATAR) + { + LLControlAvatar *control_avatar = new LLControlAvatar(id, pcode, regionp); + control_avatar->initInstance(); + res = control_avatar; + } + else if (flags & CO_FLAG_UI_AVATAR) + { + LLUIAvatar *ui_avatar = new LLUIAvatar(id, pcode, regionp); + ui_avatar->initInstance(); + res = ui_avatar; + } else { - LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp); + LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp); avatar->initInstance(); res = avatar; } @@ -224,6 +250,9 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mRenderMedia(FALSE), mBestUpdatePrecision(0), mText(), + + mHudTextColor(LLColor4::white), + mControlAvatar(NULL), mLastInterpUpdateSecs(0.f), mLastMessageUpdateSecs(0.f), mLatestRecvPacketID(0), @@ -234,9 +263,10 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mPixelArea(1024.f), mInventory(NULL), mInventorySerialNum(0), - mRegionp( regionp ), - mInventoryPending(FALSE), + mInvRequestState(INVENTORY_REQUEST_STOPPED), + mInvRequestXFerId(0), mInventoryDirty(FALSE), + mRegionp(regionp), mDead(FALSE), mOrphaned(FALSE), mUserSelected(FALSE), @@ -247,7 +277,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mRotTime(0.f), mAngularVelocityRot(), mPreviousRotation(), - mState(0), + mAttachmentState(0), mMedia(NULL), mClickAction(0), mObjectCost(0), @@ -320,7 +350,7 @@ LLViewerObject::~LLViewerObject() for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; mNameValuePairs.clear(); - + delete[] mData; mData = NULL; @@ -338,18 +368,18 @@ void LLViewerObject::deleteTEImages() { delete[] mTEImages; mTEImages = NULL; - + if (mTENormalMaps != NULL) { delete[] mTENormalMaps; mTENormalMaps = NULL; } - + if (mTESpecularMaps != NULL) { delete[] mTESpecularMaps; mTESpecularMaps = NULL; - } + } } void LLViewerObject::markDead() @@ -357,7 +387,7 @@ void LLViewerObject::markDead() if (!mDead) { //LL_INFOS() << "Marking self " << mLocalID << " as dead." << LL_ENDL; - + // if (isSelected()) { @@ -372,20 +402,30 @@ void LLViewerObject::markDead() // // Root object of this hierarchy unlinks itself. - LLVOAvatar *av = getAvatarAncestor(); if (getParent()) { ((LLViewerObject *)getParent())->removeChild(this); } LLUUID mesh_id; - if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id)) { - // This case is needed for indirectly attached mesh objects. - av->resetJointsOnDetach(mesh_id); + LLVOAvatar *av = getAvatar(); + if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id)) + { + // This case is needed for indirectly attached mesh objects. + av->updateAttachmentOverrides(); + } + } + if (getControlAvatar()) + { + unlinkControlAvatar(); } // Mark itself as dead mDead = TRUE; + if(mRegionp) + { + mRegionp->removeFromCreatedList(getLocalID()); + } gObjectList.cleanupReferences(this); LLViewerObject *childp; @@ -400,7 +440,7 @@ void LLViewerObject::markDead() } else { - // make sure avatar is no longer parented, + // make sure avatar is no longer parented, // so we can properly set it's position childp->setDrawableParent(NULL); ((LLVOAvatar*)childp)->getOffObject(); @@ -475,8 +515,8 @@ void LLViewerObject::dump() const LL_INFOS() << "PositionAgent: " << getPositionAgent() << LL_ENDL; LL_INFOS() << "PositionGlobal: " << getPositionGlobal() << LL_ENDL; LL_INFOS() << "Velocity: " << getVelocity() << LL_ENDL; - if (mDrawable.notNull() && - mDrawable->getNumFaces() && + if (mDrawable.notNull() && + mDrawable->getNumFaces() && mDrawable->getFace(0)) { LLFacePool *poolp = mDrawable->getFace(0)->getPool(); @@ -535,6 +575,8 @@ void LLViewerObject::initVOClasses() LLVOGrass::initClass(); LLVOWater::initClass(); LLVOVolume::initClass(); + + initObjectDataMap(); } void LLViewerObject::cleanupVOClasses() @@ -544,6 +586,118 @@ void LLViewerObject::cleanupVOClasses() LLVOTree::cleanupClass(); LLVOAvatar::cleanupClass(); LLVOVolume::cleanupClass(); + + sObjectDataMap.clear(); +} + +//object data map for compressed && !OUT_TERSE_IMPROVED +//static +void LLViewerObject::initObjectDataMap() +{ + U32 count = 0; + + sObjectDataMap["ID"] = count; //full id //LLUUID + count += sizeof(LLUUID); + + sObjectDataMap["LocalID"] = count; //U32 + count += sizeof(U32); + + sObjectDataMap["PCode"] = count; //U8 + count += sizeof(U8); + + sObjectDataMap["State"] = count; //U8 + count += sizeof(U8); + + sObjectDataMap["CRC"] = count; //U32 + count += sizeof(U32); + + sObjectDataMap["Material"] = count; //U8 + count += sizeof(U8); + + sObjectDataMap["ClickAction"] = count; //U8 + count += sizeof(U8); + + sObjectDataMap["Scale"] = count; //LLVector3 + count += sizeof(LLVector3); + + sObjectDataMap["Pos"] = count; //LLVector3 + count += sizeof(LLVector3); + + sObjectDataMap["Rot"] = count; //LLVector3 + count += sizeof(LLVector3); + + sObjectDataMap["SpecialCode"] = count; //U32 + count += sizeof(U32); + + sObjectDataMap["Owner"] = count; //LLUUID + count += sizeof(LLUUID); + + sObjectDataMap["Omega"] = count; //LLVector3, when SpecialCode & 0x80 is set + count += sizeof(LLVector3); + + //ParentID is after Omega if there is Omega, otherwise is after Owner + sObjectDataMap["ParentID"] = count;//U32, when SpecialCode & 0x20 is set + count += sizeof(U32); + + //------- + //The rest items are not included here + //------- +} + +//static +void LLViewerObject::unpackVector3(LLDataPackerBinaryBuffer* dp, LLVector3& value, std::string name) +{ + dp->shift(sObjectDataMap[name]); + dp->unpackVector3(value, name.c_str()); + dp->reset(); +} + +//static +void LLViewerObject::unpackUUID(LLDataPackerBinaryBuffer* dp, LLUUID& value, std::string name) +{ + dp->shift(sObjectDataMap[name]); + dp->unpackUUID(value, name.c_str()); + dp->reset(); +} + +//static +void LLViewerObject::unpackU32(LLDataPackerBinaryBuffer* dp, U32& value, std::string name) +{ + dp->shift(sObjectDataMap[name]); + dp->unpackU32(value, name.c_str()); + dp->reset(); +} + +//static +void LLViewerObject::unpackU8(LLDataPackerBinaryBuffer* dp, U8& value, std::string name) +{ + dp->shift(sObjectDataMap[name]); + dp->unpackU8(value, name.c_str()); + dp->reset(); +} + +//static +U32 LLViewerObject::unpackParentID(LLDataPackerBinaryBuffer* dp, U32& parent_id) +{ + dp->shift(sObjectDataMap["SpecialCode"]); + U32 value; + dp->unpackU32(value, "SpecialCode"); + + parent_id = 0; + if(value & 0x20) + { + S32 offset = sObjectDataMap["ParentID"]; + if(!(value & 0x80)) + { + offset -= sizeof(LLVector3); + } + + dp->shift(offset); + dp->unpackU32(parent_id, "ParentID"); + } + dp->reset(); + + return parent_id; } // Replaces all name value pairs with data from \n delimited list @@ -570,6 +724,37 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list) } } +BOOL LLViewerObject::isAnySelected() const +{ + bool any_selected = isSelected(); + for (child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + const LLViewerObject* child = *iter; + any_selected = any_selected || child->isSelected(); + } + return any_selected; +} + +void LLViewerObject::setSelected(BOOL sel) +{ + mUserSelected = sel; + static const LLCachedControl use_new_target_omega ("UseNewTargetOmegaCode", true); + if(use_new_target_omega) + { + resetRot(); + } + else + { + mRotTime = 0.f; + } + + if (!sel) + { + setAllTESelected(false); + } +} + // This method returns true if the object is over land owned by the // agent. bool LLViewerObject::isReturnable() @@ -578,7 +763,7 @@ bool LLViewerObject::isReturnable() { return false; } - + // [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a // Block if: @rez=n restricted and owned by us or a group *or* @unsit=n restricted and being sat on by us if ( (rlv_handler_t::isEnabled()) && @@ -598,19 +783,19 @@ bool LLViewerObject::isReturnable() } bool result = (mRegionp && mRegionp->objectIsReturnable(getPositionRegion(), boxes)) ? 1 : 0; - + if ( !result ) - { + { //Get list of neighboring regions relative to this vo's region std::vector uniqueRegions; mRegionp->getNeighboringRegions( uniqueRegions ); - + //Build aabb's - for root and all children std::vector returnables; typedef std::vector::iterator RegionIt; RegionIt regionStart = uniqueRegions.begin(); RegionIt regionEnd = uniqueRegions.end(); - + for (; regionStart != regionEnd; ++regionStart ) { LLViewerRegion* pTargetRegion = *regionStart; @@ -620,26 +805,26 @@ bool LLViewerObject::isReturnable() //Add it's children for (child_list_t::iterator iter = mChildList.begin(); iter != mChildList.end(); iter++) { - LLViewerObject* pChild = *iter; + LLViewerObject* pChild = *iter; buildReturnablesForChildrenVO( returnables, pChild, pTargetRegion ); } - } - - //TBD#Eventually create a region -> box list map + } + + //TBD#Eventually create a region -> box list map typedef std::vector::iterator ReturnablesIt; ReturnablesIt retCurrentIt = returnables.begin(); ReturnablesIt retEndIt = returnables.end(); - + for ( ; retCurrentIt !=retEndIt; ++retCurrentIt ) { boxes.clear(); LLViewerRegion* pRegion = (*retCurrentIt).pRegion; - boxes.push_back( (*retCurrentIt).box ); + boxes.push_back( (*retCurrentIt).box ); bool retResult = pRegion && pRegion->childrenObjectReturnable( boxes ) && pRegion->canManageEstate(); if ( retResult ) - { + { result = true; break; } @@ -654,9 +839,9 @@ void LLViewerObject::buildReturnablesForChildrenVO( std::vectormChildList.begin(); iter != pChild->mChildList.end(); iter++) { @@ -667,20 +852,20 @@ void LLViewerObject::buildReturnablesForChildrenVO( std::vector& returnables, LLViewerObject* pChild, LLViewerRegion* pTargetRegion ) { - + LLVector3 targetRegionPos; - targetRegionPos.setVec( pChild->getPositionGlobal() ); - - LLBBox childBBox = LLBBox( targetRegionPos, pChild->getRotationRegion(), pChild->getScale() * -0.5f, - pChild->getScale() * 0.5f).getAxisAligned(); - + targetRegionPos.setVec( pChild->getPositionGlobal() ); + + LLBBox childBBox = LLBBox( targetRegionPos, pChild->getRotationRegion(), pChild->getScale() * -0.5f, + pChild->getScale() * 0.5f).getAxisAligned(); + LLVector3 edgeA = targetRegionPos + childBBox.getMinLocal(); LLVector3 edgeB = targetRegionPos + childBBox.getMaxLocal(); - + LLVector3d edgeAd, edgeBd; edgeAd.setVec(edgeA); edgeBd.setVec(edgeB); - + //Only add the box when either of the extents are in a neighboring region if ( pTargetRegion->pointInRegionGlobal( edgeAd ) || pTargetRegion->pointInRegionGlobal( edgeBd ) ) { @@ -709,7 +894,7 @@ BOOL LLViewerObject::setParent(LLViewerObject* parent) { if (mParent != parent) { - LLViewerObject* old_parent = (LLViewerObject*)mParent ; + LLViewerObject* old_parent = (LLViewerObject*)mParent ; BOOL ret = LLPrimitive::setParent(parent); if (ret && old_parent && parent) { @@ -730,7 +915,7 @@ void LLViewerObject::addChild(LLViewerObject *childp) return; } } - + if (!isAvatar()) { // propagate selection properties @@ -740,9 +925,18 @@ void LLViewerObject::addChild(LLViewerObject *childp) if (childp->setParent(this)) { mChildList.push_back(childp); + childp->afterReparent(); } } +void LLViewerObject::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent) +{ +} + +void LLViewerObject::afterReparent() +{ +} + void LLViewerObject::removeChild(LLViewerObject *childp) { for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) @@ -758,12 +952,12 @@ void LLViewerObject::removeChild(LLViewerObject *childp) if(childp->getParent() == this) { - childp->setParent(NULL); + childp->setParent(NULL); } break; } } - + if (childp->isSelected()) { LLSelectMgr::getInstance()->deselectObjectAndFamily(childp); @@ -850,8 +1044,8 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) return FALSE ; } LLDrawable* old_parent = mDrawable->mParent; - mDrawable->mParent = parentp; - + mDrawable->mParent = parentp; + if (parentp && mDrawable->isActive()) { parentp->makeActive(); @@ -873,7 +1067,7 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) mDrawable->movePartition(); }*/ } - + return ret; } @@ -901,7 +1095,7 @@ void LLViewerObject::hideExtraDisplayItems( BOOL hidden ) U32 LLViewerObject::checkMediaURL(const std::string &media_url) { - U32 retval = (U32)0x0; + U32 retval = (U32)0x0; if (!mMedia && !media_url.empty()) { retval |= MEDIA_URL_ADDED; @@ -917,23 +1111,41 @@ U32 LLViewerObject::checkMediaURL(const std::string &media_url) retval |= MEDIA_URL_REMOVED; delete mMedia; mMedia = NULL; - } - else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. - { - /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && - LLTextureEntry::getVersionFromMediaVersionString(media_url) == - LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) + } + else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. + { + /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && + LLTextureEntry::getVersionFromMediaVersionString(media_url) == + LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) */ - { - // If the media URL is different and WE were not the one who - // changed it, mark dirty. - retval |= MEDIA_URL_UPDATED; - } - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - } - } - return retval; + { + // If the media URL is different and WE were not the one who + // changed it, mark dirty. + retval |= MEDIA_URL_UPDATED; + } + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + } + } + return retval; +} + +//extract spatial information from object update message +//return parent_id +//static +U32 LLViewerObject::extractSpatialExtents(LLDataPackerBinaryBuffer *dp, LLVector3& pos, LLVector3& scale, LLQuaternion& rot) +{ + U32 parent_id = 0; + LLViewerObject::unpackParentID(dp, parent_id); + + LLViewerObject::unpackVector3(dp, scale, "Scale"); + LLViewerObject::unpackVector3(dp, pos, "Pos"); + + LLVector3 vec; + LLViewerObject::unpackVector3(dp, vec, "Rot"); + rot.unpackFromVector3(vec); + + return parent_id; } U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, @@ -943,7 +1155,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, LLDataPacker *dp) { U32 retval = 0x0; - + // If region is removed from the list it is also deleted. if (!LLWorld::instance().isRegionListed(mRegionp)) { @@ -952,14 +1164,15 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } // Coordinates of objects on simulators are region-local. - U64 region_handle; - mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); + U64 region_handle = 0; + if(mesgsys != NULL) { + mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); if(regionp != mRegionp && regionp && mRegionp)//region cross { - //this is the redundant position and region update, but it is necessary in case the viewer misses the following + //this is the redundant position and region update, but it is necessary in case the viewer misses the following //position and region update messages from sim. //this redundant update should not cause any problems. LLVector3 delta_pos = mRegionp->getOriginAgent() - regionp->getOriginAgent(); @@ -968,10 +1181,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } else { + if(regionp != mRegionp) + { + if(mRegionp) + { + mRegionp->removeFromCreatedList(getLocalID()); + } + if(regionp) + { + regionp->addToCreatedList(getLocalID()); + } + } mRegionp = regionp ; } - } - + } + if (!mRegionp) { U32 x, y; @@ -984,10 +1208,10 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, F32 time_dilation = 1.f; if(mesgsys != NULL) { - U16 time_dilation16; - mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); - time_dilation = ((F32) time_dilation16) / 65535.f; - mRegionp->setTimeDilation(time_dilation); + U16 time_dilation16; + mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); + time_dilation = ((F32) time_dilation16) / 65535.f; + mRegionp->setTimeDilation(time_dilation); } // this will be used to determine if we've really changed position @@ -1016,6 +1240,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, parent_id = cur_parentp->mLocalID; } + if (!dp) { switch(update_type) @@ -1047,7 +1272,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num ); - mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); + mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num ); mTotalCRC = crc; @@ -1078,8 +1303,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mFlags |= flags; U8 state; - mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); - mState = state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num); + mAttachmentState = state; // ...new objects that should come in selected need to be added to the selected list mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); @@ -1121,17 +1346,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Setup object text if (!mText) { - mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); - mText->setFont(LLFontGL::getFontSansSerif()); - mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); - mText->setMaxLines(-1); - mText->setSourceObject(this); - mText->setOnHUDAttachment(isHUDAttachment()); + initHudText(); } //Cache for reset on debug infodisplay toggle. mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, mHudTextString, block_num ); - + LLColor4U coloru; mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num); @@ -1149,7 +1369,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mText->setObjectText(mHudTextString); } // [/RLVa:KB] - + setChanged(MOVED | SILHOUETTE); } else if (mText.notNull()) @@ -1160,8 +1380,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, std::string media_url; mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num); - retval |= checkMediaURL(media_url); - + retval |= checkMediaURL(media_url); + // // Unpack particle system data // @@ -1237,7 +1457,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U8 state; dp->unpackU8(state, "State"); - mState = state; + mAttachmentState = state; switch(update_type) { @@ -1298,7 +1518,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { gFloaterTools->dirty(); } - + dp->unpackU32(crc, "CRC"); mTotalCRC = crc; dp->unpackU8(material, "Material"); @@ -1403,12 +1623,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mText = NULL; } - std::string media_url; + std::string media_url; if (value & 0x200) { dp->unpackString(media_url, "MediaURL"); } - retval |= checkMediaURL(media_url); + retval |= checkMediaURL(media_url); // // Unpack particle system data @@ -1421,7 +1641,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { deleteParticleSource(); } - + // Mark all extra parameters not used std::map::iterator iter; for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) @@ -1477,13 +1697,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Preload these five flags for every object. // Finer shades require the object to be selected, and the selection manager // stores the extended permission info. - U32 flags; - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); - // keep local flags and overwrite remote-controlled flags - mFlags = (mFlags & FLAGS_LOCAL) | flags; - - // ...new objects that should come in selected need to be added to the selected list - mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + if(mesgsys != NULL) + { + U32 flags; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); + loadFlags(flags); + } } break; @@ -1491,7 +1710,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, break; } } - // // Fix object parenting. // @@ -1511,10 +1729,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { // No parent now, new parent in message -> attach to that parent if possible LLUUID parent_uuid; - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + + if(mesgsys != NULL) + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort()); + } + else + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + mRegionp->getHost().getAddress(), + mRegionp->getHost().getPort()); + } LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid); @@ -1525,7 +1754,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { static std::map state_map; std::map::iterator it = state_map.find(getID()); - + if(it != state_map.end() && (!it->second && sent_parentp)) { it->second = sent_parentp != NULL; @@ -1544,7 +1773,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, this->removeChild(sent_parentp); sent_parentp->setDrawableParent(NULL); } - + if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead()) { if (((LLViewerObject*)sent_parentp)->isAvatar()) @@ -1589,7 +1818,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, if ( (rlv_handler_t::isEnabled()) && (sent_parentp->isAvatar()) && (sent_parentp->getID() == gAgent.getID()) ) { // Rezzed object that's being worn as an attachment (we're assuming this will be due to llAttachToAvatar()) - S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getState()); + S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getAttachmentState()); if (gRlvAttachmentLocks.isLockedAttachmentPoint(idxAttachPt, RLV_LOCK_ADD)) { // If this will end up on an "add locked" attachment point then treat the attach as a user action @@ -1616,7 +1845,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { sent_parentp->addChild(this); } - + // Show particles, icon and HUD hideExtraDisplayItems( FALSE ); @@ -1628,11 +1857,20 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // No corresponding viewer object for the parent, put the various // pieces on the orphan list. // - + //parent_id - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); - + U32 ip, port; + + if(mesgsys != NULL) + { + ip = mesgsys->getSenderIP(); + port = mesgsys->getSenderPort(); + } + else + { + ip = mRegionp->getHost().getAddress(); + port = mRegionp->getHost().getPort(); + } gObjectList.orphanize(this, parent_id, ip, port); // Hide particles, icon and HUD @@ -1670,12 +1908,23 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, else { LLUUID parent_uuid; - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + + if(mesgsys != NULL) + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, gMessageSystem->getSenderIP(), gMessageSystem->getSenderPort()); + } + else + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + mRegionp->getHost().getAddress(), + mRegionp->getHost().getPort()); + } sent_parentp = gObjectList.findObject(parent_uuid); - + if (isAvatar()) { // This logic is meant to handle the case where a sitting avatar has reached a new sim @@ -1694,8 +1943,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // // Switching parents, but we don't know the new parent. // - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); + U32 ip, port; + + if(mesgsys != NULL) + { + ip = mesgsys->getSenderIP(); + port = mesgsys->getSenderPort(); + } + else + { + ip = mRegionp->getHost().getAddress(); + port = mRegionp->getHost().getPort(); + } // We're an orphan, flag things appropriately. gObjectList.orphanize(this, parent_id, ip, port); @@ -1779,13 +2038,13 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_rot.normQuat(); - if (sPingInterpolate) - { + if (sPingInterpolate && mesgsys != NULL) + { LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender()); if (cdp) { F32 ping_delay = 0.5f * time_dilation * ( ((F32)cdp->getPingDelay().valueInUnits()) + gFrameDTClamped); - LLVector3 diff = getVelocity() * ping_delay; + LLVector3 diff = getVelocity() * ping_delay; new_pos_parent += diff; } else @@ -1800,18 +2059,20 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // // - // If we're going to skip this message, why are we + // If we're going to skip this message, why are we // doing all the parenting, etc above? - U32 packet_id = mesgsys->getCurrentRecvPacketID(); - if (packet_id < mLatestRecvPacketID && - mLatestRecvPacketID - packet_id < 65536) + if(mesgsys != NULL) { - //skip application of this message, it's old - return retval; + U32 packet_id = mesgsys->getCurrentRecvPacketID(); + if (packet_id < mLatestRecvPacketID && + mLatestRecvPacketID - packet_id < 65536) + { + //skip application of this message, it's old + return retval; + } + mLatestRecvPacketID = packet_id; } - mLatestRecvPacketID = packet_id; - // Set the change flags for scale if (new_scale != getScale()) { @@ -1833,7 +2094,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, ||(this_update_precision > mBestUpdatePrecision)))) { mBestUpdatePrecision = this_update_precision; - + LLVector3 diff = new_pos_parent - test_pos_parent ; F32 mag_sqr = diff.magVecSquared() ; if(std::isfinite(mag_sqr)) @@ -1842,7 +2103,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } else { - LL_WARNS() << "Can not move the object/avatar to an infinite location!" << LL_ENDL ; + LL_WARNS() << "Can not move the object/avatar to an infinite location!" << LL_ENDL ; retval |= INVALID_UPDATE ; } @@ -1907,7 +2168,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } } - if ( gShowObjectUpdates ) { LLColor4 color; @@ -1928,7 +2188,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, llassert(accel_mag_sq >= 0.f); llassert(getAngularVelocity().magVecSquared() >= 0.f); - if ((MAG_CUTOFF >= vel_mag_sq) && + if ((MAG_CUTOFF >= vel_mag_sq) && (MAG_CUTOFF >= accel_mag_sq) && (MAG_CUTOFF >= getAngularVelocity().magVecSquared())) { @@ -1939,16 +2199,16 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mStatic = FALSE; } -// BUG: This code leads to problems during group rotate and any scale operation. -// Small discepencies between the simulator and viewer representations cause the -// selection center to creep, leading to objects moving around the wrong center. -// -// Removing this, however, means that if someone else drags an object you have -// selected, your selection center and dialog boxes will be wrong. It also means -// that higher precision information on selected objects will be ignored. -// -// I believe the group rotation problem is fixed. JNC 1.21.2002 -// + // BUG: This code leads to problems during group rotate and any scale operation. + // Small discepencies between the simulator and viewer representations cause the + // selection center to creep, leading to objects moving around the wrong center. + // + // Removing this, however, means that if someone else drags an object you have + // selected, your selection center and dialog boxes will be wrong. It also means + // that higher precision information on selected objects will be ignored. + // + // I believe the group rotation problem is fixed. JNC 1.21.2002 + // // Additionally, if any child is selected, need to update the dialogs and selection // center. BOOL needs_refresh = mUserSelected; @@ -1968,7 +2228,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // LLSelectMgr::getInstance()->updateSelectionCenter(); dialog_refresh_all(); - } + } // Mark update time as approx. now, with the ping delay. @@ -2003,13 +2263,13 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data, U32 block_num, S32& this_update_precision, LLVector3& new_pos_parent, LLQuaternion& new_rot, LLVector3& new_angv, LLVector3& test_pos_parent) { // Aurora Sim - //const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); + //const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); const F32 size = mRegionp->getWidth(); // Aurora Sim const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight(); const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight(); - U8 data[60+16]; // This needs to match the largest size below. + U8 data[MAX_OBJECT_PARAMS_SIZE]; // This needs to match the largest size below. #ifdef LL_BIG_ENDIAN U16 valswizzle[4]; #endif @@ -2018,7 +2278,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data LLVector4 collision_plane; S32 length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num, MAX_OBJECT_PARAMS_SIZE); switch (length) { @@ -2074,7 +2334,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2085,7 +2345,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2096,7 +2356,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data U16_to_F32(val[VZ], -size, size)); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2107,7 +2367,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data U16_to_F32(val[VZ], -size, size)); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); + htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2119,7 +2379,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2170,7 +2430,9 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data break; } - mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, mState, block_num); + U8 state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num); + mAttachmentState = state; } BOOL LLViewerObject::isActive() const @@ -2178,7 +2440,21 @@ BOOL LLViewerObject::isActive() const return TRUE; } +//load flags from cache or from message +void LLViewerObject::loadFlags(U32 flags) +{ + if(flags == (U32)(-1)) + { + return; //invalid + } + // keep local flags and overwrite remote-controlled flags + mFlags = (mFlags & FLAGS_LOCAL) | flags; + + // ...new objects that should come in selected need to be added to the selected list + mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + return; +} void LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { @@ -2219,10 +2495,10 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object // updates represents the average velocity of the last timestep, rather than the final velocity. // the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically - // + // // *TODO: should also wrap linear accel/velocity in check // to see if object is selected, instead of explicitly - // zeroing it out + // zeroing it out F32 dt = dt_seconds; F64Seconds time_since_last_update = time - mLastMessageUpdateSecs; @@ -2233,26 +2509,26 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con LLVector3 accel = getAcceleration(); LLVector3 vel = getVelocity(); - + if (sMaxUpdateInterpolationTime <= (F64Seconds)0.0) { // Old code path ... unbounded, simple interpolation if (!(accel.isExactlyZero() && vel.isExactlyZero())) { - LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; - - // region local + LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + + // region local setPositionRegion(pos + getPositionRegion()); - setVelocity(vel + accel*dt); - + setVelocity(vel + accel*dt); + // for objects that are spinning but not translating, make sure to flag them as having moved setChanged(MOVED | SILHOUETTE); } } else if (!accel.isExactlyZero() || !vel.isExactlyZero()) // object is moving { // Object is moving, and hasn't been too long since we got an update from the server - + // Calculate predicted position and velocity - LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; LLVector3 new_v = accel * dt; if (time_since_last_update > sPhaseOutUpdateInterpolationTime && @@ -2286,13 +2562,13 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con } else if (mLastInterpUpdateSecs - mLastMessageUpdateSecs > sPhaseOutUpdateInterpolationTime) { // Last update was already phased out a bit - phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / (sMaxUpdateInterpolationTime - time_since_last_interpolation); //LL_INFOS() << "Continuing motion phase out of " << (F32) phase_out << LL_ENDL; } else { // Phase out from full value - phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / (sMaxUpdateInterpolationTime - sPhaseOutUpdateInterpolationTime); //LL_INFOS() << "Starting motion phase out of " << (F32) phase_out << LL_ENDL; } @@ -2318,7 +2594,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con min_height += (0.5f * getScale().mV[VZ]); } else - { // This will put the object underground, but we can't tell if it will stop + { // This will put the object underground, but we can't tell if it will stop // at ground level or not min_height = LLWorld::getInstance()->getMinAllowedZ(this, new_pos_global); } @@ -2338,11 +2614,11 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global); if (clip_pos_global != new_pos_global) { // Was clipped, so this means we hit a edge where there is no region to enter - + //LL_INFOS() << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global) // << " from " << new_pos << LL_ENDL; new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global); - + // Stop motion and get server update for bouncing on the edge new_v.clear(); setAcceleration(LLVector3::zero); @@ -2355,11 +2631,11 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con // Set new position and velocity setPositionRegion(new_pos); - setVelocity(new_v); - + setVelocity(new_v); + // for objects that are spinning but not translating, make sure to flag them as having moved setChanged(MOVED | SILHOUETTE); - } + } // Update the last time we did anything mLastInterpUpdateSecs = time; @@ -2593,6 +2869,11 @@ void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener) } } +BOOL LLViewerObject::isInventoryPending() +{ + return mInvRequestState != INVENTORY_REQUEST_STOPPED; +} + void LLViewerObject::clearInventoryListeners() { for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer()); @@ -2631,7 +2912,7 @@ void LLViewerObject::requestInventory() void LLViewerObject::fetchInventoryFromServer() { - if (!mInventoryPending) + if (!isInventoryPending()) { delete mInventory; LLMessageSystem* msg = gMessageSystem; @@ -2644,14 +2925,248 @@ void LLViewerObject::fetchInventoryFromServer() msg->sendReliable(mRegionp->getHost()); // this will get reset by dirtyInventory or doInventoryCallback - mInventoryPending = TRUE; + mInvRequestState = INVENTORY_REQUEST_PENDING; } } +LLControlAvatar *LLViewerObject::getControlAvatar() +{ + return getRootEdit()->mControlAvatar.get(); +} + +LLControlAvatar *LLViewerObject::getControlAvatar() const +{ + return getRootEdit()->mControlAvatar.get(); +} + +// Manage the control avatar state of a given object. +// Any object can be flagged as animated, but for performance reasons +// we don't want to incur the overhead of managing a control avatar +// unless this would have some user-visible consequence. That is, +// there should be at least one rigged mesh in the linkset. Operations +// that change the state of a linkset, such as linking or unlinking +// prims, can also mean that a control avatar needs to be added or +// removed. At the end, if there is a control avatar, we make sure +// that its animation state is current. +void LLViewerObject::updateControlAvatar() +{ + LLViewerObject *root = getRootEdit(); + bool is_animated_object = root->isAnimatedObject(); + bool has_control_avatar = getControlAvatar(); + if (!is_animated_object && !has_control_avatar) + { + return; + } + + bool should_have_control_avatar = false; + if (is_animated_object) + { + bool any_rigged_mesh = root->isRiggedMesh(); + LLViewerObject::const_child_list_t& child_list = root->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + const LLViewerObject* child = *iter; + any_rigged_mesh = any_rigged_mesh || child->isRiggedMesh(); + } + should_have_control_avatar = is_animated_object && any_rigged_mesh; + } + + if (should_have_control_avatar && !has_control_avatar) + { + std::string vobj_name = llformat("Vol%p", root); + LL_DEBUGS("AnimatedObjects") << vobj_name << " calling linkControlAvatar()" << LL_ENDL; + root->linkControlAvatar(); + } + if (!should_have_control_avatar && has_control_avatar) + { + std::string vobj_name = llformat("Vol%p", root); + LL_DEBUGS("AnimatedObjects") << vobj_name << " calling unlinkControlAvatar()" << LL_ENDL; + root->unlinkControlAvatar(); + } + if (getControlAvatar()) + { + getControlAvatar()->updateAnimations(); + if (isSelected()) + { + LLSelectMgr::getInstance()->pauseAssociatedAvatars(); + } + } +} + +void LLViewerObject::print() +{ + if (!mChildList.size()) + return; + LL_INFOS() << "==============" << LL_ENDL; + LL_INFOS() << mID << LL_ENDL; + LL_INFOS() << "isAvatar() " << isAvatar() << LL_ENDL; + LL_INFOS() << " mOwnerID " << mOwnerID << LL_ENDL; + LL_INFOS() << " mRegionp " << std::hex << mRegionp << std::dec << LL_ENDL; + if (mRegionp) + { + LL_INFOS() << " getName() " << mRegionp->getName() << LL_ENDL; + LL_INFOS() << " isAlive() " << mRegionp->isAlive() << LL_ENDL; + } + LL_INFOS() << " mDead " << mDead << LL_ENDL; + LL_INFOS() << " mDrawable " << std::hex << mDrawable.get() << std::dec << LL_ENDL; + if (mDrawable) + { + LL_INFOS() << " isVisible() " << mDrawable->isVisible() << LL_ENDL; + LL_INFOS() << " getRegion() " << std::hex << mDrawable->getRegion() << std::dec << LL_ENDL; + if (mDrawable->getRegion()) + { + LL_INFOS() << " getRegion() " << mDrawable->getRegion()->getName() << LL_ENDL; + } + LL_INFOS() << " isRoot() " << mDrawable->isRoot() << LL_ENDL; + LL_INFOS() << " isDead() " << mDrawable->isDead() << LL_ENDL; + LL_INFOS() << " isNew() " << mDrawable->isNew() << LL_ENDL; + LL_INFOS() << " isUnload() " << mDrawable->isUnload() << LL_ENDL; + LL_INFOS() << " isLight() " << mDrawable->isLight() << LL_ENDL; + LL_INFOS() << " getSpatialGroup() " << mDrawable->getSpatialGroup() << LL_ENDL; + } + LL_INFOS() << " mOrphaned " << mOrphaned << LL_ENDL; + LL_INFOS() << " isAttachment() " << isAttachment() << LL_ENDL; + LL_INFOS() << " isActive() " << isActive() << LL_ENDL; + LL_INFOS() << " isRiggedMesh() " << isRiggedMesh() << LL_ENDL; + LL_INFOS() << " isHUDAttachment() " << isHUDAttachment() << LL_ENDL; + LL_INFOS() << " isMesh() " << isRiggedMesh() << LL_ENDL; + LL_INFOS() << " isParticleSource() " << isRiggedMesh() << LL_ENDL; + LL_INFOS() << " isTempAttachment() " << isTempAttachment() << LL_ENDL; + LL_INFOS() << " getVObjRadius() " << getVObjRadius() << LL_ENDL; + LL_INFOS() << " getNumVertices() " << getNumVertices() << LL_ENDL; + LL_INFOS() << " getNumIndices() " << getNumIndices() << LL_ENDL; + LL_INFOS() << " isAnySelected() " << isAnySelected() << LL_ENDL; + LL_INFOS() << " isFlexible() " << isFlexible() << LL_ENDL; + LL_INFOS() << " isSculpted() " << isSculpted() << LL_ENDL; + LL_INFOS() << " mTotalCRC " << mTotalCRC << LL_ENDL; + LL_INFOS() << " mListIndex " << mListIndex << LL_ENDL; + //LL_INFOS() << " mTEImages " << mTEImages << LL_ENDL; + //LL_INFOS() << " mTENormalMaps " << mTENormalMaps << LL_ENDL; + //LL_INFOS() << " mTESpecularMaps " << mTESpecularMaps << LL_ENDL; + LL_INFOS() << " mGLName " << mGLName << LL_ENDL; + LL_INFOS() << " mbCanSelect " << mbCanSelect << LL_ENDL; + LL_INFOS() << " mFlags" << mFlags << LL_ENDL; + //LL_INFOS() << " mPhysicsShapeType " << mPhysicsShapeType << LL_ENDL; + //LL_INFOS() << " mPhysicsGravity " << mPhysicsGravity << LL_ENDL; + //LL_INFOS() << " mPhysicsFriction " << mPhysicsFriction << LL_ENDL; + //LL_INFOS() << " mPhysicsDensity " << mPhysicsDensity << LL_ENDL; + //LL_INFOS() << " mPhysicsRestitution " << mPhysicsRestitution << LL_ENDL; + //LL_INFOS() << " mCreateSelected " << mCreateSelected << LL_ENDL; + //LL_INFOS() << " mRenderMedia " << mRenderMedia << LL_ENDL; + //LL_INFOS() << " mBestUpdatePrecision " << mBestUpdatePrecision << LL_ENDL; + //LL_INFOS() << " mText" << std::hex << mText.get() << std::dec << LL_ENDL; + //LL_INFOS() << " mHudTextString " << mHudTextString << LL_ENDL; + //LL_INFOS() << " mHudTextColor " << mHudTextColor << LL_ENDL; + //LL_INFOS() << " mIcon" << std::hex << mIcon.get() << std::dec << LL_ENDL; + LL_INFOS() << " mIsNameAttachment " << mIsNameAttachment << LL_ENDL; + LL_INFOS() << " mControlAvatar " << std::hex << mControlAvatar.get() << std::dec << LL_ENDL; + LL_INFOS() << " mChildList.size() " << mChildList.size() << LL_ENDL; + LL_INFOS() << " mLastInterpUpdateSecs " << mLastInterpUpdateSecs << LL_ENDL; + LL_INFOS() << " mLastMessageUpdateSecs " << mLastMessageUpdateSecs << LL_ENDL; + LL_INFOS() << " mLatestRecvPacketID " << mLatestRecvPacketID << LL_ENDL; + //LL_INFOS() << " mData" << std::hex << mData << std::dec << LL_ENDL; + //LL_INFOS() << " mPartSourcep " << std::hex << mPartSourcep.get() << std::dec << LL_ENDL; + //LL_INFOS() << " mAudioSourcep " << std::hex << mAudioSourcep << std::dec << LL_ENDL; + //LL_INFOS() << " mAudioGain " << mAudioGain << LL_ENDL; + LL_INFOS() << " mAppAngle " << mAppAngle << LL_ENDL; + LL_INFOS() << " mPixelArea " << mPixelArea << LL_ENDL; + LL_INFOS() << " mInventory " << mInventory << LL_ENDL; + LL_INFOS() << " mInventorySerialNum " << mInventorySerialNum << LL_ENDL; + LL_INFOS() << " mInvRequestState " << mInvRequestState << LL_ENDL; + LL_INFOS() << " mInvRequestXFerId " << mInvRequestXFerId << LL_ENDL; + LL_INFOS() << " mInventoryDirty " << mInventoryDirty << LL_ENDL; + LL_INFOS() << " mUserSelected " << mUserSelected << LL_ENDL; + LL_INFOS() << " mOnActiveList " << mOnActiveList << LL_ENDL; + LL_INFOS() << " mOnMap" << mOnMap << LL_ENDL; + LL_INFOS() << " mStatic " << mStatic << LL_ENDL; + LL_INFOS() << " mNumFaces " << mNumFaces << LL_ENDL; + LL_INFOS() << " mRotTime " << mRotTime << LL_ENDL; + //LL_INFOS() << " mAngularVelocityRot " << mAngularVelocityRot << LL_ENDL; + //LL_INFOS() << " mPreviousRotation " << mPreviousRotation << LL_ENDL; + LL_INFOS() << " mAttachmentState " << mAttachmentState << LL_ENDL; + LL_INFOS() << " mClickAction " << mClickAction << LL_ENDL; + //LL_INFOS() << " mObjectCost " << mObjectCost << LL_ENDL; + //LL_INFOS() << " mLinksetCost " << mLinksetCost << LL_ENDL; + //LL_INFOS() << " mPhysicsCost " << mPhysicsCost << LL_ENDL; + //LL_INFOS() << " mLinksetPhysicsCost " << mLinksetPhysicsCost << LL_ENDL; + LL_INFOS() << " mCostStale " << mCostStale << LL_ENDL; + LL_INFOS() << " mPhysicsShapeUnknown " << mPhysicsShapeUnknown << LL_ENDL; + LL_INFOS() << " mPositionRegion " << mPositionRegion << LL_ENDL; + LL_INFOS() << " mPositionAgent " << mPositionAgent << LL_ENDL; + LL_INFOS() << " mAttachmentItemID " << mAttachmentItemID << LL_ENDL; + LL_INFOS() << " mLastUpdateType " << mLastUpdateType << LL_ENDL; + LL_INFOS() << " mLastUpdateCached " << mLastUpdateCached << LL_ENDL; + LL_INFOS() << "==============" << LL_ENDL; +} + +void LLViewerObject::linkControlAvatar() +{ + if (!getControlAvatar() && isRootEdit()) + { + LLVOVolume *volp = dynamic_cast(this); + if (!volp) + { + LL_WARNS() << "called with null or non-volume object" << LL_ENDL; + return; + } + mControlAvatar = LLControlAvatar::createControlAvatar(volp); + LL_DEBUGS("AnimatedObjects") << volp->getID() + << " created control av for " + << (S32) (1+volp->numChildren()) << " prims" << LL_ENDL; + } + LLControlAvatar *cav = getControlAvatar(); + if (cav) + { + cav->updateAttachmentOverrides(); + if (!cav->mPlaying) + { + cav->mPlaying = true; + //if (!cav->mRootVolp->isAnySelected()) + { + cav->updateVolumeGeom(); + cav->mRootVolp->recursiveMarkForUpdate(TRUE); + } + } + } + else + { + LL_WARNS() << "no control avatar found!" << LL_ENDL; + } +} + +void LLViewerObject::unlinkControlAvatar() +{ + if (getControlAvatar()) + { + getControlAvatar()->updateAttachmentOverrides(); + } + if (isRootEdit()) + { + // This will remove the entire linkset from the control avatar + if (mControlAvatar) + { + mControlAvatar->markForDeath(); + mControlAvatar = NULL; + } + } + // For non-root prims, removing from the linkset will + // automatically remove the control avatar connection. +} + +// virtual +bool LLViewerObject::isAnimatedObject() const +{ + return false; +} + struct LLFilenameAndTask { LLUUID mTaskID; std::string mFilename; + + // for sequencing in case of multiple updates + S16 mSerial; #ifdef _DEBUG static S32 sCount; LLFilenameAndTask() @@ -2687,14 +3202,22 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) return; } - msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum); LLFilenameAndTask* ft = new LLFilenameAndTask; ft->mTaskID = task_id; + // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update + msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); + + if (ft->mSerial < object->mInventorySerialNum) + { + // viewer did some changes to inventory that were not saved yet. + LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL; + object->mInventorySerialNum = ft->mSerial; + } std::string unclean_filename; msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); - + if(ft->mFilename.empty()) { LL_DEBUGS() << "Task has no inventory" << LL_ENDL; @@ -2716,22 +3239,40 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) delete ft; return; } - gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), + U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), ft->mFilename, LL_PATH_CACHE, object->mRegionp->getHost(), TRUE, &LLViewerObject::processTaskInvFile, (void**)ft, LLXferManager::HIGH_PRIORITY); + if (object->mInvRequestState == INVENTORY_XFER) + { + if (new_id > 0 && new_id != object->mInvRequestXFerId) + { + // we started new download. + gXferManager->abortRequestById(object->mInvRequestXFerId, -1); + object->mInvRequestXFerId = new_id; + } + } + else + { + object->mInvRequestState = INVENTORY_XFER; + object->mInvRequestXFerId = new_id; + } } void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) { LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data; LLViewerObject* object = NULL; - if(ft && (0 == error_code) && - (object = gObjectList.findObject(ft->mTaskID))) + + if (ft + && (0 == error_code) + && (object = gObjectList.findObject(ft->mTaskID)) + && ft->mSerial >= object->mInventorySerialNum) { + object->mInventorySerialNum = ft->mSerial; if (object->loadTaskInvFile(ft->mFilename)) { @@ -2773,9 +3314,10 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS BOOL LLViewerObject::loadTaskInvFile(const std::string& filename) { std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename); - llifstream ifs(filename_and_local_path); + llifstream ifs(filename_and_local_path.c_str()); if(ifs.good()) { + U32 fail_count = 0; char buffer[MAX_STRING]; /* Flawfinder: ignore */ // *NOTE: This buffer size is hard coded into scanf() below. char keyword[MAX_STRING]; /* Flawfinder: ignore */ @@ -2790,8 +3332,14 @@ BOOL LLViewerObject::loadTaskInvFile(const std::string& filename) while(ifs.good()) { ifs.getline(buffer, MAX_STRING); - if (sscanf(buffer, " %254s", keyword) < 1) continue; - if(0 == strcmp("inv_item", keyword)) + if (sscanf(buffer, " %254s", keyword) == EOF) /* Flawfinder: ignore */ + { + // Blank file? + LL_WARNS() << "Issue reading from file '" + << filename << "'" << LL_ENDL; + break; + } + else if(0 == strcmp("inv_item", keyword)) { LLPointer inv = new LLViewerInventoryItem; inv->importLegacyStream(ifs); @@ -2804,9 +3352,17 @@ BOOL LLViewerObject::loadTaskInvFile(const std::string& filename) inv->rename("Contents"); mInventory->push_front(inv); } + else if (fail_count >= MAX_INV_FILE_READ_FAILS) + { + LL_WARNS() << "Encountered too many unknowns while reading from file: '" + << filename << "'" << LL_ENDL; + break; + } else { - LL_WARNS() << "Unknown token in inventory file '" + // Is there really a point to continue processing? We already failing to display full inventory + fail_count++; + LL_WARNS_ONCE() << "Unknown token while reading from inventory file. Token: '" << keyword << "'" << LL_ENDL; } } @@ -2845,7 +3401,10 @@ void LLViewerObject::doInventoryCallback() mInventoryCallbacks.erase(curiter); } } - mInventoryPending = FALSE; + + // release inventory loading state + mInvRequestXFerId = 0; + mInvRequestState = INVENTORY_REQUEST_STOPPED; } void LLViewerObject::removeInventory(const LLUUID& item_id) @@ -2960,7 +3519,7 @@ LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id) rv = *it; break; } - } + } } return rv; } @@ -3015,7 +3574,7 @@ LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& ass break; } } - } + } } return rv; } @@ -3038,7 +3597,7 @@ void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent) { //volumes calculate pixel area and angle per face return; } - + LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); LLVector3 pos_agent = getRenderPosition(); @@ -3094,7 +3653,7 @@ void LLViewerObject::updateGL() void LLViewerObject::updateFaceSize(S32 idx) { - + } LLDrawable* LLViewerObject::createDrawable(LLPipeline *pipeline) @@ -3107,7 +3666,7 @@ void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped) LLPrimitive::setScale(scale); if (mDrawable.notNull()) { - //encompass completely sheared objects by taking + //encompass completely sheared objects by taking //the most extreme point possible (<1,1,0.5>) mDrawable->setRadius(LLVector3(1,1,0.5f).scaleVec(scale).magVec()); updateDrawable(damped); @@ -3151,8 +3710,17 @@ void LLViewerObject::setLinksetCost(F32 cost) { mLinksetCost = cost; mCostStale = false; - - if (isSelected()) + + BOOL needs_refresh = isSelected(); + child_list_t::iterator iter = mChildList.begin(); + while(iter != mChildList.end() && !needs_refresh) + { + LLViewerObject* child = *iter; + needs_refresh = child->isSelected(); + iter++; + } + + if (needs_refresh) { gFloaterTools->dirty(); } @@ -3173,7 +3741,7 @@ void LLViewerObject::setLinksetPhysicsCost(F32 cost) { mLinksetPhysicsCost = cost; mCostStale = false; - + if (isSelected()) { gFloaterTools->dirty(); @@ -3187,7 +3755,7 @@ F32 LLViewerObject::getObjectCost() { gObjectList.updateObjectCost(this); } - + return mObjectCost; } @@ -3207,7 +3775,7 @@ F32 LLViewerObject::getPhysicsCost() { gObjectList.updateObjectCost(this); } - + return mPhysicsCost; } @@ -3221,11 +3789,66 @@ F32 LLViewerObject::getLinksetPhysicsCost() return mLinksetPhysicsCost; } -F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +F32 LLViewerObject::recursiveGetEstTrianglesMax() const +{ + F32 est_tris = getEstTrianglesMax(); + for (child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + const LLViewerObject* child = *iter; + if (!child->isAvatar()) + { + est_tris += child->recursiveGetEstTrianglesMax(); + } + } + return est_tris; +} + +S32 LLViewerObject::getAnimatedObjectMaxTris() const +{ + S32 max_tris = 0; + if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) + { + max_tris = S32_MAX; + } + else + { + if (gAgent.getRegion()) + { + LLSD features; + gAgent.getRegion()->getSimulatorFeatures(features); + if (features.has("AnimatedObjects")) + { + max_tris = features["AnimatedObjects"]["AnimatedObjectMaxTris"].asInteger(); + } + } + } + return max_tris; +} + +F32 LLViewerObject::getEstTrianglesMax() const { return 0.f; } +F32 LLViewerObject::getEstTrianglesStreamingCost() const +{ + return 0.f; +} + +// virtual +F32 LLViewerObject::getStreamingCost() const +{ + return 0.f; +} + +// virtual +bool LLViewerObject::getCostData(LLMeshCostData& costs) const +{ + costs = LLMeshCostData(); + return false; +} + U32 LLViewerObject::getTriangleCount(S32* vcount) const { return 0; @@ -3236,6 +3859,57 @@ U32 LLViewerObject::getHighLODTriangleCount() return 0; } +U32 LLViewerObject::recursiveGetTriangleCount(S32* vcount) const +{ + S32 total_tris = getTriangleCount(vcount); + LLViewerObject::const_child_list_t& child_list = getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + LLViewerObject* childp = *iter; + if (childp) + { + total_tris += childp->getTriangleCount(vcount); + } + } + return total_tris; +} + +// This is using the stored surface area for each volume (which +// defaults to 1.0 for the case of everything except a sculpt) and +// then scaling it linearly based on the largest dimension in the +// prim's scale. Should revisit at some point. +F32 LLViewerObject::recursiveGetScaledSurfaceArea() const +{ + F32 area = 0.f; + const LLDrawable* drawable = mDrawable; + if (drawable) + { + const LLVOVolume* volume = drawable->getVOVolume(); + if (volume) + { + if (volume->getVolume()) + { + const LLVector3& scale = volume->getScale(); + area += volume->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); + } + LLViewerObject::const_child_list_t children = volume->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator child_iter = children.begin(); + child_iter != children.end(); + ++child_iter) + { + LLViewerObject* child_obj = *child_iter; + LLVOVolume *child = dynamic_cast( child_obj ); + if (child && child->getVolume()) + { + const LLVector3& scale = child->getScale(); + area += child->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); + } + } + } + } + return area; +} void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { if(mDrawable.isNull()) @@ -3246,7 +3920,7 @@ void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax size.load3(getScale().mV); newMin.setSub(center, size); newMax.setAdd(center, size); - + mDrawable->setPositionGroup(center); } @@ -3259,7 +3933,7 @@ F32 LLViewerObject::getBinRadius() diff.setSub(ext[1], ext[0]); return diff.getLength3().getF32(); } - + return getScale().magVec(); } @@ -3320,7 +3994,7 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) S32 tex_count = getNumTEs(); for (i = 0; i < tex_count; i++) { - getTEImage(i)->setBoostLevel(LLGLTexture::BOOST_SELECTED); + getTEImage(i)->setBoostLevel(LLGLTexture::BOOST_SELECTED); } if (isSculpted() && !isMesh()) @@ -3329,7 +4003,7 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) LLUUID sculpt_id = sculpt_params->getSculptTexture(); LLViewerTextureManager::getFetchedTexture(sculpt_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLGLTexture::BOOST_SELECTED); } - + if (boost_children) { for (child_list_t::iterator iter = mChildList.begin(); @@ -3438,7 +4112,7 @@ BOOL LLViewerObject::removeNVPair(const std::string& name) gMessageSystem->newMessageFast(_PREHASH_RemoveNameValuePair); gMessageSystem->nextBlockFast(_PREHASH_TaskData); gMessageSystem->addUUIDFast(_PREHASH_ID, mID); - + gMessageSystem->nextBlockFast(_PREHASH_NameValueData); gMessageSystem->addStringFast(_PREHASH_NVPair, buffer); @@ -3496,7 +4170,7 @@ void LLViewerObject::updatePositionCaches() const } const LLVector3d LLViewerObject::getPositionGlobal() const -{ +{ // If region is removed from the list it is also deleted. if(mRegionp && LLWorld::instance().isRegionListed(mRegionp)) { @@ -3505,14 +4179,14 @@ const LLVector3d LLViewerObject::getPositionGlobal() const if (isAttachment()) { position_global = gAgent.getPosGlobalFromAgent(getRenderPosition()); - } + } return position_global; } else { LLVector3d position_global(getPosition()); return position_global; - } + } } const LLVector3 &LLViewerObject::getPositionAgent() const @@ -3568,8 +4242,20 @@ const LLVector3 LLViewerObject::getRenderPosition() const { if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) { + LLControlAvatar *cav = getControlAvatar(); + if (isRoot() && cav) + { + F32 fixup; + if ( cav->hasPelvisFixup( fixup) ) + { + //Apply a pelvis fixup (as defined by the avs skin) + LLVector3 pos = mDrawable->getPositionAgent(); + pos[VZ] += fixup; + return pos; + } + } LLVOAvatar* avatar = getAvatar(); - if (avatar) + if ((avatar) && !getControlAvatar()) { return avatar->getPositionAgent(); } @@ -3593,11 +4279,11 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const const LLQuaternion LLViewerObject::getRenderRotation() const { LLQuaternion ret; - if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) + if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED) && !isAnimatedObject()) { return ret; } - + if (mDrawable.isNull() || mDrawable->isStatic()) { ret = getRotationEdit(); @@ -3613,7 +4299,7 @@ const LLQuaternion LLViewerObject::getRenderRotation() const ret = LLQuaternion(LLMatrix4(mDrawable->getWorldMatrix().getF32ptr())); } } - + return ret; } @@ -3660,7 +4346,7 @@ void LLViewerObject::setPositionAbsoluteGlobal( const LLVector3d &pos_global, BO new_pos = new_pos * ~parentp->getRotationRegion(); } LLViewerObject::setPosition(new_pos); - + if (mParent && ((LLViewerObject*)mParent)->isAvatar()) { // we have changed the position of an attachment, so we need to clamp it @@ -3697,7 +4383,7 @@ void LLViewerObject::setPosition(const LLVector3 &pos, BOOL damped) { setChanged(TRANSLATED | SILHOUETTE); } - + LLXform::setPosition(pos); updateDrawable(damped); if (isRoot()) @@ -3731,7 +4417,7 @@ void LLViewerObject::setPositionGlobal(const LLVector3d &pos_global, BOOL damped LLQuaternion invRotation = mDrawable->getRotation(); invRotation.transQuat(); - + delta_pos = delta_pos * invRotation; // *FIX: is this right? Shouldn't we be calling the @@ -3802,7 +4488,7 @@ void LLViewerObject::setPositionAgent(const LLVector3 &pos_agent, BOOL damped) setPositionRegion(pos_region, damped); } -// identical to setPositionRegion() except it checks for child-joints +// identical to setPositionRegion() except it checks for child-joints // and doesn't also move the joint-parent // TODO -- implement similar intelligence for joint-parents toward // their joint-children @@ -3821,14 +4507,14 @@ void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped) LLViewerObject::setPosition(pos_edit, damped); mPositionRegion = pos_edit; mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); - } + } } LLViewerObject* LLViewerObject::getRootEdit() const { const LLViewerObject* root = this; - while (root->mParent + while (root->mParent && !((LLViewerObject*)root->mParent)->isAvatar()) { root = (LLViewerObject*)root->mParent; @@ -3965,10 +4651,10 @@ void LLViewerObject::setNumTEs(const U8 num_tes) { LLPointer *new_images; new_images = new LLPointer[num_tes]; - + LLPointer *new_normmaps; new_normmaps = new LLPointer[num_tes]; - + LLPointer *new_specmaps; new_specmaps = new LLPointer[num_tes]; for (i = 0; i < num_tes; i++) @@ -3994,7 +4680,7 @@ void LLViewerObject::setNumTEs(const U8 num_tes) } deleteTEImages(); - + mTEImages = new_images; mTENormalMaps = new_normmaps; mTESpecularMaps = new_specmaps; @@ -4095,14 +4781,14 @@ void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry) const LLUUID& image_id = getTE(te)->getID(); mTEImages[te] = LLViewerTextureManager::getFetchedTexture(image_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - + if (getTE(te)->getMaterialParams().notNull()) { const LLUUID& norm_id = getTE(te)->getMaterialParams()->getNormalID(); - mTENormalMaps[te] = LLViewerTextureManager::getFetchedTexture(norm_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - + mTENormalMaps[te] = LLViewerTextureManager::getFetchedTexture(norm_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE); + const LLUUID& spec_id = getTE(te)->getMaterialParams()->getSpecularID(); - mTESpecularMaps[te] = LLViewerTextureManager::getFetchedTexture(spec_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + mTESpecularMaps[te] = LLViewerTextureManager::getFetchedTexture(spec_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE); } } @@ -4157,7 +4843,7 @@ S32 LLViewerObject::setTENormalMapCore(const U8 te, LLViewerTexture *image) mat->setNormalID(uuid); } } - changeTENormalMap(te,image); + changeTENormalMap(te,image); return retval; } @@ -4178,14 +4864,14 @@ S32 LLViewerObject::setTESpecularMapCore(const U8 te, LLViewerTexture *image) if (mat) { mat->setSpecularID(uuid); - } + } } changeTESpecularMap(te, image); return retval; } //virtual -void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) +void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) { if(index < 0 || index >= getNumTEs()) { @@ -4224,14 +4910,14 @@ S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid) S32 LLViewerObject::setTENormalMap(const U8 te, const LLUUID& uuid) { LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture( - uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); + uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); return setTENormalMapCore(te, image); } S32 LLViewerObject::setTESpecularMap(const U8 te, const LLUUID& uuid) { LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture( - uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); + uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); return setTESpecularMapCore(te, image); } @@ -4430,7 +5116,7 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams); LL_DEBUGS("Material") << "Changing material params for te " << (S32)te << ", object " << mID - << " (" << retval << ")" + << " (" << retval << ")" << LL_ENDL; setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null); setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null); @@ -4575,7 +5261,7 @@ bool LLViewerObject::isImageAlphaBlended(const U8 te) const LLViewerTexture *LLViewerObject::getTENormalMap(const U8 face) const { // llassert(mTEImages); - + if (face < getNumTEs()) { LLViewerTexture* image = mTENormalMaps[face]; @@ -4588,16 +5274,16 @@ LLViewerTexture *LLViewerObject::getTENormalMap(const U8 face) const return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); } } - + LL_ERRS() << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << LL_ENDL; - + return NULL; } LLViewerTexture *LLViewerObject::getTESpecularMap(const U8 face) const { // llassert(mTEImages); - + if (face < getNumTEs()) { LLViewerTexture* image = mTESpecularMaps[face]; @@ -4610,9 +5296,9 @@ LLViewerTexture *LLViewerObject::getTESpecularMap(const U8 face) const return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); } } - + LL_ERRS() << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << LL_ENDL; - + return NULL; } @@ -4632,7 +5318,7 @@ LLBBox LLViewerObject::getBoundingBoxAgent() const { avatar_parent = (LLViewerObject*)root_edit->getParent(); } - + if (avatar_parent && avatar_parent->isAvatar() && root_edit && root_edit->mDrawable.notNull() && root_edit->mDrawable->getXform()->getParent()) { @@ -4645,7 +5331,7 @@ LLBBox LLViewerObject::getBoundingBoxAgent() const position_agent = getPositionAgent(); rot = getRotationRegion(); } - + return LLBBox( position_agent, rot, getScale() * -0.5f, getScale() * 0.5f ); } @@ -4730,12 +5416,7 @@ void LLViewerObject::setDebugText(const std::string &utf8text) if (!mText) { - mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); - mText->setFont(LLFontGL::getFontSansSerif()); - mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); - mText->setMaxLines(-1); - mText->setSourceObject(this); - mText->setOnHUDAttachment(isHUDAttachment()); + initHudText(); } mText->setColor(utf8text.empty() ? mHudTextColor : LLColor4::white ); mText->setString(utf8text.empty() ? mHudTextString : utf8text ); @@ -4743,6 +5424,16 @@ void LLViewerObject::setDebugText(const std::string &utf8text) mText->setDoFade(utf8text.empty()); updateText(); } +void LLViewerObject::initHudText() +{ + mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); + mText->setFont(LLFontGL::getFontSansSerif()); + mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); + mText->setMaxLines(-1); + mText->setSourceObject(this); + mText->setOnHUDAttachment(isHUDAttachment()); +} + // std::string LLViewerObject::getDebugText() { @@ -4776,8 +5467,8 @@ void LLViewerObject::clearIcon() } } -LLViewerObject* LLViewerObject::getSubParent() -{ +LLViewerObject* LLViewerObject::getSubParent() +{ return (LLViewerObject*) getParent(); } @@ -4797,10 +5488,16 @@ void LLViewerObject::updateText() if (!isDead()) { if (mText.notNull()) - { + { + //LLVOAvatar* avatar = getAvatar(); + //if (avatar) + //{ + // mText->setHidden(avatar->isInMuteList()); + //} + LLVector3 up_offset(0,0,0); up_offset.mV[2] = getScale().mV[VZ]*0.6f; - + if (mDrawable.notNull()) { mText->setPositionAgent(getRenderPosition() + up_offset); @@ -4818,7 +5515,13 @@ LLVOAvatar* LLViewerObject::asAvatar() return NULL; } -// If this object is directly or indirectly parented by an avatar, return it. +// If this object is directly or indirectly parented by an avatar, +// return it. Normally getAvatar() is the correct function to call; +// it will give the avatar used for skinning. The exception is with +// animated objects that are also attachments; in that case, +// getAvatar() will return the control avatar, used for skinning, and +// getAvatarAncestor will return the avatar to which the object is +// attached. LLVOAvatar* LLViewerObject::getAvatarAncestor() { LLViewerObject *pobj = (LLViewerObject*) getParent(); @@ -4848,7 +5551,7 @@ void LLViewerObject::setParticleSource(const LLPartSysData& particle_parameters, LLPointer pss = LLViewerPartSourceScript::createPSS(this, particle_parameters); mPartSourcep = pss; - + if (mPartSourcep) { mPartSourcep->setOwnerUUID(owner_id); @@ -4980,20 +5683,20 @@ void LLViewerObject::updateDrawable(BOOL force_damped) if (!isChanged(MOVED)) { //most common case, having an empty if case here makes for better branch prediction } - else if (mDrawable.notNull() && + else if (mDrawable.notNull() && !mDrawable->isState(LLDrawable::ON_MOVE_LIST)) { - BOOL damped_motion = + BOOL damped_motion = !isChanged(SHIFTED) && // not shifted between regions this frame and... ( force_damped || // ...forced into damped motion by application logic or... ( !isSelected() && // ...not selected and... ( mDrawable->isRoot() || // ... is root or ... (getParent() && !((LLViewerObject*)getParent())->isSelected())// ... parent is not selected and ... - ) && + ) && getPCode() == LL_PCODE_VOLUME && // ...is a volume object and... getVelocity().isExactlyZero() && // ...is not moving physically and... mDrawable->getGeneration() != -1 // ...was not created this frame. - ) + ) ); gPipeline.markMoved(mDrawable, damped_motion); } @@ -5012,7 +5715,7 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow { return; } - + if (audio_uuid.isNull()) { if (!mAudioSourcep || (flags & LL_SOUND_FLAG_STOP && !mAudioSourcep->isLoop())) @@ -5030,7 +5733,7 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow mAudioSourcep = NULL; } else if (flags & LL_SOUND_FLAG_STOP) - { + { // Just shut off the sound mAudioSourcep->play(LLUUID::null); } @@ -5045,14 +5748,14 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow } // don't clean up before previous sound is done. Solves: SL-33486 - if ( mAudioSourcep && mAudioSourcep->isDone() ) + if ( mAudioSourcep && mAudioSourcep->isDone() ) { gAudiop->cleanupAudioSource(mAudioSourcep); mAudioSourcep = NULL; } if (mAudioSourcep && mAudioSourcep->isMuted() && - mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) + mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) { //LL_INFOS() << "Already having this sound as muted sound, ignoring" << LL_ENDL; return; @@ -5134,31 +5837,36 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para LLNetworkData* new_block = NULL; switch (param_type) { - case LLNetworkData::PARAMS_FLEXIBLE: - { - new_block = new LLFlexibleObjectData(); - break; - } - case LLNetworkData::PARAMS_LIGHT: - { - new_block = new LLLightParams(); - break; - } - case LLNetworkData::PARAMS_SCULPT: - { - new_block = new LLSculptParams(); - break; - } - case LLNetworkData::PARAMS_LIGHT_IMAGE: - { - new_block = new LLLightImageParams(); - break; - } - default: - { - LL_INFOS() << "Unknown param type. (" << llformat("0x%2x",param_type) << ")" << LL_ENDL; - break; - } + case LLNetworkData::PARAMS_FLEXIBLE: + { + new_block = new LLFlexibleObjectData(); + break; + } + case LLNetworkData::PARAMS_LIGHT: + { + new_block = new LLLightParams(); + break; + } + case LLNetworkData::PARAMS_SCULPT: + { + new_block = new LLSculptParams(); + break; + } + case LLNetworkData::PARAMS_LIGHT_IMAGE: + { + new_block = new LLLightImageParams(); + break; + } + case LLNetworkData::PARAMS_EXTENDED_MESH: + { + new_block = new LLExtendedMeshParams(); + break; + } + default: + { + LL_INFOS() << "Unknown param type. (" << llformat("0x%2x", param_type) << ")" << LL_ENDL; + break; + } }; if (new_block) @@ -5333,25 +6041,45 @@ void LLViewerObject::clearDrawableState(U32 state, BOOL recursive) } } +BOOL LLViewerObject::isDrawableState(U32 state, BOOL recursive) const +{ + BOOL matches = FALSE; + if (mDrawable) + { + matches = mDrawable->isState(state); + } + if (recursive) + { + for (child_list_t::const_iterator iter = mChildList.begin(); + (iter != mChildList.end()) && matches; iter++) + { + LLViewerObject* child = *iter; + matches &= child->isDrawableState(state, recursive); + } + } + + return matches; +} + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// RN: these functions assume a 2-level hierarchy +// RN: these functions assume a 2-level hierarchy //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Owned by anyone? BOOL LLViewerObject::permAnyOwner() const -{ +{ if (isRootEdit()) { - return flagObjectAnyOwner(); + return flagObjectAnyOwner(); } else { return ((LLViewerObject*)getParent())->permAnyOwner(); } -} +} // Owned by this viewer? BOOL LLViewerObject::permYouOwner() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5359,12 +6087,12 @@ BOOL LLViewerObject::permYouOwner() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectYouOwner(); + return flagObjectYouOwner(); #endif } else @@ -5374,11 +6102,11 @@ BOOL LLViewerObject::permYouOwner() const } // Owned by a group? -BOOL LLViewerObject::permGroupOwner() const -{ +BOOL LLViewerObject::permGroupOwner() const +{ if (isRootEdit()) { - return flagObjectGroupOwned(); + return flagObjectGroupOwned(); } else { @@ -5388,7 +6116,7 @@ BOOL LLViewerObject::permGroupOwner() const // Can the owner edit BOOL LLViewerObject::permOwnerModify() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5396,12 +6124,12 @@ BOOL LLViewerObject::permOwnerModify() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectOwnerModify(); + return flagObjectOwnerModify(); #endif } else @@ -5412,7 +6140,7 @@ BOOL LLViewerObject::permOwnerModify() const // Can edit BOOL LLViewerObject::permModify() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5420,12 +6148,12 @@ BOOL LLViewerObject::permModify() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectModify(); + return flagObjectModify(); #endif } else @@ -5436,7 +6164,7 @@ BOOL LLViewerObject::permModify() const // Can copy BOOL LLViewerObject::permCopy() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5444,7 +6172,7 @@ BOOL LLViewerObject::permCopy() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } @@ -5468,12 +6196,12 @@ BOOL LLViewerObject::permMove() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectMove(); + return flagObjectMove(); #endif } else @@ -5484,7 +6212,7 @@ BOOL LLViewerObject::permMove() const // Can be transferred BOOL LLViewerObject::permTransfer() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5492,12 +6220,12 @@ BOOL LLViewerObject::permTransfer() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectTransfer(); + return flagObjectTransfer(); #endif } else @@ -5534,6 +6262,17 @@ void LLViewerObject::updateVolume(const LLVolumeParams& volume_params) } } +void LLViewerObject::recursiveMarkForUpdate(BOOL priority) +{ + for (LLViewerObject::child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->markForUpdate(priority); + } + markForUpdate(priority); +} + void LLViewerObject::markForUpdate(BOOL priority) { if (mDrawable.notNull()) @@ -5543,6 +6282,15 @@ void LLViewerObject::markForUpdate(BOOL priority) } } + +void LLViewerObject::markForUnload(BOOL priority) +{ + if (mDrawable.notNull()) + { + gPipeline.markRebuild(mDrawable, LLDrawable::FOR_UNLOAD, priority); + } +} + bool LLViewerObject::isPermanentEnforced() const { return flagObjectPermanent() && (mRegionp != gAgent.getRegion()) && !gAgent.isGodlike(); @@ -5564,7 +6312,18 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp) { LL_WARNS() << "viewer object set region to NULL" << LL_ENDL; } - + if(regionp != mRegionp) + { + if(mRegionp) + { + mRegionp->removeFromCreatedList(getLocalID()); + } + if(regionp) + { + regionp->addToCreatedList(getLocalID()); + } + } + mLatestRecvPacketID = 0; mRegionp = regionp; @@ -5574,10 +6333,29 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp) child->setRegion(regionp); } + if (mControlAvatar) + { + mControlAvatar->setRegion(regionp); + } + setChanged(MOVED | SILHOUETTE); updateDrawable(FALSE); } +// virtual +void LLViewerObject::updateRegion(LLViewerRegion *regionp) +{ +// if (regionp) +// { +// F64 now = LLFrameTimer::getElapsedSeconds(); +// LL_INFOS() << "Updating to region " << regionp->getName() +// << ", ms since last update message: " << (F32)((now - mLastMessageUpdateSecs) * 1000.0) +// << ", ms since last interpolation: " << (F32)((now - mLastInterpUpdateSecs) * 1000.0) +// << LL_ENDL; +// } +} + + bool LLViewerObject::specialHoverCursor() const { return flagUsePhysics() @@ -5681,13 +6459,13 @@ void LLViewerObject::setPhysicsRestitution(F32 restitution) } U8 LLViewerObject::getPhysicsShapeType() const -{ +{ if (mPhysicsShapeUnknown) { gObjectList.updatePhysicsFlags(this); } - return mPhysicsShapeType; + return mPhysicsShapeType; } void LLViewerObject::applyAngularVelocity(F32 dt) @@ -5704,7 +6482,7 @@ void LLViewerObject::applyAngularVelocity(F32 dt) angle = omega * dt; ang_vel *= 1.f/omega; - + // calculate the delta increment based on the object's angular velocity dQ.setQuat(angle, ang_vel); @@ -5714,7 +6492,7 @@ void LLViewerObject::applyAngularVelocity(F32 dt) // accumulate the angular velocity rotations to re-apply in the case of an object update mAngularVelocityRot *= dQ; } - + // Just apply the delta increment to the current rotation setRotation(getRotation()*dQ); setChanged(MOVED | SILHOUETTE); @@ -5733,25 +6511,9 @@ void LLViewerObject::resetRot() } } -//virtual -void LLViewerObject::setSelected(BOOL sel) -{ - mUserSelected = sel; - - static const LLCachedControl use_new_target_omega ("UseNewTargetOmegaCode", true); - if(use_new_target_omega) - { - resetRot(); - } - else - { - mRotTime = 0.f; - } -} - U32 LLViewerObject::getPartitionType() const -{ - return LLViewerRegion::PARTITION_NONE; +{ + return LLViewerRegion::PARTITION_NONE; } void LLViewerObject::dirtySpatialGroup(BOOL priority) const @@ -5815,7 +6577,7 @@ void LLViewerObject::saveUnselectedChildrenPosition(std::vector& posi LLViewerObject* childp = *iter; if (!childp->isSelected() && childp->mDrawable.notNull()) { - positions.push_back(childp->getPositionEdit()); + positions.push_back(childp->getPositionEdit()); } } @@ -5835,15 +6597,15 @@ void LLViewerObject::saveUnselectedChildrenRotation(std::vector& r LLViewerObject* childp = *iter; if (!childp->isSelected() && childp->mDrawable.notNull()) { - rotations.push_back(childp->getRotationEdit()); - } + rotations.push_back(childp->getRotationEdit()); + } } return ; } //counter-rotation -void LLViewerObject::resetChildrenRotationAndPosition(const std::vector& rotations, +void LLViewerObject::resetChildrenRotationAndPosition(const std::vector& rotations, const std::vector& positions) { if(mChildList.empty()) @@ -5864,30 +6626,30 @@ void LLViewerObject::resetChildrenRotationAndPosition(const std::vectorsetRotation(rotations[index] * inv_rotation); childp->setPosition((positions[index] - offset) * inv_rotation); - LLManip::rebuild(childp); + LLManip::rebuild(childp); } else //avatar { LLVector3 reset_pos = (positions[index] - offset) * inv_rotation ; LLQuaternion reset_rot = rotations[index] * inv_rotation ; - ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); ((LLVOAvatar*)childp)->mDrawable->mXform.setRotation(reset_rot) ; - - ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE); + + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE); ((LLVOAvatar*)childp)->mDrawable->getVObj()->setRotation(reset_rot, TRUE) ; - LLManip::rebuild(childp); - } + LLManip::rebuild(childp); + } index++; - } + } } return ; } //counter-translation -void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified) +void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified, BOOL skip_avatar_child) { if(mChildList.empty()) { @@ -5926,20 +6688,22 @@ void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplif } else //avatar { - LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ; + if(!skip_avatar_child) + { + LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ; - ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); - ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos); - - LLManip::rebuild(childp); - } - } + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos); + LLManip::rebuild(childp); + } + } + } } return ; } -// virtual +// virtual BOOL LLViewerObject::isTempAttachment() const { return (mID.notNull() && (mID == mAttachmentItemID)); @@ -5948,7 +6712,7 @@ BOOL LLViewerObject::isTempAttachment() const // std::string LLViewerObject::getAttachmentPointName() { - S32 point = ATTACHMENT_ID_FROM_STATE(mState); + S32 point = ATTACHMENT_ID_FROM_STATE(mAttachmentState); LLVOAvatar::attachment_map_t::iterator it = gAgentAvatarp->mAttachmentPoints.find(point); if(it != gAgentAvatarp->mAttachmentPoints.end()) { @@ -6007,6 +6771,10 @@ const LLUUID &LLViewerObject::extractAttachmentItemID() //virtual LLVOAvatar* LLViewerObject::getAvatar() const { + if (getControlAvatar()) + { + return getControlAvatar(); + } if (isAttachment()) { LLViewerObject* vobj = (LLViewerObject*) getParent(); @@ -6033,7 +6801,7 @@ public: { LLSD object_data = input["body"]["ObjectData"]; S32 num_entries = object_data.size(); - + for ( S32 i = 0; i < num_entries; i++ ) { LLSD& curr_object_data = object_data[i]; @@ -6066,9 +6834,9 @@ public: node->getObject()->setPhysicsFriction(friction); node->getObject()->setPhysicsDensity(density); node->getObject()->setPhysicsRestitution(restitution); - } + } } - + dialog_refresh_all(); }; }; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 19e7aab91..6457bd1d9 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -55,6 +55,7 @@ class LLAudioSource; class LLAudioSourceVO; class LLBBox; class LLColor4; +class LLControlAvatar; class LLDataPacker; class LLDrawable; class LLFrameTimer; @@ -76,6 +77,8 @@ class LLViewerRegion; class LLViewerTexture; class LLWorld; +class LLMeshCostData; + typedef enum e_object_update_type { OUT_FULL, @@ -112,7 +115,10 @@ struct PotentialReturnableObject //============================================================================ -class LLViewerObject: public LLPrimitive, public LLRefCount, public LLGLUpdate +class LLViewerObject +: public LLPrimitive, + public LLRefCount, + public LLGLUpdate { protected: ~LLViewerObject(); // use unref() @@ -165,6 +171,7 @@ public: INVALID_UPDATE = 0x80000000 }; + static U32 extractSpatialExtents(LLDataPackerBinaryBuffer *dp, LLVector3& pos, LLVector3& scale, LLQuaternion& rot); virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, U32 block_num, @@ -219,6 +226,7 @@ public: LLViewerRegion* getRegion() const { return mRegionp; } BOOL isSelected() const { return mUserSelected; } + BOOL isAnySelected() const; void setSelected(BOOL sel); const LLUUID &getID() const { return mID; } @@ -230,6 +238,7 @@ public: virtual BOOL isFlexible() const { return FALSE; } virtual BOOL isSculpted() const { return FALSE; } virtual BOOL isMesh() const { return FALSE; } + virtual BOOL isRiggedMesh() const { return FALSE; } virtual BOOL hasLightTexture() const { return FALSE; } // This method returns true if the object is over land owned by @@ -254,6 +263,8 @@ public: */ virtual BOOL setParent(LLViewerObject* parent); + virtual void onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent); + virtual void afterReparent(); virtual void addChild(LLViewerObject *childp); virtual void removeChild(LLViewerObject *childp); const_child_list_t& getChildren() const { return mChildList; } @@ -358,9 +369,17 @@ public: virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); - virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; + S32 getAnimatedObjectMaxTris() const; + F32 recursiveGetEstTrianglesMax() const; + virtual F32 getEstTrianglesMax() const; + virtual F32 getEstTrianglesStreamingCost() const; + virtual F32 getStreamingCost() const; + virtual bool getCostData(LLMeshCostData& costs) const; virtual U32 getTriangleCount(S32* vcount = NULL) const; virtual U32 getHighLODTriangleCount(); + F32 recursiveGetScaledSurfaceArea() const; + + U32 recursiveGetTriangleCount(S32* vcount = NULL) const; void setObjectCost(F32 cost); F32 getObjectCost(); @@ -378,7 +397,7 @@ public: // U8 getState() { return mState; } // [RLVa:KB] - Checked: 2010-09-26 (RLVa-1.3.0a) | Added: RLVa-1.3.0a - U8 getState() const { return mState; } + U8 getAttachmentState() const { return mAttachmentState; } // [/RLVa:KB] F32 getAppAngle() const { return mAppAngle; } @@ -411,13 +430,17 @@ public: void setCanSelect(BOOL canSelect); void setDebugText(const std::string &utf8text); + void initHudText(); + // std::string getDebugText(); // void setIcon(LLViewerTexture* icon_image); void clearIcon(); - void markForUpdate(BOOL priority); + void recursiveMarkForUpdate(BOOL priority); + virtual void markForUpdate(BOOL priority); + void markForUnload(BOOL priority); void updateVolume(const LLVolumeParams& volume_params); virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max); virtual F32 getBinRadius(); @@ -430,6 +453,7 @@ public: void setDrawableState(U32 state, BOOL recursive = TRUE); void clearDrawableState(U32 state, BOOL recursive = TRUE); + BOOL isDrawableState(U32 state, BOOL recursive = TRUE) const; // Called when the drawable shifts virtual void onShift(const LLVector4a &shift_vector) { } @@ -444,7 +468,7 @@ public: // viewer object has the inventory stored locally. void registerInventoryListener(LLVOInventoryListener* listener, void* user_data); void removeInventoryListener(LLVOInventoryListener* listener); - BOOL isInventoryPending() { return mInventoryPending; } + BOOL isInventoryPending(); void clearInventoryListeners(); bool hasInventoryListeners(); void requestInventory(); @@ -540,9 +564,10 @@ public: bool specialHoverCursor() const; // does it have a special hover cursor? void setRegion(LLViewerRegion *regionp); - virtual void updateRegion(LLViewerRegion *regionp) {} + virtual void updateRegion(LLViewerRegion *regionp); void updateFlags(BOOL physics_changed = FALSE); + void loadFlags(U32 flags); //load flags from cache or from message BOOL setFlags(U32 flag, BOOL state); BOOL setFlagsWithoutUpdate(U32 flag, BOOL state); void setPhysicsShapeType(U8 type); @@ -572,9 +597,16 @@ public: friend class LLViewerObjectList; friend class LLViewerMediaList; +public: + static void unpackVector3(LLDataPackerBinaryBuffer* dp, LLVector3& value, std::string name); + static void unpackUUID(LLDataPackerBinaryBuffer* dp, LLUUID& value, std::string name); + static void unpackU32(LLDataPackerBinaryBuffer* dp, U32& value, std::string name); + static void unpackU8(LLDataPackerBinaryBuffer* dp, U8& value, std::string name); + static U32 unpackParentID(LLDataPackerBinaryBuffer* dp, U32& parent_id); + public: //counter-translation - void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE) ; + void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE, BOOL skip_avatar_child = FALSE) ; //counter-rotation void resetChildrenRotationAndPosition(const std::vector& rotations, const std::vector& positions) ; @@ -595,10 +627,13 @@ private: // Motion prediction between updates void interpolateLinearMotion(const F64SecondsImplicit & time, const F32SecondsImplicit & dt); + static void initObjectDataMap(); + // forms task inventory request if none are pending void fetchInventoryFromServer(); public: + void print(); // // Viewer-side only types - use the LL_PCODE_APP mask. // @@ -649,6 +684,7 @@ private: // Grabbed from UPDATE_FLAGS U32 mFlags; + static std::map sObjectDataMap; public: // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties U8 mPhysicsShapeType; @@ -681,6 +717,27 @@ public: static BOOL sUseSharedDrawables; +public: + // Returns mControlAvatar for the edit root prim of this linkset + LLControlAvatar *getControlAvatar(); + LLControlAvatar *getControlAvatar() const; + + // Create or connect to an existing control av as applicable + void linkControlAvatar(); + // Remove any reference to control av for this prim + void unlinkControlAvatar(); + // Link or unlink as needed + void updateControlAvatar(); + + virtual bool isAnimatedObject() const; + + // Flags for createObject + static const S32 CO_FLAG_CONTROL_AVATAR = 1 << 0; + static const S32 CO_FLAG_UI_AVATAR = 1 << 1; + +protected: + LLPointer mControlAvatar; + protected: // delete an item in the inventory, but don't tell the // server. This is used internally by remove, update, and @@ -691,8 +748,7 @@ protected: // updateInventory. void doUpdateInventory(LLPointer& item, U8 key, bool is_new); - - static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp); + static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0); BOOL setData(const U8 *datap, const U32 data_size); @@ -757,9 +813,17 @@ protected: callback_list_t mInventoryCallbacks; S16 mInventorySerialNum; + enum EInventoryRequestState + { + INVENTORY_REQUEST_STOPPED, + INVENTORY_REQUEST_PENDING, + INVENTORY_XFER + }; + EInventoryRequestState mInvRequestState; + U64 mInvRequestXFerId; + BOOL mInventoryDirty; + LLViewerRegion *mRegionp; // Region that this object belongs to. - BOOL mInventoryPending; - BOOL mInventoryDirty; BOOL mDead; BOOL mOrphaned; // This is an orphaned child BOOL mUserSelected; // Cached user select information @@ -772,7 +836,7 @@ protected: LLQuaternion mAngularVelocityRot; // accumulated rotation from the angular velocity computations LLQuaternion mPreviousRotation; - U8 mState; // legacy + U8 mAttachmentState; // this encodes the attachment id in a somewhat complex way. 0 if not an attachment. LLViewerObjectMedia* mMedia; // NULL if no media associated U8 mClickAction; F32 mObjectCost; //resource cost of this object or -1 if unknown @@ -827,6 +891,11 @@ public: void setLastUpdateType(EObjectUpdateType last_update_type); BOOL getLastUpdateCached() const; void setLastUpdateCached(BOOL last_update_cached); + + virtual void updateRiggingInfo() {} + + LLJointRiggingInfoTab mJointRiggingInfoTab; + private: LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory. EObjectUpdateType mLastUpdateType; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 789d41035..0f45eea51 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -291,7 +291,19 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, // RN: this must be called after we have a drawable // (from gPipeline.addObject) // so that the drawable parent is set properly - findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); + if(msg != NULL) + { + findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); + } + else + { + LLViewerRegion* regionp = objectp->getRegion(); + if(regionp != NULL) + { + findOrphans(objectp, regionp->getHost().getAddress(), regionp->getHost().getPort()); + } + } + if(just_created && objectp && (gImportTracker.getState() == ImportTracker::WAND /*|| @@ -434,19 +446,15 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { S32 uncompressed_length = 2048; compressed_dp.reset(); - - U32 flags = 0; - if (update_type != OUT_TERSE_IMPROVED) - { - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); - } uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i, 2048); compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { + U32 flags = 0; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); compressed_dp.unpackUUID(fullid, "ID"); compressed_dp.unpackU32(local_id, "LocalID"); compressed_dp.unpackU8(pcode, "PCode"); @@ -941,14 +949,14 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) // update global timer F32 last_time = gFrameTimeSeconds; - U64 time = totalTime(); // this will become the new gFrameTime when the update is done + U64Microseconds time = totalTime(); // this will become the new gFrameTime when the update is done // Time _can_ go backwards, for example if the user changes the system clock. // It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here. // llassert(time > gFrameTime); - F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC; - gFrameTime = time; - F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC; - gFrameTimeSeconds = (F32)time_since_start; + F64Seconds time_diff = time - gFrameTime; + gFrameTime = time; + F64Seconds time_since_start = gFrameTime - gStartTime; + gFrameTimeSeconds = time_since_start; gFrameIntervalSeconds = gFrameTimeSeconds - last_time; if (gFrameIntervalSeconds < 0.f) @@ -1033,7 +1041,10 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) LLVolumeImplFlexible::updateClass(); //update animated textures - LLViewerTextureAnim::updateClass(); + if (gAnimateTextures) + { + LLViewerTextureAnim::updateClass(); + } } @@ -1051,7 +1062,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) // don't factor frames that were paused into the stats if (! mWasPaused) { - LLViewerStats::getInstance()->updateFrameStats(time_diff); + LLViewerStats::getInstance()->updateFrameStats(time_diff.value()); } /* @@ -1252,9 +1263,11 @@ void LLViewerObjectList::clearDebugText() void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) { + bool new_dead_object = true; if (mDeadObjects.find(objectp->mID) != mDeadObjects.end()) { LL_INFOS() << "Object " << objectp->mID << " already on dead list!" << LL_ENDL; + new_dead_object = false; } else { @@ -1296,7 +1309,10 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) // Also, not cleaned up removeDrawable(objectp->mDrawable); - mNumDeadObjects++; + if(new_dead_object) + { + mNumDeadObjects++; + } } static LLTrace::BlockTimerStatHandle FTM_REMOVE_DRAWABLE("Remove Drawable"); @@ -1974,12 +1990,12 @@ void LLViewerObjectList::resetObjectBeacons() mDebugBeacons.clear(); } -LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp) +LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags) { LLUUID fullid; fullid.generate(); - LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp); + LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp, flags); if (!objectp) { // LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << LL_ENDL; @@ -2031,6 +2047,10 @@ LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRe // LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << LL_ENDL; return NULL; } + if(regionp) + { + regionp->addToCreatedList(local_id); + } mUUIDObjectMap[fullid] = objectp; if(objectp->isAvatar()) diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index ab3c9b3ac..3f96c11bf 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -74,7 +74,7 @@ public: inline LLViewerObject *findObject(const LLUUID &id) const; inline LLVOAvatar *findAvatar(const LLUUID &id) const; - LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp); // Create a viewer-side object + LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0); // Create a viewer-side object LLViewerObject *createObject(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id, const LLHost &sender); @@ -141,6 +141,7 @@ public: LLViewerObject *getSelectedObject(const U32 object_id); inline S32 getNumObjects() { return (S32) mObjects.size(); } + inline S32 getNumActiveObjects() { return (S32) mActiveObjects.size(); } void addToMap(LLViewerObject *objectp); void removeFromMap(LLViewerObject *objectp); diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index 937fc7e3d..bfc533dbb 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -1101,7 +1101,7 @@ void LLOcclusionCullingGroup::checkOcclusion() LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_WAIT); while (!available && max_loop-- > 0) { - F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); + F32 max_time = llmin(gFrameIntervalSeconds.value()*10.f, 1.f); //do some usefu work while we wait LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index f5bfd9cc3..028ad4a52 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -932,6 +932,10 @@ void LLViewerRegion::dirtyHeights() } } +void LLViewerRegion::clearCachedVisibleObjects() +{ +} + BOOL LLViewerRegion::idleUpdate(F32 max_update_time) { // did_update returns TRUE if we did at least one significant update @@ -1444,6 +1448,81 @@ void LLViewerRegion::getInfo(LLSD& info) info["Region"]["Handle"]["y"] = (LLSD::Integer)y; } +class BaseFeaturesReceived : public LLHTTPClient::ResponderWithResult +{ + LOG_CLASS(BaseFeaturesReceived); +public: + BaseFeaturesReceived(const std::string& retry_url, U64 region_handle, const char* classname, boost::function fn, + S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) + : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts), mClassName(classname), mFunction(fn) + { } + + + void httpFailure(void) + { + LL_WARNS("AppInit", mClassName) << dumpResponse() << LL_ENDL; + retry(); + } + + void httpSuccess(void) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (!regionp) //region is removed or responder is not created. + { + LL_WARNS("AppInit", mClassName) + << "Received results for region that no longer exists!" << LL_ENDL; + return; + } + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(400, "Malformed response contents", content); + return; + } + mFunction(regionp, content); + } + + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return baseFeaturesReceived_timeout; } + /*virtual*/ char const* getName(void) const { return mClassName; } + +private: + + void retry() + { + if (mAttempt < mMaxAttempts) + { + mAttempt++; + LL_WARNS("AppInit", mClassName) << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; + LLHTTPClient::get(mRetryURL, new BaseFeaturesReceived(*this)); + } + } + + std::string mRetryURL; + U64 mRegionHandle; + S32 mAttempt; + S32 mMaxAttempts; + const char* mClassName; + boost::function mFunction; +}; + +void LLViewerRegion::requestSimulatorFeatures() +{ + LL_DEBUGS("SimulatorFeatures") << "region " << getName() << " ptr " << this + << " trying to request SimulatorFeatures" << LL_ENDL; + // kick off a request for simulator features + std::string url = getCapability("SimulatorFeatures"); + if (!url.empty()) + { + // kick off a request for simulator features + LLHTTPClient::get(url, new BaseFeaturesReceived(url, getHandle(), "SimulatorFeaturesReceived", &LLViewerRegion::setSimulatorFeatures)); + } + else + { + LL_WARNS("AppInit", "SimulatorFeatures") << "SimulatorFeatures cap not set" << LL_ENDL; + } +} + boost::signals2::connection LLViewerRegion::setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb) { return mSimulatorFeaturesReceivedSignal.connect(cb); @@ -1474,10 +1553,11 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) std::stringstream str; LLSDSerialize::toPrettyXML(sim_features, str); - LL_DEBUGS("SimFeatures") << "\n" << str.str() << LL_ENDL; + LL_INFOS() << "region " << getName() << " " << str.str() << LL_ENDL; mSimulatorFeatures = sim_features; setSimulatorFeaturesReceived(true); + } void LLViewerRegion::setGamingData(const LLSD& gaming_data) @@ -1552,6 +1632,14 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec return result; } +void LLViewerRegion::removeFromCreatedList(U32 local_id) +{ +} + +void LLViewerRegion::addToCreatedList(U32 local_id) +{ +} + // Get data packer for this object, if we have cached data // AND the CRC matches. JC LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) @@ -1921,6 +2009,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("MeshUploadFlag"); capabilityNames.append("NavMeshGenerationStatus"); capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("ObjectAnimation"); capabilityNames.append("ObjectMedia"); capabilityNames.append("ObjectMediaNavigate"); capabilityNames.append("ObjectNavMeshProperties"); @@ -2041,64 +2130,6 @@ void LLViewerRegion::failedSeedCapability() } } -class BaseFeaturesReceived : public LLHTTPClient::ResponderWithResult -{ - LOG_CLASS(BaseFeaturesReceived); -public: - BaseFeaturesReceived(const std::string& retry_url, U64 region_handle, const char* classname, boost::function fn, - S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) - : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts), mClassName(classname), mFunction(fn) - { } - - - void httpFailure(void) - { - LL_WARNS("AppInit", mClassName) << dumpResponse() << LL_ENDL; - retry(); - } - - void httpSuccess(void) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(!regionp) //region is removed or responder is not created. - { - LL_WARNS("AppInit", mClassName) - << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } - - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(400, "Malformed response contents", content); - return; - } - mFunction(regionp, content); - } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return baseFeaturesReceived_timeout; } - /*virtual*/ char const* getName(void) const { return mClassName; } - -private: - - void retry() - { - if (mAttempt < mMaxAttempts) - { - mAttempt++; - LL_WARNS("AppInit", mClassName) << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get(mRetryURL, new BaseFeaturesReceived(*this)); - } - } - - std::string mRetryURL; - U64 mRegionHandle; - S32 mAttempt; - S32 mMaxAttempts; - const char* mClassName; - boost::function mFunction; -}; - void LLViewerRegion::setCapability(const std::string& name, const std::string& url) { if(name == "EventQueueGet") @@ -2114,10 +2145,8 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u else if (name == "SimulatorFeatures") { // although this is not needed later, add it so we can check if the sim supports it at all later - mImpl->mCapabilities[name] = url; - - // kick off a request for simulator features - LLHTTPClient::get(url, new BaseFeaturesReceived(url, getHandle(), "SimulatorFeaturesReceived", &LLViewerRegion::setSimulatorFeatures)); + mImpl->mCapabilities["SimulatorFeatures"] = url; + requestSimulatorFeatures(); } else if (name == "GamingData") { diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index b2fee7c4b..d02ab5a53 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -328,6 +328,7 @@ public: bool meshUploadEnabled() const; // has region received its simulator features list? Requires an additional query after caps received. + void requestSimulatorFeatures(); void setSimulatorFeaturesReceived(bool); bool simulatorFeaturesReceived() const; boost::signals2::connection setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb); @@ -361,6 +362,7 @@ public: void requestCacheMisses(); void addCacheMissFull(const U32 local_id); + void clearCachedVisibleObjects(); void dumpCache(); void unpackRegionHandshake(); @@ -392,6 +394,9 @@ public: void resetMaterialsCapThrottle(); U32 getMaxMaterialsPerTransaction() const; + + void removeFromCreatedList(U32 local_id); + void addToCreatedList(U32 local_id); public: struct CompareDistance { diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 1f97ff20b..274fe6cc1 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -99,6 +99,7 @@ S32 LLViewerTexture::sMaxSculptRez = 128; //max sculpt image size const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64; const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez; const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128; +const S32 DEFAULT_ICON_DIMENTIONS = 32; S32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256. S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA; BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE; @@ -112,6 +113,8 @@ const F32 desired_discard_bias_min = -2.0f; // -max number of levels to improve const F32 desired_discard_bias_max = (F32)MAX_DISCARD_LEVEL; // max number of levels to reduce image quality by const F64 log_2 = log(2.0); +const U32 DESIRED_NORMAL_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT; + //---------------------------------------------------------------------------------------------- //namespace: LLViewerTextureAccess //---------------------------------------------------------------------------------------------- @@ -459,7 +462,7 @@ bool LLViewerTexture::isMemoryForTextureLow() LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK); - static const S32Megabytes MIN_FREE_TEXTURE_MEMORY(5); //MB + static const S32Megabytes MIN_FREE_TEXTURE_MEMORY(20); //MB static const S32Megabytes MIN_FREE_MAIN_MEMORY(100); //MB bool low_mem = false; @@ -690,9 +693,11 @@ void LLViewerTexture::setBoostLevel(S32 level) { mBoostLevel = level; if(mBoostLevel != LLViewerTexture::BOOST_NONE && - mBoostLevel != LLViewerTexture::BOOST_SELECTED) + mBoostLevel != LLViewerTexture::BOOST_ALM && + mBoostLevel != LLViewerTexture::BOOST_SELECTED && + mBoostLevel != LLViewerTexture::BOOST_ICON) { - setNoDelete(); + setNoDelete(); } } @@ -1524,15 +1529,31 @@ void LLViewerFetchedTexture::processTextureStats() { mDesiredDiscardLevel = 0; } + else if (!LLPipeline::sRenderDeferred && mBoostLevel == LLGLTexture::BOOST_ALM) + { + mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; + } + else if (mDontDiscard && mBoostLevel == LLGLTexture::BOOST_ICON) + { + if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) + { + mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + } + else + { + mDesiredDiscardLevel = 0; + } + } else if(!mFullWidth || !mFullHeight) { mDesiredDiscardLevel = llmin(getMaxDiscardLevel(), (S32)mLoadedCallbackDesiredDiscardLevel); } else { + S32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 if(!mKnownDrawWidth || !mKnownDrawHeight || mFullWidth <= mKnownDrawWidth || mFullHeight <= mKnownDrawHeight) { - if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) + if (mFullWidth > desired_size || mFullHeight > desired_size) { mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 } @@ -1782,10 +1803,11 @@ void LLViewerFetchedTexture::updateVirtualSize() { if(drawable->isRecentlyVisible()) { - if (getBoostLevel() == LLViewerTexture::BOOST_NONE && - drawable->getVObj() && drawable->getVObj()->isSelected()) - { - setBoostLevel(LLViewerTexture::BOOST_SELECTED); + if ((getBoostLevel() == LLViewerTexture::BOOST_NONE || getBoostLevel() == LLViewerTexture::BOOST_ALM) + && drawable->getVObj() + && drawable->getVObj()->isSelected()) + { + setBoostLevel(LLViewerTexture::BOOST_SELECTED); } addTextureStats(facep->getVirtualSize()); setAdditionalDecodePriority(facep->getImportanceToCamera()); @@ -1953,6 +1975,17 @@ bool LLViewerFetchedTexture::updateFetch() addToCreateTexture(); } + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; + if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) + { + // scale oversized icon, no need to give more work to gl + mRawImage->scale(expected_width, expected_height); + } + } + return TRUE; } else @@ -2057,7 +2090,7 @@ bool LLViewerFetchedTexture::updateFetch() // Load the texture progressively: we try not to rush to the desired discard too fast. // If the camera is not moving, we do not tweak the discard level notch by notch but go to the desired discard with larger boosted steps // This mitigates the "textures stay blurry" problem when loading while not killing the texture memory while moving around - S32 delta_level = (mBoostLevel > LLGLTexture::BOOST_NONE) ? 2 : 1; + S32 delta_level = (mBoostLevel > LLGLTexture::BOOST_ALM) ? 2 : 1; if (current_discard < 0) { desired_discard = llmax(desired_discard, getMaxDiscardLevel() - delta_level); @@ -2688,7 +2721,7 @@ LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level) if(mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= discard_level) { - if(mSavedRawDiscardLevel != discard_level) + if (mSavedRawDiscardLevel != discard_level && mBoostLevel != BOOST_ICON) { mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()); mRawImage->copy(getSavedRawImage()); @@ -2792,7 +2825,24 @@ void LLViewerFetchedTexture::setCachedRawImage(S32 discard_level, LLImageRaw* im { if(mCachedRawImage.notNull()) mCachedRawImage->setInCache(false); - mCachedRawImage = imageraw; + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; + if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + { + mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents()); + mCachedRawImage->copyScaled(imageraw); + } + else + { + mCachedRawImage = imageraw; + } + } + else + { + mCachedRawImage = imageraw; + } if(mCachedRawImage.notNull()) mCachedRawImage->setInCache(true); mCachedRawDiscardLevel = discard_level; @@ -2900,7 +2950,24 @@ void LLViewerFetchedTexture::saveRawImage() } mSavedRawDiscardLevel = mRawDiscardLevel; - mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; + if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + { + mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents()); + mSavedRawImage->copyScaled(mRawImage); + } + else + { + mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + } + } + else + { + mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + } if(mForceToSaveRawImage && mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel) { @@ -3079,6 +3146,10 @@ void LLViewerLODTexture::processTextureStats() if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 } + else if (!LLPipeline::sRenderDeferred && mBoostLevel == LLGLTexture::BOOST_ALM) + { + mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; + } else if (mBoostLevel < LLGLTexture::BOOST_HIGH && mMaxVirtualSize <= 10.f) { // If the image has not been significantly visible in a while, we don't want it @@ -3101,6 +3172,7 @@ void LLViewerLODTexture::processTextureStats() if (mKnownDrawWidth && mKnownDrawHeight) { S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight; + draw_texels = llclamp(draw_texels, MIN_IMAGE_AREA, MAX_IMAGE_AREA); // Use log_4 because we're in square-pixel space, so an image // with twice the width and twice the height will have mTexelsPerImage @@ -3138,8 +3210,13 @@ void LLViewerLODTexture::processTextureStats() discard_level = floorf(discard_level); F32 min_discard = 0.f; - if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) - min_discard = 1.f; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + S32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + if (mBoostLevel <= LLGLTexture::BOOST_SCULPTED) + { + desired_size = DESIRED_NORMAL_TEXTURE_SIZE; + } + if (mFullWidth > desired_size || mFullHeight > desired_size) + min_discard = 1.f; discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL); diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 41900b3b3..da84e94ec 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1333,7 +1333,7 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl max_texmem = llmin(max_texmem, system_ram/2); else max_texmem = llmin(max_texmem, system_ram); - + // limit the texture memory to a multiple of the default if we've found some cards to behave poorly otherwise max_texmem = llmin(max_texmem, (S32Megabytes) (mem_multiplier * max_texmem)); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 3ae1c9733..a5d8cf120 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3596,8 +3596,8 @@ void LLViewerWindow::updateMouseDelta() static F32 fdy = 0.f; F32 amount = 16.f; - fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); - fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); + fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds.value()*amount,1.f); + fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds.value()*amount,1.f); mCurrentMouseDelta.set(ll_round(fdx), ll_round(fdy)); mouse_vel.setVec(fdx,fdy); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 03098b8d6..3f24e1998 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -47,6 +47,7 @@ #include "llanimationstates.h" #include "llavatarnamecache.h" #include "llavatarpropertiesprocessor.h" +#include "llcontrolavatar.h" #include "llphysicsmotion.h" #include "llviewercontrol.h" #include "lldrawpoolavatar.h" @@ -88,6 +89,7 @@ #include "llviewermenu.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" +#include "llviewerregion.h" #include "llviewershadermgr.h" #include "llviewerstats.h" #include "llviewerwearable.h" @@ -147,7 +149,8 @@ extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG; const F32 MAX_HOVER_Z = 2.0; const F32 MIN_HOVER_Z = -2.0; -// #define OUTPUT_BREAST_DATA +const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f; +const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f; using namespace LLAvatarAppearanceDefines; @@ -156,7 +159,6 @@ using namespace LLAvatarAppearanceDefines; //----------------------------------------------------------------------------- const LLUUID ANIM_AGENT_BODY_NOISE_ID = LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise" const LLUUID ANIM_AGENT_BREATHE_ROT_ID = LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8"); //"breathe_rot" -const LLUUID ANIM_AGENT_PHYSICS_MOTION_ID = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion" const LLUUID ANIM_AGENT_EDITING_ID = LLUUID("2a8eba1d-a7f8-5596-d44a-b4977bf8c8bb"); //"editing" const LLUUID ANIM_AGENT_EYE_ID = LLUUID("5c780ea8-1cd1-c463-a128-48c023f6fbea"); //"eye" const LLUUID ANIM_AGENT_FLY_ADJUST_ID = LLUUID("db95561f-f1b0-9f9a-7224-b12f71af126e"); //"fly_adjust" @@ -165,6 +167,7 @@ const LLUUID ANIM_AGENT_HEAD_ROT_ID = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a6 const LLUUID ANIM_AGENT_PELVIS_FIX_ID = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix" const LLUUID ANIM_AGENT_TARGET_ID = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target" const LLUUID ANIM_AGENT_WALK_ADJUST_ID = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust" +const LLUUID ANIM_AGENT_PHYSICS_MOTION_ID = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion" // // This must be in the same order as ANIM_AGENT_BODY_NOISE through ANIM_AGENT_WALK_ADJUST (see llmotion.h)! @@ -321,6 +324,11 @@ const F32 NAMETAG_UPDATE_THRESHOLD = 0.3f; const F32 NAMETAG_VERTICAL_SCREEN_OFFSET = 25.f; const F32 NAMETAG_VERT_OFFSET_WEIGHT = 0.17f; +const U32 LLVOAvatar::VISUAL_COMPLEXITY_UNKNOWN = 0; +const F64 HUD_OVERSIZED_TEXTURE_DATA_SIZE = 1024 * 1024; + +#define SLOW_ATTACHMENT_LIST 0 + //Singu note: FADE and ALWAYS are swapped around from LL's source to match our preference panel. // Changing the "RenderName" order would cause confusion when 'always' setting suddenly gets // interpreted as 'fade', and vice versa. @@ -1032,28 +1040,27 @@ const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = S32 LLVOAvatar::sRenderName = RENDER_NAME_ALWAYS; bool LLVOAvatar::sRenderGroupTitles = true; S32 LLVOAvatar::sNumVisibleChatBubbles = 0; -BOOL LLVOAvatar::sDebugInvisible = FALSE; -BOOL LLVOAvatar::sShowAttachmentPoints = FALSE; -BOOL LLVOAvatar::sShowAnimationDebug = FALSE; -BOOL LLVOAvatar::sShowFootPlane = FALSE; -BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE; +BOOL LLVOAvatar::sDebugInvisible = false; +bool LLVOAvatar::sShowAttachmentPoints = false; +BOOL LLVOAvatar::sShowAnimationDebug = false; +bool LLVOAvatar::sShowFootPlane = false; +bool LLVOAvatar::sVisibleInFirstPerson = false; F32 LLVOAvatar::sLODFactor = 1.f; F32 LLVOAvatar::sPhysicsLODFactor = 1.f; -BOOL LLVOAvatar::sUseImpostors = FALSE; -BOOL LLVOAvatar::sJointDebug = FALSE; +bool LLVOAvatar::sUseImpostors = false; +BOOL LLVOAvatar::sJointDebug = false; F32 LLVOAvatar::sUnbakedTime = 0.f; F32 LLVOAvatar::sUnbakedUpdateTime = 0.f; F32 LLVOAvatar::sGreyTime = 0.f; F32 LLVOAvatar::sGreyUpdateTime = 0.f; //Move to LLVOAvatarSelf -BOOL LLVOAvatar::sDebugAvatarRotation = FALSE; +BOOL LLVOAvatar::sDebugAvatarRotation = false; //----------------------------------------------------------------------------- // Helper functions //----------------------------------------------------------------------------- static F32 calc_bouncy_animation(F32 x); -static U32 calc_shame(LLVOVolume* volume, std::set &textures); //----------------------------------------------------------------------------- // LLVOAvatar() @@ -1064,9 +1071,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, LLAvatarAppearance(&gAgentWearables), LLViewerObject(id, pcode, regionp), mSpecialRenderMode(0), - mAttachmentGeometryBytes(-1), - mAttachmentSurfaceArea(-1.f), - mReportedVisualComplexity(-1), + mAttachmentSurfaceArea(0.f), + mAttachmentVisibleTriangleCount(0), + mAttachmentEstTriangleCount(0.f), + mReportedVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN), mTurning(FALSE), mFreezeTimeLangolier(false), mFreezeTimeDead(false), @@ -1076,6 +1084,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mTyping(FALSE), mMeshValid(FALSE), mVisible(FALSE), + mLastImpostorUpdateFrameTime(0.f), mWindFreq(0.f), mRipplePhase( 0.f ), mBelowWater(FALSE), @@ -1112,6 +1121,9 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mUseServerBakes(FALSE), mLastUpdateRequestCOFVersion(-1), mLastUpdateReceivedCOFVersion(-1), + mIsControlAvatar(false), + mIsUIAvatar(false), + mEnableDefaultMotions(true), // mHasPhysicsParameters( false ), mIdleMinute(0), @@ -1146,6 +1158,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNeedsImpostorUpdate = TRUE; mNeedsAnimUpdate = TRUE; + mNeedsExtentUpdate = true; + mImpostorDistance = 0; mImpostorPixelArea = 0; @@ -1183,8 +1197,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) @@ -1231,9 +1252,6 @@ LLVOAvatar::~LLVOAvatar() LL_DEBUGS("Avatar") << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << LL_ENDL; std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer()); -#if USE_LL_APPEARANCE_CODE - mAttachmentPoints.clear(); -#endif mDead = TRUE; @@ -1402,8 +1420,8 @@ std::string LLVOAvatar::rezStatusToString(S32 rez_status) { if (rez_status==0) return "cloud"; if (rez_status==1) return "gray"; - if (rez_status==2) return "textured"; - if (rez_status==3) return "textured_and_downloaded"; + if (rez_status==2) return "downloading"; + if (rez_status==3) return "full"; return "unknown"; } @@ -1473,7 +1491,7 @@ void LLVOAvatar::dumpBakedStatus() const ETextureIndex index = baked_dict->mTextureIndex; if (!inst->isTextureDefined(index)) { - LL_CONT << " " << LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mName; + LL_CONT << " " << (LLAvatarAppearanceDictionary::getInstance()->getTexture(index) ? LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mName : ""); } } LL_CONT << " ) " << inst->getUnbakedPixelAreaRank(); @@ -1556,6 +1574,8 @@ void LLVOAvatar::initClass() gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST_ID,"walk_adjust"); SHClientTagMgr::instance(); //Instantiate. Parse. Will fetch a new tag file if AscentUpdateTagsOnLoad is true. + + LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged); } @@ -1564,7 +1584,7 @@ void LLVOAvatar::cleanupClass() } // virtual -void LLVOAvatar::initInstance(void) +void LLVOAvatar::initInstance() { //------------------------------------------------------------------------- // register motions @@ -1616,6 +1636,7 @@ void LLVOAvatar::initInstance(void) registerMotion( ANIM_AGENT_PHYSICS_MOTION_ID, LLPhysicsMotionController::create ); registerMotion( ANIM_AGENT_EDITING_ID, LLEditingMotion::create ); registerMotion( ANIM_AGENT_EYE_ID, LLEyeMotion::create ); + //registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); registerMotion( ANIM_AGENT_FLY_ADJUST_ID, LLFlyAdjustMotion::create ); registerMotion( ANIM_AGENT_HAND_MOTION_ID, LLHandMotion::create ); registerMotion( ANIM_AGENT_HEAD_ROT_ID, LLHeadRotMotion::create ); @@ -1634,6 +1655,8 @@ void LLVOAvatar::initInstance(void) //VTPause(); // VTune mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) ); + + mInitFlags |= 1<<1; } // virtual @@ -1667,7 +1690,7 @@ const LLVector3 LLVOAvatar::getRenderPosition() const { return getPositionAgent(); } - else if (isRoot() || !mDrawable->getParent()) + else if (isRoot()/* || !mDrawable->getParent()*/) // Animesh- { F32 fixup; if ( hasPelvisFixup( fixup) ) @@ -1705,6 +1728,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() - @@ -1715,9 +1761,8 @@ 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); @@ -1726,83 +1771,139 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) } } -void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) + +static LLTrace::BlockTimerStatHandle FTM_AVATAR_EXTENT_UPDATE("Av Upd Extent"); + +void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { - static const LLCachedControl control_derender_huge_attachments("DerenderHugeAttachments", true); - static const LLCachedControl control_max_attachment_span("MaxAttachmentSpan", 5.0f * DEFAULT_MAX_PRIM_SCALE); - - LLVector4a buffer(0.25f); - LLVector4a pos; - pos.load3(getRenderPosition().mV); - newMin.setSub(pos, buffer); - newMax.setAdd(pos, buffer); - - float max_attachment_span = llmax(DEFAULT_MAX_PRIM_SCALE, control_max_attachment_span); - //stretch bounding box by joint positions - for (polymesh_map_t::iterator i = mPolyMeshes.begin(); i != mPolyMeshes.end(); ++i) + LL_RECORD_BLOCK_TIME(FTM_AVATAR_EXTENT_UPDATE); + + static const LLCachedControl control_derender_huge_attachments("DerenderHugeAttachments", true); + static const LLCachedControl box_detail("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; + 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; + + //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()) { - LLPolyMesh* mesh = i->second; - for (U32 joint_num = 0; joint_num < mesh->mJointRenderData.size(); joint_num++) + for (polymesh_map_t::iterator i = mPolyMeshes.begin(); i != mPolyMeshes.end(); ++i) { - update_min_max(newMin, newMax, mesh->mJointRenderData[joint_num]->mWorldMatrix->getRow()); + LLPolyMesh* mesh = i->second; + for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.size(); joint_num++) + { + static const LLVector4Logical mask = _mm_load_ps((F32*)&S_V4LOGICAL_MASK_TABLE[3 * 4]); + LLVector4a trans; + trans.setSelectWithMask(mask, _mm_setzero_ps(), mesh->mJointRenderData[joint_num]->mWorldMatrix->getRow<3>()); + 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); - - mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); - + // 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); + static std::vector removal; - //stretch bounding box by attachments - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + //stretch bounding box by static attachments + if (box_detail >= 2) { - LLViewerJointAttachment* attachment = iter->second; - - if (!attachment->getValid()) + + float max_attachment_span = get_default_max_prim_scale() * 5.0f; +#if SLOW_ATTACHMENT_LIST + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { - continue ; - } + 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 && !attached_object->isHUDAttachment()) + if (attachment->getValid()) { - LLDrawable* drawable = attached_object->mDrawable; - if (drawable && !drawable->isState(LLDrawable::RIGGED)) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - LLSpatialBridge* bridge = drawable->getSpatialBridge(); - if (bridge) + // Don't we need to look at children of attached_object as well? + const LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + LLViewerJointAttachment* attachment = iter.second; + if (!attachment->getValid()) + continue; + const LLViewerObject* attached_object = iter.first; +#endif + if (attached_object && !attached_object->isHUDAttachment()) { - 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; - - // 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) + const LLVOVolume *vol = dynamic_cast(attached_object); + if (vol && vol->isAnimatedObject()) { - update_min_max(newMin,newMax,ext[0]); - update_min_max(newMin,newMax,ext[1]); + // 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; + } } - else if(control_derender_huge_attachments) + if (vol && vol->isRiggedMesh()) { - removal.push_back((LLViewerObject *)attached_object); + 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; + + // 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]); + } + else if(control_derender_huge_attachments) + { + removal.push_back((LLViewerObject *)attached_object); + } + } } } } @@ -1820,10 +1921,50 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) removal.clear(); } - //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]; + } - newMin.sub(buffer); - newMax.add(buffer); + if (joint && rig_info && rig_info->isRiggedTo()) + { + LLViewerJointAttachment *as_joint_attach = dynamic_cast(joint); + if (as_joint_attach && as_joint_attach->getIsHUDAttachment()) + { + // Ignore bounding box of HUD joints + continue; + } + const LLMatrix4a& mat = joint->getWorldMatrix(); + LLVector4a new_extents[2]; + 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; + //} + } + } + } + + // 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) @@ -1885,13 +2026,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(); } @@ -1947,7 +2104,7 @@ void LLVOAvatar::renderBones() } else { - if (jointIsRiggedTo(jointp->getName())) + if (jointIsRiggedTo(jointp)) { occ_color = RIGGED_COLOR_OCCLUDED; visible_color = RIGGED_COLOR_VISIBLE; @@ -2074,6 +2231,12 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& return FALSE; } + + if (isControlAvatar()) + { + return FALSE; + } + if (lineSegmentBoundingBox(start, end)) { for (S32 i = 0; i < (S32)mCollisionVolumes.size(); ++i) @@ -2119,6 +2282,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& if (isSelf()) { +#if SLOW_ATTACHMENT_LIST for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -2130,6 +2294,12 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& ++attachment_iter) { LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{ + const LLViewerJointAttachment* attachment = iter.second; + const LLViewerObject* attached_object = iter.first; +#endif if (attached_object && !attached_object->isDead() && attachment->getValid()) { @@ -2182,7 +2352,8 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector { LLVector4a local_end = end; LLVector4a local_intersection; - + +#if SLOW_ATTACHMENT_LIST for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -2194,7 +2365,12 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector ++attachment_iter) { LLViewerObject* attached_object = (*attachment_iter); - +#else + for(auto& iter : mAttachedObjectsVector) + {{ + LLViewerObject* attached_object = iter.first; +#endif + if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, face_hit, &local_intersection, tex_coord, normal, tangent)) { local_end = local_intersection; @@ -2276,7 +2452,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 @@ -2336,7 +2516,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; @@ -2390,12 +2570,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) @@ -2422,13 +2605,11 @@ void LLVOAvatar::resetSkeleton(bool reset_animations) //----------------------------------------------------------------------------- void LLVOAvatar::releaseMeshData() { - if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy) + if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || isUIAvatar()) { return; } - //LL_DEBUGS() << "Releasing mesh data" << LL_ENDL; - // cleanup mesh data for (avatar_joint_list_t::iterator iter = mMeshLOD.begin(); iter != mMeshLOD.end(); @@ -2476,6 +2657,10 @@ void LLVOAvatar::releaseMeshData() void LLVOAvatar::restoreMeshData() { llassert(!isSelf()); + if (mDrawable.isNull()) + { + return; + } //LL_INFOS() << "Restoring" << LL_ENDL; mMeshValid = TRUE; @@ -2654,9 +2839,6 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, } } - //LL_INFOS() << getRotation() << LL_ENDL; - //LL_INFOS() << getPosition() << LL_ENDL; - return retval; } @@ -2763,6 +2945,18 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, 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); + } + checkTextureLoading() ; // force immediate pixel area update on avatars using last frames data (before drawable or camera updates) @@ -2773,7 +2967,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, 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; @@ -2844,23 +3038,21 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) && LLVoiceClient::getInstance()->getVoiceEnabled(mID); + LL_RECORD_BLOCK_TIME(FTM_MISC_UPDATE); + idleUpdateVoiceVisualizer(voice_enabled); + idleUpdateMisc(detailed_update); + idleUpdateAppearanceAnimation(); + if (detailed_update) { - LL_RECORD_BLOCK_TIME(FTM_MISC_UPDATE); - idleUpdateVoiceVisualizer(voice_enabled); - idleUpdateMisc(detailed_update); - idleUpdateAppearanceAnimation(); - if (detailed_update) - { - LL_RECORD_BLOCK_TIME(FTM_DETAIL_UPDATE); - idleUpdateLipSync(voice_enabled); - idleUpdateLoadingEffect(); - idleUpdateBelowWater(); // wind effect uses this - idleUpdateWindEffect(); - } - - idleUpdateNameTag( mLastRootPos ); - idleUpdateRenderCost(); + LL_RECORD_BLOCK_TIME(FTM_DETAIL_UPDATE); + idleUpdateLipSync(voice_enabled); + idleUpdateLoadingEffect(); + idleUpdateBelowWater(); // wind effect uses this + idleUpdateWindEffect(); } + + idleUpdateNameTag(mLastRootPos); + idleUpdateRenderComplexity(); } void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) @@ -2963,7 +3155,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 ); @@ -2996,7 +3188,8 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) if (detailed_update || !sUseImpostors) { LL_RECORD_BLOCK_TIME(FTM_ATTACHMENT_UPDATE); - /*for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); +#if SLOW_ATTACHMENT_LIST + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) { @@ -3006,25 +3199,19 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject* attached_object = (*attachment_iter);*/ - std::vector >::iterator attachment_iter = mAttachedObjectsVector.begin(); - for(;attachment_iter!=mAttachedObjectsVector.end();++attachment_iter) + LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) {{ - LLViewerJointAttachment* attachment = attachment_iter->second; - LLViewerObject* attached_object = attachment_iter->first; + LLViewerJointAttachment* attachment = iter.second; + LLViewerObject* attached_object = iter.first; +#endif - if( !attached_object || - attached_object->isDead() || - !attached_object->mDrawable || - !attachment || - !attachment->getValid()) - continue; - - BOOL visibleAttachment = visible || - !attached_object->mDrawable->getSpatialBridge() || - attached_object->mDrawable->getSpatialBridge()->getRadius() >= 2.f; + BOOL visibleAttachment = visible || (attached_object && + !(attached_object->mDrawable->getSpatialBridge() && + attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); - if (visibleAttachment) + if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) { // if selecting any attachments, update all of them as non-damped if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment()) @@ -3080,8 +3267,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) @@ -3100,7 +3289,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) } } - if(mDrawable) + if (mDrawable.notNull()) { mDrawable->movePartition(); @@ -3228,19 +3417,22 @@ void LLVOAvatar::idleUpdateLoadingEffect() // update visibility when avatar is partially loaded if (updateIsFullyLoaded()) // changed? { - if (isFullyLoaded() && mFirstFullyVisible && isSelf()) - { - LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL; - mFirstFullyVisible = FALSE; - LLAppearanceMgr::instance().onFirstFullyVisible(); - } - if (isFullyLoaded() && mFirstFullyVisible && !isSelf()) - { - LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL; - mFirstFullyVisible = FALSE; - } if (isFullyLoaded()) { + if (mFirstFullyVisible) + { + mFirstFullyVisible = FALSE; + if (isSelf()) + { + LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + LLAppearanceMgr::instance().onFirstFullyVisible(); + } + else + { + LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + } + } + deleteParticleSource(); updateLOD(); } @@ -3273,7 +3465,7 @@ 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 + if (!mIsDummy && !isTooComplex()) { setParticleSource(particle_parameters, getID()); } @@ -4092,23 +4284,17 @@ void LLVOAvatar::slamPosition() bool LLVOAvatar::isVisuallyMuted() const { - bool muted = false; - if (!isSelf()) { - static LLCachedControl max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit", 0); - static LLCachedControl max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 0.0); static const LLCachedControl show_muted(gSavedSettings, "LiruLegacyDisplayMuteds", false); - - muted = (!show_muted && LLMuteList::getInstance()->isMuted(getID())) || - (mAttachmentGeometryBytes > (S32)max_attachment_bytes && max_attachment_bytes > 0) || - (mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f) || + return (!show_muted && LLMuteList::getInstance()->isMuted(getID()) || // [RLVa:LF] - RLV 2.9 camavdist (gRlvHandler.hasBehaviour(RLV_BHVR_CAMAVDIST) && (gAgent.getPosGlobalFromAgent(const_cast(*this).getCharacterPosition()) - gAgent.getPosGlobalFromAgent(gAgentAvatarp->getRenderPosition())).magVec() > gRlvHandler.camPole(RLV_BHVR_CAMAVDIST)) || // [/RLVa:LF] - isLangolier(); + isLangolier() || + isTooComplex()); } - return muted; + return false; } void LLVOAvatar::resetFreezeTime() @@ -4122,96 +4308,179 @@ void LLVOAvatar::resetFreezeTime() } +void LLVOAvatar::updateAppearanceMessageDebugText() +{ + S32 central_bake_version = -1; + LLViewerRegion* region = getRegion(); + if (region) + { + 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, + mUseServerBakes, 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); + } + 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 = region && region->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); + + 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); + F32 elapsed = mLastAppearanceMessageTimer.getElapsedTimeF32(); + static const char *elapsed_chars = "Xx*..."; + U32 bucket = U32(elapsed*2); + if (bucket < strlen(elapsed_chars)) + { + debug_line += llformat(" %c", elapsed_chars[bucket]); + } + addDebugText(debug_line); +} + +LLViewerInventoryItem* getObjectInventoryItem(LLViewerObject *vobj, LLUUID asset_id) +{ + LLViewerInventoryItem *item = NULL; + + if (vobj) + { + if (vobj->getInventorySerial() <= 0) + { + vobj->requestInventory(); + } + item = vobj->getInventoryItemByAsset(asset_id); + } + return item; +} + +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; +} + +void LLVOAvatar::updateAnimationDebugText() +{ + addDebugText(llformat("at=%.1f", mMotionController.getAnimTime())); + 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(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; + name = motionp->getID().asString(); + output = llformat("%s - %d", + name.c_str(), + (U32)motionp->getPriority()); + } + else + { + output = llformat("%s - %d", + motion_name.c_str(), + (U32)motionp->getPriority()); + } + if (motionp->server()) + { +#ifdef SHOW_ASSERT + output += llformat(" rt=%.1f r=%d s=0x%xl", motionp->getRuntime(), motionp->mReadyEvents, motionp->server()); +#else + output += llformat(" rt=%.1f s=0x%xl", motionp->getRuntime(), motionp->server()); +#endif + } + addDebugText(output); + } + } +} + void LLVOAvatar::updateDebugText() { + // Leave mDebugText uncleared here, in case a derived class has added some state first if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) { - S32 central_bake_version = -1; - LLViewerRegion* region = getRegion(); - if (region) - { - 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, - mUseServerBakes, 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); - } - else - { - debug_line += llformat(" - cof rcv:%d", last_received_cof_version); - } - debug_line += llformat(" bsz-z: %f avofs-z: %f", mBodySize[2], mAvatarOffset[2]); - bool hover_enabled = region && region->avatarHoverHeightEnabled(); - debug_line += hover_enabled ? " H" : " h"; - const LLVector3& hover_offset = getHoverOffset(); - if (hover_offset[2] != 0.0) - { - debug_line += llformat(" hov_z: %f", hover_offset[2]); - debug_line += llformat(" %s", (mIsSitting ? "S" : "T")); - debug_line += llformat("%s", (isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED) ? "G" : "-")); - } - F32 elapsed = mLastAppearanceMessageTimer.getElapsedTimeF32(); - static const char *elapsed_chars = "Xx*..."; - U32 bucket = U32(elapsed*2); - if (bucket < strlen(elapsed_chars)) - { - debug_line += llformat(" %c", elapsed_chars[bucket]); - } - addDebugText(debug_line); + updateAppearanceMessageDebugText(); } + if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked")) { if (!mBakedTextureDebugText.empty()) addDebugText(mBakedTextureDebugText); } + // Develop -> Avatar -> Animation Info if (LLVOAvatar::sShowAnimationDebug) { - addDebugText(llformat("at=%.1f", mMotionController.getAnimTime())); - 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()) - { - output = llformat("%s - %d", - motionp->getID().asString().c_str(), - (U32)motionp->getPriority()); - } - else - { - output = llformat("%s - %d", - motionp->getName().c_str(), - (U32)motionp->getPriority()); - } - if (motionp->server()) - { -#ifdef SHOW_ASSERT - output += llformat(" rt=%.1f r=%d s=0x%xl", motionp->getRuntime(), motionp->mReadyEvents, motionp->server()); -#else - output += llformat(" rt=%.1f s=0x%xl", motionp->getRuntime(), motionp->server()); -#endif - } - addDebugText(output); - } - } + updateAnimationDebugText(); } if (!mDebugText.size() && mText.notNull()) @@ -4228,429 +4497,16 @@ void LLVOAvatar::updateDebugText() } //------------------------------------------------------------------------ -// 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) -{ - // Frozen! - if (areAnimationsPaused()) +void LLVOAvatar::updateFootstepSounds() +{ + if (mIsDummy) { - updateMotions(LLCharacter::NORMAL_UPDATE); // This is necessary to get unpaused again. - return FALSE; + return; } - - updateDebugText(); - - if (gNoRender) - { - // Hack if we're running drones... - if (isSelf()) - { - gAgent.setPositionAgent(getPositionAgent()); - } - return FALSE; - } - - if (!mIsBuilt) - { - return FALSE; - } - - BOOL visible = isVisible(); - - // 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 - //-------------------------------------------------------------------- - - bool visually_muted = isVisuallyMuted(); - if (visible && (!isSelf() || visually_muted) && !mIsDummy && 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 (mVisibilityRank <= LLVOAvatar::sMaxVisible || - 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 - //impostor camera near clip plane - mUpdatePeriod = 1; - } - else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4) - { //background avatars are REALLY slow updating impostors - mUpdatePeriod = 16; - } - 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 - { - //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; - } - - // change animation time quanta based on avatar render load - if (!isSelf() && !mIsDummy) - { - 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; - 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"); - } - 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(); - // - //Singu note: this appears to be a safety catch: - // when getParent() is NULL and we're not playing ANIM_AGENT_SIT_GROUND_CONSTRAINED then we aren't sitting! - // The previous call existed in an attempt to fix this inconsistent state by standing up from an object. - // However, since getParent() is NULL that function would crash! - // Since we never got crash reports regarding to this, that apparently never happened, except, I discovered - // today, when you are ground sitting and then LLMotionController::deleteAllMotions or - // LLMotionController::deactivateAllMotions is called, which seems to only happen when previewing an - // to-be-uploaded animation on your own avatar (while ground sitting). - // Hence, we DO need this safety net but not for standing up from an object but for standing up from the ground. - // I fixed the crash in getOffObject(), so it's ok to call that. In order to make things consistent with - // the server we need to actually stand up though, or we can't move anymore afterwards. - if (isSelf()) - { - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); - } - // - } - - //-------------------------------------------------------------------- - // 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())) - { - //-------------------------------------------------------------------- - // get timing info - // handle initial condition case - //-------------------------------------------------------------------- - F32 animation_time = mAnimTimer.getElapsedTimeF32(); - if (mTimeLast == 0.0f) - { - mTimeLast = animation_time; - - // put the pelvis at slaved position/mRotation - mRoot->setWorldPosition( getPositionAgent() ); // first frame - mRoot->setWorldRotation( getRotation() ); - } - - //-------------------------------------------------------------------- - // dont' let dT get larger than 1/5th of a second - //-------------------------------------------------------------------- - F32 deltaTime = animation_time - mTimeLast; - - deltaTime = llclamp( deltaTime, DELTA_TIME_MIN, DELTA_TIME_MAX ); - mTimeLast = animation_time; - - mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f); - - //-------------------------------------------------------------------- - // compute the position of the avatar's root - //-------------------------------------------------------------------- - LLVector3d root_pos; - LLVector3d ground_under_pelvis; - - if (isSelf()) - { - gAgent.setPositionAgent(getRenderPosition()); - } - - root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition()); - root_pos.mdV[VZ] += getVisualParamWeight(AVATAR_HOVER); - - - 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)) || - foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE); - - if (in_air && !mInAir) - { - mTimeInAir.reset(); - } - mInAir = in_air; - - // 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) - { - root_pos += LLVector3d(getHoverOffset()); - } - - LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); - - if (newPosition != mRoot->getXform()->getWorldPosition()) - { - mRoot->touch(); - mRoot->setWorldPosition( newPosition ); // regular update - } - - - //-------------------------------------------------------------------- - // Propagate viewer object rotation to root of avatar - //-------------------------------------------------------------------- - if (!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(); - static LLCachedControl TurnAround("TurnAroundWhenWalkingBackwards"); - if (!TurnAround && (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 = LLMatrix4(mRoot->getWorldMatrix().getF32ptr()).quaternion(); - F32 root_roll, root_pitch, root_yaw; - root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw); - - if (sDebugAvatarRotation) - { - LL_INFOS() << "root_roll " << RAD_TO_DEG * root_roll - << " root_pitch " << RAD_TO_DEG * root_pitch - << " root_yaw " << RAD_TO_DEG * root_yaw - << LL_ENDL; - } - - // 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().getRow().getF32ptr() ); - - static const LLCachedControl s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow", 60.0); - static const LLCachedControl s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast", 2.0); - static const LLCachedControl useRealisticMouselook("UseRealisticMouselook"); - F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, useRealisticMouselook ? s_pelvis_rot_threshold_slow * 2 : s_pelvis_rot_threshold_slow, s_pelvis_rot_threshold_fast); - - if (self_in_mouselook && !useRealisticMouselook) - { - 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) ); - - } - } - else if (mDrawable.notNull()) - { - LLVector3 pos = mDrawable->getPosition(); - const LLQuaternion& rot = mDrawable->getRotation(); - pos += getHoverOffset() * rot; - mRoot->setPosition(pos); - mRoot->setRotation(rot); - } - - //------------------------------------------------------------------------- - // Update character motions - //------------------------------------------------------------------------- - // store data relevant to motions - mSpeed = speed; - - // update animations - if (mSpecialRenderMode == 1) // Animation Preview - updateMotions(LLCharacter::FORCE_UPDATE); - else - updateMotions(LLCharacter::NORMAL_UPDATE); - - // Special handling for sitting on ground. - if (!getParent() && (mIsSitting || was_sit_ground_constrained)) - { - F32 off_z = LLVector3d(getHoverOffset()).mdV[VZ]; - if (off_z != 0.0) - { - LLVector3 pos = mRoot->getWorldPosition(); - pos.mV[VZ] += off_z; - mRoot->touch(); - mRoot->setWorldPosition(pos); - } - } - - // update head position - updateHeadOffset(); //------------------------------------------------------------------------- // Find the ground under each foot, these are used for a variety @@ -4661,13 +4517,14 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) 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); 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) + if (!isSitting()) { //------------------------------------------------------------------------- // Figure out which foot is on ground @@ -4717,10 +4574,6 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) if ( playSound ) { -// F32 gain = clamp_rescale( mSpeedAccum, -// AUDIO_STEP_LO_SPEED, AUDIO_STEP_HI_SPEED, -// AUDIO_STEP_LO_GAIN, AUDIO_STEP_HI_GAIN ); - const F32 STEP_VOLUME = 0.5f; const LLUUID& step_sound_id = getStepSound(); @@ -4733,7 +4586,534 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) } } } +} +//------------------------------------------------------------------------ +// 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 (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() + || 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 + // impostor camera near clip plane + mUpdatePeriod = 1; + } + else if ( shouldImpostor(4) ) + { //background avatars are REALLY slow updating impostors + mUpdatePeriod = 16; + } + else if ( shouldImpostor(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 + { + //nearby avatars, update the impostors more frequently. + mUpdatePeriod = 4; + } + } + else + { + mUpdatePeriod = 1; + } +} + +//------------------------------------------------------------------------ +// 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. + + 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(); + static LLCachedControl TurnAround("TurnAroundWhenWalkingBackwards"); + if (!TurnAround && (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 = LLMatrix4(mRoot->getWorldMatrix().getF32ptr()).quaternion(); + F32 root_roll, root_pitch, root_yaw; + root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw); + + if (sDebugAvatarRotation) + { + LL_INFOS() << "root_roll " << RAD_TO_DEG * root_roll + << " root_pitch " << RAD_TO_DEG * root_pitch + << " root_yaw " << RAD_TO_DEG * root_yaw + << LL_ENDL; + } + + // 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().getRow().getF32ptr() ); + + static const LLCachedControl s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow", 60.0); + static const LLCachedControl s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast", 2.0); + static const LLCachedControl useRealisticMouselook("UseRealisticMouselook"); + F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, useRealisticMouselook ? s_pelvis_rot_threshold_slow * 2 : s_pelvis_rot_threshold_slow, s_pelvis_rot_threshold_fast); + + if (self_in_mouselook && !useRealisticMouselook) + { + 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. + { + 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; + 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"); + } + mMotionController.setTimeStep(time_step); + } +} + +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. + + //-------------------------------------------------------------------- + // get timing info + // handle initial condition case + //-------------------------------------------------------------------- + F32 animation_time = mAnimTimer.getElapsedTimeF32(); + if (mTimeLast == 0.0f) + { + mTimeLast = animation_time; + + // put the pelvis at slaved position/mRotation + mRoot->setWorldPosition( getPositionAgent() ); // first frame + mRoot->setWorldRotation( getRotation() ); + } + + //-------------------------------------------------------------------- + // dont' let dT get larger than 1/5th of a second + //-------------------------------------------------------------------- + F32 delta_time = animation_time - mTimeLast; + + delta_time = llclamp( delta_time, DELTA_TIME_MIN, DELTA_TIME_MAX ); + mTimeLast = animation_time; + + mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f); + + //-------------------------------------------------------------------- + // compute the position of the avatar's root + //-------------------------------------------------------------------- + LLVector3d root_pos; + LLVector3d ground_under_pelvis; + + if (isSelf()) + { + gAgent.setPositionAgent(getRenderPosition()); + } + + 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)) || + foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE); + + if (in_air && !mInAir) + { + mTimeInAir.reset(); + } + mInAir = in_air; + + // SL-402: with the ability to animate the position of joints + // that affect the body size calculation, computed body size + // can get stale much more easily. Simplest fix is to update + // it frequently. + // SL-427: this appears to be too frequent, moving to only do on animation state change. + //computeBodySize(); + + // 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 (!isSitting() && !was_sit_ground_constrained) + { + root_pos += LLVector3d(getHoverOffset()); + } + + LLControlAvatar *cav = dynamic_cast(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(); + mRoot->setWorldPosition( newPosition ); // regular update + } + } + + //-------------------------------------------------------------------- + // Propagate viewer object rotation to root of avatar + //-------------------------------------------------------------------- + if (!isControlAvatar() && !isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS)) + { + // Rotation fixups for avatars in motion. + // Skip for animated objects. + updateOrientation(agent, speed, delta_time); + } + } + else if (mDrawable.notNull()) + { + LLVector3 pos = mDrawable->getPosition(); + const LLQuaternion& rot = mDrawable->getRotation(); + pos += getHoverOffset() * rot; + mRoot->setPosition(pos); + mRoot->setRotation(rot); + } +} + +//------------------------------------------------------------------------ +// 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) +{ + // Frozen! + if (areAnimationsPaused()) + { + updateMotions(LLCharacter::NORMAL_UPDATE); // This is necessary to get unpaused again. + return FALSE; + } + + updateDebugText(); + + if (gNoRender) + { + // Hack if we're running drones... + if (isSelf()) + { + gAgent.setPositionAgent(getPositionAgent()); + } + return FALSE; + } + + 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(this); + is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects + } + + // 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; + + //-------------------------------------------------------------------- + + // 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 + //updateTimeStep(); + if (getParent() && !isSitting()) + { + sitOnObject((LLViewerObject*)getParent()); + } + else if (!getParent() && isSitting() && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED)) + { + getOffObject(); + // + //Singu note: this appears to be a safety catch: + // when getParent() is NULL and we're not playing ANIM_AGENT_SIT_GROUND_CONSTRAINED then we aren't sitting! + // The previous call existed in an attempt to fix this inconsistent state by standing up from an object. + // However, since getParent() is NULL that function would crash! + // Since we never got crash reports regarding to this, that apparently never happened, except, I discovered + // today, when you are ground sitting and then LLMotionController::deleteAllMotions or + // LLMotionController::deactivateAllMotions is called, which seems to only happen when previewing an + // to-be-uploaded animation on your own avatar (while ground sitting). + // Hence, we DO need this safety net but not for standing up from an object but for standing up from the ground. + // I fixed the crash in getOffObject(), so it's ok to call that. In order to make things consistent with + // the server we need to actually stand up though, or we can't move anymore afterwards. + if (isSelf()) + { + gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + } + // + } + + //-------------------------------------------------------------------- + // 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 + //------------------------------------------------------------------------- + // store data relevant to motions + mSpeed = speed; + + // update animations + if (mSpecialRenderMode == 1) // Animation Preview + { + updateMotions(LLCharacter::FORCE_UPDATE); + } + else + { + updateMotions(LLCharacter::NORMAL_UPDATE); + } + + // Special handling for sitting on ground. + if (!getParent() && (isSitting() || was_sit_ground_constrained)) + { + F32 off_z = LLVector3d(getHoverOffset()).mdV[VZ]; + if (off_z != 0.0) + { + LLVector3 pos = mRoot->getWorldPosition(); + pos.mV[VZ] += off_z; + mRoot->touch(); + mRoot->setWorldPosition(pos); + } + } + + // update head position + updateHeadOffset(); + + // Generate footstep sounds when feet hit the ground + updateFootstepSounds(); + + // Update child joints as needed. mRoot->updateWorldMatrixChildren(); //mesh vertices need to be reskinned @@ -4741,6 +5121,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) return TRUE; } + //----------------------------------------------------------------------------- // updateHeadOffset() //----------------------------------------------------------------------------- @@ -4755,22 +5136,22 @@ void LLVOAvatar::updateHeadOffset() { midEyePt = midEyePt * ~mDrawable->getWorldRotation(); } - if (mIsSitting) + if (isSitting()) { - mHeadOffset = midEyePt; + mHeadOffset = midEyePt; } else { F32 u = llmax(0.f, HEAD_MOVEMENT_AVG_TIME - (1.f / gFPSClamped)); - mHeadOffset = lerp(midEyePt, mHeadOffset, u); + mHeadOffset = lerp(midEyePt, mHeadOffset, u); } } //------------------------------------------------------------------------ // postPelvisSetRecalc //------------------------------------------------------------------------ void LLVOAvatar::postPelvisSetRecalc() -{ - mRoot->updateWorldMatrixChildren(); +{ + mRoot->updateWorldMatrixChildren(); computeBodySize(); dirtyMesh(2); } @@ -4783,7 +5164,7 @@ void LLVOAvatar::updateVisibility() if (mIsDummy) { - visible = TRUE; + visible = FALSE; } else if (mDrawable.isNull()) { @@ -4800,14 +5181,14 @@ void LLVOAvatar::updateVisibility() visible = FALSE; } - if(isSelf()) + if (isSelf()) { if (!gAgentWearables.areWearablesLoaded()) { visible = FALSE; } } - else if( !mFirstAppearanceMessageReceived ) + else if (!mFirstAppearanceMessageReceived) { visible = FALSE; } @@ -4857,19 +5238,29 @@ void LLVOAvatar::updateVisibility() LL_INFOS() << "PA: " << getPositionAgent() << LL_ENDL; /*LL_INFOS() << "SPA: " << sel_pos_agent << LL_ENDL; LL_INFOS() << "WPA: " << wrist_right_pos_agent << LL_ENDL;*/ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + + +#if SLOW_ATTACHMENT_LIST + 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) + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { if (LLViewerObject *attached_object = (*attachment_iter)) +#else + for (auto& iter : mAttachedObjectsVector) + {{ + const LLViewerObject *attached_object = iter.first; + const LLViewerJointAttachment *attachment = iter.second; + if (attachment) +#endif { - if (attached_object->mDrawable->isVisible()) + if (attached_object && attached_object->mDrawable->isVisible()) { LL_INFOS() << attachment->getName() << " visible" << LL_ENDL; } @@ -4897,7 +5288,8 @@ void LLVOAvatar::updateVisibility() } else { - if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP) + if (mMeshValid && + (isControlAvatar() || mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP)) { releaseMeshData(); } @@ -4928,6 +5320,11 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) 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); @@ -5100,7 +5497,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) { 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) @@ -5110,7 +5507,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) 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) @@ -5120,7 +5517,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) 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) @@ -5152,7 +5549,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) 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); @@ -5231,7 +5628,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); @@ -5452,7 +5849,7 @@ void LLVOAvatar::collectLocalTextureUUIDs(std::set& ids) const if (imagep) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)texture_index); - if (texture_dict->mIsLocalTexture) + if (texture_dict && texture_dict->mIsLocalTexture) { ids.insert(imagep->getID()); } @@ -5611,8 +6008,8 @@ void LLVOAvatar::updateTextures() if (imagep) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)texture_index); - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - if (texture_dict->mIsLocalTexture) + const EBakedTextureIndex baked_index = texture_dict ? texture_dict->mBakedTextureIndex : EBakedTextureIndex::BAKED_NUM_INDICES; + if (texture_dict && texture_dict->mIsLocalTexture) { addLocalTextureStats((ETextureIndex)texture_index, imagep, texel_area_ratio, render_avatar, mBakedTextureDatas[baked_index].mIsUsed); } @@ -5864,10 +6261,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 { @@ -5877,13 +6277,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 @@ -5964,6 +6370,12 @@ void LLVOAvatar::processAnimationStateChanges() //----------------------------------------------------------------------------- BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL start ) { + // SL-402, SL-427 - we need to update body size often enough to + // keep appearances in sync, but not so often that animations + // cause constant jiggling of the body or camera. Possible + // compromise is to do it on animation changes: + computeBodySize(); + BOOL result = FALSE; if ( start ) // start animation @@ -6137,6 +6549,11 @@ LLUUID LLVOAvatar::remapMotionID(const LLUUID& id) if (use_new_walk_run) result = ANIM_AGENT_RUN_NEW; } + // keeps in sync with setSex() related code (viewer controls sit's sex) + else if (id == ANIM_AGENT_SIT_FEMALE) + { + result = ANIM_AGENT_SIT; + } } @@ -6199,6 +6616,15 @@ BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) return LLCharacter::stopMotion(remap_id, stop_immediate); } +//----------------------------------------------------------------------------- +// hasMotionFromSource() +//----------------------------------------------------------------------------- +// virtual +bool LLVOAvatar::hasMotionFromSource(const LLUUID& source_id) +{ + return false; +} + //----------------------------------------------------------------------------- // stopMotionFromSource() //----------------------------------------------------------------------------- @@ -6295,7 +6721,7 @@ 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 ) @@ -6308,62 +6734,20 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id) return false; } -bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name) +bool LLVOAvatar::jointIsRiggedTo(const LLJoint *joint) const { - 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) + if (joint) + { + const LLJointRiggingInfoTab& tab = mJointRiggingInfoTab; + S32 joint_num = joint->getJointNum(); + if (joint_num < tab.size() && tab[joint_num].isRiggedTo()) { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && jointIsRiggedTo(joint_name, attached_object)) - { - return true; - } + return true; } - } + } return false; } -bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo) -{ - // 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(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()) - { - return true; - } - } - - return false; -} - void LLVOAvatar::clearAttachmentOverrides() { for (S32 i=0; iclearAttachmentScaleOverrides(); } } + + 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(); } //----------------------------------------------------------------------------- @@ -6382,42 +6780,137 @@ void LLVOAvatar::clearAttachmentOverrides() //----------------------------------------------------------------------------- void LLVOAvatar::rebuildAttachmentOverrides() { - // Attachment points - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + clearAttachmentOverrides(); + + // Handle the case that we're resetting the skeleton of an animated object. + LLControlAvatar *control_av = dynamic_cast(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 +#if SLOW_ATTACHMENT_LIST + 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(); + if (attachment_pt) + { + 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; +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + LLViewerObject *vo = iter.first; +#endif + // Attached animated objects affect joints in their control + // avs, not the avs to which they are attached. + if (vo && !vo->isAnimatedObject()) + { + addAttachmentOverridesForObject(vo); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// updateAttachmentOverrides +// +// This is intended to give the same results as +// rebuildAttachmentOverrides(), while avoiding redundant work. +// ----------------------------------------------------------------------------- +void LLVOAvatar::updateAttachmentOverrides() +{ + LL_DEBUGS("AnimatedObjects") << "updating" << LL_ENDL; + + std::set meshes_seen; + + // Handle the case that we're updating the skeleton of an animated object. + LLControlAvatar *control_av = dynamic_cast(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 +#if SLOW_ATTACHMENT_LIST + 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; +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + LLViewerObject *vo = iter.first; +#endif + // 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 active_override_meshes = mActiveOverrideMeshes; + for (std::set::iterator it = active_override_meshes.begin(); it != active_override_meshes.end(); ++it) + { + if (meshes_seen.find(*it) == meshes_seen.end()) + { + removeAttachmentOverridesForObject(*it); } } } -//----------------------------------------------------------------------------- // addAttachmentPosOverridesForObject //----------------------------------------------------------------------------- -void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) +void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set* meshes_seen, bool recursive) { - 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; - } + return; + } + LL_DEBUGS("AnimatedObjects") << "adding" << LL_ENDL; + // 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(vo); bool pelvisGotSet = false; @@ -6431,13 +6924,12 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) { return; } - LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); + const LLMeshSkinInfo* pSkinData = vobj->getSkinInfo(); - if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData ) + if ( vobj && vobj->isMesh() && pSkinData ) { - const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - const int jointCnt = pSkinData->mJointNames.size(); + const U32 bindCnt = pSkinData->mAlternateBindMatrix.size(); + const U32 jointCnt = pSkinData->mJointNames.size(); if ((bindCnt > 0) && (bindCnt != jointCnt)) { LL_WARNS_ONCE() << "invalid mesh, bindCnt " << bindCnt << "!= jointCnt " << jointCnt << ", joint overrides will be ignored." << LL_ENDL; @@ -6446,10 +6938,16 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) { const F32 pelvisZOffset = pSkinData->mPelvisOffset; const LLUUID& mesh_id = pSkinData->mMeshID; - bool fullRig = (jointCnt>=(int)JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false; - if ( fullRig ) - { - for ( U32 i=0; i<(U32)jointCnt; ++i ) + + if (meshes_seen) + { + meshes_seen->insert(mesh_id); + } + bool mesh_overrides_loaded = (mActiveOverrideMeshes.find(mesh_id) != mActiveOverrideMeshes.end()); + bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false; + if ( fullRig && !mesh_overrides_loaded ) + { + for ( U32 i=0; imJointNames[i].c_str(); LLJoint* pJoint = getJoint( lookingForJoint ); @@ -6488,10 +6986,12 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) if (!has_fixup_before || (pelvis_fixup_before != pelvis_fixup_after)) { pelvisGotSet = true; - } - + } + } - } + mActiveOverrideMeshes.insert(mesh_id); + onActiveOverrideMeshesChanged(); + } } } @@ -6616,14 +7116,14 @@ void LLVOAvatar::showAttachmentOverrides(bool verbose) const } //----------------------------------------------------------------------------- -// resetJointPositionsOnDetach +// 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 @@ -6632,46 +7132,45 @@ 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); } } //----------------------------------------------------------------------------- -// resetJointPositionsOnDetach +// 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()); + bool dummy; // unused + pJoint->removeAttachmentPosOverride(mesh_id, av_string, dummy); + pJoint->removeAttachmentScaleOverride(mesh_id, av_string); } if ( pJoint && pJoint == pJointPelvis) { removePelvisFixup( mesh_id ); + // SL-315 pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) ); } } postPelvisSetRecalc(); + + mActiveOverrideMeshes.erase(mesh_id); + onActiveOverrideMeshesChanged(); } //----------------------------------------------------------------------------- // getCharacterPosition() @@ -6723,7 +7222,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; @@ -6752,7 +7251,7 @@ F32 LLVOAvatar::getTimeDilation() //----------------------------------------------------------------------------- F32 LLVOAvatar::getPixelArea() const { - if (mIsDummy) + if (isUIAvatar()) { return 100000.f; } @@ -6803,6 +7302,7 @@ BOOL LLVOAvatar::loadSkeletonNode () return TRUE; } + //----------------------------------------------------------------------------- // initAttachmentPoints(): creates attachment points if needed, sets state based on avatar_lad.xml. //----------------------------------------------------------------------------- @@ -6901,7 +7401,26 @@ void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints) //----------------------------------------------------------------------------- void LLVOAvatar::updateVisualParams() { - setSex( (getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE ); + ESex avatar_sex = (getVisualParamWeight("male") > 0.5f) ? SEX_MALE : SEX_FEMALE; + if (getSex() != avatar_sex) + { + if (mIsSitting && findMotion(avatar_sex == SEX_MALE ? ANIM_AGENT_SIT_FEMALE : ANIM_AGENT_SIT) != NULL) + { + // In some cases of gender change server changes sit motion with motion message, + // but in case of some avatars (legacy?) there is no update from server side, + // likely because server doesn't know about difference between motions + // (female and male sit ids are same server side, so it is likely unaware that it + // need to send update) + // Make sure motion is up to date + stopMotion(ANIM_AGENT_SIT); + setSex(avatar_sex); + startMotion(ANIM_AGENT_SIT); + } + else + { + setSex(avatar_sex); + } + } LLCharacter::updateVisualParams(); @@ -7172,7 +7691,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. @@ -7235,7 +7754,12 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o return 0; } - mVisualComplexityStale = true; + if (!viewer_object->isAnimatedObject()) + { + updateAttachmentOverrides(); + } + + updateVisualComplexity(); if (viewer_object->isSelected()) { @@ -7269,14 +7793,6 @@ U32 LLVOAvatar::getNumAttachments() const return num_attachments; } -//----------------------------------------------------------------------------- -// canAttachMoreObjects() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::canAttachMoreObjects() const -{ - return (getNumAttachments() < MAX_AGENT_ATTACHMENTS); -} - //----------------------------------------------------------------------------- // canAttachMoreObjects() // Returns true if we can attach more objects. @@ -7286,6 +7802,57 @@ BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS; } +//----------------------------------------------------------------------------- +// getNumAnimatedObjectAttachments() +//----------------------------------------------------------------------------- +U32 LLVOAvatar::getNumAnimatedObjectAttachments() const +{ + 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. +//----------------------------------------------------------------------------- +U32 LLVOAvatar::getMaxAnimatedObjectAttachments() const +{ + U32 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 = (U32)llmax(0,features["AnimatedObjects"]["MaxAgentAnimatedObjectAttachments"].asInteger()); + } + } + } + return max_attach; +} + +//----------------------------------------------------------------------------- +// canAttachMoreAnimatedObjects() +// Returns true if we can attach more animated objects. +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreAnimatedObjects(U32 n) const +{ + return (getNumAnimatedObjectAttachments() + n) <= getMaxAnimatedObjectAttachments(); +} + //----------------------------------------------------------------------------- // lazyAttach() //----------------------------------------------------------------------------- @@ -7326,7 +7893,7 @@ void LLVOAvatar::lazyAttach() void LLVOAvatar::resetHUDAttachments() { - +#if SLOW_ATTACHMENT_LIST for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -7339,6 +7906,14 @@ void LLVOAvatar::resetHUDAttachments() ++attachment_iter) { const LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + const LLViewerJointAttachment* attachment = iter.second; + if (!attachment->getIsHUDAttachment()) + continue; + const LLViewerObject* attached_object = iter.first; +#endif if (attached_object && attached_object->mDrawable.notNull()) { gPipeline.markMoved(attached_object->mDrawable); @@ -7350,6 +7925,7 @@ void LLVOAvatar::resetHUDAttachments() void LLVOAvatar::rebuildRiggedAttachments( void ) { +#if SLOW_ATTACHMENT_LIST for ( attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter ) { LLViewerJointAttachment* pAttachment = iter->second; @@ -7359,6 +7935,12 @@ void LLVOAvatar::rebuildRiggedAttachments( void ) attachmentIter != attachmentIterEnd; ++attachmentIter) { const LLViewerObject* pAttachedObject = *attachmentIter; +#else + for(auto& iter : mAttachedObjectsVector) + {{ + const LLViewerObject* pAttachedObject = iter.first; + const LLViewerJointAttachment* pAttachment = iter.second; +#endif if ( pAttachment && pAttachedObject->mDrawable.notNull() ) { gPipeline.markRebuild(pAttachedObject->mDrawable); @@ -7374,7 +7956,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO ) LLUUID mesh_id; if (getRiggedMeshID(pVO, mesh_id)) { - resetJointsOnDetach(mesh_id); + //resetJointsOnDetach(mesh_id); if ( gAgentCamera.cameraCustomizeAvatar() ) { gAgent.unpauseAnimation(); @@ -7398,12 +7980,16 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) if (attachment->isObjectAttached(viewer_object)) { - mVisualComplexityStale = true; + updateVisualComplexity(); vector_replace_with_last(mAttachedObjectsVector,std::make_pair(viewer_object,attachment)); - + 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; } @@ -7424,7 +8010,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) //----------------------------------------------------------------------------- void LLVOAvatar::sitDown(BOOL bSitting) { - if (mIsSitting != bSitting) mIdleTimer.reset(); // Sitting changed, not idle + if (isSitting() != bSitting) mIdleTimer.reset(); // Sitting changed, not idle mIsSitting = bSitting; if (isSelf()) { @@ -7541,7 +8127,10 @@ void LLVOAvatar::getOffObject() mRoot->setRotation(cur_rotation_world); mRoot->getXform()->update(); + if (mEnableDefaultMotions) + { startMotion(ANIM_AGENT_BODY_NOISE); + } if (isSelf()) { @@ -7676,6 +8265,7 @@ LLViewerObject* LLVOAvatar::getWornAttachment( const LLUUID& inv_item_id ) LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) const { +#if SLOW_ATTACHMENT_LIST for(attachment_map_t::const_iterator attachment_points_iter = mAttachmentPoints.begin(); attachment_points_iter != mAttachmentPoints.end(); ++attachment_points_iter) @@ -7686,6 +8276,11 @@ LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) cons ++attachment_iter) { LLViewerObject *attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{ + LLViewerObject* attached_object = iter.first; +#endif if (attached_object && attached_object->getID() == target_id) { @@ -7745,6 +8340,18 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, bool 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() @@ -7755,24 +8362,17 @@ BOOL LLVOAvatar::isVisible() const // Determine if we have enough avatar data to render BOOL LLVOAvatar::getIsCloud() const { - // Do we have a shape? - if ((const_cast(this))->visualParamWeightsAreDefault()) + if (mIsDummy) { - return TRUE; + return false; } - if (!isTextureDefined(TEX_LOWER_BAKED) || - !isTextureDefined(TEX_UPPER_BAKED) || - !isTextureDefined(TEX_HEAD_BAKED)) - { - return TRUE; - } - - if (isTooComplex()) - { - return TRUE; - } - return FALSE; + return ( ((const_cast(this))->visualParamWeightsAreDefault())// Do we have a shape? + || ( !isTextureDefined(TEX_LOWER_BAKED) + || !isTextureDefined(TEX_UPPER_BAKED) + || !isTextureDefined(TEX_HEAD_BAKED) + ) + ); } void LLVOAvatar::updateRezzedStatusTimers() @@ -7819,7 +8419,7 @@ void LLVOAvatar::updateRezzedStatusTimers() selfStopPhase("wear_inventory_category", false); selfStopPhase("process_initial_wearables_update", false); - mVisualComplexityStale = true; + updateVisualComplexity(); } } mLastRezzedStatus = rez_status; @@ -8019,7 +8619,7 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) BOOL LLVOAvatar::isFullyLoaded() const { - static LLCachedControl const render_unloaded_avatar("RenderUnloadedAvatar", false); + static const LLCachedControl render_unloaded_avatar("RenderUnloadedAvatar", false); // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2) // Changes to LLAppearanceMgr::updateAppearanceFromCOF() expect this function to actually return mFullyLoaded for gAgentAvatarp @@ -8030,13 +8630,27 @@ BOOL LLVOAvatar::isFullyLoaded() const bool LLVOAvatar::isTooComplex() const { - static LLCachedControl ava_complexity_limit(gSavedSettings, "RenderAvatarComplexityLimit"); - if (ava_complexity_limit > 0 && mVisualComplexity >= ava_complexity_limit) + static const LLCachedControl always_render_friends("AlwaysRenderFriends", true); + bool too_complex; + if (isSelf() || (always_render_friends && LLAvatarTracker::instance().isBuddy(getID()))) { - return true; + too_complex = false; + } + else + { + // Determine if visually muted or not + static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U); + static LLCachedControl max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f); + // If the user has chosen unlimited max complexity, we also disregard max attachment area + // 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) + )); } - return false; + return too_complex; } @@ -8536,6 +9150,7 @@ BOOL LLVOAvatar::hasHUDAttachment() const LLBBox LLVOAvatar::getHUDBBox() const { LLBBox bbox; +#if SLOW_ATTACHMENT_LIST for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -8548,6 +9163,14 @@ LLBBox LLVOAvatar::getHUDBBox() const ++attachment_iter) { const LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + const LLViewerJointAttachment* attachment = iter.second; + if (!attachment || !attachment->getIsHUDAttachment()) + continue; + const LLViewerObject* attached_object = iter.first; +#endif if (attached_object == NULL) { LL_WARNS() << "HUD attached object is NULL!" << LL_ENDL; @@ -8955,7 +9578,7 @@ void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& conte if (applyParsedTEMessage(contents.mTEContents) > 0 && isChanged(TEXTURE)) { - mVisualComplexityStale = true; + updateVisualComplexity(); } // prevent the overwriting of valid baked textures with invalid baked textures @@ -9572,14 +10195,14 @@ void LLVOAvatar::cullAvatarsByPixelArea() if (gFrameTimeSeconds != sUnbakedUpdateTime) // only update once per frame { sUnbakedUpdateTime = gFrameTimeSeconds; - sUnbakedTime += gFrameIntervalSeconds; + sUnbakedTime += gFrameIntervalSeconds.value(); } if (grey_avatars > 0) { if (gFrameTimeSeconds != sGreyUpdateTime) // only update once per frame { sGreyUpdateTime = gFrameTimeSeconds; - sGreyTime += gFrameIntervalSeconds; + sGreyTime += gFrameIntervalSeconds.value(); } } } @@ -9595,16 +10218,6 @@ void LLVOAvatar::startAppearanceAnimation() } } -//virtual -void LLVOAvatar::bodySizeChanged() -{ - if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF()) - { // notify simulator of change in size - // but not if we are in the middle of updating appearance - gAgent.sendAgentSetAppearance(); - } -} - BOOL LLVOAvatar::isUsingServerBakes() const { #if 1 @@ -9641,6 +10254,7 @@ void LLVOAvatar::updateRegion(LLViewerRegion *regionp) LLViewerObject::updateRegion(regionp); } +// virtual std::string LLVOAvatar::getFullname() const { std::string name; @@ -9687,7 +10301,12 @@ void LLVOAvatar::updateFreezeCounter(S32 counter) BOOL LLVOAvatar::updateLOD() { - if (isImpostor()) + if (mDrawable.isNull()) + { + return FALSE; + } + + if (isImpostor() && 0 != mDrawable->getNumFaces() && mDrawable->getFace(0)->hasGeometry()) { return TRUE; } @@ -9712,12 +10331,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; igetJoint(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& volumes) +{ +#if SLOW_ATTACHMENT_LIST + 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; +#else + for(auto& iter : mAttachedObjectsVector) + {{ + LLViewerObject* attached_object = iter.first; +#endif + LLVOVolume *volume = dynamic_cast(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(childp); + if (volume) + { + volumes.push_back(volume); + } + } + } + } + + LLControlAvatar *control_av = dynamic_cast(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(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 volumes; + + { + LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_AVOL_UPDATE); + getAssociatedVolumes(volumes); + } + + std::map curr_rigging_info_key; + { + LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_KEY_UPDATE); + // Get current rigging info key + for (std::vector::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::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; +} + void LLVOAvatar::updateSoftwareSkinnedVertices(const LLMeshSkinInfo* skin, const LLVector4a* weight, const LLVolumeFace& vol_face, LLVertexBuffer *buffer) { //perform software vertex skinning for this face @@ -9760,7 +10523,7 @@ void LLVOAvatar::updateSoftwareSkinnedVertices(const LLMeshSkinInfo* skin, const bind_shape_matrix.affineTransform(v, t); final_mat.affineTransform(t, pos[j]); - pos[j].add(av_pos); + pos[j].add(av_pos); // Algorithm tweaked to stop hosing up normals. if (norm) { @@ -9772,6 +10535,11 @@ void LLVOAvatar::updateSoftwareSkinnedVertices(const LLMeshSkinInfo* skin, const } } +void LLVOAvatar::onActiveOverrideMeshesChanged() +{ + mJointRiggingInfoTab.setNeedsUpdate(true); +} + U32 LLVOAvatar::getPartitionType() const { // Avatars merely exist as drawables in the bridge partition @@ -9781,10 +10549,10 @@ U32 LLVOAvatar::getPartitionType() const //static void LLVOAvatar::updateImpostors() { - LLCharacter::sAllowInstancesChange = FALSE ; - - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + std::vector instances_copy = LLCharacter::sInstances; + for (std::vector::iterator iter = instances_copy.begin(); + iter != instances_copy.end(); ++iter) { LLVOAvatar* avatar = (LLVOAvatar*) *iter; if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor()) @@ -9792,8 +10560,6 @@ void LLVOAvatar::updateImpostors() gPipeline.generateImpostor(avatar); } } - - LLCharacter::sAllowInstancesChange = TRUE ; } BOOL LLVOAvatar::isImpostor() const @@ -9801,6 +10567,10 @@ BOOL LLVOAvatar::isImpostor() const return (isVisuallyMuted() || (sUseImpostors && mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE; } +BOOL LLVOAvatar::shouldImpostor(const U32 rank_factor) const +{ + return (!isSelf() && sUseImpostors && mVisibilityRank > (sMaxVisible * rank_factor)); +} BOOL LLVOAvatar::needsImpostorUpdate() const { @@ -9842,131 +10612,316 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d } -void LLVOAvatar::idleUpdateRenderCost() +void LLVOAvatar::idleUpdateRenderComplexity() { - static const LLCachedControl ARC_LIMIT("LiruNewARCLimit", 20000); - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES)) - { //set debug text to attachment geometry bytes here so render cost will override - setDebugText(llformat("%.1f KB, %.2f m^2", mAttachmentGeometryBytes/1024.f, mAttachmentSurfaceArea)); + if (isControlAvatar()) + { + LLControlAvatar *cav = dynamic_cast(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; + } } - - calculateUpdateRenderCost(); // Update mVisualComplexity if needed + // Render Complexity + calculateUpdateRenderComplexity(); // Update mVisualComplexity if needed if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME)) { - static LLCachedControl UseOldARC(gSavedSettings, "LiruSensibleARC", true); - if (UseOldARC) + std::string info_line; + F32 red_level; + F32 green_level; + LLColor4 info_color; + LLFontGL::StyleFlags info_style; + + if ( !mText ) { - U32 shame = 1; - std::set textures; - for(auto it = mAttachedObjectsVector.begin();it !=mAttachedObjectsVector.end();++it) - { - const LLViewerObject* object = it->first; - if (object && !object->isHUDAttachment()) - { - if (LLDrawable* drawable = object->mDrawable) - { - shame += 10; - if (LLVOVolume* volume = drawable->getVOVolume()) - shame += calc_shame(volume, textures); - } - } - } - shame += textures.size() * 5; - - setDebugText(llformat("%d", shame)); - F32 green = 1.f-llclamp(((F32) shame-1024.f)/1024.f, 0.f, 1.f); - F32 red = llmin((F32) shame/1024.f, 1.f); - mText->setColor(LLColor4(red,green,0,1)); + initHudText(); + mText->setFadeDistance(20.0, 5.0); // limit clutter in large crowds } else { - std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); - setDebugText(llformat("%s %d", viz_string.c_str(), mVisualComplexity)); - F32 green = 1.f-llclamp(((F32) mVisualComplexity-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f); - F32 red = llmin((F32) mVisualComplexity/(F32)ARC_LIMIT, 1.f); - mText->setColor(LLColor4(red,green,0,1)); + mText->clearString(); // clear debug text } + + /* + * NOTE: the logic for whether or not each of the values below + * controls muting MUST match that in the isVisuallyMuted and isTooComplex methods. + */ + + static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0); + info_line = llformat("%d Complexity", mVisualComplexity); + + if (max_render_cost != 0) // zero means don't care, so don't bother coloring based on this + { + green_level = 1.f-llclamp(((F32) mVisualComplexity-(F32)max_render_cost)/(F32)max_render_cost, 0.f, 1.f); + red_level = llmin((F32) mVisualComplexity/(F32)max_render_cost, 1.f); + info_color.set(red_level, green_level, 0.0, 1.0); + info_style = ( mVisualComplexity > max_render_cost + ? LLFontGL::BOLD : LLFontGL::NORMAL ); + } + else + { + info_color.set(LLColor4::grey); + info_style = LLFontGL::NORMAL; + } + mText->addLine(info_line, info_color, info_style); + + // 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 : (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 max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f); + info_line = llformat("%.0f m^2", mAttachmentSurfaceArea); + + if (max_render_cost != 0 && max_attachment_area != 0) // zero means don't care, so don't bother coloring based on this + { + green_level = 1.f-llclamp((mAttachmentSurfaceArea-max_attachment_area)/max_attachment_area, 0.f, 1.f); + red_level = llmin(mAttachmentSurfaceArea/max_attachment_area, 1.f); + info_color.set(red_level, green_level, 0.0, 1.0); + info_style = ( mAttachmentSurfaceArea > max_attachment_area + ? LLFontGL::BOLD : LLFontGL::NORMAL ); + + } + else + { + info_color.set(LLColor4::grey); + info_style = LLFontGL::NORMAL; + } + + mText->addLine(info_line, info_color, info_style); + + updateText(); // corrects position } } +void LLVOAvatar::updateVisualComplexity() +{ + LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL; + // Set the cache time to in the past so it's updated ASAP + 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(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(); + +#if 0 + 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(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); + } +#endif + } +} // Calculations for mVisualComplexity value -void LLVOAvatar::calculateUpdateRenderCost() +void LLVOAvatar::calculateUpdateRenderComplexity() { - static const U32 ARC_BODY_PART_COST = 200; + /***************************************************************** + * This calculation should not be modified by third party viewers, + * since it is used to limit rendering and should be uniform for + * everyone. If you have suggested improvements, submit them to + * the official viewer for consideration. + *****************************************************************/ + static const U32 COMPLEXITY_BODY_PART_COST = 200; + static LLCachedControl max_complexity_setting(gSavedSettings,"MaxAttachmentComplexity"); + F32 max_attachment_complexity = max_complexity_setting; + max_attachment_complexity = llmax(max_attachment_complexity, DEFAULT_MAX_ATTACHMENT_COMPLEXITY); // Diagnostic list of all textures on our avatar static std::set all_textures; if (mVisualComplexityStale) { - U32 cost = 0; + U32 cost = VISUAL_COMPLEXITY_UNKNOWN; LLVOVolume::texture_cost_t textures; + //hud_complexity_list_t hud_complexity_list; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { - const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict + = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); ETextureIndex tex_index = baked_dict->mTextureIndex; if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT))) { if (isTextureVisible(tex_index)) { - cost +=ARC_BODY_PART_COST; + cost +=COMPLEXITY_BODY_PART_COST; } } } + LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL; - /*for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + 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(this); + if (control_av) { - LLViewerJointAttachment* attachment = iter->second; + 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. +#if SLOW_ATTACHMENT_LIST + for (attachment_map_t::const_iterator attachment_point = mAttachmentPoints.begin(); + attachment_point != mAttachmentPoints.end(); + ++attachment_point) + { + LLViewerJointAttachment* attachment = attachment_point->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);*/ - auto attachment_iter = mAttachedObjectsVector.begin(); - for(;attachment_iter!=mAttachedObjectsVector.end();++attachment_iter) + const LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) {{ - const LLViewerObject* attached_object = attachment_iter->first; - if (attached_object && !attached_object->isHUDAttachment()) - { - textures.clear(); - const LLDrawable* drawable = attached_object->mDrawable; - if (drawable) - { - const LLVOVolume* volume = drawable->getVOVolume(); - if (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( child_obj ); - if (child) - { - cost += child->getRenderCost(textures); - } - } - - for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) - { - // add the cost of each individual texture in the linkset - cost += iter->second; - } - } - } - } + const LLViewerObject* attached_object = iter.first; +#endif + accountRenderComplexityForObject(attached_object, max_attachment_complexity, + textures, cost/*, hud_complexity_list*/); } - } // Diagnostic output to identify all avatar-related textures. @@ -9978,12 +10933,11 @@ void LLVOAvatar::calculateUpdateRenderCost() for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) { LLUUID image_id = it->first; - if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) - continue; - if (all_textures.find(image_id) == all_textures.end()) + if( ! (image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) + && (all_textures.find(image_id) == all_textures.end())) { // attachment texture not previously seen. - LL_INFOS() << "attachment_texture: " << image_id.asString() << LL_ENDL; + LL_DEBUGS("ARCdetail") << "attachment_texture: " << image_id.asString() << LL_ENDL; all_textures.insert(image_id); } } @@ -10003,7 +10957,7 @@ void LLVOAvatar::calculateUpdateRenderCost() continue; if (all_textures.find(image_id) == all_textures.end()) { - LL_INFOS() << "local_texture: " << texture_dict->mName << ": " << image_id << LL_ENDL; + LL_DEBUGS("ARCdetail") << "local_texture: " << texture_dict->mName << ": " << image_id << LL_ENDL; all_textures.insert(image_id); } } @@ -10112,60 +11066,3 @@ BOOL LLVOAvatar::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, return FALSE; } -U32 calc_shame(LLVOVolume* volume, std::set &textures) -{ - if (!volume) return 0; - - U32 shame = 0; - U32 invisi = 0; - U32 shiny = 0; - U32 glow = 0; - U32 alpha = 0; - U32 flexi = volume->isFlexible() ? 1 : 0; - U32 animtex = 0; - U32 particles = volume->isParticleSource() ? 1 : 0; - const LLVector3& sc = volume->getScale(); - U32 scale = U32(sc.mV[0] + sc.mV[1] + sc.mV[2]); - U32 bump = 0; - U32 planar = 0; - - LLDrawable* drawablep = volume->mDrawable; - - if (volume->isSculpted()) - textures.insert(static_cast(volume->getParameterEntry(LLNetworkData::PARAMS_SCULPT))->getSculptTexture()); - - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) - { - LLFace* face = drawablep->getFace(i); - LLViewerTexture* img = face->getTexture(); - textures.insert(img->getID()); - - if (face->getPoolType() == LLDrawPool::POOL_ALPHA) - ++alpha; - else if (!invisi && img->getPrimaryFormat() == GL_ALPHA) - invisi = 1; - - if (const LLTextureEntry* te = face->getTextureEntry()) - { - if (!bump && te->getBumpmap()) - bump = 1; - if (!shiny && te->getShiny()) - shiny = 1; - if (!glow && te->getGlow() > 0.f) - glow = 1; - if (face->mTextureMatrix) - ++animtex; - if (te->getTexGen()) - ++planar; - } - } - shame += invisi + shiny + glow + alpha*4 + flexi*8 + animtex*4 + particles*16+bump*4+scale+planar; - - for (LLViewerObject* child_objectp : volume->getChildren()) - if (LLDrawable* child_drawablep = child_objectp->mDrawable) - if (LLVOVolume* child_volumep = child_drawablep->getVOVolume()) - shame += calc_shame(child_volumep, textures); - - return shame; -} - diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index f8451604b..9ad8bfdb4 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -50,8 +50,9 @@ #include "lldriverparam.h" #include "llviewertexlayer.h" #include "material_codes.h" // LL_MCODE_END +#include "llrigginginfo.h" #include "llviewerstats.h" - +#include "llvovolume.h" #include "llavatarname.h" // @@ -80,6 +81,7 @@ class LLTexGlobalColor; class LLViewerJoint; struct LLAppearanceMessageContents; class LLMeshSkinInfo; +class LLViewerJointMesh; class SHClientTagMgr : public LLSingleton, public boost::signals2::trackable { @@ -207,7 +209,7 @@ public: /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); /*virtual*/ void updateRegion(LLViewerRegion *regionp); /*virtual*/ void updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax); - /*virtual*/ void getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); + void calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); /*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, @@ -241,6 +243,7 @@ public: void startMotion(U32 bit, F32 start_offset = 0.f); void stopMotion(U32 bit, BOOL stop_immediate = FALSE); // + virtual bool hasMotionFromSource(const LLUUID& source_id); virtual void stopMotionFromSource(const LLUUID& source_id); virtual void requestStopMotion(LLMotion* motion); LLMotion* findMotion(const LLUUID& id) const; @@ -248,19 +251,29 @@ public: void dumpAnimationState(); virtual LLJoint* getJoint(const std::string &name); - LLJoint* getJoint(S32 num); + LLJoint* getJoint(S32 num); - void addAttachmentOverridesForObject(LLViewerObject *vo); - void resetJointsOnDetach(const LLUUID& mesh_id); - void resetJointsOnDetach(LLViewerObject *vo); - bool jointIsRiggedTo(const std::string& joint_name); - bool jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo); + void addAttachmentOverridesForObject(LLViewerObject *vo, std::set* meshes_seen = NULL, bool recursive = true); + void removeAttachmentOverridesForObject(const LLUUID& mesh_id); + void removeAttachmentOverridesForObject(LLViewerObject *vo); + bool jointIsRiggedTo(const LLJoint *joint) const; void clearAttachmentOverrides(); void rebuildAttachmentOverrides(); + void updateAttachmentOverrides(); void showAttachmentOverrides(bool verbose = false) const; void getAttachmentOverrideNames( std::set& pos_names, std::set& scale_names) const; + + void getAssociatedVolumes(std::vector& volumes); + + // virtual + void updateRiggingInfo(); + // This encodes mesh id and LOD, so we can see whether display is up-to-date. + std::map mLastRiggingInfoKey; + std::set mActiveOverrideMeshes; + virtual void onActiveOverrideMeshesChanged(); + /*virtual*/ const LLUUID& getID() const; /*virtual*/ void addDebugText(const std::string& text); /*virtual*/ F32 getTimeDilation(); @@ -283,6 +296,8 @@ public: public: virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent + virtual bool isControlAvatar() const { return mIsControlAvatar; } // True if this avatar is a control av (no associated user) + virtual bool isUIAvatar() const { return mIsUIAvatar; } // True if this avatar is a supplemental av used in some UI views (no associated user) private: //aligned members LL_ALIGN_16(LLVector4a mImpostorExtents[2]); @@ -293,8 +308,16 @@ private: // Updates //-------------------------------------------------------------------- public: - void updateDebugText(); + void updateAppearanceMessageDebugText(); + void updateAnimationDebugText(); + virtual void updateDebugText(); virtual BOOL updateCharacter(LLAgent &agent); + void updateFootstepSounds(); + void computeUpdatePeriod(); + void updateOrientation(LLAgent &agent, F32 speed, F32 delta_time); + void updateTimeStep(); + void updateRootPositionAndRotation(LLAgent &agent, F32 speed, bool was_sit_ground_constrained); + void idleUpdateVoiceVisualizer(bool voice_enabled); void idleUpdateMisc(bool detailed_update); virtual void idleUpdateAppearanceAnimation(); @@ -311,19 +334,25 @@ public: // force all name tags to rebuild, useful when display names turned on/off static void invalidateNameTags(); void addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font); - void idleUpdateRenderCost(); - void calculateUpdateRenderCost(); - void updateVisualComplexity() { mVisualComplexityStale = TRUE; } + void idleUpdateRenderComplexity(); + void accountRenderComplexityForObject(const LLViewerObject *attached_object, + const F32 max_attachment_complexity, + LLVOVolume::texture_cost_t& textures, + U32& cost/*, + hud_complexity_list_t& hud_complexity_list*/); + void calculateUpdateRenderComplexity(); + static const U32 VISUAL_COMPLEXITY_UNKNOWN; + void updateVisualComplexity(); - S32 getVisualComplexity() { return mVisualComplexity; }; // Numbers calculated here by rendering AV - S32 getAttachmentGeometryBytes() { return mAttachmentGeometryBytes; }; // number of bytes in attached geometry + U32 getVisualComplexity() { return mVisualComplexity; }; // Numbers calculated here by rendering AV F32 getAttachmentSurfaceArea() { return mAttachmentSurfaceArea; }; // estimated surface area of attachments - S32 getReportedVisualComplexity() { return mReportedVisualComplexity; }; // Numbers as reported by the SL server + U32 getReportedVisualComplexity() { return mReportedVisualComplexity; }; // Numbers as reported by the SL server void setReportedVisualComplexity(S32 value) { mReportedVisualComplexity = value; }; S32 getUpdatePeriod() { return mUpdatePeriod; }; + static void updateImpostorRendering(U32 newMaxNonImpostorsValue); void idleUpdateBelowWater(); @@ -336,13 +365,13 @@ public: static U32 sMaxVisible; //(affected by control "RenderAvatarMaxVisible") static F32 sRenderDistance; //distance at which avatars will render. static BOOL sShowAnimationDebug; // show animation debug info - static BOOL sUseImpostors; //use impostors for far away avatars - static BOOL sShowFootPlane; // show foot collision plane reported by server - static BOOL sVisibleInFirstPerson; + static bool sUseImpostors; //use impostors for far away avatars + static bool sShowFootPlane; // show foot collision plane reported by server + static bool sVisibleInFirstPerson; static S32 sNumLODChangesThisFrame; static S32 sNumVisibleChatBubbles; static BOOL sDebugInvisible; - static BOOL sShowAttachmentPoints; + static bool sShowAttachmentPoints; static F32 sLODFactor; // user-settable LOD factor static F32 sPhysicsLODFactor; // user-settable physics LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar @@ -392,8 +421,6 @@ private: BOOL mPreviousFullyLoaded; BOOL mFullyLoadedInitialized; S32 mFullyLoadedFrameCounter; - S32 mVisualComplexity; - BOOL mVisualComplexityStale; LLFrameTimer mFullyLoadedTimer; LLFrameTimer mRuthTimer; bool mFreezeTimeLangolier; // True when this avatar was created during snapshot FreezeTime mode, and that mode is still active. @@ -460,12 +487,10 @@ public: static void destroyGL(); static void restoreGL(); S32 mSpecialRenderMode; // special lighting - S32 mAttachmentGeometryBytes; //number of bytes in attached geometry - F32 mAttachmentSurfaceArea; //estimated surface area of attachments - - S32 mReportedVisualComplexity; // Numbers as reported by the SL server - private: + F32 mAttachmentSurfaceArea; //estimated surface area of attachments + U32 mAttachmentVisibleTriangleCount; + F32 mAttachmentEstTriangleCount; bool shouldAlphaMask(); BOOL mNeedsSkin; // avatar has been animated and verts have not been updated @@ -474,6 +499,19 @@ private: S32 mUpdatePeriod; S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer. + // the isTooComplex method uses these mutable values to avoid recalculating too frequently + mutable U32 mVisualComplexity; + mutable bool mVisualComplexityStale; + U32 mReportedVisualComplexity; // from other viewers through the simulator + + //-------------------------------------------------------------------- + // animated object status + //-------------------------------------------------------------------- +public: + bool mIsControlAvatar; + bool mIsUIAvatar; + bool mEnableDefaultMotions; + //-------------------------------------------------------------------- // Morph masks //-------------------------------------------------------------------- @@ -513,7 +551,8 @@ private: //-------------------------------------------------------------------- public: BOOL isImpostor() const; - BOOL needsImpostorUpdate() const; + BOOL shouldImpostor(const U32 rank_factor = 1) const; + BOOL needsImpostorUpdate() const; const LLVector3& getImpostorOffset() const; const LLVector2& getImpostorDim() const; void getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const; @@ -523,14 +562,19 @@ public: static void updateImpostors(); LLRenderTarget mImpostor; BOOL mNeedsImpostorUpdate; + F32SecondsImplicit mLastImpostorUpdateFrameTime; + const LLVector3* getLastAnimExtents() const { return mLastAnimExtents; } + void setNeedsExtentUpdate(bool val) { mNeedsExtentUpdate = val; } private: LLVector3 mImpostorOffset; LLVector2 mImpostorDim; BOOL mNeedsAnimUpdate; + bool mNeedsExtentUpdate; LLVector3 mImpostorAngle; F32 mImpostorDistance; F32 mImpostorPixelArea; LLVector3 mLastAnimExtents[2]; + LLVector3 mLastAnimBasePos; //-------------------------------------------------------------------- // Wind rippling in clothes @@ -717,7 +761,6 @@ public: void applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params); void hideSkirt(); void startAppearanceAnimation(); - /*virtual*/ void bodySizeChanged(); //-------------------------------------------------------------------- // Appearance morphing @@ -755,6 +798,7 @@ private: //-------------------------------------------------------------------- public: BOOL isVisible() const; + virtual bool shouldRenderRigged() const; void setVisibilityRank(U32 rank); U32 getVisibilityRank() const { return mVisibilityRank; } // unused static S32 sNumVisibleAvatars; // Number of instances of this class @@ -779,9 +823,9 @@ public: static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj); /*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type ) const; LLViewerObject * findAttachmentByID( const LLUUID & target_id ) const; + LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object); protected: - LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object); void lazyAttach(); void rebuildRiggedAttachments( void ); @@ -803,11 +847,12 @@ public: BOOL hasHUDAttachment() const; LLBBox getHUDBBox() const; void resetHUDAttachments(); - BOOL canAttachMoreObjects() const; - BOOL canAttachMoreObjects(U32 n) const; + BOOL canAttachMoreObjects(U32 n=1) const; + U32 getMaxAnimatedObjectAttachments() const; + BOOL canAttachMoreAnimatedObjects(U32 n=1) const; protected: U32 getNumAttachments() const; // O(N), not O(1) - + U32 getNumAnimatedObjectAttachments() const; // O(N), not O(1) //-------------------------------------------------------------------- // Old/nonstandard/Agent-only functions //-------------------------------------------------------------------- diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 0a54eec6f..dc8826349 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -260,9 +260,11 @@ void LLVOAvatarSelf::initInstance() doPeriodically(update_avatar_rez_metrics, 5.0); doPeriodically(check_for_unsupported_baked_appearance, 120.0); doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0); + + mInitFlags |= 1<<2; } -void LLVOAvatarSelf::setHoverIfRegionEnabled() +void LLVOAvatarSelf::setHoverIfRegionEnabled(bool send_update) { LLViewerRegion* region = getRegion(); if (region && region->simulatorFeaturesReceived()) @@ -609,6 +611,13 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) if (!jointp && mScreenp) { jointp = mScreenp->findJoint(name); + if (jointp) + { + joint_map_t::value_type entry; + strncpy(entry.first, name.c_str(), sizeof(entry.first)); + entry.second = jointp; + mJointMap.emplace_back(entry); + } } return jointp; @@ -3010,6 +3019,12 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch) } } +// virtual +bool LLVOAvatarSelf::shouldRenderRigged() const +{ + return gAgent.needsRenderAvatar(); +} + // HACK: this will null out the avatar's local texture IDs before the TE message is sent // to ensure local texture IDs are not sent to other clients in the area. // this is a short-term solution. The long term solution will be to not set the texture @@ -3107,7 +3122,7 @@ BOOL LLVOAvatarSelf::needsRenderBeam() // don't render selection beam on hud objects is_touching_or_grabbing = FALSE; } - return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); + return is_touching_or_grabbing || (getAttachmentState() & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); } void dump_visual_param(apr_file_t* file, LLVisualParam const* viewer_param, F32 value); diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 68dba270e..98e3a2802 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -345,11 +345,14 @@ public: //-------------------------------------------------------------------- // Visibility //-------------------------------------------------------------------- + + /* virtual */ bool shouldRenderRigged() const; + public: bool sendAppearanceMessage(LLMessageSystem *mesgsys) const; // -- care and feeding of hover height. - void setHoverIfRegionEnabled(); + void setHoverIfRegionEnabled(bool send_update = true); void sendHoverHeight() const; /*virtual*/ void setHoverOffset(const LLVector3& hover_offset, bool send_update=true); diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index ad7efbf21..26e73c85b 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -103,7 +103,7 @@ LLVOGrass::~LLVOGrass() void LLVOGrass::updateSpecies() { - mSpecies = mState; + mSpecies = getAttachmentState(); if (!sSpeciesTable.count(mSpecies)) { diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 9d5f1c942..e96e2ec16 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -53,7 +53,7 @@ const F32 MAX_PART_LIFETIME = 120.f; -extern U64 gFrameTime; +extern U64MicrosecondsImplicit gFrameTime; LLPointer LLVOPartGroup::sVB = NULL; S32 LLVOPartGroup::sVBSlotFree[]; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 359d963c4..46669ede9 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -83,8 +83,11 @@ #include "lldatapacker.h" #include "llviewershadermgr.h" #include "llvoavatar.h" +#include "llcontrolavatar.h" +#include "llvoavatarself.h" #include "llvocache.h" #include "llmaterialmgr.h" +#include "llsculptidsize.h" // [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) #include "rlvhandler.h" @@ -223,6 +226,9 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mFaceMappingChanged = FALSE; mLOD = MIN_LOD; + mLODDistance = 0.0f; + mLODAdjustedDistance = 0.0f; + mLODRadius = 0.0f; mTextureAnimp = NULL; mVolumeChanged = FALSE; mVObjRadius = LLVector3(1,1,0.5f).length(); @@ -235,6 +241,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mLastFetchedMediaVersion = -1; mIndexInTex = 0; mMDCImplCount = 0; + mLastRiggingInfoLOD = -1; } LLVOVolume::~LLVOVolume() @@ -262,6 +269,7 @@ void LLVOVolume::markDead() { if (!mDead) { + LLSculptIDSize::instance().rem(getVolume()->getParams().getSculptID()); if(getMDCImplCount() > 0) { LLMediaDataClientObject::ptr_t obj = new LLMediaDataClientObjectImpl(const_cast(this), false); @@ -480,7 +488,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, { U8 tdpbuffer[1024]; LLDataPackerBinaryBuffer tdp(tdpbuffer, 1024); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num, 1024); S32 result = unpackTEMessage(tdp); if (result & teDirtyBits) { @@ -969,13 +977,14 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo // if it's a mesh if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { //meshes might not have all LODs, get the force detail to best existing LOD - LLUUID mesh_id = volume_params.getSculptID(); - - lod = gMeshRepo.getActualMeshLOD(volume_params, lod); - if (lod == -1) + if (NO_LOD != lod) { - is404 = TRUE; - lod = 0; + lod = gMeshRepo.getActualMeshLOD(volume_params, lod); + if (lod == -1) + { + is404 = TRUE; + lod = 0; + } } } } @@ -1077,8 +1086,10 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo return TRUE; } - - + else if (NO_LOD == lod) + { + LLSculptIDSize::instance().resetSizeSum(volume_params.getSculptID()); + } return FALSE; } @@ -1112,13 +1123,37 @@ void LLVOVolume::updateSculptTexture() mSculptTexture->addVolume(this); } } + +} +void LLVOVolume::updateVisualComplexity() +{ + LLVOAvatar* avatar = getAvatarAncestor(); + if (avatar) + { + avatar->updateVisualComplexity(); + } + LLVOAvatar* rigged_avatar = getAvatar(); + if(rigged_avatar && (rigged_avatar != avatar)) + { + rigged_avatar->updateVisualComplexity(); + } } void LLVOVolume::notifyMeshLoaded() { mSculptChanged = TRUE; gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); + + if (getAvatar() && !isAnimatedObject()) + { + getAvatar()->addAttachmentOverridesForObject(this); + } + if (getControlAvatar() && isAnimatedObject()) + { + getControlAvatar()->addAttachmentOverridesForObject(this); + } + updateVisualComplexity(); } // sculpt replaces generate() for sculpted surfaces @@ -1207,18 +1242,18 @@ void LLVOVolume::sculpt() } } -S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius) +S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius, F32 lod_factor) { S32 cur_detail; if (LLPipeline::sDynamicLOD) { // We've got LOD in the profile, and in the twist. Use radius. - F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance; + F32 tan_angle = (lod_factor*radius)/distance; cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f)); } else { - cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3); + cur_detail = llclamp((S32) (sqrtf(radius)*lod_factor*4.f), 0, 3); } return cur_detail; } @@ -1234,20 +1269,61 @@ BOOL LLVOVolume::calcLOD() F32 radius; F32 distance; + F32 lod_factor = LLVOVolume::sLODFactor; if (mDrawable->isState(LLDrawable::RIGGED) && getAvatar() && getAvatar()->mDrawable) { LLVOAvatar* avatar = getAvatar(); + // Not sure how this can really happen, but alas it does. Better exit here than crashing. + if( !avatar || !avatar->mDrawable ) + { + return FALSE; + } + distance = avatar->mDrawable->mDistanceWRTCamera; - radius = avatar->getBinRadius(); + + + if (avatar->isControlAvatar()) + { + // MAINT-7926 Handle volumes in an animated object as a special case + const LLVector3* box = avatar->getLastAnimExtents(); + LLVector3 diag = box[1] - box[0]; + radius = diag.magVec() * 0.5f; + LL_DEBUGS("DynamicBox") << avatar->getFullname() << " diag " << diag << " radius " << radius << LL_ENDL; + } + else + { + // Volume in a rigged mesh attached to a regular avatar. + // Note this isn't really a radius, so distance calcs are off by factor of 2 + //radius = avatar->getBinRadius(); + // SL-937: add dynamic box handling for rigged mesh on regular avatars. + const LLVector3* box = avatar->getLastAnimExtents(); + LLVector3 diag = box[1] - box[0]; + radius = diag.magVec(); // preserve old BinRadius behavior - 2x off + LL_DEBUGS("DynamicBox") << avatar->getFullname() << " diag " << diag << " radius " << radius << LL_ENDL; + } + if (distance <= 0.f || radius <= 0.f) + { + LL_DEBUGS("DynamicBox","CalcLOD") << "avatar distance/radius uninitialized, skipping" << LL_ENDL; + return FALSE; + } } else { distance = mDrawable->mDistanceWRTCamera; radius = getVolume() ? getVolume()->mLODScaleBias.scaledVec(getScale()).length() : getScale().length(); + if (distance <= 0.f || radius <= 0.f) + { + LL_DEBUGS("DynamicBox","CalcLOD") << "non-avatar distance/radius uninitialized, skipping" << LL_ENDL; + return FALSE; + } } + //hold onto unmodified distance for debugging + //F32 debug_distance = distance; + mLODDistance = distance; + mLODRadius = radius; distance *= sDistanceFactor; F32 rampDist = LLVOVolume::sLODFactor * 2; @@ -1255,22 +1331,33 @@ BOOL LLVOVolume::calcLOD() if (distance < rampDist) { // Boost LOD when you're REALLY close - distance *= distance/rampDist; + distance *= 1.0f/rampDist; + distance *= distance; + distance *= rampDist; } // DON'T Compensate for field of view changing on FOV zoom. distance *= F_PI/3.f; - cur_detail = computeLODDetail(ll_round(distance, 0.01f), - ll_round(radius, 0.01f)); + + mLODAdjustedDistance = distance; + + if (isHUDAttachment()) + { + // HUDs always show at highest detail + cur_detail = 3; + } + else + { + cur_detail = computeLODDetail(ll_round(distance, 0.01f), ll_round(radius, 0.01f), lod_factor); + } if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) && mDrawable->getFace(0)) { - //setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail)); - - setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex())); + // This is a debug display for LODs. Please don't put the texture index here. + setDebugText(llformat("%d", cur_detail)); } if (cur_detail != mLOD) @@ -1279,10 +1366,7 @@ BOOL LLVOVolume::calcLOD() mLOD = cur_detail; return TRUE; } - else - { - return FALSE; - } + return FALSE; } BOOL LLVOVolume::updateLOD() @@ -1292,7 +1376,16 @@ BOOL LLVOVolume::updateLOD() return FALSE; } - BOOL lod_changed = calcLOD(); + BOOL lod_changed = FALSE; + + if (!LLSculptIDSize::instance().isUnloaded(getVolume()->getParams().getSculptID())) + { + lod_changed = calcLOD(); + } + else + { + return FALSE; + } if (lod_changed) { @@ -1372,7 +1465,8 @@ void LLVOVolume::updateFaceFlags() BOOL LLVOVolume::setParent(LLViewerObject* parent) { BOOL ret = FALSE ; - if (parent != getParent()) + LLViewerObject *old_parent = (LLViewerObject*) getParent(); + if (parent != old_parent) { ret = LLViewerObject::setParent(parent); if (ret && mDrawable) @@ -1380,6 +1474,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent) gPipeline.markMoved(mDrawable); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); } + onReparent(old_parent, parent); } return ret ; @@ -1444,13 +1539,28 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED); - // bool rigged = false; + if (getRiggedVolume()) + { + // MAINT-8264 - better to use the existing call in calling + // func LLVOVolume::updateGeometry() if we can detect when + // updates needed, set REBUILD_RIGGED accordingly. + + // Without the flag, this will remove unused rigged volumes, which we are not currently very aggressive about. + updateRiggedVolume(); + } + LLVolume* volume = mRiggedVolume; if (!volume) { volume = getVolume(); } + bool any_valid_boxes = false; + + if (getRiggedVolume()) + { + LL_DEBUGS("RiggedBox") << "rebuilding box, volume face count " << getVolume()->getNumVolumeFaces() << " drawable face count " << mDrawable->getNumFaces() << LL_ENDL; + } for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++) { LLFace *face = mDrawable->getFace(i); @@ -1462,12 +1572,22 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) mRelativeXform, (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); + // MAINT-8264 - ignore bboxes of ill-formed faces. + if (!res) + { + continue; + } if (rebuild) { - if (i == 0) + if (getRiggedVolume()) + { + LL_DEBUGS("RiggedBox") << "rebuilding box, face " << i << " extents " << face->mExtents[0] << ", " << face->mExtents[1] << LL_ENDL; + } + if (!any_valid_boxes) { min = face->mExtents[0]; max = face->mExtents[1]; + any_valid_boxes = true; } else { @@ -1476,18 +1596,29 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) } } } - - if (rebuild) + + if (any_valid_boxes) { - mDrawable->setSpatialExtents(min,max); - min.add(max); - min.mul(0.5f); - mDrawable->setPositionGroup(min); + if (rebuild) + { + if (getRiggedVolume()) + { + LL_DEBUGS("RiggedBox") << "rebuilding got extents " << min << ", " << max << LL_ENDL; + } + mDrawable->setSpatialExtents(min, max); + min.add(max); + min.mul(0.5f); + mDrawable->setPositionGroup(min); + } + + updateRadius(); + mDrawable->movePartition(); + } + else + { + LL_DEBUGS("RiggedBox") << "genBBoxes failed to find any valid face boxes" << LL_ENDL; } - updateRadius(); - mDrawable->movePartition(); - return res; } @@ -1568,7 +1699,7 @@ static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies"); static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives"); static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); -bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable) +bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) { bool regen_faces = false; @@ -1594,6 +1725,12 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable) if ((new_lod != old_lod) || mSculptChanged) { + if (mDrawable->isState(LLDrawable::RIGGED)) + { + updateVisualComplexity(); + } + + compiled = TRUE; sNumLODChanges += new_num_faces ; if((S32)getNumTEs() != getVolume()->getNumFaces()) @@ -1658,6 +1795,8 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) group->dirtyMesh(); } + BOOL compiled = FALSE; + updateRelativeXform(); if (mDrawable.isNull()) // Not sure why this is happening, but it is... @@ -1673,12 +1812,13 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) if (mVolumeChanged) { - was_regen_faces = lodOrSculptChanged(drawable); + was_regen_faces = lodOrSculptChanged(drawable, compiled); drawable->setState(LLDrawable::REBUILD_VOLUME); } else if (mSculptChanged || mLODChanged) { - was_regen_faces = lodOrSculptChanged(drawable); + compiled = TRUE; + was_regen_faces = lodOrSculptChanged(drawable, compiled); } if (!was_regen_faces) { @@ -1691,13 +1831,20 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) else if (mLODChanged || mSculptChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); - lodOrSculptChanged(drawable); + compiled = TRUE; + lodOrSculptChanged(drawable, compiled); + + if(drawable->isState(LLDrawable::REBUILD_RIGGED | LLDrawable::RIGGED)) + { + updateRiggedVolume(false); + } genBBoxes(FALSE); } // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local else { + compiled = TRUE; // All it did was move or we changed the texture coordinate offset LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); genBBoxes(FALSE); @@ -1705,6 +1852,11 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) // Update face flags updateFaceFlags(); + + if(compiled) + { + LLPipeline::sCompiles++; + } mVolumeChanged = FALSE; mLODChanged = FALSE; @@ -2458,7 +2610,9 @@ void LLVOVolume::mediaNavigateBounceBack(U8 texture_index) LL_WARNS("MediaOnAPrim") << "FAILED to bounce back URL \"" << url << "\" -- unloading impl" << LL_ENDL; impl->setMediaFailed(true); } - else { + // Make sure we are not bouncing to url we came from + else if (impl->getCurrentMediaURL() != url) + { // Okay, navigate now LL_INFOS("MediaOnAPrim") << "bouncing back to URL: " << url << LL_ENDL; impl->navigateTo(url, "", false, true); @@ -3202,6 +3356,208 @@ BOOL LLVOVolume::setIsFlexible(BOOL is_flexible) return res; } +const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const +{ + if (getVolume()) + { + return gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this); + } + else + { + return NULL; + } +} + +// virtual +BOOL LLVOVolume::isRiggedMesh() const +{ + return isMesh() && getSkinInfo(); +} + +//---------------------------------------------------------------------------- +U32 LLVOVolume::getExtendedMeshFlags() const +{ + const LLExtendedMeshParams *param_block = + (const LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH); + if (param_block) + { + return param_block->getFlags(); + } + else + { + return 0; + } +} + +void LLVOVolume::onSetExtendedMeshFlags(U32 flags) +{ + + // The isAnySelected() check was needed at one point to prevent + // graphics problems. These are now believed to be fixed so the + // check has been disabled. + if (/*!getRootEdit()->isAnySelected() &&*/ mDrawable.notNull()) + { + // Need to trigger rebuildGeom(), which is where control avatars get created/removed + getRootEdit()->recursiveMarkForUpdate(TRUE); + } + if (isAttachment() && getAvatarAncestor()) + { + updateVisualComplexity(); + if (flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG) + { + // Making a rigged mesh into an animated object + getAvatarAncestor()->updateAttachmentOverrides(); + } + else + { + // Making an animated object into a rigged mesh + getAvatarAncestor()->updateAttachmentOverrides(); + } + } +} + +void LLVOVolume::setExtendedMeshFlags(U32 flags) +{ + U32 curr_flags = getExtendedMeshFlags(); + if (curr_flags != flags) + { + bool in_use = true; + setParameterEntryInUse(LLNetworkData::PARAMS_EXTENDED_MESH, in_use, true); + LLExtendedMeshParams *param_block = + (LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH); + if (param_block) + { + param_block->setFlags(flags); + } + parameterChanged(LLNetworkData::PARAMS_EXTENDED_MESH, true); + LL_DEBUGS("AnimatedObjects") << this + << " new flags " << flags << " curr_flags " << curr_flags + << ", calling onSetExtendedMeshFlags()" + << LL_ENDL; + onSetExtendedMeshFlags(flags); + } +} + +bool LLVOVolume::canBeAnimatedObject() const +{ + F32 est_tris = recursiveGetEstTrianglesMax(); + if (est_tris < 0 || est_tris > getAnimatedObjectMaxTris()) + { + return false; + } + return true; +} + +bool LLVOVolume::isAnimatedObject() const +{ + LLVOVolume *root_vol = (LLVOVolume*)getRootEdit(); + bool root_is_animated_flag = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + return root_is_animated_flag; +} + +// Called any time parenting changes for a volume. Update flags and +// control av accordingly. This is called after parent has been +// changed to new_parent, but before new_parent's mChildList has changed. + +// virtual +void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent) +{ + LLVOVolume *old_volp = dynamic_cast(old_parent); + + if (new_parent && !new_parent->isAvatar()) + { + if (mControlAvatar.notNull()) + { + // Here an animated object is being made the child of some + // other prim. Should remove the control av from the child. + LLControlAvatar *av = mControlAvatar; + mControlAvatar = NULL; + av->markForDeath(); + } + } + if (old_volp && old_volp->isAnimatedObject()) + { + if (old_volp->getControlAvatar()) + { + // We have been removed from an animated object, need to do cleanup. + old_volp->getControlAvatar()->updateAttachmentOverrides(); + old_volp->getControlAvatar()->updateAnimations(); + } + } +} + +// This needs to be called after onReparent(), because mChildList is +// not updated until the end of LLViewerObject::addChild() + +// virtual +void LLVOVolume::afterReparent() +{ + { + LL_DEBUGS("AnimatedObjects") << "new child added for parent " + << ((LLViewerObject*)getParent())->getID() << LL_ENDL; + } + + if (isAnimatedObject() && getControlAvatar()) + { + LL_DEBUGS("AnimatedObjects") << "adding attachment overrides, parent is animated object " + << ((LLViewerObject*)getParent())->getID() << LL_ENDL; + + // MAINT-8239 - doing a full rebuild whenever parent is set + // makes the joint overrides load more robustly. In theory, + // addAttachmentOverrides should be sufficient, but in + // practice doing a full rebuild helps compensate for + // notifyMeshLoaded() not being called reliably enough. + + // was: getControlAvatar()->addAttachmentOverridesForObject(this); + //getControlAvatar()->rebuildAttachmentOverrides(); + getControlAvatar()->updateAnimations(); + } + else + { + LL_DEBUGS("AnimatedObjects") << "not adding overrides, parent: " + << ((LLViewerObject*)getParent())->getID() + << " isAnimated: " << isAnimatedObject() << " cav " + << getControlAvatar() << LL_ENDL; + } +} + +//---------------------------------------------------------------------------- +static LLTrace::BlockTimerStatHandle FTM_VOVOL_RIGGING_INFO("VOVol Rigging Info"); + +void LLVOVolume::updateRiggingInfo() +{ + LL_RECORD_BLOCK_TIME(FTM_VOVOL_RIGGING_INFO); + if (isRiggedMesh()) + { + const LLMeshSkinInfo* skin = getSkinInfo(); + LLVOAvatar *avatar = getAvatar(); + LLVolume *volume = getVolume(); + if (skin && avatar && volume) + { + LL_DEBUGS("RigSpammish") << "starting, vovol " << this << " lod " << getLOD() << " last " << mLastRiggingInfoLOD << LL_ENDL; + if (getLOD()>mLastRiggingInfoLOD || getLOD()==3) + { + // Rigging info may need update + mJointRiggingInfoTab.clear(); + for (S32 f = 0; f < volume->getNumVolumeFaces(); ++f) + { + LLVolumeFace& vol_face = volume->getVolumeFace(f); + LLSkinningUtil::updateRiggingInfo(skin, avatar, vol_face); + if (vol_face.mJointRiggingInfoTab.size()>0) + { + mJointRiggingInfoTab.merge(vol_face.mJointRiggingInfoTab); + } + } + // Keep the highest LOD info available. + mLastRiggingInfoLOD = getLOD(); + LL_DEBUGS("RigSpammish") << "updated rigging info for LLVOVolume " + << this << " lod " << mLastRiggingInfoLOD + << LL_ENDL; + } + } + } +} + //---------------------------------------------------------------------------- void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) @@ -3215,7 +3571,7 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p //transform view vector into volume space view_vector -= getRenderPosition(); - mDrawable->mDistanceWRTCamera = view_vector.length(); + //mDrawable->mDistanceWRTCamera = view_vector.length(); LLQuaternion worldRot = getRenderRotation(); view_vector = view_vector * ~worldRot; if (!isVolumeGlobal()) @@ -3263,7 +3619,7 @@ void LLVOVolume::updateRadius() BOOL LLVOVolume::isAttachment() const { - return mState != 0 ; + return mAttachmentState != 0 ; } BOOL LLVOVolume::isHUDAttachment() const @@ -3271,7 +3627,7 @@ BOOL LLVOVolume::isHUDAttachment() const // *NOTE: we assume hud attachment points are in defined range // since this range is constant for backwards compatibility // reasons this is probably a reasonable assumption to make - S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState); + S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mAttachmentState); return ( attachment_id >= 31 && attachment_id <= 38 ); } @@ -3313,6 +3669,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const static const F32 ARC_BUMP_MULT = 1.25f; // tested based on performance static const F32 ARC_FLEXI_MULT = 5; // tested based on performance static const F32 ARC_SHINY_MULT = 1.6f; // tested based on performance + static const F32 ARC_INVISI_COST = 1.2f; // tested based on performance static const F32 ARC_WEIGHTED_MESH = 1.2f; // tested based on performance static const F32 ARC_PLANAR_COST = 1.0f; // tested based on performance to have negligible impact @@ -3321,6 +3678,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const F32 shame = 0; + U32 invisi = 0; U32 shiny = 0; U32 glow = 0; U32 alpha = 0; @@ -3342,16 +3700,25 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const path_params = volume_params.getPathParams(); profile_params = volume_params.getProfileParams(); - F32 weighted_triangles = -1.0; - getStreamingCost(NULL, NULL, &weighted_triangles); - - if (weighted_triangles > 0.0) + LLMeshCostData costs; + if (getCostData(costs)) { - num_triangles = (U32)(weighted_triangles); + if (isAnimatedObject() && isRiggedMesh()) + { + // Scaling here is to make animated object vs + // non-animated object ARC proportional to the + // corresponding calculations for streaming cost. + num_triangles = (ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * costs.getEstTrisForStreamingCost())/0.06; + } + else + { + F32 radius = getScale().length()*0.5f; + num_triangles = costs.getRadiusWeightedTris(radius); + } } } - if (num_triangles == 0) + if (num_triangles <= 0) { num_triangles = 4; } @@ -3362,15 +3729,14 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const { // base cost is dependent on mesh complexity // note that 3 is the highest LOD as of the time of this coding. - S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(),3); + S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(), getLOD()); if ( size > 0) { - if (gMeshRepo.getSkinInfo(volume_params.getSculptID(), this)) + if (isRiggedMesh()) { // weighted attachment - 1 point for every 3 bytes weighted_mesh = 1; } - } else { @@ -3428,6 +3794,10 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const { alpha = 1; } + else if (img && img->getPrimaryFormat() == GL_ALPHA) + { + invisi = 1; + } if (face->hasMedia()) { media_faces++; @@ -3481,6 +3851,11 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const shame *= alpha * ARC_ALPHA_COST; } + if(invisi) + { + shame *= invisi * ARC_INVISI_COST; + } + if (glow) { shame *= glow * ARC_GLOW_MULT; @@ -3530,6 +3905,13 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const shame += media_faces * ARC_MEDIA_FACE_COST; } + // Streaming cost for animated objects includes a fixed cost + // per linkset. Add a corresponding charge here translated into + // triangles, but not weighted by any graphics properties. + if (isAnimatedObject() && isRootEdit()) + { + shame += (ANIMATED_OBJECT_BASE_COST/0.06) * 5.0f; + } if (shame > mRenderComplexity_current) { mRenderComplexity_current = (S32)shame; @@ -3538,15 +3920,65 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const return (U32)shame; } -F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +F32 LLVOVolume::getEstTrianglesMax() const +{ + if (isMesh() && getVolume()) + { + return gMeshRepo.getEstTrianglesMax(getVolume()->getParams().getSculptID()); + } + return 0.f; +} + +F32 LLVOVolume::getEstTrianglesStreamingCost() const +{ + if (isMesh() && getVolume()) + { + return gMeshRepo.getEstTrianglesStreamingCost(getVolume()->getParams().getSculptID()); + } + return 0.f; +} + +F32 LLVOVolume::getStreamingCost() const { F32 radius = getScale().length()*0.5f; + F32 linkset_base_cost = 0.f; + LLMeshCostData costs; + if (getCostData(costs)) + { + if (isAnimatedObject() && isRootEdit()) + { + // Root object of an animated object has this to account for skeleton overhead. + linkset_base_cost = ANIMATED_OBJECT_BASE_COST; + } + if (isMesh()) + { + if (isAnimatedObject() && isRiggedMesh()) + { + return linkset_base_cost + costs.getTriangleBasedStreamingCost(); + } + else + { + return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); + } + } + else + { + return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); + } + } + else + { + return 0.f; + } +} + +// virtual +bool LLVOVolume::getCostData(LLMeshCostData& costs) const +{ if (isMesh()) - { - LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID()); - - return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD, unscaled_value); + { + return gMeshRepo.getCostData(getVolume()->getParams().getSculptID(), costs); } else { @@ -3560,8 +3992,8 @@ F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_v header["medium_lod"]["size"] = counts[2] * 10; header["high_lod"]["size"] = counts[3] * 10; - return LLMeshRepository::getStreamingCost(header, radius, NULL, NULL, -1, unscaled_value); - } + return LLMeshRepository::getCostData(header, costs); + } } //static @@ -3631,6 +4063,21 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u { mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin); } + if (!local_origin && param_type == LLNetworkData::PARAMS_EXTENDED_MESH) + { + U32 extended_mesh_flags = getExtendedMeshFlags(); + bool enabled = (extended_mesh_flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG); + bool was_enabled = (getControlAvatar() != NULL); + if (enabled != was_enabled) + { + LL_DEBUGS("AnimatedObjects") << this + << " calling onSetExtendedMeshFlags, enabled " << (U32) enabled + << " was_enabled " << (U32) was_enabled + << " local_origin " << (U32) local_origin + << LL_ENDL; + onSetExtendedMeshFlags(extended_mesh_flags); + } + } if (mDrawable.notNull()) { BOOL is_light = getIsLight(); @@ -3644,10 +4091,17 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u void LLVOVolume::setSelected(BOOL sel) { LLViewerObject::setSelected(sel); - if (mDrawable.notNull()) - { - markForUpdate(TRUE); - } + if (isAnimatedObject()) + { + getRootEdit()->recursiveMarkForUpdate(TRUE); + } + else + { + if (mDrawable.notNull()) + { + markForUpdate(TRUE); + } + } } void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) @@ -3710,7 +4164,12 @@ F32 LLVOVolume::getBinRadius() } else if (mDrawable->isStatic()) { - radius = llmax((S32) mDrawable->getRadius(), 1)*size_factor; + F32 szf = size_factor; + + radius = llmax(mDrawable->getRadius(), szf); + + radius = powf(radius, 1.f+szf/radius); + radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1]; radius += mDrawable->mDistanceWRTCamera * distance_factor[0]; } @@ -3756,6 +4215,12 @@ const LLMatrix4a& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const return xform->getWorldMatrix(); } +void LLVOVolume::markForUpdate(BOOL priority) +{ + LLViewerObject::markForUpdate(priority); + mVolumeChanged = TRUE; +} + LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const { LLVector3 ret = pos - getRenderPosition(); @@ -4016,7 +4481,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& bool LLVOVolume::treatAsRigged() { return (gFloaterTools->getVisible() || LLFloaterInspect::findInstance()) && - isAttachment() && + (isAttachment() || isAnimatedObject()) && mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED); } @@ -4048,9 +4513,7 @@ void LLVOVolume::updateRiggedVolume(bool force_update) } LLVolume* volume = getVolume(); - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this); - + const LLMeshSkinInfo* skin = getSkinInfo(); if (!skin) { clearRiggedVolume(); @@ -4103,6 +4566,18 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons { copyVolumeFaces(volume); } + else + { + bool is_paused = avatar && avatar->areAnimationsPaused(); + if (is_paused) + { + S32 frames_paused = LLFrameTimer::getFrameCount() - avatar->getMotionController().getPausedFrame(); + if (frames_paused > 2) + { + return; + } + } + } //build matrix palette static const size_t kMaxJoints = LL_MAX_JOINTS_PER_MESH_OBJECT; @@ -4111,6 +4586,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin); LLSkinningUtil::initSkinningMatrixPalette(mat, maxJoints, skin, avatar, true); + LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); @@ -4149,7 +4625,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons bind_shape_matrix.affineTransform(v, t); final_mat.affineTransform(t, pos[j]); - pos[j].add(av_pos); + pos[j].add(av_pos); // Algorithm tweaked to stop hosing up normals. } //update bounding box @@ -4632,6 +5108,81 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) return NULL; } +void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value) +{ + static LLCachedControl render_auto_mute_byte_limit(gSavedSettings, "RenderAutoMuteByteLimit", 0U); + + if (0 != render_auto_mute_byte_limit) + { + //for unload + LLSculptIDSize::container_BY_SIZE_view::iterator + itL = LLSculptIDSize::instance().getSizeInfo().get().lower_bound(render_auto_mute_byte_limit), + itU = LLSculptIDSize::instance().getSizeInfo().get().end(); + + for (; itL != itU; ++itL) + { + const LLSculptIDSize::Info &nfo = *itL; + LLVOVolume *pVVol = nfo.getPtrLLDrawable()->getVOVolume(); + if (pVVol + && !pVVol->isDead() + && pVVol->isAttachment() + && !pVVol->getAvatar()->isSelf() + && LLVOVolume::NO_LOD != pVVol->getLOD() + ) + { + //postponed + pVVol->markForUnload(); + LLSculptIDSize::instance().addToUnloaded(nfo.getSculptId()); + } + } + + //for load if it was unload + itL = LLSculptIDSize::instance().getSizeInfo().get().begin(); + itU = LLSculptIDSize::instance().getSizeInfo().get().upper_bound(render_auto_mute_byte_limit); + + for (; itL != itU; ++itL) + { + const LLSculptIDSize::Info &nfo = *itL; + LLVOVolume *pVVol = nfo.getPtrLLDrawable()->getVOVolume(); + if (pVVol + && !pVVol->isDead() + && pVVol->isAttachment() + && !pVVol->getAvatar()->isSelf() + && LLVOVolume::NO_LOD == pVVol->getLOD() + ) + { + LLSculptIDSize::instance().remFromUnloaded(nfo.getSculptId()); + pVVol->updateLOD(); + pVVol->markForUpdate(TRUE); + } + } + } + else + { + LLSculptIDSize::instance().clearUnloaded(); + + LLSculptIDSize::container_BY_SIZE_view::iterator + itL = LLSculptIDSize::instance().getSizeInfo().get().begin(), + itU = LLSculptIDSize::instance().getSizeInfo().get().end(); + + for (; itL != itU; ++itL) + { + const LLSculptIDSize::Info &nfo = *itL; + LLVOVolume *pVVol = nfo.getPtrLLDrawable()->getVOVolume(); + if (pVVol + && !pVVol->isDead() + && pVVol->isAttachment() + && !pVVol->getAvatar()->isSelf() + && LLVOVolume::NO_LOD == pVVol->getLOD() + ) + { + pVVol->updateLOD(); + pVVol->markForUpdate(TRUE); + } + } + } +} + void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (LLPipeline::sSkipUpdate) @@ -4659,34 +5210,26 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) group->mBuilt = 1.f; - LLVOAvatar* pAvatarVO = NULL; - LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); + LLViewerObject *vobj = NULL; + LLVOVolume *vol_obj = NULL; + if (bridge) { - if (bridge->mAvatar.isNull()) - { - LLViewerObject* vobj = bridge->mDrawable->getVObj(); - if (vobj) - { - bridge->mAvatar = vobj->getAvatar(); - } - } - - pAvatarVO = bridge->mAvatar; - } - - if (pAvatarVO) - { - pAvatarVO->mAttachmentGeometryBytes -= group->mGeometryBytes; - pAvatarVO->mAttachmentSurfaceArea -= group->mSurfaceArea; + vobj = bridge->mDrawable->getVObj(); + vol_obj = dynamic_cast(vobj); } + if (vol_obj) + { + vol_obj->updateVisualComplexity(); + } group->mGeometryBytes = 0; group->mSurfaceArea = 0; //cache object box size since it might be used for determining visibility - group->mObjectBoxSize = group->getObjectBounds()[1].getLength3().getF32(); + const LLVector4a* bounds = group->getObjectBounds(); + group->mObjectBoxSize = bounds[1].getLength3().getF32(); group->clearDrawMap(); @@ -4721,7 +5264,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); - if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) + if (!drawablep || drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) { continue; } @@ -4751,27 +5294,28 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); } + vobj->updateControlAvatar(); llassert_always(vobj); vobj->updateTextureVirtualSize(true); vobj->preRebuild(); drawablep->clearState(LLDrawable::HAS_ALPHA); - bool rigged = vobj->isAttachment() && - vobj->isMesh() && - gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); + if (vobj->isRiggedMesh() && + ((vobj->isAnimatedObject() && vobj->getControlAvatar()) || + (!vobj->isAnimatedObject() && vobj->getAvatar()))) + { + vobj->getAvatar()->addAttachmentOverridesForObject(vobj, NULL, false); + } + + // Standard rigged mesh attachments: + bool rigged = !vobj->isAnimatedObject() && vobj->isRiggedMesh() && vobj->isAttachment(); + // Animated objects. Have to check for isRiggedMesh() to + // exclude static objects in animated object linksets. + rigged = rigged || (vobj->isAnimatedObject() && vobj->isRiggedMesh() && + vobj->getControlAvatar() && vobj->getControlAvatar()->mPlaying); - bool is_rigged = false; - - if (rigged && pAvatarVO) - { - pAvatarVO->addAttachmentOverridesForObject(vobj); - /*if (!LLApp::isExiting() && pAvatarVO->isSelf() && debugLoggingEnabled("AvatarAttachments")) - { - bool verbose = true; - pAvatarVO->showAttachmentOverrides(verbose); - }*/ - } + bool any_rigged_face = false; static const LLCachedControl alt_batching("SHAltBatching",true); @@ -4801,7 +5345,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } facep->setState(LLFace::RIGGED); - is_rigged = true; + any_rigged_face = true; //get drawpool of avatar with rigged face LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); @@ -5397,7 +5941,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } - if (is_rigged) + if (any_rigged_face) { if (!drawablep->isState(LLDrawable::RIGGED)) { @@ -5411,6 +5955,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) else { drawablep->clearState(LLDrawable::RIGGED); + vobj->updateRiggedVolume(); } } } @@ -5468,12 +6013,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } mFaceList.clear(); - - if (pAvatarVO) - { - pAvatarVO->mAttachmentGeometryBytes += group->mGeometryBytes; - pAvatarVO->mAttachmentSurfaceArea += group->mSurfaceArea; - } } @@ -5500,9 +6039,11 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); - if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) + if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) { LLVOVolume* vobj = drawablep->getVOVolume(); + if (vobj->isNoLOD()) continue; + vobj->preRebuild(); if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 6dea71981..6ea85ccc2 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -142,13 +142,18 @@ public: void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); /*virtual*/ BOOL setParent(LLViewerObject* parent); S32 getLOD() const { return mLOD; } + void setNoLOD() { mLOD = NO_LOD; mLODChanged = TRUE; } + bool isNoLOD() const { return NO_LOD == mLOD; } const LLVector3 getPivotPositionAgent() const; const LLMatrix4a& getRelativeXform() const { return mRelativeXform; } const LLMatrix4a& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; } /*virtual*/ const LLMatrix4a& getRenderMatrix() const; typedef std::map texture_cost_t; U32 getRenderCost(texture_cost_t &textures) const; - /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; + /*virtual*/ F32 getEstTrianglesMax() const; + /*virtual*/ F32 getEstTrianglesStreamingCost() const; + /* virtual*/ F32 getStreamingCost() const; + /*virtual*/ bool getCostData(LLMeshCostData& costs) const; /*virtual*/ U32 getTriangleCount(S32* vcount = NULL) const; /*virtual*/ U32 getHighLODTriangleCount(); @@ -173,8 +178,9 @@ public: /*virtual*/ F32 getRadius() const { return mVObjRadius; }; const LLMatrix4a& getWorldMatrix(LLXformMatrix* xform) const; - void markForUpdate(BOOL priority) { LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; } - void faceMappingChanged() { mFaceMappingChanged=TRUE; }; + void markForUpdate(BOOL priority); + void markForUnload() { LLViewerObject::markForUnload(TRUE); mVolumeChanged = TRUE; } + void faceMappingChanged() { mFaceMappingChanged=TRUE; }; /*virtual*/ void onShift(const LLVector4a &shift_vector); // Called when the drawable shifts @@ -273,13 +279,28 @@ public: virtual BOOL isFlexible() const; virtual BOOL isSculpted() const; virtual BOOL isMesh() const; + virtual BOOL isRiggedMesh() const; virtual BOOL hasLightTexture() const; BOOL isVolumeGlobal() const; BOOL canBeFlexible() const; BOOL setIsFlexible(BOOL is_flexible); + const LLMeshSkinInfo* getSkinInfo() const; + + // Extended Mesh Properties + U32 getExtendedMeshFlags() const; + void onSetExtendedMeshFlags(U32 flags); + void setExtendedMeshFlags(U32 flags); + bool canBeAnimatedObject() const; + bool isAnimatedObject() const; + virtual void onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent); + virtual void afterReparent(); + //virtual + void updateRiggingInfo(); + S32 mLastRiggingInfoLOD; + // Functions that deal with media, or media navigation // Update this object's media data with the given media data array @@ -317,6 +338,8 @@ public: // tag: vaa emerald local_asset_browser void setSculptChanged(BOOL has_changed) { mSculptChanged = has_changed; } + // Flag any corresponding avatars as needing update. + void updateVisualComplexity(); void notifyMeshLoaded(); // Returns 'true' iff the media data for this object is in flight @@ -345,7 +368,7 @@ public: void clearRiggedVolume(); protected: - S32 computeLODDetail(F32 distance, F32 radius); + S32 computeLODDetail(F32 distance, F32 radius, F32 lod_factor); BOOL calcLOD(); LLFace* addFace(S32 face_index); void updateTEData(); @@ -360,7 +383,7 @@ protected: void removeMediaImpl(S32 texture_index) ; private: - bool lodOrSculptChanged(LLDrawable *drawable); + bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled); public: @@ -369,6 +392,9 @@ public: LLViewerTextureAnim *mTextureAnimp; U8 mTexAnimMode; + F32 mLODDistance; + F32 mLODAdjustedDistance; + F32 mLODRadius; private: friend class LLDrawable; friend class LLFace; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index fdd105270..4e94ce3b2 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -769,6 +769,17 @@ void LLWorld::updateRegions(F32 max_update_time) } } + +void LLWorld::clearAllVisibleObjects() +{ + for (region_list_t::iterator iter = mRegionList.begin(); + iter != mRegionList.end(); ++iter) + { + //clear all cached visible objects. + (*iter)->clearCachedVisibleObjects(); + } +} + void LLWorld::updateParticles() { static const LLCachedControl freeze_time("FreezeTime",false); @@ -842,7 +853,6 @@ LLCloudGroup* LLWorld::findCloudGroup(const LLCloudPuff &puff) } #endif - void LLWorld::renderPropertyLines() { S32 region_count = 0; diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index fa65c364a..1620a9241 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -157,6 +157,7 @@ public: void getInfo(LLSD& info); + void clearAllVisibleObjects(); public: typedef std::list region_list_t; const region_list_t& getRegionList() const { return mActiveRegionList; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 8520ce150..024075303 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -290,6 +290,8 @@ void glh_set_last_projection(const LLMatrix4a& mat) void display_update_camera(bool tiling=false); //---------------------------------------- +S32 LLPipeline::sCompiles = 0; + BOOL LLPipeline::sPickAvatar = TRUE; BOOL LLPipeline::sDynamicLOD = TRUE; BOOL LLPipeline::sShowHUDAttachments = TRUE; @@ -566,6 +568,7 @@ void LLPipeline::destroyGL() unloadShaders(); mHighlightFaces.clear(); + resetDrawOrders(); releaseVertexBuffers(); @@ -1767,6 +1770,8 @@ void LLPipeline::resetFrameStats() { assertInitialized(); + sCompiles = 0; + LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); if (mBatchCount > 0) @@ -2514,7 +2519,7 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT void LLPipeline::doOcclusion(LLCamera& camera) { - if (LLGLSLShader::sNoFixedFunction && LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups()) + if (LLGLSLShader::sNoFixedFunction && LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested && sCull->hasOcclusionGroups()) { LLVertexBuffer::unbind(); @@ -2668,6 +2673,52 @@ void LLPipeline::clearRebuildGroups() mGroupQ2Locked = false; } +void LLPipeline::clearRebuildDrawables() +{ + // Clear all drawables on the priority build queue, + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin(); + iter != mBuildQ1.end(); ++iter) + { + LLDrawable* drawablep = *iter; + if (drawablep && !drawablep->isDead()) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q2); + drawablep->clearState(LLDrawable::IN_REBUILD_Q1); + } + } + mBuildQ1.clear(); + + // clear drawables on the non-priority build queue + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin(); + iter != mBuildQ2.end(); ++iter) + { + LLDrawable* drawablep = *iter; + if (!drawablep->isDead()) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q2); + } + } + mBuildQ2.clear(); + + //clear all moving bridges + for (LLDrawable::drawable_vector_t::iterator iter = mMovedBridge.begin(); + iter != mMovedBridge.end(); ++iter) + { + LLDrawable *drawablep = *iter; + drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED | LLDrawable::ON_MOVE_LIST | LLDrawable::ANIMATED_CHILD); + } + mMovedBridge.clear(); + + //clear all moving drawables + for (LLDrawable::drawable_vector_t::iterator iter = mMovedList.begin(); + iter != mMovedList.end(); ++iter) + { + LLDrawable *drawablep = *iter; + drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED | LLDrawable::ON_MOVE_LIST | LLDrawable::ANIMATED_CHILD); + } + mMovedList.clear(); +} + static LLTrace::BlockTimerStatHandle FTM_REBUILD_PRIORITY_GROUPS("Rebuild Priority Groups"); void LLPipeline::rebuildPriorityGroups() @@ -2783,6 +2834,11 @@ void LLPipeline::updateGeom(F32 max_dtime, LLCamera& camera) } } + if (drawablep->isUnload()) + { + drawablep->unload(); + drawablep->clearState(LLDrawable::FOR_UNLOAD); + } if (updateDrawableGeom(drawablep, TRUE)) { drawablep->clearState(LLDrawable::IN_REBUILD_Q1); @@ -6591,16 +6647,37 @@ void LLPipeline::resetVertexBuffers() static LLTrace::BlockTimerStatHandle FTM_RESET_VB("Reset VB"); -void LLPipeline::doResetVertexBuffers() +void LLPipeline::doResetVertexBuffers(bool forced) { if ( !mResetVertexBuffers) { return; } - mResetVertexBuffers = false; + if(!forced && LLSpatialPartition::sTeleportRequested) + { + if(gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) + { + return; //wait for teleporting to finish + } + else + { + //teleporting aborted + LLSpatialPartition::sTeleportRequested = FALSE; + mResetVertexBuffers = false; + return; + } + } LL_RECORD_BLOCK_TIME(FTM_RESET_VB); + mResetVertexBuffers = false; releaseVertexBuffers(); + if(LLSpatialPartition::sTeleportRequested) + { + LLSpatialPartition::sTeleportRequested = FALSE; + + LLWorld::getInstance()->clearAllVisibleObjects(); + clearRebuildDrawables(); + } refreshCachedSettings(); @@ -7850,6 +7927,12 @@ void LLPipeline::renderDeferredLighting() } } + const LLViewerObject *vobj = drawablep->getVObj(); + if(vobj && vobj->getAvatar() + && (vobj->getAvatar()->isTooComplex())) + { + continue; + } LLVector4a center; center.load3(drawablep->getPositionAgent().mV); @@ -10576,11 +10659,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) avatar->setImpostorDim(tdim); - LLVOAvatar::sUseImpostors = TRUE; + LLVOAvatar::sUseImpostors = true; sUseOcclusion = occlusion; - sReflectionRender = FALSE; - sImpostorRender = FALSE; - sShadowRender = FALSE; + sReflectionRender = false; + sImpostorRender = false; + sShadowRender = false; popRenderTypeMask(); gGL.matrixMode(LLRender::MM_PROJECTION); @@ -10590,6 +10673,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) avatar->mNeedsImpostorUpdate = FALSE; avatar->cacheImpostorValues(); + avatar->mLastImpostorUpdateFrameTime = gFrameTimeSeconds; LLVertexBuffer::unbind(); LLGLStateValidator::checkStates(); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index bbe736d8c..ef399c1f8 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -115,7 +115,7 @@ public: void destroyGL(); void restoreGL(); void resetVertexBuffers(); - void doResetVertexBuffers(); + void doResetVertexBuffers(bool forced = false); void resizeScreenTexture(); void releaseVertexBuffers(); void releaseGLBuffers(); @@ -254,6 +254,7 @@ public: void rebuildPriorityGroups(); void rebuildGroups(); void clearRebuildGroups(); + void clearRebuildDrawables(); //calculate pixel area of given box from vantage point of given camera static F32 calcPixelArea(LLVector3 center, LLVector3 size, LLCamera& camera); @@ -569,6 +570,8 @@ public: S32 mTrianglesDrawn; S32 mNumVisibleNodes; + static S32 sCompiles; + static BOOL sShowHUDAttachments; static BOOL sForceOldBakedUpload; // If true will not use capabilities to upload baked textures. static S32 sUseOcclusion; // 0 = no occlusion, 1 = read only, 2 = read/write diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 92055cbde..fcffd476a 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -370,7 +370,7 @@ RlvObject::RlvObject(const LLUUID& idObj) : m_idObj(idObj), m_nLookupMisses(0) { LLViewerObject* pObj = gObjectList.findObject(idObj); m_fLookup = (NULL != pObj); - m_idxAttachPt = (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0; + m_idxAttachPt = (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getAttachmentState()) : 0; m_idRoot = (pObj) ? pObj->getRootEdit()->getID() : LLUUID::null; } diff --git a/indra/newview/rlvlocks.h b/indra/newview/rlvlocks.h index 396496290..854144bee 100644 --- a/indra/newview/rlvlocks.h +++ b/indra/newview/rlvlocks.h @@ -422,7 +422,7 @@ inline S32 RlvAttachPtLookup::getAttachPointIndex(std::string strText) // Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d inline S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerObject* pObj) { - return (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0; + return (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getAttachmentState()) : 0; } // ============================================================================ diff --git a/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml b/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml index fb7ba092d..5d208a06a 100644 --- a/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml +++ b/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml @@ -38,9 +38,11 @@ + +