Faster paintcore

Directly access the brush and paint buffers rather than using
GEGL iterators.

Replicate the relevant parts of GimpApplicator using direct
access.
This commit is contained in:
Daniel Sabo
2013-05-21 04:03:28 -07:00
parent 413a516f8e
commit cd91144f9e
7 changed files with 655 additions and 116 deletions

View File

@ -55,6 +55,8 @@ libapppaint_a_sources = \
gimpinkundo.h \ gimpinkundo.h \
gimppaintcore.c \ gimppaintcore.c \
gimppaintcore.h \ gimppaintcore.h \
gimppaintcore-loops.c \
gimppaintcore-loops.h \
gimppaintcore-stroke.c \ gimppaintcore-stroke.c \
gimppaintcore-stroke.h \ gimppaintcore-stroke.h \
gimppaintcoreundo.c \ gimppaintcoreundo.c \

View File

@ -822,10 +822,17 @@ gimp_brush_core_get_paint_buffer (GimpPaintCore *paint_core,
if ((x2 - x1) && (y2 - y1)) if ((x2 - x1) && (y2 - y1))
{ {
GimpTempBuf *temp_buf; GimpTempBuf *temp_buf;
const Babl *format;
if (gimp_drawable_get_linear (drawable))
format = babl_format ("RGBA float");
else
format = babl_format ("R'G'B'A float");
if (paint_core->paint_buffer && if (paint_core->paint_buffer &&
gegl_buffer_get_width (paint_core->paint_buffer) == (x2 - x1) && gegl_buffer_get_width (paint_core->paint_buffer) == (x2 - x1) &&
gegl_buffer_get_height (paint_core->paint_buffer) == (y2 - y1)) gegl_buffer_get_height (paint_core->paint_buffer) == (y2 - y1) &&
gegl_buffer_get_format (paint_core->paint_buffer) == format )
{ {
*paint_buffer_x = x1; *paint_buffer_x = x1;
*paint_buffer_y = y1; *paint_buffer_y = y1;
@ -834,7 +841,7 @@ gimp_brush_core_get_paint_buffer (GimpPaintCore *paint_core,
} }
temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1), temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1),
babl_format ("RGBA float")); format);
*paint_buffer_x = x1; *paint_buffer_x = x1;
*paint_buffer_y = y1; *paint_buffer_y = y1;
@ -939,7 +946,6 @@ gimp_brush_core_paste_canvas (GimpBrushCore *core,
if (brush_mask) if (brush_mask)
{ {
GimpPaintCore *paint_core = GIMP_PAINT_CORE (core); GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
GeglBuffer *paint_mask;
gint x; gint x;
gint y; gint y;
gint off_x; gint off_x;
@ -951,18 +957,12 @@ gimp_brush_core_paste_canvas (GimpBrushCore *core,
off_x = (x < 0) ? -x : 0; off_x = (x < 0) ? -x : 0;
off_y = (y < 0) ? -y : 0; off_y = (y < 0) ? -y : 0;
paint_mask = gimp_temp_buf_create_buffer ((GimpTempBuf *) brush_mask); gimp_paint_core_paste (paint_core, brush_mask,
off_x, off_y,
gimp_paint_core_paste (paint_core, paint_mask,
GEGL_RECTANGLE (off_x, off_y,
gegl_buffer_get_width (paint_core->paint_buffer),
gegl_buffer_get_height (paint_core->paint_buffer)),
drawable, drawable,
brush_opacity, brush_opacity,
image_opacity, paint_mode, image_opacity, paint_mode,
mode); mode);
g_object_unref (paint_mask);
} }
} }
@ -989,7 +989,6 @@ gimp_brush_core_replace_canvas (GimpBrushCore *core,
if (brush_mask) if (brush_mask)
{ {
GimpPaintCore *paint_core = GIMP_PAINT_CORE (core); GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
GeglBuffer *paint_mask;
gint x; gint x;
gint y; gint y;
gint off_x; gint off_x;
@ -1001,18 +1000,12 @@ gimp_brush_core_replace_canvas (GimpBrushCore *core,
off_x = (x < 0) ? -x : 0; off_x = (x < 0) ? -x : 0;
off_y = (y < 0) ? -y : 0; off_y = (y < 0) ? -y : 0;
paint_mask = gimp_temp_buf_create_buffer ((GimpTempBuf *) brush_mask); gimp_paint_core_replace (paint_core, brush_mask,
off_x, off_y,
gimp_paint_core_replace (paint_core, paint_mask,
GEGL_RECTANGLE (off_x, off_y,
gegl_buffer_get_width (paint_core->paint_buffer),
gegl_buffer_get_height (paint_core->paint_buffer)),
drawable, drawable,
brush_opacity, brush_opacity,
image_opacity, image_opacity,
mode); mode);
g_object_unref (paint_mask);
} }
} }

View File

@ -220,9 +220,15 @@ gimp_ink_get_paint_buffer (GimpPaintCore *paint_core,
if ((x2 - x1) && (y2 - y1)) if ((x2 - x1) && (y2 - y1))
{ {
GimpTempBuf *temp_buf; GimpTempBuf *temp_buf;
const Babl *format;
if (gimp_drawable_get_linear (drawable))
format = babl_format ("RGBA float");
else
format = babl_format ("R'G'B'A float");
temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1), temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1),
babl_format ("RGBA float")); format);
*paint_buffer_x = x1; *paint_buffer_x = x1;
*paint_buffer_y = y1; *paint_buffer_y = y1;
@ -332,11 +338,9 @@ gimp_ink_motion (GimpPaintCore *paint_core,
/* draw the paint_area using the just rendered canvas_buffer as mask */ /* draw the paint_area using the just rendered canvas_buffer as mask */
gimp_paint_core_paste (paint_core, gimp_paint_core_paste (paint_core,
paint_core->canvas_buffer, NULL,
GEGL_RECTANGLE (paint_core->paint_buffer_x, paint_core->paint_buffer_x,
paint_core->paint_buffer_y, paint_core->paint_buffer_y,
gegl_buffer_get_width (paint_core->paint_buffer),
gegl_buffer_get_height (paint_core->paint_buffer)),
drawable, drawable,
GIMP_OPACITY_OPAQUE, GIMP_OPACITY_OPAQUE,
gimp_context_get_opacity (context), gimp_context_get_opacity (context),

View File

@ -0,0 +1,415 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 2013 Daniel Sabo
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include "paint-types.h"
#include "core/gimptempbuf.h"
#include "gimppaintcore-loops.h"
#include "operations/gimplayermodefunctions.h"
void
combine_paint_mask_to_canvas_mask (const GimpTempBuf *paint_mask,
gint mask_x_offset,
gint mask_y_offset,
GeglBuffer *canvas_buffer,
gint x_offset,
gint y_offset,
gfloat opacity,
gboolean stipple)
{
GeglRectangle roi;
GeglBufferIterator *iter;
const gint mask_stride = gimp_temp_buf_get_width (paint_mask);
const gint mask_start_offset = mask_y_offset * mask_stride + mask_x_offset;
const Babl *mask_format = gimp_temp_buf_get_format (paint_mask);
roi.x = x_offset;
roi.y = y_offset;
roi.width = gimp_temp_buf_get_width (paint_mask) - mask_x_offset;
roi.height = gimp_temp_buf_get_height (paint_mask) - mask_y_offset;
iter = gegl_buffer_iterator_new (canvas_buffer, &roi, 0,
babl_format ("Y float"),
GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);
if (stipple)
{
if (mask_format == babl_format ("Y u8"))
{
const guint8 *mask_data = (const guint8 *) gimp_temp_buf_get_data (paint_mask);
mask_data += mask_start_offset;
while (gegl_buffer_iterator_next (iter))
{
gfloat *out_pixel = (gfloat *)iter->data[0];
int iy, ix;
for (iy = 0; iy < iter->roi[0].height; iy++)
{
int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x;
const guint8 *mask_pixel = &mask_data[mask_offset];
for (ix = 0; ix < iter->roi[0].width; ix++)
{
out_pixel[0] += (1.0 - out_pixel[0]) * (*mask_pixel / 255.0f) * opacity;
mask_pixel += 1;
out_pixel += 1;
}
}
}
}
else if (mask_format == babl_format ("Y float"))
{
const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask);
mask_data += mask_start_offset;
while (gegl_buffer_iterator_next (iter))
{
gfloat *out_pixel = (gfloat *)iter->data[0];
int iy, ix;
for (iy = 0; iy < iter->roi[0].height; iy++)
{
int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x;
const gfloat *mask_pixel = &mask_data[mask_offset];
for (ix = 0; ix < iter->roi[0].width; ix++)
{
out_pixel[0] += (1.0 - out_pixel[0]) * (*mask_pixel) * opacity;
mask_pixel += 1;
out_pixel += 1;
}
}
}
}
else
{
g_warning("Mask format not supported: %s", babl_get_name (mask_format));
}
}
else
{
if (mask_format == babl_format ("Y u8"))
{
const guint8 *mask_data = (const guint8 *) gimp_temp_buf_get_data (paint_mask);
mask_data += mask_start_offset;
while (gegl_buffer_iterator_next (iter))
{
gfloat *out_pixel = (gfloat *)iter->data[0];
int iy, ix;
for (iy = 0; iy < iter->roi[0].height; iy++)
{
int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x;
const guint8 *mask_pixel = &mask_data[mask_offset];
for (ix = 0; ix < iter->roi[0].width; ix++)
{
if (opacity > out_pixel[0])
out_pixel[0] += (opacity - out_pixel[0]) * (*mask_pixel / 255.0f) * opacity;
mask_pixel += 1;
out_pixel += 1;
}
}
}
}
else if (mask_format == babl_format ("Y float"))
{
const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask);
mask_data += mask_start_offset;
while (gegl_buffer_iterator_next (iter))
{
gfloat *out_pixel = (gfloat *)iter->data[0];
int iy, ix;
for (iy = 0; iy < iter->roi[0].height; iy++)
{
int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x;
const gfloat *mask_pixel = &mask_data[mask_offset];
for (ix = 0; ix < iter->roi[0].width; ix++)
{
if (opacity > out_pixel[0])
out_pixel[0] += (opacity - out_pixel[0]) * (*mask_pixel) * opacity;
mask_pixel += 1;
out_pixel += 1;
}
}
}
}
else
{
g_warning("Mask format not supported: %s", babl_get_name (mask_format));
}
}
}
void
canvas_buffer_to_paint_buf_alpha (GimpTempBuf *paint_buf,
GeglBuffer *canvas_buffer,
gint x_offset,
gint y_offset)
{
/* Copy the canvas buffer in rect to the paint buffer's alpha channel */
GeglRectangle roi;
GeglBufferIterator *iter;
const guint paint_stride = gimp_temp_buf_get_width (paint_buf);
gfloat *paint_data = (gfloat *) gimp_temp_buf_get_data (paint_buf);
roi.x = x_offset;
roi.y = y_offset;
roi.width = gimp_temp_buf_get_width (paint_buf);
roi.height = gimp_temp_buf_get_height (paint_buf);
iter = gegl_buffer_iterator_new (canvas_buffer, &roi, 0,
babl_format ("Y float"),
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
while (gegl_buffer_iterator_next (iter))
{
gfloat *canvas_pixel = (gfloat *)iter->data[0];
int iy, ix;
for (iy = 0; iy < iter->roi[0].height; iy++)
{
int paint_offset = (iy + iter->roi[0].y - roi.y) * paint_stride + iter->roi[0].x - roi.x;
float *paint_pixel = &paint_data[paint_offset * 4];
for (ix = 0; ix < iter->roi[0].width; ix++)
{
paint_pixel[3] *= *canvas_pixel;
canvas_pixel += 1;
paint_pixel += 4;
}
}
}
}
void
paint_mask_to_paint_buffer (const GimpTempBuf *paint_mask,
gint mask_x_offset,
gint mask_y_offset,
GimpTempBuf *paint_buf,
gfloat paint_opacity)
{
gint width = gimp_temp_buf_get_width (paint_buf);
gint height = gimp_temp_buf_get_height (paint_buf);
const gint mask_stride = gimp_temp_buf_get_width (paint_mask);
const gint mask_start_offset = mask_y_offset * mask_stride + mask_x_offset;
const Babl *mask_format = gimp_temp_buf_get_format (paint_mask);
int iy, ix;
gfloat *paint_pixel = (gfloat *)gimp_temp_buf_get_data (paint_buf);
/* Validate that the paint buffer is withing the bounds of the paint mask */
g_return_if_fail (width <= gimp_temp_buf_get_width (paint_mask) - mask_x_offset);
g_return_if_fail (height <= gimp_temp_buf_get_height (paint_mask) - mask_y_offset);
if (mask_format == babl_format ("Y u8"))
{
const guint8 *mask_data = (const guint8 *) gimp_temp_buf_get_data (paint_mask);
mask_data += mask_start_offset;
for (iy = 0; iy < height; iy++)
{
int mask_offset = iy * mask_stride;
const guint8 *mask_pixel = &mask_data[mask_offset];
for (ix = 0; ix < width; ix++)
{
paint_pixel[3] *= (((gfloat)*mask_pixel) / 255.0f) * paint_opacity;
mask_pixel += 1;
paint_pixel += 4;
}
}
}
else if (mask_format == babl_format ("Y float"))
{
const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask);
mask_data += mask_start_offset;
for (iy = 0; iy < height; iy++)
{
int mask_offset = iy * mask_stride;
const gfloat *mask_pixel = &mask_data[mask_offset];
for (ix = 0; ix < width; ix++)
{
paint_pixel[3] *= (*mask_pixel) * paint_opacity;
mask_pixel += 1;
paint_pixel += 4;
}
}
}
}
void
do_layer_blend (GeglBuffer *src_buffer,
GeglBuffer *dst_buffer,
GimpTempBuf *paint_buf,
GeglBuffer *mask_buffer,
gfloat opacity,
gint x_offset,
gint y_offset,
gint mask_x_offset,
gint mask_y_offset,
gboolean linear_mode,
GimpLayerModeEffects paint_mode)
{
GeglRectangle roi;
GeglRectangle mask_roi;
GeglRectangle process_roi;
const Babl *iterator_format;
GeglBufferIterator *iter;
const guint paint_stride = gimp_temp_buf_get_width (paint_buf);
gfloat *paint_data = (gfloat *) gimp_temp_buf_get_data (paint_buf);
GimpLayerModeFunction apply_func = get_layer_mode_function (paint_mode);
if (linear_mode)
iterator_format = babl_format ("RGBA float");
else
iterator_format = babl_format ("R'G'B'A float");
roi.x = x_offset;
roi.y = y_offset;
roi.width = gimp_temp_buf_get_width (paint_buf);
roi.height = gimp_temp_buf_get_height (paint_buf);
mask_roi.x = roi.x + mask_x_offset;
mask_roi.y = roi.y + mask_y_offset;
mask_roi.width = roi.width;
mask_roi.height = roi.height;
g_return_if_fail (gimp_temp_buf_get_format (paint_buf) == iterator_format);
iter = gegl_buffer_iterator_new (dst_buffer, &roi, 0,
iterator_format,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
gegl_buffer_iterator_add (iter, src_buffer, &roi, 0,
iterator_format,
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
if (mask_buffer)
{
gegl_buffer_iterator_add (iter, mask_buffer, &mask_roi, 0,
babl_format ("Y float"),
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
}
while (gegl_buffer_iterator_next(iter))
{
gfloat *out_pixel = (gfloat *)iter->data[0];
gfloat *in_pixel = (gfloat *)iter->data[1];
gfloat *mask_pixel = NULL;
gfloat *paint_pixel = paint_data + ((iter->roi[0].y - roi.y) * paint_stride + iter->roi[0].x - roi.x) * 4;
int iy;
if (mask_buffer)
mask_pixel = (gfloat *)iter->data[2];
process_roi.x = iter->roi[0].x;
process_roi.width = iter->roi[0].width;
process_roi.height = 1;
for (iy = 0; iy < iter->roi[0].height; iy++)
{
process_roi.x = iter->roi[0].y + iy;
(*apply_func) (in_pixel,
paint_pixel,
mask_pixel,
out_pixel,
opacity,
iter->roi[0].width,
&process_roi,
0);
in_pixel += iter->roi[0].width * 4;
out_pixel += iter->roi[0].width * 4;
if (mask_buffer)
mask_pixel += iter->roi[0].width;
paint_pixel += paint_stride * 4;
}
}
}
void
mask_components_onto (GeglBuffer *src_buffer,
GeglBuffer *aux_buffer,
GeglBuffer *dst_buffer,
GeglRectangle *roi,
GimpComponentMask mask,
gboolean linear_mode)
{
GeglBufferIterator *iter;
const Babl *iterator_format;
if (linear_mode)
iterator_format = babl_format ("RGBA float");
else
iterator_format = babl_format ("R'G'B'A float");
iter = gegl_buffer_iterator_new (dst_buffer, roi, 0,
iterator_format,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
gegl_buffer_iterator_add (iter, src_buffer, roi, 0,
iterator_format,
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
gegl_buffer_iterator_add (iter, aux_buffer, roi, 0,
iterator_format,
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
while (gegl_buffer_iterator_next(iter))
{
gfloat *dest = (gfloat *)iter->data[0];
gfloat *src = (gfloat *)iter->data[1];
gfloat *aux = (gfloat *)iter->data[2];
glong samples = iter->length;
while (samples--)
{
dest[RED] = (mask & GIMP_COMPONENT_RED) ? aux[RED] : src[RED];
dest[GREEN] = (mask & GIMP_COMPONENT_GREEN) ? aux[GREEN] : src[GREEN];
dest[BLUE] = (mask & GIMP_COMPONENT_BLUE) ? aux[BLUE] : src[BLUE];
dest[ALPHA] = (mask & GIMP_COMPONENT_ALPHA) ? aux[ALPHA] : src[ALPHA];
src += 4;
aux += 4;
dest += 4;
}
}
}

View File

@ -0,0 +1,55 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 2013 Daniel Sabo
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
void combine_paint_mask_to_canvas_mask (const GimpTempBuf *paint_mask,
gint mask_x_offset,
gint mask_y_offset,
GeglBuffer *canvas_buffer,
gint x_offset,
gint y_offset,
gfloat opacity,
gboolean stipple);
void canvas_buffer_to_paint_buf_alpha (GimpTempBuf *paint_buf,
GeglBuffer *canvas_buffer,
gint x_offset,
gint y_offset);
void paint_mask_to_paint_buffer (const GimpTempBuf *paint_mask,
gint mask_x_offset,
gint mask_y_offset,
GimpTempBuf *paint_buf,
gfloat paint_opacity);
void do_layer_blend (GeglBuffer *src_buffer,
GeglBuffer *dst_buffer,
GimpTempBuf *paint_buf,
GeglBuffer *mask_buffer,
gfloat opacity,
gint x_offset,
gint y_offset,
gint mask_x_offset,
gint mask_y_offset,
gboolean linear_mode,
GimpLayerModeEffects paint_mode);
void mask_components_onto (GeglBuffer *src_buffer,
GeglBuffer *aux_buffer,
GeglBuffer *dst_buffer,
GeglRectangle *roi,
GimpComponentMask mask,
gboolean linear_mode);

View File

@ -1,5 +1,6 @@
/* GIMP - The GNU Image Manipulation Program /* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis * Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 2013 Daniel Sabo
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -26,10 +27,8 @@
#include "paint-types.h" #include "paint-types.h"
#include "gegl/gimp-gegl-loops.h"
#include "gegl/gimp-gegl-nodes.h" #include "gegl/gimp-gegl-nodes.h"
#include "gegl/gimp-gegl-utils.h" #include "gegl/gimp-gegl-utils.h"
#include "gegl/gimpapplicator.h"
#include "core/gimp.h" #include "core/gimp.h"
#include "core/gimp-utils.h" #include "core/gimp-utils.h"
@ -42,6 +41,7 @@
#include "gimppaintcore.h" #include "gimppaintcore.h"
#include "gimppaintcoreundo.h" #include "gimppaintcoreundo.h"
#include "gimppaintcore-loops.h"
#include "gimppaintoptions.h" #include "gimppaintoptions.h"
#include "gimpairbrush.h" #include "gimpairbrush.h"
@ -405,9 +405,6 @@ gimp_paint_core_start (GimpPaintCore *core,
if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask)) if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
mask = NULL; mask = NULL;
core->applicator = gimp_applicator_new (NULL,
gimp_drawable_get_linear (drawable));
if (mask) if (mask)
{ {
GeglBuffer *mask_buffer; GeglBuffer *mask_buffer;
@ -417,15 +414,42 @@ gimp_paint_core_start (GimpPaintCore *core,
mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
gimp_item_get_offset (item, &offset_x, &offset_y); gimp_item_get_offset (item, &offset_x, &offset_y);
gimp_applicator_set_mask_buffer (core->applicator, mask_buffer); g_object_ref (mask_buffer);
gimp_applicator_set_mask_offset (core->applicator, core->mask_buffer = mask_buffer;
-offset_x, -offset_y); core->mask_x_offset = -offset_x;
core->mask_y_offset = -offset_y;
}
else
{
core->mask_buffer = NULL;
} }
gimp_applicator_set_affect (core->applicator, core->linear_mode = gimp_drawable_get_linear (drawable);
gimp_drawable_get_active_mask (drawable));
gimp_applicator_set_dest_buffer (core->applicator, /* Allocate the scratch buffer if there's a component mask */
gimp_drawable_get_buffer (drawable)); if (gimp_drawable_get_active_mask (drawable) != GIMP_COMPONENT_ALL)
{
if (core->linear_mode)
{
core->comp_buffer =
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
gimp_item_get_width (item),
gimp_item_get_height (item)),
babl_format ("RGBA float"));
}
else
{
core->comp_buffer =
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
gimp_item_get_width (item),
gimp_item_get_height (item)),
babl_format ("R'G'B'A float"));
}
}
else
{
core->comp_buffer = NULL;
}
/* Freeze the drawable preview so that it isn't constantly updated. */ /* Freeze the drawable preview so that it isn't constantly updated. */
gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable)); gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));
@ -444,18 +468,24 @@ gimp_paint_core_finish (GimpPaintCore *core,
g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
if (core->applicator)
{
g_object_unref (core->applicator);
core->applicator = NULL;
}
if (core->stroke_buffer) if (core->stroke_buffer)
{ {
g_array_free (core->stroke_buffer, TRUE); g_array_free (core->stroke_buffer, TRUE);
core->stroke_buffer = NULL; core->stroke_buffer = NULL;
} }
if (core->mask_buffer)
{
g_object_unref (core->mask_buffer);
core->mask_buffer = NULL;
}
if (core->comp_buffer)
{
g_object_unref (core->comp_buffer);
core->comp_buffer = NULL;
}
image = gimp_item_get_image (GIMP_ITEM (drawable)); image = gimp_item_get_image (GIMP_ITEM (drawable));
/* Determine if any part of the image has been altered-- /* Determine if any part of the image has been altered--
@ -737,75 +767,94 @@ gimp_paint_core_get_orig_proj (GimpPaintCore *core)
void void
gimp_paint_core_paste (GimpPaintCore *core, gimp_paint_core_paste (GimpPaintCore *core,
GeglBuffer *paint_mask, const GimpTempBuf *paint_mask,
const GeglRectangle *paint_mask_rect, gint paint_mask_offset_x,
gint paint_mask_offset_y,
GimpDrawable *drawable, GimpDrawable *drawable,
gdouble paint_opacity, gdouble paint_opacity,
gdouble image_opacity, gdouble image_opacity,
GimpLayerModeEffects paint_mode, GimpLayerModeEffects paint_mode,
GimpPaintApplicationMode mode) GimpPaintApplicationMode mode)
{ {
gint width = gegl_buffer_get_width (core->paint_buffer); GimpTempBuf *paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer);
gint height = gegl_buffer_get_height (core->paint_buffer); GeglBuffer *dest_buffer;
GeglBuffer *src_buffer;
gint width = gimp_temp_buf_get_width (paint_buf);
gint height = gimp_temp_buf_get_height (paint_buf);
if (!paint_buf)
return;
if (core->comp_buffer)
dest_buffer = core->comp_buffer;
else
dest_buffer = gimp_drawable_get_buffer (drawable);
/* If the mode is CONSTANT:
* combine the canvas buf, the paint mask to the canvas buffer
*/
if (mode == GIMP_PAINT_CONSTANT) if (mode == GIMP_PAINT_CONSTANT)
{ {
/* Some tools (ink) paint the mask to paint_core->canvas_buffer /* This step is skipped by the ink tool, which writes directly to canvas_buffer */
* directly. Don't need to copy it in this case. if (paint_mask != NULL)
*/
if (paint_mask != core->canvas_buffer)
{ {
gimp_gegl_combine_mask_weird (paint_mask, paint_mask_rect, /* Mix paint mask and canvas_buffer */
core->canvas_buffer, combine_paint_mask_to_canvas_mask (paint_mask,
GEGL_RECTANGLE (core->paint_buffer_x, paint_mask_offset_x,
core->paint_buffer_y, paint_mask_offset_y,
width, height), core->canvas_buffer,
paint_opacity, core->paint_buffer_x,
GIMP_IS_AIRBRUSH (core)); core->paint_buffer_y,
paint_opacity,
GIMP_IS_AIRBRUSH (core));
} }
gimp_gegl_apply_mask (core->canvas_buffer, /* Write canvas_buffer to paint_buf */
GEGL_RECTANGLE (core->paint_buffer_x, canvas_buffer_to_paint_buf_alpha (paint_buf,
core->paint_buffer_y, core->canvas_buffer,
width, height), core->paint_buffer_x,
core->paint_buffer, core->paint_buffer_y);
GEGL_RECTANGLE (0, 0, width, height),
1.0);
gimp_applicator_set_src_buffer (core->applicator, /* undo buf -> paint_buf -> dest_buffer */
core->undo_buffer); src_buffer = core->undo_buffer;
} }
/* Otherwise:
* combine the canvas buf and the paint mask to the canvas buf
*/
else else
{ {
gimp_gegl_apply_mask (paint_mask, paint_mask_rect, g_return_if_fail (paint_mask);
core->paint_buffer,
GEGL_RECTANGLE (0, 0, width, height),
paint_opacity);
gimp_applicator_set_src_buffer (core->applicator, /* Write paint_mask to paint_buf, does not modify canvas_buffer */
gimp_drawable_get_buffer (drawable)); paint_mask_to_paint_buffer (paint_mask,
paint_mask_offset_x,
paint_mask_offset_y,
paint_buf,
paint_opacity);
/* dest_buffer -> paint_buf -> dest_buffer */
src_buffer = dest_buffer;
} }
gimp_applicator_set_apply_buffer (core->applicator, do_layer_blend (src_buffer,
core->paint_buffer); dest_buffer,
gimp_applicator_set_apply_offset (core->applicator, paint_buf,
core->paint_buffer_x, core->mask_buffer,
core->paint_buffer_y); image_opacity,
core->paint_buffer_x,
core->paint_buffer_y,
core->mask_x_offset,
core->mask_y_offset,
core->linear_mode,
paint_mode);
gimp_applicator_set_mode (core->applicator, if (core->comp_buffer)
image_opacity, paint_mode); {
mask_components_onto (src_buffer,
/* apply the paint area to the image */ core->comp_buffer,
gimp_applicator_blit (core->applicator, gimp_drawable_get_buffer (drawable),
GEGL_RECTANGLE (core->paint_buffer_x, GEGL_RECTANGLE(core->paint_buffer_x,
core->paint_buffer_y, core->paint_buffer_y,
width, height)); width,
height),
gimp_drawable_get_active_mask (drawable),
core->linear_mode);
}
/* Update the undo extents */ /* Update the undo extents */
core->x1 = MIN (core->x1, core->paint_buffer_x); core->x1 = MIN (core->x1, core->paint_buffer_x);
@ -830,19 +879,23 @@ gimp_paint_core_paste (GimpPaintCore *core,
*/ */
void void
gimp_paint_core_replace (GimpPaintCore *core, gimp_paint_core_replace (GimpPaintCore *core,
GeglBuffer *paint_mask, const GimpTempBuf *paint_mask,
const GeglRectangle *paint_mask_rect, gint paint_mask_offset_x,
gint paint_mask_offset_y,
GimpDrawable *drawable, GimpDrawable *drawable,
gdouble paint_opacity, gdouble paint_opacity,
gdouble image_opacity, gdouble image_opacity,
GimpPaintApplicationMode mode) GimpPaintApplicationMode mode)
{ {
GeglRectangle mask_rect; GeglRectangle mask_rect;
gint width, height; gint width, height;
GeglBuffer *paint_mask_buffer;
if (! gimp_drawable_has_alpha (drawable)) if (! gimp_drawable_has_alpha (drawable))
{ {
gimp_paint_core_paste (core, paint_mask, paint_mask_rect, gimp_paint_core_paste (core, paint_mask,
paint_mask_offset_x,
paint_mask_offset_y,
drawable, drawable,
paint_opacity, paint_opacity,
image_opacity, GIMP_NORMAL_MODE, image_opacity, GIMP_NORMAL_MODE,
@ -858,19 +911,22 @@ gimp_paint_core_replace (GimpPaintCore *core,
/* Some tools (ink) paint the mask to paint_core->canvas_buffer /* Some tools (ink) paint the mask to paint_core->canvas_buffer
* directly. Don't need to copy it in this case. * directly. Don't need to copy it in this case.
*/ */
paint_mask != core->canvas_buffer) (paint_mask != NULL))
{ {
/* combine the paint mask and the canvas buffer */ /* Mix paint mask and canvas_buffer */
gimp_gegl_combine_mask_weird (paint_mask, paint_mask_rect, combine_paint_mask_to_canvas_mask (paint_mask,
core->canvas_buffer, paint_mask_offset_x,
GEGL_RECTANGLE (core->paint_buffer_x, paint_mask_offset_y,
core->paint_buffer_y, core->canvas_buffer,
width, height), core->paint_buffer_x,
paint_opacity, core->paint_buffer_y,
GIMP_IS_AIRBRUSH (core)); paint_opacity,
GIMP_IS_AIRBRUSH (core));
/* initialize the maskPR from the canvas buffer */ /* initialize the maskPR from the canvas buffer */
paint_mask = core->canvas_buffer; paint_mask_buffer = core->canvas_buffer;
g_object_ref (paint_mask_buffer);
mask_rect = *GEGL_RECTANGLE (core->paint_buffer_x, mask_rect = *GEGL_RECTANGLE (core->paint_buffer_x,
core->paint_buffer_y, core->paint_buffer_y,
@ -878,7 +934,11 @@ gimp_paint_core_replace (GimpPaintCore *core,
} }
else else
{ {
mask_rect = *paint_mask_rect; paint_mask_buffer = gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);
mask_rect = *GEGL_RECTANGLE (paint_mask_offset_x,
paint_mask_offset_y,
width, height);
} }
/* apply the paint area to the image */ /* apply the paint area to the image */
@ -886,10 +946,12 @@ gimp_paint_core_replace (GimpPaintCore *core,
GEGL_RECTANGLE (0, 0, width, height), GEGL_RECTANGLE (0, 0, width, height),
FALSE, NULL, FALSE, NULL,
image_opacity, image_opacity,
paint_mask, &mask_rect, paint_mask_buffer, &mask_rect,
core->paint_buffer_x, core->paint_buffer_x,
core->paint_buffer_y); core->paint_buffer_y);
g_object_unref (paint_mask_buffer);
/* Update the undo extents */ /* Update the undo extents */
core->x1 = MIN (core->x1, core->paint_buffer_x); core->x1 = MIN (core->x1, core->paint_buffer_x);
core->y1 = MIN (core->y1, core->paint_buffer_y); core->y1 = MIN (core->y1, core->paint_buffer_y);

View File

@ -58,14 +58,18 @@ struct _GimpPaintCore
GeglBuffer *undo_buffer; /* pixels which have been modified */ GeglBuffer *undo_buffer; /* pixels which have been modified */
GeglBuffer *saved_proj_buffer; /* proj tiles which have been modified */ GeglBuffer *saved_proj_buffer; /* proj tiles which have been modified */
GeglBuffer *canvas_buffer; /* the buffer to paint the mask to */ GeglBuffer *canvas_buffer; /* the buffer to paint the mask to */
GeglBuffer *comp_buffer; /* scratch buffer used when masking components */
gboolean linear_mode; /* if painting to a linear surface */
GeglBuffer *paint_buffer; /* the buffer to paint pixels to */ GeglBuffer *paint_buffer; /* the buffer to paint pixels to */
gint paint_buffer_x; gint paint_buffer_x;
gint paint_buffer_y; gint paint_buffer_y;
GArray *stroke_buffer; GeglBuffer *mask_buffer; /* the target drawable's mask */
gint mask_x_offset;
gint mask_y_offset;
GimpApplicator *applicator; GArray *stroke_buffer;
}; };
struct _GimpPaintCoreClass struct _GimpPaintCoreClass
@ -168,16 +172,20 @@ GeglBuffer * gimp_paint_core_get_orig_image (GimpPaintCore *core);
GeglBuffer * gimp_paint_core_get_orig_proj (GimpPaintCore *core); GeglBuffer * gimp_paint_core_get_orig_proj (GimpPaintCore *core);
void gimp_paint_core_paste (GimpPaintCore *core, void gimp_paint_core_paste (GimpPaintCore *core,
GeglBuffer *paint_mask, const GimpTempBuf *paint_mask,
const GeglRectangle *paint_mask_rect, gint paint_mask_offset_x,
gint paint_mask_offset_y,
GimpDrawable *drawable, GimpDrawable *drawable,
gdouble paint_opacity, gdouble paint_opacity,
gdouble image_opacity, gdouble image_opacity,
GimpLayerModeEffects paint_mode, GimpLayerModeEffects paint_mode,
GimpPaintApplicationMode mode); GimpPaintApplicationMode mode);
void gimp_paint_core_replace (GimpPaintCore *core, void gimp_paint_core_replace (GimpPaintCore *core,
GeglBuffer *paint_mask, const GimpTempBuf *paint_mask,
const GeglRectangle *paint_mask_rect, gint paint_mask_offset_x,
gint paint_mask_offset_y,
GimpDrawable *drawable, GimpDrawable *drawable,
gdouble paint_opacity, gdouble paint_opacity,
gdouble image_opacity, gdouble image_opacity,