2000-01-13 Michael Natterer <mitch@gimp.org> * app/gimpui.[ch] * app/preferences_dialog.c: removed & renamed some functions from gimpui.[ch] (see below). * libgimp/Makefile.am * libgimp/gimpwidgets.[ch]; new files. Functions moved from app/gimpui.[ch]. Added a constructor for the label + hscale + entry combination used in many plugins (now hscale + spinbutton). * libgimp/gimpui.h: include gimpwidgets.h * plug-ins/megawidget/megawidget.[ch]: removed all functions except the preview stuff (I'm not yet sure how to implement this in libgimp because the libgimp preview should be general enough to replace all the other plugin previews, too). * plug-ins/borderaverage/Makefile.am * plug-ins/borderaverage/borderaverage.c * plug-ins/common/plugin-defs.pl * plug-ins/common/Makefile.am * plug-ins/common/aa.c * plug-ins/common/align_layers.c * plug-ins/common/animationplay.c * plug-ins/common/apply_lens.c * plug-ins/common/blinds.c * plug-ins/common/bumpmap.c * plug-ins/common/checkerboard.c * plug-ins/common/colorify.c * plug-ins/common/convmatrix.c * plug-ins/common/cubism.c * plug-ins/common/curve_bend.c * plug-ins/common/deinterlace.c * plug-ins/common/despeckle.c * plug-ins/common/destripe.c * plug-ins/common/displace.c * plug-ins/common/edge.c * plug-ins/common/emboss.c * plug-ins/common/hot.c * plug-ins/common/nlfilt.c * plug-ins/common/pixelize.c * plug-ins/common/waves.c * plug-ins/sgi/sgi.c * plug-ins/sinus/sinus.c: ui updates like removing megawidget, using the dialog constructor, I18N fixes, indentation, ...
1110 lines
30 KiB
C
1110 lines
30 KiB
C
/*
|
|
* This is a plugin for the GIMP.
|
|
*
|
|
* Copyright (C) 1997 Xavier Bouchoux
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This plug-in produces sinus textures.
|
|
*
|
|
* Please send any patches or suggestions to me: Xavier.Bouchoux@ensimag.imag.fr.
|
|
*/
|
|
|
|
/* Version 0.99 */
|
|
|
|
#define USE_LOGO
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <gdk/gdk.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <libgimp/gimp.h>
|
|
#include <libgimp/gimpui.h>
|
|
#include <libgimp/gimpmath.h>
|
|
|
|
#include <plug-ins/megawidget/megawidget.h>
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
#ifdef USE_LOGO
|
|
#include "sinus_logo.h"
|
|
#endif
|
|
|
|
#ifndef RAND_MAX
|
|
#define RAND_MAX 2147483647
|
|
#endif /* RAND_MAX */
|
|
|
|
/*
|
|
* This structure is used for persistent data.
|
|
*/
|
|
|
|
#define B_W 0L /* colors setting */
|
|
#define USE_FG_BG 1L
|
|
#define USE_COLORS 2L
|
|
|
|
#define LINEAR 0L /* colorization settings */
|
|
#define BILINEAR 1L
|
|
#define SINUS 2L
|
|
|
|
#define IDEAL 0L /* Perturbation settings */
|
|
#define PERTURBED 1L
|
|
|
|
typedef struct
|
|
{
|
|
gdouble scalex;
|
|
gdouble scaley;
|
|
gdouble cmplx;
|
|
gdouble blend_power;
|
|
gint seed;
|
|
gint tiling;
|
|
glong perturbation;
|
|
glong colorization;
|
|
glong colors;
|
|
guchar col1[4];
|
|
guchar col2[4];
|
|
} SinusVals;
|
|
|
|
static SinusVals svals =
|
|
{
|
|
15.0,
|
|
15.0,
|
|
1.0,
|
|
0.0,
|
|
42,
|
|
TRUE,
|
|
PERTURBED,
|
|
LINEAR,
|
|
USE_COLORS,
|
|
{ 255, 255, 0, 255 },
|
|
{ 0, 0, 255, 255 }
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
gint height, width;
|
|
double c11, c12, c13, c21, c22, c23, c31, c32, c33;
|
|
double (*blend) (double );
|
|
guchar r, g, b, a;
|
|
int dr, dg, db, da;
|
|
} params;
|
|
|
|
|
|
static gint drawable_is_grayscale = FALSE;
|
|
static struct mwPreview *thePreview;
|
|
static GDrawable *drawable;
|
|
|
|
/* Declare functions */
|
|
|
|
static void query (void);
|
|
static void run (gchar *name,
|
|
gint nparams,
|
|
GParam *param,
|
|
gint *nreturn_vals,
|
|
GParam **return_vals);
|
|
static void sinus (void);
|
|
|
|
static gdouble linear (gdouble v);
|
|
static gdouble bilinear (gdouble v);
|
|
static gdouble cosinus (gdouble v);
|
|
|
|
static gint sinus_dialog (void);
|
|
static void sinus_do_preview (GtkWidget *widget);
|
|
|
|
static inline void compute_block_4 (guchar *dest_row, guint rowstride,
|
|
gint x0, gint y0, gint h, gint w, params *p);
|
|
static inline void compute_block_3 (guchar *dest_row, guint rowstride,
|
|
gint x0, gint y0, gint h, gint w, params *p);
|
|
static inline void compute_block_2 (guchar *dest_row, guint rowstride,
|
|
gint x0, gint y0, gint h, gint w, params *p);
|
|
static inline void compute_block_1 (guchar *dest_row, guint rowstride,
|
|
gint x0, gint y0, gint h, gint w, params *p);
|
|
|
|
GPlugInInfo PLUG_IN_INFO =
|
|
{
|
|
NULL, /* init_proc */
|
|
NULL, /* quit_proc */
|
|
query, /* query_proc */
|
|
run, /* run_proc */
|
|
};
|
|
|
|
MAIN ()
|
|
|
|
static void
|
|
query (void)
|
|
{
|
|
static GParamDef args[] =
|
|
{
|
|
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
|
|
{ PARAM_IMAGE, "image", "Input image (unused)" },
|
|
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
|
|
|
|
{ PARAM_FLOAT, "xscale", "Scale value for x axis" },
|
|
{ PARAM_FLOAT, "yscale", "Scale value dor y axis" },
|
|
{ PARAM_FLOAT, "complex", "Complexity factor" },
|
|
{ PARAM_INT32, "seed", "Seed value for random number generator" },
|
|
{ PARAM_INT32, "tiling", "If set, the pattern generated will tile" },
|
|
{ PARAM_INT32, "perturb", "If set, the pattern is a little more distorted..." },
|
|
{ PARAM_INT32, "colors", "where to take the colors (0= B&W, 1= fg/bg, 2= col1/col2)"},
|
|
{ PARAM_COLOR, "col1", "fist color (sometimes unused)" },
|
|
{ PARAM_COLOR, "col2", "second color (sometimes unused)" },
|
|
{ PARAM_FLOAT, "alpha1", "alpha for the first color (used if the drawable has an alpha chanel)" },
|
|
{ PARAM_FLOAT, "alpha2", "alpha for the second color (used if the drawable has an alpha chanel)" },
|
|
{ PARAM_INT32, "blend", "0= linear, 1= bilinear, 2= sinusoidal" },
|
|
{ PARAM_FLOAT, "blend_power", "Power used to strech the blend" }
|
|
};
|
|
|
|
static GParamDef *return_vals = NULL;
|
|
static gint nargs = sizeof (args) / sizeof (args[0]);
|
|
static gint nreturn_vals = 0;
|
|
|
|
INIT_I18N ();
|
|
|
|
gimp_install_procedure ("plug_in_sinus",
|
|
_("Generates a texture with sinus functions"),
|
|
"FIX ME: sinus help",
|
|
"Xavier Bouchoux",
|
|
"Xavier Bouchoux",
|
|
"1997",
|
|
N_("<Image>/Filters/Render/Sinus..."),
|
|
"RGB*, GRAY*",
|
|
PROC_PLUG_IN,
|
|
nargs, nreturn_vals,
|
|
args, return_vals);
|
|
}
|
|
|
|
static void
|
|
run (gchar *name,
|
|
gint nparams,
|
|
GParam *param,
|
|
gint *nreturn_vals,
|
|
GParam **return_vals)
|
|
{
|
|
static GParam values[1];
|
|
GRunModeType run_mode;
|
|
GStatusType status = STATUS_SUCCESS;
|
|
|
|
run_mode = param[0].data.d_int32;
|
|
|
|
*nreturn_vals = 1;
|
|
*return_vals = values;
|
|
|
|
INIT_I18N_UI();
|
|
|
|
values[0].type = PARAM_STATUS;
|
|
values[0].data.d_status = status;
|
|
|
|
switch (run_mode)
|
|
{
|
|
case RUN_INTERACTIVE:
|
|
/* Possibly retrieve data */
|
|
gimp_get_data ("plug_in_sinus", &svals);
|
|
|
|
/* In order to prepare the dialog I need to know wether it's grayscale or not */
|
|
drawable = gimp_drawable_get (param[2].data.d_drawable);
|
|
thePreview = mw_preview_build_virgin(drawable);
|
|
if (gimp_drawable_is_gray (drawable->id))
|
|
drawable_is_grayscale = TRUE;
|
|
else
|
|
drawable_is_grayscale = FALSE;
|
|
|
|
if (!sinus_dialog())
|
|
return;
|
|
|
|
break;
|
|
|
|
case RUN_NONINTERACTIVE:
|
|
/* Make sure all the arguments are there! */
|
|
if (nparams != 16)
|
|
status = STATUS_CALLING_ERROR;
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
svals.scalex = param[3].data.d_float;
|
|
svals.scaley = param[4].data.d_float;
|
|
svals.cmplx = param[5].data.d_float;
|
|
svals.seed = param[6].data.d_int32;
|
|
svals.tiling = param[7].data.d_int32;
|
|
svals.perturbation = param[8].data.d_int32;
|
|
svals.colors = param[9].data.d_int32;
|
|
svals.col1[0] = param[10].data.d_color.red;
|
|
svals.col1[1] = param[10].data.d_color.green;
|
|
svals.col1[2] = param[10].data.d_color.blue;
|
|
svals.col2[0] = param[11].data.d_color.red;
|
|
svals.col2[1] = param[11].data.d_color.green;
|
|
svals.col2[2] = param[11].data.d_color.blue;
|
|
svals.col1[3] = param[12].data.d_float * 255.0;
|
|
svals.col2[3] = param[13].data.d_float * 255.0;
|
|
svals.colorization = param[14].data.d_int32;
|
|
svals.blend_power = param[15].data.d_float;
|
|
}
|
|
break;
|
|
|
|
case RUN_WITH_LAST_VALS:
|
|
/* Possibly retrieve data */
|
|
gimp_get_data ("plug_in_sinus", &svals);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Get the specified drawable */
|
|
drawable = gimp_drawable_get (param[2].data.d_drawable);
|
|
|
|
/* Make sure that the drawable is gray or RGB */
|
|
if ((status == STATUS_SUCCESS) &&
|
|
(gimp_drawable_is_rgb (drawable->id) ||
|
|
gimp_drawable_is_gray (drawable->id)))
|
|
{
|
|
gimp_progress_init ("Calculating picture...");
|
|
gimp_tile_cache_ntiles (1);
|
|
sinus ();
|
|
|
|
if (run_mode != RUN_NONINTERACTIVE)
|
|
gimp_displays_flush ();
|
|
|
|
/* Store data */
|
|
if (run_mode == RUN_INTERACTIVE)
|
|
gimp_set_data ("plug_in_sinus", &svals, sizeof (SinusVals));
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_EXECUTION_ERROR;
|
|
}
|
|
|
|
values[0].data.d_status = status;
|
|
|
|
gimp_drawable_detach (drawable);
|
|
}
|
|
|
|
/*
|
|
* Main procedure
|
|
*/
|
|
|
|
static void
|
|
prepare_coef (params *p)
|
|
{
|
|
typedef struct { guchar r, g, b, a; } type_color;
|
|
type_color col1,col2;
|
|
double scalex = svals.scalex;
|
|
double scaley = svals.scaley;
|
|
|
|
srand(svals.seed);
|
|
switch (svals.colorization)
|
|
{
|
|
case BILINEAR:
|
|
p->blend = bilinear;
|
|
break;
|
|
case SINUS:
|
|
p->blend = cosinus;
|
|
break;
|
|
case LINEAR:
|
|
default:
|
|
p->blend = linear;
|
|
}
|
|
|
|
if (svals.perturbation==IDEAL)
|
|
{
|
|
p->c11= 0*rand();
|
|
p->c12= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley; /*rand+rand is used to keep */
|
|
p->c13= (2*G_PI*rand())/RAND_MAX;
|
|
p->c21= 0*rand();
|
|
p->c22= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley; /*correspondance beetween Ideal*/
|
|
p->c23= (2*G_PI*rand())/RAND_MAX;
|
|
p->c31= (2.0*rand()/(RAND_MAX+1.0)-1)*scalex; /*and perturbed coefs (I hope...)*/
|
|
p->c32= 0*rand();
|
|
p->c33= (2*G_PI*rand())/RAND_MAX;
|
|
}
|
|
else
|
|
{
|
|
p->c11= (2.0*rand()/(RAND_MAX+1.0)-1)*scalex;
|
|
p->c12= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley;
|
|
p->c13= (2*G_PI*rand())/RAND_MAX;
|
|
p->c21= (2.0*rand()/(RAND_MAX+1.0)-1)*scalex;
|
|
p->c22= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley;
|
|
p->c23= (2*G_PI*rand())/RAND_MAX;
|
|
p->c31= (2.0*rand()/(RAND_MAX+1.0)-1)*scalex;
|
|
p->c32= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley;
|
|
p->c33= (2*G_PI*rand())/RAND_MAX;
|
|
}
|
|
|
|
if (svals.tiling)
|
|
{
|
|
p->c11= ROUND (p->c11/(2*G_PI))*2*G_PI;
|
|
p->c12= ROUND (p->c12/(2*G_PI))*2*G_PI;
|
|
p->c21= ROUND (p->c21/(2*G_PI))*2*G_PI;
|
|
p->c22= ROUND (p->c22/(2*G_PI))*2*G_PI;
|
|
p->c31= ROUND (p->c31/(2*G_PI))*2*G_PI;
|
|
p->c32= ROUND (p->c32/(2*G_PI))*2*G_PI;
|
|
}
|
|
|
|
col2.a=svals.col2[3];
|
|
col1.a=svals.col1[3];
|
|
|
|
if (drawable_is_grayscale)
|
|
{
|
|
col1.r=col1.g=col1.b=255;
|
|
col2.r=col2.g=col2.b=0;
|
|
}
|
|
else
|
|
{
|
|
switch (svals.colors)
|
|
{
|
|
case USE_COLORS:
|
|
col1.r=svals.col1[0];
|
|
col1.g=svals.col1[1];
|
|
col1.b=svals.col1[2];
|
|
col2.r=svals.col2[0];
|
|
col2.g=svals.col2[1];
|
|
col2.b=svals.col2[2];
|
|
break;
|
|
case B_W:
|
|
col1.r=col1.g=col1.b=255;
|
|
col2.r=col2.g=col2.b=0;
|
|
break;
|
|
case USE_FG_BG:
|
|
gimp_palette_get_foreground(&col2.r, &col2.g, &col2.b);
|
|
gimp_palette_get_background(&col1.r, &col1.g, &col1.b);
|
|
break;
|
|
}
|
|
}
|
|
p->r = col1.r;
|
|
p->g = col1.g;
|
|
p->b = col1.b;
|
|
p->a = col1.a;
|
|
p->dr=(int)col2.r-col1.r;
|
|
p->dg=(int)col2.g-col1.g;
|
|
p->db=(int)col2.b-col1.b;
|
|
p->da=(int)col2.a-col1.a;
|
|
}
|
|
|
|
static void
|
|
sinus (void)
|
|
{
|
|
params p;
|
|
gint bytes;
|
|
GPixelRgn dest_rgn;
|
|
int ix1, iy1, ix2, iy2; /* Selected image size. */
|
|
gpointer pr;
|
|
gint progress, max_progress;
|
|
|
|
prepare_coef(&p);
|
|
|
|
gimp_drawable_mask_bounds(drawable->id, &ix1, &iy1, &ix2, &iy2);
|
|
|
|
p.width = drawable->width;
|
|
p.height = drawable->height;
|
|
bytes = drawable->bpp;
|
|
|
|
gimp_pixel_rgn_init(&dest_rgn, drawable, ix1, iy1, ix2-ix1, iy2-iy1, TRUE,TRUE);
|
|
progress = 0;
|
|
max_progress = (ix2-ix1)*(iy2-iy1);
|
|
|
|
for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
|
|
pr != NULL;
|
|
pr = gimp_pixel_rgns_process (pr))
|
|
{
|
|
switch (bytes)
|
|
{
|
|
case 4:
|
|
compute_block_4 (dest_rgn.data, dest_rgn.rowstride,
|
|
dest_rgn.x, dest_rgn.y, dest_rgn.w, dest_rgn.h, &p);
|
|
break;
|
|
case 3:
|
|
compute_block_3 (dest_rgn.data, dest_rgn.rowstride,
|
|
dest_rgn.x, dest_rgn.y, dest_rgn.w, dest_rgn.h, &p);
|
|
break;
|
|
case 2:
|
|
compute_block_2 (dest_rgn.data, dest_rgn.rowstride,
|
|
dest_rgn.x, dest_rgn.y, dest_rgn.w, dest_rgn.h, &p);
|
|
break;
|
|
case 1:
|
|
compute_block_1 (dest_rgn.data, dest_rgn.rowstride,
|
|
dest_rgn.x, dest_rgn.y, dest_rgn.w, dest_rgn.h, &p);
|
|
break;
|
|
}
|
|
progress += dest_rgn.w * dest_rgn.h;
|
|
gimp_progress_update ((double) progress / (double) max_progress);
|
|
}
|
|
|
|
gimp_drawable_flush (drawable);
|
|
gimp_drawable_merge_shadow (drawable->id, TRUE);
|
|
gimp_drawable_update (drawable->id, ix1, iy1, (ix2-ix1), (iy2-iy1));
|
|
}
|
|
|
|
static gdouble
|
|
linear (gdouble v)
|
|
{
|
|
register double a = v - (int) v;
|
|
|
|
return (a < 0 ? 1.0 + a : a);
|
|
}
|
|
|
|
static gdouble
|
|
bilinear (gdouble v)
|
|
{
|
|
register double a = v - (int) v;
|
|
|
|
a = (a < 0 ? 1.0 + a : a);
|
|
return (a > 0.5 ? 2 - 2 * a : 2 * a);
|
|
}
|
|
|
|
static gdouble
|
|
cosinus (gdouble v)
|
|
{
|
|
return 0.5 - 0.5 * sin ((v + 0.25) * G_PI * 2);
|
|
}
|
|
|
|
static inline void
|
|
compute_block_4 (guchar *dest_row,
|
|
guint rowstride,
|
|
gint x0,
|
|
gint y0,
|
|
gint w,
|
|
gint h,
|
|
params *p)
|
|
{
|
|
gint i,j;
|
|
double x,y, grey;
|
|
guchar *dest;
|
|
|
|
for (j = y0; j < (y0 + h); j++)
|
|
{
|
|
y=((double)j)/p->height;
|
|
dest = dest_row;
|
|
for (i= x0; i<(x0+w); i++)
|
|
{
|
|
x=((double)i)/p->width;
|
|
|
|
grey = sin(p->c11*x + p->c12*y + p->c13) * (0.5+0.5*sin(p->c31*x + p->c32*y +p->c33)) \
|
|
+ sin(p->c21*x + p->c22*y + p->c23) * (0.5-0.5*sin(p->c31*x + p->c32*y +p->c33));
|
|
grey=pow(p->blend(svals.cmplx*(0.5+0.5*grey)),exp(svals.blend_power));
|
|
|
|
*dest++= p->r+(int)(grey*p->dr);
|
|
*dest++= p->g+(int)(grey*p->dg);
|
|
*dest++= p->b+(int)(grey*p->db);
|
|
*dest++= p->a+(int)(grey*p->da);
|
|
}
|
|
dest_row += rowstride;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
compute_block_3 (guchar *dest_row,
|
|
guint rowstride,
|
|
gint x0,
|
|
gint y0,
|
|
gint w,
|
|
gint h,
|
|
params *p)
|
|
{
|
|
gint i,j;
|
|
double x,y, grey;
|
|
guchar *dest;
|
|
|
|
for (j=y0; j<(y0+h); j++)
|
|
{
|
|
y=((double)j)/p->height;
|
|
dest = dest_row;
|
|
for (i= x0; i<(x0+w); i++)
|
|
{
|
|
x=((double)i)/p->width;
|
|
|
|
grey = sin(p->c11*x + p->c12*y + p->c13) * (0.5+0.5*sin(p->c31*x + p->c32*y +p->c33)) \
|
|
+ sin(p->c21*x + p->c22*y + p->c23) * (0.5-0.5*sin(p->c31*x + p->c32*y +p->c33));
|
|
grey=pow(p->blend(svals.cmplx*(0.5+0.5*grey)),exp(svals.blend_power));
|
|
|
|
*dest++= p->r+(int)(grey*p->dr);
|
|
*dest++= p->g+(int)(grey*p->dg);
|
|
*dest++= p->b+(int)(grey*p->db);
|
|
}
|
|
dest_row += rowstride;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
compute_block_2 (guchar *dest_row,
|
|
guint rowstride,
|
|
gint x0,
|
|
gint y0,
|
|
gint w,
|
|
gint h,
|
|
params *p)
|
|
{
|
|
gint i,j;
|
|
double x,y, grey;
|
|
guchar *dest;
|
|
|
|
for (j=y0; j<(y0+h); j++)
|
|
{
|
|
y=((double)j)/p->height;
|
|
dest = dest_row;
|
|
for (i= x0; i<(x0+w); i++)
|
|
{
|
|
x=((double)i)/p->width;
|
|
|
|
grey = sin(p->c11*x + p->c12*y + p->c13) * (0.5+0.5*sin(p->c31*x + p->c32*y +p->c33)) \
|
|
+ sin(p->c21*x + p->c22*y + p->c23) * (0.5-0.5*sin(p->c31*x + p->c32*y +p->c33));
|
|
grey=pow(p->blend(svals.cmplx*(0.5+0.5*grey)),exp(svals.blend_power));
|
|
|
|
*dest++= (guchar)(grey*255.0);
|
|
*dest++= p->a+(int)(grey*p->da);
|
|
}
|
|
dest_row += rowstride;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
compute_block_1 (guchar *dest_row,
|
|
guint rowstride,
|
|
gint x0,
|
|
gint y0,
|
|
gint w,
|
|
gint h,
|
|
params *p)
|
|
{
|
|
gint i,j;
|
|
double x,y, grey;
|
|
guchar *dest;
|
|
|
|
for (j=y0; j<(y0+h); j++)
|
|
{
|
|
y=((double)j)/p->height;
|
|
dest = dest_row;
|
|
for (i= x0; i<(x0+w); i++)
|
|
{
|
|
x=((double)i)/p->width;
|
|
|
|
grey = sin(p->c11*x + p->c12*y + p->c13) * (0.5+0.5*sin(p->c31*x + p->c32*y +p->c33)) \
|
|
+ sin(p->c21*x + p->c22*y + p->c23) * (0.5-0.5*sin(p->c31*x + p->c32*y +p->c33));
|
|
grey=pow(p->blend(svals.cmplx*(0.5+0.5*grey)),exp(svals.blend_power));
|
|
|
|
*dest++= (guchar)(grey*255.0);
|
|
}
|
|
dest_row += rowstride;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------*/
|
|
/* -------------------------- UI ------------------------------- */
|
|
/* -------------------------------------------------------------- */
|
|
|
|
static void
|
|
alpha_scale_cb (GtkAdjustment *adj,
|
|
gpointer data)
|
|
{
|
|
guchar *val;
|
|
GtkWidget *color_button;
|
|
|
|
val = (guchar*) data;
|
|
|
|
*val = (guchar)(adj->value * 255.0);
|
|
|
|
color_button = gtk_object_get_user_data (GTK_OBJECT (adj));
|
|
if (GIMP_IS_COLOR_BUTTON (color_button))
|
|
gimp_color_button_update (GIMP_COLOR_BUTTON (color_button));
|
|
}
|
|
|
|
static void
|
|
alpha_scale_update (GtkWidget *color_button,
|
|
gpointer data)
|
|
{
|
|
guchar *val;
|
|
GtkWidget *adj;
|
|
|
|
val = (guchar*)data;
|
|
|
|
adj = gtk_object_get_user_data (GTK_OBJECT (color_button));
|
|
gtk_signal_handler_block_by_data (GTK_OBJECT (adj), data);
|
|
gtk_adjustment_set_value (GTK_ADJUSTMENT (adj), (gfloat)(*val) / 255.0);
|
|
gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), data);
|
|
|
|
if (do_preview)
|
|
sinus_do_preview (NULL);
|
|
}
|
|
|
|
gboolean run_flag = FALSE;
|
|
|
|
static void
|
|
sinus_ok_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
run_flag = TRUE;
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (data));
|
|
}
|
|
|
|
static void
|
|
sinus_toggle_button_update (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_toggle_button_update (widget, data);
|
|
|
|
if (do_preview)
|
|
sinus_do_preview (NULL);
|
|
}
|
|
|
|
static void
|
|
sinus_radio_button_update (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_radio_button_update (widget, data);
|
|
|
|
if (do_preview)
|
|
sinus_do_preview (NULL);
|
|
}
|
|
|
|
static void
|
|
sinus_int_adjustment_update (GtkAdjustment *adjustment,
|
|
gpointer data)
|
|
{
|
|
gimp_int_adjustment_update (adjustment, data);
|
|
|
|
if (do_preview)
|
|
sinus_do_preview (NULL);
|
|
}
|
|
|
|
static void
|
|
sinus_double_adjustment_update (GtkAdjustment *adjustment,
|
|
gpointer data)
|
|
{
|
|
gimp_double_adjustment_update (adjustment, data);
|
|
|
|
if (do_preview)
|
|
sinus_do_preview (NULL);
|
|
}
|
|
|
|
/*****************************************/
|
|
/* The note book */
|
|
/*****************************************/
|
|
|
|
gint
|
|
sinus_dialog (void)
|
|
{
|
|
GtkWidget *dlg;
|
|
GtkWidget *main_hbox;
|
|
GtkWidget *preview;
|
|
GtkWidget *notebook;
|
|
GtkWidget *page;
|
|
GtkWidget *frame;
|
|
GtkWidget *label;
|
|
GtkWidget *vbox;
|
|
GtkWidget *vbox2;
|
|
GtkWidget *hbox;
|
|
GtkWidget *table;
|
|
GtkWidget *toggle;
|
|
GtkWidget *push_col1 = NULL;
|
|
GtkWidget *push_col2 = NULL;
|
|
GtkWidget *spinbutton;
|
|
GtkObject *adj;
|
|
#ifdef USE_LOGO
|
|
GtkWidget *logo;
|
|
gint x,y;
|
|
char buf[3*100];
|
|
guchar *data;
|
|
#endif
|
|
gchar **argv;
|
|
gint argc;
|
|
|
|
argc = 1;
|
|
argv = g_new (gchar *, 1);
|
|
argv[0] = g_strdup ("sinus");
|
|
|
|
gtk_init (&argc, &argv);
|
|
gtk_rc_parse (gimp_gtkrc ());
|
|
|
|
/* Create Main window with a vbox */
|
|
/* ============================== */
|
|
dlg = gimp_dialog_new (_("Sinus"), "sinus",
|
|
gimp_plugin_help_func, "filters/sinus.html",
|
|
GTK_WIN_POS_MOUSE,
|
|
FALSE, TRUE, FALSE,
|
|
|
|
_("OK"), sinus_ok_callback,
|
|
NULL, NULL, NULL, TRUE, 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);
|
|
|
|
main_hbox = gtk_hbox_new (FALSE, 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 6);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_hbox,
|
|
TRUE, TRUE, 0);
|
|
gtk_widget_show (main_hbox);
|
|
|
|
/* Create preview */
|
|
/* ============== */
|
|
vbox = gtk_vbox_new (TRUE, 4);
|
|
gtk_box_pack_start (GTK_BOX (main_hbox), vbox, FALSE, FALSE, 0);
|
|
gtk_widget_show (vbox);
|
|
|
|
preview = mw_preview_new (vbox, thePreview, &sinus_do_preview);
|
|
sinus_do_preview (preview);
|
|
|
|
#ifdef USE_LOGO
|
|
logo = gtk_preview_new (GTK_PREVIEW_COLOR);
|
|
gtk_preview_size (GTK_PREVIEW(logo), 100, 100);
|
|
gtk_box_pack_start (GTK_BOX (vbox), logo, TRUE, FALSE, 0);
|
|
gtk_widget_show (logo);
|
|
|
|
data = (guchar *) logo_data;
|
|
for (y = 0; y < 100; y++)
|
|
{
|
|
for (x=0; x<100; x++)
|
|
{
|
|
HEADER_PIXEL (data, (&buf[3 * x]));
|
|
}
|
|
gtk_preview_draw_row (GTK_PREVIEW(logo), (guchar *) buf, 0, y, 100);
|
|
}
|
|
#endif
|
|
|
|
/* Create the notebook */
|
|
/* =================== */
|
|
notebook = gtk_notebook_new ();
|
|
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
|
|
gtk_box_pack_start (GTK_BOX (main_hbox), notebook, FALSE, FALSE, 0);
|
|
gtk_widget_show (notebook);
|
|
|
|
/* Create the drawing settings frame */
|
|
/* ================================= */
|
|
page = gtk_vbox_new (FALSE, 5);
|
|
gtk_container_set_border_width (GTK_CONTAINER (page), 4);
|
|
|
|
frame = gtk_frame_new (_("Drawing Settings"));
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
|
gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 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);
|
|
|
|
adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
|
|
_("X Scale:"), 140, 0,
|
|
svals.scalex, 0.0001, 100.0, 0.0001, 5, 4,
|
|
NULL, NULL);
|
|
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
|
|
GTK_SIGNAL_FUNC (sinus_double_adjustment_update),
|
|
&svals.scalex);
|
|
|
|
adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
|
|
_("Y Scale:"), 140, 0,
|
|
svals.scaley, 0.0001, 100.0, 0.0001, 5, 4,
|
|
NULL, NULL);
|
|
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
|
|
GTK_SIGNAL_FUNC (sinus_double_adjustment_update),
|
|
&svals.scaley);
|
|
|
|
adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
|
|
_("Complexity:"), 140, 0,
|
|
svals.cmplx, 0.0, 15.0, 0.01, 5, 2,
|
|
NULL, NULL);
|
|
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
|
|
GTK_SIGNAL_FUNC (sinus_double_adjustment_update),
|
|
&svals.cmplx);
|
|
|
|
gtk_widget_show (table);
|
|
|
|
frame= gtk_frame_new (_("Calculation Settings"));
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
|
gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 4);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
hbox = gtk_hbox_new (FALSE, 4);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
gtk_widget_show (hbox);
|
|
|
|
label = gtk_label_new (_("Random Seed:"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
gtk_widget_show (label);
|
|
|
|
spinbutton = gimp_spin_button_new (&adj, svals.seed,
|
|
-10000000000, 1000000000, 1, 10,
|
|
0, 0, 0);
|
|
gtk_widget_set_usize (spinbutton, 100, -1);
|
|
gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
|
|
GTK_SIGNAL_FUNC (sinus_int_adjustment_update),
|
|
&svals.seed);
|
|
gtk_widget_show (spinbutton);
|
|
|
|
toggle = gtk_check_button_new_with_label (_("Force Tiling?"));
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), svals.tiling);
|
|
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
GTK_SIGNAL_FUNC (sinus_toggle_button_update),
|
|
&svals.tiling);
|
|
gtk_widget_show (toggle);
|
|
|
|
vbox2 =
|
|
gimp_radio_group_new2 (FALSE, NULL,
|
|
sinus_radio_button_update,
|
|
&svals.perturbation, (gpointer) svals.perturbation,
|
|
|
|
_("Ideal"), (gpointer) IDEAL, NULL,
|
|
_("Distorted"), (gpointer) PERTURBED, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox2), 0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
|
|
gtk_widget_show (vbox2);
|
|
|
|
label = gtk_label_new (_("Settings"));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
|
|
gtk_widget_show (page);
|
|
|
|
/* Color settings dialog: */
|
|
/* ====================== */
|
|
page = gtk_vbox_new (FALSE, 4);
|
|
gtk_container_set_border_width (GTK_CONTAINER (page), 4);
|
|
|
|
if (drawable_is_grayscale)
|
|
{
|
|
frame = gtk_frame_new (_("Colors"));
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
|
gtk_box_pack_start(GTK_BOX(page), frame, FALSE, FALSE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 2);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
/*if in grey scale, the colors are necessarily black and white */
|
|
label = gtk_label_new (_("The colors are white and black."));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
|
|
gtk_container_add (GTK_CONTAINER (vbox), label);
|
|
gtk_widget_show (label);
|
|
}
|
|
else
|
|
{
|
|
frame = gimp_radio_group_new2 (TRUE, _("Colors"),
|
|
sinus_radio_button_update,
|
|
&svals.colors, (gpointer) svals.colors,
|
|
|
|
_("Black & White"),
|
|
(gpointer) B_W, NULL,
|
|
_("Foreground & Background"),
|
|
(gpointer) USE_FG_BG, NULL,
|
|
_("Choose here:"),
|
|
(gpointer) USE_COLORS, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_box_pack_start(GTK_BOX(page), frame, FALSE, FALSE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = GTK_BIN (frame)->child;
|
|
|
|
hbox = gtk_hbox_new (TRUE, 20);
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
push_col1 = gimp_color_button_new (_("First Color"),
|
|
32, 32, svals.col1, 4);
|
|
gtk_box_pack_start (GTK_BOX (hbox), push_col1, FALSE, FALSE, 0);
|
|
gtk_widget_show (push_col1);
|
|
|
|
push_col2 = gimp_color_button_new (_("Second Color"),
|
|
32, 32, svals.col2, 4);
|
|
gtk_box_pack_start (GTK_BOX (hbox), push_col2, FALSE, FALSE, 0);
|
|
gtk_widget_show (push_col2);
|
|
|
|
gtk_widget_show (hbox);
|
|
}
|
|
|
|
frame = gtk_frame_new (_("Alpha Channels"));
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
|
gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
table = gtk_table_new (2, 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);
|
|
|
|
adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
|
|
_("First Color:"), 0, 0,
|
|
svals.col1[3] / 255.0, 0.0, 1.0, 0.01, 0.1, 2,
|
|
NULL, NULL);
|
|
|
|
gtk_object_set_user_data (GTK_OBJECT (adj), push_col1);
|
|
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
|
|
GTK_SIGNAL_FUNC (alpha_scale_cb),
|
|
&svals.col1[3]);
|
|
|
|
if (push_col1)
|
|
{
|
|
gtk_object_set_user_data (GTK_OBJECT (push_col1), adj);
|
|
gtk_signal_connect (GTK_OBJECT (push_col1), "color_changed",
|
|
GTK_SIGNAL_FUNC (alpha_scale_update),
|
|
&svals.col1[3]);
|
|
}
|
|
|
|
adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
|
|
_("Second Color:"), 0, 0,
|
|
svals.col2[3] / 255.0, 0.0, 1.0, 0.01, 0.1, 2,
|
|
NULL, NULL);
|
|
|
|
gtk_object_set_user_data (GTK_OBJECT (adj), push_col2);
|
|
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
|
|
GTK_SIGNAL_FUNC (alpha_scale_cb),
|
|
&svals.col2[3]);
|
|
|
|
if (push_col2)
|
|
{
|
|
gtk_object_set_user_data (GTK_OBJECT (push_col2), adj);
|
|
gtk_signal_connect (GTK_OBJECT (push_col2), "color_changed",
|
|
GTK_SIGNAL_FUNC (alpha_scale_update),
|
|
&svals.col2[3]);
|
|
}
|
|
|
|
gtk_widget_show (table);
|
|
|
|
label = gtk_label_new (_("Colors"));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
|
|
gtk_widget_show (page);
|
|
|
|
/* blend settings dialog: */
|
|
/* ====================== */
|
|
page = gtk_vbox_new (FALSE, 4);
|
|
gtk_container_set_border_width (GTK_CONTAINER (page), 4);
|
|
|
|
frame = gtk_frame_new (_("Blend Settings"));
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
|
gtk_box_pack_start (GTK_BOX (page), frame, TRUE, TRUE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 4);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_container_border_width (GTK_CONTAINER (vbox), 4);
|
|
gtk_widget_show (vbox);
|
|
|
|
frame =
|
|
gimp_radio_group_new2 (TRUE, _("Gradient"),
|
|
sinus_radio_button_update,
|
|
&svals.colorization, (gpointer) svals.colorization,
|
|
|
|
_("Linear"), (gpointer) LINEAR, NULL,
|
|
_("Bilinear"), (gpointer) BILINEAR, NULL,
|
|
_("Sinusodial"), (gpointer) SINUS, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
table = gtk_table_new (1, 3, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
|
|
gtk_container_add (GTK_CONTAINER (vbox), table);
|
|
|
|
adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
|
|
_("Exponent:"), 0, 0,
|
|
svals.blend_power, -7.5, 7.5, 0.01, 5.0, 2,
|
|
NULL, NULL);
|
|
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
|
|
GTK_SIGNAL_FUNC (sinus_double_adjustment_update),
|
|
&svals.blend_power);
|
|
|
|
gtk_widget_show (table);
|
|
|
|
label = gtk_label_new (_("Blend"));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
|
|
gtk_widget_show (page);
|
|
|
|
gtk_widget_show (dlg);
|
|
|
|
gtk_main ();
|
|
gdk_flush ();
|
|
|
|
return run_flag;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Draw preview image. if DoCompute is TRUE then recompute image. */
|
|
/******************************************************************/
|
|
|
|
void
|
|
sinus_do_preview (GtkWidget *widget)
|
|
{
|
|
static GtkWidget *theWidget = NULL;
|
|
gint y,rowsize;
|
|
guchar *buf, *savbuf;
|
|
params p;
|
|
|
|
if (theWidget == NULL)
|
|
{
|
|
theWidget = widget;
|
|
}
|
|
|
|
rowsize = thePreview->width * thePreview->bpp;
|
|
savbuf = buf = g_new (guchar, thePreview->width*thePreview->height*thePreview->bpp);
|
|
if (buf != NULL)
|
|
{
|
|
p.height = thePreview->height;
|
|
p.width = thePreview->width;
|
|
prepare_coef (&p);
|
|
|
|
if (thePreview->bpp == 3)
|
|
compute_block_3 (buf, rowsize, 0, 0,
|
|
thePreview->width, thePreview->height, &p);
|
|
else if (thePreview->bpp == 1)
|
|
{
|
|
compute_block_1 (buf, rowsize, 0, 0,
|
|
thePreview->width, thePreview->height, &p);
|
|
}
|
|
else
|
|
fprintf (stderr, "Uh Oh.... Little sinus preview-only problem...\n");
|
|
|
|
for (y = 0; y < thePreview->height; y++)
|
|
{
|
|
gtk_preview_draw_row (GTK_PREVIEW (theWidget),
|
|
buf, 0, y, thePreview->width);
|
|
buf += rowsize;
|
|
}
|
|
g_free (savbuf);
|
|
gtk_widget_draw (theWidget, NULL);
|
|
gdk_flush ();
|
|
}
|
|
else
|
|
{
|
|
fprintf (stderr,"Not enough mem for sinus Preview...\n");
|
|
}
|
|
}
|