From 73a773d37ab3c2ba6772acf6347a82d75a601901 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 9 Apr 2010 16:14:21 +0100 Subject: [PATCH] effect: Add DesaturateEffect A simple shader-based effect that desaturates an actor and its contents based on a controllable factor. --- clutter/Makefile.am | 2 + clutter/clutter-desaturate-effect.c | 309 ++++++++++++++++++++++++++++ clutter/clutter-desaturate-effect.h | 60 ++++++ clutter/clutter.h | 1 + tests/interactive/test-rotate.c | 2 +- 5 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 clutter/clutter-desaturate-effect.c create mode 100644 clutter/clutter-desaturate-effect.h diff --git a/clutter/Makefile.am b/clutter/Makefile.am index fa82005ad..718de5568 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -95,6 +95,7 @@ source_h = \ $(srcdir)/clutter-constraint.h \ $(srcdir)/clutter-container.h \ $(srcdir)/clutter-deprecated.h \ + $(srcdir)/clutter-desaturate-effect.h \ $(srcdir)/clutter-device-manager.h \ $(srcdir)/clutter-drag-action.h \ $(srcdir)/clutter-effect.h \ @@ -180,6 +181,7 @@ source_c = \ $(srcdir)/clutter-color.c \ $(srcdir)/clutter-constraint.c \ $(srcdir)/clutter-container.c \ + $(srcdir)/clutter-desaturate-effect.c \ $(srcdir)/clutter-device-manager.c \ $(srcdir)/clutter-drag-action.c \ $(srcdir)/clutter-effect.c \ diff --git a/clutter/clutter-desaturate-effect.c b/clutter/clutter-desaturate-effect.c new file mode 100644 index 000000000..1a81e370d --- /dev/null +++ b/clutter/clutter-desaturate-effect.c @@ -0,0 +1,309 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +/** + * SECTION:clutter-desaturate-effect + * @short_description: A desaturation effect + * @see_also: #ClutterEffect, #ClutterOffscreenEffect + * + * #ClutterDesaturateEffect is a sub-class of #ClutterEffect that + * desaturates the color of an actor and its contents. The strenght + * of the desaturation effect is controllable and animatable through + * the #ClutterDesaturateEffect:factor property. + * + * #ClutterDesaturateEffect uses the programmable pipeline of the GPU + * so it is only available on graphics hardware that supports this + * feature. + * + * #ClutterDesaturateEffect is available since Clutter 1.4 + */ + +#define CLUTTER_DESATURATE_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DESATURATE_EFFECT, ClutterDesaturateEffectClass)) +#define CLUTTER_IS_DESATURATE_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DESATURATE_EFFECT)) +#define CLUTTER_DESATURATE_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DESATURATE_EFFECT, ClutterDesaturateEffectClass)) + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-desaturate-effect.h" + +#include "cogl/cogl.h" + +#include "clutter-debug.h" +#include "clutter-enum-types.h" +#include "clutter-private.h" +#include "clutter-shader-effect.h" + +typedef struct _ClutterDesaturateEffectClass ClutterDesaturateEffectClass; + +struct _ClutterDesaturateEffect +{ + ClutterShaderEffect parent_instance; + + /* a back pointer to our actor, so that we can query it */ + ClutterActor *actor; + + /* the desaturation factor, also known as "strength" */ + gdouble factor; + + guint source_set : 1; +}; + +struct _ClutterDesaturateEffectClass +{ + ClutterShaderEffectClass parent_class; +}; + +/* the magic gray vec3 has been taken from the NTSC conversion weights + * as defined by: + * + * "OpenGL Superbible, 4th edition" + * -- Richard S. Wright Jr, Benjamin Lipchak, Nicholas Haemel + * Addison-Wesley + */ +static const gchar *desaturate_glsl_shader = +"uniform sampler2D tex;\n" +"uniform float factor;\n" +"\n" +"vec3 desaturate (const vec3 color, const float desaturation)\n" +"{\n" +" const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n" +" vec3 gray = vec3 (dot (gray_conv, color));\n" +" return vec3 (mix (color.rgb, gray, desaturation));\n" +"}\n" +"\n" +"void main ()\n" +"{\n" +" vec4 color = gl_Color * texture2D (tex, vec2 (gl_TexCoord[0].xy));\n" +" color.rgb = desaturate (color.rgb, factor);\n" +" gl_FragColor = color;\n" +"}\n"; + +enum +{ + PROP_0, + + PROP_FACTOR +}; + +G_DEFINE_TYPE (ClutterDesaturateEffect, + clutter_desaturate_effect, + CLUTTER_TYPE_SHADER_EFFECT); + +static gboolean +clutter_desaturate_effect_pre_paint (ClutterEffect *effect) +{ + ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect); + ClutterShaderEffect *shader_effect; + ClutterEffectClass *parent_class; + float factor; + + if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) + return FALSE; + + self->actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); + if (self->actor == NULL) + return FALSE; + + shader_effect = CLUTTER_SHADER_EFFECT (effect); + + if (!self->source_set) + { + CoglHandle shader; + + /* get the CoglShader handle to set the source */ + shader = clutter_shader_effect_get_shader (shader_effect); + if (shader == COGL_INVALID_HANDLE) + return FALSE; + + cogl_shader_source (shader, desaturate_glsl_shader); + self->source_set = TRUE; + } + + factor = (float) self->factor; + + /* bind the uniforms to the factor property */ + clutter_shader_effect_set_uniform (shader_effect, + "tex", + G_TYPE_INT, 1, + 0); + clutter_shader_effect_set_uniform (shader_effect, + "factor", + G_TYPE_FLOAT, 1, + factor); + + parent_class = CLUTTER_EFFECT_CLASS (clutter_desaturate_effect_parent_class); + return parent_class->pre_paint (effect); +} + +static void +clutter_desaturate_effect_finalize (GObject *gobject) +{ + G_OBJECT_CLASS (clutter_desaturate_effect_parent_class)->finalize (gobject); +} + +static void +clutter_desaturate_effect_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ClutterDesaturateEffect *effect = CLUTTER_DESATURATE_EFFECT (gobject); + + switch (prop_id) + { + case PROP_FACTOR: + clutter_desaturate_effect_set_factor (effect, + g_value_get_double (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_desaturate_effect_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ClutterDesaturateEffect *effect = CLUTTER_DESATURATE_EFFECT (gobject); + + switch (prop_id) + { + case PROP_FACTOR: + g_value_set_double (value, effect->factor); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_desaturate_effect_class_init (ClutterDesaturateEffectClass *klass) +{ + ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + effect_class->pre_paint = clutter_desaturate_effect_pre_paint; + + gobject_class->set_property = clutter_desaturate_effect_set_property; + gobject_class->get_property = clutter_desaturate_effect_get_property; + gobject_class->finalize = clutter_desaturate_effect_finalize; + + /** + * ClutterDesaturateEffect:factor: + * + * The desaturation factor, between 0.0 (no desaturation) and 1.0 (full + * desaturation). + * + * Since: 1.4 + */ + pspec = g_param_spec_double ("factor", + "Factor", + "The desaturation factor", + 0.0, 1.0, + 1.0, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_FACTOR, pspec); +} + +static void +clutter_desaturate_effect_init (ClutterDesaturateEffect *self) +{ + self->factor = 1.0; +} + +/** + * clutter_desaturate_effect_new: + * @factor: the desaturation factor, between 0.0 and 1.0 + * + * Creates a new #ClutterDesaturateEffect to be used with + * clutter_actor_set_effect() + * + * Return value: the newly created #ClutterDesaturateEffect or %NULL + * + * Since: 1.4 + */ +ClutterEffect * +clutter_desaturate_effect_new (gdouble factor) +{ + g_return_val_if_fail (factor >= 0.0 && factor <= 1.0, NULL); + + return g_object_new (CLUTTER_TYPE_DESATURATE_EFFECT, + "factor", factor, + NULL); +} + +/** + * clutter_desaturate_effect_set_factor: + * @effect: a #ClutterDesaturateEffect + * @factor: the desaturation factor, between 0.0 and 1.0 + * + * Sets the desaturation factor for @effect, with 0.0 being "do not desaturate" + * and 1.0 being "fully desaturate" + * + * Since: 1.4 + */ +void +clutter_desaturate_effect_set_factor (ClutterDesaturateEffect *effect, + gdouble factor) +{ + g_return_if_fail (CLUTTER_IS_DESATURATE_EFFECT (effect)); + g_return_if_fail (factor >= 0.0 && factor <= 1.0); + + if (fabsf (effect->factor - factor) >= 0.00001) + { + effect->factor = factor; + + if (effect->actor != NULL) + clutter_actor_queue_redraw (effect->actor); + + g_object_notify (G_OBJECT (effect), "factor"); + } +} + +/** + * clutter_desaturate_effect_get_factor: + * @effect: a #ClutterDesaturateEffect + * + * Retrieves the desaturation factor of @effect + * + * Return value: the desaturation factor + * + * Since: 1.4 + */ +gdouble +clutter_desaturate_effect_get_factor (ClutterDesaturateEffect *effect) +{ + g_return_val_if_fail (CLUTTER_IS_DESATURATE_EFFECT (effect), 0.0); + + return effect->factor; +} diff --git a/clutter/clutter-desaturate-effect.h b/clutter/clutter-desaturate-effect.h new file mode 100644 index 000000000..7c51a5715 --- /dev/null +++ b/clutter/clutter-desaturate-effect.h @@ -0,0 +1,60 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: + * Emmanuele Bassi + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_DESATURATE_EFFECT_H__ +#define __CLUTTER_DESATURATE_EFFECT_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_DESATURATE_EFFECT (clutter_desaturate_effect_get_type ()) +#define CLUTTER_DESATURATE_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DESATURATE_EFFECT, ClutterDesaturateEffect)) +#define CLUTTER_IS_DESATURATE_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DESATURATE_EFFECT)) + +/** + * ClutterDesaturateEffect: + * + * ClutterDesaturateEffect is an opaque structure + * whose members cannot be directly accessed + * + * Since: 1.4 + */ +typedef struct _ClutterDesaturateEffect ClutterDesaturateEffect; + +GType clutter_desaturate_effect_get_type (void) G_GNUC_CONST; + +ClutterEffect *clutter_desaturate_effect_new (gdouble factor); + +void clutter_desaturate_effect_set_factor (ClutterDesaturateEffect *effect, + gdouble factor); +gdouble clutter_desaturate_effect_get_factor (ClutterDesaturateEffect *effect); + +G_END_DECLS + +#endif /* __CLUTTER_DESATURATE_EFFECT_H__ */ diff --git a/clutter/clutter.h b/clutter/clutter.h index 1cdf0628d..e6a8da6c5 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -59,6 +59,7 @@ #include "clutter-color.h" #include "clutter-constraint.h" #include "clutter-container.h" +#include "clutter-desaturate-effect.h" #include "clutter-device-manager.h" #include "clutter-drag-action.h" #include "clutter-effect.h" diff --git a/tests/interactive/test-rotate.c b/tests/interactive/test-rotate.c index 2001090f5..60f85df96 100644 --- a/tests/interactive/test-rotate.c +++ b/tests/interactive/test-rotate.c @@ -35,7 +35,7 @@ test_rotate_main (int argc, char *argv[]) clutter_actor_set_position (hand, 240, 140); clutter_actor_show (hand); - clutter_container_add_actor (CLUTTER_CONTAINER (stage), hand); + clutter_actor_add_effect (hand, clutter_desaturate_effect_new (0.75)); label = clutter_text_new_with_text ("Mono 16", "The Wonder\n"