Merge branch 'master' into osx_xcode5

This commit is contained in:
Latif Khalifa
2014-04-16 09:56:57 +02:00
419 changed files with 20604 additions and 7014 deletions

View File

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

View File

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

View File

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

View File

@@ -24,7 +24,7 @@
*/
#ifndef LL_LLAUDIODECODEMGR_H
#define LL_LLAUDIODECODEMG_H
#define LL_LLAUDIODECODEMGR_H
#include "stdtypes.h"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
//-----------------------------------------------------------------------------

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 = &paramMotion;
}
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 = &paramMotion;
}
//...or, if we've seen no other motion so far, make sure we blend to this only
else if (!firstMotion)
{
firstMotion = &paramMotion;
secondMotion = &paramMotion;
}
}
}
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
//-----------------------------------------------------------------------------

View File

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

View File

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

View File

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

View File

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

View 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

View 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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -113,6 +113,8 @@ public:
BOOL mHasCubeMap;
BOOL mHasDebugOutput;
BOOL mHasAdaptiveVsync;
// Vendor-specific extensions
BOOL mIsATI;
BOOL mIsNVIDIA;

View File

@@ -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");

View File

@@ -179,6 +179,7 @@ public:
AVATAR_MATRIX,
AVATAR_TRANSLATION,
AVATAR_MAX_WEIGHT,
WATER_SCREENTEX,
WATER_SCREENDEPTH,

View File

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

View File

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

View File

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

View File

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

View File

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

View 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())

View File

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

View File

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

View File

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

View File

@@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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();
};
/*==================================================*/

View File

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

View File

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

View File

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

View File

@@ -302,6 +302,15 @@ private:
F32 mNextFidgetTime;
S32 mCurrentFidget;
//--------------------------------------------------------------------
// Crouch
//--------------------------------------------------------------------
public:
bool isCrouching() const;
void toggleCrouch() { mCrouch = !mCrouch; }
private:
bool mCrouch;
//--------------------------------------------------------------------
// Fly
//--------------------------------------------------------------------

View File

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

View File

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

View File

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

View File

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

View 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()
{
}

View 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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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: ");

View 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");
*/

View 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

View File

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