1 /* This file is an image processing operation for GEGL.
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * 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/>.
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/>.
18  *
19  * Copyright 2006 Kevin Cozens <kcozens@cvs.gnome.org>
20  */
21 
22 #include "config.h"
23 #include <glib/gi18n-lib.h>
24 
25 #define MAXNCOLORS 8192
26 
27 #ifdef GEGL_PROPERTIES
28 
29 enum_start (gegl_fractal_explorer_type)
30   enum_value (GEGL_FRACTAL_EXPLORER_TYPE_MANDELBROT, "mandelbrot",
31               N_("Mandelbrot"))
32   enum_value (GEGL_FRACTAL_EXPLORER_TYPE_JULIA,      "julia",
33               N_("Julia"))
34   enum_value (GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_1, "barnsley-1",
35               N_("Barnsley 1"))
36   enum_value (GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_2, "barnsley-2",
37               N_("Barnsley 2"))
38   enum_value (GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_3, "barnsley-3",
39               N_("Barnsley 3"))
40   enum_value (GEGL_FRACTAL_EXPLORER_TYPE_SPIDER,     "spider",
41               N_("Spider"))
42   enum_value (GEGL_FRACTAL_EXPLORER_TYPE_MAN_O_WAR,  "man-o-war",
43               N_("Man O War"))
44   enum_value (GEGL_FRACTAL_EXPLORER_TYPE_LAMBDA,     "lambda",
45               N_("Lambda"))
46   enum_value (GEGL_FRACTAL_EXPLORER_TYPE_SIERPINSKI, "sierpinski",
47               N_("Sierpinski"))
48 enum_end (GeglFractalExplorerType)
49 
50 property_enum (fractaltype, _("Fractal type"),
51     GeglFractalExplorerType, gegl_fractal_explorer_type,
52     GEGL_FRACTAL_EXPLORER_TYPE_MANDELBROT)
53     description (_("Type of a fractal"))
54 
55 property_int (iter, _("Iterations"), 50)
56     value_range (1, 1000)
57 
58 property_double (zoom, _("Zoom"), 300.0)
59     description (_("Zoom in the fractal space"))
60     value_range (0.0000001, 10000000.0)
61     ui_range    (0.0000001, 10000.0)
62     ui_gamma    (1.5)
63 
64 property_double (shiftx, _("Shift X"), 0.0)
65     description (_("X shift in the fractal space"))
66     ui_range    (-1000.0, 1000.0)
67 
68 property_double (shifty, _("Shift Y"), 0.0)
69     description (_("Y shift in the fractal space"))
70     ui_range    (-1000.0, 1000.0)
71 
72 property_double (cx, _("CX"), -0.75)
73     description (_("CX (No effect in Mandelbrot and Sierpinski)"))
74     value_range (-2.5, 2.5)
75     ui_meta     ("visible", "! fractaltype {mandelbrot, sierpinski}")
76     ui_meta     ("description", "''")
77 
78 property_double (cy, _("CY"), -0.2)
79     description (_("CY (No effect in Mandelbrot and Sierpinski)"))
80     value_range (-2.5, 2.5)
81     ui_meta     ("visible", "$cx.visible")
82     ui_meta     ("description", "''")
83 
84 property_double (redstretch, _("Red stretching factor"), 1.0)
85     value_range (0.0, 1.0)
86 
87 property_double (greenstretch, _("Green stretching factor"), 1.0)
88     value_range (0.0, 1.0)
89 
90 property_double (bluestretch, _("Blue stretching factor"), 1.0)
91     value_range (0.0, 1.0)
92 
93 enum_start (gegl_fractal_explorer_mode)
94   enum_value (GEGL_FRACTAL_EXPLORER_MODE_SIN , "sine",   N_("Sine"))
95   enum_value (GEGL_FRACTAL_EXPLORER_MODE_COS , "cosine", N_("Cosine"))
96   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 property_boolean (redinvert  , _("Red inversion")  , FALSE)
112 property_boolean (greeninvert, _("Green inversion"), FALSE)
113 property_boolean (blueinvert , _("Blue inversion") , FALSE)
114 
115 property_int    (ncolors, _("Number of colors"), 256)
116     value_range (2, MAXNCOLORS)
117 
118 property_boolean (useloglog, _("Loglog smoothing"), FALSE)
119 
120 #else
121 
122 #define GEGL_OP_POINT_RENDER
123 #define GEGL_OP_NAME     fractal_explorer
124 #define GEGL_OP_C_SOURCE fractal-explorer.c
125 
126 #include "gegl-op.h"
127 #include <stdio.h>
128 
129 typedef struct
130 {
131   gfloat r, g, b;
132 } gfloatRGB;
133 
134 typedef gfloatRGB  clrmap[MAXNCOLORS];
135 
136 static void
137 make_color_map (GeglProperties *o, clrmap colormap)
138 {
139   gint     i;
140   gfloat   r;
141   gfloat   gr;
142   gfloat   bl;
143 
144   for (i = 0; i < o->ncolors; i++)
145     {
146       double x = (i*2.0) / o->ncolors;
147       r = gr = bl = 0;
148 
149       switch (o->redmode)
150         {
151         case GEGL_FRACTAL_EXPLORER_MODE_SIN:
152           r = 0.5 * o->redstretch *(1.0 + sin((x - 1) * G_PI));
153           break;
154         case GEGL_FRACTAL_EXPLORER_MODE_COS:
155           r = 0.5 * o->redstretch *(1.0 + cos((x - 1) * G_PI));
156           break;
157         case GEGL_FRACTAL_EXPLORER_MODE_NONE:
158           r = 0.5 * o->redstretch * x;
159           break;
160         default:
161           break;
162         }
163 
164       switch (o->greenmode)
165         {
166         case GEGL_FRACTAL_EXPLORER_MODE_SIN:
167           gr = 0.5 * o->greenstretch *(1.0 + sin((x - 1) * G_PI));
168           break;
169         case GEGL_FRACTAL_EXPLORER_MODE_COS:
170           gr = 0.5 * o->greenstretch *(1.0 + cos((x - 1) * G_PI));
171           break;
172         case GEGL_FRACTAL_EXPLORER_MODE_NONE:
173           gr = 0.5 * o->greenstretch * x;
174           break;
175         default:
176           break;
177         }
178 
179       switch (o->bluemode)
180         {
181         case GEGL_FRACTAL_EXPLORER_MODE_SIN:
182           bl = 0.5 * o->bluestretch * (1.0 + sin ((x - 1) * G_PI));
183           break;
184         case GEGL_FRACTAL_EXPLORER_MODE_COS:
185           bl = 0.5 * o->bluestretch * (1.0 + cos ((x - 1) * G_PI));
186           break;
187         case GEGL_FRACTAL_EXPLORER_MODE_NONE:
188           bl = 0.5 * o->bluestretch * x;
189           break;
190         default:
191           break;
192         }
193 
194       if (o->redinvert)
195         r = 1.0 - r;
196 
197       if (o->greeninvert)
198         gr = 1.0 - gr;
199 
200       if (o->blueinvert)
201         bl = 1.0 - bl;
202 
203       colormap[i].r = r;
204       colormap[i].g = gr;
205       colormap[i].b = bl;
206     }
207 }
208 
209 static void
210 prepare (GeglOperation *operation)
211 {
212   gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
213 }
214 
215 static GeglRectangle
216 get_bounding_box (GeglOperation *operation)
217 {
218   return gegl_rectangle_infinite_plane ();
219 }
220 
221 static gboolean
222 process (GeglOperation       *operation,
223          void                *out_buf,
224          glong                n_pixels,
225          const GeglRectangle *roi,
226          gint                 level)
227 {
228   GeglProperties *o = GEGL_PROPERTIES (operation);
229   gfloat     *out_pixel = out_buf;
230   gint        pixelx = roi->x; /* initial x                   */
231   gint        pixely = roi->y; /*           and y coordinates */
232   gdouble     x,y;             /* coordinate in fractal space */
233   gdouble     a,b;             /* main fractal variable in iteration loop */
234   gdouble     nexta;
235   gdouble     tmpx, tmpy;
236   gdouble     foldxinitx;
237   gdouble     foldxinity;
238   gdouble     foldyinitx;
239   gdouble     foldyinity;
240   gdouble     tempsqrx;
241   gdouble     tempsqry;
242   gdouble     olda,oldb;
243   gdouble     adjust = 0.0;
244   gint        counter;         /* iteration counter */
245   gdouble     log2 = log (2.0);
246   gint        color;
247 
248   clrmap  colormap;
249 
250   make_color_map (o, colormap);
251 
252   while (n_pixels--)
253     {
254       x = (pixelx + o->shiftx) / o->zoom;
255       y = (pixely + o->shifty) / o->zoom;
256 
257       switch (o->fractaltype)
258         {
259         case GEGL_FRACTAL_EXPLORER_TYPE_MANDELBROT:
260           a = b = 0;
261           tmpx = tmpy = 0;
262           break;
263         default:
264           tmpx = a = x;
265           tmpy = b = y;
266         }
267 
268       for (counter = 0; counter < o->iter; counter++)
269         {
270           olda = a;
271           oldb = b;
272 
273           switch (o->fractaltype)
274             {
275             case GEGL_FRACTAL_EXPLORER_TYPE_MANDELBROT:
276               nexta = a * a - b * b + x;
277               b = 2.0 * a * b + y;
278               break;
279 
280             case GEGL_FRACTAL_EXPLORER_TYPE_JULIA:
281               nexta = a * a - b * b + o->cx;
282               b = 2.0 * a * b + o->cy;
283               break;
284 
285             case GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_1:
286               foldxinitx = olda * o->cx;
287               foldyinity = oldb * o->cy;
288               foldxinity = olda * o->cy;
289               foldyinitx = oldb * o->cx;
290               /* orbit calculation */
291               if (olda >= 0)
292                 {
293                   nexta = (foldxinitx - o->cx - foldyinity);
294                   b  = (foldyinitx - o->cy + foldxinity);
295                 }
296               else
297                 {
298                   nexta = (foldxinitx + o->cx - foldyinity);
299                   b  = (foldyinitx + o->cy + foldxinity);
300                 }
301               break;
302 
303             case GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_2:
304               foldxinitx = olda * o->cx;
305               foldyinity = oldb * o->cy;
306               foldxinity = olda * o->cy;
307               foldyinitx = oldb * o->cx;
308               /* orbit calculation */
309               if (foldxinity + foldyinitx >= 0)
310                 {
311                   nexta = foldxinitx - o->cx - foldyinity;
312                   b  = foldyinitx - o->cy + foldxinity;
313                 }
314               else
315                 {
316                   nexta = foldxinitx + o->cx - foldyinity;
317                   b  = foldyinitx + o->cy + foldxinity;
318                 }
319               break;
320 
321             case GEGL_FRACTAL_EXPLORER_TYPE_BARNSLEY_3:
322               foldxinitx  = olda * olda;
323               foldyinity  = oldb * oldb;
324               foldxinity  = olda * oldb;
325               /* orbit calculation */
326               if (olda > 0)
327                 {
328                   nexta = foldxinitx - foldyinity - 1.0;
329                   b  = foldxinity * 2;
330                 }
331               else
332                 {
333                   nexta = foldxinitx - foldyinity -1.0 + o->cx * olda;
334                   b  = foldxinity * 2;
335                   b += o->cy * olda;
336                 }
337               break;
338 
339             case GEGL_FRACTAL_EXPLORER_TYPE_SPIDER:
340               /* { c=z=pixel: z=z*z+c; c=c/2+z, |z|<=4 } */
341               nexta = a*a - b*b + tmpx + o->cx;
342               b = 2 * olda * oldb + tmpy + o->cy;
343               tmpx = tmpx/2 + nexta;
344               tmpy = tmpy/2 + b;
345               break;
346 
347             case GEGL_FRACTAL_EXPLORER_TYPE_MAN_O_WAR:
348               nexta = a*a - b*b + tmpx + o->cx;
349               b = 2.0 * a * b + tmpy + o->cy;
350               tmpx = olda;
351               tmpy = oldb;
352               break;
353 
354             case GEGL_FRACTAL_EXPLORER_TYPE_LAMBDA:
355               tempsqrx = a * a;
356               tempsqry = b * b;
357               tempsqrx = olda - tempsqrx + tempsqry;
358               tempsqry = -(oldb * olda);
359               tempsqry += tempsqry + oldb;
360               nexta = o->cx * tempsqrx - o->cy * tempsqry;
361               b = o->cx * tempsqry + o->cy * tempsqrx;
362               break;
363 
364             case GEGL_FRACTAL_EXPLORER_TYPE_SIERPINSKI:
365               nexta = olda + olda;
366               b = oldb + oldb;
367               if (oldb > .5)
368                 b = b - 1;
369               else if (olda > .5)
370                 nexta = nexta - 1;
371               break;
372 
373             default:
374               g_warning (_("Unsupported fractal type: %d"), o->fractaltype);
375               return FALSE;
376             }
377 
378           a = nexta;
379 
380           if (((a * a) + (b * b)) >= 4.0)
381             break;
382         }
383 
384       if (o->useloglog)
385         {
386           gdouble modulus_square = (a * a) + (b * b);
387 
388           if (modulus_square > (G_E * G_E))
389               adjust = log (log (modulus_square) / 2.0) / log2;
390           else
391               adjust = 0.0;
392         }
393 
394       color = (gint) (((counter - adjust) * (o->ncolors - 1)) / o->iter);
395 
396       out_pixel[0] = colormap[color].r;
397       out_pixel[1] = colormap[color].g;
398       out_pixel[2] = colormap[color].b;
399       out_pixel[3] = 1.0;
400 
401       out_pixel += 4;
402 
403       /* update x and y coordinates */
404       pixelx++;
405       if (pixelx>=roi->x + roi->width)
406         {
407           pixelx=roi->x;
408           pixely++;
409         }
410     }
411 
412   return TRUE;
413 }
414 
415 
416 static void
417 gegl_op_class_init (GeglOpClass *klass)
418 {
419   GeglOperationClass            *operation_class;
420   GeglOperationPointRenderClass *point_render_class;
421 
422   operation_class    = GEGL_OPERATION_CLASS (klass);
423   point_render_class = GEGL_OPERATION_POINT_RENDER_CLASS (klass);
424 
425   point_render_class->process = process;
426   operation_class->get_bounding_box = get_bounding_box;
427   operation_class->prepare = prepare;
428 
429   gegl_operation_class_set_keys (operation_class,
430     "name",               "gegl:fractal-explorer",
431     "title",              _("Fractal Explorer"),
432     "categories",         "render:fractal",
433     "reference-hash",     "fd6c1f91d1a44d67e229754958627e7e",
434     "position-dependent", "true",
435     "license",            "GPL3+",
436     "description",        _("Rendering of multiple different fractal systems, with configurable coloring options."),
437     NULL);
438 }
439 
440 #endif
441