static void
gimp_projection_construct_gegl (GimpProjection *proj,
                                gint            x,
                                gint            y,
                                gint            w,
                                gint            h)
{
    GeglNode      *sink;
    GeglRectangle  rect;

    sink = gimp_projection_get_sink_node (proj);

    rect.x      = x;
    rect.y      = y;
    rect.width  = w;
    rect.height = h;

    if (! proj->processor)
        proj->processor = gegl_node_new_processor (sink, &rect);
    else
        gegl_processor_set_rectangle (proj->processor, &rect);

    while (gegl_processor_work (proj->processor, NULL));

    /* FIXME: Reuse it when it can handle dirty rects when painting
     * properly
     */
    g_object_unref (proj->processor);
    proj->processor = NULL;
}
Exemple #2
0
void
gimp_applicator_apply (GimpApplicator       *applicator,
                       GeglBuffer           *src_buffer,
                       GeglBuffer           *apply_buffer,
                       gint                  apply_buffer_x,
                       gint                  apply_buffer_y,
                       gdouble               opacity,
                       GimpLayerModeEffects  paint_mode)
{
    gint width  = gegl_buffer_get_width  (apply_buffer);
    gint height = gegl_buffer_get_height (apply_buffer);

    if (applicator->src_buffer != src_buffer)
    {
        applicator->src_buffer = src_buffer;

        gegl_node_set (applicator->src_node,
                       "buffer", src_buffer,
                       NULL);
    }

    if (applicator->apply_buffer != apply_buffer)
    {
        applicator->apply_buffer = apply_buffer;

        gegl_node_set (applicator->apply_src_node,
                       "buffer", apply_buffer,
                       NULL);
    }


    gegl_node_set (applicator->apply_offset_node,
                   "x", (gdouble) apply_buffer_x,
                   "y", (gdouble) apply_buffer_y,
                   NULL);

    if ((applicator->opacity    != opacity) ||
            (applicator->paint_mode != paint_mode))
    {
        applicator->opacity    = opacity;
        applicator->paint_mode = paint_mode;

        gimp_gegl_mode_node_set (applicator->mode_node,
                                 paint_mode, opacity, FALSE);
    }

    gegl_processor_set_rectangle (applicator->processor,
                                  GEGL_RECTANGLE (apply_buffer_x,
                                          apply_buffer_y,
                                          width, height));

    while (gegl_processor_work (applicator->processor, NULL));
}
static gboolean
test_change_processor_rect_do_test (GeglProcessor       *processor,
                                    const GeglRectangle *rect,
                                    GeglNode            *sink)
{
  gint        i                         = 0;
  gboolean    result                    = TRUE;
  float       expected_result_buffer[4] = { 1.0, 1.0, 1.0, 1.0 };
  float       result_buffer[4]          = { 0, };
  GeglBuffer *buffer                    = NULL;

  gegl_node_set (sink,
                 "buffer", &buffer,
                 NULL);
  
  gegl_processor_set_rectangle (processor, rect);

  while (gegl_processor_work (processor, NULL));

  gegl_buffer_get (buffer,
                   rect,
                   1.0,
                   babl_format ("RGBA float"),
                   result_buffer,
                   GEGL_AUTO_ROWSTRIDE,
                   GEGL_ABYSS_NONE);

  /* Compare with a small epsilon to account for accumulated error */
  for(i = 0; i < G_N_ELEMENTS (expected_result_buffer); i++)
    result = result && FLOATS_EQUAL (expected_result_buffer[i], result_buffer[i]);

  gegl_node_set (sink,
                 "buffer", NULL,
                 NULL);

  g_object_unref (buffer);

  return result;
}
static gboolean
task_monitor(ViewHelper *self)
{
    if (!self->processor || !self->node) {
        return FALSE;
    }

    // PERFORMANCE: combine all the rects added to the queue during a single
    // iteration of the main loop somehow

    if (!self->currently_processed_rect) {

        if (g_queue_is_empty(self->processing_queue)) {
            // Unregister worker
            self->monitor_id = 0;
            return FALSE;
        }
        else {
            // Fetch next rect to process
            self->currently_processed_rect = (GeglRectangle *)g_queue_pop_tail(self->processing_queue);
            g_assert(self->currently_processed_rect);
            gegl_processor_set_rectangle(self->processor, self->currently_processed_rect);
        }
    }

    gboolean processing_done = !gegl_processor_work(self->processor, NULL);

    if (processing_done) {
        // Go to next region
        if (self->currently_processed_rect) {
            g_free(self->currently_processed_rect);
        }
        self->currently_processed_rect = NULL;
    }

    return TRUE;
}
gboolean
gimp_gegl_apply_cached_operation (GeglBuffer          *src_buffer,
                                  GimpProgress        *progress,
                                  const gchar         *undo_desc,
                                  GeglNode            *operation,
                                  GeglBuffer          *dest_buffer,
                                  const GeglRectangle *dest_rect,
                                  GeglBuffer          *cache,
                                  const GeglRectangle *valid_rects,
                                  gint                 n_valid_rects,
                                  gboolean             cancellable)
{
  GeglNode      *gegl;
  GeglNode      *dest_node;
  GeglRectangle  rect = { 0, };
  GeglProcessor *processor        = NULL;
  gboolean       progress_started = FALSE;
  gdouble        value;
  gboolean       cancel           = FALSE;

  g_return_val_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer), FALSE);
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
  g_return_val_if_fail (GEGL_IS_NODE (operation), FALSE);
  g_return_val_if_fail (GEGL_IS_BUFFER (dest_buffer), FALSE);
  g_return_val_if_fail (cache == NULL || GEGL_IS_BUFFER (cache), FALSE);
  g_return_val_if_fail (valid_rects == NULL || cache != NULL, FALSE);
  g_return_val_if_fail (valid_rects == NULL || n_valid_rects != 0, FALSE);

  if (dest_rect)
    {
      rect = *dest_rect;
    }
  else
    {
      rect = *GEGL_RECTANGLE (0, 0, gegl_buffer_get_width  (dest_buffer),
                                    gegl_buffer_get_height (dest_buffer));
    }

  gegl = gegl_node_new ();

  if (! gegl_node_get_parent (operation))
    gegl_node_add_child (gegl, operation);

  if (src_buffer && gegl_node_has_pad (operation, "input"))
    {
      GeglNode *src_node;

      /* dup() because reading and writing the same buffer doesn't
       * work with area ops when using a processor. See bug #701875.
       */
      if (progress && (src_buffer == dest_buffer))
        src_buffer = gegl_buffer_dup (src_buffer);
      else
        g_object_ref (src_buffer);

      src_node = gegl_node_new_child (gegl,
                                      "operation", "gegl:buffer-source",
                                      "buffer",    src_buffer,
                                      NULL);

      g_object_unref (src_buffer);

      gegl_node_connect_to (src_node,  "output",
                            operation, "input");
    }

  dest_node = gegl_node_new_child (gegl,
                                   "operation", "gegl:write-buffer",
                                   "buffer",    dest_buffer,
                                   NULL);

  gegl_node_connect_to (operation, "output",
                        dest_node, "input");

  if (progress)
    {
      processor = gegl_node_new_processor (dest_node, &rect);

      if (gimp_progress_is_active (progress))
        {
          if (undo_desc)
            gimp_progress_set_text_literal (progress, undo_desc);

          progress_started = FALSE;
          cancellable      = FALSE;
        }
      else
        {
          gimp_progress_start (progress, cancellable, "%s", undo_desc);

          if (cancellable)
            g_signal_connect (progress, "cancel",
                              G_CALLBACK (gimp_gegl_apply_operation_cancel),
                              &cancel);

          progress_started = TRUE;
        }
    }

  if (cache)
    {
      cairo_region_t *region;
      gint            all_pixels;
      gint            done_pixels = 0;
      gint            n_rects;
      gint            i;

      region = cairo_region_create_rectangle ((cairo_rectangle_int_t *) &rect);

      all_pixels = rect.width * rect.height;

      for (i = 0; i < n_valid_rects; i++)
        {
          gegl_buffer_copy (cache,       valid_rects + i, GEGL_ABYSS_NONE,
                            dest_buffer, valid_rects + i);

          cairo_region_subtract_rectangle (region,
                                           (cairo_rectangle_int_t *)
                                           valid_rects + i);

          done_pixels += valid_rects[i].width * valid_rects[i].height;

          if (progress)
            gimp_progress_set_value (progress,
                                     (gdouble) done_pixels /
                                     (gdouble) all_pixels);
        }

      n_rects = cairo_region_num_rectangles (region);

      for (i = 0; ! cancel && (i < n_rects); i++)
        {
          cairo_rectangle_int_t render_rect;

          cairo_region_get_rectangle (region, i, &render_rect);

          if (progress)
            {
              gint rect_pixels = render_rect.width * render_rect.height;

#ifdef REUSE_PROCESSOR
              gegl_processor_set_rectangle (processor,
                                            (GeglRectangle *) &render_rect);
#else
              g_object_unref (processor);
              processor = gegl_node_new_processor (dest_node,
                                                   (GeglRectangle *) &render_rect);
#endif

              while (! cancel && gegl_processor_work (processor, &value))
                {
                  gimp_progress_set_value (progress,
                                           ((gdouble) done_pixels +
                                            value * rect_pixels) /
                                           (gdouble) all_pixels);

                  if (cancellable)
                    while (! cancel && g_main_context_pending (NULL))
                      g_main_context_iteration (NULL, FALSE);
                }

              done_pixels += rect_pixels;
            }
          else
            {
              gegl_node_blit (dest_node, 1.0, (GeglRectangle *) &render_rect,
                              NULL, NULL, 0, GEGL_BLIT_DEFAULT);
            }
        }

      cairo_region_destroy (region);
    }
  else
    {
      if (progress)
        {
          while (! cancel && gegl_processor_work (processor, &value))
            {
              gimp_progress_set_value (progress, value);

              if (cancellable)
                while (! cancel && g_main_context_pending (NULL))
                  g_main_context_iteration (NULL, FALSE);
            }
        }
      else
        {
          gegl_node_blit (dest_node, 1.0, &rect,
                          NULL, NULL, 0, GEGL_BLIT_DEFAULT);
        }
    }

  if (processor)
    g_object_unref (processor);

  g_object_unref (gegl);

  if (progress_started)
    {
      gimp_progress_end (progress);

      if (cancellable)
        g_signal_handlers_disconnect_by_func (progress,
                                              gimp_gegl_apply_operation_cancel,
                                              &cancel);
    }

  return ! cancel;
}