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 / glasstile.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-01  |  18.0 KB  |  718 lines

  1. /*
  2.  * This is the Glass Tile plug-in for the GIMP 1.2
  3.  * Version 1.02
  4.  *
  5.  * Copyright (C) 1997 Karl-Johan Andersson (t96kja@student.tdb.uu.se)
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  *
  21.  */
  22.  
  23. /*
  24.  * This filter divide the image into square "glass"-blocks in which
  25.  * the image is refracted. 
  26.  * 
  27.  * The alpha-channel is left unchanged.
  28.  * 
  29.  * Please send any comments or suggestions to
  30.  * Karl-Johan Andersson (t96kja@student.tdb.uu.se)
  31.  *
  32.  * May 2000 - tim copperfield [timecop@japan.co.jp]
  33.  * Added preview mode.
  34.  * Noticed there is an issue with the algorithm if odd number of rows or
  35.  * columns is requested.  Dunno why.  I am not a graphics expert :(
  36.  *  
  37.  * May 2000 alt@gimp.org Made preview work and removed some boundary 
  38.  * conditions that caused "streaks" to appear when using some tile spaces.
  39.  */ 
  40.  
  41. #include "config.h"
  42.  
  43. #include <stdlib.h>
  44. #include <string.h>
  45.  
  46. #include <gtk/gtk.h>
  47.  
  48. #include <libgimp/gimp.h>
  49. #include <libgimp/gimpui.h>
  50.  
  51. #include "libgimp/stdplugins-intl.h"
  52.  
  53.  
  54. #define PREVIEW_SIZE  128 
  55.  
  56. /* --- Typedefs --- */
  57. typedef struct
  58. {
  59.   gint xblock;
  60.   gint yblock;
  61. } GlassValues;
  62.  
  63. typedef struct
  64. {
  65.     gint run;
  66. } GlassInterface;
  67.  
  68. /* --- Declare local functions --- */
  69. static void query (void);
  70. static void run   (gchar   *name,
  71.            gint     nparams,
  72.            GimpParam  *param,
  73.            gint    *nreturn_vals,
  74.            GimpParam **return_vals);
  75.  
  76. static gint glass_dialog               (GimpDrawable     *drawable);
  77. static void glass_ok_callback          (GtkWidget     *widget,
  78.                     gpointer       data);
  79.  
  80. static void fill_preview_with_thumb    (GtkWidget     *preview_widget, 
  81.                     gint32         drawable_ID);
  82. static GtkWidget *preview_widget       (GimpDrawable     *drawable);
  83.  
  84. static void glasstile                  (GimpDrawable     *drawable, 
  85.                     gboolean       preview_mode);
  86.  
  87. /* --- Variables --- */
  88. GimpPlugInInfo PLUG_IN_INFO =
  89. {
  90.   NULL,    /* init_proc */
  91.   NULL,    /* quit_proc */
  92.   query,   /* query_proc */
  93.   run,     /* run_proc */
  94. };
  95. static GlassValues gtvals =
  96. {
  97.     20,    /* tile width  */
  98.     20     /* tile height */
  99. };
  100. static GlassInterface gt_int =
  101. {
  102.   FALSE    /* run */
  103. };
  104.  
  105. /* preview */
  106. static guchar    *preview_bits;
  107. static GtkWidget *preview;
  108. static gdouble    preview_scale_x;
  109. static gdouble    preview_scale_y;
  110. static guchar    *preview_cache;
  111. static gint       preview_cache_rowstride;
  112. static gint       preview_cache_bpp;
  113.  
  114.  
  115. /* --- Functions --- */
  116.  
  117. MAIN ()
  118.  
  119. static void
  120. query (void) 
  121. {
  122.   static GimpParamDef args[] =
  123.   {
  124.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  125.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  126.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  127.     { GIMP_PDB_INT32, "tilex", "Tile width (10 - 50)" },
  128.     { GIMP_PDB_INT32, "tiley", "Tile height (10 - 50)" }
  129.   };
  130.   static gint nargs = sizeof (args) / sizeof (args[0]);
  131.  
  132.   gimp_install_procedure ("plug_in_glasstile",
  133.               "Divide the image into square glassblocks",
  134.               "Divide the image into square glassblocks in which the image is refracted.",
  135.               "Karl-Johan Andersson", /* Author */
  136.               "Karl-Johan Andersson", /* Copyright */
  137.               "May 2000",
  138.               N_("<Image>/Filters/Glass Effects/Glass Tile..."),
  139.               "RGB*, GRAY*",
  140.               GIMP_PLUGIN,
  141.               nargs, 0,
  142.               args, NULL);
  143. }
  144.  
  145. static void
  146. run (gchar   *name,
  147.      gint     nparams,
  148.      GimpParam  *param,
  149.      gint    *nreturn_vals,
  150.      GimpParam **return_vals)
  151. {
  152.   static GimpParam values[1];
  153.   GimpDrawable *drawable;
  154.   GimpRunModeType run_mode;
  155.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  156.   
  157.   run_mode = param[0].data.d_int32;
  158.   
  159.   *nreturn_vals = 1;
  160.   *return_vals = values;
  161.   
  162.   values[0].type = GIMP_PDB_STATUS;
  163.   values[0].data.d_status = status;
  164.  
  165.   /*  Get the specified drawable  */
  166.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  167.   
  168.   switch (run_mode)
  169.     {
  170.     case GIMP_RUN_INTERACTIVE:
  171.       INIT_I18N_UI();
  172.       /*  Possibly retrieve data  */
  173.       gimp_get_data ("plug_in_glasstile", >vals);
  174.       
  175.       /*  First acquire information with a dialog  */
  176.       if (! glass_dialog (drawable))
  177.     {
  178.       gimp_drawable_detach (drawable);
  179.       return;
  180.     }
  181.       break;
  182.       
  183.     case GIMP_RUN_NONINTERACTIVE:
  184.       INIT_I18N();
  185.       /*  Make sure all the arguments are there!  */
  186.       if (nparams != 5)
  187.     status = GIMP_PDB_CALLING_ERROR;
  188.       if (status == GIMP_PDB_SUCCESS)
  189.     {
  190.       gtvals.xblock = (gint) param[3].data.d_int32;
  191.       gtvals.yblock = (gint) param[4].data.d_int32;
  192.     }
  193.       if (gtvals.xblock < 10 || gtvals.xblock > 50) 
  194.     status = GIMP_PDB_CALLING_ERROR;
  195.       if (gtvals.yblock < 10 || gtvals.yblock > 50) 
  196.     status = GIMP_PDB_CALLING_ERROR;
  197.       break;
  198.       
  199.     case GIMP_RUN_WITH_LAST_VALS:
  200.       INIT_I18N();
  201.       /*  Possibly retrieve data  */
  202.       gimp_get_data ("plug_in_glasstile", >vals);
  203.       break;
  204.       
  205.     default:
  206.       break;
  207.     }
  208.  
  209.   if (status == GIMP_PDB_SUCCESS)
  210.     {
  211.       /*  Make sure that the drawable is gray or RGB color  */
  212.       if (gimp_drawable_is_rgb (drawable->id) ||
  213.       gimp_drawable_is_gray (drawable->id))
  214.     {
  215.       gimp_progress_init ( _("Glass Tile..."));
  216.       gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
  217.       
  218.       glasstile (drawable, 0);
  219.       
  220.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  221.         gimp_displays_flush (); 
  222.       /*  Store data  */
  223.       if (run_mode == GIMP_RUN_INTERACTIVE) 
  224.         {
  225.           gimp_set_data ("plug_in_glasstile", >vals, 
  226.                  sizeof (GlassValues));
  227.           g_free (preview_bits);
  228.           g_free (preview_cache);
  229.       }
  230.     }
  231.       else
  232.     {
  233.       /* gimp_message ("glasstile: cannot operate on indexed color images"); */
  234.       status = GIMP_PDB_EXECUTION_ERROR;
  235.     }
  236.     }
  237.     
  238.   values[0].data.d_status = status;
  239.   
  240.   gimp_drawable_detach (drawable);
  241. }
  242.  
  243. static gint
  244. glass_dialog (GimpDrawable *drawable)
  245. {
  246.   GtkWidget *dlg;
  247.   GtkWidget *main_vbox;
  248.   GtkWidget *frame;
  249.   GtkWidget *table;
  250.   GtkWidget *abox;
  251.   GtkObject *adj;
  252.  
  253.   gimp_ui_init ("glasstile", TRUE);
  254.  
  255.   dlg = gimp_dialog_new (_("Glass Tile"), "glasstile",
  256.              gimp_standard_help_func, "filters/glasstile.html",
  257.              GTK_WIN_POS_MOUSE,
  258.              FALSE, TRUE, FALSE,
  259.  
  260.              _("OK"), glass_ok_callback,
  261.              NULL, NULL, NULL, TRUE, FALSE,
  262.              _("Cancel"), gtk_widget_destroy,
  263.              NULL, 1, NULL, FALSE, TRUE,
  264.  
  265.              NULL);
  266.  
  267.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  268.               GTK_SIGNAL_FUNC (gtk_main_quit),
  269.               NULL);
  270.  
  271.   main_vbox = gtk_vbox_new (FALSE, 3);
  272.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 0);
  273.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox, TRUE, TRUE, 0);
  274.   gtk_widget_show (main_vbox);
  275.  
  276.   frame = gtk_frame_new (_("Preview"));
  277.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  278.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  279.   gtk_widget_show (frame);
  280.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  281.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  282.   gtk_container_add (GTK_CONTAINER (frame), abox);
  283.   gtk_widget_show (abox);
  284.   frame = gtk_frame_new (NULL);
  285.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  286.   gtk_container_add (GTK_CONTAINER (abox), frame);
  287.   gtk_widget_show (frame);
  288.   preview = preview_widget (drawable); /* we are here */
  289.   gtk_container_add (GTK_CONTAINER (frame), preview);
  290.   glasstile (drawable, TRUE); /* filter routine, initial pass */
  291.   gtk_widget_show (preview);
  292.   
  293.   /*  Parameter settings  */
  294.   frame = gtk_frame_new (_("Parameter Settings"));
  295.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  296.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  297.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
  298.  
  299.   table = gtk_table_new (2, 3, FALSE);
  300.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  301.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  302.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  303.   gtk_container_add (GTK_CONTAINER (frame), table);
  304.  
  305.   /* Horizontal scale - Width */
  306.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  307.                   _("Tile Width:"), 150, 0,
  308.                   gtvals.xblock, 10, 50, 2, 10, 0,
  309.                   TRUE, 0, 0,
  310.                   NULL, NULL);
  311.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  312.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  313.               >vals.xblock);
  314.   gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed",
  315.                  GTK_SIGNAL_FUNC (glasstile),
  316.                  (gpointer)drawable);
  317.  
  318.   /* Horizontal scale - Height */
  319.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  320.                   _("Tile Height:"), 150, 0,
  321.                   gtvals.yblock, 10, 50, 2, 10, 0,
  322.                   TRUE, 0, 0,
  323.                   NULL, NULL);
  324.   gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  325.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  326.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  327.               >vals.yblock);
  328.   gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed",
  329.                  GTK_SIGNAL_FUNC (glasstile),
  330.                  (gpointer)drawable);
  331.  
  332.   gtk_widget_show (frame);
  333.   gtk_widget_show (table);
  334.  
  335.   gtk_widget_show (dlg);
  336.  
  337.   gtk_main ();
  338.   gdk_flush ();
  339.  
  340.   return gt_int.run;
  341. }
  342.  
  343. static void
  344. glass_ok_callback (GtkWidget *widget,
  345.            gpointer   data)
  346. {
  347.   gt_int.run = TRUE;
  348.  
  349.   gtk_widget_destroy (GTK_WIDGET (data));
  350. }
  351.  
  352. static GtkWidget *
  353. preview_widget (GimpDrawable *drawable)
  354. {
  355.   gint       size;
  356.   GtkWidget *preview;
  357.  
  358.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  359.   fill_preview_with_thumb (preview, drawable->id);
  360.   size = GTK_PREVIEW (preview)->rowstride * GTK_PREVIEW (preview)->buffer_height;
  361.   preview_bits = g_malloc (size);
  362.   memcpy (preview_bits, GTK_PREVIEW (preview)->buffer, size);
  363.  
  364.   return preview;
  365. }
  366.  
  367. static void
  368. fill_preview_with_thumb (GtkWidget *widget, 
  369.              gint32     drawable_ID)
  370. {
  371.   guchar  *drawable_data;
  372.   gint     bpp;
  373.   gint     x,y;
  374.   gint     width  = PREVIEW_SIZE;
  375.   gint     height = PREVIEW_SIZE;
  376.   guchar  *src;
  377.   gdouble  r, g, b, a;
  378.   gdouble  c0, c1;
  379.   guchar  *p0, *p1;
  380.   guchar  *even, *odd;
  381.  
  382.   bpp = 0; /* Only returned */
  383.   
  384.   drawable_data = 
  385.     gimp_drawable_get_thumbnail_data (drawable_ID, &width, &height, &bpp);
  386.  
  387.   if (width < 1 || height < 1)
  388.     return;
  389.  
  390.   preview_cache = drawable_data;
  391.   preview_cache_rowstride = width * bpp;
  392.   preview_cache_bpp = bpp;
  393.  
  394.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  395.   preview_scale_x = (gdouble)width  / (gdouble)gimp_drawable_width  (drawable_ID);
  396.   preview_scale_y = (gdouble)height / (gdouble)gimp_drawable_height (drawable_ID);
  397.  
  398.   even = g_malloc (width * 3);
  399.   odd  = g_malloc (width * 3);
  400.   src = drawable_data;
  401.  
  402.   for (y = 0; y < height; y++)
  403.     {
  404.       p0 = even;
  405.       p1 = odd;
  406.       
  407.       for (x = 0; x < width; x++) 
  408.     {
  409.       if(bpp == 4)
  410.         {
  411.           r =  ((gdouble)src[x*4+0])/255.0;
  412.           g = ((gdouble)src[x*4+1])/255.0;
  413.           b = ((gdouble)src[x*4+2])/255.0;
  414.           a = ((gdouble)src[x*4+3])/255.0;
  415.         }
  416.       else if(bpp == 3)
  417.         {
  418.           r =  ((gdouble)src[x*3+0])/255.0;
  419.           g = ((gdouble)src[x*3+1])/255.0;
  420.           b = ((gdouble)src[x*3+2])/255.0;
  421.           a = 1.0;
  422.         }
  423.       else
  424.         {
  425.           r = ((gdouble)src[x*bpp+0])/255.0;
  426.           g = b = r;
  427.           if(bpp == 2)
  428.         a = ((gdouble)src[x*bpp+1])/255.0;
  429.           else
  430.         a = 1.0;
  431.         }
  432.       
  433.       if ((x / GIMP_CHECK_SIZE_SM) & 1) 
  434.         {
  435.           c0 = GIMP_CHECK_LIGHT;
  436.           c1 = GIMP_CHECK_DARK;
  437.         } 
  438.       else 
  439.         {
  440.           c0 = GIMP_CHECK_DARK;
  441.           c1 = GIMP_CHECK_LIGHT;
  442.         }
  443.       
  444.     *p0++ = (c0 + (r - c0) * a) * 255.0;
  445.     *p0++ = (c0 + (g - c0) * a) * 255.0;
  446.     *p0++ = (c0 + (b - c0) * a) * 255.0;
  447.     
  448.     *p1++ = (c1 + (r - c1) * a) * 255.0;
  449.     *p1++ = (c1 + (g - c1) * a) * 255.0;
  450.     *p1++ = (c1 + (b - c1) * a) * 255.0;
  451.     
  452.       } /* for */
  453.       
  454.       if ((y / GIMP_CHECK_SIZE_SM) & 1)
  455.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)odd,  0, y, width);
  456.       else
  457.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)even, 0, y, width);
  458.  
  459.       src += width * bpp;
  460.     }
  461.  
  462.   g_free (even);
  463.   g_free (odd);
  464. }
  465.  
  466. static void
  467. preview_do_row(gint    row,
  468.            gint    width,
  469.            guchar *even,
  470.            guchar *odd,
  471.            guchar *src)
  472. {
  473.   gint    x;
  474.   
  475.   guchar *p0 = even;
  476.   guchar *p1 = odd;
  477.   
  478.   gdouble    r, g, b, a;
  479.   gdouble    c0, c1;
  480.   
  481.   for (x = 0; x < width; x++) 
  482.     {
  483.       if (preview_cache_bpp == 4)
  484.     {
  485.       r = ((gdouble)src[x*4+0]) / 255.0;
  486.       g = ((gdouble)src[x*4+1]) / 255.0;
  487.       b = ((gdouble)src[x*4+2]) / 255.0;
  488.       a = ((gdouble)src[x*4+3]) / 255.0;
  489.     }
  490.       else if (preview_cache_bpp == 3)
  491.     {
  492.       r = ((gdouble)src[x*3+0]) / 255.0;
  493.       g = ((gdouble)src[x*3+1]) / 255.0;
  494.       b = ((gdouble)src[x*3+2]) / 255.0;
  495.       a = 1.0;
  496.     }
  497.       else
  498.     {
  499.       r = ((gdouble)src[x*preview_cache_bpp+0]) / 255.0;
  500.       g = b = r;
  501.       if (preview_cache_bpp == 2)
  502.             a = ((gdouble)src[x*preview_cache_bpp+1]) / 255.0;
  503.       else
  504.         a = 1.0;
  505.     }
  506.       
  507.       if ((x / GIMP_CHECK_SIZE) & 1) 
  508.     {
  509.       c0 = GIMP_CHECK_LIGHT;
  510.       c1 = GIMP_CHECK_DARK;
  511.     } 
  512.       else 
  513.     {
  514.       c0 = GIMP_CHECK_DARK;
  515.       c1 = GIMP_CHECK_LIGHT;
  516.     }
  517.       
  518.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  519.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  520.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  521.       
  522.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  523.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  524.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  525.       
  526.     } /* for */
  527.   
  528.   if ((row / GIMP_CHECK_SIZE) & 1)
  529.     {
  530.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)odd,  0, row, width); 
  531.     }
  532.   else
  533.     {
  534.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)even, 0, row, width); 
  535.     }
  536. }
  537.  
  538. /*  -  Filter function  -  I wish all filter functions had a pmode :) */
  539. static void
  540. glasstile (GimpDrawable *drawable, 
  541.        gboolean   preview_mode)
  542. {
  543.   GimpPixelRgn srcPR, destPR;
  544.   gint width, height;
  545.   gint bytes;
  546.   guchar *dest, *d;
  547.   guchar *cur_row;
  548.   gint row, col, i, iwidth;
  549.   gint x1, y1, x2, y2;
  550.  
  551.   guchar *odd = NULL;
  552.   guchar *even = NULL;
  553.  
  554.   gint rutbredd, xpixel1, xpixel2;
  555.   gint ruthojd , ypixel2;
  556.   gint xhalv, xoffs, xmitt, xplus;
  557.   gint yhalv, yoffs, ymitt, yplus;
  558.   gint cbytes;
  559.       
  560.   if (preview_mode) 
  561.     {
  562.       width  = GTK_PREVIEW (preview)->buffer_width;
  563.       height = GTK_PREVIEW (preview)->buffer_height;
  564.       bytes  = preview_cache_bpp;
  565.  
  566.       x1 = y1 = 0;
  567.       x2 = width;
  568.       y2 = height;
  569.  
  570.       even = g_malloc (width * 3);
  571.       odd  = g_malloc (width * 3);
  572.     } 
  573.   else 
  574.     {
  575.       gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  576.       width  = drawable->width;
  577.       height = drawable->height;
  578.       bytes  = drawable->bpp;
  579.     }
  580.   
  581.   cur_row = g_new (guchar, width * bytes);
  582.   dest    = g_new (guchar, width * bytes);
  583.  
  584.   /*  initialize the pixel regions  */
  585.   if (preview_mode) 
  586.     {
  587.       rutbredd = gtvals.xblock * preview_scale_x;
  588.       ruthojd  = gtvals.yblock * preview_scale_y;
  589.     }
  590.   else
  591.     {
  592.       gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
  593.       gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
  594.  
  595.       rutbredd = gtvals.xblock;
  596.       ruthojd  = gtvals.yblock;
  597.     }
  598.  
  599.   xhalv = rutbredd / 2;
  600.   yhalv = ruthojd  / 2;
  601.   cbytes = bytes;
  602.  
  603.   if (cbytes % 2 == 0) 
  604.     cbytes--; 
  605.  
  606.   iwidth = width - x1;
  607.   xplus = rutbredd % 2;
  608.   yplus = ruthojd  % 2;
  609.  
  610.   ymitt = y1;
  611.   yoffs = 0;
  612.  
  613.   /*  Loop through the rows */
  614.   for (row = y1; row < y2; row++)
  615.     {
  616.       d = dest;
  617.       ypixel2 = ymitt + yoffs * 2;
  618.  
  619.       if(ypixel2 < 0)
  620.     ypixel2 = 0;
  621.  
  622.       if (preview_mode)
  623.     {
  624.           if (ypixel2 < height)
  625.             memcpy (cur_row, 
  626.             preview_cache + (ypixel2 * preview_cache_rowstride), 
  627.             preview_cache_rowstride);
  628.           else 
  629.         memcpy (cur_row, 
  630.             preview_cache + ((y2 - 1) * preview_cache_rowstride), 
  631.             preview_cache_rowstride);
  632.     }
  633.       else
  634.     {
  635.       if (ypixel2 < height) 
  636.             gimp_pixel_rgn_get_row (&srcPR, cur_row, x1, ypixel2, iwidth);
  637.           else 
  638.             gimp_pixel_rgn_get_row (&srcPR, cur_row, x1, y2 - 1, iwidth);
  639.     }
  640.  
  641.       yoffs++;
  642.  
  643.       if (yoffs == yhalv) 
  644.     {
  645.       ymitt += ruthojd;
  646.       yoffs =- yhalv;
  647.       yoffs -= yplus;
  648.     }
  649.       
  650.       xmitt = 0;
  651.       xoffs = 0;
  652.  
  653.       for (col = 0; col < (x2 - x1); col++) /* one pixel */
  654.     {
  655.       xpixel1 = (xmitt + xoffs) * bytes;
  656.       xpixel2 = (xmitt + xoffs * 2) * bytes;
  657.  
  658.       if (xpixel2 < ((x2 - x1) * bytes)) 
  659.         {
  660.           if(xpixel2 < 0)
  661.         xpixel2 = 0;
  662.           for (i = 0; i < bytes; i++) 
  663.         d[xpixel1 + i] = cur_row[xpixel2 + i];
  664.         }
  665.       else 
  666.         {
  667.           for (i = 0; i < bytes; i++)
  668.         d[xpixel1 + i]=cur_row[xpixel1 + i];
  669.         }
  670.  
  671.       xoffs++;
  672.  
  673.       if (xoffs == xhalv) 
  674.         {
  675.           xmitt += rutbredd;
  676.           xoffs =- xhalv;
  677.           xoffs -= xplus;
  678.         }
  679.     }
  680.  
  681.       /*  Store the dest  */
  682.       if (preview_mode)
  683.     preview_do_row(row,width,even,odd,dest);
  684.       else
  685.     gimp_pixel_rgn_set_row (&destPR, dest, x1, row, iwidth);
  686.       
  687.       if ((row % 5) == 0 && !preview_mode)
  688.         gimp_progress_update ((double) row / (double) (y2 - y1));
  689.     }
  690.  
  691.  
  692.   if(even)
  693.     g_free(even);
  694.  
  695.   if(odd)
  696.     g_free(odd);
  697.  
  698.  
  699.   /*  Update region  */
  700.   if (preview_mode) 
  701.     {
  702.       gtk_widget_queue_draw (preview);
  703.     }
  704.   else
  705.     {
  706.       gimp_drawable_flush (drawable);
  707.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  708.       gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  709.     }
  710.  
  711.   g_free (cur_row);
  712.   g_free (dest);
  713. }
  714.  
  715.  
  716.  
  717.  
  718.