1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3dtexturedata.h"
5#include "qquick3dtexturedata_p.h"
6#include <QtQuick3DUtils/private/qssgutils_p.h>
7#include <QtQuick3DRuntimeRender/private/qssgrendertexturedata_p.h>
8
9QT_BEGIN_NAMESPACE
10
11/*!
12 \qmltype TextureData
13 \inherits Object3D
14 \inqmlmodule QtQuick3D
15 \instantiates QQuick3DTextureData
16 \brief Base type for custom texture data.
17
18 Custom texture data allows using application-generated texture data, that
19 can possibly change dynamically as well. To use custom texture data set the
20 \l{Texture::textureData}{textureData} property of \l {Texture} to reference
21 a TextureData object.
22
23 Custom Texture data is implemented in C++ by creating a QQuick3DTextureData
24 instance, often subclassing it. The QQuick3DTextureData type is registered to
25 QML under the name of TextureData. Once the subclass is registered to QML,
26 Texture objects can start referencing it.
27
28 An example of when to use this API is when there is a need to procedurally
29 generate a texture at runtime rather than loading a static image from a file.
30
31 \code
32 import MyCustomTexture 1.0
33
34 Model {
35 source: "#Cube"
36 materials: [
37 DefaultMaterial {
38 diffuseMap: diffuseMapCustomTexture
39 }
40 ]
41 }
42
43 Texture {
44 id: diffuseMapCustomTexture
45 textureData: MyCustomTextureData {
46
47 }
48 }
49
50 \endcode
51
52 \sa Texture
53*/
54
55/*!
56 \class QQuick3DTextureData
57 \inmodule QtQuick3D
58 \inherits QQuick3DObject
59 \since 6.0
60 \brief Base class for defining custom texture data.
61
62 The QQuick3DTextureData class can be used to specify custom texture data for a
63 \l {Texture} in a Qt Quick 3D scene.
64
65 While not strictly required, the typical usage is to inherit from this class.
66 The subclass is then exposed to QML by registering it to the type system. The
67 \l{Texture::textureData}{textureData} property of a \l {QtQuick3D::Texture}{Texture}
68 can then be set to reference an instance of the registered type.
69
70 Example implementation:
71
72 \code
73 class CustomTextureData : public QQuick3DTextureData
74 {
75 Q_OBJECT
76 ... properties ...
77
78 public:
79 CustomTextureData() { regenerateTextureData(); }
80
81 void setProperty(...)
82 {
83 // Change relevant internal data.
84 // ...
85
86 // Update the texture data
87 regenerateTextureData();
88
89 // Finally, trigger an update. This is relevant in case nothing else
90 // is changed in the scene; this way we make sure a new frame will
91 // be rendered
92 update();
93 }
94 private:
95 void regenerateTextureData()
96 {
97 QByteArray textureData;
98 textureData = generateTextureData();
99 setTextureData(textureData);
100 setSize(QSize(256, 256));
101 setFormat(QQuick3DTextureData::Format::RGBA8)
102 setHasTransparency(true);
103 }
104 };
105 \endcode
106
107 This class can then be registered as a QML type and used with \l {QtQuick3D::Texture}{Texture}.
108
109 In Qt 5 type registration happened with qmlRegisterType:
110 \code
111 qmlRegisterType<MyCustomTextureData>("Example", 1, 0, "MyCustomTextureData");
112 \endcode
113
114 In Qt 6 the default approach is to use automatic registration with the help
115 of the build system. Instead of calling qmlRegisterType, the \c{.pro} file
116 can now contain:
117
118 \code
119 CONFIG += qmltypes
120 QML_IMPORT_NAME = Example
121 QML_IMPORT_MAJOR_VERSION = 1
122 \endcode
123
124 With CMake, automatic registration is the default behavior, so no special
125 settings are needed beyond basic QML module setup:
126 \code
127 qt_add_qml_module(application
128 URI Example
129 VERSION 1.0
130 )
131 \endcode
132
133 The class implementation should add QML_NAMED_ELEMENT:
134
135 \code
136 class CustomTextureData : public QQuick3DTextureData
137 {
138 Q_OBJECT
139 QML_NAMED_ELEMENT(MyCustomTextureData)
140 ...
141 };
142 \endcode
143
144 The QML code can then use the custom type:
145
146 \code
147 import Example 1.0
148
149 Model {
150 source: "#Cube"
151 materials: [
152 DefaultMaterial {
153 diffuseMap: diffuseMapCustomTexture
154 }
155 ]
156 Texture {
157 id: diffuseMapCustomTexture
158 textureData: MyCustomTextureData { }
159 }
160 }
161 \endcode
162*/
163
164/*!
165 \enum QQuick3DTextureData::Format
166 Returns the color format of the texture data assigned in \l textureData property.
167
168 \value None The color format is not defined
169 \value RGBA8 The color format is considered as 8-bit integer in R, G, B and alpha channels.
170 \value RGBA16F The color format is considered as 16-bit float in R,G,B and alpha channels.
171 \value RGBA32F The color format is considered as 32-bit float in R, G, B and alpha channels.
172 \value RGBE8 The color format is considered as 8-bit mantissa in the R, G, and B channels and 8-bit shared exponent.
173 \value R8 The color format is considered as 8-bit integer in R channel.
174 \value R16 The color format is considered as 16-bit integer in R channel.
175 \value R16F The color format is considered as 16-bit float in R channel.
176 \value R32F The color format is considered as 32-bit float R channel.
177 \value BC1 The color format is considred as BC1 compressed format with R, G, B, and alpha channels.
178 \value BC2 The color format is considred as BC2 compressed format with R, G, B, and alpha channels.
179 \value BC3 The color format is considred as BC3 compressed format with R, G, B, and alpha channels.
180 \value BC4 The color format is considred as BC4 compressed format with one color channel.
181 \value BC5 The color format is considred as BC5 compressed format with two color channels.
182 \value BC6H The color format is considred as BC6H compressed format with three high dynamic range color channels.
183 \value BC7 The color format is considred as BC7 compressed format with R, G, B, and alpha channels.
184 \value DXT1_RGBA The color format is considered as DXT1 compressed format with R, G, B and alpha channels.
185 \value DXT1_RGB The color format is considered as DXT1 compressed format with R, G and B channels.
186 \value DXT3_RGBA The color format is considered as DXT3 compressed format with R, G, B and alpha channels.
187 \value DXT5_RGBA The color format is considered as DXT5 compressed format with R, G, B and alpha channels.
188 \value ETC2_RGB8 The color format is considered as ETC2 compressed format for RGB888 data
189 \value ETC2_RGB8A1 The color format is considered as ETC2 compressed format for RGBA data where alpha is 1-bit.
190 \value ETC2_RGBA8 The color format is considered as ETC2 compressed format with RGBA8888 data.
191 \value ASTC_4x4 The color format is considered as ASTC compressed format with 4x4 block footprint.
192 \value ASTC_5x4 The color format is considered as ASTC compressed format with 5x4 block footprint.
193 \value ASTC_5x5 The color format is considered as ASTC compressed format with 5x5 block footprint.
194 \value ASTC_6x5 The color format is considered as ASTC compressed format with 6x5 block footprint.
195 \value ASTC_6x6 The color format is considered as ASTC compressed format with 6x6 block footprint.
196 \value ASTC_8x5 The color format is considered as ASTC compressed format with 8x5 block footprint.
197 \value ASTC_8x6 The color format is considered as ASTC compressed format with 8x6 block footprint.
198 \value ASTC_8x8 The color format is considered as ASTC compressed format with 8x8 block footprint.
199 \value ASTC_10x5 The color format is considered as ASTC compressed format with 10x5 block footprint.
200 \value ASTC_10x6 The color format is considered as ASTC compressed format with 10x6 block footprint.
201 \value ASTC_10x8 The color format is considered as ASTC compressed format with 10x8 block footprint.
202 \value ASTC_10x10 The color format is considered as ASTC compressed format with 10x10 block footprint.
203 \value ASTC_12x10 The color format is considered as ASTC compressed format with 12x10 block footprint.
204 \value ASTC_12x12 The color format is considered as ASTC compressed format with 12x12 block footprint.
205
206 \note With the exception of \c RGBA8, not every format is supported at runtime as this
207 depends on which backend is being used as well which hardware is being used.
208
209 \note \c RGBE is internally represented as an \c RGBA8 but is intepreted as described when used
210 as a lightProbe or skybox texture.
211
212 \note Using the value \c None will assume the default value of \c RGBA8
213*/
214
215
216QQuick3DTextureDataPrivate::QQuick3DTextureDataPrivate()
217 : QQuick3DObjectPrivate(QQuick3DTextureDataPrivate::Type::TextureData)
218{
219
220}
221
222QQuick3DTextureData::QQuick3DTextureData(QQuick3DObject *parent)
223 : QQuick3DObject(*new QQuick3DTextureDataPrivate, parent)
224{
225
226}
227
228QQuick3DTextureData::~QQuick3DTextureData()
229{
230
231}
232
233/*!
234 Returns the current texture data defined by this item.
235*/
236const QByteArray QQuick3DTextureData::textureData() const
237{
238 const Q_D(QQuick3DTextureData);
239 return d->textureData;
240
241}
242
243/*!
244 Sets the texture data. The contents of \a data must respect the \l size and
245 \l format properties as the backend will try and upload and use the data as if
246 it were a texture of size and format, and if there is any deviation the result
247 will be somewhere between incorrect rendering of the texture, or potentially a crash.
248*/
249
250void QQuick3DTextureData::setTextureData(const QByteArray &data)
251{
252 Q_D(QQuick3DTextureData);
253 d->textureData = data;
254 d->textureDataDirty = true;
255 update();
256}
257
258/*!
259 Returns the size of the texture data in pixels.
260*/
261QSize QQuick3DTextureData::size() const
262{
263 const Q_D(QQuick3DTextureData);
264 return d->size;
265}
266
267/*!
268 Sets the \a size of the texture data in pixels.
269*/
270void QQuick3DTextureData::setSize(const QSize &size)
271{
272 Q_D(QQuick3DTextureData);
273 d->size = size;
274 update();
275}
276
277/*!
278 Returns the depth of the texture data in pixels.
279*/
280int QQuick3DTextureData::depth() const
281{
282 const Q_D(QQuick3DTextureData);
283 return d->depth;
284}
285
286/*!
287 Sets the \a depth of the texture data in pixels. Setting the depth above
288 0 means that the texture is handled as a 3D texture.
289*/
290void QQuick3DTextureData::setDepth(int depth)
291{
292 Q_D(QQuick3DTextureData);
293 d->depth = depth;
294 update();
295}
296
297/*!
298 Returns the format of the texture data.
299*/
300QQuick3DTextureData::Format QQuick3DTextureData::format() const
301{
302 const Q_D(QQuick3DTextureData);
303 return d->format;
304}
305
306/*!
307 Sets the \a format of the texture data.
308
309 The default format is /c RGBA8
310*/
311void QQuick3DTextureData::setFormat(QQuick3DTextureData::Format format)
312{
313 Q_D(QQuick3DTextureData);
314 d->format = format;
315 update();
316}
317
318/*!
319 Returns \c true if the texture data has transparency.
320
321 The default value is \c false.
322*/
323bool QQuick3DTextureData::hasTransparency() const
324{
325 const Q_D(QQuick3DTextureData);
326 return d->hasTransparency;
327}
328
329/*!
330 Set \a hasTransparency to true if the texture data has an active alpha
331 channel with non-opaque values.
332
333 This is used as an optimization by the engine so that for formats that
334 do support an alpha channel do not need to have each value checked for
335 non-opaque values.
336*/
337void QQuick3DTextureData::setHasTransparency(bool hasTransparency)
338{
339 Q_D(QQuick3DTextureData);
340 d->hasTransparency = hasTransparency;
341 update();
342}
343
344
345static QSSGRenderTextureFormat::Format convertToBackendFormat(QQuick3DTextureData::Format format)
346{
347 switch (format) {
348 case QQuick3DTextureData::None:
349 case QQuick3DTextureData::RGBA8:
350 return QSSGRenderTextureFormat::RGBA8;
351 case QQuick3DTextureData::RGBA16F:
352 return QSSGRenderTextureFormat::RGBA16F;
353 case QQuick3DTextureData::RGBA32F:
354 return QSSGRenderTextureFormat::RGBA32F;
355 case QQuick3DTextureData::RGBE8:
356 return QSSGRenderTextureFormat::RGBE8;
357 case QQuick3DTextureData::R8:
358 return QSSGRenderTextureFormat::R8;
359 case QQuick3DTextureData::R16:
360 return QSSGRenderTextureFormat::R16;
361 case QQuick3DTextureData::R16F:
362 return QSSGRenderTextureFormat::R16F;
363 case QQuick3DTextureData::R32F:
364 return QSSGRenderTextureFormat::R32F;
365 case QQuick3DTextureData::BC1:
366 return QSSGRenderTextureFormat::BC1;
367 case QQuick3DTextureData::BC2:
368 return QSSGRenderTextureFormat::BC2;
369 case QQuick3DTextureData::BC3:
370 return QSSGRenderTextureFormat::BC3;
371 case QQuick3DTextureData::BC4:
372 return QSSGRenderTextureFormat::BC4;
373 case QQuick3DTextureData::BC5:
374 return QSSGRenderTextureFormat::BC5;
375 case QQuick3DTextureData::BC6H:
376 return QSSGRenderTextureFormat::BC6H;
377 case QQuick3DTextureData::BC7:
378 return QSSGRenderTextureFormat::BC7;
379 case QQuick3DTextureData::DXT1_RGBA:
380 return QSSGRenderTextureFormat::RGBA_DXT1;
381 case QQuick3DTextureData::DXT1_RGB:
382 return QSSGRenderTextureFormat::RGB_DXT1;
383 case QQuick3DTextureData::DXT3_RGBA:
384 return QSSGRenderTextureFormat::RGBA_DXT3;
385 case QQuick3DTextureData::DXT5_RGBA:
386 return QSSGRenderTextureFormat::RGBA_DXT5;
387 case QQuick3DTextureData::ETC2_RGB8:
388 return QSSGRenderTextureFormat::RGB8_ETC2;
389 case QQuick3DTextureData::ETC2_RGB8A1:
390 return QSSGRenderTextureFormat::RGB8_PunchThrough_Alpha1_ETC2;
391 case QQuick3DTextureData::ETC2_RGBA8:
392 return QSSGRenderTextureFormat::RGBA8_ETC2_EAC;
393 case QQuick3DTextureData::ASTC_4x4:
394 return QSSGRenderTextureFormat::RGBA_ASTC_4x4;
395 case QQuick3DTextureData::ASTC_5x4:
396 return QSSGRenderTextureFormat::RGBA_ASTC_5x4;
397 case QQuick3DTextureData::ASTC_5x5:
398 return QSSGRenderTextureFormat::RGBA_ASTC_5x5;
399 case QQuick3DTextureData::ASTC_6x5:
400 return QSSGRenderTextureFormat::RGBA_ASTC_6x5;
401 case QQuick3DTextureData::ASTC_6x6:
402 return QSSGRenderTextureFormat::RGBA_ASTC_6x6;
403 case QQuick3DTextureData::ASTC_8x5:
404 return QSSGRenderTextureFormat::RGBA_ASTC_8x5;
405 case QQuick3DTextureData::ASTC_8x6:
406 return QSSGRenderTextureFormat::RGBA_ASTC_8x6;
407 case QQuick3DTextureData::ASTC_8x8:
408 return QSSGRenderTextureFormat::RGBA_ASTC_8x8;
409 case QQuick3DTextureData::ASTC_10x5:
410 return QSSGRenderTextureFormat::RGBA_ASTC_10x5;
411 case QQuick3DTextureData::ASTC_10x6:
412 return QSSGRenderTextureFormat::RGBA_ASTC_10x6;
413 case QQuick3DTextureData::ASTC_10x8:
414 return QSSGRenderTextureFormat::RGBA_ASTC_10x8;
415 case QQuick3DTextureData::ASTC_10x10:
416 return QSSGRenderTextureFormat::RGBA_ASTC_10x10;
417 case QQuick3DTextureData::ASTC_12x10:
418 return QSSGRenderTextureFormat::RGBA_ASTC_12x10;
419 case QQuick3DTextureData::ASTC_12x12:
420 return QSSGRenderTextureFormat::RGBA_ASTC_12x12;
421 default:
422 return QSSGRenderTextureFormat::RGBA8;
423 }
424}
425
426/*!
427 \internal
428*/
429QSSGRenderGraphObject *QQuick3DTextureData::updateSpatialNode(QSSGRenderGraphObject *node)
430{
431 Q_D(QQuick3DTextureData);
432 if (!node) {
433 markAllDirty();
434 node = new QSSGRenderTextureData();
435 }
436 QQuick3DObject::updateSpatialNode(node);
437 auto *textureData = static_cast<QSSGRenderTextureData*>(node);
438
439 bool changed = false;
440
441 // Use a dirty flag so we don't compare large buffer values
442 if (d->textureDataDirty) {
443 d->textureDataDirty = false;
444 textureData->setTextureData(d->textureData);
445 changed = true;
446 }
447
448 // Can't use qUpdateIfNeeded unfortunately
449 if (d->size != textureData->size()) {
450 textureData->setSize(d->size);
451 changed = true;
452 }
453
454 if (d->depth != textureData->depth()) {
455 textureData->setDepth(d->depth);
456 changed = true;
457 }
458
459 QSSGRenderTextureFormat format = convertToBackendFormat(format: d->format);
460 if (format != textureData->format()) {
461 textureData->setFormat(format);
462 changed = true;
463 }
464
465 if (d->hasTransparency != textureData->hasTransparancy()) {
466 textureData->setHasTransparency(d->hasTransparency);
467 changed = true;
468 }
469
470 if (changed)
471 emit textureDataNodeDirty();
472
473 DebugViewHelpers::ensureDebugObjectName(node: textureData, src: this);
474
475 return node;
476}
477
478void QQuick3DTextureData::markAllDirty()
479{
480 QQuick3DObject::markAllDirty();
481}
482
483
484QT_END_NAMESPACE
485

source code of qtquick3d/src/quick3d/qquick3dtexturedata.cpp