diff options
author | dpope <daniel.pope@nokia.com> | 2012-03-30 19:26:27 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-04-04 10:56:35 +0200 |
commit | d3768a83cd473bb407f8b1c8e87ed36d1875e704 (patch) | |
tree | a573078c9e02ad82fdd02c0977c0e2c1830c7775 /src/plugins | |
parent | 749f3d9491b928a3ecd51a48565332c930b974ae (diff) |
Network loading of textures and models.
Task-number: QTBUG-20054
Change-Id: I0624a815ad182bae7d812125e835426fb76f6b44
Reviewed-by: Sarah Jane Smith <sarah.j.smith@nokia.com>
Diffstat (limited to 'src/plugins')
10 files changed, 208 insertions, 9 deletions
diff --git a/src/plugins/sceneformats/assimp/ailoaderiosystem.cpp b/src/plugins/sceneformats/assimp/ailoaderiosystem.cpp index 661ccd8c1..50b00dcf6 100644 --- a/src/plugins/sceneformats/assimp/ailoaderiosystem.cpp +++ b/src/plugins/sceneformats/assimp/ailoaderiosystem.cpp @@ -60,7 +60,7 @@ AiLoaderIOSystem::~AiLoaderIOSystem() bool AiLoaderIOSystem::Exists(const char* path) const { - return QFile::exists(QLatin1String(path)); + return m_device->isReadable(); } char AiLoaderIOSystem::getOsSeparator() const @@ -87,7 +87,10 @@ Assimp::IOStream* AiLoaderIOSystem::Open(const char* pFile, const char* pMode) // TODO: handle network case if (url.scheme() != QLatin1String("file")) { - qWarning("Opening %s url not supported", qPrintable(url.scheme())); + //network cases should already be opened by this stage - they + //depend entirely on the download manager returning a QBuffer, so + //cannot be handled as the simple "open file" case shown below. + qWarning("Directly opening a network URL is not supported. Use scene handler code. (URL: %s).", qPrintable(url.scheme())); return 0; } diff --git a/src/plugins/sceneformats/assimp/qailoader.h b/src/plugins/sceneformats/assimp/qailoader.h index ad620d2a1..988ba224e 100644 --- a/src/plugins/sceneformats/assimp/qailoader.h +++ b/src/plugins/sceneformats/assimp/qailoader.h @@ -55,6 +55,7 @@ struct aiMaterial; QT_BEGIN_NAMESPACE class QAiMesh; +class QAiScene; class QGLSceneNode; class QAiSceneHandler; class QGLSceneAnimation; @@ -69,6 +70,8 @@ public: QList<QGLSceneAnimation *> loadAnimations(); private: + friend class QAiScene; + void loadMesh(aiMesh *); void loadNodes(aiNode *, QGLSceneNode *); void loadMaterial(aiMaterial *); diff --git a/src/plugins/sceneformats/assimp/qaiscene.cpp b/src/plugins/sceneformats/assimp/qaiscene.cpp index ada229b73..5634855f9 100644 --- a/src/plugins/sceneformats/assimp/qaiscene.cpp +++ b/src/plugins/sceneformats/assimp/qaiscene.cpp @@ -71,6 +71,26 @@ QAiScene::QAiScene(const aiScene *scene, QAiSceneHandler *handler) m_root = loader.loadMeshes(); m_root->setParent(this); m_animations = loader.loadAnimations(); + m_aiLoader = 0; +} + +/*! + \internal + Construct a new QAiScene object and setting the given \a handler. + + Note that the scene which will be used to generate the QAiScene has + not been added yet - this is used in the network case and requires + a later call to the loadScene function to work correctly + + \sa loadScene() +*/ +QAiScene::QAiScene(QAiSceneHandler *handler) + : QGLAbstractScene(0) +{ + Q_ASSERT(handler); + //create a temporary loader and get a temporary root node for the scene. + m_aiLoader = new QAiLoader(0, handler); + m_root=m_aiLoader->m_builder.sceneNode(); } /*! @@ -80,7 +100,7 @@ QAiScene::QAiScene(const aiScene *scene, QAiSceneHandler *handler) */ QAiScene::~QAiScene() { - // nothing to do here + delete m_aiLoader; } /*! @@ -109,6 +129,59 @@ QGLSceneNode *QAiScene::mainNode() const return m_root; } +/*! + \internal + Returns the aiLoader associated with the scene (if any). +*/ +QAiLoader * QAiScene::aiLoader() const +{ + return m_aiLoader; +} + +/*! + \internal + Load the new \a scene and swap the extant palette from the temporary roote + node into the current root node. + + The QAiScene object takes ownership of the \a file. +*/ +void QAiScene::loadScene(const aiScene *scene) +{ + Q_ASSERT(scene); + + //Get the old material information + QSharedPointer<QGLMaterialCollection>oldPalette= m_aiLoader->m_builder.palette(); + int oldIndex = m_root->materialIndex(); + + //Reset the palette for the root node. + QSharedPointer<QGLMaterialCollection>newPalette = QSharedPointer<QGLMaterialCollection>(new QGLMaterialCollection()); + m_aiLoader->m_builder.sceneNode()->setPalette(newPalette); + m_aiLoader->m_scene = scene; + + //Commence loading of the mesh. + m_root = m_aiLoader->loadMeshes(); //this won't actually change the root unless we've messed up. + delete m_aiLoader; + m_aiLoader = 0; + + //Swap out the materials palette + int indexCount=0; + int materialCount=0; + QGLMaterial * currentMaterial = NULL; + do { + currentMaterial = oldPalette->removeMaterial(indexCount); + if (currentMaterial) { + materialCount = m_root->palette()->addMaterial(currentMaterial); + indexCount++; + } + } while (currentMaterial); + m_root->setMaterialIndex(materialCount-(indexCount-1)+oldIndex); + + //update picking nodes for the whole scene if needed + if (pickable()) generatePickNodes(); + + emit sceneUpdated(); +} + QList<QGLSceneAnimation *> QAiScene::animations() const { return m_animations; diff --git a/src/plugins/sceneformats/assimp/qaiscene.h b/src/plugins/sceneformats/assimp/qaiscene.h index 5eb096e29..e1543a595 100644 --- a/src/plugins/sceneformats/assimp/qaiscene.h +++ b/src/plugins/sceneformats/assimp/qaiscene.h @@ -52,24 +52,30 @@ QT_BEGIN_NAMESPACE QT_MODULE(Qt3D) -#include <QtCore/qurl.h> - class QGLSceneNode; class QAiSceneHandler; +class QAiLoader; class QAiScene : public QGLAbstractScene { Q_OBJECT public: explicit QAiScene(const aiScene *scene, QAiSceneHandler *handler); + explicit QAiScene(QAiSceneHandler *handler); virtual ~QAiScene(); + //load a scene with the current handler + void loadScene(const aiScene*scene); + QList<QObject *> objects() const; QGLSceneNode *mainNode() const; QList<QGLSceneAnimation *> animations() const; private: - QGLSceneNode *m_root; + QAiLoader * aiLoader() const; QList<QGLSceneAnimation *> m_animations; +protected: + QGLSceneNode *m_root; + QAiLoader *m_aiLoader; }; QT_END_NAMESPACE diff --git a/src/plugins/sceneformats/assimp/qaiscenehandler.cpp b/src/plugins/sceneformats/assimp/qaiscenehandler.cpp index 1f86fe869..27add9b28 100644 --- a/src/plugins/sceneformats/assimp/qaiscenehandler.cpp +++ b/src/plugins/sceneformats/assimp/qaiscenehandler.cpp @@ -41,6 +41,7 @@ #include "qaiscenehandler.h" #include "qaiscene.h" +#include "qdownloadmanager.h" #include "ailoaderiosystem.h" #include "aiScene.h" @@ -49,6 +50,8 @@ #include <QtCore/qdir.h> #include <QtCore/qdebug.h> +#include <QObject> +#include <QBuffer> #define qAiPostProcessPreset ( \ @@ -235,10 +238,10 @@ QGLAbstractScene *QAiSceneHandler::read() QUrl u = url(); if (u.scheme() != QLatin1String("file")) { - qWarning("Non-file URL's not yet supported"); - return 0; + path = u.toEncoded(); + } else { + path = u.toLocalFile(); } - path = u.toLocalFile(); if (m_removeComponentFlags) m_options |= aiProcess_RemoveComponent; @@ -285,6 +288,7 @@ QGLAbstractScene *QAiSceneHandler::read() Assimp::DefaultLogger::kill(); + finalize(); return qscene; } @@ -352,4 +356,94 @@ void DumpScene(const aiScene* pScene) } } +QGLAbstractScene * QAiSceneHandler::download() +{ + QUrl u = url(); + + if (u.scheme() == QLatin1String("file")) { + qWarning() << "Cannot download urls with FILE scheme. Use the read() method."; + } else { + if (m_removeComponentFlags) + m_options |= aiProcess_RemoveComponent; + else + m_options &= ~aiProcess_RemoveComponent; + + m_importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, m_removeComponentFlags); + m_importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, m_removeSortFlags); + m_importer.SetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT, m_meshSplitVertexLimit); + m_importer.SetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, m_meshSplitTriangleLimit); + + // force this on, and provide no way to turn it off. Its set by the + // aiProcessPreset_TargetRealtime_Quality option in the constructor. + // Guarantees that all meshes only have one primitive type + Q_ASSERT(m_options & aiProcess_SortByPType); + + setScene(new QAiScene(this)); + //m_scene = new QAiScene(this); + + //m_scene->begindownLoad(url()); + + downloadScene(); + } + return getScene(); +} + +void QAiSceneHandler::downloadComplete(QByteArray *sceneData) +{ + //Create i/o device to use for file reading. + QBuffer sceneBuffer(sceneData); + sceneBuffer.open(QIODevice::ReadOnly); + setDevice(&sceneBuffer); + + //Set i/o system to use non-file based device. + AiLoaderIOSystem *ios = new AiLoaderIOSystem(device(), url()); + m_importer.SetIOHandler(ios); + + QString path; + path = url().toEncoded(); + + Assimp::Logger *log = 0; + Assimp::Logger::LogSeverity severity = Assimp::Logger::NORMAL; + if (m_showWarnings) + { + severity = Assimp::Logger::VERBOSE; + int streams = aiDefaultLogStream_FILE | +#ifdef Q_CC_MSVC + aiDefaultLogStream_DEBUGGER +#else + aiDefaultLogStream_STDERR +#endif + ; + log = Assimp::DefaultLogger::create("AssimpLog.txt", severity, streams); + } + + const aiScene* scene = m_importer.ReadFile(path.toStdString(), m_options); + if (!scene) + { + // Notes on import success flags - according to assimp doco if validation + // is requested the flags AI_SCENE_FLAGS_VALIDATION_WARNING will be set + // if there's a warning, and AI_SCENE_FLAGS_VALIDATED is set on success. + // This does not happen. Also AI_SCENE_FLAGS_INCOMPLETE can be set on a + // valid model, so checking for that is no use either. Best way to proceed + // is that if ShowWarnings is turned on above, then any pertinent warnings + // will be shown; and if a NULL result is returned here, then its a fatal + // error and a message is shown here. If a non-NULL result is returned + // just go ahead and try to load it. + QString c = QDir::current().absolutePath(); + qWarning("Asset importer error: %s\n", m_importer.GetErrorString()); + if (log) + qWarning("For details check log: %s/AssimpLog.txt\n", qPrintable(c)); + } else { + //If we have reached this point everything has proceeded correctly, + //load the scene. + QAiScene *theScene = qobject_cast<QAiScene*>(getScene()); + theScene->loadScene(scene); + } + + Assimp::DefaultLogger::kill(); + + delete sceneData; + finalize(); +} + QT_END_NAMESPACE diff --git a/src/plugins/sceneformats/assimp/qaiscenehandler.h b/src/plugins/sceneformats/assimp/qaiscenehandler.h index 94e4eac1d..45c7a2c66 100644 --- a/src/plugins/sceneformats/assimp/qaiscenehandler.h +++ b/src/plugins/sceneformats/assimp/qaiscenehandler.h @@ -48,6 +48,7 @@ #include "assimp.hpp" #include <QtCore/qurl.h> +#include <QObject> Q_DECLARE_FLAGS(aiPostProcessFlags, aiPostProcessSteps); Q_DECLARE_OPERATORS_FOR_FLAGS(aiPostProcessFlags); @@ -59,6 +60,7 @@ class QIODevice; class QAiSceneHandler : public QGLSceneFormatHandler { + Q_OBJECT public: enum Options { NoOptions, @@ -82,6 +84,7 @@ public: ~QAiSceneHandler(); QGLAbstractScene *read(); + QGLAbstractScene *download(); void decodeOptions(const QString &options); @@ -92,6 +95,9 @@ public: quint32 removeComponentFlags() const { return m_removeComponentFlags; } quint32 removeSortFlags() const { return m_removeSortFlags; } +public slots: + void downloadComplete(QByteArray *sceneData); + private: aiPostProcessFlags m_options; bool m_showWarnings; diff --git a/src/plugins/sceneformats/bezier/qglbezierscenehandler.cpp b/src/plugins/sceneformats/bezier/qglbezierscenehandler.cpp index f79b332aa..58ea68c60 100644 --- a/src/plugins/sceneformats/bezier/qglbezierscenehandler.cpp +++ b/src/plugins/sceneformats/bezier/qglbezierscenehandler.cpp @@ -188,4 +188,10 @@ QGLAbstractScene *QGLBezierSceneHandler::read() return new QGLBezierScene(geometry.finalizedSceneNode()); } +QGLAbstractScene *QGLBezierSceneHandler::download() +{ + qWarning() << "Network loading is not supported for .bez files."; + return NULL; +} + QT_END_NAMESPACE diff --git a/src/plugins/sceneformats/bezier/qglbezierscenehandler.h b/src/plugins/sceneformats/bezier/qglbezierscenehandler.h index d07fc47d6..59f8945f9 100644 --- a/src/plugins/sceneformats/bezier/qglbezierscenehandler.h +++ b/src/plugins/sceneformats/bezier/qglbezierscenehandler.h @@ -50,6 +50,7 @@ class QGLBezierSceneHandler : public QGLSceneFormatHandler { public: QGLAbstractScene *read(); + QGLAbstractScene *download(); }; QT_END_NAMESPACE diff --git a/src/plugins/sceneformats/obj/qglobjscenehandler.cpp b/src/plugins/sceneformats/obj/qglobjscenehandler.cpp index 6ae0b7872..aea28126c 100644 --- a/src/plugins/sceneformats/obj/qglobjscenehandler.cpp +++ b/src/plugins/sceneformats/obj/qglobjscenehandler.cpp @@ -326,6 +326,12 @@ QGLAbstractScene *QGLObjSceneHandler::read() return new QGLObjScene(builder.finalizedSceneNode()); } +QGLAbstractScene *QGLObjSceneHandler::download() +{ + qWarning() << "Network loading of obj files using this plugin is not implemented."; + return NULL; +} + void QGLObjSceneHandler::loadMaterialLibrary(const QString& name) { QUrl materialUrl = url().resolved(name); diff --git a/src/plugins/sceneformats/obj/qglobjscenehandler.h b/src/plugins/sceneformats/obj/qglobjscenehandler.h index 1cfd5551f..0f62bc370 100644 --- a/src/plugins/sceneformats/obj/qglobjscenehandler.h +++ b/src/plugins/sceneformats/obj/qglobjscenehandler.h @@ -55,6 +55,7 @@ class QGLObjSceneHandler : public QGLSceneFormatHandler public: QGLObjSceneHandler(); QGLAbstractScene *read(); + QGLAbstractScene *download(); //! [1] void decodeOptions(const QString &options); |