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 / jigsaw.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-01  |  77.0 KB  |  2,807 lines

  1. /*
  2.  * jigsaw - a plug-in for the GIMP
  3.  *
  4.  * Copyright (C) Nigel Wetten
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  *
  20.  * Contact info: nigel@cs.nwu.edu
  21.  *
  22.  * Version: 1.0.0
  23.  *
  24.  * Version: 1.0.1
  25.  *
  26.  * tim coppefield [timecop@japan.co.jp]
  27.  *
  28.  * Added dynamic preview mode.
  29.  *
  30.  * Damn, this plugin is the tightest piece of code I ever seen.
  31.  * I wish all filters in the plugins operated on guchar *buffer
  32.  * of the entire image :) sweet stuff.
  33.  *
  34.  */
  35.  
  36. #include "config.h"
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41.  
  42. #include <gtk/gtk.h>
  43.  
  44. #include <libgimp/gimp.h>
  45. #include <libgimp/gimpui.h>
  46.  
  47. #include "libgimp/stdplugins-intl.h"
  48.  
  49.  
  50. #define PREVIEW_SIZE    128 
  51.  
  52.  
  53. typedef enum 
  54. {
  55.   BEZIER_1, 
  56.   BEZIER_2
  57. } style_t;
  58.  
  59. typedef enum 
  60. {
  61.   LEFT, 
  62.   RIGHT, 
  63.   UP, 
  64.   DOWN
  65. } bump_t;
  66.  
  67.  
  68. static void query (void);
  69. static void run   (gchar   *name,
  70.            gint     nparams,
  71.            GimpParam  *param,
  72.            gint    *nreturn_vals,
  73.            GimpParam **return_vals);
  74.  
  75. static gint jigsaw     (gboolean preview_mode);
  76.  
  77. static void  jigsaw_radio_button_update (GtkWidget *widget, gpointer data);
  78. static void  dialog_box (void);
  79. static void  fill_preview_with_thumb (GtkWidget *preview_widget, 
  80.                       gint32     drawable_ID);
  81. static GtkWidget *preview_widget  (GimpDrawable *drawable);
  82.  
  83. static void run_callback          (GtkWidget *widget, gpointer   data);
  84. static void check_button_callback (GtkWidget *widget, gpointer   data);
  85.  
  86. static void draw_jigsaw           (guchar    *buffer, 
  87.                    gint       width, 
  88.                    gint       height, 
  89.                    gint       bytes, 
  90.                    gboolean   preview_mode);
  91.  
  92. static void draw_vertical_border   (guchar *buffer, gint width, gint height,
  93.                     gint bytes, gint x_offset, gint ytiles,
  94.                     gint blend_lines, gdouble blend_amount,
  95.                     gboolean   preview_mode);
  96. static void draw_horizontal_border (guchar *buffer, gint width,
  97.                     gint bytes, gint y_offset, gint xtiles,
  98.                     gint blend_lines, gdouble blend_amount,
  99.                     gboolean   preview_mode);
  100. static void draw_vertical_line     (guchar *buffer, gint width, gint bytes,
  101.                     gint px[2], gint py[2],
  102.                     gboolean   preview_mode);
  103. static void draw_horizontal_line   (guchar *buffer, gint width, gint bytes,
  104.                     gint px[2], gint py[2], 
  105.                     gboolean   preview_mode);
  106. static void darken_vertical_line   (guchar *buffer, gint width, gint bytes,
  107.                     gint *px, gint *py, gdouble delta,
  108.                     gboolean   preview_mode);
  109. static void lighten_vertical_line  (guchar *buffer, gint width, gint bytes,
  110.                     gint *px, gint *py, gdouble delta,
  111.                     gboolean   preview_mode);
  112. static void darken_horizontal_line (guchar *buffer, gint width, gint bytes,
  113.                     gint *px, gint *py, gdouble delta,
  114.                     gboolean   preview_mode);
  115. static void lighten_horizontal_line(guchar *buffer, gint width, gint bytes,
  116.                     gint *px, gint *py, gdouble delta,
  117.                     gboolean   preview_mode);
  118. static void draw_right_bump        (guchar *buffer, gint width, gint bytes,
  119.                     gint x_offset, gint curve_start_offset,
  120.                     gint steps, gboolean   preview_mode);
  121. static void draw_left_bump         (guchar *buffer, gint width, gint bytes,
  122.                     gint x_offset, gint curve_start_offset,
  123.                     gint steps, gboolean   preview_mode);
  124. static void draw_up_bump           (guchar *buffer, gint width, gint bytes,
  125.                     gint y_offset, gint curve_start_offset,
  126.                     gint steps, gboolean   preview_mode);
  127. static void draw_down_bump         (guchar *buffer, gint width, gint bytes,
  128.                     gint y_offset, gint curve_start_offset,
  129.                     gint steps, gboolean   preview_mode);
  130. static void darken_right_bump      (guchar *buffer, gint width, gint bytes,
  131.                     gint x_offset, gint curve_start_offset,
  132.                     gint steps, gdouble delta, gint counter,
  133.                     gboolean   preview_mode);
  134. static void lighten_right_bump     (guchar *buffer, gint width, gint bytes,
  135.                     gint x_offset, gint curve_start_offset,
  136.                     gint steps, gdouble delta, gint counter,
  137.                     gboolean   preview_mode);
  138. static void darken_left_bump       (guchar *buffer, gint width, gint bytes,
  139.                     gint x_offset, gint curve_start_offset,
  140.                     gint steps, gdouble delta, gint counter,
  141.                     gboolean   preview_mode);
  142. static void lighten_left_bump      (guchar *buffer, gint width, gint bytes,
  143.                     gint x_offset, gint curve_start_offset,
  144.                     gint steps, gdouble delta, gint counter,
  145.                     gboolean   preview_mode);
  146. static void darken_up_bump         (guchar *buffer, gint width, gint bytes,
  147.                     gint y_offset, gint curve_start_offest,
  148.                     gint steps, gdouble delta, gint counter,
  149.                     gboolean   preview_mode);
  150. static void lighten_up_bump        (guchar *buffer, gint width, gint bytes,
  151.                     gint y_offset, gint curve_start_offset,
  152.                     gint steps, gdouble delta, gint counter,
  153.                     gboolean   preview_mode);
  154. static void darken_down_bump       (guchar *buffer, gint width, gint bytes,
  155.                     gint y_offset, gint curve_start_offset,
  156.                     gint steps, gdouble delta, gint counter,
  157.                     gboolean   preview_mode);
  158. static void lighten_down_bump      (guchar *buffer, gint width, gint bytes,
  159.                     gint y_offset, gint curve_start_offset,
  160.                     gint steps, gdouble delta, gint counter,
  161.                     gboolean   preview_mode);
  162. static void generate_grid          (gint width, gint height, gint xtiles, gint ytiles,
  163.                     gint *x, gint *y);
  164. static void generate_bezier        (gint px[4], gint py[4], gint steps,
  165.                     gint *cachex, gint *cachey);
  166. static void malloc_cache           (void);
  167. static void free_cache             (void);
  168. static void init_right_bump        (gint width, gint height);
  169. static void init_left_bump         (gint width, gint height);
  170. static void init_up_bump           (gint width, gint height);
  171. static void init_down_bump         (gint width, gint height);
  172. static void draw_bezier_line       (guchar *buffer, gint width, gint bytes,
  173.                     gint steps, gint *cx, gint *cy, 
  174.                     gboolean preview_mode);
  175. static void darken_bezier_line     (guchar *buffer, gint width, gint bytes,
  176.                     gint x_offset, gint y_offset, gint steps,
  177.                     gint *cx, gint *cy, gdouble delta, 
  178.                     gboolean preview_mode);
  179. static void lighten_bezier_line    (guchar *buffer, gint width, gint bytes,
  180.                     gint x_offset, gint y_offset, gint steps,
  181.                     gint *cx, gint *cy, gdouble delta, 
  182.                     gboolean preview_mode);
  183. static void draw_bezier_vertical_border   (guchar *buffer, gint width,
  184.                        gint height, gint bytes,
  185.                        gint x_offset, gint xtiles,
  186.                        gint ytiles, gint blend_lines,
  187.                        gdouble blend_amount, gint steps, 
  188.                        gboolean preview_mode);
  189. static void draw_bezier_horizontal_border (guchar *buffer, gint width,
  190.                        gint height, gint bytes,
  191.                        gint x_offset, gint xtiles,
  192.                        gint ytiles, gint blend_lines,
  193.                        gdouble blend_amount, gint steps, 
  194.                        gboolean preview_mode);
  195. static void check_config           (gint width, gint height);
  196.  
  197.                 
  198.  
  199. #define PLUG_IN_NAME    "jigsaw"
  200. #define PLUG_IN_STORAGE "jigsaw-storage"
  201.  
  202. #define XFACTOR2 0.0833
  203. #define XFACTOR3 0.2083
  204. #define XFACTOR4 0.2500
  205.  
  206. #define XFACTOR5 0.2500
  207. #define XFACTOR6 0.2083
  208. #define XFACTOR7 0.0833
  209.  
  210. #define YFACTOR2 0.1000
  211. #define YFACTOR3 0.2200
  212. #define YFACTOR4 0.1000
  213.  
  214. #define YFACTOR5 0.1000
  215. #define YFACTOR6 0.4666
  216. #define YFACTOR7 0.1000
  217. #define YFACTOR8 0.2000
  218.  
  219. #define MAX_VALUE 255
  220. #define MIN_VALUE 0
  221. #define DELTA 0.15
  222.  
  223. #define BLACK_R 30
  224. #define BLACK_G 30
  225. #define BLACK_B 30
  226.  
  227. #define WALL_XFACTOR2 0.05
  228. #define WALL_XFACTOR3 0.05
  229. #define WALL_YFACTOR2 0.05
  230. #define WALL_YFACTOR3 0.05
  231.  
  232. #define WALL_XCONS2 0.2
  233. #define WALL_XCONS3 0.3
  234. #define WALL_YCONS2 0.2
  235. #define WALL_YCONS3 0.3
  236.  
  237. #define FUDGE 1.2
  238.  
  239. #define MIN_XTILES 1
  240. #define MAX_XTILES 20
  241. #define MIN_YTILES 1
  242. #define MAX_YTILES 20
  243. #define MIN_BLEND_LINES 0
  244. #define MAX_BLEND_LINES 10
  245. #define MIN_BLEND_AMOUNT 0
  246. #define MAX_BLEND_AMOUNT 1.0
  247.  
  248. #define SCALE_WIDTH 200
  249. #define ENTRY_WIDTH 40
  250.  
  251. #define DRAW_POINT(buffer, index)        \
  252. do {                        \
  253.   buffer[index] = BLACK_R;            \
  254.   buffer[index+1] = BLACK_G;            \
  255.   buffer[index+2] = BLACK_B;            \
  256. } while (0)
  257.  
  258. #define DARKEN_POINT(buffer, index, delta, temp)    \
  259. do {                            \
  260.   temp = buffer[index];                    \
  261.   temp -= buffer[index] * delta;            \
  262.   if (temp < MIN_VALUE) temp = MIN_VALUE;        \
  263.   buffer[index] = temp;                    \
  264.   temp = buffer[index+1];                \
  265.   temp -= buffer[index+1] * delta;            \
  266.   if (temp < MIN_VALUE) temp = MIN_VALUE;        \
  267.   buffer[index+1] = temp;                \
  268.   temp = buffer[index+2];                \
  269.   temp -= buffer[index+2] * delta;            \
  270.   if (temp < MIN_VALUE) temp = MIN_VALUE;        \
  271.   buffer[index+2] = temp;                \
  272. } while (0)
  273.  
  274. #define LIGHTEN_POINT(buffer, index, delta, temp)    \
  275. do {                            \
  276.   temp = buffer[index] * delta;                \
  277.   temp += buffer[index];                \
  278.   if (temp > MAX_VALUE)    temp = MAX_VALUE;        \
  279.   buffer[index] = temp;                    \
  280.   temp = buffer[index+1] * delta;            \
  281.   temp += buffer[index+1];                \
  282.   if (temp > MAX_VALUE) temp = MAX_VALUE;        \
  283.   buffer[index+1] = temp;                \
  284.   temp = buffer[index+2] * delta;            \
  285.   temp += buffer[index+2];                \
  286.   if (temp > MAX_VALUE) temp = MAX_VALUE;        \
  287.   buffer[index+2] = temp;                \
  288. } while (0)
  289.  
  290.  
  291. GimpPlugInInfo PLUG_IN_INFO =
  292. {
  293.   NULL,
  294.   NULL,
  295.   query,
  296.   run
  297. };
  298.  
  299. struct config_tag
  300. {
  301.   gint    x;
  302.   gint    y;
  303.   style_t style;
  304.   gint    blend_lines;
  305.   gdouble blend_amount;
  306. };
  307.  
  308.  
  309. typedef struct config_tag config_t;
  310.  
  311. static config_t config =
  312. {
  313.   5,
  314.   5,
  315.   BEZIER_1,
  316.   3,
  317.   0.5
  318. };
  319.  
  320. struct globals_tag
  321. {
  322.   GimpDrawable *drawable;
  323.   gint  *cachex1[4];
  324.   gint  *cachex2[4];
  325.   gint  *cachey1[4];
  326.   gint  *cachey2[4];
  327.   gint  steps[4];
  328.   gint  *gridx;
  329.   gint  *gridy;
  330.   gint **blend_outer_cachex1[4];
  331.   gint **blend_outer_cachex2[4];
  332.   gint **blend_outer_cachey1[4];
  333.   gint **blend_outer_cachey2[4];
  334.   gint **blend_inner_cachex1[4];
  335.   gint **blend_inner_cachex2[4];
  336.   gint **blend_inner_cachey1[4];
  337.   gint **blend_inner_cachey2[4];
  338.   gint   dialog_result;
  339.   gint   tooltips;
  340. };
  341.  
  342. typedef struct globals_tag globals_t;
  343.  
  344. static globals_t globals =
  345. {
  346.   0,
  347.   {0, 0, 0, 0},
  348.   {0, 0, 0, 0},
  349.   {0, 0, 0, 0},
  350.   {0, 0, 0, 0},
  351.   {0, 0, 0, 0},
  352.   0,
  353.   0,
  354.   {0, 0, 0, 0},
  355.   {0, 0, 0, 0},
  356.   {0, 0, 0, 0},
  357.   {0, 0, 0, 0},
  358.   {0, 0, 0, 0},
  359.   {0, 0, 0, 0},
  360.   {0, 0, 0, 0},
  361.   {0, 0, 0, 0},
  362.   -1,
  363.   1
  364. };
  365.  
  366. /* preview globals */
  367. static guchar *preview_bits;
  368. static GtkWidget *preview;
  369.  
  370. MAIN ()
  371.  
  372. static void
  373. query (void)
  374. {
  375.   static GimpParamDef args[] =
  376.   {
  377.     { GIMP_PDB_INT32, "run_mode", "Interactive, Non-interactive, Last-Vals" },
  378.     { GIMP_PDB_IMAGE, "image", "Input image" },
  379.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  380.     { GIMP_PDB_INT32, "x", "Number of tiles across > 0" },
  381.     { GIMP_PDB_INT32, "y", "Number of tiles down > 0" },
  382.     { GIMP_PDB_INT32, "style", "The style/shape of the jigsaw puzzle, 0 or 1" },
  383.     { GIMP_PDB_INT32, "blend_lines", "Number of lines for shading bevels >= 0" },
  384.     { GIMP_PDB_FLOAT, "blend_amount", "The power of the light highlights 0 =< 5" }
  385.   };
  386.   static gint nargs = sizeof (args) / sizeof (args[0]);
  387.  
  388.   gimp_install_procedure ("plug_in_jigsaw",
  389.               "Renders a jigsaw puzzle look",
  390.               "Jigsaw puzzle look",
  391.               "Nigel Wetten",
  392.               "Nigel Wetten",
  393.               "May 2000",
  394.               N_("<Image>/Filters/Render/Pattern/Jigsaw..."),
  395.               "RGB*",
  396.               GIMP_PLUGIN,
  397.               nargs, 0,
  398.               args, NULL);
  399. }
  400.  
  401. static void
  402. run (gchar   *name,
  403.      gint     nparams,
  404.      GimpParam  *param,
  405.      gint    *nreturn_vals,
  406.      GimpParam **return_vals)
  407. {
  408.   static GimpParam values[1];
  409.   GimpDrawable *drawable;
  410.   GimpRunModeType run_mode;
  411.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  412.  
  413.   run_mode = param[0].data.d_int32;
  414.   drawable = gimp_drawable_get(param[2].data.d_drawable);
  415.   globals.drawable = drawable;
  416.   gimp_tile_cache_ntiles(drawable->width / gimp_tile_width() + 1);
  417.  
  418.   switch (run_mode)
  419.     {
  420.     case GIMP_RUN_NONINTERACTIVE:
  421.       INIT_I18N();
  422.       if (nparams == 8)
  423.     {
  424.       config.x = param[3].data.d_int32;
  425.       config.y = param[4].data.d_int32;
  426.       config.style = param[5].data.d_int32;
  427.       config.blend_lines = param[6].data.d_int32;
  428.       config.blend_amount = param[7].data.d_float;
  429.       if (jigsaw(0) == -1)
  430.         {
  431.           status = GIMP_PDB_EXECUTION_ERROR;
  432.         }
  433.     }
  434.       else
  435.     {
  436.       status = GIMP_PDB_CALLING_ERROR;
  437.     }
  438.       break;
  439.       
  440.     case GIMP_RUN_INTERACTIVE:
  441.       INIT_I18N_UI();
  442.       gimp_get_data("plug_in_jigsaw", &config);
  443.       gimp_get_data(PLUG_IN_STORAGE, &globals.tooltips);
  444.       dialog_box();
  445.       if (globals.dialog_result == -1)
  446.     {
  447.       status = GIMP_PDB_EXECUTION_ERROR;
  448.       break;
  449.     }
  450.       gimp_progress_init( _("Assembling Jigsaw"));
  451.       if (jigsaw(0) == -1)
  452.     {
  453.       status = GIMP_PDB_CALLING_ERROR;
  454.       break;
  455.     }
  456.       gimp_set_data("plug_in_jigsaw", &config, sizeof(config_t));
  457.       gimp_set_data(PLUG_IN_STORAGE, &globals.tooltips,
  458.             sizeof(globals.tooltips));
  459.       gimp_displays_flush();
  460.       g_free(preview_bits);
  461.       break;
  462.       
  463.     case GIMP_RUN_WITH_LAST_VALS:
  464.       INIT_I18N();
  465.       gimp_get_data("plug_in_jigsaw", &config);
  466.       if (jigsaw(0) == -1)
  467.     {
  468.       status = GIMP_PDB_EXECUTION_ERROR;
  469.       gimp_message("An execution error occured.");
  470.     }
  471.       else
  472.     {
  473.       gimp_displays_flush();
  474.     }
  475.  
  476.     }  /* switch */
  477.       
  478.   gimp_drawable_detach(drawable);
  479.   
  480.   *nreturn_vals = 1;
  481.   *return_vals = values;
  482.   values[0].type = GIMP_PDB_STATUS;
  483.   values[0].data.d_status = status;
  484.  
  485.   return;
  486. }
  487.  
  488. static gint
  489. jigsaw (gboolean preview_mode)
  490. {
  491.   GimpPixelRgn src_pr, dest_pr;
  492.   guchar *buffer;
  493.   GimpDrawable *drawable = globals.drawable;
  494.   gint width;
  495.   gint height;
  496.   gint bytes;
  497.   gint buffer_size;
  498.  
  499.   srand((gint)NULL);
  500.  
  501.   if (preview_mode) 
  502.     {
  503.       width  = GTK_PREVIEW (preview)->buffer_width;
  504.       height = GTK_PREVIEW (preview)->buffer_height;
  505.       bytes  = GTK_PREVIEW (preview)->bpp;
  506.       buffer_size = GTK_PREVIEW (preview)->rowstride * height;
  507.     } 
  508.   else 
  509.     {
  510.       width  = drawable->width;
  511.       height = drawable->height;
  512.       bytes  = drawable->bpp;
  513.       buffer_size = bytes * width * height;
  514.     }
  515.  
  516.   /* setup image buffer */
  517.   buffer = g_malloc (buffer_size);
  518.  
  519.   if (preview_mode) 
  520.     {
  521.       memcpy (buffer, preview_bits, buffer_size);
  522.     } 
  523.   else 
  524.     {
  525.       gimp_pixel_rgn_init (&src_pr,  drawable, 0, 0, width, height, FALSE, FALSE);
  526.       gimp_pixel_rgn_init (&dest_pr, drawable, 0, 0, width, height, TRUE, TRUE);
  527.       gimp_pixel_rgn_get_rect (&src_pr, buffer, 0, 0, width, height);
  528.     }
  529.  
  530.   check_config (width, height);
  531.   globals.steps[LEFT] = globals.steps[RIGHT] = globals.steps[UP]
  532.     = globals.steps[DOWN] = (config.x < config.y) ?
  533.     (width / config.x * 2) : (height / config.y * 2);
  534.  
  535.   malloc_cache ();
  536.   draw_jigsaw (buffer, width, height, bytes, preview_mode);
  537.   free_cache ();
  538.  
  539.   /* cleanup */
  540.   if (preview_mode) 
  541.     {
  542.       memcpy (GTK_PREVIEW (preview)->buffer, buffer, buffer_size);
  543.       gtk_widget_queue_draw (preview);
  544.     } 
  545.   else 
  546.     {
  547.       gimp_pixel_rgn_set_rect (&dest_pr, buffer, 0, 0, width, height);
  548.       gimp_drawable_flush (drawable);
  549.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  550.       gimp_drawable_update (drawable->id, 0, 0, width, height);
  551.     }
  552.  
  553.   g_free(buffer);
  554.  
  555.   return 0;
  556. }
  557.  
  558. static void
  559. generate_bezier (gint  px[4],
  560.          gint  py[4],
  561.          gint  steps,
  562.          gint *cachex,
  563.          gint *cachey)
  564. {
  565.   gdouble t = 0.0;
  566.   gdouble sigma = 1.0 / steps;
  567.   gint i;
  568.  
  569.   for (i = 0; i < steps; i++)
  570.     {
  571.       gdouble t2, t3, x, y, t_1;
  572.  
  573.       t += sigma;
  574.       t2 = t * t;
  575.       t3 = t2 * t;
  576.       t_1 = 1 - t;
  577.       x = t_1 * t_1 * t_1 * px[0]
  578.     + 3 * t * t_1 * t_1 * px[1]
  579.     + 3 * t2 * t_1 * px[2]
  580.     + t3 * px[3];
  581.       y = t_1 * t_1 * t_1 * py[0]
  582.     + 3 * t * t_1 * t_1 * py[1]
  583.     + 3 * t2 * t_1 * py[2]
  584.     + t3 * py[3];
  585.       cachex[i] = (gint) (x + 0.2);
  586.       cachey[i] = (gint) (y + 0.2);
  587.     }  /* for */
  588.   return;
  589. }
  590.  
  591. static void
  592. draw_jigsaw (guchar   *buffer,
  593.          gint      width,
  594.          gint      height,
  595.          gint      bytes,
  596.          gboolean  preview_mode)
  597. {
  598.   gint i;
  599.   gint *x, *y;
  600.   gint xtiles = config.x;
  601.   gint ytiles = config.y;
  602.   gint xlines = xtiles - 1;
  603.   gint ylines = ytiles - 1;
  604.   gint blend_lines = config.blend_lines;
  605.   gdouble blend_amount = config.blend_amount;
  606.   gint steps = globals.steps[RIGHT];
  607.   style_t style = config.style;
  608.   gint progress_total = xlines + ylines - 1;
  609.  
  610.   globals.gridx = g_new (gint, xtiles);
  611.   globals.gridy = g_new (gint, ytiles);
  612.   x = globals.gridx;
  613.   y = globals.gridy;
  614.  
  615.   generate_grid (width, height, xtiles, ytiles, globals.gridx, globals.gridy);
  616.  
  617.   init_right_bump (width, height);
  618.   init_left_bump  (width, height);
  619.   init_up_bump    (width, height);
  620.   init_down_bump  (width, height);
  621.  
  622.   if (style == BEZIER_1)
  623.     {
  624.       for (i = 0; i < xlines; i++)
  625.     {
  626.       draw_vertical_border (buffer, width, height, bytes, x[i], ytiles,
  627.                 blend_lines, blend_amount, preview_mode);
  628.       if (!preview_mode) 
  629.         gimp_progress_update ((gdouble) i / (gdouble) progress_total);
  630.     }
  631.       for (i = 0; i < ylines; i++)
  632.     {
  633.       draw_horizontal_border (buffer, width, bytes, y[i], xtiles,
  634.                   blend_lines, blend_amount, preview_mode);
  635.       if (!preview_mode) 
  636.         gimp_progress_update ((gdouble) (i + xlines) / (gdouble) progress_total);
  637.     }
  638.     }
  639.   else if (style == BEZIER_2)
  640.     {
  641.       for (i = 0; i < xlines; i++)
  642.     {
  643.       draw_bezier_vertical_border (buffer, width, height, bytes, x[i],
  644.                        xtiles, ytiles, blend_lines,
  645.                        blend_amount, steps, preview_mode);
  646.       if (!preview_mode) 
  647.         gimp_progress_update ((gdouble) i / (gdouble) progress_total);
  648.     }
  649.       for (i = 0; i < ylines; i++)
  650.     {
  651.       draw_bezier_horizontal_border (buffer, width, height, bytes, y[i],
  652.                      xtiles, ytiles, blend_lines,
  653.                      blend_amount, steps, preview_mode);
  654.       if (!preview_mode) 
  655.         gimp_progress_update ((gdouble) (i + xlines) / (gdouble) progress_total);
  656.     }
  657.     }
  658.   else
  659.     {
  660.       printf("draw_jigsaw: bad style\n");
  661.       exit(1);
  662.     }
  663.  
  664.   g_free (globals.gridx);
  665.   g_free (globals.gridy);
  666.   
  667.   return;
  668. }
  669.  
  670. static void
  671. draw_vertical_border (guchar  *buffer,
  672.               gint     width,
  673.               gint     height,
  674.               gint     bytes,
  675.               gint     x_offset,
  676.               gint     ytiles,
  677.               gint     blend_lines,
  678.               gdouble  blend_amount,
  679.               gboolean preview_mode)
  680. {
  681.   gint i, j;
  682.   gint tile_height = height / ytiles;
  683.   gint tile_height_eighth = tile_height / 8;
  684.   gint curve_start_offset = 3 * tile_height_eighth;
  685.   gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth;
  686.   gint px[2], py[2];
  687.   gint ly[2], dy[2];
  688.   gint y_offset = 0;
  689.   gdouble delta;
  690.   gdouble sigma = blend_amount / blend_lines;
  691.   gint right;
  692.   bump_t style_index;
  693.  
  694.   for (i = 0; i < ytiles; i++)
  695.     {
  696.       right = rand() & 1;
  697.       if (right)
  698.     {
  699.       style_index = RIGHT;
  700.     }
  701.       else
  702.     {
  703.       style_index = LEFT;
  704.     }
  705.       
  706.       /* first straight line from top downwards */
  707.       px[0] = px[1] = x_offset;
  708.       py[0] = y_offset; py[1] = y_offset + curve_start_offset - 1;
  709.       draw_vertical_line (buffer, width, bytes, px, py, preview_mode);
  710.       delta = blend_amount;
  711.       dy[0] = ly[0] = py[0]; dy[1] = ly[1] = py[1];
  712.       if (!right)
  713.     {
  714.       ly[1] += blend_lines + 2;
  715.     }
  716.       for (j = 0; j < blend_lines; j++)
  717.     {
  718.       dy[0]++; dy[1]--; ly[0]++; ly[1]--;
  719.       px[0] = x_offset - j - 1;
  720.       darken_vertical_line (buffer, width, bytes, px, dy, delta, preview_mode);
  721.       px[0] = x_offset + j + 1;
  722.       lighten_vertical_line (buffer, width, bytes, px, ly, delta, preview_mode);
  723.       delta -= sigma;
  724.     }
  725.  
  726.       /* top half of curve */
  727.       if (right)
  728.     {
  729.       draw_right_bump (buffer, width, bytes, x_offset,
  730.                y_offset + curve_start_offset,
  731.                globals.steps[RIGHT], preview_mode);
  732.       delta = blend_amount;
  733.       for (j = 0; j < blend_lines; j++)
  734.         {
  735.           /* use to be -j -1 */
  736.           darken_right_bump (buffer, width, bytes, x_offset,
  737.                  y_offset + curve_start_offset,
  738.                  globals.steps[RIGHT], delta, j, preview_mode);
  739.           /* use to be +j + 1 */
  740.           lighten_right_bump (buffer, width, bytes, x_offset,
  741.                   y_offset + curve_start_offset,
  742.                   globals.steps[RIGHT], delta, j, preview_mode);
  743.           delta -= sigma;
  744.         }
  745.     }
  746.       else
  747.     {
  748.       draw_left_bump (buffer, width, bytes, x_offset,
  749.               y_offset + curve_start_offset,
  750.               globals.steps[LEFT], preview_mode);
  751.       delta = blend_amount;
  752.       for (j = 0; j < blend_lines; j++)
  753.         {
  754.           /* use to be -j -1 */
  755.           darken_left_bump (buffer, width, bytes, x_offset,
  756.                 y_offset + curve_start_offset,
  757.                 globals.steps[LEFT], delta, j, preview_mode);
  758.           /* use to be -j - 1 */
  759.           lighten_left_bump (buffer, width, bytes, x_offset,
  760.                  y_offset + curve_start_offset,
  761.                  globals.steps[LEFT], delta, j, preview_mode);
  762.           delta -= sigma;
  763.         }
  764.     }
  765.       /* bottom straight line of a tile wall */
  766.       px[0] = px[1] = x_offset;
  767.       py[0] = y_offset + curve_end_offset;
  768.       py[1] = globals.gridy[i];
  769.       draw_vertical_line (buffer, width, bytes, px, py, preview_mode);
  770.       delta = blend_amount;
  771.       dy[0] = ly[0] = py[0]; dy[1] = ly[1] = py[1];
  772.       if (right)
  773.     {
  774.       dy[0] -= blend_lines + 2;
  775.     }
  776.       for (j = 0; j < blend_lines; j++)
  777.     {
  778.       dy[0]++; dy[1]--; ly[0]++; ly[1]--;
  779.       px[0] = x_offset - j - 1;
  780.       darken_vertical_line (buffer, width, bytes, px, dy, delta, preview_mode);
  781.       px[0] = x_offset + j + 1;
  782.       lighten_vertical_line (buffer, width, bytes, px, ly, delta, preview_mode);
  783.       delta -= sigma;
  784.     }
  785.  
  786.       y_offset = globals.gridy[i];
  787.     }  /* for */
  788.   
  789.   return;
  790. }
  791.  
  792. /* assumes RGB* */
  793. static void
  794. draw_horizontal_border (guchar   *buffer,
  795.             gint      width,
  796.             gint      bytes,
  797.             gint      y_offset,
  798.             gint      xtiles,
  799.             gint      blend_lines,
  800.             gdouble   blend_amount,
  801.             gboolean  preview_mode)
  802. {
  803.   gint i, j;
  804.   gint tile_width = width / xtiles;
  805.   gint tile_width_eighth = tile_width / 8;
  806.   gint curve_start_offset = 3 * tile_width_eighth;
  807.   gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth;
  808.   gint px[2], py[2];
  809.   gint dx[2], lx[2];
  810.   gint x_offset = 0;
  811.   gdouble delta;
  812.   gdouble sigma = blend_amount / blend_lines;
  813.   gint up;
  814.  
  815.   for (i = 0; i < xtiles; i++)
  816.     {
  817.       up = rand() & 1;
  818.       /* first horizontal line across */
  819.       px[0] = x_offset; px[1] = x_offset + curve_start_offset - 1;
  820.       py[0] = py[1] = y_offset;
  821.       draw_horizontal_line (buffer, width, bytes, px, py, preview_mode);
  822.       delta = blend_amount;
  823.       dx[0] = lx[0] = px[0]; dx[1] = lx[1] = px[1];
  824.       if (up)
  825.     {
  826.       lx[1] += blend_lines + 2;
  827.     }
  828.       for (j = 0; j < blend_lines; j++)
  829.     {
  830.       dx[0]++; dx[1]--; lx[0]++; lx[1]--;
  831.       py[0] = y_offset - j - 1;
  832.       darken_horizontal_line (buffer, width, bytes, dx, py, delta, preview_mode);
  833.       py[0] = y_offset + j + 1;
  834.       lighten_horizontal_line (buffer, width, bytes, lx, py, delta, preview_mode);
  835.       delta -= sigma;
  836.     }
  837.  
  838.       if (up)
  839.     {
  840.       draw_up_bump (buffer, width, bytes, y_offset,
  841.             x_offset + curve_start_offset,
  842.             globals.steps[UP], preview_mode);
  843.       delta = blend_amount;
  844.       for (j = 0; j < blend_lines; j++)
  845.         {
  846.           /* use to be -j -1 */
  847.           darken_up_bump (buffer, width, bytes, y_offset,
  848.                   x_offset + curve_start_offset,
  849.                   globals.steps[UP], delta, j, preview_mode);
  850.           /* use to be +j + 1 */
  851.           lighten_up_bump (buffer, width, bytes, y_offset,
  852.                    x_offset + curve_start_offset,
  853.                    globals.steps[UP], delta, j, preview_mode);
  854.           delta -= sigma;
  855.         }
  856.     }
  857.       else
  858.     {
  859.       draw_down_bump (buffer, width, bytes, y_offset,
  860.               x_offset + curve_start_offset,
  861.               globals.steps[DOWN], preview_mode);
  862.       delta = blend_amount;
  863.       for (j = 0; j < blend_lines; j++)
  864.         {
  865.           /* use to be +j + 1 */
  866.           darken_down_bump (buffer, width, bytes, y_offset,
  867.                 x_offset + curve_start_offset,
  868.                 globals.steps[DOWN], delta, j, preview_mode);
  869.           /* use to be -j -1 */
  870.           lighten_down_bump (buffer, width, bytes, y_offset,
  871.                  x_offset + curve_start_offset,
  872.                  globals.steps[DOWN], delta, j, preview_mode);
  873.           delta -= sigma;
  874.         }
  875.     }
  876.       /* right horizontal line of tile */
  877.       px[0] = x_offset + curve_end_offset;
  878.       px[1] = globals.gridx[i];
  879.       py[0] = py[1] = y_offset;
  880.       draw_horizontal_line (buffer, width, bytes, px, py, preview_mode);
  881.       delta = blend_amount;
  882.       dx[0] = lx[0] = px[0]; dx[1] = lx[1] = px[1];
  883.       if (!up)
  884.     {
  885.       dx[0] -= blend_lines + 2;
  886.     }
  887.       for (j = 0;j < blend_lines; j++)
  888.     {
  889.       dx[0]++; dx[1]--; lx[0]++; lx[1]--;
  890.       py[0] = y_offset - j - 1;
  891.       darken_horizontal_line (buffer, width, bytes, dx, py, delta, preview_mode);
  892.       py[0] = y_offset + j + 1;
  893.       lighten_horizontal_line (buffer, width, bytes, lx, py, delta, preview_mode);
  894.       delta -= sigma;
  895.     }
  896.       x_offset = globals.gridx[i];
  897.     }  /* for */
  898. }
  899.  
  900. /* assumes going top to bottom */
  901. static void
  902. draw_vertical_line (guchar   *buffer,
  903.             gint      width,
  904.             gint      bytes,
  905.             gint      px[2],
  906.             gint      py[2],
  907.             gboolean  preview_mode)
  908. {
  909.   gint i;
  910.   gint rowstride;
  911.   gint index;
  912.   gint length;
  913.   
  914.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  915.   index = px[0] * bytes + rowstride * py[0];
  916.   length = py[1] - py[0] + 1;
  917.  
  918.   for (i = 0; i < length; i++)
  919.     {
  920.       DRAW_POINT (buffer, index);
  921.       index += rowstride;
  922.     }
  923. }
  924.  
  925. /* assumes going left to right */
  926. static void
  927. draw_horizontal_line (guchar   *buffer,
  928.               gint      width,
  929.               gint      bytes,
  930.               gint      px[2],
  931.               gint      py[2],
  932.               gboolean  preview_mode)
  933. {
  934.   gint i;
  935.   gint rowstride;
  936.   gint index;
  937.   gint length;
  938.   
  939.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  940.   index = px[0] * bytes + rowstride * py[0];
  941.   length = px[1] - px[0] + 1;
  942.  
  943.   for (i = 0; i < length; i++)
  944.     {
  945.       DRAW_POINT(buffer, index);
  946.       index += bytes;
  947.     }
  948. }
  949.  
  950. static void
  951. draw_right_bump (guchar   *buffer,
  952.          gint      width,
  953.          gint      bytes,
  954.          gint      x_offset,
  955.          gint      curve_start_offset,
  956.          gint      steps,
  957.          gboolean  preview_mode)
  958. {
  959.   gint i;
  960.   gint x, y;
  961.   gint index;
  962.   gint rowstride;
  963.  
  964.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  965.  
  966.   for (i = 0; i < steps; i++)
  967.     {
  968.       x = *(globals.cachex1[RIGHT] + i) + x_offset;
  969.       y = *(globals.cachey1[RIGHT] + i) + curve_start_offset;
  970.       index = y * rowstride + x * bytes;
  971.       DRAW_POINT(buffer, index);
  972.  
  973.       x = *(globals.cachex2[RIGHT] + i) + x_offset;
  974.       y = *(globals.cachey2[RIGHT] + i) + curve_start_offset;
  975.       index = y * rowstride + x * bytes;
  976.       DRAW_POINT(buffer, index);
  977.     }
  978. }
  979.  
  980. static void
  981. draw_left_bump (guchar   *buffer,
  982.         gint      width,
  983.         gint      bytes,
  984.         gint      x_offset,
  985.         gint      curve_start_offset,
  986.         gint      steps,
  987.         gboolean  preview_mode)
  988. {
  989.   gint i;
  990.   gint x, y;
  991.   gint index;
  992.   gint rowstride;
  993.  
  994.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  995.  
  996.   for (i = 0; i < steps; i++)
  997.     {
  998.       x = *(globals.cachex1[LEFT] + i) + x_offset;
  999.       y = *(globals.cachey1[LEFT] + i) + curve_start_offset;
  1000.       index = y * rowstride + x * bytes;
  1001.       DRAW_POINT(buffer, index);
  1002.  
  1003.       x = *(globals.cachex2[LEFT] + i) + x_offset;
  1004.       y = *(globals.cachey2[LEFT] + i) + curve_start_offset;
  1005.       index = y * rowstride + x * bytes;
  1006.       DRAW_POINT(buffer, index);
  1007.     }
  1008. }
  1009.  
  1010. static void
  1011. draw_up_bump (guchar   *buffer,
  1012.           gint      width,
  1013.           gint      bytes,
  1014.           gint      y_offset,
  1015.           gint      curve_start_offset,
  1016.           gint      steps,
  1017.           gboolean  preview_mode)
  1018. {
  1019.   gint i;
  1020.   gint x, y;
  1021.   gint index;
  1022.   gint rowstride;
  1023.  
  1024.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1025.  
  1026.   for (i = 0; i < steps; i++)
  1027.     {
  1028.       x = *(globals.cachex1[UP] + i) + curve_start_offset;
  1029.       y = *(globals.cachey1[UP] + i) + y_offset;
  1030.       index = y * rowstride + x * bytes;
  1031.       DRAW_POINT(buffer, index);
  1032.  
  1033.       x = *(globals.cachex2[UP] + i) + curve_start_offset;
  1034.       y = *(globals.cachey2[UP] + i) + y_offset;
  1035.       index = y * rowstride + x * bytes;
  1036.       DRAW_POINT(buffer, index);
  1037.     }
  1038. }
  1039.  
  1040. static void
  1041. draw_down_bump (guchar   *buffer,
  1042.         gint      width,
  1043.         gint      bytes,
  1044.         gint      y_offset,
  1045.         gint      curve_start_offset,
  1046.         gint      steps,
  1047.         gboolean  preview_mode)
  1048. {
  1049.   gint i;
  1050.   gint x, y;
  1051.   gint index;
  1052.   gint rowstride;
  1053.  
  1054.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1055.  
  1056.   for (i = 0; i < steps; i++)
  1057.     {
  1058.       x = *(globals.cachex1[DOWN] + i) + curve_start_offset;
  1059.       y = *(globals.cachey1[DOWN] + i) + y_offset;
  1060.       index = y * rowstride + x * bytes;
  1061.       DRAW_POINT(buffer, index);
  1062.  
  1063.       x = *(globals.cachex2[DOWN] + i) + curve_start_offset;
  1064.       y = *(globals.cachey2[DOWN] + i) + y_offset;
  1065.       index = y * rowstride + x * bytes;
  1066.       DRAW_POINT(buffer, index);
  1067.     }
  1068. }
  1069.  
  1070. static void
  1071. malloc_cache (void)
  1072. {
  1073.   gint i, j;
  1074.   gint blend_lines = config.blend_lines;
  1075.   gint length = blend_lines * sizeof(gint *);
  1076.  
  1077.   for (i = 0; i < 4; i++)
  1078.     {
  1079.       gint steps_length = globals.steps[i] * sizeof(gint);
  1080.  
  1081.       globals.cachex1[i] = g_malloc (steps_length);
  1082.       globals.cachex2[i] = g_malloc (steps_length);
  1083.       globals.cachey1[i] = g_malloc (steps_length);
  1084.       globals.cachey2[i] = g_malloc (steps_length);
  1085.       globals.blend_outer_cachex1[i] = g_malloc (length);
  1086.       globals.blend_outer_cachex2[i] = g_malloc (length);
  1087.       globals.blend_outer_cachey1[i] = g_malloc (length);
  1088.       globals.blend_outer_cachey2[i] = g_malloc (length);
  1089.       globals.blend_inner_cachex1[i] = g_malloc (length);
  1090.       globals.blend_inner_cachex2[i] = g_malloc (length);
  1091.       globals.blend_inner_cachey1[i] = g_malloc (length);
  1092.       globals.blend_inner_cachey2[i] = g_malloc (length);
  1093.       for (j = 0; j < blend_lines; j++)
  1094.     {
  1095.       *(globals.blend_outer_cachex1[i] + j) = g_malloc (steps_length);
  1096.       *(globals.blend_outer_cachex2[i] + j) = g_malloc (steps_length);
  1097.       *(globals.blend_outer_cachey1[i] + j) = g_malloc (steps_length);
  1098.       *(globals.blend_outer_cachey2[i] + j) = g_malloc (steps_length);
  1099.       *(globals.blend_inner_cachex1[i] + j) = g_malloc (steps_length);
  1100.       *(globals.blend_inner_cachex2[i] + j) = g_malloc (steps_length);
  1101.       *(globals.blend_inner_cachey1[i] + j) = g_malloc (steps_length);
  1102.       *(globals.blend_inner_cachey2[i] + j) = g_malloc (steps_length);
  1103.     }
  1104.     }
  1105. }
  1106.  
  1107. static void
  1108. free_cache (void)
  1109. {
  1110.   gint i, j;
  1111.   gint blend_lines = config.blend_lines;
  1112.  
  1113.   for (i = 0; i < 4; i ++)
  1114.     {
  1115.       g_free (globals.cachex1[i]);
  1116.       g_free (globals.cachex2[i]);
  1117.       g_free (globals.cachey1[i]);
  1118.       g_free (globals.cachey2[i]);
  1119.       for (j = 0; j < blend_lines; j++)
  1120.     {
  1121.       g_free (*(globals.blend_outer_cachex1[i] + j));
  1122.       g_free (*(globals.blend_outer_cachex2[i] + j));
  1123.       g_free (*(globals.blend_outer_cachey1[i] + j));
  1124.       g_free (*(globals.blend_outer_cachey2[i] + j));
  1125.       g_free (*(globals.blend_inner_cachex1[i] + j));
  1126.       g_free (*(globals.blend_inner_cachex2[i] + j));
  1127.       g_free (*(globals.blend_inner_cachey1[i] + j));
  1128.       g_free (*(globals.blend_inner_cachey2[i] + j));
  1129.     }
  1130.       g_free (globals.blend_outer_cachex1[i]);
  1131.       g_free (globals.blend_outer_cachex2[i]);
  1132.       g_free (globals.blend_outer_cachey1[i]);
  1133.       g_free (globals.blend_outer_cachey2[i]);
  1134.       g_free (globals.blend_inner_cachex1[i]);
  1135.       g_free (globals.blend_inner_cachex2[i]);
  1136.       g_free (globals.blend_inner_cachey1[i]);
  1137.       g_free (globals.blend_inner_cachey2[i]);
  1138.     }
  1139. }
  1140.  
  1141. static void
  1142. init_right_bump (gint width,
  1143.          gint height)
  1144. {
  1145.   gint i;
  1146.   gint xtiles = config.x;
  1147.   gint ytiles = config.y;
  1148.   gint steps = globals.steps[RIGHT];
  1149.   gint px[4], py[4];
  1150.   gint x_offset = 0;
  1151.   gint tile_width =  width / xtiles;
  1152.   gint tile_height = height/ ytiles;
  1153.   gint tile_height_eighth = tile_height / 8;
  1154.   gint curve_start_offset = 0;
  1155.   gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth;
  1156.   gint blend_lines = config.blend_lines;
  1157.  
  1158.   px[0] = x_offset;
  1159.   px[1] = x_offset + XFACTOR2 * tile_width;
  1160.   px[2] = x_offset + XFACTOR3 * tile_width;
  1161.   px[3] = x_offset + XFACTOR4 * tile_width;
  1162.   py[0] = curve_start_offset;
  1163.   py[1] = curve_start_offset + YFACTOR2 * tile_height;
  1164.   py[2] = curve_start_offset - YFACTOR3 * tile_height;
  1165.   py[3] = curve_start_offset + YFACTOR4 * tile_height;
  1166.   generate_bezier(px, py, steps, globals.cachex1[RIGHT],
  1167.           globals.cachey1[RIGHT]);
  1168.   /* outside right bump */
  1169.   for (i = 0; i < blend_lines; i++)
  1170.     {
  1171.        py[0]--; py[1]--; py[2]--; px[3]++;
  1172.        generate_bezier(px, py, steps,
  1173.                *(globals.blend_outer_cachex1[RIGHT] + i),
  1174.                *(globals.blend_outer_cachey1[RIGHT] + i));
  1175.     }
  1176.   /* inside right bump */
  1177.   py[0] += blend_lines; py[1] += blend_lines; py[2] += blend_lines;
  1178.   px[3] -= blend_lines;
  1179.   for (i = 0; i < blend_lines; i++)
  1180.     {
  1181.       py[0]++; py[1]++; py[2]++; px[3]--;
  1182.       generate_bezier(px, py, steps,
  1183.               *(globals.blend_inner_cachex1[RIGHT] + i),
  1184.               *(globals.blend_inner_cachey1[RIGHT] + i));
  1185.     }
  1186.  
  1187.   /* bottom half of bump */
  1188.   px[0] = x_offset + XFACTOR5 * tile_width;
  1189.   px[1] = x_offset + XFACTOR6 * tile_width;
  1190.   px[2] = x_offset + XFACTOR7 * tile_width;
  1191.   px[3] = x_offset;
  1192.   py[0] = curve_start_offset + YFACTOR5 * tile_height;
  1193.   py[1] = curve_start_offset + YFACTOR6 * tile_height;
  1194.   py[2] = curve_start_offset + YFACTOR7 * tile_height;
  1195.   py[3] = curve_end_offset;
  1196.   generate_bezier(px, py, steps, globals.cachex2[RIGHT],
  1197.           globals.cachey2[RIGHT]);
  1198.   /* outer right bump */
  1199.   for (i = 0; i < blend_lines; i++)
  1200.     {
  1201.       py[1]++; py[2]++; py[3]++; px[0]++;
  1202.       generate_bezier(px, py, steps,
  1203.               *(globals.blend_outer_cachex2[RIGHT] + i),
  1204.               *(globals.blend_outer_cachey2[RIGHT] + i));
  1205.     }
  1206.   /* inner right bump */
  1207.   py[1] -= blend_lines; py[2] -= blend_lines; py[3] -= blend_lines;
  1208.   px[0] -= blend_lines;
  1209.   for (i = 0; i < blend_lines; i++)
  1210.     {
  1211.       py[1]--; py[2]--; py[3]--; px[0]--;
  1212.       generate_bezier(px, py, steps,
  1213.               *(globals.blend_inner_cachex2[RIGHT] + i),
  1214.               *(globals.blend_inner_cachey2[RIGHT] + i));
  1215.     }
  1216.   return;
  1217. }
  1218.  
  1219. static void
  1220. init_left_bump (gint width,
  1221.         gint height)
  1222. {
  1223.   gint i;
  1224.   gint xtiles = config.x;
  1225.   gint ytiles = config.y;
  1226.   gint steps = globals.steps[LEFT];
  1227.   gint px[4], py[4];
  1228.   gint x_offset = 0;
  1229.   gint tile_width = width / xtiles;
  1230.   gint tile_height = height / ytiles;
  1231.   gint tile_height_eighth = tile_height / 8;
  1232.   gint curve_start_offset = 0;
  1233.   gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth;
  1234.   gint blend_lines = config.blend_lines;
  1235.  
  1236.   px[0] = x_offset;
  1237.   px[1] = x_offset - XFACTOR2 * tile_width;
  1238.   px[2] = x_offset - XFACTOR3 * tile_width;
  1239.   px[3] = x_offset - XFACTOR4 * tile_width;
  1240.   py[0] = curve_start_offset;
  1241.   py[1] = curve_start_offset + YFACTOR2 * tile_height;
  1242.   py[2] = curve_start_offset - YFACTOR3 * tile_height;
  1243.   py[3] = curve_start_offset + YFACTOR4 * tile_height;
  1244.   generate_bezier(px, py, steps, globals.cachex1[LEFT],
  1245.           globals.cachey1[LEFT]);
  1246.   /* outer left bump */
  1247.   for (i = 0; i < blend_lines; i++)
  1248.     {
  1249.       py[0]--; py[1]--; py[2]--; px[3]--;
  1250.       generate_bezier(px, py, steps,
  1251.               *(globals.blend_outer_cachex1[LEFT] + i),
  1252.               *(globals.blend_outer_cachey1[LEFT] + i));
  1253.     }
  1254.   /* inner left bump */
  1255.   py[0] += blend_lines; py[1] += blend_lines; py[2] += blend_lines;
  1256.   px[3] += blend_lines;
  1257.   for (i = 0; i < blend_lines; i++)
  1258.     {
  1259.       py[0]++; py[1]++; py[2]++; px[3]++;
  1260.       generate_bezier(px, py, steps,
  1261.               *(globals.blend_inner_cachex1[LEFT] + i),
  1262.               *(globals.blend_inner_cachey1[LEFT] + i));
  1263.     }
  1264.  
  1265.   /* bottom half of bump */
  1266.   px[0] = x_offset - XFACTOR5 * tile_width;
  1267.   px[1] = x_offset - XFACTOR6 * tile_width;
  1268.   px[2] = x_offset - XFACTOR7 * tile_width;
  1269.   px[3] = x_offset;
  1270.   py[0] = curve_start_offset + YFACTOR5 * tile_height;
  1271.   py[1] = curve_start_offset + YFACTOR6 * tile_height;
  1272.   py[2] = curve_start_offset + YFACTOR7 * tile_height;
  1273.   py[3] = curve_end_offset;
  1274.   generate_bezier(px, py, steps, globals.cachex2[LEFT],
  1275.           globals.cachey2[LEFT]);
  1276.   /* outer left bump */
  1277.   for (i = 0; i < blend_lines; i++)
  1278.     {
  1279.       py[1]++; py[2]++; py[3]++; px[0]--;
  1280.       generate_bezier(px, py, steps,
  1281.               *(globals.blend_outer_cachex2[LEFT] + i),
  1282.               *(globals.blend_outer_cachey2[LEFT] + i));
  1283.     }
  1284.   /* inner left bump */
  1285.   py[1] -= blend_lines; py[2] -= blend_lines; py[3] -= blend_lines;
  1286.   px[0] += blend_lines;
  1287.   for (i = 0; i < blend_lines; i++)
  1288.     {
  1289.       py[1]--; py[2]--; py[3]--; px[0]++;
  1290.       generate_bezier(px, py, steps,
  1291.               *(globals.blend_inner_cachex2[LEFT] + i),
  1292.               *(globals.blend_inner_cachey2[LEFT] + i));
  1293.     }
  1294. }
  1295.  
  1296. static void
  1297. init_up_bump (gint width,
  1298.           gint height)
  1299. {
  1300.   gint i;
  1301.   gint xtiles = config.x;
  1302.   gint ytiles = config.y;
  1303.   gint steps = globals.steps[UP];
  1304.   gint px[4], py[4];
  1305.   gint y_offset = 0;
  1306.   gint tile_width =  width / xtiles;
  1307.   gint tile_height = height/ ytiles;
  1308.   gint tile_width_eighth = tile_width / 8;
  1309.   gint curve_start_offset = 0;
  1310.   gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth;
  1311.   gint blend_lines = config.blend_lines;
  1312.  
  1313.   px[0] = curve_start_offset;
  1314.   px[1] = curve_start_offset + YFACTOR2 * tile_width;
  1315.   px[2] = curve_start_offset - YFACTOR3 * tile_width;
  1316.   px[3] = curve_start_offset + YFACTOR4 * tile_width;
  1317.   py[0] = y_offset;
  1318.   py[1] = y_offset - XFACTOR2 * tile_height;
  1319.   py[2] = y_offset - XFACTOR3 * tile_height;
  1320.   py[3] = y_offset - XFACTOR4 * tile_height;
  1321.   generate_bezier(px, py, steps, globals.cachex1[UP],
  1322.           globals.cachey1[UP]);
  1323.   /* outer up bump */
  1324.   for (i = 0; i < blend_lines; i++)
  1325.     {
  1326.       px[0]--; px[1]--; px[2]--; py[3]--;
  1327.       generate_bezier(px, py, steps,
  1328.               *(globals.blend_outer_cachex1[UP] + i),
  1329.               *(globals.blend_outer_cachey1[UP] + i));
  1330.     }
  1331.   /* inner up bump */
  1332.   px[0] += blend_lines; px[1] += blend_lines; px[2] += blend_lines;
  1333.   py[3] += blend_lines;
  1334.   for (i = 0; i < blend_lines; i++)
  1335.     {
  1336.       px[0]++; px[1]++; px[2]++; py[3]++;
  1337.       generate_bezier(px, py, steps,
  1338.               *(globals.blend_inner_cachex1[UP] + i),
  1339.               *(globals.blend_inner_cachey1[UP] + i));
  1340.     }
  1341.  
  1342.   /* bottom half of bump */
  1343.   px[0] = curve_start_offset + YFACTOR5 * tile_width;
  1344.   px[1] = curve_start_offset + YFACTOR6 * tile_width;
  1345.   px[2] = curve_start_offset + YFACTOR7 * tile_width;
  1346.   px[3] = curve_end_offset;
  1347.   py[0] = y_offset - XFACTOR5 * tile_height;
  1348.   py[1] = y_offset - XFACTOR6 * tile_height;
  1349.   py[2] = y_offset - XFACTOR7 * tile_height;
  1350.   py[3] = y_offset;
  1351.   generate_bezier(px, py, steps, globals.cachex2[UP],
  1352.           globals.cachey2[UP]);
  1353.   /* outer up bump */
  1354.   for (i = 0; i < blend_lines; i++)
  1355.     {
  1356.       px[1]++; px[2]++; px[3]++; py[0]--;
  1357.       generate_bezier(px, py, steps,
  1358.               *(globals.blend_outer_cachex2[UP] + i),
  1359.               *(globals.blend_outer_cachey2[UP] + i));
  1360.     }
  1361.   /* inner up bump */
  1362.   px[1] -= blend_lines; px[2] -= blend_lines; px[3] -= blend_lines;
  1363.   py[0] += blend_lines;
  1364.   for (i = 0; i < blend_lines; i++)
  1365.     {
  1366.       px[1]--; px[2]--; px[3]--; py[0]++;
  1367.       generate_bezier(px, py, steps,
  1368.               *(globals.blend_inner_cachex2[UP] + i),
  1369.               *(globals.blend_inner_cachey2[UP] + i));
  1370.     }
  1371.   return;
  1372. }
  1373.  
  1374. static void
  1375. init_down_bump (gint width,
  1376.         gint height)
  1377. {
  1378.   gint i;
  1379.   gint xtiles = config.x;
  1380.   gint ytiles = config.y;
  1381.   gint steps = globals.steps[DOWN];
  1382.   gint px[4], py[4];
  1383.   gint y_offset = 0;
  1384.   gint tile_width =  width / xtiles;
  1385.   gint tile_height = height/ ytiles;
  1386.   gint tile_width_eighth = tile_width / 8;
  1387.   gint curve_start_offset = 0;
  1388.   gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth;
  1389.   gint blend_lines = config.blend_lines;
  1390.  
  1391.   px[0] = curve_start_offset;
  1392.   px[1] = curve_start_offset + YFACTOR2 * tile_width;
  1393.   px[2] = curve_start_offset - YFACTOR3 * tile_width;
  1394.   px[3] = curve_start_offset + YFACTOR4 * tile_width;
  1395.   py[0] = y_offset;
  1396.   py[1] = y_offset + XFACTOR2 * tile_height;
  1397.   py[2] = y_offset + XFACTOR3 * tile_height;
  1398.   py[3] = y_offset + XFACTOR4 * tile_height;
  1399.   generate_bezier(px, py, steps, globals.cachex1[DOWN],
  1400.           globals.cachey1[DOWN]);
  1401.   /* outer down bump */
  1402.   for (i = 0; i < blend_lines; i++)
  1403.     {
  1404.       px[0]--; px[1]--; px[2]--; py[3]++;
  1405.       generate_bezier(px, py, steps,
  1406.               *(globals.blend_outer_cachex1[DOWN] + i),
  1407.               *(globals.blend_outer_cachey1[DOWN] + i));
  1408.     }
  1409.   /* inner down bump */
  1410.   px[0] += blend_lines; px[1] += blend_lines; px[2] += blend_lines;
  1411.   py[3] -= blend_lines;
  1412.   for (i = 0; i < blend_lines; i++)
  1413.     {
  1414.       px[0]++; px[1]++; px[2]++; py[3]--;
  1415.       generate_bezier(px, py, steps,
  1416.               *(globals.blend_inner_cachex1[DOWN] + i),
  1417.               *(globals.blend_inner_cachey1[DOWN] + i));
  1418.     }
  1419.  
  1420.   /* bottom half of bump */
  1421.   px[0] = curve_start_offset + YFACTOR5 * tile_width;
  1422.   px[1] = curve_start_offset + YFACTOR6 * tile_width;
  1423.   px[2] = curve_start_offset + YFACTOR7 * tile_width;
  1424.   px[3] = curve_end_offset;
  1425.   py[0] = y_offset + XFACTOR5 * tile_height;
  1426.   py[1] = y_offset + XFACTOR6 * tile_height;
  1427.   py[2] = y_offset + XFACTOR7 * tile_height;
  1428.   py[3] = y_offset;
  1429.   generate_bezier(px, py, steps, globals.cachex2[DOWN],
  1430.           globals.cachey2[DOWN]);
  1431.   /* outer down bump */
  1432.   for (i = 0; i < blend_lines; i++)
  1433.     {
  1434.       px[1]++; px[2]++; px[3]++; py[0]++;
  1435.       generate_bezier(px, py, steps,
  1436.               *(globals.blend_outer_cachex2[DOWN] + i),
  1437.               *(globals.blend_outer_cachey2[DOWN] + i));
  1438.     }
  1439.   /* inner down bump */
  1440.   px[1] -= blend_lines; px[2] -= blend_lines; px[3] -= blend_lines;
  1441.   py[0] -= blend_lines;
  1442.   for (i = 0; i < blend_lines; i++)
  1443.     {
  1444.       px[1]--; px[2]--; px[3]--; py[0]--;
  1445.       generate_bezier(px, py, steps,
  1446.               *(globals.blend_inner_cachex2[DOWN] + i),
  1447.               *(globals.blend_inner_cachey2[DOWN] + i));
  1448.     }
  1449.   return;
  1450. }
  1451.   
  1452. static void
  1453. generate_grid (gint  width,
  1454.            gint  height,
  1455.            gint  xtiles,
  1456.            gint  ytiles,
  1457.            gint *x,
  1458.            gint *y)
  1459. {
  1460.   gint i;
  1461.   gint xlines = xtiles - 1;
  1462.   gint ylines = ytiles - 1;
  1463.   gint tile_width = width / xtiles;
  1464.   gint tile_height = height / ytiles;
  1465.   gint tile_width_leftover = width % xtiles;
  1466.   gint tile_height_leftover = height % ytiles;
  1467.   gint x_offset = tile_width;
  1468.   gint y_offset = tile_height;
  1469.   gint carry;
  1470.  
  1471.   for (i = 0; i < xlines; i++)
  1472.     {
  1473.       x[i] = x_offset;
  1474.       x_offset += tile_width;
  1475.     }
  1476.   carry = 0;
  1477.   while (tile_width_leftover)
  1478.     {
  1479.       for (i = carry; i < xlines; i++)
  1480.     {
  1481.       x[i] += 1;
  1482.     }
  1483.       tile_width_leftover--;
  1484.       carry++;
  1485.     }
  1486.   x[xlines] = width - 1;    /* padding for draw_horizontal_border */
  1487.   
  1488.   for (i = 0; i < ytiles; i++)
  1489.     {
  1490.       y[i] = y_offset;
  1491.       y_offset += tile_height;
  1492.     }
  1493.   carry = 0;
  1494.   while (tile_height_leftover)
  1495.     {
  1496.       for (i = carry; i < ylines; i++)
  1497.     {
  1498.       y[i] += 1;
  1499.     }
  1500.       tile_height_leftover--;
  1501.       carry++;
  1502.     }
  1503.   y[ylines] = height - 1;   /* padding for draw_vertical_border */
  1504. }
  1505.  
  1506. /* assumes RGB* */
  1507. /* assumes py[1] > py[0] and px[0] = px[1] */
  1508. static void
  1509. darken_vertical_line (guchar   *buffer,
  1510.               gint      width,
  1511.               gint      bytes,
  1512.               gint      px[2],
  1513.               gint      py[2],
  1514.               gdouble   delta,
  1515.               gboolean  preview_mode)
  1516. {
  1517.   gint i;
  1518.   gint rowstride;
  1519.   gint index;
  1520.   gint length;
  1521.   gint temp;
  1522.  
  1523.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1524.   index = px[0] * bytes + py[0] * rowstride;
  1525.   length = py[1] - py[0] + 1;
  1526.  
  1527.   for (i = 0; i < length; i++)
  1528.     {
  1529.       DARKEN_POINT(buffer, index, delta, temp);
  1530.       index += rowstride;
  1531.     }
  1532. }
  1533.  
  1534. /* assumes RGB* */
  1535. /* assumes py[1] > py[0] and px[0] = px[1] */
  1536. static void
  1537. lighten_vertical_line (guchar   *buffer,
  1538.                gint      width,
  1539.                gint      bytes,
  1540.                gint      px[2],
  1541.                gint      py[2],
  1542.                gdouble   delta,
  1543.                gboolean  preview_mode)
  1544. {
  1545.   gint i;
  1546.   gint rowstride;
  1547.   gint index;
  1548.   gint length;
  1549.   gint temp;
  1550.  
  1551.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1552.   index = px[0] * bytes + py[0] * rowstride;
  1553.   length = py[1] - py[0] + 1;
  1554.  
  1555.   for (i = 0; i < length; i++)
  1556.     {
  1557.       LIGHTEN_POINT(buffer, index, delta, temp);
  1558.       index += rowstride;
  1559.     }
  1560. }
  1561.  
  1562. /* assumes RGB* */
  1563. /* assumes px[1] > px[0] and py[0] = py[1] */
  1564. static void
  1565. darken_horizontal_line (guchar   *buffer,
  1566.             gint      width,
  1567.             gint      bytes,
  1568.             gint      px[2],
  1569.             gint      py[2],
  1570.             gdouble   delta,
  1571.             gboolean  preview_mode)
  1572. {
  1573.   gint i;
  1574.   gint rowstride;
  1575.   gint index;
  1576.   gint length;
  1577.   gint temp;
  1578.  
  1579.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1580.   index = px[0] * bytes + py[0] * rowstride;
  1581.   length = px[1] - px[0] + 1;
  1582.  
  1583.   for (i = 0; i < length; i++)
  1584.     {
  1585.       DARKEN_POINT(buffer, index, delta, temp);
  1586.       index += bytes;
  1587.     }
  1588. }
  1589.  
  1590. /* assumes RGB* */
  1591. /* assumes px[1] > px[0] and py[0] = py[1] */
  1592. static void
  1593. lighten_horizontal_line (guchar   *buffer,
  1594.              gint      width,
  1595.              gint      bytes,
  1596.              gint      px[2],
  1597.              gint      py[2],
  1598.              gdouble   delta,
  1599.              gboolean  preview_mode)
  1600. {
  1601.   gint i;
  1602.   gint rowstride;
  1603.   gint index;
  1604.   gint length;
  1605.   gint temp;
  1606.  
  1607.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1608.   index = px[0] * bytes + py[0] * rowstride;
  1609.   length = px[1] - px[0] + 1;
  1610.  
  1611.   for (i = 0; i < length; i++)
  1612.     {
  1613.       LIGHTEN_POINT(buffer, index, delta, temp);
  1614.       index += bytes;
  1615.     }
  1616. }
  1617.  
  1618. static void
  1619. darken_right_bump (guchar *buffer,
  1620.            gint    width,
  1621.            gint    bytes,
  1622.            gint    x_offset,
  1623.            gint    curve_start_offset,
  1624.            gint    steps,
  1625.            gdouble delta,
  1626.            gint    counter,
  1627.            gboolean  preview_mode)
  1628. {
  1629.   gint i;
  1630.   gint x, y;
  1631.   gint index;
  1632.   gint last_index1 = -1;
  1633.   gint last_index2 = -1;
  1634.   gint rowstride;
  1635.   gint temp;
  1636.   gint j = counter;
  1637.  
  1638.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1639.  
  1640.   for (i = 0; i < steps; i++)
  1641.     {
  1642.       x = x_offset
  1643.     + *(*(globals.blend_inner_cachex1[RIGHT] + j) + i);
  1644.       y = curve_start_offset
  1645.     + *(*(globals.blend_inner_cachey1[RIGHT] + j) + i);
  1646.       index = y * rowstride + x * bytes;
  1647.       if (index != last_index1)
  1648.     {
  1649.       if (i < steps / 1.3)
  1650.         {
  1651.           LIGHTEN_POINT(buffer, index, delta, temp);
  1652.         }
  1653.       else
  1654.         {
  1655.           DARKEN_POINT(buffer, index, delta, temp);
  1656.         }
  1657.       last_index1 = index;
  1658.     }
  1659.  
  1660.       x = x_offset
  1661.     + *(*(globals.blend_inner_cachex2[RIGHT] + j) + i);
  1662.       y = curve_start_offset
  1663.     + *(*(globals.blend_inner_cachey2[RIGHT] + j) + i);
  1664.       index = y * rowstride + x * bytes;
  1665.       if (index != last_index2)
  1666.     {
  1667.       DARKEN_POINT(buffer, index, delta, temp);
  1668.       last_index2 = index;
  1669.     }
  1670.     }
  1671. }
  1672.  
  1673. static void
  1674. lighten_right_bump (guchar   *buffer,
  1675.             gint      width,
  1676.             gint      bytes,
  1677.             gint      x_offset,
  1678.             gint      curve_start_offset,
  1679.             gint      steps,
  1680.             gdouble   delta,
  1681.             gint      counter,
  1682.             gboolean  preview_mode)
  1683. {
  1684.   gint i;
  1685.   gint x, y;
  1686.   gint index;
  1687.   gint last_index1 = -1;
  1688.   gint last_index2 = -1;
  1689.   gint rowstride;
  1690.   gint temp;
  1691.   gint j = counter;
  1692.  
  1693.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1694.  
  1695.   for (i = 0; i < steps; i++)
  1696.     {
  1697.       x = x_offset
  1698.     + *(*(globals.blend_outer_cachex1[RIGHT] + j) + i);
  1699.       y = curve_start_offset
  1700.     + *(*(globals.blend_outer_cachey1[RIGHT] + j) + i);
  1701.       index = y * rowstride + x * bytes;
  1702.       if (index != last_index1)
  1703.     {
  1704.       if (i < steps / 1.3)
  1705.         {
  1706.           DARKEN_POINT(buffer, index, delta, temp);
  1707.         }
  1708.       else
  1709.         {
  1710.           LIGHTEN_POINT(buffer, index, delta, temp);
  1711.         }
  1712.       last_index1 = index;
  1713.     }
  1714.       
  1715.       x = x_offset
  1716.     + *(*(globals.blend_outer_cachex2[RIGHT] + j) + i);
  1717.       y = curve_start_offset
  1718.     + *(*(globals.blend_outer_cachey2[RIGHT] + j) + i);
  1719.       index = y * rowstride + x * bytes;
  1720.       if (index != last_index2)
  1721.     {
  1722.       LIGHTEN_POINT(buffer, index, delta, temp);
  1723.       last_index2 = index;
  1724.     }
  1725.     }
  1726. }
  1727.  
  1728. static void
  1729. darken_left_bump (guchar   *buffer,
  1730.           gint      width,
  1731.           gint      bytes,
  1732.           gint      x_offset,
  1733.           gint      curve_start_offset,
  1734.           gint      steps,
  1735.           gdouble   delta,
  1736.           gint      counter,
  1737.           gboolean  preview_mode)
  1738. {
  1739.   gint i;
  1740.   gint x, y;
  1741.   gint index;
  1742.   gint last_index1 = -1;
  1743.   gint last_index2 = -1;
  1744.   gint rowstride;
  1745.   gint temp;
  1746.   gint j = counter;
  1747.  
  1748.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1749.  
  1750.   for (i = 0; i < steps; i++)
  1751.     {
  1752.       x = x_offset
  1753.     + *(*(globals.blend_outer_cachex1[LEFT] + j) + i);
  1754.       y = curve_start_offset
  1755.     + *(*(globals.blend_outer_cachey1[LEFT] + j) + i);
  1756.       index = y * rowstride + x * bytes;
  1757.       if (index != last_index1)
  1758.     {
  1759.       DARKEN_POINT(buffer, index, delta, temp);
  1760.       last_index1 = index;
  1761.     }
  1762.  
  1763.       x = x_offset
  1764.     + *(*(globals.blend_outer_cachex2[LEFT] + j) + i);
  1765.       y = curve_start_offset
  1766.     + *(*(globals.blend_outer_cachey2[LEFT] + j) + i);
  1767.       index = y * rowstride + x * bytes;
  1768.       if (index != last_index2)
  1769.     {
  1770.       if (i < steps / 4)
  1771.         {
  1772.           DARKEN_POINT(buffer, index, delta, temp);
  1773.         }
  1774.       else
  1775.         {
  1776.           LIGHTEN_POINT(buffer, index, delta, temp);
  1777.         }
  1778.       last_index2 = index;
  1779.     }
  1780.     }
  1781. }
  1782.  
  1783. static void
  1784. lighten_left_bump (guchar *buffer,
  1785.            gint    width,
  1786.            gint    bytes,
  1787.            gint    x_offset,
  1788.            gint    curve_start_offset,
  1789.            gint    steps,
  1790.            gdouble delta,
  1791.            gint    counter,
  1792.            gboolean  preview_mode)
  1793. {
  1794.   gint i;
  1795.   gint x, y;
  1796.   gint index;
  1797.   gint last_index1 = -1; 
  1798.   gint last_index2 = -1;
  1799.   gint rowstride;
  1800.   gint temp;
  1801.   gint j = counter;
  1802.  
  1803.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1804.  
  1805.   for (i = 0; i < steps; i++)
  1806.     {
  1807.       x = x_offset
  1808.     + *(*(globals.blend_inner_cachex1[LEFT] + j) + i);
  1809.       y = curve_start_offset
  1810.     + *(*(globals.blend_inner_cachey1[LEFT] + j) + i);
  1811.       index = y * rowstride + x * bytes;
  1812.       if (index != last_index1)
  1813.     {
  1814.       LIGHTEN_POINT(buffer, index, delta, temp);
  1815.       last_index1 = index;
  1816.     }
  1817.  
  1818.       x = x_offset
  1819.     + *(*(globals.blend_inner_cachex2[LEFT] + j) + i);
  1820.       y = curve_start_offset
  1821.     + *(*(globals.blend_inner_cachey2[LEFT] + j) + i);
  1822.       index = y * rowstride + x * bytes;
  1823.       if (index != last_index2)
  1824.     {
  1825.       if (i < steps / 4)
  1826.         {
  1827.           LIGHTEN_POINT(buffer, index, delta, temp);
  1828.         }
  1829.       else
  1830.         {
  1831.           DARKEN_POINT(buffer, index, delta, temp);
  1832.         }
  1833.       last_index2 = index;
  1834.     }
  1835.     }
  1836. }
  1837.  
  1838. static void
  1839. darken_up_bump (guchar   *buffer,
  1840.         gint      width,
  1841.         gint      bytes,
  1842.         gint      y_offset,
  1843.         gint      curve_start_offset,
  1844.         gint      steps,
  1845.         gdouble   delta,
  1846.         gint      counter,
  1847.         gboolean  preview_mode)
  1848. {
  1849.   gint i;
  1850.   gint x, y;
  1851.   gint index;
  1852.   gint last_index1 = -1;
  1853.   gint last_index2 = -1;
  1854.   gint rowstride;
  1855.   gint temp;
  1856.   gint j = counter;
  1857.  
  1858.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1859.  
  1860.   for (i = 0; i < steps; i++)
  1861.     {
  1862.       x = curve_start_offset
  1863.     + *(*(globals.blend_outer_cachex1[UP] + j) + i);
  1864.       y = y_offset
  1865.     + *(*(globals.blend_outer_cachey1[UP] + j) + i);
  1866.       index = y * rowstride + x * bytes;
  1867.       if (index != last_index1)
  1868.     {
  1869.       DARKEN_POINT(buffer, index, delta, temp);
  1870.       last_index1 = index;
  1871.     }
  1872.  
  1873.       x = curve_start_offset
  1874.     + *(*(globals.blend_outer_cachex2[UP] + j) + i);
  1875.       y = y_offset
  1876.     + *(*(globals.blend_outer_cachey2[UP] + j) + i);
  1877.       index = y * rowstride + x * bytes;
  1878.       if (index != last_index2)
  1879.     {
  1880.       if (i < steps / 4)
  1881.         {
  1882.           DARKEN_POINT(buffer, index, delta, temp);
  1883.         }
  1884.       else
  1885.         {
  1886.           LIGHTEN_POINT(buffer, index, delta, temp);
  1887.         }
  1888.       last_index2 = index;
  1889.     }
  1890.     }
  1891. }
  1892.  
  1893. static void
  1894. lighten_up_bump (guchar   *buffer,
  1895.          gint      width,
  1896.          gint      bytes,
  1897.          gint      y_offset,
  1898.          gint      curve_start_offset,
  1899.          gint      steps,
  1900.          gdouble   delta,
  1901.          gint      counter,
  1902.          gboolean  preview_mode)
  1903. {
  1904.   gint i;
  1905.   gint x, y;
  1906.   gint index;
  1907.   gint last_index1 = -1;
  1908.   gint last_index2 = -1;
  1909.   gint rowstride;
  1910.   gint temp;
  1911.   gint j = counter;
  1912.  
  1913.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1914.  
  1915.   for (i = 0; i < steps; i++)
  1916.     {
  1917.       x = curve_start_offset
  1918.     + *(*(globals.blend_inner_cachex1[UP] + j) + i);
  1919.       y = y_offset
  1920.     + *(*(globals.blend_inner_cachey1[UP] + j) + i);
  1921.       index = y * rowstride + x * bytes;
  1922.       if (index != last_index1)
  1923.     {
  1924.       LIGHTEN_POINT(buffer, index, delta, temp);
  1925.       last_index1 = index;
  1926.     }
  1927.  
  1928.       x = curve_start_offset
  1929.     + *(*(globals.blend_inner_cachex2[UP] + j) + i);
  1930.       y = y_offset
  1931.     + *(*(globals.blend_inner_cachey2[UP] + j) + i);
  1932.       index = y * rowstride + x * bytes;
  1933.       if (index != last_index2)
  1934.     {
  1935.       if (i < steps / 4)
  1936.         {
  1937.           LIGHTEN_POINT(buffer, index, delta, temp);
  1938.         }
  1939.       else
  1940.         {
  1941.           DARKEN_POINT(buffer, index, delta, temp);
  1942.         }
  1943.       last_index2 = index;
  1944.     }
  1945.     }
  1946. }
  1947.  
  1948. static void
  1949. darken_down_bump (guchar   *buffer,
  1950.           gint      width,
  1951.           gint      bytes,
  1952.           gint      y_offset,
  1953.           gint      curve_start_offset,
  1954.           gint      steps,
  1955.           gdouble   delta,
  1956.           gint      counter,
  1957.           gboolean  preview_mode)
  1958. {
  1959.   gint i;
  1960.   gint x, y;
  1961.   gint index;
  1962.   gint last_index1 = -1;
  1963.   gint last_index2 = -1;
  1964.   gint rowstride;
  1965.   gint temp;
  1966.   gint j = counter;
  1967.  
  1968.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  1969.  
  1970.   for (i = 0; i < steps; i++)
  1971.     {
  1972.       x = curve_start_offset
  1973.     + *(*(globals.blend_inner_cachex1[DOWN] + j) + i);
  1974.       y = y_offset
  1975.     + *(*(globals.blend_inner_cachey1[DOWN] + j) + i);
  1976.       index = y * rowstride + x * bytes;
  1977.       if (index != last_index1)
  1978.     {
  1979.       if (i < steps / 1.2)
  1980.         {
  1981.           LIGHTEN_POINT(buffer, index, delta, temp);
  1982.         }
  1983.       else
  1984.         {
  1985.           DARKEN_POINT(buffer, index, delta, temp);
  1986.         }
  1987.       last_index1 = index;
  1988.     }
  1989.  
  1990.       x = curve_start_offset
  1991.     + *(*(globals.blend_inner_cachex2[DOWN] + j) + i);
  1992.       y = y_offset
  1993.     + *(*(globals.blend_inner_cachey2[DOWN] + j) + i);
  1994.       index = y * rowstride + x * bytes;
  1995.       if (index != last_index2)
  1996.     {
  1997.       DARKEN_POINT(buffer, index, delta, temp);
  1998.       last_index2 = index;
  1999.     }
  2000.     }
  2001. }
  2002.  
  2003. static void
  2004. lighten_down_bump (guchar   *buffer,
  2005.            gint      width,
  2006.            gint      bytes,
  2007.            gint      y_offset,
  2008.            gint      curve_start_offset,
  2009.            gint      steps,
  2010.            gdouble   delta,
  2011.            gint      counter,
  2012.            gboolean  preview_mode)
  2013. {
  2014.   gint i;
  2015.   gint x, y;
  2016.   gint index;
  2017.   gint last_index1 = -1;
  2018.   gint last_index2 = -1;
  2019.   gint rowstride;
  2020.   gint temp;
  2021.   gint j = counter;
  2022.  
  2023.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  2024.  
  2025.   for (i = 0; i < steps; i++)
  2026.     {
  2027.       x = curve_start_offset
  2028.     + *(*(globals.blend_outer_cachex1[DOWN] + j) + i);
  2029.       y = y_offset
  2030.     + *(*(globals.blend_outer_cachey1[DOWN] + j) + i);
  2031.       index = y * rowstride + x * bytes;
  2032.       if (index != last_index1)
  2033.     {
  2034.       if (i < steps / 1.2)
  2035.         {
  2036.           DARKEN_POINT(buffer, index, delta, temp);
  2037.         }
  2038.       else
  2039.         {
  2040.           LIGHTEN_POINT(buffer, index, delta, temp);
  2041.         }
  2042.       last_index1 = index;
  2043.     }
  2044.  
  2045.       x = curve_start_offset
  2046.     + *(*(globals.blend_outer_cachex2[DOWN] + j) + i);
  2047.       y = y_offset
  2048.     + *(*(globals.blend_outer_cachey2[DOWN] + j) + i);
  2049.       index = y * rowstride + x * bytes;
  2050.       if (index != last_index2)
  2051.     {
  2052.       LIGHTEN_POINT(buffer, index, delta, temp);
  2053.       last_index2 = index;
  2054.     }
  2055.     }
  2056. }
  2057.  
  2058. static void
  2059. draw_bezier_line (guchar   *buffer,
  2060.           gint      width,
  2061.           gint      bytes,
  2062.           gint      steps,
  2063.           gint     *cx,
  2064.           gint     *cy,
  2065.           gboolean  preview_mode)
  2066. {
  2067.   gint i;
  2068.   gint x, y;
  2069.   gint index;
  2070.   gint rowstride;
  2071.  
  2072.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  2073.  
  2074.   for (i = 0; i < steps; i++)
  2075.     {
  2076.       x = cx[i];
  2077.       y = cy[i];
  2078.       index = y * rowstride + x * bytes;
  2079.       DRAW_POINT(buffer, index);
  2080.     }
  2081. }
  2082.  
  2083. static void
  2084. darken_bezier_line (guchar   *buffer,
  2085.             gint      width,
  2086.             gint      bytes,
  2087.             gint      x_offset,
  2088.             gint      y_offset,
  2089.             gint      steps,
  2090.             gint     *cx,
  2091.             gint     *cy,
  2092.             gdouble   delta,
  2093.             gboolean  preview_mode)
  2094. {
  2095.   gint i;
  2096.   gint x, y;
  2097.   gint index;
  2098.   gint last_index = -1;
  2099.   gint rowstride;
  2100.   gint temp;
  2101.  
  2102.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  2103.  
  2104.   for (i = 0; i < steps; i++)
  2105.     {
  2106.       x = cx[i] + x_offset;
  2107.       y = cy[i] + y_offset;
  2108.       index = y * rowstride + x * bytes;
  2109.       if (index != last_index)
  2110.     {
  2111.       DARKEN_POINT(buffer, index, delta, temp);
  2112.       last_index = index;
  2113.     }
  2114.     }
  2115. }
  2116.  
  2117. static void
  2118. lighten_bezier_line (guchar   *buffer,
  2119.              gint      width,
  2120.              gint      bytes,
  2121.              gint      x_offset,
  2122.              gint      y_offset,
  2123.              gint      steps,
  2124.              gint     *cx,
  2125.              gint     *cy,
  2126.              gdouble   delta,
  2127.              gboolean  preview_mode)
  2128. {
  2129.   gint i;
  2130.   gint x, y;
  2131.   gint index;
  2132.   gint last_index = -1;
  2133.   gint rowstride;
  2134.   gint temp;
  2135.  
  2136.   rowstride = preview_mode ? GTK_PREVIEW (preview)->rowstride : bytes * width;
  2137.  
  2138.   for (i = 0; i < steps; i++)
  2139.     {
  2140.       x = cx[i] + x_offset;
  2141.       y = cy[i] + y_offset;
  2142.       index = y * rowstride + x * bytes;
  2143.       if (index != last_index)
  2144.     {
  2145.       LIGHTEN_POINT(buffer, index, delta, temp);
  2146.       last_index = index;
  2147.     }
  2148.     }
  2149. }
  2150.  
  2151. static void
  2152. draw_bezier_vertical_border (guchar   *buffer,
  2153.                  gint      width,
  2154.                  gint      height,
  2155.                  gint      bytes,
  2156.                  gint      x_offset,
  2157.                  gint      xtiles,
  2158.                  gint      ytiles,
  2159.                  gint      blend_lines,
  2160.                  gdouble   blend_amount,
  2161.                  gint      steps,
  2162.                  gboolean  preview_mode)
  2163. {
  2164.   gint i, j;
  2165.   gint tile_width = width / xtiles;
  2166.   gint tile_height = height / ytiles;
  2167.   gint tile_height_eighth = tile_height / 8;
  2168.   gint curve_start_offset = 3 * tile_height_eighth;
  2169.   gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth;
  2170.   gint px[4], py[4];
  2171.   gint y_offset = 0;
  2172.   gdouble delta;
  2173.   gdouble sigma = blend_amount / blend_lines;
  2174.   gint right;
  2175.   bump_t style_index;
  2176.   gint *cachex, *cachey;
  2177.  
  2178.   cachex = g_new (gint, steps);
  2179.   cachey = g_new (gint, steps);
  2180.   
  2181.   for (i = 0; i < ytiles; i++)
  2182.     {
  2183.       right = rand() & 1;
  2184.       if (right)
  2185.     {
  2186.       style_index = RIGHT;
  2187.     }
  2188.       else
  2189.     {
  2190.       style_index = LEFT;
  2191.     }
  2192.       px[0] = px[3] = x_offset;
  2193.       px[1] = x_offset + WALL_XFACTOR2 * tile_width * FUDGE;
  2194.       px[2] = x_offset + WALL_XFACTOR3 * tile_width * FUDGE;
  2195.       py[0] = y_offset;
  2196.       py[1] = y_offset + WALL_YCONS2 * tile_height;
  2197.       py[2] = y_offset + WALL_YCONS3 * tile_height;
  2198.       py[3] = y_offset + curve_start_offset;
  2199.  
  2200.       if (right)
  2201.     {
  2202.       px[1] = x_offset - WALL_XFACTOR2 * tile_width;
  2203.       px[2] = x_offset - WALL_XFACTOR3 * tile_width;
  2204.     }
  2205.       generate_bezier (px, py, steps, cachex, cachey);
  2206.       draw_bezier_line (buffer, width, bytes, steps, cachex, cachey, preview_mode);
  2207.       delta = blend_amount;
  2208.       for (j = 0; j < blend_lines; j++)
  2209.     {
  2210.       px[0] =  -j - 1;
  2211.       darken_bezier_line(buffer, width, bytes, px[0], 0,
  2212.                  steps, cachex, cachey, delta, preview_mode);
  2213.       px[0] =  j + 1;
  2214.       lighten_bezier_line(buffer, width, bytes, px[0], 0,
  2215.                   steps, cachex, cachey, delta, preview_mode);
  2216.       delta -= sigma;
  2217.     }
  2218.       if (right)
  2219.     {
  2220.       draw_right_bump(buffer, width, bytes, x_offset,
  2221.               y_offset + curve_start_offset,
  2222.               globals.steps[RIGHT], preview_mode);
  2223.       delta = blend_amount;
  2224.       for (j = 0; j < blend_lines; j++)
  2225.         {
  2226.           /* use to be -j -1 */
  2227.           darken_right_bump(buffer, width, bytes, x_offset,
  2228.                 y_offset + curve_start_offset,
  2229.                 globals.steps[RIGHT], delta, j, preview_mode);
  2230.           /* use to be +j + 1 */
  2231.           lighten_right_bump(buffer, width, bytes, x_offset,
  2232.                  y_offset + curve_start_offset,
  2233.                  globals.steps[RIGHT], delta, j, preview_mode);
  2234.           delta -= sigma;
  2235.         }
  2236.     }
  2237.       else
  2238.     {
  2239.       draw_left_bump(buffer, width, bytes, x_offset,
  2240.              y_offset + curve_start_offset,
  2241.              globals.steps[LEFT], preview_mode);
  2242.       delta = blend_amount;
  2243.       for (j = 0; j < blend_lines; j++)
  2244.         {
  2245.           /* use to be -j -1 */
  2246.           darken_left_bump(buffer, width, bytes, x_offset,
  2247.                    y_offset + curve_start_offset,
  2248.                    globals.steps[LEFT], delta, j, preview_mode);
  2249.           /* use to be -j - 1 */
  2250.           lighten_left_bump(buffer, width, bytes, x_offset,
  2251.                 y_offset + curve_start_offset,
  2252.                 globals.steps[LEFT], delta, j, preview_mode);
  2253.           delta -= sigma;
  2254.         }
  2255.     }
  2256.       px[0] = px[3] = x_offset;
  2257.       px[1] = x_offset + WALL_XFACTOR2 * tile_width * FUDGE;
  2258.       px[2] = x_offset + WALL_XFACTOR3 * tile_width * FUDGE;
  2259.       py[0] = y_offset + curve_end_offset;
  2260.       py[1] = y_offset + curve_end_offset + WALL_YCONS2 * tile_height;
  2261.       py[2] = y_offset + curve_end_offset + WALL_YCONS3 * tile_height;
  2262.       py[3] = globals.gridy[i];
  2263.       if (right)
  2264.     {
  2265.       px[1] = x_offset - WALL_XFACTOR2 * tile_width;
  2266.       px[2] = x_offset - WALL_XFACTOR3 * tile_width;
  2267.     }
  2268.       generate_bezier(px, py, steps, cachex, cachey);
  2269.       draw_bezier_line(buffer, width, bytes, steps, cachex, cachey, preview_mode);
  2270.       delta = blend_amount;
  2271.       for (j = 0; j < blend_lines; j++)
  2272.     {
  2273.       px[0] =  -j - 1;
  2274.       darken_bezier_line(buffer, width, bytes, px[0], 0,
  2275.                  steps, cachex, cachey, delta, preview_mode);
  2276.       px[0] =  j + 1;
  2277.       lighten_bezier_line(buffer, width, bytes, px[0], 0,
  2278.                   steps, cachex, cachey, delta, preview_mode);
  2279.       delta -= sigma;
  2280.     }
  2281.       y_offset = globals.gridy[i];
  2282.     }  /* for */
  2283.   g_free(cachex);
  2284.   g_free(cachey);
  2285. }
  2286.  
  2287. static void
  2288. draw_bezier_horizontal_border (guchar   *buffer,
  2289.                    gint      width,
  2290.                    gint      height,
  2291.                    gint      bytes,
  2292.                    gint      y_offset,
  2293.                    gint      xtiles,
  2294.                    gint      ytiles,
  2295.                    gint      blend_lines,
  2296.                    gdouble   blend_amount,
  2297.                    gint      steps,
  2298.                    gboolean  preview_mode)
  2299. {
  2300.   gint i, j;
  2301.   gint tile_width = width / xtiles;
  2302.   gint tile_height = height / ytiles;
  2303.   gint tile_width_eighth = tile_width / 8;
  2304.   gint curve_start_offset = 3 * tile_width_eighth;
  2305.   gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth;
  2306.   gint px[4], py[4];
  2307.   gint x_offset = 0;
  2308.   gdouble delta;
  2309.   gdouble sigma = blend_amount / blend_lines;
  2310.   gint up;
  2311.   style_t style_index;
  2312.   gint *cachex, *cachey;
  2313.  
  2314.   cachex = g_malloc(steps * sizeof(gint));
  2315.   cachey = g_malloc(steps * sizeof(gint));
  2316.  
  2317.   for (i = 0; i < xtiles; i++)
  2318.     {
  2319.       up = rand() & 1;
  2320.       if (up)
  2321.     {
  2322.       style_index = UP;
  2323.     }
  2324.       else
  2325.     {
  2326.       style_index = DOWN;
  2327.     }
  2328.       px[0] = x_offset;
  2329.       px[1] = x_offset + WALL_XCONS2 * tile_width;
  2330.       px[2] = x_offset + WALL_XCONS3 * tile_width;
  2331.       px[3] = x_offset + curve_start_offset;
  2332.       py[0] = py[3] = y_offset;
  2333.       py[1] = y_offset + WALL_YFACTOR2 * tile_height * FUDGE;
  2334.       py[2] = y_offset + WALL_YFACTOR3 * tile_height * FUDGE;
  2335.       if (!up)
  2336.     {
  2337.       py[1] = y_offset - WALL_YFACTOR2 * tile_height;
  2338.       py[2] = y_offset - WALL_YFACTOR3 * tile_height;
  2339.     }
  2340.       generate_bezier(px, py, steps, cachex, cachey);
  2341.       draw_bezier_line(buffer, width, bytes, steps, cachex, cachey, preview_mode);
  2342.       delta = blend_amount;
  2343.       for (j = 0; j < blend_lines; j++)
  2344.     {
  2345.       py[0] = -j - 1;
  2346.       darken_bezier_line(buffer, width, bytes, 0, py[0], 
  2347.                  steps, cachex, cachey, delta, preview_mode);
  2348.       py[0] = j + 1;
  2349.       lighten_bezier_line(buffer, width, bytes, 0, py[0],
  2350.                   steps, cachex, cachey, delta, preview_mode);
  2351.       delta -= sigma;
  2352.     }
  2353.       /* bumps */
  2354.       if (up)
  2355.     {
  2356.       draw_up_bump(buffer, width, bytes, y_offset,
  2357.                x_offset + curve_start_offset,
  2358.                globals.steps[UP], preview_mode);
  2359.       delta = blend_amount;
  2360.       for (j = 0; j < blend_lines; j++)
  2361.         {
  2362.           /* use to be -j -1 */
  2363.           darken_up_bump(buffer, width, bytes, y_offset,
  2364.                  x_offset + curve_start_offset,
  2365.                  globals.steps[UP], delta, j, preview_mode);
  2366.           /* use to be +j + 1 */
  2367.           lighten_up_bump(buffer, width, bytes, y_offset,
  2368.                   x_offset + curve_start_offset,
  2369.                   globals.steps[UP], delta, j, preview_mode);
  2370.           delta -= sigma;
  2371.         }
  2372.     }
  2373.       else
  2374.     {
  2375.       draw_down_bump(buffer, width, bytes, y_offset,
  2376.              x_offset + curve_start_offset,
  2377.              globals.steps[DOWN], preview_mode);
  2378.       delta = blend_amount;
  2379.       for (j = 0; j < blend_lines; j++)
  2380.         {
  2381.           /* use to be +j + 1 */
  2382.           darken_down_bump(buffer, width, bytes, y_offset,
  2383.                    x_offset + curve_start_offset,
  2384.                    globals.steps[DOWN], delta, j, preview_mode);
  2385.           /* use to be -j -1 */
  2386.           lighten_down_bump(buffer, width, bytes, y_offset,
  2387.                 x_offset + curve_start_offset,
  2388.                 globals.steps[DOWN], delta, j, preview_mode);
  2389.           delta -= sigma;
  2390.         }
  2391.     }
  2392.       /* ending side wall line */
  2393.       px[0] = x_offset + curve_end_offset;
  2394.       px[1] = x_offset + curve_end_offset + WALL_XCONS2 * tile_width;
  2395.       px[2] = x_offset + curve_end_offset + WALL_XCONS3 * tile_width;
  2396.       px[3] = globals.gridx[i];
  2397.       py[0] = py[3] = y_offset;
  2398.       py[1] = y_offset + WALL_YFACTOR2 * tile_height * FUDGE;
  2399.       py[2] = y_offset + WALL_YFACTOR3 * tile_height * FUDGE;
  2400.       if (!up)
  2401.     {
  2402.       py[1] = y_offset - WALL_YFACTOR2 * tile_height;
  2403.       py[2] = y_offset - WALL_YFACTOR3 * tile_height;
  2404.     }
  2405.       generate_bezier(px, py, steps, cachex, cachey);
  2406.       draw_bezier_line(buffer, width, bytes, steps, cachex, cachey, preview_mode);
  2407.       delta = blend_amount;
  2408.       for (j = 0; j < blend_lines; j++)
  2409.     {
  2410.       py[0] =  -j - 1;
  2411.       darken_bezier_line(buffer, width, bytes, 0, py[0],
  2412.                  steps, cachex, cachey, delta, preview_mode);
  2413.       py[0] =  j + 1;
  2414.       lighten_bezier_line(buffer, width, bytes, 0, py[0],
  2415.                   steps, cachex, cachey, delta, preview_mode);
  2416.       delta -= sigma;
  2417.     }
  2418.       x_offset = globals.gridx[i];
  2419.     }  /* for */
  2420.   g_free(cachex);
  2421.   g_free(cachey);
  2422. }
  2423.  
  2424. static void
  2425. check_config (gint width,
  2426.           gint height)
  2427. {
  2428.   gint tile_width, tile_height;
  2429.   gint tile_width_limit, tile_height_limit;
  2430.   
  2431.   if (config.x < 1)
  2432.     {
  2433.       config.x = 1;
  2434.     }
  2435.   if (config.y < 1)
  2436.     {
  2437.       config.y = 1;
  2438.     }
  2439.   if (config.blend_amount < 0)
  2440.     {
  2441.       config.blend_amount = 0;
  2442.     }
  2443.   if (config.blend_amount > 5)
  2444.     {
  2445.       config.blend_amount = 5;
  2446.     }
  2447.   tile_width = width / config.x;
  2448.   tile_height = height / config.y;
  2449.   tile_width_limit = 0.4 * tile_width;
  2450.   tile_height_limit = 0.4 * tile_height;
  2451.   if ((config.blend_lines > tile_width_limit)
  2452.       || (config.blend_lines > tile_height_limit))
  2453.     {
  2454.       config.blend_lines = MIN(tile_width_limit, tile_height_limit);
  2455.     }
  2456. }
  2457.   
  2458. /********************************************************
  2459.   GUI
  2460. ********************************************************/
  2461.  
  2462. static void
  2463. dialog_box (void)
  2464. {
  2465.   GimpDrawable *drawable = globals.drawable;
  2466.   GtkWidget *dlg;
  2467.   GtkWidget *main_hbox;
  2468.   GtkWidget *abox;
  2469.  
  2470.   GtkWidget *main_vbox;
  2471.   GtkWidget *frame;
  2472.   GtkWidget *rbutton1;
  2473.   GtkWidget *rbutton2;
  2474.   GtkWidget *cbutton;
  2475.   GtkWidget *hbox;
  2476.   GtkWidget *table;
  2477.   GtkObject *adj;
  2478.  
  2479.   gimp_ui_init ("jigsaw", TRUE);
  2480.  
  2481.   dlg = gimp_dialog_new (_("Jigsaw"), "jigsaw",
  2482.              gimp_standard_help_func, "filters/jigsaw.html",
  2483.              GTK_WIN_POS_MOUSE,
  2484.              FALSE, TRUE, FALSE,
  2485.  
  2486.              _("OK"), run_callback,
  2487.              NULL, NULL, NULL, TRUE, FALSE,
  2488.              _("Cancel"), gtk_widget_destroy,
  2489.              NULL, 1, NULL, FALSE, TRUE,
  2490.  
  2491.              NULL);
  2492.  
  2493.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  2494.               GTK_SIGNAL_FUNC (gtk_main_quit),
  2495.               NULL);
  2496.  
  2497.   /* init tooltips */
  2498.   gimp_help_init ();
  2499.  
  2500.   if (globals.tooltips == 0)
  2501.     {
  2502.       gimp_help_disable_tooltips ();
  2503.     }
  2504.  
  2505.   main_hbox = gtk_hbox_new (FALSE, 2);
  2506.   gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 6);
  2507.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_hbox, TRUE, TRUE, 0);
  2508.   gtk_widget_show (main_hbox);
  2509.  
  2510.   /* make a nice frame */
  2511.   frame = gtk_frame_new (_("Preview"));
  2512.   gtk_container_set_border_width (GTK_CONTAINER (frame), 4);
  2513.   gtk_box_pack_start (GTK_BOX (main_hbox), frame, FALSE, FALSE, 0);
  2514.   gtk_widget_show (frame);
  2515.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  2516.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  2517.   gtk_container_add (GTK_CONTAINER (frame), abox);
  2518.   gtk_widget_show (abox);
  2519.   frame = gtk_frame_new (NULL);
  2520.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  2521.   gtk_container_add (GTK_CONTAINER (abox), frame);
  2522.   gtk_widget_show (frame);
  2523.   preview = preview_widget (drawable); /* we are here */
  2524.   gtk_container_add (GTK_CONTAINER (frame), preview);
  2525.   jigsaw(1); /* render preview */
  2526.   gtk_widget_show (preview);
  2527.   
  2528.   main_vbox = gtk_vbox_new (FALSE, 4);
  2529.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  2530.   gtk_box_pack_start (GTK_BOX (main_hbox), main_vbox, TRUE, TRUE, 0);
  2531.   gtk_widget_show (main_vbox);
  2532.  
  2533.   frame = gtk_frame_new (_("Number of Tiles"));
  2534.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  2535.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  2536.  
  2537.   table = gtk_table_new (2, 3, FALSE);
  2538.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  2539.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  2540.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  2541.   gtk_container_add (GTK_CONTAINER (frame), table);
  2542.  
  2543.   /* xtiles */
  2544.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  2545.                   _("Horizontal:"), SCALE_WIDTH, 0,
  2546.                   config.x, MIN_XTILES, MAX_XTILES, 1.0, 4.0, 0,
  2547.                   TRUE, 0, 0,
  2548.                   _("Number of pieces going across"), NULL);
  2549.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2550.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2551.               &config.x);
  2552.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2553.               GTK_SIGNAL_FUNC (jigsaw),
  2554.               NULL);
  2555.  
  2556.   /* ytiles */
  2557.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  2558.                   _("Vertical:"), SCALE_WIDTH, 0,
  2559.                   config.y, MIN_YTILES, MAX_YTILES, 1.0, 4.0, 0,
  2560.                   TRUE, 0, 0,
  2561.                   _("Number of pieces going down"), NULL);
  2562.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2563.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2564.               &config.y);
  2565.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2566.               GTK_SIGNAL_FUNC (jigsaw),
  2567.               NULL);
  2568.  
  2569.   gtk_widget_show (table);
  2570.   gtk_widget_show (frame);
  2571.  
  2572.   frame = gtk_frame_new (_("Bevel Edges"));
  2573.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  2574.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  2575.  
  2576.   table = gtk_table_new (2, 3, FALSE);
  2577.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  2578.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  2579.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  2580.   gtk_container_add (GTK_CONTAINER (frame), table);
  2581.  
  2582.   /* number of blending lines */
  2583.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  2584.                   _("Bevel Width:"), SCALE_WIDTH, 0,
  2585.                   config.blend_lines,
  2586.                   MIN_BLEND_LINES, MAX_BLEND_LINES, 1.0, 2.0, 0,
  2587.                   TRUE, 0, 0,
  2588.                   _("Degree of slope of each piece's edge"), NULL);
  2589.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2590.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2591.               &config.blend_lines);
  2592.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2593.               GTK_SIGNAL_FUNC (jigsaw),
  2594.               NULL);
  2595.  
  2596.   /* blending amount */
  2597.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  2598.                   _("Highlight:"), SCALE_WIDTH, 0,
  2599.                   config.blend_amount,
  2600.                   MIN_BLEND_AMOUNT, MAX_BLEND_AMOUNT, 0.05, 0.1, 2,
  2601.                   TRUE, 0, 0,
  2602.                   _("The amount of highlighting on the edges "
  2603.                 "of each piece"), NULL);
  2604.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2605.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  2606.               &config.blend_amount);
  2607.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2608.               GTK_SIGNAL_FUNC (jigsaw),
  2609.               NULL);
  2610.  
  2611.   gtk_widget_show (table);
  2612.   gtk_widget_show (frame);
  2613.   
  2614.   /* frame for primitive radio buttons */
  2615.  
  2616.   hbox = gtk_hbox_new (FALSE, 6);
  2617.   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
  2618.  
  2619.   frame = gimp_radio_group_new2 (TRUE, _("Jigsaw Style"),
  2620.                  jigsaw_radio_button_update,
  2621.                  &config.style, (gpointer) config.style,
  2622.  
  2623.                  _("Square"), (gpointer) BEZIER_1, &rbutton1,
  2624.                  _("Curved"), (gpointer) BEZIER_2, &rbutton2,
  2625.  
  2626.                  NULL);
  2627.  
  2628.   gimp_help_set_help_data (rbutton1, _("Each piece has straight sides"), NULL);
  2629.   gimp_help_set_help_data (rbutton2, _("Each piece has curved sides"), NULL);
  2630.  
  2631.   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
  2632.   gtk_widget_show (frame);
  2633.  
  2634.   table = gtk_table_new (1, 2, FALSE);
  2635.   gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
  2636.  
  2637.   cbutton = gtk_check_button_new_with_label (_("Disable Tooltips"));
  2638.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cbutton),
  2639.                 globals.tooltips ? FALSE : TRUE);
  2640.   gtk_signal_connect (GTK_OBJECT (cbutton), "toggled",
  2641.               GTK_SIGNAL_FUNC (check_button_callback),
  2642.               NULL);
  2643.   gtk_table_attach (GTK_TABLE (table), cbutton, 0, 1, 1, 2, 0, 0, 0, 20);
  2644.   gtk_widget_show (cbutton);
  2645.   gimp_help_set_help_data (cbutton, _("Toggle Tooltips on/off"), NULL);
  2646.  
  2647.   gtk_widget_show (table);
  2648.   gtk_widget_show (hbox);
  2649.   gtk_widget_show (dlg);
  2650.  
  2651.   gtk_main ();
  2652.   gimp_help_free ();
  2653.   gdk_flush ();
  2654.  
  2655.   return;
  2656. }
  2657.  
  2658. /***************************************************
  2659.   callbacks
  2660.  ***************************************************/
  2661.  
  2662. static void
  2663. run_callback (GtkWidget *widget,
  2664.           gpointer   data)
  2665. {
  2666.   globals.dialog_result = 1;
  2667.  
  2668.   gtk_widget_destroy (GTK_WIDGET (data));
  2669. }
  2670.  
  2671. static void
  2672. check_button_callback (GtkWidget *widget,
  2673.                gpointer   data)
  2674. {
  2675.   if (GTK_TOGGLE_BUTTON (widget)->active)
  2676.     {
  2677.       gimp_help_disable_tooltips ();
  2678.       globals.tooltips = 0;
  2679.     }
  2680.   else
  2681.     {
  2682.       gimp_help_enable_tooltips ();
  2683.       globals.tooltips = 1;
  2684.     }
  2685. }
  2686.  
  2687. static void
  2688. jigsaw_radio_button_update (GtkWidget *widget, 
  2689.                 gpointer data)
  2690. {
  2691.   gimp_radio_button_update (widget, data);
  2692.   if (GTK_TOGGLE_BUTTON (widget)->active)
  2693.     jigsaw (TRUE);
  2694. }
  2695.  
  2696.  
  2697. /* preview library */
  2698.  
  2699. static GtkWidget *
  2700. preview_widget (GimpDrawable *drawable)
  2701. {
  2702.   gint       size;
  2703.   GtkWidget *preview;
  2704.  
  2705.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  2706.   fill_preview_with_thumb (preview, drawable->id);
  2707.   size = GTK_PREVIEW (preview)->rowstride * GTK_PREVIEW (preview)->buffer_height;
  2708.   preview_bits = g_malloc (size);
  2709.   memcpy (preview_bits, GTK_PREVIEW (preview)->buffer, size);
  2710.  
  2711.   return preview;
  2712. }
  2713.  
  2714. static void
  2715. fill_preview_with_thumb (GtkWidget *widget, 
  2716.              gint32     drawable_ID)
  2717. {
  2718.   guchar  *drawable_data;
  2719.   gint     bpp;
  2720.   gint     x,y;
  2721.   gint     width  = PREVIEW_SIZE;
  2722.   gint     height = PREVIEW_SIZE;
  2723.   guchar  *src;
  2724.   gdouble  r, g, b, a;
  2725.   gdouble  c0, c1;
  2726.   guchar  *p0, *p1;
  2727.   guchar  *even, *odd;
  2728.  
  2729.   bpp = 0; /* Only returned */
  2730.   
  2731.   drawable_data = 
  2732.     gimp_drawable_get_thumbnail_data (drawable_ID, &width, &height, &bpp);
  2733.  
  2734.   if (width < 1 || height < 1)
  2735.     return;
  2736.  
  2737.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  2738.  
  2739.   even = g_malloc (width * 3);
  2740.   odd  = g_malloc (width * 3);
  2741.   src = drawable_data;
  2742.  
  2743.   for (y = 0; y < height; y++)
  2744.     {
  2745.       p0 = even;
  2746.       p1 = odd;
  2747.       
  2748.       for (x = 0; x < width; x++) 
  2749.     {
  2750.       if (bpp == 4)
  2751.         {
  2752.           r = ((gdouble)src[x*4+0]) / 255.0;
  2753.           g = ((gdouble)src[x*4+1]) / 255.0;
  2754.           b = ((gdouble)src[x*4+2]) / 255.0;
  2755.           a = ((gdouble)src[x*4+3]) / 255.0;
  2756.         }
  2757.       else if (bpp == 3)
  2758.         {
  2759.           r = ((gdouble)src[x*3+0]) / 255.0;
  2760.           g = ((gdouble)src[x*3+1]) / 255.0;
  2761.           b = ((gdouble)src[x*3+2]) / 255.0;
  2762.           a = 1.0;
  2763.         }
  2764.       else
  2765.         {
  2766.           r = ((gdouble)src[x*bpp+0]) / 255.0;
  2767.           g = b = r;
  2768.           if (bpp == 2)
  2769.         a = ((gdouble)src[x*bpp+1]) / 255.0;
  2770.           else
  2771.         a = 1.0;
  2772.         }
  2773.       
  2774.       if ((x / GIMP_CHECK_SIZE_SM) & 1) 
  2775.         {
  2776.           c0 = GIMP_CHECK_LIGHT;
  2777.           c1 = GIMP_CHECK_DARK;
  2778.         } 
  2779.       else 
  2780.         {
  2781.           c0 = GIMP_CHECK_DARK;
  2782.           c1 = GIMP_CHECK_LIGHT;
  2783.         }
  2784.       
  2785.     *p0++ = (c0 + (r - c0) * a) * 255.0;
  2786.     *p0++ = (c0 + (g - c0) * a) * 255.0;
  2787.     *p0++ = (c0 + (b - c0) * a) * 255.0;
  2788.     
  2789.     *p1++ = (c1 + (r - c1) * a) * 255.0;
  2790.     *p1++ = (c1 + (g - c1) * a) * 255.0;
  2791.     *p1++ = (c1 + (b - c1) * a) * 255.0;
  2792.     
  2793.       } /* for */
  2794.       
  2795.       if ((y / GIMP_CHECK_SIZE_SM) & 1)
  2796.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)odd,  0, y, width);
  2797.       else
  2798.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)even, 0, y, width);
  2799.  
  2800.       src += width * bpp;
  2801.     }
  2802.  
  2803.   g_free (even);
  2804.   g_free (odd);
  2805.   g_free (drawable_data);
  2806. }
  2807.