diff --git a/ChangeLog b/ChangeLog index 627ab07418..84ed076b84 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Thu Jan 29 01:05:10 PST 1998 Manish Singh + + * updated refract and warp plugins + * changed the INSTALL file to reflect the fact that gtk is a + separate package + * app/text_tool.c: small patch for indexed images and + antialiased toggle + Thu Jan 29 00:00:54 PST 1998 Manish Singh * removed all usage of linked.[ch] and switched to GSLists diff --git a/INSTALL b/INSTALL index 54125f91cb..8e48969096 100644 --- a/INSTALL +++ b/INSTALL @@ -51,27 +51,11 @@ recognizes. These are: the gimp uses to search for its configuration files from ~/.gimp (the directory .gimp in the users home directory) to DIR. - 5. --with-libtiff=DIR. This option specifies the location of the - tiff library and header files. For instance, the libtiff library - may reside in "/usr/local". This may be specified by - --with-libtiff="/usr/local". (Note: The compilation process - should automatically find the tiff library if it resides in - "/usr/local"). - - 6. --with-libjpeg=DIR. This option specifies the location of the - jpeg library and header files. For instance, the libjpeg library - may reside in "/usr/local". This may be specified by - --with-libjpeg="/usr/local". (Note: The compilation process - should automatically find the tiff library if it resides in - "/usr/local"). - The `make' command builds several things: - - The libraries `gtk+/glib/libglib.la', `gtk+/gdk/libgdk.la', - `gtk+/gtk/libgtk.la', `libgimp/libgimp.la', `libgimp/libgimpi.la' and + - The libraries `libgimp/libgimp.la', `libgimp/libgimpi.la' and `libgimp/libgimpui.la'. The `.la' suffix is used by libtool, the program used to ease the compilation of shared libraries on different platforms. - - The test programs `gtk+/glib/testglib' and `gtk+/gtk/testgtk'. - The plug-in programs in the `plug-ins' subdirectory. - The main GIMP program in `app/gimp'. diff --git a/app/text_tool.c b/app/text_tool.c index d2e2ec90cd..3b4cd34895 100644 --- a/app/text_tool.c +++ b/app/text_tool.c @@ -283,12 +283,19 @@ text_button_press (Tool *tool, { case RGB: case GRAY: - if (!GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) + if (!GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) { gtk_widget_show (text_tool->antialias_toggle); + if (GTK_TOGGLE_BUTTON (text_tool->antialias_toggle)->active) + text_tool->antialias = TRUE; + else + text_tool->antialias = FALSE; + } break; case INDEXED: - if (GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) + if (GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) { gtk_widget_hide (text_tool->antialias_toggle); + text_tool->antialias = FALSE; + } break; } diff --git a/app/tools/gimptexttool.c b/app/tools/gimptexttool.c index d2e2ec90cd..3b4cd34895 100644 --- a/app/tools/gimptexttool.c +++ b/app/tools/gimptexttool.c @@ -283,12 +283,19 @@ text_button_press (Tool *tool, { case RGB: case GRAY: - if (!GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) + if (!GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) { gtk_widget_show (text_tool->antialias_toggle); + if (GTK_TOGGLE_BUTTON (text_tool->antialias_toggle)->active) + text_tool->antialias = TRUE; + else + text_tool->antialias = FALSE; + } break; case INDEXED: - if (GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) + if (GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) { gtk_widget_hide (text_tool->antialias_toggle); + text_tool->antialias = FALSE; + } break; } diff --git a/app/tools/text_tool.c b/app/tools/text_tool.c index d2e2ec90cd..3b4cd34895 100644 --- a/app/tools/text_tool.c +++ b/app/tools/text_tool.c @@ -283,12 +283,19 @@ text_button_press (Tool *tool, { case RGB: case GRAY: - if (!GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) + if (!GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) { gtk_widget_show (text_tool->antialias_toggle); + if (GTK_TOGGLE_BUTTON (text_tool->antialias_toggle)->active) + text_tool->antialias = TRUE; + else + text_tool->antialias = FALSE; + } break; case INDEXED: - if (GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) + if (GTK_WIDGET_VISIBLE (text_tool->antialias_toggle)) { gtk_widget_hide (text_tool->antialias_toggle); + text_tool->antialias = FALSE; + } break; } diff --git a/plug-ins/refract/CHANGES b/plug-ins/refract/CHANGES index 1a03e886b1..87ff1eb278 100644 --- a/plug-ins/refract/CHANGES +++ b/plug-ins/refract/CHANGES @@ -1,3 +1,12 @@ +1/10/98: + +Simultaniously changed the name of the menu entry to "Refract" instead +of "Refract&Reflect" and made changes preparing to add Reflect +functionality. Note that this changed the PDB interface. + +Discovered that the GParam thing didn't need to be "fixed", so I put +it back. + 1/2/98: refract-Beta Refract is back, and better than ever! That's right... The New Layer diff --git a/plug-ins/refract/INSTALL b/plug-ins/refract/INSTALL index 5de6dad538..40950d00d5 100644 --- a/plug-ins/refract/INSTALL +++ b/plug-ins/refract/INSTALL @@ -26,3 +26,6 @@ shipped with all sorts of debugging flags turned on and optimizations turned OFF. If you don't care why refract crashes if and when it does, go ahead and comment out the debug flags and uncomment the optimizations. Hopefully it will pick up some speed that way. + +There are also a few options available for dinking in refract.h, but +none too interesting at the moment. diff --git a/plug-ins/refract/refguts.c b/plug-ins/refract/refguts.c index e26ac1514a..a51c1e6fc2 100644 --- a/plug-ins/refract/refguts.c +++ b/plug-ins/refract/refguts.c @@ -114,7 +114,7 @@ go_refract( GDrawable * drawable, gint32 image_id) /***************************/ /* Initialize lens region: */ - lensmap = gimp_drawable_get (refractvals.lensmap); + lensmap = gimp_drawable_get (refractvals.lens_id); /* Fortunately, this isn't really run repeatedly, so it's OK if it's not all that compact, right? */ @@ -406,14 +406,11 @@ delta(gdouble *offset, gdouble slope, gint height) alpha = atan(slope); if( alpha > asin( refractvals.nb / refractvals.na )) { -#ifdef REFRACT_DEBUG - puts("!"); -#endif return FALSE; /* Total Internal Refraction. Aiee! */ } beta = asin(refractvals.na * sin(alpha)/refractvals.nb); - *offset = -(refractvals.dist + height) * tan(beta - alpha); + *offset = -(refractvals.refr_dist + height) * tan(beta - alpha); return TRUE; } diff --git a/plug-ins/refract/refmain.c b/plug-ins/refract/refmain.c index 878823b3f9..5fcb32278c 100644 --- a/plug-ins/refract/refmain.c +++ b/plug-ins/refract/refmain.c @@ -95,8 +95,10 @@ GPlugInInfo PLUG_IN_INFO = RefractValues refractvals = { -1, /* Lens map ID */ + -1, /* Reflection source ID */ 32, /* lens thickness */ - 0, /* distance */ + 0, /* lens to image distance */ + 64, /* lens to reflection source distance */ 1.0003, /* index a */ 1.333, /* index b */ WRAP, /* wrap behaviour */ @@ -121,9 +123,11 @@ query () { PARAM_IMAGE, "image", "Input image" }, { PARAM_DRAWABLE, "drawable", "Input drawable" }, /* If we did have parameters, these be them: */ - { PARAM_DRAWABLE, "lensmap", "Lens map drawable" }, + { PARAM_DRAWABLE, "lens_id", "Lens map drawable" }, + { PARAM_DRAWABLE, "refl_id", "Reflection source drawable." }, { PARAM_INT32, "thick", "Lens thickness" }, - { PARAM_INT32, "dist", "Lens distance from image" }, + { PARAM_INT32, "refr_dist", "Lens distance from image" }, + { PARAM_INT32, "refl_dist", "Lens distance from reflection source" }, { PARAM_FLOAT, "na", "Index of Refraction A" }, { PARAM_FLOAT, "nb", "Index of Refraction B" }, { PARAM_INT32, "edge", "Background (0), Outside (1), Wrap (2)" }, @@ -164,6 +168,8 @@ run (gchar *name, printf("refract: pid %d\n", getpid()); #endif +/* values=g_new(GParam,1); */ + run_mode = param[0].data.d_int32; *nreturn_vals = 1; @@ -188,15 +194,17 @@ run (gchar *name, case RUN_NONINTERACTIVE: if (status == STATUS_SUCCESS) { - refractvals.lensmap = param[3].data.d_drawable; - refractvals.thick = param[4].data.d_int32; - refractvals.dist = param[5].data.d_int32; - refractvals.na = param[6].data.d_float; - refractvals.nb = param[7].data.d_float; - refractvals.edge = param[8].data.d_int32; - refractvals.newl = param[9].data.d_int32; - refractvals.xofs = param[10].data.d_int32; - refractvals.yofs = param[11].data.d_int32; + refractvals.lens_id = param[3].data.d_drawable; + refractvals.refl_id = param[4].data.d_int32; + refractvals.thick = param[5].data.d_int32; + refractvals.refr_dist = param[6].data.d_float; + refractvals.refl_dist = param[7].data.d_float; + refractvals.na = param[8].data.d_int32; + refractvals.nb = param[9].data.d_int32; + refractvals.edge = param[10].data.d_int32; + refractvals.newl = param[11].data.d_int32; + refractvals.xofs = param[12].data.d_int32; + refractvals.yofs = param[13].data.d_int32; } /* if */ break; @@ -309,7 +317,7 @@ refract_dialog() option_menu = gtk_option_menu_new(); menu = gimp_drawable_menu_new(map_constrain, map_menu_callback, - NULL, refractvals.lensmap); + NULL, refractvals.lens_id); gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu),menu); gtk_tooltips_set_tips (tooltips, option_menu, "The drawable to use as the lens."); @@ -339,7 +347,7 @@ refract_dialog() 0, 1000, 1, 10, 0/*what's this do?*/, 0, 2, 2, 3, - &refractvals.dist); + &refractvals.refr_dist); /* a entry/scale/drop-menu for each index */ mw_fscale_entry_new(table, "Index A", @@ -523,5 +531,5 @@ refract_ok_callback (GtkWidget *widget, gpointer data) static void map_menu_callback (gint32 id, gpointer data) { - refractvals.lensmap = id; + refractvals.lens_id = id; } diff --git a/plug-ins/refract/refract.h b/plug-ins/refract/refract.h index 4337ecafd0..5bcd6532f0 100644 --- a/plug-ins/refract/refract.h +++ b/plug-ins/refract/refract.h @@ -5,10 +5,8 @@ */ #ifndef REFRACT_DEBUG -#warning "REFRACT_DEBUG flag is Off." #define REFRACT_TITLE "Refract 1/2/98-Beta" #else -#warning "REFRACT_DEBUG flag is On." #define REFRACT_TITLE "Refract 1/2/98 (debug)" #endif @@ -47,15 +45,17 @@ #include "gtk/gtk.h" typedef struct { - gint32 lensmap; /* lens map id */ - gint32 thick; /* lens thickness */ - gint32 dist; /* distance */ - gdouble na; /* index a */ - gdouble nb; /* index b */ - gint edge; /* wrap/transparent */ - gint newl; /* new layer? */ - gint xofs; /* offset x */ - gint yofs; /* offset y */ + gint32 lens_id; /* lens map id */ + gint32 refl_id; /* Reflection source ID */ + gint32 thick; /* lens thickness */ + gint32 refr_dist; /* distance from lens to image. */ + gint32 refl_dist; /* Distance from lens/mirror to reflection source. */ + gdouble na; /* index a */ + gdouble nb; /* index b */ + gint32 edge; /* wrap/transparent */ + gint32 newl; /* new layer? */ + gint32 xofs; /* offset x */ + gint32 yofs; /* offset y */ } RefractValues; /* for refractvals.edge */ diff --git a/plug-ins/warp/warp.c b/plug-ins/warp/warp.c index 8006e9ce57..9c1efbf58b 100644 --- a/plug-ins/warp/warp.c +++ b/plug-ins/warp/warp.c @@ -1,6 +1,6 @@ /* Warp --- image filter plug-in for The Gimp image manipulation program * Copyright (C) 1997 John P. Beale - * Much of the 'warp' code take from the Displace plug-in by 1996 Stephen Robert Norris + * 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 * @@ -32,14 +32,24 @@ * * 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. I use a second - * image with one layer which I create for the purpose of a ping-pong between - * image buffers. When finished, the created image buffer is destroyed and the - * original is updated with the final image. + * rotated a user-specified amount first. This displacement operation happens + * iteratively, generating a new displaced image from each prior image. * ------------------------------------------------------------------- * * Revision History: + * 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. @@ -67,7 +77,8 @@ /* Some useful macros */ #define ENTRY_WIDTH 75 -#define TILE_CACHE_SIZE 48 +#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 @@ -76,13 +87,19 @@ typedef struct { gdouble amount; - gdouble angle; - gdouble iter; - gdouble dither; 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 { @@ -90,9 +107,15 @@ typedef struct { GtkWidget *angle; GtkWidget *iter; GtkWidget *dither; - GtkWidget *menu_map; + 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; @@ -108,8 +131,9 @@ static void run (gchar *name, gint *nreturn_vals, GParam **return_vals); +static void blur16 (GDrawable *drawable); + static void diff (GDrawable *drawable, - gint32 *image_id, gint32 *xl_id, gint32 *yl_id ); @@ -120,15 +144,16 @@ static void diff_prepare_row (GPixelRgn *pixel_rgn, int w); static void warp_one (GDrawable *draw, + GDrawable *new, GDrawable *map_x, GDrawable *map_y, GDrawable *mag_draw, - gint first_time ); + gint first_time, + gint step ); static void warp (GDrawable *drawable, GDrawable **map_x_p, - GDrawable **map_y_p, - gint32 *xyimage_id ); + GDrawable **map_y_p ); static gint warp_dialog (GDrawable *drawable); static GTile * warp_pixel (GDrawable * drawable, @@ -148,6 +173,10 @@ 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); @@ -155,6 +184,10 @@ 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, @@ -163,14 +196,15 @@ static void warp_toggle_update (GtkWidget *widget, gpointer data); static void warp_entry_callback (GtkWidget *widget, gpointer data); -static gdouble warp_map_give_value (guchar* ptr, - gint alpha, - gint bytes); +static void warp_entry_int_callback (GtkWidget *widget, + gpointer data); static gdouble warp_map_mag_give_value (guchar *pt, gint alpha, gint bytes); -/***** Local vars *****/ +/* -------------------------------------------------------------------------------- */ +/* Variables global over entire plug-in scope */ +/* -------------------------------------------------------------------------------- */ GPlugInInfo PLUG_IN_INFO = { @@ -182,14 +216,20 @@ GPlugInInfo PLUG_IN_INFO = static WarpVals dvals = { - 10.0, /* amount */ - 90.0, /* angle */ - 5.0, /* iterations */ + 10.0, /* amount */ + -1, /* warp_map */ + 5, /* iterations */ 0.0, /* dither */ - -1, /* warp_map */ - WRAP, /* wrap_type */ - -1, /* mag_map */ - FALSE /* mag_use */ + 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 = @@ -198,16 +238,33 @@ static WarpInterface dint = NULL, /* angle */ NULL, /* iter */ NULL, /* dither */ - NULL, /* menu_map */ - FALSE, /* run */ + NULL, /* warp_map */ NULL, /* mag_map */ - FALSE /* mag_use */ + NULL, /* mag_use */ + NULL, /* substeps */ + NULL, /* grad_map */ + NULL, /* grad_scale */ + NULL, /* vector_map */ + NULL, /* vector_scale */ + NULL, /* vector_angle */ + FALSE, /* run */ }; -gint progress = 0; /* progress indicator bar */ -guint tile_width, tile_height; /* size of an image tile */ +/* -------------------------------------------------------------------------------- */ -guchar color_pixel[4] = {0, 0, 0, 255}; /* current selected foreground color */ + /* pixel, red, green, blue */ +/* static GdkColor yellow_color = { 0, 0xd6d6, 0xd6d6, 0x0000 }; + static GdkColor grey_color = { 0, 0xd6d6, 0xd6d6, 0xd6d6 }; + */ + +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 *****/ @@ -223,20 +280,26 @@ query () { PARAM_IMAGE, "image", "Input image (unused)" }, { PARAM_DRAWABLE, "drawable", "Input drawable" }, { PARAM_FLOAT, "amount", "Pixel displacement multiplier" }, - { PARAM_FLOAT, "angle", "Angle of gradient vector rotation" }, - { PARAM_FLOAT, "iter", "Iteration count" }, - { PARAM_FLOAT, "dither", "Random dither amount" }, { 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_option", "Use magnitude map: { FALSE (0), TRUE (1) }" } + { 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", + "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", @@ -259,10 +322,10 @@ run (gchar *name, GDrawable *drawable; GDrawable *map_x = NULL; /* satisfy compiler complaints */ GDrawable *map_y = NULL; - gint32 xyimage_id; + gint32 image_ID; /* image id of drawable */ - GRunModeType run_mode; GStatusType status = STATUS_SUCCESS; + gint pcnt; /* parameter counter for scanning input params. */ run_mode = param[0].data.d_int32; @@ -295,17 +358,26 @@ run (gchar *name, break; case RUN_NONINTERACTIVE: - /* Make sure all the arguments are there! */ - if (nparams != 11) + /* 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.angle = param[4].data.d_float; - dvals.iter = param[5].data.d_float; - dvals.dither = param[6].data.d_float; - dvals.warp_map = param[7].data.d_int32; - dvals.wrap_type = param[8].data.d_int32; + 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; @@ -324,10 +396,7 @@ run (gchar *name, gimp_tile_cache_ntiles (TILE_CACHE_SIZE); /* run the warp effect */ - warp (drawable, &map_x, &map_y, &xyimage_id); - - if (run_mode != RUN_NONINTERACTIVE) - gimp_displays_flush (); + warp (drawable, &map_x, &map_y); /* Store data */ if (run_mode == RUN_INTERACTIVE) @@ -336,11 +405,28 @@ run (gchar *name, values[0].data.d_status = status; - /* gimp_drawable_detach (drawable); */ + 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); + */ - gimp_image_delete(xyimage_id); + if (run_mode != RUN_NONINTERACTIVE) + gimp_displays_flush (); } @@ -354,11 +440,18 @@ warp_dialog (GDrawable *drawable) 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; + GSList *group = NULL; GSList *groupmag = NULL; gchar **argv; @@ -384,6 +477,20 @@ warp_dialog (GDrawable *drawable) (GtkSignalFunc) warp_close_callback, NULL); + tooltips = gtk_tooltips_new (); /* obtain a tooltips widget */ + 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); @@ -405,60 +512,45 @@ warp_dialog (GDrawable *drawable) /* 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), 10); + 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), 5); + gtk_container_border_width (GTK_CONTAINER (table), 1); gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacing (GTK_TABLE (table), 0, 5); - gtk_table_set_row_spacing (GTK_TABLE (table), 1, 5); - gtk_table_set_col_spacing (GTK_TABLE (table), 0, 5); - gtk_table_set_col_spacing (GTK_TABLE (table), 1, 5); + 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 ("Rotation Angle"); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); - gtk_widget_show (label); - label = gtk_label_new ("Iterations"); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + 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, "%f", dvals.amount); + 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.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, "%f", 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); dint.iter = entry = gtk_entry_new (); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + 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, "%f", dvals.iter); + sprintf (buffer, "%d", dvals.iter); gtk_entry_set_text (GTK_ENTRY (entry), buffer); gtk_signal_connect (GTK_OBJECT (entry), "changed", - (GtkSignalFunc) warp_entry_callback, + (GtkSignalFunc) warp_entry_int_callback, &dvals.iter); gtk_widget_show (entry); @@ -468,7 +560,7 @@ warp_dialog (GDrawable *drawable) gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); - dint.menu_map = option_menu = gtk_option_menu_new (); + 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, @@ -481,7 +573,7 @@ warp_dialog (GDrawable *drawable) /* Displacement Type */ toggle_hbox = gtk_hbox_new (FALSE, 10); - gtk_container_border_width (GTK_CONTAINER (toggle_hbox), 5); + 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: "); @@ -530,22 +622,20 @@ warp_dialog (GDrawable *drawable) gtk_widget_show (frame); /* -------------------------------------------------------------------- */ + /* --------- The secondary table -------------------------- */ - - /* 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), 10); + 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 (2, 3, FALSE); - gtk_container_border_width (GTK_CONTAINER (table), 5); + 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), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - + 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); @@ -554,13 +644,43 @@ warp_dialog (GDrawable *drawable) 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, "%f", dvals.dither); + 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:"); @@ -577,10 +697,10 @@ warp_dialog (GDrawable *drawable) /* ----------------------------------------------------------------------- */ - /* Magnitude Useage */ + /* Magnitude Usage */ toggle_hbox = gtk_hbox_new (FALSE, 10); - gtk_container_border_width (GTK_CONTAINER (toggle_hbox), 5); - gtk_table_attach (GTK_TABLE (table), toggle_hbox, 0, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + 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); @@ -606,10 +726,100 @@ warp_dialog (GDrawable *drawable) 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_tips (tooltips, option_menu_grad, "Gradient map selection menu"); + + 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_tips (tooltips, option_menu_vector, "Fixed-direction-vector map selection menu"); + + gtk_widget_show (option_menu_vector); + + /* -------------------------------------------------------- */ + + gtk_widget_show (otable); + gtk_widget_show (frame); /* --------------------------------------------------------------- */ gtk_widget_show (dlg); @@ -635,6 +845,109 @@ warp_dialog (GDrawable *drawable) 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' */ @@ -648,45 +961,78 @@ diff_prepare_row (GPixelRgn *pixel_rgn, { int b; - if (y == 0) - gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y + 1), w); + 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, (y - 1), w); + 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[-(gint)pixel_rgn->bpp + b] = data[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 *image_id, gint32 *xl_id, gint32 *yl_id ) { GDrawable *draw_xd, *draw_yd; /* vector disp. drawables */ - gint32 new_image_id; /* new image holding X and Y diff. arrays */ + 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 *tmp; - gint row, col, offb, off, bytes; /* relating to indexing into pixel row arrays */ + 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 @@ -703,101 +1049,227 @@ diff (GDrawable *drawable, 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. */ - /* -- Create an image with two layers: X and Y Displacement vectors -- */ + 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, GRAY); - /* gimp_image_set_filename (new_image_id, "XY_Vectors"); */ + new_image_id = gimp_image_new(width, height, RGB); /* create new image for X,Y diff */ - xlayer_id = gimp_layer_new(new_image_id, "X_Vectors", + xlayer_id = gimp_layer_new(new_image_id, "Warp_X_Vectors", width, height, - GRAY_IMAGE, 100.0, NORMAL_MODE); - gimp_image_add_layer (new_image_id, xlayer_id, 0); + RGB_IMAGE, 100.0, NORMAL_MODE); - draw_xd = gimp_drawable_get (xlayer_id); - - ylayer_id = gimp_layer_new(new_image_id, "Y_Vectors", + ylayer_id = gimp_layer_new(new_image_id, "Warp_Y_Vectors", width, height, - GRAY_IMAGE, 100.0, NORMAL_MODE); - gimp_image_add_layer (new_image_id, ylayer_id, 0); + 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); - destx = (guchar *) malloc ((x2 - x1) * src_bytes); - desty = (guchar *) malloc ((x2 - x1) * src_bytes); - /* initialize the pixel regions */ - gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); - gimp_pixel_rgn_init (&destxPR, draw_xd, 0, 0, width, height, TRUE, FALSE); - gimp_pixel_rgn_init (&destyPR, draw_yd, 0, 0, width, height, TRUE, FALSE); + 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 ((destx==NULL) || (desty==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 - 1, (x2 - x1)); - diff_prepare_row (&srcPR, cr, x1, y1, (x2 - x1)); + 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 convolution */ + /* 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 */ { - dvalx = 0; - dvaly = 0; + 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 */ - dvalx += ((gint) -pr[off - src_bytes] + (gint) pr[off + src_bytes] + + 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]); - dvaly += ((gint) -pr[off - src_bytes] - (gint)2*pr[off] - (gint) pr[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]); } - dvalx /= (3*dest_bytes); /* take average, then reduce */ - dvalx += 127; /* take zero point to be 127, since this is one byte */ + + 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>255) dvalx=255; - *dx = (guchar) dvalx; - dx += dest_bytes; /* move data pointer on to next destination pixel */ - - dvaly /= (2*dest_bytes); /* take average, then reduce */ - dvaly += 127; /* take zero point to be 127, since this is one byte */ + 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>255) dvaly=255; - *dy = (guchar) dvaly; - dy += dest_bytes; - } + 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)); - /* shuffle the row pointers */ + /* swap around the pointers to row buffers */ tmp = pr; pr = cr; cr = nr; - nr = tmp; + 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); @@ -805,29 +1277,45 @@ diff (GDrawable *drawable, gimp_drawable_update (draw_xd->id, x1, y1, (x2 - x1), (y2 - y1)); gimp_drawable_update (draw_yd->id, x1, y1, (x2 - x1), (y2 - y1)); - - /* gimp_display_new(new_image_id); */ + + /* + 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; - *image_id = new_image_id; /* return image id for eventual destruction */ } /* end diff() */ - -/* The Warp displacement is done here. */ +/* -------------------------------------------------------------------------------- */ +/* The Warp displacement is done here. */ +/* -------------------------------------------------------------------------------- */ static void warp (GDrawable *orig_draw, GDrawable **map_x_p, - GDrawable **map_y_p, - gint32 *xyimage_id_p ) + GDrawable **map_y_p ) { GDrawable *disp_map; /* Displacement map, ie, control array */ GDrawable *mag_draw; /* Magnitude multiplier factor map */ @@ -835,18 +1323,20 @@ warp (GDrawable *orig_draw, GDrawable *map_x = NULL; GDrawable *map_y = NULL; - gchar string[80]; /* string to hold title of progress bar window */ + 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; - gint32 xyimage_id = -1; gint warp_iter; /* index var. over all "warp" Displacement iterations */ @@ -856,9 +1346,9 @@ warp (GDrawable *orig_draw, /* calculate new X,Y Displacement image maps */ - gimp_progress_init ("Finding gradient..."); + gimp_progress_init ("Finding XY gradient..."); - diff(disp_map, &xyimage_id, &xdlayer, &ydlayer); /* generate x,y differential images (arrays) */ + 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); @@ -866,34 +1356,61 @@ warp (GDrawable *orig_draw, 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++) { - sprintf(string,"Step %d...",warp_iter+1); + 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(orig_draw, map_x, map_y, mag_draw, first_time); + 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) */ - *xyimage_id_p = xyimage_id; + /* gimp_image_add_layer (orig_image_id, new_layer_id, 1); */ /* make layer visible in 'layers' dialog */ + *map_x_p = map_x; *map_y_p = map_y; } /* Warp */ +/* -------------------------------------------------------------------------------- */ static void warp_one(GDrawable *draw, + GDrawable *new, GDrawable *map_x, GDrawable *map_y, GDrawable *mag_draw, - gint first_time ) + gint first_time, + gint step ) { GPixelRgn src_rgn; GPixelRgn dest_rgn; @@ -901,36 +1418,48 @@ warp_one(GDrawable *draw, GPixelRgn map_y_rgn; GPixelRgn mag_rgn; GTile * tile = NULL; - gint row = -1; - gint col = -1; + 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 amnt_x, amnt_y; /* amount of Displacement of each pixel */ 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 */ - gdouble r, theta, angled; /* Rect <-> Polar coordinate conversion variables */ gint xm_alpha = 0; gint ym_alpha = 0; @@ -951,8 +1480,23 @@ warp_one(GDrawable *draw, 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; @@ -964,27 +1508,20 @@ warp_one(GDrawable *draw, ym_bytes = gimp_drawable_bpp(map_y->id); - gimp_pixel_rgn_init (&src_rgn, draw, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); - - /* only update shadow tiles (& push undo-stack) the first time through. Thanks Spencer! */ - if (first_time==TRUE) - gimp_pixel_rgn_init (&dest_rgn, draw, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); - else - gimp_pixel_rgn_init (&dest_rgn, draw, x1, y1, (x2 - x1), (y2 - y1), TRUE, FALSE); - - /* Register the pixel region */ - 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, &dest_rgn, &src_rgn, &map_x_rgn, &map_y_rgn, &mag_rgn); + 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, &dest_rgn, &src_rgn, &map_x_rgn, &map_y_rgn); + 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)) { @@ -994,9 +1531,7 @@ warp_one(GDrawable *draw, myrow = map_y_rgn.data; if (dvals.mag_use == TRUE) mmagrow = mag_rgn.data; - - angled = dvals.angle * M_PI / 180; - + /* loop over destination pixels */ for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) { @@ -1004,44 +1539,80 @@ warp_one(GDrawable *draw, dest = destrow; mx = mxrow; my = myrow; + if (dvals.mag_use == TRUE) mmag = mmagrow; - /* - * We could move the Displacement image address calculation out of here, - * but when we can have different sized Displacement and destination - * images we'd have to move it back anyway. - */ - for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) { - dx = (warp_map_give_value(mx, xm_alpha, xm_bytes)-127.5) / 127.5; - dy = (warp_map_give_value(my, ym_alpha, ym_bytes)-127.5) / 127.5; + /* ----- Find displacement vector (amnt_x, amnt_y) ------------ */ - r = sqrt(dx*dx + dy*dy); - theta = atan2(dy,dx); - theta += angled; - - /* here is the displacement vector */ - amnt_x = dvals.amount * r * cos(theta); - amnt_y = dvals.amount * r * sin(theta); + 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; - amnt_x *= scalefac; - amnt_y *= scalefac; + dx *= scalefac; + dy *= scalefac; } if (dvals.dither != 0.0) { /* random dither is +/- dvals.dither pixels */ - amnt_x += dvals.dither*((gdouble)(rand() - (RAND_MAX >> 1)) / (RAND_MAX >> 1)); - amnt_y += dvals.dither*((gdouble)(rand() - (RAND_MAX >> 1)) / (RAND_MAX >> 1)); + 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 */ - needx = x + amnt_x; - needy = y + amnt_y; + for (substep = 1; substep < dvals.substeps; substep++) { - mx += xm_bytes; + 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; @@ -1088,44 +1659,27 @@ warp_one(GDrawable *draw, progress += (dest_rgn.w * dest_rgn.h); gimp_progress_update ((double) progress / (double) max_progress); + + } /* for pr */ - if (tile) + 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 (draw); + gimp_drawable_flush (new); - if (first_time==TRUE) - gimp_drawable_merge_shadow(draw->id, TRUE); + gimp_drawable_merge_shadow(draw->id, (first_time == TRUE)); - gimp_drawable_update (draw->id, x1, y1, (x2 - x1), (y2 - y1)); - - /* if (run_mode != RUN_NONINTERACTIVE) */ - gimp_displays_flush(); - - } /* warp_one */ - -static gdouble -warp_map_give_value(guchar *pt, gint alpha, gint bytes) -{ - gdouble ret, val_alpha; - - if (bytes >= 3) - ret = 0.30 * pt[0] + 0.59 * pt[1] + 0.11 * pt[2]; - else - ret = (gdouble) *pt; - - if (alpha) - { - val_alpha = pt[bytes - 1]; - ret = ((ret - 127.5) * val_alpha / 255.0) + 127.5; - }; - - return (ret); -} +/* -------------------------------------------------------------------------------- */ static gdouble warp_map_mag_give_value(guchar *pt, gint alpha, gint bytes) @@ -1133,7 +1687,7 @@ warp_map_mag_give_value(guchar *pt, gint alpha, gint bytes) gdouble ret, val_alpha; if (bytes >= 3) - ret = 0.30 * pt[0] + 0.59 * pt[1] + 0.11 * pt[2]; + ret = (pt[0] + pt[1] + pt[2])/3.0; else ret = (gdouble) *pt; @@ -1241,6 +1795,25 @@ bilinear (gdouble x, gdouble y, guchar *v) 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 */ @@ -1277,6 +1850,21 @@ warp_map_mag_callback (gint32 id, 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) @@ -1310,9 +1898,20 @@ static void warp_entry_callback (GtkWidget *widget, gpointer data) { - double *text_val; + gdouble *text_val; - text_val = (double *) data; + 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))); +}