[gegl] move mirrors op out of workshop
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] move mirrors op out of workshop
- Date: Thu, 20 Jan 2011 22:14:40 +0000 (UTC)
commit 6637959e4341700409c96feff2852f05122391cd
Author: �yvind Kolås <pippin gimp org>
Date: Thu Jan 20 22:14:00 2011 +0000
move mirrors op out of workshop
operations/common/mirrors.c | 402 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 402 insertions(+), 0 deletions(-)
---
diff --git a/operations/common/mirrors.c b/operations/common/mirrors.c
new file mode 100644
index 0000000..5409178
--- /dev/null
+++ b/operations/common/mirrors.c
@@ -0,0 +1,402 @@
+/* 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>
+ * Copyright 2010 Alexia Death
+ *
+ * Based on "Kaleidoscope" GIMP plugin
+ * Copyright (C) 1999, 2002 Kelly Martin, updated 2005 by Matthew Plough
+ * kelly gimp org
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_double (m_angle, _("Mirror rotation"), 0.0, 180.0, 0.0, _("Rotation applied to the mirrors"))
+
+gegl_chant_double (r_angle, _("Result rotation"), 0.0, 360.0, 0.0, _("Rotation applied to the result"))
+
+gegl_chant_int (n_segs, _("Mirrors"), 2, 24, 6, _("Number of mirrors to use"))
+
+gegl_chant_double (c_x, _("X offset"), 0.0, 1.0, 0.5, _("X offset of the result of mirroring"))
+
+gegl_chant_double (c_y, _("Y offset"), 0.0, 1.0, 0.5, _("Y offset of the result of mirroring"))
+
+gegl_chant_double (o_x, _("Center X"), -1.0, 1.0, 0.0, _("X axis ratio for the center of mirroring"))
+
+gegl_chant_double (o_y, _("Center Y"), -1.0, 1.0, 0.0, _("Y axis ratio for the center of mirroring"))
+
+gegl_chant_double (trim_x, _("Trim X"), 0.0, 0.5, 0.0, _("X axis ratio for trimming mirror expanse"))
+
+gegl_chant_double (trim_y, _("Trim Y"), 0.0, 0.5, 0.0, _("Y axis ratio for trimming mirror expanse"))
+
+gegl_chant_double (input_scale, _("Zoom"), 0.1, 100.0, 100.0, _("Scale factor to make rendering size bigger"))
+
+gegl_chant_double (output_scale, _("Expand"), 0.0, 100.0, 1.0, _("Scale factor to make rendering size bigger"))
+
+gegl_chant_boolean (clip, _("Clip result"), TRUE, _("Clip result to input size"))
+
+gegl_chant_boolean (warp, _("Wrap input"), TRUE, _("Fill full output area"))
+
+
+#else
+
+#define GEGL_CHANT_TYPE_FILTER
+#define GEGL_CHANT_C_FILE "mirrors.c"
+
+#include "gegl-chant.h"
+#include <math.h>
+
+#if 0
+#define TRACE /* Define this to see basic tracing info. */
+#endif
+
+#if 0
+#define DO_NOT_USE_BUFFER_SAMPLE /* Define this to disable buffer sample.*/
+#endif
+
+static int
+calc_undistorted_coords(double wx, double wy,
+ double angle1, double angle2, int nsegs,
+ double cen_x, double cen_y,
+ double off_x, double off_y,
+ double *x, double *y)
+{
+ double dx, dy;
+ double r, ang;
+
+ double awidth = G_PI/nsegs;
+ double mult;
+
+ dx = wx - cen_x;
+ dy = wy - cen_y;
+
+ r = sqrt(dx*dx+dy*dy);
+ if (r == 0.0) {
+ *x = wx + off_x;
+ *y = wy + off_y;
+ return TRUE;
+ }
+
+ ang = atan2(dy,dx) - angle1 - angle2;
+ if (ang<0.0) ang = 2*G_PI - fmod (fabs (ang), 2*G_PI);
+
+ mult = ceil(ang/awidth) - 1;
+ ang = ang - mult*awidth;
+ if (((int) mult) % 2 == 1) ang = awidth - ang;
+ ang = ang + angle1;
+
+ *x = r*cos(ang) + off_x;
+ *y = r*sin(ang) + off_y;
+
+ return TRUE;
+} /* calc_undistorted_coords */
+
+/* Apply the actual transform */
+
+static void
+apply_mirror (double mirror_angle,
+ double result_angle,
+ int nsegs,
+ double cen_x,
+ double cen_y,
+ double off_x,
+ double off_y,
+ double input_scale,
+ gboolean clip,
+ gboolean warp,
+ Babl *format,
+ GeglBuffer *src,
+ GeglRectangle *in_boundary,
+ GeglBuffer *dst,
+ GeglRectangle *boundary,
+ const GeglRectangle *roi)
+{
+ gfloat *dst_buf;
+ gint row, col;
+ gdouble cx, cy;
+
+ /* Get src pixels. */
+
+ #ifdef TRACE
+ g_warning ("> mirror marker1, boundary x:%d, y:%d, w:%d, h:%d, center: (%f, %f) offset: (%f, %f)", boundary->x, boundary->y, boundary->width, boundary->height, cen_x, cen_y, off_x,off_y );
+ #endif
+
+ #ifdef DO_NOT_USE_BUFFER_SAMPLE
+ src_buf = g_new0 (gfloat, boundary->width * boundary->height * 4);
+ gegl_buffer_get (src, 1.0, boundary, format, src_buf, GEGL_AUTO_ROWSTRIDE);
+ #endif
+ /* Get buffer in which to place dst pixels. */
+ dst_buf = g_new0 (gfloat, roi->width * roi->height * 4);
+
+ mirror_angle = mirror_angle * G_PI / 180;
+ result_angle = result_angle * G_PI / 180;
+
+ for (row = 0; row < roi->height; row++) {
+ for (col = 0; col < roi->width; col++) {
+ calc_undistorted_coords(roi->x + col + 0.01, roi->y + row - 0.01, mirror_angle, result_angle,
+ nsegs,
+ cen_x, cen_y,
+ off_x * input_scale, off_y * input_scale,
+ &cx, &cy);
+
+
+ /* apply scale*/
+ cx = in_boundary->x + (cx - in_boundary->x) / input_scale;
+ cy = in_boundary->y + (cy - in_boundary->y) / input_scale;
+
+ /*Warping*/
+ if (warp)
+ {
+ double dx = cx - in_boundary->x;
+ double dy = cy - in_boundary->y;
+
+ double width_overrun = ceil ((dx) / (in_boundary->width)) ;
+ double height_overrun = ceil ((dy) / (in_boundary->height));
+
+ if (cx <= (in_boundary->x))
+ {
+ if ( fabs (fmod (width_overrun, 2)) < 1.0)
+ cx = in_boundary->x - fmod (dx, in_boundary->width);
+ else
+ cx = in_boundary->x + in_boundary->width + fmod (dx, in_boundary->width);
+ }
+
+ if (cy <= (in_boundary->y))
+ {
+ if ( fabs (fmod (height_overrun, 2)) < 1.0)
+ cy = in_boundary->y + fmod (dy, in_boundary->height);
+ else
+ cy = in_boundary->y + in_boundary->height - fmod (dy, in_boundary->height);
+ }
+
+ if (cx >= (in_boundary->x + in_boundary->width))
+ {
+ if ( fabs (fmod (width_overrun, 2)) < 1.0)
+ cx = in_boundary->x + in_boundary->width - fmod (dx, in_boundary->width);
+ else
+ cx = in_boundary->x + fmod (dx, in_boundary->width);
+ }
+
+ if (cy >= (in_boundary->y + in_boundary->height))
+ {
+ if ( fabs (fmod (height_overrun, 2)) < 1.0)
+ cy = in_boundary->y + in_boundary->height - fmod (dy, in_boundary->height);
+ else
+ cy = in_boundary->y + fmod (dy, in_boundary->height);
+ }
+ }
+ else /* cliping */
+ {
+ if (cx < boundary->x)
+ cx = 0;
+ if (cy < boundary->x)
+ cy = 0;
+
+ if (cx >= boundary->width)
+ cx = boundary->width - 1;
+ if (cy >= boundary->height)
+ cy = boundary->height -1;
+ }
+
+
+ /* Top */
+#ifdef DO_NOT_USE_BUFFER_SAMPLE
+
+ if (cx >= 0.0)
+ ix = (int) cx;
+ else
+ ix = -((int) -cx + 1);
+
+ if (cy >= 0.0)
+ iy = (int) cy;
+ else
+ iy = -((int) -cy + 1);
+
+ spx_pos = (iy * boundary->width + ix) * 4;
+#endif
+
+
+
+#ifndef DO_NOT_USE_BUFFER_SAMPLE
+ gegl_buffer_sample (src, cx, cy, 1.0, &dst_buf[(row * roi->width + col) * 4], format, GEGL_INTERPOLATION_LINEAR);
+#endif
+
+#ifdef DO_NOT_USE_BUFFER_SAMPLE
+ dst_buf[dpx_pos] = src_buf[spx_pos];
+ dst_buf[dpx_pos + 1] = src_buf[spx_pos + 1];
+ dst_buf[dpx_pos + 2] = src_buf[spx_pos + 2];
+ dst_buf[dpx_pos + 3] = src_buf[spx_pos + 3];
+#endif
+
+ } /* for */
+ } /* for */
+
+ gegl_buffer_sample_cleanup(src);
+
+ /* Store dst pixels. */
+ gegl_buffer_set (dst, roi, format, dst_buf, GEGL_AUTO_ROWSTRIDE);
+
+ gegl_buffer_flush(dst);
+
+ /* Free acquired storage. */
+#ifdef DO_NOT_USE_BUFFER_SAMPLE
+ g_free (src_buf);
+#endif
+ g_free (dst_buf);
+
+}
+
+/*****************************************************************************/
+
+static GeglRectangle
+get_effective_area (GeglOperation *operation)
+{
+ GeglRectangle result = {0,0,0,0};
+ GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input");
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ gdouble xt = o->trim_x * in_rect->width;
+ gdouble yt = o->trim_y * in_rect->height;
+
+ gegl_rectangle_copy(&result, in_rect);
+
+ /*Applying trims*/
+
+ result.x = result.x + xt;
+ result.y = result.y + yt;
+ result.width = result.width - xt;
+ result.height = result.height - yt;
+
+ return result;
+}
+
+/* Compute the region for which this operation is defined.
+ */
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+ GeglRectangle result = {0,0,0,0};
+ GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input");
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+
+ if (!in_rect){
+ return result;
+ }
+
+ if (o->clip) {
+ gegl_rectangle_copy(&result, in_rect);
+ }
+ else {
+ result.x = in_rect->x;
+ result.y = in_rect->y;
+ result.width = result.height = sqrt (in_rect->width * in_rect->width + in_rect->height * in_rect->height) * MAX ((o->o_x + 1), (o->o_y + 1)) * 2;
+ }
+
+ result.width = result.width * o->output_scale;
+ result.height = result.height * o->output_scale;
+
+ #ifdef TRACE
+ g_warning ("< get_bounding_box result = %dx%d+%d+%d", result.width, result.height, result.x, result.y);
+ #endif
+ return result;
+}
+
+/* Compute the input rectangle required to compute the specified region of interest (roi).
+ */
+static GeglRectangle
+get_required_for_output (GeglOperation *operation,
+ const gchar *input_pad,
+ const GeglRectangle *roi)
+{
+ GeglRectangle result = get_effective_area (operation);
+
+ #ifdef TRACE
+ g_warning ("> get_required_for_output src=%dx%d+%d+%d", result.width, result.height, result.x, result.y);
+ if (roi)
+ g_warning (" ROI == %dx%d+%d+%d", roi->width, roi->height, roi->x, roi->y);
+ #endif
+
+ return result;
+}
+
+/* Specify the input and output buffer formats.
+ */
+static void
+prepare (GeglOperation *operation)
+{
+ gegl_operation_set_format (operation, "input", babl_format ("RaGaBaA float"));
+ gegl_operation_set_format (operation, "output", babl_format ("RaGaBaA float"));
+}
+
+/* Perform the specified operation.
+ */
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *result)
+{
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ GeglRectangle boundary = gegl_operation_get_bounding_box (operation);
+ GeglRectangle eff_boundary = get_effective_area (operation);
+ Babl *format = babl_format ("RaGaBaA float");
+
+#ifdef DO_NOT_USE_BUFFER_SAMPLE
+ g_warning ("NOT USING BUFFER SAMPLE!");
+#endif
+ apply_mirror (o->m_angle,
+ o->r_angle,
+ o->n_segs,
+ o->c_x * boundary.width,
+ o->c_y * boundary.height,
+ o->o_x * (eff_boundary.width - eff_boundary.x) + eff_boundary.x,
+ o->o_y * (eff_boundary.height - eff_boundary.y) + eff_boundary.y,
+ o->input_scale / 100,
+ o->clip,
+ o->warp,
+ format,
+ input,
+ &eff_boundary,
+ output,
+ &boundary,
+ result);
+ return TRUE;
+}
+
+
+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->prepare = prepare;
+ operation_class->get_bounding_box = get_bounding_box;
+ operation_class->get_required_for_output = get_required_for_output;
+
+ operation_class->name = "gegl:mirrors";
+ operation_class->categories = "blur";
+ operation_class->description =
+ _("Applies mirroring effect on the image.");
+}
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]