Provide a way to cheaply flip your painted FBO
[profile/ivi/qtdeclarative.git] / src / declarative / items / qquickpainteditem.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickpainteditem.h"
43 #include <private/qquickpainteditem_p.h>
44
45 #include <private/qsgpainternode_p.h>
46 #include <private/qsgcontext_p.h>
47 #include <private/qsgadaptationlayer_p.h>
48
49 #include <qmath.h>
50
51 QT_BEGIN_NAMESPACE
52
53 /*!
54     \class QQuickPaintedItem
55     \brief The QQuickPaintedItem class provides a way to use the QPainter API in the
56     QML Scene Graph.
57
58     \inmodule QtDeclarative
59
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.
67
68     To enable QPainter to do anti-aliased rendering, use setAntialiasing().
69
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.
72
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().
77 */
78
79 /*!
80     \enum QQuickPaintedItem::RenderTarget
81
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.
84
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.
89
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.
94
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
99     painter transform.
100
101     \sa setRenderTarget()
102 */
103
104 /*!
105     \enum QQuickPaintedItem::PerformanceHint
106
107     This enum describes flags that you can enable to improve rendering
108     performance in QQuickPaintedItem. By default, none of these flags are set.
109
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.
115 */
116
117 /*!
118     \internal
119 */
120 QQuickPaintedItemPrivate::QQuickPaintedItemPrivate()
121     : QQuickItemPrivate()
122     , contentsScale(1.0)
123     , fillColor(Qt::transparent)
124     , renderTarget(QQuickPaintedItem::Image)
125     , performanceHints(0)
126     , geometryDirty(false)
127     , contentsDirty(false)
128     , opaquePainting(false)
129     , antialiasing(false)
130     , mipmap(false)
131 {
132 }
133
134 /*!
135     Constructs a QQuickPaintedItem with the given \a parent item.
136  */
137 QQuickPaintedItem::QQuickPaintedItem(QQuickItem *parent)
138     : QQuickItem(*(new QQuickPaintedItemPrivate), parent)
139 {
140     setFlag(ItemHasContents);
141 }
142
143 /*!
144     \internal
145 */
146 QQuickPaintedItem::QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent)
147     : QQuickItem(dd, parent)
148 {
149     setFlag(ItemHasContents);
150 }
151
152 /*!
153     Destroys the QQuickPaintedItem.
154 */
155 QQuickPaintedItem::~QQuickPaintedItem()
156 {
157 }
158
159 /*!
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.
162
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.
166
167     Note that calling this function will trigger a repaint of the whole scene.
168
169     \sa paint()
170 */
171 void QQuickPaintedItem::update(const QRect &rect)
172 {
173     Q_D(QQuickPaintedItem);
174     d->contentsDirty = true;
175
176     if (rect.isNull() && !d->dirtyRect.isNull())
177         d->dirtyRect = contentsBoundingRect().toAlignedRect();
178     else
179         d->dirtyRect |= (contentsBoundingRect() & rect).toAlignedRect();
180     QQuickItem::update();
181 }
182
183 /*!
184     Returns true if this item is opaque; otherwise, false is returned.
185
186     By default, painted items are not opaque.
187
188     \sa setOpaquePainting()
189 */
190 bool QQuickPaintedItem::opaquePainting() const
191 {
192     Q_D(const QQuickPaintedItem);
193     return d->opaquePainting;
194 }
195
196 /*!
197     If \a opaque is true, the item is opaque; otherwise, it is considered as translucent.
198
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.
201
202     By default, painted items are not opaque.
203
204     \sa opaquePainting()
205 */
206 void QQuickPaintedItem::setOpaquePainting(bool opaque)
207 {
208     Q_D(QQuickPaintedItem);
209
210     if (d->opaquePainting == opaque)
211         return;
212
213     d->opaquePainting = opaque;
214     QQuickItem::update();
215 }
216
217 /*!
218     Returns true if antialiased painting is enabled; otherwise, false is returned.
219
220     By default, antialiasing is not enabled.
221
222     \sa setAntialiasing()
223 */
224 bool QQuickPaintedItem::antialiasing() const
225 {
226     Q_D(const QQuickPaintedItem);
227     return d->antialiasing;
228 }
229
230 /*!
231     If \a enable is true, antialiased painting is enabled.
232
233     By default, antialiasing is not enabled.
234
235     \sa antialiasing()
236 */
237 void QQuickPaintedItem::setAntialiasing(bool enable)
238 {
239     Q_D(QQuickPaintedItem);
240
241     if (d->antialiasing == enable)
242         return;
243
244     d->antialiasing = enable;
245     update();
246 }
247
248 /*!
249     Returns true if mipmaps are enabled; otherwise, false is returned.
250
251     By default, mipmapping is not enabled.
252
253     \sa setMipmap()
254 */
255 bool QQuickPaintedItem::mipmap() const
256 {
257     Q_D(const QQuickPaintedItem);
258     return d->mipmap;
259 }
260
261 /*!
262     If \a enable is true, mipmapping is enabled on the associated texture.
263
264     Mipmapping increases rendering speed and reduces aliasing artifacts when the item is
265     scaled down.
266
267     By default, mipmapping is not enabled.
268
269     \sa mipmap()
270 */
271 void QQuickPaintedItem::setMipmap(bool enable)
272 {
273     Q_D(QQuickPaintedItem);
274
275     if (d->mipmap == enable)
276         return;
277
278     d->mipmap = enable;
279     update();
280 }
281
282 /*!
283     Returns the performance hints.
284
285     By default, no performance hint is enabled/
286
287     \sa setPerformanceHint(), setPerformanceHints()
288 */
289 QQuickPaintedItem::PerformanceHints QQuickPaintedItem::performanceHints() const
290 {
291     Q_D(const QQuickPaintedItem);
292     return d->performanceHints;
293 }
294
295 /*!
296     Sets the given performance \a hint on the item if \a enabled is true;
297     otherwise clears the performance hint.
298
299     By default, no performance hint is enabled/
300
301     \sa setPerformanceHints(), performanceHints()
302 */
303 void QQuickPaintedItem::setPerformanceHint(QQuickPaintedItem::PerformanceHint hint, bool enabled)
304 {
305     Q_D(QQuickPaintedItem);
306     PerformanceHints oldHints = d->performanceHints;
307     if (enabled)
308         d->performanceHints |= hint;
309     else
310         d->performanceHints &= ~hint;
311     if (oldHints != d->performanceHints)
312        update();
313 }
314
315 /*!
316     Sets the performance hints to \a hints
317
318     By default, no performance hint is enabled/
319
320     \sa setPerformanceHint(), performanceHints()
321 */
322 void QQuickPaintedItem::setPerformanceHints(QQuickPaintedItem::PerformanceHints hints)
323 {
324     Q_D(QQuickPaintedItem);
325     if (d->performanceHints == hints)
326         return;
327     d->performanceHints = hints;
328     update();
329 }
330
331 /*!
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.
334
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.
337
338     Use this function to know the area painted by the item.
339
340     \sa QQuickItem::width(), QQuickItem::height(), contentsSize(), contentsScale()
341 */
342 QRectF QQuickPaintedItem::contentsBoundingRect() const
343 {
344     Q_D(const QQuickPaintedItem);
345
346     qreal w = d->width;
347     QSizeF sz = d->contentsSize * d->contentsScale;
348     if (w < sz.width())
349         w = sz.width();
350     qreal h = d->height;
351     if (h < sz.height())
352         h = sz.height();
353
354     return QRectF(0, 0, w, h);
355 }
356
357 /*!
358     \property QQuickPaintedItem::contentsSize
359     \brief The size of the contents
360
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().
364 */
365 QSize QQuickPaintedItem::contentsSize() const
366 {
367     Q_D(const QQuickPaintedItem);
368     return d->contentsSize;
369 }
370
371 void QQuickPaintedItem::setContentsSize(const QSize &size)
372 {
373     Q_D(QQuickPaintedItem);
374
375     if (d->contentsSize == size)
376         return;
377
378     d->contentsSize = size;
379     update();
380 }
381
382 /*!
383     This convenience function is equivalent to calling setContentsSize(QSize()).
384 */
385 void QQuickPaintedItem::resetContentsSize()
386 {
387     setContentsSize(QSize());
388 }
389
390 /*!
391     \property QQuickPaintedItem::contentsScale
392     \brief The scale of the contents
393
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().
396
397     The default value is 1.
398 */
399 qreal QQuickPaintedItem::contentsScale() const
400 {
401     Q_D(const QQuickPaintedItem);
402     return d->contentsScale;
403 }
404
405 void QQuickPaintedItem::setContentsScale(qreal scale)
406 {
407     Q_D(QQuickPaintedItem);
408
409     if (d->contentsScale == scale)
410         return;
411
412     d->contentsScale = scale;
413     update();
414 }
415
416 /*!
417     \property QQuickPaintedItem::fillColor
418     \brief The item's background fill color.
419
420     By default, the fill color is set to Qt::transparent.
421 */
422 QColor QQuickPaintedItem::fillColor() const
423 {
424     Q_D(const QQuickPaintedItem);
425     return d->fillColor;
426 }
427
428 void QQuickPaintedItem::setFillColor(const QColor &c)
429 {
430     Q_D(QQuickPaintedItem);
431
432     if (d->fillColor == c)
433         return;
434
435     d->fillColor = c;
436     update();
437
438     emit fillColorChanged();
439 }
440
441 /*!
442     \property QQuickPaintedItem::renderTarget
443     \brief The item's render target.
444
445     This property defines which render target the QPainter renders into, it can be either
446     QSGPaintedItem::Image, QSGPaintedItem::FramebufferObject or QSGPaintedItem::InvertedYFramebufferObject.
447
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.
451
452     \warning Resizing a framebuffer object is a costly operation, avoid using
453     the QQuickPaintedItem::FramebufferObject render target if the item gets resized often.
454
455     By default, the render target is QQuickPaintedItem::Image.
456 */
457 QQuickPaintedItem::RenderTarget QQuickPaintedItem::renderTarget() const
458 {
459     Q_D(const QQuickPaintedItem);
460     return d->renderTarget;
461 }
462
463 void QQuickPaintedItem::setRenderTarget(RenderTarget target)
464 {
465     Q_D(QQuickPaintedItem);
466
467     if (d->renderTarget == target)
468         return;
469
470     d->renderTarget = target;
471     update();
472
473     emit renderTargetChanged();
474 }
475
476 /*!
477     \fn virtual void QQuickPaintedItem::paint(QPainter *painter) = 0
478
479     This function, which is usually called by the QML Scene Graph, paints the
480     contents of an item in local coordinates.
481
482     The function is called after the item has been filled with the fillColor.
483
484     Reimplement this function in a QQuickPaintedItem subclass to provide the
485     item's painting implementation, using \a painter.
486
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.
492 */
493
494 /*!
495     This function is called after the item's geometry has changed.
496 */
497 void QQuickPaintedItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
498 {
499     Q_D(QQuickPaintedItem);
500     d->geometryDirty = true;
501     QQuickItem::geometryChanged(newGeometry, oldGeometry);
502 }
503
504
505 /*!
506     This function is called when the Scene Graph node associated to the item needs to
507     be updated.
508 */
509 QSGNode *QQuickPaintedItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
510 {
511     Q_UNUSED(data);
512     Q_D(QQuickPaintedItem);
513
514     if (width() <= 0 || height() <= 0) {
515         delete oldNode;
516         return 0;
517     }
518
519     QSGPainterNode *node = static_cast<QSGPainterNode *>(oldNode);
520     if (!node)
521         node = new QSGPainterNode(this);
522
523     QRectF br = contentsBoundingRect();
524
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);
535     node->update();
536
537     d->contentsDirty = false;
538     d->geometryDirty = false;
539     d->dirtyRect = QRect();
540
541     return node;
542 }
543
544 QT_END_NAMESPACE