/* * jigsaw - a plug-in for the 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Contact info: nigel@cs.nwu.edu * * Version: 1.0.0 */ #include #include #include "glib.h" #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" typedef enum {BEZIER_1, BEZIER_2} style_t; typedef enum {LEFT, RIGHT, UP, DOWN} bump_t; static void query(void); static void run(gchar *name, gint nparams, GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); static gint jigsaw(void); static void run_callback(GtkWidget *widget, gpointer data); static void dialog_box(void); static void dialog_close_callback(GtkWidget *widget, gpointer data); static void entry_callback(GtkWidget *widget, gpointer data); static void entry_double_callback(GtkWidget *widget, gpointer data); static void radio_button_primitive_callback(GtkWidget *widget, gpointer data); static void adjustment_callback(GtkAdjustment *adjustment, gpointer data); static void adjustment_double_callback(GtkAdjustment *adjustment, gpointer data); static void check_button_callback(GtkWidget *widget, gpointer data); static void draw_jigsaw(guchar *buffer, gint width, gint height, gint bytes); static void draw_vertical_border(guchar *buffer, 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 width, gint bytes, gint y_offset, gint xtiles, gint blend_lines, gdouble blend_amount); static void draw_vertical_line(guchar *buffer, gint width, gint bytes, gint px[2], gint py[2]); static void draw_horizontal_line(guchar *buffer, gint width, gint bytes, gint px[2], gint py[2]); static void darken_vertical_line(guchar *buffer, gint width, gint bytes, gint *px, gint *py, gdouble delta); static void lighten_vertical_line(guchar *buffer, gint width, gint bytes, gint *px, gint *py, gdouble delta); static void darken_horizontal_line(guchar *buffer, gint width, gint bytes, gint *px, gint *py, gdouble delta); static void lighten_horizontal_line(guchar *buffer, gint width, gint bytes, gint *px, gint *py, gdouble delta); static void draw_right_bump(guchar *buffer, gint width, gint bytes, gint x_offset, gint curve_start_offset, gint steps); static void draw_left_bump(guchar *buffer, gint width, gint bytes, gint x_offset, gint curve_start_offset, gint steps); static void draw_up_bump(guchar *buffer, gint width, gint bytes, gint y_offset, gint curve_start_offset, gint steps); static void draw_down_bump(guchar *buffer, gint width, gint bytes, gint y_offset, gint curve_start_offset, gint steps); static void darken_right_bump(guchar *buffer, 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 width, gint bytes, gint x_offset, gint curve_start_offset, gint steps, gdouble delta, gint counter); static void darken_left_bump(guchar *buffer, 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 width, gint bytes, gint x_offset, gint curve_start_offset, gint steps, gdouble delta, gint counter); static void darken_up_bump(guchar *buffer, 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 width, gint bytes, gint y_offset, gint curve_start_offset, gint steps, gdouble delta, gint counter); static void darken_down_bump(guchar *buffer, 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 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 width, gint bytes, gint steps, gint *cx, gint *cy); static void darken_bezier_line(guchar *buffer, 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 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 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 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 PLUG_IN_NAME "jigsaw" #define PLUG_IN_STORAGE "jigsaw-storage" #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 ENTRY_WIDTH 40 #define XTILES_TEXT "Number of pieces going across" #define YTILES_TEXT "Number of pieces going down" #define BLEND_LINES_TEXT "Degree of slope of each piece's edge" #define BLEND_AMOUNT_TEXT "The amount of highlighting on the edges of each piece" #define SQUARE_TEXT "Each piece has straight sides" #define CURVE_TEXT "Each piece has curved sides" #define DISABLE_TEXT "Toggle Tooltips on/off" #define DRAW_POINT(buffer, index) \ do { \ buffer[index] = BLACK_R; \ buffer[index+1] = BLACK_G; \ buffer[index+2] = BLACK_B; \ } while (0) #define DARKEN_POINT(buffer, index, delta, temp) \ do { \ temp = buffer[index]; \ temp -= buffer[index] * delta; \ if (temp < MIN_VALUE) temp = MIN_VALUE; \ buffer[index] = temp; \ temp = buffer[index+1]; \ temp -= buffer[index+1] * delta; \ if (temp < MIN_VALUE) temp = MIN_VALUE; \ buffer[index+1] = temp; \ temp = buffer[index+2]; \ temp -= buffer[index+2] * delta; \ if (temp < MIN_VALUE) temp = MIN_VALUE; \ buffer[index+2] = temp; \ } while (0) #define LIGHTEN_POINT(buffer, index, delta, temp) \ do { \ temp = buffer[index] * delta; \ temp += buffer[index]; \ if (temp > MAX_VALUE) temp = MAX_VALUE; \ buffer[index] = temp; \ temp = buffer[index+1] * delta; \ temp += buffer[index+1]; \ if (temp > MAX_VALUE) temp = MAX_VALUE; \ buffer[index+1] = temp; \ temp = buffer[index+2] * delta; \ temp += buffer[index+2]; \ if (temp > MAX_VALUE) temp = MAX_VALUE; \ buffer[index+2] = temp; \ } while (0) 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 { GimpDrawable *drawable; 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]; gint dialog_result; gint tooltips; }; typedef struct globals_tag globals_t; static globals_t globals = { 0, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, -1, 1 }; MAIN() static void query(void) { static GimpParamDef args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, Non-interactive, Last-Vals"}, { 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 or 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"} }; static GimpParamDef *return_vals = NULL; static gint nargs = sizeof(args) / sizeof(args[0]); static gint nreturn_vals = 0; gimp_install_procedure("plug_in_jigsaw", "Renders a jigsaw puzzle look", "Jigsaw puzzle look", "Nigel Wetten", "Nigel Wetten", "1998", "/Filters/Render/Jigsaw", "RGB*", GIMP_PLUGIN, nargs, nreturn_vals, args, return_vals); return; } /* query */ /*****/ static void run(gchar *name, gint nparams, GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; GimpDrawable *drawable; GimpRunModeType run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; run_mode = param[0].data.d_int32; drawable = gimp_drawable_get(param[2].data.d_drawable); globals.drawable = drawable; gimp_tile_cache_ntiles(drawable->width / gimp_tile_width() + 1); 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; if (jigsaw() == -1) { status = GIMP_PDB_EXECUTION_ERROR; } } else { status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_INTERACTIVE: gimp_get_data("plug_in_jigsaw", &config); gimp_get_data(PLUG_IN_STORAGE, &globals.tooltips); dialog_box(); if (globals.dialog_result == -1) { status = GIMP_PDB_EXECUTION_ERROR; break; } gimp_progress_init("Assembling Jigsaw"); if (jigsaw() == -1) { status = GIMP_PDB_CALLING_ERROR; break; } gimp_set_data("plug_in_jigsaw", &config, sizeof(config_t)); gimp_set_data(PLUG_IN_STORAGE, &globals.tooltips, sizeof(globals.tooltips)); gimp_displays_flush(); break; case GIMP_RUN_WITH_LAST_VALS: gimp_get_data("plug_in_jigsaw", &config); if (jigsaw() == -1) { status = GIMP_PDB_EXECUTION_ERROR; gimp_message("An execution error occured."); } else { gimp_displays_flush(); } } /* switch */ gimp_drawable_detach(drawable); *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; return; } /* run */ /*****/ static gint jigsaw(void) { GimpPixelRgn src_pr, dest_pr; guchar *buffer; GimpDrawable *drawable = globals.drawable; gint width = drawable->width; gint height = drawable->height; gint bytes = drawable->bpp; gint buffer_size = bytes * width * height; srand((gint)NULL); /* setup image buffer */ gimp_pixel_rgn_init(&src_pr, drawable, 0, 0, width, height, FALSE, FALSE); gimp_pixel_rgn_init(&dest_pr, drawable, 0, 0, width, height, TRUE, TRUE); buffer = g_malloc(buffer_size); gimp_pixel_rgn_get_rect(&src_pr, buffer, 0, 0, width, height); 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, width, height, bytes); free_cache(); /* cleanup */ gimp_pixel_rgn_set_rect(&dest_pr, buffer, 0, 0, width, height); gimp_drawable_flush(drawable); gimp_drawable_merge_shadow(drawable->id, TRUE); gimp_drawable_update(drawable->id, 0, 0, width, height); g_free(buffer); return 0; } /* jigsaw */ /*****/ 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 */ return; } /* generate_bezier */ /*****/ static void draw_jigsaw(guchar *buffer, gint width, gint height, gint bytes) { 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; globals.gridx = g_malloc(sizeof(gint) * xtiles); globals.gridy = g_malloc(sizeof(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, width, height, bytes, x[i], ytiles, blend_lines, blend_amount); gimp_progress_update((gdouble) i / (gdouble) progress_total); } for (i = 0; i < ylines; i++) { draw_horizontal_border(buffer, width, bytes, y[i], xtiles, blend_lines, blend_amount); 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, width, height, bytes, x[i], xtiles, ytiles, blend_lines, blend_amount, steps); gimp_progress_update((gdouble) i / (gdouble) progress_total); } for (i = 0; i < ylines; i++) { draw_bezier_horizontal_border(buffer, width, height, bytes, y[i], xtiles, ytiles, blend_lines, blend_amount, steps); gimp_progress_update((gdouble) (i + xlines) / (gdouble) progress_total); } } else { printf("draw_jigsaw: bad style\n"); exit(1); } g_free(globals.gridx); g_free(globals.gridy); return; } /* draw_jigsaw */ /*****/ static void draw_vertical_border(guchar *buffer, 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; bump_t style_index; for (i = 0; i < ytiles; i++) { right = rand() & 1; if (right) { style_index = RIGHT; } else { style_index = LEFT; } /* 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, 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, width, bytes, px, dy, delta); px[0] = x_offset + j + 1; lighten_vertical_line(buffer, width, bytes, px, ly, delta); delta -= sigma; } /* top half of curve */ if (right) { draw_right_bump(buffer, 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, width, bytes, x_offset, y_offset + curve_start_offset, globals.steps[RIGHT], delta, j); /* use to be +j + 1 */ lighten_right_bump(buffer, width, bytes, x_offset, y_offset + curve_start_offset, globals.steps[RIGHT], delta, j); delta -= sigma; } } else { draw_left_bump(buffer, 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, width, bytes, x_offset, y_offset + curve_start_offset, globals.steps[LEFT], delta, j); /* use to be -j - 1 */ lighten_left_bump(buffer, 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, 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, width, bytes, px, dy, delta); px[0] = x_offset + j + 1; lighten_vertical_line(buffer, width, bytes, px, ly, delta); delta -= sigma; } y_offset = globals.gridy[i]; } /* for */ return; } /* draw_vertical_border */ /*****/ /* assumes RGB* */ static void draw_horizontal_border(guchar *buffer, 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 = rand() & 1; /* 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, 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, width, bytes, dx, py, delta); py[0] = y_offset + j + 1; lighten_horizontal_line(buffer, width, bytes, lx, py, delta); delta -= sigma; } if (up) { draw_up_bump(buffer, 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, width, bytes, y_offset, x_offset + curve_start_offset, globals.steps[UP], delta, j); /* use to be +j + 1 */ lighten_up_bump(buffer, width, bytes, y_offset, x_offset + curve_start_offset, globals.steps[UP], delta, j); delta -= sigma; } } else { draw_down_bump(buffer, 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, width, bytes, y_offset, x_offset + curve_start_offset, globals.steps[DOWN], delta, j); /* use to be -j -1 */ lighten_down_bump(buffer, 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, 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, width, bytes, dx, py, delta); py[0] = y_offset + j + 1; lighten_horizontal_line(buffer, width, bytes, lx, py, delta); delta -= sigma; } x_offset = globals.gridx[i]; } /* for */ return; } /* draw_horizontal_border */ /*****/ /* assumes going top to bottom */ static void draw_vertical_line(guchar *buffer, gint width, gint bytes, gint px[2], gint py[2]) { gint i; gint rowstride = bytes * width; gint index = px[0] * bytes + rowstride * py[0]; gint length = py[1] - py[0] + 1; for (i = 0; i < length; i++) { DRAW_POINT(buffer, index); index += rowstride; } return; } /* draw_vertical_line */ /*****/ /* assumes going left to right */ static void draw_horizontal_line(guchar *buffer, gint width, gint bytes, gint px[2], gint py[2]) { gint i; gint rowstride = bytes * width; gint index = px[0] * bytes + py[0] * rowstride; gint length = px[1] - px[0] + 1; for (i = 0; i < length; i++) { DRAW_POINT(buffer, index); index += bytes; } return; } /* draw_horizontal_line */ /*****/ static void draw_right_bump(guchar *buffer, gint width, gint bytes, gint x_offset, gint curve_start_offset, gint steps) { gint i; gint x, y; gint index; gint rowstride = width * bytes; 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, index); x = *(globals.cachex2[RIGHT] + i) + x_offset; y = *(globals.cachey2[RIGHT] + i) + curve_start_offset; index = y * rowstride + x * bytes; DRAW_POINT(buffer, index); } return; } /* draw_right_bump */ /*****/ static void draw_left_bump(guchar *buffer, gint width, gint bytes, gint x_offset, gint curve_start_offset, gint steps) { gint i; gint x, y; gint index; gint rowstride = width * bytes; 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, index); x = *(globals.cachex2[LEFT] + i) + x_offset; y = *(globals.cachey2[LEFT] + i) + curve_start_offset; index = y * rowstride + x * bytes; DRAW_POINT(buffer, index); } return; } /* draw_left_bump */ /*****/ static void draw_up_bump(guchar *buffer, gint width, gint bytes, gint y_offset, gint curve_start_offset, gint steps) { gint i; gint x, y; gint index; gint rowstride = width * bytes; 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, index); x = *(globals.cachex2[UP] + i) + curve_start_offset; y = *(globals.cachey2[UP] + i) + y_offset; index = y * rowstride + x * bytes; DRAW_POINT(buffer, index); } return; } /* draw_up_bump */ /*****/ static void draw_down_bump(guchar *buffer, gint width, gint bytes, gint y_offset, gint curve_start_offset, gint steps) { gint i; gint x, y; gint index; gint rowstride = width * bytes; 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, index); x = *(globals.cachex2[DOWN] + i) + curve_start_offset; y = *(globals.cachey2[DOWN] + i) + y_offset; index = y * rowstride + x * bytes; DRAW_POINT(buffer, index); } return; } /* draw_down_bump */ /*****/ static void malloc_cache(void) { gint i, j; gint blend_lines = config.blend_lines; gint length = blend_lines * sizeof(gint *); for (i = 0; i < 4; i++) { gint steps_length = globals.steps[i] * sizeof(gint); globals.cachex1[i] = g_malloc(steps_length); globals.cachex2[i] = g_malloc(steps_length); globals.cachey1[i] = g_malloc(steps_length); globals.cachey2[i] = g_malloc(steps_length); globals.blend_outer_cachex1[i] = g_malloc(length); globals.blend_outer_cachex2[i] = g_malloc(length); globals.blend_outer_cachey1[i] = g_malloc(length); globals.blend_outer_cachey2[i] = g_malloc(length); globals.blend_inner_cachex1[i] = g_malloc(length); globals.blend_inner_cachex2[i] = g_malloc(length); globals.blend_inner_cachey1[i] = g_malloc(length); globals.blend_inner_cachey2[i] = g_malloc(length); for (j = 0; j < blend_lines; j++) { *(globals.blend_outer_cachex1[i] + j) = g_malloc(steps_length); *(globals.blend_outer_cachex2[i] + j) = g_malloc(steps_length); *(globals.blend_outer_cachey1[i] + j) = g_malloc(steps_length); *(globals.blend_outer_cachey2[i] + j) = g_malloc(steps_length); *(globals.blend_inner_cachex1[i] + j) = g_malloc(steps_length); *(globals.blend_inner_cachex2[i] + j) = g_malloc(steps_length); *(globals.blend_inner_cachey1[i] + j) = g_malloc(steps_length); *(globals.blend_inner_cachey2[i] + j) = g_malloc(steps_length); } } /* for */ return; } /* malloc_cache() */ /*****/ 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]); } /* for */ return; } /* free_cache */ /*****/ 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)); } return; } /* init_right_bump */ /*****/ 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)); } return; } /* init_left_bump */ /*****/ 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)); } return; } /* init_top_bump */ /*****/ 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)); } return; } /* init_down_bump */ /*****/ 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 */ return; } /* generate_grid */ /*****/ /* assumes RGB* */ /* assumes py[1] > py[0] and px[0] = px[1] */ static void darken_vertical_line(guchar *buffer, gint width, gint bytes, gint px[2], gint py[2], gdouble delta ) { gint i; gint rowstride = width * bytes; gint index = px[0] * bytes + py[0] * rowstride; gint length = py[1] - py[0] + 1; gint temp; for (i = 0; i < length; i++) { DARKEN_POINT(buffer, index, delta, temp); index += rowstride; } return; } /* darken_vertical_line */ /*****/ /* assumes RGB* */ /* assumes py[1] > py[0] and px[0] = px[1] */ static void lighten_vertical_line(guchar *buffer, gint width, gint bytes, gint px[2], gint py[2], gdouble delta) { gint i; gint rowstride = width * bytes; gint index = px[0] * bytes + py[0] * rowstride; gint length = py[1] - py[0] + 1; gint temp; for (i = 0; i < length; i++) { LIGHTEN_POINT(buffer, index, delta, temp); index += rowstride; } return; } /* lighten_vertical_line */ /*****/ /* assumes RGB* */ /* assumes px[1] > px[0] and py[0] = py[1] */ static void darken_horizontal_line(guchar *buffer, gint width, gint bytes, gint px[2], gint py[2], gdouble delta) { gint i; gint rowstride = width * bytes; gint index = px[0] * bytes + py[0] * rowstride; gint length = px[1] - px[0] + 1; gint temp; for (i = 0; i < length; i++) { DARKEN_POINT(buffer, index, delta, temp); index += bytes; } return; } /* darken_horizontal_line */ /*****/ /* assumes RGB* */ /* assumes px[1] > px[0] and py[0] = py[1] */ static void lighten_horizontal_line(guchar *buffer, gint width, gint bytes, gint px[2], gint py[2], gdouble delta) { gint i; gint rowstride = width * bytes; gint index = px[0] * bytes + py[0] * rowstride; gint length = px[1] - px[0] + 1; gint temp; for (i = 0; i < length; i++) { LIGHTEN_POINT(buffer, index, delta, temp); index += bytes; } return; } /* lighten_horizontal_line */ /*****/ static void darken_right_bump(guchar *buffer, 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 = width * bytes; gint temp; gint j = counter; 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, index, delta, temp); } else { DARKEN_POINT(buffer, 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, index, delta, temp); last_index2 = index; } } return; } /* darken_right_bump */ /*****/ static void lighten_right_bump(guchar *buffer, 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 = width * bytes; gint temp; gint j = counter; 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, index, delta, temp); } else { LIGHTEN_POINT(buffer, 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, index, delta, temp); last_index2 = index; } } return; } /* lighten_right_bump */ /*****/ static void darken_left_bump(guchar *buffer, 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 = width * bytes; gint temp; gint j = counter; 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, 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, index, delta, temp); } else { LIGHTEN_POINT(buffer, index, delta, temp); } last_index2 = index; } } return; } /* darken_left_bump */ /*****/ static void lighten_left_bump(guchar *buffer, 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 = width * bytes; gint temp; gint j = counter; 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, 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, index, delta, temp); } else { DARKEN_POINT(buffer, index, delta, temp); } last_index2 = index; } } return; } /* lighten_left_bump */ /*****/ static void darken_up_bump(guchar *buffer, 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 = width * bytes; gint temp; gint j = counter; 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, 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, index, delta, temp); } else { LIGHTEN_POINT(buffer, index, delta, temp); } last_index2 = index; } } return; } /* darken_up_bump */ /*****/ static void lighten_up_bump(guchar *buffer, 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 = width * bytes; gint temp; gint j = counter; 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, 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, index, delta, temp); } else { DARKEN_POINT(buffer, index, delta, temp); } last_index2 = index; } } return; } /* lighten_up_bump */ /*****/ static void darken_down_bump(guchar *buffer, 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 = width * bytes; gint temp; gint j = counter; 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, index, delta, temp); } else { DARKEN_POINT(buffer, 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, index, delta, temp); last_index2 = index; } } return; } /* darken_down_bump */ /*****/ static void lighten_down_bump(guchar *buffer, 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 = width * bytes; gint temp; gint j = counter; 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, index, delta, temp); } else { LIGHTEN_POINT(buffer, 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, index, delta, temp); last_index2 = index; } } return; } /* lighten_down_bump */ /*****/ static void draw_bezier_line(guchar *buffer, gint width, gint bytes, gint steps, gint *cx, gint *cy) { gint i; gint x, y; gint index; gint rowstride = width * bytes; for (i = 0; i < steps; i++) { x = cx[i]; y = cy[i]; index = y * rowstride + x * bytes; DRAW_POINT(buffer, index); } return; } /* draw_bezier_line */ /*****/ static void darken_bezier_line(guchar *buffer, 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 = width * bytes; gint temp; 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, index, delta, temp); last_index = index; } } return; } /* darken_bezier_line */ /*****/ static void lighten_bezier_line(guchar *buffer, 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 = width * bytes; gint temp; 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, index, delta, temp); last_index = index; } } return; } /* lighten_bezier_line */ /*****/ static void draw_bezier_vertical_border(guchar *buffer, 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; bump_t style_index; gint *cachex, *cachey; cachex = g_malloc(steps * sizeof(gint)); cachey = g_malloc(steps * sizeof(gint)); for (i = 0; i < ytiles; i++) { right = rand() & 1; if (right) { style_index = RIGHT; } else { style_index = LEFT; } 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, width, bytes, steps, cachex, cachey); delta = blend_amount; for (j = 0; j < blend_lines; j++) { px[0] = -j - 1; darken_bezier_line(buffer, width, bytes, px[0], 0, steps, cachex, cachey, delta); px[0] = j + 1; lighten_bezier_line(buffer, width, bytes, px[0], 0, steps, cachex, cachey, delta); delta -= sigma; } if (right) { draw_right_bump(buffer, 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, width, bytes, x_offset, y_offset + curve_start_offset, globals.steps[RIGHT], delta, j); /* use to be +j + 1 */ lighten_right_bump(buffer, width, bytes, x_offset, y_offset + curve_start_offset, globals.steps[RIGHT], delta, j); delta -= sigma; } } else { draw_left_bump(buffer, 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, width, bytes, x_offset, y_offset + curve_start_offset, globals.steps[LEFT], delta, j); /* use to be -j - 1 */ lighten_left_bump(buffer, 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, width, bytes, steps, cachex, cachey); delta = blend_amount; for (j = 0; j < blend_lines; j++) { px[0] = -j - 1; darken_bezier_line(buffer, width, bytes, px[0], 0, steps, cachex, cachey, delta); px[0] = j + 1; lighten_bezier_line(buffer, width, bytes, px[0], 0, steps, cachex, cachey, delta); delta -= sigma; } y_offset = globals.gridy[i]; } /* for */ g_free(cachex); g_free(cachey); return; } /* draw_bezier_vertical_border */ /*****/ static void draw_bezier_horizontal_border(guchar *buffer, 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; style_t style_index; gint *cachex, *cachey; cachex = g_malloc(steps * sizeof(gint)); cachey = g_malloc(steps * sizeof(gint)); for (i = 0; i < xtiles; i++) { up = rand() & 1; if (up) { style_index = UP; } else { style_index = DOWN; } 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, width, bytes, steps, cachex, cachey); delta = blend_amount; for (j = 0; j < blend_lines; j++) { py[0] = -j - 1; darken_bezier_line(buffer, width, bytes, 0, py[0], steps, cachex, cachey, delta); py[0] = j + 1; lighten_bezier_line(buffer, width, bytes, 0, py[0], steps, cachex, cachey, delta); delta -= sigma; } /* bumps */ if (up) { draw_up_bump(buffer, 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, width, bytes, y_offset, x_offset + curve_start_offset, globals.steps[UP], delta, j); /* use to be +j + 1 */ lighten_up_bump(buffer, width, bytes, y_offset, x_offset + curve_start_offset, globals.steps[UP], delta, j); delta -= sigma; } } else { draw_down_bump(buffer, 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, width, bytes, y_offset, x_offset + curve_start_offset, globals.steps[DOWN], delta, j); /* use to be -j -1 */ lighten_down_bump(buffer, 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, width, bytes, steps, cachex, cachey); delta = blend_amount; for (j = 0; j < blend_lines; j++) { py[0] = -j - 1; darken_bezier_line(buffer, width, bytes, 0, py[0], steps, cachex, cachey, delta); py[0] = j + 1; lighten_bezier_line(buffer, width, bytes, 0, py[0], steps, cachex, cachey, delta); delta -= sigma; } x_offset = globals.gridx[i]; } /* for */ g_free(cachex); g_free(cachey); return; } /* draw_bezier_horizontal_border */ /*****/ 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); } return; } /*check_config */ /*****/ /******************************************************** GUI ********************************************************/ static void dialog_box(void) { GtkWidget *dlg; GtkWidget *button; GtkWidget *rbutton; GtkWidget *cbutton; GSList *list; GtkWidget *hbox; GtkWidget *frame; GtkWidget *label; GtkWidget *entry; GtkWidget *table; GtkWidget *scale; GtkObject *adjustment; GtkTooltips *tooltips; GdkColor tips_fg, tips_bg; gchar buffer[12]; gchar **argv; gint argc; argc = 1; argv = g_new(gchar *, 1); argv[0] = g_strdup(PLUG_IN_NAME); gtk_init(&argc, &argv); gtk_rc_parse(gimp_gtkrc()); /* Create the dialog box */ dlg = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dlg), PLUG_IN_NAME); gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE); gtk_signal_connect(GTK_OBJECT(dlg), "destroy", (GtkSignalFunc) dialog_close_callback, NULL); /* Action Area */ button = gtk_button_new_with_label("OK"); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) run_callback, dlg); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_grab_default(button); gtk_widget_show(button); button = gtk_button_new_with_label("Cancel"); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT(dlg)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_show(button); /* init tooltips */ tooltips = gtk_tooltips_new(); tips_fg.red = 0; tips_fg.green = 0; tips_fg.blue = 0; gdk_color_alloc(gtk_widget_get_colormap(dlg), &tips_fg); tips_bg.red = 61669; tips_bg.green = 59113; tips_bg.blue = 35979; gdk_color_alloc(gtk_widget_get_colormap(dlg), &tips_bg); gtk_tooltips_set_colors(tooltips, &tips_bg, &tips_fg); if (globals.tooltips == 0) { gtk_tooltips_disable(tooltips); } /* paramters frame */ frame = gtk_frame_new("Number of Tiles"); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width(GTK_CONTAINER(frame), 10); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), frame, TRUE, TRUE, 0); table = gtk_table_new(3, 2, FALSE); gtk_container_border_width (GTK_CONTAINER(table), 10); gtk_container_add(GTK_CONTAINER(frame), table); /* xtiles */ label = gtk_label_new("Horizontal:"); gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 5, 0); gtk_widget_show(label); adjustment = gtk_adjustment_new(config.x, MIN_XTILES, MAX_XTILES, 1.0, 1.0, 0); gtk_signal_connect(GTK_OBJECT(adjustment), "value_changed", (GtkSignalFunc) adjustment_callback, &config.x); scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment)); gtk_widget_set_usize(scale, SCALE_WIDTH, 0); gtk_table_attach(GTK_TABLE(table), scale, 1, 2, 0, 1, GTK_FILL, 0, 0, 0); gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE); gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); gtk_widget_show(scale); gtk_tooltips_set_tip(tooltips, scale, XTILES_TEXT, NULL); entry = gtk_entry_new(); gtk_object_set_user_data(GTK_OBJECT(entry), adjustment); gtk_object_set_user_data(GTK_OBJECT(adjustment), entry); gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); sprintf(buffer, "%i", config.x); gtk_entry_set_text(GTK_ENTRY(entry), buffer); gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(entry_callback), (gpointer) &config.x); gtk_table_attach(GTK_TABLE(table), entry, 2, 3, 0, 1, GTK_FILL, 0, 0, 0); gtk_widget_show(entry); gtk_tooltips_set_tip(tooltips, entry, XTILES_TEXT, NULL); /* ytiles */ label = gtk_label_new("Vertical:"); gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 0); gtk_widget_show(label); adjustment = gtk_adjustment_new(config.y, MIN_YTILES, MAX_YTILES, 1.0, 1.0, 0 ); gtk_signal_connect(GTK_OBJECT(adjustment), "value_changed", (GtkSignalFunc) adjustment_callback, &config.y); scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment)); gtk_widget_set_usize(scale, SCALE_WIDTH, 0); gtk_table_attach(GTK_TABLE(table), scale, 1, 2, 1, 2, GTK_FILL, 0, 0, 0); gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE); gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); gtk_widget_show(scale); gtk_tooltips_set_tip(tooltips, scale, YTILES_TEXT, NULL); entry = gtk_entry_new(); gtk_object_set_user_data(GTK_OBJECT(entry), adjustment); gtk_object_set_user_data(GTK_OBJECT(adjustment), entry); gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); sprintf(buffer, "%i", config.y); gtk_entry_set_text(GTK_ENTRY(entry), buffer); gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(entry_callback), (gpointer) &config.y); gtk_table_attach(GTK_TABLE(table), entry, 2, 3, 1, 2, GTK_FILL, 0, 0, 0); gtk_widget_show(entry); gtk_tooltips_set_tip(tooltips, entry, YTILES_TEXT, NULL); gtk_widget_show(table); gtk_widget_show(frame); /* frame for bevel blending */ frame = gtk_frame_new("Bevel Edges"); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width(GTK_CONTAINER(frame), 10); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), frame, TRUE, TRUE, 0); table = gtk_table_new(3, 2, FALSE); gtk_container_border_width(GTK_CONTAINER(table), 10); gtk_container_add(GTK_CONTAINER(frame), table); /* number of blending lines */ label = gtk_label_new("Bevel width:"); gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 5, 0); gtk_widget_show(label); adjustment = gtk_adjustment_new(config.blend_lines, MIN_BLEND_LINES, MAX_BLEND_LINES, 1.0, 1.0, 0); gtk_signal_connect(GTK_OBJECT(adjustment), "value_changed", (GtkSignalFunc) adjustment_callback, &config.blend_lines); scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment)); gtk_widget_set_usize(scale, SCALE_WIDTH, 0); gtk_table_attach(GTK_TABLE(table), scale, 1, 2, 0, 1, GTK_FILL, 0, 0, 0); gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE); gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); gtk_widget_show(scale); gtk_tooltips_set_tip(tooltips, scale, BLEND_LINES_TEXT, NULL); entry = gtk_entry_new(); gtk_object_set_user_data(GTK_OBJECT(entry), adjustment); gtk_object_set_user_data(GTK_OBJECT(adjustment), entry); gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); sprintf(buffer, "%i", config.blend_lines); gtk_entry_set_text(GTK_ENTRY(entry), buffer); gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(entry_callback), (gpointer) &config.blend_lines); gtk_table_attach(GTK_TABLE(table), entry, 2, 3, 0, 1, GTK_FILL, 0, 0, 0); gtk_widget_show(entry); gtk_tooltips_set_tip(tooltips, entry, BLEND_LINES_TEXT, NULL); /* blending amount */ label = gtk_label_new("Highlight:"); gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 0); gtk_widget_show(label); adjustment = gtk_adjustment_new(config.blend_amount, MIN_BLEND_AMOUNT, MAX_BLEND_AMOUNT, 1.0, 0.05, 0.0); gtk_signal_connect(GTK_OBJECT(adjustment), "value_changed", (GtkSignalFunc) adjustment_double_callback, &config.blend_amount); scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment)); gtk_widget_set_usize(scale, SCALE_WIDTH, 0); gtk_table_attach(GTK_TABLE(table), scale, 1, 2, 1, 2, GTK_FILL, 0, 0, 0); gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE); gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); gtk_widget_show(scale); gtk_tooltips_set_tip(tooltips, scale, BLEND_AMOUNT_TEXT, NULL); entry = gtk_entry_new(); gtk_object_set_user_data(GTK_OBJECT(entry), adjustment); gtk_object_set_user_data(GTK_OBJECT(adjustment), entry); gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); sprintf(buffer, "%0.2f", config.blend_amount); gtk_entry_set_text(GTK_ENTRY(entry), buffer); gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(entry_double_callback), (gpointer) &config.blend_amount); gtk_table_attach(GTK_TABLE(table), entry, 2, 3, 1, 2, GTK_FILL, 0, 0, 0); gtk_widget_show(entry); gtk_tooltips_set_tip(tooltips, entry, BLEND_AMOUNT_TEXT, NULL); gtk_widget_show(table); gtk_widget_show(frame); /* frame for primitive radio buttons */ hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), hbox, FALSE, FALSE, 0); frame = gtk_frame_new("Jigsaw Style"); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width(GTK_CONTAINER(frame), 10); gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); table = gtk_table_new(2, 1, FALSE); gtk_container_border_width(GTK_CONTAINER(table), 5); gtk_container_add(GTK_CONTAINER(frame), table); rbutton = gtk_radio_button_new_with_label(NULL, "Square"); list = gtk_radio_button_group((GtkRadioButton *) rbutton); gtk_toggle_button_set_state((GtkToggleButton *) rbutton, config.style == BEZIER_1 ? TRUE : FALSE); gtk_signal_connect(GTK_OBJECT(rbutton), "toggled", GTK_SIGNAL_FUNC(radio_button_primitive_callback), (gpointer) BEZIER_1); gtk_table_attach(GTK_TABLE(table), rbutton, 0, 1, 0, 1, GTK_FILL, 0, 10, 0); gtk_widget_show(rbutton); gtk_tooltips_set_tip(tooltips, rbutton, SQUARE_TEXT, NULL); rbutton = gtk_radio_button_new_with_label(list, "Curved"); list = gtk_radio_button_group((GtkRadioButton *) rbutton); gtk_toggle_button_set_state((GtkToggleButton *) rbutton, config.style == BEZIER_2 ? TRUE : FALSE); gtk_signal_connect(GTK_OBJECT(rbutton), "toggled", GTK_SIGNAL_FUNC(radio_button_primitive_callback), (gpointer) BEZIER_2); gtk_table_attach(GTK_TABLE(table), rbutton, 1, 2, 0, 1, GTK_FILL, 0, 10, 0); gtk_widget_show(rbutton); gtk_tooltips_set_tip(tooltips, rbutton, CURVE_TEXT, NULL); gtk_widget_show(table); gtk_widget_show(frame); table = gtk_table_new(1, 3, FALSE); gtk_container_border_width(GTK_CONTAINER(table), 3); gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0); cbutton = gtk_check_button_new_with_label("Disable Tooltips"); gtk_toggle_button_set_state((GtkToggleButton *) cbutton, globals.tooltips ? FALSE : TRUE); gtk_signal_connect(GTK_OBJECT(cbutton), "toggled", (GtkSignalFunc) check_button_callback, (gpointer) tooltips); gtk_table_attach(GTK_TABLE(table), cbutton, 0, 1, 1, 2, 0, 0, 0, 20); gtk_widget_show(cbutton); gtk_tooltips_set_tip(tooltips, cbutton, DISABLE_TEXT, NULL); gtk_widget_show(table); gtk_widget_show(hbox); gtk_widget_show(dlg); gtk_main(); gdk_flush(); return; } /*************************************************** callbacks ***************************************************/ static void run_callback(GtkWidget *widget, gpointer data) { globals.dialog_result = 1; gtk_widget_destroy(GTK_WIDGET(data)); return; } /*****/ static void dialog_close_callback(GtkWidget *widget, gpointer data) { gtk_main_quit(); return; } /* dialog_close_callback */ /*****/ static void entry_callback(GtkWidget *widget, gpointer data) { GtkAdjustment *adjustment; gint new_value; new_value = atoi(gtk_entry_get_text(GTK_ENTRY(widget))); if (*(gint *)data != new_value) { *(gint *)data = new_value; adjustment = gtk_object_get_user_data(GTK_OBJECT(widget)); if ((new_value >= adjustment->lower) && (new_value <= adjustment->upper)) { adjustment->value = new_value; gtk_signal_handler_block_by_data(GTK_OBJECT(adjustment), data); gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_signal_handler_unblock_by_data(GTK_OBJECT(adjustment), data); } } return; } /* entry_callback */ /*****/ static void radio_button_primitive_callback(GtkWidget *widget, gpointer data) { if (GTK_TOGGLE_BUTTON (widget)->active) /* button just got checked */ { if (data == (gpointer) BEZIER_1) { config.style = BEZIER_1; } else if (data == (gpointer) BEZIER_2) { config.style = BEZIER_2; } else { printf("radio_button_callback: bad data\n"); } } return; } /* radio_button_primitive_callback */ /*****/ static void check_button_callback(GtkWidget *widget, gpointer data) { if (GTK_TOGGLE_BUTTON (widget)->active) { gtk_tooltips_disable((GtkTooltips *) data); globals.tooltips = 0; } else { gtk_tooltips_enable((GtkTooltips *) data); globals.tooltips = 1; } return; } /* check_button_callback */ /*****/ static void adjustment_callback(GtkAdjustment *adjustment, gpointer data) { GtkWidget *entry; gchar buffer[50]; if (*(gint *)data != adjustment->value) { *(gint *)data = adjustment->value; entry = gtk_object_get_user_data(GTK_OBJECT(adjustment)); sprintf(buffer, "%d", *(gint *)data); gtk_signal_handler_block_by_data(GTK_OBJECT(entry), data); gtk_entry_set_text(GTK_ENTRY(entry), buffer); gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), data); } return; } /* adjustment_callback */ /*****/ static void adjustment_double_callback(GtkAdjustment *adjustment, gpointer data) { GtkWidget *entry; gchar buffer[50]; if (*(gdouble *)data != adjustment->value) { *(gdouble *)data = adjustment->value; entry = gtk_object_get_user_data(GTK_OBJECT(adjustment)); sprintf(buffer, "%0.2f", *(gdouble *)data); gtk_signal_handler_block_by_data(GTK_OBJECT(entry), data); gtk_entry_set_text(GTK_ENTRY(entry), buffer); gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), data); } return; } /* adjustment_double_callback */ /*****/ static void entry_double_callback(GtkWidget *widget, gpointer data) { GtkAdjustment *adjustment; gdouble new_value; new_value = atof(gtk_entry_get_text(GTK_ENTRY(widget))); if (*(gdouble *)data != new_value) { *(gdouble *)data = new_value; adjustment = gtk_object_get_user_data(GTK_OBJECT(widget)); if ((new_value >= adjustment->lower) && (new_value <= adjustment->upper)) { adjustment->value = new_value; gtk_signal_handler_block_by_data(GTK_OBJECT(adjustment), data); gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_signal_handler_unblock_by_data(GTK_OBJECT(adjustment), data); } } return; } /* entry_double_callback */