From 509196b1d9c1ec9c483d3b7c84168494ef804f95 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Tue, 19 Jan 2021 15:24:29 +0100 Subject: Add face support to texture file Task-Id: QTBUG-76970 Change-Id: I3bbd43357c7fcce8949522b089a4572b948f08f4 Reviewed-by: Eirik Aavitsland --- src/gui/util/qastchandler.cpp | 1 + src/gui/util/qktxhandler.cpp | 1 + src/gui/util/qpkmhandler.cpp | 1 + src/gui/util/qtexturefiledata.cpp | 108 ++++++++++++++++++++++++++------------ src/gui/util/qtexturefiledata_p.h | 13 +++-- 5 files changed, 85 insertions(+), 39 deletions(-) (limited to 'src/gui/util') diff --git a/src/gui/util/qastchandler.cpp b/src/gui/util/qastchandler.cpp index e91ae3e0f5..94cb42e29b 100644 --- a/src/gui/util/qastchandler.cpp +++ b/src/gui/util/qastchandler.cpp @@ -150,6 +150,7 @@ QTextureFileData QAstcHandler::read() res.setDataOffset(sizeof(AstcHeader)); res.setNumLevels(1); + res.setNumFaces(1); res.setDataLength(byteCount); if (oob || !res.isValid()) { diff --git a/src/gui/util/qktxhandler.cpp b/src/gui/util/qktxhandler.cpp index f65eed7290..31c572db54 100644 --- a/src/gui/util/qktxhandler.cpp +++ b/src/gui/util/qktxhandler.cpp @@ -138,6 +138,7 @@ QTextureFileData QKtxHandler::read() texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat)); texData.setNumLevels(decode(header->numberOfMipmapLevels)); + texData.setNumFaces(1); quint32 offset = headerSize + decode(header->bytesOfKeyValueData); const int maxLevels = qMin(texData.numLevels(), 32); // Cap iterations in case of corrupt file. for (int i = 0; i < maxLevels; i++) { diff --git a/src/gui/util/qpkmhandler.cpp b/src/gui/util/qpkmhandler.cpp index 1c073cf94e..0ad0a54a79 100644 --- a/src/gui/util/qpkmhandler.cpp +++ b/src/gui/util/qpkmhandler.cpp @@ -102,6 +102,7 @@ QTextureFileData QPkmHandler::read() // texture size texData.setNumLevels(1); + texData.setNumFaces(1); const int bpb = typeMap[type].bytesPerBlock; QSize paddedSize(qFromBigEndian(rawData + 8), qFromBigEndian(rawData + 10)); texData.setDataLength((paddedSize.width() / 4) * (paddedSize.height() / 4) * bpb); diff --git a/src/gui/util/qtexturefiledata.cpp b/src/gui/util/qtexturefiledata.cpp index 29c6acaeca..0a3958aaf2 100644 --- a/src/gui/util/qtexturefiledata.cpp +++ b/src/gui/util/qtexturefiledata.cpp @@ -44,6 +44,8 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQtGuiTextureIO, "qt.gui.textureio"); +constexpr size_t MAX_FACES = 6; + class QTextureFileDataPrivate : public QSharedData { public: @@ -58,7 +60,9 @@ public: offsets(other.offsets), lengths(other.lengths), size(other.size), - format(other.format) + format(other.format), + numFaces(other.numFaces), + numLevels(other.numLevels) { } @@ -66,25 +70,38 @@ public: { } - void ensureLevels(int num, bool force = false) + void ensureSize(int levels, int faces, bool force = false) { - const int newSize = force ? num : qMax(offsets.size(), num); - offsets.resize(newSize); - lengths.resize(newSize); + numLevels = force ? levels : qMax(numLevels, levels); + numFaces = force ? faces : qMax(numFaces, faces); + + offsets.resize(numFaces); + lengths.resize(numFaces); + + for (auto faceList : { &offsets, &lengths }) + for (auto &levelList : *faceList) + levelList.resize(numLevels); } + bool isValid(int level, int face) const { return level < numLevels && face < numFaces; } + + int getOffset(int level, int face) const { return offsets[face][level]; } + void setOffset(int value, int level, int face) { offsets[face][level] = value; } + int getLength(int level, int face) const { return lengths[face][level]; } + void setLength(int value, int level, int face) { lengths[face][level] = value; } + QByteArray logName; QByteArray data; - QList offsets; - QList lengths; + QVarLengthArray, MAX_FACES> offsets; // [Face][Level] = offset + QVarLengthArray, MAX_FACES> lengths; // [Face][Level] = length QSize size; quint32 format = 0; quint32 internalFormat = 0; quint32 baseInternalFormat = 0; + int numFaces = 0; + int numLevels = 0; }; - - QTextureFileData::QTextureFileData() { } @@ -117,16 +134,28 @@ bool QTextureFileData::isValid() const if (d->data.isEmpty() || d->size.isEmpty() || (!d->format && !d->internalFormat)) return false; - const int numChunks = d->offsets.size(); - if (numChunks == 0 || (d->lengths.size() != numChunks)) - return false; + const int numFacesOffset = d->offsets.length(); + const int numFacesLength = d->lengths.length(); + if (numFacesOffset == 0 || numFacesLength == 0 || d->numFaces != numFacesOffset + || d->numFaces != numFacesLength) + return false; + + const qint64 dataSize = d->data.size(); - const qint64 sz = d->data.size(); - for (int i = 0; i < numChunks; i++) { - qint64 offi = d->offsets.at(i); - qint64 leni = d->lengths.at(i); - if (offi < 0 || offi >= sz || leni <= 0 || (offi + leni > sz)) + // Go through all faces and levels and check that the range is inside the data size. + for (int face = 0; face < d->numFaces; face++) { + const int numLevelsOffset = d->offsets.at(face).size(); + const int numLevelsLength = d->lengths.at(face).size(); + if (numLevelsOffset == 0 || numLevelsLength == 0 || d->numLevels != numLevelsOffset + || d->numLevels != numLevelsLength) return false; + + for (int level = 0; level < d->numLevels; level++) { + const qint64 offset = d->getOffset(level, face); + const qint64 length = d->getLength(level, face); + if (offset < 0 || offset >= dataSize || length <= 0 || (offset + length > dataSize)) + return false; + } } return true; } @@ -149,28 +178,28 @@ void QTextureFileData::setData(const QByteArray &data) d->data = data; } -int QTextureFileData::dataOffset(int level) const +int QTextureFileData::dataOffset(int level, int face) const { - return (d && d->offsets.size() > level) ? d->offsets.at(level) : 0; + return (d && d->isValid(level, face)) ? d->getOffset(level, face) : 0; } -void QTextureFileData::setDataOffset(int offset, int level) +void QTextureFileData::setDataOffset(int offset, int level, int face) { if (d.constData() && level >= 0) { - d->ensureLevels(level + 1); - d->offsets[level] = offset; + d->ensureSize(level + 1, face + 1); + d->setOffset(offset, level, face); } } -int QTextureFileData::dataLength(int level) const +int QTextureFileData::dataLength(int level, int face) const { - return (d && d->lengths.size() > level) ? d->lengths.at(level) : 0; + return (d && d->isValid(level, face)) ? d->getLength(level, face) : 0; } -QByteArrayView QTextureFileData::getDataView(int level) const +QByteArrayView QTextureFileData::getDataView(int level, int face) const { - const int dataLength = this->dataLength(level); - const int dataOffset = this->dataOffset(level); + const int dataLength = this->dataLength(level, face); + const int dataOffset = this->dataOffset(level, face); if (d == nullptr || dataLength == 0) return QByteArrayView(); @@ -178,23 +207,34 @@ QByteArrayView QTextureFileData::getDataView(int level) const return QByteArrayView(d->data.constData() + dataOffset, dataLength); } -void QTextureFileData::setDataLength(int length, int level) +void QTextureFileData::setDataLength(int length, int level, int face) { if (d.constData() && level >= 0) { - d->ensureLevels(level + 1); - d->lengths[level] = length; + d->ensureSize(level + 1, face + 1); + d->setLength(length, level, face); } } int QTextureFileData::numLevels() const { - return d ? d->offsets.size() : 0; + return d ? d->numLevels : 0; +} + +void QTextureFileData::setNumLevels(int numLevels) +{ + if (d && numLevels >= 0) + d->ensureSize(numLevels, d->numFaces, true); +} + +int QTextureFileData::numFaces() const +{ + return d ? d->numFaces : 0; } -void QTextureFileData::setNumLevels(int num) +void QTextureFileData::setNumFaces(int numFaces) { - if (d && num >= 0) - d->ensureLevels(num, true); + if (d && numFaces >= 0) + d->ensureSize(d->numLevels, numFaces, true); } QSize QTextureFileData::size() const diff --git a/src/gui/util/qtexturefiledata_p.h b/src/gui/util/qtexturefiledata_p.h index 3d75d46c94..f6a03c0550 100644 --- a/src/gui/util/qtexturefiledata_p.h +++ b/src/gui/util/qtexturefiledata_p.h @@ -78,17 +78,20 @@ public: QByteArray data() const; void setData(const QByteArray &data); - int dataOffset(int level = 0) const; - void setDataOffset(int offset, int level = 0); + int dataOffset(int level = 0, int face = 0) const; + void setDataOffset(int offset, int level = 0, int face = 0); - int dataLength(int level = 0) const; - void setDataLength(int length, int level = 0); + int dataLength(int level = 0, int face = 0) const; + void setDataLength(int length, int level = 0, int face = 0); - QByteArrayView getDataView(int level = 0) const; + QByteArrayView getDataView(int level = 0, int face = 0) const; int numLevels() const; void setNumLevels(int num); + int numFaces() const; + void setNumFaces(int num); + QSize size() const; void setSize(const QSize &size); -- cgit v1.2.3