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 / diffraction.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  21.9 KB  |  825 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * Diffraction plug-in --- Generate diffraction patterns
  5.  * Copyright (C) 1997 Federico Mena Quintero and David Bleecker
  6.  * federico@nuclecu.unam.mx
  7.  * bleecker@math.hawaii.edu
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22.  */
  23.  
  24. #include "config.h"
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #ifdef HAVE_UNISTD_H
  29. #include <unistd.h>
  30. #endif
  31. #include <sys/types.h>
  32.  
  33. #include <gtk/gtk.h>
  34.  
  35. #include <libgimp/gimp.h>
  36. #include <libgimp/gimpui.h>
  37.  
  38. #include "libgimp/stdplugins-intl.h"
  39.  
  40.  
  41. /***** Magic numbers *****/
  42. #define ITERATIONS      100
  43. #define WEIRD_FACTOR      0.04
  44.  
  45. #define PREVIEW_WIDTH    64
  46. #define PREVIEW_HEIGHT   64
  47. #define PROGRESS_WIDTH   32
  48. #define PROGRESS_HEIGHT  16
  49. #define SCALE_WIDTH     150
  50.  
  51.  
  52. /***** Types *****/
  53.  
  54. typedef struct
  55. {
  56.   gdouble lam_r;
  57.   gdouble lam_g;
  58.   gdouble lam_b;
  59.   gdouble contour_r;
  60.   gdouble contour_g;
  61.   gdouble contour_b;
  62.   gdouble edges_r;
  63.   gdouble edges_g;
  64.   gdouble edges_b;
  65.   gdouble brightness;
  66.   gdouble scattering;
  67.   gdouble polarization;
  68. } diffraction_vals_t;
  69.  
  70. typedef struct
  71. {
  72.   GtkWidget *preview;
  73.   GtkWidget *progress;
  74.   guchar     preview_row[PREVIEW_WIDTH * 3];
  75.  
  76.   gint run;
  77. } diffraction_interface_t;
  78.  
  79.  
  80. /***** Prototypes *****/
  81.  
  82. static void query (void);
  83. static void run   (gchar   *name,
  84.            gint     nparams,
  85.            GimpParam  *param,
  86.            gint    *nreturn_vals,
  87.            GimpParam **return_vals);
  88.  
  89. static void diffraction (GimpDrawable *drawable);
  90.  
  91. static void   diff_init_luts (void);
  92. static void   diff_diffract  (gdouble  x,
  93.                   gdouble  y,
  94.                   gdouble *r,
  95.                   gdouble *g,
  96.                   gdouble *b);
  97. static double diff_point     (gdouble  x,
  98.                   gdouble  y,
  99.                   gdouble  edges,
  100.                   gdouble  contours,
  101.                   gdouble  lam);
  102. static double diff_intensity (gdouble  x,
  103.                   gdouble  y,
  104.                   gdouble  lam);
  105.  
  106. static gint diffraction_dialog     (void);
  107. static void dialog_update_preview  (void);
  108. static void dialog_update_callback (GtkWidget *widget,
  109.                     gpointer   data);
  110. static void dialog_ok_callback     (GtkWidget *widget,
  111.                     gpointer   data);
  112.  
  113. /***** Variables *****/
  114.  
  115. GimpPlugInInfo PLUG_IN_INFO =
  116. {
  117.   NULL,  /* init  */
  118.   NULL,  /* quit  */
  119.   query, /* query */
  120.   run    /* run   */
  121. };
  122.  
  123. static diffraction_vals_t dvals =
  124. {
  125.   0.815,   /* lam_r */
  126.   1.221,   /* lam_g */
  127.   1.123,   /* lam_b */
  128.   0.821,   /* contour_r */
  129.   0.821,   /* contour_g */
  130.   0.974,   /* contour_b */
  131.   0.610,   /* edges_r */
  132.   0.677,   /* edges_g */
  133.   0.636,   /* edges_b */
  134.   0.066,   /* brightness */
  135.   37.126,   /* scattering */
  136.   -0.473    /* polarization */
  137. };
  138.  
  139. static diffraction_interface_t dint =
  140. {
  141.   NULL,  /* preview */
  142.   NULL,  /* progress */
  143.   { 0 }, /* preview_row */
  144.   FALSE  /* run */
  145. };
  146.  
  147. static gdouble cos_lut[ITERATIONS + 1];
  148. static gdouble param_lut1[ITERATIONS + 1];
  149. static gdouble param_lut2[ITERATIONS + 1];
  150.  
  151.  
  152. /***** Functions *****/
  153.  
  154. MAIN ()
  155.  
  156. static void
  157. query (void)
  158. {
  159.   static GimpParamDef args[] =
  160.   {
  161.     { GIMP_PDB_INT32,    "run_mode",     "Interactive, non-interactive" },
  162.     { GIMP_PDB_IMAGE,    "image",        "Input image" },
  163.     { GIMP_PDB_DRAWABLE, "drawable",     "Input drawable" },
  164.     { GIMP_PDB_FLOAT,    "lam_r",        "Light frequency (red)" },
  165.     { GIMP_PDB_FLOAT,       "lam_g",        "Light frequency (green)" },
  166.     { GIMP_PDB_FLOAT,       "lam_b",        "Light frequency (blue)" },
  167.     { GIMP_PDB_FLOAT,       "contour_r",    "Number of contours (red)" },
  168.     { GIMP_PDB_FLOAT,       "contour_g",    "Number of contours (green)" },
  169.     { GIMP_PDB_FLOAT,       "contour_b",    "Number of contours (blue)" },
  170.     { GIMP_PDB_FLOAT,       "edges_r",      "Number of sharp edges (red)" },
  171.     { GIMP_PDB_FLOAT,       "edges_g",      "Number of sharp edges (green)" },
  172.     { GIMP_PDB_FLOAT,       "edges_b",      "Number of sharp edges (blue)" },
  173.     { GIMP_PDB_FLOAT,       "brightness",   "Brightness and shifting/fattening of contours" },
  174.     { GIMP_PDB_FLOAT,       "scattering",   "Scattering (Speed vs. quality)" },
  175.     { GIMP_PDB_FLOAT,       "polarization", "Polarization" }
  176.   };
  177.   static gint nargs = sizeof (args) / sizeof (args[0]);
  178.  
  179.   gimp_install_procedure ("plug_in_diffraction",
  180.               "Generate diffraction patterns",
  181.               "Help?  What help?  Real men do not need help :-)",  /* FIXME */
  182.               "Federico Mena Quintero",
  183.               "Federico Mena Quintero & David Bleecker",
  184.               "April 1997, 0.5",
  185.               N_("<Image>/Filters/Render/Pattern/Diffraction Patterns..."),
  186.               "RGB*",
  187.               GIMP_PLUGIN,
  188.               nargs, 0,
  189.               args, NULL);
  190. }
  191.  
  192. static void
  193. run (gchar   *name,
  194.      gint     nparams,
  195.      GimpParam  *param,
  196.      gint    *nreturn_vals,
  197.      GimpParam **return_vals)
  198. {
  199.   static GimpParam values[1];
  200.  
  201.   GimpDrawable    *active_drawable;
  202.   GimpRunModeType  run_mode;
  203.   GimpPDBStatusType   status;
  204.  
  205.   /* Initialize */
  206.  
  207.   diff_init_luts ();
  208.  
  209.   status   = GIMP_PDB_SUCCESS;
  210.   run_mode = param[0].data.d_int32;
  211.  
  212.   values[0].type          = GIMP_PDB_STATUS;
  213.   values[0].data.d_status = status;
  214.  
  215.   *nreturn_vals = 1;
  216.   *return_vals  = values;
  217.  
  218.   switch (run_mode)
  219.     {
  220.     case GIMP_RUN_INTERACTIVE:
  221.       INIT_I18N_UI();
  222.  
  223.       /* Possibly retrieve data */
  224.       gimp_get_data ("plug_in_diffraction", &dvals);
  225.  
  226.       /* Get information from the dialog */
  227.       if (!diffraction_dialog ())
  228.     return;
  229.  
  230.       break;
  231.  
  232.     case GIMP_RUN_NONINTERACTIVE:
  233.       INIT_I18N();
  234.  
  235.       /* Make sure all the arguments are present */
  236.       if (nparams != 15)
  237.     status = GIMP_PDB_CALLING_ERROR;
  238.  
  239.       if (status == GIMP_PDB_SUCCESS)
  240.     {
  241.       dvals.lam_r          = param[3].data.d_float;
  242.       dvals.lam_g          = param[4].data.d_float;
  243.       dvals.lam_b        = param[5].data.d_float;
  244.       dvals.contour_r    = param[6].data.d_float;
  245.       dvals.contour_g    = param[7].data.d_float;
  246.       dvals.contour_b    = param[8].data.d_float;
  247.       dvals.edges_r      = param[9].data.d_float;
  248.       dvals.edges_g      = param[10].data.d_float;
  249.       dvals.edges_b      = param[11].data.d_float;
  250.       dvals.brightness   = param[12].data.d_float;
  251.       dvals.scattering   = param[13].data.d_float;
  252.       dvals.polarization = param[14].data.d_float;
  253.     }
  254.  
  255.       break;
  256.  
  257.     case GIMP_RUN_WITH_LAST_VALS:
  258.       INIT_I18N();
  259.  
  260.       /* Possibly retrieve data */
  261.       gimp_get_data ("plug_in_diffraction", &dvals);
  262.       break;
  263.  
  264.     default:
  265.       break;
  266.     }
  267.  
  268.   /* Get the active drawable */
  269.   active_drawable = gimp_drawable_get (param[2].data.d_drawable);
  270.  
  271.   /* Create the diffraction pattern */
  272.   if ((status == GIMP_PDB_SUCCESS) && gimp_drawable_is_rgb(active_drawable->id))
  273.     {
  274.       /* Set the tile cache size */
  275.       gimp_tile_cache_ntiles ((active_drawable->width + gimp_tile_width() - 1) /
  276.                   gimp_tile_width());
  277.  
  278.       /* Run! */
  279.       diffraction (active_drawable);
  280.  
  281.       /* If run mode is interactive, flush displays */
  282.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  283.     gimp_displays_flush ();
  284.  
  285.       /* Store data */
  286.       if (run_mode == GIMP_RUN_INTERACTIVE)
  287.     gimp_set_data ("plug_in_diffraction",
  288.                &dvals, sizeof(diffraction_vals_t));
  289.     }
  290.   else if (status == GIMP_PDB_SUCCESS)
  291.     status = GIMP_PDB_EXECUTION_ERROR;
  292.  
  293.   values[0].data.d_status = status;
  294.  
  295.   gimp_drawable_detach (active_drawable);
  296. }
  297.  
  298. static void
  299. diffraction (GimpDrawable *drawable)
  300. {
  301.   GimpPixelRgn dest_rgn;
  302.   gpointer  pr;
  303.   gint      x1, y1, x2, y2;
  304.   gint      width, height;
  305.   gint      has_alpha;
  306.   gint      row, col;
  307.   guchar   *dest_row;
  308.   guchar   *dest;
  309.   gint      progress, max_progress;
  310.   double    left, right, bottom, top;
  311.   double    dhoriz, dvert;
  312.   double    px, py;
  313.   double    r, g, b;
  314.  
  315.   /* Get the mask bounds and image size */
  316.  
  317.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  318.  
  319.   width  = x2 - x1;
  320.   height = y2 - y1;
  321.  
  322.   has_alpha = gimp_drawable_has_alpha (drawable->id);
  323.  
  324.   /* Initialize pixel regions */
  325.  
  326.   gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, TRUE, TRUE);
  327.  
  328.   progress     = 0;
  329.   max_progress = width * height;
  330.  
  331.   gimp_progress_init (_("Creating diffraction pattern..."));
  332.  
  333.   /* Create diffraction pattern */
  334.  
  335.   left   = -5.0;
  336.   right  =  5.0;
  337.   bottom = -5.0;
  338.   top    =  5.0;
  339.  
  340.   dhoriz = (right - left) / (width - 1);
  341.   dvert  = (bottom - top) / (height - 1);
  342.  
  343.   for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
  344.        pr != NULL;
  345.        pr = gimp_pixel_rgns_process (pr))
  346.     {
  347.       dest_row = dest_rgn.data;
  348.  
  349.       py = top + dvert * (dest_rgn.y - y1);
  350.  
  351.       for (row = 0; row < dest_rgn.h; row++)
  352.     {
  353.       dest = dest_row;
  354.  
  355.       px = left + dhoriz * (dest_rgn.x - x1);
  356.  
  357.       for (col = 0; col < dest_rgn.w; col++)
  358.         {
  359.           diff_diffract (px, py, &r, &g, &b);
  360.  
  361.           *dest++ = 255.0 * r;
  362.           *dest++ = 255.0 * g;
  363.           *dest++ = 255.0 * b;
  364.  
  365.           if (has_alpha)
  366.         *dest++ = 255;
  367.  
  368.           px += dhoriz;
  369.         }
  370.  
  371.       /* Update progress */
  372.  
  373.       progress += dest_rgn.w;
  374.       gimp_progress_update ((double) progress / max_progress);
  375.  
  376.       py       += dvert;
  377.       dest_row += dest_rgn.rowstride;
  378.     }
  379.     }
  380.  
  381.   gimp_drawable_flush (drawable);
  382.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  383.   gimp_drawable_update (drawable->id, x1, y1, width, height);
  384. }
  385.  
  386. static void
  387. diff_init_luts (void)
  388. {
  389.   int    i;
  390.   double a;
  391.   double sina;
  392.  
  393.   a = -G_PI;
  394.  
  395.   for (i = 0; i <= ITERATIONS; i++)
  396.     {
  397.       sina = sin (a);
  398.  
  399.       cos_lut[i]    = cos (a);
  400.  
  401.       param_lut1[i] = 0.75 * sina;
  402.       param_lut2[i] = 0.5 * (4.0 * cos_lut[i] * cos_lut[i] + sina * sina);
  403.  
  404.       a += (2.0 * G_PI / ITERATIONS);
  405.     }
  406. }
  407.  
  408. static void
  409. diff_diffract (double  x,
  410.            double  y,
  411.            double *r,
  412.            double *g,
  413.            double *b)
  414. {
  415.   *r = diff_point (x, y, dvals.edges_r, dvals.contour_r, dvals.lam_r);
  416.   *g = diff_point (x, y, dvals.edges_g, dvals.contour_g, dvals.lam_g);
  417.   *b = diff_point (x, y, dvals.edges_b, dvals.contour_b, dvals.lam_b);
  418. }
  419.  
  420. static double
  421. diff_point (double x,
  422.         double y,
  423.         double edges,
  424.         double contours,
  425.         double lam)
  426. {
  427.   return fabs (edges * sin (contours * atan (dvals.brightness *
  428.                          diff_intensity (x, y, lam))));
  429. }
  430.  
  431. static double
  432. diff_intensity (double x,
  433.         double y,
  434.         double lam)
  435. {
  436.   int    i;
  437.   double cxy, sxy;
  438.   double param;
  439.   double polpi2;
  440.   double cospolpi2, sinpolpi2;
  441.  
  442.   cxy = 0.0;
  443.   sxy = 0.0;
  444.  
  445.   lam *= 4.0;
  446.  
  447.   for (i = 0; i <= ITERATIONS; i++)
  448.     {
  449.       param = lam *
  450.     (cos_lut[i] * x +
  451.      param_lut1[i] * y -
  452.      param_lut2[i]);
  453.  
  454.       cxy += cos (param);
  455.       sxy += sin (param);
  456.     }
  457.  
  458.   cxy *= WEIRD_FACTOR;
  459.   sxy *= WEIRD_FACTOR;
  460.  
  461.   polpi2 = dvals.polarization * (G_PI / 2.0);
  462.  
  463.   cospolpi2 = cos (polpi2);
  464.   sinpolpi2 = sin (polpi2);
  465.  
  466.   return dvals.scattering * ((cospolpi2 + sinpolpi2) * cxy * cxy +
  467.                  (cospolpi2 - sinpolpi2) * sxy * sxy);
  468. }
  469.  
  470. #if 0
  471. static double
  472. diff_intensity (double x,
  473.         double y,
  474.         double lam)
  475. {
  476.   int    i;
  477.   double cxy, sxy;
  478.   double s;
  479.   double cosa, sina;
  480.   double twocosa, param;
  481.   double polpi2;
  482.   double cospolpi2, sinpolpi2;
  483.  
  484.   s   = dvals.scattering;
  485.   cxy = 0.0;
  486.   sxy = 0.0;
  487.  
  488.   for (i = 0; i <= ITERATIONS; i++)
  489.     {
  490.       cosa = cos_lut[i];
  491.       sina = sin_lut[i];
  492.  
  493.       twocosa = 2.0 * cosa;
  494.  
  495.       param = 4.0 * lam *
  496.     (cosa * x +
  497.      0.75 * sina * y -
  498.      0.5 * (twocosa * twocosa + sina * sina));
  499.  
  500.       cxy += 0.04 * cos (param);
  501.       sxy += 0.04 * sin (param);
  502.     }
  503.  
  504.   polpi2 = dvals.polarization * (G_PI / 2.0);
  505.  
  506.   cospolpi2 = cos (polpi2);
  507.   sinpolpi2 = sin (polpi2);
  508.  
  509.   return s * ((cospolpi2 + sinpolpi2) * cxy * cxy +
  510.           (cospolpi2 - sinpolpi2) * sxy * sxy);
  511. }
  512. #endif
  513.  
  514. static gint
  515. diffraction_dialog (void)
  516. {
  517.   GtkWidget *dialog;
  518.   GtkWidget *top_table;
  519.   GtkWidget *notebook;
  520.   GtkWidget *frame;
  521.   GtkWidget *vbox;
  522.   GtkWidget *table;
  523.   GtkWidget *label;
  524.   GtkWidget *button;
  525.   GtkObject *adj;
  526.  
  527.   gimp_ui_init ("diffraction", TRUE);
  528.  
  529.   dialog = gimp_dialog_new (_("Diffraction Patterns"), "diffraction",
  530.                 gimp_standard_help_func, "filters/diffraction.html",
  531.                 GTK_WIN_POS_MOUSE,
  532.                 FALSE, TRUE, FALSE,
  533.  
  534.                 _("OK"), dialog_ok_callback,
  535.                 NULL, NULL, NULL, TRUE, FALSE,
  536.                 _("Cancel"), gtk_widget_destroy,
  537.                 NULL, 1, NULL, FALSE, TRUE,
  538.  
  539.                 NULL);
  540.  
  541.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  542.               GTK_SIGNAL_FUNC (gtk_main_quit),
  543.               NULL);
  544.  
  545.   top_table = gtk_table_new (2, 2, FALSE);
  546.   gtk_container_set_border_width(GTK_CONTAINER (top_table), 6);
  547.   gtk_table_set_row_spacings (GTK_TABLE (top_table), 4);
  548.   gtk_table_set_col_spacings (GTK_TABLE (top_table), 4);
  549.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_table,
  550.               FALSE, FALSE, 0);
  551.   gtk_widget_show (top_table);
  552.  
  553.   /* Preview */
  554.  
  555.   vbox = gtk_vbox_new (FALSE, 0);
  556.   gtk_table_attach (GTK_TABLE (top_table), vbox, 0, 1, 0, 1,
  557.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  558.   gtk_widget_show (vbox);
  559.  
  560.   frame = gtk_frame_new (NULL);
  561.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  562.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  563.   gtk_widget_show (frame);
  564.  
  565.   dint.preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  566.   gtk_preview_size (GTK_PREVIEW(dint.preview), PREVIEW_WIDTH, PREVIEW_HEIGHT);
  567.   gtk_container_add (GTK_CONTAINER (frame), dint.preview);
  568.   gtk_widget_show (dint.preview);
  569.  
  570.   dint.progress = gtk_progress_bar_new ();
  571.   gtk_widget_set_usize (dint.progress, PROGRESS_WIDTH, PROGRESS_HEIGHT);
  572.   gtk_box_pack_start (GTK_BOX (vbox), dint.progress, TRUE, FALSE, 0);
  573.   gtk_widget_show (dint.progress);
  574.  
  575.   button = gtk_button_new_with_label (_("Preview!"));
  576.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  577.               GTK_SIGNAL_FUNC (dialog_update_callback),
  578.               NULL);
  579.   gtk_table_attach (GTK_TABLE (top_table), button, 0, 1, 1, 2,
  580.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  581.   gtk_widget_show (button);
  582.  
  583.   /* Notebook */
  584.  
  585.   notebook = gtk_notebook_new ();
  586.   gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
  587.   gtk_table_attach (GTK_TABLE (top_table), notebook, 1, 2, 0, 2,
  588.             GTK_EXPAND | GTK_FILL, 0, 0, 0);
  589.   gtk_widget_show (notebook);
  590.  
  591.   /* Frequencies tab */
  592.  
  593.   table = gtk_table_new (3, 3, FALSE);
  594.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  595.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  596.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  597.   gtk_widget_show (table);
  598.  
  599.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  600.                   _("Red:"), SCALE_WIDTH, 0,
  601.                   dvals.lam_r, 0.0, 20.0, 0.2, 1.0, 3,
  602.                   TRUE, 0, 0,
  603.                   NULL, NULL);
  604.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  605.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  606.               &dvals.lam_r);
  607.  
  608.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  609.                   _("Green:"), SCALE_WIDTH, 0,
  610.                   dvals.lam_g, 0.0, 20.0, 0.2, 1.0, 3,
  611.                   TRUE, 0, 0,
  612.                   NULL, NULL);
  613.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  614.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  615.               &dvals.lam_g);
  616.  
  617.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  618.                   _("Blue:"), SCALE_WIDTH, 0,
  619.                   dvals.lam_b, 0.0, 20.0, 0.2, 1.0, 3,
  620.                   TRUE, 0, 0,
  621.                   NULL, NULL);
  622.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  623.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  624.               &dvals.lam_b);
  625.  
  626.   label = gtk_label_new (_("Frequencies"));
  627.   gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
  628.   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label);
  629.  
  630.   /* Contours tab */
  631.  
  632.   table = gtk_table_new (3, 3, FALSE);
  633.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  634.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  635.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  636.   gtk_widget_show (table);
  637.  
  638.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  639.                   _("Red:"), SCALE_WIDTH, 0,
  640.                   dvals.contour_r, 0.0, 10.0, 0.1, 1.0, 3,
  641.                   TRUE, 0, 0,
  642.                   NULL, NULL);
  643.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  644.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  645.               &dvals.contour_r);
  646.  
  647.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  648.                   _("Green:"), SCALE_WIDTH, 0,
  649.                   dvals.contour_g, 0.0, 10.0, 0.1, 1.0, 3,
  650.                   TRUE, 0, 0,
  651.                   NULL, NULL);
  652.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  653.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  654.               &dvals.contour_g);
  655.  
  656.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  657.                   _("Blue:"), SCALE_WIDTH, 0,
  658.                   dvals.contour_b, 0.0, 10.0, 0.1, 1.0, 3,
  659.                   TRUE, 0, 0,
  660.                   NULL, NULL);
  661.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  662.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  663.               &dvals.contour_b);
  664.  
  665.   label = gtk_label_new (_("Contours"));
  666.   gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
  667.   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label);
  668.  
  669.   /* Sharp edges tab */
  670.  
  671.   table = gtk_table_new (3, 2, FALSE);
  672.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  673.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  674.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  675.   gtk_widget_show (table);
  676.  
  677.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  678.                   _("Red:"), SCALE_WIDTH, 0,
  679.                   dvals.edges_r, 0.0, 1.0, 0.01, 0.1, 3,
  680.                   TRUE, 0, 0,
  681.                   NULL, NULL);
  682.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  683.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  684.               &dvals.edges_r);
  685.  
  686.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  687.                   _("Green:"), SCALE_WIDTH, 0,
  688.                   dvals.edges_g, 0.0, 1.0, 0.01, 0.1, 3,
  689.                   TRUE, 0, 0,
  690.                   NULL, NULL);
  691.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  692.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  693.               &dvals.edges_g);
  694.  
  695.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  696.                   _("Blue:"), SCALE_WIDTH, 0,
  697.                   dvals.edges_b, 0.0, 1.0, 0.01, 0.1, 3,
  698.                   TRUE, 0, 0,
  699.                   NULL, NULL);
  700.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  701.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  702.               &dvals.edges_b);
  703.  
  704.   label = gtk_label_new (_("Sharp edges"));
  705.   gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
  706.   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label);
  707.  
  708.   /* Other options tab */
  709.  
  710.   table = gtk_table_new (3, 2, FALSE);
  711.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  712.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  713.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  714.   gtk_widget_show (table);
  715.  
  716.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  717.                   _("Brightness:"), SCALE_WIDTH, 0,
  718.                   dvals.brightness, 0.0, 1.0, 0.01, 0.1, 3,
  719.                   TRUE, 0, 0,
  720.                   NULL, NULL);
  721.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  722.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  723.               &dvals.brightness);
  724.  
  725.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  726.                   _("Scattering:"), SCALE_WIDTH, 0,
  727.                   dvals.scattering, 0.0, 100.0, 1.0, 10.0, 3,
  728.                   TRUE, 0, 0,
  729.                   NULL, NULL);
  730.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  731.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  732.               &dvals.scattering);
  733.  
  734.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  735.                   _("Polatization:"), SCALE_WIDTH, 0,
  736.                   dvals.polarization, -1.0, 1.0, 0.02, 0.2, 3,
  737.                   TRUE, 0, 0,
  738.                   NULL, NULL);
  739.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  740.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  741.               &dvals.polarization);
  742.  
  743.   label = gtk_label_new (_("Other options"));
  744.   gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
  745.   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label);
  746.  
  747.   /* Done */
  748.  
  749.   gtk_widget_show (dialog);
  750.   dialog_update_preview ();
  751.  
  752.   gtk_main ();
  753.   gdk_flush ();
  754.  
  755.   return dint.run;
  756. }
  757.  
  758. static void
  759. dialog_update_preview (void)
  760. {
  761.   double  left, right, bottom, top;
  762.   double  px, py;
  763.   double  dx, dy;
  764.   double  r, g, b;
  765.   int     x, y;
  766.   guchar *p;
  767.  
  768.   left   = -5.0;
  769.   right  =  5.0;
  770.   bottom = -5.0;
  771.   top    =  5.0;
  772.  
  773.   dx = (right - left) / (PREVIEW_WIDTH - 1);
  774.   dy = (bottom - top) / (PREVIEW_HEIGHT - 1);
  775.  
  776.   py = top;
  777.  
  778.   for (y = 0; y < PREVIEW_HEIGHT; y++)
  779.     {
  780.       px = left;
  781.       p  = dint.preview_row;
  782.  
  783.       for (x = 0; x < PREVIEW_WIDTH; x++)
  784.     {
  785.       diff_diffract (px, py, &r, &g, &b);
  786.  
  787.       *p++ = 255.0 * r;
  788.       *p++ = 255.0 * g;
  789.       *p++ = 255.0 * b;
  790.  
  791.       px += dx;
  792.     }
  793.  
  794.       gtk_preview_draw_row (GTK_PREVIEW (dint.preview),
  795.                 dint.preview_row, 0, y, PREVIEW_WIDTH);
  796.  
  797.       gtk_progress_bar_update (GTK_PROGRESS_BAR (dint.progress),
  798.                    (double) y / (double) (PREVIEW_HEIGHT - 1));
  799.       gtk_widget_draw (dint.progress, NULL);
  800.       gdk_flush ();
  801.  
  802.       py += dy;
  803.     }
  804.  
  805.   gtk_widget_draw (dint.preview, NULL);
  806.   gtk_progress_bar_update (GTK_PROGRESS_BAR (dint.progress), 0.0);
  807.   gdk_flush ();
  808. }
  809.  
  810. static void
  811. dialog_update_callback (GtkWidget *widget,
  812.             gpointer   data)
  813. {
  814.   dialog_update_preview ();
  815. }
  816.  
  817. static void
  818. dialog_ok_callback (GtkWidget *widget,
  819.             gpointer   data)
  820. {
  821.   dint.run = TRUE;
  822.  
  823.   gtk_widget_destroy (GTK_WIDGET (data));
  824. }
  825.