meta-background-actor: Add gradient effect

Add a gradient effect that goes from the top to the bottom. The
height and the initial dark tone of the gradient are customizable.

https://bugzilla.gnome.org/show_bug.cgi?id=786618
This commit is contained in:
Alessandro Bono 2017-08-20 13:34:54 +02:00
parent cbc4563b30
commit 068791f6c1
2 changed files with 194 additions and 2 deletions

View File

@ -88,6 +88,9 @@ enum
PROP_META_SCREEN = 1, PROP_META_SCREEN = 1,
PROP_MONITOR, PROP_MONITOR,
PROP_BACKGROUND, PROP_BACKGROUND,
PROP_GRADIENT,
PROP_GRADIENT_HEIGHT,
PROP_GRADIENT_MAX_DARKNESS,
PROP_VIGNETTE, PROP_VIGNETTE,
PROP_VIGNETTE_SHARPNESS, PROP_VIGNETTE_SHARPNESS,
PROP_VIGNETTE_BRIGHTNESS PROP_VIGNETTE_BRIGHTNESS
@ -97,9 +100,28 @@ typedef enum {
CHANGED_BACKGROUND = 1 << 0, CHANGED_BACKGROUND = 1 << 0,
CHANGED_EFFECTS = 1 << 2, CHANGED_EFFECTS = 1 << 2,
CHANGED_VIGNETTE_PARAMETERS = 1 << 3, CHANGED_VIGNETTE_PARAMETERS = 1 << 3,
CHANGED_GRADIENT_PARAMETERS = 1 << 4,
CHANGED_ALL = 0xFFFF CHANGED_ALL = 0xFFFF
} ChangedFlags; } ChangedFlags;
#define GRADIENT_VERTEX_SHADER_DECLARATIONS \
"uniform vec2 scale;\n" \
"varying vec2 position;\n" \
#define GRADIENT_VERTEX_SHADER_CODE \
"position = cogl_tex_coord0_in.xy * scale;\n" \
#define GRADIENT_FRAGMENT_SHADER_DECLARATIONS \
"uniform float gradient_height_perc;\n" \
"uniform float gradient_max_darkness;\n" \
"varying vec2 position;\n" \
#define GRADIENT_FRAGMENT_SHADER_CODE \
"float min_brightness = 1.0 - gradient_max_darkness;\n" \
"float gradient_y_pos = min(position.y, gradient_height_perc) / gradient_height_perc;\n" \
"float pixel_brightness = (1.0 - min_brightness) * gradient_y_pos + min_brightness;\n" \
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
#define VIGNETTE_VERTEX_SHADER_DECLARATIONS \ #define VIGNETTE_VERTEX_SHADER_DECLARATIONS \
"uniform vec2 scale;\n" \ "uniform vec2 scale;\n" \
"uniform vec2 offset;\n" \ "uniform vec2 offset;\n" \
@ -123,6 +145,7 @@ typedef struct _MetaBackgroundLayer MetaBackgroundLayer;
typedef enum { typedef enum {
PIPELINE_VIGNETTE = (1 << 0), PIPELINE_VIGNETTE = (1 << 0),
PIPELINE_BLEND = (1 << 1), PIPELINE_BLEND = (1 << 1),
PIPELINE_GRADIENT = (1 << 2),
} PipelineFlags; } PipelineFlags;
struct _MetaBackgroundActorPrivate struct _MetaBackgroundActorPrivate
@ -132,6 +155,10 @@ struct _MetaBackgroundActorPrivate
MetaBackground *background; MetaBackground *background;
gboolean gradient;
double gradient_max_darkness;
int gradient_height;
gboolean vignette; gboolean vignette;
double vignette_brightness; double vignette_brightness;
double vignette_sharpness; double vignette_sharpness;
@ -231,7 +258,7 @@ meta_background_actor_get_preferred_height (ClutterActor *actor,
static CoglPipeline * static CoglPipeline *
make_pipeline (PipelineFlags pipeline_flags) make_pipeline (PipelineFlags pipeline_flags)
{ {
static CoglPipeline *templates[4]; static CoglPipeline *templates[8];
CoglPipeline **templatep; CoglPipeline **templatep;
templatep = &templates[pipeline_flags]; templatep = &templates[pipeline_flags];
@ -263,6 +290,26 @@ make_pipeline (PipelineFlags pipeline_flags)
cogl_pipeline_add_snippet (*templatep, vignette_fragment_snippet); cogl_pipeline_add_snippet (*templatep, vignette_fragment_snippet);
} }
if ((pipeline_flags & PIPELINE_GRADIENT) != 0)
{
static CoglSnippet *gradient_vertex_snippet;
static CoglSnippet *gradient_fragment_snippet;
if (!gradient_vertex_snippet)
gradient_vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
GRADIENT_VERTEX_SHADER_DECLARATIONS,
GRADIENT_VERTEX_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, gradient_vertex_snippet);
if (!gradient_fragment_snippet)
gradient_fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
GRADIENT_FRAGMENT_SHADER_DECLARATIONS,
GRADIENT_FRAGMENT_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, gradient_fragment_snippet);
}
if ((pipeline_flags & PIPELINE_BLEND) == 0) if ((pipeline_flags & PIPELINE_BLEND) == 0)
cogl_pipeline_set_blend (*templatep, "RGBA = ADD (SRC_COLOR, 0)", NULL); cogl_pipeline_set_blend (*templatep, "RGBA = ADD (SRC_COLOR, 0)", NULL);
} }
@ -285,6 +332,8 @@ setup_pipeline (MetaBackgroundActor *self,
pipeline_flags |= PIPELINE_BLEND; pipeline_flags |= PIPELINE_BLEND;
if (priv->vignette && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) if (priv->vignette && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
pipeline_flags |= PIPELINE_VIGNETTE; pipeline_flags |= PIPELINE_VIGNETTE;
if (priv->gradient && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
pipeline_flags |= PIPELINE_GRADIENT;
if (priv->pipeline && if (priv->pipeline &&
pipeline_flags != priv->pipeline_flags) pipeline_flags != priv->pipeline_flags)
@ -327,6 +376,25 @@ setup_pipeline (MetaBackgroundActor *self,
priv->changed &= ~CHANGED_VIGNETTE_PARAMETERS; priv->changed &= ~CHANGED_VIGNETTE_PARAMETERS;
} }
if ((priv->changed & CHANGED_GRADIENT_PARAMETERS) != 0)
{
MetaRectangle monitor_geometry;
float gradient_height_perc;
meta_screen_get_monitor_geometry (priv->screen, priv->monitor, &monitor_geometry);
gradient_height_perc = MAX (0.0001, priv->gradient_height / (float)monitor_geometry.height);
cogl_pipeline_set_uniform_1f (priv->pipeline,
cogl_pipeline_get_uniform_location (priv->pipeline,
"gradient_height_perc"),
gradient_height_perc);
cogl_pipeline_set_uniform_1f (priv->pipeline,
cogl_pipeline_get_uniform_location (priv->pipeline,
"gradient_max_darkness"),
priv->gradient_max_darkness);
priv->changed &= ~CHANGED_GRADIENT_PARAMETERS;
}
if (priv->vignette) if (priv->vignette)
{ {
color_component = priv->vignette_brightness * opacity / 255.; color_component = priv->vignette_brightness * opacity / 255.;
@ -484,11 +552,29 @@ meta_background_actor_set_property (GObject *object,
priv->screen = g_value_get_object (value); priv->screen = g_value_get_object (value);
break; break;
case PROP_MONITOR: case PROP_MONITOR:
priv->monitor = g_value_get_int (value); meta_background_actor_set_monitor (self, g_value_get_int (value));
break; break;
case PROP_BACKGROUND: case PROP_BACKGROUND:
meta_background_actor_set_background (self, g_value_get_object (value)); meta_background_actor_set_background (self, g_value_get_object (value));
break; break;
case PROP_GRADIENT:
meta_background_actor_set_gradient (self,
g_value_get_boolean (value),
priv->gradient_height,
priv->gradient_max_darkness);
break;
case PROP_GRADIENT_HEIGHT:
meta_background_actor_set_gradient (self,
priv->gradient,
g_value_get_int (value),
priv->gradient_max_darkness);
break;
case PROP_GRADIENT_MAX_DARKNESS:
meta_background_actor_set_gradient (self,
priv->gradient,
priv->gradient_height,
g_value_get_double (value));
break;
case PROP_VIGNETTE: case PROP_VIGNETTE:
meta_background_actor_set_vignette (self, meta_background_actor_set_vignette (self,
g_value_get_boolean (value), g_value_get_boolean (value),
@ -532,6 +618,15 @@ meta_background_actor_get_property (GObject *object,
case PROP_BACKGROUND: case PROP_BACKGROUND:
g_value_set_object (value, priv->background); g_value_set_object (value, priv->background);
break; break;
case PROP_GRADIENT:
g_value_set_boolean (value, priv->gradient);
break;
case PROP_GRADIENT_HEIGHT:
g_value_set_int (value, priv->gradient_height);
break;
case PROP_GRADIENT_MAX_DARKNESS:
g_value_set_double (value, priv->gradient_max_darkness);
break;
case PROP_VIGNETTE: case PROP_VIGNETTE:
g_value_set_boolean (value, priv->vignette); g_value_set_boolean (value, priv->vignette);
break; break;
@ -595,6 +690,36 @@ meta_background_actor_class_init (MetaBackgroundActorClass *klass)
PROP_BACKGROUND, PROP_BACKGROUND,
param_spec); param_spec);
param_spec = g_param_spec_boolean ("gradient",
"Gradient",
"Whether gradient effect is enabled",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_GRADIENT,
param_spec);
param_spec = g_param_spec_int ("gradient-height",
"Gradient Height",
"Height of gradient effect",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_GRADIENT_HEIGHT,
param_spec);
param_spec = g_param_spec_double ("gradient-max-darkness",
"Gradient Max Darkness",
"How dark is the gradient initially",
0.0, 1.0, 0.0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_GRADIENT_MAX_DARKNESS,
param_spec);
param_spec = g_param_spec_boolean ("vignette", param_spec = g_param_spec_boolean ("vignette",
"Vignette", "Vignette",
"Whether vignette effect is enabled", "Whether vignette effect is enabled",
@ -635,6 +760,10 @@ meta_background_actor_init (MetaBackgroundActor *self)
META_TYPE_BACKGROUND_ACTOR, META_TYPE_BACKGROUND_ACTOR,
MetaBackgroundActorPrivate); MetaBackgroundActorPrivate);
priv->gradient = FALSE;
priv->gradient_height = 0;
priv->gradient_max_darkness = 0.0;
priv->vignette = FALSE; priv->vignette = FALSE;
priv->vignette_brightness = 1.0; priv->vignette_brightness = 1.0;
priv->vignette_sharpness = 0.0; priv->vignette_sharpness = 0.0;
@ -751,6 +880,61 @@ meta_background_actor_set_background (MetaBackgroundActor *self,
clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
} }
void
meta_background_actor_set_gradient (MetaBackgroundActor *self,
gboolean enabled,
int height,
double max_darkness)
{
MetaBackgroundActorPrivate *priv;
gboolean changed = FALSE;
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
g_return_if_fail (height >= 0);
g_return_if_fail (max_darkness >= 0. && max_darkness <= 1.);
priv = self->priv;
enabled = enabled != FALSE && height != 0;
if (enabled != priv->gradient)
{
priv->gradient = enabled;
invalidate_pipeline (self, CHANGED_EFFECTS);
changed = TRUE;
}
if (height != priv->gradient_height || max_darkness != priv->gradient_max_darkness)
{
priv->gradient_height = height;
priv->gradient_max_darkness = max_darkness;
invalidate_pipeline (self, CHANGED_GRADIENT_PARAMETERS);
changed = TRUE;
}
if (changed)
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void
meta_background_actor_set_monitor (MetaBackgroundActor *self,
int monitor)
{
MetaBackgroundActorPrivate *priv = self->priv;
MetaRectangle old_monitor_geometry;
MetaRectangle new_monitor_geometry;
if(priv->monitor == monitor)
return;
meta_screen_get_monitor_geometry (priv->screen, priv->monitor, &old_monitor_geometry);
meta_screen_get_monitor_geometry (priv->screen, monitor, &new_monitor_geometry);
if(old_monitor_geometry.height != new_monitor_geometry.height)
invalidate_pipeline (self, CHANGED_GRADIENT_PARAMETERS);
priv->monitor = monitor;
}
void void
meta_background_actor_set_vignette (MetaBackgroundActor *self, meta_background_actor_set_vignette (MetaBackgroundActor *self,
gboolean enabled, gboolean enabled,

View File

@ -67,6 +67,14 @@ ClutterActor *meta_background_actor_new (MetaScreen *screen,
void meta_background_actor_set_background (MetaBackgroundActor *self, void meta_background_actor_set_background (MetaBackgroundActor *self,
MetaBackground *background); MetaBackground *background);
void meta_background_actor_set_gradient (MetaBackgroundActor *self,
gboolean enabled,
int height,
double tone_start);
void meta_background_actor_set_monitor (MetaBackgroundActor *self,
int monitor);
void meta_background_actor_set_vignette (MetaBackgroundActor *self, void meta_background_actor_set_vignette (MetaBackgroundActor *self,
gboolean enabled, gboolean enabled,
double brightness, double brightness,