2
* (c) Adam D. Moss : 1998-2000 : adam@gimp.org : adam@foxbox.org
8
* Version 1.01 : 2000-12-12
17
#include <libgimp/gimp.h>
18
#include <libgimp/gimpui.h>
20
#include "libgimp/stdplugins-intl.h"
23
/* Declare local functions. */
24
static void query (void);
25
static void run (const gchar *name,
27
const GimpParam *param,
29
GimpParam **return_vals);
31
static void do_fun (void);
33
static void window_response_callback (GtkWidget *widget,
36
static gboolean do_iteration (void);
38
static void render_frame (void);
39
static void init_preview_misc (void);
42
GimpPlugInInfo PLUG_IN_INFO =
46
query, /* query_proc */
51
/* These aren't really redefinable, easily. */
56
/* Global widgets'n'stuff */
57
static guchar *disp; /* RGBX preview data */
58
static guchar *env; /* src warping image data */
59
static guchar *bump1base;
61
static guchar *bump2base;
63
static guchar *srcbump;
64
static guchar *destbump;
66
static guint idle_tag;
67
static GtkWidget *drawing_area;
69
static gint32 image_id;
70
static GimpDrawable *drawable;
71
static GimpImageBaseType imagetype;
72
static guchar *palette;
81
static GimpParamDef args[] =
83
{ GIMP_PDB_INT32, "run_mode", "Must be interactive (1)" },
84
{ GIMP_PDB_IMAGE, "image", "Input Image" },
85
{ GIMP_PDB_DRAWABLE, "drawable", "Input Drawable" }
88
gimp_install_procedure ("plug_in_the_slimy_egg",
89
"A big hello from the GIMP team!",
91
"Adam D. Moss <adam@gimp.org>",
92
"Adam D. Moss <adam@gimp.org>",
95
"RGB*, INDEXED*, GRAY*",
97
G_N_ELEMENTS (args), 0,
100
gimp_plugin_menu_register ("plug_in_the_slimy_egg", "<Image>/Filters/Toys");
104
run (const gchar *name,
106
const GimpParam *param,
108
GimpParam **return_vals)
110
static GimpParam values[1];
111
GimpRunMode run_mode;
112
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
115
*return_vals = values;
117
run_mode = param[0].data.d_int32;
121
if (run_mode == GIMP_RUN_NONINTERACTIVE ||
124
status = GIMP_PDB_CALLING_ERROR;
127
if (status == GIMP_PDB_SUCCESS)
129
image_id = param[1].data.d_image;
130
drawable = gimp_drawable_get (param[2].data.d_drawable);
135
status = GIMP_PDB_CALLING_ERROR;
138
values[0].type = GIMP_PDB_STATUS;
139
values[0].data.d_status = status;
150
gimp_ui_init ("gee", TRUE);
152
dlg = gimp_dialog_new (_("GEE-SLIME"), "gee",
154
gimp_standard_help_func, "plug-in-the-slimy-egg",
157
button = gtk_dialog_add_button (GTK_DIALOG (dlg),
158
_("Thank you for choosing GIMP"),
161
g_signal_connect (dlg, "response",
162
G_CALLBACK (window_response_callback),
165
gimp_help_set_help_data (button,
166
_("A less-obsolete creation of Adam D. Moss / "
167
"adam@gimp.org / adam@foxbox.org / 1998-2000"),
170
frame = gtk_frame_new (NULL);
171
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
172
gtk_container_set_border_width (GTK_CONTAINER (frame), 12);
173
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
174
frame, FALSE, FALSE, 0);
175
gtk_widget_show (frame);
177
drawing_area = gtk_drawing_area_new ();
178
gtk_widget_set_size_request (drawing_area, IWIDTH, IHEIGHT);
179
gtk_container_add (GTK_CONTAINER (frame), drawing_area);
180
gtk_widget_show (drawing_area);
182
gtk_widget_show (dlg);
184
idle_tag = g_idle_add_full (G_PRIORITY_LOW,
185
(GSourceFunc) do_iteration,
191
/* #define LIGHT 0x19
193
#define LIGHT 0x21 */
195
static guchar llut[256];
202
for (i=0; i<256; i++)
204
/* k = i + RINT (((double)LIGHT) * pow(((double)i / 255.0), 0.5));
205
k = i + ((LIGHT*i)/255); */
206
k = i + ((LIGHT*( /* (255*255)- */ i*i))/(255*255));
208
k = i + ((LIGHT*( /* (255*255*255)- */ i*i*i))/(255*255*255));
211
k = (k>255 ? 255 : k);
220
imagetype = gimp_image_base_type(image_id);
222
if (imagetype == GIMP_INDEXED)
223
palette = gimp_image_get_colormap (image_id, &ncolours);
225
if (imagetype == GIMP_GRAY)
228
palette = g_malloc(256 * 3);
229
for (i=0; i<256; i++)
238
gimp_tile_cache_ntiles (1);
254
if (GTK_WIDGET_DRAWABLE (drawing_area))
255
gdk_draw_rgb_32_image (drawing_area->window,
256
drawing_area->style->white_gc,
257
0, 0, IWIDTH, IHEIGHT,
258
GDK_RGB_DITHER_NORMAL,
259
(guchar *) disp, IWIDTH * 4);
263
/* Rendering Functions */
267
bumpbob (int x, int y, int size)
271
/* for (o=0; o<size; o++)
273
bump[x+(size/2)+(y+o)*IWIDTH] = 255;
275
memset(&bump[x+(y+(size/2))*IWIDTH], 255, size);
278
for (o=0; o<size; o++)
281
for (p=0; p<size; p++)
285
k = destbump[p+x+(y+o)*IWIDTH] + BOB_INC;
287
destbump[p+x+(y+o)*IWIDTH] = 255;
289
destbump[p+x+(y+o)*IWIDTH] = k;
291
/* memset(&destbump[x+(y+o)*IWIDTH], 131, size); */
296
/* Adam's sillier algorithm. */
300
static guint frame = 0;
305
guint32 *environment;
310
/* signed int bycxmcybx;
313
const gint bx = -(123-128);
314
const gint by = (128+123);
316
const gint cy = -bx;*/
317
#define bx (-(123-128))
321
#define bycxmcybx (by*cx-cy*bx)
322
#define bx2 (((bx)<<19)/bycxmcybx)
323
#define by2 (((by)<<19)/bycxmcybx)
324
#define cx2 (((cx)<<19)/bycxmcybx)
325
#define cy2 (((cy)<<19)/bycxmcybx)
330
environment = (guint32*) env;
331
dest = (guint32*) disp;
332
srcbump = (frame&1) ? bump1 : bump2;
333
destbump = (frame&1) ? bump2 : bump1;
335
/* WARP DISTORTION MAP (plughole-effect) */
337
/* this setup obsolete, tranformation is constant */
344
bycxmcybx = (by*cx-cy*bx);
349
bx2 = ((bx)<<19)/bycxmcybx;
350
cx2 = ((cx)<<19)/bycxmcybx;
351
by2 = ((by)<<19)/bycxmcybx;
352
cy2 = ((cy)<<19)/bycxmcybx;
355
/* A little sub-pixel jitter to liven things up. */
356
basesx = (g_rand_int_range (gr, 0, 29<<19)/bycxmcybx) +
357
((-128-((128*256)/(cx+bx)))<<11);
358
basesy = (g_rand_int_range (gr, 0, 29<<19)/bycxmcybx) + ((-128-((128*256)/(cy+by)))<<11);
371
*dest++ = *environment++;
378
/* MELT DISTORTION MAP, APPLY IT */
391
unsigned char *bptr =
404
thisbump = (11 * *(basebump) + (
417
/* TODO: Can accelerate search for non-zero bumps with
418
casting an aligned long-word search. */
421
*(dest++) = *( environment + (i | (j<<8) ) );
422
/* *(dest++) = 111; */
427
if (thisbump <= (131<<4) )
430
*destbump = thisbump;
433
*destbump = thisbump = 131;
435
/* sy = j + ( ((thisbump) - *(destbump+IWIDTH))<<1);
436
sx = i + ( ((thisbump) - *(++destbump))<<1); + blah; */
437
sy = j + ( ((thisbump) - *(destbump+IWIDTH)));
438
sx = i + ( ((thisbump) - *(++destbump)));
439
*dest++ = *( environment + (sx | (sy<<8) ) );
440
/* sx = ( ((thisbump) - *(destbump+IWIDTH)));
441
sy = ( ((thisbump) - *(++destbump)));
442
*dest++ = (sx) | (sy<<8) | (sx<<16); */
448
srcbump = (frame&1) ? bump1 : bump2;
449
destbump = (frame&1) ? bump2 : bump1;
450
dest = (guint32 *) disp;
451
memset(destbump, 0, IWIDTH);
455
/* The idea here is that we refract IWIDTH*IHEIGHT parallel rays
456
through the surface of the slime and illuminate the points
457
where they hit the backing-image. There are some unrealistic
458
shortcuts taken, but the result is quite pleasing.
472
sy = j + ( ((sx) - *(destbump+IWIDTH-1)));
473
sx = i + ( ((sx) - *(destbump)));
475
/* cptr = (guchar*)((guint32*)(( dest+ (0xffff^(sx | (sy<<8) )) ))); */
476
cptr = (guchar*)( dest + (0xffff^(sx | (sy<<8) )) );
478
*cptr = llut[*cptr]; cptr++;
479
*cptr = llut[*cptr]; cptr++;
481
/* this second point of light's offset (1 across, 1 down)
482
isn't really 'right' but it gives a more pleasing,
486
*cptr = llut[*cptr]; cptr++;
487
*cptr = llut[*cptr]; cptr++;
495
/* Interactive bumpmap */
498
#define BOBS_PER_FRAME 70
499
destbump = (frame&1) ? bump2 : bump1;
501
gint rxp, ryp, posx, posy;
502
GdkModifierType mask;
505
gdk_window_get_pointer (drawing_area->window, &rxp, &ryp, &mask);
507
for (i = 0; i < BOBS_PER_FRAME; i++)
509
size = g_rand_int_range (gr, 1, BOBSIZE);
511
posx = rxp + BOBSPREAD/2 -
512
RINT(sqrt(g_rand_double_range (gr, 0, BOBSPREAD)) *
513
g_rand_int_range (gr, 0, BOBSPREAD));
514
posy = ryp + BOBSPREAD/2 -
515
RINT(sqrt(g_rand_double_range (gr, 0, BOBSPREAD)) *
516
g_rand_int_range (gr, 0, BOBSPREAD));
518
if (! ((posx>IWIDTH-size) ||
519
(posy>IHEIGHT-size) ||
522
bumpbob(posx, posy, size);
531
static int frame = 0;
538
bytes = IWIDTH*IHEIGHT*4;
540
for (i=0;i<bytes;i++)
555
init_preview_misc (void)
557
GimpPixelRgn pixel_rgn;
561
has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
563
env = g_malloc (4 * IWIDTH * IHEIGHT * 2);
564
disp = g_malloc ((IWIDTH + 2 + IWIDTH * IHEIGHT) * 4);
565
bump1base = g_malloc (IWIDTH * IHEIGHT + IWIDTH+IWIDTH);
566
bump2base = g_malloc (IWIDTH * IHEIGHT + IWIDTH+IWIDTH);
568
bump1 = &bump1base[IWIDTH];
569
bump2 = &bump2base[IWIDTH];
571
if ((drawable->width<256) || (drawable->height<256))
575
if (i < drawable->height)
577
gimp_pixel_rgn_init (&pixel_rgn,
580
(drawable->width/2-128):0,
581
(drawable->height>256?
582
(drawable->height/2-128):0)+i,
583
MIN(256,drawable->width),
587
gimp_pixel_rgn_get_rect (&pixel_rgn,
591
drawable->width<256 ?
592
(256-drawable->width)/2 :
597
drawable->height<256 ?
598
(256-drawable->height)/2 :
603
(drawable->drawable_id)
606
(drawable->width/2-128):0,
607
(drawable->height>256?
608
(drawable->height/2-128):0)+i,
609
MIN(256,drawable->width),
616
gimp_pixel_rgn_init (&pixel_rgn,
618
drawable->width>256?(drawable->width/2-128):0,
619
drawable->height>256?(drawable->height/2-128):0,
620
MIN(256,drawable->width),
621
MIN(256,drawable->height),
624
gimp_pixel_rgn_get_rect (&pixel_rgn,
626
drawable->width>256?(drawable->width/2-128):0,
627
drawable->height>256?(drawable->height/2-128):0,
628
MIN(256,drawable->width),
629
MIN(256,drawable->height));
632
gimp_drawable_detach(drawable);
635
/* convert the image data of varying types into flat grey or rgb. */
642
for (i=IWIDTH*IHEIGHT;i>0;i--)
645
((palette[3*(env[(i-1)*2])+2]*env[(i-1)*2+1])/255)
646
+ ((255-env[(i-1)*2+1])*((i&255) ^ (i>>8)))/255;
648
((palette[3*(env[(i-1)*2])+1]*env[(i-1)*2+1])/255)
649
+ ((255-env[(i-1)*2+1])*((i&255) ^ (i>>8)))/255;
651
((palette[3*(env[(i-1)*2])+0]*env[(i-1)*2+1])/255)
652
+ ((255-env[(i-1)*2+1])*((i&255) ^ (i>>8)))/255;
657
for (i=IWIDTH*IHEIGHT;i>0;i--)
659
env[4*(i-1)+2] = palette[3*(env[i-1])+2];
660
env[4*(i-1)+1] = palette[3*(env[i-1])+1];
661
env[4*(i-1)+0] = palette[3*(env[i-1])+0];
669
for (i=0;i<IWIDTH*IHEIGHT;i++)
672
(env[i*4+2]*env[i*4+3])/255
673
+ ((255-env[i*4+3])*((i&255) ^ (i>>8)))/255;
675
(env[i*4+1]*env[i*4+3])/255
676
+ ((255-env[i*4+3])*((i&255) ^ (i>>8)))/255;
678
(env[i*4+0]*env[i*4+3])/255
679
+ ((255-env[i*4+3])*((i&255) ^ (i>>8)))/255;
684
for (i=IWIDTH*IHEIGHT;i>0;i--)
686
env[4*(i-1)+2] = env[(i-1)*3+2];
687
env[4*(i-1)+1] = env[(i-1)*3+1];
688
env[4*(i-1)+0] = env[(i-1)*3+0];
697
/* Finally, 180-degree flip the environmental image! */
698
for (i = 0; i < IWIDTH*IHEIGHT/2; i++)
702
env[4*(i)+0] = env[4*(IWIDTH*IHEIGHT-(i+1))+0];
703
env[4*(IWIDTH*IHEIGHT-(i+1))+0] = t;
705
env[4*(i)+1] = env[4*(IWIDTH*IHEIGHT-(i+1))+1];
706
env[4*(IWIDTH*IHEIGHT-(i+1))+1] = t;
708
env[4*(i)+2] = env[4*(IWIDTH*IHEIGHT-(i+1))+2];
709
env[4*(IWIDTH*IHEIGHT-(i+1))+2] = t;
723
window_response_callback (GtkWidget *widget,
727
g_source_remove (idle_tag);
730
gtk_widget_destroy (widget);