Poser: Add Manip translate
parent
d4f3a52256
commit
854e5c6916
|
|
@ -150,6 +150,7 @@ set(viewer_SOURCE_FILES
|
|||
fslslpreproc.cpp
|
||||
fslslpreprocviewer.cpp
|
||||
fsmaniprotatejoint.cpp
|
||||
fsmaniptranslatejoint.cpp
|
||||
fsmoneytracker.cpp
|
||||
fsnamelistavatarmenu.cpp
|
||||
fsnearbychatbarlistener.cpp
|
||||
|
|
@ -997,6 +998,7 @@ set(viewer_HEADER_FILES
|
|||
fslslpreprocviewer.h
|
||||
fsmoneytracker.h
|
||||
fsmaniprotatejoint.h
|
||||
fsmaniptranslatejoint.h
|
||||
fsnamelistavatarmenu.h
|
||||
fsnearbychatbarlistener.h
|
||||
fsnearbychatcontrol.h
|
||||
|
|
|
|||
|
|
@ -276,10 +276,8 @@ void FSFloaterPoser::onFocusReceived()
|
|||
|
||||
void FSFloaterPoser::onFocusLost()
|
||||
{
|
||||
if( LLEditMenuHandler::gEditMenuHandler == this )
|
||||
{
|
||||
if (LLEditMenuHandler::gEditMenuHandler == this)
|
||||
LLEditMenuHandler::gEditMenuHandler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterPoser::draw()
|
||||
|
|
@ -361,22 +359,33 @@ void FSFloaterPoser::enableVisualManipulators()
|
|||
}
|
||||
|
||||
if (LLToolMgr::getInstance()->getCurrentToolset() != gCameraToolset)
|
||||
{
|
||||
mLastToolset = LLToolMgr::getInstance()->getCurrentToolset();
|
||||
}
|
||||
|
||||
LLToolMgr::getInstance()->setCurrentToolset(gPoserToolset);
|
||||
LLToolMgr::getInstance()->getCurrentToolset()->selectTool(FSToolCompPose::getInstance());
|
||||
FSToolCompPose::getInstance()->setAvatar(gAgentAvatarp);
|
||||
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
setVisualManipulators(avatar);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::disableVisualManipulators()
|
||||
{
|
||||
if (mLastToolset)
|
||||
{
|
||||
LLToolMgr::getInstance()->setCurrentToolset(mLastToolset);
|
||||
}
|
||||
FSToolCompPose::getInstance()->setAvatar(nullptr);
|
||||
|
||||
setVisualManipulators(nullptr);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::setVisualManipulators(LLVOAvatar* avatar)
|
||||
{
|
||||
FSToolCompPose::getInstance()->setAvatar(avatar);
|
||||
FSToolCompPoseTranslate::getInstance()->setAvatar(avatar);
|
||||
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
updateManipWithFirstSelectedJoint(selectedJoints);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClose(bool app_quitting)
|
||||
|
|
@ -1657,6 +1666,7 @@ void FSFloaterPoser::onToggleRotationFrameButton(const LLUICtrl* toggleButton)
|
|||
}
|
||||
|
||||
FSToolCompPose::getInstance()->setReferenceFrame(getReferenceFrame());
|
||||
FSToolCompPoseTranslate::getInstance()->setReferenceFrame(getReferenceFrame());
|
||||
refreshRotationSlidersAndSpinners();
|
||||
}
|
||||
|
||||
|
|
@ -1949,9 +1959,15 @@ void FSFloaterPoser::updateManipWithFirstSelectedJoint(const std::vector<FSPoser
|
|||
bool iCanPoseThem = havePermissionToAnimateOtherAvatar(avatarp);
|
||||
|
||||
if ((joints.size() >= 1) && (haveImplicitPermission || iCanPoseThem))
|
||||
{
|
||||
FSToolCompPose::getInstance()->setJoint(avatarp->getJoint(joints[0]->jointName()));
|
||||
FSToolCompPoseTranslate::getInstance()->setJoint(avatarp->getJoint(joints[0]->jointName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
FSToolCompPose::getInstance()->setJoint(nullptr);
|
||||
FSToolCompPoseTranslate::getInstance()->setJoint(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
E_RotationStyle FSFloaterPoser::getUiSelectedBoneRotationStyle(const std::string& jointName) const
|
||||
|
|
@ -2476,9 +2492,15 @@ void FSFloaterPoser::onAvatarSelect()
|
|||
bool haveExplicitPermission = havePermissionToAnimateOtherAvatar(avatar); // as permissions allow
|
||||
|
||||
if (haveImplicitPermission || haveExplicitPermission)
|
||||
{
|
||||
FSToolCompPose::getInstance()->setAvatar(avatar);
|
||||
FSToolCompPoseTranslate::getInstance()->setAvatar(avatar);
|
||||
}
|
||||
else
|
||||
{
|
||||
FSToolCompPose::getInstance()->setAvatar(nullptr);
|
||||
FSToolCompPoseTranslate::getInstance()->setAvatar(nullptr);
|
||||
}
|
||||
|
||||
bool arePosingSelected = mPoserAnimator.isPosingAvatar(avatar);
|
||||
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ public:
|
|||
// visual manipulators control
|
||||
void enableVisualManipulators();
|
||||
void disableVisualManipulators();
|
||||
void setVisualManipulators(LLVOAvatar* avatar);
|
||||
|
||||
// Visual cue for which bone is under the mouse-cursor
|
||||
void drawOnHoverJointHint();
|
||||
|
|
|
|||
|
|
@ -55,47 +55,49 @@ void FSJointPose::setPublicPosition(const LLVector3& pos)
|
|||
{
|
||||
addStateToUndo(mCurrentState);
|
||||
mCurrentState.mPosition.set(pos);
|
||||
mCurrentState.mLastChangeWasRotational = false;
|
||||
mCurrentState.mPoserChangeType = POSER_CHANGE_DEFAULT;
|
||||
}
|
||||
|
||||
void FSJointPose::setPublicRotation(bool zeroBase, const LLQuaternion& rot)
|
||||
void FSJointPose::setPublicRotation(bool zeroBase, E_PoserChangeType changeType, const LLQuaternion& rot)
|
||||
{
|
||||
addStateToUndo(mCurrentState);
|
||||
|
||||
if (zeroBase)
|
||||
zeroBaseRotation(true);
|
||||
else
|
||||
mCurrentState.mUserSpecifiedBaseZero = false;
|
||||
mCurrentState.mUserSpecifiedBaseZero = POSER_CHANGE_DEFAULT;
|
||||
|
||||
mCurrentState.mRotation.set(rot);
|
||||
mCurrentState.mLastChangeWasRotational = true;
|
||||
mCurrentState.mPoserChangeType = changeType;
|
||||
}
|
||||
|
||||
void FSJointPose::setPublicScale(const LLVector3& scale)
|
||||
{
|
||||
addStateToUndo(mCurrentState);
|
||||
mCurrentState.mScale.set(scale);
|
||||
mCurrentState.mLastChangeWasRotational = false;
|
||||
mCurrentState.mPoserChangeType = POSER_CHANGE_DEFAULT;
|
||||
}
|
||||
|
||||
bool FSJointPose::undoLastChange()
|
||||
E_PoserChangeType FSJointPose::undoLastChange()
|
||||
{
|
||||
bool changeType = mCurrentState.mLastChangeWasRotational;
|
||||
E_PoserChangeType changeType = mCurrentState.mPoserChangeType;
|
||||
mCurrentState = undoLastStateChange(mCurrentState);
|
||||
|
||||
return changeType;
|
||||
}
|
||||
|
||||
void FSJointPose::redoLastChange()
|
||||
E_PoserChangeType FSJointPose::redoLastChange()
|
||||
{
|
||||
mCurrentState = redoLastStateChange(mCurrentState);
|
||||
|
||||
return mCurrentState.mPoserChangeType;
|
||||
}
|
||||
|
||||
void FSJointPose::resetJoint()
|
||||
{
|
||||
addStateToUndo(mCurrentState);
|
||||
mCurrentState.resetJoint();
|
||||
mCurrentState.mLastChangeWasRotational = true;
|
||||
mCurrentState.mPoserChangeType = POSER_CHANGE_DEFAULT;
|
||||
}
|
||||
|
||||
void FSJointPose::addStateToUndo(const FSJointState& stateToAddToUndo)
|
||||
|
|
@ -169,13 +171,13 @@ void FSJointPose::recaptureJoint()
|
|||
}
|
||||
|
||||
mCurrentState = FSJointState(joint);
|
||||
mCurrentState.mLastChangeWasRotational = true;
|
||||
mCurrentState.mPoserChangeType = POSER_CHANGE_DEFAULT;
|
||||
}
|
||||
|
||||
LLQuaternion FSJointPose::updateJointAsDelta(bool zeroBase, const LLQuaternion& rotation, const LLVector3& position, const LLVector3& scale)
|
||||
{
|
||||
addStateToUndo(mCurrentState);
|
||||
mCurrentState.mLastChangeWasRotational = true;
|
||||
mCurrentState.mPoserChangeType = POSER_CHANGE_DEFAULT;
|
||||
|
||||
return mCurrentState.updateFromJointProperties(zeroBase, rotation, position, scale);
|
||||
}
|
||||
|
|
@ -231,7 +233,7 @@ void FSJointPose::cloneRotationFrom(FSJointPose* fromJoint)
|
|||
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
mCurrentState.cloneRotationFrom(fromJoint->mCurrentState);
|
||||
mCurrentState.mLastChangeWasRotational = true;
|
||||
mCurrentState.mPoserChangeType = POSER_CHANGE_DEFAULT;
|
||||
}
|
||||
|
||||
void FSJointPose::mirrorRotationFrom(FSJointPose* fromJoint)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,17 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
#include "llmotion.h"
|
||||
|
||||
/// <summary>
|
||||
/// Describes the kind of pose-change.
|
||||
/// Useful for undoing complex changes.
|
||||
/// </summary>
|
||||
typedef enum E_PoserChangeType
|
||||
{
|
||||
POSER_CHANGE_DEFAULT = 0, // a simple change to pos/rot/scale
|
||||
POSER_CHANGE_CHILDMOVE = 1, // position change of a child by rotating its 2 antecedent joints
|
||||
POSER_CHANGE_ROTATION = 2, // a rotation change
|
||||
} E_PoserChangeType;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class FSJointPose
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -70,13 +81,14 @@ class FSJointPose
|
|||
/// <summary>
|
||||
/// Undoes the last position set, if any.
|
||||
/// </summary>
|
||||
/// <returns>true if the change we un-did was rotational.</returns>
|
||||
bool undoLastChange();
|
||||
/// <returns>A value indicating what kind of change was undone (important for undo).</returns>
|
||||
E_PoserChangeType undoLastChange();
|
||||
|
||||
/// <summary>
|
||||
/// Undoes the last position set, if any.
|
||||
/// </summary>
|
||||
void redoLastChange();
|
||||
/// <returns>A value indicating what kind of change was redone.</returns>
|
||||
E_PoserChangeType redoLastChange();
|
||||
|
||||
/// <summary>
|
||||
/// Resets the joint to its conditions when posing started.
|
||||
|
|
@ -100,7 +112,7 @@ class FSJointPose
|
|||
/// If zeroBase is true, we treat rotations as if in BVH mode: user work.
|
||||
/// If zeroBase is false, we treat as NOT BVH: some existing pose and user work.
|
||||
/// </remarks>
|
||||
void setPublicRotation(bool zeroBase, const LLQuaternion& rot);
|
||||
void setPublicRotation(bool zeroBase, E_PoserChangeType changeType, const LLQuaternion& rot);
|
||||
|
||||
/// <summary>
|
||||
/// Reflects the base and delta rotation of the represented joint left-right.
|
||||
|
|
@ -319,7 +331,7 @@ class FSJointPose
|
|||
mUserSpecifiedBaseZero = false;
|
||||
mRotationIsWorldLocked = false;
|
||||
mJointRotationIsMirrored = false;
|
||||
mLastChangeWasRotational = true;
|
||||
mPoserChangeType = POSER_CHANGE_DEFAULT;
|
||||
mBaseRotation.set(mStartingRotation);
|
||||
mRotation.set(LLQuaternion::DEFAULT);
|
||||
mPosition.setZero();
|
||||
|
|
@ -417,15 +429,15 @@ class FSJointPose
|
|||
mRotationIsWorldLocked = state->mRotationIsWorldLocked;
|
||||
mBasePriority = state->mBasePriority;
|
||||
mJointRotationIsMirrored = state->mJointRotationIsMirrored;
|
||||
mLastChangeWasRotational = state->mLastChangeWasRotational;
|
||||
mPoserChangeType = state->mPoserChangeType;
|
||||
}
|
||||
|
||||
public:
|
||||
LLQuaternion mRotation;
|
||||
LLVector3 mPosition;
|
||||
LLVector3 mScale;
|
||||
bool mRotationIsWorldLocked = false;
|
||||
bool mLastChangeWasRotational = false;
|
||||
LLQuaternion mRotation;
|
||||
LLVector3 mPosition;
|
||||
LLVector3 mScale;
|
||||
bool mRotationIsWorldLocked = false;
|
||||
E_PoserChangeType mPoserChangeType = POSER_CHANGE_DEFAULT;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the joint has been mirrored.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,141 @@
|
|||
/**
|
||||
* @file fsmaniptranslatejoint.h
|
||||
* @brief custom manipulator for moving joints
|
||||
*
|
||||
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
|
||||
* Phoenix Firestorm Viewer Source Code
|
||||
* Copyright (c) 2025 Angeldark Raymaker @ Second Life
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
|
||||
* http://www.firestormviewer.org
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef FS_MANIP_TRANSLATE_JOINT_H
|
||||
#define FS_MANIP_TRANSLATE_JOINT_H
|
||||
|
||||
#include "llselectmgr.h"
|
||||
#include "fsmaniprotatejoint.h"
|
||||
#include "llmaniptranslate.h"
|
||||
|
||||
class LLJoint;
|
||||
class LLVOAvatar; // for LLVOAvatarSelf, etc.
|
||||
|
||||
class FSManipTranslateJoint : public LLManipTranslate
|
||||
{
|
||||
public:
|
||||
class ManipulatorHandle
|
||||
{
|
||||
public:
|
||||
LLVector3 mStartPosition;
|
||||
LLVector3 mEndPosition;
|
||||
EManipPart mManipID;
|
||||
F32 mHotSpotRadius;
|
||||
|
||||
ManipulatorHandle(LLVector3 start_pos, LLVector3 end_pos, EManipPart id, F32 radius):mStartPosition(start_pos), mEndPosition(end_pos), mManipID(id), mHotSpotRadius(radius){}
|
||||
};
|
||||
|
||||
|
||||
FSManipTranslateJoint(LLToolComposite* composite);
|
||||
virtual ~FSManipTranslateJoint() {};
|
||||
|
||||
/// <summary>
|
||||
/// Sets the joint we are going to manipulate.
|
||||
/// </summary>
|
||||
/// <param name="joint">The joint to interact with.</param>
|
||||
void setJoint(LLJoint* joint);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the avatar the manip should interact with.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar to interact with.</param>
|
||||
void setAvatar(LLVOAvatar* avatar);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the avatar the manip should interact with.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar to interact with.</param>
|
||||
void setReferenceFrame(const E_PoserReferenceFrame frame) { mReferenceFrame = frame; };
|
||||
|
||||
static U32 getGridTexName() ;
|
||||
static void destroyGL();
|
||||
static void restoreGL();
|
||||
virtual bool handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
virtual bool handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
virtual bool handleHover(S32 x, S32 y, MASK mask);
|
||||
virtual void render();
|
||||
virtual void handleSelect();
|
||||
|
||||
virtual void highlightManipulators(S32 x, S32 y);
|
||||
virtual bool handleMouseDownOnPart(S32 x, S32 y, MASK mask);
|
||||
virtual bool canAffectSelection();
|
||||
|
||||
protected:
|
||||
enum EHandleType {
|
||||
HANDLE_CONE,
|
||||
HANDLE_BOX,
|
||||
HANDLE_SPHERE
|
||||
};
|
||||
|
||||
void renderArrow(S32 which_arrow, S32 selected_arrow, F32 box_size, F32 arrow_size, F32 handle_size, bool reverse_direction);
|
||||
void renderTranslationHandles();
|
||||
void renderText();
|
||||
|
||||
private:
|
||||
bool isAvatarJointSafeToUse();
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the currently selected joint is one to move with manip.
|
||||
/// </summary>
|
||||
/// <returns>True if we can move the joint with manip, otherwise false.</returns>
|
||||
bool isMoveableJoint();
|
||||
void getManipJointNormal(LLJoint* joint, EManipPart manip, LLVector3& normal) { getManipNormal(nullptr, manip, normal);};
|
||||
bool getManipJointAxis(LLJoint* joint, EManipPart manip, LLVector3& axis) { return getManipAxis(nullptr, manip, axis); };
|
||||
|
||||
LLVector3 getChangeInPosition(LLVector3 newPosition) const;
|
||||
|
||||
S32 mLastHoverMouseX;
|
||||
S32 mLastHoverMouseY;
|
||||
bool mMouseOutsideSlop; // true after mouse goes outside slop region
|
||||
bool mCopyMadeThisDrag;
|
||||
S32 mMouseDownX;
|
||||
S32 mMouseDownY;
|
||||
F32 mAxisArrowLength; // pixels
|
||||
F32 mConeSize; // meters, world space
|
||||
F32 mArrowLengthMeters; // meters
|
||||
F32 mPlaneManipOffsetMeters;
|
||||
LLVector3 mManipNormal;
|
||||
LLVector3 mDragCursorLastGlobal;
|
||||
LLVector3d mDragCursorStartGlobal;
|
||||
LLVector3d mDragSelectionStartGlobal;
|
||||
LLTimer mUpdateTimer;
|
||||
LLVector4 mManipulatorVertices[18];
|
||||
F32 mSnapOffsetMeters;
|
||||
LLVector3 mSnapOffsetAxis;
|
||||
LLQuaternion mGridRotation;
|
||||
LLVector3 mGridOrigin;
|
||||
LLVector3 mGridScale;
|
||||
LLVector3 mArrowScales;
|
||||
LLVector3 mPlaneScales;
|
||||
LLVector4 mPlaneManipPositions;
|
||||
|
||||
LLJoint* mJoint = nullptr;
|
||||
LLVOAvatar* mAvatar = nullptr;
|
||||
E_PoserReferenceFrame mReferenceFrame = POSER_FRAME_BONE;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -114,9 +114,26 @@ void FSPoserAnimator::undoLastJointChange(LLVOAvatar* avatar, const FSPoserJoint
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
if (jointPose->undoLastChange())
|
||||
E_PoserChangeType changeType = jointPose->undoLastChange();
|
||||
if (changeType == POSER_CHANGE_ROTATION)
|
||||
undoOrRedoWorldLockedDescendants(joint, posingMotion, false);
|
||||
|
||||
if (changeType == POSER_CHANGE_CHILDMOVE)
|
||||
{
|
||||
undoOrRedoRotatedParents(joint, posingMotion, false);
|
||||
|
||||
FSJointPose* parentJointPose = findParentJointPose(posingMotion, joint.jointName());
|
||||
if (parentJointPose)
|
||||
{
|
||||
FSJointPose* grandParentJointPose = findParentJointPose(posingMotion, parentJointPose->jointName());
|
||||
if (grandParentJointPose)
|
||||
{
|
||||
auto grandParentPoserJoint = getPoserJointByName(grandParentJointPose->jointName());
|
||||
undoOrRedoWorldLockedDescendants(*grandParentPoserJoint, posingMotion, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (style == NONE || style == DELTAMODE)
|
||||
return;
|
||||
|
||||
|
|
@ -124,7 +141,8 @@ void FSPoserAnimator::undoLastJointChange(LLVOAvatar* avatar, const FSPoserJoint
|
|||
if (!oppositeJointPose)
|
||||
return;
|
||||
|
||||
if (!oppositeJointPose->undoLastChange())
|
||||
changeType = oppositeJointPose->undoLastChange();
|
||||
if (changeType != POSER_CHANGE_ROTATION)
|
||||
return;
|
||||
|
||||
auto oppositePoserJoint = getPoserJointByName(joint.mirrorJointName());
|
||||
|
|
@ -198,8 +216,10 @@ void FSPoserAnimator::redoLastJointChange(LLVOAvatar* avatar, const FSPoserJoint
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
jointPose->redoLastChange();
|
||||
E_PoserChangeType changeType = jointPose->redoLastChange();
|
||||
undoOrRedoWorldLockedDescendants(joint, posingMotion, true);
|
||||
if (changeType == POSER_CHANGE_CHILDMOVE)
|
||||
undoOrRedoRotatedParents(joint, posingMotion, true);
|
||||
|
||||
if (style == NONE || style == DELTAMODE)
|
||||
return;
|
||||
|
|
@ -465,6 +485,15 @@ void FSPoserAnimator::recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joi
|
|||
void FSPoserAnimator::updateJointFromManip(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero,
|
||||
E_BoneDeflectionStyles style, E_PoserReferenceFrame frame, const LLQuaternion& rotation,
|
||||
const LLVector3& position, const LLVector3& scale)
|
||||
{
|
||||
if (!position.isExactlyZero())
|
||||
updateJointPositionFromManip(avatar, joint, resetBaseRotationToZero, style, position);
|
||||
else
|
||||
updateJointRotationFromManip(avatar, joint, resetBaseRotationToZero, style, frame, rotation);
|
||||
}
|
||||
|
||||
void FSPoserAnimator::updateJointRotationFromManip(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero,
|
||||
E_BoneDeflectionStyles style, E_PoserReferenceFrame frame, const LLQuaternion& rotation)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return;
|
||||
|
|
@ -478,7 +507,7 @@ void FSPoserAnimator::updateJointFromManip(LLVOAvatar* avatar, const FSPoserJoin
|
|||
return;
|
||||
|
||||
LLQuaternion framedRotation = changeToRotationFrame(avatar, rotation, frame, jointPose);
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, framedRotation * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_ROTATION, framedRotation * jointPose->getPublicRotation());
|
||||
|
||||
deRotateWorldLockedDescendants(joint, posingMotion, framedRotation);
|
||||
|
||||
|
|
@ -495,14 +524,16 @@ void FSPoserAnimator::updateJointFromManip(LLVOAvatar* avatar, const FSPoserJoin
|
|||
{
|
||||
case SYMPATHETIC:
|
||||
case SYMPATHETIC_DELTA:
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, framedRotation * oppositeJointPose->getPublicRotation());
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_ROTATION,
|
||||
framedRotation * oppositeJointPose->getPublicRotation());
|
||||
if (oppositePoserJoint)
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, framedRotation);
|
||||
break;
|
||||
|
||||
case MIRROR:
|
||||
case MIRROR_DELTA:
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, mirroredRotation * oppositeJointPose->getPublicRotation());
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_ROTATION,
|
||||
mirroredRotation * oppositeJointPose->getPublicRotation());
|
||||
if (oppositePoserJoint)
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, mirroredRotation);
|
||||
break;
|
||||
|
|
@ -512,6 +543,207 @@ void FSPoserAnimator::updateJointFromManip(LLVOAvatar* avatar, const FSPoserJoin
|
|||
}
|
||||
}
|
||||
|
||||
void FSPoserAnimator::updateJointPositionFromManip(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero,
|
||||
E_BoneDeflectionStyles style, const LLVector3& position)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return;
|
||||
|
||||
LLJoint* movedJoint = avatar->getJoint(joint->jointName());
|
||||
if (!movedJoint)
|
||||
return;
|
||||
|
||||
LLJoint* parentJoint = movedJoint->getParent();
|
||||
if (!parentJoint)
|
||||
return;
|
||||
|
||||
if (jointIsPelvis(movedJoint))
|
||||
{
|
||||
auto movedPoserJoint = getPoserJointByName(joint->jointName());
|
||||
LLVector3 currentPosition = getJointPosition(avatar, *movedPoserJoint);
|
||||
LLQuaternion rootWorldRot = parentJoint->getWorldRotation();
|
||||
currentPosition += position * ~rootWorldRot;
|
||||
|
||||
setJointPosition(avatar, movedPoserJoint, currentPosition, POSER_FRAME_WORLD, NONE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (jointIsPelvis(parentJoint))
|
||||
return;
|
||||
|
||||
LLJoint* grandParentJoint = parentJoint->getParent();
|
||||
if (!grandParentJoint || jointIsPelvis(grandParentJoint))
|
||||
return;
|
||||
|
||||
LLVector3 oldMovedJointPosition = movedJoint->getWorldPosition();
|
||||
LLVector3 parentPosition = parentJoint->getWorldPosition();
|
||||
LLVector3 grandParentPosition = grandParentJoint->getWorldPosition();
|
||||
LLVector3 newMovedJointPosition = oldMovedJointPosition + position;
|
||||
LLQuaternion grandParentWorldRot = grandParentJoint->getWorldRotation();
|
||||
LLQuaternion parentWorldRot = parentJoint->getWorldRotation();
|
||||
|
||||
FSJointPose* grandParentJointPose = posingMotion->getJointPoseByJointName(grandParentJoint->getName());
|
||||
FSJointPose* parentJointPose = posingMotion->getJointPoseByJointName(parentJoint->getName());
|
||||
FSJointPose* movedJointPose = posingMotion->getJointPoseByJointName(movedJoint->getName());
|
||||
if (!grandParentJointPose || !parentJointPose)
|
||||
return;
|
||||
|
||||
LLQuaternion grandParentFrameRotChange, grandParentLengthRotChange, parentLengthRotChange;
|
||||
if (parentJointIsHinge(parentJoint))
|
||||
{
|
||||
if (!canMoveToNewPosition(grandParentPosition, parentPosition, oldMovedJointPosition, newMovedJointPosition))
|
||||
return;
|
||||
|
||||
grandParentFrameRotChange = getAbcFrameRotation(grandParentPosition, parentPosition, oldMovedJointPosition, position);
|
||||
|
||||
if (!getPlanarRotationAtAandB(grandParentPosition, parentPosition, oldMovedJointPosition, position, grandParentLengthRotChange,
|
||||
parentLengthRotChange))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
grandParentFrameRotChange.loadIdentity(); // unused here
|
||||
if (!getFreeRotationAtAandB(grandParentPosition, parentPosition, oldMovedJointPosition, position, grandParentLengthRotChange,
|
||||
parentLengthRotChange))
|
||||
return;
|
||||
}
|
||||
|
||||
// convert rotations to local frame
|
||||
grandParentFrameRotChange = grandParentWorldRot * grandParentFrameRotChange * ~grandParentWorldRot;
|
||||
grandParentLengthRotChange = grandParentWorldRot * grandParentLengthRotChange * ~grandParentWorldRot;
|
||||
parentLengthRotChange = parentWorldRot * parentLengthRotChange * ~parentWorldRot;
|
||||
|
||||
movedJointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_CHILDMOVE, movedJointPose->getPublicRotation()); // set up undo
|
||||
parentJointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_ROTATION,
|
||||
parentLengthRotChange * parentJointPose->getPublicRotation());
|
||||
grandParentJointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_ROTATION,
|
||||
grandParentLengthRotChange * grandParentJointPose->getPublicRotation());
|
||||
grandParentJointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_ROTATION,
|
||||
grandParentFrameRotChange * grandParentJointPose->getPublicRotation());
|
||||
|
||||
auto grandParentPoserJoint = getPoserJointByName(grandParentJoint->getName());
|
||||
deRotateWorldLockedDescendants(grandParentPoserJoint, posingMotion, grandParentLengthRotChange);
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::getFreeRotationAtAandB(const LLVector3 posA, const LLVector3 posB, const LLVector3 posC, const LLVector3 changeAtC,
|
||||
LLQuaternion& changeAtA, LLQuaternion& changeAtB)
|
||||
{
|
||||
LLVector3 vectorAC = posC - posA;
|
||||
LLVector3 vectorAB = posB - posA;
|
||||
F32 lengthAC = vectorAC.length();
|
||||
F32 lengthAB = vectorAB.length();
|
||||
F32 lengthBC = (posC - posB).length();
|
||||
F32 lengthMove = changeAtC.length();
|
||||
|
||||
LLVector3 rotationAxis = vectorAC % changeAtC;
|
||||
rotationAxis.normalize();
|
||||
|
||||
F32 angle = asin(lengthMove / lengthAC);
|
||||
if (isnan(angle))
|
||||
return false;
|
||||
|
||||
changeAtA = LLQuaternion(angle, rotationAxis);
|
||||
changeAtB = LLQuaternion(-angle, rotationAxis);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::getPlanarRotationAtAandB(const LLVector3 posA, const LLVector3 posB, const LLVector3 posC, const LLVector3 changeAtC,
|
||||
LLQuaternion& changeAtA, LLQuaternion& changeAtB)
|
||||
{
|
||||
LLVector3 vectorAC = posC - posA;
|
||||
LLVector3 vectorAB = posB - posA;
|
||||
F32 lengthAC = vectorAC.length();
|
||||
F32 lengthAB = vectorAB.length();
|
||||
F32 lengthBC = (posC - posB).length();
|
||||
|
||||
F32 lengthACbeforeRot = vectorAC.length();
|
||||
F32 lengthACafterRot = (posC + changeAtC - posA).length();
|
||||
LLVector3 rotationAxis = vectorAB % vectorAC;
|
||||
|
||||
rotationAxis.normalize();
|
||||
|
||||
// Distance from posA, along AC, to where B is perpendicular to AC (right angle triangle), before and after moving C; intersecting spheres
|
||||
F32 dist1 = (lengthAB * lengthAB - lengthBC * lengthBC + lengthACbeforeRot * lengthACbeforeRot) / (2.f * lengthACbeforeRot);
|
||||
F32 dist2 = (lengthAB * lengthAB - lengthBC * lengthBC + lengthACafterRot * lengthACafterRot) / (2.f * lengthACafterRot);
|
||||
|
||||
if (dist1 == dist2)
|
||||
return false;
|
||||
|
||||
F32 angle1 = acos(dist1 / lengthAB);
|
||||
F32 angle2 = acos(dist2 / lengthAB);
|
||||
changeAtA = LLQuaternion((angle1 - angle2), rotationAxis);
|
||||
|
||||
angle1 = acos((lengthACbeforeRot - dist1) / lengthBC);
|
||||
angle2 = acos((lengthACafterRot - dist2) / lengthBC);
|
||||
changeAtB = LLQuaternion((angle2 - angle1), rotationAxis);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LLQuaternion FSPoserAnimator::getAbcFrameRotation(const LLVector3 posA, const LLVector3 posB, const LLVector3 posC, const LLVector3 changeAtC)
|
||||
{
|
||||
LLVector3 vectorAC = posC - posA;
|
||||
LLVector3 vectorAnewC = vectorAC + changeAtC;
|
||||
|
||||
F32 angle = acos((vectorAC * vectorAnewC) / (vectorAC.length() * vectorAnewC.length()));
|
||||
LLVector3 rotationAxis = vectorAC % changeAtC;
|
||||
rotationAxis.normalize();
|
||||
|
||||
if (isnan(angle))
|
||||
angle = 0.f;
|
||||
|
||||
return LLQuaternion(angle, rotationAxis);
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::parentJointIsHinge(LLJoint* parentJoint)
|
||||
{
|
||||
if (!parentJoint)
|
||||
return false;
|
||||
|
||||
std::string jointName = parentJoint->getName();
|
||||
if (jointName.find("Elbow") != std::string::npos)
|
||||
return true;
|
||||
if (jointName.find("Knee") != std::string::npos)
|
||||
return true;
|
||||
if (jointName.find("Hand") != std::string::npos && jointName.find("2") != std::string::npos) // eg: mHandIndex2Right, the second 'knuckle'
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::jointIsPelvis(const LLJoint* joint)
|
||||
{
|
||||
if (!joint)
|
||||
return false;
|
||||
|
||||
std::string jointName = joint->getName();
|
||||
return jointName == "mPelvis" || jointName == "mRoot";
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::canMoveToNewPosition(const LLVector3 posA, const LLVector3 posB, const LLVector3 posC, const LLVector3 posNewC)
|
||||
{
|
||||
F32 lengthAC = (posNewC - posA).length();
|
||||
if (lengthAC < 0.04f)
|
||||
return false; // don't allow C and A to converge
|
||||
|
||||
F32 lengthAB = (posB - posA).length();
|
||||
F32 lengthBC = (posC - posB).length();
|
||||
|
||||
if (lengthAC > lengthAB + lengthBC - 0.002f)
|
||||
return false; // if the limbs become fully extended then moving back is non-trivial because the 3 joints are not a triangle
|
||||
|
||||
if (lengthAC < fabs(lengthAB - lengthBC))
|
||||
return false; // absurdity
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LLQuaternion FSPoserAnimator::getManipGimbalRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, E_PoserReferenceFrame frame)
|
||||
{
|
||||
LLQuaternion globalRot(-1.f, 0.f, 0.f, 0.f);
|
||||
|
|
@ -548,16 +780,19 @@ LLQuaternion FSPoserAnimator::getManipGimbalRotation(LLVOAvatar* avatar, const F
|
|||
if (frame == POSER_FRAME_BONE)
|
||||
return llJoint->getWorldRotation();
|
||||
|
||||
return getQuaternionFromWorldVector(llJoint->getWorldPosition() - gAgentCamera.getCameraPositionAgent());
|
||||
}
|
||||
|
||||
LLQuaternion FSPoserAnimator::getQuaternionFromWorldVector(const LLVector3 worldVector)
|
||||
{
|
||||
LLVector3 skyward(0.f, 0.f, 1.f);
|
||||
LLVector3 left(1.f, 0.f, 0.f);
|
||||
LLVector3 up, jointToCameraPosition, jointPosition;
|
||||
jointPosition = llJoint->getWorldPosition();
|
||||
jointToCameraPosition = jointPosition - gAgentCamera.getCameraPositionAgent();
|
||||
jointToCameraPosition.normalize();
|
||||
left.setVec(skyward % jointToCameraPosition);
|
||||
up.setVec(jointToCameraPosition % left);
|
||||
LLVector3 up, normVector(worldVector);
|
||||
normVector.normalize();
|
||||
left.setVec(skyward % normVector);
|
||||
up.setVec(normVector % left);
|
||||
|
||||
return LLQuaternion(jointToCameraPosition, left, up);
|
||||
return LLQuaternion(normVector, left, up);
|
||||
}
|
||||
|
||||
LLVector3 FSPoserAnimator::getJointExportRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, bool lockWholeAvatar) const
|
||||
|
|
@ -633,28 +868,28 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
case SYMPATHETIC:
|
||||
case MIRROR:
|
||||
if (rotationStyle == DELTAIC_ROT || translationRequiresDelta)
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_DEFAULT, deltaRot * jointPose->getPublicRotation());
|
||||
else
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, absRot);
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_DEFAULT, absRot);
|
||||
|
||||
break;
|
||||
|
||||
case SYMPATHETIC_DELTA:
|
||||
case MIRROR_DELTA:
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_DEFAULT, deltaRot * jointPose->getPublicRotation());
|
||||
break;
|
||||
|
||||
case DELTAMODE:
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_DEFAULT, deltaRot * jointPose->getPublicRotation());
|
||||
deRotateWorldLockedDescendants(joint, posingMotion, deltaRot);
|
||||
return;
|
||||
|
||||
case NONE:
|
||||
default:
|
||||
if (rotationStyle == DELTAIC_ROT || translationRequiresDelta)
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_DEFAULT, deltaRot * jointPose->getPublicRotation());
|
||||
else
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, absRot);
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_DEFAULT, absRot);
|
||||
|
||||
deRotateWorldLockedDescendants(joint, posingMotion, deltaRot);
|
||||
return;
|
||||
|
|
@ -677,7 +912,8 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
break;
|
||||
|
||||
case SYMPATHETIC_DELTA:
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * oppositeJointPose->getPublicRotation());
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_DEFAULT,
|
||||
deltaRot * oppositeJointPose->getPublicRotation());
|
||||
if (oppositePoserJoint)
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, deltaRot);
|
||||
break;
|
||||
|
|
@ -689,7 +925,8 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
break;
|
||||
|
||||
case MIRROR_DELTA:
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, mirroredRotation * oppositeJointPose->getPublicRotation());
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, POSER_CHANGE_DEFAULT,
|
||||
mirroredRotation * oppositeJointPose->getPublicRotation());
|
||||
if (oppositePoserJoint)
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, mirroredRotation);
|
||||
break;
|
||||
|
|
@ -1071,7 +1308,7 @@ void FSPoserAnimator::loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint*
|
|||
jointPose->purgeUndoQueue();
|
||||
|
||||
LLQuaternion rot = translateRotationToQuaternion(avatar, jointPose, POSER_FRAME_BONE, SWAP_NOTHING, NEGATE_NOTHING, rotation);
|
||||
jointPose->setPublicRotation(setBaseToZero, rot);
|
||||
jointPose->setPublicRotation(setBaseToZero, POSER_CHANGE_DEFAULT, rot);
|
||||
}
|
||||
|
||||
void FSPoserAnimator::loadJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, bool loadPositionAsDelta, LLVector3 position)
|
||||
|
|
@ -1332,10 +1569,10 @@ bool FSPoserAnimator::isAvatarSafeToUse(LLVOAvatar* avatar) const
|
|||
|
||||
int FSPoserAnimator::getChildJointDepth(const FSPoserJoint* joint, S32 depth) const
|
||||
{
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
if (numberOfBvhChildNodes < 1)
|
||||
if (joint->bvhChildren().empty())
|
||||
return depth;
|
||||
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
depth++;
|
||||
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
|
|
@ -1352,10 +1589,10 @@ int FSPoserAnimator::getChildJointDepth(const FSPoserJoint* joint, S32 depth) co
|
|||
|
||||
void FSPoserAnimator::deRotateWorldLockedDescendants(const FSPoserJoint* joint, FSPosingMotion* posingMotion, LLQuaternion rotationChange)
|
||||
{
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
if (numberOfBvhChildNodes < 1)
|
||||
if (joint->bvhChildren().empty())
|
||||
return;
|
||||
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
FSJointPose* parentJoint = posingMotion->getJointPoseByJointName(joint->jointName());
|
||||
if (!parentJoint)
|
||||
return;
|
||||
|
|
@ -1385,14 +1622,14 @@ void FSPoserAnimator::deRotateJointOrFirstLockedChild(const FSPoserJoint* joint,
|
|||
LLQuaternion rotDiffInChildFrame = differenceInWorldRot * rotationChange * ~differenceInWorldRot;
|
||||
rotDiffInChildFrame.conjugate();
|
||||
|
||||
jointPose->setPublicRotation(false, rotDiffInChildFrame * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(false, POSER_CHANGE_ROTATION, rotDiffInChildFrame * jointPose->getPublicRotation());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
if (numberOfBvhChildNodes < 1)
|
||||
if (joint->bvhChildren().empty())
|
||||
return;
|
||||
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren().at(index));
|
||||
|
|
@ -1403,12 +1640,54 @@ void FSPoserAnimator::deRotateJointOrFirstLockedChild(const FSPoserJoint* joint,
|
|||
}
|
||||
}
|
||||
|
||||
void FSPoserAnimator::undoOrRedoWorldLockedDescendants(const FSPoserJoint& joint, FSPosingMotion* posingMotion, bool redo)
|
||||
void FSPoserAnimator::undoOrRedoRotatedParents(const FSPoserJoint& joint, FSPosingMotion* posingMotion, bool redo)
|
||||
{
|
||||
size_t numberOfBvhChildNodes = joint.bvhChildren().size();
|
||||
if (numberOfBvhChildNodes < 1)
|
||||
if (!posingMotion)
|
||||
return;
|
||||
|
||||
FSJointPose* parentJointPose = findParentJointPose(posingMotion, joint.jointName());
|
||||
if (!parentJointPose)
|
||||
return;
|
||||
|
||||
if (redo)
|
||||
parentJointPose->redoLastChange();
|
||||
else
|
||||
parentJointPose->undoLastChange();
|
||||
|
||||
FSJointPose* grandParentJointPose = findParentJointPose(posingMotion, parentJointPose->jointName());
|
||||
if (!grandParentJointPose)
|
||||
return;
|
||||
|
||||
if (redo)
|
||||
grandParentJointPose->redoLastChange();
|
||||
else
|
||||
grandParentJointPose->undoLastChange();
|
||||
}
|
||||
|
||||
FSJointPose* FSPoserAnimator::findParentJointPose(FSPosingMotion* posingMotion, std::string jointName)
|
||||
{
|
||||
if (jointName.empty() || !posingMotion)
|
||||
return nullptr;
|
||||
|
||||
for (size_t index = 0; index != PoserJoints.size(); ++index)
|
||||
{
|
||||
auto children = PoserJoints[index].bvhChildren();
|
||||
auto it = std::find(children.begin(), children.end(), jointName);
|
||||
if (it == children.end())
|
||||
continue;
|
||||
|
||||
return posingMotion->getJointPoseByJointName(PoserJoints[index].jointName());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FSPoserAnimator::undoOrRedoWorldLockedDescendants(const FSPoserJoint& joint, FSPosingMotion* posingMotion, bool redo)
|
||||
{
|
||||
if (joint.bvhChildren().empty())
|
||||
return;
|
||||
|
||||
size_t numberOfBvhChildNodes = joint.bvhChildren().size();
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint.bvhChildren().at(index));
|
||||
|
|
@ -1438,10 +1717,10 @@ void FSPoserAnimator::undoOrRedoJointOrFirstLockedChild(const FSPoserJoint& join
|
|||
return;
|
||||
}
|
||||
|
||||
size_t numberOfBvhChildNodes = joint.bvhChildren().size();
|
||||
if (numberOfBvhChildNodes < 1)
|
||||
if (joint.bvhChildren().empty())
|
||||
return;
|
||||
|
||||
size_t numberOfBvhChildNodes = joint.bvhChildren().size();
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint.bvhChildren().at(index));
|
||||
|
|
|
|||
|
|
@ -792,19 +792,19 @@ public:
|
|||
void applyJointMirrorToBaseRotations(FSPosingMotion* posingMotion);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// Translates the supplied rotation vector from UI to a Quaternion for the bone.
|
||||
/// Also performs the axis-swapping and other transformations for up/down/left/right to make sense.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose joint is being manipulated.</param>
|
||||
/// <param name="joint">The joint which is being altered.</param>
|
||||
/// <param name="frame">The frame of reference the translation should be performed in.</param>
|
||||
/// <param name="translation">The axis translation to perform.</param>
|
||||
/// <param name="negation">The style of axis-negation.</param>
|
||||
/// <param name="rotation">The rotation to translate and transform to quaternion.</param>
|
||||
/// <returns>The translated rotation quaternion.</returns>
|
||||
LLQuaternion translateRotationToQuaternion(LLVOAvatar* avatar, FSJointPose* joint, E_PoserReferenceFrame frame,
|
||||
E_BoneAxisTranslation translation, S32 negation, LLVector3 rotation);
|
||||
/// <summary>
|
||||
/// Translates the supplied rotation vector from UI to a Quaternion for the bone.
|
||||
/// Also performs the axis-swapping and other transformations for up/down/left/right to make sense.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose joint is being manipulated.</param>
|
||||
/// <param name="joint">The joint which is being altered.</param>
|
||||
/// <param name="frame">The frame of reference the translation should be performed in.</param>
|
||||
/// <param name="translation">The axis translation to perform.</param>
|
||||
/// <param name="negation">The style of axis-negation.</param>
|
||||
/// <param name="rotation">The rotation to translate and transform to quaternion.</param>
|
||||
/// <returns>The translated rotation quaternion.</returns>
|
||||
LLQuaternion translateRotationToQuaternion(LLVOAvatar* avatar, FSJointPose* joint, E_PoserReferenceFrame frame,
|
||||
E_BoneAxisTranslation translation, S32 negation, LLVector3 rotation);
|
||||
|
||||
/// <summary>
|
||||
/// Translates a bone-rotation quaternion to a vector usable easily on the UI.
|
||||
|
|
@ -900,6 +900,88 @@ public:
|
|||
/// </remarks>
|
||||
LLQuaternion changeToRotationFrame(LLVOAvatar* avatar, const LLQuaternion& rotation, E_PoserReferenceFrame frame, FSJointPose* joint);
|
||||
|
||||
void updateJointRotationFromManip(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero,
|
||||
E_BoneDeflectionStyles style, E_PoserReferenceFrame frame, const LLQuaternion& rotation);
|
||||
|
||||
void updateJointPositionFromManip(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero,
|
||||
E_BoneDeflectionStyles style, const LLVector3& position);
|
||||
|
||||
/// <summary>
|
||||
/// Undoes or re-does the parent and grandparent joint rotations from a updateJointPositionFromManip(...)
|
||||
/// </summary>
|
||||
/// <param name="joint">The joint whose parent and grandparent need to undo.</param>
|
||||
/// <param name="posingMotion">The posing motion.</param>
|
||||
/// <param name="redo">Whether to redo the rotation.</param>
|
||||
void undoOrRedoRotatedParents(const FSPoserJoint& joint, FSPosingMotion* posingMotion, bool redo);
|
||||
|
||||
/// <summary>
|
||||
/// Finds a jointPose using the supplied name.
|
||||
/// </summary>
|
||||
/// <param name="posingMotion">The posing motion.</param>
|
||||
/// <param name="jointName">The name of the joint.</param>
|
||||
/// <returns>The jointPose if found, otherwise nullptr.</returns>
|
||||
FSJointPose* findParentJointPose(FSPosingMotion* posingMotion, std::string jointName);
|
||||
|
||||
/// <summary>
|
||||
/// Determines the rotation of the grand-parent joint to move a system containing a 'hinge' joint.
|
||||
/// </summary>
|
||||
/// <param name="posA">The world position of the grand-parent joint.</param>
|
||||
/// <param name="posC">The world position of the parent joint.</param>
|
||||
/// <param name="posC">The world position of the moved joint.</param>
|
||||
/// <param name="changeAtC">The world-referenced movement of the moved joint.</param>
|
||||
/// <returns>The rotation required for the system of moved-joint, parent and grandparent.</returns>
|
||||
/// <remarks>
|
||||
/// The first of a 2-part treatment to move a joint by changing the rotation of its two parents.
|
||||
/// This method determines the rotation for the entire frame (a triangle) of joint-parent-grandparent.
|
||||
/// It finds the vector of the grand-parent to child (vectorAC) before and after moment, then uses
|
||||
/// dot-product to determine the angle change.
|
||||
/// Cross product of the change-vector and AC determines the axis of rotation.
|
||||
/// </remarks>
|
||||
LLQuaternion getAbcFrameRotation(const LLVector3 posA, const LLVector3 posB, const LLVector3 posC, const LLVector3 changeAtC);
|
||||
|
||||
/// <summary>
|
||||
/// Determines the rotation changes for the grandparent and parent joints to position the child when the parent joint is a hinge.
|
||||
/// </summary>
|
||||
/// <param name="posA">The world position of the grand-parent joint.</param>
|
||||
/// <param name="posB">The world position of the parent joint.</param>
|
||||
/// <param name="posC">The world position of the moved joint.</param>
|
||||
/// <param name="changeAtC">The world-referenced movement of the moved joint.</param>
|
||||
/// <param name="changeAtA">The rotation at the grandparent to extend or retract the moved joint.</param>
|
||||
/// <param name="changeAtB">The rotation at the parent to extend or retract the moved joint.</param>
|
||||
/// <returns>True if the rotation can be made, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// The second of a 2-part treatment to move a joint by changing the rotation of its two parents.
|
||||
/// This method calculates rotations at grandparent and parent so that the length AC (grandparent to child) changes.
|
||||
/// Both rotations are in the plane created by grandparent-parent-child.
|
||||
/// This emulates the behaviour of a 'hinge' joint, like 'flexing' an elbow or knee.
|
||||
/// Child movement is along vector AC (grandparent-child), and does not account for 'world movement' differences in C because of changeAtC,
|
||||
/// as that is handled by getAbcFrameRotation.
|
||||
/// </remarks>
|
||||
bool getPlanarRotationAtAandB(const LLVector3 posA, const LLVector3 posB, const LLVector3 posC, const LLVector3 changeAtC,
|
||||
LLQuaternion& changeAtA, LLQuaternion& changeAtB);
|
||||
|
||||
/// <summary>
|
||||
/// Determines the rotation changes for the grandparent and parent joints to position the child when all joints are 'socket' joints.
|
||||
/// </summary>
|
||||
/// <param name="posA">The world position of the grand-parent joint.</param>
|
||||
/// <param name="posB">The world position of the parent joint.</param>
|
||||
/// <param name="posC">The world position of the moved joint.</param>
|
||||
/// <param name="changeAtC">The world-referenced movement of the moved joint.</param>
|
||||
/// <param name="changeAtA">The rotation at the grandparent to extend or retract the moved joint.</param>
|
||||
/// <param name="changeAtB">The rotation at the parent to extend or retract the moved joint.</param>
|
||||
/// <returns>True if the rotation can be made, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// Moves the child spherically in the specified direction by rotating the parent and grandparent.
|
||||
/// </remarks>
|
||||
bool getFreeRotationAtAandB(const LLVector3 posA, const LLVector3 posB, const LLVector3 posC, const LLVector3 changeAtC,
|
||||
LLQuaternion& changeAtA, LLQuaternion& changeAtB);
|
||||
|
||||
LLQuaternion getQuaternionFromWorldVector(const LLVector3 worldVector);
|
||||
|
||||
bool parentJointIsHinge(LLJoint* parentJoint);
|
||||
bool jointIsPelvis(const LLJoint* joint);
|
||||
bool canMoveToNewPosition(const LLVector3 posA, const LLVector3 posB, const LLVector3 posC, const LLVector3 posNewC);
|
||||
|
||||
/// <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.
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ void FSPosingMotion::setAllRotationsToZeroAndClearUndo()
|
|||
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
|
||||
{
|
||||
poserJoint_iter->purgeUndoQueue();
|
||||
poserJoint_iter->setPublicRotation(true, LLQuaternion::DEFAULT);
|
||||
poserJoint_iter->setPublicRotation(true, POSER_CHANGE_ROTATION, LLQuaternion::DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1017,13 +1017,11 @@ bool FSToolCompPose::handleMouseUp(S32 x, S32 y, MASK mask)
|
|||
// If you want SHIFT+CTRL combos to do something else
|
||||
LLTool* FSToolCompPose::getOverrideTool(MASK mask)
|
||||
{
|
||||
// Example from LLToolCompRotate that calls scale if SHIFT+CTRL
|
||||
if (mask == (MASK_CONTROL | MASK_SHIFT))
|
||||
if (mask == MASK_CONTROL)
|
||||
{
|
||||
// If you have a scale tool, return that. Or else remove
|
||||
// this if you don't want an override.
|
||||
return LLToolCompScale::getInstance();
|
||||
return FSToolCompPoseTranslate::getInstance();
|
||||
}
|
||||
|
||||
// Otherwise fallback
|
||||
return LLToolComposite::getOverrideTool(mask);
|
||||
}
|
||||
|
|
@ -1061,3 +1059,148 @@ void FSToolCompPose::render()
|
|||
LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
FSToolCompPoseTranslate* FSToolCompPoseTranslate::getInstance()
|
||||
{
|
||||
// Meyers singleton pattern
|
||||
static FSToolCompPoseTranslate instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// Constructor
|
||||
FSToolCompPoseTranslate::FSToolCompPoseTranslate() : LLToolComposite(std::string("PoseTranslate"))
|
||||
{
|
||||
// Create a joint manipulator
|
||||
mManip = new FSManipTranslateJoint(this);
|
||||
|
||||
// Set the default and current subtool
|
||||
mCur = mManip;
|
||||
mDefault = mManip;
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// Destructor
|
||||
FSToolCompPoseTranslate::~FSToolCompPoseTranslate()
|
||||
{
|
||||
delete mManip;
|
||||
mManip = nullptr;
|
||||
|
||||
delete mSelectRect;
|
||||
mSelectRect = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// Handle Hover
|
||||
bool FSToolCompPoseTranslate::handleHover(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
// If the current subtool hasn't captured the mouse,
|
||||
// switch to your manip subtool (like LLToolCompRotate).
|
||||
if (!mCur->hasMouseCapture())
|
||||
{
|
||||
setCurrentTool(mManip);
|
||||
}
|
||||
return mCur->handleHover(x, y, mask);
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// Handle MouseDown
|
||||
bool FSToolCompPoseTranslate::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
mMouseDown = true;
|
||||
|
||||
// Kick off an async pick, which calls pickCallback when complete
|
||||
// so we can see if user clicked on a manip ring or not
|
||||
gViewerWindow->pickAsync(x, y, mask, pickCallback);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// The pickCallback
|
||||
void FSToolCompPoseTranslate::pickCallback(const LLPickInfo& pick_info)
|
||||
{
|
||||
FSToolCompPoseTranslate* self = FSToolCompPoseTranslate::getInstance();
|
||||
FSManipTranslateJoint* manip = self->mManip;
|
||||
|
||||
if (!manip) return; // No manipulator available, exit
|
||||
|
||||
// Highlight the manipulator based on the mouse position
|
||||
manip->highlightManipulators(pick_info.mMousePt.mX, pick_info.mMousePt.mY);
|
||||
|
||||
if (!self->mMouseDown)
|
||||
{
|
||||
// No action needed if mouse is up; interaction is handled by highlight logic
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if a manipulator ring is highlighted
|
||||
if (manip->getHighlightedPart() != LLManip::LL_NO_PART)
|
||||
{
|
||||
// Switch to the manipulator tool for dragging
|
||||
self->setCurrentTool(manip);
|
||||
manip->handleMouseDownOnPart(pick_info.mMousePt.mX, pick_info.mMousePt.mY, pick_info.mKeyMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no ring is highlighted, reset interaction or do nothing
|
||||
LL_DEBUGS("FSToolCompPose") << "No manipulator ring selected" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------
|
||||
// Handle MouseUp
|
||||
bool FSToolCompPoseTranslate::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
mMouseDown = false;
|
||||
// The base LLToolComposite sets mCur->handleMouseUp(...)
|
||||
// and does other management
|
||||
return LLToolComposite::handleMouseUp(x, y, mask);
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// getOverrideTool
|
||||
// If you want SHIFT+CTRL combos to do something else
|
||||
LLTool* FSToolCompPoseTranslate::getOverrideTool(MASK mask)
|
||||
{
|
||||
if (mask == (MASK_CONTROL | MASK_SHIFT))
|
||||
{
|
||||
return LLToolCompScale::getInstance();
|
||||
}
|
||||
// Otherwise fallback
|
||||
return LLToolComposite::getOverrideTool(mask);
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// Handle DoubleClick
|
||||
bool FSToolCompPoseTranslate::handleDoubleClick(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if (!mManip->getSelection()->isEmpty() &&
|
||||
mManip->getHighlightedPart() == LLManip::LL_NO_PART)
|
||||
{
|
||||
// Possibly show some pose properties or open the pose floater
|
||||
mPoser = dynamic_cast<FSFloaterPoser*>(LLFloaterReg::showInstance("fs_poser"));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If nothing selected, try a mouse down again
|
||||
return handleMouseDown(x, y, mask);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// render
|
||||
void FSToolCompPoseTranslate::render()
|
||||
{
|
||||
// Render the current subtool
|
||||
mCur->render();
|
||||
|
||||
// If the current subtool is not the manip, we can still
|
||||
// optionally draw manip guidelines in the background
|
||||
if (mCur != mManip)
|
||||
{
|
||||
mManip->renderGuidelines(); // or something similar if your manip has it
|
||||
LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ protected:
|
|||
|
||||
// Subclass of LLToolComposite
|
||||
#include "fsmaniprotatejoint.h" // For FSManipRotateJoint
|
||||
#include "fsmaniptranslatejoint.h"
|
||||
#include "fsfloaterposer.h"
|
||||
class FSToolCompPose : public LLToolComposite
|
||||
{
|
||||
|
|
@ -292,5 +293,40 @@ protected:
|
|||
bool mMouseDown = false;
|
||||
};
|
||||
|
||||
class FSToolCompPoseTranslate : public LLToolComposite
|
||||
{
|
||||
public:
|
||||
// Typical pattern: pass a name like "Pose"
|
||||
FSToolCompPoseTranslate();
|
||||
virtual ~FSToolCompPoseTranslate();
|
||||
|
||||
// For some viewer patterns, we create a static singleton:
|
||||
static FSToolCompPoseTranslate* getInstance();
|
||||
|
||||
// Overriding base events:
|
||||
virtual bool handleHover(S32 x, S32 y, MASK mask) override;
|
||||
virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
virtual bool handleMouseUp(S32 x, S32 y, MASK mask) override;
|
||||
virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) override;
|
||||
virtual void render() override;
|
||||
void setAvatar(LLVOAvatar* avatar) { mManip->setAvatar(avatar); };
|
||||
void setJoint(LLJoint* joint) { mManip->setJoint(joint); };
|
||||
void setReferenceFrame(E_PoserReferenceFrame frame) { mManip->setReferenceFrame(frame); };
|
||||
|
||||
// Optional override if you have SHIFT/CTRL combos
|
||||
virtual LLTool* getOverrideTool(MASK mask) override;
|
||||
|
||||
// The pick callback invoked on async pick
|
||||
static void pickCallback(const LLPickInfo& pick_info);
|
||||
void setPoserFloater(FSFloaterPoser* poser){ mPoser = poser; };
|
||||
FSFloaterPoser* getPoserFloater(){ return mPoser; };
|
||||
protected:
|
||||
// Tools within this composite
|
||||
FSManipTranslateJoint* mManip = nullptr;
|
||||
LLToolSelectRect* mSelectRect = nullptr;
|
||||
FSFloaterPoser* mPoser = nullptr;
|
||||
bool mMouseDown = false;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_TOOLCOMP_H
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ void LLToolMgr::initTools()
|
|||
gBasicToolset->addTool( LLToolCompInspect::getInstance() );
|
||||
gFaceEditToolset->addTool( LLToolCamera::getInstance() );
|
||||
gPoserToolset->addTool( FSToolCompPose::getInstance() );
|
||||
gPoserToolset->addTool( FSToolCompPoseTranslate::getInstance() );
|
||||
|
||||
// On startup, use "select" tool
|
||||
setCurrentToolset(gBasicToolset);
|
||||
|
|
|
|||
|
|
@ -5105,9 +5105,12 @@ void LLViewerWindow::renderSelections( bool for_gl_pick, bool pick_parcel_walls,
|
|||
}
|
||||
// <FS:Beq> render the poser manipulator guides
|
||||
// if we have something selected those toosl should override
|
||||
if ( (!for_hud) && (selection->isEmpty()) && (LLToolMgr::getInstance()->getCurrentTool() == FSToolCompPose::getInstance()) )
|
||||
if (!for_hud && selection->isEmpty())
|
||||
{
|
||||
FSToolCompPose::getInstance()->render();
|
||||
if (LLToolMgr::getInstance()->getCurrentTool() == FSToolCompPose::getInstance())
|
||||
FSToolCompPose::getInstance()->render();
|
||||
if (LLToolMgr::getInstance()->getCurrentTool() == FSToolCompPoseTranslate::getInstance())
|
||||
FSToolCompPoseTranslate::getInstance()->render();
|
||||
}
|
||||
// </FS:Beq>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue