[gegl/paint-system: 6/7] Extract brush-stroke code from gegl-path.c



commit c27187c9244eff4fd427bc4dbedff3f30510b5da
Author: Damien de Lemeny <d delemeny gmail com>
Date:   Thu Jun 10 15:29:22 2010 +0200

    Extract brush-stroke code from gegl-path.c
    
    * remove stroke code from gegl-path.c
    * rename gegl:path to gegl:brush-stroke(workshop)
    * modify the stroke operation (heavy refactoring)
    * prepare the use of brush workers
    * modify gegl-paint example to use gegl:brush-stroke

 examples/gegl-paint.c              |   47 ++---
 gegl/property-types/gegl-path.c    |  235 ----------------------
 operations/external/Makefile.am    |    5 +-
 operations/external/path.c         |  342 --------------------------------
 operations/workshop/brush-stroke.c |  382 ++++++++++++++++++++++++++++++++++++
 5 files changed, 403 insertions(+), 608 deletions(-)
---
diff --git a/examples/gegl-paint.c b/examples/gegl-paint.c
index 6dfabbf..81a32f4 100644
--- a/examples/gegl-paint.c
+++ b/examples/gegl-paint.c
@@ -23,22 +23,24 @@
 #include "util/gegl-view.c"
 #include "property-types/gegl-path.h"
 
-#define HARDNESS     0.2
-#define LINEWIDTH   60.0
-#define COLOR       "rgba(0.0,0.0,0.0,0.4)"
+#define SCALE    3.0
+#define SPACING  0.5
+#define HARDNESS 0.2
+#define OPACITY  0.5
+#define COLOR    "rgb(0.5,0.3,0.0)"
 
 GtkWidget         *window;
 GtkWidget         *view;
 static GeglBuffer *buffer   = NULL;
+
 static GeglNode   *gegl     = NULL;
 static GeglNode   *out      = NULL;
 static GeglNode   *top      = NULL;
+static GeglNode   *stroke   = NULL;
+
 static gboolean    pen_down = FALSE;
 static GeglPath   *vector   = NULL;
 
-static GeglNode   *over     = NULL;
-static GeglNode   *stroke   = NULL;
-
 
 static gboolean paint_press (GtkWidget      *widget,
                              GdkEventButton *event)
@@ -47,16 +49,16 @@ static gboolean paint_press (GtkWidget      *widget,
     {
       vector     = gegl_path_new ();
 
-      over       = gegl_node_new_child (gegl, "operation", "gegl:over", NULL);
-      stroke     = gegl_node_new_child (gegl, "operation", "gegl:path",
+      stroke     = gegl_node_new_child (gegl, "operation", "gegl:brush-stroke",
                                         "d", vector,
-                                        "fill-opacity", 0.0,
-                                        "stroke", gegl_color_new (COLOR),
-                                        "stroke-width", LINEWIDTH,
-                                        "stroke-hardness", HARDNESS,
+                                        "color", gegl_color_new (COLOR),
+                                        "scale", SCALE,
+                                        "hardness", HARDNESS,
+                                        "spacing", SPACING,
+                                        "opacity", OPACITY,
                                         NULL);
-      gegl_node_link_many (top, over, out, NULL);
-      gegl_node_connect_to (stroke, "output", over, "aux");
+      gegl_node_link_many (top, stroke, out, NULL);
+
       gegl_path_append (vector, 'M', event->x, event->y);
 
       pen_down = TRUE;
@@ -89,35 +91,26 @@ static gboolean paint_release (GtkWidget      *widget,
 {
   if (event->button == 1)
     {
-      gdouble        x0, x1, y0, y1;
       GeglProcessor *processor;
       GeglNode      *writebuf;
-      GeglRectangle  roi;
-
-      gegl_path_get_bounds (vector, &x0, &x1, &y0, &y1);
-
-      roi.x = x0 - LINEWIDTH;
-      roi.y = y0 - LINEWIDTH;
-      roi.width = x1 - x0 + LINEWIDTH * 2;
-      roi.height = y1 - y0 + LINEWIDTH * 2;
+      GeglRectangle  roi = gegl_node_get_bounding_box(stroke);
 
       writebuf = gegl_node_new_child (gegl,
                                       "operation", "gegl:write-buffer",
                                       "buffer",    buffer,
                                       NULL);
-      gegl_node_link_many (over, writebuf, NULL);
+      gegl_node_link_many (stroke, writebuf, NULL);
 
       processor = gegl_node_new_processor (writebuf, &roi);
       while (gegl_processor_work (processor, NULL)) ;
 
       gegl_processor_destroy (processor);
-      g_object_unref (writebuf);
 
       gegl_node_link_many (top, out, NULL);
-      g_object_unref (over);
+
       g_object_unref (stroke);
+      g_object_unref (writebuf);
 
-      over     = NULL;
       stroke   = NULL;
       pen_down = FALSE;
 
diff --git a/gegl/property-types/gegl-path.c b/gegl/property-types/gegl-path.c
index 50af23a..ea06760 100644
--- a/gegl/property-types/gegl-path.c
+++ b/gegl/property-types/gegl-path.c
@@ -2006,241 +2006,6 @@ fill_close:  /* label used for goto to close last segment */
   }
 }
 
-typedef struct StampStatic {
-  gboolean  valid;
-  Babl     *format;
-  gfloat   *buf;
-  gdouble   radius;
-}StampStatic;
-
-#if 0
-void gegl_path_stamp (GeglBuffer *buffer,
-                      gdouble     x,
-                      gdouble     y,
-                      gdouble     radius,
-                      gdouble     hardness,
-                      GeglColor  *color,
-                      gdouble     opacity);
-#endif
-
-static void gegl_path_stamp (GeglBuffer *buffer,
-                             const GeglRectangle *clip_rect,
-                             gdouble     x,
-                             gdouble     y,
-                             gdouble     radius,
-                             gdouble     hardness,
-                             GeglColor  *color,
-                             gdouble     opacity)
-{
-  gfloat col[4];
-  static StampStatic s = {FALSE,}; /* XXX: 
-                                      we will ultimately leak the last valid
-                                      cached brush. */
-
-  GeglRectangle temp;
-  GeglRectangle roi;
-
-  roi.x = floor(x-radius);
-  roi.y = floor(y-radius);
-  roi.width = ceil (x+radius) - floor (x-radius);
-  roi.height = ceil (y+radius) - floor (y-radius);
-
-  gegl_color_get_rgba4f (color, col);
-
-  /* bail out if we wouldn't leave a mark on the buffer */
-  if (!gegl_rectangle_intersect (&temp, &roi, clip_rect))
-    {
-      return;
-    }
-
-  if (s.format == NULL)
-    s.format = babl_format ("RaGaBaA float");
-
-  if (s.buf == NULL ||
-      s.radius != radius)
-    {
-      if (s.buf != NULL)
-        g_free (s.buf);
-      /* allocate a little bit more, just in case due to rounding errors and
-       * such */
-      s.buf = g_malloc (4*4* (roi.width + 2 ) * (roi.height + 2));
-      s.radius = radius;
-      s.valid = TRUE;  
-    }
-  g_assert (s.buf);
-
-  gegl_buffer_get_unlocked (buffer, 1.0, &roi, s.format, s.buf, 0);
-
-  {
-    gint u, v;
-    gint i=0;
-
-    gfloat radius_squared = radius * radius;
-    gfloat inner_radius_squared = (radius * hardness)*(radius * hardness);
-    gfloat soft_range = radius_squared - inner_radius_squared;
-
-    for (v= roi.y; v < roi.y + roi.height ; v++)
-    {
-      gfloat vy2 = (v-y)*(v-y);
-      for (u= roi.x; u < roi.x + roi.width; u++)
-        {
-          gfloat o = (u-x) * (u-x) + vy2;
-
-          if (o < inner_radius_squared)
-             o = col[3];
-          else if (o < radius_squared)
-            {
-              o = (1.0 - (o-inner_radius_squared) / (soft_range)) * col[3];
-            }
-          else
-            {
-              o=0.0;
-            }
-         if (o!=0.0)
-           {
-             gint c;
-             o = o*opacity;
-             for (c=0;c<4;c++)
-               s.buf[i*4+c] = (s.buf[i*4+c] * (1.0-o) + col[c] * o);
-           }
-         i++;
-        }
-    }
-  }
-  gegl_buffer_set_unlocked (buffer, &roi, s.format, s.buf, 0);
-}
-
-
-void gegl_path_stroke (GeglBuffer *buffer,
-                       const GeglRectangle *clip_rect,
-                       GeglPath *vector,
-                       GeglColor  *color,
-                       gdouble     linewidth,
-                       gdouble     hardness,
-                       gdouble     opacity);
-
-
-void gegl_path_stroke (GeglBuffer *buffer,
-                       const GeglRectangle *clip_rect,
-                       GeglPath *vector,
-                       GeglColor  *color,
-                       gdouble     linewidth,
-                       gdouble     hardness,
-                       gdouble     opacity)
-{
-  GeglPathPrivate *priv = GEGL_PATH_GET_PRIVATE (vector);
-  gfloat traveled_length = 0;
-  gfloat need_to_travel = 0;
-  gfloat x = 0,y = 0;
-  GeglPathList *iter;
-  gdouble       xmin, xmax, ymin, ymax;
-  GeglRectangle extent;
-
-  if (!vector)
-    return;
-
-  if (!clip_rect)
-    {
-      g_print ("using buffer extent\n");
-      clip_rect = gegl_buffer_get_extent (buffer);
-    }
-
-  ensure_flattened (vector);
-
-  iter = priv->flat_path;
-  gegl_path_get_bounds (vector, &xmin, &xmax, &ymin, &ymax);
-  extent.x = floor (xmin);
-  extent.y = floor (ymin);
-  extent.width = ceil (xmax) - extent.x;
-  extent.height = ceil (ymax) - extent.y;
-
-  if (!gegl_rectangle_intersect (&extent, &extent, clip_rect))
-   {
-     return;
-   }
-  if (gegl_buffer_is_shared (buffer))
-    while (!gegl_buffer_try_lock (buffer));
-
-  /*gegl_buffer_clear (buffer, &extent);*/
-
-  while (iter)
-    {
-      /*fprintf (stderr, "%c, %i %i\n", iter->d.type, iter->d.point[0].x, iter->d.point[0].y);*/
-      switch (iter->d.type)
-        {
-          case 'M':
-            x = iter->d.point[0].x;
-            y = iter->d.point[0].y;
-            need_to_travel = 0;
-            traveled_length = 0;
-            break;
-          case 'L':
-            {
-              Point a,b;
-
-              gfloat spacing;
-              gfloat local_pos;
-              gfloat distance;
-              gfloat offset;
-              gfloat leftover;
-              gfloat radius = linewidth / 2.0;
-
-
-              a.x = x;
-              a.y = y;
-
-              b.x = iter->d.point[0].x;
-              b.y = iter->d.point[0].y;
-
-              spacing = 0.2 * radius;
-
-              distance = point_dist (&a, &b);
-
-              leftover = need_to_travel - traveled_length;
-              offset = spacing - leftover;
-
-              local_pos = offset;
-
-              if (distance > 0)
-                for (;
-                     local_pos <= distance;
-                     local_pos += spacing)
-                  {
-                    Point spot;
-                    gfloat ratio = local_pos / distance;
-                    gfloat radius = linewidth/2;
-
-                    lerp (&spot, &a, &b, ratio);
-
-                    gegl_path_stamp (buffer, clip_rect,
-                      spot.x, spot.y, radius, hardness, color, opacity);
-
-                    traveled_length += spacing;
-                  }
-
-              need_to_travel += distance;
-
-              x = b.x;
-              y = b.y;
-            }
-
-            break;
-          case 'u':
-            g_error ("stroking uninitialized path\n");
-            break;
-          case 's':
-            break;
-          default:
-            g_error ("can't stroke for instruction: %i\n", iter->d.type);
-            break;
-        }
-      iter=iter->next;
-    }
-
-  if (gegl_buffer_is_shared (buffer))
-    gegl_buffer_unlock (buffer);
-}
-
 gint gegl_path_type_get_n_items (gchar type)
 {
   InstructionInfo *info = lookup_instruction_info (type);
diff --git a/operations/external/Makefile.am b/operations/external/Makefile.am
index 81d8956..cf2d80b 100644
--- a/operations/external/Makefile.am
+++ b/operations/external/Makefile.am
@@ -12,10 +12,7 @@ text_la_CFLAGS = $(AM_CFLAGS) $(PANGOCAIRO_CFLAGS)
 endif
 
 if HAVE_CAIRO
-ops += path.la vector-fill.la vector-stroke.la
-path_la_SOURCES = path.c
-path_la_LIBADD = $(op_libs) $(CAIRO_LIBS)
-path_la_CFLAGS = $(AM_CFLAGS) $(CAIRO_CFLAGS)
+ops += vector-fill.la vector-stroke.la
 vector_fill_la_SOURCES = vector-fill.c
 vector_fill_la_LIBADD = $(op_libs) $(CAIRO_LIBS)
 vector_fill_la_CFLAGS = $(AM_CFLAGS) $(CAIRO_CFLAGS)
diff --git a/operations/workshop/brush-stroke.c b/operations/workshop/brush-stroke.c
new file mode 100644
index 0000000..c62e88a
--- /dev/null
+++ b/operations/workshop/brush-stroke.c
@@ -0,0 +1,382 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2006 �yvind Kolås <pippin gimp org>
+ */
+
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+
+gegl_chant_path   (d,        _("Vector"),
+                             _("A GeglVector representing the path of the stroke"))
+gegl_chant_string (transform,_("Transform"), "",
+                             _("svg style description of transform."))
+
+/* Brush shape parameters - FIXME : those should not be in the stroke operation
+ * stroking is about where to put dabs of paint, not modifying the brush
+ * use a brush dab op instead
+ */
+gegl_chant_double (scale,    _("Scale Factor"),  0.0, 10.0, 2.0,
+                             _("Brush Scale Factor"))
+gegl_chant_double (hardness, _("Hardness"),   0.0, 1.0, 0.6,
+                             _("Brush Hardness, 0.0 for soft 1.0 for hard."))
+gegl_chant_double (angle,    _("Angle"),   0.0, 360.0, 0.0,
+                             _("Brush Angle."))
+gegl_chant_double (aspect,   _("Aspect Ratio"),   0.1, 10.0, 1.0,
+                             _("Brush Aspect, 0.1 for pancake 10.0 for spike."))
+gegl_chant_double (force,    _("Force"),   0.0, 1.0, 0.6,
+                             _("Brush Force."))
+
+/* Stroke shape parameters */
+gegl_chant_double (spacing,  _("Spacing"),   0.01, 200, 0.6,
+                             _("Stroke Spacing."))
+gegl_chant_double (jitter,   _("Jitter"),   0.0, 1.0, 0.6,
+                             _("Stroke Jitter"))
+
+gegl_chant_color  (color,    _("Color"),      "rgba(0.0,0.0,0.0,0.0)",
+                             _("Color of paint to use for stroking."))
+gegl_chant_double (opacity,  _("Opacity"),  -2.0, 2.0, 1.0,
+                             _("Stroke Opacity."))
+
+#else
+
+#define GEGL_CHANT_TYPE_FILTER
+#define GEGL_CHANT_C_FILE "brush-stroke.c"
+
+#include "gegl-plugin.h"
+#include "gegl-buffer-private.h"
+
+/* the path api isn't public yet */
+#include "property-types/gegl-path.h"
+static void path_changed (GeglPath *path,
+                          const GeglRectangle *roi,
+                          gpointer userdata);
+
+#include "gegl-chant.h"
+#include <stdio.h>
+
+
+typedef struct StampStatic {
+  gboolean  valid;
+  Babl     *format;
+  gfloat   *buf;
+  gdouble   radius;
+}StampStatic;
+
+static void gegl_path_stamp (GeglBuffer *buffer,
+                             const GeglRectangle *clip_rect,
+                             gdouble     x,
+                             gdouble     y,
+                             gdouble     radius,
+                             gdouble     hardness,
+                             GeglColor  *color,
+                             gdouble     opacity)
+{
+  gfloat col[4];
+  static StampStatic s = {FALSE,}; /* XXX: 
+                                      we will ultimately leak the last valid
+                                      cached brush. */
+
+  GeglRectangle temp;
+  GeglRectangle roi;
+
+  roi.x = floor(x-radius);
+  roi.y = floor(y-radius);
+  roi.width = ceil (x+radius) - floor (x-radius);
+  roi.height = ceil (y+radius) - floor (y-radius);
+
+  gegl_color_get_rgba4f (color, col);
+
+  /* bail out if we wouldn't leave a mark on the buffer */
+  if (!gegl_rectangle_intersect (&temp, &roi, clip_rect))
+    {
+      return;
+    }
+
+  if (s.format == NULL)
+    s.format = babl_format ("RaGaBaA float");
+
+  if (s.buf == NULL ||
+      s.radius != radius)
+    {
+      if (s.buf != NULL)
+        g_free (s.buf);
+      /* allocate a little bit more, just in case due to rounding errors and
+       * such */
+      s.buf = g_malloc (4*4* (roi.width + 2 ) * (roi.height + 2));
+      s.radius = radius;
+      s.valid = TRUE;  
+    }
+  g_assert (s.buf);
+
+  gegl_buffer_get_unlocked (buffer, 1.0, &roi, s.format, s.buf, 0);
+
+  {
+    gint u, v;
+    gint i=0;
+
+    gfloat radius_squared = radius * radius;
+    gfloat inner_radius_squared = (radius * hardness)*(radius * hardness);
+    gfloat soft_range = radius_squared - inner_radius_squared;
+
+    for (v= roi.y; v < roi.y + roi.height ; v++)
+    {
+      gfloat vy2 = (v-y)*(v-y);
+      for (u= roi.x; u < roi.x + roi.width; u++)
+        {
+          gfloat o = (u-x) * (u-x) + vy2;
+
+          if (o < inner_radius_squared)
+             o = col[3];
+          else if (o < radius_squared)
+            {
+              o = (1.0 - (o-inner_radius_squared) / (soft_range)) * col[3];
+            }
+          else
+            {
+              o=0.0;
+            }
+         if (o!=0.0)
+           {
+             gint c;
+             o = o*opacity;
+             for (c=0;c<4;c++)
+               s.buf[i*4+c] = (s.buf[i*4+c] * (1.0-o) + col[c] * o);
+           }
+         i++;
+        }
+    }
+  }
+  gegl_buffer_set_unlocked (buffer, &roi, s.format, s.buf, 0);
+}
+
+static void path_changed (GeglPath *path,
+                          const GeglRectangle *roi,
+                          gpointer userdata)
+{
+  GeglRectangle rect = *roi;
+  GeglChantO    *o   = GEGL_CHANT_PROPERTIES (userdata);
+  gfloat stroke_width = o->scale*5.0*2.0;
+  /* invalidate the incoming rectangle */
+  
+  rect.x -= stroke_width/2.;
+  rect.y -= stroke_width/2;
+  rect.width += stroke_width;
+  rect.height += stroke_width;
+
+  gegl_operation_invalidate (userdata, &rect, FALSE);
+};
+
+static void
+prepare (GeglOperation *operation)
+{
+  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+  gegl_operation_set_format (operation, "output", babl_format ("RaGaBaA float"));
+  gegl_operation_set_format (operation, "input", babl_format ("RaGaBaA float"));
+  /*
+  gegl_operation_set_format (operation, "aux", babl_format ("Y float"));
+  */
+  if (o->transform && o->transform[0] != '\0')
+    {
+      GeglMatrix3 matrix;
+      gegl_matrix3_parse_string (matrix, o->transform);
+      gegl_path_set_matrix (o->d, matrix);
+    }
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+  GeglChantO    *o       = GEGL_CHANT_PROPERTIES (operation);
+  GeglRectangle  defined = { 0, 0, 512, 512 };
+  GeglRectangle *in_rect;
+  gdouble        x0, x1, y0, y1;
+  gfloat stroke_width = o->scale*5.0;
+
+  in_rect =  gegl_operation_source_get_bounding_box (operation, "input");
+
+  gegl_path_get_bounds (o->d, &x0, &x1, &y0, &y1);
+  defined.x      = x0 - stroke_width/2;
+  defined.y      = y0 - stroke_width/2;
+  defined.width  = x1 - x0 + stroke_width;
+  defined.height = y1 - y0 + stroke_width;
+
+  if (in_rect)
+    {
+      gegl_rectangle_bounding_box (&defined, &defined, in_rect);
+    }
+
+  return defined;
+}
+
+#if 0
+static gboolean gegl_path_is_closed (GeglPath *path)
+{
+  const GeglPathItem *knot;
+
+  if (!path)
+    return FALSE;
+  knot = gegl_path_get_node (path, -1);
+  if (!knot)
+    return FALSE;
+  if (knot->type == 'z')
+    {
+      return TRUE;
+    }
+  return FALSE;
+}
+#endif
+
+
+#if 0
+static GeglRectangle
+get_cached_region (GeglOperation *operation)
+{
+  return get_bounding_box (operation);
+}
+#endif
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *output,
+         const GeglRectangle *result)
+{
+  GeglChantO *o  = GEGL_CHANT_PROPERTIES (operation);
+  GeglPath *path = o->d;
+
+  gfloat spacing, length, radius, hardness, opacity;
+  gdouble pos = 0;
+  gboolean incremental = TRUE;
+
+  if (!o->d)
+    return TRUE;
+
+  if (input)
+    {
+      gegl_buffer_copy (input, result, output, result);
+    }
+  else
+    {
+      gegl_buffer_clear (output, result);
+    }
+
+    radius = 5 * o->scale;
+    hardness = o->hardness;
+
+    length  = gegl_path_get_length(path);
+
+    
+    if (gegl_buffer_is_shared (output))
+      while (!gegl_buffer_try_lock (output));
+
+    do
+    {
+      gdouble x, y;
+
+      /* Set the brush tip : set brush worker's pos */
+      if (! gegl_path_calc (path,pos,&x,&y)) break;
+      /* Compute coordinates : jitter ? */
+
+      if (incremental)
+      {
+          /* Blend into output : set blend worker pos and process */
+          gegl_path_stamp (output, result,
+                x, y, radius, hardness, o->color, o->opacity);
+      }
+      else
+      {
+          /* Blend into a mask */
+      }
+
+      /* Calculate next position */
+      spacing = o->spacing * radius;
+      pos = pos + spacing;
+    }
+    while (pos < length);
+
+    if (! incremental)
+    {
+      /* Blend the mask into output */
+    }
+
+    if (gegl_buffer_is_shared (output))
+      gegl_buffer_unlock (output);
+
+  return  TRUE;
+}
+
+static GeglNode *detect (GeglOperation *operation,
+                         gint           x,
+                         gint           y)
+{
+#if 0
+  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+  cairo_t *cr;
+  cairo_surface_t *surface;
+  gchar *data = "     ";
+  gboolean result = FALSE;
+
+  surface = cairo_image_surface_create_for_data ((guchar*)data,
+                                                 CAIRO_FORMAT_ARGB32,
+                                                 1,1,4);
+  cr = cairo_create (surface);
+  gegl_path_cairo_play (o->d, cr);
+  cairo_set_line_width (cr, o->stroke_width);
+
+
+  if (o->stroke_width > 0.1 && o->stroke_opacity > 0.0001)
+    result = cairo_in_stroke (cr, x, y);
+
+
+  cairo_destroy (cr);
+
+  if (result)
+    return operation->node;
+
+#endif
+  return NULL;
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+  GeglOperationClass       *operation_class;
+  GeglOperationFilterClass *filter_class;
+
+  operation_class = GEGL_OPERATION_CLASS (klass);
+  filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
+
+  filter_class->process = process;
+  operation_class->get_bounding_box = get_bounding_box;
+  operation_class->prepare = prepare;
+  operation_class->detect = detect;
+  /*operation_class->no_cache = TRUE;*/
+
+  operation_class->name        = "gegl:brush-stroke";
+  operation_class->categories  = "render";
+  operation_class->description = _("Renders a brush stroke");
+#if 0
+  operation_class->get_cached_region = (void*)get_cached_region;
+#endif
+}
+
+
+#endif



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