1 /****************************************************************************
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the Qt Graphical Effects module.
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
14 ** * Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** * Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in
18 ** the documentation and/or other materials provided with the
20 ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 ** of its contributors may be used to endorse or promote products derived
22 ** from this software without specific prior written permission.
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
39 ****************************************************************************/
46 \inqmlmodule QtGraphicalEffects 1.0
47 \since QtGraphicalEffects 1.0
48 \inherits QtQuick2::Item
49 \ingroup qtgraphicaleffects-motion-blur
50 \brief Applies directional blur in a circular direction around the items
53 Effect creates perceived impression that the source item appears to be
54 rotating to the direction of the blur.
56 Other available motionblur effects are
57 \l{QtGraphicalEffects1::ZoomBlur}{ZoomBlur} and
58 \l{QtGraphicalEffects1::DirectionalBlur}{DirectionalBlur}.
65 \li \image Original_bug.png
66 \li \image RadialBlur_bug.png
69 \section1 Example Usage
71 The following example shows how to apply the effect.
72 \snippet RadialBlur-example.qml example
78 This property defines the source item that is going to be blurred.
80 \note It is not supported to let the effect include itself, for
81 instance by setting source to the effect's parent.
83 property variant source
86 This property defines the direction for the blur and at the same time
87 the level of blurring. The larger the angle, the more the result becomes
88 blurred. The quality of the blur depends on
89 \l{RadialBlur::samples}{samples} property. If angle value is large, more
90 samples are needed to keep the visual quality at high level.
92 Allowed values are between 0.0 and 360.0. By default the property is set
97 \li Output examples with different angle values
101 \li \image RadialBlur_angle1.png
102 \li \image RadialBlur_angle2.png
103 \li \image RadialBlur_angle3.png
105 \li \b { angle: 0.0 }
106 \li \b { angle: 15.0 }
107 \li \b { angle: 30.0 }
113 \li \l horizontalOffset: 0
114 \li \l horizontalOffset: 0
115 \li \l horizontalOffset: 0
117 \li \l verticalOffset: 0
118 \li \l verticalOffset: 0
119 \li \l verticalOffset: 0
122 property real angle: 0.0
125 This property defines how many samples are taken per pixel when blur
126 calculation is done. Larger value produces better quality, but is slower
129 This property is not intended to be animated. Changing this property may
130 cause the underlying OpenGL shaders to be recompiled.
132 Allowed values are between 0 and inf (practical maximum depends on GPU).
133 By default the property is set to \c 0 (no samples).
136 property int samples: 0
139 \qmlproperty real QtGraphicalEffects1::RadialBlur::horizontalOffset
140 \qmlproperty real QtGraphicalEffects1::RadialBlur::verticalOffset
142 These properties define the offset in pixels for the perceived center
143 point of the rotation.
145 Allowed values are between -inf and inf.
146 By default these properties are set to \c 0.
150 \li Output examples with different horizontalOffset values
154 \li \image RadialBlur_horizontalOffset1.png
155 \li \image RadialBlur_horizontalOffset2.png
156 \li \image RadialBlur_horizontalOffset3.png
158 \li \b { horizontalOffset: 75.0 }
159 \li \b { horizontalOffset: 0.0 }
160 \li \b { horizontalOffset: -75.0 }
170 \li \l verticalOffset: 0
171 \li \l verticalOffset: 0
172 \li \l verticalOffset: 0
175 property real horizontalOffset: 0.0
176 property real verticalOffset: 0.0
179 This property defines the blur behavior near the edges of the item,
180 where the pixel blurring is affected by the pixels outside the source
183 If the property is set to \c true, the pixels outside the source are
184 interpreted to be transparent, which is similar to OpenGL
185 clamp-to-border extension. The blur is expanded slightly outside the
188 If the property is set to \c false, the pixels outside the source are
189 interpreted to contain the same color as the pixels at the edge of the
190 item, which is similar to OpenGL clamp-to-edge behavior. The blur does
191 not expand outside the effect item area.
193 By default, the property is set to \c false.
195 property bool transparentBorder: false
198 This property allows the effect output pixels to be cached in order to
199 improve the rendering performance.
201 Every time the source or effect properties are changed, the pixels in
202 the cache must be updated. Memory consumption is increased, because an
203 extra buffer of memory is required for storing the effect output.
205 It is recommended to disable the cache when the source or the effect
206 properties are animated.
208 By default, the property is set to \c false.
211 property bool cached: false
215 input: rootItem.source
216 sourceRect: shaderItem.transparentBorder ? Qt.rect(-1, -1, parent.width + 2.0, parent.height + 2.0) : Qt.rect(0, 0, 0, 0)
221 anchors.fill: shaderItem
222 visible: rootItem.cached
224 sourceItem: shaderItem
231 property variant source: sourceProxy.output
232 property variant center: Qt.point(0.5 + rootItem.horizontalOffset / parent.width, 0.5 + rootItem.verticalOffset / parent.height)
233 property bool transparentBorder: rootItem.transparentBorder && rootItem.samples > 1
234 property int samples: rootItem.samples
235 property real weight: 1.0 / Math.max(1.0, rootItem.samples)
236 property real angleSin: Math.sin(rootItem.angle/2 * Math.PI/180)
237 property real angleCos: Math.cos(rootItem.angle/2 * Math.PI/180)
238 property real angleSinStep: Math.sin(-rootItem.angle * Math.PI/180 / Math.max(1.0, rootItem.samples - 1))
239 property real angleCosStep: Math.cos(-rootItem.angle * Math.PI/180 / Math.max(1.0, rootItem.samples - 1))
240 property variant expandPixels: transparentBorder ? Qt.size(0.5 * parent.height, 0.5 * parent.width) : Qt.size(0,0)
241 property variant expand: transparentBorder ? Qt.size(expandPixels.width / width, expandPixels.height / height) : Qt.size(0,0)
242 property variant delta: Qt.size(1.0 / rootItem.width, 1.0 / rootItem.height)
243 property real w: parent.width
244 property real h: parent.height
246 x: transparentBorder ? -expandPixels.width - 1 : 0
247 y: transparentBorder ? -expandPixels.height - 1 : 0
248 width: transparentBorder ? parent.width + expandPixels.width * 2.0 + 2 : parent.width
249 height: transparentBorder ? parent.height + expandPixels.height * 2.0 + 2 : parent.height
251 property string fragmentShaderSkeleton: "
252 varying highp vec2 qt_TexCoord0;
253 uniform highp float qt_Opacity;
254 uniform lowp sampler2D source;
255 uniform highp float angleSin;
256 uniform highp float angleCos;
257 uniform highp float angleSinStep;
258 uniform highp float angleCosStep;
259 uniform highp float weight;
260 uniform highp vec2 expand;
261 uniform highp vec2 center;
262 uniform highp vec2 delta;
263 uniform highp float w;
264 uniform highp float h;
268 gl_FragColor = vec4(0.0);
269 mediump vec2 texCoord = qt_TexCoord0;
271 PLACEHOLDER_EXPAND_STEPS
273 highp vec2 dir = vec2(texCoord.s * w - w * center.x, texCoord.t * h - h * center.y);
274 m[0] = vec2(angleCos, -angleSin);
275 m[1] = vec2(angleSin, angleCos);
278 m[0] = vec2(angleCosStep, -angleSinStep);
279 m[1] = vec2(angleSinStep, angleCosStep);
281 PLACEHOLDER_UNROLLED_LOOP
283 gl_FragColor *= weight * qt_Opacity;
287 function buildFragmentShader() {
288 var shader = fragmentShaderSkeleton
291 if (transparentBorder) {
292 expandSteps += "texCoord = (texCoord - expand) / (1.0 - 2.0 * expand);"
295 var unrolledLoop = "gl_FragColor += texture2D(source, texCoord);\n"
297 if (rootItem.samples > 1) {
299 for (var i = 0; i < rootItem.samples; i++)
300 unrolledLoop += "gl_FragColor += texture2D(source, center + dir * delta); dir *= m;\n"
303 shader = shader.replace("PLACEHOLDER_EXPAND_STEPS", expandSteps)
304 fragmentShader = shader.replace("PLACEHOLDER_UNROLLED_LOOP", unrolledLoop)
307 onFragmentShaderChanged: sourceChanged()
308 onSamplesChanged: buildFragmentShader()
309 onTransparentBorderChanged: buildFragmentShader()
310 Component.onCompleted: buildFragmentShader()