diff options
Diffstat (limited to 'plug-ins/common/jigsaw.c')
-rw-r--r-- | plug-ins/common/jigsaw.c | 2563 |
1 files changed, 2563 insertions, 0 deletions
diff --git a/plug-ins/common/jigsaw.c b/plug-ins/common/jigsaw.c new file mode 100644 index 0000000..eade3d3 --- /dev/null +++ b/plug-ins/common/jigsaw.c @@ -0,0 +1,2563 @@ +/* + * jigsaw - a plug-in for GIMP + * + * Copyright (C) Nigel Wetten + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Contact info: nigel@cs.nwu.edu + * + * Version: 1.0.0 + * + * Version: 1.0.1 + * + * tim coppefield [timecop@japan.co.jp] + * + * Added dynamic preview mode. + * + * Damn, this plugin is the tightest piece of code I ever seen. + * I wish all filters in the plugins operated on guchar *buffer + * of the entire image :) sweet stuff. + * + */ + +#include "config.h" + +#include <string.h> + +#include <libgimp/gimp.h> +#include <libgimp/gimpui.h> + +#include "libgimp/stdplugins-intl.h" + + +#define PLUG_IN_PROC "plug-in-jigsaw" +#define PLUG_IN_BINARY "jigsaw" +#define PLUG_IN_ROLE "gimp-jigsaw" + + +typedef enum +{ + BEZIER_1, + BEZIER_2 +} style_t; + +typedef enum +{ + LEFT, + RIGHT, + UP, + DOWN +} bump_t; + + +static void query (void); +static void run (const gchar *name, + gint nparams, + const GimpParam *param, + gint *nreturn_vals, + GimpParam **return_vals); + +static void jigsaw (guint32 drawable_id, + GimpPreview *preview); +static void jigsaw_preview (gpointer drawable_id, + GimpPreview *preview); + +static gboolean jigsaw_dialog (guint32 drawable_id); + +static void draw_jigsaw (guchar *buffer, + gint bufsize, + gint width, + gint height, + gint bytes, + gboolean preview_mode); + +static void draw_vertical_border (guchar *buffer, gint bufsize, + gint width, gint height, + gint bytes, gint x_offset, gint ytiles, + gint blend_lines, gdouble blend_amount); +static void draw_horizontal_border (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint y_offset, gint xtiles, + gint blend_lines, gdouble blend_amount); +static void draw_vertical_line (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint px[2], gint py[2]); +static void draw_horizontal_line (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint px[2], gint py[2]); +static void darken_vertical_line (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint *px, gint *py, gdouble delta); +static void lighten_vertical_line (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint *px, gint *py, gdouble delta); +static void darken_horizontal_line (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint *px, gint *py, gdouble delta); +static void lighten_horizontal_line(guchar *buffer, gint bufsize, + gint width, gint bytes, + gint *px, gint *py, gdouble delta); +static void draw_right_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint x_offset, gint curve_start_offset, + gint steps); +static void draw_left_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint x_offset, gint curve_start_offset, + gint steps); +static void draw_up_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint y_offset, gint curve_start_offset, + gint steps); +static void draw_down_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint y_offset, gint curve_start_offset, + gint steps); +static void darken_right_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint x_offset, gint curve_start_offset, + gint steps, gdouble delta, gint counter); +static void lighten_right_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint x_offset, gint curve_start_offset, + gint steps, gdouble delta, gint counter); +static void darken_left_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint x_offset, gint curve_start_offset, + gint steps, gdouble delta, gint counter); +static void lighten_left_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint x_offset, gint curve_start_offset, + gint steps, gdouble delta, gint counter); +static void darken_up_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint y_offset, gint curve_start_offest, + gint steps, gdouble delta, gint counter); +static void lighten_up_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint y_offset, gint curve_start_offset, + gint steps, gdouble delta, gint counter); +static void darken_down_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint y_offset, gint curve_start_offset, + gint steps, gdouble delta, gint counter); +static void lighten_down_bump (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint y_offset, gint curve_start_offset, + gint steps, gdouble delta, gint counter); +static void generate_grid (gint width, gint height, gint xtiles, gint ytiles, + gint *x, gint *y); +static void generate_bezier (gint px[4], gint py[4], gint steps, + gint *cachex, gint *cachey); +static void malloc_cache (void); +static void free_cache (void); +static void init_right_bump (gint width, gint height); +static void init_left_bump (gint width, gint height); +static void init_up_bump (gint width, gint height); +static void init_down_bump (gint width, gint height); +static void draw_bezier_line (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint steps, gint *cx, gint *cy); +static void darken_bezier_line (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint x_offset, gint y_offset, gint steps, + gint *cx, gint *cy, gdouble delta); +static void lighten_bezier_line (guchar *buffer, gint bufsize, + gint width, gint bytes, + gint x_offset, gint y_offset, gint steps, + gint *cx, gint *cy, gdouble delta); +static void draw_bezier_vertical_border (guchar *buffer, gint bufsize, + gint width, gint height, + gint bytes, + gint x_offset, gint xtiles, + gint ytiles, gint blend_lines, + gdouble blend_amount, gint steps); +static void draw_bezier_horizontal_border (guchar *buffer, gint bufsize, + gint width, gint height, + gint bytes, + gint x_offset, gint xtiles, + gint ytiles, gint blend_lines, + gdouble blend_amount, gint steps); +static void check_config (gint width, gint height); + + + +#define XFACTOR2 0.0833 +#define XFACTOR3 0.2083 +#define XFACTOR4 0.2500 + +#define XFACTOR5 0.2500 +#define XFACTOR6 0.2083 +#define XFACTOR7 0.0833 + +#define YFACTOR2 0.1000 +#define YFACTOR3 0.2200 +#define YFACTOR4 0.1000 + +#define YFACTOR5 0.1000 +#define YFACTOR6 0.4666 +#define YFACTOR7 0.1000 +#define YFACTOR8 0.2000 + +#define MAX_VALUE 255 +#define MIN_VALUE 0 +#define DELTA 0.15 + +#define BLACK_R 30 +#define BLACK_G 30 +#define BLACK_B 30 + +#define WALL_XFACTOR2 0.05 +#define WALL_XFACTOR3 0.05 +#define WALL_YFACTOR2 0.05 +#define WALL_YFACTOR3 0.05 + +#define WALL_XCONS2 0.2 +#define WALL_XCONS3 0.3 +#define WALL_YCONS2 0.2 +#define WALL_YCONS3 0.3 + +#define FUDGE 1.2 + +#define MIN_XTILES 1 +#define MAX_XTILES 20 +#define MIN_YTILES 1 +#define MAX_YTILES 20 +#define MIN_BLEND_LINES 0 +#define MAX_BLEND_LINES 10 +#define MIN_BLEND_AMOUNT 0 +#define MAX_BLEND_AMOUNT 1.0 + +#define SCALE_WIDTH 200 + +#define DRAW_POINT(buffer, bufsize, index) \ + do \ + { \ + if ((index) >= 0 && (index) + 2 < (bufsize)) \ + { \ + buffer[(index) + 0] = BLACK_R; \ + buffer[(index) + 1] = BLACK_G; \ + buffer[(index) + 2] = BLACK_B; \ + } \ + } \ + while (0) + +#define DARKEN_POINT(buffer, bufsize, index, delta, temp) \ + do \ + { \ + if ((index) >= 0 && (index) + 2 < (bufsize)) \ + { \ + temp = MAX (buffer[(index) + 0] * (1.0 - (delta)), MIN_VALUE); \ + buffer[(index) + 0] = temp; \ + temp = MAX (buffer[(index) + 1] * (1.0 - (delta)), MIN_VALUE); \ + buffer[(index) + 1] = temp; \ + temp = MAX (buffer[(index) + 2] * (1.0 - (delta)), MIN_VALUE); \ + buffer[(index) + 2] = temp; \ + } \ + } \ + while (0) + +#define LIGHTEN_POINT(buffer, bufsize, index, delta, temp) \ + do \ + { \ + if ((index) >= 0 && (index) + 2 < (bufsize)) \ + { \ + temp = MIN (buffer[(index) + 0] * (1.0 + (delta)), MAX_VALUE); \ + buffer[(index) + 0] = temp; \ + temp = MIN (buffer[(index) + 1] * (1.0 + (delta)), MAX_VALUE); \ + buffer[(index) + 1] = temp; \ + temp = MIN (buffer[(index) + 2] * (1.0 + (delta)), MAX_VALUE); \ + buffer[(index) + 2] = temp; \ + } \ + } \ + while (0) + + +const GimpPlugInInfo PLUG_IN_INFO = +{ + NULL, + NULL, + query, + run +}; + +struct config_tag +{ + gint x; + gint y; + style_t style; + gint blend_lines; + gdouble blend_amount; +}; + + +typedef struct config_tag config_t; + +static config_t config = +{ + 5, + 5, + BEZIER_1, + 3, + 0.5 +}; + +struct globals_tag +{ + gint *cachex1[4]; + gint *cachex2[4]; + gint *cachey1[4]; + gint *cachey2[4]; + gint steps[4]; + gint *gridx; + gint *gridy; + gint **blend_outer_cachex1[4]; + gint **blend_outer_cachex2[4]; + gint **blend_outer_cachey1[4]; + gint **blend_outer_cachey2[4]; + gint **blend_inner_cachex1[4]; + gint **blend_inner_cachex2[4]; + gint **blend_inner_cachey1[4]; + gint **blend_inner_cachey2[4]; +}; + +typedef struct globals_tag globals_t; + +static globals_t globals; + +MAIN () + +static void +query (void) +{ + static const GimpParamDef args[] = + { + { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" }, + { GIMP_PDB_IMAGE, "image", "Input image" }, + { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }, + { GIMP_PDB_INT32, "x", "Number of tiles across > 0" }, + { GIMP_PDB_INT32, "y", "Number of tiles down > 0" }, + { GIMP_PDB_INT32, "style", "The style/shape of the jigsaw puzzle { 0, 1 }" }, + { GIMP_PDB_INT32, "blend-lines", "Number of lines for shading bevels >= 0" }, + { GIMP_PDB_FLOAT, "blend-amount", "The power of the light highlights 0 =< 5" } + }; + + gimp_install_procedure (PLUG_IN_PROC, + N_("Add a jigsaw-puzzle pattern to the image"), + "Jigsaw puzzle look", + "Nigel Wetten", + "Nigel Wetten", + "May 2000", + N_("_Jigsaw..."), + "RGB*", + GIMP_PLUGIN, + G_N_ELEMENTS (args), 0, + args, NULL); + + gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Render/Pattern"); +} + +static void +run (const gchar *name, + gint nparams, + const GimpParam *param, + gint *nreturn_vals, + GimpParam **return_vals) +{ + static GimpParam values[1]; + GimpRunMode run_mode; + guint32 drawable_id; + GimpPDBStatusType status = GIMP_PDB_SUCCESS; + + INIT_I18N (); + gegl_init (NULL, NULL); + + run_mode = param[0].data.d_int32; + drawable_id = param[2].data.d_drawable; + + switch (run_mode) + { + case GIMP_RUN_NONINTERACTIVE: + if (nparams == 8) + { + config.x = param[3].data.d_int32; + config.y = param[4].data.d_int32; + config.style = param[5].data.d_int32; + config.blend_lines = param[6].data.d_int32; + config.blend_amount = param[7].data.d_float; + + jigsaw (drawable_id, NULL); + } + else + { + status = GIMP_PDB_CALLING_ERROR; + } + break; + + case GIMP_RUN_INTERACTIVE: + gimp_get_data (PLUG_IN_PROC, &config); + if (! jigsaw_dialog (drawable_id)) + { + status = GIMP_PDB_CANCEL; + break; + } + gimp_progress_init (_("Assembling jigsaw")); + + jigsaw (drawable_id, NULL); + gimp_set_data (PLUG_IN_PROC, &config, sizeof(config_t)); + gimp_displays_flush (); + break; + + case GIMP_RUN_WITH_LAST_VALS: + gimp_get_data (PLUG_IN_PROC, &config); + jigsaw (drawable_id, NULL); + gimp_displays_flush (); + } /* switch */ + + *nreturn_vals = 1; + *return_vals = values; + values[0].type = GIMP_PDB_STATUS; + values[0].data.d_status = status; +} + +static void +jigsaw (guint32 drawable_id, + GimpPreview *preview) +{ + GeglBuffer *gegl_buffer = NULL; + const Babl *format = NULL; + guchar *buffer; + gint width; + gint height; + gint bytes; + gint buffer_size; + + if (preview) + { + gimp_preview_get_size (preview, &width, &height); + buffer = gimp_drawable_get_thumbnail_data (drawable_id, + &width, &height, &bytes); + buffer_size = bytes * width * height; + } + else + { + gegl_buffer = gimp_drawable_get_buffer (drawable_id); + + width = gimp_drawable_width (drawable_id); + height = gimp_drawable_height (drawable_id); + + if (gimp_drawable_has_alpha (drawable_id)) + format = babl_format ("R'G'B'A u8"); + else + format = babl_format ("R'G'B' u8"); + + bytes = babl_format_get_bytes_per_pixel (format); + + /* setup image buffer */ + buffer_size = bytes * width * height; + buffer = g_new (guchar, buffer_size); + + gegl_buffer_get (gegl_buffer, GEGL_RECTANGLE (0, 0, width, height), 1.0, + format, buffer, + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + g_object_unref (gegl_buffer); + } + + check_config (width, height); + globals.steps[LEFT] = globals.steps[RIGHT] = globals.steps[UP] + = globals.steps[DOWN] = (config.x < config.y) ? + (width / config.x * 2) : (height / config.y * 2); + + malloc_cache (); + draw_jigsaw (buffer, buffer_size, width, height, bytes, preview != NULL); + free_cache (); + + /* cleanup */ + if (preview) + { + gimp_preview_draw_buffer (preview, buffer, width * bytes); + } + else + { + gegl_buffer = gimp_drawable_get_shadow_buffer (drawable_id); + + gegl_buffer_set (gegl_buffer, GEGL_RECTANGLE (0, 0, width, height), 0, + format, buffer, + GEGL_AUTO_ROWSTRIDE); + g_object_unref (gegl_buffer); + + gimp_drawable_merge_shadow (drawable_id, TRUE); + gimp_drawable_update (drawable_id, 0, 0, width, height); + } + + g_free (buffer); +} + +static void +jigsaw_preview (gpointer drawable_id, + GimpPreview *preview) +{ + jigsaw (GPOINTER_TO_INT (drawable_id), preview); +} + +static void +generate_bezier (gint px[4], + gint py[4], + gint steps, + gint *cachex, + gint *cachey) +{ + gdouble t = 0.0; + gdouble sigma = 1.0 / steps; + gint i; + + for (i = 0; i < steps; i++) + { + gdouble t2, t3, x, y, t_1; + + t += sigma; + t2 = t * t; + t3 = t2 * t; + t_1 = 1 - t; + x = t_1 * t_1 * t_1 * px[0] + + 3 * t * t_1 * t_1 * px[1] + + 3 * t2 * t_1 * px[2] + + t3 * px[3]; + y = t_1 * t_1 * t_1 * py[0] + + 3 * t * t_1 * t_1 * py[1] + + 3 * t2 * t_1 * py[2] + + t3 * py[3]; + cachex[i] = (gint) (x + 0.2); + cachey[i] = (gint) (y + 0.2); + } /* for */ +} + +static void +draw_jigsaw (guchar *buffer, + gint bufsize, + gint width, + gint height, + gint bytes, + gboolean preview_mode) +{ + gint i; + gint *x, *y; + gint xtiles = config.x; + gint ytiles = config.y; + gint xlines = xtiles - 1; + gint ylines = ytiles - 1; + gint blend_lines = config.blend_lines; + gdouble blend_amount = config.blend_amount; + gint steps = globals.steps[RIGHT]; + style_t style = config.style; + gint progress_total = xlines + ylines - 1; + + g_return_if_fail (buffer != NULL); + + globals.gridx = g_new (gint, xtiles); + globals.gridy = g_new (gint, ytiles); + x = globals.gridx; + y = globals.gridy; + + generate_grid (width, height, xtiles, ytiles, globals.gridx, globals.gridy); + + init_right_bump (width, height); + init_left_bump (width, height); + init_up_bump (width, height); + init_down_bump (width, height); + + if (style == BEZIER_1) + { + for (i = 0; i < xlines; i++) + { + draw_vertical_border (buffer, bufsize, width, height, bytes, + x[i], ytiles, + blend_lines, blend_amount); + if (!preview_mode) + gimp_progress_update ((gdouble) i / (gdouble) progress_total); + } + for (i = 0; i < ylines; i++) + { + draw_horizontal_border (buffer, bufsize, width, bytes, y[i], xtiles, + blend_lines, blend_amount); + if (!preview_mode) + gimp_progress_update ((gdouble) (i + xlines) / (gdouble) progress_total); + } + } + else if (style == BEZIER_2) + { + for (i = 0; i < xlines; i++) + { + draw_bezier_vertical_border (buffer, bufsize, width, height, bytes, + x[i], xtiles, ytiles, blend_lines, + blend_amount, steps); + if (!preview_mode) + gimp_progress_update ((gdouble) i / (gdouble) progress_total); + } + for (i = 0; i < ylines; i++) + { + draw_bezier_horizontal_border (buffer, bufsize, width, height, bytes, + y[i], xtiles, ytiles, blend_lines, + blend_amount, steps); + if (!preview_mode) + gimp_progress_update ((gdouble) (i + xlines) / (gdouble) progress_total); + } + } + else + { + g_printerr ("draw_jigsaw: bad style\n"); + gimp_quit (); + } + gimp_progress_update (1.0); + + g_free (globals.gridx); + g_free (globals.gridy); +} + +static void +draw_vertical_border (guchar *buffer, + gint bufsize, + gint width, + gint height, + gint bytes, + gint x_offset, + gint ytiles, + gint blend_lines, + gdouble blend_amount) +{ + gint i, j; + gint tile_height = height / ytiles; + gint tile_height_eighth = tile_height / 8; + gint curve_start_offset = 3 * tile_height_eighth; + gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth; + gint px[2], py[2]; + gint ly[2], dy[2]; + gint y_offset = 0; + gdouble delta; + gdouble sigma = blend_amount / blend_lines; + gint right; + + for (i = 0; i < ytiles; i++) + { + right = g_random_int_range (0, 2); + + /* first straight line from top downwards */ + px[0] = px[1] = x_offset; + py[0] = y_offset; py[1] = y_offset + curve_start_offset - 1; + draw_vertical_line (buffer, bufsize, width, bytes, px, py); + delta = blend_amount; + dy[0] = ly[0] = py[0]; dy[1] = ly[1] = py[1]; + if (!right) + { + ly[1] += blend_lines + 2; + } + for (j = 0; j < blend_lines; j++) + { + dy[0]++; dy[1]--; ly[0]++; ly[1]--; + px[0] = x_offset - j - 1; + darken_vertical_line (buffer, bufsize, width, bytes, px, dy, delta); + px[0] = x_offset + j + 1; + lighten_vertical_line (buffer, bufsize, width, bytes, px, ly, delta); + delta -= sigma; + } + + /* top half of curve */ + if (right) + { + draw_right_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[RIGHT]); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + /* use to be -j -1 */ + darken_right_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[RIGHT], delta, j); + /* use to be +j + 1 */ + lighten_right_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[RIGHT], delta, j); + delta -= sigma; + } + } + else + { + draw_left_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[LEFT]); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + /* use to be -j -1 */ + darken_left_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[LEFT], delta, j); + /* use to be -j - 1 */ + lighten_left_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[LEFT], delta, j); + delta -= sigma; + } + } + /* bottom straight line of a tile wall */ + px[0] = px[1] = x_offset; + py[0] = y_offset + curve_end_offset; + py[1] = globals.gridy[i]; + draw_vertical_line (buffer, bufsize, width, bytes, px, py); + delta = blend_amount; + dy[0] = ly[0] = py[0]; dy[1] = ly[1] = py[1]; + if (right) + { + dy[0] -= blend_lines + 2; + } + for (j = 0; j < blend_lines; j++) + { + dy[0]++; dy[1]--; ly[0]++; ly[1]--; + px[0] = x_offset - j - 1; + darken_vertical_line (buffer, bufsize, width, bytes, px, dy, delta); + px[0] = x_offset + j + 1; + lighten_vertical_line (buffer, bufsize, width, bytes, px, ly, delta); + delta -= sigma; + } + + y_offset = globals.gridy[i]; + } /* for */ +} + +/* assumes RGB* */ +static void +draw_horizontal_border (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint y_offset, + gint xtiles, + gint blend_lines, + gdouble blend_amount) +{ + gint i, j; + gint tile_width = width / xtiles; + gint tile_width_eighth = tile_width / 8; + gint curve_start_offset = 3 * tile_width_eighth; + gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth; + gint px[2], py[2]; + gint dx[2], lx[2]; + gint x_offset = 0; + gdouble delta; + gdouble sigma = blend_amount / blend_lines; + gint up; + + for (i = 0; i < xtiles; i++) + { + up = g_random_int_range (0, 2); + + /* first horizontal line across */ + px[0] = x_offset; px[1] = x_offset + curve_start_offset - 1; + py[0] = py[1] = y_offset; + draw_horizontal_line (buffer, bufsize, width, bytes, px, py); + delta = blend_amount; + dx[0] = lx[0] = px[0]; dx[1] = lx[1] = px[1]; + if (up) + { + lx[1] += blend_lines + 2; + } + for (j = 0; j < blend_lines; j++) + { + dx[0]++; dx[1]--; lx[0]++; lx[1]--; + py[0] = y_offset - j - 1; + darken_horizontal_line (buffer, bufsize, width, bytes, dx, py, + delta); + py[0] = y_offset + j + 1; + lighten_horizontal_line (buffer, bufsize, width, bytes, lx, py, + delta); + delta -= sigma; + } + + if (up) + { + draw_up_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[UP]); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + /* use to be -j -1 */ + darken_up_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[UP], delta, j); + /* use to be +j + 1 */ + lighten_up_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[UP], delta, j); + delta -= sigma; + } + } + else + { + draw_down_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[DOWN]); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + /* use to be +j + 1 */ + darken_down_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[DOWN], delta, j); + /* use to be -j -1 */ + lighten_down_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[DOWN], delta, j); + delta -= sigma; + } + } + /* right horizontal line of tile */ + px[0] = x_offset + curve_end_offset; + px[1] = globals.gridx[i]; + py[0] = py[1] = y_offset; + draw_horizontal_line (buffer, bufsize, width, bytes, px, py); + delta = blend_amount; + dx[0] = lx[0] = px[0]; dx[1] = lx[1] = px[1]; + if (!up) + { + dx[0] -= blend_lines + 2; + } + for (j = 0;j < blend_lines; j++) + { + dx[0]++; dx[1]--; lx[0]++; lx[1]--; + py[0] = y_offset - j - 1; + darken_horizontal_line (buffer, bufsize, width, bytes, dx, py, + delta); + py[0] = y_offset + j + 1; + lighten_horizontal_line (buffer, bufsize, width, bytes, lx, py, + delta); + delta -= sigma; + } + x_offset = globals.gridx[i]; + } /* for */ +} + +/* assumes going top to bottom */ +static void +draw_vertical_line (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint px[2], + gint py[2]) +{ + gint i; + gint rowstride; + gint index; + gint length; + + rowstride = bytes * width; + index = px[0] * bytes + rowstride * py[0]; + length = py[1] - py[0] + 1; + + for (i = 0; i < length; i++) + { + DRAW_POINT (buffer, bufsize, index); + index += rowstride; + } +} + +/* assumes going left to right */ +static void +draw_horizontal_line (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint px[2], + gint py[2]) +{ + gint i; + gint rowstride; + gint index; + gint length; + + rowstride = bytes * width; + index = px[0] * bytes + rowstride * py[0]; + length = px[1] - px[0] + 1; + + for (i = 0; i < length; i++) + { + DRAW_POINT (buffer, bufsize, index); + index += bytes; + } +} + +static void +draw_right_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint x_offset, + gint curve_start_offset, + gint steps) +{ + gint i; + gint x, y; + gint index; + gint rowstride; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = globals.cachex1[RIGHT][i] + x_offset; + y = globals.cachey1[RIGHT][i] + curve_start_offset; + index = y * rowstride + x * bytes; + DRAW_POINT (buffer, bufsize, index); + + x = globals.cachex2[RIGHT][i] + x_offset; + y = globals.cachey2[RIGHT][i] + curve_start_offset; + index = y * rowstride + x * bytes; + DRAW_POINT (buffer, bufsize, index); + } +} + +static void +draw_left_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint x_offset, + gint curve_start_offset, + gint steps) +{ + gint i; + gint x, y; + gint index; + gint rowstride; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = globals.cachex1[LEFT][i] + x_offset; + y = globals.cachey1[LEFT][i] + curve_start_offset; + index = y * rowstride + x * bytes; + DRAW_POINT (buffer, bufsize, index); + + x = globals.cachex2[LEFT][i] + x_offset; + y = globals.cachey2[LEFT][i] + curve_start_offset; + index = y * rowstride + x * bytes; + DRAW_POINT (buffer, bufsize, index); + } +} + +static void +draw_up_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint y_offset, + gint curve_start_offset, + gint steps) +{ + gint i; + gint x, y; + gint index; + gint rowstride; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = globals.cachex1[UP][i] + curve_start_offset; + y = globals.cachey1[UP][i] + y_offset; + index = y * rowstride + x * bytes; + DRAW_POINT (buffer, bufsize, index); + + x = globals.cachex2[UP][i] + curve_start_offset; + y = globals.cachey2[UP][i] + y_offset; + index = y * rowstride + x * bytes; + DRAW_POINT (buffer, bufsize, index); + } +} + +static void +draw_down_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint y_offset, + gint curve_start_offset, + gint steps) +{ + gint i; + gint x, y; + gint index; + gint rowstride; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = globals.cachex1[DOWN][i] + curve_start_offset; + y = globals.cachey1[DOWN][i] + y_offset; + index = y * rowstride + x * bytes; + DRAW_POINT (buffer, bufsize, index); + + x = globals.cachex2[DOWN][i] + curve_start_offset; + y = globals.cachey2[DOWN][i] + y_offset; + index = y * rowstride + x * bytes; + DRAW_POINT (buffer, bufsize, index); + } +} + +static void +malloc_cache (void) +{ + gint i, j; + gint blend_lines = config.blend_lines; + + for (i = 0; i < 4; i++) + { + gint steps = globals.steps[i]; + + globals.cachex1[i] = g_new (gint, steps); + globals.cachex2[i] = g_new (gint, steps); + globals.cachey1[i] = g_new (gint, steps); + globals.cachey2[i] = g_new (gint, steps); + globals.blend_outer_cachex1[i] = g_new (gint *, blend_lines); + globals.blend_outer_cachex2[i] = g_new (gint *, blend_lines); + globals.blend_outer_cachey1[i] = g_new (gint *, blend_lines); + globals.blend_outer_cachey2[i] = g_new (gint *, blend_lines); + globals.blend_inner_cachex1[i] = g_new (gint *, blend_lines); + globals.blend_inner_cachex2[i] = g_new (gint *, blend_lines); + globals.blend_inner_cachey1[i] = g_new (gint *, blend_lines); + globals.blend_inner_cachey2[i] = g_new (gint *, blend_lines); + for (j = 0; j < blend_lines; j++) + { + globals.blend_outer_cachex1[i][j] = g_new (gint, steps); + globals.blend_outer_cachex2[i][j] = g_new (gint, steps); + globals.blend_outer_cachey1[i][j] = g_new (gint, steps); + globals.blend_outer_cachey2[i][j] = g_new (gint, steps); + globals.blend_inner_cachex1[i][j] = g_new (gint, steps); + globals.blend_inner_cachex2[i][j] = g_new (gint, steps); + globals.blend_inner_cachey1[i][j] = g_new (gint, steps); + globals.blend_inner_cachey2[i][j] = g_new (gint, steps); + } + } +} + +static void +free_cache (void) +{ + gint i, j; + gint blend_lines = config.blend_lines; + + for (i = 0; i < 4; i ++) + { + g_free (globals.cachex1[i]); + g_free (globals.cachex2[i]); + g_free (globals.cachey1[i]); + g_free (globals.cachey2[i]); + for (j = 0; j < blend_lines; j++) + { + g_free (globals.blend_outer_cachex1[i][j]); + g_free (globals.blend_outer_cachex2[i][j]); + g_free (globals.blend_outer_cachey1[i][j]); + g_free (globals.blend_outer_cachey2[i][j]); + g_free (globals.blend_inner_cachex1[i][j]); + g_free (globals.blend_inner_cachex2[i][j]); + g_free (globals.blend_inner_cachey1[i][j]); + g_free (globals.blend_inner_cachey2[i][j]); + } + g_free (globals.blend_outer_cachex1[i]); + g_free (globals.blend_outer_cachex2[i]); + g_free (globals.blend_outer_cachey1[i]); + g_free (globals.blend_outer_cachey2[i]); + g_free (globals.blend_inner_cachex1[i]); + g_free (globals.blend_inner_cachex2[i]); + g_free (globals.blend_inner_cachey1[i]); + g_free (globals.blend_inner_cachey2[i]); + } +} + +static void +init_right_bump (gint width, + gint height) +{ + gint i; + gint xtiles = config.x; + gint ytiles = config.y; + gint steps = globals.steps[RIGHT]; + gint px[4], py[4]; + gint x_offset = 0; + gint tile_width = width / xtiles; + gint tile_height = height/ ytiles; + gint tile_height_eighth = tile_height / 8; + gint curve_start_offset = 0; + gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth; + gint blend_lines = config.blend_lines; + + px[0] = x_offset; + px[1] = x_offset + XFACTOR2 * tile_width; + px[2] = x_offset + XFACTOR3 * tile_width; + px[3] = x_offset + XFACTOR4 * tile_width; + py[0] = curve_start_offset; + py[1] = curve_start_offset + YFACTOR2 * tile_height; + py[2] = curve_start_offset - YFACTOR3 * tile_height; + py[3] = curve_start_offset + YFACTOR4 * tile_height; + generate_bezier(px, py, steps, globals.cachex1[RIGHT], + globals.cachey1[RIGHT]); + /* outside right bump */ + for (i = 0; i < blend_lines; i++) + { + py[0]--; py[1]--; py[2]--; px[3]++; + generate_bezier(px, py, steps, + globals.blend_outer_cachex1[RIGHT][i], + globals.blend_outer_cachey1[RIGHT][i]); + } + /* inside right bump */ + py[0] += blend_lines; py[1] += blend_lines; py[2] += blend_lines; + px[3] -= blend_lines; + for (i = 0; i < blend_lines; i++) + { + py[0]++; py[1]++; py[2]++; px[3]--; + generate_bezier(px, py, steps, + globals.blend_inner_cachex1[RIGHT][i], + globals.blend_inner_cachey1[RIGHT][i]); + } + + /* bottom half of bump */ + px[0] = x_offset + XFACTOR5 * tile_width; + px[1] = x_offset + XFACTOR6 * tile_width; + px[2] = x_offset + XFACTOR7 * tile_width; + px[3] = x_offset; + py[0] = curve_start_offset + YFACTOR5 * tile_height; + py[1] = curve_start_offset + YFACTOR6 * tile_height; + py[2] = curve_start_offset + YFACTOR7 * tile_height; + py[3] = curve_end_offset; + generate_bezier(px, py, steps, globals.cachex2[RIGHT], + globals.cachey2[RIGHT]); + /* outer right bump */ + for (i = 0; i < blend_lines; i++) + { + py[1]++; py[2]++; py[3]++; px[0]++; + generate_bezier(px, py, steps, + globals.blend_outer_cachex2[RIGHT][i], + globals.blend_outer_cachey2[RIGHT][i]); + } + /* inner right bump */ + py[1] -= blend_lines; py[2] -= blend_lines; py[3] -= blend_lines; + px[0] -= blend_lines; + for (i = 0; i < blend_lines; i++) + { + py[1]--; py[2]--; py[3]--; px[0]--; + generate_bezier(px, py, steps, + globals.blend_inner_cachex2[RIGHT][i], + globals.blend_inner_cachey2[RIGHT][i]); + } +} + +static void +init_left_bump (gint width, + gint height) +{ + gint i; + gint xtiles = config.x; + gint ytiles = config.y; + gint steps = globals.steps[LEFT]; + gint px[4], py[4]; + gint x_offset = 0; + gint tile_width = width / xtiles; + gint tile_height = height / ytiles; + gint tile_height_eighth = tile_height / 8; + gint curve_start_offset = 0; + gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth; + gint blend_lines = config.blend_lines; + + px[0] = x_offset; + px[1] = x_offset - XFACTOR2 * tile_width; + px[2] = x_offset - XFACTOR3 * tile_width; + px[3] = x_offset - XFACTOR4 * tile_width; + py[0] = curve_start_offset; + py[1] = curve_start_offset + YFACTOR2 * tile_height; + py[2] = curve_start_offset - YFACTOR3 * tile_height; + py[3] = curve_start_offset + YFACTOR4 * tile_height; + generate_bezier(px, py, steps, globals.cachex1[LEFT], + globals.cachey1[LEFT]); + /* outer left bump */ + for (i = 0; i < blend_lines; i++) + { + py[0]--; py[1]--; py[2]--; px[3]--; + generate_bezier(px, py, steps, + globals.blend_outer_cachex1[LEFT][i], + globals.blend_outer_cachey1[LEFT][i]); + } + /* inner left bump */ + py[0] += blend_lines; py[1] += blend_lines; py[2] += blend_lines; + px[3] += blend_lines; + for (i = 0; i < blend_lines; i++) + { + py[0]++; py[1]++; py[2]++; px[3]++; + generate_bezier(px, py, steps, + globals.blend_inner_cachex1[LEFT][i], + globals.blend_inner_cachey1[LEFT][i]); + } + + /* bottom half of bump */ + px[0] = x_offset - XFACTOR5 * tile_width; + px[1] = x_offset - XFACTOR6 * tile_width; + px[2] = x_offset - XFACTOR7 * tile_width; + px[3] = x_offset; + py[0] = curve_start_offset + YFACTOR5 * tile_height; + py[1] = curve_start_offset + YFACTOR6 * tile_height; + py[2] = curve_start_offset + YFACTOR7 * tile_height; + py[3] = curve_end_offset; + generate_bezier(px, py, steps, globals.cachex2[LEFT], + globals.cachey2[LEFT]); + /* outer left bump */ + for (i = 0; i < blend_lines; i++) + { + py[1]++; py[2]++; py[3]++; px[0]--; + generate_bezier(px, py, steps, + globals.blend_outer_cachex2[LEFT][i], + globals.blend_outer_cachey2[LEFT][i]); + } + /* inner left bump */ + py[1] -= blend_lines; py[2] -= blend_lines; py[3] -= blend_lines; + px[0] += blend_lines; + for (i = 0; i < blend_lines; i++) + { + py[1]--; py[2]--; py[3]--; px[0]++; + generate_bezier(px, py, steps, + globals.blend_inner_cachex2[LEFT][i], + globals.blend_inner_cachey2[LEFT][i]); + } +} + +static void +init_up_bump (gint width, + gint height) +{ + gint i; + gint xtiles = config.x; + gint ytiles = config.y; + gint steps = globals.steps[UP]; + gint px[4], py[4]; + gint y_offset = 0; + gint tile_width = width / xtiles; + gint tile_height = height/ ytiles; + gint tile_width_eighth = tile_width / 8; + gint curve_start_offset = 0; + gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth; + gint blend_lines = config.blend_lines; + + px[0] = curve_start_offset; + px[1] = curve_start_offset + YFACTOR2 * tile_width; + px[2] = curve_start_offset - YFACTOR3 * tile_width; + px[3] = curve_start_offset + YFACTOR4 * tile_width; + py[0] = y_offset; + py[1] = y_offset - XFACTOR2 * tile_height; + py[2] = y_offset - XFACTOR3 * tile_height; + py[3] = y_offset - XFACTOR4 * tile_height; + generate_bezier(px, py, steps, globals.cachex1[UP], + globals.cachey1[UP]); + /* outer up bump */ + for (i = 0; i < blend_lines; i++) + { + px[0]--; px[1]--; px[2]--; py[3]--; + generate_bezier(px, py, steps, + globals.blend_outer_cachex1[UP][i], + globals.blend_outer_cachey1[UP][i]); + } + /* inner up bump */ + px[0] += blend_lines; px[1] += blend_lines; px[2] += blend_lines; + py[3] += blend_lines; + for (i = 0; i < blend_lines; i++) + { + px[0]++; px[1]++; px[2]++; py[3]++; + generate_bezier(px, py, steps, + globals.blend_inner_cachex1[UP][i], + globals.blend_inner_cachey1[UP][i]); + } + + /* bottom half of bump */ + px[0] = curve_start_offset + YFACTOR5 * tile_width; + px[1] = curve_start_offset + YFACTOR6 * tile_width; + px[2] = curve_start_offset + YFACTOR7 * tile_width; + px[3] = curve_end_offset; + py[0] = y_offset - XFACTOR5 * tile_height; + py[1] = y_offset - XFACTOR6 * tile_height; + py[2] = y_offset - XFACTOR7 * tile_height; + py[3] = y_offset; + generate_bezier(px, py, steps, globals.cachex2[UP], + globals.cachey2[UP]); + /* outer up bump */ + for (i = 0; i < blend_lines; i++) + { + px[1]++; px[2]++; px[3]++; py[0]--; + generate_bezier(px, py, steps, + globals.blend_outer_cachex2[UP][i], + globals.blend_outer_cachey2[UP][i]); + } + /* inner up bump */ + px[1] -= blend_lines; px[2] -= blend_lines; px[3] -= blend_lines; + py[0] += blend_lines; + for (i = 0; i < blend_lines; i++) + { + px[1]--; px[2]--; px[3]--; py[0]++; + generate_bezier(px, py, steps, + globals.blend_inner_cachex2[UP][i], + globals.blend_inner_cachey2[UP][i]); + } +} + +static void +init_down_bump (gint width, + gint height) +{ + gint i; + gint xtiles = config.x; + gint ytiles = config.y; + gint steps = globals.steps[DOWN]; + gint px[4], py[4]; + gint y_offset = 0; + gint tile_width = width / xtiles; + gint tile_height = height/ ytiles; + gint tile_width_eighth = tile_width / 8; + gint curve_start_offset = 0; + gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth; + gint blend_lines = config.blend_lines; + + px[0] = curve_start_offset; + px[1] = curve_start_offset + YFACTOR2 * tile_width; + px[2] = curve_start_offset - YFACTOR3 * tile_width; + px[3] = curve_start_offset + YFACTOR4 * tile_width; + py[0] = y_offset; + py[1] = y_offset + XFACTOR2 * tile_height; + py[2] = y_offset + XFACTOR3 * tile_height; + py[3] = y_offset + XFACTOR4 * tile_height; + generate_bezier(px, py, steps, globals.cachex1[DOWN], + globals.cachey1[DOWN]); + /* outer down bump */ + for (i = 0; i < blend_lines; i++) + { + px[0]--; px[1]--; px[2]--; py[3]++; + generate_bezier(px, py, steps, + globals.blend_outer_cachex1[DOWN][i], + globals.blend_outer_cachey1[DOWN][i]); + } + /* inner down bump */ + px[0] += blend_lines; px[1] += blend_lines; px[2] += blend_lines; + py[3] -= blend_lines; + for (i = 0; i < blend_lines; i++) + { + px[0]++; px[1]++; px[2]++; py[3]--; + generate_bezier(px, py, steps, + globals.blend_inner_cachex1[DOWN][i], + globals.blend_inner_cachey1[DOWN][i]); + } + + /* bottom half of bump */ + px[0] = curve_start_offset + YFACTOR5 * tile_width; + px[1] = curve_start_offset + YFACTOR6 * tile_width; + px[2] = curve_start_offset + YFACTOR7 * tile_width; + px[3] = curve_end_offset; + py[0] = y_offset + XFACTOR5 * tile_height; + py[1] = y_offset + XFACTOR6 * tile_height; + py[2] = y_offset + XFACTOR7 * tile_height; + py[3] = y_offset; + generate_bezier(px, py, steps, globals.cachex2[DOWN], + globals.cachey2[DOWN]); + /* outer down bump */ + for (i = 0; i < blend_lines; i++) + { + px[1]++; px[2]++; px[3]++; py[0]++; + generate_bezier(px, py, steps, + globals.blend_outer_cachex2[DOWN][i], + globals.blend_outer_cachey2[DOWN][i]); + } + /* inner down bump */ + px[1] -= blend_lines; px[2] -= blend_lines; px[3] -= blend_lines; + py[0] -= blend_lines; + for (i = 0; i < blend_lines; i++) + { + px[1]--; px[2]--; px[3]--; py[0]--; + generate_bezier(px, py, steps, + globals.blend_inner_cachex2[DOWN][i], + globals.blend_inner_cachey2[DOWN][i]); + } +} + +static void +generate_grid (gint width, + gint height, + gint xtiles, + gint ytiles, + gint *x, + gint *y) +{ + gint i; + gint xlines = xtiles - 1; + gint ylines = ytiles - 1; + gint tile_width = width / xtiles; + gint tile_height = height / ytiles; + gint tile_width_leftover = width % xtiles; + gint tile_height_leftover = height % ytiles; + gint x_offset = tile_width; + gint y_offset = tile_height; + gint carry; + + for (i = 0; i < xlines; i++) + { + x[i] = x_offset; + x_offset += tile_width; + } + carry = 0; + while (tile_width_leftover) + { + for (i = carry; i < xlines; i++) + { + x[i] += 1; + } + tile_width_leftover--; + carry++; + } + x[xlines] = width - 1; /* padding for draw_horizontal_border */ + + for (i = 0; i < ytiles; i++) + { + y[i] = y_offset; + y_offset += tile_height; + } + carry = 0; + while (tile_height_leftover) + { + for (i = carry; i < ylines; i++) + { + y[i] += 1; + } + tile_height_leftover--; + carry++; + } + y[ylines] = height - 1; /* padding for draw_vertical_border */ +} + +/* assumes RGB* */ +/* assumes py[1] > py[0] and px[0] = px[1] */ +static void +darken_vertical_line (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint px[2], + gint py[2], + gdouble delta) +{ + gint i; + gint rowstride; + gint index; + gint length; + gint temp; + + rowstride = bytes * width; + index = px[0] * bytes + py[0] * rowstride; + length = py[1] - py[0] + 1; + + for (i = 0; i < length; i++) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + index += rowstride; + } +} + +/* assumes RGB* */ +/* assumes py[1] > py[0] and px[0] = px[1] */ +static void +lighten_vertical_line (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint px[2], + gint py[2], + gdouble delta) +{ + gint i; + gint rowstride; + gint index; + gint length; + gint temp; + + rowstride = bytes * width; + index = px[0] * bytes + py[0] * rowstride; + length = py[1] - py[0] + 1; + + for (i = 0; i < length; i++) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + index += rowstride; + } +} + +/* assumes RGB* */ +/* assumes px[1] > px[0] and py[0] = py[1] */ +static void +darken_horizontal_line (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint px[2], + gint py[2], + gdouble delta) +{ + gint i; + gint rowstride; + gint index; + gint length; + gint temp; + + rowstride = bytes * width; + index = px[0] * bytes + py[0] * rowstride; + length = px[1] - px[0] + 1; + + for (i = 0; i < length; i++) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + index += bytes; + } +} + +/* assumes RGB* */ +/* assumes px[1] > px[0] and py[0] = py[1] */ +static void +lighten_horizontal_line (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint px[2], + gint py[2], + gdouble delta) +{ + gint i; + gint rowstride; + gint index; + gint length; + gint temp; + + rowstride = bytes * width; + index = px[0] * bytes + py[0] * rowstride; + length = px[1] - px[0] + 1; + + for (i = 0; i < length; i++) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + index += bytes; + } +} + +static void +darken_right_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint x_offset, + gint curve_start_offset, + gint steps, + gdouble delta, + gint counter) +{ + gint i; + gint x, y; + gint index; + gint last_index1 = -1; + gint last_index2 = -1; + gint rowstride; + gint temp; + gint j = counter; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = x_offset + + globals.blend_inner_cachex1[RIGHT][j][i]; + y = curve_start_offset + + globals.blend_inner_cachey1[RIGHT][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index1) + { + if (i < steps / 1.3) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + } + else + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + } + last_index1 = index; + } + + x = x_offset + + globals.blend_inner_cachex2[RIGHT][j][i]; + y = curve_start_offset + + globals.blend_inner_cachey2[RIGHT][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index2) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + last_index2 = index; + } + } +} + +static void +lighten_right_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint x_offset, + gint curve_start_offset, + gint steps, + gdouble delta, + gint counter) +{ + gint i; + gint x, y; + gint index; + gint last_index1 = -1; + gint last_index2 = -1; + gint rowstride; + gint temp; + gint j = counter; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = x_offset + + globals.blend_outer_cachex1[RIGHT][j][i]; + y = curve_start_offset + + globals.blend_outer_cachey1[RIGHT][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index1) + { + if (i < steps / 1.3) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + } + else + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + } + last_index1 = index; + } + + x = x_offset + + globals.blend_outer_cachex2[RIGHT][j][i]; + y = curve_start_offset + + globals.blend_outer_cachey2[RIGHT][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index2) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + last_index2 = index; + } + } +} + +static void +darken_left_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint x_offset, + gint curve_start_offset, + gint steps, + gdouble delta, + gint counter) +{ + gint i; + gint x, y; + gint index; + gint last_index1 = -1; + gint last_index2 = -1; + gint rowstride; + gint temp; + gint j = counter; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = x_offset + + globals.blend_outer_cachex1[LEFT][j][i]; + y = curve_start_offset + + globals.blend_outer_cachey1[LEFT][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index1) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + last_index1 = index; + } + + x = x_offset + + globals.blend_outer_cachex2[LEFT][j][i]; + y = curve_start_offset + + globals.blend_outer_cachey2[LEFT][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index2) + { + if (i < steps / 4) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + } + else + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + } + last_index2 = index; + } + } +} + +static void +lighten_left_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint x_offset, + gint curve_start_offset, + gint steps, + gdouble delta, + gint counter) +{ + gint i; + gint x, y; + gint index; + gint last_index1 = -1; + gint last_index2 = -1; + gint rowstride; + gint temp; + gint j = counter; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = x_offset + + globals.blend_inner_cachex1[LEFT][j][i]; + y = curve_start_offset + + globals.blend_inner_cachey1[LEFT][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index1) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + last_index1 = index; + } + + x = x_offset + + globals.blend_inner_cachex2[LEFT][j][i]; + y = curve_start_offset + + globals.blend_inner_cachey2[LEFT][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index2) + { + if (i < steps / 4) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + } + else + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + } + last_index2 = index; + } + } +} + +static void +darken_up_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint y_offset, + gint curve_start_offset, + gint steps, + gdouble delta, + gint counter) +{ + gint i; + gint x, y; + gint index; + gint last_index1 = -1; + gint last_index2 = -1; + gint rowstride; + gint temp; + gint j = counter; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = curve_start_offset + + globals.blend_outer_cachex1[UP][j][i]; + y = y_offset + + globals.blend_outer_cachey1[UP][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index1) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + last_index1 = index; + } + + x = curve_start_offset + + globals.blend_outer_cachex2[UP][j][i]; + y = y_offset + + globals.blend_outer_cachey2[UP][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index2) + { + if (i < steps / 4) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + } + else + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + } + last_index2 = index; + } + } +} + +static void +lighten_up_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint y_offset, + gint curve_start_offset, + gint steps, + gdouble delta, + gint counter) +{ + gint i; + gint x, y; + gint index; + gint last_index1 = -1; + gint last_index2 = -1; + gint rowstride; + gint temp; + gint j = counter; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = curve_start_offset + + globals.blend_inner_cachex1[UP][j][i]; + y = y_offset + + globals.blend_inner_cachey1[UP][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index1) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + last_index1 = index; + } + + x = curve_start_offset + + globals.blend_inner_cachex2[UP][j][i]; + y = y_offset + + globals.blend_inner_cachey2[UP][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index2) + { + if (i < steps / 4) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + } + else + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + } + last_index2 = index; + } + } +} + +static void +darken_down_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint y_offset, + gint curve_start_offset, + gint steps, + gdouble delta, + gint counter) +{ + gint i; + gint x, y; + gint index; + gint last_index1 = -1; + gint last_index2 = -1; + gint rowstride; + gint temp; + gint j = counter; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = curve_start_offset + + globals.blend_inner_cachex1[DOWN][j][i]; + y = y_offset + + globals.blend_inner_cachey1[DOWN][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index1) + { + if (i < steps / 1.2) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + } + else + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + } + last_index1 = index; + } + + x = curve_start_offset + + globals.blend_inner_cachex2[DOWN][j][i]; + y = y_offset + + globals.blend_inner_cachey2[DOWN][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index2) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + last_index2 = index; + } + } +} + +static void +lighten_down_bump (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint y_offset, + gint curve_start_offset, + gint steps, + gdouble delta, + gint counter) +{ + gint i; + gint x, y; + gint index; + gint last_index1 = -1; + gint last_index2 = -1; + gint rowstride; + gint temp; + gint j = counter; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = curve_start_offset + + globals.blend_outer_cachex1[DOWN][j][i]; + y = y_offset + + globals.blend_outer_cachey1[DOWN][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index1) + { + if (i < steps / 1.2) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + } + else + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + } + last_index1 = index; + } + + x = curve_start_offset + + globals.blend_outer_cachex2[DOWN][j][i]; + y = y_offset + + globals.blend_outer_cachey2[DOWN][j][i]; + index = y * rowstride + x * bytes; + if (index != last_index2) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + last_index2 = index; + } + } +} + +static void +draw_bezier_line (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint steps, + gint *cx, + gint *cy) +{ + gint i; + gint x, y; + gint index; + gint rowstride; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = cx[i]; + y = cy[i]; + index = y * rowstride + x * bytes; + DRAW_POINT (buffer, bufsize, index); + } +} + +static void +darken_bezier_line (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint x_offset, + gint y_offset, + gint steps, + gint *cx, + gint *cy, + gdouble delta) +{ + gint i; + gint x, y; + gint index; + gint last_index = -1; + gint rowstride; + gint temp; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = cx[i] + x_offset; + y = cy[i] + y_offset; + index = y * rowstride + x * bytes; + if (index != last_index) + { + DARKEN_POINT (buffer, bufsize, index, delta, temp); + last_index = index; + } + } +} + +static void +lighten_bezier_line (guchar *buffer, + gint bufsize, + gint width, + gint bytes, + gint x_offset, + gint y_offset, + gint steps, + gint *cx, + gint *cy, + gdouble delta) +{ + gint i; + gint x, y; + gint index; + gint last_index = -1; + gint rowstride; + gint temp; + + rowstride = bytes * width; + + for (i = 0; i < steps; i++) + { + x = cx[i] + x_offset; + y = cy[i] + y_offset; + index = y * rowstride + x * bytes; + if (index != last_index) + { + LIGHTEN_POINT (buffer, bufsize, index, delta, temp); + last_index = index; + } + } +} + +static void +draw_bezier_vertical_border (guchar *buffer, + gint bufsize, + gint width, + gint height, + gint bytes, + gint x_offset, + gint xtiles, + gint ytiles, + gint blend_lines, + gdouble blend_amount, + gint steps) +{ + gint i, j; + gint tile_width = width / xtiles; + gint tile_height = height / ytiles; + gint tile_height_eighth = tile_height / 8; + gint curve_start_offset = 3 * tile_height_eighth; + gint curve_end_offset = curve_start_offset + 2 * tile_height_eighth; + gint px[4], py[4]; + gint y_offset = 0; + gdouble delta; + gdouble sigma = blend_amount / blend_lines; + gint right; + gint *cachex, *cachey; + + cachex = g_new (gint, steps); + cachey = g_new (gint, steps); + + for (i = 0; i < ytiles; i++) + { + right = g_random_int_range (0, 2); + + px[0] = px[3] = x_offset; + px[1] = x_offset + WALL_XFACTOR2 * tile_width * FUDGE; + px[2] = x_offset + WALL_XFACTOR3 * tile_width * FUDGE; + py[0] = y_offset; + py[1] = y_offset + WALL_YCONS2 * tile_height; + py[2] = y_offset + WALL_YCONS3 * tile_height; + py[3] = y_offset + curve_start_offset; + + if (right) + { + px[1] = x_offset - WALL_XFACTOR2 * tile_width; + px[2] = x_offset - WALL_XFACTOR3 * tile_width; + } + generate_bezier (px, py, steps, cachex, cachey); + draw_bezier_line (buffer, bufsize, width, bytes, steps, cachex, cachey); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + px[0] = -j - 1; + darken_bezier_line (buffer, bufsize, width, bytes, px[0], 0, + steps, cachex, cachey, delta); + px[0] = j + 1; + lighten_bezier_line (buffer, bufsize, width, bytes, px[0], 0, + steps, cachex, cachey, delta); + delta -= sigma; + } + if (right) + { + draw_right_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[RIGHT]); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + /* use to be -j -1 */ + darken_right_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[RIGHT], delta, j); + /* use to be +j + 1 */ + lighten_right_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[RIGHT], delta, j); + delta -= sigma; + } + } + else + { + draw_left_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[LEFT]); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + /* use to be -j -1 */ + darken_left_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[LEFT], delta, j); + /* use to be -j - 1 */ + lighten_left_bump (buffer, bufsize, width, bytes, x_offset, + y_offset + curve_start_offset, + globals.steps[LEFT], delta, j); + delta -= sigma; + } + } + px[0] = px[3] = x_offset; + px[1] = x_offset + WALL_XFACTOR2 * tile_width * FUDGE; + px[2] = x_offset + WALL_XFACTOR3 * tile_width * FUDGE; + py[0] = y_offset + curve_end_offset; + py[1] = y_offset + curve_end_offset + WALL_YCONS2 * tile_height; + py[2] = y_offset + curve_end_offset + WALL_YCONS3 * tile_height; + py[3] = globals.gridy[i]; + if (right) + { + px[1] = x_offset - WALL_XFACTOR2 * tile_width; + px[2] = x_offset - WALL_XFACTOR3 * tile_width; + } + generate_bezier (px, py, steps, cachex, cachey); + draw_bezier_line (buffer, bufsize, width, bytes, steps, cachex, cachey); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + px[0] = -j - 1; + darken_bezier_line (buffer, bufsize, width, bytes, px[0], 0, + steps, cachex, cachey, delta); + px[0] = j + 1; + lighten_bezier_line (buffer, bufsize, width, bytes, px[0], 0, + steps, cachex, cachey, delta); + delta -= sigma; + } + y_offset = globals.gridy[i]; + } /* for */ + g_free(cachex); + g_free(cachey); +} + +static void +draw_bezier_horizontal_border (guchar *buffer, + gint bufsize, + gint width, + gint height, + gint bytes, + gint y_offset, + gint xtiles, + gint ytiles, + gint blend_lines, + gdouble blend_amount, + gint steps) +{ + gint i, j; + gint tile_width = width / xtiles; + gint tile_height = height / ytiles; + gint tile_width_eighth = tile_width / 8; + gint curve_start_offset = 3 * tile_width_eighth; + gint curve_end_offset = curve_start_offset + 2 * tile_width_eighth; + gint px[4], py[4]; + gint x_offset = 0; + gdouble delta; + gdouble sigma = blend_amount / blend_lines; + gint up; + gint *cachex, *cachey; + + cachex = g_new (gint, steps); + cachey = g_new (gint, steps); + + for (i = 0; i < xtiles; i++) + { + up = g_random_int_range (0, 2); + + px[0] = x_offset; + px[1] = x_offset + WALL_XCONS2 * tile_width; + px[2] = x_offset + WALL_XCONS3 * tile_width; + px[3] = x_offset + curve_start_offset; + py[0] = py[3] = y_offset; + py[1] = y_offset + WALL_YFACTOR2 * tile_height * FUDGE; + py[2] = y_offset + WALL_YFACTOR3 * tile_height * FUDGE; + if (!up) + { + py[1] = y_offset - WALL_YFACTOR2 * tile_height; + py[2] = y_offset - WALL_YFACTOR3 * tile_height; + } + generate_bezier (px, py, steps, cachex, cachey); + draw_bezier_line (buffer, bufsize, width, bytes, steps, cachex, cachey); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + py[0] = -j - 1; + darken_bezier_line (buffer, bufsize, width, bytes, 0, py[0], + steps, cachex, cachey, delta); + py[0] = j + 1; + lighten_bezier_line (buffer, bufsize, width, bytes, 0, py[0], + steps, cachex, cachey, delta); + delta -= sigma; + } + /* bumps */ + if (up) + { + draw_up_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[UP]); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + /* use to be -j -1 */ + darken_up_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[UP], delta, j); + /* use to be +j + 1 */ + lighten_up_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[UP], delta, j); + delta -= sigma; + } + } + else + { + draw_down_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[DOWN]); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + /* use to be +j + 1 */ + darken_down_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[DOWN], delta, j); + /* use to be -j -1 */ + lighten_down_bump (buffer, bufsize, width, bytes, y_offset, + x_offset + curve_start_offset, + globals.steps[DOWN], delta, j); + delta -= sigma; + } + } + /* ending side wall line */ + px[0] = x_offset + curve_end_offset; + px[1] = x_offset + curve_end_offset + WALL_XCONS2 * tile_width; + px[2] = x_offset + curve_end_offset + WALL_XCONS3 * tile_width; + px[3] = globals.gridx[i]; + py[0] = py[3] = y_offset; + py[1] = y_offset + WALL_YFACTOR2 * tile_height * FUDGE; + py[2] = y_offset + WALL_YFACTOR3 * tile_height * FUDGE; + if (!up) + { + py[1] = y_offset - WALL_YFACTOR2 * tile_height; + py[2] = y_offset - WALL_YFACTOR3 * tile_height; + } + generate_bezier (px, py, steps, cachex, cachey); + draw_bezier_line (buffer, bufsize, width, bytes, steps, cachex, cachey); + delta = blend_amount; + for (j = 0; j < blend_lines; j++) + { + py[0] = -j - 1; + darken_bezier_line (buffer, bufsize, width, bytes, 0, py[0], + steps, cachex, cachey, delta); + py[0] = j + 1; + lighten_bezier_line (buffer, bufsize, width, bytes, 0, py[0], + steps, cachex, cachey, delta); + delta -= sigma; + } + x_offset = globals.gridx[i]; + } /* for */ + g_free(cachex); + g_free(cachey); +} + +static void +check_config (gint width, + gint height) +{ + gint tile_width, tile_height; + gint tile_width_limit, tile_height_limit; + + if (config.x < 1) + { + config.x = 1; + } + if (config.y < 1) + { + config.y = 1; + } + if (config.blend_amount < 0) + { + config.blend_amount = 0; + } + if (config.blend_amount > 5) + { + config.blend_amount = 5; + } + tile_width = width / config.x; + tile_height = height / config.y; + tile_width_limit = 0.4 * tile_width; + tile_height_limit = 0.4 * tile_height; + if ((config.blend_lines > tile_width_limit) + || (config.blend_lines > tile_height_limit)) + { + config.blend_lines = MIN(tile_width_limit, tile_height_limit); + } +} + +/******************************************************** + GUI +********************************************************/ + +static gboolean +jigsaw_dialog (guint32 drawable_id) +{ + GtkWidget *dialog; + GtkWidget *main_vbox; + GtkWidget *preview; + GtkSizeGroup *group; + GtkWidget *frame; + GtkWidget *rbutton1; + GtkWidget *rbutton2; + GtkWidget *table; + GtkObject *adj; + gboolean run; + + gimp_ui_init (PLUG_IN_BINARY, TRUE); + + dialog = gimp_dialog_new (_("Jigsaw"), PLUG_IN_ROLE, + NULL, 0, + gimp_standard_help_func, PLUG_IN_PROC, + + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_OK"), GTK_RESPONSE_OK, + + NULL); + + gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog), + GTK_RESPONSE_OK, + GTK_RESPONSE_CANCEL, + -1); + + gimp_window_set_transient (GTK_WINDOW (dialog)); + + main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12); + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), + main_vbox, TRUE, TRUE, 0); + gtk_widget_show (main_vbox); + + preview = gimp_aspect_preview_new_from_drawable_id (drawable_id); + gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0); + gtk_widget_show (preview); + + g_signal_connect_swapped (preview, "invalidated", + G_CALLBACK (jigsaw_preview), + GINT_TO_POINTER (drawable_id)); + + frame = gimp_frame_new (_("Number of Tiles")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + + table = gtk_table_new (2, 3, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 6); + gtk_table_set_row_spacings (GTK_TABLE (table), 6); + gtk_container_add (GTK_CONTAINER (frame), table); + + group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + /* xtiles */ + adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, + _("_Horizontal:"), SCALE_WIDTH, 0, + config.x, MIN_XTILES, MAX_XTILES, 1.0, 4.0, 0, + TRUE, 0, 0, + _("Number of pieces going across"), NULL); + + gtk_size_group_add_widget (group, GIMP_SCALE_ENTRY_LABEL (adj)); + g_object_unref (group); + + g_signal_connect (adj, "value-changed", + G_CALLBACK (gimp_int_adjustment_update), + &config.x); + g_signal_connect_swapped (adj, "value-changed", + G_CALLBACK (gimp_preview_invalidate), + preview); + + /* ytiles */ + adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1, + _("_Vertical:"), SCALE_WIDTH, 0, + config.y, MIN_YTILES, MAX_YTILES, 1.0, 4.0, 0, + TRUE, 0, 0, + _("Number of pieces going down"), NULL); + + gtk_size_group_add_widget (group, GIMP_SCALE_ENTRY_LABEL (adj)); + + g_signal_connect (adj, "value-changed", + G_CALLBACK (gimp_int_adjustment_update), + &config.y); + g_signal_connect_swapped (adj, "value-changed", + G_CALLBACK (gimp_preview_invalidate), + preview); + + gtk_widget_show (table); + gtk_widget_show (frame); + + frame = gimp_frame_new (_("Bevel Edges")); + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + + table = gtk_table_new (2, 3, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 6); + gtk_table_set_row_spacings (GTK_TABLE (table), 6); + gtk_container_add (GTK_CONTAINER (frame), table); + + /* number of blending lines */ + adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, + _("_Bevel width:"), SCALE_WIDTH, 4, + config.blend_lines, + MIN_BLEND_LINES, MAX_BLEND_LINES, 1.0, 2.0, 0, + TRUE, 0, 0, + _("Degree of slope of each piece's edge"), NULL); + + gtk_size_group_add_widget (group, GIMP_SCALE_ENTRY_LABEL (adj)); + + g_signal_connect (adj, "value-changed", + G_CALLBACK (gimp_int_adjustment_update), + &config.blend_lines); + g_signal_connect_swapped (adj, "value-changed", + G_CALLBACK (gimp_preview_invalidate), + preview); + + /* blending amount */ + adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1, + _("H_ighlight:"), SCALE_WIDTH, 4, + config.blend_amount, + MIN_BLEND_AMOUNT, MAX_BLEND_AMOUNT, 0.05, 0.1, 2, + TRUE, 0, 0, + _("The amount of highlighting on the edges " + "of each piece"), NULL); + + gtk_size_group_add_widget (group, GIMP_SCALE_ENTRY_LABEL (adj)); + + g_signal_connect (adj, "value-changed", + G_CALLBACK (gimp_double_adjustment_update), + &config.blend_amount); + g_signal_connect_swapped (adj, "value-changed", + G_CALLBACK (gimp_preview_invalidate), + preview); + + gtk_widget_show (table); + gtk_widget_show (frame); + + /* frame for primitive radio buttons */ + + frame = gimp_int_radio_group_new (TRUE, _("Jigsaw Style"), + G_CALLBACK (gimp_radio_button_update), + &config.style, config.style, + + _("_Square"), BEZIER_1, &rbutton1, + _("C_urved"), BEZIER_2, &rbutton2, + + NULL); + + gimp_help_set_help_data (rbutton1, _("Each piece has straight sides"), NULL); + gimp_help_set_help_data (rbutton2, _("Each piece has curved sides"), NULL); + g_signal_connect_swapped (rbutton1, "toggled", + G_CALLBACK (gimp_preview_invalidate), + preview); + g_signal_connect_swapped (rbutton2, "toggled", + G_CALLBACK (gimp_preview_invalidate), + preview); + + gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0); + gtk_widget_show (frame); + + gtk_widget_show (dialog); + + run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); + + gtk_widget_destroy (dialog); + + return run; +} |