/* Water Surface -- creates waves textures plug-in. * Copyright (C) 2001 Kyoichiro Suda * * 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. */ /* Water Surface plug-in version 1.7, Mar 2002 * This plug-in draw waves like a water surface. * * Changes * add reset button * * TODO * sort paramaters * pickup last previewed timeseed */ #include #include #include #include #include #include /* #include "libgimp/stdplugins-intl.h" */ #include #ifndef PACKAGE #define PACKAGE "gimp-plugins-das" #endif #ifdef ENABLE_NLS #define INIT_I18N() G_STMT_START{ \ setlocale(LC_MESSAGES, ""); \ bindtextdomain("gimp-libgimp", LOCALEDIR); \ bindtextdomain(PACKAGE, LOCALEDIR); \ textdomain(PACKAGE); \ }G_STMT_END #else #define INIT_I18N() G_STMT_START{ \ bindtextdomain("gimp-libgimp", LOCALEDIR); \ bindtextdomain(PACKAGE, LOCALEDIR); \ textdomain(PACKAGE); \ }G_STMT_END #endif #define INIT_I18N_UI() G_STMT_START{ \ gtk_set_locale(); \ setlocale (LC_NUMERIC, "C"); \ INIT_I18N(); \ }G_STMT_END /*---- Defines ----*/ #define PLUG_IN_NAME "plug_in_water_surface" #define PLUG_IN_VERSION "Water Surface 1.7" #define PREVIEW_SIZE 100 #define SCALE_WIDTH 100 /*---- enum ----*/ typedef enum { LINEAR, SINUSOIDAL, SPHERICAL, SAWTOOTH, TRIANGULAR, POTTER, HALFPIPE, } wave_styles; typedef enum { AVERAGE, TERRITORY, GREATER, LESSER, } wave_modes; typedef enum { NOISE_NONE, NOISE_ALL, NOISE_FLAT, NOISE_WAVE, } noise_modes; /*---- Typedefs ----*/ typedef struct { gint points; gint timeseed; gint seed; gdouble range; gdouble width; gdouble disorder; gdouble decay; gdouble dephase; gdouble direction; gdouble intensity; gdouble converge; gdouble shift_x; gdouble shift_y; gint tilable; gdouble flat; gdouble phase; gint style; gint mode; gint areas; gint steeple; gint nmode; gdouble noise; } WSurfaceValues; typedef struct { GtkSpinButton *points; GtkToggleButton *timeseed; GtkSpinButton *seed; GtkAdjustment *range; GtkAdjustment *width; GtkAdjustment *disorder; GtkAdjustment *decay; GtkAdjustment *dephase; GtkAdjustment *direction; GtkAdjustment *intensity; GtkAdjustment *converge; GtkAdjustment *shift_x; GtkAdjustment *shift_y; GtkToggleButton *tilable; GtkSpinButton *flat; GtkAdjustment *phase; GtkOptionMenu *style; GtkOptionMenu *mode; GtkToggleButton *areas; GtkToggleButton *steeple; GtkOptionMenu *nmode; GtkSpinButton *noise; GtkSpinButton *anim_frames; } WSurfaceWidgets; typedef struct { gdouble xpos; gdouble ypos; gdouble width; gdouble vanish; gdouble phase; } Waves; typedef struct { guchar fg[4]; guchar bg[4]; } Color; /*---- Prototypes ----*/ static void query (void); static void run (gchar *name, gint nparams, GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); static void water_surface (GimpDrawable *drawable); static void water_surface_anim (gint32 image_ID, GimpDrawable *drawable); static void subvals_init (gint width, gint height); static Waves *waves_new (Waves *waves, gint width, gint height); static Waves *waves_tilable (Waves *waves, gint width, gint height); static gint render_waves (Waves *waves, GimpPixelRgn *region); static gdouble waves_areas (Waves *point, gdouble cycle, gdouble level); static gdouble pixel_level (Waves *waves, gfloat x, gfloat y); static void waves_distance (Waves *point, gdouble x, gdouble y, gdouble *length, gdouble *vanish, gdouble *cycle); static gdouble waves_level (wave_styles style, gdouble cycle); static void pixel_coloring (guchar *pixel, gdouble level); static void preview_water_surface (GimpDrawable *drawable); static GtkWidget *preview_widget (GimpDrawable *drawable); static void preview_update (GtkObject *obj, gpointer data); static void ws_int_adjustment_update (GtkAdjustment *adjustment, gpointer data); static void ws_double_adjustment_update (GtkAdjustment *adjustment, gpointer data); static void ws_toggle_button_update (GtkWidget *toggle, gpointer data); static void ws_menu_item_update (GtkWidget *widget, gpointer data); static gint water_surface_dialog (GimpDrawable *drawable); static void dialog_ok_callback (GtkWidget *widget, gpointer data); static void dialog_ok_callback_anim (GtkWidget *widget, gpointer data); static void dialog_reset_callback (GtkWidget *widget, gpointer data); static void vals_init (WSurfaceValues *destvalsptr); /*---- Variables ----*/ GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run /* run_proc */ }; static WSurfaceValues vals; static WSurfaceValues subvals ; const WSurfaceValues vals_default = { 16, /* points */ FALSE, /* seed_type */ 5910, /* seed */ 2.000, /* range */ 0.300, /* width */ 0.500, /* disorder */ 0.000, /* decay */ 1.000, /* dephase */ 0.000, /* horizontal angle */ 0.000, /* vertical angle */ 0.000, /* convergence */ 0.000, /* shift_x */ 0.000, /* shift_y */ FALSE, /* tilable */ 0.500, /* flat */ 0.000, /* phase */ HALFPIPE, /* style */ TERRITORY, /* mode */ FALSE, /* anti areasing */ FALSE, /* file steeple */ NOISE_NONE, /* noise mode */ 0.500, /* noise */ }; static WSurfaceWidgets wsdlg; static Color color; static gint has_alpha; static gint channels; static GtkWidget *preview; static GimpDrawable *_drawable; static gint do_preview = TRUE; static gint make_anim = FALSE; static gint anim_frames = 8; typedef struct { gint run; } WSurfaceInterface; static WSurfaceInterface wint = { FALSE /* have we run? */ }; MAIN () static void query () { static GimpParamDef args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }, { GIMP_PDB_INT32, "points", "Number of wave points ( > 1)" }, { GIMP_PDB_INT32, "timeseed", "Use time seed (TRUE/FALSE)" }, { GIMP_PDB_INT32, "seed", "Random seed" }, { GIMP_PDB_FLOAT, "range", "Generation range ( > 0)" }, { GIMP_PDB_FLOAT, "width", "Ratio of Wavelength ( > 0)" }, { GIMP_PDB_FLOAT, "disorder", "Disorder of width (0.0 - 1.0)" }, { GIMP_PDB_FLOAT, "decay", "Decay ratio of wave (0 = eternity)" }, { GIMP_PDB_FLOAT, "dephase", "Dephase of waves (0.0 - 1.0)" }, { GIMP_PDB_FLOAT, "direction", "Direction of stream current (0.0 - 12.0)"}, { GIMP_PDB_FLOAT, "intensity", "Intensity of stream current (0.0 - 1.0)" }, { GIMP_PDB_FLOAT, "converge", "convergence in wave (0.0 - 2.0)" }, { GIMP_PDB_FLOAT, "shift_x", "Total displacement on X axis" }, { GIMP_PDB_FLOAT, "shift_y", "Total displacement on Y axis" }, { GIMP_PDB_INT32, "tilable", "Create a tilable output (TRUE/FALSE)" }, { GIMP_PDB_FLOAT, "flat", "Level to gain (0.0 - 1.0)" }, { GIMP_PDB_FLOAT, "phase", "Phase of cycle(0.0 - 1.0)" }, { GIMP_PDB_INT32, "style", "Mode of forming level (0: Linear, 1: Sinusoidal, 2: Sawtooth, 3: Triangular, 4: Potter, 5: Halfpipe)" }, { GIMP_PDB_INT32, "mode", "Mode of mixing level (0: Average, 1: Territory, 2: Greater, 3: Lesser)" }, { GIMP_PDB_INT32, "areas", "Anti areasing (TRUE/FALSE)" }, { GIMP_PDB_INT32, "steeple","File down steeple of center (TRUE/FALSE)"}, { GIMP_PDB_INT32, "nmode", "Mode of noise (0: None, 1: All, 2: on Flat, 3: on Wave)" }, { GIMP_PDB_FLOAT, "noise", "Random noise (0.0 - 1.0)" } }; static gint nargs = sizeof (args) / sizeof (args[0]); gimp_install_procedure (PLUG_IN_NAME, "Generate waves texture", "Generate waves texture like the water surface, " "it can make abstract image with many waves, " "also pop style with symple mathmatics.", "Kyoichiro Suda ", "Kyoichiro Suda", "Aug 2001", N_("/Filters/Render/Nature/Water Surface..."), "RGB*, GRAY*", GIMP_PLUGIN, nargs, 0, args, NULL); } static void run (gchar *name, gint nparams, GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; gint32 image_ID; GimpDrawable *drawable; GimpRunModeType run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; //gchar prog_label[32]; run_mode = param[0].data.d_int32; image_ID = param[1].data.d_int32; drawable = gimp_drawable_get(param[2].data.d_drawable); _drawable = drawable; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; *nreturn_vals = 1; *return_vals = values; INIT_I18N_UI (); if (gimp_drawable_is_rgb (drawable->id) || gimp_drawable_is_gray (drawable->id)) { switch (run_mode) { case GIMP_RUN_INTERACTIVE: if (!gimp_get_data (PLUG_IN_NAME, &vals)) vals_init (&vals); if (!water_surface_dialog (drawable)) /* return on Cancel */ return; break; case GIMP_RUN_NONINTERACTIVE: if ((strcmp (name, PLUG_IN_NAME) == 0) && (nparams == 25)) { vals.points = (gint) param[3].data.d_int32; vals.points = (gint) CLAMP (vals.points, 0, 255); vals.timeseed = (param[4].data.d_int32) ? TRUE : FALSE; vals.seed = (gint) param[5].data.d_int32; vals.range = (gdouble) param[6].data.d_float; vals.range = (gdouble) MAX (0, vals.range); vals.width = (gdouble) param[7].data.d_float; vals.width = (gdouble) MAX (0, vals.width); vals.disorder = (gdouble) param[8].data.d_float; vals.disorder = (gdouble) CLAMP (vals.disorder, 0, 1); vals.decay = (gdouble) param[9].data.d_float; vals.decay = (gdouble) MAX (0, vals.decay); vals.dephase = (gdouble) param[10].data.d_float; vals.dephase = (gdouble) CLAMP (vals.dephase, 0, 1); vals.direction = (gdouble) param[11].data.d_float; vals.direction = (gdouble) fmod(vals.direction, 12.0); vals.intensity = (gdouble) param[12].data.d_float; vals.intensity = (gdouble) CLAMP (vals.direction, 0, 1); vals.converge = (gdouble) param[13].data.d_float; vals.converge = (gdouble) CLAMP (vals.converge, 0, 2); vals.shift_x = (gdouble) param[14].data.d_float; vals.shift_y = (gdouble) param[15].data.d_float; vals.tilable = (param[16].data.d_int32) ? TRUE : FALSE; vals.flat = (gdouble) param[17].data.d_float; vals.flat = (gdouble) CLAMP (vals.flat, 0, 1); vals.phase = (gdouble) param[18].data.d_float; vals.phase = (gdouble) CLAMP (vals.phase, 0, 1); vals.style = (gint) param[19].data.d_int32; vals.style = (gint) CLAMP (vals.style, 0, 7); vals.mode = (gint) param[20].data.d_int32; vals.mode = (gint) CLAMP (vals.mode, 0, 3); vals.areas = (param[21].data.d_int32) ? TRUE : FALSE; vals.steeple = (param[22].data.d_int32) ? TRUE : FALSE; vals.nmode = (gint) param[23].data.d_int32; vals.nmode = (gint) CLAMP (vals.nmode, 0, 3); vals.noise = (gdouble) param[24].data.d_float; vals.noise = (gdouble) CLAMP (vals.noise, 0, 1); } else { status = GIMP_PDB_CALLING_ERROR; } break; case GIMP_RUN_WITH_LAST_VALS: gimp_get_data (PLUG_IN_NAME, &vals); break; default: break; } /* Create texture */ if (status == GIMP_PDB_SUCCESS) { /* Set the tile cache size (all col tiles ?) */ gimp_tile_cache_ntiles ((drawable->width + gimp_tile_width() - 1) / gimp_tile_width()); /* Run! */ if (make_anim == FALSE) water_surface (drawable); else water_surface_anim (image_ID, drawable); /* If we ran interactively (even repeating) update the display. */ if (run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_displays_flush (); } /* If we use the dialog popup, set the data for future use. */ if (run_mode == GIMP_RUN_INTERACTIVE) { gimp_set_data (PLUG_IN_NAME, &vals, sizeof (WSurfaceValues)); } } } else { /* * If we got the wrong drawable type, we need to complain. */ status = GIMP_PDB_EXECUTION_ERROR; } /* * DONE! * Set the status where the GIMP can see it, and let go * of the drawable. */ values[0].data.d_status = status; gimp_drawable_detach (drawable); } static void subvals_init (gint width, gint height) { /* ratio to pixel */ subvals.width = (width < height ? width : height) / 2 * vals.width; if (subvals.width <= 0) subvals.width = 0.00001; subvals.shift_x = width * vals.range * vals.shift_x; subvals.shift_y = height * vals.range * vals.shift_y; subvals.seed = (vals.timeseed == TRUE) ? time (NULL) : vals.seed; subvals.areas = vals.areas; /* Direction of stream current */ subvals.direction = (vals.direction - 3) / 12 * 2 * G_PI; /* Convergence of stream current */ if (vals.converge < 1.0) subvals.converge = 1 - vals.converge; else subvals.converge = 2 - vals.converge; /* Get colors */ gimp_palette_get_foreground (&color.fg[0], &color.fg[1], &color.fg[2]); gimp_palette_get_background (&color.bg[0], &color.bg[1], &color.bg[2]); /* Channels and Alpha */ channels = gimp_drawable_bpp(_drawable->id); has_alpha = gimp_drawable_has_alpha(_drawable->id); if (has_alpha) channels --; } static Waves * waves_new (Waves *waves, gint width, gint height) { gint range_x = width * vals.range; gint range_y = height * vals.range; gint zero_x = width / 2; gint zero_y = height / 2; gint i; srand(subvals.seed); for (i = 0; i < vals.points; i ++) { waves->xpos = zero_x + (range_x * ((1.0*rand()/G_MAXRAND) - 0.5)); waves->ypos = zero_y + (range_y * ((1.0*rand()/G_MAXRAND) - 0.5)); waves->width = subvals.width + (vals.disorder * subvals.width * ((2.0*rand()/G_MAXRAND) - 1)); waves->vanish = (vals.decay > 0) ? (waves->width / vals.decay) : 0; waves->phase = (vals.dephase * (1.0*rand()/RAND_MAX)); waves ++; } return waves; } static Waves * waves_tilable (Waves *waves, gint width, gint height) { Waves *tmpwaves; gint points; gint i, x, y; gint offset; tmpwaves = g_malloc (vals.points * sizeof(Waves)); /* pre parse */ points = 0; for (i = 0; i < vals.points; i ++) { /* Shift */ (waves + i)->xpos -= subvals.shift_x; (waves + i)->ypos -= subvals.shift_y; if ((waves + i)->xpos > 0 && (waves + i)->xpos < width && (waves + i)->ypos > 0 && (waves + i)->ypos < height) { memcpy (tmpwaves + points, waves + i, sizeof(Waves)); points ++; } } subvals.points = points * 9; if (points < 1) { return NULL; } /* limit */ for (i=0; i < points; i ++) { if ((tmpwaves + i)->vanish == 0) { (tmpwaves + i)->vanish = MIN(width, height); } else { (tmpwaves + i)->vanish = MIN((tmpwaves + i)->vanish, width); (tmpwaves + i)->vanish = MIN((tmpwaves + i)->vanish, height); } } /* copy back 9th */ for (i = 0; i < 9; i ++) { memcpy (waves + (i * points), tmpwaves, (points * sizeof(Waves))); } g_free (tmpwaves); for (y = 0; y < 3; y ++) { for (x = 0; x < 3; x ++) { offset = points * ((y * 3) + x); for (i = 0; i< points; i ++) { (waves + offset + i)->xpos += width * (x - 1); (waves + offset + i)->ypos += height * (y - 1); } } } return waves; } static void waves_distance (Waves *point, gdouble x, gdouble y, gdouble *length, gdouble *vanish, gdouble *cycle) { gdouble length_x, length_y; gdouble angle = 0, zoom, steeple = 0, converge; /* * waves distance */ x += subvals.shift_x; y += subvals.shift_y; length_x = x - point->xpos; length_y = y - point->ypos; *length = hypot(length_x, length_y); /* * Intensity of stream current * subvals.direction = ((vals.direction - 3) / 12) * 2 * G_PI */ if (*length == 0) angle = G_PI / 2; else if (vals.intensity > 0 || vals.converge > 0) { angle = acos(length_x / *length); if (length_y > 0) angle = 2 * G_PI - angle; angle += subvals.direction; /*** angle = .. -PI(turned) .. 0 (ordered) .. PI (turned) .. ***/ } if (vals.intensity > 0) { zoom = 1 + vals.intensity * cos(angle); if (zoom > 0) *length /= zoom; else { *length = - *length; *vanish = 0; *cycle = -1; return; } } /* * waves vanish */ if (point->vanish > 0) { *vanish = 1 - (*length / point->vanish); if (*vanish <= 0) { *cycle = -1; return; } } else *vanish = 1; /* * file steeple */ if (vals.steeple == TRUE) { steeple = 0.5 * point->width; if (*length < steeple) { //*vanish *= (0.75 + 0.25 * sin((*length / steeple - 0.5) * G_PI)); } } /* * convergence in wave */ if (vals.converge > 0) { converge = (1 - fabs( fmod(angle + 2 * G_PI, 2 * G_PI) / G_PI - 1)); /*** converge => 0(ordered)..1(turned) ***/ if (vals.converge < 1) { gdouble v0, vcenter; v0 = (subvals.converge + (sin(G_PI * (0.5 - converge))+1) / 2 * (1 - subvals.converge)); if (vals.steeple == TRUE && *length < steeple) { vcenter = 1 - (vals.converge / 2); if (converge > 0.5) v0 = vcenter + (vcenter-v0) * sin((*length/steeple / 2 +1) * G_PI); else if (converge < 0.5) v0 = vcenter + (v0-vcenter) * sin( *length/steeple / 2 * G_PI); } if (v0 > 1 || v0 < 0) fprintf (stderr, "DEBUG: *** internal error: convergence in wave (v0=%1.2f)\n", v0); *vanish *= v0; } else if (vals.converge < 2) { converge /= subvals.converge; if (converge < 1) { gdouble v0; v0 = ((sin(G_PI * (0.5 - converge)) + 1) / 2); if (vals.steeple == TRUE && *length < steeple) { if (v0 < 0.5) v0 = 0.5 + (0.5-v0) * sin((*length/steeple / 2 +1) * G_PI); else if (v0 > 0.5) v0 = 0.5 + (v0-0.5) * sin( *length/steeple / 2 * G_PI); } if (v0 > 1 || v0 < 0) fprintf (stderr, "DEBUG: *** internal error: convergence in wave (v0=%1.2f)\n", v0); *vanish *= v0; } else { if (vals.steeple == TRUE && *length < steeple) { *vanish *= 0.5 + 0.5 * sin((*length/steeple / 2 - 1) * G_PI); } else { *vanish = 0; } } } else { *vanish = 0; return; } } /* * waves cycle */ *cycle = fmod(((*length / point->width) + point->phase - vals.phase), 1); if (*cycle < 0) *cycle += 1; return; } static gdouble waves_level (wave_styles style, gdouble cycle) { gdouble level; switch (style) { case LINEAR: level = cycle; break; case SINUSOIDAL: level = (sin((cycle - 0.5) * G_PI) + 1) /2; break; case SPHERICAL: if (cycle < 0.5) level = sin(cycle * G_PI) / 2; else level = 1 + sin((cycle - 1) * G_PI) / 2; break; case SAWTOOTH: if (cycle < 0.5) level = cycle * 2; else level = 1 - fmod((cycle * 2), 1); break; case TRIANGULAR: level = (sin(cycle * 2 * G_PI) + 1) / 2; break; case HALFPIPE: level = sin((cycle + 1) * G_PI) + 1; break; case POTTER: if (cycle < 0.5) level = sin(cycle * G_PI); else level = sin((cycle + 0.5) * G_PI) + 1; break; default: level = cycle; } return level; } static gdouble waves_areas (Waves *point, gdouble cycle, gdouble level) { gdouble areas; if (cycle * point->width < 0.5) areas = cycle * point->width; else if ((1 - cycle) * point->width < 0.5) areas = (1 - cycle) * point->width; else return level; switch (vals.style) { case LINEAR: case SINUSOIDAL: case SPHERICAL: level = level * (0.5 + areas) + (1 - level) * (0.5 - areas); break; } return level; } static gdouble pixel_level (Waves *waves, gfloat x, gfloat y) { gint i; gdouble length; gdouble cycle; gdouble vanish; gdouble level; gdouble level_sum; gdouble level_div; gdouble flat; /* noise flat */ if (vals.nmode == NOISE_FLAT && vals.noise > 0) { flat = vals.flat * (1 - vals.noise) + vals.noise * (sin(((1.0*rand()/G_MAXRAND) + vals.phase) * 2 * G_PI) + 1) / 2; } else { flat = vals.flat; } level = level_sum = level_div = 0; if (vals.mode == GREATER || vals.mode == LESSER) level_sum = flat; for (i = 0; i < subvals.points; i++) { waves_distance(waves + i, x, y, &length, &vanish, &cycle); if (vanish > 0) { /* waves level */ level = waves_level(vals.style, cycle); /* noise wave */ if (vals.nmode == NOISE_WAVE && vals.noise > 0 && level > 0) { level = level * (1 - vals.noise) + level * vals.noise * (sin(((1.0*rand()/G_MAXRAND) + vals.phase) * 2 * G_PI) + 1) / 2; } /* anti areas (linear only) */ if (subvals.areas == TRUE) level = waves_areas(waves + i, cycle, level); } else level = 0; switch (vals.mode) { case AVERAGE: if (vanish >= 1) { level_sum += level; } else if (vanish > 0) { level = (level * vanish) + (flat * (1 - vanish)); level_sum += level; } else { level_sum += flat; } break; case TERRITORY: if (vanish >= 1) { level_sum += level; level_div += 1; } else if (vanish > 0) { level_sum += level * vanish; level_div += vanish; } break; case GREATER: if (vanish >= 1) { if (level_sum < level) level_sum = level; } else if (vanish > 0) { level = (level * vanish) + (flat * (1- vanish)); if (level_sum < level) level_sum = level; } else if (level_sum < flat) level_sum = flat; break; case LESSER: if (vanish >= 1) { if (level_sum > level) level_sum = level; } else if (vanish > 0) { level = (level * vanish) + (flat * (1- vanish)); if (level_sum > level) level_sum = level; } else if (level_sum > flat) level_sum = flat; break; } } switch (vals.mode) { case AVERAGE: level = level_sum / subvals.points; break; case TERRITORY: if (level_div > 1 ) level = level_sum / level_div; else if (level_div > 0 ) level = (level_sum * level_div) + (flat * (1 - level_div)); else level = flat; break; case GREATER: case LESSER: level = level_sum; break; } /* nois all */ if (vals.nmode == NOISE_ALL && vals.noise > 0) { level = level * (1 - vals.noise) + level * vals.noise * (sin(((1.0*rand()/G_MAXRAND) + vals.phase) * 2 * G_PI) + 1) / 2; } return level; } static void pixel_coloring (guchar *pixel, gdouble level) { gint i; for (i = 0; i < channels; i++) { pixel[i] = ((gdouble) color.fg[i] * level) + ((gdouble) color.bg[i] * (1 - level)); } if (has_alpha) pixel[channels] = 255; } static gint render_waves (Waves *waves, GimpPixelRgn *region) { gint x, y; gdouble level; gint bpp = channels + has_alpha; //guchar *buf; //buf = g_malloc0 (region->w * bpp); for (y = 0; y < region->h; y++) { for (x = 0; x < region->w; x++) { level = pixel_level (waves, x + region->x, y + region->y); /* DEBUG */ if (level < 0.00000 || level > 1.00000) { fprintf(stderr, "DEBUG: *** level over/under (%d,%d): %5.3f\n", x, y, level); level = CLAMP (level, 0, 1); } pixel_coloring (region->data + (region->rowstride * y) + (bpp * x), level); //pixel_coloring (buf + ((channels + has_alpha) * x), level); } } return (region->w * region->h); } static void water_surface (GimpDrawable *drawable) { Waves waves[vals.points * 9]; gint width, height; GimpPixelRgn region; gint sel_x1, sel_y1, sel_x2, sel_y2; gint sel_width, sel_height; guint progress, max_progress; guchar *pr; width = drawable->width; height = drawable->height; subvals_init (width, height); waves_new (waves, width, height); /* tilable */ if (vals.tilable) { waves_tilable (waves, width, height); if (subvals.points == 0) return; subvals.shift_x = subvals.shift_y = 0; } else subvals.points = vals.points; /* Get selection area */ 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; gimp_pixel_rgn_init (®ion, drawable, sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE); /* One, two, three, go! */ progress = 0; max_progress = sel_width * sel_height; gimp_progress_init ("Water Surface.."); for (pr = gimp_pixel_rgns_register (1, ®ion); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { progress += render_waves (waves, ®ion); gimp_progress_update ((double) progress / (double) max_progress); } /* Update the drawable */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->id, TRUE); gimp_drawable_update (drawable->id, sel_x1, sel_y1, sel_width, sel_height); } static void water_surface_anim (gint32 image_ID, GimpDrawable *drawable) { gfloat phase_bak = vals.phase; gint32 layer_ID; gint i; for (i = 0; i < anim_frames; i++) { if (i == 0) { if (gimp_drawable_is_layer (drawable->id)) layer_ID = drawable->id; else return; } else { layer_ID = gimp_layer_new (image_ID, gimp_layer_get_name (drawable->id), drawable->width, drawable->height, gimp_drawable_type_with_alpha (image_ID), 100.0, GIMP_NORMAL_MODE); gimp_image_add_layer (image_ID, layer_ID, -1); } vals.phase = fmod (phase_bak + (1.0 / anim_frames * i), 1); water_surface (gimp_drawable_get (layer_ID)); } vals.phase = phase_bak; } static void preview_water_surface (GimpDrawable *drawable) { Waves waves[vals.points * 9]; gint width, height; GimpPixelRgn region; guchar *pr; guchar *srcbuf, *distbuf; gint m; gint x, y; gint bpp, preview_bpp = 3; /* preview size with aspect ratio */ width = drawable->width; height = drawable->height; m = MAX (width, height); width = ROUND(PREVIEW_SIZE * (1.0 * width / m)); height = ROUND(PREVIEW_SIZE * (1.0 * height / m)); width = MAX(width, 1); height = MAX(height, 1); /* gimp_tile_cache_ntiles ((width + gimp_tile_width() - 1) / gimp_tile_width() * (height + gimp_tile_height() - 1) / gimp_tile_height()); */ subvals_init (width, height); subvals.areas = FALSE; /* has_alpha = 0; channels = 3; */ bpp = channels + has_alpha; waves_new (waves, width, height); /* tilable */ if (vals.tilable) { waves_tilable (waves, width, height); if (subvals.points == 0) return; subvals.shift_x = subvals.shift_y = 0; } else subvals.points = vals.points; gtk_preview_size (GTK_PREVIEW (preview), width, height); gimp_pixel_rgn_init (®ion, drawable, 0, 0, width, height, TRUE, TRUE); for (pr = gimp_pixel_rgns_register (1, ®ion); pr != NULL; pr = gimp_pixel_rgns_process (pr)) render_waves (waves, ®ion); srcbuf = g_malloc (width * bpp); distbuf = g_malloc (width * preview_bpp); for (y = 0; y < height; y ++) { if (channels == preview_bpp && ! has_alpha) { gimp_pixel_rgn_get_row (®ion, distbuf, 0, y, width); } else if (channels != preview_bpp || has_alpha) { gimp_pixel_rgn_get_row (®ion, srcbuf, 0, y, width); for (x = 0; x < width ; x ++) { *(distbuf + x * preview_bpp) = *(distbuf + x * preview_bpp + 1) = *(distbuf + x * preview_bpp + 2) = *(srcbuf + x * bpp); } } gtk_preview_draw_row(GTK_PREVIEW (preview), distbuf, 0, y, width); } g_free (srcbuf); g_free (distbuf); /* Update */ gtk_widget_queue_draw (preview); //vals.seed = subval.seed; } static GtkWidget * preview_widget (GimpDrawable *drawable) { GtkWidget *preview; guchar *buf; gint y; preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (preview), PREVIEW_SIZE, PREVIEW_SIZE); buf = g_malloc0 (PREVIEW_SIZE * 3); for (y = 0; y < PREVIEW_SIZE; y++) gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, y, PREVIEW_SIZE); g_free (buf); return preview; } static void preview_update (GtkObject *obj, gpointer data) { /* gimp_double_adjustment_update (obj, data); */ /* drawable = gtk_object_get_data (GTK_OBJECT (obj), "drawable"); */ preview_water_surface (_drawable); } static void ws_int_adjustment_update (GtkAdjustment *adjustment, gpointer data) { gimp_int_adjustment_update (adjustment, data); if (do_preview) preview_water_surface (_drawable); } static void ws_double_adjustment_update (GtkAdjustment *adjustment, gpointer data) { gimp_double_adjustment_update (adjustment, data); if (do_preview) preview_water_surface (_drawable); } static void ws_toggle_button_update (GtkWidget *toggle, gpointer data) { gimp_toggle_button_update (toggle, data); if (do_preview) preview_water_surface (_drawable); } static void ws_menu_item_update (GtkWidget *widget, gpointer data) { gimp_menu_item_update (widget, data); if (do_preview) preview_water_surface (_drawable); } static gint water_surface_dialog (GimpDrawable *drawable) { GtkWidget *dlg; GtkWidget *main_hbox; GtkWidget *sub_vbox; GtkWidget *abox; GtkWidget *vbox; /* GtkWidget *hbox; */ GtkWidget *frame; GtkWidget *table; GtkWidget *toggle; GtkBox *seed_hbox; GtkWidget *spinbutton; GtkWidget *menu; GtkWidget *button; GtkWidget *sep; GtkWidget *r1, *r2, *r3, *r4, *r5, *r6, *r7; GtkObject *adj; gimp_ui_init ("wsurface", TRUE); dlg = gimp_dialog_new (PLUG_IN_VERSION, "wsurface", gimp_standard_help_func, "filters/water_surface.html", GTK_WIN_POS_MOUSE, FALSE, TRUE, FALSE, _("OK"), dialog_ok_callback, NULL, NULL, NULL, TRUE, FALSE, _("Animation"), dialog_ok_callback_anim, NULL, NULL, NULL, FALSE, FALSE, _("Reset"), dialog_reset_callback, NULL, NULL, NULL, FALSE, FALSE, _("Cancel"), gtk_widget_destroy, NULL, 1, NULL, FALSE, TRUE, NULL); gtk_signal_connect (GTK_OBJECT (dlg), "destroy", GTK_SIGNAL_FUNC (gtk_main_quit), NULL); gimp_help_init (); main_hbox = gtk_hbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 4); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_hbox, TRUE, TRUE, 0); gtk_widget_show (main_hbox); /* left side */ sub_vbox = gtk_vbox_new (FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (sub_vbox), 0); gtk_box_pack_start (GTK_BOX (main_hbox), sub_vbox, TRUE, TRUE, 0); gtk_widget_show (sub_vbox); /* * Parameter settings * * First set up the basic containers, label them, etc. */ frame = gtk_frame_new (_("Formation of waves")); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_set_border_width (GTK_CONTAINER(frame), 4); gtk_box_pack_start (GTK_BOX(sub_vbox), frame, TRUE, TRUE, 0); gtk_widget_show (frame); table = gtk_table_new (3, 5, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); /* Random Seed */ seed_hbox = GTK_BOX (gimp_random_seed_new (&vals.seed, &vals.timeseed, TRUE, FALSE)); gimp_table_attach_aligned (GTK_TABLE (table), 0, 0, _("Random Seed:"), 1.0, 0.5, GTK_WIDGET (seed_hbox), 1, TRUE); gtk_signal_connect (GTK_OBJECT (GIMP_RANDOM_SEED_SPINBUTTON_ADJ (seed_hbox)), "value_changed", GTK_SIGNAL_FUNC (ws_int_adjustment_update), &vals.seed); { /* get back widgets */ GtkBoxChild *child; child = seed_hbox->children->data; wsdlg.seed = GTK_SPIN_BUTTON (child->widget); child = seed_hbox->children->next->data; wsdlg.timeseed = GTK_TOGGLE_BUTTON (child->widget); } /* Number of points (1 to 60) */ spinbutton = gimp_spin_button_new (&adj, vals.points, 1, 60, 1, 8, 0, 1, 0); gimp_table_attach_aligned (GTK_TABLE (table), 0, 1, _("Points:"), 1.0, 0.5, spinbutton, 1, TRUE); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_int_adjustment_update), &vals.points); gimp_help_set_help_data (spinbutton, _("Number of points"), NULL); wsdlg.points = GTK_SPIN_BUTTON (spinbutton); /* Tilable */ toggle = gtk_check_button_new_with_label (_("Tilable")); gtk_table_attach (GTK_TABLE (table), toggle, 2, 3, 1, 2, GTK_SHRINK | GTK_FILL, GTK_FILL, 1, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), vals.tilable); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", GTK_SIGNAL_FUNC (ws_toggle_button_update), &vals.tilable); gtk_widget_show (toggle); wsdlg.tilable = GTK_TOGGLE_BUTTON (toggle); /* Generation range (0 to 4) */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2, _("Range:"), SCALE_WIDTH, 0, vals.range, 0.0, 4.0, 0.2, 1.0, 3, TRUE, 0, 0, _("Generation range"), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.range); wsdlg.range = GTK_ADJUSTMENT (adj); /* Shift X */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 3, _("Shift X:"), SCALE_WIDTH, 0, vals.shift_x, -8.0, 8.0, 0.05, 1.0, 3, TRUE, 0, 0, _("Total displacement on X axis."), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.shift_x); wsdlg.shift_x = GTK_ADJUSTMENT (adj); /* Shift Y */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 4, _("Shift Y:"), SCALE_WIDTH, 0, vals.shift_y, -8.0, 8.0, 0.05, 1.0, 3, TRUE, 0, 0, _("Total displacement on Y axis."), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.shift_y); wsdlg.shift_y = GTK_ADJUSTMENT (adj); /* * Wavelength and phase */ frame = gtk_frame_new (_("Wavelength and phase")); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_set_border_width (GTK_CONTAINER(frame), 4); gtk_box_pack_start (GTK_BOX (sub_vbox), frame, TRUE, TRUE, 0); gtk_widget_show (frame); table = gtk_table_new (3, 6, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); /* Wavelength ratio (0 to 2) */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, _("Wavelength:"), SCALE_WIDTH, 0, vals.width, 0.0, 2.0, 0.01, 0.1, 3, TRUE, 0, 0, _("Wavelength ratio between width of canvas"), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.width); wsdlg.width = GTK_ADJUSTMENT (adj); /* Disorder of individual wavelength (0 to 1) */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1, _("Disorder:"), SCALE_WIDTH, 0, vals.disorder, 0.0, 1.0, 0.1, 1.0, 3, TRUE, 0, 0, _("Disorder of individual wavelength"), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.disorder); wsdlg.disorder = GTK_ADJUSTMENT (adj); /* Decay ratio of wave (0 to 2) */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2, _("Decay ratio:"), SCALE_WIDTH, 0, vals.decay, 0.0, 2.0, 0.01, 0.1, 3, TRUE, 0, 0, _("Decay rate in cycle"), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.decay); wsdlg.decay = GTK_ADJUSTMENT (adj); /* ------------------------ */ sep = gtk_hseparator_new (); gtk_table_attach (GTK_TABLE (table), sep, 0, 3, 3, 4, GTK_SHRINK | GTK_FILL, GTK_FILL, 1, 2); gtk_widget_show (sep); /* Jump start ratio (0 to 1) */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 4, _("Dephase:"), SCALE_WIDTH, 0, vals.dephase, 0.0, 1.0, 0.1, 0.2, 3, TRUE, 0, 0, _("Dephase of waves"), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.dephase); wsdlg.dephase = GTK_ADJUSTMENT (adj); /* Phase of allwaves (0.0 to 1.0) */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 5, _("Phase:"), SCALE_WIDTH, 0, vals.phase, 0.0, 1.0, 0.1, 0.2, 3, TRUE, 0, 0, _("phase of all waves"), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.phase); wsdlg.phase = GTK_ADJUSTMENT (adj); /* * Stream current */ frame = gtk_frame_new (_("Stream current")); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_set_border_width (GTK_CONTAINER(frame), 4); gtk_box_pack_start (GTK_BOX(sub_vbox), frame, TRUE, TRUE, 0); gtk_widget_show (frame); table = gtk_table_new (3, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); /* Direction of stream current (0.0 to 12.0) */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, _("Direction:"), SCALE_WIDTH, 0, vals.direction, 0.0, 12.0, 1.0, 3.0, 3, TRUE, 0, 0, _("Direction of stream current"), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.direction); wsdlg.direction = GTK_ADJUSTMENT (adj); /* Intensity of stream current (0.0 to 1.0) */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1, _("Intensity:"), SCALE_WIDTH, 0, vals.intensity, 0.0, 1.0, 0.1, 0.25, 3, TRUE, 0, 0, _("Intensity of stream current"), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.intensity); wsdlg.intensity = GTK_ADJUSTMENT (adj); /* Convergence of stream current (0.0 to 2.0) */ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2, _("Convergence:"), SCALE_WIDTH, 0, vals.converge, 0.0, 2.0, 0.1, 1.0, 3, TRUE, 0, 0, _("Convergence in wave"), NULL); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.converge); wsdlg.converge = GTK_ADJUSTMENT (adj); /* * right side */ sub_vbox = gtk_vbox_new (FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (sub_vbox), 0); gtk_box_pack_start (GTK_BOX (main_hbox), sub_vbox, TRUE, TRUE, 0); gtk_widget_show (sub_vbox); /* * make a nice preview frame */ frame = gtk_frame_new (_("Preview")); gtk_container_set_border_width (GTK_CONTAINER (frame), 4); gtk_box_pack_start (GTK_BOX (sub_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_container_set_border_width (GTK_CONTAINER (abox), 4); gtk_container_add (GTK_CONTAINER (frame), abox); gtk_widget_show (abox); vbox = gtk_vbox_new (FALSE, 4); gtk_container_add (GTK_CONTAINER (abox), vbox); gtk_widget_show (vbox); frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); gtk_widget_show (frame); preview = preview_widget (drawable); /* we are here */ gtk_container_add (GTK_CONTAINER (frame), preview); preview_water_surface (drawable); /* preview image */ gtk_widget_show (preview); button = gtk_button_new_with_label (_("Update Preview")); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (preview_update), drawable); gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0); gtk_widget_show (button); toggle = gtk_check_button_new_with_label (_("Auto update")); gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), do_preview); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", GTK_SIGNAL_FUNC (ws_toggle_button_update), &do_preview); gtk_widget_show (toggle); /* * Syle and Mode */ frame = gtk_frame_new (_("Style and Mode")); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_set_border_width (GTK_CONTAINER(frame), 4); gtk_box_pack_start (GTK_BOX (sub_vbox), frame, TRUE, TRUE, 0); gtk_widget_show (frame); table = gtk_table_new (3, 6, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); /* Anti areasing */ toggle = gtk_check_button_new_with_label (_("Anti areasing")); gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 0, 1, GTK_SHRINK | GTK_FILL, GTK_FILL, 1, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), vals.areas); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", GTK_SIGNAL_FUNC (gimp_toggle_button_update), &vals.areas); gimp_help_set_help_data (toggle, _("Smooth difference in level for linear"), NULL); gtk_widget_show (toggle); wsdlg.areas = GTK_TOGGLE_BUTTON (toggle); /* File down steeple of center */ toggle = gtk_check_button_new_with_label (_("File steeple")); gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 1, 2, GTK_SHRINK | GTK_FILL, GTK_FILL, 1, 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), vals.steeple); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", GTK_SIGNAL_FUNC (ws_toggle_button_update), &vals.steeple); gimp_help_set_help_data (toggle, _("File down steeple of center"), NULL); gtk_widget_show (toggle); wsdlg.steeple = GTK_TOGGLE_BUTTON (toggle); /* Flat (0 to 1) */ spinbutton = gimp_spin_button_new (&adj, vals.flat, 0.0, 1.0, 0.1, 0.25, 0, 1, 2); gimp_help_set_help_data (spinbutton, _("Level of stabilized water"), NULL); gimp_table_attach_aligned (GTK_TABLE (table), 0, 2, _("Flat:"), 1.0, 0.5, spinbutton, 1, TRUE); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.flat); wsdlg.flat = GTK_SPIN_BUTTON (spinbutton); /* ---------------- */ sep = gtk_hseparator_new (); gtk_table_attach (GTK_TABLE (table), sep, 0, 3, 3, 4, GTK_SHRINK | GTK_FILL, GTK_FILL, 1, 2); gtk_widget_show (sep); /* Style of cycle to level */ menu = gimp_option_menu_new2 (FALSE, ws_menu_item_update, &vals.style, (gpointer) vals.style, _("Linear"), (gpointer) LINEAR, &r1, _("Sinusoidal"), (gpointer) SINUSOIDAL, &r2, _("Spherical"), (gpointer) SPHERICAL, &r3, _("Sawtooth Wave"), (gpointer) SAWTOOTH, &r4, _("Triangular Wave"), (gpointer) TRIANGULAR, &r5, _("Potter"), (gpointer) POTTER, &r6, _("Half Pipe"), (gpointer) HALFPIPE, &r7, NULL); gimp_table_attach_aligned (GTK_TABLE (table), 0, 4, _("Style:"), 1.0, 0.5, menu, 1, TRUE); gtk_widget_show (menu); wsdlg.style = GTK_OPTION_MENU (menu); gimp_help_set_help_data (r1, _("Discontinuity Wave"), NULL); gimp_help_set_help_data (r2, _("High contrast Wave"), NULL); gimp_help_set_help_data (r3, _("Soft contrast Wave"), NULL); gimp_help_set_help_data (r4, _("Stiff Wave"), NULL); gimp_help_set_help_data (r5, _("Smooth Wave"), NULL); gimp_help_set_help_data (r6, _("kneaded Wave"), NULL); gimp_help_set_help_data (r7, _("Conspicuous Wave"), NULL); /*gimp_help_set_help_data (r8, _("Flat surface"), NULL);*/ /* Mode of level mixing */ menu = gimp_option_menu_new2 (FALSE, ws_menu_item_update, &vals.mode, (gpointer) vals.mode, _("Average"), (gpointer) AVERAGE, &r1, _("Territory"), (gpointer) TERRITORY, &r2, _("Greater"), (gpointer) GREATER, &r3, _("Lesser"), (gpointer) LESSER, &r4, NULL); gimp_table_attach_aligned (GTK_TABLE (table), 0, 5, _("Mode:"), 1.0, 0.5, menu, 1, TRUE); gtk_widget_show (menu); wsdlg.mode = GTK_OPTION_MENU (menu); gimp_help_set_help_data (r1, _("Average of All"), NULL); gimp_help_set_help_data (r2, _("Vanished with possess"), NULL); gimp_help_set_help_data (r3, _("Lighten(Darken) only"), NULL); gimp_help_set_help_data (r4, _("Darken(Lighten) only"), NULL); /* * Noise */ /* frame = gtk_frame_new (_("Noise")); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_set_border_width (GTK_CONTAINER(frame), 4); gtk_box_pack_start (GTK_BOX (sub_vbox), frame, TRUE, TRUE, 0); gtk_widget_show (frame); table = gtk_table_new (3, 2, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); */ /* Mode of Noise */ /* menu = gimp_option_menu_new2 (FALSE, ws_menu_item_update, &vals.nmode, (gpointer) vals.nmode, _("None"), (gpointer) NOISE_NONE, &r1, _("All"), (gpointer) NOISE_ALL, &r2, _("to Flat"), (gpointer) NOISE_FLAT, &r3, _("to Wave"), (gpointer) NOISE_WAVE, &r4, NULL); gimp_table_attach_aligned (GTK_TABLE (table), 0, 0, _("Mode:"), 1.0, 0.5, menu, 1, TRUE); gtk_widget_show (menu); wsdlg.nmode = GTK_OPTION_MENU (menu); gimp_help_set_help_data (r1, _("Do not use noise efect"), NULL); gimp_help_set_help_data (r2, _("Add noise to all simply"), NULL); gimp_help_set_help_data (r3, _("Add noise only flat area"), NULL); gimp_help_set_help_data (r4, _("Add noise with wave"), NULL); */ /* Random noise (0 to 1) */ /* spinbutton = gimp_spin_button_new (&adj, vals.noise, 0.0, 1.0, 0.1, 0.25, 0, 1, 2); gimp_table_attach_aligned (GTK_TABLE (table), 0, 1, _("Value:"), 1.0, 0.5, spinbutton, 1, TRUE); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_double_adjustment_update), &vals.noise); wsdlg.noise = GTK_SPIN_BUTTON (spinbutton); */ /* * Animation */ frame = gtk_frame_new (_("Animation")); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_set_border_width (GTK_CONTAINER(frame), 4); gtk_box_pack_start (GTK_BOX(sub_vbox), frame, TRUE, TRUE, 0); gtk_widget_show (frame); table = gtk_table_new (3, 2, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_container_add (GTK_CONTAINER (frame), table); gtk_widget_show (table); /* Number of frames in cycle (1 to 256) */ spinbutton = gimp_spin_button_new (&adj, anim_frames, 1, 256, 1, 8, 0, 1, 0); gimp_table_attach_aligned (GTK_TABLE (table), 0, 1, _("Frames:"), 1.0, 0.5, spinbutton, 1, TRUE); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", GTK_SIGNAL_FUNC (ws_int_adjustment_update), &anim_frames); gimp_help_set_help_data (spinbutton, _("Number of frames in cycle"), NULL); wsdlg.anim_frames = GTK_SPIN_BUTTON (spinbutton); /* all to be done */ gtk_widget_show (dlg); gtk_main (); gimp_help_free (); gdk_flush (); return wint.run; } static void dialog_ok_callback (GtkWidget *widget, gpointer data) { wint.run = TRUE; gtk_widget_destroy (GTK_WIDGET (data)); } static void dialog_ok_callback_anim (GtkWidget *widget, gpointer data) { wint.run = TRUE; make_anim = TRUE; gtk_widget_destroy (GTK_WIDGET (data)); } static void dialog_reset_callback (GtkWidget *widget, gpointer data) { gint preview_bak; preview_bak = do_preview; do_preview = FALSE; vals_init (&vals); gtk_spin_button_set_value (wsdlg.points, vals.points); gtk_toggle_button_set_active (wsdlg.timeseed, vals.timeseed); gtk_spin_button_set_value (wsdlg.seed, vals.seed); gtk_adjustment_set_value (wsdlg.range, vals.range); gtk_adjustment_set_value (wsdlg.width, vals.width); gtk_adjustment_set_value (wsdlg.disorder, vals.disorder); gtk_adjustment_set_value (wsdlg.decay, vals.decay); gtk_adjustment_set_value (wsdlg.dephase, vals.dephase); gtk_adjustment_set_value (wsdlg.direction, vals.direction); gtk_adjustment_set_value (wsdlg.intensity, vals.intensity); gtk_adjustment_set_value (wsdlg.converge, vals.converge); gtk_adjustment_set_value (wsdlg.shift_x, vals.shift_x); gtk_adjustment_set_value (wsdlg.shift_y, vals.shift_y); gtk_toggle_button_set_active (wsdlg.tilable, vals.tilable); gtk_spin_button_set_value (wsdlg.flat, vals.flat); gtk_adjustment_set_value (wsdlg.phase, vals.phase); gtk_option_menu_set_history (wsdlg.style, vals.style); gtk_option_menu_set_history (wsdlg.mode, vals.mode); gtk_toggle_button_set_active (wsdlg.areas, vals.areas); gtk_toggle_button_set_active (wsdlg.steeple, vals.steeple); /*gtk_option_menu_set_history (wsdlg.nmode, vals.nmode); gtk_spin_button_set_value (wsdlg.noise, vals.noise);*/ gtk_spin_button_set_value (wsdlg.anim_frames, anim_frames); do_preview = preview_bak; if (do_preview) preview_water_surface(_drawable); } static void vals_init (WSurfaceValues *destvalsptr) { memcpy(destvalsptr, &vals_default, sizeof(WSurfaceValues)); anim_frames = 8; }