[gimp/wip/paintcore-loops] app: refactor gimppaintcore-loops to coalesce iteration
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/paintcore-loops] app: refactor gimppaintcore-loops to coalesce iteration
- Date: Sun, 15 Apr 2018 01:52:18 +0000 (UTC)
commit d5cbdb48021298c830f8c95aace074b736bddb0b
Author: Ell <ell_se yahoo com>
Date: Sat Apr 14 19:02:21 2018 -0400
app: refactor gimppaintcore-loops to coalesce iteration
WIP
app/paint/gimppaintcore-loops.cc | 1190 ++++++++++++++++++++++++++++----------
app/paint/gimppaintcore-loops.h | 116 +++--
app/paint/gimppaintcore.c | 75 ++--
3 files changed, 1008 insertions(+), 373 deletions(-)
---
diff --git a/app/paint/gimppaintcore-loops.cc b/app/paint/gimppaintcore-loops.cc
index c02335d..beb9ec8 100644
--- a/app/paint/gimppaintcore-loops.cc
+++ b/app/paint/gimppaintcore-loops.cc
@@ -34,211 +34,922 @@ extern "C"
#include "gimppaintcore-loops.h"
+} /* extern "C" */
+
#define MIN_PARALLEL_SUB_SIZE 64
#define MIN_PARALLEL_SUB_AREA (MIN_PARALLEL_SUB_SIZE * MIN_PARALLEL_SUB_SIZE)
-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)
+enum
{
- GeglRectangle roi;
+ ALGORITHM_PAINT_BUF = 1u << 31,
+ ALGORITHM_PAINT_MASK = 1u << 30,
+ ALGORITHM_STIPPLE = 1u << 29
+};
- 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);
- gint width;
- gint height;
- width = gimp_temp_buf_get_width (paint_mask);
- height = gimp_temp_buf_get_height (paint_mask);
+template <class T>
+struct identity
+{
+ using type = T;
+};
- roi.x = x_offset;
- roi.y = y_offset;
- roi.width = width - mask_x_offset;
- roi.height = height - mask_y_offset;
- gimp_parallel_distribute_area (&roi, MIN_PARALLEL_SUB_AREA,
- [=] (const GeglRectangle *area)
- {
- GeglBufferIterator *iter;
+template <class Visitor,
+ class Algorithm>
+static inline void
+dispatch (Visitor visitor,
+ const GimpPaintCoreLoopsParams *params,
+ GimpPaintCoreLoopsAlgorithm algorithms,
+ identity<Algorithm> algorithm)
+{
+ visitor (algorithm);
+}
- iter = gegl_buffer_iterator_new (canvas_buffer, area, 0,
- babl_format ("Y float"),
- GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
+template <class Algorithm,
+ class Dispatch,
+ gboolean = (Algorithm::filter & Dispatch::mask) == Dispatch::mask>
+struct dispatch_impl
+{
+ template <class Visitor,
+ class... DispatchRest>
+ static void
+ apply (Visitor visitor,
+ const GimpPaintCoreLoopsParams *params,
+ GimpPaintCoreLoopsAlgorithm algorithms,
+ identity<Algorithm> algorithm,
+ Dispatch disp,
+ DispatchRest... disp_rest)
+ {
+ disp (
+ [&] (auto algorithm)
+ {
+ dispatch (visitor, params, algorithms, algorithm, disp_rest...);
+ },
+ params, algorithms, algorithm);
+ }
+};
+
+template <class Algorithm,
+ class Dispatch>
+struct dispatch_impl<Algorithm, Dispatch, TRUE>
+{
+ template <class Visitor,
+ class... DispatchRest>
+ static void
+ apply (Visitor visitor,
+ const GimpPaintCoreLoopsParams *params,
+ GimpPaintCoreLoopsAlgorithm algorithms,
+ identity<Algorithm> algorithm,
+ Dispatch disp,
+ DispatchRest... disp_rest)
+ {
+ dispatch (visitor, params, algorithms, algorithm, disp_rest...);
+ }
+};
+
+template <class Visitor,
+ class Algorithm,
+ class Dispatch,
+ class... DispatchRest>
+static inline void
+dispatch (Visitor visitor,
+ const GimpPaintCoreLoopsParams *params,
+ GimpPaintCoreLoopsAlgorithm algorithms,
+ identity<Algorithm> algorithm,
+ Dispatch disp,
+ DispatchRest... disp_rest)
+{
+ dispatch_impl<Algorithm, Dispatch>::apply (
+ visitor, params, algorithms, algorithm, disp, disp_rest...);
+}
- 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;
+static inline gfloat
+value_to_float (guint8 value)
+{
+ return value / 255.0f;
+}
- 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];
+static inline gfloat
+value_to_float (gfloat value)
+{
+ return value;
+}
- for (ix = 0; ix < iter->roi[0].width; ix++)
- {
- out_pixel[0] += (1.0 - out_pixel[0]) * (*mask_pixel / 255.0f) * opacity;
+template <class T>
+static inline gfloat
+value_to_float (T value) = delete;
- 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;
+struct AlgorithmBase
+{
+ static constexpr guint filter = 0;
+
+ static constexpr gint canvas_buffer_iterator = -1;
+ static constexpr GeglAccessMode canvas_buffer_access = {};
+
+ static constexpr gint n_iterators = 0;
+
+ explicit
+ AlgorithmBase (const GimpPaintCoreLoopsParams *params)
+ {
+ }
+
+ template <class Derived>
+ struct State
+ {
+ };
+
+ template <class Derived>
+ void
+ init (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area) const
+ {
+ }
+
+ template <class Derived>
+ void
+ init_step (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area) const
+ {
+ }
+
+ template <class Derived>
+ void
+ process_row (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area,
+ gint y) const
+ {
+ }
+};
+
+template <template <class Base> class TemplateAlgorithm,
+ guint Mask>
+struct BasicDispatch
+{
+ static constexpr guint mask = Mask;
+
+ template <class Visitor,
+ class Algorithm>
+ void
+ operator () (Visitor visitor,
+ const GimpPaintCoreLoopsParams *params,
+ GimpPaintCoreLoopsAlgorithm algorithms,
+ identity<Algorithm> algorithm) const
+ {
+ visitor (identity<TemplateAlgorithm<Algorithm>> ());
+ }
+};
+
+template <template <class Base> class TemplateAlgorithm,
+ guint Mask,
+ class... Dependencies>
+struct AlgorithmDispatch
+{
+ static constexpr guint mask = Mask;
+
+ 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;
+
+ visitor (identity<TemplateAlgorithm<NewAlgorithm>> ());
+ },
+ params, algorithms, algorithm, Dependencies ()...);
+ }
+ else
+ {
+ visitor (algorithm);
+ }
+ }
+};
+
+template <class Base>
+struct PaintBuf : Base
+{
+ using paint_type = gfloat;
- 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];
+ static constexpr guint filter = Base::filter | ALGORITHM_PAINT_BUF;
- for (ix = 0; ix < iter->roi[0].width; ix++)
- {
- out_pixel[0] += (1.0 - out_pixel[0]) * (*mask_pixel) * opacity;
+ gint paint_stride;
+ paint_type *paint_data;
- 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;
+ explicit
+ PaintBuf (const GimpPaintCoreLoopsParams *params) :
+ Base (params)
+ {
+ paint_stride = gimp_temp_buf_get_width (params->paint_buf) * 4;
+ paint_data = (paint_type *) gimp_temp_buf_get_data (params->paint_buf);
+ }
+};
- while (gegl_buffer_iterator_next (iter))
- {
- gfloat *out_pixel = (gfloat *)iter->data[0];
- int iy, ix;
+static BasicDispatch<PaintBuf, ALGORITHM_PAINT_BUF> dispatch_paint_buf;
- 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];
+template <class Base,
+ class MaskType>
+struct PaintMask : Base
+{
+ using mask_type = MaskType;
+
+ static constexpr guint filter = Base::filter | ALGORITHM_PAINT_MASK;
+
+ gint mask_stride;
+ const mask_type *mask_data;
+
+ explicit
+ PaintMask (const GimpPaintCoreLoopsParams *params) :
+ Base (params)
+ {
+ mask_stride = gimp_temp_buf_get_width (params->paint_mask);
+ mask_data =
+ (const mask_type *) gimp_temp_buf_get_data (params->paint_mask) +
+ params->paint_mask_offset_y * mask_stride +
+ params->paint_mask_offset_x;
+ }
+};
+
+struct DispatchPaintMask
+{
+ static constexpr guint mask = ALGORITHM_PAINT_MASK;
+
+ template <class Visitor,
+ class Algorithm>
+ void
+ operator () (Visitor visitor,
+ const GimpPaintCoreLoopsParams *params,
+ GimpPaintCoreLoopsAlgorithm algorithms,
+ identity<Algorithm> algorithm) const
+ {
+ const Babl *mask_format = gimp_temp_buf_get_format (params->paint_mask);
+
+ if (mask_format == babl_format ("Y u8"))
+ visitor (identity<PaintMask<Algorithm, guint8>> ());
+ else if (mask_format == babl_format ("Y float"))
+ visitor (identity<PaintMask<Algorithm, gfloat>> ());
+ else
+ g_warning ("Mask format not supported: %s", babl_get_name (mask_format));
+ }
+} static dispatch_paint_mask;
+
+template <class Base,
+ gboolean StippleFlag>
+struct Stipple : Base
+{
+ static constexpr guint filter = Base::filter | ALGORITHM_STIPPLE;
- 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;
+ static constexpr gboolean stipple = StippleFlag;
- mask_pixel += 1;
- out_pixel += 1;
- }
- }
- }
- }
- else if (mask_format == babl_format ("Y float"))
+ using Base::Base;
+};
+
+struct DispatchStipple
+{
+ static constexpr guint mask = ALGORITHM_STIPPLE;
+
+ template <class Visitor,
+ class Algorithm>
+ void
+ operator () (Visitor visitor,
+ const GimpPaintCoreLoopsParams *params,
+ GimpPaintCoreLoopsAlgorithm algorithms,
+ identity<Algorithm> algorithm) const
+ {
+ if (params->stipple)
+ visitor (identity<Stipple<Algorithm, TRUE>> ());
+ else
+ visitor (identity<Stipple<Algorithm, FALSE>> ());
+ }
+} static dispatch_stipple;
+
+template <class Base,
+ guint Access>
+struct CanvasBufferIterator : Base
+{
+ static constexpr gint canvas_buffer_iterator =
+ Base::canvas_buffer_iterator < 0 ? Base::n_iterators :
+ Base::canvas_buffer_iterator;
+ static constexpr GeglAccessMode canvas_buffer_access =
+ (GeglAccessMode) (+Base::canvas_buffer_access | Access);
+ static constexpr gint n_iterators =
+ Base::canvas_buffer_iterator < 0 ? Base::n_iterators + 1:
+ Base::n_iterators;
+
+ using Base::Base;
+
+ template <class Derived>
+ using State = typename Base::template State<Derived>;
+
+ template <class Derived>
+ void
+ init (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area) const
+ {
+ Base::init (params, state, iter, roi, area);
+
+ if (Base::canvas_buffer_iterator < 0)
+ {
+ gegl_buffer_iterator_add (iter, params->canvas_buffer, area, 0,
+ babl_format ("Y float"),
+ Derived::canvas_buffer_access,
+ GEGL_ABYSS_NONE);
+ }
+ }
+};
+
+template <class Base>
+struct CombinePaintMaskToCanvasMaskToPaintBufAlpha : CanvasBufferIterator<Base,
+ GEGL_BUFFER_READWRITE>
+{
+ using base_type = CanvasBufferIterator<Base, GEGL_BUFFER_READWRITE>;
+ using mask_type = typename base_type::mask_type;
+
+ static constexpr guint filter =
+ base_type::filter |
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_MASK |
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA |
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUFFER;
+
+ using base_type::base_type;
+
+ template <class Derived>
+ struct State : base_type::template State<Derived>
+ {
+ gfloat *canvas_pixel;
+ };
+
+ template <class Derived>
+ void
+ init_step (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area) const
+ {
+ base_type::init_step (params, state, iter, roi, area);
+
+ state->canvas_pixel =
+ (gfloat *) iter->data[base_type::canvas_buffer_iterator];
+ }
+
+ template <class Derived>
+ void
+ process_row (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area,
+ gint y) const
+ {
+ base_type::process_row (params, state, iter, roi, area, y);
+
+ gint mask_offset = (y + iter->roi[0].y - roi->y) * this->mask_stride +
+ iter->roi[0].x - roi->x;
+ const mask_type *mask_pixel = &this->mask_data[mask_offset];
+ gint paint_offset = (y + iter->roi[0].y - roi->y) * this->paint_stride +
+ (iter->roi[0].x - roi->x) * 4;
+ gfloat *paint_pixel = &this->paint_data[paint_offset];
+ gint x;
+
+ for (x = 0; x < iter->roi[0].width; x++)
+ {
+ if (base_type::stipple)
+ {
+ state->canvas_pixel[0] += (1.0 - state->canvas_pixel[0]) *
+ value_to_float (*mask_pixel) *
+ params->paint_opacity;
+ }
+ else
+ {
+ if (params->paint_opacity > state->canvas_pixel[0])
+ {
+ state->canvas_pixel[0] += (params->paint_opacity - state->canvas_pixel[0]) *
+ value_to_float (*mask_pixel) *
+ params->paint_opacity;
+ }
+ }
+
+ paint_pixel[3] *= state->canvas_pixel[0];
+
+ mask_pixel += 1;
+ state->canvas_pixel += 1;
+ paint_pixel += 4;
+ }
+ }
+};
+
+static AlgorithmDispatch<
+ CombinePaintMaskToCanvasMaskToPaintBufAlpha,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_MASK |
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA,
+ decltype (dispatch_paint_buf),
+ decltype (dispatch_paint_mask),
+ decltype (dispatch_stipple)
+>
+dispatch_combine_paint_mask_to_canvas_mask_to_paint_buf_alpha;
+
+template <class Base>
+struct CombinePaintMaskToCanvasMask : CanvasBufferIterator<Base,
+ GEGL_BUFFER_READWRITE>
+{
+ using base_type = CanvasBufferIterator<Base, GEGL_BUFFER_READWRITE>;
+ using mask_type = typename base_type::mask_type;
+
+ static constexpr guint filter =
+ base_type::filter |
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_MASK |
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUFFER;
+
+ using base_type::base_type;
+
+ template <class Derived>
+ struct State : base_type::template State<Derived>
+ {
+ gfloat *canvas_pixel;
+ };
+
+ template <class Derived>
+ void
+ init_step (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area) const
+ {
+ base_type::init_step (params, state, iter, roi, area);
+
+ state->canvas_pixel =
+ (gfloat *) iter->data[base_type::canvas_buffer_iterator];
+ }
+
+ template <class Derived>
+ void
+ process_row (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area,
+ gint y) const
+ {
+ base_type::process_row (params, state, iter, roi, area, y);
+
+ gint mask_offset = (y + iter->roi[0].y - roi->y) * this->mask_stride +
+ iter->roi[0].x - roi->x;
+ const mask_type *mask_pixel = &this->mask_data[mask_offset];
+ gint x;
+
+ for (x = 0; x < iter->roi[0].width; x++)
+ {
+ if (base_type::stipple)
+ {
+ state->canvas_pixel[0] += (1.0 - state->canvas_pixel[0]) *
+ value_to_float (*mask_pixel) *
+ params->paint_opacity;
+ }
+ else
+ {
+ if (params->paint_opacity > state->canvas_pixel[0])
+ {
+ state->canvas_pixel[0] += (params->paint_opacity - state->canvas_pixel[0]) *
+ value_to_float (*mask_pixel) *
+ params->paint_opacity;
+ }
+ }
+
+ mask_pixel += 1;
+ state->canvas_pixel += 1;
+ }
+ }
+};
+
+static AlgorithmDispatch<
+ CombinePaintMaskToCanvasMask,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_MASK,
+ decltype (dispatch_paint_mask),
+ decltype (dispatch_stipple)
+>
+dispatch_combine_paint_mask_to_canvas_mask;
+
+template <class Base>
+struct CanvasBufferToPaintBufAlpha : CanvasBufferIterator<Base,
+ GEGL_BUFFER_READ>
+{
+ using base_type = CanvasBufferIterator<Base, GEGL_BUFFER_READ>;
+
+ 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_BUFFER;
+
+ using base_type::base_type;
+
+ template <class Derived>
+ struct State : base_type::template State<Derived>
+ {
+ const gfloat *canvas_pixel;
+ };
+
+ template <class Derived>
+ void
+ init_step (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area) const
+ {
+ base_type::init_step (params, state, iter, roi, area);
+
+ state->canvas_pixel =
+ (const gfloat *) iter->data[base_type::canvas_buffer_iterator];
+ }
+
+ template <class Derived>
+ void
+ process_row (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area,
+ gint y) const
+ {
+ base_type::process_row (params, state, iter, roi, area, y);
+
+ /* Copy the canvas buffer in rect to the paint buffer's alpha channel */
+
+ gint paint_offset = (y + iter->roi[0].y - roi->y) * this->paint_stride +
+ (iter->roi[0].x - roi->x) * 4;
+ gfloat *paint_pixel = &this->paint_data[paint_offset];
+ gint x;
+
+ for (x = 0; x < iter->roi[0].width; x++)
+ {
+ paint_pixel[3] *= *state->canvas_pixel;
+
+ state->canvas_pixel += 1;
+ paint_pixel += 4;
+ }
+ }
+};
+
+static AlgorithmDispatch<
+ CanvasBufferToPaintBufAlpha,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA,
+ decltype (dispatch_paint_buf)
+>
+dispatch_canvas_buffer_to_paint_buf_alpha;
+
+template <class Base>
+struct PaintMaskToPaintBuffer : Base
+{
+ using mask_type = typename Base::mask_type;
+
+ static constexpr guint filter =
+ Base::filter |
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUFFER;
+
+ explicit
+ PaintMaskToPaintBuffer (const GimpPaintCoreLoopsParams *params) :
+ Base (params)
+ {
+ /* Validate that the paint buffer is withing the bounds of the paint mask */
+ g_return_if_fail (gimp_temp_buf_get_width (params->paint_buf) <=
+ gimp_temp_buf_get_width (params->paint_mask) -
+ params->paint_mask_offset_x);
+ g_return_if_fail (gimp_temp_buf_get_height (params->paint_buf) <=
+ gimp_temp_buf_get_height (params->paint_mask) -
+ params->paint_mask_offset_y);
+ }
+
+ template <class Derived>
+ using State = typename Base::template State<Derived>;
+
+ template <class Derived>
+ void
+ process_row (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area,
+ gint y) const
+ {
+ Base::process_row (params, state, iter, roi, area, y);
+
+ gint paint_offset = (y + iter->roi[0].y - roi->y) * this->paint_stride +
+ (iter->roi[0].x - roi->x) * 4;
+ gfloat *paint_pixel = &this->paint_data[paint_offset];
+ gint mask_offset = (y + iter->roi[0].y - roi->y) * this->mask_stride +
+ iter->roi[0].x - roi->x;
+ const mask_type *mask_pixel = &this->mask_data[mask_offset];
+ gint x;
+
+ for (x = 0; x < iter->roi[0].width; x++)
+ {
+ paint_pixel[3] *= value_to_float (*mask_pixel) * params->paint_opacity;
+
+ mask_pixel += 1;
+ paint_pixel += 4;
+ }
+ }
+};
+
+static AlgorithmDispatch<
+ PaintMaskToPaintBuffer,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUFFER,
+ decltype (dispatch_paint_buf),
+ decltype (dispatch_paint_mask)
+>
+dispatch_paint_mask_to_paint_buffer;
+
+template <class Base>
+struct DoLayerBlend : Base
+{
+ static constexpr guint filter =
+ Base::filter |
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND;
+
+ static constexpr gint iterator_base = Base::n_iterators;
+ static constexpr gint n_iterators = Base::n_iterators + 3;
+
+ const Babl *iterator_format;
+ GimpOperationLayerMode layer_mode;
+
+ explicit
+ DoLayerBlend (const GimpPaintCoreLoopsParams *params) :
+ Base (params)
+ {
+ layer_mode.layer_mode = params->paint_mode;
+ layer_mode.opacity = params->image_opacity;
+ layer_mode.function = gimp_layer_mode_get_function (params->paint_mode);
+ layer_mode.blend_function = gimp_layer_mode_get_blend_function (params->paint_mode);
+ layer_mode.blend_space = gimp_layer_mode_get_blend_space (params->paint_mode);
+ layer_mode.composite_space = gimp_layer_mode_get_composite_space (params->paint_mode);
+ layer_mode.composite_mode = gimp_layer_mode_get_paint_composite_mode (params->paint_mode);
+ layer_mode.real_composite_mode = layer_mode.composite_mode;
+
+ iterator_format = gimp_layer_mode_get_format (params->paint_mode,
+ layer_mode.composite_space,
+ layer_mode.blend_space,
+ gimp_temp_buf_get_format (params->paint_buf));
+
+ g_return_if_fail (gimp_temp_buf_get_format (params->paint_buf) == iterator_format);
+ }
+
+ template <class Derived>
+ struct State : Base::template State<Derived>
+ {
+ GeglRectangle process_roi;
+
+ gfloat *out_pixel;
+ gfloat *in_pixel;
+ gfloat *mask_pixel;
+ gfloat *paint_pixel;
+ };
+
+ template <class Derived>
+ void
+ init (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area) const
+ {
+ Base::init (params, state, iter, roi, area);
+
+ GeglRectangle mask_area = *area;
+
+ mask_area.x -= params->mask_offset_x;
+ mask_area.y -= params->mask_offset_y;
+
+ gegl_buffer_iterator_add (iter, params->dest_buffer, area, 0,
+ iterator_format,
+ GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
+
+ gegl_buffer_iterator_add (iter, params->src_buffer, area, 0,
+ iterator_format,
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+ if (params->mask_buffer)
+ {
+ gegl_buffer_iterator_add (iter, params->mask_buffer, &mask_area, 0,
+ babl_format ("Y float"),
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+ }
+ }
+
+ template <class Derived>
+ void
+ init_step (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area) const
+ {
+ Base::init_step (params, state, iter, roi, area);
+
+ state->out_pixel = (gfloat *) iter->data[iterator_base + 0];
+ state->in_pixel = (gfloat *) iter->data[iterator_base + 1];
+ state->mask_pixel = NULL;
+
+ state->paint_pixel = this->paint_data +
+ (iter->roi[0].y - roi->y) * this->paint_stride +
+ (iter->roi[0].x - roi->x) * 4;
+
+ if (params->mask_buffer)
+ state->mask_pixel = (gfloat *) iter->data[iterator_base + 2];
+
+ state->process_roi.x = iter->roi[0].x;
+ state->process_roi.width = iter->roi[0].width;
+ state->process_roi.height = 1;
+ }
+
+ template <class Derived>
+ void
+ process_row (const GimpPaintCoreLoopsParams *params,
+ State<Derived> *state,
+ GeglBufferIterator *iter,
+ const GeglRectangle *roi,
+ const GeglRectangle *area,
+ gint y) const
+ {
+ Base::process_row (params, state, iter, roi, area, y);
+
+ state->process_roi.y = iter->roi[0].y + y;
+
+ layer_mode.function ((GeglOperation*) &layer_mode,
+ state->in_pixel,
+ state->paint_pixel,
+ state->mask_pixel,
+ state->out_pixel,
+ iter->roi[0].width,
+ &state->process_roi,
+ 0);
+
+ state->in_pixel += iter->roi[0].width * 4;
+ state->out_pixel += iter->roi[0].width * 4;
+ if (params->mask_buffer)
+ state->mask_pixel += iter->roi[0].width;
+ state->paint_pixel += this->paint_stride;
+ }
+};
+
+static AlgorithmDispatch<
+ DoLayerBlend,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND,
+ decltype (dispatch_paint_buf)
+>
+dispatch_do_layer_blend;
+
+void
+gimp_paint_core_loops_process (const GimpPaintCoreLoopsParams *params,
+ GimpPaintCoreLoopsAlgorithm algorithms)
+{
+ GeglRectangle roi;
+
+ if (params->paint_buf)
+ {
+ roi.x = params->paint_buf_offset_x;
+ roi.y = params->paint_buf_offset_y;
+ roi.width = gimp_temp_buf_get_width (params->paint_buf);
+ roi.height = gimp_temp_buf_get_height (params->paint_buf);
+ }
+ else
+ {
+ roi.x = params->paint_buf_offset_x;
+ roi.y = params->paint_buf_offset_y;
+ roi.width = gimp_temp_buf_get_width (params->paint_mask) -
+ params->paint_mask_offset_x;
+ roi.height = gimp_temp_buf_get_height (params->paint_mask) -
+ params->paint_mask_offset_y;
+ }
+
+ dispatch (
+ [&] (auto algorithm_type)
+ {
+ using Algorithm = typename decltype (algorithm_type)::type;
+ using State = typename Algorithm::template State<Algorithm>;
+
+ Algorithm algorithm (params);
+
+ gimp_parallel_distribute_area (&roi, MIN_PARALLEL_SUB_AREA,
+ [=] (const GeglRectangle *area)
+ {
+ State state;
+ gint y;
+
+ if (Algorithm::n_iterators > 0)
{
- const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask);
- mask_data += mask_start_offset;
+ GeglBufferIterator *iter;
+
+ iter = gegl_buffer_iterator_empty_new ();
+
+ algorithm.init (params, &state, iter, &roi, area);
while (gegl_buffer_iterator_next (iter))
{
- gfloat *out_pixel = (gfloat *)iter->data[0];
- int iy, ix;
+ algorithm.init_step (params, &state, iter, &roi, area);
- for (iy = 0; iy < iter->roi[0].height; iy++)
+ for (y = 0; y < iter->roi[0].height; y++)
{
- 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;
- }
+ algorithm.process_row (params, &state,
+ iter, &roi, area, y);
}
}
}
else
{
- g_warning("Mask format not supported: %s", babl_get_name (mask_format));
+ GeglBufferIterator iter;
+
+ iter.roi[0] = *area;
+
+ algorithm.init (params, &state, &iter, &roi, area);
+ algorithm.init_step (params, &state, &iter, &roi, area);
+
+ for (y = 0; y < iter.roi[0].height; y++)
+ {
+ algorithm.process_row (params, &state,
+ &iter, &roi, area, y);
+ }
}
- }
- });
+ });
+ },
+ params, algorithms, identity<AlgorithmBase> (),
+ dispatch_combine_paint_mask_to_canvas_mask_to_paint_buf_alpha,
+ dispatch_combine_paint_mask_to_canvas_mask,
+ dispatch_canvas_buffer_to_paint_buf_alpha,
+ dispatch_paint_mask_to_paint_buffer,
+ dispatch_do_layer_blend);
}
void
-canvas_buffer_to_paint_buf_alpha (GimpTempBuf *paint_buf,
- GeglBuffer *canvas_buffer,
- gint x_offset,
- gint y_offset)
+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)
{
- /* Copy the canvas buffer in rect to the paint buffer's alpha channel */
- GeglRectangle roi;
+ GimpPaintCoreLoopsParams params = {};
- const guint paint_stride = gimp_temp_buf_get_width (paint_buf);
- gfloat *paint_data = (gfloat *) gimp_temp_buf_get_data (paint_buf);
+ params.canvas_buffer = canvas_buffer;
- 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);
+ params.paint_buf_offset_x = x_offset;
+ params.paint_buf_offset_y = y_offset;
- gimp_parallel_distribute_area (&roi, MIN_PARALLEL_SUB_AREA,
- [=] (const GeglRectangle *area)
- {
- GeglBufferIterator *iter;
+ params.paint_mask = paint_mask;
+ params.paint_mask_offset_x = mask_x_offset;
+ params.paint_mask_offset_y = mask_y_offset;
- iter = gegl_buffer_iterator_new (canvas_buffer, area, 0,
- babl_format ("Y float"),
- GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+ params.stipple = stipple;
- while (gegl_buffer_iterator_next (iter))
- {
- gfloat *canvas_pixel = (gfloat *)iter->data[0];
- int iy, ix;
+ params.paint_opacity = opacity;
- 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];
+ gimp_paint_core_loops_process (
+ ¶ms,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_MASK);
+}
- for (ix = 0; ix < iter->roi[0].width; ix++)
- {
- paint_pixel[3] *= *canvas_pixel;
+void
+canvas_buffer_to_paint_buf_alpha (GimpTempBuf *paint_buf,
+ GeglBuffer *canvas_buffer,
+ gint x_offset,
+ gint y_offset)
+{
+ GimpPaintCoreLoopsParams params = {};
- canvas_pixel += 1;
- paint_pixel += 4;
- }
- }
- }
- });
+ params.canvas_buffer = canvas_buffer;
+
+ params.paint_buf = paint_buf;
+ params.paint_buf_offset_x = x_offset;
+ params.paint_buf_offset_y = y_offset;
+
+ gimp_paint_core_loops_process (
+ ¶ms,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA);
}
void
@@ -248,63 +959,19 @@ paint_mask_to_paint_buffer (const GimpTempBuf *paint_mask,
GimpTempBuf *paint_buf,
gfloat paint_opacity)
{
- gint width = gimp_temp_buf_get_width (paint_buf);
- gint height = gimp_temp_buf_get_height (paint_buf);
+ GimpPaintCoreLoopsParams params = {};
- 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);
+ params.paint_buf = 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);
+ params.paint_mask = paint_mask;
+ params.paint_mask_offset_x = mask_x_offset;
+ params.paint_mask_offset_y = mask_y_offset;
- gimp_parallel_distribute_range (height, MIN_PARALLEL_SUB_SIZE,
- [=] (gint y, gint height)
- {
- int iy, ix;
- gfloat *paint_pixel = (gfloat *)gimp_temp_buf_get_data (paint_buf) +
- y * width * 4;
-
- 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 + y * mask_stride;
-
- for (iy = 0; iy < height; iy++)
- {
- int mask_offset = iy * mask_stride;
- const guint8 *mask_pixel = &mask_data[mask_offset];
+ params.paint_opacity = paint_opacity;
- 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 + y * mask_stride;
-
- 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;
- }
- }
- }
- });
+ gimp_paint_core_loops_process (
+ ¶ms,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUFFER);
}
void
@@ -319,99 +986,26 @@ do_layer_blend (GeglBuffer *src_buffer,
gint mask_y_offset,
GimpLayerMode paint_mode)
{
- GeglRectangle roi;
- const Babl *iterator_format;
- guint paint_stride;
- gfloat *paint_data;
- GimpOperationLayerMode layer_mode;
-
- paint_stride = gimp_temp_buf_get_width (paint_buf);
- paint_data = (gfloat *) gimp_temp_buf_get_data (paint_buf);
-
- layer_mode.layer_mode = paint_mode;
- layer_mode.opacity = opacity;
- layer_mode.function = gimp_layer_mode_get_function (paint_mode);
- layer_mode.blend_function = gimp_layer_mode_get_blend_function (paint_mode);
- layer_mode.blend_space = gimp_layer_mode_get_blend_space (paint_mode);
- layer_mode.composite_space = gimp_layer_mode_get_composite_space (paint_mode);
- layer_mode.composite_mode = gimp_layer_mode_get_paint_composite_mode (paint_mode);
- layer_mode.real_composite_mode = layer_mode.composite_mode;
-
- iterator_format = gimp_layer_mode_get_format (paint_mode,
- layer_mode.composite_space,
- layer_mode.blend_space,
- gimp_temp_buf_get_format (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);
-
- g_return_if_fail (gimp_temp_buf_get_format (paint_buf) == iterator_format);
+ GimpPaintCoreLoopsParams params = {};
- gimp_parallel_distribute_area (&roi, MIN_PARALLEL_SUB_AREA,
- [=] (const GeglRectangle *area)
- {
- GeglBufferIterator *iter;
- GeglRectangle mask_area = *area;
-
- mask_area.x -= mask_x_offset;
- mask_area.y -= mask_y_offset;
-
- iter = gegl_buffer_iterator_new (dst_buffer, area, 0,
- iterator_format,
- GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
-
- gegl_buffer_iterator_add (iter, src_buffer, area, 0,
- iterator_format,
- GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+ params.paint_buf = paint_buf;
+ params.paint_buf_offset_x = x_offset;
+ params.paint_buf_offset_y = y_offset;
- if (mask_buffer)
- {
- gegl_buffer_iterator_add (iter, mask_buffer, &mask_area, 0,
- babl_format ("Y float"),
- GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
- }
-
- while (gegl_buffer_iterator_next (iter))
- {
- GeglRectangle process_roi;
- gfloat *out_pixel = (gfloat *) iter->data[0];
- gfloat *in_pixel = (gfloat *) iter->data[1];
- gfloat *mask_pixel = NULL;
- gfloat *paint_pixel;
- gint iy;
+ params.src_buffer = src_buffer;
+ params.dest_buffer = dst_buffer;
- paint_pixel = paint_data + ((iter->roi[0].y - roi.y) * paint_stride + iter->roi[0].x - roi.x) * 4;
+ params.mask_buffer = mask_buffer;
+ params.mask_offset_x = mask_x_offset;
+ params.mask_offset_y = mask_y_offset;
- if (mask_buffer)
- mask_pixel = (gfloat *)iter->data[2];
+ params.image_opacity = opacity;
- process_roi.x = iter->roi[0].x;
- process_roi.width = iter->roi[0].width;
- process_roi.height = 1;
+ params.paint_mode = paint_mode;
- for (iy = 0; iy < iter->roi[0].height; iy++)
- {
- process_roi.y = iter->roi[0].y + iy;
-
- layer_mode.function ((GeglOperation*) &layer_mode,
- in_pixel,
- paint_pixel,
- mask_pixel,
- out_pixel,
- 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;
- }
- }
- });
+ gimp_paint_core_loops_process (
+ ¶ms,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND);
}
void
@@ -467,5 +1061,3 @@ mask_components_onto (GeglBuffer *src_buffer,
}
});
}
-
-} /* extern "C" */
diff --git a/app/paint/gimppaintcore-loops.h b/app/paint/gimppaintcore-loops.h
index 746d2a5..1e2c1fd 100644
--- a/app/paint/gimppaintcore-loops.h
+++ b/app/paint/gimppaintcore-loops.h
@@ -19,43 +19,85 @@
#define __GIMP_PAINT_CORE_LOOPS_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);
-
-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,
- GimpLayerMode paint_mode);
-
-void mask_components_onto (GeglBuffer *src_buffer,
- GeglBuffer *aux_buffer,
- GeglBuffer *dst_buffer,
- GeglRectangle *roi,
- GimpComponentMask mask,
- gboolean linear_mode);
+typedef enum
+{
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_NONE = 0,
+
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_MASK = 1 << 0,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA = 1 << 1,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUFFER = 1 << 2,
+ GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND = 1 << 3
+} GimpPaintCoreLoopsAlgorithm;
+
+
+typedef struct
+{
+ GeglBuffer *canvas_buffer;
+
+ GimpTempBuf *paint_buf;
+ gint paint_buf_offset_x;
+ gint paint_buf_offset_y;
+
+ const GimpTempBuf *paint_mask;
+ gint paint_mask_offset_x;
+ gint paint_mask_offset_y;
+
+ gboolean stipple;
+
+ GeglBuffer *src_buffer;
+ GeglBuffer *dest_buffer;
+
+ GeglBuffer *mask_buffer;
+ gint mask_offset_x;
+ gint mask_offset_y;
+
+ gdouble paint_opacity;
+ gdouble image_opacity;
+
+ GimpLayerMode paint_mode;
+} GimpPaintCoreLoopsParams;
+
+
+void gimp_paint_core_loops_process (const GimpPaintCoreLoopsParams *params,
+ GimpPaintCoreLoopsAlgorithm algorithms);
+
+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,
+ GimpLayerMode paint_mode);
+
+void mask_components_onto (GeglBuffer *src_buffer,
+ GeglBuffer *aux_buffer,
+ GeglBuffer *dst_buffer,
+ GeglRectangle *roi,
+ GimpComponentMask mask,
+ gboolean linear_mode);
#endif /* __GIMP_PAINT_CORE_LOOPS_H__ */
diff --git a/app/paint/gimppaintcore.c b/app/paint/gimppaintcore.c
index 79b8e48..f8e6986 100644
--- a/app/paint/gimppaintcore.c
+++ b/app/paint/gimppaintcore.c
@@ -864,77 +864,78 @@ gimp_paint_core_paste (GimpPaintCore *core,
}
else
{
- GimpTempBuf *paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer);
- GeglBuffer *dest_buffer;
- GeglBuffer *src_buffer;
+ GimpPaintCoreLoopsParams params = {};
+ GimpPaintCoreLoopsAlgorithm algorithms = GIMP_PAINT_CORE_LOOPS_ALGORITHM_NONE;
- if (! paint_buf)
+ params.paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer);
+ params.paint_buf_offset_x = core->paint_buffer_x;
+ params.paint_buf_offset_y = core->paint_buffer_y;
+
+ if (! params.paint_buf)
return;
if (core->comp_buffer)
- dest_buffer = core->comp_buffer;
+ params.dest_buffer = core->comp_buffer;
else
- dest_buffer = gimp_drawable_get_buffer (drawable);
+ params.dest_buffer = gimp_drawable_get_buffer (drawable);
if (mode == GIMP_PAINT_CONSTANT)
{
+ params.canvas_buffer = core->canvas_buffer;
+
/* This step is skipped by the ink tool, which writes
* directly to canvas_buffer
*/
if (paint_mask != NULL)
{
/* 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));
+ params.paint_mask = paint_mask;
+ params.paint_mask_offset_x = paint_mask_offset_x;
+ params.paint_mask_offset_y = paint_mask_offset_y;
+ params.stipple = GIMP_IS_AIRBRUSH (core);
+ params.paint_opacity = paint_opacity;
+
+ algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_MASK;
}
/* 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);
+ algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA;
/* undo buf -> paint_buf -> dest_buffer */
- src_buffer = core->undo_buffer;
+ params.src_buffer = core->undo_buffer;
}
else
{
g_return_if_fail (paint_mask);
/* 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);
+ params.paint_mask = paint_mask;
+ params.paint_mask_offset_x = paint_mask_offset_x;
+ params.paint_mask_offset_y = paint_mask_offset_y;
+ params.paint_opacity = paint_opacity;
+
+ algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUFFER;
/* dest_buffer -> paint_buf -> dest_buffer */
if (core->comp_buffer)
- src_buffer = gimp_drawable_get_buffer (drawable);
+ params.src_buffer = gimp_drawable_get_buffer (drawable);
else
- src_buffer = dest_buffer;
+ params.src_buffer = params.dest_buffer;
}
- 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,
- paint_mode);
+ params.mask_buffer = core->mask_buffer;
+ params.mask_offset_x = core->mask_x_offset;
+ params.mask_offset_y = core->mask_y_offset;
+ params.image_opacity = image_opacity;
+ params.paint_mode = paint_mode;
+
+ algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND;
+
+ gimp_paint_core_loops_process (¶ms, algorithms);
if (core->comp_buffer)
{
- mask_components_onto (src_buffer,
+ mask_components_onto (params.src_buffer,
core->comp_buffer,
gimp_drawable_get_buffer (drawable),
GEGL_RECTANGLE (core->paint_buffer_x,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]