home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / fractaltrace.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  22.3 KB  |  847 lines

  1. /*******************************************************************************
  2.  
  3.   fractaltrace.c  -- This is a plug-in for the GIMP 1.0
  4.  
  5.   Copyright (C) 1997  Hirotsuna Mizuno
  6.                       s1041150@u-aizu.ac.jp
  7.  
  8.   This program is free software; you can redistribute it and/or modify it
  9.   under the terms of the GNU General Public License as published by the Free
  10.   Software Foundation; either version 2 of the License, or (at your option)
  11.   any later version.
  12.  
  13.   This program is distributed in the hope that it will be useful, but WITHOUT
  14.   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15.   FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16.   more details.
  17.  
  18.   You should have received a copy of the GNU General Public License along with
  19.   this program; if not, write to the Free Software Foundation, Inc.,
  20.   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21.  
  22. *******************************************************************************/
  23.  
  24. #define PLUG_IN_NAME     "plug_in_fractal_trace"
  25. #define PLUG_IN_VERSION  "v0.4 test version (Dec. 25 1997)"
  26.  
  27. /******************************************************************************/
  28.  
  29. #include "config.h"
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33.  
  34. #include <gtk/gtk.h>
  35.  
  36. #include <libgimp/gimp.h>
  37. #include <libgimp/gimpui.h>
  38.  
  39. #include "libgimp/stdplugins-intl.h"
  40.  
  41. /******************************************************************************/
  42.  
  43. static void query  (void);
  44. static void run    (gchar   *name,
  45.             gint     nparams,
  46.             GimpParam  *param,
  47.             gint    *nreturn_vals,
  48.             GimpParam **return_vals);
  49.  
  50. static void filter      (GimpDrawable *drawable);
  51.  
  52. static void pixels_init (GimpDrawable *drawable);
  53. static void pixels_free (void);
  54.  
  55. static int  dialog_show         (void);
  56. static void dialog_preview_draw (void);
  57.  
  58. /******************************************************************************/
  59.  
  60. GimpPlugInInfo PLUG_IN_INFO =
  61. {
  62.   NULL,  /* init_proc  */
  63.   NULL,  /* quit_proc  */
  64.   query, /* query_proc */
  65.   run    /* run_proc   */
  66. };
  67.  
  68. MAIN ()
  69.  
  70. /******************************************************************************/
  71.  
  72. enum
  73. {
  74.   OUTSIDE_TYPE_WRAP,
  75.   OUTSIDE_TYPE_TRANSPARENT,
  76.   OUTSIDE_TYPE_BLACK,
  77.   OUTSIDE_TYPE_WHITE
  78. };
  79.  
  80. typedef struct
  81. {
  82.   gdouble x1;
  83.   gdouble x2;
  84.   gdouble y1;
  85.   gdouble y2;
  86.   gint32  depth;
  87.   gint32  outside_type;
  88. } parameter_t;
  89.  
  90. static parameter_t parameters =
  91. {
  92.   -1.0,
  93.   +0.5,
  94.   -1.0,
  95.   +1.0,
  96.   3,
  97.   OUTSIDE_TYPE_WRAP
  98. };
  99.  
  100. /******************************************************************************/
  101.  
  102. static void
  103. query (void)
  104. {
  105.   static GimpParamDef args[] =
  106.   {
  107.     { GIMP_PDB_INT32,    "run_mode",     "interactive / non-interactive"    },
  108.     { GIMP_PDB_IMAGE,    "image",        "input image (not used)"           },
  109.     { GIMP_PDB_DRAWABLE, "drawable",     "input drawable"                   },
  110.     { GIMP_PDB_FLOAT,    "xmin",         "xmin fractal image delimiter"     },
  111.     { GIMP_PDB_FLOAT,    "xmax",         "xmax fractal image delimiter"     },
  112.     { GIMP_PDB_FLOAT,    "ymin",         "ymin fractal image delimiter"     },
  113.     { GIMP_PDB_FLOAT,    "ymax",         "ymax fractal image delimiter"     },
  114.     { GIMP_PDB_INT32,    "depth",        "trace depth"                      },
  115.     { GIMP_PDB_INT32,    "outside_type", "outside type"
  116.                                       "(0=WRAP/1=TRANS/2=BLACK/3=WHITE)" }
  117.   };
  118.   static gint nargs = sizeof (args) / sizeof (args[0]);
  119.  
  120.   gimp_install_procedure (PLUG_IN_NAME,
  121.               "transform image with the Mandelbrot Fractal",
  122.               "transform image with the Mandelbrot Fractal",
  123.               "Hirotsuna Mizuno <s1041150@u-aizu.ac.jp>",
  124.               "Copyright (C) 1997 Hirotsuna Mizuno",
  125.               PLUG_IN_VERSION,
  126.               N_("<Image>/Filters/Map/Fractal Trace..."),
  127.               "RGB*, GRAY*",
  128.               GIMP_PLUGIN,
  129.               nargs, 0,
  130.               args, NULL);
  131. }
  132.  
  133. /******************************************************************************/
  134.  
  135. typedef struct
  136. {
  137.   gint     x1;
  138.   gint     x2;
  139.   gint     y1;
  140.   gint     y2;
  141.   gint     width;
  142.   gint     height;
  143.   gdouble  center_x;
  144.   gdouble  center_y;
  145. } selection_t;
  146.  
  147. typedef struct
  148. {
  149.   gint         width;
  150.   gint         height;
  151.   gint         bpp;
  152.   gint         alpha;
  153. } image_t;
  154.  
  155. static selection_t selection;
  156. static image_t     image;
  157.   
  158. /******************************************************************************/
  159.  
  160. static void
  161. run (gchar   *name,
  162.      gint     argc,
  163.      GimpParam  *args,
  164.      gint    *retc,
  165.      GimpParam **rets)
  166. {
  167.   GimpDrawable     *drawable;
  168.   GimpRunModeType   run_mode;
  169.   GimpPDBStatusType    status;
  170.   static GimpParam  returns[1];
  171.  
  172.   run_mode = args[0].data.d_int32;
  173.   status   = GIMP_PDB_SUCCESS;
  174.  
  175.   drawable     = gimp_drawable_get (args[2].data.d_drawable);
  176.   image.width  = gimp_drawable_width( drawable->id);
  177.   image.height = gimp_drawable_height (drawable->id);
  178.   image.bpp    = gimp_drawable_bpp (drawable->id);
  179.   image.alpha  = gimp_drawable_has_alpha (drawable->id);
  180.   gimp_drawable_mask_bounds (drawable->id, &selection.x1, &selection.y1,
  181.                  &selection.x2, &selection.y2);
  182.   selection.width    = selection.x2 - selection.y1;
  183.   selection.height   = selection.y2 - selection.y1;
  184.   selection.center_x = selection.x1 + (gdouble) selection.width / 2.0;
  185.   selection.center_y = selection.y1 + (gdouble) selection.height / 2.0;
  186.  
  187.   pixels_init (drawable);
  188.  
  189.   if (!gimp_drawable_is_rgb(drawable->id) && 
  190.       !gimp_drawable_is_gray(drawable->id))
  191.     {
  192.       status = GIMP_PDB_EXECUTION_ERROR;
  193.     }
  194.  
  195.   switch (run_mode)
  196.     {
  197.     case GIMP_RUN_WITH_LAST_VALS:
  198.       INIT_I18N();
  199.       gimp_get_data (PLUG_IN_NAME, ¶meters);
  200.       break;
  201.  
  202.     case GIMP_RUN_INTERACTIVE:
  203.       INIT_I18N_UI();
  204.       gimp_get_data (PLUG_IN_NAME, ¶meters);
  205.       if (!dialog_show ())
  206.     {
  207.       status = GIMP_PDB_EXECUTION_ERROR;
  208.       break;
  209.     }
  210.       gimp_set_data (PLUG_IN_NAME, ¶meters, sizeof (parameter_t));
  211.       break;
  212.  
  213.     case GIMP_RUN_NONINTERACTIVE:
  214.       if (argc != 9)
  215.     {
  216.       status = GIMP_PDB_CALLING_ERROR;
  217.     }
  218.       else
  219.     {
  220.       parameters.x1           = args[3].data.d_float;
  221.       parameters.x2           = args[4].data.d_float;
  222.       parameters.y1           = args[5].data.d_float;
  223.       parameters.y2           = args[6].data.d_float;
  224.       parameters.depth        = args[7].data.d_int32;
  225.       parameters.outside_type = args[8].data.d_int32;
  226.     }
  227.       INIT_I18N();
  228.       break;
  229.     }
  230.  
  231.   if (status == GIMP_PDB_SUCCESS)
  232.     {
  233.       gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
  234.       filter (drawable);
  235.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  236.     gimp_displays_flush();
  237.     }
  238.  
  239.   gimp_drawable_detach (drawable);
  240.  
  241.   pixels_free ();
  242.  
  243.   returns[0].type          = GIMP_PDB_STATUS;
  244.   returns[0].data.d_status = status;
  245.   *retc = 1;
  246.   *rets = returns;
  247. }
  248.  
  249. /******************************************************************************/
  250.  
  251. static guchar    **spixels;
  252. static guchar    **dpixels;
  253. static GimpPixelRgn   sPR;
  254. static GimpPixelRgn   dPR;
  255.  
  256. typedef struct
  257. {
  258.   guchar r;
  259.   guchar g;
  260.   guchar b;
  261.   guchar a;
  262. } pixel_t;
  263.  
  264. static void
  265. pixels_init (GimpDrawable *drawable)
  266. {
  267.   gint y;
  268.  
  269.   gimp_pixel_rgn_init (&sPR, drawable,
  270.                0, 0, image.width, image.height, FALSE, FALSE);
  271.   gimp_pixel_rgn_init (&dPR, drawable,
  272.                0, 0, image.width, image.height, TRUE, TRUE);
  273.  
  274.   spixels = g_new (guchar *, image.height);
  275.   dpixels = g_new (guchar *, image.height);
  276.  
  277.   for (y = 0; y < image.height; y++)
  278.     {
  279.       spixels[y] = g_new (guchar, image.width * image.bpp);
  280.       dpixels[y] = g_new (guchar, image.width * image.bpp);
  281.       gimp_pixel_rgn_get_row (&sPR, spixels[y], 0, y, image.width);
  282.     }
  283. }
  284.  
  285. static void
  286. pixels_free (void)
  287. {
  288.   gint y;
  289.  
  290.   for (y = 0; y < image.height; y++)
  291.     {
  292.       g_free (spixels[y]);
  293.       g_free (dpixels[y]);
  294.     }
  295.   g_free (spixels);
  296.   g_free (dpixels);
  297. }
  298.  
  299. static void
  300. pixels_get (gint     x,
  301.         gint     y,
  302.         pixel_t *pixel)
  303. {
  304.   if(x < 0) x = 0; else if (image.width  <= x) x = image.width  - 1;
  305.   if(y < 0) y = 0; else if (image.height <= y) y = image.height - 1;
  306.  
  307.   switch (image.bpp)
  308.     {
  309.     case 1: /* GRAY */
  310.       pixel->r = spixels[y][x*image.bpp];
  311.       pixel->g = spixels[y][x*image.bpp];
  312.       pixel->b = spixels[y][x*image.bpp];
  313.       pixel->a = 255;
  314.       break;
  315.     case 2: /* GRAY+A */
  316.       pixel->r = spixels[y][x*image.bpp];
  317.       pixel->g = spixels[y][x*image.bpp];
  318.       pixel->b = spixels[y][x*image.bpp];
  319.       pixel->a = spixels[y][x*image.bpp+1];
  320.       break;
  321.     case 3: /* RGB */
  322.       pixel->r = spixels[y][x*image.bpp];
  323.       pixel->g = spixels[y][x*image.bpp+1];
  324.       pixel->b = spixels[y][x*image.bpp+2];
  325.       pixel->a = 255;
  326.       break;
  327.     case 4: /* RGB+A */
  328.       pixel->r = spixels[y][x*image.bpp];
  329.       pixel->g = spixels[y][x*image.bpp+1];
  330.       pixel->b = spixels[y][x*image.bpp+2];
  331.       pixel->a = spixels[y][x*image.bpp+3];
  332.       break;
  333.     }
  334. }
  335.  
  336. static void
  337. pixels_get_biliner (gdouble  x,
  338.             gdouble  y,
  339.             pixel_t *pixel)
  340. {
  341.   pixel_t A, B, C, D;
  342.   gdouble a, b, c, d;
  343.   gint    x1, y1, x2, y2;
  344.   gdouble dx, dy;
  345.  
  346.   x1 = (gint) floor (x);
  347.   x2 = x1 + 1;
  348.   y1 = (gint) floor (y);
  349.   y2 = y1 + 1;
  350.  
  351.   dx = x - (gdouble) x1;
  352.   dy = y - (gdouble) y1;
  353.   a  = (1.0 - dx) * (1.0 - dy);
  354.   b  = dx * (1.0 - dy);
  355.   c  = (1.0 - dx) * dy;
  356.   d  = dx * dy;
  357.  
  358.   pixels_get (x1, y1, &A);
  359.   pixels_get (x2, y1, &B);
  360.   pixels_get (x1, y2, &C);
  361.   pixels_get (x2, y2, &D);
  362.  
  363.   pixel->r = (guchar) (a * (gdouble) A.r + b * (gdouble) B.r +
  364.                c * (gdouble) C.r + d * (gdouble) D.r);
  365.   pixel->g = (guchar) (a * (gdouble) A.g + b * (gdouble) B.g +
  366.                c * (gdouble) C.g + d * (gdouble) D.g);
  367.   pixel->b = (guchar) (a * (gdouble) A.b + b * (gdouble) B.b +
  368.                c * (gdouble) C.b + d * (gdouble) D.b);
  369.   pixel->a = (guchar) (a * (gdouble) A.a + b * (gdouble) B.a +
  370.                c * (gdouble) C.a + d * (gdouble) D.a);
  371. }
  372.  
  373. static void
  374. pixels_set (gint     x,
  375.         gint     y,
  376.         pixel_t *pixel)
  377. {
  378.   switch (image.bpp)
  379.     {
  380.     case 1: /* GRAY */
  381.       dpixels[y][x*image.bpp]   = pixel->r;
  382.       break;
  383.     case 2: /* GRAY+A */
  384.       dpixels[y][x*image.bpp]   = pixel->r;
  385.       dpixels[y][x*image.bpp+1] = pixel->a;
  386.       break;
  387.     case 3: /* RGB */
  388.       dpixels[y][x*image.bpp]   = pixel->r;
  389.       dpixels[y][x*image.bpp+1] = pixel->g;
  390.       dpixels[y][x*image.bpp+2] = pixel->b;
  391.       break;
  392.     case 4: /* RGB+A */
  393.       dpixels[y][x*image.bpp]   = pixel->r;
  394.       dpixels[y][x*image.bpp+1] = pixel->g;
  395.       dpixels[y][x*image.bpp+2] = pixel->b;
  396.       dpixels[y][x*image.bpp+3] = pixel->a;
  397.       break;
  398.     }
  399. }
  400.  
  401. static void
  402. pixels_store (void)
  403. {
  404.   gint y;
  405.  
  406.   for (y = selection.y1; y < selection.y2; y++)
  407.     {
  408.       gimp_pixel_rgn_set_row (&dPR, dpixels[y], 0, y, image.width);
  409.     }
  410. }
  411.  
  412. /******************************************************************************/
  413.  
  414. static void
  415. mandelbrot (gdouble  x,
  416.         gdouble  y,
  417.         gdouble *u,
  418.         gdouble *v)
  419. {
  420.   gint    iter = 0;
  421.   gdouble xx   = x;
  422.   gdouble yy   = y;
  423.   gdouble x2   = xx * xx;
  424.   gdouble y2   = yy * yy;
  425.   gdouble tmp;
  426.  
  427.   while (iter < parameters.depth)
  428.     {
  429.       tmp = x2 - y2 + x;
  430.       yy  = 2 * xx * yy + y;
  431.       xx  = tmp;
  432.       x2  = xx * xx;
  433.       y2  = yy * yy;
  434.       iter++;
  435.     }
  436.   *u = xx;
  437.   *v = yy;
  438. }
  439.  
  440. /******************************************************************************/
  441.  
  442. static void
  443. filter (GimpDrawable *drawable)
  444. {
  445.   gint    x, y;
  446.   pixel_t pixel;
  447.   gdouble scale_x, scale_y;
  448.   gdouble cx, cy;
  449.   gdouble px, py;
  450.  
  451.   gimp_progress_init (_("Fractal Trace"));
  452.  
  453.   scale_x = (parameters.x2 - parameters.x1) / selection.width;
  454.   scale_y = (parameters.y2 - parameters.y1) / selection.height;
  455.  
  456.   for (y = selection.y1; y < selection.y2; y++)
  457.     {
  458.       cy = parameters.y1 + (y - selection.y1) * scale_y;
  459.       for (x = selection.x1; x < selection.x2; x++)
  460.     {
  461.       cx = parameters.x1 + (x - selection.x1) * scale_x;
  462.       mandelbrot (cx, cy, &px, &py);
  463.       px = (px - parameters.x1) / scale_x + selection.x1;
  464.       py = (py - parameters.y1) / scale_y + selection.y1;
  465.       if (0 <= px && px < image.width && 0 <= py && py < image.height)
  466.         {
  467.           pixels_get_biliner (px, py, &pixel);
  468.         }
  469.       else
  470.         {
  471.           switch (parameters.outside_type)
  472.         {
  473.         case OUTSIDE_TYPE_WRAP:
  474.           px = fmod (px, image.width);
  475.           py = fmod (py, image.height);
  476.           if( px < 0.0) px += image.width;
  477.           if (py < 0.0) py += image.height;
  478.           pixels_get_biliner (px, py, &pixel);
  479.           break;
  480.         case OUTSIDE_TYPE_TRANSPARENT:
  481.           pixel.r = pixel.g = pixel.b = 0;
  482.           pixel.a = 0;
  483.           break;
  484.         case OUTSIDE_TYPE_BLACK:
  485.           pixel.r = pixel.g = pixel.b = 0;
  486.           pixel.a = 255;
  487.           break;
  488.         case OUTSIDE_TYPE_WHITE:
  489.           pixel.r = pixel.g = pixel.b = 255;
  490.           pixel.a = 255;
  491.           break;
  492.         }
  493.         }
  494.       pixels_set (x, y, &pixel);
  495.     }
  496.       gimp_progress_update ((gdouble) (y-selection.y1) / selection.height);
  497.     }
  498.  
  499.   pixels_store ();
  500.  
  501.   gimp_drawable_flush (drawable);
  502.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  503.   gimp_drawable_update (drawable->id,
  504.             selection.x1, selection.y1,
  505.             selection.width, selection.height);
  506. }
  507.  
  508. /******************************************************************************/
  509.  
  510. #define PREVIEW_SIZE 200
  511.  
  512. typedef struct
  513. {
  514.   GtkWidget  *preview;
  515.   guchar    **source;
  516.   guchar    **pixels;
  517.   gdouble     scale;
  518.   gint        width;
  519.   gint        height;
  520.   gint        bpp;
  521. } preview_t;
  522.  
  523. static preview_t preview;
  524.  
  525. static void
  526. dialog_preview_setpixel (gint     x,
  527.              gint     y,
  528.              pixel_t *pixel)
  529. {
  530.   switch (preview.bpp)
  531.     {
  532.     case 1:
  533.       preview.pixels[y][x*preview.bpp] = pixel->r;
  534.       break;
  535.     case 3:
  536.       preview.pixels[y][x*preview.bpp]   = pixel->r;
  537.       preview.pixels[y][x*preview.bpp+1] = pixel->g;
  538.       preview.pixels[y][x*preview.bpp+2] = pixel->b;
  539.       break;
  540.     }
  541. }
  542.  
  543. static void
  544. dialog_preview_store (void)
  545. {
  546.   gint y;
  547.  
  548.   for (y = 0; y < preview.height; y++)
  549.     {
  550.       gtk_preview_draw_row (GTK_PREVIEW (preview.preview),
  551.                 preview.pixels[y], 0, y, preview.width);
  552.     }
  553.   gtk_widget_draw (preview.preview, NULL);
  554.   gdk_flush ();
  555. }
  556.  
  557. static void
  558. dialog_preview_init (void)
  559. {
  560.   pixel_t  pixel;
  561.   gint     x, y;
  562.   gdouble  cx, cy;
  563.  
  564.   if (image.width < image.height)
  565.     preview.scale = (gdouble)selection.height / (gdouble)PREVIEW_SIZE;
  566.   else
  567.     preview.scale = (gdouble)selection.width / (gdouble)PREVIEW_SIZE;
  568.   preview.width  = (gdouble)selection.width / preview.scale;
  569.   preview.height = (gdouble)selection.height / preview.scale;
  570.  
  571.   if (image.bpp < 3)
  572.     {
  573.       preview.bpp = 1;
  574.       preview.preview = gtk_preview_new (GTK_PREVIEW_GRAYSCALE);
  575.     }
  576.   else
  577.     {
  578.       preview.bpp = 3;
  579.       preview.preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  580.     }
  581.   gtk_preview_size (GTK_PREVIEW (preview.preview),
  582.             preview.width, preview.height);
  583.  
  584.   preview.source = g_new (guchar *, preview.height);
  585.   preview.pixels = g_new (guchar *, preview.height);
  586.   for (y = 0; y < preview.height; y++)
  587.     {
  588.       preview.source[y] = g_new (guchar, preview.width * preview.bpp);
  589.       preview.pixels[y] = g_new (guchar, preview.width * preview.bpp);
  590.     }
  591.  
  592.   for (y = 0; y < preview.height; y++)
  593.     {
  594.       cy = selection.y1 + (gdouble)y * preview.scale;
  595.       for (x = 0; x < preview.width; x++)
  596.     {
  597.       cx = selection.x1 + (gdouble)x * preview.scale;
  598.       pixels_get_biliner (cx, cy, &pixel);
  599.       dialog_preview_setpixel (x, y, &pixel);
  600.     }
  601.     }
  602.   dialog_preview_store ();
  603. }
  604.  
  605. static void
  606. dialog_preview_draw (void)
  607. {
  608.   gint    x, y;
  609.   pixel_t pixel;
  610.   gdouble scale_x, scale_y;
  611.   gdouble cx, cy;
  612.   gdouble px, py;
  613.  
  614.   scale_x = (parameters.x2 - parameters.x1) / preview.width;
  615.   scale_y = (parameters.y2 - parameters.y1) / preview.height;
  616.  
  617.   for (y = 0; y < preview.height; y++)
  618.     {
  619.       cy = parameters.y1 + y * scale_y;
  620.       for (x = 0; x < preview.width; x++)
  621.     {
  622.       cx = parameters.x1 + x * scale_x;
  623.       mandelbrot(cx, cy, &px, &py);
  624.       px = (px - parameters.x1) / scale_x * preview.scale + selection.x1;
  625.       py = (py - parameters.y1) / scale_y * preview.scale + selection.y1;
  626.       if (0 <= px && px < image.width && 0 <= py && py < image.height)
  627.         {
  628.           pixels_get_biliner (px, py, &pixel);
  629.         }
  630.       else
  631.         {
  632.           switch (parameters.outside_type)
  633.         {
  634.         case OUTSIDE_TYPE_WRAP:
  635.           px = fmod (px, image.width);
  636.           py = fmod (py, image.height);
  637.           if (px < 0.0) px += image.width;
  638.           if (py < 0.0) py += image.height;
  639.           pixels_get_biliner (px, py, &pixel);
  640.           break;
  641.         case OUTSIDE_TYPE_TRANSPARENT:
  642.           pixel.r = pixel.g = pixel.b =
  643.             (((x % (GIMP_CHECK_SIZE * 2) < GIMP_CHECK_SIZE) ?
  644.               (y % (GIMP_CHECK_SIZE * 2) < GIMP_CHECK_SIZE) :
  645.               (y % (GIMP_CHECK_SIZE * 2) > GIMP_CHECK_SIZE)) ?
  646.              GIMP_CHECK_LIGHT : GIMP_CHECK_DARK) * 255;
  647.           break;
  648.         case OUTSIDE_TYPE_BLACK:
  649.           pixel.r = pixel.g = pixel.b = 0;
  650.           break;
  651.         case OUTSIDE_TYPE_WHITE:
  652.           pixel.r = pixel.g = pixel.b = 255;
  653.           break;
  654.         }
  655.         }
  656.       dialog_preview_setpixel (x, y, &pixel);
  657.     }
  658.     }
  659.  
  660.   dialog_preview_store ();
  661. }
  662.  
  663. /******************************************************************************/
  664.  
  665. static gboolean dialog_status = FALSE;
  666.  
  667. static void
  668. dialog_int_adjustment_update (GtkAdjustment *adjustment,
  669.                   gpointer       data)
  670. {
  671.   gimp_int_adjustment_update (adjustment, data);
  672.  
  673.   dialog_preview_draw ();
  674. }
  675.  
  676. static void
  677. dialog_double_adjustment_update (GtkAdjustment *adjustment,
  678.                  gpointer       data)
  679. {
  680.   gimp_double_adjustment_update (adjustment, data);
  681.  
  682.   dialog_preview_draw ();
  683. }
  684.  
  685. static void
  686. dialog_ok_callback (GtkWidget *widget,
  687.             gpointer   data)
  688. {
  689.   dialog_status = TRUE;
  690.  
  691.   gtk_widget_destroy (GTK_WIDGET (data));
  692. }
  693.  
  694. static void
  695. dialog_outside_type_callback (GtkWidget *widget,
  696.                   gpointer  *data)
  697. {
  698.   gimp_radio_button_update (widget, data);
  699.  
  700.   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
  701.     dialog_preview_draw ();
  702. }
  703.  
  704. /******************************************************************************/
  705.  
  706. static gint
  707. dialog_show (void)
  708. {
  709.   GtkWidget *dialog;
  710.   GtkWidget *mainbox;
  711.   GtkWidget *hbox;
  712.   GtkWidget *table;
  713.   GtkWidget *frame;
  714.   GtkWidget *abox;
  715.   GtkWidget *pframe;
  716.   GtkObject *adj;
  717.  
  718.   gimp_ui_init ("fractaltrace", TRUE);
  719.  
  720.   dialog = gimp_dialog_new (_("Fractal Trace"), "fractaltrace",
  721.                 gimp_standard_help_func, "filters/fractaltrace.html",
  722.                 GTK_WIN_POS_MOUSE,
  723.                 FALSE, TRUE, FALSE,
  724.  
  725.                 _("OK"), dialog_ok_callback,
  726.                 NULL, NULL, NULL, TRUE, FALSE,
  727.                 _("Cancel"), gtk_widget_destroy,
  728.                 NULL, 1, NULL, FALSE, TRUE,
  729.  
  730.                 NULL);
  731.  
  732.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  733.               GTK_SIGNAL_FUNC (gtk_main_quit),
  734.               NULL);
  735.  
  736.   mainbox = gtk_vbox_new (FALSE, 4);
  737.   gtk_container_set_border_width (GTK_CONTAINER (mainbox), 6);
  738.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), mainbox);
  739.   gtk_widget_show (mainbox);
  740.  
  741.   hbox = gtk_hbox_new (FALSE, 6);
  742.   gtk_box_pack_start (GTK_BOX (mainbox), hbox, FALSE, FALSE, 0);
  743.   gtk_widget_show (hbox);
  744.  
  745.   /*  Preview  */
  746.   frame = gtk_frame_new (_("Preview"));
  747.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  748.   gtk_widget_show (frame);
  749.  
  750.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  751.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  752.   gtk_container_add (GTK_CONTAINER (frame), abox);
  753.   gtk_widget_show (abox);
  754.  
  755.   pframe = gtk_frame_new (NULL);
  756.   gtk_frame_set_shadow_type (GTK_FRAME (pframe), GTK_SHADOW_IN);
  757.   gtk_container_add (GTK_CONTAINER (abox), pframe);
  758.   gtk_widget_show (pframe);
  759.  
  760.   dialog_preview_init ();
  761.   gtk_container_add (GTK_CONTAINER (pframe), preview.preview);
  762.   gtk_widget_show (preview.preview);
  763.  
  764.   /*  Settings  */
  765.   frame = gimp_radio_group_new2 (TRUE, _("Outside Type"),
  766.                  dialog_outside_type_callback,
  767.                  ¶meters.outside_type,
  768.                  (gpointer) parameters.outside_type,
  769.  
  770.                  _("Warp"),
  771.                  (gpointer) OUTSIDE_TYPE_WRAP, NULL,
  772.                  _("Transparent"),
  773.                  (gpointer) OUTSIDE_TYPE_TRANSPARENT, NULL,
  774.                  _("Black"),
  775.                  (gpointer) OUTSIDE_TYPE_BLACK, NULL,
  776.                  _("White"),
  777.                  (gpointer) OUTSIDE_TYPE_WHITE, NULL,
  778.  
  779.                  NULL);
  780.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  781.   gtk_widget_show (frame);
  782.  
  783.   frame = gtk_frame_new (_("Mandelbrot Parameters"));
  784.   gtk_box_pack_start (GTK_BOX (mainbox), frame, FALSE, FALSE, 0);
  785.   gtk_widget_show (frame);
  786.  
  787.   table = gtk_table_new (5, 3, FALSE);
  788.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  789.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  790.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  791.   gtk_container_add (GTK_CONTAINER (frame), table);
  792.   gtk_widget_show (table);
  793.  
  794.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  795.                   "X1:", 0, 0,
  796.                   parameters.x1, -50, 50, 0.1, 0.5, 2,
  797.                   TRUE, 0, 0,
  798.                   NULL, NULL);
  799.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  800.               GTK_SIGNAL_FUNC (dialog_double_adjustment_update),
  801.               ¶meters.x1);
  802.  
  803.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  804.                   "X2:", 0, 0,
  805.                   parameters.x2, -50, 50, 0.1, 0.5, 2,
  806.                   TRUE, 0, 0,
  807.                   NULL, NULL);
  808.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  809.               GTK_SIGNAL_FUNC (dialog_double_adjustment_update),
  810.               ¶meters.x2);
  811.  
  812.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  813.                   "Y1:", 0, 0,
  814.                   parameters.y1, -50, 50, 0.1, 0.5, 2,
  815.                   TRUE, 0, 0,
  816.                   NULL, NULL);
  817.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  818.               GTK_SIGNAL_FUNC (dialog_double_adjustment_update),
  819.               ¶meters.y1);
  820.  
  821.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 3,
  822.                   "Y2:", 0, 0,
  823.                   parameters.y2, -50, 50, 0.1, 0.5, 2,
  824.                   TRUE, 0, 0,
  825.                   NULL, NULL);
  826.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  827.               GTK_SIGNAL_FUNC (dialog_double_adjustment_update),
  828.               ¶meters.y2);
  829.  
  830.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 4,
  831.                   "Depth:", 0, 0,
  832.                   parameters.depth, 1, 50, 1, 5, 0,
  833.                   TRUE, 0, 0,
  834.                   NULL, NULL);
  835.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  836.               GTK_SIGNAL_FUNC (dialog_int_adjustment_update),
  837.               ¶meters.depth);
  838.  
  839.   gtk_widget_show (dialog);
  840.   dialog_preview_draw ();
  841.  
  842.   gtk_main ();
  843.   gdk_flush ();
  844.  
  845.   return dialog_status;
  846. }
  847.