Merge branch 'master' into osx_xcode5
This commit is contained in:
@@ -16,11 +16,14 @@ endif(WORD_SIZE EQUAL 32)
|
||||
|
||||
set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-win32")
|
||||
set(vivox_files
|
||||
SLVoice.exe
|
||||
alut.dll
|
||||
vivoxsdk.dll
|
||||
ca-bundle.crt
|
||||
libsndfile-1.dll
|
||||
ortp.dll
|
||||
wrap_oal.dll
|
||||
SLVoice.exe
|
||||
vivoxoal.dll
|
||||
vivoxplatform.dll
|
||||
vivoxsdk.dll
|
||||
zlib1.dll
|
||||
)
|
||||
copy_if_different(
|
||||
${vivox_src_dir}
|
||||
|
||||
@@ -392,6 +392,40 @@ void InstanceTracker<T>::dump(void)
|
||||
|
||||
} // namespace debug
|
||||
|
||||
template<class T>
|
||||
class AIDebugInstanceCounter
|
||||
{
|
||||
public:
|
||||
static int sInstanceCount;
|
||||
|
||||
protected:
|
||||
static void print_count(char const* name, int count, bool destruction);
|
||||
|
||||
AIDebugInstanceCounter()
|
||||
{
|
||||
print_count(typeid(T).name(), ++sInstanceCount, false);
|
||||
}
|
||||
AIDebugInstanceCounter(AIDebugInstanceCounter const&)
|
||||
{
|
||||
print_count(typeid(T).name(), ++sInstanceCount, false);
|
||||
}
|
||||
~AIDebugInstanceCounter()
|
||||
{
|
||||
print_count(typeid(T).name(), --sInstanceCount, true);
|
||||
}
|
||||
};
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
int AIDebugInstanceCounter<T>::sInstanceCount;
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void AIDebugInstanceCounter<T>::print_count(char const* name, int count, bool destruction)
|
||||
{
|
||||
Dout(dc::notice, (destruction ? "Destructed " : "Constructing ") << name << ", now " << count << " instance" << ((count == 1) ? "." : "s."));
|
||||
}
|
||||
|
||||
//! Debugging macro.
|
||||
//
|
||||
// Print "Entering " << \a data to channel \a cntrl and increment
|
||||
|
||||
@@ -317,7 +317,7 @@ namespace HACD
|
||||
bool m_addFacesPoints; //>! specifies whether to add faces points or not
|
||||
bool m_addExtraDistPoints; //>! specifies whether to add extra points for concave shapes or not
|
||||
|
||||
friend HACD * const CreateHACD(HeapManager * heapManager = 0);
|
||||
friend HACD * const CreateHACD(HeapManager * heapManager);
|
||||
friend void DestroyHACD(HACD * const hacd);
|
||||
};
|
||||
inline HACD * const CreateHACD(HeapManager * heapManager)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
#ifndef LL_LLAUDIODECODEMGR_H
|
||||
#define LL_LLAUDIODECODEMG_H
|
||||
#define LL_LLAUDIODECODEMGR_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ set(llcharacter_SOURCE_FILES
|
||||
lljointsolverrp3.cpp
|
||||
llkeyframefallmotion.cpp
|
||||
llkeyframemotion.cpp
|
||||
llkeyframemotionparam.cpp
|
||||
llkeyframestandmotion.cpp
|
||||
llkeyframewalkmotion.cpp
|
||||
llmotion.cpp
|
||||
@@ -57,7 +56,6 @@ set(llcharacter_HEADER_FILES
|
||||
lljointstate.h
|
||||
llkeyframefallmotion.h
|
||||
llkeyframemotion.h
|
||||
llkeyframemotionparam.h
|
||||
llkeyframestandmotion.h
|
||||
llkeyframewalkmotion.h
|
||||
llmotion.h
|
||||
|
||||
@@ -136,7 +136,6 @@ LLMotion* LLCharacter::findMotion( const LLUUID &id )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// createMotion()
|
||||
// NOTE: Always assign the result to a LLPointer!
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion* LLCharacter::createMotion( const LLUUID &id )
|
||||
{
|
||||
@@ -195,11 +194,26 @@ void LLCharacter::updateMotions(e_update_t update_type)
|
||||
{
|
||||
if (update_type == HIDDEN_UPDATE)
|
||||
{
|
||||
//<singu>
|
||||
// Keep updating avatars that have at least one motion that is synchronized with a still running motion.
|
||||
// This call tells the other controllers that we are in principle hidden.
|
||||
// It returns false if we need to keep updating anyway.
|
||||
if (!mMotionController.hidden(true))
|
||||
{
|
||||
mMotionController.updateMotions(LLCharacter::NORMAL_UPDATE);
|
||||
return;
|
||||
}
|
||||
//</singu>
|
||||
LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION);
|
||||
mMotionController.updateMotionsMinimal();
|
||||
}
|
||||
else
|
||||
{
|
||||
//<singu>
|
||||
// This call tells the other controllers that we are visible and that they need
|
||||
// to keep updating if they are synchronized with us, even if they are hidden.
|
||||
mMotionController.hidden(false);
|
||||
//</singu>
|
||||
LLFastTimer t(FTM_UPDATE_ANIMATION);
|
||||
// unpause if the number of outstanding pause requests has dropped to the initial one
|
||||
if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
|
||||
@@ -529,3 +543,17 @@ LLAnimPauseRequest LLCharacter::requestPause()
|
||||
return mPauseRequest;
|
||||
}
|
||||
|
||||
void LLCharacter::requestPause(std::vector<LLAnimPauseRequest>& avatar_pause_handles)
|
||||
{
|
||||
mMotionController.pauseAllMotions();
|
||||
avatar_pause_handles.push_back(mPauseRequest);
|
||||
}
|
||||
|
||||
void LLCharacter::pauseAllSyncedCharacters(std::vector<LLAnimPauseRequest>& avatar_pause_handles)
|
||||
{
|
||||
// Pause this avatar.
|
||||
requestPause(avatar_pause_handles);
|
||||
// Also pause all avatars with synchronized motions.
|
||||
mMotionController.pauseAllSyncedCharacters(avatar_pause_handles);
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,7 @@ public:
|
||||
|
||||
// is this motion active?
|
||||
BOOL isMotionActive( const LLUUID& id );
|
||||
bool isMotionActive(U32 bit) const { return mMotionController.isactive(bit); }
|
||||
|
||||
// Event handler for motion deactivation.
|
||||
// Called when a motion has completely stopped and has been deactivated.
|
||||
@@ -158,6 +159,8 @@ public:
|
||||
void updateMotions(e_update_t update_type);
|
||||
|
||||
LLAnimPauseRequest requestPause();
|
||||
void requestPause(std::vector<LLAnimPauseRequest>& avatar_pause_handles);
|
||||
void pauseAllSyncedCharacters(std::vector<LLAnimPauseRequest>& avatar_pause_handles);
|
||||
BOOL areAnimationsPaused() const { return mMotionController.isPaused(); }
|
||||
void setAnimTimeFactor(F32 factor) { mMotionController.setTimeFactor(factor); }
|
||||
void setTimeStep(F32 time_step) { mMotionController.setTimeStep(time_step); }
|
||||
|
||||
@@ -49,7 +49,7 @@ S32 LLEditingMotion::sHandPosePriority = 3;
|
||||
// LLEditingMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLEditingMotion::LLEditingMotion( const LLUUID &id) : LLMotion(id)
|
||||
LLEditingMotion::LLEditingMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EDITING)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
|
||||
@@ -155,7 +155,7 @@ BOOL LLEditingMotion::onActivate()
|
||||
mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() );
|
||||
mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() );
|
||||
|
||||
return TRUE;
|
||||
return AIMaskedMotion::onActivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -256,12 +256,4 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLEditingMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLEditingMotion::onDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// End
|
||||
|
||||
@@ -49,11 +49,11 @@
|
||||
// class LLEditingMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLEditingMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLEditingMotion(const LLUUID &id);
|
||||
LLEditingMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLEditingMotion();
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLEditingMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEditingMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -107,9 +107,6 @@ public:
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// joint states to be animated
|
||||
|
||||
@@ -61,7 +61,7 @@ const F32 HAND_MORPH_BLEND_TIME = 0.2f;
|
||||
// LLHandMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLHandMotion::LLHandMotion(const LLUUID &id) : LLMotion(id)
|
||||
LLHandMotion::LLHandMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_HAND_MOTION)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
mLastTime = 0.f;
|
||||
@@ -112,7 +112,7 @@ BOOL LLHandMotion::onActivate()
|
||||
mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
|
||||
mCharacter->updateVisualParams();
|
||||
}
|
||||
return TRUE;
|
||||
return AIMaskedMotion::onActivate();
|
||||
}
|
||||
|
||||
|
||||
@@ -235,14 +235,6 @@ BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHandMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLHandMotion::onDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHandMotion::getHandPoseName()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
// class LLHandMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLHandMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
typedef enum e_hand_pose
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
} eHandPose;
|
||||
|
||||
// Constructor
|
||||
LLHandMotion(const LLUUID &id);
|
||||
LLHandMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLHandMotion();
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLHandMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLHandMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -122,9 +122,6 @@ public:
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
virtual BOOL canDeprecate() { return FALSE; }
|
||||
|
||||
static std::string getHandPoseName(eHandPose pose);
|
||||
|
||||
@@ -76,8 +76,8 @@ const F32 EYE_BLINK_TIME_DELTA = 0.005f; // time between one eye starting a blin
|
||||
// LLHeadRotMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLHeadRotMotion::LLHeadRotMotion(const LLUUID &id) :
|
||||
LLMotion(id),
|
||||
LLHeadRotMotion::LLHeadRotMotion(LLUUID const& id, LLMotionController* controller) :
|
||||
AIMaskedMotion(id, controller, ANIM_AGENT_HEAD_ROT),
|
||||
mCharacter(NULL),
|
||||
mTorsoJoint(NULL),
|
||||
mHeadJoint(NULL)
|
||||
@@ -104,7 +104,10 @@ LLHeadRotMotion::~LLHeadRotMotion()
|
||||
LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *character)
|
||||
{
|
||||
if (!character)
|
||||
{
|
||||
llwarns << "character is NULL." << llendl;
|
||||
return STATUS_FAILURE;
|
||||
}
|
||||
mCharacter = character;
|
||||
|
||||
mPelvisJoint = character->getJoint("mPelvis");
|
||||
@@ -169,16 +172,6 @@ LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *characte
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHeadRotMotion::onActivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLHeadRotMotion::onActivate()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHeadRotMotion::onUpdate()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -263,19 +256,11 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHeadRotMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLHeadRotMotion::onDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLEyeMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id)
|
||||
LLEyeMotion::LLEyeMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EYE)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
mEyeJitterTime = 0.f;
|
||||
@@ -343,16 +328,6 @@ LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character)
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLEyeMotion::onActivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLEyeMotion::onActivate()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLEyeMotion::onUpdate()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -533,6 +508,8 @@ void LLEyeMotion::onDeactivate()
|
||||
{
|
||||
joint->setRotation(LLQuaternion::DEFAULT);
|
||||
}
|
||||
|
||||
AIMaskedMotion::onDeactivate();
|
||||
}
|
||||
|
||||
// End
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
// class LLHeadRotMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLHeadRotMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLHeadRotMotion(const LLUUID &id);
|
||||
LLHeadRotMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLHeadRotMotion();
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLHeadRotMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLHeadRotMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -94,19 +94,11 @@ public:
|
||||
// must return true to indicate success and be available for activation
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
|
||||
// called when a motion is activated
|
||||
// must return TRUE to indicate success, or else
|
||||
// it will be deactivated
|
||||
virtual BOOL onActivate();
|
||||
|
||||
// called per time step
|
||||
// must return TRUE while it is active, and
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// joint states to be animated
|
||||
@@ -129,11 +121,11 @@ public:
|
||||
// class LLEyeMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLEyeMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLEyeMotion(const LLUUID &id);
|
||||
LLEyeMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLEyeMotion();
|
||||
@@ -145,7 +137,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create( const LLUUID &id) { return new LLEyeMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEyeMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -177,11 +169,6 @@ public:
|
||||
// must return true to indicate success and be available for activation
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
|
||||
// called when a motion is activated
|
||||
// must return TRUE to indicate success, or else
|
||||
// it will be deactivated
|
||||
virtual BOOL onActivate();
|
||||
|
||||
// called per time step
|
||||
// must return TRUE while it is active, and
|
||||
// must return FALSE when the motion is completed.
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "lldarray.h"
|
||||
|
||||
const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15;
|
||||
const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 4!
|
||||
const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 16!
|
||||
const U32 LL_HAND_JOINT_NUM = 31;
|
||||
const U32 LL_FACE_JOINT_NUM = 30;
|
||||
const S32 LL_CHARACTER_MAX_PRIORITY = 7;
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
// LLKeyframeFallMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeFallMotion::LLKeyframeFallMotion(const LLUUID &id) : LLKeyframeMotion(id)
|
||||
LLKeyframeFallMotion::LLKeyframeFallMotion(LLUUID const& id, LLMotionController* controller) : LLKeyframeMotion(id, controller)
|
||||
{
|
||||
mVelocityZ = 0.f;
|
||||
mCharacter = NULL;
|
||||
|
||||
@@ -47,7 +47,7 @@ class LLKeyframeFallMotion :
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeFallMotion(const LLUUID &id);
|
||||
LLKeyframeFallMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeFallMotion();
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLKeyframeFallMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeFallMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@@ -84,38 +84,55 @@ LLKeyframeMotion::JointMotionList::~JointMotionList()
|
||||
for_each(mJointMotionArray.begin(), mJointMotionArray.end(), DeletePointer());
|
||||
}
|
||||
|
||||
U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo()
|
||||
//Singu: add parameter 'silent'.
|
||||
U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo(bool silent) const
|
||||
{
|
||||
S32 total_size = sizeof(JointMotionList);
|
||||
|
||||
for (U32 i = 0; i < getNumJointMotions(); i++)
|
||||
{
|
||||
LLKeyframeMotion::JointMotion* joint_motion_p = mJointMotionArray[i];
|
||||
LLKeyframeMotion::JointMotion const* joint_motion_p = mJointMotionArray[i];
|
||||
|
||||
llinfos << "\tJoint " << joint_motion_p->mJointName << llendl;
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\tJoint " << joint_motion_p->mJointName << llendl;
|
||||
}
|
||||
if (joint_motion_p->mUsage & LLJointState::SCALE)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at "
|
||||
<< joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << llendl;
|
||||
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at "
|
||||
<< joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << llendl;
|
||||
}
|
||||
total_size += joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey);
|
||||
}
|
||||
if (joint_motion_p->mUsage & LLJointState::ROT)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at "
|
||||
<< joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << llendl;
|
||||
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at "
|
||||
<< joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << llendl;
|
||||
}
|
||||
total_size += joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey);
|
||||
}
|
||||
if (joint_motion_p->mUsage & LLJointState::POS)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at "
|
||||
<< joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << llendl;
|
||||
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at "
|
||||
<< joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << llendl;
|
||||
}
|
||||
total_size += joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey);
|
||||
}
|
||||
}
|
||||
llinfos << "Size: " << total_size << " bytes" << llendl;
|
||||
//Singu: Also add memory used by the constraints.
|
||||
S32 constraints_size = mConstraints.size() * sizeof(constraint_list_t::value_type);
|
||||
total_size += constraints_size;
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\t" << mConstraints.size() << " constraints at " << constraints_size << " bytes" << llendl;
|
||||
llinfos << "Size: " << total_size << " bytes" << llendl;
|
||||
}
|
||||
|
||||
return total_size;
|
||||
}
|
||||
@@ -427,9 +444,8 @@ void LLKeyframeMotion::JointMotion::update(LLJointState* joint_state, F32 time,
|
||||
// LLKeyframeMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id)
|
||||
: LLMotion(id),
|
||||
mJointMotionList(NULL),
|
||||
LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id, LLMotionController* controller)
|
||||
: LLMotion(id, controller),
|
||||
mPelvisp(NULL),
|
||||
mLastSkeletonSerialNum(0),
|
||||
mLastUpdateTime(0.f),
|
||||
@@ -452,9 +468,9 @@ LLKeyframeMotion::~LLKeyframeMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
// create()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion *LLKeyframeMotion::create(const LLUUID &id)
|
||||
LLMotion* LLKeyframeMotion::create(LLUUID const& id, LLMotionController* controller)
|
||||
{
|
||||
return new LLKeyframeMotion(id);
|
||||
return new LLKeyframeMotion(id, controller);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -517,6 +533,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact
|
||||
case ASSET_FETCHED:
|
||||
return STATUS_HOLD;
|
||||
case ASSET_FETCH_FAILED:
|
||||
llwarns << "Trying to initialize a motion that failed to be fetched." << llendl;
|
||||
return STATUS_FAILURE;
|
||||
case ASSET_LOADED:
|
||||
return STATUS_SUCCESS;
|
||||
@@ -526,7 +543,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact
|
||||
break;
|
||||
}
|
||||
|
||||
LLKeyframeMotion::JointMotionList* joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID());
|
||||
LLKeyframeMotion::JointMotionListPtr joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID());
|
||||
|
||||
if(joint_motion_list)
|
||||
{
|
||||
@@ -801,7 +818,44 @@ void LLKeyframeMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
// setStopTime()
|
||||
//-----------------------------------------------------------------------------
|
||||
// time is in seconds since character creation
|
||||
//
|
||||
// Consider a looping animation of 20 frames, where the loop in point is at 3 frames
|
||||
// and the loop out point at 16 frames:
|
||||
//
|
||||
// The first 3 frames of the animation would be the "loop in" animation.
|
||||
// The last 4 frames of the animation would be the "loop out" animation.
|
||||
// Frames 4 through 15 would be the looping animation frames.
|
||||
//
|
||||
// If the animation would not be looping, all frames would just be played once sequentially:
|
||||
//
|
||||
// mActivationTimestamp -.
|
||||
// v
|
||||
// 0 3 15 16 20
|
||||
// | | \| |
|
||||
// ---------------------
|
||||
// <--> <-- mLoopInPoint (relative to mActivationTimestamp)
|
||||
// <--------------> <-- mLoopOutPoint (relative to mActivationTimestamp)
|
||||
// <----mDuration------>
|
||||
//
|
||||
// When looping the animation would repeat frames 3 to 16 (loop) a few times, for example:
|
||||
//
|
||||
// 0 3 15 3 15 3 15 3 15 16 20
|
||||
// | | loop 1 \| loop 2 \| loop 3 \| loop 4 \| |
|
||||
// ------------------------------------------------------------
|
||||
//LOOP^ ^ LOOP
|
||||
// IN | <----->| OUT
|
||||
// start_loop_time loop_fraction_time-' time
|
||||
//
|
||||
// The time at which the animation is started corresponds to frame 0 and is stored
|
||||
// in mActivationTimestamp (in seconds since character creation).
|
||||
//
|
||||
// If setStopTime() is called with a time somewhere inside loop 4,
|
||||
// then 'loop_fraction_time' is the time from the beginning of
|
||||
// loop 4 till 'time'. Thus 'time - loop_fraction_time' is the first
|
||||
// frame of loop 4, and '(time - loop_fraction_time) +
|
||||
// (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint)'
|
||||
// would correspond to frame 20.
|
||||
//
|
||||
void LLKeyframeMotion::setStopTime(F32 time)
|
||||
{
|
||||
LLMotion::setStopTime(time);
|
||||
@@ -819,6 +873,8 @@ void LLKeyframeMotion::setStopTime(F32 time)
|
||||
loop_fraction_time = fmod(time - start_loop_time,
|
||||
mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint);
|
||||
}
|
||||
// This sets mStopTimestamp to the time that corresponds to the end of the animation (ie, frame 20 in the above example)
|
||||
// minus the ease out duration, so that the animation eases out during the loop out and finishes exactly at the end.
|
||||
mStopTimestamp = llmax(time,
|
||||
(time - loop_fraction_time) + (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint) - getEaseOutDuration());
|
||||
}
|
||||
@@ -1227,13 +1283,42 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
}
|
||||
}
|
||||
|
||||
// Helper class.
|
||||
template<typename T>
|
||||
struct AIAutoDestruct
|
||||
{
|
||||
T* mPtr;
|
||||
AIAutoDestruct() : mPtr(NULL) { }
|
||||
~AIAutoDestruct() { delete mPtr; }
|
||||
void add(T* ptr) { mPtr = ptr; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// deserialize()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
{
|
||||
BOOL old_version = FALSE;
|
||||
mJointMotionList = new LLKeyframeMotion::JointMotionList;
|
||||
|
||||
//<singu>
|
||||
|
||||
// First add a new LLKeyframeMotion::JointMotionList to the cache, then assign a pointer
|
||||
// to that to mJointMotionList. In LLs code the cache is never deleted again. Now it is
|
||||
// is deleted when the last mJointMotionList pointer is destructed.
|
||||
//
|
||||
// It is possible that we get here for an already added animation, because animations can
|
||||
// be requested multiple times (we get here from LLKeyframeMotion::onLoadComplete) when
|
||||
// the animation was still downloading from a previous request for another LLMotionController
|
||||
// object (avatar). In that case we just overwrite the old data while decoding it again.
|
||||
mJointMotionList = LLKeyframeDataCache::getKeyframeData(getID());
|
||||
bool singu_new_joint_motion_list = !mJointMotionList;
|
||||
if (singu_new_joint_motion_list)
|
||||
{
|
||||
// Create a new JointMotionList.
|
||||
mJointMotionList = LLKeyframeDataCache::createKeyframeData(getID());
|
||||
}
|
||||
|
||||
//</singu>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// get base priority
|
||||
@@ -1396,8 +1481,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mJointMotionList->mJointMotionArray.clear();
|
||||
mJointMotionList->mJointMotionArray.reserve(num_motions);
|
||||
if (singu_new_joint_motion_list)
|
||||
{
|
||||
mJointMotionList->mJointMotionArray.reserve(num_motions);
|
||||
}
|
||||
mJointStates.clear();
|
||||
mJointStates.reserve(num_motions);
|
||||
|
||||
@@ -1407,8 +1494,19 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
|
||||
for(U32 i=0; i<num_motions; ++i)
|
||||
{
|
||||
AIAutoDestruct<JointMotion> watcher;
|
||||
|
||||
JointMotion* joint_motion = new JointMotion;
|
||||
mJointMotionList->mJointMotionArray.push_back(joint_motion);
|
||||
if (singu_new_joint_motion_list)
|
||||
{
|
||||
// Pass ownership to mJointMotionList.
|
||||
mJointMotionList->mJointMotionArray.push_back(joint_motion);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just delete this at the end.
|
||||
watcher.add(joint_motion);
|
||||
}
|
||||
|
||||
std::string joint_name;
|
||||
if (!dp.unpackString(joint_name, "joint_name"))
|
||||
@@ -1836,7 +1934,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mJointMotionList->mConstraints.push_front(constraintp);
|
||||
AIAutoDestruct<JointConstraintSharedData> watcher;
|
||||
if (singu_new_joint_motion_list)
|
||||
{
|
||||
mJointMotionList->mConstraints.push_front(constraintp);
|
||||
}
|
||||
else
|
||||
{
|
||||
watcher.add(constraintp);
|
||||
}
|
||||
|
||||
constraintp->mJointStateIndices = new S32[constraintp->mChainLength + 1]; // note: mChainLength is size-limited - comes from a byte
|
||||
|
||||
@@ -1876,15 +1982,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
if (constraintp->mJointStateIndices[i] < 0 )
|
||||
{
|
||||
llwarns << "No joint index for constraint " << i << llendl;
|
||||
delete constraintp;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *FIX: support cleanup of old keyframe data
|
||||
LLKeyframeDataCache::addKeyframeData(getID(), mJointMotionList);
|
||||
mAssetStatus = ASSET_LOADED;
|
||||
|
||||
setupPose();
|
||||
@@ -2226,16 +2329,24 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs,
|
||||
//--------------------------------------------------------------------
|
||||
// LLKeyframeDataCache::dumpDiagInfo()
|
||||
//--------------------------------------------------------------------
|
||||
void LLKeyframeDataCache::dumpDiagInfo()
|
||||
// <singu>
|
||||
// quiet = 0 : print everything in detail.
|
||||
// 1 : print the UUIDs of all animations in the cache and the total memory usage.
|
||||
// 2 : only print the total memory usage.
|
||||
// </singu>
|
||||
void LLKeyframeDataCache::dumpDiagInfo(int quiet)
|
||||
{
|
||||
// keep track of totals
|
||||
U32 total_size = 0;
|
||||
|
||||
char buf[1024]; /* Flawfinder: ignore */
|
||||
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
llinfos << " Global Motion Table (DEBUG only)" << llendl;
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
if (quiet < 2)
|
||||
{
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
llinfos << " Global Motion Table" << llendl;
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
}
|
||||
|
||||
// print each loaded mesh, and it's memory usage
|
||||
for (keyframe_data_map_t::iterator map_it = sKeyframeDataMap.begin();
|
||||
@@ -2243,30 +2354,46 @@ void LLKeyframeDataCache::dumpDiagInfo()
|
||||
{
|
||||
U32 joint_motion_kb;
|
||||
|
||||
LLKeyframeMotion::JointMotionList *motion_list_p = map_it->second;
|
||||
LLKeyframeMotion::JointMotionList const* motion_list_p = map_it->get();
|
||||
|
||||
llinfos << "Motion: " << map_it->first << llendl;
|
||||
if (quiet < 2)
|
||||
{
|
||||
llinfos << "Motion: " << map_it->key() << llendl;
|
||||
}
|
||||
|
||||
joint_motion_kb = motion_list_p->dumpDiagInfo();
|
||||
|
||||
total_size += joint_motion_kb;
|
||||
if (motion_list_p)
|
||||
{
|
||||
joint_motion_kb = motion_list_p->dumpDiagInfo(quiet);
|
||||
total_size += joint_motion_kb;
|
||||
}
|
||||
}
|
||||
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
if (quiet < 2)
|
||||
{
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
}
|
||||
llinfos << "Motions\tTotal Size" << llendl;
|
||||
snprintf(buf, sizeof(buf), "%d\t\t%d bytes", (S32)sKeyframeDataMap.size(), total_size ); /* Flawfinder: ignore */
|
||||
llinfos << buf << llendl;
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
if (quiet < 2)
|
||||
{
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLKeyframeDataCache::addKeyframeData()
|
||||
// LLKeyframeDataCache::createKeyframeData()
|
||||
//--------------------------------------------------------------------
|
||||
void LLKeyframeDataCache::addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList* joint_motion_listp)
|
||||
//<singu> This function replaces LLKeyframeDataCache::addKeyframeData and was rewritten to fix a memory leak (aka, the usage of AICachedPointer).
|
||||
LLKeyframeMotion::JointMotionListPtr LLKeyframeDataCache::createKeyframeData(LLUUID const& id)
|
||||
{
|
||||
sKeyframeDataMap[id] = joint_motion_listp;
|
||||
std::pair<keyframe_data_map_t::iterator, bool> result =
|
||||
sKeyframeDataMap.insert(AICachedPointer<LLUUID, LLKeyframeMotion::JointMotionList>(id, new LLKeyframeMotion::JointMotionList, &sKeyframeDataMap));
|
||||
llassert(result.second); // id may not already exist in the cache.
|
||||
return &*result.first; // Construct and return a JointMotionListPt from a pointer to the actually inserted AICachedPointer.
|
||||
}
|
||||
//</singu>
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLKeyframeDataCache::removeKeyframeData()
|
||||
@@ -2276,7 +2403,6 @@ void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id)
|
||||
keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id);
|
||||
if (found_data != sKeyframeDataMap.end())
|
||||
{
|
||||
delete found_data->second;
|
||||
sKeyframeDataMap.erase(found_data);
|
||||
}
|
||||
}
|
||||
@@ -2284,14 +2410,14 @@ void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id)
|
||||
//--------------------------------------------------------------------
|
||||
// LLKeyframeDataCache::getKeyframeData()
|
||||
//--------------------------------------------------------------------
|
||||
LLKeyframeMotion::JointMotionList* LLKeyframeDataCache::getKeyframeData(const LLUUID& id)
|
||||
LLKeyframeMotion::JointMotionListPtr LLKeyframeDataCache::getKeyframeData(const LLUUID& id)
|
||||
{
|
||||
keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id);
|
||||
if (found_data == sKeyframeDataMap.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return found_data->second;
|
||||
return &*found_data; // Construct and return a JointMotionListPt from a pointer to the found AICachedPointer.
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
@@ -2307,7 +2433,6 @@ LLKeyframeDataCache::~LLKeyframeDataCache()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLKeyframeDataCache::clear()
|
||||
{
|
||||
for_each(sKeyframeDataMap.begin(), sKeyframeDataMap.end(), DeletePairedPointer());
|
||||
sKeyframeDataMap.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
* AICachedPointer and AICachedPointPtr copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
@@ -48,10 +49,12 @@
|
||||
#include "v3dmath.h"
|
||||
#include "v3math.h"
|
||||
#include "llbvhconsts.h"
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
class LLKeyframeDataCache;
|
||||
class LLVFS;
|
||||
class LLDataPacker;
|
||||
class LLMotionController;
|
||||
|
||||
#define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f)
|
||||
#define MAX_CHAIN_LENGTH (4)
|
||||
@@ -59,6 +62,112 @@ class LLDataPacker;
|
||||
const S32 KEYFRAME_MOTION_VERSION = 1;
|
||||
const S32 KEYFRAME_MOTION_SUBVERSION = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <singu>
|
||||
|
||||
template<typename KEY, typename T>
|
||||
class AICachedPointer;
|
||||
|
||||
template<typename KEY, typename T>
|
||||
void intrusive_ptr_add_ref(AICachedPointer<KEY, T> const* p);
|
||||
|
||||
template<typename KEY, typename T>
|
||||
void intrusive_ptr_release(AICachedPointer<KEY, T> const* p);
|
||||
|
||||
template<typename KEY, typename T>
|
||||
class AICachedPointer
|
||||
{
|
||||
public:
|
||||
typedef std::set<AICachedPointer<KEY, T> > container_type;
|
||||
|
||||
private:
|
||||
KEY mKey; // The unique key.
|
||||
LLPointer<T> mData; // The actual data pointer.
|
||||
container_type* mCache; // Pointer to the underlaying cache.
|
||||
mutable int mRefCount; // Number of AICachedPointerPtr's pointing to this object.
|
||||
|
||||
public:
|
||||
// Construct a NULL pointer. This is needed when adding a new entry to a std::set, it is always first default constructed.
|
||||
AICachedPointer(void) : mCache(NULL) { }
|
||||
|
||||
// Copy constructor. This is needed to replace the std::set inserted instance with its actual value.
|
||||
AICachedPointer(AICachedPointer const& cptr) : mKey(cptr.mKey), mData(cptr.mData), mCache(cptr.mCache), mRefCount(0) { }
|
||||
|
||||
// Construct a AICachedPointer that points to 'ptr' with key 'key'.
|
||||
AICachedPointer(KEY const& key, T* ptr, container_type* cache) : mKey(key), mData(ptr), mCache(cache), mRefCount(-1) { }
|
||||
|
||||
// Construct a temporary NULL pointer that can be used in a search for a key.
|
||||
AICachedPointer(KEY const& key) : mKey(key), mCache(NULL) { }
|
||||
|
||||
// Accessors for key and data.
|
||||
KEY const& key(void) const { return mKey; }
|
||||
T const* get(void) const { return mData.get(); }
|
||||
T* get(void) { return mData.get(); }
|
||||
|
||||
// Order only by key.
|
||||
friend bool operator<(AICachedPointer const& cp1, AICachedPointer const& cp2) { return cp1.mKey < cp2.mKey; }
|
||||
|
||||
private:
|
||||
friend void intrusive_ptr_add_ref<>(AICachedPointer<KEY, T> const* p);
|
||||
friend void intrusive_ptr_release<>(AICachedPointer<KEY, T> const* p);
|
||||
|
||||
private:
|
||||
AICachedPointer& operator=(AICachedPointer const&);
|
||||
};
|
||||
|
||||
template<typename KEY, typename T>
|
||||
void intrusive_ptr_add_ref(AICachedPointer<KEY, T> const* p)
|
||||
{
|
||||
llassert(p->mCache);
|
||||
if (p->mCache)
|
||||
{
|
||||
p->mRefCount++;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename KEY, typename T>
|
||||
void intrusive_ptr_release(AICachedPointer<KEY, T> const* p)
|
||||
{
|
||||
llassert(p->mCache);
|
||||
if (p->mCache)
|
||||
{
|
||||
if (--p->mRefCount == 0)
|
||||
{
|
||||
p->mCache->erase(p->mKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename KEY, typename T>
|
||||
class AICachedPointerPtr
|
||||
{
|
||||
private:
|
||||
boost::intrusive_ptr<AICachedPointer<KEY, T> const> mPtr;
|
||||
static int sCnt;
|
||||
|
||||
public:
|
||||
AICachedPointerPtr(void) { ++sCnt; }
|
||||
AICachedPointerPtr(AICachedPointerPtr const& cpp) : mPtr(cpp.mPtr) { ++sCnt; }
|
||||
AICachedPointerPtr(AICachedPointer<KEY, T> const* cp) : mPtr(cp) { ++sCnt; }
|
||||
~AICachedPointerPtr() { --sCnt; }
|
||||
|
||||
typedef boost::intrusive_ptr<AICachedPointer<KEY, T> const> const AICachedPointerPtr<KEY, T>::* const bool_type;
|
||||
operator bool_type() const { return mPtr ? &AICachedPointerPtr<KEY, T>::mPtr : NULL; }
|
||||
|
||||
T const* operator->() const { return mPtr->get(); }
|
||||
T* operator->() { return const_cast<AICachedPointer<KEY, T>&>(*mPtr).get(); }
|
||||
T const& operator*() const { return *mPtr->get(); }
|
||||
T& operator*() { return *const_cast<AICachedPointer<KEY, T>&>(*mPtr).get(); }
|
||||
|
||||
AICachedPointerPtr& operator=(AICachedPointerPtr const& cpp) { mPtr = cpp.mPtr; return *this; }
|
||||
};
|
||||
|
||||
template<typename KEY, typename T>
|
||||
int AICachedPointerPtr<KEY, T>::sCnt;
|
||||
|
||||
// </singu>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLKeyframeMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -68,7 +177,7 @@ class LLKeyframeMotion :
|
||||
friend class LLKeyframeDataCache;
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeMotion(const LLUUID &id);
|
||||
LLKeyframeMotion(const LLUUID &id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeMotion();
|
||||
@@ -85,7 +194,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID& id);
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -158,7 +267,7 @@ public:
|
||||
U32 getFileSize();
|
||||
BOOL serialize(LLDataPacker& dp) const;
|
||||
BOOL deserialize(LLDataPacker& dp);
|
||||
BOOL isLoaded() { return mJointMotionList != NULL; }
|
||||
BOOL isLoaded() { return !!mJointMotionList; }
|
||||
|
||||
|
||||
// setters for modifying a keyframe animation
|
||||
@@ -393,7 +502,7 @@ public:
|
||||
//-------------------------------------------------------------------------
|
||||
// JointMotionList
|
||||
//-------------------------------------------------------------------------
|
||||
class JointMotionList
|
||||
class JointMotionList : public LLRefCount
|
||||
{
|
||||
public:
|
||||
std::vector<JointMotion*> mJointMotionArray;
|
||||
@@ -416,19 +525,22 @@ public:
|
||||
public:
|
||||
JointMotionList();
|
||||
~JointMotionList();
|
||||
U32 dumpDiagInfo();
|
||||
U32 dumpDiagInfo(bool silent = false) const;
|
||||
JointMotion* getJointMotion(U32 index) const { llassert(index < mJointMotionArray.size()); return mJointMotionArray[index]; }
|
||||
U32 getNumJointMotions() const { return mJointMotionArray.size(); }
|
||||
};
|
||||
|
||||
|
||||
// Singu: Type of a pointer to the cached pointer (in LLKeyframeDataCache::sKeyframeDataMap) to a JointMotionList object.
|
||||
typedef AICachedPointerPtr<LLUUID, JointMotionList> JointMotionListPtr;
|
||||
|
||||
protected:
|
||||
static LLVFS* sVFS;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Member Data
|
||||
//-------------------------------------------------------------------------
|
||||
JointMotionList* mJointMotionList;
|
||||
JointMotionListPtr mJointMotionList; // singu: automatically clean up cache entry when destructed.
|
||||
std::vector<LLPointer<LLJointState> > mJointStates;
|
||||
LLJoint* mPelvisp;
|
||||
LLCharacter* mCharacter;
|
||||
@@ -442,21 +554,24 @@ protected:
|
||||
|
||||
class LLKeyframeDataCache
|
||||
{
|
||||
public:
|
||||
// *FIX: implement this as an actual singleton member of LLKeyframeMotion
|
||||
private:
|
||||
friend class LLKeyframeMotion;
|
||||
LLKeyframeDataCache(){};
|
||||
~LLKeyframeDataCache();
|
||||
|
||||
typedef std::map<LLUUID, class LLKeyframeMotion::JointMotionList*> keyframe_data_map_t;
|
||||
public:
|
||||
typedef AICachedPointer<LLUUID, LLKeyframeMotion::JointMotionList>::container_type keyframe_data_map_t; // singu: add automatic cache cleanup.
|
||||
static keyframe_data_map_t sKeyframeDataMap;
|
||||
|
||||
static void addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList*);
|
||||
static LLKeyframeMotion::JointMotionList* getKeyframeData(const LLUUID& id);
|
||||
//<singu>
|
||||
static LLKeyframeMotion::JointMotionListPtr createKeyframeData(LLUUID const& id); // id may not exist.
|
||||
static LLKeyframeMotion::JointMotionListPtr getKeyframeData(LLUUID const& id); // id may or may not exists. Returns a NULL pointer when it doesn't exist.
|
||||
//</singu>
|
||||
|
||||
static void removeKeyframeData(const LLUUID& id);
|
||||
|
||||
//print out diagnostic info
|
||||
static void dumpDiagInfo();
|
||||
static void dumpDiagInfo(int quiet = 0); // singu: added param 'quiet'.
|
||||
static void clear();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,456 +0,0 @@
|
||||
/**
|
||||
* @file llkeyframemotionparam.cpp
|
||||
* @brief Implementation of LLKeyframeMotion class.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llkeyframemotionparam.h"
|
||||
#include "llcharacter.h"
|
||||
#include "llmath.h"
|
||||
#include "m3math.h"
|
||||
#include "lldir.h"
|
||||
#include "llanimationstates.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam class
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id)
|
||||
{
|
||||
mDefaultKeyframeMotion = NULL;
|
||||
mCharacter = NULL;
|
||||
|
||||
mEaseInDuration = 0.f;
|
||||
mEaseOutDuration = 0.f;
|
||||
mDuration = 0.f;
|
||||
mPriority = LLJoint::LOW_PRIORITY;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLKeyframeMotionParam()
|
||||
// Class Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeMotionParam::~LLKeyframeMotionParam()
|
||||
{
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
delete paramMotion.mMotion;
|
||||
}
|
||||
motionList.clear();
|
||||
}
|
||||
mParameterizedMotions.clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::onInitialize(LLCharacter *character)
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character)
|
||||
{
|
||||
mCharacter = character;
|
||||
|
||||
if (!loadMotions())
|
||||
{
|
||||
return STATUS_FAILURE;
|
||||
}
|
||||
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
LLMotion* motion = paramMotion.mMotion;
|
||||
motion->onInitialize(character);
|
||||
|
||||
if (motion->getDuration() > mEaseInDuration)
|
||||
{
|
||||
mEaseInDuration = motion->getEaseInDuration();
|
||||
}
|
||||
|
||||
if (motion->getEaseOutDuration() > mEaseOutDuration)
|
||||
{
|
||||
mEaseOutDuration = motion->getEaseOutDuration();
|
||||
}
|
||||
|
||||
if (motion->getDuration() > mDuration)
|
||||
{
|
||||
mDuration = motion->getDuration();
|
||||
}
|
||||
|
||||
if (motion->getPriority() > mPriority)
|
||||
{
|
||||
mPriority = motion->getPriority();
|
||||
}
|
||||
|
||||
LLPose *pose = motion->getPose();
|
||||
|
||||
mPoseBlender.addMotion(motion);
|
||||
for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState())
|
||||
{
|
||||
LLPose *blendedPose = mPoseBlender.getBlendedPose();
|
||||
blendedPose->addJointState(jsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::onActivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotionParam::onActivate()
|
||||
{
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
paramMotion.mMotion->activate(mActivationTimestamp);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::onUpdate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
F32 weightFactor = 1.f / (F32)mParameterizedMotions.size();
|
||||
|
||||
// zero out all pose weights
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
// llinfos << "Weight for pose " << paramMotion.mMotion->getName() << " is " << paramMotion.mMotion->getPose()->getWeight() << llendl;
|
||||
paramMotion.mMotion->getPose()->setWeight(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
const std::string& paramName = iter->first;
|
||||
F32* paramValue = (F32 *)mCharacter->getAnimationData(paramName);
|
||||
if (NULL == paramValue) // unexpected, but...
|
||||
{
|
||||
llwarns << "paramValue == NULL" << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// DANGER! Do not modify mParameterizedMotions while using these pointers!
|
||||
const ParameterizedMotion* firstMotion = NULL;
|
||||
const ParameterizedMotion* secondMotion = NULL;
|
||||
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
paramMotion.mMotion->onUpdate(time, joint_mask);
|
||||
|
||||
F32 distToParam = paramMotion.mParam - *paramValue;
|
||||
|
||||
if ( distToParam <= 0.f)
|
||||
{
|
||||
// keep track of the motion closest to the parameter value
|
||||
firstMotion = ¶mMotion;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we've passed the parameter value
|
||||
// so store the first motion we find as the second one we want to blend...
|
||||
if (firstMotion && !secondMotion )
|
||||
{
|
||||
secondMotion = ¶mMotion;
|
||||
}
|
||||
//...or, if we've seen no other motion so far, make sure we blend to this only
|
||||
else if (!firstMotion)
|
||||
{
|
||||
firstMotion = ¶mMotion;
|
||||
secondMotion = ¶mMotion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLPose *firstPose;
|
||||
LLPose *secondPose;
|
||||
|
||||
if (firstMotion)
|
||||
firstPose = firstMotion->mMotion->getPose();
|
||||
else
|
||||
firstPose = NULL;
|
||||
|
||||
if (secondMotion)
|
||||
secondPose = secondMotion->mMotion->getPose();
|
||||
else
|
||||
secondPose = NULL;
|
||||
|
||||
// now modify weight of the subanim (only if we are blending between two motions)
|
||||
if (firstMotion && secondMotion)
|
||||
{
|
||||
if (firstMotion == secondMotion)
|
||||
{
|
||||
firstPose->setWeight(weightFactor);
|
||||
}
|
||||
else if (firstMotion->mParam == secondMotion->mParam)
|
||||
{
|
||||
firstPose->setWeight(0.5f * weightFactor);
|
||||
secondPose->setWeight(0.5f * weightFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 first_weight = 1.f -
|
||||
((llclamp(*paramValue - firstMotion->mParam, 0.f, (secondMotion->mParam - firstMotion->mParam))) /
|
||||
(secondMotion->mParam - firstMotion->mParam));
|
||||
first_weight = llclamp(first_weight, 0.f, 1.f);
|
||||
|
||||
F32 second_weight = 1.f - first_weight;
|
||||
|
||||
firstPose->setWeight(first_weight * weightFactor);
|
||||
secondPose->setWeight(second_weight * weightFactor);
|
||||
|
||||
// llinfos << "Parameter " << *paramName << ": " << *paramValue << llendl;
|
||||
// llinfos << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << llendl;
|
||||
}
|
||||
}
|
||||
else if (firstMotion && !secondMotion)
|
||||
{
|
||||
firstPose->setWeight(weightFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// blend poses
|
||||
mPoseBlender.blendAndApply();
|
||||
|
||||
llinfos << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << llendl;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLKeyframeMotionParam::onDeactivate()
|
||||
{
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
paramMotion.mMotion->onDeactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::addKeyframeMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value)
|
||||
{
|
||||
LLMotion *newMotion = mCharacter->createMotion( id );
|
||||
|
||||
if (!newMotion)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
newMotion->setName(name);
|
||||
|
||||
// now add motion to this list
|
||||
mParameterizedMotions[param].insert(ParameterizedMotion(newMotion, value));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::setDefaultKeyframeMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name)
|
||||
{
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
if (paramMotion.mMotion->getName() == name)
|
||||
{
|
||||
mDefaultKeyframeMotion = paramMotion.mMotion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// loadMotions()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotionParam::loadMotions()
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// Load named file by concatenating the character prefix with the motion name.
|
||||
// Load data into a buffer to be parsed.
|
||||
//-------------------------------------------------------------------------
|
||||
//std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix())
|
||||
// + "_" + getName() + ".llp";
|
||||
//RN: deprecated unused reference to "motion" directory
|
||||
std::string path;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// open the file
|
||||
//-------------------------------------------------------------------------
|
||||
S32 fileSize = 0;
|
||||
LLAPRFile infile(path, LL_APR_R, &fileSize);
|
||||
apr_file_t* fp = infile.getFileHandle() ;
|
||||
if (!fp || fileSize == 0)
|
||||
{
|
||||
llinfos << "ERROR: can't open: " << path << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// allocate a text buffer
|
||||
try
|
||||
{
|
||||
std::vector<char> text(fileSize+1);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// load data from file into buffer
|
||||
//-------------------------------------------------------------------------
|
||||
bool error = false;
|
||||
char *p = &text[0];
|
||||
while ( 1 )
|
||||
{
|
||||
if (apr_file_eof(fp) == APR_EOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (apr_file_gets(p, 1024, fp) != APR_SUCCESS)
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
while ( *(++p) )
|
||||
;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// close the file
|
||||
//-------------------------------------------------------------------------
|
||||
infile.close();
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// check for error
|
||||
//-------------------------------------------------------------------------
|
||||
llassert( p <= (&text[0] + fileSize) );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
llinfos << "ERROR: error while reading from " << path << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
llinfos << "Loading parametric keyframe data for: " << getName() << llendl;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// parse the text and build keyframe data structures
|
||||
//-------------------------------------------------------------------------
|
||||
p = &text[0];
|
||||
S32 num;
|
||||
char strA[80]; /* Flawfinder: ignore */
|
||||
char strB[80]; /* Flawfinder: ignore */
|
||||
F32 floatA = 0.0f;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// get priority
|
||||
//-------------------------------------------------------------------------
|
||||
BOOL isFirstMotion = TRUE;
|
||||
num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (num == 0 || num == EOF) break;
|
||||
if ((num != 3))
|
||||
{
|
||||
llinfos << "WARNING: can't read parametric motion" << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(std::string(strA)), strB, floatA);
|
||||
if (isFirstMotion)
|
||||
{
|
||||
isFirstMotion = FALSE;
|
||||
setDefaultKeyframeMotion(strA);
|
||||
}
|
||||
|
||||
p = strstr(p, "\n");
|
||||
if (!p)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p++;
|
||||
num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
catch(std::bad_alloc)
|
||||
{
|
||||
llinfos << "ERROR: Unable to allocate keyframe text buffer." << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// End
|
||||
@@ -1,176 +0,0 @@
|
||||
/**
|
||||
* @file llkeyframemotionparam.h
|
||||
* @brief Implementation of LLKeframeMotionParam class.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLKEYFRAMEMOTIONPARAM_H
|
||||
#define LL_LLKEYFRAMEMOTIONPARAM_H
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header files
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "llmotion.h"
|
||||
#include "lljointstate.h"
|
||||
#include "v3math.h"
|
||||
#include "llquaternion.h"
|
||||
#include "linked_lists.h"
|
||||
#include "llkeyframemotion.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLKeyframeMotionParam
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLKeyframeMotionParam :
|
||||
public LLMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeMotionParam(const LLUUID &id);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeMotionParam();
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// functions to support MotionController and MotionRegistry
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLKeyframeMotionParam(id); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// animation callbacks to be implemented by subclasses
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// motions must specify whether or not they loop
|
||||
virtual BOOL getLoop() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// motions must report their total duration
|
||||
virtual F32 getDuration() {
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
// motions must report their "ease in" duration
|
||||
virtual F32 getEaseInDuration() {
|
||||
return mEaseInDuration;
|
||||
}
|
||||
|
||||
// motions must report their "ease out" duration.
|
||||
virtual F32 getEaseOutDuration() {
|
||||
return mEaseOutDuration;
|
||||
}
|
||||
|
||||
// motions must report their priority
|
||||
virtual LLJoint::JointPriority getPriority() {
|
||||
return mPriority;
|
||||
}
|
||||
|
||||
virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
|
||||
|
||||
// called to determine when a motion should be activated/deactivated based on avatar pixel coverage
|
||||
virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; }
|
||||
|
||||
// run-time (post constructor) initialization,
|
||||
// called after parameters have been set
|
||||
// must return true to indicate success and be available for activation
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
|
||||
// called when a motion is activated
|
||||
// must return TRUE to indicate success, or else
|
||||
// it will be deactivated
|
||||
virtual BOOL onActivate();
|
||||
|
||||
// called per time step
|
||||
// must return TRUE while it is active, and
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
virtual LLPose* getPose() { return mPoseBlender.getBlendedPose();}
|
||||
|
||||
protected:
|
||||
//-------------------------------------------------------------------------
|
||||
// new functions defined by this subclass
|
||||
//-------------------------------------------------------------------------
|
||||
struct ParameterizedMotion
|
||||
{
|
||||
ParameterizedMotion(LLMotion* motion, F32 param) : mMotion(motion), mParam(param) {}
|
||||
LLMotion* mMotion;
|
||||
F32 mParam;
|
||||
};
|
||||
|
||||
// add a motion and associated parameter triplet
|
||||
BOOL addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value);
|
||||
|
||||
// set default motion for LOD and retrieving blend constants
|
||||
void setDefaultKeyframeMotion(char *);
|
||||
|
||||
BOOL loadMotions();
|
||||
|
||||
protected:
|
||||
//-------------------------------------------------------------------------
|
||||
// Member Data
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
struct compare_motions
|
||||
{
|
||||
bool operator() (const ParameterizedMotion& a, const ParameterizedMotion& b) const
|
||||
{
|
||||
if (a.mParam != b.mParam)
|
||||
return (a.mParam < b.mParam);
|
||||
else
|
||||
return a.mMotion < b.mMotion;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::set < ParameterizedMotion, compare_motions > motion_list_t;
|
||||
typedef std::map <std::string, motion_list_t > motion_map_t;
|
||||
motion_map_t mParameterizedMotions;
|
||||
LLMotion* mDefaultKeyframeMotion;
|
||||
LLCharacter* mCharacter;
|
||||
LLPoseBlender mPoseBlender;
|
||||
|
||||
F32 mEaseInDuration;
|
||||
F32 mEaseOutDuration;
|
||||
F32 mDuration;
|
||||
LLJoint::JointPriority mPriority;
|
||||
|
||||
LLUUID mTransactionID;
|
||||
};
|
||||
|
||||
#endif // LL_LLKEYFRAMEMOTIONPARAM_H
|
||||
@@ -50,7 +50,7 @@ const F32 POSITION_THRESHOLD = 0.1f;
|
||||
// LLKeyframeStandMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeStandMotion::LLKeyframeStandMotion(const LLUUID &id) : LLKeyframeMotion(id)
|
||||
LLKeyframeStandMotion::LLKeyframeStandMotion(LLUUID const& id, LLMotionController* controller) : LLKeyframeMotion(id, controller)
|
||||
{
|
||||
mFlipFeet = FALSE;
|
||||
mCharacter = NULL;
|
||||
|
||||
@@ -48,7 +48,7 @@ class LLKeyframeStandMotion :
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeStandMotion(const LLUUID &id);
|
||||
LLKeyframeStandMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeStandMotion();
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLKeyframeStandMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeStandMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@@ -55,8 +55,8 @@ const F32 SPEED_ADJUST_TIME_CONSTANT = 0.1f; // time constant for speed adjustm
|
||||
// LLKeyframeWalkMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id)
|
||||
: LLKeyframeMotion(id),
|
||||
LLKeyframeWalkMotion::LLKeyframeWalkMotion(LLUUID const& id, LLMotionController* controller)
|
||||
: LLKeyframeMotion(id, controller),
|
||||
mCharacter(NULL),
|
||||
mCyclePhase(0.0f),
|
||||
mRealTimeLast(0.0f),
|
||||
@@ -138,8 +138,8 @@ BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
// LLWalkAdjustMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) :
|
||||
LLMotion(id),
|
||||
LLWalkAdjustMotion::LLWalkAdjustMotion(LLUUID const& id, LLMotionController* controller) :
|
||||
AIMaskedMotion(id, controller, ANIM_AGENT_WALK_ADJUST),
|
||||
mLastTime(0.f),
|
||||
mAnimSpeed(0.f),
|
||||
mAdjustedSpeed(0.f),
|
||||
@@ -193,7 +193,7 @@ BOOL LLWalkAdjustMotion::onActivate()
|
||||
F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
|
||||
mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset);
|
||||
|
||||
return TRUE;
|
||||
return AIMaskedMotion::onActivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -325,13 +325,14 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
void LLWalkAdjustMotion::onDeactivate()
|
||||
{
|
||||
mCharacter->removeAnimationData("Walk Speed");
|
||||
AIMaskedMotion::onDeactivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLFlyAdjustMotion::LLFlyAdjustMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLFlyAdjustMotion::LLFlyAdjustMotion(const LLUUID &id)
|
||||
: LLMotion(id),
|
||||
LLFlyAdjustMotion::LLFlyAdjustMotion(LLUUID const& id, LLMotionController* controller)
|
||||
: AIMaskedMotion(id, controller, ANIM_AGENT_FLY_ADJUST),
|
||||
mRoll(0.f)
|
||||
{
|
||||
mName = "fly_adjust";
|
||||
@@ -368,7 +369,7 @@ BOOL LLFlyAdjustMotion::onActivate()
|
||||
mPelvisState->setPosition(LLVector3::zero);
|
||||
mPelvisState->setRotation(LLQuaternion::DEFAULT);
|
||||
mRoll = 0.f;
|
||||
return TRUE;
|
||||
return AIMaskedMotion::onActivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -52,7 +52,7 @@ class LLKeyframeWalkMotion :
|
||||
friend class LLWalkAdjustMotion;
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeWalkMotion(const LLUUID &id);
|
||||
LLKeyframeWalkMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeWalkMotion();
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLKeyframeWalkMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeWalkMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -86,11 +86,11 @@ public:
|
||||
S32 mDownFoot;
|
||||
};
|
||||
|
||||
class LLWalkAdjustMotion : public LLMotion
|
||||
class LLWalkAdjustMotion : public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLWalkAdjustMotion(const LLUUID &id);
|
||||
LLWalkAdjustMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLWalkAdjustMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLWalkAdjustMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -136,11 +136,11 @@ public:
|
||||
F32 mAnkleOffset;
|
||||
};
|
||||
|
||||
class LLFlyAdjustMotion : public LLMotion
|
||||
class LLFlyAdjustMotion : public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLFlyAdjustMotion(const LLUUID &id);
|
||||
LLFlyAdjustMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -149,7 +149,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLFlyAdjustMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLFlyAdjustMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -157,7 +157,6 @@ public:
|
||||
//-------------------------------------------------------------------------
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
virtual BOOL onActivate();
|
||||
virtual void onDeactivate() {};
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGHER_PRIORITY;}
|
||||
virtual BOOL getLoop() { return TRUE; }
|
||||
|
||||
@@ -37,6 +37,125 @@
|
||||
|
||||
#include "llmotion.h"
|
||||
#include "llcriticaldamp.h"
|
||||
#include "llmotioncontroller.h"
|
||||
|
||||
//<singu>
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// AISyncClientMotion class
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
AISyncKey* AISyncClientMotion::createSyncKey(AISyncKey const* from_key) const
|
||||
{
|
||||
// The const cast is needed because getDuration() is non-const while it should have been.
|
||||
AISyncClientMotion* self = const_cast<AISyncClientMotion*>(this);
|
||||
// Only synchronize motions with the same duration and loop value.
|
||||
return new AISyncKeyMotion(from_key, self->getDuration(), self->getLoop());
|
||||
}
|
||||
|
||||
void AISyncClientMotion::aisync_loading(void)
|
||||
{
|
||||
// Register the motion for (possible) synchronization: this marks the time at which is should have started.
|
||||
unregister_client(); // In case it is already registered. Getting here means we are being (re)started now, we need to synchronize with other motions that start now.
|
||||
register_client();
|
||||
}
|
||||
|
||||
void AISyncClientMotion::aisync_loaded(void)
|
||||
{
|
||||
AISyncServer* server = this->server();
|
||||
if (!server)
|
||||
{
|
||||
// Already expired without being synchronized (no other motion was started at the same time).
|
||||
return;
|
||||
}
|
||||
AISyncKey const& key = server->key(); // The allocation of this is owned by server.
|
||||
// There is no need to resync if there was not another motion started at the same time and the key already expired.
|
||||
bool need_resync = !(server->never_synced() && key.expired());
|
||||
AISyncKey* new_key = NULL;
|
||||
if (need_resync)
|
||||
{
|
||||
// Create a new key using the old start time.
|
||||
new_key = createSyncKey(&key);
|
||||
}
|
||||
server->remove(this); // This resets mServer and might even delete server.
|
||||
if (need_resync)
|
||||
{
|
||||
// Add the client to another server (based on the new key). This takes ownership of the key allocation.
|
||||
AISyncServerMap::instance().register_client(this, new_key);
|
||||
}
|
||||
}
|
||||
|
||||
F32 LLMotion::getRuntime(void) const
|
||||
{
|
||||
llassert(mActive);
|
||||
return mController->getAnimTime() - mActivationTimestamp;
|
||||
}
|
||||
|
||||
F32 LLMotion::getAnimTime(void) const
|
||||
{
|
||||
return mController->getAnimTime();
|
||||
}
|
||||
|
||||
F32 LLMotion::syncActivationTime(F32 time)
|
||||
{
|
||||
AISyncServer* server = this->server();
|
||||
if (!server)
|
||||
{
|
||||
register_client();
|
||||
server = this->server();
|
||||
}
|
||||
AISyncServer::client_list_t const& clients = server->getClients();
|
||||
if (clients.size() > 1)
|
||||
{
|
||||
// Look for the client with the smallest runtime.
|
||||
AISyncClientMotion* motion_with_smallest_runtime = NULL;
|
||||
F32 runtime = 1e10;
|
||||
// Run over all motions in this to be synchronized group.
|
||||
for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client)
|
||||
{
|
||||
if ((client->mReadyEvents & 2)) // Is this motion active? Motions that aren't loaded yet are not active.
|
||||
{
|
||||
// Currently, if event 2 is set then this is an LLMotion.
|
||||
llassert(dynamic_cast<AISyncClientMotion*>(client->mClientPtr));
|
||||
AISyncClientMotion* motion = static_cast<AISyncClientMotion*>(client->mClientPtr);
|
||||
// Deactivated motions should have been deregistered, certainly not have event 2 set.
|
||||
llassert(static_cast<LLMotion*>(motion)->isActive());
|
||||
if (motion->getRuntime() < runtime)
|
||||
{
|
||||
// This is a bit fuzzy since theoretically the runtime of all active motions in the list should be the same.
|
||||
// Just use the smallest value to get rid of some randomness. We might even synchronizing with ourselves
|
||||
// in which case 'time' would be set to a value such that mActivationTimestamp won't change.
|
||||
// In practise however, this list will contain only two clients: this, being inactive, and our partner.
|
||||
runtime = motion->getRuntime();
|
||||
motion_with_smallest_runtime = motion;
|
||||
}
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Here is where the actual synchronization takes place.
|
||||
// Current we only synchronize looped motions.
|
||||
if (getLoop())
|
||||
{
|
||||
if (motion_with_smallest_runtime)
|
||||
{
|
||||
// Pretend the motion was started in the past at the same time as the other motion(s).
|
||||
time = getAnimTime() - runtime;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
void AISyncClientMotion::deregistered(void)
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
mReadyEvents = 0;
|
||||
#endif
|
||||
}
|
||||
//</singu>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -48,10 +167,11 @@
|
||||
// LLMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion::LLMotion( const LLUUID &id ) :
|
||||
LLMotion::LLMotion(LLUUID const& id, LLMotionController* controller) :
|
||||
mStopped(TRUE),
|
||||
mActive(FALSE),
|
||||
mID(id),
|
||||
mController(controller),
|
||||
mActivationTimestamp(0.f),
|
||||
mStopTimestamp(0.f),
|
||||
mSendStopTimestamp(F32_MAX),
|
||||
@@ -147,6 +267,19 @@ void LLMotion::activate(F32 time)
|
||||
{
|
||||
mActivationTimestamp = time;
|
||||
mStopped = FALSE;
|
||||
//<singu>
|
||||
if (mController && !mController->syncing_disabled()) // Avoid being registered when syncing is disabled for this motion.
|
||||
{
|
||||
if (mActive)
|
||||
{
|
||||
// If the motion is already active then we are being restarted.
|
||||
// Unregister it first (if it is registered) so that the call to ready will cause it to be registered
|
||||
// and be synchronized with other motions that are started at this moment.
|
||||
unregister_client();
|
||||
}
|
||||
ready(6, 2 | (mController->isHidden() ? 0 : 4)); // Signal that mActivationTimestamp is set/valid (2), and that this server has a visible motion (4) (or not).
|
||||
}
|
||||
//</singu>
|
||||
mActive = TRUE;
|
||||
onActivate();
|
||||
}
|
||||
@@ -159,6 +292,14 @@ void LLMotion::deactivate()
|
||||
mActive = FALSE;
|
||||
mPose.setWeight(0.f);
|
||||
|
||||
//<singu>
|
||||
if (server()) // Only when this motion is already registered.
|
||||
{
|
||||
ready(6, 0); // Signal that mActivationTimestamp is no longer valid.
|
||||
unregister_client(); // No longer running, so no longer a part of this sync group.
|
||||
}
|
||||
//</singu>
|
||||
|
||||
if (mDeactivateCallback)
|
||||
{
|
||||
(*mDeactivateCallback)(mDeactivateCallbackUserData);
|
||||
@@ -174,4 +315,19 @@ BOOL LLMotion::canDeprecate()
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIMaskedMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
BOOL AIMaskedMotion::onActivate()
|
||||
{
|
||||
mController->activated(mMaskBit);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void AIMaskedMotion::onDeactivate()
|
||||
{
|
||||
mController->deactivated(mMaskBit);
|
||||
}
|
||||
|
||||
// End
|
||||
|
||||
@@ -38,16 +38,85 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string>
|
||||
|
||||
#include "aisyncclient.h"
|
||||
#include "llerror.h"
|
||||
#include "llpose.h"
|
||||
#include "lluuid.h"
|
||||
|
||||
class LLCharacter;
|
||||
class LLMotionController;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class AISync* stuff
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class AISyncKeyMotion : public AISyncKey
|
||||
{
|
||||
private:
|
||||
F32 mDuration;
|
||||
bool mLoop;
|
||||
|
||||
public:
|
||||
AISyncKeyMotion(AISyncKey const* from_key, F32 duration, bool loop) : AISyncKey(from_key), mDuration(duration), mLoop(loop) { }
|
||||
|
||||
// Virtual functions of AISyncKey.
|
||||
public:
|
||||
/*virtual*/ synckeytype_t getkeytype(void) const
|
||||
{
|
||||
// Return a unique identifier for this class, where the low 8 bits represent the syncgroup.
|
||||
return synckeytype_motion;
|
||||
}
|
||||
|
||||
/*virtual*/ bool equals(AISyncKey const& key) const
|
||||
{
|
||||
switch (key.getkeytype())
|
||||
{
|
||||
case synckeytype_motion:
|
||||
{
|
||||
// The other key is of the same type.
|
||||
AISyncKeyMotion const& motion_key = static_cast<AISyncKeyMotion const&>(key);
|
||||
return mLoop == motion_key.mLoop && is_approx_equal(mDuration, motion_key.mDuration);
|
||||
}
|
||||
default:
|
||||
// The keys must be in the same syncgroup.
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class AISyncClientMotion : public AISyncClient
|
||||
{
|
||||
protected:
|
||||
// Make sure that clients that are destroyed are first unregistered.
|
||||
// This is needed, for example, when loading fails or when excess motions are being purged.
|
||||
/*virtual*/ ~AISyncClientMotion() { unregister_client(); }
|
||||
|
||||
// AISyncClient events.
|
||||
/*virtual*/ AISyncKey* createSyncKey(AISyncKey const* from_key = NULL) const;
|
||||
/*virtual*/ void event1_ready(void) { }
|
||||
/*virtual*/ void event1_not_ready(void) { }
|
||||
/*virtual*/ void deregistered(void);
|
||||
|
||||
protected:
|
||||
// This is called when the server sent us a message that it wants us to play this animation, but we can't because it isn't fully downloaded yet.
|
||||
void aisync_loading(void);
|
||||
// This is called when that motion is successfully loaded and it has to be re-registered because now the duration etc is known.
|
||||
void aisync_loaded(void);
|
||||
|
||||
public:
|
||||
// Virtual functions of AISyncClientMotion.
|
||||
// These are defined by classes derived from LLMotion (which is derived from this class).
|
||||
virtual BOOL getLoop() = 0;
|
||||
virtual F32 getDuration() = 0;
|
||||
virtual F32 getAnimTime(void) const = 0;
|
||||
virtual F32 getRuntime(void) const = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLMotion
|
||||
class LLMotion : public AISyncClientMotion
|
||||
{
|
||||
friend class LLMotionController;
|
||||
|
||||
@@ -66,7 +135,7 @@ public:
|
||||
};
|
||||
|
||||
// Constructor
|
||||
LLMotion(const LLUUID &id);
|
||||
LLMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLMotion();
|
||||
@@ -114,7 +183,22 @@ protected:
|
||||
BOOL isActive() { return mActive; }
|
||||
public:
|
||||
void activate(F32 time);
|
||||
|
||||
|
||||
//<singu>
|
||||
// Returns the time that this motion has been running.
|
||||
virtual F32 getRuntime(void) const;
|
||||
|
||||
// Return the current time (in seconds since creation of the controller).
|
||||
virtual F32 getAnimTime(void) const;
|
||||
|
||||
// This is called when a motion is to be activated, but might need synchronization.
|
||||
// It adjusts the start time to match that of other motions in the same synchronization group that were already started.
|
||||
F32 syncActivationTime(F32 time);
|
||||
|
||||
// Accessor.
|
||||
LLMotionController* getController(void) const { return mController; }
|
||||
//</singu>
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// animation callbacks to be implemented by subclasses
|
||||
@@ -181,6 +265,9 @@ protected:
|
||||
//-------------------------------------------------------------------------
|
||||
std::string mName; // instance name assigned by motion controller
|
||||
LLUUID mID;
|
||||
//<singu>
|
||||
LLMotionController* mController;
|
||||
//</singu>
|
||||
|
||||
F32 mActivationTimestamp; // time when motion was activated
|
||||
F32 mStopTimestamp; // time when motion was told to stop
|
||||
@@ -199,9 +286,9 @@ protected:
|
||||
class LLTestMotion : public LLMotion
|
||||
{
|
||||
public:
|
||||
LLTestMotion(const LLUUID &id) : LLMotion(id){}
|
||||
LLTestMotion(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller){}
|
||||
~LLTestMotion() {}
|
||||
static LLMotion *create(const LLUUID& id) { return new LLTestMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLTestMotion(id, controller); }
|
||||
BOOL getLoop() { return FALSE; }
|
||||
F32 getDuration() { return 0.0f; }
|
||||
F32 getEaseInDuration() { return 0.0f; }
|
||||
@@ -223,9 +310,9 @@ public:
|
||||
class LLNullMotion : public LLMotion
|
||||
{
|
||||
public:
|
||||
LLNullMotion(const LLUUID &id) : LLMotion(id) {}
|
||||
LLNullMotion(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller) {}
|
||||
~LLNullMotion() {}
|
||||
static LLMotion *create(const LLUUID &id) { return new LLNullMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLNullMotion(id, controller); }
|
||||
|
||||
// motions must specify whether or not they loop
|
||||
/*virtual*/ BOOL getLoop() { return TRUE; }
|
||||
@@ -266,5 +353,41 @@ public:
|
||||
// called when a motion is deactivated
|
||||
/*virtual*/ void onDeactivate() {}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIMaskedMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// These motions have a bit assigned in LLMotionController::mActiveMask
|
||||
// that is set and uset upon activation/deactivation.
|
||||
|
||||
// This must be in the same order as ANIM_AGENT_BODY_NOISE_ID through ANIM_AGENT_WALK_ADJUST_ID in llvoavatar.cpp.
|
||||
U32 const ANIM_AGENT_BODY_NOISE = 0x001;
|
||||
U32 const ANIM_AGENT_BREATHE_ROT = 0x002;
|
||||
U32 const ANIM_AGENT_PHYSICS_MOTION = 0x004;
|
||||
U32 const ANIM_AGENT_EDITING = 0x008;
|
||||
U32 const ANIM_AGENT_EYE = 0x010;
|
||||
U32 const ANIM_AGENT_FLY_ADJUST = 0x020;
|
||||
U32 const ANIM_AGENT_HAND_MOTION = 0x040;
|
||||
U32 const ANIM_AGENT_HEAD_ROT = 0x080;
|
||||
U32 const ANIM_AGENT_PELVIS_FIX = 0x100;
|
||||
U32 const ANIM_AGENT_TARGET = 0x200;
|
||||
U32 const ANIM_AGENT_WALK_ADJUST = 0x400;
|
||||
|
||||
class AIMaskedMotion : public LLMotion
|
||||
{
|
||||
private:
|
||||
U32 mMaskBit;
|
||||
|
||||
public:
|
||||
AIMaskedMotion(LLUUID const& id, LLMotionController* controller, U32 mask_bit) : LLMotion(id, controller), mMaskBit(mask_bit) { }
|
||||
|
||||
/*virtual*/ BOOL onActivate();
|
||||
/*virtual*/ void onDeactivate();
|
||||
|
||||
U32 getMaskBit(void) const { return mMaskBit; }
|
||||
};
|
||||
|
||||
#endif // LL_LLMOTION_H
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ void LLMotionRegistry::markBad( const LLUUID& id )
|
||||
//-----------------------------------------------------------------------------
|
||||
// createMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
|
||||
LLMotion* LLMotionRegistry::createMotion(LLUUID const& id, LLMotionController* controller)
|
||||
{
|
||||
LLMotionConstructor constructor = get_if_there(mMotionTable, id, LLMotionConstructor(NULL));
|
||||
LLMotion* motion = NULL;
|
||||
@@ -105,11 +105,11 @@ LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
|
||||
if ( constructor == NULL )
|
||||
{
|
||||
// *FIX: need to replace with a better default scheme. RN
|
||||
motion = LLKeyframeMotion::create(id);
|
||||
motion = LLKeyframeMotion::create(id, controller);
|
||||
}
|
||||
else
|
||||
{
|
||||
motion = constructor(id);
|
||||
motion = constructor(id, controller);
|
||||
}
|
||||
|
||||
return motion;
|
||||
@@ -126,18 +126,22 @@ LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotionController::LLMotionController()
|
||||
: mTimeFactor(sCurrentTimeFactor),
|
||||
: mIsSelf(FALSE),
|
||||
mTimeFactor(sCurrentTimeFactor),
|
||||
mCharacter(NULL),
|
||||
mAnimTime(0.f),
|
||||
mActiveMask(0),
|
||||
mDisableSyncing(0),
|
||||
mHidden(false),
|
||||
mHaveVisibleSyncedMotions(false),
|
||||
mPrevTimerElapsed(0.f),
|
||||
mAnimTime(0.f),
|
||||
mLastTime(0.0f),
|
||||
mHasRunOnce(FALSE),
|
||||
mPaused(FALSE),
|
||||
mPauseTime(0.f),
|
||||
mTimeStep(0.f),
|
||||
mTimeStepCount(0),
|
||||
mLastInterp(0.f),
|
||||
mIsSelf(FALSE)
|
||||
mLastInterp(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -168,7 +172,15 @@ void LLMotionController::deleteAllMotions()
|
||||
mLoadingMotions.clear();
|
||||
mLoadedMotions.clear();
|
||||
mActiveMotions.clear();
|
||||
|
||||
//<singu>
|
||||
mActiveMask = 0;
|
||||
for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer());
|
||||
mDeprecatedMotions.clear();
|
||||
for (motion_map_t::iterator iter = mAllMotions.begin(); iter != mAllMotions.end(); ++iter)
|
||||
{
|
||||
iter->second->unregister_client();
|
||||
}
|
||||
//</singu>
|
||||
for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer());
|
||||
mAllMotions.clear();
|
||||
}
|
||||
@@ -178,26 +190,19 @@ void LLMotionController::deleteAllMotions()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::purgeExcessMotions()
|
||||
{
|
||||
if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
|
||||
//<singu>
|
||||
// The old code attempted to remove non-active motions from mDeprecatedMotions,
|
||||
// but that is nonsense: there are no motions in mDeprecatedMotions that are not active.
|
||||
if (mLoadedMotions.size() <= MAX_MOTION_INSTANCES)
|
||||
{
|
||||
// clean up deprecated motions
|
||||
for (motion_set_t::iterator deprecated_motion_it = mDeprecatedMotions.begin();
|
||||
deprecated_motion_it != mDeprecatedMotions.end(); )
|
||||
{
|
||||
motion_set_t::iterator cur_iter = deprecated_motion_it++;
|
||||
LLMotion* cur_motionp = *cur_iter;
|
||||
if (!isMotionActive(cur_motionp))
|
||||
{
|
||||
// Motion is deprecated so we know it's not cannonical,
|
||||
// we can safely remove the instance
|
||||
removeMotionInstance(cur_motionp); // modifies mDeprecatedMotions
|
||||
mDeprecatedMotions.erase(cur_iter);
|
||||
}
|
||||
}
|
||||
// Speed up, no need to create motions_to_kill.
|
||||
return;
|
||||
}
|
||||
//</singu>
|
||||
|
||||
std::set<LLUUID> motions_to_kill;
|
||||
if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
|
||||
|
||||
if (1) // Singu: leave indentation alone...
|
||||
{
|
||||
// too many motions active this frame, kill all blenders
|
||||
mPoseBlender.clearBlenders();
|
||||
@@ -308,24 +313,44 @@ BOOL LLMotionController::registerMotion( const LLUUID& id, LLMotionConstructor c
|
||||
void LLMotionController::removeMotion( const LLUUID& id)
|
||||
{
|
||||
LLMotion* motionp = findMotion(id);
|
||||
mAllMotions.erase(id);
|
||||
removeMotionInstance(motionp);
|
||||
//<singu>
|
||||
// If a motion is erased from mAllMotions, it must be deleted.
|
||||
if (motionp)
|
||||
{
|
||||
mAllMotions.erase(id);
|
||||
removeMotionInstance(motionp);
|
||||
delete motionp;
|
||||
}
|
||||
//</singu>
|
||||
}
|
||||
|
||||
// removes instance of a motion from all runtime structures, but does
|
||||
// not erase entry by ID, as this could be a duplicate instance
|
||||
// use removeMotion(id) to remove all references to a given motion by id.
|
||||
// use removeMotion(id) to remove a reference to a given motion by id
|
||||
// (that will not remove (active) deprecated motions).
|
||||
void LLMotionController::removeMotionInstance(LLMotion* motionp)
|
||||
{
|
||||
if (motionp)
|
||||
{
|
||||
llassert(findMotion(motionp->getID()) != motionp);
|
||||
if (motionp->isActive())
|
||||
motionp->deactivate();
|
||||
mLoadingMotions.erase(motionp);
|
||||
mLoadedMotions.erase(motionp);
|
||||
mActiveMotions.remove(motionp);
|
||||
delete motionp;
|
||||
//<singu>
|
||||
// Deactivation moved here. Only delete motionp when it is being removed from mDeprecatedMotions.
|
||||
if (motionp->isActive())
|
||||
{
|
||||
motionp->deactivate();
|
||||
// If a motion is deactivated, it must be removed from mDeprecatedMotions if there.
|
||||
motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp);
|
||||
if (found_it != mDeprecatedMotions.end())
|
||||
{
|
||||
mDeprecatedMotions.erase(found_it);
|
||||
// If a motion is erased from mDeprecatedMotions, it must be deleted.
|
||||
delete motionp;
|
||||
}
|
||||
}
|
||||
//</singu>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +366,7 @@ LLMotion* LLMotionController::createMotion( const LLUUID &id )
|
||||
if (!motion)
|
||||
{
|
||||
// look up constructor and create it
|
||||
motion = sRegistry.createMotion(id);
|
||||
motion = sRegistry.createMotion(id, this);
|
||||
if (!motion)
|
||||
{
|
||||
return NULL;
|
||||
@@ -393,6 +418,7 @@ BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset)
|
||||
if (motion
|
||||
&& !mPaused
|
||||
&& motion->canDeprecate()
|
||||
&& motion->isActive() // singu: do not deprecate motions that are not active.
|
||||
&& motion->getFadeWeight() > 0.01f // not LOD-ed out
|
||||
&& (motion->isBlending() || motion->getStopTime() != 0.f))
|
||||
{
|
||||
@@ -418,7 +444,19 @@ BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset)
|
||||
}
|
||||
|
||||
// llinfos << "Starting motion " << name << llendl;
|
||||
return activateMotionInstance(motion, mAnimTime - start_offset);
|
||||
//<singu>
|
||||
F32 start_time = mAnimTime - start_offset;
|
||||
if (!mDisableSyncing)
|
||||
{
|
||||
start_time = motion->syncActivationTime(start_time);
|
||||
}
|
||||
++mDisableSyncing;
|
||||
//</singu>
|
||||
BOOL res = activateMotionInstance(motion, start_time);
|
||||
//<singu>
|
||||
--mDisableSyncing;
|
||||
//</singu>
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -774,7 +812,19 @@ void LLMotionController::updateLoadingMotions()
|
||||
// this motion should be playing
|
||||
if (!motionp->isStopped())
|
||||
{
|
||||
activateMotionInstance(motionp, mAnimTime);
|
||||
//<singu>
|
||||
F32 start_time = mAnimTime;
|
||||
if (!mDisableSyncing)
|
||||
{
|
||||
motionp->aisync_loaded();
|
||||
start_time = motionp->syncActivationTime(start_time);
|
||||
}
|
||||
++mDisableSyncing;
|
||||
//</singu>
|
||||
activateMotionInstance(motionp, start_time);
|
||||
//<singu>
|
||||
--mDisableSyncing;
|
||||
//</singu>
|
||||
}
|
||||
}
|
||||
else if (status == LLMotion::STATUS_FAILURE)
|
||||
@@ -782,12 +832,15 @@ void LLMotionController::updateLoadingMotions()
|
||||
llinfos << "Motion " << motionp->getID() << " init failed." << llendl;
|
||||
sRegistry.markBad(motionp->getID());
|
||||
mLoadingMotions.erase(curiter);
|
||||
motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp);
|
||||
if (found_it != mDeprecatedMotions.end())
|
||||
{
|
||||
mDeprecatedMotions.erase(found_it);
|
||||
}
|
||||
// Singu note: a motion in mLoadingMotions will not be in mActiveMotions
|
||||
// and therefore not be in mDeprecatedMotions. So, we don't have to
|
||||
// check for it's existence there.
|
||||
llassert(mDeprecatedMotions.find(motionp) == mDeprecatedMotions.end());
|
||||
mAllMotions.erase(motionp->getID());
|
||||
//<singu>
|
||||
// Make sure we're not registered anymore.
|
||||
motionp->unregister_client();
|
||||
//</singu>
|
||||
delete motionp;
|
||||
}
|
||||
}
|
||||
@@ -821,8 +874,15 @@ void LLMotionController::updateMotions(bool force_update)
|
||||
{
|
||||
F32 time_interval = fmodf(update_time, mTimeStep);
|
||||
|
||||
// always animate *ahead* of actual time
|
||||
S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1;
|
||||
//<singu>
|
||||
// This old code is nonsense.
|
||||
//S32 quantum_count = llmax(0, llround((update_time - time_interval) / mTimeStep)) + 1;
|
||||
// (update_time - time_interval) / mTimeStep is an integer! We need llround to get rid of floating point errors, not llfloor.
|
||||
// Moreover, just rounding off to the nearest integer with llround(update_time / mTimeStep) makes a lot more sense:
|
||||
// it is the best we can do to get as close to what we should draw as possible.
|
||||
// However, mAnimTime may only be incremented; therefore make sure of that with the llmax.
|
||||
S32 quantum_count = llmax(llround(update_time / mTimeStep), llceil(mAnimTime / mTimeStep));
|
||||
//</singu>
|
||||
if (quantum_count == mTimeStepCount)
|
||||
{
|
||||
// we're still in same time quantum as before, so just interpolate and exit
|
||||
@@ -848,7 +908,8 @@ void LLMotionController::updateMotions(bool force_update)
|
||||
}
|
||||
else
|
||||
{
|
||||
mAnimTime = update_time;
|
||||
// Singu note: mAnimTime may never be set back in time.
|
||||
mAnimTime = llmax(mAnimTime, update_time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,6 +976,12 @@ BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
|
||||
|
||||
if (mLoadingMotions.find(motion) != mLoadingMotions.end())
|
||||
{
|
||||
//<singu>
|
||||
if (!syncing_disabled())
|
||||
{
|
||||
motion->aisync_loading();
|
||||
}
|
||||
//</singu>
|
||||
// we want to start this motion, but we can't yet, so flag it as started
|
||||
motion->setStopped(FALSE);
|
||||
// report pending animations as activated
|
||||
@@ -970,18 +1037,16 @@ BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLMotionController::deactivateMotionInstance(LLMotion *motion)
|
||||
{
|
||||
motion->deactivate();
|
||||
|
||||
motion_set_t::iterator found_it = mDeprecatedMotions.find(motion);
|
||||
if (found_it != mDeprecatedMotions.end())
|
||||
{
|
||||
// deprecated motions need to be completely excised
|
||||
removeMotionInstance(motion);
|
||||
mDeprecatedMotions.erase(found_it);
|
||||
removeMotionInstance(motion); // singu note: this deactivates motion and removes it from mDeprecatedMotions.
|
||||
}
|
||||
else
|
||||
{
|
||||
// for motions that we are keeping, simply remove from active queue
|
||||
motion->deactivate(); // singu note: moved here from the top of the function.
|
||||
mActiveMotions.remove(motion);
|
||||
}
|
||||
|
||||
@@ -1049,11 +1114,26 @@ void LLMotionController::dumpMotions()
|
||||
state_string += std::string("L");
|
||||
if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end())
|
||||
state_string += std::string("A");
|
||||
if (mDeprecatedMotions.find(motion) != mDeprecatedMotions.end())
|
||||
state_string += std::string("D");
|
||||
llassert(mDeprecatedMotions.find(motion) == mDeprecatedMotions.end()); // singu: it's impossible that a motion is in mAllMotions and mDeprecatedMotions at the same time.
|
||||
llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl;
|
||||
|
||||
}
|
||||
//<singu>
|
||||
// Also dump the deprecated motions.
|
||||
for (motion_set_t::iterator iter = mDeprecatedMotions.begin();
|
||||
iter != mDeprecatedMotions.end(); ++iter)
|
||||
{
|
||||
std::string state_string;
|
||||
LLMotion* motion = *iter;
|
||||
LLUUID id = motion->getID();
|
||||
llassert(mLoadingMotions.find(motion) == mLoadingMotions.end());
|
||||
if (mLoadedMotions.find(motion) != mLoadedMotions.end())
|
||||
state_string += std::string("L");
|
||||
if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end())
|
||||
state_string += std::string("A");
|
||||
state_string += "D";
|
||||
llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl;
|
||||
}
|
||||
//</singu>
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1061,11 +1141,11 @@ void LLMotionController::dumpMotions()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::deactivateAllMotions()
|
||||
{
|
||||
for (motion_map_t::iterator iter = mAllMotions.begin();
|
||||
iter != mAllMotions.end(); iter++)
|
||||
// Singu note: this must run over mActiveMotions: other motions are not active,
|
||||
// and running over mAllMotions will miss the ones in mDeprecatedMotions.
|
||||
for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end();)
|
||||
{
|
||||
LLMotion* motionp = iter->second;
|
||||
deactivateMotionInstance(motionp);
|
||||
deactivateMotionInstance(*iter++); // This might invalidate iter by erasing it from mActiveMotions.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1086,8 +1166,7 @@ void LLMotionController::flushAllMotions()
|
||||
active_motions.push_back(std::make_pair(motionp->getID(),dtime));
|
||||
motionp->deactivate(); // don't call deactivateMotionInstance() because we are going to reactivate it
|
||||
}
|
||||
mActiveMotions.clear();
|
||||
|
||||
|
||||
// delete all motion instances
|
||||
deleteAllMotions();
|
||||
|
||||
@@ -1096,13 +1175,136 @@ void LLMotionController::flushAllMotions()
|
||||
mCharacter->removeAnimationData("Hand Pose");
|
||||
|
||||
// restart motions
|
||||
//<singu>
|
||||
// Because we called motionp->deactivate() above, instead of deactivateMotionInstance(),
|
||||
// prevent calling AISyncClientMotion::activateInstance in startMotion below.
|
||||
disable_syncing();
|
||||
//</singu>
|
||||
for (std::vector<std::pair<LLUUID,F32> >::iterator iter = active_motions.begin();
|
||||
iter != active_motions.end(); ++iter)
|
||||
{
|
||||
startMotion(iter->first, iter->second);
|
||||
}
|
||||
//<singu>
|
||||
enable_syncing();
|
||||
//</singu>
|
||||
}
|
||||
|
||||
//<singu>
|
||||
//-----------------------------------------------------------------------------
|
||||
// toggle_hidden()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::toggle_hidden(void)
|
||||
{
|
||||
mHaveVisibleSyncedMotions = mHidden; // Default is false if we just became invisible (otherwise this value isn't used).
|
||||
mHidden = !mHidden;
|
||||
synceventset_t const visible = mHidden ? 0 : 4;
|
||||
|
||||
// Run over all motions.
|
||||
for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter)
|
||||
{
|
||||
LLMotion* motionp = *iter;
|
||||
AISyncServer* server = motionp->server();
|
||||
if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active.
|
||||
{
|
||||
bool visible_before = server->events_with_at_least_one_client_ready() & 4;
|
||||
server->ready(4, visible, motionp); // Mark that now we are visible or no longer visible.
|
||||
bool visible_after = server->events_with_at_least_one_client_ready() & 4;
|
||||
if (visible_after) // Are there any synchronized motions (left) that ARE visible?
|
||||
{
|
||||
mHaveVisibleSyncedMotions = true;
|
||||
}
|
||||
if (visible_before != visible_after)
|
||||
{
|
||||
// The group as a whole now might need to change whether or not it is animated.
|
||||
AISyncServer::client_list_t const& clients = server->getClients();
|
||||
for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client)
|
||||
{
|
||||
LLMotion* motion = dynamic_cast<LLMotion*>(client->mClientPtr);
|
||||
if (!motion)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLMotionController* controller = motion->getController();
|
||||
if (controller == this)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (visible_after)
|
||||
{
|
||||
// Us becoming visible means that all synchronized avatars need to be animated again too.
|
||||
controller->setHaveVisibleSyncedMotions();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Us becoming hidden means that all synchronized avatars might stop animating.
|
||||
controller->refresh_hidden(); // It is extremely unlikely, but harmless, to call this twice on the same controller.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMotionController::refresh_hidden(void)
|
||||
{
|
||||
mHaveVisibleSyncedMotions = !mHidden;
|
||||
|
||||
// Run over all motions.
|
||||
for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter)
|
||||
{
|
||||
LLMotion* motionp = *iter;
|
||||
AISyncServer* server = motionp->server();
|
||||
if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active.
|
||||
{
|
||||
bool visible_after = server->events_with_at_least_one_client_ready() & 4;
|
||||
if (visible_after) // Are there any synchronized motions (left) that ARE visible?
|
||||
{
|
||||
mHaveVisibleSyncedMotions = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMotionController::pauseAllSyncedCharacters(std::vector<LLAnimPauseRequest>& avatar_pause_handles)
|
||||
{
|
||||
// Run over all motions.
|
||||
for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter)
|
||||
{
|
||||
LLMotion* motionp = *iter;
|
||||
AISyncServer* server = motionp->server();
|
||||
if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active.
|
||||
{
|
||||
// Run over all clients of the found servers.
|
||||
AISyncServer::client_list_t const& clients = server->getClients();
|
||||
for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client)
|
||||
{
|
||||
LLMotion* motion = dynamic_cast<LLMotion*>(client->mClientPtr);
|
||||
if (!motion)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLMotionController* controller = motion->getController();
|
||||
if (controller == this)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
controller->requestPause(avatar_pause_handles);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMotionController::requestPause(std::vector<LLAnimPauseRequest>& avatar_pause_handles)
|
||||
{
|
||||
if (mCharacter)
|
||||
{
|
||||
mCharacter->requestPause(avatar_pause_handles);
|
||||
}
|
||||
}
|
||||
|
||||
//</singu>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// pause()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -51,11 +51,14 @@
|
||||
// This is necessary because llcharacter.h includes this file.
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLCharacter;
|
||||
class LLMotionController;
|
||||
class LLPauseRequestHandle;
|
||||
typedef LLPointer<LLPauseRequestHandle> LLAnimPauseRequest;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLMotionRegistry
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef LLMotion*(*LLMotionConstructor)(const LLUUID &id);
|
||||
typedef LLMotion* (*LLMotionConstructor)(LLUUID const& id, LLMotionController*);
|
||||
|
||||
class LLMotionRegistry
|
||||
{
|
||||
@@ -72,7 +75,7 @@ public:
|
||||
|
||||
// creates a new instance of a named motion
|
||||
// returns NULL motion is not registered
|
||||
LLMotion *createMotion( const LLUUID &id );
|
||||
LLMotion* createMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// initialization of motion failed, don't try to create this motion again
|
||||
void markBad( const LLUUID& id );
|
||||
@@ -115,7 +118,6 @@ public:
|
||||
|
||||
// unregisters a motion with the controller
|
||||
// (actually just forwards call to motion registry)
|
||||
// returns true if successfull
|
||||
void removeMotion( const LLUUID& id );
|
||||
|
||||
// start motion
|
||||
@@ -150,10 +152,20 @@ public:
|
||||
//Flush is a liar.
|
||||
void deactivateAllMotions();
|
||||
|
||||
//<singu>
|
||||
void activated(U32 bit) { mActiveMask |= bit; }
|
||||
void deactivated(U32 bit) { mActiveMask &= ~bit; }
|
||||
bool isactive(U32 bit) const { return (mActiveMask & bit) != 0; }
|
||||
//</singu>
|
||||
|
||||
// pause and continue all motions
|
||||
void pauseAllMotions();
|
||||
void unpauseAllMotions();
|
||||
BOOL isPaused() const { return mPaused; }
|
||||
//<singu>
|
||||
void requestPause(std::vector<LLAnimPauseRequest>& avatar_pause_handles);
|
||||
void pauseAllSyncedCharacters(std::vector<LLAnimPauseRequest>& avatar_pause_handles);
|
||||
//</singu>
|
||||
|
||||
void setTimeStep(F32 step);
|
||||
|
||||
@@ -180,7 +192,10 @@ protected:
|
||||
// internal operations act on motion instances directly
|
||||
// as there can be duplicate motions per id during blending overlap
|
||||
void deleteAllMotions();
|
||||
// singu: LLMotion needs access to activateMotionInstance.
|
||||
public:
|
||||
BOOL activateMotionInstance(LLMotion *motion, F32 time);
|
||||
protected:
|
||||
BOOL deactivateMotionInstance(LLMotion *motion);
|
||||
void deprecateMotionInstance(LLMotion* motion);
|
||||
BOOL stopMotionInstance(LLMotion *motion, BOOL stop_imemdiate);
|
||||
@@ -205,10 +220,13 @@ protected:
|
||||
// Life cycle of an animation:
|
||||
//
|
||||
// Animations are instantiated and immediately put in the mAllMotions map for their entire lifetime.
|
||||
// Singu note: that is not true, they are moved to mDeprecatedMotions (often) for the last part of their lifetime.
|
||||
// If the animations depend on any asset data, the appropriate data is fetched from the data server,
|
||||
// and the animation is put on the mLoadingMotions list.
|
||||
// Once an animations is loaded, it will be initialized and put on the mLoadedMotions list.
|
||||
// Any animation that is currently playing also sits in the mActiveMotions list.
|
||||
// Singu note: animations are only put in mDeprecatedMotions if and while they are playing,
|
||||
// therefore animations in mDeprecatedMotions will be (must be) active and in mActiveMotions.
|
||||
|
||||
typedef std::map<LLUUID, LLMotion*> motion_map_t;
|
||||
motion_map_t mAllMotions;
|
||||
@@ -217,7 +235,13 @@ protected:
|
||||
motion_set_t mLoadedMotions;
|
||||
motion_list_t mActiveMotions;
|
||||
motion_set_t mDeprecatedMotions;
|
||||
|
||||
|
||||
//<singu>
|
||||
U32 mActiveMask;
|
||||
int mDisableSyncing; // Set while LLMotion::onActivate (and onDeactivate) are called for this controller.
|
||||
bool mHidden; // The value of the last call to hidden().
|
||||
bool mHaveVisibleSyncedMotions; // Set when we are synchronized with one or more motions of a controller that is not hidden.
|
||||
//</singu>
|
||||
LLFrameTimer mTimer;
|
||||
F32 mPrevTimerElapsed;
|
||||
F32 mAnimTime;
|
||||
@@ -230,6 +254,26 @@ protected:
|
||||
F32 mLastInterp;
|
||||
|
||||
U8 mJointSignature[2][LL_CHARACTER_MAX_JOINTS];
|
||||
|
||||
//<singu>
|
||||
public:
|
||||
// Internal administration for AISync.
|
||||
void disable_syncing(void) { mDisableSyncing += 100; }
|
||||
void enable_syncing(void) { mDisableSyncing -= 100; }
|
||||
bool syncing_disabled(void) const { return mDisableSyncing >= 100; }
|
||||
|
||||
// Accessors needed for synchronization.
|
||||
F32 getAnimTime(void) const { return mAnimTime; }
|
||||
bool isHidden(void) const { return mHidden; }
|
||||
|
||||
// Called often. Should return false if we still need to keep updating our motions even if we're not visible.
|
||||
bool hidden(bool not_visible) { if (mHidden != not_visible) toggle_hidden(); return !mHaveVisibleSyncedMotions; }
|
||||
|
||||
private:
|
||||
void toggle_hidden(void);
|
||||
void refresh_hidden(void);
|
||||
void setHaveVisibleSyncedMotions(void) { mHaveVisibleSyncedMotions = true; }
|
||||
//</singu>
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -52,7 +52,7 @@ const F32 TORSO_ROT_FRACTION = 0.5f;
|
||||
// LLTargetingMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLTargetingMotion::LLTargetingMotion(const LLUUID &id) : LLMotion(id)
|
||||
LLTargetingMotion::LLTargetingMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_TARGET)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
mName = "targeting";
|
||||
@@ -99,14 +99,6 @@ LLMotion::LLMotionInitStatus LLTargetingMotion::onInitialize(LLCharacter *charac
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTargetingMotion::onActivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLTargetingMotion::onActivate()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTargetingMotion::onUpdate()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -166,12 +158,4 @@ BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTargetingMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLTargetingMotion::onDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// End
|
||||
|
||||
@@ -48,11 +48,11 @@
|
||||
// class LLTargetingMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLTargetingMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLTargetingMotion(const LLUUID &id);
|
||||
LLTargetingMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLTargetingMotion();
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLTargetingMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLTargetingMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -96,19 +96,11 @@ public:
|
||||
// must return true to indicate success and be available for activation
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
|
||||
// called when a motion is activated
|
||||
// must return TRUE to indicate success, or else
|
||||
// it will be deactivated
|
||||
virtual BOOL onActivate();
|
||||
|
||||
// called per time step
|
||||
// must return TRUE while it is active, and
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
public:
|
||||
|
||||
LLCharacter *mCharacter;
|
||||
|
||||
@@ -20,6 +20,7 @@ set(llcommon_SOURCE_FILES
|
||||
aialert.cpp
|
||||
aifile.cpp
|
||||
aiframetimer.cpp
|
||||
aisyncclient.cpp
|
||||
aithreadid.cpp
|
||||
imageids.cpp
|
||||
indra_constants.cpp
|
||||
@@ -112,11 +113,13 @@ set(llcommon_HEADER_FILES
|
||||
aifile.h
|
||||
aiframetimer.h
|
||||
airecursive.h
|
||||
aisyncclient.h
|
||||
aithreadid.h
|
||||
aithreadsafe.h
|
||||
bitpack.h
|
||||
ctype_workaround.h
|
||||
doublelinkedlist.h
|
||||
fix_macros.h
|
||||
imageids.h
|
||||
indra_constants.h
|
||||
linden_common.h
|
||||
|
||||
698
indra/llcommon/aisyncclient.cpp
Normal file
698
indra/llcommon/aisyncclient.cpp
Normal file
@@ -0,0 +1,698 @@
|
||||
/**
|
||||
* @file aisyncclient.cpp
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 13/12/2013
|
||||
* - Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
/*
|
||||
* AISyncClient : the base class of a client object (LLMotion) that needs to be informed
|
||||
* of the state of other such objects and/or to poll a server object about the state of
|
||||
* other such objects, in order to be and stay synchronized with those other objects.
|
||||
* In the case of an LLMotion (animation), all clients would be started and stopped at
|
||||
* the same time, as long as they are part of the same synchronization group (AISyncServer).
|
||||
*
|
||||
* AISyncKey: object that determines what synchronization group a client belongs to.
|
||||
* When a new client is created, a new AISyncKey is created too, using information from
|
||||
* the client, the current frame number and the current frame time. If two AISyncKey
|
||||
* compare equal, using operator==(AISyncKey const& key1, AISyncKey const& key2),
|
||||
* then the clients that created them need to be synchronized.
|
||||
*
|
||||
* AISyncServer: object that represents a group of clients that need to be synchronized:
|
||||
* it's a wrapper around a std::list<AISyncClientData> with pointers to all the clients
|
||||
* that need to be synchronized. It also stores the AISyncKey of the first (oldest) client
|
||||
* that was added. Clients with keys that compare equal to that will be added.
|
||||
* If a client is added with a synckeytype_t that is larger then it always replaces
|
||||
* the existing key however.
|
||||
*
|
||||
* AISyncServerMap: A wrapper around std::list<boost::intrusive_ptr<AISyncServer> >
|
||||
* that stores pointers to all currently existing AISyncServer objects. New entries
|
||||
* are added at the end, so the oldest key is at the front.
|
||||
*
|
||||
* AISyncServerMap list + - - - - - - + - - - - - - + ... The AISyncServerMap is
|
||||
* | | | a list with refcounted
|
||||
* V V V pointers to AISyncServers.
|
||||
* AISyncClient +--> AISyncServer
|
||||
* | <--- list key ---> AISyncKey Each AISyncServer is a
|
||||
* DerivedClient . list of normal pointers
|
||||
* . AISyncClients and one
|
||||
* <--- . pointer to a AISyncKey.
|
||||
* Each AISyncClient is the
|
||||
* base class of a DerivedClient
|
||||
* and pointers back to the
|
||||
* server with a refcounted
|
||||
* pointer.
|
||||
*
|
||||
* A new client is passed to the AISyncServerMap to be stored in a new or existing AISyncServer
|
||||
* object, using the key that the client produces. A boost::intrusive_ptr<AISyncServer> member
|
||||
* of the client is set to point to this server.
|
||||
*
|
||||
* The lifetime of the server objects is determined by the intrusive_ptr objects that
|
||||
* point to it: all the clients (which have an externally determined lifetime) and one
|
||||
* pointer in the AISyncServerMap. However, regularly a check is done on all servers in
|
||||
* the list to find expired servers: objects with keys older than two frames and older
|
||||
* than 0.1 seconds; if such a server is found and it has zero or one client, then the
|
||||
* client is unregistered and the pointer (and thus the server) removed from the
|
||||
* AISyncServerMap. If it has two or more clients then the entry is kept until both
|
||||
* clients are removed, which therefore can only be detected in intrusive_ptr_release
|
||||
* which only has access to the server object. The server then is removed from the list
|
||||
* by searching through it for the pointer to the server.
|
||||
*/
|
||||
|
||||
#include "sys.h"
|
||||
#include "aisyncclient.h"
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include "debug.h"
|
||||
|
||||
bool operator==(AISyncKey const& key1, AISyncKey const& key2)
|
||||
{
|
||||
// Test if these keys match based on time.
|
||||
if (std::abs((S32)(key1.mStartFrameCount - key2.mStartFrameCount)) > 1 &&
|
||||
std::abs(key1.mFrameTimer.getStartTime() - key2.mFrameTimer.getStartTime()) >= sSyncKeyExpirationTime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Time matches, let the derived classes determine if they also match otherwise.
|
||||
return key1.equals(key2);
|
||||
}
|
||||
|
||||
#ifdef CWDEBUG
|
||||
struct SyncEventSet {
|
||||
synceventset_t mBits;
|
||||
SyncEventSet(synceventset_t bits) : mBits(bits) { }
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, SyncEventSet const& ses)
|
||||
{
|
||||
for (int b = sizeof(ses.mBits) * 8 - 1; b >= 0; --b)
|
||||
{
|
||||
int m = 1 << b;
|
||||
os << ((ses.mBits & m) ? '1' : '0');
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
void print_clients(AISyncServer const* server, AISyncServer::client_list_t const& client_list)
|
||||
{
|
||||
Dout(dc::notice, "Clients of server " << server << ": ");
|
||||
for (AISyncServer::client_list_t::const_iterator iter = client_list.begin(); iter != client_list.end(); ++ iter)
|
||||
{
|
||||
llassert(iter->mClientPtr->mReadyEvents == iter->mReadyEvents);
|
||||
Dout(dc::notice, "-> " << iter->mClientPtr << " : " << SyncEventSet(iter->mReadyEvents));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void AISyncServerMap::register_client(AISyncClient* client, AISyncKey* new_key)
|
||||
{
|
||||
// client must always be a new client that has to be stored somewhere.
|
||||
llassert(client->server() == NULL);
|
||||
// Obviously the client can't be ready for anything when it isn't registered yet.
|
||||
llassert(!client->mReadyEvents);
|
||||
|
||||
// Find if a server with this key already exists.
|
||||
AISyncServer* server = NULL;
|
||||
for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end();)
|
||||
{
|
||||
boost::intrusive_ptr<AISyncServer>& server_ptr = *iter++; // Immediately increment iter because the call to unregister_last_client will erase it.
|
||||
AISyncKey const& server_key(server_ptr->key());
|
||||
if (server_key.is_older_than(*new_key)) // This means that the server key is expired: a new key will never match.
|
||||
{
|
||||
if (server_ptr->never_synced()) // This means that it contains one or zero clients and will never contain more.
|
||||
{
|
||||
// Get rid of this server.
|
||||
server_ptr->unregister_last_client(); // This will cause the server to be deleted, and erased from mServers.
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (*new_key == server_key)
|
||||
{
|
||||
server = server_ptr.get();
|
||||
// mServers stores new servers in strict order of the creation time of the keys,
|
||||
// so once we find a server with a key that is equal, none of the remaining servers
|
||||
// will have expired if they were never synced and we're done with the loop.
|
||||
// Servers that synced might have been added later, but we don't unregister
|
||||
// clients from those anyway because their sync partner might still show up.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (server)
|
||||
{
|
||||
// A server already exists.
|
||||
// Keep the oldest key, unless this new key has a synckeytype_t that is larger!
|
||||
if (new_key->getkeytype() > server->key().getkeytype())
|
||||
{
|
||||
server->swapkey(new_key);
|
||||
}
|
||||
delete new_key;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new server for this client. Transfers the ownership of the key allocation to the server.
|
||||
server = new AISyncServer(new_key);
|
||||
// Add it to mServers, before the last server that is younger then the new key.
|
||||
server_list_t::iterator where = mServers.end(); // Insert the new server before 'where',
|
||||
server_list_t::iterator new_where = where;
|
||||
while (where != mServers.begin()) // unless there exists a server before that
|
||||
{
|
||||
--new_where;
|
||||
if (new_key->getCreationTime() > (*new_where)->key().getCreationTime()) // and the new key is not younger then that,
|
||||
{
|
||||
break;
|
||||
}
|
||||
where = new_where; // then insert it before that element (etc).
|
||||
}
|
||||
// This method causes a single call to intrusive_ptr_add_ref and none to intrusive_ptr_release.
|
||||
server_ptr_t server_ptr = server;
|
||||
mServers.insert(where, server_ptr_t())->swap(server_ptr);
|
||||
}
|
||||
|
||||
// Add the client to the server.
|
||||
server->add(client);
|
||||
}
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
void AISyncServer::sanity_check(void) const
|
||||
{
|
||||
synceventset_t ready_events = (synceventset_t)-1; // All clients are ready.
|
||||
client_list_t::const_iterator client_iter = mClients.begin();
|
||||
while (client_iter != mClients.end())
|
||||
{
|
||||
ready_events &= client_iter->mReadyEvents;
|
||||
++client_iter;
|
||||
}
|
||||
synceventset_t pending_events = 0; // At least one client is ready.
|
||||
client_iter = mClients.begin();
|
||||
while (client_iter != mClients.end())
|
||||
{
|
||||
pending_events |= client_iter->mReadyEvents;
|
||||
++client_iter;
|
||||
}
|
||||
llassert(ready_events == mReadyEvents);
|
||||
llassert(pending_events == mPendingEvents);
|
||||
}
|
||||
#endif
|
||||
|
||||
void AISyncServer::add(AISyncClient* client)
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
// The client can't already be ready when it isn't even added to a server yet.
|
||||
llassert(!client->mReadyEvents);
|
||||
synceventset_t old_ready_events = mReadyEvents;
|
||||
// A new client is not ready for anything.
|
||||
mReadyEvents = 0;
|
||||
// Set mSynchronized if after adding client we'll have more than 1 client (that prevents the
|
||||
// server from being deleted unless all clients are actually destructed or explicitly unregistered).
|
||||
if (!mSynchronized && mClients.size() > 0)
|
||||
{
|
||||
mSynchronized = true;
|
||||
}
|
||||
// Trigger the existing clients to be not-ready anymore (if we were before).
|
||||
trigger(old_ready_events);
|
||||
// Only then add the new client (so that it didn't get not-ready trigger).
|
||||
mClients.push_back(client);
|
||||
client->mServer = this;
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AISyncServer::remove(AISyncClient* client)
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
client_list_t::iterator client_iter = mClients.begin();
|
||||
synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready.
|
||||
synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus).
|
||||
client_list_t::iterator found_client = mClients.end();
|
||||
while (client_iter != mClients.end())
|
||||
{
|
||||
if (client_iter->mClientPtr == client)
|
||||
{
|
||||
found_client = client_iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
remaining_ready_events &= client_iter->mReadyEvents;
|
||||
remaining_pending_events |= client_iter->mReadyEvents;
|
||||
}
|
||||
++client_iter;
|
||||
}
|
||||
llassert(found_client != mClients.end());
|
||||
// This must be the same as client->mReadyEvents.
|
||||
llassert(found_client->mReadyEvents == client->mReadyEvents);
|
||||
mClients.erase(found_client);
|
||||
synceventset_t old_ready_events = mReadyEvents;
|
||||
mReadyEvents = remaining_ready_events;
|
||||
mPendingEvents = remaining_pending_events;
|
||||
trigger(old_ready_events);
|
||||
client->mServer.reset();
|
||||
client->deregistered();
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AISyncServer::unregister_last_client(void)
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
// This function may only be called for servers with exactly one client that was never (potentially) synchronized.
|
||||
llassert(!mSynchronized && mClients.size() == 1);
|
||||
AISyncClient* client = mClients.begin()->mClientPtr;
|
||||
mClients.clear();
|
||||
client->mServer.reset();
|
||||
llassert(mReadyEvents == client->mReadyEvents);
|
||||
llassert(mPendingEvents == mReadyEvents);
|
||||
// No need to update mReadyEvents/mPendingEvents because the server is going to be deleted,
|
||||
// but inform the client that is no longer has a server.
|
||||
client->deregistered();
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AISyncServer::trigger(synceventset_t old_ready_events)
|
||||
{
|
||||
// If event 1 changed, informat all clients about it.
|
||||
if (((old_ready_events ^ mReadyEvents) & 1))
|
||||
{
|
||||
for (client_list_t::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter)
|
||||
{
|
||||
if ((mReadyEvents & 1))
|
||||
{
|
||||
client_iter->mClientPtr->event1_ready();
|
||||
}
|
||||
else
|
||||
{
|
||||
client_iter->mClientPtr->event1_not_ready();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AISyncServer::ready(synceventset_t events, synceventset_t yesno, AISyncClient* client)
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
synceventset_t added_events = events & yesno;
|
||||
synceventset_t removed_events = events & ~yesno;
|
||||
|
||||
// Run over all clients to find the client and calculate the current state.
|
||||
synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready.
|
||||
synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus).
|
||||
client_list_t::iterator found_client = mClients.end();
|
||||
for (client_list_t::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter)
|
||||
{
|
||||
if (client_iter->mClientPtr == client)
|
||||
{
|
||||
found_client = client_iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
remaining_ready_events &= client_iter->mReadyEvents;
|
||||
remaining_pending_events |= client_iter->mReadyEvents;
|
||||
}
|
||||
}
|
||||
|
||||
llassert(mReadyEvents == (remaining_ready_events & found_client->mReadyEvents));
|
||||
llassert(mPendingEvents == (remaining_pending_events | found_client->mReadyEvents));
|
||||
|
||||
found_client->mReadyEvents &= ~removed_events;
|
||||
found_client->mReadyEvents |= added_events;
|
||||
#ifdef SHOW_ASSERT
|
||||
client->mReadyEvents = found_client->mReadyEvents;
|
||||
#endif
|
||||
|
||||
synceventset_t old_ready_events = mReadyEvents;
|
||||
|
||||
mReadyEvents = remaining_ready_events & found_client->mReadyEvents;
|
||||
mPendingEvents = remaining_pending_events | found_client->mReadyEvents;
|
||||
|
||||
trigger(old_ready_events);
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
void intrusive_ptr_add_ref(AISyncServer* server)
|
||||
{
|
||||
server->mRefCount++;
|
||||
}
|
||||
|
||||
void intrusive_ptr_release(AISyncServer* server)
|
||||
{
|
||||
llassert(server->mRefCount > 0);
|
||||
server->mRefCount--;
|
||||
if (server->mRefCount == 0)
|
||||
{
|
||||
delete server;
|
||||
}
|
||||
else if (server->mRefCount == 1)
|
||||
{
|
||||
// If the the last pointer to this server is in the the AISyncServerMap, then delete that too.
|
||||
AISyncServerMap::instance().remove_server(server);
|
||||
}
|
||||
}
|
||||
|
||||
void AISyncServerMap::remove_server(AISyncServer* server)
|
||||
{
|
||||
for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end(); ++iter)
|
||||
{
|
||||
if (server == iter->get())
|
||||
{
|
||||
mServers.erase(iter); // This causes server to be deleted too.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// The server must be found: this function is only called from intrusive_ptr_release for servers
|
||||
// with just a single server_ptr_t left, which must be the one in mServers (otherwise it wasn't
|
||||
// even registered properly!)
|
||||
llassert(false);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// SYNC_TESTSUITE
|
||||
//=============================================================================
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
|
||||
//static
|
||||
U32 LLFrameTimer::sFrameCount;
|
||||
|
||||
double innerloop_count = 0;
|
||||
|
||||
double LLFrameTimer::getCurrentTime()
|
||||
{
|
||||
return innerloop_count * 0.001;
|
||||
}
|
||||
|
||||
template<synckeytype_t synckeytype>
|
||||
class TestsuiteKey : public AISyncKey
|
||||
{
|
||||
private:
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
TestsuiteKey(int index) : mIndex(index) { }
|
||||
|
||||
int getIndex(void) const { return mIndex; }
|
||||
|
||||
// Virtual functions of AISyncKey.
|
||||
public:
|
||||
/*virtual*/ synckeytype_t getkeytype(void) const
|
||||
{
|
||||
// Return a unique identifier for this class, where the low 8 bits represent the syncgroup.
|
||||
return synckeytype;
|
||||
}
|
||||
|
||||
/*virtual*/ bool equals(AISyncKey const& key) const
|
||||
{
|
||||
synckeytype_t const theotherkey = (synckeytype_t)(synckeytype ^ 0x100);
|
||||
switch (key.getkeytype())
|
||||
{
|
||||
case synckeytype:
|
||||
{
|
||||
// The other key is of the same type.
|
||||
TestsuiteKey<synckeytype> const& test_key = static_cast<TestsuiteKey<synckeytype> const&>(key);
|
||||
return (mIndex & 1) == (test_key.mIndex & 1);
|
||||
}
|
||||
case theotherkey:
|
||||
{
|
||||
TestsuiteKey<theotherkey> const& test_key = static_cast<TestsuiteKey<theotherkey> const&>(key);
|
||||
return (mIndex & 2) == (test_key.getIndex() & 2);
|
||||
}
|
||||
default:
|
||||
// The keys must be in the same syncgroup.
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<synckeytype_t synckeytype>
|
||||
class TestsuiteClient : public AISyncClient
|
||||
{
|
||||
// AISyncClient events.
|
||||
protected:
|
||||
/*virtual*/ AISyncKey* createSyncKey(void) const
|
||||
{
|
||||
return new TestsuiteKey<synckeytype>(mIndex);
|
||||
}
|
||||
|
||||
private:
|
||||
int mIndex;
|
||||
bool mRequestedRegistered;
|
||||
synceventset_t mRequestedReady;
|
||||
bool mActualReady1;
|
||||
|
||||
public:
|
||||
TestsuiteClient() : mIndex(-1), mRequestedRegistered(false), mRequestedReady(0), mActualReady1(false) { }
|
||||
~TestsuiteClient() { if (is_registered()) this->ready(mRequestedReady, (synceventset_t)0); }
|
||||
|
||||
void setIndex(int index) { mIndex = index; }
|
||||
|
||||
protected:
|
||||
/*virtual*/ void event1_ready(void)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
Dout(dc::notice, "Calling TestsuiteClient<" << synckeytype << ">::event1_ready() (mIndex = " << mIndex << ") of client " << this);
|
||||
#endif
|
||||
llassert(!mActualReady1);
|
||||
mActualReady1 = true;
|
||||
}
|
||||
|
||||
/*virtual*/ void event1_not_ready(void)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
Dout(dc::notice, "Calling TestsuiteClient<" << synckeytype << ">::event1_not_ready() (mIndex = " << mIndex << ") of client " << this);
|
||||
#endif
|
||||
llassert(mActualReady1);
|
||||
mActualReady1 = false;
|
||||
}
|
||||
|
||||
// This is called when the server expired and we're the only client on it.
|
||||
/*virtual*/ void deregistered(void)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
DoutEntering(dc::notice, "TestsuiteClient<" << synckeytype << ">::deregistered(), with this = " << this);
|
||||
#endif
|
||||
mRequestedRegistered = false;
|
||||
mRequestedReady = 0;
|
||||
mActualReady1 = false;
|
||||
this->mReadyEvents = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_registered(void) const { return this->server(); }
|
||||
|
||||
public:
|
||||
void change_state(unsigned long r);
|
||||
bool getRequestedRegistered(void) const { return mRequestedRegistered; }
|
||||
synceventset_t getRequestedReady(void) const { return mRequestedReady; }
|
||||
};
|
||||
|
||||
TestsuiteClient<synckeytype_test1a>* client1ap;
|
||||
TestsuiteClient<synckeytype_test1b>* client1bp;
|
||||
TestsuiteClient<synckeytype_test2a>* client2ap;
|
||||
TestsuiteClient<synckeytype_test2b>* client2bp;
|
||||
|
||||
int const number_of_clients_per_syncgroup = 8;
|
||||
|
||||
template<synckeytype_t synckeytype>
|
||||
void TestsuiteClient<synckeytype>::change_state(unsigned long r)
|
||||
{
|
||||
bool change_registered = r & 1;
|
||||
r >>= 1;
|
||||
synceventset_t toggle_events = r & 15;
|
||||
r >>= 4;
|
||||
if (change_registered)
|
||||
{
|
||||
if (mRequestedRegistered && !mRequestedReady)
|
||||
{
|
||||
mRequestedRegistered = false;
|
||||
this->unregister_client();
|
||||
}
|
||||
}
|
||||
else if (toggle_events)
|
||||
{
|
||||
mRequestedReady ^= toggle_events;
|
||||
mRequestedRegistered = true;
|
||||
this->ready(toggle_events, mRequestedReady & toggle_events);
|
||||
}
|
||||
llassert(mRequestedRegistered == is_registered());
|
||||
AISyncServer* server = this->server();
|
||||
if (mRequestedRegistered)
|
||||
{
|
||||
synceventset_t all_ready = synceventset_t(-1);
|
||||
synceventset_t any_ready = 0;
|
||||
int nr = 0;
|
||||
for (int cl = 0; cl < number_of_clients_per_syncgroup; ++cl)
|
||||
{
|
||||
switch ((synckeytype & 0xff))
|
||||
{
|
||||
case syncgroup_test1:
|
||||
{
|
||||
if (client1ap[cl].server() == server)
|
||||
{
|
||||
if (client1ap[cl].getRequestedRegistered())
|
||||
{
|
||||
++nr;
|
||||
all_ready &= client1ap[cl].getRequestedReady();
|
||||
any_ready |= client1ap[cl].getRequestedReady();
|
||||
}
|
||||
}
|
||||
if (client1bp[cl].server() == server)
|
||||
{
|
||||
if (client1bp[cl].getRequestedRegistered())
|
||||
{
|
||||
++nr;
|
||||
all_ready &= client1bp[cl].getRequestedReady();
|
||||
any_ready |= client1bp[cl].getRequestedReady();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case syncgroup_test2:
|
||||
{
|
||||
if (client2ap[cl].server() == server)
|
||||
{
|
||||
if (client2ap[cl].getRequestedRegistered())
|
||||
{
|
||||
++nr;
|
||||
all_ready &= client2ap[cl].getRequestedReady();
|
||||
any_ready |= client2ap[cl].getRequestedReady();
|
||||
}
|
||||
}
|
||||
if (client2bp[cl].server() == server)
|
||||
{
|
||||
if (client2bp[cl].getRequestedRegistered())
|
||||
{
|
||||
++nr;
|
||||
all_ready &= client2bp[cl].getRequestedReady();
|
||||
any_ready |= client2bp[cl].getRequestedReady();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
llassert(nr == server->getClients().size());
|
||||
llassert(!!(all_ready & 1) == mActualReady1);
|
||||
llassert(this->server()->events_with_all_clients_ready() == all_ready);
|
||||
llassert(this->server()->events_with_at_least_one_client_ready() == any_ready);
|
||||
llassert(nr == 0 || (any_ready & all_ready) == all_ready);
|
||||
}
|
||||
llassert(mRequestedReady == this->mReadyEvents);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Debug(libcw_do.on());
|
||||
Debug(dc::notice.on());
|
||||
Debug(libcw_do.set_ostream(&std::cout));
|
||||
Debug(list_channels_on(libcw_do));
|
||||
|
||||
unsigned short seed16v[3] = { 0x1234, 0xfedc, 0x7091 };
|
||||
|
||||
for (int k = 0;; ++k)
|
||||
{
|
||||
std::cout << "Loop: " << k << "; SEED: " << std::hex << seed16v[0] << ", " << seed16v[1] << ", " << seed16v[2] << std::dec << std::endl;
|
||||
++LLFrameTimer::sFrameCount;
|
||||
|
||||
seed48(seed16v);
|
||||
seed16v[0] = lrand48() & 0xffff;
|
||||
seed16v[1] = lrand48() & 0xffff;
|
||||
seed16v[2] = lrand48() & 0xffff;
|
||||
|
||||
TestsuiteClient<synckeytype_test1a> client1a[number_of_clients_per_syncgroup];
|
||||
TestsuiteClient<synckeytype_test1b> client1b[number_of_clients_per_syncgroup];
|
||||
TestsuiteClient<synckeytype_test2a> client2a[number_of_clients_per_syncgroup];
|
||||
TestsuiteClient<synckeytype_test2b> client2b[number_of_clients_per_syncgroup];
|
||||
client1ap = client1a;
|
||||
client1bp = client1b;
|
||||
client2ap = client2a;
|
||||
client2bp = client2b;
|
||||
|
||||
for (int i = 0; i < number_of_clients_per_syncgroup; ++i)
|
||||
{
|
||||
client1a[i].setIndex(i);
|
||||
client1b[i].setIndex(i);
|
||||
client2a[i].setIndex(i);
|
||||
client2b[i].setIndex(i);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 1000000; ++j)
|
||||
{
|
||||
innerloop_count += 1;
|
||||
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
Dout(dc::notice, "Innerloop: " << j);
|
||||
#endif
|
||||
unsigned long r = lrand48();
|
||||
synckeytype_t keytype = (r & 1) ? ((r & 2) ? synckeytype_test1a : synckeytype_test1b) : ((r & 2) ? synckeytype_test2a : synckeytype_test2b);
|
||||
r >>= 2;
|
||||
int cl = (r & 255) % number_of_clients_per_syncgroup;
|
||||
r >>= 8;
|
||||
switch (keytype)
|
||||
{
|
||||
case synckeytype_test1a:
|
||||
client1a[cl].change_state(r);
|
||||
break;
|
||||
case synckeytype_test1b:
|
||||
client1b[cl].change_state(r);
|
||||
break;
|
||||
case synckeytype_test2a:
|
||||
client2a[cl].change_state(r);
|
||||
break;
|
||||
case synckeytype_test2b:
|
||||
client2b[cl].change_state(r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
304
indra/llcommon/aisyncclient.h
Normal file
304
indra/llcommon/aisyncclient.h
Normal file
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* @file aisyncclient.h
|
||||
* @brief Declaration of AISyncClient.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 12/12/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AI_SYNC_CLIENT_H
|
||||
#define AI_SYNC_CLIENT_H
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
/*
|
||||
* To compile the testsuite, run:
|
||||
*
|
||||
* cd indra/llcommon
|
||||
* g++ -O3 -DCWDEBUG -DSYNC_TESTSUITE -I. -I../cwdebug aisyncclient.cpp -lcwd
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cassert>
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
typedef float F32;
|
||||
typedef double F64;
|
||||
#define LL_COMMON_API
|
||||
#define SHOW_ASSERT
|
||||
#define ASSERT_ONLY_COMMA(...) , __VA_ARGS__
|
||||
#define llassert assert
|
||||
|
||||
struct LLFrameTimer
|
||||
{
|
||||
double mStartTime;
|
||||
double mExpiry;
|
||||
static double getCurrentTime(void);
|
||||
static U32 sFrameCount;
|
||||
static U32 getFrameCount() { return sFrameCount; }
|
||||
F64 getStartTime() const { return mStartTime; }
|
||||
void reset(double expiration) { mStartTime = getCurrentTime(); mExpiry = mStartTime + expiration; }
|
||||
bool hasExpired(void) const { return getCurrentTime() > mExpiry; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LLSingleton
|
||||
{
|
||||
static T sInstance;
|
||||
static T& instance(void) { return sInstance; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T LLSingleton<T>::sInstance;
|
||||
|
||||
#else // !SYNC_TESTSUITE
|
||||
#include "llsingleton.h"
|
||||
#include "llframetimer.h"
|
||||
#endif
|
||||
#include <list>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Keys with a different syncgroup are never equal (so they are never synchronized).
|
||||
enum syncgroups
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
syncgroup_test1,
|
||||
syncgroup_test2,
|
||||
#else
|
||||
syncgroup_motions, // Syncgroup used for animations.
|
||||
#endif
|
||||
syncgroup_size
|
||||
};
|
||||
|
||||
// Each key type must return a unique identifier that exists of its syncgroup (the least significant 8 bit) plus a few bit to make it unique (bit 9 and higher).
|
||||
enum synckeytype_t
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
synckeytype_test1a = 0x000 + syncgroup_test1,
|
||||
synckeytype_test1b = 0x100 + syncgroup_test1,
|
||||
synckeytype_test2a = 0x000 + syncgroup_test2,
|
||||
synckeytype_test2b = 0x100 + syncgroup_test2,
|
||||
#else
|
||||
synckeytype_motion = syncgroup_motions // There is currently only one key type in the syncgroup_motions group: AISyncKeyMotion.
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef U32 synceventset_t; // A mask where each bit represents a ready state.
|
||||
|
||||
static F32 const sSyncKeyExpirationTime = 0.25; // In seconds.
|
||||
|
||||
class LL_COMMON_API AISyncKey
|
||||
{
|
||||
private:
|
||||
LLFrameTimer mFrameTimer; // This timer is started at the moment the sync key is created.
|
||||
U32 mStartFrameCount; // The frame count at which the timer was started.
|
||||
|
||||
public:
|
||||
// Constructor.
|
||||
AISyncKey(AISyncKey const* from_key) : mStartFrameCount(from_key ? from_key->mStartFrameCount : LLFrameTimer::getFrameCount())
|
||||
{
|
||||
if (from_key)
|
||||
{
|
||||
mFrameTimer.copy(from_key->mFrameTimer);
|
||||
}
|
||||
else
|
||||
{
|
||||
mFrameTimer.reset(sSyncKeyExpirationTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor.
|
||||
virtual ~AISyncKey() { }
|
||||
|
||||
// Return true if this key expired.
|
||||
bool expired(void) const
|
||||
{
|
||||
// The key has expired when sSyncKeyExpirationTime seconds have elapsed AND at least two frames have passed.
|
||||
return mFrameTimer.getFrameCount() > mStartFrameCount + 1 && mFrameTimer.hasExpired();
|
||||
}
|
||||
|
||||
// Returns true if this object and key would not compare equal based on time because this object is too old.
|
||||
bool is_older_than(AISyncKey const& key) const
|
||||
{
|
||||
return key.mStartFrameCount > mStartFrameCount + 1 && key.mFrameTimer.getStartTime() > mFrameTimer.getStartTime() + sSyncKeyExpirationTime;
|
||||
}
|
||||
|
||||
// Return the creation time of this key (in number of seconds since application start).
|
||||
F64 getCreationTime(void) const { return mFrameTimer.getStartTime(); }
|
||||
|
||||
// Returns true if the two keys match, meaning that they should be synchronized.
|
||||
friend bool operator==(AISyncKey const& key1, AISyncKey const& key2);
|
||||
|
||||
// Returns an ID that uniquely identifies the derived type.
|
||||
// Currently the only derived type is AISyncKeyMotion with ID synckeytype_motion.
|
||||
virtual synckeytype_t getkeytype(void) const = 0;
|
||||
|
||||
// Returns true if the data in the derived objects match, meaning that they should be synchronized.
|
||||
virtual bool equals(AISyncKey const& key) const = 0;
|
||||
};
|
||||
|
||||
// Forward declaration.
|
||||
class AISyncClient;
|
||||
class AISyncServer;
|
||||
LL_COMMON_API extern void intrusive_ptr_add_ref(AISyncServer* server);
|
||||
LL_COMMON_API extern void intrusive_ptr_release(AISyncServer* server);
|
||||
|
||||
struct LL_COMMON_API AISyncClientData
|
||||
{
|
||||
AISyncClient* mClientPtr;
|
||||
synceventset_t mReadyEvents;
|
||||
|
||||
AISyncClientData(AISyncClient* client) : mClientPtr(client), mReadyEvents(0) { }
|
||||
};
|
||||
|
||||
class LL_COMMON_API AISyncServer
|
||||
{
|
||||
public:
|
||||
typedef std::list<AISyncClientData> client_list_t;
|
||||
|
||||
private:
|
||||
int mRefCount; // Number of boost::intrusive_ptr objects pointing to this object.
|
||||
AISyncKey* mKey; // The key of the first client that was added.
|
||||
client_list_t mClients; // A list with pointers to all registered clients.
|
||||
bool mSynchronized; // Set when a server gets more than one client, and not reset anymore after that.
|
||||
synceventset_t mReadyEvents; // 0xFFFFFFFF bitwise-AND-ed with all clients.
|
||||
synceventset_t mPendingEvents; // The bitwise-OR of all clients.
|
||||
|
||||
public:
|
||||
AISyncServer(AISyncKey* key) : mRefCount(0), mKey(key), mSynchronized(false), mReadyEvents((synceventset_t)-1), mPendingEvents(0) { }
|
||||
~AISyncServer() { delete mKey; }
|
||||
|
||||
// Add a new client to this server.
|
||||
void add(AISyncClient* client);
|
||||
|
||||
// Remove a client from this server.
|
||||
void remove(AISyncClient* client);
|
||||
|
||||
// Return the key associated to this server (which is the key produced by the first client of the largest synckeytype_t that was added).
|
||||
AISyncKey const& key(void) const { return *mKey; }
|
||||
// Replace they key with another key (of larger synckeytype_t).
|
||||
void swapkey(AISyncKey*& key_ptr) { AISyncKey* tmp = key_ptr; key_ptr = mKey; mKey = tmp; }
|
||||
|
||||
// Returns true if this server never had more than one client.
|
||||
bool never_synced(void) const { return !mSynchronized; }
|
||||
|
||||
// Set readiness of all events at once.
|
||||
void ready(synceventset_t events, synceventset_t yesno, AISyncClient* client);
|
||||
|
||||
// Unregister the (only) client because it's own its own and will never need synchronization.
|
||||
void unregister_last_client(void);
|
||||
|
||||
// Return the events that all clients for.
|
||||
synceventset_t events_with_all_clients_ready(void) const { return mReadyEvents; }
|
||||
|
||||
// Return events that at least one client is ready for.
|
||||
synceventset_t events_with_at_least_one_client_ready(void) const { return mPendingEvents; }
|
||||
|
||||
// Return a list of all registered clients.
|
||||
client_list_t const& getClients(void) const { return mClients; }
|
||||
|
||||
private:
|
||||
// Call event1_ready() or event1_not_ready() on all clients if the least significant bit of mReadyEvents changed.
|
||||
void trigger(synceventset_t old_ready_events);
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
void sanity_check(void) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend LL_COMMON_API void intrusive_ptr_add_ref(AISyncServer* server);
|
||||
friend LL_COMMON_API void intrusive_ptr_release(AISyncServer* server);
|
||||
};
|
||||
|
||||
class LL_COMMON_API AISyncServerMap : public LLSingleton<AISyncServerMap>
|
||||
{
|
||||
public:
|
||||
typedef boost::intrusive_ptr<AISyncServer> server_ptr_t; // The type of a (stored) pointer to the server objects.
|
||||
typedef std::list<server_ptr_t> server_list_t; // The type of the list with pointers to the server objects.
|
||||
|
||||
private:
|
||||
server_list_t mServers; // A list with pointers to all server objects.
|
||||
|
||||
public:
|
||||
// Find or create a server object that the client belongs to and store the client in it.
|
||||
// If a new server is created, it is stored in mServers.
|
||||
void register_client(AISyncClient* client, AISyncKey* new_key);
|
||||
|
||||
private:
|
||||
friend LL_COMMON_API void intrusive_ptr_release(AISyncServer* server);
|
||||
// Remove a server from the map, only called by intrusive_ptr_release when there is one pointer left;
|
||||
// therefore, the server should not have any clients.
|
||||
void remove_server(AISyncServer* server);
|
||||
};
|
||||
|
||||
class LL_COMMON_API AISyncClient
|
||||
{
|
||||
private:
|
||||
friend class AISyncServer;
|
||||
boost::intrusive_ptr<AISyncServer> mServer; // The server this client was registered with, or NULL when unregistered.
|
||||
|
||||
public:
|
||||
#ifdef SHOW_ASSERT
|
||||
synceventset_t mReadyEvents;
|
||||
AISyncClient(void) : mReadyEvents(0) { }
|
||||
#endif
|
||||
virtual ~AISyncClient() { llassert(!mServer); /* If this fails then you need to add unregister_client() to the top of the destructor of the derived class that implements deregistered(). */ }
|
||||
virtual AISyncKey* createSyncKey(AISyncKey const* from_key = NULL) const = 0;
|
||||
|
||||
virtual void event1_ready(void) = 0;
|
||||
virtual void event1_not_ready(void) = 0;
|
||||
|
||||
// Only client. Client was forcefully deregistered from expired server because it was the only client.
|
||||
virtual void deregistered(void)
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
mReadyEvents = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
AISyncServer* server(void) const { return mServer.get(); }
|
||||
|
||||
// Add this client to a server with matching sync key. Optionally the server is first created.
|
||||
void register_client(void) { AISyncServerMap::instance().register_client(this, createSyncKey()); }
|
||||
|
||||
// Remove this client from its server, if any.
|
||||
void unregister_client(void) { if (mServer) mServer->remove(this); }
|
||||
|
||||
// Call 'ready' when you are ready (or not) to get a call to start().
|
||||
// Returns true if that call was made (immediately), otherwise it may happen later.
|
||||
|
||||
// Set readiness of all events at once.
|
||||
void ready(synceventset_t events, synceventset_t yesno)
|
||||
{
|
||||
if (!mServer)
|
||||
{
|
||||
register_client();
|
||||
}
|
||||
mServer->ready(events, yesno, this);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
25
indra/llcommon/fix_macros.h
Normal file
25
indra/llcommon/fix_macros.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @file fix_macros.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2012-11-16
|
||||
* @brief The Mac system headers seem to #define macros with obnoxiously
|
||||
* generic names, preventing any library from using those names. We've
|
||||
* had to fix these in so many places that it's worth making a header
|
||||
* file to handle it.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Copyright (c) 2012, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// DON'T use an #include guard: every time we encounter this header, #undef
|
||||
// these macros all over again.
|
||||
|
||||
// who injects MACROS with such generic names?! Grr.
|
||||
#ifdef equivalent
|
||||
#undef equivalent
|
||||
#endif
|
||||
|
||||
#ifdef check
|
||||
#undef check
|
||||
#endif
|
||||
@@ -47,6 +47,10 @@ public:
|
||||
// Create an LLFrameTimer and start it. After creation it is running and in the state expired (hasExpired will return true).
|
||||
LLFrameTimer(void) : mExpiry(0), mRunning(true), mPaused(false) { if (!sGlobalMutex) global_initialization(); setAge(0.0); }
|
||||
|
||||
//<singu>
|
||||
void copy(LLFrameTimer const& timer) { mStartTime = timer.mStartTime; mExpiry = timer.mExpiry; mRunning = timer.mRunning; mPaused = timer.mPaused; }
|
||||
//</singu>
|
||||
|
||||
// Atomic reads of static variables.
|
||||
|
||||
// Return the number of seconds since the start of the application.
|
||||
@@ -142,6 +146,9 @@ public:
|
||||
bool hasExpired() const { return getElapsedSeconds() >= mExpiry; }
|
||||
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(getElapsedSeconds() - mStartTime); }
|
||||
bool getStarted() const { return mRunning; }
|
||||
//<singu>
|
||||
F64 getStartTime() const { llassert(!mPaused); return mStartTime; }
|
||||
//</singu>
|
||||
|
||||
// return the seconds since epoch when this timer will expire.
|
||||
F64 expiresAt() const;
|
||||
|
||||
@@ -268,7 +268,7 @@ void LLInventoryObject::updateServer(BOOL) const
|
||||
llwarns << "LLInventoryObject::updateServer() called. Doesn't do anything." << llendl;
|
||||
}
|
||||
|
||||
inline
|
||||
// inline
|
||||
void LLInventoryObject::correctInventoryName(std::string& name)
|
||||
{
|
||||
LLStringUtil::replaceNonstandardASCII(name, ' ');
|
||||
@@ -1169,7 +1169,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd)
|
||||
// Because WT_UNKNOWN now has locally a special meaning, make sure we don't receive it from the server.
|
||||
if (wt == WT_UNKNOWN)
|
||||
{
|
||||
llwarns << "Received inventory item with wearable type WT_UNKNOWN from server! You should upgrade your viewer." << llendl;
|
||||
lldebugs << "Received inventory item with wearable type WT_UNKNOWN from server!" << llendl;
|
||||
// Change this new wearable type to WT_COUNT, as if when we had not inserted WT_UNKNOWN locally.
|
||||
mFlags += 1;
|
||||
wt = WT_COUNT;
|
||||
|
||||
@@ -84,9 +84,13 @@ public:
|
||||
void setParent(const LLUUID& new_parent);
|
||||
void setType(LLAssetType::EType type);
|
||||
|
||||
private:
|
||||
// [RLVa:KB] - Checked: 2014-01-07 (RLVa-1.4.10)
|
||||
// in place correction for inventory name string
|
||||
void correctInventoryName(std::string& name);
|
||||
static void correctInventoryName(std::string& name);
|
||||
// [/RLVa:KB]
|
||||
private:
|
||||
// // in place correction for inventory name string
|
||||
// void correctInventoryName(std::string& name);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// File Support
|
||||
|
||||
@@ -669,25 +669,31 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
|
||||
return false;
|
||||
}
|
||||
|
||||
const S32& LLAvatarNameCache::phoenix_name_system()
|
||||
{
|
||||
static const LLCachedControl<S32> name_system("PhoenixNameSystem", 0);
|
||||
return name_system;
|
||||
}
|
||||
|
||||
// Return true when name has been set to Phoenix Name System Name, if not return false.
|
||||
bool LLAvatarNameCache::getPNSName(const LLUUID& agent_id, std::string& name)
|
||||
bool LLAvatarNameCache::getPNSName(const LLUUID& agent_id, std::string& name, const S32& name_system)
|
||||
{
|
||||
LLAvatarName avatar_name;
|
||||
if (get(agent_id, &avatar_name))
|
||||
getPNSName(avatar_name, name);
|
||||
getPNSName(avatar_name, name, name_system);
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// get() with callback compatible version of getPNSName
|
||||
void LLAvatarNameCache::getPNSName(const LLAvatarName& avatar_name, std::string& name)
|
||||
void LLAvatarNameCache::getPNSName(const LLAvatarName& avatar_name, std::string& name, const S32& name_system)
|
||||
{
|
||||
static LLCachedControl<S32> phoenix_name_system("PhoenixNameSystem", 0);
|
||||
switch (phoenix_name_system)
|
||||
switch (name_system)
|
||||
{
|
||||
case 0 : name = avatar_name.getLegacyName(); break;
|
||||
case 1 : name = avatar_name.getCompleteName(); break;
|
||||
case 2 : name = avatar_name.mDisplayName; break;
|
||||
case 3 : name = avatar_name.getLegacyName() + (avatar_name.mIsDisplayNameDefault ? "" : " (" + avatar_name.mDisplayName + ")"); break;
|
||||
default : name = avatar_name.getLegacyName(); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,12 +65,13 @@ namespace LLAvatarNameCache
|
||||
// If name is in cache, returns true and fills in provided LLAvatarName
|
||||
// otherwise returns false
|
||||
bool get(const LLUUID& agent_id, LLAvatarName *av_name);
|
||||
const S32& phoenix_name_system();
|
||||
// If get() succeeds, returns true and fills in name string
|
||||
// via void function below, otherwise returns false
|
||||
bool getPNSName(const LLUUID& agent_id, std::string& name);
|
||||
bool getPNSName(const LLUUID& agent_id, std::string& name, const S32& name_system = phoenix_name_system());
|
||||
// Perform a filling of name string according to Phoenix Name System,
|
||||
// when we have an LLAvatarName already.
|
||||
void getPNSName(const LLAvatarName& avatar_name, std::string& name);
|
||||
void getPNSName(const LLAvatarName& avatar_name, std::string& name, const S32& name_system = phoenix_name_system());
|
||||
|
||||
// Callback types for get() below
|
||||
typedef boost::signals2::signal<
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "llmessagethrottle.h"
|
||||
#include "llframetimer.h"
|
||||
#include "fix_macros.h"
|
||||
|
||||
// This is used for the stl search_n function.
|
||||
#if _MSC_VER >= 1500 // VC9 has a bug in search_n
|
||||
|
||||
@@ -442,6 +442,8 @@ LLGLManager::LLGLManager() :
|
||||
mHasCubeMap(FALSE),
|
||||
mHasDebugOutput(FALSE),
|
||||
|
||||
mHasAdaptiveVsync(FALSE),
|
||||
|
||||
mIsATI(FALSE),
|
||||
mIsNVIDIA(FALSE),
|
||||
mIsIntel(FALSE),
|
||||
@@ -956,6 +958,12 @@ void LLGLManager::initExtensions()
|
||||
mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
|
||||
#endif
|
||||
|
||||
#if LL_WINDOWS
|
||||
mHasAdaptiveVsync = ExtensionExists("WGL_EXT_swap_control_tear", gGLHExts.mSysExts);
|
||||
#elif LL_LINUX
|
||||
mHasAdaptiveVsync = ExtensionExists("GLX_EXT_swap_control_tear", gGLHExts.mSysExts);
|
||||
#endif
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
llinfos << "initExtensions() checking shell variables to adjust features..." << llendl;
|
||||
// Our extension support for the Linux Client is very young with some
|
||||
@@ -980,6 +988,7 @@ void LLGLManager::initExtensions()
|
||||
mHasShaderObjects = FALSE;
|
||||
mHasVertexShader = FALSE;
|
||||
mHasFragmentShader = FALSE;
|
||||
mHasAdaptiveVsync = FALSE;
|
||||
LL_WARNS("RenderInit") << "GL extension support DISABLED via LL_GL_NOEXT" << LL_ENDL;
|
||||
}
|
||||
else if (getenv("LL_GL_BASICEXT")) /* Flawfinder: ignore */
|
||||
|
||||
@@ -113,6 +113,8 @@ public:
|
||||
BOOL mHasCubeMap;
|
||||
BOOL mHasDebugOutput;
|
||||
|
||||
BOOL mHasAdaptiveVsync;
|
||||
|
||||
// Vendor-specific extensions
|
||||
BOOL mIsATI;
|
||||
BOOL mIsNVIDIA;
|
||||
|
||||
@@ -1225,6 +1225,7 @@ void LLShaderMgr::initAttribsAndUniforms()
|
||||
|
||||
mReservedUniforms.push_back("matrixPalette");
|
||||
mReservedUniforms.push_back("translationPalette");
|
||||
mReservedUniforms.push_back("maxWeight");
|
||||
|
||||
mReservedUniforms.push_back("screenTex");
|
||||
mReservedUniforms.push_back("screenDepth");
|
||||
|
||||
@@ -179,6 +179,7 @@ public:
|
||||
|
||||
AVATAR_MATRIX,
|
||||
AVATAR_TRANSLATION,
|
||||
AVATAR_MAX_WEIGHT,
|
||||
|
||||
WATER_SCREENTEX,
|
||||
WATER_SCREENDEPTH,
|
||||
|
||||
@@ -921,6 +921,23 @@ void LLLineEditor::addChar(const llwchar uni_char)
|
||||
|
||||
mText.insert(getCursor(), w_buf);
|
||||
setCursor(getCursor() + 1);
|
||||
|
||||
if (!mReadOnly && mAutoreplaceCallback != NULL)
|
||||
{
|
||||
// autoreplace the text, if necessary
|
||||
S32 replacement_start;
|
||||
S32 replacement_length;
|
||||
LLWString replacement_string;
|
||||
S32 new_cursor_pos = getCursor();
|
||||
mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, mText);
|
||||
|
||||
if (replacement_length > 0 || !replacement_string.empty())
|
||||
{
|
||||
mText.erase(replacement_start, replacement_length);
|
||||
mText.insert(replacement_start, replacement_string);
|
||||
setCursor(new_cursor_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -167,6 +167,10 @@ public:
|
||||
virtual BOOL isSpellDirty() const { return mText.getString() != mPrevSpelledText; } // Returns TRUE if user changed value at all
|
||||
virtual void resetSpellDirty() { mPrevSpelledText = mText.getString(); } // Clear dirty state
|
||||
|
||||
typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t;
|
||||
autoreplace_callback_t mAutoreplaceCallback;
|
||||
void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; }
|
||||
|
||||
// assumes UTF8 text
|
||||
virtual void setValue(const LLSD& value ) { setText(value.asString()); }
|
||||
virtual LLSD getValue() const { return LLSD(getText()); }
|
||||
|
||||
@@ -1503,14 +1503,13 @@ LLNotificationPtr LLNotifications::add(AIAlert::Error const& error, int type, un
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// class UpdateItem
|
||||
// struct UpdateItem
|
||||
//
|
||||
// Allow LLNotifications::add, LLNotifications::cancel and LLNotifications::update
|
||||
// to be called from any thread.
|
||||
|
||||
class UpdateItem
|
||||
struct UpdateItem
|
||||
{
|
||||
public:
|
||||
char const* sigtype;
|
||||
LLNotificationPtr pNotif;
|
||||
UpdateItem(char const* st, LLNotificationPtr const& np) : sigtype(st), pNotif(np) { }
|
||||
|
||||
@@ -197,7 +197,7 @@ class LLNotification :
|
||||
{
|
||||
LOG_CLASS(LLNotification);
|
||||
friend class LLNotifications;
|
||||
friend class UpdateItem;
|
||||
friend struct UpdateItem;
|
||||
|
||||
public:
|
||||
// parameter object used to instantiate a new notification
|
||||
@@ -568,7 +568,7 @@ class LLNotificationChannelBase :
|
||||
public boost::signals2::trackable
|
||||
{
|
||||
LOG_CLASS(LLNotificationChannelBase);
|
||||
friend class UpdateItem;
|
||||
friend struct UpdateItem;
|
||||
public:
|
||||
LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) :
|
||||
mFilter(filter), mItems_sf(comp)
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
|
||||
static LLRegisterWidget<LLScrollListCtrl> r("scroll_list");
|
||||
|
||||
LLMenuGL* sScrollListMenus[1] = {}; // List menus that recur, such as general avatars or groups menus
|
||||
|
||||
// local structures & classes.
|
||||
struct SortScrollListItem
|
||||
{
|
||||
@@ -2552,7 +2554,15 @@ void LLScrollListCtrl::setScrollListParameters(LLXMLNodePtr node)
|
||||
node->getAttribute_bool("mouse_wheel_opaque", mMouseWheelOpaque);
|
||||
}
|
||||
|
||||
if (node->hasAttribute("menu_file"))
|
||||
if (node->hasAttribute("menu_num"))
|
||||
{
|
||||
// Some scroll lists use common menus identified by number
|
||||
// 0 is menu_avs_list.xml, 1 will be for groups, 2 could be for lists of objects
|
||||
S32 menu_num;
|
||||
node->getAttributeS32("menu_num", menu_num);
|
||||
mPopupMenu = sScrollListMenus[menu_num];
|
||||
}
|
||||
else if (node->hasAttribute("menu_file"))
|
||||
{
|
||||
std::string menu_file;
|
||||
node->getAttributeString("menu_file", menu_file);
|
||||
|
||||
@@ -388,7 +388,7 @@ LLWindow* LLWindowManager::createWindow(
|
||||
const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags,
|
||||
BOOL fullscreen,
|
||||
BOOL clearBg,
|
||||
BOOL disable_vsync,
|
||||
const S32 vsync_mode,
|
||||
BOOL use_gl,
|
||||
BOOL ignore_pixel_depth,
|
||||
U32 fsaa_samples)
|
||||
@@ -400,26 +400,26 @@ LLWindow* LLWindowManager::createWindow(
|
||||
#if LL_MESA_HEADLESS
|
||||
new_window = new LLWindowMesaHeadless(callbacks,
|
||||
title, name, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth);
|
||||
fullscreen, clearBg, vsync_mode, ignore_pixel_depth);
|
||||
#elif LL_SDL
|
||||
new_window = new LLWindowSDL(callbacks,
|
||||
title, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples);
|
||||
fullscreen, clearBg, vsync_mode, ignore_pixel_depth, fsaa_samples);
|
||||
#elif LL_WINDOWS
|
||||
new_window = new LLWindowWin32(callbacks,
|
||||
title, name, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples);
|
||||
fullscreen, clearBg, vsync_mode, ignore_pixel_depth, fsaa_samples);
|
||||
#elif LL_DARWIN
|
||||
new_window = new LLWindowMacOSX(callbacks,
|
||||
title, name, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples);
|
||||
fullscreen, clearBg, vsync_mode, ignore_pixel_depth, fsaa_samples);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
new_window = new LLWindowHeadless(callbacks,
|
||||
title, name, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth);
|
||||
fullscreen, clearBg, vsync_mode, ignore_pixel_depth);
|
||||
}
|
||||
|
||||
if (FALSE == new_window->isValid())
|
||||
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
BOOL setSize(LLCoordScreen size);
|
||||
BOOL setSize(LLCoordWindow size);
|
||||
virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true);
|
||||
virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) = 0;
|
||||
virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL) = 0;
|
||||
virtual BOOL setCursorPosition(LLCoordWindow position) = 0;
|
||||
virtual BOOL getCursorPosition(LLCoordWindow *position) = 0;
|
||||
virtual void showCursor() = 0;
|
||||
@@ -121,6 +121,8 @@ public:
|
||||
virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma
|
||||
virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples
|
||||
virtual U32 getFSAASamples() = 0;
|
||||
virtual void setVsyncMode(const S32 vsync_mode) = 0;
|
||||
virtual S32 getVsyncMode() = 0;
|
||||
virtual BOOL restoreGamma() = 0; // Restore original gamma table (before updating gamma)
|
||||
virtual ESwapMethod getSwapMethod() { return mSwapMethod; }
|
||||
virtual void processMiscNativeEvents();
|
||||
@@ -274,7 +276,7 @@ public:
|
||||
U32 flags = 0,
|
||||
BOOL fullscreen = FALSE,
|
||||
BOOL clearBg = FALSE,
|
||||
BOOL disable_vsync = TRUE,
|
||||
const S32 vsync_mode = 0,
|
||||
BOOL use_gl = TRUE,
|
||||
BOOL ignore_pixel_depth = FALSE,
|
||||
U32 fsaa_samples = 0);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
//
|
||||
LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
|
||||
U32 flags, BOOL fullscreen, BOOL clear_background,
|
||||
BOOL disable_vsync, BOOL ignore_pixel_depth)
|
||||
const S32 vsync_mode, BOOL ignore_pixel_depth)
|
||||
: LLWindow(callbacks, fullscreen, flags)
|
||||
{
|
||||
// Initialize a headless keyboard.
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;};
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;};
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;};
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;};
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL) {return FALSE;};
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
|
||||
/*virtual*/ void showCursor() {};
|
||||
@@ -69,6 +69,8 @@ public:
|
||||
/*virtual*/ BOOL setGamma(const F32 gamma) {return FALSE; }; // Set the gamma
|
||||
/*virtual*/ void setFSAASamples(const U32 fsaa_samples) { }
|
||||
/*virtual*/ U32 getFSAASamples() { return 0; }
|
||||
/*virtual*/ void setVsyncMode(const S32 vsync_mode) {}
|
||||
/*virtual*/ S32 getVsyncMode() { return 0; }
|
||||
/*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma)
|
||||
//virtual ESwapMethod getSwapMethod() { return mSwapMethod; }
|
||||
/*virtual*/ void gatherInput() {};
|
||||
@@ -96,7 +98,7 @@ public:
|
||||
S32 x, S32 y,
|
||||
S32 width, S32 height,
|
||||
U32 flags, BOOL fullscreen, BOOL clear_background,
|
||||
BOOL disable_vsync, BOOL ignore_pixel_depth);
|
||||
const S32 vsync_mode, BOOL ignore_pixel_depth);
|
||||
virtual ~LLWindowHeadless();
|
||||
|
||||
private:
|
||||
|
||||
@@ -210,7 +210,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
|
||||
S32 height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync,
|
||||
const S32 vsync_mode,
|
||||
BOOL ignore_pixel_depth,
|
||||
U32 fsaa_samples)
|
||||
: LLWindow(NULL, fullscreen, flags)
|
||||
@@ -253,6 +253,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
|
||||
mPreeditor = NULL;
|
||||
mRawKeyEvent = NULL;
|
||||
mFSAASamples = fsaa_samples;
|
||||
mVsyncMode = vsync_mode;
|
||||
mForceRebuild = FALSE;
|
||||
|
||||
// For reasons that aren't clear to me, LLTimers seem to be created in the "started" state.
|
||||
@@ -283,7 +284,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
|
||||
gWindowImplementation = this;
|
||||
|
||||
// Create the GL context and set it up for windowed or fullscreen, as appropriate.
|
||||
if(createContext(x, y, width, height, 32, fullscreen, disable_vsync))
|
||||
if(createContext(x, y, width, height, 32, fullscreen, vsync_mode))
|
||||
{
|
||||
if(mWindow != NULL)
|
||||
{
|
||||
@@ -323,7 +324,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync)
|
||||
BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode)
|
||||
{
|
||||
OSStatus err;
|
||||
BOOL glNeedsInit = FALSE;
|
||||
@@ -780,7 +781,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
|
||||
|
||||
// Disable vertical sync for swap
|
||||
GLint frames_per_swap = 0;
|
||||
if (disable_vsync)
|
||||
if (vsync_mode != 1)
|
||||
{
|
||||
LL_DEBUGS("GLInit") << "Disabling vertical sync" << LL_ENDL;
|
||||
frames_per_swap = 0;
|
||||
@@ -816,7 +817,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
|
||||
|
||||
|
||||
// changing fullscreen resolution, or switching between windowed and fullscreen mode.
|
||||
BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
|
||||
BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp)
|
||||
{
|
||||
BOOL needsRebuild = FALSE;
|
||||
BOOL result = true;
|
||||
@@ -892,7 +893,7 @@ BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, B
|
||||
{
|
||||
mForceRebuild = FALSE;
|
||||
destroyContext();
|
||||
result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync);
|
||||
result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, vsync_mode);
|
||||
if (result)
|
||||
{
|
||||
if(mWindow != NULL)
|
||||
@@ -1341,6 +1342,16 @@ void LLWindowMacOSX::setFSAASamples(const U32 samples)
|
||||
mForceRebuild = TRUE;
|
||||
}
|
||||
|
||||
S32 LLWindowMacOSX::getVsyncMode()
|
||||
{
|
||||
return mVsyncMode;
|
||||
}
|
||||
void LLWindowMacOSX::setVsyncMode(const S32 vsync_mode)
|
||||
{
|
||||
mVsyncMode = vsync_mode;
|
||||
mForceRebuild = TRUE;
|
||||
}
|
||||
|
||||
BOOL LLWindowMacOSX::restoreGamma()
|
||||
{
|
||||
CGDisplayRestoreColorSyncSettings();
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL);
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
|
||||
/*virtual*/ void showCursor();
|
||||
@@ -81,6 +81,8 @@ public:
|
||||
/*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma
|
||||
/*virtual*/ U32 getFSAASamples();
|
||||
/*virtual*/ void setFSAASamples(const U32 fsaa_samples);
|
||||
/*virtual*/ void setVsyncMode(const S32 vsync_mode);
|
||||
/*virtual*/ S32 getVsyncMode();
|
||||
/*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma)
|
||||
/*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; }
|
||||
/*virtual*/ void gatherInput();
|
||||
@@ -124,7 +126,7 @@ public:
|
||||
protected:
|
||||
LLWindowMacOSX(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg, BOOL disable_vsync,
|
||||
BOOL fullscreen, BOOL clearBg, const S32 vsync_mode,
|
||||
BOOL ignore_pixel_depth,
|
||||
U32 fsaa_samples);
|
||||
~LLWindowMacOSX();
|
||||
@@ -152,7 +154,7 @@ protected:
|
||||
//
|
||||
|
||||
// create or re-create the GL context/window. Called from the constructor and switchContext().
|
||||
BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync);
|
||||
BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode);
|
||||
void destroyContext();
|
||||
void setupFailure(const std::string& text, const std::string& caption, U32 type);
|
||||
static pascal OSStatus staticEventHandler (EventHandlerCallRef myHandler, EventRef event, void* userData);
|
||||
@@ -201,6 +203,7 @@ protected:
|
||||
BOOL mMaximized;
|
||||
BOOL mMinimized;
|
||||
U32 mFSAASamples;
|
||||
S32 mVsyncMode;
|
||||
BOOL mForceRebuild;
|
||||
|
||||
S32 mDragOverrideCursor;
|
||||
|
||||
@@ -41,7 +41,7 @@ U16 *gMesaBuffer = NULL;
|
||||
LLWindowMesaHeadless::LLWindowMesaHeadless(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
|
||||
U32 flags, BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync, BOOL ignore_pixel_depth)
|
||||
const S32 vsync_mode, BOOL ignore_pixel_depth)
|
||||
: LLWindow(callbacks, fullscreen, flags)
|
||||
{
|
||||
llinfos << "MESA Init" << llendl;
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;};
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;};
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;};
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;};
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL) {return FALSE;};
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
|
||||
/*virtual*/ void showCursor() {};
|
||||
@@ -74,6 +74,8 @@ public:
|
||||
/*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma)
|
||||
/*virtual*/ void setFSAASamples(const U32 fsaa_samples) { /* FSAA not supported yet on Mesa headless.*/ }
|
||||
/*virtual*/ U32 getFSAASamples() { return 0; }
|
||||
/*virtual*/ void setVsyncMode(const S32 vsync_mode) {}
|
||||
/*virtual*/ S32 getVsyncMode() { return 0; }
|
||||
//virtual ESwapMethod getSwapMethod() { return mSwapMethod; }
|
||||
/*virtual*/ void gatherInput() {};
|
||||
/*virtual*/ void delayInputProcessing() {};
|
||||
@@ -98,7 +100,7 @@ public:
|
||||
LLWindowMesaHeadless(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
|
||||
U32 flags, BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync, BOOL ignore_pixel_depth);
|
||||
const S32 vsync_mode, BOOL ignore_pixel_depth);
|
||||
~LLWindowMesaHeadless();
|
||||
|
||||
private:
|
||||
|
||||
@@ -192,7 +192,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, S32 x, S32 y, S32 width,
|
||||
S32 height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync,
|
||||
const S32 vsync_mode,
|
||||
BOOL ignore_pixel_depth, U32 fsaa_samples)
|
||||
: LLWindow(callbacks, fullscreen, flags),
|
||||
Lock_Display(NULL),
|
||||
@@ -233,7 +233,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,
|
||||
mWindowTitle = title;
|
||||
|
||||
// Create the GL context and set it up for windowed or fullscreen, as appropriate.
|
||||
if(createContext(x, y, width, height, 32, fullscreen, disable_vsync))
|
||||
if(createContext(x, y, width, height, 32, fullscreen, vsync_mode))
|
||||
{
|
||||
gGLManager.initGL();
|
||||
|
||||
@@ -373,7 +373,7 @@ static int x11_detect_VRAM_kb()
|
||||
}
|
||||
#endif // LL_X11
|
||||
|
||||
BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync)
|
||||
BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode)
|
||||
{
|
||||
//bool glneedsinit = false;
|
||||
|
||||
@@ -721,6 +721,50 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B
|
||||
}
|
||||
#endif // LL_X11
|
||||
|
||||
#if SDL_VERSION_ATLEAST(1,3,0)
|
||||
// Disable vertical sync for swap
|
||||
if (vsync_mode == 0)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL;
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
}
|
||||
else if(vsync_mode == -1)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Enabling adaptive vertical sync" << LL_ENDL;
|
||||
if(SDL_GL_SetSwapInterval(-1) == -1)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Failed to enable adaptive vertical sync. Disabling vsync." << LL_ENDL;
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Window") << "Enabling vertical sync" << LL_ENDL;
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
}
|
||||
#else // SDL_VERSION_ATLEAST(1,3,0)
|
||||
#ifdef SDL_GL_SWAP_CONTROL
|
||||
if (vsync_mode == 0)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL;
|
||||
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0);
|
||||
}
|
||||
else if(vsync_mode == -1)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Enabling adaptive vertical sync" << LL_ENDL;
|
||||
if(SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, -1) == -1)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Failed to enable adaptive vertical sync. Disabling vsync." << LL_ENDL;
|
||||
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Window") << "Enabling vertical sync" << LL_ENDL;
|
||||
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
|
||||
}
|
||||
#endif // SDL_GL_SWAP_CONTROL
|
||||
#endif // SDL_VERSION_ATLEAST(1,3,0)
|
||||
|
||||
//make sure multisampling is disabled by default
|
||||
glDisable(GL_MULTISAMPLE_ARB);
|
||||
@@ -736,7 +780,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B
|
||||
|
||||
|
||||
// changing fullscreen resolution, or switching between windowed and fullscreen mode.
|
||||
BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
|
||||
BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp)
|
||||
{
|
||||
const BOOL needsRebuild = TRUE; // Just nuke the context and start over.
|
||||
BOOL result = true;
|
||||
@@ -746,7 +790,7 @@ BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL
|
||||
if(needsRebuild)
|
||||
{
|
||||
destroyContext();
|
||||
result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync);
|
||||
result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, vsync_mode);
|
||||
if (result)
|
||||
{
|
||||
gGLManager.initGL();
|
||||
@@ -987,6 +1031,16 @@ void LLWindowSDL::setFSAASamples(const U32 samples)
|
||||
mFSAASamples = samples;
|
||||
}
|
||||
|
||||
S32 LLWindowSDL::getVsyncMode()
|
||||
{
|
||||
return mVsyncMode;
|
||||
}
|
||||
|
||||
void LLWindowSDL::setVsyncMode(const S32 vsync_mode)
|
||||
{
|
||||
mVsyncMode = vsync_mode;
|
||||
}
|
||||
|
||||
F32 LLWindowSDL::getGamma()
|
||||
{
|
||||
return 1/mGamma;
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL);
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
|
||||
/*virtual*/ void showCursor();
|
||||
@@ -92,6 +92,8 @@ public:
|
||||
/*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma
|
||||
/*virtual*/ U32 getFSAASamples();
|
||||
/*virtual*/ void setFSAASamples(const U32 samples);
|
||||
/*virtual*/ void setVsyncMode(const S32 vsync_mode);
|
||||
/*virtual*/ S32 getVsyncMode();
|
||||
/*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma)
|
||||
/*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; }
|
||||
/*virtual*/ void processMiscNativeEvents();
|
||||
@@ -149,7 +151,7 @@ public:
|
||||
protected:
|
||||
LLWindowSDL(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, int x, int y, int width, int height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg, BOOL disable_vsync,
|
||||
BOOL fullscreen, BOOL clearBg, const S32 vsync_mode,
|
||||
BOOL ignore_pixel_depth, U32 fsaa_samples);
|
||||
~LLWindowSDL();
|
||||
|
||||
@@ -174,7 +176,7 @@ protected:
|
||||
//
|
||||
|
||||
// create or re-create the GL context/window. Called from the constructor and switchContext().
|
||||
BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync);
|
||||
BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode);
|
||||
void destroyContext();
|
||||
void setupFailure(const std::string& text, const std::string& caption, U32 type);
|
||||
void fixWindowSize(void);
|
||||
@@ -194,6 +196,7 @@ protected:
|
||||
F32 mOverrideAspectRatio;
|
||||
F32 mGamma;
|
||||
U32 mFSAASamples;
|
||||
S32 mVsyncMode;
|
||||
|
||||
int mSDLFlags;
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
|
||||
S32 height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync,
|
||||
const S32 vsync_mode,
|
||||
BOOL ignore_pixel_depth,
|
||||
U32 fsaa_samples)
|
||||
: LLWindow(callbacks, fullscreen, flags)
|
||||
@@ -903,7 +903,7 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size)
|
||||
}
|
||||
|
||||
// changing fullscreen resolution
|
||||
BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
|
||||
BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp)
|
||||
{
|
||||
GLuint pixel_format;
|
||||
DEVMODE dev_mode;
|
||||
@@ -1650,14 +1650,27 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
|
||||
}
|
||||
|
||||
// Disable vertical sync for swap
|
||||
if (disable_vsync && wglSwapIntervalEXT)
|
||||
if(wglSwapIntervalEXT)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL;
|
||||
wglSwapIntervalEXT(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL;
|
||||
if (vsync_mode == 0)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL;
|
||||
wglSwapIntervalEXT(0);
|
||||
}
|
||||
else if(vsync_mode == -1)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Enabling adaptive vertical sync" << LL_ENDL;
|
||||
if(wglSwapIntervalEXT(-1) == 0)
|
||||
{
|
||||
LL_DEBUGS("Window") << "Failed to enable adaptive vertical sync. Disabling vsync." << LL_ENDL;
|
||||
wglSwapIntervalEXT(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Window") << "Enabling vertical sync" << LL_ENDL;
|
||||
wglSwapIntervalEXT(1);
|
||||
}
|
||||
}
|
||||
|
||||
SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this);
|
||||
@@ -3030,6 +3043,16 @@ U32 LLWindowWin32::getFSAASamples()
|
||||
return mFSAASamples;
|
||||
}
|
||||
|
||||
S32 LLWindowWin32::getVsyncMode()
|
||||
{
|
||||
return mVsyncMode;
|
||||
}
|
||||
|
||||
void LLWindowWin32::setVsyncMode(const S32 vsync_mode)
|
||||
{
|
||||
mVsyncMode = vsync_mode;
|
||||
}
|
||||
|
||||
LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions)
|
||||
{
|
||||
if (!mSupportedResolutions)
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, const LLCoordScreen * const posp = NULL);
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
|
||||
/*virtual*/ void showCursor();
|
||||
@@ -80,6 +80,8 @@ public:
|
||||
/*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma
|
||||
/*virtual*/ void setFSAASamples(const U32 fsaa_samples);
|
||||
/*virtual*/ U32 getFSAASamples();
|
||||
/*virtual*/ void setVsyncMode(const S32 vsync_mode);
|
||||
/*virtual*/ S32 getVsyncMode();
|
||||
/*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma)
|
||||
/*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; }
|
||||
/*virtual*/ void gatherInput();
|
||||
@@ -121,7 +123,7 @@ public:
|
||||
protected:
|
||||
LLWindowWin32(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg, BOOL disable_vsync,
|
||||
BOOL fullscreen, BOOL clearBg, const S32 vsync_mode,
|
||||
BOOL ignore_pixel_depth, U32 fsaa_samples);
|
||||
~LLWindowWin32();
|
||||
|
||||
@@ -186,6 +188,7 @@ protected:
|
||||
|
||||
F32 mCurrentGamma;
|
||||
U32 mFSAASamples;
|
||||
S32 mVsyncMode;
|
||||
WORD mPrevGammaRamp[256*3];
|
||||
WORD mCurrentGammaRamp[256*3];
|
||||
|
||||
|
||||
@@ -126,6 +126,7 @@ set(viewer_SOURCE_FILES
|
||||
llassetuploadresponders.cpp
|
||||
llattachmentsmgr.cpp
|
||||
llaudiosourcevo.cpp
|
||||
llautoreplace.cpp
|
||||
llavataractions.cpp
|
||||
llavatarpropertiesprocessor.cpp
|
||||
llbox.cpp
|
||||
@@ -181,6 +182,7 @@ set(viewer_SOURCE_FILES
|
||||
llfloaterabout.cpp
|
||||
llfloateractivespeakers.cpp
|
||||
llfloaterauction.cpp
|
||||
llfloaterautoreplacesettings.cpp
|
||||
llfloateravatarinfo.cpp
|
||||
llfloateravatarlist.cpp
|
||||
llfloateravatarpicker.cpp
|
||||
@@ -574,9 +576,10 @@ set(viewer_SOURCE_FILES
|
||||
noise.cpp
|
||||
pipeline.cpp
|
||||
qtoolalign.cpp
|
||||
rlvactions.cpp
|
||||
rlvcommon.cpp
|
||||
rlvextensions.cpp
|
||||
rlvfloaterbehaviour.cpp
|
||||
rlvfloaters.cpp
|
||||
rlvhandler.cpp
|
||||
rlvhelper.cpp
|
||||
rlvinventory.cpp
|
||||
@@ -645,6 +648,7 @@ set(viewer_HEADER_FILES
|
||||
llassetuploadresponders.h
|
||||
llattachmentsmgr.h
|
||||
llaudiosourcevo.h
|
||||
llautoreplace.h
|
||||
llavataractions.h
|
||||
llavatarpropertiesprocessor.h
|
||||
llbox.h
|
||||
@@ -700,6 +704,7 @@ set(viewer_HEADER_FILES
|
||||
llfloaterabout.h
|
||||
llfloateractivespeakers.h
|
||||
llfloaterauction.h
|
||||
llfloaterautoreplacesettings.h
|
||||
llfloateravatarinfo.h
|
||||
llfloateravatarlist.h
|
||||
llfloateravatarpicker.h
|
||||
@@ -1100,10 +1105,11 @@ set(viewer_HEADER_FILES
|
||||
noise.h
|
||||
pipeline.h
|
||||
qtoolalign.h
|
||||
rlvactions.h
|
||||
rlvcommon.h
|
||||
rlvdefines.h
|
||||
rlvextensions.h
|
||||
rlvfloaterbehaviour.h
|
||||
rlvfloaters.h
|
||||
rlvhandler.h
|
||||
rlvhelper.h
|
||||
rlvinventory.h
|
||||
@@ -1138,7 +1144,7 @@ if (DARWIN)
|
||||
|
||||
# Add resource files to the project.
|
||||
set(viewer_RESOURCE_FILES
|
||||
${VIEWER_BRANDING_ID}.icns
|
||||
${VIEWER_BRANDING_ID}_icon.icns
|
||||
macview.r
|
||||
gpu_table.txt
|
||||
SecondLife.nib/
|
||||
@@ -1516,7 +1522,7 @@ if (WINDOWS)
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
ARGS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
|
||||
--arch=${ARCH}
|
||||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
--branding_id=${VIEWER_BRANDING_ID}
|
||||
--build=${CMAKE_CURRENT_BINARY_DIR}
|
||||
@@ -1538,7 +1544,7 @@ if (WINDOWS)
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
ARGS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
|
||||
--arch=${ARCH}
|
||||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
--actions=copy
|
||||
--branding_id=${VIEWER_BRANDING_ID}
|
||||
@@ -1700,7 +1706,7 @@ if (DARWIN)
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "${product}"
|
||||
MACOSX_BUNDLE_INFO_STRING "A stable third-party Second Life viewer."
|
||||
MACOSX_BUNDLE_ICON_FILE "${VIEWER_BRANDING_ID}.icns"
|
||||
MACOSX_BUNDLE_ICON_FILE "${VIEWER_BRANDING_ID}_icon.icns"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "${VIEWER_BRANDING_NAME}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${viewer_VERSION}"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "${VIEWER_BRANDING_NAME}"
|
||||
|
||||
@@ -310,16 +310,12 @@ U32 AIHTTPView::updateColumn(U32 col, U32 start)
|
||||
return mStartColumn[col];
|
||||
}
|
||||
|
||||
//static
|
||||
void AIHTTPView::toggle_visibility(void* user_data)
|
||||
// virtual
|
||||
void AIHTTPView::setVisible(BOOL visible)
|
||||
{
|
||||
LLView* viewp = (LLView*)user_data;
|
||||
bool visible = !viewp->getVisible();
|
||||
if (visible)
|
||||
{
|
||||
AIPerService::resetUsed();
|
||||
}
|
||||
viewp->setVisible(visible);
|
||||
if (visible && visible != getVisible())
|
||||
AIPerService::resetUsed();
|
||||
LLContainerView::setVisible(visible);
|
||||
}
|
||||
|
||||
U64 AIHTTPView::sTime_40ms;
|
||||
|
||||
@@ -49,6 +49,7 @@ class AIHTTPView : public LLContainerView
|
||||
~AIHTTPView();
|
||||
|
||||
/*virtual*/ void draw(void);
|
||||
/*virtual*/ void setVisible(BOOL visible);
|
||||
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
|
||||
|
||||
@@ -66,7 +67,6 @@ class AIHTTPView : public LLContainerView
|
||||
|
||||
public:
|
||||
static U64 getTime_40ms(void) { return sTime_40ms; }
|
||||
static void toggle_visibility(void* user_data);
|
||||
};
|
||||
|
||||
extern AIHTTPView *gHttpView;
|
||||
|
||||
8330
indra/newview/app_settings/autoreplace.xml
Normal file
8330
indra/newview/app_settings/autoreplace.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@
|
||||
<key>SGAllowRiggedMeshSelection</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Allow selection of your worn rigged meshes in build mode</string>
|
||||
<string>Allow selection of worn rigged meshes in build or inspect mode</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
@@ -573,7 +573,7 @@
|
||||
<key>CheckForGridUpdates</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Fetch list of grids from Hippo server</string>
|
||||
<string>Fetch list of grids from location set in GridUpdateList</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
@@ -592,6 +592,17 @@
|
||||
<key>Value</key>
|
||||
<string>Second Life</string>
|
||||
</map>
|
||||
<key>GridUpdateList</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>URL to fetch Grid updates from</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string/>
|
||||
</map>
|
||||
|
||||
<key>VivoxLicenseAccepted</key>
|
||||
<map>
|
||||
@@ -651,6 +662,22 @@
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LiruCrosshairColor</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Color of crosshairs in mouselook</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Color4</string>
|
||||
<key>Value</key>
|
||||
<array>
|
||||
<real>1.0</real>
|
||||
<real>1.0</real>
|
||||
<real>1.0</real>
|
||||
<real>1.0</real>
|
||||
</array>
|
||||
</map>
|
||||
<key>LiruGridInTitle</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -719,6 +746,17 @@
|
||||
<key>Value</key>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>LiruLegacyOutfitAllLinks</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Legacy outfits in clothing folder, completely made of links.. no other settings will apply for legacy outfits as they'll all be links.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>LiruLegacyOutfitStoreObjChanges</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -730,17 +768,6 @@
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>LiruLegacySpeakerNames</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether all lists of speakers use legacy names, or your desired way of displaying names.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LiruLocalTime</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -763,6 +790,17 @@
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LiruMiniBuildFloater</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not the build tools floater is tinified (except in Land tool)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>LiruMouselookHidesFloaters</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -796,6 +834,17 @@
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>LiruMouselookHidesToolbar</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not the toolbar will be hidden in mouselook</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>LiruMouselookMenu</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -979,6 +1028,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>LocalBitmapUpdate</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Default setting for whether local textures should update or not upon change, changed by toggling on or off.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>InstantMessageLogPathAnyAccount</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -990,6 +1050,32 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<string/>
|
||||
</map>
|
||||
<key>ScriptMessageAPI</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Channel used for interaction with the Script Message API</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<key>IsCOA</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>ScriptMessageAPIKey</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Key to encode messages sent to the Script Message API</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>Enter Key Here</string>
|
||||
<key>IsCOA</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>UseConciseIMButtons</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -2618,6 +2704,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>AutoReplace</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Replaces keywords with a configured word or phrase</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>AutoAcceptAllNewInventory</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -6021,6 +6118,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>DoubleClickShowWorldMap</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable double-click to show world map from mini map</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>DragAndDropToolTipDelay</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -8402,7 +8510,7 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>ForceMandatoryUpdate</key>
|
||||
<map>
|
||||
@@ -10139,6 +10247,28 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>MiniMapCollisionParcels</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Show collision parcels on the mini-map as they become available</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>MiniMapForSaleParcels</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Show for-sale parcels with a yellow highlight on the mini-map</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>MiniMapPrimMaxAltitudeDelta</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -10172,6 +10302,28 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<real>256.0</real>
|
||||
</map>
|
||||
<key>MiniMapPropertyLines</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Show property boundaries on the mini-map</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>MiniMapRadarTrackingCircles</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Show tracking circles around the avatars you've selected on the radar in the minimap</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>MiniMapCenter</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -10286,6 +10438,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<real>128.0</real>
|
||||
</map>
|
||||
<key>MiniMapWorldMapTextures</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use the world map texture tile on the mini-map rather than the terrain texture</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>MouseSensitivity</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -16487,7 +16650,7 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>-1</string>
|
||||
<string>0</string>
|
||||
</map>
|
||||
<key>VivoxDebugSIPURIHostName</key>
|
||||
<map>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>RestrainedLoveDebug</key>
|
||||
<map>
|
||||
@@ -22,7 +22,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RestrainedLoveCanOOC</key>
|
||||
<map>
|
||||
@@ -33,7 +33,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>RestrainedLoveForbidGiveToRLV</key>
|
||||
<map>
|
||||
@@ -44,7 +44,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RestrainedLoveNoSetEnv</key>
|
||||
<map>
|
||||
@@ -55,19 +55,8 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RestrainedLoveOffsetAvatarZ</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Offset the avatar.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>0.0</real>
|
||||
</map>
|
||||
<key>RestrainedLoveReplaceWhenFolderBeginsWith</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -88,7 +77,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>RestrainedLoveStackWhenFolderBeginsWith</key>
|
||||
<map>
|
||||
@@ -110,7 +99,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RLVaEnableCompositeFolders</key>
|
||||
<map>
|
||||
@@ -121,7 +110,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RLVaEnableLegacyNaming</key>
|
||||
<map>
|
||||
@@ -132,7 +121,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>RLVaEnableSharedWear</key>
|
||||
<map>
|
||||
@@ -143,7 +132,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>RLVaHideLockedLayers</key>
|
||||
<map>
|
||||
@@ -154,7 +143,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RLVaHideLockedAttachments</key>
|
||||
<map>
|
||||
@@ -165,7 +154,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RLVaSharedInvAutoRename</key>
|
||||
<map>
|
||||
@@ -176,7 +165,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>RLVaShowAssertionFailures</key>
|
||||
<map>
|
||||
@@ -187,7 +176,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>RLVaShowNameTags</key>
|
||||
<map>
|
||||
@@ -198,7 +187,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RLVaTopLevelMenu</key>
|
||||
<map>
|
||||
@@ -209,7 +198,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RLVaWearReplaceUnlocked</key>
|
||||
<map>
|
||||
@@ -220,18 +209,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>WarnFirstRLVGiveToRLV</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enables FirstRLVGiveToRLV warning dialog</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>ForceInitialCOFDelay</key>
|
||||
<map>
|
||||
|
||||
@@ -240,5 +240,27 @@
|
||||
<key>Value</key>
|
||||
<real>.5</real>
|
||||
</map>
|
||||
<key>SHAltBatching</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Experimental retooling of face batching.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<real>1</real>
|
||||
</map>
|
||||
<key>SHRenderVsyncMode</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Desired vertical sychronization method. (0 = Disabled, 1 = Standard [Double-buffered], -1 = Adaptive [if supported])</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<real>0</real>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
||||
@@ -26,6 +26,7 @@ ATTRIBUTE vec4 weight4;
|
||||
|
||||
uniform mat3 matrixPalette[52];
|
||||
uniform vec3 translationPalette[52];
|
||||
uniform float maxWeight;
|
||||
|
||||
mat4 getObjectSkinnedTransform()
|
||||
{
|
||||
@@ -34,7 +35,7 @@ mat4 getObjectSkinnedTransform()
|
||||
vec4 w = fract(weight4);
|
||||
vec4 index = floor(weight4);
|
||||
|
||||
index = min(index, vec4(51.0));
|
||||
index = min(index, vec4(maxWeight));
|
||||
index = max(index, vec4( 0.0));
|
||||
|
||||
float scale = 1.0/(w.x+w.y+w.z+w.w);
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "llagent.h"
|
||||
#include "llcolorswatch.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llfloaterautoreplacesettings.h"
|
||||
#include "llradiogroup.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewercontrol.h"
|
||||
@@ -92,6 +93,7 @@ LLPrefsAscentChat::LLPrefsAscentChat()
|
||||
getChild<LLUICtrl>("antispam_checkbox")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitDialogBlock, this, _1, _2));
|
||||
getChild<LLUICtrl>("Group Invites")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitDialogBlock, this, _1, _2));
|
||||
|
||||
getChild<LLUICtrl>("autoreplace")->setCommitCallback(boost::bind(LLFloaterAutoReplaceSettings::showInstance, LLSD()));
|
||||
getChild<LLUICtrl>("KeywordsOn")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1));
|
||||
getChild<LLUICtrl>("KeywordsList")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1));
|
||||
getChild<LLUICtrl>("KeywordsSound")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1));
|
||||
@@ -298,7 +300,11 @@ void LLPrefsAscentChat::refreshValues()
|
||||
mOnlyComm = gSavedSettings.getBOOL("CommunicateSpecificShortcut");
|
||||
mItalicizeActions = gSavedSettings.getBOOL("LiruItalicizeActions");
|
||||
mLegacyLogLaunch = gSavedSettings.getBOOL("LiruLegacyLogLaunch");
|
||||
mLegacySpeakerNames = gSavedSettings.getBOOL("LiruLegacySpeakerNames");
|
||||
mFriendNames = gSavedSettings.getS32("FriendNameSystem");
|
||||
mGroupMembersNames = gSavedSettings.getS32("GroupMembersNameSystem");
|
||||
mLandManagementNames = gSavedSettings.getS32("LandManagementNameSystem");
|
||||
mRadarNames = gSavedSettings.getS32("RadarNameSystem");
|
||||
mSpeakerNames = gSavedSettings.getS32("SpeakerNameSystem");
|
||||
|
||||
//Autoresponse ------------------------------------------------------------------------
|
||||
mIMResponseAnyoneItemID = gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID");
|
||||
@@ -376,6 +382,18 @@ void LLPrefsAscentChat::refresh()
|
||||
combo->setCurrentByIndex(mDateFormat);
|
||||
}
|
||||
|
||||
//Chat UI -----------------------------------------------------------------------------
|
||||
if (combo = getChild<LLComboBox>("friends_namesystem_combobox"))
|
||||
combo->setCurrentByIndex(mFriendNames);
|
||||
if (combo = getChild<LLComboBox>("group_members_namesystem_combobox"))
|
||||
combo->setCurrentByIndex(mGroupMembersNames);
|
||||
if (combo = getChild<LLComboBox>("land_management_namesystem_combobox"))
|
||||
combo->setCurrentByIndex(mLandManagementNames);
|
||||
if (combo = getChild<LLComboBox>("radar_namesystem_combobox"))
|
||||
combo->setCurrentByIndex(mRadarNames);
|
||||
if (combo = getChild<LLComboBox>("speaker_namesystem_combobox"))
|
||||
combo->setCurrentByIndex(mSpeakerNames);
|
||||
|
||||
//Antispam ------------------------------------------------------------------------
|
||||
// sensitivity tuners
|
||||
childSetEnabled("spammsg_checkbox", mEnableAS);
|
||||
@@ -537,7 +555,11 @@ void LLPrefsAscentChat::cancel()
|
||||
gSavedSettings.setBOOL("CommunicateSpecificShortcut", mOnlyComm);
|
||||
gSavedSettings.setBOOL("LiruItalicizeActions", mItalicizeActions);
|
||||
gSavedSettings.setBOOL("LiruLegacyLogLaunch", mLegacyLogLaunch);
|
||||
gSavedSettings.setBOOL("LiruLegacySpeakerNames", mLegacySpeakerNames);
|
||||
gSavedSettings.setS32("FriendNameSystem", mFriendNames);
|
||||
gSavedSettings.setS32("GroupMembersNameSystem", mGroupMembersNames);
|
||||
gSavedSettings.setS32("LandManagementNameSystem", mLandManagementNames);
|
||||
gSavedSettings.setS32("RadarNameSystem", mRadarNames);
|
||||
gSavedSettings.setS32("SpeakerNameSystem", mSpeakerNames);
|
||||
|
||||
//Autoresponse ------------------------------------------------------------------------
|
||||
gSavedPerAccountSettings.setString("AutoresponseAnyoneItemID", mIMResponseAnyoneItemID);
|
||||
|
||||
@@ -87,8 +87,12 @@ private:
|
||||
bool mOneLineConfButt;
|
||||
bool mOnlyComm;
|
||||
bool mItalicizeActions;
|
||||
bool mLegacySpeakerNames;
|
||||
bool mLegacyLogLaunch;
|
||||
S32 mFriendNames;
|
||||
S32 mGroupMembersNames;
|
||||
S32 mLandManagementNames;
|
||||
S32 mRadarNames;
|
||||
S32 mSpeakerNames;
|
||||
|
||||
//Autoresponse ------------------------------------------------------------------------
|
||||
std::string mIMResponseAnyoneItemID;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -98,7 +98,7 @@ class LocalBitmap
|
||||
{
|
||||
public:
|
||||
LocalBitmap(std::string filename);
|
||||
virtual ~LocalBitmap(void);
|
||||
virtual ~LocalBitmap();
|
||||
friend class LocalAssetBrowser;
|
||||
|
||||
public: /* [enums, typedefs, etc] */
|
||||
@@ -127,23 +127,22 @@ class LocalBitmap
|
||||
};
|
||||
|
||||
public: /* [information query functions] */
|
||||
std::string getShortName(void);
|
||||
std::string getFileName(void);
|
||||
LLUUID getID(void);
|
||||
LLSD getLastModified(void);
|
||||
std::string getLinkStatus(void);
|
||||
bool getUpdateBool(void);
|
||||
std::string getShortName();
|
||||
std::string getFileName();
|
||||
LLUUID getID();
|
||||
LLSD getLastModified();
|
||||
std::string getLinkStatus();
|
||||
bool getUpdateBool();
|
||||
void setType( S32 );
|
||||
bool getIfValidBool(void);
|
||||
S32 getType(void);
|
||||
void getDebugInfo(void);
|
||||
bool getIfValidBool();
|
||||
S32 getType();
|
||||
void getDebugInfo();
|
||||
|
||||
private: /* [maintenence functions] */
|
||||
void updateSelf(void);
|
||||
void updateSelf();
|
||||
bool decodeSelf(LLImageRaw* rawimg);
|
||||
void setUpdateBool(void);
|
||||
void setUpdateBool();
|
||||
|
||||
LocalBitmap* getThis(void);
|
||||
std::vector<LLFace*> getFaceUsesThis(LLDrawable*);
|
||||
std::vector<affected_object> getUsingObjects(bool seek_by_type = true,
|
||||
bool seek_textures = false, bool seek_sculptmaps = false);
|
||||
@@ -184,7 +183,7 @@ class LocalAssetBrowser
|
||||
static void UpdateTextureCtrlList(LLScrollListCtrl*);
|
||||
static void setLayerUpdated(bool toggle) { mLayerUpdated = toggle; }
|
||||
static void setSculptUpdated(bool toggle) { mSculptUpdated = toggle; }
|
||||
static void AddBitmap(void);
|
||||
static void AddBitmap();
|
||||
static void AddBitmap_continued(AIFilePicker* filepicker);
|
||||
static void DelBitmap( std::vector<LLScrollListItem*>, S32 column = BITMAPLIST_COL_ID );
|
||||
|
||||
@@ -194,18 +193,18 @@ class LocalAssetBrowser
|
||||
the latter - each time the button's pressed. */
|
||||
|
||||
private:
|
||||
static void onChangeHappened(void);
|
||||
static void onChangeHappened();
|
||||
static void onUpdateBool(LLUUID);
|
||||
static void onSetType(LLUUID, S32);
|
||||
static LocalBitmap* GetBitmapUnit(LLUUID);
|
||||
static bool IsDoingUpdates(void);
|
||||
static void PingTimer(void);
|
||||
static void PerformTimedActions(void);
|
||||
static void PerformSculptUpdates(LocalBitmap*);
|
||||
static bool IsDoingUpdates();
|
||||
static void PingTimer();
|
||||
static void PerformTimedActions();
|
||||
static void PerformSculptUpdates(LocalBitmap&);
|
||||
|
||||
protected:
|
||||
static std::vector<LocalBitmap*> loaded_bitmaps;
|
||||
typedef std::vector<LocalBitmap*>::iterator local_list_iter;
|
||||
static std::vector<LocalBitmap> loaded_bitmaps;
|
||||
typedef std::vector<LocalBitmap>::iterator local_list_iter;
|
||||
static bool mLayerUpdated;
|
||||
static bool mSculptUpdated;
|
||||
};
|
||||
@@ -225,17 +224,13 @@ public:
|
||||
FloaterLocalAssetBrowser();
|
||||
virtual ~FloaterLocalAssetBrowser();
|
||||
static void show(void*);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
/* Widget related callbacks */
|
||||
// Button callback declarations
|
||||
static void onClickAdd(void* userdata);
|
||||
static void onClickDel(void* userdata);
|
||||
static void onClickMore(void* userdata);
|
||||
static void onClickLess(void* userdata);
|
||||
static void onClickUpload(void* userdata);
|
||||
// Button callback declarations
|
||||
void onClickAdd();
|
||||
void onClickDel();
|
||||
void onClickUpload();
|
||||
|
||||
// ScrollList callback declarations
|
||||
void onChooseBitmapList();
|
||||
@@ -271,17 +266,12 @@ private:
|
||||
LLTextBox* mCaptionNameTxt;
|
||||
LLTextBox* mCaptionTimeTxt;
|
||||
|
||||
/* static pointer to self, wai? oh well. */
|
||||
static FloaterLocalAssetBrowser* sLFInstance;
|
||||
|
||||
// non-widget functions
|
||||
static void FloaterResize(bool expand);
|
||||
static void UpdateRightSide(void);
|
||||
void FloaterResize(bool expand);
|
||||
void UpdateRightSide();
|
||||
|
||||
public:
|
||||
static void UpdateBitmapScrollList(void);
|
||||
|
||||
|
||||
void UpdateBitmapScrollList();
|
||||
};
|
||||
|
||||
/*==================================================*/
|
||||
|
||||
@@ -891,6 +891,8 @@ void HippoGridManager::loadFromFile()
|
||||
|
||||
void HippoGridManager::parseUrl(const std::string url, bool mergeIfNewer)
|
||||
{
|
||||
if (url.empty()) return;
|
||||
|
||||
llinfos << "Loading grid info from '" << url << "'." << llendl;
|
||||
|
||||
// query update server
|
||||
|
||||
@@ -31,6 +31,7 @@ RequestExecutionLevel admin ; on Vista we must be admin because we write to Prog
|
||||
;; !define INSTNAME "SecondLife%(grid_caps)s"
|
||||
;; !define SHORTCUT "Second Life (%(grid_caps)s)"
|
||||
;; !define URLNAME "secondlife%(grid)s"
|
||||
;; !define AUTHOR "Linden Research, Inc."
|
||||
;; !define UNINSTALL_SETTINGS 1
|
||||
|
||||
%%GRID_VARS%%
|
||||
@@ -76,8 +77,8 @@ Name "${VIEWERNAME}"
|
||||
SubCaption 0 $(LicenseSubTitleSetup) ; override "license agreement" text
|
||||
|
||||
BrandingText "Prepare to Implode!" ; bottom of window text
|
||||
Icon %%SOURCE%%\installers\windows\install_icon_singularity.ico
|
||||
UninstallIcon %%SOURCE%%\installers\windows\uninstall_icon_singularity.ico
|
||||
Icon %%SOURCE%%\installers\windows\${INSTALL_ICON}
|
||||
UninstallIcon %%SOURCE%%\installers\windows\${UNINSTALL_ICON}
|
||||
WindowIcon off ; show our icon in left corner
|
||||
# BGGradient 9090b0 000000 notext
|
||||
CRCCheck on ; make sure CRC is OK
|
||||
@@ -89,7 +90,7 @@ SetOverwrite on ; stomp files by default
|
||||
AutoCloseWindow true ; after all files install, close window
|
||||
|
||||
InstallDir "%%INSTALLDIR%%"
|
||||
InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" ""
|
||||
InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\${INSTNAME}" ""
|
||||
DirText $(DirectoryChooseTitle) $(DirectoryChooseSetup)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -191,7 +192,7 @@ FunctionEnd
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
Function CheckIfAlreadyCurrent
|
||||
Push $0
|
||||
ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version"
|
||||
ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Version"
|
||||
StrCmp $0 ${VERSION_LONG} 0 DONE
|
||||
MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK DONE
|
||||
Quit
|
||||
@@ -550,7 +551,7 @@ SetShellVarContext all
|
||||
Call un.CloseSecondLife
|
||||
|
||||
; Clean up registry keys and subkeys (these should all be !defines somewhere)
|
||||
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG"
|
||||
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG"
|
||||
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
|
||||
|
||||
; Clean up shortcuts
|
||||
@@ -693,7 +694,7 @@ lbl_check_silent:
|
||||
|
||||
; If we currently have a version of SL installed, default to the language of that install
|
||||
; Otherwise don't change $LANGUAGE and it will default to the OS UI language.
|
||||
ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
|
||||
ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\${INSTNAME}" "InstallerLanguage"
|
||||
IfErrors lbl_build_menu
|
||||
StrCpy $LANGUAGE $0
|
||||
|
||||
@@ -711,7 +712,7 @@ lbl_build_menu:
|
||||
StrCpy $LANGUAGE $0
|
||||
|
||||
; save language in registry
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" $LANGUAGE
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\${INSTNAME}" "InstallerLanguage" $LANGUAGE
|
||||
lbl_return:
|
||||
Pop $0
|
||||
Return
|
||||
@@ -721,7 +722,7 @@ FunctionEnd
|
||||
Function un.onInit
|
||||
; read language from registry and set for uninstaller
|
||||
; Key will be removed on successful uninstall
|
||||
ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
|
||||
ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\${INSTNAME}" "InstallerLanguage"
|
||||
IfErrors lbl_end
|
||||
StrCpy $LANGUAGE $0
|
||||
lbl_end:
|
||||
@@ -810,11 +811,11 @@ CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Write registry
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "" "$INSTDIR"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" "${VERSION_LONG}"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags" "$INSTFLAGS"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut" "$INSTSHORTCUT"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$INSTEXE"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "" "$INSTDIR"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Version" "${VERSION_LONG}"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Flags" "$INSTFLAGS"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Shortcut" "$INSTSHORTCUT"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${AUTHOR}\$INSTPROG" "Exe" "$INSTEXE"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayName" "$INSTPROG (remove only)"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "UninstallString" '"$INSTDIR\uninst.exe"'
|
||||
|
||||
|
||||
@@ -103,10 +103,11 @@
|
||||
|
||||
#include "lluictrlfactory.h" //For LLUICtrlFactory::getLayeredXMLNode
|
||||
|
||||
// [RLVa:KB] - Checked: 2010-09-27 (RLVa-1.1.3b)
|
||||
// [RLVa:KB] - Checked: 2011-11-04 (RLVa-1.4.4a)
|
||||
#include "rlvactions.h"
|
||||
#include "rlvhandler.h"
|
||||
#include "rlvinventory.h"
|
||||
#include "llattachmentsmgr.h"
|
||||
#include "rlvhelper.h"
|
||||
#include "rlvui.h"
|
||||
// [/RLVa:KB]
|
||||
|
||||
#include "NACLantispam.h" // for NaCl Antispam Registry
|
||||
@@ -420,6 +421,7 @@ LLAgent::LLAgent() :
|
||||
|
||||
mNextFidgetTime(0.f),
|
||||
mCurrentFidget(0),
|
||||
mCrouch(false),
|
||||
mFirstLogin(FALSE),
|
||||
mGenderChosen(FALSE),
|
||||
mAppearanceSerialNum(0),
|
||||
@@ -639,13 +641,14 @@ void LLAgent::moveUp(S32 direction)
|
||||
if (direction > 0)
|
||||
{
|
||||
setControlFlags(AGENT_CONTROL_UP_POS | AGENT_CONTROL_FAST_UP);
|
||||
mCrouch = false;
|
||||
}
|
||||
else if (direction < 0)
|
||||
{
|
||||
setControlFlags(AGENT_CONTROL_UP_NEG | AGENT_CONTROL_FAST_UP);
|
||||
}
|
||||
|
||||
if (!isCrouch) camera_reset_on_motion();
|
||||
if (!mCrouch) camera_reset_on_motion();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -687,6 +690,11 @@ void LLAgent::movePitch(F32 mag)
|
||||
}
|
||||
}
|
||||
|
||||
bool LLAgent::isCrouching() const
|
||||
{
|
||||
return mCrouch && !getFlying(); // Never crouch when flying
|
||||
}
|
||||
|
||||
|
||||
// Does this parcel allow you to fly?
|
||||
BOOL LLAgent::canFly()
|
||||
@@ -770,6 +778,7 @@ void LLAgent::setFlying(BOOL fly)
|
||||
{
|
||||
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_FLY_COUNT);
|
||||
}
|
||||
mCrouch = false;
|
||||
setControlFlags(AGENT_CONTROL_FLY);
|
||||
}
|
||||
else
|
||||
@@ -818,17 +827,20 @@ void LLAgent::standUp()
|
||||
// setControlFlags(AGENT_CONTROL_STAND_UP);
|
||||
// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
|
||||
// RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking
|
||||
if ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStand()) )
|
||||
if ( (!rlv_handler_t::isEnabled()) || (RlvActions::canStand()) )
|
||||
{
|
||||
setControlFlags(AGENT_CONTROL_STAND_UP);
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
}
|
||||
|
||||
|
||||
void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id)
|
||||
{
|
||||
llinfos << "called" << llendl;
|
||||
|
||||
|
||||
// Old-style appearance entering a server-bake region.
|
||||
if (isAgentAvatarValid() &&
|
||||
!gAgentAvatarp->isUsingServerBakes() &&
|
||||
(mRegionp->getCentralBakeVersion()>0))
|
||||
@@ -971,7 +983,6 @@ const LLHost& LLAgent::getRegionHost() const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// inPrelude()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1148,7 +1159,7 @@ void LLAgent::sitDown()
|
||||
// setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
|
||||
// [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
|
||||
// RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking
|
||||
if ( (!rlv_handler_t::isEnabled()) || ((gRlvHandler.canStand()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) )
|
||||
if ( (!rlv_handler_t::isEnabled()) || ((RlvActions::canStand()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) )
|
||||
{
|
||||
setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
|
||||
}
|
||||
@@ -4330,7 +4341,7 @@ void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global)
|
||||
// [RLVa:KB] - Checked: 2010-10-07 (RLVa-1.2.1f) | Added: RLVa-1.2.1f
|
||||
// RELEASE-RLVa: [SL-2.2.0] Make sure this isn't used for anything except double-click teleporting
|
||||
if ( (rlv_handler_t::isEnabled()) && (!RlvUtil::isForceTp()) &&
|
||||
((gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) || (!gRlvHandler.canStand())) )
|
||||
((gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) || (!RlvActions::canStand())) )
|
||||
{
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT);
|
||||
return;
|
||||
|
||||
@@ -302,6 +302,15 @@ private:
|
||||
F32 mNextFidgetTime;
|
||||
S32 mCurrentFidget;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Crouch
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
bool isCrouching() const;
|
||||
void toggleCrouch() { mCrouch = !mCrouch; }
|
||||
private:
|
||||
bool mCrouch;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Fly
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
@@ -2076,7 +2076,7 @@ void LLAgentCamera::handleScrollWheel(S32 clicks)
|
||||
if (MASK mask = gKeyboard->currentMask(true)) // Singu Note: Conveniently set view offsets while modifier keys are held during scroll
|
||||
{
|
||||
static const LLCachedControl<bool> enableCameraOffsetScroll("SinguOffsetScrollKeys");
|
||||
if (mask & MASK_CONTROL|MASK_SHIFT && enableCameraOffsetScroll)
|
||||
if (mask & (MASK_CONTROL|MASK_SHIFT) && enableCameraOffsetScroll)
|
||||
{
|
||||
const F32 change(static_cast<F32>(clicks) * 0.1f);
|
||||
if (mask & MASK_SHIFT)
|
||||
@@ -2191,8 +2191,8 @@ void LLAgentCamera::changeCameraToMouselook(BOOL animate)
|
||||
|
||||
//gViewerWindow->stopGrab();
|
||||
LLSelectMgr::getInstance()->deselectAll();
|
||||
gViewerWindow->hideCursor();
|
||||
gViewerWindow->moveCursorToCenter();
|
||||
// gViewerWindow->hideCursor();
|
||||
// gViewerWindow->moveCursorToCenter();
|
||||
|
||||
if (mCameraMode != CAMERA_MODE_MOUSELOOK)
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
#include "llfloatercustomize.h"
|
||||
|
||||
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
|
||||
#include "rlvhandler.h"
|
||||
#include "rlvinventory.h"
|
||||
#include "llattachmentsmgr.h"
|
||||
@@ -65,7 +65,7 @@
|
||||
LLAgentWearables gAgentWearables;
|
||||
|
||||
BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE;
|
||||
// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-3.0.0a) | Added: Catznip-2.1.1d
|
||||
// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1)
|
||||
bool LLAgentWearables::mInitialWearablesLoaded = false;
|
||||
// [/SL:KB]
|
||||
|
||||
@@ -829,7 +829,7 @@ const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32
|
||||
return LLUUID();
|
||||
}
|
||||
|
||||
// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f
|
||||
// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0)
|
||||
void LLAgentWearables::getWearableItemIDs(uuid_vec_t& idItems) const
|
||||
{
|
||||
for (wearableentry_map_t::const_iterator itWearableType = mWearableDatas.begin();
|
||||
@@ -844,8 +844,8 @@ void LLAgentWearables::getWearableItemIDs(LLWearableType::EType eType, uuid_vec_
|
||||
wearableentry_map_t::const_iterator itWearableType = mWearableDatas.find(eType);
|
||||
if (mWearableDatas.end() != itWearableType)
|
||||
{
|
||||
for (wearableentry_vec_t::const_iterator itWearable = itWearableType->second.begin(), endWearable = itWearableType->second.end();
|
||||
itWearable != endWearable; ++itWearable)
|
||||
for (wearableentry_vec_t::const_iterator itWearable = itWearableType->second.begin();
|
||||
itWearable != itWearableType->second.end(); ++itWearable)
|
||||
{
|
||||
LLViewerWearable* wearable = dynamic_cast<LLViewerWearable*>(*itWearable);
|
||||
if(wearable)
|
||||
@@ -1402,7 +1402,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
|
||||
// Start rendering & update the server
|
||||
mWearablesLoaded = TRUE;
|
||||
checkWearablesLoaded();
|
||||
// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-09-22 (Catznip-3.0.0a) | Modified: Catznip-2.2.0a
|
||||
// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-09-22 (Catznip-2.2)
|
||||
if (!mInitialWearablesLoaded)
|
||||
{
|
||||
mInitialWearablesLoaded = true;
|
||||
@@ -1830,7 +1830,7 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
|
||||
msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
|
||||
msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
|
||||
msg->addU8Fast(_PREHASH_AttachmentPt, replace? 0 : ATTACHMENT_ADD); // Wear at the previous or default attachment point
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1b) | Added: RLVa-1.3.1b
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
|
||||
if ( (rlv_handler_t::isEnabled()) && (sInitialAttachmentsRequested) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
|
||||
{
|
||||
RlvAttachmentLockWatchdog::instance().onWearAttachment(item, RLV_WEAR_ADD);
|
||||
@@ -1847,7 +1847,7 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
|
||||
}
|
||||
}
|
||||
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1b) | Added: RLVa-1.3.1b
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
|
||||
sInitialAttachmentsRequested = true;
|
||||
// [/RLVa:KB]
|
||||
}
|
||||
@@ -2076,7 +2076,7 @@ boost::signals2::connection LLAgentWearables::addLoadedCallback(loaded_callback_
|
||||
return mLoadedSignal.connect(cb);
|
||||
}
|
||||
|
||||
// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-3.0.0a) | Added: Catznip-2.1.1d
|
||||
// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1)
|
||||
boost::signals2::connection LLAgentWearables::addInitialWearablesLoadedCallback(loaded_callback_t cb)
|
||||
{
|
||||
return mInitialWearablesLoadedSignal.connect(cb);
|
||||
|
||||
@@ -583,7 +583,7 @@ public:
|
||||
void onWearableAssetFetch(LLViewerWearable *wearable);
|
||||
void onAllComplete();
|
||||
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0)
|
||||
bool pollStopped();
|
||||
// [/SL:KB]
|
||||
|
||||
@@ -670,7 +670,7 @@ void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type)
|
||||
mTypesToRecover.erase(type);
|
||||
}
|
||||
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-06-19 (Catznip-3.0.0a) | Added: Catznip-2.1.2a
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-06-19 (Catznip-2.1)
|
||||
//void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items)
|
||||
//{
|
||||
// mObjItems = items;
|
||||
@@ -780,10 +780,11 @@ void LLWearableHoldingPattern::onAllComplete()
|
||||
LL_INFOS("Avatar") << self_av_string() << "Updating agent wearables with " << mResolved << " wearable items " << LL_ENDL;
|
||||
LLAppearanceMgr::instance().updateAgentWearables(this, false);
|
||||
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-03-22 (Catznip-3.0.0a) | Added: Catznip-2.1.2a
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-03-22 (Catznip-2.1)
|
||||
// // Update attachments to match those requested.
|
||||
// if (isAgentAvatarValid())
|
||||
// {
|
||||
// LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.count() << " attachments" << LL_ENDL;
|
||||
// llinfos << "Updating " << mObjItems.count() << " attachments" << llendl;
|
||||
// LLAgentWearables::userUpdateAttachments(mObjItems);
|
||||
// }
|
||||
@@ -821,7 +822,7 @@ bool LLWearableHoldingPattern::pollFetchCompletion()
|
||||
// runway skip here?
|
||||
llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
|
||||
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0)
|
||||
// If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves
|
||||
doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollStopped, this));
|
||||
return true;
|
||||
@@ -897,7 +898,7 @@ void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLView
|
||||
// runway skip here?
|
||||
llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
|
||||
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0)
|
||||
// If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves
|
||||
return;
|
||||
// [/SL:KB]
|
||||
@@ -971,7 +972,7 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()
|
||||
}
|
||||
}
|
||||
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0)
|
||||
bool LLWearableHoldingPattern::pollStopped()
|
||||
{
|
||||
// We have to keep on polling until we're sure that all callbacks have completed or they'll cause a crash
|
||||
@@ -991,7 +992,7 @@ bool LLWearableHoldingPattern::pollMissingWearables()
|
||||
// runway skip here?
|
||||
llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
|
||||
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a
|
||||
// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0)
|
||||
// If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves
|
||||
doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollStopped, this));
|
||||
return true;
|
||||
@@ -1386,7 +1387,7 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up
|
||||
|
||||
if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
|
||||
{
|
||||
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(&wear_on_avatar_cb,_1,replace));
|
||||
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
|
||||
copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
|
||||
return false;
|
||||
}
|
||||
@@ -1525,7 +1526,7 @@ void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id)
|
||||
LLInventoryModel::item_array_t items;
|
||||
LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false);
|
||||
|
||||
gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector);
|
||||
gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector, true);
|
||||
|
||||
LLInventoryModel::item_array_t::const_iterator it = items.begin();
|
||||
const LLInventoryModel::item_array_t::const_iterator it_end = items.end();
|
||||
@@ -1536,6 +1537,18 @@ void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id)
|
||||
uuids_to_remove.push_back(item->getUUID());
|
||||
}
|
||||
removeItemsFromAvatar(uuids_to_remove);
|
||||
|
||||
// deactivate all gestures in the outfit folder
|
||||
LLInventoryModel::item_array_t gest_items;
|
||||
getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE, true);
|
||||
for(S32 i = 0; i < gest_items.count(); ++i)
|
||||
{
|
||||
LLViewerInventoryItem* gest_item = gest_items.get(i);
|
||||
if (LLGestureMgr::instance().isGestureActive(gest_item->getLinkedUUID()))
|
||||
{
|
||||
LLGestureMgr::instance().deactivateGesture(gest_item->getLinkedUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a copy of src_id + contents as a subfolder of dst_id.
|
||||
@@ -1711,8 +1724,19 @@ bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id)
|
||||
cats,
|
||||
items,
|
||||
LLInventoryModel::EXCLUDE_TRASH,
|
||||
is_worn);
|
||||
return items.size() > 0;
|
||||
is_worn,
|
||||
/*follow_folder_links=*/ true);
|
||||
|
||||
if (items.size()) return true;
|
||||
|
||||
// Is there an active gesture in outfit_cat_id?
|
||||
items.reset();
|
||||
LLIsType is_gesture(LLAssetType::AT_GESTURE);
|
||||
gInventory.collectDescendentsIf(outfit_cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_gesture, /*follow_folder_links=*/ true);
|
||||
for(S32 i = 0; i < items.count(); ++i)
|
||||
if (LLGestureMgr::instance().isGestureActive(items.get(i)->getLinkedUUID()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -1744,7 +1768,7 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
|
||||
|
||||
// Check whether it's the base outfit.
|
||||
// if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID())
|
||||
// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-21 (Catznip-3.0.0a) | Added: Catznip-2.1.2d
|
||||
// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-21 (Catznip-2.1)
|
||||
if ( (outfit_cat_id.isNull()) || ((outfit_cat_id == getBaseOutfitUUID()) && (!isOutfitDirty())) )
|
||||
// [/SL:KB]
|
||||
{
|
||||
@@ -1798,8 +1822,19 @@ void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_lin
|
||||
continue;
|
||||
if (item->getIsLinkType())
|
||||
{
|
||||
#if 0
|
||||
if (keep_items && keep_items->find(item) != LLInventoryModel::item_array_t::FAIL)
|
||||
{
|
||||
llinfos << "preserved item" << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
gInventory.purgeObject(item->getUUID());
|
||||
}
|
||||
#else
|
||||
gInventory.purgeObject(item->getUUID());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1892,9 +1927,8 @@ void LLAppearanceMgr::filterWearableItems(
|
||||
if (size <= 0)
|
||||
continue;
|
||||
// S32 start_index = llmax(0,size-max_per_type);
|
||||
// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-05-11 (Catznip-3.0.0a) | Added: Catznip-2.0.0h
|
||||
S32 start_index =
|
||||
llmax(0, size - ((LLAssetType::AT_BODYPART == LLWearableType::getAssetType((LLWearableType::EType)i)) ? 1 : max_per_type));
|
||||
// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-05-11 (Catznip-2.0)
|
||||
S32 start_index = llmax(0, size - ((LLAssetType::AT_BODYPART == LLWearableType::getAssetType((LLWearableType::EType)i)) ? 1 : max_per_type));
|
||||
// [/SL:KB[
|
||||
for (S32 j = start_index; j<size; j++)
|
||||
{
|
||||
@@ -1933,10 +1967,10 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid,
|
||||
void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
|
||||
{
|
||||
LLInventoryModel::item_array_t body_items_new, wear_items_new, obj_items_new, gest_items_new;
|
||||
getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART, false);
|
||||
getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING, false);
|
||||
getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT, false);
|
||||
getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE, false);
|
||||
getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART, true);
|
||||
getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING, true);
|
||||
getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT, true);
|
||||
getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE, true);
|
||||
updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, category);
|
||||
}
|
||||
|
||||
@@ -1948,7 +1982,7 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new,
|
||||
// [/RLVa:KB]
|
||||
{
|
||||
// LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
|
||||
// llinfos << "starting, cat " << (pcat ? pcat->getName() : "[UNKNOWN]") << llendl;
|
||||
// LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL;
|
||||
// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Added: RLVa-1.2.0b
|
||||
// RELEASE-RLVa: [SL-2.0.0] If pcat ever gets used for anything further down the beta we'll know about it
|
||||
llinfos << "starting" << llendl;
|
||||
@@ -2220,8 +2254,6 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo
|
||||
{
|
||||
gAgentWearables.setWearableOutfit(items, wearables, !append);
|
||||
}
|
||||
|
||||
// dec_busy_count();
|
||||
}
|
||||
|
||||
static void remove_non_link_items(LLInventoryModel::item_array_t &items)
|
||||
@@ -2334,7 +2366,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
|
||||
BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF);
|
||||
selfStartPhase("update_appearance_from_cof");
|
||||
|
||||
LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL;
|
||||
LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL;
|
||||
|
||||
//checking integrity of the COF in terms of ordering of wearables,
|
||||
//checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state)
|
||||
@@ -2372,7 +2404,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
|
||||
remove_non_link_items(wear_items);
|
||||
remove_non_link_items(obj_items);
|
||||
remove_non_link_items(gest_items);
|
||||
// [SL:KB] - Patch: Apperance-Misc | Checked: 2010-11-24 (Catznip-3.0.0a) | Added: Catzip-2.4.0f
|
||||
// [SL:KB] - Patch: Apperance-Misc | Checked: 2010-11-24 (Catznip-2.4)
|
||||
// Since we're following folder links we might have picked up new duplicates, or exceeded MAX_CLOTHING_PER_TYPE
|
||||
removeDuplicateItems(wear_items);
|
||||
removeDuplicateItems(obj_items);
|
||||
@@ -2387,7 +2419,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
|
||||
dumpItemArray(wear_items,"asset_dump: wear_item");
|
||||
dumpItemArray(obj_items,"asset_dump: obj_item");
|
||||
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-3.0.0a) | Added: Catznip-2.2.0a
|
||||
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2)
|
||||
// Update attachments to match those requested.
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
@@ -2704,7 +2736,6 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
|
||||
void LLAppearanceMgr::wearOutfitByName(const std::string& name)
|
||||
{
|
||||
LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL;
|
||||
//inc_busy_count();
|
||||
|
||||
LLInventoryModel::cat_array_t cat_array;
|
||||
LLInventoryModel::item_array_t item_array;
|
||||
@@ -3006,21 +3037,25 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id)
|
||||
LLInventoryModel::EXCLUDE_TRASH);
|
||||
for (S32 i=0; i<item_array.count(); i++)
|
||||
{
|
||||
const LLInventoryItem* item = item_array.get(i).get();
|
||||
// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8)
|
||||
const LLViewerInventoryItem* item = item_array.get(i).get();
|
||||
if (item->getIsLinkType() && item->getLinkedUUID() == item_id)
|
||||
{
|
||||
// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8)
|
||||
#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
|
||||
#if 0 // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
|
||||
// NOTE-RLVa: debug-only, can be removed down the line
|
||||
if (rlv_handler_t::isEnabled())
|
||||
{
|
||||
RLV_ASSERT(rlvPredCanRemoveItem(item));
|
||||
}
|
||||
#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
|
||||
// [/RLVa:KB]
|
||||
|
||||
gInventory.purgeObject(item->getUUID());
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
// const LLInventoryItem* item = item_array.get(i).get();
|
||||
// if (item->getIsLinkType() && item->getLinkedUUID() == item_id)
|
||||
// {
|
||||
// gInventory.purgeObject(item->getUUID());
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3038,7 +3073,7 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type)
|
||||
if (item->getIsLinkType()) // we must operate on links only
|
||||
{
|
||||
// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8)
|
||||
#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
|
||||
#if 0 // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
|
||||
// NOTE-RLVa: debug-only, can be removed down the line
|
||||
if (rlv_handler_t::isEnabled())
|
||||
{
|
||||
@@ -3487,7 +3522,7 @@ public:
|
||||
// Error
|
||||
/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
|
||||
{
|
||||
llwarns << "appearance update request failed, status: " << status << " reason: " << reason << llendl;
|
||||
llwarns << "appearance update request failed, status: " << status << " reason: " << reason << " code: " << content["code"].asInteger() << " error: \"" << content["error"].asString() << "\"" << llendl;
|
||||
LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL;
|
||||
onFailure(status);
|
||||
}
|
||||
@@ -3724,6 +3759,9 @@ public:
|
||||
*/
|
||||
LLAppearanceMgr::instance().changeOutfit(true, mFolderID, false);
|
||||
}
|
||||
|
||||
void setFailed() { mFailed = true; } // Singu Note: Lies and hacks
|
||||
|
||||
private:
|
||||
class LLCreateBase : public LLInventoryCallback
|
||||
{
|
||||
@@ -3912,12 +3950,18 @@ LLUUID LLAppearanceMgr::makeNewOutfitLegacy(const std::string& new_folder_name,
|
||||
|
||||
LLPointer<LLCreateLegacyOutfit> cb = new LLCreateLegacyOutfit(folder_id,boost::bind(&scroll_to_folder,folder_id),boost::bind(&show_created_outfit,folder_id,true));
|
||||
uuid_vec_t obj_ids; // Collect the uuids of copyable objects, in order to keep any changes made in the copies
|
||||
bool use_all_links(gSavedSettings.getBOOL("LiruLegacyOutfitAllLinks"));
|
||||
|
||||
for (LLInventoryModel::item_array_t::const_iterator iter = items.begin();
|
||||
iter != items.end();
|
||||
++iter)
|
||||
{
|
||||
LLViewerInventoryItem* item = (*iter);
|
||||
if (use_all_links)
|
||||
{
|
||||
cb->makeLink(item, item->LLInventoryItem::getDescription());
|
||||
continue;
|
||||
}
|
||||
LLViewerInventoryItem* base_item = item->getLinkedItem() ? item->getLinkedItem() : item;
|
||||
bool is_copy = base_item->getPermissions().allowCopyBy(gAgent.getID());
|
||||
bool is_obj = base_item->getInventoryType() == LLInventoryType::IT_OBJECT;
|
||||
@@ -3936,10 +3980,12 @@ LLUUID LLAppearanceMgr::makeNewOutfitLegacy(const std::string& new_folder_name,
|
||||
cb->makeCopy(item,is_multi && use_links);
|
||||
}
|
||||
}
|
||||
if (gSavedSettings.getBOOL("LiruLegacyOutfitStoreObjChanges")) // As a last resort, someone may create a legacy outfit to undo attachment changes
|
||||
if (!use_all_links && gSavedSettings.getBOOL("LiruLegacyOutfitStoreObjChanges")) // As a last resort, someone may create a legacy outfit to undo attachment changes
|
||||
LLAppearanceMgr::instance().removeItemsFromAvatar(obj_ids); // The avatar will have to go without these for now
|
||||
cb->dispatch();
|
||||
|
||||
if (use_all_links) cb->setFailed(); // Cause an early return to avoid rewearing
|
||||
|
||||
return folder_id;
|
||||
}
|
||||
|
||||
@@ -3953,6 +3999,11 @@ void LLAppearanceMgr::wearBaseOutfit()
|
||||
|
||||
void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
|
||||
{
|
||||
if (ids_to_remove.empty())
|
||||
{
|
||||
llwarns << "called with empty list, nothing to do" << llendl;
|
||||
}
|
||||
|
||||
// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8)
|
||||
bool fUpdateAppearance = false;
|
||||
for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
|
||||
@@ -4400,7 +4451,6 @@ void wear_multiple(const uuid_vec_t& ids, bool replace)
|
||||
|
||||
// SLapp for easy-wearing of a stock (library) avatar
|
||||
//
|
||||
/*
|
||||
class LLWearFolderHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
@@ -4430,4 +4480,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
LLWearFolderHandler gWearFolderHandler;*/
|
||||
LLWearFolderHandler gWearFolderHandler;
|
||||
|
||||
@@ -304,6 +304,8 @@ const std::string MARKER_FILE_NAME("Singularity.exec_marker");
|
||||
const std::string ERROR_MARKER_FILE_NAME("Singularity.error_marker");
|
||||
const std::string LLERROR_MARKER_FILE_NAME("Singularity.llerror_marker");
|
||||
const std::string LOGOUT_MARKER_FILE_NAME("Singularity.logout_marker");
|
||||
const std::string LOG_FILE("Singularity.log");
|
||||
extern const std::string OLD_LOG_FILE("Singularity.old");
|
||||
static BOOL gDoDisconnect = FALSE;
|
||||
static std::string gLaunchFileOnQuit;
|
||||
|
||||
@@ -353,6 +355,7 @@ void init_default_trans_args()
|
||||
{
|
||||
default_trans_args.insert("SECOND_LIFE"); // World
|
||||
default_trans_args.insert("APP_NAME");
|
||||
default_trans_args.insert("SHORT_APP_NAME");
|
||||
default_trans_args.insert("CAPITALIZED_APP_NAME");
|
||||
default_trans_args.insert("SECOND_LIFE_GRID");
|
||||
default_trans_args.insert("SUPPORT_SITE");
|
||||
@@ -1220,7 +1223,7 @@ bool LLAppViewer::mainLoop()
|
||||
{
|
||||
joystick->scanJoystick();
|
||||
gKeyboard->scanKeyboard();
|
||||
if(isCrouch)
|
||||
if (gAgent.isCrouching())
|
||||
{
|
||||
gAgent.moveUp(-1);
|
||||
}
|
||||
@@ -1946,13 +1949,11 @@ bool LLAppViewer::initLogging()
|
||||
LLError::setFatalFunction(errorCallback);
|
||||
|
||||
// Remove the last ".old" log file.
|
||||
std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
|
||||
"Singularity.old");
|
||||
std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, OLD_LOG_FILE);
|
||||
LLFile::remove(old_log_file);
|
||||
|
||||
// Rename current log file to ".old"
|
||||
std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
|
||||
"Singularity.log");
|
||||
std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOG_FILE);
|
||||
LLFile::rename(log_file, old_log_file);
|
||||
|
||||
// Set the log file to Singularity.log
|
||||
@@ -2363,23 +2364,6 @@ bool LLAppViewer::initConfiguration()
|
||||
#if LL_DARWIN
|
||||
// Initialize apple menubar and various callbacks
|
||||
init_apple_menu(LLTrans::getString("APP_NAME").c_str());
|
||||
|
||||
#if __ppc__
|
||||
// If the CPU doesn't have Altivec (i.e. it's not at least a G4), don't go any further.
|
||||
// Only test PowerPC - all Intel Macs have SSE.
|
||||
if(!gSysCPU.hasAltivec())
|
||||
{
|
||||
std::ostringstream msg;
|
||||
msg << LLTrans::getString("MBRequiresAltiVec");
|
||||
OSMessageBox(
|
||||
msg.str(),
|
||||
LLStringUtil::null,
|
||||
OSMB_OK);
|
||||
removeMarkerFile();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // LL_DARWIN
|
||||
|
||||
// Display splash screen. Must be after above check for previous
|
||||
@@ -2664,7 +2648,7 @@ void LLAppViewer::writeSystemInfo()
|
||||
// that the crash report will go to the proper location in the case of a
|
||||
// prior freeze.
|
||||
std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
|
||||
if(crashHostUrl != "")
|
||||
if (!crashHostUrl.empty())
|
||||
{
|
||||
gDebugInfo["CrashHostUrl"] = crashHostUrl;
|
||||
}
|
||||
@@ -2725,7 +2709,7 @@ void LLAppViewer::handleViewerCrash()
|
||||
|
||||
// Insert crash host url (url to post crash log to) if configured.
|
||||
std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
|
||||
if(crashHostUrl != "")
|
||||
if (!crashHostUrl.empty())
|
||||
{
|
||||
gDebugInfo["Dynamic"]["CrashHostUrl"] = crashHostUrl;
|
||||
}
|
||||
|
||||
802
indra/newview/llautoreplace.cpp
Normal file
802
indra/newview/llautoreplace.cpp
Normal file
@@ -0,0 +1,802 @@
|
||||
/**
|
||||
* @file llautoreplace.cpp
|
||||
* @brief Auto Replace Manager
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llautoreplace.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llboost.h"
|
||||
#include "llcontrol.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
const char* LLAutoReplace::SETTINGS_FILE_NAME = "autoreplace.xml";
|
||||
|
||||
void LLAutoReplace::autoreplaceCallback(S32& replacement_start, S32& replacement_length, LLWString& replacement_string, S32& cursor_pos, const LLWString& input_text)
|
||||
{
|
||||
// make sure these returned values are cleared in case there is no replacement
|
||||
replacement_start = 0;
|
||||
replacement_length = 0;
|
||||
replacement_string.clear();
|
||||
|
||||
static LLCachedControl<bool> perform_autoreplace(gSavedSettings, "AutoReplace", 0);
|
||||
if (perform_autoreplace)
|
||||
{
|
||||
S32 word_end = cursor_pos - 1;
|
||||
|
||||
bool at_space = (input_text[word_end] == ' ');
|
||||
bool have_word = (LLWStringUtil::isPartOfWord(input_text[word_end]));
|
||||
|
||||
if (at_space || have_word)
|
||||
{
|
||||
if (at_space && word_end > 0)
|
||||
{
|
||||
// find out if this space immediately follows a word
|
||||
word_end--;
|
||||
have_word = (LLWStringUtil::isPartOfWord(input_text[word_end]));
|
||||
}
|
||||
if (have_word)
|
||||
{
|
||||
// word_end points to the end of a word, now find the start of the word
|
||||
std::string word;
|
||||
S32 word_start = word_end;
|
||||
for (S32 back_one = word_start - 1;
|
||||
back_one >= 0 && LLWStringUtil::isPartOfWord(input_text[back_one]);
|
||||
back_one--
|
||||
)
|
||||
{
|
||||
word_start--; // walk word_start back to the beginning of the word
|
||||
}
|
||||
LL_DEBUGS("AutoReplace") << "word_start: " << word_start << " word_end: " << word_end << LL_ENDL;
|
||||
std::string str_text = std::string(input_text.begin(), input_text.end());
|
||||
std::string last_word = str_text.substr(word_start, word_end - word_start + 1);
|
||||
std::string replacement_word(mSettings.replaceWord(last_word));
|
||||
|
||||
if (replacement_word != last_word)
|
||||
{
|
||||
// The last word is one for which we have a replacement
|
||||
if (at_space)
|
||||
{
|
||||
// return the replacement string
|
||||
replacement_start = word_start;
|
||||
replacement_length = last_word.length();
|
||||
replacement_string = utf8str_to_wstring(replacement_word);
|
||||
LLWString old_string = utf8str_to_wstring(last_word);
|
||||
S32 size_change = replacement_string.size() - old_string.size();
|
||||
cursor_pos += size_change;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLAutoReplace::getUserSettingsFileName()
|
||||
{
|
||||
std::string path=gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "");
|
||||
|
||||
if (!path.empty())
|
||||
{
|
||||
path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, SETTINGS_FILE_NAME);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string LLAutoReplace::getAppSettingsFileName()
|
||||
{
|
||||
std::string path=gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "");
|
||||
|
||||
if (!path.empty())
|
||||
{
|
||||
path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, SETTINGS_FILE_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("AutoReplace") << "Failed to get app settings directory name" << LL_ENDL;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings LLAutoReplace::getSettings()
|
||||
{
|
||||
return mSettings;
|
||||
}
|
||||
|
||||
void LLAutoReplace::setSettings(const LLAutoReplaceSettings& newSettings)
|
||||
{
|
||||
mSettings.set(newSettings);
|
||||
/// Make the newSettings active and write them to user storage
|
||||
saveToUserSettings();
|
||||
}
|
||||
|
||||
LLAutoReplace::LLAutoReplace()
|
||||
{
|
||||
}
|
||||
|
||||
void LLAutoReplace::initSingleton()
|
||||
{
|
||||
loadFromSettings();
|
||||
}
|
||||
|
||||
void LLAutoReplace::loadFromSettings()
|
||||
{
|
||||
std::string filename=getUserSettingsFileName();
|
||||
if (filename.empty())
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "no valid user settings directory." << LL_ENDL;
|
||||
}
|
||||
if(gDirUtilp->fileExists(filename))
|
||||
{
|
||||
LLSD userSettings;
|
||||
llifstream file;
|
||||
file.open(filename.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXML(userSettings, file);
|
||||
}
|
||||
file.close();
|
||||
if ( mSettings.setFromLLSD(userSettings) )
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "settings loaded from '" << filename << "'" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "invalid settings found in '" << filename << "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else // no user settings found, try application settings
|
||||
{
|
||||
std::string defaultName = getAppSettingsFileName();
|
||||
LL_INFOS("AutoReplace") << " user settings file '" << filename << "' not found"<< LL_ENDL;
|
||||
|
||||
bool gotSettings = false;
|
||||
if(gDirUtilp->fileExists(defaultName))
|
||||
{
|
||||
LLSD appDefault;
|
||||
llifstream file;
|
||||
file.open(defaultName.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXMLDocument(appDefault, file);
|
||||
}
|
||||
file.close();
|
||||
|
||||
if ( mSettings.setFromLLSD(appDefault) )
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "settings loaded from '" << defaultName.c_str() << "'" << LL_ENDL;
|
||||
gotSettings = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "invalid settings found in '" << defaultName.c_str() << "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! gotSettings )
|
||||
{
|
||||
if (mSettings.setFromLLSD(mSettings.getExampleLLSD()))
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "no settings found; loaded example." << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "no settings found and example invalid!" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAutoReplace::saveToUserSettings()
|
||||
{
|
||||
std::string filename=getUserSettingsFileName();
|
||||
llofstream file;
|
||||
file.open(filename.c_str());
|
||||
LLSDSerialize::toPrettyXML(mSettings.asLLSD(), file);
|
||||
file.close();
|
||||
LL_INFOS("AutoReplace") << "settings saved to '" << filename << "'" << LL_ENDL;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// LLAutoReplaceSettings
|
||||
// ================================================================
|
||||
|
||||
const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_NAME = "name"; ///< key for looking up list names
|
||||
const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_REPLACEMENTS = "replacements"; ///< key for looking up replacement map
|
||||
|
||||
LLAutoReplaceSettings::LLAutoReplaceSettings()
|
||||
{
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::LLAutoReplaceSettings(const LLAutoReplaceSettings& settings)
|
||||
{
|
||||
// copy all values through fundamental type intermediates for thread safety
|
||||
mLists = LLSD::emptyArray();
|
||||
|
||||
for ( LLSD::array_const_iterator list = settings.mLists.beginArray(), listEnd = settings.mLists.endArray();
|
||||
list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( (*list).isMap() ) // can fail due to LLSD-30: ignore it
|
||||
{
|
||||
LLSD listMap = LLSD::emptyMap();
|
||||
std::string listName = (*list)[AUTOREPLACE_LIST_NAME];
|
||||
listMap[AUTOREPLACE_LIST_NAME] = listName;
|
||||
listMap[AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
|
||||
for ( LLSD::map_const_iterator
|
||||
entry = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].beginMap(),
|
||||
entriesEnd = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].endMap();
|
||||
entry != entriesEnd;
|
||||
entry++
|
||||
)
|
||||
{
|
||||
std::string keyword = entry->first;
|
||||
std::string replacement = entry->second.asString();
|
||||
listMap[AUTOREPLACE_LIST_REPLACEMENTS].insert(keyword, LLSD(replacement));
|
||||
}
|
||||
|
||||
mLists.append(listMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAutoReplaceSettings::set(const LLAutoReplaceSettings& newSettings)
|
||||
{
|
||||
mLists = newSettings.mLists;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::setFromLLSD(const LLSD& settingsFromLLSD)
|
||||
{
|
||||
bool settingsValid = true;
|
||||
|
||||
if ( settingsFromLLSD.isArray() )
|
||||
{
|
||||
for ( LLSD::array_const_iterator
|
||||
list = settingsFromLLSD.beginArray(),
|
||||
listEnd = settingsFromLLSD.endArray();
|
||||
settingsValid && list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( (*list).isDefined() ) // can be undef due to LLSD-30: ignore it
|
||||
{
|
||||
settingsValid = listIsValid(*list);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
settingsValid = false;
|
||||
LL_WARNS("AutoReplace") << "settings are not an array" << LL_ENDL;
|
||||
}
|
||||
|
||||
if ( settingsValid )
|
||||
{
|
||||
mLists = settingsFromLLSD;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "invalid settings discarded; using hard coded example" << LL_ENDL;
|
||||
}
|
||||
|
||||
return settingsValid;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::listNameMatches( const LLSD& list, const std::string name )
|
||||
{
|
||||
return list.isMap()
|
||||
&& list.has(AUTOREPLACE_LIST_NAME)
|
||||
&& list[AUTOREPLACE_LIST_NAME].asString() == name;
|
||||
}
|
||||
|
||||
const LLSD* LLAutoReplaceSettings::getListEntries(std::string listName)
|
||||
{
|
||||
const LLSD* returnedEntries = NULL;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
||||
returnedEntries == NULL && list != endList;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& thisList = *list;
|
||||
if ( listNameMatches(thisList, listName) )
|
||||
{
|
||||
returnedEntries = &thisList[AUTOREPLACE_LIST_REPLACEMENTS];
|
||||
}
|
||||
}
|
||||
return returnedEntries;
|
||||
}
|
||||
|
||||
std::string LLAutoReplaceSettings::replacementFor(std::string keyword, std::string listName)
|
||||
{
|
||||
std::string replacement;
|
||||
bool foundList = false;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
||||
! foundList && list != endList;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& thisList = *list;
|
||||
if ( listNameMatches(thisList, listName) )
|
||||
{
|
||||
foundList = true; // whether there is a replacement or not, we're done
|
||||
if ( thisList.isMap()
|
||||
&& thisList.has(AUTOREPLACE_LIST_REPLACEMENTS)
|
||||
&& thisList[AUTOREPLACE_LIST_REPLACEMENTS].has(keyword)
|
||||
)
|
||||
{
|
||||
replacement = thisList[AUTOREPLACE_LIST_REPLACEMENTS][keyword].asString();
|
||||
LL_DEBUGS("AutoReplace")<<"'"<<keyword<<"' -> '"<<replacement<<"'"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!foundList)
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to find list '"<<listName<<"'"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (replacement.empty())
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to find '"<<keyword<<"'"<<LL_ENDL;
|
||||
}
|
||||
return replacement;
|
||||
}
|
||||
|
||||
LLSD LLAutoReplaceSettings::getListNames()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"====="<<LL_ENDL;
|
||||
LLSD toReturn = LLSD::emptyArray();
|
||||
S32 counter=0;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
||||
list != endList;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& thisList = *list;
|
||||
if ( thisList.isMap() )
|
||||
{
|
||||
if ( thisList.has(AUTOREPLACE_LIST_NAME) )
|
||||
{
|
||||
std::string name = thisList[AUTOREPLACE_LIST_NAME].asString();
|
||||
LL_DEBUGS("AutoReplace")<<counter<<" '"<<name<<"'"<<LL_ENDL;
|
||||
toReturn.append(LLSD(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("AutoReplace") <<counter<<" ! MISSING "<<AUTOREPLACE_LIST_NAME<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<counter<<" ! not a map: "/*<<LLSD::typeString(thisList.type())*/<< LL_ENDL;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
LL_DEBUGS("AutoReplace")<<"^^^^^^"<<LL_ENDL;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::listIsValid(const LLSD& list)
|
||||
{
|
||||
bool listValid = true;
|
||||
if ( ! list.isMap() )
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace") << "list is not a map" << LL_ENDL;
|
||||
}
|
||||
else if ( ! list.has(AUTOREPLACE_LIST_NAME)
|
||||
|| ! list[AUTOREPLACE_LIST_NAME].isString()
|
||||
|| list[AUTOREPLACE_LIST_NAME].asString().empty()
|
||||
)
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "list found without " << AUTOREPLACE_LIST_NAME
|
||||
<< " (or it is empty)"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
else if ( ! list.has(AUTOREPLACE_LIST_REPLACEMENTS) || ! list[AUTOREPLACE_LIST_REPLACEMENTS].isMap() )
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace") << "list '" << list[AUTOREPLACE_LIST_NAME].asString() << "' without " << AUTOREPLACE_LIST_REPLACEMENTS << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( LLSD::map_const_iterator
|
||||
entry = list[AUTOREPLACE_LIST_REPLACEMENTS].beginMap(),
|
||||
entriesEnd = list[AUTOREPLACE_LIST_REPLACEMENTS].endMap();
|
||||
listValid && entry != entriesEnd;
|
||||
entry++
|
||||
)
|
||||
{
|
||||
if ( ! entry->second.isString() )
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "non-string replacement value found in list '"
|
||||
<< list[AUTOREPLACE_LIST_NAME].asString() << "'"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return listValid;
|
||||
}
|
||||
|
||||
const LLSD* LLAutoReplaceSettings::exportList(std::string listName)
|
||||
{
|
||||
const LLSD* exportedList = NULL;
|
||||
for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray();
|
||||
exportedList == NULL && list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, listName) )
|
||||
{
|
||||
const LLSD& namedList = (*list);
|
||||
exportedList = &namedList;
|
||||
}
|
||||
}
|
||||
return exportedList;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::listNameIsUnique(const LLSD& newList)
|
||||
{
|
||||
bool nameIsUnique = true;
|
||||
// this must always be called with a valid list, so it is safe to assume it has a name
|
||||
std::string newListName = newList[AUTOREPLACE_LIST_NAME].asString();
|
||||
for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray();
|
||||
nameIsUnique && list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, newListName) )
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"duplicate list name '"<<newListName<<"'"<<LL_ENDL;
|
||||
nameIsUnique = false;
|
||||
}
|
||||
}
|
||||
return nameIsUnique;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void LLAutoReplaceSettings::createEmptyList(LLSD& emptyList)
|
||||
{
|
||||
emptyList = LLSD::emptyMap();
|
||||
emptyList[AUTOREPLACE_LIST_NAME] = "Empty";
|
||||
emptyList[AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void LLAutoReplaceSettings::setListName(LLSD& list, const std::string& newName)
|
||||
{
|
||||
list[AUTOREPLACE_LIST_NAME] = newName;
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::string LLAutoReplaceSettings::getListName(LLSD& list)
|
||||
{
|
||||
std::string name;
|
||||
if ( list.isMap() && list.has(AUTOREPLACE_LIST_NAME) && list[AUTOREPLACE_LIST_NAME].isString() )
|
||||
{
|
||||
name = list[AUTOREPLACE_LIST_NAME].asString();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::AddListResult LLAutoReplaceSettings::addList(const LLSD& newList)
|
||||
{
|
||||
AddListResult result;
|
||||
if ( listIsValid( newList ) )
|
||||
{
|
||||
if ( listNameIsUnique( newList ) )
|
||||
{
|
||||
mLists.append(newList);
|
||||
result = AddListOk;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to add duplicate name" << LL_ENDL;
|
||||
result = AddListDuplicateName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to add invalid list" << LL_ENDL;
|
||||
result = AddListInvalidList;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::AddListResult LLAutoReplaceSettings::replaceList(const LLSD& newList)
|
||||
{
|
||||
AddListResult result = AddListInvalidList;
|
||||
if ( listIsValid( newList ) )
|
||||
{
|
||||
std::string listName = newList[AUTOREPLACE_LIST_NAME].asString();
|
||||
bool listFound = false;
|
||||
S32 search_index;
|
||||
LLSD targetList;
|
||||
// The following is working around the fact that LLSD arrays containing maps also seem to have undefined entries... see LLSD-30
|
||||
for ( search_index = 0, targetList = mLists[0];
|
||||
!listFound && search_index < mLists.size();
|
||||
search_index += 1, targetList = mLists[search_index]
|
||||
)
|
||||
{
|
||||
if ( targetList.isMap() )
|
||||
{
|
||||
if ( listNameMatches( targetList, listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"list to replace found at "<<search_index<<LL_ENDL;
|
||||
mLists.erase(search_index);
|
||||
mLists.insert(search_index, newList);
|
||||
listFound = true;
|
||||
result = AddListOk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! listFound )
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to replace unconfigured list" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to add invalid list" << LL_ENDL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::removeReplacementList(std::string listName)
|
||||
{
|
||||
bool found = false;
|
||||
for( S32 index = 0; !found && mLists[index].isDefined(); index++ )
|
||||
{
|
||||
if( listNameMatches(mLists.get(index), listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"list '"<<listName<<"'"<<LL_ENDL;
|
||||
mLists.erase(index);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/// Move the named list up in the priority order
|
||||
bool LLAutoReplaceSettings::increaseListPriority(std::string listName)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<listName<<LL_ENDL;
|
||||
bool found = false;
|
||||
S32 search_index, previous_index;
|
||||
LLSD targetList;
|
||||
// The following is working around the fact that LLSD arrays containing maps also seem to have undefined entries... see LLSD-30
|
||||
previous_index = -1;
|
||||
for ( search_index = 0, targetList = mLists[0];
|
||||
!found && search_index < mLists.size();
|
||||
search_index += 1, targetList = mLists[search_index]
|
||||
)
|
||||
{
|
||||
if ( targetList.isMap() )
|
||||
{
|
||||
if ( listNameMatches( targetList, listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"found at "<<search_index<<", previous is "<<previous_index<<LL_ENDL;
|
||||
found = true;
|
||||
if (previous_index >= 0)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace") << "erase "<<search_index<<LL_ENDL;
|
||||
mLists.erase(search_index);
|
||||
LL_DEBUGS("AutoReplace") << "insert at "<<previous_index<<LL_ENDL;
|
||||
mLists.insert(previous_index, targetList);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempted to move top list up" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_index = search_index;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//LL_DEBUGS("AutoReplace") << search_index<<" is "<<LLSD::typeString(targetList.type())<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/// Move the named list down in the priority order
|
||||
bool LLAutoReplaceSettings::decreaseListPriority(std::string listName)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<listName<<LL_ENDL;
|
||||
S32 found_index = -1;
|
||||
S32 search_index;
|
||||
for ( search_index = 0;
|
||||
found_index == -1 && search_index < mLists.size();
|
||||
search_index++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches( mLists[search_index], listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"found at index "<<search_index<<LL_ENDL;
|
||||
found_index = search_index;
|
||||
}
|
||||
}
|
||||
if (found_index != -1)
|
||||
{
|
||||
S32 next_index;
|
||||
for ( next_index = found_index+1;
|
||||
next_index < mLists.size() && ! mLists[next_index].isMap();
|
||||
next_index++
|
||||
)
|
||||
{
|
||||
// skipping over any undefined slots (see LLSD-30)
|
||||
LL_WARNS("AutoReplace")<<next_index<<" ! not a map: "/*<<LLSD::typeString(mLists[next_index].type())*/<< LL_ENDL;
|
||||
}
|
||||
if ( next_index < mLists.size() )
|
||||
{
|
||||
LLSD next_list = mLists[next_index];
|
||||
LL_DEBUGS("AutoReplace") << "erase "<<next_index<<LL_ENDL;
|
||||
mLists.erase(next_index);
|
||||
LL_DEBUGS("AutoReplace") << "insert at "<<found_index<<LL_ENDL;
|
||||
mLists.insert(found_index, next_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempted to move bottom list down" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "not found" << LL_ENDL;
|
||||
}
|
||||
return (found_index != -1);
|
||||
}
|
||||
|
||||
|
||||
std::string LLAutoReplaceSettings::replaceWord(const std::string currentWord)
|
||||
{
|
||||
std::string returnedWord = currentWord; // in case no replacement is found
|
||||
static LLCachedControl<bool> autoreplace_enabled(gSavedSettings, "AutoReplace", false);
|
||||
if ( autoreplace_enabled )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"checking '"<<currentWord<<"'"<< LL_ENDL;
|
||||
//loop through lists in order
|
||||
bool found = false;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
||||
! found && list != endLists;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& checkList = *list;
|
||||
const LLSD& replacements = checkList[AUTOREPLACE_LIST_REPLACEMENTS];
|
||||
|
||||
if ( replacements.has(currentWord) )
|
||||
{
|
||||
found = true;
|
||||
LL_DEBUGS("AutoReplace")
|
||||
<< " found in list '" << checkList[AUTOREPLACE_LIST_NAME].asString()
|
||||
<< " => '" << replacements[currentWord].asString() << "'"
|
||||
<< LL_ENDL;
|
||||
returnedWord = replacements[currentWord].asString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnedWord;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::addEntryToList(LLWString keyword, LLWString replacement, std::string listName)
|
||||
{
|
||||
bool added = false;
|
||||
|
||||
if ( ! keyword.empty() && ! replacement.empty() )
|
||||
{
|
||||
bool isOneWord = true;
|
||||
for (size_t character = 0; isOneWord && character < keyword.size(); character++ )
|
||||
{
|
||||
if ( ! LLWStringUtil::isPartOfWord(keyword[character]) )
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "keyword '" << wstring_to_utf8str(keyword) << "' not a single word (len "<<keyword.size()<<" '"<<character<<"')" << LL_ENDL;
|
||||
isOneWord = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isOneWord )
|
||||
{
|
||||
bool listFound = false;
|
||||
for( LLSD::array_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
||||
! listFound && list != endLists;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, listName) )
|
||||
{
|
||||
listFound = true;
|
||||
(*list)[AUTOREPLACE_LIST_REPLACEMENTS][wstring_to_utf8str(keyword)]=wstring_to_utf8str(replacement);
|
||||
}
|
||||
}
|
||||
if (listFound)
|
||||
{
|
||||
added = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "list '" << listName << "' not found" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::removeEntryFromList(std::string keyword, std::string listName)
|
||||
{
|
||||
bool found = false;
|
||||
for( LLSD::array_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
||||
! found && list != endLists;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, listName) )
|
||||
{
|
||||
found = true;
|
||||
(*list)[AUTOREPLACE_LIST_REPLACEMENTS].erase(keyword);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "list '" << listName << "' not found" << LL_ENDL;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
LLSD LLAutoReplaceSettings::getExampleLLSD()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<LL_ENDL;
|
||||
LLSD example = LLSD::emptyArray();
|
||||
|
||||
example[0] = LLSD::emptyMap();
|
||||
example[0][AUTOREPLACE_LIST_NAME] = "Example List 1";
|
||||
example[0][AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
example[0][AUTOREPLACE_LIST_REPLACEMENTS]["keyword1"] = "replacement string 1";
|
||||
example[0][AUTOREPLACE_LIST_REPLACEMENTS]["keyword2"] = "replacement string 2";
|
||||
|
||||
example[1] = LLSD::emptyMap();
|
||||
example[1][AUTOREPLACE_LIST_NAME] = "Example List 2";
|
||||
example[1][AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
example[1][AUTOREPLACE_LIST_REPLACEMENTS]["mistake1"] = "correction 1";
|
||||
example[1][AUTOREPLACE_LIST_REPLACEMENTS]["mistake2"] = "correction 2";
|
||||
|
||||
return example;
|
||||
}
|
||||
|
||||
const LLSD& LLAutoReplaceSettings::asLLSD()
|
||||
{
|
||||
return mLists;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::~LLAutoReplaceSettings()
|
||||
{
|
||||
}
|
||||
227
indra/newview/llautoreplace.h
Normal file
227
indra/newview/llautoreplace.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* @file llautoreplace.h
|
||||
* @brief Auto Replace Manager
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#ifndef LLAUTOREPLACE_H
|
||||
#define LLAUTOREPLACE_H
|
||||
|
||||
#include "lllineeditor.h"
|
||||
|
||||
class LLAutoReplace;
|
||||
|
||||
/** The configuration data for the LLAutoReplace object
|
||||
*
|
||||
* This is a separate class so that the LLFloaterAutoReplaceSettings
|
||||
* can have a copy of the configuration to manipulate before committing
|
||||
* the changes back to the LLAutoReplace singleton that provides the
|
||||
* autoreplace callback.
|
||||
*/
|
||||
class LLAutoReplaceSettings
|
||||
{
|
||||
public:
|
||||
LLAutoReplaceSettings();
|
||||
~LLAutoReplaceSettings();
|
||||
|
||||
/// Constructor for creating a tempory copy of the current settings
|
||||
LLAutoReplaceSettings(const LLAutoReplaceSettings& settings);
|
||||
|
||||
/// Replace the current settings with new ones and save them to the user settings file
|
||||
void set(const LLAutoReplaceSettings& newSettings);
|
||||
|
||||
/// Load the current settings read from an LLSD file
|
||||
bool setFromLLSD(const LLSD& settingsFromLLSD);
|
||||
///< @returns whether or not the settingsFromLLSD were valid
|
||||
|
||||
// ================================================================
|
||||
///@{ @name List Operations
|
||||
// ================================================================
|
||||
|
||||
/// @returns the configured list names as an LLSD Array of strings
|
||||
LLSD getListNames();
|
||||
|
||||
/// Status values returned from the addList method
|
||||
typedef enum
|
||||
{
|
||||
AddListOk,
|
||||
AddListDuplicateName,
|
||||
AddListInvalidList,
|
||||
} AddListResult;
|
||||
|
||||
/// Inserts a new list at the end of the priority order
|
||||
AddListResult addList(const LLSD& newList);
|
||||
|
||||
/// Inserts a list in place of an existing list of the same name
|
||||
AddListResult replaceList(const LLSD& newList);
|
||||
|
||||
/// Removes the named list, @returns false if not found
|
||||
bool removeReplacementList(std::string listName);
|
||||
|
||||
/// Move the named list up in the priority order
|
||||
bool increaseListPriority(std::string listName);
|
||||
///< @returns false if the list is not found
|
||||
|
||||
/// Move the named list down in the priority order
|
||||
bool decreaseListPriority(std::string listName);
|
||||
///< @returns false if the list is not found
|
||||
|
||||
/// Get a copy of just one list (for saving to an export file)
|
||||
const LLSD* exportList(std::string listName);
|
||||
/// @returns an LLSD map
|
||||
|
||||
/// Checks for required elements, and that each has the correct type.
|
||||
bool listIsValid(const LLSD& listSettings);
|
||||
|
||||
/// Checks for required elements, and that each has the correct type.
|
||||
bool listNameIs(const LLSD& listSettings);
|
||||
|
||||
/// Checks to see if a new lists name conflicts with one in the settings
|
||||
bool listNameIsUnique(const LLSD& newList);
|
||||
/// @note must be called with LLSD that has passed listIsValid
|
||||
|
||||
/// Initializes emptyList to an empty list named 'Empty'
|
||||
static void createEmptyList(LLSD& emptyList);
|
||||
|
||||
/// Resets the name of a list to a new value
|
||||
static void setListName(LLSD& list, const std::string& newName);
|
||||
|
||||
/// Gets the name of a list
|
||||
static std::string getListName(LLSD& list);
|
||||
|
||||
///@}
|
||||
// ================================================================
|
||||
///@{ @name Replacement Entry Operations
|
||||
// ================================================================
|
||||
|
||||
/// Get the replacements specified by a given list
|
||||
const LLSD* getListEntries(std::string listName);
|
||||
///< @returns an LLSD Map of keyword -> replacement test pairs
|
||||
|
||||
/// Get the replacement for the keyword from the specified list
|
||||
std::string replacementFor(std::string keyword, std::string listName);
|
||||
|
||||
/// Adds a keywword/replacement pair to the named list
|
||||
bool addEntryToList(LLWString keyword, LLWString replacement, std::string listName);
|
||||
|
||||
/// Removes the keywword and its replacement from the named list
|
||||
bool removeEntryFromList(std::string keyword, std::string listName);
|
||||
|
||||
/**
|
||||
* Look for currentWord in the lists in order, returning any substitution found
|
||||
* If no configured substitution is found, returns currentWord
|
||||
*/
|
||||
std::string replaceWord(const std::string currentWord /**< word to search for */ );
|
||||
|
||||
/// Provides a hard-coded example of settings
|
||||
LLSD getExampleLLSD();
|
||||
|
||||
/// Get the actual settings as LLSD
|
||||
const LLSD& asLLSD();
|
||||
///< @note for use only in AutoReplace::saveToUserSettings
|
||||
|
||||
private:
|
||||
/// Efficiently and safely compare list names
|
||||
bool listNameMatches( const LLSD& list, const std::string name );
|
||||
|
||||
/// The actual llsd data structure
|
||||
LLSD mLists;
|
||||
|
||||
static const std::string AUTOREPLACE_LIST_NAME; ///< key for looking up list names
|
||||
static const std::string AUTOREPLACE_LIST_REPLACEMENTS; ///< key for looking up replacement map
|
||||
|
||||
/**<
|
||||
* LLSD structure of the lists
|
||||
* - The configuration is an array (mLists),
|
||||
* - Each entry in the array is a replacement list
|
||||
* - Each replacement list is a map with three keys:
|
||||
* @verbatim
|
||||
* "name" String the name of the list
|
||||
* "replacements" Map keyword -> replacement pairs
|
||||
*
|
||||
* <llsd>
|
||||
* <array>
|
||||
* <map>
|
||||
* <key>name</key> <string>List 1</string>
|
||||
* <key>data</key>
|
||||
* <map>
|
||||
* <key>keyword1</key> <string>replacement1</string>
|
||||
* <key>keyword2</key> <string>replacement2</string>
|
||||
* </map>
|
||||
* </map>
|
||||
* <map>
|
||||
* <key>name</key> <string>List 2</string>
|
||||
* <key>data</key>
|
||||
* <map>
|
||||
* <key>keyword1</key> <string>replacement1</string>
|
||||
* <key>keyword2</key> <string>replacement2</string>
|
||||
* </map>
|
||||
* </map>
|
||||
* </array>
|
||||
* </llsd>
|
||||
* @endverbatim
|
||||
*/
|
||||
};
|
||||
|
||||
/** Provides a facility to auto-replace text dynamically as it is entered.
|
||||
*
|
||||
* When the end of a word is detected (defined as any punctuation character,
|
||||
* or any whitespace except newline or return), the preceding word is used
|
||||
* as a lookup key in an ordered list of maps. If a match is found in any
|
||||
* map, the replacement start index and length are returned along with the
|
||||
* new replacement string.
|
||||
*
|
||||
* See the autoreplaceCallback method for how to add autoreplace functionality
|
||||
* to a text entry tool.
|
||||
*/
|
||||
class LLAutoReplace : public LLSingleton<LLAutoReplace>
|
||||
{
|
||||
public:
|
||||
/// Callback that provides the hook for use in text entry methods
|
||||
void autoreplaceCallback(S32& replacement_start, S32& replacement_length, LLWString& replacement_string, S32& cursor_pos, const LLWString& input_text);
|
||||
|
||||
/// Get a copy of the current settings
|
||||
LLAutoReplaceSettings getSettings();
|
||||
|
||||
/// Commit new settings after making changes
|
||||
void setSettings(const LLAutoReplaceSettings& settings);
|
||||
|
||||
private:
|
||||
friend class LLSingleton<LLAutoReplace>;
|
||||
LLAutoReplace();
|
||||
/*virtual*/ void initSingleton();
|
||||
|
||||
LLAutoReplaceSettings mSettings; ///< configuration information
|
||||
|
||||
/// Read settings from persistent storage
|
||||
void loadFromSettings();
|
||||
|
||||
/// Make the newSettings active and write them to user storage
|
||||
void saveToUserSettings();
|
||||
|
||||
/// Compute the user settings file name
|
||||
std::string getUserSettingsFileName();
|
||||
|
||||
/// Compute the (read-ony) application settings file name
|
||||
std::string getAppSettingsFileName();
|
||||
|
||||
/// basename for the settings files
|
||||
static const char* SETTINGS_FILE_NAME;
|
||||
};
|
||||
|
||||
#endif /* LLAUTOREPLACE_H */
|
||||
@@ -52,8 +52,9 @@
|
||||
#include "llslurl.h" // IDEVO
|
||||
#include "llavatarname.h"
|
||||
#include "llagentui.h"
|
||||
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
|
||||
#include "rlvhandler.h"
|
||||
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0)
|
||||
#include "rlvactions.h"
|
||||
#include "rlvcommon.h"
|
||||
// [/RLVa:KB]
|
||||
|
||||
#include "llviewerwindow.h"
|
||||
@@ -182,16 +183,12 @@ void LLAvatarActions::startIM(const LLUUID& id)
|
||||
if (id.isNull() || gAgentID == id)
|
||||
return;
|
||||
|
||||
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
|
||||
if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(id)) )
|
||||
// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
|
||||
if ( (!RlvActions::canStartIM(id)) && (!RlvActions::hasOpenP2PSession(id)) )
|
||||
{
|
||||
LLUUID idSession = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, id);
|
||||
if ( (idSession.notNull()) && (!gIMMgr->hasSession(idSession)) )
|
||||
{
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
|
||||
return;
|
||||
}
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
|
||||
return;
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
@@ -234,16 +231,12 @@ void LLAvatarActions::startCall(const LLUUID& id)
|
||||
return;
|
||||
}
|
||||
|
||||
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
|
||||
if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(id)) )
|
||||
// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
|
||||
if ( (!RlvActions::canStartIM(id)) && (!RlvActions::hasOpenP2PSession(id)) )
|
||||
{
|
||||
LLUUID idSession = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, id);
|
||||
if ( (idSession.notNull()) && (!gIMMgr->hasSession(idSession)) )
|
||||
{
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
|
||||
return;
|
||||
}
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
|
||||
return;
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
@@ -262,12 +255,12 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids)
|
||||
LLDynamicArray<LLUUID> id_array;
|
||||
for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
|
||||
{
|
||||
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
|
||||
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0)
|
||||
const LLUUID& idAgent = *it;
|
||||
if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(idAgent)) )
|
||||
if (!RlvActions::canStartIM(idAgent))
|
||||
{
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF, LLSD().with("RECIPIENT", LLSLURL("agent", idAgent, "completename").getSLURLString()));
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
|
||||
return;
|
||||
}
|
||||
id_array.push_back(idAgent);
|
||||
@@ -315,12 +308,12 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids)
|
||||
{
|
||||
for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
|
||||
{
|
||||
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
|
||||
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0)
|
||||
const LLUUID& idAgent = *it;
|
||||
if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(idAgent)) )
|
||||
if (!RlvActions::canStartIM(idAgent))
|
||||
{
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF, LLSD().with("RECIPIENT", LLSLURL("agent", idAgent, "completename").getSLURLString()));
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
|
||||
return;
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "llfocusmgr.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llautoreplace.h"
|
||||
#include "llbutton.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llcommandhandler.h" // secondlife:///app/chat/ support
|
||||
@@ -149,6 +150,7 @@ BOOL LLChatBar::postBuild()
|
||||
mInputEditor = findChild<LLLineEditor>("Chat Editor");
|
||||
if (mInputEditor)
|
||||
{
|
||||
mInputEditor->setAutoreplaceCallback(boost::bind(&LLAutoReplace::autoreplaceCallback, LLAutoReplace::getInstance(), _1, _2, _3, _4, _5));
|
||||
mInputEditor->setKeystrokeCallback(boost::bind(&LLChatBar::onInputEditorKeystroke,this));
|
||||
mInputEditor->setFocusLostCallback(boost::bind(&LLChatBar::onInputEditorFocusLost));
|
||||
mInputEditor->setFocusReceivedCallback(boost::bind(&LLChatBar::onInputEditorGainFocus));
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout;
|
||||
extern const std::string OLD_LOG_FILE;
|
||||
|
||||
class LLCrashLoggerResponder : public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
@@ -284,7 +285,7 @@ void LLCrashLogger::gatherFiles()
|
||||
mCrashInfo["DebugLog"] = mDebugLog;
|
||||
mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"stats.log");
|
||||
// Singu Note: we have just started again, log has been renamed
|
||||
mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "Singularity.old");
|
||||
mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, OLD_LOG_FILE);
|
||||
|
||||
llinfos << "Encoding files..." << llendl;
|
||||
|
||||
|
||||
@@ -295,14 +295,7 @@ void LLDrawPoolAlpha::render(S32 pass)
|
||||
}
|
||||
}
|
||||
|
||||
if (mVertexShaderLevel > 0)
|
||||
{
|
||||
renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, pass);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderAlpha(getVertexDataMask(), pass);
|
||||
}
|
||||
renderAlpha(getVertexDataMask(), pass); //getVertexDataMask base mask if fixed-function.
|
||||
|
||||
gGL.setColorMask(true, false);
|
||||
|
||||
@@ -380,6 +373,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
|
||||
BOOL light_enabled = TRUE;
|
||||
|
||||
BOOL use_shaders = gPipeline.canUseVertexShaders();
|
||||
|
||||
BOOL depth_only = (pass == 1 && !LLPipeline::sImpostorRender);
|
||||
|
||||
for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
|
||||
{
|
||||
@@ -394,7 +389,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
|
||||
|| group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_CLOUD
|
||||
|| group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE;
|
||||
|
||||
bool draw_glow_for_this_partition = mVertexShaderLevel > 0; // no shaders = no glow.
|
||||
bool draw_glow_for_this_partition = !depth_only && mVertexShaderLevel > 0; // no shaders = no glow.
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group");
|
||||
LLFastTimer t(FTM_RENDER_ALPHA_GROUP_LOOP);
|
||||
@@ -408,16 +403,16 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
|
||||
{
|
||||
LLDrawInfo& params = **k;
|
||||
|
||||
if ((params.mVertexBuffer->getTypeMask() & mask) != mask)
|
||||
/*if ((params.mVertexBuffer->getTypeMask() & mask) != mask)
|
||||
{ //FIXME!
|
||||
llwarns << "Missing required components, skipping render batch." << llendl;
|
||||
continue;
|
||||
}
|
||||
}*/
|
||||
|
||||
// Fix for bug - NORSPEC-271
|
||||
// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
|
||||
// We don't want the nearly invisible objects to cause of DoF effects
|
||||
if(pass == 1 && !LLPipeline::sImpostorRender)
|
||||
if(depth_only)
|
||||
{
|
||||
LLFace* face = params.mFace;
|
||||
if(face)
|
||||
@@ -450,18 +445,19 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
|
||||
llassert_always(!LLGLSLShader::sNoFixedFunction);
|
||||
llassert_always(!LLGLSLShader::sCurBoundShaderPtr);
|
||||
|
||||
if(params.mFullbright == light_enabled || !initialized_lighting)
|
||||
bool fullbright = depth_only || params.mFullbright;
|
||||
if(fullbright == !!light_enabled || !initialized_lighting)
|
||||
{
|
||||
light_enabled = !params.mFullbright;
|
||||
light_enabled = !fullbright;
|
||||
initialized_lighting = true;
|
||||
|
||||
if (light_enabled) // Turn off lighting if it hasn't already been so.
|
||||
{
|
||||
gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
|
||||
gPipeline.enableLightsDynamic();
|
||||
}
|
||||
else // Turn on lighting if it isn't already.
|
||||
{
|
||||
gPipeline.enableLightsDynamic();
|
||||
gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -512,7 +508,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
|
||||
current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, params.mSpecularMap);
|
||||
}
|
||||
}
|
||||
else if(deferred_render && current_shader == simple_shader)
|
||||
/*else if(deferred_render && current_shader == simple_shader)
|
||||
{
|
||||
current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, 0.0f);
|
||||
@@ -520,7 +516,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
|
||||
current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep);
|
||||
LLViewerFetchedTexture::sWhiteImagep->addTextureStats(params.mVSize);
|
||||
current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep);
|
||||
}
|
||||
}*/
|
||||
|
||||
if (params.mTextureList.size() > 1)
|
||||
{
|
||||
@@ -567,12 +563,13 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
|
||||
static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_PUSH("Alpha Push Verts");
|
||||
{
|
||||
LLFastTimer t(FTM_RENDER_ALPHA_PUSH);
|
||||
gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
|
||||
// Singu Note: Only remove tan/texcoord1/texcoord2 if actually using the fullbright shader. Material faces ignore fullbright bit.
|
||||
params.mVertexBuffer->setBuffer(mask & ~((current_shader == fullbright_shader) ? (LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2) : 0));
|
||||
|
||||
gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
|
||||
// Singu Note: If using shaders, pull the attribute mask from it, else used passed base mask.
|
||||
params.mVertexBuffer->setBuffer(current_shader ? current_shader->mAttributeMask : mask);
|
||||
|
||||
params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
|
||||
gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
|
||||
params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
|
||||
gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
|
||||
}
|
||||
|
||||
// If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow). Interleaving these state-changing calls could be expensive, but glow must be drawn Z-sorted with alpha.
|
||||
@@ -588,7 +585,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
|
||||
emissive_shader->bind();
|
||||
|
||||
// glow doesn't use vertex colors from the mesh data
|
||||
params.mVertexBuffer->setBuffer((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE);
|
||||
// Singu Note: Pull attribs from shader, since we always have one here.
|
||||
params.mVertexBuffer->setBuffer(emissive_shader->mAttributeMask);
|
||||
|
||||
// do the actual drawing, again
|
||||
params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
|
||||
|
||||
@@ -1575,6 +1575,10 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
|
||||
for (U32 j = 0; j < count; ++j)
|
||||
{
|
||||
LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
|
||||
if(!joint)
|
||||
{
|
||||
joint = avatar->getJoint("mRoot");
|
||||
}
|
||||
if (joint)
|
||||
{
|
||||
mat[j] = skin->mInvBindMatrix[j];
|
||||
@@ -1599,7 +1603,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
|
||||
{
|
||||
F32 w = weight[j][k];
|
||||
|
||||
idx[k] = llclamp((S32) floorf(w), 0, 63);
|
||||
idx[k] = llclamp((S32) floorf(w), 0, S32(count-1));
|
||||
wght[k] = w - floorf(w);
|
||||
scale += wght[k];
|
||||
}
|
||||
@@ -1703,6 +1707,10 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
|
||||
for (U32 i = 0; i < count; ++i)
|
||||
{
|
||||
LLJoint* joint = avatar->getJoint(skin->mJointNames[i]);
|
||||
if(!joint)
|
||||
{
|
||||
joint = avatar->getJoint("mRoot");
|
||||
}
|
||||
if (joint)
|
||||
{
|
||||
mat[i] = skin->mInvBindMatrix[i];
|
||||
@@ -1747,7 +1755,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
|
||||
(GLfloat*) mp);
|
||||
|
||||
LLDrawPoolAvatar::sVertexProgram->uniform3fv(LLShaderMgr::AVATAR_TRANSLATION, count, transp);
|
||||
|
||||
LLDrawPoolAvatar::sVertexProgram->uniform1f(LLShaderMgr::AVATAR_MAX_WEIGHT, F32(count-1));
|
||||
|
||||
stop_glerror();
|
||||
}
|
||||
@@ -1943,7 +1951,7 @@ void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
|
||||
LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
|
||||
|
||||
renderRigged(avatar, RIGGED_ALPHA);
|
||||
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
//gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
gGL.setColorMask(true, false);
|
||||
}
|
||||
}
|
||||
@@ -1961,7 +1969,7 @@ void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
|
||||
LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
|
||||
|
||||
renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
|
||||
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
//gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
gGL.setColorMask(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ void LLDrawPoolBump::render(S32 pass)
|
||||
{
|
||||
LLFastTimer t(FTM_RENDER_BUMP);
|
||||
|
||||
if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE))
|
||||
if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -548,11 +548,17 @@ void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass)
|
||||
{
|
||||
if (LLPipeline::sUnderWaterRender)
|
||||
{
|
||||
gDeferredFullbrightWaterProgram.bind();
|
||||
//gDeferredFullbrightWaterProgram.bind();
|
||||
//Use alpha-mask version to ignore alpha values while still allowing us to occlude glow.
|
||||
gDeferredFullbrightAlphaMaskWaterProgram.bind();
|
||||
gDeferredFullbrightAlphaMaskWaterProgram.setMinimumAlpha(0.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
gDeferredFullbrightProgram.bind();
|
||||
//gDeferredFullbrightProgram.bind();
|
||||
//Use alpha-mask version to ignore alpha values while still allowing us to occlude glow.
|
||||
gDeferredFullbrightAlphaMaskProgram.bind();
|
||||
gDeferredFullbrightAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -573,11 +579,11 @@ void LLDrawPoolFullbright::endPostDeferredPass(S32 pass)
|
||||
{
|
||||
if (LLPipeline::sUnderWaterRender)
|
||||
{
|
||||
gDeferredFullbrightWaterProgram.unbind();
|
||||
gDeferredFullbrightAlphaMaskWaterProgram.unbind();
|
||||
}
|
||||
else
|
||||
{
|
||||
gDeferredFullbrightProgram.unbind();
|
||||
gDeferredFullbrightAlphaMaskProgram.unbind();
|
||||
}
|
||||
LLRenderPass::endRenderPass(pass);
|
||||
}
|
||||
|
||||
@@ -253,6 +253,7 @@ void LLDrawPoolWater::render(S32 pass)
|
||||
|
||||
glClearStencil(1);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glClearStencil(0);
|
||||
LLGLEnable gls_stencil(GL_STENCIL_TEST);
|
||||
glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);
|
||||
glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
|
||||
|
||||
@@ -326,6 +326,7 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass)
|
||||
|
||||
const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius();
|
||||
|
||||
LLGLDisable stencil(GL_STENCIL_TEST);
|
||||
LLGLSNoFog disableFog;
|
||||
LLGLDepthTest depth(GL_TRUE, GL_FALSE);
|
||||
LLGLDisable clip(GL_CLIP_PLANE0);
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
// LLEmote()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLEmote::LLEmote(const LLUUID &id) : LLMotion(id)
|
||||
LLEmote::LLEmote(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class LLEmote :
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLEmote(const LLUUID &id);
|
||||
LLEmote(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLEmote();
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLEmote(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEmote(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@@ -1297,15 +1297,33 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
||||
|
||||
if (rebuild_color) // FALSE if tep == NULL
|
||||
{ //decide if shiny goes in alpha channel of color
|
||||
|
||||
static const LLCachedControl<bool> alt_batching("SHAltBatching",true);
|
||||
if (tep &&
|
||||
getPoolType() != LLDrawPool::POOL_ALPHA) // <--- alpha channel MUST contain transparency, not shiny
|
||||
((!alt_batching && getPoolType() != LLDrawPool::POOL_ALPHA) ||
|
||||
(alt_batching && getPoolType() != LLDrawPool::POOL_ALPHA &&
|
||||
getPoolType() != LLDrawPool::POOL_ALPHA_MASK &&
|
||||
getPoolType() != LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK && // <--- alpha channel MUST contain transparency, not shiny
|
||||
(getPoolType() != LLDrawPool::POOL_SIMPLE || LLPipeline::sRenderDeferred)))) // Impostor pass for simple uses alpha masking. Need to be opaque.
|
||||
{
|
||||
LLMaterial* mat = tep->getMaterialParams().get();
|
||||
|
||||
bool shiny_in_alpha = false;
|
||||
bool shiny_in_alpha = alt_batching ? true : false;
|
||||
|
||||
if(alt_batching)
|
||||
{
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{ //store shiny in alpha if we don't have a specular map
|
||||
if (getPoolType() == LLDrawPool::POOL_MATERIALS && mat->getSpecularID().notNull())
|
||||
{
|
||||
shiny_in_alpha = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
if (!mat || mat->getSpecularID().isNull())
|
||||
{
|
||||
shiny_in_alpha = true;
|
||||
@@ -1318,10 +1336,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
||||
shiny_in_alpha = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shiny_in_alpha)
|
||||
if(getPoolType() == LLDrawPool::POOL_FULLBRIGHT)
|
||||
{
|
||||
color.mV[3] = 1.f; //Simple fullbright reads alpha for fog contrib, not shiny/transparency, so since opaque, force to 1.
|
||||
}
|
||||
else if (shiny_in_alpha)
|
||||
{
|
||||
|
||||
GLfloat alpha[4] =
|
||||
{
|
||||
0.00f,
|
||||
|
||||
@@ -62,8 +62,9 @@
|
||||
|
||||
#include "hippogridmanager.h"
|
||||
|
||||
// [RLVa:KB]
|
||||
#include "rlvhandler.h"
|
||||
// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.4.0)
|
||||
#include "rlvactions.h"
|
||||
#include "rlvhelper.h"
|
||||
// [/RLVa:KB]
|
||||
|
||||
#if LL_WINDOWS
|
||||
@@ -168,15 +169,7 @@ LLFloaterAbout::LLFloaterAbout()
|
||||
|
||||
// Position
|
||||
LLViewerRegion* region = gAgent.getRegion();
|
||||
// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-04 (RLVa-1.0.0a)
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
|
||||
{
|
||||
support.append(RlvStrings::getString(RLV_STRING_HIDDEN));
|
||||
support.append("\n\n");
|
||||
}
|
||||
else if (region)
|
||||
// [/RLVa:KB]
|
||||
// if (region)
|
||||
if (region)
|
||||
{
|
||||
LLStyleSP server_link_style(new LLStyle);
|
||||
server_link_style->setVisible(true);
|
||||
@@ -184,6 +177,9 @@ LLFloaterAbout::LLFloaterAbout()
|
||||
server_link_style->setLinkHREF(region->getCapability("ServerReleaseNotes"));
|
||||
server_link_style->setColor(gSavedSettings.getColor4("HTMLLinkColor"));
|
||||
|
||||
// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10)
|
||||
if (RlvActions::canShowLocation())
|
||||
{
|
||||
const LLVector3d &pos = gAgent.getPositionGlobal();
|
||||
LLUIString pos_text = getString("you_are_at");
|
||||
pos_text.setArg("[POSITION]",
|
||||
@@ -204,6 +200,10 @@ LLFloaterAbout::LLFloaterAbout()
|
||||
support.append(buffer);
|
||||
support.append(")");
|
||||
}
|
||||
}
|
||||
else
|
||||
support.append(RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
|
||||
// [/RLVa:KN]
|
||||
support.append("\n");
|
||||
|
||||
support.append(gLastVersionChannel);
|
||||
@@ -267,6 +267,10 @@ LLFloaterAbout::LLFloaterAbout()
|
||||
|
||||
support.append("OpenGL Version: ");
|
||||
support.append( (const char*) glGetString(GL_VERSION) );
|
||||
// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0)
|
||||
support.append("\n");
|
||||
support.append("RLV Version: " + (RlvActions::isRlvEnabled()) ? RlvStrings::getVersionAbout() : "(disabled)");
|
||||
// [/RLVa:KB]
|
||||
support.append("\n\n");
|
||||
|
||||
support.append("Viewer SSE Version: ");
|
||||
|
||||
632
indra/newview/llfloaterautoreplacesettings.cpp
Normal file
632
indra/newview/llfloaterautoreplacesettings.cpp
Normal file
@@ -0,0 +1,632 @@
|
||||
/**
|
||||
* @file llfloaterautoreplacesettings.cpp
|
||||
* @brief Auto Replace List floater
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloaterautoreplacesettings.h"
|
||||
|
||||
#include "statemachine/aifilepicker.h"
|
||||
#include "llscrolllistctrl.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
#include "llautoreplace.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
|
||||
LLFloaterAutoReplaceSettings::LLFloaterAutoReplaceSettings(const LLSD& key)
|
||||
: LLFloater(/*key*/)
|
||||
, mSelectedListName("")
|
||||
, mListNames(NULL)
|
||||
, mReplacementsList(NULL)
|
||||
, mKeyword(NULL)
|
||||
, mPreviousKeyword("")
|
||||
, mReplacement(NULL)
|
||||
{
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_autoreplace.xml");
|
||||
}
|
||||
|
||||
BOOL LLFloaterAutoReplaceSettings::postBuild(void)
|
||||
{
|
||||
// get copies of the current settings that we will operate on
|
||||
mEnabled = gSavedSettings.getBOOL("AutoReplace");
|
||||
LL_DEBUGS("AutoReplace") << ( mEnabled ? "enabled" : "disabled") << LL_ENDL;
|
||||
|
||||
mSettings = LLAutoReplace::getInstance()->getSettings();
|
||||
|
||||
// global checkbox for whether or not autoreplace is active
|
||||
LLUICtrl* enabledCheckbox = getChild<LLUICtrl>("autoreplace_enable");
|
||||
enabledCheckbox->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onAutoReplaceToggled, this));
|
||||
enabledCheckbox->setValue(LLSD(mEnabled));
|
||||
|
||||
// top row list creation and deletion
|
||||
getChild<LLUICtrl>("autoreplace_import_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onImportList,this));
|
||||
getChild<LLUICtrl>("autoreplace_export_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onExportList,this));
|
||||
getChild<LLUICtrl>("autoreplace_new_list")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onNewList,this));
|
||||
getChild<LLUICtrl>("autoreplace_delete_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteList,this));
|
||||
|
||||
// the list of keyword->replacement lists
|
||||
mListNames = getChild<LLScrollListCtrl>("autoreplace_list_name");
|
||||
mListNames->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectList, this));
|
||||
mListNames->setCommitOnSelectionChange(true);
|
||||
|
||||
// list ordering
|
||||
getChild<LLUICtrl>("autoreplace_list_up")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onListUp,this));
|
||||
getChild<LLUICtrl>("autoreplace_list_down")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onListDown,this));
|
||||
|
||||
// keyword->replacement entry add / delete
|
||||
getChild<LLUICtrl>("autoreplace_add_entry")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onAddEntry,this));
|
||||
getChild<LLUICtrl>("autoreplace_delete_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteEntry,this));
|
||||
|
||||
// entry edits
|
||||
mKeyword = getChild<LLLineEditor>("autoreplace_keyword");
|
||||
mReplacement = getChild<LLLineEditor>("autoreplace_replacement");
|
||||
getChild<LLUICtrl>("autoreplace_save_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveEntry, this));
|
||||
|
||||
// dialog termination ( Save Changes / Cancel )
|
||||
getChild<LLUICtrl>("autoreplace_save_changes")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveChanges, this));
|
||||
getChild<LLUICtrl>("autoreplace_cancel")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::close, this, false));
|
||||
|
||||
// the list of keyword->replacement pairs
|
||||
mReplacementsList = getChild<LLScrollListCtrl>("autoreplace_list_replacements");
|
||||
mReplacementsList->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectEntry, this));
|
||||
mReplacementsList->setCommitOnSelectionChange(true);
|
||||
|
||||
center();
|
||||
|
||||
mSelectedListName.clear();
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterAutoReplaceSettings::updateListNames()
|
||||
{
|
||||
mListNames->deleteAllItems(); // start from scratch
|
||||
|
||||
LLSD listNames = mSettings.getListNames(); // Array of Strings
|
||||
|
||||
for ( LLSD::array_const_iterator entry = listNames.beginArray(), end = listNames.endArray();
|
||||
entry != end;
|
||||
++entry
|
||||
)
|
||||
{
|
||||
const std::string& listName = entry->asString();
|
||||
mListNames->addSimpleElement(listName);
|
||||
}
|
||||
|
||||
if (!mSelectedListName.empty())
|
||||
{
|
||||
mListNames->setSelectedByValue( LLSD(mSelectedListName), true );
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::updateListNamesControls()
|
||||
{
|
||||
if ( mSelectedListName.empty() )
|
||||
{
|
||||
// There is no selected list
|
||||
|
||||
// Disable all controls that operate on the selected list
|
||||
getChild<LLButton>("autoreplace_export_list")->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_delete_list")->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_list_up")->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_list_down")->setEnabled(false);
|
||||
|
||||
mReplacementsList->deleteAllItems();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enable the controls that operate on the selected list
|
||||
getChild<LLButton>("autoreplace_export_list")->setEnabled(true);
|
||||
getChild<LLButton>("autoreplace_delete_list")->setEnabled(true);
|
||||
getChild<LLButton>("autoreplace_list_up")->setEnabled(!selectedListIsFirst());
|
||||
getChild<LLButton>("autoreplace_list_down")->setEnabled(!selectedListIsLast());
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onSelectList()
|
||||
{
|
||||
std::string previousSelectedListName = mSelectedListName;
|
||||
// only one selection allowed
|
||||
LLSD selected = mListNames->getSelectedValue();
|
||||
if (selected.isDefined())
|
||||
{
|
||||
mSelectedListName = selected.asString();
|
||||
LL_DEBUGS("AutoReplace")<<"selected list '"<<mSelectedListName<<"'"<<LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelectedListName.clear();
|
||||
LL_DEBUGS("AutoReplace")<<"unselected"<<LL_ENDL;
|
||||
}
|
||||
|
||||
updateListNamesControls();
|
||||
|
||||
if ( previousSelectedListName != mSelectedListName )
|
||||
{
|
||||
updateReplacementsList();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onSelectEntry()
|
||||
{
|
||||
LLSD selectedRow = mReplacementsList->getSelectedValue();
|
||||
if (selectedRow.isDefined())
|
||||
{
|
||||
mPreviousKeyword = selectedRow.asString();
|
||||
LL_DEBUGS("AutoReplace")<<"selected entry '"<<mPreviousKeyword<<"'"<<LL_ENDL;
|
||||
mKeyword->setValue(selectedRow);
|
||||
std::string replacement = mSettings.replacementFor(mPreviousKeyword, mSelectedListName );
|
||||
mReplacement->setValue(replacement);
|
||||
enableReplacementEntry();
|
||||
mReplacement->setFocus(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no entry selection, so the entry panel should be off
|
||||
disableReplacementEntry();
|
||||
LL_DEBUGS("AutoReplace")<<"no row selected"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::updateReplacementsList()
|
||||
{
|
||||
// start from scratch, since this should only be called when the list changes
|
||||
mReplacementsList->deleteAllItems();
|
||||
|
||||
if ( mSelectedListName.empty() )
|
||||
{
|
||||
mReplacementsList->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_add_entry")->setEnabled(false);
|
||||
disableReplacementEntry();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Populate the keyword->replacement list from the selected list
|
||||
const LLSD* mappings = mSettings.getListEntries(mSelectedListName);
|
||||
for ( LLSD::map_const_iterator entry = mappings->beginMap(), end = mappings->endMap();
|
||||
entry != end;
|
||||
entry++
|
||||
)
|
||||
{
|
||||
LLSD row;
|
||||
row["id"] = entry->first;
|
||||
row["columns"][0]["column"] = "Keyword";
|
||||
row["columns"][0]["value"] = entry->first;
|
||||
row["columns"][1]["column"] = "Replacement";
|
||||
row["columns"][1]["value"] = entry->second;
|
||||
|
||||
mReplacementsList->addElement(row, ADD_BOTTOM);
|
||||
}
|
||||
|
||||
mReplacementsList->deselectAllItems(false /* don't call commit */);
|
||||
mReplacementsList->setEnabled(true);
|
||||
|
||||
getChild<LLButton>("autoreplace_add_entry")->setEnabled(true);
|
||||
disableReplacementEntry();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::enableReplacementEntry()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<LL_ENDL;
|
||||
mKeyword->setEnabled(true);
|
||||
mReplacement->setEnabled(true);
|
||||
getChild<LLButton>("autoreplace_save_entry")->setEnabled(true);
|
||||
getChild<LLButton>("autoreplace_delete_entry")->setEnabled(true);
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::disableReplacementEntry()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<LL_ENDL;
|
||||
mPreviousKeyword.clear();
|
||||
mKeyword->clear();
|
||||
mKeyword->setEnabled(false);
|
||||
mReplacement->clear();
|
||||
mReplacement->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_save_entry")->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_delete_entry")->setEnabled(false);
|
||||
}
|
||||
|
||||
// called when the global settings checkbox is changed
|
||||
void LLFloaterAutoReplaceSettings::onAutoReplaceToggled()
|
||||
{
|
||||
// set our local copy of the flag, copied to the global preference in onOk
|
||||
mEnabled = childGetValue("autoreplace_enable").asBoolean();
|
||||
LL_DEBUGS("AutoReplace")<< "autoreplace_enable " << ( mEnabled ? "on" : "off" ) << LL_ENDL;
|
||||
}
|
||||
|
||||
// called when the List Up button is pressed
|
||||
void LLFloaterAutoReplaceSettings::onListUp()
|
||||
{
|
||||
S32 selectedRow = mListNames->getFirstSelectedIndex();
|
||||
LLSD selectedName = mListNames->getSelectedValue().asString();
|
||||
|
||||
if ( mSettings.increaseListPriority(selectedName) )
|
||||
{
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "invalid row ("<<selectedRow<<") selected '"<<selectedName<<"'"
|
||||
<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// called when the List Down button is pressed
|
||||
void LLFloaterAutoReplaceSettings::onListDown()
|
||||
{
|
||||
S32 selectedRow = mListNames->getFirstSelectedIndex();
|
||||
std::string selectedName = mListNames->getSelectedValue().asString();
|
||||
|
||||
if ( mSettings.decreaseListPriority(selectedName) )
|
||||
{
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "invalid row ("<<selectedRow<<") selected '"<<selectedName<<"'"
|
||||
<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// called when the Delete Entry button is pressed
|
||||
void LLFloaterAutoReplaceSettings::onDeleteEntry()
|
||||
{
|
||||
LLSD selectedRow = mReplacementsList->getSelectedValue();
|
||||
if (selectedRow.isDefined())
|
||||
{
|
||||
std::string keyword = selectedRow.asString();
|
||||
mReplacementsList->deleteSelectedItems(); // delete from the control
|
||||
mSettings.removeEntryFromList(keyword, mSelectedListName); // delete from the local settings copy
|
||||
disableReplacementEntry(); // no selection active, so turn off the buttons
|
||||
}
|
||||
}
|
||||
|
||||
// called when the Import List button is pressed
|
||||
void LLFloaterAutoReplaceSettings::onImportList()
|
||||
{
|
||||
AIFilePicker* picker = AIFilePicker::create();
|
||||
picker->open(FFLOAD_XML, "", "autoreplace");
|
||||
picker->run(boost::bind(&LLFloaterAutoReplaceSettings::onImportList_continued, this, picker));
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onImportList_continued(AIFilePicker* picker)
|
||||
{
|
||||
if (picker->hasFilename())
|
||||
{
|
||||
llifstream file;
|
||||
file.open(picker->getFilename());
|
||||
LLSD newList;
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXMLDocument(newList, file);
|
||||
}
|
||||
file.close();
|
||||
|
||||
switch ( mSettings.addList(newList) )
|
||||
{
|
||||
case LLAutoReplaceSettings::AddListOk:
|
||||
mSelectedListName = LLAutoReplaceSettings::getListName(newList);
|
||||
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
break;
|
||||
|
||||
case LLAutoReplaceSettings::AddListDuplicateName:
|
||||
{
|
||||
std::string newName = LLAutoReplaceSettings::getListName(newList);
|
||||
LL_WARNS("AutoReplace")<<"name '"<<newName<<"' is in use; prompting for new name"<<LL_ENDL;
|
||||
LLSD newPayload;
|
||||
newPayload["list"] = newList;
|
||||
LLSD args;
|
||||
args["DUPNAME"] = newName;
|
||||
|
||||
LLNotificationsUtil::add("RenameAutoReplaceList", args, newPayload,
|
||||
boost::bind(&LLFloaterAutoReplaceSettings::callbackListNameConflict, this, _1, _2));
|
||||
}
|
||||
break;
|
||||
|
||||
case LLAutoReplaceSettings::AddListInvalidList:
|
||||
LLNotificationsUtil::add("InvalidAutoReplaceList");
|
||||
LL_WARNS("AutoReplace") << "imported list was invalid" << LL_ENDL;
|
||||
|
||||
mSelectedListName.clear();
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
break;
|
||||
|
||||
default:
|
||||
LL_ERRS("AutoReplace") << "invalid AddListResult" << LL_ENDL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AutoReplace") << "file selection failed for import list" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onNewList()
|
||||
{
|
||||
LLSD payload;
|
||||
LLSD emptyList;
|
||||
LLAutoReplaceSettings::createEmptyList(emptyList);
|
||||
payload["list"] = emptyList;
|
||||
LLSD args;
|
||||
|
||||
LLNotificationsUtil::add("AddAutoReplaceList", args, payload,
|
||||
boost::bind(&LLFloaterAutoReplaceSettings::callbackNewListName, this, _1, _2));
|
||||
}
|
||||
|
||||
bool LLFloaterAutoReplaceSettings::callbackNewListName(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"called"<<LL_ENDL;
|
||||
|
||||
LLSD newList = notification["payload"]["list"];
|
||||
|
||||
if ( response.has("listname") && response["listname"].isString() )
|
||||
{
|
||||
std::string newName = response["listname"].asString();
|
||||
LLAutoReplaceSettings::setListName(newList, newName);
|
||||
|
||||
switch ( mSettings.addList(newList) )
|
||||
{
|
||||
case LLAutoReplaceSettings::AddListOk:
|
||||
LL_INFOS("AutoReplace") << "added new list '"<<newName<<"'"<<LL_ENDL;
|
||||
mSelectedListName = newName;
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
break;
|
||||
|
||||
case LLAutoReplaceSettings::AddListDuplicateName:
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"name '"<<newName<<"' is in use; prompting for new name"<<LL_ENDL;
|
||||
LLSD newPayload;
|
||||
newPayload["list"] = notification["payload"]["list"];
|
||||
LLSD args;
|
||||
args["DUPNAME"] = newName;
|
||||
|
||||
LLNotificationsUtil::add("RenameAutoReplaceList", args, newPayload,
|
||||
boost::bind(&LLFloaterAutoReplaceSettings::callbackListNameConflict, this, _1, _2));
|
||||
}
|
||||
break;
|
||||
|
||||
case LLAutoReplaceSettings::AddListInvalidList:
|
||||
LLNotificationsUtil::add("InvalidAutoReplaceList");
|
||||
|
||||
mSelectedListName.clear();
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
break;
|
||||
|
||||
default:
|
||||
LL_ERRS("AutoReplace") << "invalid AddListResult" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("AutoReplace") << "adding notification response" << LL_ENDL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// callback for the RenameAutoReplaceList notification
|
||||
bool LLFloaterAutoReplaceSettings::callbackListNameConflict(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
LLSD newList = notification["payload"]["list"];
|
||||
std::string listName = LLAutoReplaceSettings::getListName(newList);
|
||||
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
switch ( option )
|
||||
{
|
||||
case 0:
|
||||
// Replace current list
|
||||
if ( LLAutoReplaceSettings::AddListOk == mSettings.replaceList(newList) )
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "replaced list '"<<listName<<"'"<<LL_ENDL;
|
||||
mSelectedListName = listName;
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to replace list '"<<listName<<"'"<<LL_ENDL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Use New Name
|
||||
LL_INFOS("AutoReplace")<<"option 'use new name' selected"<<LL_ENDL;
|
||||
callbackNewListName(notification, response);
|
||||
break;
|
||||
|
||||
default:
|
||||
LL_ERRS("AutoReplace")<<"invalid selected option "<<option<<LL_ENDL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onDeleteList()
|
||||
{
|
||||
std::string listName = mListNames->getSelectedValue().asString();
|
||||
if ( ! listName.empty() )
|
||||
{
|
||||
if ( mSettings.removeReplacementList(listName) )
|
||||
{
|
||||
LL_INFOS("AutoReplace")<<"deleted list '"<<listName<<"'"<<LL_ENDL;
|
||||
mReplacementsList->deleteSelectedItems(); // remove from the scrolling list
|
||||
mSelectedListName.clear();
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to delete list '"<<listName<<"'"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"no list selected for delete"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onExportList()
|
||||
{
|
||||
std::string listName=mListNames->getFirstSelected()->getColumn(0)->getValue().asString();
|
||||
std::string listFileName = listName + ".xml";
|
||||
AIFilePicker* picker = AIFilePicker::create();
|
||||
picker->open(listFileName, FFSAVE_XML, "", "autoreplace");
|
||||
picker->run(boost::bind(&LLFloaterAutoReplaceSettings::onExportList_continued, this, picker, mSettings.exportList(listName)));
|
||||
}
|
||||
void LLFloaterAutoReplaceSettings::onExportList_continued(AIFilePicker* picker, const LLSD* list)
|
||||
{
|
||||
if (picker->hasFilename())
|
||||
{
|
||||
llofstream file;
|
||||
file.open(picker->getFilename());
|
||||
LLSDSerialize::toPrettyXML(*list, file);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onAddEntry()
|
||||
{
|
||||
mPreviousKeyword.clear();
|
||||
mReplacementsList->deselectAllItems(false /* don't call commit */);
|
||||
mKeyword->clear();
|
||||
mReplacement->clear();
|
||||
enableReplacementEntry();
|
||||
mKeyword->setFocus(true);
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onSaveEntry()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"called"<<LL_ENDL;
|
||||
|
||||
if ( ! mPreviousKeyword.empty() )
|
||||
{
|
||||
// delete any existing value for the key that was editted
|
||||
LL_INFOS("AutoReplace")
|
||||
<< "list '" << mSelectedListName << "' "
|
||||
<< "removed '" << mPreviousKeyword
|
||||
<< "'" << LL_ENDL;
|
||||
mSettings.removeEntryFromList( mPreviousKeyword, mSelectedListName );
|
||||
}
|
||||
|
||||
LLWString keyword = mKeyword->getWText();
|
||||
LLWString replacement = mReplacement->getWText();
|
||||
if ( mSettings.addEntryToList(keyword, replacement, mSelectedListName) )
|
||||
{
|
||||
// insert the new keyword->replacement pair
|
||||
LL_INFOS("AutoReplace")
|
||||
<< "list '" << mSelectedListName << "' "
|
||||
<< "added '" << wstring_to_utf8str(keyword)
|
||||
<< "' -> '" << wstring_to_utf8str(replacement)
|
||||
<< "'" << LL_ENDL;
|
||||
|
||||
updateReplacementsList();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("InvalidAutoReplaceEntry");
|
||||
LL_WARNS("AutoReplace")<<"invalid entry "
|
||||
<< "keyword '" << wstring_to_utf8str(keyword)
|
||||
<< "' replacement '" << wstring_to_utf8str(replacement)
|
||||
<< "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onSaveChanges()
|
||||
{
|
||||
// put our local copy of the settings into the active copy
|
||||
LLAutoReplace::getInstance()->setSettings( mSettings );
|
||||
// save our local copy of the global feature enable/disable value
|
||||
gSavedSettings.setBOOL("AutoReplace", mEnabled);
|
||||
close();
|
||||
}
|
||||
|
||||
bool LLFloaterAutoReplaceSettings::selectedListIsFirst()
|
||||
{
|
||||
bool isFirst = false;
|
||||
|
||||
if (!mSelectedListName.empty())
|
||||
{
|
||||
LLSD lists = mSettings.getListNames(); // an Array of Strings
|
||||
LLSD first = lists.get(0);
|
||||
if ( first.isString() && first.asString() == mSelectedListName )
|
||||
{
|
||||
isFirst = true;
|
||||
}
|
||||
}
|
||||
return isFirst;
|
||||
}
|
||||
|
||||
bool LLFloaterAutoReplaceSettings::selectedListIsLast()
|
||||
{
|
||||
bool isLast = false;
|
||||
|
||||
if (!mSelectedListName.empty())
|
||||
{
|
||||
LLSD last;
|
||||
LLSD lists = mSettings.getListNames(); // an Array of Strings
|
||||
for ( LLSD::array_const_iterator list = lists.beginArray(), listEnd = lists.endArray();
|
||||
list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
last = *list;
|
||||
}
|
||||
if ( last.isString() && last.asString() == mSelectedListName )
|
||||
{
|
||||
isLast = true;
|
||||
}
|
||||
}
|
||||
return isLast;
|
||||
}
|
||||
|
||||
/* TBD
|
||||
mOldText = getChild<LLLineEditor>("autoreplace_old_text");
|
||||
mNewText = getChild<LLLineEditor>("autoreplace_new_text");
|
||||
*/
|
||||
111
indra/newview/llfloaterautoreplacesettings.h
Normal file
111
indra/newview/llfloaterautoreplacesettings.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @file llfloaterautoreplacesettings.h
|
||||
* @brief Auto Replace List floater
|
||||
* @copyright Copyright (c) 2011 LordGregGreg Back
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LLFLOATERAUTOREPLACESETTINGS_H
|
||||
#define LLFLOATERAUTOREPLACESETTINGS_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llautoreplace.h"
|
||||
|
||||
class AIFilePicker;
|
||||
class LLLineEditor;
|
||||
class LLScrollListCtrl;
|
||||
|
||||
class LLFloaterAutoReplaceSettings : public LLFloater, public LLFloaterSingleton<LLFloaterAutoReplaceSettings>
|
||||
{
|
||||
public:
|
||||
LLFloaterAutoReplaceSettings(const LLSD& key = LLSD());
|
||||
|
||||
/*virtual*/ BOOL postBuild();
|
||||
|
||||
private:
|
||||
|
||||
/** @{ @name Local Copies of Settings
|
||||
* These are populated in the postBuild method with the values
|
||||
* current when the floater is instantiated, and then either
|
||||
* discarded when Cancel is pressed, or copied back to the active
|
||||
* settings if Ok is pressed.
|
||||
*/
|
||||
bool mEnabled; ///< the global preference for AutoReplace
|
||||
LLAutoReplaceSettings mSettings; ///< settings being modified
|
||||
/** @} */
|
||||
|
||||
/// convenience variable - the name of the currently selected list (if any)
|
||||
std::string mSelectedListName;
|
||||
/// the scrolling list of list names (one column, no headings, order manually controlled)
|
||||
LLScrollListCtrl* mListNames;
|
||||
/// the scroling list of keyword->replacement pairs
|
||||
LLScrollListCtrl* mReplacementsList;
|
||||
|
||||
/// the keyword for the entry editing pane
|
||||
LLLineEditor* mKeyword;
|
||||
/// saved keyword value
|
||||
std::string mPreviousKeyword;
|
||||
/// the replacement for the entry editing pane
|
||||
LLLineEditor* mReplacement;
|
||||
|
||||
/// callback for when the feature enable/disable checkbox changes
|
||||
void onAutoReplaceToggled();
|
||||
/// callback for when an entry in the list of list names is selected
|
||||
void onSelectList();
|
||||
|
||||
void onImportList();
|
||||
void onImportList_continued(AIFilePicker* picker);
|
||||
void onExportList();
|
||||
void onExportList_continued(AIFilePicker* picker, const LLSD* list);
|
||||
void onNewList();
|
||||
void onDeleteList();
|
||||
|
||||
void onListUp();
|
||||
void onListDown();
|
||||
|
||||
void onSelectEntry();
|
||||
void onAddEntry();
|
||||
void onDeleteEntry();
|
||||
void onSaveEntry();
|
||||
|
||||
void onSaveChanges();
|
||||
|
||||
/// updates the contents of the mListNames
|
||||
void updateListNames();
|
||||
/// updates the controls associated with mListNames (depends on whether a name is selected or not)
|
||||
void updateListNamesControls();
|
||||
/// updates the contents of the mReplacementsList
|
||||
void updateReplacementsList();
|
||||
/// enables the components that should only be active when a keyword is selected
|
||||
void enableReplacementEntry();
|
||||
/// disables the components that should only be active when a keyword is selected
|
||||
void disableReplacementEntry();
|
||||
|
||||
/// called from the AddAutoReplaceList notification dialog
|
||||
bool callbackNewListName(const LLSD& notification, const LLSD& response);
|
||||
/// called from the RenameAutoReplaceList notification dialog
|
||||
bool callbackListNameConflict(const LLSD& notification, const LLSD& response);
|
||||
|
||||
bool selectedListIsFirst();
|
||||
bool selectedListIsLast();
|
||||
};
|
||||
|
||||
#endif // LLFLOATERAUTOREPLACESETTINGS_H
|
||||
@@ -291,7 +291,7 @@ LLFloaterAvatarList::~LLFloaterAvatarList()
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterAvatarList::toggle(void*)
|
||||
void LLFloaterAvatarList::toggleInstance(const LLSD&)
|
||||
{
|
||||
// [RLVa:KB]
|
||||
if(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
|
||||
@@ -301,7 +301,7 @@ void LLFloaterAvatarList::toggle(void*)
|
||||
}
|
||||
else
|
||||
// [/RLVa:KB]
|
||||
if(!instanceExists() || !getInstance()->getVisible())
|
||||
if (!instanceVisible())
|
||||
{
|
||||
showInstance();
|
||||
}
|
||||
@@ -603,8 +603,9 @@ void LLFloaterAvatarList::updateAvatarList()
|
||||
{
|
||||
const LLUUID &avid = avatar_ids[i];
|
||||
|
||||
static const LLCachedControl<S32> namesystem("RadarNameSystem");
|
||||
std::string name;
|
||||
if (!LLAvatarNameCache::getPNSName(avid, name))
|
||||
if (!LLAvatarNameCache::getPNSName(avid, name, namesystem))
|
||||
continue; //prevent (Loading...)
|
||||
|
||||
LLAvatarListEntry* entry = getAvatarEntry(avid);
|
||||
@@ -1547,6 +1548,11 @@ LLUUID LLFloaterAvatarList::getSelectedID()
|
||||
return LLUUID::null;
|
||||
}
|
||||
|
||||
uuid_vec_t LLFloaterAvatarList::getSelectedIDs()
|
||||
{
|
||||
return mAvatarList->getSelectedIDs();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterAvatarList::callbackFreeze(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user