1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qtextureimagedata_p.h"
41#include <QDebug>
42#include <QFileInfo>
43#include <QFile>
44
45QT_BEGIN_NAMESPACE
46
47namespace Qt3DRender {
48
49QTextureImageDataPrivate::QTextureImageDataPrivate()
50 : m_width(-1)
51 , m_height(-1)
52 , m_depth(-1)
53 , m_layers(-1)
54 , m_faces(-1)
55 , m_mipLevels(-1)
56 , m_blockSize(-1)
57 , m_alignment(1)
58 , m_target(QOpenGLTexture::Target2D)
59 , m_format(QOpenGLTexture::NoFormat)
60 , m_pixelFormat(QOpenGLTexture::RGBA)
61 , m_pixelType(QOpenGLTexture::UInt8)
62 , m_isCompressed(false)
63 , m_isKtx(false)
64{
65}
66
67QByteArray QTextureImageDataPrivate::ktxData(int layer, int face, int mipmapLevel) const
68{
69 Q_ASSERT(layer >= 0 && layer < m_layers &&
70 face >= 0 && face < m_faces &&
71 mipmapLevel >= 0 && mipmapLevel < m_mipLevels);
72
73 int offset = 0;
74 for (int i = 0; i < mipmapLevel; i++)
75 offset += (mipmapLevelSize(level: i) * m_faces * m_layers) + 4;
76 const int selectedMipmapLevelSize = mipmapLevelSize(level: mipmapLevel);
77 offset += (selectedMipmapLevelSize * m_faces * layer) + (selectedMipmapLevelSize * face) + 4;
78
79 return QByteArray::fromRawData(m_data.constData() + offset, size: selectedMipmapLevelSize);
80}
81
82QByteArray QTextureImageDataPrivate::data(int layer, int face, int mipmapLevel) const
83{
84 if (layer < 0 || layer >= m_layers ||
85 face < 0 || face >= m_faces ||
86 mipmapLevel < 0 || mipmapLevel >= m_mipLevels) {
87 qWarning() << Q_FUNC_INFO << "Requesting texture data for invalid layer, face or mipMapLevel";
88 return QByteArray();
89 }
90
91 if (m_dataExtractor)
92 return m_dataExtractor(m_data, layer, face, mipmapLevel);
93
94 if (m_isKtx)
95 return ktxData(layer, face, mipmapLevel);
96
97 int offset = layer * ddsLayerSize() + face * ddsFaceSize();
98
99 for (int i = 0; i < mipmapLevel; i++)
100 offset += mipmapLevelSize(level: i);
101
102 return QByteArray::fromRawData(m_data.constData() + offset, size: mipmapLevelSize(level: mipmapLevel));
103}
104
105QTextureImageDataPrivate *QTextureImageDataPrivate::get(QTextureImageData *imageData)
106{
107 return imageData->d_func();
108}
109
110void QTextureImageDataPrivate::setData(const QByteArray &data,
111 int blockSize,
112 bool isCompressed)
113{
114 m_isCompressed = isCompressed;
115 m_data = data;
116 m_blockSize = blockSize;
117}
118
119void QTextureImageDataPrivate::setData(const QByteArray &data,
120 std::function<QByteArray(QByteArray rawData, int layer, int face, int mipmapLevel)> dataExtractor,
121 bool isCompressed)
122{
123 m_isCompressed = isCompressed;
124 m_data = data;
125 m_dataExtractor = dataExtractor;
126}
127
128int QTextureImageDataPrivate::ddsLayerSize() const
129{
130 return m_faces * ddsFaceSize();
131}
132
133int QTextureImageDataPrivate::ddsFaceSize() const
134{
135 int size = 0;
136
137 for (int i = 0; i < m_mipLevels; i++)
138 size += mipmapLevelSize(level: i);
139
140 return size;
141}
142
143// XXX check if this works for ETC1 compression
144int QTextureImageDataPrivate::mipmapLevelSize(int level) const
145{
146 int w = qMax(a: m_width >> level, b: 1);
147 int h = qMax(a: m_height >> level, b: 1);
148 int d = qMax(a: m_depth >> level, b: 1);
149
150 if (m_isCompressed)
151 return ((w + 3) / 4) * ((h + 3) / 4) * m_blockSize * d;
152 else
153 return w * h * m_blockSize * d;
154}
155
156/*!
157 \class Qt3DRender::QTextureImageData
158 \inmodule Qt3DRender
159 \since 5.5
160 \brief QTextureImageData stores data representing a texture.
161 */
162
163/*!
164 Constructs a new Qt3DRender::QTextureImageData.
165*/
166QTextureImageData::QTextureImageData()
167 : d_ptr(new QTextureImageDataPrivate())
168{
169}
170
171/*! \internal */
172QTextureImageData::QTextureImageData(QTextureImageDataPrivate &dd)
173 : d_ptr(&dd)
174{
175}
176
177/*! \internal */
178QTextureImageData::~QTextureImageData()
179{
180 cleanup();
181 delete d_ptr;
182}
183
184QTextureImageData &QTextureImageData::operator=(const QTextureImageData &other)
185{
186 Q_D(QTextureImageData);
187 *d = *other.d_ptr;
188 return *this;
189}
190
191/*!
192 Remove stored texture data and return the object to its initial state
193 */
194void QTextureImageData::cleanup() Q_DECL_NOTHROW
195{
196 Q_D(QTextureImageData);
197 d->m_width = -1;
198 d->m_height = -1;
199 d->m_depth = -1;
200 d->m_layers = -1;
201 d->m_faces = -1;
202 d->m_mipLevels = -1;
203 d->m_blockSize = 0;
204 d->m_alignment = 1;
205 d->m_isCompressed = false;
206 d->m_data.clear();
207}
208
209/*!
210 \return true if the stored texture is in a compressed format
211 */
212bool QTextureImageData::isCompressed() const Q_DECL_NOTHROW
213{
214 Q_D(const QTextureImageData);
215 return d->m_isCompressed;
216}
217
218/*!
219 \return the width of the stored texture
220*/
221int QTextureImageData::width() const Q_DECL_NOTHROW
222{
223 Q_D(const QTextureImageData);
224 return d->m_width;
225}
226
227/*!
228 \return the height of the stored texture
229 */
230int QTextureImageData::height() const Q_DECL_NOTHROW
231{
232 Q_D(const QTextureImageData);
233 return d->m_height;
234}
235
236/*!
237 \return the depth of the stored texture
238 */
239int QTextureImageData::depth() const Q_DECL_NOTHROW
240{
241 Q_D(const QTextureImageData);
242 return d->m_depth;
243}
244
245/*!
246 \return the number of layers in the stored texture
247 */
248int QTextureImageData::layers() const Q_DECL_NOTHROW
249{
250 Q_D(const QTextureImageData);
251 return d->m_layers;
252}
253
254/*!
255 \return the number of mip levels in the stored texture
256 */
257int QTextureImageData::mipLevels() const Q_DECL_NOTHROW
258{
259 Q_D(const QTextureImageData);
260 return d->m_mipLevels;
261}
262
263/*!
264 \return the number of faces in the stored texture
265 */
266int QTextureImageData::faces() const Q_DECL_NOTHROW
267{
268 Q_D(const QTextureImageData);
269 return d->m_faces;;
270}
271
272/*!
273 * Sets the width to \a width.
274 * \param setWidth
275 */
276void QTextureImageData::setWidth(int width) Q_DECL_NOTHROW
277{
278 Q_D(QTextureImageData);
279 d->m_width = width;
280}
281
282/*!
283 * Sets the height to \a height.
284 * \param setHeight
285 */
286void QTextureImageData::setHeight(int height) Q_DECL_NOTHROW
287{
288 Q_D(QTextureImageData);
289 d->m_height = height;
290}
291
292/*!
293 * Sets the depth to \a depth.
294 * \param setDepth
295 */
296void QTextureImageData::setDepth(int depth) Q_DECL_NOTHROW
297{
298 Q_D(QTextureImageData);
299 d->m_depth = depth;
300}
301
302/*!
303 * Sets the layers to \a layers.
304 * \param setLayers
305 */
306void QTextureImageData::setLayers(int layers) Q_DECL_NOTHROW
307{
308 Q_D(QTextureImageData);
309 d->m_layers = layers;
310}
311
312/*!
313 * Sets the mip levels to \a mipLevels.
314 * \param setMipLevels
315 */
316void QTextureImageData::setMipLevels(int mipLevels) Q_DECL_NOTHROW
317{
318 Q_D(QTextureImageData);
319 d->m_mipLevels = mipLevels;
320}
321
322/*!
323 * Sets the faces to \a faces.
324 * \param setFaces
325 */
326void QTextureImageData::setFaces(int faces) Q_DECL_NOTHROW
327{
328 Q_D(QTextureImageData);
329 d->m_faces = faces;
330}
331
332/*!
333 \return the target for the stored texture
334 */
335QOpenGLTexture::Target QTextureImageData::target() const Q_DECL_NOTHROW
336{
337 Q_D(const QTextureImageData);
338 return d->m_target;
339}
340
341/*!
342 \return the format of the stored texture
343 */
344QOpenGLTexture::TextureFormat QTextureImageData::format() const Q_DECL_NOTHROW
345{
346 Q_D(const QTextureImageData);
347 return d->m_format;
348}
349
350/*!
351 * Sets the target to \a target.
352 * \param target
353 */
354void QTextureImageData::setTarget(QOpenGLTexture::Target target) Q_DECL_NOTHROW
355{
356 Q_D(QTextureImageData);
357 d->m_target = target;
358}
359
360/*!
361 * Sets the format to \a format.
362 * \param
363 */
364void QTextureImageData::setFormat(QOpenGLTexture::TextureFormat format) Q_DECL_NOTHROW
365{
366 Q_D(QTextureImageData);
367 d->m_format = format;
368}
369
370/*!
371 * Sets the pixel format to \a pixelFormat.
372 * \param setPixelFormat
373 */
374void QTextureImageData::setPixelFormat(QOpenGLTexture::PixelFormat pixelFormat) Q_DECL_NOTHROW
375{
376 Q_D(QTextureImageData);
377 d->m_pixelFormat = pixelFormat;
378}
379
380/*!
381 * Sets the pixel type to \a pixelType
382 * \param setPixelType
383 */
384void QTextureImageData::setPixelType(QOpenGLTexture::PixelType pixelType) Q_DECL_NOTHROW
385{
386 Q_D(QTextureImageData);
387 d->m_pixelType = pixelType;
388}
389
390/*!
391 Copies the image \a image as raw data within this object
392 */
393void QTextureImageData::setImage(const QImage &image)
394{
395 Q_D(QTextureImageData);
396 d->m_width = image.width();
397 d->m_height = image.height();
398 d->m_depth = 1;
399 d->m_faces = 1;
400 d->m_layers = 1;
401 d->m_mipLevels = 1;
402 QImage glImage = image.convertToFormat(f: QImage::Format_RGBA8888);
403 Q_ASSERT_X(glImage.bytesPerLine() == (glImage.width() * glImage.depth() + 7) / 8,
404 "QTextureImageData::setImage", "glImage is not packed"); // QTBUG-48330
405 d->m_blockSize = 4;
406 QByteArray imageBytes((const char*) glImage.constBits(), glImage.sizeInBytes());
407 setData(data: imageBytes, blockSize: d->m_blockSize, isCompressed: false);
408 d->m_format = QOpenGLTexture::RGBA8_UNorm;
409 d->m_pixelFormat = QOpenGLTexture::RGBA;
410 d->m_pixelType = QOpenGLTexture::UInt8;
411 d->m_target = QOpenGLTexture::Target2D;
412}
413
414/*!
415 Store the data \a data with blocksize \a blockSize and if the data to be stored is compressed \a isCompressed
416 */
417void QTextureImageData::setData(const QByteArray &data, int blockSize, bool isCompressed)
418{
419 Q_D(QTextureImageData);
420 d->setData(data, blockSize, isCompressed);
421}
422
423/*!
424 \return the raw image data for the texture at layer \a layer, face \a face and mipmapLevel \a mipmapLevel
425 */
426QByteArray QTextureImageData::data(int layer, int face, int mipmapLevel) const
427{
428 Q_D(const QTextureImageData);
429 return d->data(layer, face, mipmapLevel);
430}
431
432/*!
433 \return the pixel format of the stored texture
434 */
435QOpenGLTexture::PixelFormat QTextureImageData::pixelFormat() const Q_DECL_NOTHROW
436{
437 Q_D(const QTextureImageData);
438 return d->m_pixelFormat;
439}
440
441/*!
442 \return the pixel type of the stored texture
443 */
444QOpenGLTexture::PixelType QTextureImageData::pixelType() const Q_DECL_NOTHROW
445{
446 Q_D(const QTextureImageData);
447 return d->m_pixelType;
448}
449
450} // namespace Qt3DRender
451
452QT_END_NAMESPACE
453

source code of qt3d/src/render/texture/qtextureimagedata.cpp