/* 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 . * * Copyright (C) 1997 Hirotsuna Mizuno * Copyright (C) 2011 Robert Sasu */ #include "config.h" #include #ifdef GEGL_CHANT_PROPERTIES gegl_chant_string (fractal, _("Fractal"), "fractal", _("Type of fractal to use. " "Choices are julia, mandelbrot. Default is mandelbrot.")) gegl_chant_double (X1, _("X1"), -50.0, 50.0, -1.00, _("X1 value, position")) gegl_chant_double (X2, _("X2"), -50.0, 50.0, 0.50, _("X2 value, position")) gegl_chant_double (Y1, _("Y1"), -50.0, 50.0, -1.00, _("X2 value, position")) gegl_chant_double (Y2, _("Y2"), -50.0, 50.0, 1.00, _("Y2 value, position")) gegl_chant_double (JX, _("JX"), -50.0, 50.0, 0.5, _("Julia seed X value, position")) gegl_chant_double (JY, _("JY"), -50.0, 50.0, 0.5, _("Julia seed Y value, position")) gegl_chant_int (depth, _("Depth"), 1, 65536, 3, _("Depth value")) gegl_chant_double (bailout, _("Bailout"), 0.0, G_MAXDOUBLE, G_MAXDOUBLE, _("Bailout length")) gegl_chant_string (background, _("Background"), "wrap", _("Optional parameter to override automatic selection of wrap background. " "Choices are wrap, black, white and transparent.")) #else #define GEGL_CHANT_TYPE_FILTER #define GEGL_CHANT_C_FILE "fractal-trace.c" #include "gegl-chant.h" #include typedef enum { BACKGROUND_TYPE_WRAP, BACKGROUND_TYPE_TRANSPARENT, BACKGROUND_TYPE_BLACK, BACKGROUND_TYPE_WHITE } BackgroundType; typedef enum { FRACTAL_TYPE_MANDELBROT, FRACTAL_TYPE_JULIA } FractalType; static void prepare (GeglOperation *operation) { gegl_operation_set_format (operation, "input", babl_format ("RGBA float")); gegl_operation_set_format (operation, "output", babl_format ("RGBA float")); } static void julia (gdouble x, gdouble y, gdouble jx, gdouble jy, gdouble *u, gdouble *v, gint depth, gdouble bailout2) { 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; if ((x2 + y2) > bailout2) break; } *u = xx; *v = yy; } static void fractaltrace (GeglBuffer *input, const GeglRectangle *picture, gfloat *dst_buf, const GeglRectangle *roi, GeglChantO *o, gint y, FractalType fractal_type, BackgroundType background_type, const Babl *format) { 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]; scale_x = (o->X2 - o->X1) / picture->width; scale_y = (o->Y2 - o->Y1) / picture->height; bailout2 = o->bailout * o->bailout; offset = (y - roi->y) * roi->width * 4; for (x = roi->x; x < roi->x + roi->width; x++) { gdouble cx, cy; gdouble px, py; dest[1] = dest[2] = dest[3] = dest[0] = 0.0; switch (fractal_type) { case FRACTAL_TYPE_JULIA: #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; \ 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); #undef gegl_unmap break; case FRACTAL_TYPE_MANDELBROT: #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; \ 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); #undef gegl_unmap break; default: g_error (_("Unsupported fractal type")); } if (0 <= px && px < picture->width && 0 <= py && py < picture->height) { gegl_buffer_sample (input, px, py, &scale, dest, format, GEGL_SAMPLER_LOHALO, GEGL_ABYSS_NONE); } else { switch (background_type) { case BACKGROUND_TYPE_WRAP: px = fmod (px, picture->width); py = fmod (py, picture->height); if (px < 0.0) px += picture->width; if (py < 0.0) py += picture->height; /* Check for NaN */ if (isnan (px)) { if (signbit (px)) px = 0.0; else px = picture->width - 1.0; } if (isnan (py)) { if (signbit (py)) py = 0.0; else py = picture->height - 1.0; } gegl_buffer_sample (input, px, py, &scale, dest, format, GEGL_SAMPLER_LOHALO, GEGL_ABYSS_NONE); break; case BACKGROUND_TYPE_TRANSPARENT: dest[0] = dest[1] = dest[2] = dest[3] = 0.0; break; case BACKGROUND_TYPE_BLACK: dest[0] = dest[1] = dest[2] = 0.0; dest[3] = 1.0; break; case BACKGROUND_TYPE_WHITE: dest[0] = dest[1] = dest[2] = dest[3] = 1.0; break; } } for (i = 0; i < 4; i++) dst_buf[offset++] = dest[i]; } } static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o; GeglRectangle boundary; const Babl *format; FractalType fractal_type; BackgroundType background_type; gfloat *dst_buf; gint y; o = GEGL_CHANT_PROPERTIES (operation); boundary = gegl_operation_get_bounding_box (operation); fractal_type = FRACTAL_TYPE_MANDELBROT; if (!strcmp (o->fractal, "mandelbrot")) fractal_type = FRACTAL_TYPE_MANDELBROT; else if (!strcmp(o->fractal, "julia")) fractal_type = FRACTAL_TYPE_JULIA; background_type = BACKGROUND_TYPE_WRAP; if (!strcmp (o->background, "wrap")) background_type = BACKGROUND_TYPE_WRAP; else if (!strcmp (o->background, "transparent")) background_type = BACKGROUND_TYPE_TRANSPARENT; else if (!strcmp (o->background, "black")) background_type = BACKGROUND_TYPE_BLACK; else if (!strcmp (o->background, "white")) background_type = BACKGROUND_TYPE_WHITE; format = babl_format ("RGBA float"); dst_buf = g_new0 (gfloat, result->width * result->height * 4); for (y = result->y; y < result->y + result->height; y++) fractaltrace (input, &boundary, dst_buf, result, o, y, fractal_type, background_type, format); gegl_buffer_set (output, result, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE); g_free (dst_buf); gegl_buffer_sample_cleanup (input); return TRUE; } static GeglRectangle get_bounding_box (GeglOperation *operation) { GeglRectangle result = {0,0,0,0}; GeglRectangle *in_rect; in_rect = gegl_operation_source_get_bounding_box (operation, "input"); if (!in_rect) return result; return *in_rect; } static GeglRectangle get_required_for_output (GeglOperation *operation, const gchar *input_pad, const GeglRectangle *roi) { return get_bounding_box (operation); } static void gegl_chant_class_init (GeglChantClass *klass) { GeglOperationClass *operation_class; GeglOperationFilterClass *filter_class; operation_class = GEGL_OPERATION_CLASS (klass); filter_class = GEGL_OPERATION_FILTER_CLASS (klass); filter_class->process = process; operation_class->prepare = prepare; operation_class->get_bounding_box = get_bounding_box; operation_class->get_required_for_output = get_required_for_output; gegl_operation_class_set_keys (operation_class, "categories" , "map", "name" , "gegl:fractal-trace", "description" , _("Performs fractal trace on the image"), NULL); } #endif