Commit 1b449533 authored by Michael Natterer's avatar Michael Natterer 😴

app: port bucket fill to GEGL

Add mask offset parameters to gimp_gegl_create_apply_opacity_node()
so it's possible to use a part of the mask only, bucket fill
uses that to avoid uneccessary work where the mask is empty.

Should use the same in gimp_drawable_stroke_scan_convert().
parent 1780cfc1
......@@ -27,12 +27,13 @@
#include "core-types.h"
#include "base/pixel-region.h"
#include "base/temp-buf.h"
#include "base/tile-manager.h"
#include "paint-funcs/paint-funcs.h"
#include "gegl/gimp-gegl-nodes.h"
#include "gegl/gimp-gegl-utils.h"
#include "gimp.h"
#include "gimp-apply-operation.h"
#include "gimpchannel.h"
#include "gimpchannel-combine.h"
#include "gimpcontext.h"
......@@ -138,14 +139,15 @@ gimp_drawable_bucket_fill_internal (GimpDrawable *drawable,
GimpPattern *pattern)
{
GimpImage *image;
TileManager *buf_tiles;
PixelRegion bufPR, maskPR;
GimpChannel *mask = NULL;
gint bytes;
GimpChannel *mask;
TileManager *tiles;
GeglBuffer *buffer;
GeglBuffer *mask_buffer;
GeglNode *apply_opacity;
PixelRegion bufPR;
gint x1, y1, x2, y2;
guchar col[MAX_CHANNELS];
TempBuf *pat_buf = NULL;
gboolean new_buf = FALSE;
gint mask_offset_x = 0;
gint mask_offset_y = 0;
gboolean selection;
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
......@@ -157,30 +159,11 @@ gimp_drawable_bucket_fill_internal (GimpDrawable *drawable,
image = gimp_item_get_image (GIMP_ITEM (drawable));
bytes = gimp_drawable_bytes (drawable);
selection = gimp_item_mask_bounds (GIMP_ITEM (drawable), &x1, &y1, &x2, &y2);
if ((x1 == x2) || (y1 == y2))
return;
if (fill_mode == GIMP_FG_BUCKET_FILL ||
fill_mode == GIMP_BG_BUCKET_FILL)
{
gimp_image_transform_rgb (image, gimp_drawable_type (drawable),
color, col);
}
else if (fill_mode == GIMP_PATTERN_BUCKET_FILL)
{
pat_buf = gimp_image_transform_temp_buf (image,
gimp_drawable_type (drawable),
pattern->mask, &new_buf);
}
else
{
g_warning ("%s: invalid fill_mode passed", G_STRFUNC);
return;
}
gimp_set_busy (image->gimp);
/* Do a seed bucket fill...To do this, calculate a new
......@@ -209,16 +192,16 @@ gimp_drawable_bucket_fill_internal (GimpDrawable *drawable,
-off_x, -off_y);
}
mask_buffer = gimp_drawable_get_read_buffer (GIMP_DRAWABLE (mask));
gimp_channel_bounds (mask, &x1, &y1, &x2, &y2);
/* make sure we handle the mask correctly if it was sample-merged */
if (sample_merged)
{
GimpItem *item;
GimpItem *item = GIMP_ITEM (drawable);
gint off_x, off_y;
item = GIMP_ITEM (drawable);
/* Limit the channel bounds to the drawable's extents */
gimp_item_get_offset (item, &off_x, &off_y);
......@@ -227,11 +210,10 @@ gimp_drawable_bucket_fill_internal (GimpDrawable *drawable,
x2 = CLAMP (x2, off_x, (off_x + gimp_item_get_width (item)));
y2 = CLAMP (y2, off_y, (off_y + gimp_item_get_height (item)));
pixel_region_init (&maskPR,
gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
x1, y1, (x2 - x1), (y2 - y1), TRUE);
mask_offset_x = x1;
mask_offset_y = y1;
/* translate mask bounds to drawable coords */
/* translate mask bounds to drawable coords */
x1 -= off_x;
y1 -= off_y;
x2 -= off_x;
......@@ -239,48 +221,64 @@ gimp_drawable_bucket_fill_internal (GimpDrawable *drawable,
}
else
{
pixel_region_init (&maskPR,
gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
x1, y1, (x2 - x1), (y2 - y1), TRUE);
mask_offset_x = x1;
mask_offset_y = y1;
}
/* if the image doesn't have an alpha channel, make sure that
* the buf_tiles have. We need the alpha channel to fill with
* the region calculated above
*/
if (! gimp_drawable_has_alpha (drawable))
bytes++;
buf_tiles = tile_manager_new ((x2 - x1), (y2 - y1), bytes);
pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE);
tiles = tile_manager_new ((x2 - x1), (y2 - y1),
gimp_drawable_bytes_with_alpha (drawable));
buffer = gimp_tile_manager_create_buffer (tiles,
gimp_drawable_get_format_with_alpha (drawable),
TRUE);
switch (fill_mode)
{
case GIMP_FG_BUCKET_FILL:
case GIMP_BG_BUCKET_FILL:
color_region_mask (&bufPR, &maskPR, col);
{
GeglColor *gegl_color = gegl_color_new (NULL);
gimp_gegl_color_set_rgba (gegl_color, color);
gegl_buffer_set_color (buffer, NULL, gegl_color);
g_object_unref (gegl_color);
}
break;
case GIMP_PATTERN_BUCKET_FILL:
pattern_region (&bufPR, &maskPR, pat_buf, x1, y1);
{
GeglBuffer *pattern_buffer = gimp_pattern_create_buffer (pattern);
gegl_buffer_set_pattern (buffer, NULL, pattern_buffer, -x1, -y1);
g_object_unref (pattern_buffer);
}
break;
}
apply_opacity = gimp_gegl_create_apply_opacity_node (mask_buffer, 1.0,
mask_offset_x,
mask_offset_y);
gimp_apply_operation (buffer, NULL, NULL,
apply_opacity, 1.0,
buffer, NULL);
g_object_unref (apply_opacity);
g_object_unref (buffer);
g_object_unref (mask);
/* Apply it to the image */
pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), FALSE);
pixel_region_init (&bufPR, tiles, 0, 0, (x2 - x1), (y2 - y1), FALSE);
gimp_drawable_apply_region (drawable, &bufPR,
TRUE, C_("undo-type", "Bucket Fill"),
opacity, paint_mode,
NULL, NULL, x1, y1);
tile_manager_unref (buf_tiles);
gimp_drawable_update (drawable, x1, y1, x2 - x1, y2 - y1);
/* free the mask */
g_object_unref (mask);
tile_manager_unref (tiles);
if (new_buf)
temp_buf_free (pat_buf);
gimp_drawable_update (drawable, x1, y1, x2 - x1, y2 - y1);
gimp_unset_busy (image->gimp);
}
......@@ -390,10 +390,11 @@ gimp_drawable_stroke_scan_convert (GimpDrawable *drawable,
break;
}
apply_opacity = gimp_gegl_create_apply_opacity_node (mask_buffer, 1.0);
apply_opacity = gimp_gegl_create_apply_opacity_node (mask_buffer, 1.0,
0, 0);
gimp_apply_operation (base_buffer, NULL, NULL,
apply_opacity, TRUE,
apply_opacity, 1.0,
base_buffer, NULL);
g_object_unref (apply_opacity);
......
......@@ -1601,7 +1601,8 @@ gimp_layer_apply_mask (GimpLayer *layer,
mask_buffer = gimp_drawable_get_read_buffer (GIMP_DRAWABLE (mask));
dest_buffer = gimp_drawable_get_write_buffer (GIMP_DRAWABLE (layer));
apply_opacity = gimp_gegl_create_apply_opacity_node (mask_buffer, 1.0);
apply_opacity = gimp_gegl_create_apply_opacity_node (mask_buffer, 1.0,
0, 0);
gimp_drawable_apply_operation_to_buffer (GIMP_DRAWABLE (layer), NULL, NULL,
apply_opacity, TRUE, dest_buffer);
......
......@@ -70,7 +70,10 @@ gimp_gegl_create_flatten_node (const GimpRGB *background)
GeglNode *
gimp_gegl_create_apply_opacity_node (GeglBuffer *mask,
gdouble opacity)
gdouble opacity,
/* offsets *into* the mask */
gint mask_offset_x,
gint mask_offset_y)
{
GeglNode *node;
GeglNode *input;
......@@ -96,8 +99,26 @@ gimp_gegl_create_apply_opacity_node (GeglBuffer *mask,
gegl_node_connect_to (input, "output",
opacity_node, "input");
gegl_node_connect_to (mask_source, "output",
opacity_node, "aux");
if (mask_offset_x != 0 || mask_offset_y != 0)
{
GeglNode *translate = gegl_node_new_child (node,
"operation", "gegl:translate",
"x", (gdouble) -mask_offset_x,
"y", (gdouble) -mask_offset_y,
NULL);
gegl_node_connect_to (mask_source, "output",
translate, "input");
gegl_node_connect_to (translate, "output",
opacity_node, "aux");
}
else
{
gegl_node_connect_to (mask_source, "output",
opacity_node, "aux");
}
gegl_node_connect_to (opacity_node, "output",
output, "input");
......
......@@ -24,7 +24,10 @@
GeglNode * gimp_gegl_create_flatten_node (const GimpRGB *background);
GeglNode * gimp_gegl_create_apply_opacity_node (GeglBuffer *mask,
gdouble opacity);
gdouble opacity,
/* offsets *into* the mask */
gint mask_offset_x,
gint mask_offset_y);
#endif /* __GIMP_GEGL_NODES_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment