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 | |
49 | QT_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 | |
92 | static 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 | |
99 | class QGLCustomShaderEffectStage : public QGLCustomShaderStage |
100 | { |
101 | public: |
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 | |
115 | void QGLCustomShaderEffectStage::setUniforms(QGLShaderProgram *program) |
116 | { |
117 | effect->setUniforms(program); |
118 | } |
119 | |
120 | #endif |
121 | |
122 | class QGraphicsShaderEffectPrivate : public QGraphicsEffectPrivate |
123 | { |
124 | Q_DECLARE_PUBLIC(QGraphicsShaderEffect) |
125 | public: |
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 | */ |
143 | QGraphicsShaderEffect::QGraphicsShaderEffect(QObject *parent) |
144 | : QGraphicsEffect(*new QGraphicsShaderEffectPrivate(), parent) |
145 | { |
146 | } |
147 | |
148 | /*# |
149 | Destroys this shader effect. |
150 | */ |
151 | QGraphicsShaderEffect::~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 | */ |
167 | QByteArray 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 | */ |
187 | void 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 | */ |
202 | void 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(system: Qt::LogicalCoordinates, offset: &offset); |
220 | painter->drawPixmap(p: offset, pm: pixmap); |
221 | } else { |
222 | // Draw pixmap in device coordinates to avoid pixmap scaling. |
223 | const QPixmap pixmap = sourcePixmap(system: Qt::DeviceCoordinates, offset: &offset); |
224 | QTransform restoreTransform = painter->worldTransform(); |
225 | painter->setWorldTransform(matrix: QTransform()); |
226 | painter->drawPixmap(p: offset, pm: pixmap); |
227 | painter->setWorldTransform(matrix: 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 | */ |
248 | void 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 | */ |
267 | void QGraphicsShaderEffect::setUniforms(QGLShaderProgram *program) |
268 | { |
269 | Q_UNUSED(program); |
270 | } |
271 | |
272 | QT_END_NAMESPACE |
273 | |