app: in gimppaintcore-loops, add {CANVAS_BUFFER,PAINT_MASK}_TO_COMP_MASK algorithms

In gimppaintcore-loops, add CANVAS_BUFFER_TO_COMP_MASK and
PAINT_MASK_TO_COMP_MASK paint algorithms, which copy the canvas
buffer and the paint mask, respectively, to the compositing mask.
When there is an image mask buffer, the algorithms additionally
combine the copied mask with the mask buffer.  When possible, the
algorithms use the canvas buffer/paint mask data directly as the
compositing mask data, instead of copying.

These algorithms are necessary in order to implement
gimp_paint_core_replace() in terms of
gimp_paint_core_loops_process(), which is done by the next commit.
This commit is contained in:
Ell 2019-02-12 06:11:31 -05:00
parent f9c072c328
commit 183a55613e
2 changed files with 389 additions and 5 deletions

View File

@ -942,7 +942,9 @@ struct CombinePaintMaskToCanvasBufferToPaintBufAlpha :
base_type::filter |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA;
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
using base_type::base_type;
@ -1042,7 +1044,8 @@ struct CombinePaintMaskToCanvasBuffer :
static constexpr guint filter =
base_type::filter |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA;
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
using base_type::base_type;
@ -1132,7 +1135,9 @@ struct CanvasBufferToPaintBufAlpha : CanvasBufferIterator<Base,
static constexpr guint filter =
base_type::filter |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA;
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
using base_type::base_type;
@ -1207,7 +1212,9 @@ struct PaintMaskToPaintBufAlpha : Base
static constexpr guint filter =
Base::filter |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA;
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
explicit
PaintMaskToPaintBufAlpha (const GimpPaintCoreLoopsParams *params) :
@ -1264,6 +1271,379 @@ static AlgorithmDispatch<
dispatch_paint_mask_to_paint_buf_alpha;
/* CanvasBufferToCompMask, dispatch_canvas_buffer_to_comp_mask():
*
* An algorithm class, implementing the CANVAS_BUFFER_TO_COMP_MASK algorithm.
*/
template <class Base,
gboolean Direct>
struct CanvasBufferToCompMask : CanvasBufferIterator<Base, GEGL_ACCESS_READ>
{
using base_type = CanvasBufferIterator<Base, GEGL_ACCESS_READ>;
using comp_mask_type = typename base_type::comp_mask_type;
static constexpr guint filter =
base_type::filter |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
using base_type::base_type;
template <class Derived>
struct State : base_type::template State<Derived>
{
const gfloat *canvas_pixel;
const gfloat *mask_pixel;
};
template <class Derived>
void
init_step (const GimpPaintCoreLoopsParams *params,
State<Derived> *state,
GeglBufferIterator *iter,
const GeglRectangle *roi,
const GeglRectangle *area,
const GeglRectangle *rect) const
{
base_type::init_step (params, state, iter, roi, area, rect);
state->canvas_pixel =
(const gfloat *) iter->items[state->canvas_buffer_iterator].data;
state->mask_pixel =
(const gfloat *) iter->items[state->mask_buffer_iterator].data;
}
template <class Derived>
void
process_row (const GimpPaintCoreLoopsParams *params,
State<Derived> *state,
GeglBufferIterator *iter,
const GeglRectangle *roi,
const GeglRectangle *area,
const GeglRectangle *rect,
gint y) const
{
base_type::process_row (params, state, iter, roi, area, rect, y);
comp_mask_type *comp_mask_pixel = state->comp_mask_data;
gint x;
for (x = 0; x < rect->width; x++)
{
comp_mask_pixel[0] = state->canvas_pixel[0] * state->mask_pixel[0];
comp_mask_pixel += 1;
state->canvas_pixel += 1;
state->mask_pixel += 1;
}
}
};
template <class Base>
struct CanvasBufferToCompMask<Base, TRUE> :
CanvasBufferIterator<Base, GEGL_ACCESS_READ>
{
using base_type = CanvasBufferIterator<Base, GEGL_ACCESS_READ>;
static constexpr guint filter =
base_type::filter |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
using base_type::base_type;
template <class Derived>
using State = typename base_type::template State<Derived>;
template <class Derived>
void
init_step (const GimpPaintCoreLoopsParams *params,
State<Derived> *state,
GeglBufferIterator *iter,
const GeglRectangle *roi,
const GeglRectangle *area,
const GeglRectangle *rect) const
{
base_type::init_step (params, state, iter, roi, area, rect);
state->comp_mask_data =
(gfloat *) iter->items[state->canvas_buffer_iterator].data - rect->width;
}
template <class Derived>
void
process_row (const GimpPaintCoreLoopsParams *params,
State<Derived> *state,
GeglBufferIterator *iter,
const GeglRectangle *roi,
const GeglRectangle *area,
const GeglRectangle *rect,
gint y) const
{
base_type::process_row (params, state, iter, roi, area, rect, y);
state->comp_mask_data += rect->width;
}
};
struct DispatchCanvasBufferToCompMask
{
static constexpr guint mask =
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
template <class Base>
using AlgorithmDirect = CanvasBufferToCompMask<Base, TRUE>;
template <class Base>
using AlgorithmIndirect = CanvasBufferToCompMask<Base, FALSE>;
using DispatchDirect = BasicDispatch<
AlgorithmDirect,
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK,
decltype (dispatch_comp_mask)
>;
using DispatchIndirect = BasicDispatch<
AlgorithmIndirect,
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK,
decltype (dispatch_temp_comp_mask)
>;
template <class Algorithm,
gboolean HasMaskBufferIterator = has_mask_buffer_iterator (
(Algorithm *) NULL)>
struct Dispatch : DispatchIndirect
{
};
template <class Algorithm>
struct Dispatch<Algorithm, FALSE> : DispatchDirect
{
};
template <class Visitor,
class Algorithm>
void
operator () (Visitor visitor,
const GimpPaintCoreLoopsParams *params,
GimpPaintCoreLoopsAlgorithm algorithms,
identity<Algorithm> algorithm) const
{
if ((algorithms & mask) == mask)
{
dispatch (
[&] (auto algorithm)
{
using NewAlgorithm = typename decltype (algorithm)::type;
Dispatch<NewAlgorithm> () (visitor, params, algorithms, algorithm);
},
params, algorithms, algorithm,
dispatch_mask_buffer_iterator);
}
else
{
visitor (algorithm);
}
}
} static dispatch_canvas_buffer_to_comp_mask;
/* PaintMaskToCompMask, dispatch_paint_mask_to_comp_mask():
*
* An algorithm class, implementing the PAINT_MASK_TO_COMP_MASK algorithm.
*/
template <class Base,
gboolean Direct>
struct PaintMaskToCompMask : Base
{
using mask_type = typename Base::mask_type;
using comp_mask_type = typename Base::comp_mask_type;
static constexpr guint filter =
Base::filter |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
using Base::Base;
template <class Derived>
struct State : Base::template State<Derived>
{
const gfloat *mask_pixel;
};
template <class Derived>
void
init_step (const GimpPaintCoreLoopsParams *params,
State<Derived> *state,
GeglBufferIterator *iter,
const GeglRectangle *roi,
const GeglRectangle *area,
const GeglRectangle *rect) const
{
Base::init_step (params, state, iter, roi, area, rect);
if (has_mask_buffer_iterator (this))
{
state->mask_pixel =
(const gfloat *) iter->items[mask_buffer_iterator (this, state)].data;
}
}
template <class Derived>
void
process_row (const GimpPaintCoreLoopsParams *params,
State<Derived> *state,
GeglBufferIterator *iter,
const GeglRectangle *roi,
const GeglRectangle *area,
const GeglRectangle *rect,
gint y) const
{
Base::process_row (params, state, iter, roi, area, rect, y);
gint mask_offset = (y - roi->y) * this->mask_stride +
(rect->x - roi->x);
const mask_type *mask_pixel = &this->mask_data[mask_offset];
comp_mask_type *comp_mask_pixel = state->comp_mask_data;
gint x;
if (has_mask_buffer_iterator (this))
{
for (x = 0; x < rect->width; x++)
{
comp_mask_pixel[0] = value_to_float (mask_pixel[0]) *
state->mask_pixel[0];
comp_mask_pixel += 1;
mask_pixel += 1;
state->mask_pixel += 1;
}
}
else
{
for (x = 0; x < rect->width; x++)
{
comp_mask_pixel[0] = value_to_float (mask_pixel[0]);
comp_mask_pixel += 1;
mask_pixel += 1;
}
}
}
};
template <class Base>
struct PaintMaskToCompMask<Base, TRUE> : Base
{
using mask_type = typename Base::mask_type;
static constexpr guint filter =
Base::filter |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK |
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
using Base::Base;
template <class Derived>
using State = typename Base::template State<Derived>;
template <class Derived>
void
init_step (const GimpPaintCoreLoopsParams *params,
State<Derived> *state,
GeglBufferIterator *iter,
const GeglRectangle *roi,
const GeglRectangle *area,
const GeglRectangle *rect) const
{
Base::init_step (params, state, iter, roi, area, rect);
gint mask_offset = (rect->y - roi->y) * this->mask_stride +
(rect->x - roi->x);
state->comp_mask_data = (mask_type *) &this->mask_data[mask_offset] -
this->mask_stride;
}
template <class Derived>
void
process_row (const GimpPaintCoreLoopsParams *params,
State<Derived> *state,
GeglBufferIterator *iter,
const GeglRectangle *roi,
const GeglRectangle *area,
const GeglRectangle *rect,
gint y) const
{
Base::process_row (params, state, iter, roi, area, rect, y);
state->comp_mask_data += this->mask_stride;
}
};
struct DispatchPaintMaskToCompMask
{
static constexpr guint mask =
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
template <class Base>
using AlgorithmDirect = PaintMaskToCompMask<Base, TRUE>;
template <class Base>
using AlgorithmIndirect = PaintMaskToCompMask<Base, FALSE>;
using DispatchDirect = BasicDispatch<
AlgorithmDirect,
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK,
decltype (dispatch_comp_mask)
>;
using DispatchIndirect = BasicDispatch<
AlgorithmIndirect,
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK,
decltype (dispatch_temp_comp_mask)
>;
template <class Algorithm,
class MaskType = typename Algorithm::mask_type,
gboolean HasMaskBufferIterator = has_mask_buffer_iterator (
(Algorithm *) NULL)>
struct Dispatch : DispatchIndirect
{
};
template <class Algorithm>
struct Dispatch<Algorithm, gfloat, FALSE> : DispatchDirect
{
};
template <class Visitor,
class Algorithm>
void
operator () (Visitor visitor,
const GimpPaintCoreLoopsParams *params,
GimpPaintCoreLoopsAlgorithm algorithms,
identity<Algorithm> algorithm) const
{
if ((algorithms & mask) == mask)
{
dispatch (
[&] (auto algorithm)
{
using NewAlgorithm = typename decltype (algorithm)::type;
Dispatch<NewAlgorithm> () (visitor, params, algorithms, algorithm);
},
params, algorithms, algorithm,
dispatch_paint_mask, dispatch_mask_buffer_iterator);
}
else
{
visitor (algorithm);
}
}
} static dispatch_paint_mask_to_comp_mask;
/* DoLayerBlend, dispatch_do_layer_blend():
*
* An algorithm class, implementing the DO_LAYER_BLEND algorithm.
@ -1515,6 +1895,8 @@ gimp_paint_core_loops_process (const GimpPaintCoreLoopsParams *params,
dispatch_combine_paint_mask_to_canvas_buffer,
dispatch_canvas_buffer_to_paint_buf_alpha,
dispatch_paint_mask_to_paint_buf_alpha,
dispatch_canvas_buffer_to_comp_mask,
dispatch_paint_mask_to_comp_mask,
dispatch_do_layer_blend);
}

View File

@ -26,7 +26,9 @@ typedef enum
GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER = 1 << 0,
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA = 1 << 1,
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA = 1 << 2,
GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND = 1 << 3
GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK = 1 << 3,
GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK = 1 << 4,
GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND = 1 << 5
} GimpPaintCoreLoopsAlgorithm;