1// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qpaintedtextureimage.h"
5#include "qpaintedtextureimage_p.h"
6
7#include <QtGui/qpainter.h>
8#include <QtGui/qimage.h>
9
10QT_BEGIN_NAMESPACE
11
12namespace Qt3DRender {
13
14/*!
15 \class Qt3DRender::QPaintedTextureImage
16 \inmodule Qt3DRender
17 \since 5.8
18 \brief A QAbstractTextureImage that can be written through a QPainter.
19
20 A QPaintedTextureImage provides a way to specify a texture image
21 (and thus an OpenGL texture) through a QPainter. The width and height of the
22 texture image can be specified through the width and height or size
23 properties.
24
25 A QPaintedTextureImage must be subclassed and the virtual paint() function
26 implemented. Each time update() is called on the QPaintedTextureImage,
27 the paint() function is invoked and the resulting image is uploaded.
28
29 The QPaintedTextureImage must be attached to some QAbstractTexture.
30 */
31
32
33
34QPaintedTextureImagePrivate::QPaintedTextureImagePrivate()
35 : m_imageSize(256,256)
36 , m_devicePixelRatio(1.0)
37 , m_generation(0)
38{
39}
40
41QPaintedTextureImagePrivate::~QPaintedTextureImagePrivate()
42{
43}
44
45void QPaintedTextureImagePrivate::repaint()
46{
47 // create or re-allocate QImage with current size
48 if (m_image.isNull()
49 || m_image->size() != m_imageSize
50 || m_image->devicePixelRatio() != m_devicePixelRatio)
51 {
52 m_image.reset(other: new QImage(m_imageSize, QImage::Format_RGBA8888));
53 m_image->setDevicePixelRatio(m_devicePixelRatio);
54 m_image->fill(color: Qt::transparent);
55 }
56
57 QPainter painter(m_image.data());
58 q_func()->paint(painter: &painter);
59 painter.end();
60
61 ++m_generation;
62 m_currentGenerator = QSharedPointer<QPaintedTextureImageDataGenerator>::create(arguments&: *m_image.data(), arguments&: m_generation, arguments: q_func()->id());
63 q_func()->notifyDataGeneratorChanged();
64}
65
66QPaintedTextureImage::QPaintedTextureImage(Qt3DCore::QNode *parent)
67 : QAbstractTextureImage(*new QPaintedTextureImagePrivate, parent)
68{
69}
70
71QPaintedTextureImage::~QPaintedTextureImage()
72{
73}
74
75/*!
76 \property QPaintedTextureImage::width
77
78 This property holds the width of the texture image.
79 The width must be greater than or equal to 1.
80*/
81int QPaintedTextureImage::width() const
82{
83 Q_D(const QPaintedTextureImage);
84 return d->m_imageSize.width();
85}
86
87/*!
88 \property QPaintedTextureImage::height
89
90 This property holds the height of the texture image.
91 The height must be greater than or equal to 1.
92*/
93int QPaintedTextureImage::height() const
94{
95 Q_D(const QPaintedTextureImage);
96 return d->m_imageSize.height();
97}
98
99/*!
100 \property QPaintedTextureImage::size
101
102 This property holds the size of the texture image.
103
104 \sa height, width
105
106*/
107QSize QPaintedTextureImage::size() const
108{
109 Q_D(const QPaintedTextureImage);
110 return d->m_imageSize;
111}
112
113/*!
114 Sets the width (\a w) of the texture image. Triggers an update, if the size changes.
115 */
116void QPaintedTextureImage::setWidth(int w)
117{
118 if (w < 1) {
119 qWarning() << "QPaintedTextureImage: Attempting to set invalid width" << w << ". Will be ignored";
120 return;
121 }
122 setSize(QSize(w, height()));
123}
124
125/*!
126 Sets the height (\a h) of the texture image. Triggers an update, if the size changes.
127 */
128void QPaintedTextureImage::setHeight(int h)
129{
130 if (h < 1) {
131 qWarning() << "QPaintedTextureImage: Attempting to set invalid height" << h << ". Will be ignored";
132 return;
133 }
134 setSize(QSize(width(), h));
135}
136
137/*!
138 Sets the width and height of the texture image. Triggers an update, if the \a size changes.
139 */
140void QPaintedTextureImage::setSize(QSize size)
141{
142 Q_D(QPaintedTextureImage);
143
144 if (d->m_imageSize != size) {
145 if (size.isEmpty()) {
146 qWarning() << "QPaintedTextureImage: Attempting to set invalid size" << size << ". Will be ignored";
147 return;
148 }
149
150 const bool changeW = d->m_imageSize.width() != size.width();
151 const bool changeH = d->m_imageSize.height() != size.height();
152
153 d->m_imageSize = size;
154
155 if (changeW)
156 Q_EMIT widthChanged(w: d->m_imageSize.height());
157 if (changeH)
158 Q_EMIT heightChanged(w: d->m_imageSize.height());
159
160 Q_EMIT sizeChanged(size: d->m_imageSize);
161
162 d->repaint();
163 }
164}
165
166/*!
167 Immediately triggers the painted texture's paint() function,
168 which in turn uploads the new image to the GPU. If you are
169 making multiple changes to a painted texture, consider waiting
170 until all changes are complete before calling update, in order
171 to minimize the number of repaints required.
172
173 Parameter \a rect is currently unused.
174*/
175void QPaintedTextureImage::update(const QRect &rect)
176{
177 Q_UNUSED(rect);
178 Q_D(QPaintedTextureImage);
179
180 d->repaint();
181}
182
183/*!
184 \fn Qt3DRender::QPaintedTextureImage::paint(QPainter *painter)
185
186 Paints the texture image with the specified QPainter object \a painter.
187
188 QPainter considers the top-left corner of an image as its origin, while OpenGL considers
189 the bottom-left corner of a texture as its origin. An easy way to account for this difference
190 is to set a custom viewport on the painter before doing any other painting:
191
192 \code
193 painter->setViewport(0, height(), width(), -height());
194 ...
195 \endcode
196*/
197QTextureImageDataGeneratorPtr QPaintedTextureImage::dataGenerator() const
198{
199 Q_D(const QPaintedTextureImage);
200 return d->m_currentGenerator;
201}
202
203
204QPaintedTextureImageDataGenerator::QPaintedTextureImageDataGenerator(const QImage &image, int gen, Qt3DCore::QNodeId texId)
205 : m_image(image) // pixels are implicitly shared, no copying
206 , m_generation(gen)
207 , m_paintedTextureImageId(texId)
208{
209}
210
211QPaintedTextureImageDataGenerator::~QPaintedTextureImageDataGenerator()
212{
213}
214
215QTextureImageDataPtr QPaintedTextureImageDataGenerator::operator ()()
216{
217 QTextureImageDataPtr textureData = QTextureImageDataPtr::create();
218 textureData->setImage(m_image);
219 return textureData;
220}
221
222bool QPaintedTextureImageDataGenerator::operator ==(const QTextureImageDataGenerator &other) const
223{
224 const QPaintedTextureImageDataGenerator *otherFunctor = functor_cast<QPaintedTextureImageDataGenerator>(other: &other);
225 return (otherFunctor != nullptr && otherFunctor->m_generation == m_generation && otherFunctor->m_paintedTextureImageId == m_paintedTextureImageId);
226}
227
228} // namespace Qt3DRender
229
230QT_END_NAMESPACE
231
232#include "moc_qpaintedtextureimage.cpp"
233
234

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