Пример #1
0
static void
pixelize (gfloat              *input,
          gfloat              *output,
          const GeglRectangle *roi,
          const GeglRectangle *extended_roi,
          const GeglRectangle *whole_region,
          GeglProperties          *o)
{
  gint          start_x = block_index (roi->x, o->size_x) * o->size_x;
  gint          start_y = block_index (roi->y, o->size_y) * o->size_y;
  gint          x, y;
  gint          off_shape_x, off_shape_y;
  gfloat        color[4];
  GeglRectangle rect_shape;

  rect_shape.width  = ceilf (o->size_x * (gfloat)o->ratio_x);
  rect_shape.height = ceilf (o->size_y * (gfloat)o->ratio_y);

  off_shape_x = floorf ((o->size_x - (gfloat)o->ratio_x * o->size_x) / 2.0f);
  off_shape_y = floorf ((o->size_y - (gfloat)o->ratio_y * o->size_y) / 2.0f);

  for (y = start_y; y < roi->y + roi->height; y += o->size_y)
    for (x = start_x; x < roi->x + roi->width; x += o->size_x)
      {
        GeglRectangle rect = {x, y, o->size_x, o->size_y};
        GeglRectangle rect2;

        rect_shape.x = x + off_shape_x;
        rect_shape.y = y + off_shape_y;

        gegl_rectangle_intersect (&rect, whole_region, &rect);

        if (rect.width < 1 || rect.height < 1)
          continue;

        rect2.x = rect.x - extended_roi->x;
        rect2.y = rect.y - extended_roi->y;
        rect2.width  = rect.width;
        rect2.height = rect.height;

        mean_rectangle (input, &rect2, extended_roi->width, color);

        gegl_rectangle_intersect (&rect, roi, &rect);

        rect2.x = rect.x - roi->x;
        rect2.y = rect.y - roi->y;
        rect2.width  = rect.width;
        rect2.height = rect.height;

        rect_shape.x -= roi->x;
        rect_shape.y -= roi->y;

        set_rectangle (output, &rect2, &rect_shape,
                       roi->width, color, o->norm);
      }
}
Пример #2
0
static gboolean
gimp_operation_normal_parent_process (GeglOperation        *operation,
                                      GeglOperationContext *context,
                                      const gchar          *output_prop,
                                      const GeglRectangle  *result,
                                      gint                  level)
{
#if 0
  /*  this code tries to be smart but is in fact just a too stupid
   *  copy from gegl's normal mode. to fix it, it needs to take
   *  mask and opacity into account
   */
  const GeglRectangle *in_extent  = NULL;
  const GeglRectangle *aux_extent = NULL;
  GObject             *input;
  GObject             *aux;

  /* get the raw values this does not increase the reference count */
  input = gegl_operation_context_get_object (context, "input");
  aux   = gegl_operation_context_get_object (context, "aux");

  /* pass the input/aux buffers directly through if they are not
   * overlapping
   */
  if (input)
    in_extent = gegl_buffer_get_abyss (GEGL_BUFFER (input));

  if (! input ||
      (aux && ! gegl_rectangle_intersect (NULL, in_extent, result)))
    {
      gegl_operation_context_set_object (context, "output", aux);
      return TRUE;
    }

  if (aux)
    aux_extent = gegl_buffer_get_abyss (GEGL_BUFFER (aux));

  if (! aux ||
      (input && ! gegl_rectangle_intersect (NULL, aux_extent, result)))
    {
      gegl_operation_context_set_object (context, "output", input);
      return TRUE;
    }
#endif

  /* chain up, which will create the needed buffers for our actual
   * process function
   */
  return GEGL_OPERATION_CLASS (parent_class)->process (operation, context,
                                                       output_prop, result,
                                                       level);
}
Пример #3
0
int main(int argc, char *argv[])
{
  GeglRectangle expected_infinite_plane = gegl_rectangle_infinite_plane ();
  GeglRectangle infinite_plane          = { INFINITE_PLANE };
  int           result = SUCCESS;
  int           i      = 0;

  /* Make sure our representation of an infinite plane GeglRectangle
   * is correct
   */
  if (! gegl_rectangle_equal (&infinite_plane, &expected_infinite_plane))
    {
      result = FAILURE;
      g_printerr("This test case and GEGL does not represent an infinite plane\n"
                 "GeglRectangle in the same way, update this test case. Aborting.\n");
      goto abort;
    }

  for (i = 0; i < G_N_ELEMENTS (tests); i++)
    {
      GeglRectangle result_rect;
      gboolean      return_value;

      /* gegl_rectangle_bounding_box() */
      gegl_rectangle_bounding_box (&result_rect,
                                   &tests[i].rect1,
                                   &tests[i].rect2);
      if (! gegl_rectangle_equal (&result_rect, &tests[i].bounding_box_result))
        {
          result = FAILURE;
          g_printerr("The gegl_rectangle_bounding_box() test #%d failed. Aborting.\n", i + 1);
          goto abort;
        }

      /* gegl_rectangle_intersect() */
      return_value = gegl_rectangle_intersect (&result_rect,
                                               &tests[i].rect1,
                                               &tests[i].rect2);
      if (! gegl_rectangle_equal (&result_rect, &tests[i].intersect_result) ||
          return_value != tests[i].intersect_return_value)
        {
          result = FAILURE;
          g_printerr("The gegl_rectangle_intersect() test #%d failed. Aborting.\n", i + 1);
          goto abort;
        }

      /* gegl_rectangle_contains() */
      return_value = gegl_rectangle_contains (&tests[i].rect1,
                                              &tests[i].rect2);
      if (return_value != tests[i].contains_return_value)
        {
          result = FAILURE;
          g_printerr("The gegl_rectangle_contains() test #%d failed. Aborting.\n", i + 1);
          goto abort;
        }
    }

abort:
  return result;
}
Пример #4
0
/* Fast paths */
static gboolean operation_process (GeglOperation        *operation,
                                   GeglOperationContext *context,
                                   const gchar          *output_prop,
                                   const GeglRectangle  *result,
                                   gint                  level)
{
  GeglOperationClass  *operation_class;
  gpointer input, aux;
  operation_class = GEGL_OPERATION_CLASS (gegl_chant_parent_class);

  /* get the raw values this does not increase the reference count */
  input = gegl_operation_context_get_object (context, "input");
  aux = gegl_operation_context_get_object (context, "aux");

  /* pass the input/aux buffers directly through if they are alone*/
  {
    const GeglRectangle *in_extent = NULL;
    const GeglRectangle *aux_extent = NULL;

    if (input)
      in_extent = gegl_buffer_get_abyss (input);

    if ((!input ||
        (aux && !gegl_rectangle_intersect (NULL, in_extent, result))))
      {
         gegl_operation_context_take_object (context, "output",
                                             g_object_ref (aux));
         return TRUE;
      }
    if (aux)
      aux_extent = gegl_buffer_get_abyss (aux);

    if (!aux ||
        (input && !gegl_rectangle_intersect (NULL, aux_extent, result)))
      {
        gegl_operation_context_take_object (context, "output",
                                            g_object_ref (input));
        return TRUE;
      }
  }
  /* chain up, which will create the needed buffers for our actual
   * process function
   */
  return operation_class->process (operation, context, output_prop, result, level);
}
Пример #5
0
static void
pixelize_noalloc (GeglBuffer          *input,
                  GeglBuffer          *output,
                  const GeglRectangle *roi,
                  const GeglRectangle *whole_region,
                  GeglProperties          *o)
{
  gint start_x = block_index (roi->x, o->size_x) * o->size_x;
  gint start_y = block_index (roi->y, o->size_y) * o->size_y;
  gint x, y;
  gint off_shape_x, off_shape_y;

  GeglColor *color = gegl_color_new ("white");

  GeglRectangle rect_shape;

  rect_shape.width  = ceilf (o->size_x * (gfloat)o->ratio_x);
  rect_shape.height = ceilf (o->size_y * (gfloat)o->ratio_y);

  off_shape_x = floorf ((o->size_x - (gfloat)o->ratio_x * o->size_x) / 2.0f);
  off_shape_y = floorf ((o->size_y - (gfloat)o->ratio_y * o->size_y) / 2.0f);

  for (y = start_y; y < roi->y + roi->height; y += o->size_y)
    for (x = start_x; x < roi->x + roi->width; x += o->size_x)
      {
        GeglRectangle rect = {x, y, o->size_x, o->size_y};

        gegl_rectangle_intersect (&rect, whole_region, &rect);

        if (rect.width < 1 || rect.height < 1)
          continue;

        mean_rectangle_noalloc (input, &rect, color);

        gegl_rectangle_intersect (&rect, roi, &rect);

        rect_shape.x = x + off_shape_x;
        rect_shape.y = y + off_shape_y;

        set_rectangle_noalloc (output, &rect, &rect_shape, color, o->norm);
      }

  g_object_unref (color);
}
static gboolean
photos_operation_svg_multiply_operation_process (GeglOperation *operation,
                                                 GeglOperationContext *context,
                                                 const gchar *output_pad,
                                                 const GeglRectangle *roi,
                                                 gint level)
{
  GObject *aux;
  GObject *input;
  const GeglRectangle *aux_bbox = NULL;
  const GeglRectangle *in_bbox = NULL;
  gboolean ret_val = TRUE;

  aux = gegl_operation_context_get_object (context, "aux");
  if (aux != NULL)
    aux_bbox = gegl_buffer_get_abyss (GEGL_BUFFER (aux));

  input = gegl_operation_context_get_object (context, "input");
  if (input != NULL)
    in_bbox = gegl_buffer_get_abyss (GEGL_BUFFER (input));

  if (aux == NULL || (input != NULL && !gegl_rectangle_intersect (NULL, aux_bbox, roi)))
    {
      gegl_operation_context_set_object (context, "output", input);
      goto out;
    }

  if (input == NULL || (aux != NULL && !gegl_rectangle_intersect (NULL, in_bbox, roi)))
    {
      gegl_operation_context_set_object (context, "output", aux);
      goto out;
    }

  ret_val = GEGL_OPERATION_CLASS (photos_operation_svg_multiply_parent_class)->process (operation,
                                                                                        context,
                                                                                        output_pad,
                                                                                        roi,
                                                                                        level);

 out:
  return ret_val;
}
Пример #7
0
static void
set_rectangle (gfloat          *output,
               GeglRectangle   *rect,
               GeglRectangle   *rect_shape,
               gint             rowstride,
               gfloat          *color,
               GeglPixelizeNorm norm)
{
  gint c, x, y;
  gfloat center_x, center_y;
  GeglRectangle rect2;

  gfloat shape_area = rect_shape->width * rect_shape->height;

  center_x = rect_shape->x + rect_shape->width / 2.0f;
  center_y = rect_shape->y + rect_shape->height / 2.0f;

  gegl_rectangle_intersect (&rect2, rect, rect_shape);

  switch (norm)
    {
    case (GEGL_PIXELIZE_NORM_INFINITY):

      for (y = rect2.y; y < rect2.y + rect2.height; y++)
        for (x = rect2.x; x < rect2.x + rect2.width; x++)
          for (c = 0; c < 4; c++)
            output [4 * (y * rowstride + x) + c] = color[c];
      break;

    case (GEGL_PIXELIZE_NORM_EUCLIDEAN):

      for (y = rect->y; y < rect->y + rect->height; y++)
        for (x = rect->x; x < rect->x + rect->width; x++)
          if (SQR ((x - center_x) / (gfloat) rect_shape->width) +
              SQR ((y - center_y) / (gfloat) rect_shape->height) <= 1.0f)
            for (c = 0; c < 4; c++)
              output [4 * (y * rowstride + x) + c] = color[c];
      break;

    case (GEGL_PIXELIZE_NORM_MANHATTAN):

      for (y = rect->y; y < rect->y + rect->height; y++)
        for (x = rect->x; x < rect->x + rect->width; x++)
          if (fabsf (center_x - x) * rect_shape->height +
              fabsf (center_y - y) * rect_shape->width < shape_area)
            for (c = 0; c < 4; c++)
              output [4 * (y * rowstride + x) + c] = color[c];

      break;
    }
}
Пример #8
0
static GeglRectangle
gegl_crop_get_required_for_output (GeglOperation       *operation,
                                   const gchar         *input_pad,
                                   const GeglRectangle *roi)
{
  GeglProperties   *o = GEGL_PROPERTIES (operation);
  GeglRectangle result;

  result.x      = o->x;
  result.y      = o->y;
  result.width  = o->width;
  result.height = o->height;

  gegl_rectangle_intersect (&result, &result, roi);
  return result;
}
Пример #9
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  gint    i, j;
  gfloat *buf1, *buf2, *buf3;

  if (gegl_operation_use_opencl (operation))
    if (cl_process (operation, input, output, result))
      return TRUE;

  buf1 = g_new (gfloat, SQR (CHUNK_SIZE + LAPLACE_RADIUS * 2) * 4);
  buf2 = g_new (gfloat, SQR (CHUNK_SIZE + LAPLACE_RADIUS * 2) * 4);
  buf3 = g_new (gfloat, SQR (CHUNK_SIZE) * 4);

  for (j = 0; (j-1) * CHUNK_SIZE < result->height; j++)
    for (i = 0; (i-1) * CHUNK_SIZE < result->width; i++)
      {
        GeglRectangle chunked_result;
        GeglRectangle compute;

        chunked_result = *GEGL_RECTANGLE (result->x + i * CHUNK_SIZE,
                                          result->y + j * CHUNK_SIZE,
                                          CHUNK_SIZE, CHUNK_SIZE);

        gegl_rectangle_intersect (&chunked_result, &chunked_result, result);

        if (chunked_result.width < 1  || chunked_result.height < 1)
          continue;

        compute = gegl_operation_get_required_for_output (operation,
                                                          "input",
                                                          &chunked_result);

        edge_laplace (input, &compute, output, &chunked_result,
                      buf1, buf2, buf3);
      }

  g_free (buf1);
  g_free (buf2);
  g_free (buf3);

  return  TRUE;
}
Пример #10
0
static GeglRectangle
gegl_crop_get_invalidated_by_change (GeglOperation       *operation,
                                     const gchar         *input_pad,
                                     const GeglRectangle *input_region)
{
  GeglProperties   *o = GEGL_PROPERTIES (operation);
  GeglRectangle result;

  result.x = o->x;
  result.y = o->y;
  result.width = o->width;
  result.height = o->height;

  gegl_rectangle_intersect (&result, &result, input_region);

  return result;
}
Пример #11
0
void
gegl_buffer_cl_cache_invalidate (GeglBuffer          *buffer,
                                 const GeglRectangle *roi)
{
  GeglRectangle tmp;
  GList *elem;
  gpointer data;

  for (elem=cache_entries; elem; elem=elem->next)
    {
      CacheEntry *e = elem->data;
      if (e->valid && e->buffer == buffer
          && (!roi || gegl_rectangle_intersect (&tmp, roi, &e->roi)))
        {
          g_assert (e->used == 0);
          gegl_clReleaseMemObject (e->tex);
          e->valid = FALSE;
        }
    }

  g_mutex_lock (&cache_mutex);

  while (cache_entry_find_invalid (&data))
    {
      CacheEntry *entry = data;
      memset(entry, 0x0, sizeof (CacheEntry));

      g_slice_free (CacheEntry, data);
      cache_entries = g_list_remove (cache_entries, data);
    }

  g_mutex_unlock (&cache_mutex);

#if 0
  g_printf ("-- ");
  for (elem=cache_entry; elem; elem=elem->next)
    {
      CacheEntry *e = elem->data;
      g_printf ("%p %p {%d, %d, %d, %d} %d | ", e->tex, e->buffer, e->roi.x, e->roi.y, e->roi.width, e->roi.height, e->valid);
    }
  g_printf ("\n");
#endif

}
Пример #12
0
static void
retile_subs (GeglBufferIterator *iter,
             int                 x,
             int                 y)
{
  GeglBufferIteratorPriv *priv = iter->priv;
  GeglRectangle real_roi;
  int index;

  int shift_x = priv->origin_tile.x;
  int shift_y = priv->origin_tile.y;

  int tile_x = gegl_tile_indice (x + shift_x, priv->origin_tile.width);
  int tile_y = gegl_tile_indice (y + shift_y, priv->origin_tile.height);

  /* Reset tile size */
  real_roi.x = (tile_x * priv->origin_tile.width)  - shift_x;
  real_roi.y = (tile_y * priv->origin_tile.height) - shift_y;
  real_roi.width  = priv->origin_tile.width;
  real_roi.height = priv->origin_tile.height;

  /* Trim tile down to the iteration roi */
  gegl_rectangle_intersect (&iter->roi[0], &real_roi, &priv->sub_iter[0].full_rect);
  priv->sub_iter[0].real_roi = iter->roi[0];

  for (index = 1; index < priv->num_buffers; index++)
    {
      SubIterState *lead_sub = &priv->sub_iter[0];
      SubIterState *sub = &priv->sub_iter[index];

      int roi_offset_x = sub->full_rect.x - lead_sub->full_rect.x;
      int roi_offset_y = sub->full_rect.y - lead_sub->full_rect.y;

      iter->roi[index].x = iter->roi[0].x + roi_offset_x;
      iter->roi[index].y = iter->roi[0].y + roi_offset_y;
      iter->roi[index].width  = iter->roi[0].width;
      iter->roi[index].height = iter->roi[0].height;
      sub->real_roi = iter->roi[index];
    }
}
Пример #13
0
static GeglRectangle
get_required_for_output (GeglOperation        *operation,
                         const gchar         *input_pad,
                         const GeglRectangle *region)
{
  GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
  GeglRectangle            rect;
  GeglRectangle            defined;

  defined = get_bounding_box (operation);
  gegl_rectangle_intersect (&rect, region, &defined);

  if (rect.width  != 0 &&
      rect.height != 0)
    {
      rect.x -= area->left;
      rect.y -= area->top;
      rect.width  += area->left + area->right;
      rect.height  += area->top + area->bottom;
    }

  return rect;
}
Пример #14
0
static void
set_rectangle_noalloc (GeglBuffer      *output,
                       GeglRectangle   *rect,
                       GeglRectangle   *rect_shape,
                       GeglColor       *color,
                       GeglPixelizeNorm norm)
{
  if (norm == GEGL_PIXELIZE_NORM_INFINITY)
    {
      GeglRectangle rect2;
      gegl_rectangle_intersect (&rect2, rect, rect_shape);
      gegl_buffer_set_color (output, &rect2, color);
    }
  else
    {
      GeglBufferIterator *gi;
      gint                c, x, y;
      gfloat              col[4];
      gfloat              center_x, center_y;
      gfloat              shape_area = rect_shape->width * rect_shape->height;

      center_x = rect_shape->x + rect_shape->width / 2.0f;
      center_y = rect_shape->y + rect_shape->height / 2.0f;

      gegl_color_get_pixel (color, babl_format ("RaGaBaA float"), col);

      gi = gegl_buffer_iterator_new (output, rect, 0, babl_format ("RaGaBaA float"),
                                     GEGL_ACCESS_WRITE, GEGL_ABYSS_CLAMP);

      while (gegl_buffer_iterator_next (gi))
        {
          gfloat       *data = (gfloat*) gi->data[0];
          GeglRectangle roi = gi->roi[0];

          switch (norm)
            {
            case (GEGL_PIXELIZE_NORM_EUCLIDEAN):

              for (y = 0; y < roi.height; y++)
                for (x = 0; x < roi.width; x++)
                  if (SQR ((x + roi.x - center_x) / (gfloat) rect_shape->width) +
                      SQR ((y + roi.y - center_y) / (gfloat) rect_shape->height) <= 1.0f)
                    for (c = 0; c < 4; c++)
                      data [4 * (y * roi.width + x) + c] = col[c];
              break;

            case (GEGL_PIXELIZE_NORM_MANHATTAN):

              for (y = 0; y < roi.height; y++)
                for (x = 0; x < roi.width; x++)
                  if (fabsf (x + roi.x - center_x) * rect_shape->height +
                      fabsf (y + roi.y - center_y) * rect_shape->width
                      < shape_area)
                    for (c = 0; c < 4; c++)
                      data [4 * (y * roi.width + x) + c] = col[c];
              break;

            case (GEGL_PIXELIZE_NORM_INFINITY):
              break;
            }
        }
    }
}
Пример #15
0
static int
gimp_mypaint_surface_draw_dab (MyPaintSurface *base_surface,
                               float           x,
                               float           y,
                               float           radius,
                               float           color_r,
                               float           color_g,
                               float           color_b,
                               float           opaque,
                               float           hardness,
                               float           color_a,
                               float           aspect_ratio,
                               float           angle,
                               float           lock_alpha,
                               float           colorize)
{
  GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface;
  GeglBufferIterator *iter;
  GeglRectangle       dabRect;
  GimpComponentMask   component_mask = surface->component_mask;

  const float one_over_radius2 = 1.0f / (radius * radius);
  const double angle_rad = angle / 360 * 2 * M_PI;
  const float cs = cos(angle_rad);
  const float sn = sin(angle_rad);
  float normal_mode;
  float segment1_slope;
  float segment2_slope;
  float r_aa_start;

  hardness = CLAMP (hardness, 0.0f, 1.0f);
  segment1_slope = -(1.0f / hardness - 1.0f);
  segment2_slope = -hardness / (1.0f - hardness);
  aspect_ratio = MAX (1.0f, aspect_ratio);

  r_aa_start = radius - 1.0f;
  r_aa_start = MAX (r_aa_start, 0);
  r_aa_start = (r_aa_start * r_aa_start) / aspect_ratio;

  normal_mode = opaque * (1.0f - colorize);
  colorize = opaque * colorize;

  /* FIXME: This should use the real matrix values to trim aspect_ratio dabs */
  dabRect = calculate_dab_roi (x, y, radius);
  gegl_rectangle_intersect (&dabRect, &dabRect, gegl_buffer_get_extent (surface->buffer));

  if (dabRect.width <= 0 || dabRect.height <= 0)
    return 0;

  gegl_rectangle_bounding_box (&surface->dirty, &surface->dirty, &dabRect);

  iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0,
                                   babl_format ("R'G'B'A float"),
                                   GEGL_BUFFER_READWRITE,
                                   GEGL_ABYSS_NONE);
  if (surface->paint_mask)
    {
      GeglRectangle mask_roi = dabRect;
      mask_roi.x -= surface->paint_mask_x;
      mask_roi.y -= surface->paint_mask_y;
      gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0,
                                babl_format ("Y float"),
                                GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
    }

  while (gegl_buffer_iterator_next (iter))
    {
      float *pixel = (float *)iter->data[0];
      float *mask;
      int iy, ix;

      if (surface->paint_mask)
        mask = iter->data[1];
      else
        mask = NULL;

      for (iy = iter->roi[0].y; iy < iter->roi[0].y + iter->roi[0].height; iy++)
        {
          for (ix = iter->roi[0].x; ix < iter->roi[0].x +  iter->roi[0].width; ix++)
            {
              float rr, base_alpha, alpha, dst_alpha, r, g, b, a;
              if (radius < 3.0f)
                rr = calculate_rr_antialiased (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2, r_aa_start);
              else
                rr = calculate_rr (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2);
              base_alpha = calculate_alpha_for_rr (rr, hardness, segment1_slope, segment2_slope);
              alpha = base_alpha * normal_mode;
              if (mask)
                alpha *= *mask;
              dst_alpha = pixel[ALPHA];
              /* a = alpha * color_a + dst_alpha * (1.0f - alpha);
               * which converts to: */
              a = alpha * (color_a - dst_alpha) + dst_alpha;
              r = pixel[RED];
              g = pixel[GREEN];
              b = pixel[BLUE];

              if (a > 0.0f)
                {
                  /* By definition the ratio between each color[] and pixel[] component in a non-pre-multipled blend always sums to 1.0f.
                   * Originaly this would have been "(color[n] * alpha * color_a + pixel[n] * dst_alpha * (1.0f - alpha)) / a",
                   * instead we only calculate the cheaper term. */
                  float src_term = (alpha * color_a) / a;
                  float dst_term = 1.0f - src_term;
                  r = color_r * src_term + r * dst_term;
                  g = color_g * src_term + g * dst_term;
                  b = color_b * src_term + b * dst_term;
                }

              if (colorize > 0.0f && base_alpha > 0.0f)
                {
                  alpha = base_alpha * colorize;
                  a = alpha + dst_alpha - alpha * dst_alpha;
                  if (a > 0.0f)
                    {
                      GimpHSL pixel_hsl, out_hsl;
                      GimpRGB pixel_rgb = {color_r, color_g, color_b};
                      GimpRGB out_rgb   = {r, g, b};
                      float src_term = alpha / a;
                      float dst_term = 1.0f - src_term;

                      gimp_rgb_to_hsl (&pixel_rgb, &pixel_hsl);
                      gimp_rgb_to_hsl (&out_rgb, &out_hsl);

                      out_hsl.h = pixel_hsl.h;
                      out_hsl.s = pixel_hsl.s;
                      gimp_hsl_to_rgb (&out_hsl, &out_rgb);

                      r = (float)out_rgb.r * src_term + r * dst_term;
                      g = (float)out_rgb.g * src_term + g * dst_term;
                      b = (float)out_rgb.b * src_term + b * dst_term;
                    }
                }

              if (component_mask != GIMP_COMPONENT_MASK_ALL)
                {
                  if (component_mask & GIMP_COMPONENT_MASK_RED)
                    pixel[RED]   = r;
                  if (component_mask & GIMP_COMPONENT_MASK_GREEN)
                    pixel[GREEN] = g;
                  if (component_mask & GIMP_COMPONENT_MASK_BLUE)
                    pixel[BLUE]  = b;
                  if (component_mask & GIMP_COMPONENT_MASK_ALPHA)
                    pixel[ALPHA] = a;
                }
              else
                {
                  pixel[RED]   = r;
                  pixel[GREEN] = g;
                  pixel[BLUE]  = b;
                  pixel[ALPHA] = a;
                }

              pixel += 4;
              if (mask)
                mask += 1;
            }
        }
    }

  return 1;
}
Пример #16
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
  GeglProperties              *o    = GEGL_PROPERTIES (operation);

  GeglBuffer *dest, *dest_tmp;

  GeglRectangle  working_region;
  GeglRectangle *whole_region;

  GeglBufferIterator *iter;

  whole_region = gegl_operation_source_get_bounding_box (operation, "input");

  working_region.x      = result->x - area->left;
  working_region.width  = result->width + area->left + area->right;
  working_region.y      = result->y - area->top;
  working_region.height = result->height + area->top + area->bottom;

  gegl_rectangle_intersect (&working_region, &working_region, whole_region);

  dest_tmp = gegl_buffer_new (&working_region, babl_format ("Y' float"));

  iter = gegl_buffer_iterator_new (dest_tmp, &working_region, 0, babl_format ("Y' float"),
                                   GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, input, &working_region, 0, babl_format ("Y' float"),
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      gint    i;
      gfloat *data_out = iter->data[0];
      gfloat *data_in  = iter->data[1];

      for (i = 0; i < iter->length; i++)
        {
          /* compute sigmoidal transfer */
          gfloat val = *data_in;
          val = 1.0 / (1.0 + exp (-(SIGMOIDAL_BASE + (o->sharpness * SIGMOIDAL_RANGE)) * (val - 0.5)));
          val = val * o->brightness;
          *data_out = CLAMP (val, 0.0, 1.0);

          data_out +=1;
          data_in  +=1;
        }
    }

  dest = grey_blur_buffer (dest_tmp, o->glow_radius, result);

  iter = gegl_buffer_iterator_new (output, result, 0, babl_format ("RGBA float"),
                                   GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, input, result, 0, babl_format ("RGBA float"),
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, dest, result, 0, babl_format ("Y' float"),
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      gint    i;
      gfloat *data_out  = iter->data[0];
      gfloat *data_in   = iter->data[1];
      gfloat *data_blur = iter->data[2];

      for (i = 0; i < iter->length; i++)
        {
          gint c;
          for (c = 0; c < 3; c++)
            {
              gfloat tmp = (1.0 - data_in[c]) * (1.0 - *data_blur);
              data_out[c] = CLAMP (1.0 - tmp, 0.0, 1.0);
            }

          data_out[3] = data_in[3];

          data_out += 4;
          data_in  += 4;
          data_blur+= 1;
        }
    }

  g_object_unref (dest);
  g_object_unref (dest_tmp);

  return TRUE;
}
Пример #17
0
static gboolean
gimp_channel_combine_start (GimpChannel            *mask,
                            GimpChannelOps          op,
                            const GeglRectangle    *rect,
                            gboolean                full_extent,
                            gboolean                full_value,
                            GimpChannelCombineData *data)
{
  GeglBuffer    *buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
  GeglRectangle  extent;
  gboolean       intersects;

  extent.x      = 0;
  extent.y      = 0;
  extent.width  = gimp_item_get_width  (GIMP_ITEM (mask));
  extent.height = gimp_item_get_height (GIMP_ITEM (mask));

  intersects = gegl_rectangle_intersect (&data->rect, rect, &extent);

  data->bounds_known  = mask->bounds_known;
  data->empty         = mask->empty;

  data->bounds.x      = mask->x1;
  data->bounds.y      = mask->y1;
  data->bounds.width  = mask->x2 - mask->x1;
  data->bounds.height = mask->y2 - mask->y1;

  gegl_buffer_freeze_changed (buffer);

  /*  Determine new boundary  */
  switch (op)
    {
    case GIMP_CHANNEL_OP_REPLACE:
      gimp_channel_combine_clear (mask, NULL);

      if (! intersects)
        {
          data->bounds_known = TRUE;
          data->empty        = TRUE;

          return FALSE;
        }

      data->bounds_known = FALSE;

      if (full_extent)
        {
          data->bounds_known = TRUE;
          data->empty        = FALSE;
          data->bounds       = data->rect;
        }
      break;

    case GIMP_CHANNEL_OP_ADD:
      if (! intersects)
        return FALSE;

      data->bounds_known = FALSE;

      if (full_extent && (mask->bounds_known ||
                          gegl_rectangle_equal (&data->rect, &extent)))
        {
          data->bounds_known = TRUE;
          data->empty        = FALSE;

          if (mask->bounds_known && ! mask->empty)
            {
              gegl_rectangle_bounding_box (&data->bounds,
                                           &data->bounds, &data->rect);
            }
          else
            {
              data->bounds = data->rect;
            }
        }
      break;

    case GIMP_CHANNEL_OP_SUBTRACT:
      if (intersects && mask->bounds_known)
        {
          if (mask->empty)
            {
              intersects = FALSE;
            }
          else
            {
              intersects = gegl_rectangle_intersect (&data->rect,
                                                     &data->rect,
                                                     &data->bounds);
            }
        }

      if (! intersects)
        return FALSE;

      if (full_value &&
          gegl_rectangle_contains (&data->rect,
                                   mask->bounds_known ? &data->bounds :
                                                        &extent))
        {
          gimp_channel_combine_clear (mask, NULL);

          data->bounds_known = TRUE;
          data->empty        = TRUE;

          return FALSE;
        }

      data->bounds_known = FALSE;

      gegl_buffer_set_abyss (buffer, &data->rect);
      break;

    case GIMP_CHANNEL_OP_INTERSECT:
      if (intersects && mask->bounds_known)
        {
          if (mask->empty)
            {
              intersects = FALSE;
            }
          else
            {
              intersects = gegl_rectangle_intersect (&data->rect,
                                                     &data->rect,
                                                     &data->bounds);
            }
        }

      if (! intersects)
        {
          gimp_channel_combine_clear (mask, NULL);

          data->bounds_known = TRUE;
          data->empty        = TRUE;

          return FALSE;
        }

      if (full_value && mask->bounds_known &&
          gegl_rectangle_contains (&data->rect, &data->bounds))
        {
          return FALSE;
        }

      data->bounds_known = FALSE;

      gimp_channel_combine_clear_complement (mask, &data->rect);

      gegl_buffer_set_abyss (buffer, &data->rect);
      break;
    }

  return TRUE;
}
Пример #18
0
static inline gboolean
_gegl_buffer_cl_cache_flush2 (GeglTileHandlerCache *cache,
                              const GeglRectangle  *roi)
{
  size_t size;
  GList *elem;
  GeglRectangle tmp;
  cl_int cl_err = 0;

  gpointer data;
  gboolean need_cl = FALSE;

  for (elem=cache_entries; elem; elem=elem->next)
    {
      CacheEntry *entry = elem->data;

      if (entry->valid && entry->tile_storage->cache == cache
          && (!roi || gegl_rectangle_intersect (&tmp, roi, &entry->roi)))
        {
          entry->valid = FALSE;
          entry->used ++;

          gegl_cl_color_babl (entry->buffer->soft_format, &size);

          data = g_malloc(entry->roi.width * entry->roi.height * size);

          cl_err = gegl_clEnqueueReadBuffer(gegl_cl_get_command_queue(),
                                            entry->tex, CL_TRUE, 0, entry->roi.width * entry->roi.height * size, data,
                                            0, NULL, NULL);
          /* tile-ize */
          gegl_buffer_set (entry->buffer, &entry->roi, 0, entry->buffer->soft_format, data, GEGL_AUTO_ROWSTRIDE);

          entry->used --;
          need_cl = TRUE;

          g_free(data);

          CL_CHECK;
        }
    }

  if (need_cl)
    {
      cl_err = gegl_clFinish (gegl_cl_get_command_queue ());
      CL_CHECK;

      g_mutex_lock (&cache_mutex);

      while (cache_entry_find_invalid (&data))
        {
          CacheEntry *entry = data;

#if 1
          GEGL_NOTE (GEGL_DEBUG_OPENCL, "Removing from cl-cache: %p %s {%d %d %d %d}", entry->buffer, babl_get_name(entry->buffer->soft_format),
                                                                                       entry->roi.x, entry->roi.y, entry->roi.width, entry->roi.height);
#endif

          gegl_clReleaseMemObject(entry->tex);

          memset (entry, 0x0, sizeof (CacheEntry));

          g_slice_free (CacheEntry, data);
          cache_entries = g_list_remove (cache_entries, data);
        }

      g_mutex_unlock (&cache_mutex);
    }

  return TRUE;

error:

  g_mutex_lock (&cache_mutex);

  while (cache_entry_find_invalid (&data))
    {
      g_slice_free (CacheEntry, data);
      cache_entries = g_list_remove (cache_entries, data);
    }

  g_mutex_unlock (&cache_mutex);

  /* XXX : result is corrupted */
  return FALSE;
}
Пример #19
0
GeglBuffer *
gegl_operation_context_dup_input_maybe_copy (GeglOperationContext *context,
                                             const gchar          *padname,
                                             const GeglRectangle  *roi)
{
  GeglBuffer    *input;
  GeglBuffer    *output;
  GeglBuffer    *result;
  GeglRectangle  required;
  GeglRectangle  temp;
  gint           shift_x;
  gint           shift_y;
  gint           tile_width;
  gint           tile_height;

  input = GEGL_BUFFER (gegl_operation_context_get_object (context, padname));

  if (! input)
    return NULL;

  /* return input directly when processing a level greater than 0, since
   * gegl_buffer_copy() only copies level-0 tiles
   */
  if (context->level > 0)
    return g_object_ref (input);

  output = GEGL_BUFFER (gegl_operation_context_get_object (context, "output"));

  /* return input directly when processing in-place, otherwise, the copied
   * input buffer will occupy space in the cache after the original is modified
   */
  if (input == output)
    return g_object_ref (input);

  /* get required region to copy */
  required = gegl_operation_get_required_for_output (context->operation,
                                                     padname, roi);

  /* return input directly if the required rectangle is infinite, so that we
   * don't attempt to copy an infinite region
   */
  if (gegl_rectangle_is_infinite_plane (&required))
    return g_object_ref (input);

  /* align required region to the tile grid */
  shift_x     = input->shift_x;
  shift_y     = input->shift_y;
  tile_width  = input->tile_width;
  tile_height = input->tile_height;

  temp.x      = (gint) floor ((gdouble) (required.x                   + shift_x) / tile_width)  * tile_width;
  temp.y      = (gint) floor ((gdouble) (required.y                   + shift_y) / tile_height) * tile_height;
  temp.width  = (gint) ceil  ((gdouble) (required.x + required.width  + shift_x) / tile_width)  * tile_width  - temp.x;
  temp.height = (gint) ceil  ((gdouble) (required.y + required.height + shift_y) / tile_height) * tile_height - temp.y;

  temp.x -= shift_x;
  temp.y -= shift_y;

  required = temp;

  /* intersect required region with input abyss */
  gegl_rectangle_intersect (&required, &required, &input->abyss);

  /* create new buffer with similar characteristics to the input buffer */
  result = g_object_new (GEGL_TYPE_BUFFER,
                         "format",       input->soft_format,
                         "x",            input->extent.x,
                         "y",            input->extent.y,
                         "width",        input->extent.width,
                         "height",       input->extent.height,
                         "abyss-x",      input->abyss.x,
                         "abyss-y",      input->abyss.y,
                         "abyss-width",  input->abyss.width,
                         "abyss-height", input->abyss.height,
                         "shift-x",      shift_x,
                         "shift-y",      shift_y,
                         "tile-width",   tile_width,
                         "tile-height",  tile_height,
                         NULL);

  /* if the tile size doesn't match, bail */
  if (result->tile_width != tile_width || result->tile_height != tile_height)
    {
      g_object_unref (result);

      return g_object_ref (input);
    }

  /* copy required region from input to result -- tiles will generally be COWed */
  gegl_buffer_copy (input,  &required, GEGL_ABYSS_NONE,
                    result, &required);

  return result;
}
Пример #20
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *roi,
         gint                 level)
{
  GeglRectangle            src_rect;
  GeglRectangle           *whole_region;
  GeglProperties          *o = GEGL_PROPERTIES (operation);
  GeglOperationAreaFilter *op_area;

  op_area = GEGL_OPERATION_AREA_FILTER (operation);

  whole_region = gegl_operation_source_get_bounding_box (operation, "input");

  if (gegl_operation_use_opencl (operation))
    if (cl_process (operation, input, output, roi))
      return TRUE;

  if (o->size_x * o->size_y < SQR (ALLOC_THRESHOLD_SIZE))
    {
      gfloat  background_color[4];
      gfloat *input_buf  = g_new (gfloat,
                                  (CHUNK_SIZE + o->size_x * 2) *
                                  (CHUNK_SIZE + o->size_y * 2) * 4);
      gfloat *output_buf = g_new (gfloat, SQR (CHUNK_SIZE) * 4);
      gint    i, j;

      gegl_color_get_pixel (o->background, babl_format("RaGaBaA float"),
                            background_color);

      for (j = 0; (j-1) * CHUNK_SIZE < roi->height; j++)
        for (i = 0; (i-1) * CHUNK_SIZE < roi->width; i++)
          {
            GeglRectangle chunked_result;
            GeglRectangle chunked_sizes;

            chunked_result = *GEGL_RECTANGLE (roi->x + i * CHUNK_SIZE,
                                              roi->y + j * CHUNK_SIZE,
                                              CHUNK_SIZE, CHUNK_SIZE);

            gegl_rectangle_intersect (&chunked_result, &chunked_result, roi);

            if (chunked_result.width < 1  || chunked_result.height < 1)
              continue;

            src_rect = chunked_result;
            src_rect.x -= op_area->left;
            src_rect.y -= op_area->top;
            src_rect.width += op_area->left + op_area->right;
            src_rect.height += op_area->top + op_area->bottom;

            gegl_buffer_get (input, &src_rect, 1.0, babl_format ("RaGaBaA float"),
                             input_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);

            gegl_rectangle_copy (&chunked_sizes, &chunked_result);
            chunked_sizes.x = 0;
            chunked_sizes.y = 0;

            set_rectangle (output_buf, &chunked_sizes, &chunked_sizes,
                           chunked_result.width, background_color,
                           GEGL_PIXELIZE_NORM_INFINITY);

            pixelize (input_buf, output_buf, &chunked_result, &src_rect,
                      whole_region, o);

            gegl_buffer_set (output, &chunked_result, 0,
                             babl_format ("RaGaBaA float"),
                             output_buf, GEGL_AUTO_ROWSTRIDE);
          }

      g_free (input_buf);
      g_free (output_buf);
    }
  else
    {
      gegl_buffer_set_color (output, roi, o->background);
      pixelize_noalloc (input, output, roi, whole_region, o);
    }

  return  TRUE;
}
Пример #21
0
static GObject *
gegl_buffer_constructor (GType                  type,
                         guint                  n_params,
                         GObjectConstructParam *params)
{
  GObject         *object;
  GeglBuffer      *buffer;
  GeglTileBackend *backend;
  GeglTileHandler *handler;
  GeglTileSource  *source;

  object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);

  buffer  = GEGL_BUFFER (object);
  handler = GEGL_TILE_HANDLER (object);
  source  = handler->source;
  backend = gegl_buffer_backend (buffer);

  if (source)
    {
      if (GEGL_IS_TILE_STORAGE (source))
        buffer->format = GEGL_TILE_STORAGE (source)->format;
      else if (GEGL_IS_BUFFER (source))
        buffer->format = GEGL_BUFFER (source)->format;
    }
  else
    {
      if (buffer->backend)
        {
          backend = buffer->backend;
          buffer->format = gegl_tile_backend_get_format (backend);
        }
      else
        {
          gboolean use_ram = FALSE;
          const char *maybe_path = NULL;

          if (!buffer->format)
            {
              g_warning ("Buffer constructed without format, assuming RGBA float");
              buffer->format = babl_format("RGBA float");
            }

          /* make a new backend & storage */

          if (buffer->path)
            maybe_path = buffer->path;
          else
            maybe_path = gegl_config ()->swap;

          if (maybe_path)
            use_ram = g_ascii_strcasecmp (maybe_path, "ram") == 0;
          else
            use_ram = TRUE;

          if (use_ram == TRUE)
            {
              backend = g_object_new (GEGL_TYPE_TILE_BACKEND_RAM,
                                      "tile-width", buffer->tile_width,
                                      "tile-height", buffer->tile_height,
                                      "format", buffer->format,
                                      NULL);
            }
          else
            {
              if (buffer->path)
                {
                  backend = g_object_new (GEGL_TYPE_TILE_BACKEND_FILE,
                                          "tile-width", buffer->tile_width,
                                          "tile-height", buffer->tile_height,
                                          "format", buffer->format,
                                          "path", buffer->path,
                                          NULL);
                }
              else
                {
                  gchar *path = get_next_swap_path();

                  backend = g_object_new (GEGL_TYPE_TILE_BACKEND_FILE,
                                          "tile-width", buffer->tile_width,
                                          "tile-height", buffer->tile_height,
                                          "format", buffer->format,
                                          "path", path,
                                          NULL);
                  g_free (path);
                }
            }

          buffer->backend = backend;
        }

      source = GEGL_TILE_SOURCE (gegl_tile_storage_new (backend));
      gegl_tile_handler_set_source ((GeglTileHandler*)(buffer), source);
      g_object_unref (source);
      g_object_unref (backend);
    }

   /* Connect to the changed signal of source, this is used by some backends
    * (e.g. File) to notify of outside changes to the buffer.
    */
  if (GEGL_IS_TILE_STORAGE (source))
    {
      g_signal_connect (source, "changed",
                        G_CALLBACK (gegl_buffer_storage_changed),
                        buffer);
    }

  g_assert (backend);

  if (buffer->extent.width == -1 ||
      buffer->extent.height == -1) /* no specified extents,
                                      inheriting from source */
    {
      if (GEGL_IS_BUFFER (source))
        {
          buffer->extent.x = GEGL_BUFFER (source)->extent.x;
          buffer->extent.y = GEGL_BUFFER (source)->extent.y;
          buffer->extent.width  = GEGL_BUFFER (source)->extent.width;
          buffer->extent.height = GEGL_BUFFER (source)->extent.height;
        }
      else if (GEGL_IS_TILE_STORAGE (source))
        {
          buffer->extent.x = 0;
          buffer->extent.y = 0;
          buffer->extent.width  = GEGL_TILE_STORAGE (source)->width;
          buffer->extent.height = GEGL_TILE_STORAGE (source)->height;
        }
      else
        {
          buffer->extent.x = 0;
          buffer->extent.y = 0;
          buffer->extent.width  = 0;
          buffer->extent.height = 0;
        }
    }

  buffer->abyss_tracks_extent = FALSE;

  if (buffer->abyss.width == 0 &&
      buffer->abyss.height == 0 &&
      buffer->abyss.x == 0 &&
      buffer->abyss.y == 0)      /* 0 sized extent == inherit buffer extent
                                  */
    {
      buffer->abyss.x             = buffer->extent.x;
      buffer->abyss.y             = buffer->extent.y;
      buffer->abyss.width         = buffer->extent.width;
      buffer->abyss.height        = buffer->extent.height;
      buffer->abyss_tracks_extent = TRUE;
    }
  else if (buffer->abyss.width == 0 &&
           buffer->abyss.height == 0)
    {
      g_warning ("peculiar abyss dimensions: %i,%i %ix%i",
                 buffer->abyss.x,
                 buffer->abyss.y,
                 buffer->abyss.width,
                 buffer->abyss.height);
    }
  else if (buffer->abyss.width == -1 ||
           buffer->abyss.height == -1)
    {
      buffer->abyss.x      = GEGL_BUFFER (source)->abyss.x - buffer->shift_x;
      buffer->abyss.y      = GEGL_BUFFER (source)->abyss.y - buffer->shift_y;
      buffer->abyss.width  = GEGL_BUFFER (source)->abyss.width;
      buffer->abyss.height = GEGL_BUFFER (source)->abyss.height;
    }

  /* intersect our own abyss with parent's abyss if it exists
   */
  if (GEGL_IS_BUFFER (source))
    {
      GeglRectangle parent;
      GeglRectangle request;
      GeglRectangle self;

      parent.x = GEGL_BUFFER (source)->abyss.x - buffer->shift_x;
      parent.y = GEGL_BUFFER (source)->abyss.y - buffer->shift_y;
      parent.width = GEGL_BUFFER (source)->abyss.width;
      parent.height = GEGL_BUFFER (source)->abyss.height;

      request.x = buffer->abyss.x;
      request.y = buffer->abyss.y;
      request.width = buffer->abyss.width;
      request.height = buffer->abyss.height;

      gegl_rectangle_intersect (&self, &parent, &request);

      /* Don't have the abyss track the extent if the intersection is
       * not the entire extent. Otherwise, setting the extent identical
       * to itself could suddenly make the abyss bigger. */
      if (buffer->abyss_tracks_extent &&
          (buffer->extent.x      != self.x ||
           buffer->extent.y      != self.y ||
           buffer->extent.width  != self.width ||
           buffer->extent.height != self.height) )
        {
          buffer->abyss_tracks_extent = FALSE;
        }

      buffer->abyss.x      = self.x;
      buffer->abyss.y      = self.y;
      buffer->abyss.width  = self.width;
      buffer->abyss.height = self.height;
    }

  /* compute our own total shift <- this should probably happen
   * approximatly first */
  if (GEGL_IS_BUFFER (source))
    {
      GeglBuffer *source_buf;

      source_buf = GEGL_BUFFER (source);

      buffer->shift_x += source_buf->shift_x;
      buffer->shift_y += source_buf->shift_y;
    }
  else
    {
    }

  buffer->tile_storage = gegl_buffer_tile_storage (buffer);

  /* intialize the soft format to be equivalent to the actual
   * format
   */
  buffer->soft_format = buffer->format;

  return object;
}
Пример #22
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglChantO    *o = GEGL_CHANT_PROPERTIES (operation);
  LensValues     lens;
  GeglRectangle  boundary;
  gint           i, j;
  gfloat        *src_buf, *dst_buf;
  gfloat         background[4];

  boundary = *gegl_operation_source_get_bounding_box (operation, "input");
  lens     =  lens_setup_calc (o, boundary);

  src_buf = g_new0 (gfloat, SQR (MAX_WH) * 4);
  dst_buf = g_new0 (gfloat, SQR (CHUNK_SIZE) * 4);

  gegl_color_get_pixel (o->background, babl_format ("RGBA float"), background);

  for (j = 0; (j-1) * CHUNK_SIZE < result->height; j++)
    for (i = 0; (i-1) * CHUNK_SIZE < result->width; i++)
      {
        GeglRectangle chunked_result;
        GeglRectangle area;
        gint          x, y;

        chunked_result = *GEGL_RECTANGLE (result->x + i * CHUNK_SIZE,
                                          result->y + j * CHUNK_SIZE,
                                          CHUNK_SIZE, CHUNK_SIZE);

        gegl_rectangle_intersect (&chunked_result, &chunked_result, result);

        if (chunked_result.width < 1  || chunked_result.height < 1)
          continue;

        area = get_required (&boundary, &chunked_result, operation);

        clamp_area (&area, lens.centre_x, lens.centre_y);

        gegl_buffer_get (input, &area, 1.0, babl_format ("RGBA float"), src_buf,
                         GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);

        for (y = chunked_result.y; y < chunked_result.y + chunked_result.height; y++)
          for (x = chunked_result.x; x < chunked_result.x + chunked_result.width; x++)
            {
              lens_distort_func (src_buf, dst_buf, &area, &chunked_result, &boundary,
                                 &lens, x, y, input, background);
            }

        gegl_buffer_set (output, &chunked_result, 0, babl_format ("RGBA float"),
                         dst_buf, GEGL_AUTO_ROWSTRIDE);
      }

  g_free (dst_buf);
  g_free (src_buf);

  return TRUE;
}
Пример #23
0
void
gegl_graph_prepare_request (GeglGraphTraversal  *path,
                            const GeglRectangle *request_roi,
                            gint                 level)
{
  GList *list_iter = NULL;
  static const GeglRectangle empty_rect = {0, 0, 0, 0};

  g_return_if_fail (path->bfs_path);

  if (path->rects_dirty)
    {
      /* Zero all the needs rects so we can intersect with them below */
      for (list_iter = path->bfs_path; list_iter; list_iter = list_iter->next)
        {
          GeglNode *node = GEGL_NODE (list_iter->data);
          GeglOperationContext *context = g_hash_table_lookup (path->contexts, node);

          /* We only need to reset the need rect, result will always get overwritten */
          gegl_operation_context_set_need_rect (context, &empty_rect);

          /* Reset cached status, because the rect we need may have changed */
          context->cached = FALSE;
        }
    }

  path->rects_dirty = TRUE;

  {
    /* Prep the first node */
    GeglNode *node = GEGL_NODE (path->bfs_path->data);
    GeglOperationContext *context = g_hash_table_lookup (path->contexts, node);
    GeglRectangle new_need;

    g_return_if_fail (context);

    gegl_rectangle_intersect (&new_need, &node->have_rect, request_roi);

    gegl_operation_context_set_need_rect (context, &new_need);
    gegl_operation_context_set_result_rect (context, &new_need);
  }
  
  /* Iterate over all the nodes and propagate the requested rectangle */
  for (list_iter = path->bfs_path; list_iter; list_iter = list_iter->next)
    {
      GeglNode             *node      = GEGL_NODE (list_iter->data);
      GeglOperation        *operation = node->operation;
      GeglOperationContext *context;
      GeglRectangle        *request;
      GSList               *input_pads;
      
      context = g_hash_table_lookup (path->contexts, node);
      g_return_if_fail (context);
      
      request = gegl_operation_context_get_need_rect (context);

      if (request->width == 0 || request->height == 0)
        {
          gegl_operation_context_set_result_rect (context, &empty_rect);
          continue;
        }
      
      if (node->cache)
        {
          gint i;
          for (i = level; i >=0 && !context->cached; i--)
          {
            if (gegl_region_rect_in (node->cache->valid_region[level], request) == GEGL_OVERLAP_RECTANGLE_IN)
            {
              /* This node is cached and the cache fulfills our need rect */
              context->cached = TRUE;
              gegl_operation_context_set_result_rect (context, &empty_rect);
            }
          }
          if (context->cached)
            continue;
        }

      {
        /* Expand request if the operation has a minimum processing requirement */
        GeglRectangle full_request = gegl_operation_get_cached_region (operation, request);

        gegl_operation_context_set_need_rect (context, &full_request);

        /* FIXME: We could trim this down based on the cache, instead of being all or nothing */
        gegl_operation_context_set_result_rect (context, request);

        for (input_pads = node->input_pads; input_pads; input_pads = input_pads->next)
          {
            GeglPad *source_pad = gegl_pad_get_connected_to (input_pads->data);

            if (source_pad)
              {
                GeglNode             *source_node    = gegl_pad_get_node (source_pad);
                GeglOperationContext *source_context = g_hash_table_lookup (path->contexts, source_node);
                const gchar          *pad_name       = gegl_pad_get_name (input_pads->data);

                GeglRectangle rect, current_need, new_need;

                /* Combine this need rect with any existing request */
                rect = gegl_operation_get_required_for_output (operation, pad_name, &full_request);
                current_need = *gegl_operation_context_get_need_rect (source_context);

                gegl_rectangle_bounding_box (&new_need, &rect, &current_need);

                /* Limit request to the nodes output */
                gegl_rectangle_intersect (&new_need, &source_node->have_rect, &new_need);

                gegl_operation_context_set_need_rect (source_context, &new_need);
              }
          }
      }
    }
}
Пример #24
0
static void
gimp_channel_combine_clear (GimpChannel         *mask,
                            const GeglRectangle *rect)
{
  GeglBuffer    *buffer;
  GeglRectangle  area;
  GeglRectangle  update_area;

  if (mask->bounds_known && mask->empty)
    return;

  buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

  if (rect)
    {
      if (rect->width <= 0 || rect->height <= 0)
        return;

      if (mask->bounds_known)
        {
          if (! gegl_rectangle_intersect (&area,
                                          GEGL_RECTANGLE (mask->x1,
                                                          mask->y1,
                                                          mask->x2 - mask->x1,
                                                          mask->y2 - mask->y1),
                                          rect))
            {
              return;
            }
        }
      else
        {
          area = *rect;
        }

      update_area = area;
    }
  else
    {
      if (mask->bounds_known)
        {
          area.x      = mask->x1;
          area.y      = mask->y1;
          area.width  = mask->x2 - mask->x1;
          area.height = mask->y2 - mask->y1;
        }
      else
        {
          area.x      = 0;
          area.y      = 0;
          area.width  = gimp_item_get_width  (GIMP_ITEM (mask));
          area.height = gimp_item_get_height (GIMP_ITEM (mask));
        }

      update_area = area;

      gimp_gegl_rectangle_align_to_tile_grid (&area, &area, buffer);
    }

  gegl_buffer_clear (buffer, &area);

  gimp_drawable_update (GIMP_DRAWABLE (mask),
                        update_area.x, update_area.y,
                        update_area.width, update_area.height);
}
Пример #25
0
static void
stamp (GeglChantO          *o,
       const GeglRectangle *result,
       gdouble              x,
       gdouble              y)
{
  WarpPrivate         *priv = (WarpPrivate*) o->chant_data;
  GeglBufferIterator  *it;
  const Babl          *format;
  gdouble              influence;
  gdouble              x_mean = 0.0;
  gdouble              y_mean = 0.0;
  gint                 x_iter, y_iter;
  GeglRectangle        area = {x - o->size / 2.0,
                               y - o->size / 2.0,
                               o->size,
                               o->size};

  /* first point of the stroke */
  if (!priv->last_point_set)
    {
      priv->last_x = x;
      priv->last_y = y;
      priv->last_point_set = TRUE;
      return;
    }

  /* don't stamp if outside the roi treated */
  if (!gegl_rectangle_intersect (NULL, result, &area))
    return;

  format = babl_format_n (babl_type ("float"), 2);

  /* If needed, compute the mean deformation */
  if (o->behavior == GEGL_WARP_BEHAVIOR_SMOOTH)
    {
      gint pixel_count = 0;

      it = gegl_buffer_iterator_new (priv->buffer, &area, 0, format, GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (it))
        {
          gint    n_pixels    = it->length;
          gfloat *coords      = it->data[0];

          while (n_pixels--)
            {
              x_mean += coords[0];
              y_mean += coords[1];
              coords += 2;
            }
          pixel_count += it->roi->width * it->roi->height;
        }
      x_mean /= pixel_count;
      y_mean /= pixel_count;
    }

  it = gegl_buffer_iterator_new (priv->buffer, &area, 0, format, GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (it))
    {
      /* iterate inside the stamp roi */
      gint    n_pixels = it->length;
      gfloat *coords   = it->data[0];

      x_iter = it->roi->x; /* initial x         */
      y_iter = it->roi->y; /* and y coordinates */

      while (n_pixels--)
        {
          influence = 0.01 * o->strength * get_stamp_force (o,
                                                            x_iter - x,
                                                            y_iter - y);

          switch (o->behavior)
            {
              case GEGL_WARP_BEHAVIOR_MOVE:
                coords[0] += influence * (priv->last_x - x);
                coords[1] += influence * (priv->last_y - y);
                break;
              case GEGL_WARP_BEHAVIOR_GROW:
                coords[0] -= 2.0 * influence * (x_iter - x) / o->size;
                coords[1] -= 2.0 * influence * (y_iter - y) / o->size;
                break;
              case GEGL_WARP_BEHAVIOR_SHRINK:
                coords[0] += 2.0 * influence * (x_iter - x) / o->size;
                coords[1] += 2.0 * influence * (y_iter - y) / o->size;
                break;
              case GEGL_WARP_BEHAVIOR_SWIRL_CW:
                coords[0] += 3.0 * influence * (y_iter - y) / o->size;
                coords[1] -= 5.0 * influence * (x_iter - x) / o->size;
                break;
              case GEGL_WARP_BEHAVIOR_SWIRL_CCW:
                coords[0] -= 3.0 * influence * (y_iter - y) / o->size;
                coords[1] += 5.0 * influence * (x_iter - x) / o->size;
                break;
              case GEGL_WARP_BEHAVIOR_ERASE:
                coords[0] *= 1.0 - MIN (influence, 1.0);
                coords[1] *= 1.0 - MIN (influence, 1.0);
                break;
              case GEGL_WARP_BEHAVIOR_SMOOTH:
                coords[0] -= influence * (coords[0] - x_mean);
                coords[1] -= influence * (coords[1] - y_mean);
                break;
            }

          coords += 2;

          /* update x and y coordinates */
          x_iter++;
          if (x_iter >= (it->roi->x + it->roi->width))
            {
              x_iter = it->roi->x;
              y_iter++;
            }
        }
    }

  /* Memorize the stamp location for movement dependant behavior like move */
  priv->last_x = x;
  priv->last_y = y;
}