fractal-trace.c 7.92 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* 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/>.
 *
16 17
 * Copyright (C) 1997 Hirotsuna Mizuno <s1041150@u-aizu.ac.jp>
 * Copyright (C) 2011 Robert Sasu <sasu.robert@gmail.com>
18 19 20 21 22
 */

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

23
#ifdef GEGL_PROPERTIES
24

25
enum_start (gegl_fractal_trace_type)
26 27
  enum_value (GEGL_FRACTAL_TRACE_TYPE_MANDELBROT, "mandelbrot", N_("Mandelbrot"))
  enum_value (GEGL_FRACTAL_TRACE_TYPE_JULIA,      "julia",      N_("Julia"))
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
enum_end (GeglFractalTraceType)

property_enum (fractal, _("Fractal type"),
               GeglFractalTraceType, gegl_fractal_trace_type,
               GEGL_FRACTAL_TRACE_TYPE_MANDELBROT)

property_double (X1, _("X1"), -1.0)
  description   (_("X1 value, position"))
  value_range   (-50.0, 50.0)

property_double (X2, _("X2"), 0.50)
  description   (_("X2 value, position"))
  value_range   (-50.0, 50.0)

property_double (Y1, _("Y1"), -1.0)
  description   (_("Y1 value, position"))
  value_range   (-50.0, 50.0)

property_double (Y2, _("Y2"), 1.0)
47
  description   (_("Y2 value, position"))
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
  value_range   (-50.0, 50.0)

property_double (JX, _("JX"), 0.5)
  description (_("Julia seed X value, position"))
  value_range   (-50.0, 50.0)

property_double (JY, _("JY"), 0.5)
  description (_("Julia seed Y value, position"))
  value_range   (-50.0, 50.0)

property_int    (depth, _("Depth"), 3)
  value_range   (1, 65536)

property_double (bailout, _("Bailout length"), G_MAXDOUBLE)
  value_range   (0.0, G_MAXDOUBLE)

property_enum   (abyss_policy, _("Abyss policy"),
                   GeglAbyssPolicy, gegl_abyss_policy, GEGL_ABYSS_LOOP)
  description   (_("How to deal with pixels outside of the input buffer"))
67

68
#else
69

70
#define GEGL_OP_FILTER
71
#define GEGL_OP_C_SOURCE fractal-trace.c
72

73
#include "gegl-op.h"
74 75
#include <math.h>

76 77
static void
prepare (GeglOperation *operation)
78
{
79
  gegl_operation_set_format (operation, "input",  babl_format ("RGBA float"));
80
  gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
81
}
82 83 84 85 86 87 88 89

static void
julia (gdouble  x,
       gdouble  y,
       gdouble  jx,
       gdouble  jy,
       gdouble *u,
       gdouble *v,
90 91
       gint     depth,
       gdouble  bailout2)
92 93 94 95 96 97 98 99 100 101 102 103 104 105
{
  gint    i;
  gdouble xx = x;
  gdouble yy = y;

  for (i = 0; i < depth; i++)
    {
      gdouble x2, y2, tmp;

      x2 = xx * xx;
      y2 = yy * yy;
      tmp = x2 - y2 + jx;
      yy  = 2 * xx * yy + jy;
      xx  = tmp;
106 107

      if ((x2 + y2) > bailout2)
108
        break;
109 110 111 112 113 114 115
    }

  *u = xx;
  *v = yy;
}

static void
116
fractaltrace (GeglBuffer            *input,
117
              GeglSampler           *sampler,
118 119 120
              const GeglRectangle   *picture,
              gfloat                *dst_buf,
              const GeglRectangle   *roi,
121
              GeglProperties        *o,
122
              gint                   y,
123 124 125
              GeglFractalTraceType   fractal_type,
              const Babl            *format,
              gint                   level)
126
{
127 128 129 130 131 132 133
  GeglMatrix2  scale;        /* a matrix indicating scaling factors around the
                                current center pixel.
                              */
  gint         x, i, offset;
  gdouble      scale_x, scale_y;
  gdouble      bailout2;
  gfloat       dest[4];
134

135 136
  scale_x = (o->X2 - o->X1) / picture->width;
  scale_y = (o->Y2 - o->Y1) / picture->height;
137

138 139
  bailout2 = o->bailout * o->bailout;

140 141 142 143
  offset = (y - roi->y) * roi->width * 4;

  for (x = roi->x; x < roi->x + roi->width; x++)
    {
144 145
      gdouble cx, cy;
      gdouble px, py;
146
      dest[1] = dest[2] = dest[3] = dest[0] = 0.0;
147

148
      switch (fractal_type)
149
        {
150
        case GEGL_FRACTAL_TRACE_TYPE_JULIA:
151 152 153 154
#define gegl_unmap(u,v,ud,vd) {                                         \
            gdouble rx, ry;                                             \
            cx = o->X1 + ((u) - picture->x) * scale_x;                  \
            cy = o->Y1 + ((v) - picture->y) * scale_y;                  \
155 156 157 158 159 160
            julia (cx, cy, o->JX, o->JY, &rx, &ry, o->depth, bailout2); \
            ud = (rx - o->X1) / scale_x + picture->x;                   \
            vd = (ry - o->Y1) / scale_y + picture->y;                   \
          }
        gegl_sampler_compute_scale (scale, x, y);
        gegl_unmap(x,y,px,py);
161
#undef gegl_unmap
162
        break;
163

164
        case GEGL_FRACTAL_TRACE_TYPE_MANDELBROT:
165
#define gegl_unmap(u,v,ud,vd) {                                     \
166 167 168 169 170 171 172 173 174
            gdouble rx, ry;                                         \
            cx = o->X1 + ((u) - picture->x) * scale_x;              \
            cy = o->Y1 + ((v) - picture->y) * scale_y;              \
            julia (cx, cy, cx, cy, &rx, &ry, o->depth, bailout2);   \
            ud = (rx - o->X1) / scale_x + picture->x;               \
            vd = (ry - o->Y1) / scale_y + picture->y;               \
          }
        gegl_sampler_compute_scale (scale, x, y);
        gegl_unmap(x,y,px,py);
175
#undef gegl_unmap
176
        break;
177

178 179 180 181
        default:
          g_error (_("Unsupported fractal type"));
        }

182
      gegl_sampler_get (sampler, px, py, &scale, dest, o->abyss_policy);
183 184 185

      for (i = 0; i < 4; i++)
        dst_buf[offset++] = dest[i];
186 187 188
    }
}

189
static gboolean
190 191 192
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
193 194
         const GeglRectangle *result,
         gint                 level)
195
{
196
  GeglProperties    *o = GEGL_PROPERTIES (operation);
197
  GeglRectangle  boundary;
198
  const Babl    *format;
199
  GeglSampler   *sampler;
200 201 202 203 204 205
  gfloat        *dst_buf;
  gint           y;

  boundary = gegl_operation_get_bounding_box (operation);

  format = babl_format ("RGBA float");
206
  dst_buf = g_new0 (gfloat, result->width * result->height * 4);
207
  sampler = gegl_buffer_sampler_new_at_level (input, format, GEGL_SAMPLER_NOHALO, level);
208 209

  for (y = result->y; y < result->y + result->height; y++)
210
    fractaltrace (input, sampler, &boundary, dst_buf, result, o, y, o->fractal, format, level);
211

212
  gegl_buffer_set (output, result, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE);
213
  g_object_unref (sampler);
214 215 216

  g_free (dst_buf);

217
  gegl_buffer_sample_cleanup (input);
218

219 220 221 222 223 224
  return TRUE;
}

static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
225
  GeglRectangle  result = { 0, 0, 0, 0 };
226
  GeglRectangle *in_rect;
227

228
  in_rect = gegl_operation_source_get_bounding_box (operation, "input");
229
  if (!in_rect)
230
    return result;
231

232
  return *in_rect;
233 234 235 236 237 238 239
}

static GeglRectangle
get_required_for_output (GeglOperation       *operation,
                         const gchar         *input_pad,
                         const GeglRectangle *roi)
{
240
  return get_bounding_box (operation);
241 242
}

243
static void
244
gegl_op_class_init (GeglOpClass *klass)
245 246 247 248 249 250 251 252
{
  GeglOperationClass       *operation_class;
  GeglOperationFilterClass *filter_class;

  operation_class = GEGL_OPERATION_CLASS (klass);
  filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);

  operation_class->prepare                 = prepare;
253
  operation_class->get_bounding_box        = get_bounding_box;
254 255
  operation_class->get_required_for_output = get_required_for_output;

256 257
  filter_class->process                    = process;

258
  gegl_operation_class_set_keys (operation_class,
259
    "name",               "gegl:fractal-trace",
260
    "title",              _("Fractal Trace"),
261 262
    "position-dependent", "true",
    "categories",         "map",
263
    "license",            "GPL3+",
264
    "description", _("Transform the image with the fractals"),
265
    NULL);
266 267 268
}

#endif