home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / unofficial-plug-ins / RGB_Displace / RGB_Displace.c < prev   
Encoding:
C/C++ Source or Header  |  1998-12-01  |  30.6 KB  |  1,058 lines

  1. /**********************************************************************
  2.  *  RGB Displace plug-in (Version 1.00)
  3.  *  Daniel Cotting (cotting@multimania.com)
  4.  **********************************************************************
  5.  *  Official homepages: http://www.multimania.com/cotting
  6.  *                      http://cotting.citeweb.net
  7.  **********************************************************************    
  8.  */
  9.  
  10. /* The GIMP -- an image manipulation program
  11.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or
  16.  * (at your option) any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <math.h>
  31. #include "gtk/gtk.h"
  32. #include "libgimp/gimp.h"
  33. #include "logo.h"
  34.  
  35. /***** Macros *****/
  36.  
  37. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  38. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  39.  
  40.  
  41. /***** Magic numbers *****/
  42.  
  43. #define PREVIEW_SIZE 128
  44. #define SCALE_WIDTH  200
  45. #define ENTRY_WIDTH  45
  46.  
  47.  
  48. /***** Types *****/
  49. typedef struct {
  50.     gdouble redx;
  51.         gdouble greenx;
  52.         gdouble bluex;
  53.     gdouble redy;
  54.         gdouble greeny;
  55.         gdouble bluey;
  56. } rgb_vals_t;
  57.  
  58. typedef struct {
  59.         GtkWidget *preview;
  60.         guchar    *image;
  61.         guchar    *wimage;
  62.         gint run;
  63. } rgb_interface_t;
  64.  
  65.  
  66.  
  67. /* Declare local functions. */
  68.  
  69. static void      query  (void);
  70. static void      run    (char      *name,
  71.                  int        nparams,
  72.                  GParam    *param,
  73.                  int       *nreturn_vals,
  74.                  GParam   **return_vals);
  75.  
  76. static void      rgb         (GDrawable  *drawable);
  77. static void      rgb_render_row  (const guchar *src_row,
  78.                          guchar *dest_row,
  79.                          gint row,
  80.                          gint row_width,
  81.                          gint bytes,
  82.                      gdouble, gdouble, gdouble,
  83.                      gdouble, gdouble, gdouble);
  84. static void      rgb_get_pixel(int x, int y, guchar *pixel);
  85.  
  86.  
  87. static void      build_preview_source_image(void);
  88.  
  89. static gint      rgb_dialog(void);
  90. static void      dialog_update_preview(void);
  91. static void      dialog_create_value(char *title, GtkTable *table, int row, gdouble *value,
  92.                          int left, int right, const char *desc);
  93. static void      dialog_scale_update(GtkAdjustment *adjustment, gdouble *value);
  94. static void      dialog_entry_update(GtkWidget *widget, gdouble *value);
  95. static void      dialog_close_callback(GtkWidget *widget, gpointer data);
  96. static void      dialog_ok_callback(GtkWidget *widget, gpointer data);
  97. static void      dialog_cancel_callback(GtkWidget *widget, gpointer data);
  98. GtkWidget       * rgb_logo_dialog(void);
  99.  
  100.  
  101.  
  102.                         
  103.                         
  104. /***** Variables *****/
  105.  
  106. GtkWidget *maindlg;
  107. GtkWidget *logodlg;
  108. GtkTooltips *tips;
  109. GdkColor tips_fg,tips_bg;    
  110. int ready=0;
  111. gint32         image_ID;
  112.  
  113.  
  114.  
  115. GPlugInInfo PLUG_IN_INFO =
  116. {
  117.   NULL,    /* init_proc */
  118.   NULL,    /* quit_proc */
  119.   query,   /* query_proc */
  120.   run,     /* run_proc */
  121. };
  122.  
  123. static rgb_interface_t wint = {
  124.         NULL,  /* preview */
  125.         NULL,  /* image */
  126.         NULL,  /* wimage */
  127.         FALSE  /* run */
  128. }; /* wint */
  129.  
  130. static rgb_vals_t wvals = {
  131.         0,0,0,0,0,0,
  132. }; /* wvals */
  133.  
  134. static GDrawable *drawable;
  135. static gint   tile_width, tile_height;
  136. static gint   img_width, img_height, img_bpp;
  137. static gint   sel_x1, sel_y1, sel_x2, sel_y2;
  138. static gint   sel_width, sel_height;
  139. static gint   preview_width, preview_height;
  140. static GTile *the_tile = NULL;
  141. static double cen_x, cen_y;
  142. static double scale_x, scale_y;
  143.  
  144. /***** Functions *****/
  145.  
  146.  
  147. MAIN ()
  148.  
  149. static void
  150. query ()
  151. {
  152.   static GParamDef args[] =
  153.   {
  154.     { PARAM_INT32,    "run_mode",    "Interactive, non-interactive" },
  155.     { PARAM_IMAGE,    "image",       "Input image" },
  156.     { PARAM_DRAWABLE, "drawable",    "Input drawable" },
  157.     { PARAM_FLOAT,    "redx",   "Red x displacement" },
  158.     { PARAM_FLOAT,    "greenx", "Green x displacement" },
  159.     { PARAM_FLOAT,    "bluex",  "Blue x displacement" },
  160.     { PARAM_FLOAT,    "redy",     "Red y displacement" },
  161.     { PARAM_FLOAT,    "greeny",   "Green y displacement" },
  162.     { PARAM_FLOAT,    "bluey",    "Blue y displacement" },
  163.   };
  164.   static GParamDef *return_vals = NULL;
  165.   static int nargs = sizeof (args) / sizeof (args[0]);
  166.   static int nreturn_vals = 0;
  167.  
  168.   gimp_install_procedure ("plug_in_rgb",
  169.                   "RGB Transformation Plug-In",
  170.                   "No help yet. Just try it and you'll see!",
  171.                   "Daniel Cotting (cotting@multimania.com, http://www.multimania.com/cotting)",
  172.                   "Daniel Cotting (cotting@multimania.com, http://www.multimania.com/cotting)",
  173.                   "November 1998",
  174.                   "<Image>/Filters/Colors/RGB Displace",
  175.                   "RGB*",
  176.                   PROC_PLUG_IN,
  177.                   nargs, nreturn_vals,
  178.                   args, return_vals);
  179. }
  180.  
  181.  
  182.  
  183. static void
  184. run (char    *name,
  185.      int      nparams,
  186.      GParam  *param,
  187.      int     *nreturn_vals,
  188.      GParam **return_vals)
  189. {
  190.   static GParam values[1];
  191.   GRunModeType  run_mode;
  192.   double        xhsiz, yhsiz;
  193.   int       pwidth, pheight;
  194.   GStatusType status = STATUS_SUCCESS;
  195.  
  196.  
  197.   run_mode = param[0].data.d_int32;
  198.  
  199.   values[0].type = PARAM_STATUS;
  200.   values[0].data.d_status = status;
  201.  
  202.   *nreturn_vals = 1;
  203.   *return_vals = values;
  204.  
  205.  
  206.  
  207.   /*  Get the specified drawable  */
  208.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  209.   image_ID = param[1].data.d_image;
  210.   tile_width  = gimp_tile_width();
  211.   tile_height = gimp_tile_height();
  212.  
  213.   img_width  = gimp_drawable_width(drawable->id);
  214.   img_height = gimp_drawable_height(drawable->id);
  215.   img_bpp    = gimp_drawable_bpp(drawable->id);
  216.  
  217.   gimp_drawable_mask_bounds(drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
  218.  
  219.   sel_width  = sel_x2 - sel_x1;
  220.   sel_height = sel_y2 - sel_y1;
  221.  
  222.   cen_x = (double) (sel_x2 - 1 + sel_x1) / 2.0;
  223.   cen_y = (double) (sel_y2 - 1 + sel_y1) / 2.0;
  224.  
  225.   xhsiz = (double) (sel_width - 1) / 2.0;
  226.   yhsiz = (double) (sel_height - 1) / 2.0;
  227.  
  228.         if (xhsiz < yhsiz) {
  229.             scale_x = yhsiz / xhsiz;
  230.             scale_y = 1.0;
  231.         } else if (xhsiz > yhsiz) {
  232.             scale_x = 1.0;
  233.             scale_y = xhsiz / yhsiz;
  234.         } else {
  235.             scale_x = 1.0;
  236.             scale_y = 1.0;
  237.         } /* else */
  238.  
  239.         /* Calculate preview size */
  240.         if (sel_width > sel_height) {
  241.             pwidth  = MIN(sel_width, PREVIEW_SIZE);
  242.             pheight = sel_height * pwidth / sel_width;
  243.         } else {
  244.             pheight = MIN(sel_height, PREVIEW_SIZE);
  245.             pwidth  = sel_width * pheight / sel_height;
  246.         } /* else */
  247.  
  248.         preview_width  = MAX(pwidth, 2);  /* Min size is 2 */
  249.         preview_height = MAX(pheight, 2);
  250.  
  251.         /* See how we will run */
  252.         switch (run_mode) {
  253.             case RUN_INTERACTIVE:
  254.                 /* Possibly retrieve data */
  255.  
  256.                 gimp_get_data("plug_in_rgb", &wvals);
  257.  
  258.                 /* Get information from the dialog */
  259.  
  260.                 if (!rgb_dialog())
  261.                     return;
  262.  
  263.                 break;
  264.  
  265.             case RUN_NONINTERACTIVE:
  266.                 /* Make sure all the arguments are present */
  267.  
  268.                 if (nparams != 6)
  269.                     status = STATUS_CALLING_ERROR;
  270.  
  271.                 if (status == STATUS_SUCCESS)
  272.  
  273.                     wvals.redx = param[0].data.d_float;
  274.                     wvals.greenx = param[1].data.d_float;
  275.                     wvals.bluex = param[2].data.d_float;
  276.                     wvals.redy = param[3].data.d_float;
  277.                     wvals.greeny = param[4].data.d_float;
  278.                     wvals.bluey = param[5].data.d_float;
  279.  
  280.  
  281.                 break;
  282.  
  283.             case RUN_WITH_LAST_VALS:
  284.                 /* Possibly retrieve data */
  285.  
  286.                 gimp_get_data("plug_in_rgb", &wvals);
  287.                 break;
  288.  
  289.             default:
  290.                 break;
  291.         } /* switch */
  292.  
  293.  
  294.   if (status == STATUS_SUCCESS)
  295.     {
  296.       /*  Make sure that the drawable is indexed or RGB color  */
  297.       if (gimp_drawable_color (drawable->id))
  298.         {
  299.           gimp_progress_init ("RGB Displace: Transforming ...");
  300.  
  301.             /* Set the tile cache size */
  302.  
  303.             gimp_tile_cache_ntiles(2*(drawable->width / gimp_tile_width()+1));
  304.  
  305.             /* Run! */
  306.  
  307.  
  308. /*          gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width ()
  309.                            + 1));*/
  310.           rgb (drawable);
  311.             if (run_mode != RUN_NONINTERACTIVE)
  312.                 gimp_displays_flush();
  313.  
  314.             /* Store data */
  315.  
  316.             if (run_mode == RUN_INTERACTIVE)
  317.                 gimp_set_data("plug_in_rgb", &wvals, sizeof(rgb_vals_t));
  318.  
  319.         }
  320.       else
  321.         {
  322.           status = STATUS_EXECUTION_ERROR;
  323.         }
  324.     }
  325.  
  326.   values[0].data.d_status = status;
  327.  
  328.   gimp_drawable_detach (drawable);
  329. }
  330.  
  331. /*****/
  332.  
  333. static void
  334. rgb_get_pixel(int x, int y, guchar *pixel)
  335. {
  336.         static gint row  = -1;
  337.         static gint col  = -1;
  338.  
  339.         gint    newcol, newrow;
  340.         gint    newcoloff, newrowoff;
  341.         guchar *p;
  342.         int     i;
  343.  
  344.         if ((x < 0) || (x >= img_width) || (y < 0) || (y >= img_height)) {
  345.             pixel[0] = 0;
  346.             pixel[1] = 0;
  347.             pixel[2] = 0;
  348.             pixel[3] = 0;
  349.  
  350.             return;
  351.         } /* if */
  352.  
  353.         newcol    = x / tile_width; /* The compiler should optimize this */
  354.         newcoloff = x % tile_width;
  355.         newrow    = y / tile_height;
  356.         newrowoff = y % tile_height;
  357.  
  358.         if ((col != newcol) || (row != newrow) || (the_tile == NULL)) {
  359.  
  360.             if (the_tile != NULL)
  361.                 gimp_tile_unref(the_tile, FALSE);
  362.  
  363.             the_tile = gimp_drawable_get_tile(drawable, FALSE, newrow, newcol);
  364.             gimp_tile_ref(the_tile);
  365.             col = newcol;
  366.             row = newrow;
  367.         } /* if */
  368.         p = the_tile->data + the_tile->bpp * (the_tile->ewidth * newrowoff + newcoloff);
  369.         for (i = img_bpp; i; i--)
  370.             *pixel++ = *p++;
  371.  
  372. } /* rgb_get_pixel */
  373.  
  374.  
  375.  
  376. static void
  377. rgb_render_row (const guchar *src_row,
  378.               guchar *dest_row,
  379.               gint row,
  380.               gint row_width,
  381.               gint bytes, 
  382.           gdouble redx, gdouble greenx, gdouble bluex,
  383.                  gdouble redy, gdouble greeny, gdouble bluey          
  384.           )
  385.  
  386.  
  387.  
  388.  
  389. {
  390.   gint col, bytenum;
  391.   guchar *pixel;
  392.   
  393.   pixel=(guchar*) malloc(10);
  394.   
  395.   for (col = 0; col < row_width ; col++)
  396.     {
  397.       short int v1, v2, v3;
  398.       rgb_get_pixel(col-redx, row-redy, pixel);
  399.       v1=pixel[0];
  400.       rgb_get_pixel(col-greenx, row-greeny, pixel);
  401.       v2=pixel[1];
  402.       rgb_get_pixel(col-bluex, row-bluey, pixel); 
  403.       v3=pixel[2];
  404.       
  405.       dest_row[col*bytes] = (int)v1;
  406.       dest_row[col*bytes +1] = (int)v2;
  407.       dest_row[col*bytes +2] = (int)v3;
  408.  
  409.       if (bytes>3)
  410.         for (bytenum = 3; bytenum<bytes; bytenum++)
  411.           {
  412.             dest_row[col*bytes+bytenum] = src_row[col*bytes+bytenum];
  413.           }
  414.     }
  415. }
  416.  
  417.  
  418.  
  419.  
  420.  
  421. static void
  422. rgb (GDrawable *drawable)
  423. {
  424.   GPixelRgn srcPR, destPR;
  425.   gint width, height;
  426.   gint bytes;
  427.   guchar *src_row;
  428.   guchar *dest_row;
  429.   gint row;
  430.   gint x1, y1, x2, y2;
  431.   gdouble redx,greenx,bluex;
  432.   gdouble redy,greeny,bluey;
  433.  
  434.   /* Get the input area. This is the bounding box of the selection in
  435.    *  the image (or the entire image if there is no selection). Only
  436.    *  operating on the input area is simply an optimization. It doesn't
  437.    *  need to be done for correct operation. (It simply makes it go
  438.    *  faster, since fewer pixels need to be operated on).
  439.    */
  440.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  441.  
  442.   /* Get the size of the input image. (This will/must be the same
  443.    *  as the size of the output image.
  444.    */
  445.   width = drawable->width;
  446.   height = drawable->height;
  447.   bytes = drawable->bpp;
  448.  
  449.   /*  allocate row buffers  */
  450.   src_row = (guchar *) malloc ((x2 - x1) * bytes);
  451.   dest_row = (guchar *) malloc ((x2 - x1) * bytes);
  452.  
  453.  
  454.   /*  initialize the pixel regions  */
  455.   gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
  456.   gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
  457.  
  458.  
  459.   redx = wvals.redx;
  460.   greenx = wvals.greenx;
  461.   bluex = wvals.bluex;
  462.   redy = wvals.redy;
  463.   greeny = wvals.greeny;
  464.   bluey = wvals.bluey;
  465.  
  466.   for (row = y1; row < y2; row++)
  467.  
  468.     {
  469.       gimp_pixel_rgn_get_row (&srcPR, src_row, x1, row, (x2 - x1));
  470.  
  471.       rgb_render_row (src_row,
  472.                 dest_row,
  473.                 row,
  474.                 (x2 - x1),
  475.                 bytes,
  476.                 redx, greenx, bluex,
  477.             redy, greeny, bluey);
  478.  
  479.       /*  store the dest  */
  480.       gimp_pixel_rgn_set_row (&destPR, dest_row, x1, row, (x2 - x1));
  481.  
  482.       if ((row % 10) == 0)
  483.         gimp_progress_update ((double) row / (double) (y2 - y1));
  484.     }
  485.  
  486.   /*  update the processed region  */
  487.   gimp_drawable_flush (drawable);
  488.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  489.   gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  490.  
  491.   free (src_row);
  492.   free (dest_row);
  493. }
  494.  
  495. /*****/
  496.  
  497. static void
  498. build_preview_source_image(void)
  499. {
  500.         double  left, right, bottom, top;
  501.         double  px, py;
  502.         double  dx, dy;
  503.         int     x, y;
  504.         guchar *p;
  505.         guchar  pixel[4];
  506.  
  507.         wint.image  = g_malloc(preview_width * preview_height * 3 * sizeof(guchar));
  508.         wint.wimage = g_malloc(preview_width * preview_height * 3 * sizeof(guchar));
  509.  
  510.         left   = sel_x1;
  511.         right  = sel_x2 - 1;
  512.         bottom = sel_y2 - 1;
  513.         top    = sel_y1;
  514.  
  515.         dx = (right - left) / (preview_width - 1);
  516.         dy = (bottom - top) / (preview_height - 1);
  517.  
  518.         py = top;
  519.  
  520.         p = wint.image;
  521.  
  522.         for (y = 0; y < preview_height; y++) {
  523.             px = left;
  524.             for (x = 0; x < preview_width; x++) {
  525.                 rgb_get_pixel((int) px, (int) py, pixel);
  526.  
  527.                 *p++ = pixel[0];
  528.                 *p++ = pixel[1];
  529.                 *p++ = pixel[2];
  530.  
  531.                 px += dx;
  532.             } /* for */
  533.  
  534.             py += dy;
  535.         } /* for */
  536. } /* build_preview_source_image */
  537.  
  538.  
  539. static void
  540. rgb_logo_ok_callback(GtkWidget *widget, gpointer   data)
  541. {
  542.   gtk_widget_set_sensitive (maindlg, TRUE);
  543.   gtk_widget_destroy(logodlg);
  544. }
  545.  
  546. static void
  547. rgb_close_callback(GtkWidget *widget,  gpointer   data)
  548.   gtk_main_quit();
  549. }
  550.  
  551. static void
  552. rgb_about_callback(GtkWidget *widget, gpointer   data)
  553. {
  554.   gtk_widget_set_sensitive (maindlg, FALSE);
  555.   rgb_logo_dialog();
  556. }
  557.  
  558. static void
  559. set_tooltip (GtkTooltips *tooltips, GtkWidget *widget, const char *desc)
  560. {
  561.   if (desc && desc[0])
  562.     gtk_tooltips_set_tip (tooltips, widget, (char *) desc, NULL);
  563. }
  564.  
  565.  
  566. /*****/
  567.  
  568. static gint
  569. rgb_dialog(void)
  570. {
  571.         GtkWidget  *dialog;
  572.         GtkWidget  *top_table;
  573.         GtkWidget  *frame;
  574.         GtkWidget  *toggle_vbox;
  575.         GtkWidget  *table, *table2, *table3;
  576.         GtkWidget  *button;
  577.         gint        argc;
  578.         gchar     **argv;
  579.         guchar     *color_cube;
  580.  
  581.     argc    = 1;
  582.         argv    = g_new(gchar *, 1);
  583.         argv[0] = g_strdup("rgb");
  584.  
  585.         gtk_init(&argc, &argv);
  586.  
  587.         gtk_preview_set_gamma(gimp_gamma());
  588.         gtk_preview_set_install_cmap(gimp_install_cmap());
  589.         color_cube = gimp_color_cube();
  590.         gtk_preview_set_color_cube(color_cube[0], color_cube[1], color_cube[2], color_cube[3]);
  591.  
  592.         gtk_widget_set_default_visual(gtk_preview_get_visual());
  593.         gtk_widget_set_default_colormap(gtk_preview_get_cmap());
  594.  
  595.         build_preview_source_image();
  596.         dialog = maindlg = gtk_dialog_new();
  597.         gtk_window_set_title(GTK_WINDOW(dialog), "RGB");
  598.         gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
  599.         gtk_container_border_width(GTK_CONTAINER(dialog), 0);
  600.         gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
  601.                    (GtkSignalFunc) dialog_close_callback,
  602.                    NULL);
  603.  
  604.         top_table = gtk_table_new(10, 10, FALSE);
  605.         gtk_container_border_width(GTK_CONTAINER(top_table), 6);
  606.         gtk_table_set_row_spacings(GTK_TABLE(top_table), 4);
  607.         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), top_table, FALSE, FALSE, 0);
  608.         gtk_widget_show(top_table);
  609.  
  610.     /* use black as foreground: */
  611.         tips = gtk_tooltips_new ();
  612.         tips_fg.red   = 0;
  613.         tips_fg.green = 0;
  614.         tips_fg.blue  = 0;
  615.        /* postit yellow (khaki) as background: */
  616.         gdk_color_alloc (gtk_widget_get_colormap (top_table), &tips_fg);
  617.         tips_bg.red   = 61669;
  618.         tips_bg.green = 59113;
  619.         tips_bg.blue  = 35979;
  620.         gdk_color_alloc (gtk_widget_get_colormap (top_table), &tips_bg);
  621.         gtk_tooltips_set_colors (tips,&tips_bg,&tips_fg);
  622.  
  623.         /* Preview */
  624.  
  625.         frame = gtk_frame_new(NULL);
  626.         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
  627.         gtk_table_attach(GTK_TABLE(top_table), frame, 0, 1, 0, 1, 0, 0, 5, 0);
  628.         gtk_widget_show(frame);
  629.  
  630.         wint.preview = gtk_preview_new(GTK_PREVIEW_COLOR);
  631.         gtk_preview_size(GTK_PREVIEW(wint.preview), preview_width, preview_height);
  632.         gtk_container_add(GTK_CONTAINER(frame), wint.preview);
  633.         gtk_widget_show(wint.preview);
  634.     
  635.         /* Controls */
  636.  
  637.     frame = gtk_frame_new ("Channel X-Axis Displacement Options");
  638.         gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  639.         gtk_container_border_width(GTK_CONTAINER(frame), 0);
  640.         gtk_table_attach (GTK_TABLE (top_table), frame, 0, 4, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 0);
  641.         toggle_vbox = gtk_vbox_new (FALSE, 0);
  642.         gtk_container_border_width (GTK_CONTAINER (toggle_vbox), 0);
  643.         gtk_container_add (GTK_CONTAINER (frame), toggle_vbox);
  644.  
  645.         table = gtk_table_new(1, 3, FALSE);
  646.         gtk_container_border_width(GTK_CONTAINER(table), 0);
  647.         gtk_box_pack_start (GTK_BOX (toggle_vbox), table, FALSE, FALSE, 0);
  648.         gtk_widget_show(table);
  649.  
  650.         dialog_create_value("R.X", GTK_TABLE(table), 0, &wvals.redx,-50,50, "Red Channel X Disp");
  651.  
  652.  
  653.         table2 = gtk_table_new(1, 3, FALSE);
  654.         gtk_container_border_width(GTK_CONTAINER(table2), 0);
  655.         gtk_box_pack_start (GTK_BOX (toggle_vbox), table2, FALSE, FALSE, 0);
  656.         gtk_widget_show(table2);
  657.  
  658.         dialog_create_value("G.X", GTK_TABLE(table2), 0, &wvals.greenx,-50,50, "Green Channel X Disp");
  659.  
  660.  
  661.         table3 = gtk_table_new(1, 3, FALSE);
  662.         gtk_container_border_width(GTK_CONTAINER(table3), 0);
  663.         gtk_box_pack_start (GTK_BOX (toggle_vbox), table3, FALSE, FALSE, 0);
  664.         gtk_widget_show(table3);
  665.  
  666.         dialog_create_value("B.X", GTK_TABLE(table3), 0, &wvals.bluex,-50,50, "Blue Channel X Disp");
  667.         gtk_widget_show(toggle_vbox);
  668.         gtk_widget_show(frame);
  669.  
  670.     frame = gtk_frame_new ("Channel Y-Axis Displacement Option");
  671.         gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  672.         gtk_container_border_width(GTK_CONTAINER(frame), 0);
  673.         gtk_table_attach (GTK_TABLE (top_table), frame, 0, 4, 4, 5, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 0);
  674.         toggle_vbox = gtk_vbox_new (FALSE, 0);
  675.         gtk_container_border_width (GTK_CONTAINER (toggle_vbox), 0);
  676.         gtk_container_add (GTK_CONTAINER (frame), toggle_vbox);
  677.  
  678.         table = gtk_table_new(1, 3, FALSE);
  679.         gtk_container_border_width(GTK_CONTAINER(table), 0);
  680.         gtk_box_pack_start (GTK_BOX (toggle_vbox), table, FALSE, FALSE, 0);
  681.         gtk_widget_show(table);
  682.         gtk_widget_show(toggle_vbox);
  683.         gtk_widget_show(frame);
  684.  
  685.  
  686.         dialog_create_value("R.Y", GTK_TABLE(table), 0, &wvals.redy,-50,50, "Red Channel Y Disp");
  687.  
  688.  
  689.         table2 = gtk_table_new(1, 3, FALSE);
  690.         gtk_container_border_width(GTK_CONTAINER(table2), 0);
  691.         gtk_box_pack_start (GTK_BOX (toggle_vbox), table2, FALSE, FALSE, 0);
  692.         gtk_widget_show(table2);
  693.  
  694.         dialog_create_value("G.Y", GTK_TABLE(table2), 0, &wvals.greeny,-50,50, "Green Channel Y Disp");
  695.  
  696.  
  697.         table3 = gtk_table_new(1, 3, FALSE);
  698.         gtk_container_border_width(GTK_CONTAINER(table3), 0);
  699.         gtk_box_pack_start (GTK_BOX (toggle_vbox), table3, FALSE, FALSE, 0);
  700.         gtk_widget_show(table3);
  701.  
  702.         dialog_create_value("B.Y", GTK_TABLE(table3), 0, &wvals.bluey,-50,50, "Blue Channel Y Disp");
  703.  
  704.         /* Buttons */
  705.  
  706.  
  707.        gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 6);
  708.  
  709.         button = gtk_button_new_with_label("OK");
  710.         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  711.         gtk_signal_connect(GTK_OBJECT(button), "clicked",
  712.                    (GtkSignalFunc) dialog_ok_callback,
  713.                    dialog);
  714.         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
  715.         gtk_widget_grab_default(button);
  716.         gtk_widget_show(button);
  717.         set_tooltip(tips,button,"Accept settings and apply filter on image");
  718.  
  719.         button = gtk_button_new_with_label("Cancel");
  720.         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  721.         gtk_signal_connect(GTK_OBJECT(button), "clicked",
  722.                    (GtkSignalFunc) dialog_cancel_callback,
  723.                    dialog);
  724.         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
  725.         gtk_widget_show(button);
  726.         set_tooltip(tips,button,"Reject any changes and close plug-in");
  727.  
  728.     button = gtk_button_new_with_label("About...");
  729.         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  730.         gtk_signal_connect(GTK_OBJECT(button), "clicked",
  731.                      (GtkSignalFunc)rgb_about_callback,button);
  732.         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
  733.              button, TRUE, TRUE, 0);
  734.         gtk_widget_show(button);
  735.     set_tooltip(tips,button,"Show information about this plug-in and the author");
  736.  
  737.  
  738.         /* Done */
  739.  
  740.         gtk_widget_show(dialog);
  741.     ready=1;
  742.         dialog_update_preview(); 
  743.  
  744.         gtk_main();
  745.         gdk_flush();
  746.         if (the_tile != NULL) {
  747.             gimp_tile_unref(the_tile, FALSE);
  748.             the_tile = NULL;
  749.         } /* if */
  750.  
  751.         g_free(wint.image);
  752.         g_free(wint.wimage);
  753.  
  754.         return wint.run;
  755. } /* rgb_dialog */
  756.  
  757.  
  758. /*****/
  759.  
  760. static void
  761. dialog_update_preview(void)
  762. {
  763.         double  left, right, bottom, top;
  764.         double  dx, dy;
  765.         int  px, py;
  766.         int     x, y;
  767.         gdouble  redx, greenx, bluex;
  768.         gdouble  redy, greeny, bluey;
  769.         short int r,g,b;
  770.         double  scale_x, scale_y;
  771.         guchar *p_ul, *i, *p;
  772.         if (ready==0) return;
  773.         left   = sel_x1;
  774.         right  = sel_x2 - 1;
  775.         bottom = sel_y2 - 1;
  776.         top    = sel_y1;
  777.         dx = (right - left) / (preview_width - 1);
  778.         dy = (bottom - top) / (preview_height - 1);
  779.  
  780.         redx = wvals.redx;
  781.         greenx = wvals.greenx;
  782.         bluex = wvals.bluex;
  783.     
  784.         redy = wvals.redy;
  785.         greeny = wvals.greeny;
  786.         bluey = wvals.bluey;
  787.  
  788.         scale_x = (double) (preview_width - 1) / (right - left);
  789.         scale_y = (double) (preview_height - 1) / (bottom - top);
  790.  
  791.         py = 0;
  792.  
  793.         p_ul = wint.wimage;
  794.  
  795.         for (y = 0; y < preview_height; y++) {
  796.             px = 0;
  797.  
  798.             for (x = 0; x < preview_width; x++) {
  799.         
  800.                    i = wint.image + 3 * (preview_width * (py-(int)(scale_y*redy)) + px-(int)(redx*scale_x));
  801.                    r = *i;
  802.                    i = wint.image + 3 * (preview_width * (py-(int)(scale_y*greeny)) + px-(int)(greenx*scale_x))+1;
  803.                    g = *i;
  804.                    i = wint.image + 3 * (preview_width * (py-(int)(scale_y*bluey)) + px-(int)(bluex*scale_x))+2;
  805.                    b = *i;
  806.                if (py-(int)(scale_y*redy)>=preview_height) r=0;
  807.                if (py-(int)(scale_y*greeny)>=preview_height) g=0;
  808.                if (py-(int)(scale_y*bluey)>=preview_height) b=0;
  809.                if (px-(int)(scale_x*redx)>=preview_width) r=0;
  810.                if (px-(int)(scale_x*greenx)>=preview_width) g=0;
  811.                if (px-(int)(scale_x*bluex)>=preview_width) b=0;
  812.                
  813.                 if (py-(int)(scale_y*redy)<0) r=0;
  814.                if (py-(int)(scale_y*greeny)<0) g=0;
  815.                if (py-(int)(scale_y*bluey)<0) b=0;
  816.                if (px-(int)(scale_x*redx)<0) r=0;
  817.                if (px-(int)(scale_x*greenx)<0) g=0;
  818.                if (px-(int)(scale_x*bluex)<0) b=0;
  819.                    p_ul[0] = r;
  820.                    p_ul[1] = g;
  821.                    p_ul[2] = b;
  822.                    p_ul += 3;
  823.                    px += 1; 
  824.             } /* for */
  825.             py +=1; 
  826.         } /* for */
  827.  
  828.         p = wint.wimage;
  829.  
  830.         for (y = 0; y < preview_height; y++) {
  831.             gtk_preview_draw_row(GTK_PREVIEW(wint.preview), p, 0, y, preview_width);
  832.             p += preview_width * 3;
  833.         } /* for */
  834.         gtk_widget_draw(wint.preview, NULL);
  835.         gdk_flush();
  836. } /* dialog_update_preview */
  837.  
  838.  
  839. /*****/
  840.  
  841. static void
  842. dialog_create_value(char *title, GtkTable *table, int row, gdouble *value,
  843.                 int left, int right, const char *desc)
  844. {
  845.         GtkWidget *label;
  846.         GtkWidget *scale;
  847.         GtkWidget *entry;
  848.         GtkObject *scale_data;
  849.         char       buf[256];
  850.  
  851.         label = gtk_label_new(title);
  852.         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
  853.         gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
  854.         gtk_widget_show(label);
  855.  
  856.  
  857.         scale_data = gtk_adjustment_new(*value, left, right,
  858.                         (right - left) / 1000,
  859.                         (right - left) / 1000,
  860.                         0);
  861.  
  862.         gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
  863.                    (GtkSignalFunc) dialog_scale_update,
  864.                    value);
  865.  
  866.         scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data));
  867.         gtk_widget_set_usize(scale, SCALE_WIDTH, 0);
  868.         gtk_table_attach(table, scale, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
  869.         gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE);
  870.         gtk_scale_set_digits(GTK_SCALE(scale), 3);
  871.         gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS);
  872.         gtk_widget_show(scale);
  873.         set_tooltip(tips,scale,desc);
  874.  
  875.         entry = gtk_entry_new();
  876.         gtk_object_set_user_data(GTK_OBJECT(entry), scale_data);
  877.         gtk_object_set_user_data(scale_data, entry);
  878.         gtk_widget_set_usize(entry, ENTRY_WIDTH, 0);
  879.         sprintf(buf, "%0.2f", *value);
  880.         gtk_entry_set_text(GTK_ENTRY(entry), buf);
  881.         gtk_signal_connect(GTK_OBJECT(entry), "changed",
  882.                    (GtkSignalFunc) dialog_entry_update,
  883.                    value);
  884.         gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
  885.         gtk_widget_show(entry);
  886.     set_tooltip(tips,entry,desc);
  887.  
  888. } /* dialog_create_value */
  889.  
  890. /*****/
  891.  
  892. static void
  893. dialog_scale_update(GtkAdjustment *adjustment, gdouble *value)
  894. {
  895.         GtkWidget *entry;
  896.         char       buf[256];
  897.  
  898.         if (*value != adjustment->value) {
  899.             *value = adjustment->value;
  900.  
  901.             entry = gtk_object_get_user_data(GTK_OBJECT(adjustment));
  902.             sprintf(buf, "%0.2f", *value);
  903.  
  904.             gtk_signal_handler_block_by_data(GTK_OBJECT(entry), value);
  905.             gtk_entry_set_text(GTK_ENTRY(entry), buf);
  906.             gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), value);
  907.  
  908.             dialog_update_preview();
  909.         } /* if */
  910. } /* dialog_scale_update */
  911. /*****/
  912.  
  913. static void
  914. dialog_entry_update(GtkWidget *widget, gdouble *value)
  915. {
  916.         GtkAdjustment *adjustment;
  917.         gdouble        new_value;
  918.  
  919.         new_value = atof(gtk_entry_get_text(GTK_ENTRY(widget)));
  920.  
  921.         if (*value != new_value) {
  922.             adjustment = gtk_object_get_user_data(GTK_OBJECT(widget));
  923.  
  924.             if ((new_value >= adjustment->lower) &&
  925.                 (new_value <= adjustment->upper)) {
  926.                 *value        = new_value;
  927.                 adjustment->value = new_value;
  928.  
  929.                 gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed");
  930.  
  931.                 dialog_update_preview();
  932.             } /* if */
  933.         } /* if */
  934. } /* dialog_entry_update */
  935.  
  936.  
  937. static void
  938. dialog_close_callback(GtkWidget *widget, gpointer data)
  939. {
  940.         gtk_main_quit();
  941. } /* dialog_close_callback */
  942.  
  943.  
  944. /*****/
  945.  
  946. static void
  947. dialog_ok_callback(GtkWidget *widget, gpointer data)
  948. {
  949.         wint.run = TRUE;
  950.         gtk_widget_destroy(GTK_WIDGET(data));
  951. } /* dialog_ok_callback */
  952.  
  953.  
  954. /*****/
  955.  
  956. static void
  957. dialog_cancel_callback(GtkWidget *widget, gpointer data)
  958. {
  959.         gtk_widget_destroy(GTK_WIDGET(data));
  960. } /* dialog_cancel_callback */
  961.  
  962.  
  963. GtkWidget * 
  964. rgb_logo_dialog()
  965. {
  966.   GtkWidget *xdlg;
  967.   GtkWidget *xlabel;
  968.   GtkWidget *xbutton;
  969.   GtkWidget *xlogo_box;
  970.   GtkWidget *xpreview;
  971.   GtkWidget *xframe,*xframe2;
  972.   GtkWidget *xvbox;
  973.   GtkWidget *xhbox;
  974.   char *text;
  975.   guchar *temp,*temp2;
  976.   unsigned char *datapointer;
  977.   gint y,x;
  978.   xdlg = logodlg = gtk_dialog_new();
  979.   gtk_window_set_title(GTK_WINDOW(xdlg), "About");
  980.   gtk_window_position(GTK_WINDOW(xdlg), GTK_WIN_POS_MOUSE);
  981.   gtk_signal_connect(GTK_OBJECT(xdlg), "destroy",
  982.                      (GtkSignalFunc)rgb_close_callback,
  983.              NULL);
  984.  
  985.   xbutton = gtk_button_new_with_label("OK");
  986.   GTK_WIDGET_SET_FLAGS(xbutton, GTK_CAN_DEFAULT);
  987.   gtk_signal_connect(GTK_OBJECT(xbutton), "clicked",
  988.                      (GtkSignalFunc)rgb_logo_ok_callback,
  989.              xdlg);
  990.   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(xdlg)->action_area),
  991.              xbutton, TRUE, TRUE, 0);
  992.   gtk_widget_grab_default(xbutton);
  993.   gtk_widget_show(xbutton);
  994.   set_tooltip(tips,xbutton,"This closes the information box");
  995.  
  996.   xframe = gtk_frame_new(NULL);
  997.   gtk_frame_set_shadow_type(GTK_FRAME(xframe), GTK_SHADOW_ETCHED_IN);
  998.   gtk_container_border_width(GTK_CONTAINER(xframe), 10);
  999.   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(xdlg)->vbox), xframe, TRUE, TRUE, 0);
  1000.   xvbox = gtk_vbox_new(FALSE, 5);
  1001.   gtk_container_border_width(GTK_CONTAINER(xvbox), 10);
  1002.   gtk_container_add(GTK_CONTAINER(xframe), xvbox);
  1003.  
  1004.   /*  The logo frame & drawing area  */
  1005.   xhbox = gtk_hbox_new (FALSE, 5);
  1006.   gtk_box_pack_start (GTK_BOX (xvbox), xhbox, FALSE, TRUE, 0);
  1007.  
  1008.   xlogo_box = gtk_vbox_new (FALSE, 0);
  1009.   gtk_box_pack_start (GTK_BOX (xhbox), xlogo_box, FALSE, FALSE, 0);
  1010.  
  1011.   xframe2 = gtk_frame_new (NULL);
  1012.   gtk_frame_set_shadow_type (GTK_FRAME (xframe2), GTK_SHADOW_IN);
  1013.   gtk_box_pack_start (GTK_BOX (xlogo_box), xframe2, FALSE, FALSE, 0);
  1014.  
  1015.   xpreview = gtk_preview_new (GTK_PREVIEW_COLOR);
  1016.   gtk_preview_size (GTK_PREVIEW (xpreview), logo_width, logo_height);
  1017.   temp = g_malloc((logo_width+10)*3);
  1018.   datapointer=header_data+logo_width*logo_height-1;
  1019.   for (y = 0; y < logo_height; y++){
  1020.     temp2=temp;
  1021.     for (x = 0; x< logo_width; x++) {
  1022.       HEADER_PIXEL(datapointer,temp2); temp2+=3;}
  1023.     gtk_preview_draw_row (GTK_PREVIEW (xpreview),
  1024.               temp,
  1025.               0, y, logo_width); 
  1026.   }              
  1027.   g_free(temp);
  1028.   gtk_container_add (GTK_CONTAINER (xframe2), xpreview);
  1029.   gtk_widget_show (xpreview);
  1030.   gtk_widget_show (xframe2);
  1031.   gtk_widget_show (xlogo_box);
  1032.   gtk_widget_show (xhbox);
  1033.  
  1034.   xhbox = gtk_hbox_new(FALSE, 5);
  1035.   gtk_box_pack_start(GTK_BOX(xvbox), xhbox, TRUE, TRUE, 0);
  1036.   text = "\nCotting Software Productions\n"
  1037.          "Quellenstrasse 10\n"
  1038.        "CH-8005 Zuerich (Switzerland)\n\n"
  1039.      "cotting@multimania.com\n"
  1040.      "http://www.multimania.com/cotting\n\n"
  1041.          "RGB Displace Plug-In for the GIMP\n"
  1042.          "Version 1.00\n";
  1043.   xlabel = gtk_label_new(text);
  1044.   gtk_box_pack_start(GTK_BOX(xhbox), xlabel, TRUE, FALSE, 0);
  1045.   gtk_widget_show(xlabel);
  1046.  
  1047.   gtk_widget_show(xhbox);
  1048.  
  1049.   gtk_widget_show(xvbox);
  1050.   gtk_widget_show(xframe);
  1051.   gtk_widget_show(xdlg);
  1052.  
  1053.   gtk_main();
  1054.   gdk_flush();
  1055.   return xdlg;
  1056. }
  1057.