summaryrefslogtreecommitdiffstats
path: root/src/render/texture/qtexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/texture/qtexture.cpp')
-rw-r--r--src/render/texture/qtexture.cpp202
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
-
-