From ed39948ccf776b50fba9c3c7934ddb727091db11 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Aug 2010 17:43:15 +0100 Subject: [PATCH] colorize-effect: Do not inherit from ShaderEffect See commits: 7daeb217 blur-effect: Do not inherit from ShaderEffect 1ec57743 desaturate-effect: Do not inherit from ShaderEffect We might avoid using shaders at all in the future for simple effects. --- clutter/clutter-colorize-effect.c | 156 ++++++++++++++++++++++++++++++-------- 1 file changed, 126 insertions(+), 30 deletions(-) diff --git a/clutter/clutter-colorize-effect.c b/clutter/clutter-colorize-effect.c index 3ba2980..7168a67 100644 --- a/clutter/clutter-colorize-effect.c +++ b/clutter/clutter-colorize-effect.c @@ -30,10 +30,6 @@ * #ClutterColorizeEffect is a sub-class of #ClutterEffect that * colorizes an actor with the given tint. * - * #ClutterColorizeEffect uses the programmable pipeline of the GPU - * so it is only available on graphics hardware that supports this - * feature. - * * #ClutterColorizeEffect is available since Clutter 1.4 */ @@ -51,25 +47,33 @@ #include "clutter-debug.h" #include "clutter-enum-types.h" +#include "clutter-offscreen-effect.h" #include "clutter-private.h" -#include "clutter-shader-effect.h" typedef struct _ClutterColorizeEffectClass ClutterColorizeEffectClass; struct _ClutterColorizeEffect { - ClutterShaderEffect parent_instance; + ClutterOffscreenEffect parent_instance; /* a back pointer to our actor, so that we can query it */ ClutterActor *actor; /* the tint of the colorization */ ClutterColor tint; + + CoglHandle shader; + CoglHandle program; + + gint tex_uniform; + gint tint_uniform; + + guint is_compiled : 1; }; struct _ClutterColorizeEffectClass { - ClutterShaderEffectClass parent_class; + ClutterOffscreenEffectClass parent_class; }; /* the magic gray vec3 has been taken from the NTSC conversion weights @@ -106,48 +110,136 @@ static GParamSpec *obj_props[PROP_LAST]; G_DEFINE_TYPE (ClutterColorizeEffect, clutter_colorize_effect, - CLUTTER_TYPE_SHADER_EFFECT); + CLUTTER_TYPE_OFFSCREEN_EFFECT); static gboolean clutter_colorize_effect_pre_paint (ClutterEffect *effect) { ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect); - ClutterShaderEffect *shader_effect; ClutterEffectClass *parent_class; - float tint_r, tint_g, tint_b; if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) return FALSE; - shader_effect = CLUTTER_SHADER_EFFECT (effect); + self->actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect)); + if (self->actor == NULL) + return FALSE; - clutter_shader_effect_set_shader_source (shader_effect, colorize_glsl_shader); + if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) + { + /* if we don't have support for GLSL shaders then we + * forcibly disable the ActorMeta + */ + g_warning ("Unable to use the ShaderEffect: the graphics hardware " + "or the current GL driver does not implement support " + "for the GLSL shading language."); + clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE); + return FALSE; + } - /* we want normalized values here */ - tint_r = self->tint.red / 255.0f; - tint_g = self->tint.green / 255.0f; - tint_b = self->tint.blue / 255.0f; + if (self->shader == COGL_INVALID_HANDLE) + { + self->shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); + cogl_shader_source (self->shader, colorize_glsl_shader); - /* 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, - "tint", - G_TYPE_FLOAT, 3, - tint_r, - tint_g, - tint_b); + self->is_compiled = FALSE; + self->tex_uniform = -1; + self->tint_uniform = -1; + } + + if (self->program == COGL_INVALID_HANDLE) + self->program = cogl_create_program (); + + if (!self->is_compiled) + { + g_assert (self->shader != COGL_INVALID_HANDLE); + g_assert (self->program != COGL_INVALID_HANDLE); + + cogl_shader_compile (self->shader); + if (!cogl_shader_is_compiled (self->shader)) + { + gchar *log_buf = cogl_shader_get_info_log (self->shader); + + g_warning (G_STRLOC ": Unable to compile the colorize shader: %s", + log_buf); + g_free (log_buf); + + cogl_handle_unref (self->shader); + cogl_handle_unref (self->program); + + self->shader = COGL_INVALID_HANDLE; + self->program = COGL_INVALID_HANDLE; + } + else + { + cogl_program_attach_shader (self->program, self->shader); + cogl_program_link (self->program); + + cogl_handle_unref (self->shader); + + self->is_compiled = TRUE; + + self->tex_uniform = + cogl_program_get_uniform_location (self->program, "tex"); + self->tint_uniform = + cogl_program_get_uniform_location (self->program, "tint"); + } + } parent_class = CLUTTER_EFFECT_CLASS (clutter_colorize_effect_parent_class); return parent_class->pre_paint (effect); } static void -clutter_colorize_effect_finalize (GObject *gobject) +clutter_colorize_effect_paint_target (ClutterOffscreenEffect *effect) +{ + ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect); + ClutterOffscreenEffectClass *parent; + CoglHandle material; + + if (self->program == COGL_INVALID_HANDLE) + goto out; + + cogl_program_use (self->program); + + if (self->tex_uniform > -1) + cogl_program_uniform_1i (self->tex_uniform, 0); + + if (self->tint_uniform > -1) + { + float tint[3] = { + self->tint.red / 255.0, + self->tint.green / 255.0, + self->tint.blue / 255.0 + }; + + cogl_program_uniform_float (self->tint_uniform, 3, 1, tint); + } + + cogl_program_use (COGL_INVALID_HANDLE); + + material = clutter_offscreen_effect_get_target (effect); + cogl_material_set_user_program (material, self->program); + +out: + parent = CLUTTER_OFFSCREEN_EFFECT_CLASS (clutter_colorize_effect_parent_class); + parent->paint_target (effect); +} + +static void +clutter_colorize_effect_dispose (GObject *gobject) { - G_OBJECT_CLASS (clutter_colorize_effect_parent_class)->finalize (gobject); + ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (gobject); + + if (self->program != COGL_INVALID_HANDLE) + { + cogl_handle_unref (self->program); + + self->program = COGL_INVALID_HANDLE; + self->shader = COGL_INVALID_HANDLE; + } + + G_OBJECT_CLASS (clutter_colorize_effect_parent_class)->dispose (gobject); } static void @@ -196,13 +288,17 @@ clutter_colorize_effect_class_init (ClutterColorizeEffectClass *klass) { ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterOffscreenEffectClass *offscreen_class; GParamSpec *pspec; + offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); + offscreen_class->paint_target = clutter_colorize_effect_paint_target; + effect_class->pre_paint = clutter_colorize_effect_pre_paint; gobject_class->set_property = clutter_colorize_effect_set_property; gobject_class->get_property = clutter_colorize_effect_get_property; - gobject_class->finalize = clutter_colorize_effect_finalize; + gobject_class->dispose = clutter_colorize_effect_dispose; /** * ClutterColorizeEffect:tint: -- 2.7.4