mirror of
https://github.com/overte-org/overte.git
synced 2025-06-27 08:09:58 +02:00
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:
parent
0fb2390877
commit
b7009b4631
6 changed files with 77 additions and 40 deletions
|
@ -8,6 +8,8 @@
|
||||||
// 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
|
||||||
//
|
//
|
||||||
|
|
||||||
|
var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
|
var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";
|
||||||
|
|
||||||
progressDialog = (function () {
|
progressDialog = (function () {
|
||||||
var that = {},
|
var that = {},
|
||||||
|
|
|
@ -39,35 +39,44 @@ QSharedPointer<Resource> AnimationCache::createResource(const QUrl& url, const Q
|
||||||
return QSharedPointer<Resource>(new Animation(url), &Resource::allReferencesCleared);
|
return QSharedPointer<Resource>(new Animation(url), &Resource::allReferencesCleared);
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation::Animation(const QUrl& url) : Resource(url) {}
|
AnimationReader::AnimationReader(const QUrl& url, QNetworkReply* reply) :
|
||||||
|
_url(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),
|
|
||||||
_reply(reply) {
|
_reply(reply) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationReader::run() {
|
void AnimationReader::run() {
|
||||||
QSharedPointer<Resource> animation = _animation.toStrongRef();
|
try {
|
||||||
if (!animation.isNull()) {
|
if (!_reply) {
|
||||||
QMetaObject::invokeMethod(animation.data(), "setGeometry",
|
throw QString("Reply is NULL ?!");
|
||||||
Q_ARG(FBXGeometry*, readFBX(_reply->readAll(), QVariantHash(), _reply->property("url").toString())));
|
}
|
||||||
|
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();
|
_reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Animation::Animation(const QUrl& url) : Resource(url) {}
|
||||||
|
|
||||||
bool Animation::isLoaded() const {
|
bool Animation::isLoaded() const {
|
||||||
return _loaded && _geometry;
|
return _loaded && _geometry;
|
||||||
}
|
}
|
||||||
|
@ -100,17 +109,27 @@ const QVector<FBXAnimationFrame>& Animation::getFramesReference() const {
|
||||||
return _geometry->animationFrames;
|
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);
|
_geometry.reset(geometry);
|
||||||
finishedLoading(true);
|
finishedLoading(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::downloadFinished(QNetworkReply* reply) {
|
void Animation::animationParseError(int error, QString str) {
|
||||||
// send the reader off to the thread pool
|
qCCritical(animation) << "Animation failure parsing " << _url.toDisplayString() << "code =" << error << str;
|
||||||
QThreadPool::globalInstance()->start(new AnimationReader(_self, reply));
|
emit failed(QNetworkReply::UnknownContentError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AnimationDetails::AnimationDetails() :
|
AnimationDetails::AnimationDetails() :
|
||||||
role(), url(), fps(0.0f), priority(0.0f), loop(false), hold(false),
|
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)
|
startAutomatically(false), firstFrame(0.0f), lastFrame(0.0f), running(false), frameIndex(0.0f)
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifndef hifi_AnimationCache_h
|
#ifndef hifi_AnimationCache_h
|
||||||
#define hifi_AnimationCache_h
|
#define hifi_AnimationCache_h
|
||||||
|
|
||||||
|
#include <QRunnable>
|
||||||
#include <QScriptEngine>
|
#include <QScriptEngine>
|
||||||
#include <QScriptValue>
|
#include <QScriptValue>
|
||||||
|
|
||||||
|
@ -64,16 +65,33 @@ public:
|
||||||
const QVector<FBXAnimationFrame>& getFramesReference() const;
|
const QVector<FBXAnimationFrame>& getFramesReference() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Q_INVOKABLE void setGeometry(FBXGeometry* geometry);
|
|
||||||
|
|
||||||
virtual void downloadFinished(QNetworkReply* reply);
|
virtual void downloadFinished(QNetworkReply* reply);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void animationParseSuccess(FBXGeometry* geometry);
|
||||||
|
void animationParseError(int error, QString str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::unique_ptr<FBXGeometry> _geometry;
|
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 {
|
class AnimationDetails {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
void AnimationHandle::setURL(const QUrl& url) {
|
void AnimationHandle::setURL(const QUrl& url) {
|
||||||
if (_url != url) {
|
if (_url != url) {
|
||||||
_animation = DependencyManager::get<AnimationCache>()->getAnimation(_url = url);
|
_animation = DependencyManager::get<AnimationCache>()->getAnimation(_url = url);
|
||||||
|
_animation->ensureLoading();
|
||||||
QObject::connect(_animation.data(), &Resource::onRefresh, this, &AnimationHandle::clearJoints);
|
QObject::connect(_animation.data(), &Resource::onRefresh, this, &AnimationHandle::clearJoints);
|
||||||
_jointMappings.clear();
|
_jointMappings.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,7 @@ QString FBXGeometry::getModelNameOfMesh(int meshIndex) const {
|
||||||
|
|
||||||
static int fbxGeometryMetaTypeId = qRegisterMetaType<FBXGeometry>();
|
static int fbxGeometryMetaTypeId = qRegisterMetaType<FBXGeometry>();
|
||||||
static int fbxAnimationFrameMetaTypeId = qRegisterMetaType<FBXAnimationFrame>();
|
static int fbxAnimationFrameMetaTypeId = qRegisterMetaType<FBXAnimationFrame>();
|
||||||
static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<FBXAnimationFrame> >();
|
static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<FBXAnimationFrame>>();
|
||||||
|
|
||||||
template<class T> int streamSize() {
|
template<class T> int streamSize() {
|
||||||
return sizeof(T);
|
return sizeof(T);
|
||||||
|
@ -1858,12 +1858,18 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
||||||
foreach (const FBXNode& subobject, object.children) {
|
foreach (const FBXNode& subobject, object.children) {
|
||||||
if (subobject.name == "RelativeFilename") {
|
if (subobject.name == "RelativeFilename") {
|
||||||
QByteArray filename = subobject.properties.at(0).toByteArray();
|
QByteArray filename = subobject.properties.at(0).toByteArray();
|
||||||
|
qCDebug(modelformat) << "AJT: RelativeFilename, filename =" << filename;
|
||||||
filename = fileOnUrl(filename, url);
|
filename = fileOnUrl(filename, url);
|
||||||
|
qCDebug(modelformat) << "AJT: url = " << url;
|
||||||
|
qCDebug(modelformat) << "AJT: filename2 = " << filename;
|
||||||
|
|
||||||
textureFilenames.insert(getID(object.properties), filename);
|
textureFilenames.insert(getID(object.properties), filename);
|
||||||
} else if (subobject.name == "TextureName") {
|
} else if (subobject.name == "TextureName") {
|
||||||
// trim the name from the timestamp
|
// trim the name from the timestamp
|
||||||
QString name = QString(subobject.properties.at(0).toByteArray());
|
QString name = QString(subobject.properties.at(0).toByteArray());
|
||||||
|
qCDebug(modelformat) << "AJT: TextureName, name =" << name;
|
||||||
name = name.left(name.indexOf('['));
|
name = name.left(name.indexOf('['));
|
||||||
|
qCDebug(modelformat) << "AJT: name2 =" << name;
|
||||||
textureNames.insert(getID(object.properties), name);
|
textureNames.insert(getID(object.properties), name);
|
||||||
} else if (subobject.name == "Texture_Alpha_Source") {
|
} else if (subobject.name == "Texture_Alpha_Source") {
|
||||||
tex.assign<uint8_t>(tex.alphaSource, subobject.properties.at(0).value<int>());
|
tex.assign<uint8_t>(tex.alphaSource, subobject.properties.at(0).value<int>());
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
#include "FBXReader.h"
|
#include "FBXReader.h"
|
||||||
#include "OBJReader.h"
|
#include "OBJReader.h"
|
||||||
|
|
||||||
#include <AnimationCache.h>
|
|
||||||
|
|
||||||
#include <gpu/Batch.h>
|
#include <gpu/Batch.h>
|
||||||
#include <gpu/Stream.h>
|
#include <gpu/Stream.h>
|
||||||
|
|
||||||
|
@ -383,20 +381,13 @@ protected:
|
||||||
/// Reads geometry in a worker thread.
|
/// Reads geometry in a worker thread.
|
||||||
class GeometryReader : public QObject, public QRunnable {
|
class GeometryReader : public QObject, public QRunnable {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GeometryReader(const QUrl& url, QNetworkReply* reply, const QVariantHash& mapping);
|
GeometryReader(const QUrl& url, QNetworkReply* reply, const QVariantHash& mapping);
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void onSuccess(FBXGeometry* geometry);
|
void onSuccess(FBXGeometry* geometry);
|
||||||
void onError(int error, QString str);
|
void onError(int error, QString str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QWeakPointer<Resource> _geometry;
|
|
||||||
QUrl _url;
|
QUrl _url;
|
||||||
QNetworkReply* _reply;
|
QNetworkReply* _reply;
|
||||||
QVariantHash _mapping;
|
QVariantHash _mapping;
|
||||||
|
|
Loading…
Reference in a new issue