Texture file support: add mipmap reading to ktx handler
Change-Id: Ic2c10b3e64d63d2272a8a3922d2b3f99dfd45bdb Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
parent
307d0b32f0
commit
9d1c881f49
@ -43,6 +43,11 @@
|
|||||||
#include <QSize>
|
#include <QSize>
|
||||||
|
|
||||||
//#define KTX_DEBUG
|
//#define KTX_DEBUG
|
||||||
|
#ifdef KTX_DEBUG
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QMetaEnum>
|
||||||
|
#include <QOpenGLTexture>
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -68,7 +73,7 @@ struct KTXHeader {
|
|||||||
quint32 bytesOfKeyValueData;
|
quint32 bytesOfKeyValueData;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int headerSize = sizeof(KTXHeader);
|
static const quint32 headerSize = sizeof(KTXHeader);
|
||||||
|
|
||||||
// Currently unused, declared for future reference
|
// Currently unused, declared for future reference
|
||||||
struct KTXKeyValuePairItem {
|
struct KTXKeyValuePairItem {
|
||||||
@ -111,7 +116,8 @@ QTextureFileData QKtxHandler::read()
|
|||||||
return QTextureFileData();
|
return QTextureFileData();
|
||||||
|
|
||||||
QByteArray buf = device()->readAll();
|
QByteArray buf = device()->readAll();
|
||||||
if (buf.size() < headerSize || !canRead(QByteArray(), buf)) {
|
const quint32 dataSize = quint32(buf.size());
|
||||||
|
if (dataSize < headerSize || !canRead(QByteArray(), buf)) {
|
||||||
qCDebug(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
|
qCDebug(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
|
||||||
return QTextureFileData();
|
return QTextureFileData();
|
||||||
}
|
}
|
||||||
@ -130,13 +136,17 @@ QTextureFileData QKtxHandler::read()
|
|||||||
texData.setGLInternalFormat(decode(header->glInternalFormat));
|
texData.setGLInternalFormat(decode(header->glInternalFormat));
|
||||||
texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat));
|
texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat));
|
||||||
|
|
||||||
//### For now, ignore any additional mipmap levels
|
texData.setNumLevels(decode(header->numberOfMipmapLevels));
|
||||||
texData.setNumLevels(1);
|
quint32 offset = headerSize + decode(header->bytesOfKeyValueData);
|
||||||
int preambleSize = headerSize + decode(header->bytesOfKeyValueData);
|
const int maxLevels = qMin(texData.numLevels(), 32); // Cap iterations in case of corrupt file.
|
||||||
if (buf.size() >= preambleSize + int(sizeof(KTXMipmapLevel))) {
|
for (int i = 0; i < maxLevels; i++) {
|
||||||
texData.setDataOffset(preambleSize + sizeof(quint32)); // for the imageSize
|
if (offset + sizeof(KTXMipmapLevel) > dataSize) // Corrupt file; avoid oob read
|
||||||
const KTXMipmapLevel *level = reinterpret_cast<const KTXMipmapLevel *>(buf.constData() + preambleSize);
|
break;
|
||||||
texData.setDataLength(decode(level->imageSize));
|
const KTXMipmapLevel *level = reinterpret_cast<const KTXMipmapLevel *>(buf.constData() + offset);
|
||||||
|
quint32 levelLen = decode(level->imageSize);
|
||||||
|
texData.setDataOffset(offset + sizeof(KTXMipmapLevel::imageSize), i);
|
||||||
|
texData.setDataLength(levelLen, i);
|
||||||
|
offset += sizeof(KTXMipmapLevel::imageSize) + levelLen + (3 - ((levelLen + 3) % 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!texData.isValid()) {
|
if (!texData.isValid()) {
|
||||||
@ -147,7 +157,7 @@ QTextureFileData QKtxHandler::read()
|
|||||||
texData.setLogName(logName());
|
texData.setLogName(logName());
|
||||||
|
|
||||||
#ifdef KTX_DEBUG
|
#ifdef KTX_DEBUG
|
||||||
qDebug() << "KTX file handler read" << texData.data();
|
qDebug() << "KTX file handler read" << texData;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return texData;
|
return texData;
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>texturefiles/car.ktx</file>
|
<file>texturefiles/car.ktx</file>
|
||||||
<file>texturefiles/pattern.pkm</file>
|
<file>texturefiles/pattern.pkm</file>
|
||||||
|
<file>texturefiles/car_mips.ktx</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
BIN
tests/auto/gui/util/qtexturefilereader/texturefiles/car_mips.ktx
Normal file
BIN
tests/auto/gui/util/qtexturefilereader/texturefiles/car_mips.ktx
Normal file
Binary file not shown.
@ -44,26 +44,38 @@ void tst_qtexturefilereader::checkHandlers_data()
|
|||||||
QTest::addColumn<QSize>("size");
|
QTest::addColumn<QSize>("size");
|
||||||
QTest::addColumn<quint32>("glFormat");
|
QTest::addColumn<quint32>("glFormat");
|
||||||
QTest::addColumn<quint32>("glInternalFormat");
|
QTest::addColumn<quint32>("glInternalFormat");
|
||||||
// todo: glBaseInternalFormat
|
QTest::addColumn<quint32>("glBaseInternalFormat");
|
||||||
QTest::addColumn<int>("levels");
|
QTest::addColumn<int>("levels");
|
||||||
QTest::addColumn<int>("dataOffset");
|
QTest::addColumn<QList<int>>("dataOffsets");
|
||||||
QTest::addColumn<int>("dataLength");
|
QTest::addColumn<QList<int>>("dataLengths");
|
||||||
|
|
||||||
QTest::addRow("pattern.pkm") << QStringLiteral(":/texturefiles/pattern.pkm")
|
QTest::addRow("pattern.pkm") << QStringLiteral(":/texturefiles/pattern.pkm")
|
||||||
<< QSize(64, 64)
|
<< QSize(64, 64)
|
||||||
<< quint32(0x0)
|
<< quint32(0x0)
|
||||||
<< quint32(0x8d64)
|
<< quint32(0x8d64)
|
||||||
|
<< quint32(0x0)
|
||||||
<< 1
|
<< 1
|
||||||
<< 16
|
<< (QList<int>() << 16)
|
||||||
<< 2048;
|
<< (QList<int>() << 2048);
|
||||||
|
|
||||||
QTest::addRow("car.ktx") << QStringLiteral(":/texturefiles/car.ktx")
|
QTest::addRow("car.ktx") << QStringLiteral(":/texturefiles/car.ktx")
|
||||||
<< QSize(146, 80)
|
<< QSize(146, 80)
|
||||||
<< quint32(0x0)
|
<< quint32(0x0)
|
||||||
<< quint32(0x9278)
|
<< quint32(0x9278)
|
||||||
|
<< quint32(0x1908)
|
||||||
<< 1
|
<< 1
|
||||||
<< 68
|
<< (QList<int>() << 68)
|
||||||
<< 11840;
|
<< (QList<int>() << 11840);
|
||||||
|
|
||||||
|
QTest::addRow("car_mips.ktx") << QStringLiteral(":/texturefiles/car_mips.ktx")
|
||||||
|
<< QSize(146, 80)
|
||||||
|
<< quint32(0x0)
|
||||||
|
<< quint32(0x9274)
|
||||||
|
<< quint32(0x1907)
|
||||||
|
<< 8
|
||||||
|
<< (QList<int>() << 68 << 5992 << 7516 << 7880 << 8004 << 8056 << 8068 << 8080)
|
||||||
|
<< (QList<int>() << 5920 << 1520 << 360 << 120 << 48 << 8 << 8 << 8);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_qtexturefilereader::checkHandlers()
|
void tst_qtexturefilereader::checkHandlers()
|
||||||
@ -73,8 +85,8 @@ void tst_qtexturefilereader::checkHandlers()
|
|||||||
QFETCH(quint32, glFormat);
|
QFETCH(quint32, glFormat);
|
||||||
QFETCH(quint32, glInternalFormat);
|
QFETCH(quint32, glInternalFormat);
|
||||||
QFETCH(int, levels);
|
QFETCH(int, levels);
|
||||||
QFETCH(int, dataOffset);
|
QFETCH(QList<int>, dataOffsets);
|
||||||
QFETCH(int, dataLength);
|
QFETCH(QList<int>, dataLengths);
|
||||||
|
|
||||||
QFile f(fileName);
|
QFile f(fileName);
|
||||||
QVERIFY(f.open(QIODevice::ReadOnly));
|
QVERIFY(f.open(QIODevice::ReadOnly));
|
||||||
@ -88,8 +100,10 @@ void tst_qtexturefilereader::checkHandlers()
|
|||||||
QCOMPARE(tex.glFormat(), glFormat);
|
QCOMPARE(tex.glFormat(), glFormat);
|
||||||
QCOMPARE(tex.glInternalFormat(), glInternalFormat);
|
QCOMPARE(tex.glInternalFormat(), glInternalFormat);
|
||||||
QCOMPARE(tex.numLevels(), levels);
|
QCOMPARE(tex.numLevels(), levels);
|
||||||
QCOMPARE(tex.dataOffset(), dataOffset);
|
for (int i = 0; i < tex.numLevels(); i++) {
|
||||||
QCOMPARE(tex.dataLength(), dataLength);
|
QCOMPARE(tex.dataOffset(i), dataOffsets.at(i));
|
||||||
|
QCOMPARE(tex.dataLength(i), dataLengths.at(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_qtexturefilereader)
|
QTEST_MAIN(tst_qtexturefilereader)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user