diff --git a/indra/newview/fsfloaterposer.cpp b/indra/newview/fsfloaterposer.cpp
index f5104ea2d5..0ccd53c6c0 100644
--- a/indra/newview/fsfloaterposer.cpp
+++ b/indra/newview/fsfloaterposer.cpp
@@ -915,15 +915,14 @@ void FSFloaterPoser::timedReload()
if (loadPoseFromXml(avatar, mLoadPoseTimer->getPosePath(), mLoadPoseTimer->getLoadMethod()))
{
- setLoadingProgress(false);
+ mLoadPoseTimer->completeLoading();
onJointTabSelect();
refreshJointScrollListMembers();
setSavePosesButtonText(!mPoserAnimator.allBaseRotationsAreZero(avatar));
}
- else
- {
- setLoadingProgress(true);
- }
+
+ if (mLoadPoseTimer->loadCompleteOrFailed())
+ setLoadingProgress(false);
}
void FSFloaterPoser::setLoadingProgress(bool started)
@@ -1145,22 +1144,25 @@ bool FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose
setJointBaseRotationToZero = startFromZeroRot;
if (loadPositions && control_map.has("position"))
- {
vec3.setValue(control_map["position"]);
- mPoserAnimator.loadJointPosition(avatar, poserJoint, loadPositionsAndScalesAsDeltas, vec3);
- }
+ else
+ vec3.clear();
+
+ mPoserAnimator.loadJointPosition(avatar, poserJoint, loadPositionsAndScalesAsDeltas, vec3);
if (loadRotations && control_map.has("rotation"))
- {
vec3.setValue(control_map["rotation"]);
- mPoserAnimator.loadJointRotation(avatar, poserJoint, setJointBaseRotationToZero, vec3);
- }
+ else
+ vec3.clear();
+
+ mPoserAnimator.loadJointRotation(avatar, poserJoint, setJointBaseRotationToZero, vec3);
if (loadScales && control_map.has("scale"))
- {
vec3.setValue(control_map["scale"]);
- mPoserAnimator.loadJointScale(avatar, poserJoint, loadPositionsAndScalesAsDeltas, vec3);
- }
+ else
+ vec3.clear();
+
+ mPoserAnimator.loadJointScale(avatar, poserJoint, loadPositionsAndScalesAsDeltas, vec3);
worldLocked = control_map.has("worldLocked") ? control_map["worldLocked"].asBoolean() : false;
mPoserAnimator.setRotationIsWorldLocked(avatar, *poserJoint, worldLocked);
@@ -1823,6 +1825,9 @@ void FSFloaterPoser::setUiSelectedAvatarSaveFileName(const std::string& saveFile
LLVOAvatar* FSFloaterPoser::getAvatarByUuid(const LLUUID& avatarToFind) const
{
+ if (avatarToFind.isNull())
+ return nullptr;
+
for (LLCharacter* character : LLCharacter::sInstances)
{
if (avatarToFind != character->getID())
@@ -2775,15 +2780,14 @@ bool FSLoadPoseTimer::tick()
{
if (!mAttemptLoading)
return false;
-
- if (mLoadAttempts > 5)
- return false;
-
if (mCallback.empty())
return false;
- mCallback();
+ if (mLoadAttempts >= mMaxLoadAttempts)
+ mAttemptLoading = false;
+
mLoadAttempts++;
+ mCallback();
return false;
}
diff --git a/indra/newview/fsfloaterposer.h b/indra/newview/fsfloaterposer.h
index 79830826b5..a88f690a4b 100644
--- a/indra/newview/fsfloaterposer.h
+++ b/indra/newview/fsfloaterposer.h
@@ -542,9 +542,11 @@ public:
FSLoadPoseTimer(callback_t callback);
/*virtual*/ bool tick();
- void tryLoading(std::string filePath, E_LoadPoseMethods loadMethod);
- std::string getPosePath() { return mPoseFullPath; };
- E_LoadPoseMethods getLoadMethod() { return mLoadType; };
+ void tryLoading(std::string filePath, E_LoadPoseMethods loadMethod);
+ bool loadCompleteOrFailed() const { return !mAttemptLoading && mLoadAttempts > 0; }
+ void completeLoading() { mAttemptLoading = false; }
+ std::string getPosePath() { return mPoseFullPath; };
+ E_LoadPoseMethods getLoadMethod() const { return mLoadType; };
private:
callback_t mCallback;
@@ -552,6 +554,7 @@ private:
E_LoadPoseMethods mLoadType = ROT_POS_AND_SCALES;
std::string mPoseFullPath;
int mLoadAttempts = 0;
+ const int mMaxLoadAttempts = 5;
};
#endif
diff --git a/indra/newview/fsposeranimator.h b/indra/newview/fsposeranimator.h
index 387e60da12..880997a750 100644
--- a/indra/newview/fsposeranimator.h
+++ b/indra/newview/fsposeranimator.h
@@ -734,6 +734,17 @@ public:
/// The joints which were recaptured.
void updatePosingState(LLVOAvatar* avatar, std::vector jointsRecaptured);
+ ///
+ /// Add a new posing state, or updates the matching posing state with the supplied data.
+ ///
+ /// The avatar the posing state is intended for.
+ /// The ID of the animation.
+ /// The frame-time of the animation.
+ /// The names of the joints, if any, the animation should specifically be applied to.
+ /// The capture order.
+ /// True if the posing state was added or changed by the update data, otherwise false.
+ bool addOrUpdatePosingState(LLVOAvatar* avatar, LLUUID animId, F32 updateTime, std::string jointNames, int captureOrder);
+
///
/// Traverses the joints and applies reversals to the base rotations if needed.
///
diff --git a/indra/newview/fsposestate.cpp b/indra/newview/fsposestate.cpp
index 8d0f679fa0..ea94565d7d 100644
--- a/indra/newview/fsposestate.cpp
+++ b/indra/newview/fsposestate.cpp
@@ -18,7 +18,6 @@ void FSPoseState::captureMotionStates(LLVOAvatar* avatar)
continue;
fsMotionState newState;
- newState.avatarId = avatar->getID();
newState.motionId = anim_it->first;
newState.lastUpdateTime = motion->getLastUpdateTime();
newState.captureOrder = 0;
@@ -39,11 +38,10 @@ void FSPoseState::updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingM
// this happens on second/subsequent recaptures; the first recapture is no longer needed
for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end();)
{
- bool avatarMatches = (*it).avatarId == avatar->getID();
std::string joints = (*it).jointNamesAnimated;
bool recaptureMatches = !joints.empty() && !jointNamesRecaptured.empty() && jointNamesRecaptured.find(joints) != std::string::npos;
- if (avatarMatches && recaptureMatches)
+ if (recaptureMatches)
it = sMotionStates[avatar->getID()].erase(it);
else
it++;
@@ -61,11 +59,10 @@ void FSPoseState::updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingM
bool foundMatch = false;
for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end(); it++)
{
- bool avatarMatches = (*it).avatarId == avatar->getID();
bool motionIdMatches = (*it).motionId == anim_it->first;
bool updateTimesMatch = (*it).lastUpdateTime == motion->getLastUpdateTime(); // consider when recapturing the same animation at different times for a subset of bones
- foundMatch = avatarMatches && motionIdMatches && updateTimesMatch;
+ foundMatch = motionIdMatches && updateTimesMatch;
if (foundMatch)
break;
}
@@ -74,7 +71,6 @@ void FSPoseState::updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingM
continue;
fsMotionState newState;
- newState.avatarId = avatar->getID();
newState.motionId = anim_it->first;
newState.lastUpdateTime = motion->getLastUpdateTime();
newState.jointNamesAnimated = jointNamesRecaptured;
@@ -85,19 +81,41 @@ void FSPoseState::updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingM
}
}
+bool FSPoseState::addOrUpdatePosingMotionState(LLVOAvatar* avatar, LLUUID animId, F32 updateTime, std::string jointNames, int captureOrder)
+{
+ if (!avatar)
+ return false;
+
+ bool foundMatch = false;
+ for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end(); it++)
+ {
+ bool motionIdMatches = (*it).motionId == animId;
+ bool updateTimesMatch = (*it).lastUpdateTime == updateTime;
+ bool jointNamesMatch = (*it).jointNamesAnimated == jointNames;
+ bool captureOrdersMatch = (*it).captureOrder == captureOrder;
+
+ foundMatch = motionIdMatches && updateTimesMatch && jointNamesMatch && captureOrdersMatch;
+ if (foundMatch)
+ return false;
+ }
+
+ fsMotionState newState;
+ newState.motionId = animId;
+ newState.lastUpdateTime = updateTime;
+ newState.jointNamesAnimated = jointNames;
+ newState.captureOrder = captureOrder;
+ newState.avatarOwnsPose = false;
+
+ sMotionStates[avatar->getID()].push_back(newState);
+ return true;
+}
+
void FSPoseState::purgeMotionStates(LLVOAvatar* avatar)
{
if (!avatar)
return;
- std::vector::iterator it;
- for (it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end();)
- {
- if ((*it).avatarId == avatar->getID())
- it = sMotionStates[avatar->getID()].erase(it);
- else
- it++;
- }
+ sMotionStates[avatar->getID()].clear();
}
void FSPoseState::writeMotionStates(LLVOAvatar* avatar, LLSD* saveRecord)
@@ -108,8 +126,6 @@ void FSPoseState::writeMotionStates(LLVOAvatar* avatar, LLSD* saveRecord)
int animNumber = 0;
for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end(); ++it)
{
- if (it->avatarId != avatar->getID())
- continue;
if (!it->avatarOwnsPose)
continue;
@@ -118,7 +134,6 @@ void FSPoseState::writeMotionStates(LLVOAvatar* avatar, LLSD* saveRecord)
(*saveRecord)[uniqueAnimId]["lastUpdateTime"] = it->lastUpdateTime;
(*saveRecord)[uniqueAnimId]["jointNamesAnimated"] = it->jointNamesAnimated;
(*saveRecord)[uniqueAnimId]["captureOrder"] = it->captureOrder;
- (*saveRecord)[uniqueAnimId]["playOrder"] = animNumber;
}
}
@@ -131,14 +146,13 @@ void FSPoseState::restoreMotionStates(LLVOAvatar* avatar, LLSD pose)
for (auto itr = pose.beginMap(); itr != pose.endMap(); ++itr)
{
- std::string const& name = itr->first;
- LLSD const& control_map = itr->second;
+ std::string const& name = itr->first;
+ LLSD const& control_map = itr->second;
if (!name.starts_with("poseState"))
continue;
fsMotionState newState;
- newState.avatarId = avatar->getID();
newState.avatarOwnsPose = true;
if (control_map.has("animationId"))
@@ -178,9 +192,6 @@ bool FSPoseState::applyMotionStatesToPosingMotion(LLVOAvatar* avatar, FSPosingMo
bool needPriorityReset = false;
for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end(); it++)
{
- if (it->avatarId != avatar->getID())
- continue;
-
needPriorityReset = it->captureOrder > lastCaptureOrder;
if (it->motionApplied)
@@ -216,8 +227,6 @@ void FSPoseState::resetPriorityForCaptureOrder(LLVOAvatar* avatar, FSPosingMotio
{
if (it->jointNamesAnimated.empty())
continue;
- if (it->avatarId != avatar->getID())
- continue;
if (it->motionApplied)
continue;
if (it->captureOrder != captureOrder)
diff --git a/indra/newview/fsposestate.h b/indra/newview/fsposestate.h
index 233258565c..e941e28d70 100644
--- a/indra/newview/fsposestate.h
+++ b/indra/newview/fsposestate.h
@@ -41,9 +41,6 @@ public:
/// Captures the current animations posing the supplied avatar and how long they have been playing.
///
/// The avatar whose animations are to be captured.
- ///
- /// Only animations owned by the supplied avatar are documented.
- ///
void captureMotionStates(LLVOAvatar* avatar);
///
@@ -54,6 +51,17 @@ public:
/// The names of the joints being recaptured.
void updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingMotion, std::string jointNamesRecaptured);
+ ///
+ /// Add a new posing state, or updates the matching posing state with the supplied data.
+ ///
+ /// The avatar the posing state is intended for.
+ /// The ID of the animation.
+ /// The frame-time of the animation.
+ /// The names of the joints, if any, the animation should specifically be applied to.
+ /// The capture order.
+ /// True if the posing state was added or changed by the update data, otherwise false.
+ bool addOrUpdatePosingMotionState(LLVOAvatar* avatar, LLUUID animId, F32 updateTime, std::string jointNames, int captureOrder);
+
///
/// Removes all current animation states for the supplied avatar.
///
@@ -98,11 +106,6 @@ private:
class fsMotionState
{
public:
- ///
- /// The avatar ID this record is associated with.
- ///
- LLUUID avatarId;
-
///
/// The motion ID recorded animating the avatar ID.
///