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

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * Polarize plug-in --- maps a rectangul to a circle or vice-versa
  5.  * Copyright (C) 1997 Daniel Dunbar
  6.  * Email: ddunbar@diads.com
  7.  * WWW:   http://millennium.diads.com/gimp/
  8.  * Copyright (C) 1997 Federico Mena Quintero
  9.  * federico@nuclecu.unam.mx
  10.  * Copyright (C) 1996 Marc Bless
  11.  * E-mail: bless@ai-lab.fh-furtwangen.de
  12.  * WWW:    www.ai-lab.fh-furtwangen.de/~bless
  13.  *
  14.  * This program is free software; you can redistribute it and/or modify
  15.  * it under the terms of the GNU General Public License as published by
  16.  * the Free Software Foundation; either version 2 of the License, or
  17.  * (at your option) any later version.
  18.  *
  19.  * This program is distributed in the hope that it will be useful,
  20.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.  * GNU General Public License for more details.
  23.  *
  24.  * You should have received a copy of the GNU General Public License
  25.  * along with this program; if not, write to the Free Software
  26.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  27.  */
  28.  
  29.  
  30. /* Version 1.0:
  31.  * This is the follow-up release.  It contains a few minor changes, the
  32.  * most major being that the first time I released the wrong version of
  33.  * the code, and this time the changes have been fixed.  I also added
  34.  * tooltips to the dialog.
  35.  *
  36.  * Feel free to email me if you have any comments or suggestions on this
  37.  * plugin.
  38.  *               --Daniel Dunbar
  39.  *                 ddunbar@diads.com
  40.  */
  41.  
  42.  
  43. /* Version .5:
  44.  * This is the first version publicly released, it will probably be the
  45.  * last also unless i can think of some features i want to add.
  46.  *
  47.  * This plug-in was created with loads of help from quartic (Frederico
  48.  * Mena Quintero), and would surely not have come about without it.
  49.  *
  50.  * The polar algorithms is copied from Marc Bless' polar plug-in for
  51.  * .54, many thanks to him also.
  52.  * 
  53.  * If you can think of a neat addition to this plug-in, or any other
  54.  * info about it, please email me at ddunbar@diads.com.
  55.  *                                     - Daniel Dunbar
  56.  */
  57.  
  58. #include "config.h"
  59.  
  60. #include <stdio.h>
  61. #include <signal.h>
  62. #include <stdlib.h>
  63. #ifdef HAVE_UNISTD_H
  64. #include <unistd.h>
  65. #endif
  66.  
  67. #include <gtk/gtk.h>
  68.  
  69. #include <libgimp/gimp.h>
  70. #include <libgimp/gimpui.h>
  71.  
  72. #include "libgimp/stdplugins-intl.h"
  73.  
  74.  
  75. #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
  76.  
  77.  
  78. /***** Magic numbers *****/
  79.  
  80. #define PLUG_IN_NAME    "plug_in_polar_coords"
  81. #define PLUG_IN_VERSION "July 1997, 0.5"
  82.  
  83. #define PREVIEW_SIZE 128
  84. #define SCALE_WIDTH  200
  85. #define ENTRY_WIDTH   60
  86.  
  87. /***** Types *****/
  88.  
  89. typedef struct
  90. {
  91.   gdouble circle;
  92.   gdouble angle;
  93.   gint backwards;
  94.   gint inverse;
  95.   gint polrec;
  96. } polarize_vals_t;
  97.  
  98. typedef struct
  99. {
  100.   GtkWidget *preview;
  101.   guchar    *check_row_0;
  102.   guchar    *check_row_1;
  103.   guchar    *image;
  104.   guchar    *dimage;
  105.  
  106.   gint       run;
  107. } polarize_interface_t;
  108.  
  109. typedef struct
  110. {
  111.   gint       col, row;
  112.   gint       img_width, img_height, img_bpp, img_has_alpha;
  113.   gint       tile_width, tile_height;
  114.   guchar     bg_color[4];
  115.   GimpDrawable *drawable;
  116.   GimpTile     *tile;
  117. } pixel_fetcher_t;
  118.  
  119.  
  120. /***** Prototypes *****/
  121.  
  122. static void query (void);
  123. static void run   (gchar   *name,
  124.            gint     nparams,
  125.            GimpParam  *param,
  126.            gint    *nreturn_vals,
  127.            GimpParam **return_vals);
  128.  
  129. static void   polarize(void);
  130. static int    calc_undistorted_coords(double wx, double wy,
  131.                       double *x, double *y);
  132. static guchar bilinear(double x, double y, guchar *values);
  133.  
  134. static pixel_fetcher_t *pixel_fetcher_new(GimpDrawable *drawable);
  135. static void             pixel_fetcher_set_bg_color(pixel_fetcher_t *pf, guchar r, guchar g, guchar b, guchar a);
  136. static void             pixel_fetcher_get_pixel(pixel_fetcher_t *pf, int x, int y, guchar *pixel);
  137. static void             pixel_fetcher_destroy(pixel_fetcher_t *pf);
  138.  
  139. static void build_preview_source_image(void);
  140.  
  141. static gint polarize_dialog       (void);
  142. static void dialog_update_preview (void);
  143.  
  144. static void dialog_scale_update (GtkAdjustment *adjustment, gdouble *value);
  145. static void dialog_ok_callback  (GtkWidget *widget, gpointer data);
  146.  
  147. static void polar_toggle_callback (GtkWidget *widget, gpointer data);
  148.  
  149. /***** Variables *****/
  150.  
  151. GimpPlugInInfo PLUG_IN_INFO =
  152. {
  153.   NULL,  /* init_proc  */
  154.   NULL,  /* quit_proc  */
  155.   query, /* query_proc */
  156.   run    /* run_proc   */
  157. };
  158.  
  159. static polarize_vals_t pcvals =
  160. {
  161.   100.0, /* circle */
  162.   0.0,  /* angle */
  163.   0, /* backwards */
  164.   1,  /* inverse */
  165.   1  /* polar to rectangular? */
  166. };
  167.  
  168. static polarize_interface_t pcint =
  169. {
  170.   NULL,  /* preview */
  171.   NULL,  /* check_row_0 */
  172.   NULL,  /* check_row_1 */
  173.   NULL,  /* image */
  174.   NULL,  /* dimage */
  175.   FALSE  /* run */
  176. };
  177.  
  178. static GimpDrawable *drawable;
  179.  
  180. static gint img_width, img_height, img_bpp, img_has_alpha;
  181. static gint sel_x1, sel_y1, sel_x2, sel_y2;
  182. static gint sel_width, sel_height;
  183. static gint preview_width, preview_height;
  184.  
  185. static double cen_x, cen_y;
  186. static double scale_x, scale_y;
  187.  
  188. /***** Functions *****/
  189.  
  190. MAIN ()
  191.  
  192. static void
  193. query (void)
  194. {
  195.   static GimpParamDef args[] =
  196.   {
  197.     { GIMP_PDB_INT32,    "run_mode",  "Interactive, non-interactive" },
  198.     { GIMP_PDB_IMAGE,    "image",     "Input image" },
  199.     { GIMP_PDB_DRAWABLE, "drawable",  "Input drawable" },
  200.     { GIMP_PDB_FLOAT,    "circle",    "Circle depth in %" },
  201.     { GIMP_PDB_FLOAT,    "angle",     "Offset angle" },
  202.     { GIMP_PDB_INT32,    "backwards",    "Map backwards?" },
  203.     { GIMP_PDB_INT32,    "inverse",     "Map from top?" },
  204.     { GIMP_PDB_INT32,    "polrec",     "Polar to rectangular?" }
  205.   };
  206.   static gint nargs = sizeof (args) / sizeof (args[0]);
  207.  
  208.   gimp_install_procedure (PLUG_IN_NAME,
  209.               "Converts and image to and from polar coords",
  210.               "Remaps and image from rectangular coordinates to polar coordinates "
  211.               "or vice versa",
  212.               "Daniel Dunbar and Federico Mena Quintero",
  213.               "Daniel Dunbar and Federico Mena Quintero",
  214.               PLUG_IN_VERSION,
  215.               N_("<Image>/Filters/Distorts/Polar Coords..."),
  216.               "RGB*, GRAY*",
  217.               GIMP_PLUGIN,
  218.               nargs, 0,
  219.               args, NULL);
  220. }
  221.  
  222. static void
  223. run (gchar   *name,
  224.      gint     nparams,
  225.      GimpParam  *param,
  226.      gint    *nreturn_vals,
  227.      GimpParam **return_vals)
  228. {
  229.   static GimpParam values[1];
  230.  
  231.   GimpRunModeType run_mode;
  232.   GimpPDBStatusType  status;
  233.   double       xhsiz, yhsiz;
  234.   int          pwidth, pheight;
  235.  
  236.   status   = GIMP_PDB_SUCCESS;
  237.   run_mode = param[0].data.d_int32;
  238.  
  239.   values[0].type          = GIMP_PDB_STATUS;
  240.   values[0].data.d_status = status;
  241.  
  242.   *nreturn_vals = 1;
  243.   *return_vals  = values;
  244.  
  245.   /* Get the active drawable info */
  246.  
  247.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  248.  
  249.   img_width     = gimp_drawable_width (drawable->id);
  250.   img_height    = gimp_drawable_height (drawable->id);
  251.   img_bpp       = gimp_drawable_bpp (drawable->id);
  252.   img_has_alpha = gimp_drawable_has_alpha (drawable->id);
  253.  
  254.   gimp_drawable_mask_bounds (drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
  255.  
  256.   /* Calculate scaling parameters */
  257.  
  258.   sel_width  = sel_x2 - sel_x1;
  259.   sel_height = sel_y2 - sel_y1;
  260.  
  261.   cen_x = (double) (sel_x1 + sel_x2 - 1) / 2.0;
  262.   cen_y = (double) (sel_y1 + sel_y2 - 1) / 2.0;
  263.  
  264.   xhsiz = (double) (sel_width - 1) / 2.0;
  265.   yhsiz = (double) (sel_height - 1) / 2.0;
  266.  
  267.   if (xhsiz < yhsiz)
  268.     {
  269.       scale_x = yhsiz / xhsiz;
  270.       scale_y = 1.0;
  271.     }
  272.   else if (xhsiz > yhsiz)
  273.     {
  274.       scale_x = 1.0;
  275.       scale_y = xhsiz / yhsiz;
  276.     }
  277.   else
  278.     {
  279.       scale_x = 1.0;
  280.       scale_y = 1.0;
  281.     }
  282.  
  283.   /* Calculate preview size */
  284.  
  285.   if (sel_width > sel_height)
  286.     {
  287.       pwidth  = MIN (sel_width, PREVIEW_SIZE);
  288.       pheight = sel_height * pwidth / sel_width;
  289.     }
  290.   else
  291.     {
  292.       pheight = MIN (sel_height, PREVIEW_SIZE);
  293.       pwidth  = sel_width * pheight / sel_height;
  294.     }
  295.  
  296.   preview_width  = MAX (pwidth, 2); /* Min size is 2 */
  297.   preview_height = MAX (pheight, 2);
  298.  
  299.   /* See how we will run */
  300.  
  301.   switch (run_mode)
  302.     {
  303.     case GIMP_RUN_INTERACTIVE:
  304.       INIT_I18N_UI();
  305.  
  306.       /* Possibly retrieve data */
  307.       gimp_get_data (PLUG_IN_NAME, &pcvals);
  308.  
  309.       /* Get information from the dialog */
  310.       if (!polarize_dialog ())
  311.     return;
  312.  
  313.       break;
  314.  
  315.     case GIMP_RUN_NONINTERACTIVE:
  316.       INIT_I18N();
  317.  
  318.       /* Make sure all the arguments are present */
  319.       if (nparams != 8)
  320.     {
  321.       status = GIMP_PDB_CALLING_ERROR;
  322.     }
  323.       else
  324.     {
  325.       pcvals.circle  = param[3].data.d_float;
  326.       pcvals.angle  = param[4].data.d_float;
  327.       pcvals.backwards  = param[5].data.d_int32;
  328.       pcvals.inverse  = param[6].data.d_int32;
  329.       pcvals.polrec  = param[7].data.d_int32;
  330.     }
  331.       break;
  332.  
  333.     case GIMP_RUN_WITH_LAST_VALS:
  334.       INIT_I18N();
  335.  
  336.       /* Possibly retrieve data */
  337.       gimp_get_data (PLUG_IN_NAME, &pcvals);
  338.       break;
  339.  
  340.     default:
  341.       break;
  342.     }
  343.  
  344.   /* Distort the image */
  345.   if ((status == GIMP_PDB_SUCCESS) &&
  346.       (gimp_drawable_is_rgb (drawable->id) ||
  347.        gimp_drawable_is_gray (drawable->id)))
  348.     {
  349.       /* Set the tile cache size */
  350.       gimp_tile_cache_ntiles (2 * (drawable->width + gimp_tile_width() - 1) /
  351.                   gimp_tile_width ());
  352.  
  353.       /* Run! */
  354.       polarize ();
  355.  
  356.       /* If run mode is interactive, flush displays */
  357.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  358.     gimp_displays_flush ();
  359.  
  360.       /* Store data */
  361.       if (run_mode == GIMP_RUN_INTERACTIVE)
  362.     gimp_set_data (PLUG_IN_NAME, &pcvals, sizeof (polarize_vals_t));
  363.     }
  364.   else if (status == GIMP_PDB_SUCCESS)
  365.     status = GIMP_PDB_EXECUTION_ERROR;
  366.  
  367.   values[0].data.d_status = status;
  368.  
  369.   gimp_drawable_detach (drawable);
  370. }
  371.  
  372. static void
  373. polarize (void)
  374. {
  375.   GimpPixelRgn  dest_rgn;
  376.   guchar    *dest, *d;
  377.   guchar     pixel[4][4];
  378.   guchar     pixel2[4];
  379.   guchar     values[4];
  380.   gint       progress, max_progress;
  381.   double     cx, cy;
  382.   guchar     bg_color[4];
  383.   gint       x1, y1, x2, y2;
  384.   gint       x, y, b;
  385.   gpointer   pr;
  386.   
  387.   pixel_fetcher_t *pft;
  388.  
  389.   /* Get selection area */
  390.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  391.  
  392.   /* Initialize pixel region */
  393.   gimp_pixel_rgn_init (&dest_rgn, drawable,
  394.                x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
  395.   
  396.   pft = pixel_fetcher_new (drawable);
  397.  
  398.   gimp_palette_get_background (&bg_color[0], &bg_color[1], &bg_color[2]);
  399.   pixel_fetcher_set_bg_color (pft, bg_color[0], bg_color[1], bg_color[2],
  400.                   (img_has_alpha ? 0 : 255));
  401.  
  402.   progress     = 0;
  403.   max_progress = img_width * img_height;
  404.  
  405.   gimp_progress_init (_("Polarizing..."));
  406.  
  407.   for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
  408.        pr != NULL;
  409.        pr = gimp_pixel_rgns_process (pr))
  410.     {
  411.       dest = dest_rgn.data;
  412.  
  413.       for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++)
  414.     {
  415.       d = dest;
  416.  
  417.       for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++)
  418.         {
  419.           if (calc_undistorted_coords (x, y, &cx, &cy))
  420.         {
  421.           pixel_fetcher_get_pixel (pft, cx, cy, pixel[0]);
  422.           pixel_fetcher_get_pixel (pft, cx + 1, cy, pixel[1]);
  423.           pixel_fetcher_get_pixel (pft, cx, cy + 1, pixel[2]);
  424.           pixel_fetcher_get_pixel (pft, cx + 1, cy + 1, pixel[3]);
  425.  
  426.           for (b = 0; b < img_bpp; b++)
  427.             {
  428.               values[0] = pixel[0][b];
  429.               values[1] = pixel[1][b];
  430.               values[2] = pixel[2][b];
  431.               values[3] = pixel[3][b];
  432.        
  433.               d[b] = bilinear (cx, cy, values);
  434.             }
  435.         }
  436.           else
  437.         {
  438.           pixel_fetcher_get_pixel (pft, x, y, pixel2);
  439.           for (b = 0; b < img_bpp; b++)
  440.             {
  441.               d[b] = 255;
  442.             }      
  443.         }
  444.  
  445.           d += dest_rgn.bpp;
  446.         }
  447.       
  448.       dest += dest_rgn.rowstride;
  449.     }
  450.       progress += dest_rgn.w *dest_rgn.h;
  451.  
  452.       gimp_progress_update ((double) progress / max_progress);
  453.     }
  454.   
  455.   gimp_drawable_flush (drawable);
  456.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  457.   gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  458. }
  459.  
  460. static gint
  461. calc_undistorted_coords (gdouble  wx,
  462.              gdouble  wy,
  463.              gdouble *x,
  464.              gdouble *y)
  465. {
  466.   gint    inside;
  467.   gdouble phi, phi2;
  468.   gdouble xx, xm, ym, yy;
  469.   gint    xdiff, ydiff;
  470.   gdouble r;
  471.   gdouble m;
  472.   gdouble xmax, ymax, rmax;
  473.   gdouble x_calc, y_calc;
  474.   gdouble xi, yi;
  475.   gdouble circle, angl, t, angle;
  476.   gint    x1, x2, y1, y2;
  477.  
  478.   /* initialize */
  479.  
  480.   phi = 0.0;
  481.   r = 0.0;
  482.  
  483.   x1 = 0;
  484.   y1 = 0;
  485.   x2 = img_width;
  486.   y2 = img_height;
  487.   xdiff = x2 - x1;
  488.   ydiff = y2 - y1;
  489.   xm = xdiff / 2.0;
  490.   ym = ydiff / 2.0;
  491.   circle = pcvals.circle;
  492.   angle = pcvals.angle;
  493.   angl = (double)angle / 180.0 * G_PI;
  494.  
  495.   if (pcvals.polrec)
  496.     {
  497.       if (wx >= cen_x)
  498.     {
  499.       if (wy > cen_y)
  500.         {
  501.           phi = G_PI - atan (((double)(wx - cen_x))/((double)(wy - cen_y)));
  502.           r   = sqrt (SQR (wx - cen_x) + SQR (wy - cen_y));
  503.         }
  504.       else if (wy < cen_y)
  505.         {
  506.           phi = atan (((double)(wx - cen_x))/((double)(cen_y - wy)));
  507.           r   = sqrt (SQR (wx - cen_x) + SQR (cen_y - wy));
  508.         }
  509.       else
  510.         {
  511.           phi = G_PI / 2;
  512.           r   = wx - cen_x; /* cen_x - x1; */
  513.         }
  514.     }
  515.       else if (wx < cen_x)
  516.     {
  517.       if (wy < cen_y)
  518.         {
  519.           phi = 2 * G_PI - atan (((double)(cen_x -wx)) /
  520.                      ((double)(cen_y - wy)));
  521.           r   = sqrt (SQR (cen_x - wx) + SQR (cen_y - wy));
  522.         }
  523.       else if (wy > cen_y)
  524.         {
  525.           phi = G_PI + atan (((double)(cen_x - wx))/((double)(wy - cen_y)));
  526.           r   = sqrt (SQR (cen_x - wx) + SQR (wy - cen_y));
  527.         }
  528.       else
  529.         {
  530.           phi = 1.5 * G_PI;
  531.           r   = cen_x - wx; /* cen_x - x1; */
  532.         }
  533.     }
  534.       if (wx != cen_x)
  535.     {
  536.       m = fabs (((double)(wy - cen_y)) / ((double)(wx - cen_x)));
  537.     }
  538.       else
  539.     {
  540.       m = 0;
  541.     }
  542.     
  543.       if (m <= ((double)(y2 - y1) / (double)(x2 - x1)))
  544.     {
  545.       if (wx == cen_x)
  546.         {
  547.           xmax = 0;
  548.           ymax = cen_y - y1;
  549.         }
  550.       else
  551.         {
  552.           xmax = cen_x - x1;
  553.           ymax = m * xmax;
  554.         }
  555.     }
  556.       else
  557.     {
  558.       ymax = cen_y - y1;
  559.       xmax = ymax / m;
  560.     }
  561.     
  562.       rmax = sqrt ( (double)(SQR (xmax) + SQR (ymax)) );
  563.     
  564.       t = ((cen_y - y1) < (cen_x - x1)) ? (cen_y - y1) : (cen_x - x1);
  565.       rmax = (rmax - t) / 100 * (100 - circle) + t;
  566.     
  567.       phi = fmod (phi + angl, 2*G_PI);
  568.     
  569.       if (pcvals.backwards)
  570.     x_calc = x2 - 1 - (x2 - x1 - 1)/(2*G_PI) * phi;
  571.       else
  572.     x_calc = (x2 - x1 - 1)/(2*G_PI) * phi + x1;
  573.     
  574.       if (pcvals.inverse)
  575.     y_calc = (y2 - y1)/rmax   * r   + y1;
  576.       else
  577.     y_calc = y2 - (y2 - y1)/rmax * r;
  578.     
  579.       xi = (int) (x_calc+0.5);
  580.       yi = (int) (y_calc+0.5);
  581.     
  582.       if (WITHIN(0, xi, img_width - 1) && WITHIN(0, yi, img_height - 1))
  583.     {
  584.       *x = x_calc;
  585.       *y = y_calc;
  586.       
  587.       inside = TRUE;
  588.     }
  589.       else
  590.     {
  591.       inside = FALSE;
  592.     }
  593.     }
  594.   else
  595.     {
  596.       if (pcvals.backwards)
  597.     phi = (2 * G_PI) * (x2 - wx) / xdiff;
  598.       else
  599.     phi = (2 * G_PI) * (wx - x1) / xdiff;
  600.     
  601.       phi = fmod (phi + angl, 2 * G_PI);
  602.     
  603.       if (phi >= 1.5 * G_PI)
  604.     phi2 = 2 * G_PI - phi;
  605.       else
  606.     if (phi >= G_PI)
  607.       phi2 = phi - G_PI;
  608.     else
  609.       if (phi >= 0.5 * G_PI)
  610.         phi2 = G_PI - phi;
  611.       else
  612.         phi2 = phi;
  613.     
  614.       xx = tan (phi2);
  615.       if (xx != 0)
  616.     m = (double) 1.0 / xx;
  617.       else
  618.     m = 0;
  619.     
  620.       if (m <= ((double)(ydiff) / (double)(xdiff)))
  621.     {
  622.       if (phi2 == 0)
  623.         {
  624.           xmax = 0;
  625.           ymax = ym - y1;
  626.         }
  627.       else
  628.         {
  629.           xmax = xm - x1;
  630.           ymax = m * xmax;
  631.         }
  632.     }
  633.       else
  634.     {
  635.       ymax = ym - y1;
  636.       xmax = ymax / m;
  637.     }
  638.     
  639.       rmax = sqrt ((double)(SQR (xmax) + SQR (ymax)));
  640.     
  641.       t = ((ym - y1) < (xm - x1)) ? (ym - y1) : (xm - x1);
  642.     
  643.       rmax = (rmax - t) / 100.0 * (100 - circle) + t;
  644.     
  645.       if (pcvals.inverse)
  646.     r = rmax * (double)((wy - y1) / (double)(ydiff));
  647.       else
  648.     r = rmax * (double)((y2 - wy) / (double)(ydiff));
  649.     
  650.       xx = r * sin (phi2);
  651.       yy = r * cos (phi2);
  652.     
  653.       if (phi >= 1.5 * G_PI)
  654.     {
  655.       x_calc = (double)xm - xx;
  656.       y_calc = (double)ym - yy;
  657.     }
  658.       else
  659.     if (phi >= G_PI)
  660.       {
  661.         x_calc = (double)xm - xx;
  662.         y_calc = (double)ym + yy;
  663.       }
  664.     else
  665.       if (phi >= 0.5 * G_PI)
  666.         {
  667.           x_calc = (double)xm + xx;
  668.           y_calc = (double)ym + yy;
  669.         }
  670.       else
  671.         {
  672.           x_calc = (double)xm + xx;
  673.           y_calc = (double)ym - yy;
  674.         }
  675.     
  676.       xi = (int)(x_calc + 0.5);
  677.       yi = (int)(y_calc + 0.5);
  678.   
  679.       if (WITHIN(0, xi, img_width - 1) && WITHIN(0, yi, img_height - 1)) {
  680.     *x = x_calc;
  681.     *y = y_calc;
  682.       
  683.     inside = TRUE;
  684.       }
  685.       else
  686.     {
  687.       inside = FALSE;
  688.     }
  689.     }
  690.   
  691.   return inside;
  692. }
  693.  
  694. static guchar
  695. bilinear (gdouble  x,
  696.       gdouble  y,
  697.       guchar *values)
  698. {
  699.   gdouble m0, m1;
  700.  
  701.   x = fmod (x, 1.0);
  702.   y = fmod (y, 1.0);
  703.  
  704.   if (x < 0.0)
  705.     x += 1.0;
  706.  
  707.   if (y < 0.0)
  708.     y += 1.0;
  709.  
  710.   m0 = (double) values[0] + x * ((double) values[1] - values[0]);
  711.   m1 = (double) values[2] + x * ((double) values[3] - values[2]);
  712.  
  713.   return (guchar) (m0 + y * (m1 - m0));
  714. }
  715.  
  716. static pixel_fetcher_t *
  717. pixel_fetcher_new (GimpDrawable *drawable)
  718. {
  719.   pixel_fetcher_t *pf;
  720.  
  721.   pf = g_new (pixel_fetcher_t, 1);
  722.  
  723.   pf->col           = -1;
  724.   pf->row           = -1;
  725.   pf->img_width     = gimp_drawable_width (drawable->id);
  726.   pf->img_height    = gimp_drawable_height (drawable->id);
  727.   pf->img_bpp       = gimp_drawable_bpp (drawable->id);
  728.   pf->img_has_alpha = gimp_drawable_has_alpha (drawable->id);
  729.   pf->tile_width    = gimp_tile_width ();
  730.   pf->tile_height   = gimp_tile_height ();
  731.   pf->bg_color[0]   = 0;
  732.   pf->bg_color[1]   = 0;
  733.   pf->bg_color[2]   = 0;
  734.   pf->bg_color[3]   = 0;
  735.  
  736.   pf->drawable    = drawable;
  737.   pf->tile        = NULL;
  738.  
  739.   return pf;
  740. }
  741.  
  742. static void
  743. pixel_fetcher_set_bg_color (pixel_fetcher_t *pf,
  744.                 guchar           r,
  745.                 guchar           g,
  746.                 guchar           b,
  747.                 guchar           a)
  748. {
  749.   pf->bg_color[0] = r;
  750.   pf->bg_color[1] = g;
  751.   pf->bg_color[2] = b;
  752.  
  753.   if (pf->img_has_alpha)
  754.     pf->bg_color[pf->img_bpp - 1] = a;
  755. }
  756.  
  757. static void
  758. pixel_fetcher_get_pixel (pixel_fetcher_t *pf,
  759.              gint             x,
  760.              gint             y,
  761.              guchar          *pixel)
  762. {
  763.   gint    col, row;
  764.   gint    coloff, rowoff;
  765.   guchar *p;
  766.   gint    i;
  767.  
  768.   if ((x < sel_x1) || (x >= sel_x2) ||
  769.       (y < sel_y1) || (y >= sel_y2))
  770.     {
  771.       for (i = 0; i < pf->img_bpp; i++)
  772.     pixel[i] = pf->bg_color[i];
  773.  
  774.       return;
  775.     }
  776.  
  777.   col    = x / pf->tile_width;
  778.   coloff = x % pf->tile_width;
  779.   row    = y / pf->tile_height;
  780.   rowoff = y % pf->tile_height;
  781.  
  782.   if ((col != pf->col) ||
  783.       (row != pf->row) ||
  784.       (pf->tile == NULL))
  785.     {
  786.       if (pf->tile != NULL)
  787.     gimp_tile_unref(pf->tile, FALSE);
  788.  
  789.       pf->tile = gimp_drawable_get_tile (pf->drawable, FALSE, row, col);
  790.       gimp_tile_ref (pf->tile);
  791.  
  792.       pf->col = col;
  793.       pf->row = row;
  794.     }
  795.  
  796.   p = pf->tile->data + pf->img_bpp * (pf->tile->ewidth * rowoff + coloff);
  797.  
  798.   for (i = pf->img_bpp; i; i--)
  799.     *pixel++ = *p++;
  800. }
  801.  
  802. static void
  803. pixel_fetcher_destroy (pixel_fetcher_t *pf)
  804. {
  805.   if (pf->tile != NULL)
  806.     gimp_tile_unref (pf->tile, FALSE);
  807.  
  808.   g_free (pf);
  809. }
  810.  
  811. static void
  812. build_preview_source_image (void)
  813. {
  814.   gdouble          left, right, bottom, top;
  815.   gdouble          px, py;
  816.   gdouble          dx, dy;
  817.   gint             x, y;
  818.   guchar          *p;
  819.   guchar           pixel[4];
  820.   pixel_fetcher_t *pf;
  821.  
  822.   pcint.check_row_0 = g_new (guchar, preview_width);
  823.   pcint.check_row_1 = g_new (guchar, preview_width);
  824.   pcint.image       = g_new (guchar, preview_width * preview_height * 4);
  825.   pcint.dimage      = g_new (guchar, preview_width * preview_height * 3);
  826.  
  827.   left   = sel_x1;
  828.   right  = sel_x2 - 1;
  829.   bottom = sel_y2 - 1;
  830.   top    = sel_y1;
  831.  
  832.   dx = (right - left) / (preview_width - 1);
  833.   dy = (bottom - top) / (preview_height - 1);
  834.  
  835.   py = top;
  836.  
  837.   pf = pixel_fetcher_new(drawable);
  838.  
  839.   p = pcint.image;
  840.  
  841.   for (y = 0; y < preview_height; y++)
  842.     {
  843.       px = left;
  844.  
  845.       for (x = 0; x < preview_width; x++)
  846.     {
  847.       /* Checks */
  848.  
  849.       if ((x / GIMP_CHECK_SIZE) & 1)
  850.         {
  851.           pcint.check_row_0[x] = GIMP_CHECK_DARK * 255;
  852.           pcint.check_row_1[x] = GIMP_CHECK_LIGHT * 255;
  853.         }
  854.       else
  855.         {
  856.           pcint.check_row_0[x] = GIMP_CHECK_LIGHT * 255;
  857.           pcint.check_row_1[x] = GIMP_CHECK_DARK * 255;
  858.         }
  859.  
  860.       /* Thumbnail image */
  861.  
  862.       pixel_fetcher_get_pixel (pf, (int) px, (int) py, pixel);
  863.  
  864.       if (img_bpp < 3)
  865.         {
  866.           if (img_has_alpha)
  867.         pixel[3] = pixel[1];
  868.           else
  869.         pixel[3] = 255;
  870.  
  871.           pixel[1] = pixel[0];
  872.           pixel[2] = pixel[0];
  873.         }
  874.       else if (!img_has_alpha)
  875.         pixel[3] = 255;
  876.  
  877.       *p++ = pixel[0];
  878.       *p++ = pixel[1];
  879.       *p++ = pixel[2];
  880.       *p++ = pixel[3];
  881.  
  882.       px += dx;
  883.     }
  884.  
  885.       py += dy;
  886.     }
  887.  
  888.   pixel_fetcher_destroy (pf);
  889. }
  890.  
  891. static gint
  892. polarize_dialog (void)
  893. {
  894.   GtkWidget *dialog;
  895.   GtkWidget *main_vbox;
  896.   GtkWidget *vbox;
  897.   GtkWidget *frame;
  898.   GtkWidget *table;
  899.   GtkWidget *abox;
  900.   GtkWidget *pframe;
  901.   GtkWidget *toggle;
  902.   GtkWidget *hbox;
  903.   GtkObject *adj;
  904.  
  905.   gimp_ui_init ("polar", TRUE);
  906.  
  907.   build_preview_source_image ();
  908.  
  909.   dialog = gimp_dialog_new (_("Polarize"), "polar",
  910.                 gimp_standard_help_func, "filters/polar.html",
  911.                 GTK_WIN_POS_MOUSE,
  912.                 FALSE, TRUE, FALSE,
  913.  
  914.                 _("OK"), dialog_ok_callback,
  915.                 NULL, NULL, NULL, TRUE, FALSE,
  916.                 _("Cancel"), gtk_widget_destroy,
  917.                 NULL, 1, NULL, FALSE, TRUE,
  918.  
  919.                 NULL);
  920.  
  921.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  922.               GTK_SIGNAL_FUNC (gtk_main_quit),
  923.               NULL);
  924.  
  925.   /* Initialize Tooltips */
  926.   gimp_help_init ();
  927.     
  928.   main_vbox = gtk_vbox_new (FALSE, 4);
  929.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  930.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox), main_vbox,
  931.               FALSE, FALSE, 0);
  932.   gtk_widget_show (main_vbox);
  933.  
  934.   /* Preview */
  935.   frame = gtk_frame_new (_("Preview"));
  936.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  937.   gtk_widget_show (frame);
  938.  
  939.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  940.   gtk_container_add (GTK_CONTAINER (frame), abox);
  941.   gtk_widget_show (abox);
  942.  
  943.   pframe = gtk_frame_new (NULL);
  944.   gtk_frame_set_shadow_type (GTK_FRAME (pframe), GTK_SHADOW_IN);
  945.   gtk_container_set_border_width (GTK_CONTAINER (pframe), 4);
  946.   gtk_container_add (GTK_CONTAINER (abox), pframe);
  947.   gtk_widget_show (pframe);
  948.  
  949.   pcint.preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  950.   gtk_preview_size (GTK_PREVIEW (pcint.preview), preview_width, preview_height);
  951.   gtk_container_add (GTK_CONTAINER (pframe), pcint.preview);
  952.   gtk_widget_show (pcint.preview);
  953.  
  954.   /* Controls */
  955.   frame = gtk_frame_new (_("Parameter Settings"));
  956.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  957.   gtk_widget_show (frame);
  958.  
  959.   vbox = gtk_vbox_new (FALSE, 4);
  960.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  961.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  962.   gtk_widget_show (vbox);
  963.  
  964.   table = gtk_table_new (2, 3, FALSE);
  965.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  966.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  967.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  968.   gtk_widget_show (table);
  969.  
  970.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  971.                   _("Circle Depth in Percent:"), SCALE_WIDTH, 0,
  972.                   pcvals.circle, 0.0, 100.0, 1.0, 10.0, 2,
  973.                   TRUE, 0, 0,
  974.                   NULL, NULL);
  975.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  976.               GTK_SIGNAL_FUNC (dialog_scale_update),
  977.               &pcvals.circle);
  978.  
  979.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  980.                   _("Offset Angle:"), SCALE_WIDTH, 0,
  981.                   pcvals.angle, 0.0, 359.0, 1.0, 15.0, 2,
  982.                   TRUE, 0, 0,
  983.                   NULL, NULL);
  984.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  985.               GTK_SIGNAL_FUNC (dialog_scale_update),
  986.               &pcvals.angle);
  987.  
  988.   /* togglebuttons for backwards, top, polar->rectangular */
  989.   hbox = gtk_hbox_new (TRUE, 4);
  990.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  991.  
  992.   toggle = gtk_check_button_new_with_label (_("Map Backwards"));
  993.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), pcvals.backwards);
  994.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled", 
  995.               GTK_SIGNAL_FUNC (polar_toggle_callback),
  996.               &pcvals.backwards);
  997.   gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 0);
  998.   gtk_widget_show (toggle);
  999.   gimp_help_set_help_data (toggle,
  1000.                _("If checked the mapping will begin at the right "
  1001.                  "side, as opposed to beginning at the left."),
  1002.                NULL);
  1003.  
  1004.   toggle = gtk_check_button_new_with_label (_("Map from Top"));
  1005.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), pcvals.inverse);
  1006.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled", 
  1007.               (GtkSignalFunc) polar_toggle_callback,
  1008.               &pcvals.inverse);
  1009.   gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 0);
  1010.   gtk_widget_show (toggle);
  1011.   gimp_help_set_help_data (toggle,
  1012.                _("If unchecked the mapping will put the bottom "
  1013.                  "row in the middle and the top row on the "
  1014.                  "outside.  If checked it will be the opposite."),
  1015.                NULL);
  1016.  
  1017.   toggle = gtk_check_button_new_with_label (_("To Polar"));
  1018.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), pcvals.polrec);
  1019.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled", 
  1020.               (GtkSignalFunc) polar_toggle_callback,
  1021.               &pcvals.polrec);
  1022.   gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 0);
  1023.   gtk_widget_show (toggle);
  1024.   gimp_help_set_help_data (toggle,
  1025.                _("If unchecked the image will be circularly "
  1026.                  "mapped onto a rectangle.  If checked the image "
  1027.                  "will be mapped onto a circle."),
  1028.                NULL);
  1029.  
  1030.   gtk_widget_show (hbox);
  1031.  
  1032.   /* Done */
  1033.  
  1034.   gtk_widget_show (dialog);
  1035.   dialog_update_preview ();
  1036.  
  1037.   gtk_main ();
  1038.   gimp_help_free ();
  1039.   gdk_flush ();
  1040.  
  1041.   g_free (pcint.check_row_0);
  1042.   g_free (pcint.check_row_1);
  1043.   g_free (pcint.image);
  1044.   g_free (pcint.dimage);
  1045.  
  1046.   return pcint.run;
  1047. }
  1048.  
  1049. static void
  1050. dialog_update_preview (void)
  1051. {
  1052.   gdouble  left, right, bottom, top;
  1053.   gdouble  dx, dy;
  1054.   gdouble  px, py;
  1055.   gdouble  cx = 0.0, cy = 0.0;
  1056.   gint     ix, iy;
  1057.   gint     x, y;
  1058.   gdouble  scale_x, scale_y;
  1059.   guchar  *p_ul, *i, *p;
  1060.   guchar  *check_ul;
  1061.   gint     check;
  1062.   guchar   outside[4];
  1063.  
  1064.   gimp_palette_get_background (&outside[0], &outside[1], &outside[2]);
  1065.   outside[3] = (img_has_alpha ? 0 : 255);
  1066.  
  1067.   if (img_bpp < 3)
  1068.     {
  1069.       outside[1] = outside[0];
  1070.       outside[2] = outside[0];
  1071.     }
  1072.  
  1073.   left   = sel_x1;
  1074.   right  = sel_x2 - 1;
  1075.   bottom = sel_y2 - 1;
  1076.   top    = sel_y1;
  1077.  
  1078.   dx = (right - left) / (preview_width - 1);
  1079.   dy = (bottom - top) / (preview_height - 1);
  1080.  
  1081.   scale_x = (double) preview_width / (right - left + 1);
  1082.   scale_y = (double) preview_height / (bottom - top + 1);
  1083.  
  1084.   py = top;
  1085.  
  1086.   p_ul = pcint.dimage;
  1087. /* p_lr = pcint.dimage + 3 * (preview_width * preview_height - 1);*/
  1088.  
  1089.   for (y = 0; y < preview_height; y++)
  1090.     {
  1091.       px = left;
  1092.  
  1093.       if ((y / GIMP_CHECK_SIZE) & 1)
  1094.     check_ul = pcint.check_row_0;
  1095.       else
  1096.     check_ul = pcint.check_row_1;
  1097.  
  1098.       for (x = 0; x < preview_width; x++)
  1099.     {
  1100.       calc_undistorted_coords (px, py, &cx, &cy);
  1101.  
  1102.       cx = (cx - left) * scale_x;
  1103.       cy = (cy - top) * scale_y;
  1104.  
  1105.       ix = (int) (cx + 0.5);
  1106.       iy = (int) (cy + 0.5);
  1107.  
  1108.       check = check_ul[x];
  1109.  
  1110.       if ((ix >= 0) && (ix < preview_width) &&
  1111.           (iy >= 0) && (iy < preview_height))
  1112.         i = pcint.image + 4 * (preview_width * iy + ix);
  1113.       else
  1114.         i = outside;
  1115.  
  1116.       p_ul[0] = check + ((i[0] - check) * i[3]) / 255;
  1117.       p_ul[1] = check + ((i[1] - check) * i[3]) / 255;
  1118.       p_ul[2] = check + ((i[2] - check) * i[3]) / 255;
  1119.  
  1120.       p_ul += 3;
  1121.  
  1122.       px += dx;
  1123.     }
  1124.  
  1125.       py += dy;
  1126.     }
  1127.  
  1128.   p = pcint.dimage;
  1129.  
  1130.   for (y = 0; y < img_height; y++)
  1131.     {
  1132.       gtk_preview_draw_row (GTK_PREVIEW (pcint.preview), p, 0, y, preview_width);
  1133.  
  1134.       p += preview_width * 3;
  1135.     }
  1136.  
  1137.   gtk_widget_draw (pcint.preview, NULL);
  1138.   gdk_flush ();
  1139. }
  1140.  
  1141. static void
  1142. dialog_scale_update (GtkAdjustment *adjustment,
  1143.              gdouble       *value)
  1144. {
  1145.   gimp_double_adjustment_update (adjustment, value);
  1146.  
  1147.   dialog_update_preview ();
  1148. }
  1149.  
  1150. static void
  1151. dialog_ok_callback (GtkWidget *widget,
  1152.             gpointer   data)
  1153. {
  1154.   pcint.run = TRUE;
  1155.  
  1156.   gtk_widget_destroy (GTK_WIDGET (data));
  1157. }
  1158.  
  1159. static void
  1160. polar_toggle_callback (GtkWidget *widget,
  1161.                gpointer   data)
  1162. {
  1163.   gimp_toggle_button_update (widget, data);
  1164.  
  1165.   dialog_update_preview ();
  1166. }
  1167.