home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / smudge.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  13.8 KB  |  494 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <gtk/gtk.h>
  22. #include <gdk/gdkkeysyms.h>
  23.  
  24. #include "apptypes.h"
  25.  
  26. #include "appenv.h"
  27. #include "drawable.h"
  28. #include "smudge.h"
  29. #include "gdisplay.h"
  30. #include "gimplut.h"
  31. #include "gimpui.h"
  32. #include "paint_funcs.h"
  33. #include "paint_core.h"
  34. #include "paint_options.h"
  35. #include "selection.h"
  36. #include "tools.h"
  37. #include "gimage.h"
  38.  
  39. #include "libgimp/gimpmath.h"
  40.  
  41. #include "libgimp/gimpintl.h"
  42.  
  43.  
  44. /* default defines */
  45.  
  46. #define SMUDGE_DEFAULT_RATE   50.0
  47.  
  48. /*  the smudge structures  */
  49.  
  50. typedef struct _SmudgeOptions SmudgeOptions;
  51.  
  52. struct _SmudgeOptions
  53. {
  54.   PaintOptions  paint_options;
  55.  
  56.   gdouble       rate;
  57.   gdouble       rate_d;
  58.   GtkObject    *rate_w;
  59. };
  60.  
  61. static PixelRegion  accumPR;
  62. static guchar      *accum_data;
  63.  
  64. /*  the smudge tool options  */
  65. static SmudgeOptions * smudge_options = NULL;
  66.  
  67. /*  local variables */
  68. static gdouble  non_gui_rate;
  69.  
  70. /*  function prototypes */
  71. static void      smudge_motion     (PaintCore *, PaintPressureOptions *,
  72.                     gdouble, GimpDrawable *);
  73. static gboolean  smudge_init       (PaintCore *, GimpDrawable *);
  74. static void      smudge_finish     (PaintCore *, GimpDrawable *);
  75.  
  76. static void      smudge_nonclipped_painthit_coords (PaintCore *paint_core,
  77.                             gint      *x,
  78.                             gint      *y, 
  79.                             gint      *w,
  80.                             gint      *h);
  81. static void      smudge_allocate_accum_buffer      (gint       w,
  82.                             gint       h, 
  83.                             gint       bytes,
  84.                             guchar    *do_fill);
  85.  
  86. static void
  87. smudge_options_reset (void)
  88. {
  89.   SmudgeOptions *options = smudge_options;
  90.  
  91.   paint_options_reset ((PaintOptions *) options);
  92.  
  93.   gtk_adjustment_set_value (GTK_ADJUSTMENT (options->rate_w), options->rate_d);
  94. }
  95.  
  96. static SmudgeOptions *
  97. smudge_options_new (void)
  98. {
  99.   SmudgeOptions *options;
  100.  
  101.   GtkWidget *vbox;
  102.   GtkWidget *hbox;
  103.   GtkWidget *label;
  104.   GtkWidget *scale;
  105.  
  106.   /*  the new smudge tool options structure  */
  107.   options = g_new (SmudgeOptions, 1);
  108.   paint_options_init ((PaintOptions *) options,
  109.               SMUDGE,
  110.               smudge_options_reset);
  111.  
  112.   options->rate = options->rate_d = SMUDGE_DEFAULT_RATE;
  113.  
  114.   /*  the main vbox  */
  115.   vbox = ((ToolOptions *) options)->main_vbox;
  116.  
  117.   /*  the rate scale  */
  118.   hbox = gtk_hbox_new (FALSE, 4);
  119.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  120.  
  121.   label = gtk_label_new (_("Rate:"));
  122.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
  123.   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  124.   gtk_widget_show (label);
  125.  
  126.   options->rate_w =
  127.     gtk_adjustment_new (options->rate_d, 0.0, 100.0, 1.0, 1.0, 0.0);
  128.   scale = gtk_hscale_new (GTK_ADJUSTMENT (options->rate_w));
  129.   gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
  130.   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  131.   gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
  132.   gtk_signal_connect (GTK_OBJECT (options->rate_w), "value_changed",
  133.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  134.               &options->rate);
  135.   gtk_widget_show (scale);
  136.   gtk_widget_show (hbox);
  137.  
  138.   return options;
  139. }
  140.  
  141. void *
  142. smudge_paint_func (PaintCore    *paint_core,
  143.            GimpDrawable *drawable,
  144.            int           state)
  145. {
  146.   /* initialization fails if the user starts outside the drawable */
  147.   static gboolean initialized = FALSE;
  148.  
  149.   switch (state)
  150.     {
  151.     case MOTION_PAINT:
  152.       if (!initialized)
  153.     initialized = smudge_init (paint_core, drawable);
  154.       if (initialized)
  155.     smudge_motion (paint_core, smudge_options->paint_options.pressure_options,
  156.                smudge_options->rate, drawable);
  157.       break;
  158.     case FINISH_PAINT:
  159.       smudge_finish (paint_core, drawable);
  160.       initialized = FALSE;
  161.       break;
  162.     }
  163.  
  164.   return NULL;
  165. }
  166.  
  167. static void
  168. smudge_finish (PaintCore    *paint_core,
  169.            GimpDrawable *drawable)
  170. {
  171.   if (accum_data)
  172.     {
  173.       g_free (accum_data);
  174.       accum_data = NULL;
  175.     }
  176. }
  177.  
  178. static void 
  179. smudge_nonclipped_painthit_coords (PaintCore *paint_core,
  180.                    gint      *x, 
  181.                    gint      *y, 
  182.                    gint      *w, 
  183.                    gint      *h)
  184. {
  185.   /* Note: these are the brush mask size plus a border of 1 pixel */
  186.   *x = (gint) paint_core->curx - paint_core->brush->mask->width/2 - 1;
  187.   *y = (gint) paint_core->cury - paint_core->brush->mask->height/2 - 1;
  188.   *w = paint_core->brush->mask->width + 2;
  189.   *h = paint_core->brush->mask->height + 2;
  190. }
  191.  
  192. static gboolean
  193. smudge_init (PaintCore    *paint_core,
  194.          GimpDrawable *drawable)
  195. {
  196.   GImage *gimage;
  197.   TempBuf *area;
  198.   PixelRegion  srcPR;
  199.   gint x, y, w, h;
  200.   gint was_clipped;
  201.   guchar *do_fill = NULL;
  202.  
  203.   if (! (gimage = drawable_gimage (drawable)))
  204.     return FALSE;
  205.  
  206.   /*  If the image type is indexed, don't smudge  */
  207.   if ((drawable_type (drawable) == INDEXED_GIMAGE) ||
  208.       (drawable_type (drawable) == INDEXEDA_GIMAGE))
  209.     return FALSE;
  210.  
  211.   area = paint_core_get_paint_area (paint_core, drawable, 1.0);
  212.  
  213.   if (!area) 
  214.     return FALSE;
  215.   
  216.   /*  adjust the x and y coordinates to the upper left corner of the brush  */
  217.   smudge_nonclipped_painthit_coords (paint_core, &x, &y, &w, &h);
  218.   
  219.   if (x != area->x || y != area->y || w != area->width || h != area->height)
  220.     was_clipped = TRUE;
  221.   else 
  222.     was_clipped = FALSE;
  223.  
  224.   /* When clipped, accum_data may contain pixels that map to
  225.      off-canvas pixels of the under-the-brush image, particulary
  226.      when the brush image contains an edge or corner of the
  227.      image. These off-canvas pixels are not a part of the current
  228.      composite, but may be composited in later generations. do_fill
  229.      contains a copy of the color of the pixel at the center of the
  230.      brush; assumed this is a reasonable choice for off- canvas pixels
  231.      that may enter into the blend */
  232.  
  233.   if (was_clipped)
  234.     do_fill = gimp_drawable_get_color_at (drawable,
  235.                  CLAMP ((gint) paint_core->curx, 0, gimp_drawable_width (drawable) - 1),
  236.                  CLAMP ((gint) paint_core->cury, 0, gimp_drawable_height (drawable) - 1));
  237.   
  238.   smudge_allocate_accum_buffer (w, h, gimp_drawable_bytes (drawable), do_fill);
  239.  
  240.   accumPR.x = area->x - x; 
  241.   accumPR.y = area->y - y;
  242.   accumPR.w = area->width;
  243.   accumPR.h = area->height;
  244.   accumPR.rowstride = accumPR.bytes * w; 
  245.   accumPR.data = accum_data 
  246.     + accumPR.rowstride * accumPR.y 
  247.     + accumPR.x * accumPR.bytes;
  248.  
  249.   pixel_region_init (&srcPR, drawable_data (drawable), 
  250.         area->x, area->y, area->width, area->height, FALSE);
  251.  
  252.   /* copy the region under the original painthit. */
  253.   copy_region (&srcPR, &accumPR);
  254.  
  255.   accumPR.x = area->x - x; 
  256.   accumPR.y = area->y - y;
  257.   accumPR.w = area->width;
  258.   accumPR.h = area->height;
  259.   accumPR.rowstride = accumPR.bytes * w;
  260.   accumPR.data = accum_data
  261.     + accumPR.rowstride * accumPR.y 
  262.     + accumPR.x * accumPR.bytes;
  263.  
  264.   if (do_fill) 
  265.     g_free(do_fill);
  266.  
  267.   return TRUE;
  268. }
  269.  
  270. static void
  271. smudge_allocate_accum_buffer (gint    w, 
  272.                   gint    h, 
  273.                   gint    bytes,
  274.                   guchar *do_fill)
  275.   /*  Allocate the accumulation buffer */
  276.   accumPR.bytes = bytes;
  277.   accum_data = g_malloc (w * h * bytes);
  278.  
  279.   if (do_fill != NULL)
  280.     {
  281.       /* guchar color[3] = {0,0,0}; */
  282.       accumPR.x = 0; 
  283.       accumPR.y = 0;
  284.       accumPR.w = w;
  285.       accumPR.h = h;
  286.       accumPR.rowstride = accumPR.bytes * w;
  287.       accumPR.data = accum_data;
  288.       color_region (&accumPR, (const guchar*)do_fill);
  289.     }
  290. }
  291.  
  292. Tool *
  293. tools_new_smudge (void)
  294. {
  295.   Tool * tool;
  296.   PaintCore * private;
  297.  
  298.   /*  The tool options  */
  299.   if (! smudge_options)
  300.     {
  301.       smudge_options = smudge_options_new ();
  302.       tools_register (SMUDGE, (ToolOptions *) smudge_options);
  303.  
  304.       /*  press all default buttons  */
  305.       smudge_options_reset ();
  306.     }
  307.  
  308.   tool = paint_core_new (SMUDGE);
  309.   /*tool->modifier_key_func = smudge_modifier_key_func;*/
  310.  
  311.   private = (PaintCore *) tool->private;
  312.   private->paint_func = smudge_paint_func;
  313.  
  314.   return tool;
  315. }
  316.  
  317. void
  318. tools_free_smudge (Tool *tool)
  319. {
  320.   paint_core_free (tool);
  321. }
  322.  
  323. static void
  324. smudge_motion (PaintCore            *paint_core,
  325.            PaintPressureOptions *pressure_options,
  326.            gdouble               smudge_rate,
  327.            GimpDrawable         *drawable)
  328. {
  329.   GImage *gimage;
  330.   TempBuf * area;
  331.   PixelRegion srcPR, destPR, tempPR;
  332.   gdouble rate;
  333.   gint opacity;
  334.   gint x,y,w,h;
  335.  
  336.   if (! (gimage = drawable_gimage (drawable)))
  337.     return;
  338.  
  339.   /*  If the image type is indexed, don't smudge  */
  340.   if ((drawable_type (drawable) == INDEXED_GIMAGE) ||
  341.       (drawable_type (drawable) == INDEXEDA_GIMAGE))
  342.     return;
  343.  
  344.   smudge_nonclipped_painthit_coords (paint_core, &x, &y, &w, &h);
  345.  
  346.   /*  Get the paint area */
  347.   /*  Smudge won't scale!  */
  348.   if (! (area = paint_core_get_paint_area (paint_core, drawable, 1.0)))
  349.     return;
  350.  
  351.   /* srcPR will be the pixels under the current painthit from 
  352.      the drawable*/
  353.  
  354.   pixel_region_init (&srcPR, drawable_data (drawable), 
  355.              area->x, area->y, area->width, area->height, FALSE);
  356.  
  357.   /* Enable pressure sensitive rate */
  358.   if (pressure_options->rate)
  359.     rate = MIN (smudge_rate / 100.0 * paint_core->curpressure * 2.0, 1.0);
  360.   else
  361.     rate = smudge_rate / 100.0;
  362.  
  363.   /* The tempPR will be the built up buffer (for smudge) */ 
  364.   tempPR.bytes = accumPR.bytes;
  365.   tempPR.rowstride = accumPR.rowstride;
  366.   tempPR.x = area->x - x; 
  367.   tempPR.y = area->y - y;
  368.   tempPR.w = area->width;
  369.   tempPR.h = area->height;
  370.   tempPR.data = accum_data +
  371.     tempPR.rowstride * tempPR.y + tempPR.x * tempPR.bytes;
  372.  
  373.   /* The dest will be the paint area we got above (= canvas_buf) */    
  374.  
  375.   destPR.bytes = area->bytes;                                     
  376.   destPR.x = 0; destPR.y = 0;                                     
  377.   destPR.w = area->width;                                         
  378.   destPR.h = area->height;                                        
  379.   destPR.rowstride = area->width * area->bytes;                  
  380.   destPR.data = temp_buf_data (area); 
  381.  
  382.   /*  
  383.      Smudge uses the buffer Accum.
  384.      For each successive painthit Accum is built like this
  385.     Accum =  rate*Accum  + (1-rate)*I.
  386.      where I is the pixels under the current painthit. 
  387.      Then the paint area (canvas_buf) is built as 
  388.     (Accum,1) (if no alpha),
  389.   */
  390.  
  391.   blend_region (&srcPR, &tempPR, &tempPR, ROUND (rate * 255.0));
  392.  
  393.   /* re-init the tempPR */
  394.  
  395.   tempPR.bytes = accumPR.bytes;
  396.   tempPR.rowstride = accumPR.rowstride;
  397.   tempPR.x = area->x - x; 
  398.   tempPR.y = area->y - y;
  399.   tempPR.w = area->width;
  400.   tempPR.h = area->height;
  401.   tempPR.data = accum_data 
  402.     + tempPR.rowstride * tempPR.y 
  403.     + tempPR.x * tempPR.bytes;
  404.  
  405.   if (!drawable_has_alpha (drawable))                             
  406.     add_alpha_region (&tempPR, &destPR);                          
  407.   else                                                            
  408.     copy_region (&tempPR, &destPR);
  409.  
  410.   opacity = 255 * gimp_context_get_opacity (NULL);
  411.   if (pressure_options->opacity)
  412.     opacity = opacity * 2.0 * paint_core->curpressure;
  413.  
  414.   /*Replace the newly made paint area to the gimage*/ 
  415.   paint_core_replace_canvas (paint_core, drawable, 
  416.                  MIN (opacity, 255),
  417.                  OPAQUE_OPACITY, 
  418.                  pressure_options->pressure ? PRESSURE : SOFT,
  419.                  1.0, INCREMENTAL);
  420. }
  421.  
  422. static void *
  423. smudge_non_gui_paint_func (PaintCore    *paint_core,
  424.                GimpDrawable *drawable,
  425.                int           state)
  426. {
  427.   smudge_motion (paint_core, &non_gui_pressure_options, non_gui_rate, drawable);
  428.  
  429.   return NULL;
  430. }
  431.  
  432. gboolean
  433. smudge_non_gui_default (GimpDrawable *drawable,
  434.             int           num_strokes,
  435.             double       *stroke_array)
  436. {
  437.   gdouble rate = SMUDGE_DEFAULT_RATE;
  438.   SmudgeOptions *options = smudge_options;
  439.  
  440.   if (options)
  441.     rate = options->rate;
  442.  
  443.   return smudge_non_gui (drawable, rate, num_strokes, stroke_array);
  444. }
  445.  
  446. gboolean
  447. smudge_non_gui (GimpDrawable *drawable,
  448.         gdouble       rate,
  449.         int           num_strokes,
  450.         double       *stroke_array)
  451. {
  452.   gint i;
  453.  
  454.   if (paint_core_init (&non_gui_paint_core, drawable,
  455.                stroke_array[0], stroke_array[1]))
  456.     {
  457.       smudge_init (&non_gui_paint_core, drawable);
  458.  
  459.       /* Set the paint core's paint func */
  460.       non_gui_paint_core.paint_func = smudge_non_gui_paint_func;
  461.  
  462.       non_gui_rate = rate;
  463.  
  464.       non_gui_paint_core.curx = non_gui_paint_core.startx = 
  465.     non_gui_paint_core.lastx = stroke_array[0];
  466.       non_gui_paint_core.cury = non_gui_paint_core.starty = 
  467.     non_gui_paint_core.lasty = stroke_array[1];
  468.  
  469.       smudge_non_gui_paint_func (&non_gui_paint_core, drawable, 0); 
  470.  
  471.       for (i = 1; i < num_strokes; i++)
  472.     {
  473.       non_gui_paint_core.curx = stroke_array[i * 2 + 0];
  474.       non_gui_paint_core.cury = stroke_array[i * 2 + 1];
  475.  
  476.       paint_core_interpolate (&non_gui_paint_core, drawable);
  477.  
  478.       non_gui_paint_core.lastx = non_gui_paint_core.curx;
  479.       non_gui_paint_core.lasty = non_gui_paint_core.cury;
  480.     }
  481.  
  482.       /* Finish the painting */
  483.       paint_core_finish (&non_gui_paint_core, drawable, -1);
  484.  
  485.       /* Cleanup */
  486.       paint_core_cleanup ();
  487.       smudge_finish (&non_gui_paint_core, drawable);
  488.       return TRUE;
  489.     }
  490.   else
  491.     return FALSE;
  492. }
  493.