diff options
Diffstat (limited to 'src/render/texture/qtexture.cpp')
-rw-r--r-- | src/render/texture/qtexture.cpp | 202 |
1 files changed, 155 insertions, 47 deletions
diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp index 7dc071833..931d66c64 100644 --- a/src/render/texture/qtexture.cpp +++ b/src/render/texture/qtexture.cpp @@ -44,7 +44,17 @@ #include "qtexture.h" #include "qtexture_p.h" #include <QFileInfo> +#include <QMimeDatabase> +#include <QMimeType> #include <qendian.h> +#include <Qt3DCore/private/qscene_p.h> +#include <Qt3DCore/qaspectengine.h> +#include <Qt3DCore/private/qdownloadhelperservice_p.h> +#include <Qt3DRender/private/qrenderaspect_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/texture_p.h> +#include <Qt3DRender/private/qurlhelper_p.h> QT_BEGIN_NAMESPACE @@ -390,7 +400,7 @@ const struct DX10Format { DXGI_FORMAT_R8_UNORM, { QOpenGLTexture::Red, QOpenGLTexture::R8_UNorm, QOpenGLTexture::UInt8, 1, false } }, { DXGI_FORMAT_R8G8_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG8_UNorm, QOpenGLTexture::UInt8, 2, false } }, { DXGI_FORMAT_R16_UNORM, { QOpenGLTexture::Red, QOpenGLTexture::R16_UNorm, QOpenGLTexture::UInt16, 2, false } }, -{ DXGI_FORMAT_R16_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG16_UNorm, QOpenGLTexture::UInt16, 4, false } }, +{ DXGI_FORMAT_R16G16_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG16_UNorm, QOpenGLTexture::UInt16, 4, false } }, // depth formats { DXGI_FORMAT_D16_UNORM, { QOpenGLTexture::Depth, QOpenGLTexture::D16, QOpenGLTexture::NoPixelType, 2, false } }, @@ -424,9 +434,8 @@ enum CompressedFormatExtension { PKM }; -CompressedFormatExtension texturedCompressedFormat(const QString &source) +CompressedFormatExtension texturedCompressedFormat(const QString &suffix) { - const QString suffix = QFileInfo(source).suffix(); if (suffix == QStringLiteral("pkm")) return PKM; if (suffix == QStringLiteral("dds")) @@ -434,19 +443,14 @@ CompressedFormatExtension texturedCompressedFormat(const QString &source) return None; } -QTextureImageDataPtr setPkmFile(const QString &source) +QTextureImageDataPtr setPkmFile(QIODevice *source) { QTextureImageDataPtr imageData; - QFile f(source); - if (!f.open(QIODevice::ReadOnly)) { - qWarning() << "Failed to open" << source; - return imageData; - } - // ETC1 in PKM, as generated by f.ex. Android's etc1tool + // ETC1 in PKM, as generated by source->ex. Android's etc1tool static const char pkmMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; const int pkmHeaderSize = 6 + 2 + 4 * 2; - const QByteArray header = f.read(pkmHeaderSize); + const QByteArray header = source->read(pkmHeaderSize); if (header.size() >= pkmHeaderSize && !qstrncmp(header.constData(), pkmMagic, 6)) { imageData = QTextureImageDataPtr::create(); imageData->setTarget(QOpenGLTexture::Target2D); @@ -455,7 +459,7 @@ QTextureImageDataPtr setPkmFile(const QString &source) imageData->setWidth(qFromBigEndian(*(reinterpret_cast<const quint16 *>(header.constData() + 6 + 2)))); imageData->setHeight(qFromBigEndian(*(reinterpret_cast<const quint16 *>(header.constData() + 6 + 2 + 2)))); imageData->setDepth(1); - const QByteArray data = f.readAll(); + const QByteArray data = source->readAll(); if (data.size() < (imageData->width() / 4) * (imageData->height() / 4) * 8) qWarning() << "Unexpected end of ETC1 data in" << source; const bool isCompressed = true; @@ -467,17 +471,12 @@ QTextureImageDataPtr setPkmFile(const QString &source) return imageData; } -QTextureImageDataPtr setDdsFile(const QString &source) +QTextureImageDataPtr setDdsFile(QIODevice *source) { QTextureImageDataPtr imageData; - QFile f(source); - if (!f.open(QIODevice::ReadOnly)) { - qWarning() << "Failed to open" << source; - return imageData; - } DdsHeader header; - if ((f.read(reinterpret_cast<char *>(&header), sizeof header) != sizeof header) + if ((source->read(reinterpret_cast<char *>(&header), sizeof header) != sizeof header) || (qstrncmp(header.magic, "DDS ", 4) != 0)) return imageData; @@ -490,7 +489,7 @@ QTextureImageDataPtr setDdsFile(const QString &source) if (fourCC == DdsFourCC<'D', 'X', '1', '0'>::value) { // DX10 texture DdsDX10Header dx10Header; - if (f.read(reinterpret_cast<char *>(&dx10Header), sizeof dx10Header) != sizeof dx10Header) + if (source->read(reinterpret_cast<char *>(&dx10Header), sizeof dx10Header) != sizeof dx10Header) return imageData; layers = qFromLittleEndian(dx10Header.arraySize); @@ -582,13 +581,13 @@ QTextureImageDataPtr setDdsFile(const QString &source) // data const int dataSize = layers * layerSize; - const QByteArray data = f.read(dataSize); + const QByteArray data = source->read(dataSize); if (data.size() < dataSize) { qWarning() << "Unexpected end of data in" << source; return imageData; } - if (!f.atEnd()) + if (!source->atEnd()) qWarning() << "Unrecognized data in" << source; imageData = QTextureImageDataPtr::create(); @@ -626,26 +625,39 @@ QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool #endif ) { const QString source = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(url); - const CompressedFormatExtension formatExtension = texturedCompressedFormat(source); - switch (formatExtension) { - case DDS: - textureData = setDdsFile(source); - break; - case PKM: - textureData = setPkmFile(source); - break; - default: - QImage img; - if (img.load(source)) { - textureData = QTextureImageDataPtr::create(); - textureData->setImage(mirrored ? img.mirrored() : img); - } - break; - } + QFile f(source); + if (!f.open(QIODevice::ReadOnly)) + qWarning() << "Failed to open" << source; + else + textureData = loadTextureData(&f, QFileInfo(source).suffix(), allow3D, mirrored); + } + return textureData; +} - if (!allow3D && textureData && (textureData->layers() > 1 || textureData->depth() > 1)) - qWarning() << "Texture data has a 3rd dimension which wasn't expected"; +QTextureImageDataPtr TextureLoadingHelper::loadTextureData(QIODevice *data, const QString& suffix, + bool allow3D, bool mirrored) +{ + QTextureImageDataPtr textureData; + const CompressedFormatExtension formatExtension = texturedCompressedFormat(suffix); + switch (formatExtension) { + case DDS: + textureData = setDdsFile(data); + break; + case PKM: + textureData = setPkmFile(data); + break; + default: { + QImage img; + if (img.load(data, suffix.toLatin1())) { + textureData = QTextureImageDataPtr::create(); + textureData->setImage(mirrored ? img.mirrored() : img); + } + break; + } } + + if (!allow3D && textureData && (textureData->layers() > 1 || textureData->depth() > 1)) + qWarning() << "Texture data has a 3rd dimension which wasn't expected"; return textureData; } @@ -653,8 +665,43 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()() { QTextureDataPtr generatedData = QTextureDataPtr::create(); m_status = QAbstractTexture::Loading; + QTextureImageDataPtr textureData; + + if (!Qt3DCore::QDownloadHelperService::isLocal(m_url)) { + if (m_sourceData.isEmpty()) { + // first time around, trigger a download + if (m_texture) { + auto downloadService = Qt3DCore::QDownloadHelperService::getService(m_engine); + Qt3DCore::QDownloadRequestPtr request(new TextureDownloadRequest(m_texture, m_url, + m_engine)); + downloadService->submitRequest(request); + } + return generatedData; + } + + // second time around, we have the data + QT_PREPEND_NAMESPACE(QBuffer) buffer(&m_sourceData); + if (buffer.open(QIODevice::ReadOnly)) { + QString suffix = m_url.toString(); + suffix = suffix.right(suffix.length() - suffix.lastIndexOf('.')); + + QStringList ext(suffix); + + QMimeDatabase db; + QMimeType mtype = db.mimeTypeForData(m_sourceData); + if (mtype.isValid()) { + ext << mtype.suffixes(); + } - const QTextureImageDataPtr textureData = TextureLoadingHelper::loadTextureData(m_url, true, m_mirrored); + for (QString s: qAsConst(ext)) { + textureData = TextureLoadingHelper::loadTextureData(&buffer, suffix, true, m_mirrored); + if (textureData && textureData->data().length() > 0) + break; + } + } + } else { + textureData = TextureLoadingHelper::loadTextureData(m_url, true, m_mirrored); + } if (textureData && textureData->data().length() > 0) { generatedData->setTarget(static_cast<QAbstractTexture::Target>(textureData->target())); @@ -672,12 +719,55 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()() return generatedData; } +TextureDownloadRequest::TextureDownloadRequest(Qt3DCore::QNodeId texture, const QUrl& source, + Qt3DCore::QAspectEngine *engine) + : Qt3DCore::QDownloadRequest(source) + , m_texture(texture) + , m_engine(engine) +{ + +} + +// Executed in download thread +void TextureDownloadRequest::onCompleted() +{ + if (cancelled() || !succeeded()) + return; + + QRenderAspectPrivate* d_aspect = QRenderAspectPrivate::findPrivate(m_engine); + if (!d_aspect) + return; + + Render::Texture *texture = d_aspect->m_nodeManagers->textureManager()->lookupResource(m_texture); + if (!texture) + return; + + QSharedPointer<QTextureFromSourceGenerator> functor = + qSharedPointerCast<QTextureFromSourceGenerator>(texture->dataGenerator()); + functor->m_sourceData = m_data; + + // mark the component as dirty so that the functor runs again in the correct job + texture->addDirtyFlag(Render::Texture::DirtyDataGenerator); +} + QTextureLoaderPrivate::QTextureLoaderPrivate() : QAbstractTexturePrivate() , m_mirrored(true) { } +void QTextureLoaderPrivate::setScene(Qt3DCore::QScene *scene) +{ + QAbstractTexturePrivate::setScene(scene); + updateFunctor(); +} + +void QTextureLoaderPrivate::updateFunctor() +{ + Qt3DCore::QAspectEngine *engine = m_scene ? m_scene->engine() : nullptr; + setDataFunctor(QTextureFromSourceGeneratorPtr::create(m_id, m_source, m_mirrored, engine)); +} + /*! \class Qt3DRender::QTexture1D \inmodule Qt3DRender @@ -900,10 +990,25 @@ QTextureBuffer::~QTextureBuffer() /*! * Constructs a new Qt3DRender::QTextureLoader instance with \a parent as parent. + * + * Note that by default, if not contradicted by the file metadata, the loaded texture + * will have the following properties set: + * - wrapMode set to Repeat + * - minificationFilter set to LinearMipMapLinear + * - magnificationFilter set to Linear + * - generateMipMaps set to true + * - maximumAnisotropy set to 16.0f + * - target set to TargetAutomatic */ QTextureLoader::QTextureLoader(QNode *parent) : QAbstractTexture(*new QTextureLoaderPrivate, parent) { + d_func()->m_wrapMode.setX(QTextureWrapMode::Repeat); + d_func()->m_wrapMode.setY(QTextureWrapMode::Repeat); + d_func()->m_minFilter = LinearMipMapLinear; + d_func()->m_magFilter = Linear; + d_func()->m_autoMipMap = true; + d_func()->m_maximumAnisotropy = 16.0f; d_func()->m_target = TargetAutomatic; } @@ -936,7 +1041,7 @@ void QTextureLoader::setSource(const QUrl& source) Q_D(QTextureLoader); if (source != d->m_source) { d->m_source = source; - d->setDataFunctor(QTextureFromSourceGeneratorPtr::create(d->m_source, d->m_mirrored)); + d->updateFunctor(); const bool blocked = blockNotifications(true); emit sourceChanged(source); blockNotifications(blocked); @@ -984,7 +1089,7 @@ void QTextureLoader::setMirrored(bool mirrored) Q_D(QTextureLoader); if (mirrored != d->m_mirrored) { d->m_mirrored = mirrored; - d->setDataFunctor(QTextureFromSourceGeneratorPtr::create(d->m_source, d->m_mirrored)); + d->updateFunctor(); const bool blocked = blockNotifications(true); emit mirroredChanged(mirrored); blockNotifications(blocked); @@ -1000,7 +1105,8 @@ bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) co const QTextureFromSourceGenerator *otherFunctor = functor_cast<QTextureFromSourceGenerator>(&other); return (otherFunctor != nullptr && otherFunctor->m_url == m_url && - otherFunctor->m_mirrored == m_mirrored); + otherFunctor->m_mirrored == m_mirrored && + otherFunctor->m_engine == m_engine); } QUrl QTextureFromSourceGenerator::url() const @@ -1018,16 +1124,18 @@ bool QTextureFromSourceGenerator::isMirrored() const * instance with \a url. * \param url */ -QTextureFromSourceGenerator::QTextureFromSourceGenerator(const QUrl &url, bool mirrored) +QTextureFromSourceGenerator::QTextureFromSourceGenerator(Qt3DCore::QNodeId texture, + const QUrl &url, bool mirrored, + Qt3DCore::QAspectEngine *engine) : QTextureGenerator() , m_url(url) , m_status(QAbstractTexture::None) , m_mirrored(mirrored) + , m_texture(texture) + , m_engine(engine) { } } // namespace Qt3DRender QT_END_NAMESPACE - - |