home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / gee_zoom.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-20  |  20.1 KB  |  906 lines

  1. /*
  2.  * (c) Adam D. Moss : 1998-2000 : adam@gimp.org : adam@foxbox.org
  3.  *
  4.  * This is part of the GIMP package and is released under the GNU
  5.  * Public License.
  6.  */
  7.  
  8. /*
  9.  * Version 1.06 : 2000-12-12
  10.  *
  11.  * 1.06:
  12.  * "Out of hyding" remix.  Dr Jekyll is still suspiciously
  13.  * absent from the fine bogey tale until Chapter Three.
  14.  *
  15.  * 1.05:
  16.  * Sub-pixel jitter is now less severe and less coarse.
  17.  *
  18.  * 1.04:
  19.  * Wigglyness and button-click fun.
  20.  *
  21.  * 1.03:
  22.  * Fix for pseudocolor displays w/gdkrgb.
  23.  *
  24.  * 1.02:
  25.  * Massive speedup if you have a very recent version of GTK 1.1.
  26.  * Removed possible div-by-0 errors, took the plugin out
  27.  * of hiding (guess we need a new easter-egg for GIMP 1.2!)
  28.  */
  29. #include "config.h"
  30.  
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35. #include <time.h>
  36.  
  37. #include <gtk/gtk.h>
  38.  
  39. #include <libgimp/gimp.h>
  40. #include <libgimp/gimpui.h>
  41.  
  42. #include "libgimp/stdplugins-intl.h"
  43.  
  44.  
  45. /* Test for GTK1.2-style gdkrgb code, else use old 'preview' code. */
  46. #ifdef __GDK_RGB_H__
  47. #define RAPH_IS_HOME yep
  48. #endif
  49.  
  50.  
  51.  
  52. /* Declare local functions. */
  53. static void query (void);
  54. static void run   (gchar      *name,
  55.            gint        nparams,
  56.            GimpParam  *param,
  57.            gint       *nreturn_vals,
  58.            GimpParam **return_vals);
  59.  
  60. static void do_fun            (void);
  61.  
  62. static gint window_delete_callback (GtkWidget *widget,
  63.                     GdkEvent  *event,
  64.                     gpointer   data);
  65. static void window_close_callback  (GtkWidget *widget,
  66.                     gpointer   data);
  67. static gint iteration_callback          (gpointer   data);
  68. static void toggle_feedbacktype    (GtkWidget *widget,
  69.                     gpointer   data);
  70.  
  71. static void render_frame           (void);
  72. static void show_frame             (void);
  73. static void init_preview_misc      (void);
  74.  
  75.  
  76. GimpPlugInInfo PLUG_IN_INFO =
  77. {
  78.   NULL,  /* init_proc  */
  79.   NULL,  /* quit_proc  */
  80.   query, /* query_proc */
  81.   run,   /* run_proc   */
  82. };
  83.  
  84.  
  85. static const guint  width = 256;
  86. static const guint height = 256;
  87.  
  88.  
  89. #define LUTSIZE 512
  90. #define LUTSIZEMASK ((LUTSIZE)-1)
  91. static gint wigglelut[LUTSIZE];
  92.  
  93. #define LOWAMP 2
  94. #define HIGHAMP 11
  95. static gint wiggleamp = LOWAMP;
  96.  
  97.  
  98. /* Global widgets'n'stuff */
  99. static guchar     *seed_data;
  100. static guchar     *preview_data1;
  101. static guchar     *preview_data2;
  102. #ifdef RAPH_IS_HOME
  103. static GtkWidget  *drawing_area;
  104. #else
  105. static GtkPreview *preview = NULL;
  106. #endif
  107. static gint32      image_id;
  108. static GimpDrawable      *drawable;
  109. static GimpImageBaseType  imagetype;
  110. static guchar     *palette;
  111. static gint        ncolours;
  112.  
  113. static gint       idle_tag;
  114. static GtkWidget *eventbox;
  115. static gboolean   feedbacktype = FALSE;
  116. static gboolean   wiggly = TRUE;
  117. static gboolean   rgb_mode;
  118.  
  119.  
  120. MAIN ()
  121.  
  122. static void
  123. query (void)
  124. {
  125.   static GimpParamDef args[] =
  126.   {
  127.     { GIMP_PDB_INT32, "run_mode", "Must be interactive (1)" },
  128.     { GIMP_PDB_IMAGE, "image", "Input Image" },
  129.     { GIMP_PDB_DRAWABLE, "drawable", "Input Drawable" },
  130.   };
  131.   static gint nargs = sizeof (args) / sizeof (args[0]);
  132.  
  133.   gimp_install_procedure("plug_in_the_old_egg",
  134.              "A big hello from the GIMP team!",
  135.              "Hay-ulp",
  136.              "Adam D. Moss <adam@gimp.org>",
  137.              "Adam D. Moss <adam@gimp.org>",
  138.              "1998",
  139.              N_("<Image>/Filters/Toys/Gee-Zoom"),
  140.              "RGB*, INDEXED*, GRAY*",
  141.              GIMP_PLUGIN,
  142.              nargs, 0,
  143.              args, NULL);
  144. }
  145.  
  146. static void
  147. run (gchar      *name,
  148.      gint        n_params,
  149.      GimpParam  *param, 
  150.      gint       *nreturn_vals,
  151.      GimpParam **return_vals)
  152. {
  153.   static GimpParam  values[1];
  154.   GimpRunModeType   run_mode;
  155.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  156.  
  157.   *nreturn_vals = 1;
  158.   *return_vals = values;
  159.  
  160.   run_mode = param[0].data.d_int32;
  161.  
  162.   INIT_I18N_UI();
  163.  
  164.   if (run_mode == GIMP_RUN_NONINTERACTIVE ||
  165.       n_params != 3)
  166.     {
  167.       status = GIMP_PDB_CALLING_ERROR;
  168.     }
  169.   
  170.   if (status == GIMP_PDB_SUCCESS)
  171.     {
  172.       image_id = param[1].data.d_image;
  173.       drawable = gimp_drawable_get (param[2].data.d_drawable);
  174.  
  175.       if (drawable)
  176.     do_fun();
  177.       else
  178.     status = GIMP_PDB_CALLING_ERROR;
  179.     }
  180.  
  181.   values[0].type = GIMP_PDB_STATUS;
  182.   values[0].data.d_status = status;
  183. }
  184.  
  185.  
  186. static void
  187. build_dialog (GimpImageBaseType  basetype,
  188.           gchar             *imagename)
  189. {
  190.   GtkWidget *dlg;
  191.   GtkWidget *button;
  192.   GtkWidget *frame;
  193.   GtkWidget *frame2;
  194.   GtkWidget *vbox;
  195.   GtkWidget *hbox;
  196.   GtkWidget *hbox2;
  197.   GtkTooltips *tooltips;
  198.  
  199.   gimp_ui_init ("gee_zoom", TRUE);
  200.  
  201.   dlg = gtk_dialog_new ();
  202.   gtk_window_set_title (GTK_WINDOW (dlg),
  203.             _("GEE-ZOOM: The Plug-In Formerly Known As \"The GIMP E'er Egg\""));
  204.  
  205.   gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
  206.   gtk_signal_connect (GTK_OBJECT (dlg), "delete_event",
  207.               (GtkSignalFunc) window_delete_callback,
  208.               NULL);
  209.  
  210.   gimp_help_connect_help_accel (dlg, gimp_standard_help_func, "filters/gee.html");
  211.  
  212.   /* Action area - 'close' button only. */
  213.  
  214.   button = gtk_button_new_with_label (_("** Thank you for choosing GIMP **"));
  215.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  216.   gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
  217.                  (GtkSignalFunc) window_close_callback,
  218.                  GTK_OBJECT (dlg));
  219.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area),
  220.               button, TRUE, TRUE, 0);
  221.   gtk_widget_grab_default (button);
  222.   gtk_widget_show (button);
  223.  
  224.   tooltips = gtk_tooltips_new();
  225.   gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), button,
  226.                _("An obsolete creation of Adam D. Moss / adam@gimp.org / adam@foxbox.org / 1998-2000"),
  227.                NULL);
  228.   gtk_tooltips_enable (tooltips);
  229.  
  230.   /* The 'fun' half of the dialog */
  231.     
  232.   frame = gtk_frame_new (NULL);
  233.  
  234.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  235.   gtk_container_set_border_width (GTK_CONTAINER (frame), 3);
  236.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0);
  237.  
  238.   hbox = gtk_hbox_new (FALSE, 5);
  239.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
  240.   gtk_container_add (GTK_CONTAINER (frame), hbox);
  241.  
  242.   vbox = gtk_vbox_new (FALSE, 5);
  243.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
  244.   gtk_container_add (GTK_CONTAINER (hbox), vbox);
  245.  
  246.   hbox2 = gtk_hbox_new (TRUE, 0);
  247.   gtk_container_set_border_width (GTK_CONTAINER (hbox2), 0);
  248.   gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0);
  249.  
  250.   frame2 = gtk_frame_new (NULL);
  251.   gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_ETCHED_IN);
  252.   gtk_box_pack_start (GTK_BOX (hbox2), frame2, FALSE, FALSE, 0);
  253.  
  254.   eventbox = gtk_event_box_new();
  255.   gtk_container_add (GTK_CONTAINER (frame2), GTK_WIDGET (eventbox));
  256.  
  257. #ifdef RAPH_IS_HOME
  258.   drawing_area = gtk_drawing_area_new ();
  259.   gtk_widget_set_usize (drawing_area, width, height);
  260.   gtk_container_add (GTK_CONTAINER (eventbox), drawing_area);
  261.   gtk_widget_show (drawing_area);
  262. #else
  263.   preview = GTK_PREVIEW (gtk_preview_new (rgb_mode ?
  264.                       GTK_PREVIEW_COLOR :
  265.                       GTK_PREVIEW_GRAYSCALE));
  266.   gtk_preview_size (preview, width, height);
  267.   gtk_container_add (GTK_CONTAINER (eventbox), GTK_WIDGET (preview));
  268.   gtk_widget_show (GTK_WIDGET (preview));
  269. #endif /* RAPH_IS_HOME */
  270.  
  271.   gtk_widget_show (eventbox);
  272.   gtk_widget_set_events (eventbox,
  273.              gtk_widget_get_events (eventbox)
  274.              | GDK_BUTTON_RELEASE_MASK);
  275.  
  276.   gtk_widget_show (frame2);
  277.  
  278.   gtk_widget_show (hbox2);
  279.  
  280.   gtk_widget_show (vbox);
  281.  
  282.   gtk_widget_show (hbox);
  283.  
  284.   gtk_widget_show (frame);
  285.  
  286.   gtk_widget_show (dlg);
  287.         
  288.   idle_tag = gtk_idle_add_priority (GTK_PRIORITY_LOW,
  289.                     (GtkFunction) iteration_callback,
  290.                     NULL);
  291.   
  292.   gtk_signal_connect (GTK_OBJECT (eventbox), "button_release_event",
  293.               GTK_SIGNAL_FUNC (toggle_feedbacktype),
  294.               NULL);
  295. }
  296.  
  297.  
  298. static void 
  299. init_lut (void)
  300. {
  301.   gint i;
  302.  
  303.   for (i=0; i<LUTSIZE; i++)
  304.     {
  305.       wigglelut[i] = RINT((double)(wiggleamp<<11))*(sin((double)(i) /
  306.                         ((double)LUTSIZEMASK /
  307.                          10 * G_PI)));
  308.     }
  309. }
  310.  
  311.  
  312. static void 
  313. do_fun (void)
  314. {
  315.   imagetype = gimp_image_base_type(image_id);
  316.  
  317.   if (imagetype == GIMP_INDEXED)
  318.     palette = gimp_image_get_cmap(image_id, &ncolours);
  319.  
  320.   /* cache hint */
  321.   gimp_tile_cache_ntiles (1);
  322.  
  323.   init_preview_misc();
  324.   build_dialog(gimp_image_base_type(image_id),
  325.                gimp_image_get_filename(image_id));
  326.  
  327.   init_lut();
  328.   
  329.   render_frame();
  330.   show_frame();
  331.  
  332.   gtk_main ();
  333.   gdk_flush ();
  334. }
  335.  
  336.  
  337. /* Rendering Functions */
  338.  
  339. /* Adam's silly algorithm. */
  340. static void 
  341. domap1 (unsigned char *src, unsigned char *dest,
  342.     int bx, int by, int cx, int cy)
  343. {
  344.   unsigned int dy;
  345.   signed int bycxmcybx;
  346.   signed int bx2,by2;
  347.   signed int cx2,cy2;
  348.   unsigned int basesx;
  349.   unsigned int basesy;
  350.  
  351.   static unsigned int grrr=0;
  352.  
  353.   grrr++;
  354.  
  355.   if ((cx+bx) == 0)
  356.     cx++;
  357.  
  358.   if ((cy+by) == 0)
  359.     by++;
  360.  
  361.   bycxmcybx = (by*cx-cy*bx);
  362.  
  363.   if (bycxmcybx == 0)
  364.     bycxmcybx = 1;
  365.  
  366.   /* A little sub-pixel jitter to liven things up. */
  367.   basesx = (((RAND_FUNC ()%(29<<19))/bycxmcybx)) + ((-128-((128*256)/(cx+bx)))<<11);
  368.   basesy = (((RAND_FUNC ()%(29<<19))/bycxmcybx)) + ((-128-((128*256)/(cy+by)))<<11);
  369.  
  370.   bx2 = ((bx)<<19)/bycxmcybx;
  371.   cx2 = ((cx)<<19)/bycxmcybx;
  372.   by2 = ((by)<<19)/bycxmcybx;
  373.   cy2 = ((cy)<<19)/bycxmcybx;
  374.  
  375.   for (dy=0;dy<256;dy++)
  376.     {
  377.       unsigned int sx;
  378.       unsigned int sy;
  379.       unsigned int dx;
  380.  
  381.       sy = (basesy+=cx2);
  382.       sx = (basesx-=bx2);
  383.  
  384.       if (wiggly)
  385.     {
  386.       sx += wigglelut[(((basesy)>>11)+grrr) & LUTSIZEMASK];
  387.       sy += wigglelut[(((basesx)>>11)+(grrr/3)) & LUTSIZEMASK];
  388.     }
  389.  
  390.       dx = 256;
  391.       do
  392.     {
  393.       *dest++ = (*(src +
  394.            (
  395.             (
  396.              ((255&(
  397.                 (sx>>11)
  398.                 )))
  399.              |
  400.              ((((255&(
  401.                   (sy>>11)
  402.                   ))<<8)))
  403.              )
  404.             )));
  405.       ;
  406.       sx += by2;
  407.       sy -= cy2;
  408.     }
  409.       while (--dx);
  410.     }
  411. }
  412.  
  413. /* 3bypp variant */
  414. static void 
  415. domap3(unsigned char *src, unsigned char *dest,
  416.        int bx, int by, int cx, int cy)
  417. {
  418.   unsigned int dy;
  419.   signed int bycxmcybx;
  420.   signed int bx2,by2;
  421.   signed int cx2,cy2;
  422.   unsigned int basesx;
  423.   unsigned int basesy;
  424.  
  425.   static unsigned int grrr=0;
  426.  
  427.   grrr++;
  428.  
  429.   if ((cx+bx) == 0)
  430.     cx++;
  431.  
  432.   if ((cy+by) == 0)
  433.     by++;
  434.  
  435.   bycxmcybx = (by*cx-cy*bx);
  436.  
  437.   if (bycxmcybx == 0)
  438.     bycxmcybx = 1;
  439.  
  440.   /* A little sub-pixel jitter to liven things up. */
  441.   basesx = (((RAND_FUNC ()%(29<<19))/bycxmcybx)) + ((-128-((128*256)/(cx+bx)))<<11);
  442.   basesy = (((RAND_FUNC ()%(29<<19))/bycxmcybx)) + ((-128-((128*256)/(cy+by)))<<11);
  443.  
  444.   bx2 = ((bx)<<19)/bycxmcybx;
  445.   cx2 = ((cx)<<19)/bycxmcybx;
  446.   by2 = ((by)<<19)/bycxmcybx;
  447.   cy2 = ((cy)<<19)/bycxmcybx;
  448.  
  449.   for (dy=0;dy<256;dy++)
  450.     {
  451.       unsigned int sx;
  452.       unsigned int sy;
  453.       unsigned int dx; 
  454.       
  455.       sy = (basesy+=cx2);
  456.       sx = (basesx-=bx2);
  457.  
  458.       if (wiggly)
  459.     {
  460.       sx += wigglelut[(((basesy)>>11)+grrr) & LUTSIZEMASK];
  461.       sy += wigglelut[(((basesx)>>11)+(grrr/3)) & LUTSIZEMASK];
  462.     }
  463.       
  464.       dx = 256;
  465.       
  466.       do
  467.     {
  468.       unsigned char* addr;
  469.       
  470.       addr = src + 3*
  471.         (
  472.          (
  473.           ((255&(
  474.              (sx>>11)
  475.              )))
  476.           |
  477.           ((((255&(
  478.                (sy>>11)
  479.                ))<<8)))
  480.           )
  481.          );
  482.       
  483.       *dest++ = *(addr);
  484.       *dest++ = *(addr+1);
  485.       *dest++ = *(addr+2);
  486.       
  487.       sx += by2;
  488.       sy -= cy2;
  489.     }
  490.       while (--dx);
  491.     }
  492. }
  493.  
  494.  
  495. static void
  496. render_frame (void)
  497. {
  498.   int i;
  499.   static int frame = 0;
  500.   unsigned char* tmp;
  501.   static gint xp=128, yp=128;
  502.   gint rxp, ryp;
  503.   GdkModifierType mask;
  504.   gint pixels;
  505.  
  506.   pixels = width*height*(rgb_mode?3:1);
  507.  
  508. #ifdef RAPH_IS_HOME
  509. #else
  510.   gdk_flush();
  511. #endif
  512.  
  513.   tmp = preview_data2;
  514.   preview_data2 = preview_data1;
  515.   preview_data1 = tmp;
  516.  
  517.   if (frame==0)
  518.     {
  519.       for (i=0;i<pixels;i++)
  520.     {
  521.       preview_data2[i] =
  522.         preview_data1[i] =
  523.         seed_data[i];
  524.     }
  525.     }
  526.  
  527.   gdk_window_get_pointer (eventbox->window, &rxp, &ryp, &mask);
  528.  
  529.   if ((abs(rxp)>60)||(abs(ryp)>60))
  530.     {
  531.       xp = rxp;
  532.       yp = ryp;
  533.     }
  534.  
  535.   if (rgb_mode)
  536.     {
  537.       domap3(preview_data2, preview_data1,
  538.          -(yp-xp)/2, xp+yp
  539.          ,
  540.          xp+yp, (yp-xp)/2
  541.          );
  542.  
  543. #ifdef RAPH_IS_HOME
  544.       gdk_draw_rgb_image (drawing_area->window,
  545.               drawing_area->style->white_gc,
  546.               0, 0, width, height,
  547.               GDK_RGB_DITHER_NORMAL,
  548.               preview_data1, width * 3);
  549. #else
  550.       for (i=0;i<height;i++)
  551.     {
  552.       gtk_preview_draw_row (preview,
  553.                 &preview_data1[i*width*3],
  554.                 0, i, width);
  555.     }
  556. #endif
  557.  
  558.       /*      memcpy(preview_data1, seed_data, 256*256*3); */
  559.  
  560.       if (frame != 0)
  561.     {
  562.       if (feedbacktype)
  563.         {
  564.           for (i=0;i<pixels;i++)
  565.         {
  566.           gint t;
  567.           t = preview_data1[i] + seed_data[i] - 128;
  568.           preview_data1[i] = /*CLAMP(t,0,255);*/
  569.             (t&256)? (~(t>>10)) : t; /* Quick specialized clamp */
  570.         }
  571.         }
  572.       else/* if (0) */
  573.         {
  574.           gint pixwords = pixels/sizeof(gint32);
  575.           gint32* seedwords = (gint32*) seed_data;
  576.           gint32* prevwords = (gint32*) preview_data1;
  577.  
  578.           for (i=0;i<pixwords;i++)
  579.         {
  580.           /*preview_data1[i] = (preview_data1[i]*2 +
  581.             seed_data[i]) /3;*/
  582.  
  583.           /* mod'd version of the below for a 'deeper' mix */
  584.           prevwords[i] =
  585.             ((prevwords[i] >> 1) & 0x7f7f7f7f) +
  586.             ((prevwords[i] >> 2) & 0x3f3f3f3f) +
  587.             ((seedwords[i] >> 2) & 0x3f3f3f3f);
  588.           /* This is from Raph L... it should be a fast 50%/50%
  589.              blend, though I don't know if 50%/50% is as nice as
  590.              the old ratio. */
  591.           /*
  592.             prevwords[i] =
  593.             ((prevwords[i] >> 1) & 0x7f7f7f7f) +
  594.             ((seedwords[i] >> 1) & 0x7f7f7f7f) +
  595.             (prevwords[i] & seedwords[i] & 0x01010101); */
  596.         }
  597.         }    
  598.     }
  599.     }
  600.   else /* GRAYSCALE */
  601.     {
  602.       domap1(preview_data2, preview_data1,
  603.          -(yp-xp)/2, xp+yp
  604.          ,
  605.          xp+yp, (yp-xp)/2
  606.          );
  607.  
  608. #ifdef RAPH_IS_HOME
  609.       gdk_draw_gray_image (drawing_area->window,
  610.                drawing_area->style->white_gc,
  611.                0, 0, width, height,
  612.                GDK_RGB_DITHER_NORMAL,
  613.                preview_data1, width);
  614. #else
  615.       for (i=0;i<height;i++)
  616.     {
  617.       gtk_preview_draw_row (preview,
  618.                 &preview_data1[i*width],
  619.                 0, i, width);
  620.     }
  621. #endif
  622.  
  623.       if (frame != 0)
  624.     {
  625.       if (feedbacktype)
  626.         {
  627.           for (i=0;i<pixels;i++)
  628.         {
  629.           int t;
  630.           t = preview_data1[i] + seed_data[i] - 128;
  631.           preview_data1[i] = /*CLAMP(t,0,255);*/
  632.             (t&256)? (~(t>>10)) : t; /* Quick specialized clamp */
  633.         }
  634.         }
  635.       else
  636.         {
  637.           gint pixwords = pixels/sizeof(gint32);
  638.           gint32* seedwords = (gint32*) seed_data;
  639.           gint32* prevwords = (gint32*) preview_data1;
  640.  
  641.           for (i=0;i<pixwords;i++)
  642.         {
  643.  
  644.           /* mod'd version of the below for a 'deeper' mix */
  645.           prevwords[i] =
  646.             ((prevwords[i] >> 1) & 0x7f7f7f7f) +
  647.             ((prevwords[i] >> 2) & 0x3f3f3f3f) +
  648.             ((seedwords[i] >> 2) & 0x3f3f3f3f);
  649.           /* This is from Raph L... it should be a fast 50%/50%
  650.              blend, though I don't know if 50%/50% is as nice as
  651.              the old ratio. */
  652.           /*
  653.             prevwords[i] =
  654.             ((prevwords[i] >> 1) & 0x7f7f7f7f) +
  655.             ((seedwords[i] >> 1) & 0x7f7f7f7f) +
  656.             (prevwords[i] & seedwords[i] & 0x01010101); */
  657.         }
  658.         }    
  659.     }
  660.     }
  661.  
  662.   frame++;
  663. }
  664.  
  665.  
  666. static void
  667. show_frame (void)
  668. {
  669. #ifdef RAPH_IS_HOME
  670. #else
  671.   /* Tell GTK to physically draw the preview */
  672.   gtk_widget_draw (GTK_WIDGET (preview), NULL);
  673. #endif /* RAPH_IS_HOME */
  674. }
  675.  
  676.  
  677. static void
  678. init_preview_misc (void)
  679. {
  680.   GimpPixelRgn pixel_rgn;
  681.   gint i;
  682.   gboolean has_alpha;
  683.  
  684.   if ((imagetype == GIMP_RGB) || (imagetype == GIMP_INDEXED))
  685.     rgb_mode = TRUE;
  686.   else
  687.     rgb_mode = FALSE;
  688.  
  689.   has_alpha = gimp_drawable_has_alpha(drawable->id);
  690.  
  691.   seed_data = g_malloc(width*height*4);
  692.   preview_data1 = g_malloc(width*height*(rgb_mode?3:1));
  693.   preview_data2 = g_malloc(width*height*(rgb_mode?3:1));
  694.  
  695.   if ((drawable->width<256) || (drawable->height<256))
  696.     {
  697.       for (i=0;i<256;i++)
  698.     {
  699.       if (i < drawable->height)
  700.         {
  701.           gimp_pixel_rgn_init (&pixel_rgn,
  702.                    drawable,
  703.                    drawable->width>256?
  704.                    (drawable->width/2-128):0,
  705.                    (drawable->height>256?
  706.                    (drawable->height/2-128):0)+i,
  707.                    MIN(256,drawable->width),
  708.                    1,
  709.                    FALSE,
  710.                    FALSE);
  711.           gimp_pixel_rgn_get_rect (&pixel_rgn,
  712.                        &seed_data[(256*i +
  713.                          (
  714.                           (
  715.                            drawable->width<256 ?
  716.                            (256-drawable->width)/2 :
  717.                            0
  718.                            )
  719.                           +
  720.                           (
  721.                            drawable->height<256 ?
  722.                            (256-drawable->height)/2 :
  723.                            0
  724.                            ) * 256
  725.                           )) *
  726.                          gimp_drawable_bpp
  727.                          (drawable->id)
  728.                        ],
  729.                        drawable->width>256?
  730.                        (drawable->width/2-128):0,
  731.                        (drawable->height>256?
  732.                        (drawable->height/2-128):0)+i,
  733.                        MIN(256,drawable->width),
  734.                        1);
  735.         }
  736.     }
  737.     }
  738.   else
  739.     {
  740.       gimp_pixel_rgn_init (&pixel_rgn,
  741.                drawable,
  742.                drawable->width>256?(drawable->width/2-128):0,
  743.                drawable->height>256?(drawable->height/2-128):0,
  744.                MIN(256,drawable->width),
  745.                MIN(256,drawable->height),
  746.                FALSE,
  747.                FALSE);
  748.       gimp_pixel_rgn_get_rect (&pixel_rgn,
  749.                    seed_data,
  750.                    drawable->width>256?(drawable->width/2-128):0,
  751.                    drawable->height>256?(drawable->height/2-128):0,
  752.                    MIN(256,drawable->width),
  753.                    MIN(256,drawable->height));
  754.     }
  755.  
  756.   gimp_drawable_detach(drawable);
  757.  
  758.  
  759.   /* convert the image data of varying types into flat grey or rgb. */
  760.   switch (imagetype)
  761.     {
  762.     case GIMP_INDEXED:
  763.       if (has_alpha)
  764.     {
  765.       for (i=width*height;i>0;i--)
  766.         {
  767.           seed_data[3*(i-1)+2] =
  768.         ((palette[3*(seed_data[(i-1)*2])+2]*seed_data[(i-1)*2+1])/255)
  769.         + ((255-seed_data[(i-1)*2+1])*(RAND_FUNC ()%256))/255;
  770.           seed_data[3*(i-1)+1] =
  771.         ((palette[3*(seed_data[(i-1)*2])+1]*seed_data[(i-1)*2+1])/255)
  772.         + ((255-seed_data[(i-1)*2+1])*(RAND_FUNC ()%256))/255;
  773.           seed_data[3*(i-1)+0] =
  774.         ((palette[3*(seed_data[(i-1)*2])+0]*seed_data[(i-1)*2+1])/255)
  775.         + ((255-seed_data[(i-1)*2+1])*(RAND_FUNC ()%256))/255;
  776.         }
  777.     }
  778.       else
  779.     {
  780.       for (i=width*height;i>0;i--)
  781.         {
  782.           seed_data[3*(i-1)+2] = palette[3*(seed_data[i-1])+2];
  783.           seed_data[3*(i-1)+1] = palette[3*(seed_data[i-1])+1];
  784.           seed_data[3*(i-1)+0] = palette[3*(seed_data[i-1])+0];
  785.         }
  786.     }
  787.       break;
  788.  
  789.     case GIMP_GRAY:
  790.       if (has_alpha)
  791.     {
  792.       for (i=0;i<width*height;i++)
  793.         {
  794.           seed_data[i] =
  795.         (seed_data[i*2]*seed_data[i*2+1])/255
  796.         + ((255-seed_data[i*2+1])*(RAND_FUNC ()%256))/255;
  797.         }
  798.     }
  799.       break;
  800.  
  801.     case GIMP_RGB:
  802.       if (has_alpha)
  803.     {
  804.       for (i=0;i<width*height;i++)
  805.         {
  806.           seed_data[i*3+2] =
  807.         (seed_data[i*4+2]*seed_data[i*4+3])/255
  808.         + ((255-seed_data[i*4+3])*(RAND_FUNC ()%256))/255;
  809.           seed_data[i*3+1] =
  810.         (seed_data[i*4+1]*seed_data[i*4+3])/255
  811.         + ((255-seed_data[i*4+3])*(RAND_FUNC ()%256))/255;
  812.           seed_data[i*3+0] =
  813.         (seed_data[i*4+0]*seed_data[i*4+3])/255
  814.         + ((255-seed_data[i*4+3])*(RAND_FUNC ()%256))/255;
  815.         }
  816.     }
  817.       break;
  818.  
  819.     default:
  820.       break;
  821.     }
  822. }
  823.  
  824.  
  825.  
  826. /* Util. */
  827.  
  828. static int
  829. do_iteration (void)
  830. {
  831.   render_frame ();
  832.  
  833.   return 1;
  834. }
  835.  
  836.  
  837.  
  838. /*  Callbacks  */
  839.  
  840. static gint
  841. window_delete_callback (GtkWidget *widget,
  842.                 GdkEvent  *event,
  843.                 gpointer   data)
  844. {
  845.   gtk_idle_remove (idle_tag);
  846.  
  847.   gdk_flush ();
  848.   gtk_main_quit ();
  849.  
  850.   return FALSE;
  851. }
  852.  
  853. static void
  854. window_close_callback (GtkWidget *widget,
  855.                        gpointer   data)
  856. {
  857.   if (data)
  858.     gtk_widget_destroy(GTK_WIDGET(data));
  859.  
  860.   window_delete_callback (NULL, NULL, NULL);
  861. }
  862.  
  863. static void
  864. toggle_feedbacktype (GtkWidget *widget,
  865.              gpointer   event)
  866. {
  867.   GdkEventButton *bevent = (GdkEventButton *) event;
  868.  
  869.   if (bevent->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK))
  870.     {
  871.       wiggleamp = bevent->x/5;
  872.       
  873.       wiggly = TRUE;
  874.       init_lut();
  875.  
  876.       return;
  877.     }
  878.  
  879.   if (bevent->state & GDK_BUTTON1_MASK)
  880.     feedbacktype = !feedbacktype;
  881.  
  882.   if (bevent->state & GDK_BUTTON2_MASK)
  883.     wiggly = !wiggly;
  884.  
  885.   if (bevent->state & GDK_BUTTON3_MASK)
  886.     {
  887.       if (wiggleamp == LOWAMP)
  888.     wiggleamp = HIGHAMP;
  889.       else
  890.     wiggleamp = LOWAMP;
  891.  
  892.       wiggly = TRUE;
  893.       init_lut();
  894.     }
  895. }
  896.  
  897.  
  898. static gint
  899. iteration_callback (gpointer   data)
  900. {
  901.   do_iteration();
  902.   show_frame();
  903.  
  904.   return TRUE;
  905. }
  906.