FIRE-30873: First pass at BVH saving
parent
1f834f06bd
commit
3a7878fe2b
|
|
@ -8056,6 +8056,17 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSPoserSaveBvhFileAlso</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether to save a BVH file as well when saving a pose.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>MeshUploadLogXML</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -42,14 +42,17 @@
|
|||
#include "llscrolllistctrl.h"
|
||||
#include "llsliderctrl.h"
|
||||
#include "lltabcontainer.h"
|
||||
#include "llcheckboxctrl.h"
|
||||
|
||||
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 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_";
|
||||
static const std::string POSER_ADVANCEDWINDOWSTATE_SAVE_KEY = "FSPoserAdvancedWindowState";
|
||||
static const std::string POSER_ALSOSAVEBVHFILE_SAVE_KEY = "FSPoserSaveBvhFileAlso";
|
||||
|
||||
static const std::string POSER_AVATAR_PANEL_JOINTSPARENT = "joints_parent_panel";
|
||||
static const std::string POSER_AVATAR_PANEL_TRACKBALL = "trackball_panel";
|
||||
|
|
@ -86,6 +89,8 @@ static const std::string POSER_AVATAR_ADV_SLIDER_SCALEX_NAME = "Advanced_Scale_X
|
|||
static const std::string POSER_AVATAR_ADV_SLIDER_SCALEY_NAME = "Advanced_Scale_Y";
|
||||
static const std::string POSER_AVATAR_ADV_SLIDER_SCALEZ_NAME = "Advanced_Scale_Z";
|
||||
static const std::string POSER_AVATAR_ADV_BUTTON_NAME = "start_stop_posing_button";
|
||||
static const std::string POSER_AVATAR_ADVANCED_SAVEOPTIONSPANEL_NAME = "save_file_options";
|
||||
static const std::string POSER_AVATAR_ADVANCED_SAVEBVHCHECKBOX_NAME = "also_save_bvh_checkbox";
|
||||
|
||||
static const std::string POSER_AVATAR_SCROLLLIST_AVATARSELECTION = "avatarSelection_scroll";
|
||||
static const std::string POSER_AVATAR_STARTSTOP_POSING_BUTTON_NAME = "start_stop_posing_button";
|
||||
|
|
@ -221,6 +226,14 @@ bool FSFloaterPoser::postBuild()
|
|||
advancedButton->setValue(true);
|
||||
}
|
||||
|
||||
bool saveBvhCheckboxState = gSavedSettings.getBOOL(POSER_ALSOSAVEBVHFILE_SAVE_KEY);
|
||||
if (saveBvhCheckboxState)
|
||||
{
|
||||
LLCheckBoxCtrl* saveBvhCheckbox = getChild<LLCheckBoxCtrl>(POSER_AVATAR_ADVANCED_SAVEBVHCHECKBOX_NAME);
|
||||
if (saveBvhCheckbox)
|
||||
saveBvhCheckbox->set(true);
|
||||
}
|
||||
|
||||
LLLineEditor *poseSaveName = getChild<LLLineEditor>(POSER_AVATAR_LINEEDIT_FILESAVENAME);
|
||||
if (poseSaveName)
|
||||
poseSaveName->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
|
||||
|
|
@ -246,6 +259,10 @@ void FSFloaterPoser::onClose(bool app_quitting)
|
|||
LLButton *advancedButton = getChild<LLButton>(POSER_AVATAR_ADVANCED_TOGGLEBUTTON_NAME);
|
||||
if (advancedButton)
|
||||
gSavedSettings.setBOOL(POSER_ADVANCEDWINDOWSTATE_SAVE_KEY, advancedButton->getValue().asBoolean());
|
||||
|
||||
LLCheckBoxCtrl* saveBvhCheckbox = getChild<LLCheckBoxCtrl>(POSER_AVATAR_ADVANCED_SAVEBVHCHECKBOX_NAME);
|
||||
if (saveBvhCheckbox)
|
||||
gSavedSettings.setBOOL(POSER_ALSOSAVEBVHFILE_SAVE_KEY, saveBvhCheckbox->getValue());
|
||||
}
|
||||
|
||||
void FSFloaterPoser::refreshPosesScroll()
|
||||
|
|
@ -344,9 +361,59 @@ void FSFloaterPoser::onClickPoseSave()
|
|||
refreshPosesScroll();
|
||||
setUiSelectedAvatarSaveFileName(filename);
|
||||
// TODO: provide feedback for save
|
||||
|
||||
LLCheckBoxCtrl* saveBvhCheckbox = getChild<LLCheckBoxCtrl>(POSER_AVATAR_ADVANCED_SAVEBVHCHECKBOX_NAME);
|
||||
if (!saveBvhCheckbox)
|
||||
return;
|
||||
|
||||
bool alsoSaveAsBvh = saveBvhCheckbox->getValue().asBoolean();
|
||||
if (alsoSaveAsBvh)
|
||||
savePoseToBvh(avatar, filename);
|
||||
}
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::savePoseToBvh(LLVOAvatar* avatar, std::string poseFileName)
|
||||
{
|
||||
if (poseFileName.empty())
|
||||
return false;
|
||||
|
||||
if (!_poserAnimator.isPosingAvatar(avatar))
|
||||
return false;
|
||||
|
||||
bool writeSuccess = false;
|
||||
|
||||
try
|
||||
{
|
||||
std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY);
|
||||
if (!gDirUtilp->fileExists(pathname))
|
||||
{
|
||||
LL_WARNS("Poser") << "Couldn't find folder: " << pathname << " - creating one." << LL_ENDL;
|
||||
LLFile::mkdir(pathname);
|
||||
}
|
||||
|
||||
std::string fullSavePath =
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY, poseFileName + POSE_EXTERNAL_FORMAT_FILE_EXT);
|
||||
|
||||
llofstream file;
|
||||
file.open(fullSavePath.c_str());
|
||||
if (!file.is_open())
|
||||
{
|
||||
LL_WARNS("Poser") << "Unable to save pose!" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
writeSuccess = _poserAnimator.writePoseAsBvh(&file, avatar);
|
||||
|
||||
file.close();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::savePoseToXml(LLVOAvatar* avatar, std::string poseFileName)
|
||||
{
|
||||
if (poseFileName.empty())
|
||||
|
|
@ -360,7 +427,7 @@ bool FSFloaterPoser::savePoseToXml(LLVOAvatar* avatar, std::string poseFileName)
|
|||
std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY);
|
||||
if (!gDirUtilp->fileExists(pathname))
|
||||
{
|
||||
LL_WARNS("Posing") << "Couldn't find folder: " << pathname << " - creating one." << LL_ENDL;
|
||||
LL_WARNS("Poser") << "Couldn't find folder: " << pathname << " - creating one." << LL_ENDL;
|
||||
LLFile::mkdir(pathname);
|
||||
}
|
||||
|
||||
|
|
@ -393,7 +460,7 @@ bool FSFloaterPoser::savePoseToXml(LLVOAvatar* avatar, std::string poseFileName)
|
|||
file.open(fullSavePath.c_str());
|
||||
if (!file.is_open())
|
||||
{
|
||||
LL_WARNS("GroupMute") << "Unable to save pose!" << LL_ENDL;
|
||||
LL_WARNS("Poser") << "Unable to save pose!" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
LLSDSerialize::toPrettyXML(record, file);
|
||||
|
|
@ -935,6 +1002,28 @@ void FSFloaterPoser::onToggleLoadSavePanel()
|
|||
|
||||
if (loadSavePanelExpanded)
|
||||
refreshPosesScroll();
|
||||
|
||||
showOrHideAdvancedSaveOptions();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::showOrHideAdvancedSaveOptions()
|
||||
{
|
||||
LLButton* yourPosesButton = getChild<LLButton>(POSER_AVATAR_TOGGLEBUTTON_LOADSAVE);
|
||||
if (!yourPosesButton)
|
||||
return;
|
||||
|
||||
LLButton* advancedButton = getChild<LLButton>(POSER_AVATAR_ADVANCED_TOGGLEBUTTON_NAME);
|
||||
if (!advancedButton)
|
||||
return;
|
||||
|
||||
LLUICtrl* advSavePanel = getChild<LLUICtrl>(POSER_AVATAR_ADVANCED_SAVEOPTIONSPANEL_NAME);
|
||||
if (!advSavePanel)
|
||||
return;
|
||||
|
||||
bool loadSavePanelExpanded = yourPosesButton->getValue().asBoolean();
|
||||
bool advancedPanelExpanded = advancedButton->getValue().asBoolean();
|
||||
|
||||
advSavePanel->setVisible(loadSavePanelExpanded && advancedPanelExpanded);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onToggleMirrorChange() { setRotationChangeButtons(true, false); }
|
||||
|
|
@ -1238,7 +1327,7 @@ void FSFloaterPoser::onToggleAdvancedPanel()
|
|||
return;
|
||||
|
||||
this->reshape(poserFloaterWidth, poserFloaterHeight);
|
||||
|
||||
showOrHideAdvancedSaveOptions();
|
||||
onJointSelect();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -198,11 +198,13 @@ class FSFloaterPoser : public LLFloater
|
|||
void onClickPoseSave();
|
||||
void onPoseFileSelect();
|
||||
bool savePoseToXml(LLVOAvatar* avatar, std::string posePath);
|
||||
bool savePoseToBvh(LLVOAvatar* avatar, std::string posePath);
|
||||
void onClickBrowsePoseCache();
|
||||
void onPoseMenuAction(const LLSD& param);
|
||||
void loadPoseFromXml(LLVOAvatar* avatar, std::string poseFileName, E_LoadPoseMethods loadMethod);
|
||||
void setPoseSaveFileTextBoxToUiSelectedAvatarSaveFileName();
|
||||
void setUiSelectedAvatarSaveFileName(std::string saveFileName);
|
||||
void showOrHideAdvancedSaveOptions();
|
||||
|
||||
// UI Event Handlers:
|
||||
void onAvatarsRefresh();
|
||||
|
|
|
|||
|
|
@ -800,3 +800,121 @@ bool FSPoserAnimator::isAvatarSafeToUse(LLVOAvatar *avatar)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::writePoseAsBvh(llofstream* fileStream, LLVOAvatar* avatar)
|
||||
{
|
||||
if (!fileStream || !avatar)
|
||||
return false;
|
||||
|
||||
*fileStream << "HIERARCHY" << std::endl;
|
||||
auto startingJoint = getPoserJointByName("mPelvis");
|
||||
writeBvhFragment(fileStream, avatar, startingJoint, 0);
|
||||
*fileStream << "MOTION" << std::endl;
|
||||
*fileStream << "Frames: 1" << std::endl;
|
||||
*fileStream << "Frame Time: 1" << std::endl;
|
||||
writeBvhMotion(fileStream, avatar, startingJoint);
|
||||
*fileStream << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::writeBvhFragment(llofstream* fileStream, LLVOAvatar* avatar, const FSPoserJoint* joint, int tabStops)
|
||||
{
|
||||
if (!joint)
|
||||
return false;
|
||||
|
||||
auto position = getJointPosition(avatar, *joint);
|
||||
|
||||
switch (joint->boneType())
|
||||
{
|
||||
case WHOLEAVATAR:
|
||||
*fileStream << "ROOT " + joint->jointName() << std::endl;
|
||||
*fileStream << "{" << std::endl;
|
||||
*fileStream << getTabs(tabStops + 1) + "OFFSET " + vec3ToXYZString(position) << std::endl;
|
||||
*fileStream << getTabs(tabStops + 1) + "CHANNELS 6 Xposition Yposition Zposition Xrotation Yrotation Zrotation" << std::endl;
|
||||
break;
|
||||
|
||||
default:
|
||||
*fileStream << getTabs(tabStops) + "JOINT " + joint->jointName() << std::endl;
|
||||
*fileStream << getTabs(tabStops) + "{" << std::endl;
|
||||
*fileStream << getTabs(tabStops + 1) + "OFFSET " + vec3ToXYZString(position) << std::endl;
|
||||
*fileStream << getTabs(tabStops + 1) + "CHANNELS 3 Xrotation Yrotation Zrotation" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
if (numberOfBvhChildNodes > 0)
|
||||
{
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren()[index]);
|
||||
writeBvhFragment(fileStream, avatar, nextJoint, tabStops + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*fileStream << getTabs(tabStops + 1) + "End Site" << std::endl;
|
||||
*fileStream << getTabs(tabStops + 1) + "{" << std::endl;
|
||||
*fileStream << getTabs(tabStops + 2) + "OFFSET " + vec3ToXYZString(position) << std::endl; // I don't understand this node
|
||||
*fileStream << getTabs(tabStops + 1) + "}" << std::endl;
|
||||
}
|
||||
|
||||
*fileStream << getTabs(tabStops) + "}" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::writeBvhMotion(llofstream* fileStream, LLVOAvatar* avatar, const FSPoserJoint* joint)
|
||||
{
|
||||
if (!joint)
|
||||
return false;
|
||||
|
||||
auto rotation = getJointRotation(avatar, *joint, SWAP_NOTHING, NEGATE_NOTHING, false);
|
||||
auto position = getJointPosition(avatar, *joint);
|
||||
|
||||
switch (joint->boneType())
|
||||
{
|
||||
case WHOLEAVATAR:
|
||||
*fileStream << vec3ToXYZString(position) + " " + rotationToXZYString(rotation);
|
||||
break;
|
||||
|
||||
default:
|
||||
*fileStream << " " + rotationToXZYString(rotation);
|
||||
break;
|
||||
}
|
||||
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren()[index]);
|
||||
writeBvhMotion(fileStream, avatar, nextJoint);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string FSPoserAnimator::vec3ToXYZString(LLVector3 val)
|
||||
{
|
||||
return f32ToString(val[VX]) + " " + f32ToString(val[VY]) + " " + f32ToString(val[VZ]);
|
||||
}
|
||||
|
||||
std::string FSPoserAnimator::rotationToXZYString(LLVector3 val)
|
||||
{
|
||||
return f32ToString(val[VY] * RAD_TO_DEG) + " " + f32ToString(val[VZ] * RAD_TO_DEG) + " " + f32ToString(val[VX] * RAD_TO_DEG);
|
||||
}
|
||||
|
||||
std::string FSPoserAnimator::getTabs(int numOfTabstops)
|
||||
{
|
||||
std::string tabSpaces;
|
||||
for (int i = 0; i < numOfTabstops; i++)
|
||||
tabSpaces += "\t";
|
||||
|
||||
return tabSpaces;
|
||||
}
|
||||
|
||||
std::string FSPoserAnimator::f32ToString(F32 val)
|
||||
{
|
||||
std::string str;
|
||||
char buf[20];
|
||||
snprintf(buf, 20, "%f", val);
|
||||
str = buf;
|
||||
return str;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ public:
|
|||
std::string _jointName; // expected to be a match to LLJoint.getName() for a joint implementation.
|
||||
std::string _mirrorJointName;
|
||||
E_BoneTypes _boneList;
|
||||
std::vector<std::string> _bvhChildren;
|
||||
bool _dontFlipOnMirror = false;
|
||||
public:
|
||||
/// <summary>
|
||||
|
|
@ -122,6 +123,11 @@ public:
|
|||
/// </summary>
|
||||
bool dontFlipOnMirror() const { return _dontFlipOnMirror; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of child bvh joints for this.
|
||||
/// </summary>
|
||||
std::vector<std::string> bvhChildren() const { return _bvhChildren; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of a PoserJoint.
|
||||
/// </summary>
|
||||
|
|
@ -132,13 +138,15 @@ public:
|
|||
/// </param>
|
||||
/// <param name="b">The opposite joint name, if any. Also expected to be a well-known name.</param>
|
||||
/// <param name="c">The type of bone, often determining with which other bones the new instance would appear with.</param>
|
||||
/// <param name="d">The option for whether this joint should rotation-flip it counterpart when mirroring the pose of the entire body.</param>
|
||||
FSPoserJoint(std::string a, std::string b, E_BoneTypes c, bool d = false)
|
||||
/// <param name="d">The optional array of joints, needed for BVH saving, which are the direct decendent(s) of this joint.</param>
|
||||
/// <param name="e">The option for whether this joint should rotation-flip it counterpart when mirroring the pose of the entire body.</param>
|
||||
FSPoserJoint(std::string a, std::string b, E_BoneTypes c, std::vector<std::string> d = {}, bool e = false)
|
||||
{
|
||||
_jointName = a;
|
||||
_mirrorJointName = b;
|
||||
_boneList = c;
|
||||
_dontFlipOnMirror = d;
|
||||
_bvhChildren = d;
|
||||
_dontFlipOnMirror = e;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -152,25 +160,25 @@ public:
|
|||
/// </remarks>
|
||||
const std::vector<FSPoserJoint> PoserJoints {
|
||||
// head, torso, legs
|
||||
{"mPelvis", "", WHOLEAVATAR}, {"mTorso", "", BODY}, {"mChest", "", BODY}, {"mNeck", "", BODY}, {"mHead", "", BODY},
|
||||
{"mCollarLeft", "mCollarRight", BODY}, {"mShoulderLeft", "mShoulderRight", BODY}, {"mElbowLeft", "mElbowRight", BODY}, {"mWristLeft", "mWristRight", BODY},
|
||||
{"mCollarRight", "mCollarLeft", BODY, true}, {"mShoulderRight", "mShoulderLeft", BODY, true}, {"mElbowRight", "mElbowLeft", BODY, true}, {"mWristRight", "mWristLeft", BODY, true},
|
||||
{"mHipLeft", "mHipRight", BODY}, {"mKneeLeft", "mKneeRight", BODY}, {"mAnkleLeft", "mAnkleRight", BODY},
|
||||
{"mHipRight", "mHipLeft", BODY, true}, {"mKneeRight", "mKneeLeft", BODY, true}, {"mAnkleRight", "mAnkleLeft", BODY, true},
|
||||
{"mPelvis", "", WHOLEAVATAR, {"mTorso", "mHipLeft", "mHipRight"}}, {"mTorso", "", BODY, {"mChest"}}, {"mChest", "", BODY, {"mNeck", "mCollarLeft", "mCollarRight", "mWingsRoot"}}, {"mNeck", "", BODY, {"mHead"}}, {"mHead", "", BODY},
|
||||
{"mCollarLeft", "mCollarRight", BODY, {"mShoulderLeft"}}, {"mShoulderLeft", "mShoulderRight", BODY, {"mElbowLeft"}}, {"mElbowLeft", "mElbowRight", BODY, {"mWristLeft"}}, {"mWristLeft", "mWristRight", BODY},
|
||||
{"mCollarRight", "mCollarLeft", BODY, {"mShoulderRight"}, true}, {"mShoulderRight", "mShoulderLeft", BODY, {"mElbowRight"}, true}, {"mElbowRight", "mElbowLeft", BODY, {"mWristRight"}, true}, {"mWristRight", "mWristLeft", BODY, {}, true},
|
||||
{"mHipLeft", "mHipRight", BODY, {"mKneeLeft"}}, {"mKneeLeft", "mKneeRight", BODY, {"mAnkleLeft"}}, {"mAnkleLeft", "mAnkleRight", BODY},
|
||||
{"mHipRight", "mHipLeft", BODY, {"mKneeRight"}, true}, {"mKneeRight", "mKneeLeft", BODY, {"mAnkleRight"}, true}, {"mAnkleRight", "mAnkleLeft", BODY, {}, true},
|
||||
|
||||
// face
|
||||
{"mFaceForeheadLeft", "mFaceForeheadRight", FACE}, {"mFaceForeheadCenter", "", FACE}, {"mFaceForeheadRight", "mFaceForeheadLeft", FACE, true},
|
||||
{"mFaceForeheadLeft", "mFaceForeheadRight", FACE}, {"mFaceForeheadCenter", "", FACE}, {"mFaceForeheadRight", "mFaceForeheadLeft", FACE, {}, true},
|
||||
{"mFaceEyebrowOuterLeft", "mFaceEyebrowOuterRight", FACE}, {"mFaceEyebrowCenterLeft", "mFaceEyebrowCenterRight", FACE}, {"mFaceEyebrowInnerLeft", "mFaceEyebrowInnerRight", FACE},
|
||||
{"mFaceEyebrowOuterRight", "mFaceEyebrowOuterLeft", FACE, true}, {"mFaceEyebrowCenterRight", "mFaceEyebrowCenterLeft", FACE, true}, {"mFaceEyebrowInnerRight", "mFaceEyebrowInnerLeft", FACE, true},
|
||||
{"mFaceEyebrowOuterRight", "mFaceEyebrowOuterLeft", FACE, {}, true}, {"mFaceEyebrowCenterRight", "mFaceEyebrowCenterLeft", FACE, {}, true}, {"mFaceEyebrowInnerRight", "mFaceEyebrowInnerLeft", FACE, {}, true},
|
||||
|
||||
{"mEyeLeft", "mEyeRight", FACE}, {"mEyeRight", "mEyeLeft", FACE, true},
|
||||
{"mFaceEyeLidUpperLeft", "mFaceEyeLidUpperRight", FACE}, {"mFaceEyeLidLowerLeft", "mFaceEyeLidLowerRight", FACE}, {"mFaceEyeLidUpperRight", "mFaceEyeLidUpperLeft", FACE, true}, {"mFaceEyeLidLowerRight", "mFaceEyeLidLowerLeft", FACE, true},
|
||||
{"mEyeLeft", "mEyeRight", FACE}, {"mEyeRight", "mEyeLeft", FACE, {}, true},
|
||||
{"mFaceEyeLidUpperLeft", "mFaceEyeLidUpperRight", FACE}, {"mFaceEyeLidLowerLeft", "mFaceEyeLidLowerRight", FACE}, {"mFaceEyeLidUpperRight", "mFaceEyeLidUpperLeft", FACE, {}, true}, {"mFaceEyeLidLowerRight", "mFaceEyeLidLowerLeft", FACE, {}, true},
|
||||
|
||||
{"mFaceCheekUpperLeft", "mFaceCheekUpperRight", FACE}, {"mFaceCheekLowerLeft", "mFaceCheekLowerRight", FACE}, {"mFaceCheekUpperRight", "mFaceCheekUpperLeft", FACE, true}, {"mFaceCheekLowerRight", "mFaceCheekLowerLeft", FACE, true},
|
||||
{"mFaceLipUpperLeft", "mFaceLipUpperRight", FACE}, {"mFaceLipUpperCenter", "", FACE}, {"mFaceLipUpperRight", "mFaceLipUpperLeft", FACE, true},
|
||||
{"mFaceLipCornerLeft", "mFaceLipCornerRight", FACE}, {"mFaceLipCornerRight", "mFaceLipCornerLeft", FACE, true},
|
||||
{"mFaceTongueBase", "", FACE}, {"mFaceTongueTip", "", FACE, true},
|
||||
{"mFaceLipLowerLeft", "mFaceLipLowerRight", FACE}, {"mFaceLipLowerCenter", "", FACE}, {"mFaceLipLowerRight", "mFaceLipLowerLeft", FACE, true},
|
||||
{"mFaceCheekUpperLeft", "mFaceCheekUpperRight", FACE}, {"mFaceCheekLowerLeft", "mFaceCheekLowerRight", FACE}, {"mFaceCheekUpperRight", "mFaceCheekUpperLeft", FACE, {}, true}, {"mFaceCheekLowerRight", "mFaceCheekLowerLeft", FACE, {}, true},
|
||||
{"mFaceLipUpperLeft", "mFaceLipUpperRight", FACE}, {"mFaceLipUpperCenter", "", FACE}, {"mFaceLipUpperRight", "mFaceLipUpperLeft", FACE, {}, true},
|
||||
{"mFaceLipCornerLeft", "mFaceLipCornerRight", FACE}, {"mFaceLipCornerRight", "mFaceLipCornerLeft", FACE, {}, true},
|
||||
{"mFaceTongueBase", "", FACE}, {"mFaceTongueTip", "", FACE, {}, true},
|
||||
{"mFaceLipLowerLeft", "mFaceLipLowerRight", FACE}, {"mFaceLipLowerCenter", "", FACE}, {"mFaceLipLowerRight", "mFaceLipLowerLeft", FACE, {}, true},
|
||||
{"mFaceJaw", "", FACE},
|
||||
|
||||
//left hand
|
||||
|
|
@ -181,25 +189,25 @@ public:
|
|||
{"mHandPinky1Left", "mHandPinky1Right", HANDS}, {"mHandPinky2Left", "mHandPinky2Right", HANDS}, {"mHandPinky3Left", "mHandPinky3Right", HANDS},
|
||||
|
||||
// right hand
|
||||
{"mHandThumb1Right", "mHandThumb1Left", HANDS, true}, {"mHandThumb2Right", "mHandThumb2Left", HANDS, true}, {"mHandThumb3Right", "mHandThumb3Left", HANDS, true},
|
||||
{"mHandIndex1Right", "mHandIndex1Left", HANDS, true}, {"mHandIndex2Right", "mHandIndex2Left", HANDS, true}, {"mHandIndex3Right", "mHandIndex3Left", HANDS, true},
|
||||
{"mHandMiddle1Right", "mHandMiddle1Left", HANDS, true}, {"mHandMiddle2Right", "mHandMiddle2Left", HANDS, true}, {"mHandMiddle3Right", "mHandMiddle3Left", HANDS, true},
|
||||
{"mHandRing1Right", "mHandRing1Left", HANDS, true}, {"mHandRing2Right", "mHandRing2Left", HANDS, true}, {"mHandRing3Right", "mHandRing3Left", HANDS, true},
|
||||
{"mHandPinky1Right", "mHandPinky1Left", HANDS, true}, {"mHandPinky2Right", "mHandPinky2Left", HANDS, true}, {"mHandPinky3Right", "mHandPinky3Left", HANDS, true},
|
||||
{"mHandThumb1Right", "mHandThumb1Left", HANDS, {}, true}, {"mHandThumb2Right", "mHandThumb2Left", HANDS, {}, true}, {"mHandThumb3Right", "mHandThumb3Left", HANDS, {}, true},
|
||||
{"mHandIndex1Right", "mHandIndex1Left", HANDS, {}, true}, {"mHandIndex2Right", "mHandIndex2Left", HANDS, {}, true}, {"mHandIndex3Right", "mHandIndex3Left", HANDS, {}, true},
|
||||
{"mHandMiddle1Right", "mHandMiddle1Left", HANDS, {}, true}, {"mHandMiddle2Right", "mHandMiddle2Left", HANDS, {}, true}, {"mHandMiddle3Right", "mHandMiddle3Left", HANDS, {}, true},
|
||||
{"mHandRing1Right", "mHandRing1Left", HANDS, {}, true}, {"mHandRing2Right", "mHandRing2Left", HANDS, {}, true}, {"mHandRing3Right", "mHandRing3Left", HANDS, {}, true},
|
||||
{"mHandPinky1Right", "mHandPinky1Left", HANDS, {}, true}, {"mHandPinky2Right", "mHandPinky2Left", HANDS, {}, true}, {"mHandPinky3Right", "mHandPinky3Left", HANDS, {}, true},
|
||||
|
||||
// tail and hind limbs
|
||||
{"mTail1", "", MISC}, {"mTail2", "", MISC}, {"mTail3", "", MISC}, {"mTail4", "", MISC}, {"mTail5", "", MISC}, {"mTail6", "", MISC}, {"mGroin", "", MISC},
|
||||
{"mHindLimbsRoot", "", MISC},
|
||||
{"mHindLimb1Left", "mHindLimb1Right", MISC}, {"mHindLimb2Left", "mHindLimb2Right", MISC}, {"mHindLimb3Left", "mHindLimb3Right", MISC}, {"mHindLimb4Left", "mHindLimb4Right", MISC},
|
||||
{"mHindLimb1Right", "mHindLimb1Left", MISC, true}, {"mHindLimb2Right", "mHindLimb2Left", MISC, true}, {"mHindLimb3Right", "mHindLimb3Left", MISC, true}, {"mHindLimb4Right", "mHindLimb4Left", MISC, true},
|
||||
{"mHindLimb1Right", "mHindLimb1Left", MISC, {}, true}, {"mHindLimb2Right", "mHindLimb2Left", MISC, {}, true}, {"mHindLimb3Right", "mHindLimb3Left", MISC, {}, true}, {"mHindLimb4Right", "mHindLimb4Left", MISC, {}, true},
|
||||
|
||||
// wings
|
||||
{"mWingsRoot", "", MISC},
|
||||
{"mWing1Left", "mWing1Right", MISC}, {"mWing2Left", "mWing2Right", MISC}, {"mWing3Left", "mWing3Right", MISC}, {"mWing4Left", "mWing4Right", MISC}, {"mWing4FanLeft", "mWing4FanRight", MISC},
|
||||
{"mWing1Right", "mWing1Left", MISC, true}, {"mWing2Right", "mWing2Left", MISC, true}, {"mWing3Right", "mWing3Left", MISC, true}, {"mWing4Right", "mWing4Left", MISC, true}, {"mWing4FanRight", "mWing4FanLeft", MISC, true},
|
||||
{"mWing1Right", "mWing1Left", MISC, {}, true}, {"mWing2Right", "mWing2Left", MISC, {}, true}, {"mWing3Right", "mWing3Left", MISC, {}, true}, {"mWing4Right", "mWing4Left", MISC, {}, true}, {"mWing4FanRight", "mWing4FanLeft", MISC, {}, true},
|
||||
|
||||
// Collision Volumes
|
||||
{"LEFT_PEC", "RIGHT_PEC", COL_VOLUMES}, {"RIGHT_PEC", "LEFT_PEC", COL_VOLUMES, true}, {"BELLY", "", COL_VOLUMES}, {"BUTT", "", COL_VOLUMES},
|
||||
{"LEFT_PEC", "RIGHT_PEC", COL_VOLUMES}, {"RIGHT_PEC", "LEFT_PEC", COL_VOLUMES, {}, true}, {"BELLY", "", COL_VOLUMES}, {"BUTT", "", COL_VOLUMES},
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
@ -390,6 +398,14 @@ public:
|
|||
/// <param name="avatar">The avatar whose pose should flip left-right.</param>
|
||||
void flipEntirePose(LLVOAvatar *avatar);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the supplied PoserJoint for the supplied avatar is being posed.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar having the joint to which we refer.</param>
|
||||
/// <param name="joint">The joint being queried for.</param>
|
||||
/// <returns>True if this is joint is being posed for the supplied avatar, otherwise false.</returns>
|
||||
bool writePoseAsBvh(llofstream *fileStream, LLVOAvatar* avatar);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// Translates a rotation vector from the UI to a Quaternion for the bone.
|
||||
|
|
@ -431,7 +447,16 @@ public:
|
|||
/// </summary>
|
||||
/// <param name="avatar">The avatar to test if it is safe to animate.</param>
|
||||
/// <returns>True if the avatar is safe to manipulate, otherwise false.</returns>
|
||||
bool isAvatarSafeToUse(LLVOAvatar *avatar);
|
||||
bool isAvatarSafeToUse(LLVOAvatar* avatar);
|
||||
|
||||
bool writeBvhFragment(llofstream* fileStream, LLVOAvatar* avatar, const FSPoserJoint* joint, int tabStops);
|
||||
|
||||
bool writeBvhMotion(llofstream* fileStream, LLVOAvatar* avatar, const FSPoserJoint* joint);
|
||||
|
||||
std::string static f32ToString(F32 val);
|
||||
std::string static getTabs(int numOfTabstops);
|
||||
std::string static rotationToXZYString(LLVector3 val);
|
||||
std::string static vec3ToXYZString(LLVector3 val);
|
||||
|
||||
/// <summary>
|
||||
/// Maps the avatar's ID to the animation registered to them.
|
||||
|
|
|
|||
|
|
@ -1115,7 +1115,7 @@ width="565">
|
|||
visible="true"
|
||||
auto_resize="false"
|
||||
name="advanced_controls_layout"
|
||||
width="607">
|
||||
width="600">
|
||||
<panel
|
||||
follows="top|left|right"
|
||||
height="97"
|
||||
|
|
@ -1126,7 +1126,7 @@ width="565">
|
|||
mouse_opaque="false"
|
||||
visible="false"
|
||||
name="advanced_parent_panel"
|
||||
width="607">
|
||||
width="555">
|
||||
<tab_container
|
||||
follows="all"
|
||||
halign="center"
|
||||
|
|
@ -1138,7 +1138,7 @@ width="565">
|
|||
tab_group="1"
|
||||
tab_position="top"
|
||||
top_pad="0"
|
||||
width="607">
|
||||
width="555">
|
||||
<panel
|
||||
follows="all"
|
||||
background_visible="false"
|
||||
|
|
@ -1148,7 +1148,7 @@ width="565">
|
|||
title="Body Part Position"
|
||||
name="position_panel"
|
||||
top="0"
|
||||
width="607">
|
||||
width="555">
|
||||
<slider
|
||||
decimal_digits="3"
|
||||
can_edit_text="true"
|
||||
|
|
@ -1164,7 +1164,7 @@ width="565">
|
|||
min_val="-0.5"
|
||||
name="Advanced_Position_X"
|
||||
top_pad="6"
|
||||
width="520" >
|
||||
width="530" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.PositionSet"
|
||||
parameter="0"/>
|
||||
|
|
@ -1184,7 +1184,7 @@ width="565">
|
|||
min_val="-0.5"
|
||||
name="Advanced_Position_Y"
|
||||
top_pad="1"
|
||||
width="520" >
|
||||
width="530" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.PositionSet"
|
||||
parameter="1"/>
|
||||
|
|
@ -1204,7 +1204,7 @@ width="565">
|
|||
min_val="-0.5"
|
||||
name="Advanced_Position_Z"
|
||||
top_pad="1"
|
||||
width="520" >
|
||||
width="530" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.PositionSet"
|
||||
parameter="2"/>
|
||||
|
|
@ -1283,7 +1283,7 @@ width="565">
|
|||
min_val="0"
|
||||
name="Advanced_Scale_X"
|
||||
top_pad="6"
|
||||
width="520" >
|
||||
width="530" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.ScaleSet"
|
||||
parameter="0"/>
|
||||
|
|
@ -1303,7 +1303,7 @@ width="565">
|
|||
min_val="0"
|
||||
name="Advanced_Scale_Y"
|
||||
top_pad="1"
|
||||
width="520" >
|
||||
width="530" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.ScaleSet"
|
||||
parameter="1"/>
|
||||
|
|
@ -1323,7 +1323,7 @@ width="565">
|
|||
min_val="0"
|
||||
name="Advanced_Scale_Z"
|
||||
top_pad="1"
|
||||
width="520" >
|
||||
width="530" >
|
||||
<slider.commit_callback
|
||||
function="Poser.Advanced.ScaleSet"
|
||||
parameter="2"/>
|
||||
|
|
@ -1379,6 +1379,27 @@ 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">
|
||||
<check_box
|
||||
name="also_save_bvh_checkbox"
|
||||
height="16"
|
||||
label="Write BVH when saving"
|
||||
follows="left|top"
|
||||
left="0"
|
||||
tool_tip="When you save your pose, also write a BVH file, which can be uploaded via the 'Build' menu to pose yourself or others in-world"
|
||||
top_pad="5"
|
||||
width="134" />
|
||||
</panel>
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</floater>
|
||||
|
|
|
|||
Loading…
Reference in New Issue