From b1f00d6f22d6a261218fe11efea94d8e0f99bcd1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 11 Apr 2019 16:41:31 -0700 Subject: [PATCH] attempt to handle atp redirects from .fbx to .baked.fst --- .../src/material-networking/TextureCache.cpp | 6 +- .../src/model-networking/ModelCache.cpp | 315 ++++++++---------- .../src/model-networking/ModelCache.h | 43 ++- 3 files changed, 171 insertions(+), 193 deletions(-) diff --git a/libraries/material-networking/src/material-networking/TextureCache.cpp b/libraries/material-networking/src/material-networking/TextureCache.cpp index 6ceb5d328a..25e7eeb25d 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.cpp +++ b/libraries/material-networking/src/material-networking/TextureCache.cpp @@ -635,11 +635,9 @@ void NetworkTexture::makeLocalRequest() { } bool NetworkTexture::handleFailedRequest(ResourceRequest::Result result) { - if (_currentlyLoadingResourceType != ResourceType::KTX - && result == ResourceRequest::Result::RedirectFail) { - + if (_shouldFailOnRedirect && result == ResourceRequest::Result::RedirectFail) { auto newPath = _request->getRelativePathUrl(); - if (newPath.fileName().endsWith(".ktx")) { + if (newPath.fileName().toLower().endsWith(".ktx")) { _currentlyLoadingResourceType = ResourceType::KTX; _activeUrl = newPath; _shouldFailOnRedirect = false; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 26fc0095c5..b914faaab9 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -31,8 +31,6 @@ Q_LOGGING_CATEGORY(trace_resource_parse_geometry, "trace.resource.parse.geometry") -class GeometryReader; - class GeometryExtra { public: const GeometryMappingPair& mapping; @@ -87,113 +85,6 @@ namespace std { }; } -QUrl resolveTextureBaseUrl(const QUrl& url, const QUrl& textureBaseUrl) { - return textureBaseUrl.isValid() ? textureBaseUrl : url; -} - -class GeometryMappingResource : public GeometryResource { - Q_OBJECT -public: - GeometryMappingResource(const QUrl& url) : GeometryResource(url) {}; - - QString getType() const override { return "GeometryMapping"; } - - virtual void downloadFinished(const QByteArray& data) override; - -private slots: - void onGeometryMappingLoaded(bool success); - -private: - GeometryResource::Pointer _geometryResource; - QMetaObject::Connection _connection; -}; - -void GeometryMappingResource::downloadFinished(const QByteArray& data) { - PROFILE_ASYNC_BEGIN(resource_parse_geometry, "GeometryMappingResource::downloadFinished", _url.toString(), - { { "url", _url.toString() } }); - - // store parsed contents of FST file - _mapping = FSTReader::readMapping(data); - - QString filename = _mapping.value("filename").toString(); - - if (filename.isNull()) { - finishedLoading(false); - } else { - const QString baseURL = _mapping.value("baseURL").toString(); - const QUrl base = _effectiveBaseURL.resolved(baseURL); - QUrl url = base.resolved(filename); - - QString texdir = _mapping.value(TEXDIR_FIELD).toString(); - if (!texdir.isNull()) { - if (!texdir.endsWith('/')) { - texdir += '/'; - } - _textureBaseUrl = resolveTextureBaseUrl(url, base.resolved(texdir)); - } else { - _textureBaseUrl = url.resolved(QUrl(".")); - } - - auto scripts = FSTReader::getScripts(base, _mapping); - if (scripts.size() > 0) { - _mapping.remove(SCRIPT_FIELD); - for (auto &scriptPath : scripts) { - _mapping.insertMulti(SCRIPT_FIELD, scriptPath); - } - } - - auto animGraphVariant = _mapping.value("animGraphUrl"); - - if (animGraphVariant.isValid()) { - QUrl fstUrl(animGraphVariant.toString()); - if (fstUrl.isValid()) { - _animGraphOverrideUrl = base.resolved(fstUrl); - } else { - _animGraphOverrideUrl = QUrl(); - } - } else { - _animGraphOverrideUrl = QUrl(); - } - - auto modelCache = DependencyManager::get(); - GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseUrl, false }; - - // Get the raw GeometryResource - _geometryResource = modelCache->getResource(url, QUrl(), &extra, std::hash()(extra)).staticCast(); - // Avoid caching nested resources - their references will be held by the parent - _geometryResource->_isCacheable = false; - - if (_geometryResource->isLoaded()) { - onGeometryMappingLoaded(!_geometryResource->getURL().isEmpty()); - } else { - if (_connection) { - disconnect(_connection); - } - - _connection = connect(_geometryResource.data(), &Resource::finished, - this, &GeometryMappingResource::onGeometryMappingLoaded); - } - } -} - -void GeometryMappingResource::onGeometryMappingLoaded(bool success) { - if (success && _geometryResource) { - _hfmModel = _geometryResource->_hfmModel; - _materialMapping = _geometryResource->_materialMapping; - _meshParts = _geometryResource->_meshParts; - _meshes = _geometryResource->_meshes; - _materials = _geometryResource->_materials; - - // Avoid holding onto extra references - _geometryResource.reset(); - // Make sure connection will not trigger again - disconnect(_connection); // FIXME Should not have to do this - } - - PROFILE_ASYNC_END(resource_parse_geometry, "GeometryMappingResource::downloadFinished", _url.toString()); - finishedLoading(success); -} - class GeometryReader : public QRunnable { public: GeometryReader(const ModelLoader& modelLoader, QWeakPointer& resource, const QUrl& url, const GeometryMappingPair& mapping, @@ -308,47 +199,137 @@ void GeometryReader::run() { } } -class GeometryDefinitionResource : public GeometryResource { - Q_OBJECT -public: - GeometryDefinitionResource(const ModelLoader& modelLoader, const QUrl& url) : GeometryResource(url), _modelLoader(modelLoader) {} - GeometryDefinitionResource(const GeometryDefinitionResource& other) : - GeometryResource(other), - _modelLoader(other._modelLoader), - _mapping(other._mapping), - _combineParts(other._combineParts) {} +QUrl resolveTextureBaseUrl(const QUrl& url, const QUrl& textureBaseUrl) { + return textureBaseUrl.isValid() ? textureBaseUrl : url; +} - QString getType() const override { return "GeometryDefinition"; } +GeometryResource::GeometryResource(const GeometryResource& other) : + Resource(other), + Geometry(other), + _modelLoader(other._modelLoader), + _mappingPair(other._mappingPair), + _textureBaseURL(other._textureBaseURL), + _combineParts(other._combineParts), + _isCacheable(other._isCacheable) +{ + if (other._geometryResource) { + _startedLoading = false; + } +} - virtual void downloadFinished(const QByteArray& data) override; +void GeometryResource::downloadFinished(const QByteArray& data) { + if (_activeUrl.fileName().toLower().endsWith(".fst")) { + PROFILE_ASYNC_BEGIN(resource_parse_geometry, "GeometryResource::downloadFinished", _url.toString(), { { "url", _url.toString() } }); - void setExtra(void* extra) override; + // store parsed contents of FST file + _mapping = FSTReader::readMapping(data); -protected: - Q_INVOKABLE void setGeometryDefinition(HFMModel::Pointer hfmModel, const MaterialMapping& materialMapping); + QString filename = _mapping.value("filename").toString(); -private: - ModelLoader _modelLoader; - GeometryMappingPair _mapping; - bool _combineParts; -}; + if (filename.isNull()) { + finishedLoading(false); + } else { + const QString baseURL = _mapping.value("baseURL").toString(); + const QUrl base = _effectiveBaseURL.resolved(baseURL); + QUrl url = base.resolved(filename); -void GeometryDefinitionResource::setExtra(void* extra) { + QString texdir = _mapping.value(TEXDIR_FIELD).toString(); + if (!texdir.isNull()) { + if (!texdir.endsWith('/')) { + texdir += '/'; + } + _textureBaseURL = resolveTextureBaseUrl(url, base.resolved(texdir)); + } else { + _textureBaseURL = url.resolved(QUrl(".")); + } + + auto scripts = FSTReader::getScripts(base, _mapping); + if (scripts.size() > 0) { + _mapping.remove(SCRIPT_FIELD); + for (auto &scriptPath : scripts) { + _mapping.insertMulti(SCRIPT_FIELD, scriptPath); + } + } + + auto animGraphVariant = _mapping.value("animGraphUrl"); + + if (animGraphVariant.isValid()) { + QUrl fstUrl(animGraphVariant.toString()); + if (fstUrl.isValid()) { + _animGraphOverrideUrl = base.resolved(fstUrl); + } else { + _animGraphOverrideUrl = QUrl(); + } + } else { + _animGraphOverrideUrl = QUrl(); + } + + auto modelCache = DependencyManager::get(); + GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseURL, false }; + + // Get the raw GeometryResource + _geometryResource = modelCache->getResource(url, QUrl(), &extra, std::hash()(extra)).staticCast(); + // Avoid caching nested resources - their references will be held by the parent + _geometryResource->_isCacheable = false; + + if (_geometryResource->isLoaded()) { + onGeometryMappingLoaded(!_geometryResource->getURL().isEmpty()); + } else { + if (_connection) { + disconnect(_connection); + } + + _connection = connect(_geometryResource.data(), &Resource::finished, this, &GeometryResource::onGeometryMappingLoaded); + } + } + } else { + if (_url != _effectiveBaseURL) { + _url = _effectiveBaseURL; + _textureBaseURL = _effectiveBaseURL; + } + QThreadPool::globalInstance()->start(new GeometryReader(_modelLoader, _self, _effectiveBaseURL, _mappingPair, data, _combineParts, _request->getWebMediaType())); + } +} + +bool GeometryResource::handleFailedRequest(ResourceRequest::Result result) { + if (_shouldFailOnRedirect && result == ResourceRequest::Result::RedirectFail) { + auto newPath = _request->getRelativePathUrl(); + if (newPath.fileName().toLower().endsWith(".fst")) { + _activeUrl = newPath; + _shouldFailOnRedirect = false; + makeRequest(); + return true; + } + } + return Resource::handleFailedRequest(result); +} + +void GeometryResource::onGeometryMappingLoaded(bool success) { + if (success && _geometryResource) { + _hfmModel = _geometryResource->_hfmModel; + _materialMapping = _geometryResource->_materialMapping; + _meshParts = _geometryResource->_meshParts; + _meshes = _geometryResource->_meshes; + _materials = _geometryResource->_materials; + + // Avoid holding onto extra references + _geometryResource.reset(); + // Make sure connection will not trigger again + disconnect(_connection); // FIXME Should not have to do this + } + + PROFILE_ASYNC_END(resource_parse_geometry, "GeometryResource::downloadFinished", _url.toString()); + finishedLoading(success); +} + +void GeometryResource::setExtra(void* extra) { const GeometryExtra* geometryExtra = static_cast(extra); - _mapping = geometryExtra ? geometryExtra->mapping : GeometryMappingPair(QUrl(), QVariantHash()); - _textureBaseUrl = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl(); + _mappingPair = geometryExtra ? geometryExtra->mapping : GeometryMappingPair(QUrl(), QVariantHash()); + _textureBaseURL = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl(); _combineParts = geometryExtra ? geometryExtra->combineParts : true; } -void GeometryDefinitionResource::downloadFinished(const QByteArray& data) { - if (_url != _effectiveBaseURL) { - _url = _effectiveBaseURL; - _textureBaseUrl = _effectiveBaseURL; - } - QThreadPool::globalInstance()->start(new GeometryReader(_modelLoader, _self, _effectiveBaseURL, _mapping, data, _combineParts, _request->getWebMediaType())); -} - -void GeometryDefinitionResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const MaterialMapping& materialMapping) { +void GeometryResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const MaterialMapping& materialMapping) { // Assume ownership of the processed HFMModel _hfmModel = hfmModel; _materialMapping = materialMapping; @@ -357,7 +338,7 @@ void GeometryDefinitionResource::setGeometryDefinition(HFMModel::Pointer hfmMode QHash materialIDAtlas; for (const HFMMaterial& material : _hfmModel->materials) { materialIDAtlas[material.materialID] = _materials.size(); - _materials.push_back(std::make_shared(material, _textureBaseUrl)); + _materials.push_back(std::make_shared(material, _textureBaseURL)); } std::shared_ptr meshes = std::make_shared(); @@ -380,6 +361,23 @@ void GeometryDefinitionResource::setGeometryDefinition(HFMModel::Pointer hfmMode finishedLoading(true); } +void GeometryResource::deleter() { + resetTextures(); + Resource::deleter(); +} + +void GeometryResource::setTextures() { + if (_hfmModel) { + for (const HFMMaterial& material : _hfmModel->materials) { + _materials.push_back(std::make_shared(material, _textureBaseURL)); + } + } +} + +void GeometryResource::resetTextures() { + _materials.clear(); +} + ModelCache::ModelCache() { const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE); @@ -392,26 +390,14 @@ ModelCache::ModelCache() { } QSharedPointer ModelCache::createResource(const QUrl& url) { - Resource* resource = nullptr; - if (url.path().toLower().endsWith(".fst")) { - resource = new GeometryMappingResource(url); - } else { - resource = new GeometryDefinitionResource(_modelLoader, url); - } - - return QSharedPointer(resource, &Resource::deleter); + return QSharedPointer(new GeometryResource(url, _modelLoader), &GeometryResource::deleter); } QSharedPointer ModelCache::createResourceCopy(const QSharedPointer& resource) { - if (resource->getURL().path().toLower().endsWith(".fst")) { - return QSharedPointer(new GeometryMappingResource(*resource.staticCast()), &Resource::deleter); - } else { - return QSharedPointer(new GeometryDefinitionResource(*resource.staticCast()), &Resource::deleter); - } + return QSharedPointer(new GeometryResource(*resource.staticCast()), &GeometryResource::deleter); } -GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, - const GeometryMappingPair& mapping, const QUrl& textureBaseUrl) { +GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const GeometryMappingPair& mapping, const QUrl& textureBaseUrl) { bool combineParts = true; GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash()(geometryExtra)).staticCast(); @@ -531,23 +517,6 @@ const std::shared_ptr Geometry::getShapeMaterial(int partID) co return nullptr; } -void GeometryResource::deleter() { - resetTextures(); - Resource::deleter(); -} - -void GeometryResource::setTextures() { - if (_hfmModel) { - for (const HFMMaterial& material : _hfmModel->materials) { - _materials.push_back(std::make_shared(material, _textureBaseUrl)); - } - } -} - -void GeometryResource::resetTextures() { - _materials.clear(); -} - void GeometryResourceWatcher::startWatching() { connect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished); connect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed); diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index ca1ceaff16..034a00912a 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -24,8 +24,6 @@ class MeshPart; -class GeometryMappingResource; - using GeometryMappingPair = std::pair; Q_DECLARE_METATYPE(GeometryMappingPair) @@ -60,8 +58,6 @@ public: const QVariantHash& getMapping() const { return _mapping; } protected: - friend class GeometryMappingResource; - // Shared across all geometries, constant throughout lifetime std::shared_ptr _hfmModel; MaterialMapping _materialMapping; @@ -80,23 +76,30 @@ private: /// A geometry loaded from the network. class GeometryResource : public Resource, public Geometry { + Q_OBJECT public: using Pointer = QSharedPointer; - GeometryResource(const QUrl& url) : Resource(url) {} - GeometryResource(const GeometryResource& other) : - Resource(other), - Geometry(other), - _textureBaseUrl(other._textureBaseUrl), - _isCacheable(other._isCacheable) {} + GeometryResource(const QUrl& url, const ModelLoader& modelLoader) : Resource(url), _modelLoader(modelLoader) { _shouldFailOnRedirect = !url.fileName().toLower().endsWith(".fst"); } + GeometryResource(const GeometryResource& other); - virtual bool areTexturesLoaded() const override { return isLoaded() && Geometry::areTexturesLoaded(); } + QString getType() const override { return "Geometry"; } virtual void deleter() override; + virtual void downloadFinished(const QByteArray& data) override; + bool handleFailedRequest(ResourceRequest::Result result) override; + void setExtra(void* extra) override; + + virtual bool areTexturesLoaded() const override { return isLoaded() && Geometry::areTexturesLoaded(); } + +private slots: + void onGeometryMappingLoaded(bool success); + protected: friend class ModelCache; - friend class GeometryMappingResource; + + Q_INVOKABLE void setGeometryDefinition(HFMModel::Pointer hfmModel, const MaterialMapping& materialMapping); // Geometries may not hold onto textures while cached - that is for the texture cache // Instead, these methods clear and reset textures from the geometry when caching/loading @@ -104,10 +107,18 @@ protected: void setTextures(); void resetTextures(); - QUrl _textureBaseUrl; - virtual bool isCacheable() const override { return _loaded && _isCacheable; } - bool _isCacheable { true }; + +private: + ModelLoader _modelLoader; + GeometryMappingPair _mappingPair; + QUrl _textureBaseURL; + bool _combineParts; + + GeometryResource::Pointer _geometryResource; + QMetaObject::Connection _connection; + + bool _isCacheable{ true }; }; class GeometryResourceWatcher : public QObject { @@ -158,7 +169,7 @@ public: const QUrl& textureBaseUrl = QUrl()); protected: - friend class GeometryMappingResource; + friend class GeometryResource; virtual QSharedPointer createResource(const QUrl& url) override; QSharedPointer createResourceCopy(const QSharedPointer& resource) override;