mirror of
https://github.com/overte-org/overte.git
synced 2025-04-16 10:28:57 +02:00
Fix loading standalone baked textures from Asset Server
NetworkTexture was not properly handling redirected ATP files. For instance, if going from .jpg -> .ktx, the NetworkTexture class needs to be aware of this so it can stop the current request and make multiple requests for the individual mip levels.
This commit is contained in:
parent
ca62e7168c
commit
e9258ec97a
9 changed files with 63 additions and 18 deletions
|
@ -49,7 +49,7 @@ static const int INTERFACE_RUNNING_CHECK_FREQUENCY_MS = 1000;
|
|||
const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server";
|
||||
|
||||
static const QStringList BAKEABLE_MODEL_EXTENSIONS = { "fbx" };
|
||||
static const QList<QByteArray> BAKEABLE_TEXTURE_EXTENSIONS = QImageReader::supportedImageFormats();
|
||||
static QStringList BAKEABLE_TEXTURE_EXTENSIONS;
|
||||
static const QString BAKED_MODEL_SIMPLE_NAME = "asset.fbx";
|
||||
static const QString BAKED_TEXTURE_SIMPLE_NAME = "texture.ktx";
|
||||
|
||||
|
@ -71,7 +71,8 @@ void BakeAssetTask::run() {
|
|||
};
|
||||
} else {
|
||||
baker = std::unique_ptr<TextureBaker> {
|
||||
new TextureBaker(QUrl("file:///" + _filePath), image::TextureUsage::CUBE_TEXTURE, PathUtils::generateTemporaryDir())
|
||||
new TextureBaker(QUrl("file:///" + _filePath), image::TextureUsage::CUBE_TEXTURE,
|
||||
PathUtils::generateTemporaryDir())
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -198,7 +199,7 @@ bool AssetServer::needsToBeBaked(const AssetPath& path, const AssetHash& assetHa
|
|||
auto extension = path.mid(dotIndex + 1);
|
||||
|
||||
QString bakedFilename;
|
||||
|
||||
|
||||
if (BAKEABLE_MODEL_EXTENSIONS.contains(extension)) {
|
||||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
} else if (BAKEABLE_TEXTURE_EXTENSIONS.contains(extension.toLocal8Bit()) && hasMetaFile(assetHash)) {
|
||||
|
@ -247,6 +248,8 @@ AssetServer::AssetServer(ReceivedMessage& message) :
|
|||
_transferTaskPool(this),
|
||||
_bakingTaskPool(this)
|
||||
{
|
||||
BAKEABLE_TEXTURE_EXTENSIONS = TextureBaker::getSupportedFormats();
|
||||
qDebug() << "Supported baking texture formats:" << BAKEABLE_MODEL_EXTENSIONS;
|
||||
|
||||
// Most of the work will be I/O bound, reading from disk and constructing packet objects,
|
||||
// so the ideal is greater than the number of cores on the system.
|
||||
|
|
|
@ -43,6 +43,14 @@ void TextureBaker::bake() {
|
|||
loadTexture();
|
||||
}
|
||||
|
||||
const QStringList TextureBaker::getSupportedFormats() {
|
||||
auto formats = QImageReader::supportedImageFormats();
|
||||
QStringList stringFormats;
|
||||
std::transform(formats.begin(), formats.end(), std::back_inserter(stringFormats),
|
||||
[](auto& format) -> QString { return format; });
|
||||
return stringFormats;
|
||||
}
|
||||
|
||||
void TextureBaker::loadTexture() {
|
||||
// check if the texture is local or first needs to be downloaded
|
||||
if (_textureURL.isLocalFile()) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QRunnable>
|
||||
#include <QImageReader>
|
||||
|
||||
#include <image/Image.h>
|
||||
|
||||
|
@ -28,6 +29,8 @@ class TextureBaker : public Baker {
|
|||
public:
|
||||
TextureBaker(const QUrl& textureURL, image::TextureUsage::Type textureType, const QDir& outputDirectory);
|
||||
|
||||
static const QStringList getSupportedFormats();
|
||||
|
||||
const QByteArray& getOriginalTexture() const { return _originalTexture; }
|
||||
|
||||
QUrl getTextureURL() const { return _textureURL; }
|
||||
|
|
|
@ -299,6 +299,8 @@ NetworkTexture::NetworkTexture(const QUrl& url, image::TextureUsage::Type type,
|
|||
_textureSource = std::make_shared<gpu::TextureSource>();
|
||||
_lowestRequestedMipLevel = 0;
|
||||
|
||||
_shouldFailOnRedirect = !_sourceIsKTX;
|
||||
|
||||
if (type == image::TextureUsage::CUBE_TEXTURE) {
|
||||
setLoadPriority(this, SKYBOX_LOAD_PRIORITY);
|
||||
} else if (_sourceIsKTX) {
|
||||
|
@ -428,6 +430,21 @@ void NetworkTexture::makeRequest() {
|
|||
|
||||
}
|
||||
|
||||
bool NetworkTexture::handleFailedRequest(ResourceRequest::Result result) {
|
||||
if (!_sourceIsKTX && result == ResourceRequest::Result::RedirectFail) {
|
||||
auto newPath = _request->getRelativePathUrl();
|
||||
if (newPath.fileName().endsWith(".ktx")) {
|
||||
qDebug() << "Redirecting to" << newPath << "from" << _url;
|
||||
_sourceIsKTX = true;
|
||||
_activeUrl = newPath;
|
||||
_shouldFailOnRedirect = false;
|
||||
makeRequest();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Resource::handleFailedRequest(result);
|
||||
}
|
||||
|
||||
void NetworkTexture::startRequestForNextMipLevel() {
|
||||
auto self = _self.lock();
|
||||
if (!self) {
|
||||
|
@ -527,7 +544,7 @@ void NetworkTexture::ktxInitialDataRequestFinished() {
|
|||
_ktxHighMipData = _ktxMipRequest->getData();
|
||||
handleFinishedInitialLoad();
|
||||
} else {
|
||||
if (handleFailedRequest(result)) {
|
||||
if (Resource::handleFailedRequest(result)) {
|
||||
_ktxResourceState = PENDING_INITIAL_LOAD;
|
||||
} else {
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
|
@ -616,7 +633,7 @@ void NetworkTexture::ktxMipRequestFinished() {
|
|||
finishedLoading(false);
|
||||
}
|
||||
} else {
|
||||
if (handleFailedRequest(result)) {
|
||||
if (Resource::handleFailedRequest(result)) {
|
||||
_ktxResourceState = PENDING_MIP_REQUEST;
|
||||
} else {
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
|
|
|
@ -75,6 +75,8 @@ protected:
|
|||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
bool handleFailedRequest(ResourceRequest::Result result) override;
|
||||
|
||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);
|
||||
|
||||
|
|
|
@ -82,19 +82,23 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
|
|||
Q_ASSERT(_state == InProgress);
|
||||
Q_ASSERT(request == _assetMappingRequest);
|
||||
|
||||
bool failed = false;
|
||||
|
||||
switch (request->getError()) {
|
||||
case MappingRequest::NoError:
|
||||
// we have no error, we should have a resulting hash - use that to send of a request for that asset
|
||||
qCDebug(networking) << "Got mapping for:" << path << "=>" << request->getHash();
|
||||
|
||||
requestHash(request->getHash());
|
||||
|
||||
statTracker->incrementStat(STAT_ATP_MAPPING_REQUEST_SUCCESS);
|
||||
|
||||
// if we got a redirected path we need to store that with the resource request as relative path URL
|
||||
if (request->wasRedirected()) {
|
||||
qDebug() << "Request was redirected";
|
||||
if (request->wasRedirected() && _failOnRedirect) {
|
||||
_relativePathURL = ATP_SCHEME + request->getRedirectedPath();
|
||||
_result = RedirectFail;
|
||||
|
||||
failed = true;
|
||||
} else {
|
||||
requestHash(request->getHash());
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -113,17 +117,20 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
|
|||
break;
|
||||
}
|
||||
|
||||
// since we've failed we know we are finished
|
||||
_state = Finished;
|
||||
emit finished();
|
||||
|
||||
statTracker->incrementStat(STAT_ATP_MAPPING_REQUEST_FAILED);
|
||||
statTracker->incrementStat(STAT_ATP_REQUEST_FAILED);
|
||||
failed = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
_state = Finished;
|
||||
emit finished();
|
||||
|
||||
statTracker->incrementStat(STAT_ATP_MAPPING_REQUEST_FAILED);
|
||||
statTracker->incrementStat(STAT_ATP_REQUEST_FAILED);
|
||||
}
|
||||
|
||||
_assetMappingRequest->deleteLater();
|
||||
_assetMappingRequest = nullptr;
|
||||
});
|
||||
|
|
|
@ -687,8 +687,9 @@ void Resource::makeRequest() {
|
|||
PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_request->setByteRange(_requestByteRange);
|
||||
_request->setFailOnRedirect(_shouldFailOnRedirect);
|
||||
|
||||
qCDebug(resourceLog).noquote() << "Starting request for:" << _url.toDisplayString();
|
||||
emit loading();
|
||||
|
|
|
@ -449,12 +449,13 @@ protected:
|
|||
Q_INVOKABLE void allReferencesCleared();
|
||||
|
||||
/// Return true if the resource will be retried
|
||||
bool handleFailedRequest(ResourceRequest::Result result);
|
||||
virtual bool handleFailedRequest(ResourceRequest::Result result);
|
||||
|
||||
QUrl _url;
|
||||
QUrl _effectiveBaseURL{ _url };
|
||||
QUrl _activeUrl;
|
||||
ByteRange _requestByteRange;
|
||||
bool _shouldFailOnRedirect { false };
|
||||
|
||||
// _loaded == true means we are in a loaded and usable state. It is possible that there may still be
|
||||
// active requests/loading while in this state. Example: Progressive KTX downloads, where higher resolution
|
||||
|
|
|
@ -57,7 +57,8 @@ public:
|
|||
AccessDenied,
|
||||
InvalidByteRange,
|
||||
InvalidURL,
|
||||
NotFound
|
||||
NotFound,
|
||||
RedirectFail
|
||||
};
|
||||
Q_ENUM(Result)
|
||||
|
||||
|
@ -70,6 +71,7 @@ public:
|
|||
bool loadedFromCache() const { return _loadedFromCache; }
|
||||
bool getRangeRequestSuccessful() const { return _rangeRequestSuccessful; }
|
||||
bool getTotalSizeOfResource() const { return _totalSizeOfResource; }
|
||||
void setFailOnRedirect(bool failOnRedirect) { _failOnRedirect = failOnRedirect; }
|
||||
|
||||
void setCacheEnabled(bool value) { _cacheEnabled = value; }
|
||||
void setByteRange(ByteRange byteRange) { _byteRange = byteRange; }
|
||||
|
@ -89,6 +91,7 @@ protected:
|
|||
State _state { NotStarted };
|
||||
Result _result;
|
||||
QByteArray _data;
|
||||
bool _failOnRedirect { false };
|
||||
bool _cacheEnabled { true };
|
||||
bool _loadedFromCache { false };
|
||||
ByteRange _byteRange;
|
||||
|
|
Loading…
Reference in a new issue