app: add gimp_gegl_replace() as replacement for combine_regions_replace()
and use it in gimp_drawable_real_replace_buffer(). The new GEGL loop is a stupid 1:1 copy of legacy and needs improvement.
This commit is contained in:
@ -268,50 +268,10 @@ gimp_drawable_real_replace_buffer (GimpDrawable *drawable,
|
|||||||
GimpImage *image = gimp_item_get_image (item);
|
GimpImage *image = gimp_item_get_image (item);
|
||||||
GimpChannel *mask = gimp_image_get_mask (image);
|
GimpChannel *mask = gimp_image_get_mask (image);
|
||||||
GeglBuffer *drawable_buffer;
|
GeglBuffer *drawable_buffer;
|
||||||
GimpTempBuf *temp_buf;
|
|
||||||
PixelRegion src2PR;
|
|
||||||
PixelRegion maskPR;
|
|
||||||
gint x, y, width, height;
|
gint x, y, width, height;
|
||||||
gint offset_x, offset_y;
|
gint offset_x, offset_y;
|
||||||
PixelRegion src1PR, destPR;
|
|
||||||
gboolean active_components[MAX_CHANNELS];
|
gboolean active_components[MAX_CHANNELS];
|
||||||
|
|
||||||
temp_buf = gimp_gegl_buffer_get_temp_buf (buffer);
|
|
||||||
|
|
||||||
if (temp_buf)
|
|
||||||
{
|
|
||||||
pixel_region_init_temp_buf (&src2PR, temp_buf,
|
|
||||||
buffer_region->x, buffer_region->y,
|
|
||||||
buffer_region->width, buffer_region->height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pixel_region_init (&src2PR, gimp_gegl_buffer_get_tiles (buffer),
|
|
||||||
buffer_region->x, buffer_region->y,
|
|
||||||
buffer_region->width, buffer_region->height,
|
|
||||||
FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
temp_buf = gimp_gegl_buffer_get_temp_buf (mask_buffer);
|
|
||||||
|
|
||||||
if (temp_buf)
|
|
||||||
{
|
|
||||||
pixel_region_init_temp_buf (&maskPR, temp_buf,
|
|
||||||
mask_buffer_region->x,
|
|
||||||
mask_buffer_region->y,
|
|
||||||
mask_buffer_region->width,
|
|
||||||
mask_buffer_region->height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pixel_region_init (&maskPR, gimp_gegl_buffer_get_tiles (mask_buffer),
|
|
||||||
mask_buffer_region->x,
|
|
||||||
mask_buffer_region->y,
|
|
||||||
mask_buffer_region->width,
|
|
||||||
mask_buffer_region->height,
|
|
||||||
FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* don't apply the mask to itself and don't apply an empty mask */
|
/* don't apply the mask to itself and don't apply an empty mask */
|
||||||
if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
|
if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
|
||||||
mask = NULL;
|
mask = NULL;
|
||||||
@ -323,7 +283,8 @@ gimp_drawable_real_replace_buffer (GimpDrawable *drawable,
|
|||||||
gimp_item_get_offset (item, &offset_x, &offset_y);
|
gimp_item_get_offset (item, &offset_x, &offset_y);
|
||||||
|
|
||||||
/* make sure the image application coordinates are within drawable bounds */
|
/* make sure the image application coordinates are within drawable bounds */
|
||||||
gimp_rectangle_intersect (dest_x, dest_y, src2PR.w, src2PR.h,
|
gimp_rectangle_intersect (dest_x, dest_y,
|
||||||
|
buffer_region->width, buffer_region->height,
|
||||||
0, 0,
|
0, 0,
|
||||||
gimp_item_get_width (item),
|
gimp_item_get_width (item),
|
||||||
gimp_item_get_height (item),
|
gimp_item_get_height (item),
|
||||||
@ -351,20 +312,8 @@ gimp_drawable_real_replace_buffer (GimpDrawable *drawable,
|
|||||||
|
|
||||||
drawable_buffer = gimp_drawable_get_buffer (drawable);
|
drawable_buffer = gimp_drawable_get_buffer (drawable);
|
||||||
|
|
||||||
/* configure the pixel regions */
|
|
||||||
pixel_region_init (&src1PR, gimp_gegl_buffer_get_tiles (drawable_buffer),
|
|
||||||
x, y, width, height,
|
|
||||||
FALSE);
|
|
||||||
pixel_region_init (&destPR, gimp_gegl_buffer_get_tiles (drawable_buffer),
|
|
||||||
x, y, width, height,
|
|
||||||
TRUE);
|
|
||||||
pixel_region_resize (&src2PR,
|
|
||||||
src2PR.x + (x - dest_x), src2PR.y + (y - dest_y),
|
|
||||||
width, height);
|
|
||||||
|
|
||||||
if (mask)
|
if (mask)
|
||||||
{
|
{
|
||||||
PixelRegion tempPR;
|
|
||||||
GimpTempBuf *temp_buf;
|
GimpTempBuf *temp_buf;
|
||||||
GeglBuffer *src_buffer;
|
GeglBuffer *src_buffer;
|
||||||
GeglBuffer *dest_buffer;
|
GeglBuffer *dest_buffer;
|
||||||
@ -386,19 +335,30 @@ gimp_drawable_real_replace_buffer (GimpDrawable *drawable,
|
|||||||
dest_buffer, GEGL_RECTANGLE (0, 0, width, height),
|
dest_buffer, GEGL_RECTANGLE (0, 0, width, height),
|
||||||
1.0);
|
1.0);
|
||||||
|
|
||||||
g_object_unref (dest_buffer);
|
gimp_gegl_replace (buffer,
|
||||||
|
buffer_region,
|
||||||
pixel_region_init_temp_buf (&tempPR, temp_buf, 0, 0, width, height);
|
drawable_buffer,
|
||||||
|
GEGL_RECTANGLE (x, y, width, height),
|
||||||
combine_regions_replace (&src1PR, &src2PR, &destPR, &tempPR,
|
dest_buffer,
|
||||||
|
GEGL_RECTANGLE (0, 0, width, height),
|
||||||
|
drawable_buffer,
|
||||||
|
GEGL_RECTANGLE (x, y, width, height),
|
||||||
opacity * 255.999,
|
opacity * 255.999,
|
||||||
active_components);
|
active_components);
|
||||||
|
|
||||||
|
g_object_unref (dest_buffer);
|
||||||
gimp_temp_buf_unref (temp_buf);
|
gimp_temp_buf_unref (temp_buf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
combine_regions_replace (&src1PR, &src2PR, &destPR, &maskPR,
|
gimp_gegl_replace (buffer,
|
||||||
|
buffer_region,
|
||||||
|
drawable_buffer,
|
||||||
|
GEGL_RECTANGLE (x, y, width, height),
|
||||||
|
mask_buffer,
|
||||||
|
mask_buffer_region,
|
||||||
|
drawable_buffer,
|
||||||
|
GEGL_RECTANGLE (x, y, width, height),
|
||||||
opacity * 255.999,
|
opacity * 255.999,
|
||||||
active_components);
|
active_components);
|
||||||
}
|
}
|
||||||
|
@ -470,3 +470,108 @@ gimp_gegl_combine_mask (GeglBuffer *mask_buffer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_gegl_replace (GeglBuffer *top_buffer,
|
||||||
|
const GeglRectangle *top_rect,
|
||||||
|
GeglBuffer *bottom_buffer,
|
||||||
|
const GeglRectangle *bottom_rect,
|
||||||
|
GeglBuffer *mask_buffer,
|
||||||
|
const GeglRectangle *mask_rect,
|
||||||
|
GeglBuffer *dest_buffer,
|
||||||
|
const GeglRectangle *dest_rect,
|
||||||
|
guchar opacity,
|
||||||
|
const gboolean *affect)
|
||||||
|
{
|
||||||
|
GeglBufferIterator *iter;
|
||||||
|
const gint alpha = 4 - 1;
|
||||||
|
const gdouble norm_opacity = opacity * (1.0 / 65536.0);
|
||||||
|
|
||||||
|
iter = gegl_buffer_iterator_new (top_buffer, top_rect, 0,
|
||||||
|
babl_format ("R'G'B'A u8"),
|
||||||
|
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
|
||||||
|
|
||||||
|
gegl_buffer_iterator_add (iter, bottom_buffer, bottom_rect, 0,
|
||||||
|
babl_format ("R'G'B'A u8"),
|
||||||
|
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
|
||||||
|
|
||||||
|
gegl_buffer_iterator_add (iter, mask_buffer, mask_rect, 0,
|
||||||
|
babl_format ("Y u8"),
|
||||||
|
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
|
||||||
|
|
||||||
|
gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
|
||||||
|
babl_format ("R'G'B'A u8"),
|
||||||
|
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
|
||||||
|
|
||||||
|
while (gegl_buffer_iterator_next (iter))
|
||||||
|
{
|
||||||
|
const guchar *top = iter->data[0];
|
||||||
|
const guchar *bottom = iter->data[1];
|
||||||
|
const guchar *mask = iter->data[2];
|
||||||
|
guchar *dest = iter->data[3];
|
||||||
|
|
||||||
|
while (iter->length--)
|
||||||
|
{
|
||||||
|
guint b;
|
||||||
|
gdouble mask_val = mask[0] * norm_opacity;
|
||||||
|
|
||||||
|
/* calculate new alpha first. */
|
||||||
|
gint s1_a = bottom[alpha];
|
||||||
|
gint s2_a = top[alpha];
|
||||||
|
gdouble a_val = s1_a + mask_val * (s2_a - s1_a);
|
||||||
|
|
||||||
|
if (a_val == 0)
|
||||||
|
{
|
||||||
|
/* In any case, write out versions of the blending
|
||||||
|
* function that result when combinations of s1_a, s2_a,
|
||||||
|
* and mask_val --> 0 (or mask_val -->1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 1: s1_a, s2_a, AND mask_val all approach 0+: */
|
||||||
|
/* 2: s1_a AND s2_a both approach 0+, regardless of mask_val: */
|
||||||
|
if (s1_a + s2_a == 0.0)
|
||||||
|
{
|
||||||
|
for (b = 0; b < alpha; b++)
|
||||||
|
{
|
||||||
|
gint new_val = 0.5 + (gdouble) bottom[b] +
|
||||||
|
mask_val * ((gdouble) top[b] - (gdouble) bottom[b]);
|
||||||
|
|
||||||
|
dest[b] = affect[b] ? MIN (new_val, 255) : bottom[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3: mask_val AND s1_a both approach 0+, regardless of s2_a */
|
||||||
|
else if (s1_a + mask_val == 0.0)
|
||||||
|
{
|
||||||
|
for (b = 0; b < alpha; b++)
|
||||||
|
dest[b] = bottom[b];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4: mask_val -->1 AND s2_a -->0, regardless of s1_a */
|
||||||
|
else if (1.0 - mask_val + s2_a == 0.0)
|
||||||
|
{
|
||||||
|
for (b = 0; b < alpha; b++)
|
||||||
|
dest[b] = affect[b] ? top[b] : bottom[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gdouble a_recip = 1.0 / a_val;
|
||||||
|
/* possible optimization: fold a_recip into s1_a and s2_a */
|
||||||
|
for (b = 0; b < alpha; b++)
|
||||||
|
{
|
||||||
|
gint new_val = 0.5 + a_recip * (bottom[b] * s1_a + mask_val *
|
||||||
|
(top[b] * s2_a - bottom[b] * s1_a));
|
||||||
|
dest[b] = affect[b] ? MIN (new_val, 255) : bottom[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest[alpha] = affect[alpha] ? a_val + 0.5 : s1_a;
|
||||||
|
|
||||||
|
top += 4;
|
||||||
|
bottom += 4;
|
||||||
|
mask += 1;
|
||||||
|
dest += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -64,5 +64,16 @@ void gimp_gegl_combine_mask (GeglBuffer *mask_buffer,
|
|||||||
gdouble opacity,
|
gdouble opacity,
|
||||||
gboolean stipple);
|
gboolean stipple);
|
||||||
|
|
||||||
|
void gimp_gegl_replace (GeglBuffer *top_buffer,
|
||||||
|
const GeglRectangle *top_rect,
|
||||||
|
GeglBuffer *bottom_buffer,
|
||||||
|
const GeglRectangle *bottom_rect,
|
||||||
|
GeglBuffer *mask_buffer,
|
||||||
|
const GeglRectangle *mask_rect,
|
||||||
|
GeglBuffer *dest_buffer,
|
||||||
|
const GeglRectangle *dest_rect,
|
||||||
|
guchar opacity,
|
||||||
|
const gboolean *affect);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GIMP_GEGL_LOOPS_H__ */
|
#endif /* __GIMP_GEGL_LOOPS_H__ */
|
||||||
|
Reference in New Issue
Block a user