mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 07:12:40 +02:00
attempt to handle atp redirects from .fbx to .baked.fst
This commit is contained in:
parent
080ef882a8
commit
b1f00d6f22
3 changed files with 171 additions and 193 deletions
|
@ -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;
|
||||
|
|
|
@ -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<ModelCache>();
|
||||
GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseUrl, false };
|
||||
|
||||
// Get the raw GeometryResource
|
||||
_geometryResource = modelCache->getResource(url, QUrl(), &extra, std::hash<GeometryExtra>()(extra)).staticCast<GeometryResource>();
|
||||
// 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>& 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<ModelCache>();
|
||||
GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseURL, false };
|
||||
|
||||
// Get the raw GeometryResource
|
||||
_geometryResource = modelCache->getResource(url, QUrl(), &extra, std::hash<GeometryExtra>()(extra)).staticCast<GeometryResource>();
|
||||
// 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<const GeometryExtra*>(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<QString, size_t> materialIDAtlas;
|
||||
for (const HFMMaterial& material : _hfmModel->materials) {
|
||||
materialIDAtlas[material.materialID] = _materials.size();
|
||||
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
|
||||
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseURL));
|
||||
}
|
||||
|
||||
std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
|
||||
|
@ -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<NetworkMaterial>(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<Resource> 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, &Resource::deleter);
|
||||
return QSharedPointer<Resource>(new GeometryResource(url, _modelLoader), &GeometryResource::deleter);
|
||||
}
|
||||
|
||||
QSharedPointer<Resource> ModelCache::createResourceCopy(const QSharedPointer<Resource>& resource) {
|
||||
if (resource->getURL().path().toLower().endsWith(".fst")) {
|
||||
return QSharedPointer<Resource>(new GeometryMappingResource(*resource.staticCast<GeometryMappingResource>()), &Resource::deleter);
|
||||
} else {
|
||||
return QSharedPointer<Resource>(new GeometryDefinitionResource(*resource.staticCast<GeometryDefinitionResource>()), &Resource::deleter);
|
||||
}
|
||||
return QSharedPointer<Resource>(new GeometryResource(*resource.staticCast<GeometryResource>()), &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>()(geometryExtra)).staticCast<GeometryResource>();
|
||||
|
@ -531,23 +517,6 @@ const std::shared_ptr<NetworkMaterial> 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<NetworkMaterial>(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);
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
|
||||
class MeshPart;
|
||||
|
||||
class GeometryMappingResource;
|
||||
|
||||
using GeometryMappingPair = std::pair<QUrl, QVariantHash>;
|
||||
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<const HFMModel> _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>;
|
||||
|
||||
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<Resource> createResource(const QUrl& url) override;
|
||||
QSharedPointer<Resource> createResourceCopy(const QSharedPointer<Resource>& resource) override;
|
||||
|
|
Loading…
Reference in a new issue