Fix for animation resources

The problem was that the invokeMethod between the AnimationReader thread
and the main thread was failing, because FBXGeometry* wasn't a registered meta type.

So, I ended up normalizing the AnimationReader class to be more like GeometryReader,
in that it uses singles and slots to communicate success and failure, rather then
invokeMethod.
This commit is contained in:
Anthony J. Thibault 2015-08-21 16:09:06 -07:00
parent 0fb2390877
commit b7009b4631
6 changed files with 77 additions and 40 deletions

View file

@ -8,6 +8,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";
progressDialog = (function () {
var that = {},
@ -142,4 +144,4 @@ progressDialog = (function () {
that.cleanup = cleanup;
return that;
}());
}());

View file

@ -39,35 +39,44 @@ QSharedPointer<Resource> AnimationCache::createResource(const QUrl& url, const Q
return QSharedPointer<Resource>(new Animation(url), &Resource::allReferencesCleared);
}
Animation::Animation(const QUrl& url) : Resource(url) {}
class AnimationReader : public QRunnable {
public:
AnimationReader(const QWeakPointer<Resource>& animation, QNetworkReply* reply);
virtual void run();
private:
QWeakPointer<Resource> _animation;
QNetworkReply* _reply;
};
AnimationReader::AnimationReader(const QWeakPointer<Resource>& animation, QNetworkReply* reply) :
_animation(animation),
AnimationReader::AnimationReader(const QUrl& url, QNetworkReply* reply) :
_url(url),
_reply(reply) {
}
void AnimationReader::run() {
QSharedPointer<Resource> animation = _animation.toStrongRef();
if (!animation.isNull()) {
QMetaObject::invokeMethod(animation.data(), "setGeometry",
Q_ARG(FBXGeometry*, readFBX(_reply->readAll(), QVariantHash(), _reply->property("url").toString())));
try {
if (!_reply) {
throw QString("Reply is NULL ?!");
}
QString urlname = _url.path().toLower();
bool urlValid = true;
urlValid &= !urlname.isEmpty();
urlValid &= !_url.path().isEmpty();
urlValid &= _url.path().toLower().endsWith(".fbx");
if (urlValid) {
// Let's read the binaries from the network
FBXGeometry* fbxgeo = nullptr;
if (_url.path().toLower().endsWith(".fbx")) {
fbxgeo = readFBX(_reply, QVariantHash(), _url.path());
} else {
QString errorStr("usupported format");
emit onError(299, errorStr);
}
emit onSuccess(fbxgeo);
} else {
throw QString("url is invalid");
}
} catch (const QString& error) {
emit onError(299, error);
}
_reply->deleteLater();
}
Animation::Animation(const QUrl& url) : Resource(url) {}
bool Animation::isLoaded() const {
return _loaded && _geometry;
}
@ -100,17 +109,27 @@ const QVector<FBXAnimationFrame>& Animation::getFramesReference() const {
return _geometry->animationFrames;
}
void Animation::setGeometry(FBXGeometry* geometry) {
void Animation::downloadFinished(QNetworkReply* reply) {
// parse the animation/fbx file on a background thread.
AnimationReader* animationReader = new AnimationReader(reply->url(), reply);
connect(animationReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(animationParseSuccess(FBXGeometry*)));
connect(animationReader, SIGNAL(onError(int, QString)), SLOT(animationParseError(int, QString)));
QThreadPool::globalInstance()->start(animationReader);
}
void Animation::animationParseSuccess(FBXGeometry* geometry) {
qCDebug(animation) << "Animation parse success" << _url.toDisplayString();
_geometry.reset(geometry);
finishedLoading(true);
}
void Animation::downloadFinished(QNetworkReply* reply) {
// send the reader off to the thread pool
QThreadPool::globalInstance()->start(new AnimationReader(_self, reply));
void Animation::animationParseError(int error, QString str) {
qCCritical(animation) << "Animation failure parsing " << _url.toDisplayString() << "code =" << error << str;
emit failed(QNetworkReply::UnknownContentError);
}
AnimationDetails::AnimationDetails() :
role(), url(), fps(0.0f), priority(0.0f), loop(false), hold(false),
startAutomatically(false), firstFrame(0.0f), lastFrame(0.0f), running(false), frameIndex(0.0f)

View file

@ -12,6 +12,7 @@
#ifndef hifi_AnimationCache_h
#define hifi_AnimationCache_h
#include <QRunnable>
#include <QScriptEngine>
#include <QScriptValue>
@ -64,16 +65,33 @@ public:
const QVector<FBXAnimationFrame>& getFramesReference() const;
protected:
Q_INVOKABLE void setGeometry(FBXGeometry* geometry);
virtual void downloadFinished(QNetworkReply* reply);
protected slots:
void animationParseSuccess(FBXGeometry* geometry);
void animationParseError(int error, QString str);
private:
std::unique_ptr<FBXGeometry> _geometry;
};
/// Reads geometry in a worker thread.
class AnimationReader : public QObject, public QRunnable {
Q_OBJECT
public:
AnimationReader(const QUrl& url, QNetworkReply* reply);
virtual void run();
signals:
void onSuccess(FBXGeometry* geometry);
void onError(int error, QString str);
private:
QUrl _url;
QNetworkReply* _reply;
};
class AnimationDetails {
public:

View file

@ -15,6 +15,7 @@
void AnimationHandle::setURL(const QUrl& url) {
if (_url != url) {
_animation = DependencyManager::get<AnimationCache>()->getAnimation(_url = url);
_animation->ensureLoading();
QObject::connect(_animation.data(), &Resource::onRefresh, this, &AnimationHandle::clearJoints);
_jointMappings.clear();
}

View file

@ -182,7 +182,7 @@ QString FBXGeometry::getModelNameOfMesh(int meshIndex) const {
static int fbxGeometryMetaTypeId = qRegisterMetaType<FBXGeometry>();
static int fbxAnimationFrameMetaTypeId = qRegisterMetaType<FBXAnimationFrame>();
static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<FBXAnimationFrame> >();
static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<FBXAnimationFrame>>();
template<class T> int streamSize() {
return sizeof(T);
@ -1858,12 +1858,18 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
foreach (const FBXNode& subobject, object.children) {
if (subobject.name == "RelativeFilename") {
QByteArray filename = subobject.properties.at(0).toByteArray();
qCDebug(modelformat) << "AJT: RelativeFilename, filename =" << filename;
filename = fileOnUrl(filename, url);
qCDebug(modelformat) << "AJT: url = " << url;
qCDebug(modelformat) << "AJT: filename2 = " << filename;
textureFilenames.insert(getID(object.properties), filename);
} else if (subobject.name == "TextureName") {
// trim the name from the timestamp
QString name = QString(subobject.properties.at(0).toByteArray());
qCDebug(modelformat) << "AJT: TextureName, name =" << name;
name = name.left(name.indexOf('['));
qCDebug(modelformat) << "AJT: name2 =" << name;
textureNames.insert(getID(object.properties), name);
} else if (subobject.name == "Texture_Alpha_Source") {
tex.assign<uint8_t>(tex.alphaSource, subobject.properties.at(0).value<int>());

View file

@ -21,8 +21,6 @@
#include "FBXReader.h"
#include "OBJReader.h"
#include <AnimationCache.h>
#include <gpu/Batch.h>
#include <gpu/Stream.h>
@ -383,20 +381,13 @@ protected:
/// Reads geometry in a worker thread.
class GeometryReader : public QObject, public QRunnable {
Q_OBJECT
public:
GeometryReader(const QUrl& url, QNetworkReply* reply, const QVariantHash& mapping);
virtual void run();
signals:
void onSuccess(FBXGeometry* geometry);
void onError(int error, QString str);
private:
QWeakPointer<Resource> _geometry;
QUrl _url;
QNetworkReply* _reply;
QVariantHash _mapping;