More animation controls.

This commit is contained in:
Andrzej Kapolka 2014-05-21 15:30:50 -07:00
parent 906e082215
commit de7c05cb2d
6 changed files with 80 additions and 12 deletions

View file

@ -441,10 +441,12 @@ void MyAvatar::removeAnimationHandle(const AnimationHandlePointer& handle) {
_animationHandles.removeOne(handle); _animationHandles.removeOne(handle);
} }
void MyAvatar::startAnimation(const QString& url, float fps, float priority, bool loop, const QStringList& maskedJoints) { void MyAvatar::startAnimation(const QString& url, float fps, float priority,
bool loop, bool hold, int firstFrame, int lastFrame, const QStringList& maskedJoints) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "startAnimation", Q_ARG(const QString&, url), QMetaObject::invokeMethod(this, "startAnimation", Q_ARG(const QString&, url), Q_ARG(float, fps),
Q_ARG(float, fps), Q_ARG(float, priority), Q_ARG(bool, loop), Q_ARG(const QStringList&, maskedJoints)); Q_ARG(float, priority), Q_ARG(bool, loop), Q_ARG(bool, hold), Q_ARG(int, firstFrame),
Q_ARG(int, lastFrame), Q_ARG(const QStringList&, maskedJoints));
return; return;
} }
AnimationHandlePointer handle = _skeletonModel.createAnimationHandle(); AnimationHandlePointer handle = _skeletonModel.createAnimationHandle();
@ -452,6 +454,9 @@ void MyAvatar::startAnimation(const QString& url, float fps, float priority, boo
handle->setFPS(fps); handle->setFPS(fps);
handle->setPriority(priority); handle->setPriority(priority);
handle->setLoop(loop); handle->setLoop(loop);
handle->setHold(hold);
handle->setFirstFrame(firstFrame);
handle->setLastFrame(lastFrame);
handle->setMaskedJoints(maskedJoints); handle->setMaskedJoints(maskedJoints);
handle->start(); handle->start();
} }
@ -514,6 +519,10 @@ void MyAvatar::saveData(QSettings* settings) {
settings->setValue("url", pointer->getURL()); settings->setValue("url", pointer->getURL());
settings->setValue("fps", pointer->getFPS()); settings->setValue("fps", pointer->getFPS());
settings->setValue("priority", pointer->getPriority()); settings->setValue("priority", pointer->getPriority());
settings->setValue("loop", pointer->getLoop());
settings->setValue("hold", pointer->getHold());
settings->setValue("firstFrame", pointer->getFirstFrame());
settings->setValue("lastFrame", pointer->getLastFrame());
settings->setValue("maskedJoints", pointer->getMaskedJoints()); settings->setValue("maskedJoints", pointer->getMaskedJoints());
} }
settings->endArray(); settings->endArray();
@ -581,6 +590,10 @@ void MyAvatar::loadData(QSettings* settings) {
handle->setURL(settings->value("url").toUrl()); handle->setURL(settings->value("url").toUrl());
handle->setFPS(loadSetting(settings, "fps", 30.0f)); handle->setFPS(loadSetting(settings, "fps", 30.0f));
handle->setPriority(loadSetting(settings, "priority", 1.0f)); handle->setPriority(loadSetting(settings, "priority", 1.0f));
handle->setLoop(settings->value("loop", true).toBool());
handle->setHold(settings->value("hold", false).toBool());
handle->setFirstFrame(settings->value("firstFrame", 0).toInt());
handle->setLastFrame(settings->value("lastFrame", INT_MAX).toInt());
handle->setMaskedJoints(settings->value("maskedJoints").toStringList()); handle->setMaskedJoints(settings->value("maskedJoints").toStringList());
} }
settings->endArray(); settings->endArray();

View file

@ -67,8 +67,8 @@ public:
void removeAnimationHandle(const AnimationHandlePointer& handle); void removeAnimationHandle(const AnimationHandlePointer& handle);
/// Allows scripts to run animations. /// Allows scripts to run animations.
Q_INVOKABLE void startAnimation(const QString& url, float fps = 30.0f, Q_INVOKABLE void startAnimation(const QString& url, float fps = 30.0f, float priority = 1.0f, bool loop = false,
float priority = 1.0f, bool loop = false, const QStringList& maskedJoints = QStringList()); bool hold = false, int firstFrame = 0, int lastFrame = INT_MAX, const QStringList& maskedJoints = QStringList());
/// Stops an animation as identified by a URL. /// Stops an animation as identified by a URL.
Q_INVOKABLE void stopAnimation(const QString& url); Q_INVOKABLE void stopAnimation(const QString& url);

View file

@ -1694,7 +1694,7 @@ void AnimationHandle::setRunning(bool running) {
if (!_model->_runningAnimations.contains(_self)) { if (!_model->_runningAnimations.contains(_self)) {
insertSorted(_model->_runningAnimations, _self); insertSorted(_model->_runningAnimations, _self);
} }
_frameIndex = 0.0f; _frameIndex = _firstFrame;
} else { } else {
_model->_runningAnimations.removeOne(_self); _model->_runningAnimations.removeOne(_self);
@ -1706,7 +1706,10 @@ AnimationHandle::AnimationHandle(Model* model) :
_model(model), _model(model),
_fps(30.0f), _fps(30.0f),
_priority(1.0f), _priority(1.0f),
_firstFrame(0),
_lastFrame(INT_MAX),
_loop(false), _loop(false),
_hold(false),
_running(false) { _running(false) {
} }
@ -1737,10 +1740,11 @@ void AnimationHandle::simulate(float deltaTime) {
stop(); stop();
return; return;
} }
int ceilFrameIndex = (int)glm::ceil(_frameIndex); int lastFrameIndex = qMin(_lastFrame, animationGeometry.animationFrames.size() - 1);
if (!_loop && ceilFrameIndex >= animationGeometry.animationFrames.size()) { int firstFrameIndex = qMin(_firstFrame, lastFrameIndex);
if ((!_loop && _frameIndex >= lastFrameIndex) || firstFrameIndex == lastFrameIndex) {
// passed the end; apply the last frame // passed the end; apply the last frame
const FBXAnimationFrame& frame = animationGeometry.animationFrames.last(); const FBXAnimationFrame& frame = animationGeometry.animationFrames.at(lastFrameIndex);
for (int i = 0; i < _jointMappings.size(); i++) { for (int i = 0; i < _jointMappings.size(); i++) {
int mapping = _jointMappings.at(i); int mapping = _jointMappings.at(i);
if (mapping != -1) { if (mapping != -1) {
@ -1750,14 +1754,20 @@ void AnimationHandle::simulate(float deltaTime) {
} }
} }
} }
stop(); if (!_hold) {
stop();
}
return; return;
} }
int frameCount = lastFrameIndex - firstFrameIndex + 1;
_frameIndex = firstFrameIndex + glm::mod(qMax(_frameIndex - firstFrameIndex, 0.0f), (float)frameCount);
qDebug() << _frameIndex;
// blend between the closest two frames // blend between the closest two frames
const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at( const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at(
ceilFrameIndex % animationGeometry.animationFrames.size()); firstFrameIndex + ((int)glm::ceil(_frameIndex) - firstFrameIndex) % frameCount);
const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at( const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at(
(int)glm::floor(_frameIndex) % animationGeometry.animationFrames.size()); firstFrameIndex + ((int)glm::floor(_frameIndex) - firstFrameIndex) % frameCount);
float frameFraction = glm::fract(_frameIndex); float frameFraction = glm::fract(_frameIndex);
for (int i = 0; i < _jointMappings.size(); i++) { for (int i = 0; i < _jointMappings.size(); i++) {
int mapping = _jointMappings.at(i); int mapping = _jointMappings.at(i);

View file

@ -393,6 +393,15 @@ public:
void setLoop(bool loop) { _loop = loop; } void setLoop(bool loop) { _loop = loop; }
bool getLoop() const { return _loop; } bool getLoop() const { return _loop; }
void setHold(bool hold) { _hold = hold; }
bool getHold() const { return _hold; }
void setFirstFrame(int firstFrame) { _firstFrame = firstFrame; }
int getFirstFrame() const { return _firstFrame; }
void setLastFrame(int lastFrame) { _lastFrame = lastFrame; }
int getLastFrame() const { return _lastFrame; }
void setMaskedJoints(const QStringList& maskedJoints); void setMaskedJoints(const QStringList& maskedJoints);
const QStringList& getMaskedJoints() const { return _maskedJoints; } const QStringList& getMaskedJoints() const { return _maskedJoints; }
@ -416,7 +425,10 @@ private:
QUrl _url; QUrl _url;
float _fps; float _fps;
float _priority; float _priority;
int _firstFrame;
int _lastFrame;
bool _loop; bool _loop;
bool _hold;
QStringList _maskedJoints; QStringList _maskedJoints;
bool _running; bool _running;
QVector<int> _jointMappings; QVector<int> _jointMappings;

View file

@ -9,6 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QCheckBox>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <QFileDialog> #include <QFileDialog>
@ -107,6 +108,24 @@ AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePo
maskedJointBox->addWidget(_chooseMaskedJoints = new QPushButton("Choose")); maskedJointBox->addWidget(_chooseMaskedJoints = new QPushButton("Choose"));
connect(_chooseMaskedJoints, SIGNAL(clicked(bool)), SLOT(chooseMaskedJoints())); connect(_chooseMaskedJoints, SIGNAL(clicked(bool)), SLOT(chooseMaskedJoints()));
layout->addRow("Loop:", _loop = new QCheckBox());
_loop->setChecked(handle->getLoop());
connect(_loop, SIGNAL(toggled(bool)), SLOT(updateHandle()));
layout->addRow("Hold:", _hold = new QCheckBox());
_hold->setChecked(handle->getHold());
connect(_hold, SIGNAL(toggled(bool)), SLOT(updateHandle()));
layout->addRow("First Frame:", _firstFrame = new QSpinBox());
_firstFrame->setMaximum(INT_MAX);
_firstFrame->setValue(handle->getFirstFrame());
connect(_firstFrame, SIGNAL(valueChanged(int)), SLOT(updateHandle()));
layout->addRow("Last Frame:", _lastFrame = new QSpinBox());
_lastFrame->setMaximum(INT_MAX);
_lastFrame->setValue(handle->getLastFrame());
connect(_lastFrame, SIGNAL(valueChanged(int)), SLOT(updateHandle()));
QPushButton* remove = new QPushButton("Delete"); QPushButton* remove = new QPushButton("Delete");
layout->addRow(remove); layout->addRow(remove);
connect(remove, SIGNAL(clicked(bool)), SLOT(removeHandle())); connect(remove, SIGNAL(clicked(bool)), SLOT(removeHandle()));
@ -149,7 +168,15 @@ void AnimationPanel::updateHandle() {
_handle->setURL(_url->text()); _handle->setURL(_url->text());
_handle->setFPS(_fps->value()); _handle->setFPS(_fps->value());
_handle->setPriority(_priority->value()); _handle->setPriority(_priority->value());
_handle->setLoop(_loop->isChecked());
_handle->setHold(_hold->isChecked());
_handle->setFirstFrame(_firstFrame->value());
_handle->setLastFrame(_lastFrame->value());
_handle->setMaskedJoints(_maskedJoints->text().split(QRegExp("\\s*,\\s*"))); _handle->setMaskedJoints(_maskedJoints->text().split(QRegExp("\\s*,\\s*")));
if ((_loop->isChecked() || _hold->isChecked()) && !_handle->isRunning()) {
_handle->start();
}
} }
void AnimationPanel::removeHandle() { void AnimationPanel::removeHandle() {

View file

@ -17,9 +17,11 @@
#include "avatar/MyAvatar.h" #include "avatar/MyAvatar.h"
class QCheckBox;
class QDoubleSpinner; class QDoubleSpinner;
class QLineEdit; class QLineEdit;
class QPushButton; class QPushButton;
class QSpinBox;
class QVBoxLayout; class QVBoxLayout;
/// Allows users to edit the avatar animations. /// Allows users to edit the avatar animations.
@ -64,6 +66,10 @@ private:
QLineEdit* _url; QLineEdit* _url;
QDoubleSpinBox* _fps; QDoubleSpinBox* _fps;
QDoubleSpinBox* _priority; QDoubleSpinBox* _priority;
QCheckBox* _loop;
QCheckBox* _hold;
QSpinBox* _firstFrame;
QSpinBox* _lastFrame;
QLineEdit* _maskedJoints; QLineEdit* _maskedJoints;
QPushButton* _chooseMaskedJoints; QPushButton* _chooseMaskedJoints;
bool _applying; bool _applying;