[gegl] Finish removing old cairo code, put most operation logic in place



commit 4af4d357decd9c549aaa38f0cf6e6f3ead89950e
Author: Barak Itkin <lightningismyname gmail com>
Date:   Tue Aug 2 01:36:10 2011 +0300

    Finish removing old cairo code, put most operation logic in place

 operations/common/seamless-clone/find-outline.c    |    4 +-
 operations/common/seamless-clone/find-outline.h    |    2 +-
 operations/common/seamless-clone/make-mesh.c       |   63 ++++-
 operations/common/seamless-clone/make-mesh.h       |   11 +-
 .../poly2tri-c/refine/triangulation.c              |   25 ++
 .../poly2tri-c/refine/triangulation.h              |    5 +-
 operations/common/seamless-clone/seamless-clone.c  |  293 ++++++--------------
 7 files changed, 180 insertions(+), 223 deletions(-)
---
diff --git a/operations/common/seamless-clone/find-outline.c b/operations/common/seamless-clone/find-outline.c
index 280ebbe..d993718 100644
--- a/operations/common/seamless-clone/find-outline.c
+++ b/operations/common/seamless-clone/find-outline.c
@@ -161,8 +161,8 @@ outline_walk_cw (GeglRectangle      *rect,
 #define pteq(pt1,pt2) (((pt1)->x == (pt2)->x) && ((pt1)->y == (pt2)->y))
 
 GPtrArray*
-outline_find_ccw (GeglRectangle *rect,
-                  gfloat        *pixels)
+sc_outline_find_ccw (GeglRectangle *rect,
+                    gfloat        *pixels)
 {
   GPtrArray *points = g_ptr_array_new ();
   
diff --git a/operations/common/seamless-clone/find-outline.h b/operations/common/seamless-clone/find-outline.h
index 2fd7155..79dcd4c 100644
--- a/operations/common/seamless-clone/find-outline.h
+++ b/operations/common/seamless-clone/find-outline.h
@@ -33,7 +33,7 @@ typedef struct  {
  */
 typedef GPtrArray ScOutline;
 
-ScOutline* outline_find_ccw (GeglRectangle *rect, gfloat *pixels);
+ScOutline* sc_outline_find_ccw (GeglRectangle *rect, gfloat *pixels);
 
 void       sc_outline_free  (ScOutline *self);
 
diff --git a/operations/common/seamless-clone/make-mesh.c b/operations/common/seamless-clone/make-mesh.c
index 12b559f..5d4a905 100644
--- a/operations/common/seamless-clone/make-mesh.c
+++ b/operations/common/seamless-clone/make-mesh.c
@@ -99,6 +99,8 @@ sc_compute_sample_list_weights (gdouble        Px,
   gdouble weightTotal = 0, weightTemp;
   gint special = -1;
 
+  sl->total_weight = 0;
+
   for (i = 0; i < N; i++)
     {
       ScPoint *pt1 = g_ptr_array_index_cyclic (sl->points, i);
@@ -121,6 +123,7 @@ sc_compute_sample_list_weights (gdouble        Px,
           
           g_ptr_array_add (sl->points, pt1);
           g_array_append_val (sl->weights, temp);
+          sl->total_weight = 1;
           return;
         }
 
@@ -146,12 +149,13 @@ sc_compute_sample_list_weights (gdouble        Px,
   for (i = 1; i < N; i++)
     {
       weightTemp = (tan_as_half[i - 1] + tan_as_half[i % N]) / pow (norms[i % N], 2);
+      sl->total_weight += weightTemp;
       g_array_append_val (sl->weights, weightTemp);
        }
 }
 
-static ScSampleList*
-sc_compute_sample_list (ScOutline     *outline,
+ScSampleList*
+sc_sample_list_compute (ScOutline     *outline,
                         gdouble        Px,
                         gdouble        Py)
 {
@@ -177,13 +181,66 @@ sc_compute_sample_list (ScOutline     *outline,
   return sl;
 }
 
+void
+sc_sample_list_free (ScSampleList *self)
+{
+  g_ptr_array_free (self->points);
+  g_array_free (self->weights);
+  g_slice_free (ScSampleList, self);
+}
+
+ScMeshSampling*
+sc_mesh_sampling_compute (ScOutline         *outline,
+                          P2tRTriangulation *mesh)
+{
+  GPtrArray  *points = g_ptr_array_new ();
+  GHashTable *pt2sample = g_hash_table_new (g_direct_hash, g_direct_equal);
+  gint i;
+
+  /* Note that the get_points function increases the refcount of the
+   * returned points, so we must unref them when done with them
+   */
+  p2tr_triangulation_get_points (mesh, points)
+
+  for (i = 0; i < points->len; i++)
+    {
+         P2tRPoint    *pt = (P2tRPoint*) g_ptr_array_index (points, i);
+         ScSampleList *sl = sc_compute_sample_list (outline, pt->x, pt->y);
+         g_hash_table_insert (pt2sample, pt, sl);
+       }
+
+  /* We will unref the points when freeing the hash table */
+  g_ptr_array_free (points);
+       
+  return pt2sample;
+}
+
+static void
+sc_mesh_sampling_entry_free_hfunc (gpointer point,
+                                   gpointer sampling_list,
+                                   gpointer unused)
+{
+  /* Unref the point returned from triangulation_get_points */
+  p2tr_point_unref ((P2tRPoint*)point);
+  /* Free the sampling list */
+  sc_sample_list_free ((ScSampleList*)sampling_list);
+}
+
+void
+sc_mesh_sampling_free (ScMeshSampling *self)
+{
+  GHashTable     *real = (GHashTable*) self;
+  g_hash_table_foreach (real, sc_mesh_sampling_entry_free_hfunc, NULL);
+  g_hash_table_destroy (real);
+}
+
 /**
  * sc_make_fine_mesh:
  * @outline: An ScOutline object describing the PSLG of the mesh
  * @mesh_bounds: A rectangle in which the bounds of the mesh should be
  *               stored
  */
-static P2tRTriangulation*
+P2tRTriangulation*
 sc_make_fine_mesh (ScOutline     *outline,
                    GeglRectangle *mesh_bounds)
 {
diff --git a/operations/common/seamless-clone/make-mesh.h b/operations/common/seamless-clone/make-mesh.h
index 43af30b..79eaf9a 100644
--- a/operations/common/seamless-clone/make-mesh.h
+++ b/operations/common/seamless-clone/make-mesh.h
@@ -26,12 +26,13 @@ typedef struct {
   gdouble    total_weight;
 } ScSampleList;
 
-void sc_free_sample_list (ScSampleList *self);
+typedef GHashTable ScMeshSampling;
 
-void
-ComputeSampling (P2tRTriangulation  *T,
-                 P2tRHashSet       **edgePts,
-                 GHashTable        **sampling);
+ScSampleList* sc_sample_list_compute (ScOutline *outline, gdouble Px, gdouble Py);
+void          sc_sample_list_free    (ScSampleList *self);
+
+ScMeshSampling* sc_mesh_sampling_compute (ScOutline *outline, P2tRTriangulation *mesh);
+void            sc_mesh_sampling_free    (ScMeshSampling *self);
 
 void
 ComputeInnerSample (P2tRPoint  *X,
diff --git a/operations/common/seamless-clone/poly2tri-c/refine/triangulation.c 
b/operations/common/seamless-clone/poly2tri-c/refine/triangulation.c
index fa09578..bcdea60 100755
--- a/operations/common/seamless-clone/poly2tri-c/refine/triangulation.c
+++ b/operations/common/seamless-clone/poly2tri-c/refine/triangulation.c
@@ -144,6 +144,31 @@ p2tr_triangulation_add_tr (P2tRTriangulation *self, P2tRTriangle *tr)
   p2tr_triangle_ref (tr);
 }
 
+void
+p2tr_triangulation_get_points (P2tRTriangulation *self, GPtrArray *dest)
+{
+  P2tRHashSetIter  iter;
+  P2tRTriangle    *tr;
+  P2tRHashSet     *pts = p2tr_hash_set_set_new (g_direct_hash, g_direct_equal, NULL);
+  gint             i;
+  
+  p2tr_hash_set_iter_init (&iter, self->tris);
+  while (p2tr_hash_set_iter_next (&iter, (gpointer*)&tr))
+    {
+         for (i = 0; i < 3; i++)
+           {
+                 P2tRPoint *pt = p2tr_edge_get_end (tr->edges[i]);
+             if (! p2tr_hash_set_contains (pts, pt))
+               {
+                         p2tr_point_ref (pt);
+                         g_ptr_array_add (dest, pt);
+                         p2tr_hash_set_insert (pts, pt);
+                   }
+               }
+    }
+
+  g_hash_table_free (pts);
+}
 /* ########################################################################## */
 /*                               Point struct                                 */
 /* ########################################################################## */
diff --git a/operations/common/seamless-clone/poly2tri-c/refine/triangulation.h 
b/operations/common/seamless-clone/poly2tri-c/refine/triangulation.h
index 8dd56c9..f300cd8 100755
--- a/operations/common/seamless-clone/poly2tri-c/refine/triangulation.h
+++ b/operations/common/seamless-clone/poly2tri-c/refine/triangulation.h
@@ -106,6 +106,9 @@ void p2tr_triangulation_add_pt (P2tRTriangulation *self, P2tRPoint *pt);
 void p2tr_triangulation_add_ed (P2tRTriangulation *self, P2tREdge *ed);
 void p2tr_triangulation_add_tr (P2tRTriangulation *self, P2tRTriangle *tr);
 
+void p2tr_triangulation_get_points (P2tRTriangulation *self, GPtrArray *dest);
+
+
 /* ########################################################################## */
 /*                               Point struct                                 */
 /* ########################################################################## */
@@ -327,4 +330,4 @@ void p2tr_debug_tri (P2tRTriangle* tr, gboolean newline);
 }
 #endif
 
-#endif /* TRIANGULATION_H */
\ No newline at end of file
+#endif /* TRIANGULATION_H */
diff --git a/operations/common/seamless-clone/seamless-clone.c 
b/operations/common/seamless-clone/seamless-clone.c
index d5b5e2a..3aaec50 100644
--- a/operations/common/seamless-clone/seamless-clone.c
+++ b/operations/common/seamless-clone/seamless-clone.c
@@ -27,8 +27,6 @@
 #include <glib/gi18n-lib.h>
 #include "gegl-chant.h"
 
-#include <cairo.h>
-
 #include <stdio.h> /* TODO: get rid of this debugging way! */
 
 #include "poly2tri-c/poly2tri.h"
@@ -65,200 +63,43 @@ prepare (GeglOperation *operation)
   gegl_operation_set_format (operation, "output", format);
 }
 
-/*******************************************************************/
-/******************** Part 2 - Mesh rendering **********************/
-/*******************************************************************/
-
-/*
- * Store the bounds of the mesh inside mesh_bounds
- */
-static cairo_pattern_t*
-gimp_operation_seamless_clone_make_fine_mesh (GPtrArray     *ptList,
-                                              GeglBuffer    *aux,
-                                              GeglBuffer    *input,
-                                              GeglRectangle *mesh_bounds)
-{
-  Babl *format = babl_format("RGB float");
-  gfloat dest[3], aux_c[3], input_c[3];
-  GList *X = NULL;   /* List of P2tRPoint */
-  GList *XEs = NULL; /* List of P2tREdge */
-  gint i, N = ptList->len;
-
-  gint min_x = G_MAXINT, max_x = -G_MAXINT, min_y = G_MAXINT, max_y = -G_MAXINT;
-
-  GList *tmpPts = NULL, *tris = NULL;
-
-  printf ("Making mesh from %d points!\n", ptList->len);
-
-  for (i = 0; i < N; i++)
-    {
-      SPoint *pt = (SPoint*) g_ptr_array_index (ptList, i);
-      min_x = MIN (pt->x, min_x);
-      min_y = MIN (pt->y, min_y);
-      max_x = MAX (pt->x, max_x);
-      max_y = MAX (pt->y, max_y);
-      /* No one should care if the points are given in reverse order */
-      X = g_list_prepend (X, p2tr_point_new (pt->x, pt->y));
-    }
-
-  mesh_bounds->x = min_x;
-  mesh_bounds->y = min_y;
-  mesh_bounds->width = max_x - min_x;
-  mesh_bounds->height = max_y - min_y;
-
-  GList *liter = X;
-  while (liter != NULL)
-    {
-      P2tREdge *E = p2tr_edge_new ((P2tRPoint*)(liter->data), 
(P2tRPoint*)(g_list_cyclic_next(X,liter)->data));
-      XEs = g_list_prepend (XEs, E);
-      p2tr_edge_set_constrained (E, TRUE);
-      liter = liter->next;
-    }
-
-  printf ("Edges %p made, now just triangulate!\n", XEs);
-  P2tRTriangulation *T = p2tr_triangulate (X);
-  printf ("Triangulation %p made! %d triangles, %d(/2) edges, %d points\n", T, g_hash_table_size 
(T->tris),g_hash_table_size (T->edges),g_hash_table_size (T->pts));
-
-  DelaunayTerminator (T,XEs,M_PI/7,p2tr_false_delta);
-  printf ("Terminated!\n");
-
-  P2trHashSetIter iter;
-  P2tRTriangle *t;
-  p2tr_hash_set_iter_init (&iter, T->tris);
-  cairo_pattern_t *mesh = cairo_pattern_create_mesh ();
-
-  P2tRHashSet  *edgePts;
-  GHashTable   *sampling;
-
-  ComputeSampling (T, &edgePts, &sampling);
-
-
-#define GetPtColor(pt,dest)                    \
-do {                                           \
-  if (p2tr_hash_set_contains (edgePts, (pt)))  \
-    {                                          \
-      gegl_buffer_sample (aux, (pt)->x, (pt)->y, NULL, aux_c, format, GEGL_INTERPOLATION_NEAREST); \
-      gegl_buffer_sample (input, (pt)->x, (pt)->y, NULL, input_c, format, GEGL_INTERPOLATION_NEAREST); \
-      (dest)[0] = TO_CAIRO(input_c[0] - aux_c[0]);         \
-      (dest)[1] = TO_CAIRO(input_c[1] - aux_c[1]);         \
-      (dest)[2] = TO_CAIRO(input_c[2] - aux_c[2]);         \
-    }                                          \
-  else                                         \
-    ComputeInnerSample ((pt), g_hash_table_lookup (sampling, (pt)), input, aux, (dest)); \
-} while (FALSE)
-
-  while (p2tr_hash_set_iter_next (&iter, (gpointer*)&t))
-    {
-      p2tr_assert_and_explain (t != NULL, "NULL triangle found!\n");
-      p2tr_assert_and_explain (t->edges[0] != NULL && t->edges[1] != NULL && t->edges[2] != NULL,
-                               "Removed triangle found!\n");
-
-
-      P2tRPoint* tpt;
-      cairo_mesh_pattern_begin_patch (mesh);
-
-      tpt = p2tr_edge_get_start (t->edges[0]);
-      cairo_mesh_pattern_move_to (mesh, tpt->x, tpt->y);
 
-      tpt = p2tr_edge_get_start (t->edges[1]);
-      cairo_mesh_pattern_line_to (mesh, tpt->x, tpt->y);
-
-      tpt = p2tr_edge_get_start (t->edges[2]);
-      cairo_mesh_pattern_line_to (mesh, tpt->x, tpt->y);
-
-//      tpt = p2t_triangle_get_point (triangle_index(tris,i), 0);
-//      cairo_mesh_pattern_line_to (mesh, tpt->x, tpt->y);
-
-      tpt = p2tr_edge_get_start (t->edges[0]);
-      GetPtColor (tpt,dest);
-      cairo_mesh_pattern_set_corner_color_rgb (mesh, 0, dest[2], dest[1], dest[0]);
-
-      tpt = p2tr_edge_get_start (t->edges[1]);
-      GetPtColor (tpt,dest);
-      cairo_mesh_pattern_set_corner_color_rgb (mesh, 1, dest[2], dest[1], dest[0]);
-
-      tpt = p2tr_edge_get_start (t->edges[2]);
-      GetPtColor (tpt,dest);
-      cairo_mesh_pattern_set_corner_color_rgb (mesh, 2, dest[2], dest[1], dest[0]);
-
-      cairo_mesh_pattern_end_patch (mesh);
-      }
-  return mesh;
-}
+typedef struct {
+  GeglBuffer     *aux_buf;
+  GeglBuffer     *input_buf;
+  ScMeshSampling *sampling;
+} ScColorComputeInfo;
 
 static void
-render_outline (GPtrArray       *pts,
-                cairo_t         *cr)
+sc_point_to_color_func (P2tRPoint *point,
+                        gfloat    *dest,
+                        gpointer  *cci_p)
 {
-  SPoint *pt;
+  ScColorComputeInfo *cci = (ScColorComputeInfo*) cci_p;
+  gfloat aux_c[4], input_c[4], dest_c[3] = {0, 0, 0};
   gint i;
+  const gint N = cci->points->len;
+  
+  /* This function should be very light, so save some effort! */
+  const static Babl *format = babl_format("RGB float");
 
-  if (pts->len <= 0)
-    return;
-
-  pt = (SPoint*) g_ptr_array_index (pts, 0);
-
-  cairo_move_to (cr, pt->x, pt->y);
-
-  for (i = 1; i < pts->len; i++)
+  for (i = 0; i < N; i++)
     {
-      pt = (SPoint*) g_ptr_array_index (pts, i);
-      cairo_line_to (cr, pt->x, pt->y);
-    }
-
-  cairo_close_path (cr);
-}
-
-/*******************************************************************/
-/********************** Part 3 - Cairo Utils ***********************/
-/*******************************************************************/
-static cairo_surface_t *
-surface_for_rect (const GeglRectangle *roi)
-{
-  guchar *data;
-
-  data = g_new0 (guchar, roi->width * roi->height * 4);
-
-  return cairo_image_surface_create_for_data (data,
-                                              CAIRO_FORMAT_ARGB32,
-                                              roi->width,
-                                              roi->height,
-                                              roi->width * 4);
-}
-
-static void
-commit_and_free_surface (GeglBuffer          *output,
-                         GeglBuffer          *aux,
-                         const GeglRectangle *roi,
-                         cairo_surface_t     *surface)
-{
-  gint i, j;
-  Babl *format = babl_format ("RGBA u8");
-  guchar *data = cairo_image_surface_get_data (surface);
-  guchar bg[3];
-
-  g_assert (cairo_image_surface_get_width (surface) == roi->width);
-  g_assert (cairo_image_surface_get_height (surface) == roi->height);
-  g_assert (cairo_image_surface_get_stride (surface) == roi->width * 4);
-
-  for (i = 0; i < roi->height; i++)
-    for (j = 0; j < roi->width; j++)
-      {
-        gint off = (i * roi->width + j) * 4;
-        gegl_buffer_sample (aux, roi->x + j, roi->y + i, NULL, bg, format, GEGL_INTERPOLATION_NEAREST);
-
-        data[off++] = (gint)CLAMP(bg[0] + FROM_CAIRO(data[off]), 0, 255);
-        data[off++] = (gint)CLAMP(bg[1] + FROM_CAIRO(data[off]), 0, 255);
-        data[off++] = (gint)CLAMP(bg[2] + FROM_CAIRO(data[off]), 0, 255);
-        data[off] = (data[off] >= 255) ? 255 : 0;
-      }
-
-
-  gegl_buffer_set (output, roi, format, data,
-                   GEGL_AUTO_ROWSTRIDE);
-
-  cairo_surface_destroy (surface);
-//  g_free (data);
+      P2tRPoint *pt = g_ptr_array_index (cci->sampling->points, i);
+      gdouble weight = g_array_index (cci->sampling->weights, gdouble, i);
+      
+      gegl_buffer_sample (cci->aux_buf, pt->x, pt->y, NULL, aux_c, format, GEGL_INTERPOLATION_NEAREST);
+      gegl_buffer_sample (cci->input_buf, pt->x, pt->y, NULL, input_c, format, GEGL_INTERPOLATION_NEAREST);
+      
+      dest_c[0] = weight * (input_buf[0] - aux_buf[0]);
+      dest_c[1] = weight * (input_buf[1] - aux_buf[1]);
+      dest_c[2] = weight * (input_buf[2] - aux_buf[2]);
+       }
+
+  dest[0] = dest_c[0] / cci->sampling->total_weight;
+  dest[1] = dest_c[1] / cci->sampling->total_weight;
+  dest[2] = dest_c[2] / cci->sampling->total_weight;
+  dest[3] = 1;
 }
 
 static gboolean
@@ -269,45 +110,75 @@ process (GeglOperation       *operation,
          const GeglRectangle *result)
 {
   GPtrArray *ptList;
-  gfloat    *aux_raw;
+  gfloat    *aux_raw, *out_raw;
 
-  // GeglRectangle input_rect = *gegl_buffer_get_extent (input);
+  GeglRectangle input_rect = *gegl_buffer_get_extent (input);
   GeglRectangle aux_rect   = *gegl_operation_source_get_bounding_box (operation, "aux");
 
-  cairo_surface_t *out_surf;
-  cairo_t         *cr;
+  ScOutline          *outline;
+  
+  P2tRTriangulation  *mesh;
+  GeglRectangle       mesh_bounds;
+
+  ScMeshSampling     *mesh_sampling;
+
+  ScColorComputeInfo  cci;
+  P2tRImageConfig     imcfg;
 
   printf ("The aux_rect is:\n");
   gegl_rectangle_dump (&aux_rect);
 
+  /********************************************************************/
+  /* Part 1: The preprocessing                                        */
+  /********************************************************************/
+  
+  /* First, find the paste outline */
   aux_raw = g_new (gfloat, 4 * aux_rect.width * aux_rect.height);
-
   gegl_buffer_get (aux, 1.0, &aux_rect, babl_format("RGBA float"), aux_raw, GEGL_AUTO_ROWSTRIDE);
-
-  ptList = outline_find_ccw (&aux_rect, aux_raw);
-
+  
+  outline = outline_find_ccw (&aux_rect, aux_raw);
+  
   g_free (aux_raw);
   aux_raw = NULL;
 
-  printf ("The result is:\n");
-  gegl_rectangle_dump (result);
+  /* Then, Generate the mesh */
+  mesh = sc_make_fine_mesh (outline, &mesh_bounds);
+
+  /* Finally, Generate the mesh sample list for each point */
+  mesh_sampling = sc_mesh_sampling_compute (outline, mesh);
+
+  /* If caching of UV is desired, it shold be done here! */
+
+  /********************************************************************/
+  /* Part 2: The rendering                                            */
+  /********************************************************************/
 
-  out_surf = surface_for_rect (result);
-  cr = cairo_create (out_surf);
+  /* Alocate the output buffer */
+  out_raw = g_new (gfloat, 4 * result.width * result.height);
 
-  GeglRectangle mesh_bounds;
-  cairo_pattern_t *mesh = gimp_operation_seamless_clone_make_fine_mesh (ptList, aux, input, &mesh_bounds);
-  cairo_set_source (cr, mesh);
-  render_outline (ptList, cr);
-  cairo_fill_preserve (cr);
+  /* Render the mesh into it */
+  cci->aux_buf = aux;
+  cci->input_buf = input;
+  cci->sampling = mesh_sampling;
+
+  imcfg->min_x = result->x;
+  imcfg->min_y = result->y;
+  imcfg->step_x = imcfg->step_y = 1;
+  imcfg->x_samples = result->width;
+  imcfg->y_samples = result->height;
+  imcfg->cpp = 4;
   
-  cairo_pattern_destroy (mesh);
-  cairo_destroy (cr);
-  commit_and_free_surface (output, aux, result, out_surf);
+  p2tr_mesh_render_scanline (mesh, out_raw, &imcfg, sc_point_to_color_func, &cci);
 
-  g_free (aux_raw);
-  g_ptr_array_free (ptList, TRUE);
+  /* TODO: Add the aux to the mesh rendering! */
+  gegl_buffer_set (output, result, babl_format("RGBA float"), out_raw, GEGL_AUTO_ROWSTRIDE);
 
+  /* Free memory, by the order things were allocated! */
+  g_free (out_raw);
+  sc_mesh_sampling_free (mesh_sampling);
+  p2tr_triangulation_free (mes);
+  sc_outline_free (outline);
+  
   return  TRUE;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]