Merge
commit
014480a79b
1
.hgtags
1
.hgtags
|
|
@ -541,3 +541,4 @@ ad0e15543836d64d6399d28b32852510435e344a 5.1.0-release
|
|||
ac3b1332ad4f55b7182a8cbcc1254535a0069f75 5.1.7-release
|
||||
23ea0fe36fadf009a60c080392ce80e4bf8af8d9 5.1.8-release
|
||||
52422540bfe54b71155aa455360bee6e3ef1fd96 5.1.9-release
|
||||
821edfcd14919c0e95c590866171c61fb57e8623 6.0.0-release
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1739,7 +1742,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)
|
||||
{
|
||||
|
|
@ -1754,13 +1757,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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; \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1626,6 +1626,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;
|
||||
|
|
@ -2053,3 +2055,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
5.1.10
|
||||
6.0.1
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -646,6 +646,11 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LLAppViewerWin32::beingDebugged()
|
||||
{
|
||||
return IsDebuggerPresent();
|
||||
}
|
||||
|
||||
bool LLAppViewerWin32::restoreErrorTrap()
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ LLViewerTexture *LLDrawPool::getDebugTexture()
|
|||
return NULL;
|
||||
}
|
||||
|
||||
//virtual
|
||||
//virtuals
|
||||
void LLDrawPool::beginRenderPass( S32 pass )
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ public:
|
|||
virtual S32 getVertexShaderLevel() const;
|
||||
|
||||
LLDrawPoolAvatar();
|
||||
~LLDrawPoolAvatar();
|
||||
/*virtual*/ BOOL isDead();
|
||||
|
||||
static LLMatrix4& getModelView();
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -646,6 +647,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;
|
||||
|
|
@ -670,6 +675,10 @@ bool LLSelectMgr::enableLinkObjects()
|
|||
new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
|
||||
}
|
||||
}
|
||||
if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable())
|
||||
{
|
||||
new_value = false;
|
||||
}
|
||||
return new_value;
|
||||
}
|
||||
|
||||
|
|
@ -6662,7 +6671,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
|
||||
|
|
@ -6680,23 +6692,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
|
||||
|
|
@ -6773,6 +6774,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()
|
||||
|
|
@ -7249,10 +7303,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;
|
||||
|
|
@ -7409,6 +7469,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;
|
||||
|
|
|
|||
|
|
@ -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 ¤t_zoom) const;
|
||||
|
|
@ -849,7 +854,7 @@ private:
|
|||
LLFrameTimer mEffectsTimer;
|
||||
BOOL mForceSelection;
|
||||
|
||||
LLAnimPauseRequest mPauseRequest;
|
||||
std::vector<LLAnimPauseRequest> mPauseRequests;
|
||||
};
|
||||
|
||||
// *DEPRECATED: For callbacks or observers, use
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -468,8 +468,6 @@ public:
|
|||
virtual LLCamera transformCamera(LLCamera& camera);
|
||||
|
||||
LLDrawable* mDrawable;
|
||||
LLPointer<LLVOAvatar> mAvatar;
|
||||
|
||||
};
|
||||
|
||||
class LLCullResult
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -139,8 +143,11 @@ const U32 MAX_INV_FILE_READ_FAILS = 25;
|
|||
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);
|
||||
|
||||
|
|
@ -167,6 +174,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);
|
||||
|
|
@ -236,6 +255,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),
|
||||
|
|
@ -260,7 +280,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),
|
||||
|
|
@ -366,17 +386,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;
|
||||
|
|
@ -677,6 +703,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;
|
||||
|
|
@ -849,9 +887,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)
|
||||
|
|
@ -1068,6 +1115,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.
|
||||
|
|
@ -1122,10 +1172,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
|
||||
|
|
@ -1381,7 +1431,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);
|
||||
|
|
@ -1651,7 +1701,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
|
|||
|
||||
U8 state;
|
||||
mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
|
||||
mState = state;
|
||||
mAttachmentState = state;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1674,7 +1724,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
|
|||
U8 state;
|
||||
|
||||
dp->unpackU8(state, "State");
|
||||
mState = state;
|
||||
mAttachmentState = state;
|
||||
|
||||
switch(update_type)
|
||||
{
|
||||
|
|
@ -2907,6 +2957,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;
|
||||
|
|
@ -3531,11 +3706,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;
|
||||
|
|
@ -3546,6 +3776,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;
|
||||
|
|
@ -3649,7 +3931,6 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void LLViewerObject::setLineWidthForWindowSize(S32 window_width)
|
||||
{
|
||||
if (window_width < 700)
|
||||
|
|
@ -3876,8 +4157,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();
|
||||
}
|
||||
|
|
@ -3901,7 +4194,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;
|
||||
}
|
||||
|
|
@ -5242,7 +5535,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();
|
||||
|
|
@ -5581,6 +5880,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;
|
||||
|
|
@ -5980,6 +6284,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())
|
||||
|
|
@ -6039,6 +6354,11 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp)
|
|||
child->setRegion(regionp);
|
||||
}
|
||||
|
||||
if (mControlAvatar)
|
||||
{
|
||||
mControlAvatar->setRegion(regionp);
|
||||
}
|
||||
|
||||
setChanged(MOVED | SILHOUETTE);
|
||||
updateDrawable(FALSE);
|
||||
}
|
||||
|
|
@ -6487,6 +6807,10 @@ const std::string& LLViewerObject::getAttachmentItemName() const
|
|||
//virtual
|
||||
LLVOAvatar* LLViewerObject::getAvatar() const
|
||||
{
|
||||
if (getControlAvatar())
|
||||
{
|
||||
return getControlAvatar();
|
||||
}
|
||||
if (isAttachment())
|
||||
{
|
||||
LLViewerObject* vobj = (LLViewerObject*) getParent();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -690,6 +708,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
|
||||
|
|
@ -700,8 +739,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);
|
||||
|
||||
|
|
@ -789,7 +827,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
|
||||
|
|
@ -845,6 +883,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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -307,6 +307,7 @@ public:
|
|||
bool bakesOnMeshEnabled() 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);
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
@ -720,7 +766,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
|
||||
** **
|
||||
|
|
@ -743,9 +791,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 );
|
||||
|
||||
|
|
@ -765,10 +813,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
|
||||
** **
|
||||
|
|
@ -901,7 +951,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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -312,6 +312,9 @@ public:
|
|||
//--------------------------------------------------------------------
|
||||
// Visibility
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/* virtual */ bool shouldRenderRigged() const;
|
||||
|
||||
public:
|
||||
bool sendAppearanceMessage(LLMessageSystem *mesgsys) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -11649,6 +11661,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
|
|||
|
||||
avatar->mNeedsImpostorUpdate = FALSE;
|
||||
avatar->cacheImpostorValues();
|
||||
avatar->mLastImpostorUpdateFrameTime = gFrameTimeSeconds;
|
||||
|
||||
LLVertexBuffer::unbind();
|
||||
LLGLState::checkStates();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -2650,6 +2650,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">
|
||||
|
|
@ -3559,6 +3569,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"
|
||||
|
|
|
|||
|
|
@ -10213,6 +10213,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
|
||||
|
|
@ -10343,6 +10351,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"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue