示例#1
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglChantO          *o = GEGL_CHANT_PROPERTIES (operation);
  WarpPrivate         *priv = (WarpPrivate*) o->chant_data;
  gdouble              dist;
  gdouble              stamps;
  gdouble              spacing = MAX (o->size * 0.01, 0.5); /*1% spacing for starters*/

  GeglPathPoint        prev, next, lerp;
  gulong               i;
  GeglPathList        *event;

  priv->buffer = gegl_buffer_dup (input);

  event = gegl_path_get_path (o->stroke);

  prev = *(event->d.point);

  while (event->next)
    {
      event = event->next;
      next = *(event->d.point);
      dist = gegl_path_point_dist (&next, &prev);
      stamps = dist / spacing;

      if (stamps < 1)
        {
          stamp (o, result, next.x, next.y);
          prev = next;
        }
      else
        {
          for (i = 0; i < stamps; i++)
            {
              gegl_path_point_lerp (&lerp, &prev, &next, (i * spacing) / dist);
              stamp (o, result, lerp.x, lerp.y);
            }
          prev = lerp;
        }
    }

  /* Affect the output buffer */
  gegl_buffer_copy (priv->buffer, result, output, result);
  gegl_buffer_set_extent (output, gegl_buffer_get_extent (input));
  g_object_unref (priv->buffer);

  /* prepare for the recomputing of the op */
  priv->last_point_set = FALSE;

  return TRUE;
}
示例#2
0
static gboolean
process (GeglOperation        *operation,
         GeglOperationContext *context,
         const gchar          *output_prop,
         const GeglRectangle  *result,
         gint                  level)
{
  GeglProperties  *o    = GEGL_PROPERTIES (operation);
  WarpPrivate     *priv = (WarpPrivate*) o->user_data;

  GeglBuffer      *input;

  gdouble          spacing = MAX (o->size * o->spacing, 0.5);
  gdouble          dist;
  gint             stamps;
  gint             i;
  gdouble          t;

  GeglPathPoint    prev, next, lerp;
  GeglPathList    *event;
  WarpPointList   *processed_event;
  WarpPointList  **processed_event_ptr;

  if (!o->stroke || strcmp (output_prop, "output"))
    return FALSE;

  /* if the previously processed stroke is valid, the cached buffer can be
   * passed as output right away.
   */
  if (priv->processed_stroke_valid)
    {
      g_assert (priv->buffer != NULL);

      gegl_operation_context_set_object (context,
                                         "output", G_OBJECT (priv->buffer));

      return TRUE;
    }

  /* ... otherwise, we need to check if the previously processed stroke is an
   * initial segment of the current stroke ...
   */

  event               = gegl_path_get_path (o->stroke);
  processed_event     = priv->processed_stroke;
  processed_event_ptr = &priv->processed_stroke;

  while (event && processed_event)
    {
      if (event->d.point[0].x != processed_event->point.x ||
          event->d.point[0].y != processed_event->point.y)
        {
          break;
        }

      processed_event_ptr = &processed_event->next;

      event           = event->next;
      processed_event = processed_event->next;
    }

  /* if the loop stopped before we reached the last event of the processed
   * stroke, it's not an initial segment, and we need to clear the cache, and
   * process the entire stroke.
   */
  if (processed_event)
    {
      clear_cache (o);

      event               = gegl_path_get_path (o->stroke);
      processed_event_ptr = &priv->processed_stroke;
    }
  /* otherwise, we simply continue processing remaining stroke on top of the
   * previously processed buffer.
   */

  /* intialize the cached buffer if we don't already have one. */
  if (! priv->buffer)
    {
      input = GEGL_BUFFER (gegl_operation_context_get_object (context,
                                                              "input"));

      priv->buffer = gegl_buffer_dup (input);

      /* we pass the buffer as output directly while keeping it cached, so mark
       * it as forked.
       */
      gegl_object_set_has_forked (G_OBJECT (priv->buffer));
    }

  if (event)
    {
      /* is this the first event of the stroke? */
      if (! priv->processed_stroke)
        {
          prev = *(event->d.point);

          priv->last_x = prev.x;
          priv->last_y = prev.y;
        }
      else
        {
          prev.x = priv->last_x;
          prev.y = priv->last_y;
        }

      for (; event; event = event->next)
        {
          next = *(event->d.point);
          dist = gegl_path_point_dist (&next, &prev);
          stamps = floor (dist / spacing) + 1;

          /* stroke the current segment, such that there's always a stamp at
           * its final endpoint, and at positive integer multiples of
           * `spacing` away from it.
           */

          if (stamps == 1)
            {
              stamp (o, next.x, next.y);
            }
          else
            {
              for (i = 0; i < stamps; i++)
                {
                  t = 1.0 - ((stamps - i - 1) * spacing) / dist;

                  gegl_path_point_lerp (&lerp, &prev, &next, t);
                  stamp (o, lerp.x, lerp.y);
                }
            }

          prev = next;

          /* append the current event to the processed path. */
          processed_event        = g_slice_new (WarpPointList);
          processed_event->point = next;

          *processed_event_ptr = processed_event;
          processed_event_ptr  = &processed_event->next;
        }

      *processed_event_ptr = NULL;
    }

  priv->processed_stroke_valid = TRUE;

  /* pass the processed buffer as output */
  gegl_operation_context_set_object (context,
                                     "output", G_OBJECT (priv->buffer));

  return TRUE;
}