1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qpkmhandler_p.h"
5#include "qtexturefiledata_p.h"
6
7#include <QFile>
8#include <QDebug>
9#include <QSize>
10#include <qendian.h>
11
12//#define ETC_DEBUG
13
14QT_BEGIN_NAMESPACE
15
16static const int qpkmh_headerSize = 16;
17
18struct PkmType
19{
20 quint32 glFormat;
21 quint32 bytesPerBlock;
22};
23
24static constexpr PkmType typeMap[5] = {
25 { .glFormat: 0x8D64, .bytesPerBlock: 8 }, // GL_ETC1_RGB8_OES
26 { .glFormat: 0x9274, .bytesPerBlock: 8 }, // GL_COMPRESSED_RGB8_ETC2
27 { .glFormat: 0, .bytesPerBlock: 0 }, // unused (obsolete)
28 { .glFormat: 0x9278, .bytesPerBlock: 16}, // GL_COMPRESSED_RGBA8_ETC2_EAC
29 { .glFormat: 0x9276, .bytesPerBlock: 8 } // GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
30};
31
32QPkmHandler::~QPkmHandler() = default;
33
34bool QPkmHandler::canRead(const QByteArray &suffix, const QByteArray &block)
35{
36 Q_UNUSED(suffix);
37
38 return block.startsWith(bv: "PKM ");
39}
40
41QTextureFileData QPkmHandler::read()
42{
43 QTextureFileData texData;
44
45 if (!device())
46 return texData;
47
48 QByteArray fileData = device()->readAll();
49 if (fileData.size() < qpkmh_headerSize || !canRead(suffix: QByteArray(), block: fileData)) {
50 qCDebug(lcQtGuiTextureIO, "Invalid PKM file %s", logName().constData());
51 return QTextureFileData();
52 }
53 texData.setData(fileData);
54
55 const char *rawData = fileData.constData();
56
57 // ignore version (rawData + 4 & 5)
58
59 // texture type
60 quint16 type = qFromBigEndian<quint16>(src: rawData + 6);
61 if (type >= sizeof(typeMap)/sizeof(typeMap[0])) {
62 qCDebug(lcQtGuiTextureIO, "Unknown compression format in PKM file %s", logName().constData());
63 return QTextureFileData();
64 }
65 texData.setGLFormat(0); // 0 for compressed textures
66 texData.setGLInternalFormat(typeMap[type].glFormat);
67 //### setBaseInternalFormat
68
69 // texture size
70 texData.setNumLevels(1);
71 texData.setNumFaces(1);
72 const int bpb = typeMap[type].bytesPerBlock;
73 QSize paddedSize(qFromBigEndian<quint16>(src: rawData + 8), qFromBigEndian<quint16>(src: rawData + 10));
74 texData.setDataLength(length: (paddedSize.width() / 4) * (paddedSize.height() / 4) * bpb);
75 QSize texSize(qFromBigEndian<quint16>(src: rawData + 12), qFromBigEndian<quint16>(src: rawData + 14));
76 texData.setSize(texSize);
77
78 texData.setDataOffset(offset: qpkmh_headerSize);
79
80 if (!texData.isValid()) {
81 qCDebug(lcQtGuiTextureIO, "Invalid values in header of PKM file %s", logName().constData());
82 return QTextureFileData();
83 }
84
85 texData.setLogName(logName());
86
87#ifdef ETC_DEBUG
88 qDebug() << "PKM file handler read" << texData;
89#endif
90 return texData;
91}
92
93QT_END_NAMESPACE
94

source code of qtbase/src/gui/util/qpkmhandler.cpp