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

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * Bump map plug-in --- emboss an image by using another image as a bump map
  5.  * Copyright (C) 1997 Federico Mena Quintero <federico@nuclecu.unam.mx>
  6.  * Copyright (C) 1997-2000 Jens Lautenbacher <jtl@gimp.org>
  7.  * Copyright (C) 2000 Sven Neumann <sven@gimp.org>
  8.  * 
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23.  */
  24.  
  25.  
  26. /* This plug-in uses the algorithm described by John Schlag, "Fast
  27.  * Embossing Effects on Raster Image Data" in Graphics Gems IV (ISBN
  28.  * 0-12-336155-9).  It takes a grayscale image to be applied as a
  29.  * bump-map to another image, producing a nice embossing effect.
  30.  */
  31.  
  32. /* Version 3.0-pre1-ac2:
  33.  *
  34.  * - waterlevel/ambient restricted to 0-255
  35.  * - correctly initialize bumpmap_offsets
  36.  */   
  37.  
  38. /* Version 3.0-pre1-ac1:
  39.  *
  40.  * - Now able not to tile the bumpmap - this is the default.
  41.  * - Added new PDB call plug_in_bumpmap_tiled.
  42.  * - Added scrollbars for preview.
  43.  * - Fixed slider feedback for bumpmap offset and set initial offsets
  44.  *   from drawable offsets.
  45.  * - Make it work as intended from the very beginning...
  46.  */
  47.   
  48. /* Version 2.04:
  49.  *
  50.  * - The preview is now scrollable via draging with button 1 in the
  51.  * preview area. Thanks to Quartic for helping with gdk event handling.
  52.  *
  53.  * - The bumpmap's offset can alternatively be adjusted by dragging with
  54.  * button 3 in the preview area.
  55.  */
  56.  
  57. /* Version 2.03:
  58.  *
  59.  * - Now transparency in the bumpmap drawable is handled as specified
  60.  * by the waterlevel parameter.  Thanks to Jens for suggesting it!
  61.  *
  62.  * - New cool ambient lighting method.  Thanks to Jens Lautenbacher
  63.  * for creating it!  Something useful actually came out of those IRC
  64.  * sessions ;-)
  65.  *
  66.  * - Added proper rounding wherever it seemed appropriate.  This fixes
  67.  * some minor artifacts in the output.
  68.  */
  69.  
  70.  
  71. /* Version 2.02:
  72.  *
  73.  * - Fixed a stupid bug in the preview code (offsets were not wrapped
  74.  * correctly in some situations).  Thanks to Jens Lautenbacher for
  75.  * reporting it!
  76.  */
  77.  
  78.  
  79. /* Version 2.01:
  80.  *
  81.  * - For the preview, vertical scrolling and setting the vertical
  82.  * bumpmap offset are now *much* faster.  Instead of calling
  83.  * gimp_pixel_rgn_get_row() a lot of times, I now use an adapted
  84.  * version of gimp_pixel_rgn_get_rect().
  85.  */
  86.  
  87.  
  88. /* Version 2.00:
  89.  *
  90.  * - Rewrote from the 0.54 version (well, from the 0.99.9
  91.  * distribution, actually...).  New in this release are the correct
  92.  * handling of all image depths, sizes, and offsets.  Also the
  93.  * different map types, the compensation and map inversion options
  94.  * were added.  The preview widget is new, too.
  95.  */
  96.  
  97.  
  98. /* TODO:
  99.  *
  100.  * - Speed-ups
  101.  */
  102.  
  103. #include "config.h"
  104.  
  105. #include <stdio.h>
  106. #include <stdlib.h>
  107. #include <string.h>
  108. #ifdef HAVE_UNISTD_H
  109. #include <unistd.h>
  110. #endif
  111.  
  112. #include <gtk/gtk.h>
  113.  
  114. #include <libgimp/gimp.h>
  115. #include <libgimp/gimpui.h>
  116.  
  117. #include "libgimp/stdplugins-intl.h"
  118.  
  119.  
  120. /***** Magic numbers *****/
  121.  
  122. #define PLUG_IN_VERSION "April 2000, 3.0-pre1-ac2"
  123.  
  124. #define PREVIEW_SIZE    128
  125. #define SCALE_WIDTH       0
  126.  
  127. /***** Types *****/
  128.  
  129. enum
  130. {
  131.   LINEAR = 0,
  132.   SPHERICAL,
  133.   SINUOSIDAL
  134. };
  135.  
  136. enum
  137. {
  138.   DRAG_NONE = 0,
  139.   DRAG_SCROLL,
  140.   DRAG_BUMPMAP
  141. };
  142.  
  143. typedef struct
  144. {
  145.   gint32  bumpmap_id;
  146.   gdouble azimuth;
  147.   gdouble elevation;
  148.   gint    depth;
  149.   gint    xofs;
  150.   gint    yofs;
  151.   gint    waterlevel;
  152.   gint    ambient;
  153.   gint    compensate;
  154.   gint    invert;
  155.   gint    type;
  156.   gint    tiled;
  157. } bumpmap_vals_t;
  158.  
  159. typedef struct
  160. {
  161.   gint    lx, ly;       /* X and Y components of light vector */
  162.   gint    nz2, nzlz;    /* nz^2, nz*lz */
  163.   gint    background;   /* Shade for vertical normals */
  164.   gdouble compensation; /* Background compensation */
  165.   guchar  lut[256];     /* Look-up table for modes */
  166. } bumpmap_params_t;
  167.  
  168. typedef struct
  169. {
  170.   GtkWidget   *preview;
  171.   GtkObject   *preview_adj_x;
  172.   GtkObject   *preview_adj_y;
  173.   gint         preview_width;
  174.   gint         preview_height;
  175.   gint         mouse_x;
  176.   gint         mouse_y;
  177.   gint         preview_xofs;
  178.   gint         preview_yofs;
  179.   gint         drag_mode;
  180.  
  181.   GtkObject   *offset_adj_x;
  182.   GtkObject   *offset_adj_y;
  183.   
  184.   guchar      *check_row_0;
  185.   guchar      *check_row_1;
  186.  
  187.   guchar     **src_rows;
  188.   guchar     **bm_rows;
  189.  
  190.   gint         src_yofs;
  191.   gint         bm_yofs;
  192.  
  193.   GimpDrawable   *bm_drawable;
  194.   gint         bm_width;
  195.   gint         bm_height;
  196.   gint         bm_bpp;
  197.   gint         bm_has_alpha;
  198.  
  199.   GimpPixelRgn    src_rgn;
  200.   GimpPixelRgn    bm_rgn;
  201.  
  202.   bumpmap_params_t params;
  203.  
  204.   gint         run;
  205. } bumpmap_interface_t;
  206.  
  207.  
  208. /***** Prototypes *****/
  209.  
  210. static void query (void);
  211. static void run   (gchar   *name,
  212.            gint     nparams,
  213.            GimpParam  *param,
  214.            gint    *nreturn_vals,
  215.            GimpParam **return_vals);
  216.  
  217. static void bumpmap             (void);
  218. static void bumpmap_init_params (bumpmap_params_t *params);
  219. static void bumpmap_row         (guchar           *src_row,
  220.                  guchar           *dest_row,
  221.                  gint              width,
  222.                  gint              bpp,
  223.                  gint              has_alpha,
  224.                  guchar           *bm_row1,
  225.                  guchar           *bm_row2,
  226.                  guchar           *bm_row3,
  227.                  gint              bm_width,
  228.                  gint              bm_xofs,
  229.                  gboolean          tiled,
  230.                  gboolean          row_in_bumpmap,       
  231.                  bumpmap_params_t *params);
  232. static void bumpmap_convert_row (guchar           *row,
  233.                  gint              width,
  234.                  gint              bpp,
  235.                  gint              has_alpha,
  236.                  guchar           *lut);
  237.  
  238. static gint bumpmap_dialog              (void);
  239. static void dialog_init_preview         (void);
  240. static void dialog_new_bumpmap          (gboolean init_offsets);
  241. static void dialog_update_preview       (void);
  242. static gint dialog_preview_events       (GtkWidget *widget, GdkEvent *event);
  243. static void dialog_scroll_src           (void);
  244. static void dialog_scroll_bumpmap       (void);
  245. static void dialog_get_rows             (GimpPixelRgn *pr, guchar **rows,
  246.                      gint x, gint y,
  247.                      gint width, gint height);
  248. static void dialog_fill_src_rows        (gint start, gint how_many, gint yofs);
  249. static void dialog_fill_bumpmap_rows    (gint start, gint how_many, gint yofs);
  250.  
  251. static void dialog_compensate_callback  (GtkWidget *widget, gpointer data);
  252. static void dialog_invert_callback      (GtkWidget *widget, gpointer data);
  253. static void dialog_tiled_callback       (GtkWidget *widget, gpointer data);
  254. static void dialog_map_type_callback    (GtkWidget *widget, gpointer data);
  255. static gint dialog_constrain            (gint32 image_id, gint32 drawable_id,
  256.                      gpointer data);
  257. static void dialog_bumpmap_callback     (gint32 id, gpointer data);
  258. static void dialog_dscale_update        (GtkAdjustment *adjustment,
  259.                      gdouble *value);
  260. static void dialog_iscale_update_normal (GtkAdjustment *adjustment, gint *value);
  261. static void dialog_iscale_update_full   (GtkAdjustment *adjustment, gint *value);
  262. static void dialog_ok_callback          (GtkWidget *widget, gpointer data);
  263.  
  264. /***** Variables *****/
  265.  
  266. GimpPlugInInfo PLUG_IN_INFO =
  267. {
  268.   NULL,  /* init_proc  */
  269.   NULL,  /* quit_proc  */
  270.   query, /* query_proc */
  271.   run    /* run_proc   */
  272. };
  273.  
  274. static bumpmap_vals_t bmvals =
  275. {
  276.   -1,     /* bumpmap_id */
  277.   135.0,  /* azimuth */
  278.   45.0,   /* elevation */
  279.   3,      /* depth */
  280.   0,      /* xofs */
  281.   0,      /* yofs */
  282.   0,      /* waterlevel */
  283.   0,      /* ambient */
  284.   FALSE,  /* compensate */
  285.   FALSE,  /* invert */
  286.   LINEAR, /* type */
  287.   FALSE   /* tiled */
  288. };
  289.  
  290. static bumpmap_interface_t bmint =
  291. {
  292.   NULL,      /* preview */
  293.   NULL,      /* preview_adj_x */
  294.   NULL,      /* preview_adj_y */
  295.   0,         /* preview_width */
  296.   0,         /* preview_height */
  297.   0,         /* mouse_x */
  298.   0,         /* mouse_y */
  299.   0,         /* preview_xofs */
  300.   0,         /* preview_yofs */
  301.   DRAG_NONE, /* drag_mode */
  302.   NULL,      /* offset_adj_x */
  303.   NULL,      /* offset_adj_y */
  304.   NULL,      /* check_row_0 */
  305.   NULL,      /* check_row_1 */
  306.   NULL,      /* src_rows */
  307.   NULL,      /* bm_rows */
  308.   0,         /* src_yofs */
  309.   -1,        /* bm_yofs */
  310.   NULL,      /* bm_drawable */
  311.   0,         /* bm_width */
  312.   0,         /* bm_height */
  313.   0,         /* bm_bpp */
  314.   0,         /* bm_has_alpha */
  315.   { 0 },     /* src_rgn */
  316.   { 0 },     /* bm_rgn */
  317.   { 0 },     /* params */
  318.   FALSE      /* run */
  319. };
  320.  
  321. static GimpDrawable *drawable = NULL;
  322.  
  323. static gint       sel_x1, sel_y1;
  324. static gint       sel_x2, sel_y2;
  325. static gint       sel_width, sel_height;
  326. static gint       img_bpp;
  327. static gboolean   img_has_alpha;
  328.  
  329. /***** Functions *****/
  330.  
  331. MAIN ()
  332.  
  333. static void
  334. query (void)
  335. {
  336.   static GimpParamDef args[] =
  337.   {
  338.     { GIMP_PDB_INT32,    "run_mode",   "Interactive, non-interactive" },
  339.     { GIMP_PDB_IMAGE,    "image",      "Input image" },
  340.     { GIMP_PDB_DRAWABLE, "drawable",   "Input drawable" },
  341.     { GIMP_PDB_DRAWABLE, "bumpmap",    "Bump map drawable" },
  342.     { GIMP_PDB_FLOAT,    "azimuth",    "Azimuth" },
  343.     { GIMP_PDB_FLOAT,    "elevation",  "Elevation" },
  344.     { GIMP_PDB_INT32,    "depth",      "Depth" },
  345.     { GIMP_PDB_INT32,    "xofs",       "X offset" },
  346.     { GIMP_PDB_INT32,    "yofs",       "Y offset" },
  347.     { GIMP_PDB_INT32,    "waterlevel", "Level that full transparency should represent" },
  348.     { GIMP_PDB_INT32,    "ambient",    "Ambient lighting factor" },
  349.     { GIMP_PDB_INT32,    "compensate", "Compensate for darkening" },
  350.     { GIMP_PDB_INT32,    "invert",     "Invert bumpmap" },
  351.     { GIMP_PDB_INT32,    "type",       "Type of map (LINEAR (0), SPHERICAL (1), SINUOSIDAL (2))" }
  352.   };
  353.   static gint nargs = sizeof (args) / sizeof (args[0]);
  354.  
  355.   gimp_install_procedure ("plug_in_bump_map",
  356.               "Create an embossing effect using an image as a "
  357.               "bump map",
  358.               "This plug-in uses the algorithm described by John "
  359.               "Schlag, \"Fast Embossing Effects on Raster Image "
  360.               "Data\" in Graphics GEMS IV (ISBN 0-12-336155-9). "
  361.               "It takes a drawable to be applied as a bump "
  362.               "map to another image and produces a nice embossing "
  363.               "effect.",
  364.               "Federico Mena Quintero, Jens Lautenbacher & Sven Neumann",
  365.               "Federico Mena Quintero, Jens Lautenbacher & Sven Neumann",
  366.               PLUG_IN_VERSION,
  367.               N_("<Image>/Filters/Map/Bump Map..."),
  368.               "RGB*, GRAY*",
  369.               GIMP_PLUGIN,
  370.               nargs, 0,
  371.               args, NULL);
  372.  
  373.   gimp_install_procedure ("plug_in_bump_map_tiled",
  374.               "Create an embossing effect using a tiled image "
  375.               "as a bump map",
  376.               "This plug-in uses the algorithm described by John "
  377.               "Schlag, \"Fast Embossing Effects on Raster Image "
  378.               "Data\" in Graphics GEMS IV (ISBN 0-12-336155-9). "
  379.               "It takes a drawable to be tiled and applied as a "
  380.               "bump map to another image and produces a nice "
  381.               "embossing effect.",
  382.               "Federico Mena Quintero, Jens Lautenbacher & Sven Neumann",
  383.               "Federico Mena Quintero, Jens Lautenbacher & Sven Neumann",
  384.               PLUG_IN_VERSION,
  385.               NULL,
  386.               "RGB*, GRAY*",
  387.               GIMP_PLUGIN,
  388.               nargs, 0,
  389.               args, NULL);
  390. }
  391.  
  392. static void
  393. run (gchar   *name,
  394.      gint     nparams,
  395.      GimpParam  *param,
  396.      gint    *nreturn_vals,
  397.      GimpParam **return_vals)
  398. {
  399.   static GimpParam values[1];
  400.  
  401.   GimpRunModeType run_mode;
  402.   GimpPDBStatusType  status;
  403.  
  404.   INIT_I18N_UI();
  405.  
  406.   status   = GIMP_PDB_SUCCESS;
  407.   run_mode = param[0].data.d_int32;
  408.  
  409.   values[0].type          = GIMP_PDB_STATUS;
  410.   values[0].data.d_status = status;
  411.  
  412.   *nreturn_vals = 1;
  413.   *return_vals  = values;
  414.  
  415.   /* Get drawable information */
  416.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  417.  
  418.   gimp_drawable_mask_bounds (drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
  419.  
  420.   sel_width     = sel_x2 - sel_x1;
  421.   sel_height    = sel_y2 - sel_y1;
  422.   img_bpp       = gimp_drawable_bpp (drawable->id);
  423.   img_has_alpha = gimp_drawable_has_alpha (drawable->id);
  424.  
  425.   /* See how we will run */
  426.   switch (run_mode)
  427.     {
  428.     case GIMP_RUN_INTERACTIVE:
  429.       /* Possibly retrieve data */
  430.       gimp_get_data (name, &bmvals);
  431.   
  432.       /* Get information from the dialog */
  433.       if (!bumpmap_dialog ())
  434.     return;
  435.  
  436.       break;
  437.  
  438.     case GIMP_RUN_NONINTERACTIVE:
  439.       /* Make sure all the arguments are present */
  440.       if (nparams != 14)
  441.     {
  442.       status = GIMP_PDB_CALLING_ERROR;
  443.     }
  444.       else
  445.     {
  446.       bmvals.bumpmap_id = param[3].data.d_drawable;
  447.       bmvals.azimuth    = param[4].data.d_float;
  448.       bmvals.elevation  = param[5].data.d_float;
  449.       bmvals.depth      = param[6].data.d_int32;
  450.       bmvals.depth      = param[6].data.d_int32;
  451.       bmvals.xofs       = param[7].data.d_int32;
  452.       bmvals.yofs       = param[8].data.d_int32;
  453.       bmvals.waterlevel = param[9].data.d_int32;
  454.       bmvals.ambient    = param[10].data.d_int32;
  455.       bmvals.compensate = param[11].data.d_int32;
  456.       bmvals.invert     = param[12].data.d_int32;
  457.       bmvals.type       = param[13].data.d_int32;
  458.       bmvals.tiled      = strcmp (name, "plug_in_bump_map_tiled") == 0;  
  459.     }
  460.       break;
  461.  
  462.     case GIMP_RUN_WITH_LAST_VALS:
  463.       /* Possibly retrieve data */
  464.       gimp_get_data (name, &bmvals);
  465.       break;
  466.  
  467.     default:
  468.       break;
  469.     }
  470.  
  471.   /* Bumpmap the image */
  472.  
  473.   if (status == GIMP_PDB_SUCCESS)
  474.     {
  475.       if ((gimp_drawable_is_rgb(drawable->id) ||
  476.        gimp_drawable_is_gray(drawable->id)))
  477.     {
  478.       /* Set the tile cache size */
  479.       gimp_tile_cache_ntiles (2 * (drawable->width +
  480.                        gimp_tile_width () - 1) /
  481.                   gimp_tile_width ());
  482.  
  483.       /* Run! */
  484.       bumpmap ();
  485.  
  486.       /* If run mode is interactive, flush displays */
  487.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  488.         gimp_displays_flush ();
  489.  
  490.       /* Store data */
  491.       if (run_mode == GIMP_RUN_INTERACTIVE)
  492.         gimp_set_data (name, &bmvals, sizeof (bumpmap_vals_t));
  493.     }
  494.     }
  495.   else
  496.     status = GIMP_PDB_EXECUTION_ERROR;
  497.  
  498.   values[0].data.d_status = status;
  499.  
  500.   gimp_drawable_detach (drawable);
  501. }
  502.  
  503. static void
  504. bumpmap (void)
  505. {
  506.   bumpmap_params_t  params;
  507.   GimpDrawable        *bm_drawable;
  508.   GimpPixelRgn         src_rgn, dest_rgn, bm_rgn;
  509.   gint              bm_width, bm_height, bm_bpp, bm_has_alpha;
  510.   gint              yofs1, yofs2, yofs3;
  511.   guchar           *bm_row1, *bm_row2, *bm_row3, *bm_tmprow;
  512.   guchar           *src_row, *dest_row;
  513.   gint              y;
  514.   gint              progress;
  515.   gint              tmp;
  516.  
  517. #if 0
  518.   g_print ("bumpmap: waiting... (pid %d)\n", getpid ());
  519.   kill (getpid (), SIGSTOP);
  520. #endif
  521.  
  522.   gimp_progress_init (_("Bump-mapping..."));
  523.     
  524.   /* Get the bumpmap drawable */
  525.   if (bmvals.bumpmap_id != -1)
  526.     bm_drawable = gimp_drawable_get (bmvals.bumpmap_id);
  527.   else
  528.     bm_drawable = drawable;
  529.  
  530.   if (!bm_drawable)
  531.     return;
  532.  
  533.   /* Get image information */
  534.   bm_width     = gimp_drawable_width (bm_drawable->id);
  535.   bm_height    = gimp_drawable_height (bm_drawable->id);
  536.   bm_bpp       = gimp_drawable_bpp (bm_drawable->id);
  537.   bm_has_alpha = gimp_drawable_has_alpha (bm_drawable->id);
  538.  
  539.   /* Initialize offsets */
  540.   tmp = bmvals.yofs + sel_y1;
  541.   if (tmp < 0)
  542.     yofs2 = bm_height - (- tmp % bm_height);
  543.   else
  544.     yofs2 = tmp % bm_height;
  545.  
  546.   yofs1 = (yofs2 + bm_height - 1) % bm_height;
  547.   yofs3 = (yofs2 + 1) % bm_height;
  548.  
  549.   /* Initialize row buffers */
  550.   bm_row1 = g_new (guchar, bm_width * bm_bpp);
  551.   bm_row2 = g_new (guchar, bm_width * bm_bpp);
  552.   bm_row3 = g_new (guchar, bm_width * bm_bpp);
  553.  
  554.   src_row  = g_new (guchar, sel_width * img_bpp);
  555.   dest_row = g_new (guchar, sel_width * img_bpp);
  556.  
  557.   /* Initialize pixel regions */
  558.   gimp_pixel_rgn_init (&src_rgn, drawable,
  559.                sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE);
  560.   gimp_pixel_rgn_init (&dest_rgn, drawable,
  561.                sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
  562.   gimp_pixel_rgn_init (&bm_rgn, bm_drawable,
  563.                0, 0, bm_width, bm_height, FALSE, FALSE);
  564.  
  565.   /* Bumpmap */
  566.  
  567.   bumpmap_init_params (¶ms);
  568.  
  569.   gimp_pixel_rgn_get_row (&bm_rgn, bm_row1, 0, yofs1, bm_width);
  570.   gimp_pixel_rgn_get_row (&bm_rgn, bm_row2, 0, yofs2, bm_width);
  571.   gimp_pixel_rgn_get_row (&bm_rgn, bm_row3, 0, yofs3, bm_width);
  572.  
  573.   bumpmap_convert_row (bm_row1, bm_width, bm_bpp, bm_has_alpha, params.lut);
  574.   bumpmap_convert_row (bm_row2, bm_width, bm_bpp, bm_has_alpha, params.lut);
  575.   bumpmap_convert_row (bm_row3, bm_width, bm_bpp, bm_has_alpha, params.lut);
  576.  
  577.   progress = 0;
  578.  
  579.   for (y = sel_y1; y < sel_y2; y++)
  580.     {
  581.       gimp_pixel_rgn_get_row (&src_rgn, src_row, sel_x1, y, sel_width);
  582.  
  583.       bumpmap_row (src_row, dest_row, sel_width, img_bpp, img_has_alpha,
  584.            bm_row1, bm_row2, bm_row3, bm_width, bmvals.xofs,
  585.            bmvals.tiled, 
  586.            y == CLAMP (y, - bmvals.yofs, - bmvals.yofs + bm_height),
  587.            ¶ms);
  588.  
  589.       gimp_pixel_rgn_set_row (&dest_rgn, dest_row, sel_x1, y, sel_width);
  590.  
  591.       /* Next line */
  592.  
  593.       bm_tmprow = bm_row1;
  594.       bm_row1   = bm_row2;
  595.       bm_row2   = bm_row3;
  596.       bm_row3   = bm_tmprow;
  597.         
  598.       if (++yofs3 == bm_height)
  599.     yofs3 = 0;
  600.  
  601.       gimp_pixel_rgn_get_row (&bm_rgn, bm_row3, 0, yofs3, bm_width);
  602.       bumpmap_convert_row (bm_row3, bm_width, bm_bpp, bm_has_alpha, params.lut);
  603.  
  604.       gimp_progress_update ((double) ++progress / sel_height);
  605.     }
  606.  
  607.   /* Done */
  608.  
  609.   g_free (bm_row1);
  610.   g_free (bm_row2);
  611.   g_free (bm_row3);
  612.   g_free (src_row);
  613.   g_free (dest_row);
  614.  
  615.   if (bm_drawable != drawable)
  616.     gimp_drawable_detach (bm_drawable);
  617.  
  618.   gimp_drawable_flush (drawable);
  619.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  620.   gimp_drawable_update (drawable->id, sel_x1, sel_y1, sel_width, sel_height);
  621. }
  622.  
  623. static void
  624. bumpmap_init_params (bumpmap_params_t *params)
  625. {
  626.   gdouble azimuth;
  627.   gdouble elevation;
  628.   gint    lz, nz;
  629.   gint    i;
  630.   gdouble n;
  631.  
  632.   /* Convert to radians */
  633.   azimuth   = G_PI * bmvals.azimuth / 180.0;
  634.   elevation = G_PI * bmvals.elevation / 180.0;
  635.  
  636.   /* Calculate the light vector */
  637.   params->lx = cos(azimuth) * cos(elevation) * 255.0;
  638.   params->ly = sin(azimuth) * cos(elevation) * 255.0;
  639.   lz         = sin(elevation) * 255.0;
  640.  
  641.   /* Calculate constant Z component of surface normal */
  642.   nz           = (6 * 255) / bmvals.depth;
  643.   params->nz2  = nz * nz;
  644.   params->nzlz = nz * lz;
  645.  
  646.   /* Optimize for vertical normals */
  647.   params->background = lz;
  648.  
  649.   /* Calculate darkness compensation factor */
  650.   params->compensation = sin(elevation);
  651.  
  652.   /* Create look-up table for map type */
  653.   for (i = 0; i < 256; i++)
  654.     {
  655.       switch (bmvals.type)
  656.     {
  657.     case SPHERICAL:
  658.       n = i / 255.0 - 1.0;
  659.       params->lut[i] = (int) (255.0 * sqrt(1.0 - n * n) + 0.5);
  660.       break;
  661.  
  662.     case SINUOSIDAL:
  663.       n = i / 255.0;
  664.       params->lut[i] = (int) (255.0 * (sin((-G_PI / 2.0) + G_PI * n) + 1.0) /
  665.                   2.0 + 0.5);
  666.       break;
  667.  
  668.     case LINEAR:
  669.     default:
  670.       params->lut[i] = i;
  671.     }
  672.  
  673.       if (bmvals.invert)
  674.     params->lut[i] = 255 - params->lut[i];
  675.     }
  676. }
  677.  
  678. static void
  679. bumpmap_row (guchar           *src,
  680.          guchar           *dest,
  681.          gint              width,
  682.          gint              bpp,
  683.          gint              has_alpha,
  684.          guchar           *bm_row1,
  685.          guchar           *bm_row2,
  686.          guchar           *bm_row3,
  687.          gint              bm_width,
  688.          gint              bm_xofs,
  689.          gboolean          tiled,
  690.          gboolean          row_in_bumpmap,       
  691.          bumpmap_params_t *params)
  692. {
  693.   gint xofs1, xofs2, xofs3;
  694.   gint shade;
  695.   gint ndotl;
  696.   gint nx, ny;
  697.   gint x, k;
  698.   gint pbpp;
  699.   gint result;
  700.   gint tmp;
  701.  
  702.   if (has_alpha)
  703.     pbpp = bpp - 1;
  704.   else
  705.     pbpp = bpp;
  706.  
  707.   tmp = bm_xofs + sel_x1;
  708.   if (tmp < 0)
  709.     xofs2 = bm_width - (- tmp % bm_width);
  710.   else
  711.     xofs2 = tmp % bm_width;
  712.  
  713.   xofs1 = (xofs2 + bm_width - 1) % bm_width;
  714.   xofs3 = (xofs2 + 1) % bm_width;
  715.  
  716.   for (x = 0; x < width; x++)
  717.     {
  718.       /* Calculate surface normal from bump map */
  719.  
  720.       if (tiled || (row_in_bumpmap &&
  721.             x == CLAMP (x, - tmp, - tmp + bm_width)))
  722.     {
  723.       nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] -
  724.         bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]);
  725.       ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] -
  726.         bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]);
  727.     }
  728.        else 
  729.      {
  730.        nx = ny = 0;
  731.      }
  732.  
  733.       /* Shade */
  734.  
  735.       if ((nx == 0) && (ny == 0))
  736.     shade = params->background;
  737.       else
  738.     {
  739.       ndotl = nx * params->lx + ny * params->ly + params->nzlz;
  740.  
  741.       if (ndotl < 0)
  742.         shade = params->compensation * bmvals.ambient;
  743.       else
  744.         {
  745.           shade = ndotl / sqrt(nx * nx + ny * ny + params->nz2);
  746.  
  747.           shade = shade + MAX(0, (255 * params->compensation - shade)) *
  748.         bmvals.ambient / 255;
  749.         }
  750.     }
  751.  
  752.       /* Paint */
  753.  
  754.       if (bmvals.compensate)
  755.     for (k = pbpp; k; k--)
  756.       {
  757.         result  = (*src++ * shade) / (params->compensation * 255);
  758.         *dest++ = MIN(255, result);
  759.       }
  760.       else
  761.     for (k = pbpp; k; k--)
  762.       *dest++ = *src++ * shade / 255;
  763.  
  764.       if (has_alpha)
  765.     *dest++ = *src++;
  766.  
  767.       /* Next pixel */
  768.  
  769.       if (++xofs1 == bm_width)
  770.     xofs1 = 0;
  771.  
  772.       if (++xofs2 == bm_width)
  773.     xofs2 = 0;
  774.  
  775.       if (++xofs3 == bm_width)
  776.     xofs3 = 0;
  777.     }
  778. }
  779.  
  780. static void
  781. bumpmap_convert_row (guchar *row, 
  782.              gint    width, 
  783.              gint    bpp, 
  784.              gint    has_alpha, 
  785.              guchar *lut)
  786. {
  787.   guchar *p;
  788.  
  789.   p = row;
  790.  
  791.   has_alpha = has_alpha ? 1 : 0;
  792.  
  793.   if (bpp >= 3)
  794.     for (; width; width--)
  795.       {
  796.     if (has_alpha)
  797.       *p++ = lut[(int) (bmvals.waterlevel +
  798.                 (((int) (INTENSITY (row[0], row[1], row[2]) + 0.5) - 
  799.                   bmvals.waterlevel) * 
  800.                  row[3]) / 255.0)];
  801.     else
  802.       *p++ = lut[(int) (INTENSITY (row[0], row[1], row[2]) + 0.5)];
  803.  
  804.     row += 3 + has_alpha;
  805.       }
  806.   else
  807.     for (; width; width--)
  808.       {
  809.     if (has_alpha)
  810.       *p++ = lut[bmvals.waterlevel +
  811.             ((row[0] - bmvals.waterlevel) * row[1]) / 255];
  812.     else
  813.       *p++ = lut[*row];
  814.  
  815.     row += 1 + has_alpha;
  816.       }
  817. }
  818.  
  819. static gint
  820. bumpmap_dialog (void)
  821. {
  822.   GtkWidget *dialog;
  823.   GtkWidget *top_vbox;
  824.   GtkWidget *hbox;
  825.   GtkWidget *frame;
  826.   GtkWidget *preview;
  827.   GtkWidget *vbox;
  828.   GtkWidget *sep;
  829.   GtkWidget *abox;
  830.   GtkWidget *pframe;
  831.   GtkWidget *ptable;
  832.   GtkWidget *scrollbar;
  833.   GtkWidget *table;
  834.   GtkWidget *right_vbox;
  835.   GtkWidget *option_menu;
  836.   GtkWidget *menu;
  837.   GtkWidget *button;
  838.   GtkObject *adj;
  839.   gint       i;
  840.   gint       row;
  841.  
  842.   gimp_ui_init ("bumpmap", TRUE);
  843.  
  844.   dialog = gimp_dialog_new (_("Bump Map"), "bumpmap",
  845.                 gimp_standard_help_func, "filters/bumpmap.html",
  846.                 GTK_WIN_POS_MOUSE,
  847.                 FALSE, TRUE, FALSE,
  848.  
  849.                 _("OK"), dialog_ok_callback,
  850.                 NULL, NULL, NULL, TRUE, FALSE,
  851.                 _("Cancel"), gtk_widget_destroy,
  852.                 NULL, 1, NULL, FALSE, TRUE,
  853.  
  854.                 NULL);
  855.  
  856.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  857.               GTK_SIGNAL_FUNC (gtk_main_quit),
  858.               NULL);
  859.  
  860.   top_vbox = gtk_vbox_new (FALSE, 4);
  861.   gtk_container_set_border_width (GTK_CONTAINER (top_vbox), 6);
  862.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_vbox,
  863.               FALSE, FALSE, 0);
  864.   gtk_widget_show (top_vbox);
  865.  
  866.   hbox = gtk_hbox_new (FALSE, 6);
  867.   gtk_box_pack_start (GTK_BOX (top_vbox), hbox, FALSE, FALSE, 0);
  868.   gtk_widget_show (hbox);
  869.  
  870.   /* Preview */
  871.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  872.   gtk_box_pack_start (GTK_BOX (hbox), abox, FALSE, FALSE, 0);
  873.   gtk_widget_show (abox);
  874.  
  875.   ptable = gtk_table_new (2, 2, FALSE);
  876.   gtk_container_set_border_width (GTK_CONTAINER (ptable), 4);
  877.   gtk_container_add (GTK_CONTAINER (abox), ptable);
  878.   gtk_widget_show (ptable);
  879.   
  880.   pframe = gtk_frame_new (NULL);
  881.   gtk_frame_set_shadow_type (GTK_FRAME (pframe), GTK_SHADOW_IN);
  882.   gtk_container_set_border_width (GTK_CONTAINER (pframe), 0);
  883.   gtk_table_attach (GTK_TABLE (ptable), pframe, 0, 1, 0, 1, 
  884.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  885.   gtk_widget_show (pframe);
  886.  
  887.   bmint.preview_width  = MIN (sel_width, PREVIEW_SIZE);
  888.   bmint.preview_height = MIN (sel_height, PREVIEW_SIZE);
  889.  
  890.   bmint.preview = preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  891.   gtk_preview_size (GTK_PREVIEW (bmint.preview),
  892.             bmint.preview_width, bmint.preview_height);
  893.   gtk_container_add (GTK_CONTAINER (pframe), bmint.preview);
  894.   gtk_widget_show (bmint.preview);
  895.   
  896.   bmint.preview_adj_x = 
  897.     gtk_adjustment_new (0, 0, sel_width, 1, 10, bmint.preview_width);
  898.   if (sel_width > PREVIEW_SIZE)
  899.     {
  900.       scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (bmint.preview_adj_x));
  901.       gtk_table_attach (GTK_TABLE (ptable), scrollbar, 0, 1, 1, 2, 
  902.             GTK_FILL | GTK_EXPAND, 0, 0, 0);
  903.       gtk_widget_show (scrollbar);
  904.     }
  905.   
  906.   bmint.preview_adj_y = 
  907.     gtk_adjustment_new (0, 0, sel_height, 1, 10, bmint.preview_height);
  908.   if (sel_height > PREVIEW_SIZE)
  909.     {
  910.       scrollbar = gtk_vscrollbar_new (GTK_ADJUSTMENT (bmint.preview_adj_y));
  911.       gtk_table_attach (GTK_TABLE (ptable), scrollbar, 1, 2, 0,1, 
  912.             0, GTK_FILL | GTK_EXPAND, 0, 0);
  913.       gtk_widget_show (scrollbar);
  914.     }
  915.  
  916.   gtk_widget_set_events (bmint.preview, 
  917.              GDK_BUTTON_PRESS_MASK |
  918.              GDK_BUTTON_RELEASE_MASK | 
  919.              GDK_BUTTON_MOTION_MASK |
  920.              GDK_POINTER_MOTION_HINT_MASK);
  921.   gtk_signal_connect (GTK_OBJECT (bmint.preview), "event",
  922.               (GtkSignalFunc) dialog_preview_events,
  923.               NULL);
  924.   gtk_signal_connect (GTK_OBJECT (bmint.preview_adj_x), "value_changed",
  925.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal), 
  926.               &bmint.preview_xofs);
  927.   gtk_signal_connect (GTK_OBJECT (bmint.preview_adj_y), "value_changed",
  928.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal), 
  929.               &bmint.preview_yofs);
  930.  
  931.   dialog_init_preview ();
  932.  
  933.   /* Type of map */
  934.   frame =
  935.     gimp_radio_group_new2 (TRUE, _("Map Type"),
  936.                dialog_map_type_callback,
  937.                &bmvals.type, (gpointer) bmvals.type,
  938.  
  939.                _("Linear Map"),     (gpointer) LINEAR, NULL,
  940.                _("Spherical Map"),  (gpointer) SPHERICAL, NULL,
  941.                _("Sinuosidal Map"), (gpointer) SINUOSIDAL, NULL,
  942.  
  943.                NULL);
  944.   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
  945.   gtk_widget_show (frame);
  946.  
  947.   right_vbox = GTK_BIN (frame)->child;
  948.  
  949.   sep = gtk_hseparator_new ();
  950.   gtk_box_pack_start (GTK_BOX (right_vbox), sep, FALSE, FALSE, 1);
  951.   gtk_widget_show (sep);
  952.  
  953.   /* Compensate darkening */
  954.   button = gtk_check_button_new_with_label (_("Compensate for Darkening"));
  955.   gtk_box_pack_start (GTK_BOX (right_vbox), button, FALSE, FALSE, 0);
  956.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  957.                 bmvals.compensate ? TRUE : FALSE);
  958.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  959.               GTK_SIGNAL_FUNC (dialog_compensate_callback),
  960.               NULL);
  961.   gtk_widget_show (button);
  962.  
  963.   /* Invert bumpmap */
  964.   button = gtk_check_button_new_with_label (_("Invert Bumpmap"));
  965.   gtk_box_pack_start (GTK_BOX (right_vbox), button, FALSE, FALSE, 0);
  966.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  967.                 bmvals.invert ? TRUE : FALSE);
  968.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  969.               GTK_SIGNAL_FUNC (dialog_invert_callback),
  970.               NULL);
  971.   gtk_widget_show (button);
  972.  
  973.   /* Tile bumpmap */
  974.   button = gtk_check_button_new_with_label (_("Tile Bumpmap"));
  975.   gtk_box_pack_start (GTK_BOX (right_vbox), button, FALSE, FALSE, 0);
  976.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  977.                 bmvals.tiled ? TRUE : FALSE);
  978.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  979.               GTK_SIGNAL_FUNC (dialog_tiled_callback),
  980.               NULL);
  981.   gtk_widget_show (button);  
  982.  
  983.   frame = gtk_frame_new (_("Parameter Settings"));
  984.   gtk_box_pack_start (GTK_BOX (top_vbox), frame, FALSE, FALSE, 0);
  985.   gtk_widget_show (frame);
  986.  
  987.   vbox = gtk_vbox_new (FALSE, 2);
  988.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  989.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  990.   gtk_widget_show (vbox);
  991.  
  992.   /* Bump map menu */
  993.   table = gtk_table_new (1, 2, FALSE);
  994.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  995.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  996.   gtk_widget_show (table);
  997.  
  998.   option_menu = gtk_option_menu_new ();
  999.   menu = gimp_drawable_menu_new (dialog_constrain,
  1000.                  dialog_bumpmap_callback,
  1001.                  NULL,
  1002.                  bmvals.bumpmap_id);
  1003.   gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
  1004.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  1005.                  _("Bump Map:"), 1.0, 0.5,
  1006.                  option_menu, 2, TRUE);
  1007.  
  1008.   sep = gtk_hseparator_new ();
  1009.   gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 0);
  1010.   gtk_widget_show (sep);
  1011.  
  1012.   /* Table for bottom controls */
  1013.  
  1014.   table = gtk_table_new (7, 3, FALSE);
  1015.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1016.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  1017.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  1018.   gtk_widget_show (table);
  1019.  
  1020.   /* Controls */
  1021.   row = 0;
  1022.  
  1023.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1024.                   _("Azimuth:"), SCALE_WIDTH, 0,
  1025.                   bmvals.azimuth, 0.0, 360.0, 1.0, 15.0, 2,
  1026.                   TRUE, 0, 0,
  1027.                   NULL, NULL);
  1028.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1029.               GTK_SIGNAL_FUNC (dialog_dscale_update),
  1030.               &bmvals.azimuth);
  1031.  
  1032.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1033.                   _("Elevation:"), SCALE_WIDTH, 0,
  1034.                   bmvals.elevation, 0.5, 90.0, 1.0, 5.0, 2,
  1035.                   TRUE, 0, 0,
  1036.                   NULL, NULL);
  1037.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1038.               GTK_SIGNAL_FUNC (dialog_dscale_update),
  1039.               &bmvals.elevation);
  1040.  
  1041.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
  1042.                   _("Depth:"), SCALE_WIDTH, 0,
  1043.                   bmvals.depth, 1.0, 65.0, 1.0, 5.0, 0,
  1044.                   TRUE, 0, 0,
  1045.                   NULL, NULL);
  1046.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1047.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal),
  1048.               &bmvals.depth);
  1049.   gtk_table_set_row_spacing (GTK_TABLE (table), row++, 8);
  1050.  
  1051.   bmint.offset_adj_x = adj = 
  1052.     gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1053.               _("X Offset:"), SCALE_WIDTH, 0,
  1054.               bmvals.xofs, -1000.0, 1001.0, 1.0, 10.0, 0,
  1055.               TRUE, 0, 0,
  1056.               NULL, NULL);
  1057.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1058.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal),
  1059.               &bmvals.xofs);
  1060.  
  1061.   bmint.offset_adj_y = adj = 
  1062.     gimp_scale_entry_new (GTK_TABLE (table), 0, row,
  1063.               _("Y Offset:"), SCALE_WIDTH, 0,
  1064.               bmvals.yofs, -1000.0, 1001.0, 1.0, 10.0, 0,
  1065.               TRUE, 0, 0,
  1066.               NULL, NULL);
  1067.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1068.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal),
  1069.               &bmvals.yofs);
  1070.   gtk_table_set_row_spacing (GTK_TABLE (table), row++, 8);
  1071.  
  1072.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1073.                   _("Waterlevel:"), SCALE_WIDTH, 0,
  1074.                   bmvals.waterlevel, 0.0, 255.0, 1.0, 8.0, 0,
  1075.                   TRUE, 0, 0,
  1076.                   NULL, NULL);
  1077.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1078.               GTK_SIGNAL_FUNC (dialog_iscale_update_full),
  1079.               &bmvals.waterlevel);
  1080.  
  1081.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1082.                   _("Ambient:"), SCALE_WIDTH, 0,
  1083.                   bmvals.ambient, 0.0, 255.0, 1.0, 8.0, 0,
  1084.                   TRUE, 0, 0,
  1085.                   NULL, NULL);
  1086.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1087.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal),
  1088.               &bmvals.ambient);
  1089.  
  1090.   /* Done */
  1091.  
  1092.   gtk_widget_show (dialog);
  1093.  
  1094.   gtk_main ();
  1095.   gdk_flush ();
  1096.  
  1097.   g_free (bmint.check_row_0);
  1098.   g_free (bmint.check_row_1);
  1099.  
  1100.   for (i = 0; i < bmint.preview_height; i++)
  1101.     g_free (bmint.src_rows[i]);
  1102.  
  1103.   g_free (bmint.src_rows);
  1104.  
  1105.   for (i = 0; i < (bmint.preview_height + 2); i++)
  1106.     g_free (bmint.bm_rows[i]);
  1107.  
  1108.   g_free (bmint.bm_rows);
  1109.  
  1110.   if (bmint.bm_drawable != drawable)
  1111.     gimp_drawable_detach (bmint.bm_drawable);
  1112.  
  1113.   return bmint.run;
  1114. }
  1115.  
  1116. static void
  1117. dialog_init_preview (void)
  1118. {
  1119.   gint x;
  1120.     
  1121.   /* Create checkerboard rows */
  1122.  
  1123.   bmint.check_row_0 = g_new (guchar, bmint.preview_width);
  1124.   bmint.check_row_1 = g_new (guchar, bmint.preview_width);
  1125.  
  1126.   for (x = 0; x < bmint.preview_width; x++)
  1127.     if ((x / GIMP_CHECK_SIZE) & 1)
  1128.       {
  1129.     bmint.check_row_0[x] = GIMP_CHECK_DARK  * 255;
  1130.     bmint.check_row_1[x] = GIMP_CHECK_LIGHT * 255;
  1131.       }
  1132.     else
  1133.       {
  1134.     bmint.check_row_0[x] = GIMP_CHECK_LIGHT * 255;
  1135.     bmint.check_row_1[x] = GIMP_CHECK_DARK  * 255;
  1136.       }
  1137.  
  1138.   /* Initialize source rows */
  1139.  
  1140.   gimp_pixel_rgn_init (&bmint.src_rgn, drawable,
  1141.                sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE);
  1142.  
  1143.   bmint.src_rows = g_new (guchar *, bmint.preview_height);
  1144.  
  1145.   for (x = 0; x < bmint.preview_height; x++)
  1146.     bmint.src_rows[x]  = g_new (guchar, sel_width * 4);
  1147.  
  1148.   dialog_fill_src_rows (0,
  1149.             bmint.preview_height,
  1150.             sel_y1 + bmint.preview_yofs);
  1151.  
  1152.   /* Initialize bumpmap rows */
  1153.  
  1154.   bmint.bm_rows = g_new (guchar *, bmint.preview_height + 2);
  1155.  
  1156.   for (x = 0; x < (bmint.preview_height + 2); x++)
  1157.     bmint.bm_rows[x] = NULL;
  1158. }
  1159.  
  1160. static gint
  1161. dialog_preview_events (GtkWidget *widget, 
  1162.                GdkEvent  *event)
  1163. {
  1164.   gint            x, y;
  1165.   gint            dx, dy;
  1166.   GdkEventButton *bevent;
  1167.     
  1168.   gtk_widget_get_pointer (widget, &x, &y);
  1169.  
  1170.   bevent = (GdkEventButton *) event;
  1171.  
  1172.   switch (event->type)
  1173.     {
  1174.     case GDK_BUTTON_PRESS:
  1175.       switch (bevent->button)
  1176.     {
  1177.     case 1:
  1178.     case 2:  
  1179.       if (bevent->state & GDK_SHIFT_MASK)
  1180.         bmint.drag_mode = DRAG_BUMPMAP;
  1181.       else
  1182.         bmint.drag_mode = DRAG_SCROLL;
  1183.       break;
  1184.  
  1185.     case 3:
  1186.       bmint.drag_mode = DRAG_BUMPMAP;
  1187.       break;
  1188.  
  1189.     default:
  1190.       return FALSE;
  1191.     }
  1192.  
  1193.       bmint.mouse_x = x;
  1194.       bmint.mouse_y = y;
  1195.  
  1196.       gtk_grab_add (widget);
  1197.  
  1198.       break;
  1199.  
  1200.     case GDK_BUTTON_RELEASE:
  1201.       if (bmint.drag_mode != DRAG_NONE)
  1202.     {
  1203.       gtk_grab_remove (widget);
  1204.       bmint.drag_mode = DRAG_NONE;
  1205.       dialog_update_preview ();
  1206.     }
  1207.  
  1208.       break;
  1209.  
  1210.     case GDK_MOTION_NOTIFY:
  1211.       dx = x - bmint.mouse_x;
  1212.       dy = y - bmint.mouse_y;
  1213.  
  1214.       bmint.mouse_x = x;
  1215.       bmint.mouse_y = y;
  1216.  
  1217.       if ((dx == 0) && (dy == 0))
  1218.     break;
  1219.  
  1220.       switch (bmint.drag_mode)
  1221.     {
  1222.     case DRAG_SCROLL:
  1223.       bmint.preview_xofs = CLAMP (bmint.preview_xofs - dx,
  1224.                       0,
  1225.                       sel_width - bmint.preview_width);
  1226.       gtk_signal_handler_block_by_data (GTK_OBJECT (bmint.preview_adj_x), 
  1227.                         &bmint.preview_xofs);
  1228.       gtk_adjustment_set_value (GTK_ADJUSTMENT (bmint.preview_adj_x), 
  1229.                     bmint.preview_xofs);
  1230.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (bmint.preview_adj_x), 
  1231.                           &bmint.preview_xofs);
  1232.       bmint.preview_yofs = CLAMP (bmint.preview_yofs - dy,
  1233.                       0,
  1234.                       sel_height - bmint.preview_height);
  1235.       gtk_signal_handler_block_by_data (GTK_OBJECT (bmint.preview_adj_y), 
  1236.                         &bmint.preview_yofs);
  1237.       gtk_adjustment_set_value (GTK_ADJUSTMENT (bmint.preview_adj_y), 
  1238.                     bmint.preview_yofs);
  1239.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (bmint.preview_adj_y), 
  1240.                           &bmint.preview_yofs);
  1241.       
  1242.       break;
  1243.  
  1244.     case DRAG_BUMPMAP:
  1245.       bmvals.xofs = CLAMP (bmvals.xofs - dx, -1000, 1000);
  1246.       gtk_signal_handler_block_by_data (GTK_OBJECT (bmint.offset_adj_x), 
  1247.                         &bmvals.xofs);
  1248.       gtk_adjustment_set_value (GTK_ADJUSTMENT (bmint.offset_adj_x), 
  1249.                     bmvals.xofs);
  1250.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (bmint.offset_adj_x), 
  1251.                           &bmvals.xofs);
  1252.  
  1253.       bmvals.yofs = CLAMP (bmvals.yofs - dy, -1000, 1000);
  1254.       gtk_signal_handler_block_by_data (GTK_OBJECT (bmint.offset_adj_y), 
  1255.                         &bmvals.yofs);
  1256.       gtk_adjustment_set_value (GTK_ADJUSTMENT (bmint.offset_adj_y), 
  1257.                     bmvals.yofs);
  1258.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (bmint.offset_adj_y), 
  1259.                           &bmvals.yofs);
  1260.  
  1261.       break;
  1262.  
  1263.     default:
  1264.       return FALSE;
  1265.     }
  1266.  
  1267.       dialog_update_preview ();
  1268.  
  1269.       break; 
  1270.  
  1271.     default:
  1272.       break;
  1273.     }
  1274.  
  1275.   return FALSE;
  1276. }
  1277.  
  1278. static void
  1279. dialog_new_bumpmap (gboolean init_offsets)
  1280. {
  1281.   GtkAdjustment   *adj;
  1282.   gint             i;
  1283.   gint             yofs;
  1284.   gint             bump_offset_x;
  1285.   gint             bump_offset_y;
  1286.   gint             draw_offset_y;
  1287.   gint             draw_offset_x;
  1288.  
  1289.   /* Get drawable */
  1290.   if (bmint.bm_drawable && (bmint.bm_drawable != drawable))
  1291.     gimp_drawable_detach (bmint.bm_drawable);
  1292.  
  1293.   if (bmvals.bumpmap_id != -1)
  1294.     bmint.bm_drawable = gimp_drawable_get (bmvals.bumpmap_id);
  1295.   else
  1296.     bmint.bm_drawable = drawable;
  1297.  
  1298.   if (!bmint.bm_drawable)
  1299.     return;
  1300.  
  1301.   /* Get sizes */
  1302.   bmint.bm_width     = gimp_drawable_width (bmint.bm_drawable->id);
  1303.   bmint.bm_height    = gimp_drawable_height (bmint.bm_drawable->id);
  1304.   bmint.bm_bpp       = gimp_drawable_bpp (bmint.bm_drawable->id);
  1305.   bmint.bm_has_alpha = gimp_drawable_has_alpha (bmint.bm_drawable->id);
  1306.  
  1307.   if (init_offsets)
  1308.     {      
  1309.       gimp_drawable_offsets (bmint.bm_drawable->id, &bump_offset_x, &bump_offset_y);
  1310.       gimp_drawable_offsets (drawable->id, &draw_offset_x, &draw_offset_y);
  1311.       
  1312.       bmvals.xofs = draw_offset_x - bump_offset_x;
  1313.       bmvals.yofs = draw_offset_y - bump_offset_y;
  1314.     }
  1315.  
  1316.   adj = (GtkAdjustment *) bmint.offset_adj_x;
  1317.   if (adj)
  1318.     {
  1319.       adj->value = bmvals.xofs;
  1320.       gtk_signal_handler_block_by_data (GTK_OBJECT (adj), &bmvals.xofs);
  1321.       gtk_adjustment_value_changed (adj);
  1322.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), &bmvals.xofs);
  1323.     }
  1324.   
  1325.   adj = (GtkAdjustment *) bmint.offset_adj_y;
  1326.   if (adj)
  1327.     {
  1328.       adj->value = bmvals.yofs;
  1329.       gtk_signal_handler_block_by_data (GTK_OBJECT (adj), &bmvals.yofs);
  1330.       gtk_adjustment_value_changed (adj);
  1331.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), &bmvals.yofs);
  1332.     }
  1333.   
  1334.   /* Initialize pixel region */
  1335.  
  1336.   gimp_pixel_rgn_init (&bmint.bm_rgn, bmint.bm_drawable,
  1337.                0, 0, bmint.bm_width, bmint.bm_height, FALSE, FALSE);
  1338.  
  1339.   /* Initialize row buffers */
  1340.  
  1341.   yofs = bmvals.yofs + bmint.preview_yofs - 1; /* Minus 1 for conv. matrix */
  1342.  
  1343.   if (yofs < 0)
  1344.     yofs = bmint.bm_height - (-yofs % bmint.bm_height);
  1345.   else
  1346.     yofs = yofs % bmint.bm_height;
  1347.  
  1348.   bmint.bm_yofs = yofs;
  1349.  
  1350.   for (i = 0; i < (bmint.preview_height + 2); i++)
  1351.     {
  1352.       if (bmint.bm_rows[i])
  1353.     g_free (bmint.bm_rows[i]);
  1354.  
  1355.       bmint.bm_rows[i] = g_new (guchar, bmint.bm_width * bmint.bm_bpp);
  1356.     }
  1357.  
  1358.   bumpmap_init_params (&bmint.params);
  1359.   dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, yofs);
  1360. }
  1361.  
  1362. static void
  1363. dialog_update_preview (void)
  1364. {
  1365.   static guchar dest_row[PREVIEW_SIZE * 4];
  1366.   static guchar preview_row[PREVIEW_SIZE * 3];
  1367.  
  1368.   guchar *check_row;
  1369.   guchar  check;
  1370.   gint    xofs;
  1371.   gint    x, y;
  1372.   guchar *sp, *p;
  1373.  
  1374.   bumpmap_init_params (&bmint.params);
  1375.  
  1376.   /* Scroll the row buffers */
  1377.  
  1378.   dialog_scroll_src ();
  1379.   dialog_scroll_bumpmap ();
  1380.  
  1381.   /* Bumpmap */
  1382.  
  1383.   xofs = bmint.preview_xofs;
  1384.  
  1385.   for (y = 0; y < bmint.preview_height; y++)
  1386.     {
  1387.       bumpmap_row (bmint.src_rows[y] + 4 * xofs, dest_row,
  1388.            bmint.preview_width, 4, TRUE,
  1389.            bmint.bm_rows[y], 
  1390.            bmint.bm_rows[y + 1],
  1391.            bmint.bm_rows[y + 2],
  1392.            bmint.bm_width, xofs + bmvals.xofs,
  1393.            bmvals.tiled, 
  1394.            y == CLAMP (y, 
  1395.                    - bmvals.yofs - bmint.preview_yofs - sel_y1 ,
  1396.                    - bmvals.yofs - bmint.preview_yofs - sel_y1 + bmint.bm_height),
  1397.            &bmint.params);
  1398.  
  1399.       /* Paint row */
  1400.  
  1401.       sp = dest_row;
  1402.       p  = preview_row;
  1403.  
  1404.       if ((y / GIMP_CHECK_SIZE) & 1)
  1405.     check_row = bmint.check_row_0;
  1406.       else
  1407.     check_row = bmint.check_row_1;
  1408.  
  1409.       for (x = 0; x < bmint.preview_width; x++)
  1410.     {
  1411.       check = check_row[x];
  1412.  
  1413.       p[0] = check + ((sp[0] - check) * sp[3]) / 255;
  1414.       p[1] = check + ((sp[1] - check) * sp[3]) / 255;
  1415.       p[2] = check + ((sp[2] - check) * sp[3]) / 255;
  1416.  
  1417.       sp += 4;
  1418.       p  += 3;
  1419.     }
  1420.  
  1421.       gtk_preview_draw_row (GTK_PREVIEW(bmint.preview),
  1422.                 preview_row, 0, y, bmint.preview_width);
  1423.     }
  1424.  
  1425.   gtk_widget_draw (bmint.preview, NULL);
  1426.   gdk_flush ();
  1427. }
  1428.  
  1429. #define SWAP_ROWS(a, b, t) { t = a; a = b; b = t; }
  1430.  
  1431. static void
  1432. dialog_scroll_src (void)
  1433. {
  1434.   gint    yofs;
  1435.   gint    y, ofs;
  1436.   guchar *tmp;
  1437.  
  1438.   yofs = bmint.preview_yofs;
  1439.  
  1440.   if (yofs == bmint.src_yofs)
  1441.     return;
  1442.  
  1443.   if (yofs < bmint.src_yofs)
  1444.     {
  1445.       ofs = bmint.src_yofs - yofs;
  1446.  
  1447.       /* Scroll useful rows... */
  1448.  
  1449.       if (ofs < bmint.preview_height)
  1450.     for (y = (bmint.preview_height - 1); y >= ofs; y--)
  1451.       SWAP_ROWS (bmint.src_rows[y], bmint.src_rows[y - ofs], tmp);
  1452.  
  1453.       /* ... and get the new ones */
  1454.  
  1455.       dialog_fill_src_rows (0, MIN (ofs, bmint.preview_height), sel_y1 + yofs);
  1456.     }
  1457.   else
  1458.     {
  1459.       ofs = yofs - bmint.src_yofs;
  1460.  
  1461.       /* Scroll useful rows... */
  1462.  
  1463.       if (ofs < bmint.preview_height)
  1464.     for (y = 0; y < (bmint.preview_height - ofs); y++)
  1465.       SWAP_ROWS (bmint.src_rows[y], bmint.src_rows[y + ofs], tmp);
  1466.  
  1467.       /* ... and get the new ones */
  1468.  
  1469.       dialog_fill_src_rows ((bmint.preview_height -
  1470.                  MIN (ofs, bmint.preview_height)),
  1471.                 MIN (ofs, bmint.preview_height),
  1472.                 (sel_y1 + yofs + bmint.preview_height -
  1473.                  MIN (ofs, bmint.preview_height)));
  1474.     }
  1475.  
  1476.   bmint.src_yofs = yofs;
  1477. }
  1478.  
  1479. static void
  1480. dialog_scroll_bumpmap (void)
  1481. {
  1482.   gint    yofs;
  1483.   gint    y, ofs;
  1484.   guchar *tmp;
  1485.  
  1486.   yofs = bmvals.yofs + bmint.preview_yofs - 1; /* Minus 1 for conv. matrix */
  1487.  
  1488.   if (yofs < 0)
  1489.     yofs = bmint.bm_height - (-yofs % bmint.bm_height);
  1490.   else
  1491.     yofs %= bmint.bm_height;
  1492.  
  1493.   if (yofs == bmint.bm_yofs)
  1494.     return;
  1495.  
  1496.   if (yofs < bmint.bm_yofs)
  1497.     {
  1498.       ofs = bmint.bm_yofs - yofs;
  1499.  
  1500.       /* Scroll useful rows... */
  1501.  
  1502.       if (ofs < (bmint.preview_height + 2))
  1503.     for (y = (bmint.preview_height + 1); y >= ofs; y--)
  1504.       SWAP_ROWS (bmint.bm_rows[y], bmint.bm_rows[y - ofs], tmp);
  1505.  
  1506.       /* ... and get the new ones */
  1507.  
  1508.       dialog_fill_bumpmap_rows (0,
  1509.                 MIN (ofs, bmint.preview_height + 2),
  1510.                 yofs);
  1511.     }
  1512.   else
  1513.     {
  1514.       ofs = yofs - bmint.bm_yofs;
  1515.  
  1516.       /* Scroll useful rows... */
  1517.  
  1518.       if (ofs < (bmint.preview_height + 2))
  1519.     for (y = 0; y < (bmint.preview_height + 2 - ofs); y++)
  1520.       SWAP_ROWS (bmint.bm_rows[y], bmint.bm_rows[y + ofs], tmp);
  1521.  
  1522.       /* ... and get the new ones */
  1523.  
  1524.       dialog_fill_bumpmap_rows ((bmint.preview_height + 2 -
  1525.                  MIN (ofs, bmint.preview_height + 2)),
  1526.                 MIN (ofs, bmint.preview_height + 2),
  1527.                 (yofs + bmint.preview_height + 2 -
  1528.                  MIN (ofs, bmint.preview_height + 2)) %
  1529.                 bmint.bm_height);
  1530.     }
  1531.  
  1532.   bmint.bm_yofs = yofs;
  1533. }
  1534.  
  1535. static void
  1536. dialog_get_rows (GimpPixelRgn  *pr, 
  1537.          guchar    **rows, 
  1538.          gint        x, 
  1539.          gint        y, 
  1540.          gint        width, 
  1541.          gint        height)
  1542. {
  1543.   /* This is shamelessly ripped off from gimp_pixel_rgn_get_rect().
  1544.    * Its function is exactly the same, but it can fetch an image
  1545.    * rectangle to a sparse buffer which is defined as separate
  1546.    * rows instead of one big linear region.
  1547.    */
  1548.  
  1549.   GimpTile  *tile;
  1550.   guchar *src, *dest;
  1551.   gint    xstart, ystart;
  1552.   gint    xend, yend;
  1553.   gint    xboundary;
  1554.   gint    yboundary;
  1555.   gint    xstep, ystep;
  1556.   gint    b, bpp;
  1557.   gint    tx, ty;
  1558.   gint    tile_width, tile_height;
  1559.  
  1560.   tile_width  = gimp_tile_width();
  1561.   tile_height = gimp_tile_height();
  1562.  
  1563.   bpp = pr->bpp;
  1564.  
  1565.   xstart = x;
  1566.   ystart = y;
  1567.   xend   = x + width;
  1568.   yend   = y + height;
  1569.   ystep  = 0; /* Shut up -Wall */
  1570.  
  1571.   while (y < yend)
  1572.     {
  1573.       x = xstart;
  1574.  
  1575.       while (x < xend)
  1576.     {
  1577.       tile = gimp_drawable_get_tile2 (pr->drawable, pr->shadow, x, y);
  1578.       gimp_tile_ref (tile);
  1579.  
  1580.       xstep     = tile->ewidth - (x % tile_width);
  1581.       ystep     = tile->eheight - (y % tile_height);
  1582.       xboundary = x + xstep;
  1583.       yboundary = y + ystep;
  1584.       xboundary = MIN (xboundary, xend);
  1585.       yboundary = MIN (yboundary, yend);
  1586.  
  1587.       for (ty = y; ty < yboundary; ty++)
  1588.         {
  1589.           src  = tile->data + tile->bpp * (tile->ewidth * (ty % tile_height) +
  1590.                            (x % tile_width));
  1591.           dest = rows[ty - ystart] + bpp * (x - xstart);
  1592.  
  1593.           for (tx = x; tx < xboundary; tx++)
  1594.         for (b = bpp; b; b--)
  1595.           *dest++ = *src++;
  1596.         }
  1597.  
  1598.       gimp_tile_unref (tile, FALSE);
  1599.  
  1600.       x += xstep;
  1601.     }
  1602.  
  1603.       y += ystep;
  1604.     }
  1605. }
  1606.  
  1607. static void
  1608. dialog_fill_src_rows (gint start, 
  1609.               gint how_many, 
  1610.               gint yofs)
  1611. {
  1612.   gint    x;
  1613.   gint    y;
  1614.   guchar *sp;
  1615.   guchar *p;
  1616.  
  1617.   dialog_get_rows (&bmint.src_rgn,
  1618.            bmint.src_rows + start,
  1619.            sel_x1,
  1620.            yofs,
  1621.            sel_width,
  1622.            how_many);
  1623.  
  1624.   /* Convert to RGBA.  We move backwards! */
  1625.  
  1626.   for (y = start; y < (start + how_many); y++)
  1627.     {
  1628.       sp = bmint.src_rows[y] + img_bpp * sel_width - 1;
  1629.       p  = bmint.src_rows[y] + 4 * sel_width - 1;
  1630.  
  1631.       for (x = 0; x < sel_width; x++)
  1632.     {
  1633.       if (img_has_alpha)
  1634.         *p-- = *sp--;
  1635.       else
  1636.         *p-- = 255;
  1637.  
  1638.       if (img_bpp < 3)
  1639.         {
  1640.           *p-- = *sp;
  1641.           *p-- = *sp;
  1642.           *p-- = *sp--;
  1643.         }
  1644.       else
  1645.         {
  1646.           *p-- = *sp--;
  1647.           *p-- = *sp--;
  1648.           *p-- = *sp--;
  1649.         }
  1650.     }
  1651.     }
  1652. }
  1653.  
  1654. static void
  1655. dialog_fill_bumpmap_rows (gint start, 
  1656.               gint how_many, 
  1657.               gint yofs)
  1658. {
  1659.   gint buf_row_ofs;
  1660.   gint remaining;
  1661.   gint this_pass;
  1662.  
  1663.   /* Adapt to offset of selection */
  1664.   yofs += sel_y1;
  1665.   if (yofs < 0)
  1666.     yofs = bmint.bm_height - (-yofs % bmint.bm_height);
  1667.   else
  1668.     yofs %= bmint.bm_height;
  1669.  
  1670.   buf_row_ofs = start;
  1671.   remaining   = how_many;
  1672.  
  1673.   while (remaining > 0)
  1674.     {
  1675.       this_pass = MIN (remaining, bmint.bm_height - yofs);
  1676.  
  1677.       dialog_get_rows (&bmint.bm_rgn,
  1678.                bmint.bm_rows + buf_row_ofs,
  1679.                0,
  1680.                yofs,
  1681.                bmint.bm_width,
  1682.                this_pass);
  1683.  
  1684.       yofs         = (yofs + this_pass) % bmint.bm_height;
  1685.       remaining   -= this_pass;
  1686.       buf_row_ofs += this_pass;
  1687.     }
  1688.  
  1689.   /* Convert rows */
  1690.  
  1691.   for (; how_many; how_many--)
  1692.     {
  1693.       bumpmap_convert_row (bmint.bm_rows[start],
  1694.                bmint.bm_width,
  1695.                bmint.bm_bpp,
  1696.                bmint.bm_has_alpha,
  1697.                bmint.params.lut);
  1698.  
  1699.       start++;
  1700.     }
  1701. }
  1702.  
  1703. static void
  1704. dialog_compensate_callback (GtkWidget *widget, 
  1705.                 gpointer   data)
  1706. {
  1707.   bmvals.compensate = GTK_TOGGLE_BUTTON (widget)->active;
  1708.  
  1709.   dialog_update_preview ();
  1710. }
  1711.  
  1712. static void
  1713. dialog_invert_callback (GtkWidget *widget, 
  1714.             gpointer   data)
  1715. {
  1716.   bmvals.invert = GTK_TOGGLE_BUTTON (widget)->active;
  1717.  
  1718.   bumpmap_init_params (&bmint.params);
  1719.   dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, bmint.bm_yofs);
  1720.   dialog_update_preview ();
  1721. }
  1722.  
  1723. static void
  1724. dialog_tiled_callback (GtkWidget *widget, 
  1725.             gpointer   data)
  1726. {
  1727.   bmvals.tiled = GTK_TOGGLE_BUTTON (widget)->active;
  1728.  
  1729.   bumpmap_init_params (&bmint.params);
  1730.   dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, bmint.bm_yofs);
  1731.   dialog_update_preview ();
  1732. }
  1733.  
  1734. static void
  1735. dialog_map_type_callback (GtkWidget *widget, 
  1736.               gpointer   data)
  1737. {
  1738.   gimp_radio_button_update (widget, data);
  1739.  
  1740.   if (GTK_TOGGLE_BUTTON (widget)->active)
  1741.     {
  1742.       bumpmap_init_params (&bmint.params);
  1743.       dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, bmint.bm_yofs);
  1744.       dialog_update_preview ();
  1745.     }
  1746. }
  1747.  
  1748. static gint
  1749. dialog_constrain (gint32   image_id, 
  1750.           gint32   drawable_id, 
  1751.           gpointer data)
  1752. {
  1753.   if (drawable_id == -1)
  1754.     return TRUE;
  1755.  
  1756.   return (gimp_drawable_is_rgb (drawable_id) ||
  1757.       gimp_drawable_is_gray (drawable_id));
  1758. }
  1759.  
  1760. static void
  1761. dialog_bumpmap_callback (gint32   id, 
  1762.              gpointer data)
  1763. {
  1764.   if (bmvals.bumpmap_id == id)
  1765.     {
  1766.       dialog_new_bumpmap (FALSE);
  1767.     }
  1768.   else
  1769.     {
  1770.       bmvals.bumpmap_id = id;
  1771.       dialog_new_bumpmap (TRUE);
  1772.     }
  1773.   dialog_update_preview ();
  1774. }
  1775.  
  1776. static void
  1777. dialog_dscale_update (GtkAdjustment *adjustment, 
  1778.               gdouble       *value)
  1779. {
  1780.   gimp_double_adjustment_update (adjustment, value);
  1781.  
  1782.   dialog_update_preview ();
  1783. }
  1784.  
  1785. static void
  1786. dialog_iscale_update_normal (GtkAdjustment *adjustment, 
  1787.                  gint          *value)
  1788. {
  1789.   gimp_int_adjustment_update (adjustment, value);
  1790.  
  1791.   dialog_update_preview ();
  1792. }
  1793.  
  1794. static void
  1795. dialog_iscale_update_full (GtkAdjustment *adjustment, 
  1796.                gint          *value)
  1797. {
  1798.   gimp_int_adjustment_update (adjustment, value);
  1799.  
  1800.   bumpmap_init_params (&bmint.params);
  1801.   dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, bmint.bm_yofs);
  1802.   dialog_update_preview ();
  1803. }
  1804.  
  1805. static void
  1806. dialog_ok_callback (GtkWidget *widget, 
  1807.             gpointer   data)
  1808. {
  1809.   bmint.run = TRUE;
  1810.  
  1811.   gtk_widget_destroy (GTK_WIDGET (data));
  1812. }
  1813.