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

  1. /* Cubism --- image filter plug-in for The Gimp image manipulation program
  2.  * Copyright (C) 1996 Spencer Kimball, Tracy Scott
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  *
  18.  * You can contact me at quartic@polloux.fciencias.unam.mx
  19.  * You can contact the original The Gimp authors at gimp@xcf.berkeley.edu
  20.  * Speedups by Elliot Lee
  21.  */
  22. #include "config.h"
  23.  
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. #include <gtk/gtk.h>
  28.  
  29. #include <libgimp/gimp.h>
  30. #include <libgimp/gimpui.h>
  31.  
  32. #include "libgimp/stdplugins-intl.h"
  33.  
  34.  
  35. #define SCALE_WIDTH    125
  36. #define BLACK            0
  37. #define BG               1
  38. #define SUPERSAMPLE      4
  39. #define MAX_POINTS       4
  40. #define MIN_ANGLE   -36000
  41. #define MAX_ANGLE    36000
  42. #define RANDOMNESS       5
  43.  
  44. typedef struct
  45. {
  46.   gint        npts;
  47.   GimpVector2 pts[MAX_POINTS];
  48. } Polygon;
  49.  
  50. typedef struct
  51. {
  52.   gdouble tile_size;
  53.   gdouble tile_saturation;
  54.   gint    bg_color;
  55. } CubismVals;
  56.  
  57. typedef struct
  58. {
  59.   gint run;
  60. } CubismInterface;
  61.  
  62. /* Declare local functions.
  63.  */
  64. static void      query  (void);
  65. static void      run    (gchar      *name,
  66.              gint        nparams,
  67.              GimpParam     *param,
  68.              gint       *nreturn_vals,
  69.              GimpParam    **return_vals);
  70. static void      cubism (GimpDrawable  *drawable);
  71.  
  72. static void      render_cubism        (GimpDrawable *drawable);
  73. static void      fill_poly_color      (Polygon   *poly,
  74.                        GimpDrawable *drawable,
  75.                        guchar    *col);
  76. static void      convert_segment      (gint       x1,
  77.                        gint       y1,
  78.                        gint       x2,
  79.                        gint       y2,
  80.                        gint       offset,
  81.                        gint      *min,
  82.                        gint      *max);
  83. static void      randomize_indices    (gint       count,
  84.                        gint      *indices);
  85. static gdouble   fp_rand              (gdouble    val);
  86. static gint      int_rand             (gint       val);
  87. static gdouble   calc_alpha_blend     (gdouble   *vec,
  88.                        gdouble    one_over_dist,
  89.                        gdouble    x,
  90.                        gdouble    y);
  91. static void      polygon_add_point    (Polygon   *poly,
  92.                        gdouble    x,
  93.                        gdouble    y);
  94. static void      polygon_translate    (Polygon   *poly,
  95.                        gdouble    tx,
  96.                        gdouble    ty);
  97. static void      polygon_rotate       (Polygon   *poly,
  98.                        gdouble    theta);
  99. static gint      polygon_extents      (Polygon   *poly,
  100.                        gdouble   *min_x,
  101.                        gdouble   *min_y,
  102.                        gdouble   *max_x,
  103.                        gdouble   *max_y);
  104. static void      polygon_reset        (Polygon   *poly);
  105.  
  106. static gint      cubism_dialog        (void);
  107. static void      cubism_ok_callback   (GtkWidget *widget,
  108.                        gpointer   data);
  109.  
  110. /*
  111.  *  Local variables
  112.  */
  113.  
  114. static guchar bg_col[4];
  115.  
  116. static CubismVals cvals =
  117. {
  118.   10.0,        /* tile_size */
  119.   2.5,         /* tile_saturation */
  120.   BLACK        /* bg_color */
  121. };
  122.  
  123. static CubismInterface cint =
  124. {
  125.   FALSE         /* run */
  126. };
  127.  
  128. GimpPlugInInfo PLUG_IN_INFO =
  129. {
  130.   NULL,  /* init_proc  */
  131.   NULL,  /* quit_proc  */
  132.   query, /* query_proc */
  133.   run,   /* run_proc   */
  134. };
  135.  
  136.  
  137. /*
  138.  *  Functions
  139.  */
  140.  
  141. MAIN ()
  142.  
  143. static void
  144. query (void)
  145. {
  146.   static GimpParamDef args[] =
  147.   {
  148.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  149.     { GIMP_PDB_IMAGE, "image", "Input image" },
  150.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  151.     { GIMP_PDB_FLOAT, "tile_size", "Average diameter of each tile (in pixels)" },
  152.     { GIMP_PDB_FLOAT, "tile_saturation", "Expand tiles by this amount" },
  153.     { GIMP_PDB_INT32, "bg_color", "Background color: { BLACK (0), BG (1) }" }
  154.   };
  155.   static gint nargs = sizeof (args) / sizeof (args[0]);
  156.  
  157.   gimp_install_procedure ("plug_in_cubism",
  158.               "Convert the input drawable into a collection of rotated squares",
  159.               "Help not yet written for this plug-in",
  160.               "Spencer Kimball & Tracy Scott",
  161.               "Spencer Kimball & Tracy Scott",
  162.               "1996",
  163.               N_("<Image>/Filters/Artistic/Cubism..."),
  164.               "RGB*, GRAY*",
  165.               GIMP_PLUGIN,
  166.               nargs, 0,
  167.               args, NULL);
  168. }
  169.  
  170. static void
  171. run (gchar   *name,
  172.      gint     nparams,
  173.      GimpParam  *param,
  174.      gint    *nreturn_vals,
  175.      GimpParam **return_vals)
  176. {
  177.   static GimpParam values[1];
  178.   GimpDrawable *active_drawable;
  179.   GimpRunModeType run_mode;
  180.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  181.  
  182.   INIT_I18N_UI();
  183.  
  184.   run_mode = param[0].data.d_int32;
  185.  
  186.   *nreturn_vals = 1;
  187.   *return_vals = values;
  188.  
  189.   values[0].type = GIMP_PDB_STATUS;
  190.   values[0].data.d_status = status;
  191.  
  192.   switch (run_mode)
  193.     {
  194.     case GIMP_RUN_INTERACTIVE:
  195.       /*  Possibly retrieve data  */
  196.       gimp_get_data ("plug_in_cubism", &cvals);
  197.  
  198.       /*  First acquire information with a dialog  */
  199.       if (! cubism_dialog ())
  200.     return;
  201.       break;
  202.  
  203.     case GIMP_RUN_NONINTERACTIVE:
  204.       /*  Make sure all the arguments are there!  */
  205.       if (nparams != 6)
  206.     status = GIMP_PDB_CALLING_ERROR;
  207.       if (status == GIMP_PDB_SUCCESS)
  208.     {
  209.       cvals.tile_size = param[3].data.d_float;
  210.       cvals.tile_saturation = param[4].data.d_float;
  211.       cvals.bg_color = param[5].data.d_int32;
  212.     }
  213.       if (status == GIMP_PDB_SUCCESS &&
  214.       (cvals.bg_color < BLACK || cvals.bg_color > BG))
  215.     status = GIMP_PDB_CALLING_ERROR;
  216.       break;
  217.  
  218.     case GIMP_RUN_WITH_LAST_VALS:
  219.       /*  Possibly retrieve data  */
  220.       gimp_get_data ("plug_in_cubism", &cvals);
  221.       break;
  222.  
  223.     default:
  224.       break;
  225.     }
  226.  
  227.   /*  get the active drawable  */
  228.   active_drawable = gimp_drawable_get (param[2].data.d_drawable);
  229.  
  230.   /*  Render the cubism effect  */
  231.   if ((status == GIMP_PDB_SUCCESS) &&
  232.       (gimp_drawable_is_rgb (active_drawable->id) ||
  233.        gimp_drawable_is_gray (active_drawable->id)))
  234.     {
  235.       /*  set cache size  */
  236.       gimp_tile_cache_ntiles (SQR (4 * cvals.tile_size * cvals.tile_saturation) / SQR (gimp_tile_width ()));
  237.  
  238.       cubism (active_drawable);
  239.  
  240.       /*  If the run mode is interactive, flush the displays  */
  241.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  242.     gimp_displays_flush ();
  243.  
  244.       /*  Store mvals data  */
  245.       if (run_mode == GIMP_RUN_INTERACTIVE)
  246.     gimp_set_data ("plug_in_cubism", &cvals, sizeof (CubismVals));
  247.     }
  248.   else if (status == GIMP_PDB_SUCCESS)
  249.     {
  250.       /* gimp_message ("cubism: cannot operate on indexed color images"); */
  251.       status = GIMP_PDB_EXECUTION_ERROR;
  252.     }
  253.  
  254.   values[0].data.d_status = status;
  255.  
  256.   gimp_drawable_detach (active_drawable);
  257. }
  258.  
  259. static void
  260. cubism (GimpDrawable *drawable)
  261. {
  262.   gint x1, y1, x2, y2;
  263.  
  264.   /*  find the drawable mask bounds  */
  265.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  266.  
  267.   /*  determine the background color  */
  268.   if (cvals.bg_color == BLACK)
  269.     bg_col[0] = bg_col[1] = bg_col[2] = 0;
  270.   else
  271.     gimp_palette_get_background (&bg_col[0], &bg_col[1], &bg_col[2]);
  272.  
  273.   if (gimp_drawable_has_alpha (drawable->id))
  274.     bg_col[drawable->bpp - 1] = 0;
  275.  
  276.   gimp_progress_init (_("Cubistic Transformation"));
  277.  
  278.   /*  render the cubism  */
  279.   render_cubism (drawable);
  280.  
  281.   /*  merge the shadow, update the drawable  */
  282.   gimp_drawable_flush (drawable);
  283.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  284.   gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  285. }
  286.  
  287. static gint
  288. cubism_dialog (void)
  289. {
  290.   GtkWidget *dlg;
  291.   GtkWidget *toggle;
  292.   GtkWidget *frame;
  293.   GtkWidget *table;
  294.   GtkObject *scale_data;
  295.  
  296.   gimp_ui_init ("cubism", FALSE);
  297.  
  298.   dlg = gimp_dialog_new (_("Cubism"), "cubism",
  299.              gimp_standard_help_func, "filters/cubism.html",
  300.              GTK_WIN_POS_MOUSE,
  301.              FALSE, TRUE, FALSE,
  302.  
  303.              _("OK"), cubism_ok_callback,
  304.              NULL, NULL, NULL, TRUE, FALSE,
  305.              _("Cancel"), gtk_widget_destroy,
  306.              NULL, 1, NULL, FALSE, TRUE,
  307.  
  308.              NULL);
  309.  
  310.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  311.               GTK_SIGNAL_FUNC (gtk_main_quit),
  312.               NULL);
  313.  
  314.   /*  parameter settings  */
  315.   frame = gtk_frame_new (_("Parameter Settings"));
  316.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  317.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  318.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0);
  319.  
  320.   table = gtk_table_new (3, 3, FALSE);
  321.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  322.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  323.   gtk_table_set_row_spacing (GTK_TABLE (table), 0, 4);
  324.   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
  325.   gtk_container_add (GTK_CONTAINER (frame), table);
  326.  
  327.   toggle = gtk_check_button_new_with_label (_("Use Background Color"));
  328.   gtk_table_attach (GTK_TABLE (table), toggle, 0, 3, 0, 1,
  329.             GTK_FILL, GTK_FILL, 0, 0);
  330.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  331.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  332.               &cvals.bg_color);
  333.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
  334.                 (cvals.bg_color == BG));
  335.   gtk_widget_show (toggle);
  336.  
  337.   scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  338.                      _("Tile Size:"), SCALE_WIDTH, 0,
  339.                      cvals.tile_size, 0.0, 100.0, 1.0, 10.0, 1,
  340.                      TRUE, 0, 0,
  341.                      NULL, NULL);
  342.   gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
  343.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  344.               &cvals.tile_size);
  345.  
  346.   scale_data =
  347.     gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  348.               _("Tile Saturation:"), SCALE_WIDTH, 0,
  349.               cvals.tile_saturation, 0.0, 10.0, 0.1, 1, 1,
  350.               TRUE, 0, 0,
  351.               NULL, NULL);
  352.   gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
  353.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  354.               &cvals.tile_saturation);
  355.  
  356.   gtk_widget_show (table);
  357.   gtk_widget_show (frame);
  358.  
  359.   gtk_widget_show (dlg);
  360.  
  361.   gtk_main ();
  362.   gdk_flush ();
  363.  
  364.   return cint.run;
  365. }
  366.  
  367. static void
  368. cubism_ok_callback (GtkWidget *widget,
  369.             gpointer   data)
  370. {
  371.   cint.run = TRUE;
  372.  
  373.   gtk_widget_destroy (GTK_WIDGET (data));
  374. }
  375.  
  376. static void
  377. render_cubism (GimpDrawable *drawable)
  378. {
  379.   GimpPixelRgn src_rgn;
  380.   gdouble img_area, tile_area;
  381.   gdouble x, y;
  382.   gdouble width, height;
  383.   gdouble theta;
  384.   gint ix, iy;
  385.   gint rows, cols;
  386.   gint i, j, count;
  387.   gint num_tiles;
  388.   gint x1, y1, x2, y2;
  389.   Polygon poly;
  390.   guchar col[4];
  391.   guchar *dest;
  392.   gint bytes;
  393.   gint has_alpha;
  394.   gint *random_indices;
  395.   gpointer pr;
  396.  
  397.   has_alpha = gimp_drawable_has_alpha (drawable->id);
  398.   bytes = drawable->bpp;
  399.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  400.   img_area = (x2 - x1) * (y2 - y1);
  401.   tile_area = SQR (cvals.tile_size);
  402.  
  403.   cols = ((x2 - x1) + cvals.tile_size - 1) / cvals.tile_size;
  404.   rows = ((y2 - y1) + cvals.tile_size - 1) / cvals.tile_size;
  405.  
  406.   /*  Fill the image with the background color  */
  407.   gimp_pixel_rgn_init (&src_rgn, drawable,
  408.                x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
  409.   for (pr = gimp_pixel_rgns_register (1, &src_rgn);
  410.        pr != NULL;
  411.        pr = gimp_pixel_rgns_process (pr))
  412.     {
  413.       count = src_rgn.w * src_rgn.h;
  414.       dest = src_rgn.data;
  415.  
  416.       while (count--)
  417.     for (i = 0; i < bytes; i++)
  418.       *dest++ = bg_col[i];
  419.     }
  420.  
  421.   num_tiles = (rows + 1) * (cols + 1);
  422.   random_indices = g_new (gint, num_tiles);
  423.   for (i = 0; i < num_tiles; i++)
  424.     random_indices[i] = i;
  425.  
  426.   randomize_indices (num_tiles, random_indices);
  427.  
  428.   count = 0;
  429.   gimp_pixel_rgn_init (&src_rgn, drawable,
  430.                x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
  431.  
  432.   while (count < num_tiles)
  433.     {
  434.       i = random_indices[count] / (cols + 1);
  435.       j = random_indices[count] % (cols + 1);
  436.       x = j * cvals.tile_size + (cvals.tile_size / 4.0) - fp_rand (cvals.tile_size/2.0) + x1;
  437.       y = i * cvals.tile_size + (cvals.tile_size / 4.0) - fp_rand (cvals.tile_size/2.0) + y1;
  438.       width = (cvals.tile_size + fp_rand (cvals.tile_size / 4.0) - cvals.tile_size / 8.0) * cvals.tile_saturation;
  439.       height = (cvals.tile_size + fp_rand (cvals.tile_size / 4.0) - cvals.tile_size / 8.0) * cvals.tile_saturation;
  440.       theta = fp_rand (2 * G_PI);
  441.       polygon_reset (&poly);
  442.       polygon_add_point (&poly, -width / 2.0, -height / 2.0);
  443.       polygon_add_point (&poly, width / 2.0, -height / 2.0);
  444.       polygon_add_point (&poly, width / 2.0, height / 2.0);
  445.       polygon_add_point (&poly, -width / 2.0, height / 2.0);
  446.       polygon_rotate (&poly, theta);
  447.       polygon_translate (&poly, x, y);
  448.  
  449.       /*  bounds check on x, y  */
  450.       ix = (int) x;
  451.       iy = (int) y;
  452.       if (ix < x1)
  453.     ix = x1;
  454.       if (ix >= x2)
  455.     ix = x2 - 1;
  456.       if (iy < y1)
  457.     iy = y1;
  458.       if (iy >= y2)
  459.     iy = y2 - 1;
  460.  
  461.       gimp_pixel_rgn_get_pixel (&src_rgn, col, ix, iy);
  462.  
  463.       if (! has_alpha || (has_alpha && col[bytes - 1] != 0))
  464.     fill_poly_color (&poly, drawable, col);
  465.  
  466.       count++;
  467.       if ((count % 5) == 0)
  468.     gimp_progress_update ((double) count / (double) num_tiles);
  469.     }
  470.  
  471.   gimp_progress_update (1.0);
  472.   g_free (random_indices);
  473. }
  474.  
  475. static inline gdouble
  476. calc_alpha_blend (gdouble *vec,
  477.           gdouble  one_over_dist,
  478.           gdouble  x,
  479.           gdouble  y)
  480. {
  481.   gdouble r;
  482.  
  483.   if (!one_over_dist)
  484.     return 1.0;
  485.   else
  486.     {
  487.       r = (vec[0] * x + vec[1] * y) * one_over_dist;
  488.       if (r < 0.2)
  489.     r = 0.2;
  490.       else if (r > 1.0)
  491.     r = 1.0;
  492.     }
  493.   return r;
  494. }
  495.  
  496. static void
  497. fill_poly_color (Polygon   *poly,
  498.          GimpDrawable *drawable,
  499.          guchar    *col)
  500. {
  501.   GimpPixelRgn src_rgn;
  502.   gdouble dmin_x, dmin_y;
  503.   gdouble dmax_x, dmax_y;
  504.   gint xs, ys;
  505.   gint xe, ye;
  506.   gint min_x, min_y;
  507.   gint max_x, max_y;
  508.   gint size_x, size_y;
  509.   gint * max_scanlines, *max_scanlines_iter;
  510.   gint * min_scanlines, *min_scanlines_iter;
  511.   gint val;
  512.   gint alpha;
  513.   gint bytes;
  514.   guchar buf[4];
  515.   gint i, j, x, y;
  516.   gdouble sx, sy;
  517.   gdouble ex, ey;
  518.   gdouble xx, yy;
  519.   gdouble vec[2];
  520.   gdouble dist, one_over_dist;
  521.   gint x1, y1, x2, y2;
  522.   gint *vals, *vals_iter, *vals_end;
  523.  
  524.   sx = poly->pts[0].x;
  525.   sy = poly->pts[0].y;
  526.   ex = poly->pts[1].x;
  527.   ey = poly->pts[1].y;
  528.  
  529.   dist = sqrt (SQR (ex - sx) + SQR (ey - sy));
  530.   if (dist > 0.0)
  531.     {
  532.       one_over_dist = 1/dist;
  533.       vec[0] = (ex - sx) * one_over_dist;
  534.       vec[1] = (ey - sy) * one_over_dist;
  535.     }
  536.   else
  537.     one_over_dist = 0.0;
  538.  
  539.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  540.   bytes = drawable->bpp;
  541.  
  542.   polygon_extents (poly, &dmin_x, &dmin_y, &dmax_x, &dmax_y);
  543.   min_x = (gint) dmin_x;
  544.   min_y = (gint) dmin_y;
  545.   max_x = (gint) dmax_x;
  546.   max_y = (gint) dmax_y;
  547.  
  548.   size_y = (max_y - min_y) * SUPERSAMPLE;
  549.   size_x = (max_x - min_x) * SUPERSAMPLE;
  550.  
  551.   min_scanlines = min_scanlines_iter = g_new (gint, size_y);
  552.   max_scanlines = max_scanlines_iter = g_new (gint, size_y);
  553.   for (i = 0; i < size_y; i++)
  554.     {
  555.       min_scanlines[i] = max_x * SUPERSAMPLE;
  556.       max_scanlines[i] = min_x * SUPERSAMPLE;
  557.     }
  558.  
  559.   if(poly->npts) {
  560.     gint poly_npts = poly->npts;
  561.     GimpVector2 *curptr;
  562.  
  563.     xs = (gint) (poly->pts[poly_npts-1].x);
  564.     ys = (gint) (poly->pts[poly_npts-1].y);
  565.     xe = (gint) poly->pts[0].x;
  566.     ye = (gint) poly->pts[0].y;
  567.  
  568.     xs *= SUPERSAMPLE;
  569.     ys *= SUPERSAMPLE;
  570.     xe *= SUPERSAMPLE;
  571.     ye *= SUPERSAMPLE;
  572.  
  573.     convert_segment (xs, ys, xe, ye, min_y * SUPERSAMPLE,
  574.              min_scanlines, max_scanlines);
  575.  
  576.     for (i = 1, curptr = &poly->pts[0]; i < poly_npts; i++)
  577.       {
  578.     xs = (gint) curptr->x;
  579.     ys = (gint) curptr->y;
  580.     curptr++;
  581.     xe = (gint) curptr->x;
  582.     ye = (gint) curptr->y;
  583.  
  584.     xs *= SUPERSAMPLE;
  585.     ys *= SUPERSAMPLE;
  586.     xe *= SUPERSAMPLE;
  587.     ye *= SUPERSAMPLE;
  588.  
  589.     convert_segment (xs, ys, xe, ye, min_y * SUPERSAMPLE,
  590.              min_scanlines, max_scanlines);
  591.       }
  592.   }
  593.  
  594.   gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0,
  595.                drawable->width, drawable->height, TRUE, TRUE);
  596.  
  597.   vals = g_new (gint, size_x);
  598.  
  599.   for (i = 0; i < size_y; i++, min_scanlines_iter++, max_scanlines_iter++)
  600.     {
  601.       if (! (i % SUPERSAMPLE))
  602.     {
  603.       memset (vals, 0, sizeof (gint) * size_x);
  604.     }
  605.  
  606.       yy = (gdouble)i / (gdouble)SUPERSAMPLE + min_y;
  607.  
  608.       for (j = *min_scanlines_iter; j < *max_scanlines_iter; j++)
  609.     {
  610.       x = j - min_x * SUPERSAMPLE;
  611.       vals[x] += 255;
  612.     }
  613.  
  614.       if (! ((i + 1) % SUPERSAMPLE))
  615.     {
  616.       y = (i / SUPERSAMPLE) + min_y;
  617.  
  618.       if (y >= y1 && y < y2)
  619.         {
  620.           for (j = 0; j < size_x; j += SUPERSAMPLE)
  621.         {
  622.           x = (j / SUPERSAMPLE) + min_x;
  623.  
  624.           if (x >= x1 && x < x2)
  625.             {
  626.               for (val = 0, vals_iter = &vals[j],
  627.                  vals_end = &vals_iter[SUPERSAMPLE];
  628.                vals_iter < vals_end;
  629.                vals_iter++)
  630.             val += *vals_iter;
  631.  
  632.               val /= SQR(SUPERSAMPLE);
  633.  
  634.               if (val > 0)
  635.             {
  636.               xx = (gdouble) j / (gdouble) SUPERSAMPLE + min_x;
  637.               alpha = (gint) (val * calc_alpha_blend (vec, one_over_dist, xx - sx, yy - sy));
  638.  
  639.               gimp_pixel_rgn_get_pixel (&src_rgn, buf, x, y);
  640.  
  641. #ifndef USE_READABLE_BUT_SLOW_CODE
  642.               {
  643.                 guchar *buf_iter = buf,
  644.                   *col_iter = col,
  645.                   *buf_end = buf+bytes;
  646.  
  647.                 for(; buf_iter < buf_end; buf_iter++, col_iter++)
  648.                   *buf_iter = ((guint)(*col_iter * alpha)
  649.                        + (((guint)*buf_iter)
  650.                           * (256 - alpha))) >> 8;
  651.               }
  652. #else /* original, pre-ECL code */
  653.               for (b = 0; b < bytes; b++)
  654.                 buf[b] = ((col[b] * alpha) + (buf[b] * (255 - alpha))) / 255;
  655.  
  656. #endif
  657.               gimp_pixel_rgn_set_pixel (&src_rgn, buf, x, y);
  658.             }
  659.             }
  660.         }
  661.         }
  662.     }
  663.     }
  664.  
  665.   g_free (vals);
  666.   g_free (min_scanlines);
  667.   g_free (max_scanlines);
  668. }
  669.  
  670. static void
  671. convert_segment (gint  x1,
  672.          gint  y1,
  673.          gint  x2,
  674.          gint  y2,
  675.          gint  offset,
  676.          gint *min,
  677.          gint *max)
  678. {
  679.   gint ydiff, y, tmp;
  680.   gdouble xinc, xstart;
  681.  
  682.   if (y1 > y2)
  683.     {
  684.       tmp = y2; y2 = y1; y1 = tmp;
  685.       tmp = x2; x2 = x1; x1 = tmp;
  686.     }
  687.   ydiff = (y2 - y1);
  688.  
  689.   if (ydiff)
  690.     {
  691.       xinc = (gdouble) (x2 - x1) / (gdouble) ydiff;
  692.       xstart = x1 + 0.5 * xinc;
  693.       for (y = y1 ; y < y2; y++)
  694.     {
  695.       if (xstart < min[y - offset])
  696.         min[y-offset] = xstart;
  697.       if (xstart > max[y - offset])
  698.         max[y-offset] = xstart;
  699.  
  700.       xstart += xinc;
  701.     }
  702.     }
  703. }
  704.  
  705. static void
  706. randomize_indices (gint  count,
  707.            gint *indices)
  708. {
  709.   gint i;
  710.   gint index1, index2;
  711.   gint tmp;
  712.  
  713.   for (i = 0; i < count * RANDOMNESS; i++)
  714.     {
  715.       index1 = int_rand (count);
  716.       index2 = int_rand (count);
  717.       tmp = indices[index1];
  718.       indices[index1] = indices[index2];
  719.       indices[index2] = tmp;
  720.     }
  721. }
  722.  
  723. static gdouble
  724. fp_rand (gdouble val)
  725. {
  726.   gdouble rand_val;
  727.  
  728.   rand_val = (gdouble) rand () / (gdouble) (G_MAXRAND - 1);
  729.   return rand_val * val;
  730. }
  731.  
  732. static gint
  733. int_rand (gint val)
  734. {
  735.   gint rand_val;
  736.  
  737.   rand_val = rand () % val;
  738.   return rand_val;
  739. }
  740.  
  741. static void
  742. polygon_add_point (Polygon *poly,
  743.            gdouble  x,
  744.            gdouble  y)
  745. {
  746.   if (poly->npts < 12)
  747.     {
  748.       poly->pts[poly->npts].x = x;
  749.       poly->pts[poly->npts].y = y;
  750.       poly->npts++;
  751.     }
  752.   else
  753.     g_print ("Unable to add additional point.\n");
  754. }
  755.  
  756. static void
  757. polygon_rotate (Polygon *poly,
  758.         gdouble  theta)
  759. {
  760.   gint i;
  761.   gdouble ct, st;
  762.   gdouble ox, oy;
  763.  
  764.   ct = cos (theta);
  765.   st = sin (theta);
  766.  
  767.   for (i = 0; i < poly->npts; i++)
  768.     {
  769.       ox = poly->pts[i].x;
  770.       oy = poly->pts[i].y;
  771.       poly->pts[i].x = ct * ox - st * oy;
  772.       poly->pts[i].y = st * ox + ct * oy;
  773.     }
  774. }
  775.  
  776. static void
  777. polygon_translate (Polygon *poly,
  778.            gdouble  tx,
  779.            gdouble  ty)
  780. {
  781.   gint i;
  782.  
  783.   for (i = 0; i < poly->npts; i++)
  784.     {
  785.       poly->pts[i].x += tx;
  786.       poly->pts[i].y += ty;
  787.     }
  788. }
  789.  
  790. static gint
  791. polygon_extents (Polygon *poly,
  792.          gdouble *x1,
  793.          gdouble *y1,
  794.          gdouble *x2,
  795.          gdouble *y2)
  796. {
  797.   gint i;
  798.  
  799.   if (!poly->npts)
  800.     return 0;
  801.  
  802.   *x1 = *x2 = poly->pts[0].x;
  803.   *y1 = *y2 = poly->pts[0].y;
  804.  
  805.   for (i = 1; i < poly->npts; i++)
  806.     {
  807.       if (poly->pts[i].x < *x1)
  808.     *x1 = poly->pts[i].x;
  809.       if (poly->pts[i].x > *x2)
  810.     *x2 = poly->pts[i].x;
  811.       if (poly->pts[i].y < *y1)
  812.     *y1 = poly->pts[i].y;
  813.       if (poly->pts[i].y > *y2)
  814.     *y2 = poly->pts[i].y;
  815.     }
  816.  
  817.   return 1;
  818. }
  819.  
  820. static void
  821. polygon_reset (Polygon *poly)
  822. {
  823.   poly->npts = 0;
  824. }
  825.