1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qgraphicsshadereffect_p.h"
41
42#include "qglshaderprogram.h"
43#include "gl2paintengineex/qglcustomshaderstage_p.h"
44#define QGL_HAVE_CUSTOM_SHADERS 1
45#include <QtGui/qpainter.h>
46#include <QtWidgets/qgraphicsitem.h>
47#include <private/qgraphicseffect_p.h>
48
49QT_BEGIN_NAMESPACE
50
51/*#
52 \class QGraphicsShaderEffect
53 \inmodule QtOpenGL
54 \brief The QGraphicsShaderEffect class is the base class for creating
55 custom GLSL shader effects in a QGraphicsScene.
56 \since 4.6
57 \ingroup multimedia
58 \ingroup graphicsview-api
59
60 The specific effect is defined by a fragment of GLSL source code
61 supplied to setPixelShaderFragment(). This source code must define a
62 function with the signature
63 \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)}
64 that returns the source pixel value
65 to use in the paint engine's shader program. The shader fragment
66 is linked with the regular shader code used by the GL2 paint engine
67 to construct a complete QGLShaderProgram.
68
69 The following example shader converts the incoming pixmap to
70 grayscale and then applies a colorize operation using the
71 \c effectColor value:
72
73 \snippet code/src_opengl_qgraphicsshadereffect.cpp 0
74
75 To use this shader code, it is necessary to define a subclass
76 of QGraphicsShaderEffect as follows:
77
78 \snippet code/src_opengl_qgraphicsshadereffect.cpp 1
79
80 The setUniforms() function is called when the effect is about
81 to be used for drawing to give the subclass the opportunity to
82 set effect-specific uniform variables.
83
84 QGraphicsShaderEffect is only supported when the GL2 paint engine
85 is in use. When any other paint engine is in use (GL1, raster, etc),
86 the drawItem() method will draw its item argument directly with
87 no effect applied.
88
89 \sa QGraphicsEffect
90*/
91
92static const char qglslDefaultImageFragmentShader[] = "\
93 lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) { \
94 return texture2D(imageTexture, textureCoords); \
95 }\n";
96
97#ifdef QGL_HAVE_CUSTOM_SHADERS
98
99class QGLCustomShaderEffectStage : public QGLCustomShaderStage
100{
101public:
102 QGLCustomShaderEffectStage
103 (QGraphicsShaderEffect *e, const QByteArray& source)
104 : QGLCustomShaderStage(),
105 effect(e)
106 {
107 setSource(source);
108 }
109
110 void setUniforms(QGLShaderProgram *program) override;
111
112 QGraphicsShaderEffect *effect;
113};
114
115void QGLCustomShaderEffectStage::setUniforms(QGLShaderProgram *program)
116{
117 effect->setUniforms(program);
118}
119
120#endif
121
122class QGraphicsShaderEffectPrivate : public QGraphicsEffectPrivate
123{
124 Q_DECLARE_PUBLIC(QGraphicsShaderEffect)
125public:
126 QGraphicsShaderEffectPrivate()
127 : pixelShaderFragment(qglslDefaultImageFragmentShader)
128#ifdef QGL_HAVE_CUSTOM_SHADERS
129 , customShaderStage(0)
130#endif
131 {
132 }
133
134 QByteArray pixelShaderFragment;
135#ifdef QGL_HAVE_CUSTOM_SHADERS
136 QGLCustomShaderEffectStage *customShaderStage;
137#endif
138};
139
140/*#
141 Constructs a shader effect and attaches it to \a parent.
142*/
143QGraphicsShaderEffect::QGraphicsShaderEffect(QObject *parent)
144 : QGraphicsEffect(*new QGraphicsShaderEffectPrivate(), parent)
145{
146}
147
148/*#
149 Destroys this shader effect.
150*/
151QGraphicsShaderEffect::~QGraphicsShaderEffect()
152{
153#ifdef QGL_HAVE_CUSTOM_SHADERS
154 Q_D(QGraphicsShaderEffect);
155 delete d->customShaderStage;
156#endif
157}
158
159/*#
160 Returns the source code for the pixel shader fragment for
161 this shader effect. The default is a shader that copies
162 its incoming pixmap directly to the output with no effect
163 applied.
164
165 \sa setPixelShaderFragment()
166*/
167QByteArray QGraphicsShaderEffect::pixelShaderFragment() const
168{
169 Q_D(const QGraphicsShaderEffect);
170 return d->pixelShaderFragment;
171}
172
173/*#
174 Sets the source code for the pixel shader fragment for
175 this shader effect to \a code.
176
177 The \a code must define a GLSL function with the signature
178 \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)}
179 that returns the source pixel value to use in the paint engine's
180 shader program. The following is the default pixel shader fragment,
181 which draws a pixmap with no effect applied:
182
183 \snippet code/src_opengl_qgraphicsshadereffect.cpp 2
184
185 \sa pixelShaderFragment(), setUniforms()
186*/
187void QGraphicsShaderEffect::setPixelShaderFragment(const QByteArray& code)
188{
189 Q_D(QGraphicsShaderEffect);
190 if (d->pixelShaderFragment != code) {
191 d->pixelShaderFragment = code;
192#ifdef QGL_HAVE_CUSTOM_SHADERS
193 delete d->customShaderStage;
194 d->customShaderStage = 0;
195#endif
196 }
197}
198
199/*#
200 \reimp
201*/
202void QGraphicsShaderEffect::draw(QPainter *painter)
203{
204 Q_D(QGraphicsShaderEffect);
205
206#ifdef QGL_HAVE_CUSTOM_SHADERS
207 // Set the custom shader on the paint engine. The setOnPainter()
208 // call may fail if the paint engine is not GL2. In that case,
209 // we fall through to drawing the pixmap normally.
210 if (!d->customShaderStage) {
211 d->customShaderStage = new QGLCustomShaderEffectStage
212 (this, d->pixelShaderFragment);
213 }
214 bool usingShader = d->customShaderStage->setOnPainter(painter);
215
216 QPoint offset;
217 if (sourceIsPixmap()) {
218 // No point in drawing in device coordinates (pixmap will be scaled anyways).
219 const QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset);
220 painter->drawPixmap(offset, pixmap);
221 } else {
222 // Draw pixmap in device coordinates to avoid pixmap scaling.
223 const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset);
224 QTransform restoreTransform = painter->worldTransform();
225 painter->setWorldTransform(QTransform());
226 painter->drawPixmap(offset, pixmap);
227 painter->setWorldTransform(restoreTransform);
228 }
229
230 // Remove the custom shader to return to normal painting operations.
231 if (usingShader)
232 d->customShaderStage->removeFromPainter(painter);
233#else
234 drawSource(painter);
235#endif
236}
237
238/*#
239 Sets the custom uniform variables on this shader effect to
240 be dirty. The setUniforms() function will be called the next
241 time the shader program corresponding to this effect is used.
242
243 This function is typically called by subclasses when an
244 effect-specific parameter is changed by the application.
245
246 \sa setUniforms()
247*/
248void QGraphicsShaderEffect::setUniformsDirty()
249{
250#ifdef QGL_HAVE_CUSTOM_SHADERS
251 Q_D(QGraphicsShaderEffect);
252 if (d->customShaderStage)
253 d->customShaderStage->setUniformsDirty();
254#endif
255}
256
257/*#
258 Sets custom uniform variables on the current GL context when
259 \a program is about to be used by the paint engine.
260
261 This function should be overridden if the shader set with
262 setPixelShaderFragment() has additional parameters beyond
263 those that the paint engine normally sets itself.
264
265 \sa setUniformsDirty()
266*/
267void QGraphicsShaderEffect::setUniforms(QGLShaderProgram *program)
268{
269 Q_UNUSED(program);
270}
271
272QT_END_NAMESPACE
273