FIRE-34744: Preen diff save, update recapture

meow-7.2.2
Angeldark Raymaker 2024-11-04 22:05:14 +00:00
parent 73ea090f99
commit f4b515175b
7 changed files with 125 additions and 30 deletions

View File

@ -307,6 +307,12 @@ void FSFloaterPoser::onPoseFileSelect()
LLStringExplicit name = LLStringExplicit(poseName);
mPoseSaveNameEditor->setEnabled(enableButtons);
mPoseSaveNameEditor->setText(name);
bool isDeltaSave = !poseFileStartsFromTeePose(name);
if (isDeltaSave)
mLoadPosesBtn->setLabel("Load Diff");
else
mLoadPosesBtn->setLabel("Load Pose");
}
void FSFloaterPoser::onClickPoseSave()
@ -348,13 +354,13 @@ bool FSFloaterPoser::savePoseToXml(LLVOAvatar* avatar, const std::string& poseFi
std::string fullSavePath =
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY, poseFileName + POSE_INTERNAL_FORMAT_FILE_EXT);
bool fromZeroRot = mPoserAnimator.posingStartedFromZeroRotations(avatar);
bool savingDiff = !mPoserAnimator.posingStartedFromZeroRotations(avatar);
LLSD record;
record["version"]["value"] = (S32)4;
record["startFromTeePose"]["value"] = fromZeroRot;
record["startFromTeePose"]["value"] = !savingDiff;
LLVector3 rotation, position, scale;
LLVector3 rotation, position, scale, zeroVector;
for (const FSPoserAnimator::FSPoserJoint& pj : mPoserAnimator.PoserJoints)
{
@ -362,8 +368,13 @@ bool FSFloaterPoser::savePoseToXml(LLVOAvatar* avatar, const std::string& poseFi
if (!mPoserAnimator.tryGetJointSaveVectors(avatar, pj, &rotation, &position, &scale))
continue;
record[bone_name] = pj.jointName();
record[bone_name]["enabled"] = mPoserAnimator.isPosingAvatarJoint(avatar, pj);
bool jointRotPosScaleAllZero = rotation == zeroVector && position == zeroVector && scale == zeroVector;
bool posingThisJoint = mPoserAnimator.isPosingAvatarJoint(avatar, pj);
if (savingDiff && (!posingThisJoint || jointRotPosScaleAllZero))
continue;
record[bone_name] = bone_name;
record[bone_name]["enabled"] = posingThisJoint;
record[bone_name]["rotation"] = rotation.getValue();
record[bone_name]["position"] = position.getValue();
record[bone_name]["scale"] = scale.getValue();
@ -494,17 +505,7 @@ void FSFloaterPoser::onClickRecaptureSelectedBones()
if (currentlyPosing)
continue;
LLVector3 newRotation = mPoserAnimator.getJointRotation(avatar, *item, getJointTranslation(item->jointName()),
getJointNegation(item->jointName()), CURRENTROTATION);
LLVector3 newPosition = mPoserAnimator.getJointPosition(avatar, *item, true);
LLVector3 newScale = mPoserAnimator.getJointScale(avatar, *item, true);
mPoserAnimator.setPosingAvatarJoint(avatar, *item, true);
mPoserAnimator.setJointRotation(avatar, item, newRotation, NONE, getJointTranslation(item->jointName()),
getJointNegation(item->jointName()));
mPoserAnimator.setJointPosition(avatar, item, newPosition, NONE);
mPoserAnimator.setJointScale(avatar, item, newScale, NONE);
mPoserAnimator.recaptureJoint(avatar, *item, getJointTranslation(item->jointName()), getJointNegation(item->jointName()));
}
refreshRotationSliders();
@ -674,6 +675,51 @@ void FSFloaterPoser::onClickLoadHandPose(bool isRightHand)
}
bool FSFloaterPoser::poseFileStartsFromTeePose(const std::string& poseFileName)
{
std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY);
if (!gDirUtilp->fileExists(pathname))
return false;
std::string fullPath =
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY, poseFileName + POSE_INTERNAL_FORMAT_FILE_EXT);
try
{
LLSD pose;
llifstream infile;
bool startFromZeroRot = false;
infile.open(fullPath);
if (!infile.is_open())
return false;
S32 lineCount = LLSDSerialize::fromXML(pose, infile);
if (lineCount == LLSDParser::PARSE_FAILURE)
{
LL_WARNS("Posing") << "Failed to parse file: " << poseFileName << LL_ENDL;
return startFromZeroRot;
}
for (LLSD::map_const_iterator itr = pose.beginMap(); itr != pose.endMap(); ++itr)
{
std::string const& name = itr->first;
LLSD const& control_map = itr->second;
if (name == "startFromTeePose")
startFromZeroRot = control_map["value"].asBoolean();
}
return startFromZeroRot;
}
catch (const std::exception& e)
{
LL_WARNS("Posing") << "Unable to load or parse the pose: " << poseFileName << " exception: " << e.what() << LL_ENDL;
}
return false;
}
void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& poseFileName, E_LoadPoseMethods loadMethod)
{
std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY);
@ -732,7 +778,7 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose
if (version > 3)
loadPositionsAndScalesAsDeltas = true;
if (startFromZeroRot) // old save formats will always start from T-Pose, for better or worse.
if (startFromZeroRot) // legacy saves will always start from T-Pose, for better or worse.
{
disableRecapture();
mPoserAnimator.setAllAvatarStartingRotationsToZero(avatar);
@ -772,7 +818,7 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose
}
}
}
}
}
catch ( const std::exception & e )
{
LL_WARNS("Posing") << "Everything caught fire trying to load the pose: " << poseFileName << " exception: " << e.what() << LL_ENDL;

View File

@ -202,6 +202,7 @@ class FSFloaterPoser : public LLFloater
void onClickBrowsePoseCache();
void onPoseMenuAction(const LLSD& param);
void loadPoseFromXml(LLVOAvatar* avatar, const std::string& poseFileName, E_LoadPoseMethods loadMethod);
bool poseFileStartsFromTeePose(const std::string& poseFileName);
void setPoseSaveFileTextBoxToUiSelectedAvatarSaveFileName();
void setUiSelectedAvatarSaveFileName(const std::string& saveFileName);
void showOrHideAdvancedSaveOptions();

View File

@ -440,6 +440,40 @@ void FSPoserAnimator::setAllAvatarStartingRotationsToZero(LLVOAvatar* avatar)
posingMotion->setAllRotationsToZero();
}
void FSPoserAnimator::recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation)
{
LLVector3 newRotation = getJointRotation(avatar, joint, translation, negation, CURRENTROTATION);
LLVector3 newPosition = getJointPosition(avatar, joint, true);
LLVector3 newScale = getJointScale(avatar, joint, true);
setPosingAvatarJoint(avatar, joint, true);
setStartingJointRotation(avatar, &joint, newRotation, translation, negation);
// recapture of positions and scale does not reset starting values, since this this could result in unwanted residue deformation after posing stops.
setJointPosition(avatar, &joint, newPosition, NONE);
setJointScale(avatar, &joint, newScale, NONE);
}
void FSPoserAnimator::setStartingJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& rotation,
E_BoneAxisTranslation translation, S32 negation)
{
if (!isAvatarSafeToUse(avatar))
return;
if (!joint)
return;
FSPosingMotion* posingMotion = getPosingMotion(avatar);
if (!posingMotion)
return;
FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName());
if (!jointPose)
return;
LLQuaternion rot_quat = translateRotationToQuaternion(translation, negation, rotation);
jointPose->setJointStartRotations(rot_quat);
}
LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation, E_BoneRotationType rotType) const
{
LLVector3 vec3;

View File

@ -32,7 +32,7 @@
/// <summary>
/// Describes how we will cluster the joints/bones/thingos.
/// Each joint/bone/thingo should have one of these, <see:"FSPoserAnimator.PoserJoints"/>.
/// Each joint/bone/thingo should have one of these, FSPoserAnimator.PoserJoints.
/// </summary>
typedef enum E_BoneTypes
{
@ -446,7 +446,7 @@ public:
/// <param name="avatar">The avatar whose joint is being queried.</param>
/// <param name="joint">The joint to determine the rotation for.</param>
/// <param name="translation">The joint to determine the rotation for.</param>
/// <param name="negation">The style of negation to apply to the set.</param>
/// <param name="negation">The style of negation to dis-apply to the get.</param>
/// <param name="rotType">The type of rotation to get from the supplied joint for the supplied avatar.</param>
/// <returns>The rotation of the requested joint, if determinable, otherwise a default vector.</returns>
LLVector3 getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation, E_BoneRotationType rotType) const;
@ -459,6 +459,7 @@ public:
/// <param name="rotation">The rotation to set the joint to.</param>
/// <param name="style">Any ancilliary action to be taken with the change to be made.</param>
/// <param name="translation">The axial translation form the supplied joint.</param>
/// <param name="negation">The style of negation to apply to the set.</param>
void setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& rotation, E_BoneDeflectionStyles style,
E_BoneAxisTranslation translation, S32 negation);
@ -492,6 +493,15 @@ public:
/// <param name="avatar">The avatar whose pose should flip left-right.</param>
void flipEntirePose(LLVOAvatar* avatar);
/// <summary>
/// Recaptures the rotation, position and scale state of the supplied joint for the supplied avatar.
/// </summary>
/// <param name="avatar">The avatar whose joint is to be recaptured.</param>
/// <param name="joint">The joint to recapture.</param>
/// <param name="translation">The axial translation form the supplied joint.</param>
/// <param name="negation">The style of negation to apply to the recapture.</param>
void recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation);
/// <summary>
/// Sets all of the joint rotations of the supplied avatar to zero.
/// </summary>
@ -533,8 +543,8 @@ public:
/// <param name="rotation">The rotation to load.</param>
/// <remarks>
/// All rotations we load are deltas to the current rotation the supplied joint has.
/// Whether the joint already has a rotation because some animation is playing (sp possibly a non-zero rotation),
/// or whether it is a rotation relative to zero, the result is always the same: just 'add' this rotation to the existing.
/// Whether the joint already has a rotation because some animation is playing,
/// or whether its rotation is zero, the result is always the same: just 'add' the supplied rotation to the existing rotation.
/// </remarks>
void loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, LLVector3 rotation);
@ -549,7 +559,7 @@ public:
/// A position is saved as an absolute if the user created the pose from 'scratch' (at present the 'T-Pose').
/// Otherwise the position is saved as a delta.
/// The primary purpose is aesthetic: the numbers inside of a 'delta save file' have 'zeros everywhere'.
/// A delta-save thus accurately reflects what the user changed, and not what the original creator of the modified pose specified.
/// A delta-save thus accurately reflects what the user changed, and not what the original pose is.
/// 'Legacy' (pre save format version-4) poses we expect to load as absolutes.
/// </remarks>
void loadJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, bool loadPositionAsDelta, LLVector3 position);
@ -612,6 +622,9 @@ public:
/// <returns>True if the avatar is safe to manipulate, otherwise false.</returns>
bool isAvatarSafeToUse(LLVOAvatar* avatar) const;
void setStartingJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& rotation,
E_BoneAxisTranslation translation, S32 negation);
/// <summary>
/// Maps the avatar's ID to the animation registered to them.
/// Thus we start/stop the same animation, and get/set the same rotations etc.

View File

@ -269,19 +269,20 @@ bool FSPosingMotion::allStartingRotationsAreZero() const
void FSPosingMotion::setAllRotationsToZero()
{
LLQuaternion zeroQuat;
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
{
if (poserJoint_iter->isCollisionVolume())
continue;
poserJoint_iter->setRotationsToZero();
poserJoint_iter->setJointStartRotations(zeroQuat);
}
}
constexpr size_t MaximumUndoQueueLength = 20;
/// <summary>
/// The constant time interval, in seconds,
/// The constant time interval, in seconds, specifying whether an 'undo' value should be added.
/// </summary>
constexpr std::chrono::duration<double> UndoUpdateInterval = std::chrono::duration<double>(0.3);
@ -517,7 +518,7 @@ void FSPosingMotion::FSJointPose::revertCollisionVolume()
joint->setScale(mBeginningScale);
}
void FSPosingMotion::FSJointPose::setRotationsToZero() { mBeginningRotation = mTargetRotation = LLQuaternion(); }
void FSPosingMotion::FSJointPose::setJointStartRotations(LLQuaternion quat) { mBeginningRotation = mTargetRotation = quat; }
FSPosingMotion::FSJointPose::FSJointPose(LLJoint* joint, bool isCollisionVolume)
{

View File

@ -223,9 +223,9 @@ public:
void revertCollisionVolume();
/// <summary>
/// Sets all rotations to zero.
/// Sets the beginning and target rotations to the supplied rotation.
/// </summary>
void setRotationsToZero();
void setJointStartRotations(LLQuaternion quat);
/// <summary>
/// Gets the pointer to the jointstate for the joint this represents.

View File

@ -654,7 +654,7 @@ width="403">
background_visible="false"
layout="topleft"
visible="true"
title="Posee"
title="Model"
mouse_opaque="false"
name="avatarSelection_panel"
top="0"
@ -1137,7 +1137,7 @@ width="403">
name="button_RecaptureParts"
left_pad="1"
top_delta="0"
tool_tip="If the selected body part(s) is/are OFF, this Recaptures what those body parts are doing right now"
tool_tip="If the selected body part(s) is/are OFF, this Recaptures what those body parts are doing right now. This button disables if you start from a T-Pose"
width="45" >
<button.commit_callback
function="Poser.RecaptureSelectedBones"/>