src/opengl/qgraphicsshadereffect.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 QtOpenGL module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qgraphicsshadereffect_p.h"
       
    43 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
       
    44 #include "qglshaderprogram.h"
       
    45 #include "gl2paintengineex/qglcustomshaderstage_p.h"
       
    46 #define QGL_HAVE_CUSTOM_SHADERS 1
       
    47 #endif
       
    48 #include <QtGui/qpainter.h>
       
    49 #include <QtGui/qgraphicsitem.h>
       
    50 #include <QtGui/private/qgraphicseffect_p.h>
       
    51 
       
    52 QT_BEGIN_NAMESPACE
       
    53 
       
    54 /*#
       
    55     \class QGraphicsShaderEffect
       
    56     \brief The QGraphicsShaderEffect class is the base class for creating
       
    57     custom GLSL shader effects in a QGraphicsScene.
       
    58     \since 4.6
       
    59     \ingroup multimedia
       
    60     \ingroup graphicsview-api
       
    61 
       
    62     The specific effect is defined by a fragment of GLSL source code
       
    63     supplied to setPixelShaderFragment().  This source code must define a
       
    64     function with the signature
       
    65     \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)}
       
    66     that returns the source pixel value
       
    67     to use in the paint engine's shader program.  The shader fragment
       
    68     is linked with the regular shader code used by the GL2 paint engine
       
    69     to construct a complete QGLShaderProgram.
       
    70 
       
    71     The following example shader converts the incoming pixmap to
       
    72     grayscale and then applies a colorize operation using the
       
    73     \c effectColor value:
       
    74 
       
    75     \code
       
    76     static char const colorizeShaderCode[] =
       
    77         "uniform lowp vec4 effectColor;\n"
       
    78         "lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) {\n"
       
    79         "    vec4 src = texture2D(imageTexture, textureCoords);\n"
       
    80         "    float gray = dot(src.rgb, vec3(0.212671, 0.715160, 0.072169));\n"
       
    81         "    vec4 colorize = 1.0-((1.0-gray)*(1.0-effectColor));\n"
       
    82         "    return vec4(colorize.rgb, src.a);\n"
       
    83         "}";
       
    84     \endcode
       
    85 
       
    86     To use this shader code, it is necessary to define a subclass
       
    87     of QGraphicsShaderEffect as follows:
       
    88 
       
    89     \code
       
    90     class ColorizeEffect : public QGraphicsShaderEffect
       
    91     {
       
    92         Q_OBJECT
       
    93     public:
       
    94         ColorizeEffect(QObject *parent = 0)
       
    95             : QGraphicsShaderEffect(parent), color(Qt::black)
       
    96         {
       
    97             setPixelShaderFragment(colorizeShaderCode);
       
    98         }
       
    99 
       
   100         QColor effectColor() const { return color; }
       
   101         void setEffectColor(const QColor& c)
       
   102         {
       
   103             color = c;
       
   104             setUniformsDirty();
       
   105         }
       
   106 
       
   107     protected:
       
   108         void setUniforms(QGLShaderProgram *program)
       
   109         {
       
   110             program->setUniformValue("effectColor", color);
       
   111         }
       
   112 
       
   113     private:
       
   114         QColor color;
       
   115     };
       
   116     \endcode
       
   117 
       
   118     The setUniforms() function is called when the effect is about
       
   119     to be used for drawing to give the subclass the opportunity to
       
   120     set effect-specific uniform variables.
       
   121 
       
   122     QGraphicsShaderEffect is only supported when the GL2 paint engine
       
   123     is in use.  When any other paint engine is in use (GL1, raster, etc),
       
   124     the drawItem() method will draw its item argument directly with
       
   125     no effect applied.
       
   126 
       
   127     \sa QGraphicsEffect
       
   128 */
       
   129 
       
   130 static const char qglslDefaultImageFragmentShader[] = "\
       
   131     lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) { \
       
   132         return texture2D(imageTexture, textureCoords); \
       
   133     }\n";
       
   134 
       
   135 #ifdef QGL_HAVE_CUSTOM_SHADERS
       
   136 
       
   137 class QGLCustomShaderEffectStage : public QGLCustomShaderStage
       
   138 {
       
   139 public:
       
   140     QGLCustomShaderEffectStage
       
   141             (QGraphicsShaderEffect *e, const QByteArray& source)
       
   142         : QGLCustomShaderStage(),
       
   143           effect(e)
       
   144     {
       
   145         setSource(source);
       
   146     }
       
   147 
       
   148     void setUniforms(QGLShaderProgram *program);
       
   149 
       
   150     QGraphicsShaderEffect *effect;
       
   151 };
       
   152 
       
   153 void QGLCustomShaderEffectStage::setUniforms(QGLShaderProgram *program)
       
   154 {
       
   155     effect->setUniforms(program);
       
   156 }
       
   157 
       
   158 #endif
       
   159 
       
   160 class QGraphicsShaderEffectPrivate : public QGraphicsEffectPrivate
       
   161 {
       
   162     Q_DECLARE_PUBLIC(QGraphicsShaderEffect)
       
   163 public:
       
   164     QGraphicsShaderEffectPrivate()
       
   165         : pixelShaderFragment(qglslDefaultImageFragmentShader)
       
   166 #ifdef QGL_HAVE_CUSTOM_SHADERS
       
   167           , customShaderStage(0)
       
   168 #endif
       
   169     {
       
   170     }
       
   171 
       
   172     QByteArray pixelShaderFragment;
       
   173 #ifdef QGL_HAVE_CUSTOM_SHADERS
       
   174     QGLCustomShaderEffectStage *customShaderStage;
       
   175 #endif
       
   176 };
       
   177 
       
   178 /*#
       
   179     Constructs a shader effect and attaches it to \a parent.
       
   180 */
       
   181 QGraphicsShaderEffect::QGraphicsShaderEffect(QObject *parent)
       
   182     : QGraphicsEffect(*new QGraphicsShaderEffectPrivate(), parent)
       
   183 {
       
   184 }
       
   185 
       
   186 /*#
       
   187     Destroys this shader effect.
       
   188 */
       
   189 QGraphicsShaderEffect::~QGraphicsShaderEffect()
       
   190 {
       
   191 #ifdef QGL_HAVE_CUSTOM_SHADERS
       
   192     Q_D(QGraphicsShaderEffect);
       
   193     delete d->customShaderStage;
       
   194 #endif
       
   195 }
       
   196 
       
   197 /*#
       
   198     Returns the source code for the pixel shader fragment for
       
   199     this shader effect.  The default is a shader that copies
       
   200     its incoming pixmap directly to the output with no effect
       
   201     applied.
       
   202 
       
   203     \sa setPixelShaderFragment()
       
   204 */
       
   205 QByteArray QGraphicsShaderEffect::pixelShaderFragment() const
       
   206 {
       
   207     Q_D(const QGraphicsShaderEffect);
       
   208     return d->pixelShaderFragment;
       
   209 }
       
   210 
       
   211 /*#
       
   212     Sets the source code for the pixel shader fragment for
       
   213     this shader effect to \a code.
       
   214 
       
   215     The \a code must define a GLSL function with the signature
       
   216     \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)}
       
   217     that returns the source pixel value to use in the paint engine's
       
   218     shader program.  The following is the default pixel shader fragment,
       
   219     which draws a pixmap with no effect applied:
       
   220 
       
   221     \code
       
   222     lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) {
       
   223         return texture2D(imageTexture, textureCoords);
       
   224     }
       
   225     \endcode
       
   226 
       
   227     \sa pixelShaderFragment(), setUniforms()
       
   228 */
       
   229 void QGraphicsShaderEffect::setPixelShaderFragment(const QByteArray& code)
       
   230 {
       
   231     Q_D(QGraphicsShaderEffect);
       
   232     if (d->pixelShaderFragment != code) {
       
   233         d->pixelShaderFragment = code;
       
   234 #ifdef QGL_HAVE_CUSTOM_SHADERS
       
   235         delete d->customShaderStage;
       
   236         d->customShaderStage = 0;
       
   237 #endif
       
   238     }
       
   239 }
       
   240 
       
   241 /*#
       
   242     \reimp
       
   243 */
       
   244 void QGraphicsShaderEffect::draw(QPainter *painter, QGraphicsEffectSource *source)
       
   245 {
       
   246     Q_D(QGraphicsShaderEffect);
       
   247 
       
   248 #ifdef QGL_HAVE_CUSTOM_SHADERS
       
   249     // Set the custom shader on the paint engine.  The setOnPainter()
       
   250     // call may fail if the paint engine is not GL2.  In that case,
       
   251     // we fall through to drawing the pixmap normally.
       
   252     if (!d->customShaderStage) {
       
   253         d->customShaderStage = new QGLCustomShaderEffectStage
       
   254             (this, d->pixelShaderFragment);
       
   255     }
       
   256     bool usingShader = d->customShaderStage->setOnPainter(painter);
       
   257 
       
   258     QPoint offset;
       
   259     if (source->isPixmap()) {
       
   260         // No point in drawing in device coordinates (pixmap will be scaled anyways).
       
   261         const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset);
       
   262         painter->drawPixmap(offset, pixmap);
       
   263     } else {
       
   264         // Draw pixmap in device coordinates to avoid pixmap scaling.
       
   265         const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset);
       
   266         QTransform restoreTransform = painter->worldTransform();
       
   267         painter->setWorldTransform(QTransform());
       
   268         painter->drawPixmap(offset, pixmap);
       
   269         painter->setWorldTransform(restoreTransform);
       
   270     }
       
   271 
       
   272     // Remove the custom shader to return to normal painting operations.
       
   273     if (usingShader)
       
   274         d->customShaderStage->removeFromPainter(painter);
       
   275 #else
       
   276     source->draw(painter);
       
   277 #endif
       
   278 }
       
   279 
       
   280 /*#
       
   281     Sets the custom uniform variables on this shader effect to
       
   282     be dirty.  The setUniforms() function will be called the next
       
   283     time the shader program corresponding to this effect is used.
       
   284 
       
   285     This function is typically called by subclasses when an
       
   286     effect-specific parameter is changed by the application.
       
   287 
       
   288     \sa setUniforms()
       
   289 */
       
   290 void QGraphicsShaderEffect::setUniformsDirty()
       
   291 {
       
   292 #ifdef QGL_HAVE_CUSTOM_SHADERS
       
   293     Q_D(QGraphicsShaderEffect);
       
   294     if (d->customShaderStage)
       
   295         d->customShaderStage->setUniformsDirty();
       
   296 #endif
       
   297 }
       
   298 
       
   299 /*#
       
   300     Sets custom uniform variables on the current GL context when
       
   301     \a program is about to be used by the paint engine.
       
   302 
       
   303     This function should be overridden if the shader set with
       
   304     setPixelShaderFragment() has additional parameters beyond
       
   305     those that the paint engine normally sets itself.
       
   306 
       
   307     \sa setUniformsDirty()
       
   308 */
       
   309 void QGraphicsShaderEffect::setUniforms(QGLShaderProgram *program)
       
   310 {
       
   311     Q_UNUSED(program);
       
   312 }
       
   313 
       
   314 QT_END_NAMESPACE