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:
parent
5431b40ee8
commit
9614f4d434
@ -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)";
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user