src/hbcore/ovgeffects/hbvgreflectioneffect.cpp
changeset 0 16d8024aca5e
child 5 627c4a0fd0e7
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbCore module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 
       
    26 #include "hbvgreflectioneffect_p.h"
       
    27 #include "hbvgreflectioneffect_p_p.h"
       
    28 #include "hbvgcolorizeeffect_p_p.h" // for getColorMatrix
       
    29 #include "hbvgblureffect_p_p.h" // for identityLUT
       
    30 #include <QPainter>
       
    31 #include <QGraphicsItem>
       
    32 #include <QDebug>
       
    33 
       
    34 /*!
       
    35  * \class HbVgReflectionEffect
       
    36  *
       
    37  * \brief OpenVG-based reflection effect.
       
    38  * 
       
    39  * \internal
       
    40  */
       
    41 
       
    42 HbVgReflectionEffectPrivate::HbVgReflectionEffectPrivate()
       
    43     : fade(0), fadeInited(false)
       
    44 {    
       
    45 }
       
    46 
       
    47 HbVgReflectionEffectPrivate::~HbVgReflectionEffectPrivate()
       
    48 {
       
    49 #ifdef HB_EFFECTS_OPENVG
       
    50     if (fadeInited) {
       
    51         vgDestroyPaint(fadePaint);
       
    52     }
       
    53 #endif
       
    54 }
       
    55 
       
    56 HbVgReflectionEffect::HbVgReflectionEffect(QObject *parent)
       
    57     : HbVgFrameEffect(*new HbVgReflectionEffectPrivate, parent)
       
    58 {
       
    59 }
       
    60 
       
    61 HbVgReflectionEffect::HbVgReflectionEffect(HbVgReflectionEffectPrivate &dd, QObject *parent)
       
    62     : HbVgFrameEffect(dd, parent)
       
    63 {
       
    64 }
       
    65 
       
    66 HbVgReflectionEffect::~HbVgReflectionEffect()
       
    67 {
       
    68 }
       
    69 
       
    70 QPointF HbVgReflectionEffect::offset() const
       
    71 {
       
    72     Q_D(const HbVgReflectionEffect);
       
    73     return d->offset;
       
    74 }
       
    75 
       
    76 void HbVgReflectionEffect::setOffset(const QPointF &offset)
       
    77 {
       
    78     Q_D(HbVgReflectionEffect);
       
    79     if (offset == d->offset)
       
    80         return;
       
    81     d->offset = offset;
       
    82     updateEffectBoundingRect();
       
    83     emit offsetChanged(offset);
       
    84 }
       
    85 
       
    86 qreal HbVgReflectionEffect::fade() const
       
    87 {
       
    88     Q_D(const HbVgReflectionEffect);
       
    89     return d->fade;
       
    90 }
       
    91 
       
    92 /*!
       
    93  * The fade parameter tells where the opacity in the gradual fade-out effect reaches zero,
       
    94  * i.e. total transparency, when moving upwards from the bottom of the reflection. The
       
    95  * default 0 is a special value, it disables the fade-out effect on the reflection
       
    96  * completely. Examples: 0.5 causes the lower half of the reflection to be completely
       
    97  * invisible (and the upper half linearly faded), 0.9 causes almost the entire reflection
       
    98  * to be invisible, 1 shows nothing from the reflection (it is completely faded out).
       
    99  */
       
   100 void HbVgReflectionEffect::setFade(qreal fade)
       
   101 {
       
   102     Q_D(HbVgReflectionEffect);
       
   103     if (fade == d->fade)
       
   104         return;
       
   105     d->fade = fade;
       
   106     updateEffect();
       
   107     emit fadeChanged(fade);
       
   108 }
       
   109 
       
   110 QColor HbVgReflectionEffect::color() const
       
   111 {
       
   112     Q_D(const HbVgReflectionEffect);
       
   113     return d->color;
       
   114 }
       
   115 
       
   116 void HbVgReflectionEffect::setColor(const QColor &color)
       
   117 {
       
   118     Q_D(HbVgReflectionEffect);
       
   119     if (color == d->color)
       
   120         return;
       
   121     d->color = color;
       
   122     updateEffect();
       
   123     emit colorChanged(color);
       
   124 }
       
   125 
       
   126 QRectF HbVgReflectionEffect::boundingRectFor(const QRectF &rect) const
       
   127 {
       
   128     // Double the height of the rectangle but take also the offset into account.
       
   129     Q_D(const HbVgReflectionEffect);
       
   130     QRectF r(rect);
       
   131     QPointF mappedOffset = d->mapOffset(d->offset);
       
   132     qreal rotationAngle = d->mainWindowRotation();  
       
   133     
       
   134     if (rotationAngle == 0) 
       
   135         r.adjust(0, 0, 0, r.height());
       
   136     else if (rotationAngle == 90 || rotationAngle == -270)
       
   137         r.adjust(-r.width(), 0, 0, 0);
       
   138     else if (rotationAngle == -90 || rotationAngle == 270)
       
   139         r.adjust(0, 0, r.width(), 0);
       
   140       
       
   141     qreal x1 = qMin(r.left(), r.left() + mappedOffset.x());
       
   142     qreal y1 = qMin(r.top(), r.top() + mappedOffset.y());
       
   143     qreal x2 = qMax(r.right(), r.right() + mappedOffset.x());
       
   144     qreal y2 = qMax(r.bottom(), r.bottom() + mappedOffset.y());
       
   145         
       
   146     return QRectF(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
       
   147 }
       
   148 
       
   149 void HbVgReflectionEffect::performEffect(QPainter *painter,
       
   150                                          const QPointF &offset,
       
   151                                          const QVariant &vgImage,
       
   152                                          const QSize &vgImageSize)
       
   153 {
       
   154 #ifdef HB_EFFECTS_OPENVG
       
   155     Q_D(HbVgReflectionEffect);
       
   156 
       
   157     if (d->hints & ForceFrameHint) {
       
   158         painter->save();
       
   159         HbVgFrameEffect::performEffect(painter, offset, vgImage, vgImageSize);
       
   160         painter->restore();
       
   161     }
       
   162 
       
   163     QPaintDevice *pdev = painter->device();
       
   164     QRectF rectWithChildren = d->deviceRectForSource(
       
   165         HbVgFrameEffectPrivate::IncludeChildren,
       
   166         pdev);
       
   167     QRectF rectWithoutChildren = d->deviceRectForSource(
       
   168         HbVgFrameEffectPrivate::ExcludeChildren,
       
   169         pdev);
       
   170     VGImage srcImage = vgImage.value<VGImage>();
       
   171     VGImage dstImage = d->ensurePixmap(&d->dstPixmap, vgImageSize);
       
   172 
       
   173     // Draw the source pixmap using the painter, this will also set up the
       
   174     // IMAGE_USER_TO_SURFACE matrix.
       
   175     painter->drawPixmap(offset, d->srcPixmap);
       
   176 
       
   177     // Prepare the mirrored image.    
       
   178     qreal rotationAngle = d->mainWindowRotation();
       
   179     qreal absRotationAngle = qAbs(rotationAngle);
       
   180     
       
   181     VGfloat m[9];
       
   182     vgGetMatrix(m);
       
   183     vgLoadIdentity();
       
   184     if (absRotationAngle == 0)
       
   185         m[4] *= -1.0f;
       
   186     else if (absRotationAngle == 90 || absRotationAngle == 270)
       
   187         m[0] *= -1.0f;
       
   188     vgMultMatrix(m);
       
   189     
       
   190     // Must move the mirrored image to have it on top of the original and then down
       
   191     // again to have it below in portrait-mode. Rotation angles -90 or 270 causes image to be moved to right,
       
   192     // and in rotation angles -90 and 270, image is in correct place initially.
       
   193     // Try to take the exclude-children hint into account when performing the second move.
       
   194     
       
   195     VGfloat trans;
       
   196     if (absRotationAngle == 0) {        
       
   197         if (d->hints & ExcludeChildrenHint)
       
   198             trans = -rectWithChildren.height() - rectWithoutChildren.height();
       
   199         else
       
   200             trans = -2.0f * rectWithChildren.height();
       
   201         
       
   202         vgTranslate(0.0f, trans);
       
   203     }  
       
   204     else if (absRotationAngle == 90 || absRotationAngle == 270) {
       
   205         if (d->hints & ExcludeChildrenHint)
       
   206             trans = -rectWithChildren.width() - rectWithoutChildren.width();
       
   207         else
       
   208             trans = -2.0f * rectWithChildren.width();
       
   209         
       
   210         vgTranslate(trans, 0.0f);
       
   211     }
       
   212         
       
   213     // Apply the additional offset. Note: down = minus, right = plus.
       
   214     QPointF mappedOffset = d->mapOffset(d->offset);    
       
   215     VGfloat ox = (VGfloat) mappedOffset.x();
       
   216     VGfloat oy = (VGfloat) mappedOffset.y();
       
   217 
       
   218     if (rotationAngle == 0)   
       
   219         vgTranslate(ox, -oy); 
       
   220     else if (rotationAngle == 90 || rotationAngle == -270)
       
   221         vgTranslate(-ox, oy);   
       
   222     else if (rotationAngle == -90 || rotationAngle == 270)
       
   223         vgTranslate(-ox, oy); 
       
   224     
       
   225     // Apply the opacity and the color. When no color was set and the opacity is 1, the
       
   226     // source image will be used as it is. This is the only place where we can try to use
       
   227     // the pixmap cache.
       
   228     VGImage imgToDraw = srcImage;
       
   229     QPixmap cachedPm = cached(vgImageSize);
       
   230    if (cachedPm.isNull()) {
       
   231         VGImage tmpImage = VG_INVALID_HANDLE;
       
   232         if (d->color.isValid()) {
       
   233             // Perform a colorize effect (ignore the opacity here because it must be set for
       
   234             // the full image, not just the color overlay).
       
   235             tmpImage = d->ensurePixmap(&d->tmpPixmap, vgImageSize);
       
   236             VGfloat colorMatrix[20];
       
   237             HbVgColorizeEffectPrivate::getColorMatrix(colorMatrix, d->color, 1.0f);
       
   238             vgColorMatrix(tmpImage, srcImage, colorMatrix);
       
   239             imgToDraw = tmpImage;
       
   240         }
       
   241         qreal opacity = clamp(d->opacity, 0.0f, 1.0f);
       
   242         if (d->opacity < 1.0f - HBVG_EPSILON) {
       
   243             // Apply the opacity, i.e. modify the alpha channel.
       
   244             if (d->paramsChanged) {
       
   245                 for (int i = 0; i < 256; ++i)
       
   246                     d->alphaLUT[i] = (VGubyte) (i * opacity);
       
   247             }
       
   248             vgLookup(dstImage, imgToDraw,
       
   249                      identityLUT, identityLUT, identityLUT, d->alphaLUT,
       
   250                      VG_TRUE, VG_FALSE);
       
   251             imgToDraw = dstImage;
       
   252         }
       
   253         // If colorize and/or opacity was used then try to cache the result.
       
   254         if (imgToDraw == tmpImage)
       
   255             tryCache(d->tmpPixmap);
       
   256         else if (imgToDraw == dstImage)
       
   257             tryCache(d->dstPixmap);
       
   258     } else {
       
   259         imgToDraw = qPixmapToVGImage(cachedPm);
       
   260     }
       
   261 
       
   262     // Fade out the lower part of the mirrored image. Skip this if 'fade' is 0, i.e. there
       
   263     // is no fade-out effect.
       
   264     VGfloat fade = (VGfloat) clamp(d->fade, 0.0f, 1.0f);
       
   265     if (fade > HBVG_EPSILON) {
       
   266         // Prepare the linear gradient used for fading if not yet done.
       
   267         if (!d->fadeInited) {
       
   268             d->fadePaint = vgCreatePaint();
       
   269             vgSetParameteri(d->fadePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
       
   270             vgSetParameteri(d->fadePaint,
       
   271                             VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_REFLECT);
       
   272             d->fadeInited = true;
       
   273         }
       
   274 
       
   275         if (d->paramsChanged) {
       
   276             // Prepare the color ramp, take the value of 'fade' into account. (It tells
       
   277             // where the opacity reaches zero, i.e. total transparency.) The RGB values
       
   278             // are set to 1 because the mirrored image's RGB values must not be changed,
       
   279             // only the alpha channel needs a little manipulation (to get the gradual
       
   280             // fade-out effect).
       
   281             VGfloat stops[] = {
       
   282                 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
       
   283                 1.0f - fade, 1.0f, 1.0f, 1.0f, 0.0f,
       
   284                 1.0f, 1.0f, 1.0f, 1.0f, 0.0f
       
   285             };
       
   286             vgSetParameterfv(d->fadePaint, VG_PAINT_COLOR_RAMP_STOPS, 15, stops);
       
   287         }
       
   288 
       
   289         // Set up the linear gradient based on the (transformed) size of the source.
       
   290         VGfloat sw = (VGfloat) rectWithChildren.width();
       
   291         VGfloat sh = (VGfloat) rectWithChildren.height();
       
   292          // must be bottom-up to get the proper effect
       
   293         if (rotationAngle == 0)  {
       
   294             VGfloat grad[] = { sw / 2.0f, sh,
       
   295                                sw / 2.0f, 0.0f };            
       
   296             vgSetParameterfv(d->fadePaint, VG_PAINT_LINEAR_GRADIENT, 4, grad);
       
   297         }
       
   298         else if (rotationAngle == -90 || rotationAngle == 270){
       
   299             VGfloat grad[] = { sw, sh / 2.0f,
       
   300                                0.0f, sh / 2.0f };
       
   301             vgSetParameterfv(d->fadePaint, VG_PAINT_LINEAR_GRADIENT, 4, grad);
       
   302         }
       
   303         else if (rotationAngle == 90 || rotationAngle == -270){
       
   304             VGfloat grad[] = { 0.0f, sh / 2.0f,
       
   305                                sw, sh / 2.0f };
       
   306             vgSetParameterfv(d->fadePaint, VG_PAINT_LINEAR_GRADIENT, 4, grad);
       
   307         }        
       
   308 
       
   309         // Draw the mirrored image by using the paint to get a gradual fade-out effect.
       
   310         vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
       
   311         vgLoadIdentity();
       
   312         vgSetPaint(d->fadePaint, VG_FILL_PATH);
       
   313         vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY);
       
   314         vgDrawImage(imgToDraw);
       
   315         vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
       
   316         vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
       
   317         vgSetPaint(VG_INVALID_HANDLE, VG_FILL_PATH);
       
   318     } else {
       
   319         // Just draw the mirrored image normally.
       
   320         vgDrawImage(imgToDraw);
       
   321     }
       
   322 
       
   323 #else
       
   324     Q_UNUSED(painter);
       
   325     Q_UNUSED(offset);
       
   326     Q_UNUSED(vgImage);
       
   327     Q_UNUSED(vgImageSize);
       
   328 #endif
       
   329 }