Document recursion limitations of the graphical effects.
[qt:qtgraphicaleffects.git] / src / effects / Colorize.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 Colorize
46     \inqmlmodule QtGraphicalEffects 1.0
47     \since QtGraphicalEffects 1.0
48     \inherits QtQuick2::Item
49     \ingroup qtgraphicaleffects-color
50     \brief Sets the color in the HSL color space.
51
52     The effect is similar to what happens when a colorized glass is put on top
53     of a grayscale image. Colorize uses the hue, saturation, and lightness (HSL)
54     color space. You can specify a desired value for each property. You can
55     shift all HSL values with the
56     \l{QtGraphicalEffects1::HueSaturation}{HueSaturation} effect.
57
58     Alternatively, you can use the
59     \l{QtGraphicalEffects1::ColorOverlay}{ColorOverlay} effect to colorize the
60     source item in the RGBA color space.
61
62     \table
63     \header
64         \li Source
65         \li Effect applied
66     \row
67         \li \image Original_bug.png
68         \li \image Colorize_bug.png
69     \endtable
70
71     \section1 Example
72
73     The following example shows how to apply the effect.
74     \snippet Colorize-example.qml example
75 */
76 Item {
77     id: rootItem
78
79     /*!
80         This property defines the source item that provides the source pixels
81         for the effect.
82
83         \note It is not supported to let the effect include itself, for
84         instance by setting source to the effect's parent.
85     */
86     property variant source
87
88     /*!
89         This property defines the hue value which is used to colorize the
90         source.
91
92         The value ranges from 0.0 to 1.0. By default, the property is set to \c
93         0.0, which produces a slightly red color.
94
95         \table
96         \header
97             \li Allowed hue values
98         \row
99             \li \image Colorize_hue_scale.png
100         \endtable
101
102         \table
103         \header
104         \li Output examples with different hue values
105         \li
106         \li
107         \row
108             \li \image Colorize_hue1.png
109             \li \image Colorize_hue2.png
110             \li \image Colorize_hue3.png
111         \row
112             \li \b { hue: 0.2 }
113             \li \b { hue: 0.5 }
114             \li \b { hue: 0.8 }
115         \row
116             \li \l saturation: 1
117             \li \l saturation: 1
118             \li \l saturation: 1
119         \row
120             \li \l lightness: 0
121             \li \l lightness: 0
122             \li \l lightness: 0
123         \endtable
124     */
125     property real hue: 0.0
126
127     /*!
128         This property defines the saturation value which is used to colorize the
129         source.
130
131         The value ranges from 0.0 (desaturated) to 1.0 (saturated). By default,
132         the property is set to \c 1.0 (saturated).
133
134         \table
135         \header
136         \li Output examples with different saturation values
137         \li
138         \li
139         \row
140             \li \image Colorize_saturation1.png
141             \li \image Colorize_saturation2.png
142             \li \image Colorize_saturation3.png
143         \row
144             \li \b { saturation: 0 }
145             \li \b { saturation: 0.5 }
146             \li \b { saturation: 1 }
147         \row
148             \li \l hue: 0
149             \li \l hue: 0
150             \li \l hue: 0
151         \row
152             \li \l lightness: 0
153             \li \l lightness: 0
154             \li \l lightness: 0
155         \endtable
156     */
157     property real saturation: 1.0
158
159     /*!
160         This property defines how much the source lightness value is increased
161         or decreased.
162
163         Unlike hue and saturation properties, lightness does not set the used
164         value, but it shifts the existing source pixel lightness value.
165
166         The value ranges from -1.0 (decreased) to 1.0 (increased). By default,
167         the property is set to \c 0.0 (no change).
168
169         \table
170         \header
171         \li Output examples with different lightness values
172         \li
173         \li
174         \row
175             \li \image Colorize_lightness1.png
176             \li \image Colorize_lightness2.png
177             \li \image Colorize_lightness3.png
178         \row
179             \li \b { lightness: -0.75 }
180             \li \b { lightness: 0 }
181             \li \b { lightness: 0.75 }
182         \row
183             \li \l hue: 0
184             \li \l hue: 0
185             \li \l hue: 0
186         \row
187             \li \l saturation: 1
188             \li \l saturation: 1
189             \li \l saturation: 1
190         \endtable
191     */
192     property real lightness: 0.0
193
194     /*!
195         This property allows the effect output pixels to be cached in order to
196         improve the rendering performance.
197
198         Every time the source or effect properties are changed, the pixels in
199         the cache must be updated. Memory consumption is increased, because an
200         extra buffer of memory is required for storing the effect output.
201
202         It is recommended to disable the cache when the source or the effect
203         properties are animated.
204
205         By default, the property is set to \c false.
206     */
207     property bool cached: false
208
209     SourceProxy {
210         id: sourceProxy
211         input: rootItem.source
212     }
213
214     ShaderEffectSource {
215         id: cacheItem
216         anchors.fill: parent
217         visible: rootItem.cached
218         smooth: true
219         sourceItem: shaderItem
220         live: true
221         hideSource: visible
222     }
223
224     ShaderEffect {
225         id: shaderItem
226         property variant source: sourceProxy.output
227         property real hue: rootItem.hue
228         property real saturation: rootItem.saturation
229         property real lightness: rootItem.lightness
230
231         anchors.fill: parent
232
233         fragmentShader: "
234             varying mediump vec2 qt_TexCoord0;
235             uniform highp float qt_Opacity;
236             uniform lowp sampler2D source;
237             uniform highp float hue;
238             uniform highp float saturation;
239             uniform highp float lightness;
240
241             highp float RGBtoL(highp vec3 color) {
242                 highp float cmin = min(color.r, min(color.g, color.b));
243                 highp float cmax = max(color.r, max(color.g, color.b));
244                 highp float l = (cmin + cmax) / 2.0;
245                 return l;
246             }
247
248             highp float hueToIntensity(highp float v1, highp float v2, highp float h) {
249                 h = fract(h);
250                 if (h < 1.0 / 6.0)
251                     return v1 + (v2 - v1) * 6.0 * h;
252                 else if (h < 1.0 / 2.0)
253                     return v2;
254                 else if (h < 2.0 / 3.0)
255                     return v1 + (v2 - v1) * 6.0 * (2.0 / 3.0 - h);
256
257                 return v1;
258             }
259
260             highp vec3 HSLtoRGB(highp vec3 color) {
261                 highp float h = color.x;
262                 highp float l = color.z;
263                 highp float s = color.y;
264
265                 if (s < 1.0 / 256.0)
266                     return vec3(l, l, l);
267
268                 highp float v1;
269                 highp float v2;
270                 if (l < 0.5)
271                     v2 = l * (1.0 + s);
272                 else
273                     v2 = (l + s) - (s * l);
274
275                 v1 = 2.0 * l - v2;
276
277                 highp float d = 1.0 / 3.0;
278                 highp float r = hueToIntensity(v1, v2, h + d);
279                 highp float g = hueToIntensity(v1, v2, h);
280                 highp float b = hueToIntensity(v1, v2, h - d);
281                 return vec3(r, g, b);
282             }
283
284             void main() {
285                 lowp vec4 sample = texture2D(source, qt_TexCoord0);
286                 sample = vec4(sample.rgb / max(1.0/256.0, sample.a), sample.a);
287                 highp float light = RGBtoL(sample.rgb);
288                 highp float c = step(0.0, lightness);
289                 sample.rgb = HSLtoRGB(vec3(hue, saturation, mix(light, c, abs(lightness))));
290                 gl_FragColor = vec4(sample.rgb * sample.a, sample.a) * qt_Opacity;
291             }
292         "
293     }
294 }