4 * An OpenGL based 'interactive canvas' library.
6 * Copyright (C) 2010 Intel Corporation.
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 * Emmanuele Bassi <ebassi@linux.intel.com>
26 * SECTION:clutter-desaturate-effect
27 * @short_description: A desaturation effect
28 * @see_also: #ClutterEffect, #ClutterOffscreenEffect
30 * #ClutterDesaturateEffect is a sub-class of #ClutterEffect that
31 * desaturates the color of an actor and its contents. The strenght
32 * of the desaturation effect is controllable and animatable through
33 * the #ClutterDesaturateEffect:factor property.
35 * #ClutterDesaturateEffect is available since Clutter 1.4
38 #define CLUTTER_DESATURATE_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DESATURATE_EFFECT, ClutterDesaturateEffectClass))
39 #define CLUTTER_IS_DESATURATE_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DESATURATE_EFFECT))
40 #define CLUTTER_DESATURATE_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DESATURATE_EFFECT, ClutterDesaturateEffectClass))
46 #define CLUTTER_ENABLE_EXPERIMENTAL_API
50 #include "clutter-desaturate-effect.h"
52 #include "cogl/cogl.h"
54 #include "clutter-debug.h"
55 #include "clutter-enum-types.h"
56 #include "clutter-offscreen-effect.h"
57 #include "clutter-private.h"
59 struct _ClutterDesaturateEffect
61 ClutterOffscreenEffect parent_instance;
63 /* the desaturation factor, also known as "strength" */
71 CoglPipeline *pipeline;
74 struct _ClutterDesaturateEffectClass
76 ClutterOffscreenEffectClass parent_class;
78 CoglPipeline *base_pipeline;
81 /* the magic gray vec3 has been taken from the NTSC conversion weights
84 * "OpenGL Superbible, 4th edition"
85 * -- Richard S. Wright Jr, Benjamin Lipchak, Nicholas Haemel
88 static const gchar *desaturate_glsl_declarations =
89 "uniform float factor;\n"
91 "vec3 desaturate (const vec3 color, const float desaturation)\n"
93 " const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n"
94 " vec3 gray = vec3 (dot (gray_conv, color));\n"
95 " return vec3 (mix (color.rgb, gray, desaturation));\n"
98 static const gchar *desaturate_glsl_source =
99 " cogl_color_out.rgb = desaturate (cogl_color_out.rgb, factor);\n";
110 static GParamSpec *obj_props[PROP_LAST];
112 G_DEFINE_TYPE (ClutterDesaturateEffect,
113 clutter_desaturate_effect,
114 CLUTTER_TYPE_OFFSCREEN_EFFECT);
117 clutter_desaturate_effect_pre_paint (ClutterEffect *effect)
119 ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect);
120 ClutterEffectClass *parent_class;
122 if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
125 if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
127 /* if we don't have support for GLSL shaders then we
128 * forcibly disable the ActorMeta
130 g_warning ("Unable to use the ShaderEffect: the graphics hardware "
131 "or the current GL driver does not implement support "
132 "for the GLSL shading language.");
133 clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE);
137 parent_class = CLUTTER_EFFECT_CLASS (clutter_desaturate_effect_parent_class);
138 if (parent_class->pre_paint (effect))
140 ClutterOffscreenEffect *offscreen_effect =
141 CLUTTER_OFFSCREEN_EFFECT (effect);
144 texture = clutter_offscreen_effect_get_texture (offscreen_effect);
145 self->tex_width = cogl_texture_get_width (texture);
146 self->tex_height = cogl_texture_get_height (texture);
148 cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
157 clutter_desaturate_effect_paint_target (ClutterOffscreenEffect *effect)
159 ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect);
162 guint8 paint_opacity;
164 texture = clutter_offscreen_effect_get_texture (effect);
165 cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
167 actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
168 paint_opacity = clutter_actor_get_paint_opacity (actor);
170 cogl_pipeline_set_color4ub (self->pipeline,
175 cogl_push_source (self->pipeline);
177 cogl_rectangle (0, 0,
178 cogl_texture_get_width (texture),
179 cogl_texture_get_height (texture));
185 clutter_desaturate_effect_dispose (GObject *gobject)
187 ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (gobject);
189 if (self->pipeline != NULL)
191 cogl_object_unref (self->pipeline);
192 self->pipeline = NULL;
195 G_OBJECT_CLASS (clutter_desaturate_effect_parent_class)->dispose (gobject);
199 clutter_desaturate_effect_set_property (GObject *gobject,
204 ClutterDesaturateEffect *effect = CLUTTER_DESATURATE_EFFECT (gobject);
209 clutter_desaturate_effect_set_factor (effect,
210 g_value_get_double (value));
214 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
220 clutter_desaturate_effect_get_property (GObject *gobject,
225 ClutterDesaturateEffect *effect = CLUTTER_DESATURATE_EFFECT (gobject);
230 g_value_set_double (value, effect->factor);
234 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
240 update_factor_uniform (ClutterDesaturateEffect *self)
242 if (self->factor_uniform > -1)
243 cogl_pipeline_set_uniform_1f (self->pipeline,
244 self->factor_uniform,
249 clutter_desaturate_effect_class_init (ClutterDesaturateEffectClass *klass)
251 ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
252 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
253 ClutterOffscreenEffectClass *offscreen_class;
255 offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
256 offscreen_class->paint_target = clutter_desaturate_effect_paint_target;
258 effect_class->pre_paint = clutter_desaturate_effect_pre_paint;
261 * ClutterDesaturateEffect:factor:
263 * The desaturation factor, between 0.0 (no desaturation) and 1.0 (full
268 obj_props[PROP_FACTOR] =
269 g_param_spec_double ("factor",
271 P_("The desaturation factor"),
274 CLUTTER_PARAM_READWRITE);
276 gobject_class->dispose = clutter_desaturate_effect_dispose;
277 gobject_class->set_property = clutter_desaturate_effect_set_property;
278 gobject_class->get_property = clutter_desaturate_effect_get_property;
280 g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
284 clutter_desaturate_effect_init (ClutterDesaturateEffect *self)
286 ClutterDesaturateEffectClass *klass = CLUTTER_DESATURATE_EFFECT_GET_CLASS (self);
288 if (G_UNLIKELY (klass->base_pipeline == NULL))
291 clutter_backend_get_cogl_context (clutter_get_default_backend ());
292 CoglSnippet *snippet;
294 klass->base_pipeline = cogl_pipeline_new (ctx);
296 snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
297 desaturate_glsl_declarations,
298 desaturate_glsl_source);
299 cogl_pipeline_add_snippet (klass->base_pipeline, snippet);
300 cogl_object_unref (snippet);
302 cogl_pipeline_set_layer_null_texture (klass->base_pipeline,
303 0, /* layer number */
304 COGL_TEXTURE_TYPE_2D);
307 self->pipeline = cogl_pipeline_copy (klass->base_pipeline);
309 self->factor_uniform =
310 cogl_pipeline_get_uniform_location (self->pipeline, "factor");
314 update_factor_uniform (self);
318 * clutter_desaturate_effect_new:
319 * @factor: the desaturation factor, between 0.0 and 1.0
321 * Creates a new #ClutterDesaturateEffect to be used with
322 * clutter_actor_add_effect()
324 * Return value: the newly created #ClutterDesaturateEffect or %NULL
329 clutter_desaturate_effect_new (gdouble factor)
331 g_return_val_if_fail (factor >= 0.0 && factor <= 1.0, NULL);
333 return g_object_new (CLUTTER_TYPE_DESATURATE_EFFECT,
339 * clutter_desaturate_effect_set_factor:
340 * @effect: a #ClutterDesaturateEffect
341 * @factor: the desaturation factor, between 0.0 and 1.0
343 * Sets the desaturation factor for @effect, with 0.0 being "do not desaturate"
344 * and 1.0 being "fully desaturate"
349 clutter_desaturate_effect_set_factor (ClutterDesaturateEffect *effect,
352 g_return_if_fail (CLUTTER_IS_DESATURATE_EFFECT (effect));
353 g_return_if_fail (factor >= 0.0 && factor <= 1.0);
355 if (fabsf (effect->factor - factor) >= 0.00001)
357 effect->factor = factor;
358 update_factor_uniform (effect);
360 clutter_effect_queue_repaint (CLUTTER_EFFECT (effect));
362 g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_FACTOR]);
367 * clutter_desaturate_effect_get_factor:
368 * @effect: a #ClutterDesaturateEffect
370 * Retrieves the desaturation factor of @effect
372 * Return value: the desaturation factor
377 clutter_desaturate_effect_get_factor (ClutterDesaturateEffect *effect)
379 g_return_val_if_fail (CLUTTER_IS_DESATURATE_EFFECT (effect), 0.0);
381 return effect->factor;