diff -r 000000000000 -r 1918ee327afb src/opengl/qgraphicsshadereffect.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/opengl/qgraphicsshadereffect.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,314 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgraphicsshadereffect_p.h" +#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) +#include "qglshaderprogram.h" +#include "gl2paintengineex/qglcustomshaderstage_p.h" +#define QGL_HAVE_CUSTOM_SHADERS 1 +#endif +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*# + \class QGraphicsShaderEffect + \brief The QGraphicsShaderEffect class is the base class for creating + custom GLSL shader effects in a QGraphicsScene. + \since 4.6 + \ingroup multimedia + \ingroup graphicsview-api + + The specific effect is defined by a fragment of GLSL source code + supplied to setPixelShaderFragment(). This source code must define a + function with the signature + \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)} + that returns the source pixel value + to use in the paint engine's shader program. The shader fragment + is linked with the regular shader code used by the GL2 paint engine + to construct a complete QGLShaderProgram. + + The following example shader converts the incoming pixmap to + grayscale and then applies a colorize operation using the + \c effectColor value: + + \code + static char const colorizeShaderCode[] = + "uniform lowp vec4 effectColor;\n" + "lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) {\n" + " vec4 src = texture2D(imageTexture, textureCoords);\n" + " float gray = dot(src.rgb, vec3(0.212671, 0.715160, 0.072169));\n" + " vec4 colorize = 1.0-((1.0-gray)*(1.0-effectColor));\n" + " return vec4(colorize.rgb, src.a);\n" + "}"; + \endcode + + To use this shader code, it is necessary to define a subclass + of QGraphicsShaderEffect as follows: + + \code + class ColorizeEffect : public QGraphicsShaderEffect + { + Q_OBJECT + public: + ColorizeEffect(QObject *parent = 0) + : QGraphicsShaderEffect(parent), color(Qt::black) + { + setPixelShaderFragment(colorizeShaderCode); + } + + QColor effectColor() const { return color; } + void setEffectColor(const QColor& c) + { + color = c; + setUniformsDirty(); + } + + protected: + void setUniforms(QGLShaderProgram *program) + { + program->setUniformValue("effectColor", color); + } + + private: + QColor color; + }; + \endcode + + The setUniforms() function is called when the effect is about + to be used for drawing to give the subclass the opportunity to + set effect-specific uniform variables. + + QGraphicsShaderEffect is only supported when the GL2 paint engine + is in use. When any other paint engine is in use (GL1, raster, etc), + the drawItem() method will draw its item argument directly with + no effect applied. + + \sa QGraphicsEffect +*/ + +static const char qglslDefaultImageFragmentShader[] = "\ + lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) { \ + return texture2D(imageTexture, textureCoords); \ + }\n"; + +#ifdef QGL_HAVE_CUSTOM_SHADERS + +class QGLCustomShaderEffectStage : public QGLCustomShaderStage +{ +public: + QGLCustomShaderEffectStage + (QGraphicsShaderEffect *e, const QByteArray& source) + : QGLCustomShaderStage(), + effect(e) + { + setSource(source); + } + + void setUniforms(QGLShaderProgram *program); + + QGraphicsShaderEffect *effect; +}; + +void QGLCustomShaderEffectStage::setUniforms(QGLShaderProgram *program) +{ + effect->setUniforms(program); +} + +#endif + +class QGraphicsShaderEffectPrivate : public QGraphicsEffectPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsShaderEffect) +public: + QGraphicsShaderEffectPrivate() + : pixelShaderFragment(qglslDefaultImageFragmentShader) +#ifdef QGL_HAVE_CUSTOM_SHADERS + , customShaderStage(0) +#endif + { + } + + QByteArray pixelShaderFragment; +#ifdef QGL_HAVE_CUSTOM_SHADERS + QGLCustomShaderEffectStage *customShaderStage; +#endif +}; + +/*# + Constructs a shader effect and attaches it to \a parent. +*/ +QGraphicsShaderEffect::QGraphicsShaderEffect(QObject *parent) + : QGraphicsEffect(*new QGraphicsShaderEffectPrivate(), parent) +{ +} + +/*# + Destroys this shader effect. +*/ +QGraphicsShaderEffect::~QGraphicsShaderEffect() +{ +#ifdef QGL_HAVE_CUSTOM_SHADERS + Q_D(QGraphicsShaderEffect); + delete d->customShaderStage; +#endif +} + +/*# + Returns the source code for the pixel shader fragment for + this shader effect. The default is a shader that copies + its incoming pixmap directly to the output with no effect + applied. + + \sa setPixelShaderFragment() +*/ +QByteArray QGraphicsShaderEffect::pixelShaderFragment() const +{ + Q_D(const QGraphicsShaderEffect); + return d->pixelShaderFragment; +} + +/*# + Sets the source code for the pixel shader fragment for + this shader effect to \a code. + + The \a code must define a GLSL function with the signature + \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)} + that returns the source pixel value to use in the paint engine's + shader program. The following is the default pixel shader fragment, + which draws a pixmap with no effect applied: + + \code + lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) { + return texture2D(imageTexture, textureCoords); + } + \endcode + + \sa pixelShaderFragment(), setUniforms() +*/ +void QGraphicsShaderEffect::setPixelShaderFragment(const QByteArray& code) +{ + Q_D(QGraphicsShaderEffect); + if (d->pixelShaderFragment != code) { + d->pixelShaderFragment = code; +#ifdef QGL_HAVE_CUSTOM_SHADERS + delete d->customShaderStage; + d->customShaderStage = 0; +#endif + } +} + +/*# + \reimp +*/ +void QGraphicsShaderEffect::draw(QPainter *painter, QGraphicsEffectSource *source) +{ + Q_D(QGraphicsShaderEffect); + +#ifdef QGL_HAVE_CUSTOM_SHADERS + // Set the custom shader on the paint engine. The setOnPainter() + // call may fail if the paint engine is not GL2. In that case, + // we fall through to drawing the pixmap normally. + if (!d->customShaderStage) { + d->customShaderStage = new QGLCustomShaderEffectStage + (this, d->pixelShaderFragment); + } + bool usingShader = d->customShaderStage->setOnPainter(painter); + + QPoint offset; + if (source->isPixmap()) { + // No point in drawing in device coordinates (pixmap will be scaled anyways). + const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); + painter->drawPixmap(offset, pixmap); + } else { + // Draw pixmap in device coordinates to avoid pixmap scaling. + const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + painter->drawPixmap(offset, pixmap); + painter->setWorldTransform(restoreTransform); + } + + // Remove the custom shader to return to normal painting operations. + if (usingShader) + d->customShaderStage->removeFromPainter(painter); +#else + source->draw(painter); +#endif +} + +/*# + Sets the custom uniform variables on this shader effect to + be dirty. The setUniforms() function will be called the next + time the shader program corresponding to this effect is used. + + This function is typically called by subclasses when an + effect-specific parameter is changed by the application. + + \sa setUniforms() +*/ +void QGraphicsShaderEffect::setUniformsDirty() +{ +#ifdef QGL_HAVE_CUSTOM_SHADERS + Q_D(QGraphicsShaderEffect); + if (d->customShaderStage) + d->customShaderStage->setUniformsDirty(); +#endif +} + +/*# + Sets custom uniform variables on the current GL context when + \a program is about to be used by the paint engine. + + This function should be overridden if the shader set with + setPixelShaderFragment() has additional parameters beyond + those that the paint engine normally sets itself. + + \sa setUniformsDirty() +*/ +void QGraphicsShaderEffect::setUniforms(QGLShaderProgram *program) +{ + Q_UNUSED(program); +} + +QT_END_NAMESPACE