[gegl] operations: fix gegl:wind
- From: Thomas Manni <tmanni src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] operations: fix gegl:wind
- Date: Sun, 7 Jun 2015 16:17:58 +0000 (UTC)
commit d5186790cfe7cc8248d45da0eeb9c01dad0fbfed
Author: Thomas Manni <thomas manni free fr>
Date: Sun Jun 7 18:49:51 2015 +0200
operations: fix gegl:wind
- add original gimp plug-in parameters
- add new "top" and "bottom" directions
- use proper multi-threading strategy
operations/common/wind.c | 825 +++++++++++++++++++++++++++++++---------------
1 files changed, 560 insertions(+), 265 deletions(-)
---
diff --git a/operations/common/wind.c b/operations/common/wind.c
index 049c0fe..b027fbe 100644
--- a/operations/common/wind.c
+++ b/operations/common/wind.c
@@ -1,21 +1,22 @@
/* 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.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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,
+ * This program 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.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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/>.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright Nigel Wetten
* Copyright 2000 Tim Copperfield <timecop japan co jp>
* Copyright 2011 Hans Lo <hansshulo gmail com>
+ *
*/
#include "config.h"
@@ -23,163 +24,509 @@
#ifdef GEGL_PROPERTIES
-property_double (threshold, _("Threshold"), 10.0)
- description(_("Higher values restrict the effect to fewer areas of the image"))
- value_range (0, 100)
-
-property_int (strength, _("Strength"), 40)
- description(_("Higher values increase the magnitude of the effect"))
- value_range(1,1000)
-
-property_seed (seed, _("Random seed"), rand)
+enum_start (gegl_wind_style)
+ enum_value (GEGL_WIND_STYLE_WIND, "wind", N_("Wind"))
+ enum_value (GEGL_WIND_STYLE_BLAST, "blast", N_("Blast"))
+enum_end (GeglWindStyle)
+
+enum_start (gegl_wind_direction)
+ enum_value (GEGL_WIND_DIRECTION_LEFT, "left", N_("Left"))
+ enum_value (GEGL_WIND_DIRECTION_RIGHT, "right", N_("Right"))
+ enum_value (GEGL_WIND_DIRECTION_TOP, "top", N_("Top"))
+ enum_value (GEGL_WIND_DIRECTION_BOTTOM, "bottom", N_("Bottom"))
+enum_end (GeglWindDirection)
+
+enum_start (gegl_wind_edge)
+ enum_value (GEGL_WIND_EDGE_LEADING, "leading", N_("Leading"))
+ enum_value (GEGL_WIND_EDGE_TRAILING, "trailing", N_("Trailing"))
+ enum_value (GEGL_WIND_EDGE_BOTH, "both", N_("Both"))
+enum_end (GeglWindEdge)
+
+property_enum (style, _("Style"),
+ GeglWindStyle, gegl_wind_style,
+ GEGL_WIND_STYLE_WIND)
+ description (_("Style of effect"))
+
+property_enum (direction, _("Direction"),
+ GeglWindDirection, gegl_wind_direction,
+ GEGL_WIND_DIRECTION_LEFT)
+ description (_("Direction of the effect"))
+
+property_enum (edge, _("Edge Affected"),
+ GeglWindEdge, gegl_wind_edge,
+ GEGL_WIND_EDGE_LEADING)
+ description (_("Edge behavior"))
+
+property_int (threshold, _("Threshold"), 10)
+ description (_("Higher values restrict the effect to fewer areas of the image"))
+ value_range (0, 50)
+
+property_int (strength, _("Strength"), 10)
+ description (_("Higher values increase the magnitude of the effect"))
+ value_range (1, 100)
#else
-#define GEGL_OP_AREA_FILTER
+#define GEGL_OP_FILTER
#define GEGL_OP_C_SOURCE wind.c
#include "gegl-op.h"
-#include <stdlib.h>
+#include "gegl-config.h"
+#include <math.h>
-typedef struct
+#define COMPARE_WIDTH 3
+
+typedef struct ThreadData
{
- gint x;
- gint y;
-} pair;
-
-static guint tuple_hash (gconstpointer v);
-static gboolean tuple_equal (gconstpointer v1,
- gconstpointer v2);
-static guint
-tuple_hash (gconstpointer v)
+ GeglOperationFilterClass *klass;
+ GeglOperation *operation;
+ GeglBuffer *input;
+ GeglBuffer *output;
+ gint *pending;
+ gint level;
+ gboolean success;
+ GeglRectangle roi;
+} ThreadData;
+
+static void
+thread_process (gpointer thread_data, gpointer unused)
{
- const pair *data = v;
- return (g_int_hash (&data->x) ^ g_int_hash (&data->y));
+ ThreadData *data = thread_data;
+ if (!data->klass->process (data->operation,
+ data->input, data->output, &data->roi, data->level))
+ data->success = FALSE;
+ g_atomic_int_add (data->pending, -1);
}
-static gboolean
-tuple_equal (gconstpointer v1,
- gconstpointer v2)
+static GThreadPool *
+thread_pool (void)
{
- const pair *data1 = v1;
- const pair *data2 = v2;
- return (g_int_equal (&data1->x, &data2->x) &&
- g_int_equal (&data1->y, &data2->y));
+ static GThreadPool *pool = NULL;
+ if (!pool)
+ {
+ pool = g_thread_pool_new (thread_process, NULL, gegl_config_threads (),
+ FALSE, NULL);
+ }
+ return pool;
}
static void
-get_derivative (gfloat *pixel1,
- gfloat *pixel2,
- gfloat *derivative)
+get_derivative (gfloat *pixel1,
+ gfloat *pixel2,
+ gboolean has_alpha,
+ GeglWindEdge edge,
+ gfloat *derivative)
{
gint i;
- for (i = 0; i < 4; i++)
- derivative[i] = pixel1[i] - pixel2[i];
+
+ for (i = 0; i < 3; i++)
+ derivative[i] = pixel2[i] - pixel1[i];
+
+ if (has_alpha)
+ derivative[3] = pixel2[3] - pixel1[3];
+ else
+ derivative[3] = 0.0;
+
+ if (edge == GEGL_WIND_EDGE_BOTH)
+ {
+ for (i = 0; i < 4; i++)
+ derivative[i] = fabs (derivative[i]);
+ }
+ else if (edge == GEGL_WIND_EDGE_LEADING)
+ {
+ for (i = 0; i < 4; i++)
+ derivative[i] = - derivative[i];
+ }
}
static gboolean
-threshold_exceeded (gfloat *pixel1,
- gfloat *pixel2,
- gfloat threshold)
+threshold_exceeded (gfloat *pixel1,
+ gfloat *pixel2,
+ gboolean has_alpha,
+ GeglWindEdge edge,
+ gint threshold)
{
gfloat derivative[4];
gint i;
- gfloat sum;
+ gfloat sum = 0.0;
- get_derivative (pixel1, pixel2, derivative);
+ get_derivative (pixel1, pixel2, has_alpha, edge, derivative);
- sum = 0.0;
for (i = 0; i < 4; i++)
sum += derivative[i];
- return ((sum / 4.0) > (threshold/100.0));
+
+ return ((sum / 4.0f) > (threshold / 200.0));
}
static void
-calculate_bleed (GeglOperation *operation,
- GeglBuffer *input)
+reverse_buffer (gfloat *buffer,
+ gint length,
+ gint bytes)
{
- GeglProperties *o = GEGL_PROPERTIES (operation);
- GeglRectangle rectA, rectB;
- GeglBufferIterator *iter;
- gfloat max_length = (gfloat) o->strength;
- gfloat threshold = o->threshold;
- GHashTable *bleed_table = o->user_data;
-
- rectA = *gegl_operation_source_get_bounding_box (operation, "input");
- rectA.width -= 3;
- rectB = rectA;
- rectB.x += 3;
-
- if (rectA.width <= 0)
- return;
-
- iter = gegl_buffer_iterator_new (input,
- &rectA,
- 0,
- babl_format ("RGBA float"),
- GEGL_ACCESS_READ,
- GEGL_ABYSS_NONE);
-
- gegl_buffer_iterator_add (iter,
- input,
- &rectB,
- 0,
- babl_format ("RGBA float"),
- GEGL_ACCESS_READ,
- GEGL_ABYSS_NONE);
-
- while (gegl_buffer_iterator_next (iter))
+ gint b, i, si;
+ gfloat temp;
+ gint midpoint;
+
+ midpoint = length / 2;
+ for (i = 0; i < midpoint; i += bytes)
+ {
+ si = length - bytes - i;
+
+ for (b = 0; b < bytes; b++)
+ {
+ temp = buffer[i + b];
+ buffer[i + b] = buffer[si + b];
+ buffer[si + b] = temp;
+ }
+ }
+}
+
+static void
+render_wind_row (gfloat *buffer,
+ gint n_components,
+ gint lpi,
+ GeglProperties *o,
+ GRand *gr)
+{
+ gfloat *blend_color;
+ gfloat *target_color;
+ gfloat *blend_amt;
+ gboolean has_alpha;
+ gint i, j, b;
+ gint bleed_length;
+ gint n;
+ gint sbi; /* starting bleed index */
+ gint lbi; /* last bleed index */
+ gdouble denominator;
+ gint comp_stride = n_components * COMPARE_WIDTH;
+
+ target_color = g_new0 (gfloat, n_components);
+ blend_color = g_new0 (gfloat, n_components);
+ blend_amt = g_new0 (gfloat, n_components);
+
+ has_alpha = n_components > 3 ? TRUE : FALSE;
+
+ for (j = 0; j < lpi; j += n_components)
{
- gint ix, iy;
- gfloat *pixelsA = (gfloat *)iter->data[0];
- gfloat *pixelsB = (gfloat *)iter->data[1];
-
- for (ix = 0; ix < iter->roi[0].width; ix++)
- for (iy = 0; iy < iter->roi[0].height; iy++)
- {
- gint idx = iy * iter->roi[0].width + ix * 4;
- if (threshold_exceeded (&pixelsA[idx], &pixelsB[idx], threshold))
- {
- gint x = ix + iter->roi[0].x;
- gint y = iy + iter->roi[0].y;
- pair *k = g_new (pair, 1);
- gint *v = g_new (gint, 1);
- gint bleed_length = 1 + gegl_random_int_range (o->rand, x, y, 0, 0, 0, max_length);
-
- k->x = x;
- k->y = y;
-
- *v = bleed_length;
- g_hash_table_insert (bleed_table, k, v);
- }
- }
+ gint pxi = j;
+
+ if (threshold_exceeded (buffer + pxi,
+ buffer + pxi + comp_stride,
+ has_alpha,
+ o->edge,
+ o->threshold))
+ {
+ gdouble bleed_length_max;
+ sbi = pxi + comp_stride;
+
+ for (b = 0; b < n_components; b++)
+ {
+ blend_color[b] = buffer[pxi + b];
+ target_color[b] = buffer[sbi + b];
+ }
+
+ if (g_rand_int_range (gr, 0, 3))
+ {
+ bleed_length_max = o->strength;
+ }
+ else
+ {
+ bleed_length_max = 4 * o->strength;
+ }
+
+ bleed_length = 1 + (gint) (bleed_length_max * g_rand_double (gr));
+
+ lbi = sbi + bleed_length * n_components;
+ if (lbi > lpi)
+ {
+ lbi = lpi;
+ }
+
+ for (b = 0; b < n_components; b++)
+ blend_amt[b] = target_color[b] - blend_color[b];
+
+ denominator = 2.0 / (bleed_length * bleed_length + bleed_length);
+ n = bleed_length;
+
+ for (i = sbi; i < lbi; i += n_components)
+ {
+ if (!threshold_exceeded (buffer + pxi,
+ buffer + i,
+ has_alpha,
+ o->edge,
+ o->threshold)
+ && g_rand_boolean (gr))
+ {
+ break;
+ }
+
+ for (b = 0; b < n_components; b++)
+ {
+ blend_color[b] += blend_amt[b] * n * denominator;
+ blend_color[b] = CLAMP (blend_color[b], 0.0, 1.0);
+ buffer[i + b] = (blend_color[b] * 2 + buffer[i + b]) / 3;
+ }
+
+ if (threshold_exceeded (buffer + i,
+ buffer + i + comp_stride,
+ has_alpha,
+ GEGL_WIND_EDGE_BOTH,
+ o->threshold))
+ {
+ for (b = 0; b < n_components; b++)
+ {
+ target_color[b] = buffer[i + comp_stride + b];
+ blend_amt[b] = target_color[b] - blend_color[b];
+ }
+
+ denominator = 2.0 / (n * n + n);
+ }
+ n--;
+ }
+ }
+ }
+
+ g_free (target_color);
+ g_free (blend_color);
+ g_free (blend_amt);
+}
+
+static gboolean
+render_blast_row (gfloat *buffer,
+ gint n_components,
+ gint lpi,
+ GeglProperties *o,
+ GRand *gr)
+{
+ gint sbi, lbi;
+ gint bleed_length;
+ gint i, j, b;
+ gint weight, random_factor;
+ gboolean skip = FALSE;
+
+ for (j = 0; j < lpi; j += n_components)
+ {
+ gfloat *pbuf = buffer + j;
+
+ if (threshold_exceeded (pbuf,
+ pbuf + n_components,
+ n_components > 3,
+ o->edge,
+ o->threshold))
+ {
+ sbi = j;
+ weight = g_rand_int_range (gr, 0, 10);
+
+ if (weight > 5)
+ {
+ random_factor = 2;
+ }
+ else if (weight > 3)
+ {
+ random_factor = 3;
+ }
+ else
+ {
+ random_factor = 4;
+ }
+
+ bleed_length = 0;
+
+ switch (g_rand_int_range (gr, 0, random_factor))
+ {
+ case 3:
+ bleed_length += o->strength;
+ case 2:
+ bleed_length += o->strength;
+ case 1:
+ bleed_length += o->strength;
+ case 0:
+ bleed_length += o->strength;
+ }
+
+ lbi = sbi + n_components * bleed_length;
+ if (lbi > lpi)
+ {
+ lbi = lpi;
+ }
+
+ for (i = sbi; i < lbi; i += n_components)
+ for (b = 0; b < n_components; b++)
+ buffer[i+b] = *(pbuf + b);
+
+ j = lbi - n_components;
+
+ if (g_rand_int_range (gr, 0, 10) > 7)
+ {
+ skip = TRUE;
+ }
+ }
}
+ return skip;
}
static void
prepare (GeglOperation *operation)
{
- GeglProperties *o;
- GeglOperationAreaFilter *op_area;
+ const Babl *in_format = gegl_operation_get_source_format (operation, "input");
+ const Babl *format = babl_format ("RGB float");
- op_area = GEGL_OPERATION_AREA_FILTER (operation);
- o = GEGL_PROPERTIES (operation);
+ if (in_format)
+ {
+ if (babl_format_has_alpha (in_format))
+ format = babl_format ("RGBA float");
+ }
- if (o->user_data)
+ gegl_operation_set_format (operation, "input", format);
+ gegl_operation_set_format (operation, "output", format);
+}
+
+static GeglRectangle
+get_cached_region (GeglOperation *operation,
+ const GeglRectangle *roi)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglRectangle *boundary;
+ GeglRectangle result;
+
+ boundary = gegl_operation_source_get_bounding_box (operation, "input");
+ result = *roi;
+
+ if (o->direction == GEGL_WIND_DIRECTION_LEFT ||
+ o->direction == GEGL_WIND_DIRECTION_RIGHT)
+ {
+ result.x = boundary->x;
+ result.width = boundary->width;
+ }
+ else
+ {
+ result.y = boundary->y;
+ result.height = boundary->height;
+ }
+
+ return result;
+}
+
+static GeglRectangle
+get_required_for_output (GeglOperation *operation,
+ const gchar *input_pad,
+ const GeglRectangle *roi)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglRectangle *boundary;
+ GeglRectangle result;
+
+ boundary = gegl_operation_source_get_bounding_box (operation, "input");
+ result = *roi;
+
+ if (o->direction == GEGL_WIND_DIRECTION_TOP)
+ {
+ result.height = boundary->height - roi->y;
+ }
+ else if (o->direction == GEGL_WIND_DIRECTION_BOTTOM)
+ {
+ result.y = boundary->y;
+ result.height = boundary->height - roi->y + roi->height;
+ }
+ else if (o->direction == GEGL_WIND_DIRECTION_RIGHT)
+ {
+ result.x = boundary->x;
+ result.width = boundary->width - roi->x + roi->width;
+ }
+ else
+ {
+ result.width = boundary->width - roi->x;
+ }
+
+ return result;
+}
+
+static gboolean
+operation_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglOperationFilterClass *klass;
+ GeglBuffer *input;
+ GeglBuffer *output;
+ gboolean success = FALSE;
+
+ klass = GEGL_OPERATION_FILTER_GET_CLASS (operation);
+
+ g_assert (klass->process);
+
+ if (strcmp (output_prop, "output"))
+ {
+ g_warning ("requested processing of %s pad on a filter", output_prop);
+ return FALSE;
+ }
+
+ input = gegl_operation_context_get_source (context, "input");
+ output = gegl_operation_context_get_target (context, "output");
+
+ if (gegl_operation_use_threading (operation, result))
+ {
+ gint threads = gegl_config_threads ();
+ GThreadPool *pool = thread_pool ();
+ ThreadData thread_data[GEGL_MAX_THREADS];
+ gint pending = threads;
+
+ if (o->direction == GEGL_WIND_DIRECTION_LEFT ||
+ o->direction == GEGL_WIND_DIRECTION_RIGHT)
+ {
+ gint bit = result->height / threads;
+ for (gint j = 0; j < threads; j++)
+ {
+ thread_data[j].roi.x = result->x;
+ thread_data[j].roi.width = result->width;
+ thread_data[j].roi.y = result->y + bit * j;
+ thread_data[j].roi.height = bit;
+ }
+ thread_data[threads-1].roi.height = result->height - (bit * (threads-1));
+ }
+ else
{
- g_hash_table_destroy (o->user_data);
- o->user_data = NULL;
+ gint bit = result->width / threads;
+ for (gint j = 0; j < threads; j++)
+ {
+ thread_data[j].roi.y = result->y;
+ thread_data[j].roi.height = result->height;
+ thread_data[j].roi.x = result->x + bit * j;
+ thread_data[j].roi.width = bit;
+ }
+ thread_data[threads-1].roi.width = result->width - (bit * (threads-1));
}
+ for (gint i = 0; i < threads; i++)
+ {
+ thread_data[i].klass = klass;
+ thread_data[i].operation = operation;
+ thread_data[i].input = input;
+ thread_data[i].output = output;
+ thread_data[i].pending = &pending;
+ thread_data[i].level = level;
+ thread_data[i].success = TRUE;
+ }
+
+ for (gint i = 1; i < threads; i++)
+ g_thread_pool_push (pool, &thread_data[i], NULL);
+ thread_process (&thread_data[0], NULL);
- op_area->left = o->strength;
- op_area->right = o->strength;
- op_area->top = o->strength;
- op_area->bottom = o->strength;
+ while (g_atomic_int_get (&pending)) {};
- gegl_operation_set_format (operation, "input",
- babl_format ("RGBA float"));
- gegl_operation_set_format (operation, "output",
- babl_format ("RGBA float"));
+ success = thread_data[0].success;
+ }
+ else
+ {
+ success = klass->process (operation, input, output, result, level);
+ }
+
+ if (input != NULL)
+ g_object_unref (input);
+
+ return success;
}
static gboolean
@@ -189,183 +536,131 @@ process (GeglOperation *operation,
const GeglRectangle *result,
gint level)
{
- GeglProperties *o = GEGL_PROPERTIES (operation);
- GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
-
- gfloat *src_buf;
- gfloat *dst_buf;
-
- gint n_pixels = result->width * result->height;
- GeglRectangle src_rect;
-
- gfloat *current_pix;
- gfloat *target_pix;
- gfloat *dst_pix;
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *format = gegl_operation_get_format (operation, "output");
+ gint n_components = babl_format_get_n_components (format);
- gint x, y;
- gint total_src_pixels;
- gint total_dst_pixels;
+ gint y, row_size;
+ gint row_start, row_end;
+ GeglRectangle row_rect;
+ gfloat *row_buf;
+ GRand *gr;
+ gboolean skip_rows;
+ gboolean need_reverse;
+ gboolean horizontal_effect;
+ gint last_pix;
- gint bleed_max;
- gint bleed_index;
- gfloat blend_coefficient;
+ gr = g_rand_new ();
- GHashTable *bleed_table;
+ horizontal_effect = (o->direction == GEGL_WIND_DIRECTION_LEFT ||
+ o->direction == GEGL_WIND_DIRECTION_RIGHT);
- static GMutex mutex = { 0, };
+ need_reverse = (o->direction == GEGL_WIND_DIRECTION_RIGHT ||
+ o->direction == GEGL_WIND_DIRECTION_TOP);
- g_mutex_lock (&mutex);
- if (!o->user_data)
+ if (horizontal_effect)
{
- o->user_data = g_hash_table_new_full (tuple_hash, tuple_equal, g_free, g_free);
- calculate_bleed (operation, input);
+ row_size = result->width * n_components;
+ row_start = result->y;
+ row_end = result->y + result->height;
+ row_rect.x = result->x;
+ row_rect.width = result->width;
+ row_rect.height = 1;
}
- g_mutex_unlock (&mutex);
-
- bleed_table = (GHashTable*) o->user_data;
-
- src_rect.x = result->x - op_area->left;
- src_rect.width = result->width + op_area->left + op_area->right;
- src_rect.y = result->y - op_area->top;
- src_rect.height = result->height + op_area->top + op_area->bottom;
-
- total_src_pixels = src_rect.width * src_rect.height;
- total_dst_pixels = result->width * result->height;
-
- src_buf = gegl_malloc (4 * total_src_pixels * sizeof (gfloat));
- dst_buf = gegl_malloc (4 * total_dst_pixels * sizeof (gfloat));
-
- gegl_buffer_get (input,
- &src_rect,
- 1.0,
- babl_format ("RGBA float"),
- src_buf,
- GEGL_AUTO_ROWSTRIDE,
- GEGL_ABYSS_NONE);
-
- current_pix = src_buf + 4*(o->strength + src_rect.width * o->strength);
- dst_pix = dst_buf;
- x = 0;
- y = 0;
- bleed_max = 0;
- bleed_index = 0;
- while (n_pixels--)
+ else
{
- gint i;
- pair key = {x + result->x, y + result->y};
- gint *bleed = g_hash_table_lookup (bleed_table, &key);
-
- if (x == 0) {
- for (i = 0; i < o->strength; i++)
- {
- pair key = {result->x - i, y + result->y};
- gint *bleed = g_hash_table_lookup (bleed_table, &key);
- if (bleed) {
- bleed_max = *bleed;
- bleed_index = *bleed - i;
- break;
- }
- }
- }
+ row_size = result->height * n_components;
+ row_start = result->x;
+ row_end = result->x + result->width;
+ row_rect.y = result->y;
+ row_rect.width = 1;
+ row_rect.height = result->height;
+ }
- for (i = 0; i < 4; i++)
- dst_pix[i] = current_pix[i];
+ row_buf = g_new (gfloat, row_size);
- if (bleed)
+ for (y = row_start; y < row_end; y++)
+ {
+ if (horizontal_effect)
+ row_rect.y = y;
+ else
+ row_rect.x = y;
+
+ gegl_buffer_get (input, &row_rect, 1.0, format, row_buf,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ if (need_reverse)
+ reverse_buffer (row_buf, row_size, n_components);
+
+ if (o->style == GEGL_WIND_STYLE_WIND)
{
- gfloat blend_color[4];
- gfloat blend_amount[4];
- gfloat *blend_pix;
-
- bleed_max = *bleed;
- bleed_index = *bleed;
- target_pix = current_pix;
- blend_pix = current_pix - 12;
- for (i = 0; i < 4; i++)
- {
- blend_amount[i] = target_pix[i] - blend_pix[i];
- blend_color[i] = blend_pix[i] + blend_amount[i];
- dst_pix[i] = (2.0 * blend_color[i] + dst_pix[i])/3.0;
- }
+ last_pix = row_size - n_components;
+ skip_rows = FALSE;
+ render_wind_row (row_buf, n_components, last_pix, o, gr);
}
- else if (bleed_index > 0)
+ else
{
- gfloat blend_color[4];
- gfloat blend_amount[4];
- gfloat *blend_pix;
- bleed_index--;
- blend_coefficient = 1.0 - ((gfloat) bleed_index)/(gfloat) bleed_max;
- blend_pix = current_pix - 4 * (bleed_max - bleed_index) - 12;
- target_pix = current_pix;
- for (i = 0; i < 4; i++)
- {
- blend_amount[i] = target_pix[i] - blend_pix[i];
- blend_color[i] = blend_pix[i] + blend_amount[i] * blend_coefficient;
- dst_pix[i] = (2.0 * blend_color[i] + dst_pix[i])/3.0;
- }
+ last_pix = row_size - (n_components * COMPARE_WIDTH);
+ skip_rows = render_blast_row (row_buf, n_components, last_pix, o, gr);
}
- x++;
- current_pix += 4;
- dst_pix += 4;
- if (x >= result->width)
+ if (need_reverse)
+ reverse_buffer (row_buf, row_size, n_components);
+
+ gegl_buffer_set (output, &row_rect, level, format, row_buf,
+ GEGL_AUTO_ROWSTRIDE);
+
+ if (skip_rows)
{
- bleed_max = 0;
- bleed_index = 0;
- x = 0;
- y++;
- current_pix += 8 * o->strength;
+ GeglRectangle rect = row_rect;
+ gint n_rows = g_rand_int_range (gr, 1, 3);
+
+ if (horizontal_effect)
+ {
+ rect.y = y + 1;
+ rect.height = n_rows;
+ }
+ else
+ {
+ rect.x = y + 1;
+ rect.width = n_rows;
+ }
+
+ gegl_buffer_copy (input, &rect, GEGL_ABYSS_CLAMP, output, &rect);
+ y += n_rows;
}
}
- gegl_buffer_set (output,
- result,
- 1,
- babl_format ("RGBA float"),
- dst_buf,
- GEGL_AUTO_ROWSTRIDE);
- gegl_free (src_buf);
- gegl_free (dst_buf);
+ g_rand_free (gr);
+ g_free (row_buf);
return TRUE;
}
static void
-finalize (GObject *object)
-{
- GeglProperties *o = GEGL_PROPERTIES (object);
-
- if (o->user_data)
- {
- g_hash_table_destroy (o->user_data);
- o->user_data = NULL;
- }
-
- G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
-}
-
-static void
gegl_op_class_init (GeglOpClass *klass)
{
- GObjectClass *object_class;
GeglOperationClass *operation_class;
GeglOperationFilterClass *filter_class;
- object_class = G_OBJECT_CLASS (klass);
operation_class = GEGL_OPERATION_CLASS (klass);
filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
- object_class->finalize = finalize;
- filter_class->process = process;
- operation_class->prepare = prepare;
+ filter_class->process = process;
+ operation_class->process = operation_process;
+ operation_class->prepare = prepare;
+ operation_class->get_cached_region = get_cached_region;
+ operation_class->get_required_for_output = get_required_for_output;
+ operation_class->opencl_support = FALSE;
gegl_operation_class_set_keys (operation_class,
- "categories", "distort",
- "name", "gegl:wind",
- "title", _("Wind"),
- "license", "GPL3+",
- "description", _("Wind-like bleed effect"),
- NULL);
+ "name", "gegl:wind",
+ "title", _("Wind"),
+ "categories", "distort",
+ "license", "GPL3+",
+ "description", _("Wind-like bleed effect"),
+ NULL);
}
+
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]