Gimp/plug-ins/common/lic.c
Michael Natterer b10adabb5e Added parent window API to the GimpProgress interface and to the libgimp
2005-09-09  Michael Natterer  <mitch@gimp.org>

	Added parent window API to the GimpProgress interface and to
	the libgimp progress stuff. Might look strange, but does
	the right thing in almost all cases (image window, file dialog,
	script-fu dialog etc). Fixes bug #62988.

	* app/core/gimpprogress.[ch]: added GimpProgress::get_window()
	which should return a toplevel window ID if the progress is in a
	window that wants to be the transient parent of plug-in dialogs.

	* app/widgets/gimpwidgets-utils.[ch] (gimp_window_get_native): new
	function which returns the window handle of a GtkWindow's GdkWindow.

	* app/widgets/gimpfiledialog.c: implement ::get_window().

	* app/display/gimpdisplay.[ch]: ditto. Removed window handle API.

	* app/gui/gui-vtable.c: changed accordingly.

	* libgimpbase/gimpbaseenums.[ch] (enum GimpProgressCommand):
	added GIMP_PROGRESS_COMMAND_GET_WINDOW.

	* app/plug-in/plug-in-progress.[ch] (plug_in_progress_get_window):
	new function. Also renamed some functions to match the
	GimpProgress interface, and not the legacy PDB procedure names.

	* tools/pdbgen/pdb/progress.pdb
	* app/core/gimppdbprogress.c: implement get_window() on both
	sides of the wire, keeping backward compatibility (hopefully).

	* libgimp/gimpprogress.[ch]: deprecated gimp_progress_install()
	and added gimp_progress_install_vtable() which takes a vtable with
	padding to be extensible. Added get_window() vtable entry and
	dispatch it accordingly. Also added pulse() which was implemented
	in a hackish way before. Everything is of course backward
	compatible.

	* libgimp/gimpprogressbar.c: inmplement the get_window() stuff
	so a plug-in dialog containing a progress can be the transient
	parent of another dialog in another plug-in.

	* libgimp/gimpui.[ch] (gimp_ui_get_progress_window): new function
	which returns a foreign GdkWindow of this plug-ins progress
	window.

	Renamed gimp_window_set_transient_for_default_display() to
	gimp_window_set_transient() and make it use the progress' window
	handle instead of the display's (which is the right thing to do in
	almost all cases).

	* libgimp/gimp.def
	* libgimp/gimpui.def: add the new functions.

	* tools/pdbgen/enums.pl
	* app/pdb/internal_procs.c
	* app/pdb/progress_cmds.c
	* libgimp/gimpprogress_pdb.[ch]: regenerated.

	* libgimp/gimpexport.c
	* plug-ins/*/*.c: follow API change.
2005-09-09 18:07:31 +00:00

904 lines
24 KiB
C

/* LIC 0.14 -- image filter plug-in for The Gimp program
* Copyright (C) 1996 Tom Bech
*
* E-mail: tomb@gimp.org
* You can contact the original The Gimp authors at gimp@xcf.berkeley.edu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* In other words, you can't sue me for whatever happens while using this ;)
*
* Changes (post 0.10):
* -> 0.11: Fixed a bug in the convolution kernels (Tom).
* -> 0.12: Added Quartic's bilinear interpolation stuff (Tom).
* -> 0.13 Changed some UI stuff causing trouble with the 0.60 release, added
* the (GIMP) tags and changed random() calls to rand() (Tom)
* -> 0.14 Ported to 0.99.11 (Tom)
*
* This plug-in implements the Line Integral Convolution (LIC) as described in
* Cabral et al. "Imaging vector fields using line integral convolution" in the
* Proceedings of ACM SIGGRAPH 93. Publ. by ACM, New York, NY, USA. p. 263-270.
* Some of the code is based on code by Steinar Haugen (thanks!), the Perlin
* noise function is practically ripped as is :)
*/
#include "config.h"
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "libgimp/stdplugins-intl.h"
/************/
/* Typedefs */
/************/
#define numx 40 /* Pseudo-random vector grid size */
#define numy 40
#define PLUG_IN_PROC "plug-in-lic"
#define PLUG_IN_BINARY "lic"
typedef enum
{
LIC_HUE,
LIC_SATURATION,
LIC_BRIGHTNESS
} LICEffectChannel;
/*****************************/
/* Global variables and such */
/*****************************/
static gdouble G[numx][numy][2];
typedef struct
{
gdouble filtlen;
gdouble noisemag;
gdouble intsteps;
gdouble minv;
gdouble maxv;
gint effect_channel;
gint effect_operator;
gint effect_convolve;
gint32 effect_image_id;
} LicValues;
static LicValues licvals;
static gdouble l = 10.0;
static gdouble dx = 2.0;
static gdouble dy = 2.0;
static gdouble minv = -2.5;
static gdouble maxv = 2.5;
static gdouble isteps = 20.0;
static gboolean source_drw_has_alpha = FALSE;
static gint effect_width, effect_height;
static gint border_x1, border_y1, border_x2, border_y2;
static GtkWidget *dialog;
/************************/
/* Convenience routines */
/************************/
static void
peek (GimpPixelRgn *src_rgn,
gint x,
gint y,
GimpRGB *color)
{
static guchar data[4] = { 0, };
gimp_pixel_rgn_get_pixel (src_rgn, data, x, y);
gimp_rgba_set_uchar (color, data[0], data[1], data[2], data[3]);
}
static void
poke (GimpPixelRgn *dest_rgn,
gint x,
gint y,
GimpRGB *color)
{
static guchar data[4];
gimp_rgba_get_uchar (color, &data[0], &data[1], &data[2], &data[3]);
gimp_pixel_rgn_set_pixel (dest_rgn, data, x, y);
}
static gint
peekmap (const guchar *image,
gint x,
gint y)
{
while (x < 0)
x += effect_width;
x %= effect_width;
while (y < 0)
y += effect_height;
y %= effect_height;
return (gint) image[x + effect_width * y];
}
/*************/
/* Main part */
/*************/
/***************************************************/
/* Compute the derivative in the x and y direction */
/* We use these convolution kernels: */
/* |1 0 -1| | 1 2 1| */
/* DX: |2 0 -2| DY: | 0 0 0| */
/* |1 0 -1| | -1 -2 -1| */
/* (It's a varation of the Sobel kernels, really) */
/***************************************************/
static gint
gradx (const guchar *image,
gint x,
gint y)
{
gint val = 0;
val = val + peekmap (image, x-1, y-1);
val = val - peekmap (image, x+1, y-1);
val = val + 2 * peekmap (image, x-1, y);
val = val - 2 * peekmap (image, x+1, y);
val = val + peekmap (image, x-1, y+1);
val = val - peekmap (image, x+1, y+1);
return val;
}
static gint
grady (const guchar *image,
gint x,
gint y)
{
gint val = 0;
val = val + peekmap (image, x-1, y-1);
val = val + 2 * peekmap (image, x, y-1);
val = val + peekmap (image, x+1, y-1);
val = val - peekmap (image, x-1, y+1);
val = val - 2 * peekmap (image, x, y+1);
val = val - peekmap (image, x+1, y+1);
return val;
}
/************************************/
/* A nice 2nd order cubic spline :) */
/************************************/
static gdouble
cubic (gdouble t)
{
gdouble at = fabs (t);
return (at < 1.0) ? at * at * (2.0 * at - 3.0) + 1.0 : 0.0;
}
static gdouble
omega (gdouble u,
gdouble v,
gint i,
gint j)
{
while (i < 0)
i += numx;
while (j < 0)
j += numy;
i %= numx;
j %= numy;
return cubic (u) * cubic (v) * (G[i][j][0]*u + G[i][j][1]*v);
}
/*************************************************************/
/* The noise function (2D variant of Perlins noise function) */
/*************************************************************/
static gdouble
noise (gdouble x,
gdouble y)
{
gint i, sti = (gint) floor (x / dx);
gint j, stj = (gint) floor (y / dy);
gdouble sum = 0.0;
/* Calculate the gdouble sum */
/* ======================== */
for (i = sti; i <= sti + 1; i++)
for (j = stj; j <= stj + 1; j++)
sum += omega ((x - (gdouble) i * dx) / dx,
(y - (gdouble) j * dy) / dy,
i, j);
return sum;
}
/*************************************************/
/* Generates pseudo-random vectors with length 1 */
/*************************************************/
static void
generatevectors (void)
{
gdouble alpha;
gint i, j;
GRand *gr;
gr = g_rand_new();
for (i = 0; i < numx; i++)
{
for (j = 0; j < numy; j++)
{
alpha = g_rand_double_range (gr, 0, 2) * G_PI;
G[i][j][0] = cos (alpha);
G[i][j][1] = sin (alpha);
}
}
g_rand_free (gr);
}
/* A simple triangle filter */
/* ======================== */
static gdouble
filter (gdouble u)
{
gdouble f = 1.0 - fabs (u) / l;
return (f < 0.0) ? 0.0 : f;
}
/******************************************************/
/* Compute the Line Integral Convolution (LIC) at x,y */
/******************************************************/
static gdouble
lic_noise (gint x,
gint y,
gdouble vx,
gdouble vy)
{
gdouble i = 0.0;
gdouble f1 = 0.0, f2 = 0.0;
gdouble u, step = 2.0 * l / isteps;
gdouble xx = (gdouble) x, yy = (gdouble) y;
gdouble c, s;
/* Get vector at x,y */
/* ================= */
c = vx;
s = vy;
/* Calculate integral numerically */
/* ============================== */
f1 = filter (-l) * noise (xx + l * c , yy + l * s);
for (u = -l + step; u <= l; u += step)
{
f2 = filter (u) * noise ( xx - u * c , yy - u * s);
i += (f1 + f2) * 0.5 * step;
f1 = f2;
}
i = (i - minv) / (maxv - minv);
i = CLAMP (i, 0.0, 1.0);
i = (i / 2.0) + 0.5;
return i;
}
static void
getpixel (GimpPixelRgn *src_rgn,
GimpRGB *p,
gdouble u,
gdouble v)
{
register gint x1, y1, x2, y2;
gint width, height;
static GimpRGB pp[4];
width = src_rgn->w;
height = src_rgn->h;
x1 = (gint)u;
y1 = (gint)v;
if (x1 < 0)
x1 = width - (-x1 % width);
else
x1 = x1 % width;
if (y1 < 0)
y1 = height - (-y1 % height);
else
y1 = y1 % height;
x2 = (x1 + 1) % width;
y2 = (y1 + 1) % height;
peek (src_rgn, x1, y1, &pp[0]);
peek (src_rgn, x2, y1, &pp[1]);
peek (src_rgn, x1, y2, &pp[2]);
peek (src_rgn, x2, y2, &pp[3]);
if (source_drw_has_alpha)
*p = gimp_bilinear_rgba (u, v, pp);
else
*p = gimp_bilinear_rgb (u, v, pp);
}
static void
lic_image (GimpPixelRgn *src_rgn,
gint x,
gint y,
gdouble vx,
gdouble vy,
GimpRGB *color)
{
gdouble u, step = 2.0 * l / isteps;
gdouble xx = (gdouble) x, yy = (gdouble) y;
gdouble c, s;
GimpRGB col = { 0, 0, 0, 0 };
GimpRGB col1, col2, col3;
/* Get vector at x,y */
/* ================= */
c = vx;
s = vy;
/* Calculate integral numerically */
/* ============================== */
getpixel (src_rgn, &col1, xx + l * c, yy + l * s);
if (source_drw_has_alpha)
gimp_rgba_multiply (&col1, filter (-l));
else
gimp_rgb_multiply (&col1, filter (-l));
for (u = -l + step; u <= l; u += step)
{
getpixel (src_rgn, &col2, xx - u * c, yy - u * s);
if (source_drw_has_alpha)
{
gimp_rgba_multiply (&col2, filter (u));
col3 = col1;
gimp_rgba_add (&col3, &col2);
gimp_rgba_multiply (&col3, 0.5 * step);
gimp_rgba_add (&col, &col3);
}
else
{
gimp_rgb_multiply (&col2, filter (u));
col3 = col1;
gimp_rgb_add (&col3, &col2);
gimp_rgb_multiply (&col3, 0.5 * step);
gimp_rgb_add (&col, &col3);
}
col1 = col2;
}
if (source_drw_has_alpha)
gimp_rgba_multiply (&col, 1.0 / l);
else
gimp_rgb_multiply (&col, 1.0 / l);
gimp_rgb_clamp (&col);
*color = col;
}
static guchar*
rgb_to_hsl (GimpDrawable *drawable,
LICEffectChannel effect_channel)
{
guchar *themap, data[4];
gint x, y;
GimpRGB color;
GimpHSL color_hsl;
gdouble val = 0.0;
glong maxc, index = 0;
GimpPixelRgn region;
GRand *gr;
gr = g_rand_new ();
maxc = drawable->width * drawable->height;
gimp_pixel_rgn_init (&region, drawable, 0, 0,
drawable->width, drawable->height, FALSE, FALSE);
themap = g_new (guchar, maxc);
for (y = 0; y < region.h; y++)
{
for (x = 0; x < region.w; x++)
{
data[3] = 255;
gimp_pixel_rgn_get_pixel (&region, data, x, y);
gimp_rgba_set_uchar (&color, data[0], data[1], data[2], data[3]);
gimp_rgb_to_hsl (&color, &color_hsl);
switch (effect_channel)
{
case LIC_HUE:
val = color_hsl.h * 255;
break;
case LIC_SATURATION:
val = color_hsl.s * 255;
break;
case LIC_BRIGHTNESS:
val = color_hsl.l * 255;
break;
}
/* add some random to avoid unstructured areas. */
val += g_rand_double_range (gr, -1.0, 1.0);
themap[index++] = (guchar) CLAMP0255 (RINT (val));
}
}
g_rand_free (gr);
return themap;
}
static void
compute_lic (GimpDrawable *drawable,
const guchar *scalarfield,
gboolean rotate)
{
gint xcount, ycount;
GimpRGB color;
gdouble vx, vy, tmp;
GimpPixelRgn src_rgn, dest_rgn;
gimp_pixel_rgn_init (&src_rgn, drawable,
0, 0,
drawable->width,
drawable->height, FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable,
0, 0,
drawable->width,
drawable->height, TRUE, TRUE);
for (ycount = 0; ycount < src_rgn.h; ycount++)
{
for (xcount = 0; xcount < src_rgn.w; xcount++)
{
/* Get derivative at (x,y) and normalize it */
/* ============================================================== */
vx = gradx (scalarfield, xcount, ycount);
vy = grady (scalarfield, xcount, ycount);
/* Rotate if needed */
if (rotate)
{
tmp = vy;
vy = -vx;
vx = tmp;
}
tmp = sqrt (vx * vx + vy * vy);
if (tmp >= 0.000001)
{
tmp = 1.0 / tmp;
vx *= tmp;
vy *= tmp;
}
/* Convolve with the LIC at (x,y) */
/* ============================== */
if (licvals.effect_convolve == 0)
{
peek (&src_rgn, xcount, ycount, &color);
tmp = lic_noise (xcount, ycount, vx, vy);
if (source_drw_has_alpha)
gimp_rgba_multiply (&color, tmp);
else
gimp_rgb_multiply (&color, tmp);
}
else
{
lic_image (&src_rgn, xcount, ycount, vx, vy, &color);
}
poke (&dest_rgn, xcount, ycount, &color);
}
gimp_progress_update ((gfloat) ycount / (gfloat) src_rgn.h);
}
}
static void
compute_image (GimpDrawable *drawable)
{
GimpDrawable *effect;
guchar *scalarfield = NULL;
/* Get some useful info on the input drawable */
/* ========================================== */
gimp_drawable_mask_bounds (drawable->drawable_id,
&border_x1, &border_y1, &border_x2, &border_y2);
gimp_progress_init (_("Van Gogh (LIC)..."));
if (licvals.effect_convolve == 0)
generatevectors ();
if (licvals.filtlen < 0.1)
licvals.filtlen = 0.1;
l = licvals.filtlen;
dx = dy = licvals.noisemag;
minv = licvals.minv / 10.0;
maxv = licvals.maxv / 10.0;
isteps = licvals.intsteps;
source_drw_has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
effect = gimp_drawable_get (licvals.effect_image_id);
effect_width = effect->width;
effect_height = effect->height;
switch (licvals.effect_channel)
{
case 0:
scalarfield = rgb_to_hsl (effect, LIC_HUE);
break;
case 1:
scalarfield = rgb_to_hsl (effect, LIC_SATURATION);
break;
case 2:
scalarfield = rgb_to_hsl (effect, LIC_BRIGHTNESS);
break;
}
compute_lic (drawable, scalarfield, licvals.effect_operator);
g_free (scalarfield);
/* Update image */
/* ============ */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
gimp_drawable_update (drawable->drawable_id, 0, 0,
drawable->width, drawable->height);
gimp_displays_flush ();
}
/**************************/
/* Below is only UI stuff */
/**************************/
static gboolean
effect_image_constrain (gint32 image_id,
gint32 drawable_id,
gpointer data)
{
return gimp_drawable_is_rgb (drawable_id);
}
static gboolean
create_main_dialog (void)
{
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *combo;
GtkObject *scale_data;
gint row;
gboolean run;
gimp_ui_init (PLUG_IN_BINARY, TRUE);
dialog = gimp_dialog_new (_("Van Gogh (LIC)"), PLUG_IN_BINARY,
NULL, 0,
gimp_standard_help_func, PLUG_IN_PROC,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gimp_window_set_transient (GTK_WINDOW (dialog));
vbox = gtk_vbox_new (FALSE, 12);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
gtk_widget_show (vbox);
hbox = gtk_hbox_new (FALSE, 12);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
frame = gimp_int_radio_group_new (TRUE, _("Effect Channel"),
G_CALLBACK (gimp_radio_button_update),
&licvals.effect_channel,
licvals.effect_channel,
_("_Hue"), 0, NULL,
_("_Saturation"), 1, NULL,
_("_Brightness"), 2, NULL,
NULL);
gtk_container_add (GTK_CONTAINER (hbox), frame);
gtk_widget_show (frame);
frame = gimp_int_radio_group_new (TRUE, _("Effect Operator"),
G_CALLBACK (gimp_radio_button_update),
&licvals.effect_operator,
licvals.effect_operator,
_("_Derivative"), 0, NULL,
_("_Gradient"), 1, NULL,
NULL);
gtk_container_add (GTK_CONTAINER (hbox), frame);
gtk_widget_show (frame);
frame = gimp_int_radio_group_new (TRUE, _("Convolve"),
G_CALLBACK (gimp_radio_button_update),
&licvals.effect_convolve,
licvals.effect_convolve,
_("_With white noise"), 0, NULL,
_("W_ith source image"), 1, NULL,
NULL);
gtk_container_add (GTK_CONTAINER (hbox), frame);
gtk_widget_show (frame);
/* Effect image menu */
table = gtk_table_new (1, 2, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
gtk_widget_show (table);
combo = gimp_drawable_combo_box_new (effect_image_constrain, NULL);
gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
licvals.effect_image_id,
G_CALLBACK (gimp_int_combo_box_get_active),
&licvals.effect_image_id);
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
_("_Effect image:"), 0.0, 0.5, combo, 2, TRUE);
table = gtk_table_new (5, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
gtk_widget_show (table);
row = 0;
scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
_("_Filter length:"), 0, 6,
licvals.filtlen, 0.1, 64, 1.0, 8.0, 1,
TRUE, 0, 0,
NULL, NULL);
g_signal_connect (scale_data, "value-changed",
G_CALLBACK (gimp_double_adjustment_update),
&licvals.filtlen);
scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
_("_Noise magnitude:"), 0, 6,
licvals.noisemag, 1, 5, 0.1, 1.0, 1,
TRUE, 0, 0,
NULL, NULL);
g_signal_connect (scale_data, "value-changed",
G_CALLBACK (gimp_double_adjustment_update),
&licvals.noisemag);
scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
_("In_tegration steps:"), 0, 6,
licvals.intsteps, 1, 40, 1.0, 5.0, 1,
TRUE, 0, 0,
NULL, NULL);
g_signal_connect (scale_data, "value-changed",
G_CALLBACK (gimp_double_adjustment_update),
&licvals.intsteps);
scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
_("_Minimum value:"), 0, 6,
licvals.minv, -100, 0, 1, 10, 1,
TRUE, 0, 0,
NULL, NULL);
g_signal_connect (scale_data, "value-changed",
G_CALLBACK (gimp_double_adjustment_update),
&licvals.minv);
scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
_("M_aximum value:"), 0, 6,
licvals.maxv, 0, 100, 1, 10, 1,
TRUE, 0, 0,
NULL, NULL);
g_signal_connect (scale_data, "value-changed",
G_CALLBACK (gimp_double_adjustment_update),
&licvals.maxv);
gtk_widget_show (dialog);
run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
gtk_widget_destroy (dialog);
return run;
}
/*************************************/
/* Set parameters to standard values */
/*************************************/
static void
set_default_settings (void)
{
licvals.filtlen = 5;
licvals.noisemag = 2;
licvals.intsteps = 25;
licvals.minv = -25;
licvals.maxv = 25;
licvals.effect_channel = 2;
licvals.effect_operator = 1;
licvals.effect_convolve = 1;
licvals.effect_image_id = 0;
}
static void
query (void)
{
static GimpParamDef args[] =
{
{ GIMP_PDB_INT32, "run-mode", "Interactive" },
{ GIMP_PDB_IMAGE, "image", "Input image" },
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
};
gimp_install_procedure (PLUG_IN_PROC,
"Creates a Van Gogh effect (Line Integral Convolution)",
"No help yet",
"Tom Bech & Federico Mena Quintero",
"Tom Bech & Federico Mena Quintero",
"Version 0.14, September 24 1997",
N_("_Van Gogh (LIC)..."),
"RGB*",
GIMP_PLUGIN,
G_N_ELEMENTS (args), 0,
args, NULL);
gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Artistic");
}
static void
run (const gchar *name,
gint nparams,
const GimpParam *param,
gint *nreturn_vals,
GimpParam **return_vals)
{
static GimpParam values[1];
GimpDrawable *drawable;
GimpRunMode run_mode;
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
run_mode = param[0].data.d_int32;
INIT_I18N ();
*nreturn_vals = 1;
*return_vals = values;
values[0].type = GIMP_PDB_STATUS;
values[0].data.d_status = status;
/* Set default values */
/* ================== */
set_default_settings ();
/* Possibly retrieve data */
/* ====================== */
gimp_get_data (PLUG_IN_PROC, &licvals);
/* Get the specified drawable */
/* ========================== */
drawable = gimp_drawable_get (param[2].data.d_drawable);
if (status == GIMP_PDB_SUCCESS)
{
/* Make sure that the drawable is RGBA or RGB color */
/* ================================================ */
if (gimp_drawable_is_rgb (drawable->drawable_id))
{
/* Set the tile cache size */
/* ======================= */
gimp_tile_cache_ntiles (2*(drawable->width / gimp_tile_width () + 1));
switch (run_mode)
{
case GIMP_RUN_INTERACTIVE:
if (create_main_dialog ())
compute_image (drawable);
gimp_set_data (PLUG_IN_PROC, &licvals, sizeof (LicValues));
break;
case GIMP_RUN_WITH_LAST_VALS:
compute_image (drawable);
break;
default:
break;
}
}
else
status = GIMP_PDB_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
GimpPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()