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