Update copyright year in Digia's license headers
[qt:qtgraphicaleffects.git] / src / effects / DirectionalBlur.qml
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the Qt Graphical Effects module.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
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
19 **     distribution.
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.
23 **
24 **
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."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 import QtQuick 2.0
42 import "private"
43
44 /*!
45     \qmltype DirectionalBlur
46     \inqmlmodule QtGraphicalEffects 1.0
47     \since QtGraphicalEffects 1.0
48     \inherits QtQuick2::Item
49     \ingroup qtgraphicaleffects-motion-blur
50     \brief Applies blur effect to the specified direction.
51
52     Effect creates perceived impression that the source item appears to be
53     moving in the direction of the blur. Blur is applied to both sides of
54     each pixel, therefore setting the direction to 0 and 180 provides the
55     same result.
56
57     Other available motionblur effects are \l{QtGraphicalEffects1::ZoomBlur}{ZoomBlur} and
58     \l{QtGraphicalEffects1::RadialBlur}{RadialBlur}.
59
60     \table
61     \header
62         \li Source
63         \li Effect applied
64     \row
65         \li \image Original_bug.png
66         \li \image DirectionalBlur_bug.png
67     \endtable
68
69     \section1 Example
70
71     The following example shows how to apply the effect.
72     \snippet DirectionalBlur-example.qml example
73
74 */
75 Item {
76     id: rootItem
77
78     /*!
79         This property defines the source item that is going to be blurred.
80     */
81     property variant source
82
83     /*!
84         This property defines the percieved amount of movement for each pixel.
85         The movement is divided evenly to both sides of each pixel.
86
87         The quality of the blur depends on \l{DirectionalBlur::samples}{samples}
88         property. If length value is large, more samples are needed to keep the
89         visual quality at high level.
90
91         The value ranges from 0.0 to inf.
92         By default the property is set to \c 0.0 (no blur).
93
94         \table
95         \header
96         \li Output examples with different length values
97         \li
98         \li
99         \row
100             \li \image DirectionalBlur_length1.png
101             \li \image DirectionalBlur_length2.png
102             \li \image DirectionalBlur_length3.png
103         \row
104             \li \b { length: 0.0 }
105             \li \b { length: 32.0 }
106             \li \b { length: 48.0 }
107         \row
108             \li \l samples: 24
109             \li \l samples: 24
110             \li \l samples: 24
111         \row
112             \li \l angle: 0
113             \li \l angle: 0
114             \li \l angle: 0
115         \endtable
116
117     */
118     property real length: 0.0
119
120     /*!
121         This property defines how many samples are taken per pixel when blur
122         calculation is done. Larger value produces better quality, but is slower
123         to render.
124
125         This property is not intended to be animated. Changing this property may
126         cause the underlying OpenGL shaders to be recompiled.
127
128         Allowed values are between 0 and inf (practical maximum depends on GPU).
129         By default the property is set to \c 0 (no samples).
130
131     */
132     property int samples: 0
133
134     /*!
135         This property defines the direction for the blur. Blur is applied to
136         both sides of each pixel, therefore setting the direction to 0 and 180
137         produces the same result.
138
139         The value ranges from -180.0 to 180.0.
140         By default the property is set to \c 0.0.
141
142         \table
143         \header
144         \li Output examples with different angle values
145         \li
146         \li
147         \row
148             \li \image DirectionalBlur_angle1.png
149             \li \image DirectionalBlur_angle2.png
150             \li \image DirectionalBlur_angle3.png
151         \row
152             \li \b { angle: 0.0 }
153             \li \b { angle: 45.0 }
154             \li \b { angle: 90.0 }
155         \row
156             \li \l samples: 24
157             \li \l samples: 24
158             \li \l samples: 24
159         \row
160             \li \l length: 32
161             \li \l length: 32
162             \li \l length: 32
163         \endtable
164
165     */
166     property real angle: 0.0
167
168     /*!
169         This property defines the blur behavior near the edges of the item,
170         where the pixel blurring is affected by the pixels outside the source
171         edges.
172
173         If the property is set to \c true, the pixels outside the source are
174         interpreted to be transparent, which is similar to OpenGL
175         clamp-to-border extension. The blur is expanded slightly outside the
176         effect item area.
177
178         If the property is set to \c false, the pixels outside the source are
179         interpreted to contain the same color as the pixels at the edge of the
180         item, which is similar to OpenGL clamp-to-edge behavior. The blur does
181         not expand outside the effect item area.
182
183         By default, the property is set to \c false.
184
185     */
186     property bool transparentBorder: false
187
188     /*!
189         This property allows the effect output pixels to be cached in order to
190         improve the rendering performance.
191
192         Every time the source or effect properties are changed, the pixels in
193         the cache must be updated. Memory consumption is increased, because an
194         extra buffer of memory is required for storing the effect output.
195
196         It is recommended to disable the cache when the source or the effect
197         properties are animated.
198
199         By default, the property is set to \c false.
200
201     */
202     property bool cached: false
203
204     SourceProxy {
205         id: sourceProxy
206         input: rootItem.source
207         sourceRect: rootItem.transparentBorder ? Qt.rect(-1, -1, parent.width + 2.0, parent.height + 2.0) : Qt.rect(0, 0, 0, 0)
208     }
209
210     ShaderEffectSource {
211         id: cacheItem
212         anchors.fill: shaderItem
213         visible: rootItem.cached
214         smooth: true
215         sourceItem: shaderItem
216         live: true
217         hideSource: visible
218     }
219
220     ShaderEffect {
221         id: shaderItem
222         property variant source: sourceProxy.output
223         property real len: rootItem.length
224         property bool transparentBorder: rootItem.transparentBorder
225         property real samples: rootItem.samples
226         property real weight: 1.0 / Math.max(1.0, rootItem.samples)
227         property variant expandPixels: transparentBorder ? Qt.size(rootItem.samples, rootItem.samples) : Qt.size(0,0)
228         property variant expand: transparentBorder ? Qt.size(expandPixels.width / width, expandPixels.height / height) : Qt.size(0,0)
229         property variant delta: Qt.size(1.0 / rootItem.width * Math.cos((rootItem.angle + 90) * Math.PI/180), 1.0 / rootItem.height * Math.sin((rootItem.angle + 90) * Math.PI/180))
230
231         x: transparentBorder ? -expandPixels.width - 1: 0
232         y: transparentBorder ? -expandPixels.height - 1 : 0
233         width: transparentBorder ? parent.width + 2.0 * expandPixels.width + 2 : parent.width
234         height: transparentBorder ? parent.height + 2.0 * expandPixels.height + 2 : parent.height
235
236         property string fragmentShaderSkeleton: "
237             varying highp vec2 qt_TexCoord0;
238             uniform highp float qt_Opacity;
239             uniform lowp sampler2D source;
240             uniform highp float len;
241             uniform highp float samples;
242             uniform highp float weight;
243             uniform highp vec2 expand;
244             uniform highp vec2 delta;
245
246             void main(void) {
247                 highp vec2 shift = delta * len / max(1.0, samples - 1.0);
248                 mediump vec2 texCoord = qt_TexCoord0;
249                 gl_FragColor = vec4(0.0);
250
251                 PLACEHOLDER_EXPAND_STEPS
252
253                 texCoord -= shift * max(0.0, samples - 1.0) * 0.5;
254
255                 PLACEHOLDER_UNROLLED_LOOP
256
257                 gl_FragColor *= weight * qt_Opacity;
258            }
259         "
260
261         function buildFragmentShader() {
262             var shader = fragmentShaderSkeleton
263             var expandSteps = ""
264
265             if (transparentBorder) {
266                 expandSteps += "texCoord = (texCoord - expand) / (1.0 - 2.0 * expand);"
267             }
268
269             var unrolledLoop = "gl_FragColor += texture2D(source, texCoord);\n"
270
271             if (rootItem.samples > 1) {
272                 unrolledLoop = ""
273                 for (var i = 0; i < rootItem.samples; i++)
274                     unrolledLoop += "gl_FragColor += texture2D(source, texCoord); texCoord += shift;\n"
275             }
276
277             shader = shader.replace("PLACEHOLDER_EXPAND_STEPS", expandSteps)
278             fragmentShader = shader.replace("PLACEHOLDER_UNROLLED_LOOP", unrolledLoop)
279         }
280
281         onFragmentShaderChanged: sourceChanged()
282         onSamplesChanged: buildFragmentShader()
283         onTransparentBorderChanged: buildFragmentShader()
284         Component.onCompleted: buildFragmentShader()
285     }
286 }