From 625df2ac593383bf1f00680813cf0e0a2a417aee Mon Sep 17 00:00:00 2001 From: Marc Lehmann Date: Fri, 3 Sep 1999 23:14:44 +0000 Subject: [PATCH] *** empty log message *** --- ChangeLog | 6 +- plug-ins/AlienMap2/AlienMap2.c | 1234 +++++++++++ plug-ins/AlienMap2/Makefile.am | 36 + plug-ins/AlienMap2/logo.h | 788 +++++++ plug-ins/Makefile.am | 1 + plug-ins/common/Makefile.am | 20 + plug-ins/common/color_enhance.c | 479 ++++ plug-ins/common/nova.c | 988 +++++---- plug-ins/common/plugin-defs.pl | 2 + plug-ins/common/sparkle.c | 620 ++++-- plug-ins/common/warp.c | 1922 +++++++++++++++++ plug-ins/script-fu/scripts/frosty-logo.scm | 2 +- plug-ins/script-fu/scripts/starburst-logo.scm | 2 +- plug-ins/script-fu/scripts/starscape-logo.scm | 2 +- plug-ins/script-fu/scripts/t-o-p-logo.scm | 2 +- 15 files changed, 5551 insertions(+), 553 deletions(-) create mode 100644 plug-ins/AlienMap2/AlienMap2.c create mode 100644 plug-ins/AlienMap2/Makefile.am create mode 100644 plug-ins/AlienMap2/logo.h create mode 100644 plug-ins/common/color_enhance.c create mode 100644 plug-ins/common/warp.c diff --git a/ChangeLog b/ChangeLog index e9a2a500c3..5d2e396072 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,10 @@ Sat Sep 4 01:04:00 CEST 1999 Marc Lehmann - * plug-ins/Makefile.am, plug.ins/AlienMap2: new plug-in. + * plug-ins/Makefile.am, plug-ins/AlienMap2: new plug-in. Sat Sep 4 00:38:01 CEST 1999 Marc Lehmann - * plug-ins/common/nova.c, + * plug-ins/common/nova.c, plug-ins/common/Makefile.am, plug-ins/script-fu/scripts/starburst-logo.scm, plug-ins/script-fu/scripts/starscape-logo.scm: updated nova plug-in and two dependent scripts. @@ -16,7 +16,7 @@ Sat Sep 4 00:32:18 CEST 1999 Marc Lehmann Sat Sep 4 00:23:07 CEST 1999 Marc Lehmann - * plug-ins/common/sparkle.c, + * plug-ins/common/sparkle.c, plug-ins/common/Makefile.am, plug-ins/script-fu/scripts/frosty-logo.scm, plug-ins/script-fu/scripts/t-o-p-logo.scm: updated sparkle plug-in and two dependent scripts. diff --git a/plug-ins/AlienMap2/AlienMap2.c b/plug-ins/AlienMap2/AlienMap2.c new file mode 100644 index 0000000000..6fe98ac121 --- /dev/null +++ b/plug-ins/AlienMap2/AlienMap2.c @@ -0,0 +1,1234 @@ +/********************************************************************** + * AlienMap2 (Co-)sine color transformation plug-in (Version 1.01) + * Martin Weber (martin.weber@usa.net) + ********************************************************************** + * Official Homepage: http://diverse.freepage.de/martin.weber + ********************************************************************** + * Most code taken from AlienMap by Daniel Cotting + * This is not a replacement for AlienMap! + ********************************************************************** + */ + +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + */ + +#include +#include +#include +#include "gtk/gtk.h" +#include "libgimp/gimp.h" +#include "logo.h" + +/***** Macros *****/ + +#define ALIEN_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define ALIEN_MAX(a, b) (((a) > (b)) ? (a) : (b)) + + +/***** Magic numbers *****/ + +#define PREVIEW_SIZE 128 +#define SCALE_WIDTH 200 +#define ENTRY_WIDTH 45 + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /* M_PI */ + +/***** Color model *****/ + +#define RGB 0 +#define HSL 1 + +/***** Types *****/ +typedef struct { + gdouble redfrequency; + gdouble redangle; + gdouble greenfrequency; + gdouble greenangle; + gdouble bluefrequency; + gdouble blueangle; + gint colormodel; + gint redmode; + gint greenmode; + gint bluemode; +} alienmap2_vals_t; + +typedef struct { + GtkWidget *preview; + guchar *image; + guchar *wimage; + gint run; +} alienmap2_interface_t; + + + +/* Declare local functions. */ + +static void query (void); +static void run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals); + +static void alienmap2 (GDrawable *drawable); +static void alienmap2_render_row (const guchar *src_row, + guchar *dest_row, + gint row, + gint row_width, + gint bytes); +static void alienmap2_get_pixel(int x, int y, guchar *pixel); +void transform (short int *, short int *, short int *); + + +static void build_preview_source_image(void); + +static gint alienmap2_dialog(void); +static void dialog_update_preview(void); +static void dialog_create_value(char *title, GtkTable *table, int row, gdouble *value, + int left, int right, const char *desc); +static void dialog_scale_update(GtkAdjustment *adjustment, gdouble *value); +static void dialog_entry_update(GtkWidget *widget, gdouble *value); +static void dialog_close_callback(GtkWidget *widget, gpointer data); +static void dialog_ok_callback(GtkWidget *widget, gpointer data); +static void dialog_cancel_callback(GtkWidget *widget, gpointer data); +static void alienmap2_toggle_update (GtkWidget *widget, + gpointer data); +void alienmap2_logo_dialog (void); +static void rgb_to_hsl (gdouble r, + gdouble g, + gdouble b, + gdouble * h, + gdouble * s, + gdouble * l); +static void hsl_to_rgb (gdouble h, + gdouble sl, + gdouble l, + gdouble * r, + gdouble * g, + gdouble * b); + + + + + +/***** Variables *****/ + +GtkWidget *maindlg; +GtkWidget *logodlg; +GtkTooltips *tips; +GdkColor tips_fg,tips_bg; + +GPlugInInfo PLUG_IN_INFO = +{ + NULL, /* init_proc */ + NULL, /* quit_proc */ + query, /* query_proc */ + run, /* run_proc */ +}; + +static alienmap2_interface_t wint = { + NULL, /* preview */ + NULL, /* image */ + NULL, /* wimage */ + FALSE /* run */ +}; /* wint */ + +static alienmap2_vals_t wvals = { + 1.0, + 0.0, + 1.0, + 0.0, + 1.0, + 0.0, + RGB, + FALSE, + FALSE, + FALSE, +}; /* wvals */ + +static GDrawable *drawable; +static gint tile_width, tile_height; +static gint img_width, img_height, img_bpp; +static gint sel_x1, sel_y1, sel_x2, sel_y2; +static gint sel_width, sel_height; +static gint preview_width, preview_height; +static GTile *the_tile = NULL; +static double cen_x, cen_y; +static double scale_x, scale_y; + +gint use_rgb; +gint use_hsl; + +/***** Functions *****/ + + +MAIN () + +static void +query () +{ + static GParamDef args[] = + { + { PARAM_INT32, "run_mode", "Interactive, non-interactive" }, + { PARAM_IMAGE, "image", "Input image" }, + { PARAM_DRAWABLE, "drawable", "Input drawable" }, + { PARAM_FLOAT, "redfrequency", "Red/hue component frequency factor" }, + { PARAM_FLOAT, "redangle", "Red/hue component angle factor (0-360)" }, + { PARAM_FLOAT, "greenfrequency", "Green/saturation component frequency factor" }, + { PARAM_FLOAT, "greenangle", "Green/saturation component angle factor (0-360)" }, + { PARAM_FLOAT, "bluefrequency", "Blue/luminance component frequency factor" }, + { PARAM_FLOAT, "blueangle", "Blue/luminance component angle factor (0-360)" }, + { PARAM_INT8, "colormodel", "Color model (0: RGB, 1: HSL)" }, + { PARAM_INT8, "redmode", "Red/hue application mode (TRUE, FALSE)" }, + { PARAM_INT8, "greenmode", "Green/saturation application mode (TRUE, FALSE)" }, + { PARAM_INT8, "bluemode", "Blue/luminance application mode (TRUE, FALSE)" }, + }; + static GParamDef *return_vals = NULL; + static int nargs = sizeof (args) / sizeof (args[0]); + static int nreturn_vals = 0; + + gimp_install_procedure ("plug_in_alienmap2", + "AlienMap2 Color Transformation Plug-In", + "No help yet. Just try it and you'll see!", + "Martin Weber (martin.weber@usa.net, http://diverse.freepage.de/martin.weber)", + "Martin Weber (martin.weber@usa.net, http://diverse.freepage.de/martin.weber", + "24th April 1998", + "/Filters/Colors/Alien Map 2", + "RGB*", + PROC_PLUG_IN, + nargs, nreturn_vals, + args, return_vals); +} + + + +void +transform (short int *r, + short int *g, + short int *b) +{ + gint red, green, blue; + gdouble r1, g1, b1, h, s, l; + red = *r; + green = *g; + blue = *b; + + if (wvals.colormodel == HSL) + { + r1 = (gdouble) red / 255.0; + g1 = (gdouble) green / 255.0; + b1 = (gdouble) blue / 255.0; + rgb_to_hsl (r1, g1, b1, &h, &s, &l); + if (wvals.redmode) + h = 0.5*(1.0+sin(((2*h-1.0)*wvals.redfrequency+wvals.redangle/180.0)*M_PI)); + if (wvals.greenmode) + s = 0.5*(1.0+sin(((2*s-1.0)*wvals.greenfrequency+wvals.greenangle/180.0)*M_PI)); + if (wvals.bluemode) + l = 0.5*(1.0+sin(((2*l-1.0)*wvals.bluefrequency+wvals.blueangle/180.0)*M_PI)); + hsl_to_rgb (h, s, l, &r1, &g1, &b1); + red = (gint) (255.0 * r1 + 0.5); + green = (gint) (255.0 * g1 + 0.5); + blue = (gint) (255.0 * b1 + 0.5); + } + else if (wvals.colormodel == RGB) + { + if (wvals.redmode) + red = (int) (127.5*(1.0+sin(((red/127.5-1.0)*wvals.redfrequency+wvals.redangle/180.0)*M_PI))+0.5); + if (wvals.greenmode) + green = (int) (127.5*(1.0+sin(((green/127.5-1.0)*wvals.greenfrequency+wvals.greenangle/180.0)*M_PI))+0.5); + if (wvals.bluemode) + blue = (int) (127.5*(1.0+sin(((blue/127.5-1.0)*wvals.bluefrequency+wvals.blueangle/180.0)*M_PI))+0.5); + } + + *r = red; + *g = green; + *b = blue; +} + + +static void +run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals) +{ + static GParam values[1]; +/* GDrawable *drawable; */ +/* gint32 image_ID; */ + GRunModeType run_mode; + double xhsiz, yhsiz; + int pwidth, pheight; + GStatusType status = STATUS_SUCCESS; + + + run_mode = param[0].data.d_int32; + + values[0].type = PARAM_STATUS; + values[0].data.d_status = status; + + *nreturn_vals = 1; + *return_vals = values; + + + + /* Get the specified drawable */ + drawable = gimp_drawable_get (param[2].data.d_drawable); +/* image_ID = param[1].data.d_image; */ + tile_width = gimp_tile_width(); + tile_height = gimp_tile_height(); + + img_width = gimp_drawable_width(drawable->id); + img_height = gimp_drawable_height(drawable->id); + img_bpp = gimp_drawable_bpp(drawable->id); + + gimp_drawable_mask_bounds(drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2); + + sel_width = sel_x2 - sel_x1; + sel_height = sel_y2 - sel_y1; + + cen_x = (double) (sel_x2 - 1 + sel_x1) / 2.0; + cen_y = (double) (sel_y2 - 1 + sel_y1) / 2.0; + + xhsiz = (double) (sel_width - 1) / 2.0; + yhsiz = (double) (sel_height - 1) / 2.0; + + if (xhsiz < yhsiz) { + scale_x = yhsiz / xhsiz; + scale_y = 1.0; + } else if (xhsiz > yhsiz) { + scale_x = 1.0; + scale_y = xhsiz / yhsiz; + } else { + scale_x = 1.0; + scale_y = 1.0; + } /* else */ + + /* Calculate preview size */ + if (sel_width > sel_height) { + pwidth = ALIEN_MIN(sel_width, PREVIEW_SIZE); + pheight = sel_height * pwidth / sel_width; + } else { + pheight = ALIEN_MIN(sel_height, PREVIEW_SIZE); + pwidth = sel_width * pheight / sel_height; + } /* else */ + + preview_width = ALIEN_MAX(pwidth, 2); /* Min size is 2 */ + preview_height = ALIEN_MAX(pheight, 2); + + /* See how we will run */ + switch (run_mode) { + case RUN_INTERACTIVE: + /* Possibly retrieve data */ + + gimp_get_data("plug_in_alienmap2", &wvals); + + /* Get information from the dialog */ + + if (!alienmap2_dialog()) + return; + + break; + + case RUN_NONINTERACTIVE: + /* Make sure all the arguments are present */ + + if (nparams != 13) + status = STATUS_CALLING_ERROR; + + if (status == STATUS_SUCCESS) + + wvals.redfrequency = param[3].data.d_float; + wvals.redangle = param[4].data.d_float; + wvals.greenfrequency = param[5].data.d_float; + wvals.greenangle = param[6].data.d_float; + wvals.bluefrequency = param[7].data.d_float; + wvals.blueangle = param[8].data.d_float; + wvals.colormodel = param[9].data.d_int8; + wvals.redmode = param[10].data.d_int8 ? TRUE : FALSE; + wvals.greenmode = param[11].data.d_int8 ? TRUE : FALSE; + wvals.bluemode = param[12].data.d_int8 ? TRUE : FALSE; + + break; + + case RUN_WITH_LAST_VALS: + /* Possibly retrieve data */ + + gimp_get_data("plug_in_alienmap2", &wvals); + break; + + default: + break; + } /* switch */ + + + if (status == STATUS_SUCCESS) + { + /* Make sure that the drawable is indexed or RGB color */ + if (gimp_drawable_color (drawable->id)) + { + gimp_progress_init ("AlienMap2: Transforming ..."); + + /* Set the tile cache size */ + + gimp_tile_cache_ntiles(2*(drawable->width / gimp_tile_width()+1)); + + /* Run! */ + + +/* gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width()+1));*/ + alienmap2 (drawable); + if (run_mode != RUN_NONINTERACTIVE) + gimp_displays_flush(); + + /* Store data */ + + if (run_mode == RUN_INTERACTIVE) + gimp_set_data("plug_in_alienmap2", &wvals, sizeof(alienmap2_vals_t)); + + } + else + { +/* gimp_message("This filter only applies on RGB-images"); */ + status = STATUS_EXECUTION_ERROR; + } + } + + values[0].data.d_status = status; + + gimp_drawable_detach (drawable); +} + +/*****/ + +static void +alienmap2_get_pixel(int x, int y, guchar *pixel) +{ + static gint row = -1; + static gint col = -1; + + gint newcol, newrow; + gint newcoloff, newrowoff; + guchar *p; + int i; + + if ((x < 0) || (x >= img_width) || (y < 0) || (y >= img_height)) { + pixel[0] = 0; + pixel[1] = 0; + pixel[2] = 0; + pixel[3] = 0; + + return; + } /* if */ + + newcol = x / tile_width; /* The compiler should optimize this */ + newcoloff = x % tile_width; + newrow = y / tile_height; + newrowoff = y % tile_height; + + if ((col != newcol) || (row != newrow) || (the_tile == NULL)) { + + if (the_tile != NULL) + gimp_tile_unref(the_tile, FALSE); + + the_tile = gimp_drawable_get_tile(drawable, FALSE, newrow, newcol); + gimp_tile_ref(the_tile); + col = newcol; + row = newrow; + } /* if */ + p = the_tile->data + the_tile->bpp * (the_tile->ewidth * newrowoff + newcoloff); + for (i = img_bpp; i; i--) + *pixel++ = *p++; + +} /* alienmap2_get_pixel */ + + + +static void +alienmap2_render_row (const guchar *src_row, + guchar *dest_row, + gint row, + gint row_width, + gint bytes) + + + + +{ + gint col, bytenum; + + for (col = 0; col < row_width ; col++) + { + short int v1, v2, v3; + + v1 = (short int)src_row[col*bytes]; + v2 = (short int)src_row[col*bytes +1]; + v3 = (short int)src_row[col*bytes +2]; + + transform(&v1, &v2, &v3); + + dest_row[col*bytes] = (int)v1; + dest_row[col*bytes +1] = (int)v2; + dest_row[col*bytes +2] = (int)v3; + + if (bytes>3) + for (bytenum = 3; bytenumid, &x1, &y1, &x2, &y2); + + /* Get the size of the input image. (This will/must be the same + * as the size of the output image. + */ + width = drawable->width; + height = drawable->height; + bytes = drawable->bpp; + + /* allocate row buffers */ + src_row = (guchar *) malloc ((x2 - x1) * bytes); + dest_row = (guchar *) malloc ((x2 - x1) * bytes); + + + /* initialize the pixel regions */ + gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); + gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE); + + + for (row = y1; row < y2; row++) + + { + gimp_pixel_rgn_get_row (&srcPR, src_row, x1, row, (x2 - x1)); + + alienmap2_render_row (src_row, + dest_row, + row, + (x2 - x1), + bytes); + + /* store the dest */ + gimp_pixel_rgn_set_row (&destPR, dest_row, x1, row, (x2 - x1)); + + if ((row % 10) == 0) + gimp_progress_update ((double) row / (double) (y2 - y1)); + } + + /* update the processed region */ + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->id, TRUE); + gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1)); + + free (src_row); + free (dest_row); +} + +/*****/ + +static void +build_preview_source_image(void) +{ + double left, right, bottom, top; + double px, py; + double dx, dy; + int x, y; + guchar *p; + guchar pixel[4]; + + wint.image = g_malloc(preview_width * preview_height * 3 * sizeof(guchar)); + wint.wimage = g_malloc(preview_width * preview_height * 3 * sizeof(guchar)); + + left = sel_x1; + right = sel_x2 - 1; + bottom = sel_y2 - 1; + top = sel_y1; + + dx = (right - left) / (preview_width - 1); + dy = (bottom - top) / (preview_height - 1); + + py = top; + + p = wint.image; + + for (y = 0; y < preview_height; y++) { + px = left; + for (x = 0; x < preview_width; x++) { + alienmap2_get_pixel((int) px, (int) py, pixel); + + *p++ = pixel[0]; + *p++ = pixel[1]; + *p++ = pixel[2]; + + px += dx; + } /* for */ + + py += dy; + } /* for */ +} /* build_preview_source_image */ + + +static void +set_tooltip (GtkTooltips *tooltips, GtkWidget *widget, const char *desc) +{ + if (desc && desc[0]) + gtk_tooltips_set_tip (tooltips, widget, (char *) desc, NULL); +} + + +/*****/ + +static gint +alienmap2_dialog(void) +{ + GtkWidget *dialog; + GtkWidget *top_table; + GtkWidget *frame; + GtkWidget *toggle; + GtkWidget *toggle_vbox; + GtkWidget *table; + GtkWidget *button; + GSList *mode_group = NULL; + gint argc; + gchar **argv; + guchar *color_cube; + + + use_rgb = (wvals.colormodel == RGB); + use_hsl = (wvals.colormodel == HSL); + + argc = 1; + argv = g_new(gchar *, 1); + argv[0] = g_strdup("alienmap"); + + gtk_init(&argc, &argv); + gtk_rc_parse(gimp_gtkrc()); + + gtk_preview_set_gamma(gimp_gamma()); + gtk_preview_set_install_cmap(gimp_install_cmap()); + color_cube = gimp_color_cube(); + gtk_preview_set_color_cube(color_cube[0], color_cube[1], color_cube[2], color_cube[3]); + + gtk_widget_set_default_visual(gtk_preview_get_visual()); + gtk_widget_set_default_colormap(gtk_preview_get_cmap()); + + build_preview_source_image(); + dialog = maindlg = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(dialog), "AlienMap2"); + gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE); + gtk_container_border_width(GTK_CONTAINER(dialog), 0); + gtk_signal_connect(GTK_OBJECT(dialog), "destroy", + (GtkSignalFunc) dialog_close_callback, + NULL); + + top_table = gtk_table_new(7, 4, FALSE); + gtk_container_border_width(GTK_CONTAINER(top_table), 6); + gtk_table_set_row_spacings(GTK_TABLE(top_table), 4); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), top_table, FALSE, FALSE, 0); + gtk_widget_show(top_table); + + /* use black as foreground: */ + tips = gtk_tooltips_new (); + tips_fg.red = 0; + tips_fg.green = 0; + tips_fg.blue = 0; + /* postit yellow (khaki) as background: */ + gdk_color_alloc (gtk_widget_get_colormap (top_table), &tips_fg); + tips_bg.red = 61669; + tips_bg.green = 59113; + tips_bg.blue = 35979; + gdk_color_alloc (gtk_widget_get_colormap (top_table), &tips_bg); + gtk_tooltips_set_colors (tips,&tips_bg,&tips_fg); + + /* Preview */ + + frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_table_attach(GTK_TABLE(top_table), frame, 0, 1, 0, 1, 0, 0, 0, 0); + gtk_widget_show(frame); + + wint.preview = gtk_preview_new(GTK_PREVIEW_COLOR); + gtk_preview_size(GTK_PREVIEW(wint.preview), preview_width, preview_height); + gtk_container_add(GTK_CONTAINER(frame), wint.preview); + gtk_widget_show(wint.preview); + /* Controls */ + + + table = gtk_table_new(6, 3, FALSE); + gtk_container_border_width(GTK_CONTAINER(table), 0); + gtk_table_attach(GTK_TABLE(top_table), table, 0, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 5, 5); + gtk_widget_show(table); + + dialog_create_value("R/H-Frequency:", GTK_TABLE(table), 1, &wvals.redfrequency,0,5.0000000000000, "Change frequency of the red/hue channel"); +if (wvals.redfrequency!=1.0) exit; + + dialog_create_value("R/H-Phaseshift:", GTK_TABLE(table), 2, &wvals.redangle,0,360.00000000000000, "Change angle of the red/hue channel"); + + dialog_create_value("G/S-Frequency:", GTK_TABLE(table), 3, &wvals.greenfrequency,0,5.00000000000, "Change frequeny of the green/saturation channel"); + + dialog_create_value("G/S-Phaseshift:", GTK_TABLE(table), 4, &wvals.greenangle,0,360.00000000000000, "Change angle of the green/saturation channel"); + dialog_create_value("B/L-Frequency:", GTK_TABLE(table), 5, &wvals.bluefrequency,0,5.00000000000, "Change frequency of the blue/luminance channel"); + + dialog_create_value("B/L-Phaseshift:", GTK_TABLE(table), 6, &wvals.blueangle,0,360.00000000000, "Change angle of the blue/luminance channel"); + + + /* Mode toggle box */ + frame = gtk_frame_new ("Mode:"); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); + gtk_table_attach (GTK_TABLE (top_table), frame, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 5); + toggle_vbox = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (toggle_vbox), 5); + gtk_container_add (GTK_CONTAINER (frame), toggle_vbox); + + toggle = gtk_radio_button_new_with_label (mode_group, "RGB color model"); + mode_group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) alienmap2_toggle_update, + &use_rgb); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_rgb); + gtk_widget_show (toggle); + + set_tooltip(tips,toggle,"Use RGB color model"); + + toggle = gtk_radio_button_new_with_label (mode_group, "HSL color model"); + mode_group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) alienmap2_toggle_update, + &use_hsl); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_hsl); + gtk_widget_show (toggle); + set_tooltip(tips,toggle,"Use HSL color model"); + + toggle = gtk_check_button_new_with_label ("Modify red/hue channel"); + gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) alienmap2_toggle_update, + &wvals.redmode); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), wvals.redmode); + gtk_widget_show (toggle); + + set_tooltip(tips,toggle,"Use function for red/hue component"); + + toggle = gtk_check_button_new_with_label ("Modify green/saturation channel"); + gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) alienmap2_toggle_update, + &wvals.greenmode); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), wvals.greenmode); + gtk_widget_show (toggle); + + set_tooltip(tips,toggle,"Use function for green/saturation component"); + + toggle = gtk_check_button_new_with_label ("Modify blue/luminance channel"); + gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) alienmap2_toggle_update, + &wvals.bluemode); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), wvals.bluemode); + gtk_widget_show (toggle); + + set_tooltip(tips,toggle,"Use function for blue/luminance component"); + + gtk_widget_show (toggle_vbox); + gtk_widget_show (frame); + + + /* Buttons */ + + +gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 6); + + button = gtk_button_new_with_label("OK"); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + (GtkSignalFunc) dialog_ok_callback, + dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0); + gtk_widget_grab_default(button); + gtk_widget_show(button); + set_tooltip(tips,button,"Accept settings and apply filter on image"); + + button = gtk_button_new_with_label("Cancel"); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + (GtkSignalFunc) dialog_cancel_callback, + dialog); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0); + gtk_widget_show(button); + set_tooltip(tips,button,"Reject any changes and close plug-in"); + + button = gtk_button_new_with_label("About..."); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC (alienmap2_logo_dialog), + NULL); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show(button); + set_tooltip(tips,button,"Show information about this plug-in and the author"); + + + + /* Done */ + + gtk_widget_show(dialog); + dialog_update_preview(); + + gtk_main(); + gtk_object_unref (GTK_OBJECT (tips)); + gdk_flush(); + if (the_tile != NULL) { + gimp_tile_unref(the_tile, FALSE); + the_tile = NULL; + } /* if */ + + g_free(wint.image); + g_free(wint.wimage); + + return wint.run; +} /* alienmap2_dialog */ + + +/*****/ + +static void +dialog_update_preview(void) +{ + double left, right, bottom, top; + double dx, dy; + int px, py; + int x, y; + short int r,g,b; + double scale_x, scale_y; + guchar *p_ul, *i, *p; + + left = sel_x1; + right = sel_x2 - 1; + bottom = sel_y2 - 1; + top = sel_y1; + dx = (right - left) / (preview_width - 1); + dy = (bottom - top) / (preview_height - 1); + + scale_x = (double) (preview_width - 1) / (right - left); + scale_y = (double) (preview_height - 1) / (bottom - top); + + py = 0; + + p_ul = wint.wimage; + + for (y = 0; y < preview_height; y++) { + px = 0; + + for (x = 0; x < preview_width; x++) { + i = wint.image + 3 * (preview_width * py + px); + r = *i++; + g = *i++; + b = *i; + transform(&r,&g,&b); + p_ul[0] = r; + p_ul[1] = g; + p_ul[2] = b; + p_ul += 3; + px += 1; /* dx; */ + } /* for */ + py +=1; /* dy; */ + } /* for */ + + p = wint.wimage; + + for (y = 0; y < preview_height; y++) { + gtk_preview_draw_row(GTK_PREVIEW(wint.preview), p, 0, y, preview_width); + p += preview_width * 3; + } /* for */ + gtk_widget_draw(wint.preview, NULL); + gdk_flush(); +} /* dialog_update_preview */ + + +/*****/ + +static void +dialog_create_value(char *title, GtkTable *table, int row, gdouble *value, + int left, int right, const char *desc) +{ + GtkWidget *label; + GtkWidget *scale; + GtkWidget *entry; + GtkObject *scale_data; + char buf[256]; + + label = gtk_label_new(title); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); + gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); + gtk_widget_show(label); + + + scale_data = gtk_adjustment_new(*value, left, right, + (right - left) / 128, + (right - left) / 128, + 0); + + gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed", + (GtkSignalFunc) dialog_scale_update, + value); + + scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data)); + gtk_widget_set_usize(scale, SCALE_WIDTH, 0); + gtk_table_attach(table, scale, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 5, 5); + gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE); + gtk_scale_set_digits(GTK_SCALE(scale), 3); + gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); + gtk_widget_show(scale); + set_tooltip(tips,scale,desc); + + entry = gtk_entry_new(); + gtk_object_set_user_data(GTK_OBJECT(entry), scale_data); + gtk_object_set_user_data(scale_data, entry); + gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); + sprintf(buf, "%0.2f", *value); + gtk_entry_set_text(GTK_ENTRY(entry), buf); + gtk_signal_connect(GTK_OBJECT(entry), "changed", + (GtkSignalFunc) dialog_entry_update, + value); + gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); + gtk_widget_show(entry); + set_tooltip(tips,entry,desc); + +} /* dialog_create_value */ + +/*****/ + +static void +dialog_scale_update(GtkAdjustment *adjustment, gdouble *value) +{ + GtkWidget *entry; + char buf[256]; + + if (*value != adjustment->value) { + *value = adjustment->value; + + entry = gtk_object_get_user_data(GTK_OBJECT(adjustment)); + sprintf(buf, "%0.2f", *value); + + gtk_signal_handler_block_by_data(GTK_OBJECT(entry), value); + gtk_entry_set_text(GTK_ENTRY(entry), buf); + gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), value); + + dialog_update_preview(); + } /* if */ +} /* dialog_scale_update */ +/*****/ + +static void +dialog_entry_update(GtkWidget *widget, gdouble *value) +{ + GtkAdjustment *adjustment; + gdouble new_value; + + new_value = atof(gtk_entry_get_text(GTK_ENTRY(widget))); + + if (*value != new_value) { + adjustment = gtk_object_get_user_data(GTK_OBJECT(widget)); + + if ((new_value >= adjustment->lower) && + (new_value <= adjustment->upper)) { + *value = new_value; + adjustment->value = new_value; + + gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); + + dialog_update_preview(); + } /* if */ + } /* if */ +} /* dialog_entry_update */ + + +static void +dialog_close_callback(GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} /* dialog_close_callback */ + + +/*****/ + +static void +dialog_ok_callback(GtkWidget *widget, gpointer data) +{ + wint.run = TRUE; + gtk_widget_destroy(GTK_WIDGET(data)); +} /* dialog_ok_callback */ + + +/*****/ + +static void +dialog_cancel_callback(GtkWidget *widget, gpointer data) +{ + gtk_widget_destroy(GTK_WIDGET(data)); +} /* dialog_cancel_callback */ + + +static void +alienmap2_toggle_update (GtkWidget *widget, + gpointer data) +{ + int *toggle_val; + + toggle_val = (int *) data; + + if (GTK_TOGGLE_BUTTON (widget)->active) + *toggle_val = TRUE; + else + *toggle_val = FALSE; + + /* determine colormodel */ + if (use_rgb) + wvals.colormodel = RGB; + else if (use_hsl) + wvals.colormodel = HSL; + + dialog_update_preview(); + +} + +void +alienmap2_logo_dialog() +{ + GtkWidget *xlabel; + GtkWidget *xbutton; + GtkWidget *xlogo_box; + GtkWidget *xpreview; + GtkWidget *xframe,*xframe2; + GtkWidget *xvbox; + GtkWidget *xhbox; + char *text; + guchar *temp,*temp2; + guchar *datapointer; + gint y,x; + + if (!logodlg) + { + logodlg = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(logodlg), "About Alien Map 2"); + gtk_window_position(GTK_WINDOW(logodlg), GTK_WIN_POS_MOUSE); + gtk_signal_connect(GTK_OBJECT(logodlg), + "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroyed), + &logodlg); + gtk_quit_add_destroy (1, GTK_OBJECT (logodlg)); + gtk_signal_connect(GTK_OBJECT(logodlg), + "delete_event", + GTK_SIGNAL_FUNC (gtk_widget_hide_on_delete), + &logodlg); + + xbutton = gtk_button_new_with_label("OK"); + GTK_WIDGET_SET_FLAGS(xbutton, GTK_CAN_DEFAULT); + gtk_signal_connect_object (GTK_OBJECT(xbutton), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_hide), + GTK_OBJECT(logodlg)); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(logodlg)->action_area), + xbutton, TRUE, TRUE, 0); + gtk_widget_grab_default(xbutton); + gtk_widget_show(xbutton); + set_tooltip(tips,xbutton,"This closes the information box"); + + xframe = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(xframe), GTK_SHADOW_ETCHED_IN); + gtk_container_border_width(GTK_CONTAINER(xframe), 10); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(logodlg)->vbox), xframe, TRUE, TRUE, 0); + xvbox = gtk_vbox_new(FALSE, 5); + gtk_container_border_width(GTK_CONTAINER(xvbox), 10); + gtk_container_add(GTK_CONTAINER(xframe), xvbox); + + /* The logo frame & drawing area */ + xhbox = gtk_hbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (xvbox), xhbox, FALSE, TRUE, 0); + + xlogo_box = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (xhbox), xlogo_box, FALSE, FALSE, 0); + + xframe2 = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (xframe2), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (xlogo_box), xframe2, FALSE, FALSE, 0); + + xpreview = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_size (GTK_PREVIEW (xpreview), logo_width, logo_height); + temp = g_malloc((logo_width+10)*3); + datapointer=header_data+logo_width*logo_height-1; + for (y = 0; y < logo_height; y++){ + temp2=temp; + for (x = 0; x< logo_width; x++) { + HEADER_PIXEL(datapointer,temp2); temp2+=3;} + gtk_preview_draw_row (GTK_PREVIEW (xpreview), + temp, + 0, y, logo_width); + } + g_free(temp); + gtk_container_add (GTK_CONTAINER (xframe2), xpreview); + gtk_widget_show (xpreview); + gtk_widget_show (xframe2); + gtk_widget_show (xlogo_box); + gtk_widget_show (xhbox); + + xhbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(xvbox), xhbox, TRUE, TRUE, 0); + text = "\nMartin Weber\n" + "martin.weber@usa.net\n" + "http://diverse.freepage.de/martin.weber\n\n" + "AlienMap2 Plug-In for the GIMP\n" + "Version 1.0\n"; + xlabel = gtk_label_new(text); + gtk_box_pack_start(GTK_BOX(xhbox), xlabel, TRUE, FALSE, 0); + gtk_widget_show(xlabel); + + gtk_widget_show(xhbox); + + gtk_widget_show(xvbox); + gtk_widget_show(xframe); + gtk_widget_show(logodlg); + } + else + { + gtk_widget_show (logodlg); + gdk_window_raise (logodlg->window); + } +} + +/* + * RGB-HSL transforms. + * Ken Fishkin, Pixar Inc., January 1989. + */ + +/* + * given r,g,b on [0 ... 1], + * return (h,s,l) on [0 ... 1] + */ + +static void +rgb_to_hsl (gdouble r, + gdouble g, + gdouble b, + gdouble *h, + gdouble *s, + gdouble *l) +{ + gdouble v; + gdouble m; + gdouble vm; + gdouble r2, g2, b2; + + v = MAX(r,g); + v = MAX(v,b); + m = MIN(r,g); + m = MIN(m,b); + + if ((*l = (m + v) / 2.0) <= 0.0) + return; + if ((*s = vm = v - m) > 0.0) + { + *s /= (*l <= 0.5) ? (v + m ) : + (2.0 - v - m) ; + } + else + return; + + r2 = (v - r) / vm; + g2 = (v - g) / vm; + b2 = (v - b) / vm; + + if (r == v) + *h = (g == m ? 5.0 + b2 : 1.0 - g2); + else if (g == v) + *h = (b == m ? 1.0 + r2 : 3.0 - b2); + else + *h = (r == m ? 3.0 + g2 : 5.0 - r2); + + *h /= 6; +} + +/* + * given h,s,l on [0..1], + * return r,g,b on [0..1] + */ + +static void +hsl_to_rgb (gdouble h, + gdouble sl, + gdouble l, + gdouble *r, + gdouble *g, + gdouble *b) +{ + gdouble v; + + v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl); + if (v <= 0) + { + *r = *g = *b = 0.0; + } + else + { + gdouble m; + gdouble sv; + gint sextant; + gdouble fract, vsf, mid1, mid2; + + m = l + l - v; + sv = (v - m ) / v; + h *= 6.0; + sextant = h; + fract = h - sextant; + vsf = v * sv * fract; + mid1 = m + vsf; + mid2 = v - vsf; + switch (sextant) + { + case 0: *r = v; *g = mid1; *b = m; break; + case 1: *r = mid2; *g = v; *b = m; break; + case 2: *r = m; *g = v; *b = mid1; break; + case 3: *r = m; *g = mid2; *b = v; break; + case 4: *r = mid1; *g = m; *b = v; break; + case 5: *r = v; *g = m; *b = mid2; break; + } + } +} + diff --git a/plug-ins/AlienMap2/Makefile.am b/plug-ins/AlienMap2/Makefile.am new file mode 100644 index 0000000000..c1f1de4278 --- /dev/null +++ b/plug-ins/AlienMap2/Makefile.am @@ -0,0 +1,36 @@ +## Process this file with automake to produce Makefile.in + +pluginlibdir = $(gimpplugindir)/plug-ins + +pluginlib_PROGRAMS = AlienMap2 + +AlienMap2_SOURCES = \ + AlienMap2.c \ + logo.h + +INCLUDES = \ + -I$(top_srcdir) \ + $(GTK_CFLAGS) \ + -I$(includedir) + +LDADD = \ + $(top_builddir)/libgimp/libgimp.la \ + $(GTK_LIBS) + +DEPS = \ + $(top_builddir)/libgimp/libgimp.la + +AlienMap2_DEPENDENCIES = $(DEPS) + +.PHONY: files + +files: + @files=`ls $(DISTFILES) 2> /dev/null`; for p in $$files; do \ + echo $$p; \ + done + @for subdir in $(SUBDIRS); do \ + files=`cd $$subdir; $(MAKE) files | grep -v "make\[[1-9]\]"`; \ + for file in $$files; do \ + echo $$subdir/$$file; \ + done; \ + done diff --git a/plug-ins/AlienMap2/logo.h b/plug-ins/AlienMap2/logo.h new file mode 100644 index 0000000000..cb94ec445f --- /dev/null +++ b/plug-ins/AlienMap2/logo.h @@ -0,0 +1,788 @@ +/* GIMP header image file format (Indexed): //logo.h */ + +static unsigned int logo_width = 200; +static unsigned int logo_height = 72; + +/* Call this macro repeatedly. After each use, the pixel data can be extracted */ + +#define HEADER_PIXEL(data,pixel) \ + pixel[0] = palette_data[data[0]*3+2]; \ + pixel[1] = palette_data[data[0]*3+1]; \ + pixel[2] = palette_data[data[0]*3+0]; \ + data--; + +static unsigned char +palette_data[] = { 4,2,2,4,110,178,32,4,122,4,36, +86,15,3,66,4,58,127,36,8,186,4,34,122,17,2, +34,4,19,66,12,4,162,90,2,69,88,2,48,7,20, +2,25,2,103,8,14,48,4,58,186,90,3,154,82,2, +129,55,2,34,17,2,18,17,34,191,94,2,101,57,2, +70,7,32,154,12,22,157,17,3,50,4,88,150,96,3, +186,86,2,138,87,2,86,212,214,210,4,19,98,52,2, +154,15,11,2,4,132,216,7,18,125,12,6,82,37,12, +18,4,88,189,86,14,48,128,2,157,32,4,138,4,60, +155,4,48,126,60,2,218,7,10,52,13,12,66,129,2, +50,56,2,52,52,14,98,4,47,157,6,20,87,48,2, +24,58,2,101,120,2,141,52,5,170,4,113,215,127,2, +73,4,90,210,4,52,112,36,18,194,59,2,85,42,2, +10,107,2,173,95,2,114,31,3,52,4,79,160,84,3, +189,14,10,40,30,2,69,96,2,58,113,2,126,9,37, +231,17,33,170,28,14,2,4,30,146,68,10,37,132,2, +82,23,4,7,4,10,122,4,36,108,32,2,37,7,27, +2,4,98,175,84,10,146,4,101,191,4,14,146,8,29, +86,4,2,170,8,60,230,84,10,162,72,2,39,102,2, +142,4,142,221,4,49,143,68,12,170,4,124,213,15,4, +74,114,2,69,112,2,158,32,3,23,8,50,190,111,2, +104,6,40,154,96,2,210,6,28,104,60,2,138,61,2, +25,68,2,114,58,2,125,39,2,114,73,2,69,16,4, +58,4,88,177,56,14,26,138,2,173,4,68,176,71,2, +55,76,2,210,4,78,130,17,3,42,6,27,69,112,2, +49,12,26,178,47,13,159,18,11,10,13,11,74,141,2, +58,52,18,234,4,82,186,4,126,198,4,103,213,4,62, +206,4,72,226,12,46,210,72,12,222,12,26,146,20,34, +210,4,113,197,4,131,229,4,48,170,4,76,170,7,43, +95,52,30,218,15,11,170,52,14,202,12,14,86,4,40, +174,108,14,202,156,2,186,60,12,130,5,40,129,73,13, +189,12,42,138,44,14,202,4,59,143,4,124,229,4,69, +191,4,69,157,4,60,114,4,43,110,14,14,58,20,26, +157,28,26,210,4,87,162,4,91,202,4,110,226,4,98, +226,4,101,202,17,14,186,28,18,18,60,2,234,28,10, +114,4,30,114,8,10,162,12,54,186,20,26,130,100,10, +170,40,18,154,4,22,114,28,26,234,4,22,58,4,66, +226,4,54,202,12,42,202,4,38,98,4,145,234,4,76, +146,4,94,148,4,138,213,4,94,186,4,54,126,4,54, +154,4,118,211,4,106,178,4,106,188,4,54,142,4,94, +170,4,70,202,4,118,197,4,54,173,4,82,178,72,4, +172,36,10,138,76,14,162,4,98,210,4,118,226,112,2, +114,24,19,8,30,2,85,84,6,226,141,2,73,28,30, +10,28,46,186,112,4,206,36,10,90,36,2,174,108,2, +58,41,3,130,44,10,194,9,33,130,92,2,162,51,2, +42,12,32,162,81,3,146,44,11,26,28,6,146,44,2, +178,30,12,10,60,10,178,64,2,146,28,10,178,92,10, +210,5,41,146,40,2,102,96,2,125,100,2,88,74,2, +157,142,2,159,26,10,55,143,2,50,73,2,102,134,2, +142,73,2,84,127,2,126,142,2,82,156,2,178,28,10, +158,28,26,114,84,14,202,12,4,10,5,20,74,17,2, +26,92,2,194,7,19,106}; + +static unsigned char header_data[] = { 71,99,218,218,99,11,71,218,71,71, +218,99,99,99,71,99,218,99,99,99,99,218,71,218,99,218,218,99,99,218, +218,99,99,218,99,218,99,58,218,99,99,99,58,218,99,99,99,58,99,58, +99,58,11,58,99,58,58,11,99,58,99,58,99,99,99,218,99,218,99,58, +99,71,99,218,71,12,12,12,12,12,12,12,12,12,92,19,19,19,92,92, +92,92,19,108,19,19,19,19,19,19,53,53,53,53,101,19,19,53,53,19, +19,19,12,92,92,12,12,12,71,71,218,99,218,218,71,71,12,12,218,99, +58,58,58,99,99,99,58,99,99,99,11,58,11,58,58,99,58,99,99,99, +58,99,99,99,99,58,99,99,99,99,99,218,99,99,11,99,99,99,11,99, +99,218,218,218,99,218,99,99,218,218,99,99,218,99,218,218,99,99,218,11, +218,71,99,218,99,218,218,99,71,8,218,99,218,218,99,99,99,99,99,99, +218,218,99,99,218,99,218,99,218,71,99,99,99,218,99,99,218,99,99,99, +218,218,99,99,99,99,58,99,58,30,99,99,99,99,99,99,58,99,99,58, +99,58,99,58,99,99,58,58,58,99,58,58,99,218,218,71,99,99,71,71, +71,123,12,118,71,71,12,71,123,12,12,19,19,19,53,19,19,53,53,19, +19,53,101,63,20,63,20,63,53,53,53,101,53,53,53,19,53,53,53,19, +92,12,12,12,71,12,12,12,12,12,92,71,218,218,71,218,71,71,71,71, +99,218,58,58,58,99,99,99,99,58,58,58,99,58,99,58,58,99,58,58, +99,99,58,99,99,99,99,58,99,58,30,99,99,99,218,99,58,99,99,58, +11,99,99,218,99,218,218,99,99,218,71,99,218,99,99,218,99,99,218,99, +11,218,99,218,99,11,218,99,99,8,71,71,71,99,218,71,218,99,71,218, +11,99,218,218,99,218,99,218,99,99,99,99,218,99,99,99,99,99,218,99, +99,99,99,99,99,11,99,99,99,99,99,99,58,99,58,99,58,99,58,58, +99,11,58,58,99,58,99,99,58,58,218,99,123,71,71,71,123,71,71,218, +99,99,218,71,12,12,12,12,92,19,19,53,19,53,53,53,53,19,53,53, +53,53,19,53,19,53,53,53,53,53,63,63,101,63,63,20,53,19,53,53, +53,19,92,92,12,12,12,71,71,71,71,12,12,71,71,12,12,12,12,12, +12,218,218,99,58,58,99,58,99,58,99,58,99,99,58,218,58,99,58,99, +99,99,99,11,58,99,99,58,99,99,58,58,99,99,99,99,99,99,99,99, +99,58,218,99,218,99,99,99,218,99,99,218,99,11,218,99,218,218,99,99, +218,99,218,11,99,71,99,218,71,8,99,99,218,99,99,99,218,99,99,218, +218,99,11,99,99,218,99,218,99,218,218,99,58,99,99,99,58,11,99,99, +58,99,99,58,58,58,58,99,99,99,99,218,58,99,99,99,58,58,99,99, +58,58,99,58,99,58,99,99,58,58,99,218,71,71,218,218,218,58,58,58, +218,99,71,123,12,12,12,19,19,108,108,108,92,92,92,12,71,12,12,92, +19,53,53,53,101,53,53,19,53,101,53,20,53,79,79,0,34,79,20,63, +53,53,53,19,19,19,12,12,12,71,71,71,71,71,71,123,71,12,12,12, +12,12,71,71,218,58,99,58,218,58,218,99,58,99,58,99,99,218,58,58, +58,99,58,58,99,99,58,99,58,99,99,218,58,58,99,99,99,99,99,99, +58,11,99,99,218,218,218,99,218,99,99,218,218,99,218,99,99,218,218,99, +218,99,71,218,99,218,99,99,99,8,218,218,99,218,99,218,99,218,218,99, +11,218,218,218,218,99,71,99,218,99,99,99,218,58,99,99,99,99,218,30, +58,99,58,99,58,11,58,99,58,99,58,58,58,99,58,58,99,99,58,58, +58,99,58,99,58,58,99,58,218,99,99,218,58,99,58,58,58,58,58,218, +71,12,12,71,71,12,12,12,12,71,71,118,71,71,118,71,71,12,223,19, +19,53,53,53,53,63,229,20,79,20,34,0,20,101,101,63,20,101,101,53, +108,53,53,53,53,53,101,19,92,12,12,12,12,71,71,218,218,218,71,71, +118,12,71,71,218,218,58,58,58,58,58,58,218,58,58,58,99,99,218,99, +58,58,99,99,58,99,58,99,58,58,58,99,99,99,58,99,99,99,58,58, +99,58,58,99,99,99,99,99,99,99,218,99,99,218,99,218,218,99,99,218, +99,58,99,99,218,99,218,218,218,8,99,218,99,218,99,218,11,99,218,99, +99,99,99,99,218,99,58,99,99,99,58,99,218,99,99,99,99,99,58,99, +58,218,99,99,99,58,218,58,58,58,99,99,58,99,218,58,99,99,58,218, +58,99,58,99,99,99,58,99,58,58,58,58,99,58,58,58,58,218,218,12, +71,71,71,12,12,71,71,12,71,12,71,71,71,71,12,92,19,53,53,53, +101,63,79,34,251,0,0,63,20,53,19,53,53,53,53,19,19,53,19,19, +19,108,19,19,19,19,19,19,53,53,108,12,12,12,71,71,218,58,58,58, +99,218,71,71,71,12,218,99,99,58,58,58,58,218,58,58,58,58,58,99, +99,58,58,99,58,218,58,99,99,99,99,58,99,128,99,58,99,99,11,99, +99,58,11,58,99,99,99,218,58,11,99,58,99,218,99,99,218,99,99,99, +218,71,99,99,218,99,11,99,218,8,218,99,218,99,218,99,99,218,99,218, +58,218,58,218,99,99,218,99,58,99,99,99,99,78,11,58,99,58,99,99, +99,58,58,99,58,11,58,58,218,99,99,58,58,58,99,58,58,58,99,99, +58,58,58,58,58,58,99,58,99,99,99,58,58,58,58,58,218,71,118,12, +71,71,71,71,71,12,71,71,71,71,71,12,92,19,19,53,53,63,20,251, +0,79,79,0,79,34,34,79,0,63,229,20,63,101,53,101,19,53,19,92, +12,71,12,92,12,12,12,12,12,92,19,92,92,71,12,118,71,218,99,58, +58,58,58,58,218,123,71,218,58,58,58,99,58,58,58,218,58,218,58,58, +218,58,99,58,58,58,99,99,58,99,58,99,218,99,99,99,58,58,58,11, +58,58,99,58,99,99,30,99,99,99,58,218,218,30,99,218,99,99,99,218, +99,99,218,218,99,99,218,71,99,8,99,99,71,99,218,218,99,218,99,218, +99,218,99,58,11,58,99,99,11,58,99,58,99,99,99,99,58,58,99,99, +58,99,99,99,99,58,99,78,58,58,99,99,218,78,58,218,58,99,212,58, +99,58,58,58,218,58,58,58,58,58,58,58,58,58,218,71,12,12,71,71, +123,218,218,58,99,71,123,71,71,12,19,19,19,53,53,19,19,53,63,53, +101,101,101,63,101,101,20,20,79,0,0,79,79,34,251,79,79,251,101,53, +19,92,12,71,71,71,218,12,218,12,71,71,71,71,71,12,71,71,123,71, +58,58,58,58,58,58,58,99,99,58,58,58,99,58,58,58,99,58,99,58, +99,58,58,99,58,58,58,58,99,58,99,58,99,58,99,58,99,99,58,58, +99,99,99,58,99,58,58,58,99,99,99,30,128,58,99,99,99,99,99,58, +218,99,99,218,218,99,99,218,71,8,71,218,99,99,99,99,218,99,99,99, +99,30,58,11,58,58,99,58,58,58,58,30,58,58,99,99,99,58,99,58, +99,58,99,58,58,58,218,99,58,99,58,58,58,218,99,58,58,58,58,58, +58,99,99,99,58,99,99,58,58,212,99,58,58,218,71,71,218,218,99,58, +58,58,58,218,123,71,71,12,108,19,19,108,19,19,223,92,19,92,12,12, +19,19,19,19,53,53,63,63,229,0,34,34,79,0,79,0,75,34,0,34, +79,20,53,19,92,12,71,71,71,218,71,123,71,123,71,71,71,71,71,71, +71,218,58,58,58,58,58,58,58,99,58,58,58,58,58,58,58,58,99,58, +58,99,99,58,99,58,58,58,58,58,58,99,58,99,58,99,58,58,99,99, +58,58,99,99,58,58,218,58,58,99,58,99,11,58,58,99,58,218,99,99, +99,99,218,99,99,218,99,99,99,8,99,218,99,218,99,99,99,99,58,58, +11,58,99,58,58,30,58,11,58,11,58,99,99,58,99,58,58,58,99,58, +58,99,58,99,99,58,58,99,58,99,58,99,58,99,212,58,58,58,58,58, +58,58,58,58,58,58,58,58,58,58,212,58,218,218,218,99,58,58,58,58, +58,99,71,71,71,12,71,71,12,12,12,71,71,123,71,218,71,71,71,92, +19,108,63,79,229,126,0,79,0,0,34,34,34,126,34,251,79,0,126,34, +79,0,79,20,63,19,19,12,71,71,71,218,71,99,71,71,71,71,71,71, +71,71,218,58,58,58,212,58,58,58,58,58,58,58,58,58,58,58,58,58, +58,58,99,58,58,99,58,58,99,99,128,218,58,58,99,58,99,58,58,99, +218,58,58,218,99,99,99,99,99,99,58,99,99,58,30,218,99,99,99,99, +99,99,218,99,99,99,218,218,99,8,218,99,99,99,58,99,99,99,99,99, +58,58,218,99,99,99,58,99,58,58,58,99,58,99,58,99,99,99,58,58, +99,99,58,58,58,58,58,58,99,99,58,99,99,58,58,58,58,99,58,58, +99,58,99,58,78,212,99,212,99,58,58,99,58,58,78,78,246,99,212,58, +99,71,123,71,71,71,71,71,218,218,71,123,218,218,218,118,12,19,63,63, +0,0,0,34,34,0,34,79,79,79,0,34,79,79,20,101,53,101,53,19, +53,53,101,101,53,53,19,19,19,92,218,218,218,218,218,212,78,58,218,218, +71,71,71,11,58,246,58,78,246,58,58,58,99,99,58,58,99,58,212,58, +99,58,99,58,58,99,58,58,58,58,58,212,218,58,58,99,58,58,99,58, +99,99,99,58,58,99,99,99,58,99,58,58,99,99,99,58,58,99,99,99, +99,99,99,11,58,99,99,99,218,8,99,99,218,99,99,218,99,218,58,58, +11,78,58,99,58,99,58,99,58,11,58,99,58,99,58,58,58,99,99,58, +99,99,99,58,58,58,58,58,58,58,58,58,58,58,58,212,99,58,212,99, +58,58,78,58,78,58,58,58,58,58,58,58,58,58,246,58,246,58,58,71, +218,71,71,71,218,71,71,71,71,218,218,71,71,92,92,53,63,126,79,0, +0,79,0,79,34,79,0,126,79,79,79,79,79,229,229,101,53,108,92,71, +71,71,71,71,71,12,12,19,108,19,92,71,71,71,71,218,212,246,78,58, +58,218,218,71,71,58,58,212,212,78,212,78,78,58,58,58,58,58,99,58, +78,58,58,99,58,58,58,58,58,58,58,58,99,58,99,58,58,212,99,58, +58,99,58,99,58,99,99,58,58,99,99,58,58,58,58,11,78,99,99,99, +99,58,99,58,71,99,99,99,99,8,99,99,99,218,99,58,99,30,58,11, +58,11,58,58,99,58,58,99,58,99,58,99,99,58,99,58,99,58,58,99, +58,58,58,58,58,78,58,99,58,99,58,58,58,58,99,58,212,99,58,58, +58,78,78,78,58,58,58,58,58,212,58,78,58,78,78,78,58,99,218,218, +71,218,218,71,58,99,58,99,71,71,71,12,19,20,79,251,0,251,79,251, +79,63,126,79,79,79,79,229,79,79,79,126,126,79,79,63,20,53,53,92, +12,12,218,71,71,218,218,218,71,218,71,71,71,218,71,218,218,58,246,246, +78,212,78,58,218,218,58,58,58,246,78,212,78,212,58,58,58,58,58,212, +78,78,78,58,58,99,58,58,58,58,58,58,58,58,58,218,99,99,58,99, +58,58,218,99,58,58,99,58,99,99,58,99,99,99,58,99,99,58,58,58, +218,99,11,58,99,99,99,218,99,8,99,30,218,58,11,99,99,58,99,58, +99,58,58,99,218,99,218,58,99,99,58,58,58,58,99,58,99,99,58,99, +58,58,58,78,78,58,58,58,58,58,99,246,78,78,58,58,58,58,58,78, +78,212,78,246,246,58,58,58,212,58,212,246,78,246,58,212,218,218,218,218, +218,58,246,58,246,58,218,218,123,12,19,19,53,53,101,53,63,101,63,63, +63,63,63,63,63,101,63,53,63,53,53,53,53,108,19,19,19,19,108,19, +92,92,12,12,71,71,218,99,99,218,218,218,218,218,71,71,71,218,218,246, +78,78,246,78,78,78,58,58,58,78,78,78,78,246,58,58,58,58,58,78, +212,78,78,58,58,58,58,99,58,58,58,58,58,58,99,58,58,58,58,58, +58,99,58,58,99,58,58,58,58,58,58,99,58,58,58,58,58,99,99,99, +58,99,58,99,99,58,99,99,99,8,99,99,30,58,58,58,58,58,58,99, +58,11,99,58,99,58,58,58,58,58,58,99,58,58,58,58,58,58,99,58, +99,58,78,58,58,58,99,58,58,78,246,78,58,78,58,58,58,58,78,212, +246,78,246,78,78,99,212,246,78,246,58,246,246,78,246,218,218,218,58,58, +246,78,78,246,58,218,218,71,12,12,108,92,108,19,108,53,63,63,63,53, +53,53,19,223,92,92,49,118,118,118,118,118,118,118,71,118,118,12,12,12, +92,71,71,123,218,99,11,58,58,58,58,78,58,99,99,123,71,218,218,218, +246,246,78,212,78,212,78,246,78,78,58,78,246,78,246,78,58,58,58,58, +99,78,246,78,246,99,58,58,58,58,58,78,78,78,78,99,58,99,58,99, +78,58,58,99,58,218,218,58,58,99,58,58,58,218,99,58,58,58,58,11, +58,99,99,99,58,99,99,218,58,8,99,99,58,99,58,11,58,11,58,58, +99,58,99,58,99,58,99,58,58,218,58,58,58,99,58,99,58,58,58,99, +78,58,58,58,99,58,58,78,78,58,246,78,246,99,58,58,58,212,78,78, +246,58,246,58,78,78,78,58,246,78,78,58,246,58,58,58,212,58,246,78, +212,246,58,58,71,71,71,71,12,92,92,92,108,53,53,53,19,19,223,223, +49,223,92,49,49,223,92,49,118,118,118,71,118,112,118,11,11,112,71,112, +71,71,11,11,11,99,99,58,58,78,78,78,246,78,246,58,99,71,218,71, +218,78,78,246,78,246,58,246,78,246,212,58,246,58,246,78,212,78,246,58, +58,58,78,246,246,78,78,99,58,58,58,212,78,58,78,58,58,58,58,58, +78,58,78,99,58,58,99,58,58,58,58,99,58,58,99,218,58,99,58,58, +58,58,99,58,99,99,58,99,99,8,99,99,58,58,58,99,58,99,99,58, +99,58,58,58,58,58,58,218,99,58,99,58,58,58,58,58,99,58,58,78, +58,78,78,78,78,58,78,58,78,78,78,212,78,58,78,58,78,212,78,246, +78,246,78,78,212,246,246,78,246,212,246,246,78,246,58,246,78,246,58,246, +246,58,99,218,218,218,71,12,92,19,19,19,19,19,223,223,49,223,49,118, +49,112,30,30,237,103,208,208,245,208,245,208,245,245,245,103,208,103,22,237, +30,30,11,11,11,11,71,71,11,99,58,78,78,246,58,246,246,246,58,99, +99,218,212,78,246,78,246,78,246,58,78,58,246,78,58,246,78,212,78,246, +58,212,58,78,78,212,78,78,58,58,99,78,78,78,78,78,58,58,99,58, +58,78,78,78,58,58,99,58,99,58,58,99,58,218,58,58,99,58,58,218, +99,58,99,99,58,99,30,99,99,8,58,99,58,99,58,58,58,99,58,99, +58,218,218,58,99,58,99,58,58,58,78,99,78,58,99,58,58,78,58,78, +78,58,78,78,58,78,78,246,246,212,78,78,78,58,78,246,78,246,58,246, +212,78,58,78,78,58,246,78,78,78,58,246,78,246,78,58,246,78,78,78, +58,218,99,11,71,12,92,92,92,223,223,223,223,223,49,118,112,22,237,208, +72,245,55,243,245,72,72,72,65,208,236,208,208,245,72,55,243,55,55,243, +245,245,245,103,237,237,30,11,11,112,71,11,99,58,78,246,246,246,246,78, +58,218,58,58,246,78,212,78,246,78,246,78,212,78,78,212,78,246,78,78, +58,78,78,78,78,78,246,246,246,58,58,78,58,246,78,212,78,78,99,58, +58,78,58,58,58,58,58,99,58,58,58,58,78,58,58,99,99,58,58,58, +99,218,58,99,99,99,58,99,58,8,99,99,99,58,11,58,58,58,99,58, +58,58,58,58,58,58,58,99,99,78,78,58,58,78,58,58,99,78,78,78, +78,78,78,78,78,78,212,246,246,246,246,78,78,246,246,58,246,78,246,78, +78,78,212,246,246,246,78,78,212,246,246,246,58,246,246,78,246,246,78,58, +218,99,71,12,12,92,92,82,223,49,223,118,112,22,208,72,72,208,65,22, +22,112,11,112,112,112,112,112,118,118,118,112,112,112,30,244,244,30,237,65, +236,72,55,55,243,243,208,208,237,237,11,71,11,11,71,11,99,58,246,246, +246,78,78,246,58,246,78,246,58,246,58,246,58,246,246,78,78,78,212,78, +212,246,212,78,246,246,58,78,78,246,99,246,246,58,246,58,78,78,78,58, +78,78,78,78,78,78,58,58,58,99,58,58,78,99,58,58,58,218,99,99, +58,58,99,58,99,58,58,99,99,8,58,58,99,58,99,218,99,58,99,99, +99,58,99,58,99,58,58,58,58,78,58,58,58,58,58,58,58,78,212,78, +78,58,246,78,58,246,246,246,246,246,246,246,78,58,246,78,246,58,246,58, +246,78,78,78,58,246,212,78,78,78,58,246,78,212,246,58,78,212,58,99, +218,71,12,92,19,223,49,49,118,62,30,22,208,208,103,30,244,112,244,118, +112,23,49,49,49,49,49,49,49,49,82,82,223,82,49,118,23,118,118,112, +11,30,237,22,65,245,55,243,245,245,103,237,237,11,71,11,71,71,218,58, +246,246,78,246,78,212,78,246,246,78,246,246,78,78,212,78,212,78,246,78, +78,58,246,78,58,246,78,212,78,246,78,78,78,78,78,212,246,246,246,78, +58,78,78,78,58,78,78,58,58,58,58,58,99,58,58,58,58,58,99,58, +58,58,58,58,58,99,99,58,58,8,99,99,58,58,58,99,99,99,99,58, +58,99,78,58,78,99,58,58,99,78,78,78,58,78,58,58,78,246,78,212, +78,78,58,78,246,246,246,246,246,246,58,78,78,246,58,246,78,246,78,246, +78,212,78,212,212,246,78,78,246,246,78,212,58,99,212,246,246,58,99,218, +118,12,92,223,223,49,49,11,237,208,208,103,244,23,118,112,118,112,49,49, +19,82,82,82,223,49,66,49,49,82,223,223,101,19,223,82,223,82,223,82, +82,49,23,112,11,244,30,65,72,55,55,245,208,22,237,112,11,118,71,218, +218,58,58,78,246,78,212,78,78,212,99,78,212,246,78,246,78,246,78,212, +246,246,78,246,246,78,246,78,246,58,246,78,58,78,246,246,246,246,212,246, +78,78,78,78,78,58,78,78,99,58,78,78,78,99,58,58,99,58,99,99, +58,99,99,99,99,58,99,58,99,8,99,99,99,58,58,99,58,58,99,58, +58,58,78,78,58,58,58,58,58,58,78,78,78,78,78,58,246,246,246,246, +246,78,78,212,246,246,246,246,246,246,78,212,78,246,78,212,78,246,58,246, +78,246,78,58,58,212,246,58,78,246,246,58,58,58,58,246,58,218,71,12, +223,223,49,49,49,30,65,72,72,30,112,118,118,112,118,49,223,223,223,49, +244,244,244,244,23,23,23,23,70,66,49,70,49,70,70,118,23,23,23,23, +49,223,19,82,223,223,23,11,244,237,208,72,55,55,208,103,30,11,11,49, +71,71,99,58,246,78,246,246,58,246,58,58,246,212,78,246,58,246,78,58, +58,212,78,78,212,78,212,78,78,78,212,78,78,78,246,212,246,246,246,212, +246,58,78,78,78,78,58,78,78,99,58,58,78,58,58,58,99,58,58,58, +58,58,58,58,99,58,99,58,99,8,99,58,58,218,58,58,58,99,58,58, +58,99,58,58,99,58,78,78,78,78,78,78,78,58,246,246,246,212,246,246, +212,246,78,246,246,246,246,246,212,246,246,78,246,58,212,246,78,78,78,246, +58,246,212,99,58,246,78,246,246,58,58,58,58,78,246,58,99,118,12,92, +223,223,223,11,22,72,208,244,49,112,112,118,49,82,223,49,244,244,242,62, +23,62,23,23,244,244,244,244,244,244,62,30,244,244,244,244,23,112,210,23, +62,244,244,23,223,82,53,82,49,112,30,30,65,72,55,245,208,237,30,112, +71,49,118,71,99,78,78,78,246,246,58,99,58,246,212,78,246,58,246,212, +99,58,212,246,78,246,78,246,212,246,78,246,246,212,246,246,246,212,246,246, +246,246,78,78,246,246,78,78,78,78,58,58,78,58,58,58,58,58,99,99, +99,78,99,58,99,99,58,99,58,8,58,99,58,99,99,58,58,99,58,58, +58,58,58,58,78,58,78,78,58,78,58,246,78,78,78,212,246,246,212,246, +246,246,246,246,246,246,246,246,246,246,246,58,246,58,99,212,246,212,78,78, +78,99,58,58,78,246,58,78,246,58,58,58,58,212,58,218,71,12,49,49, +49,112,22,72,65,112,49,112,112,112,223,19,118,62,244,62,62,23,23,244, +244,244,244,112,23,49,49,223,19,223,82,223,223,49,223,23,118,112,244,30, +62,62,62,62,23,62,23,223,82,8,82,71,30,244,22,72,55,245,103,237, +11,71,12,12,71,99,78,78,78,58,212,58,58,58,58,212,78,58,246,78, +58,58,58,212,78,246,58,78,78,212,212,246,246,246,212,246,246,246,246,246, +246,246,58,78,78,58,246,212,78,78,58,78,58,78,78,78,58,78,58,58, +218,58,58,99,58,99,99,99,58,8,218,99,58,58,58,99,58,58,99,78, +78,58,99,58,58,78,58,78,246,78,78,58,78,212,246,246,246,246,246,246, +246,246,246,212,246,212,246,246,246,212,78,246,58,58,58,246,78,78,212,246, +58,58,58,58,212,78,246,212,58,58,58,58,58,58,71,12,49,223,223,49, +30,208,72,30,49,49,112,49,223,223,23,22,244,62,23,23,62,22,112,118, +49,49,223,118,23,244,30,242,22,242,242,62,242,244,244,112,23,49,49,223, +23,112,30,244,62,112,210,23,23,49,82,8,223,244,237,30,208,55,243,245, +22,30,71,118,12,71,99,78,78,246,212,58,58,58,58,246,246,246,78,246, +58,58,58,78,212,78,246,246,246,58,58,212,246,246,246,246,246,246,246,246, +246,78,246,58,246,246,246,78,212,78,78,78,58,78,58,78,58,58,99,58, +58,58,99,58,58,58,58,58,58,8,58,99,58,58,58,58,99,58,78,78, +58,58,78,58,58,78,78,58,78,78,78,78,78,246,212,246,246,246,246,246, +246,246,246,246,246,246,212,246,246,246,78,58,58,58,58,246,78,78,246,99, +212,58,212,58,212,78,78,58,58,218,58,212,58,99,71,49,223,49,49,30, +55,72,112,49,244,11,49,82,112,242,242,62,23,62,244,112,118,223,82,118, +30,236,29,225,231,33,248,42,42,42,219,2,42,219,110,107,231,29,65,244, +112,223,223,49,112,30,30,23,23,23,23,49,82,101,49,30,30,242,72,243, +208,103,30,71,118,12,71,99,78,78,78,58,58,58,58,58,78,58,246,78, +58,58,99,58,246,58,246,58,246,58,99,58,212,246,246,212,246,246,246,246, +246,246,246,246,212,246,246,246,246,78,58,78,78,78,78,78,58,78,78,78, +58,78,99,99,99,58,58,99,99,8,99,58,99,99,58,58,58,58,78,78, +78,78,58,58,58,78,78,78,78,78,246,246,58,246,246,246,246,246,246,246, +246,246,212,246,99,58,246,246,246,246,212,58,58,58,99,212,78,212,212,58, +78,58,58,58,246,246,78,58,71,218,58,58,11,71,118,223,49,23,103,243, +22,49,118,30,118,82,49,30,242,62,70,62,244,118,223,82,112,65,93,205, +217,42,80,147,98,4,26,8,8,8,8,121,8,8,26,4,98,210,111,219, +29,29,65,112,223,82,23,30,244,62,62,62,62,49,82,82,112,30,30,65, +243,245,103,30,71,118,12,71,218,212,246,58,58,212,212,58,58,246,212,78, +58,58,212,58,58,246,78,246,58,58,58,58,246,212,246,246,246,246,246,246, +246,212,246,246,246,246,212,246,246,212,78,246,212,78,58,78,78,78,58,78, +78,78,58,58,58,58,99,58,58,8,58,58,58,58,58,58,58,58,237,78, +58,78,78,58,78,78,212,78,246,78,78,246,246,246,246,246,246,246,246,246, +246,246,246,58,58,58,246,246,246,246,58,58,99,58,58,246,246,78,99,78, +246,78,58,58,58,58,58,218,12,99,58,99,71,92,49,223,118,22,41,65, +223,23,30,118,19,23,22,242,23,23,30,112,223,19,112,29,222,232,87,80, +98,26,121,8,20,253,20,20,20,20,101,20,20,20,253,253,20,8,121,26, +4,14,2,231,29,30,49,82,112,30,244,62,23,210,118,82,101,223,30,244, +65,55,243,103,237,71,118,71,71,99,58,58,58,58,218,58,58,58,246,212, +58,58,212,78,99,58,246,246,78,58,58,58,58,246,246,246,246,246,246,246, +246,246,246,212,246,246,246,246,246,246,246,78,78,78,78,78,58,78,58,78, +78,58,58,58,78,99,58,58,99,8,99,58,58,99,99,58,58,58,58,237, +78,78,58,78,78,246,78,246,78,246,78,246,246,246,246,246,246,246,246,246, +246,246,58,58,58,58,246,246,246,58,99,78,246,212,99,246,212,58,78,246, +58,246,58,58,58,212,218,12,118,58,58,71,12,49,19,49,237,41,65,49, +118,112,223,82,244,236,62,66,62,30,82,8,112,93,68,6,137,88,162,253, +253,20,253,19,223,23,244,244,54,242,54,242,244,62,112,49,223,20,20,20, +20,253,26,98,14,33,29,244,82,101,112,22,62,62,62,23,49,53,82,30, +112,22,243,243,208,11,71,118,12,218,99,58,58,58,12,71,58,58,58,58, +99,58,58,246,246,58,58,246,246,58,58,58,99,58,246,246,246,246,78,58, +246,212,246,246,246,246,246,212,246,246,78,78,78,78,58,78,78,78,78,58, +78,58,78,237,78,58,99,99,78,8,58,99,58,58,78,78,78,78,78,78, +58,78,78,58,78,246,78,212,246,246,246,246,246,246,246,246,246,103,246,246, +246,246,58,58,58,99,212,246,246,58,212,78,246,58,58,58,58,58,212,78, +78,78,58,58,58,58,123,49,218,99,11,118,223,223,82,237,41,208,23,118, +237,223,82,244,18,210,23,23,112,19,223,103,64,6,148,147,26,253,20,8, +66,23,54,111,219,219,137,24,76,24,163,25,137,42,204,42,151,109,244,223, +20,20,20,20,8,4,111,231,236,23,82,12,237,62,62,23,62,223,253,223, +237,244,22,41,245,103,11,112,118,71,218,58,58,99,92,92,128,58,58,58, +58,58,58,212,78,58,58,212,58,58,58,78,78,58,212,246,246,246,58,58, +212,246,212,246,246,246,246,246,246,212,246,78,246,246,78,78,78,78,78,58, +78,58,58,78,99,58,58,58,99,8,99,58,58,58,58,78,78,58,78,78, +78,78,78,78,78,58,246,246,246,246,246,246,246,246,103,246,246,246,246,246, +246,78,58,58,58,58,58,212,58,58,78,212,78,78,99,58,58,212,78,246, +212,212,58,58,58,218,92,12,218,99,71,12,223,82,118,243,55,23,223,30, +223,19,244,93,54,49,23,112,82,82,245,153,138,234,162,8,253,101,49,30, +111,125,24,201,142,16,159,142,43,95,197,156,193,193,51,141,224,25,248,231, +65,118,20,20,20,20,121,210,231,55,244,82,49,30,244,62,62,244,223,20, +118,237,112,208,243,245,237,71,118,49,71,58,58,218,92,92,12,58,58,99, +58,58,212,78,212,212,58,58,58,58,58,212,78,58,58,246,246,246,99,58, +99,246,246,246,246,246,246,246,246,246,212,246,58,78,78,78,78,78,58,78, +78,58,78,78,58,78,58,99,58,8,99,99,58,58,58,78,78,58,78,58, +78,78,78,246,78,78,78,246,246,246,246,246,246,246,246,103,246,246,246,246, +246,58,58,58,58,58,58,58,58,58,78,78,246,78,58,58,58,212,78,58, +58,78,58,58,58,12,92,12,99,218,118,19,82,223,22,116,237,49,112,112, +101,112,93,109,70,112,118,82,223,55,136,185,44,26,253,253,82,62,107,163, +117,16,114,159,161,106,98,46,26,26,26,26,26,4,32,81,44,142,43,234, +10,56,236,23,20,20,20,8,4,219,225,237,19,82,11,244,62,54,62,223, +20,112,30,244,72,239,103,237,71,12,12,71,58,71,92,92,12,128,58,58, +58,58,246,78,246,58,58,58,99,58,58,246,78,78,58,246,246,58,58,58, +58,212,246,212,246,246,246,246,246,246,78,78,246,58,246,58,78,246,78,58, +78,58,78,78,58,58,58,58,58,8,58,58,58,58,78,237,58,78,78,78, +78,78,78,58,246,246,212,246,246,246,246,246,246,246,246,246,246,246,246,246, +78,58,58,58,58,58,99,58,58,246,246,246,58,246,58,58,58,78,246,218, +11,58,58,58,58,12,92,71,218,11,49,223,101,23,239,93,23,118,244,223, +223,65,29,70,70,112,82,82,72,233,135,152,121,253,20,49,242,179,176,39, +198,156,32,47,26,26,69,113,26,47,9,47,162,113,26,121,113,252,152,159, +43,234,217,238,30,253,20,251,8,4,107,17,30,82,223,22,62,62,54,244, +82,19,237,112,244,41,245,30,112,71,92,71,99,71,12,92,92,71,78,58, +58,246,246,58,78,212,58,58,58,58,58,78,246,58,99,58,212,58,58,58, +58,78,246,246,246,246,246,246,246,246,246,246,78,78,78,78,246,58,78,78, +58,58,58,99,58,99,58,58,58,8,58,99,99,58,58,78,78,58,78,58, +78,58,78,78,78,78,78,246,246,246,246,246,246,246,246,246,78,246,246,246, +58,58,78,58,78,58,58,99,58,78,58,246,246,58,58,58,212,58,58,12, +71,58,58,58,99,92,92,71,218,71,223,8,19,22,150,30,49,11,23,101, +30,93,54,49,112,49,20,30,254,181,95,26,253,253,49,65,163,166,206,202, +52,26,8,121,4,161,43,114,139,131,57,200,195,188,192,88,26,26,121,98, +197,67,234,145,230,22,82,20,20,8,98,107,100,112,253,112,103,244,54,62, +49,20,49,237,118,208,243,103,11,11,12,92,92,92,92,12,49,12,58,58, +78,58,246,78,246,78,212,99,58,58,78,246,58,78,58,58,58,99,58,58, +58,99,246,246,246,246,246,246,246,246,246,246,246,78,246,78,246,78,58,78, +78,58,78,78,78,58,58,99,58,8,99,58,58,58,99,78,58,78,78,78, +78,78,78,78,78,246,246,246,246,246,246,246,246,246,246,246,58,212,58,246, +99,212,58,99,78,99,58,58,78,246,58,58,58,78,78,58,78,78,99,71, +12,71,58,58,12,12,12,71,11,12,223,101,49,243,100,118,223,112,82,19, +93,225,113,23,244,101,223,41,129,199,52,253,20,223,242,124,39,57,117,122, +121,121,47,44,195,35,94,196,165,189,189,189,27,84,200,139,67,186,26,121, +240,106,159,234,175,68,242,20,20,20,8,210,238,93,223,19,237,244,23,54, +62,19,101,244,112,30,243,208,237,11,12,92,49,223,12,12,92,12,58,78, +246,78,58,246,78,212,78,78,58,58,212,58,58,58,78,99,58,58,99,58, +58,58,246,246,246,246,246,246,246,246,246,246,78,246,58,78,58,78,78,78, +78,78,237,78,58,58,58,58,58,8,99,58,99,58,78,78,78,58,78,78, +78,78,78,78,78,58,246,246,246,246,103,246,246,246,246,218,58,58,78,78, +58,99,71,12,58,78,58,78,58,78,123,12,78,78,58,212,78,78,123,92, +12,12,99,99,12,92,92,71,11,118,82,101,112,116,236,82,112,112,82,118, +100,110,66,23,49,101,244,215,73,43,69,253,101,23,219,59,97,202,52,8, +8,4,120,97,187,139,27,143,46,113,26,26,46,88,60,27,131,200,192,47, +82,66,81,159,234,170,68,118,20,251,20,26,2,64,244,101,118,22,23,62, +62,49,20,118,244,23,208,245,30,11,71,12,92,12,12,49,12,12,71,58, +246,246,78,246,78,246,58,78,58,78,212,218,12,246,78,99,58,78,78,11, +12,58,58,246,246,103,246,246,58,246,246,246,246,78,246,78,78,78,58,78, +78,58,58,58,78,58,58,99,58,8,99,58,58,58,99,78,58,78,78,78, +78,212,78,246,246,78,99,58,246,246,246,246,246,246,71,12,99,58,58,99, +58,58,53,251,71,78,78,78,78,246,19,19,71,246,246,78,212,246,12,92, +12,12,12,12,92,12,12,71,218,118,19,101,244,239,65,223,244,11,53,112, +222,235,66,112,223,20,72,45,90,221,8,253,19,242,214,97,57,152,26,8, +26,188,57,187,139,186,8,8,8,8,121,121,8,8,26,4,44,131,94,67, +162,82,113,44,159,76,220,29,82,0,20,8,98,238,245,82,82,237,23,62, +54,112,20,223,237,49,22,245,237,11,71,49,12,92,12,12,12,12,71,78, +246,58,246,58,246,78,246,58,246,212,58,19,101,218,78,78,99,58,58,53, +101,71,58,246,246,246,78,71,92,58,246,246,212,246,78,58,58,78,78,58, +78,78,78,78,58,58,58,58,58,8,99,99,58,99,58,78,78,58,99,58, +78,78,58,246,78,58,71,92,218,246,246,246,103,246,12,92,92,58,58,58, +58,218,63,53,19,246,246,78,78,212,53,92,92,212,246,78,78,58,92,218, +12,12,92,92,92,12,12,71,11,118,101,101,22,116,242,223,237,11,8,30, +17,62,70,112,8,53,72,172,134,143,8,20,223,109,102,57,97,81,121,82, +252,114,35,157,165,26,253,8,8,46,182,4,26,26,8,8,113,160,190,35, +186,66,121,106,117,152,232,68,49,79,20,8,26,42,17,223,53,22,112,244, +54,244,8,82,30,118,30,245,30,11,99,12,12,92,123,12,12,12,71,78, +246,78,246,78,58,246,246,58,246,58,12,53,53,12,78,78,78,99,12,63, +63,92,78,78,246,246,78,229,229,12,246,246,246,212,78,71,71,58,78,78, +58,78,78,58,58,58,212,58,58,8,99,58,58,58,58,78,78,58,99,218, +99,58,246,78,78,58,12,92,12,78,246,246,246,218,92,92,19,71,58,58, +58,12,38,92,53,71,246,58,246,218,108,92,92,218,246,212,78,58,12,218, +12,12,12,92,12,92,12,71,71,118,82,8,103,116,242,82,244,11,82,30, +222,210,223,23,8,101,55,172,183,186,8,253,223,110,102,157,97,161,8,8, +127,67,190,140,189,26,8,8,69,127,120,5,52,26,26,8,121,9,84,187, +43,113,82,98,142,152,89,119,244,20,0,253,121,219,64,23,101,30,30,23, +54,244,82,101,30,112,112,72,237,71,30,12,12,92,118,12,12,12,71,58, +246,246,58,246,58,212,78,246,58,246,108,63,53,19,78,78,78,58,53,101, +53,108,78,246,246,246,108,79,20,53,246,246,246,78,99,92,92,12,99,78, +78,58,58,218,218,218,99,58,58,8,99,99,58,58,58,99,99,218,71,11, +99,99,78,246,212,71,218,71,92,71,246,246,246,71,92,92,19,19,58,58, +58,92,53,92,92,108,58,246,246,71,92,92,92,92,212,246,246,58,123,48, +12,12,12,92,92,12,12,12,99,118,19,101,237,116,65,49,30,112,82,244, +222,235,26,118,82,101,65,136,183,7,8,8,82,242,21,157,57,192,69,8, +26,7,191,157,190,60,9,8,26,52,84,131,60,4,121,8,26,113,67,94, +142,113,82,98,43,152,10,119,244,251,0,253,121,111,64,23,101,244,22,49, +62,62,82,101,112,23,112,103,30,71,11,12,12,118,12,12,118,12,71,78, +78,246,78,58,218,58,78,246,246,12,53,101,53,19,58,78,58,12,63,63, +53,63,218,246,246,71,79,20,63,101,218,246,246,218,12,19,108,12,99,58, +99,71,218,71,71,218,71,218,71,8,99,58,99,99,58,58,11,218,71,218, +71,71,218,58,58,99,218,99,71,92,218,78,246,92,92,12,223,53,71,58, +58,19,19,92,92,19,12,78,78,12,92,92,92,92,71,78,78,218,123,241, +48,12,12,92,49,12,118,12,71,49,223,101,11,116,65,66,112,11,82,112, +100,54,66,66,223,20,244,105,90,159,8,8,8,244,10,167,187,202,98,8, +121,47,192,169,190,35,195,188,188,195,57,84,106,47,8,8,8,122,195,140, +95,66,82,98,142,221,175,119,244,251,251,20,8,219,64,112,101,30,242,118, +23,62,19,20,11,118,112,22,11,11,99,12,12,12,12,71,12,118,71,58, +246,58,246,99,12,99,212,78,58,19,53,53,101,53,58,78,218,53,101,53, +53,63,218,246,246,63,0,101,19,53,12,78,58,12,108,92,19,108,92,71, +71,12,71,71,123,71,71,123,71,8,99,99,58,58,58,11,58,11,99,218, +99,11,99,99,218,99,218,99,71,12,12,99,99,92,92,92,12,19,53,71, +99,38,53,12,12,92,19,218,212,92,92,92,48,12,108,128,246,218,123,48, +128,123,12,12,12,12,12,118,71,71,223,8,112,41,55,49,49,244,223,49, +93,231,70,82,223,20,82,116,181,158,252,8,20,223,242,214,57,157,156,46, +8,66,26,147,44,198,86,196,86,198,44,52,4,8,8,8,46,60,97,194, +52,82,82,180,159,177,232,64,66,79,20,8,26,231,100,49,8,237,62,23, +62,244,82,82,30,223,11,237,112,11,11,12,12,71,12,12,118,12,71,218, +246,78,58,218,92,99,246,212,92,53,79,79,53,53,218,58,19,63,38,126, +53,101,92,58,19,251,63,223,19,19,92,71,12,223,92,223,223,92,19,92, +12,71,123,71,71,71,71,71,71,8,11,58,11,58,99,58,99,58,99,58, +58,218,218,218,99,218,11,99,99,71,92,92,12,49,92,71,99,12,53,53, +92,20,53,123,48,12,92,19,218,19,92,12,241,48,92,92,58,218,92,241, +128,212,71,12,118,12,12,71,71,112,223,19,82,55,116,112,49,244,223,19, +208,238,235,66,223,253,82,22,250,73,95,113,8,82,49,111,102,207,132,188, +252,69,8,121,162,4,47,52,127,4,4,26,26,8,8,46,186,86,169,95, +66,8,4,95,192,87,45,236,101,251,253,8,70,222,236,223,223,237,244,23, +54,244,82,82,237,118,11,244,71,11,99,71,118,12,12,12,12,12,12,58, +78,78,246,123,108,12,212,12,53,63,13,83,63,53,12,92,53,226,13,13, +53,53,53,226,75,63,12,71,92,19,19,92,92,92,19,12,12,12,92,12, +71,71,71,71,71,12,71,71,71,8,99,99,58,99,99,58,58,99,58,58, +11,218,71,71,11,218,99,99,58,218,12,19,92,92,92,99,78,58,92,101, +75,251,53,12,123,48,92,108,101,63,92,12,241,241,92,92,108,92,108,128, +212,246,58,12,12,12,49,12,12,118,12,49,19,237,116,22,49,118,244,82, +112,17,231,70,223,82,20,82,93,45,133,7,46,8,8,49,50,224,168,207, +142,60,127,46,8,26,8,8,8,8,8,8,121,26,47,192,166,169,7,113, +66,113,7,156,36,217,28,23,251,251,20,26,111,222,30,8,49,22,112,62, +242,112,101,112,30,49,244,11,112,11,99,71,12,12,118,12,12,12,71,246, +246,78,212,92,108,92,218,53,38,13,0,0,63,101,20,63,101,75,83,83, +63,101,229,79,126,92,58,78,12,19,92,92,19,92,12,71,71,118,71,71, +218,12,71,71,71,71,71,218,99,8,218,99,218,58,58,218,99,99,58,99, +58,58,99,99,218,99,218,99,58,58,99,92,92,92,19,58,78,78,99,108, +0,34,38,123,123,48,123,92,53,108,92,12,241,241,241,123,92,19,19,123, +241,212,246,99,12,71,12,71,12,71,118,223,82,118,245,100,112,49,30,118, +223,237,238,111,113,223,19,20,49,93,144,184,44,113,8,253,19,210,173,141, +168,57,196,142,60,52,122,182,113,113,122,3,60,159,130,86,43,122,26,223, +47,106,95,76,89,68,244,20,251,20,8,210,238,72,223,19,30,112,23,62, +244,223,20,118,112,112,244,118,11,99,99,218,71,218,71,12,12,71,58,58, +78,246,246,92,63,53,53,101,83,0,83,83,53,63,63,53,20,83,0,0, +53,53,79,0,226,78,58,78,12,108,92,19,92,71,58,58,99,71,71,123, +71,218,218,71,218,218,99,218,99,8,99,99,218,218,99,99,99,99,58,99, +99,58,99,11,71,99,99,58,58,58,58,71,92,92,19,78,78,58,78,218, +53,63,101,123,123,48,48,123,92,19,92,92,241,241,241,241,92,92,92,12, +241,212,78,78,123,118,12,12,12,12,112,92,49,223,30,247,65,49,23,112, +82,23,72,231,14,26,82,19,101,49,17,146,102,154,147,69,8,82,49,23, +249,104,158,39,206,169,86,130,202,142,202,114,39,117,76,88,4,66,66,113, +7,95,234,175,68,22,101,20,251,8,4,107,100,112,101,112,30,23,112,62, +49,101,49,244,118,112,112,118,11,78,99,99,99,58,71,12,92,99,246,78, +246,58,218,108,108,53,63,229,0,83,34,13,53,53,101,38,13,0,0,13, +53,101,63,101,99,78,58,78,71,19,19,92,71,58,99,58,11,218,218,71, +99,99,99,99,218,58,99,218,218,8,71,218,99,99,218,58,99,99,99,99, +99,58,99,58,99,218,11,58,58,99,58,58,71,92,92,58,78,78,78,78, +118,19,53,123,48,128,128,48,123,12,92,92,48,128,212,48,241,12,12,92, +241,128,246,246,246,71,12,12,12,71,71,118,49,223,49,208,116,22,49,23, +11,223,223,72,225,235,113,82,82,101,49,65,68,164,201,7,162,26,8,121, +66,223,23,216,14,36,177,152,154,152,80,255,98,66,66,223,66,4,32,152, +152,163,228,222,112,251,20,20,8,113,219,222,22,82,23,22,62,112,54,244, +101,82,112,112,23,118,112,11,11,78,58,58,246,99,71,71,99,58,246,212, +58,58,123,108,108,53,20,13,101,19,34,13,53,53,53,0,75,38,0,34, +63,53,53,71,58,78,58,78,11,92,92,71,58,58,58,58,99,218,11,99, +11,58,218,218,99,99,218,99,99,8,99,71,99,99,99,99,99,218,58,99, +218,58,99,99,99,58,58,78,58,99,58,58,58,71,12,78,78,78,78,78, +58,12,19,12,48,218,246,218,48,12,92,92,241,48,58,212,48,241,12,92, +48,241,212,58,212,212,123,118,12,71,118,118,12,223,49,118,55,239,244,223, +112,112,82,118,236,225,14,4,26,82,101,19,112,93,153,21,224,174,88,162, +26,26,121,82,66,66,66,66,66,66,26,82,66,26,113,127,32,44,51,87, +248,222,236,223,20,20,20,8,70,111,17,237,223,49,237,30,62,54,30,118, +253,49,112,118,23,118,118,11,99,58,58,58,212,99,71,218,246,78,78,58, +58,58,108,108,63,38,13,92,58,12,13,251,53,63,251,79,12,71,34,34, +251,53,19,58,78,78,78,58,58,71,71,58,99,99,58,99,58,11,58,99, +99,99,99,218,218,99,218,218,99,8,71,99,218,218,218,99,218,99,99,99, +99,71,58,99,99,99,99,58,58,99,58,58,78,58,99,78,58,78,58,78, +78,78,99,218,128,58,58,78,128,48,12,92,123,241,78,246,58,48,241,218, +12,128,212,212,58,58,212,218,71,12,71,12,118,12,223,49,11,243,55,244, +49,112,244,223,49,236,17,111,4,121,82,82,8,223,244,29,153,61,148,234, +152,32,147,52,4,4,113,26,113,26,98,98,147,255,7,193,24,163,217,238, +110,112,101,20,20,253,8,70,107,222,22,223,223,244,244,244,244,242,112,82, +223,118,23,23,49,118,71,11,58,58,58,246,246,58,99,78,58,212,212,78, +58,99,53,53,38,83,19,58,246,19,34,79,251,34,34,71,58,71,79,13, +83,63,218,58,58,99,58,78,58,99,78,58,99,99,99,58,58,99,99,58, +218,11,218,99,11,218,11,99,71,8,71,218,218,11,71,99,218,99,99,99, +99,218,11,99,58,58,58,58,11,58,99,218,58,58,78,78,78,78,58,58, +78,78,78,78,58,78,78,78,58,58,48,123,48,48,128,78,246,78,128,241, +241,241,128,212,58,58,58,58,218,12,118,71,71,112,118,223,49,11,245,55, +30,49,112,244,223,19,30,93,107,111,4,26,101,101,8,101,112,242,93,203, +6,170,21,74,51,51,104,24,234,76,24,104,76,124,232,56,225,18,30,223, +20,20,20,20,8,66,235,231,236,112,223,118,30,112,112,54,244,112,82,49, +112,23,118,118,12,11,99,99,246,58,58,58,78,58,246,246,78,78,212,78, +58,12,53,229,34,40,78,78,58,38,0,13,13,79,71,58,58,71,13,0, +38,71,58,99,58,99,58,99,78,58,58,99,99,99,71,99,58,99,218,99, +71,99,218,99,99,71,218,99,71,8,71,71,71,123,218,218,11,218,218,218, +218,99,218,218,99,99,99,99,58,99,99,99,99,99,58,78,78,58,58,99, +99,78,78,246,78,212,78,78,58,78,128,48,48,241,48,246,78,58,246,128, +128,128,128,128,212,78,212,78,58,218,71,71,12,12,118,118,49,49,112,208, +41,22,49,112,244,23,19,49,22,93,219,14,4,8,82,101,20,101,223,49, +30,65,18,29,17,203,228,230,56,96,91,225,225,236,242,112,49,82,20,20, +20,20,82,113,210,107,29,22,118,223,112,30,244,244,62,112,23,82,223,49, +118,118,49,49,118,71,99,246,58,58,212,246,246,78,212,58,246,246,78,58, +218,53,209,126,40,78,78,78,218,0,34,34,79,71,78,99,58,71,251,229, +12,58,99,99,99,58,58,58,58,99,99,99,99,218,99,58,99,99,99,218, +99,218,11,218,218,11,218,71,71,8,71,123,71,71,218,123,71,99,11,99, +218,11,99,71,218,99,58,99,99,58,218,218,99,99,58,58,58,58,99,58, +58,99,58,246,246,246,78,58,58,58,78,58,48,48,241,78,246,78,78,58, +58,241,241,241,212,58,246,78,246,58,218,71,71,71,118,118,118,49,49,112, +103,243,236,112,49,244,112,49,223,118,65,93,107,14,98,113,82,8,101,253, +101,20,101,82,82,223,118,118,49,49,49,82,82,101,101,20,20,253,253,121, +26,70,235,110,29,103,118,223,223,11,244,244,54,242,244,49,19,223,49,118, +118,49,12,71,11,99,212,246,78,78,78,78,212,246,78,58,78,212,78,58, +12,38,213,71,78,58,58,78,40,83,79,20,99,58,99,58,99,12,92,71, +78,58,99,99,99,99,99,99,99,99,218,218,99,218,218,99,218,218,11,218, +11,218,218,71,218,218,71,123,71,8,71,71,12,71,71,218,218,218,71,71, +218,218,218,218,71,218,218,99,99,218,99,99,99,99,99,99,58,99,58,99, +99,99,99,58,78,78,78,78,58,99,58,58,58,128,48,128,78,78,58,78, +212,212,212,241,128,58,246,246,58,246,58,218,218,118,71,71,118,12,118,49, +23,237,245,55,208,23,118,23,112,223,223,118,244,236,18,110,14,210,4,66, +121,8,82,20,82,101,101,251,20,20,20,101,8,20,8,8,26,26,210,235, +109,110,65,30,118,223,49,244,244,244,244,242,65,30,223,82,49,118,118,49, +92,49,118,71,11,78,246,78,58,246,212,246,78,78,246,78,246,78,212,218, +53,92,99,78,58,58,58,246,53,0,53,99,99,58,99,58,99,71,218,58, +99,58,99,218,58,99,58,78,99,99,11,99,71,99,99,218,99,99,218,71, +123,218,71,218,12,71,71,71,71,8,71,71,71,71,71,118,71,71,218,99, +71,71,71,123,71,71,218,99,99,218,218,71,11,218,99,99,58,99,58,99, +99,99,218,58,58,78,78,78,58,99,99,58,58,58,58,128,246,78,58,58, +58,58,246,128,128,58,212,246,78,78,78,58,58,218,71,71,11,118,118,49, +12,23,11,103,243,72,237,23,23,112,23,223,19,223,112,22,109,18,29,111, +111,210,210,70,4,26,26,26,26,26,26,4,4,70,98,235,2,18,29,65, +54,23,223,49,23,244,244,112,244,54,22,244,118,82,223,223,118,92,49,49, +223,71,11,99,99,78,246,58,246,78,58,212,78,78,58,58,246,78,58,218, +71,78,58,58,99,58,58,99,19,77,58,58,58,218,99,58,58,58,58,58, +218,99,11,218,58,99,218,58,218,218,71,218,218,71,99,71,218,71,71,218, +71,123,71,71,71,71,71,71,12,8,118,118,71,71,118,71,71,71,118,12, +71,123,71,71,71,71,71,71,218,99,99,99,218,218,71,218,99,99,58,99, +99,218,99,218,58,58,246,78,78,99,99,99,99,58,246,78,58,246,58,58, +58,58,58,78,78,58,58,58,246,212,99,58,58,58,218,99,71,118,11,118, +49,49,49,23,11,208,55,245,22,112,23,23,23,23,49,49,49,223,112,30, +22,236,18,18,18,29,18,18,18,18,107,236,29,236,236,22,30,23,223,223, +223,118,118,112,244,112,244,242,242,30,23,223,82,223,49,49,49,223,49,12, +71,71,99,58,246,212,58,58,58,78,78,78,58,58,58,58,78,212,246,78, +78,58,58,11,99,58,78,78,99,58,58,99,218,99,58,99,58,58,58,218, +99,71,218,99,218,58,99,218,218,71,218,123,71,99,71,218,71,71,71,12, +71,71,12,12,12,12,12,12,12,8,12,12,12,12,12,12,118,118,71,71, +71,218,71,123,71,71,71,71,123,71,218,11,218,71,218,123,218,99,218,58, +99,99,11,218,71,99,99,58,78,58,99,99,71,99,58,78,246,246,246,58, +58,218,58,99,78,78,246,78,78,246,58,58,58,212,58,58,99,71,71,118, +71,118,118,23,49,112,112,103,72,72,65,244,112,23,118,118,70,223,223,223, +223,49,118,23,118,112,112,244,112,112,23,23,23,49,49,223,223,49,23,118, +244,244,112,62,244,109,22,30,49,223,223,82,49,223,49,223,223,118,118,71, +99,99,99,78,78,246,58,58,78,78,58,58,58,99,78,246,78,78,78,78, +99,99,99,58,99,58,78,78,58,99,99,11,218,99,99,58,58,11,99,218, +218,218,71,99,218,218,11,218,123,71,218,71,71,218,71,71,123,71,118,12, +71,12,12,12,12,12,12,12,12,8,12,12,12,12,12,12,71,71,71,118, +71,118,71,71,118,12,71,71,71,71,99,218,123,71,218,71,218,71,99,99, +99,218,218,71,218,218,99,58,58,58,58,218,99,218,218,99,58,99,78,58, +58,99,99,99,58,58,78,246,246,78,78,78,58,99,58,58,99,58,99,71, +11,71,12,23,118,118,118,23,112,30,103,208,208,65,242,112,118,23,23,118, +118,118,49,112,23,112,11,112,112,112,118,49,49,49,49,112,23,23,112,244, +244,22,22,22,242,112,49,223,223,66,223,49,223,49,223,49,12,71,71,99, +99,58,212,212,246,58,78,78,58,58,99,99,99,58,78,78,78,78,58,58, +99,99,99,58,58,58,58,58,99,218,71,218,99,99,218,58,99,99,71,218, +71,71,218,99,71,99,123,71,118,118,123,71,71,123,71,71,12,12,118,12, +12,12,12,12,12,12,71,12,71,8,12,92,12,92,71,12,118,118,12,12, +118,71,71,12,71,71,118,12,12,71,118,218,71,71,71,12,71,12,218,218, +99,99,218,218,71,71,71,218,99,99,99,99,71,71,218,71,99,58,58,58, +58,58,99,11,99,99,99,58,246,78,246,78,58,99,99,99,58,58,99,99, +99,11,71,112,112,118,118,92,118,23,118,112,30,237,103,65,65,22,30,54, +244,244,23,112,244,112,244,112,244,23,244,23,112,62,244,244,30,242,22,242, +22,30,23,49,49,19,82,223,223,49,49,49,223,49,12,11,11,218,99,58, +58,78,78,78,246,78,78,99,99,58,99,58,58,78,78,78,58,99,218,218, +71,99,99,99,58,99,58,99,71,123,71,218,99,99,218,99,218,71,12,71, +71,218,71,71,218,71,71,71,71,71,12,71,71,71,118,12,12,12,71,71, +12,12,12,12,118,12,12,92,12,8,12,12,71,12,12,12,12,12,71,12, +118,12,12,12,118,12,71,12,12,71,71,71,71,123,71,12,12,71,71,218, +218,218,11,71,123,71,71,218,71,99,99,58,99,99,71,218,218,99,218,58, +58,58,58,99,218,71,99,218,58,58,58,246,212,58,58,99,99,58,99,58, +58,58,58,218,71,71,112,71,118,118,49,23,118,118,49,112,112,30,237,22, +22,22,103,22,22,22,22,22,30,242,22,22,22,103,22,22,30,112,112,23, +49,49,49,82,223,66,49,49,49,49,223,12,118,71,218,99,99,58,99,58, +78,246,78,246,58,58,99,99,218,218,99,99,99,58,58,58,99,218,71,218, +99,99,58,58,58,99,218,123,71,71,218,218,99,99,99,123,71,71,71,92, +71,71,218,218,71,12,12,12,118,71,12,118,71,71,71,12,12,12,12,12, +12,12,118,118,12,12,12,12,12,8,92,92,92,12,12,12,12,12,12,12, +92,12,12,12,71,12,118,12,12,12,12,12,71,71,71,12,12,71,118,71, +71,123,71,71,71,118,71,71,71,123,71,218,218,99,218,71,12,71,71,218, +218,58,58,99,58,71,71,218,218,218,99,58,58,58,58,58,99,99,99,218, +218,99,58,58,99,99,99,11,11,11,23,112,118,112,49,118,118,118,23,118, +49,118,23,112,112,112,112,244,112,112,118,112,118,49,49,223,49,223,223,49, +223,223,49,49,223,49,223,223,118,118,71,11,218,99,218,99,218,78,58,58, +58,58,58,218,218,218,218,218,58,99,58,58,58,58,218,99,71,71,123,71, +218,99,58,99,99,71,71,12,12,71,71,71,218,218,218,71,118,71,71,12, +123,71,12,71,71,12,12,12,118,71,12,12,12,118,118,12,71,118,12,118, +12,12,12,12,12,92,12,12,92,8,92,92,12,12,92,12,92,12,12,12, +12,12,118,12,12,12,12,12,12,12,118,12,12,71,118,71,12,12,71,118, +71,71,71,123,218,118,12,71,71,71,71,99,99,218,218,71,71,71,71,71, +99,218,99,58,99,218,218,71,71,71,218,71,58,99,58,58,99,58,218,99, +99,218,99,99,58,58,58,99,58,99,218,11,71,112,11,112,118,23,118,23, +49,118,118,92,49,92,49,92,49,92,49,223,223,49,223,49,49,49,49,82, +49,49,49,223,118,118,71,71,11,71,99,218,218,99,58,58,58,58,58,58, +58,218,218,218,71,218,218,99,99,99,99,58,218,218,71,123,71,71,218,11, +99,99,218,218,71,71,12,71,12,218,218,218,71,218,118,12,71,118,71,71, +71,71,71,71,118,71,12,12,12,71,12,12,12,12,12,12,12,49,12,12, +12,92,12,49,12,92,12,12,92,8,92,92,92,92,92,12,92,12,12,92, +12,92,12,92,12,71,71,12,12,12,12,71,12,118,71,118,71,118,12,12, +12,12,71,71,218,71,71,118,118,12,12,118,71,218,71,218,123,12,12,12, +12,71,71,99,99,99,218,71,71,71,71,123,71,218,218,58,99,99,58,218, +99,218,218,11,99,218,99,218,218,58,58,58,99,218,71,11,71,71,118,11, +112,71,112,118,112,12,118,118,118,118,118,118,118,118,118,118,223,223,49,49, +118,118,118,71,71,71,218,71,218,71,99,99,99,218,58,58,58,218,218,218, +218,71,71,218,123,71,218,99,58,218,218,99,71,118,12,71,71,71,218,218, +218,99,71,118,12,12,12,71,71,123,71,71,71,12,118,12,92,71,118,71, +12,12,71,12,12,92,12,12,12,118,12,12,12,12,12,92,12,12,12,92, +71,92,12,92,92,92,92,92,12,8,92,92,92,92,92,92,92,92,92,12, +92,12,92,12,92,92,12,118,92,12,12,92,92,12,12,12,12,12,12,12, +12,12,71,118,12,118,71,71,12,12,12,12,118,71,218,71,218,71,118,12, +12,71,12,71,218,71,99,218,123,71,71,12,71,118,71,71,99,218,218,99, +218,99,218,218,218,71,123,71,218,218,218,218,99,99,99,58,99,99,99,218, +99,71,71,71,11,71,11,11,11,11,11,11,11,11,71,118,12,118,218,218, +71,218,71,71,218,71,99,71,99,99,99,58,218,99,218,218,71,71,71,71, +71,71,123,71,11,99,99,99,218,218,71,71,12,12,12,71,123,218,71,218, +71,118,71,12,118,12,12,71,71,218,118,12,12,12,92,12,71,118,71,71, +12,71,92,12,92,12,12,12,118,12,12,92,92,12,92,12,92,92,92,92, +92,92,92,92,12,92,92,92,92,8,92,92,92,12,92,92,92,92,92,92, +92,92,92,12,92,92,12,12,92,92,92,12,92,92,12,12,118,12,12,92, +92,12,12,12,71,71,71,118,12,118,12,12,12,71,12,71,71,71,71,12, +12,12,118,12,12,118,218,71,71,71,12,71,71,71,12,12,71,71,71,11, +218,99,218,218,218,218,71,71,71,71,71,71,71,71,218,218,218,218,99,218, +218,218,99,218,99,218,218,218,218,218,218,218,218,99,218,11,218,71,71,71, +71,123,71,123,71,218,99,218,218,11,218,99,71,71,71,71,71,71,71,92, +71,71,71,123,71,218,71,71,71,118,12,12,12,12,71,71,71,218,71,71, +12,12,12,12,12,12,12,71,71,71,12,12,12,12,12,12,12,12,118,12, +12,92,92,92,12,92,12,71,12,92,92,12,92,92,92,92,92,12,92,92, +92,92,92,92,92,92,92,92,92,8,92,19,92,92,92,92,92,223,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,12,92,12,92,12,118,12,12, +12,92,92,12,92,12,12,12,71,12,49,12,92,92,12,12,71,12,12,12, +12,71,12,12,12,12,71,12,71,71,218,218,71,118,12,12,12,71,12,12, +71,123,71,71,99,71,71,123,71,123,71,123,71,71,71,71,71,71,71,71, +71,218,218,218,71,71,218,71,218,71,218,71,71,123,71,123,71,123,71,123, +218,71,218,218,218,218,71,71,71,71,71,12,12,12,12,12,12,12,71,71, +71,123,218,218,71,71,12,12,12,71,12,12,12,12,71,71,71,12,118,12, +12,92,12,12,12,12,12,12,71,12,92,12,92,12,12,118,12,12,12,92, +92,92,92,92,92,12,92,92,12,92,92,92,92,19,12,92,92,92,92,92, +12,92,92,92,92,92,92,92,92,8,19,108,19,108,12,19,92,92,92,92, +92,92,92,92,92,19,92,92,92,92,92,92,92,92,92,92,92,92,12,92, +92,92,92,92,92,92,12,12,12,12,71,12,92,92,92,92,12,92,118,12, +12,12,12,12,92,12,12,12,71,12,71,71,71,12,12,12,12,12,12,92, +112,118,71,12,71,71,71,218,71,71,71,71,71,71,12,12,12,12,12,12, +12,118,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71, +71,71,71,71,71,71,71,71,118,71,12,71,12,12,12,12,12,71,71,123, +71,71,71,92,12,12,12,12,92,92,71,12,12,12,12,71,12,12,92,12, +92,92,12,118,12,12,118,12,12,92,92,92,92,12,12,12,12,92,92,92, +92,12,92,12,92,12,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,12,19,19,108,92,8,92,92,19,92,108,92,19,92,92,92, +92,108,92,92,92,12,92,92,12,92,92,92,92,92,92,92,92,92,92,12, +12,92,92,92,92,223,12,92,12,12,12,12,12,92,92,12,92,12,12,12, +12,12,12,12,49,12,92,92,92,92,12,12,71,12,12,12,12,12,12,12, +92,92,118,92,12,12,118,12,12,12,12,12,12,71,12,12,12,12,12,12, +12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, +12,12,118,118,12,118,12,12,12,12,12,12,12,12,12,12,12,12,71,12, +12,12,71,92,12,92,92,49,12,12,12,12,118,12,12,118,92,12,92,92, +12,12,12,12,123,12,92,92,92,92,92,92,12,92,12,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,12,92,92,92,19,92,92,108, +92,19,92,108,108,92,108,92,108,8,19,108,19,92,19,108,108,108,92,19, +92,92,19,92,108,108,92,108,108,92,92,92,92,92,92,19,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,12,92,12,92,92,92,92,92, +92,12,12,12,12,12,12,92,92,92,92,92,92,12,12,12,12,12,118,12, +12,12,12,92,12,12,12,12,71,12,12,12,12,71,71,12,12,71,118,118, +12,12,12,12,12,118,12,12,12,92,12,12,12,12,12,71,12,12,118,12, +12,71,12,12,12,12,12,92,118,118,12,12,12,12,71,12,12,12,49,12, +92,12,92,92,92,12,92,12,12,12,12,12,92,92,92,92,92,92,92,92, +12,12,71,92,92,92,12,92,223,92,92,92,12,92,92,92,92,92,12,19, +92,92,92,92,92,92,108,92,108,19,92,108,108,108,92,92,19,108,92,108, +19,92,19,92,108,92,108,19,19,8,19,108,19,108,108,19,92,19,108,19, +19,108,108,19,19,92,108,92,92,108,19,12,108,108,92,19,108,108,92,19, +92,92,92,92,92,92,108,19,92,92,92,92,12,92,92,92,92,92,92,92, +92,92,92,12,12,118,123,92,12,12,92,92,92,92,92,92,12,12,12,12, +12,92,12,12,92,12,92,92,92,92,92,92,12,12,12,12,12,12,12,71, +71,12,12,12,12,12,12,12,71,12,12,12,12,12,12,92,12,12,92,12, +92,12,12,49,12,92,12,12,12,12,12,71,12,12,12,12,92,12,92,12, +92,92,92,92,92,12,12,12,12,92,12,12,92,92,92,92,92,92,12,12, +12,92,92,92,92,19,108,92,92,92,92,92,92,92,92,19,92,108,108,92, +92,92,92,19,108,92,19,108,92,108,108,92,19,92,108,19,108,92,108,92, +19,108,108,92,108,108,19,92,108,8,19,19,19,19,19,108,19,19,108,92, +19,19,108,92,19,19,108,19,108,92,108,19,92,19,92,92,92,19,92,92, +92,92,92,92,92,92,19,108,92,19,19,92,92,92,92,92,92,92,223,92, +223,92,92,92,92,92,92,92,92,92,92,92,92,223,92,92,92,12,92,12, +12,12,12,12,92,12,12,92,12,92,92,92,92,92,92,92,92,92,92,92, +92,92,12,92,49,92,12,92,92,12,12,92,12,92,12,92,12,12,92,12, +12,12,12,12,12,12,12,92,92,92,12,92,92,92,92,92,92,92,92,92, +92,92,12,12,12,12,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,12,19,92,92,108,12,92,92,92,12,19,92,92,108,92,19,19,92, +92,92,92,92,108,19,92,19,19,92,92,108,108,92,108,92,19,19,19,108, +19,19,19,19,19,19,108,19,19,8,19,53,19,53,19,53,19,53,19,108, +19,108,19,108,108,108,19,108,19,108,19,108,108,108,108,19,108,19,108,19, +19,92,108,19,19,12,108,92,108,92,108,19,108,92,92,92,92,92,92,19, +92,19,108,92,19,92,92,92,92,92,92,92,92,92,92,92,108,108,19,92, +92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,12,92,92,92,12,92,19,92,92,92,92,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,108,19,92,92,223,92,92,92,92,92,92, +19,108,108,108,108,19,92,92,92,92,108,108,108,108,108,92,108,92,108,19, +92,19,108,108,19,108,108,108,108,108,19,19,19,19,19,19,108,108,53,19, +108,19,108,53,19,53,19,53,19,8,19,19,19,19,19,19,19,19,19,19, +19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,108,19,108,19, +19,19,19,19,108,19,108,19,108,19,108,19,19,19,19,108,19,92,92,92, +19,19,108,19,108,19,19,92,92,92,92,92,92,92,92,19,19,108,19,108, +19,92,19,92,92,92,92,92,92,92,92,92,92,92,92,19,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,19,19,19,92,19,19,92,19,19,108,92,92,92,19,92,92,92, +92,92,92,92,92,19,19,19,19,108,19,108,92,92,92,92,92,92,19,19, +92,19,223,19,108,19,108,92,19,19,19,19,19,19,108,19,108,19,108,19, +19,19,19,19,19,19,19,19,19,108,19,108,19,108,19,19,19,19,19,19, +19,19,19,19,19,19,19,19,19,8}; diff --git a/plug-ins/Makefile.am b/plug-ins/Makefile.am index 518bfdc6c8..78e1514b88 100644 --- a/plug-ins/Makefile.am +++ b/plug-ins/Makefile.am @@ -29,6 +29,7 @@ SUBDIRS = \ script-fu \ $(GIMP_PERL) \ AlienMap \ + AlienMap2 \ FractalExplorer \ Lighting \ MapObject \ diff --git a/plug-ins/common/Makefile.am b/plug-ins/common/Makefile.am index a1d53f0a83..f142558c95 100644 --- a/plug-ins/common/Makefile.am +++ b/plug-ins/common/Makefile.am @@ -32,6 +32,7 @@ libexec_PROGRAMS = \ bz2 \ c_astretch \ checkerboard \ + color_enhance \ colorify \ compose \ convmatrix \ @@ -128,6 +129,7 @@ libexec_PROGRAMS = \ video \ vinvert \ vpropagate \ + warp \ waves \ whirlpinch \ wind \ @@ -277,6 +279,15 @@ checkerboard_LDADD = \ $(GTK_LIBS) \ $(INTLLIBS) +color_enhance_SOURCES = \ + color_enhance.c + +color_enhance_LDADD = \ + $(top_builddir)/libgimp/libgimpui.la \ + $(top_builddir)/libgimp/libgimp.la \ + $(GTK_LIBS) \ + $(INTLLIBS) + colorify_SOURCES = \ colorify.c @@ -1061,6 +1072,15 @@ vpropagate_LDADD = \ $(GTK_LIBS) \ $(INTLLIBS) +warp_SOURCES = \ + warp.c + +warp_LDADD = \ + $(top_builddir)/libgimp/libgimpui.la \ + $(top_builddir)/libgimp/libgimp.la \ + $(GTK_LIBS) \ + $(INTLLIBS) + waves_SOURCES = \ waves.c diff --git a/plug-ins/common/color_enhance.c b/plug-ins/common/color_enhance.c new file mode 100644 index 0000000000..81303d7c2b --- /dev/null +++ b/plug-ins/common/color_enhance.c @@ -0,0 +1,479 @@ +/* Color Enhance 0.10 --- image filter plug-in for The Gimp image + * manipulation program + * + * Copyright (C) 1999 Martin Weber + * Copyright (C) 1996 Federico Mena Quintero + * + * You can contact me at martin.weber@usa.net + * You can contact the original The Gimp authors at gimp@xcf.berkeley.edu + * + * 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. + */ + +/* This simple plug-in does an automatic Saturation stretch. For each + channel in the image, it finds the minimum and maximum values... it + uses those values to stretch the individual histograms to the full + range. For some images it may do just what you want; for others + it may be total crap :) This version operates in HSV space + and preserves hue. Most code is taken from autostretch_hsv */ + + +#include +#include +#include "libgimp/gimp.h" + +/* Declare local functions. + */ +static void query (void); +static void run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals); + +static void Color_Enhance (GDrawable * drawable); +static void indexed_Color_Enhance (gint32 image_ID); + +static void calc_rgb_to_hsv(gint r, gint g, gint b, double *h, double + *s, double *v); +static void calc_hsv_to_rgb(gint *r, gint *g, gint *b, + double h, double s, double v); + +GPlugInInfo PLUG_IN_INFO = +{ + NULL, /* init_proc */ + NULL, /* quit_proc */ + query, /* query_proc */ + run, /* run_proc */ +}; + + +MAIN () + +static void +query () +{ + static GParamDef args[] = + { + { PARAM_INT32, "run_mode", "Interactive, non-interactive" }, + { PARAM_IMAGE, "image", "Input image" }, + { PARAM_DRAWABLE, "drawable", "Input drawable" }, + }; + static GParamDef *return_vals = NULL; + static int nargs = sizeof (args) / sizeof (args[0]); + static int nreturn_vals = 0; + + gimp_install_procedure ("plug_in_Color_Enhance", + "Automatically stretch the saturation of the +specified drawable to cover all possible ranges.", + "This simple plug-in does an automatic +saturation stretch. For each channel in the image, it finds the +minimum and maximum values... it uses those values to stretch the individual +histograms to the full range. For some images it may do just what +you want; for others it may be total crap :). This version differs from +Contrast Autostretch in that it works in HSV space, and preserves hue.", + "Martin Weber", + "Martin Weber", + "1997", + "/Image/Colors/Color Enhance", + "RGB*, INDEXED*", + PROC_PLUG_IN, + nargs, nreturn_vals, + args, + return_vals); } + +static void +run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals) +{ + static GParam values[1]; + GDrawable *drawable; + GRunModeType run_mode; + GStatusType status = STATUS_SUCCESS; + + gint32 image_ID; + + run_mode = param[0].data.d_int32; + + /* Get the specified drawable */ + drawable = gimp_drawable_get (param[2].data.d_drawable); + image_ID = param[1].data.d_image; + + /* Make sure that the drawable is gray or RGB color */ + if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id)) + { + gimp_progress_init ("Color Enhance..."); + gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); + Color_Enhance (drawable); + + if (run_mode != RUN_NONINTERACTIVE) + gimp_displays_flush (); + } + else if (gimp_drawable_indexed (drawable->id)) + { + indexed_Color_Enhance (image_ID); + + if (run_mode != RUN_NONINTERACTIVE) + gimp_displays_flush (); + } + else + { + /* gimp_message ("Color_Enhance: cannot operate on indexed color images"); */ + status = STATUS_EXECUTION_ERROR; + } + + *nreturn_vals = 1; + *return_vals = values; + + values[0].type = PARAM_STATUS; + values[0].data.d_status = status; + + gimp_drawable_detach (drawable); +} + + +static void +indexed_Color_Enhance(gint32 image_ID) /* a.d.m. */ +{ + guchar *cmap; + gint ncols,i; + + double vhi = 0.0, vlo = 1.0; + + cmap = gimp_image_get_cmap (image_ID, &ncols); + + if (cmap==NULL) + { + printf("Color_Enhance: cmap was NULL! Quitting...\n"); + gimp_quit(); + } + + for (i=0;i vhi) vhi = v; + if (v < vlo) vlo = v; + } + + for (i=0;i 255) c = 255; + m += k; + if (m > 255) m = 255; + y += k; + if (y > 255) y = 255; + cmap[i*3+0] = 255 - c; + cmap[i*3+1] = 255 - m; + cmap[i*3+2] = 255 - y; + } + + gimp_image_set_cmap (image_ID, cmap, ncols); +} + + +static void +Color_Enhance (GDrawable *drawable) +{ + GPixelRgn src_rgn, dest_rgn; + guchar *src, *s; + guchar *dest, *d; + double vhi = 0.0, vlo = 1.0; + gint progress, max_progress; + gint has_alpha, alpha; + gint x1, y1, x2, y2; + gint x, y; + gpointer pr; + + /* Get selection area */ + gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); + has_alpha = gimp_drawable_has_alpha (drawable->id); + alpha = (has_alpha) ? drawable->bpp - 1 : drawable->bpp; + + /* Initialize progress */ + progress = 0; + max_progress = (x2 - x1) * (y2 - y1) * 2; + + gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); + + for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) + { + src = src_rgn.data; + + for (y = 0; y < src_rgn.h; y++) + { + s = src; + for (x = 0; x < src_rgn.w; x++) + { + if (!has_alpha || (has_alpha && s[alpha])) + { + double h, z, v; + double c, m, y; + double k; + c = 255 - s[0]; + m = 255 - s[1]; + y = 255 - s[2]; + k = c; + if (m < k) k = m; + if (y < k) k = y; + calc_rgb_to_hsv(c - k, m - k, y - k, &h, &z, &v); + if (v > vhi) vhi = v; + if (v < vlo) vlo = v; + } + + s += src_rgn.bpp; + } + + src += src_rgn.rowstride; + } + + /* Update progress */ + progress += src_rgn.w * src_rgn.h; + + gimp_progress_update ((double) progress / (double) max_progress); + } + + /* Now substitute pixel vales */ + gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); + gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); + + for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) + { + src = src_rgn.data; + dest = dest_rgn.data; + + for (y = 0; y < src_rgn.h; y++) + { + s = src; + d = dest; + + for (x = 0; x < src_rgn.w; x++) + { + double h, z, v; + gint c, m, y; + double k; + c = 255 - s[0]; + m = 255 - s[1]; + y = 255 - s[2]; + k = c; + if (m < k) k = m; + if (y < k) k = y; + calc_rgb_to_hsv(c - k, m - k, y - k, &h, &z, &v); + if (vhi!=vlo) + v = (v-vlo) / (vhi-vlo); + calc_hsv_to_rgb(&c, &m , &y, h, z, v); + c += k; + if (c > 255) c = 255; + m += k; + if (m > 255) m = 255; + y += k; + if (y > 255) y = 255; + d[0] = 255 - c; + d[1] = 255 - m; + d[2] = 255 - y; + + if (has_alpha) + d[alpha] = s[alpha]; + + s += src_rgn.bpp; + d += dest_rgn.bpp; + } + + src += src_rgn.rowstride; + dest += dest_rgn.rowstride; + + } + + /* Update progress */ + progress += src_rgn.w * src_rgn.h; + + gimp_progress_update ((double) progress / (double) max_progress); + } + + /* update the region */ + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->id, TRUE); + gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1)); +} + +static void +calc_rgb_to_hsv(gint r, gint g, gint b, double *hue, double *sat, double +*val) { + double red, green, blue; + double h, s, v; + double min, max; + double delta; + + red = (double)r / 255.0; + green = (double)g / 255.0; + blue = (double)b / 255.0; + + h = 0.0; /* Shut up -Wall */ + + if (red > green) + { + if (red > blue) + max = red; + else + max = blue; + + if (green < blue) + min = green; + else + min = blue; + } + else + { + if (green > blue) + max = green; + else + max = blue; + + if (red < blue) + min = red; + else + min = blue; + } + + v = max; + + if (max != 0.0) + s = (max - min) / max; + else + s = 0.0; + + if (s == 0.0) + h = 0.0; + else + { + delta = max - min; + + if (red == max) + h = (green - blue) / delta; + else if (green == max) + h = 2 + (blue - red) / delta; + else if (blue == max) + h = 4 + (red - green) / delta; + + h /= 6.0; + + if (h < 0.0) + h += 1.0; + else if (h > 1.0) + h -= 1.0; + } + + *hue = h; + *sat = s; + *val = v; +} + +static void +calc_hsv_to_rgb(gint *r, gint *g, gint *b, double h, double s, double +v) { + double hue, saturation, value; + double f, p, q, t; + + if (s == 0.0) + { + h = v; + s = v; + v = v; /* heh */ + } + else + { + hue = h * 6.0; + saturation = s; + value = v; + + if (hue == 6.0) + hue = 0.0; + + f = hue - (int) hue; + p = value * (1.0 - saturation); + q = value * (1.0 - saturation * f); + t = value * (1.0 - saturation * (1.0 - f)); + + switch ((int) hue) + { + case 0: + h = value; + s = t; + v = p; + break; + + case 1: + h = q; + s = value; + v = p; + break; + + case 2: + h = p; + s = value; + v = t; + break; + + case 3: + h = p; + s = q; + v = value; + break; + + case 4: + h = t; + s = p; + v = value; + break; + + case 5: + h = value; + s = p; + v = q; + break; + } + } + + *r = h*255; + *g = s*255; + *b = v*255; + +} + diff --git a/plug-ins/common/nova.c b/plug-ins/common/nova.c index 3a8bf64580..faede6d526 100644 --- a/plug-ins/common/nova.c +++ b/plug-ins/common/nova.c @@ -3,7 +3,7 @@ * * SuperNova plug-in * Copyright (C) 1997 Eiichi Takamori , - * Spencer Kimball, Federico Mena Quintero + * Spencer Kimball, Federico Mena Quintero * * 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 @@ -12,7 +12,7 @@ * * 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 + * 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 @@ -21,15 +21,20 @@ */ /* - * version 1.1115 + * version 1.122 * This plug-in requires GIMP v0.99.10 or above. * * This plug-in produces an effect like a supernova burst. * - * Eiichi Takamori - * http://ha1.seikyou.ne.jp/home/taka/gimp/ + * Eiichi Takamori + * http://ha1.seikyou.ne.jp/home/taka/gimp/ * * + * Changes from version 1.1115 to version 1.122 by Martin Weber: + * - Little bug fixes + * - Added random hue + * - Freeing memory + * * Changes from version 1.1114 to version 1.1115: * - Added gtk_rc_parse * - Fixed bug that drawing preview of small height image @@ -49,12 +54,11 @@ * - fix preview * - add notebook interface and so on */ -#include "config.h" #include #include +#include #include - #include "gtk/gtk.h" #include "libgimp/gimp.h" @@ -66,6 +70,10 @@ static char rcsid[] = "$Id$"; /* Some useful macros */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /* M_PI */ + #ifndef RAND_MAX #define RAND_MAX 2147483647 #endif /* RAND_MAX */ @@ -82,19 +90,20 @@ static void dummy_printf( char *fmt, ... ) {} #define PREVIEW_SIZE 100 #define TILE_CACHE_SIZE 16 -#define PREVIEW 0x1 -#define CURSOR 0x2 -#define ALL 0xf +#define PREVIEW 0x1 +#define CURSOR 0x2 +#define ALL 0xf #define PREVIEW_MASK GDK_EXPOSURE_MASK | \ - GDK_BUTTON_PRESS_MASK | \ - GDK_BUTTON1_MOTION_MASK + GDK_BUTTON_PRESS_MASK | \ + GDK_BUTTON1_MOTION_MASK typedef struct { - gint xcenter, ycenter; - gint color[3]; - gint radius; - gint nspoke; + gint xcenter, ycenter; + gint color[3]; + gint radius; + gint nspoke; + gint randomhue; } NovaValues; typedef struct { @@ -102,89 +111,103 @@ typedef struct { } NovaInterface; typedef struct { - GtkObject *adjustment; - GtkWidget *entry; - gint constraint; + GtkObject *adjustment; + GtkWidget *entry; + gint constraint; } NovaEntryScaleData; typedef struct { - GDrawable *drawable; - gint dwidth, dheight; - gint bpp; - GtkWidget *xentry, *yentry; - GtkWidget *preview; - gint pwidth, pheight; - gint cursor; - gint curx, cury; /* x,y of cursor in preview */ - gint oldx, oldy; - gint in_call; + GDrawable *drawable; + gint dwidth, dheight; + gint bpp; + GtkWidget *xentry, *yentry; + GtkWidget *preview; + gint pwidth, pheight; + gint cursor; + gint curx, cury; /* x,y of cursor in preview */ + gint oldx, oldy; + gint in_call; } NovaCenter; /* Declare a local function. */ -static void query (void); -static void run (gchar *name, - gint nparams, - GParam *param, - gint *nreturn_vals, - GParam **return_vals); +static void query (void); +static void run (gchar *name, + gint nparams, + GParam *param, + gint *nreturn_vals, + GParam **return_vals); -static gint nova_dialog ( GDrawable *drawable ); +static gint nova_dialog ( GDrawable *drawable ); static GtkWidget * nova_center_create ( GDrawable *drawable ); -static void nova_center_destroy ( GtkWidget *widget, - gpointer data ); -static void nova_center_preview_init ( NovaCenter *center ); -static void nova_center_draw ( NovaCenter *center, gint update ); -static void nova_center_entry_update ( GtkWidget *widget, - gpointer data ); -static void nova_center_cursor_update ( NovaCenter *center ); -static gint nova_center_preview_expose ( GtkWidget *widget, - GdkEvent *event ); -static gint nova_center_preview_events ( GtkWidget *widget, - GdkEvent *event ); +static void nova_center_destroy ( GtkWidget *widget, + gpointer data ); +static void nova_center_preview_init ( NovaCenter *center ); +static void nova_center_draw ( NovaCenter *center, gint update ); +static void nova_center_entry_update ( GtkWidget *widget, + gpointer data ); +static void nova_center_cursor_update ( NovaCenter *center ); +static gint nova_center_preview_expose ( GtkWidget *widget, + GdkEvent *event ); +static gint nova_center_preview_events ( GtkWidget *widget, + GdkEvent *event ); -static void nova_int_entryscale_new ( GtkTable *table, gint x, gint y, - gchar *caption, gint *intvar, - gint min, gint max, gint constraint); +static void nova_int_entryscale_new ( GtkTable *table, gint x, gint y, + gchar *caption, gint *intvar, + gint min, gint max, gint constraint); -static void nova_close_callback (GtkWidget *widget, - gpointer data); -static void nova_ok_callback (GtkWidget *widget, - gpointer data); +static void nova_close_callback (GtkWidget *widget, + gpointer data); +static void nova_ok_callback (GtkWidget *widget, + gpointer data); -static void nova_paired_entry_destroy_callback (GtkWidget *widget, - gpointer data); +static void nova_paired_entry_destroy_callback (GtkWidget *widget, + gpointer data); -static void nova_paired_int_scale_update (GtkAdjustment *adjustment, - gpointer data); -static void nova_paired_int_entry_update (GtkWidget *widget, - gpointer data ); +static void nova_paired_int_scale_update (GtkAdjustment *adjustment, + gpointer data); +static void nova_paired_int_entry_update (GtkWidget *widget, + gpointer data ); -static void nova (GDrawable *drawable); +static void nova (GDrawable *drawable); + +static void rgb_to_hsl (gdouble r, + gdouble g, + gdouble b, + gdouble * h, + gdouble * s, + gdouble * l); +static void hsl_to_rgb (gdouble h, + gdouble sl, + gdouble l, + gdouble * r, + gdouble * g, + gdouble * b); GPlugInInfo PLUG_IN_INFO = { - NULL, /* init_proc */ - NULL, /* quit_proc */ + NULL, /* init_proc */ + NULL, /* quit_proc */ query, /* query_proc */ - run, /* run_proc */ + run, /* run_proc */ }; static NovaValues pvals = { - 128, 128, /* xcenter, ycenter */ - { 90, 100, 256 }, /* color */ - 20, /* radius */ - 100 /* nspoke */ + 128, 128, /* xcenter, ycenter */ + { 90, 100, 256 }, /* color */ + 20, /* radius */ + 100, /* nspoke */ + 0 /* random hue */ }; static NovaInterface pint = { - FALSE /* run */ + FALSE /* run */ }; @@ -200,9 +223,10 @@ query() { PARAM_DRAWABLE, "drawable", "Input drawable" }, { PARAM_INT32, "xcenter", "X coordinates of the center of supernova" }, { PARAM_INT32, "ycenter", "Y coordinates of the center of supernova" }, - { PARAM_COLOR, "color", "Color of supernova" }, - { PARAM_INT32, "radius", "Radius of supernova" }, - { PARAM_INT32, "nspoke", "Number of spokes" } + { PARAM_COLOR, "color", "Color of supernova" }, + { PARAM_INT32, "radius", "Radius of supernova" }, + { PARAM_INT32, "nspoke", "Number of spokes" }, + { PARAM_INT32, "randomhue", "Random hue" } }; static GParamDef *return_vals = NULL; static gint nargs = sizeof (args) / sizeof (args[0]); @@ -214,16 +238,16 @@ query() " RGB*, GRAY* image."; gimp_install_procedure ("plug_in_nova", - "Produce Supernova effect to the specified drawable", - help_string, - "Eiichi Takamori", - "Eiichi Takamori", - "1997", - "/Filters/Light Effects/SuperNova", - "RGB*, GRAY*", - PROC_PLUG_IN, - nargs, nreturn_vals, - args, return_vals); + "Produce Supernova effect to the specified drawable", + help_string, + "Eiichi Takamori", + "Eiichi Takamori", + "1997", + "/Filters/Light Effects/SuperNova", + "RGB*, GRAY*", + PROC_PLUG_IN, + nargs, nreturn_vals, + args, return_vals); } static void @@ -257,29 +281,30 @@ run (gchar *name, /* First acquire information with a dialog */ if (! nova_dialog ( drawable )) - { - gimp_drawable_detach (drawable); - return; - } + { + gimp_drawable_detach (drawable); + return; + } break; case RUN_NONINTERACTIVE: /* Make sure all the arguments are there! */ - if (nparams != 8) - status = STATUS_CALLING_ERROR; + if (nparams != 9) + status = STATUS_CALLING_ERROR; if (status == STATUS_SUCCESS) - { - pvals.xcenter = param[3].data.d_int32; - pvals.ycenter = param[4].data.d_int32; - pvals.color[0] = param[5].data.d_color.red; - pvals.color[1] = param[5].data.d_color.green; - pvals.color[2] = param[5].data.d_color.blue; - pvals.radius = param[6].data.d_int32; - pvals.nspoke = param[7].data.d_int32; - } + { + pvals.xcenter = param[3].data.d_int32; + pvals.ycenter = param[4].data.d_int32; + pvals.color[0] = param[5].data.d_color.red; + pvals.color[1] = param[5].data.d_color.green; + pvals.color[2] = param[5].data.d_color.blue; + pvals.radius = param[6].data.d_int32; + pvals.nspoke = param[7].data.d_int32; + pvals.randomhue = param[8].data.d_int32; + } if ((status == STATUS_SUCCESS) && - pvals.radius <= 0 ) - status = STATUS_CALLING_ERROR; + pvals.radius <= 0 ) + status = STATUS_CALLING_ERROR; break; case RUN_WITH_LAST_VALS: @@ -295,24 +320,24 @@ run (gchar *name, { /* Make sure that the drawable is gray or RGB color */ if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id)) - { - gimp_progress_init ("Rendering..."); - gimp_tile_cache_ntiles (TILE_CACHE_SIZE); + { + gimp_progress_init ("Rendering..."); + gimp_tile_cache_ntiles (TILE_CACHE_SIZE); - nova (drawable); + nova (drawable); - if (run_mode != RUN_NONINTERACTIVE) - gimp_displays_flush (); + if (run_mode != RUN_NONINTERACTIVE) + gimp_displays_flush (); - /* Store data */ - if (run_mode == RUN_INTERACTIVE) - gimp_set_data ("plug_in_nova", &pvals, sizeof (NovaValues)); - } + /* Store data */ + if (run_mode == RUN_INTERACTIVE) + gimp_set_data ("plug_in_nova", &pvals, sizeof (NovaValues)); + } else - { - /* gimp_message ("nova: cannot operate on indexed color images"); */ - status = STATUS_EXECUTION_ERROR; - } + { + /* gimp_message ("nova: cannot operate on indexed color images"); */ + status = STATUS_EXECUTION_ERROR; + } } values[0].data.d_status = status; @@ -322,9 +347,9 @@ run (gchar *name, /*******************/ -/* */ +/* */ /* Main Dialog */ -/* */ +/* */ /*******************/ static gint @@ -337,7 +362,7 @@ nova_dialog ( GDrawable *drawable ) GtkWidget *center_frame; guchar *color_cube; gchar **argv; - gint argc; + gint argc; argc = 1; argv = g_new (gchar *, 1); @@ -351,7 +376,7 @@ nova_dialog ( GDrawable *drawable ) gtk_preview_set_install_cmap (gimp_install_cmap ()); color_cube = gimp_color_cube (); gtk_preview_set_color_cube (color_cube[0], color_cube[1], - color_cube[2], color_cube[3]); + color_cube[2], color_cube[3]); gtk_widget_set_default_visual (gtk_preview_get_visual ()); gtk_widget_set_default_colormap (gtk_preview_get_cmap ()); @@ -365,15 +390,15 @@ nova_dialog ( GDrawable *drawable ) gtk_window_set_title (GTK_WINDOW (dlg), "SuperNova"); gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE); gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - (GtkSignalFunc) nova_close_callback, - NULL); + (GtkSignalFunc) nova_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) nova_ok_callback, - dlg); + (GtkSignalFunc) nova_ok_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); @@ -381,8 +406,8 @@ nova_dialog ( GDrawable *drawable ) 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)); + (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); @@ -392,7 +417,7 @@ nova_dialog ( GDrawable *drawable ) 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 (6, 2, FALSE); + table = gtk_table_new (7, 2, FALSE); gtk_container_border_width (GTK_CONTAINER (table), 10); gtk_container_add (GTK_CONTAINER (frame), table); gtk_table_set_row_spacings (GTK_TABLE (table), 3); @@ -400,22 +425,25 @@ nova_dialog ( GDrawable *drawable ) center_frame = nova_center_create ( drawable ); gtk_table_attach( GTK_TABLE(table), center_frame, 0, 2, 0, 1, - 0, 0, 0, 0 ); + 0, 0, 0, 0 ); nova_int_entryscale_new( GTK_TABLE (table), 0, 1, - "R value:", &pvals.color[0], - 0, 255, TRUE ); + "R value:", &pvals.color[0], + 0, 255, TRUE ); nova_int_entryscale_new( GTK_TABLE (table), 0, 2, - "G value:", &pvals.color[1], - 0, 255, TRUE ); + "G value:", &pvals.color[1], + 0, 255, TRUE ); nova_int_entryscale_new( GTK_TABLE (table), 0, 3, - "B value:", &pvals.color[2], - 0, 255, TRUE ); + "B value:", &pvals.color[2], + 0, 255, TRUE ); nova_int_entryscale_new( GTK_TABLE (table), 0, 4, - "Radius:", &pvals.radius, - 1, 100, FALSE ); + "Radius:", &pvals.radius, + 1, 100, FALSE ); nova_int_entryscale_new( GTK_TABLE (table), 0, 5, - "Spokes:", &pvals.nspoke, - 1, 1024, TRUE ); + "Spokes:", &pvals.nspoke, + 1, 1024, TRUE ); + nova_int_entryscale_new( GTK_TABLE (table), 0, 6, + "Random hue:", &pvals.randomhue, + 0, 360, TRUE ); gtk_widget_show (frame); gtk_widget_show (table); @@ -431,14 +459,14 @@ nova_dialog ( GDrawable *drawable ) static void nova_close_callback (GtkWidget *widget, - gpointer data) + gpointer data) { gtk_main_quit (); } static void nova_ok_callback (GtkWidget *widget, - gpointer data) + gpointer data) { pint.run = TRUE; gtk_widget_destroy (GTK_WIDGET (data)); @@ -462,20 +490,20 @@ nova_ok_callback (GtkWidget *widget, static GtkWidget * nova_center_create ( GDrawable *drawable ) { - NovaCenter *center; - GtkWidget *frame; - GtkWidget *table; - GtkWidget *label; - GtkWidget *entry; - GtkWidget *pframe; - GtkWidget *preview; - gchar buf[256]; + NovaCenter *center; + GtkWidget *frame; + GtkWidget *table; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *pframe; + GtkWidget *preview; + gchar buf[256]; center = g_new( NovaCenter, 1 ); center->drawable = drawable; center->dwidth = gimp_drawable_width(drawable->id ); center->dheight = gimp_drawable_height(drawable->id ); - center->bpp = gimp_drawable_bpp(drawable->id); + center->bpp = gimp_drawable_bpp(drawable->id); if ( gimp_drawable_has_alpha(drawable->id) ) center->bpp--; center->cursor = FALSE; @@ -487,8 +515,8 @@ nova_center_create ( GDrawable *drawable ) frame = gtk_frame_new ( "Center of SuperNova" ); gtk_signal_connect( GTK_OBJECT( frame ), "destroy", - (GtkSignalFunc) nova_center_destroy, - center ); + (GtkSignalFunc) nova_center_destroy, + center ); gtk_frame_set_shadow_type( GTK_FRAME( frame ) ,GTK_SHADOW_ETCHED_IN ); gtk_container_border_width( GTK_CONTAINER( frame ), 10 ); @@ -500,14 +528,14 @@ nova_center_create ( GDrawable *drawable ) label = gtk_label_new ( "X: " ); gtk_misc_set_alignment( GTK_MISC(label), 0.0, 0.5 ); - gtk_table_attach( GTK_TABLE(table), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0 ); + gtk_table_attach( GTK_TABLE(table), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(label); center->xentry = entry = gtk_entry_new (); gtk_object_set_user_data( GTK_OBJECT(entry), center ); gtk_signal_connect( GTK_OBJECT(entry), "changed", - (GtkSignalFunc) nova_center_entry_update, - &pvals.xcenter ); + (GtkSignalFunc) nova_center_entry_update, + &pvals.xcenter ); gtk_widget_set_usize( GTK_WIDGET(entry), ENTRY_WIDTH,0 ); gtk_table_attach( GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0 ); gtk_widget_show(entry); @@ -520,10 +548,10 @@ nova_center_create ( GDrawable *drawable ) center->yentry = entry = gtk_entry_new (); gtk_object_set_user_data( GTK_OBJECT(entry), center ); gtk_signal_connect( GTK_OBJECT(entry), "changed", - (GtkSignalFunc) nova_center_entry_update, - &pvals.ycenter ); + (GtkSignalFunc) nova_center_entry_update, + &pvals.ycenter ); gtk_widget_set_usize( GTK_WIDGET(entry), ENTRY_WIDTH, 0 ); - gtk_table_attach( GTK_TABLE(table), entry, 3, 4, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0 ); + gtk_table_attach( GTK_TABLE(table), entry, 3, 4, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(entry); /* frame (shadow_in) that contains preview */ @@ -536,11 +564,11 @@ nova_center_create ( GDrawable *drawable ) gtk_object_set_user_data( GTK_OBJECT(preview), center ); gtk_widget_set_events( GTK_WIDGET(preview), PREVIEW_MASK ); gtk_signal_connect_after( GTK_OBJECT(preview), "expose_event", - (GtkSignalFunc) nova_center_preview_expose, - center ); + (GtkSignalFunc) nova_center_preview_expose, + center ); gtk_signal_connect( GTK_OBJECT(preview), "event", - (GtkSignalFunc) nova_center_preview_events, - center ); + (GtkSignalFunc) nova_center_preview_events, + center ); gtk_container_add( GTK_CONTAINER( pframe ), center->preview ); /* @@ -579,7 +607,7 @@ nova_center_create ( GDrawable *drawable ) static void nova_center_destroy ( GtkWidget *widget, - gpointer data ) + gpointer data ) { NovaCenter *center = data; g_free( center ); @@ -594,9 +622,9 @@ static void render_preview ( GtkWidget *preview, GPixelRgn *srcrgn ); static void nova_center_preview_init ( NovaCenter *center ) { - GtkWidget *preview; - GPixelRgn src_rgn; - gint dwidth, dheight, pwidth, pheight, bpp; + GtkWidget *preview; + GPixelRgn src_rgn; + gint dwidth, dheight, pwidth, pheight, bpp; preview = center->preview; dwidth = center->dwidth; @@ -606,31 +634,31 @@ nova_center_preview_init ( NovaCenter *center ) bpp = center->bpp; gimp_pixel_rgn_init ( &src_rgn, center->drawable, 0, 0, - center->dwidth, center->dheight, FALSE, FALSE ); + center->dwidth, center->dheight, FALSE, FALSE ); render_preview( center->preview, &src_rgn ); } /*====================================================================== - Preview Rendering Util routine + Preview Rendering Util routine =======================================================================*/ #define CHECKWIDTH 4 #define LIGHTCHECK 192 #define DARKCHECK 128 #ifndef OPAQUE -#define OPAQUE 255 +#define OPAQUE 255 #endif static void render_preview ( GtkWidget *preview, GPixelRgn *srcrgn ) { - guchar *src_row, *dest_row, *src, *dest; - gint row, col; - gint dwidth, dheight, pwidth, pheight; - gint *src_col; - gint bpp, alpha, has_alpha, b; - guchar check; + guchar *src_row, *dest_row, *src, *dest; + gint row, col; + gint dwidth, dheight, pwidth, pheight; + gint *src_col; + gint bpp, alpha, has_alpha, b; + guchar check; dwidth = srcrgn->w; dheight = srcrgn->h; @@ -662,43 +690,43 @@ render_preview ( GtkWidget *preview, GPixelRgn *srcrgn ) for ( row = 0; row < pheight; row++ ) { gimp_pixel_rgn_get_row ( srcrgn, src_row, - 0, row * dheight / pheight, dwidth ); + 0, row * dheight / pheight, dwidth ); dest = dest_row; for ( col = 0; col < pwidth; col++ ) - { - src = &src_row[ src_col[col] ]; - if( !has_alpha || src[alpha] == OPAQUE ) - { - /* no alpha channel or opaque -- simple way */ - for ( b = 0; b < alpha; b++ ) - dest[b] = src[b]; - } - else - { - /* more or less transparent */ - if( ( col % (CHECKWIDTH*2) < CHECKWIDTH ) ^ - ( row % (CHECKWIDTH*2) < CHECKWIDTH ) ) - check = LIGHTCHECK; - else - check = DARKCHECK; + { + src = &src_row[ src_col[col] ]; + if( !has_alpha || src[alpha] == OPAQUE ) + { + /* no alpha channel or opaque -- simple way */ + for ( b = 0; b < alpha; b++ ) + dest[b] = src[b]; + } + else + { + /* more or less transparent */ + if( ( col % (CHECKWIDTH*2) < CHECKWIDTH ) ^ + ( row % (CHECKWIDTH*2) < CHECKWIDTH ) ) + check = LIGHTCHECK; + else + check = DARKCHECK; - if ( src[alpha] == 0 ) - { - /* full transparent -- check */ - for ( b = 0; b < alpha; b++ ) - dest[b] = check; - } - else - { - /* middlemost transparent -- mix check and src */ - for ( b = 0; b < alpha; b++ ) - dest[b] = ( src[b]*src[alpha] + check*(OPAQUE-src[alpha]) ) / OPAQUE; - } - } - dest += alpha; - } + if ( src[alpha] == 0 ) + { + /* full transparent -- check */ + for ( b = 0; b < alpha; b++ ) + dest[b] = check; + } + else + { + /* middlemost transparent -- mix check and src */ + for ( b = 0; b < alpha; b++ ) + dest[b] = ( src[b]*src[alpha] + check*(OPAQUE-src[alpha]) ) / OPAQUE; + } + } + dest += alpha; + } gtk_preview_draw_row( GTK_PREVIEW( preview ), dest_row, - 0, row, pwidth ); + 0, row, pwidth ); } g_free ( src_col ); @@ -707,7 +735,7 @@ render_preview ( GtkWidget *preview, GPixelRgn *srcrgn ) } /*====================================================================== - Preview Rendering Util routine End + Preview Rendering Util routine End =======================================================================*/ /* @@ -728,23 +756,23 @@ nova_center_draw ( NovaCenter *center, gint update ) if( update & CURSOR ) { DEBUG1("draw-cursor %d old=%d,%d cur=%d,%d\n", - center->cursor, center->oldx, center->oldy, center->curx, center->cury); + center->cursor, center->oldx, center->oldy, center->curx, center->cury); gdk_gc_set_function ( center->preview->style->black_gc, GDK_INVERT); if( center->cursor ) - { - gdk_draw_line ( center->preview->window, - center->preview->style->black_gc, - center->oldx, 1, center->oldx, center->pheight-1 ); - gdk_draw_line ( center->preview->window, - center->preview->style->black_gc, - 1, center->oldy, center->pwidth-1, center->oldy ); - } + { + gdk_draw_line ( center->preview->window, + center->preview->style->black_gc, + center->oldx, 1, center->oldx, center->pheight-1 ); + gdk_draw_line ( center->preview->window, + center->preview->style->black_gc, + 1, center->oldy, center->pwidth-1, center->oldy ); + } gdk_draw_line ( center->preview->window, - center->preview->style->black_gc, - center->curx, 1, center->curx, center->pheight-1 ); + center->preview->style->black_gc, + center->curx, 1, center->curx, center->pheight-1 ); gdk_draw_line ( center->preview->window, - center->preview->style->black_gc, - 1, center->cury, center->pwidth-1, center->cury ); + center->preview->style->black_gc, + 1, center->cury, center->pwidth-1, center->cury ); /* current position of cursor is updated */ center->oldx = center->curx; center->oldy = center->cury; @@ -760,7 +788,7 @@ nova_center_draw ( NovaCenter *center, gint update ) static void nova_center_entry_update ( GtkWidget *widget, - gpointer data ) + gpointer data ) { NovaCenter *center; gint *val, new_val; @@ -775,10 +803,10 @@ nova_center_entry_update ( GtkWidget *widget, center = gtk_object_get_user_data( GTK_OBJECT(widget) ); DEBUG1("entry:newval in_call=%d\n", center->in_call ); if( !center->in_call ) - { - nova_center_cursor_update( center ); - nova_center_draw ( center, CURSOR ); - } + { + nova_center_cursor_update( center ); + nova_center_draw ( center, CURSOR ); + } } } @@ -793,9 +821,9 @@ nova_center_cursor_update ( NovaCenter *center ) center->curx = pvals.xcenter * center->pwidth / center->dwidth; center->cury = pvals.ycenter * center->pheight / center->dheight; - if( center->curx < 0 ) center->curx = 0; + if( center->curx < 0 ) center->curx = 0; else if( center->curx >= center->pwidth ) center->curx = center->pwidth-1; - if( center->cury < 0 ) center->cury = 0; + if( center->cury < 0 ) center->cury = 0; else if( center->cury >= center->pheight) center->cury = center->pheight-1; } @@ -805,7 +833,7 @@ nova_center_cursor_update ( NovaCenter *center ) */ static gint nova_center_preview_expose( GtkWidget *widget, - GdkEvent *event ) + GdkEvent *event ) { NovaCenter *center; @@ -821,7 +849,7 @@ nova_center_preview_expose( GtkWidget *widget, static gint nova_center_preview_events ( GtkWidget *widget, - GdkEvent *event ) + GdkEvent *event ) { NovaCenter *center; GdkEventButton *bevent; @@ -865,31 +893,31 @@ nova_center_preview_events ( GtkWidget *widget, /*=================================================================== - Entry - Scale Pair + Entry - Scale Pair ====================================================================*/ /***********************************************************************/ -/* */ -/* Create new entry-scale pair with label. (int) */ -/* 1 row and 2 cols of table are needed. */ -/* */ -/* `x' and `y' means starting row and col in `table'. */ -/* */ -/* `caption' is label string. */ -/* */ -/* `min', `max' are boundary of scale. */ -/* */ +/* */ +/* Create new entry-scale pair with label. (int) */ +/* 1 row and 2 cols of table are needed. */ +/* */ +/* `x' and `y' means starting row and col in `table'. */ +/* */ +/* `caption' is label string. */ +/* */ +/* `min', `max' are boundary of scale. */ +/* */ /* `constraint' means whether value of *intvar should be constraint */ -/* by scale adjustment, e.g. between `min' and `max'. */ -/* */ +/* by scale adjustment, e.g. between `min' and `max'. */ +/* */ /***********************************************************************/ static void nova_int_entryscale_new ( GtkTable *table, gint x, gint y, - gchar *caption, gint *intvar, - gint min, gint max, gint constraint) + gchar *caption, gint *intvar, + gint min, gint max, gint constraint) { GtkWidget *hbox; GtkWidget *label; @@ -897,7 +925,7 @@ nova_int_entryscale_new ( GtkTable *table, gint x, gint y, GtkWidget *scale; GtkObject *adjustment; NovaEntryScaleData *userdata; - gchar buffer[256]; + gchar buffer[256]; label = gtk_label_new (caption); @@ -922,14 +950,14 @@ nova_int_entryscale_new ( GtkTable *table, gint x, gint y, gtk_object_set_user_data (GTK_OBJECT(adjustment), userdata); gtk_signal_connect (GTK_OBJECT (entry), "changed", - (GtkSignalFunc) nova_paired_int_entry_update, - intvar); + (GtkSignalFunc) nova_paired_int_entry_update, + intvar); gtk_signal_connect ( adjustment, "value_changed", - (GtkSignalFunc) nova_paired_int_scale_update, - intvar); + (GtkSignalFunc) nova_paired_int_scale_update, + intvar); gtk_signal_connect ( GTK_OBJECT( entry ), "destroy", - (GtkSignalFunc) nova_paired_entry_destroy_callback, - userdata ); + (GtkSignalFunc) nova_paired_entry_destroy_callback, + userdata ); hbox = gtk_hbox_new ( FALSE, 5 ); @@ -937,9 +965,9 @@ nova_int_entryscale_new ( GtkTable *table, gint x, gint y, gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, TRUE, 0); gtk_table_attach (GTK_TABLE (table), label, x, x+1, y, y+1, - GTK_FILL, GTK_FILL, 0, 0); + GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach (GTK_TABLE (table), hbox, x+1, x+2, y, y+1, - GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); gtk_widget_show (label); gtk_widget_show (entry); @@ -953,7 +981,7 @@ nova_int_entryscale_new ( GtkTable *table, gint x, gint y, */ static void nova_paired_entry_destroy_callback (GtkWidget *widget, - gpointer data) + gpointer data) { NovaEntryScaleData *userdata; userdata = data; @@ -965,7 +993,7 @@ nova_paired_entry_destroy_callback (GtkWidget *widget, static void nova_paired_int_scale_update (GtkAdjustment *adjustment, - gpointer data) + gpointer data) { NovaEntryScaleData *userdata; GtkEntry *entry; @@ -993,186 +1021,302 @@ nova_paired_int_scale_update (GtkAdjustment *adjustment, static void nova_paired_int_entry_update (GtkWidget *widget, - gpointer data) -{ - NovaEntryScaleData *userdata; - GtkAdjustment *adjustment; - int new_val, constraint_val; - int *val; + gpointer data) + { + NovaEntryScaleData *userdata; + GtkAdjustment *adjustment; + int new_val, constraint_val; + int *val; + + val = data; + new_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget))); + *val = new_val; + + userdata = gtk_object_get_user_data (GTK_OBJECT (widget)); + adjustment = GTK_ADJUSTMENT( userdata->adjustment ); + + constraint_val = new_val; + if ( constraint_val < adjustment->lower ) + constraint_val = adjustment->lower; + if ( constraint_val > adjustment->upper ) + constraint_val = adjustment->upper; + + if ( userdata->constraint ) + *val = constraint_val; + else + *val = new_val; + + adjustment->value = constraint_val; + 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 ); + + } + + /* + ################################################################ + ## ## + ## Main Calculation ## + ## ## + ################################################################ + */ + + + static double gauss() + { + double sum=0; + int i; + for(i=0; i<6; i++) + sum+=(double)rand()/RAND_MAX; + return sum/6; + } + + static void + nova (GDrawable *drawable) + { + GPixelRgn src_rgn, dest_rgn; + gpointer pr; + guchar *src_row, *dest_row; + guchar *src, *dest; + gint x1, y1, x2, y2; + gint row, col; + gint x, y; + gint alpha, has_alpha, bpp; + gint progress, max_progress; + /****************/ + gint xc, yc; /* center of image */ + gdouble u, v; + gdouble l, l0; + gdouble w, w1, c; + gdouble *spoke; + gdouble nova_alpha; + gdouble src_alpha; + gdouble new_alpha; + gdouble compl_ratio; + gdouble ratio; + gdouble r, g, b, h, s, lu; + gdouble spokecol; + gint i, j; + gint color[4]; + gint *spokecolor; + + /* initialize */ + + new_alpha = 0.0; + + srand(time(NULL)); + spoke = g_new( gdouble, pvals.nspoke ); + spokecolor = g_new (gint, 3 * pvals.nspoke); - val = data; - new_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget))); - *val = new_val; + rgb_to_hsl (pvals.color[0]/255.0, pvals.color[1]/255.0, pvals.color[2]/255.0, &h, &s, &lu); - userdata = gtk_object_get_user_data (GTK_OBJECT (widget)); - adjustment = GTK_ADJUSTMENT( userdata->adjustment ); - - constraint_val = new_val; - if ( constraint_val < adjustment->lower ) - constraint_val = adjustment->lower; - if ( constraint_val > adjustment->upper ) - constraint_val = adjustment->upper; - - if ( userdata->constraint ) - *val = constraint_val; - else - *val = new_val; - - adjustment->value = constraint_val; - 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 ); - -} - -/* -################################################################ -## ## -## Main Calculation ## -## ## -################################################################ -*/ - - -static double gauss() -{ - double sum=0; - int i; - for(i=0; i<6; i++) - sum+=(double)rand()/RAND_MAX; - return sum/6; -} - -static void -nova (GDrawable *drawable) -{ - GPixelRgn src_rgn, dest_rgn; - gpointer pr; - guchar *src_row, *dest_row; - guchar *src, *dest; - gint x1, y1, x2, y2; - gint row, col; - gint x, y; - gint alpha, has_alpha, bpp; - gint progress, max_progress; - /****************/ - gint xc, yc; /* center of image */ - gdouble u, v; - gdouble l, l0; - gdouble w, w1, c; - gdouble *spoke; - gdouble nova_alpha; - gdouble src_alpha; - gdouble new_alpha; - gdouble compl_ratio; - gdouble ratio; - gint i; - gint color[4]; - - /* initialize */ - - new_alpha = 0.0; - - srand(time(NULL)); - spoke = g_new( gdouble, pvals.nspoke ); - for( i=0; iid, &x1, &y1, &x2, &y2); - - /* - xc = (x1+x2)/2; - yc = (y1+y2)/2; */ - xc = pvals.xcenter; - yc = pvals.ycenter; - l0 = (x2-xc)/4+1; /* standard length */ - - bpp = gimp_drawable_bpp (drawable->id); - has_alpha = gimp_drawable_has_alpha (drawable->id); - alpha = (has_alpha) ? bpp - 1 : bpp; - - gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, x2-x1, y2-y1, FALSE, FALSE); - gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, x2-x1, y2-y1, TRUE, TRUE); - - /* Initialize progress */ - progress = 0; - max_progress = (x2 - x1) * (y2 - y1); - - for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); - pr != NULL; pr = gimp_pixel_rgns_process (pr)) + for( i=0; i= 1.0) h -= 1.0; + hsl_to_rgb (h, s, lu, &r, &g, &b); + spokecolor[3*i+0] = 255.0 * r; + spokecolor[3*i+1] = 255.0 * g; + spokecolor[3*i+2] = 255.0 * b; + } + + gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); + + /* + xc = (x1+x2)/2; + yc = (y1+y2)/2; */ + xc = pvals.xcenter; + yc = pvals.ycenter; + l0 = (x2-xc)/4+1; /* standard length */ + + bpp = gimp_drawable_bpp (drawable->id); + has_alpha = gimp_drawable_has_alpha (drawable->id); + alpha = (has_alpha) ? bpp - 1 : bpp; + + gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, x2-x1, y2-y1, FALSE, FALSE); + gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, x2-x1, y2-y1, TRUE, TRUE); + + /* Initialize progress */ + progress = 0; + max_progress = (x2 - x1) * (y2 - y1); + + for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); + pr != NULL; pr = gimp_pixel_rgns_process (pr)) + { + src_row = src_rgn.data; + dest_row = dest_rgn.data; + + for ( row = 0, y = src_rgn.y; row < src_rgn.h; row++, y++) + { + src = src_row; + dest = dest_row; + + for ( col = 0, x = src_rgn.x; col < src_rgn.w; col++, x++) + { + u = (gdouble) (x-xc) / pvals.radius; + v = (gdouble) (y-yc) / pvals.radius; + l = sqrt( u*u + v*v ); + + /* This algorithm is still under construction. */ + c = (atan2 (u, v) / (2 * M_PI) + .51) * pvals.nspoke; + i = (int) floor (c); + c -= i; + i %= pvals.nspoke; + w1 = spoke[i] * (1 - c) + spoke[(i + 1) % pvals.nspoke] * c; + w1 = w1 * w1; + + w = 1/(l+0.001)*0.9; + + nova_alpha = CLAMP (w, 0.0, 1.0); + + if (has_alpha) + { + src_alpha = (gdouble) src[alpha] / 255.0; + new_alpha = src_alpha + (1.0 - src_alpha) * nova_alpha; + + if (new_alpha != 0.0) + ratio = nova_alpha / new_alpha; + else + ratio = 0.0; + } + else + ratio = nova_alpha; + + compl_ratio = 1.0 - ratio; + + for (j = 0; j < alpha; j++) + { + spokecol = (gdouble)spokecolor[3*i+j]*(1.0-c) + (gdouble)spokecolor[3*((i + 1) % pvals.nspoke)+j]*c; + if (w > 1.0) + color[j] = CLAMP (spokecol * w, 0, 255); + else + color[j] = src[j] * compl_ratio + spokecol * ratio; + + c = CLAMP (w1 * w, 0, 1); + color[j] = color[j] + 255 * c; + + dest[j]= CLAMP (color[j], 0, 255); + } + + if (has_alpha) + dest[alpha] = new_alpha * 255.0; + + src += src_rgn.bpp; + dest += dest_rgn.bpp; + } + src_row += src_rgn.rowstride; + dest_row += dest_rgn.rowstride; + } + /* Update progress */ + progress += src_rgn.w * src_rgn.h; + gimp_progress_update ((double) progress / (double) max_progress); + } + + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->id, TRUE); + gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1)); + + g_free( spoke ); + g_free( spokecolor ); + } + + /* + * RGB-HSL transforms. + * Ken Fishkin, Pixar Inc., January 1989. + */ - for ( row = 0, y = src_rgn.y; row < src_rgn.h; row++, y++) - { - src = src_row; - dest = dest_row; + /* + * given r,g,b on [0 ... 1], + * return (h,s,l) on [0 ... 1] + */ - for ( col = 0, x = src_rgn.x; col < src_rgn.w; col++, x++) - { - u = (gdouble) (x-xc) / pvals.radius; - v = (gdouble) (y-yc) / pvals.radius; - l = sqrt( u*u + v*v ); + static void + rgb_to_hsl (gdouble r, + gdouble g, + gdouble b, + gdouble *h, + gdouble *s, + gdouble *l) + { + gdouble v; + gdouble m; + gdouble vm; + gdouble r2, g2, b2; - /* This algorithm is still under construction. */ - c = (atan2 (u, v) / (2 * G_PI) + .51) * pvals.nspoke; - i = (int) floor (c); - c -= i; - i %= pvals.nspoke; - w1 = spoke[i] * (1 - c) + spoke[(i + 1) % pvals.nspoke] * c; - w1 = w1 * w1; + v = MAX(r,g); + v = MAX(v,b); + m = MIN(r,g); + m = MIN(m,b); - w = 1/(l+0.001)*0.9; + if ((*l = (m + v) / 2.0) <= 0.0) + return; + if ((*s = vm = v - m) > 0.0) + { + *s /= (*l <= 0.5) ? (v + m ) : (2.0 - v - m) ; + } + else + return; - nova_alpha = CLAMP (w, 0.0, 1.0); + r2 = (v - r) / vm; + g2 = (v - g) / vm; + b2 = (v - b) / vm; - if (has_alpha) - { - src_alpha = (gdouble) src[alpha] / 255.0; - new_alpha = src_alpha + (1.0 - src_alpha) * nova_alpha; + if (r == v) + *h = (g == m ? 5.0 + b2 : 1.0 - g2); + else if (g == v) + *h = (b == m ? 1.0 + r2 : 3.0 - b2); + else + *h = (r == m ? 3.0 + g2 : 5.0 - r2); - if (new_alpha != 0.0) - ratio = nova_alpha / new_alpha; - else - ratio = 0.0; - } - else - ratio = nova_alpha; + *h /= 6; + } - compl_ratio = 1.0 - ratio; + /* + * given h,s,l on [0..1], + * return r,g,b on [0..1] + */ - for (i = 0; i < alpha; i++) - { - if (w > 1.0) - color[i] = CLAMP (pvals.color[i] * w, 0, 255); - else - color[i] = src[i] * compl_ratio + pvals.color[i] * ratio; + static void + hsl_to_rgb (gdouble h, + gdouble sl, + gdouble l, + gdouble *r, + gdouble *g, + gdouble *b) + { + gdouble v; - c = CLAMP (w1 * w, 0, 1); - color[i] = color[i] + 255 * c; - - dest[i]= CLAMP (color[i], 0, 255); - } - - if (has_alpha) - dest[alpha] = new_alpha * 255.0; - - src += src_rgn.bpp; - dest += dest_rgn.bpp; - } - src_row += src_rgn.rowstride; - dest_row += dest_rgn.rowstride; - } - /* Update progress */ - progress += src_rgn.w * src_rgn.h; - gimp_progress_update ((double) progress / (double) max_progress); - } - - gimp_drawable_flush (drawable); - gimp_drawable_merge_shadow (drawable->id, TRUE); - gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1)); - - g_free( spoke ); -} + v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl); + if (v <= 0) + { + *r = *g = *b = 0.0; + } + else + { + gdouble m; + gdouble sv; + gint sextant; + gdouble fract, vsf, mid1, mid2; + m = l + l - v; + sv = (v - m ) / v; + h *= 6.0; + sextant = h; + fract = h - sextant; + vsf = v * sv * fract; + mid1 = m + vsf; + mid2 = v - vsf; + switch (sextant) + { + case 0: *r = v; *g = mid1; *b = m; break; + case 1: *r = mid2; *g = v; *b = m; break; + case 2: *r = m; *g = v; *b = mid1; break; + case 3: *r = m; *g = mid2; *b = v; break; + case 4: *r = mid1; *g = m; *b = v; break; + case 5: *r = v; *g = m; *b = mid2; break; + } + } + } + diff --git a/plug-ins/common/plugin-defs.pl b/plug-ins/common/plugin-defs.pl index 984d8baff1..2e21bca9f4 100644 --- a/plug-ins/common/plugin-defs.pl +++ b/plug-ins/common/plugin-defs.pl @@ -14,6 +14,7 @@ 'bz2' => { libdep => 'glib' }, 'c_astretch' => { libdep => 'glib' }, 'checkerboard' => { libdep => 'gtk' }, + 'color_enhance' => { libdep => 'gtk', ui => 1 }, 'colorify' => { libdep => 'gtk' }, 'compose' => { libdep => 'gtk', ui => 1 }, 'convmatrix' => { libdep => 'gtk' }, @@ -110,6 +111,7 @@ 'video' => { libdep => 'gtk' }, 'vinvert' => { libdep => 'glib' }, 'vpropagate' => { libdep => 'gtk' }, + 'warp' => { libdep => 'gtk', ui => 1 }, 'waves' => { libdep => 'gtk', libsupp => 'megawidget' }, 'whirlpinch' => { libdep => 'gtk' }, 'wind' => { libdep => 'gtk' }, diff --git a/plug-ins/common/sparkle.c b/plug-ins/common/sparkle.c index 6d855d1039..1023f9e30d 100644 --- a/plug-ins/common/sparkle.c +++ b/plug-ins/common/sparkle.c @@ -1,5 +1,7 @@ /* Sparkle --- image filter plug-in for The Gimp image manipulation program - * Copyright (C) 1996 by John Beale; ported to Gimp by Michael J. Hammel + * Copyright (C) 1996 by John Beale; ported to Gimp by Michael J. Hammel; + * It has been optimized a little, bugfixed and modified by Martin Weber + * for additional functionality. * * 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 @@ -16,28 +18,35 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * You can contact Michael at mjhammel@csn.net + * You can contact Martin at martin.weber@usa.net * Note: set tabstops to 3 to make this more readable. */ /* - * Sparkle - simulate pixel bloom and diffraction effects + * Sparkle 1.26 - simulate pixel bloom and diffraction effects */ -#include "config.h" #include #include #include - +#include #include "gtk/gtk.h" #include "libgimp/gimp.h" -#define SCALE_WIDTH 125 -#define TILE_CACHE_SIZE 16 +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /* M_PI */ + +#define SCALE_WIDTH 175 #define MAX_CHANNELS 4 #define PSV 2 /* point spread value */ #define EPSILON 0.001 #define SQR(a) ((a) * (a)) +#define NATURAL 0 +#define FOREGROUND 1 +#define BACKGROUND 2 + typedef struct { gdouble lum_threshold; @@ -45,6 +54,14 @@ typedef struct gdouble spike_len; gdouble spike_pts; gdouble spike_angle; + gdouble density; + gdouble opacity; + gdouble random_hue; + gdouble random_saturation; + gint preserve_luminosity; + gint invers; + gint border; + gint colortype; } SparkleVals; typedef struct @@ -54,15 +71,16 @@ typedef struct /* Declare local functions. */ + static void query (void); static void run (char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals); - +static void sparkle_toggle_update (GtkWidget *widget, + gpointer data); static gint sparkle_dialog (void); - static gint compute_luminosity (guchar * pixel, gint gray, gint has_alpha); @@ -70,7 +88,6 @@ static gint compute_lum_threshold (GDrawable * drawable, gdouble percentile); static void sparkle (GDrawable * drawable, gint threshold); - static void fspike (GPixelRgn * dest_rgn, gint gray, gint x1, @@ -79,6 +96,8 @@ static void fspike (GPixelRgn * dest_rgn, gint y2, gdouble xr, gdouble yr, + gint tile_width, + gint tile_height, gdouble inten, gdouble length, gdouble angle); @@ -90,10 +109,13 @@ static GTile* rpnt (GDrawable * drawable, gint y2, gdouble xr, gdouble yr, + gint tile_width, + gint tile_height, gint * row, gint * col, gint bytes, - gdouble * inten); + gdouble inten, + guchar color[MAX_CHANNELS]); static void rgb_to_hsl (gdouble r, gdouble g, gdouble b, @@ -106,13 +128,15 @@ static void hsl_to_rgb (gdouble h, gdouble * r, gdouble * g, gdouble * b); - -static void sparkle_close_callback (GtkWidget *widget, - gpointer data); -static void sparkle_ok_callback (GtkWidget *widget, - gpointer data); -static void sparkle_scale_update (GtkAdjustment *adjustment, - double *scale_val); +static void sparkle_close_callback(GtkWidget *widget, + gpointer data); +static void sparkle_ok_callback (GtkWidget *widget, + gpointer data); +static void sparkle_scale_update (GtkAdjustment *adjustment, + double *scale_val); +static void set_tooltip (GtkTooltips *tooltips, + GtkWidget *widget, + const char *desc); GPlugInInfo PLUG_IN_INFO = { @@ -125,10 +149,18 @@ GPlugInInfo PLUG_IN_INFO = static SparkleVals svals = { 0.001, /* luminosity threshold */ - 0.5, /* flare intensity */ - 20.0, /* spike length */ - 6.0, /* spike points */ - 15.0 /* spike angle */ + 0.5, /* flare intensity */ + 20.0, /* spike length */ + 4.0, /* spike points */ + 15.0, /* spike angle */ + 1.0, /* spike density */ + 1.0, /* opacity */ + 0.0, /* random hue */ + 0.0, /* random saturation */ + FALSE, /* preserve_luminosity */ + FALSE, /* invers */ + FALSE, /* border */ + NATURAL /* colortype */ }; static SparkleInterface sint = @@ -151,9 +183,17 @@ query () { PARAM_DRAWABLE, "drawable", "Input drawable" }, { PARAM_FLOAT, "lum_threshold", "Luminosity threshold (0.0 - 1.0)" }, { PARAM_FLOAT, "flare_inten", "Flare intensity (0.0 - 1.0)" }, - { PARAM_FLOAT, "spike_len", "Spike length (in pixels)" }, + { PARAM_INT32, "spike_len", "Spike length (in pixels)" }, { PARAM_INT32, "spike_pts", "# of spike points" }, - { PARAM_FLOAT, "spike_angle", "Spike angle (0.0-360.0 degrees)" } + { PARAM_INT32, "spike_angle", "Spike angle (0-360 degrees, -1: random)" }, + { PARAM_FLOAT, "density", "Spike density (0.0 - 1.0)" }, + { PARAM_FLOAT, "opacity", "Opacity (0.0 - 1.0)" }, + { PARAM_FLOAT, "random_hue", "Random hue (0.0 - 1.0)" }, + { PARAM_FLOAT, "random_saturation", "Random saturation (0.0 - 1.0)" }, + { PARAM_INT32, "preserve_luminosity", "Preserve luminosity (TRUE/FALSE)" }, + { PARAM_INT32, "invers", "Invers (TRUE/FALSE)" }, + { PARAM_INT32, "border", "Add border (TRUE/FALSE)" }, + { PARAM_INT32, "colortype", "Color of sparkles: { NATURAL (0), FOREGROUND (1), BACKGROUND (2) }" } }; static GParamDef *return_vals = NULL; static int nargs = sizeof (args) / sizeof (args[0]); @@ -161,10 +201,10 @@ query () gimp_install_procedure ("plug_in_sparkle", "Simulates pixel bloom and diffraction effects", - "More here later", - "John Beale, & (ported to GIMP v0.54) Michael J. Hammel & (ported to GIMP v1.0) Spencer Kimball", + "No help yet", + "John Beale, & (ported to GIMP v0.54) Michael J. Hammel & ted to GIMP v1.0) Spencer Kimball", "John Beale", - "1996", + "Version 1.26, December 1998", "/Filters/Light Effects/Sparkle", "RGB*, GRAY*", PROC_PLUG_IN, @@ -183,7 +223,7 @@ run (char *name, GDrawable *drawable; GRunModeType run_mode; GStatusType status = STATUS_SUCCESS; - gint threshold; + gint threshold, x1, y1, x2, y2; run_mode = param[0].data.d_int32; @@ -206,15 +246,23 @@ run (char *name, case RUN_NONINTERACTIVE: /* Make sure all the arguments are there! */ - if (nparams != 8) + if (nparams != 16) status = STATUS_CALLING_ERROR; if (status == STATUS_SUCCESS) { svals.lum_threshold = param[3].data.d_float; svals.flare_inten = param[4].data.d_float; - svals.spike_len = param[5].data.d_float; + svals.spike_len = param[5].data.d_int32; svals.spike_pts = param[6].data.d_int32; - svals.spike_angle = param[7].data.d_float; + svals.spike_angle = param[7].data.d_int32; + svals.density = param[8].data.d_float; + svals.opacity = param[9].data.d_float; + svals.random_hue = param[10].data.d_float; + svals.random_saturation = param[11].data.d_float; + svals.preserve_luminosity = (param[12].data.d_int32) ? TRUE : FALSE; + svals.invers = (param[13].data.d_int32) ? TRUE : FALSE; + svals.border = (param[14].data.d_int32) ? TRUE : FALSE; + svals.colortype = param[15].data.d_int32; } if (status == STATUS_SUCCESS && (svals.lum_threshold < 0.0 || svals.lum_threshold > 1.0)) @@ -222,12 +270,31 @@ run (char *name, if (status == STATUS_SUCCESS && (svals.flare_inten < 0.0 || svals.flare_inten > 1.0)) status = STATUS_CALLING_ERROR; + if (status == STATUS_SUCCESS && + (svals.spike_len < 0)) + status = STATUS_CALLING_ERROR; if (status == STATUS_SUCCESS && (svals.spike_pts < 0)) status = STATUS_CALLING_ERROR; if (status == STATUS_SUCCESS && - (svals.spike_angle < 0.0 || svals.spike_angle > 360.0)) + (svals.spike_angle < -1 || svals.spike_angle > 360)) status = STATUS_CALLING_ERROR; + if (status == STATUS_SUCCESS && + (svals.density < 0.0 || svals.density > 1.0)) + status = STATUS_CALLING_ERROR; + if (status == STATUS_SUCCESS && + (svals.opacity < 0.0 || svals.opacity > 1.0)) + status = STATUS_CALLING_ERROR; + if (status == STATUS_SUCCESS && + (svals.random_hue < 0.0 || svals.random_hue > 1.0)) + status = STATUS_CALLING_ERROR; + if (status == STATUS_SUCCESS && + (svals.random_saturation < 0.0 || svals.random_saturation > 1.0)) + status = STATUS_CALLING_ERROR; + if (status == STATUS_SUCCESS && + (svals.colortype < NATURAL || svals.colortype > BACKGROUND)) + status = STATUS_CALLING_ERROR; + break; case RUN_WITH_LAST_VALS: @@ -246,10 +313,18 @@ run (char *name, if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id)) { gimp_progress_init ("Sparkling..."); - gimp_tile_cache_ntiles (TILE_CACHE_SIZE); + gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); - /* compute the luminosity which exceeds the luminosity threshold */ - threshold = compute_lum_threshold (drawable, svals.lum_threshold); + if (svals.border == FALSE) + /* compute the luminosity which exceeds the luminosity threshold */ + threshold = compute_lum_threshold (drawable, svals.lum_threshold); + else + { + gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); + num_sparkles = 2 * (x2 - x1 + y2 - y1); + threshold = 255; + } + sparkle (drawable, threshold); if (run_mode != RUN_NONINTERACTIVE) @@ -261,7 +336,7 @@ run (char *name, } else { - /* gimp_message ("blur: cannot operate on indexed color images"); */ + /* gimp_message ("sparkle: cannot operate on indexed color images"); */ status = STATUS_EXECUTION_ERROR; } @@ -279,9 +354,16 @@ sparkle_dialog () GtkWidget *scale; GtkWidget *frame; GtkWidget *table; + GtkWidget *toggle; GtkObject *scale_data; + GSList *group = NULL; gchar **argv; gint argc; + gint use_natural = (svals.colortype == NATURAL); + gint use_foreground = (svals.colortype == FOREGROUND); + gint use_background = (svals.colortype == BACKGROUND); + GtkTooltips *tips; + GdkColor tips_fg, tips_bg; argc = 1; argv = g_new (gchar *, 1); @@ -290,6 +372,7 @@ sparkle_dialog () gtk_init (&argc, &argv); gtk_rc_parse (gimp_gtkrc ()); + dlg = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (dlg), "Sparkle"); gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE); @@ -297,6 +380,19 @@ sparkle_dialog () (GtkSignalFunc) sparkle_close_callback, NULL); + /* use black as foreground: */ + tips = gtk_tooltips_new (); + tips_fg.red = 0; + tips_fg.green = 0; + tips_fg.blue = 0; + /* postit yellow (khaki) as background: */ + 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 (tips,&tips_bg,&tips_fg); + /* Action area */ button = gtk_button_new_with_label ("OK"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); @@ -306,6 +402,7 @@ sparkle_dialog () gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_grab_default (button); gtk_widget_show (button); + set_tooltip(tips,button,"Accept settings and apply filter on image"); button = gtk_button_new_with_label ("Cancel"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); @@ -314,19 +411,21 @@ sparkle_dialog () GTK_OBJECT (dlg)); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_show (button); + set_tooltip(tips,button,"Reject any changes and close plug-in"); /* parameter settings */ frame = gtk_frame_new ("Parameter Settings"); 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 (5, 2, FALSE); + table = gtk_table_new (15, 2, FALSE); gtk_container_border_width (GTK_CONTAINER (table), 10); gtk_container_add (GTK_CONTAINER (frame), table); + label = gtk_label_new ("Luminosity Threshold"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 5, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 5, 5); scale_data = gtk_adjustment_new (svals.lum_threshold, 0.0, 0.1, 0.001, 0.001, 0.0); scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); gtk_widget_set_usize (scale, SCALE_WIDTH, 0); @@ -339,10 +438,12 @@ sparkle_dialog () &svals.lum_threshold); gtk_widget_show (label); gtk_widget_show (scale); + set_tooltip(tips,scale,"Adjust the Luminosity Threshold"); + label = gtk_label_new ("Flare Intensity"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 5); scale_data = gtk_adjustment_new (svals.flare_inten, 0.0, 1.0, 0.01, 0.01, 0.0); scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); gtk_widget_set_usize (scale, SCALE_WIDTH, 0); @@ -355,26 +456,29 @@ sparkle_dialog () &svals.flare_inten); gtk_widget_show (label); gtk_widget_show (scale); + set_tooltip(tips,scale,"Adjust the Flare Intensity"); label = gtk_label_new ("Spike Length"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, 0, 5, 0); - scale_data = gtk_adjustment_new (svals.spike_len, 1.0, 100.0, 1.0, 1.0, 0.0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, 0, 5, 5); + scale_data = gtk_adjustment_new (svals.spike_len, 1, 100, 1, 1, 0); scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); gtk_widget_set_usize (scale, SCALE_WIDTH, 0); gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 2, 3, GTK_FILL, 0, 0, 0); gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_scale_set_digits (GTK_SCALE (scale), 0); gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed", (GtkSignalFunc) sparkle_scale_update, &svals.spike_len); gtk_widget_show (label); gtk_widget_show (scale); + set_tooltip(tips,scale,"Adjust the Spike Length"); label = gtk_label_new ("Spike Points"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, GTK_FILL, 0, 5, 0); - scale_data = gtk_adjustment_new (svals.spike_pts, 0.0, 16.0, 1.0, 1.0, 0.0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, GTK_FILL, 0, 5, 5); + scale_data = gtk_adjustment_new (svals.spike_pts, 0, 16, 1, 1, 0); scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); gtk_widget_set_usize (scale, SCALE_WIDTH, 0); gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 3, 4, GTK_FILL, 0, 0, 0); @@ -386,21 +490,180 @@ sparkle_dialog () &svals.spike_pts); gtk_widget_show (label); gtk_widget_show (scale); + set_tooltip(tips,scale,"Adjust the Number of Spike Points"); - label = gtk_label_new ("Spike Angle"); + label = gtk_label_new ("Spike Angle (-1: Random)"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, GTK_FILL, 0, 5, 0); - scale_data = gtk_adjustment_new (svals.spike_angle, 0.0, 360.0, 5.0, 5.0, 0.0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, GTK_FILL, 0, 5, 5); + scale_data = gtk_adjustment_new (svals.spike_angle, -1, 360, 5, 5, 0); scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); gtk_widget_set_usize (scale, SCALE_WIDTH, 0); gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 4, 5, GTK_FILL, 0, 0, 0); gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_scale_set_digits (GTK_SCALE (scale), 0); gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed", (GtkSignalFunc) sparkle_scale_update, &svals.spike_angle); gtk_widget_show (label); gtk_widget_show (scale); + set_tooltip(tips,scale,"Adjust the Spike Angle (-1 means a Random Angle is choosen)"); + + label = gtk_label_new ("Spike Density"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 5, 6, GTK_FILL, 0, 5, 5); + scale_data = gtk_adjustment_new (svals.density, 0.0, 1.0, 0.01, 0.01, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); + gtk_widget_set_usize (scale, SCALE_WIDTH, 0); + gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 5, 6, GTK_FILL, 0, 0, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_scale_set_digits (GTK_SCALE (scale), 2); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed", + (GtkSignalFunc) sparkle_scale_update, + &svals.density); + gtk_widget_show (label); + gtk_widget_show (scale); + set_tooltip(tips,scale,"Adjust the Spike Density"); + + label = gtk_label_new ("Opacity"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 6, 7, GTK_FILL, 0, 5, 5); + scale_data = gtk_adjustment_new (svals.opacity, 0.0, 1.0, 0.01, 0.01, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); + gtk_widget_set_usize (scale, SCALE_WIDTH, 0); + gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 6, 7, GTK_FILL, 0, 0, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_scale_set_digits (GTK_SCALE (scale), 2); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed", + (GtkSignalFunc) sparkle_scale_update, + &svals.opacity); + gtk_widget_show (label); + gtk_widget_show (scale); + set_tooltip(tips,scale,"Adjust the Opacity of the Spikes"); + + label = gtk_label_new ("Random Hue"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 7, 8, GTK_FILL, 0, 5, 5); + scale_data = gtk_adjustment_new (svals.random_hue, 0.0, 1.0, 0.01, 0.01, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); + gtk_widget_set_usize (scale, SCALE_WIDTH, 0); + gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 7, 8, GTK_FILL, 0, 0, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_scale_set_digits (GTK_SCALE (scale), 2); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed", + (GtkSignalFunc) sparkle_scale_update, + &svals.random_hue); + gtk_widget_show (label); + gtk_widget_show (scale); + set_tooltip(tips,scale,"Adjust the Value how much the Hue should be changed randomly"); + + label = gtk_label_new ("Random Saturation"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 8, 9, GTK_FILL, 0, 5, 5); + scale_data = gtk_adjustment_new (svals.random_saturation, 0.0, 1.0, 0.01, 0.01, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); + gtk_widget_set_usize (scale, SCALE_WIDTH, 0); + gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 8, 9, GTK_FILL, 0, 0, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_scale_set_digits (GTK_SCALE (scale), 2); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed", + (GtkSignalFunc) sparkle_scale_update, + &svals.random_saturation); + gtk_widget_show (label); + gtk_widget_show (scale); + set_tooltip(tips,scale,"Adjust the Value how much the Saturation should be changed randomly"); + + label = gtk_label_new ("Preserve Luminosity"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 9, 10, GTK_FILL, 0, 5, 5); + gtk_widget_show(label); + toggle = gtk_check_button_new (); + + gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 9, 10, GTK_FILL, 0, 0, 0); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), svals.preserve_luminosity); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) sparkle_toggle_update, + &svals.preserve_luminosity); + gtk_widget_show (toggle); + set_tooltip(tips,toggle,"Should the Luminosity be preserved?"); + + label = gtk_label_new ("Invers"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 10, 11, GTK_FILL, 0, 5, 5); + gtk_widget_show(label); + toggle = gtk_check_button_new (); + + gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 10, 11, GTK_FILL, 0, 0, 0); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), svals.invers); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) sparkle_toggle_update, + &svals.invers); + gtk_widget_show (toggle); + set_tooltip(tips,toggle,"Should an Inverse Effect be done?"); + + label = gtk_label_new ("Add Border"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 11, 12, GTK_FILL, 0, 5, 5); + gtk_widget_show(label); + toggle = gtk_check_button_new (); + gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 11, 12, GTK_FILL, 0, 0, 0); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), svals.border); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) sparkle_toggle_update, + &svals.border); + gtk_widget_show (toggle); + set_tooltip(tips,toggle,"Draw a Border of Spikes around the Image"); + + /* colortype */ + label = gtk_label_new ("Natural Color"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 12, 13, GTK_FILL, 0, 5, 5); + gtk_widget_show(label); + + toggle = gtk_radio_button_new (group); + gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 12, 13, GTK_FILL, 0, 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_natural); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) sparkle_toggle_update, + &use_natural); + gtk_widget_show (toggle); + set_tooltip(tips,toggle,"Use the Color of the Image"); + + label = gtk_label_new ("Foreground Color"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 13, 14, GTK_FILL, 0, 5, 5); + gtk_widget_show(label); + + toggle = gtk_radio_button_new (group); + gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 13, 14, GTK_FILL, 0, 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_foreground); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) sparkle_toggle_update, + &use_foreground); + gtk_widget_show (toggle); + set_tooltip(tips,toggle,"Use the Foreground Color"); + + label = gtk_label_new ("Background Color"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 14, 15, GTK_FILL, 0, 5, 5); + gtk_widget_show(label); + + toggle = gtk_radio_button_new (group); + gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 14, 15, GTK_FILL, 0, 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_background); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) sparkle_toggle_update, + &use_background); + gtk_widget_show (toggle); + set_tooltip(tips,toggle,"Use the Background Color"); + gtk_widget_show (frame); gtk_widget_show (table); @@ -409,7 +672,16 @@ sparkle_dialog () gtk_main (); gdk_flush (); + /* determine colortype */ + if (use_natural) + svals.colortype = NATURAL; + else if (use_foreground) + svals.colortype = FOREGROUND; + else if (use_background) + svals.colortype = BACKGROUND; + return sint.run; + } static gint @@ -417,21 +689,35 @@ compute_luminosity (guchar *pixel, gint gray, gint has_alpha) { + gint pixel0, pixel1, pixel2; + + if (svals.invers == FALSE) + { + pixel0 = pixel[0]; + pixel1 = pixel[1]; + pixel2 = pixel[2]; + } + else + { + pixel0 = 255 - pixel[0]; + pixel1 = 255 - pixel[1]; + pixel2 = 255 - pixel[2]; + } if (gray) { if (has_alpha) - return (pixel[0] * pixel[1]) / 255; + return (pixel0 * pixel1) / 255; else - return pixel[0]; + return (pixel0); } else { gint min, max; - min = MIN (pixel[0], pixel[1]); - min = MIN (min, pixel[2]); - max = MAX (pixel[0], pixel[1]); - max = MAX (max, pixel[2]); + min = MIN (pixel0, pixel1); + min = MIN (min, pixel2); + max = MAX (pixel0, pixel1); + max = MAX (max, pixel2); if (has_alpha) return ((min + max) * pixel[3]) / 510; @@ -499,7 +785,7 @@ sparkle (GDrawable *drawable, { GPixelRgn src_rgn, dest_rgn; guchar *src, *dest; - gdouble nfrac, length, inten; + gdouble nfrac, length, inten, spike_angle; gint cur_progress, max_progress; gint x1, y1, x2, y2; gint size, lum, x, y, b; @@ -507,11 +793,14 @@ sparkle (GDrawable *drawable, gint has_alpha, alpha; gpointer pr; guchar *tmp1; + gint tile_width, tile_height; gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); gray = gimp_drawable_gray (drawable->id); has_alpha = gimp_drawable_has_alpha (drawable->id); alpha = (has_alpha) ? drawable->bpp - 1 : drawable->bpp; + tile_width = gimp_tile_width(); + tile_height = gimp_tile_height(); /* initialize the progress dialog */ cur_progress = 0; @@ -528,65 +817,80 @@ sparkle (GDrawable *drawable, size = src_rgn.w * src_rgn.h; while (size --) - { - if(has_alpha && src[alpha] == 0) - { - memset(dest, 0, alpha * sizeof(guchar)); - dest += alpha; - } - else - { - for (b = 0, tmp1 = src; b < alpha; b++) - { - *dest++ = *tmp1++; - } - } - if (has_alpha) - *dest++ = src[alpha]; + { + if(has_alpha && src[alpha] == 0) + { + memset(dest, 0, alpha * sizeof(guchar)); + dest += alpha; + } + else + { + for (b = 0, tmp1 = src; b < alpha; b++) + { + *dest++ = *tmp1++; + } + } + if (has_alpha) + *dest++ = src[alpha]; - src += src_rgn.bpp; - } + src += src_rgn.bpp; + } } /* add effects to new image based on intensity of old pixels */ gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); - for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) + for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { src = src_rgn.data; for (y = 0; y < src_rgn.h; y++) for (x = 0; x < src_rgn.w; x++) { - lum = compute_luminosity (src, gray, has_alpha); + if (svals.border) + { + if (x + src_rgn.x == 0 || y + src_rgn.y == 0 + || x + src_rgn.x == drawable->width - 1 + || y + src_rgn.y == drawable->height - 1) + lum = 255; + else + lum = 0; + } + else + lum = compute_luminosity (src, gray, has_alpha); if (lum >= threshold) { nfrac = fabs ((gdouble) (lum + 1 - threshold) / (gdouble) (256 - threshold)); - - length = svals.spike_len * pow (nfrac, 0.8); + length = (gdouble) svals.spike_len * (gdouble) pow (nfrac, 0.8); inten = svals.flare_inten * pow (nfrac, 1.0); /* fspike im x,y intens rlength angle */ if (svals.spike_pts > 0) { /* major spikes */ - fspike (&dest_rgn, gray, x1, y1, x2, y2, + if (svals.spike_angle == -1) + spike_angle = 360.0 * rand () / RAND_MAX; + else + spike_angle = svals.spike_angle; + if (rand() <= RAND_MAX * svals.density) + { + fspike (&dest_rgn, gray, x1, y1, x2, y2, x + src_rgn.x, y + src_rgn.y, - inten, length, svals.spike_angle); - - /* minor spikes */ - fspike (&dest_rgn, gray, x1, y1, x2, y2, + tile_width, tile_height, + inten, length, spike_angle); + /* minor spikes */ + fspike (&dest_rgn, gray, x1, y1, x2, y2, x + src_rgn.x, y + src_rgn.y, + tile_width, tile_height, inten * 0.7, length * 0.7, - (svals.spike_angle + 180.0 / svals.spike_pts)); + ((gdouble) spike_angle + 180.0 / svals.spike_pts)); + } } - cur_progress ++; if ((cur_progress % 5) == 0) gimp_progress_update ((double) cur_progress / (double) max_progress); } - src += src_rgn.bpp; } } @@ -608,27 +912,27 @@ fspike (GPixelRgn *dest_rgn, gint y2, gdouble xr, gdouble yr, + gint tile_width, + gint tile_height, gdouble inten, gdouble length, gdouble angle) { gdouble xrt, yrt, dx, dy; gdouble rpos; - gdouble in[MAX_CHANNELS]; - gdouble val[MAX_CHANNELS]; - gdouble ho = 1.0, so = 1.0, vo = 1.0; + gdouble in; gdouble theta, efac; gdouble sfac; - gdouble *gd_tmp1, *gd_tmp2; - guchar *guc_tmp; + gdouble r, g, b; + gdouble h, s, l; GTile *tile = NULL; gint row, col; gint i; gint bytes; gint x, y; gint ok; - gint b; guchar pixel[MAX_CHANNELS]; + guchar color[MAX_CHANNELS]; theta = angle; efac = 2.0; /* exponent on intensity falloff with radius */ @@ -644,18 +948,41 @@ fspike (GPixelRgn *dest_rgn, gimp_pixel_rgn_get_pixel (dest_rgn, pixel, x, y); - for (b = 0, gd_tmp1 = val, guc_tmp = pixel; b < bytes; b++) - *gd_tmp1++ = (gdouble) (gint)(*guc_tmp++) / 255.0; - - /* increase saturation to full for color image */ - if (! gray) + if (svals.colortype == FOREGROUND) + gimp_palette_get_foreground (&color[0], &color[1], &color[2]); + else if (svals.colortype == BACKGROUND) + gimp_palette_get_background (&color[0], &color[1], &color[2]); + else { - rgb_to_hsl (val[0], val[1], val[2], &ho, &so, &vo); - hsl_to_rgb (ho, 1.0, vo, &val[0], &val[1], &val[2]); + color[0] = pixel[0]; + color[1] = pixel[1]; + color[2] = pixel[2]; + } + if (svals.invers != FALSE) + { + color[0] = 255 - color[0]; + color[1] = 255 - color[1]; + color[2] = 255 - color[2]; + } + if (svals.random_hue != 0.0 || svals.random_saturation != 0.0) + { + r = color[0] / 255.0; + g = color[1] / 255.0; + b = color[2] / 255.0; + rgb_to_hsl(r, g, b, &h, &s, &l); + h = h + svals.random_hue * ((gdouble) rand() / (gdouble) RAND_MAX - 0.5); + if (h >= 1.0) h -= 1.0; + else if (h < 0) h += 1.0; + s = s + svals.random_saturation * (2 * (gdouble) rand() / (gdouble) RAND_MAX - 1.0); + if (s > 1.0) s = 1.0; + hsl_to_rgb(h, s, l, &r, &g, &b); + color[0] = r * 255.0; + color[1] = g * 255.0; + color[2] = b * 255.0; } - dx = 0.2 * cos (theta * G_PI / 180.0); - dy = 0.2 * sin (theta * G_PI / 180.0); + dx = 0.2 * cos (theta * M_PI / 180.0); + dy = 0.2 * sin (theta * M_PI / 180.0); xrt = xr; yrt = yr; rpos = 0.2; @@ -664,20 +991,16 @@ fspike (GPixelRgn *dest_rgn, { sfac = exp (-pow (rpos / length, efac)); sfac = sfac * inten; - ok = FALSE; - for (b = 0, gd_tmp1 = in, gd_tmp2 = val; b < bytes; - b++, gd_tmp1++, gd_tmp2++) - { - *gd_tmp1 = 0.2 * (*gd_tmp2) * sfac; - if (*gd_tmp1 > 0.01) - ok = TRUE; - } - tile = rpnt (dest_rgn->drawable, tile, x1, y1, x2, y2, xrt, yrt, &row, &col, bytes, in); - tile = rpnt (dest_rgn->drawable, tile, x1, y1, x2, y2, xrt + 1, yrt, &row, &col, bytes, in); - tile = rpnt (dest_rgn->drawable, tile, x1, y1, x2, y2, xrt + 1, yrt + 1, &row, &col, bytes, in); - tile = rpnt (dest_rgn->drawable, tile, x1, y1, x2, y2, xrt, yrt + 1, &row, &col, bytes, in); + in = 0.2 * sfac; + if (in > 0.01) + ok = TRUE; + + tile = rpnt (dest_rgn->drawable, tile, x1, y1, x2, y2, xrt, yrt, tile_width, tile_height, &row, &col, bytes, in, color); + tile = rpnt (dest_rgn->drawable, tile, x1, y1, x2, y2, xrt + 1, yrt, tile_width, tile_height, &row, &col, bytes, in, color); + tile = rpnt (dest_rgn->drawable, tile, x1, y1, x2, y2, xrt + 1, yrt + 1, tile_width, tile_height, &row, &col, bytes, in, color); + tile = rpnt (dest_rgn->drawable, tile, x1, y1, x2, y2, xrt, yrt + 1, tile_width, tile_height, &row, &col, bytes, in, color); xrt += dx; yrt += dy; @@ -700,45 +1023,75 @@ rpnt (GDrawable *drawable, gint y2, gdouble xr, gdouble yr, + gint tile_width, + gint tile_height, gint *row, gint *col, gint bytes, - gdouble *inten) + gdouble inten, + guchar color[MAX_CHANNELS]) { gint x, y, b; - gdouble dx, dy, rs, fac; - gdouble val; + gdouble dx, dy, rs, val; guchar *pixel; - guchar *guc_tmp; - gdouble *gd_tmp; + gdouble new; + gint newcol, newrow; + gint newcoloff, newrowoff; x = (int) (xr); /* integer coord. to upper left of real point */ y = (int) (yr); if (x >= x1 && y >= y1 && x < x2 && y < y2) { - if ((x >> 6 != *col) || (y >> 6 != *row)) + newcol = x / tile_width; + newcoloff = x % tile_width; + newrow = y / tile_height; + newrowoff = y % tile_height; + + if ((newcol != *col) || (newrow != *row)) { - *col = x >> 6; - *row = y >> 6; + *col = newcol; + *row = newrow; if (tile) gimp_tile_unref (tile, TRUE); tile = gimp_drawable_get_tile (drawable, TRUE, *row, *col); gimp_tile_ref (tile); } - pixel = tile->data + tile->bpp * (tile->ewidth * (y % 64) + (x % 64)); + pixel = tile->data + tile->bpp * (tile->ewidth * newrowoff + newcoloff); dx = xr - x; dy = yr - y; rs = dx * dx + dy * dy; - fac = exp (-rs / PSV); + val = inten * exp (-rs / PSV); - for (b = 0, guc_tmp = pixel, gd_tmp = inten; b < bytes; - b++, guc_tmp++, gd_tmp++) + for (b = 0; b < bytes; b++) { - val = (*gd_tmp) * fac; - val += (gdouble) *guc_tmp / 255.0; - if (val > 1.0) val = 1.0; - *guc_tmp = (guchar) (val * 255.0); + if (svals.invers == FALSE) + new = pixel[b]; + else + new = 255 - pixel[b]; + + if (svals.preserve_luminosity==TRUE) + { + if (new < color[b]) + new *= (1.0 - val * svals.opacity); + else + { + new -= val * color[b] * svals.opacity; + if (new < 0.0) + new = 0.0; + + } + } + new *= 1.0 - val * (1.0 - svals.opacity); + new += val * color[b]; + + if (new > 255) new = 255; + else new = new; + + if (svals.invers != FALSE) + pixel[b] = 255 - new; + else + pixel[b] = new; } } @@ -869,3 +1222,22 @@ sparkle_scale_update (GtkAdjustment *adjustment, { *scale_val = adjustment->value; } + +static void +sparkle_toggle_update (GtkWidget *widget, + gpointer data) +{ + int *toggle_val; + toggle_val = (int *) data; + if (GTK_TOGGLE_BUTTON (widget)->active) + *toggle_val = TRUE; + else + *toggle_val = FALSE; +} + +static void +set_tooltip (GtkTooltips *tooltips, GtkWidget *widget, const char *desc) +{ + if (desc && desc[0]) + gtk_tooltips_set_tip (tooltips, widget, (char *) desc, NULL); +} diff --git a/plug-ins/common/warp.c b/plug-ins/common/warp.c new file mode 100644 index 0000000000..c3944fa60a --- /dev/null +++ b/plug-ins/common/warp.c @@ -0,0 +1,1922 @@ +/* Warp --- image filter plug-in for The Gimp image manipulation program + * Copyright (C) 1997 John P. Beale + * Much of the 'warp' is from the Displace plug-in: 1996 Stephen Robert Norris + * Much of the 'displace' code taken in turn from the pinch plug-in + * which is by 1996 Federico Mena Quintero + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * You can contact me (the warp author) at beale@best.com + * Please send me any patches or enhancements to this code. + * You can contact the original The Gimp authors at gimp@xcf.berkeley.edu + * + * -------------------------------------------------------------------- + * Warp Program structure: after running the user interface and setting the + * parameters, warp generates a brand-new image (later to be deleted + * before the user ever sees it) which contains two grayscale layers, + * representing the X and Y gradients of the "control" image. For this + * purpose, all channels of the control image are summed for a scalar + * value at each pixel coordinate for the gradient operation. + * + * The X,Y components of the calculated gradient are then used to displace pixels + * from the source image into the destination image. The displacement vector is + * rotated a user-specified amount first. This displacement operation happens + * iteratively, generating a new displaced image from each prior image. + * ------------------------------------------------------------------- + * + * Revision History: + * Version 0.37 12/19/98 Fixed Tooltips and freeing memory + * Version 0.36 11/9/97 Changed XY vector layers back to own image + * fixed 'undo' problem (hopefully) + * + * Version 0.35 11/3/97 Added vector-map, mag-map, grad-map to + * diff vector instead of separate operation + * further futzing with drawable updates + * starting adding tooltips + * + * Version 0.34 10/30/97 'Fixed' drawable update problem + * Added 16-bit resolution to differential map + * Added substep increments for finer control + * + * Version 0.33 10/26/97 Added 'angle increment' to user interface + * + * Version 0.32 10/25/97 Added magnitude control map (secondary control) + * Changed undo behavior to be one undo-step per warp call. + * + * Version 0.31 10/25/97 Fixed src/dest pixregions so program works + * with multiple-layer images. Still don't know + * exactly what I did to fix it :-/ Also, added 'color' option for + * border pixels to use the current selected foreground color. + * + * Version 0.3 10/20/97 Initial release for Gimp 0.99.xx + */ + + +#include +#include +#include +#include +#include +#include /* time(NULL) for random # seed */ +#include "gtk/gtk.h" +#include "libgimp/gimp.h" +#include "libgimp/gimpui.h" + + +/* Some useful macros */ + +#define ENTRY_WIDTH 75 +#define TILE_CACHE_SIZE 30 /* was 48. There is a cache flush problem in GIMP preventing sequential updates */ +#define MIN_ARGS 6 /* minimum number of arguments required */ + +#define WRAP 0 +#define SMEAR 1 +#define BLACK 2 +#define COLOR 3 + +typedef struct { + gdouble amount; + gint warp_map; + gint iter; + gdouble dither; + gdouble angle; + gint wrap_type; + gint mag_map; + gint mag_use; + gint substeps; + gint grad_map; + gdouble grad_scale; + gint vector_map; + gdouble vector_scale; + gdouble vector_angle; +} WarpVals; + +typedef struct { + GtkWidget *amount; + GtkWidget *angle; + GtkWidget *iter; + GtkWidget *dither; + GtkWidget *warp_map; + GtkWidget *mag_map; + GtkWidget *mag_use; + GtkWidget *substeps; + GtkWidget *grad_map; + GtkWidget *grad_scale; + GtkWidget *vector_map; + GtkWidget *vector_scale; + GtkWidget *vector_angle; + + gint run; +} WarpInterface; + +/* + * Function prototypes. + */ + +static void query (void); +static void run (gchar *name, + gint nparams, + GParam *param, + gint *nreturn_vals, + GParam **return_vals); + +static void blur16 (GDrawable *drawable); + +static void diff (GDrawable *drawable, + gint32 *xl_id, + gint32 *yl_id ); + +static void diff_prepare_row (GPixelRgn *pixel_rgn, + guchar *data, + int x, + int y, + int w); + +static void warp_one (GDrawable *draw, + GDrawable *new, + GDrawable *map_x, + GDrawable *map_y, + GDrawable *mag_draw, + gint first_time, + gint step ); + +static void warp (GDrawable *drawable, + GDrawable **map_x_p, + GDrawable **map_y_p ); + +static gint warp_dialog (GDrawable *drawable); +static GTile * warp_pixel (GDrawable * drawable, + GTile * tile, + gint width, + gint height, + gint x1, + gint y1, + gint x2, + gint y2, + gint x, + gint y, + gint * row, + gint * col, + guchar * pixel); +static guchar bilinear (gdouble x, + gdouble y, + guchar * v); + +static gint bilinear16 (gdouble x, + gdouble y, + gint * v); + +static gint warp_map_constrain (gint32 image_id, + gint32 drawable_id, + gpointer data); +static void warp_map_callback (gint32 id, + gpointer data); +static void warp_map_mag_callback (gint32 id, + gpointer data); +static void warp_map_grad_callback (gint32 id, + gpointer data); +static void warp_map_vector_callback (gint32 id, + gpointer data); +static void warp_close_callback (GtkWidget *widget, + gpointer data); +static void warp_ok_callback (GtkWidget *widget, + gpointer data); +static void warp_toggle_update (GtkWidget *widget, + gpointer data); +static void warp_entry_callback (GtkWidget *widget, + gpointer data); +static void warp_entry_int_callback (GtkWidget *widget, + gpointer data); +static gdouble warp_map_mag_give_value (guchar *pt, + gint alpha, + gint bytes); + +/* -------------------------------------------------------------------------------- */ +/* Variables global over entire plug-in scope */ +/* -------------------------------------------------------------------------------- */ + +GPlugInInfo PLUG_IN_INFO = +{ + NULL, /* init_proc */ + NULL, /* quit_proc */ + query, /* query_proc */ + run, /* run_proc */ +}; + +static WarpVals dvals = +{ + 10.0, /* amount */ + -1, /* warp_map */ + 5, /* iterations */ + 0.0, /* dither */ + 90.0, /* angle */ + WRAP, /* wrap_type */ + -1, /* mag_map */ + FALSE, /* mag_use */ + 1, /* substeps */ + -1, /* grad_map */ + 0.0, /* grad_scale */ + -1, /* vector_map */ + 0.0, /* vector_scale */ + 0.0 /* vector_angle */ +}; + +static WarpInterface dint = +{ + NULL, /* amount */ + NULL, /* angle */ + NULL, /* iter */ + NULL, /* dither */ + NULL, /* warp_map */ + NULL, /* mag_map */ + NULL, /* mag_use */ + NULL, /* substeps */ + NULL, /* grad_map */ + NULL, /* grad_scale */ + NULL, /* vector_map */ + NULL, /* vector_scale */ + NULL, /* vector_angle */ + FALSE, /* run */ +}; + +/* -------------------------------------------------------------------------------- */ + +gint display_diff_map = TRUE; /* show 16-bit diff. vectormap */ +gint progress = 0; /* progress indicator bar */ +guint tile_width, tile_height; /* size of an image tile */ +GRunModeType run_mode; /* interactive, non-, etc. */ +guchar color_pixel[4] = {0, 0, 0, 255}; /* current selected foreground color */ + + +/* -------------------------------------------------------------------------------- */ + + +/***** Functions *****/ + +MAIN () + +static void +query () +{ + static GParamDef args[] = + { + { PARAM_INT32, "run_mode", "Interactive, non-interactive" }, + { PARAM_IMAGE, "image", "Input image (unused)" }, + { PARAM_DRAWABLE, "drawable", "Input drawable" }, + { PARAM_FLOAT, "amount", "Pixel displacement multiplier" }, + { PARAM_DRAWABLE, "warp_map", "Displacement control map" }, + { PARAM_INT32, "iter", "Iteration count (last required argument)" }, + { PARAM_FLOAT, "dither", "Random dither amount (first optional argument)" }, + { PARAM_FLOAT, "angle", "Angle of gradient vector rotation" }, + { PARAM_INT32, "wrap_type", "Edge behavior: { WRAP (0), SMEAR (1), BLACK (2), COLOR (3) }" }, + { PARAM_DRAWABLE, "mag_map", "Magnitude control map" }, + { PARAM_INT32, "mag_use", "Use magnitude map: { FALSE (0), TRUE (1) }" }, + { PARAM_INT32, "substeps", "Substeps between image updates" }, + { PARAM_INT32, "grad_map", "Gradient control map" }, + { PARAM_FLOAT, "grad_scale", "Scaling factor for gradient map (0=don't use)" }, + { PARAM_INT32, "vector_map", "Fixed vector control map" }, + { PARAM_FLOAT, "vector_scale", "Scaling factor for fixed vector map (0=don't use)" }, + { PARAM_FLOAT, "vector_angle", "Angle for fixed vector map" }, + }; + static GParamDef *return_vals = NULL; + static gint nargs = sizeof (args) / sizeof (args[0]); + static gint nreturn_vals = 0; + + gimp_install_procedure ("plug_in_warp", + "Twist or smear an image. (only first six arguments are required)", + "Smears an image along vector paths calculated as the gradient of a separate control matrix. The effect can look like brushstrokes of acrylic or watercolor paint, in some cases.", + "John P. Beale", + "John P. Beale", + "1997", + "/Filters/Artistic/Warp", + "RGB*, GRAY*", + PROC_PLUG_IN, + nargs, nreturn_vals, + args, return_vals); +} + +static void +run (gchar *name, + gint nparams, + GParam *param, + gint *nreturn_vals, + GParam **return_vals) +{ + static GParam values[1]; + GDrawable *drawable; + GDrawable *map_x = NULL; /* satisfy compiler complaints */ + GDrawable *map_y = NULL; + gint32 image_ID; /* image id of drawable */ + + GStatusType status = STATUS_SUCCESS; + gint pcnt; /* parameter counter for scanning input params. */ + + run_mode = param[0].data.d_int32; + + tile_width = gimp_tile_width(); /* initialize some globals */ + tile_height = gimp_tile_height(); + + /* get currently selected foreground pixel color */ + gimp_palette_get_foreground (&color_pixel[0], &color_pixel[1], &color_pixel[2]); + + + + /* Get the specified drawable */ + drawable = gimp_drawable_get (param[2].data.d_drawable); + + *nreturn_vals = 1; + *return_vals = values; + + values[0].type = PARAM_STATUS; + values[0].data.d_status = status; + + switch (run_mode) + { + case RUN_INTERACTIVE: + /* Possibly retrieve data */ + gimp_get_data ("plug_in_warp", &dvals); + + /* First acquire information with a dialog */ + if (! warp_dialog (drawable)) + return; + break; + + case RUN_NONINTERACTIVE: + /* Make sure minimum args (mode, image, draw, amount, warp_map, iter) are there */ + if (nparams < MIN_ARGS) + status = STATUS_CALLING_ERROR; + if (status == STATUS_SUCCESS) + { + pcnt = MIN_ARGS; /* parameter counter */ + dvals.amount = param[3].data.d_float; + dvals.warp_map = param[4].data.d_int32; + dvals.iter = param[5].data.d_int32; + if (nparams > pcnt++) dvals.dither = param[6].data.d_float; + if (nparams > pcnt++) dvals.angle = param[7].data.d_float; + if (nparams > pcnt++) dvals.wrap_type = param[8].data.d_int32; + if (nparams > pcnt++) dvals.mag_map = param[9].data.d_int32; + if (nparams > pcnt++) dvals.mag_use = param[10].data.d_int32; + if (nparams > pcnt++) dvals.substeps = param[11].data.d_int32; + if (nparams > pcnt++) dvals.grad_map = param[12].data.d_int32; + if (nparams > pcnt++) dvals.grad_scale = param[13].data.d_float; + if (nparams > pcnt++) dvals.vector_map = param[14].data.d_int32; + if (nparams > pcnt++) dvals.vector_scale = param[15].data.d_float; + if (nparams > pcnt++) dvals.vector_angle = param[16].data.d_float; + } + break; + + case RUN_WITH_LAST_VALS: + /* Possibly retrieve data */ + gimp_get_data ("plug_in_warp", &dvals); + break; + + default: + break; + } + + if (status == STATUS_SUCCESS) + { + /* set the tile cache size */ + gimp_tile_cache_ntiles (TILE_CACHE_SIZE); + + /* run the warp effect */ + warp (drawable, &map_x, &map_y); + + /* Store data */ + if (run_mode == RUN_INTERACTIVE) + gimp_set_data ("plug_in_warp", &dvals, sizeof (WarpVals)); + } + + values[0].data.d_status = status; + + image_ID = gimp_layer_get_image_id(map_x->id); + gimp_image_delete(image_ID); + gimp_displays_flush(); + + /* + if (display_diff_map == FALSE) { + gimp_layer_delete(map_x->id); + gimp_layer_delete(map_y->id); + } else { + image_ID = gimp_layer_get_image_id(drawable->id); + gimp_image_disable_undo(image_ID); + gimp_image_enable_undo(image_ID); + } + */ + + + gimp_drawable_detach (map_x); + gimp_drawable_detach (map_y); + + + if (run_mode != RUN_NONINTERACTIVE) + gimp_displays_flush (); + +} + +static int +warp_dialog (GDrawable *drawable) +{ + GtkWidget *dlg; + GtkWidget *label; + GtkWidget *button; + GtkWidget *toggle; + GtkWidget *toggle_hbox; + GtkWidget *frame; + GtkWidget *table; + GtkWidget *otable; + GtkWidget *entry; + GtkWidget *option_menu; + GtkWidget *option_menu_mag; + GtkWidget *option_menu_grad; + GtkWidget *option_menu_vector; + GtkWidget *menu; + GtkWidget *magmenu; + GtkWidget *gradmenu; + GtkWidget *vectormenu; + GtkTooltips *tooltips; + GdkColor tips_fg, tips_bg; + + GSList *group = NULL; + GSList *groupmag = NULL; + gchar **argv; + gchar buffer[32]; + gint argc; + gint use_wrap = (dvals.wrap_type == WRAP); + gint use_smear = (dvals.wrap_type == SMEAR); + gint use_black = (dvals.wrap_type == BLACK); + gint use_color = (dvals.wrap_type == COLOR); + gint mag_use_yes = (dvals.mag_use == TRUE); + gint mag_use_no = (dvals.mag_use == FALSE); + + argc = 1; + argv = g_new (gchar *, 1); + argv[0] = g_strdup ("Warp"); + + gtk_init (&argc, &argv); + + dlg = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (dlg), "Warp"); + gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + (GtkSignalFunc) warp_close_callback, + NULL); + + /* use black as foreground: */ + tooltips = gtk_tooltips_new (); /* obtain a tooltips widget */ + tips_fg.red = 0; + tips_fg.green = 0; + tips_fg.blue = 0; + /* postit yellow (khaki) as background: */ + 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); +/* gtk_tooltips_set_delay (tooltips, 0);*/ /* any longer and the tooltip will persist and + obscure the popup menu if mouse button clicked before 1 second */ + + /* + This call does not seem to work. leaves tooltip 100% black, no color + + gtk_tooltips_set_colors (tooltips, &yellow_color, &grey_color); + void gtk_tooltips_set_colors (GtkTooltips *tooltips, + GdkColor *background, + GdkColor *foreground); + */ + + + /* 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) warp_ok_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); + + /* The main table */ + frame = gtk_frame_new ("Main Options"); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); + gtk_container_border_width (GTK_CONTAINER (frame), 1); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0); + + /* table params: rows, columns */ + table = gtk_table_new (4, 3, FALSE); + gtk_container_border_width (GTK_CONTAINER (table), 1); + gtk_container_add (GTK_CONTAINER (frame), table); + + gtk_table_set_row_spacings (GTK_TABLE (table), 1); + gtk_table_set_col_spacings (GTK_TABLE (table), 1); + + /* on_x, on_y */ + label = gtk_label_new ("Step Size"); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + label = gtk_label_new ("Iterations"); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + /* amount, angle, iter */ + dint.amount = entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_set_usize (entry, ENTRY_WIDTH, 0); + sprintf (buffer, "%3.3f", dvals.amount); + gtk_entry_set_text (GTK_ENTRY (entry), buffer); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + (GtkSignalFunc) warp_entry_callback, + &dvals.amount); + gtk_widget_show (entry); + + + dint.iter = entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_set_usize (entry, ENTRY_WIDTH, 0); + sprintf (buffer, "%d", dvals.iter); + gtk_entry_set_text (GTK_ENTRY (entry), buffer); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + (GtkSignalFunc) warp_entry_int_callback, + &dvals.iter); + gtk_widget_show (entry); + + + /* Displacement map menu */ + label = gtk_label_new ("Displacement Map:"); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + dint.warp_map = option_menu = gtk_option_menu_new (); + gtk_table_attach (GTK_TABLE (table), option_menu, 2, 3, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + menu = gimp_drawable_menu_new (warp_map_constrain, warp_map_callback, + drawable, dvals.warp_map); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + gtk_widget_show (option_menu); + + + /* ================================================================================== */ + + /* Displacement Type */ + toggle_hbox = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (toggle_hbox), 1); + gtk_table_attach (GTK_TABLE (table), toggle_hbox, 0, 3, 3, 4, GTK_FILL, GTK_FILL, 0, 0); + + label = gtk_label_new ("On Edges: "); + gtk_box_pack_start (GTK_BOX (toggle_hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + toggle = gtk_radio_button_new_with_label (group, "Wrap"); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) warp_toggle_update, + &use_wrap); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_wrap); + gtk_widget_show (toggle); + + toggle = gtk_radio_button_new_with_label (group, "Smear"); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) warp_toggle_update, + &use_smear); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_smear); + gtk_widget_show (toggle); + + toggle = gtk_radio_button_new_with_label (group, "Black"); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) warp_toggle_update, + &use_black); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_black); + gtk_widget_show (toggle); + + toggle = gtk_radio_button_new_with_label (group, "FG Color"); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) warp_toggle_update, + &use_color); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_color); + gtk_widget_show (toggle); + + gtk_widget_show (toggle_hbox); + + gtk_widget_show (table); + gtk_widget_show (frame); + + /* -------------------------------------------------------------------- */ + /* --------- The secondary table -------------------------- */ + + frame = gtk_frame_new ("Secondary Options"); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); + gtk_container_border_width (GTK_CONTAINER (frame), 1); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0); + + /* table params: rows, columns */ + table = gtk_table_new (3, 3, FALSE); + gtk_container_border_width (GTK_CONTAINER (table), 1); + gtk_container_add (GTK_CONTAINER (frame), table); + + gtk_table_set_row_spacings (GTK_TABLE (table), 1); + gtk_table_set_col_spacings (GTK_TABLE (table), 1); + + label = gtk_label_new ("Dither Size"); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + dint.dither = entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_set_usize (entry, ENTRY_WIDTH, 0); + sprintf (buffer, "%3.3f", dvals.dither); + gtk_entry_set_text (GTK_ENTRY (entry), buffer); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + (GtkSignalFunc) warp_entry_callback, + &dvals.dither); + gtk_widget_show (entry); + + label = gtk_label_new ("Substeps"); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + dint.substeps = entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_set_usize (entry, ENTRY_WIDTH, 0); + sprintf (buffer, "%d", dvals.substeps); + gtk_entry_set_text (GTK_ENTRY (entry), buffer); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + (GtkSignalFunc) warp_entry_int_callback, + &dvals.substeps); + gtk_widget_show (entry); + + /* -------------------------------------------------------- */ + label = gtk_label_new ("Rotation Angle"); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + + dint.angle = entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_set_usize (entry, ENTRY_WIDTH, 0); + sprintf (buffer, "%3.1f", dvals.angle); + gtk_entry_set_text (GTK_ENTRY (entry), buffer); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + (GtkSignalFunc) warp_entry_callback, + &dvals.angle); + gtk_widget_show (entry); + + + /* Magnitude map menu */ + label = gtk_label_new ("Magnitude Map:"); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + dint.mag_map = option_menu_mag = gtk_option_menu_new (); + gtk_table_attach (GTK_TABLE (table), option_menu_mag, 2, 3, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + magmenu = gimp_drawable_menu_new (warp_map_constrain, warp_map_mag_callback, + drawable, dvals.mag_map); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu_mag), magmenu); + gtk_widget_show (option_menu_mag); + + + /* ----------------------------------------------------------------------- */ + /* Magnitude Usage */ + toggle_hbox = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (toggle_hbox), 1); + gtk_table_attach (GTK_TABLE (table), toggle_hbox, 2, 3, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + + label = gtk_label_new ("Use Mag Map: "); + gtk_box_pack_start (GTK_BOX (toggle_hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + toggle = gtk_radio_button_new_with_label (groupmag, "Yes"); + groupmag = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) warp_toggle_update, + &mag_use_yes); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), mag_use_yes); + gtk_widget_show (toggle); + + toggle = gtk_radio_button_new_with_label (groupmag, "No"); + groupmag = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) warp_toggle_update, + &mag_use_no); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), mag_use_no); + gtk_widget_show (toggle); + + gtk_widget_show (toggle_hbox); + + gtk_widget_show (table); + gtk_widget_show (frame); + + /* -------------------------------------------------------------------- */ + /* --------- The "other" table -------------------------- */ + + frame = gtk_frame_new ("Other Options"); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); + gtk_container_border_width (GTK_CONTAINER (frame), 1); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0); + + /* table params: rows, columns */ + otable = gtk_table_new (3, 3, FALSE); + gtk_container_border_width (GTK_CONTAINER (otable), 1); + gtk_container_add (GTK_CONTAINER (frame), otable); + + gtk_table_set_row_spacings (GTK_TABLE (otable), 1); + gtk_table_set_col_spacings (GTK_TABLE (otable), 1); + + label = gtk_label_new ("Gradient Scale"); + gtk_table_attach (GTK_TABLE (otable), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + dint.grad_scale = entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (otable), entry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_set_usize (entry, ENTRY_WIDTH, 0); + sprintf (buffer, "%3.3f", dvals.grad_scale); + gtk_entry_set_text (GTK_ENTRY (entry), buffer); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + (GtkSignalFunc) warp_entry_callback, + &dvals.grad_scale); + gtk_widget_show (entry); + + /* --------- Gradient map menu ---------------- */ + + dint.grad_map = option_menu_grad = gtk_option_menu_new (); + gtk_table_attach (GTK_TABLE (otable), option_menu_grad, 2, 3, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gradmenu = gimp_drawable_menu_new (warp_map_constrain, warp_map_grad_callback, + drawable, dvals.grad_map); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu_grad), gradmenu); + gtk_tooltips_set_tip (tooltips, option_menu_grad, "Gradient map selection menu", NULL); + + gtk_widget_show (option_menu_grad); + + + + /* ---------------------------------------------- */ + + + label = gtk_label_new ("Vector Mag"); + gtk_table_attach (GTK_TABLE (otable), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + dint.vector_scale = entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (otable), entry, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_set_usize (entry, ENTRY_WIDTH, 0); + sprintf (buffer, "%3.3f", dvals.vector_scale); + gtk_entry_set_text (GTK_ENTRY (entry), buffer); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + (GtkSignalFunc) warp_entry_callback, + &dvals.vector_scale); + gtk_widget_show (entry); + + /* -------------------------------------------------------- */ + label = gtk_label_new ("Angle"); + gtk_table_attach (GTK_TABLE (otable), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + dint.vector_angle = entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (otable), entry, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_set_usize (entry, ENTRY_WIDTH, 0); + sprintf (buffer, "%3.1f", dvals.vector_angle); + gtk_entry_set_text (GTK_ENTRY (entry), buffer); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + (GtkSignalFunc) warp_entry_callback, + &dvals.vector_angle); + gtk_widget_show (entry); + + /* --------- Vector map menu ---------------- */ + dint.vector_map = option_menu_vector = gtk_option_menu_new (); + gtk_table_attach (GTK_TABLE (otable), option_menu_vector, 2, 3, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + vectormenu = gimp_drawable_menu_new (warp_map_constrain, warp_map_vector_callback, + drawable, dvals.vector_map); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu_vector), vectormenu); + gtk_tooltips_set_tip (tooltips, option_menu_vector, "Fixed-direction-vector map selection menu", NULL); + + gtk_widget_show (option_menu_vector); + + /* -------------------------------------------------------- */ + + gtk_widget_show (otable); + gtk_widget_show (frame); + /* --------------------------------------------------------------- */ + + gtk_widget_show (dlg); + + gtk_main (); + gtk_object_unref (GTK_OBJECT (tooltips)); + gdk_flush (); + + /* determine wrap type */ + if (use_wrap) + dvals.wrap_type = WRAP; + else if (use_smear) + dvals.wrap_type = SMEAR; + else if (use_black) + dvals.wrap_type = BLACK; + else if (use_color) + dvals.wrap_type = COLOR; + + /* determine whether to use magnitude multiplier map */ + if (mag_use_yes) + dvals.mag_use = TRUE; + else if (mag_use_no) + dvals.mag_use = FALSE; + + return dint.run; +} +/* ---------------------------------------------------------------------- */ + +static void +blur16 (GDrawable *drawable) + /* blur a 2-or-more byte-per-pixel drawable, 1st 2 bytes interpreted as a 16-bit height field. */ +{ + GPixelRgn srcPR, destPR; + gint width, height; + gint src_bytes; + gint dest_bytes; + gint dest_bytes_inc; + gint offb, off1; + + guchar *dest, *d; /* pointers to rows of X and Y diff. data */ + guchar *prev_row, *pr; + guchar *cur_row, *cr; + guchar *next_row, *nr; + guchar *tmp; + gint row, col; /* relating to indexing into pixel row arrays */ + gint x1, y1, x2, y2; + gdouble pval; /* average pixel value of pixel & neighbors */ + + /* --------------------------------------- */ + + gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); + + width = drawable->width; /* size of input drawable*/ + height = drawable->height; + src_bytes = drawable->bpp; /* bytes per pixel in SOURCE drawable, must be 2 or more */ + dest_bytes = drawable->bpp; /* bytes per pixel in SOURCE drawable, >= 2 */ + dest_bytes_inc = dest_bytes - 2; /* this is most likely zero, but I guess it's more conservative... */ + + /* allocate row buffers for source & dest. data */ + + prev_row = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); + cur_row = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); + next_row = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); + dest = (guchar *) malloc ((x2 - x1) * src_bytes); + + /* initialize the pixel regions (read from source, write into dest) */ + gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); + gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE); + + pr = prev_row + src_bytes; /* row arrays are prepared for indexing to -1 (!) */ + cr = cur_row + src_bytes; + nr = next_row + src_bytes; + + diff_prepare_row (&srcPR, pr, x1, y1, (x2 - x1)); + diff_prepare_row (&srcPR, cr, x1, y1+1, (x2 - x1)); + + /* loop through the rows, applying the smoothing function */ + for (row = y1; row < y2; row++) + { + /* prepare the next row */ + diff_prepare_row (&srcPR, nr, x1, row + 1, (x2 - x1)); + + d = dest; + for (col = 0; col < (x2 - x1); col++) /* over columns of pixels */ + { + offb = col*src_bytes; /* base of byte pointer offset */ + off1 = offb+1; /* offset into row arrays */ + + pval = ( 256.0*pr[offb - src_bytes] + pr[off1 - src_bytes] + + 256.0*pr[offb] + pr[off1] + + 256.0*pr[offb + src_bytes] + pr[off1 + src_bytes] + + 256.0*cr[offb - src_bytes] + cr[off1 - src_bytes] + + 256.0*cr[offb] + cr[off1] + + 256.0*cr[offb + src_bytes] + cr[off1 + src_bytes] + + 256.0*nr[offb - src_bytes] + nr[off1 - src_bytes] + + 256.0*nr[offb] + nr[off1] + + 256.0*nr[offb + src_bytes]) + nr[off1 + src_bytes]; + + pval /= 9.0; /* take the average */ + *d++ = (guchar) (((gint)pval)>>8); /* high-order byte */ + *d++ = (guchar) (((gint)pval)%256); /* low-order byte */ + d += dest_bytes_inc; /* move data pointer on to next destination pixel */ + + } + /* store the dest */ + gimp_pixel_rgn_set_row (&destPR, dest, x1, row, (x2 - x1)); + + /* shuffle the row pointers */ + tmp = pr; + pr = cr; + cr = nr; + nr = tmp; + + if ((row % 5) == 0) + gimp_progress_update ((double) row / (double) (y2 - y1)); + } + + /* update the region */ + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->id, TRUE); + gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1)); + + free (prev_row); /* row buffers allocated at top of fn. */ + free (cur_row); + free (next_row); + free (dest); + +} /* end blur16() */ + + +/* ====================================================================== */ +/* Get one row of pixels from the PixelRegion and put them in 'data' */ + +static void +diff_prepare_row (GPixelRgn *pixel_rgn, + guchar *data, + int x, + int y, + int w) +{ + int b; + + if (y == 0) /* wrap around */ + gimp_pixel_rgn_get_row (pixel_rgn, data, x, (pixel_rgn->h - 1), w); + else if (y == pixel_rgn->h) + gimp_pixel_rgn_get_row (pixel_rgn, data, x, 1, w); + else + gimp_pixel_rgn_get_row (pixel_rgn, data, x, y, w); + + /* Fill in edge pixels */ + for (b = 0; b < pixel_rgn->bpp; b++) + { + data[-pixel_rgn->bpp + b] = data[b]; + data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b]; + } +} + +/* --------------------------------------------------------------------------------------------- */ +/* 'diff' combines the input drawables to prepare the two 16-bit (X,Y) vector displacement maps */ +/* --------------------------------------------------------------------------------------------- */ + +static void +diff (GDrawable *drawable, + gint32 *xl_id, + gint32 *yl_id ) +{ + GDrawable *draw_xd, *draw_yd; /* vector disp. drawables */ + GDrawable *mdraw, *vdraw, *gdraw; + gint32 image_id; /* image holding X and Y diff. arrays */ + gint32 new_image_id; /* image holding X and Y diff. layers */ + gint32 layer_active; /* currently active layer */ + gint32 xlayer_id, ylayer_id; /* individual X and Y layer ID numbers */ + GPixelRgn srcPR, destxPR, destyPR; + GPixelRgn vecPR, magPR, gradPR; + gint width, height; + gint src_bytes; + gint mbytes=0; + gint vbytes=0; + gint gbytes=0; /* bytes-per-pixel of various source drawables */ + gint dest_bytes; + gint dest_bytes_inc; + gint do_gradmap = FALSE; /* whether to add in gradient of gradmap to final diff. map */ + gint do_vecmap = FALSE; /* whether to add in a fixed vector scaled by the vector map */ + gint do_magmap = FALSE; /* whether to multiply result by the magnitude map */ + + guchar *destx, *dx, *desty, *dy; /* pointers to rows of X and Y diff. data */ + guchar *tmp; + guchar *prev_row, *pr; + guchar *cur_row, *cr; + guchar *next_row, *nr; + guchar *prev_row_g, *prg=NULL; /* pointers to gradient map data */ + guchar *cur_row_g, *crg=NULL; + guchar *next_row_g, *nrg=NULL; + guchar *cur_row_v, *crv=NULL; /* pointers to vector map data */ + guchar *cur_row_m, *crm=NULL; /* pointers to magnitude map data */ + gint row, col, offb, off, bytes; /* relating to indexing into pixel row arrays */ + gint x1, y1, x2, y2; + gint dvalx, dvaly; /* differential value at particular pixel */ + gdouble tx, ty; /* temporary x,y differential value increments from gradmap, etc. */ + gdouble rdx, rdy; /* x,y differential values: real #s */ + gdouble rscalefac; /* scaling factor for x,y differential of 'curl' map */ + gdouble gscalefac; /* scaling factor for x,y differential of 'gradient' map */ + gdouble r, theta, dtheta; /* rectangular<-> spherical coordinate transform for vector rotation */ + gdouble scale_vec_x, scale_vec_y; /* fixed vector X,Y component scaling factors */ + gint has_alpha, ind; + + /* -------------------------------------------------------------------------------------------------- */ + + if (dvals.grad_scale != 0.0) + do_gradmap = TRUE; /* add in gradient of gradmap if scale != 0.000 */ + if (dvals.vector_scale != 0.0) /* add in gradient of vectormap if scale != 0.000 */ + do_vecmap = TRUE; + do_magmap = (dvals.mag_use == TRUE); /* multiply by magnitude map if so requested */ + + /* Get the input area. This is the bounding box of the selection in + * the image (or the entire image if there is no selection). Only + * operating on the input area is simply an optimization. It doesn't + * need to be done for correct operation. (It simply makes it go + * faster, since fewer pixels need to be operated on). + */ + gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); + + /* Get the size of the input image. (This will/must be the same + * as the size of the output image. + */ + width = drawable->width; + height = drawable->height; + src_bytes = drawable->bpp; /* bytes per pixel in SOURCE drawable */ + has_alpha = gimp_drawable_has_alpha(drawable->id); + + /* -- Add two layers: X and Y Displacement vectors -- */ + /* -- I'm using a RGB drawable and using the first two bytes for a + 16-bit pixel value. This is either clever, or a kluge, + depending on your point of view. */ + + image_id = gimp_layer_get_image_id(drawable->id); + layer_active = gimp_image_get_active_layer(image_id); + + new_image_id = gimp_image_new(width, height, RGB); /* create new image for X,Y diff */ + + xlayer_id = gimp_layer_new(new_image_id, "Warp_X_Vectors", + width, height, + RGB_IMAGE, 100.0, NORMAL_MODE); + + ylayer_id = gimp_layer_new(new_image_id, "Warp_Y_Vectors", + width, height, + RGB_IMAGE, 100.0, NORMAL_MODE); + + draw_yd = gimp_drawable_get (ylayer_id); + draw_xd = gimp_drawable_get (xlayer_id); + + gimp_image_add_layer (new_image_id, xlayer_id, 1); + gimp_image_add_layer (new_image_id, ylayer_id, 1); + gimp_drawable_fill(xlayer_id, BG_IMAGE_FILL); + gimp_drawable_fill(ylayer_id, BG_IMAGE_FILL); + gimp_image_set_active_layer(image_id, layer_active); + + dest_bytes = draw_xd->bpp; /* bytes per pixel in destination drawable(s) */ + /* for a GRAYA drawable, I would expect this to be two bytes; any more would be excess */ + dest_bytes_inc = dest_bytes - 2; + + + /* allocate row buffers for source & dest. data */ + /* P.S. Hey, what happens if malloc returns NULL, hmmm..? */ + + prev_row = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); + cur_row = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); + next_row = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); + + prev_row_g = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); + cur_row_g = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); + next_row_g = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); + + cur_row_v = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); /* vector map */ + cur_row_m = (guchar *) malloc ((x2 - x1 + 2) * src_bytes); /* magnitude map */ + + destx = (guchar *) malloc ((x2 - x1) * dest_bytes); + desty = (guchar *) malloc ((x2 - x1) * dest_bytes); + + if ((desty==NULL) || (destx==NULL) || (cur_row_m==NULL) || (cur_row_v==NULL) + || (next_row_g==NULL) || (cur_row_g==NULL) || (prev_row_g==NULL) + || (next_row==NULL) || (cur_row==NULL) || (prev_row==NULL)) { + fprintf(stderr,"Warp diff: error allocating memory.\n"); + exit(1); + } + + /* initialize the source and destination pixel regions */ + gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); /* 'curl' vector-rotation input */ + gimp_pixel_rgn_init (&destxPR, draw_xd, 0, 0, width, height, TRUE, FALSE); /* destination: X diff output */ + gimp_pixel_rgn_init (&destyPR, draw_yd, 0, 0, width, height, TRUE, FALSE); /* Y diff output */ + + pr = prev_row + src_bytes; + cr = cur_row + src_bytes; + nr = next_row + src_bytes; + + diff_prepare_row (&srcPR, pr, x1, y1, (x2 - x1)); + diff_prepare_row (&srcPR, cr, x1, y1+1, (x2 - x1)); + + /* fixed-vector (x,y) component scale factors */ + scale_vec_x = dvals.vector_scale*cos((90-dvals.vector_angle)*M_PI/180.0)*256.0/10; + scale_vec_y = dvals.vector_scale*sin((90-dvals.vector_angle)*M_PI/180.0)*256.0/10; + + if (do_vecmap) { + /* fprintf(stderr,"%f %f x,y vector components.\n",scale_vec_x,scale_vec_y); */ + + vdraw = gimp_drawable_get(dvals.vector_map); + vbytes = vdraw->bpp; /* bytes per pixel in SOURCE drawable */ + gimp_pixel_rgn_init (&vecPR, vdraw, 0, 0, width, height, FALSE, FALSE); /* fixed-vector scale-map */ + crv = cur_row_v + vbytes; + diff_prepare_row (&vecPR, crv, x1, y1, (x2 - x1)); + } + if (do_gradmap) { + gdraw = gimp_drawable_get(dvals.grad_map); + gbytes = gdraw->bpp; + gimp_pixel_rgn_init (&gradPR, gdraw, 0, 0, width, height, FALSE, FALSE); /* fixed-vector scale-map */ + prg = prev_row_g + gbytes; + crg = cur_row_g + gbytes; + nrg = next_row_g + gbytes; + diff_prepare_row (&gradPR, prg, x1, y1 - 1, (x2 - x1)); + diff_prepare_row (&gradPR, crg, x1, y1, (x2 - x1)); + } + if (do_magmap) { + mdraw = gimp_drawable_get(dvals.mag_map); + mbytes = mdraw->bpp; + gimp_pixel_rgn_init (&magPR, mdraw, 0, 0, width, height, FALSE, FALSE); /* fixed-vector scale-map */ + crm = cur_row_m + mbytes; + diff_prepare_row (&magPR, crm, x1, y1, (x2 - x1)); + } + + dtheta = dvals.angle * M_PI / 180.0; + rscalefac = 256.0 / (3*src_bytes); /* note that '3' is rather arbitrary here. */ + gscalefac = dvals.grad_scale* 256.0 / (3*gbytes); /* scale factor for gradient map components */ + + /* loop through the rows, applying the differential convolution */ + for (row = y1; row < y2; row++) + { + /* prepare the next row */ + diff_prepare_row (&srcPR, nr, x1, row + 1, (x2 - x1)); + + if (do_magmap) + diff_prepare_row (&magPR, crm, x1, row + 1, (x2 - x1)); + if (do_vecmap) + diff_prepare_row (&vecPR, crv, x1, row + 1, (x2 - x1)); + if (do_gradmap) + diff_prepare_row (&gradPR, crg, x1, row + 1, (x2 - x1)); + + dx = destx; + dy = desty; + ind = 0; + + for (col = 0; col < (x2 - x1); col++) /* over columns of pixels */ + { + rdx = 0.0; + rdy = 0.0; + ty = 0.0; + tx = 0.0; + + offb = col*src_bytes; /* base of byte pointer offset */ + for (bytes=0; bytes < src_bytes; bytes++) /* add all channels together */ + { + off = offb+bytes; /* offset into row arrays */ + rdx += ((gint) -pr[off - src_bytes] + (gint) pr[off + src_bytes] + + (gint) -2*cr[off - src_bytes] + (gint) 2*cr[off + src_bytes] + + (gint) -nr[off - src_bytes] + (gint) nr[off + src_bytes]); + + rdy += ((gint) -pr[off - src_bytes] - (gint)2*pr[off] - (gint) pr[off + src_bytes] + + (gint) nr[off - src_bytes] + (gint)2*nr[off] + (gint) nr[off + src_bytes]); + } + + rdx *= rscalefac; /* take average, then reduce. Assume max. rdx now 65535 */ + rdy *= rscalefac; /* take average, then reduce */ + + theta = atan2(rdy,rdx); /* convert to polar, then back to rectang. coords */ + r = sqrt(rdy*rdy + rdx*rdx); + theta += dtheta; /* rotate gradient vector by this angle (radians) */ + rdx = r * cos(theta); + rdy = r * sin(theta); + + if (do_gradmap) { + + offb = col*gbytes; /* base of byte pointer offset into pixel values (R,G,B,Alpha, etc.) */ + for (bytes=0; bytes < src_bytes; bytes++) /* add all channels together */ + { + off = offb+bytes; /* offset into row arrays */ + tx += ((gint) -prg[off - gbytes] + (gint) prg[off + gbytes] + + (gint) -2*crg[off - gbytes] + (gint) 2*crg[off + gbytes] + + (gint) -nrg[off - gbytes] + (gint) nrg[off + gbytes]); + + ty += ((gint) -prg[off - gbytes] - (gint)2*prg[off] - (gint) prg[off + gbytes] + + (gint) nrg[off - gbytes] + (gint)2*nrg[off] + (gint) nrg[off + gbytes]); + } + tx *= gscalefac; + ty *= gscalefac; + + rdx += tx; /* add gradient component in to the other one */ + rdy += ty; + + } /* if (do_gradmap) */ + + + if (do_vecmap) { /* add in fixed vector scaled by vec. map data */ + tx = (gdouble) crv[col*vbytes]; /* use first byte only */ + rdx += scale_vec_x * tx; + rdy += scale_vec_y * tx; + + } /* if (do_vecmap) */ + + if (do_magmap) { /* multiply result by mag. map data */ + tx = (gdouble) crm[col*mbytes]; + rdx = (rdx * tx)/(255.0); + rdy = (rdy * tx)/(255.0); + + } /* if do_magmap */ + + + dvalx = rdx + (2<<14); /* take zero point to be 2^15, since this is two bytes */ + dvaly = rdy + (2<<14); + + if (dvalx<0) dvalx=0; + if (dvalx>65535) dvalx=65535; + *dx++ = (guchar) (dvalx >> 8); /* store high order byte in value channel */ + *dx++ = (guchar) (dvalx % 256); /* store low order byte in alpha channel */ + dx += dest_bytes_inc; /* move data pointer on to next destination pixel */ + + if (dvaly<0) dvaly=0; + if (dvaly>65535) dvaly=65535; + *dy++ = (guchar) (dvaly >> 8); + *dy++ = (guchar) (dvaly % 256); + dy += dest_bytes_inc; + + } /* ------------------------------- for (col...) --------------------------- */ + + /* store the dest */ + gimp_pixel_rgn_set_row (&destxPR, destx, x1, row, (x2 - x1)); + gimp_pixel_rgn_set_row (&destyPR, desty, x1, row, (x2 - x1)); + + /* swap around the pointers to row buffers */ + tmp = pr; + pr = cr; + cr = nr; + nr = tmp; + + if (do_gradmap) { + tmp = prg; + prg = crg; + crg = nrg; + nrg = tmp; + } + + if ((row % 5) == 0) + gimp_progress_update ((double) row / (double) (y2 - y1)); + + } /* for (row..) */ + + /* update the region */ + gimp_drawable_flush (draw_xd); + gimp_drawable_flush (draw_yd); + + gimp_drawable_update (draw_xd->id, x1, y1, (x2 - x1), (y2 - y1)); + gimp_drawable_update (draw_yd->id, x1, y1, (x2 - x1), (y2 - y1)); + + /* + if (display_diff_map) { + gimp_display_new(new_image_id); + } + */ + + gimp_displays_flush(); /* make sure layer is visible */ + + gimp_progress_init ("Smoothing X gradient..."); + blur16(draw_xd); + gimp_progress_init ("Smoothing Y gradient..."); + blur16(draw_yd); + + free (prev_row); /* row buffers allocated at top of fn. */ + free (cur_row); + free (next_row); + free (prev_row_g); /* row buffers allocated at top of fn. */ + free (cur_row_g); + free (next_row_g); + free (cur_row_v); + free (cur_row_m); + + free (destx); + free (desty); + + *xl_id = xlayer_id; /* pass back the X and Y layer ID numbers */ + *yl_id = ylayer_id; + +} /* end diff() */ + +/* -------------------------------------------------------------------------------- */ +/* The Warp displacement is done here. */ +/* -------------------------------------------------------------------------------- */ + +static void +warp (GDrawable *orig_draw, + GDrawable **map_x, + GDrawable **map_y ) +{ + GDrawable *disp_map; /* Displacement map, ie, control array */ + GDrawable *mag_draw; /* Magnitude multiplier factor map */ + + gchar string[80]; /* string to hold title of progress bar window */ + + gint first_time = TRUE; + gint width; + gint height; + gint bytes; + gint orig_image_id; + gint image_type; + + + gint x1, y1, x2, y2; + + gint32 xdlayer = -1; + gint32 ydlayer = -1; + + gint warp_iter; /* index var. over all "warp" Displacement iterations */ + + + disp_map = gimp_drawable_get(dvals.warp_map); + mag_draw = gimp_drawable_get(dvals.mag_map); + + /* calculate new X,Y Displacement image maps */ + + gimp_progress_init ("Finding XY gradient..."); + + diff(disp_map, &xdlayer, &ydlayer); /* generate x,y differential images (arrays) */ + + /* Get selection area */ + gimp_drawable_mask_bounds (orig_draw->id, &x1, &y1, &x2, &y2); + + width = orig_draw->width; + height = orig_draw->height; + bytes = orig_draw->bpp; + image_type = gimp_drawable_type(orig_draw->id); + + *map_x = gimp_drawable_get(xdlayer); + *map_y = gimp_drawable_get(ydlayer); + + orig_image_id = gimp_layer_get_image_id(orig_draw->id); + + /* gimp_image_lower_layer(orig_image_id, new_layer_id); */ /* hide it! */ + + /* gimp_layer_set_opacity(new_layer_id, 0.0); */ + + for (warp_iter = 0; warp_iter < dvals.iter; warp_iter++) + { + if (run_mode != RUN_NONINTERACTIVE) { + sprintf(string,"Flow Step %d...",warp_iter+1); + gimp_progress_init (string); + progress = 0; + gimp_progress_update (0); + } + warp_one(orig_draw, orig_draw, *map_x, *map_y, mag_draw, first_time, warp_iter); + + /* + sprintf(string,"Background Step %d...",warp_iter+1); + gimp_progress_init (string); + progress = 0; + warp_one(new_image, orig_draw, *map_x, *map_y, mag_draw, FALSE, warp_iter); + */ + + gimp_drawable_update (orig_draw->id, x1, y1, (x2 - x1), (y2 - y1)); + + if (run_mode != RUN_NONINTERACTIVE) + gimp_displays_flush(); + + + first_time = FALSE; + + } /* end for (warp_iter) */ + + /* gimp_image_add_layer (orig_image_id, new_layer_id, 1); */ /* make layer visible in 'layers' dialog */ + +} /* Warp */ + +/* -------------------------------------------------------------------------------- */ + +static void +warp_one(GDrawable *draw, + GDrawable *new, + GDrawable *map_x, + GDrawable *map_y, + GDrawable *mag_draw, + gint first_time, + gint step ) +{ + GPixelRgn src_rgn; + GPixelRgn dest_rgn; + GPixelRgn map_x_rgn; + GPixelRgn map_y_rgn; + GPixelRgn mag_rgn; + GTile * tile = NULL; + GTile * xtile = NULL; + GTile * ytile = NULL; + gint row=-1; + gint xrow=-1; + gint yrow=-1; + gint col=-1; + gint xcol=-1; + gint ycol=-1; + + gpointer pr; + + gint width = -1; + gint height = -1; + gint dest_bytes=-1; + gint dmap_bytes=-1; + + guchar *destrow, *dest; + guchar *srcrow, *src; + guchar *mxrow=NULL, *mx; /* NULL ptr. to make gcc's -Wall fn. happy */ + guchar *myrow=NULL, *my; + + guchar *mmagrow=NULL, *mmag=NULL; + guchar pixel[4][4]; + gint x1, y1, x2, y2; + gint x, y; + gint max_progress; + + gdouble needx, needy; + gdouble xval=0; /* initialize to quiet compiler grumbles */ + gdouble yval=0; /* interpolated vector displacement */ + gdouble scalefac; /* multiplier for vector displacement scaling */ + gdouble dscalefac; /* multiplier for incremental displacement vectors */ + gint xi, yi; + gint substep; /* loop variable counting displacement vector substeps */ + + guchar values[4]; + gint ivalues[4]; + guchar val; + + gint k; + + gdouble dx, dy; /* X and Y Displacement, integer from GRAY map */ + + gint xm_alpha = 0; + gint ym_alpha = 0; + gint mmag_alpha = 0; + gint xm_bytes = 1; + gint ym_bytes = 1; + gint mmag_bytes = 1; + + + srand(time(NULL)); /* seed random # generator */ + + /* ================ Outer Loop calculation =================================== */ + + /* Get selection area */ + + gimp_drawable_mask_bounds (draw->id, &x1, &y1, &x2, &y2); + width = draw->width; + height = draw->height; + dest_bytes = draw->bpp; + + dmap_bytes = map_x->bpp; + + max_progress = (x2 - x1) * (y2 - y1); + + + /* --------- Register the (many) pixel regions ---------- */ + + gimp_pixel_rgn_init (&src_rgn, draw, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); + + /* only push undo-stack the first time through. Thanks Spencer! */ + if (first_time==TRUE) + gimp_pixel_rgn_init (&dest_rgn, new, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); + else + /* gimp_pixel_rgn_init (&dest_rgn, new, x1, y1, (x2 - x1), (y2 - y1), TRUE, FALSE); */ + gimp_pixel_rgn_init (&dest_rgn, new, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); + + + gimp_pixel_rgn_init (&map_x_rgn, map_x, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); + if (gimp_drawable_has_alpha(map_x->id)) + xm_alpha = 1; + xm_bytes = gimp_drawable_bpp(map_x->id); + + gimp_pixel_rgn_init (&map_y_rgn, map_y, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); + if (gimp_drawable_has_alpha(map_y->id)) + ym_alpha = 1; + ym_bytes = gimp_drawable_bpp(map_y->id); + + + if (dvals.mag_use == TRUE) { + gimp_pixel_rgn_init (&mag_rgn, mag_draw, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); + if (gimp_drawable_has_alpha(mag_draw->id)) + mmag_alpha = 1; + mmag_bytes = gimp_drawable_bpp(mag_draw->id); + + pr = gimp_pixel_rgns_register (5, &src_rgn, &dest_rgn, &map_x_rgn, &map_y_rgn, &mag_rgn); + } else { + pr = gimp_pixel_rgns_register (4, &src_rgn, &dest_rgn, &map_x_rgn, &map_y_rgn); + } + + dscalefac = (dvals.amount) / (256* 127.5 * dvals.substeps); /* substep displacement vector scale factor */ + + + for (pr = pr; pr != NULL; pr = gimp_pixel_rgns_process (pr)) + { + + srcrow = src_rgn.data; + destrow = dest_rgn.data; + mxrow = map_x_rgn.data; + myrow = map_y_rgn.data; + if (dvals.mag_use == TRUE) + mmagrow = mag_rgn.data; + + /* loop over destination pixels */ + for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) + { + src = srcrow; + dest = destrow; + mx = mxrow; + my = myrow; + + if (dvals.mag_use == TRUE) + mmag = mmagrow; + + for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) + { + /* ----- Find displacement vector (amnt_x, amnt_y) ------------ */ + + dx = dscalefac * ((256.0*mx[0])+mx[1] -32768); /* 16-bit values */ + dy = dscalefac * ((256.0*my[0])+my[1] -32768); + + if (dvals.mag_use == TRUE) { + scalefac = warp_map_mag_give_value(mmag, mmag_alpha, mmag_bytes)/255.0; + dx *= scalefac; + dy *= scalefac; + } + + if (dvals.dither != 0.0) { /* random dither is +/- dvals.dither pixels */ + dx += dvals.dither*((gdouble)(rand() - (RAND_MAX >> 1)) / (RAND_MAX >> 1)); + dy += dvals.dither*((gdouble)(rand() - (RAND_MAX >> 1)) / (RAND_MAX >> 1)); + } + + if (dvals.substeps != 1) { /* trace (substeps) iterations of displacement vector */ + + for (substep = 1; substep < dvals.substeps; substep++) { + + needx = x + dx; /* In this (substep) loop, (x,y) remain fixed. (dx,dy) vary each step. */ + needy = y + dy; + + if (needx >= 0.0) xi = (int) needx; + else xi = -((int) -needx + 1); + + if (needy >= 0.0) yi = (int) needy; + else yi = -((int) -needy + 1); + + /* get 4 neighboring DX values from DiffX drawable for linear interpolation */ + xtile = warp_pixel (map_x, xtile, width, height, x1, y1, x2, y2, xi, yi, &xrow, &xcol, pixel[0]); + xtile = warp_pixel (map_x, xtile, width, height, x1, y1, x2, y2, xi + 1, yi, &xrow, &xcol, pixel[1]); + xtile = warp_pixel (map_x, xtile, width, height, x1, y1, x2, y2, xi, yi + 1, &xrow, &xcol, pixel[2]); + xtile = warp_pixel (map_x, xtile, width, height, x1, y1, x2, y2, xi + 1, yi + 1, &xrow, &xcol, pixel[3]); + + ivalues[0] = 256*pixel[0][0] + pixel[0][1]; + ivalues[1] = 256*pixel[1][0] + pixel[1][1]; + ivalues[2] = 256*pixel[2][0] + pixel[2][1]; + ivalues[3] = 256*pixel[3][0] + pixel[3][1]; + xval = bilinear16(needx, needy, ivalues); + + /* get 4 neighboring DY values from DiffY drawable for linear interpolation */ + ytile = warp_pixel (map_y, ytile, width, height, x1, y1, x2, y2, xi, yi, &yrow, &ycol, pixel[0]); + ytile = warp_pixel (map_y, ytile, width, height, x1, y1, x2, y2, xi + 1, yi, &yrow, &ycol, pixel[1]); + ytile = warp_pixel (map_y, ytile, width, height, x1, y1, x2, y2, xi, yi + 1, &yrow, &ycol, pixel[2]); + ytile = warp_pixel (map_y, ytile, width, height, x1, y1, x2, y2, xi + 1, yi + 1, &yrow, &ycol, pixel[3]); + + ivalues[0] = 256*pixel[0][0] + pixel[0][1]; + ivalues[1] = 256*pixel[1][0] + pixel[1][1]; + ivalues[2] = 256*pixel[2][0] + pixel[2][1]; + ivalues[3] = 256*pixel[3][0] + pixel[3][1]; + yval = bilinear16(needx, needy, ivalues); + + dx += dscalefac * (xval-32768); /* move displacement vector to this new value */ + dy += dscalefac * (yval-32768); + + } /* for (substep) */ + } /* if (substeps != 0) */ + + + /* --------------------------------------------------------- */ + + needx = x + dx; + needy = y + dy; + + mx += xm_bytes; /* pointers into x,y displacement maps */ + my += ym_bytes; + + if (dvals.mag_use == TRUE) + mmag += mmag_bytes; + + /* Calculations complete; now copy the proper pixel */ + + if (needx >= 0.0) + xi = (int) needx; + else + xi = -((int) -needx + 1); + + if (needy >= 0.0) + yi = (int) needy; + else + yi = -((int) -needy + 1); + + /* get 4 neighboring pixel values from source drawable for linear interpolation */ + tile = warp_pixel (draw, tile, width, height, x1, y1, x2, y2, xi, yi, &row, &col, pixel[0]); + tile = warp_pixel (draw, tile, width, height, x1, y1, x2, y2, xi + 1, yi, &row, &col, pixel[1]); + tile = warp_pixel (draw, tile, width, height, x1, y1, x2, y2, xi, yi + 1, &row, &col, pixel[2]); + tile = warp_pixel (draw, tile, width, height, x1, y1, x2, y2, xi + 1, yi + 1, &row, &col, pixel[3]); + + for (k = 0; k < dest_bytes; k++) + { + values[0] = pixel[0][k]; + values[1] = pixel[1][k]; + values[2] = pixel[2][k]; + values[3] = pixel[3][k]; + val = bilinear(needx, needy, values); + + *dest++ = val; + } /* for k */ + + } /* for x */ + + /* srcrow += src_rgn.rowstride; */ + srcrow += src_rgn.rowstride; + destrow += dest_rgn.rowstride; + mxrow += map_x_rgn.rowstride; + myrow += map_y_rgn.rowstride; + if (dvals.mag_use == TRUE) + mmagrow += mag_rgn.rowstride; + + } /* for y */ + + progress += (dest_rgn.w * dest_rgn.h); + gimp_progress_update ((double) progress / (double) max_progress); + + + } /* for pr */ + + if (tile != NULL) + gimp_tile_unref (tile, FALSE); + + if (xtile != NULL) + gimp_tile_unref (xtile, FALSE); + + if (ytile != NULL) + gimp_tile_unref (ytile, FALSE); + + /* update the region */ + gimp_drawable_flush (new); + + gimp_drawable_merge_shadow(draw->id, (first_time == TRUE)); + +} /* warp_one */ + +/* -------------------------------------------------------------------------------- */ + +static gdouble +warp_map_mag_give_value(guchar *pt, gint alpha, gint bytes) +{ + gdouble ret, val_alpha; + + if (bytes >= 3) + ret = (pt[0] + pt[1] + pt[2])/3.0; + else + ret = (gdouble) *pt; + + if (alpha) + { + val_alpha = pt[bytes - 1]; + ret = (ret * val_alpha / 255.0); + }; + + return (ret); +} + + +static GTile * +warp_pixel (GDrawable * drawable, + GTile * tile, + gint width, + gint height, + gint x1, + gint y1, + gint x2, + gint y2, + gint x, + gint y, + gint * row, + gint * col, + guchar * pixel) +{ + static guchar empty_pixel[4] = {0, 0, 0, 0}; + guchar *data; + gint b; + + /* Tile the image. */ + if (dvals.wrap_type == WRAP) + { + if (x < 0) + x = width - (-x % width); + else + x %= width; + + if (y < 0) + y = height - (-y % height); + else + y %= height; + } + /* Smear out the edges of the image by repeating pixels. */ + else if (dvals.wrap_type == SMEAR) + { + if (x < 0) + x = 0; + else if (x > width - 1) + x = width - 1; + + if (y < 0) + y = 0; + else if (y > height - 1) + y = height - 1; + } + + if (x >= x1 && y >= y1 && x < x2 && y < y2) + { + if ((( (guint) (x / tile_width)) != *col) || (( (guint) (y / tile_height)) != *row)) + { + *col = x / tile_width; + *row = y / tile_height; + if (tile) + gimp_tile_unref (tile, FALSE); + tile = gimp_drawable_get_tile (drawable, FALSE, *row, *col); + gimp_tile_ref (tile); + } + + data = tile->data + tile->bpp * (tile->ewidth * (y % tile_height) + (x % tile_width)); + } + else + { + if (dvals.wrap_type == BLACK) + data = empty_pixel; + else + data = color_pixel; /* must have selected COLOR type */ + } + + for (b = 0; b < drawable->bpp; b++) + pixel[b] = data[b]; + + return tile; +} + + +static guchar +bilinear (gdouble x, gdouble y, guchar *v) +{ + gdouble m0, m1; + + x = fmod(x, 1.0); + y = fmod(y, 1.0); + + if (x < 0) + x += 1.0; + if (y < 0) + y += 1.0; + + m0 = (gdouble) v[0] + x * ((gdouble) v[1] - v[0]); + m1 = (gdouble) v[2] + x * ((gdouble) v[3] - v[2]); + + return (guchar) (m0 + y * (m1 - m0)); +} /* bilinear */ + +static gint +bilinear16 (gdouble x, gdouble y, gint *v) +{ + gdouble m0, m1; + + x = fmod(x, 1.0); + y = fmod(y, 1.0); + + if (x < 0) + x += 1.0; + if (y < 0) + y += 1.0; + + m0 = (gdouble) v[0] + x * ((gdouble) v[1] - v[0]); + m1 = (gdouble) v[2] + x * ((gdouble) v[3] - v[2]); + + return (gint) (m0 + y * (m1 - m0)); +} /* bilinear16 */ + + +/* Warp interface functions */ + +static gint +warp_map_constrain (gint32 image_id, + gint32 drawable_id, + gpointer data) +{ + GDrawable *drawable; + + drawable = (GDrawable *) data; + + if (drawable_id == -1) + return TRUE; + + if (gimp_drawable_width (drawable_id) == drawable->width && + gimp_drawable_height (drawable_id) == drawable->height) + return TRUE; + else + return FALSE; +} + +static void +warp_map_callback (gint32 id, + gpointer data) +{ + dvals.warp_map = id; +} + +static void +warp_map_mag_callback (gint32 id, + gpointer data) +{ + dvals.mag_map = id; +} + +static void +warp_map_grad_callback (gint32 id, + gpointer data) +{ + dvals.grad_map = id; +} + +static void +warp_map_vector_callback (gint32 id, + gpointer data) +{ + dvals.vector_map = id; +} + + +static void +warp_close_callback (GtkWidget *widget, + gpointer data) +{ + gtk_main_quit (); +} + +static void +warp_ok_callback (GtkWidget *widget, + gpointer data) +{ + dint.run = TRUE; + gtk_widget_destroy (GTK_WIDGET (data)); +} + +static void +warp_toggle_update (GtkWidget *widget, + gpointer data) +{ + int *toggle_val; + + toggle_val = (int *) data; + + if (GTK_TOGGLE_BUTTON (widget)->active) + *toggle_val = TRUE; + else + *toggle_val = FALSE; +} + +static void +warp_entry_callback (GtkWidget *widget, + gpointer data) +{ + gdouble *text_val; + + text_val = (gdouble *) data; + + *text_val = atof (gtk_entry_get_text (GTK_ENTRY (widget))); +} + +static void +warp_entry_int_callback (GtkWidget *widget, + gpointer data) +{ + gint *text_val; + + text_val = (gint *) data; + + *text_val = (gint) atof(gtk_entry_get_text (GTK_ENTRY (widget))); +} diff --git a/plug-ins/script-fu/scripts/frosty-logo.scm b/plug-ins/script-fu/scripts/frosty-logo.scm index 6c3bd7695f..51280074c4 100644 --- a/plug-ins/script-fu/scripts/frosty-logo.scm +++ b/plug-ins/script-fu/scripts/frosty-logo.scm @@ -38,7 +38,7 @@ (plug-in-noisify 1 img sparkle-layer FALSE 0.2 0.2 0.2 0.0) (plug-in-c-astretch 1 img sparkle-layer) (gimp-selection-none img) - (plug-in-sparkle 1 img sparkle-layer 0.03 0.45 (/ (min width height) 2) 6 15) + (plug-in-sparkle 1 img sparkle-layer 0.03 0.45 (/ (min width height) 2) 6 15 1.0 1.0 0.0 0.0 FALSE FALSE FALSE 0) (gimp-levels sparkle-layer 1 0 255 0.2 0 255) (gimp-levels sparkle-layer 2 0 255 0.7 0 255) (gimp-selection-layer-alpha sparkle-layer) diff --git a/plug-ins/script-fu/scripts/starburst-logo.scm b/plug-ins/script-fu/scripts/starburst-logo.scm index b631d82273..0bc7774e2c 100644 --- a/plug-ins/script-fu/scripts/starburst-logo.scm +++ b/plug-ins/script-fu/scripts/starburst-logo.scm @@ -45,7 +45,7 @@ (gimp-edit-fill layer-mask) (gimp-selection-none img) (plug-in-nova 1 img burst-layer (car burst-coords) (cdr burst-coords) - burst-color burstradius 100) + burst-color burstradius 100 0) (gimp-selection-layer-alpha text-layer) (gimp-palette-set-background '(0 0 0)) diff --git a/plug-ins/script-fu/scripts/starscape-logo.scm b/plug-ins/script-fu/scripts/starscape-logo.scm index ad0a4975e3..6cc0b7f367 100644 --- a/plug-ins/script-fu/scripts/starscape-logo.scm +++ b/plug-ins/script-fu/scripts/starscape-logo.scm @@ -88,7 +88,7 @@ (gimp-palette-set-foreground '(255 255 255)) (gimp-blend text-layer FG-BG-RGB NORMAL BILINEAR 100 0 REPEAT-NONE FALSE 0 0 cx cy bx by) - (plug-in-nova 1 img glow-layer novax novay glow-color novaradius 100) + (plug-in-nova 1 img glow-layer novax novay glow-color novaradius 100 0) (gimp-selection-all img) (gimp-patterns-set-pattern "Stone") diff --git a/plug-ins/script-fu/scripts/t-o-p-logo.scm b/plug-ins/script-fu/scripts/t-o-p-logo.scm index 8a36d22f09..f589ad7c1b 100644 --- a/plug-ins/script-fu/scripts/t-o-p-logo.scm +++ b/plug-ins/script-fu/scripts/t-o-p-logo.scm @@ -38,7 +38,7 @@ (gimp-selection-border img edge-size) (plug-in-noisify 1 img sparkle-layer FALSE hit-rate hit-rate hit-rate 0.0) (gimp-selection-none img) - (plug-in-sparkle 1 img sparkle-layer 0.03 0.45 width 6 15) + (plug-in-sparkle 1 img sparkle-layer 0.03 0.45 width 6 15 1.0 1.0 0.0 0.0 FALSE FALSE FALSE 0) (gimp-selection-load selection) (gimp-selection-shrink img edge-size) (gimp-levels sparkle-layer 0 0 255 1.2 0 255)