[gegl] long-shadow: add midpoint parameter to finite fading styles
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] long-shadow: add midpoint parameter to finite fading styles
- Date: Wed, 29 Aug 2018 17:03:51 +0000 (UTC)
commit 74a673cf6031ae57baa5acc65b8e7c4472c0e492
Author: Ell <ell_se yahoo com>
Date: Wed Aug 29 12:51:21 2018 -0400
long-shadow: add midpoint parameter to finite fading styles
Add a "midpoint-rel" property, which acts as the fade midpoint
parameter, instead of the "midpoint" property, for the fadinig-
fixed-length and fading-fixed-rate styles. Unlike the latter,
"midpoint-rel" is specified as a factor of the shadow length,
instead of as an absolute distance. When using GUM, as GIMP does,
the label of both properties is "midpoint", so they appear to be a
single property.
The midpoint value determines the gamma curve to use as the drop-
off function of the shadow. When it is 0.5, the drop-off is
linear, as before; when it is < 0.5, the drop-off decelerates; and,
when it is > 0.5, the drop-off accelerates.
Note that in the fixed-rate style, higher midpoint values result in
darker but *shorter* shadows, and a 1.0 midpoint results in no
shadow at all.
operations/common/long-shadow.c | 576 +++++++++++++++++++++++++++++++---------
1 file changed, 449 insertions(+), 127 deletions(-)
---
diff --git a/operations/common/long-shadow.c b/operations/common/long-shadow.c
index 848b347fb..bf47413fb 100644
--- a/operations/common/long-shadow.c
+++ b/operations/common/long-shadow.c
@@ -60,6 +60,13 @@ property_double (midpoint, _("Midpoint"), 100.0)
ui_range (0.0, 1000.0)
ui_meta ("visible", "style {fading}")
+property_double (midpoint_rel, _("Midpoint (relative)"), 0.5)
+ description (_("Shadow fade midpoint, as a factor of the shadow length"))
+ value_range (0.0, 1.0)
+ ui_meta ("visible", "style {fading-fixed-length, fading-fixed-rate}")
+ ui_meta ("label", "alt-label")
+ ui_meta ("alt-label", _("Midpoint"))
+
property_color (color, _("Color"), "black")
description (_("Shadow color"))
ui_meta ("role", "color-primary")
@@ -93,6 +100,24 @@ property_enum (composition, _("Composition"),
} \
G_STMT_END
+typedef enum
+{
+ VARIANT_FINITE,
+ VARIANT_FADING_FIXED_LENGTH_ACCELERATING,
+ VARIANT_FADING_FIXED_LENGTH_DECELERATING,
+ VARIANT_FADING_FIXED_RATE_NONLINEAR,
+ VARIANT_FADING_FIXED_RATE_LINEAR,
+ VARIANT_INFINITE,
+ VARIANT_FADING
+} Variant;
+
+typedef struct
+{
+ gfloat *fade_lut;
+ gint fade_lut_size;
+ gfloat fade_lut_gamma;
+} Data;
+
typedef struct
{
gfloat value;
@@ -113,10 +138,29 @@ typedef struct
ShadowItem *queue;
} Pixel;
+typedef struct
+{
+ Pixel pixel;
+ Shadow max1;
+ gfloat max2;
+} FFLPixel;
+
+typedef struct
+{
+ gfloat value;
+ gfloat fy;
+ gint last_fy;
+} FFRPixel;
+
typedef struct
{
GeglProperties options;
+ gboolean is_finite;
+ gboolean is_fading;
+
+ Variant variant;
+
/* image -> filter coordinate transformation */
gboolean flip_horizontally;
gboolean flip_vertically;
@@ -126,9 +170,15 @@ typedef struct
gdouble tan_angle;
gint shadow_height;
+ gfloat shadow_proj;
gfloat shadow_remainder;
gfloat fade_rate;
+ gfloat fade_rate_inv;
+ gfloat fade_gamma;
+ gfloat fade_gamma_inv;
+
+ const gfloat *fade_lut;
GeglRectangle input_bounds;
GeglRectangle roi;
@@ -212,6 +262,55 @@ init_options (Context *ctx,
{
ctx->options = *options;
+ ctx->is_finite = is_finite (options);
+ ctx->is_fading = is_fading (options);
+
+ if (ctx->is_finite && ctx->is_fading)
+ {
+ if (ctx->options.length <= EPSILON ||
+ ctx->options.midpoint_rel <= EPSILON ||
+ ctx->options.midpoint_rel >= 1.0 - EPSILON)
+ {
+ if (ctx->options.midpoint_rel <= EPSILON ||
+ ctx->options.style == GEGL_LONG_SHADOW_STYLE_FADING_FIXED_RATE)
+ {
+ ctx->options.length = 0.0;
+ }
+
+ ctx->options.style = GEGL_LONG_SHADOW_STYLE_FINITE;
+ ctx->is_fading = FALSE;
+ }
+ }
+
+ switch (ctx->options.style)
+ {
+ case GEGL_LONG_SHADOW_STYLE_INFINITE:
+ ctx->variant = VARIANT_INFINITE;
+ break;
+
+ case GEGL_LONG_SHADOW_STYLE_FINITE:
+ ctx->variant = VARIANT_FINITE;
+ break;
+
+ case GEGL_LONG_SHADOW_STYLE_FADING:
+ ctx->variant = VARIANT_FADING;
+ break;
+
+ case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_LENGTH:
+ if (ctx->options.midpoint_rel >= 0.5)
+ ctx->variant = VARIANT_FADING_FIXED_LENGTH_ACCELERATING;
+ else
+ ctx->variant = VARIANT_FADING_FIXED_LENGTH_DECELERATING;
+ break;
+
+ case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_RATE:
+ if (fabs (ctx->options.midpoint_rel - 0.5) > EPSILON)
+ ctx->variant = VARIANT_FADING_FIXED_RATE_NONLINEAR;
+ else
+ ctx->variant = VARIANT_FADING_FIXED_RATE_LINEAR;
+ break;
+ }
+
ctx->level = level;
ctx->scale = 1.0 / (1 << level);
ctx->scale_inv = 1 << level;
@@ -260,14 +359,12 @@ init_geometry (Context *ctx)
ctx->tan_angle = tan (ctx->options.angle);
- if (is_finite (&ctx->options))
+ if (ctx->is_finite)
{
- gdouble shadow_height;
-
- shadow_height = cos (ctx->options.angle) * ctx->options.length;
+ ctx->shadow_proj = cos (ctx->options.angle) * ctx->options.length;
- ctx->shadow_height = ceil (shadow_height);
- ctx->shadow_remainder = 1.0 - (ctx->shadow_height - shadow_height);
+ ctx->shadow_height = ceil (ctx->shadow_proj);
+ ctx->shadow_remainder = 1.0 - (ctx->shadow_height - ctx->shadow_proj);
}
}
@@ -445,6 +542,13 @@ get_affecting_filter_range (Context *ctx,
if (fx1) *fx1 = ceil (project_to_filter (ctx, u1 - 0.5, fy + 0.5));
}
+static inline gfloat
+fade_value (Context *ctx,
+ gfloat fy)
+{
+ return 1.0f - powf (fy * ctx->fade_rate, ctx->fade_gamma);
+}
+
static void
init_fade (Context *ctx)
{
@@ -464,14 +568,38 @@ init_fade (Context *ctx)
case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_LENGTH:
case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_RATE:
- if (ctx->shadow_height > 0)
- {
- ctx->fade_rate = 1.0 / (cos (ctx->options.angle) *
- ctx->options.length);
- }
- else
+ ctx->fade_rate = 1.0 / (ctx->shadow_proj + 1.0);
+ ctx->fade_gamma = -G_LN2 / log (ctx->options.midpoint_rel);
+
+ ctx->fade_rate_inv = 1.0 / ctx->fade_rate;
+ ctx->fade_gamma_inv = 1.0 / ctx->fade_gamma;
+
+ if (ctx->options.style == GEGL_LONG_SHADOW_STYLE_FADING_FIXED_LENGTH)
{
- ctx->fade_rate = 1.0f;
+ Data *data = ctx->options.user_data;
+
+ if (! data)
+ {
+ data = g_slice_new0 (Data);
+
+ ctx->options.user_data = data;
+ }
+
+ if (ctx->shadow_height + 1 != data->fade_lut_size ||
+ ctx->fade_gamma != data->fade_lut_gamma)
+ {
+ gint fy;
+
+ data->fade_lut = g_renew (gfloat, data->fade_lut,
+ ctx->shadow_height + 1);
+ data->fade_lut_size = ctx->shadow_height + 1;
+ data->fade_lut_gamma = ctx->fade_gamma;
+
+ for (fy = 0; fy <= ctx->shadow_height; fy++)
+ data->fade_lut[fy] = fade_value (ctx, fy);
+ }
+
+ ctx->fade_lut = data->fade_lut;
}
break;
@@ -508,7 +636,7 @@ init_area (Context *ctx,
ctx->area = ctx->roi;
- if (is_finite (&ctx->options))
+ if (ctx->is_finite)
{
gint u0;
@@ -536,16 +664,24 @@ init_area (Context *ctx,
static void
init_screen (Context *ctx)
{
- switch (ctx->options.style)
+ switch (ctx->variant)
{
- case GEGL_LONG_SHADOW_STYLE_FINITE:
- case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_LENGTH:
+ case VARIANT_FINITE:
+ case VARIANT_FADING_FIXED_LENGTH_ACCELERATING:
ctx->pixel_size = sizeof (Pixel);
break;
- case GEGL_LONG_SHADOW_STYLE_INFINITE:
- case GEGL_LONG_SHADOW_STYLE_FADING:
- case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_RATE:
+ case VARIANT_FADING_FIXED_LENGTH_DECELERATING:
+ ctx->pixel_size = sizeof (FFLPixel);
+ break;
+
+ case VARIANT_FADING_FIXED_RATE_NONLINEAR:
+ ctx->pixel_size = sizeof (FFRPixel);
+ break;
+
+ case VARIANT_FADING_FIXED_RATE_LINEAR:
+ case VARIANT_INFINITE:
+ case VARIANT_FADING:
ctx->pixel_size = sizeof (gfloat);
break;
}
@@ -578,13 +714,25 @@ clear_pixel_queue (Context *ctx,
static void
cleanup_screen (Context *ctx)
{
- if (ctx->pixel_size == sizeof (Pixel))
+ switch (ctx->options.style)
{
- Pixel *p = ctx->screen;
- gint u;
+ case GEGL_LONG_SHADOW_STYLE_FINITE:
+ case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_LENGTH:
+ {
+ guchar *p = ctx->screen;
+ gint u;
- for (u = ctx->u0; u < ctx->u1; u++)
- clear_pixel_queue (ctx, &p[u]);
+ p += ctx->u0 * ctx->pixel_size;
+
+ for (u = ctx->u0; u < ctx->u1; u++, p += ctx->pixel_size)
+ clear_pixel_queue (ctx, (Pixel *) p);
+ }
+ break;
+
+ case GEGL_LONG_SHADOW_STYLE_INFINITE:
+ case GEGL_LONG_SHADOW_STYLE_FADING:
+ case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_RATE:
+ break;
}
ctx->screen = (guchar *) ctx->screen + ctx->pixel_size * ctx->u0;
@@ -658,14 +806,25 @@ shadow_value (Context *ctx,
const Shadow *shadow,
gint fy)
{
- if (ctx->options.style == GEGL_LONG_SHADOW_STYLE_FINITE ||
- ! shadow->value)
+ if (! ctx->is_fading)
+ return shadow->value;
+ else
+ return shadow->value * ctx->fade_lut[fy - shadow->fy];
+}
+
+static inline gfloat
+shadow_collation_value (Context *ctx,
+ const Shadow *shadow,
+ gint fy)
+{
+ if (ctx->variant == VARIANT_FINITE ||
+ ctx->variant == VARIANT_FADING_FIXED_LENGTH_DECELERATING)
{
return shadow->value;
}
else
{
- return shadow->value * (1.0f - ctx->fade_rate * (fy - shadow->fy));
+ return shadow->value * ctx->fade_lut[fy - shadow->fy];
}
}
@@ -696,26 +855,29 @@ static void
trim_shadow (Context *ctx,
gint fy)
{
- if (fy <= ctx->roi.y && ! is_fading (&ctx->options))
+ if (fy <= ctx->roi.y && ! ctx->is_fading)
return;
if (ctx->active_u0 >= ctx->active_u1)
return;
- switch (ctx->options.style)
+ switch (ctx->variant)
{
- case GEGL_LONG_SHADOW_STYLE_FINITE:
- case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_LENGTH:
+ case VARIANT_FINITE:
+ case VARIANT_FADING_FIXED_LENGTH_ACCELERATING:
+ case VARIANT_FADING_FIXED_LENGTH_DECELERATING:
{
- Pixel *p = ctx->screen;
- gint active_u0 = ctx->u1;
- gint active_u1 = ctx->u0;
- gint fy_shadow_height = fy - ctx->shadow_height;
- gint u;
+ guchar *p = ctx->screen;
+ gint active_u0 = ctx->u1;
+ gint active_u1 = ctx->u0;
+ gint fy_shadow_height = fy - ctx->shadow_height;
+ gint u;
- for (u = ctx->active_u0; u < ctx->active_u1; u++)
+ p += ctx->active_u0 * ctx->pixel_size;
+
+ for (u = ctx->active_u0; u < ctx->active_u1; u++, p += ctx->pixel_size)
{
- Pixel *pixel = &p[u];
+ Pixel *pixel = (Pixel *) p;
gboolean active = (pixel->shadow.value != 0.0);
if (active && pixel->shadow.fy < fy_shadow_height)
@@ -723,9 +885,33 @@ trim_shadow (Context *ctx,
if (active)
{
- if (ctx->options.style ==
- GEGL_LONG_SHADOW_STYLE_FADING_FIXED_LENGTH &&
- pixel->queue)
+ if (ctx->variant ==
+ VARIANT_FADING_FIXED_LENGTH_DECELERATING)
+ {
+ FFLPixel *ffl_pixel = (FFLPixel *) p;
+ ShadowItem *item;
+
+ ffl_pixel->max1.value = shadow_value (ctx,
+ &pixel->shadow, fy);
+ ffl_pixel->max1.fy = pixel->shadow.fy;
+ ffl_pixel->max2 = 0.0f;
+
+ for (item = pixel->queue; item; item = item->next)
+ {
+ gfloat value = shadow_value (ctx, &item->shadow, fy);
+
+ if (value > ffl_pixel->max1.value)
+ {
+ ffl_pixel->max2 = ffl_pixel->max1.value;
+
+ ffl_pixel->max1.value = value;
+ ffl_pixel->max1.fy = item->shadow.fy;
+ }
+ }
+ }
+ else if (ctx->variant ==
+ VARIANT_FADING_FIXED_LENGTH_ACCELERATING &&
+ pixel->queue)
{
ShadowItem *item = pixel->queue->prev;
ShadowItem *last_item = item;
@@ -775,7 +961,39 @@ trim_shadow (Context *ctx,
}
break;
- case GEGL_LONG_SHADOW_STYLE_FADING:
+ case VARIANT_FADING_FIXED_RATE_NONLINEAR:
+ {
+ FFRPixel *p = ctx->screen;
+ gint active_u0 = ctx->u1;
+ gint active_u1 = ctx->u0;
+ gint u;
+
+ for (u = ctx->active_u0; u < ctx->active_u1; u++)
+ {
+ FFRPixel *pixel = &p[u];
+
+ if (! pixel->value)
+ continue;
+
+ if (pixel->last_fy < fy)
+ {
+ pixel->value = 0.0f;
+ }
+ else
+ {
+ pixel->value = fade_value (ctx, fy - pixel->fy);
+
+ active_u0 = MIN (active_u0, u);
+ active_u1 = u + 1;
+ }
+ }
+
+ ctx->active_u0 = active_u0;
+ ctx->active_u1 = active_u1;
+ }
+ break;
+
+ case VARIANT_FADING_FIXED_RATE_LINEAR:
{
gfloat *p = ctx->screen;
gint active_u0 = ctx->u1;
@@ -787,7 +1005,7 @@ trim_shadow (Context *ctx,
if (! p[u])
continue;
- p[u] *= ctx->fade_rate;
+ p[u] -= ctx->fade_rate;
if (p[u] <= EPSILON)
{
@@ -805,7 +1023,7 @@ trim_shadow (Context *ctx,
}
break;
- case GEGL_LONG_SHADOW_STYLE_FADING_FIXED_RATE:
+ case VARIANT_FADING:
{
gfloat *p = ctx->screen;
gint active_u0 = ctx->u1;
@@ -817,7 +1035,7 @@ trim_shadow (Context *ctx,
if (! p[u])
continue;
- p[u] -= ctx->fade_rate;
+ p[u] *= ctx->fade_rate;
if (p[u] <= EPSILON)
{
@@ -835,7 +1053,7 @@ trim_shadow (Context *ctx,
}
break;
- case GEGL_LONG_SHADOW_STYLE_INFINITE:
+ case VARIANT_INFINITE:
break;
}
}
@@ -855,83 +1073,123 @@ add_shadow (Context *ctx,
u0 = MAX (u0, ctx->u0);
u1 = MIN (u1, ctx->u1);
- if (ctx->pixel_size == sizeof (Pixel))
+ switch (ctx->variant)
{
- Pixel *p = ctx->screen;
+ case VARIANT_FINITE:
+ case VARIANT_FADING_FIXED_LENGTH_ACCELERATING:
+ case VARIANT_FADING_FIXED_LENGTH_DECELERATING:
+ {
+ guchar *p = ctx->screen;
- for (u = u0; u < u1; u++)
- {
- Pixel *pixel = &p[u];
+ p += u0 * ctx->pixel_size;
- if (value >= shadow_value (ctx, &pixel->shadow, fy))
- {
- pixel->shadow.value = value;
- pixel->shadow.fy = fy;
+ for (u = u0; u < u1; u++, p += ctx->pixel_size)
+ {
+ Pixel *pixel = (Pixel *) p;
- clear_pixel_queue (ctx, pixel);
+ if (value >= shadow_collation_value (ctx, &pixel->shadow, fy))
+ {
+ pixel->shadow.value = value;
+ pixel->shadow.fy = fy;
- ctx->active_u0 = MIN (ctx->active_u0, u0);
- ctx->active_u1 = MAX (ctx->active_u1, u1);
- }
- else if (! pixel->queue)
- {
- if (fy != pixel->shadow.fy)
- {
- pixel->queue = g_slice_new (ShadowItem);
-
- pixel->queue->shadow.value = value;
- pixel->queue->shadow.fy = fy;
- pixel->queue->next = NULL;
- pixel->queue->prev = pixel->queue;
- }
- }
- else
- {
- ShadowItem *item = pixel->queue->prev;
- ShadowItem *last_item = item;
- ShadowItem *new_item = NULL;
+ clear_pixel_queue (ctx, pixel);
+ }
+ else if (! pixel->queue)
+ {
+ if (fy != pixel->shadow.fy)
+ {
+ pixel->queue = g_slice_new (ShadowItem);
- do
- {
- if (value < shadow_value (ctx, &item->shadow, fy))
- break;
+ pixel->queue->shadow.value = value;
+ pixel->queue->shadow.fy = fy;
+ pixel->queue->next = NULL;
+ pixel->queue->prev = pixel->queue;
+ }
+ }
+ else
+ {
+ ShadowItem *item = pixel->queue->prev;
+ ShadowItem *last_item = item;
+ ShadowItem *new_item = NULL;
- g_slice_free (ShadowItem, new_item);
- new_item = item;
+ do
+ {
+ if (value < shadow_collation_value (ctx, &item->shadow, fy))
+ break;
- item = item->prev;
- }
- while (item != last_item);
+ g_slice_free (ShadowItem, new_item);
+ new_item = item;
- if (! new_item)
- {
- if (fy == last_item->shadow.fy)
- continue;
+ item = item->prev;
+ }
+ while (item != last_item);
- new_item = g_slice_new (ShadowItem);
+ if (! new_item)
+ {
+ if (fy == last_item->shadow.fy)
+ continue;
- new_item->prev = last_item;
- last_item->next = new_item;
- }
+ new_item = g_slice_new (ShadowItem);
- new_item->shadow.value = value;
- new_item->shadow.fy = fy;
- new_item->next = NULL;
+ new_item->prev = last_item;
+ last_item->next = new_item;
+ }
- pixel->queue->prev = new_item;
- }
- }
- }
- else
- {
- gfloat *p = ctx->screen;
+ new_item->shadow.value = value;
+ new_item->shadow.fy = fy;
+ new_item->next = NULL;
+
+ pixel->queue->prev = new_item;
+ }
+
+ if (ctx->variant == VARIANT_FADING_FIXED_LENGTH_DECELERATING)
+ {
+ FFLPixel *ffl_pixel = (FFLPixel *) p;
- for (u = u0; u < u1; u++)
- p[u] = MAX (p[u], value);
+ if (value >= ffl_pixel->max1.value)
+ {
+ ffl_pixel->max1.value = value;
+ ffl_pixel->max1.fy = fy;
+ }
+ }
+ }
+ }
+ break;
- ctx->active_u0 = MIN (ctx->active_u0, u0);
- ctx->active_u1 = MAX (ctx->active_u1, u1);
+ case VARIANT_FADING_FIXED_RATE_NONLINEAR:
+ {
+ FFRPixel *p = ctx->screen;
+
+ for (u = u0; u < u1; u++)
+ {
+ FFRPixel *pixel = &p[u];
+
+ if (value >= pixel->value)
+ {
+ pixel->value = value;
+ pixel->fy = fy - powf (1.0f - value,
+ ctx->fade_gamma_inv) *
+ ctx->fade_rate_inv;
+ pixel->last_fy = ceilf (pixel->fy + ctx->shadow_proj);
+ }
+ }
+ }
+ break;
+
+ case VARIANT_FADING_FIXED_RATE_LINEAR:
+ case VARIANT_INFINITE:
+ case VARIANT_FADING:
+ {
+ gfloat *p = ctx->screen;
+
+ for (u = u0; u < u1; u++)
+ p[u] = MAX (p[u], value);
+ }
+ break;
}
+
+ ctx->active_u0 = MIN (ctx->active_u0, u0);
+ ctx->active_u1 = MAX (ctx->active_u1, u1);
}
static inline void
@@ -952,28 +1210,66 @@ get_pixel_shadow (Context *ctx,
gconstpointer pixel,
gint fy)
{
- if (ctx->pixel_size == sizeof (Pixel))
+ switch (ctx->variant)
{
- const Pixel *p = pixel;
- gfloat value = shadow_value (ctx, &p->shadow, fy);
+ case VARIANT_FINITE:
+ case VARIANT_FADING_FIXED_LENGTH_ACCELERATING:
+ {
+ const Pixel *p = pixel;
+ gfloat value = shadow_value (ctx, &p->shadow, fy);
- if (value && p->shadow.fy + ctx->shadow_height == fy)
- {
- value *= ctx->shadow_remainder;
+ if (value && p->shadow.fy + ctx->shadow_height == fy)
+ {
+ value *= ctx->shadow_remainder;
- if (p->queue)
- value += (1.0 - ctx->shadow_remainder) *
- shadow_value (ctx, &p->queue->shadow, fy);
- }
+ if (p->queue)
+ value += (1.0 - ctx->shadow_remainder) *
+ shadow_value (ctx, &p->queue->shadow, fy);
+ }
- return value;
- }
- else
- {
- const gfloat *p = pixel;
+ return value;
+ }
+
+ case VARIANT_FADING_FIXED_LENGTH_DECELERATING:
+ {
+ const FFLPixel *p = pixel;
+ gfloat value = p->max1.value;
+
+ if (value && p->max1.fy + ctx->shadow_height == fy)
+ {
+ value *= ctx->shadow_remainder;
+ value += (1.0 - ctx->shadow_remainder) * p->max2;
+ }
- return *p;
+ return value;
+ }
+
+ case VARIANT_FADING_FIXED_RATE_NONLINEAR:
+ {
+ const FFRPixel *p = pixel;
+ gfloat value = p->value;
+
+ if (fy == p->last_fy)
+ {
+ gfloat remainder = p->fy + ctx->shadow_proj + 1.0f - fy;
+
+ value *= remainder;
+ }
+
+ return value;
+ }
+
+ case VARIANT_FADING_FIXED_RATE_LINEAR:
+ case VARIANT_INFINITE:
+ case VARIANT_FADING:
+ {
+ const gfloat *p = pixel;
+
+ return *p;
+ }
}
+
+ g_return_val_if_reached (0.0f);
}
static void
@@ -1245,10 +1541,11 @@ process (GeglOperation *operation,
const GeglRectangle *roi,
gint level)
{
- Context ctx;
- gint fx, fy;
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ Context ctx;
+ gint fx, fy;
- init_options (&ctx, GEGL_PROPERTIES (operation), level);
+ init_options (&ctx, o, level);
init_geometry (&ctx);
init_fade (&ctx);
init_area (&ctx, operation, roi);
@@ -1295,21 +1592,46 @@ process (GeglOperation *operation,
set_row (&ctx, fy);
}
+ o->user_data = ctx.options.user_data;
+
cleanup_buffers (&ctx);
cleanup_screen (&ctx);
return TRUE;
}
+static void
+dispose (GObject *object)
+{
+ GeglProperties *o = GEGL_PROPERTIES (object);
+
+ if (o->user_data)
+ {
+ Data *data = o->user_data;
+
+ g_free (data->fade_lut);
+
+ g_slice_free (Data, data);
+
+ o->user_data = NULL;
+ }
+
+ G_OBJECT_CLASS (gegl_op_parent_class)->dispose (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->dispose = dispose;
+
operation_class->get_required_for_output = get_required_for_output;
operation_class->get_invalidated_by_change = get_invalidated_by_change;
operation_class->get_bounding_box = get_bounding_box;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]