Better_Software_Header_MobileBetter_Software_Header_Web

Find what you need - explore our website and developer resources

Efficiency Matters!

Streamlining your Modern UX with Compressed Textures


    class CompressedSGTexture : public QSGTexture
    {
        Q_OBJECT

    public:
        CompressedSGTexture(const PKMImage &image);
        ~CompressedSGTexture();
        void bind() Q_DECL_OVERRIDE;
        bool hasAlphaChannel() const Q_DECL_OVERRIDE;
        bool hasMipmaps() const Q_DECL_OVERRIDE;

        int textureId() const Q_DECL_OVERRIDE;
        QSize textureSize() const Q_DECL_OVERRIDE;

    private:
        PKMImage m_image;
        QScopedPointer ⟨QOpenGLTexture⟩ m_texture;
    };

QQuickTextureFactory *CompressedTextureImageProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
{
    Q_UNUSED(requestedSize);

    QFile imageFile(QStringLiteral(:/%1.pkm”).arg(id));
    if (!imageFile.open(QFile::ReadOnly))
        return 0;

    QByteArray header = imageFile.read(PKM_HEADER_LENGTH);
    if (header.length() != PKM_HEADER_LENGTH) {
        qWarning() ⟨⟨ “PKM header too short;
        return 0;
    }

    PKMImage image;
    const char *headerData = header.constData();

    // Parse the PKM header
    if (memcmp(headerData, PKM_HEADER_PREAMBLE, PKM_HEADER_PREAMBLE_LENGTH) != 0) {
        qWarning() ⟨⟨ “Malformed PKM header (missing heading);
        return 0;
    }
    headerData += 4;

    if (memcmp(headerData, PKM_HEADER_VERSION, PKM_HEADER_VERSION_LENGTH) != 0) {
        qWarning() ⟨⟨ “Malformed PKM header (wrong version);
        return 0;
    }
    headerData += 2;

#define UCC(x) (reinterpret_castconst uchar *(x))
    const quint16 dataType = qFromBigEndian⟨quint16⟩(UCC(headerData));
    if (dataType != PKM_ETC2_RGB_NO_MIPMAPS) {
        qWarning() ⟨⟨ “Malformed PKM header (wrong data type);
        return 0;
    }
    headerData += 2;

    image.effectiveSize.rwidth() = qFromBigEndian⟨quint16⟩(UCC(headerData));
    headerData += 2;
    image.effectiveSize.rheight() = qFromBigEndian⟨quint16⟩(UCC(headerData));
    headerData += 2;
    image.originalSize.rwidth() = qFromBigEndian⟨quint16⟩(UCC(headerData));
    headerData += 2;
    image.originalSize.rheight() = qFromBigEndian⟨quint16⟩(UCC(headerData));
    headerData += 2;
#undef UCC

    Q_ASSERT(image.effectiveSize.width() % 4 == 0);
    Q_ASSERT(image.effectiveSize.height() % 4 == 0);
    Q_ASSERT(headerData == header.constEnd());

    // Read out the payload
    const qint64 imageDataLength = ((image.effectiveSize.width() / 4) * (image.effectiveSize.height() / 4)) * 8;
    image.data = imageFile.read(imageDataLength);
    if (image.data.length() != imageDataLength) {
        qWarning() ⟨⟨ “Malformed PKM file: payload too short;
        return 0;
    }

    if (!imageFile.atEnd()) {
        qWarning() ⟨⟨ “Malformed PKM file: data after the payload”;
        return 0;
    }

    if (size)
        *size = image.effectiveSize;

    return new CompressedTextureFactory(image);
}

class CompressedTextureFactory : public QQuickTextureFactory
{

    Q_OBJECT
public:
    CompressedTextureFactory(const PKMImage &image);

    QSGTexture *createTexture(QQuickWindow *window) const Q_DECL_OVERRIDE;
    QImage image() const Q_DECL_OVERRIDE;
    int textureByteCount() const Q_DECL_OVERRIDE;
    QSize textureSize() const Q_DECL_OVERRIDE;

private:
    PKMImage m_image;
};

CompressedTextureFactory::CompressedTextureFactory(const PKMImage &image)
    : m_image(image)
{
}

QSGTexture *CompressedTextureFactory::createTexture(QQuickWindow *window) const
{
    Q_UNUSED(window);
    return new CompressedSGTexture(m_image);
}

QImage CompressedTextureFactory::image() const
{
    // FIXME/TODO: we can't easily get a QImage out of compressed texture data;
    // uncompressing image left as an exercise for the reader. This function
    // isn't called under normal circumstances...
    return QImage();
}

int CompressedTextureFactory::textureByteCount() const
{
    return m_image.data.length();
}

QSize CompressedTextureFactory::textureSize() const
{
    return m_image.effectiveSize;
}

2 Comments

21 - Nov - 2015

Daniel Kabel

21 - Nov - 2015

Andy Gryc

01_NoPhoto

Andy Gryc

Co-Founder at Third Law autotech marketing

GiuseppeD'Angelo

Giuseppe D’Angelo

Senior Software Engineer