mirror of https://github.com/GNOME/gimp.git
Added fractaltrace plugin
Fixed about dialog problems (seems to work now) Added gimprc option for enabling/disabling tooltips
This commit is contained in:
parent
31bceb1daf
commit
d75b2337f2
|
@ -1,3 +1,11 @@
|
|||
Wed Dec 10 16:59:56 PST 1997 Manish Singh <yosh@gimp.org>
|
||||
|
||||
* Added gimprc option for enabling/disabling tooltips
|
||||
|
||||
* Fixed up about dialog
|
||||
|
||||
* Added Fractaltrace plugin
|
||||
|
||||
Tue Dec 9 15:26:48 PST 1997 Manish Singh <yosh@gimp.org>
|
||||
|
||||
* Added Lauri Alanko's tools patch
|
||||
|
|
|
@ -393,7 +393,7 @@ about_dialog_timer (gpointer data)
|
|||
{
|
||||
for (i = 0, k = 0; i < dissolve_height; i++)
|
||||
for (j = 0; j < dissolve_width; j++, k++)
|
||||
if (frame >= dissolve_map[k])
|
||||
if (frame == dissolve_map[k])
|
||||
{
|
||||
gdk_draw_pixmap (logo_area->window,
|
||||
logo_area->style->black_gc,
|
||||
|
|
|
@ -393,7 +393,7 @@ about_dialog_timer (gpointer data)
|
|||
{
|
||||
for (i = 0, k = 0; i < dissolve_height; i++)
|
||||
for (j = 0; j < dissolve_width; j++, k++)
|
||||
if (frame >= dissolve_map[k])
|
||||
if (frame == dissolve_map[k])
|
||||
{
|
||||
gdk_draw_pixmap (logo_area->window,
|
||||
logo_area->style->black_gc,
|
||||
|
|
|
@ -525,6 +525,8 @@ create_toolbox ()
|
|||
gtk_tooltips_set_colors (tool_tips,
|
||||
&colors[11],
|
||||
&main_vbox->style->fg[GTK_STATE_NORMAL]);
|
||||
if (!show_tool_tips)
|
||||
gtk_tooltips_disable (tool_tips);
|
||||
|
||||
/* Build the menu bar with menus */
|
||||
menus_get_toolbox_menubar (&menubar, &table);
|
||||
|
|
|
@ -525,6 +525,8 @@ create_toolbox ()
|
|||
gtk_tooltips_set_colors (tool_tips,
|
||||
&colors[11],
|
||||
&main_vbox->style->fg[GTK_STATE_NORMAL]);
|
||||
if (!show_tool_tips)
|
||||
gtk_tooltips_disable (tool_tips);
|
||||
|
||||
/* Build the menu bar with menus */
|
||||
menus_get_toolbox_menubar (&menubar, &table);
|
||||
|
|
|
@ -111,6 +111,7 @@ int default_height = 256;
|
|||
int default_type = RGB;
|
||||
int show_tips = TRUE;
|
||||
int last_tip = -1;
|
||||
int show_tool_tips = FALSE;
|
||||
|
||||
static int get_next_token (void);
|
||||
static int peek_next_token (void);
|
||||
|
@ -213,6 +214,7 @@ static ParseFunc funcs[] =
|
|||
{ "plug-in", TT_XPLUGIN, NULL, NULL },
|
||||
{ "plug-in-def", TT_XPLUGINDEF, NULL, NULL },
|
||||
{ "menu-path", TT_XMENUPATH, NULL, NULL },
|
||||
{ "show-tool-tips", TT_BOOLEAN, &show_tool_tips, NULL },
|
||||
};
|
||||
static int nfuncs = sizeof (funcs) / sizeof (funcs[0]);
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ extern int default_width, default_height;
|
|||
extern int default_type;
|
||||
extern int show_tips;
|
||||
extern int last_tip;
|
||||
extern int show_tool_tips;
|
||||
|
||||
/* function prototypes */
|
||||
char * gimp_directory (void);
|
||||
|
|
|
@ -393,7 +393,7 @@ about_dialog_timer (gpointer data)
|
|||
{
|
||||
for (i = 0, k = 0; i < dissolve_height; i++)
|
||||
for (j = 0; j < dissolve_width; j++, k++)
|
||||
if (frame >= dissolve_map[k])
|
||||
if (frame == dissolve_map[k])
|
||||
{
|
||||
gdk_draw_pixmap (logo_area->window,
|
||||
logo_area->style->black_gc,
|
||||
|
|
|
@ -525,6 +525,8 @@ create_toolbox ()
|
|||
gtk_tooltips_set_colors (tool_tips,
|
||||
&colors[11],
|
||||
&main_vbox->style->fg[GTK_STATE_NORMAL]);
|
||||
if (!show_tool_tips)
|
||||
gtk_tooltips_disable (tool_tips);
|
||||
|
||||
/* Build the menu bar with menus */
|
||||
menus_get_toolbox_menubar (&menubar, &table);
|
||||
|
|
|
@ -421,6 +421,7 @@ plug-ins/glasstile/Makefile
|
|||
plug-ins/colorify/Makefile
|
||||
plug-ins/papertile/Makefile
|
||||
plug-ins/illusion/Makefile
|
||||
plug-ins/fractaltrace/Makefile
|
||||
app/Makefile
|
||||
docs/Makefile
|
||||
)
|
||||
|
|
|
@ -137,6 +137,10 @@
|
|||
# #: #x#
|
||||
(preview-size small)
|
||||
|
||||
# Tooltips
|
||||
# Comment this out to disable the tooltips in the toolbox
|
||||
(show-tool-tips)
|
||||
|
||||
# Controlling ruler visibility
|
||||
# The default behavior is for rulers to be ON
|
||||
# This can also be toggled with the View->Show Rulers command or shift+control+r
|
||||
|
|
|
@ -137,6 +137,10 @@
|
|||
# #: #x#
|
||||
(preview-size small)
|
||||
|
||||
# Tooltips
|
||||
# Comment this out to disable the tooltips in the toolbox
|
||||
(show-tool-tips)
|
||||
|
||||
# Controlling ruler visibility
|
||||
# The default behavior is for rulers to be ON
|
||||
# This can also be toggled with the View->Show Rulers command or shift+control+r
|
||||
|
|
|
@ -63,6 +63,7 @@ SUBDIRS = \
|
|||
film \
|
||||
fits \
|
||||
fp \
|
||||
fractaltrace \
|
||||
gauss_iir \
|
||||
gauss_rle \
|
||||
gbr \
|
||||
|
|
|
@ -0,0 +1,904 @@
|
|||
/*******************************************************************************
|
||||
|
||||
fractaltrace.c -- This is a plug-in for the GIMP 1.0
|
||||
|
||||
Copyright (C) 1997 Hirotsuna Mizuno
|
||||
s1041150@u-aizu.ac.jp
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#define PLUG_IN_NAME "plug_in_fractal_trace"
|
||||
#define PLUG_IN_TITLE "Fractal Trace"
|
||||
#define PLUG_IN_VERSION "v0.4 test version (Dec. 25 1997)"
|
||||
#define PLUG_IN_CATEGORY "<Image>/Filters/Distorts/Fractal Trace"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <math.h>
|
||||
#include <libgimp/gimp.h>
|
||||
|
||||
#ifndef PI_2
|
||||
#define PI_2 (3.14159265358979323*2.0)
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void query( void );
|
||||
static void run( char*, int, GParam*, int*, GParam** );
|
||||
static void filter( GDrawable* );
|
||||
|
||||
static void pixels_init( GDrawable* );
|
||||
static void pixels_free( void );
|
||||
|
||||
static int dialog_show( void );
|
||||
static void dialog_preview_draw( void );
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
GPlugInInfo PLUG_IN_INFO = {
|
||||
NULL, /* init_proc */
|
||||
NULL, /* quit_proc */
|
||||
query, /* query_proc */
|
||||
run /* run_proc */
|
||||
};
|
||||
|
||||
MAIN();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
gint32 wrap;
|
||||
gint32 transparent;
|
||||
gint32 black;
|
||||
gint32 white;
|
||||
} outside_type_t;
|
||||
|
||||
#define OUTSIDE_TYPE_WRAP 0
|
||||
#define OUTSIDE_TYPE_TRANSPARENT 1
|
||||
#define OUTSIDE_TYPE_BLACK 2
|
||||
#define OUTSIDE_TYPE_WHITE 3
|
||||
|
||||
static outside_type_t outside_type = {
|
||||
OUTSIDE_TYPE_WRAP,
|
||||
OUTSIDE_TYPE_TRANSPARENT,
|
||||
OUTSIDE_TYPE_BLACK,
|
||||
OUTSIDE_TYPE_WHITE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
gdouble x1;
|
||||
gdouble x2;
|
||||
gdouble y1;
|
||||
gdouble y2;
|
||||
gint32 depth;
|
||||
gint32 outside_type;
|
||||
} parameter_t;
|
||||
|
||||
static parameter_t parameters = {
|
||||
-1.0,
|
||||
+0.5,
|
||||
-1.0,
|
||||
+1.0,
|
||||
3,
|
||||
OUTSIDE_TYPE_WRAP
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void query( void )
|
||||
{
|
||||
static GParamDef args[] = {
|
||||
{ PARAM_INT32, "run_mode", "interactive / non-interactive" },
|
||||
{ PARAM_IMAGE, "image", "input image (not used)" },
|
||||
{ PARAM_DRAWABLE, "drawable", "input drawable" },
|
||||
{ PARAM_FLOAT, "xmin", "xmin fractal image delimiter" },
|
||||
{ PARAM_FLOAT, "xmax", "xmax fractal image delimiter" },
|
||||
{ PARAM_FLOAT, "ymin", "ymin fractal image delimiter" },
|
||||
{ PARAM_FLOAT, "ymax", "ymax fractal image delimiter" },
|
||||
{ PARAM_FLOAT, "ymax", "ymax fractal image delimiter" },
|
||||
{ PARAM_INT32, "depth", "trace depth" },
|
||||
{ PARAM_INT32, "outside_type", "outside type"
|
||||
"(0=WRAP/1=TRANS/2=BLACK/3=WHITE)" },
|
||||
};
|
||||
static int nargs = sizeof( args ) / sizeof( args[0] );
|
||||
|
||||
static GParamDef *rets = NULL;
|
||||
static int nrets = 0;
|
||||
|
||||
gimp_install_procedure(
|
||||
PLUG_IN_NAME,
|
||||
"transform image with the Mandelbrot Fractal",
|
||||
"transform image with the Mandelbrot Fractal",
|
||||
"Hirotsuna Mizuno <s1041150@u-aizu.ac.jp>",
|
||||
"Copyright (C) 1997 Hirotsuna Mizuno",
|
||||
PLUG_IN_VERSION,
|
||||
PLUG_IN_CATEGORY,
|
||||
"RGB*, GRAY*",
|
||||
PROC_PLUG_IN,
|
||||
nargs,
|
||||
nrets,
|
||||
args,
|
||||
rets
|
||||
);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
gint x1;
|
||||
gint x2;
|
||||
gint y1;
|
||||
gint y2;
|
||||
gint width;
|
||||
gint height;
|
||||
gdouble center_x;
|
||||
gdouble center_y;
|
||||
} selection_t;
|
||||
|
||||
typedef struct {
|
||||
gint width;
|
||||
gint height;
|
||||
gint bpp;
|
||||
gint alpha;
|
||||
} image_t;
|
||||
|
||||
static selection_t selection;
|
||||
static image_t image;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void run( char *name, int argc, GParam *args, int *retc, GParam **rets )
|
||||
{
|
||||
GDrawable *drawable;
|
||||
GRunModeType run_mode;
|
||||
GStatusType status;
|
||||
static GParam returns[1];
|
||||
|
||||
run_mode = args[0].data.d_int32;
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
drawable = gimp_drawable_get( args[2].data.d_drawable );
|
||||
image.width = gimp_drawable_width( drawable->id );
|
||||
image.height = gimp_drawable_height( drawable->id );
|
||||
image.bpp = gimp_drawable_bpp( drawable->id );
|
||||
image.alpha = gimp_drawable_has_alpha( drawable->id );
|
||||
gimp_drawable_mask_bounds( drawable->id, &selection.x1, &selection.y1,
|
||||
&selection.x2, &selection.y2 );
|
||||
selection.width = selection.x2 - selection.y1;
|
||||
selection.height = selection.y2 - selection.y1;
|
||||
selection.center_x = selection.x1 + (gdouble)selection.width / 2.0;
|
||||
selection.center_y = selection.y1 + (gdouble)selection.height / 2.0;
|
||||
|
||||
pixels_init( drawable );
|
||||
|
||||
if( !gimp_drawable_color( drawable->id ) &&
|
||||
!gimp_drawable_gray( drawable->id ) ){
|
||||
status = STATUS_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
switch( run_mode ){
|
||||
case RUN_WITH_LAST_VALS:
|
||||
gimp_get_data( PLUG_IN_NAME, ¶meters );
|
||||
break;
|
||||
case RUN_INTERACTIVE:
|
||||
gimp_get_data( PLUG_IN_NAME, ¶meters );
|
||||
if( !dialog_show() ){
|
||||
status = STATUS_EXECUTION_ERROR;
|
||||
break;
|
||||
}
|
||||
gimp_set_data( PLUG_IN_NAME, ¶meters, sizeof( parameter_t ) );
|
||||
break;
|
||||
case RUN_NONINTERACTIVE:
|
||||
if( argc != 9 ){
|
||||
status = STATUS_CALLING_ERROR;
|
||||
} else {
|
||||
parameters.x1 = args[3].data.d_float;
|
||||
parameters.x2 = args[4].data.d_float;
|
||||
parameters.y1 = args[5].data.d_float;
|
||||
parameters.y2 = args[6].data.d_float;
|
||||
parameters.depth = args[7].data.d_int32;
|
||||
parameters.outside_type = args[8].data.d_int32;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if( status == STATUS_SUCCESS ){
|
||||
gimp_tile_cache_ntiles( 2 * ( drawable->width / gimp_tile_width() + 1 ) );
|
||||
filter( drawable );
|
||||
if( run_mode != RUN_NONINTERACTIVE ) gimp_displays_flush();
|
||||
}
|
||||
|
||||
gimp_drawable_detach( drawable );
|
||||
|
||||
pixels_free();
|
||||
|
||||
returns[0].type = PARAM_STATUS;
|
||||
returns[0].data.d_status = status;
|
||||
*retc = 1;
|
||||
*rets = returns;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static guchar **spixels;
|
||||
static guchar **dpixels;
|
||||
static GPixelRgn sPR;
|
||||
static GPixelRgn dPR;
|
||||
|
||||
typedef struct {
|
||||
guchar r;
|
||||
guchar g;
|
||||
guchar b;
|
||||
guchar a;
|
||||
} pixel_t;
|
||||
|
||||
static void pixels_init( GDrawable *drawable )
|
||||
{
|
||||
gint y;
|
||||
gimp_pixel_rgn_init( &sPR, drawable,
|
||||
0, 0, image.width, image.height, FALSE, FALSE );
|
||||
gimp_pixel_rgn_init( &dPR, drawable,
|
||||
0, 0, image.width, image.height, TRUE, TRUE );
|
||||
spixels = (guchar**)g_malloc( image.height * sizeof( guchar* ) );
|
||||
dpixels = (guchar**)g_malloc( image.height * sizeof( guchar* ) );
|
||||
for( y = 0; y < image.height; y++ ){
|
||||
spixels[y] = (guchar*)g_malloc( image.width * image.bpp * sizeof( guchar ) );
|
||||
dpixels[y] = (guchar*)g_malloc( image.width * image.bpp * sizeof( guchar ) );
|
||||
gimp_pixel_rgn_get_row( &sPR, spixels[y], 0, y, image.width );
|
||||
}
|
||||
}
|
||||
|
||||
static void pixels_free( void )
|
||||
{
|
||||
gint y;
|
||||
for( y = 0; y < image.height; y++ ){
|
||||
free( spixels[y] );
|
||||
free( dpixels[y] );
|
||||
}
|
||||
free( spixels );
|
||||
free( dpixels );
|
||||
}
|
||||
|
||||
static void pixels_get( gint x, gint y, pixel_t *pixel )
|
||||
{
|
||||
if( x < 0 ) x = 0; else if( image.width <= x ) x = image.width - 1;
|
||||
if( y < 0 ) y = 0; else if( image.height <= y ) y = image.height - 1;
|
||||
|
||||
switch( image.bpp ){
|
||||
case 1: /* GRAY */
|
||||
pixel->r = spixels[y][x*image.bpp];
|
||||
pixel->g = spixels[y][x*image.bpp];
|
||||
pixel->b = spixels[y][x*image.bpp];
|
||||
pixel->a = 255;
|
||||
break;
|
||||
case 2: /* GRAY+A */
|
||||
pixel->r = spixels[y][x*image.bpp];
|
||||
pixel->g = spixels[y][x*image.bpp];
|
||||
pixel->b = spixels[y][x*image.bpp];
|
||||
pixel->a = spixels[y][x*image.bpp+1];
|
||||
break;
|
||||
case 3: /* RGB */
|
||||
pixel->r = spixels[y][x*image.bpp];
|
||||
pixel->g = spixels[y][x*image.bpp+1];
|
||||
pixel->b = spixels[y][x*image.bpp+2];
|
||||
pixel->a = 255;
|
||||
break;
|
||||
case 4: /* RGB+A */
|
||||
pixel->r = spixels[y][x*image.bpp];
|
||||
pixel->g = spixels[y][x*image.bpp+1];
|
||||
pixel->b = spixels[y][x*image.bpp+2];
|
||||
pixel->a = spixels[y][x*image.bpp+3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pixels_get_biliner( gdouble x, gdouble y, pixel_t *pixel )
|
||||
{
|
||||
pixel_t A, B, C, D;
|
||||
gdouble a, b, c, d;
|
||||
gint x1, y1, x2, y2;
|
||||
gdouble dx, dy;
|
||||
|
||||
x1 = (gint)floor( x );
|
||||
x2 = x1 + 1;
|
||||
y1 = (gint)floor( y );
|
||||
y2 = y1 + 1;
|
||||
|
||||
dx = x - (gdouble)x1;
|
||||
dy = y - (gdouble)y1;
|
||||
a = ( 1.0 - dx ) * ( 1.0 - dy );
|
||||
b = dx * ( 1.0 - dy );
|
||||
c = ( 1.0 - dx ) * dy;
|
||||
d = dx * dy;
|
||||
|
||||
pixels_get( x1, y1, &A );
|
||||
pixels_get( x2, y1, &B );
|
||||
pixels_get( x1, y2, &C );
|
||||
pixels_get( x2, y2, &D );
|
||||
|
||||
pixel->r = (guchar)( a * (gdouble)A.r + b * (gdouble)B.r +
|
||||
c * (gdouble)C.r + d * (gdouble)D.r );
|
||||
pixel->g = (guchar)( a * (gdouble)A.g + b * (gdouble)B.g +
|
||||
c * (gdouble)C.g + d * (gdouble)D.g );
|
||||
pixel->b = (guchar)( a * (gdouble)A.b + b * (gdouble)B.b +
|
||||
c * (gdouble)C.b + d * (gdouble)D.b );
|
||||
pixel->a = (guchar)( a * (gdouble)A.a + b * (gdouble)B.a +
|
||||
c * (gdouble)C.a + d * (gdouble)D.a );
|
||||
}
|
||||
|
||||
static void pixels_set( gint x, gint y, pixel_t *pixel )
|
||||
{
|
||||
switch( image.bpp ){
|
||||
case 1: /* GRAY */
|
||||
dpixels[y][x*image.bpp] = pixel->r;
|
||||
break;
|
||||
case 2: /* GRAY+A */
|
||||
dpixels[y][x*image.bpp] = pixel->r;
|
||||
dpixels[y][x*image.bpp+1] = pixel->a;
|
||||
break;
|
||||
case 3: /* RGB */
|
||||
dpixels[y][x*image.bpp] = pixel->r;
|
||||
dpixels[y][x*image.bpp+1] = pixel->g;
|
||||
dpixels[y][x*image.bpp+2] = pixel->b;
|
||||
break;
|
||||
case 4: /* RGB+A */
|
||||
dpixels[y][x*image.bpp] = pixel->r;
|
||||
dpixels[y][x*image.bpp+1] = pixel->g;
|
||||
dpixels[y][x*image.bpp+2] = pixel->b;
|
||||
dpixels[y][x*image.bpp+3] = pixel->a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pixels_store( void )
|
||||
{
|
||||
gint y;
|
||||
for( y = selection.y1; y < selection.y2; y++ ){
|
||||
gimp_pixel_rgn_set_row( &dPR, dpixels[y], 0, y, image.width );
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void mandelbrot( gdouble x, gdouble y, gdouble *u, gdouble *v )
|
||||
{
|
||||
gint iter = 0;
|
||||
gdouble xx = x;
|
||||
gdouble yy = y;
|
||||
gdouble x2 = xx * xx;
|
||||
gdouble y2 = yy * yy;
|
||||
gdouble tmp;
|
||||
while( iter < parameters.depth ){
|
||||
tmp = x2 - y2 + x;
|
||||
yy = 2 * xx * yy + y;
|
||||
xx = tmp;
|
||||
x2 = xx * xx;
|
||||
y2 = yy * yy;
|
||||
iter++;
|
||||
}
|
||||
*u = xx;
|
||||
*v = yy;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void filter( GDrawable *drawable )
|
||||
{
|
||||
gint x, y;
|
||||
pixel_t pixel;
|
||||
gdouble scale_x, scale_y;
|
||||
gdouble cx, cy;
|
||||
gdouble px, py;
|
||||
|
||||
gimp_progress_init( PLUG_IN_TITLE );
|
||||
|
||||
scale_x = ( parameters.x2 - parameters.x1 ) / selection.width;
|
||||
scale_y = ( parameters.y2 - parameters.y1 ) / selection.height;
|
||||
|
||||
for( y = selection.y1; y < selection.y2; y++ ){
|
||||
cy = parameters.y1 + ( y - selection.y1 ) * scale_y;
|
||||
for( x = selection.x1; x < selection.x2; x++ ){
|
||||
cx = parameters.x1 + ( x - selection.x1 ) * scale_x;
|
||||
mandelbrot( cx, cy, &px, &py );
|
||||
px = ( px - parameters.x1 ) / scale_x + selection.x1;
|
||||
py = ( py - parameters.y1 ) / scale_y + selection.y1;
|
||||
if( 0 <= px && px < image.width && 0 <= py && py < image.height ){
|
||||
pixels_get_biliner( px, py, &pixel );
|
||||
} else {
|
||||
switch( parameters.outside_type ){
|
||||
case OUTSIDE_TYPE_WRAP:
|
||||
px = fmod( px, image.width );
|
||||
py = fmod( py, image.height );
|
||||
if( px < 0.0 ) px += image.width;
|
||||
if( py < 0.0 ) py += image.height;
|
||||
pixels_get_biliner( px, py, &pixel );
|
||||
break;
|
||||
case OUTSIDE_TYPE_TRANSPARENT:
|
||||
pixel.r = pixel.g = pixel.b = 0;
|
||||
pixel.a = 0;
|
||||
break;
|
||||
case OUTSIDE_TYPE_BLACK:
|
||||
pixel.r = pixel.g = pixel.b = 0;
|
||||
pixel.a = 255;
|
||||
break;
|
||||
case OUTSIDE_TYPE_WHITE:
|
||||
pixel.r = pixel.g = pixel.b = 255;
|
||||
pixel.a = 255;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pixels_set( x, y, &pixel );
|
||||
}
|
||||
gimp_progress_update( (gdouble)(y-selection.y1)/selection.height );
|
||||
}
|
||||
|
||||
pixels_store();
|
||||
|
||||
gimp_drawable_flush( drawable );
|
||||
gimp_drawable_merge_shadow( drawable->id, TRUE );
|
||||
gimp_drawable_update( drawable->id,
|
||||
selection.x1, selection.y1, selection.width, selection.height );
|
||||
}
|
||||
|
||||
/*
|
||||
GUI
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int dialog_status;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void dialog_entry_gint32_callback( GtkWidget *widget, gpointer *data )
|
||||
{
|
||||
gint32 value = (gint32)atof( gtk_entry_get_text( GTK_ENTRY( widget ) ) );
|
||||
if( *(gint32*)data != value ){
|
||||
*(gint32*)data = value;
|
||||
dialog_preview_draw();
|
||||
}
|
||||
}
|
||||
|
||||
static void dialog_entry_gint32_new( char *caption, gint32 *value,
|
||||
GtkWidget *table, gint row )
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry;
|
||||
char buffer[256];
|
||||
|
||||
label = gtk_label_new( caption );
|
||||
gtk_table_attach_defaults( GTK_TABLE( table ), label, 0, 1, row, row + 1 );
|
||||
gtk_widget_show( label );
|
||||
|
||||
entry = gtk_entry_new();
|
||||
sprintf( buffer, "%d", *value );
|
||||
gtk_entry_set_text( GTK_ENTRY( entry ), buffer );
|
||||
gtk_signal_connect( GTK_OBJECT( entry ), "changed",
|
||||
GTK_SIGNAL_FUNC( dialog_entry_gint32_callback ), value );
|
||||
gtk_table_attach_defaults( GTK_TABLE( table ), entry, 1, 2, row, row + 1 );
|
||||
gtk_widget_show( entry );
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void dialog_entry_gdouble_callback( GtkWidget *widget, gpointer *data )
|
||||
{
|
||||
gdouble value = (gdouble)atof( gtk_entry_get_text( GTK_ENTRY( widget ) ) );
|
||||
if( *(gdouble*)data != value ){
|
||||
*(gdouble*)data = value;
|
||||
dialog_preview_draw();
|
||||
}
|
||||
}
|
||||
|
||||
static void dialog_entry_gdouble_new( char *caption, gdouble *value,
|
||||
GtkWidget *table, gint row )
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry;
|
||||
char buffer[256];
|
||||
|
||||
label = gtk_label_new( caption );
|
||||
gtk_table_attach_defaults( GTK_TABLE( table ), label, 0, 1, row, row + 1 );
|
||||
gtk_widget_show( label );
|
||||
|
||||
entry = gtk_entry_new();
|
||||
sprintf( buffer, "%f", *value );
|
||||
gtk_entry_set_text( GTK_ENTRY( entry ), buffer );
|
||||
gtk_signal_connect( GTK_OBJECT( entry ), "changed",
|
||||
GTK_SIGNAL_FUNC( dialog_entry_gdouble_callback ), value );
|
||||
gtk_table_attach_defaults( GTK_TABLE( table ), entry, 1, 2, row, row + 1 );
|
||||
gtk_widget_show( entry );
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static GtkWidget* dialog_entry_table( void )
|
||||
{
|
||||
GtkWidget *table;
|
||||
|
||||
table = gtk_table_new( 5, 2, FALSE );
|
||||
gtk_table_set_row_spacings( GTK_TABLE( table ), 2 );
|
||||
gtk_table_set_col_spacings( GTK_TABLE( table ), 10 );
|
||||
dialog_entry_gdouble_new( "X1", ¶meters.x1, table, 0 );
|
||||
dialog_entry_gdouble_new( "X2", ¶meters.x2, table, 1 );
|
||||
dialog_entry_gdouble_new( "Y1", ¶meters.y1, table, 2 );
|
||||
dialog_entry_gdouble_new( "Y2", ¶meters.y2, table, 3 );
|
||||
dialog_entry_gint32_new( "DEPTH", ¶meters.depth, table, 4 );
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void dialog_destroy_callback( GtkWidget *widget, gpointer data )
|
||||
{
|
||||
gtk_main_quit();
|
||||
gdk_flush();
|
||||
}
|
||||
|
||||
static void dialog_ok_callback( GtkWidget *widget, gpointer data )
|
||||
{
|
||||
dialog_status = TRUE;
|
||||
gtk_widget_destroy( GTK_WIDGET( data ) );
|
||||
}
|
||||
|
||||
static void dialog_cancel_callback( GtkWidget *widget, gpointer data )
|
||||
{
|
||||
dialog_status = FALSE;
|
||||
gtk_widget_destroy( GTK_WIDGET( data ) );
|
||||
}
|
||||
|
||||
static void dialog_help_callback( GtkWidget *widget, gpointer data )
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void dialog_outside_type_callback( GtkWidget *widget, gpointer *data )
|
||||
{
|
||||
gint32 value = *(gint32*)data;
|
||||
|
||||
if( parameters.outside_type != value ){
|
||||
parameters.outside_type = value;
|
||||
dialog_preview_draw();
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#define PREVIEW_SIZE 200
|
||||
|
||||
typedef struct {
|
||||
GtkWidget *preview;
|
||||
guchar **source;
|
||||
guchar **pixels;
|
||||
gdouble scale;
|
||||
gint width;
|
||||
gint height;
|
||||
gint bpp;
|
||||
} preview_t;
|
||||
|
||||
static preview_t preview;
|
||||
|
||||
static void dialog_preview_setpixel( gint x, gint y, pixel_t *pixel )
|
||||
{
|
||||
switch( preview.bpp ){
|
||||
case 1:
|
||||
preview.pixels[y][x*preview.bpp] = pixel->r;
|
||||
break;
|
||||
case 3:
|
||||
preview.pixels[y][x*preview.bpp] = pixel->r;
|
||||
preview.pixels[y][x*preview.bpp+1] = pixel->g;
|
||||
preview.pixels[y][x*preview.bpp+2] = pixel->b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void dialog_preview_store( void )
|
||||
{
|
||||
gint y;
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
gtk_preview_draw_row( GTK_PREVIEW( preview.preview ),
|
||||
preview.pixels[y], 0, y, preview.width );
|
||||
}
|
||||
gtk_widget_draw( preview.preview, NULL );
|
||||
gdk_flush();
|
||||
}
|
||||
|
||||
static void dialog_preview_init( void )
|
||||
{
|
||||
{
|
||||
guchar *cube;
|
||||
gtk_preview_set_gamma( gimp_gamma() );
|
||||
gtk_preview_set_install_cmap( gimp_install_cmap() );
|
||||
cube = gimp_color_cube();
|
||||
gtk_preview_set_color_cube( cube[0], cube[1], cube[2], cube[3] );
|
||||
gtk_widget_set_default_visual( gtk_preview_get_visual() );
|
||||
gtk_widget_set_default_colormap( gtk_preview_get_cmap() );
|
||||
}
|
||||
|
||||
if( image.width < image.height )
|
||||
preview.scale = (gdouble)selection.height / (gdouble)PREVIEW_SIZE;
|
||||
else
|
||||
preview.scale = (gdouble)selection.width / (gdouble)PREVIEW_SIZE;
|
||||
preview.width = (gdouble)selection.width / preview.scale;
|
||||
preview.height = (gdouble)selection.height / preview.scale;
|
||||
|
||||
if( image.bpp < 3 ){
|
||||
preview.bpp = 1;
|
||||
preview.preview = gtk_preview_new( GTK_PREVIEW_GRAYSCALE );
|
||||
} else {
|
||||
preview.bpp = 3;
|
||||
preview.preview = gtk_preview_new( GTK_PREVIEW_COLOR );
|
||||
}
|
||||
gtk_preview_size( GTK_PREVIEW( preview.preview ), preview.width, preview.height );
|
||||
|
||||
{
|
||||
gint y;
|
||||
preview.source = (guchar**)g_malloc( preview.height * sizeof( guchar* ) );
|
||||
preview.pixels = (guchar**)g_malloc( preview.height * sizeof( guchar* ) );
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
preview.source[y] = (guchar*)g_malloc( preview.width * preview.bpp * sizeof( guchar ) );
|
||||
preview.pixels[y] = (guchar*)g_malloc( preview.width * preview.bpp * sizeof( guchar ) );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
pixel_t pixel;
|
||||
gint x, y;
|
||||
gdouble cx, cy;
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
cy = selection.y1 + (gdouble)y * preview.scale;
|
||||
for( x = 0; x < preview.width; x++ ){
|
||||
cx = selection.x1 + (gdouble)x * preview.scale;
|
||||
pixels_get_biliner( cx, cy, &pixel );
|
||||
dialog_preview_setpixel( x, y, &pixel );
|
||||
}
|
||||
}
|
||||
dialog_preview_store();
|
||||
}
|
||||
}
|
||||
|
||||
static void dialog_preview_free( void )
|
||||
{
|
||||
gint y;
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
free( preview.source[y] );
|
||||
free( preview.pixels[y] );
|
||||
}
|
||||
free( preview.source );
|
||||
free( preview.pixels );
|
||||
}
|
||||
|
||||
static void dialog_preview_draw( void )
|
||||
{
|
||||
gint x, y;
|
||||
pixel_t pixel;
|
||||
gdouble scale_x, scale_y;
|
||||
gdouble cx, cy;
|
||||
gdouble px, py;
|
||||
|
||||
scale_x = ( parameters.x2 - parameters.x1 ) / preview.width;
|
||||
scale_y = ( parameters.y2 - parameters.y1 ) / preview.height;
|
||||
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
cy = parameters.y1 + y * scale_y;
|
||||
for( x = 0; x < preview.width; x++ ){
|
||||
cx = parameters.x1 + x * scale_x;
|
||||
mandelbrot( cx, cy, &px, &py );
|
||||
px = ( px - parameters.x1 ) / scale_x * preview.scale + selection.x1;
|
||||
py = ( py - parameters.y1 ) / scale_y * preview.scale + selection.y1;
|
||||
if( 0 <= px && px < image.width && 0 <= py && py < image.height ){
|
||||
pixels_get_biliner( px, py, &pixel );
|
||||
} else {
|
||||
switch( parameters.outside_type ){
|
||||
case OUTSIDE_TYPE_WRAP:
|
||||
px = fmod( px, image.width );
|
||||
py = fmod( py, image.height );
|
||||
if( px < 0.0 ) px += image.width;
|
||||
if( py < 0.0 ) py += image.height;
|
||||
pixels_get_biliner( px, py, &pixel );
|
||||
break;
|
||||
case OUTSIDE_TYPE_TRANSPARENT:
|
||||
case OUTSIDE_TYPE_BLACK:
|
||||
pixel.r = pixel.g = pixel.b = 0;
|
||||
break;
|
||||
case OUTSIDE_TYPE_WHITE:
|
||||
pixel.r = pixel.g = pixel.b = 255;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dialog_preview_setpixel( x, y, &pixel );
|
||||
}
|
||||
}
|
||||
|
||||
dialog_preview_store();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static gint dialog_show( void )
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *mainbox;
|
||||
|
||||
dialog_status = FALSE;
|
||||
|
||||
{
|
||||
gint argc = 1;
|
||||
gchar **argv = g_new( gchar *, 1 );
|
||||
argv[0] = g_strdup( PLUG_IN_TITLE );
|
||||
gtk_init( &argc, &argv );
|
||||
gtk_rc_parse( gimp_gtkrc() );
|
||||
}
|
||||
|
||||
dialog = gtk_dialog_new();
|
||||
gtk_signal_connect( GTK_OBJECT( dialog ), "destroy",
|
||||
GTK_SIGNAL_FUNC( dialog_destroy_callback ), NULL );
|
||||
|
||||
mainbox = gtk_hbox_new( FALSE, 0 );
|
||||
gtk_container_add( GTK_CONTAINER( GTK_DIALOG( dialog )->vbox ), mainbox );
|
||||
gtk_widget_show( mainbox );
|
||||
|
||||
{
|
||||
GtkWidget *button;
|
||||
|
||||
button = gtk_button_new_with_label( "OK" );
|
||||
gtk_signal_connect_object( GTK_OBJECT( button ), "clicked",
|
||||
GTK_SIGNAL_FUNC( dialog_ok_callback ),
|
||||
GTK_OBJECT( dialog ) );
|
||||
gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialog )->action_area ),
|
||||
button, TRUE, TRUE, 0 );
|
||||
GTK_WIDGET_SET_FLAGS( button, GTK_CAN_DEFAULT );
|
||||
gtk_widget_grab_default( button );
|
||||
gtk_widget_show( button );
|
||||
|
||||
button = gtk_button_new_with_label( "Cancel" );
|
||||
gtk_signal_connect_object( GTK_OBJECT( button ), "clicked",
|
||||
GTK_SIGNAL_FUNC( dialog_cancel_callback ),
|
||||
GTK_OBJECT( dialog ) );
|
||||
gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialog )->action_area ),
|
||||
button, TRUE, TRUE, 0 );
|
||||
gtk_widget_show( button );
|
||||
|
||||
button = gtk_button_new_with_label( "Help" );
|
||||
gtk_signal_connect_object( GTK_OBJECT( button ), "clicked",
|
||||
GTK_SIGNAL_FUNC( dialog_help_callback ),
|
||||
GTK_OBJECT( dialog ) );
|
||||
gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialog )->action_area ),
|
||||
button, TRUE, TRUE, 0 );
|
||||
gtk_widget_show( button );
|
||||
}
|
||||
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *frame;
|
||||
|
||||
vbox = gtk_vbox_new( TRUE, 0 );
|
||||
gtk_container_border_width( GTK_CONTAINER( vbox ), 10 );
|
||||
gtk_box_pack_start( GTK_BOX( mainbox ), vbox, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( vbox );
|
||||
|
||||
frame = gtk_frame_new( NULL );
|
||||
gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN );
|
||||
gtk_box_pack_start( GTK_BOX( vbox ), frame, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( frame );
|
||||
|
||||
dialog_preview_init();
|
||||
gtk_container_add( GTK_CONTAINER( frame ), preview.preview );
|
||||
gtk_widget_show( preview.preview );
|
||||
}
|
||||
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *entrytable;
|
||||
GtkWidget *separator;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *framebox;
|
||||
GtkWidget *button;
|
||||
GSList *group;
|
||||
|
||||
vbox = gtk_vbox_new( FALSE, 0 );
|
||||
gtk_container_border_width( GTK_CONTAINER( vbox ), 10 );
|
||||
gtk_box_pack_start( GTK_BOX( mainbox ), vbox, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( vbox );
|
||||
|
||||
entrytable = dialog_entry_table();
|
||||
gtk_box_pack_start( GTK_BOX( vbox ), entrytable, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( entrytable );
|
||||
|
||||
separator = gtk_hseparator_new();
|
||||
gtk_box_pack_start( GTK_BOX( vbox ), separator, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( entrytable );
|
||||
|
||||
frame = gtk_frame_new( "Outside Type" );
|
||||
gtk_container_border_width( GTK_CONTAINER( frame ), 5 );
|
||||
gtk_box_pack_start( GTK_BOX( vbox ), frame, TRUE, TRUE, 0 );
|
||||
gtk_widget_show( frame );
|
||||
|
||||
framebox = gtk_vbox_new( FALSE, 0 );
|
||||
gtk_container_border_width( GTK_CONTAINER( framebox ), 5 );
|
||||
gtk_container_add( GTK_CONTAINER( frame ), framebox );
|
||||
gtk_widget_show( framebox );
|
||||
|
||||
group = NULL;
|
||||
|
||||
button = gtk_radio_button_new_with_label( group, "Wrap" );
|
||||
gtk_box_pack_start( GTK_BOX( framebox ), button, FALSE, FALSE, 0 );
|
||||
gtk_signal_connect( GTK_OBJECT( button ), "toggled",
|
||||
GTK_SIGNAL_FUNC( dialog_outside_type_callback ),
|
||||
&outside_type.wrap );
|
||||
gtk_widget_show( button );
|
||||
if( parameters.outside_type == OUTSIDE_TYPE_WRAP ){
|
||||
gtk_toggle_button_toggled( GTK_TOGGLE_BUTTON( button ) );
|
||||
gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( button ), TRUE );
|
||||
}
|
||||
group = gtk_radio_button_group( GTK_RADIO_BUTTON( button ) );
|
||||
|
||||
button = gtk_radio_button_new_with_label( group, "Transparent" );
|
||||
gtk_box_pack_start( GTK_BOX( framebox ), button, FALSE, FALSE, 0 );
|
||||
gtk_signal_connect( GTK_OBJECT( button ), "toggled",
|
||||
GTK_SIGNAL_FUNC( dialog_outside_type_callback ),
|
||||
&outside_type.transparent );
|
||||
gtk_widget_show( button );
|
||||
if( parameters.outside_type == OUTSIDE_TYPE_TRANSPARENT ){
|
||||
gtk_toggle_button_toggled( GTK_TOGGLE_BUTTON( button ) );
|
||||
gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( button ), TRUE );
|
||||
}
|
||||
if( !image.alpha ){
|
||||
gtk_widget_set_sensitive( button, FALSE );
|
||||
}
|
||||
group = gtk_radio_button_group( GTK_RADIO_BUTTON( button ) );
|
||||
|
||||
button = gtk_radio_button_new_with_label( group, "Black" );
|
||||
gtk_box_pack_start( GTK_BOX( framebox ), button, FALSE, FALSE, 0 );
|
||||
gtk_signal_connect( GTK_OBJECT( button ), "toggled",
|
||||
GTK_SIGNAL_FUNC( dialog_outside_type_callback ),
|
||||
&outside_type.black );
|
||||
gtk_widget_show( button );
|
||||
if( parameters.outside_type == OUTSIDE_TYPE_BLACK ){
|
||||
gtk_toggle_button_toggled( GTK_TOGGLE_BUTTON( button ) );
|
||||
gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( button ), TRUE );
|
||||
}
|
||||
group = gtk_radio_button_group( GTK_RADIO_BUTTON( button ) );
|
||||
|
||||
button = gtk_radio_button_new_with_label( group, "White" );
|
||||
gtk_box_pack_start( GTK_BOX( framebox ), button, FALSE, FALSE, 0 );
|
||||
gtk_signal_connect( GTK_OBJECT( button ), "toggled",
|
||||
GTK_SIGNAL_FUNC( dialog_outside_type_callback ),
|
||||
&outside_type.white );
|
||||
gtk_widget_show( button );
|
||||
if( parameters.outside_type == OUTSIDE_TYPE_WHITE ){
|
||||
gtk_toggle_button_toggled( GTK_TOGGLE_BUTTON( button ) );
|
||||
gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( button ), TRUE );
|
||||
}
|
||||
group = gtk_radio_button_group( GTK_RADIO_BUTTON( button ) );
|
||||
|
||||
}
|
||||
|
||||
gtk_widget_show( dialog );
|
||||
dialog_preview_draw();
|
||||
|
||||
gtk_main();
|
||||
|
||||
return dialog_status;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
|
@ -0,0 +1,5 @@
|
|||
Makefile.in
|
||||
Makefile
|
||||
.deps
|
||||
_libs
|
||||
fractaltrace
|
|
@ -0,0 +1,42 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
pluginlibdir = $(gimpplugindir)/plug-ins
|
||||
|
||||
pluginlib_PROGRAMS = fractaltrace
|
||||
|
||||
fractaltrace_SOURCES = \
|
||||
fractaltrace.c
|
||||
|
||||
INCLUDES = \
|
||||
$(X_CFLAGS) \
|
||||
-I$(top_srcdir) \
|
||||
-I$(includedir)
|
||||
|
||||
LDADD = \
|
||||
$(top_builddir)/libgimp/libgimpui.la \
|
||||
$(top_builddir)/libgimp/libgimp.la \
|
||||
$(X_LIBS) \
|
||||
\
|
||||
-lc
|
||||
|
||||
DEPS = \
|
||||
$(top_builddir)/libgimp/libgimpui.la \
|
||||
$(top_builddir)/libgimp/libgimp.la
|
||||
|
||||
fractaltrace_DEPENDENCIES = $(DEPS)
|
||||
|
||||
.PHONY: files
|
||||
|
||||
files:
|
||||
@files=`ls $(DISTFILES) 2> /dev/null`; for p in $$files; do \
|
||||
echo $$p; \
|
||||
done
|
||||
@for subdir in $(SUBDIRS); do \
|
||||
files=`cd $$subdir; $(MAKE) files | grep -v "make\[[1-9]\]"`; \
|
||||
for file in $$files; do \
|
||||
echo $$subdir/$$file; \
|
||||
done; \
|
||||
done
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,904 @@
|
|||
/*******************************************************************************
|
||||
|
||||
fractaltrace.c -- This is a plug-in for the GIMP 1.0
|
||||
|
||||
Copyright (C) 1997 Hirotsuna Mizuno
|
||||
s1041150@u-aizu.ac.jp
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#define PLUG_IN_NAME "plug_in_fractal_trace"
|
||||
#define PLUG_IN_TITLE "Fractal Trace"
|
||||
#define PLUG_IN_VERSION "v0.4 test version (Dec. 25 1997)"
|
||||
#define PLUG_IN_CATEGORY "<Image>/Filters/Distorts/Fractal Trace"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <math.h>
|
||||
#include <libgimp/gimp.h>
|
||||
|
||||
#ifndef PI_2
|
||||
#define PI_2 (3.14159265358979323*2.0)
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void query( void );
|
||||
static void run( char*, int, GParam*, int*, GParam** );
|
||||
static void filter( GDrawable* );
|
||||
|
||||
static void pixels_init( GDrawable* );
|
||||
static void pixels_free( void );
|
||||
|
||||
static int dialog_show( void );
|
||||
static void dialog_preview_draw( void );
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
GPlugInInfo PLUG_IN_INFO = {
|
||||
NULL, /* init_proc */
|
||||
NULL, /* quit_proc */
|
||||
query, /* query_proc */
|
||||
run /* run_proc */
|
||||
};
|
||||
|
||||
MAIN();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
gint32 wrap;
|
||||
gint32 transparent;
|
||||
gint32 black;
|
||||
gint32 white;
|
||||
} outside_type_t;
|
||||
|
||||
#define OUTSIDE_TYPE_WRAP 0
|
||||
#define OUTSIDE_TYPE_TRANSPARENT 1
|
||||
#define OUTSIDE_TYPE_BLACK 2
|
||||
#define OUTSIDE_TYPE_WHITE 3
|
||||
|
||||
static outside_type_t outside_type = {
|
||||
OUTSIDE_TYPE_WRAP,
|
||||
OUTSIDE_TYPE_TRANSPARENT,
|
||||
OUTSIDE_TYPE_BLACK,
|
||||
OUTSIDE_TYPE_WHITE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
gdouble x1;
|
||||
gdouble x2;
|
||||
gdouble y1;
|
||||
gdouble y2;
|
||||
gint32 depth;
|
||||
gint32 outside_type;
|
||||
} parameter_t;
|
||||
|
||||
static parameter_t parameters = {
|
||||
-1.0,
|
||||
+0.5,
|
||||
-1.0,
|
||||
+1.0,
|
||||
3,
|
||||
OUTSIDE_TYPE_WRAP
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void query( void )
|
||||
{
|
||||
static GParamDef args[] = {
|
||||
{ PARAM_INT32, "run_mode", "interactive / non-interactive" },
|
||||
{ PARAM_IMAGE, "image", "input image (not used)" },
|
||||
{ PARAM_DRAWABLE, "drawable", "input drawable" },
|
||||
{ PARAM_FLOAT, "xmin", "xmin fractal image delimiter" },
|
||||
{ PARAM_FLOAT, "xmax", "xmax fractal image delimiter" },
|
||||
{ PARAM_FLOAT, "ymin", "ymin fractal image delimiter" },
|
||||
{ PARAM_FLOAT, "ymax", "ymax fractal image delimiter" },
|
||||
{ PARAM_FLOAT, "ymax", "ymax fractal image delimiter" },
|
||||
{ PARAM_INT32, "depth", "trace depth" },
|
||||
{ PARAM_INT32, "outside_type", "outside type"
|
||||
"(0=WRAP/1=TRANS/2=BLACK/3=WHITE)" },
|
||||
};
|
||||
static int nargs = sizeof( args ) / sizeof( args[0] );
|
||||
|
||||
static GParamDef *rets = NULL;
|
||||
static int nrets = 0;
|
||||
|
||||
gimp_install_procedure(
|
||||
PLUG_IN_NAME,
|
||||
"transform image with the Mandelbrot Fractal",
|
||||
"transform image with the Mandelbrot Fractal",
|
||||
"Hirotsuna Mizuno <s1041150@u-aizu.ac.jp>",
|
||||
"Copyright (C) 1997 Hirotsuna Mizuno",
|
||||
PLUG_IN_VERSION,
|
||||
PLUG_IN_CATEGORY,
|
||||
"RGB*, GRAY*",
|
||||
PROC_PLUG_IN,
|
||||
nargs,
|
||||
nrets,
|
||||
args,
|
||||
rets
|
||||
);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
gint x1;
|
||||
gint x2;
|
||||
gint y1;
|
||||
gint y2;
|
||||
gint width;
|
||||
gint height;
|
||||
gdouble center_x;
|
||||
gdouble center_y;
|
||||
} selection_t;
|
||||
|
||||
typedef struct {
|
||||
gint width;
|
||||
gint height;
|
||||
gint bpp;
|
||||
gint alpha;
|
||||
} image_t;
|
||||
|
||||
static selection_t selection;
|
||||
static image_t image;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void run( char *name, int argc, GParam *args, int *retc, GParam **rets )
|
||||
{
|
||||
GDrawable *drawable;
|
||||
GRunModeType run_mode;
|
||||
GStatusType status;
|
||||
static GParam returns[1];
|
||||
|
||||
run_mode = args[0].data.d_int32;
|
||||
status = STATUS_SUCCESS;
|
||||
|
||||
drawable = gimp_drawable_get( args[2].data.d_drawable );
|
||||
image.width = gimp_drawable_width( drawable->id );
|
||||
image.height = gimp_drawable_height( drawable->id );
|
||||
image.bpp = gimp_drawable_bpp( drawable->id );
|
||||
image.alpha = gimp_drawable_has_alpha( drawable->id );
|
||||
gimp_drawable_mask_bounds( drawable->id, &selection.x1, &selection.y1,
|
||||
&selection.x2, &selection.y2 );
|
||||
selection.width = selection.x2 - selection.y1;
|
||||
selection.height = selection.y2 - selection.y1;
|
||||
selection.center_x = selection.x1 + (gdouble)selection.width / 2.0;
|
||||
selection.center_y = selection.y1 + (gdouble)selection.height / 2.0;
|
||||
|
||||
pixels_init( drawable );
|
||||
|
||||
if( !gimp_drawable_color( drawable->id ) &&
|
||||
!gimp_drawable_gray( drawable->id ) ){
|
||||
status = STATUS_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
switch( run_mode ){
|
||||
case RUN_WITH_LAST_VALS:
|
||||
gimp_get_data( PLUG_IN_NAME, ¶meters );
|
||||
break;
|
||||
case RUN_INTERACTIVE:
|
||||
gimp_get_data( PLUG_IN_NAME, ¶meters );
|
||||
if( !dialog_show() ){
|
||||
status = STATUS_EXECUTION_ERROR;
|
||||
break;
|
||||
}
|
||||
gimp_set_data( PLUG_IN_NAME, ¶meters, sizeof( parameter_t ) );
|
||||
break;
|
||||
case RUN_NONINTERACTIVE:
|
||||
if( argc != 9 ){
|
||||
status = STATUS_CALLING_ERROR;
|
||||
} else {
|
||||
parameters.x1 = args[3].data.d_float;
|
||||
parameters.x2 = args[4].data.d_float;
|
||||
parameters.y1 = args[5].data.d_float;
|
||||
parameters.y2 = args[6].data.d_float;
|
||||
parameters.depth = args[7].data.d_int32;
|
||||
parameters.outside_type = args[8].data.d_int32;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if( status == STATUS_SUCCESS ){
|
||||
gimp_tile_cache_ntiles( 2 * ( drawable->width / gimp_tile_width() + 1 ) );
|
||||
filter( drawable );
|
||||
if( run_mode != RUN_NONINTERACTIVE ) gimp_displays_flush();
|
||||
}
|
||||
|
||||
gimp_drawable_detach( drawable );
|
||||
|
||||
pixels_free();
|
||||
|
||||
returns[0].type = PARAM_STATUS;
|
||||
returns[0].data.d_status = status;
|
||||
*retc = 1;
|
||||
*rets = returns;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static guchar **spixels;
|
||||
static guchar **dpixels;
|
||||
static GPixelRgn sPR;
|
||||
static GPixelRgn dPR;
|
||||
|
||||
typedef struct {
|
||||
guchar r;
|
||||
guchar g;
|
||||
guchar b;
|
||||
guchar a;
|
||||
} pixel_t;
|
||||
|
||||
static void pixels_init( GDrawable *drawable )
|
||||
{
|
||||
gint y;
|
||||
gimp_pixel_rgn_init( &sPR, drawable,
|
||||
0, 0, image.width, image.height, FALSE, FALSE );
|
||||
gimp_pixel_rgn_init( &dPR, drawable,
|
||||
0, 0, image.width, image.height, TRUE, TRUE );
|
||||
spixels = (guchar**)g_malloc( image.height * sizeof( guchar* ) );
|
||||
dpixels = (guchar**)g_malloc( image.height * sizeof( guchar* ) );
|
||||
for( y = 0; y < image.height; y++ ){
|
||||
spixels[y] = (guchar*)g_malloc( image.width * image.bpp * sizeof( guchar ) );
|
||||
dpixels[y] = (guchar*)g_malloc( image.width * image.bpp * sizeof( guchar ) );
|
||||
gimp_pixel_rgn_get_row( &sPR, spixels[y], 0, y, image.width );
|
||||
}
|
||||
}
|
||||
|
||||
static void pixels_free( void )
|
||||
{
|
||||
gint y;
|
||||
for( y = 0; y < image.height; y++ ){
|
||||
free( spixels[y] );
|
||||
free( dpixels[y] );
|
||||
}
|
||||
free( spixels );
|
||||
free( dpixels );
|
||||
}
|
||||
|
||||
static void pixels_get( gint x, gint y, pixel_t *pixel )
|
||||
{
|
||||
if( x < 0 ) x = 0; else if( image.width <= x ) x = image.width - 1;
|
||||
if( y < 0 ) y = 0; else if( image.height <= y ) y = image.height - 1;
|
||||
|
||||
switch( image.bpp ){
|
||||
case 1: /* GRAY */
|
||||
pixel->r = spixels[y][x*image.bpp];
|
||||
pixel->g = spixels[y][x*image.bpp];
|
||||
pixel->b = spixels[y][x*image.bpp];
|
||||
pixel->a = 255;
|
||||
break;
|
||||
case 2: /* GRAY+A */
|
||||
pixel->r = spixels[y][x*image.bpp];
|
||||
pixel->g = spixels[y][x*image.bpp];
|
||||
pixel->b = spixels[y][x*image.bpp];
|
||||
pixel->a = spixels[y][x*image.bpp+1];
|
||||
break;
|
||||
case 3: /* RGB */
|
||||
pixel->r = spixels[y][x*image.bpp];
|
||||
pixel->g = spixels[y][x*image.bpp+1];
|
||||
pixel->b = spixels[y][x*image.bpp+2];
|
||||
pixel->a = 255;
|
||||
break;
|
||||
case 4: /* RGB+A */
|
||||
pixel->r = spixels[y][x*image.bpp];
|
||||
pixel->g = spixels[y][x*image.bpp+1];
|
||||
pixel->b = spixels[y][x*image.bpp+2];
|
||||
pixel->a = spixels[y][x*image.bpp+3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pixels_get_biliner( gdouble x, gdouble y, pixel_t *pixel )
|
||||
{
|
||||
pixel_t A, B, C, D;
|
||||
gdouble a, b, c, d;
|
||||
gint x1, y1, x2, y2;
|
||||
gdouble dx, dy;
|
||||
|
||||
x1 = (gint)floor( x );
|
||||
x2 = x1 + 1;
|
||||
y1 = (gint)floor( y );
|
||||
y2 = y1 + 1;
|
||||
|
||||
dx = x - (gdouble)x1;
|
||||
dy = y - (gdouble)y1;
|
||||
a = ( 1.0 - dx ) * ( 1.0 - dy );
|
||||
b = dx * ( 1.0 - dy );
|
||||
c = ( 1.0 - dx ) * dy;
|
||||
d = dx * dy;
|
||||
|
||||
pixels_get( x1, y1, &A );
|
||||
pixels_get( x2, y1, &B );
|
||||
pixels_get( x1, y2, &C );
|
||||
pixels_get( x2, y2, &D );
|
||||
|
||||
pixel->r = (guchar)( a * (gdouble)A.r + b * (gdouble)B.r +
|
||||
c * (gdouble)C.r + d * (gdouble)D.r );
|
||||
pixel->g = (guchar)( a * (gdouble)A.g + b * (gdouble)B.g +
|
||||
c * (gdouble)C.g + d * (gdouble)D.g );
|
||||
pixel->b = (guchar)( a * (gdouble)A.b + b * (gdouble)B.b +
|
||||
c * (gdouble)C.b + d * (gdouble)D.b );
|
||||
pixel->a = (guchar)( a * (gdouble)A.a + b * (gdouble)B.a +
|
||||
c * (gdouble)C.a + d * (gdouble)D.a );
|
||||
}
|
||||
|
||||
static void pixels_set( gint x, gint y, pixel_t *pixel )
|
||||
{
|
||||
switch( image.bpp ){
|
||||
case 1: /* GRAY */
|
||||
dpixels[y][x*image.bpp] = pixel->r;
|
||||
break;
|
||||
case 2: /* GRAY+A */
|
||||
dpixels[y][x*image.bpp] = pixel->r;
|
||||
dpixels[y][x*image.bpp+1] = pixel->a;
|
||||
break;
|
||||
case 3: /* RGB */
|
||||
dpixels[y][x*image.bpp] = pixel->r;
|
||||
dpixels[y][x*image.bpp+1] = pixel->g;
|
||||
dpixels[y][x*image.bpp+2] = pixel->b;
|
||||
break;
|
||||
case 4: /* RGB+A */
|
||||
dpixels[y][x*image.bpp] = pixel->r;
|
||||
dpixels[y][x*image.bpp+1] = pixel->g;
|
||||
dpixels[y][x*image.bpp+2] = pixel->b;
|
||||
dpixels[y][x*image.bpp+3] = pixel->a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pixels_store( void )
|
||||
{
|
||||
gint y;
|
||||
for( y = selection.y1; y < selection.y2; y++ ){
|
||||
gimp_pixel_rgn_set_row( &dPR, dpixels[y], 0, y, image.width );
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void mandelbrot( gdouble x, gdouble y, gdouble *u, gdouble *v )
|
||||
{
|
||||
gint iter = 0;
|
||||
gdouble xx = x;
|
||||
gdouble yy = y;
|
||||
gdouble x2 = xx * xx;
|
||||
gdouble y2 = yy * yy;
|
||||
gdouble tmp;
|
||||
while( iter < parameters.depth ){
|
||||
tmp = x2 - y2 + x;
|
||||
yy = 2 * xx * yy + y;
|
||||
xx = tmp;
|
||||
x2 = xx * xx;
|
||||
y2 = yy * yy;
|
||||
iter++;
|
||||
}
|
||||
*u = xx;
|
||||
*v = yy;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void filter( GDrawable *drawable )
|
||||
{
|
||||
gint x, y;
|
||||
pixel_t pixel;
|
||||
gdouble scale_x, scale_y;
|
||||
gdouble cx, cy;
|
||||
gdouble px, py;
|
||||
|
||||
gimp_progress_init( PLUG_IN_TITLE );
|
||||
|
||||
scale_x = ( parameters.x2 - parameters.x1 ) / selection.width;
|
||||
scale_y = ( parameters.y2 - parameters.y1 ) / selection.height;
|
||||
|
||||
for( y = selection.y1; y < selection.y2; y++ ){
|
||||
cy = parameters.y1 + ( y - selection.y1 ) * scale_y;
|
||||
for( x = selection.x1; x < selection.x2; x++ ){
|
||||
cx = parameters.x1 + ( x - selection.x1 ) * scale_x;
|
||||
mandelbrot( cx, cy, &px, &py );
|
||||
px = ( px - parameters.x1 ) / scale_x + selection.x1;
|
||||
py = ( py - parameters.y1 ) / scale_y + selection.y1;
|
||||
if( 0 <= px && px < image.width && 0 <= py && py < image.height ){
|
||||
pixels_get_biliner( px, py, &pixel );
|
||||
} else {
|
||||
switch( parameters.outside_type ){
|
||||
case OUTSIDE_TYPE_WRAP:
|
||||
px = fmod( px, image.width );
|
||||
py = fmod( py, image.height );
|
||||
if( px < 0.0 ) px += image.width;
|
||||
if( py < 0.0 ) py += image.height;
|
||||
pixels_get_biliner( px, py, &pixel );
|
||||
break;
|
||||
case OUTSIDE_TYPE_TRANSPARENT:
|
||||
pixel.r = pixel.g = pixel.b = 0;
|
||||
pixel.a = 0;
|
||||
break;
|
||||
case OUTSIDE_TYPE_BLACK:
|
||||
pixel.r = pixel.g = pixel.b = 0;
|
||||
pixel.a = 255;
|
||||
break;
|
||||
case OUTSIDE_TYPE_WHITE:
|
||||
pixel.r = pixel.g = pixel.b = 255;
|
||||
pixel.a = 255;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pixels_set( x, y, &pixel );
|
||||
}
|
||||
gimp_progress_update( (gdouble)(y-selection.y1)/selection.height );
|
||||
}
|
||||
|
||||
pixels_store();
|
||||
|
||||
gimp_drawable_flush( drawable );
|
||||
gimp_drawable_merge_shadow( drawable->id, TRUE );
|
||||
gimp_drawable_update( drawable->id,
|
||||
selection.x1, selection.y1, selection.width, selection.height );
|
||||
}
|
||||
|
||||
/*
|
||||
GUI
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int dialog_status;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void dialog_entry_gint32_callback( GtkWidget *widget, gpointer *data )
|
||||
{
|
||||
gint32 value = (gint32)atof( gtk_entry_get_text( GTK_ENTRY( widget ) ) );
|
||||
if( *(gint32*)data != value ){
|
||||
*(gint32*)data = value;
|
||||
dialog_preview_draw();
|
||||
}
|
||||
}
|
||||
|
||||
static void dialog_entry_gint32_new( char *caption, gint32 *value,
|
||||
GtkWidget *table, gint row )
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry;
|
||||
char buffer[256];
|
||||
|
||||
label = gtk_label_new( caption );
|
||||
gtk_table_attach_defaults( GTK_TABLE( table ), label, 0, 1, row, row + 1 );
|
||||
gtk_widget_show( label );
|
||||
|
||||
entry = gtk_entry_new();
|
||||
sprintf( buffer, "%d", *value );
|
||||
gtk_entry_set_text( GTK_ENTRY( entry ), buffer );
|
||||
gtk_signal_connect( GTK_OBJECT( entry ), "changed",
|
||||
GTK_SIGNAL_FUNC( dialog_entry_gint32_callback ), value );
|
||||
gtk_table_attach_defaults( GTK_TABLE( table ), entry, 1, 2, row, row + 1 );
|
||||
gtk_widget_show( entry );
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void dialog_entry_gdouble_callback( GtkWidget *widget, gpointer *data )
|
||||
{
|
||||
gdouble value = (gdouble)atof( gtk_entry_get_text( GTK_ENTRY( widget ) ) );
|
||||
if( *(gdouble*)data != value ){
|
||||
*(gdouble*)data = value;
|
||||
dialog_preview_draw();
|
||||
}
|
||||
}
|
||||
|
||||
static void dialog_entry_gdouble_new( char *caption, gdouble *value,
|
||||
GtkWidget *table, gint row )
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry;
|
||||
char buffer[256];
|
||||
|
||||
label = gtk_label_new( caption );
|
||||
gtk_table_attach_defaults( GTK_TABLE( table ), label, 0, 1, row, row + 1 );
|
||||
gtk_widget_show( label );
|
||||
|
||||
entry = gtk_entry_new();
|
||||
sprintf( buffer, "%f", *value );
|
||||
gtk_entry_set_text( GTK_ENTRY( entry ), buffer );
|
||||
gtk_signal_connect( GTK_OBJECT( entry ), "changed",
|
||||
GTK_SIGNAL_FUNC( dialog_entry_gdouble_callback ), value );
|
||||
gtk_table_attach_defaults( GTK_TABLE( table ), entry, 1, 2, row, row + 1 );
|
||||
gtk_widget_show( entry );
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static GtkWidget* dialog_entry_table( void )
|
||||
{
|
||||
GtkWidget *table;
|
||||
|
||||
table = gtk_table_new( 5, 2, FALSE );
|
||||
gtk_table_set_row_spacings( GTK_TABLE( table ), 2 );
|
||||
gtk_table_set_col_spacings( GTK_TABLE( table ), 10 );
|
||||
dialog_entry_gdouble_new( "X1", ¶meters.x1, table, 0 );
|
||||
dialog_entry_gdouble_new( "X2", ¶meters.x2, table, 1 );
|
||||
dialog_entry_gdouble_new( "Y1", ¶meters.y1, table, 2 );
|
||||
dialog_entry_gdouble_new( "Y2", ¶meters.y2, table, 3 );
|
||||
dialog_entry_gint32_new( "DEPTH", ¶meters.depth, table, 4 );
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void dialog_destroy_callback( GtkWidget *widget, gpointer data )
|
||||
{
|
||||
gtk_main_quit();
|
||||
gdk_flush();
|
||||
}
|
||||
|
||||
static void dialog_ok_callback( GtkWidget *widget, gpointer data )
|
||||
{
|
||||
dialog_status = TRUE;
|
||||
gtk_widget_destroy( GTK_WIDGET( data ) );
|
||||
}
|
||||
|
||||
static void dialog_cancel_callback( GtkWidget *widget, gpointer data )
|
||||
{
|
||||
dialog_status = FALSE;
|
||||
gtk_widget_destroy( GTK_WIDGET( data ) );
|
||||
}
|
||||
|
||||
static void dialog_help_callback( GtkWidget *widget, gpointer data )
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void dialog_outside_type_callback( GtkWidget *widget, gpointer *data )
|
||||
{
|
||||
gint32 value = *(gint32*)data;
|
||||
|
||||
if( parameters.outside_type != value ){
|
||||
parameters.outside_type = value;
|
||||
dialog_preview_draw();
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#define PREVIEW_SIZE 200
|
||||
|
||||
typedef struct {
|
||||
GtkWidget *preview;
|
||||
guchar **source;
|
||||
guchar **pixels;
|
||||
gdouble scale;
|
||||
gint width;
|
||||
gint height;
|
||||
gint bpp;
|
||||
} preview_t;
|
||||
|
||||
static preview_t preview;
|
||||
|
||||
static void dialog_preview_setpixel( gint x, gint y, pixel_t *pixel )
|
||||
{
|
||||
switch( preview.bpp ){
|
||||
case 1:
|
||||
preview.pixels[y][x*preview.bpp] = pixel->r;
|
||||
break;
|
||||
case 3:
|
||||
preview.pixels[y][x*preview.bpp] = pixel->r;
|
||||
preview.pixels[y][x*preview.bpp+1] = pixel->g;
|
||||
preview.pixels[y][x*preview.bpp+2] = pixel->b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void dialog_preview_store( void )
|
||||
{
|
||||
gint y;
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
gtk_preview_draw_row( GTK_PREVIEW( preview.preview ),
|
||||
preview.pixels[y], 0, y, preview.width );
|
||||
}
|
||||
gtk_widget_draw( preview.preview, NULL );
|
||||
gdk_flush();
|
||||
}
|
||||
|
||||
static void dialog_preview_init( void )
|
||||
{
|
||||
{
|
||||
guchar *cube;
|
||||
gtk_preview_set_gamma( gimp_gamma() );
|
||||
gtk_preview_set_install_cmap( gimp_install_cmap() );
|
||||
cube = gimp_color_cube();
|
||||
gtk_preview_set_color_cube( cube[0], cube[1], cube[2], cube[3] );
|
||||
gtk_widget_set_default_visual( gtk_preview_get_visual() );
|
||||
gtk_widget_set_default_colormap( gtk_preview_get_cmap() );
|
||||
}
|
||||
|
||||
if( image.width < image.height )
|
||||
preview.scale = (gdouble)selection.height / (gdouble)PREVIEW_SIZE;
|
||||
else
|
||||
preview.scale = (gdouble)selection.width / (gdouble)PREVIEW_SIZE;
|
||||
preview.width = (gdouble)selection.width / preview.scale;
|
||||
preview.height = (gdouble)selection.height / preview.scale;
|
||||
|
||||
if( image.bpp < 3 ){
|
||||
preview.bpp = 1;
|
||||
preview.preview = gtk_preview_new( GTK_PREVIEW_GRAYSCALE );
|
||||
} else {
|
||||
preview.bpp = 3;
|
||||
preview.preview = gtk_preview_new( GTK_PREVIEW_COLOR );
|
||||
}
|
||||
gtk_preview_size( GTK_PREVIEW( preview.preview ), preview.width, preview.height );
|
||||
|
||||
{
|
||||
gint y;
|
||||
preview.source = (guchar**)g_malloc( preview.height * sizeof( guchar* ) );
|
||||
preview.pixels = (guchar**)g_malloc( preview.height * sizeof( guchar* ) );
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
preview.source[y] = (guchar*)g_malloc( preview.width * preview.bpp * sizeof( guchar ) );
|
||||
preview.pixels[y] = (guchar*)g_malloc( preview.width * preview.bpp * sizeof( guchar ) );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
pixel_t pixel;
|
||||
gint x, y;
|
||||
gdouble cx, cy;
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
cy = selection.y1 + (gdouble)y * preview.scale;
|
||||
for( x = 0; x < preview.width; x++ ){
|
||||
cx = selection.x1 + (gdouble)x * preview.scale;
|
||||
pixels_get_biliner( cx, cy, &pixel );
|
||||
dialog_preview_setpixel( x, y, &pixel );
|
||||
}
|
||||
}
|
||||
dialog_preview_store();
|
||||
}
|
||||
}
|
||||
|
||||
static void dialog_preview_free( void )
|
||||
{
|
||||
gint y;
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
free( preview.source[y] );
|
||||
free( preview.pixels[y] );
|
||||
}
|
||||
free( preview.source );
|
||||
free( preview.pixels );
|
||||
}
|
||||
|
||||
static void dialog_preview_draw( void )
|
||||
{
|
||||
gint x, y;
|
||||
pixel_t pixel;
|
||||
gdouble scale_x, scale_y;
|
||||
gdouble cx, cy;
|
||||
gdouble px, py;
|
||||
|
||||
scale_x = ( parameters.x2 - parameters.x1 ) / preview.width;
|
||||
scale_y = ( parameters.y2 - parameters.y1 ) / preview.height;
|
||||
|
||||
for( y = 0; y < preview.height; y++ ){
|
||||
cy = parameters.y1 + y * scale_y;
|
||||
for( x = 0; x < preview.width; x++ ){
|
||||
cx = parameters.x1 + x * scale_x;
|
||||
mandelbrot( cx, cy, &px, &py );
|
||||
px = ( px - parameters.x1 ) / scale_x * preview.scale + selection.x1;
|
||||
py = ( py - parameters.y1 ) / scale_y * preview.scale + selection.y1;
|
||||
if( 0 <= px && px < image.width && 0 <= py && py < image.height ){
|
||||
pixels_get_biliner( px, py, &pixel );
|
||||
} else {
|
||||
switch( parameters.outside_type ){
|
||||
case OUTSIDE_TYPE_WRAP:
|
||||
px = fmod( px, image.width );
|
||||
py = fmod( py, image.height );
|
||||
if( px < 0.0 ) px += image.width;
|
||||
if( py < 0.0 ) py += image.height;
|
||||
pixels_get_biliner( px, py, &pixel );
|
||||
break;
|
||||
case OUTSIDE_TYPE_TRANSPARENT:
|
||||
case OUTSIDE_TYPE_BLACK:
|
||||
pixel.r = pixel.g = pixel.b = 0;
|
||||
break;
|
||||
case OUTSIDE_TYPE_WHITE:
|
||||
pixel.r = pixel.g = pixel.b = 255;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dialog_preview_setpixel( x, y, &pixel );
|
||||
}
|
||||
}
|
||||
|
||||
dialog_preview_store();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static gint dialog_show( void )
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *mainbox;
|
||||
|
||||
dialog_status = FALSE;
|
||||
|
||||
{
|
||||
gint argc = 1;
|
||||
gchar **argv = g_new( gchar *, 1 );
|
||||
argv[0] = g_strdup( PLUG_IN_TITLE );
|
||||
gtk_init( &argc, &argv );
|
||||
gtk_rc_parse( gimp_gtkrc() );
|
||||
}
|
||||
|
||||
dialog = gtk_dialog_new();
|
||||
gtk_signal_connect( GTK_OBJECT( dialog ), "destroy",
|
||||
GTK_SIGNAL_FUNC( dialog_destroy_callback ), NULL );
|
||||
|
||||
mainbox = gtk_hbox_new( FALSE, 0 );
|
||||
gtk_container_add( GTK_CONTAINER( GTK_DIALOG( dialog )->vbox ), mainbox );
|
||||
gtk_widget_show( mainbox );
|
||||
|
||||
{
|
||||
GtkWidget *button;
|
||||
|
||||
button = gtk_button_new_with_label( "OK" );
|
||||
gtk_signal_connect_object( GTK_OBJECT( button ), "clicked",
|
||||
GTK_SIGNAL_FUNC( dialog_ok_callback ),
|
||||
GTK_OBJECT( dialog ) );
|
||||
gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialog )->action_area ),
|
||||
button, TRUE, TRUE, 0 );
|
||||
GTK_WIDGET_SET_FLAGS( button, GTK_CAN_DEFAULT );
|
||||
gtk_widget_grab_default( button );
|
||||
gtk_widget_show( button );
|
||||
|
||||
button = gtk_button_new_with_label( "Cancel" );
|
||||
gtk_signal_connect_object( GTK_OBJECT( button ), "clicked",
|
||||
GTK_SIGNAL_FUNC( dialog_cancel_callback ),
|
||||
GTK_OBJECT( dialog ) );
|
||||
gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialog )->action_area ),
|
||||
button, TRUE, TRUE, 0 );
|
||||
gtk_widget_show( button );
|
||||
|
||||
button = gtk_button_new_with_label( "Help" );
|
||||
gtk_signal_connect_object( GTK_OBJECT( button ), "clicked",
|
||||
GTK_SIGNAL_FUNC( dialog_help_callback ),
|
||||
GTK_OBJECT( dialog ) );
|
||||
gtk_box_pack_start( GTK_BOX( GTK_DIALOG( dialog )->action_area ),
|
||||
button, TRUE, TRUE, 0 );
|
||||
gtk_widget_show( button );
|
||||
}
|
||||
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *frame;
|
||||
|
||||
vbox = gtk_vbox_new( TRUE, 0 );
|
||||
gtk_container_border_width( GTK_CONTAINER( vbox ), 10 );
|
||||
gtk_box_pack_start( GTK_BOX( mainbox ), vbox, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( vbox );
|
||||
|
||||
frame = gtk_frame_new( NULL );
|
||||
gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN );
|
||||
gtk_box_pack_start( GTK_BOX( vbox ), frame, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( frame );
|
||||
|
||||
dialog_preview_init();
|
||||
gtk_container_add( GTK_CONTAINER( frame ), preview.preview );
|
||||
gtk_widget_show( preview.preview );
|
||||
}
|
||||
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *entrytable;
|
||||
GtkWidget *separator;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *framebox;
|
||||
GtkWidget *button;
|
||||
GSList *group;
|
||||
|
||||
vbox = gtk_vbox_new( FALSE, 0 );
|
||||
gtk_container_border_width( GTK_CONTAINER( vbox ), 10 );
|
||||
gtk_box_pack_start( GTK_BOX( mainbox ), vbox, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( vbox );
|
||||
|
||||
entrytable = dialog_entry_table();
|
||||
gtk_box_pack_start( GTK_BOX( vbox ), entrytable, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( entrytable );
|
||||
|
||||
separator = gtk_hseparator_new();
|
||||
gtk_box_pack_start( GTK_BOX( vbox ), separator, FALSE, FALSE, 0 );
|
||||
gtk_widget_show( entrytable );
|
||||
|
||||
frame = gtk_frame_new( "Outside Type" );
|
||||
gtk_container_border_width( GTK_CONTAINER( frame ), 5 );
|
||||
gtk_box_pack_start( GTK_BOX( vbox ), frame, TRUE, TRUE, 0 );
|
||||
gtk_widget_show( frame );
|
||||
|
||||
framebox = gtk_vbox_new( FALSE, 0 );
|
||||
gtk_container_border_width( GTK_CONTAINER( framebox ), 5 );
|
||||
gtk_container_add( GTK_CONTAINER( frame ), framebox );
|
||||
gtk_widget_show( framebox );
|
||||
|
||||
group = NULL;
|
||||
|
||||
button = gtk_radio_button_new_with_label( group, "Wrap" );
|
||||
gtk_box_pack_start( GTK_BOX( framebox ), button, FALSE, FALSE, 0 );
|
||||
gtk_signal_connect( GTK_OBJECT( button ), "toggled",
|
||||
GTK_SIGNAL_FUNC( dialog_outside_type_callback ),
|
||||
&outside_type.wrap );
|
||||
gtk_widget_show( button );
|
||||
if( parameters.outside_type == OUTSIDE_TYPE_WRAP ){
|
||||
gtk_toggle_button_toggled( GTK_TOGGLE_BUTTON( button ) );
|
||||
gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( button ), TRUE );
|
||||
}
|
||||
group = gtk_radio_button_group( GTK_RADIO_BUTTON( button ) );
|
||||
|
||||
button = gtk_radio_button_new_with_label( group, "Transparent" );
|
||||
gtk_box_pack_start( GTK_BOX( framebox ), button, FALSE, FALSE, 0 );
|
||||
gtk_signal_connect( GTK_OBJECT( button ), "toggled",
|
||||
GTK_SIGNAL_FUNC( dialog_outside_type_callback ),
|
||||
&outside_type.transparent );
|
||||
gtk_widget_show( button );
|
||||
if( parameters.outside_type == OUTSIDE_TYPE_TRANSPARENT ){
|
||||
gtk_toggle_button_toggled( GTK_TOGGLE_BUTTON( button ) );
|
||||
gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( button ), TRUE );
|
||||
}
|
||||
if( !image.alpha ){
|
||||
gtk_widget_set_sensitive( button, FALSE );
|
||||
}
|
||||
group = gtk_radio_button_group( GTK_RADIO_BUTTON( button ) );
|
||||
|
||||
button = gtk_radio_button_new_with_label( group, "Black" );
|
||||
gtk_box_pack_start( GTK_BOX( framebox ), button, FALSE, FALSE, 0 );
|
||||
gtk_signal_connect( GTK_OBJECT( button ), "toggled",
|
||||
GTK_SIGNAL_FUNC( dialog_outside_type_callback ),
|
||||
&outside_type.black );
|
||||
gtk_widget_show( button );
|
||||
if( parameters.outside_type == OUTSIDE_TYPE_BLACK ){
|
||||
gtk_toggle_button_toggled( GTK_TOGGLE_BUTTON( button ) );
|
||||
gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( button ), TRUE );
|
||||
}
|
||||
group = gtk_radio_button_group( GTK_RADIO_BUTTON( button ) );
|
||||
|
||||
button = gtk_radio_button_new_with_label( group, "White" );
|
||||
gtk_box_pack_start( GTK_BOX( framebox ), button, FALSE, FALSE, 0 );
|
||||
gtk_signal_connect( GTK_OBJECT( button ), "toggled",
|
||||
GTK_SIGNAL_FUNC( dialog_outside_type_callback ),
|
||||
&outside_type.white );
|
||||
gtk_widget_show( button );
|
||||
if( parameters.outside_type == OUTSIDE_TYPE_WHITE ){
|
||||
gtk_toggle_button_toggled( GTK_TOGGLE_BUTTON( button ) );
|
||||
gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( button ), TRUE );
|
||||
}
|
||||
group = gtk_radio_button_group( GTK_RADIO_BUTTON( button ) );
|
||||
|
||||
}
|
||||
|
||||
gtk_widget_show( dialog );
|
||||
dialog_preview_draw();
|
||||
|
||||
gtk_main();
|
||||
|
||||
return dialog_status;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
Loading…
Reference in New Issue