app: add gimp_gegl_smudge_blend(), a brute-force port of blend_region()

and use it in GimpSmudge. This only to get functionality ported and
the API done, and not the final state.
This commit is contained in:
Michael Natterer
2012-04-18 00:32:10 +02:00
parent e4d97f9a95
commit c3ceb8698d
3 changed files with 157 additions and 51 deletions

View File

@ -307,3 +307,102 @@ gimp_gegl_dodgeburn (GeglBuffer *src_buffer,
break;
}
}
/*
* blend_pixels patched 8-24-05 to fix bug #163721. Note that this change
* causes the function to treat src1 and src2 asymmetrically. This gives the
* right behavior for the smudge tool, which is the only user of this function
* at the time of patching. If you want to use the function for something
* else, caveat emptor.
*/
void
gimp_gegl_smudge_blend (GeglBuffer *top_buffer,
const GeglRectangle *top_rect,
GeglBuffer *bottom_buffer,
const GeglRectangle *bottom_rect,
GeglBuffer *dest_buffer,
const GeglRectangle *dest_rect,
guchar blend)
{
GeglBufferIterator *iter;
const Babl *top_format;
const Babl *bottom_format;
const Babl *dest_format;
gint top_bpp;
gint bottom_bpp;
gint dest_bpp;
top_format = gegl_buffer_get_format (top_buffer);
bottom_format = gegl_buffer_get_format (bottom_buffer);
dest_format = gegl_buffer_get_format (dest_buffer);
top_bpp = babl_format_get_bytes_per_pixel (top_format);
bottom_bpp = babl_format_get_bytes_per_pixel (bottom_format);
dest_bpp = babl_format_get_bytes_per_pixel (dest_format);
iter = gegl_buffer_iterator_new (top_buffer, top_rect, 0, NULL,
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
gegl_buffer_iterator_add (iter, bottom_buffer, bottom_rect, 0, NULL,
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0, NULL,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
while (gegl_buffer_iterator_next (iter))
{
const guchar *top = iter->data[0];
const guchar *bottom = iter->data[1];
guchar *dest = iter->data[2];
if (babl_format_has_alpha (top_format))
{
const guint blend1 = 255 - blend;
const guint blend2 = blend + 1;
const guint c = top_bpp - 1;
while (iter->length--)
{
const gint a1 = blend1 * bottom[c];
const gint a2 = blend2 * top[c];
const gint a = a1 + a2;
guint b;
if (!a)
{
for (b = 0; b < top_bpp; b++)
dest[b] = 0;
}
else
{
for (b = 0; b < c; b++)
dest[b] =
bottom[b] + (bottom[b] * a1 + top[b] * a2 - a * bottom[b]) / a;
dest[c] = a >> 8;
}
top += top_bpp;
bottom += bottom_bpp;
dest += dest_bpp;
}
}
else
{
const guchar blend1 = 255 - blend;
while (iter->length--)
{
guint b;
for (b = 0; b < top_bpp; b++)
dest[b] =
bottom[b] + (bottom[b] * blend1 + top[b] * blend - bottom[b] * 255) / 255;
top += top_bpp;
bottom += bottom_bpp;
dest += dest_bpp;
}
}
}
}

View File

@ -25,23 +25,31 @@
/* this is a pretty stupid port of concolve_region() that only works
* on a linear source buffer
*/
void gimp_gegl_convolve (GeglBuffer *src_buffer,
const GeglRectangle *src_rect,
GeglBuffer *dest_buffer,
const GeglRectangle *dest_rect,
const gfloat *kernel,
gint kernel_size,
gdouble divisor,
GimpConvolutionType mode,
gboolean alpha_weighting);
void gimp_gegl_convolve (GeglBuffer *src_buffer,
const GeglRectangle *src_rect,
GeglBuffer *dest_buffer,
const GeglRectangle *dest_rect,
const gfloat *kernel,
gint kernel_size,
gdouble divisor,
GimpConvolutionType mode,
gboolean alpha_weighting);
void gimp_gegl_dodgeburn (GeglBuffer *src_buffer,
const GeglRectangle *src_rect,
GeglBuffer *dest_buffer,
const GeglRectangle *dest_rect,
gdouble exposure,
GimpDodgeBurnType type,
GimpTransferMode mode);
void gimp_gegl_dodgeburn (GeglBuffer *src_buffer,
const GeglRectangle *src_rect,
GeglBuffer *dest_buffer,
const GeglRectangle *dest_rect,
gdouble exposure,
GimpDodgeBurnType type,
GimpTransferMode mode);
void gimp_gegl_smudge_blend (GeglBuffer *top_buffer,
const GeglRectangle *top_rect,
GeglBuffer *bottom_buffer,
const GeglRectangle *bottom_rect,
GeglBuffer *dest_buffer,
const GeglRectangle *dest_rect,
guchar blend);
#endif /* __GIMP_GEGL_LOOPS_H__ */

View File

@ -23,13 +23,9 @@
#include "paint-types.h"
#include "base/pixel-region.h"
#include "paint-funcs/paint-funcs.h"
#include "gegl/gimp-gegl-loops.h"
#include "gegl/gimp-gegl-utils.h"
#include "core/gimp.h"
#include "core/gimpbrush.h"
#include "core/gimpdrawable.h"
#include "core/gimpdynamics.h"
@ -164,13 +160,12 @@ gimp_smudge_start (GimpPaintCore *paint_core,
GimpPaintOptions *paint_options,
const GimpCoords *coords)
{
GimpSmudge *smudge = GIMP_SMUDGE (paint_core);
GeglBuffer *paint_buffer;
gint paint_buffer_x;
gint paint_buffer_y;
GimpTempBuf *accum_temp;
gint accum_size;
gint x, y;
GimpSmudge *smudge = GIMP_SMUDGE (paint_core);
GeglBuffer *paint_buffer;
gint paint_buffer_x;
gint paint_buffer_y;
gint accum_size;
gint x, y;
if (gimp_drawable_is_indexed (drawable))
return FALSE;
@ -185,10 +180,10 @@ gimp_smudge_start (GimpPaintCore *paint_core,
gimp_smudge_accumulator_size (paint_options, &accum_size);
/* Allocate the accumulation buffer */
accum_temp = gimp_temp_buf_new (accum_size, accum_size,
gimp_drawable_get_format (drawable));
smudge->accum_buffer = gimp_temp_buf_create_buffer (accum_temp);
gimp_temp_buf_unref (accum_temp);
smudge->accum_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
accum_size,
accum_size),
gimp_drawable_get_format (drawable));
/* adjust the x and y coordinates to the upper left corner of the
* accumulator
@ -251,7 +246,8 @@ gimp_smudge_motion (GimpPaintCore *paint_core,
GeglBuffer *paint_buffer;
gint paint_buffer_x;
gint paint_buffer_y;
PixelRegion srcPR, tempPR;
gint paint_buffer_width;
gint paint_buffer_height;
gdouble fade_point;
gdouble opacity;
gdouble rate;
@ -284,16 +280,12 @@ gimp_smudge_motion (GimpPaintCore *paint_core,
if (! paint_buffer)
return;
paint_buffer_width = gegl_buffer_get_width (paint_buffer);
paint_buffer_height = gegl_buffer_get_height (paint_buffer);
/* Get the unclipped acumulator coordinates */
gimp_smudge_accumulator_coords (paint_core, coords, &x, &y);
/* srcPR will be the pixels under the current painthit from the drawable */
pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
paint_buffer_x,
paint_buffer_y,
gegl_buffer_get_width (paint_buffer),
gegl_buffer_get_height (paint_buffer), FALSE);
/* Enable dynamic rate */
rate_output = gimp_dynamics_get_output (dynamics,
GIMP_DYNAMICS_OUTPUT_RATE);
@ -305,14 +297,6 @@ gimp_smudge_motion (GimpPaintCore *paint_core,
rate = (options->rate / 100.0) * dynamic_rate;
/* The tempPR will be the built up buffer (for smudge) */
pixel_region_init_temp_buf (&tempPR,
gimp_gegl_buffer_get_temp_buf (smudge->accum_buffer),
paint_buffer_x - x,
paint_buffer_y - y,
gegl_buffer_get_width (paint_buffer),
gegl_buffer_get_height (paint_buffer));
/* Smudge uses the buffer Accum.
* For each successive painthit Accum is built like this
* Accum = rate*Accum + (1-rate)*I.
@ -321,13 +305,28 @@ gimp_smudge_motion (GimpPaintCore *paint_core,
* (Accum,1) (if no alpha),
*/
blend_region (&srcPR, &tempPR, &tempPR, ROUND (rate * 255.0));
gimp_gegl_smudge_blend (smudge->accum_buffer,
GEGL_RECTANGLE (paint_buffer_x - x,
paint_buffer_y - y,
paint_buffer_width,
paint_buffer_height),
gimp_drawable_get_buffer (drawable),
GEGL_RECTANGLE (paint_buffer_x,
paint_buffer_y,
paint_buffer_width,
paint_buffer_height),
smudge->accum_buffer,
GEGL_RECTANGLE (paint_buffer_x - x,
paint_buffer_y - y,
paint_buffer_width,
paint_buffer_height),
ROUND (rate * 255.0));
gegl_buffer_copy (smudge->accum_buffer,
GEGL_RECTANGLE (paint_buffer_x - x,
paint_buffer_y - y,
gegl_buffer_get_width (paint_buffer),
gegl_buffer_get_height (paint_buffer)),
paint_buffer_width,
paint_buffer_height),
paint_buffer,
GEGL_RECTANGLE (0, 0, 0, 0));