[gegl] move mirrors op out of workshop



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]