Revision control

++ // Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++ #include "qtextureimagedata_p.h"
++ #include <QFileInfo>
++ #include <QFile>
++ #include <QDebug>
++
++ 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<QByteArray(QByteArray rawData, int layer, int face, int mipmapLevel)> 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() noexcept
++ {
++ 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 noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_isCompressed;
++ }
++
++ /*!
++ \return the width of the stored texture
++ */
++ int QTextureImageData::width() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_width;
++ }
++
++ /*!
++ \return the height of the stored texture
++ */
++ int QTextureImageData::height() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_height;
++ }
++
++ /*!
++ \return the depth of the stored texture
++ */
++ int QTextureImageData::depth() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_depth;
++ }
++
++ /*!
++ \return the number of layers in the stored texture
++ */
++ int QTextureImageData::layers() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_layers;
++ }
++
++ /*!
++ \return the number of mip levels in the stored texture
++ */
++ int QTextureImageData::mipLevels() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_mipLevels;
++ }
++
++ /*!
++ \return the number of faces in the stored texture
++ */
++ int QTextureImageData::faces() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_faces;;
++ }
++
++ /*!
++ * Sets the width to \a width.
++ * \param setWidth
++ */
++ void QTextureImageData::setWidth(int width) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_width = width;
++ }
++
++ /*!
++ * Sets the height to \a height.
++ * \param setHeight
++ */
++ void QTextureImageData::setHeight(int height) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_height = height;
++ }
++
++ /*!
++ * Sets the depth to \a depth.
++ * \param setDepth
++ */
++ void QTextureImageData::setDepth(int depth) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_depth = depth;
++ }
++
++ /*!
++ * Sets the layers to \a layers.
++ * \param setLayers
++ */
++ void QTextureImageData::setLayers(int layers) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_layers = layers;
++ }
++
++ /*!
++ * Sets the mip levels to \a mipLevels.
++ * \param setMipLevels
++ */
++ void QTextureImageData::setMipLevels(int mipLevels) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_mipLevels = mipLevels;
++ }
++
++ /*!
++ * Sets the faces to \a faces.
++ * \param setFaces
++ */
++ void QTextureImageData::setFaces(int faces) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_faces = faces;
++ }
++
++ /*!
++ * Sets the \a alignment requirements for the image.
++ */
++ void QTextureImageData::setAlignment(int alignment) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_alignment = alignment;
++ }
++
++ /*!
++ \return the alignment requirement for the image.
++ */
++ int QTextureImageData::alignment() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_alignment;
++ }
++
++ /*!
++ \return the target for the stored texture.
++ */
++ QOpenGLTexture::Target QTextureImageData::target() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_target;
++ }
++
++ /*!
++ \return the format of the stored texture.
++ */
++ QOpenGLTexture::TextureFormat QTextureImageData::format() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_format;
++ }
++
++ /*!
++ * Sets the target to \a target.
++ */
++ void QTextureImageData::setTarget(QOpenGLTexture::Target target) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_target = target;
++ }
++
++ /*!
++ * Sets the format to \a format.
++ */
++ void QTextureImageData::setFormat(QOpenGLTexture::TextureFormat format) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_format = format;
++ }
++
++ /*!
++ * Sets the pixel format to \a pixelFormat.
++ */
++ void QTextureImageData::setPixelFormat(QOpenGLTexture::PixelFormat pixelFormat) noexcept
++ {
++ Q_D(QTextureImageData);
++ d->m_pixelFormat = pixelFormat;
++ }
++
++ /*!
++ * Sets the pixel type to \a pixelType.
++ */
++ void QTextureImageData::setPixelType(QOpenGLTexture::PixelType pixelType) noexcept
++ {
++ 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;
++ }
++
++ /*!
++ Stores 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);
++ }
++
++ void QTextureImageData::setData(const QByteArray &data, std::function<QByteArray(QByteArray data, int layer, int face, int mipmapLevel)> dataExtractor, bool isCompressed)
++ {
++ Q_D(QTextureImageData);
++ d->setData(data, dataExtractor, 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 noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_pixelFormat;
++ }
++
++ /*!
++ \return the pixel type of the stored texture.
++ */
++ QOpenGLTexture::PixelType QTextureImageData::pixelType() const noexcept
++ {
++ Q_D(const QTextureImageData);
++ return d->m_pixelType;
++ }
++
++ } // namespace Qt3DRender
++
++ QT_END_NAMESPACE