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 RecursiveBlur 45 \inqmlmodule QtGraphicalEffects 46 \since QtGraphicalEffects 1.0 47 \inherits QtQuick2::Item 48 \ingroup qtgraphicaleffects-blur 49 \brief Blurs repeatedly, providing a strong blur effect. 50 51 The RecursiveBlur effect softens the image by blurring it with an algorithm 52 that uses a recursive feedback loop to blur the source multiple times. The 53 effect may give more blurry results than 54 \l{QtGraphicalEffects::GaussianBlur}{GaussianBlur} or 55 \l{QtGraphicalEffects::FastBlur}{FastBlur}, but the result is produced 56 asynchronously and takes more time. 57 58 \table 59 \header 60 \li Source 61 \li Effect applied 62 \row 63 \li \image Original_bug.png 64 \li \image RecursiveBlur_bug.png 65 \endtable 66 67 \note This effect is available when running with OpenGL. 68 69 \section1 Example 70 71 The following example shows how to apply the effect. 72 \snippet RecursiveBlur-example.qml example 73 74*/ 75Item { 76 id: rootItem 77 78 /*! 79 This property defines the source item that is going to be blurred. 80 81 \note It is not supported to let the effect include itself, for 82 instance by setting source to the effect's parent. 83 */ 84 property variant source 85 86 /*! 87 This property defines the distance of neighboring pixels which influence 88 the blurring of individual pixels. A larger radius provides better 89 quality, but is slower to render. 90 91 \b Note: The radius value in this effect is not intended to be changed 92 or animated frequently. The correct way to use it is to set the correct 93 value and keep it unchanged for the whole duration of the iterative blur 94 sequence. 95 96 The value ranges from (no blur) to 16.0 (maximum blur step). By default, 97 the property is set to \c 0.0 (no blur). 98 99 \table 100 \header 101 \li Output examples with different radius values 102 \li 103 \li 104 \row 105 \li \image RecursiveBlur_radius1.png 106 \li \image RecursiveBlur_radius2.png 107 \li \image RecursiveBlur_radius3.png 108 \row 109 \li \b { radius: 2.5 } 110 \li \b { radius: 4.5 } 111 \li \b { radius: 7.5 } 112 \row 113 \li \l loops: 20 114 \li \l loops: 20 115 \li \l loops: 20 116 \endtable 117 118 */ 119 property real radius: 0.0 120 121 /*! 122 This property allows the effect output pixels to be cached in order to 123 improve the rendering performance. 124 125 Every time the source or effect properties are changed, the pixels in 126 the cache must be updated. Memory consumption is increased, because an 127 extra buffer of memory is required for storing the effect output. 128 129 It is recommended to disable the cache when the source or the effect 130 properties are animated. 131 132 By default, the property is set to \c false. 133 134 */ 135 property bool cached: false 136 137 /*! 138 This property defines the blur behavior near the edges of the item, 139 where the pixel blurring is affected by the pixels outside the source 140 edges. 141 142 If the property is set to \c true, the pixels outside the source are 143 interpreted to be transparent, which is similar to OpenGL 144 clamp-to-border extension. The blur is expanded slightly outside the 145 effect item area. 146 147 If the property is set to \c false, the pixels outside the source are 148 interpreted to contain the same color as the pixels at the edge of the 149 item, which is similar to OpenGL clamp-to-edge behavior. The blur does 150 not expand outside the effect item area. 151 152 By default, the property is set to \c false. 153 154 \table 155 \header 156 \li Output examples with different transparentBorder values 157 \li 158 \li 159 \row 160 \li \image RecursiveBlur_transparentBorder1.png 161 \li \image RecursiveBlur_transparentBorder2.png 162 \row 163 \li \b { transparentBorder: false } 164 \li \b { transparentBorder: true } 165 \row 166 \li \l loops: 20 167 \li \l loops: 20 168 \row 169 \li \l radius: 7.5 170 \li \l radius: 7.5 171 \endtable 172 */ 173 property bool transparentBorder: false 174 175 /*! 176 This property defines the amount of blur iterations that are going to be 177 performed for the source. When the property changes, the iterative 178 blurring process starts. If the value is decreased or if the value 179 changes from zero to non-zero, a snapshot is taken from the source. The 180 snapshot is used as a starting point for the process. 181 182 The iteration loop tries to run as fast as possible. The speed might be 183 limited by the VSYNC or the time needed for one blur step, or both. 184 Sometimes it may be desirable to perform the blurring with a slower 185 pace. In that case, it may be convenient to control the property with 186 Animation which increases the value. 187 188 The value ranges from 0 to inf. By default, the property is set to \c 0. 189 190 \table 191 \header 192 \li Output examples with different loops values 193 \li 194 \li 195 \row 196 \li \image RecursiveBlur_loops1.png 197 \li \image RecursiveBlur_loops2.png 198 \li \image RecursiveBlur_loops3.png 199 \row 200 \li \b { loops: 4 } 201 \li \b { loops: 20 } 202 \li \b { loops: 70 } 203 \row 204 \li \l radius: 7.5 205 \li \l radius: 7.5 206 \li \l radius: 7.5 207 \endtable 208 209 */ 210 property int loops: 0 211 212 /*! 213 This property holds the progress of asynchronous source blurring 214 process, from 0.0 (nothing blurred) to 1.0 (finished). 215 */ 216 property real progress: loops > 0.0 ? Math.min(1.0, recursionTimer.counter / loops) : 0.0 217 218 onLoopsChanged: recursiveSource.scheduleUpdate() 219 onSourceChanged: recursionTimer.reset() 220 onRadiusChanged: recursionTimer.reset() 221 onTransparentBorderChanged: recursionTimer.reset() 222 223 SourceProxy { 224 id: sourceProxy 225 input: rootItem.source 226 sourceRect: rootItem.transparentBorder ? Qt.rect(-1, -1, parent.width + 2, parent.height + 2) : Qt.rect(0, 0, 0, 0) 227 } 228 229 ShaderEffectSource { 230 id: cacheItem 231 anchors.fill: verticalBlur 232 smooth: true 233 visible: rootItem.cached 234 hideSource: visible 235 live: true 236 sourceItem: inputItem.visible ? inputItem : verticalBlur 237 } 238 239 Item { 240 id: recursionTimer 241 property int counter: 0 242 243 function reset() { 244 counter = 0 245 recursiveSource.scheduleUpdate() 246 } 247 248 function nextFrame() { 249 if (loops < counter) 250 recursionTimer.counter = 0 251 252 if (counter > 0) 253 recursiveSource.sourceItem = verticalBlur 254 else 255 recursiveSource.sourceItem = inputItem 256 257 if (counter < loops) { 258 recursiveSource.scheduleUpdate() 259 counter++ 260 } 261 } 262 } 263 264 ShaderEffect { 265 id: inputItem 266 property variant source: sourceProxy.output 267 property real expandX: rootItem.transparentBorder ? (horizontalBlur.maximumRadius) / horizontalBlur.width : 0.0 268 property real expandY: rootItem.transparentBorder ? (horizontalBlur.maximumRadius) / horizontalBlur.height : 0.0 269 270 anchors.fill: verticalBlur 271 visible: !verticalBlur.visible 272 273 vertexShader: "qrc:/qt-project.org/imports/QtGraphicalEffects/shaders/recursiveblur.vert" 274 275 fragmentShader: "qrc:/qt-project.org/imports/QtGraphicalEffects/shaders/recursiveblur.frag" 276 } 277 278 ShaderEffectSource { 279 id: recursiveSource 280 visible: false 281 smooth: true 282 hideSource: false 283 live: false 284 sourceItem: inputItem 285 recursive: true 286 onSourceItemChanged: scheduleUpdate() 287 onScheduledUpdateCompleted: recursionTimer.nextFrame() 288 } 289 290 GaussianDirectionalBlur { 291 id: verticalBlur 292 x: rootItem.transparentBorder ? -horizontalBlur.maximumRadius - 1 : 0 293 y: rootItem.transparentBorder ? -horizontalBlur.maximumRadius - 1 : 0 294 width: horizontalBlur.width + 2 295 height: horizontalBlur.height + 2 296 297 horizontalStep: 0.0 298 verticalStep: 1.0 / parent.height 299 300 source: ShaderEffectSource { 301 sourceItem: horizontalBlur 302 hideSource: true 303 visible: false 304 smooth: true 305 } 306 307 deviation: (radius + 1) / 2.3333 308 radius: rootItem.radius 309 maximumRadius: Math.ceil(rootItem.radius) 310 transparentBorder: false 311 visible: loops > 0 312 } 313 314 GaussianDirectionalBlur { 315 id: horizontalBlur 316 width: rootItem.transparentBorder ? parent.width + 2 * maximumRadius + 2 : parent.width 317 height: rootItem.transparentBorder ? parent.height + 2 * maximumRadius + 2 : parent.height 318 319 horizontalStep: 1.0 / parent.width 320 verticalStep: 0.0 321 322 source: recursiveSource 323 deviation: (radius + 1) / 2.3333 324 radius: rootItem.radius 325 maximumRadius: Math.ceil(rootItem.radius) 326 transparentBorder: false 327 visible: false 328 } 329} 330