From 8cbad1bf548049fb3c2593e147fd8c750514d716 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 15 Apr 2014 19:37:28 -0700 Subject: [PATCH] More work on animation loading. --- examples/crazylegs.js | 14 +++++ interface/src/Application.cpp | 1 + interface/src/Application.h | 1 + libraries/fbx/src/FBXReader.cpp | 2 + libraries/fbx/src/FBXReader.h | 3 + .../script-engine/src/AnimationCache.cpp | 55 ++++++++++++++++++- libraries/script-engine/src/AnimationCache.h | 41 +++++++++++++- libraries/script-engine/src/ScriptEngine.cpp | 2 + 8 files changed, 117 insertions(+), 2 deletions(-) diff --git a/examples/crazylegs.js b/examples/crazylegs.js index 6311aea6e4..3554def63a 100644 --- a/examples/crazylegs.js +++ b/examples/crazylegs.js @@ -22,6 +22,8 @@ for (var i = 0; i < jointList.length; i++) { } print("# Joint list end"); +var foo = AnimationCache.getAnimation("http://www.fungibleinsight.com/faces/hip_hop_dancing_2.fbx"); + Script.update.connect(function(deltaTime) { cumulativeTime += deltaTime; MyAvatar.setJointData("joint_R_hip", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); @@ -30,6 +32,18 @@ Script.update.connect(function(deltaTime) { AMPLITUDE * (1.0 + Math.sin(cumulativeTime * FREQUENCY)))); MyAvatar.setJointData("joint_L_knee", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * (1.0 - Math.sin(cumulativeTime * FREQUENCY)))); + + if (foo.jointNames.length > 0) { + print(foo.jointNames); + print(foo.frames.length); + if (foo.frames.length > 0) { + print(foo.frames[0].rotations.length); + if (foo.frames[0].rotations.length > 0) { + var rot = foo.frames[0].rotations[0]; + print(rot.x + " " + rot.y + " " + rot.z + " " + rot.w); + } + } + } }); Script.scriptEnding.connect(function() { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1fabca3711..91fdff96b5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3387,6 +3387,7 @@ void Application::loadScript(const QString& scriptName) { scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); + scriptEngine->registerGlobalObject("AnimationCache", &_animationCache); QThread* workerThread = new QThread(this); diff --git a/interface/src/Application.h b/interface/src/Application.h index 6a14788caa..4606a3d622 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -468,6 +468,7 @@ private: QSet _keysPressed; GeometryCache _geometryCache; + AnimationCache _animationCache; TextureCache _textureCache; GlowEffect _glowEffect; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 6c51e11150..5fad95be3d 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -72,6 +72,8 @@ bool FBXGeometry::hasBlendedMeshes() const { } static int fbxGeometryMetaTypeId = qRegisterMetaType(); +static int fbxAnimationFrameMetaTypeId = qRegisterMetaType(); +static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType >(); template QVariant readBinaryArray(QDataStream& in) { quint32 arrayLength; diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 8d45c2ae23..2f840e868e 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -146,6 +146,9 @@ public: QVector rotations; }; +Q_DECLARE_METATYPE(FBXAnimationFrame) +Q_DECLARE_METATYPE(QVector) + /// An attachment to an FBX document. class FBXAttachment { public: diff --git a/libraries/script-engine/src/AnimationCache.cpp b/libraries/script-engine/src/AnimationCache.cpp index 2a6aac1992..078dc382c4 100644 --- a/libraries/script-engine/src/AnimationCache.cpp +++ b/libraries/script-engine/src/AnimationCache.cpp @@ -10,11 +10,20 @@ // #include +#include #include #include "AnimationCache.h" -QSharedPointer AnimationCache::getAnimation(const QUrl& url) { +static int animationPointerMetaTypeId = qRegisterMetaType(); + +AnimationPointer AnimationCache::getAnimation(const QUrl& url) { + if (QThread::currentThread() != thread()) { + AnimationPointer result; + QMetaObject::invokeMethod(this, "getAnimation", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(AnimationPointer, result), Q_ARG(const QUrl&, url)); + return result; + } return getResource(url).staticCast(); } @@ -54,6 +63,30 @@ void AnimationReader::run() { _reply->deleteLater(); } +QStringList Animation::getJointNames() const { + if (QThread::currentThread() != thread()) { + QStringList result; + QMetaObject::invokeMethod(const_cast(this), "getJointNames", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QStringList, result)); + return result; + } + QStringList names; + foreach (const FBXJoint& joint, _geometry.joints) { + names.append(joint.name); + } + return names; +} + +QVector Animation::getFrames() const { + if (QThread::currentThread() != thread()) { + QVector result; + QMetaObject::invokeMethod(const_cast(this), "getFrames", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVector, result)); + return result; + } + return _geometry.animationFrames; +} + void Animation::setGeometry(const FBXGeometry& geometry) { _geometry = geometry; finishedLoading(true); @@ -63,3 +96,23 @@ void Animation::downloadFinished(QNetworkReply* reply) { // send the reader off to the thread pool QThreadPool::globalInstance()->start(new AnimationReader(_self, reply)); } + +QStringList AnimationObject::getJointNames() const { + return qscriptvalue_cast(thisObject())->getJointNames(); +} + +QVector AnimationObject::getFrames() const { + return qscriptvalue_cast(thisObject())->getFrames(); +} + +QVector AnimationFrameObject::getRotations() const { + return qscriptvalue_cast(thisObject()).rotations; +} + +void registerAnimationTypes(QScriptEngine* engine) { + qScriptRegisterSequenceMetaType >(engine); + engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject( + new AnimationFrameObject(), QScriptEngine::ScriptOwnership)); + engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject( + new AnimationObject(), QScriptEngine::ScriptOwnership)); +} diff --git a/libraries/script-engine/src/AnimationCache.h b/libraries/script-engine/src/AnimationCache.h index bb8a0f2313..a382ef40d7 100644 --- a/libraries/script-engine/src/AnimationCache.h +++ b/libraries/script-engine/src/AnimationCache.h @@ -12,19 +12,27 @@ #ifndef hifi_AnimationCache_h #define hifi_AnimationCache_h +#include + #include #include +class QScriptEngine; + class Animation; +typedef QSharedPointer AnimationPointer; + /// Scriptable interface for FBX animation loading. class AnimationCache : public ResourceCache { Q_OBJECT public: - QSharedPointer getAnimation(const QUrl& url); + Q_INVOKABLE AnimationPointer getAnimation(const QString& url) { return getAnimation(QUrl(url)); } + + Q_INVOKABLE AnimationPointer getAnimation(const QUrl& url); protected: @@ -32,6 +40,8 @@ protected: const QSharedPointer& fallback, bool delayLoad, const void* extra); }; +Q_DECLARE_METATYPE(AnimationPointer) + /// An animation loaded from the network. class Animation : public Resource { Q_OBJECT @@ -42,6 +52,10 @@ public: const FBXGeometry& getGeometry() const { return _geometry; } + Q_INVOKABLE QStringList getJointNames() const; + + Q_INVOKABLE QVector getFrames() const; + protected: Q_INVOKABLE void setGeometry(const FBXGeometry& geometry); @@ -53,4 +67,29 @@ private: FBXGeometry _geometry; }; +/// Scriptable wrapper for animation pointers. +class AnimationObject : public QObject, protected QScriptable { + Q_OBJECT + Q_PROPERTY(QStringList jointNames READ getJointNames) + Q_PROPERTY(QVector frames READ getFrames) + +public: + + Q_INVOKABLE QStringList getJointNames() const; + + Q_INVOKABLE QVector getFrames() const; +}; + +/// Scriptable wrapper for animation frames. +class AnimationFrameObject : public QObject, protected QScriptable { + Q_OBJECT + Q_PROPERTY(QVector rotations READ getRotations) + +public: + + Q_INVOKABLE QVector getRotations() const; +}; + +void registerAnimationTypes(QScriptEngine* engine); + #endif // hifi_AnimationCache_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index b0e2d1495b..60321e7c54 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -180,11 +180,13 @@ void ScriptEngine::init() { registerVoxelMetaTypes(&_engine); registerEventTypes(&_engine); registerMenuItemProperties(&_engine); + registerAnimationTypes(&_engine); qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); qScriptRegisterSequenceMetaType >(&_engine); qScriptRegisterSequenceMetaType >(&_engine); + qScriptRegisterSequenceMetaType >(&_engine); qScriptRegisterSequenceMetaType >(&_engine); QScriptValue soundConstructorValue = _engine.newFunction(soundConstructor);