/* * (c) Adam D. Moss : 1998-2000 : adam@gimp.org : adam@foxbox.org * * This is part of the GIMP package and is released under the GNU * Public License. */ /* * Version 1.06 : 2000-12-12 * * 1.06: * "Out of hyding" remix. Dr Jekyll is still suspiciously * absent from the fine bogey tale until Chapter Three. * * 1.05: * Sub-pixel jitter is now less severe and less coarse. * * 1.04: * Wigglyness and button-click fun. * * 1.03: * Fix for pseudocolor displays w/gdkrgb. * * 1.02: * Massive speedup if you have a very recent version of GTK 1.1. * Removed possible div-by-0 errors, took the plugin out * of hiding (guess we need a new easter-egg for GIMP 1.2!) */ #include "config.h" #include #include #include #include #include #include "libgimp/stdplugins-intl.h" /* Declare local functions. */ static void query (void); static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); static void do_fun (void); static void window_response_callback (GtkWidget *widget, gint response_id, gpointer data); static gboolean do_iteration (void); static gboolean toggle_feedbacktype (GtkWidget *widget, GdkEventButton *bevent); static void render_frame (void); static void init_preview_misc (void); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; static const guint width = 256; static const guint height = 256; static GRand *gr; #define LUTSIZE 512 #define LUTSIZEMASK ((LUTSIZE)-1) static gint wigglelut[LUTSIZE]; #define LOWAMP 2 #define HIGHAMP 11 static gint wiggleamp = LOWAMP; /* Global widgets'n'stuff */ static guchar *seed_data; static guchar *preview_data1; static guchar *preview_data2; static GtkWidget *drawing_area; static gint32 image_id; static GimpDrawable *drawable; static GimpImageBaseType imagetype; static guchar *palette; static gint ncolours; static guint idle_tag; static gboolean feedbacktype = FALSE; static gboolean wiggly = TRUE; static gboolean rgb_mode; MAIN () static void query (void) { static GimpParamDef args[] = { { GIMP_PDB_INT32, "run_mode", "Must be interactive (1)" }, { GIMP_PDB_IMAGE, "image", "Input Image" }, { GIMP_PDB_DRAWABLE, "drawable", "Input Drawable" } }; gimp_install_procedure ("plug_in_the_old_egg", "A big hello from the GIMP team!", "Hay-ulp", "Adam D. Moss ", "Adam D. Moss ", "1998", N_("Gee-_Zoom"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, G_N_ELEMENTS (args), 0, args, NULL); gimp_plugin_menu_register ("plug_in_the_old_egg", "/Filters/Toys"); } static void run (const gchar *name, gint n_params, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; gr = g_rand_new (); *nreturn_vals = 1; *return_vals = values; run_mode = param[0].data.d_int32; INIT_I18N (); if (run_mode == GIMP_RUN_NONINTERACTIVE || n_params != 3) { status = GIMP_PDB_CALLING_ERROR; } if (status == GIMP_PDB_SUCCESS) { image_id = param[1].data.d_image; drawable = gimp_drawable_get (param[2].data.d_drawable); if (drawable) do_fun(); else status = GIMP_PDB_CALLING_ERROR; } values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; g_rand_free (gr); } static void build_dialog (void) { GtkWidget *dlg; GtkWidget *button; GtkWidget *frame; gimp_ui_init ("gee_zoom", TRUE); dlg = gimp_dialog_new (_("GEE-ZOOM"), "gee_zoom", NULL, 0, gimp_standard_help_func, "plug-in-the-old-egg", NULL); button = gtk_dialog_add_button (GTK_DIALOG (dlg), _("Thank you for choosing GIMP"), GTK_RESPONSE_OK); g_signal_connect (dlg, "response", G_CALLBACK (window_response_callback), NULL); gimp_help_set_help_data (button, _("An obsolete creation of Adam D. Moss / " "adam@gimp.org / adam@foxbox.org / 1998-2000"), NULL); /* The 'fun' half of the dialog */ frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); gtk_container_set_border_width (GTK_CONTAINER (frame), 12); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); drawing_area = gtk_drawing_area_new (); gtk_widget_set_size_request (drawing_area, width, height); gtk_container_add (GTK_CONTAINER (frame), drawing_area); gtk_widget_show (drawing_area); gtk_widget_add_events (drawing_area, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); g_signal_connect (drawing_area, "button_release_event", G_CALLBACK (toggle_feedbacktype), NULL); gtk_widget_show (dlg); idle_tag = g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) do_iteration, NULL, NULL); } static void init_lut (void) { gint i; for (i=0; i>11)+grrr) & LUTSIZEMASK]; sy += wigglelut[(((basesx)>>11)+(grrr/3)) & LUTSIZEMASK]; } dx = 256; do { *dest++ = (*(src + ( ( ((255&( (sx>>11) ))) | ((((255&( (sy>>11) ))<<8))) ) ))); ; sx += by2; sy -= cy2; } while (--dx); } } /* 3bypp variant */ static void domap3(unsigned char *src, unsigned char *dest, int bx, int by, int cx, int cy) { unsigned int dy; signed int bycxmcybx; signed int bx2,by2; signed int cx2,cy2; unsigned int basesx; unsigned int basesy; static unsigned int grrr=0; grrr++; if ((cx+bx) == 0) cx++; if ((cy+by) == 0) by++; bycxmcybx = (by*cx-cy*bx); if (bycxmcybx == 0) bycxmcybx = 1; /* A little sub-pixel jitter to liven things up. */ basesx = ((g_rand_int_range (gr, 0, 29<<19)/bycxmcybx)) + ((-128-((128*256)/(cx+bx)))<<11); basesy = ((g_rand_int_range (gr, 0, 29<<19)/bycxmcybx)) + ((-128-((128*256)/(cy+by)))<<11); bx2 = ((bx)<<19)/bycxmcybx; cx2 = ((cx)<<19)/bycxmcybx; by2 = ((by)<<19)/bycxmcybx; cy2 = ((cy)<<19)/bycxmcybx; for (dy=0;dy<256;dy++) { unsigned int sx; unsigned int sy; unsigned int dx; sy = (basesy+=cx2); sx = (basesx-=bx2); if (wiggly) { sx += wigglelut[(((basesy)>>11)+grrr) & LUTSIZEMASK]; sy += wigglelut[(((basesx)>>11)+(grrr/3)) & LUTSIZEMASK]; } dx = 256; do { unsigned char* addr; addr = src + 3* ( ( ((255&( (sx>>11) ))) | ((((255&( (sy>>11) ))<<8))) ) ); *dest++ = *(addr); *dest++ = *(addr+1); *dest++ = *(addr+2); sx += by2; sy -= cy2; } while (--dx); } } static void render_frame (void) { int i; static int frame = 0; unsigned char* tmp; static gint xp=128, yp=128; gint rxp, ryp; GdkModifierType mask; gint pixels; if (! GTK_WIDGET_DRAWABLE (drawing_area)) return; pixels = width*height*(rgb_mode?3:1); tmp = preview_data2; preview_data2 = preview_data1; preview_data1 = tmp; if (frame==0) { for (i=0;iwindow, &rxp, &ryp, &mask); if ((abs(rxp)>60)||(abs(ryp)>60)) { xp = rxp; yp = ryp; } if (rgb_mode) { domap3(preview_data2, preview_data1, -(yp-xp)/2, xp+yp , xp+yp, (yp-xp)/2 ); gdk_draw_rgb_image (drawing_area->window, drawing_area->style->white_gc, 0, 0, width, height, GDK_RGB_DITHER_NORMAL, preview_data1, width * 3); /* memcpy(preview_data1, seed_data, 256*256*3); */ if (frame != 0) { if (feedbacktype) { for (i=0;i>10)) : t; /* Quick specialized clamp */ } } else/* if (0) */ { gint pixwords = pixels/sizeof(gint32); gint32* seedwords = (gint32*) seed_data; gint32* prevwords = (gint32*) preview_data1; for (i=0;i> 1) & 0x7f7f7f7f) + ((prevwords[i] >> 2) & 0x3f3f3f3f) + ((seedwords[i] >> 2) & 0x3f3f3f3f); /* This is from Raph L... it should be a fast 50%/50% blend, though I don't know if 50%/50% is as nice as the old ratio. */ /* prevwords[i] = ((prevwords[i] >> 1) & 0x7f7f7f7f) + ((seedwords[i] >> 1) & 0x7f7f7f7f) + (prevwords[i] & seedwords[i] & 0x01010101); */ } } } } else /* GRAYSCALE */ { domap1(preview_data2, preview_data1, -(yp-xp)/2, xp+yp , xp+yp, (yp-xp)/2 ); gdk_draw_gray_image (drawing_area->window, drawing_area->style->white_gc, 0, 0, width, height, GDK_RGB_DITHER_NORMAL, preview_data1, width); if (frame != 0) { if (feedbacktype) { for (i=0;i>10)) : t; /* Quick specialized clamp */ } } else { gint pixwords = pixels/sizeof(gint32); gint32* seedwords = (gint32*) seed_data; gint32* prevwords = (gint32*) preview_data1; for (i=0;i> 1) & 0x7f7f7f7f) + ((prevwords[i] >> 2) & 0x3f3f3f3f) + ((seedwords[i] >> 2) & 0x3f3f3f3f); /* This is from Raph L... it should be a fast 50%/50% blend, though I don't know if 50%/50% is as nice as the old ratio. */ /* prevwords[i] = ((prevwords[i] >> 1) & 0x7f7f7f7f) + ((seedwords[i] >> 1) & 0x7f7f7f7f) + (prevwords[i] & seedwords[i] & 0x01010101); */ } } } } frame++; } static void init_preview_misc (void) { GimpPixelRgn pixel_rgn; gint i; gboolean has_alpha; if ((imagetype == GIMP_RGB) || (imagetype == GIMP_INDEXED)) rgb_mode = TRUE; else rgb_mode = FALSE; has_alpha = gimp_drawable_has_alpha(drawable->drawable_id); seed_data = g_malloc(width*height*4); preview_data1 = g_malloc(width*height*(rgb_mode?3:1)); preview_data2 = g_malloc(width*height*(rgb_mode?3:1)); if ((drawable->width<256) || (drawable->height<256)) { for (i=0;i<256;i++) { if (i < drawable->height) { gimp_pixel_rgn_init (&pixel_rgn, drawable, drawable->width>256? (drawable->width/2-128):0, (drawable->height>256? (drawable->height/2-128):0)+i, MIN(256,drawable->width), 1, FALSE, FALSE); gimp_pixel_rgn_get_rect (&pixel_rgn, &seed_data[(256*i + ( ( drawable->width<256 ? (256-drawable->width)/2 : 0 ) + ( drawable->height<256 ? (256-drawable->height)/2 : 0 ) * 256 )) * gimp_drawable_bpp (drawable->drawable_id) ], drawable->width>256? (drawable->width/2-128):0, (drawable->height>256? (drawable->height/2-128):0)+i, MIN(256,drawable->width), 1); } } } else { gimp_pixel_rgn_init (&pixel_rgn, drawable, drawable->width>256?(drawable->width/2-128):0, drawable->height>256?(drawable->height/2-128):0, MIN(256,drawable->width), MIN(256,drawable->height), FALSE, FALSE); gimp_pixel_rgn_get_rect (&pixel_rgn, seed_data, drawable->width>256?(drawable->width/2-128):0, drawable->height>256?(drawable->height/2-128):0, MIN(256,drawable->width), MIN(256,drawable->height)); } gimp_drawable_detach(drawable); /* convert the image data of varying types into flat grey or rgb. */ switch (imagetype) { case GIMP_INDEXED: if (has_alpha) { for (i=width*height;i>0;i--) { seed_data[3*(i-1)+2] = ((palette[3*(seed_data[(i-1)*2])+2]*seed_data[(i-1)*2+1])/255) + ((255-seed_data[(i-1)*2+1]) * g_rand_int_range (gr, 0, 256))/255; seed_data[3*(i-1)+1] = ((palette[3*(seed_data[(i-1)*2])+1]*seed_data[(i-1)*2+1])/255) + ((255-seed_data[(i-1)*2+1]) * g_rand_int_range (gr, 0, 256))/255; seed_data[3*(i-1)+0] = ((palette[3*(seed_data[(i-1)*2])+0]*seed_data[(i-1)*2+1])/255) + ((255-seed_data[(i-1)*2+1]) * g_rand_int_range (gr, 0, 256))/255; } } else { for (i=width*height;i>0;i--) { seed_data[3*(i-1)+2] = palette[3*(seed_data[i-1])+2]; seed_data[3*(i-1)+1] = palette[3*(seed_data[i-1])+1]; seed_data[3*(i-1)+0] = palette[3*(seed_data[i-1])+0]; } } break; case GIMP_GRAY: if (has_alpha) { for (i=0;istate & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) { wiggleamp = bevent->x/5; wiggly = TRUE; init_lut(); return TRUE; } if (bevent->state & GDK_BUTTON1_MASK) feedbacktype = !feedbacktype; if (bevent->state & GDK_BUTTON2_MASK) wiggly = !wiggly; if (bevent->state & GDK_BUTTON3_MASK) { if (wiggleamp == LOWAMP) wiggleamp = HIGHAMP; else wiggleamp = LOWAMP; wiggly = TRUE; init_lut (); } return TRUE; }