1/****************************************************************************
2**
3** Copyright (C) 2016 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:BSD$
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** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24**   * Redistributions of source code must retain the above copyright
25**     notice, this list of conditions and the following disclaimer.
26**   * Redistributions in binary form must reproduce the above copyright
27**     notice, this list of conditions and the following disclaimer in
28**     the documentation and/or other materials provided with the
29**     distribution.
30**   * Neither the name of The Qt Company Ltd nor the names of its
31**     contributors may be used to endorse or promote products derived
32**     from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51import QtQuick 2.0
52
53Item {
54    id: rootItem
55    property variant source
56    property real spread: 0.0
57    property real blur: 0.0
58    property color color: "white"
59    property bool transparentBorder: false
60    property bool cached: false
61
62    SourceProxy {
63        id: sourceProxy
64        input: rootItem.source
65    }
66
67    ShaderEffectSource {
68        id: cacheItem
69        anchors.fill: shaderItem
70        visible: rootItem.cached
71        smooth: true
72        sourceItem: shaderItem
73        live: true
74        hideSource: visible
75    }
76
77    property string __internalBlurVertexShader: "
78        attribute highp vec4 qt_Vertex;
79        attribute highp vec2 qt_MultiTexCoord0;
80        uniform highp mat4 qt_Matrix;
81        uniform highp float yStep;
82        uniform highp float xStep;
83        varying highp vec2 qt_TexCoord0;
84        varying highp vec2 qt_TexCoord1;
85        varying highp vec2 qt_TexCoord2;
86        varying highp vec2 qt_TexCoord3;
87
88        void main() {
89            qt_TexCoord0 = vec2(qt_MultiTexCoord0.x + xStep, qt_MultiTexCoord0.y + yStep * 0.36);
90            qt_TexCoord1 = vec2(qt_MultiTexCoord0.x + xStep * 0.36, qt_MultiTexCoord0.y - yStep);
91            qt_TexCoord2 = vec2(qt_MultiTexCoord0.x - xStep * 0.36, qt_MultiTexCoord0.y + yStep);
92            qt_TexCoord3 = vec2(qt_MultiTexCoord0.x - xStep, qt_MultiTexCoord0.y - yStep * 0.36);
93            gl_Position = qt_Matrix * qt_Vertex;
94        }
95    "
96
97    property string __internalBlurFragmentShader: "
98        uniform lowp sampler2D source;
99        uniform lowp float qt_Opacity;
100        varying highp vec2 qt_TexCoord0;
101        varying highp vec2 qt_TexCoord1;
102        varying highp vec2 qt_TexCoord2;
103        varying highp vec2 qt_TexCoord3;
104
105        void main() {
106            highp vec4 sourceColor = (texture2D(source, qt_TexCoord0) +
107            texture2D(source, qt_TexCoord1) +
108            texture2D(source, qt_TexCoord2) +
109            texture2D(source, qt_TexCoord3)) * 0.25;
110            gl_FragColor = sourceColor * qt_Opacity;
111        }
112   "
113
114    ShaderEffect {
115        id: level0
116        property variant source: sourceProxy.output
117        anchors.fill: parent
118        visible: false
119        smooth: true
120    }
121
122    ShaderEffectSource {
123        id: level1
124        width: Math.ceil(shaderItem.width / 32) * 32
125        height: Math.ceil(shaderItem.height / 32) * 32
126        sourceItem: level0
127        hideSource: rootItem.visible
128        sourceRect: transparentBorder ? Qt.rect(-64, -64, shaderItem.width, shaderItem.height) : Qt.rect(0,0,0,0)
129        smooth: true
130        visible: false
131    }
132
133    ShaderEffect {
134        id: effect1
135        property variant source: level1
136        property real yStep: 1/height
137        property real xStep: 1/width
138        anchors.fill: level2
139        visible: false
140        smooth: true
141        vertexShader: __internalBlurVertexShader
142        fragmentShader: __internalBlurFragmentShader
143    }
144
145    ShaderEffectSource {
146        id: level2
147        width: level1.width / 2
148        height: level1.height / 2
149        sourceItem: effect1
150        hideSource: rootItem.visible
151        visible: false
152        smooth: true
153    }
154
155    ShaderEffect {
156        id: effect2
157        property variant source: level2
158        property real yStep: 1/height
159        property real xStep: 1/width
160        anchors.fill: level3
161        visible: false
162        smooth: true
163        vertexShader: __internalBlurVertexShader
164        fragmentShader: __internalBlurFragmentShader
165    }
166
167    ShaderEffectSource {
168        id: level3
169        width: level2.width / 2
170        height: level2.height / 2
171        sourceItem: effect2
172        hideSource: rootItem.visible
173        visible: false
174        smooth: true
175    }
176
177    ShaderEffect {
178        id: effect3
179        property variant source: level3
180        property real yStep: 1/height
181        property real xStep: 1/width
182        anchors.fill: level4
183        visible: false
184        smooth: true
185        vertexShader: __internalBlurVertexShader
186        fragmentShader: __internalBlurFragmentShader
187    }
188
189    ShaderEffectSource {
190        id: level4
191        width: level3.width / 2
192        height: level3.height / 2
193        sourceItem: effect3
194        hideSource: rootItem.visible
195        visible: false
196        smooth: true
197    }
198
199    ShaderEffect {
200        id: effect4
201        property variant source: level4
202        property real yStep: 1/height
203        property real xStep: 1/width
204        anchors.fill: level5
205        visible: false
206        smooth: true
207        vertexShader: __internalBlurVertexShader
208        fragmentShader: __internalBlurFragmentShader
209    }
210
211    ShaderEffectSource {
212        id: level5
213        width: level4.width / 2
214        height: level4.height / 2
215        sourceItem: effect4
216        hideSource: rootItem.visible
217        visible: false
218        smooth: true
219    }
220
221    ShaderEffect {
222        id: effect5
223        property variant source: level5
224        property real yStep: 1/height
225        property real xStep: 1/width
226        anchors.fill: level6
227        visible: false
228        smooth: true
229        vertexShader: __internalBlurVertexShader
230        fragmentShader: __internalBlurFragmentShader
231    }
232
233    ShaderEffectSource {
234        id: level6
235        width: level5.width / 2
236        height: level5.height / 2
237        sourceItem: effect5
238        hideSource: rootItem.visible
239        visible: false
240        smooth: true
241    }
242
243    Item {
244        id: dummysource
245        width: 1
246        height: 1
247        visible: false
248    }
249
250    ShaderEffectSource {
251        id: dummy
252        width: 1
253        height: 1
254        sourceItem: dummysource
255        visible: false
256        smooth: false
257        live: false
258    }
259
260    ShaderEffect {
261        id: shaderItem
262        x: transparentBorder ? -64 : 0
263        y: transparentBorder ? -64 : 0
264        width: transparentBorder ? parent.width + 128 : parent.width
265        height: transparentBorder ? parent.height + 128 : parent.height
266
267        property variant source1: level1
268        property variant source2: level2
269        property variant source3: level3
270        property variant source4: level4
271        property variant source5: level5
272        property variant source6: level6
273        property real lod: rootItem.blur
274
275        property real weight1;
276        property real weight2;
277        property real weight3;
278        property real weight4;
279        property real weight5;
280        property real weight6;
281
282        property real spread: 1.0 - (rootItem.spread * 0.98)
283        property alias color: rootItem.color
284
285        function weight(v) {
286            if (v <= 0.0)
287                return 1
288            if (v >= 0.5)
289                return 0
290
291            return 1.0 - v / 0.5
292        }
293
294        function calculateWeights() {
295
296            var w1 = weight(Math.abs(lod - 0.100))
297            var w2 = weight(Math.abs(lod - 0.300))
298            var w3 = weight(Math.abs(lod - 0.500))
299            var w4 = weight(Math.abs(lod - 0.700))
300            var w5 = weight(Math.abs(lod - 0.900))
301            var w6 = weight(Math.abs(lod - 1.100))
302
303            var sum = w1 + w2 + w3 + w4 + w5 + w6;
304            weight1 = w1 / sum;
305            weight2 = w2 / sum;
306            weight3 = w3 / sum;
307            weight4 = w4 / sum;
308            weight5 = w5 / sum;
309            weight6 = w6 / sum;
310
311            upateSources()
312        }
313
314        function upateSources() {
315            var sources = new Array();
316            var weights = new Array();
317
318            if (weight1 > 0) {
319                sources.push(level1)
320                weights.push(weight1)
321            }
322
323            if (weight2 > 0) {
324                sources.push(level2)
325                weights.push(weight2)
326            }
327
328            if (weight3 > 0) {
329                sources.push(level3)
330                weights.push(weight3)
331            }
332
333            if (weight4 > 0) {
334                sources.push(level4)
335                weights.push(weight4)
336            }
337
338            if (weight5 > 0) {
339                sources.push(level5)
340                weights.push(weight5)
341            }
342
343            if (weight6 > 0) {
344                sources.push(level6)
345                weights.push(weight6)
346            }
347
348            for (var j = sources.length; j < 6; j++) {
349                sources.push(dummy)
350                weights.push(0.0)
351            }
352
353            source1 = sources[0]
354            source2 = sources[1]
355            source3 = sources[2]
356            source4 = sources[3]
357            source5 = sources[4]
358            source6 = sources[5]
359
360            weight1 = weights[0]
361            weight2 = weights[1]
362            weight3 = weights[2]
363            weight4 = weights[3]
364            weight5 = weights[4]
365            weight6 = weights[5]
366        }
367
368        Component.onCompleted: calculateWeights()
369
370        onLodChanged: calculateWeights()
371
372        fragmentShader: "
373            uniform lowp sampler2D source1;
374            uniform lowp sampler2D source2;
375            uniform lowp sampler2D source3;
376            uniform lowp sampler2D source4;
377            uniform lowp sampler2D source5;
378            uniform mediump float weight1;
379            uniform mediump float weight2;
380            uniform mediump float weight3;
381            uniform mediump float weight4;
382            uniform mediump float weight5;
383            uniform highp vec4 color;
384            uniform highp float spread;
385            uniform lowp float qt_Opacity;
386            varying mediump vec2 qt_TexCoord0;
387
388            highp float linearstep(highp float e0, highp float e1, highp float x) {
389                return clamp((x - e0) / (e1 - e0), 0.0, 1.0);
390            }
391
392            void main() {
393                lowp vec4 sourceColor = texture2D(source1, qt_TexCoord0) * weight1;
394                sourceColor += texture2D(source2, qt_TexCoord0) * weight2;
395                sourceColor += texture2D(source3, qt_TexCoord0) * weight3;
396                sourceColor += texture2D(source4, qt_TexCoord0) * weight4;
397                sourceColor += texture2D(source5, qt_TexCoord0) * weight5;
398                sourceColor = mix(vec4(0), color, linearstep(0.0, spread, sourceColor.a));
399                gl_FragColor = sourceColor * qt_Opacity;
400            }
401        "
402    }
403}
404