예제 #1
0
CoglPipeline *
_st_create_shadow_pipeline (StShadow    *shadow_spec,
                            CoglTexture *src_texture)
{
  ClutterBackend *backend = clutter_get_default_backend ();
  CoglContext *ctx = clutter_backend_get_cogl_context (backend);
  CoglError *error = NULL;

  static CoglPipeline *shadow_pipeline_template = NULL;

  CoglPipeline *pipeline;
  CoglTexture *texture;
  guchar *pixels_in, *pixels_out;
  gint width_in, height_in, rowstride_in;
  gint width_out, height_out, rowstride_out;

  g_return_val_if_fail (shadow_spec != NULL, NULL);
  g_return_val_if_fail (src_texture != NULL, NULL);

  width_in  = cogl_texture_get_width  (src_texture);
  height_in = cogl_texture_get_height (src_texture);
  rowstride_in = (width_in + 3) & ~3;

  pixels_in  = g_malloc0 (rowstride_in * height_in);

  cogl_texture_get_data (src_texture, COGL_PIXEL_FORMAT_A_8,
                         rowstride_in, pixels_in);

  pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in,
                            shadow_spec->blur,
                            &width_out, &height_out, &rowstride_out);
  g_free (pixels_in);

  texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, width_out, height_out,
                                                         COGL_PIXEL_FORMAT_A_8,
                                                         rowstride_out,
                                                         pixels_out,
                                                         &error));

  if (error)
    {
      g_warning ("Failed to allocate texture: %s", error->message);
      cogl_error_free (error);
    }

  g_free (pixels_out);

  if (G_UNLIKELY (shadow_pipeline_template == NULL))
    {
      shadow_pipeline_template = cogl_pipeline_new (ctx);

      /* We set up the pipeline to blend the shadow texture with the combine
       * constant, but defer setting the latter until painting, so that we can
       * take the actor's overall opacity into account. */
      cogl_pipeline_set_layer_combine (shadow_pipeline_template, 0,
                                       "RGBA = MODULATE (CONSTANT, TEXTURE[A])",
                                       NULL);
    }

  pipeline = cogl_pipeline_copy (shadow_pipeline_template);
  cogl_pipeline_set_layer_texture (pipeline, 0, texture);

  if (texture)
    cogl_object_unref (texture);

  return pipeline;
}
예제 #2
0
static CoglHandle
cinnamon_app_create_faded_icon_cpu (StTextureCache *cache,
                                 const char     *key,
                                 void           *datap,
                                 GError        **error)
{
  ClutterBackend *backend = clutter_get_default_backend ();
  CoglContext *ctx = clutter_backend_get_cogl_context (backend);
  CreateFadedIconData *data = datap;
  CinnamonApp *app;
  GdkPixbuf *pixbuf;
  int size;
  int scale;
  CoglHandle texture;
  gint width, height, rowstride;
  guint8 n_channels;
  gboolean have_alpha;
  gint fade_start;
  gint fade_range;
  guint i, j;
  guint pixbuf_byte_size;
  guint8 *orig_pixels;
  guint8 *pixels;
  GIcon *icon;
  GtkIconInfo *info;

  app = data->app;
  size = data->size;
  scale = data->scale;

  info = NULL;

  icon = g_app_info_get_icon (G_APP_INFO (gmenu_tree_entry_get_app_info (app->entry)));
  if (icon != NULL)
    {
      info = gtk_icon_theme_lookup_by_gicon_for_scale (gtk_icon_theme_get_default (),
                                                       icon, size, scale,
                                                       GTK_ICON_LOOKUP_FORCE_SIZE);
    }

  if (info == NULL)
    {
      icon = g_themed_icon_new ("application-x-executable");
      info = gtk_icon_theme_lookup_by_gicon_for_scale (gtk_icon_theme_get_default (),
                                                       icon, size, scale,
                                                       GTK_ICON_LOOKUP_FORCE_SIZE);
      g_object_unref (icon);
    }

  if (info == NULL)
    return COGL_INVALID_HANDLE;

  pixbuf = gtk_icon_info_load_icon (info, NULL);
  gtk_icon_info_free (info);

  if (pixbuf == NULL)
    return COGL_INVALID_HANDLE;

  width = gdk_pixbuf_get_width (pixbuf);
  height = gdk_pixbuf_get_height (pixbuf);
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
  orig_pixels = gdk_pixbuf_get_pixels (pixbuf);
  have_alpha = gdk_pixbuf_get_has_alpha (pixbuf);

  pixbuf_byte_size = (height - 1) * rowstride +
    + width * ((n_channels * gdk_pixbuf_get_bits_per_sample (pixbuf) + 7) / 8);

  pixels = g_malloc0 (rowstride * height);
  memcpy (pixels, orig_pixels, pixbuf_byte_size);

  fade_start = width / 2;
  fade_range = width - fade_start;
  for (i = fade_start; i < width; i++)
    {
      for (j = 0; j < height; j++)
        {
          guchar *pixel = &pixels[j * rowstride + i * n_channels];
          float fade = 1.0 - ((float) i - fade_start) / fade_range;
          pixel[0] = 0.5 + pixel[0] * fade;
          pixel[1] = 0.5 + pixel[1] * fade;
          pixel[2] = 0.5 + pixel[2] * fade;
          if (have_alpha)
            pixel[3] = 0.5 + pixel[3] * fade;
        }
    }

  texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, width, height,
                                                         have_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
#if COGL_VERSION < COGL_VERSION_ENCODE (1, 18, 0)
                                                         COGL_PIXEL_FORMAT_ANY,
#endif
                                                         rowstride,
                                                         pixels,
                                                         NULL));
  g_free (pixels);
  g_object_unref (pixbuf);

  return texture;
}
예제 #3
0
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 (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);
    }
}
예제 #4
0
static void
clutter_deform_effect_init_arrays (ClutterDeformEffect *self)
{
  ClutterDeformEffectPrivate *priv = self->priv;
  gint x, y, direction, n_indices;
  CoglAttribute *attributes[3];
  guint16 *static_indices;
  CoglContext *ctx =
    clutter_backend_get_cogl_context (clutter_get_default_backend ());
  CoglIndices *indices;
  guint16 *idx;
  int i;

  clutter_deform_effect_free_arrays (self);

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

  static_indices = g_new (guint16, n_indices);

#define MESH_INDEX(x,y) ((y) * (priv->x_tiles + 1) + (x))

  /* compute all the triangles from the various tiles */
  direction = 1;

  idx = static_indices;
  idx[0] = MESH_INDEX (0, 0);
  idx[1] = MESH_INDEX (0, 1);
  idx += 2;

  for (y = 0; y < priv->y_tiles; y++)
    {
      for (x = 0; x < priv->x_tiles; x++)
        {
          if (direction)
            {
              idx[0] = MESH_INDEX (x + 1, y);
              idx[1] = MESH_INDEX (x + 1, y + 1);
            }
          else
            {
              idx[0] = MESH_INDEX (priv->x_tiles - x - 1, y);
              idx[1] = MESH_INDEX (priv->x_tiles - x - 1, y + 1);
            }

          idx += 2;
        }

      if (y == (priv->y_tiles - 1))
        break;

      if (direction)
        {
          idx[0] = MESH_INDEX (priv->x_tiles, y + 1);
          idx[1] = MESH_INDEX (priv->x_tiles, y + 1);
          idx[2] = MESH_INDEX (priv->x_tiles, y + 2);
        }
      else
        {
          idx[0] = MESH_INDEX (0, y + 1);
          idx[1] = MESH_INDEX (0, y + 1);
          idx[2] = MESH_INDEX (0, y + 2);
        }

      idx += 3;

      direction = !direction;
    }

#undef MESH_INDEX

  indices = cogl_indices_new (ctx,
                              COGL_INDICES_TYPE_UNSIGNED_SHORT,
                              static_indices,
                              n_indices);

  g_free (static_indices);

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

  priv->buffer =
    cogl_attribute_buffer_new (ctx,
                               sizeof (CoglVertexP3T2C4) *
                               priv->n_vertices,
                               NULL);

  /* The application is expected to continuously modify the vertices
     so we should give a hint to Cogl about that */
  cogl_buffer_set_update_hint (COGL_BUFFER (priv->buffer),
                               COGL_BUFFER_UPDATE_HINT_DYNAMIC);

  attributes[0] = cogl_attribute_new (priv->buffer,
                                      "cogl_position_in",
                                      sizeof (CoglVertexP3T2C4),
                                      G_STRUCT_OFFSET (CoglVertexP3T2C4, x),
                                      3, /* n_components */
                                      COGL_ATTRIBUTE_TYPE_FLOAT);
  attributes[1] = cogl_attribute_new (priv->buffer,
                                      "cogl_tex_coord0_in",
                                      sizeof (CoglVertexP3T2C4),
                                      G_STRUCT_OFFSET (CoglVertexP3T2C4, s),
                                      2, /* n_components */
                                      COGL_ATTRIBUTE_TYPE_FLOAT);
  attributes[2] = cogl_attribute_new (priv->buffer,
                                      "cogl_color_in",
                                      sizeof (CoglVertexP3T2C4),
                                      G_STRUCT_OFFSET (CoglVertexP3T2C4, r),
                                      4, /* n_components */
                                      COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);

  priv->primitive =
    cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLE_STRIP,
                                        priv->n_vertices,
                                        attributes,
                                        3 /* n_attributes */);
  cogl_primitive_set_indices (priv->primitive,
                              indices,
                              n_indices);

  if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DEFORM_TILES))
    {
      priv->lines_primitive =
        cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_LINE_STRIP,
                                            priv->n_vertices,
                                            attributes,
                                            2 /* n_attributes */);
      cogl_primitive_set_indices (priv->lines_primitive,
                                  indices,
                                  n_indices);
    }

  cogl_object_unref (indices);

  for (i = 0; i < 3; i++)
    cogl_object_unref (attributes[i]);

  priv->is_dirty = TRUE;
}
예제 #5
0
static gboolean
shm_buffer_attach (MetaWaylandBuffer  *buffer,
                   CoglTexture       **texture,
                   gboolean           *changed_texture,
                   GError            **error)
{
  MetaBackend *backend = meta_get_backend ();
  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
  CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
  struct wl_shm_buffer *shm_buffer;
  int stride, width, height;
  CoglPixelFormat format;
  CoglTextureComponents components;
  CoglBitmap *bitmap;
  CoglTexture *new_texture;

  shm_buffer = wl_shm_buffer_get (buffer->resource);
  stride = wl_shm_buffer_get_stride (shm_buffer);
  width = wl_shm_buffer_get_width (shm_buffer);
  height = wl_shm_buffer_get_height (shm_buffer);
  shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components);

  if (*texture &&
      cogl_texture_get_width (*texture) == width &&
      cogl_texture_get_height (*texture) == height &&
      cogl_texture_get_components (*texture) == components &&
      _cogl_texture_get_format (*texture) == format)
    {
      buffer->is_y_inverted = TRUE;
      *changed_texture = FALSE;
      return TRUE;
    }

  cogl_clear_object (texture);

  wl_shm_buffer_begin_access (shm_buffer);

  bitmap = cogl_bitmap_new_for_data (cogl_context,
                                     width, height,
                                     format,
                                     stride,
                                     wl_shm_buffer_get_data (shm_buffer));

  new_texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap));
  cogl_texture_set_components (new_texture, components);

  if (!cogl_texture_allocate (new_texture, error))
    {
      g_clear_pointer (&new_texture, cogl_object_unref);
      if (g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE))
        {
          CoglTexture2DSliced *texture_sliced;

          g_clear_error (error);

          texture_sliced =
            cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                    COGL_TEXTURE_MAX_WASTE);
          new_texture = COGL_TEXTURE (texture_sliced);
          cogl_texture_set_components (new_texture, components);

          if (!cogl_texture_allocate (new_texture, error))
            g_clear_pointer (&new_texture, cogl_object_unref);
        }
    }

  cogl_object_unref (bitmap);

  wl_shm_buffer_end_access (shm_buffer);

  if (!new_texture)
    return FALSE;

  *texture = new_texture;
  *changed_texture = TRUE;
  buffer->is_y_inverted = TRUE;

  return TRUE;
}
예제 #6
0
static gboolean
egl_image_buffer_attach (MetaWaylandBuffer  *buffer,
                         CoglTexture       **texture,
                         gboolean           *changed_texture,
                         GError            **error)
{
  MetaBackend *backend = meta_get_backend ();
  MetaEgl *egl = meta_backend_get_egl (backend);
  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
  CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
  EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
  int format, width, height, y_inverted;
  CoglPixelFormat cogl_format;
  EGLImageKHR egl_image;
  CoglTexture2D *texture_2d;

  if (buffer->egl_image.texture)
    {
      *changed_texture = *texture != buffer->egl_image.texture;
      cogl_clear_object (texture);
      *texture = cogl_object_ref (buffer->egl_image.texture);
      return TRUE;
    }

  if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
                                      EGL_TEXTURE_FORMAT, &format,
                                      error))
    return FALSE;

  if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
                                      EGL_WIDTH, &width,
                                      error))
    return FALSE;

  if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
                                      EGL_HEIGHT, &height,
                                      error))
    return FALSE;

  if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
                                      EGL_WAYLAND_Y_INVERTED_WL, &y_inverted,
                                      NULL))
    y_inverted = EGL_TRUE;

  switch (format)
    {
    case EGL_TEXTURE_RGB:
      cogl_format = COGL_PIXEL_FORMAT_RGB_888;
      break;
    case EGL_TEXTURE_RGBA:
      cogl_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
      break;
    default:
      g_set_error (error, G_IO_ERROR,
                   G_IO_ERROR_FAILED,
                   "Unsupported buffer format %d", format);
      return FALSE;
    }

  /* The WL_bind_wayland_display spec states that EGL_NO_CONTEXT is to be used
   * in conjunction with the EGL_WAYLAND_BUFFER_WL target. */
  egl_image = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
                                     EGL_WAYLAND_BUFFER_WL, buffer->resource,
                                     NULL,
                                     error);
  if (egl_image == EGL_NO_IMAGE_KHR)
    return FALSE;

  texture_2d = cogl_egl_texture_2d_new_from_image (cogl_context,
                                                   width, height,
                                                   cogl_format,
                                                   egl_image,
                                                   error);

  meta_egl_destroy_image (egl, egl_display, egl_image, NULL);

  if (!texture_2d)
    return FALSE;

  buffer->egl_image.texture = COGL_TEXTURE (texture_2d);
  buffer->is_y_inverted = !!y_inverted;

  cogl_clear_object (texture);
  *texture = cogl_object_ref (buffer->egl_image.texture);
  *changed_texture = TRUE;

  return TRUE;
}
예제 #7
0
static void
ensure_xfixes_cursor (MetaCursorTracker *tracker)
{
  MetaDisplay *display = meta_get_display ();
  XFixesCursorImage *cursor_image;
  CoglTexture2D *sprite;
  guint8 *cursor_data;
  gboolean free_cursor_data;
  CoglContext *ctx;

  if (tracker->xfixes_cursor)
    return;

  cursor_image = XFixesGetCursorImage (display->xdisplay);
  if (!cursor_image)
    return;

  /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit
   * quantities as arrays of long; we need to convert on 64 bit */
  if (sizeof(long) == 4)
    {
      cursor_data = (guint8 *)cursor_image->pixels;
      free_cursor_data = FALSE;
    }
  else
    {
      int i, j;
      guint32 *cursor_words;
      gulong *p;
      guint32 *q;

      cursor_words = g_new (guint32, cursor_image->width * cursor_image->height);
      cursor_data = (guint8 *)cursor_words;

      p = cursor_image->pixels;
      q = cursor_words;
      for (j = 0; j < cursor_image->height; j++)
        for (i = 0; i < cursor_image->width; i++)
          *(q++) = *(p++);

      free_cursor_data = TRUE;
    }

  ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
  sprite = cogl_texture_2d_new_from_data (ctx,
                                          cursor_image->width,
                                          cursor_image->height,
                                          CLUTTER_CAIRO_FORMAT_ARGB32,
                                          cursor_image->width * 4, /* stride */
                                          cursor_data,
                                          NULL);

  if (free_cursor_data)
    g_free (cursor_data);

  if (sprite != NULL)
    {
      MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite,
                                                                        cursor_image->xhot,
                                                                        cursor_image->yhot);
      tracker->xfixes_cursor = cursor;
    }
  XFree (cursor_image);
}
예제 #8
0
static void
st_background_effect_init (StBackgroundEffect *self)
{
  CoglContext *ctx;
  StBackgroundEffectClass *klass = ST_BACKGROUND_EFFECT_GET_CLASS (self);

  if (G_UNLIKELY (klass->base_pipeline == NULL))
    {
      ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());

      klass->base_pipeline = cogl_pipeline_new (ctx);
    }
    
  self->pipeline0 = cogl_pipeline_copy (klass->base_pipeline);
  self->pipeline1 = cogl_pipeline_copy (klass->base_pipeline);
  self->pipeline2 = cogl_pipeline_copy (klass->base_pipeline);
  self->pipeline3 = cogl_pipeline_copy (klass->base_pipeline);
  self->pipeline4 = cogl_pipeline_copy (klass->base_pipeline);

  CoglSnippet *snippet;
  snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP,
                              box_blur_glsl_declarations,
                              NULL);

  cogl_snippet_set_replace (snippet, box_blur_glsl_shader);
  cogl_pipeline_add_layer_snippet (self->pipeline0, 0, snippet);
  cogl_pipeline_add_layer_snippet (self->pipeline1, 0, snippet);
  cogl_pipeline_add_layer_snippet (self->pipeline3, 0, snippet);
  cogl_object_unref (snippet);

  cogl_pipeline_set_layer_wrap_mode (self->pipeline0, 0,
                                     COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE);

  cogl_pipeline_set_layer_wrap_mode (self->pipeline0, 1,
                                     COGL_PIPELINE_WRAP_MODE_REPEAT);

  cogl_pipeline_set_layer_wrap_mode (self->pipeline1, 0,
                                     COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE);

  cogl_pipeline_set_layer_wrap_mode (self->pipeline2, 0,
                                     COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE);

  cogl_pipeline_set_layer_wrap_mode (self->pipeline3, 0,
                                     COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE);

  cogl_pipeline_set_layer_wrap_mode (self->pipeline4, 0,
                                     COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE);

  cogl_pipeline_set_cull_face_mode (self->pipeline0,
                                    COGL_PIPELINE_CULL_FACE_MODE_NONE);

  cogl_pipeline_set_cull_face_mode (self->pipeline1,
                                    COGL_PIPELINE_CULL_FACE_MODE_NONE);

  cogl_pipeline_set_cull_face_mode (self->pipeline2,
                                    COGL_PIPELINE_CULL_FACE_MODE_NONE);

  cogl_pipeline_set_cull_face_mode (self->pipeline3,
                                    COGL_PIPELINE_CULL_FACE_MODE_NONE);

  cogl_pipeline_set_cull_face_mode (self->pipeline4,
                                    COGL_PIPELINE_CULL_FACE_MODE_NONE);

  cogl_pipeline_set_layer_filters (self->pipeline0, 0,
                                   COGL_PIPELINE_FILTER_LINEAR,
                                   COGL_PIPELINE_FILTER_LINEAR);

  cogl_pipeline_set_layer_filters (self->pipeline0, 1,
                                   COGL_PIPELINE_FILTER_NEAREST,
                                   COGL_PIPELINE_FILTER_NEAREST);

  cogl_pipeline_set_layer_filters (self->pipeline1, 0,
                                   COGL_PIPELINE_FILTER_LINEAR,
                                   COGL_PIPELINE_FILTER_LINEAR);

  cogl_pipeline_set_layer_filters (self->pipeline2, 0,
                                   COGL_PIPELINE_FILTER_LINEAR,
                                   COGL_PIPELINE_FILTER_LINEAR);

  cogl_pipeline_set_layer_filters (self->pipeline3, 0,
                                   COGL_PIPELINE_FILTER_LINEAR,
                                   COGL_PIPELINE_FILTER_LINEAR);

  cogl_pipeline_set_layer_filters (self->pipeline4, 0,
                                   COGL_PIPELINE_FILTER_LINEAR,
                                   COGL_PIPELINE_FILTER_LINEAR);

  cogl_pipeline_set_layer_null_texture (self->pipeline0,
                                        0,
                                        COGL_TEXTURE_TYPE_2D);

  cogl_pipeline_set_layer_null_texture (self->pipeline1,
                                        0,
                                        COGL_TEXTURE_TYPE_2D);

  cogl_pipeline_set_layer_null_texture (self->pipeline2,
                                        0,
                                        COGL_TEXTURE_TYPE_2D);

  cogl_pipeline_set_layer_null_texture (self->pipeline3,
                                        0,
                                        COGL_TEXTURE_TYPE_2D);
  
  cogl_pipeline_set_layer_null_texture (self->pipeline4,
                                        0,
                                        COGL_TEXTURE_TYPE_2D);

  self->pixel_step_uniform0 =
    cogl_pipeline_get_uniform_location (self->pipeline0, "pixel_step");

  self->BumpTex_uniform =
    cogl_pipeline_get_uniform_location (self->pipeline0, "BumpTex");

  self->bump_step_uniform =
    cogl_pipeline_get_uniform_location (self->pipeline0, "bump_step");

  self->pixel_step_uniform1 =
    cogl_pipeline_get_uniform_location (self->pipeline1, "pixel_step");

  self->pixel_step_uniform2 =
    cogl_pipeline_get_uniform_location (self->pipeline3, "pixel_step");

  cogl_pipeline_set_blend (self->pipeline0,
                           "RGBA = ADD(SRC_COLOR, DST_COLOR*0)",
                           NULL);

  cogl_pipeline_set_blend (self->pipeline1,
                           "RGBA = ADD (SRC_COLOR*DST_COLOR[A], DST_COLOR*(1-DST_COLOR[A]))",
                           NULL);

  cogl_pipeline_set_color4ub (self->pipeline1,
                              0xff,
                              0xff,
                              0xff,
                              0xff);

  cogl_pipeline_set_alpha_test_function (self->pipeline2,
                                         COGL_PIPELINE_ALPHA_FUNC_LESS,
                                         0.004f);

  cogl_pipeline_set_color_mask (self->pipeline2,
                                COGL_COLOR_MASK_ALPHA);

  cogl_pipeline_set_blend (self->pipeline2,
                           "RGBA = ADD(SRC_COLOR, DST_COLOR*0)",
                           NULL);

  cogl_pipeline_set_alpha_test_function (self->pipeline3,
                                         COGL_PIPELINE_ALPHA_FUNC_GEQUAL,
                                         0.004f);
    
  cogl_pipeline_set_color_mask (self->pipeline3,
                                COGL_COLOR_MASK_ALL);

  cogl_pipeline_set_blend (self->pipeline3,
                           "RGBA = ADD (SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))",
                           NULL);

  cogl_pipeline_set_alpha_test_function (self->pipeline4,
                                         COGL_PIPELINE_ALPHA_FUNC_GEQUAL,
                                         0.004f);
    
  cogl_pipeline_set_color_mask (self->pipeline4,
                                COGL_COLOR_MASK_ALL);

  cogl_pipeline_set_blend (self->pipeline4,
                           "RGBA = ADD (SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))",
                           NULL);


  self->bg_texture = NULL;

  self->bg_sub_texture = NULL;

  self->bumpmap_location = "/usr/share/cinnamon/bumpmaps/frost.png";

  self->bg_bumpmap = cogl_texture_new_from_file (self->bumpmap_location,
                                                 COGL_TEXTURE_NO_SLICING,
                                                 COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                                                 NULL);
  if (self->bg_bumpmap != NULL)
    {
      self->bumptex_width_i = cogl_texture_get_width (self->bg_bumpmap);
      self->bumptex_height_i = cogl_texture_get_height (self->bg_bumpmap);

      cogl_pipeline_set_layer_texture (self->pipeline0, 1, self->bg_bumpmap);
    }
  else
    {
      cogl_pipeline_set_layer_null_texture (self->pipeline0,
                                            1,
                                            COGL_TEXTURE_TYPE_2D);
    }

  cogl_pipeline_set_layer_combine (self->pipeline0,1,
                                   "RGBA = REPLACE (PREVIOUS)",
                                   NULL);

  self->old_time = 0;

  self->opacity = 0;

}
예제 #9
0
static void
make_shadow (MetaShadow     *shadow,
             cairo_region_t *region)
{
  ClutterBackend *backend = clutter_get_default_backend ();
  CoglContext *ctx = clutter_backend_get_cogl_context (backend);
  CoglError *error = NULL;
  int d = get_box_filter_size (shadow->key.radius);
  int spread = get_shadow_spread (shadow->key.radius);
  cairo_rectangle_int_t extents;
  cairo_region_t *row_convolve_region;
  cairo_region_t *column_convolve_region;
  guchar *buffer;
  int buffer_width;
  int buffer_height;
  int x_offset;
  int y_offset;
  int n_rectangles, j, k;

  cairo_region_get_extents (region, &extents);

  /* In the case where top_fade >= 0 and the portion above the top
   * edge of the shape will be cropped, it seems like we could create
   * a smaller buffer and omit the top portion, but actually, in our
   * multi-pass blur algorithm, the blur into the area above the window
   * in the first pass will contribute back to the final pixel values
   * for the top pixels, so we create a buffer as if we weren't cropping
   * and only crop when creating the CoglTexture.
   */

  buffer_width = extents.width + 2 * spread;
  buffer_height = extents.height + 2 * spread;

  /* Round up so we have aligned rows/columns */
  buffer_width = (buffer_width + 3) & ~3;
  buffer_height = (buffer_height + 3) & ~3;

  /* Square buffer allows in-place swaps, which are roughly 70% faster, but we
   * don't want to over-allocate too much memory.
   */
  if (buffer_height < buffer_width && buffer_height > (3 * buffer_width) / 4)
    buffer_height = buffer_width;
  if (buffer_width < buffer_height && buffer_width > (3 * buffer_height) / 4)
    buffer_width = buffer_height;

  buffer = g_malloc0 (buffer_width * buffer_height);

  /* Blurring with multiple box-blur passes is fast, but (especially for
   * large shadow sizes) we can improve efficiency by restricting the blur
   * to the region that actually needs to be blurred.
   */
  row_convolve_region = meta_make_border_region (region, spread, spread, FALSE);
  column_convolve_region = meta_make_border_region (region, 0, spread, TRUE);

  /* Offsets between coordinates of the regions and coordinates in the buffer */
  x_offset = spread;
  y_offset = spread;

  /* Step 1: unblurred image */
  n_rectangles = cairo_region_num_rectangles (region);
  for (k = 0; k < n_rectangles; k++)
    {
      cairo_rectangle_int_t rect;

      cairo_region_get_rectangle (region, k, &rect);
      for (j = y_offset + rect.y; j < y_offset + rect.y + rect.height; j++)
        memset (buffer + buffer_width * j + x_offset + rect.x, 255, rect.width);
    }

  /* Step 2: swap rows and columns */
  buffer = flip_buffer (buffer, buffer_width, buffer_height);

  /* Step 3: blur rows (really columns) */
  blur_rows (column_convolve_region, y_offset, x_offset,
             buffer, buffer_height, buffer_width,
             d);

  /* Step 4: swap rows and columns */
  buffer = flip_buffer (buffer, buffer_height, buffer_width);

  /* Step 5: blur rows */
  blur_rows (row_convolve_region, x_offset, y_offset,
             buffer, buffer_width, buffer_height,
             d);

  /* Step 6: fade out the top, if applicable */
  if (shadow->key.top_fade >= 0)
    {
      for (j = y_offset; j < y_offset + MIN (shadow->key.top_fade, extents.height + shadow->outer_border_bottom); j++)
        fade_bytes(buffer + j * buffer_width, buffer_width, j - y_offset, shadow->key.top_fade);
    }

  /* We offset the passed in pixels to crop off the extra area we allocated at the top
   * in the case of top_fade >= 0. We also account for padding at the left for symmetry
   * though that doesn't currently occur.
   */
  shadow->texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx,
                                                                 shadow->outer_border_left + extents.width + shadow->outer_border_right,
                                                                 shadow->outer_border_top + extents.height + shadow->outer_border_bottom,
                                                                 COGL_PIXEL_FORMAT_A_8,
                                                                 buffer_width,
                                                                 (buffer +
                                                                  (y_offset - shadow->outer_border_top) * buffer_width +
                                                                  (x_offset - shadow->outer_border_left)),
                                                                 &error));

  if (error)
    {
      meta_warning ("Failed to allocate shadow texture: %s\n", error->message);
      cogl_error_free (error);
    }

  cairo_region_destroy (row_convolve_region);
  cairo_region_destroy (column_convolve_region);
  g_free (buffer);

  shadow->pipeline = meta_create_texture_pipeline (shadow->texture);
}
예제 #10
0
static gboolean
setup_framebuffers (StThemeNodeTransition *transition,
                    const ClutterActorBox *allocation)
{
  ClutterBackend *backend = clutter_get_default_backend ();
  CoglContext *ctx = clutter_backend_get_cogl_context (backend);
  StThemeNodeTransitionPrivate *priv = transition->priv;
  CoglColor clear_color = { 0, 0, 0, 0 };
  guint width, height;

  /* template material to avoid unnecessary shader compilation */
  static CoglHandle material_template = COGL_INVALID_HANDLE;

  width  = priv->offscreen_box.x2 - priv->offscreen_box.x1;
  height = priv->offscreen_box.y2 - priv->offscreen_box.y1;

  g_return_val_if_fail (width  > 0, FALSE);
  g_return_val_if_fail (height > 0, FALSE);

  if (priv->old_texture)
    cogl_handle_unref (priv->old_texture);
  priv->old_texture = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx,
                                                                   width,
                                                                   height
#if COGL_VERSION < COGL_VERSION_ENCODE (1, 18, 0)
                                                                   ,COGL_PIXEL_FORMAT_ANY
#endif
                                                                   ));

  if (priv->new_texture)
    cogl_handle_unref (priv->new_texture);
  priv->new_texture = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx,
                                                                   width,
                                                                   height
#if COGL_VERSION < COGL_VERSION_ENCODE (1, 18, 0)
                                                                   ,COGL_PIXEL_FORMAT_ANY
#endif
                                                                   ));

  g_return_val_if_fail (priv->old_texture != COGL_INVALID_HANDLE, FALSE);
  g_return_val_if_fail (priv->new_texture != COGL_INVALID_HANDLE, FALSE);

  if (priv->old_offscreen)
    cogl_handle_unref (priv->old_offscreen);
  priv->old_offscreen = cogl_offscreen_new_to_texture (priv->old_texture);

  if (priv->new_offscreen)
    cogl_handle_unref (priv->new_offscreen);
  priv->new_offscreen = cogl_offscreen_new_to_texture (priv->new_texture);

  g_return_val_if_fail (priv->old_offscreen != COGL_INVALID_HANDLE, FALSE);
  g_return_val_if_fail (priv->new_offscreen != COGL_INVALID_HANDLE, FALSE);

  if (priv->material == NULL)
    {
      if (G_UNLIKELY (material_template == COGL_INVALID_HANDLE))
        {
          material_template = cogl_material_new ();

          cogl_material_set_layer_combine (material_template, 0,
                                           "RGBA = REPLACE (TEXTURE)",
                                           NULL);
          cogl_material_set_layer_combine (material_template, 1,
                                           "RGBA = INTERPOLATE (PREVIOUS, "
                                                               "TEXTURE, "
                                                               "CONSTANT[A])",
                                           NULL);
          cogl_material_set_layer_combine (material_template, 2,
                                           "RGBA = MODULATE (PREVIOUS, "
                                                            "PRIMARY)",
                                           NULL);
        }
      priv->material = cogl_material_copy (material_template);
    }

  cogl_material_set_layer (priv->material, 0, priv->new_texture);
  cogl_material_set_layer (priv->material, 1, priv->old_texture);

  cogl_push_framebuffer (priv->old_offscreen);
  cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
  cogl_ortho (priv->offscreen_box.x1, priv->offscreen_box.x2,
              priv->offscreen_box.y2, priv->offscreen_box.y1,
              0.0, 1.0);
  st_theme_node_paint (priv->old_theme_node, allocation, 255);
  cogl_pop_framebuffer ();

  cogl_push_framebuffer (priv->new_offscreen);
  cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
  cogl_ortho (priv->offscreen_box.x1, priv->offscreen_box.x2,
              priv->offscreen_box.y2, priv->offscreen_box.y1,
              0.0, 1.0);
  st_theme_node_paint (priv->new_theme_node, allocation, 255);
  cogl_pop_framebuffer ();

  return TRUE;
}
예제 #11
0
static void
clutter_canvas_emit_draw (ClutterCanvas *self)
{
  ClutterCanvasPrivate *priv = self->priv;
  int real_width, real_height;
  cairo_surface_t *surface;
  gboolean mapped_buffer;
  unsigned char *data;
  CoglBuffer *buffer;
  int window_scale = 1;
  gboolean res;
  cairo_t *cr;

  g_assert (priv->height > 0 && priv->width > 0);

  priv->dirty = TRUE;

  if (priv->scale_factor_set)
    window_scale = priv->scale_factor;
  else
    g_object_get (clutter_settings_get_default (),
                  "window-scaling-factor", &window_scale,
                  NULL);

  real_width = priv->width * window_scale;
  real_height = priv->height * window_scale;

  CLUTTER_NOTE (MISC, "Creating Cairo surface with size %d x %d (real: %d x %d, scale: %d)",
                priv->width, priv->height,
                real_width, real_height,
                window_scale);

  if (priv->buffer == NULL)
    {
      CoglContext *ctx;

      ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
      priv->buffer = cogl_bitmap_new_with_size (ctx,
                                                real_width,
                                                real_height,
                                                CLUTTER_CAIRO_FORMAT_ARGB32);
    }

  buffer = COGL_BUFFER (cogl_bitmap_get_buffer (priv->buffer));
  if (buffer == NULL)
    return;

  cogl_buffer_set_update_hint (buffer, COGL_BUFFER_UPDATE_HINT_DYNAMIC);

  data = cogl_buffer_map (buffer,
                          COGL_BUFFER_ACCESS_READ_WRITE,
                          COGL_BUFFER_MAP_HINT_DISCARD);

  if (data != NULL)
    {
      int bitmap_stride = cogl_bitmap_get_rowstride (priv->buffer);

      surface = cairo_image_surface_create_for_data (data,
                                                     CAIRO_FORMAT_ARGB32,
                                                     real_width,
                                                     real_height,
                                                     bitmap_stride);
      mapped_buffer = TRUE;
    }
  else
    {
      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                            real_width,
                                            real_height);

      mapped_buffer = FALSE;
    }

  cairo_surface_set_device_scale (surface, window_scale, window_scale);

  self->priv->cr = cr = cairo_create (surface);

  g_signal_emit (self, canvas_signals[DRAW], 0,
                 cr, priv->width, priv->height,
                 &res);

#ifdef CLUTTER_ENABLE_DEBUG
  if (_clutter_diagnostic_enabled () && cairo_status (cr))
    {
      g_warning ("Drawing failed for <ClutterCanvas>[%p]: %s",
                 self,
                 cairo_status_to_string (cairo_status (cr)));
    }
#endif

  self->priv->cr = NULL;
  cairo_destroy (cr);

  if (mapped_buffer)
    cogl_buffer_unmap (buffer);
  else
    {
      int size = cairo_image_surface_get_stride (surface) * priv->height;
      cogl_buffer_set_data (buffer,
                            0,
                            cairo_image_surface_get_data (surface),
                            size);
    }

  cairo_surface_destroy (surface);
}