summaryrefslogtreecommitdiffstats
path: root/plug-ins/common/jigsaw.c
diff options
context:
space:
mode:
Diffstat (limited to 'plug-ins/common/jigsaw.c')
-rw-r--r--plug-ins/common/jigsaw.c2563
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;
+}