1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickpainteditem.h"
43 #include <private/qquickpainteditem_p.h>
45 #include <private/qsgpainternode_p.h>
46 #include <private/qsgcontext_p.h>
47 #include <private/qsgadaptationlayer_p.h>
54 \class QQuickPaintedItem
55 \brief The QQuickPaintedItem class provides a way to use the QPainter API in the
58 \inmodule QtDeclarative
60 The QQuickPaintedItem makes it possible to use the QPainter API with the QML Scene Graph.
61 It sets up a textured rectangle in the Scene Graph and uses a QPainter to paint
62 onto the texture. The render target can be either a QImage or a QOpenGLFramebufferObject.
63 When the render target is a QImage, QPainter first renders into the image then
64 the content is uploaded to the texture.
65 When a QOpenGLFramebufferObject is used, QPainter paints directly onto the texture.
66 Call update() to trigger a repaint.
68 To enable QPainter to do anti-aliased rendering, use setAntialiasing().
70 QQuickPaintedItem is meant to make it easier to port old code that is using the
71 QPainter API to the QML Scene Graph API and it should be used only for that purpose.
73 To write your own painted item, you first create a subclass of QQuickPaintedItem, and then
74 start by implementing its only pure virtual public function: paint(), which implements
75 the actual painting. To get the size of the area painted by the item, use
76 contentsBoundingRect().
80 \enum QQuickPaintedItem::RenderTarget
82 This enum describes QQuickPaintedItem's render targets. The render target is the
83 surface QPainter paints onto before the item is rendered on screen.
85 \value Image The default; QPainter paints into a QImage using the raster paint engine.
86 The image's content needs to be uploaded to graphics memory afterward, this operation
87 can potentially be slow if the item is large. This render target allows high quality
88 anti-aliasing and fast item resizing.
90 \value FramebufferObject QPainter paints into a QOpenGLFramebufferObject using the GL
91 paint engine. Painting can be faster as no texture upload is required, but anti-aliasing
92 quality is not as good as if using an image. This render target allows faster rendering
93 in some cases, but you should avoid using it if the item is resized often.
95 \value InvertedYFramebufferObject Exactly as for FramebufferObject above, except once
96 the painting is done, prior to rendering the painted image is flipped about the
97 x-axis so that the top-most pixels are now at the bottom. Since this is done with the
98 OpenGL texture coordinates it is a much faster way to achieve this effect than using a
101 \sa setRenderTarget()
105 \enum QQuickPaintedItem::PerformanceHint
107 This enum describes flags that you can enable to improve rendering
108 performance in QQuickPaintedItem. By default, none of these flags are set.
110 \value FastFBOResizing If your item gets resized often and you are using the
111 QQuickPaintedItem::FramebufferObject render target, set this flag to true to reduce the
112 item resizing time at the cost of using more graphics memory. Resizing a Framebuffer object
113 is a costly operation, by enabling this property the Framebuffer Object will use a texture
114 larger than the actual size of the item to avoid as much as possible resizing it.
120 QQuickPaintedItemPrivate::QQuickPaintedItemPrivate()
121 : QQuickItemPrivate()
123 , fillColor(Qt::transparent)
124 , renderTarget(QQuickPaintedItem::Image)
125 , performanceHints(0)
126 , geometryDirty(false)
127 , contentsDirty(false)
128 , opaquePainting(false)
129 , antialiasing(false)
135 Constructs a QQuickPaintedItem with the given \a parent item.
137 QQuickPaintedItem::QQuickPaintedItem(QQuickItem *parent)
138 : QQuickItem(*(new QQuickPaintedItemPrivate), parent)
140 setFlag(ItemHasContents);
146 QQuickPaintedItem::QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent)
147 : QQuickItem(dd, parent)
149 setFlag(ItemHasContents);
153 Destroys the QQuickPaintedItem.
155 QQuickPaintedItem::~QQuickPaintedItem()
160 Schedules a redraw of the area covered by \a rect in this item. You can call this function
161 whenever your item needs to be redrawn, such as if it changes appearance or size.
163 This function does not cause an immediate paint; instead it schedules a paint request that
164 is processed by the QML Scene Graph when the next frame is rendered. The item will only be
165 redrawn if it is visible.
167 Note that calling this function will trigger a repaint of the whole scene.
171 void QQuickPaintedItem::update(const QRect &rect)
173 Q_D(QQuickPaintedItem);
174 d->contentsDirty = true;
176 if (rect.isNull() && !d->dirtyRect.isNull())
177 d->dirtyRect = contentsBoundingRect().toAlignedRect();
179 d->dirtyRect |= (contentsBoundingRect() & rect).toAlignedRect();
180 QQuickItem::update();
184 Returns true if this item is opaque; otherwise, false is returned.
186 By default, painted items are not opaque.
188 \sa setOpaquePainting()
190 bool QQuickPaintedItem::opaquePainting() const
192 Q_D(const QQuickPaintedItem);
193 return d->opaquePainting;
197 If \a opaque is true, the item is opaque; otherwise, it is considered as translucent.
199 Opaque items are not blended with the rest of the scene, you should set this to true
200 if the content of the item is opaque to speed up rendering.
202 By default, painted items are not opaque.
206 void QQuickPaintedItem::setOpaquePainting(bool opaque)
208 Q_D(QQuickPaintedItem);
210 if (d->opaquePainting == opaque)
213 d->opaquePainting = opaque;
214 QQuickItem::update();
218 Returns true if antialiased painting is enabled; otherwise, false is returned.
220 By default, antialiasing is not enabled.
222 \sa setAntialiasing()
224 bool QQuickPaintedItem::antialiasing() const
226 Q_D(const QQuickPaintedItem);
227 return d->antialiasing;
231 If \a enable is true, antialiased painting is enabled.
233 By default, antialiasing is not enabled.
237 void QQuickPaintedItem::setAntialiasing(bool enable)
239 Q_D(QQuickPaintedItem);
241 if (d->antialiasing == enable)
244 d->antialiasing = enable;
249 Returns true if mipmaps are enabled; otherwise, false is returned.
251 By default, mipmapping is not enabled.
255 bool QQuickPaintedItem::mipmap() const
257 Q_D(const QQuickPaintedItem);
262 If \a enable is true, mipmapping is enabled on the associated texture.
264 Mipmapping increases rendering speed and reduces aliasing artifacts when the item is
267 By default, mipmapping is not enabled.
271 void QQuickPaintedItem::setMipmap(bool enable)
273 Q_D(QQuickPaintedItem);
275 if (d->mipmap == enable)
283 Returns the performance hints.
285 By default, no performance hint is enabled/
287 \sa setPerformanceHint(), setPerformanceHints()
289 QQuickPaintedItem::PerformanceHints QQuickPaintedItem::performanceHints() const
291 Q_D(const QQuickPaintedItem);
292 return d->performanceHints;
296 Sets the given performance \a hint on the item if \a enabled is true;
297 otherwise clears the performance hint.
299 By default, no performance hint is enabled/
301 \sa setPerformanceHints(), performanceHints()
303 void QQuickPaintedItem::setPerformanceHint(QQuickPaintedItem::PerformanceHint hint, bool enabled)
305 Q_D(QQuickPaintedItem);
306 PerformanceHints oldHints = d->performanceHints;
308 d->performanceHints |= hint;
310 d->performanceHints &= ~hint;
311 if (oldHints != d->performanceHints)
316 Sets the performance hints to \a hints
318 By default, no performance hint is enabled/
320 \sa setPerformanceHint(), performanceHints()
322 void QQuickPaintedItem::setPerformanceHints(QQuickPaintedItem::PerformanceHints hints)
324 Q_D(QQuickPaintedItem);
325 if (d->performanceHints == hints)
327 d->performanceHints = hints;
332 This function returns the outer bounds of the item as a rectangle; all painting must be
333 restricted to inside an item's bounding rect.
335 If the contents size has not been set it reflects the size of the item; otherwise
336 it reflects the contents size scaled by the contents scale.
338 Use this function to know the area painted by the item.
340 \sa QQuickItem::width(), QQuickItem::height(), contentsSize(), contentsScale()
342 QRectF QQuickPaintedItem::contentsBoundingRect() const
344 Q_D(const QQuickPaintedItem);
347 QSizeF sz = d->contentsSize * d->contentsScale;
354 return QRectF(0, 0, w, h);
358 \property QQuickPaintedItem::contentsSize
359 \brief The size of the contents
361 The contents size is the size of the item in regards to how it is painted
362 using the paint() function. This is distinct from the size of the
363 item in regards to height() and width().
365 QSize QQuickPaintedItem::contentsSize() const
367 Q_D(const QQuickPaintedItem);
368 return d->contentsSize;
371 void QQuickPaintedItem::setContentsSize(const QSize &size)
373 Q_D(QQuickPaintedItem);
375 if (d->contentsSize == size)
378 d->contentsSize = size;
383 This convenience function is equivalent to calling setContentsSize(QSize()).
385 void QQuickPaintedItem::resetContentsSize()
387 setContentsSize(QSize());
391 \property QQuickPaintedItem::contentsScale
392 \brief The scale of the contents
394 All painting happening in paint() is scaled by the contents scale. This is distinct
395 from the scale of the item in regards to scale().
397 The default value is 1.
399 qreal QQuickPaintedItem::contentsScale() const
401 Q_D(const QQuickPaintedItem);
402 return d->contentsScale;
405 void QQuickPaintedItem::setContentsScale(qreal scale)
407 Q_D(QQuickPaintedItem);
409 if (d->contentsScale == scale)
412 d->contentsScale = scale;
417 \property QQuickPaintedItem::fillColor
418 \brief The item's background fill color.
420 By default, the fill color is set to Qt::transparent.
422 QColor QQuickPaintedItem::fillColor() const
424 Q_D(const QQuickPaintedItem);
428 void QQuickPaintedItem::setFillColor(const QColor &c)
430 Q_D(QQuickPaintedItem);
432 if (d->fillColor == c)
438 emit fillColorChanged();
442 \property QQuickPaintedItem::renderTarget
443 \brief The item's render target.
445 This property defines which render target the QPainter renders into, it can be either
446 QSGPaintedItem::Image, QSGPaintedItem::FramebufferObject or QSGPaintedItem::InvertedYFramebufferObject.
448 Each has certain benefits, typically performance versus quality. Using a framebuffer
449 object avoids a costly upload of the image contents to the texture in graphics memory,
450 while using an image enables high quality anti-aliasing.
452 \warning Resizing a framebuffer object is a costly operation, avoid using
453 the QQuickPaintedItem::FramebufferObject render target if the item gets resized often.
455 By default, the render target is QQuickPaintedItem::Image.
457 QQuickPaintedItem::RenderTarget QQuickPaintedItem::renderTarget() const
459 Q_D(const QQuickPaintedItem);
460 return d->renderTarget;
463 void QQuickPaintedItem::setRenderTarget(RenderTarget target)
465 Q_D(QQuickPaintedItem);
467 if (d->renderTarget == target)
470 d->renderTarget = target;
473 emit renderTargetChanged();
477 \fn virtual void QQuickPaintedItem::paint(QPainter *painter) = 0
479 This function, which is usually called by the QML Scene Graph, paints the
480 contents of an item in local coordinates.
482 The function is called after the item has been filled with the fillColor.
484 Reimplement this function in a QQuickPaintedItem subclass to provide the
485 item's painting implementation, using \a painter.
487 \note The QML Scene Graph uses two separate threads, the main thread does things such as
488 processing events or updating animations while a second thread does the actual OpenGL rendering.
489 As a consequence, paint() is not called from the main GUI thread but from the GL enabled
490 renderer thread. At the moment paint() is called, the GUI thread is blocked and this is
491 therefore thread-safe.
495 This function is called after the item's geometry has changed.
497 void QQuickPaintedItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
499 Q_D(QQuickPaintedItem);
500 d->geometryDirty = true;
501 QQuickItem::geometryChanged(newGeometry, oldGeometry);
506 This function is called when the Scene Graph node associated to the item needs to
509 QSGNode *QQuickPaintedItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
512 Q_D(QQuickPaintedItem);
514 if (width() <= 0 || height() <= 0) {
519 QSGPainterNode *node = static_cast<QSGPainterNode *>(oldNode);
521 node = new QSGPainterNode(this);
523 QRectF br = contentsBoundingRect();
525 node->setPreferredRenderTarget(d->renderTarget);
526 node->setFastFBOResizing(d->performanceHints & FastFBOResizing);
527 node->setSize(QSize(qRound(br.width()), qRound(br.height())));
528 node->setSmoothPainting(d->antialiasing);
529 node->setLinearFiltering(d->smooth);
530 node->setMipmapping(d->mipmap);
531 node->setOpaquePainting(d->opaquePainting);
532 node->setFillColor(d->fillColor);
533 node->setContentsScale(d->contentsScale);
534 node->setDirty(d->contentsDirty || d->geometryDirty, d->dirtyRect);
537 d->contentsDirty = false;
538 d->geometryDirty = false;
539 d->dirtyRect = QRect();