static void
clutter_deform_effect_set_property (GObject      *gobject,
                                    guint         prop_id,
                                    const GValue *value,
                                    GParamSpec   *pspec)
{
  ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject);

  switch (prop_id)
    {
    case PROP_X_TILES:
      clutter_deform_effect_set_n_tiles (self, g_value_get_uint (value),
                                         self->priv->y_tiles);
      break;

    case PROP_Y_TILES:
      clutter_deform_effect_set_n_tiles (self, self->priv->x_tiles,
                                         g_value_get_uint (value));
      break;

    case PROP_BACK_MATERIAL:
      clutter_deform_effect_set_back_material (self, g_value_get_boxed (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
    }
}
static void
clutter_deform_effect_get_property (GObject    *gobject,
                                    guint       prop_id,
                                    GValue     *value,
                                    GParamSpec *pspec)
{
  ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (gobject)->priv;

  switch (prop_id)
    {
    case PROP_X_TILES:
      g_value_set_uint (value, priv->x_tiles);
      break;

    case PROP_Y_TILES:
      g_value_set_uint (value, priv->y_tiles);
      break;

    case PROP_BACK_MATERIAL:
      g_value_set_boxed (value, priv->back_pipeline);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
    }
}
static void
clutter_deform_effect_set_actor (ClutterActorMeta *meta,
                                 ClutterActor     *actor)
{
  ClutterDeformEffectPrivate *priv = CLUTTER_DEFORM_EFFECT (meta)->priv;

  if (priv->allocation_id != 0)
    {
      ClutterActor *old_actor = clutter_actor_meta_get_actor (meta);

      if (old_actor != NULL)
        g_signal_handler_disconnect (old_actor, priv->allocation_id);

      priv->allocation_id = 0;
    }

  /* we need to invalidate the VBO whenever the allocation of the actor
   * changes
   */
  if (actor != NULL)
    priv->allocation_id = g_signal_connect (actor, "allocation-changed",
                                            G_CALLBACK (vbo_invalidate),
                                            meta);

  priv->is_dirty = TRUE;

  CLUTTER_ACTOR_META_CLASS (clutter_deform_effect_parent_class)->set_actor (meta, actor);
}
static void
clutter_deform_effect_finalize (GObject *gobject)
{
  ClutterDeformEffect *self = CLUTTER_DEFORM_EFFECT (gobject);

  clutter_deform_effect_free_arrays (self);
  clutter_deform_effect_free_back_pipeline (self);

  G_OBJECT_CLASS (clutter_deform_effect_parent_class)->finalize (gobject);
}
/**
 * clutter_page_turn_effect_set_radius:
 * @effect: a #ClutterPageTurnEffect:
 * @radius: the radius of the page curling, in pixels
 *
 * Sets the radius of the page curling
 *
 * Since: 1.4
 */
void
clutter_page_turn_effect_set_radius (ClutterPageTurnEffect *effect,
                                     gfloat                 radius)
{
  g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect));

  effect->radius = radius;

  clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect));

  g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_RADIUS]);
}
/**
 * clutter_page_turn_effect_set_angle:
 * @effect: #ClutterPageTurnEffect
 * @angle: the angle of the page curl, in degrees
 *
 * Sets the angle of the page curling, in degrees
 *
 * Since: 1.4
 */
void
clutter_page_turn_effect_set_angle (ClutterPageTurnEffect *effect,
                                    gdouble                angle)
{
  g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect));
  g_return_if_fail (angle >= 0.0 && angle <= 360.0);

  effect->angle = angle;

  clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect));

  g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_ANGLE]);
}
/**
 * clutter_page_turn_effect_set_period:
 * @effect: a #ClutterPageTurnEffect
 * @period: the period of the page curl, between 0.0 and 1.0
 *
 * Sets the period of the page curling, between 0.0 (no curling)
 * and 1.0 (fully curled)
 *
 * Since: 1.4
 */
void
clutter_page_turn_effect_set_period (ClutterPageTurnEffect *effect,
                                     gdouble                period)
{
  g_return_if_fail (CLUTTER_IS_PAGE_TURN_EFFECT (effect));
  g_return_if_fail (period >= 0.0 && period <= 1.0);

  effect->period = period;

  clutter_deform_effect_invalidate (CLUTTER_DEFORM_EFFECT (effect));

  g_object_notify_by_pspec (G_OBJECT (effect), obj_props[PROP_PERIOD]);
}
static void
clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect)
{
  ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect);
  ClutterDeformEffectPrivate *priv = self->priv;
  CoglHandle material;
  CoglPipeline *pipeline;
  CoglDepthState depth_state;
  CoglFramebuffer *fb = cogl_get_draw_framebuffer ();

  if (priv->is_dirty)
    {
      ClutterRect rect;
      gboolean mapped_buffer;
      CoglVertexP3T2C4 *verts;
      ClutterActor *actor;
      gfloat width, height;
      guint opacity;
      gint i, j;

      actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
      opacity = clutter_actor_get_paint_opacity (actor);

      /* 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 = clutter_rect_get_width (&rect);
          height = clutter_rect_get_height (&rect);
        }
      else
        clutter_actor_get_size (actor, &width, &height);

      /* XXX ideally, the sub-classes should tell us what they
       * changed in the texture vertices; we then would be able to
       * avoid resubmitting the same data, if it did not change. for
       * the time being, we resubmit everything
       */
      verts = cogl_buffer_map (COGL_BUFFER (priv->buffer),
                               COGL_BUFFER_ACCESS_WRITE,
                               COGL_BUFFER_MAP_HINT_DISCARD);

      /* If the map failed then we'll resort to allocating a temporary
         buffer */
      if (verts == NULL)
        {
          mapped_buffer = FALSE;
          verts = g_malloc (sizeof (*verts) * priv->n_vertices);
        }
      else
        mapped_buffer = TRUE;

      for (i = 0; i < priv->y_tiles + 1; i++)
        {
          for (j = 0; j < priv->x_tiles + 1; j++)
            {
              CoglVertexP3T2C4 *vertex_out;
              CoglTextureVertex vertex;

              /* CoglTextureVertex isn't an ideal structure to use for
                 this because it contains a CoglColor. The internal
                 layout of CoglColor is mean to be private so Clutter
                 can not pass a pointer to it as a vertex
                 attribute. Also it contains padding so we end up
                 storing more data in the vertex buffer than we need
                 to. Instead we let the application modify a dummy
                 vertex and then copy the details back out to a more
                 well-defined struct */

              vertex.tx = (float) j / priv->x_tiles;
              vertex.ty = (float) i / priv->y_tiles;

              vertex.x = width * vertex.tx;
              vertex.y = height * vertex.ty;
              vertex.z = 0.0f;

              cogl_color_init_from_4ub (&vertex.color, 255, 255, 255, opacity);

              clutter_deform_effect_deform_vertex (self,
                                                   width, height,
                                                   &vertex);

              vertex_out = verts + i * (priv->x_tiles + 1) + j;

              vertex_out->x = vertex.x;
              vertex_out->y = vertex.y;
              vertex_out->z = vertex.z;
              vertex_out->s = vertex.tx;
              vertex_out->t = vertex.ty;
              vertex_out->r = cogl_color_get_red_byte (&vertex.color);
              vertex_out->g = cogl_color_get_green_byte (&vertex.color);
              vertex_out->b = cogl_color_get_blue_byte (&vertex.color);
              vertex_out->a = cogl_color_get_alpha_byte (&vertex.color);
            }
        }

      if (mapped_buffer)
        cogl_buffer_unmap (COGL_BUFFER (priv->buffer));
      else
        {
          cogl_buffer_set_data (COGL_BUFFER (priv->buffer),
                                0, /* offset */
                                verts,
                                sizeof (*verts) * priv->n_vertices);
          g_free (verts);
        }

      priv->is_dirty = FALSE;
    }

  material = clutter_offscreen_effect_get_target (effect);
  pipeline = COGL_PIPELINE (material);

  /* enable depth testing */
  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_test_enabled (&depth_state, TRUE);
  cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL);

  /* enable backface culling if we have a back material */
  if (priv->back_pipeline != NULL)
    cogl_pipeline_set_cull_face_mode (pipeline,
                                      COGL_PIPELINE_CULL_FACE_MODE_BACK);

  /* draw the front */
  if (material != NULL)
    cogl_framebuffer_draw_primitive (fb, pipeline, priv->primitive);

  /* draw the back */
  if (priv->back_pipeline != NULL)
    {
      CoglPipeline *back_pipeline;

      /* We probably shouldn't be modifying the user's material so
         instead we make a temporary copy */
      back_pipeline = cogl_pipeline_copy (priv->back_pipeline);
      cogl_pipeline_set_depth_state (back_pipeline, &depth_state, NULL);
      cogl_pipeline_set_cull_face_mode (back_pipeline,
                                        COGL_PIPELINE_CULL_FACE_MODE_FRONT);

      cogl_framebuffer_draw_primitive (fb, back_pipeline, priv->primitive);

      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);
    }
}
Beispiel #9
0
static void
clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect)
{
  ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect);
  ClutterDeformEffectPrivate *priv = self->priv;
  gboolean is_depth_enabled, is_cull_enabled;
  CoglHandle material;
  gint n_tiles;

  if (priv->is_dirty)
    {
      ClutterActor *actor;
      gfloat width, height;
      guint opacity;
      gint i, j;

      actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
      opacity = clutter_actor_get_paint_opacity (actor);

      /* 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_size (effect, &width, &height))
        clutter_actor_get_size (actor, &width, &height);

      for (i = 0; i < priv->y_tiles + 1; i++)
        {
          for (j = 0; j < priv->x_tiles + 1; j++)
            {
              CoglTextureVertex *vertex;

              vertex = &priv->vertices[(i * (priv->x_tiles + 1)) + j];

              vertex->tx = (float) j / priv->x_tiles;
              vertex->ty = (float) i / priv->y_tiles;

              vertex->x = width * vertex->tx;
              vertex->y = height * vertex->ty;
              vertex->z = 0.0f;

              cogl_color_init_from_4ub (&vertex->color, 255, 255, 255, opacity);

              _clutter_deform_effect_deform_vertex (self, width, height, vertex);
            }
        }

      /* XXX in theory, the sub-classes should tell us what they changed
       * in the texture vertices; we then would be able to avoid resubmitting
       * the same data, if it did not change. for the time being, we resubmit
       * everything
       */
      cogl_vertex_buffer_add (priv->vbo, "gl_Vertex",
                              3,
                              COGL_ATTRIBUTE_TYPE_FLOAT,
                              FALSE,
                              sizeof (CoglTextureVertex),
                              &priv->vertices->x);
      cogl_vertex_buffer_add (priv->vbo, "gl_MultiTexCoord0",
                              2,
                              COGL_ATTRIBUTE_TYPE_FLOAT,
                              FALSE,
                              sizeof (CoglTextureVertex),
                              &priv->vertices->tx);
      cogl_vertex_buffer_add (priv->vbo, "gl_Color",
                              4,
                              COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE,
                              FALSE,
                              sizeof (CoglTextureVertex),
                              &priv->vertices->color);

      priv->is_dirty = FALSE;
    }

  /* enable depth test, if it's not already enabled */
  is_depth_enabled = cogl_get_depth_test_enabled ();
  if (!is_depth_enabled)
    cogl_set_depth_test_enabled (TRUE);

  /* enable backface culling if it's not already enabled and if
   * we have a back material
   */
  is_cull_enabled = cogl_get_backface_culling_enabled ();
  if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled)
    cogl_set_backface_culling_enabled (TRUE);
  else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled)
    cogl_set_backface_culling_enabled (FALSE);

  n_tiles = (priv->x_tiles + 1) * (priv->y_tiles + 1);

  /* draw the front */
  material = clutter_offscreen_effect_get_target (effect);
  if (material != COGL_INVALID_HANDLE)
    {
      cogl_set_source (material);
      cogl_vertex_buffer_draw_elements (priv->vbo,
                                        COGL_VERTICES_MODE_TRIANGLE_STRIP,
                                        priv->indices,
                                        0,
                                        n_tiles,
                                        0,
                                        priv->n_indices);
    }

  /* draw the back */
  material = priv->back_material;
  if (material != COGL_INVALID_HANDLE)
    {
      cogl_set_source (priv->back_material);
      cogl_vertex_buffer_draw_elements (priv->vbo,
                                        COGL_VERTICES_MODE_TRIANGLE_STRIP,
                                        priv->back_indices,
                                        0,
                                        n_tiles,
                                        0,
                                        priv->n_indices);
    }

  /* restore the previous state */
  if (!is_depth_enabled)
    cogl_set_depth_test_enabled (FALSE);

  if (priv->back_material != COGL_INVALID_HANDLE && !is_cull_enabled)
    cogl_set_backface_culling_enabled (FALSE);
  else if (priv->back_material == COGL_INVALID_HANDLE && is_cull_enabled)
    cogl_set_backface_culling_enabled (TRUE);
}