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