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:
@ -55,6 +55,8 @@ libapppaint_a_sources = \
|
||||
gimpinkundo.h \
|
||||
gimppaintcore.c \
|
||||
gimppaintcore.h \
|
||||
gimppaintcore-loops.c \
|
||||
gimppaintcore-loops.h \
|
||||
gimppaintcore-stroke.c \
|
||||
gimppaintcore-stroke.h \
|
||||
gimppaintcoreundo.c \
|
||||
|
||||
@ -822,10 +822,17 @@ gimp_brush_core_get_paint_buffer (GimpPaintCore *paint_core,
|
||||
if ((x2 - x1) && (y2 - y1))
|
||||
{
|
||||
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 &&
|
||||
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_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),
|
||||
babl_format ("RGBA float"));
|
||||
format);
|
||||
|
||||
*paint_buffer_x = x1;
|
||||
*paint_buffer_y = y1;
|
||||
@ -939,7 +946,6 @@ gimp_brush_core_paste_canvas (GimpBrushCore *core,
|
||||
if (brush_mask)
|
||||
{
|
||||
GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
|
||||
GeglBuffer *paint_mask;
|
||||
gint x;
|
||||
gint y;
|
||||
gint off_x;
|
||||
@ -951,18 +957,12 @@ gimp_brush_core_paste_canvas (GimpBrushCore *core,
|
||||
off_x = (x < 0) ? -x : 0;
|
||||
off_y = (y < 0) ? -y : 0;
|
||||
|
||||
paint_mask = gimp_temp_buf_create_buffer ((GimpTempBuf *) brush_mask);
|
||||
|
||||
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)),
|
||||
gimp_paint_core_paste (paint_core, brush_mask,
|
||||
off_x, off_y,
|
||||
drawable,
|
||||
brush_opacity,
|
||||
image_opacity, paint_mode,
|
||||
mode);
|
||||
|
||||
g_object_unref (paint_mask);
|
||||
}
|
||||
}
|
||||
|
||||
@ -989,7 +989,6 @@ gimp_brush_core_replace_canvas (GimpBrushCore *core,
|
||||
if (brush_mask)
|
||||
{
|
||||
GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
|
||||
GeglBuffer *paint_mask;
|
||||
gint x;
|
||||
gint y;
|
||||
gint off_x;
|
||||
@ -1001,18 +1000,12 @@ gimp_brush_core_replace_canvas (GimpBrushCore *core,
|
||||
off_x = (x < 0) ? -x : 0;
|
||||
off_y = (y < 0) ? -y : 0;
|
||||
|
||||
paint_mask = gimp_temp_buf_create_buffer ((GimpTempBuf *) brush_mask);
|
||||
|
||||
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)),
|
||||
gimp_paint_core_replace (paint_core, brush_mask,
|
||||
off_x, off_y,
|
||||
drawable,
|
||||
brush_opacity,
|
||||
image_opacity,
|
||||
mode);
|
||||
|
||||
g_object_unref (paint_mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -220,9 +220,15 @@ gimp_ink_get_paint_buffer (GimpPaintCore *paint_core,
|
||||
if ((x2 - x1) && (y2 - y1))
|
||||
{
|
||||
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),
|
||||
babl_format ("RGBA float"));
|
||||
format);
|
||||
|
||||
*paint_buffer_x = x1;
|
||||
*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 */
|
||||
gimp_paint_core_paste (paint_core,
|
||||
paint_core->canvas_buffer,
|
||||
GEGL_RECTANGLE (paint_core->paint_buffer_x,
|
||||
paint_core->paint_buffer_y,
|
||||
gegl_buffer_get_width (paint_core->paint_buffer),
|
||||
gegl_buffer_get_height (paint_core->paint_buffer)),
|
||||
NULL,
|
||||
paint_core->paint_buffer_x,
|
||||
paint_core->paint_buffer_y,
|
||||
drawable,
|
||||
GIMP_OPACITY_OPAQUE,
|
||||
gimp_context_get_opacity (context),
|
||||
|
||||
415
app/paint/gimppaintcore-loops.c
Normal file
415
app/paint/gimppaintcore-loops.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
app/paint/gimppaintcore-loops.h
Normal file
55
app/paint/gimppaintcore-loops.h
Normal 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);
|
||||
@ -1,5 +1,6 @@
|
||||
/* GIMP - The GNU Image Manipulation Program
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -26,10 +27,8 @@
|
||||
|
||||
#include "paint-types.h"
|
||||
|
||||
#include "gegl/gimp-gegl-loops.h"
|
||||
#include "gegl/gimp-gegl-nodes.h"
|
||||
#include "gegl/gimp-gegl-utils.h"
|
||||
#include "gegl/gimpapplicator.h"
|
||||
|
||||
#include "core/gimp.h"
|
||||
#include "core/gimp-utils.h"
|
||||
@ -42,6 +41,7 @@
|
||||
|
||||
#include "gimppaintcore.h"
|
||||
#include "gimppaintcoreundo.h"
|
||||
#include "gimppaintcore-loops.h"
|
||||
#include "gimppaintoptions.h"
|
||||
|
||||
#include "gimpairbrush.h"
|
||||
@ -405,9 +405,6 @@ gimp_paint_core_start (GimpPaintCore *core,
|
||||
if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
|
||||
mask = NULL;
|
||||
|
||||
core->applicator = gimp_applicator_new (NULL,
|
||||
gimp_drawable_get_linear (drawable));
|
||||
|
||||
if (mask)
|
||||
{
|
||||
GeglBuffer *mask_buffer;
|
||||
@ -417,15 +414,42 @@ gimp_paint_core_start (GimpPaintCore *core,
|
||||
mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
|
||||
gimp_item_get_offset (item, &offset_x, &offset_y);
|
||||
|
||||
gimp_applicator_set_mask_buffer (core->applicator, mask_buffer);
|
||||
gimp_applicator_set_mask_offset (core->applicator,
|
||||
-offset_x, -offset_y);
|
||||
g_object_ref (mask_buffer);
|
||||
core->mask_buffer = mask_buffer;
|
||||
core->mask_x_offset = -offset_x;
|
||||
core->mask_y_offset = -offset_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
core->mask_buffer = NULL;
|
||||
}
|
||||
|
||||
gimp_applicator_set_affect (core->applicator,
|
||||
gimp_drawable_get_active_mask (drawable));
|
||||
gimp_applicator_set_dest_buffer (core->applicator,
|
||||
gimp_drawable_get_buffer (drawable));
|
||||
core->linear_mode = gimp_drawable_get_linear (drawable);
|
||||
|
||||
/* Allocate the scratch buffer if there's a component mask */
|
||||
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. */
|
||||
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_item_is_attached (GIMP_ITEM (drawable)));
|
||||
|
||||
if (core->applicator)
|
||||
{
|
||||
g_object_unref (core->applicator);
|
||||
core->applicator = NULL;
|
||||
}
|
||||
|
||||
if (core->stroke_buffer)
|
||||
{
|
||||
g_array_free (core->stroke_buffer, TRUE);
|
||||
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));
|
||||
|
||||
/* Determine if any part of the image has been altered--
|
||||
@ -737,75 +767,94 @@ gimp_paint_core_get_orig_proj (GimpPaintCore *core)
|
||||
|
||||
void
|
||||
gimp_paint_core_paste (GimpPaintCore *core,
|
||||
GeglBuffer *paint_mask,
|
||||
const GeglRectangle *paint_mask_rect,
|
||||
const GimpTempBuf *paint_mask,
|
||||
gint paint_mask_offset_x,
|
||||
gint paint_mask_offset_y,
|
||||
GimpDrawable *drawable,
|
||||
gdouble paint_opacity,
|
||||
gdouble image_opacity,
|
||||
GimpLayerModeEffects paint_mode,
|
||||
GimpPaintApplicationMode mode)
|
||||
{
|
||||
gint width = gegl_buffer_get_width (core->paint_buffer);
|
||||
gint height = gegl_buffer_get_height (core->paint_buffer);
|
||||
GimpTempBuf *paint_buf = gimp_gegl_buffer_get_temp_buf (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)
|
||||
{
|
||||
/* Some tools (ink) paint the mask to paint_core->canvas_buffer
|
||||
* directly. Don't need to copy it in this case.
|
||||
*/
|
||||
if (paint_mask != core->canvas_buffer)
|
||||
/* This step is skipped by the ink tool, which writes directly to canvas_buffer */
|
||||
if (paint_mask != NULL)
|
||||
{
|
||||
gimp_gegl_combine_mask_weird (paint_mask, paint_mask_rect,
|
||||
core->canvas_buffer,
|
||||
GEGL_RECTANGLE (core->paint_buffer_x,
|
||||
core->paint_buffer_y,
|
||||
width, height),
|
||||
paint_opacity,
|
||||
GIMP_IS_AIRBRUSH (core));
|
||||
/* Mix paint mask and canvas_buffer */
|
||||
combine_paint_mask_to_canvas_mask (paint_mask,
|
||||
paint_mask_offset_x,
|
||||
paint_mask_offset_y,
|
||||
core->canvas_buffer,
|
||||
core->paint_buffer_x,
|
||||
core->paint_buffer_y,
|
||||
paint_opacity,
|
||||
GIMP_IS_AIRBRUSH (core));
|
||||
}
|
||||
|
||||
gimp_gegl_apply_mask (core->canvas_buffer,
|
||||
GEGL_RECTANGLE (core->paint_buffer_x,
|
||||
core->paint_buffer_y,
|
||||
width, height),
|
||||
core->paint_buffer,
|
||||
GEGL_RECTANGLE (0, 0, width, height),
|
||||
1.0);
|
||||
/* Write canvas_buffer to paint_buf */
|
||||
canvas_buffer_to_paint_buf_alpha (paint_buf,
|
||||
core->canvas_buffer,
|
||||
core->paint_buffer_x,
|
||||
core->paint_buffer_y);
|
||||
|
||||
gimp_applicator_set_src_buffer (core->applicator,
|
||||
core->undo_buffer);
|
||||
/* undo buf -> paint_buf -> dest_buffer */
|
||||
src_buffer = core->undo_buffer;
|
||||
}
|
||||
/* Otherwise:
|
||||
* combine the canvas buf and the paint mask to the canvas buf
|
||||
*/
|
||||
else
|
||||
{
|
||||
gimp_gegl_apply_mask (paint_mask, paint_mask_rect,
|
||||
core->paint_buffer,
|
||||
GEGL_RECTANGLE (0, 0, width, height),
|
||||
paint_opacity);
|
||||
g_return_if_fail (paint_mask);
|
||||
|
||||
gimp_applicator_set_src_buffer (core->applicator,
|
||||
gimp_drawable_get_buffer (drawable));
|
||||
/* Write paint_mask to paint_buf, does not modify canvas_buffer */
|
||||
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,
|
||||
core->paint_buffer);
|
||||
gimp_applicator_set_apply_offset (core->applicator,
|
||||
core->paint_buffer_x,
|
||||
core->paint_buffer_y);
|
||||
do_layer_blend (src_buffer,
|
||||
dest_buffer,
|
||||
paint_buf,
|
||||
core->mask_buffer,
|
||||
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,
|
||||
image_opacity, paint_mode);
|
||||
|
||||
/* apply the paint area to the image */
|
||||
gimp_applicator_blit (core->applicator,
|
||||
GEGL_RECTANGLE (core->paint_buffer_x,
|
||||
core->paint_buffer_y,
|
||||
width, height));
|
||||
if (core->comp_buffer)
|
||||
{
|
||||
mask_components_onto (src_buffer,
|
||||
core->comp_buffer,
|
||||
gimp_drawable_get_buffer (drawable),
|
||||
GEGL_RECTANGLE(core->paint_buffer_x,
|
||||
core->paint_buffer_y,
|
||||
width,
|
||||
height),
|
||||
gimp_drawable_get_active_mask (drawable),
|
||||
core->linear_mode);
|
||||
}
|
||||
|
||||
/* Update the undo extents */
|
||||
core->x1 = MIN (core->x1, core->paint_buffer_x);
|
||||
@ -830,19 +879,23 @@ gimp_paint_core_paste (GimpPaintCore *core,
|
||||
*/
|
||||
void
|
||||
gimp_paint_core_replace (GimpPaintCore *core,
|
||||
GeglBuffer *paint_mask,
|
||||
const GeglRectangle *paint_mask_rect,
|
||||
const GimpTempBuf *paint_mask,
|
||||
gint paint_mask_offset_x,
|
||||
gint paint_mask_offset_y,
|
||||
GimpDrawable *drawable,
|
||||
gdouble paint_opacity,
|
||||
gdouble image_opacity,
|
||||
GimpPaintApplicationMode mode)
|
||||
{
|
||||
GeglRectangle mask_rect;
|
||||
gint width, height;
|
||||
GeglRectangle mask_rect;
|
||||
gint width, height;
|
||||
GeglBuffer *paint_mask_buffer;
|
||||
|
||||
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,
|
||||
paint_opacity,
|
||||
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
|
||||
* 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 */
|
||||
gimp_gegl_combine_mask_weird (paint_mask, paint_mask_rect,
|
||||
core->canvas_buffer,
|
||||
GEGL_RECTANGLE (core->paint_buffer_x,
|
||||
core->paint_buffer_y,
|
||||
width, height),
|
||||
paint_opacity,
|
||||
GIMP_IS_AIRBRUSH (core));
|
||||
/* Mix paint mask and canvas_buffer */
|
||||
combine_paint_mask_to_canvas_mask (paint_mask,
|
||||
paint_mask_offset_x,
|
||||
paint_mask_offset_y,
|
||||
core->canvas_buffer,
|
||||
core->paint_buffer_x,
|
||||
core->paint_buffer_y,
|
||||
paint_opacity,
|
||||
GIMP_IS_AIRBRUSH (core));
|
||||
|
||||
/* 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,
|
||||
core->paint_buffer_y,
|
||||
@ -878,7 +934,11 @@ gimp_paint_core_replace (GimpPaintCore *core,
|
||||
}
|
||||
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 */
|
||||
@ -886,10 +946,12 @@ gimp_paint_core_replace (GimpPaintCore *core,
|
||||
GEGL_RECTANGLE (0, 0, width, height),
|
||||
FALSE, NULL,
|
||||
image_opacity,
|
||||
paint_mask, &mask_rect,
|
||||
paint_mask_buffer, &mask_rect,
|
||||
core->paint_buffer_x,
|
||||
core->paint_buffer_y);
|
||||
|
||||
g_object_unref (paint_mask_buffer);
|
||||
|
||||
/* Update the undo extents */
|
||||
core->x1 = MIN (core->x1, core->paint_buffer_x);
|
||||
core->y1 = MIN (core->y1, core->paint_buffer_y);
|
||||
|
||||
@ -58,14 +58,18 @@ struct _GimpPaintCore
|
||||
GeglBuffer *undo_buffer; /* pixels 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 *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 */
|
||||
gint paint_buffer_x;
|
||||
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
|
||||
@ -168,16 +172,20 @@ GeglBuffer * gimp_paint_core_get_orig_image (GimpPaintCore *core);
|
||||
GeglBuffer * gimp_paint_core_get_orig_proj (GimpPaintCore *core);
|
||||
|
||||
void gimp_paint_core_paste (GimpPaintCore *core,
|
||||
GeglBuffer *paint_mask,
|
||||
const GeglRectangle *paint_mask_rect,
|
||||
const GimpTempBuf *paint_mask,
|
||||
gint paint_mask_offset_x,
|
||||
gint paint_mask_offset_y,
|
||||
GimpDrawable *drawable,
|
||||
gdouble paint_opacity,
|
||||
gdouble image_opacity,
|
||||
GimpLayerModeEffects paint_mode,
|
||||
GimpPaintApplicationMode mode);
|
||||
|
||||
|
||||
void gimp_paint_core_replace (GimpPaintCore *core,
|
||||
GeglBuffer *paint_mask,
|
||||
const GeglRectangle *paint_mask_rect,
|
||||
const GimpTempBuf *paint_mask,
|
||||
gint paint_mask_offset_x,
|
||||
gint paint_mask_offset_y,
|
||||
GimpDrawable *drawable,
|
||||
gdouble paint_opacity,
|
||||
gdouble image_opacity,
|
||||
|
||||
Reference in New Issue
Block a user