parent
1e143623c3
commit
fddbde3f91
|
|
@ -8056,6 +8056,17 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSPoserStopPosingWhenClosed</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether to stop animating with the poser when the poser window is closed.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FSPoserTrackpadSensitivity</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "llviewercontrol.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llwindow.h"
|
||||
#include "llvoavatarself.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
@ -52,6 +53,7 @@ constexpr char XML_LIST_TITLE_STRING_PREFIX[] = "title_";
|
|||
constexpr char XML_JOINT_TRANSFORM_STRING_PREFIX[] = "joint_transform_";
|
||||
constexpr std::string_view POSER_ADVANCEDWINDOWSTATE_SAVE_KEY = "FSPoserAdvancedWindowState";
|
||||
constexpr std::string_view POSER_TRACKPAD_SENSITIVITY_SAVE_KEY = "FSPoserTrackpadSensitivity";
|
||||
constexpr std::string_view POSER_STOPPOSINGWHENCLOSED_SAVE_KEY = "FSPoserStopPosingWhenClosed";
|
||||
} // namespace
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -59,6 +61,7 @@ constexpr std::string_view POSER_TRACKPAD_SENSITIVITY_SAVE_KEY = "FSPoserTrackpa
|
|||
/// The trackpad ordinarily has a range of +1..-1; multiplied by PI, gives PI to -PI, or all 360 degrees of deflection.
|
||||
/// </summary>
|
||||
constexpr F32 NormalTrackpadRangeInRads = F_PI;
|
||||
bool FSFloaterPoser::mDisableRecaptureUntilStopPosing;
|
||||
|
||||
FSFloaterPoser::FSFloaterPoser(const LLSD& key) : LLFloater(key)
|
||||
{
|
||||
|
|
@ -76,6 +79,7 @@ FSFloaterPoser::FSFloaterPoser(const LLSD& key) : LLFloater(key)
|
|||
mCommitCallbackRegistrar.add("Poser.AdjustTrackPadSensitivity", [this](LLUICtrl*, const LLSD&) { onAdjustTrackpadSensitivity(); });
|
||||
|
||||
mCommitCallbackRegistrar.add("Poser.PositionSet", [this](LLUICtrl*, const LLSD&) { onAvatarPositionSet(); });
|
||||
mCommitCallbackRegistrar.add("Poser.SetToTPose", [this](LLUICtrl*, const LLSD&) { onSetAvatarToTpose(); });
|
||||
|
||||
mCommitCallbackRegistrar.add("Poser.Advanced.PositionSet", [this](LLUICtrl*, const LLSD&) { onAdvancedPositionSet(); });
|
||||
mCommitCallbackRegistrar.add("Poser.Advanced.ScaleSet", [this](LLUICtrl*, const LLSD&) { onAdvancedScaleSet(); });
|
||||
|
|
@ -154,9 +158,7 @@ bool FSFloaterPoser::postBuild()
|
|||
|
||||
mToggleAdvancedPanelBtn = getChild<LLButton>("toggleAdvancedPanel");
|
||||
if (gSavedSettings.getBOOL(POSER_ADVANCEDWINDOWSTATE_SAVE_KEY))
|
||||
{
|
||||
mToggleAdvancedPanelBtn->setValue(true);
|
||||
}
|
||||
|
||||
mTrackpadSensitivitySlider = getChild<LLSliderCtrl>("trackpad_sensitivity_slider");
|
||||
mTrackpadSensitivitySlider->setValue(gSavedSettings.getF32(POSER_TRACKPAD_SENSITIVITY_SAVE_KEY));
|
||||
|
|
@ -195,6 +197,9 @@ bool FSFloaterPoser::postBuild()
|
|||
mToggleSympatheticRotationBtn = getChild<LLButton>("button_toggleSympatheticRotation");
|
||||
mToggleDeltaModeBtn = getChild<LLButton>("delta_mode_toggle");
|
||||
mRedoChangeBtn = getChild<LLButton>("button_redo_change");
|
||||
mSetToTposeButton = getChild<LLButton>("set_t_pose_button");
|
||||
mRecaptureJointsButton = getChild<LLButton>("button_RecaptureParts");
|
||||
mRecaptureJointsButton->setEnabled(!mDisableRecaptureUntilStopPosing);
|
||||
|
||||
mJointsParentPnl = getChild<LLPanel>("joints_parent_panel");
|
||||
mAdvancedParentPnl = getChild<LLPanel>("advanced_parent_panel");
|
||||
|
|
@ -207,6 +212,10 @@ bool FSFloaterPoser::postBuild()
|
|||
mMiscJointsPnl = getChild<LLPanel>("misc_joints_panel");
|
||||
mCollisionVolumesPnl = getChild<LLPanel>("collision_volumes_panel");
|
||||
|
||||
mStopPosingWhenClosed = getChild<LLCheckBoxCtrl>("stop_posing_on_close_checkbox");
|
||||
if (gSavedSettings.getBOOL(POSER_STOPPOSINGWHENCLOSED_SAVE_KEY))
|
||||
mStopPosingWhenClosed->set(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -217,13 +226,21 @@ void FSFloaterPoser::onOpen(const LLSD& key)
|
|||
onJointSelect();
|
||||
onOpenSetAdvancedPanel();
|
||||
refreshPoseScroll(mHandPresetsScrollList, POSE_PRESETS_HANDS_SUBDIRECTORY);
|
||||
startPosingSelf();
|
||||
|
||||
LLFloater::onOpen(key);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClose(bool app_quitting)
|
||||
{
|
||||
gSavedSettings.setBOOL(POSER_ADVANCEDWINDOWSTATE_SAVE_KEY, mToggleAdvancedPanelBtn->getValue().asBoolean());
|
||||
if (mToggleAdvancedPanelBtn)
|
||||
gSavedSettings.setBOOL(POSER_ADVANCEDWINDOWSTATE_SAVE_KEY, mToggleAdvancedPanelBtn->getValue().asBoolean());
|
||||
|
||||
if (mStopPosingWhenClosed)
|
||||
gSavedSettings.setBOOL(POSER_STOPPOSINGWHENCLOSED_SAVE_KEY, mStopPosingWhenClosed->getValue());
|
||||
|
||||
if (gSavedSettings.getBOOL(POSER_STOPPOSINGWHENCLOSED_SAVE_KEY))
|
||||
stopPosingSelf();
|
||||
|
||||
LLFloater::onClose(app_quitting);
|
||||
}
|
||||
|
|
@ -331,26 +348,25 @@ 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);
|
||||
|
||||
LLSD record;
|
||||
S32 version = 3;
|
||||
record["version"]["value"] = version;
|
||||
record["version"]["value"] = (S32)4;
|
||||
record["startFromTeePose"]["value"] = fromZeroRot;
|
||||
|
||||
LLVector3 rotation, position, scale;
|
||||
|
||||
for (const FSPoserAnimator::FSPoserJoint& pj : mPoserAnimator.PoserJoints)
|
||||
{
|
||||
std::string bone_name = pj.jointName();
|
||||
std::string bone_name = pj.jointName();
|
||||
if (!mPoserAnimator.tryGetJointSaveVectors(avatar, pj, &rotation, &position, &scale))
|
||||
continue;
|
||||
|
||||
LLVector3 vec3 = mPoserAnimator.getJointRotation(avatar, pj, SWAP_NOTHING, NEGATE_NOTHING);
|
||||
|
||||
record[bone_name] = pj.jointName();
|
||||
record[bone_name]["rotation"] = vec3.getValue();
|
||||
|
||||
vec3 = mPoserAnimator.getJointPosition(avatar, pj);
|
||||
record[bone_name]["position"] = vec3.getValue();
|
||||
|
||||
vec3 = mPoserAnimator.getJointScale(avatar, pj);
|
||||
record[bone_name]["scale"] = vec3.getValue();
|
||||
|
||||
record[bone_name]["enabled"] = mPoserAnimator.isPosingAvatarJoint(avatar, pj);
|
||||
record[bone_name] = pj.jointName();
|
||||
record[bone_name]["enabled"] = mPoserAnimator.isPosingAvatarJoint(avatar, pj);
|
||||
record[bone_name]["rotation"] = rotation.getValue();
|
||||
record[bone_name]["position"] = position.getValue();
|
||||
record[bone_name]["scale"] = scale.getValue();
|
||||
}
|
||||
|
||||
llofstream file;
|
||||
|
|
@ -394,7 +410,7 @@ void FSFloaterPoser::onClickToggleSelectedBoneEnabled()
|
|||
|
||||
refreshRotationSliders();
|
||||
refreshTrackpadCursor();
|
||||
refreshTextEmbiggeningOnAllScrollLists();
|
||||
refreshTextHighlightingOnAllScrollLists();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickFlipSelectedJoints()
|
||||
|
|
@ -458,6 +474,9 @@ void FSFloaterPoser::onClickFlipPose()
|
|||
|
||||
void FSFloaterPoser::onClickRecaptureSelectedBones()
|
||||
{
|
||||
if (mDisableRecaptureUntilStopPosing)
|
||||
return;
|
||||
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
return;
|
||||
|
|
@ -476,7 +495,7 @@ void FSFloaterPoser::onClickRecaptureSelectedBones()
|
|||
continue;
|
||||
|
||||
LLVector3 newRotation = mPoserAnimator.getJointRotation(avatar, *item, getJointTranslation(item->jointName()),
|
||||
getJointNegation(item->jointName()), true);
|
||||
getJointNegation(item->jointName()), CURRENTROTATION);
|
||||
LLVector3 newPosition = mPoserAnimator.getJointPosition(avatar, *item, true);
|
||||
LLVector3 newScale = mPoserAnimator.getJointScale(avatar, *item, true);
|
||||
|
||||
|
|
@ -490,7 +509,7 @@ void FSFloaterPoser::onClickRecaptureSelectedBones()
|
|||
|
||||
refreshRotationSliders();
|
||||
refreshTrackpadCursor();
|
||||
refreshTextEmbiggeningOnAllScrollLists();
|
||||
refreshTextHighlightingOnAllScrollLists();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickBrowsePoseCache()
|
||||
|
|
@ -673,14 +692,16 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose
|
|||
loadMethod == ROT_POS_AND_SCALES;
|
||||
bool loadScales = loadMethod == SCALES || loadMethod == POSITIONS_AND_SCALES || loadMethod == ROTATIONS_AND_SCALES ||
|
||||
loadMethod == ROT_POS_AND_SCALES;
|
||||
bool loadHandsOnly = loadMethod == HAND_RIGHT || loadMethod == HAND_LEFT;
|
||||
|
||||
try
|
||||
{
|
||||
LLSD pose;
|
||||
llifstream infile;
|
||||
LLVector3 vec3;
|
||||
bool enabled;
|
||||
LLSD pose;
|
||||
llifstream infile;
|
||||
LLVector3 vec3;
|
||||
LLQuaternion quat;
|
||||
bool enabled;
|
||||
S32 version = 0;
|
||||
bool startFromZeroRot = false;
|
||||
|
||||
infile.open(fullPath);
|
||||
if (!infile.is_open())
|
||||
|
|
@ -697,40 +718,48 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose
|
|||
|
||||
for (LLSD::map_const_iterator 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 (loadHandsOnly && name.find("Hand") == std::string::npos)
|
||||
continue;
|
||||
if (name == "startFromTeePose")
|
||||
startFromZeroRot = control_map["value"].asBoolean();
|
||||
|
||||
if (name == "version")
|
||||
version = (S32)control_map["value"].asInteger();
|
||||
}
|
||||
|
||||
bool loadPositionsAndScalesAsDeltas = false;
|
||||
if (version > 3)
|
||||
loadPositionsAndScalesAsDeltas = true;
|
||||
|
||||
if (startFromZeroRot) // old save formats will always start from T-Pose, for better or worse.
|
||||
mPoserAnimator.setAllAvatarStartingRotationsToZero(avatar);
|
||||
|
||||
for (LLSD::map_const_iterator itr = pose.beginMap(); itr != pose.endMap(); ++itr)
|
||||
{
|
||||
std::string const& name = itr->first;
|
||||
LLSD const& control_map = itr->second;
|
||||
|
||||
const FSPoserAnimator::FSPoserJoint *poserJoint = mPoserAnimator.getPoserJointByName(name);
|
||||
if (!poserJoint)
|
||||
continue;
|
||||
|
||||
if (loadHandsOnly && control_map.has("rotation"))
|
||||
{
|
||||
vec3.setValue(control_map["rotation"]);
|
||||
|
||||
mPoserAnimator.setJointRotation(avatar, poserJoint, vec3, NONE, SWAP_NOTHING, NEGATE_NOTHING);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (loadRotations && control_map.has("rotation"))
|
||||
{
|
||||
vec3.setValue(control_map["rotation"]);
|
||||
mPoserAnimator.setJointRotation(avatar, poserJoint, vec3, NONE, SWAP_NOTHING, NEGATE_NOTHING); // If we keep defaults BD poses mostly load, except fingers
|
||||
mPoserAnimator.loadJointRotation(avatar, poserJoint, vec3);
|
||||
}
|
||||
|
||||
if (loadPositions && control_map.has("position"))
|
||||
{
|
||||
vec3.setValue(control_map["position"]);
|
||||
mPoserAnimator.setJointPosition(avatar, poserJoint, vec3, NONE);
|
||||
mPoserAnimator.loadJointPosition(avatar, poserJoint, loadPositionsAndScalesAsDeltas, vec3);
|
||||
}
|
||||
|
||||
if (loadScales && control_map.has("scale"))
|
||||
{
|
||||
vec3.setValue(control_map["scale"]);
|
||||
mPoserAnimator.setJointScale(avatar, poserJoint, vec3, NONE);
|
||||
mPoserAnimator.loadJointScale(avatar, poserJoint, loadPositionsAndScalesAsDeltas, vec3);
|
||||
}
|
||||
|
||||
if (control_map.has("enabled"))
|
||||
|
|
@ -749,6 +778,35 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose
|
|||
onJointSelect();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::startPosingSelf()
|
||||
{
|
||||
setUiSelectedAvatar(gAgentAvatarp->getID());
|
||||
LLVOAvatar* avatar = getAvatarByUuid(gAgentAvatarp->getID());
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
bool arePosingSelected = mPoserAnimator.isPosingAvatar(avatar);
|
||||
if (!arePosingSelected && couldAnimateAvatar(avatar))
|
||||
mPoserAnimator.tryPosingAvatar(avatar);
|
||||
|
||||
onAvatarSelect();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::stopPosingSelf()
|
||||
{
|
||||
LLVOAvatar* avatar = getAvatarByUuid(gAgentAvatarp->getID());
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
bool arePosingSelected = mPoserAnimator.isPosingAvatar(avatar);
|
||||
if (!arePosingSelected)
|
||||
return;
|
||||
|
||||
mPoserAnimator.stopPosingAvatar(avatar);
|
||||
onAvatarSelect();
|
||||
reEnableRecaptureIfAllowed();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onPoseStartStop()
|
||||
{
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
|
|
@ -759,6 +817,7 @@ void FSFloaterPoser::onPoseStartStop()
|
|||
if (arePosingSelected)
|
||||
{
|
||||
mPoserAnimator.stopPosingAvatar(avatar);
|
||||
reEnableRecaptureIfAllowed();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -799,7 +858,6 @@ bool FSFloaterPoser::havePermissionToAnimateAvatar(LLVOAvatar *avatar) const
|
|||
|
||||
void FSFloaterPoser::poseControlsEnable(bool enable)
|
||||
{
|
||||
mJointsParentPnl->setEnabled(enable);
|
||||
mAdvancedParentPnl->setEnabled(enable);
|
||||
mTrackballPnl->setEnabled(enable);
|
||||
mFlipPoseBtn->setEnabled(enable);
|
||||
|
|
@ -1060,6 +1118,24 @@ void FSFloaterPoser::onUndoLastScale()
|
|||
refreshAdvancedScaleSliders();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onSetAvatarToTpose()
|
||||
{
|
||||
auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - mTimeLastClickedJointReset;
|
||||
mTimeLastClickedJointReset = std::chrono::system_clock::now();
|
||||
if (timeIntervalSinceLastClick > mDoubleClickInterval)
|
||||
return;
|
||||
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
mRecaptureJointsButton->setEnabled(false);
|
||||
mSavePosesBtn->setLabel("Save Pose");
|
||||
mDisableRecaptureUntilStopPosing = true;
|
||||
|
||||
mPoserAnimator.setAllAvatarStartingRotationsToZero(avatar);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onResetPosition()
|
||||
{
|
||||
// This is a double-click function: it needs to run twice within some amount of time to complete.
|
||||
|
|
@ -1342,6 +1418,23 @@ LLVOAvatar* FSFloaterPoser::getUiSelectedAvatar() const
|
|||
return getAvatarByUuid(selectedAvatarId);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::setUiSelectedAvatar(const LLUUID& avatarToSelect)
|
||||
{
|
||||
for (auto listItem : mAvatarSelectionScrollList->getAllData())
|
||||
{
|
||||
LLScrollListCell* cell = listItem->getColumn(COL_UUID);
|
||||
if (!cell)
|
||||
continue;
|
||||
|
||||
LLUUID avatarId = cell->getValue().asUUID();
|
||||
if (avatarId != avatarToSelect)
|
||||
continue;
|
||||
|
||||
listItem->setSelected(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterPoser::setPoseSaveFileTextBoxToUiSelectedAvatarSaveFileName()
|
||||
{
|
||||
LLScrollListItem* item = mAvatarSelectionScrollList->getFirstSelected();
|
||||
|
|
@ -1665,7 +1758,7 @@ LLVector3 FSFloaterPoser::getRotationOfFirstSelectedJoint() const
|
|||
return rotation;
|
||||
|
||||
rotation = mPoserAnimator.getJointRotation(avatar, *selectedJoints.front(), getJointTranslation(selectedJoints.front()->jointName()),
|
||||
getJointNegation(selectedJoints.front()->jointName()));
|
||||
getJointNegation(selectedJoints.front()->jointName()), TARGETROTATION);
|
||||
|
||||
return rotation;
|
||||
}
|
||||
|
|
@ -1781,8 +1874,9 @@ void FSFloaterPoser::onAvatarSelect()
|
|||
|
||||
bool arePosingSelected = mPoserAnimator.isPosingAvatar(avatar);
|
||||
mStartStopPosingBtn->setValue(arePosingSelected);
|
||||
mSetToTposeButton->setEnabled(arePosingSelected);
|
||||
poseControlsEnable(arePosingSelected);
|
||||
refreshTextEmbiggeningOnAllScrollLists();
|
||||
refreshTextHighlightingOnAllScrollLists();
|
||||
onJointSelect();
|
||||
setPoseSaveFileTextBoxToUiSelectedAvatarSaveFileName();
|
||||
}
|
||||
|
|
@ -1794,7 +1888,7 @@ uuid_vec_t FSFloaterPoser::getNearbyAvatarsAndAnimeshes() const
|
|||
for (LLCharacter* character : LLCharacter::sInstances)
|
||||
{
|
||||
LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(character);
|
||||
if (!couldAnimateAvatar(avatar))
|
||||
if (!havePermissionToAnimateAvatar(avatar))
|
||||
continue;
|
||||
|
||||
avatar_ids.emplace_back(character->getID());
|
||||
|
|
@ -1889,7 +1983,7 @@ void FSFloaterPoser::onAvatarsRefresh()
|
|||
row["columns"][COL_UUID]["value"] = uuid;
|
||||
row["columns"][COL_SAVE]["column"] = "saveFileName";
|
||||
row["columns"][COL_SAVE]["value"] = "";
|
||||
LLScrollListItem* item = mAvatarSelectionScrollList->addElement(row);
|
||||
LLScrollListItem* item = mAvatarSelectionScrollList->addElement(row);
|
||||
}
|
||||
|
||||
// Add Animesh avatars
|
||||
|
|
@ -1917,12 +2011,11 @@ void FSFloaterPoser::onAvatarsRefresh()
|
|||
}
|
||||
|
||||
mAvatarSelectionScrollList->updateLayout();
|
||||
refreshTextEmbiggeningOnAllScrollLists();
|
||||
refreshTextHighlightingOnAllScrollLists();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::refreshTextEmbiggeningOnAllScrollLists()
|
||||
void FSFloaterPoser::refreshTextHighlightingOnAllScrollLists()
|
||||
{
|
||||
// the avatars
|
||||
for (auto listItem : mAvatarSelectionScrollList->getAllData())
|
||||
{
|
||||
LLScrollListCell* cell = listItem->getColumn(COL_UUID);
|
||||
|
|
@ -1946,6 +2039,34 @@ void FSFloaterPoser::refreshTextEmbiggeningOnAllScrollLists()
|
|||
addBoldToScrollList(mCollisionVolumesScrollList, avatar);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::reEnableRecaptureIfAllowed()
|
||||
{
|
||||
if (posingAnyoneOnScrollList())
|
||||
return;
|
||||
|
||||
mRecaptureJointsButton->setEnabled(true);
|
||||
mSavePosesBtn->setLabel("Save Diff");
|
||||
mDisableRecaptureUntilStopPosing = false;
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::posingAnyoneOnScrollList()
|
||||
{
|
||||
for (auto listItem : mAvatarSelectionScrollList->getAllData())
|
||||
{
|
||||
LLScrollListCell* cell = listItem->getColumn(COL_UUID);
|
||||
if (!cell)
|
||||
continue;
|
||||
|
||||
LLUUID selectedAvatarId = cell->getValue().asUUID();
|
||||
LLVOAvatar* listAvatar = getAvatarByUuid(selectedAvatarId);
|
||||
|
||||
if (mPoserAnimator.isPosingAvatar(listAvatar))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FSFloaterPoser::addBoldToScrollList(LLScrollListCtrl* list, LLVOAvatar* avatar)
|
||||
{
|
||||
if (!avatar)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@ class FSFloaterPoser : public LLFloater
|
|||
void onOpen(const LLSD& key) override;
|
||||
void onClose(bool app_quitting) override;
|
||||
|
||||
|
||||
static bool mDisableRecaptureUntilStopPosing;
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the supplied pose list from the supplued subdirectory.
|
||||
/// </summary>
|
||||
|
|
@ -136,6 +137,12 @@ class FSFloaterPoser : public LLFloater
|
|||
/// <returns>The currently selected avatar or animesh.</returns>
|
||||
LLVOAvatar* getUiSelectedAvatar() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the UI selection for avatar or animesh.
|
||||
/// </summary>
|
||||
/// <param name="avatarToSelect">The ID of the avatar to select, if found.</param>
|
||||
void setUiSelectedAvatar(const LLUUID& avatarToSelect);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current bone-deflection style: encapsulates 'anything else you want to do' while you're manipulating a joint.
|
||||
/// Such as: fiddle the opposite joint too.
|
||||
|
|
@ -216,8 +223,11 @@ class FSFloaterPoser : public LLFloater
|
|||
void onRedoLastScale();
|
||||
void onResetPosition();
|
||||
void onResetScale();
|
||||
void onSetAvatarToTpose();
|
||||
void enableOrDisableRedoButton();
|
||||
void onPoseStartStop();
|
||||
void startPosingSelf();
|
||||
void stopPosingSelf();
|
||||
void onLimbTrackballChanged();
|
||||
void onLimbYawPitchRollChanged();
|
||||
void onAvatarPositionSet();
|
||||
|
|
@ -284,9 +294,19 @@ class FSFloaterPoser : public LLFloater
|
|||
S32 getJointNegation(const std::string& jointName) const;
|
||||
|
||||
/// <summary>
|
||||
/// The smallest text embiggens the noble selection.
|
||||
/// Refreshes the text on all scroll lists based on their state.
|
||||
/// </summary>
|
||||
void refreshTextEmbiggeningOnAllScrollLists();
|
||||
void refreshTextHighlightingOnAllScrollLists();
|
||||
|
||||
/// <summary>
|
||||
/// Recapture is be disabled if user is making their own pose (starting from a T-Pose).
|
||||
/// </summary>
|
||||
void reEnableRecaptureIfAllowed();
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether any avatar know by the UI is being posed.
|
||||
/// </summary>
|
||||
bool posingAnyoneOnScrollList();
|
||||
|
||||
/// <summary>
|
||||
/// Applies the appropriate font-face (such as bold) to the text of the supplied list, to indicate use.
|
||||
|
|
@ -356,8 +376,10 @@ class FSFloaterPoser : public LLFloater
|
|||
LLButton* mToggleSympatheticRotationBtn{ nullptr };
|
||||
LLButton* mToggleDeltaModeBtn{ nullptr };
|
||||
LLButton* mRedoChangeBtn{ nullptr };
|
||||
LLButton* mSetToTposeButton{ nullptr };
|
||||
LLButton* mRecaptureJointsButton{ nullptr };
|
||||
|
||||
LLCheckBoxCtrl* mAlsoSaveBvhCbx{ nullptr };
|
||||
LLCheckBoxCtrl* mStopPosingWhenClosed{ nullptr };
|
||||
LLLineEditor* mPoseSaveNameEditor{ nullptr };
|
||||
|
||||
LLPanel* mAdvancedParentPnl{ nullptr };
|
||||
|
|
|
|||
|
|
@ -412,7 +412,35 @@ void FSPoserAnimator::setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
}
|
||||
}
|
||||
|
||||
LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation, bool forRecapture) const
|
||||
bool FSPoserAnimator::posingStartedFromZeroRotations(LLVOAvatar* avatar) const
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return false;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return false;
|
||||
|
||||
bool allStartingRotationsAreZero = posingMotion->allStartingRotationsAreZero();
|
||||
if (allStartingRotationsAreZero)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FSPoserAnimator::setAllAvatarStartingRotationsToZero(LLVOAvatar* avatar)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return;
|
||||
|
||||
posingMotion->setAllRotationsToZero();
|
||||
}
|
||||
|
||||
LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation, E_BoneRotationType rotType) const
|
||||
{
|
||||
LLVector3 vec3;
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
|
|
@ -427,11 +455,18 @@ LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoi
|
|||
return vec3;
|
||||
|
||||
LLQuaternion rot;
|
||||
if (forRecapture)
|
||||
rot = jointPose->getCurrentRotation();
|
||||
else
|
||||
rot = jointPose->getTargetRotation();
|
||||
|
||||
switch (rotType)
|
||||
{
|
||||
case TARGETROTATION:
|
||||
rot = jointPose->getTargetRotation();
|
||||
break;
|
||||
|
||||
case CURRENTROTATION:
|
||||
default:
|
||||
rot = jointPose->getCurrentRotation();
|
||||
break;
|
||||
}
|
||||
|
||||
return translateRotationFromQuaternion(translation, negation, rot);
|
||||
}
|
||||
|
||||
|
|
@ -709,6 +744,85 @@ void FSPoserAnimator::setJointScale(LLVOAvatar* avatar, const FSPoserJoint* join
|
|||
oppositeJointPose->setTargetScale(scale);
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::tryGetJointSaveVectors(LLVOAvatar* avatar, const FSPoserJoint& joint, LLVector3* rot, LLVector3* pos, LLVector3* scale)
|
||||
{
|
||||
if (!rot || !pos || !scale)
|
||||
return false;
|
||||
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return false;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return false;
|
||||
|
||||
FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName());
|
||||
if (!jointPose)
|
||||
return false;
|
||||
|
||||
LLQuaternion difference = jointPose->getTargetRotation() * jointPose->getBeginningRotation().conjugate(); // diff * q1 = q2 -> diff = q2 * inverse(q1)
|
||||
|
||||
difference.getEulerAngles(&rot->mV[VX], &rot->mV[VY], &rot->mV[VZ]);
|
||||
pos->set(jointPose->getTargetPosition() - jointPose->getBeginningPosition());
|
||||
scale->set(jointPose->getTargetScale() - jointPose->getBeginningScale());
|
||||
return true;
|
||||
}
|
||||
|
||||
void FSPoserAnimator::loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, LLVector3 rotation)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar) || !joint)
|
||||
return;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return;
|
||||
|
||||
FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName());
|
||||
if (!jointPose)
|
||||
return;
|
||||
|
||||
LLQuaternion rot = translateRotationToQuaternion(SWAP_NOTHING, NEGATE_NOTHING, rotation);
|
||||
jointPose->setTargetRotation(rot * jointPose->getBeginningRotation());
|
||||
}
|
||||
|
||||
void FSPoserAnimator::loadJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, bool loadPositionAsDelta, LLVector3 position)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar) || !joint)
|
||||
return;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return;
|
||||
|
||||
FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName());
|
||||
if (!jointPose)
|
||||
return;
|
||||
|
||||
if (loadPositionAsDelta)
|
||||
jointPose->setTargetPosition(jointPose->getBeginningPosition() + position);
|
||||
else
|
||||
jointPose->setTargetPosition(position);
|
||||
}
|
||||
|
||||
void FSPoserAnimator::loadJointScale(LLVOAvatar* avatar, const FSPoserJoint* joint, bool loadScaleAsDelta, LLVector3 scale)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar) || !joint)
|
||||
return;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return;
|
||||
|
||||
FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName());
|
||||
if (!jointPose)
|
||||
return;
|
||||
|
||||
if (loadScaleAsDelta)
|
||||
jointPose->setTargetScale(jointPose->getTargetScale() + scale);
|
||||
else
|
||||
jointPose->setTargetScale(scale);
|
||||
}
|
||||
|
||||
const FSPoserAnimator::FSPoserJoint* FSPoserAnimator::getPoserJointByName(const std::string& jointName)
|
||||
{
|
||||
for (size_t index = 0; index != PoserJoints.size(); ++index)
|
||||
|
|
@ -720,7 +834,7 @@ const FSPoserAnimator::FSPoserJoint* FSPoserAnimator::getPoserJointByName(const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::tryPosingAvatar(LLVOAvatar *avatar)
|
||||
bool FSPoserAnimator::tryPosingAvatar(LLVOAvatar* avatar)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return false;
|
||||
|
|
@ -781,20 +895,18 @@ FSPosingMotion* FSPoserAnimator::getPosingMotion(LLVOAvatar* avatar) const
|
|||
FSPosingMotion* FSPoserAnimator::findOrCreatePosingMotion(LLVOAvatar* avatar)
|
||||
{
|
||||
FSPosingMotion* motion = getPosingMotion(avatar);
|
||||
if (motion)
|
||||
return motion;
|
||||
|
||||
if (!motion)
|
||||
{
|
||||
LLTransactionID mTransactionID;
|
||||
mTransactionID.generate();
|
||||
LLAssetID animationAssetId = mTransactionID.makeAssetID(gAgent.getSecureSessionID());
|
||||
LLTransactionID mTransactionID;
|
||||
mTransactionID.generate();
|
||||
LLAssetID animationAssetId = mTransactionID.makeAssetID(gAgent.getSecureSessionID());
|
||||
|
||||
if (avatar->registerMotion(animationAssetId, FSPosingMotion::create))
|
||||
sAvatarIdToRegisteredAnimationId[avatar->getID()] = animationAssetId;
|
||||
if (avatar->registerMotion(animationAssetId, FSPosingMotion::create))
|
||||
sAvatarIdToRegisteredAnimationId[avatar->getID()] = animationAssetId;
|
||||
|
||||
return dynamic_cast<FSPosingMotion*>(avatar->createMotion(animationAssetId));
|
||||
}
|
||||
return dynamic_cast<FSPosingMotion*>(avatar->createMotion(animationAssetId));
|
||||
|
||||
return motion;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::isAvatarSafeToUse(LLVOAvatar* avatar) const
|
||||
|
|
|
|||
|
|
@ -56,6 +56,15 @@ typedef enum E_BoneDeflectionStyles
|
|||
DELTAMODE = 3, // each selected joint changes by the same supplied amount relative to their current
|
||||
} E_BoneDeflectionStyles;
|
||||
|
||||
/// <summary>
|
||||
/// When getting the rotation of a joint, we can apply different considerations to the rotation.
|
||||
/// </summary>
|
||||
typedef enum E_BoneRotationType
|
||||
{
|
||||
CURRENTROTATION = 0, // the current rotation the joint has
|
||||
TARGETROTATION = 1, // the rotation the we want to achieve
|
||||
} E_BoneRotationType;
|
||||
|
||||
/// <summary>
|
||||
/// When we're going from bone-rotation to the UI sliders, some of the axes need swapping so they make sense in UI-terms.
|
||||
/// eg: for one bone, the X-axis may mean up and down, but for another bone, the x-axis might be left-right.
|
||||
|
|
@ -435,10 +444,9 @@ public:
|
|||
/// <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="forRecapture">Get the current non-poser rotation, for recapture opportunity.</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,
|
||||
bool forRecapture = false) const;
|
||||
LLVector3 getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation, E_BoneRotationType rotType) const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the rotation of a joint for the supplied avatar.
|
||||
|
|
@ -481,6 +489,83 @@ public:
|
|||
/// <param name="avatar">The avatar whose pose should flip left-right.</param>
|
||||
void flipEntirePose(LLVOAvatar* avatar);
|
||||
|
||||
/// <summary>
|
||||
/// Sets all of the joint rotations of the supplied avatar to zero.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose joint rotations should be set to zero.</param>
|
||||
void setAllAvatarStartingRotationsToZero(LLVOAvatar* avatar);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the kind of save to perform should be a 'delta' save, or a complete save.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose pose-rotations are being considered for saving.</param>
|
||||
/// <returns>True if the save should save only 'deltas' to the rotation, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// A save of the rotation 'deltas' facilitates a user saving their changes to an existing animation.
|
||||
/// Thus the save represents 'nothing other than the changes the user made', to some other pose which they may have limited rights to.
|
||||
/// </remarks>
|
||||
bool posingStartedFromZeroRotations(LLVOAvatar* avatar) const;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the rotation, position and scale changes from initial conditions, to save in some export container.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose pose is being considered for saving.</param>
|
||||
/// <param name="joint">The joint we are considering the save for.</param>
|
||||
/// <param name="rot">The quaternion to store the rotation to save in.</param>
|
||||
/// <param name="pos">The vector to store the position to save in.</param>
|
||||
/// <param name="scale">The vector to store the scale to save in.</param>
|
||||
/// <returns>True if the joint should be saved, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// Our objective is to protect peoples novel work: the poses created with this, and poses from other sources, such as in-world.
|
||||
/// In all scenarios, this yeilds 'deltas' of rotation/position/scale.
|
||||
/// The deltas represent the user's novel work, and may be relative to some initial values (as from a pose), or to 'nothing' (such as all rotations == 0, or, the 'T-Pose').
|
||||
/// </remarks>
|
||||
bool tryGetJointSaveVectors(LLVOAvatar* avatar, const FSPoserJoint& joint, LLVector3* rot, LLVector3* pos, LLVector3* scale);
|
||||
|
||||
/// <summary>
|
||||
/// Loads a joint rotation for the supplied joint on the supplied avatar.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar to load the rotation for.</param>
|
||||
/// <param name="joint">The joint to load the rotation for.</param>
|
||||
/// <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.
|
||||
/// </remarks>
|
||||
void loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, LLVector3 rotation);
|
||||
|
||||
/// <summary>
|
||||
/// Loads a joint position for the supplied joint on the supplied avatar.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar to load the position for.</param>
|
||||
/// <param name="joint">The joint to load the position for.</param>
|
||||
/// <param name="loadPositionAsDelta">Whether to the supplied position as a delta to the current position, or not.</param>
|
||||
/// <param name="position">The Position to apply to the supplied joint.</param>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// '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);
|
||||
|
||||
/// <summary>
|
||||
/// Loads a joint scale for the supplied joint on the supplied avatar.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar to load the scale for.</param>
|
||||
/// <param name="joint">The joint to load the scale for.</param>
|
||||
/// <param name="loadScaleAsDelta">Whether to the supplied scale as a delta to the current scale, or not.</param>
|
||||
/// <param name="scale">The scale to apply to the supplied joint.</param>
|
||||
/// <remarks>
|
||||
/// A scale is saved as an absolute if the user created the pose from 'scratch' (at present the 'T-Pose').
|
||||
/// Otherwise the scale is saved as a delta.
|
||||
/// The primary purpose is somewhat aesthetic: the numbers inside of a 'pose modification XML' has zeros everywhere.
|
||||
/// A delta-save thus accurately reflects what the user changed, and not what the original creator of the modified pose specified.
|
||||
/// </remarks>
|
||||
void loadJointScale(LLVOAvatar* avatar, const FSPoserJoint* joint, bool loadScaleAsDelta, LLVector3 scale);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// Translates a rotation vector from the UI to a Quaternion for the bone.
|
||||
|
|
|
|||
|
|
@ -249,6 +249,34 @@ bool FSPosingMotion::currentlyPosingJoint(LLJoint* joint)
|
|||
return (state & POSER_JOINT_STATE);
|
||||
}
|
||||
|
||||
bool FSPosingMotion::allStartingRotationsAreZero() const
|
||||
{
|
||||
LLQuaternion zeroQuat;
|
||||
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
|
||||
{
|
||||
if (poserJoint_iter->jointName() == "mPelvis")
|
||||
continue;
|
||||
if (poserJoint_iter->isCollisionVolume())
|
||||
continue;
|
||||
|
||||
LLQuaternion quat = poserJoint_iter->getBeginningRotation();
|
||||
if (quat != zeroQuat)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FSPosingMotion::setAllRotationsToZero()
|
||||
{
|
||||
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
|
||||
{
|
||||
if (poserJoint_iter->isCollisionVolume())
|
||||
continue;
|
||||
|
||||
poserJoint_iter->setRotationsToZero();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t MaximumUndoQueueLength = 20;
|
||||
|
||||
|
|
@ -489,6 +517,8 @@ void FSPosingMotion::FSJointPose::revertCollisionVolume()
|
|||
joint->setScale(mBeginningScale);
|
||||
}
|
||||
|
||||
void FSPosingMotion::FSJointPose::setRotationsToZero() { mBeginningRotation = mTargetRotation = LLQuaternion(); }
|
||||
|
||||
FSPosingMotion::FSJointPose::FSJointPose(LLJoint* joint, bool isCollisionVolume)
|
||||
{
|
||||
mJointState = new LLJointState;
|
||||
|
|
|
|||
|
|
@ -222,6 +222,11 @@ public:
|
|||
/// </summary>
|
||||
void revertCollisionVolume();
|
||||
|
||||
/// <summary>
|
||||
/// Sets all rotations to zero.
|
||||
/// </summary>
|
||||
void setRotationsToZero();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pointer to the jointstate for the joint this represents.
|
||||
/// </summary>
|
||||
|
|
@ -295,6 +300,17 @@ public:
|
|||
/// <returns>The unique, per-session, per-character motion identity.</returns>
|
||||
LLAssetID motionId() const { return mMotionID; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether all starting rotations are zero.
|
||||
/// </summary>
|
||||
/// <returns>True if all starting rotations are zero, otherwise false.</returns>
|
||||
bool allStartingRotationsAreZero() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets all of the non-Collision Volume rotations to zero.
|
||||
/// </summary>
|
||||
void setAllRotationsToZero();
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// The kind of joint state this animation is concerned with changing.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ height="310"
|
|||
layout="topleft"
|
||||
name="floater_poser"
|
||||
title="Avatar and Animesh Poser"
|
||||
width="565">
|
||||
width="403">
|
||||
<string name="icon_category" translate="false">Inv_BodyShape</string>
|
||||
<string name="icon_bone" translate="false"></string>
|
||||
<string name="icon_object" translate="false">Inv_Object</string>
|
||||
|
|
@ -256,7 +256,7 @@ width="565">
|
|||
follows="top|left|right"
|
||||
height="425"
|
||||
layout="topleft"
|
||||
left="7"
|
||||
left="3"
|
||||
border_size="-4"
|
||||
close_time_constant="0.02"
|
||||
open_time_constant="0.02"
|
||||
|
|
@ -273,68 +273,16 @@ width="565">
|
|||
name="regular_controls_layout"
|
||||
height="290"
|
||||
width="607">
|
||||
<panel
|
||||
follows="left|top|bottom"
|
||||
height="302"
|
||||
background_visible="false"
|
||||
layout="topleft"
|
||||
visible="true"
|
||||
mouse_opaque="false"
|
||||
name="avatarSelection_panel"
|
||||
top="0"
|
||||
left="0"
|
||||
width="153">
|
||||
<avatar_list
|
||||
allow_select="true"
|
||||
follows="all"
|
||||
height="383"
|
||||
layout="topleft"
|
||||
multi_select="true"
|
||||
name="avatars_online"
|
||||
keep_one_selected="false"
|
||||
show_permissions_granted="true"
|
||||
width="317" />
|
||||
<scroll_list
|
||||
column_padding="0"
|
||||
draw_heading="true"
|
||||
height="285"
|
||||
can_sort="false"
|
||||
follows="all"
|
||||
layout="topleft"
|
||||
left="1"
|
||||
tool_tip="Select the Avatar or Animesh you want to animate."
|
||||
width="153"
|
||||
multi_select="false"
|
||||
name="avatarSelection_scroll"
|
||||
top="0">
|
||||
<scroll_list.columns
|
||||
label=""
|
||||
name="icon"
|
||||
relative_width="0.0" />
|
||||
<scroll_list.columns
|
||||
label="Select Someone..."
|
||||
name="name"
|
||||
relative_width="1.0" />
|
||||
<scroll_list.columns
|
||||
label="UUID"
|
||||
name="uuid"
|
||||
relative_width="0.0" />
|
||||
<scroll_list.columns
|
||||
label="SaveFileName"
|
||||
name="saveFileName"
|
||||
relative_width="0.0" />
|
||||
</scroll_list>
|
||||
</panel>
|
||||
<panel
|
||||
follows="left"
|
||||
height="290"
|
||||
background_visible="false"
|
||||
layout="topleft"
|
||||
enabled="false"
|
||||
enabled="true"
|
||||
mouse_opaque="false"
|
||||
name="joints_parent_panel"
|
||||
top="0"
|
||||
left_pad="2"
|
||||
left="0"
|
||||
width="235">
|
||||
<tab_container
|
||||
follows="all"
|
||||
|
|
@ -345,7 +293,7 @@ width="565">
|
|||
enabled="true"
|
||||
name="joints_tabs"
|
||||
tab_height="20"
|
||||
tab_width="50"
|
||||
tab_width="55"
|
||||
tab_group="1"
|
||||
tab_position="left"
|
||||
top="0"
|
||||
|
|
@ -545,6 +493,38 @@ width="565">
|
|||
tab_position="top"
|
||||
top="0"
|
||||
width="235">
|
||||
<panel
|
||||
follows="all"
|
||||
background_visible="false"
|
||||
height="299"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
title="Adjust"
|
||||
name="hands_joints_panel"
|
||||
top="0"
|
||||
width="481">
|
||||
<scroll_list
|
||||
column_padding="2"
|
||||
draw_heading="true"
|
||||
height="300"
|
||||
follows="all"
|
||||
can_sort="false"
|
||||
layout="topleft"
|
||||
left="2"
|
||||
width="479"
|
||||
multi_select="true"
|
||||
name="hand_joints_scroll"
|
||||
top="0">
|
||||
<scroll_list.columns
|
||||
label=""
|
||||
name="icon"
|
||||
relative_width="0.1" />
|
||||
<scroll_list.columns
|
||||
label="Body Part"
|
||||
name="joint"
|
||||
relative_width="0.9" />
|
||||
</scroll_list>
|
||||
</panel>
|
||||
<panel
|
||||
follows="all"
|
||||
background_visible="false"
|
||||
|
|
@ -600,38 +580,6 @@ width="565">
|
|||
function="Poser.LoadRightHand"/>
|
||||
</button>
|
||||
</panel>
|
||||
<panel
|
||||
follows="all"
|
||||
background_visible="false"
|
||||
height="299"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
title="Adjust"
|
||||
name="hands_joints_panel"
|
||||
top="0"
|
||||
width="481">
|
||||
<scroll_list
|
||||
column_padding="2"
|
||||
draw_heading="true"
|
||||
height="300"
|
||||
follows="all"
|
||||
can_sort="false"
|
||||
layout="topleft"
|
||||
left="2"
|
||||
width="479"
|
||||
multi_select="true"
|
||||
name="hand_joints_scroll"
|
||||
top="0">
|
||||
<scroll_list.columns
|
||||
label=""
|
||||
name="icon"
|
||||
relative_width="0.1" />
|
||||
<scroll_list.columns
|
||||
label="Body Part"
|
||||
name="joint"
|
||||
relative_width="0.9" />
|
||||
</scroll_list>
|
||||
</panel>
|
||||
</tab_container>
|
||||
<panel
|
||||
follows="all"
|
||||
|
|
@ -697,6 +645,157 @@ width="565">
|
|||
relative_width="0.9" />
|
||||
</scroll_list>
|
||||
</panel>
|
||||
<panel
|
||||
follows="left|top|bottom"
|
||||
height="302"
|
||||
background_visible="false"
|
||||
layout="topleft"
|
||||
visible="true"
|
||||
title="Posee"
|
||||
mouse_opaque="false"
|
||||
name="avatarSelection_panel"
|
||||
top="0"
|
||||
left="0"
|
||||
width="153">
|
||||
<avatar_list
|
||||
allow_select="true"
|
||||
follows="all"
|
||||
height="150"
|
||||
layout="topleft"
|
||||
multi_select="true"
|
||||
name="avatars_online"
|
||||
keep_one_selected="false"
|
||||
show_permissions_granted="true"
|
||||
width="317" />
|
||||
<scroll_list
|
||||
column_padding="0"
|
||||
draw_heading="true"
|
||||
height="160"
|
||||
can_sort="false"
|
||||
follows="all"
|
||||
layout="topleft"
|
||||
left="3"
|
||||
tool_tip="Select the Avatar or Animesh you want to animate."
|
||||
width="151"
|
||||
multi_select="false"
|
||||
name="avatarSelection_scroll"
|
||||
top="0">
|
||||
<scroll_list.columns
|
||||
label=""
|
||||
name="icon"
|
||||
relative_width="0.0" />
|
||||
<scroll_list.columns
|
||||
label="Select Someone to Pose..."
|
||||
name="name"
|
||||
relative_width="1.0" />
|
||||
<scroll_list.columns
|
||||
label="UUID"
|
||||
name="uuid"
|
||||
relative_width="0.0" />
|
||||
<scroll_list.columns
|
||||
label="SaveFileName"
|
||||
name="saveFileName"
|
||||
relative_width="0.0" />
|
||||
</scroll_list>
|
||||
<button
|
||||
height="21"
|
||||
follows="top|left"
|
||||
layout="topleft"
|
||||
label=""
|
||||
image_overlay="Refresh_Off"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
name="refresh_avatars"
|
||||
tool_tip="Refresh the list of avatars and animeshes"
|
||||
width="20"
|
||||
top="142"
|
||||
left="3">
|
||||
<button.commit_callback
|
||||
function="Poser.RefreshAvatars"/>
|
||||
</button>
|
||||
<button
|
||||
height="21"
|
||||
follows="top|left"
|
||||
enabled="false"
|
||||
is_toggle="true"
|
||||
label="Start Posing"
|
||||
top_delta="0"
|
||||
left_pad="2"
|
||||
label_selected="Stop Posing"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
button_flash_enable="true"
|
||||
flash_color="0.7 0.7 1 1"
|
||||
button_flash_count="64"
|
||||
button_flash_rate="0.5"
|
||||
tool_tip="Start posing the selected avatar or animesh, if you are allowed to"
|
||||
name="start_stop_posing_button"
|
||||
width="150">
|
||||
<button.commit_callback
|
||||
function="Poser.StartStopAnimating"/>
|
||||
</button>
|
||||
<button
|
||||
height="21"
|
||||
follows="top|left"
|
||||
layout="topleft"
|
||||
left="3"
|
||||
top_pad="1"
|
||||
label="Set to T-Pose"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
name="set_t_pose_button"
|
||||
tool_tip="Double-click to set the selected avatar to a 'T-Pose'"
|
||||
width="172">
|
||||
<button.commit_callback
|
||||
function="Poser.SetToTPose"/>
|
||||
</button>
|
||||
</panel>
|
||||
<panel
|
||||
follows="all"
|
||||
background_visible="false"
|
||||
height="299"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
title="Settings"
|
||||
name="settings_panel"
|
||||
top="0"
|
||||
width="481">
|
||||
<text follows="left|top"
|
||||
name="limb_pitch_label"
|
||||
height="10"
|
||||
layout="topleft"
|
||||
left_delta="3"
|
||||
top_pad="2"
|
||||
width="200">Trackpad Sensitivity:</text>
|
||||
<slider
|
||||
decimal_digits="2"
|
||||
can_edit_text="true"
|
||||
follows="left|top"
|
||||
height="14"
|
||||
increment="0.01"
|
||||
initial_value="0"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
max_val="2"
|
||||
min_val="0.01"
|
||||
name="trackpad_sensitivity_slider"
|
||||
tool_tip="Adjusts the sensitivity of the trackball"
|
||||
top_pad="3"
|
||||
logarithmic="1"
|
||||
width="170" >
|
||||
<slider.commit_callback
|
||||
function="Poser.AdjustTrackPadSensitivity"
|
||||
parameter="2"/>
|
||||
</slider>
|
||||
<check_box
|
||||
name="stop_posing_on_close_checkbox"
|
||||
height="16"
|
||||
label="Stop posing when closed"
|
||||
follows="left|top"
|
||||
left="5"
|
||||
tool_tip="Not stopping you pose can be helpful if you do a lot of work, and don't want to accidentally lose it."
|
||||
top_pad="5"
|
||||
width="134" />
|
||||
</panel>
|
||||
</tab_container>
|
||||
</panel>
|
||||
<panel
|
||||
|
|
@ -961,43 +1060,6 @@ width="565">
|
|||
left="0"
|
||||
name="button_controls_panel"
|
||||
width="800">
|
||||
<button
|
||||
height="21"
|
||||
follows="top|left"
|
||||
layout="topleft"
|
||||
label=""
|
||||
image_overlay="Refresh_Off"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
name="refresh_avatars"
|
||||
tool_tip="Refresh the list of avatars and animeshes"
|
||||
width="20"
|
||||
top_pad="-1"
|
||||
left="2">
|
||||
<button.commit_callback
|
||||
function="Poser.RefreshAvatars"/>
|
||||
</button>
|
||||
<button
|
||||
height="21"
|
||||
follows="top|left"
|
||||
enabled="false"
|
||||
is_toggle="true"
|
||||
label="Start Posing"
|
||||
top_delta="0"
|
||||
left_pad="2"
|
||||
label_selected="Stop Posing"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
button_flash_enable="true"
|
||||
flash_color="0.7 0.7 1 1"
|
||||
button_flash_count="64"
|
||||
button_flash_rate="0.5"
|
||||
tool_tip="Start posing the selected avatar or animesh, if you are allowed to"
|
||||
name="start_stop_posing_button"
|
||||
width="108">
|
||||
<button.commit_callback
|
||||
function="Poser.StartStopAnimating"/>
|
||||
</button>
|
||||
<button
|
||||
height="21"
|
||||
follows="top|left"
|
||||
|
|
@ -1012,7 +1074,8 @@ width="565">
|
|||
name="toggleAdvancedPanel"
|
||||
tool_tip="Toggle the Advanced Settings area"
|
||||
width="20"
|
||||
left_pad="2">
|
||||
top_pad="-1"
|
||||
left="2">
|
||||
<button.commit_callback
|
||||
function="Poser.ToggleAdvancedPanel"/>
|
||||
</button>
|
||||
|
|
@ -1025,8 +1088,8 @@ width="565">
|
|||
mouse_opaque="false"
|
||||
left_pad="0"
|
||||
top_delta="0"
|
||||
name="advbutton_spacer_panel"
|
||||
width="54"/>
|
||||
name="button_spacer_panel"
|
||||
width="36"/>
|
||||
<button
|
||||
height="21"
|
||||
follows="top|left"
|
||||
|
|
@ -1037,7 +1100,7 @@ width="565">
|
|||
image_unselected="Toolbar_Middle_Off"
|
||||
name="FlipPose_avatar"
|
||||
tool_tip="Flip the whole pose left/right"
|
||||
width="23"
|
||||
width="21"
|
||||
top_delta="0"
|
||||
left_pad="1">
|
||||
<button.commit_callback
|
||||
|
|
@ -1049,11 +1112,11 @@ width="565">
|
|||
layout="topleft"
|
||||
enabled="false"
|
||||
label=""
|
||||
image_overlay="Sync_Progress_1"
|
||||
image_overlay="Edit_Flip_X"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
name="FlipJoint_avatar"
|
||||
tool_tip="Mirror the selected body part(s) left/right"
|
||||
width="23"
|
||||
width="21"
|
||||
top_delta="0"
|
||||
left_pad="1">
|
||||
<button.commit_callback
|
||||
|
|
@ -1089,7 +1152,7 @@ width="565">
|
|||
left_pad="1"
|
||||
top_delta="0"
|
||||
tool_tip="Turn the Poser on or off for the selected body part(s). When off, that body part animates like normal (with your AO or a pose-ball/etc.)"
|
||||
width="85" >
|
||||
width="84" >
|
||||
<button.commit_callback
|
||||
function="Poser.TogglePosingSelectedBones"/>
|
||||
</button>
|
||||
|
|
@ -1103,7 +1166,7 @@ width="565">
|
|||
left_pad="0"
|
||||
top_delta="0"
|
||||
name="button_spacer_panel"
|
||||
width="60"/>
|
||||
width="58"/>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="21"
|
||||
|
|
@ -1172,10 +1235,10 @@ width="565">
|
|||
height="21"
|
||||
follows="top|left"
|
||||
layout="topleft"
|
||||
label="Save Pose"
|
||||
label="Save Diff"
|
||||
enabled="false"
|
||||
visible="false"
|
||||
tool_tip="Save the current pose."
|
||||
tool_tip="A Diff is just your changes to an existing Pose. Start from a T-Pose to save a new work"
|
||||
image_overlay="Icon_Dock_Foreground"
|
||||
image_overlay_alignment="left"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
|
|
@ -1246,7 +1309,7 @@ width="565">
|
|||
min_val="-0.5"
|
||||
name="Advanced_Position_X"
|
||||
top_pad="6"
|
||||
width="530" >
|
||||
width="380" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.PositionSet"
|
||||
parameter="0"/>
|
||||
|
|
@ -1266,7 +1329,7 @@ width="565">
|
|||
min_val="-0.5"
|
||||
name="Advanced_Position_Y"
|
||||
top_pad="1"
|
||||
width="530" >
|
||||
width="380" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.PositionSet"
|
||||
parameter="1"/>
|
||||
|
|
@ -1286,7 +1349,7 @@ width="565">
|
|||
min_val="-0.5"
|
||||
name="Advanced_Position_Z"
|
||||
top_pad="1"
|
||||
width="530" >
|
||||
width="380" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.PositionSet"
|
||||
parameter="2"/>
|
||||
|
|
@ -1331,7 +1394,7 @@ width="565">
|
|||
image_overlay="Inv_TrashOpen"
|
||||
image_overlay_alignment="left"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
name="reset_positions"
|
||||
name="undo_position_change"
|
||||
tool_tip="Double click to reset position back to original"
|
||||
width="110"
|
||||
top_delta="0"
|
||||
|
|
@ -1365,7 +1428,7 @@ width="565">
|
|||
min_val="0"
|
||||
name="Advanced_Scale_X"
|
||||
top_pad="6"
|
||||
width="530" >
|
||||
width="380" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.ScaleSet"
|
||||
parameter="0"/>
|
||||
|
|
@ -1385,7 +1448,7 @@ width="565">
|
|||
min_val="0"
|
||||
name="Advanced_Scale_Y"
|
||||
top_pad="1"
|
||||
width="530" >
|
||||
width="380" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.ScaleSet"
|
||||
parameter="1"/>
|
||||
|
|
@ -1405,7 +1468,7 @@ width="565">
|
|||
min_val="0"
|
||||
name="Advanced_Scale_Z"
|
||||
top_pad="1"
|
||||
width="530" >
|
||||
width="380" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.ScaleSet"
|
||||
parameter="2"/>
|
||||
|
|
@ -1418,7 +1481,7 @@ width="565">
|
|||
image_overlay="Script_Undo"
|
||||
image_overlay_alignment="left"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
name="undo_scale_change"
|
||||
name="undo_position_change"
|
||||
tool_tip="Undo the last scale change"
|
||||
width="150"
|
||||
top_pad="2"
|
||||
|
|
@ -1450,7 +1513,7 @@ width="565">
|
|||
image_overlay="Inv_TrashOpen"
|
||||
image_overlay_alignment="left"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
name="reset_scales"
|
||||
name="undo_scale_change"
|
||||
tool_tip="Double click to reset scale back to original"
|
||||
width="110"
|
||||
top_delta="0"
|
||||
|
|
@ -1461,39 +1524,6 @@ width="565">
|
|||
</panel>
|
||||
</tab_container>
|
||||
</panel>
|
||||
<panel
|
||||
follows="left|top"
|
||||
height="100"
|
||||
background_visible="false"
|
||||
layout="topleft"
|
||||
visible="false"
|
||||
enabled="true"
|
||||
mouse_opaque="false"
|
||||
name="save_file_options"
|
||||
left_pad="2"
|
||||
width="235">
|
||||
<slider
|
||||
decimal_digits="2"
|
||||
can_edit_text="true"
|
||||
follows="left|top"
|
||||
height="14"
|
||||
increment="0.01"
|
||||
initial_value="0"
|
||||
label="Sensitivity"
|
||||
label_width="70"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
max_val="2"
|
||||
min_val="0.0001"
|
||||
name="trackpad_sensitivity_slider"
|
||||
tool_tip="Adjusts the sensitivity of the trackball"
|
||||
top_pad="1"
|
||||
width="200" >
|
||||
<slider.commit_callback
|
||||
function="Poser.AdjustTrackPadSensitivity"
|
||||
parameter="2"/>
|
||||
</slider>
|
||||
</panel>
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</floater>
|
||||
|
|
|
|||
Loading…
Reference in New Issue