Document recursion limitations of the graphical effects.
[qt:qtgraphicaleffects.git] / src / effects / ConicalGradient.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 ConicalGradient
46     \inqmlmodule QtGraphicalEffects 1.0
47     \since QtGraphicalEffects 1.0
48     \inherits QtQuick2::Item
49     \ingroup qtgraphicaleffects-gradient
50     \brief Draws a conical gradient.
51
52     A gradient is defined by two or more colors, which are blended seamlessly.
53     The colors start from the specified angle and end at 360 degrees larger
54     angle value.
55
56     \table
57     \header
58         \li Effect applied
59     \row
60         \li \image ConicalGradient.png
61     \endtable
62
63     \section1 Example
64
65     The following example shows how to apply the effect.
66     \snippet ConicalGradient-example.qml example
67
68 */
69 Item {
70     id: rootItem
71
72     /*!
73         This property allows the effect output pixels to be cached in order to
74         improve the rendering performance.
75
76         Every time the source or effect properties are changed, the pixels in
77         the cache must be updated. Memory consumption is increased, because an
78         extra buffer of memory is required for storing the effect output.
79
80         It is recommended to disable the cache when the source or the effect
81         properties are animated.
82
83         By default, the property is set to \c false.
84
85     */
86     property bool cached: false
87
88     /*!
89         This property defines the starting angle where the color at the gradient
90         position of 0.0 is rendered. Colors at larger position values are
91         rendered into larger angle values and blended seamlessly. Angle values
92         increase clockwise.
93
94         \table
95         \header
96         \li Output examples with different angle values
97         \li
98         \li
99         \row
100             \li \image ConicalGradient_angle1.png
101             \li \image ConicalGradient_angle2.png
102             \li \image ConicalGradient_angle3.png
103         \row
104             \li \b { angle: 0 }
105             \li \b { angle: 45 }
106             \li \b { angle: 185 }
107         \row
108             \li \l horizontalOffset: 0
109             \li \l horizontalOffset: 0
110             \li \l horizontalOffset: 0
111         \row
112             \li \l verticalOffset: 0
113             \li \l verticalOffset: 0
114             \li \l verticalOffset: 0
115         \endtable
116
117     */
118     property real angle: 0.0
119
120     /*!
121     \qmlproperty real QtGraphicalEffects1::ConicalGradient::horizontalOffset
122     \qmlproperty real QtGraphicalEffects1::ConicalGradient::verticalOffset
123
124     The horizontalOffset and verticalOffset properties define the offset in
125     pixels for the center point of the gradient compared to the item center.
126
127     The value ranges from -inf to inf. By default, the properties are set to \c
128     0.
129
130     \table
131     \header
132     \li Output examples with different horizontalOffset values
133     \li
134     \li
135     \row
136         \li \image ConicalGradient_horizontalOffset1.png
137         \li \image ConicalGradient_horizontalOffset2.png
138         \li \image ConicalGradient_horizontalOffset3.png
139     \row
140         \li \b { horizontalOffset: -50 }
141         \li \b { horizontalOffset: 0 }
142         \li \b { horizontalOffset: 50 }
143     \row
144         \li \l angle: 0
145         \li \l angle: 0
146         \li \l angle: 0
147     \row
148         \li \l verticalOffset: 0
149         \li \l verticalOffset: 0
150         \li \l verticalOffset: 0
151     \endtable
152     */
153     property real horizontalOffset: 0.0
154     property real verticalOffset: 0.0
155
156     /*!
157         This property defines the item that is going to be filled with gradient.
158         Source item gets rendered into an intermediate pixel buffer and the
159         alpha values from the result are used to determine the gradient's pixels
160         visibility in the display. The default value for source is undefined and
161         in that case whole effect area is filled with gradient.
162
163         \table
164         \header
165         \li Output examples with different source values
166         \li
167         \row
168             \li \image ConicalGradient_maskSource1.png
169             \li \image ConicalGradient_maskSource2.png
170         \row
171             \li \b { source: undefined }
172             \li \b { source:  }
173         \row
174             \li \l angle: 0
175             \li \l angle: 0
176         \row
177             \li \l horizontalOffset: 0
178             \li \l horizontalOffset: 0
179         \row
180             \li \l verticalOffset: 0
181             \li \l verticalOffset: 0
182         \endtable
183
184
185         \note It is not supported to let the effect include itself, for
186         instance by setting source to the effect's parent.
187     */
188     property variant source
189
190 /*!
191     A gradient is defined by two or more colors, which are blended seamlessly.
192     The colors are specified as a set of GradientStop child items, each of which
193     defines a position on the gradient (from 0.0 to 1.0), and a color.
194     The position of each GradientStop is defined by the position property.
195     The color is defined by the color property.
196
197     \table
198     \header
199     \li Output examples with different gradient values
200     \li
201     \li
202     \row
203         \li \image ConicalGradient_gradient1.png
204         \li \image ConicalGradient_gradient2.png
205         \li \image ConicalGradient_gradient3.png
206     \row
207         \li \b {gradient:} \code
208 Gradient {
209   GradientStop { position: 0.000
210   color: Qt.rgba(1, 0, 0, 1) }
211   GradientStop { position: 0.167;
212   color: Qt.rgba(1, 1, 0, 1) }
213   GradientStop { position: 0.333;
214   color: Qt.rgba(0, 1, 0, 1) }
215   GradientStop { position: 0.500;
216   color: Qt.rgba(0, 1, 1, 1) }
217   GradientStop { position: 0.667;
218   color: Qt.rgba(0, 0, 1, 1) }
219   GradientStop { position: 0.833;
220   color: Qt.rgba(1, 0, 1, 1) }
221   GradientStop { position: 1.000;
222   color: Qt.rgba(1, 0, 0, 1) }
223 }
224     \endcode
225         \li \b {gradient:} \code
226 Gradient {
227   GradientStop { position: 0.0
228   color: "#F0F0F0"
229   }
230   GradientStop { position: 0.5
231   color: "#000000"
232   }
233   GradientStop { position: 1.0
234   color: "#F0F0F0"
235   }
236 }
237     \endcode
238         \li \b {gradient:} \code
239 Gradient {
240   GradientStop { position: 0.0
241     color: "#00000000"
242   }
243   GradientStop { position: 1.0
244     color: "#FF000000"
245   }
246 }
247     \endcode
248     \row
249         \li \l angle: 0
250         \li \l angle: 0
251         \li \l angle: 0
252     \row
253         \li \l horizontalOffset: 0
254         \li \l horizontalOffset: 0
255         \li \l horizontalOffset: 0
256     \row
257         \li \l verticalOffset: 0
258         \li \l verticalOffset: 0
259         \li \l verticalOffset: 0
260     \endtable
261
262 */
263     property Gradient gradient: Gradient {
264         GradientStop { position: 0.0; color: "white" }
265         GradientStop { position: 1.0; color: "black" }
266     }
267
268     SourceProxy {
269         id: maskSourceProxy
270         input: rootItem.source
271     }
272
273     Rectangle {
274         id: gradientRect
275         width: 16
276         height: 256
277         gradient: rootItem.gradient
278         smooth: true
279    }
280
281     ShaderEffectSource {
282         id: cacheItem
283         anchors.fill: parent
284         visible: rootItem.cached
285         smooth: true
286         rotation: shaderItem.rotation
287         sourceItem: shaderItem
288         live: true
289         hideSource: visible
290     }
291
292     ShaderEffect {
293         id: shaderItem
294         property variant gradientSource: ShaderEffectSource {
295             sourceItem: gradientRect
296             smooth: true
297             hideSource: true
298             visible: false
299         }
300         property variant maskSource: maskSourceProxy.output
301         property real startAngle: (rootItem.angle - 90) * Math.PI/180
302         property variant center: Qt.point(0.5 + horizontalOffset / width, 0.5 + verticalOffset / height)
303
304         anchors.fill: parent
305
306         fragmentShader: maskSource == undefined ? noMaskShader : maskShader
307
308         onFragmentShaderChanged: startAngleChanged()
309
310         property string noMaskShader: "
311             varying mediump vec2 qt_TexCoord0;
312             uniform lowp sampler2D gradientSource;
313             uniform highp float qt_Opacity;
314             uniform highp float startAngle;
315             uniform highp vec2 center;
316
317             void main() {
318                 const highp float PI = 3.14159265;
319                 const highp float PIx2inv = 0.1591549;
320                 highp float a = (atan((center.y - qt_TexCoord0.t), (center.x - qt_TexCoord0.s)) + PI - startAngle) * PIx2inv;
321                 gl_FragColor = texture2D(gradientSource, vec2(0.0, fract(a))) * qt_Opacity;
322             }
323         "
324
325         property string maskShader: "
326             varying mediump vec2 qt_TexCoord0;
327             uniform lowp sampler2D gradientSource;
328             uniform lowp sampler2D maskSource;
329             uniform highp float qt_Opacity;
330             uniform highp float startAngle;
331             uniform highp vec2 center;
332
333             void main() {
334                 lowp float maskAlpha = texture2D(maskSource, qt_TexCoord0).a;
335                 const highp float PI = 3.14159265;
336                 const highp float PIx2inv = 0.1591549;
337                 highp float a = (atan((center.y - qt_TexCoord0.t), (center.x - qt_TexCoord0.s)) + PI - startAngle) * PIx2inv;
338                 gl_FragColor = texture2D(gradientSource, vec2(0.0, fract(a))) * maskAlpha * qt_Opacity;
339             }
340         "
341     }
342 }