Make it possible to create QTextureFileData from images

Currently it is only possible to create a cube map texture from a single
compressed texture file. In many cases, the cubemap asset is available
as a set of individual image files. Making it possible to use these
images directly will make the development process more efficient, and
will reduce the size of the assets needed to be shipped with demos and
examples.

Task-number: QTBUG-103191
Change-Id: Icd12548e2dab55ec2123804cb28353cbf29926ce
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
This commit is contained in:
Paul Olav Tvete 2022-05-25 08:59:13 +02:00
parent 5431b40ee8
commit 9614f4d434
2 changed files with 54 additions and 16 deletions

View File

@ -1,6 +1,7 @@
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "QtGui/qimage.h"
#include "qtexturefiledata_p.h"
#include <QtCore/qsize.h>
#include <QtCore/qvarlengtharray.h>
@ -21,14 +22,17 @@ public:
QTextureFileDataPrivate(const QTextureFileDataPrivate &other)
: QSharedData(other),
mode(other.mode),
logName(other.logName),
data(other.data),
offsets(other.offsets),
lengths(other.lengths),
images(other.images),
size(other.size),
format(other.format),
numFaces(other.numFaces),
numLevels(other.numLevels)
numLevels(other.numLevels),
keyValues(other.keyValues)
{
}
@ -40,13 +44,18 @@ public:
{
numLevels = force ? levels : qMax(numLevels, levels);
numFaces = force ? faces : qMax(numFaces, faces);
if (mode == QTextureFileData::ByteArrayMode) {
offsets.resize(numFaces);
lengths.resize(numFaces);
for (auto faceList : { &offsets, &lengths })
for (auto &levelList : *faceList)
levelList.resize(numLevels);
} else {
images.resize(numFaces);
for (auto &levelList : images)
levelList.resize(numLevels);
}
}
bool isValid(int level, int face) const { return level < numLevels && face < numFaces; }
@ -56,10 +65,12 @@ public:
int getLength(int level, int face) const { return lengths[face][level]; }
void setLength(int value, int level, int face) { lengths[face][level] = value; }
QTextureFileData::Mode mode = QTextureFileData::ByteArrayMode;
QByteArray logName;
QByteArray data;
QVarLengthArray<QList<int>, MAX_FACES> offsets; // [Face][Level] = offset
QVarLengthArray<QList<int>, MAX_FACES> lengths; // [Face][Level] = length
QVarLengthArray<QList<QImage>, MAX_FACES> images; // [Face][Level] = length
QSize size;
quint32 format = 0;
quint32 internalFormat = 0;
@ -69,8 +80,10 @@ public:
QMap<QByteArray, QByteArray> keyValues;
};
QTextureFileData::QTextureFileData()
QTextureFileData::QTextureFileData(Mode mode)
{
d = new QTextureFileDataPrivate;
d->mode = mode;
}
QTextureFileData::QTextureFileData(const QTextureFileData &other)
@ -98,6 +111,9 @@ bool QTextureFileData::isValid() const
if (!d)
return false;
if (d->mode == ImageMode)
return true; // Manually populated: the caller needs to do verification at that time.
if (d->data.isEmpty() || d->size.isEmpty() || (!d->format && !d->internalFormat))
return false;
@ -139,19 +155,26 @@ QByteArray QTextureFileData::data() const
void QTextureFileData::setData(const QByteArray &data)
{
if (!d.constData()) //### uh think about this design, this is the only way to create; should be constructor instead at least
d = new QTextureFileDataPrivate;
Q_ASSERT(d->mode == ByteArrayMode);
d->data = data;
}
void QTextureFileData::setData(const QImage &image, int level, int face)
{
Q_ASSERT(d->mode == ImageMode);
d->ensureSize(level + 1, face + 1);
d->images[face][level] = image;
}
int QTextureFileData::dataOffset(int level, int face) const
{
Q_ASSERT(d->mode == ByteArrayMode);
return (d && d->isValid(level, face)) ? d->getOffset(level, face) : 0;
}
void QTextureFileData::setDataOffset(int offset, int level, int face)
{
Q_ASSERT(d->mode == ByteArrayMode);
if (d.constData() && level >= 0) {
d->ensureSize(level + 1, face + 1);
d->setOffset(offset, level, face);
@ -160,11 +183,13 @@ void QTextureFileData::setDataOffset(int offset, int level, int face)
int QTextureFileData::dataLength(int level, int face) const
{
Q_ASSERT(d->mode == ByteArrayMode);
return (d && d->isValid(level, face)) ? d->getLength(level, face) : 0;
}
QByteArrayView QTextureFileData::getDataView(int level, int face) const
{
if (d->mode == ByteArrayMode) {
const int dataLength = this->dataLength(level, face);
const int dataOffset = this->dataOffset(level, face);
@ -172,10 +197,17 @@ QByteArrayView QTextureFileData::getDataView(int level, int face) const
return QByteArrayView();
return QByteArrayView(d->data.constData() + dataOffset, dataLength);
} else {
if (!d->isValid(level, face))
return QByteArrayView();
const QImage &img = d->images[face][level];
return img.isNull() ? QByteArrayView() : QByteArrayView(img.constBits(), img.sizeInBytes());
}
}
void QTextureFileData::setDataLength(int length, int level, int face)
{
Q_ASSERT(d->mode == ByteArrayMode);
if (d.constData() && level >= 0) {
d->ensureSize(level + 1, face + 1);
d->setLength(length, level, face);
@ -286,9 +318,11 @@ QDebug operator<<(QDebug dbg, const QTextureFileData &d)
dbg << "glInternalFormat:" << glFormatName(d.glInternalFormat());
dbg << "glBaseInternalFormat:" << glFormatName(d.glBaseInternalFormat());
dbg.nospace() << "Levels: " << d.numLevels();
dbg.nospace() << "Faces: " << d.numFaces();
if (!d.isValid())
dbg << " {Invalid}";
dbg << ")";
dbg << (d.d->mode ? "[bytearray-based]" : "[image-based]");
} else {
dbg << "null)";
}

View File

@ -30,7 +30,9 @@ class QTextureFileDataPrivate;
class Q_GUI_EXPORT QTextureFileData
{
public:
QTextureFileData();
enum Mode { ByteArrayMode, ImageMode };
QTextureFileData(Mode mode = ByteArrayMode);
QTextureFileData(const QTextureFileData &other);
QTextureFileData &operator=(const QTextureFileData &other);
~QTextureFileData();
@ -42,6 +44,7 @@ public:
QByteArray data() const;
void setData(const QByteArray &data);
void setData(const QImage &image, int level = 0, int face = 0);
int dataOffset(int level = 0, int face = 0) const;
void setDataOffset(int offset, int level = 0, int face = 0);
@ -77,6 +80,7 @@ public:
private:
QSharedDataPointer<QTextureFileDataPrivate> d;
friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QTextureFileData &d);
};
Q_DECLARE_TYPEINFO(QTextureFileData, Q_RELOCATABLE_TYPE);