4 * An OpenGL based 'interactive canvas' library.
6 * Copyright (C) 2010-2012 Inclusive Design Research Centre, OCAD University.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22 * Joseph Scheuhammer <clown@alum.mit.edu>
26 * SECTION:clutter-brightness-contrast-effect
27 * @short_description: Increase/decrease brightness and/or contrast of actor.
28 * @see_also: #ClutterEffect, #ClutterOffscreenEffect
30 * #ClutterBrightnessContrastEffect is a sub-class of #ClutterEffect that
31 * changes the overall brightness of a #ClutterActor.
33 * #ClutterBrightnessContrastEffect is available since Clutter 1.10
36 #define CLUTTER_BRIGHTNESS_CONTRAST_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT, ClutterBrightnessContrastEffectClass))
37 #define CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT))
38 #define CLUTTER_BRIGHTNESS_CONTRAST_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT, ClutterBrightnessContrastEffectClass))
46 #define CLUTTER_ENABLE_EXPERIMENTAL_API
48 #include "clutter-brightness-contrast-effect.h"
50 #include <cogl/cogl.h>
52 #include "clutter-debug.h"
53 #include "clutter-enum-types.h"
54 #include "clutter-offscreen-effect.h"
55 #include "clutter-private.h"
57 struct _ClutterBrightnessContrastEffect
59 ClutterOffscreenEffect parent_instance;
61 /* Brightness and contrast changes. */
62 gfloat brightness_red;
63 gfloat brightness_green;
64 gfloat brightness_blue;
67 gfloat contrast_green;
70 gint brightness_multiplier_uniform;
71 gint brightness_offset_uniform;
72 gint contrast_uniform;
77 CoglPipeline *pipeline;
80 struct _ClutterBrightnessContrastEffectClass
82 ClutterOffscreenEffectClass parent_class;
84 CoglPipeline *base_pipeline;
87 /* Brightness effects in GLSL.
89 static const gchar *brightness_contrast_decls =
90 "uniform vec3 brightness_multiplier;\n"
91 "uniform vec3 brightness_offset;\n"
92 "uniform vec3 contrast;\n";
94 static const gchar *brightness_contrast_source =
95 /* Apply the brightness. The brightness_offset is multiplied by the
96 alpha to keep the color pre-multiplied */
97 "cogl_color_out.rgb = (cogl_color_out.rgb * brightness_multiplier +\n"
98 " brightness_offset * cogl_color_out.a);\n"
99 /* Apply the contrast */
100 "cogl_color_out.rgb = ((cogl_color_out.rgb - 0.5 * cogl_color_out.a) *\n"
101 " contrast + 0.5 * cogl_color_out.a);\n";
103 static const ClutterColor no_brightness_change = { 0x7f, 0x7f, 0x7f, 0xff };
104 static const ClutterColor no_contrast_change = { 0x7f, 0x7f, 0x7f, 0xff };
105 static const gfloat no_change = 0.0f;
117 static GParamSpec *obj_props[PROP_LAST];
119 G_DEFINE_TYPE (ClutterBrightnessContrastEffect,
120 clutter_brightness_contrast_effect,
121 CLUTTER_TYPE_OFFSCREEN_EFFECT);
124 clutter_brightness_contrast_effect_pre_paint (ClutterEffect *effect)
126 ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
127 ClutterEffectClass *parent_class;
129 if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
132 if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
134 /* if we don't have support for GLSL shaders then we
135 * forcibly disable the ActorMeta
137 g_warning ("Unable to use the ClutterBrightnessContrastEffect: the "
138 "graphics hardware or the current GL driver does not "
139 "implement support for the GLSL shading language. The "
140 "effect will be disabled.");
141 clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE);
146 CLUTTER_EFFECT_CLASS (clutter_brightness_contrast_effect_parent_class);
147 if (parent_class->pre_paint (effect))
149 ClutterOffscreenEffect *offscreen_effect =
150 CLUTTER_OFFSCREEN_EFFECT (effect);
153 texture = clutter_offscreen_effect_get_texture (offscreen_effect);
154 self->tex_width = cogl_texture_get_width (texture);
155 self->tex_height = cogl_texture_get_height (texture);
157 cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
166 clutter_brightness_contrast_effect_paint_target (ClutterOffscreenEffect *effect)
168 ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
170 guint8 paint_opacity;
172 actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
173 paint_opacity = clutter_actor_get_paint_opacity (actor);
175 cogl_pipeline_set_color4ub (self->pipeline,
180 cogl_push_source (self->pipeline);
182 cogl_rectangle (0, 0, self->tex_width, self->tex_height);
188 clutter_brightness_contrast_effect_dispose (GObject *gobject)
190 ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (gobject);
192 if (self->pipeline != NULL)
194 cogl_object_unref (self->pipeline);
195 self->pipeline = NULL;
198 G_OBJECT_CLASS (clutter_brightness_contrast_effect_parent_class)->dispose (gobject);
202 clutter_brightness_contrast_effect_set_property (GObject *gobject,
207 ClutterBrightnessContrastEffect *effect = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (gobject);
211 case PROP_BRIGHTNESS:
213 const ClutterColor *color = clutter_value_get_color (value);
214 clutter_brightness_contrast_effect_set_brightness_full (effect,
215 color->red / 127.0f - 1.0f,
216 color->green / 127.0f - 1.0f,
217 color->blue / 127.0f - 1.0f);
223 const ClutterColor *color = clutter_value_get_color (value);
224 clutter_brightness_contrast_effect_set_contrast_full (effect,
225 color->red / 127.0f - 1.0f,
226 color->green / 127.0f - 1.0f,
227 color->blue / 127.0f - 1.0f);
232 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
238 clutter_brightness_contrast_effect_get_property (GObject *gobject,
243 ClutterBrightnessContrastEffect *effect = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (gobject);
248 case PROP_BRIGHTNESS:
250 color.red = (effect->brightness_red + 1.0f) * 127.0f;
251 color.green = (effect->brightness_green + 1.0f) * 127.0f;
252 color.blue = (effect->brightness_blue + 1.0f) * 127.0f;
255 clutter_value_set_color (value, &color);
261 color.red = (effect->contrast_red + 1.0f) * 127.0f;
262 color.green = (effect->contrast_green + 1.0f) * 127.0f;
263 color.blue = (effect->contrast_blue + 1.0f) * 127.0f;
266 clutter_value_set_color (value, &color);
271 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
277 clutter_brightness_contrast_effect_class_init (ClutterBrightnessContrastEffectClass *klass)
279 ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
280 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
281 ClutterOffscreenEffectClass *offscreen_class;
283 offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
284 offscreen_class->paint_target = clutter_brightness_contrast_effect_paint_target;
286 effect_class->pre_paint = clutter_brightness_contrast_effect_pre_paint;
288 gobject_class->set_property = clutter_brightness_contrast_effect_set_property;
289 gobject_class->get_property = clutter_brightness_contrast_effect_get_property;
290 gobject_class->dispose = clutter_brightness_contrast_effect_dispose;
293 * ClutterBrightnessContrastEffect:brightness:
295 * The brightness change to apply to the effect.
297 * This property uses a #ClutterColor to represent the changes to each
298 * color channel. The range is [ 0, 255 ], with 127 as the value used
299 * to indicate no change; values smaller than 127 indicate a decrease
300 * in brightness, and values larger than 127 indicate an increase in
305 obj_props[PROP_BRIGHTNESS] =
306 clutter_param_spec_color ("brightness",
308 P_("The brightness change to apply"),
309 &no_brightness_change,
310 CLUTTER_PARAM_READWRITE);
313 * ClutterBrightnessContrastEffect:contrast:
315 * The contrast change to apply to the effect.
317 * This property uses a #ClutterColor to represent the changes to each
318 * color channel. The range is [ 0, 255 ], with 127 as the value used
319 * to indicate no change; values smaller than 127 indicate a decrease
320 * in contrast, and values larger than 127 indicate an increase in
325 obj_props[PROP_CONTRAST] =
326 clutter_param_spec_color ("contrast",
328 P_("The contrast change to apply"),
330 CLUTTER_PARAM_READWRITE);
332 g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
336 get_brightness_values (gfloat value,
342 *multiplier = 1.0f + value;
347 *multiplier = 1.0f - value;
353 update_uniforms (ClutterBrightnessContrastEffect *self)
355 if (self->brightness_multiplier_uniform > -1 &&
356 self->brightness_offset_uniform > -1)
358 float brightness_multiplier[3];
359 float brightness_offset[3];
361 get_brightness_values (self->brightness_red,
362 brightness_multiplier + 0,
363 brightness_offset + 0);
364 get_brightness_values (self->brightness_green,
365 brightness_multiplier + 1,
366 brightness_offset + 1);
367 get_brightness_values (self->brightness_blue,
368 brightness_multiplier + 2,
369 brightness_offset + 2);
371 cogl_pipeline_set_uniform_float (self->pipeline,
372 self->brightness_multiplier_uniform,
373 3, /* n_components */
375 brightness_multiplier);
376 cogl_pipeline_set_uniform_float (self->pipeline,
377 self->brightness_offset_uniform,
378 3, /* n_components */
383 if (self->contrast_uniform > -1)
385 float contrast[3] = {
386 tan ((self->contrast_red + 1) * G_PI_4),
387 tan ((self->contrast_green + 1) * G_PI_4),
388 tan ((self->contrast_blue + 1) * G_PI_4)
391 cogl_pipeline_set_uniform_float (self->pipeline,
392 self->contrast_uniform,
393 3, /* n_components */
400 clutter_brightness_contrast_effect_init (ClutterBrightnessContrastEffect *self)
402 ClutterBrightnessContrastEffectClass *klass;
404 self->brightness_red = no_change;
405 self->brightness_green = no_change;
406 self->brightness_blue = no_change;
408 self->contrast_red = no_change;
409 self->contrast_green = no_change;
410 self->contrast_blue = no_change;
412 klass = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT_GET_CLASS (self);
414 if (G_UNLIKELY (klass->base_pipeline == NULL))
416 CoglSnippet *snippet;
418 clutter_backend_get_cogl_context (clutter_get_default_backend ());
420 klass->base_pipeline = cogl_pipeline_new (ctx);
422 snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
423 brightness_contrast_decls,
424 brightness_contrast_source);
425 cogl_pipeline_add_snippet (klass->base_pipeline, snippet);
426 cogl_object_unref (snippet);
428 cogl_pipeline_set_layer_null_texture (klass->base_pipeline,
429 0, /* layer number */
430 COGL_TEXTURE_TYPE_2D);
433 self->pipeline = cogl_pipeline_copy (klass->base_pipeline);
435 self->brightness_multiplier_uniform =
436 cogl_pipeline_get_uniform_location (self->pipeline,
437 "brightness_multiplier");
438 self->brightness_offset_uniform =
439 cogl_pipeline_get_uniform_location (self->pipeline,
440 "brightness_offset");
441 self->contrast_uniform =
442 cogl_pipeline_get_uniform_location (self->pipeline, "contrast");
444 update_uniforms (self);
448 * clutter_brightness_contrast_effect_new:
450 * Creates a new #ClutterBrightnessContrastEffect to be used with
451 * clutter_actor_add_effect()
453 * Return value: (transfer full): the newly created
454 * #ClutterBrightnessContrastEffect or %NULL. Use g_object_unref() when
460 clutter_brightness_contrast_effect_new (void)
462 return g_object_new (CLUTTER_TYPE_BRIGHTNESS_CONTRAST_EFFECT, NULL);
466 * clutter_brightness_contrast_effect_set_brightness_full:
467 * @effect: a #ClutterBrightnessContrastEffect
468 * @red: red component of the change in brightness
469 * @green: green component of the change in brightness
470 * @blue: blue component of the change in brightness
472 * The range for each component is [-1.0, 1.0] where 0.0 designates no change,
473 * values below 0.0 mean a decrease in brightness, and values above indicate
479 clutter_brightness_contrast_effect_set_brightness_full (ClutterBrightnessContrastEffect *effect,
484 g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect));
486 if (red == effect->brightness_red &&
487 green == effect->brightness_green &&
488 blue == effect->brightness_blue)
491 effect->brightness_red = red;
492 effect->brightness_green = green;
493 effect->brightness_blue = blue;
495 update_uniforms (effect);
497 clutter_effect_queue_repaint (CLUTTER_EFFECT (effect));
499 g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_BRIGHTNESS]);
503 * clutter_brightness_contrast_effect_get_brightness:
504 * @effect: a #ClutterBrightnessContrastEffect
505 * @red: (out) (allow-none): return location for red component of the
506 * change in brightness
507 * @green: (out) (allow-none): return location for green component of the
508 * change in brightness
509 * @blue: (out) (allow-none): return location for blue component of the
510 * change in brightness
512 * Retrieves the change in brightness used by @effect.
517 clutter_brightness_contrast_effect_get_brightness (ClutterBrightnessContrastEffect *effect,
522 g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect));
525 *red = effect->brightness_red;
528 *green = effect->brightness_green;
531 *blue = effect->brightness_blue;
535 * clutter_brightness_contrast_effect_set_brightness:
536 * @effect: a #ClutterBrightnessContrastEffect
537 * @brightness: the brightness change for all three components (r, g, b)
539 * The range of @brightness is [-1.0, 1.0], where 0.0 designates no change;
540 * a value below 0.0 indicates a decrease in brightness; and a value
541 * above 0.0 indicates an increase of brightness.
546 clutter_brightness_contrast_effect_set_brightness (ClutterBrightnessContrastEffect *effect,
549 clutter_brightness_contrast_effect_set_brightness_full (effect,
556 * clutter_brightness_contrast_effect_set_contrast_full:
557 * @effect: a #ClutterBrightnessContrastEffect
558 * @red: red component of the change in contrast
559 * @green: green component of the change in contrast
560 * @blue: blue component of the change in contrast
562 * The range for each component is [-1.0, 1.0] where 0.0 designates no change,
563 * values below 0.0 mean a decrease in contrast, and values above indicate
569 clutter_brightness_contrast_effect_set_contrast_full (ClutterBrightnessContrastEffect *effect,
574 g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect));
576 if (red == effect->contrast_red &&
577 green == effect->contrast_green &&
578 blue == effect->contrast_blue)
581 effect->contrast_red = red;
582 effect->contrast_green = green;
583 effect->contrast_blue = blue;
585 update_uniforms (effect);
587 clutter_effect_queue_repaint (CLUTTER_EFFECT (effect));
589 g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_CONTRAST]);
593 * clutter_brightness_contrast_effect_get_contrast:
594 * @effect: a #ClutterBrightnessContrastEffect
595 * @red: (out) (allow-none): return location for red component of the
597 * @green: (out) (allow-none): return location for green component of the
599 * @blue: (out) (allow-none): return location for blue component of the
602 * Retrieves the contrast value used by @effect.
607 clutter_brightness_contrast_effect_get_contrast (ClutterBrightnessContrastEffect *effect,
612 g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect));
615 *red = effect->contrast_red;
618 *green = effect->contrast_green;
621 *blue = effect->contrast_blue;
625 * clutter_brightness_contrast_effect_set_contrast:
626 * @effect: a #ClutterBrightnessContrastEffect
627 * @contrast: contrast change for all three channels
629 * The range for @contrast is [-1.0, 1.0], where 0.0 designates no change;
630 * a value below 0.0 indicates a decrease in contrast; and a value above
631 * 0.0 indicates an increase.
636 clutter_brightness_contrast_effect_set_contrast (ClutterBrightnessContrastEffect *effect,
639 clutter_brightness_contrast_effect_set_contrast_full (effect,