Merged in lindenlab/axon

master
AndreyL ProductEngine 2018-11-14 16:20:05 +02:00
commit 39652180ae
107 changed files with 6513 additions and 1576 deletions

View File

@ -236,6 +236,14 @@
<boolean>false</boolean>
</map>
<key>ObjectAnimation</key>
<map>
<key>flavor</key>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
<key>AvatarAppearance</key>
<map>
<key>flavor</key>

View File

@ -190,7 +190,8 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
mNumBones(0),
mNumCollisionVolumes(0),
mCollisionVolumes(NULL),
mIsBuilt(FALSE)
mIsBuilt(FALSE),
mInitFlags(0)
{
llassert_always(mWearableData);
mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES);
@ -281,6 +282,8 @@ void LLAvatarAppearance::initInstance()
buildCharacter();
mInitFlags |= 1<<0;
}
// virtual
@ -1724,7 +1727,7 @@ void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info)
}
mJointAliasMap[*i] = bone_name;
}
LLAvatarBoneInfo::child_list_t::const_iterator iter;
for (iter = bone_info->mChildList.begin(); iter != bone_info->mChildList.end(); ++iter)
{
@ -1739,13 +1742,34 @@ const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases
{
LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter;
for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin(); iter != sAvatarSkeletonInfo->mBoneInfoList.end(); ++iter)
for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin();
iter != sAvatarSkeletonInfo->mBoneInfoList.end();
++iter)
{
//LLAvatarBoneInfo *bone_info = *iter;
makeJointAliases( *iter );
}
LLAvatarXmlInfo::attachment_info_list_t::iterator attach_iter;
for (attach_iter = sAvatarXmlInfo->mAttachmentInfoList.begin();
attach_iter != sAvatarXmlInfo->mAttachmentInfoList.end();
++attach_iter)
{
LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *attach_iter;
std::string bone_name = info->mName;
// Also accept the name with spaces substituted with
// underscores. This gives a mechanism for referencing such joints
// in daes, which don't allow spaces.
std::string sub_space_to_underscore = bone_name;
LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_');
if (sub_space_to_underscore != bone_name)
{
mJointAliasMap[sub_space_to_underscore] = bone_name;
}
}
}
return mJointAliasMap;
}

View File

@ -70,6 +70,7 @@ public:
static void initClass();
static void cleanupClass(); // Cleanup data that's only init'd once per class.
virtual void initInstance(); // Called after construction to initialize the instance.
S32 mInitFlags;
virtual BOOL loadSkeletonNode();
BOOL loadMeshNodes();
BOOL loadLayersets();
@ -227,7 +228,7 @@ protected:
** RENDERING
**/
public:
BOOL mIsDummy; // for special views
BOOL mIsDummy; // for special views and animated object controllers; local to viewer
//--------------------------------------------------------------------
// Morph masks

View File

@ -428,13 +428,6 @@ void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh
{
return;
}
// BENTO
// Not clear pelvis overrides are meaningful/useful.
//if (mName == "mPelvis")
//{
// return;
//}
LLVector3 before_pos;
LLUUID before_mesh_id;
bool has_active_override_before = hasAttachmentPosOverride( before_pos, before_mesh_id );
@ -881,7 +874,7 @@ void LLJoint::setWorldRotation( const LLQuaternion& rot )
//--------------------------------------------------------------------
const LLVector3& LLJoint::getScale()
{
return mXform.getScale();
return mXform.getScale();
}
//--------------------------------------------------------------------

View File

@ -70,6 +70,16 @@ private:
map_type m_map;
};
inline bool operator==(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b)
{
return a.getMap() == b.getMap();
}
inline bool operator!=(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b)
{
return !(a == b);
}
//-----------------------------------------------------------------------------
// class LLJoint
//-----------------------------------------------------------------------------

View File

@ -135,7 +135,7 @@ LLMotionController::LLMotionController()
mLastTime(0.0f),
mHasRunOnce(FALSE),
mPaused(FALSE),
mPauseTime(0.f),
mPausedFrame(0),
mTimeStep(0.f),
mTimeStepCount(0),
mLastInterp(0.f),
@ -441,7 +441,8 @@ BOOL LLMotionController::stopMotionLocally(const LLUUID &id, BOOL stop_immediate
{
// if already inactive, return false
LLMotion *motion = findMotion(id);
return stopMotionInstance(motion, stop_immediate);
// SL-1290: always stop immediate if paused
return stopMotionInstance(motion, stop_immediate||mPaused);
}
BOOL LLMotionController::stopMotionInstance(LLMotion* motion, BOOL stop_immediate)
@ -814,6 +815,10 @@ void LLMotionController::updateLoadingMotions()
//-----------------------------------------------------------------------------
void LLMotionController::updateMotions(bool force_update)
{
// SL-763: "Distant animated objects run at super fast speed"
// The use_quantum optimization or possibly the associated code in setTimeStamp()
// does not work as implemented.
// Currently setting mTimeStep to nonzero is disabled elsewhere.
BOOL use_quantum = (mTimeStep != 0.f);
// Always update mPrevTimerElapsed
@ -1125,6 +1130,7 @@ void LLMotionController::pauseAllMotions()
{
//LL_INFOS() << "Pausing animations..." << LL_ENDL;
mPaused = TRUE;
mPausedFrame = LLFrameTimer::getFrameCount();
}
}

View File

@ -148,12 +148,16 @@ public:
void pauseAllMotions();
void unpauseAllMotions();
BOOL isPaused() const { return mPaused; }
S32 getPausedFrame() const { return mPausedFrame; }
void setTimeStep(F32 step);
F32 getTimeStep() const { return mTimeStep; }
void setTimeFactor(F32 time_factor);
F32 getTimeFactor() const { return mTimeFactor; }
F32 getAnimTime() const { return mAnimTime; }
motion_list_t& getActiveMotions() { return mActiveMotions; }
void incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions);
@ -218,7 +222,7 @@ protected:
F32 mLastTime;
BOOL mHasRunOnce;
BOOL mPaused;
F32 mPauseTime;
S32 mPausedFrame;
F32 mTimeStep;
S32 mTimeStepCount;
F32 mLastInterp;

View File

@ -78,3 +78,10 @@ struct LLContextStatus
};
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status);
#define dumpStack(tag) \
if (debugLoggingEnabled(tag)) \
{ \
LLCallStack cs; \
LL_DEBUGS(tag) << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL; \
}

View File

@ -29,6 +29,7 @@
#include "llerror.h"
#include "llerrorcontrol.h"
#include "llsdutil.h"
#include <cctype>
#ifdef __GNUC__
@ -89,9 +90,14 @@ namespace {
{
closelog();
}
virtual bool enabled() override
{
return LLError::getEnabledLogTypesMask() & 0x01;
}
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
const std::string& message) override
{
int syslogPriority = LOG_CRIT;
switch (level) {
@ -119,6 +125,13 @@ namespace {
{
LL_INFOS() << "Error setting log file to " << filename << LL_ENDL;
}
else
{
if (!LLError::getAlwaysFlush())
{
mFile.sync_with_stdio(false);
}
}
mWantsTime = true;
mWantsTags = true;
}
@ -128,12 +141,28 @@ namespace {
mFile.close();
}
virtual bool enabled() override
{
#ifdef LL_RELEASE_FOR_DOWNLOAD
return 1;
#else
return LLError::getEnabledLogTypesMask() & 0x02;
#endif
}
bool okay() { return mFile.good(); }
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
const std::string& message) override
{
mFile << message << std::endl;
if (LLError::getAlwaysFlush())
{
mFile << message << std::endl;
}
else
{
mFile << message << "\n";
}
}
private:
@ -149,8 +178,13 @@ namespace {
mWantsTime = timestamp;
}
virtual bool enabled() override
{
return LLError::getEnabledLogTypesMask() & 0x04;
}
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
const std::string& message) override
{
if (ANSI_PROBE == mUseANSI)
mUseANSI = (checkANSI() ? ANSI_YES : ANSI_NO);
@ -209,8 +243,13 @@ namespace {
public:
RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { }
virtual bool enabled() override
{
return LLError::getEnabledLogTypesMask() & 0x08;
}
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
const std::string& message) override
{
mBuffer->addLine(message);
}
@ -226,8 +265,13 @@ namespace {
RecordToWinDebug()
{}
virtual bool enabled() override
{
return LLError::getEnabledLogTypesMask() & 0x10;
}
virtual void recordMessage(LLError::ELevel level,
const std::string& message)
const std::string& message) override
{
debugger_print(message);
}
@ -394,7 +438,7 @@ namespace
i != callSites.end();
++i)
{
(*i)->invalidate();
(*i)->invalidate();
}
callSites.clear();
@ -413,7 +457,11 @@ namespace LLError
bool mPrintLocation;
LLError::ELevel mDefaultLevel;
bool mLogAlwaysFlush;
U32 mEnabledLogTypesMask;
LevelMap mFunctionLevelMap;
LevelMap mClassLevelMap;
LevelMap mFileLevelMap;
@ -454,6 +502,8 @@ namespace LLError
: LLRefCount(),
mPrintLocation(false),
mDefaultLevel(LLError::LEVEL_DEBUG),
mLogAlwaysFlush(true),
mEnabledLogTypesMask(255),
mFunctionLevelMap(),
mClassLevelMap(),
mFileLevelMap(),
@ -618,6 +668,8 @@ namespace
LLError::Settings::getInstance()->reset();
LLError::setDefaultLevel(LLError::LEVEL_INFO);
LLError::setAlwaysFlush(true);
LLError::setEnabledLogTypesMask(0xFFFFFFFF);
LLError::setFatalFunction(LLError::crashAndLoop);
LLError::setTimeFunction(LLError::utcTime);
@ -691,6 +743,30 @@ namespace LLError
return s->mDefaultLevel;
}
void setAlwaysFlush(bool flush)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
s->mLogAlwaysFlush = flush;
}
bool getAlwaysFlush()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
return s->mLogAlwaysFlush;
}
void setEnabledLogTypesMask(U32 mask)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
s->mEnabledLogTypesMask = mask;
}
U32 getEnabledLogTypesMask()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
return s->mEnabledLogTypesMask;
}
void setFunctionLevel(const std::string& function_name, ELevel level)
{
Globals::getInstance()->invalidateCallSites();
@ -771,7 +847,15 @@ namespace LLError
setPrintLocation(config["print-location"]);
setDefaultLevel(decodeLevel(config["default-level"]));
if (config.has("log-always-flush"))
{
setAlwaysFlush(config["log-always-flush"]);
}
if (config.has("enabled-log-types-mask"))
{
setEnabledLogTypesMask(config["enabled-log-types-mask"].asInteger());
}
LLSD sets = config["settings"];
LLSD::array_const_iterator a, end;
for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
@ -954,7 +1038,12 @@ namespace
++i)
{
LLError::RecorderPtr r = *i;
if (!r->enabled())
{
continue;
}
std::ostringstream message_stream;
if (r->wantsTime() && s->mTimeFunction != NULL)
@ -1088,6 +1177,7 @@ namespace {
namespace LLError
{
bool Log::shouldLog(CallSite& site)
{
LogLock lock;
@ -1553,18 +1643,16 @@ namespace LLError
bool debugLoggingEnabled(const std::string& tag)
{
const char* tags[] = {tag.c_str()};
::size_t tag_count = 1;
LLError::CallSite _site(LLError::LEVEL_DEBUG, __FILE__, __LINE__,
typeid(_LL_CLASS_TO_LOG), __FUNCTION__, false, tags, tag_count);
if (LL_UNLIKELY(_site.shouldLog()))
{
return true;
}
else
LogLock lock;
if (!lock.ok())
{
return false;
}
LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
LLError::ELevel level = LLError::LEVEL_DEBUG;
bool res = checkLevelMap(s->mTagLevelMap, tag, level);
return res;
}

View File

@ -74,6 +74,10 @@ namespace LLError
LL_COMMON_API void setPrintLocation(bool);
LL_COMMON_API void setDefaultLevel(LLError::ELevel);
LL_COMMON_API ELevel getDefaultLevel();
LL_COMMON_API void setAlwaysFlush(bool flush);
LL_COMMON_API bool getAlwaysFlush();
LL_COMMON_API void setEnabledLogTypesMask(U32 mask);
LL_COMMON_API U32 getEnabledLogTypesMask();
LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel);
LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel);
LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel);
@ -140,6 +144,8 @@ namespace LLError
virtual void recordMessage(LLError::ELevel, const std::string& message) = 0;
// use the level for better display, not for filtering
virtual bool enabled() { return true; }
bool wantsTime();
bool wantsTags();
bool wantsLevel();

View File

@ -60,6 +60,12 @@ class LLMutex ;
LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);
#ifdef SHOW_ASSERT
// This is incredibly expensive - in profiling Windows RWD builds, 30%
// of CPU time was in aligment checks.
//#define ASSERT_ALIGNMENT
#endif
#ifdef ASSERT_ALIGNMENT
#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(uintptr_t(ptr),((U32)alignment))
#else
#define ll_assert_aligned(ptr,alignment)

View File

@ -869,6 +869,25 @@ std::string LLStringOps::getDatetimeCode (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
{

View File

@ -211,6 +211,9 @@ public:
static bool getPacificDaylightTime(void) { return sPacificDaylightTime;}
static std::string getDatetimeCode (std::string key);
// Express a value like 1234567 as "1.23M"
static std::string getReadableNumber(F64 num);
};
/**

View File

@ -20,10 +20,12 @@ set(llmath_SOURCE_FILES
llcoordframe.cpp
llline.cpp
llmatrix3a.cpp
llmatrix4a.cpp
llmodularmath.cpp
lloctree.cpp
llperlin.cpp
llquaternion.cpp
llrigginginfo.cpp
llrect.cpp
llsphere.cpp
llvector4a.cpp
@ -70,6 +72,7 @@ set(llmath_HEADER_FILES
llquaternion2.h
llquaternion2.inl
llrect.h
llrigginginfo.h
llsimdmath.h
llsimdtypes.h
llsimdtypes.inl

View File

@ -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]);
}
}

View File

@ -121,7 +121,7 @@ public:
res.add(z);
}
inline void affineTransformSSE(const LLVector4a& v, LLVector4a& res)
inline void affineTransformSSE(const LLVector4a& v, LLVector4a& res) const
{
LLVector4a x,y,z;
@ -138,7 +138,7 @@ public:
res.setAdd(x,z);
}
inline void affineTransformNonSSE(const LLVector4a& v, LLVector4a& res)
inline void affineTransformNonSSE(const LLVector4a& v, LLVector4a& res) const
{
F32 x = v[0] * mMatrix[0][0] + v[1] * mMatrix[1][0] + v[2] * mMatrix[2][0] + mMatrix[3][0];
F32 y = v[0] * mMatrix[0][1] + v[1] * mMatrix[1][1] + v[2] * mMatrix[2][1] + mMatrix[3][1];
@ -147,7 +147,7 @@ public:
res.set(x,y,z,w);
}
inline void affineTransform(const LLVector4a& v, LLVector4a& res)
inline void affineTransform(const LLVector4a& v, LLVector4a& res) const
{
affineTransformSSE(v,res);
}
@ -176,4 +176,12 @@ inline void matMul(const LLMatrix4a &a, const LLMatrix4a &b, LLMatrix4a &res)
res.mMatrix[3] = row3;
}
inline std::ostream& operator<<(std::ostream& s, const LLMatrix4a& m)
{
s << "[" << m.mMatrix[0] << ", " << m.mMatrix[1] << ", " << m.mMatrix[2] << ", " << m.mMatrix[3] << "]";
return s;
}
void matMulBoundBox(const LLMatrix4a &a, const LLVector4a *in_extents, LLVector4a *out_extents);
#endif

View File

@ -0,0 +1,159 @@
/**
* @file llrigginginfo.cpp
* @brief Functions for tracking rigged box extents
*
* $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 "llrigginginfo.h"
//-----------------------------------------------------------------------------
// LLJointRiggingInfo
//-----------------------------------------------------------------------------
LLJointRiggingInfo::LLJointRiggingInfo()
{
mRiggedExtents[0].clear();
mRiggedExtents[1].clear();
mIsRiggedTo = false;
}
bool LLJointRiggingInfo::isRiggedTo() const
{
return mIsRiggedTo;
}
void LLJointRiggingInfo::setIsRiggedTo(bool val)
{
mIsRiggedTo = val;
}
LLVector4a *LLJointRiggingInfo::getRiggedExtents()
{
return mRiggedExtents;
}
const LLVector4a *LLJointRiggingInfo::getRiggedExtents() const
{
return mRiggedExtents;
}
// Combine two rigging info states.
// - isRiggedTo if either of the source infos are rigged to
// - box is union of the two sources
void LLJointRiggingInfo::merge(const LLJointRiggingInfo& other)
{
if (other.mIsRiggedTo)
{
if (mIsRiggedTo)
{
// Combine existing boxes
update_min_max(mRiggedExtents[0], mRiggedExtents[1], other.mRiggedExtents[0]);
update_min_max(mRiggedExtents[0], mRiggedExtents[1], other.mRiggedExtents[1]);
}
else
{
// Initialize box
mIsRiggedTo = true;
mRiggedExtents[0] = other.mRiggedExtents[0];
mRiggedExtents[1] = other.mRiggedExtents[1];
}
}
}
LLJointRiggingInfoTab::LLJointRiggingInfoTab():
mRigInfoPtr(NULL),
mSize(0),
mNeedsUpdate(true)
{
}
LLJointRiggingInfoTab::~LLJointRiggingInfoTab()
{
clear();
}
// This doesn't preserve data if the size changes. In practice
// this doesn't matter because the size is always either
// LL_CHARACTER_MAX_ANIMATED_JOINTS or 0.
void LLJointRiggingInfoTab::resize(S32 size)
{
if (size != mSize)
{
clear();
if (size > 0)
{
mRigInfoPtr = new LLJointRiggingInfo[size];
mSize = size;
}
}
}
void LLJointRiggingInfoTab::clear()
{
if (mRigInfoPtr)
{
delete[](mRigInfoPtr);
mRigInfoPtr = NULL;
mSize = 0;
}
}
void showDetails(const LLJointRiggingInfoTab& src, const std::string& str)
{
S32 count_rigged = 0;
S32 count_box = 0;
LLVector4a zero_vec;
zero_vec.clear();
for (S32 i=0; i<src.size(); i++)
{
if (src[i].isRiggedTo())
{
count_rigged++;
if ((!src[i].getRiggedExtents()[0].equals3(zero_vec)) ||
(!src[i].getRiggedExtents()[1].equals3(zero_vec)))
{
count_box++;
}
}
}
LL_DEBUGS("RigSpammish") << "details: " << str << " has " << count_rigged << " rigged joints, of which " << count_box << " are non-empty" << LL_ENDL;
}
void LLJointRiggingInfoTab::merge(const LLJointRiggingInfoTab& src)
{
//showDetails(*this, "input this");
// Size should be either LL_CHARACTER_MAX_ANIMATED_JOINTS, or 0 if
// no data. Not necessarily the same for both inputs.
if (src.size() > size())
{
resize(src.size());
}
S32 min_size = llmin(size(), src.size());
for (S32 i=0; i<min_size; i++)
{
(*this)[i].merge(src[i]);
}
//showDetails(src, "input src");
//showDetails(*this, "output this");
}

View File

@ -0,0 +1,100 @@
/**
* @file llrigginginfo.h
* @brief Functions for tracking rigged box extents
*
* $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$
*/
// Stores information related to associated rigged mesh vertices
// This lives in llmath because llvolume lives in llmath.
#ifndef LL_LLRIGGINGINFO_H
#define LL_LLRIGGINGINFO_H
#include "llvector4a.h"
// Extents are in joint space
// isRiggedTo is based on the state of all currently associated rigged meshes
LL_ALIGN_PREFIX(16)
class LLJointRiggingInfo
{
public:
LLJointRiggingInfo();
bool isRiggedTo() const;
void setIsRiggedTo(bool val);
LLVector4a *getRiggedExtents();
const LLVector4a *getRiggedExtents() const;
void merge(const LLJointRiggingInfo& other);
void* operator new(size_t size)
{
return ll_aligned_malloc_16(size);
}
void operator delete(void* ptr)
{
ll_aligned_free_16(ptr);
}
void* operator new[](size_t size)
{
return ll_aligned_malloc_16(size);
}
void operator delete[](void* ptr)
{
ll_aligned_free_16(ptr);
}
private:
LL_ALIGN_16(LLVector4a mRiggedExtents[2]);
bool mIsRiggedTo;
} LL_ALIGN_POSTFIX(16);
// For storing all the rigging info associated with a given avatar or
// object, keyed by joint_num.
// Using direct memory management instead of std::vector<> to avoid alignment issues.
class LLJointRiggingInfoTab
{
public:
LLJointRiggingInfoTab();
~LLJointRiggingInfoTab();
void resize(S32 size);
void clear();
S32 size() const { return mSize; }
void merge(const LLJointRiggingInfoTab& src);
LLJointRiggingInfo& operator[](S32 i) { return mRigInfoPtr[i]; }
const LLJointRiggingInfo& operator[](S32 i) const { return mRigInfoPtr[i]; };
bool needsUpdate() { return mNeedsUpdate; }
void setNeedsUpdate(bool val) { mNeedsUpdate = val; }
private:
// Not implemented
LLJointRiggingInfoTab& operator=(const LLJointRiggingInfoTab& src);
LLJointRiggingInfoTab(const LLJointRiggingInfoTab& src);
LLJointRiggingInfo *mRigInfoPtr;
S32 mSize;
bool mNeedsUpdate;
};
#endif

View File

@ -320,7 +320,7 @@ public:
inline const LLVector4a& operator= ( const LLQuad& rhs );
inline operator LLQuad() const;
private:
LLQuad mQ;
} LL_ALIGN_POSTFIX(16);
@ -331,4 +331,9 @@ inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p
max.setMax(max, p);
}
inline std::ostream& operator<<(std::ostream& s, const LLVector4a& v)
{
s << "(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")";
return s;
}
#endif

View File

@ -1,5 +1,4 @@
/**
* @file llvolume.cpp
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
@ -2639,6 +2638,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
}
//calculate bounding box
// VFExtents change
LLVector4a& min = face.mExtents[0];
LLVector4a& max = face.mExtents[1];
@ -4768,6 +4768,7 @@ LLVolumeFace::~LLVolumeFace()
{
ll_aligned_free_16(mExtents);
mExtents = NULL;
mCenter = NULL;
freeData();
}
@ -4949,7 +4950,7 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
//
if (new_face.mNumVertices <= mNumVertices)
{
llassert(new_face.mNumIndices == mNumIndices);
llassert(new_face.mNumIndices == mNumIndices);
swapData(new_face);
}
@ -5570,7 +5571,7 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
// S32 i;
S32 grid_size = (profile.size()-1)/4;
// VFExtents change
LLVector4a& min = mExtents[0];
LLVector4a& max = mExtents[1];
@ -5847,7 +5848,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
LLVector2 cuv;
LLVector2 min_uv, max_uv;
// VFExtents change
LLVector4a& min = mExtents[0];
LLVector4a& max = mExtents[1];
@ -6286,6 +6287,9 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
mNumVertices = num_verts;
mNumAllocatedVertices = num_verts;
// Force update
mJointRiggingInfoTab.clear();
}
void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
@ -6407,96 +6411,6 @@ void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v,
}
}
void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in)
{
U16 offset = mNumVertices;
S32 new_count = face.mNumVertices + mNumVertices;
if (new_count > 65536)
{
LL_ERRS() << "Cannot append face -- 16-bit overflow will occur." << LL_ENDL;
}
if (face.mNumVertices == 0)
{
LL_ERRS() << "Cannot append empty face." << LL_ENDL;
}
U32 old_vsize = mNumVertices*16;
U32 new_vsize = new_count * 16;
U32 old_tcsize = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF;
U32 new_tcsize = (new_count*sizeof(LLVector2)+0xF) & ~0xF;
U32 new_size = new_vsize * 2 + new_tcsize;
//allocate new buffer space
LLVector4a* old_buf = mPositions;
mPositions = (LLVector4a*) ll_aligned_malloc<64>(new_size);
mNormals = mPositions + new_count;
mTexCoords = (LLVector2*) (mNormals+new_count);
mNumAllocatedVertices = new_count;
LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) old_buf, old_vsize);
LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize);
LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) (old_buf+mNumVertices*2), old_tcsize);
mNumVertices = new_count;
//get destination address of appended face
LLVector4a* dst_pos = mPositions+offset;
LLVector2* dst_tc = mTexCoords+offset;
LLVector4a* dst_norm = mNormals+offset;
//get source addresses of appended face
const LLVector4a* src_pos = face.mPositions;
const LLVector2* src_tc = face.mTexCoords;
const LLVector4a* src_norm = face.mNormals;
//load aligned matrices
LLMatrix4a mat, norm_mat;
mat.loadu(mat_in);
norm_mat.loadu(norm_mat_in);
for (U32 i = 0; i < face.mNumVertices; ++i)
{
//transform appended face position and store
mat.affineTransform(src_pos[i], dst_pos[i]);
//transform appended face normal and store
norm_mat.rotate(src_norm[i], dst_norm[i]);
dst_norm[i].normalize3fast();
//copy appended face texture coordinate
dst_tc[i] = src_tc[i];
if (offset == 0 && i == 0)
{ //initialize bounding box
mExtents[0] = mExtents[1] = dst_pos[i];
}
else
{
//stretch bounding box
update_min_max(mExtents[0], mExtents[1], dst_pos[i]);
}
}
new_count = mNumIndices + face.mNumIndices;
//allocate new index buffer
mIndices = (U16*) ll_aligned_realloc_16(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF, (mNumIndices*sizeof(U16)+0xF) & ~0xF);
//get destination address into new index buffer
U16* dst_idx = mIndices+mNumIndices;
mNumIndices = new_count;
for (U32 i = 0; i < face.mNumIndices; ++i)
{ //copy indices, offsetting by old vertex count
dst_idx[i] = face.mIndices[i]+offset;
}
}
BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{
LL_CHECK_MEMORY
@ -6642,7 +6556,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{
update_min_max(face_min, face_max, *cur_pos++);
}
// VFExtents change
mExtents[0] = face_min;
mExtents[1] = face_max;

View File

@ -57,6 +57,7 @@ class LLVolumeTriangle;
#include "llpointer.h"
#include "llfile.h"
#include "llalignedarray.h"
#include "llrigginginfo.h"
//============================================================================
@ -871,8 +872,6 @@ public:
BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
void createTangents();
void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform);
void resizeVertices(S32 num_verts);
void allocateTangents(S32 num_verts);
void allocateWeights(S32 num_verts);
@ -958,6 +957,10 @@ public:
LLVector4a* mWeights;
mutable BOOL mWeightsScrubbed;
// Which joints are rigged to, and the bounding box of any rigged
// vertices per joint.
LLJointRiggingInfoTab mJointRiggingInfoTab;
LLOctreeNode<LLVolumeTriangle>* mOctree;

View File

@ -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;
}

View File

@ -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)
{

View File

@ -818,6 +818,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");

View File

@ -818,6 +818,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;

View File

@ -192,7 +192,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
{
return LLModel::BAD_ELEMENT;
}
// VFExtents change
face.mExtents[0].set(v[0], v[1], v[2]);
face.mExtents[1].set(v[0], v[1], v[2]);
}
@ -254,6 +254,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
if (!found)
{
// VFExtents change
update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());
verts.push_back(cv);
if (verts.size() >= 65535)
@ -305,6 +306,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
}
face = LLVolumeFace();
// VFExtents change
face.mExtents[0].set(v[0], v[1], v[2]);
face.mExtents[1].set(v[0], v[1], v[2]);
point_map.clear();
@ -383,6 +385,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
if (pos_source)
{
v = pos_source->getFloat_array()->getValue();
// VFExtents change
face.mExtents[0].set(v[0], v[1], v[2]);
face.mExtents[1].set(v[0], v[1], v[2]);
}
@ -482,6 +485,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
if (!found)
{
// VFExtents change
update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());
verts.push_back(cv);
if (verts.size() >= 65535)
@ -551,6 +555,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
}
face = LLVolumeFace();
// VFExtents change
face.mExtents[0].set(v[0], v[1], v[2]);
face.mExtents[1].set(v[0], v[1], v[2]);
verts.clear();
@ -734,7 +739,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
{
return LLModel::NO_ERRORS;
}
// VFExtents change
face.mExtents[0] = verts[0].getPosition();
face.mExtents[1] = verts[0].getPosition();
@ -758,6 +763,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
for (std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.begin(); iter != vert_idx.end(); ++iter)
{
new_verts[iter->second] = iter->first;
// VFExtents change
update_min_max(face.mExtents[0], face.mExtents[1], iter->first.getPosition());
}

View File

@ -276,6 +276,7 @@ void LLModel::normalizeVolumeFaces()
// We shrink the extents so
// that they fall within
// the unit cube.
// VFExtents change
face.mExtents[0].add(trans);
face.mExtents[0].mul(scale);
@ -400,40 +401,6 @@ void LLModel::setVolumeFaceData(
LLVector4a::memcpyNonAliased16((F32*) face.mIndices, (F32*) ind.get(), size);
}
void LLModel::appendFaces(LLModel *model, LLMatrix4 &transform, LLMatrix4& norm_mat)
{
if (mVolumeFaces.empty())
{
setNumVolumeFaces(1);
}
LLVolumeFace& face = mVolumeFaces[mVolumeFaces.size()-1];
for (S32 i = 0; i < model->getNumFaces(); ++i)
{
face.appendFace(model->getVolumeFace(i), transform, norm_mat);
}
}
void LLModel::appendFace(const LLVolumeFace& src_face, std::string src_material, LLMatrix4& mat, LLMatrix4& norm_mat)
{
S32 rindex = getNumVolumeFaces()-1;
if (rindex == -1 ||
mVolumeFaces[rindex].mNumVertices + src_face.mNumVertices >= 65536)
{ //empty or overflow will occur, append new face
LLVolumeFace cur_face;
cur_face.appendFace(src_face, mat, norm_mat);
addFace(cur_face);
mMaterialList.push_back(src_material);
}
else
{ //append to existing end face
mVolumeFaces.rbegin()->appendFace(src_face, mat, norm_mat);
}
}
void LLModel::addFace(const LLVolumeFace& face)
{
if (face.mNumVertices == 0)
@ -1391,14 +1358,16 @@ bool LLModel::loadDecomposition(LLSD& header, std::istream& is)
LLMeshSkinInfo::LLMeshSkinInfo():
mPelvisOffset(0.0),
mLockScaleIfJointPosition(false),
mInvalidJointsScrubbed(false)
mInvalidJointsScrubbed(false),
mJointNumsInitialized(false)
{
}
LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin):
mPelvisOffset(0.0),
mLockScaleIfJointPosition(false),
mInvalidJointsScrubbed(false)
mInvalidJointsScrubbed(false),
mJointNumsInitialized(false)
{
fromLLSD(skin);
}

View File

@ -38,7 +38,6 @@ class domMesh;
#define MAX_MODEL_FACES 8
class LLMeshSkinInfo
{
public:
@ -57,6 +56,7 @@ public:
float mPelvisOffset;
bool mLockScaleIfJointPosition;
bool mInvalidJointsScrubbed;
bool mJointNumsInitialized;
};
class LLModel : public LLVolume
@ -158,9 +158,6 @@ public:
EModelStatus getStatus() const {return mStatus;}
static std::string getStatusString(U32 status) ;
void appendFaces(LLModel* model, LLMatrix4& transform, LLMatrix4& normal_transform);
void appendFace(const LLVolumeFace& src_face, std::string src_material, LLMatrix4& mat, LLMatrix4& norm_mat);
void setNumVolumeFaces(S32 count);
void setVolumeFaceData(
S32 f,

View File

@ -81,6 +81,7 @@ public:
GENERATING_VERTEX_BUFFERS,
GENERATING_LOD,
DONE,
WARNING_BIND_SHAPE_ORIENTATION,
ERROR_PARSING, //basically loading failed
ERROR_MATERIALS,
ERROR_PASSWORD_REQUIRED,

View File

@ -1609,6 +1609,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size)
return (size == 17);
case PARAMS_LIGHT_IMAGE:
return (size == 28);
case PARAMS_EXTENDED_MESH:
return (size == 4);
}
return FALSE;
@ -2036,3 +2038,67 @@ bool LLLightImageParams::fromLLSD(LLSD& sd)
return false;
}
//============================================================================
LLExtendedMeshParams::LLExtendedMeshParams()
{
mType = PARAMS_EXTENDED_MESH;
mFlags = 0;
}
BOOL LLExtendedMeshParams::pack(LLDataPacker &dp) const
{
dp.packU32(mFlags, "flags");
return TRUE;
}
BOOL LLExtendedMeshParams::unpack(LLDataPacker &dp)
{
dp.unpackU32(mFlags, "flags");
return TRUE;
}
bool LLExtendedMeshParams::operator==(const LLNetworkData& data) const
{
if (data.mType != PARAMS_EXTENDED_MESH)
{
return false;
}
const LLExtendedMeshParams *param = (const LLExtendedMeshParams*)&data;
if ( (param->mFlags != mFlags) )
{
return false;
}
return true;
}
void LLExtendedMeshParams::copy(const LLNetworkData& data)
{
const LLExtendedMeshParams *param = (LLExtendedMeshParams*)&data;
mFlags = param->mFlags;
}
LLSD LLExtendedMeshParams::asLLSD() const
{
LLSD sd;
sd["flags"] = LLSD::Integer(mFlags);
return sd;
}
bool LLExtendedMeshParams::fromLLSD(LLSD& sd)
{
if (sd.has("flags"))
{
setFlags( sd["flags"].asInteger());
return true;
}
return false;
}

View File

@ -106,6 +106,7 @@ public:
PARAMS_LIGHT_IMAGE = 0x40,
PARAMS_RESERVED = 0x50, // Used on server-side
PARAMS_MESH = 0x60,
PARAMS_EXTENDED_MESH = 0x70,
};
public:
@ -288,6 +289,27 @@ public:
};
class LLExtendedMeshParams : public LLNetworkData
{
protected:
U32 mFlags;
public:
static const U32 ANIMATED_MESH_ENABLED_FLAG = 0x1 << 0;
LLExtendedMeshParams();
/*virtual*/ BOOL pack(LLDataPacker &dp) const;
/*virtual*/ BOOL unpack(LLDataPacker &dp);
/*virtual*/ bool operator==(const LLNetworkData& data) const;
/*virtual*/ void copy(const LLNetworkData& data);
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
void setFlags(const U32& flags) { mFlags = flags; }
U32 getFlags() const { return mFlags; }
};
// This code is not naming-standards compliant. Leaving it like this for
// now to make the connection to code in

View File

@ -151,6 +151,7 @@ set(viewer_SOURCE_FILES
llcommunicationchannel.cpp
llcompilequeue.cpp
llconfirmationmanager.cpp
llcontrolavatar.cpp
llconversationlog.cpp
llconversationloglist.cpp
llconversationloglistitem.cpp
@ -604,6 +605,7 @@ set(viewer_SOURCE_FILES
lltransientfloatermgr.cpp
lltranslate.cpp
lltwitterconnect.cpp
lluiavatar.cpp
lluilistener.cpp
lluploaddialog.cpp
llurl.cpp
@ -773,6 +775,7 @@ set(viewer_HEADER_FILES
llcommunicationchannel.h
llcompilequeue.h
llconfirmationmanager.h
llcontrolavatar.h
llconversationlog.h
llconversationloglist.h
llconversationloglistitem.h
@ -1220,6 +1223,7 @@ set(viewer_HEADER_FILES
lltranslate.h
lltwitterconnect.h
lluiconstants.h
lluiavatar.h
lluilistener.h
lluploaddialog.h
lluploadfloaterobservers.h

View File

@ -1 +1 @@
5.1.10
6.0.0

View File

@ -2,6 +2,22 @@
<map>
<!-- default-level can be ALL, DEBUG, INFO, WARN, ERROR, or NONE -->
<key>default-level</key> <string>INFO</string>
<key>print-location</key> <boolean>false</boolean>
<key>log-always-flush</key> <boolean>true</boolean>
<!-- All log types are enabled by default. Can be toggled individually;
bitwise-or all the ones you want to enable.
Log types and their masks are:
1 - RecordToSyslog (not used by viewer)
2 - RecordToFile (SecondLife.log)
4 - RecordToStderr (this will appear in the console window, if there is one)
8 - RecordToFixedBuffer (viewer debug console)
16 - RecordToWinDebug (on windows, output to VS IDE window)
For example, value of 10 = 2|8 would enable logging only to SecondLife.log and the viewer debug console.
Note: RecordToFile is always enabled in release builds.
-->
<key>enabled-log-types-mask</key> <integer>255</integer>
<key>settings</key>
<array>
<!-- Suppress anything but ERROR for some very verbose components -->
@ -50,6 +66,7 @@
<key>tags</key>
<array>
<!-- sample entry for debugging specific items
<string>AnimatedObjects</string>
<string>Avatar</string>
<string>Inventory</string>
<string>SceneLoadTiming</string>

View File

@ -2182,6 +2182,94 @@
<key>Value</key>
<string />
</map>
<key>DebugAnimatedObjects</key>
<map>
<key>Comment</key>
<string>Show info related to animated objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>DebugObjectLODs</key>
<map>
<key>Comment</key>
<string>Show info related to lod calculations for attached or animated objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>AnimatedObjectsIgnoreLimits</key>
<map>
<key>Comment</key>
<string>Ignore server-enforced limits on animated objects. This is only useful for server testing.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>AnimatedObjectsAllowLeftClick</key>
<map>
<key>Comment</key>
<string>Allow left-click interaction with animated objects. Uncertain how much performance impact this will have.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>AnimatedObjectsGlobalScale</key>
<map>
<key>Comment</key>
<string>Temporary testing: allow an extra scale factor to be forced on animated objects.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>1.00</real>
</map>
<key>AnimatedObjectsMaxLegalOffset</key>
<map>
<key>Comment</key>
<string>Max visual offset between object position and rendered position</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>3.0</real>
</map>
<key>AnimatedObjectsMaxLegalSize</key>
<map>
<key>Comment</key>
<string>Max bounding box size for animated object's rendered position</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>64.0</real>
</map>
<key>AvatarBoundingBoxComplexity</key>
<map>
<key>Comment</key>
<string>How many aspects to consider for avatar bounding box</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>3</integer>
</map>
<key>DebugAvatarAppearanceMessage</key>
<map>
<key>Comment</key>

View File

@ -881,6 +881,16 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
{
gSky.mVOGroundp->setRegion(regionp);
}
if (regionp->capabilitiesReceived())
{
regionp->requestSimulatorFeatures();
}
else
{
regionp->setCapabilitiesReceivedCallback(boost::bind(&LLViewerRegion::requestSimulatorFeatures, regionp));
}
}
else
{

View File

@ -880,7 +880,10 @@ void LLWearableHoldingPattern::onAllComplete()
++it)
{
LLViewerObject *objectp = *it;
gAgentAvatarp->addAttachmentOverridesForObject(objectp);
if (!objectp->isAnimatedObject())
{
gAgentAvatarp->addAttachmentOverridesForObject(objectp);
}
}
// Add new attachments to match those requested.

View File

@ -1086,7 +1086,7 @@ bool LLAppViewer::init()
// don't nag developers who need to run the executable directly
#if LL_RELEASE_FOR_DOWNLOAD
// MAINT-8305: If we're processing a SLURL, skip the launcher check.
if (gSavedSettings.getString("CmdLineLoginLocation").empty())
if (gSavedSettings.getString("CmdLineLoginLocation").empty() && !beingDebugged())
{
const char* PARENT = getenv("PARENT");
if (! (PARENT && std::string(PARENT) == "SL_Launcher"))
@ -3918,12 +3918,6 @@ void LLAppViewer::requestQuit()
gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
}
// Try to send last batch of avatar rez metrics.
if (!gDisconnected && isAgentAvatarValid())
{
gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
}
LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
effectp->setPositionGlobal(gAgent.getPositionGlobal());
effectp->setColor(LLColor4U(gAgent.getEffectColor()));

View File

@ -646,6 +646,11 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
return true;
}
bool LLAppViewerWin32::beingDebugged()
{
return IsDebuggerPresent();
}
bool LLAppViewerWin32::restoreErrorTrap()
{
return true;

View File

@ -49,6 +49,7 @@ protected:
virtual bool initHardwareTest(); // Win32 uses DX9 to test hardware.
virtual bool initParseCommandLine(LLCommandLineParser& clp);
virtual bool beingDebugged();
virtual bool restoreErrorTrap();
virtual void initCrashReporting(bool reportFreeze);

View File

@ -112,8 +112,13 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro(std::string url, U64
)
{
LLUUID target_agent_id = LLUUID(agent_iter->first);
LLViewerObject* avatarp = gObjectList.findObject(target_agent_id);
if (avatarp && avatarp->isAvatar())
LLViewerObject* vobjp = gObjectList.findObject(target_agent_id);
LLVOAvatar *avatarp = NULL;
if (vobjp)
{
avatarp = vobjp->asAvatar();
}
if (avatarp && !avatarp->isControlAvatar())
{
const LLSD & agent_info_map = agent_iter->second;
if (agent_info_map.isMap())
@ -123,7 +128,7 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro(std::string url, U64
if (agent_info_map.has(KEY_WEIGHT))
{
((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger());
avatarp->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger());
}
}
else
@ -201,6 +206,7 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U
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
{
avatar->calculateUpdateRenderComplexity(); // Make sure the numbers are up-to-date

View File

@ -0,0 +1,642 @@
/**
* @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, const F64 &time)
{
if (mMarkedForDeath)
{
markDead();
mMarkedForDeath = false;
}
else
{
LLVOAvatar::idleUpdate(agent,time);
}
}
BOOL LLControlAvatar::updateCharacter(LLAgent &agent)
{
return LLVOAvatar::updateCharacter(agent);
}
//virtual
void LLControlAvatar::updateDebugText()
{
if (gSavedSettings.getBOOL("DebugAnimatedObjects"))
{
S32 total_linkset_count = 0;
if (mRootVolp)
{
total_linkset_count = 1 + mRootVolp->getChildren().size();
}
std::vector<LLVOVolume*> volumes;
getAnimatedVolumes(volumes);
S32 animated_volume_count = volumes.size();
std::string active_string;
std::string type_string;
std::string lod_string;
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<LLVOVolume*>::iterator it = volumes.begin();
it != volumes.end(); ++it)
{
LLVOVolume *volp = *it;
S32 verts = 0;
total_tris += volp->getTriangleCount(&verts);
total_verts += verts;
est_tris += volp->getEstTrianglesMax();
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<LLVOVolume*>& volumes)
{
if (!mRootVolp)
{
return;
}
volumes.push_back(mRootVolp);
LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren();
for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); ++iter)
{
LLViewerObject* childp = *iter;
LLVOVolume *child_volp = dynamic_cast<LLVOVolume*>(childp);
if (child_volp && child_volp->isAnimatedObject())
{
volumes.push_back(child_volp);
}
}
}
// This is called after an associated object receives an animation
// message. Combine the signaled animations for all associated objects
// and process any resulting state changes.
void LLControlAvatar::updateAnimations()
{
if (!mRootVolp)
{
LL_WARNS_ONCE("AnimatedObjectsNotify") << "No root vol" << LL_ENDL;
return;
}
std::vector<LLVOVolume*> volumes;
getAnimatedVolumes(volumes);
// Rebuild mSignaledAnimations from the associated volumes.
std::map<LLUUID, S32> anims;
for (std::vector<LLVOVolume*>::iterator vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it)
{
LLVOVolume *volp = *vol_it;
//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<LLUUID,S32>::iterator anim_it = signaled_animations.begin();
anim_it != signaled_animations.end();
++anim_it)
{
std::map<LLUUID,S32>::iterator found_anim_it = anims.find(anim_it->first);
if (found_anim_it != anims.end())
{
// Animation already present, use the larger sequence id
anims[anim_it->first] = llmax(found_anim_it->second, anim_it->second);
}
else
{
// Animation not already present, use this sequence id.
anims[anim_it->first] = anim_it->second;
}
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,
BOOL pick_rigged,
S32* face_hit,
LLVector4a* intersection,
LLVector2* tex_coord,
LLVector4a* normal,
LLVector4a* tangent)
{
LLViewerObject* hit = NULL;
if (lineSegmentBoundingBox(start, end))
{
LLVector4a local_end = end;
LLVector4a local_intersection;
if (mRootVolp &&
mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent))
{
local_end = local_intersection;
if (intersection)
{
*intersection = local_intersection;
}
hit = mRootVolp;
}
}
return hit;
}
// 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<LLCharacter*>::iterator it = LLCharacter::sInstances.begin();
for ( ; it != LLCharacter::sInstances.end(); ++it)
{
LLControlAvatar* cav = dynamic_cast<LLControlAvatar*>(*it);
if (!cav) continue;
cav->mRegionChanged = true;
}
}

View File

@ -0,0 +1,113 @@
/**
* @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, const F64 &time);
virtual BOOL updateCharacter(LLAgent &agent);
void getAnimatedVolumes(std::vector<LLVOVolume*>& volumes);
void updateAnimations();
virtual LLViewerObject* lineSegmentIntersectRiggedAttachments(
const LLVector4a& start, const LLVector4a& end,
S32 face = -1, // which face to check, -1 = ALL_SIDES
BOOL pick_transparent = FALSE,
BOOL pick_rigged = FALSE,
S32* face_hit = NULL, // which face was hit
LLVector4a* intersection = NULL, // return the intersection point
LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
LLVector4a* normal = NULL, // return the surface normal at the intersection point
LLVector4a* tangent = NULL); // return the surface tangent at the intersection point
virtual void updateDebugText();
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<LLUUID, S32> signaled_animation_map_t;
typedef std::map<LLUUID, signaled_animation_map_t> object_signaled_animation_map_t;
// Stores information about previously requested animations, by object id.
class LLObjectSignaledAnimationMap: public LLSingleton<LLObjectSignaledAnimationMap>
{
LLSINGLETON_EMPTY_CTOR(LLObjectSignaledAnimationMap);
public:
object_signaled_animation_map_t mMap;
object_signaled_animation_map_t& getMap() { return mMap; }
};
#endif //LL_CONTROLAVATAR_H

View File

@ -32,6 +32,7 @@
#include "material_codes.h"
// viewer includes
#include "llagent.h"
#include "llcriticaldamp.h"
#include "llface.h"
#include "lllightconstants.h"
@ -50,6 +51,7 @@
#include "llviewerobjectlist.h"
#include "llviewerwindow.h"
#include "llvocache.h"
#include "llcontrolavatar.h"
#include "lldrawpoolavatar.h"
const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
@ -573,7 +575,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);
@ -726,6 +729,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)
{
@ -897,6 +904,30 @@ 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
{
@ -1113,7 +1144,8 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp)
llassert(!groupp || (LLSpatialGroup*)groupp->hasElement(this));
if (cur_groupp != groupp && getVOVolume())
{ //NULL out vertex buffer references for volumes on spatial group change to maintain
{
//NULL out vertex buffer references for volumes on spatial group change to maintain
//requirement that every face vertex buffer is either NULL or points to a vertex buffer
//contained by its drawable's spatial group
for (S32 i = 0; i < getNumFaces(); ++i)

View File

@ -141,7 +141,7 @@ LLViewerTexture *LLDrawPool::getDebugTexture()
return NULL;
}
//virtual
//virtuals
void LLDrawPool::beginRenderPass( S32 pass )
{
}

View File

@ -109,6 +109,32 @@ LLDrawPoolAvatar::LLDrawPoolAvatar() :
{
}
LLDrawPoolAvatar::~LLDrawPoolAvatar()
{
if (!isDead())
{
LL_WARNS() << "Destroying avatar drawpool that still contains faces" << LL_ENDL;
}
}
// virtual
BOOL LLDrawPoolAvatar::isDead()
{
if (!LLFacePool::isDead())
{
return FALSE;
}
for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
{
if (mRiggedFace[i].size() > 0)
{
return FALSE;
}
}
return TRUE;
}
//-----------------------------------------------------------------------------
// instancePool()
//-----------------------------------------------------------------------------
@ -467,7 +493,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
}
LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull())
if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull())
{
return;
}
@ -1683,7 +1709,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
{
if (avatar->isSelf() && !gAgent.needsRenderAvatar())
if (!avatar->shouldRenderRigged())
{
return;
}
@ -1714,13 +1740,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;
@ -1934,13 +1954,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;
@ -2061,11 +2075,16 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
{
llassert (facep->isState(LLFace::RIGGED));
llassert(getType() == LLDrawPool::POOL_AVATAR);
if (facep->getPool() && facep->getPool() != this)
{
LL_ERRS() << "adding rigged face that's already in another pool" << LL_ENDL;
}
if (type >= NUM_RIGGED_PASSES)
{
LL_ERRS() << "Invalid rigged face type." << LL_ENDL;
}
if (facep->getRiggedIndex(type) != -1)
{
LL_ERRS() << "Tried to add a rigged face that's referenced elsewhere." << LL_ENDL;
@ -2078,6 +2097,12 @@ void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)
{
llassert (facep->isState(LLFace::RIGGED));
llassert(getType() == LLDrawPool::POOL_AVATAR);
if (facep->getPool() != this)
{
LL_ERRS() << "Tried to remove a rigged face from the wrong pool" << LL_ENDL;
}
facep->setPool(NULL);
for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)

View File

@ -60,6 +60,8 @@ public:
virtual S32 getVertexShaderLevel() const;
LLDrawPoolAvatar();
~LLDrawPoolAvatar();
/*virtual*/ BOOL isDead();
static LLMatrix4& getModelView();

View File

@ -331,11 +331,7 @@ void LLFace::dirtyTexture()
{
vobj->mLODChanged = TRUE;
LLVOAvatar* avatar = vobj->getAvatar();
if (avatar)
{ //avatar render cost may have changed
avatar->updateVisualComplexity();
}
vobj->updateVisualComplexity();
}
gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE);
}
@ -815,17 +811,11 @@ bool less_than_max_mag(const LLVector4a& vec)
}
BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
const LLMatrix4& mat_vert_in, BOOL global_volume)
const LLMatrix4& mat_vert_in, BOOL global_volume)
{
//get bounding box
if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED))
{
//VECTORIZE THIS
LLMatrix4a mat_vert;
mat_vert.loadu(mat_vert_in);
LLVector4a min,max;
if (f >= volume.getNumVolumeFaces())
{
LL_WARNS() << "Generating bounding box for invalid face index!" << LL_ENDL;
@ -833,77 +823,52 @@ 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));
LL_DEBUGS("RiggedBox") << "updating extents for face " << f
<< " starting extents " << mExtents[0] << ", " << mExtents[1]
<< " starting vf extents " << face.mExtents[0] << ", " << face.mExtents[1]
<< " num verts " << face.mNumVertices << LL_ENDL;
//min, max are in volume space, convert to drawable render space
// MAINT-8264 - stray vertices, especially in low LODs, cause bounding box errors.
if (face.mNumVertices < 3)
{
LL_DEBUGS("RiggedBox") << "skipping face " << f << ", bad num vertices "
<< face.mNumVertices << " " << face.mNumIndices << " " << face.mWeights << LL_ENDL;
return FALSE;
}
//VECTORIZE THIS
LLMatrix4a mat_vert;
mat_vert.loadu(mat_vert_in);
LLVector4a new_extents[2];
//get 8 corners of bounding box
LLVector4Logical mask[6];
llassert(less_than_max_mag(face.mExtents[0]));
llassert(less_than_max_mag(face.mExtents[1]));
for (U32 i = 0; i < 6; ++i)
{
mask[i].clear();
}
matMulBoundBox(mat_vert, face.mExtents, mExtents);
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] = min;
v[7] = max;
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]);
}
LL_DEBUGS("RiggedBox") << "updated extents for face " << f
<< " bbox gave extents " << mExtents[0] << ", " << mExtents[1] << LL_ENDL;
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;
}
LL_DEBUGS("RiggedBox") << "updated extents for face " << f
<< " to " << mExtents[0] << ", " << mExtents[1] << 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();

View File

@ -1042,14 +1042,8 @@ LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicT
mCameraPitch = 0.f;
mCameraZoom = 1.f;
mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion());
mDummyAvatar->createDrawable(&gPipeline);
mDummyAvatar->mIsDummy = TRUE;
mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR);
mDummyAvatar->mSpecialRenderMode = 1;
mDummyAvatar->setPositionAgent(LLVector3::zero);
mDummyAvatar->slamPosition();
mDummyAvatar->updateJointLODs();
mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
mDummyAvatar->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET);
mDummyAvatar->hideSkirt();

View File

@ -566,15 +566,8 @@ LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLViewerDyna
mCameraPitch = 0.f;
mCameraZoom = 1.f;
mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion());
mDummyAvatar->createDrawable(&gPipeline);
mDummyAvatar->mIsDummy = TRUE;
mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR);
mDummyAvatar->mSpecialRenderMode = 2;
mDummyAvatar->setPositionAgent(LLVector3::zero);
mDummyAvatar->slamPosition();
mDummyAvatar->updateJointLODs();
mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
// gPipeline.markVisible(mDummyAvatar->mDrawable, *LLViewerCamera::getInstance());
mTextureName = 0;
}

View File

@ -685,6 +685,11 @@ void LLFloaterModelPreview::draw()
childSetTextArg("status", "[STATUS]", getString("status_parse_error"));
toggleCalculateButton(false);
}
else
if (mModelPreview->getLoadState() == LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION)
{
childSetTextArg("status", "[STATUS]", getString("status_bind_shape_orientation"));
}
else
{
childSetTextArg("status", "[STATUS]", getString("status_idle"));
@ -1368,7 +1373,11 @@ U32 LLModelPreview::calcResourceCost()
F32 radius = scale.length()*0.5f*debug_scale;
streaming_cost += LLMeshRepository::getStreamingCost(ret, radius);
LLMeshCostData costs;
if (gMeshRepo.getCostData(ret, costs))
{
streaming_cost += costs.getRadiusBasedStreamingCost(radius);
}
}
}
@ -1618,6 +1627,19 @@ void LLModelPreview::rebuildUploadData()
mFMP->childDisable( "calculate_btn" );
}
}
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP;
bool upload_skinweights = fmp && fmp->childGetValue("upload_skin").asBoolean();
if (upload_skinweights && high_lod_model->mSkinInfo.mJointNames.size() > 0)
{
LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(high_lod_model->mSkinInfo.mBindShapeMatrix);
LLQuaternion identity;
if (!bind_rot.isEqualEps(identity,0.01))
{
LL_WARNS() << "non-identity bind shape rot. mat is " << high_lod_model->mSkinInfo.mBindShapeMatrix
<< " bind_rot " << bind_rot << LL_ENDL;
setLoadState( LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION );
}
}
}
instance.mTransform = mat;
mUploadData.push_back(instance);
@ -1763,9 +1785,17 @@ void LLModelPreview::getJointAliases( JointMap& joint_map)
//Joint names and aliases come from avatar_skeleton.xml
joint_map = av->getJointAliases();
for (S32 i = 0; i < av->mNumCollisionVolumes; i++)
std::vector<std::string> cv_names, attach_names;
av->getSortedJointNames(1, cv_names);
av->getSortedJointNames(2, attach_names);
for (std::vector<std::string>::iterator it = cv_names.begin(); it != cv_names.end(); ++it)
{
joint_map[av->mCollisionVolumes[i].getName()] = av->mCollisionVolumes[i].getName();
joint_map[*it] = *it;
}
for (std::vector<std::string>::iterator it = attach_names.begin(); it != attach_names.end(); ++it)
{
joint_map[*it] = *it;
}
}
@ -3451,16 +3481,11 @@ void LLModelPreview::update()
//-----------------------------------------------------------------------------
void LLModelPreview::createPreviewAvatar( void )
{
mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion() );
mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR );
if ( mPreviewAvatar )
{
mPreviewAvatar->createDrawable( &gPipeline );
mPreviewAvatar->mIsDummy = TRUE;
mPreviewAvatar->mSpecialRenderMode = 1;
mPreviewAvatar->setPositionAgent( LLVector3::zero );
mPreviewAvatar->slamPosition();
mPreviewAvatar->updateJointLODs();
mPreviewAvatar->updateGeometry( mPreviewAvatar->mDrawable );
mPreviewAvatar->startMotion( ANIM_AGENT_STAND );
mPreviewAvatar->hideSkirt();
}

View File

@ -169,7 +169,10 @@ protected:
void draw();
void initDecompControls();
// FIXME - this function and mStatusMessage have no visible effect, and the
// actual status messages are managed by directly manipulation of
// the UI element.
void setStatusMessage(const std::string& msg);
LLModelPreview* mModelPreview;

View File

@ -4214,22 +4214,80 @@ void LLMeshRepository::uploadError(LLSD& args)
mUploadErrorQ.push(args);
}
F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, 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)
{
return getStreamingCost(iter->second, radius, bytes, bytes_visible, lod, unscaled_value);
result = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value);
}
}
return 0.f;
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::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value)
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")
@ -4323,7 +4381,7 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32
F32 weighted_avg = triangles_high*high_area +
triangles_mid*mid_area +
triangles_low*low_area +
triangles_lowest*lowest_area;
triangles_lowest*lowest_area;
if (unscaled_value)
{
@ -4333,6 +4391,204 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32
return weighted_avg/gSavedSettings.getU32("MeshTriangleBudget")*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)
{
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")

View File

@ -490,6 +490,53 @@ private:
LLCore::HttpRequest::priority_t mHttpPriority;
};
// 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<S32> mSizeByLOD;
// Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest.
std::vector<F32> mEstTrisByLOD;
};
class LLMeshRepository
{
public:
@ -511,8 +558,13 @@ public:
static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events
F32 getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL);
static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL);
// 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);
bool getCostData(LLSD& header, LLMeshCostData& data);
LLMeshRepository();
@ -623,5 +675,8 @@ public:
extern LLMeshRepository gMeshRepo;
const F32 ANIMATED_OBJECT_BASE_COST = 15.0f;
const F32 ANIMATED_OBJECT_COST_PER_KTRI = 1.5f;
#endif

View File

@ -78,6 +78,8 @@
#include "llviewercontrol.h"
#include "llmeshrepository.h"
#include "llvoavatarself.h"
#include <boost/bind.hpp>
// "Features" Tab
@ -86,6 +88,7 @@ BOOL LLPanelVolume::postBuild()
{
// Flexible Objects Parameters
{
childSetCommitCallback("Animated Mesh Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitAnimatedMeshCheckbox, this, _1, _2), NULL);
childSetCommitCallback("Flexible1D Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitIsFlexible, this, _1, _2), NULL);
childSetCommitCallback("FlexNumSections",onCommitFlexible,this);
getChild<LLUICtrl>("FlexNumSections")->setValidateBeforeCommit(precommitValidate);
@ -237,6 +240,11 @@ void LLPanelVolume::getState( )
{
volobjp = (LLVOVolume *)objectp;
}
LLVOVolume *root_volobjp = NULL;
if (root_objectp && (root_objectp->getPCode() == LL_PCODE_VOLUME))
{
root_volobjp = (LLVOVolume *)root_objectp;
}
if( !objectp )
{
@ -260,6 +268,8 @@ void LLPanelVolume::getState( )
BOOL editable = root_objectp->permModify() && !root_objectp->isPermanentEnforced();
BOOL single_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )
&& LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1;
BOOL single_root_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ) &&
LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1;
// Select Single Message
if (single_volume)
@ -345,7 +355,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<LLUICtrl>("Animated Mesh Checkbox Ctrl")->setValue(is_animated_mesh);
BOOL enabled_animated_object_box = FALSE;
if (root_volobjp && root_volobjp == volobjp)
{
enabled_animated_object_box = single_root_volume && root_volobjp && root_volobjp->canBeAnimatedObject() && editable;
#if 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<LLUICtrl>("Flexible1D Checkbox Ctrl")->setValue(is_flexible);
@ -582,6 +620,7 @@ void LLPanelVolume::clearCtrls()
getChildView("Light Radius")->setEnabled(false);
getChildView("Light Falloff")->setEnabled(false);
getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false);
getChildView("Flexible1D Checkbox Ctrl")->setEnabled(false);
getChildView("FlexNumSections")->setEnabled(false);
getChildView("FlexGravity")->setEnabled(false);
@ -891,6 +930,31 @@ void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata )
self->refresh();
}
void LLPanelVolume::onCommitAnimatedMeshCheckbox(LLUICtrl *, void*)
{
LLViewerObject* objectp = mObject;
if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME))
{
return;
}
LLVOVolume *volobjp = (LLVOVolume *)objectp;
BOOL animated_mesh = getChild<LLUICtrl>("Animated Mesh Checkbox Ctrl")->getValue();
U32 flags = volobjp->getExtendedMeshFlags();
U32 new_flags = flags;
if (animated_mesh)
{
new_flags |= LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG;
}
else
{
new_flags &= ~LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG;
}
if (new_flags != flags)
{
volobjp->setExtendedMeshFlags(new_flags);
}
}
void LLPanelVolume::onCommitIsFlexible(LLUICtrl *, void*)
{
if (mObject->flagObjectPermanent())

View File

@ -63,6 +63,7 @@ public:
static void onCommitLight( LLUICtrl* ctrl, void* userdata);
void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata);
static void onCommitFlexible( LLUICtrl* ctrl, void* userdata);
void onCommitAnimatedMeshCheckbox(LLUICtrl* ctrl, void* userdata);
static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata);
static void onCommitMaterial( LLUICtrl* ctrl, void* userdata);

View File

@ -87,7 +87,7 @@ namespace {
U32 render_feature = feature_from_string( iter->asString() );
if ( render_feature != 0 )
{
LLPipeline::toggleRenderDebugControl( render_feature );
LLPipeline::toggleRenderDebugFeatureControl( render_feature );
}
}
}
@ -123,7 +123,7 @@ namespace {
iter != request["displays"].endArray();
++iter)
{
U32 info_display = info_display_from_string( iter->asString() );
U64 info_display = info_display_from_string( iter->asString() );
if ( info_display != 0 )
{
LLPipeline::toggleRenderDebug( info_display );
@ -134,7 +134,7 @@ namespace {
void has_info_display_wrapper(LLSD const& request)
{
LLEventAPI::Response response(LLSD(), request);
U32 info_display = info_display_from_string( request["display"].asString() );
U64 info_display = info_display_from_string( request["display"].asString() );
if ( info_display != 0 )
{
response["value"] = gPipeline.hasRenderDebugMask(info_display);

View File

@ -33,6 +33,7 @@
#include "llviewerregion.h"
#include "llagent.h"
#include "llvolumemgr.h"
#include "llmeshrepository.h"
LLSceneView* gSceneView = NULL;
@ -129,17 +130,23 @@ void LLSceneView::draw()
visible_triangles[idx].push_back(visible);
triangles[idx].push_back(high_triangles);
S32 bytes = 0;
S32 visible_bytes = 0;
F32 streaming = object->getStreamingCost(&bytes, &visible_bytes);
total_streaming[idx] += streaming;
streaming_cost[idx].push_back(streaming);
F32 streaming = object->getStreamingCost();
total_streaming[idx] += streaming;
streaming_cost[idx].push_back(streaming);
F32 physics = object->getPhysicsCost();
total_physics[idx] += physics;
physics_cost[idx].push_back(physics);
S32 bytes = 0;
S32 visible_bytes = 0;
LLMeshCostData costs;
if (object->getCostData(costs))
{
bytes = costs.getSizeTotal();
visible_bytes = costs.getSizeByLOD(object->getLOD());
}
total_bytes[idx] += bytes;
total_visible_bytes[idx] += visible_bytes;
}

View File

@ -46,6 +46,7 @@
#include "llundo.h"
#include "lluuid.h"
#include "llvolume.h"
#include "llcontrolavatar.h"
#include "message.h"
#include "object_flags.h"
#include "llquaternion.h"
@ -645,6 +646,10 @@ void LLSelectMgr::confirmUnlinkObjects(const LLSD& notification, const LLSD& res
// otherwise. this allows the handle_link method to more finely check
// the selection and give an error message when the uer has a
// reasonable expectation for the link to work, but it will fail.
//
// For animated objects, there's additional check that if the
// selection includes at least one animated object, the total mesh
// triangle count cannot exceed the designated limit.
bool LLSelectMgr::enableLinkObjects()
{
bool new_value = false;
@ -669,6 +674,10 @@ bool LLSelectMgr::enableLinkObjects()
new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
}
}
if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable())
{
new_value = false;
}
return new_value;
}
@ -6659,7 +6668,10 @@ S32 get_family_count(LLViewerObject *parent)
//-----------------------------------------------------------------------------
// updateSelectionCenter
//-----------------------------------------------------------------------------
//
// FIXME this is a grab bag of functionality only some of which has to do
// with the selection center
// -----------------------------------------------------------------------------
void LLSelectMgr::updateSelectionCenter()
{
const F32 MOVE_SELECTION_THRESHOLD = 1.f; // Movement threshold in meters for updating selection
@ -6677,23 +6689,12 @@ void LLSelectMgr::updateSelectionCenter()
mSelectionCenterGlobal.clearVec();
mShowSelection = FALSE;
mSelectionBBox = LLBBox();
mPauseRequest = NULL;
resetAgentHUDZoom();
}
else
{
mSelectedObjects->mSelectType = getSelectTypeForObject(object);
if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid() && object->getParent() != NULL)
{
mPauseRequest = gAgentAvatarp->requestPause();
}
else
{
mPauseRequest = NULL;
}
if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid())
{
// reset hud ZOOM
@ -6770,6 +6771,59 @@ void LLSelectMgr::updateSelectionCenter()
{
gEditMenuHandler = NULL;
}
pauseAssociatedAvatars();
}
//-----------------------------------------------------------------------------
// pauseAssociatedAvatars
//
// If the selection includes an attachment or an animated object, the
// associated avatars should pause their animations until they are no
// longer selected.
//-----------------------------------------------------------------------------
void LLSelectMgr::pauseAssociatedAvatars()
{
mPauseRequests.clear();
for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
iter != mSelectedObjects->end(); iter++)
{
LLSelectNode* node = *iter;
LLViewerObject* object = node->getObject();
if (!object)
continue;
mSelectedObjects->mSelectType = getSelectTypeForObject(object);
if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT &&
isAgentAvatarValid() && object->getParent() != NULL)
{
if (object->isAnimatedObject())
{
// Is an animated object attachment.
// Pause both the control avatar and the avatar it's attached to.
if (object->getControlAvatar())
{
mPauseRequests.push_back(object->getControlAvatar()->requestPause());
}
mPauseRequests.push_back(gAgentAvatarp->requestPause());
}
else
{
// Is a regular attachment. Pause the avatar it's attached to.
mPauseRequests.push_back(gAgentAvatarp->requestPause());
}
}
else
{
if (object && object->isAnimatedObject() && object->getControlAvatar())
{
// Is a non-attached animated object. Pause the control avatar.
mPauseRequests.push_back(object->getControlAvatar()->requestPause());
}
}
}
}
void LLSelectMgr::updatePointAt()
@ -7246,10 +7300,16 @@ F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* vis
if (object)
{
S32 bytes = 0;
S32 visible = 0;
cost += object->getStreamingCost(&bytes, &visible);
cost += object->getStreamingCost();
S32 bytes = 0;
S32 visible = 0;
LLMeshCostData costs;
if (object->getCostData(costs))
{
bytes = costs.getSizeTotal();
visible = costs.getSizeByLOD(object->getLOD());
}
if (total_bytes)
{
*total_bytes += bytes;
@ -7406,6 +7466,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;

View File

@ -340,6 +340,9 @@ public:
// returns TRUE is any node is currenly worn as an attachment
BOOL isAttachment();
bool checkAnimatedObjectEstTris();
bool checkAnimatedObjectLinkable();
// Apply functors to various subsets of the selected objects
// If firstonly is FALSE, returns the AND of all apply() calls.
// Else returns TRUE immediately if any apply() call succeeds (i.e. OR with early exit)
@ -748,6 +751,8 @@ public:
LLVector3d getSelectionCenterGlobal() const { return mSelectionCenterGlobal; }
void updateSelectionCenter();
void pauseAssociatedAvatars();
void resetAgentHUDZoom();
void setAgentHUDZoom(F32 target_zoom, F32 current_zoom);
void getAgentHUDZoom(F32 &target_zoom, F32 &current_zoom) const;
@ -849,7 +854,7 @@ private:
LLFrameTimer mEffectsTimer;
BOOL mForceSelection;
LLAnimPauseRequest mPauseRequest;
std::vector<LLAnimPauseRequest> mPauseRequests;
};
// *DEPRECATED: For callbacks or observers, use

View File

@ -31,26 +31,73 @@
#include "llvoavatar.h"
#include "llviewercontrol.h"
#include "llmeshrepository.h"
#include "llvolume.h"
#include "llrigginginfo.h"
void dump_avatar_and_skin_state(const std::string& reason, LLVOAvatar *avatar, const LLMeshSkinInfo *skin)
{
static S32 dump_count = 0;
const S32 max_dump = 10;
if (dump_count < max_dump)
{
LL_WARNS("Avatar") << avatar->getFullname() << " dumping, reason " << reason
<< " avatar build state: isBuilt() " << avatar->isBuilt()
<< " mInitFlags " << avatar->mInitFlags << LL_ENDL;
LL_WARNS("Avatar") << "Skin num joints " << skin->mJointNames.size() << " " << skin->mJointNums.size() << LL_ENDL;
LL_WARNS("Avatar") << "Skin scrubbed " << skin->mInvalidJointsScrubbed
<< " nums init " << skin->mJointNumsInitialized << LL_ENDL;
for (S32 j=0; j<skin->mJointNames.size(); j++)
{
LL_WARNS("Avatar") << "skin joint idx " << j << " name [" << skin->mJointNames[j]
<< "] num " << skin->mJointNums[j] << LL_ENDL;
const std::string& name = skin->mJointNames[j];
S32 joint_num = skin->mJointNums[j];
LLJoint *name_joint = avatar->getJoint(name);
LLJoint *num_joint = avatar->getJoint(joint_num);
if (!name_joint)
{
LL_WARNS("Avatar") << "failed to find joint by name" << LL_ENDL;
}
if (!num_joint)
{
LL_WARNS("Avatar") << "failed to find joint by num" << LL_ENDL;
}
if (num_joint != name_joint)
{
LL_WARNS("Avatar") << "joint pointers don't match" << LL_ENDL;
}
if (num_joint && num_joint->getJointNum() != joint_num)
{
LL_WARNS("Avatar") << "joint found by num has wrong num " << joint_num << "!=" << num_joint->getJointNum() << LL_ENDL;
}
if (name_joint && name_joint->getJointNum() != joint_num)
{
LL_WARNS("Avatar") << "joint found by name has wrong num " << joint_num << "!=" << name_joint->getJointNum() << LL_ENDL;
}
}
LL_WARNS("Avatar") << LL_ENDL;
dump_count++;
}
}
// static
void LLSkinningUtil::initClass()
{
}
// static
U32 LLSkinningUtil::getMaxJointCount()
{
U32 result = LL_MAX_JOINTS_PER_MESH_OBJECT;
return result;
}
// static
U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin)
{
return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size());
}
// static
void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin)
{
if (skin->mInvalidJointsScrubbed)
@ -64,35 +111,25 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin
// needed for handling of any legacy bad data.
if (!avatar->getJoint(skin->mJointNames[j]))
{
LL_DEBUGS("Avatar") << "Mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL;
LL_DEBUGS("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint " << skin->mJointNames[j] << LL_ENDL;
LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL;
skin->mJointNames[j] = "mPelvis";
skin->mJointNumsInitialized = false; // force update after names change.
}
}
skin->mInvalidJointsScrubbed = true;
}
// static
void LLSkinningUtil::initSkinningMatrixPalette(
LLMatrix4* mat,
S32 count,
const LLMeshSkinInfo* skin,
LLVOAvatar *avatar)
{
initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar);
for (U32 j = 0; j < count; ++j)
{
LLJoint *joint = NULL;
if (skin->mJointNums[j] == -1)
{
joint = avatar->getJoint(skin->mJointNames[j]);
if (joint)
{
skin->mJointNums[j] = joint->getJointNum();
}
}
else
{
joint = avatar->getJoint(skin->mJointNums[j]);
}
LLJoint *joint = avatar->getJoint(skin->mJointNums[j]);
if (joint)
{
#define MAT_USE_SSE
@ -114,12 +151,19 @@ void LLSkinningUtil::initSkinningMatrixPalette(
// rendering should be disabled unless all joints are
// valid. In other cases of skinned rendering, invalid
// joints should already have been removed during scrubInvalidJoints().
LL_WARNS_ONCE("Avatar") << "Rigged to invalid joint name " << skin->mJointNames[j] << LL_ENDL;
LL_WARNS_ONCE("Avatar") << avatar->getFullname()
<< " rigged to invalid joint name " << skin->mJointNames[j]
<< " num " << skin->mJointNums[j] << LL_ENDL;
LL_WARNS_ONCE("Avatar") << avatar->getFullname()
<< " avatar build state: isBuilt() " << avatar->isBuilt()
<< " mInitFlags " << avatar->mInitFlags << LL_ENDL;
#if 0
dump_avatar_and_skin_state("initSkinningMatrixPalette joint not found", avatar, skin);
#endif
}
}
}
// static
void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin)
{
#ifdef SHOW_ASSERT // same condition that controls llassert()
@ -159,7 +203,6 @@ void LLSkinningUtil::scrubSkinWeights(LLVector4a* weights, U32 num_vertices, con
checkSkinWeights(weights, num_vertices, skin);
}
// static
void LLSkinningUtil::getPerVertexSkinMatrix(
F32* weights,
LLMatrix4a* mat,
@ -216,3 +259,150 @@ void LLSkinningUtil::getPerVertexSkinMatrix(
llassert(valid_weights);
}
void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar)
{
if (!skin->mJointNumsInitialized)
{
for (U32 j = 0; j < skin->mJointNames.size(); ++j)
{
LLJoint *joint = NULL;
if (skin->mJointNums[j] == -1)
{
joint = avatar->getJoint(skin->mJointNames[j]);
if (joint)
{
skin->mJointNums[j] = joint->getJointNum();
if (skin->mJointNums[j] < 0)
{
LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " joint has unusual number " << skin->mJointNames[j] << ": " << skin->mJointNums[j] << LL_ENDL;
LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " avatar build state: isBuilt() " << avatar->isBuilt() << " mInitFlags " << avatar->mInitFlags << LL_ENDL;
}
}
else
{
LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " unable to find joint " << skin->mJointNames[j] << LL_ENDL;
LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " avatar build state: isBuilt() " << avatar->isBuilt() << " mInitFlags " << avatar->mInitFlags << LL_ENDL;
#if 0
dump_avatar_and_skin_state("initJointNums joint not found", avatar, skin);
#endif
}
}
}
skin->mJointNumsInitialized = true;
}
}
static LLTrace::BlockTimerStatHandle FTM_FACE_RIGGING_INFO("Face Rigging Info");
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<LLMeshSkinInfo*>(skin), avatar);
if (vol_face.mJointRiggingInfoTab.size()==0)
{
//std::set<S32> 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<vol_face.mNumVertices; i++)
{
LLVector4a& pos = vol_face.mPositions[i];
F32 *weights = vol_face.mWeights[i].getF32ptr();
LLVector4 wght;
S32 idx[4];
F32 scale = 0.0f;
// FIXME unpacking of weights should be pulled into a common function and optimized if possible.
for (U32 k = 0; k < 4; k++)
{
F32 w = weights[k];
idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS-1);
wght[k] = w - idx[k];
scale += wght[k];
}
if (scale > 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;
matMul(bind_shape, inv_bind, mat);
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)
{
LLMatrix3 bind_mat = mat4.getMat3();
for (auto i = 0; i < 3; i++)
{
F32 len = 0.0f;
for (auto j = 0; j < 3; j++)
{
len += bind_mat.mMatrix[i][j] * bind_mat.mMatrix[i][j];
}
if (len > 0.0f)
{
len = sqrt(len);
for (auto j = 0; j < 3; j++)
{
bind_mat.mMatrix[i][j] /= len;
}
}
}
bind_mat.invert();
LLQuaternion bind_rot = bind_mat.quaternion();
bind_rot.normalize();
return bind_rot;
}

View File

@ -30,18 +30,21 @@
class LLVOAvatar;
class LLMeshSkinInfo;
class LLMatrix4a;
class LLVolumeFace;
class LLSkinningUtil
namespace LLSkinningUtil
{
public:
static void initClass();
static U32 getMaxJointCount();
static U32 getMeshJointCount(const LLMeshSkinInfo *skin);
static void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin);
static void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);
static void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
static void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
static void getPerVertexSkinMatrix(F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints);
void initClass();
U32 getMaxJointCount();
U32 getMeshJointCount(const LLMeshSkinInfo *skin);
void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin);
void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);
void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
void getPerVertexSkinMatrix(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);
};
#endif

View File

@ -29,6 +29,7 @@
#include "llspatialpartition.h"
#include "llappviewer.h"
#include "llcallstack.h"
#include "lltexturecache.h"
#include "lltexturefetch.h"
#include "llimageworker.h"
@ -52,6 +53,9 @@
#include "llvolumemgr.h"
#include "lltextureatlas.h"
#include "llviewershadermgr.h"
#include "llcontrolavatar.h"
//#pragma optimize("", off)
static LLTrace::BlockTimerStatHandle FTM_FRUSTUM_CULL("Frustum Culling");
static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound Partition");
@ -777,6 +781,10 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
dist = eye.getLength3().getF32();
}
LL_DEBUGS("RiggedBox") << "calcDistance, group " << group << " camera " << origin << " obj bounds "
<< group->mObjectBounds[0] << ", " << group->mObjectBounds[1]
<< " dist " << dist << " radius " << group->mRadius << LL_ENDL;
if (dist < 16.f)
{
dist /= 16.f;
@ -808,7 +816,8 @@ F32 LLSpatialGroup::getUpdateUrgency() const
BOOL LLSpatialGroup::changeLOD()
{
if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))
{ ///a rebuild is going to happen, update distance and LoD
{
//a rebuild is going to happen, update distance and LoD
return TRUE;
}
@ -816,8 +825,28 @@ BOOL LLSpatialGroup::changeLOD()
{
F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius));
// MAINT-8264 - this check is not robust if it needs to work
// for bounding boxes much larger than the actual enclosed
// objects, and using distance to box center is also
// problematic. Consider the case that you have a large box
// where the enclosed object is in one corner. As you zoom in
// on the corner, the object gets much closer to the camera,
// but the distance to the box center changes very little, and
// an LOD change will not trigger, so object LOD gets "stuck"
// at a too-low value. In the case of the above JIRA, the box
// was large only due to another error, so this logic did not
// need to be changed.
if (fabsf(ratio) >= getSpatialPartition()->mSlopRatio)
{
LL_DEBUGS("RiggedBox") << "changeLOD true because of ratio compare "
<< fabsf(ratio) << " " << getSpatialPartition()->mSlopRatio << LL_ENDL;
LL_DEBUGS("RiggedBox") << "sg " << this << "\nmDistance " << mDistance
<< " mLastUpdateDistance " << mLastUpdateDistance
<< " mRadius " << mRadius
<< " fab ratio " << fabsf(ratio)
<< " slop " << getSpatialPartition()->mSlopRatio << LL_ENDL;
return TRUE;
}
@ -869,16 +898,6 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
}
}
//clean up avatar attachment stats
LLSpatialBridge* bridge = getSpatialPartition()->asBridge();
if (bridge)
{
if (bridge->mAvatar.notNull())
{
bridge->mAvatar->subtractAttachmentArea(mSurfaceArea );
}
}
clearDrawMap();
mVertexBuffer = NULL;
mBufferMap.clear();
@ -2119,17 +2138,17 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
{
if (drawable->isSpatialBridge())
{
gGL.diffuseColor4f(1,0.5f,0,1);
gGL.diffuseColor4f(1,0.5f,0,1); // orange
}
else if (drawable->getVOVolume())
{
if (drawable->isRoot())
{
if (drawable->isRoot())
{
gGL.diffuseColor4f(1,1,0,1);
gGL.diffuseColor4f(1,1,0,1); // yellow
}
else
{
gGL.diffuseColor4f(0,1,0,1);
gGL.diffuseColor4f(0,1,0,1); // green
}
}
else if (drawable->getVObj())
@ -2137,24 +2156,41 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
switch (drawable->getVObj()->getPCode())
{
case LLViewerObject::LL_VO_SURFACE_PATCH:
gGL.diffuseColor4f(0,1,1,1);
gGL.diffuseColor4f(0,1,1,1); // cyan
break;
case LLViewerObject::LL_VO_CLOUDS:
// no longer used
break;
case LLViewerObject::LL_VO_PART_GROUP:
case LLViewerObject::LL_VO_HUD_PART_GROUP:
gGL.diffuseColor4f(0,0,1,1);
gGL.diffuseColor4f(0,0,1,1); // blue
break;
case LLViewerObject::LL_VO_VOID_WATER:
case LLViewerObject::LL_VO_WATER:
gGL.diffuseColor4f(0,0.5f,1,1);
gGL.diffuseColor4f(0,0.5f,1,1); // medium blue
break;
case LL_PCODE_LEGACY_TREE:
gGL.diffuseColor4f(0,0.5f,0,1);
gGL.diffuseColor4f(0,0.5f,0,1); // dark green
break;
default:
gGL.diffuseColor4f(1,0,1,1);
LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(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;
}
}

View File

@ -468,8 +468,6 @@ public:
virtual LLCamera transformCamera(LLCamera& camera);
LLDrawable* mDrawable;
LLPointer<LLVOAvatar> mAvatar;
};
class LLCullResult

View File

@ -2397,6 +2397,7 @@ void register_viewer_callbacks(LLMessageSystem* msg)
msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value);
msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value);
msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation);
msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation);
msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance);
msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint);
msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response);

View File

@ -785,7 +785,7 @@ void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAccep
mDrop = drop;
if (mDrop)
{
// don't allow drag and drop onto transparent objects
// don't allow drag and drop onto rigged or transparent objects
pick(gViewerWindow->pickImmediate(x, y, FALSE, FALSE));
}
else

View File

@ -111,9 +111,11 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
mMouseOutsideSlop = FALSE;
mMouseDownX = x;
mMouseDownY = y;
LLTimer pick_timer;
BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
//left mouse down always picks transparent (but see handleMouseUp)
mPick = gViewerWindow->pickImmediate(x, y, TRUE, FALSE);
mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged);
LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL;
mPick.mKeyMask = mask;
mMouseButtonDown = true;
@ -128,7 +130,10 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
// don't pick transparent so users can't "pay" transparent objects
mPick = gViewerWindow->pickImmediate(x, y, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ TRUE, /*BOOL pick_particle*/ TRUE);
mPick = gViewerWindow->pickImmediate(x, y,
/*BOOL pick_transparent*/ FALSE,
/*BOOL pick_rigged*/ TRUE,
/*BOOL pick_particle*/ TRUE);
mPick.mKeyMask = mask;
// claim not handled so UI focus stays same
@ -544,7 +549,8 @@ void LLToolPie::selectionPropertiesReceived()
BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
{
mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE);
BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged);
LLViewerObject *parent = NULL;
LLViewerObject *object = mHoverPick.getObject();
LLSelectMgr::getInstance()->setHoverObject(object, mHoverPick.mObjectFace);
@ -590,7 +596,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
else
{
// perform a separate pick that detects transparent objects since they respond to 1-click actions
LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE, FALSE);
LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged);
LLViewerObject* click_action_object = click_action_pick.getObject();
@ -676,6 +682,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
LLPickInfo savedPick = mPick;
mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
FALSE /* ignore transparent */,
FALSE /* ignore rigged */,
FALSE /* ignore particles */);
if (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick
@ -765,6 +772,7 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
LLPickInfo savedPick = mPick;
mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
FALSE /* ignore transparent */,
FALSE /* ignore rigged */,
FALSE /* ignore particles */);
if(mPick.mPickType == LLPickInfo::PICK_OBJECT)
@ -1757,8 +1765,7 @@ BOOL LLToolPie::handleRightClickPick()
gMenuHolder->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
bool is_other_attachment = (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner());
if (object->isAvatar()
|| is_other_attachment)
if (object->isAvatar() || is_other_attachment)
{
// Find the attachment's avatar
while( object && object->isAttachment())

View File

@ -64,7 +64,8 @@ LLToolSelect::LLToolSelect( LLToolComposite* composite )
BOOL LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask)
{
// do immediate pick query
mPick = gViewerWindow->pickImmediate(x, y, TRUE, FALSE);
BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged);
// Pass mousedown to agent
LLTool::handleMouseDown(x, y, mask);

View File

@ -71,7 +71,8 @@ void dialog_refresh_all(void);
BOOL LLToolSelectRect::handleMouseDown(S32 x, S32 y, MASK mask)
{
handlePick(gViewerWindow->pickImmediate(x, y, TRUE, FALSE));
BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
handlePick(gViewerWindow->pickImmediate(x, y, TRUE /* pick_transparent */, pick_rigged));
LLTool::handleMouseDown(x, y, mask);

View File

@ -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;
}

View File

@ -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

View File

@ -356,6 +356,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()
//-----------------------------------------------------------------------------

View File

@ -77,6 +77,7 @@ public:
S32 getGroup() const { return mGroup; }
S32 getPieSlice() const { return mPieSlice; }
S32 getNumObjects() const { return mAttachedObjects.size(); }
S32 getNumAnimatedObjects() const;
void clampObjectPosition();

View File

@ -964,7 +964,7 @@ class LLAdvancedSetDisplayTextureDensity : public view_listener_t
//////////////////
// INFO DISPLAY //
//////////////////
U32 info_display_from_string(std::string info_display)
U64 info_display_from_string(std::string info_display)
{
if ("verify" == info_display)
{
@ -1078,6 +1078,14 @@ U32 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY;
}
else if ("triangle count" == info_display)
{
return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT;
}
else if ("impostors" == info_display)
{
return LLPipeline::RENDER_DEBUG_IMPOSTORS;
}
else
{
LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL;
@ -1089,7 +1097,7 @@ class LLAdvancedToggleInfoDisplay : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
U32 info_display = info_display_from_string( userdata.asString() );
U64 info_display = info_display_from_string( userdata.asString() );
LL_INFOS("ViewerMenu") << "toggle " << userdata.asString() << LL_ENDL;
@ -1107,7 +1115,7 @@ class LLAdvancedCheckInfoDisplay : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
U32 info_display = info_display_from_string( userdata.asString() );
U64 info_display = info_display_from_string( userdata.asString() );
bool new_value = false;
if ( info_display != 0 )
@ -1617,7 +1625,24 @@ class LLAdvancedEnableAppearanceToXML : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
return gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
if (obj && obj->isAnimatedObject() && obj->getControlAvatar())
{
return gSavedSettings.getBOOL("DebugAnimatedObjects");
}
else if (obj && obj->isAttachment() && obj->getAvatar())
{
return gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
}
else if (obj && obj->isAvatar())
{
// This has to be a non-control avatar, because control avs are invisible and unclickable.
return gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
}
else
{
return false;
}
}
};
@ -1626,13 +1651,34 @@ class LLAdvancedAppearanceToXML : public view_listener_t
bool handleEvent(const LLSD& userdata)
{
std::string emptyname;
LLVOAvatar* avatar =
find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
if (!avatar)
{
LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
LLVOAvatar *avatar = NULL;
if (obj)
{
if (obj->isAvatar())
{
avatar = obj->asAvatar();
}
else
{
// If there is a selection, find the associated
// avatar. Normally there's only one obvious choice. But
// what should be returned if the object is in an attached
// animated object? getAvatar() will give the skeleton of
// the animated object. getAvatarAncestor() will give the
// actual human-driven avatar.
avatar = obj->getAvatar();
}
}
else
{
// If no selection, use the self avatar.
avatar = gAgentAvatarp;
}
avatar->dumpArchetypeXML(emptyname);
}
if (avatar)
{
avatar->dumpArchetypeXML(emptyname);
}
return true;
}
};
@ -6058,7 +6104,12 @@ class LLAvatarResetSkeleton: public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
LLVOAvatar* avatar = NULL;
LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
if (obj)
{
avatar = obj->getAvatar();
}
if(avatar)
{
avatar->resetSkeleton(false);
@ -6067,6 +6118,20 @@ class LLAvatarResetSkeleton: public view_listener_t
}
};
class LLAvatarEnableResetSkeleton: public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
if (obj && obj->getAvatar())
{
return true;
}
return false;
}
};
class LLAvatarResetSkeletonAndAnimations : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@ -6900,7 +6965,7 @@ class LLAttachmentEnableDrop : public view_listener_t
// Do not enable drop if all faces of object are not enabled
if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))
{
S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState());
S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState());
attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
if (attachment)
@ -9109,6 +9174,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile");
view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton");
view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton");
view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations");
enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible));

View File

@ -143,7 +143,7 @@ void handle_export_selected( void * );
// Convert strings to internal types
U32 render_type_from_string(std::string render_type);
U32 feature_from_string(std::string feature);
U32 info_display_from_string(std::string info_display);
U64 info_display_from_string(std::string info_display);
class LLViewerMenuHolderGL : public LLMenuHolderGL
{

View File

@ -54,6 +54,7 @@
#include "llagentcamera.h"
#include "llcallingcard.h"
#include "llbuycurrencyhtml.h"
#include "llcontrolavatar.h"
#include "llfirstuse.h"
#include "llfloaterbump.h"
#include "llfloaterbuyland.h"
@ -102,6 +103,7 @@
#include "llviewerwindow.h"
#include "llvlmanager.h"
#include "llvoavatarself.h"
#include "llvovolume.h"
#include "llworld.h"
#include "pipeline.h"
#include "llfloaterworldmap.h"
@ -4023,23 +4025,27 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
LLUUID animation_id;
LLUUID uuid;
S32 anim_sequence_id;
LLVOAvatar *avatarp;
LLVOAvatar *avatarp = NULL;
mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
//clear animation flags
avatarp = (LLVOAvatar *)gObjectList.findObject(uuid);
LLViewerObject *objp = gObjectList.findObject(uuid);
if (objp)
{
avatarp = objp->asAvatar();
}
if (!avatarp)
{
// no agent by this ID...error?
LL_WARNS("Messaging") << "Received animation state for unknown avatar" << uuid << LL_ENDL;
LL_WARNS("Messaging") << "Received animation state for unknown avatar " << uuid << LL_ENDL;
return;
}
S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList);
//clear animation flags
avatarp->mSignaledAnimations.clear();
if (avatarp->isSelf())
@ -4110,6 +4116,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<LLVOVolume*>(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;

View File

@ -100,6 +100,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);

View File

@ -60,6 +60,7 @@
#include "llbbox.h"
#include "llbox.h"
#include "llcylinder.h"
#include "llcontrolavatar.h"
#include "lldrawable.h"
#include "llface.h"
#include "llfloaterproperties.h"
@ -69,6 +70,7 @@
#include "llselectmgr.h"
#include "llrendersphere.h"
#include "lltooldraganddrop.h"
#include "lluiavatar.h"
#include "llviewercamera.h"
#include "llviewertexturelist.h"
#include "llviewerinventory.h"
@ -103,6 +105,8 @@
#include "llfloaterperms.h"
#include "llvocache.h"
#include "llcleanup.h"
#include "llcallstack.h"
#include "llmeshrepository.h"
//#define DEBUG_UPDATE_TYPE
@ -140,8 +144,11 @@ 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)
{
LL_DEBUGS("ObjectUpdate") << "creating " << id << LL_ENDL;
dumpStack("ObjectUpdateStack");
LLViewerObject *res = NULL;
LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT);
@ -168,6 +175,18 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
}
res = gAgentAvatarp;
}
else if (flags & CO_FLAG_CONTROL_AVATAR)
{
LLControlAvatar *control_avatar = new LLControlAvatar(id, pcode, regionp);
control_avatar->initInstance();
res = control_avatar;
}
else if (flags & CO_FLAG_UI_AVATAR)
{
LLUIAvatar *ui_avatar = new LLUIAvatar(id, pcode, regionp);
ui_avatar->initInstance();
res = ui_avatar;
}
else
{
LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp);
@ -237,6 +256,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mText(),
mHudText(""),
mHudTextColor(LLColor4::white),
mControlAvatar(NULL),
mLastInterpUpdateSecs(0.f),
mLastMessageUpdateSecs(0.f),
mLatestRecvPacketID(0),
@ -261,7 +281,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),
@ -367,17 +387,23 @@ void LLViewerObject::markDead()
//LL_INFOS() << "Marking self " << mLocalID << " as dead." << LL_ENDL;
// Root object of this hierarchy unlinks itself.
LLVOAvatar *av = getAvatarAncestor();
if (getParent())
{
((LLViewerObject *)getParent())->removeChild(this);
}
LLUUID mesh_id;
if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id))
{
// This case is needed for indirectly attached mesh objects.
av->resetJointsOnDetach(mesh_id);
}
{
LLVOAvatar *av = getAvatar();
if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id))
{
// This case is needed for indirectly attached mesh objects.
av->updateAttachmentOverrides();
}
}
if (getControlAvatar())
{
unlinkControlAvatar();
}
// Mark itself as dead
mDead = TRUE;
@ -678,6 +704,18 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list)
}
}
BOOL LLViewerObject::isAnySelected() const
{
bool any_selected = isSelected();
for (child_list_t::const_iterator iter = mChildList.begin();
iter != mChildList.end(); iter++)
{
const LLViewerObject* child = *iter;
any_selected = any_selected || child->isSelected();
}
return any_selected;
}
void LLViewerObject::setSelected(BOOL sel)
{
mUserSelected = sel;
@ -850,9 +888,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)
@ -1069,6 +1116,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
{
LL_DEBUGS_ONCE("SceneLoadTiming") << "Received viewer object data" << LL_ENDL;
LL_DEBUGS("ObjectUpdate") << " mesgsys " << mesgsys << " dp " << dp << " id " << getID() << " update_type " << (S32) update_type << LL_ENDL;
dumpStack("ObjectUpdateStack");
U32 retval = 0x0;
// If region is removed from the list it is also deleted.
@ -1123,10 +1173,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
@ -1384,7 +1434,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
U8 state;
mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
mState = state;
mAttachmentState = state;
// ...new objects that should come in selected need to be added to the selected list
mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
@ -1654,7 +1704,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
U8 state;
mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
mState = state;
mAttachmentState = state;
break;
}
@ -1677,7 +1727,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
U8 state;
dp->unpackU8(state, "State");
mState = state;
mAttachmentState = state;
switch(update_type)
{
@ -2910,6 +2960,131 @@ void LLViewerObject::fetchInventoryFromServer()
}
}
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::linkControlAvatar()
{
if (!getControlAvatar() && isRootEdit())
{
LLVOVolume *volp = dynamic_cast<LLVOVolume*>(this);
if (!volp)
{
LL_WARNS() << "called with null or non-volume object" << LL_ENDL;
return;
}
mControlAvatar = LLControlAvatar::createControlAvatar(volp);
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;
@ -3534,11 +3709,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;
@ -3549,6 +3779,58 @@ U32 LLViewerObject::getHighLODTriangleCount()
return 0;
}
U32 LLViewerObject::recursiveGetTriangleCount(S32* vcount) const
{
S32 total_tris = getTriangleCount(vcount);
LLViewerObject::const_child_list_t& child_list = getChildren();
for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); ++iter)
{
LLViewerObject* childp = *iter;
if (childp)
{
total_tris += childp->getTriangleCount(vcount);
}
}
return total_tris;
}
// This is using the stored surface area for each volume (which
// defaults to 1.0 for the case of everything except a sculpt) and
// then scaling it linearly based on the largest dimension in the
// prim's scale. Should revisit at some point.
F32 LLViewerObject::recursiveGetScaledSurfaceArea() const
{
F32 area = 0.f;
const LLDrawable* drawable = mDrawable;
if (drawable)
{
const LLVOVolume* volume = drawable->getVOVolume();
if (volume)
{
if (volume->getVolume())
{
const LLVector3& scale = volume->getScale();
area += volume->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
}
LLViewerObject::const_child_list_t children = volume->getChildren();
for (LLViewerObject::const_child_list_t::const_iterator child_iter = children.begin();
child_iter != children.end();
++child_iter)
{
LLViewerObject* child_obj = *child_iter;
LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
if (child && child->getVolume())
{
const LLVector3& scale = child->getScale();
area += child->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
}
}
}
}
return area;
}
void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
{
LLVector4a center;
@ -3652,7 +3934,6 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)
}
}
void LLViewerObject::setLineWidthForWindowSize(S32 window_width)
{
if (window_width < 700)
@ -3879,8 +4160,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();
}
@ -3904,7 +4197,7 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const
const LLQuaternion LLViewerObject::getRenderRotation() const
{
LLQuaternion ret;
if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED) && !isAnimatedObject())
{
return ret;
}
@ -5166,7 +5459,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();
@ -5505,6 +5804,11 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para
new_block = new LLLightImageParams();
break;
}
case LLNetworkData::PARAMS_EXTENDED_MESH:
{
new_block = new LLExtendedMeshParams();
break;
}
default:
{
LL_INFOS() << "Unknown param type." << LL_ENDL;
@ -5904,6 +6208,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())
@ -5963,6 +6278,11 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp)
child->setRegion(regionp);
}
if (mControlAvatar)
{
mControlAvatar->setRegion(regionp);
}
setChanged(MOVED | SILHOUETTE);
updateDrawable(FALSE);
}
@ -6411,6 +6731,10 @@ const std::string& LLViewerObject::getAttachmentItemName() const
//virtual
LLVOAvatar* LLViewerObject::getAvatar() const
{
if (getControlAvatar())
{
return getControlAvatar();
}
if (isAttachment())
{
LLViewerObject* vobj = (LLViewerObject*) getParent();

View File

@ -42,11 +42,13 @@
#include "v3math.h"
#include "llvertexbuffer.h"
#include "llbbox.h"
#include "llrigginginfo.h"
class LLAgent; // TODO: Get rid of this.
class LLAudioSource;
class LLAudioSourceVO;
class LLColor4;
class LLControlAvatar;
class LLDataPacker;
class LLDataPackerBinaryBuffer;
class LLDrawable;
@ -67,6 +69,8 @@ class LLViewerRegion;
class LLViewerTexture;
class LLWorld;
class LLMeshCostData;
typedef enum e_object_update_type
{
OUT_FULL,
@ -220,6 +224,8 @@ public:
LLViewerRegion* getRegion() const { return mRegionp; }
BOOL isSelected() const { return mUserSelected; }
// Check whole linkset
BOOL isAnySelected() const;
virtual void setSelected(BOOL sel);
const LLUUID &getID() const { return mID; }
@ -231,6 +237,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
@ -255,6 +262,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; }
@ -356,9 +365,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();
@ -374,7 +391,7 @@ public:
void sendShapeUpdate();
U8 getState() { return mState; }
U8 getAttachmentState() { return mAttachmentState; }
F32 getAppAngle() const { return mAppAngle; }
F32 getPixelArea() const { return mPixelArea; }
@ -411,7 +428,8 @@ public:
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);
@ -686,6 +704,27 @@ public:
static BOOL sUseSharedDrawables;
public:
// Returns mControlAvatar for the edit root prim of this linkset
LLControlAvatar *getControlAvatar();
LLControlAvatar *getControlAvatar() const;
// Create or connect to an existing control av as applicable
void linkControlAvatar();
// Remove any reference to control av for this prim
void unlinkControlAvatar();
// Link or unlink as needed
void updateControlAvatar();
virtual bool isAnimatedObject() const;
// Flags for createObject
static const S32 CO_FLAG_CONTROL_AVATAR = 1 << 0;
static const S32 CO_FLAG_UI_AVATAR = 1 << 1;
protected:
LLPointer<LLControlAvatar> mControlAvatar;
protected:
// delete an item in the inventory, but don't tell the
// server. This is used internally by remove, update, and
@ -696,8 +735,7 @@ protected:
// updateInventory.
void doUpdateInventory(LLPointer<LLViewerInventoryItem>& item, U8 key, bool is_new);
static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp);
static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0);
BOOL setData(const U8 *datap, const U32 data_size);
@ -785,7 +823,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
@ -841,6 +879,10 @@ public:
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;

View File

@ -68,6 +68,7 @@
#include "u64.h"
#include "llviewertexturelist.h"
#include "lldatapacker.h"
#include "llcallstack.h"
#ifdef LL_USESYSTEMLIBS
#include <zlib.h>
#else
@ -241,6 +242,10 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,
}
// ignore returned flags
LL_DEBUGS("ObjectUpdate") << "uuid " << objectp->mID << " calling processUpdateMessage "
<< objectp << " just_created " << just_created << " from_cache " << from_cache << " msg " << msg << LL_ENDL;
dumpStack("ObjectUpdateStack");
objectp->processUpdateMessage(msg, user_data, i, update_type, dpp);
if (objectp->isDead())
@ -352,7 +357,10 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry*
if (!objectp)
{
objectp = createObjectFromCache(pcode, regionp, fullid, entry->getLocalID());
LL_DEBUGS("ObjectUpdate") << "uuid " << fullid << " created objectp " << objectp << LL_ENDL;
dumpStack("ObjectUpdateStack");
if (!objectp)
{
LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL;
@ -471,6 +479,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
compressed_dp.reset();
uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data);
LL_DEBUGS("ObjectUpdate") << "got binary data from message to compressed_dpbuffer" << LL_ENDL;
mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i, 2048);
compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length);
@ -530,6 +539,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
// LL_WARNS() << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << LL_ENDL;
mNumUnknownUpdates++;
}
else
{
LL_DEBUGS("ObjectUpdate") << "Non-full, non-compressed update, obj " << local_id << ", global ID " << fullid << " from " << mesgsys->getSender() << LL_ENDL;
}
}
else // OUT_FULL only?
{
@ -538,10 +551,19 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
msg_size += sizeof(LLUUID);
msg_size += sizeof(U32);
// LL_INFOS() << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << LL_ENDL;
LL_DEBUGS("ObjectUpdate") << "Full Update, obj " << local_id << ", global ID " << fullid << " from " << mesgsys->getSender() << LL_ENDL;
}
objectp = findObject(fullid);
if (compressed)
{
LL_DEBUGS("ObjectUpdate") << "uuid " << fullid << " received compressed data from message (earlier in function)" << LL_ENDL;
}
LL_DEBUGS("ObjectUpdate") << "uuid " << fullid << " objectp " << objectp
<< " update_cache " << (S32) update_cache << " compressed " << compressed
<< " update_type " << update_type << LL_ENDL;
dumpStack("ObjectUpdateStack");
if(update_cache)
{
objectp = regionp->updateCacheEntry(local_id, objectp, update_type);
@ -616,6 +638,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
#endif
objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender());
LL_DEBUGS("ObjectUpdate") << "creating object " << fullid << " result " << objectp << LL_ENDL;
dumpStack("ObjectUpdateStack");
if (!objectp)
{
LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL;
@ -710,12 +736,17 @@ void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys,
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i);
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
msg_size += sizeof(U32) * 2;
LL_DEBUGS("ObjectUpdate") << "got probe for id " << id << " crc " << crc << LL_ENDL;
dumpStack("ObjectUpdateStack");
// Lookup data packer and add this id to cache miss lists if necessary.
U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE;
if(!regionp->probeCache(id, crc, flags, cache_miss_type))
{
// Cache Miss.
LL_DEBUGS("ObjectUpdate") << "cache miss for id " << id << " crc " << crc << " miss type " << (S32) cache_miss_type << LL_ENDL;
recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size);
continue; // no data packer, skip this object
@ -876,8 +907,8 @@ void LLViewerObjectList::update(LLAgent &agent)
{
if (idle_count >= idle_list.size())
{
idle_list.push_back( objectp );
}
idle_list.push_back( objectp );
}
else
{
idle_list[idle_count] = objectp;
@ -914,7 +945,7 @@ void LLViewerObjectList::update(LLAgent &agent)
{
objectp = *idle_iter;
llassert(objectp->isActive());
objectp->idleUpdate(agent, frame_time);
objectp->idleUpdate(agent, frame_time);
}
//update flexible objects
@ -1274,6 +1305,9 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
// Cleanup any references we have to this object
// Remove from object map so noone can look it up.
LL_DEBUGS("ObjectUpdate") << " dereferencing id " << objectp->mID << LL_ENDL;
dumpStack("ObjectUpdateStack");
mUUIDObjectMap.erase(objectp->mID);
//if (objectp->getRegion())
@ -1960,12 +1994,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;
@ -1985,6 +2019,9 @@ LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, L
{
llassert_always(uuid.notNull());
LL_DEBUGS("ObjectUpdate") << "creating " << uuid << " local_id " << local_id << LL_ENDL;
dumpStack("ObjectUpdateStack");
LLViewerObject *objectp = LLViewerObject::createObject(uuid, pcode, regionp);
if (!objectp)
{
@ -2019,6 +2056,9 @@ LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRe
fullid = uuid;
}
LL_DEBUGS("ObjectUpdate") << "createObject creating " << fullid << LL_ENDL;
dumpStack("ObjectUpdateStack");
LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp);
if (!objectp)
{

View File

@ -67,7 +67,7 @@ public:
inline LLViewerObject *getObject(const S32 index);
inline LLViewerObject *findObject(const LLUUID &id);
LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp); // Create a viewer-side object
LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0); // Create a viewer-side object
LLViewerObject *createObjectFromCache(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id);
LLViewerObject *createObject(const LLPCode pcode, LLViewerRegion *regionp,
const LLUUID &uuid, const U32 local_id, const LLHost &sender);

View File

@ -731,7 +731,7 @@ bool LLViewerOctreeGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4
update_min_max(newMin, newMax, minMax[0]);
update_min_max(newMin, newMax, minMax[1]);
}
mObjectBounds[0].setAdd(newMin, newMax);
mObjectBounds[0].mul(0.5f);
mObjectBounds[1].setSub(newMax, newMin);

View File

@ -78,6 +78,7 @@
#include "llcoros.h"
#include "lleventcoro.h"
#include "llcorehttputil.h"
#include "llcallstack.h"
#ifdef LL_WINDOWS
#pragma warning(disable:4355)
@ -241,6 +242,8 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL;
return; // this error condition is not recoverable.
}
LL_DEBUGS("AppInit", "Capabilities") << "requesting seed caps for handle " << regionHandle
<< " name " << regionp->getName() << LL_ENDL;
std::string url = regionp->getCapability("Seed");
if (url.empty())
@ -269,7 +272,8 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
buildCapabilityNames(capabilityNames);
LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url
<< " (attempt #" << mSeedCapAttempts + 1 << ")" << LL_ENDL;
<< " region name " << regionp->getName()
<< " (attempt #" << mSeedCapAttempts + 1 << ")" << LL_ENDL;
regionp = NULL;
result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames);
@ -323,6 +327,8 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
#endif
regionp->setCapabilitiesReceived(true);
LL_DEBUGS("AppInit", "Capabilities") << "received caps for handle " << regionHandle
<< " region name " << regionp->getName() << LL_ENDL;
if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
{
@ -1259,7 +1265,7 @@ void LLViewerRegion::updateVisibleEntries(F32 max_time)
LLPointer<LLViewerOctreeGroup> group = *group_iter;
if(group->getNumRefs() < 3 || //group to be deleted
!group->getOctreeNode() || group->isEmpty()) //group empty
{
{
continue;
}
@ -2143,6 +2149,26 @@ void LLViewerRegion::getInfo(LLSD& info)
info["Region"]["Handle"]["y"] = (LLSD::Integer)y;
}
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())
{
std::string coroname =
LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro",
boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, url, getHandle()));
LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << LL_ENDL;
}
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);
@ -2174,7 +2200,7 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
std::stringstream str;
LLSDSerialize::toPrettyXML(sim_features, str);
LL_INFOS() << str.str() << LL_ENDL;
LL_INFOS() << "region " << getName() << " " << str.str() << LL_ENDL;
mSimulatorFeatures = sim_features;
setSimulatorFeaturesReceived(true);
@ -2220,7 +2246,7 @@ void LLViewerRegion::decodeBoundingInfo(LLVOCacheEntry* entry)
{
LLViewerRegion* old_regionp = ((LLDrawable*)entry->getEntry()->getDrawable())->getRegion();
if(old_regionp != this && old_regionp)
{
{
LLViewerObject* obj = ((LLDrawable*)entry->getEntry()->getDrawable())->getVObj();
if(obj)
{
@ -2383,12 +2409,18 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerB
// we've seen this object before
if (entry->getCRC() == crc)
{
LL_DEBUGS("AnimatedObjects") << " got dupe for local_id " << local_id << LL_ENDL;
dumpStack("AnimatedObjectsStack");
// Record a hit
entry->recordDupe();
result = CACHE_UPDATE_DUPE;
}
else //CRC changed
{
LL_DEBUGS("AnimatedObjects") << " got update for local_id " << local_id << LL_ENDL;
dumpStack("AnimatedObjectsStack");
// Update the cache entry
entry->updateEntry(crc, dp);
@ -2399,6 +2431,9 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerB
}
else
{
LL_DEBUGS("AnimatedObjects") << " got first notification for local_id " << local_id << LL_ENDL;
dumpStack("AnimatedObjectsStack");
// we haven't seen this object before
// Create new entry and add to map
result = CACHE_UPDATE_ADDED;
@ -2503,7 +2538,7 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss
// Record a hit
mRegionCacheHitCount++;
entry->recordHit();
cache_miss_type = CACHE_MISS_TYPE_NONE;
cache_miss_type = CACHE_MISS_TYPE_NONE;
entry->setUpdateFlags(flags);
if(entry->isState(LLVOCacheEntry::ACTIVE))
@ -2526,12 +2561,14 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss
// LL_INFOS() << "CRC miss for " << local_id << LL_ENDL;
addCacheMiss(local_id, CACHE_MISS_TYPE_CRC);
cache_miss_type = CACHE_MISS_TYPE_CRC;
}
}
else
{
// LL_INFOS() << "Cache miss for " << local_id << LL_ENDL;
addCacheMiss(local_id, CACHE_MISS_TYPE_FULL);
cache_miss_type = CACHE_MISS_TYPE_FULL;
}
return false;
@ -2568,6 +2605,9 @@ void LLViewerRegion::requestCacheMisses()
msg->nextBlockFast(_PREHASH_ObjectData);
msg->addU8Fast(_PREHASH_CacheMissType, (*iter).mType);
msg->addU32Fast(_PREHASH_ID, (*iter).mID);
LL_DEBUGS("AnimatedObjects") << "Requesting cache missed object " << (*iter).mID << LL_ENDL;
blocks++;
if (blocks >= 255)
@ -2873,6 +2913,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");
@ -2967,12 +3008,8 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u
}
else if (name == "SimulatorFeatures")
{
// kick off a request for simulator features
std::string coroname =
LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro",
boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, url, getHandle()));
LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << LL_ENDL;
mImpl->mCapabilities["SimulatorFeatures"] = url;
requestSimulatorFeatures();
}
else
{

View File

@ -305,6 +305,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);

View File

@ -543,7 +543,14 @@ public:
object_count++;
S32 bytes = 0;
S32 visible = 0;
cost += object->getStreamingCost(&bytes, &visible);
cost += object->getStreamingCost();
LLMeshCostData costs;
if (object->getCostData(costs))
{
bytes = costs.getSizeTotal();
visible = costs.getSizeByLOD(object->getLOD());
}
S32 vt = 0;
count += object->getTriangleCount(&vt);
vcount += vt;
@ -1146,7 +1153,9 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
if (prim_media_dnd_enabled)
{
LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/, FALSE );
LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY,
TRUE /* pick_transparent */,
FALSE /* pick_rigged */);
LLUUID object_id = pick_info.getObjectID();
S32 object_face = pick_info.mObjectFace;

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,10 @@
#include "lldriverparam.h"
#include "llviewertexlayer.h"
#include "material_codes.h" // LL_MCODE_END
#include "llrigginginfo.h"
#include "llviewerstats.h"
#include "llvovolume.h"
#include "llavatarrendernotifier.h"
extern const LLUUID ANIM_AGENT_BODY_NOISE;
extern const LLUUID ANIM_AGENT_BREATHE_ROT;
@ -159,7 +162,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,
@ -169,7 +172,8 @@ public:
LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
LLVector4a* normal = NULL, // return the surface normal at the intersection point
LLVector4a* tangent = NULL); // return the surface tangent at the intersection point
LLViewerObject* lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
virtual LLViewerObject* lineSegmentIntersectRiggedAttachments(
const LLVector4a& start, const LLVector4a& end,
S32 face = -1, // which face to check, -1 = ALL_SIDES
BOOL pick_transparent = FALSE,
BOOL pick_rigged = FALSE,
@ -200,18 +204,28 @@ public:
virtual LLJoint* getJoint(const std::string &name);
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<LLUUID>* 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<std::string>& pos_names,
std::set<std::string>& scale_names) const;
void getAssociatedVolumes(std::vector<LLVOVolume*>& volumes);
// virtual
void updateRiggingInfo();
// This encodes mesh id and LOD, so we can see whether display is up-to-date.
std::map<LLUUID,S32> mLastRiggingInfoKey;
std::set<LLUUID> mActiveOverrideMeshes;
virtual void onActiveOverrideMeshesChanged();
/*virtual*/ const LLUUID& getID() const;
/*virtual*/ void addDebugText(const std::string& text);
/*virtual*/ F32 getTimeDilation();
@ -233,6 +247,9 @@ public:
public:
virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
virtual bool isControlAvatar() const { return mIsControlAvatar; } // True if this avatar is a control av (no associated user)
virtual bool isUIAvatar() const { return mIsUIAvatar; } // True if this avatar is a supplemental av used in some UI views (no associated user)
private: //aligned members
LL_ALIGN_16(LLVector4a mImpostorExtents[2]);
@ -240,8 +257,16 @@ private: //aligned members
// 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();
@ -259,14 +284,17 @@ public:
static void invalidateNameTags();
void addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font);
void idleUpdateRenderComplexity();
void accountRenderComplexityForObject(const LLViewerObject *attached_object,
const F32 max_attachment_complexity,
LLVOVolume::texture_cost_t& textures,
U32& cost,
hud_complexity_list_t& hud_complexity_list);
void calculateUpdateRenderComplexity();
static const U32 VISUAL_COMPLEXITY_UNKNOWN;
void updateVisualComplexity();
U32 getVisualComplexity() { return mVisualComplexity; }; // Numbers calculated here by rendering AV
F32 getAttachmentSurfaceArea() { return mAttachmentSurfaceArea; }; // estimated surface area of attachments
void addAttachmentArea(F32 delta_area);
void subtractAttachmentArea(F32 delta_area);
U32 getReportedVisualComplexity() { return mReportedVisualComplexity; }; // Numbers as reported by the SL server
void setReportedVisualComplexity(U32 value) { mReportedVisualComplexity = value; };
@ -422,6 +450,8 @@ public:
private:
F32 mAttachmentSurfaceArea; //estimated surface area of attachments
U32 mAttachmentVisibleTriangleCount;
F32 mAttachmentEstTriangleCount;
bool shouldAlphaMask();
BOOL mNeedsSkin; // avatar has been animated and verts have not been updated
@ -440,6 +470,14 @@ public:
VisualMuteSettings mVisuallyMuteSetting; // Always or never visually mute this AV
//--------------------------------------------------------------------
// animated object status
//--------------------------------------------------------------------
public:
bool mIsControlAvatar;
bool mIsUIAvatar;
bool mEnableDefaultMotions;
//--------------------------------------------------------------------
// Morph masks
//--------------------------------------------------------------------
@ -478,7 +516,7 @@ private:
// Impostors
//--------------------------------------------------------------------
public:
BOOL isImpostor();
virtual BOOL isImpostor();
BOOL shouldImpostor(const U32 rank_factor = 1) const;
BOOL needsImpostorUpdate() const;
const LLVector3& getImpostorOffset() const;
@ -490,14 +528,22 @@ 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;
// This becomes true in the constructor and false after the first
// idleUpdateMisc(). Not clear it serves any purpose.
BOOL mNeedsAnimUpdate;
bool mNeedsExtentUpdate;
LLVector3 mImpostorAngle;
F32 mImpostorDistance;
F32 mImpostorPixelArea;
LLVector3 mLastAnimExtents[2];
LLVector3 mLastAnimBasePos;
LLCachedControl<bool> mRenderUnloadedAvatar;
@ -716,7 +762,9 @@ private:
//--------------------------------------------------------------------
public:
BOOL isVisible() const;
virtual bool shouldRenderRigged() const;
void setVisibilityRank(U32 rank);
U32 getVisibilityRank() const { return mVisibilityRank; }
static S32 sNumVisibleAvatars; // Number of instances of this class
/** Appearance
** **
@ -739,9 +787,9 @@ public:
static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj);
/*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type ) const;
LLViewerObject * findAttachmentByID( const LLUUID & target_id ) const;
LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);
protected:
LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);
void lazyAttach();
void rebuildRiggedAttachments( void );
@ -761,10 +809,12 @@ public:
BOOL hasHUDAttachment() const;
LLBBox getHUDBBox() const;
void resetHUDAttachments();
BOOL canAttachMoreObjects() const;
BOOL canAttachMoreObjects(U32 n) const;
BOOL canAttachMoreObjects(U32 n=1) const;
S32 getMaxAnimatedObjectAttachments() const;
BOOL canAttachMoreAnimatedObjects(U32 n=1) const;
protected:
U32 getNumAttachments() const; // O(N), not O(1)
U32 getNumAnimatedObjectAttachments() const; // O(N), not O(1)
/** Wearables
** **
@ -897,7 +947,7 @@ private:
**/
public:
std::string getFullname() const; // Returns "FirstName LastName"
virtual std::string getFullname() const; // Returns "FirstName LastName"
std::string avString() const; // Frequently used string in log messages "Avatar '<full name'"
protected:
static void getAnimLabels(std::vector<std::string>* labels);

View File

@ -235,6 +235,8 @@ void LLVOAvatarSelf::initInstance()
//doPeriodically(output_self_av_texture_diagnostics, 30.0);
doPeriodically(update_avatar_rez_metrics, 5.0);
doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0);
mInitFlags |= 1<<2;
}
void LLVOAvatarSelf::setHoverIfRegionEnabled()
@ -2699,6 +2701,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
@ -2793,7 +2801,7 @@ BOOL LLVOAvatarSelf::needsRenderBeam()
// don't render selection beam on hud objects
is_touching_or_grabbing = FALSE;
}
return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
return is_touching_or_grabbing || (getAttachmentState() & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
}
// static

View File

@ -312,6 +312,9 @@ public:
//--------------------------------------------------------------------
// Visibility
//--------------------------------------------------------------------
/* virtual */ bool shouldRenderRigged() const;
public:
bool sendAppearanceMessage(LLMessageSystem *mesgsys) const;

View File

@ -92,7 +92,7 @@ LLVOGrass::~LLVOGrass()
void LLVOGrass::updateSpecies()
{
mSpecies = mState;
mSpecies = getAttachmentState();
if (!sSpeciesTable.count(mSpecies))
{

File diff suppressed because it is too large Load Diff

View File

@ -64,6 +64,8 @@ public:
}
void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume);
std::string mExtraDebugText;
};
// Base class for implementations of the volume - Primitive, Flexible Object, etc.
@ -136,8 +138,10 @@ public:
/*virtual*/ const LLMatrix4 getRenderMatrix() const;
typedef std::map<LLUUID, S32> texture_cost_t;
U32 getRenderCost(texture_cost_t &textures) const;
F32 getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const;
/*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL) { return getStreamingCost(bytes, visible_bytes, NULL); }
/*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();
@ -163,7 +167,7 @@ public:
/*virtual*/ F32 getRadius() const { return mVObjRadius; };
const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const;
void markForUpdate(BOOL priority) { LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; }
void markForUpdate(BOOL priority);
void markForUnload() { LLViewerObject::markForUnload(TRUE); mVolumeChanged = TRUE; }
void faceMappingChanged() { mFaceMappingChanged=TRUE; };
@ -264,12 +268,29 @@ 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
@ -303,7 +324,10 @@ public:
bool hasMedia() const;
LLVector3 getApproximateFaceNormal(U8 face_id);
// Flag any corresponding avatars as needing update.
void updateVisualComplexity();
void notifyMeshLoaded();
// Returns 'true' iff the media data for this object is in flight
@ -332,7 +356,7 @@ public:
void clearRiggedVolume();
protected:
S32 computeLODDetail(F32 distance, F32 radius, F32 lod_factor);
S32 computeLODDetail(F32 distance, F32 radius, F32 lod_factor);
BOOL calcLOD();
LLFace* addFace(S32 face_index);
void updateTEData();
@ -356,6 +380,9 @@ public:
LLViewerTextureAnim *mTextureAnimp;
U8 mTexAnimMode;
F32 mLODDistance;
F32 mLODAdjustedDistance;
F32 mLODRadius;
private:
friend class LLDrawable;
friend class LLFace;

View File

@ -3356,6 +3356,18 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f
{
if (drawablep && !drawablep->isDead() && assertInitialized())
{
if (debugLoggingEnabled("AnimatedObjectsLinkset"))
{
LLVOVolume *vol_obj = drawablep->getVOVolume();
if (vol_obj && vol_obj->isAnimatedObject() && vol_obj->isRiggedMesh())
{
std::string vobj_name = llformat("Vol%p", vol_obj);
F32 est_tris = vol_obj->getEstTrianglesMax();
LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " markRebuild, tris " << est_tris
<< " priority " << (S32) priority << " flag " << std::hex << flag << LL_ENDL;
}
}
if (!drawablep->isState(LLDrawable::BUILT))
{
priority = true;
@ -6844,7 +6856,7 @@ bool LLPipeline::toggleRenderTypeControlNegated(S32 type)
}
//static
void LLPipeline::toggleRenderDebug(U32 bit)
void LLPipeline::toggleRenderDebug(U64 bit)
{
if (gPipeline.hasRenderDebugMask(bit))
{
@ -6859,7 +6871,7 @@ void LLPipeline::toggleRenderDebug(U32 bit)
//static
bool LLPipeline::toggleRenderDebugControl(U32 bit)
bool LLPipeline::toggleRenderDebugControl(U64 bit)
{
return gPipeline.hasRenderDebugMask(bit);
}
@ -11650,6 +11662,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
avatar->mNeedsImpostorUpdate = FALSE;
avatar->cacheImpostorValues();
avatar->mLastImpostorUpdateFrameTime = gFrameTimeSeconds;
LLVertexBuffer::unbind();
LLGLState::checkStates();

View File

@ -330,10 +330,10 @@ public:
void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES);
bool hasRenderDebugFeatureMask(const U32 mask) const { return bool(mRenderDebugFeatureMask & mask); }
bool hasRenderDebugMask(const U32 mask) const { return bool(mRenderDebugMask & mask); }
bool hasRenderDebugMask(const U64 mask) const { return bool(mRenderDebugMask & mask); }
void setAllRenderDebugFeatures() { mRenderDebugFeatureMask = 0xffffffff; }
void clearAllRenderDebugFeatures() { mRenderDebugFeatureMask = 0x0; }
void setAllRenderDebugDisplays() { mRenderDebugMask = 0xffffffff; }
void setAllRenderDebugDisplays() { mRenderDebugMask = 0xffffffffffffffff; }
void clearAllRenderDebugDisplays() { mRenderDebugMask = 0x0; }
bool hasRenderType(const U32 type) const;
@ -357,11 +357,11 @@ public:
// For UI control of render features
static bool hasRenderTypeControl(U32 data);
static void toggleRenderDebug(U32 data);
static void toggleRenderDebug(U64 data);
static void toggleRenderDebugFeature(U32 data);
static void toggleRenderTypeControl(U32 data);
static bool toggleRenderTypeControlNegated(S32 data);
static bool toggleRenderDebugControl(U32 data);
static bool toggleRenderDebugControl(U64 data);
static bool toggleRenderDebugFeatureControl(U32 data);
static void setRenderDebugFeatureControl(U32 bit, bool value);
@ -500,39 +500,41 @@ public:
RENDER_DEBUG_FEATURE_FOOT_SHADOWS = 0x0100,
};
enum LLRenderDebugMask
enum LLRenderDebugMask: U64
{
RENDER_DEBUG_COMPOSITION = 0x00000001,
RENDER_DEBUG_VERIFY = 0x00000002,
RENDER_DEBUG_BBOXES = 0x00000004,
RENDER_DEBUG_OCTREE = 0x00000008,
RENDER_DEBUG_WIND_VECTORS = 0x00000010,
RENDER_DEBUG_OCCLUSION = 0x00000020,
RENDER_DEBUG_POINTS = 0x00000040,
RENDER_DEBUG_TEXTURE_PRIORITY = 0x00000080,
RENDER_DEBUG_TEXTURE_AREA = 0x00000100,
RENDER_DEBUG_FACE_AREA = 0x00000200,
RENDER_DEBUG_PARTICLES = 0x00000400,
RENDER_DEBUG_GLOW = 0x00000800,
RENDER_DEBUG_TEXTURE_ANIM = 0x00001000,
RENDER_DEBUG_LIGHTS = 0x00002000,
RENDER_DEBUG_BATCH_SIZE = 0x00004000,
RENDER_DEBUG_ALPHA_BINS = 0x00008000,
RENDER_DEBUG_RAYCAST = 0x00010000,
RENDER_DEBUG_AVATAR_DRAW_INFO = 0x00020000,
RENDER_DEBUG_SHADOW_FRUSTA = 0x00040000,
RENDER_DEBUG_SCULPTED = 0x00080000,
RENDER_DEBUG_AVATAR_VOLUME = 0x00100000,
RENDER_DEBUG_AVATAR_JOINTS = 0x00200000,
RENDER_DEBUG_BUILD_QUEUE = 0x00400000,
RENDER_DEBUG_AGENT_TARGET = 0x00800000,
RENDER_DEBUG_UPDATE_TYPE = 0x01000000,
RENDER_DEBUG_PHYSICS_SHAPES = 0x02000000,
RENDER_DEBUG_NORMALS = 0x04000000,
RENDER_DEBUG_LOD_INFO = 0x08000000,
RENDER_DEBUG_RENDER_COMPLEXITY = 0x10000000,
RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000,
RENDER_DEBUG_TEXEL_DENSITY = 0x40000000
RENDER_DEBUG_COMPOSITION = 0x00000001,
RENDER_DEBUG_VERIFY = 0x00000002,
RENDER_DEBUG_BBOXES = 0x00000004,
RENDER_DEBUG_OCTREE = 0x00000008,
RENDER_DEBUG_WIND_VECTORS = 0x00000010,
RENDER_DEBUG_OCCLUSION = 0x00000020,
RENDER_DEBUG_POINTS = 0x00000040,
RENDER_DEBUG_TEXTURE_PRIORITY = 0x00000080,
RENDER_DEBUG_TEXTURE_AREA = 0x00000100,
RENDER_DEBUG_FACE_AREA = 0x00000200,
RENDER_DEBUG_PARTICLES = 0x00000400,
RENDER_DEBUG_GLOW = 0x00000800, // not used
RENDER_DEBUG_TEXTURE_ANIM = 0x00001000,
RENDER_DEBUG_LIGHTS = 0x00002000,
RENDER_DEBUG_BATCH_SIZE = 0x00004000,
RENDER_DEBUG_ALPHA_BINS = 0x00008000, // not used
RENDER_DEBUG_RAYCAST = 0x00010000,
RENDER_DEBUG_AVATAR_DRAW_INFO = 0x00020000,
RENDER_DEBUG_SHADOW_FRUSTA = 0x00040000,
RENDER_DEBUG_SCULPTED = 0x00080000,
RENDER_DEBUG_AVATAR_VOLUME = 0x00100000,
RENDER_DEBUG_AVATAR_JOINTS = 0x00200000,
RENDER_DEBUG_BUILD_QUEUE = 0x00400000,
RENDER_DEBUG_AGENT_TARGET = 0x00800000,
RENDER_DEBUG_UPDATE_TYPE = 0x01000000,
RENDER_DEBUG_PHYSICS_SHAPES = 0x02000000,
RENDER_DEBUG_NORMALS = 0x04000000,
RENDER_DEBUG_LOD_INFO = 0x08000000,
RENDER_DEBUG_RENDER_COMPLEXITY = 0x10000000,
RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used
RENDER_DEBUG_TEXEL_DENSITY = 0x40000000,
RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000,
RENDER_DEBUG_IMPOSTORS = 0x100000000
};
public:
@ -669,10 +671,10 @@ protected:
std::stack<std::string> mRenderTypeEnableStack;
U32 mRenderDebugFeatureMask;
U32 mRenderDebugMask;
U64 mRenderDebugMask;
U64 mOldRenderDebugMask;
std::stack<U32> mRenderDebugFeatureStack;
U32 mOldRenderDebugMask;
/////////////////////////////////////////////
//

View File

@ -14,6 +14,7 @@
<string name="status_idle"></string>
<string name="status_parse_error">Error: Dae parsing issue - see log for details.</string>
<string name="status_bind_shape_orientation">Warning: bind shape matrix is not in standard X-forward orientation.</string>
<string name="status_material_mismatch">Error: Material of model is not a subset of reference model.</string>
<string name="status_reading_file">Loading...</string>
<string name="status_generating_meshes">Generating Meshes...</string>

View File

@ -2,7 +2,7 @@
<floater
positioning="cascading"
legacy_header_height="18"
height="590"
height="600"
layout="topleft"
bg_opaque_image="Window_NoTitle_Foreground"
bg_alpha_image="Window_NoTitle_Background"
@ -2135,7 +2135,7 @@ even though the user gets a free copy.
<panel
border="false"
follows="all"
height="367"
height="387"
label="Features"
layout="topleft"
left_delta="0"
@ -2173,13 +2173,23 @@ even though the user gets a free copy.
Edit object features:
</text>
<check_box
height="19"
height="15"
label="Animated Mesh"
layout="topleft"
left="10"
name="Animated Mesh Checkbox Ctrl"
tool_tip="Allows rigged mesh objects to be animated independently"
top_pad="10"
width="121" />
<check_box
height="10"
label="Flexible Path"
follows="left|top"
layout="topleft"
left="10"
name="Flexible1D Checkbox Ctrl"
tool_tip="Allows object to flex about the Z axis (Client-side only)"
top_pad="20"
top_pad="15"
width="121" />
<spinner
follows="left|top"

View File

@ -214,4 +214,20 @@
<menu_item_call.on_enable
function="EnableMuteParticle" />
</menu_item_call>
<menu_item_call
label="Dump XML"
name="Dump XML">
<menu_item_call.on_click
function="Advanced.AppearanceToXML" />
<menu_item_call.on_visible
function="Advanced.EnableAppearanceToXML"/>
</menu_item_call>
<menu_item_call
label="Reset Skeleton"
name="Reset Skeleton">
<menu_item_call.on_click
function="Avatar.ResetSkeleton" />
<menu_item_call.on_visible
function="Avatar.EnableResetSkeleton"/>
</menu_item_call>
</context_menu>

View File

@ -2651,6 +2651,16 @@
function="Advanced.ToggleInfoDisplay"
parameter="lod info" />
</menu_item_check>
<menu_item_check
label="Triangle Count"
name="Triangle Count">
<menu_item_check.on_check
function="Advanced.CheckInfoDisplay"
parameter="triangle count" />
<menu_item_check.on_click
function="Advanced.ToggleInfoDisplay"
parameter="triangle count" />
</menu_item_check>
<menu_item_check
label="Build Queue"
name="Build Queue">
@ -3560,6 +3570,16 @@
function="Advanced.ToggleInfoDisplay"
parameter="agent target" />
</menu_item_check>
<menu_item_check
label="Show Impostor Extents"
name="Show Impostor Extents">
<menu_item_check.on_check
function="Advanced.CheckInfoDisplay"
parameter="impostors" />
<menu_item_check.on_click
function="Advanced.ToggleInfoDisplay"
parameter="impostors" />
</menu_item_check>
<!-- Appears not to exist anymore
<menu_item_check
label="Debug Rotation"

View File

@ -10223,6 +10223,14 @@ You have been teleported by the object '[OBJECT_NAME]' owned by an unknown user.
type="notify">
<tag>fail</tag>
Unable to create requested object. The region is full.
</notification>
<notification
icon="alertmodal.tga"
name="CantCreateAnimatedObjectTooLarge"
type="notify">
<tag>fail</tag>
Unable to create requested animated object because it exceeds the rigged triangle limit.
</notification>
<notification
@ -10353,6 +10361,46 @@ Your access privileges don't allow you to duplicate objects here.
You are not allowed to change this shape.
</notification>
<notification
icon="alertmodal.tga"
name="NoPermsTooManyAttachedAnimatedObjects"
type="notify">
<tag>fail</tag>
Operation would cause the number of attached animated objects to exceed the limit.
</notification>
<notification
icon="alertmodal.tga"
name="NoPermsLinkAnimatedObjectTooLarge"
type="notify">
<tag>fail</tag>
Can't link these objects because the resulting animated object would exceed the rigged triangle limit.
</notification>
<notification
icon="alertmodal.tga"
name="NoPermsSetFlagAnimatedObjectTooLarge"
type="notify">
<tag>fail</tag>
Can't make this object into an animated object because it would exceed the rigged triangle limit.
</notification>
<notification
icon="alertmodal.tga"
name="CantChangeAnimatedObjectStateInsufficientLand"
type="notify">
<tag>fail</tag>
Can't change animated object state for this object because it would cause parcel limit to be exceeded.
</notification>
<notification
icon="alertmodal.tga"
name="ErrorNoMeshData"
type="notify">
<tag>fail</tag>
Server error: cannot complete this operation because mesh data is not loaded.
</notification>
<notification
icon="alertmodal.tga"
name="NoAccessToClaimObjects"

View File

@ -34,7 +34,6 @@
*
*/
#include "linden_common.h"
#include "llerrorcontrol.h"
#include "lltut.h"
@ -685,5 +684,4 @@ int main(int argc, char **argv)
return retval;
//delete mycallback;
}

Some files were not shown because too many files have changed in this diff Show More