/**************************************************************************** ** ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ****************************************************************************/ #include "qtextureimagedata_p.h" #include #include #include QT_BEGIN_NAMESPACE namespace Qt3DRender { QTextureImageDataPrivate::QTextureImageDataPrivate() : m_width(-1) , m_height(-1) , m_depth(-1) , m_layers(-1) , m_faces(-1) , m_mipLevels(-1) , m_blockSize(-1) , m_alignment(1) , m_target(QOpenGLTexture::Target2D) , m_format(QOpenGLTexture::NoFormat) , m_pixelFormat(QOpenGLTexture::RGBA) , m_pixelType(QOpenGLTexture::UInt8) , m_isCompressed(false) , m_isKtx(false) { } QByteArray QTextureImageDataPrivate::ktxData(int layer, int face, int mipmapLevel) const { Q_ASSERT(layer >= 0 && layer < m_layers && face >= 0 && face < m_faces && mipmapLevel >= 0 && mipmapLevel < m_mipLevels); int offset = 0; for (int i = 0; i < mipmapLevel; i++) offset += (mipmapLevelSize(i) * m_faces * m_layers) + 4; const int selectedMipmapLevelSize = mipmapLevelSize(mipmapLevel); offset += (selectedMipmapLevelSize * m_faces * layer) + (selectedMipmapLevelSize * face) + 4; return QByteArray::fromRawData(m_data.constData() + offset, selectedMipmapLevelSize); } QByteArray QTextureImageDataPrivate::data(int layer, int face, int mipmapLevel) const { if (layer < 0 || layer >= m_layers || face < 0 || face >= m_faces || mipmapLevel < 0 || mipmapLevel >= m_mipLevels) { qWarning() << Q_FUNC_INFO << "Requesting texture data for invalid layer, face or mipMapLevel"; return QByteArray(); } if (m_dataExtractor) return m_dataExtractor(m_data, layer, face, mipmapLevel); if (m_isKtx) return ktxData(layer, face, mipmapLevel); int offset = layer * ddsLayerSize() + face * ddsFaceSize(); for (int i = 0; i < mipmapLevel; i++) offset += mipmapLevelSize(i); return QByteArray::fromRawData(m_data.constData() + offset, mipmapLevelSize(mipmapLevel)); } QTextureImageDataPrivate *QTextureImageDataPrivate::get(QTextureImageData *imageData) { return imageData->d_func(); } void QTextureImageDataPrivate::setData(const QByteArray &data, int blockSize, bool isCompressed) { m_isCompressed = isCompressed; m_data = data; m_blockSize = blockSize; } void QTextureImageDataPrivate::setData(const QByteArray &data, std::function dataExtractor, bool isCompressed) { m_isCompressed = isCompressed; m_data = data; m_dataExtractor = dataExtractor; } int QTextureImageDataPrivate::ddsLayerSize() const { return m_faces * ddsFaceSize(); } int QTextureImageDataPrivate::ddsFaceSize() const { int size = 0; for (int i = 0; i < m_mipLevels; i++) size += mipmapLevelSize(i); return size; } // XXX check if this works for ETC1 compression int QTextureImageDataPrivate::mipmapLevelSize(int level) const { int w = qMax(m_width >> level, 1); int h = qMax(m_height >> level, 1); int d = qMax(m_depth >> level, 1); if (m_isCompressed) return ((w + 3) / 4) * ((h + 3) / 4) * m_blockSize * d; else return w * h * m_blockSize * d; } /*! \class Qt3DRender::QTextureImageData \inmodule Qt3DRender \since 5.5 \brief QTextureImageData stores data representing a texture. */ /*! Constructs a new Qt3DRender::QTextureImageData. */ QTextureImageData::QTextureImageData() : d_ptr(new QTextureImageDataPrivate()) { } /*! \internal */ QTextureImageData::QTextureImageData(QTextureImageDataPrivate &dd) : d_ptr(&dd) { } /*! \internal */ QTextureImageData::~QTextureImageData() { cleanup(); delete d_ptr; } QTextureImageData &QTextureImageData::operator=(const QTextureImageData &other) { Q_D(QTextureImageData); *d = *other.d_ptr; return *this; } /*! Remove stored texture data and return the object to its initial state */ void QTextureImageData::cleanup() Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_width = -1; d->m_height = -1; d->m_depth = -1; d->m_layers = -1; d->m_faces = -1; d->m_mipLevels = -1; d->m_blockSize = 0; d->m_alignment = 1; d->m_isCompressed = false; d->m_data.clear(); } /*! \return true if the stored texture is in a compressed format */ bool QTextureImageData::isCompressed() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_isCompressed; } /*! \return the width of the stored texture */ int QTextureImageData::width() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_width; } /*! \return the height of the stored texture */ int QTextureImageData::height() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_height; } /*! \return the depth of the stored texture */ int QTextureImageData::depth() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_depth; } /*! \return the number of layers in the stored texture */ int QTextureImageData::layers() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_layers; } /*! \return the number of mip levels in the stored texture */ int QTextureImageData::mipLevels() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_mipLevels; } /*! \return the number of faces in the stored texture */ int QTextureImageData::faces() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_faces;; } /*! * Sets the width to \a width. * \param setWidth */ void QTextureImageData::setWidth(int width) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_width = width; } /*! * Sets the height to \a height. * \param setHeight */ void QTextureImageData::setHeight(int height) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_height = height; } /*! * Sets the depth to \a depth. * \param setDepth */ void QTextureImageData::setDepth(int depth) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_depth = depth; } /*! * Sets the layers to \a layers. * \param setLayers */ void QTextureImageData::setLayers(int layers) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_layers = layers; } /*! * Sets the mip levels to \a mipLevels. * \param setMipLevels */ void QTextureImageData::setMipLevels(int mipLevels) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_mipLevels = mipLevels; } /*! * Sets the faces to \a faces. * \param setFaces */ void QTextureImageData::setFaces(int faces) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_faces = faces; } /*! \return the target for the stored texture */ QOpenGLTexture::Target QTextureImageData::target() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_target; } /*! \return the format of the stored texture */ QOpenGLTexture::TextureFormat QTextureImageData::format() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_format; } /*! * Sets the target to \a target. * \param target */ void QTextureImageData::setTarget(QOpenGLTexture::Target target) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_target = target; } /*! * Sets the format to \a format. * \param */ void QTextureImageData::setFormat(QOpenGLTexture::TextureFormat format) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_format = format; } /*! * Sets the pixel format to \a pixelFormat. * \param setPixelFormat */ void QTextureImageData::setPixelFormat(QOpenGLTexture::PixelFormat pixelFormat) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_pixelFormat = pixelFormat; } /*! * Sets the pixel type to \a pixelType * \param setPixelType */ void QTextureImageData::setPixelType(QOpenGLTexture::PixelType pixelType) Q_DECL_NOTHROW { Q_D(QTextureImageData); d->m_pixelType = pixelType; } /*! Copies the image \a image as raw data within this object */ void QTextureImageData::setImage(const QImage &image) { Q_D(QTextureImageData); d->m_width = image.width(); d->m_height = image.height(); d->m_depth = 1; d->m_faces = 1; d->m_layers = 1; d->m_mipLevels = 1; QImage glImage = image.convertToFormat(QImage::Format_RGBA8888); Q_ASSERT_X(glImage.bytesPerLine() == (glImage.width() * glImage.depth() + 7) / 8, "QTextureImageData::setImage", "glImage is not packed"); // QTBUG-48330 d->m_blockSize = 4; QByteArray imageBytes((const char*) glImage.constBits(), glImage.sizeInBytes()); setData(imageBytes, d->m_blockSize, false); d->m_format = QOpenGLTexture::RGBA8_UNorm; d->m_pixelFormat = QOpenGLTexture::RGBA; d->m_pixelType = QOpenGLTexture::UInt8; d->m_target = QOpenGLTexture::Target2D; } /*! Store the data \a data with blocksize \a blockSize and if the data to be stored is compressed \a isCompressed */ void QTextureImageData::setData(const QByteArray &data, int blockSize, bool isCompressed) { Q_D(QTextureImageData); d->setData(data, blockSize, isCompressed); } /*! \return the raw image data for the texture at layer \a layer, face \a face and mipmapLevel \a mipmapLevel */ QByteArray QTextureImageData::data(int layer, int face, int mipmapLevel) const { Q_D(const QTextureImageData); return d->data(layer, face, mipmapLevel); } /*! \return the pixel format of the stored texture */ QOpenGLTexture::PixelFormat QTextureImageData::pixelFormat() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_pixelFormat; } /*! \return the pixel type of the stored texture */ QOpenGLTexture::PixelType QTextureImageData::pixelType() const Q_DECL_NOTHROW { Q_D(const QTextureImageData); return d->m_pixelType; } } // namespace Qt3DRender QT_END_NAMESPACE