Add face support to texture file
Task-Id: QTBUG-76970 Change-Id: I3bbd43357c7fcce8949522b089a4572b948f08f4 Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
This commit is contained in:
parent
d95a1a8bd4
commit
509196b1d9
@ -150,6 +150,7 @@ QTextureFileData QAstcHandler::read()
|
|||||||
|
|
||||||
res.setDataOffset(sizeof(AstcHeader));
|
res.setDataOffset(sizeof(AstcHeader));
|
||||||
res.setNumLevels(1);
|
res.setNumLevels(1);
|
||||||
|
res.setNumFaces(1);
|
||||||
res.setDataLength(byteCount);
|
res.setDataLength(byteCount);
|
||||||
|
|
||||||
if (oob || !res.isValid()) {
|
if (oob || !res.isValid()) {
|
||||||
|
@ -138,6 +138,7 @@ QTextureFileData QKtxHandler::read()
|
|||||||
texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat));
|
texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat));
|
||||||
|
|
||||||
texData.setNumLevels(decode(header->numberOfMipmapLevels));
|
texData.setNumLevels(decode(header->numberOfMipmapLevels));
|
||||||
|
texData.setNumFaces(1);
|
||||||
quint32 offset = headerSize + decode(header->bytesOfKeyValueData);
|
quint32 offset = headerSize + decode(header->bytesOfKeyValueData);
|
||||||
const int maxLevels = qMin(texData.numLevels(), 32); // Cap iterations in case of corrupt file.
|
const int maxLevels = qMin(texData.numLevels(), 32); // Cap iterations in case of corrupt file.
|
||||||
for (int i = 0; i < maxLevels; i++) {
|
for (int i = 0; i < maxLevels; i++) {
|
||||||
|
@ -102,6 +102,7 @@ QTextureFileData QPkmHandler::read()
|
|||||||
|
|
||||||
// texture size
|
// texture size
|
||||||
texData.setNumLevels(1);
|
texData.setNumLevels(1);
|
||||||
|
texData.setNumFaces(1);
|
||||||
const int bpb = typeMap[type].bytesPerBlock;
|
const int bpb = typeMap[type].bytesPerBlock;
|
||||||
QSize paddedSize(qFromBigEndian<quint16>(rawData + 8), qFromBigEndian<quint16>(rawData + 10));
|
QSize paddedSize(qFromBigEndian<quint16>(rawData + 8), qFromBigEndian<quint16>(rawData + 10));
|
||||||
texData.setDataLength((paddedSize.width() / 4) * (paddedSize.height() / 4) * bpb);
|
texData.setDataLength((paddedSize.width() / 4) * (paddedSize.height() / 4) * bpb);
|
||||||
|
@ -44,6 +44,8 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcQtGuiTextureIO, "qt.gui.textureio");
|
Q_LOGGING_CATEGORY(lcQtGuiTextureIO, "qt.gui.textureio");
|
||||||
|
|
||||||
|
constexpr size_t MAX_FACES = 6;
|
||||||
|
|
||||||
class QTextureFileDataPrivate : public QSharedData
|
class QTextureFileDataPrivate : public QSharedData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -58,7 +60,9 @@ public:
|
|||||||
offsets(other.offsets),
|
offsets(other.offsets),
|
||||||
lengths(other.lengths),
|
lengths(other.lengths),
|
||||||
size(other.size),
|
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);
|
numLevels = force ? levels : qMax(numLevels, levels);
|
||||||
offsets.resize(newSize);
|
numFaces = force ? faces : qMax(numFaces, faces);
|
||||||
lengths.resize(newSize);
|
|
||||||
|
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 logName;
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
QList<int> offsets;
|
QVarLengthArray<QList<int>, MAX_FACES> offsets; // [Face][Level] = offset
|
||||||
QList<int> lengths;
|
QVarLengthArray<QList<int>, MAX_FACES> lengths; // [Face][Level] = length
|
||||||
QSize size;
|
QSize size;
|
||||||
quint32 format = 0;
|
quint32 format = 0;
|
||||||
quint32 internalFormat = 0;
|
quint32 internalFormat = 0;
|
||||||
quint32 baseInternalFormat = 0;
|
quint32 baseInternalFormat = 0;
|
||||||
|
int numFaces = 0;
|
||||||
|
int numLevels = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QTextureFileData::QTextureFileData()
|
QTextureFileData::QTextureFileData()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -117,16 +134,28 @@ bool QTextureFileData::isValid() const
|
|||||||
if (d->data.isEmpty() || d->size.isEmpty() || (!d->format && !d->internalFormat))
|
if (d->data.isEmpty() || d->size.isEmpty() || (!d->format && !d->internalFormat))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const int numChunks = d->offsets.size();
|
const int numFacesOffset = d->offsets.length();
|
||||||
if (numChunks == 0 || (d->lengths.size() != numChunks))
|
const int numFacesLength = d->lengths.length();
|
||||||
return false;
|
if (numFacesOffset == 0 || numFacesLength == 0 || d->numFaces != numFacesOffset
|
||||||
|
|| d->numFaces != numFacesLength)
|
||||||
|
return false;
|
||||||
|
|
||||||
const qint64 sz = d->data.size();
|
const qint64 dataSize = d->data.size();
|
||||||
for (int i = 0; i < numChunks; i++) {
|
|
||||||
qint64 offi = d->offsets.at(i);
|
// Go through all faces and levels and check that the range is inside the data size.
|
||||||
qint64 leni = d->lengths.at(i);
|
for (int face = 0; face < d->numFaces; face++) {
|
||||||
if (offi < 0 || offi >= sz || leni <= 0 || (offi + leni > sz))
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -149,28 +178,28 @@ void QTextureFileData::setData(const QByteArray &data)
|
|||||||
d->data = 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) {
|
if (d.constData() && level >= 0) {
|
||||||
d->ensureLevels(level + 1);
|
d->ensureSize(level + 1, face + 1);
|
||||||
d->offsets[level] = offset;
|
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 dataLength = this->dataLength(level, face);
|
||||||
const int dataOffset = this->dataOffset(level);
|
const int dataOffset = this->dataOffset(level, face);
|
||||||
|
|
||||||
if (d == nullptr || dataLength == 0)
|
if (d == nullptr || dataLength == 0)
|
||||||
return QByteArrayView();
|
return QByteArrayView();
|
||||||
@ -178,23 +207,34 @@ QByteArrayView QTextureFileData::getDataView(int level) const
|
|||||||
return QByteArrayView(d->data.constData() + dataOffset, dataLength);
|
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) {
|
if (d.constData() && level >= 0) {
|
||||||
d->ensureLevels(level + 1);
|
d->ensureSize(level + 1, face + 1);
|
||||||
d->lengths[level] = length;
|
d->setLength(length, level, face);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int QTextureFileData::numLevels() const
|
int QTextureFileData::numLevels() const
|
||||||
{
|
{
|
||||||
return d ? d->offsets.size() : 0;
|
return d ? d->numLevels : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTextureFileData::setNumLevels(int num)
|
void QTextureFileData::setNumLevels(int numLevels)
|
||||||
{
|
{
|
||||||
if (d && num >= 0)
|
if (d && numLevels >= 0)
|
||||||
d->ensureLevels(num, true);
|
d->ensureSize(numLevels, d->numFaces, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int QTextureFileData::numFaces() const
|
||||||
|
{
|
||||||
|
return d ? d->numFaces : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTextureFileData::setNumFaces(int numFaces)
|
||||||
|
{
|
||||||
|
if (d && numFaces >= 0)
|
||||||
|
d->ensureSize(d->numLevels, numFaces, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize QTextureFileData::size() const
|
QSize QTextureFileData::size() const
|
||||||
|
@ -78,17 +78,20 @@ public:
|
|||||||
QByteArray data() const;
|
QByteArray data() const;
|
||||||
void setData(const QByteArray &data);
|
void setData(const QByteArray &data);
|
||||||
|
|
||||||
int dataOffset(int level = 0) const;
|
int dataOffset(int level = 0, int face = 0) const;
|
||||||
void setDataOffset(int offset, int level = 0);
|
void setDataOffset(int offset, int level = 0, int face = 0);
|
||||||
|
|
||||||
int dataLength(int level = 0) const;
|
int dataLength(int level = 0, int face = 0) const;
|
||||||
void setDataLength(int length, int level = 0);
|
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;
|
int numLevels() const;
|
||||||
void setNumLevels(int num);
|
void setNumLevels(int num);
|
||||||
|
|
||||||
|
int numFaces() const;
|
||||||
|
void setNumFaces(int num);
|
||||||
|
|
||||||
QSize size() const;
|
QSize size() const;
|
||||||
void setSize(const QSize &size);
|
void setSize(const QSize &size);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user