[gegl] spiral: add logarithmic mode
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] spiral: add logarithmic mode
- Date: Sat, 29 Apr 2017 17:27:15 +0000 (UTC)
commit a417b1fbec984b2279ffb4405c85c4b8a8c56fab
Author: Ell <ell_se yahoo com>
Date: Sat Apr 29 11:08:36 2017 -0400
spiral: add logarithmic mode
And some small antialiasing/alignment improvements.
operations/workshop/spiral.c | 280 +++++++++++++++++++++++++++++++++---------
1 files changed, 221 insertions(+), 59 deletions(-)
---
diff --git a/operations/workshop/spiral.c b/operations/workshop/spiral.c
index 0805013..9ec0548 100644
--- a/operations/workshop/spiral.c
+++ b/operations/workshop/spiral.c
@@ -22,6 +22,16 @@
#ifdef GEGL_PROPERTIES
+enum_start (gegl_spiral_type)
+ enum_value (GEGL_SPIRAL_TYPE_LINEAR, "linear", N_("Linear"))
+ enum_value (GEGL_SPIRAL_TYPE_LOGARITHMIC, "logarithmic", N_("Logarithmic"))
+enum_end (GeglSpiralType)
+
+property_enum (type, _("Type"),
+ GeglSpiralType, gegl_spiral_type,
+ GEGL_SPIRAL_TYPE_LINEAR)
+ description (_("Spiral type"))
+
property_double (x, _("X"), 0.5)
description (_("Spiral origin X coordinate"))
ui_range (0.0, 1.0)
@@ -40,6 +50,12 @@ property_double (radius, _("Radius"), 100.0)
ui_range (1.0, 400.0)
ui_meta ("unit", "pixel-distance")
+property_double (base, _("Base"), 2.0)
+ description (_("Logarithmic spiral base"))
+ value_range (1.0, G_MAXDOUBLE)
+ ui_range (1.0, 20.0)
+ ui_gamma (2.0)
+
property_double (balance, _("Balance"), 0.0)
description (_("Area balance between the two colors"))
value_range (-1.0, 1.0)
@@ -139,72 +155,57 @@ blend (const gfloat *color1,
}
}
-static gboolean
-process (GeglOperation *operation,
- void *out_buf,
- glong n_pixels,
- const GeglRectangle *roi,
- gint level)
+static void
+process_linear (gfloat *out,
+ gint width,
+ gint height,
+ gfloat x0,
+ gfloat y0,
+ gfloat radius,
+ gfloat thickness,
+ gfloat angle,
+ gboolean clockwise,
+ const gfloat *color1,
+ const gfloat *color2)
{
- GeglProperties *o = GEGL_PROPERTIES (operation);
- const Babl *format = babl_format ("R'G'B'A float");
- gfloat *dest = out_buf;
- gfloat scale = 1.0 / (1 << level);
- gfloat radius = scale * o->radius;
- gfloat thickness = (1.0 - o->balance) / 2.0;
- gfloat angle = o->rotation / 360.0;
- gboolean clockwise = o->direction == GEGL_SPIRAL_DIRECTION_CLOCKWISE;
- gfloat lim;
- gfloat color1[4];
- gfloat color2[4];
- gfloat x0;
- gfloat x;
- gfloat y;
- gint i;
- gint j;
-
- if (thickness <= 0.5)
- {
- gegl_color_get_pixel (o->color1, format, color1);
- gegl_color_get_pixel (o->color2, format, color2);
- }
- else
+ gfloat lim;
+ gfloat x;
+ gfloat y;
+ gint i;
+ gint j;
+
+ if (thickness > 0.5)
{
- thickness = 1.0 - thickness;
- angle -= 0.5;
+ const gfloat *temp;
- gegl_color_get_pixel (o->color2, format, color1);
- gegl_color_get_pixel (o->color1, format, color2);
+ thickness = 1.0 - thickness;
+ angle = fmod (angle + thickness, 1.0);
+
+ temp = color1;
+ color1 = color2;
+ color2 = temp;
}
- if (radius == 1.0 || thickness == 0.0)
+ if (thickness == 0.0 || radius == 1.0)
{
gfloat color[4];
blend (color2, color1, thickness, color);
- gegl_memset_pattern (dest, color, sizeof (color), n_pixels);
+ gegl_memset_pattern (out, color, sizeof (color), width * height);
- return TRUE;
+ return;
}
lim = thickness * radius;
- if (clockwise)
- angle = 1.0 - angle;
+ y = y0;
- angle += thickness / 2.0;
-
- angle = fmodf (angle + 0.5, 1.0) - 0.5;
-
- x0 = roi->x - scale * gegl_coordinate_relative_to_pixel (o->x, o->width);
- y = roi->y - scale * gegl_coordinate_relative_to_pixel (o->y, o->height);
-
- for (j = roi->height; j; j--, y++)
+ for (j = height; j; j--, y++)
{
x = x0;
- for (i = roi->width; i; i--, x++)
+ for (i = width; i; i--, x++)
{
gfloat r;
gfloat t;
@@ -223,40 +224,201 @@ process (GeglOperation *operation,
r = fmodf (r - s, radius);
if (r < 0.5f)
- a = MIN (lim, r + 0.5f);
+ {
+ a = MIN (lim, r + 0.5f);
+ }
else if (r > radius - 0.5f)
- a = MAX (lim - (r - 0.5f), 0.0f) + MIN (lim, (r + 0.5f) - radius);
+ {
+ a = MAX (lim - (r - 0.5f), 0.0f) +
+ MIN (lim, (r + 0.5f) - radius);
+ }
else
- a = CLAMP (lim - (r - 0.5f), 0.0f, 1.0f);
+ {
+ a = CLAMP (lim - (r - 0.5f), 0.0f, 1.0f);
+ }
}
else
{
gfloat l = lim - (radius - s);
+ a = CLAMP ((r + 0.5f) - s, 0.0f, lim);
+
if (t <= 0.5f)
{
if (r < 0.5f)
- a = CLAMP (l + radius / 2.0f, 0.0f, 0.5f - r);
- else
- a = 0.0f;
+ {
+ a += CLAMP (l + radius / 2.0f, 0.0f, 0.5f - r);
+ }
}
else
{
if (r < 0.5f)
- a = CLAMP (l, 0.0f, r + 0.5f);
+ {
+ a += CLAMP (l, 0.0f, r + 0.5f) +
+ CLAMP ((0.5f - r) - (s - radius / 2.0f), 0.0f, lim);
+ }
else
- a = CLAMP (l - (r - 0.5f), 0.0f, 1.0f);
+ {
+ a += CLAMP (l - (r - 0.5f), 0.0f, 1.0f);
+ }
}
+ }
+
+ blend (color2, color1, a, out);
+
+ out += 4;
+ }
+ }
+}
+
+static void
+process_logarithmic (gfloat *out,
+ gint width,
+ gint height,
+ gfloat x0,
+ gfloat y0,
+ gfloat radius,
+ gfloat base,
+ gfloat thickness,
+ gfloat angle,
+ gboolean clockwise,
+ const gfloat *color1,
+ const gfloat *color2)
+{
+ gfloat log_radius;
+ gfloat base_inv;
+ gfloat log_base;
+ gfloat log_base_inv;
+ gfloat lim;
+ gfloat ratio;
+ gfloat x;
+ gfloat y;
+ gint i;
+ gint j;
+
+ if (thickness == 0.0 || thickness == 1.0 || base == 1.0)
+ {
+ const gfloat *color;
+
+ color = thickness > 0.5f ? color1 : color2;
+
+ gegl_memset_pattern (out, color, 4 * sizeof (gfloat), width * height);
+
+ return;
+ }
+
+ log_radius = log (radius);
+ base_inv = 1.0 / base;
+ log_base = log (base);
+ log_base_inv = 1.0 / log_base;
+ lim = exp (log_base * thickness);
+ ratio = (lim - 1.0) / (base - 1.0);
+
+ y = y0;
- if (r > s - 0.5f)
- a += MIN (lim, (r + 0.5f) - s);
+ for (j = height; j; j--, y++)
+ {
+ x = x0;
+
+ for (i = width; i; i--, x++)
+ {
+ gfloat r;
+ gfloat t;
+ gfloat a;
+ gfloat s;
+ gfloat l;
+ gfloat S;
+
+ r = sqrtf (x * x + y * y);
+ t = RAD_TO_REV * atan2f (clockwise ? y : -y, x) - angle;
+
+ t += t < 0.0f;
+
+ s = log_base_inv * (logf (r) - log_radius);
+ s = expf (log_base * (floorf (s - t) + t) + log_radius);
+
+ l = s * lim;
+ S = s * base;
+
+ if (r >= s + 0.5f)
+ {
+ a = CLAMP (l - (r - 0.5f), 0.0f, 1.0f);
+
+ if (r > S - 0.5f)
+ a += MIN (l * base - S, r + 0.5f - S);
}
+ else
+ {
+ if (s - s * base_inv >= 0.5f)
+ {
+ a = MIN (l - s, r + 0.5f - s);
+ a += MAX (l * base_inv - (r - 0.5f), 0.0f);
- blend (color2, color1, a, dest);
+ if (r > S - 0.5f)
+ a += MIN (l * base - S, r + 0.5f - S);
+ }
+ else
+ {
+ a = ratio;
+ }
+ }
+
+ blend (color2, color1, a, out);
- dest += 4;
+ out += 4;
}
}
+}
+
+static gboolean
+process (GeglOperation *operation,
+ void *out,
+ glong n_pixels,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *format = babl_format ("R'G'B'A float");
+ gfloat scale = 1.0 / (1 << level);
+ gfloat x0;
+ gfloat y0;
+ gfloat radius = scale * o->radius;
+ gfloat thickness = (1.0 - o->balance) / 2.0;
+ gfloat angle = o->rotation / 360.0;
+ gboolean clockwise = o->direction == GEGL_SPIRAL_DIRECTION_CLOCKWISE;
+ gfloat color1[4];
+ gfloat color2[4];
+
+ x0 = roi->x -
+ scale * gegl_coordinate_relative_to_pixel (o->x, o->width) + 0.5;
+ y0 = roi->y -
+ scale * gegl_coordinate_relative_to_pixel (o->y, o->height) + 0.5;
+
+ if (clockwise)
+ angle = 1.0 - angle;
+
+ angle = fmod (angle + thickness / 2.0, 1.0);
+
+ gegl_color_get_pixel (o->color1, format, color1);
+ gegl_color_get_pixel (o->color2, format, color2);
+
+ switch (o->type)
+ {
+ case GEGL_SPIRAL_TYPE_LINEAR:
+ process_linear (out, roi->width, roi->height,
+ x0, y0, radius, thickness, angle, clockwise,
+ color1, color2);
+ break;
+
+ case GEGL_SPIRAL_TYPE_LOGARITHMIC:
+ process_logarithmic (out, roi->width, roi->height,
+ x0, y0, radius, o->base, thickness, angle, clockwise,
+ color1, color2);
+ break;
+
+ default:
+ g_return_val_if_reached (FALSE);
+ }
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]