It is currently Sat Aug 01, 2026 12:43 pm


All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: GEGL - Ray Distortion (Grok made)
PostPosted: Thu May 22, 2025 10:50 pm  (#1) 
Offline
GimpChat Member
User avatar

Joined: Oct 31, 2020
Posts: 2013
Grok made a GEGL plugin inspired by Pixelitor's "Radial Waves" but simpler. It still does a very similar effect. Notice the preview image showing it distorting a gradient.

Attachment:
raydistortion_grok.png
raydistortion_grok.png [ 241.54 KiB | Viewed 3007 times ]



I did not make this plugin. Grok did, I just instructed it. I have no idea how to write math like this. Explained simply this plugin is like GEGL Waves (gegl:waves) but it uses a uneven star shape instead of circular water ripples. In theory it could be done with other shapes too

Attachment:
linux_binaries_gegl_plugin.zip [7.36 KiB]
Downloaded 84 times


Attachment:
windows_binaries_gegl_plugin.zip [42.29 KiB]
Downloaded 293 times


Code here

/* 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 <https://www.gnu.org/licenses/>.
*
* Copyright 2006 Øyvind Kolås <[email protected]>
* 2025 Grok and DeepSeek with Beaver's help
*/

#include "config.h"
#include <glib/gi18n-lib.h>
#include <gegl.h>
#include <gegl-plugin.h>
#include <math.h>

#ifdef GEGL_PROPERTIES

property_double (center_x, _("Center X"), 0.5)
    description (_("Horizontal center of the effect (relative to image width, 0.0 to 1.0)"))
    value_range (0.0, 1.0)
    ui_meta ("unit", "relative-coordinate")
    ui_meta ("direction", "x")

property_double (center_y, _("Center Y"), 0.5)
    description (_("Vertical center of the effect (relative to image height, 0.0 to 1.0)"))
    value_range (0.0, 1.0)
    ui_meta ("unit", "relative-coordinate")
    ui_meta ("direction", "y")

property_int (angular_division, _("Star Points"), 30)
    description (_("Number of points in the uneven star shape for the ray distortion"))
    value_range (6, 50)

property_double (wavelength, _("Ray Length"), 60.0)
    description (_("Length of the rays in pixels"))
    value_range (1.0, 200.0)

property_double (amplitude, _("Ray Intensity"), 10.0)
    description (_("Strength of the rays in pixels"))
    value_range (0.0, 100.0)

property_double (phase, _("Phase"), 0.0)
    description (_("Phase shift of the effect in degrees"))
    value_range (0.0, 360.0)
    ui_meta ("unit", "degree")

#else

#define GEGL_OP_FILTER
#define GEGL_OP_NAME     raydistortion
#define GEGL_OP_C_SOURCE raydis.c

#include "gegl-op.h"

static void prepare (GeglOperation *operation)
{
  const Babl *format = babl_format ("RGBA float");
  gegl_operation_set_format (operation, "input", format);
  gegl_operation_set_format (operation, "output", format);
}

static GeglRectangle get_bounding_box (GeglOperation *operation)
{
  GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input");
  if (!in_rect)
    return gegl_rectangle_infinite_plane ();
  return *in_rect;
}

static GeglRectangle get_required_for_output (GeglOperation *operation,
                                              const gchar *input_pad,
                                              const GeglRectangle *roi)
{
  GeglProperties *o = GEGL_PROPERTIES (operation);
  GeglRectangle result = *roi;

  /* Expand the region of interest to account for the maximum displacement */
  gdouble max_displacement = o->amplitude;
  result.x -= max_displacement;
  result.y -= max_displacement;
  result.width += 2 * max_displacement;
  result.height += 2 * max_displacement;

  GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input");
  if (in_rect)
    gegl_rectangle_intersect (&result, &result, in_rect);

  return result;
}

/* Function to mirror coordinates within image bounds */
static gdouble mirror_coordinate (gdouble coord, gdouble min, gdouble max)
{
  gdouble range = max - min;
  if (range <= 0) return min; /* Avoid division by zero */

  /* Normalize coordinate to range [min, max) */
  gdouble normalized = coord - min;
  gdouble mod = fmod (normalized, 2 * range);

  /* Mirror by reflecting across the boundaries */
  if (mod < 0) mod += 2 * range; /* Handle negative values */
  if (mod < range)
    return min + mod; /* Forward direction */
  else
    return min + (2 * range - mod); /* Reflected direction */
}

static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglProperties *o = GEGL_PROPERTIES (operation);
  const Babl *format = babl_format ("RGBA float");
  gfloat *output_pixel = g_new (gfloat, 4);
  gdouble phase_rad = o->phase * G_PI / 180.0;

  /* Get image dimensions for relative coordinates and mirroring */
  GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input");
  gdouble center_x = o->center_x * in_rect->width + in_rect->x;
  gdouble center_y = o->center_y * in_rect->height + in_rect->y;
  gdouble min_x = in_rect->x;
  gdouble max_x = in_rect->x + in_rect->width;
  gdouble min_y = in_rect->y;
  gdouble max_y = in_rect->y + in_rect->height;

  for (gint y = result->y; y < result->y + result->height; y++)
  {
    for (gint x = result->x; x < result->x + result->width; x++)
    {
      /* Calculate radial distance and angle from center */
      gdouble dx = x - center_x;
      gdouble dy = y - center_y;
      gdouble distance = sqrt (dx * dx + dy * dy);
      gdouble theta = atan2 (dy, dx); /* Angle in radians */

      /* Compute ray distortion effect with uneven star shape */
      gdouble src_x = x;
      gdouble src_y = y;

      /* Create an uneven star shape using a deterministic method */
      gdouble base_points = o->angular_division;
      gdouble irregularity = sin (theta * base_points); /* Deterministic unevenness */
      gdouble varied_points = base_points + irregularity * 0.5; /* Reduced variation for subtlety */
      gdouble angular_segment = floor (theta * varied_points / (2.0 * G_PI)) * (2.0 * G_PI) / varied_points;
      gdouble segment_factor = cos (theta - angular_segment);
      segment_factor = pow (segment_factor, 4.0); /* Sharpen the rays for distortion effect */

      /* Apply the effect directly */
      gdouble displacement = sin (theta * base_points + phase_rad); /* Fluctuating based on angle */

      /* Apply displacement radially, scaled by amplitude and segment factor */
      gdouble dist = distance == 0.0 ? 1.0 : distance;
      gdouble offset = o->amplitude * displacement * segment_factor * (distance / o->wavelength);
      src_x = x - offset * (dx / dist); /* Pull pixels toward the center for ray distortion effect */
      src_y = y - offset * (dy / dist);

      /* Mirror coordinates to stay within image bounds */
      src_x = mirror_coordinate (src_x, min_x, max_x);
      src_y = mirror_coordinate (src_y, min_y, max_y);

      /* Sample input at the displaced coordinates */
      gegl_buffer_sample (input, src_x, src_y, NULL, output_pixel, format,
                          GEGL_SAMPLER_LINEAR, GEGL_ABYSS_CLAMP);

      GeglRectangle pixel_rect = {x, y, 1, 1};
      gegl_buffer_set (output, &pixel_rect, 0, format, output_pixel, GEGL_AUTO_ROWSTRIDE);
    }
  }

  g_free (output_pixel);
  return TRUE;
}

static void
gegl_op_class_init (GeglOpClass *klass)
{
  GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
  GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass);

  operation_class->prepare = prepare;
  operation_class->get_bounding_box = get_bounding_box;
  operation_class->get_required_for_output = get_required_for_output;
  filter_class->process = process;

  gegl_operation_class_set_keys (operation_class,
    "name",        "ai/lb:ray-distortion",
    "title",       _("Ray Distortion"),
    "reference-hash", "raydistortion2025",
    "description", _("Distort the image with uneven star rays"),
    "gimp:menu-path", "<Image>/Filters/AI GEGL",
    "gimp:menu-label", _("Ray Distortion..."),
    NULL);
}

#endif


LOCATION TO PUT BINARIES

Windows

C:\Users\(USERNAME)\AppData\Local\gegl-0.4\plug-ins

Linux

~/.local/share/gegl-0.4/plug-ins

Linux (Flatpak includes Chromebook)

~/.var/app/org.gimp.GIMP/data/gegl-0.4/plug-ins


Last edited by contrast_ on Thu May 22, 2025 10:53 pm, edited 1 time in total.

Share on Facebook Share on Twitter Share on Orkut Share on Digg Share on MySpace Share on Delicious Share on Technorati
Top
 Post subject: Re: GEGL - Ray Distortion (Grok made)
PostPosted: Thu May 22, 2025 10:52 pm  (#2) 
Offline
GimpChat Member
User avatar

Joined: Oct 31, 2020
Posts: 2013
Here is the code correctly zipped. I ran into the 3 attachment limit because I am too lazy to use imgur for the image.

Attachment:
code.zip [12.78 KiB]
Downloaded 69 times


Top
 Post subject: Re: GEGL - Ray Distortion (Grok made)
PostPosted: Sat May 24, 2025 4:01 pm  (#3) 
Offline
GimpChat Member

Joined: Sep 26, 2015
Posts: 74
You need to rename zip files to include plugin name. I think you have named another plugin the same name.


Top
 Post subject: Re: GEGL - Ray Distortion (Grok made)
PostPosted: Sat May 24, 2025 5:57 pm  (#4) 
Offline
GimpChat Member
User avatar

Joined: Oct 31, 2020
Posts: 2013
I just checked and no other plugin shares its name or code name.


Top
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]



* Login  



Powered by phpBB3 © phpBB Group