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 / waves.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-28  |  21.0 KB  |  843 lines

  1. /**************************************************
  2.  * file: waves/waves.c
  3.  *
  4.  * Copyright (c) 1997 Eric L. Hernes (erich@rrnet.com)
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. The name of the author may not be used to endorse or promote products
  13.  *    derived from this software withough specific prior written permission
  14.  *
  15.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  *
  26.  * $Id: waves.c,v 1.17 2000/08/28 00:42:20 mitch Exp $
  27.  */
  28.  
  29. #include "config.h"
  30.  
  31. #include <string.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. enum
  43. {
  44.   MODE_SMEAR,
  45.   MODE_BLACKEN
  46. };
  47.  
  48. struct Grgb
  49. {
  50.   guint8 red;
  51.   guint8 green;
  52.   guint8 blue;
  53. };
  54.  
  55. struct GRegion
  56. {
  57.   gint32 x;
  58.   gint32 y;
  59.   gint32 width;
  60.   gint32 height;
  61. };
  62.  
  63. struct piArgs
  64. {
  65.   gdouble amplitude;
  66.   gdouble phase;
  67.   gdouble wavelength;
  68.   gint32  type;
  69.   gint32  reflective;
  70. };
  71.  
  72. /*  preview stuff -- to be removed as soon as we have a real libgimp preview  */
  73.  
  74. struct mwPreview
  75. {
  76.   gint     width;
  77.   gint     height;
  78.   gint     bpp;
  79.   gdouble  scale;
  80.   guchar  *bits;
  81. };
  82.  
  83. #define PREVIEW_SIZE 100
  84.  
  85. static gint do_preview = TRUE;
  86.  
  87. static GtkWidget        * mw_preview_new   (GtkWidget        *parent,
  88.                                             struct mwPreview *mwp);
  89. static struct mwPreview * mw_preview_build (GimpDrawable        *drawable);
  90.  
  91. static struct mwPreview *mwp;
  92.  
  93.  
  94. static void query (void);
  95. static void run   (gchar   *name,
  96.            gint     nparam,
  97.            GimpParam  *param,
  98.            gint    *nretvals,
  99.            GimpParam **retvals);
  100.  
  101. static gint pluginCore       (struct piArgs *argp,
  102.                   gint32         drawable);
  103. static gint pluginCoreIA     (struct piArgs *argp,
  104.                   gint32         drawable);
  105.  
  106. static void waves_do_preview (GtkWidget     *preview);
  107.  
  108. static void wave (guchar  *src,
  109.           guchar  *dest,
  110.           gint     width,
  111.           gint     height,
  112.           gint     bypp,
  113.           gdouble  amplitude,
  114.           gdouble  wavelength,
  115.           gdouble  phase,
  116.           gint     smear,
  117.           gint     reflective,
  118.           gint     verbose);
  119.  
  120. static guchar bilinear (gdouble x,
  121.             gdouble y,
  122.             guchar *v);
  123.  
  124. #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? TRUE : FALSE)
  125.  
  126. GimpPlugInInfo PLUG_IN_INFO =
  127. {
  128.   NULL,  /* init_proc  */
  129.   NULL,  /* quit_proc  */
  130.   query, /* query_proc */
  131.   run,   /* run_proc   */
  132. };
  133.  
  134. MAIN ()
  135.  
  136. static void
  137. query (void)
  138. {
  139.   static GimpParamDef args[] =
  140.   {
  141.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  142.     { GIMP_PDB_IMAGE, "image", "The Image" },
  143.     { GIMP_PDB_DRAWABLE, "drawable", "The Drawable" },
  144.     { GIMP_PDB_FLOAT, "amplitude", "The Amplitude of the Waves" },
  145.     { GIMP_PDB_FLOAT, "phase", "The Phase of the Waves" },
  146.     { GIMP_PDB_FLOAT, "wavelength", "The Wavelength of the Waves" },
  147.     { GIMP_PDB_INT32, "type", "Type of waves, black/smeared" },
  148.     { GIMP_PDB_INT32, "reflective", "Use Reflection" }
  149.   };
  150.   static gint nargs = sizeof (args) / sizeof (args[0]);
  151.  
  152.   gimp_install_procedure ("plug_in_waves",
  153.               "Distort the image with waves",
  154.               "none yet",
  155.               "Eric L. Hernes, Stephen Norris",
  156.               "Stephen Norris",
  157.               "1997",
  158.               N_("<Image>/Filters/Distorts/Waves..."),
  159.               "RGB*, GRAY*",
  160.               GIMP_PLUGIN,
  161.               nargs, 0,
  162.               args, NULL);
  163. }
  164.  
  165. static void
  166. run (gchar   *name,
  167.      gint     nparam,
  168.      GimpParam  *param,
  169.      gint    *nretvals,
  170.      GimpParam **retvals)
  171. {
  172.   static GimpParam rvals[1];
  173.  
  174.   struct piArgs args;
  175.  
  176.   *nretvals = 1;
  177.   *retvals = rvals;
  178.  
  179.   memset (&args, (int) 0, sizeof (struct piArgs));
  180.   args.type = -1;
  181.   gimp_get_data ("plug_in_waves", &args);
  182.  
  183.   rvals[0].type = GIMP_PDB_STATUS;
  184.   rvals[0].data.d_status = GIMP_PDB_SUCCESS;
  185.   switch (param[0].data.d_int32)
  186.     {
  187.       GimpDrawable *drawable;
  188.  
  189.     case GIMP_RUN_INTERACTIVE:
  190.       INIT_I18N_UI();
  191.       /* XXX: add code here for interactive running */
  192.       if (args.type == -1)
  193.     {
  194.       args.amplitude  = 10.0;
  195.       args.wavelength = 10;
  196.       args.phase      = 0.0;
  197.       args.type       = MODE_SMEAR;
  198.       args.reflective = 0;
  199.     }
  200.  
  201.       drawable = gimp_drawable_get (param[2].data.d_drawable);
  202.       mwp = mw_preview_build (drawable);
  203.  
  204.       if (pluginCoreIA(&args, param[2].data.d_drawable) == -1)
  205.     {
  206.       rvals[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  207.     }
  208.       else
  209.     {
  210.       gimp_set_data ("plug_in_waves", &args, sizeof (struct piArgs));
  211.     }
  212.  
  213.     break;
  214.  
  215.     case GIMP_RUN_NONINTERACTIVE:
  216.       INIT_I18N();
  217.       /* XXX: add code here for non-interactive running */
  218.       if (nparam != 8)
  219.     {
  220.       rvals[0].data.d_status = GIMP_PDB_CALLING_ERROR;
  221.       break;
  222.     }
  223.       args.amplitude  = param[3].data.d_float;
  224.       args.phase      = param[4].data.d_float;
  225.       args.wavelength = param[5].data.d_float;
  226.       args.type       = param[6].data.d_int32;
  227.       args.reflective = param[7].data.d_int32;
  228.  
  229.       if (pluginCore (&args, param[2].data.d_drawable) == -1)
  230.     {
  231.       rvals[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  232.       break;
  233.     }
  234.     break;
  235.  
  236.     case GIMP_RUN_WITH_LAST_VALS:
  237.       INIT_I18N();
  238.       /* XXX: add code here for last-values running */
  239.       if (pluginCore (&args, param[2].data.d_drawable) == -1)
  240.     {
  241.       rvals[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  242.     }
  243.       break;
  244.     }
  245. }
  246.  
  247. static gint
  248. pluginCore (struct piArgs *argp,
  249.         gint32         drawable)
  250. {
  251.   gint retval=0;
  252.   GimpDrawable *drw;
  253.   GimpPixelRgn srcPr, dstPr;
  254.   guchar *src, *dst;
  255.   guint width, height, Bpp;
  256.  
  257.   drw = gimp_drawable_get (drawable);
  258.  
  259.   width = drw->width;
  260.   height = drw->height;
  261.   Bpp = drw->bpp;
  262.  
  263.   src = g_new (guchar, width * height * Bpp);
  264.   dst = g_new (guchar, width * height * Bpp);
  265.   gimp_pixel_rgn_init (&srcPr, drw, 0, 0, width, height, FALSE, FALSE);
  266.   gimp_pixel_rgn_init (&dstPr, drw, 0, 0, width, height, TRUE, TRUE);
  267.   gimp_pixel_rgn_get_rect (&srcPr, src, 0, 0, width, height);
  268.  
  269.   wave (src, dst, width, height, Bpp, argp->amplitude, argp->wavelength,
  270.         argp->phase, argp->type==0, argp->reflective, 1);
  271.   gimp_pixel_rgn_set_rect (&dstPr, dst, 0, 0, width, height);
  272.  
  273.   g_free (src);
  274.   g_free (dst);
  275.  
  276.   gimp_drawable_flush (drw);
  277.   gimp_drawable_merge_shadow (drw->id, TRUE);
  278.   gimp_drawable_update (drw->id, 0, 0, width, height);
  279.  
  280.   gimp_displays_flush ();
  281.  
  282.   return retval;
  283. }
  284.  
  285. static gboolean run_flag = FALSE;
  286.  
  287. static void
  288. waves_ok_callback (GtkWidget *widget,
  289.            gpointer   data)
  290. {
  291.   run_flag = TRUE;
  292.  
  293.   gtk_widget_destroy (GTK_WIDGET (data));
  294. }
  295.  
  296. static void
  297. waves_toggle_button_update (GtkWidget *widget,
  298.                 gpointer   data)
  299. {
  300.   gimp_toggle_button_update (widget, data);
  301.  
  302.   if (do_preview)
  303.     waves_do_preview (NULL);
  304. }
  305.  
  306. static void
  307. waves_radio_button_update (GtkWidget *widget,
  308.                gpointer   data)
  309. {
  310.   gimp_radio_button_update (widget, data);
  311.  
  312.   if (do_preview && GTK_TOGGLE_BUTTON (widget)->active)
  313.     waves_do_preview (NULL);
  314. }
  315.  
  316. static void
  317. waves_double_adjustment_update (GtkAdjustment *adjustment,
  318.                 gpointer   data)
  319. {
  320.   gimp_double_adjustment_update (adjustment, data);
  321.  
  322.   if (do_preview)
  323.     waves_do_preview (NULL);
  324. }
  325.  
  326. static gint
  327. pluginCoreIA (struct piArgs *argp,
  328.           gint32         drawable)
  329. {
  330.   gint r=-1; /* default to error return */
  331.   GtkWidget *dlg;
  332.   GtkWidget *main_vbox;
  333.   GtkWidget *frame;
  334.   GtkWidget *hbox;
  335.   GtkWidget *vbox;
  336.   GtkWidget *sep;
  337.   GtkWidget *table;
  338.   GtkWidget *preview;
  339.   GtkWidget *toggle;
  340.   GtkObject *adj;
  341.  
  342.   gimp_ui_init ("waves", TRUE);
  343.  
  344.   dlg = gimp_dialog_new ( _("Waves"), "waves",
  345.              gimp_standard_help_func, "filters/waves.html",
  346.              GTK_WIN_POS_MOUSE,
  347.              FALSE, TRUE, FALSE,
  348.  
  349.              _("OK"), waves_ok_callback,
  350.              NULL, NULL, NULL, TRUE, FALSE,
  351.              _("Cancel"), gtk_widget_destroy,
  352.              NULL, 1, NULL, FALSE, TRUE,
  353.  
  354.              NULL);
  355.  
  356.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  357.               GTK_SIGNAL_FUNC (gtk_main_quit),
  358.               NULL);
  359.  
  360.   main_vbox = gtk_vbox_new (FALSE, 4);
  361.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  362.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox,
  363.               TRUE, TRUE, 0);
  364.   gtk_widget_show (main_vbox);
  365.  
  366.   hbox = gtk_hbox_new (FALSE, 4);
  367.   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
  368.   gtk_widget_show (hbox);
  369.  
  370.   preview = mw_preview_new (hbox, mwp);
  371.   gtk_object_set_data (GTK_OBJECT (preview), "piArgs", argp);
  372.   waves_do_preview (preview);
  373.  
  374.   frame = gimp_radio_group_new2 (TRUE, _("Mode"),
  375.                  waves_radio_button_update,
  376.                  &argp->type, (gpointer) argp->type,
  377.  
  378.                  _("Smear"),   (gpointer) MODE_SMEAR, NULL,
  379.                  _("Blacken"), (gpointer) MODE_BLACKEN, NULL,
  380.  
  381.                  NULL);
  382.   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
  383.   gtk_widget_show (frame);
  384.  
  385.   vbox = GTK_BIN (frame)->child;
  386.  
  387.   sep = gtk_hseparator_new ();
  388.   gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 2);
  389.   gtk_widget_show (sep);
  390.  
  391.   toggle = gtk_check_button_new_with_label ( _("Reflective"));
  392.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), argp->reflective);
  393.   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
  394.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  395.               GTK_SIGNAL_FUNC (waves_toggle_button_update),
  396.               &argp->reflective);
  397.   gtk_widget_show (toggle);
  398.  
  399.   frame = gtk_frame_new ( _("Parameter Settings"));
  400.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  401.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  402.   gtk_widget_show (frame);
  403.  
  404.   table = gtk_table_new (3, 3, FALSE);
  405.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  406.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  407.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  408.   gtk_container_add (GTK_CONTAINER (frame), table);
  409.  
  410.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  411.                   _("Amplitude:"), 140, 0,
  412.                   argp->amplitude, 0.0, 101.0, 1.0, 5.0, 2,
  413.                   TRUE, 0, 0,
  414.                   NULL, NULL);
  415.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  416.               GTK_SIGNAL_FUNC (waves_double_adjustment_update),
  417.               &argp->amplitude);
  418.  
  419.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  420.                   _("Phase:"), 140, 0,
  421.                   argp->phase, 0.0, 360.0, 2.0, 5.0, 2,
  422.                   TRUE, 0, 0,
  423.                   NULL, NULL);
  424.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  425.               GTK_SIGNAL_FUNC (waves_double_adjustment_update),
  426.               &argp->phase);
  427.  
  428.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  429.                   _("Wavelength:"), 140, 0,
  430.                   argp->wavelength, 0.1, 50.0, 1.0, 5.0, 2,
  431.                   TRUE, 0, 0,
  432.                   NULL, NULL);
  433.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  434.               GTK_SIGNAL_FUNC (waves_double_adjustment_update),
  435.               &argp->wavelength);
  436.  
  437.   gtk_widget_show (table);
  438.  
  439.   gtk_widget_show (dlg);
  440.  
  441.   gtk_main ();
  442.   gdk_flush ();
  443.  
  444.   if (run_flag)
  445.     {
  446. #if 0
  447.       fprintf (stderr, "running:\n");
  448.       /*fprintf (stderr, "\t(image %d)\n", argp->image);*/
  449.       fprintf (stderr, "\t(drawable %d)\n", argp->drawable);
  450.       fprintf (stderr, "\t(amplitude %f)\n", argp->amplitude);
  451.       fprintf (stderr, "\t(phase %f)\n", argp->phase);
  452.       fprintf (stderr, "\t(wavelength %f)\n", argp->wavelength);
  453.       fprintf (stderr, "\t(type %d)\n", argp->type);
  454.       fprintf (stderr, "\t(reflective %d)\n", argp->reflective);
  455. #endif
  456.       return pluginCore (argp, drawable);
  457.     }
  458.   else
  459.     {
  460.       return r;
  461.     }
  462. }
  463.  
  464. static void
  465. waves_do_preview (GtkWidget *widget)
  466. {
  467.   static GtkWidget *theWidget = NULL;
  468.   struct piArgs *argp;
  469.   guchar *dst;
  470.   gint y;
  471.  
  472.   if (theWidget == NULL)
  473.     {
  474.       theWidget = widget;
  475.     }
  476.  
  477.   argp = gtk_object_get_data (GTK_OBJECT (theWidget), "piArgs");
  478.   dst = g_new (guchar, mwp->width * mwp->height * mwp->bpp);
  479.  
  480.   wave (mwp->bits, dst, mwp->width, mwp->height, mwp->bpp,
  481.     (argp->amplitude / mwp->scale), (argp->wavelength / mwp->scale),
  482.     argp->phase, argp->type == 0, argp->reflective, 0);
  483.  
  484.   for (y = 0; y < mwp->height; y++)
  485.     {
  486.       gtk_preview_draw_row (GTK_PREVIEW (theWidget),
  487.                 dst + (y * mwp->width * mwp->bpp), 0, y,
  488.                 mwp->width);
  489.     }
  490.  
  491.   gtk_widget_draw (theWidget, NULL);
  492.   gdk_flush ();
  493.   g_free (dst);
  494. }
  495.  
  496. static void
  497. mw_preview_toggle_callback (GtkWidget *widget,
  498.                             gpointer   data)
  499. {
  500.   gimp_toggle_button_update (widget, data);
  501.  
  502.   if (do_preview)
  503.     waves_do_preview (NULL);
  504. }
  505.  
  506. static struct mwPreview *
  507. mw_preview_build_virgin (GimpDrawable *drawable)
  508. {
  509.   struct mwPreview *mwp;
  510.  
  511.   mwp = g_new (struct mwPreview, 1);
  512.  
  513.   if (drawable->width > drawable->height)
  514.     {
  515.       mwp->scale  = (gdouble) drawable->width / (gdouble) PREVIEW_SIZE;
  516.       mwp->width  = PREVIEW_SIZE;
  517.       mwp->height = drawable->height / mwp->scale;
  518.     }
  519.   else
  520.     {
  521.       mwp->scale  = (gdouble) drawable->height / (gdouble) PREVIEW_SIZE;
  522.       mwp->height = PREVIEW_SIZE;
  523.       mwp->width  = drawable->width / mwp->scale;
  524.     }
  525.  
  526.   mwp->bpp  = 3;
  527.   mwp->bits = NULL;
  528.  
  529.   return mwp;
  530. }
  531.  
  532. static struct mwPreview *
  533. mw_preview_build (GimpDrawable *drawable)
  534. {
  535.   struct mwPreview *mwp;
  536.   gint x, y, b;
  537.   guchar *bc;
  538.   guchar *drawableBits;
  539.   GimpPixelRgn pr;
  540.  
  541.   mwp = mw_preview_build_virgin (drawable);
  542.  
  543.   gimp_pixel_rgn_init (&pr, drawable,
  544.                0, 0, drawable->width, drawable->height, FALSE, FALSE);
  545.   drawableBits = g_new (guchar, drawable->width * drawable->bpp);
  546.  
  547.   bc = mwp->bits = g_new (guchar, mwp->width * mwp->height * mwp->bpp);
  548.   for (y = 0; y < mwp->height; y++)
  549.     {
  550.       gimp_pixel_rgn_get_row (&pr, drawableBits,
  551.                   0, (gint) (y * mwp->scale), drawable->width);
  552.  
  553.       for (x = 0; x < mwp->width; x++)
  554.         {
  555.           for (b = 0; b < mwp->bpp; b++)
  556.             *bc++ = *(drawableBits +
  557.                       ((gint) (x * mwp->scale) * drawable->bpp) +
  558.               b % drawable->bpp);
  559.         }
  560.     }
  561.   g_free (drawableBits);
  562.  
  563.   return mwp;
  564. }
  565.  
  566. static GtkWidget *
  567. mw_preview_new (GtkWidget        *parent,
  568.                 struct mwPreview *mwp)
  569. {
  570.   GtkWidget *preview;
  571.   GtkWidget *frame;
  572.   GtkWidget *pframe;
  573.   GtkWidget *vbox;
  574.   GtkWidget *button;
  575.  
  576.   frame = gtk_frame_new (_("Preview"));
  577.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  578.   gtk_box_pack_start (GTK_BOX (parent), frame, FALSE, FALSE, 0);
  579.   gtk_widget_show (frame);
  580.  
  581.   vbox = gtk_vbox_new (FALSE, 2);
  582.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  583.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  584.   gtk_widget_show (vbox);
  585.  
  586.   pframe = gtk_frame_new (NULL);
  587.   gtk_frame_set_shadow_type (GTK_FRAME(pframe), GTK_SHADOW_IN);
  588.   gtk_box_pack_start (GTK_BOX (vbox), pframe, FALSE, FALSE, 0);
  589.   gtk_widget_show (pframe);
  590.  
  591.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  592.   gtk_preview_size (GTK_PREVIEW (preview), mwp->width, mwp->height);
  593.   gtk_container_add (GTK_CONTAINER (pframe), preview);
  594.   gtk_widget_show (preview);
  595.  
  596.   button = gtk_check_button_new_with_label (_("Do Preview"));
  597.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), do_preview);
  598.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  599.                       GTK_SIGNAL_FUNC (mw_preview_toggle_callback),
  600.                       &do_preview);
  601.   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  602.   gtk_widget_show (button);
  603.  
  604.   return preview;
  605. }
  606.  
  607.  
  608. static void
  609. wave (guchar  *src,
  610.       guchar  *dst,
  611.       gint     width,
  612.       gint     height,
  613.       gint     bypp,
  614.       gdouble  amplitude,
  615.       gdouble  wavelength,
  616.       gdouble  phase,
  617.       gint     smear,
  618.       gint     reflective,
  619.       gint     verbose)
  620. {
  621.   glong   rowsiz;
  622.   guchar *p;
  623.   guchar *dest;
  624.   gint    x1, y1, x2, y2;
  625.   gint    x, y;
  626.   gint    prog_interval=0;
  627.   gint    x1_in, y1_in, x2_in, y2_in;
  628.  
  629.   gdouble cen_x, cen_y;       /* Center of wave */
  630.   gdouble xhsiz, yhsiz;       /* Half size of selection */
  631.   gdouble radius, radius2;    /* Radius and radius^2 */
  632.   gdouble amnt, d;
  633.   gdouble needx, needy;
  634.   gdouble dx, dy;
  635.   gdouble xscale, yscale;
  636.  
  637.   gint xi, yi;
  638.  
  639.   guchar  values[4];
  640.   guchar  val;
  641.  
  642.   gint k;
  643.  
  644.   phase = phase * G_PI / 180;
  645.   rowsiz   = width * bypp;
  646.  
  647.   if (verbose)
  648.     {
  649.       gimp_progress_init (_("Waving..."));
  650.       prog_interval=height/10;
  651.     }
  652.  
  653.   x1 = y1 = 0;
  654.   x2 = width;
  655.   y2 = height;
  656.  
  657.   /* Wave the image.  For each pixel in the destination image
  658.    * which is inside the selection, we compute the corresponding
  659.    * waved location in the source image.  We use bilinear
  660.    * interpolation to avoid ugly jaggies.
  661.    *
  662.    * Let's assume that we are operating on a circular area.
  663.    * Every point within <radius> distance of the wave center is
  664.    * waveed to its destination position.
  665.    *
  666.    * Basically, introduce a wave into the image. I made up the
  667.    * forumla initially, but it looks good. Quartic added the
  668.    * wavelength etc. to it while I was asleep :) Just goes to show
  669.    * we should work with people in different time zones more.
  670.    *
  671.    */
  672.  
  673.   /* Center of selection */
  674.   cen_x = (double) (x2 - 1 + x1) / 2.0;
  675.   cen_y = (double) (y2 - 1 + y1) / 2.0;
  676.  
  677.   /* Compute wave radii (semiaxes) */
  678.   xhsiz = (double) (x2 - x1) / 2.0;
  679.   yhsiz = (double) (y2 - y1) / 2.0;
  680.  
  681.   /* These are the necessary scaling factors to turn the wave
  682.      ellipse into a large circle */
  683.  
  684.   if (xhsiz < yhsiz)
  685.     {
  686.       xscale = yhsiz / xhsiz;
  687.       yscale = 1.0;
  688.     }
  689.   else if (xhsiz > yhsiz)
  690.     {
  691.       xscale = 1.0;
  692.       yscale = xhsiz / yhsiz;
  693.     }
  694.   else
  695.     {
  696.       xscale = 1.0;
  697.       yscale = 1.0;
  698.     }
  699.  
  700.   radius  = MAX (xhsiz, yhsiz);
  701.   radius2 = radius * radius;
  702.  
  703.   /* Wave the image! */
  704.  
  705.   dst += y1 * rowsiz + x1 * bypp;
  706.  
  707.   wavelength *= 2;
  708.  
  709.   for (y = y1; y < y2; y++)
  710.     {
  711.       dest = dst;
  712.  
  713.       if (verbose && (y % prog_interval == 0))
  714.     gimp_progress_update ((double) y / (double) height);
  715.  
  716.       for (x = x1; x < x2; x++)
  717.     {
  718.       /* Distance from current point to wave center, scaled */
  719.       dx = (x - cen_x) * xscale;
  720.       dy = (y - cen_y) * yscale;
  721.  
  722.       /* Distance^2 to center of *circle* (our scaled ellipse) */
  723.       d = sqrt (dx * dx + dy * dy);
  724.  
  725.       /* Use the formula described above. */
  726.  
  727.       /* Calculate waved point and scale again to ellipsify */
  728.  
  729.       /*
  730.        * Reflective waves are strange - the effect is much
  731.        * more like a mirror which is in the shape of
  732.        * the wave than anything else.
  733.        */
  734.  
  735.       if (reflective)
  736.         {
  737.           amnt = amplitude * fabs (sin (((d / wavelength) * (2.0 * G_PI) +
  738.                          phase)));
  739.  
  740.           needx = (amnt * dx) / xscale + cen_x;
  741.           needy = (amnt * dy) / yscale + cen_y;
  742.         }
  743.       else
  744.         {
  745.           amnt = amplitude * sin (((d / wavelength) * (2.0 * G_PI) +
  746.                        phase));
  747.  
  748.           needx = (amnt + dx) / xscale + cen_x;
  749.           needy = (amnt + dy) / yscale + cen_y;
  750.         }
  751.  
  752.       /* Calculations complete; now copy the proper pixel */
  753.  
  754.       xi = needx;
  755.       yi = needy;
  756.  
  757.       if (smear)
  758.         {
  759.           if (xi > width - 2)
  760.         {
  761.           xi = width - 2;
  762.         }
  763.           else if (xi < 0)
  764.         {
  765.           xi = 0;
  766.         }
  767.           if (yi > height - 2)
  768.         {
  769.           yi = height - 2;
  770.         }
  771.           else if (yi < 0)
  772.         {
  773.           yi = 0;
  774.         }
  775.         }
  776.  
  777.       p = src + rowsiz * yi + xi * bypp;
  778.  
  779.       x1_in = WITHIN (0, xi, width - 1);
  780.       y1_in = WITHIN (0, yi, height - 1);
  781.       x2_in = WITHIN (0, xi + 1, width - 1);
  782.       y2_in = WITHIN (0, yi + 1, height - 1);
  783.  
  784.       for (k = 0; k < bypp; k++)
  785.         {
  786.           if (x1_in && y1_in)
  787.         values[0] = *(p + k);
  788.           else
  789.         values[0] = 0;
  790.  
  791.           if (x2_in && y1_in)
  792.         values[1] = *(p + bypp + k);
  793.           else
  794.         values[1] = 0;
  795.  
  796.           if (x1_in && y2_in)
  797.         values[2] = *(p + rowsiz + k);
  798.           else
  799.         values[2] = 0;
  800.  
  801.           if (x2_in)
  802.         {
  803.           if (y2_in)
  804.             values[3] = *(p + bypp + k + rowsiz);
  805.           else
  806.             values[3] = 0;
  807.         }
  808.           else
  809.         values[3] = 0;
  810.  
  811.           val = bilinear (needx, needy, values);
  812.  
  813.           *dest++ = val;
  814.         }
  815.     }
  816.  
  817.       dst += rowsiz;
  818.     }
  819.  
  820.   if (verbose)
  821.     gimp_progress_update (1.0);
  822. }
  823.  
  824. static guchar
  825. bilinear (gdouble  x,
  826.       gdouble  y,
  827.       guchar  *v)
  828. {
  829.   gdouble m0, m1;
  830.   x = fmod (x, 1.0);
  831.   y = fmod (y, 1.0);
  832.  
  833.   if (x < 0)
  834.     x += 1.0;
  835.   if (y < 0)
  836.     y += 1.0;
  837.  
  838.   m0 = (1.0 - x) * v[0] + x * v[1];
  839.   m1 = (1.0 - x) * v[2] + x * v[3];
  840.  
  841.   return (guchar) ((1.0 - y) * m0 + y * m1);
  842. }
  843.