fractal-explorer.c 13.1 KB
Newer Older
Kevin Cozens's avatar
Kevin Cozens committed
1 2
/* This file is an image processing operation for GEGL.
 *
3 4 5 6
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
Kevin Cozens's avatar
Kevin Cozens committed
7
 *
8
 * This program is distributed in the hope that it will be useful,
Kevin Cozens's avatar
Kevin Cozens committed
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 11 12 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
14
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
Kevin Cozens's avatar
Kevin Cozens committed
15 16
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
Kevin Cozens's avatar
Kevin Cozens committed
18 19 20 21
 *
 * Copyright 2006 Kevin Cozens <kcozens@cvs.gnome.org>
 */

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

Kevin Cozens's avatar
Kevin Cozens committed
25 26
#define MAXNCOLORS 8192

27 28
#ifdef GEGL_PROPERTIES

29
enum_start (gegl_fractal_explorer_type)
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
  enum_value (GEGL_FRACTAL_EXPLORER_TYPE_MANDELBROT, "mandelbrot",
              N_("Mandelbrot"))
  enum_value (GEGL_FRACTAL_EXPLORER_TYPE_JULIA,      "julia",
              N_("Julia"))
  enum_value (GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_1, "barnsley-1",
              N_("Barnsley 1"))
  enum_value (GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_2, "barnsley-2",
              N_("Barnsley 2"))
  enum_value (GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_3, "barnsley-3",
              N_("Barnsley 3"))
  enum_value (GEGL_FRACTAL_EXPLORER_TYPE_SPIDER,     "spider",
              N_("Spider"))
  enum_value (GEGL_FRACTAL_EXPLORER_TYPE_MAN_O_WAR,  "man-o-war",
              N_("Man O War"))
  enum_value (GEGL_FRACTAL_EXPLORER_TYPE_LAMBDA,     "lambda",
              N_("Lambda"))
  enum_value (GEGL_FRACTAL_EXPLORER_TYPE_SIERPINSKI, "sierpinski",
              N_("Sierpinski"))
48
enum_end (GeglFractalExplorerType)
49

50
property_enum (fractaltype, _("Fractal type"),
51
    GeglFractalExplorerType, gegl_fractal_explorer_type,
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
    GEGL_FRACTAL_EXPLORER_TYPE_MANDELBROT)
    description (_("Type of a fractal"))

property_int (iter, _("Iterations"), 50)
    value_range (1, 1000)

property_double (zoom, _("Zoom"), 300.0)
    description (_("Zoom in the fractal space"))
    value_range (0.0000001, 10000000.0)
    ui_range    (0.0000001, 10000.0)
    ui_gamma    (1.5)

property_double (shiftx, _("Shift X"), 0.0)
    description (_("X shift in the fractal space"))
    ui_range    (-1000.0, 1000.0)

property_double (shifty, _("Shift Y"), 0.0)
    description (_("Y shift in the fractal space"))
    ui_range    (-1000.0, 1000.0)

property_double (cx, _("CX"), -0.75)
    description (_("CX (No effect in Mandelbrot and Sierpinski)"))
    value_range (-2.5, 2.5)
75 76
    ui_meta     ("visible", "! fractaltype {mandelbrot, sierpinski}")
    ui_meta     ("description", "''")
77 78 79 80

property_double (cy, _("CY"), -0.2)
    description (_("CY (No effect in Mandelbrot and Sierpinski)"))
    value_range (-2.5, 2.5)
81 82
    ui_meta     ("visible", "$cx.visible")
    ui_meta     ("description", "''")
83 84 85 86 87 88 89 90 91

property_double (redstretch, _("Red stretching factor"), 1.0)
    value_range (0.0, 1.0)

property_double (greenstretch, _("Green stretching factor"), 1.0)
    value_range (0.0, 1.0)

property_double (bluestretch, _("Blue stretching factor"), 1.0)
    value_range (0.0, 1.0)
92

93
enum_start (gegl_fractal_explorer_mode)
94 95 96
  enum_value (GEGL_FRACTAL_EXPLORER_MODE_SIN , "sine",   N_("Sine"))
  enum_value (GEGL_FRACTAL_EXPLORER_MODE_COS , "cosine", N_("Cosine"))
  enum_value (GEGL_FRACTAL_EXPLORER_MODE_NONE, "none",   N_("None"))
97
enum_end (GeglFractalExplorerMode)
98

99
property_enum (redmode, _("Red application mode"),
100
    GeglFractalExplorerMode, gegl_fractal_explorer_mode,
101
    GEGL_FRACTAL_EXPLORER_MODE_COS)
102

103
property_enum (greenmode, _("Green application mode"),
104
    GeglFractalExplorerMode, gegl_fractal_explorer_mode,
105
    GEGL_FRACTAL_EXPLORER_MODE_COS)
106

107
property_enum (bluemode, _("Blue application mode"),
108
    GeglFractalExplorerMode, gegl_fractal_explorer_mode,
109
    GEGL_FRACTAL_EXPLORER_MODE_SIN)
110

111 112 113
property_boolean (redinvert  , _("Red inversion")  , FALSE)
property_boolean (greeninvert, _("Green inversion"), FALSE)
property_boolean (blueinvert , _("Blue inversion") , FALSE)
114

115 116
property_int    (ncolors, _("Number of colors"), 256)
    value_range (2, MAXNCOLORS)
117

118
property_boolean (useloglog, _("Loglog smoothing"), FALSE)
Kevin Cozens's avatar
Kevin Cozens committed
119 120 121

#else

122
#define GEGL_OP_POINT_RENDER
123
#define GEGL_OP_NAME     fractal_explorer
124
#define GEGL_OP_C_SOURCE fractal-explorer.c
Kevin Cozens's avatar
Kevin Cozens committed
125

126
#include "gegl-op.h"
Kevin Cozens's avatar
Kevin Cozens committed
127 128 129 130
#include <math.h>
#include <stdio.h>

typedef struct
131
{
132 133 134 135
  gfloat r, g, b;
} gfloatRGB;

typedef gfloatRGB  clrmap[MAXNCOLORS];
Kevin Cozens's avatar
Kevin Cozens committed
136

137
static void
138
make_color_map (GeglProperties *o, clrmap colormap)
139 140 141 142 143 144 145 146 147 148 149 150 151
{
  gint     i;
  gfloat   r;
  gfloat   gr;
  gfloat   bl;

  for (i = 0; i < o->ncolors; i++)
    {
      double x = (i*2.0) / o->ncolors;
      r = gr = bl = 0;

      switch (o->redmode)
        {
152
        case GEGL_FRACTAL_EXPLORER_MODE_SIN:
153 154
          r = 0.5 * o->redstretch *(1.0 + sin((x - 1) * G_PI));
          break;
155
        case GEGL_FRACTAL_EXPLORER_MODE_COS:
156 157
          r = 0.5 * o->redstretch *(1.0 + cos((x - 1) * G_PI));
          break;
158
        case GEGL_FRACTAL_EXPLORER_MODE_NONE:
159 160 161 162 163
          r = 0.5 * o->redstretch * x;
          break;
        default:
          break;
        }
Kevin Cozens's avatar
Kevin Cozens committed
164

165 166
      switch (o->greenmode)
        {
167
        case GEGL_FRACTAL_EXPLORER_MODE_SIN:
168 169
          gr = 0.5 * o->greenstretch *(1.0 + sin((x - 1) * G_PI));
          break;
170
        case GEGL_FRACTAL_EXPLORER_MODE_COS:
171 172
          gr = 0.5 * o->greenstretch *(1.0 + cos((x - 1) * G_PI));
          break;
173
        case GEGL_FRACTAL_EXPLORER_MODE_NONE:
174 175 176 177 178 179 180 181
          gr = 0.5 * o->greenstretch * x;
          break;
        default:
          break;
        }

      switch (o->bluemode)
        {
182
        case GEGL_FRACTAL_EXPLORER_MODE_SIN:
183 184
          bl = 0.5 * o->bluestretch * (1.0 + sin ((x - 1) * G_PI));
          break;
185
        case GEGL_FRACTAL_EXPLORER_MODE_COS:
186 187
          bl = 0.5 * o->bluestretch * (1.0 + cos ((x - 1) * G_PI));
          break;
188
        case GEGL_FRACTAL_EXPLORER_MODE_NONE:
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
          bl = 0.5 * o->bluestretch * x;
          break;
        default:
          break;
        }

      if (o->redinvert)
        r = 1.0 - r;

      if (o->greeninvert)
        gr = 1.0 - gr;

      if (o->blueinvert)
        bl = 1.0 - bl;

      colormap[i].r = r;
      colormap[i].g = gr;
      colormap[i].b = bl;
    }
}
Kevin Cozens's avatar
Kevin Cozens committed
209 210

static void
211
prepare (GeglOperation *operation)
Kevin Cozens's avatar
Kevin Cozens committed
212
{
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
  gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
}

static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
  return gegl_rectangle_infinite_plane ();
}

static gboolean
process (GeglOperation       *operation,
         void                *out_buf,
         glong                n_pixels,
         const GeglRectangle *roi,
         gint                 level)
{
229
  GeglProperties *o = GEGL_PROPERTIES (operation);
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
  gfloat     *out_pixel = out_buf;
  gint        pixelx = roi->x; /* initial x                   */
  gint        pixely = roi->y; /*           and y coordinates */
  gdouble     x,y;             /* coordinate in fractal space */
  gdouble     a,b;             /* main fractal variable in iteration loop */
  gdouble     nexta;
  gdouble     tmpx, tmpy;
  gdouble     foldxinitx;
  gdouble     foldxinity;
  gdouble     foldyinitx;
  gdouble     foldyinity;
  gdouble     tempsqrx;
  gdouble     tempsqry;
  gdouble     olda,oldb;
  gdouble     adjust = 0.0;
  gint        counter;         /* iteration counter */
  gdouble     log2 = log (2.0);
  gint        color;

  clrmap  colormap;

  make_color_map (o, colormap);

  while (n_pixels--)
Kevin Cozens's avatar
Kevin Cozens committed
254
    {
255 256
      x = (pixelx + o->shiftx) / o->zoom;
      y = (pixely + o->shifty) / o->zoom;
257

258
      switch (o->fractaltype)
Kevin Cozens's avatar
Kevin Cozens committed
259
        {
260
        case GEGL_FRACTAL_EXPLORER_TYPE_MANDELBROT:
261
          a = b = 0;
262 263 264
          tmpx = tmpy = 0;
          break;
        default:
265 266
          tmpx = a = x;
          tmpy = b = y;
Kevin Cozens's avatar
Kevin Cozens committed
267 268
        }

269
      for (counter = 0; counter < o->iter; counter++)
Kevin Cozens's avatar
Kevin Cozens committed
270
        {
271 272
          olda = a;
          oldb = b;
Kevin Cozens's avatar
Kevin Cozens committed
273

274
          switch (o->fractaltype)
Kevin Cozens's avatar
Kevin Cozens committed
275
            {
276
            case GEGL_FRACTAL_EXPLORER_TYPE_MANDELBROT:
277 278
              nexta = a * a - b * b + x;
              b = 2.0 * a * b + y;
Kevin Cozens's avatar
Kevin Cozens committed
279 280
              break;

281
            case GEGL_FRACTAL_EXPLORER_TYPE_JULIA:
282 283
              nexta = a * a - b * b + o->cx;
              b = 2.0 * a * b + o->cy;
Kevin Cozens's avatar
Kevin Cozens committed
284 285
              break;

286
            case GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_1:
287 288 289 290
              foldxinitx = olda * o->cx;
              foldyinity = oldb * o->cy;
              foldxinity = olda * o->cy;
              foldyinitx = oldb * o->cx;
Kevin Cozens's avatar
Kevin Cozens committed
291
              /* orbit calculation */
292
              if (olda >= 0)
Kevin Cozens's avatar
Kevin Cozens committed
293
                {
294 295
                  nexta = (foldxinitx - o->cx - foldyinity);
                  b  = (foldyinitx - o->cy + foldxinity);
Kevin Cozens's avatar
Kevin Cozens committed
296 297 298
                }
              else
                {
299 300
                  nexta = (foldxinitx + o->cx - foldyinity);
                  b  = (foldyinitx + o->cy + foldxinity);
Kevin Cozens's avatar
Kevin Cozens committed
301 302 303
                }
              break;

304
            case GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_2:
305 306 307 308
              foldxinitx = olda * o->cx;
              foldyinity = oldb * o->cy;
              foldxinity = olda * o->cy;
              foldyinitx = oldb * o->cx;
Kevin Cozens's avatar
Kevin Cozens committed
309 310 311
              /* orbit calculation */
              if (foldxinity + foldyinitx >= 0)
                {
312 313
                  nexta = foldxinitx - o->cx - foldyinity;
                  b  = foldyinitx - o->cy + foldxinity;
Kevin Cozens's avatar
Kevin Cozens committed
314 315 316
                }
              else
                {
317 318
                  nexta = foldxinitx + o->cx - foldyinity;
                  b  = foldyinitx + o->cy + foldxinity;
Kevin Cozens's avatar
Kevin Cozens committed
319 320 321
                }
              break;

322
            case GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_3:
323 324 325
              foldxinitx  = olda * olda;
              foldyinity  = oldb * oldb;
              foldxinity  = olda * oldb;
Kevin Cozens's avatar
Kevin Cozens committed
326
              /* orbit calculation */
327
              if (olda > 0)
Kevin Cozens's avatar
Kevin Cozens committed
328
                {
329 330
                  nexta = foldxinitx - foldyinity - 1.0;
                  b  = foldxinity * 2;
Kevin Cozens's avatar
Kevin Cozens committed
331 332 333
                }
              else
                {
334 335 336
                  nexta = foldxinitx - foldyinity -1.0 + o->cx * olda;
                  b  = foldxinity * 2;
                  b += o->cy * olda;
Kevin Cozens's avatar
Kevin Cozens committed
337 338 339
                }
              break;

340
            case GEGL_FRACTAL_EXPLORER_TYPE_SPIDER:
Kevin Cozens's avatar
Kevin Cozens committed
341
              /* { c=z=pixel: z=z*z+c; c=c/2+z, |z|<=4 } */
342 343 344 345
              nexta = a*a - b*b + tmpx + o->cx;
              b = 2 * olda * oldb + tmpy + o->cy;
              tmpx = tmpx/2 + nexta;
              tmpy = tmpy/2 + b;
Kevin Cozens's avatar
Kevin Cozens committed
346 347
              break;

348
            case GEGL_FRACTAL_EXPLORER_TYPE_MAN_O_WAR:
349 350 351 352
              nexta = a*a - b*b + tmpx + o->cx;
              b = 2.0 * a * b + tmpy + o->cy;
              tmpx = olda;
              tmpy = oldb;
Kevin Cozens's avatar
Kevin Cozens committed
353 354
              break;

355
            case GEGL_FRACTAL_EXPLORER_TYPE_LAMBDA:
356 357 358 359 360 361 362
              tempsqrx = a * a;
              tempsqry = b * b;
              tempsqrx = olda - tempsqrx + tempsqry;
              tempsqry = -(oldb * olda);
              tempsqry += tempsqry + oldb;
              nexta = o->cx * tempsqrx - o->cy * tempsqry;
              b = o->cx * tempsqry + o->cy * tempsqrx;
Kevin Cozens's avatar
Kevin Cozens committed
363 364
              break;

365
            case GEGL_FRACTAL_EXPLORER_TYPE_SIERPINSKI:
366 367 368 369 370 371
              nexta = olda + olda;
              b = oldb + oldb;
              if (oldb > .5)
                b = b - 1;
              else if (olda > .5)
                nexta = nexta - 1;
Kevin Cozens's avatar
Kevin Cozens committed
372 373 374
              break;

            default:
375 376
              g_warning (_("Unsupported fractal type: %d"), o->fractaltype);
              return FALSE;
Kevin Cozens's avatar
Kevin Cozens committed
377 378
            }

379
          a = nexta;
Kevin Cozens's avatar
Kevin Cozens committed
380

381
          if (((a * a) + (b * b)) >= 4.0)
Kevin Cozens's avatar
Kevin Cozens committed
382 383 384
            break;
        }

385
      if (o->useloglog)
Kevin Cozens's avatar
Kevin Cozens committed
386
        {
387
          gdouble modulus_square = (a * a) + (b * b);
Kevin Cozens's avatar
Kevin Cozens committed
388 389 390 391 392 393 394

          if (modulus_square > (G_E * G_E))
              adjust = log (log (modulus_square) / 2.0) / log2;
          else
              adjust = 0.0;
        }

395
      color = (gint) (((counter - adjust) * (o->ncolors - 1)) / o->iter);
Kevin Cozens's avatar
Kevin Cozens committed
396

397 398 399 400
      out_pixel[0] = colormap[color].r;
      out_pixel[1] = colormap[color].g;
      out_pixel[2] = colormap[color].b;
      out_pixel[3] = 1.0;
Kevin Cozens's avatar
Kevin Cozens committed
401

402
      out_pixel += 4;
Kevin Cozens's avatar
Kevin Cozens committed
403

404 405 406
      /* update x and y coordinates */
      pixelx++;
      if (pixelx>=roi->x + roi->width)
Kevin Cozens's avatar
Kevin Cozens committed
407
        {
408 409
          pixelx=roi->x;
          pixely++;
Kevin Cozens's avatar
Kevin Cozens committed
410 411
        }
    }
412 413 414 415 416 417

  return TRUE;
}


static void
418
gegl_op_class_init (GeglOpClass *klass)
419
{
420 421
  GeglOperationClass            *operation_class;
  GeglOperationPointRenderClass *point_render_class;
422

423 424
  operation_class    = GEGL_OPERATION_CLASS (klass);
  point_render_class = GEGL_OPERATION_POINT_RENDER_CLASS (klass);
425

426
  point_render_class->process = process;
427
  operation_class->get_bounding_box = get_bounding_box;
428 429
  operation_class->prepare = prepare;

430
  gegl_operation_class_set_keys (operation_class,
431 432 433
    "name",               "gegl:fractal-explorer",
    "title",              _("Fractal Explorer"),
    "categories",         "render:fractal",
434
    "reference-hash",     "fd6c1f91d1a44d67e229754958627e7e",
435
    "position-dependent", "true",
436 437
    "license",            "GPL3+",
    "description",        _("Rendering of multiple different fractal systems, with configurable coloring options."),
438
    NULL);
439 440
}

Kevin Cozens's avatar
Kevin Cozens committed
441
#endif