RecursiveBlur.qml 11 KB

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