Document recursion limitations of the graphical effects.
[qt:qtgraphicaleffects.git] / src / effects / LevelAdjust.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 Add-On 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 LevelAdjust
46     \inqmlmodule QtGraphicalEffects 1.0
47     \since QtGraphicalEffects 1.0
48     \inherits QtQuick2::Item
49     \ingroup qtgraphicaleffects-color
50     \brief Adjusts color levels in the RGBA color space.
51
52     This effect adjusts the source item colors separately for each color
53     channel. Source item contrast can be adjusted and color balance altered.
54
55     \table
56     \header
57         \li Source
58         \li Effect applied
59     \row
60         \li \image Original_butterfly.png
61         \li \image LevelAdjust_butterfly.png
62     \endtable
63
64     \section1 Example
65
66     The following example shows how to apply the effect.
67     \snippet LevelAdjust-example.qml example
68
69 */
70 Item {
71     id: rootItem
72
73     /*!
74         This property defines the source item that provides the source pixels
75         for the effect.
76
77         \note It is not supported to let the effect include itself, for
78         instance by setting source to the effect's parent.
79     */
80     property variant source
81
82     /*!
83         This property defines the change factor for how the value of each pixel
84         color channel is altered according to the equation:
85
86         \code result.rgb = pow(original.rgb, 1.0 / gamma.rgb); \endcode
87
88         Setting the gamma values under QtVector3d(1.0, 1.0, 1.0) makes the image
89         darker, the values above QtVector3d(1.0, 1.0, 1.0) lighten it.
90
91         The value ranges from QtVector3d(0.0, 0.0, 0.0) (darkest) to inf
92         (lightest). By default, the property is set to \c QtVector3d(1.0, 1.0,
93         1.0) (no change).
94
95         \table
96         \header
97         \li Output examples with different gamma values
98         \li
99         \li
100         \row
101             \li \image LevelAdjust_gamma1.png
102             \li \image LevelAdjust_gamma2.png
103             \li \image LevelAdjust_gamma3.png
104         \row
105             \li \b { gamma: Qt.vector3d(1.0, 1.0, 1.0) }
106             \li \b { gamma: Qt.vector3d(1.0, 0.4, 2.0) }
107             \li \b { gamma: Qt.vector3d(1.0, 0.1, 4.0) }
108         \row
109             \li \l minimumInput: #000000
110             \li \l minimumInput: #000000
111             \li \l minimumInput: #000000
112         \row
113             \li \l maximumInput: #ffffff
114             \li \l maximumInput: #ffffff
115             \li \l maximumInput: #ffffff
116         \row
117             \li \l minimumOutput: #000000
118             \li \l minimumOutput: #000000
119             \li \l minimumOutput: #000000
120         \row
121             \li \l maximumOutput: #ffffff
122             \li \l maximumOutput: #ffffff
123             \li \l maximumOutput: #ffffff
124         \endtable
125
126         \table
127         \header
128             \li Pixel color channel luminance curves of the above images.
129             \li
130             \li
131         \row
132             \li \image LevelAdjust_default_curve.png
133             \li \image LevelAdjust_gamma2_curve.png
134             \li \image LevelAdjust_gamma3_curve.png
135         \row
136             \li X-axis: pixel original luminance
137             \li
138             \li
139         \row
140             \li Y-axis: color channel luminance with effect applied
141             \li
142             \li
143         \endtable
144     */
145     property variant gamma: Qt.vector3d(1.0, 1.0, 1.0)
146
147     /*!
148         This property defines the minimum input level for each color channel. It
149         sets the black-point, all pixels having lower value than this property
150         are rendered as black (per color channel). Increasing the value darkens
151         the dark areas.
152
153         The value ranges from "#00000000" to "#ffffffff". By default, the
154         property is set to \c "#00000000" (no change).
155
156         \table
157         \header
158         \li Output examples with different minimumInput values
159         \li
160         \li
161         \row
162             \li \image LevelAdjust_minimumInput1.png
163             \li \image LevelAdjust_minimumInput2.png
164             \li \image LevelAdjust_minimumInput3.png
165         \row
166             \li \b { minimumInput: #00000000 }
167             \li \b { minimumInput: #00000040 }
168             \li \b { minimumInput: #00000070 }
169         \row
170             \li \l maximumInput: #ffffff
171             \li \l maximumInput: #ffffff
172             \li \l maximumInput: #ffffff
173         \row
174             \li \l minimumOutput: #000000
175             \li \l minimumOutput: #000000
176             \li \l minimumOutput: #000000
177         \row
178             \li \l maximumOutput: #ffffff
179             \li \l maximumOutput: #ffffff
180             \li \l maximumOutput: #ffffff
181         \row
182             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
183             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
184             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
185         \endtable
186
187         \table
188         \header
189             \li Pixel color channel luminance curves of the above images.
190             \li
191             \li
192         \row
193             \li \image LevelAdjust_default_curve.png
194             \li \image LevelAdjust_minimumInput2_curve.png
195             \li \image LevelAdjust_minimumInput3_curve.png
196         \row
197             \li X-axis: pixel original luminance
198             \li
199             \li
200         \row
201             \li Y-axis: color channel luminance with effect applied
202             \li
203             \li
204         \endtable
205
206     */
207     property color minimumInput: Qt.rgba(0.0, 0.0, 0.0, 0.0)
208
209     /*!
210         This property defines the maximum input level for each color channel.
211         It sets the white-point, all pixels having higher value than this
212         property are rendered as white (per color channel).
213         Decreasing the value lightens the light areas.
214
215         The value ranges from "#ffffffff" to "#00000000". By default, the
216         property is set to \c "#ffffffff" (no change).
217
218         \table
219         \header
220         \li Output examples with different maximumInput values
221         \li
222         \li
223         \row
224             \li \image LevelAdjust_maximumInput1.png
225             \li \image LevelAdjust_maximumInput2.png
226             \li \image LevelAdjust_maximumInput3.png
227         \row
228             \li \b { maximumInput: #FFFFFFFF }
229             \li \b { maximumInput: #FFFFFF80 }
230             \li \b { maximumInput: #FFFFFF30 }
231         \row
232             \li \l minimumInput: #000000
233             \li \l minimumInput: #000000
234             \li \l minimumInput: #000000
235         \row
236             \li \l minimumOutput: #000000
237             \li \l minimumOutput: #000000
238             \li \l minimumOutput: #000000
239         \row
240             \li \l maximumOutput: #ffffff
241             \li \l maximumOutput: #ffffff
242             \li \l maximumOutput: #ffffff
243         \row
244             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
245             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
246             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
247         \endtable
248
249         \table
250         \header
251             \li Pixel color channel luminance curves of the above images.
252             \li
253             \li
254         \row
255             \li \image LevelAdjust_default_curve.png
256             \li \image LevelAdjust_maximumInput2_curve.png
257             \li \image LevelAdjust_maximumInput3_curve.png
258         \row
259             \li X-axis: pixel original luminance
260             \li
261             \li
262         \row
263             \li Y-axis: color channel luminance with effect applied
264             \li
265             \li
266         \endtable
267
268     */
269     property color maximumInput: Qt.rgba(1.0, 1.0, 1.0, 1.0)
270
271     /*!
272         This property defines the minimum output level for each color channel.
273         Increasing the value lightens the dark areas, reducing the contrast.
274
275         The value ranges from "#00000000" to "#ffffffff". By default, the
276         property is set to \c "#00000000" (no change).
277
278         \table
279         \header
280         \li Output examples with different minimumOutput values
281         \li
282         \li
283         \row
284             \li \image LevelAdjust_minimumOutput1.png
285             \li \image LevelAdjust_minimumOutput2.png
286             \li \image LevelAdjust_minimumOutput3.png
287         \row
288             \li \b { minimumOutput: #00000000 }
289             \li \b { minimumOutput: #00000070 }
290             \li \b { minimumOutput: #000000A0 }
291         \row
292             \li \l minimumInput: #000000
293             \li \l minimumInput: #000000
294             \li \l minimumInput: #000000
295         \row
296             \li \l maximumInput: #ffffff
297             \li \l maximumInput: #ffffff
298             \li \l maximumInput: #ffffff
299         \row
300             \li \l maximumOutput: #ffffff
301             \li \l maximumOutput: #ffffff
302             \li \l maximumOutput: #ffffff
303         \row
304             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
305             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
306             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
307         \endtable
308
309         \table
310         \header
311             \li Pixel color channel luminance curves of the above images.
312             \li
313             \li
314         \row
315             \li \image LevelAdjust_default_curve.png
316             \li \image LevelAdjust_minimumOutput2_curve.png
317             \li \image LevelAdjust_minimumOutput3_curve.png
318         \row
319             \li X-axis: pixel original luminance
320             \li
321             \li
322         \row
323             \li Y-axis: color channel luminance with effect applied
324             \li
325             \li
326         \endtable
327
328     */
329     property color minimumOutput: Qt.rgba(0.0, 0.0, 0.0, 0.0)
330
331     /*!
332         This property defines the maximum output level for each color channel.
333         Decreasing the value darkens the light areas, reducing the contrast.
334
335         The value ranges from "#ffffffff" to "#00000000". By default, the
336         property is set to \c "#ffffffff" (no change).
337
338         \table
339         \header
340         \li Output examples with different maximumOutput values
341         \li
342         \li
343         \row
344             \li \image LevelAdjust_maximumOutput1.png
345             \li \image LevelAdjust_maximumOutput2.png
346             \li \image LevelAdjust_maximumOutput3.png
347         \row
348             \li \b { maximumOutput: #FFFFFFFF }
349             \li \b { maximumOutput: #FFFFFF80 }
350             \li \b { maximumOutput: #FFFFFF30 }
351         \row
352             \li \l minimumInput: #000000
353             \li \l minimumInput: #000000
354             \li \l minimumInput: #000000
355         \row
356             \li \l maximumInput: #ffffff
357             \li \l maximumInput: #ffffff
358             \li \l maximumInput: #ffffff
359         \row
360             \li \l minimumOutput: #000000
361             \li \l minimumOutput: #000000
362             \li \l minimumOutput: #000000
363         \row
364             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
365             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
366             \li \l gamma: Qt.vector3d(1.0, 1.0, 1.0)
367         \endtable
368
369         \table
370         \header
371             \li Pixel color channel luminance curves of the above images.
372             \li
373             \li
374         \row
375             \li \image LevelAdjust_default_curve.png
376             \li \image LevelAdjust_maximumOutput2_curve.png
377             \li \image LevelAdjust_maximumOutput3_curve.png
378         \row
379             \li X-axis: pixel original luminance
380             \li
381             \li
382         \row
383             \li Y-axis: color channel luminance with effect applied
384             \li
385             \li
386         \endtable
387     */
388     property color maximumOutput: Qt.rgba(1.0, 1.0, 1.0, 1.0)
389
390     /*!
391         This property allows the effect output pixels to be cached in order to
392         improve the rendering performance.
393
394         Every time the source or effect properties are changed, the pixels in
395         the cache must be updated. Memory consumption is increased, because an
396         extra buffer of memory is required for storing the effect output.
397
398         It is recommended to disable the cache when the source or the effect
399         properties are animated.
400
401         By default, the property is set to \c false.
402     */
403     property bool cached: false
404
405     SourceProxy {
406         id: sourceProxy
407         input: rootItem.source
408     }
409
410     ShaderEffectSource {
411         id: cacheItem
412         anchors.fill: parent
413         visible: rootItem.cached
414         smooth: true
415         sourceItem: shaderItem
416         live: true
417         hideSource: visible
418     }
419
420     ShaderEffect {
421         id: shaderItem
422         property variant source: sourceProxy.output
423         property variant minimumInputRGB: Qt.vector3d(rootItem.minimumInput.r, rootItem.minimumInput.g, rootItem.minimumInput.b)
424         property variant maximumInputRGB: Qt.vector3d(rootItem.maximumInput.r, rootItem.maximumInput.g, rootItem.maximumInput.b)
425         property real minimumInputAlpha: rootItem.minimumInput.a
426         property real maximumInputAlpha: rootItem.maximumInput.a
427         property variant minimumOutputRGB: Qt.vector3d(rootItem.minimumOutput.r, rootItem.minimumOutput.g, rootItem.minimumOutput.b)
428         property variant maximumOutputRGB: Qt.vector3d(rootItem.maximumOutput.r, rootItem.maximumOutput.g, rootItem.maximumOutput.b)
429         property real minimumOutputAlpha: rootItem.minimumOutput.a
430         property real maximumOutputAlpha: rootItem.maximumOutput.a
431         property variant gamma: Qt.vector3d(1.0 / Math.max(rootItem.gamma.x, 0.0001), 1.0 / Math.max(rootItem.gamma.y, 0.0001), 1.0 / Math.max(rootItem.gamma.z, 0.0001))
432         anchors.fill: parent
433
434         fragmentShader: "
435             varying highp vec2 qt_TexCoord0;
436             uniform highp float qt_Opacity;
437             uniform lowp sampler2D source;
438             uniform highp vec3 minimumInputRGB;
439             uniform highp vec3 maximumInputRGB;
440             uniform highp float minimumInputAlpha;
441             uniform highp float maximumInputAlpha;
442             uniform highp vec3 minimumOutputRGB;
443             uniform highp vec3 maximumOutputRGB;
444             uniform highp float minimumOutputAlpha;
445             uniform highp float maximumOutputAlpha;
446             uniform highp vec3 gamma;
447
448             highp float linearstep(highp float e0, highp float e1, highp float x) {
449                 return clamp((x - e0) / (e1 - e0), 0.0, 1.0);
450             }
451
452             void main(void) {
453                 highp vec4 textureColor = texture2D(source, qt_TexCoord0.st);
454                 highp vec4 color = vec4(textureColor.rgb / max(1.0/256.0, textureColor.a), textureColor.a);
455
456                 color.r = linearstep(minimumInputRGB.r, maximumInputRGB.r, color.r);
457                 color.g = linearstep(minimumInputRGB.g, maximumInputRGB.g, color.g);
458                 color.b = linearstep(minimumInputRGB.b, maximumInputRGB.b, color.b);
459                 color.a = linearstep(minimumInputAlpha, maximumInputAlpha, color.a);
460
461                 color.rgb = pow(color.rgb, gamma);
462
463                 color.r = minimumOutputRGB.r + color.r * (maximumOutputRGB.r - minimumOutputRGB.r);
464                 color.g = minimumOutputRGB.g + color.g * (maximumOutputRGB.g - minimumOutputRGB.g);
465                 color.b = minimumOutputRGB.b + color.b * (maximumOutputRGB.b - minimumOutputRGB.b);
466                 color.a = minimumOutputAlpha + color.a * (maximumOutputAlpha - minimumOutputAlpha);
467
468                 gl_FragColor = vec4(color.rgb * color.a, color.a) * qt_Opacity;
469             }
470         "
471     }
472 }