parent
c4f67ee0ba
commit
fc0c595051
|
|
@ -48,6 +48,7 @@ static const std::string POSE_INTERNAL_FORMAT_FILE_MASK = "*.xml";
|
|||
static const std::string POSE_INTERNAL_FORMAT_FILE_EXT = ".xml";
|
||||
static const std::string POSE_EXTERNAL_FORMAT_FILE_EXT = ".bvh";
|
||||
static const std::string POSE_SAVE_SUBDIRECTORY = "poses";
|
||||
static const std::string POSE_PRESETS_HANDS_SUBDIRECTORY = "poses\\hand_presets";
|
||||
static const std::string XML_LIST_HEADER_STRING_PREFIX = "header_";
|
||||
static const std::string XML_LIST_TITLE_STRING_PREFIX = "title_";
|
||||
static const std::string XML_JOINT_TRANSFORM_STRING_PREFIX = "joint_transform_";
|
||||
|
|
@ -62,7 +63,8 @@ static const std::string POSER_AVATAR_TABGROUP_JOINTS = "joints_tabs";
|
|||
static const std::string POSER_AVATAR_TAB_POSITION = "positionRotation_panel";
|
||||
static const std::string POSER_AVATAR_TAB_BODY = "body_joints_panel";
|
||||
static const std::string POSER_AVATAR_TAB_FACE = "face_joints_panel";
|
||||
static const std::string POSER_AVATAR_TAB_HANDS = "hands_joints_panel";
|
||||
static const std::string POSER_AVATAR_TAB_HANDS = "hands_tabs";
|
||||
static const std::string POSER_AVATAR_TAB_HANDJOINTS = "hands_joints_panel";
|
||||
static const std::string POSER_AVATAR_TAB_MISC = "misc_joints_panel";
|
||||
static const std::string POSER_AVATAR_TAB_VOLUMES = "collision_volumes_panel";
|
||||
|
||||
|
|
@ -116,6 +118,7 @@ static const std::string POSER_AVATAR_SCROLLLIST_FACEJOINTS_NAME = "face_joi
|
|||
static const std::string POSER_AVATAR_SCROLLLIST_HANDJOINTS_NAME = "hand_joints_scroll";
|
||||
static const std::string POSER_AVATAR_SCROLLLIST_MISCJOINTS_NAME = "misc_joints_scroll";
|
||||
static const std::string POSER_AVATAR_SCROLLLIST_VOLUMES_NAME = "collision_volumes_scroll";
|
||||
static const std::string POSER_AVATAR_SCROLLLIST_HAND_PRESETS_NAME = "hand_presets_scroll";
|
||||
|
||||
FSFloaterPoser::FSFloaterPoser(const LLSD& key) : LLFloater(key)
|
||||
{
|
||||
|
|
@ -146,6 +149,8 @@ FSFloaterPoser::FSFloaterPoser(const LLSD& key) : LLFloater(key)
|
|||
mCommitCallbackRegistrar.add("Poser.Save", boost::bind(&FSFloaterPoser::onClickPoseSave, this));
|
||||
mCommitCallbackRegistrar.add("Pose.Menu", boost::bind(&FSFloaterPoser::onPoseMenuAction, this, _2));
|
||||
mCommitCallbackRegistrar.add("Poser.BrowseCache", boost::bind(&FSFloaterPoser::onClickBrowsePoseCache, this));
|
||||
mCommitCallbackRegistrar.add("Poser.LoadLeftHand", boost::bind(&FSFloaterPoser::onClickLoadLeftHandPose, this));
|
||||
mCommitCallbackRegistrar.add("Poser.LoadRightHand", boost::bind(&FSFloaterPoser::onClickLoadRightHandPose, this));
|
||||
|
||||
mCommitCallbackRegistrar.add("Poser.FlipPose", boost::bind(&FSFloaterPoser::onClickFlipPose, this));
|
||||
mCommitCallbackRegistrar.add("Poser.FlipJoint", boost::bind(&FSFloaterPoser::onClickFlipSelectedJoints, this));
|
||||
|
|
@ -261,6 +266,7 @@ void FSFloaterPoser::onOpen(const LLSD& key)
|
|||
refreshJointScrollListMembers();
|
||||
onJointSelect();
|
||||
onOpenSetAdvancedPanel();
|
||||
refreshPoseScroll(POSER_AVATAR_SCROLLLIST_HAND_PRESETS_NAME, POSE_PRESETS_HANDS_SUBDIRECTORY);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClose(bool app_quitting)
|
||||
|
|
@ -274,15 +280,18 @@ void FSFloaterPoser::onClose(bool app_quitting)
|
|||
gSavedSettings.setBOOL(POSER_ALSOSAVEBVHFILE_SAVE_KEY, saveBvhCheckbox->getValue());
|
||||
}
|
||||
|
||||
void FSFloaterPoser::refreshPosesScroll()
|
||||
void FSFloaterPoser::refreshPoseScroll(std::string scrollListName, std::string subDirectory)
|
||||
{
|
||||
LLScrollListCtrl *posesScrollList = getChild<LLScrollListCtrl>(POSER_AVATAR_SCROLLLIST_LOADSAVE_NAME);
|
||||
if (scrollListName.empty() || subDirectory.empty())
|
||||
return;
|
||||
|
||||
LLScrollListCtrl* posesScrollList = getChild<LLScrollListCtrl>(scrollListName);
|
||||
if (!posesScrollList)
|
||||
return;
|
||||
|
||||
posesScrollList->clearRows();
|
||||
|
||||
std::string dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "poses");
|
||||
std::string dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, subDirectory);
|
||||
std::string file;
|
||||
LLDirIterator dir_iter(dir, POSE_INTERNAL_FORMAT_FILE_MASK);
|
||||
while (dir_iter.next(file))
|
||||
|
|
@ -367,7 +376,7 @@ void FSFloaterPoser::onClickPoseSave()
|
|||
bool successfulSave = savePoseToXml(avatar, filename);
|
||||
if (successfulSave)
|
||||
{
|
||||
refreshPosesScroll();
|
||||
refreshPoseScroll(POSER_AVATAR_SCROLLLIST_LOADSAVE_NAME, POSE_SAVE_SUBDIRECTORY);
|
||||
setUiSelectedAvatarSaveFileName(filename);
|
||||
// TODO: provide feedback for save
|
||||
|
||||
|
|
@ -682,6 +691,97 @@ void FSFloaterPoser::onPoseMenuAction(const LLSD ¶m)
|
|||
refreshJointScrollListMembers();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickLoadLeftHandPose()
|
||||
{
|
||||
// This is a double-click function: it needs to run twice within some amount of time to complete.
|
||||
auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - _timeLastClickedJointReset;
|
||||
_timeLastClickedJointReset = std::chrono::system_clock::now();
|
||||
if (timeIntervalSinceLastClick > _doubleClickInterval)
|
||||
return;
|
||||
|
||||
onClickLoadHandPose(false);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickLoadRightHandPose()
|
||||
{
|
||||
// This is a double-click function: it needs to run twice within some amount of time to complete.
|
||||
auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - _timeLastClickedJointReset;
|
||||
_timeLastClickedJointReset = std::chrono::system_clock::now();
|
||||
if (timeIntervalSinceLastClick > _doubleClickInterval)
|
||||
return;
|
||||
|
||||
onClickLoadHandPose(true);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickLoadHandPose(bool isRightHand)
|
||||
{
|
||||
LLScrollListCtrl* handPosesScrollList = getChild<LLScrollListCtrl>(POSER_AVATAR_SCROLLLIST_HAND_PRESETS_NAME);
|
||||
if (!handPosesScrollList)
|
||||
return;
|
||||
|
||||
LLScrollListItem* item = handPosesScrollList->getFirstSelected();
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
std::string poseName = item->getColumn(0)->getValue().asString();
|
||||
std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_PRESETS_HANDS_SUBDIRECTORY);
|
||||
if (!gDirUtilp->fileExists(pathname))
|
||||
return;
|
||||
|
||||
std::string fullPath =
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_PRESETS_HANDS_SUBDIRECTORY, poseName + POSE_INTERNAL_FORMAT_FILE_EXT);
|
||||
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if (!avatar)
|
||||
return;
|
||||
if (!_poserAnimator.isPosingAvatar(avatar))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
LLSD pose;
|
||||
llifstream infile;
|
||||
LLVector3 vec3;
|
||||
|
||||
infile.open(fullPath);
|
||||
if (!infile.is_open())
|
||||
return;
|
||||
|
||||
while (!infile.eof())
|
||||
{
|
||||
S32 lineCount = LLSDSerialize::fromXML(pose, infile);
|
||||
if (lineCount == LLSDParser::PARSE_FAILURE)
|
||||
{
|
||||
LL_WARNS("Posing") << "Failed to parse loading a file for a hand: " << poseName << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
for (LLSD::map_const_iterator itr = pose.beginMap(); itr != pose.endMap(); ++itr)
|
||||
{
|
||||
std::string const& name = itr->first;
|
||||
LLSD const& control_map = itr->second;
|
||||
|
||||
if (name.find("Hand") == std::string::npos)
|
||||
continue;
|
||||
if (isRightHand != (name.find("Left") == std::string::npos))
|
||||
continue;
|
||||
|
||||
const FSPoserAnimator::FSPoserJoint* poserJoint = _poserAnimator.getPoserJointByName(name);
|
||||
if (!poserJoint)
|
||||
continue;
|
||||
|
||||
vec3.setValue(control_map["rotation"]);
|
||||
_poserAnimator.setJointRotation(avatar, poserJoint, vec3, NONE, SWAP_NOTHING, NEGATE_NOTHING);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LL_WARNS("Posing") << "Threw an exception trying to load a hand pose: " << poseName << LL_ENDL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, std::string poseFileName, E_LoadPoseMethods loadMethod)
|
||||
{
|
||||
std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY);
|
||||
|
|
@ -698,8 +798,9 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, std::string poseFileNam
|
|||
loadMethod == ROT_POS_AND_SCALES;
|
||||
bool loadPositions = loadMethod == POSITIONS || loadMethod == ROTATIONS_AND_POSITIONS || loadMethod == POSITIONS_AND_SCALES ||
|
||||
loadMethod == ROT_POS_AND_SCALES;
|
||||
bool loadScales = loadMethod == SCALES || loadMethod == POSITIONS_AND_SCALES || loadMethod == ROTATIONS_AND_SCALES ||
|
||||
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
|
||||
{
|
||||
|
|
@ -726,10 +827,21 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, std::string poseFileNam
|
|||
std::string const &name = itr->first;
|
||||
LLSD const &control_map = itr->second;
|
||||
|
||||
if (loadHandsOnly && name.find("Hand") == std::string::npos)
|
||||
continue;
|
||||
|
||||
const FSPoserAnimator::FSPoserJoint *poserJoint = _poserAnimator.getPoserJointByName(name);
|
||||
if (!poserJoint)
|
||||
continue;
|
||||
|
||||
if (loadHandsOnly && control_map.has("rotation"))
|
||||
{
|
||||
vec3.setValue(control_map["rotation"]);
|
||||
|
||||
_poserAnimator.setJointRotation(avatar, poserJoint, vec3, NONE, SWAP_NOTHING, NEGATE_NOTHING);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (loadRotations && control_map.has("rotation"))
|
||||
{
|
||||
vec3.setValue(control_map["rotation"]);
|
||||
|
|
@ -1016,7 +1128,7 @@ void FSFloaterPoser::onToggleLoadSavePanel()
|
|||
this->reshape(poserFloaterWidth, poserFloaterHeight);
|
||||
|
||||
if (loadSavePanelExpanded)
|
||||
refreshPosesScroll();
|
||||
refreshPoseScroll(POSER_AVATAR_SCROLLLIST_LOADSAVE_NAME, POSE_SAVE_SUBDIRECTORY);
|
||||
|
||||
showOrHideAdvancedSaveOptions();
|
||||
}
|
||||
|
|
@ -1067,6 +1179,8 @@ void FSFloaterPoser::setRotationChangeButtons(bool togglingMirror, bool toggling
|
|||
|
||||
if (togglingMirror || togglingSympathetic)
|
||||
deltaModeToggleButton->setValue(false);
|
||||
|
||||
refreshTrackpadCursor();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onUndoLastRotation()
|
||||
|
|
@ -1346,11 +1460,11 @@ std::vector<FSPoserAnimator::FSPoserJoint *> FSFloaterPoser::getUiSelectedPoserJ
|
|||
{
|
||||
std::vector<FSPoserAnimator::FSPoserJoint *> joints;
|
||||
|
||||
LLTabContainer *jointTabGroup = getChild<LLTabContainer>(POSER_AVATAR_TABGROUP_JOINTS);
|
||||
if (!jointTabGroup)
|
||||
LLTabContainer *tabGroup = getChild<LLTabContainer>(POSER_AVATAR_TABGROUP_JOINTS);
|
||||
if (!tabGroup)
|
||||
return joints;
|
||||
|
||||
std::string activeTabName = jointTabGroup->getCurrentPanel()->getName();
|
||||
std::string activeTabName = tabGroup->getCurrentPanel()->getName();
|
||||
if (activeTabName.empty())
|
||||
return joints;
|
||||
|
||||
|
|
@ -1363,7 +1477,18 @@ std::vector<FSPoserAnimator::FSPoserJoint *> FSFloaterPoser::getUiSelectedPoserJ
|
|||
else if (boost::iequals(activeTabName, POSER_AVATAR_TAB_FACE))
|
||||
scrollListName = POSER_AVATAR_SCROLLLIST_FACEJOINTS_NAME;
|
||||
else if (boost::iequals(activeTabName, POSER_AVATAR_TAB_HANDS))
|
||||
scrollListName = POSER_AVATAR_SCROLLLIST_HANDJOINTS_NAME;
|
||||
{
|
||||
tabGroup = getChild<LLTabContainer>(POSER_AVATAR_TAB_HANDS);
|
||||
if (!tabGroup)
|
||||
return joints;
|
||||
|
||||
activeTabName = tabGroup->getCurrentPanel()->getName();
|
||||
if (activeTabName.empty())
|
||||
return joints;
|
||||
|
||||
if (boost::iequals(activeTabName, POSER_AVATAR_TAB_HANDJOINTS))
|
||||
scrollListName = POSER_AVATAR_SCROLLLIST_HANDJOINTS_NAME;
|
||||
}
|
||||
else if (boost::iequals(activeTabName, POSER_AVATAR_TAB_MISC))
|
||||
scrollListName = POSER_AVATAR_SCROLLLIST_MISCJOINTS_NAME;
|
||||
else if (boost::iequals(activeTabName, POSER_AVATAR_TAB_VOLUMES))
|
||||
|
|
@ -2018,7 +2143,6 @@ uuid_vec_t FSFloaterPoser::getCurrentlyListedAvatarsAndAnimeshes()
|
|||
|
||||
S32 FSFloaterPoser::getAvatarListIndexForUuid(LLUUID toFind)
|
||||
{
|
||||
|
||||
LLScrollListCtrl* avatarScrollList = getChild<LLScrollListCtrl>(POSER_AVATAR_SCROLLLIST_AVATARSELECTION);
|
||||
if (!avatarScrollList)
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -38,11 +38,14 @@ typedef enum E_LoadPoseMethods
|
|||
{
|
||||
ROTATIONS = 1,
|
||||
POSITIONS = 2,
|
||||
SCALES = 4,
|
||||
ROTATIONS_AND_POSITIONS = 3,
|
||||
ROTATIONS_AND_SCALES = 4,
|
||||
POSITIONS_AND_SCALES = 5,
|
||||
ROT_POS_AND_SCALES = 6
|
||||
SCALES = 3,
|
||||
ROTATIONS_AND_POSITIONS = 4,
|
||||
ROTATIONS_AND_SCALES = 5,
|
||||
POSITIONS_AND_SCALES = 6,
|
||||
ROT_POS_AND_SCALES = 7,
|
||||
HAND_RIGHT = 8,
|
||||
HAND_LEFT = 9,
|
||||
FACE_ONLY = 10,
|
||||
} E_LoadPoseMethods;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -79,9 +82,9 @@ class FSFloaterPoser : public LLFloater
|
|||
const F32 normalTrackpadRangeInRads = F_PI;
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the pose load/save list.
|
||||
/// Refreshes the supplied pose list from the supplued subdirectory.
|
||||
/// </summary>
|
||||
void refreshPosesScroll();
|
||||
void refreshPoseScroll(std::string scrollListName, std::string subDirectory);
|
||||
|
||||
/// <summary>
|
||||
/// (Dis)Enables all of the posing controls; such as when you can't pose for reasons.
|
||||
|
|
@ -227,6 +230,9 @@ class FSFloaterPoser : public LLFloater
|
|||
void onPoseJointsReset();
|
||||
void onOpenSetAdvancedPanel();
|
||||
void onAdjustTrackpadSensitivity();
|
||||
void onClickLoadLeftHandPose();
|
||||
void onClickLoadRightHandPose();
|
||||
void onClickLoadHandPose(bool isRightHand);
|
||||
|
||||
// UI Refreshments
|
||||
void refreshRotationSliders();
|
||||
|
|
|
|||
|
|
@ -521,38 +521,109 @@ width="565">
|
|||
relative_width="0.9" />
|
||||
</scroll_list>
|
||||
</panel>
|
||||
<panel
|
||||
<tab_container
|
||||
follows="all"
|
||||
background_visible="false"
|
||||
height="299"
|
||||
halign="center"
|
||||
height="285"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
enabled="true"
|
||||
title="Hands"
|
||||
name="hands_joints_panel"
|
||||
name="hands_tabs"
|
||||
tab_height="20"
|
||||
tab_width="50"
|
||||
tab_group="1"
|
||||
tab_position="top"
|
||||
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>
|
||||
width="235">
|
||||
<panel
|
||||
follows="all"
|
||||
background_visible="false"
|
||||
height="299"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
title="Presets"
|
||||
name="hands_presets_panel"
|
||||
top="0"
|
||||
width="481">
|
||||
<scroll_list
|
||||
column_padding="2"
|
||||
draw_heading="true"
|
||||
height="275"
|
||||
follows="all"
|
||||
can_sort="false"
|
||||
layout="topleft"
|
||||
left="2"
|
||||
width="479"
|
||||
multi_select="false"
|
||||
name="hand_presets_scroll"
|
||||
top="0">
|
||||
<scroll_list.columns
|
||||
label="Preset Name"
|
||||
name="name"
|
||||
relative_width="0.9" />
|
||||
</scroll_list>
|
||||
<button
|
||||
follows="top|left"
|
||||
height="21"
|
||||
layout="topleft"
|
||||
label="Set Left"
|
||||
name="button_loadHandPoseLeft"
|
||||
tool_tip="Double click to set your left hand to the selected preset"
|
||||
top_delta="238"
|
||||
left_pad="1"
|
||||
left="2"
|
||||
width="88" >
|
||||
<button.commit_callback
|
||||
function="Poser.LoadLeftHand"/>
|
||||
</button>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="21"
|
||||
layout="topleft"
|
||||
label="Set Right"
|
||||
name="button_loadHandPoseRight"
|
||||
tool_tip="Double click to set your right hand to the selected preset"
|
||||
left_pad="1"
|
||||
top_delta="0"
|
||||
width="88" >
|
||||
<button.commit_callback
|
||||
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"
|
||||
background_visible="false"
|
||||
|
|
|
|||
Loading…
Reference in New Issue