From 0e15c82e49e60b61c8b6c1cd6e795e10b429655f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 May 2014 11:58:20 -0700 Subject: [PATCH 1/3] Allow setting masked joints for each animation. --- interface/src/avatar/MyAvatar.cpp | 2 ++ interface/src/renderer/Model.cpp | 14 ++++++++++++++ interface/src/renderer/Model.h | 4 ++++ interface/src/ui/AnimationsDialog.cpp | 28 +++++++++++++++++++++++++++ interface/src/ui/AnimationsDialog.h | 3 +++ 5 files changed, 51 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 181814d127..a886ad4503 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -513,6 +513,7 @@ void MyAvatar::saveData(QSettings* settings) { settings->setValue("url", pointer->getURL()); settings->setValue("fps", pointer->getFPS()); settings->setValue("priority", pointer->getPriority()); + settings->setValue("maskedJoints", pointer->getMaskedJoints()); } settings->endArray(); @@ -579,6 +580,7 @@ void MyAvatar::loadData(QSettings* settings) { handle->setURL(settings->value("url").toUrl()); handle->setFPS(loadSetting(settings, "fps", 30.0f)); handle->setPriority(loadSetting(settings, "priority", 1.0f)); + handle->setMaskedJoints(settings->value("maskedJoints").toStringList()); } settings->endArray(); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 7bef1fd959..900d7ff951 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1684,6 +1684,11 @@ void AnimationHandle::setPriority(float priority) { } } +void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) { + _maskedJoints = maskedJoints; + _jointMappings.clear(); +} + void AnimationHandle::setRunning(bool running) { if ((_running = running)) { if (!_model->_runningAnimations.contains(_self)) { @@ -1716,6 +1721,15 @@ void AnimationHandle::simulate(float deltaTime) { if (_jointMappings.isEmpty()) { return; } + if (!_maskedJoints.isEmpty()) { + const FBXGeometry& geometry = _model->getGeometry()->getFBXGeometry(); + for (int i = 0; i < _jointMappings.size(); i++) { + int& mapping = _jointMappings[i]; + if (mapping != -1 && _maskedJoints.contains(geometry.joints.at(mapping).name)) { + mapping = -1; + } + } + } } const FBXGeometry& animationGeometry = _animation->getGeometry(); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index feef91f703..59ec50cac1 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -393,6 +393,9 @@ public: void setLoop(bool loop) { _loop = loop; } bool getLoop() const { return _loop; } + void setMaskedJoints(const QStringList& maskedJoints); + const QStringList& getMaskedJoints() const { return _maskedJoints; } + void setRunning(bool running); bool isRunning() const { return _running; } @@ -414,6 +417,7 @@ private: float _fps; float _priority; bool _loop; + QStringList _maskedJoints; bool _running; QVector _jointMappings; float _frameIndex; diff --git a/interface/src/ui/AnimationsDialog.cpp b/interface/src/ui/AnimationsDialog.cpp index a9341fa283..29837f67be 100644 --- a/interface/src/ui/AnimationsDialog.cpp +++ b/interface/src/ui/AnimationsDialog.cpp @@ -100,6 +100,13 @@ AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePo _priority->setValue(handle->getPriority()); connect(_priority, SIGNAL(valueChanged(double)), SLOT(updateHandle())); + QHBoxLayout* maskedJointBox = new QHBoxLayout(); + layout->addRow("Masked Joints:", maskedJointBox); + maskedJointBox->addWidget(_maskedJoints = new QLineEdit(handle->getMaskedJoints().join(", ")), 1); + connect(_maskedJoints, SIGNAL(returnPressed()), SLOT(updateHandle())); + maskedJointBox->addWidget(_chooseMaskedJoints = new QPushButton("Choose")); + connect(_chooseMaskedJoints, SIGNAL(clicked(bool)), SLOT(chooseMaskedJoints())); + QPushButton* remove = new QPushButton("Delete"); layout->addRow(remove); connect(remove, SIGNAL(clicked(bool)), SLOT(removeHandle())); @@ -118,10 +125,31 @@ void AnimationPanel::chooseURL() { emit _url->returnPressed(); } +void AnimationPanel::chooseMaskedJoints() { + QMenu menu; + QStringList maskedJoints = _handle->getMaskedJoints(); + foreach (const QString& jointName, Application::getInstance()->getAvatar()->getJointNames()) { + QAction* action = menu.addAction(jointName); + action->setCheckable(true); + action->setChecked(maskedJoints.contains(jointName)); + } + QAction* action = menu.exec(_chooseMaskedJoints->mapToGlobal(QPoint(0, 0))); + if (action) { + if (action->isChecked()) { + maskedJoints.append(action->text()); + } else { + maskedJoints.removeOne(action->text()); + } + _handle->setMaskedJoints(maskedJoints); + _maskedJoints->setText(maskedJoints.join(", ")); + } +} + void AnimationPanel::updateHandle() { _handle->setURL(_url->text()); _handle->setFPS(_fps->value()); _handle->setPriority(_priority->value()); + _handle->setMaskedJoints(_maskedJoints->text().split(QRegExp("\\s*,\\s*"))); } void AnimationPanel::removeHandle() { diff --git a/interface/src/ui/AnimationsDialog.h b/interface/src/ui/AnimationsDialog.h index 5491418f6d..7693a1da97 100644 --- a/interface/src/ui/AnimationsDialog.h +++ b/interface/src/ui/AnimationsDialog.h @@ -53,6 +53,7 @@ public: private slots: void chooseURL(); + void chooseMaskedJoints(); void updateHandle(); void removeHandle(); @@ -63,6 +64,8 @@ private: QLineEdit* _url; QDoubleSpinBox* _fps; QDoubleSpinBox* _priority; + QLineEdit* _maskedJoints; + QPushButton* _chooseMaskedJoints; bool _applying; }; From 709a9d75f6cc6e0d7633cd2f663fbf7534b660ee Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 May 2014 12:03:47 -0700 Subject: [PATCH 2/3] Provide an option for the masked joints in the scriptable method, fix a couple of annoying warnings. --- interface/src/avatar/MyAvatar.cpp | 5 +++-- interface/src/avatar/MyAvatar.h | 2 +- interface/src/ui/NodeBounds.cpp | 2 -- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a886ad4503..be88a80b90 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -441,10 +441,10 @@ void MyAvatar::removeAnimationHandle(const AnimationHandlePointer& handle) { _animationHandles.removeOne(handle); } -void MyAvatar::startAnimation(const QString& url, float fps, float priority, bool loop) { +void MyAvatar::startAnimation(const QString& url, float fps, float priority, bool loop, const QStringList& maskedJoints) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "startAnimation", Q_ARG(const QString&, url), - Q_ARG(float, fps), Q_ARG(float, priority), Q_ARG(bool, loop)); + Q_ARG(float, fps), Q_ARG(float, priority), Q_ARG(bool, loop), Q_ARG(const QStringList&, maskedJoints)); return; } AnimationHandlePointer handle = _skeletonModel.createAnimationHandle(); @@ -452,6 +452,7 @@ void MyAvatar::startAnimation(const QString& url, float fps, float priority, boo handle->setFPS(fps); handle->setPriority(priority); handle->setLoop(loop); + handle->setMaskedJoints(maskedJoints); handle->start(); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 11493524ca..9d6f22264f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -68,7 +68,7 @@ public: /// Allows scripts to run animations. 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()); /// Stops an animation as identified by a URL. Q_INVOKABLE void stopAnimation(const QString& url); diff --git a/interface/src/ui/NodeBounds.cpp b/interface/src/ui/NodeBounds.cpp index 735dc66ddf..c4139f39c5 100644 --- a/interface/src/ui/NodeBounds.cpp +++ b/interface/src/ui/NodeBounds.cpp @@ -133,7 +133,6 @@ void NodeBounds::draw() { glTranslatef(selectedCenter.x, selectedCenter.y, selectedCenter.z); glScalef(selectedScale, selectedScale, selectedScale); - NodeType_t selectedNodeType = selectedNode->getType(); float red, green, blue; getColorForNodeType(selectedNode->getType(), red, green, blue); @@ -225,7 +224,6 @@ void NodeBounds::drawOverlay() { const int FONT = 2; const int PADDING = 10; const int MOUSE_OFFSET = 10; - const int BACKGROUND_OFFSET_Y = -20; const int BACKGROUND_BEVEL = 3; int mouseX = application->getMouseX(), From 906e082215fb4b8c988689d3b2ae7b10b981e7f5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 May 2014 13:56:20 -0700 Subject: [PATCH 3/3] If there are no animation frames in the model, treat its default position as a single frame. --- libraries/fbx/src/FBXReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index d8663055cd..37a03bcdee 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1442,7 +1442,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } // figure the number of animation frames from the curves - int frameCount = 0; + int frameCount = 1; foreach (const AnimationCurve& curve, animationCurves) { frameCount = qMax(frameCount, curve.values.size()); }