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 / lic.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  31.0 KB  |  1,344 lines

  1. /* LIC 0.14 -- image filter plug-in for The Gimp program
  2.  * Copyright (C) 1996 Tom Bech
  3.  *
  4.  * E-mail: tomb@gimp.org
  5.  * You can contact the original The Gimp authors at gimp@xcf.berkeley.edu
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  *
  21.  * In other words, you can't sue me for whatever happens while using this ;)
  22.  *
  23.  * Changes (post 0.10):
  24.  * -> 0.11: Fixed a bug in the convolution kernels (Tom).
  25.  * -> 0.12: Added Quartic's bilinear interpolation stuff (Tom).
  26.  * -> 0.13 Changed some UI stuff causing trouble with the 0.60 release, added
  27.  *         the (GIMP) tags and changed random() calls to rand() (Tom)
  28.  * -> 0.14 Ported to 0.99.11 (Tom)
  29.  *
  30.  * This plug-in implements the Line Integral Convolution (LIC) as described in
  31.  * Cabral et al. "Imaging vector fields using line integral convolution" in the
  32.  * Proceedings of ACM SIGGRAPH 93. Publ. by ACM, New York, NY, USA. p. 263-270.
  33.  * Some of the code is based on code by Steinar Haugen (thanks!), the Perlin
  34.  * noise function is practically ripped as is :)
  35.  */
  36.  
  37. #include "config.h"
  38.  
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <signal.h>
  42.  
  43. #include <gdk/gdk.h>
  44. #include <gtk/gtk.h>
  45.  
  46. #include <libgimp/gimp.h>
  47. #include <libgimp/gimpui.h>
  48.  
  49. #include "libgimp/stdplugins-intl.h"
  50.  
  51.  
  52. /************/
  53. /* Typedefs */
  54. /************/
  55.  
  56. #define CHECKBOUNDS(x,y) (x>=0 && y>=0 && x<width && y<height)
  57.  
  58. #define EPSILON 1.0e-5
  59.  
  60. #define numx    40              /* Pseudo-random vector grid size */
  61. #define numy    40
  62.  
  63. #define stepx   0.5
  64. #define stepy   0.5
  65.  
  66. #define TILE_CACHE_SIZE 16
  67.  
  68. /***********************/
  69. /* Some useful structs */
  70. /***********************/
  71.  
  72. typedef struct
  73. {
  74.   gdouble r, g, b, a;
  75. } rgbpixel;
  76.  
  77. /*****************************/
  78. /* Global variables and such */
  79. /*****************************/
  80.  
  81. static rgbpixel black = { 0.0, 0.0, 0.0 };
  82.  
  83. static gdouble G[numx][numy][2];
  84.  
  85. typedef struct
  86. {
  87.   gdouble  filtlen;
  88.   gdouble  noisemag;
  89.   gdouble  intsteps;
  90.   gdouble  minv;
  91.   gdouble  maxv;
  92.   gboolean create_new_image;
  93.   gint     effect_channel;
  94.   gint     effect_operator;
  95.   gint     effect_convolve;
  96.   gint32   effect_image_id;
  97. } LicValues;
  98.  
  99. static LicValues licvals;
  100.  
  101. static gdouble l      = 10.0;
  102. static gdouble dx     =  2.0;
  103. static gdouble dy     =  2.0;
  104. static gdouble minv   = -2.5;
  105. static gdouble maxv   =  2.5;
  106. static gdouble isteps = 20.0;
  107.  
  108. static GimpDrawable *input_drawable;
  109. static GimpDrawable *output_drawable;
  110. static GimpPixelRgn  source_region;
  111. static GimpPixelRgn  dest_region;
  112.  
  113. static gint    width, height, in_channels;
  114. static gint    border_x1, border_y1, border_x2, border_y2;
  115. static glong   maxcounter;
  116. static guchar *scalarfield;
  117.  
  118. static GtkWidget *dialog;
  119.  
  120. /************************/
  121. /* Convenience routines */
  122. /************************/
  123.  
  124. static void
  125. rgb_add (rgbpixel *a,
  126.      rgbpixel *b)
  127. {
  128.   a->r = a->r + b->r;
  129.   a->g = a->g + b->g;
  130.   a->b = a->b + b->b;
  131. }
  132.  
  133. static void
  134. rgb_mul (rgbpixel *a,
  135.      gdouble   b)
  136. {
  137.   a->r = a->r * b;
  138.   a->g = a->g * b;
  139.   a->b = a->b * b;
  140. }
  141.  
  142. static void
  143. rgb_clamp (rgbpixel *a)
  144. {
  145.   a->r = CLAMP (a->r, 0.0, 1.0);
  146.   a->g = CLAMP (a->g, 0.0, 1.0);
  147.   a->b = CLAMP (a->b, 0.0, 1.0);
  148. }
  149.  
  150. static rgbpixel
  151. peek (gint x,
  152.       gint y)
  153. {
  154.   static guchar data[4];
  155.   rgbpixel color;
  156.  
  157.   gimp_pixel_rgn_get_pixel (&source_region, data, x, y);
  158.  
  159.   color.r = (gdouble) data[0] / 255.0;
  160.   color.g = (gdouble) data[1] / 255.0;
  161.   color.b = (gdouble) data[2] / 255.0;
  162.  
  163.   if (input_drawable->bpp == 4)
  164.     {
  165.       if (in_channels == 4)
  166.         color.a = (gdouble) data[3] / 255.0;
  167.       else
  168.         color.a = 1.0;
  169.     }
  170.   else
  171.     color.a = 1.0;
  172.  
  173.   return color;
  174. }
  175.  
  176. static void
  177. poke (gint      x,
  178.       gint      y,
  179.       rgbpixel *color)
  180. {
  181.   static guchar data[4];
  182.   
  183.   data[0] = (guchar) (color->r * 255.0);
  184.   data[1] = (guchar) (color->g * 255.0);
  185.   data[2] = (guchar) (color->b * 255.0);
  186.   data[3] = (guchar) (color->a * 255.0);
  187.  
  188.   gimp_pixel_rgn_set_pixel (&dest_region, data, x, y);
  189. }
  190.  
  191. /****************************************/
  192. /* Allocate memory for temporary images */
  193. /****************************************/
  194.  
  195. static gint
  196. image_setup (GimpDrawable *drawable,
  197.          gint       interactive)
  198. {
  199.   /* Get some useful info on the input drawable */
  200.   /* ========================================== */
  201.  
  202.   input_drawable = drawable;
  203.   output_drawable = drawable;
  204.  
  205.   gimp_drawable_mask_bounds (drawable->id,
  206.                  &border_x1, &border_y1, &border_x2, &border_y2);
  207.  
  208.   width = input_drawable->width;
  209.   height = input_drawable->height;
  210.  
  211.   gimp_pixel_rgn_init (&source_region, input_drawable,
  212.                0, 0, width, height, FALSE, FALSE);
  213.  
  214.   maxcounter = (glong) width * (glong) height;
  215.  
  216.   /* Assume at least RGB */
  217.   /* =================== */
  218.  
  219.   in_channels = 3;
  220.   if (gimp_drawable_has_alpha (input_drawable->id))
  221.     in_channels++;
  222.  
  223.   if (interactive)
  224.     {
  225.       /* Allocate memory for temp. images */
  226.       /* ================================ */
  227.     }
  228.  
  229.   return TRUE;
  230. }
  231.  
  232. static guchar
  233. peekmap (guchar *image,
  234.      gint    x,
  235.      gint    y)
  236. {
  237.   glong index;
  238.  
  239.   index = (glong) x + (glong) width * (glong) y;
  240.  
  241.   return image[index] ;
  242. }
  243.  
  244. /*************/
  245. /* Main part */
  246. /*************/
  247.  
  248. /***************************************************/
  249. /* Compute the derivative in the x and y direction */
  250. /* We use these convolution kernels:               */
  251. /*     |1 0 -1|     |  1   2   1|                  */
  252. /* DX: |2 0 -2| DY: |  0   0   0|                  */
  253. /*     |1 0 -1|     | -1  -2  -1|                  */
  254. /* (It's a varation of the Sobel kernels, really)  */
  255. /***************************************************/
  256.  
  257. static gint
  258. gradx (guchar *image,
  259.        gint    x,
  260.        gint    y)
  261. {
  262.   gint val=0;
  263.  
  264.   if (CHECKBOUNDS (x-1, y-1))
  265.     val = val + (gint) peekmap (image, x-1, y-1);
  266.   if (CHECKBOUNDS (x+1, y-1))
  267.     val = val - (gint) peekmap (image, x+1, y-1);
  268.  
  269.   if (CHECKBOUNDS (x-1, y))
  270.     val = val + 2 * (gint) peekmap (image, x-1, y);
  271.   if (CHECKBOUNDS (x+1, y))
  272.     val = val - 2 * (gint) peekmap (image, x+1, y);
  273.  
  274.   if (CHECKBOUNDS (x-1, y+1))
  275.     val = val + (gint) peekmap (image, x-1, y+1);
  276.   if (CHECKBOUNDS (x+1, y+1))
  277.     val = val - (gint) peekmap (image, x+1, y+1);
  278.  
  279.   return val;
  280. }
  281.  
  282. static gint
  283. grady (guchar *image,
  284.        gint    x,
  285.        gint    y)
  286. {
  287.   gint val = 0;
  288.  
  289.   if (CHECKBOUNDS (x-1, y-1))
  290.     val = val + (gint) peekmap (image, x-1, y-1);
  291.   if (CHECKBOUNDS (x, y-1))
  292.     val = val + 2 * (gint) peekmap (image, x, y-1);
  293.   if (CHECKBOUNDS (x+1, y-1))
  294.     val = val + (gint) peekmap (image, x+1, y-1);
  295.  
  296.   if (CHECKBOUNDS (x-1, y+1))
  297.     val = val - (gint) peekmap (image, x-1, y+1);
  298.   if (CHECKBOUNDS (x, y+1))
  299.     val = val - 2 * (gint) peekmap (image, x, y+1);
  300.   if (CHECKBOUNDS (x+1, y+1))
  301.     val = val - (gint) peekmap (image, x+1, y+1);
  302.  
  303.   return val;
  304. }
  305.  
  306. /************************************/
  307. /* A nice 2nd order cubic spline :) */
  308. /************************************/
  309.  
  310. static gdouble
  311. cubic (gdouble t)
  312. {
  313.   gdouble at = fabs (t);
  314.  
  315.   if (at<1.0)
  316.     return 2.0 * at*at*at - 3.0 * at*at + 1.0;
  317.  
  318.   return 0.0;
  319. }
  320.  
  321. static gdouble
  322. omega (gdouble u,
  323.        gdouble v,
  324.        gint    i,
  325.        gint    j)
  326. {
  327.   while (i < 0)
  328.     i += numx;
  329.  
  330.   while (j < 0)
  331.     j += numy;
  332.  
  333.   i %= numx;
  334.   j %= numy;
  335.  
  336.   return cubic (u) * cubic (v) * (G[i][j][0]*u + G[i][j][1]*v);
  337. }
  338.  
  339. /*************************************************************/
  340. /* The noise function (2D variant of Perlins noise function) */
  341. /*************************************************************/
  342.  
  343. static gdouble
  344. noise (gdouble x,
  345.        gdouble y)
  346. {
  347.   gint i, sti = (gint) floor (x / dx);
  348.   gint j, stj = (gint) floor (y / dy);
  349.  
  350.   gdouble sum = 0.0;
  351.  
  352.   /* Calculate the gdouble sum */
  353.   /* ======================== */
  354.  
  355.   for (i = sti; i <= sti + 1; i++)
  356.     {
  357.       for (j = stj; j <= stj + 1; j++)
  358.         sum += omega ((x - (gdouble) i * dx) / dx,
  359.               (y - (gdouble) j * dy) / dy,
  360.               i, j);
  361.     }
  362.  
  363.   return sum;
  364. }
  365.  
  366. /*************************************************/
  367. /* Generates pseudo-random vectors with length 1 */
  368. /*************************************************/
  369.  
  370. static void
  371. generatevectors (void)
  372. {
  373.   gdouble alpha;
  374.   gint i, j;
  375.  
  376.   for (i = 0; i < numx; i++)
  377.     {
  378.       for (j = 0; j < numy; j++)
  379.         {
  380.           alpha = (gdouble) (rand () % 1000) * (G_PI / 500.0);
  381.           G[i][j][0] = cos (alpha);
  382.           G[i][j][1] = sin (alpha);
  383.         }
  384.     }
  385. }
  386.  
  387. /* A simple triangle filter */
  388. /* ======================== */
  389.  
  390. static gdouble
  391. filter (gdouble u)
  392. {
  393.   gdouble f = 1.0 - fabs (u) / l;
  394.  
  395.   if (f < 0.0)
  396.     f = 0.0;
  397.  
  398.   return f;
  399. }
  400.  
  401. /******************************************************/
  402. /* Compute the Line Integral Convolution (LIC) at x,y */
  403. /******************************************************/
  404.  
  405. static gdouble
  406. lic_noise (gint    x,
  407.        gint    y,
  408.        gdouble vx,
  409.        gdouble vy)
  410. {
  411.   gdouble i = 0.0;
  412.   gdouble f1 = 0.0, f2 = 0.0;
  413.   gdouble u, step = 2.0 * l / isteps;
  414.   gdouble xx = (gdouble) x, yy = (gdouble) y;
  415.   gdouble c, s;
  416.  
  417.   /* Get vector at x,y */
  418.   /* ================= */
  419.  
  420.   c = vx;
  421.   s = vy;
  422.  
  423.   /* Calculate integral numerically */
  424.   /* ============================== */
  425.  
  426.   f1 = filter (-l) * noise (xx + l * c , yy + l * s);
  427.  
  428.   for (u = -l + step; u <= l; u += step)
  429.     {
  430.       f2 = filter (u) * noise ( xx - u * c , yy - u * s);
  431.       i += (f1 + f2) * 0.5 * step;
  432.       f1 = f2;
  433.     }
  434.  
  435.   i = (i - minv) / (maxv - minv);
  436.  
  437.   if (i < 0.0)
  438.     i = 0.0;
  439.   
  440.   if (i > 1.0)
  441.     i = 1.0;
  442.  
  443.   i = (i / 2.0) + 0.5;
  444.  
  445.   return i;
  446. }
  447.  
  448. static rgbpixel
  449. bilinear (gdouble   x,
  450.       gdouble   y,
  451.       rgbpixel *p)
  452. {
  453.   gdouble  m0, m1;
  454.   gdouble  ix, iy;
  455.   rgbpixel v;
  456.  
  457.   x = fmod (x, 1.0);
  458.   y = fmod (y, 1.0);
  459.  
  460.   if (x < 0)
  461.      x += 1.0;
  462.  
  463.   if (y < 0)
  464.     y += 1.0;
  465.  
  466.   ix = 1.0 - x;
  467.   iy = 1.0 - y;
  468.  
  469.   /* Red */
  470.   /* === */
  471.  
  472.   m0 = ix * p[0].r + x * p[1].r;
  473.   m1 = ix * p[2].r + x * p[3].r;
  474.  
  475.   v.r = iy * m0 + y * m1;
  476.  
  477.   /* Green */
  478.   /* ===== */
  479.  
  480.   m0 = ix * p[0].g + x * p[1].g;
  481.   m1 = ix * p[2].g + x * p[3].g;
  482.  
  483.   v.g = iy * m0 + y * m1;
  484.  
  485.   /* Blue */
  486.   /* ==== */
  487.  
  488.   m0 = ix * p[0].b + x * p[1].b;
  489.   m1 = ix * p[2].b + x * p[3].b;
  490.  
  491.   v.b = iy * m0 + y * m1;
  492.  
  493.   return v;
  494. }
  495.  
  496. static void
  497. getpixel (rgbpixel *p,
  498.       gdouble   u,
  499.       gdouble   v)
  500. {
  501.   register gint x1, y1, x2, y2;
  502.   static rgbpixel pp[4];
  503.  
  504.   x1 = (gint)u;
  505.   y1 = (gint)v;
  506.  
  507.   if (x1 < 0)
  508.     x1 = width - (-x1 % width);
  509.   else
  510.     x1 = x1 % width;
  511.   
  512.   if (y1 < 0)
  513.     y1 = height - (-y1 % height);
  514.   else
  515.     y1 = y1 % height;
  516.  
  517.   x2 = (x1 + 1) % width;
  518.   y2 = (y1 + 1) % height;
  519.  
  520.   pp[0] = peek (x1, y1);
  521.   pp[1] = peek (x2, y1);
  522.   pp[2] = peek (x1, y2);
  523.   pp[3] = peek (x2, y2);
  524.  
  525.   *p = bilinear (u, v, pp);
  526. }
  527.  
  528. static void
  529. lic_image (gint      x,
  530.        gint      y,
  531.        gdouble   vx,
  532.        gdouble   vy,
  533.        rgbpixel *color)
  534. {
  535.   gdouble u, step = 2.0 * l / isteps;
  536.   gdouble xx = (gdouble) x, yy = (gdouble) y;
  537.   gdouble c, s;
  538.   rgbpixel col, col1, col2, col3;
  539.  
  540.   /* Get vector at x,y */
  541.   /* ================= */
  542.  
  543.   c = vx;
  544.   s = vy;
  545.  
  546.   /* Calculate integral numerically */
  547.   /* ============================== */
  548.  
  549.   col = black;
  550.   getpixel (&col1, xx + l * c, yy + l * s);
  551.   rgb_mul (&col1, filter (-l));
  552.  
  553.   for (u = -l + step; u <= l; u += step)
  554.     {
  555.       getpixel (&col2, xx - u * c, yy - u * s);
  556.       rgb_mul (&col2, filter (u));
  557.  
  558.       col3 = col1;
  559.       rgb_add (&col3, &col2);
  560.       rgb_mul (&col3, 0.5 * step);
  561.       rgb_add (&col, &col3);
  562.  
  563.       col1 = col2;
  564.     }
  565.  
  566.   rgb_mul (&col, 1.0 / l);
  567.   rgb_clamp (&col);
  568.  
  569.   *color = col;
  570. }
  571.  
  572. static gdouble
  573. maximum (gdouble a,
  574.      gdouble b,
  575.      gdouble c)
  576. {
  577.   gdouble max = a;
  578.  
  579.   if (b > max)
  580.     max = b;
  581.   if (c > max)
  582.     max = c;
  583.  
  584.   return max;
  585. }
  586.  
  587. static gdouble
  588. minimum (gdouble a,
  589.      gdouble b,
  590.      gdouble c)
  591. {
  592.   gdouble min = a;
  593.  
  594.   if (b < min)
  595.     min = b;
  596.   if (c < min)
  597.     min = c;
  598.  
  599.   return min;
  600. }
  601.  
  602. static void
  603. get_hue (rgbpixel *col,
  604.      gdouble  *hue)
  605. {
  606.   gdouble max, min, delta;
  607.  
  608.   max = maximum (col->r, col->g, col->b);
  609.   min = minimum (col->r, col->g, col->b);
  610.  
  611.   if (max == min)
  612.     {
  613.       *hue = -1.0;
  614.     }
  615.   else
  616.     {
  617.       delta = max-min;
  618.       if (col->r == max)
  619.         *hue = (col->g - col->b) / delta;
  620.       else if (col->g == max)
  621.         *hue = 2.0 + (col->b - col->r) / delta;
  622.       else if (col->b == max)
  623.         *hue = 4.0 + (col->r - col->g) / delta;
  624.  
  625.       *hue = *hue * 60.0;
  626.       if (*hue < 0.0)
  627.         *hue = *hue + 360.0;
  628.     }
  629. }
  630.  
  631. static void
  632. get_saturation (rgbpixel *col,
  633.         gdouble  *sat)
  634. {
  635.   gdouble max, min, l;
  636.  
  637.   max = maximum (col->r, col->g, col->b);
  638.   min = minimum (col->r, col->g, col->b);
  639.  
  640.   if (max == min)
  641.     {
  642.       *sat = 0.0;
  643.     }
  644.   else
  645.     {
  646.       l = (max + min) / 2.0;
  647.       if (l <= 0.5)
  648.         *sat = (max - min) / (max + min);
  649.       else
  650.         *sat = (max - min) / (2.0 - max - min);
  651.     }
  652. }
  653.  
  654. static void
  655. get_brightness (rgbpixel *col,
  656.         gdouble  *bri)
  657. {
  658.   gdouble max, min;
  659.  
  660.   max = maximum (col->r, col->g, col->b);
  661.   min = minimum (col->r, col->g, col->b);
  662.  
  663.   *bri = (max + min) / 2.0;
  664. }
  665.  
  666. static void
  667. rgb_to_hue (GimpDrawable  *image,
  668.         guchar    **map)
  669. {
  670.   guchar *themap, data[4];
  671.   gint w, h, x, y;
  672.   rgbpixel color;
  673.   gdouble val;
  674.   glong maxc, index = 0;
  675.   GimpPixelRgn region;
  676.  
  677.   w = image->width;
  678.   h = image->height;
  679.   maxc = (glong) w * (glong) h;
  680.  
  681.   /* gimp_drawable_mask_bounds (drawable->id,
  682.      &border_x1, &border_y1, &border_x2, &border_y2); */
  683.  
  684.   gimp_pixel_rgn_init (®ion, image,  0, 0, w, h, FALSE, FALSE);
  685.  
  686.   themap = g_new (guchar, maxc);
  687.  
  688.   for (y = 0; y < h; y++)
  689.     {
  690.       for (x = 0; x < w; x++)
  691.         {
  692.           gimp_pixel_rgn_get_pixel (®ion, data, x, y);
  693.  
  694.           color.r = data[0];
  695.           color.g = data[1];
  696.           color.b = data[2];
  697.  
  698.           get_hue (&color, &val);
  699.  
  700.           themap[index++] = (guchar) (val * 255.0);
  701.         }
  702.     }
  703.  
  704.   *map = themap;
  705. }
  706.  
  707. static void
  708. rgb_to_saturation (GimpDrawable  *image,
  709.            guchar    **map)
  710. {
  711.   guchar *themap, data[4];
  712.   gint w, h, x, y;
  713.   rgbpixel color;
  714.   gdouble val;
  715.   glong maxc, index = 0;
  716.   GimpPixelRgn region;
  717.  
  718.   w = image->width;
  719.   h = image->height;
  720.   maxc = (glong) w * (glong) h;
  721.  
  722.   /* gimp_drawable_mask_bounds (drawable->id,
  723.      &border_x1, &border_y1, &border_x2, &border_y2); */
  724.  
  725.   gimp_pixel_rgn_init (®ion, image,  0, 0, w, h, FALSE, FALSE);
  726.  
  727.   themap = g_new (guchar, maxc);
  728.  
  729.   for (y = 0; y < h; y++)
  730.     {
  731.       for (x = 0; x < w; x++)
  732.         {
  733.           gimp_pixel_rgn_get_pixel (®ion, data, x, y);
  734.  
  735.           color.r = data[0];
  736.           color.g = data[1];
  737.           color.b = data[2];
  738.  
  739.           get_saturation (&color, &val);
  740.  
  741.           themap[index++] = (guchar) (val * 255.0);
  742.         }
  743.     }
  744.  
  745.   *map = themap;
  746. }
  747.  
  748. static void
  749. rgb_to_brightness (GimpDrawable  *image,
  750.            guchar    **map)
  751. {
  752.   guchar *themap, data[4];
  753.   gint w, h, x, y;
  754.   rgbpixel color;
  755.   gdouble val;
  756.   glong maxc, index = 0;
  757.   GimpPixelRgn region;
  758.  
  759.   w = image->width;
  760.   h = image->height;
  761.   maxc = (glong) w * (glong) h;
  762.  
  763.   /* gimp_drawable_mask_bounds (drawable->id,
  764.      &border_x1, &border_y1, &border_x2, &border_y2); */
  765.  
  766.   gimp_pixel_rgn_init (®ion, image,  0, 0, w, h, FALSE, FALSE);
  767.  
  768.   themap = g_new (guchar, maxc);
  769.  
  770.   for (y = 0; y < h; y++)
  771.     {
  772.       for (x = 0; x < w; x++)
  773.         {
  774.           gimp_pixel_rgn_get_pixel (®ion, data, x, y);
  775.  
  776.           color.r = data[0];
  777.           color.g = data[1];
  778.           color.b = data[2];
  779.  
  780.           get_brightness (&color, &val);
  781.  
  782.           themap[index++] = (guchar) (val * 255.0);
  783.         }
  784.     }
  785.  
  786.   *map = themap;
  787. }
  788.  
  789. static void
  790. compute_lic_derivative (void)
  791. {
  792.   gint xcount, ycount;
  793.   glong counter = 0;
  794.   rgbpixel color;
  795.   gdouble vx, vy, tmp;
  796.  
  797.   for (ycount = 0; ycount < height; ycount++)
  798.     {
  799.       for (xcount = 0; xcount < width; xcount++)
  800.         {
  801.           /* Get direction vector at (x,y) and normalize it */
  802.           /* ============================================== */
  803.  
  804.           vx = gradx (scalarfield, xcount, ycount);
  805.           vy = grady (scalarfield, xcount, ycount);
  806.  
  807.           tmp = sqrt (vx * vx + vy * vy);
  808.           if (tmp != 0.0)
  809.             {
  810.               tmp = 1.0 / tmp;
  811.               vx *= tmp;
  812.           vy *= tmp;
  813.             }
  814.  
  815.           /* Convolve with the LIC at (x,y) */
  816.           /* ============================== */
  817.  
  818.           if (licvals.effect_convolve == 0)
  819.             {
  820.               color = peek (xcount, ycount);
  821.               tmp = lic_noise (xcount, ycount, vx, vy);
  822.               rgb_mul (&color, tmp);
  823.             }
  824.           else
  825.             lic_image (xcount, ycount, vx, vy, &color);
  826.  
  827.           poke (xcount, ycount, &color);
  828.  
  829.           counter++;
  830.  
  831.           if ((counter % width) == 0)
  832.             gimp_progress_update ((gfloat) counter / (gfloat) maxcounter);
  833.         }
  834.     }
  835. }
  836.  
  837. static void
  838. compute_lic_gradient (void)
  839. {
  840.   gint xcount, ycount;
  841.   glong counter = 0;
  842.   rgbpixel color;
  843.   gdouble vx, vy, tmp;
  844.  
  845.   for (ycount = 0; ycount < height; ycount++)
  846.     {
  847.       for (xcount = 0; xcount < width; xcount++)
  848.         {
  849.           /* Get derivative at (x,y), rotate it 90 degrees and normalize it */
  850.           /* ============================================================== */
  851.  
  852.           vx = gradx (scalarfield, xcount, ycount);
  853.           vy = grady (scalarfield, xcount, ycount);
  854.  
  855.           vx = -1.0 * vx; tmp = vy; vy = vx; vx = tmp;
  856.  
  857.           tmp = sqrt (vx * vx + vy * vy);
  858.           if (tmp != 0.0)
  859.             {
  860.               tmp = 1.0 / tmp;
  861.               vx *= tmp;
  862.           vy *= tmp;
  863.             }
  864.  
  865.           /* Convolve with the LIC at (x,y) */
  866.           /* ============================== */
  867.  
  868.           if (licvals.effect_convolve == 0)
  869.             {
  870.               color = peek (xcount, ycount);
  871.               tmp = lic_noise (xcount, ycount, vx, vy);
  872.               rgb_mul (&color, tmp);
  873.             }
  874.           else
  875.             lic_image (xcount, ycount, vx, vy, &color);
  876.  
  877.           poke (xcount, ycount, &color);
  878.  
  879.           counter++;
  880.  
  881.           if ((counter % width) == 0)
  882.             gimp_progress_update ((gfloat) counter / (gfloat) maxcounter);
  883.         }
  884.     }
  885. }
  886.  
  887. static void
  888. compute_image (void)
  889. {
  890.   gint32 new_image_id = -1, new_layer_id = -1;
  891.   GimpDrawable *effect;
  892.  
  893.   if (licvals.create_new_image)
  894.     {
  895.       /* Create a new image */
  896.       /* ================== */
  897.  
  898.       new_image_id = gimp_image_new (width, height, GIMP_RGB);
  899.       gimp_image_undo_disable (new_image_id);
  900.       
  901.       /* Create a "normal" layer */
  902.       /* ======================= */
  903.  
  904.       new_layer_id = gimp_layer_new (new_image_id, _("Background"),
  905.                      width, height, GIMP_RGB_IMAGE,
  906.                      100.0, GIMP_NORMAL_MODE);
  907.       gimp_image_add_layer (new_image_id, new_layer_id, 0);
  908.       output_drawable = gimp_drawable_get (new_layer_id);
  909.     }
  910.  
  911.   gimp_pixel_rgn_init (&dest_region, output_drawable,
  912.                0, 0, width, height, TRUE, TRUE);
  913.  
  914.   gimp_progress_init (_("Van Gogh (LIC)"));
  915.  
  916.   if (licvals.effect_convolve == 0)
  917.     generatevectors ();
  918.  
  919.   l = (gdouble) licvals.filtlen;
  920.   dx = dy = (gdouble) licvals.noisemag;
  921.   minv = ((gdouble) licvals.minv) / 10.0;
  922.   maxv = ((gdouble) licvals.maxv) / 10.0;
  923.   isteps = (gdouble) licvals.intsteps;
  924.  
  925.   effect = gimp_drawable_get (licvals.effect_image_id);
  926.  
  927.   switch (licvals.effect_channel)
  928.     {
  929.       case 0:
  930.         rgb_to_hue (effect, &scalarfield);
  931.         break;
  932.       case 1:
  933.         rgb_to_saturation (effect, &scalarfield);
  934.         break;
  935.       case 2:
  936.         rgb_to_brightness (effect, &scalarfield);
  937.         break;
  938.     }
  939.  
  940.   if (scalarfield == NULL)
  941.     {
  942.       g_print ("LIC: Couldn't allocate temporary buffer - out of memory!\n");
  943.       return;
  944.     }
  945.  
  946.   if (licvals.effect_operator == 0)
  947.     compute_lic_derivative ();
  948.   else
  949.     compute_lic_gradient ();
  950.  
  951.   g_free (scalarfield);
  952.  
  953.   /* Update image */
  954.   /* ============ */
  955.  
  956.   gimp_drawable_flush (output_drawable);
  957.   gimp_drawable_merge_shadow (output_drawable->id, TRUE);
  958.   gimp_drawable_update (output_drawable->id, 0, 0, width, height);
  959.  
  960.   if (new_image_id != -1)
  961.     {
  962.       gimp_display_new (new_image_id);
  963.       gimp_displays_flush ();
  964.       gimp_drawable_detach (output_drawable);
  965.       gimp_image_undo_enable (new_image_id);
  966.     }
  967. }
  968.  
  969. /**************************/
  970. /* Below is only UI stuff */
  971. /**************************/
  972.  
  973. static void
  974. ok_button_clicked (GtkWidget *widget,
  975.            gpointer   data)
  976. {
  977.   gtk_widget_hide (GTK_WIDGET (data));
  978.   gdk_flush ();
  979.   compute_image ();
  980.   gtk_main_quit ();
  981. }
  982.  
  983. static gint
  984. effect_image_constrain (gint32    image_id,
  985.             gint32   drawable_id,
  986.             gpointer data)
  987. {
  988.   if (drawable_id == -1)
  989.     return(TRUE);
  990.  
  991.   return gimp_drawable_is_rgb (drawable_id);
  992. }
  993.  
  994. static void
  995. effect_image_callback (gint32   id,
  996.                gpointer data)
  997. {
  998.   licvals.effect_image_id = id;
  999. }
  1000.  
  1001. static void
  1002. create_main_dialog (void)
  1003. {
  1004.   GtkWidget *main_vbox;
  1005.   GtkWidget *vbox;
  1006.   GtkWidget *sep;
  1007.   GtkWidget *hbox;
  1008.   GtkWidget *frame;
  1009.   GtkWidget *table;
  1010.   GtkWidget *option_menu;
  1011.   GtkWidget *menu;
  1012.   GtkWidget *button;
  1013.   GtkObject *scale_data;
  1014.   gint       row;
  1015.   
  1016.   dialog = gimp_dialog_new (_("Van Gogh (LIC)"), "lic",
  1017.                 gimp_standard_help_func, "filters/lic.html",
  1018.                 GTK_WIN_POS_MOUSE,
  1019.                 FALSE, TRUE, FALSE,
  1020.  
  1021.                 _("OK"), ok_button_clicked,
  1022.                 NULL, NULL, NULL, TRUE, FALSE,
  1023.                 _("Cancel"), gtk_main_quit,
  1024.                 NULL, NULL, NULL, FALSE, TRUE,
  1025.  
  1026.                 NULL);
  1027.  
  1028.   main_vbox = gtk_vbox_new (FALSE, 4);
  1029.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  1030.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
  1031.   gtk_widget_show (main_vbox);
  1032.  
  1033.   hbox = gtk_hbox_new (FALSE, 6);
  1034.   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
  1035.   gtk_widget_show (hbox);
  1036.  
  1037.   frame = gtk_frame_new (_("Options"));
  1038.   gtk_container_add (GTK_CONTAINER (hbox), frame);
  1039.   gtk_widget_show (frame);
  1040.  
  1041.   vbox = gtk_vbox_new (FALSE, 1);
  1042.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  1043.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  1044.   gtk_widget_show (vbox);
  1045.   
  1046.   button = gtk_check_button_new_with_label( _("Create\nNew Image"));
  1047.   gtk_label_set_justify (GTK_LABEL (GTK_BIN (button)->child), GTK_JUSTIFY_LEFT);
  1048.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  1049.                 licvals.create_new_image == TRUE);
  1050.   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  1051.   gtk_widget_show (button);
  1052.  
  1053.   frame = gimp_radio_group_new2 (TRUE, _("Effect Channel"),
  1054.                  gimp_radio_button_update,
  1055.                  &licvals.effect_channel,
  1056.                  (gpointer) licvals.effect_channel,
  1057.  
  1058.                  _("Hue"),        (gpointer) 0, NULL,
  1059.                  _("Saturation"), (gpointer) 1, NULL,
  1060.                  _("Brightness"), (gpointer) 2, NULL,
  1061.  
  1062.                  NULL);
  1063.   gtk_container_add (GTK_CONTAINER (hbox), frame);
  1064.   gtk_widget_show (frame);
  1065.  
  1066.   frame = gimp_radio_group_new2 (TRUE, _("Effect Operator"),
  1067.                  gimp_radio_button_update,
  1068.                  &licvals.effect_operator,
  1069.                  (gpointer) licvals.effect_operator,
  1070.  
  1071.                  _("Derivative"), (gpointer) 0, NULL,
  1072.                  _("Gradient"),   (gpointer) 1, NULL,
  1073.  
  1074.                  NULL);
  1075.   gtk_container_add (GTK_CONTAINER (hbox), frame);
  1076.   gtk_widget_show (frame);
  1077.  
  1078.   frame = gimp_radio_group_new2 (TRUE, _("Convolve"),
  1079.                  gimp_radio_button_update,
  1080.                  &licvals.effect_convolve,
  1081.                  (gpointer) licvals.effect_convolve,
  1082.  
  1083.                  _("With White Noise"),  (gpointer) 0, NULL,
  1084.                  _("With Source Image"), (gpointer) 1, NULL,
  1085.  
  1086.                  NULL);
  1087.   gtk_container_add (GTK_CONTAINER (hbox), frame);
  1088.   gtk_widget_show (frame);
  1089.  
  1090.   frame = gtk_frame_new (_("Parameter Settings"));
  1091.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  1092.   gtk_widget_show (frame);
  1093.  
  1094.   vbox = gtk_vbox_new (FALSE, 2);
  1095.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  1096.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  1097.   gtk_widget_show (vbox);
  1098.  
  1099.   /* Effect image menu */
  1100.   table = gtk_table_new (1, 2, FALSE);
  1101.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1102.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  1103.   gtk_widget_show (table);
  1104.  
  1105.   option_menu = gtk_option_menu_new ();
  1106.   menu = gimp_drawable_menu_new (effect_image_constrain,
  1107.                  effect_image_callback,
  1108.                  NULL,
  1109.                  licvals.effect_image_id);
  1110.   gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
  1111.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  1112.                  _("Effect Image:"), 1.0, 0.5,
  1113.                  option_menu, 2, TRUE);
  1114.  
  1115.   sep = gtk_hseparator_new ();
  1116.   gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 0);
  1117.   gtk_widget_show (sep);
  1118.  
  1119.   table = gtk_table_new (5, 3, FALSE);
  1120.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1121.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  1122.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  1123.   gtk_widget_show (table);
  1124.  
  1125.   row = 0;
  1126.  
  1127.   scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1128.                      _("Filter Length:"), 0, 0,
  1129.                      licvals.filtlen, 0, 64, 1.0, 8.0, 1,
  1130.                      TRUE, 0, 0,
  1131.                      NULL, NULL);
  1132.   gtk_signal_connect (GTK_OBJECT(scale_data), "value_changed",
  1133.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  1134.               &licvals.filtlen);
  1135.  
  1136.   scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1137.                      _("Noise Magnitude:"), 0, 0,
  1138.                      licvals.noisemag, 1, 5, 0.1, 1.0, 1,
  1139.                      TRUE, 0, 0,
  1140.                      NULL, NULL);
  1141.   gtk_signal_connect (GTK_OBJECT(scale_data), "value_changed",
  1142.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  1143.               &licvals.noisemag);
  1144.  
  1145.   scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1146.                      _("Integration Steps:"), 0, 0,
  1147.                      licvals.intsteps, 1, 40, 1.0, 5.0, 1,
  1148.                      TRUE, 0, 0,
  1149.                      NULL, NULL);
  1150.   gtk_signal_connect (GTK_OBJECT(scale_data), "value_changed",
  1151.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  1152.               &licvals.intsteps);
  1153.  
  1154.   scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1155.                      _("Minimum Value:"), 0, 0,
  1156.                      licvals.minv, -100, 0, 1, 10, 1,
  1157.                      TRUE, 0, 0,
  1158.                      NULL, NULL);
  1159.   gtk_signal_connect (GTK_OBJECT(scale_data), "value_changed",
  1160.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  1161.               &licvals.minv);
  1162.  
  1163.   scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1164.                      _("Maximum Value:"), 0, 0,
  1165.                      licvals.maxv, 0, 100, 1, 10, 1,
  1166.                      TRUE, 0, 0,
  1167.                      NULL, NULL);
  1168.   gtk_signal_connect (GTK_OBJECT(scale_data), "value_changed",
  1169.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  1170.               &licvals.maxv);
  1171.  
  1172.   gtk_widget_show (dialog);
  1173. }
  1174.  
  1175. /******************/
  1176. /* Implementation */
  1177. /******************/
  1178.  
  1179. static void lic_interactive    (GimpDrawable *drawable);
  1180. /*
  1181. static void lic_noninteractive (GimpDrawable *drawable);
  1182. */
  1183.  
  1184. /*************************************/
  1185. /* Set parameters to standard values */
  1186. /*************************************/
  1187.  
  1188. static void
  1189. set_default_settings (void)
  1190. {
  1191.   licvals.filtlen=5;
  1192.   licvals.noisemag=2;
  1193.   licvals.intsteps=25;
  1194.   licvals.minv=-25;
  1195.   licvals.maxv=25;
  1196.   licvals.create_new_image=TRUE;  
  1197.   licvals.effect_channel=2;
  1198.   licvals.effect_operator=1;
  1199.   licvals.effect_convolve=1;
  1200.   licvals.effect_image_id=0;
  1201. }
  1202.  
  1203. static void
  1204. query (void)
  1205. {
  1206.   static GimpParamDef args[] =
  1207.   {
  1208.     { GIMP_PDB_INT32, "run_mode", "Interactive" },
  1209.     { GIMP_PDB_IMAGE, "image", "Input image" },
  1210.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
  1211.   };
  1212.   static gint nargs = sizeof (args) / sizeof (args[0]);
  1213.  
  1214.   gimp_install_procedure ("plug_in_lic",
  1215.               "Creates a Van Gogh effect (Line Integral Convolution)",
  1216.               "No help yet",
  1217.               "Tom Bech & Federico Mena Quintero",
  1218.               "Tom Bech & Federico Mena Quintero",
  1219.               "Version 0.14, September 24 1997",
  1220.               N_("<Image>/Filters/Map/Van Gogh (LIC)..."),
  1221.               "RGB",
  1222.               GIMP_PLUGIN,
  1223.               nargs, 0,
  1224.               args, NULL);
  1225. }
  1226.  
  1227. static void
  1228. run (gchar   *name,
  1229.      gint     nparams,
  1230.      GimpParam  *param,
  1231.      gint    *nreturn_vals,
  1232.      GimpParam **return_vals)
  1233. {
  1234.   static GimpParam values[1];
  1235.   GimpDrawable *drawable;
  1236.   GimpRunModeType run_mode;
  1237.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  1238.  
  1239.   run_mode = param[0].data.d_int32;
  1240.  
  1241.   if (run_mode == GIMP_RUN_INTERACTIVE)
  1242.     {
  1243.       INIT_I18N_UI();
  1244.     }
  1245.   else
  1246.     {
  1247.       INIT_I18N();
  1248.     }
  1249.  
  1250.   *nreturn_vals = 1;
  1251.   *return_vals = values;
  1252.  
  1253.   values[0].type = GIMP_PDB_STATUS;
  1254.   values[0].data.d_status = status;
  1255.  
  1256.   /* Set default values */
  1257.   /* ================== */
  1258.  
  1259.   set_default_settings ();
  1260.  
  1261.   /* Possibly retrieve data */
  1262.   /* ====================== */
  1263.  
  1264.   gimp_get_data ("plug_in_lic", &licvals);
  1265.  
  1266.   /* Get the specified drawable */
  1267.   /* ========================== */
  1268.   
  1269.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  1270.  
  1271.   if (status == GIMP_PDB_SUCCESS)
  1272.     {
  1273.       /* Make sure that the drawable is RGBA or RGB color */
  1274.       /* ================================================ */
  1275.  
  1276.       if (gimp_drawable_is_rgb (drawable->id))
  1277.     {
  1278.       /* Set the tile cache size */
  1279.           /* ======================= */
  1280.  
  1281.       gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
  1282.  
  1283.           switch (run_mode)
  1284.             {
  1285.               case GIMP_RUN_INTERACTIVE:
  1286.                 lic_interactive (drawable);
  1287.                 gimp_set_data ("plug_in_lic", &licvals, sizeof (LicValues));
  1288.               break;
  1289.               case GIMP_RUN_WITH_LAST_VALS:
  1290.                 image_setup (drawable, FALSE);
  1291.                 compute_image ();
  1292.                 break;
  1293.               default:
  1294.                 break;
  1295.             }
  1296.         }
  1297.       else
  1298.         status = GIMP_PDB_EXECUTION_ERROR;
  1299.     }
  1300.  
  1301.   values[0].data.d_status = status;
  1302.   gimp_drawable_detach (drawable);
  1303. }
  1304.  
  1305. GimpPlugInInfo PLUG_IN_INFO =
  1306. {
  1307.   NULL,  /* init_proc  */
  1308.   NULL,  /* quit_proc  */
  1309.   query, /* query_proc */
  1310.   run,   /* run_proc   */
  1311. };
  1312.  
  1313. static void
  1314. lic_interactive (GimpDrawable *drawable)
  1315. {
  1316.   gimp_ui_init ("lic", TRUE);
  1317.  
  1318.   /* Create application window */
  1319.   /* ========================= */
  1320.  
  1321.   create_main_dialog ();
  1322.  
  1323.   /* Prepare images */
  1324.   /* ============== */
  1325.  
  1326.   image_setup (drawable, TRUE);
  1327.   
  1328.   /* Gtk main event loop */
  1329.   /* =================== */
  1330.   
  1331.   gtk_main ();
  1332.   gdk_flush ();
  1333. }
  1334.  
  1335. /*
  1336. static void
  1337. lic_noninteractive (GimpDrawable *drawable)
  1338. {
  1339.   g_message ("Noninteractive not yet implemented! Sorry.\n");
  1340. }
  1341. */
  1342.  
  1343. MAIN ()
  1344.