Document recursion limitations of the graphical effects.
[qt:qtgraphicaleffects.git] / src / effects / Displace.qml
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the Qt Graphical Effects module.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 **     of its contributors may be used to endorse or promote products derived
22 **     from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 import QtQuick 2.0
42 import "private"
43
44 /*!
45     \qmltype Displace
46     \inqmlmodule QtGraphicalEffects 1.0
47     \since QtGraphicalEffects 1.0
48     \inherits QtQuick2::Item
49     \ingroup qtgraphicaleffects-distortion
50     \brief Moves the pixels of the source item according to the given
51     displacement map.
52
53     \table
54     \header
55         \li Source
56         \li DisplacementSource
57         \li Effect applied
58     \row
59         \li \image Original_bug.png
60         \li \image Displace_map.png
61         \li \image Displace_bug.png
62     \endtable
63
64     \section1 Example
65
66     The following example shows how to apply the effect.
67     \snippet Displace-example.qml example
68
69 */
70 Item {
71     id: rootItem
72
73     /*!
74         This property defines the source item for the pixels that are going to
75         be displaced according to the data from
76         \l{Displace::displacementSource}{displacementSource}.
77
78         \note It is not supported to let the effect include itself, for
79         instance by setting source to the effect's parent.
80     */
81     property variant source
82
83     /*!
84         This property defines the item that is going to be used as the
85         displacement map. The displacementSource item gets rendered into the
86         intermediate pixel buffer. The red and green component values from the
87         result determine the displacement of the pixels from the source item.
88
89         The format for the displacement map is similar to the tangent space
90         normal maps, which can be created with most 3D-modeling tools. Many
91         image processing tools include the support for generating normal maps.
92         Alternatively, the displacement map for this effect can also be a QML
93         element which is colored appropriately. Like any QML element, it can be
94         animated. It is recommended that the size of the diplacement map matches
95         the size of the \l{Displace::source}{source}.
96
97         The displace data is interpreted in the RGBA format. For every pixel:
98         the red channel stores the x-axis displacement, and the green channel
99         stores the y-axis displacement. Blue and alpha channels are ignored for
100         this effect.
101
102         Assuming that red channel value 1.0 is fully red (0.0 having no red at
103         all), this effect considers pixel component value 0.5 to cause no
104         displacement at all. Values above 0.5 shift pixels to the left, values
105         below 0.5 do the shift to the right. In a similar way, green channel
106         values above 0.5 displace the pixels upwards, and values below 0.5 shift
107         the pixels downwards. The actual amount of displacement in pixels
108         depends on the \l displacement property.
109
110     */
111     property variant displacementSource
112
113     /*!
114         This property defines the scale for the displacement. The bigger scale,
115         the bigger the displacement of the pixels. The value set to 0.0 causes
116         no displacement.
117
118         The value ranges from -1.0 (inverted maximum shift, according to
119         displacementSource) to 1.0 (maximum shift, according to
120         displacementSource). By default, the property is set to \c 0.0 (no
121         displacement).
122
123         \table
124         \header
125         \li Output examples with different displacement values
126         \li
127         \li
128         \row
129             \li \image Displace_displacement1.png
130             \li \image Displace_displacement2.png
131             \li \image Displace_displacement3.png
132         \row
133             \li \b { displacement: -0.2 }
134             \li \b { displacement: 0.0 }
135             \li \b { displacement: 0.2 }
136         \endtable
137
138     */
139     property real displacement: 0.0
140
141     /*!
142         This property allows the effect output pixels to be cached in order to
143         improve the rendering performance.
144
145         Every time the source or effect properties are changed, the pixels in
146         the cache must be updated. Memory consumption is increased, because an
147         extra buffer of memory is required for storing the effect output.
148
149         It is recommended to disable the cache when the source or the effect
150         properties are animated.
151
152         By default, the property is set to \c false.
153
154     */
155     property bool cached: false
156
157     SourceProxy {
158         id: sourceProxy
159         input: rootItem.source
160     }
161
162     SourceProxy {
163         id: displacementSourceProxy
164         input: rootItem.displacementSource
165     }
166
167     ShaderEffectSource {
168         id: cacheItem
169         anchors.fill: parent
170         visible: rootItem.cached
171         smooth: true
172         sourceItem: shaderItem
173         live: true
174         hideSource: visible
175     }
176
177     ShaderEffect {
178         id: shaderItem
179         property variant source: sourceProxy.output
180         property variant displacementSource: displacementSourceProxy.output
181         property real displacement: rootItem.displacement
182         property real xPixel: 1.0/width
183         property real yPixel: 1.0/height
184
185         anchors.fill: parent
186
187         fragmentShader: "
188             varying highp vec2 qt_TexCoord0;
189             uniform highp float qt_Opacity;
190             uniform lowp sampler2D source;
191             uniform lowp sampler2D displacementSource;
192             uniform highp float displacement;
193             uniform highp float xPixel;
194             uniform highp float yPixel;
195
196             highp float linearstep(highp float e0, highp float e1, highp float x) {
197                 return clamp((x - e0) / (e1 - e0), 0.0, 1.0);
198             }
199
200             void main() {
201                 lowp vec4 offset = texture2D(displacementSource, qt_TexCoord0);
202                 offset.xy -= vec2(0.5, 0.5);
203                 offset.xy = offset.xy * step(vec2(1.0/256.0), abs(offset.xy));
204                 highp vec2 tx = qt_TexCoord0 + (vec2(-offset.x, offset.y) * displacement);
205
206                 lowp float e1 = linearstep(0.0, xPixel, tx.x);
207                 lowp float e2 = linearstep(0.0, yPixel, tx.y);
208                 lowp float e3 = 1.0 - linearstep(1.0, 1.0 + xPixel, tx.x);
209                 lowp float e4 = 1.0 - linearstep(1.0, 1.0 + yPixel, tx.y);
210
211                 lowp vec4 sample = texture2D(source, tx);
212                 sample.rgb *= e1 * e2 * e3 * e4;
213                 gl_FragColor = sample * qt_Opacity * offset.a;
214             }
215         "
216     }
217 }