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