diff --git a/etc/message.xml b/etc/message.xml index 6d8160abb5..b444fe6c11 100755 --- a/etc/message.xml +++ b/etc/message.xml @@ -236,6 +236,14 @@ false + ObjectAnimation + + flavor + template + trusted-sender + false + + AvatarAppearance flavor diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 60359ca304..92217c60ff 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -190,7 +190,8 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mNumBones(0), mNumCollisionVolumes(0), mCollisionVolumes(NULL), - mIsBuilt(FALSE) + mIsBuilt(FALSE), + mInitFlags(0) { llassert_always(mWearableData); mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES); @@ -281,6 +282,8 @@ void LLAvatarAppearance::initInstance() buildCharacter(); + mInitFlags |= 1<<0; + } // virtual @@ -1724,7 +1727,7 @@ void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info) } mJointAliasMap[*i] = bone_name; } - + LLAvatarBoneInfo::child_list_t::const_iterator iter; for (iter = bone_info->mChildList.begin(); iter != bone_info->mChildList.end(); ++iter) { @@ -1739,13 +1742,34 @@ const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases { LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; - for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin(); iter != sAvatarSkeletonInfo->mBoneInfoList.end(); ++iter) + for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin(); + iter != sAvatarSkeletonInfo->mBoneInfoList.end(); + ++iter) { //LLAvatarBoneInfo *bone_info = *iter; makeJointAliases( *iter ); } + + LLAvatarXmlInfo::attachment_info_list_t::iterator attach_iter; + for (attach_iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); + attach_iter != sAvatarXmlInfo->mAttachmentInfoList.end(); + ++attach_iter) + { + LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *attach_iter; + std::string bone_name = info->mName; + + // Also accept the name with spaces substituted with + // underscores. This gives a mechanism for referencing such joints + // in daes, which don't allow spaces. + std::string sub_space_to_underscore = bone_name; + LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_'); + if (sub_space_to_underscore != bone_name) + { + mJointAliasMap[sub_space_to_underscore] = bone_name; + } + } } - + return mJointAliasMap; } diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index ccd6323ed8..7815c1844b 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -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 diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index a3d5679f65..e2f512f86e 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -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(); } //-------------------------------------------------------------------- diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 0c8fbfebb0..8112d246f2 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -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 //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 35e76f1d9d..c48d02b652 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -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(); } } diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 9d9c64f4f0..637ee4d2bb 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -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; diff --git a/indra/llcommon/llcallstack.h b/indra/llcommon/llcallstack.h index 1f7a7689d7..5acf04a49f 100644 --- a/indra/llcommon/llcallstack.h +++ b/indra/llcommon/llcallstack.h @@ -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; \ + } diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 64288e114b..40eb7d9bac 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -29,6 +29,7 @@ #include "llerror.h" #include "llerrorcontrol.h" +#include "llsdutil.h" #include #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; } diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index caf2ba72c2..1730f0c640 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -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(); diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 5b17d9e3a4..f04ae5f5cb 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -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) diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index c45db3b185..9a02fecd72 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -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 { diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index a4a5b393cb..68ee9db46b 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -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); }; /** diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index 4c8bcdac91..379c3ee9ea 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -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 diff --git a/indra/llmath/llmatrix4a.cpp b/indra/llmath/llmatrix4a.cpp new file mode 100644 index 0000000000..fe8f0b98f3 --- /dev/null +++ b/indra/llmath/llmatrix4a.cpp @@ -0,0 +1,80 @@ +/** +* @file llmatrix4a.cpp +* @brief Functions for vectorized matrix/vector operations +* +* $LicenseInfo:firstyear=2018&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llmath.h" +#include "llmatrix4a.h" + +// Convert a bounding box into other coordinate system. Should give +// the same results as transforming every corner of the bounding box +// and extracting the bounding box of that, although that's not +// necessarily the fastest way to implement. +void matMulBoundBox(const LLMatrix4a &mat, const LLVector4a *in_extents, LLVector4a *out_extents) +{ + //get 8 corners of bounding box + LLVector4Logical mask[6]; + + for (U32 i = 0; i < 6; ++i) + { + mask[i].clear(); + } + + mask[0].setElement<2>(); //001 + mask[1].setElement<1>(); //010 + mask[2].setElement<1>(); //011 + mask[2].setElement<2>(); + mask[3].setElement<0>(); //100 + mask[4].setElement<0>(); //101 + mask[4].setElement<2>(); + mask[5].setElement<0>(); //110 + mask[5].setElement<1>(); + + LLVector4a v[8]; + + v[6] = in_extents[0]; + v[7] = in_extents[1]; + + for (U32 i = 0; i < 6; ++i) + { + v[i].setSelectWithMask(mask[i], in_extents[0], in_extents[1]); + } + + LLVector4a tv[8]; + + //transform bounding box into drawable space + for (U32 i = 0; i < 8; ++i) + { + mat.affineTransform(v[i], tv[i]); + } + + //find bounding box + out_extents[0] = out_extents[1] = tv[0]; + + for (U32 i = 1; i < 8; ++i) + { + out_extents[0].setMin(out_extents[0], tv[i]); + out_extents[1].setMax(out_extents[1], tv[i]); + } +} diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 216334752a..7ba347062f 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -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 diff --git a/indra/llmath/llrigginginfo.cpp b/indra/llmath/llrigginginfo.cpp new file mode 100644 index 0000000000..0de07950c1 --- /dev/null +++ b/indra/llmath/llrigginginfo.cpp @@ -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 size()) + { + resize(src.size()); + } + S32 min_size = llmin(size(), src.size()); + for (S32 i=0; i 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 diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 79d0a44551..222f3cf235 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -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 diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 6b6cd65ce2..ba284574c8 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -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& 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; diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index d3c1ac46fe..1d6d35c432 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -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* mOctree; diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index e7107dee16..b04c67d926 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -369,3 +369,39 @@ BOOL LLVector3::parseVector3(const std::string& buf, LLVector3* value) return FALSE; } + +// Displacement from query point to nearest neighbor point on bounding box. +// Returns zero vector for points within or on the box. +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box) +{ + LLVector3 offset; + for (S32 k=0; k<3; k++) + { + offset[k] = 0; + if (pos[k] < box[0][k]) + { + offset[k] = pos[k] - box[0][k]; + } + else if (pos[k] > box[1][k]) + { + offset[k] = pos[k] - box[1][k]; + } + } + return offset; +} + +bool box_valid_and_non_zero(const LLVector3* box) +{ + if (!box[0].isFinite() || !box[1].isFinite()) + { + return false; + } + LLVector3 zero_vec; + zero_vec.clear(); + if ((box[0] != zero_vec) || (box[1] != zero_vec)) + { + return true; + } + return false; +} + diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index f3fbce4843..6f857d7061 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -163,6 +163,8 @@ LLVector3 inverse_projected_vec(const LLVector3 &a, const LLVector3 &b); // Retu LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b (same as projected_vec) LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b); // Returns component of vector a not parallel to vector b (same as projected_vec) LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box); // Displacement from query point to nearest point on bounding box. +bool box_valid_and_non_zero(const LLVector3* box); inline LLVector3::LLVector3(void) { diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 1ae8a6ac15..f8e11e324e 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -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"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 7910fde305..334236fb25 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -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; diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 8401cb976e..8f75d89e5a 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -192,7 +192,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector& 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& 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& 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& 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& 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& 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& 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& fac for (std::map::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()); } diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 8fbb4f6b96..37548e3fe3 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -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); } diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 097558ef67..cf3288489a 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -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, diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index d64e0a0773..643c45a6d8 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -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, diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index edf7c41e40..c69c059880 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1609,6 +1609,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size) return (size == 17); case PARAMS_LIGHT_IMAGE: return (size == 28); + case PARAMS_EXTENDED_MESH: + return (size == 4); } return FALSE; @@ -2036,3 +2038,67 @@ bool LLLightImageParams::fromLLSD(LLSD& sd) return false; } + +//============================================================================ + +LLExtendedMeshParams::LLExtendedMeshParams() +{ + mType = PARAMS_EXTENDED_MESH; + mFlags = 0; +} + +BOOL LLExtendedMeshParams::pack(LLDataPacker &dp) const +{ + dp.packU32(mFlags, "flags"); + + return TRUE; +} + +BOOL LLExtendedMeshParams::unpack(LLDataPacker &dp) +{ + dp.unpackU32(mFlags, "flags"); + + return TRUE; +} + +bool LLExtendedMeshParams::operator==(const LLNetworkData& data) const +{ + if (data.mType != PARAMS_EXTENDED_MESH) + { + return false; + } + + const LLExtendedMeshParams *param = (const LLExtendedMeshParams*)&data; + if ( (param->mFlags != mFlags) ) + { + return false; + } + + return true; +} + +void LLExtendedMeshParams::copy(const LLNetworkData& data) +{ + const LLExtendedMeshParams *param = (LLExtendedMeshParams*)&data; + mFlags = param->mFlags; +} + +LLSD LLExtendedMeshParams::asLLSD() const +{ + LLSD sd; + + sd["flags"] = LLSD::Integer(mFlags); + + return sd; +} + +bool LLExtendedMeshParams::fromLLSD(LLSD& sd) +{ + if (sd.has("flags")) + { + setFlags( sd["flags"].asInteger()); + return true; + } + + return false; +} diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 99a32e614c..c138c2ac2b 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -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 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 2fc722d4c3..ce8b662231 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -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 diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 48ea19be07..09b254e90c 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -5.1.10 +6.0.0 diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index 8ced81fdb3..482012cdd6 100644 --- a/indra/newview/app_settings/logcontrol.xml +++ b/indra/newview/app_settings/logcontrol.xml @@ -2,6 +2,22 @@ default-level INFO + print-location false + log-always-flush true + + enabled-log-types-mask 255 settings @@ -50,6 +66,7 @@ tags viewer +{ + ObjectAnimation High 30 Trusted Unencoded + { + Sender Single + { ID LLUUID } + } + { + AnimationList Variable + { AnimID LLUUID } + { AnimSequenceID S32 } + } +} + // ************************************************************************* // Asset storage messages // ************************************************************************* diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1 index 5bc06ec042..db87ad5e77 100755 --- a/scripts/messages/message_template.msg.sha1 +++ b/scripts/messages/message_template.msg.sha1 @@ -1 +1 @@ -337f351910b0c8821cb3d447bc6578516a043c80 \ No newline at end of file +55df2c7135733c5da64ef8f01859b83a433a3a09 \ No newline at end of file diff --git a/scripts/testing/lsl/axon_test_region_driver.lsl b/scripts/testing/lsl/axon_test_region_driver.lsl new file mode 100644 index 0000000000..dcf146a9cf --- /dev/null +++ b/scripts/testing/lsl/axon_test_region_driver.lsl @@ -0,0 +1,54 @@ +list buttons = ["anim start", "anim stop", "step", "verbose on", "verbose off", " "]; +string dialogInfo = "\nPlease make a choice."; + +key ToucherID; +integer dialogChannel; +integer listenHandle; +integer commandChannel; + +default +{ + state_entry() + { + dialogChannel = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) ); + commandChannel = -2001; + } + + touch_start(integer num_detected) + { + ToucherID = llDetectedKey(0); + llListenRemove(listenHandle); + listenHandle = llListen(dialogChannel, "", ToucherID, ""); + llDialog(ToucherID, dialogInfo, buttons, dialogChannel); + //llSetTimerEvent(60.0); // Here we set a time limit for responses + } + + listen(integer channel, string name, key id, string message) + { + if (message == "-") + { + llDialog(ToucherID, dialogInfo, buttons, dialogChannel); + return; + } + + llListenRemove(listenHandle); + // stop timer since the menu was clicked + llSetTimerEvent(0); + + //llOwnerSay("Sending message " + message + " on channel " + (string)commandChannel); + llRegionSay(commandChannel, message); + } + + timer() + { + // stop timer + llSetTimerEvent(0); + + llListenRemove(listenHandle); + //llWhisper(0, "Sorry. You snooze; you lose."); + } +} + +// Local Variables: +// shadow-file-name: "$SW_HOME/axon/scripts/testing/lsl/axon_test_region_driver.lsl" +// End: diff --git a/scripts/testing/lsl/cycle_object_animations.lsl b/scripts/testing/lsl/cycle_object_animations.lsl new file mode 100644 index 0000000000..46910e3656 --- /dev/null +++ b/scripts/testing/lsl/cycle_object_animations.lsl @@ -0,0 +1,118 @@ +integer listenHandle; +integer verbose; +integer current_animation_number; +string NowPlaying; + +say_if_verbose(integer channel, string message) +{ + if (verbose) + { + llSay(channel, message); + } +} + +stop_all_animations() +{ + integer count = llGetInventoryNumber(INVENTORY_ANIMATION); + string ItemName; + string NowPlaying; + while (count--) + { + ItemName = llGetInventoryName(INVENTORY_ANIMATION, count); + say_if_verbose(0, "Stopping " + ItemName); + llStopObjectAnimation(ItemName); + } +} + +start_cycle_animations() +{ + current_animation_number = llGetInventoryNumber(INVENTORY_ANIMATION); + next_animation(); // Do first iteration without waiting for timer + llSetTimerEvent(5.0); +} + +next_animation() +{ + string ItemName; + if (NowPlaying != "") + { + say_if_verbose(0, "Stopping " + NowPlaying); + llStopObjectAnimation(NowPlaying); + } + if (current_animation_number--) + { + ItemName = llGetInventoryName(INVENTORY_ANIMATION, current_animation_number); + say_if_verbose(0, "Starting " + ItemName); + llStartObjectAnimation(ItemName); + NowPlaying = ItemName; + } + else + { + // Start again at the top + current_animation_number = llGetInventoryNumber(INVENTORY_ANIMATION); + } +} + +stop_cycle_animations() +{ + llSetTimerEvent(0); +} + +default +{ + state_entry() + { + say_if_verbose(0, "Animated Object here"); + listenHandle = llListen(-2001,"","",""); + verbose = 0; + + stop_all_animations(); + } + + listen(integer channel, string name, key id, string message) + { + //llOwnerSay("got message " + name + " " + (string) id + " " + message); + list words = llParseString2List(message,[" "],[]); + string command = llList2String(words,0); + string option = llList2String(words,1); + if (command=="anim") + { + stop_all_animations(); + if (option=="start") + { + start_cycle_animations(); + } + else if (option=="stop") + { + stop_cycle_animations(); + } + } + if (command=="verbose") + { + if (option=="on") + { + verbose = 1; + } + else if (option=="off") + { + verbose = 0; + } + } + } + + timer() + { + say_if_verbose(0, "timer triggered"); + next_animation(); + } + + touch_start(integer total_number) + { + say_if_verbose(0, "Touch started."); + start_cycle_animations(); + } +} + +// Local Variables: +// shadow-file-name: "$SW_HOME/axon/scripts/testing/lsl/cycle_object_animations.lsl" +// End: diff --git a/scripts/testing/lsl/cycle_object_animations_v2.lsl b/scripts/testing/lsl/cycle_object_animations_v2.lsl new file mode 100644 index 0000000000..60879fcce2 --- /dev/null +++ b/scripts/testing/lsl/cycle_object_animations_v2.lsl @@ -0,0 +1,133 @@ +integer listenHandle; +integer verbose; +integer current_animation_number; +string NowPlaying; + +say_if_verbose(integer channel, string message) +{ + if (verbose) + { + llSay(channel, message); + } +} + +stop_all_animations() +{ + list curr_anims = llGetObjectAnimationNames(); + say_if_verbose(0,"stopping all, curr_anims are " + (string) curr_anims); + integer length = llGetListLength(curr_anims); + integer index = 0; + while (index < length) + { + string anim = llList2String(curr_anims, index); + say_if_verbose(0, "Stopping " + anim); + llStopObjectAnimation(anim); + // This check isn't really needed, just included to demonstrate is_animation_running() + if (is_animation_running(anim)) + { + say_if_verbose(0, "ERROR - failed to stop " + anim + "!"); + } + ++index; + } +} + +integer is_animation_running(string anim) +{ + list curr_anims = llGetObjectAnimationNames(); + return ~llListFindList(curr_anims, (list)anim); +} + +start_cycle_animations() +{ + current_animation_number = llGetInventoryNumber(INVENTORY_ANIMATION); + next_animation(); // Do first iteration without waiting for timer + llSetTimerEvent(5.0); +} + +next_animation() +{ + string ItemName; + if (NowPlaying != "") + { + say_if_verbose(0, "Stopping " + NowPlaying); + llStopObjectAnimation(NowPlaying); + } + if (current_animation_number--) + { + ItemName = llGetInventoryName(INVENTORY_ANIMATION, current_animation_number); + say_if_verbose(0, "Starting " + ItemName); + llStartObjectAnimation(ItemName); + key anim_id = llGetInventoryKey(ItemName); + say_if_verbose(0, "Started item " + ItemName + " inv key " + (string) anim_id); + NowPlaying = ItemName; + } + else + { + // Start again at the top + current_animation_number = llGetInventoryNumber(INVENTORY_ANIMATION); + } +} + +stop_cycle_animations() +{ + llSetTimerEvent(0); +} + +default +{ + state_entry() + { + say_if_verbose(0, "Animated Object here"); + listenHandle = llListen(-2001,"","",""); + verbose = 0; + + stop_all_animations(); + } + + listen(integer channel, string name, key id, string message) + { + //llOwnerSay("got message " + name + " " + (string) id + " " + message); + list words = llParseString2List(message,[" "],[]); + string command = llList2String(words,0); + string option = llList2String(words,1); + if (command=="anim") + { + stop_all_animations(); + if (option=="start") + { + start_cycle_animations(); + } + else if (option=="stop") + { + stop_cycle_animations(); + } + } + if (command=="verbose") + { + if (option=="on") + { + verbose = 1; + } + else if (option=="off") + { + verbose = 0; + } + } + } + + timer() + { + say_if_verbose(0, "timer triggered"); + next_animation(); + } + + touch_start(integer total_number) + { + say_if_verbose(0, "Touch started."); + start_cycle_animations(); + } +} + +// Local Variables: +// shadow-file-name: "$SW_HOME/axon/scripts/testing/lsl/cycle_object_animations_v2.lsl" +// End: diff --git a/scripts/testing/lsl/move_in_circle_using_llSetRegionPos.lsl b/scripts/testing/lsl/move_in_circle_using_llSetRegionPos.lsl new file mode 100644 index 0000000000..cc5b899b67 --- /dev/null +++ b/scripts/testing/lsl/move_in_circle_using_llSetRegionPos.lsl @@ -0,0 +1,90 @@ +integer listenHandle; +integer verbose; +integer num_steps = 12; +float circle_time = 5.0; +integer circle_step; +vector circle_pos; +vector circle_center; +float circle_radius; + +start_circle(vector center, float radius) +{ + vector currentPosition = llGetPos(); + circle_center = center; + circle_radius = radius; + circle_step = 0; + llSetTimerEvent(circle_time/num_steps); + llTargetOmega(<0.0, 0.0, 1.0>, TWO_PI/circle_time, 1.0); +} + +stop_circle() +{ + llSetTimerEvent(0); + llTargetOmega(<0.0, 0.0, 1.0>, TWO_PI/circle_time, 0.0); + llSetRegionPos(circle_center); +} + +next_circle() +{ + float rad = (circle_step * TWO_PI)/num_steps; + float x = circle_center.x + llCos(rad)*circle_radius; + float y = circle_center.y + llSin(rad)*circle_radius; + float z = circle_center.z; + llSetRegionPos(); + circle_step = (circle_step+1)%num_steps; +} + +default +{ + state_entry() + { + //llSay(0, "Hello, Avatar!"); + listenHandle = llListen(-2001,"","",""); + verbose = 0; + circle_center = llGetPos(); + } + + listen(integer channel, string name, key id, string message) + { + //llOwnerSay("got message " + name + " " + (string) id + " " + message); + list words = llParseString2List(message,[" "],[]); + string command = llList2String(words,0); + string option = llList2String(words,1); + if (command=="anim") + { + if (option=="start") + { + start_circle(llGetPos(), 3.0); + } + else if (option=="stop") + { + stop_circle(); + } + } + if (command=="verbose") + { + if (option=="on") + { + verbose = 1; + } + else if (option=="off") + { + verbose = 0; + } + } + if (command=="step") + { + llSetTimerEvent(0); + next_circle(); + } + } + + timer() + { + next_circle(); + } +} + +// Local Variables: +// shadow-file-name: "$SW_HOME/axon/scripts/testing/lsl/move_in_circle_using_llSetRegionPos.lsl" +// End: