Compare commits

...

25 Commits

Author SHA1 Message Date
Georges Basile Stavracas Neto
edf8a1e399 clutter/effect: Move ClutterEffect creation to ClutterActor
As so paint node creation is centralized in a single function.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 11:05:59 -03:00
Georges Basile Stavracas Neto
dd80e623a0 clutter/offscreen-effect: Document paint nodes
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 11:05:59 -03:00
Georges Basile Stavracas Neto
5e680fd43f clutter/effect: Add paint nodes to all paint vfuncs
In the purely paint node based rendering future, ClutterEffects
simply add more paint nodes to the tree when painting the actor.

This is the leap to achieve that future.

Add paint nodes to pre_paint, paint, and post_paint, and move the
ClutterEffectNode creation to _clutter_effect_paint().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 11:05:59 -03:00
Georges Basile Stavracas Neto
4226fa50da clutter/offscreen-effect: Remove clutter_offscreen_effect_get_target_rect
And drop the annoying 'position' field from ClutterOffscreenEffect as well.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 11:05:59 -03:00
Georges Basile Stavracas Neto
e5ee6e1138 clutter/deform-effect: Use clutter_offscreen_effect_get_target_size()
We don't read the x/y position anyway.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 11:05:59 -03:00
Georges Basile Stavracas Neto
47b88de3b6 clutter/offscreen-effect: Undeprecate clutter_offscreen_effect_get_target_size()
clutter_offscreen_effect_get_target_rect() is going away soon.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 11:05:59 -03:00
Georges Basile Stavracas Neto
e9b9784c5c clutter/offscreen-effect: Implement paint_node()
The paint node tree that ClutterOffscreenEffect generates is
simple:

  Root
    |------------+
    |            |
  Layer        Pipeline
    |
  Actor

Right now, both pre-paint and ClutterLayerNode push the offscreen
to the framebuffer stack. That's harmless, and will go away soon
anyway.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 11:05:59 -03:00
Georges Basile Stavracas Neto
1135a74e3e clutter/offscreen-effect: Use paint nodes to paint target
Add a new ClutterPaintNode parameter to the paint_target() vfunc.
For now, create a temporary ClutterEffectNode that is passed to
paint_target() and immediately painted; next commits will move
this to upper layers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 11:05:59 -03:00
Georges Basile Stavracas Neto
ae14a0a677 clutter/desaturate-effect: Switch to create_pipeline vfunc
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 10:55:32 -03:00
Georges Basile Stavracas Neto
dbe0602c4c clutter/colorize-effect: Switch to create_pipeline vfunc
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 10:55:32 -03:00
Georges Basile Stavracas Neto
f6c57366af clutter/brightness-contrast-effect: Switch to create_pipeline vfunc
Pretty much the exact same steps and constraints of the previous
commit.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 10:55:32 -03:00
Georges Basile Stavracas Neto
6ee3ece103 clutter/blur-effect: Switch to create_pipeline vfunc
The blur pipeline is still cached on ClutterBlurEffect, and we
simply update the uniforms when asked to create the pipeline.

Now that ClutterOffscreenEffect will use the blur pipeline, it
doesn't need to override the paint_target() vfunc anymore.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 10:55:32 -03:00
Georges Basile Stavracas Neto
be3743ec3f clutter/offscreen-effect: Add new create_pipeline() vfunc
The most annoying aspect of ClutterOffscreenEffect right now, and
the reason for all its subclasses to override pre-paint, is that
the pipeline creating isn't under subclasses' control. That means
all subclasses must ask ClutterOffscreenEffect to run pre-paint
and create the pipeline, then they all create their own pipelines
to paint.

To reduce this complexity, add a new create_pipeline() vfunc to
ClutterOffscreenEffect. Next commits will port effects to use this
vfunc when necessary.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 10:55:32 -03:00
Georges Basile Stavracas Neto
59a3075f60 clutter/offscreen-effect: Remove CoglMaterial from public API
Rename clutter_offscreen_effect_get_material() to get_pipeline() and
make it return (actuall, stop casting to) a CoglMaterial.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1355
2020-07-06 10:55:32 -03:00
Georges Basile Stavracas Neto
5d7edde37d Introduce ClutterBlitNode
It is not possible to express a blit operation using paint
nodes as of now. This is a requirement for GNOME Shell, e.g.,
to implement its blur effect.

Add a new ClutterBlitNode node that takes two framebuffers as
input, and blits source into dest according to added rectangles.

Because this paint node uses the rectangles in a different way
compared to all the other nodes, add an auxiliary method to
ensure all blit operations are valid.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:55:00 -03:00
Georges Basile Stavracas Neto
96e8074a4f clutter/paint-nodes: Add serialization to layer node
It's useful to know which framebuffer the layer node is holding,
so serialize that too.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:55:00 -03:00
Georges Basile Stavracas Neto
c261eb736a clutter/paint-nodes: Push and pop framebuffer even without ops
ClutterLayerNode currently skips pushing and popping its framebuffer
to the paint context when no rectangles are added to it. However,
it's still useful to do that, since we might want to render child
nodes to the offscreen and reuse the pipeline in a later node.

Make ClutterLayerNode push and pop its framebuffer even without
rectangles.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:55:00 -03:00
Georges Basile Stavracas Neto
03be5ed9f1 clutter/paint-nodes: Add new ClutterLayerNode API
ClutterLayerNode is the "offscreen framebuffer" node, that paints
it's child nodes in a separate framebuffer, and then copies that
framebuffer to the parent one.

It'll be useful to hand ClutterLayerNode which framebuffer to use,
as this is a requirement for porting e.g. ClutterOffscreenEffect
and subclasses.

Add a new clutter_layer_node_new_with_framebuffer() API.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:55:00 -03:00
Georges Basile Stavracas Neto
6f0719b3c7 clutter/paint-nodes: Don't skip pipeline node constructor
ClutterPipelineNode will be used by GNOME Shell in the future.
Fortunately for us, CoglPipeline is already usable from GJS,
so we don't need to skip the constructor for the pipeline node.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:55:00 -03:00
Georges Basile Stavracas Neto
6be6f04456 clutter/paint-nodes: Add opacity overriding to ClutterActorNode
Some effects, such as ShellBlurEffect and ClutterOffscreenEffect, need
to make sure the actor is painted fully opaque. With ClutterActorNode,
however, that is currently not possible.

Add a new 'opacity' parameter to clutter_actor_node_new(). It follows
the opacity override heuristic, where -1 means disable, and anything
else is clamped to [0, 255].

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:54:49 -03:00
Georges Basile Stavracas Neto
e0a8e824b3 clutter/offscreen-effect: Simplify paint
Simply chain up to get the pre and post paint methods,
instead of reimplementing ClutterEffect.paint()

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:39:59 -03:00
Georges Basile Stavracas Neto
0d51678bbe clutter/offscreen-effect: Clear framebuffer on pre_paint
Move the framebuffer cleanup to ClutterOffscreenEffect.pre_paint().
This will allow us to properly chain up ClutterOffscreenEffect.paint()
and not reimplement exactly what ClutterEffect does by default.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:39:59 -03:00
Georges Basile Stavracas Neto
35af306acc clutter/effect: Add paint_node vfunc
Introduce a new paint_node vfunc that, if implemented, allows
the effect to add nodes to a transient paint node that is
immediately painted. This is a transitional step until we
have fully delegated paint node rendering.

The most basic implementation of a ClutterEffect.paint_node
vfunc, and also the default implementation, is with an actor
node, as follows:

```
static void
foo_bar_paint_node (ClutterEffect           *effect,
                    ClutterPaintNode        *node,
                    ClutterPaintContext     *paint_context,
                    ClutterEffectPaintFlags  flags)
{
  g_autoptr (ClutterPaintNode) actor_node = NULL;

  actor_node = clutter_actor_node_new (effect->actor);
  clutter_paint_node_add_child (node, actor_node);
}
```

This example gives the exact same behavior of simply calling
clutter_actor_continue_paint(). In the future, the paint node
itself will be a parameter of clutter_actor_continue_paint()
and we'll be able to simplify it event more.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:39:59 -03:00
Georges Basile Stavracas Neto
e8f9d093b1 Introduce ClutterEffectNode
ClutterEffectNode is a private ClutterPaintNode implementation
that does effectively nothing, but helps organizing the paint
node tree. It also helps debugging, since it can output the
effect class and name to the JSON debugging routines.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:39:59 -03:00
Georges Basile Stavracas Neto
0f1289e534 clutter/effect: Don't expose pre and post paint helpers
They're not used outside ClutterEffect.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
2020-07-06 10:39:59 -03:00
16 changed files with 768 additions and 468 deletions

View File

@ -3737,7 +3737,7 @@ clutter_actor_paint (ClutterActor *self,
if (!CLUTTER_ACTOR_IS_MAPPED (self))
return;
actor_node = clutter_actor_node_new (self);
actor_node = clutter_actor_node_new (self, -1);
root_node = clutter_paint_node_ref (actor_node);
if (priv->has_clip)
@ -3958,6 +3958,7 @@ clutter_actor_continue_paint (ClutterActor *self,
}
else
{
g_autoptr (ClutterPaintNode) effect_node = NULL;
ClutterEffect *old_current_effect;
ClutterEffectPaintFlags run_flags = 0;
@ -3986,7 +3987,14 @@ clutter_actor_continue_paint (ClutterActor *self,
run_flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY)
run_flags |= CLUTTER_EFFECT_PAINT_BYPASS_EFFECT;
_clutter_effect_paint (priv->current_effect, paint_context, run_flags);
effect_node = clutter_effect_node_new (priv->current_effect);
_clutter_effect_paint (priv->current_effect,
effect_node,
paint_context,
run_flags);
clutter_paint_node_paint (effect_node, paint_context);
priv->current_effect = old_current_effect;
}

View File

@ -81,9 +81,6 @@ struct _ClutterBlurEffect
gint pixel_step_uniform;
gint tex_width;
gint tex_height;
CoglPipeline *pipeline;
};
@ -98,20 +95,42 @@ G_DEFINE_TYPE (ClutterBlurEffect,
clutter_blur_effect,
CLUTTER_TYPE_OFFSCREEN_EFFECT);
static CoglPipeline *
clutter_blur_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterBlurEffect *blur_effect = CLUTTER_BLUR_EFFECT (effect);
if (blur_effect->pixel_step_uniform > -1)
{
float pixel_step[2];
int tex_width, tex_height;
tex_width = cogl_texture_get_width (texture);
tex_height = cogl_texture_get_height (texture);
pixel_step[0] = 1.0f / tex_width;
pixel_step[1] = 1.0f / tex_height;
cogl_pipeline_set_uniform_float (blur_effect->pipeline,
blur_effect->pixel_step_uniform,
2, /* n_components */
1, /* count */
pixel_step);
}
cogl_pipeline_set_layer_texture (blur_effect->pipeline, 0, texture);
return cogl_object_ref (blur_effect->pipeline);
}
static gboolean
clutter_blur_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect);
ClutterEffectClass *parent_class;
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;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* if we don't have support for GLSL shaders then we
@ -125,59 +144,7 @@ clutter_blur_effect_pre_paint (ClutterEffect *effect,
}
parent_class = CLUTTER_EFFECT_CLASS (clutter_blur_effect_parent_class);
if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
if (self->pixel_step_uniform > -1)
{
gfloat pixel_step[2];
pixel_step[0] = 1.0f / self->tex_width;
pixel_step[1] = 1.0f / self->tex_height;
cogl_pipeline_set_uniform_float (self->pipeline,
self->pixel_step_uniform,
2, /* n_components */
1, /* count */
pixel_step);
}
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_blur_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
guint8 paint_opacity;
paint_opacity = clutter_actor_get_paint_opacity (self->actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
self->tex_width, self->tex_height);
return parent_class->pre_paint (effect, node, paint_context);
}
static gboolean
@ -229,7 +196,7 @@ clutter_blur_effect_class_init (ClutterBlurEffectClass *klass)
effect_class->modify_paint_volume = clutter_blur_effect_modify_paint_volume;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->paint_target = clutter_blur_effect_paint_target;
offscreen_class->create_pipeline = clutter_blur_effect_create_pipeline;
}
static void

View File

@ -69,9 +69,6 @@ struct _ClutterBrightnessContrastEffect
gint brightness_offset_uniform;
gint contrast_uniform;
gint tex_width;
gint tex_height;
CoglPipeline *pipeline;
};
@ -129,16 +126,26 @@ will_have_no_effect (ClutterBrightnessContrastEffect *self)
G_APPROX_VALUE (self->contrast_blue, no_change, FLT_EPSILON));
}
static CoglPipeline *
clutter_brightness_contrast_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterBrightnessContrastEffect *self =
CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return cogl_object_ref (self->pipeline);
}
static gboolean
clutter_brightness_contrast_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (will_have_no_effect (self))
return FALSE;
@ -157,47 +164,8 @@ clutter_brightness_contrast_effect_pre_paint (ClutterEffect *effect,
parent_class =
CLUTTER_EFFECT_CLASS (clutter_brightness_contrast_effect_parent_class);
if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_brightness_contrast_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterActor *actor;
guint8 paint_opacity;
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
self->tex_width, self->tex_height);
return parent_class->pre_paint (effect, node, paint_context);
}
static void
@ -297,7 +265,7 @@ clutter_brightness_contrast_effect_class_init (ClutterBrightnessContrastEffectCl
ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->paint_target = clutter_brightness_contrast_effect_paint_target;
offscreen_class->create_pipeline = clutter_brightness_contrast_effect_create_pipeline;
effect_class->pre_paint = clutter_brightness_contrast_effect_pre_paint;

View File

@ -59,9 +59,6 @@ struct _ClutterColorizeEffect
gint tint_uniform;
gint tex_width;
gint tex_height;
CoglPipeline *pipeline;
};
@ -104,16 +101,24 @@ G_DEFINE_TYPE (ClutterColorizeEffect,
clutter_colorize_effect,
CLUTTER_TYPE_OFFSCREEN_EFFECT);
static CoglPipeline *
clutter_colorize_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterColorizeEffect *colorize_effect = CLUTTER_COLORIZE_EFFECT (effect);
cogl_pipeline_set_layer_texture (colorize_effect->pipeline, 0, texture);
return cogl_object_ref (colorize_effect->pipeline);
}
static gboolean
clutter_colorize_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect);
ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* if we don't have support for GLSL shaders then we
@ -127,47 +132,7 @@ clutter_colorize_effect_pre_paint (ClutterEffect *effect,
}
parent_class = CLUTTER_EFFECT_CLASS (clutter_colorize_effect_parent_class);
if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_colorize_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterActor *actor;
guint8 paint_opacity;
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
self->tex_width, self->tex_height);
return parent_class->pre_paint (effect, node, paint_context);
}
static void
@ -233,7 +198,7 @@ clutter_colorize_effect_class_init (ClutterColorizeEffectClass *klass)
ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->paint_target = clutter_colorize_effect_paint_target;
offscreen_class->create_pipeline = clutter_colorize_effect_create_pipeline;
effect_class->pre_paint = clutter_colorize_effect_pre_paint;

View File

@ -58,9 +58,12 @@
#include <cogl/cogl.h>
#include "clutter-color.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-offscreen-effect-private.h"
#include "clutter-paint-node.h"
#include "clutter-paint-nodes.h"
#include "clutter-private.h"
#define DEFAULT_N_TILES 32
@ -166,19 +169,16 @@ clutter_deform_effect_set_actor (ClutterActorMeta *meta,
static void
clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect);
ClutterDeformEffectPrivate *priv = self->priv;
CoglHandle material;
CoglPipeline *pipeline;
CoglDepthState depth_state;
CoglFramebuffer *fb =
clutter_paint_context_get_framebuffer (paint_context);
if (priv->is_dirty)
{
graphene_rect_t rect;
gboolean mapped_buffer;
CoglVertexP3T2C4 *verts;
ClutterActor *actor;
@ -192,12 +192,7 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
/* if we don't have a target size, fall back to the actor's
* allocation, though wrong it might be
*/
if (clutter_offscreen_effect_get_target_rect (effect, &rect))
{
width = graphene_rect_get_width (&rect);
height = graphene_rect_get_height (&rect);
}
else
if (!clutter_offscreen_effect_get_target_size (effect, &width, &height))
clutter_actor_get_size (actor, &width, &height);
/* XXX ideally, the sub-classes should tell us what they
@ -277,8 +272,7 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
priv->is_dirty = FALSE;
}
material = clutter_offscreen_effect_get_target (effect);
pipeline = COGL_PIPELINE (material);
pipeline = clutter_offscreen_effect_get_pipeline (effect);
/* enable depth testing */
cogl_depth_state_init (&depth_state);
@ -292,12 +286,22 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
COGL_PIPELINE_CULL_FACE_MODE_BACK);
/* draw the front */
if (material != NULL)
cogl_framebuffer_draw_primitive (fb, pipeline, priv->primitive);
if (pipeline != NULL)
{
ClutterPaintNode *front_node;
front_node = clutter_pipeline_node_new (pipeline);
clutter_paint_node_set_static_name (front_node,
"ClutterDeformEffect (front)");
clutter_paint_node_add_child (node, front_node);
clutter_paint_node_add_primitive (front_node, priv->primitive);
clutter_paint_node_unref (front_node);
}
/* draw the back */
if (priv->back_pipeline != NULL)
{
ClutterPaintNode *back_node;
CoglPipeline *back_pipeline;
/* We probably shouldn't be modifying the user's material so
@ -307,20 +311,30 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
cogl_pipeline_set_cull_face_mode (back_pipeline,
COGL_PIPELINE_CULL_FACE_MODE_FRONT);
cogl_framebuffer_draw_primitive (fb, back_pipeline, priv->primitive);
back_node = clutter_pipeline_node_new (back_pipeline);
clutter_paint_node_set_static_name (back_node,
"ClutterDeformEffect (back)");
clutter_paint_node_add_child (node, back_node);
clutter_paint_node_add_primitive (back_node, priv->primitive);
clutter_paint_node_unref (back_node);
cogl_object_unref (back_pipeline);
}
if (G_UNLIKELY (priv->lines_primitive != NULL))
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglPipeline *lines_pipeline = cogl_pipeline_new (ctx);
cogl_pipeline_set_color4f (lines_pipeline, 1.0, 0, 0, 1.0);
cogl_framebuffer_draw_primitive (fb, lines_pipeline,
priv->lines_primitive);
cogl_object_unref (lines_pipeline);
const ClutterColor *red;
ClutterPaintNode *lines_node;
red = clutter_color_get_static (CLUTTER_COLOR_RED);
lines_node = clutter_color_node_new (red);
clutter_paint_node_set_static_name (lines_node,
"ClutterDeformEffect (lines)");
clutter_paint_node_add_child (node, lines_node);
clutter_paint_node_add_primitive (lines_node, priv->lines_primitive);
clutter_paint_node_unref (lines_node);
}
}

View File

@ -111,16 +111,25 @@ G_DEFINE_TYPE (ClutterDesaturateEffect,
clutter_desaturate_effect,
CLUTTER_TYPE_OFFSCREEN_EFFECT);
static CoglPipeline *
clutter_desaturate_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterDesaturateEffect *desaturate_effect =
CLUTTER_DESATURATE_EFFECT (effect);
cogl_pipeline_set_layer_texture (desaturate_effect->pipeline, 0, texture);
return cogl_object_ref (desaturate_effect->pipeline);
}
static gboolean
clutter_desaturate_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect);
ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* if we don't have support for GLSL shaders then we
@ -134,52 +143,7 @@ clutter_desaturate_effect_pre_paint (ClutterEffect *effect,
}
parent_class = CLUTTER_EFFECT_CLASS (clutter_desaturate_effect_parent_class);
if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_desaturate_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterActor *actor;
CoglHandle texture;
guint8 paint_opacity;
texture = clutter_offscreen_effect_get_texture (effect);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture));
return parent_class->pre_paint (effect, node, paint_context);
}
static void
@ -254,7 +218,7 @@ clutter_desaturate_effect_class_init (ClutterDesaturateEffectClass *klass)
ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->paint_target = clutter_desaturate_effect_paint_target;
offscreen_class->create_pipeline = clutter_desaturate_effect_create_pipeline;
effect_class->pre_paint = clutter_desaturate_effect_pre_paint;

View File

@ -5,14 +5,11 @@
G_BEGIN_DECLS
gboolean _clutter_effect_pre_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context);
void _clutter_effect_post_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context);
gboolean _clutter_effect_modify_paint_volume (ClutterEffect *effect,
ClutterPaintVolume *volume);
gboolean _clutter_effect_has_custom_paint_volume (ClutterEffect *effect);
void _clutter_effect_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags);
void _clutter_effect_pick (ClutterEffect *effect,

View File

@ -169,6 +169,8 @@
#include "clutter-effect-private.h"
#include "clutter-enum-types.h"
#include "clutter-marshal.h"
#include "clutter-paint-node-private.h"
#include "clutter-paint-nodes.h"
#include "clutter-private.h"
#include "clutter-actor-private.h"
@ -178,6 +180,7 @@ G_DEFINE_ABSTRACT_TYPE (ClutterEffect,
static gboolean
clutter_effect_real_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
return TRUE;
@ -185,6 +188,7 @@ clutter_effect_real_pre_paint (ClutterEffect *effect,
static void
clutter_effect_real_post_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
}
@ -197,25 +201,40 @@ clutter_effect_real_modify_paint_volume (ClutterEffect *effect,
}
static void
clutter_effect_real_paint (ClutterEffect *effect,
clutter_effect_real_paint_node (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (effect);
ClutterPaintNode *actor_node;
ClutterActor *actor;
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
actor_node = clutter_actor_node_new (actor, -1);
clutter_paint_node_add_child (node, actor_node);
clutter_paint_node_unref (actor_node);
}
static void
clutter_effect_real_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
ClutterEffectClass *effect_class = CLUTTER_EFFECT_GET_CLASS (effect);
gboolean pre_paint_succeeded;
/* The default implementation provides a compatibility wrapper for
effects that haven't migrated to use the 'paint' virtual yet. This
just calls the old pre and post virtuals before chaining on */
pre_paint_succeeded = _clutter_effect_pre_paint (effect, paint_context);
pre_paint_succeeded = effect_class->pre_paint (effect, node,paint_context);
actor = clutter_actor_meta_get_actor (actor_meta);
clutter_actor_continue_paint (actor, paint_context);
effect_class->paint_node (effect, node, paint_context, flags);
if (pre_paint_succeeded)
_clutter_effect_post_paint (effect, paint_context);
effect_class->post_paint (effect, node, paint_context);
}
static void
@ -255,6 +274,7 @@ clutter_effect_class_init (ClutterEffectClass *klass)
klass->post_paint = clutter_effect_real_post_paint;
klass->modify_paint_volume = clutter_effect_real_modify_paint_volume;
klass->paint = clutter_effect_real_paint;
klass->paint_node = clutter_effect_real_paint_node;
klass->pick = clutter_effect_real_pick;
}
@ -263,32 +283,18 @@ clutter_effect_init (ClutterEffect *self)
{
}
gboolean
_clutter_effect_pre_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context)
{
g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
return CLUTTER_EFFECT_GET_CLASS (effect)->pre_paint (effect, paint_context);
}
void
_clutter_effect_post_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context)
{
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
CLUTTER_EFFECT_GET_CLASS (effect)->post_paint (effect, paint_context);
}
void
_clutter_effect_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect, paint_context, flags);
CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect,
node,
paint_context,
flags);
}
void

View File

@ -77,14 +77,21 @@ struct _ClutterEffectClass
/*< public >*/
gboolean (* pre_paint) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context);
void (* post_paint) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context);
gboolean (* modify_paint_volume) (ClutterEffect *effect,
ClutterPaintVolume *volume);
void (* paint) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags);
void (* paint_node) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags);
void (* pick) (ClutterEffect *effect,

View File

@ -60,6 +60,30 @@
* #ClutterOffscreenEffectClass.create_texture() virtual function; no chain up
* to the #ClutterOffscreenEffect implementation is required in this
* case.
*
* ## Paint nodes
*
* #ClutterOffscreenEffect is generates the following paint node tree:
*
* |[<!-- language="plain" -->
* Effect
*
* Layer Pipeline
*
* Actor
* ]|
*
* When the actor contents are cached, the generated paint node tree
* looks like this:
*
* |[<!-- language="plain" -->
* Effect
*
* Pipeline
* ]|
*
* In both cases, the "Pipeline" node is created with the return value
* of #ClutterOffscreenEffectClass.create_pipeline().
*/
#include "clutter-build-config.h"
@ -75,6 +99,8 @@
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "clutter-paint-context-private.h"
#include "clutter-paint-node-private.h"
#include "clutter-paint-nodes.h"
#include "clutter-paint-volume-private.h"
#include "clutter-actor-box-private.h"
@ -87,8 +113,6 @@ struct _ClutterOffscreenEffectPrivate
ClutterActor *actor;
ClutterActor *stage;
graphene_point3d_t position;
int fbo_offset_x;
int fbo_offset_y;
@ -158,6 +182,25 @@ ensure_pipeline_filter_for_scale (ClutterOffscreenEffect *self,
filter, filter);
}
static CoglPipeline *
clutter_offscreen_effect_real_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterOffscreenEffectPrivate *priv = effect->priv;
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglPipeline *pipeline;
float resource_scale;
resource_scale = clutter_actor_get_real_resource_scale (priv->actor);
pipeline = cogl_pipeline_new (ctx);
ensure_pipeline_filter_for_scale (effect, resource_scale);
cogl_pipeline_set_layer_texture (pipeline, 0, texture);
return pipeline;
}
static gboolean
update_fbo (ClutterEffect *effect,
int target_width,
@ -166,6 +209,8 @@ update_fbo (ClutterEffect *effect,
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterOffscreenEffectClass *offscreen_class =
CLUTTER_OFFSCREEN_EFFECT_GET_CLASS (effect);
priv->stage = clutter_actor_get_stage (priv->actor);
if (priv->stage == NULL)
@ -185,15 +230,6 @@ update_fbo (ClutterEffect *effect,
return TRUE;
}
if (priv->pipeline == NULL)
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
priv->pipeline = cogl_pipeline_new (ctx);
ensure_pipeline_filter_for_scale (self, resource_scale);
}
g_clear_pointer (&priv->texture, cogl_object_unref);
g_clear_pointer (&priv->offscreen, cogl_object_unref);
@ -202,8 +238,6 @@ update_fbo (ClutterEffect *effect,
if (priv->texture == NULL)
return FALSE;
cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->texture);
priv->target_width = target_width;
priv->target_height = target_height;
@ -212,8 +246,7 @@ update_fbo (ClutterEffect *effect,
{
g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC);
cogl_object_unref (priv->pipeline);
priv->pipeline = NULL;
cogl_clear_object (&priv->pipeline);
priv->target_width = 0;
priv->target_height = 0;
@ -221,35 +254,33 @@ update_fbo (ClutterEffect *effect,
return FALSE;
}
cogl_clear_object (&priv->pipeline);
priv->pipeline = offscreen_class->create_pipeline (self, priv->texture);
return TRUE;
}
static gboolean
clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterActorBox raw_box, box;
ClutterActor *stage;
CoglMatrix projection, old_modelview, modelview;
CoglMatrix projection, modelview;
const ClutterPaintVolume *volume;
CoglColor transparent;
gfloat stage_width, stage_height;
gfloat target_width = -1, target_height = -1;
CoglFramebuffer *framebuffer;
float resource_scale;
float ceiled_resource_scale;
graphene_point3d_t local_offset;
gfloat old_viewport[4];
local_offset = GRAPHENE_POINT3D_INIT (0.0f, 0.0f, 0.0f);
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
goto fail;
if (priv->actor == NULL)
return FALSE;
goto fail;
stage = _clutter_actor_get_stage_internal (priv->actor);
clutter_actor_get_size (stage, &stage_width, &stage_height);
@ -294,12 +325,7 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
/* First assert that the framebuffer is the right size... */
if (!update_fbo (effect, target_width, target_height, resource_scale))
return FALSE;
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_get_modelview_matrix (framebuffer, &old_modelview);
clutter_paint_context_push_framebuffer (paint_context, priv->offscreen);
goto fail;
/* We don't want the FBO contents to be transformed. That could waste memory
* (e.g. during zoom), or result in something that's not rectangular (clipped
@ -311,13 +337,6 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
clutter_actor_get_transform (priv->stage, &modelview);
cogl_framebuffer_set_modelview_matrix (priv->offscreen, &modelview);
/* Save the original viewport for calculating priv->position */
_clutter_stage_get_viewport (CLUTTER_STAGE (priv->stage),
&old_viewport[0],
&old_viewport[1],
&old_viewport[2],
&old_viewport[3]);
/* Set up the viewport so that it has the same size as the stage (avoid
* distortion), but translated to account for the FBO offset...
*/
@ -331,45 +350,22 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
_clutter_stage_get_projection_matrix (CLUTTER_STAGE (priv->stage),
&projection);
/* Now save the global position of the effect (not just of the actor).
* It doesn't appear anyone actually uses this yet, but get_target_rect is
* documented as returning it. So we should...
*/
_clutter_util_fully_transform_vertices (&old_modelview,
&projection,
old_viewport,
&local_offset,
&priv->position,
1);
cogl_framebuffer_set_projection_matrix (priv->offscreen, &projection);
cogl_color_init_from_4ub (&transparent, 0, 0, 0, 0);
cogl_framebuffer_clear (priv->offscreen,
COGL_BUFFER_BIT_COLOR |
COGL_BUFFER_BIT_DEPTH,
&transparent);
cogl_framebuffer_push_matrix (priv->offscreen);
/* Override the actor's opacity to fully opaque - we paint the offscreen
* texture with the actor's paint opacity, so we need to do this to avoid
* multiplying the opacity twice.
*/
priv->old_opacity_override =
clutter_actor_get_opacity_override (priv->actor);
clutter_actor_set_opacity_override (priv->actor, 0xff);
return TRUE;
fail:
cogl_clear_object (&priv->offscreen);
return FALSE;
}
static void
clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterOffscreenEffectPrivate *priv = effect->priv;
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterPaintNode *pipeline_node;
guint8 paint_opacity;
paint_opacity = clutter_actor_get_paint_opacity (priv->actor);
@ -380,96 +376,122 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
paint_opacity,
paint_opacity);
pipeline_node = clutter_pipeline_node_new (priv->pipeline);
clutter_paint_node_set_static_name (pipeline_node,
"ClutterOffscreenEffect (pipeline)");
clutter_paint_node_add_child (node, pipeline_node);
/* At this point we are in stage coordinates translated so if
* we draw our texture using a textured quad the size of the paint
* box then we will overlay where the actor would have drawn if it
* hadn't been redirected offscreen.
*/
cogl_framebuffer_draw_textured_rectangle (framebuffer,
priv->pipeline,
0, 0,
clutter_paint_node_add_rectangle (pipeline_node,
&(ClutterActorBox) {
0.f, 0.f,
cogl_texture_get_width (priv->texture),
cogl_texture_get_height (priv->texture),
0.0, 0.0,
1.0, 1.0);
});
clutter_paint_node_unref (pipeline_node);
}
static void
clutter_offscreen_effect_paint_texture (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterOffscreenEffectPrivate *priv = effect->priv;
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
CoglMatrix modelview;
CoglMatrix transform;
float resource_scale;
cogl_framebuffer_push_matrix (framebuffer);
/* The current modelview matrix is *almost* perfect already. It's only
* missing a correction for the expanded FBO and offset rendering within...
*/
cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview);
cogl_matrix_init_identity (&transform);
resource_scale = clutter_actor_get_resource_scale (priv->actor);
if (resource_scale != 1.0f)
{
float paint_scale = 1.0f / resource_scale;
cogl_matrix_scale (&modelview, paint_scale, paint_scale, 1);
cogl_matrix_scale (&transform, paint_scale, paint_scale, 1);
}
cogl_matrix_translate (&modelview,
cogl_matrix_translate (&transform,
priv->fbo_offset_x,
priv->fbo_offset_y,
0.0f);
cogl_framebuffer_set_modelview_matrix (framebuffer, &modelview);
if (!cogl_matrix_is_identity (&transform))
{
ClutterPaintNode *transform_node;
transform_node = clutter_transform_node_new (&transform);
clutter_paint_node_set_static_name (transform_node,
"ClutterOffscreenEffect (transform)");
clutter_paint_node_add_child (node, transform_node);
clutter_paint_node_unref (transform_node);
node = transform_node;
}
/* paint the target material; this is virtualized for
* sub-classes that require special hand-holding
*/
clutter_offscreen_effect_paint_target (effect, paint_context);
cogl_framebuffer_pop_matrix (framebuffer);
clutter_offscreen_effect_paint_target (effect, node, paint_context);
}
static void
clutter_offscreen_effect_post_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
CoglFramebuffer *framebuffer;
g_warn_if_fail (priv->offscreen);
g_warn_if_fail (priv->pipeline);
g_warn_if_fail (priv->actor);
/* Restore the previous opacity override */
if (priv->actor)
{
clutter_actor_set_opacity_override (priv->actor,
priv->old_opacity_override);
}
clutter_offscreen_effect_paint_texture (self, node, paint_context);
}
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_pop_matrix (framebuffer);
clutter_paint_context_pop_framebuffer (paint_context);
static void
clutter_offscreen_effect_paint_node (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = offscreen_effect->priv;
ClutterPaintNode *layer_node;
ClutterPaintNode *actor_node;
clutter_offscreen_effect_paint_texture (self, paint_context);
layer_node = clutter_layer_node_new_with_framebuffer (priv->offscreen,
priv->pipeline,
255);
clutter_paint_node_set_static_name (layer_node,
"ClutterOffscreenEffect (actor offscreen)");
clutter_paint_node_add_child (node, layer_node);
clutter_paint_node_unref (layer_node);
actor_node = clutter_actor_node_new (priv->actor, 255);
clutter_paint_node_add_child (layer_node, actor_node);
clutter_paint_node_unref (actor_node);
}
static void
clutter_offscreen_effect_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterEffectClass *parent_class =
CLUTTER_EFFECT_CLASS (clutter_offscreen_effect_parent_class);
if (flags & CLUTTER_EFFECT_PAINT_BYPASS_EFFECT)
{
clutter_actor_continue_paint (priv->actor, paint_context);
parent_class->paint_node (effect, node, paint_context, flags);
cogl_clear_object (&priv->offscreen);
return;
}
@ -478,21 +500,9 @@ clutter_offscreen_effect_paint (ClutterEffect *effect,
* then we can just use the cached image in the FBO.
*/
if (priv->offscreen == NULL || (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY))
{
ClutterEffectClass *effect_class = CLUTTER_EFFECT_GET_CLASS (effect);
gboolean pre_paint_succeeded;
pre_paint_succeeded = effect_class->pre_paint (effect, paint_context);
clutter_actor_continue_paint (priv->actor, paint_context);
if (pre_paint_succeeded)
effect_class->post_paint (effect, paint_context);
parent_class->paint (effect, node, paint_context, flags);
else
g_clear_pointer (&priv->offscreen, cogl_object_unref);
}
else
clutter_offscreen_effect_paint_texture (self, paint_context);
clutter_offscreen_effect_paint_texture (self, node, paint_context);
}
static void
@ -530,6 +540,7 @@ clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
klass->create_texture = clutter_offscreen_effect_real_create_texture;
klass->create_pipeline = clutter_offscreen_effect_real_create_pipeline;
klass->paint_target = clutter_offscreen_effect_real_paint_target;
meta_class->set_actor = clutter_offscreen_effect_set_actor;
@ -538,6 +549,7 @@ clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass)
effect_class->pre_paint = clutter_offscreen_effect_pre_paint;
effect_class->post_paint = clutter_offscreen_effect_post_paint;
effect_class->paint = clutter_offscreen_effect_paint;
effect_class->paint_node = clutter_offscreen_effect_paint_node;
gobject_class->finalize = clutter_offscreen_effect_finalize;
}
@ -578,33 +590,34 @@ clutter_offscreen_effect_get_texture (ClutterOffscreenEffect *effect)
}
/**
* clutter_offscreen_effect_get_target: (skip)
* clutter_offscreen_effect_get_pipeline:
* @effect: a #ClutterOffscreenEffect
*
* Retrieves the material used as a render target for the offscreen
* Retrieves the pipeline used as a render target for the offscreen
* buffer created by @effect
*
* You should only use the returned #CoglMaterial when painting. The
* returned material might change between different frames.
* You should only use the returned #CoglPipeline when painting. The
* returned pipeline might change between different frames.
*
* Return value: (transfer none): a #CoglMaterial or %NULL. The
* returned material is owned by Clutter and it should not be
* modified or freed
* Return value: (transfer none)(nullable): a #CoglPipeline. The
* pipeline is owned by Clutter and it should not be modified
* or freed
*
* Since: 1.4
*/
CoglMaterial *
clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect)
CoglPipeline *
clutter_offscreen_effect_get_pipeline (ClutterOffscreenEffect *effect)
{
g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect),
NULL);
return (CoglMaterial *)effect->priv->pipeline;
return effect->priv->pipeline;
}
/**
* clutter_offscreen_effect_paint_target:
* @effect: a #ClutterOffscreenEffect
* @node: a #ClutterPaintNode
* @paint_context: a #ClutterPaintContext
*
* Calls the paint_target() virtual function of the @effect
@ -613,11 +626,13 @@ clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect)
*/
void
clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
g_return_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect));
CLUTTER_OFFSCREEN_EFFECT_GET_CLASS (effect)->paint_target (effect,
node,
paint_context);
}
@ -665,8 +680,6 @@ clutter_offscreen_effect_create_texture (ClutterOffscreenEffect *effect,
* and %FALSE otherwise
*
* Since: 1.8
*
* Deprecated: 1.14: Use clutter_offscreen_effect_get_target_rect() instead
*/
gboolean
clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect,
@ -690,43 +703,3 @@ clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect,
return TRUE;
}
/**
* clutter_offscreen_effect_get_target_rect:
* @effect: a #ClutterOffscreenEffect
* @rect: (out caller-allocates): return location for the target area
*
* Retrieves the origin and size of the offscreen buffer used by @effect to
* paint the actor to which it has been applied.
*
* This function should only be called by #ClutterOffscreenEffect
* implementations, from within the #ClutterOffscreenEffectClass.paint_target()
* virtual function.
*
* Return value: %TRUE if the offscreen buffer has a valid rectangle,
* and %FALSE otherwise
*
* Since: 1.14
*/
gboolean
clutter_offscreen_effect_get_target_rect (ClutterOffscreenEffect *effect,
graphene_rect_t *rect)
{
ClutterOffscreenEffectPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect), FALSE);
g_return_val_if_fail (rect != NULL, FALSE);
priv = effect->priv;
if (priv->texture == NULL)
return FALSE;
graphene_rect_init (rect,
priv->position.x,
priv->position.y,
cogl_texture_get_width (priv->texture),
cogl_texture_get_height (priv->texture));
return TRUE;
}

View File

@ -79,7 +79,10 @@ struct _ClutterOffscreenEffectClass
CoglHandle (* create_texture) (ClutterOffscreenEffect *effect,
gfloat width,
gfloat height);
CoglPipeline* (* create_pipeline) (ClutterOffscreenEffect *effect,
CoglTexture *texture);
void (* paint_target) (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context);
/*< private >*/
@ -96,28 +99,25 @@ CLUTTER_EXPORT
GType clutter_offscreen_effect_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
CoglMaterial * clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect);
CoglPipeline * clutter_offscreen_effect_get_pipeline (ClutterOffscreenEffect *effect);
CLUTTER_EXPORT
CoglHandle clutter_offscreen_effect_get_texture (ClutterOffscreenEffect *effect);
CLUTTER_EXPORT
void clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context);
CLUTTER_EXPORT
CoglHandle clutter_offscreen_effect_create_texture (ClutterOffscreenEffect *effect,
gfloat width,
gfloat height);
CLUTTER_DEPRECATED_FOR (clutter_offscreen_effect_get_target_rect)
CLUTTER_EXPORT
gboolean clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect,
gfloat *width,
gfloat *height);
CLUTTER_EXPORT
gboolean clutter_offscreen_effect_get_target_rect (ClutterOffscreenEffect *effect,
graphene_rect_t *rect);
G_END_DECLS
#endif /* __CLUTTER_OFFSCREEN_EFFECT_H__ */

View File

@ -141,6 +141,26 @@ ClutterPaintNode * clutter_paint_node_get_last_child (Clutter
G_GNUC_INTERNAL
ClutterPaintNode * clutter_paint_node_get_parent (ClutterPaintNode *node);
#define CLUTTER_TYPE_EFFECT_NODE (clutter_effect_node_get_type ())
#define CLUTTER_EFFECT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_EFFECT_NODE, ClutterEffectNode))
#define CLUTTER_IS_EFFECT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_EFFECT_NODE))
/**
* ClutterEffectNode:
*
* The #ClutterEffectNode structure is an opaque
* type whose members cannot be directly accessed.
*/
typedef struct _ClutterEffectNode ClutterEffectNode;
typedef struct _ClutterEffectNode ClutterEffectNodeClass;
CLUTTER_EXPORT
GType clutter_effect_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_effect_node_new (ClutterEffect *actor);
G_END_DECLS
#endif /* __CLUTTER_PAINT_NODE_PRIVATE_H__ */

View File

@ -551,7 +551,7 @@ clutter_pipeline_node_init (ClutterPipelineNode *self)
}
/**
* clutter_pipeline_node_new: (skip)
* clutter_pipeline_node_new:
* @pipeline: (allow-none): a Cogl pipeline state object, or %NULL
*
* Creates a new #ClutterPaintNode that will use the @pipeline to
@ -1115,6 +1115,8 @@ struct _ClutterActorNode
ClutterPaintNode parent_instance;
ClutterActor *actor;
int opacity_override;
int old_opacity_override;
};
struct _ClutterActorNodeClass
@ -1130,6 +1132,14 @@ clutter_actor_node_pre_draw (ClutterPaintNode *node,
{
ClutterActorNode *actor_node = CLUTTER_ACTOR_NODE (node);
if (actor_node->opacity_override != -1)
{
actor_node->old_opacity_override =
clutter_actor_get_opacity_override (actor_node->actor);
clutter_actor_set_opacity_override (actor_node->actor,
actor_node->opacity_override);
}
CLUTTER_SET_PRIVATE_FLAGS (actor_node->actor, CLUTTER_IN_PAINT);
return TRUE;
@ -1151,6 +1161,12 @@ clutter_actor_node_post_draw (ClutterPaintNode *node,
ClutterActorNode *actor_node = CLUTTER_ACTOR_NODE (node);
CLUTTER_UNSET_PRIVATE_FLAGS (actor_node->actor, CLUTTER_IN_PAINT);
if (actor_node->opacity_override != -1)
{
clutter_actor_set_opacity_override (actor_node->actor,
actor_node->old_opacity_override);
}
}
static JsonNode *
@ -1192,6 +1208,7 @@ clutter_actor_node_init (ClutterActorNode *self)
/*
* clutter_actor_node_new:
* @actor: the actor to paint
* @opacity: opacity to draw the actor with, or -1 to use the actor's opacity
*
* Creates a new #ClutterActorNode.
*
@ -1203,7 +1220,8 @@ clutter_actor_node_init (ClutterActorNode *self)
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_actor_node_new (ClutterActor *actor)
clutter_actor_node_new (ClutterActor *actor,
int opacity)
{
ClutterActorNode *res;
@ -1211,11 +1229,96 @@ clutter_actor_node_new (ClutterActor *actor)
res = _clutter_paint_node_create (CLUTTER_TYPE_ACTOR_NODE);
res->actor = actor;
res->opacity_override = CLAMP (opacity, -1, 255);
return (ClutterPaintNode *) res;
}
/*
* ClutterEffectNode
*/
struct _ClutterEffectNode
{
ClutterPaintNode parent_instance;
ClutterEffect *effect;
};
struct _ClutterEffectNodeClass
{
ClutterPaintNodeClass parent_class;
};
G_DEFINE_TYPE (ClutterEffectNode, clutter_effect_node, CLUTTER_TYPE_PAINT_NODE)
static JsonNode *
clutter_effect_node_serialize (ClutterPaintNode *node)
{
ClutterEffectNode *effect_node = CLUTTER_EFFECT_NODE (node);
ClutterActorMeta *effect_meta = CLUTTER_ACTOR_META (effect_node->effect);
g_autoptr (JsonBuilder) builder = NULL;
g_autoptr (GString) string = NULL;
const char *meta_name;
meta_name = clutter_actor_meta_get_name (effect_meta);
string = g_string_new (NULL);
g_string_append (string, G_OBJECT_TYPE_NAME (effect_node->effect));
g_string_append (string, " (");
if (meta_name)
g_string_append_printf (string, "\"%s\"", meta_name);
else
g_string_append (string, "unnamed");
g_string_append (string, ")");
builder = json_builder_new ();
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "effect");
json_builder_add_string_value (builder, string->str);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void
clutter_effect_node_class_init (ClutterEffectNodeClass *klass)
{
ClutterPaintNodeClass *node_class;
node_class = CLUTTER_PAINT_NODE_CLASS (klass);
node_class->serialize = clutter_effect_node_serialize;
}
static void
clutter_effect_node_init (ClutterEffectNode *self)
{
}
/*
* clutter_effect_node_new:
* @actor: the actor to paint
*
* Creates a new #ClutterEffectNode.
*
* Return value: (transfer full): the newly created #ClutterEffectNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_effect_node_new (ClutterEffect *effect)
{
ClutterEffectNode *res;
g_assert (effect != NULL);
res = _clutter_paint_node_create (CLUTTER_TYPE_EFFECT_NODE);
res->effect = effect;
return (ClutterPaintNode *) res;
}
/*
* ClutterLayerNode
*/
@ -1235,6 +1338,7 @@ struct _ClutterLayerNode
CoglFramebuffer *offscreen;
guint8 opacity;
gboolean update_modelview;
};
struct _ClutterLayerNodeClass
@ -1249,8 +1353,6 @@ clutter_layer_node_pre_draw (ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterLayerNode *lnode = (ClutterLayerNode *) node;
CoglFramebuffer *framebuffer;
CoglMatrix matrix;
/* if we were unable to create an offscreen buffer for this node, then
* we simply ignore it
@ -1258,18 +1360,16 @@ clutter_layer_node_pre_draw (ClutterPaintNode *node,
if (lnode->offscreen == NULL)
return FALSE;
/* if no geometry was submitted for this node then we simply ignore it */
if (node->operations == NULL)
return FALSE;
if (lnode->update_modelview)
{
CoglFramebuffer *framebuffer;
CoglMatrix matrix;
/* copy the same modelview from the current framebuffer to the one we
* are going to use
*/
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_get_modelview_matrix (framebuffer, &matrix);
clutter_paint_context_push_framebuffer (paint_context, lnode->offscreen);
cogl_framebuffer_set_modelview_matrix (lnode->offscreen, &matrix);
cogl_framebuffer_set_viewport (lnode->offscreen,
@ -1280,6 +1380,9 @@ clutter_layer_node_pre_draw (ClutterPaintNode *node,
cogl_framebuffer_set_projection_matrix (lnode->offscreen,
&lnode->projection);
}
clutter_paint_context_push_framebuffer (paint_context, lnode->offscreen);
/* clear out the target framebuffer */
cogl_framebuffer_clear4f (lnode->offscreen,
@ -1307,6 +1410,10 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
cogl_framebuffer_pop_matrix (lnode->offscreen);
clutter_paint_context_pop_framebuffer (paint_context);
/* if no geometry was submitted for this node then we simply ignore it */
if (node->operations == NULL)
return;
fb = clutter_paint_context_get_framebuffer (paint_context);
for (i = 0; i < node->operations->len; i++)
@ -1367,6 +1474,25 @@ clutter_layer_node_finalize (ClutterPaintNode *node)
CLUTTER_PAINT_NODE_CLASS (clutter_layer_node_parent_class)->finalize (node);
}
static JsonNode *
clutter_layer_node_serialize (ClutterPaintNode *node)
{
ClutterLayerNode *layer_node = CLUTTER_LAYER_NODE (node);
g_autoptr (JsonBuilder) builder = NULL;
g_autofree char *framebuffer_ptr = NULL;
builder = json_builder_new ();
framebuffer_ptr = g_strdup_printf ("%p", layer_node->offscreen);
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "framebuffer");
json_builder_add_string_value (builder, framebuffer_ptr);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void
clutter_layer_node_class_init (ClutterLayerNodeClass *klass)
{
@ -1376,6 +1502,7 @@ clutter_layer_node_class_init (ClutterLayerNodeClass *klass)
node_class->pre_draw = clutter_layer_node_pre_draw;
node_class->post_draw = clutter_layer_node_post_draw;
node_class->finalize = clutter_layer_node_finalize;
node_class->serialize = clutter_layer_node_serialize;
}
static void
@ -1418,6 +1545,7 @@ clutter_layer_node_new (const CoglMatrix *projection,
res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
res->update_modelview = TRUE;
res->projection = *projection;
res->viewport = *viewport;
res->fbo_width = width;
@ -1458,3 +1586,245 @@ out:
return (ClutterPaintNode *) res;
}
/**
* clutter_layer_node_new_with_framebuffer:
* @framebuffer: a #CoglFramebuffer
* @pipeline: a #CoglPipeline
* @opacity: the opacity to be used when drawing the layer
*
* Creates a new #ClutterLayerNode with @framebuffer and
* @pipeline. @framebuffer will then be painted using the
* given @opacity.
*
* When using this constructor, the caller is responsible
* for setting up the framebuffer's modelview and projection
* matrices.
*
* Return value: (transfer full)(nullable): the newly created #ClutterLayerNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_layer_node_new_with_framebuffer (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,
guint8 opacity)
{
ClutterLayerNode *res;
CoglColor color;
g_return_val_if_fail (cogl_is_framebuffer (framebuffer), NULL);
res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
res->update_modelview = FALSE;
res->offscreen = cogl_object_ref (framebuffer);
res->pipeline = cogl_pipeline_copy (pipeline);
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
cogl_pipeline_set_color (res->pipeline, &color);
return (ClutterPaintNode *) res;
}
/*
* ClutterBlitNode
*/
struct _ClutterBlitNode
{
ClutterPaintNode parent_instance;
CoglFramebuffer *source;
CoglFramebuffer *dest;
};
struct _ClutterBlitNodeClass
{
ClutterPaintNodeClass parent_class;
};
G_DEFINE_TYPE (ClutterBlitNode, clutter_blit_node, CLUTTER_TYPE_PAINT_NODE)
static gboolean
clutter_blit_node_pre_draw (ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
return TRUE;
}
static void
clutter_blit_node_draw (ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
g_autoptr (GError) error = NULL;
CoglFramebuffer *source;
guint i;
if (node->operations == NULL)
return;
source = blit_node->source;
if (!source)
source = clutter_paint_context_get_framebuffer (paint_context);
for (i = 0; i < node->operations->len; i++)
{
const ClutterPaintOperation *op;
float op_width, op_height;
op = &g_array_index (node->operations, ClutterPaintOperation, i);
switch (op->opcode)
{
case PAINT_OP_INVALID:
break;
case PAINT_OP_TEX_RECT:
op_width = op->op.texrect[6] - op->op.texrect[4];
op_height = op->op.texrect[7] - op->op.texrect[5];
cogl_blit_framebuffer (source,
blit_node->dest,
op->op.texrect[0],
op->op.texrect[1],
op->op.texrect[4],
op->op.texrect[5],
op_width,
op_height,
&error);
if (error)
{
g_warning ("Error blitting framebuffers: %s", error->message);
return;
}
break;
case PAINT_OP_MULTITEX_RECT:
case PAINT_OP_PRIMITIVE:
break;
}
}
}
static void
clutter_blit_node_finalize (ClutterPaintNode *node)
{
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
cogl_clear_object (&blit_node->source);
cogl_clear_object (&blit_node->dest);
CLUTTER_PAINT_NODE_CLASS (clutter_layer_node_parent_class)->finalize (node);
}
static JsonNode *
clutter_blit_node_serialize (ClutterPaintNode *node)
{
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
g_autoptr (JsonBuilder) builder = NULL;
g_autofree char *source_ptr = NULL;
g_autofree char *dest_ptr = NULL;
builder = json_builder_new ();
source_ptr = g_strdup_printf ("%p", blit_node->source);
dest_ptr = g_strdup_printf ("%p", blit_node->dest);
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "source");
json_builder_add_string_value (builder, source_ptr);
json_builder_end_object (builder);
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "dest");
json_builder_add_string_value (builder, dest_ptr);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void
clutter_blit_node_class_init (ClutterTransformNodeClass *klass)
{
ClutterPaintNodeClass *node_class;
node_class = CLUTTER_PAINT_NODE_CLASS (klass);
node_class->pre_draw = clutter_blit_node_pre_draw;
node_class->draw = clutter_blit_node_draw;
node_class->finalize = clutter_blit_node_finalize;
node_class->serialize = clutter_blit_node_serialize;
}
static void
clutter_blit_node_init (ClutterBlitNode *self)
{
}
/**
* clutter_blit_node_new:
* @source: (nullable): the source #CoglFramebuffer
* @dest: the destination #CoglFramebuffer
*
* Creates a new #ClutterBlitNode that blits @source into @dest.
*
* If @source is %NULL, the most recent framebuffer stacked into a
* #ClutterPaintContext is used.
*
* You must only add rectangles using clutter_blit_node_add_blit_rectangle().
*
* Return value: (transfer full): the newly created #ClutterBlitNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_blit_node_new (CoglFramebuffer *source,
CoglFramebuffer *dest)
{
ClutterBlitNode *res;
g_return_val_if_fail (cogl_is_framebuffer (dest), NULL);
res = _clutter_paint_node_create (CLUTTER_TYPE_BLIT_NODE);
res->source = source ? cogl_object_ref (source) : NULL;
res->dest = cogl_object_ref (dest);
return (ClutterPaintNode *) res;
}
/**
* clutter_blit_node_add_blit_rectangle:
* @blit_node: a #ClutterBlitNode
* @src_x: Source x position
* @src_y: Source y position
* @dst_x: Destination x position
* @dst_y: Destination y position
* @width: Width of region to copy
* @height: Height of region to copy
*
* Adds a new blit rectangle to the stack of rectangles. All the
* constraints of cogl_blit_framebuffer() apply here.
*/
void
clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height)
{
g_return_if_fail (CLUTTER_IS_BLIT_NODE (blit_node));
clutter_paint_node_add_texture_rectangle (CLUTTER_PAINT_NODE (blit_node),
&(ClutterActorBox) {
src_x,
src_y,
src_x + width,
src_y + height,
},
dst_x,
dst_y,
dst_x + width,
dst_y + height);
}

View File

@ -160,7 +160,8 @@ CLUTTER_EXPORT
GType clutter_actor_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_actor_node_new (ClutterActor *actor);
ClutterPaintNode * clutter_actor_node_new (ClutterActor *actor,
int opacity);
#define CLUTTER_TYPE_ROOT_NODE (clutter_root_node_get_type ())
#define CLUTTER_ROOT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ROOT_NODE, ClutterRootNode))
@ -208,6 +209,11 @@ ClutterPaintNode * clutter_layer_node_new (const CoglMatrix
float height,
guint8 opacity);
CLUTTER_EXPORT
ClutterPaintNode * clutter_layer_node_new_with_framebuffer (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,
guint8 opacity);
#define CLUTTER_TYPE_TRANSFORM_NODE (clutter_transform_node_get_type ())
#define CLUTTER_TRANSFORM_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TRANSFORM_NODE, ClutterTransformNode))
@ -230,6 +236,38 @@ GType clutter_transform_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_transform_node_new (const CoglMatrix *projection);
#define CLUTTER_TYPE_BLIT_NODE (clutter_blit_node_get_type ())
#define CLUTTER_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BLIT_NODE, ClutterBlitNode))
#define CLUTTER_IS_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BLIT_NODE))
/*
* ClutterBlitNode:
*
* The #ClutterLayerNode structure is an opaque
* type whose members cannot be directly accessed.
*
* Since: 1.10
*/
typedef struct _ClutterBlitNode ClutterBlitNode;
typedef struct _ClutterPaintNodeClass ClutterBlitNodeClass;
CLUTTER_EXPORT
GType clutter_blit_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_blit_node_new (CoglFramebuffer *source,
CoglFramebuffer *dest);
CLUTTER_EXPORT
void clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height);
G_END_DECLS
#endif /* __CLUTTER_PAINT_NODES_H__ */

View File

@ -384,12 +384,13 @@ clutter_shader_effect_try_static_source (ClutterShaderEffect *self)
static void
clutter_shader_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterShaderEffect *self = CLUTTER_SHADER_EFFECT (effect);
ClutterShaderEffectPrivate *priv = self->priv;
ClutterOffscreenEffectClass *parent;
CoglHandle material;
CoglPipeline *pipeline;
/* If the source hasn't been set then we'll try to get it from the
static source instead */
@ -407,14 +408,14 @@ clutter_shader_effect_paint_target (ClutterOffscreenEffect *effect,
clutter_shader_effect_update_uniforms (CLUTTER_SHADER_EFFECT (effect));
/* associate the program to the offscreen target material */
material = clutter_offscreen_effect_get_target (effect);
cogl_pipeline_set_user_program (material, priv->program);
/* associate the program to the offscreen target pipeline */
pipeline = clutter_offscreen_effect_get_pipeline (effect);
cogl_pipeline_set_user_program (pipeline, priv->program);
out:
/* paint the offscreen buffer */
parent = CLUTTER_OFFSCREEN_EFFECT_CLASS (clutter_shader_effect_parent_class);
parent->paint_target (effect, paint_context);
parent->paint_target (effect, node, paint_context);
}

View File

@ -37,6 +37,7 @@ G_DEFINE_TYPE (FooOldShaderEffect,
static void
foo_old_shader_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
clutter_shader_effect_set_shader_source (CLUTTER_SHADER_EFFECT (effect),
@ -47,7 +48,7 @@ foo_old_shader_effect_paint_target (ClutterOffscreenEffect *effect,
1.0f, 0.0f, 0.0f);
CLUTTER_OFFSCREEN_EFFECT_CLASS (foo_old_shader_effect_parent_class)->
paint_target (effect, paint_context);
paint_target (effect, node, paint_context);
}
static void
@ -112,6 +113,7 @@ foo_new_shader_effect_get_static_source (ClutterShaderEffect *effect)
static void
foo_new_shader_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect),
@ -120,7 +122,7 @@ foo_new_shader_effect_paint_target (ClutterOffscreenEffect *effect,
0.0f, 1.0f, 0.0f);
CLUTTER_OFFSCREEN_EFFECT_CLASS (foo_new_shader_effect_parent_class)->
paint_target (effect, paint_context);
paint_target (effect, node, paint_context);
}
static void