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 / wind.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-01  |  31.6 KB  |  1,244 lines

  1. /*
  2.  * wind 1.1.0 - a plug-in for the GIMP
  3.  *
  4.  * Copyright (C) Nigel Wetten
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  *
  20.  * Contact info: nigel@cs.nwu.edu
  21.  * Version: 1.0.0
  22.  *
  23.  * Version: 1.1.0
  24.  * May 2000 tim copperfield [timecop@japan.co.jp]
  25.  *
  26.  * Added dynamic preview.
  27.  *
  28.  */
  29.  
  30. #include "config.h"
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35.  
  36. #include <gtk/gtk.h>
  37.  
  38. #include <libgimp/gimp.h>
  39. #include <libgimp/gimpui.h>
  40.  
  41. #include "libgimp/stdplugins-intl.h"
  42.  
  43.  
  44. #define PLUG_IN_NAME "wind"
  45.  
  46. #define COMPARE_WIDTH   3
  47.  
  48. #define SCALE_WIDTH   200
  49. #define MIN_THRESHOLD   0
  50. #define MAX_THRESHOLD  50
  51. #define MIN_STRENGTH    1
  52. #define MAX_STRENGTH   50
  53. #define PREVIEW_SIZE  128
  54.  
  55. typedef enum
  56. {
  57.   LEFT,
  58.   RIGHT
  59. } direction_t;
  60.  
  61. typedef enum
  62. {
  63.   RENDER_WIND,
  64.   RENDER_BLAST
  65. } algorithm_t;
  66.  
  67. typedef enum
  68. {
  69.   BOTH,
  70.   LEADING,
  71.   TRAILING
  72. } edge_t;
  73.  
  74.  
  75. static void query (void);
  76. static void run   (gchar   *name,
  77.            gint     nparams,
  78.            GimpParam  *param,
  79.            gint    *nreturn_vals,
  80.            GimpParam **return_vals);
  81.  
  82. static void dialog_box       (GimpDrawable   *drawable);
  83. static void ok_callback      (GtkWidget   *widget, 
  84.                   gpointer     data);
  85. static void radio_callback   (GtkWidget   *widget, 
  86.                   gpointer     data);
  87.  
  88. static gint render_effect    (GimpDrawable   *drawable, 
  89.                   gboolean     preview_mode);
  90. static void render_wind      (GimpDrawable   *drawable, 
  91.                   gint         threshold, 
  92.                   gint         strength,
  93.                   direction_t  direction, 
  94.                   edge_t       edge, 
  95.                   gboolean     preview_mode);
  96. static void render_blast     (GimpDrawable   *drawable, 
  97.                   gint         threshold, 
  98.                   gint         strength,
  99.                   direction_t  direction, 
  100.                   edge_t       edge, 
  101.                   gboolean     preview_mode);
  102. static gint render_blast_row (guchar      *buffer, 
  103.                   gint         bytes, 
  104.                   gint         lpi,
  105.                   gint         threshold,
  106.                   gint         strength, 
  107.                   edge_t       edge);
  108. static void render_wind_row  (guchar      *sb, 
  109.                   gint         bytes, 
  110.                   gint         lpi, 
  111.                   gint         threshold,
  112.                   gint         strength, 
  113.                   edge_t       edge);
  114.  
  115.  
  116. static void get_derivative     (guchar  *pixel_R1, 
  117.                 guchar  *pixel_R2,
  118.                 edge_t   edge, 
  119.                 gboolean has_alpha,
  120.                 gint    *derivative_R,
  121.                 gint    *derivative_G, 
  122.                 gint    *derivative_B,
  123.                 gint    *derivative_A);
  124. static gint threshold_exceeded (guchar  *pixel_R1, 
  125.                 guchar  *pixel_R2,
  126.                 edge_t   edge, 
  127.                 gint     threshold,
  128.                 gboolean has_alpha);
  129. static void reverse_buffer     (guchar  *buffer, 
  130.                 gint     length, 
  131.                 gint     bytes);
  132.  
  133. static void       fill_preview   (GtkWidget *preview_widget, 
  134.                   GimpDrawable *drawable);
  135. static GtkWidget *preview_widget (GimpDrawable *drawable);
  136.  
  137.  
  138. GimpPlugInInfo PLUG_IN_INFO =
  139. {
  140.   NULL,     /* init_proc  */
  141.   NULL,     /* quit_proc  */
  142.   query, /* query_proc */
  143.   run     /* run_proc   */
  144. };
  145.  
  146.  
  147. /*********************
  148.   Globals
  149.   *******************/
  150.  
  151. /* This is needed to communicate the result from the dialog
  152.    box button's callback function*/
  153. static gint dialog_result = -1;
  154.  
  155. struct config_tag
  156. {
  157.   gint        threshold;     /* derivative comparison for edge detection */
  158.   direction_t direction;     /* of wind, LEFT or RIGHT */
  159.   gint        strength;         /* how many pixels to bleed */
  160.   algorithm_t alg;           /* which algorithm */
  161.   edge_t      edge;          /* controls abs, ne+ static guchar *preview_bits;
  162. + static GtkWidget *preview;
  163. gation of derivative */
  164. };
  165.  
  166. typedef struct config_tag config_t;
  167. config_t config =
  168. {
  169.   10,          /* threshold for derivative edge detection */
  170.   LEFT,        /* bleed to the right */
  171.   10,          /* how many pixels to bleed */
  172.   RENDER_WIND, /* default algorithm */
  173.   LEADING      /* abs(derivative); */
  174. };
  175.  
  176. static guchar    *preview_cache;
  177. static GtkWidget *preview;
  178. static gint       preview_cache_rowstride;
  179. static gint       preview_cache_bpp;
  180.  
  181. MAIN ()
  182.  
  183. static void
  184. query (void)
  185. {
  186.   static GimpParamDef args[] =
  187.   {
  188.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  189.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  190.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  191.     { GIMP_PDB_INT32, "threshold", "Controls where blending will be done >= 0" },
  192.     { GIMP_PDB_INT32, "direction", "Left or Right: 0 or 1" },
  193.     { GIMP_PDB_INT32, "strength", "Controls the extent of the blending > 1" },
  194.     { GIMP_PDB_INT32, "alg", "WIND, BLAST" },
  195.     { GIMP_PDB_INT32, "edge", "LEADING, TRAILING, or BOTH" }
  196.   };
  197.   static gint nargs = sizeof (args) / sizeof (args[0]);
  198.  
  199.   gimp_install_procedure ("plug_in_wind",
  200.               "Renders a wind effect.",
  201.               "Renders a wind effect.",
  202.               "Nigel Wetten",
  203.               "Nigel Wetten",
  204.               "May 2000",
  205.               N_("<Image>/Filters/Distorts/Wind..."),
  206.               "RGB*",
  207.               GIMP_PLUGIN,
  208.               nargs, 0,
  209.               args, NULL);
  210. }
  211.  
  212. static void
  213. run (gchar   *name,
  214.      gint     nparams,
  215.      GimpParam  *param,
  216.      gint    *nreturn_vals,
  217.      GimpParam **return_vals)
  218. {
  219.   static GimpParam values[1];
  220.   GimpDrawable *drawable;
  221.   GimpRunModeType run_mode;
  222.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  223.  
  224.   run_mode = param[0].data.d_int32;
  225.   drawable = gimp_drawable_get(param[2].data.d_drawable);
  226.   gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
  227.   switch (run_mode)
  228.     {
  229.     case GIMP_RUN_NONINTERACTIVE:
  230.       INIT_I18N();
  231.       if (nparams != 8)
  232.     {
  233.       status = GIMP_PDB_CALLING_ERROR;
  234.     }
  235.       else
  236.     {
  237.       config.threshold = param[3].data.d_int32;
  238.       config.direction = param[4].data.d_int32;
  239.       config.strength = param[5].data.d_int32;
  240.       config.alg = param[6].data.d_int32;
  241.       config.edge = param[7].data.d_int32;
  242.  
  243.       if (render_effect(drawable, 0) == -1)
  244.         status = GIMP_PDB_EXECUTION_ERROR;
  245.     }
  246.       break;
  247.       
  248.     case GIMP_RUN_INTERACTIVE:
  249.       INIT_I18N_UI();
  250.       gimp_get_data("plug_in_wind", &config);
  251.       dialog_box(drawable);
  252.       if (dialog_result == -1)
  253.     {
  254.       status = GIMP_PDB_EXECUTION_ERROR;
  255.       break;
  256.     }
  257.       if (render_effect(drawable, 0) == -1)
  258.     {
  259.       status = GIMP_PDB_CALLING_ERROR;
  260.       break;
  261.     }
  262.       g_free(preview_cache);
  263.       gimp_set_data("plug_in_wind", &config, sizeof(config_t));
  264.       gimp_displays_flush();
  265.       break;
  266.       
  267.     case GIMP_RUN_WITH_LAST_VALS:
  268.       INIT_I18N();
  269.       gimp_get_data("plug_in_wind", &config);
  270.       if (render_effect (drawable, FALSE) == -1)
  271.     {
  272.       status = GIMP_PDB_EXECUTION_ERROR;
  273.       gimp_message("An execution error occured.");
  274.     }
  275.       else
  276.     {
  277.       gimp_displays_flush ();
  278.     }
  279.     }
  280.       
  281.   gimp_drawable_detach(drawable);
  282.   
  283.   *nreturn_vals = 1;
  284.   *return_vals = values;
  285.   values[0].type = GIMP_PDB_STATUS;
  286.   values[0].data.d_status = status;
  287.  
  288.   return;
  289. }
  290.  
  291. static gint
  292. render_effect (GimpDrawable *drawable, 
  293.            gboolean   preview_mode)
  294. {
  295.   if (config.alg == RENDER_WIND)
  296.     {
  297.       render_wind (drawable, config.threshold, config.strength,
  298.            config.direction, config.edge, preview_mode);
  299.     }
  300.   else if (config.alg == RENDER_BLAST)
  301.     {
  302.       render_blast (drawable, config.threshold, config.strength,
  303.             config.direction, config.edge, preview_mode);
  304.     }
  305.   return 0;
  306. }
  307.  
  308. static void
  309. preview_do_row(gint    row,
  310.            gint    width,
  311.            guchar *even,
  312.            guchar *odd,
  313.            guchar *src)
  314. {
  315.   gint    x;
  316.   
  317.   guchar *p0 = even;
  318.   guchar *p1 = odd;
  319.   
  320.   gdouble    r, g, b, a;
  321.   gdouble    c0, c1;
  322.   
  323.   for (x = 0; x < width; x++) 
  324.     {
  325.       if (preview_cache_bpp == 4)
  326.     {
  327.       r = ((gdouble)src[x*4+0]) / 255.0;
  328.       g = ((gdouble)src[x*4+1]) / 255.0;
  329.       b = ((gdouble)src[x*4+2]) / 255.0;
  330.       a = ((gdouble)src[x*4+3]) / 255.0;
  331.     }
  332.       else if (preview_cache_bpp == 3)
  333.     {
  334.       r = ((gdouble)src[x*3+0]) / 255.0;
  335.       g = ((gdouble)src[x*3+1]) / 255.0;
  336.       b = ((gdouble)src[x*3+2]) / 255.0;
  337.       a = 1.0;
  338.     }
  339.       else
  340.     {
  341.       r = ((gdouble)src[x*preview_cache_bpp+0]) / 255.0;
  342.       g = b = r;
  343.       if (preview_cache_bpp == 2)
  344.             a = ((gdouble)src[x*preview_cache_bpp+1]) / 255.0;
  345.       else
  346.         a = 1.0;
  347.     }
  348.       
  349.       if ((x / GIMP_CHECK_SIZE) & 1) 
  350.     {
  351.       c0 = GIMP_CHECK_LIGHT;
  352.       c1 = GIMP_CHECK_DARK;
  353.     } 
  354.       else 
  355.     {
  356.       c0 = GIMP_CHECK_DARK;
  357.       c1 = GIMP_CHECK_LIGHT;
  358.     }
  359.       
  360.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  361.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  362.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  363.       
  364.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  365.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  366.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  367.       
  368.     } /* for */
  369.   
  370.   if ((row / GIMP_CHECK_SIZE) & 1)
  371.     {
  372.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)odd,  0, row, width); 
  373.     }
  374.   else
  375.     {
  376.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)even, 0, row, width); 
  377.     }
  378. }
  379.  
  380. static void
  381. render_blast (GimpDrawable   *drawable,
  382.           gint         threshold,
  383.           gint         strength,
  384.           direction_t  direction,
  385.           edge_t       edge,
  386.           gboolean     preview_mode)
  387. {
  388.   gint x1, x2, y1, y2;
  389.   gint width;
  390.   gint height;
  391.   gint bytes = drawable->bpp;
  392.   guchar *buffer;
  393.   GimpPixelRgn src_region, dest_region;
  394.   gint row;
  395.   gint row_stride;
  396.   gint marker = 0;
  397.   gint lpi;
  398.   guchar *odd = NULL;
  399.   guchar *even = NULL;
  400.  
  401.   if (preview_mode) 
  402.     {
  403.       width  = GTK_PREVIEW (preview)->buffer_width;
  404.       height = GTK_PREVIEW (preview)->buffer_height;
  405.       bytes  = preview_cache_bpp;
  406.  
  407.       x1 = y1 = 0;
  408.       x2 = width;
  409.       y2 = height;
  410.  
  411.       row_stride = preview_cache_rowstride;
  412.       even = g_malloc (width * 3);
  413.       odd  = g_malloc (width * 3);
  414.     } 
  415.   else 
  416.     {
  417.       gimp_progress_init( _("Rendering Blast..."));
  418.       gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  419.  
  420.       width = x2 - x1;
  421.       height = y2 - y1;
  422.  
  423.       gimp_pixel_rgn_init (&src_region,  drawable, x1, y1, width, height, FALSE, FALSE);
  424.       gimp_pixel_rgn_init (&dest_region, drawable, x1, y1, width, height, TRUE, TRUE);
  425.  
  426.       row_stride = width * bytes;
  427.   }
  428.  
  429.   lpi = row_stride - bytes;
  430.  
  431.   buffer = (guchar *) g_malloc (row_stride);
  432.   
  433.   for (row = y1; row < y2; row++)
  434.     {
  435.       if (preview_mode)
  436.         memcpy (buffer, preview_cache + (row * row_stride), row_stride);
  437.       else
  438.         gimp_pixel_rgn_get_row (&src_region, buffer, x1, row, width);
  439.  
  440.       if (direction == RIGHT)
  441.     {
  442.       reverse_buffer (buffer, row_stride, bytes);
  443.     }
  444.  
  445.       marker = render_blast_row (buffer, bytes, lpi, threshold, strength, edge);
  446.  
  447.       if (direction == RIGHT)
  448.     {
  449.       reverse_buffer (buffer, row_stride, bytes);
  450.     }
  451.  
  452.       if (preview_mode) 
  453.     {
  454.       preview_do_row(row,width,even,odd,buffer);
  455.     } 
  456.       else 
  457.     {
  458.       gimp_pixel_rgn_set_row (&dest_region, buffer, x1, row, width);
  459.       gimp_progress_update ((double) (row - y1)/ (double) (height));
  460.     }
  461.  
  462.       if (marker)
  463.     {
  464.       gint j, limit;
  465.       
  466.       limit = 1 + rand () % 2;
  467.       for (j = 0; (j < limit) && (row < y2); j++)
  468.         {
  469.           row++;
  470.           if (row < y2)
  471.         {
  472.                   if (preview_mode) 
  473.             {
  474.               memcpy (buffer, preview_cache + (row * row_stride), row_stride);
  475.               preview_do_row(row,width,even,odd,buffer);
  476.             } 
  477.           else 
  478.             {
  479.               gimp_pixel_rgn_get_row (&src_region, buffer, x1, row, width);
  480.               gimp_pixel_rgn_set_row (&dest_region, buffer, x1, row, width);
  481.             }
  482.         }
  483.         }
  484.       marker = 0;
  485.     }
  486.     }
  487.  
  488.  if(even)
  489.     g_free(even);
  490.  
  491.   if(odd)
  492.     g_free(odd);
  493.  
  494.   g_free(buffer);
  495.   
  496.   /*  update the region  */
  497.   if (preview_mode) 
  498.     {
  499.       gtk_widget_queue_draw (preview);
  500.     }
  501.   else 
  502.     {
  503.       gimp_drawable_flush (drawable);
  504.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  505.       gimp_drawable_update (drawable->id, x1, y1, x2 - x1, y2 - y1);
  506.     }
  507.  
  508.   return;
  509. }
  510.  
  511. static void
  512. render_wind (GimpDrawable   *drawable,
  513.          gint         threshold,
  514.          gint         strength,
  515.          direction_t  direction,
  516.          edge_t       edge,
  517.          gboolean     preview_mode)
  518. {
  519.   GimpPixelRgn src_region, dest_region;
  520.   gint width;
  521.   gint height;
  522.   gint bytes;
  523.   gint row_stride;
  524.   gint comp_stride;
  525.   gint row;
  526.   guchar *sb;
  527.   gint lpi;
  528.   gint x1, y1, x2, y2;
  529.   guchar *odd = NULL;
  530.   guchar *even = NULL;
  531.  
  532.   if (preview_mode) 
  533.     {
  534.       width  = GTK_PREVIEW (preview)->buffer_width;
  535.       height = GTK_PREVIEW (preview)->buffer_height;
  536.       bytes  = preview_cache_bpp;
  537.  
  538.       x1 = y1 = 0;
  539.       x2 = width;
  540.       y2 = height;
  541.  
  542.       row_stride = preview_cache_rowstride;
  543.       even = g_malloc (width * 3);
  544.       odd  = g_malloc (width * 3);
  545.     } 
  546.   else 
  547.     {
  548.       gimp_progress_init( _("Rendering Wind..."));
  549.       gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  550.  
  551.       bytes = drawable->bpp;
  552.       width = x2 - x1;
  553.       height = y2 - y1;
  554.  
  555.       gimp_pixel_rgn_init (&src_region, drawable, x1, y1, width, height, FALSE, FALSE);
  556.       gimp_pixel_rgn_init (&dest_region, drawable, x1, y1, width, height, TRUE, TRUE);
  557.  
  558.       row_stride = width * bytes;
  559.     }
  560.   
  561.   comp_stride = bytes * COMPARE_WIDTH;
  562.   lpi = row_stride - comp_stride;
  563.  
  564.   sb = g_malloc (row_stride);
  565.   
  566.   for (row = y1; row < y2; row++)
  567.     {
  568.       if (preview_mode) 
  569.     memcpy (sb, preview_cache + (row * row_stride), row_stride);
  570.       else 
  571.     gimp_pixel_rgn_get_row (&src_region, sb, x1, row, width);
  572.  
  573.       if (direction == RIGHT)
  574.     reverse_buffer (sb, row_stride, bytes);
  575.       
  576.       render_wind_row (sb, bytes, lpi, threshold, strength, edge);
  577.  
  578.       if (direction == RIGHT)
  579.     reverse_buffer(sb, row_stride, bytes);
  580.  
  581.       if (preview_mode) 
  582.     {
  583.       preview_do_row(row,width,even,odd,sb);
  584.     } 
  585.       else 
  586.     {
  587.       gimp_pixel_rgn_set_row (&dest_region, sb, x1, row, width);
  588.       gimp_progress_update ((double) (row - y1)/ (double) (height));
  589.     }
  590.     }
  591.  
  592.   if(even)
  593.     g_free(even);
  594.  
  595.   if(odd)
  596.     g_free(odd);
  597.  
  598.   g_free(sb);
  599.  
  600.   /*  update the region  */
  601.   if (preview_mode) 
  602.     {
  603.       gtk_widget_queue_draw (preview);
  604.     } 
  605.   else 
  606.     {
  607.       gimp_drawable_flush (drawable);
  608.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  609.       gimp_drawable_update (drawable->id, x1, y1, x2 - x1, y2 - y1);
  610.     }
  611.  
  612.   return;
  613. }
  614.  
  615. static gint
  616. render_blast_row (guchar *buffer,
  617.           gint    bytes,
  618.           gint    lpi,
  619.           gint    threshold,
  620.           gint    strength,
  621.           edge_t  edge)
  622. {
  623.   gint Ri, Gi, Bi, Ai= 0;
  624.   gint sbi, lbi;
  625.   gint bleed_length;
  626.   gint i, j;
  627.   gint weight, random_factor;
  628.   gint skip = 0;
  629.  
  630.   for (j = 0; j < lpi; j += bytes)
  631.     {
  632.       Ri = j; Gi = j + 1; Bi = j + 2;
  633.  
  634.       if(bytes > 3)
  635.     Ai = j + 3;
  636.       
  637.       if (threshold_exceeded(buffer+Ri, buffer+Ri+bytes, edge, threshold, (bytes > 3)))
  638.     {
  639.       /* we have found an edge, do bleeding */
  640.       sbi = Ri;
  641.           
  642.       weight = rand() % 10;
  643.       if (weight > 5)
  644.         {
  645.           random_factor = 2;
  646.         }
  647.       else if (weight > 3)
  648.         {
  649.           random_factor = 3;
  650.         }
  651.       else
  652.         {
  653.           random_factor = 4;
  654.         }
  655.       bleed_length = 0;
  656.       switch (rand() % random_factor)
  657.         {
  658.         case 3:
  659.           bleed_length += strength;
  660.           /* fall through to add up multiples of strength */
  661.         case 2:
  662.           bleed_length += strength;
  663.           /* fall through */
  664.         case 1:
  665.           bleed_length += strength;
  666.           /* fall through */
  667.         case 0:
  668.           bleed_length += strength;
  669.           /* fall through */
  670.         }
  671.  
  672.       lbi = sbi + bytes * bleed_length;
  673.       if (lbi > lpi)
  674.         {
  675.           lbi = lpi;
  676.         }
  677.  
  678.       for (i = sbi; i < lbi; i += bytes)
  679.         {
  680.           buffer[i] = buffer[Ri];
  681.           buffer[i+1] = buffer[Gi];
  682.           buffer[i+2] = buffer[Bi];
  683.           if(bytes > 3)
  684.         buffer[i+3] = buffer[Ai];
  685.         }
  686.       j = lbi - bytes;
  687.       if ((rand() % 10) > 7)
  688.         {
  689.           skip = 1;
  690.         }
  691.     }
  692.     }
  693.   return skip;
  694. }
  695.  
  696. static void
  697. render_wind_row (guchar *sb,
  698.          gint    bytes,
  699.          gint    lpi,
  700.          gint    threshold,
  701.          gint    strength,
  702.          edge_t  edge)
  703. {
  704.   gint i, j;
  705.   gint bleed_length;
  706.   gint blend_amt_R, blend_amt_G, blend_amt_B, blend_amt_A = 0 ;
  707.   gint blend_colour_R, blend_colour_G, blend_colour_B, blend_colour_A = 0 ;
  708.   gint target_colour_R, target_colour_G, target_colour_B, target_colour_A = 0;
  709.   gdouble bleed_length_max;
  710.   gint bleed_variation;
  711.   gint n;
  712.   gint sbi;  /* starting bleed index */
  713.   gint lbi;     /* last bleed index */
  714.   gdouble denominator;
  715.   gint comp_stride = bytes * COMPARE_WIDTH;
  716.   
  717.   for (j = 0; j < lpi; j += bytes)
  718.     {
  719.       gint Ri = j;
  720.       gint Gi = j + 1;
  721.       gint Bi = j + 2;
  722.       gint Ai = 0;
  723.  
  724.       if(bytes > 3)
  725.     Ai = j + 3;
  726.  
  727.       if (threshold_exceeded(sb+Ri, sb+Ri+comp_stride, edge, threshold,(bytes > 3)))
  728.     {
  729.       /* we have found an edge, do bleeding */
  730.       sbi = Ri + comp_stride;
  731.       blend_colour_R = sb[Ri];
  732.       blend_colour_G = sb[Gi];
  733.       blend_colour_B = sb[Bi];
  734.       target_colour_R = sb[sbi];
  735.       target_colour_G = sb[sbi+1];
  736.       target_colour_B = sb[sbi+2];
  737.       bleed_length_max = strength;
  738.  
  739.       if(bytes > 3)
  740.         {
  741.           blend_colour_A = sb[Ai];
  742.           target_colour_A = sb[sbi+3];
  743.         }
  744.  
  745.       if (rand() % 3) /* introduce weighted randomness */
  746.         {
  747.           bleed_length_max = strength;
  748.         }
  749.       else
  750.         {
  751.           bleed_length_max = 4 * strength;
  752.         }
  753.  
  754.       bleed_variation = 1
  755.         + (gint) (bleed_length_max * rand() / (G_MAXRAND + 1.0));
  756.  
  757.       lbi = sbi + bleed_variation * bytes;
  758.       if (lbi > lpi)
  759.         {
  760.           lbi = lpi; /* stop overunning the buffer */
  761.         }
  762.  
  763.       bleed_length = bleed_variation;
  764.  
  765.       blend_amt_R = target_colour_R - blend_colour_R;
  766.       blend_amt_G = target_colour_G - blend_colour_G;
  767.       blend_amt_B = target_colour_B - blend_colour_B;
  768.       if(bytes > 3)
  769.         {
  770.            blend_amt_A = target_colour_A - blend_colour_A;
  771.         }
  772.       denominator = bleed_length * bleed_length + bleed_length;
  773.       denominator = 2.0 / denominator;
  774.       n = bleed_length;
  775.       for (i = sbi; i < lbi; i += bytes)
  776.         {
  777.  
  778.           /* check against original colour */
  779.           if (!threshold_exceeded(sb+Ri, sb+i, edge, threshold,(bytes>3))
  780.           && (rand() % 2))
  781.         {
  782.           break;
  783.         }
  784.  
  785.           blend_colour_R += blend_amt_R * n * denominator;
  786.           blend_colour_G += blend_amt_G * n * denominator;
  787.           blend_colour_B += blend_amt_B * n * denominator;
  788.  
  789.           if(bytes > 3)
  790.         {
  791.           blend_colour_A += blend_amt_A * n * denominator;
  792.           if (blend_colour_A > 255) blend_colour_A = 255;
  793.           else if (blend_colour_A < 0) blend_colour_A = 0;
  794.         }
  795.  
  796.           if (blend_colour_R > 255) blend_colour_R = 255;
  797.           else if (blend_colour_R < 0) blend_colour_R = 0;
  798.           if (blend_colour_G > 255) blend_colour_G = 255;
  799.           else if (blend_colour_G < 0) blend_colour_G = 0;
  800.           if (blend_colour_B > 255) blend_colour_B = 255;
  801.           else if (blend_colour_B < 0) blend_colour_B = 0;
  802.  
  803.           sb[i] = (blend_colour_R * 2 + sb[i]) / 3;
  804.           sb[i+1] = (blend_colour_G * 2 + sb[i+1]) / 3;
  805.           sb[i+2] = (blend_colour_B * 2 + sb[i+2]) / 3;
  806.  
  807.           if(bytes > 3)
  808.         sb[i+3] = (blend_colour_A * 2 + sb[i+3]) / 3;
  809.  
  810.           if (threshold_exceeded(sb+i, sb+i+comp_stride, BOTH,
  811.                      threshold,(bytes>3)))
  812.         {
  813.           target_colour_R = sb[i+comp_stride];
  814.           target_colour_G = sb[i+comp_stride+1];
  815.           target_colour_B = sb[i+comp_stride+2];
  816.           if(bytes > 3)
  817.             target_colour_A = sb[i+comp_stride+3];
  818.           blend_amt_R = target_colour_R - blend_colour_R;
  819.           blend_amt_G = target_colour_G - blend_colour_G;
  820.           blend_amt_B = target_colour_B - blend_colour_B;
  821.           if(bytes > 3)
  822.             blend_amt_A = target_colour_A - blend_colour_A;
  823.           denominator = n * n + n;
  824.           denominator = 2.0 / denominator;
  825.         }
  826.           n--;
  827.         }
  828.     }
  829.     }
  830.   return;
  831. }
  832.  
  833. static gint
  834. threshold_exceeded (guchar  *pixel_R1,
  835.             guchar  *pixel_R2,
  836.             edge_t   edge,
  837.             gint     threshold,
  838.             gboolean has_alpha)
  839. {
  840.   gint derivative_R, derivative_G, derivative_B, derivative_A;
  841.   gint return_value;
  842.  
  843.   get_derivative(pixel_R1, pixel_R2, edge, has_alpha,
  844.          &derivative_R, &derivative_G, &derivative_B, &derivative_A);
  845.  
  846.   if(((derivative_R + 
  847.        derivative_G + 
  848.        derivative_B + 
  849.        derivative_A) / 4) > threshold)
  850.     {
  851.       return_value = 1;
  852.     }
  853.   else
  854.     {
  855.       return_value = 0;
  856.     }
  857.   return return_value;
  858. }
  859.  
  860. static void
  861. get_derivative (guchar  *pixel_R1,
  862.         guchar  *pixel_R2,
  863.         edge_t   edge,
  864.         gboolean has_alpha,
  865.         gint    *derivative_R,
  866.         gint    *derivative_G,
  867.         gint    *derivative_B,
  868.         gint    *derivative_A)
  869. {
  870.   guchar *pixel_G1 = pixel_R1 + 1;
  871.   guchar *pixel_B1 = pixel_R1 + 2;
  872.   guchar *pixel_G2 = pixel_R2 + 1;
  873.   guchar *pixel_B2 = pixel_R2 + 2;
  874.   guchar *pixel_A1;
  875.   guchar *pixel_A2;
  876.  
  877.   if(has_alpha)
  878.     {
  879.       pixel_A1 = pixel_R1 + 3;
  880.       pixel_A2 = pixel_R2 + 3;
  881.       *derivative_A = *pixel_A2 - *pixel_A1;
  882.     }
  883.   else
  884.     {
  885.       *derivative_A = 0;
  886.     }
  887.  
  888.   *derivative_R = *pixel_R2 - *pixel_R1;
  889.   *derivative_G = *pixel_G2 - *pixel_G1;
  890.   *derivative_B = *pixel_B2 - *pixel_B1;
  891.   
  892.   if (edge == BOTH)
  893.     {
  894.       *derivative_R = abs(*derivative_R);
  895.       *derivative_G = abs(*derivative_G);
  896.       *derivative_B = abs(*derivative_B);
  897.       *derivative_A = abs(*derivative_A);
  898.     }
  899.   else if (edge == LEADING)
  900.     {
  901.       *derivative_R = -(*derivative_R);
  902.       *derivative_G = -(*derivative_G);
  903.       *derivative_B = -(*derivative_B);
  904.       *derivative_A = -(*derivative_A);
  905.     }
  906.   else if (edge == TRAILING)
  907.     {
  908.       /* no change needed */
  909.     }
  910.   return;
  911. }
  912.  
  913. static void
  914. reverse_buffer (guchar *buffer,
  915.         gint    length,
  916.         gint    bytes)
  917. {
  918.   gint i, si;
  919.   gint temp;
  920.   gint midpoint;
  921.   
  922.   midpoint = length / 2;
  923.   for (i = 0; i < midpoint; i += bytes)
  924.     {
  925.       si = length - bytes - i;
  926.       
  927.       temp = buffer[i];
  928.       buffer[i] = buffer[si];
  929.       buffer[si] = (guchar) temp;
  930.  
  931.       temp = buffer[i+1];
  932.       buffer[i+1] = buffer[si+1];
  933.       buffer[si+1] = (guchar) temp;
  934.  
  935.       temp = buffer[i+2];
  936.       buffer[i+2] = buffer[si+2];
  937.       buffer[si+2] = (guchar) temp;
  938.  
  939.       if(bytes > 3)
  940.     {
  941.       temp = buffer[i+3];
  942.       buffer[i+3] = buffer[si+3];
  943.       buffer[si+3] = (guchar) temp;
  944.     }
  945.     }
  946.  
  947.   return;
  948. }
  949.  
  950. /***************************************************
  951.   GUI 
  952.  ***************************************************/
  953.  
  954. static void
  955. ok_callback (GtkWidget *widget,
  956.          gpointer   data)
  957. {
  958.   /* we have to stop the dialog from being closed with strength < 1 */
  959.   /* since we use spinbuttons this should never happen ...          */
  960.   if (config.strength < 1)
  961.     {
  962.       g_message (_("Wind Strength must be greater than 0."));
  963.     }
  964.   else
  965.     {
  966.       dialog_result = 1;
  967.       gtk_widget_destroy (GTK_WIDGET (data));
  968.     }
  969. }
  970.  
  971. static void
  972. radio_callback (GtkWidget *widget, 
  973.         gpointer   data)
  974. {
  975.   GimpDrawable *drawable;
  976.  
  977.   gimp_radio_button_update (widget, data);
  978.  
  979.   if (GTK_TOGGLE_BUTTON (widget)->active)
  980.     {
  981.       drawable = gtk_object_get_data (GTK_OBJECT (widget), "drawable");
  982.       if (drawable != NULL)
  983.     render_effect (drawable, TRUE);
  984.     }
  985. }
  986.  
  987. static void
  988. dialog_box (GimpDrawable *drawable)
  989. {
  990.   GtkWidget *main_vbox;
  991.   GtkWidget *vbox;
  992.   GtkWidget *abox;
  993.   GtkWidget *table;
  994.   GtkObject *adj;
  995.   GtkWidget *frame;
  996.   GtkWidget *dlg;
  997.   GtkWidget *style1;
  998.   GtkWidget *style2;
  999.   GtkWidget *dir1;
  1000.   GtkWidget *dir2;
  1001.   GtkWidget *edge1;
  1002.   GtkWidget *edge2;
  1003.   GtkWidget *edge3;
  1004.  
  1005.   gimp_ui_init ("wind", TRUE);
  1006.  
  1007.   dlg = gimp_dialog_new ( _("Wind"), "wind",
  1008.              gimp_standard_help_func, "filters/wind.html",
  1009.              GTK_WIN_POS_MOUSE,
  1010.              FALSE, TRUE, FALSE,
  1011.  
  1012.              _("OK"), ok_callback,
  1013.              NULL, NULL, NULL, TRUE, FALSE,
  1014.              _("Cancel"), gtk_widget_destroy,
  1015.              NULL, 1, NULL, FALSE, TRUE,
  1016.  
  1017.              NULL);
  1018.  
  1019.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  1020.               GTK_SIGNAL_FUNC (gtk_main_quit),
  1021.               NULL);
  1022.  
  1023.   /* init tooltips */
  1024.   gimp_help_init ();
  1025.   
  1026.   vbox = gtk_vbox_new (FALSE, 2);
  1027.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 0);
  1028.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), vbox, TRUE, TRUE, 0);
  1029.   gtk_widget_show (vbox);
  1030.  
  1031.   frame = gtk_frame_new (_("Preview"));
  1032.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  1033.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  1034.   gtk_widget_show (frame);
  1035.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  1036.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  1037.   gtk_container_add (GTK_CONTAINER (frame), abox);
  1038.   gtk_widget_show (abox);
  1039.   frame = gtk_frame_new (NULL);
  1040.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  1041.   gtk_container_add (GTK_CONTAINER (abox), frame);
  1042.   gtk_widget_show (frame);
  1043.   preview = preview_widget (drawable); /* we are here */
  1044.   gtk_container_add (GTK_CONTAINER (frame), preview);
  1045.   render_effect (drawable, TRUE); /* render preview image */
  1046.   gtk_widget_show (preview);
  1047.  
  1048.   frame = gtk_frame_new (_("Parameter Settings"));
  1049.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  1050.   gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  1051.   gtk_widget_show (frame);
  1052.  
  1053.   main_vbox = gtk_vbox_new (FALSE, 4);
  1054.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  1055.   gtk_container_add (GTK_CONTAINER (frame), main_vbox);
  1056.   gtk_widget_show (main_vbox);
  1057.  
  1058.   /*****************************************************
  1059.     outer frame and table
  1060.   ***************************************************/
  1061.  
  1062.   table = gtk_table_new (1, 3, FALSE);
  1063.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1064.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  1065.   gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
  1066.  
  1067.   /*********************************************************
  1068.     radio buttons for choosing wind rendering algorithm
  1069.     ******************************************************/
  1070.  
  1071.   frame = gimp_radio_group_new2 (TRUE, _("Style"),
  1072.                  radio_callback,
  1073.                  &config.alg, (gpointer) config.alg,
  1074.                  _("Wind"),  (gpointer) RENDER_WIND,  &style1,
  1075.                  _("Blast"), (gpointer) RENDER_BLAST, &style2,
  1076.  
  1077.                  NULL);
  1078.   gtk_object_set_data (GTK_OBJECT (style1), "drawable", drawable);
  1079.   gtk_object_set_data (GTK_OBJECT (style2), "drawable", drawable);
  1080.  
  1081.   gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1,
  1082.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  1083.   gtk_widget_show (frame);
  1084.  
  1085.   /******************************************************
  1086.     radio buttons for choosing LEFT or RIGHT
  1087.     **************************************************/
  1088.  
  1089.   frame = gimp_radio_group_new2 (TRUE, _("Direction"),
  1090.                  radio_callback,
  1091.                  &config.direction, (gpointer) config.direction,
  1092.                  _("Left"),  (gpointer) LEFT,  &dir1,
  1093.                  _("Right"), (gpointer) RIGHT, &dir2,
  1094.                  NULL);
  1095.   gtk_object_set_data (GTK_OBJECT (dir1), "drawable", drawable);
  1096.   gtk_object_set_data (GTK_OBJECT (dir2), "drawable", drawable);
  1097.  
  1098.   gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
  1099.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  1100.   gtk_widget_show (frame);
  1101.   
  1102.   /*****************************************************
  1103.     radio buttons for choosing BOTH, LEADING, TRAILING
  1104.     ***************************************************/
  1105.  
  1106.   frame = gimp_radio_group_new2 (TRUE, _("Edge Affected"),
  1107.                  radio_callback,
  1108.                  &config.edge, (gpointer) config.edge,
  1109.  
  1110.                  _("Leading"),  (gpointer) LEADING,  &edge1,
  1111.                  _("Trailing"), (gpointer) TRAILING, &edge2,
  1112.                  _("Both"),     (gpointer) BOTH,     &edge3,
  1113.  
  1114.                  NULL);
  1115.   gtk_object_set_data (GTK_OBJECT (edge1), "drawable", drawable);
  1116.   gtk_object_set_data (GTK_OBJECT (edge2), "drawable", drawable);
  1117.   gtk_object_set_data (GTK_OBJECT (edge3), "drawable", drawable);
  1118.  
  1119.   gtk_table_attach (GTK_TABLE (table), frame, 2, 3, 0, 1,
  1120.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  1121.   gtk_widget_show (frame);
  1122.  
  1123.   gtk_widget_show (table);
  1124.  
  1125.   /****************************************************
  1126.    table for sliders
  1127.    ****************************************************/
  1128.   table = gtk_table_new (2, 3, FALSE);
  1129.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1130.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  1131.   gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
  1132.  
  1133.   /*****************************************************
  1134.     slider and entry for threshold
  1135.     ***************************************************/
  1136.  
  1137.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  1138.                   _("Threshold:"), SCALE_WIDTH, 0,
  1139.                   config.threshold,
  1140.                   MIN_THRESHOLD, MAX_THRESHOLD, 1.0, 10, 0,
  1141.                   TRUE, 0, 0,
  1142.                   _("Higher values restrict the effect to fewer areas of the image"), NULL);
  1143.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1144.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  1145.               &config.threshold);
  1146.   gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed",
  1147.                  GTK_SIGNAL_FUNC (render_effect),
  1148.                  (gpointer)drawable);
  1149.  
  1150.   /*****************************************************
  1151.     slider and entry for strength of wind
  1152.     ****************************************************/
  1153.  
  1154.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  1155.                   _("Strength:"), SCALE_WIDTH, 0,
  1156.                   config.strength,
  1157.                   MIN_STRENGTH, MAX_STRENGTH, 1.0, 10.0, 0,
  1158.                   TRUE, 0, 0,
  1159.                   _("Higher values increase the magnitude of the effect"), NULL);
  1160.  
  1161.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1162.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  1163.               &config.strength);
  1164.   gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed",
  1165.                  GTK_SIGNAL_FUNC (render_effect),
  1166.                  (gpointer)drawable);
  1167.  
  1168.   gtk_widget_show (table);
  1169.  
  1170.   gtk_widget_show (dlg);
  1171.  
  1172.   gtk_main ();
  1173.   gdk_flush ();
  1174. }
  1175.  
  1176.  
  1177. static GtkWidget *
  1178. preview_widget (GimpDrawable *drawable)
  1179. {
  1180.   gint       size;
  1181.  
  1182.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  1183.   fill_preview (preview, drawable);
  1184.   size = GTK_PREVIEW (preview)->rowstride * GTK_PREVIEW (preview)->buffer_height;
  1185.  
  1186.   return preview;
  1187. }
  1188.  
  1189. static void
  1190. fill_preview (GtkWidget *widget, 
  1191.           GimpDrawable *drawable)
  1192. {
  1193.   GimpPixelRgn  srcPR;
  1194.   gint       width;
  1195.   gint       height;
  1196.   gint       x1, x2, y1, y2;
  1197.   gint       bpp;
  1198.   gint       y;
  1199.   guchar    *src;
  1200.   guchar    *even, *odd;
  1201.   
  1202.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  1203.  
  1204.   if (x2 - x1 > PREVIEW_SIZE)
  1205.     x2 = x1 + PREVIEW_SIZE;
  1206.   
  1207.   if (y2 - y1 > PREVIEW_SIZE)
  1208.     y2 = y1 + PREVIEW_SIZE;
  1209.   
  1210.   width  = x2 - x1;
  1211.   height = y2 - y1;
  1212.   bpp    = gimp_drawable_bpp (drawable->id);
  1213.   
  1214.   if (width < 1 || height < 1)
  1215.     return;
  1216.  
  1217.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  1218.  
  1219.   gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, x2, y2, FALSE, FALSE);
  1220.  
  1221.   even = g_malloc (width * 3);
  1222.   odd  = g_malloc (width * 3);
  1223.   src  = g_malloc (width * bpp);
  1224.   preview_cache = g_malloc(width * bpp * height);
  1225.   preview_cache_rowstride = width * bpp;
  1226.   preview_cache_bpp = bpp;
  1227.  
  1228.   for (y = 0; y < height; y++)
  1229.     {
  1230.       gimp_pixel_rgn_get_row (&srcPR, src, x1, y + y1, width);
  1231.       memcpy(preview_cache + (y*width*bpp),src,width*bpp);
  1232.     }
  1233.   
  1234.   for (y = 0; y < height; y++)
  1235.     {
  1236.       preview_do_row(y,width,even,odd,preview_cache + (y*width*bpp));
  1237.     }
  1238.  
  1239.  
  1240.   g_free (even);
  1241.   g_free (odd);
  1242.   g_free (src);
  1243. }
  1244.