|
Packit |
bc1512 |
/* This file is an image processing operation for GEGL
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* GEGL is free software; you can redistribute it and/or
|
|
Packit |
bc1512 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
bc1512 |
* License as published by the Free Software Foundation; either
|
|
Packit |
bc1512 |
* version 3 of the License, or (at your option) any later version.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit |
bc1512 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
bc1512 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
bc1512 |
* Lesser General Public License for more details.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
bc1512 |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* Copyright 2011 Michael Muré <batolettre@gmail.com>
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include "config.h"
|
|
Packit |
bc1512 |
#include <glib/gi18n-lib.h>
|
|
Packit |
bc1512 |
#include <math.h>
|
|
Packit |
bc1512 |
#include <stdio.h> /* for test only */
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#ifdef GEGL_CHANT_PROPERTIES
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_chant_double (strength, _("Strength"), 0.0, 100.0, 50,
|
|
Packit |
bc1512 |
_("Effect Strength"))
|
|
Packit |
bc1512 |
gegl_chant_double (size, _("Size"), 1.0, 10000.0, 40.0,
|
|
Packit |
bc1512 |
_("Effect Size"))
|
|
Packit |
bc1512 |
gegl_chant_double (hardness, _("Hardness"), 0.0, 1.0, 0.5,
|
|
Packit |
bc1512 |
_("Effect Hardness"))
|
|
Packit |
bc1512 |
gegl_chant_path (stroke, _("Stroke"), _("Effect Strength"))
|
|
Packit |
bc1512 |
gegl_chant_enum (behavior, _("Behavior"), GeglWarpBehavior, GEGL_TYPE_WARP_BEHAVIOR,
|
|
Packit |
bc1512 |
GEGL_WARP_BEHAVIOR_MOVE, _("Behavior of the op"))
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#else
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#define GEGL_CHANT_TYPE_FILTER
|
|
Packit |
bc1512 |
#define GEGL_CHANT_C_FILE "warp.c"
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include "gegl-plugin.h"
|
|
Packit |
bc1512 |
#include "gegl-path.h"
|
|
Packit |
bc1512 |
static void path_changed (GeglPath *path,
|
|
Packit |
bc1512 |
const GeglRectangle *roi,
|
|
Packit |
bc1512 |
gpointer userdata);
|
|
Packit |
bc1512 |
#include "gegl-chant.h"
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
typedef struct {
|
|
Packit |
bc1512 |
gdouble *lookup;
|
|
Packit |
bc1512 |
GeglBuffer *buffer;
|
|
Packit |
bc1512 |
gdouble last_x;
|
|
Packit |
bc1512 |
gdouble last_y;
|
|
Packit |
bc1512 |
gboolean last_point_set;
|
|
Packit |
bc1512 |
} WarpPrivate;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
path_changed (GeglPath *path,
|
|
Packit |
bc1512 |
const GeglRectangle *roi,
|
|
Packit |
bc1512 |
gpointer userdata)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglRectangle rect = *roi;
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (userdata);
|
|
Packit |
bc1512 |
/* invalidate the incoming rectangle */
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
rect.x -= o->size/2;
|
|
Packit |
bc1512 |
rect.y -= o->size/2;
|
|
Packit |
bc1512 |
rect.width += o->size;
|
|
Packit |
bc1512 |
rect.height += o->size;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_operation_invalidate (userdata, &rect, FALSE);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
prepare (GeglOperation *operation)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit |
bc1512 |
WarpPrivate *priv;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
const Babl *format = babl_format_n (babl_type ("float"), 2);
|
|
Packit |
bc1512 |
gegl_operation_set_format (operation, "input", format);
|
|
Packit |
bc1512 |
gegl_operation_set_format (operation, "output", format);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (!o->chant_data)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
o->chant_data = g_slice_new (WarpPrivate);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
priv = (WarpPrivate*) o->chant_data;
|
|
Packit |
bc1512 |
priv->last_point_set = FALSE;
|
|
Packit |
bc1512 |
priv->lookup = NULL;
|
|
Packit |
bc1512 |
priv->buffer = NULL;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
finalize (GObject *object)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (object);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (o->chant_data)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
g_slice_free (WarpPrivate, o->chant_data);
|
|
Packit |
bc1512 |
o->chant_data = NULL;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
G_OBJECT_CLASS (gegl_chant_parent_class)->finalize (object);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static gdouble
|
|
Packit |
bc1512 |
gauss (gdouble f)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/* This is not a real gauss function. */
|
|
Packit |
bc1512 |
/* Approximation is valid if -1 < f < 1 */
|
|
Packit |
bc1512 |
if (f < -0.5)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
f = -1.0 - f;
|
|
Packit |
bc1512 |
return (2.0 * f*f);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (f < 0.5)
|
|
Packit |
bc1512 |
return (1.0 - 2.0 * f*f);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
f = 1.0 - f;
|
|
Packit |
bc1512 |
return (2.0 * f*f);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* set up lookup table */
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
calc_lut (GeglChantO *o)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
WarpPrivate *priv = (WarpPrivate*) o->chant_data;
|
|
Packit |
bc1512 |
gint length;
|
|
Packit |
bc1512 |
gint x;
|
|
Packit |
bc1512 |
gdouble exponent;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
length = ceil (0.5 * o->size + 1.0);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
priv->lookup = g_malloc (length * sizeof (gdouble));
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if ((1.0 - o->hardness) < 0.0000004)
|
|
Packit |
bc1512 |
exponent = 1000000.0;
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
exponent = 0.4 / (1.0 - o->hardness);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
for (x = 0; x < length; x++)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
priv->lookup[x] = gauss (pow (2.0 * x / o->size, exponent));
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static gdouble
|
|
Packit |
bc1512 |
get_stamp_force (GeglChantO *o,
|
|
Packit |
bc1512 |
gdouble x,
|
|
Packit |
bc1512 |
gdouble y)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
WarpPrivate *priv = (WarpPrivate*) o->chant_data;
|
|
Packit |
bc1512 |
gfloat radius;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (!priv->lookup)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
calc_lut (o);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
radius = sqrt(x*x+y*y);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (radius < 0.5 * o->size + 1)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/* linear interpolation */
|
|
Packit |
bc1512 |
gdouble a, ratio;
|
|
Packit |
bc1512 |
gdouble before, after;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
a = floor (radius);
|
|
Packit |
bc1512 |
ratio = (radius - a);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
before = priv->lookup[(gint) a];
|
|
Packit |
bc1512 |
after = priv->lookup[(gint) a + 1];
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return ratio * before + (1.0 - ratio) * after;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return 0.0;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
stamp (GeglChantO *o,
|
|
Packit |
bc1512 |
const GeglRectangle *result,
|
|
Packit |
bc1512 |
gdouble x,
|
|
Packit |
bc1512 |
gdouble y)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
WarpPrivate *priv = (WarpPrivate*) o->chant_data;
|
|
Packit |
bc1512 |
GeglBufferIterator *it;
|
|
Packit |
bc1512 |
const Babl *format;
|
|
Packit |
bc1512 |
gdouble influence;
|
|
Packit |
bc1512 |
gdouble x_mean = 0.0;
|
|
Packit |
bc1512 |
gdouble y_mean = 0.0;
|
|
Packit |
bc1512 |
gint x_iter, y_iter;
|
|
Packit |
bc1512 |
GeglRectangle area = {x - o->size / 2.0,
|
|
Packit |
bc1512 |
y - o->size / 2.0,
|
|
Packit |
bc1512 |
o->size,
|
|
Packit |
bc1512 |
o->size};
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* first point of the stroke */
|
|
Packit |
bc1512 |
if (!priv->last_point_set)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
priv->last_x = x;
|
|
Packit |
bc1512 |
priv->last_y = y;
|
|
Packit |
bc1512 |
priv->last_point_set = TRUE;
|
|
Packit |
bc1512 |
return;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* don't stamp if outside the roi treated */
|
|
Packit |
bc1512 |
if (!gegl_rectangle_intersect (NULL, result, &area))
|
|
Packit |
bc1512 |
return;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
format = babl_format_n (babl_type ("float"), 2);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* If needed, compute the mean deformation */
|
|
Packit |
bc1512 |
if (o->behavior == GEGL_WARP_BEHAVIOR_SMOOTH)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gint pixel_count = 0;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
it = gegl_buffer_iterator_new (priv->buffer, &area, 0, format, GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
while (gegl_buffer_iterator_next (it))
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gint n_pixels = it->length;
|
|
Packit |
bc1512 |
gfloat *coords = it->data[0];
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
while (n_pixels--)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
x_mean += coords[0];
|
|
Packit |
bc1512 |
y_mean += coords[1];
|
|
Packit |
bc1512 |
coords += 2;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
pixel_count += it->roi->width * it->roi->height;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
x_mean /= pixel_count;
|
|
Packit |
bc1512 |
y_mean /= pixel_count;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
it = gegl_buffer_iterator_new (priv->buffer, &area, 0, format, GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
while (gegl_buffer_iterator_next (it))
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/* iterate inside the stamp roi */
|
|
Packit |
bc1512 |
gint n_pixels = it->length;
|
|
Packit |
bc1512 |
gfloat *coords = it->data[0];
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
x_iter = it->roi->x; /* initial x */
|
|
Packit |
bc1512 |
y_iter = it->roi->y; /* and y coordinates */
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
while (n_pixels--)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
influence = 0.01 * o->strength * get_stamp_force (o,
|
|
Packit |
bc1512 |
x_iter - x,
|
|
Packit |
bc1512 |
y_iter - y);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
switch (o->behavior)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
case GEGL_WARP_BEHAVIOR_MOVE:
|
|
Packit |
bc1512 |
coords[0] += influence * (priv->last_x - x);
|
|
Packit |
bc1512 |
coords[1] += influence * (priv->last_y - y);
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
case GEGL_WARP_BEHAVIOR_GROW:
|
|
Packit |
bc1512 |
coords[0] -= 2.0 * influence * (x_iter - x) / o->size;
|
|
Packit |
bc1512 |
coords[1] -= 2.0 * influence * (y_iter - y) / o->size;
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
case GEGL_WARP_BEHAVIOR_SHRINK:
|
|
Packit |
bc1512 |
coords[0] += 2.0 * influence * (x_iter - x) / o->size;
|
|
Packit |
bc1512 |
coords[1] += 2.0 * influence * (y_iter - y) / o->size;
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
case GEGL_WARP_BEHAVIOR_SWIRL_CW:
|
|
Packit |
bc1512 |
coords[0] += 3.0 * influence * (y_iter - y) / o->size;
|
|
Packit |
bc1512 |
coords[1] -= 5.0 * influence * (x_iter - x) / o->size;
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
case GEGL_WARP_BEHAVIOR_SWIRL_CCW:
|
|
Packit |
bc1512 |
coords[0] -= 3.0 * influence * (y_iter - y) / o->size;
|
|
Packit |
bc1512 |
coords[1] += 5.0 * influence * (x_iter - x) / o->size;
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
case GEGL_WARP_BEHAVIOR_ERASE:
|
|
Packit |
bc1512 |
coords[0] *= 1.0 - MIN (influence, 1.0);
|
|
Packit |
bc1512 |
coords[1] *= 1.0 - MIN (influence, 1.0);
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
case GEGL_WARP_BEHAVIOR_SMOOTH:
|
|
Packit |
bc1512 |
coords[0] -= influence * (coords[0] - x_mean);
|
|
Packit |
bc1512 |
coords[1] -= influence * (coords[1] - y_mean);
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
coords += 2;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* update x and y coordinates */
|
|
Packit |
bc1512 |
x_iter++;
|
|
Packit |
bc1512 |
if (x_iter >= (it->roi->x + it->roi->width))
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
x_iter = it->roi->x;
|
|
Packit |
bc1512 |
y_iter++;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* Memorize the stamp location for movement dependant behavior like move */
|
|
Packit |
bc1512 |
priv->last_x = x;
|
|
Packit |
bc1512 |
priv->last_y = y;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static gboolean
|
|
Packit |
bc1512 |
process (GeglOperation *operation,
|
|
Packit |
bc1512 |
GeglBuffer *input,
|
|
Packit |
bc1512 |
GeglBuffer *output,
|
|
Packit |
bc1512 |
const GeglRectangle *result,
|
|
Packit |
bc1512 |
gint level)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit |
bc1512 |
WarpPrivate *priv = (WarpPrivate*) o->chant_data;
|
|
Packit |
bc1512 |
gdouble dist;
|
|
Packit |
bc1512 |
gdouble stamps;
|
|
Packit |
bc1512 |
gdouble spacing = MAX (o->size * 0.01, 0.5); /*1% spacing for starters*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
GeglPathPoint prev, next, lerp;
|
|
Packit |
bc1512 |
gulong i;
|
|
Packit |
bc1512 |
GeglPathList *event;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
printf("Process %p\n", operation);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
priv->buffer = gegl_buffer_dup (input);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
event = gegl_path_get_path (o->stroke);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
prev = *(event->d.point);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
while (event->next)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
event = event->next;
|
|
Packit |
bc1512 |
next = *(event->d.point);
|
|
Packit |
bc1512 |
dist = gegl_path_point_dist (&next, &prev;;
|
|
Packit |
bc1512 |
stamps = dist / spacing;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (stamps < 1)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
stamp (o, result, next.x, next.y);
|
|
Packit |
bc1512 |
prev = next;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
for (i = 0; i < stamps; i++)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gegl_path_point_lerp (&lerp, &prev, &next, (i * spacing) / dist);
|
|
Packit |
bc1512 |
stamp (o, result, lerp.x, lerp.y);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
prev = lerp;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* Affect the output buffer */
|
|
Packit |
bc1512 |
gegl_buffer_copy (priv->buffer, result, output, result);
|
|
Packit |
bc1512 |
gegl_buffer_set_extent (output, gegl_buffer_get_extent (input));
|
|
Packit |
bc1512 |
g_object_unref (priv->buffer);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* prepare for the recomputing of the op */
|
|
Packit |
bc1512 |
priv->last_point_set = FALSE;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return TRUE;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
gegl_chant_class_init (GeglChantClass *klass)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
Packit |
bc1512 |
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
|
Packit |
bc1512 |
GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
object_class->finalize = finalize;
|
|
Packit |
bc1512 |
operation_class->prepare = prepare;
|
|
Packit |
bc1512 |
filter_class->process = process;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_operation_class_set_keys (operation_class,
|
|
Packit |
bc1512 |
"name" , "gegl:warp",
|
|
Packit |
bc1512 |
"categories" , "transform",
|
|
Packit |
bc1512 |
"description" , _("Compute a relative displacement mapping from a stroke"),
|
|
Packit |
bc1512 |
NULL);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
#endif
|