diff --git a/indra/llcharacter/llbvhloader.h b/indra/llcharacter/llbvhloader.h
index de16d86ff4..c2c755664e 100755
--- a/indra/llcharacter/llbvhloader.h
+++ b/indra/llcharacter/llbvhloader.h
@@ -296,6 +296,10 @@ public:
ELoadStatus getStatus() { return mStatus; }
+ // FIRE-17277: Allow entering Loop In/Loop Out as frames
+ S32 getNumFrames() { return mNumFrames; }
+ //
+
protected:
// Consumes one line of input from file.
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index 3b1aee77d1..4ad9774397 100755
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -176,6 +176,12 @@ void LLFloaterBvhPreview::setAnimCallbacks()
getChild("loop_in_point")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateLoopIn, this, _1));
getChild("loop_out_point")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitLoopOut, this));
getChild("loop_out_point")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateLoopOut, this, _1));
+ // FIRE-17277: Allow entering Loop In/Loop Out as frames
+ getChild("loop_in_frames")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitLoopInFrames, this));
+ getChild("loop_in_frames")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateLoopInFrames, this, _1));
+ getChild("loop_out_frames")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitLoopOutFrames, this));
+ getChild("loop_out_frames")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateLoopOutFrames, this, _1));
+ //
getChild("hand_pose_combo")->setCommitCallback(boost::bind(&LLFloaterBvhPreview::onCommitHandPose, this));
@@ -329,6 +335,20 @@ BOOL LLFloaterBvhPreview::loadBVH()
// motion will be returned, but it will be in a load-pending state, as this is a new motion
// this motion will not request an asset transfer until next update, so we have a chance to
// load the keyframe data locally
+ // FIRE-17277: Allow entering Loop In/Loop Out as frames
+ mNumFrames = loaderp->getNumFrames();
+ getChild("loop_in_frames")->setMaxValue(LLSD((F32)mNumFrames));
+ getChild("loop_out_frames")->setMaxValue(LLSD((F32)mNumFrames));
+ // (Re)assign loop frames spinners from loop percentages.
+ getChild("loop_in_frames")->setValue(LLSD((F32)getChild("loop_in_point")->getValue().asReal() / 100.f * (F32)mNumFrames));
+ getChild("loop_out_frames")->setValue(LLSD((F32)getChild("loop_out_point")->getValue().asReal() / 100.f * (F32)mNumFrames));
+
+ LLUIString out_str = getString("FS_report_frames");
+ out_str.setArg("[F]", llformat("%d", mNumFrames));
+ out_str.setArg("[S]", llformat("%.1f", loaderp->getDuration()));
+ out_str.setArg("[FPS]", llformat("%.1f", (F32)mNumFrames / loaderp->getDuration()));
+ getChild("frames_label")->setValue(LLSD(out_str));
+ //
// Preview on own avatar
//motionp = (LLKeyframeMotion*)mAnimPreview->getDummyAvatar()->createMotion(mMotionID);
motionp = dynamic_cast(mAnimPreview->getPreviewAvatar(this)->createMotion(mMotionID));
@@ -869,7 +889,10 @@ void LLFloaterBvhPreview::onCommitLoopIn()
if (motionp)
{
- motionp->setLoopIn((F32)getChild("loop_in_point")->getValue().asReal() / 100.f);
+ // FIRE-17277: Allow entering Loop In/Loop Out as frames
+ //motionp->setLoopIn((F32)getChild("loop_in_point")->getValue().asReal() / 100.f);
+ getChild("loop_in_frames")->setValue(LLSD((F32)getChild("loop_in_point")->getValue().asReal() / 100.f * (F32)mNumFrames));
+ //
resetMotion();
getChild("loop_check")->setValue(LLSD(TRUE));
onCommitLoop();
@@ -893,13 +916,61 @@ void LLFloaterBvhPreview::onCommitLoopOut()
if (motionp)
{
- motionp->setLoopOut((F32)getChild("loop_out_point")->getValue().asReal() * 0.01f * motionp->getDuration());
+ // FIRE-17277: Allow entering Loop In/Loop Out as frames
+ //motionp->setLoopOut((F32)getChild("loop_out_point")->getValue().asReal() * 0.01f * motionp->getDuration());
+ getChild("loop_out_frames")->setValue(LLSD((F32)getChild("loop_out_point")->getValue().asReal() / 100.f * (F32)mNumFrames));
+ //
resetMotion();
getChild("loop_check")->setValue(LLSD(TRUE));
onCommitLoop();
}
}
+// FIRE-17277: Allow entering Loop In/Loop Out as frames
+//-----------------------------------------------------------------------------
+// onCommitLoopInFrames()
+//-----------------------------------------------------------------------------
+void LLFloaterBvhPreview::onCommitLoopInFrames()
+{
+ if (!getEnabled() || !mAnimPreview)
+ return;
+
+ // Preview on own avatar
+ LLVOAvatar* avatarp = mAnimPreview->getPreviewAvatar(this);
+ LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
+
+ if (motionp)
+ {
+ getChild("loop_in_point")->setValue(LLSD(mNumFrames == 0 ? 0.f : 100.f * (F32)getChild("loop_in_frames")->getValue().asReal() / (F32)mNumFrames));
+ resetMotion();
+ getChild("loop_check")->setValue(LLSD(TRUE));
+ // The values are actually set here:
+ onCommitLoop();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// onCommitLoopOutFrames()
+//-----------------------------------------------------------------------------
+void LLFloaterBvhPreview::onCommitLoopOutFrames()
+{
+ if (!getEnabled() || !mAnimPreview)
+ return;
+
+ // Preview on own avatar
+ LLVOAvatar* avatarp = mAnimPreview->getPreviewAvatar(this);
+ LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID);
+
+ if (motionp)
+ {
+ getChild("loop_out_point")->setValue(LLSD(mNumFrames == 0 ? 100.f : 100.f * (F32)getChild("loop_out_frames")->getValue().asReal() / (F32)mNumFrames));
+ resetMotion();
+ getChild("loop_check")->setValue(LLSD(TRUE));
+ onCommitLoop();
+ }
+}
+//
+
//-----------------------------------------------------------------------------
// onCommitName()
//-----------------------------------------------------------------------------
@@ -1083,6 +1154,9 @@ bool LLFloaterBvhPreview::validateLoopIn(const LLSD& data)
}
getChild("loop_in_point")->setValue(LLSD(loop_in_value));
+ // FIRE-17277: Allow entering Loop In/Loop Out as frames
+ getChild("loop_in_frames")->setValue(LLSD(loop_in_value / 100.f * (F32)mNumFrames));
+ //
return true;
}
@@ -1111,10 +1185,74 @@ bool LLFloaterBvhPreview::validateLoopOut(const LLSD& data)
}
getChild("loop_out_point")->setValue(LLSD(loop_out_value));
+ // FIRE-17277: Allow entering Loop In/Loop Out as frames
+ getChild("loop_out_frames")->setValue(LLSD(loop_out_value / 100.f * (F32)mNumFrames));
+ //
return true;
}
+// FIRE-17277: Allow entering Loop In/Loop Out as frames
+//-----------------------------------------------------------------------------
+// validateLoopInFrames()
+//-----------------------------------------------------------------------------
+bool LLFloaterBvhPreview::validateLoopInFrames(const LLSD& data)
+{
+ if (!getEnabled())
+ return false;
+
+ F32 loop_in_value = (F32)getChild("loop_in_frames")->getValue().asReal();
+ F32 loop_out_value = (F32)getChild("loop_out_frames")->getValue().asReal();
+
+ if (loop_in_value < 0.f)
+ {
+ loop_in_value = 0.f;
+ }
+ else if (loop_in_value > 100.f)
+ {
+ loop_in_value = 100.f;
+ }
+ else if (loop_in_value > loop_out_value)
+ {
+ loop_in_value = loop_out_value;
+ }
+
+ getChild("loop_in_frames")->setValue(LLSD(loop_in_value));
+ getChild("loop_in_point")->setValue(LLSD(mNumFrames == 0 ? 0.f : 100.f * loop_in_value / (F32)mNumFrames));
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// validateLoopOutFrames()
+//-----------------------------------------------------------------------------
+bool LLFloaterBvhPreview::validateLoopOutFrames(const LLSD& data)
+{
+ if (!getEnabled())
+ return false;
+
+ F32 loop_out_value = (F32)getChild("loop_out_frames")->getValue().asReal();
+ F32 loop_in_value = (F32)getChild("loop_in_frames")->getValue().asReal();
+
+ if (loop_out_value < 0.f)
+ {
+ loop_out_value = 0.f;
+ }
+ else if (loop_out_value > 100.f)
+ {
+ loop_out_value = 100.f;
+ }
+ else if (loop_out_value < loop_in_value)
+ {
+ loop_out_value = loop_in_value;
+ }
+
+ getChild("loop_out_frames")->setValue(LLSD(loop_out_value));
+ getChild("loop_out_point")->setValue(LLSD(mNumFrames == 0 ? 100.f : 100.f * loop_out_value / (F32)mNumFrames));
+ return true;
+}
+//
+
+
//-----------------------------------------------------------------------------
// refresh()
//-----------------------------------------------------------------------------
diff --git a/indra/newview/llfloaterbvhpreview.h b/indra/newview/llfloaterbvhpreview.h
index 6b7e6c3c5d..a803c411ba 100755
--- a/indra/newview/llfloaterbvhpreview.h
+++ b/indra/newview/llfloaterbvhpreview.h
@@ -116,6 +116,12 @@ public:
LLAssetType::EType type,
void* user_data,
S32 status, LLExtStat ext_status);
+ // FIRE-17277: Allow entering Loop In/Loop Out as frames
+ void onCommitLoopInFrames();
+ void onCommitLoopOutFrames();
+ bool validateLoopInFrames(const LLSD& data);
+ bool validateLoopOutFrames(const LLSD& data);
+ //
private:
void setAnimCallbacks() ;
// Reload animation from disk
@@ -146,6 +152,9 @@ protected:
// FIRE-2083: Slider in upload animation floater doesn't work
LLFrameTimer mTimer;
+
+ // FIRE-17277: Allow entering Loop In/Loop Out as frames
+ S32 mNumFrames;
};
#endif // LL_LLFLOATERBVHPREVIEW_H
diff --git a/indra/newview/skins/default/xui/en/floater_animation_bvh_preview.xml b/indra/newview/skins/default/xui/en/floater_animation_bvh_preview.xml
index 453a92c5e5..ef02e1e690 100755
--- a/indra/newview/skins/default/xui/en/floater_animation_bvh_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_animation_bvh_preview.xml
@@ -2,7 +2,7 @@
Incorrect root joint name, use "hip".
+
+ [F] frm. [S] s. [FPS] fps
+
+
+ 300 frm. 30 s. 10 fps
+
+
+
Unable to read animation file.
We recommend BVH files exported from Poser 4.