Beispiel #1
0
void
_clutter_stage_wayland_repaint_region (ClutterStageWayland *stage_wayland,
				       ClutterStage        *stage)
{
  ClutterGeometry geom;
  cairo_rectangle_int_t rect;
  int i, count;

  count = cairo_region_num_rectangles (stage_wayland->repaint_region);
  for (i = 0; i < count; i++)
    {
      cairo_region_get_rectangle (stage_wayland->repaint_region, i, &rect);

      cogl_clip_push_window_rectangle (rect.x - 1, rect.y - 1,
				       rect.width + 2, rect.height + 2);

      geom.x = rect.x;
      geom.y = rect.y;
      geom.width = rect.width;
      geom.height = rect.height;
      /* FIXME: We should pass geom in as second arg, but some actors
       * cull themselves a little to much.  Disable for now.*/
      _clutter_stage_do_paint (stage, NULL);

      cogl_clip_pop ();
    }
}
static void
mx_stack_paint_children (ClutterActor *actor)
{
  MxStackPrivate *priv = MX_STACK (actor)->priv;

  GList *c;

  for (c = priv->children; c; c = c->next)
    {
      ClutterActor *child = c->data;
      gboolean crop;

      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
        continue;

      clutter_container_child_get (CLUTTER_CONTAINER (actor),
                                   child,
                                   "crop", &crop,
                                   NULL);

      if (crop)
        {
          /* clip */
          cogl_clip_push_rectangle (priv->allocation.x1,
                                    priv->allocation.y1,
                                    priv->allocation.x2,
                                    priv->allocation.y2);
          clutter_actor_paint (c->data);
          cogl_clip_pop ();
        }
      else
        clutter_actor_paint (c->data);
    }
}
Beispiel #3
0
static void
empathy_rounded_effect_paint (ClutterEffect *effect,
    ClutterEffectPaintFlags flags)
{
  EmpathyRoundedEffect *self = EMPATHY_ROUNDED_EFFECT (effect);
  ClutterActor *actor;
  ClutterActorBox allocation = { 0, };
  gfloat width, height;

  actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self));
  clutter_actor_get_allocation_box (actor, &allocation);
  clutter_actor_box_get_size (&allocation, &width, &height);

  cogl_path_new ();

  /* Create and store a path describing a rounded rectangle. The small
   * size of the preview window makes the radius of the rounded corners
   * very small too, so we can safely use a very coarse angle step
   * without loosing rendering accuracy. It also significantly reduces
   * the time spent in the underlying internal cogl path functions */
  cogl_path_round_rectangle (0, 0, width, height, height / 16., 15);

  cogl_clip_push_from_path ();

  /* Flip */
  cogl_push_matrix ();
  cogl_translate (width, 0, 0);
  cogl_scale (-1, 1, 1);

  clutter_actor_continue_paint (actor);

  cogl_pop_matrix ();
  cogl_clip_pop ();
}
Beispiel #4
0
static void
mex_column_paint (ClutterActor *actor)
{
  GList *c;
  MxPadding padding;
  ClutterActorBox box;

  MexColumn *self = MEX_COLUMN (actor);
  MexColumnPrivate *priv = self->priv;

  CLUTTER_ACTOR_CLASS (mex_column_parent_class)->paint (actor);

  mx_widget_get_padding (MX_WIDGET (actor), &padding);
  clutter_actor_get_allocation_box (actor, &box);

  cogl_clip_push_rectangle (padding.left,
                            padding.top + priv->adjustment_value,
                            box.x2 - box.x1 - padding.right,
                            box.y2 - box.y1 - padding.bottom +
                            priv->adjustment_value);

  for (c = priv->children; c; c = c->next)
    {
      /* skip the current focus and paint it last*/
      if (priv->current_focus != c->data)
        clutter_actor_paint (c->data);
    }

  /* paint the current focused actor last to ensure any shadow is drawn
   * on top of other items */
  if (priv->current_focus)
    clutter_actor_paint (priv->current_focus);

  cogl_clip_pop ();
}
Beispiel #5
0
static void
mex_column_pick (ClutterActor *actor, const ClutterColor *color)
{
  GList *c;
  gdouble value;
  MxPadding padding;
  ClutterActorBox box;

  MexColumn *self = MEX_COLUMN (actor);
  MexColumnPrivate *priv = self->priv;

  CLUTTER_ACTOR_CLASS (mex_column_parent_class)->pick (actor, color);

  /* Don't pick children when we don't have focus */
  if (!priv->has_focus)
    return;

  mx_widget_get_padding (MX_WIDGET (actor), &padding);
  clutter_actor_get_allocation_box (actor, &box);
  if (priv->adjustment)
    value = priv->adjustment_value;
  else
    value = 0;

  cogl_clip_push_rectangle (padding.left,
                            padding.top + value,
                            box.x2 - box.x1 - padding.right,
                            box.y2 - box.y1 - padding.bottom + value);

  for (c = priv->children; c; c = c->next)
    clutter_actor_paint (c->data);

  cogl_clip_pop ();
}
static void
mex_content_box_paint (ClutterActor *actor)
{
  MexContentBoxPrivate *priv = MEX_CONTENT_BOX (actor)->priv;
  gboolean clipped = FALSE;

  CLUTTER_ACTOR_CLASS (mex_content_box_parent_class)->paint (actor);

  if (G_UNLIKELY (priv->clip_to_allocation))
    {
      ClutterActorBox box;
      clutter_actor_get_allocation_box (actor, &box);
      cogl_clip_push_rectangle (0, 0, box.x2 - box.x1, box.y2 - box.y1);
      clipped = TRUE;
    }

  clutter_actor_paint (priv->tile);

  if (G_UNLIKELY (priv->extras_visible))
    {
      ClutterActorBox box;

      clutter_actor_paint (priv->action_list);
      clutter_actor_paint (priv->info_panel);

      /* separator */
      cogl_set_source_color4ub (255, 255, 255, 51);
      clutter_actor_get_allocation_box (priv->info_panel, &box);
      cogl_path_line (box.x1, box.y1, box.x2, box.y1);
      cogl_path_stroke ();
    }

  if (G_UNLIKELY (clipped))
    cogl_clip_pop ();
}
Beispiel #7
0
static void
st_box_layout_paint (ClutterActor *actor)
{
  StBoxLayout *self = ST_BOX_LAYOUT (actor);
  StBoxLayoutPrivate *priv = self->priv;
  StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
  GList *l, *children;
  gdouble x, y;
  ClutterActorBox allocation_box;
  ClutterActorBox content_box;

  get_border_paint_offsets (self, &x, &y);
  if (x != 0 || y != 0)
    {
      cogl_push_matrix ();
      cogl_translate ((int)x, (int)y, 0);
    }

  CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->paint (actor);

  if (x != 0 || y != 0)
    {
      cogl_pop_matrix ();
    }

  children = st_container_get_children_list (ST_CONTAINER (actor));

  if (children == NULL)
    return;

  clutter_actor_get_allocation_box (actor, &allocation_box);
  st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);

  content_box.x1 += x;
  content_box.y1 += y;
  content_box.x2 += x;
  content_box.y2 += y;

  /* The content area forms the viewport into the scrolled contents, while
   * the borders and background stay in place; after drawing the borders and
   * background, we clip to the content area */
  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_push_rectangle ((int)content_box.x1,
                              (int)content_box.y1,
                              (int)content_box.x2,
                              (int)content_box.y2);

  for (l = children; l; l = g_list_next (l))
    {
      ClutterActor *child = (ClutterActor*) l->data;

      if (CLUTTER_ACTOR_IS_VISIBLE (child))
        clutter_actor_paint (child);
    }

  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_pop ();
}
static void
st_box_layout_paint (ClutterActor *actor)
{
  StBoxLayout *self = ST_BOX_LAYOUT (actor);
  StBoxLayoutPrivate *priv = self->priv;
  StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
  gdouble x, y;
  ClutterActorBox allocation_box;
  ClutterActorBox content_box;
  ClutterActor *child;

  get_border_paint_offsets (self, &x, &y);
  if (x != 0 || y != 0)
    {
      cogl_push_matrix ();
      cogl_translate ((int)x, (int)y, 0);
    }

  st_widget_paint_background (ST_WIDGET (actor));

  if (x != 0 || y != 0)
    {
      cogl_pop_matrix ();
    }

  if (clutter_actor_get_n_children (actor) == 0)
    return;

  clutter_actor_get_allocation_box (actor, &allocation_box);
  st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);

  content_box.x1 += x;
  content_box.y1 += y;
  content_box.x2 += x;
  content_box.y2 += y;

  /* The content area forms the viewport into the scrolled contents, while
   * the borders and background stay in place; after drawing the borders and
   * background, we clip to the content area */
  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_push_rectangle ((int)content_box.x1,
                              (int)content_box.y1,
                              (int)content_box.x2,
                              (int)content_box.y2);

  for (child = clutter_actor_get_first_child (actor);
       child != NULL;
       child = clutter_actor_get_next_sibling (child))
    clutter_actor_paint (child);

  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_pop ();
}
static void
st_box_layout_pick (ClutterActor       *actor,
                    const ClutterColor *color)
{
  StBoxLayout *self = ST_BOX_LAYOUT (actor);
  StBoxLayoutPrivate *priv = self->priv;
  StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
  gdouble x, y;
  ClutterActorBox allocation_box;
  ClutterActorBox content_box;
  ClutterActor *child;

  get_border_paint_offsets (self, &x, &y);
  if (x != 0 || y != 0)
    {
      cogl_push_matrix ();
      cogl_translate ((int)x, (int)y, 0);
    }

  CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->pick (actor, color);

  if (x != 0 || y != 0)
    {
      cogl_pop_matrix ();
    }

  if (clutter_actor_get_n_children (actor) == 0)
    return;

  clutter_actor_get_allocation_box (actor, &allocation_box);
  st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);

  content_box.x1 += x;
  content_box.y1 += y;
  content_box.x2 += x;
  content_box.y2 += y;

  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_push_rectangle ((int)content_box.x1,
                              (int)content_box.y1,
                              (int)content_box.x2,
                              (int)content_box.y2);

  for (child = clutter_actor_get_first_child (actor);
       child != NULL;
       child = clutter_actor_get_next_sibling (child))
    clutter_actor_paint (child);

  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_pop ();
}
static void
mex_grid_view_paint (ClutterActor *actor)
{
  MexGridViewPrivate *priv = MEX_GRID_VIEW (actor)->priv;
  ClutterActorBox gbox, mbox;

  CLUTTER_ACTOR_CLASS (mex_grid_view_parent_class)->paint (actor);

  clutter_actor_get_allocation_box (priv->menu_layout, &mbox);
  clutter_actor_get_allocation_box (priv->grid_layout, &gbox);

  cogl_clip_push_rectangle (mbox.x2, mbox.y1, gbox.x2, gbox.y2);

  clutter_actor_paint (priv->grid_layout);

  cogl_clip_pop ();

  clutter_actor_paint (priv->menu_layout);
}
static void
shell_slicer_paint_child (ShellSlicer *self)
{
  ClutterActor *child;
  ClutterActorBox self_box;
  ClutterActorBox child_box;
  float width, height, child_width, child_height;
  StAlign x_align, y_align;
  double x_align_factor, y_align_factor;

  child = st_bin_get_child (ST_BIN (self));

  if (!child)
    return;

  st_bin_get_alignment (ST_BIN (self), &x_align, &y_align);
  _st_get_align_factors (x_align, y_align,
                         &x_align_factor, &y_align_factor);

  clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &self_box);
  clutter_actor_get_allocation_box (child, &child_box);

  width = self_box.x2 - self_box.x1;
  height = self_box.y2 - self_box.y1;
  child_width = child_box.x2 - child_box.x1;
  child_height = child_box.y2 - child_box.y1;

  cogl_push_matrix ();

  cogl_clip_push_rectangle (0, 0, width, height);
  cogl_translate ((int)(0.5 + x_align_factor * (width - child_width)),
                  (int)(0.5 + y_align_factor * (height - child_height)),
                  0);

  clutter_actor_paint (child);

  cogl_clip_pop ();

  cogl_pop_matrix ();
}
Beispiel #12
0
static void
empathy_rounded_actor_paint (ClutterActor *actor)
{
  EmpathyRoundedActor *self = EMPATHY_ROUNDED_ACTOR (actor);
  ClutterActorBox allocation = { 0, };
  gfloat width, height;

  clutter_actor_get_allocation_box (actor, &allocation);
  clutter_actor_box_get_size (&allocation, &width, &height);

  cogl_path_new ();

  /* create and store a path describing a rounded rectangle */
  cogl_path_round_rectangle (0, 0, width, height,
      height / self->priv->round_factor, 0.1);

  cogl_clip_push_from_path ();

  CLUTTER_ACTOR_CLASS (empathy_rounded_actor_parent_class)->paint (actor);

  cogl_clip_pop ();
}
Beispiel #13
0
static void
clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
{
  ClutterBackendX11 *backend_x11;
  ClutterBackendGLX *backend_glx;
  ClutterStageX11 *stage_x11;
  ClutterStageGLX *stage_glx;
  GLXDrawable drawable;
  unsigned int video_sync_count;
  gboolean may_use_clipped_redraw;
  gboolean use_clipped_redraw;

  CLUTTER_STATIC_TIMER (painting_timer,
                        "Redrawing", /* parent */
                        "Painting actors",
                        "The time spent painting actors",
                        0 /* no application private data */);
  CLUTTER_STATIC_TIMER (swapbuffers_timer,
                        "Redrawing", /* parent */
                        "glXSwapBuffers",
                        "The time spent blocked by glXSwapBuffers",
                        0 /* no application private data */);
  CLUTTER_STATIC_TIMER (blit_sub_buffer_timer,
                        "Redrawing", /* parent */
                        "glx_blit_sub_buffer",
                        "The time spent in _glx_blit_sub_buffer",
                        0 /* no application private data */);

  stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  if (stage_x11->xwin == None)
    return;

  stage_glx = CLUTTER_STAGE_GLX (stage_window);

  backend_x11 = stage_x11->backend;
  backend_glx = CLUTTER_BACKEND_GLX (backend_x11);

  CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);

  if (G_LIKELY (backend_glx->can_blit_sub_buffer) &&
      /* NB: a zero width redraw clip == full stage redraw */
      stage_glx->bounding_redraw_clip.width != 0 &&
      /* some drivers struggle to get going and produce some junk
       * frames when starting up... */
      G_LIKELY (stage_glx->frame_count > 3) &&
      /* While resizing a window clipped redraws are disabled to avoid
       * artefacts. See clutter-event-x11.c:event_translate for a
       * detailed explanation */
      G_LIKELY (stage_x11->clipped_redraws_cool_off == 0))
    {
      may_use_clipped_redraw = TRUE;
    }
  else
    may_use_clipped_redraw = FALSE;

  if (may_use_clipped_redraw &&
      G_LIKELY (!(clutter_paint_debug_flags &
                  CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
    use_clipped_redraw = TRUE;
  else
    use_clipped_redraw = FALSE;

  if (use_clipped_redraw)
    {
      CLUTTER_NOTE (CLIPPING,
                    "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
                    stage_glx->bounding_redraw_clip.x,
                    stage_glx->bounding_redraw_clip.y,
                    stage_glx->bounding_redraw_clip.width,
                    stage_glx->bounding_redraw_clip.height);
      cogl_clip_push_window_rectangle (stage_glx->bounding_redraw_clip.x,
                                       stage_glx->bounding_redraw_clip.y,
                                       stage_glx->bounding_redraw_clip.width,
                                       stage_glx->bounding_redraw_clip.height);
      _clutter_stage_do_paint (stage_x11->wrapper,
                               &stage_glx->bounding_redraw_clip);
      cogl_clip_pop ();
    }
  else
    {
      CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n");
      _clutter_stage_do_paint (stage_x11->wrapper, NULL);
    }

  if (may_use_clipped_redraw &&
      G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
    {
      static CoglMaterial *outline = NULL;
      ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
      ClutterActor *actor = CLUTTER_ACTOR (stage_x11->wrapper);
      CoglHandle vbo;
      float x_1 = clip->x;
      float x_2 = clip->x + clip->width;
      float y_1 = clip->y;
      float y_2 = clip->y + clip->height;
      float quad[8] = {
        x_1, y_1,
        x_2, y_1,
        x_2, y_2,
        x_1, y_2
      };
      CoglMatrix modelview;

      if (outline == NULL)
        {
          outline = cogl_material_new ();
          cogl_material_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff);
        }

      vbo = cogl_vertex_buffer_new (4);
      cogl_vertex_buffer_add (vbo,
                              "gl_Vertex",
                              2, /* n_components */
                              COGL_ATTRIBUTE_TYPE_FLOAT,
                              FALSE, /* normalized */
                              0, /* stride */
                              quad);
      cogl_vertex_buffer_submit (vbo);

      cogl_push_matrix ();
      cogl_matrix_init_identity (&modelview);
      _clutter_actor_apply_modelview_transform (actor, &modelview);
      cogl_set_modelview_matrix (&modelview);
      cogl_set_source (outline);
      cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP,
                               0 , 4);
      cogl_pop_matrix ();
      cogl_object_unref (vbo);
    }

  cogl_flush ();
  CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);

  drawable = stage_glx->glxwin
           ? stage_glx->glxwin
           : stage_x11->xwin;

  /* If we might ever use _clutter_backend_glx_blit_sub_buffer then we
   * always need to keep track of the video_sync_count so that we can
   * throttle blits.
   *
   * Note: we get the count *before* we issue any glXCopySubBuffer or
   * blit_sub_buffer request in case the count would go up before
   * returning control to us.
   */
  if (backend_glx->can_blit_sub_buffer && backend_glx->get_video_sync)
    backend_glx->get_video_sync (&video_sync_count);

  /* push on the screen */
  if (use_clipped_redraw)
    {
      ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
      ClutterGeometry copy_area;
      ClutterActor *actor;

      CLUTTER_NOTE (BACKEND,
                    "_glx_blit_sub_buffer (window: 0x%lx, "
                                          "x: %d, y: %d, "
                                          "width: %d, height: %d)",
                    (unsigned long) drawable,
                    stage_glx->bounding_redraw_clip.x,
                    stage_glx->bounding_redraw_clip.y,
                    stage_glx->bounding_redraw_clip.width,
                    stage_glx->bounding_redraw_clip.height);

      /* XXX: It seems there will be a race here in that the stage
       * window may be resized before glXCopySubBufferMESA is handled
       * and so we may copy the wrong region. I can't really see how
       * we can handle this with the current state of X but at least
       * in this case a full redraw should be queued by the resize
       * anyway so it should only exhibit temporary artefacts.
       */
      actor = CLUTTER_ACTOR (stage_x11->wrapper);
      copy_area.y = clutter_actor_get_height (actor)
                  - clip->y
                  - clip->height;
      copy_area.x = clip->x;
      copy_area.width = clip->width;
      copy_area.height = clip->height;

      /* glXCopySubBufferMESA and glBlitFramebuffer are not integrated
       * with the glXSwapIntervalSGI mechanism which we usually use to
       * throttle the Clutter framerate to the vertical refresh and so
       * we have to manually wait for the vblank period...
       */

      /* Here 'is_synchronized' only means that the blit won't cause a
       * tear, ie it won't prevent multiple blits per retrace if they
       * can all be performed in the blanking period. If that's the
       * case then we still want to use the vblank sync menchanism but
       * we only need it to throttle redraws.
       */
      if (!backend_glx->blit_sub_buffer_is_synchronized)
        {
          /* XXX: note that glXCopySubBuffer, at least for Intel, is
           * synchronized with the vblank but glBlitFramebuffer may
           * not be so we use the same scheme we do when calling
           * glXSwapBuffers without the swap_control extension and
           * call glFinish () before waiting for the vblank period.
           *
           * See where we call glXSwapBuffers for more details.
           */
          glFinish ();
          wait_for_vblank (backend_glx);
        }
      else if (backend_glx->get_video_sync)
        {
          /* If we have the GLX_SGI_video_sync extension then we can
           * be a bit smarter about how we throttle blits by avoiding
           * any waits if we can see that the video sync count has
           * already progressed. */
          if (backend_glx->last_video_sync_count == video_sync_count)
            wait_for_vblank (backend_glx);
        }
      else
        wait_for_vblank (backend_glx);

      CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
      _clutter_backend_glx_blit_sub_buffer (backend_glx,
                                            drawable,
                                            copy_area.x,
                                            copy_area.y,
                                            copy_area.width,
                                            copy_area.height);
      CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer);
    }
  else
    {
      CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)",
                    backend_x11->xdpy,
                    (unsigned long) drawable);

      /* If we have GLX swap buffer events then glXSwapBuffers will return
       * immediately and we need to track that there is a swap in
       * progress... */
      if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
        stage_glx->pending_swaps++;

      if (backend_glx->vblank_type != CLUTTER_VBLANK_GLX_SWAP &&
          backend_glx->vblank_type != CLUTTER_VBLANK_NONE)
        {
          /* If we are going to wait for VBLANK manually, we not only
           * need to flush out pending drawing to the GPU before we
           * sleep, we need to wait for it to finish. Otherwise, we
           * may end up with the situation:
           *
           *        - We finish drawing      - GPU drawing continues
           *        - We go to sleep         - GPU drawing continues
           * VBLANK - We call glXSwapBuffers - GPU drawing continues
           *                                 - GPU drawing continues
           *                                 - Swap buffers happens
           *
           * Producing a tear. Calling glFinish() first will cause us
           * to properly wait for the next VBLANK before we swap. This
           * obviously does not happen when we use _GLX_SWAP and let
           * the driver do the right thing
           */
          glFinish ();

          wait_for_vblank (backend_glx);
        }

      CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
      glXSwapBuffers (backend_x11->xdpy, drawable);
      CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);

      _cogl_swap_buffers_notify ();
    }

  backend_glx->last_video_sync_count = video_sync_count;

  /* reset the redraw clipping for the next paint... */
  stage_glx->initialized_redraw_clip = FALSE;

  stage_glx->frame_count++;
}
static void
on_paint (ClutterActor *actor, void *state)
{
  float saved_viewport[4];
  CoglMatrix saved_projection;
  CoglMatrix projection;
  CoglMatrix modelview;
  guchar *data;
  CoglHandle tex;
  CoglHandle offscreen;
  CoglColor black;
  float x0;
  float y0;
  float width;
  float height;

  /* for clearing the offscreen framebuffer to black... */
  cogl_color_init_from_4ub (&black, 0x00, 0x00, 0x00, 0xff);

  cogl_get_viewport (saved_viewport);
  cogl_get_projection_matrix (&saved_projection);
  cogl_push_matrix ();

  cogl_matrix_init_identity (&projection);
  cogl_matrix_init_identity (&modelview);

  cogl_set_projection_matrix (&projection);
  cogl_set_modelview_matrix (&modelview);

  /* - Create a 100x200 viewport (i.e. smaller than the onscreen framebuffer)
   *   and position it a (20, 10) inside the framebuffer.
   * - Fill the whole viewport with a purple rectangle
   * - Verify that the framebuffer is black with a 100x200 purple rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     100, /* width */
                     200); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* fill the viewport with purple.. */
  cogl_set_source_color4ub (0xff, 0x00, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0xff, 0x00, 0xff);


  /* - Create a viewport twice the size of the onscreen framebuffer with
   *   a negative offset positioning it at (-20, -10) relative to the
   *   buffer itself.
   * - Draw a 100x200 green rectangle at (40, 20) within the viewport (which
   *   is (20, 10) within the framebuffer)
   * - Verify that the framebuffer is black with a 100x200 green rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (-20, /* x */
                     -10, /* y */
                     FRAMEBUFFER_WIDTH * 2, /* width */
                     FRAMEBUFFER_HEIGHT * 2); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* draw a 100x200 green rectangle offset into the viewport such that its
   * top left corner should be found at (20, 10) in the offscreen buffer */
  /* (offset 40 pixels right from the left of the viewport) */
  x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f;
  /* (offset 20 pixels down from the top of the viewport) */
  y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f;
  width = (1.0f / FRAMEBUFFER_WIDTH) * 100;
  height = (1.0f / FRAMEBUFFER_HEIGHT) * 200;
  cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
  cogl_rectangle (x0, y0, x0 + width, y0 - height);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0x00, 0xff, 0x00);


  /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
   *   buffer.
   * - Push a 100x200 window space clip rectangle at (20, 10)
   * - Fill the whole viewport with a blue rectangle
   * - Verify that the framebuffer is black with a 100x200 blue rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     200, /* width */
                     400); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  cogl_clip_push_window_rectangle (20, 10, 100, 200);
  /* fill the viewport with blue.. */
  cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  cogl_clip_pop ();
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0x00, 0x00, 0xff);


  /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
   *   buffer.
   * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport
   *   (i.e. (40, 20) inside the framebuffer)
   * - Fill the whole viewport with a green rectangle
   * - Verify that the framebuffer is black with a 100x200 green rectangle at
   *   (40, 20)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     200, /* width */
                     400); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* figure out where to position our clip rectangle in model space
   * coordinates... */
  /* (offset 40 pixels right from the left of the viewport) */
  x0 = -1.0f + (2.0f / 200) * 20.f;
  /* (offset 20 pixels down from the top of the viewport) */
  y0 = 1.0f - (2.0f / 400) * 10.0f;
  width = (2.0f / 200) * 100;
  height = (2.0f / 400) * 200;
  /* add the clip rectangle... */
  cogl_push_matrix ();
  cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0);
  /* XXX: Rotate just enough to stop Cogl from converting our model space
   * rectangle into a window space rectangle.. */
  cogl_rotate (0.1, 0, 0, 1);
  cogl_clip_push_rectangle (-(width/2.0), -(height/2.0),
                            width/2.0, height/2.0);
  cogl_pop_matrix ();
  /* fill the viewport with green.. */
  cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  cogl_clip_pop ();
  assert_rectangle_color_and_black_border (40, 20, 100, 200,
                                           0x00, 0xff, 0x00);


  /* Set the viewport to something specific so we can verify that it gets
   * restored after we are done testing with an offscreen framebuffer... */
  cogl_set_viewport (20, 10, 100, 200);

  /*
   * Next test offscreen drawing...
   */
  data = g_malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
  tex = cogl_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
                                    COGL_TEXTURE_NO_SLICING,
                                    COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */
                                    COGL_PIXEL_FORMAT_ANY, /* internal fmt */
                                    FRAMEBUFFER_WIDTH * 4, /* rowstride */
                                    data);
  g_free (data);
  offscreen = cogl_offscreen_new_to_texture (tex);

  cogl_push_framebuffer (offscreen);


  /* - Create a 100x200 viewport (i.e. smaller than the offscreen framebuffer)
   *   and position it a (20, 10) inside the framebuffer.
   * - Fill the whole viewport with a blue rectangle
   * - Verify that the framebuffer is black with a 100x200 blue rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     100, /* width */
                     200); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* fill the viewport with blue.. */
  cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0x00, 0x00, 0xff);


  /* - Create a viewport twice the size of the offscreen framebuffer with
   *   a negative offset positioning it at (-20, -10) relative to the
   *   buffer itself.
   * - Draw a 100x200 red rectangle at (40, 20) within the viewport (which
   *   is (20, 10) within the framebuffer)
   * - Verify that the framebuffer is black with a 100x200 red rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (-20, /* x */
                     -10, /* y */
                     FRAMEBUFFER_WIDTH * 2, /* width */
                     FRAMEBUFFER_HEIGHT * 2); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* draw a 100x200 red rectangle offset into the viewport such that its
   * top left corner should be found at (20, 10) in the offscreen buffer */
  /* (offset 40 pixels right from the left of the viewport) */
  x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f;
  /* (offset 20 pixels down from the top of the viewport) */
  y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f;
  width = (1.0f / FRAMEBUFFER_WIDTH) * 100;
  height = (1.0f / FRAMEBUFFER_HEIGHT) * 200;
  cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
  cogl_rectangle (x0, y0, x0 + width, y0 - height);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0xff, 0x00, 0x00);


  /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
   *   buffer.
   * - Push a 100x200 window space clip rectangle at (20, 10)
   * - Fill the whole viewport with a blue rectangle
   * - Verify that the framebuffer is black with a 100x200 blue rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     200, /* width */
                     400); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  cogl_clip_push_window_rectangle (20, 10, 100, 200);
  /* fill the viewport with blue.. */
  cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  cogl_clip_pop ();
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0x00, 0x00, 0xff);


  /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
   *   buffer.
   * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport
   *   (i.e. (40, 20) inside the framebuffer)
   * - Fill the whole viewport with a green rectangle
   * - Verify that the framebuffer is black with a 100x200 green rectangle at
   *   (40, 20)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     200, /* width */
                     400); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* figure out where to position our clip rectangle in model space
   * coordinates... */
  /* (offset 40 pixels right from the left of the viewport) */
  x0 = -1.0f + (2.0f / 200) * 20.f;
  /* (offset 20 pixels down from the top of the viewport) */
  y0 = 1.0f - (2.0f / 400) * 10.0f;
  width = (2.0f / 200) * 100;
  height = (2.0f / 400) * 200;
  /* add the clip rectangle... */
  cogl_push_matrix ();
  cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0);
  /* XXX: Rotate just enough to stop Cogl from converting our model space
   * rectangle into a window space rectangle.. */
  cogl_rotate (0.1, 0, 0, 1);
  cogl_clip_push_rectangle (-(width/2.0), -(height/2.0),
                            width/2, height/2);
  cogl_pop_matrix ();
  /* fill the viewport with green.. */
  cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  cogl_clip_pop ();
  assert_rectangle_color_and_black_border (40, 20, 100, 200,
                                           0x00, 0xff, 0x00);


  /* Set the viewport to something obscure to verify that it gets
   * replace when we switch back to the onscreen framebuffer... */
  cogl_set_viewport (0, 0, 10, 10);

  cogl_pop_framebuffer ();
  cogl_handle_unref (offscreen);

  /*
   * Verify that the previous onscreen framebuffer's viewport was restored
   * by drawing a white rectangle across the whole viewport. This should
   * draw a 100x200 rectangle at (20,10) relative to the onscreen draw
   * buffer...
   */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0xff, 0xff, 0xff);


  /* Uncomment to display the last contents of the offscreen framebuffer */
#if 1
  cogl_matrix_init_identity (&projection);
  cogl_matrix_init_identity (&modelview);
  cogl_set_viewport (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT);
  cogl_set_projection_matrix (&projection);
  cogl_set_modelview_matrix (&modelview);
  cogl_set_source_texture (tex);
  cogl_rectangle (-1, 1, 1, -1);
#endif

  cogl_handle_unref (tex);

  /* Finally restore the stage's original state... */
  cogl_pop_matrix ();
  cogl_set_projection_matrix (&saved_projection);
  cogl_set_viewport (saved_viewport[0], saved_viewport[1],
                     saved_viewport[2], saved_viewport[3]);


  /* Comment this out if you want visual feedback of what this test
   * paints.
   */
  clutter_main_quit ();
}
static void
mnb_fancy_bin_paint (ClutterActor *actor)
{
  MnbFancyBin *self = MNB_FANCY_BIN (actor);
  MnbFancyBinPrivate *priv = self->priv;

  /* Draw the clipped child if necessary */
  if (priv->fanciness > 0.0)
    {
      MxPadding padding;
      gfloat width, height;

      clutter_actor_get_size (actor, &width, &height);
      mx_widget_get_padding (MX_WIDGET (actor), &padding);

      /* Create a clip path so that the clone won't poke out
       * from underneath the background.
       */
      cogl_path_new ();
      cogl_path_move_to (padding.left + priv->curve_radius,
                         padding.top);
      cogl_path_arc (width - padding.right - priv->curve_radius,
                     priv->curve_radius + padding.top,
                     priv->curve_radius,
                     priv->curve_radius,
                     270,
                     360);
      cogl_path_arc (width - padding.right - priv->curve_radius,
                     height - padding.bottom - priv->curve_radius,
                     priv->curve_radius,
                     priv->curve_radius,
                     0,
                     90);
      cogl_path_arc (padding.left + priv->curve_radius,
                     height - padding.bottom - priv->curve_radius,
                     priv->curve_radius,
                     priv->curve_radius,
                     90,
                     180);
      cogl_path_arc (padding.left + priv->curve_radius,
                     padding.top + priv->curve_radius,
                     priv->curve_radius,
                     priv->curve_radius,
                     180,
                     270);
      cogl_path_close ();
      cogl_clip_push_from_path ();

      /* Paint child */
      if (priv->child)
        clutter_actor_paint (priv->child);

      cogl_clip_pop ();

      /* Chain up for background */
      CLUTTER_ACTOR_CLASS (mnb_fancy_bin_parent_class)->paint (actor);
    }

  /* Draw the un-fancy child */
  if ((priv->fanciness < 1.0) && priv->clone)
    clutter_actor_paint (priv->clone);
}
Beispiel #16
0
static void
post_paint_clip_cb (void)
{
  cogl_clip_pop ();
}