1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 2013 Daniel Sabo
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19 #include <gegl.h>
20 #include <gdk-pixbuf/gdk-pixbuf.h>
21
22 extern "C"
23 {
24
25 #include "paint-types.h"
26
27 #include "operations/layer-modes/gimp-layer-modes.h"
28
29 #include "core/gimptempbuf.h"
30
31 #include "operations/gimpoperationmaskcomponents.h"
32
33 #include "operations/layer-modes/gimpoperationlayermode.h"
34
35 #include "gimppaintcore-loops.h"
36
37 } /* extern "C" */
38
39
40 #define PIXELS_PER_THREAD \
41 (/* each thread costs as much as */ 64.0 * 64.0 /* pixels */)
42
43
44 /* In order to avoid iterating over the same region of the same buffers
45 * multiple times, when calling more than one of the paint-core loop functions
46 * (hereafter referred to as "algorithms") in succession, we provide a single
47 * function, gimp_paint_core_loops_process(), which can be used to perform
48 * multiple algorithms in a row. This function takes a pointer to a
49 * GimpPaintCoreLoopsParams structure, providing the parameters for the
50 * algorithms, and a GimpPaintCoreLoopsAlgorithm bitset, which specifies the
51 * set of algorithms to run; currently, the algorithms are always run in a
52 * fixed order. For convenience, we provide public functions for the
53 * individual algorithms, but they're merely wrappers around
54 * gimp_paint_core_loops_process().
55 *
56 * We use some C++ magic to statically generate specialized versions of
57 * gimp_paint_core_loops_process() for all possible combinations of algorithms,
58 * and, where relevant, formats and input parameters, and to dispatch to the
59 * correct version at runtime.
60 *
61 * To achieve this, each algorithm provides two components:
62 *
63 * - The algorithm class template, which implements the algorithm, following
64 * a common interface. See the AlgorithmBase class for a description of
65 * the interface. Each algorithm class takes its base class as a template
66 * parameter, which allows us to construct a class hierarchy corresponding
67 * to a specific set of algorithms. Some classes in the hierarchy are not
68 * algorithms themselves, but are rather helpers, which provide some
69 * functionality to the algorithms further down the hierarchy, such as
70 * access to specific buffers.
71 *
72 * - A dispatch function, which takes the input parameters, the requested set
73 * of algorithms, the (type of) the current algorithm hierarchy, and a
74 * visitor object. The function calls the visitor with a (potentially)
75 * modified hierarchy, depending on the input. Ihe dispatch function for
76 * an algorithm checks if the requested set of algorithms contains a
77 * certain algorithm, adds the said algorithm to the hierarchy accordingly,
78 * and calls the visitor with the new hierarchy. See the AlgorithmDispatch
79 * class, which provides a dispatch-function implementation which
80 * algorithms can use instead of providing their own dispatch function.
81 *
82 * Helper classes in the hierarchy may also provide dispatch functions,
83 * which likewise modify the hierarchy based on the input parameters. For
84 * example, the dispatch_paint_mask() function adds a certain PaintMask
85 * specialization to the hierarchy, depending on the format of the paint
86 * mask buffer; this can be used to specialize algorithms based on the mask
87 * format; an algorithm that depends on the paint mask may dispatch through
88 * this function, before modifying the hierarchy itself.
89 *
90 * The dispatch() function is used to construct an algorithm hierarchy by
91 * dispatching through a list of functions. gimp_paint_core_loops_process()
92 * calls dispatch() with the full list of algorithm dispatch functions,
93 * receiving in return the algorithm hierarchy matching the input. It then
94 * uses the algorithm interface to perform the actual processing.
95 */
96
97
98 enum
99 {
100 ALGORITHM_PAINT_BUF = 1u << 31,
101 ALGORITHM_PAINT_MASK = 1u << 30,
102 ALGORITHM_STIPPLE = 1u << 29,
103 ALGORITHM_COMP_MASK = 1u << 28,
104 ALGORITHM_TEMP_COMP_MASK = 1u << 27,
105 ALGORITHM_COMP_BUFFER = 1u << 26,
106 ALGORITHM_TEMP_COMP_BUFFER = 1u << 25,
107 ALGORITHM_CANVAS_BUFFER_ITERATOR = 1u << 24,
108 ALGORITHM_MASK_BUFFER_ITERATOR = 1u << 23
109 };
110
111
112 template <class T>
113 struct identity
114 {
115 using type = T;
116 };
117
118
119 /* dispatch():
120 *
121 * Takes a list of dispatch function objects, and calls each of them, in order,
122 * with the same 'params' and 'algorithms' parameters, passing 'algorithm' as
123 * the input hierarchy to the first dispatch function, and passing the output
124 * hierarchy of the previous dispatch function as the input hierarchy for the
125 * next dispatch function. Calls 'visitor' with the output hierarchy of the
126 * last dispatch function.
127 *
128 * Each algorithm hierarchy should provide a 'filter' static data member, and
129 * each dispatch function object should provide a 'mask' static data member.
130 * If the bitwise-AND of the current hierarchy's 'filter' member and the
131 * current dispatch function's 'mask' member is equal to 'mask', the dispatch
132 * function is skipped. This can be used to make sure that a class appears
133 * only once in the hierarchy, even if its dispatch function is used multiple
134 * times, or to prevent an algorithm from being dispatched, if it cannot be
135 * used together with another algorithm.
136 */
137
138 template <class Visitor,
139 class Algorithm>
140 static inline void
dispatch(Visitor visitor,const GimpPaintCoreLoopsParams * params,GimpPaintCoreLoopsAlgorithm algorithms,identity<Algorithm> algorithm)141 dispatch (Visitor visitor,
142 const GimpPaintCoreLoopsParams *params,
143 GimpPaintCoreLoopsAlgorithm algorithms,
144 identity<Algorithm> algorithm)
145 {
146 visitor (algorithm);
147 }
148
149 template <class Algorithm,
150 class Dispatch,
151 gboolean = (Algorithm::filter & Dispatch::mask) == Dispatch::mask>
152 struct dispatch_impl
153 {
154 template <class Visitor,
155 class... DispatchRest>
156 static void
applydispatch_impl157 apply (Visitor visitor,
158 const GimpPaintCoreLoopsParams *params,
159 GimpPaintCoreLoopsAlgorithm algorithms,
160 identity<Algorithm> algorithm,
161 Dispatch disp,
162 DispatchRest... disp_rest)
163 {
164 disp (
165 [&] (auto algorithm)
166 {
167 dispatch (visitor, params, algorithms, algorithm, disp_rest...);
168 },
169 params, algorithms, algorithm);
170 }
171 };
172
173 template <class Algorithm,
174 class Dispatch>
175 struct dispatch_impl<Algorithm, Dispatch, TRUE>
176 {
177 template <class Visitor,
178 class... DispatchRest>
179 static void
applydispatch_impl180 apply (Visitor visitor,
181 const GimpPaintCoreLoopsParams *params,
182 GimpPaintCoreLoopsAlgorithm algorithms,
183 identity<Algorithm> algorithm,
184 Dispatch disp,
185 DispatchRest... disp_rest)
186 {
187 dispatch (visitor, params, algorithms, algorithm, disp_rest...);
188 }
189 };
190
191 template <class Visitor,
192 class Algorithm,
193 class Dispatch,
194 class... DispatchRest>
195 static inline void
dispatch(Visitor visitor,const GimpPaintCoreLoopsParams * params,GimpPaintCoreLoopsAlgorithm algorithms,identity<Algorithm> algorithm,Dispatch disp,DispatchRest...disp_rest)196 dispatch (Visitor visitor,
197 const GimpPaintCoreLoopsParams *params,
198 GimpPaintCoreLoopsAlgorithm algorithms,
199 identity<Algorithm> algorithm,
200 Dispatch disp,
201 DispatchRest... disp_rest)
202 {
203 dispatch_impl<Algorithm, Dispatch>::apply (
204 visitor, params, algorithms, algorithm, disp, disp_rest...);
205 }
206
207
208 /* value_to_float():
209 *
210 * Converts a component value to float.
211 */
212
213 static inline gfloat
value_to_float(guint8 value)214 value_to_float (guint8 value)
215 {
216 return value / 255.0f;
217 }
218
219 static inline gfloat
value_to_float(gfloat value)220 value_to_float (gfloat value)
221 {
222 return value;
223 }
224
225 template <class T>
226 static inline gfloat
227 value_to_float (T value) = delete;
228
229
230 /* AlgorithmBase:
231 *
232 * The base class of the algorithm hierarchy.
233 */
234
235 struct AlgorithmBase
236 {
237 /* Used to filter-out dispatch functions; see the description of dispatch().
238 * Algorithms that redefine 'filter' should bitwise-OR their filter with that
239 * of their base class.
240 */
241 static constexpr guint filter = 0;
242
243 /* The current maximal number of iterators used by the hierarchy. Algorithms
244 * should redefine 'max_n_iterators' by adding the maximal number of
245 * iterators they use to this value.
246 */
247 static constexpr gint max_n_iterators = 0;
248
249 /* Non-static data members should be initialized in the constructor, and
250 * should not be further modified.
251 */
252 explicit
AlgorithmBaseAlgorithmBase253 AlgorithmBase (const GimpPaintCoreLoopsParams *params)
254 {
255 }
256
257 /* Algorithms should store their dynamic state in the 'State' member class
258 * template. This template will be instantiated with the most-derived type
259 * of the hierarchy, which allows an algorithm to depend on the properties of
260 * its descendants. Algorithms that provide their own 'State' class should
261 * derive it from the 'State' class of their base class, passing 'Derived' as
262 * the template argument.
263 *
264 * Algorithms can be run in parallel on multiple threads. In this case, each
265 * thread uses its own 'State' object, while the algorithm object itself is
266 * either shared, or is a copy of a shared algorithm object. Either way, the
267 * algorithm object itself is immutable, while the state object is mutable.
268 */
269 template <class Derived>
270 struct State
271 {
272 };
273
274 /* The 'init()' function is called once per state object before processing
275 * starts, and should initialize the state object, and, if necessary, the
276 * iterator.
277 *
278 * 'params' is the same parameter struct passed to the constructor. 'state'
279 * is the state object. 'iter' is the iterator; each distinct state object
280 * uses a distinct iterator; if the algorithm hierarchy doesn't use any
281 * iterator, 'iter' may be NULL. 'roi' is the full region to be processed.
282 * 'area' is the subregion to be processed by the current state object.
283 *
284 * An algorithm that overrides this function should call the 'init()'
285 * function of its base class first, using the same arguments.
286 */
287 template <class Derived>
288 void
initAlgorithmBase289 init (const GimpPaintCoreLoopsParams *params,
290 State<Derived> *state,
291 GeglBufferIterator *iter,
292 const GeglRectangle *roi,
293 const GeglRectangle *area) const
294 {
295 }
296
297 /* The 'init_step()' function is called once after each
298 * 'gegl_buffer_iterator_next()' call, and should perform any necessary
299 * initialization required before processing the current chunk.
300 *
301 * The parameters are the same as for 'init()', with the addition of 'rect',
302 * which is the area of the current chunk.
303 *
304 * An algorithm that overrides this function should call the 'init_step()'
305 * function of its base class first, using the same arguments.
306 */
307 template <class Derived>
308 void
init_stepAlgorithmBase309 init_step (const GimpPaintCoreLoopsParams *params,
310 State<Derived> *state,
311 GeglBufferIterator *iter,
312 const GeglRectangle *roi,
313 const GeglRectangle *area,
314 const GeglRectangle *rect) const
315 {
316 }
317
318 /* The 'process_row()' function is called for each row in the current chunk,
319 * and should perform the actual processing.
320 *
321 * The parameters are the same as for 'init_step()', with the addition of
322 * 'y', which is the current row.
323 *
324 * An algorithm that overrides this function should call the 'process_row()'
325 * function of its base class first, using the same arguments.
326 */
327 template <class Derived>
328 void
process_rowAlgorithmBase329 process_row (const GimpPaintCoreLoopsParams *params,
330 State<Derived> *state,
331 GeglBufferIterator *iter,
332 const GeglRectangle *roi,
333 const GeglRectangle *area,
334 const GeglRectangle *rect,
335 gint y) const
336 {
337 }
338
339 /* The 'finalize_step()' function is called once per chunk after its
340 * processing is done, and should finalize any chunk-specific resources of
341 * the state object.
342 *
343 * 'params' is the same parameter struct passed to the constructor. 'state'
344 * is the state object.
345 *
346 * An algorithm that overrides this function should call the
347 * 'finalize_step()' function of its base class after performing its own
348 * finalization, using the same arguments.
349 */
350 template <class Derived>
351 void
finalize_stepAlgorithmBase352 finalize_step (const GimpPaintCoreLoopsParams *params,
353 State<Derived> *state) const
354 {
355 }
356
357 /* The 'finalize()' function is called once per state object after processing
358 * is done, and should finalize the state object.
359 *
360 * 'params' is the same parameter struct passed to the constructor. 'state'
361 * is the state object.
362 *
363 * An algorithm that overrides this function should call the 'finalize()'
364 * function of its base class after performing its own finalization, using
365 * the same arguments.
366 */
367 template <class Derived>
368 void
finalizeAlgorithmBase369 finalize (const GimpPaintCoreLoopsParams *params,
370 State<Derived> *state) const
371 {
372 }
373 };
374
375
376 /* BasicDispatch:
377 *
378 * A class template implementing a simple dispatch function object, which adds
379 * an algorithm to the hierarchy unconditionally. 'AlgorithmTemplate' is the
380 * alogithm class template (usually a helper class, rather than an actual
381 * algorithm), 'Mask' is the dispatch function mask, as described in
382 * 'dispatch()', and 'Dependencies' is a list of (types of) dispatch functions
383 * the algorithm depends on.
384 *
385 * Before adding the algorithm to the hierarchy, the hierarchy is augmented by
386 * dispatching through the list of dependencies, in order.
387 */
388
389 template <template <class Base> class AlgorithmTemplate,
390 guint Mask,
391 class... Dependencies>
392 struct BasicDispatch
393 {
394 static constexpr guint mask = Mask;
395
396 template <class Visitor,
397 class Algorithm>
398 void
operator ()BasicDispatch399 operator () (Visitor visitor,
400 const GimpPaintCoreLoopsParams *params,
401 GimpPaintCoreLoopsAlgorithm algorithms,
402 identity<Algorithm> algorithm) const
403 {
404 dispatch (
405 [&] (auto algorithm)
406 {
407 using NewAlgorithm = typename decltype (algorithm)::type;
408
409 visitor (identity<AlgorithmTemplate<NewAlgorithm>> ());
410 },
411 params, algorithms, algorithm, Dependencies ()...);
412 }
413 };
414
415 template <template <class Base> class AlgorithmTemplate,
416 guint Mask>
417 struct BasicDispatch<AlgorithmTemplate, Mask>
418 {
419 static constexpr guint mask = Mask;
420
421 template <class Visitor,
422 class Algorithm>
423 void
operator ()BasicDispatch424 operator () (Visitor visitor,
425 const GimpPaintCoreLoopsParams *params,
426 GimpPaintCoreLoopsAlgorithm algorithms,
427 identity<Algorithm> algorithm) const
428 {
429 visitor (identity<AlgorithmTemplate<Algorithm>> ());
430 }
431 };
432
433
434 /* AlgorithmDispatch:
435 *
436 * A class template implementing a dispatch function suitable for dispatching
437 * algorithms. 'AlgorithmTemplate' is the algorithm class template, 'Mask' is
438 * the dispatch function mask, as described in 'dispatch()', and 'Dependencies'
439 * is a list of (types of) dispatch functions the algorithm depends on, used as
440 * explained below.
441 *
442 * 'AlgorithmDispatch' adds the algorithm to the hierarchy if it's included in
443 * the set of requested algorithms; specifically, if the bitwise-AND of the
444 * requested-algorithms bitset and of 'Mask' is equal to 'Mask'.
445 *
446 * Before adding the algorithm to the hierarchy, the hierarchy is augmented by
447 * dispatching through the list of dependencies, in order.
448 */
449
450 template <template <class Base> class AlgorithmTemplate,
451 guint Mask,
452 class... Dependencies>
453 struct AlgorithmDispatch
454 {
455 static constexpr guint mask = Mask;
456
457 template <class Visitor,
458 class Algorithm>
459 void
operator ()AlgorithmDispatch460 operator () (Visitor visitor,
461 const GimpPaintCoreLoopsParams *params,
462 GimpPaintCoreLoopsAlgorithm algorithms,
463 identity<Algorithm> algorithm) const
464 {
465 if ((algorithms & mask) == mask)
466 {
467 dispatch (
468 [&] (auto algorithm)
469 {
470 using NewAlgorithm = typename decltype (algorithm)::type;
471
472 visitor (identity<AlgorithmTemplate<NewAlgorithm>> ());
473 },
474 params, algorithms, algorithm, Dependencies ()...);
475 }
476 else
477 {
478 visitor (algorithm);
479 }
480 }
481 };
482
483
484 /* MandatoryAlgorithmDispatch:
485 *
486 * A class template implementing a dispatch function suitable for dispatching
487 * algorithms that must be included in all hierarchies. 'AlgorithmTemplate' is
488 * the algorithm class template, 'Mask' is the dispatch function mask, as
489 * described in 'dispatch()', and 'Dependencies' is a list of (types of)
490 * dispatch functions the algorithm depends on, used as explained below.
491 *
492 * 'MandatoryAlgorithmDispatch' verifies that the algorithm is included in the
493 * set of requested algorithms (specifically, that the bitwise-AND of the
494 * requested-algorithms bitset and of 'Mask' is equal to 'Mask'), and adds the
495 * it to the hierarchy unconditionally.
496 *
497 * Before adding the algorithm to the hierarchy, the hierarchy is augmented by
498 * dispatching through the list of dependencies, in order.
499 */
500
501 template <template <class Base> class AlgorithmTemplate,
502 guint Mask,
503 class... Dependencies>
504 struct MandatoryAlgorithmDispatch
505 {
506 static constexpr guint mask = Mask;
507
508 template <class Visitor,
509 class Algorithm>
510 void
operator ()MandatoryAlgorithmDispatch511 operator () (Visitor visitor,
512 const GimpPaintCoreLoopsParams *params,
513 GimpPaintCoreLoopsAlgorithm algorithms,
514 identity<Algorithm> algorithm) const
515 {
516 g_return_if_fail ((algorithms & Mask) == Mask);
517
518 BasicDispatch<AlgorithmTemplate, Mask, Dependencies...> () (visitor,
519 params,
520 algorithms,
521 algorithm);
522 }
523 };
524
525 /* SuppressedAlgorithmDispatch:
526 *
527 * A class template implementing a placeholder dispatch function suitable for
528 * dispatching algorithms that are never included in any hierarchy.
529 * 'AlgorithmTemplate' is the algorithm class template, 'Mask' is the dispatch
530 * function mask, as described in 'dispatch()', and 'Dependencies' is a list of
531 * (types of) dispatch functions the algorithm depends on. Note that
532 * 'AlgorithmTemplate' and 'Dependencies' are not actually used, and are merely
533 * included for exposition.
534 *
535 * 'SuppressedAlgorithmDispatch' verifies that the algorithm is not included in
536 * the set of requested algorithms (specifically, that the bitwise-AND of the
537 * requested-algorithms bitset and of 'Mask' is not equal to 'Mask'), and
538 * doesn't modify the hierarchy.
539 */
540
541 template <template <class Base> class AlgorithmTemplate,
542 guint Mask,
543 class... Dependencies>
544 struct SuppressedAlgorithmDispatch
545 {
546 static constexpr guint mask = Mask;
547
548 template <class Visitor,
549 class Algorithm>
550 void
operator ()SuppressedAlgorithmDispatch551 operator () (Visitor visitor,
552 const GimpPaintCoreLoopsParams *params,
553 GimpPaintCoreLoopsAlgorithm algorithms,
554 identity<Algorithm> algorithm) const
555 {
556 g_return_if_fail ((algorithms & Mask) != Mask);
557
558 visitor (algorithm);
559 }
560 };
561
562
563 /* PaintBuf, dispatch_paint_buf():
564 *
565 * An algorithm helper class, providing access to the paint buffer. Algorithms
566 * that use the paint buffer should specify 'dispatch_paint_buf()' as a
567 * dependency, and access 'PaintBuf' members through their base type/subobject.
568 */
569
570 template <class Base>
571 struct PaintBuf : Base
572 {
573 /* Component type of the paint buffer. */
574 using paint_type = gfloat;
575
576 static constexpr guint filter = Base::filter | ALGORITHM_PAINT_BUF;
577
578 /* Paint buffer stride, in 'paint_type' elements. */
579 gint paint_stride;
580 /* Pointer to the start of the paint buffer data. */
581 paint_type *paint_data;
582
583 explicit
PaintBufPaintBuf584 PaintBuf (const GimpPaintCoreLoopsParams *params) :
585 Base (params)
586 {
587 paint_stride = gimp_temp_buf_get_width (params->paint_buf) * 4;
588 paint_data = (paint_type *) gimp_temp_buf_get_data (params->paint_buf);
589 }
590 };
591
592 static BasicDispatch<PaintBuf, ALGORITHM_PAINT_BUF> dispatch_paint_buf;
593
594
595 /* PaintMask, dispatch_paint_mask():
596 *
597 * An algorithm helper class, providing access to the paint mask. Algorithms
598 * that use the paint mask should specify 'dispatch_paint_mask()' as a
599 * dependency, and access 'PaintMask' members through their base type/
600 * subobject.
601 */
602
603 template <class Base,
604 class MaskType>
605 struct PaintMask : Base
606 {
607 /* Component type of the paint mask. */
608 using mask_type = MaskType;
609
610 static constexpr guint filter = Base::filter | ALGORITHM_PAINT_MASK;
611
612 /* Paint mask stride, in 'mask_type' elements. */
613 gint mask_stride;
614 /* Pointer to the start of the paint mask data, taking the mask offset into
615 * account.
616 */
617 const mask_type *mask_data;
618
619 explicit
PaintMaskPaintMask620 PaintMask (const GimpPaintCoreLoopsParams *params) :
621 Base (params)
622 {
623 mask_stride = gimp_temp_buf_get_width (params->paint_mask);
624 mask_data =
625 (const mask_type *) gimp_temp_buf_get_data (params->paint_mask) +
626 params->paint_mask_offset_y * mask_stride +
627 params->paint_mask_offset_x;
628 }
629 };
630
631 struct DispatchPaintMask
632 {
633 static constexpr guint mask = ALGORITHM_PAINT_MASK;
634
635 template <class Visitor,
636 class Algorithm>
637 void
operator ()DispatchPaintMask638 operator () (Visitor visitor,
639 const GimpPaintCoreLoopsParams *params,
640 GimpPaintCoreLoopsAlgorithm algorithms,
641 identity<Algorithm> algorithm) const
642 {
643 const Babl *mask_format = gimp_temp_buf_get_format (params->paint_mask);
644
645 if (mask_format == babl_format ("Y u8"))
646 visitor (identity<PaintMask<Algorithm, guint8>> ());
647 else if (mask_format == babl_format ("Y float"))
648 visitor (identity<PaintMask<Algorithm, gfloat>> ());
649 else
650 g_warning ("Mask format not supported: %s", babl_get_name (mask_format));
651 }
652 } static dispatch_paint_mask;
653
654
655 /* Stipple, dispatch_stipple():
656 *
657 * An algorithm helper class, providing access to the 'stipple' parameter.
658 * Algorithms that use the 'stipple' parameter should specify
659 * 'dispatch_stipple()' as a dependency, and access 'Stipple' members through
660 * their base type/subobject.
661 */
662
663 template <class Base,
664 gboolean StippleFlag>
665 struct Stipple : Base
666 {
667 static constexpr guint filter = Base::filter | ALGORITHM_STIPPLE;
668
669 /* The value of the 'stipple' parameter, usable as a constant expression. */
670 static constexpr gboolean stipple = StippleFlag;
671
672 using Base::Base;
673 };
674
675 struct DispatchStipple
676 {
677 static constexpr guint mask = ALGORITHM_STIPPLE;
678
679 template <class Visitor,
680 class Algorithm>
681 void
operator ()DispatchStipple682 operator () (Visitor visitor,
683 const GimpPaintCoreLoopsParams *params,
684 GimpPaintCoreLoopsAlgorithm algorithms,
685 identity<Algorithm> algorithm) const
686 {
687 if (params->stipple)
688 visitor (identity<Stipple<Algorithm, TRUE>> ());
689 else
690 visitor (identity<Stipple<Algorithm, FALSE>> ());
691 }
692 } static dispatch_stipple;
693
694
695 /* CompMask, dispatch_comp_mask(), has_comp_mask(), comp_mask_data():
696 *
697 * An algorithm helper class, providing access to the mask used for
698 * compositing. When this class is part of the hierarchy, 'DoLayerBlend' uses
699 * this buffer as the mask, instead of the input parameters' 'mask_buffer'.
700 * Algorithms that use the compositing mask should specify
701 * 'dispatch_comp_mask()' as a dependency, and access 'CompMask' members
702 * through their base type/subobject.
703 *
704 * Note that 'CompMask' only provides *access* to the compositing mask, but
705 * doesn't provide its actual *storage*. This is the responsibility of the
706 * algorithms that use 'CompMask'. Algorithms that need temporary storage for
707 * the compositing mask can use 'TempCompMask'.
708 *
709 * The 'has_comp_mask()' constexpr function determines if a given algorithm
710 * hierarchy uses the compositing mask.
711 *
712 * The 'comp_mask_data()' function returns a pointer to the compositing mask
713 * data for the current row if the hierarchy uses the compositing mask, or NULL
714 * otherwise.
715 */
716
717 template <class Base>
718 struct CompMask : Base
719 {
720 /* Component type of the compositing mask. */
721 using comp_mask_type = gfloat;
722
723 static constexpr guint filter = Base::filter | ALGORITHM_COMP_MASK;
724
725 using Base::Base;
726
727 template <class Derived>
728 struct State : Base::template State<Derived>
729 {
730 /* Pointer to the compositing mask data for the current row. */
731 comp_mask_type *comp_mask_data;
732 };
733 };
734
735 static BasicDispatch<CompMask, ALGORITHM_COMP_MASK> dispatch_comp_mask;
736
737 template <class Base>
738 static constexpr gboolean
has_comp_mask(const CompMask<Base> * algorithm)739 has_comp_mask (const CompMask<Base> *algorithm)
740 {
741 return TRUE;
742 }
743
744 static constexpr gboolean
has_comp_mask(const AlgorithmBase * algorithm)745 has_comp_mask (const AlgorithmBase *algorithm)
746 {
747 return FALSE;
748 }
749
750 template <class Base,
751 class State>
752 static gfloat *
comp_mask_data(const CompMask<Base> * algorithm,State * state)753 comp_mask_data (const CompMask<Base> *algorithm,
754 State *state)
755 {
756 return state->comp_mask_data;
757 }
758
759 template <class State>
760 static gfloat *
comp_mask_data(const AlgorithmBase * algorithm,State * state)761 comp_mask_data (const AlgorithmBase *algorithm,
762 State *state)
763 {
764 return NULL;
765 }
766
767
768 /* TempCompMask, dispatch_temp_comp_mask():
769 *
770 * An algorithm helper class, providing temporary storage for the compositing
771 * mask. Algorithms that need a temporary compositing mask should specify
772 * 'dispatch_temp_comp_mask()' as a dependency, which itself includes
773 * 'dispatch_comp_mask()' as a dependency.
774 */
775
776 template <class Base>
777 struct TempCompMask : Base
778 {
779 static constexpr guint filter = Base::filter | ALGORITHM_TEMP_COMP_MASK;
780
781 using Base::Base;
782
783 template <class Derived>
784 using State = typename Base::template State<Derived>;
785
786 template <class Derived>
787 void
init_stepTempCompMask788 init_step (const GimpPaintCoreLoopsParams *params,
789 State<Derived> *state,
790 GeglBufferIterator *iter,
791 const GeglRectangle *roi,
792 const GeglRectangle *area,
793 const GeglRectangle *rect) const
794 {
795 Base::init_step (params, state, iter, roi, area, rect);
796
797 state->comp_mask_data = gegl_scratch_new (gfloat, rect->width);
798 }
799
800
801 template <class Derived>
802 void
finalize_stepTempCompMask803 finalize_step (const GimpPaintCoreLoopsParams *params,
804 State<Derived> *state) const
805 {
806 gegl_scratch_free (state->comp_mask_data);
807
808 Base::finalize_step (params, state);
809 }
810 };
811
812 static BasicDispatch<
813 TempCompMask,
814 ALGORITHM_TEMP_COMP_MASK,
815 decltype (dispatch_comp_mask)
816 > dispatch_temp_comp_mask;
817
818
819 /* CompBuffer, dispatch_comp_buffer(), has_comp_buffer(), comp_buffer_data():
820 *
821 * An algorithm helper class, providing access to the output buffer used for
822 * compositing. When this class is part of the hierarchy, 'DoLayerBlend' uses
823 * this buffer as the output buffer, instead of the input parameters'
824 * 'dest_buffer'. Algorithms that use the compositing buffer should specify
825 * 'dispatch_comp_buffer()' as a dependency, and access 'CompBuffer' members
826 * through their base type/subobject.
827 *
828 * Note that 'CompBuffer' only provides *access* to the compositing buffer, but
829 * doesn't provide its actual *storage*. This is the responsibility of the
830 * algorithms that use 'CompBuffer'. Algorithms that need temporary storage
831 * for the compositing buffer can use 'TempCompBuffer'.
832 *
833 * The 'has_comp_buffer()' constexpr function determines if a given algorithm
834 * hierarchy uses the compositing buffer.
835 *
836 * The 'comp_buffer_data()' function returns a pointer to the compositing
837 * buffer data for the current row if the hierarchy uses the compositing
838 * buffer, or NULL otherwise.
839 */
840
841 template <class Base>
842 struct CompBuffer : Base
843 {
844 /* Component type of the compositing buffer. */
845 using comp_buffer_type = gfloat;
846
847 static constexpr guint filter = Base::filter | ALGORITHM_COMP_BUFFER;
848
849 using Base::Base;
850
851 template <class Derived>
852 struct State : Base::template State<Derived>
853 {
854 /* Pointer to the compositing buffer data for the current row. */
855 comp_buffer_type *comp_buffer_data;
856 };
857 };
858
859 static BasicDispatch<CompBuffer, ALGORITHM_COMP_BUFFER> dispatch_comp_buffer;
860
861 template <class Base>
862 static constexpr gboolean
has_comp_buffer(const CompBuffer<Base> * algorithm)863 has_comp_buffer (const CompBuffer<Base> *algorithm)
864 {
865 return TRUE;
866 }
867
868 static constexpr gboolean
has_comp_buffer(const AlgorithmBase * algorithm)869 has_comp_buffer (const AlgorithmBase *algorithm)
870 {
871 return FALSE;
872 }
873
874 template <class Base,
875 class State>
876 static gfloat *
comp_buffer_data(const CompBuffer<Base> * algorithm,State * state)877 comp_buffer_data (const CompBuffer<Base> *algorithm,
878 State *state)
879 {
880 return state->comp_buffer_data;
881 }
882
883 template <class State>
884 static gfloat *
comp_buffer_data(const AlgorithmBase * algorithm,State * state)885 comp_buffer_data (const AlgorithmBase *algorithm,
886 State *state)
887 {
888 return NULL;
889 }
890
891
892 /* TempCompBuffer, dispatch_temp_comp_buffer():
893 *
894 * An algorithm helper class, providing temporary storage for the compositing
895 * buffer. Algorithms that need a temporary compositing buffer should specify
896 * 'dispatch_temp_comp_buffer()' as a dependency, which itself includes
897 * 'dispatch_comp_buffer()' as a dependency.
898 */
899
900 template <class Base>
901 struct TempCompBuffer : Base
902 {
903 static constexpr guint filter = Base::filter | ALGORITHM_TEMP_COMP_BUFFER;
904
905 using Base::Base;
906
907 template <class Derived>
908 using State = typename Base::template State<Derived>;
909
910 template <class Derived>
911 void
init_stepTempCompBuffer912 init_step (const GimpPaintCoreLoopsParams *params,
913 State<Derived> *state,
914 GeglBufferIterator *iter,
915 const GeglRectangle *roi,
916 const GeglRectangle *area,
917 const GeglRectangle *rect) const
918 {
919 Base::init_step (params, state, iter, roi, area, rect);
920
921 state->comp_buffer_data = gegl_scratch_new (gfloat, 4 * rect->width);
922 }
923
924
925 template <class Derived>
926 void
finalize_stepTempCompBuffer927 finalize_step (const GimpPaintCoreLoopsParams *params,
928 State<Derived> *state) const
929 {
930 gegl_scratch_free (state->comp_buffer_data);
931
932 Base::finalize_step (params, state);
933 }
934 };
935
936 static BasicDispatch<
937 TempCompBuffer,
938 ALGORITHM_TEMP_COMP_BUFFER,
939 decltype (dispatch_comp_buffer)
940 > dispatch_temp_comp_buffer;
941
942
943 /* CanvasBufferIterator, DispatchCanvasBufferIterator:
944 *
945 * An algorithm helper class, providing iterator-access to the canvas buffer.
946 * Algorithms that iterate over the canvas buffer should specify
947 * 'DispatchCanvasBufferIterator<Access>' as a dependency, where 'Access' is
948 * the desired access mode to the canvas buffer, and access its members through
949 * their base type/subobject.
950 */
951
952 template <class Base,
953 guint Access,
954 gboolean First>
955 struct CanvasBufferIterator;
956
957 template <class Base,
958 guint Access>
959 static constexpr gboolean
canvas_buffer_iterator_is_first(CanvasBufferIterator<Base,Access,TRUE> * algorithm)960 canvas_buffer_iterator_is_first (CanvasBufferIterator<Base, Access, TRUE> *algorithm)
961 {
962 return FALSE;
963 }
964
965 static constexpr gboolean
canvas_buffer_iterator_is_first(AlgorithmBase * algorithm)966 canvas_buffer_iterator_is_first (AlgorithmBase *algorithm)
967 {
968 return TRUE;
969 }
970
971 template <class Base,
972 guint Access,
973 gboolean First = canvas_buffer_iterator_is_first ((Base *) NULL)>
974 struct CanvasBufferIterator : Base
975 {
976 /* The combined canvas-buffer access mode used by the hierarchy, up to, and
977 * including, the current class.
978 */
979 static constexpr GeglAccessMode canvas_buffer_access =
980 (GeglAccessMode) (Base::canvas_buffer_access | Access);
981
982 using Base::Base;
983 };
984
985 template <class Base,
986 guint Access>
987 struct CanvasBufferIterator<Base, Access, TRUE> : Base
988 {
989 /* The combined canvas-buffer access mode used by the hierarchy, up to, and
990 * including, the current class.
991 */
992 static constexpr GeglAccessMode canvas_buffer_access =
993 (GeglAccessMode) Access;
994
995 static constexpr gint max_n_iterators =
996 Base::max_n_iterators + 1;
997
998 using Base::Base;
999
1000 template <class Derived>
1001 struct State : Base::template State<Derived>
1002 {
1003 gint canvas_buffer_iterator;
1004 };
1005
1006 template <class Derived>
1007 void
initCanvasBufferIterator1008 init (const GimpPaintCoreLoopsParams *params,
1009 State<Derived> *state,
1010 GeglBufferIterator *iter,
1011 const GeglRectangle *roi,
1012 const GeglRectangle *area) const
1013 {
1014 state->canvas_buffer_iterator = gegl_buffer_iterator_add (
1015 iter, params->canvas_buffer, area, 0, babl_format ("Y float"),
1016 Derived::canvas_buffer_access, GEGL_ABYSS_NONE);
1017
1018 /* initialize the base class *after* initializing the iterator, to make
1019 * sure that canvas_buffer is the primary buffer of the iterator, if no
1020 * subclass added an iterator first.
1021 */
1022 Base::init (params, state, iter, roi, area);
1023 }
1024 };
1025
1026 template <guint Access>
1027 struct DispatchCanvasBufferIteratorHelper
1028 {
1029 template <class Base>
1030 using algorithm_template = CanvasBufferIterator<Base, Access>;
1031 };
1032
1033 template <guint Access>
1034 using DispatchCanvasBufferIterator = BasicDispatch<
1035 DispatchCanvasBufferIteratorHelper<Access>::template algorithm_template,
1036 ALGORITHM_CANVAS_BUFFER_ITERATOR
1037 >;
1038
1039
1040 /* MaskBufferIterator, mask_buffer_iterator_dispatch(),
1041 * has_mask_buffer_iterator():
1042 *
1043 * An algorithm helper class, providing read-only iterator-access to the mask
1044 * buffer. Algorithms that iterate over the mask buffer should specify
1045 * 'dispatch_mask_buffer_iterator()' as a dependency, and access
1046 * 'MaskBufferIterator' members through their base type/subobject.
1047 *
1048 * The 'has_mask_buffer_iterator()' constexpr function determines if a given
1049 * algorithm hierarchy uses has a mask-buffer iterator.
1050 *
1051 * The 'mask_buffer_iterator()' function returns the index of the mask-buffer
1052 * iterator if the hierarchy has one, or -1 otherwise.
1053 */
1054
1055 template <class Base>
1056 struct MaskBufferIterator : Base
1057 {
1058 static constexpr guint filter = Base::filter | ALGORITHM_MASK_BUFFER_ITERATOR;
1059
1060 static constexpr gint max_n_iterators = Base::max_n_iterators + 1;
1061
1062 using Base::Base;
1063
1064 template <class Derived>
1065 struct State : Base::template State<Derived>
1066 {
1067 gint mask_buffer_iterator;
1068 };
1069
1070 template <class Derived>
1071 void
initMaskBufferIterator1072 init (const GimpPaintCoreLoopsParams *params,
1073 State<Derived> *state,
1074 GeglBufferIterator *iter,
1075 const GeglRectangle *roi,
1076 const GeglRectangle *area) const
1077 {
1078 Base::init (params, state, iter, roi, area);
1079
1080 GeglRectangle mask_area = *area;
1081
1082 mask_area.x -= params->mask_offset_x;
1083 mask_area.y -= params->mask_offset_y;
1084
1085 state->mask_buffer_iterator = gegl_buffer_iterator_add (
1086 iter, params->mask_buffer, &mask_area, 0, babl_format ("Y float"),
1087 GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
1088 }
1089 };
1090
1091 struct DispatchMaskBufferIterator
1092 {
1093 static constexpr guint mask = ALGORITHM_MASK_BUFFER_ITERATOR;
1094
1095 template <class Visitor,
1096 class Algorithm>
1097 void
operator ()DispatchMaskBufferIterator1098 operator () (Visitor visitor,
1099 const GimpPaintCoreLoopsParams *params,
1100 GimpPaintCoreLoopsAlgorithm algorithms,
1101 identity<Algorithm> algorithm) const
1102 {
1103 if (params->mask_buffer)
1104 visitor (identity<MaskBufferIterator<Algorithm>> ());
1105 else
1106 visitor (algorithm);
1107 }
1108 } static dispatch_mask_buffer_iterator;
1109
1110 template <class Base>
1111 static constexpr gboolean
has_mask_buffer_iterator(const MaskBufferIterator<Base> * algorithm)1112 has_mask_buffer_iterator (const MaskBufferIterator<Base> *algorithm)
1113 {
1114 return TRUE;
1115 }
1116
1117 static constexpr gboolean
has_mask_buffer_iterator(const AlgorithmBase * algorithm)1118 has_mask_buffer_iterator (const AlgorithmBase *algorithm)
1119 {
1120 return FALSE;
1121 }
1122
1123 template <class Base,
1124 class State>
1125 static gint
mask_buffer_iterator(const MaskBufferIterator<Base> * algorithm,State * state)1126 mask_buffer_iterator (const MaskBufferIterator<Base> *algorithm,
1127 State *state)
1128 {
1129 return state->mask_buffer_iterator;
1130 }
1131
1132 template <class State>
1133 static gint
mask_buffer_iterator(const AlgorithmBase * algorithm,State * state)1134 mask_buffer_iterator (const AlgorithmBase *algorithm,
1135 State *state)
1136 {
1137 return -1;
1138 }
1139
1140
1141 /* CombinePaintMaskToCanvasBufferToPaintBufAlpha,
1142 * dispatch_combine_paint_mask_to_canvas_buffer_to_paint_buf_alpha():
1143 *
1144 * An algorithm class, providing an optimized version combining both the
1145 * COMBINE_PAINT_MASK_TO_CANVAS_BUFFER and the CANVAS_BUFFER_TO_PAINT_BUF_ALPHA
1146 * algorithms. Used instead of the individual implementations, when both
1147 * algorithms are requested.
1148 */
1149
1150 template <class Base>
1151 struct CombinePaintMaskToCanvasBufferToPaintBufAlpha : Base
1152 {
1153 using mask_type = typename Base::mask_type;
1154
1155 static constexpr guint filter =
1156 Base::filter |
1157 GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER |
1158 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA |
1159 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA |
1160 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
1161 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1162
1163 using Base::Base;
1164
1165 template <class Derived>
1166 struct State : Base::template State<Derived>
1167 {
1168 gfloat *canvas_pixel;
1169 };
1170
1171 template <class Derived>
1172 void
init_stepCombinePaintMaskToCanvasBufferToPaintBufAlpha1173 init_step (const GimpPaintCoreLoopsParams *params,
1174 State<Derived> *state,
1175 GeglBufferIterator *iter,
1176 const GeglRectangle *roi,
1177 const GeglRectangle *area,
1178 const GeglRectangle *rect) const
1179 {
1180 Base::init_step (params, state, iter, roi, area, rect);
1181
1182 state->canvas_pixel =
1183 (gfloat *) iter->items[state->canvas_buffer_iterator].data;
1184 }
1185
1186 template <class Derived>
1187 void
process_rowCombinePaintMaskToCanvasBufferToPaintBufAlpha1188 process_row (const GimpPaintCoreLoopsParams *params,
1189 State<Derived> *state,
1190 GeglBufferIterator *iter,
1191 const GeglRectangle *roi,
1192 const GeglRectangle *area,
1193 const GeglRectangle *rect,
1194 gint y) const
1195 {
1196 Base::process_row (params, state, iter, roi, area, rect, y);
1197
1198 gint mask_offset = (y - roi->y) * this->mask_stride +
1199 (rect->x - roi->x);
1200 const mask_type *mask_pixel = &this->mask_data[mask_offset];
1201 gint paint_offset = (y - roi->y) * this->paint_stride +
1202 (rect->x - roi->x) * 4;
1203 gfloat *paint_pixel = &this->paint_data[paint_offset];
1204 gint x;
1205
1206 for (x = 0; x < rect->width; x++)
1207 {
1208 if (Base::stipple)
1209 {
1210 state->canvas_pixel[0] += (1.0 - state->canvas_pixel[0]) *
1211 value_to_float (*mask_pixel) *
1212 params->paint_opacity;
1213 }
1214 else
1215 {
1216 if (params->paint_opacity > state->canvas_pixel[0])
1217 {
1218 state->canvas_pixel[0] += (params->paint_opacity - state->canvas_pixel[0]) *
1219 value_to_float (*mask_pixel) *
1220 params->paint_opacity;
1221 }
1222 }
1223
1224 paint_pixel[3] *= state->canvas_pixel[0];
1225
1226 mask_pixel += 1;
1227 state->canvas_pixel += 1;
1228 paint_pixel += 4;
1229 }
1230 }
1231 };
1232
1233 static SuppressedAlgorithmDispatch<
1234 CombinePaintMaskToCanvasBufferToPaintBufAlpha,
1235 GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER |
1236 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA,
1237 decltype (dispatch_paint_buf),
1238 decltype (dispatch_paint_mask),
1239 decltype (dispatch_stipple),
1240 DispatchCanvasBufferIterator<GEGL_BUFFER_READWRITE>
1241 >
1242 dispatch_combine_paint_mask_to_canvas_buffer_to_paint_buf_alpha;
1243
1244
1245 /* CombinePaintMaskToCanvasBuffer,
1246 * dispatch_combine_paint_mask_to_canvas_buffer():
1247 *
1248 * An algorithm class, implementing the COMBINE_PAINT_MASK_TO_CANVAS_BUFFER
1249 * algorithm.
1250 */
1251
1252 template <class Base>
1253 struct CombinePaintMaskToCanvasBuffer : Base
1254 {
1255 using mask_type = typename Base::mask_type;
1256
1257 static constexpr guint filter =
1258 Base::filter |
1259 GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER |
1260 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA |
1261 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA |
1262 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1263
1264 using Base::Base;
1265
1266 template <class Derived>
1267 struct State : Base::template State<Derived>
1268 {
1269 gfloat *canvas_pixel;
1270 };
1271
1272 template <class Derived>
1273 void
init_stepCombinePaintMaskToCanvasBuffer1274 init_step (const GimpPaintCoreLoopsParams *params,
1275 State<Derived> *state,
1276 GeglBufferIterator *iter,
1277 const GeglRectangle *roi,
1278 const GeglRectangle *area,
1279 const GeglRectangle *rect) const
1280 {
1281 Base::init_step (params, state, iter, roi, area, rect);
1282
1283 state->canvas_pixel =
1284 (gfloat *) iter->items[state->canvas_buffer_iterator].data;
1285 }
1286
1287 template <class Derived>
1288 void
process_rowCombinePaintMaskToCanvasBuffer1289 process_row (const GimpPaintCoreLoopsParams *params,
1290 State<Derived> *state,
1291 GeglBufferIterator *iter,
1292 const GeglRectangle *roi,
1293 const GeglRectangle *area,
1294 const GeglRectangle *rect,
1295 gint y) const
1296 {
1297 Base::process_row (params, state, iter, roi, area, rect, y);
1298
1299 gint mask_offset = (y - roi->y) * this->mask_stride +
1300 (rect->x - roi->x);
1301 const mask_type *mask_pixel = &this->mask_data[mask_offset];
1302 gint x;
1303
1304 for (x = 0; x < rect->width; x++)
1305 {
1306 if (Base::stipple)
1307 {
1308 state->canvas_pixel[0] += (1.0 - state->canvas_pixel[0]) *
1309 value_to_float (*mask_pixel) *
1310 params->paint_opacity;
1311 }
1312 else
1313 {
1314 if (params->paint_opacity > state->canvas_pixel[0])
1315 {
1316 state->canvas_pixel[0] += (params->paint_opacity - state->canvas_pixel[0]) *
1317 value_to_float (*mask_pixel) *
1318 params->paint_opacity;
1319 }
1320 }
1321
1322 mask_pixel += 1;
1323 state->canvas_pixel += 1;
1324 }
1325 }
1326 };
1327
1328 static AlgorithmDispatch<
1329 CombinePaintMaskToCanvasBuffer,
1330 GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER,
1331 decltype (dispatch_paint_mask),
1332 decltype (dispatch_stipple),
1333 DispatchCanvasBufferIterator<GEGL_BUFFER_READWRITE>
1334 >
1335 dispatch_combine_paint_mask_to_canvas_buffer;
1336
1337
1338 /* CanvasBufferToPaintBufAlpha, dispatch_canvas_buffer_to_paint_buf_alpha():
1339 *
1340 * An algorithm class, implementing the CANVAS_BUFFER_TO_PAINT_BUF_ALPHA
1341 * algorithm.
1342 */
1343
1344 template <class Base>
1345 struct CanvasBufferToPaintBufAlpha : Base
1346 {
1347 static constexpr guint filter =
1348 Base::filter |
1349 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA |
1350 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA |
1351 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
1352 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1353
1354 using Base::Base;
1355
1356 template <class Derived>
1357 struct State : Base::template State<Derived>
1358 {
1359 const gfloat *canvas_pixel;
1360 };
1361
1362 template <class Derived>
1363 void
init_stepCanvasBufferToPaintBufAlpha1364 init_step (const GimpPaintCoreLoopsParams *params,
1365 State<Derived> *state,
1366 GeglBufferIterator *iter,
1367 const GeglRectangle *roi,
1368 const GeglRectangle *area,
1369 const GeglRectangle *rect) const
1370 {
1371 Base::init_step (params, state, iter, roi, area, rect);
1372
1373 state->canvas_pixel =
1374 (const gfloat *) iter->items[state->canvas_buffer_iterator].data;
1375 }
1376
1377 template <class Derived>
1378 void
process_rowCanvasBufferToPaintBufAlpha1379 process_row (const GimpPaintCoreLoopsParams *params,
1380 State<Derived> *state,
1381 GeglBufferIterator *iter,
1382 const GeglRectangle *roi,
1383 const GeglRectangle *area,
1384 const GeglRectangle *rect,
1385 gint y) const
1386 {
1387 Base::process_row (params, state, iter, roi, area, rect, y);
1388
1389 /* Copy the canvas buffer in rect to the paint buffer's alpha channel */
1390
1391 gint paint_offset = (y - roi->y) * this->paint_stride +
1392 (rect->x - roi->x) * 4;
1393 gfloat *paint_pixel = &this->paint_data[paint_offset];
1394 gint x;
1395
1396 for (x = 0; x < rect->width; x++)
1397 {
1398 paint_pixel[3] *= *state->canvas_pixel;
1399
1400 state->canvas_pixel += 1;
1401 paint_pixel += 4;
1402 }
1403 }
1404 };
1405
1406 static SuppressedAlgorithmDispatch<
1407 CanvasBufferToPaintBufAlpha,
1408 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA,
1409 decltype (dispatch_paint_buf),
1410 DispatchCanvasBufferIterator<GEGL_BUFFER_READ>
1411 >
1412 dispatch_canvas_buffer_to_paint_buf_alpha;
1413
1414
1415 /* PaintMaskToPaintBufAlpha, dispatch_paint_mask_to_paint_buf_alpha():
1416 *
1417 * An algorithm class, implementing the PAINT_MASK_TO_PAINT_BUF_ALPHA
1418 * algorithm.
1419 */
1420
1421 template <class Base>
1422 struct PaintMaskToPaintBufAlpha : Base
1423 {
1424 using mask_type = typename Base::mask_type;
1425
1426 static constexpr guint filter =
1427 Base::filter |
1428 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA |
1429 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
1430 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1431
1432 explicit
PaintMaskToPaintBufAlphaPaintMaskToPaintBufAlpha1433 PaintMaskToPaintBufAlpha (const GimpPaintCoreLoopsParams *params) :
1434 Base (params)
1435 {
1436 /* Validate that the paint buffer is within the bounds of the paint mask */
1437 g_return_if_fail (gimp_temp_buf_get_width (params->paint_buf) <=
1438 gimp_temp_buf_get_width (params->paint_mask) -
1439 params->paint_mask_offset_x);
1440 g_return_if_fail (gimp_temp_buf_get_height (params->paint_buf) <=
1441 gimp_temp_buf_get_height (params->paint_mask) -
1442 params->paint_mask_offset_y);
1443 }
1444
1445 template <class Derived>
1446 using State = typename Base::template State<Derived>;
1447
1448 template <class Derived>
1449 void
process_rowPaintMaskToPaintBufAlpha1450 process_row (const GimpPaintCoreLoopsParams *params,
1451 State<Derived> *state,
1452 GeglBufferIterator *iter,
1453 const GeglRectangle *roi,
1454 const GeglRectangle *area,
1455 const GeglRectangle *rect,
1456 gint y) const
1457 {
1458 Base::process_row (params, state, iter, roi, area, rect, y);
1459
1460 gint paint_offset = (y - roi->y) * this->paint_stride +
1461 (rect->x - roi->x) * 4;
1462 gfloat *paint_pixel = &this->paint_data[paint_offset];
1463 gint mask_offset = (y - roi->y) * this->mask_stride +
1464 (rect->x - roi->x);
1465 const mask_type *mask_pixel = &this->mask_data[mask_offset];
1466 gint x;
1467
1468 for (x = 0; x < rect->width; x++)
1469 {
1470 paint_pixel[3] *= value_to_float (*mask_pixel) * params->paint_opacity;
1471
1472 mask_pixel += 1;
1473 paint_pixel += 4;
1474 }
1475 }
1476 };
1477
1478 static SuppressedAlgorithmDispatch<
1479 PaintMaskToPaintBufAlpha,
1480 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA,
1481 decltype (dispatch_paint_buf),
1482 decltype (dispatch_paint_mask)
1483 >
1484 dispatch_paint_mask_to_paint_buf_alpha;
1485
1486
1487 /* CanvasBufferToCompMask, dispatch_canvas_buffer_to_comp_mask():
1488 *
1489 * An algorithm class, implementing the CANVAS_BUFFER_TO_COMP_MASK algorithm.
1490 */
1491
1492 template <class Base,
1493 gboolean Direct>
1494 struct CanvasBufferToCompMask : Base
1495 {
1496 using comp_mask_type = typename Base::comp_mask_type;
1497
1498 static constexpr guint filter =
1499 Base::filter |
1500 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
1501 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1502
1503 using Base::Base;
1504
1505 template <class Derived>
1506 struct State : Base::template State<Derived>
1507 {
1508 const gfloat *canvas_pixel;
1509 const gfloat *mask_pixel;
1510 };
1511
1512 template <class Derived>
1513 void
init_stepCanvasBufferToCompMask1514 init_step (const GimpPaintCoreLoopsParams *params,
1515 State<Derived> *state,
1516 GeglBufferIterator *iter,
1517 const GeglRectangle *roi,
1518 const GeglRectangle *area,
1519 const GeglRectangle *rect) const
1520 {
1521 Base::init_step (params, state, iter, roi, area, rect);
1522
1523 state->canvas_pixel =
1524 (const gfloat *) iter->items[state->canvas_buffer_iterator].data;
1525 state->mask_pixel =
1526 (const gfloat *) iter->items[state->mask_buffer_iterator].data;
1527 }
1528
1529 template <class Derived>
1530 void
process_rowCanvasBufferToCompMask1531 process_row (const GimpPaintCoreLoopsParams *params,
1532 State<Derived> *state,
1533 GeglBufferIterator *iter,
1534 const GeglRectangle *roi,
1535 const GeglRectangle *area,
1536 const GeglRectangle *rect,
1537 gint y) const
1538 {
1539 Base::process_row (params, state, iter, roi, area, rect, y);
1540
1541 comp_mask_type *comp_mask_pixel = state->comp_mask_data;
1542 gint x;
1543
1544 for (x = 0; x < rect->width; x++)
1545 {
1546 comp_mask_pixel[0] = state->canvas_pixel[0] * state->mask_pixel[0];
1547
1548 comp_mask_pixel += 1;
1549 state->canvas_pixel += 1;
1550 state->mask_pixel += 1;
1551 }
1552 }
1553 };
1554
1555 template <class Base>
1556 struct CanvasBufferToCompMask<Base, TRUE> : Base
1557 {
1558 static constexpr guint filter =
1559 Base::filter |
1560 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK |
1561 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1562
1563 using Base::Base;
1564
1565 template <class Derived>
1566 using State = typename Base::template State<Derived>;
1567
1568 template <class Derived>
1569 void
init_stepCanvasBufferToCompMask1570 init_step (const GimpPaintCoreLoopsParams *params,
1571 State<Derived> *state,
1572 GeglBufferIterator *iter,
1573 const GeglRectangle *roi,
1574 const GeglRectangle *area,
1575 const GeglRectangle *rect) const
1576 {
1577 Base::init_step (params, state, iter, roi, area, rect);
1578
1579 state->comp_mask_data =
1580 (gfloat *) iter->items[state->canvas_buffer_iterator].data - rect->width;
1581 }
1582
1583 template <class Derived>
1584 void
process_rowCanvasBufferToCompMask1585 process_row (const GimpPaintCoreLoopsParams *params,
1586 State<Derived> *state,
1587 GeglBufferIterator *iter,
1588 const GeglRectangle *roi,
1589 const GeglRectangle *area,
1590 const GeglRectangle *rect,
1591 gint y) const
1592 {
1593 Base::process_row (params, state, iter, roi, area, rect, y);
1594
1595 state->comp_mask_data += rect->width;
1596 }
1597 };
1598
1599 struct DispatchCanvasBufferToCompMask
1600 {
1601 static constexpr guint mask =
1602 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
1603
1604 template <class Base>
1605 using AlgorithmDirect = CanvasBufferToCompMask<Base, TRUE>;
1606 template <class Base>
1607 using AlgorithmIndirect = CanvasBufferToCompMask<Base, FALSE>;
1608
1609 using DispatchDirect = BasicDispatch<
1610 AlgorithmDirect,
1611 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK,
1612 decltype (dispatch_comp_mask)
1613 >;
1614 using DispatchIndirect = BasicDispatch<
1615 AlgorithmIndirect,
1616 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK,
1617 decltype (dispatch_temp_comp_mask)
1618 >;
1619
1620 template <class Algorithm,
1621 gboolean HasMaskBufferIterator = has_mask_buffer_iterator (
1622 (Algorithm *) NULL)>
1623 struct Dispatch : DispatchIndirect
1624 {
1625 };
1626
1627 template <class Algorithm>
1628 struct Dispatch<Algorithm, FALSE> : DispatchDirect
1629 {
1630 };
1631
1632 template <class Visitor,
1633 class Algorithm>
1634 void
operator ()DispatchCanvasBufferToCompMask1635 operator () (Visitor visitor,
1636 const GimpPaintCoreLoopsParams *params,
1637 GimpPaintCoreLoopsAlgorithm algorithms,
1638 identity<Algorithm> algorithm) const
1639 {
1640 if ((algorithms & mask) == mask)
1641 {
1642 dispatch (
1643 [&] (auto algorithm)
1644 {
1645 using NewAlgorithm = typename decltype (algorithm)::type;
1646
1647 Dispatch<NewAlgorithm> () (visitor, params, algorithms, algorithm);
1648 },
1649 params, algorithms, algorithm,
1650 DispatchCanvasBufferIterator<GEGL_BUFFER_READ> (),
1651 dispatch_mask_buffer_iterator);
1652 }
1653 else
1654 {
1655 visitor (algorithm);
1656 }
1657 }
1658 } static dispatch_canvas_buffer_to_comp_mask;
1659
1660
1661 /* PaintMaskToCompMask, dispatch_paint_mask_to_comp_mask():
1662 *
1663 * An algorithm class, implementing the PAINT_MASK_TO_COMP_MASK algorithm.
1664 */
1665
1666 template <class Base,
1667 gboolean Direct>
1668 struct PaintMaskToCompMask : Base
1669 {
1670 using mask_type = typename Base::mask_type;
1671 using comp_mask_type = typename Base::comp_mask_type;
1672
1673 static constexpr guint filter =
1674 Base::filter |
1675 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1676
1677 using Base::Base;
1678
1679 template <class Derived>
1680 struct State : Base::template State<Derived>
1681 {
1682 const gfloat *mask_pixel;
1683 };
1684
1685 template <class Derived>
1686 void
init_stepPaintMaskToCompMask1687 init_step (const GimpPaintCoreLoopsParams *params,
1688 State<Derived> *state,
1689 GeglBufferIterator *iter,
1690 const GeglRectangle *roi,
1691 const GeglRectangle *area,
1692 const GeglRectangle *rect) const
1693 {
1694 Base::init_step (params, state, iter, roi, area, rect);
1695
1696 if (has_mask_buffer_iterator (this))
1697 {
1698 state->mask_pixel =
1699 (const gfloat *) iter->items[mask_buffer_iterator (this, state)].data;
1700 }
1701 }
1702
1703 template <class Derived>
1704 void
process_rowPaintMaskToCompMask1705 process_row (const GimpPaintCoreLoopsParams *params,
1706 State<Derived> *state,
1707 GeglBufferIterator *iter,
1708 const GeglRectangle *roi,
1709 const GeglRectangle *area,
1710 const GeglRectangle *rect,
1711 gint y) const
1712 {
1713 Base::process_row (params, state, iter, roi, area, rect, y);
1714
1715 gint mask_offset = (y - roi->y) * this->mask_stride +
1716 (rect->x - roi->x);
1717 const mask_type *mask_pixel = &this->mask_data[mask_offset];
1718 comp_mask_type *comp_mask_pixel = state->comp_mask_data;
1719 gint x;
1720
1721 if (has_mask_buffer_iterator (this))
1722 {
1723 for (x = 0; x < rect->width; x++)
1724 {
1725 comp_mask_pixel[0] = value_to_float (mask_pixel[0]) *
1726 state->mask_pixel[0] *
1727 params->paint_opacity;
1728
1729 comp_mask_pixel += 1;
1730 mask_pixel += 1;
1731 state->mask_pixel += 1;
1732 }
1733 }
1734 else
1735 {
1736 for (x = 0; x < rect->width; x++)
1737 {
1738 comp_mask_pixel[0] = value_to_float (mask_pixel[0]) *
1739 params->paint_opacity;
1740
1741 comp_mask_pixel += 1;
1742 mask_pixel += 1;
1743 }
1744 }
1745 }
1746 };
1747
1748 template <class Base>
1749 struct PaintMaskToCompMask<Base, TRUE> : Base
1750 {
1751 using mask_type = typename Base::mask_type;
1752
1753 static constexpr guint filter =
1754 Base::filter |
1755 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK |
1756 GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
1757
1758 using Base::Base;
1759
1760 template <class Derived>
1761 using State = typename Base::template State<Derived>;
1762
1763 template <class Derived>
1764 void
init_stepPaintMaskToCompMask1765 init_step (const GimpPaintCoreLoopsParams *params,
1766 State<Derived> *state,
1767 GeglBufferIterator *iter,
1768 const GeglRectangle *roi,
1769 const GeglRectangle *area,
1770 const GeglRectangle *rect) const
1771 {
1772 Base::init_step (params, state, iter, roi, area, rect);
1773
1774 gint mask_offset = (rect->y - roi->y) * this->mask_stride +
1775 (rect->x - roi->x);
1776
1777 state->comp_mask_data = (mask_type *) &this->mask_data[mask_offset] -
1778 this->mask_stride;
1779 }
1780
1781 template <class Derived>
1782 void
process_rowPaintMaskToCompMask1783 process_row (const GimpPaintCoreLoopsParams *params,
1784 State<Derived> *state,
1785 GeglBufferIterator *iter,
1786 const GeglRectangle *roi,
1787 const GeglRectangle *area,
1788 const GeglRectangle *rect,
1789 gint y) const
1790 {
1791 Base::process_row (params, state, iter, roi, area, rect, y);
1792
1793 state->comp_mask_data += this->mask_stride;
1794 }
1795 };
1796
1797 struct DispatchPaintMaskToCompMask
1798 {
1799 static constexpr guint mask =
1800 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
1801
1802 template <class Base>
1803 using AlgorithmDirect = PaintMaskToCompMask<Base, TRUE>;
1804 template <class Base>
1805 using AlgorithmIndirect = PaintMaskToCompMask<Base, FALSE>;
1806
1807 using DispatchDirect = BasicDispatch<
1808 AlgorithmDirect,
1809 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK,
1810 decltype (dispatch_comp_mask)
1811 >;
1812 using DispatchIndirect = BasicDispatch<
1813 AlgorithmIndirect,
1814 GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK,
1815 decltype (dispatch_temp_comp_mask)
1816 >;
1817
1818 template <class Algorithm,
1819 class MaskType = typename Algorithm::mask_type,
1820 gboolean HasMaskBufferIterator = has_mask_buffer_iterator (
1821 (Algorithm *) NULL)>
1822 struct Dispatch : DispatchIndirect
1823 {
1824 };
1825
1826 template <class Algorithm>
1827 struct Dispatch<Algorithm, gfloat, FALSE> : DispatchDirect
1828 {
1829 };
1830
1831 template <class Visitor,
1832 class Algorithm>
1833 void
operator ()DispatchPaintMaskToCompMask1834 operator () (Visitor visitor,
1835 const GimpPaintCoreLoopsParams *params,
1836 GimpPaintCoreLoopsAlgorithm algorithms,
1837 identity<Algorithm> algorithm) const
1838 {
1839 if ((algorithms & mask) == mask)
1840 {
1841 dispatch (
1842 [&] (auto algorithm)
1843 {
1844 using NewAlgorithm = typename decltype (algorithm)::type;
1845
1846 if (params->paint_opacity == GIMP_OPACITY_OPAQUE)
1847 Dispatch<NewAlgorithm> () (visitor, params, algorithms, algorithm);
1848 else
1849 DispatchIndirect () (visitor, params, algorithms, algorithm);
1850 },
1851 params, algorithms, algorithm,
1852 dispatch_paint_mask,
1853 dispatch_mask_buffer_iterator);
1854 }
1855 else
1856 {
1857 visitor (algorithm);
1858 }
1859 }
1860 } static dispatch_paint_mask_to_comp_mask;
1861
1862
1863 /* DoLayerBlend, dispatch_do_layer_blend():
1864 *
1865 * An algorithm class, implementing the DO_LAYER_BLEND algorithm.
1866 */
1867
1868 template <class Base>
1869 struct DoLayerBlend : Base
1870 {
1871 static constexpr guint filter =
1872 Base::filter |
1873 GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND;
1874
1875 static constexpr gint max_n_iterators = Base::max_n_iterators + 2;
1876
1877 const Babl *iterator_format;
1878 GimpOperationLayerMode layer_mode;
1879
1880 explicit
DoLayerBlendDoLayerBlend1881 DoLayerBlend (const GimpPaintCoreLoopsParams *params) :
1882 Base (params)
1883 {
1884 layer_mode.layer_mode = params->paint_mode;
1885 layer_mode.opacity = params->image_opacity;
1886 layer_mode.function = gimp_layer_mode_get_function (params->paint_mode);
1887 layer_mode.blend_function = gimp_layer_mode_get_blend_function (params->paint_mode);
1888 layer_mode.blend_space = gimp_layer_mode_get_blend_space (params->paint_mode);
1889 layer_mode.composite_space = gimp_layer_mode_get_composite_space (params->paint_mode);
1890 layer_mode.composite_mode = gimp_layer_mode_get_paint_composite_mode (params->paint_mode);
1891
1892 iterator_format = gimp_layer_mode_get_format (params->paint_mode,
1893 layer_mode.blend_space,
1894 layer_mode.composite_space,
1895 layer_mode.composite_mode,
1896 gimp_temp_buf_get_format (params->paint_buf));
1897
1898 g_return_if_fail (gimp_temp_buf_get_format (params->paint_buf) == iterator_format);
1899 }
1900
1901 template <class Derived>
1902 struct State : Base::template State<Derived>
1903 {
1904 gint iterator_base;
1905
1906 GeglRectangle process_roi;
1907
1908 gfloat *out_pixel;
1909 gfloat *in_pixel;
1910 gfloat *mask_pixel;
1911 gfloat *paint_pixel;
1912 };
1913
1914 template <class Derived>
1915 void
initDoLayerBlend1916 init (const GimpPaintCoreLoopsParams *params,
1917 State<Derived> *state,
1918 GeglBufferIterator *iter,
1919 const GeglRectangle *roi,
1920 const GeglRectangle *area) const
1921 {
1922 state->iterator_base = gegl_buffer_iterator_add (iter, params->src_buffer,
1923 area, 0, iterator_format,
1924 GEGL_ACCESS_READ,
1925 GEGL_ABYSS_NONE);
1926
1927 if (! has_comp_buffer ((const Derived *) this))
1928 {
1929 gegl_buffer_iterator_add (iter, params->dest_buffer, area, 0,
1930 iterator_format,
1931 GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
1932 }
1933
1934 /* initialize the base class *after* initializing the iterator, to make
1935 * sure that src_buffer is the primary buffer of the iterator, if no
1936 * subclass added an iterator first.
1937 */
1938 Base::init (params, state, iter, roi, area);
1939 }
1940
1941 template <class Derived>
1942 void
init_stepDoLayerBlend1943 init_step (const GimpPaintCoreLoopsParams *params,
1944 State<Derived> *state,
1945 GeglBufferIterator *iter,
1946 const GeglRectangle *roi,
1947 const GeglRectangle *area,
1948 const GeglRectangle *rect) const
1949 {
1950 Base::init_step (params, state, iter, roi, area, rect);
1951
1952 state->in_pixel = (gfloat *) iter->items[state->iterator_base + 0].data;
1953
1954 state->paint_pixel = this->paint_data +
1955 (rect->y - roi->y) * this->paint_stride +
1956 (rect->x - roi->x) * 4;
1957
1958 if (! has_comp_mask (this) && has_mask_buffer_iterator (this))
1959 {
1960 state->mask_pixel =
1961 (gfloat *) iter->items[mask_buffer_iterator (this, state)].data;
1962 }
1963
1964 if (! has_comp_buffer ((const Derived *) this))
1965 state->out_pixel = (gfloat *) iter->items[state->iterator_base + 1].data;
1966
1967 state->process_roi.x = rect->x;
1968 state->process_roi.width = rect->width;
1969 state->process_roi.height = 1;
1970 }
1971
1972 template <class Derived>
1973 void
process_rowDoLayerBlend1974 process_row (const GimpPaintCoreLoopsParams *params,
1975 State<Derived> *state,
1976 GeglBufferIterator *iter,
1977 const GeglRectangle *roi,
1978 const GeglRectangle *area,
1979 const GeglRectangle *rect,
1980 gint y) const
1981 {
1982 Base::process_row (params, state, iter, roi, area, rect, y);
1983
1984 gfloat *mask_pixel;
1985 gfloat *out_pixel;
1986
1987 if (has_comp_mask (this))
1988 mask_pixel = comp_mask_data (this, state);
1989 else if (has_mask_buffer_iterator (this))
1990 mask_pixel = state->mask_pixel;
1991 else
1992 mask_pixel = NULL;
1993
1994 if (! has_comp_buffer ((const Derived *) this))
1995 {
1996 out_pixel = state->out_pixel;
1997 }
1998 else
1999 {
2000 out_pixel = comp_buffer_data (
2001 (const Derived *) this,
2002 (typename Derived::template State<Derived> *) state);
2003 }
2004
2005 state->process_roi.y = y;
2006
2007 layer_mode.function ((GeglOperation*) &layer_mode,
2008 state->in_pixel,
2009 state->paint_pixel,
2010 mask_pixel,
2011 out_pixel,
2012 rect->width,
2013 &state->process_roi,
2014 0);
2015
2016 state->in_pixel += rect->width * 4;
2017 state->paint_pixel += this->paint_stride;
2018 if (! has_comp_mask (this) && has_mask_buffer_iterator (this))
2019 state->mask_pixel += rect->width;
2020 if (! has_comp_buffer ((const Derived *) this))
2021 state->out_pixel += rect->width * 4;
2022 }
2023 };
2024
2025 static MandatoryAlgorithmDispatch<
2026 DoLayerBlend,
2027 GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND,
2028 decltype (dispatch_paint_buf),
2029 decltype (dispatch_mask_buffer_iterator)
2030 >
2031 dispatch_do_layer_blend;
2032
2033
2034 /* MaskComponents, dispatch_mask_components():
2035 *
2036 * An algorithm class, implementing the MASK_COMPONENTS algorithm.
2037 */
2038
2039 template <class Base>
2040 struct MaskComponents : Base
2041 {
2042 static constexpr guint filter =
2043 Base::filter |
2044 GIMP_PAINT_CORE_LOOPS_ALGORITHM_MASK_COMPONENTS;
2045
2046 static constexpr gint max_n_iterators = Base::max_n_iterators + 1;
2047
2048 const Babl *format;
2049 const Babl *comp_fish = NULL;
2050
2051 explicit
MaskComponentsMaskComponents2052 MaskComponents (const GimpPaintCoreLoopsParams *params) :
2053 Base (params)
2054 {
2055 format = gimp_operation_mask_components_get_format (
2056 gegl_buffer_get_format (params->dest_buffer));
2057
2058 if (format != this->iterator_format)
2059 comp_fish = babl_fish (this->iterator_format, format);
2060 }
2061
2062 template <class Derived>
2063 struct State : Base::template State<Derived>
2064 {
2065 gint dest_buffer_iterator;
2066
2067 guint8 *dest_pixel;
2068 guint8 *comp_pixel;
2069 };
2070
2071 template <class Derived>
2072 void
initMaskComponents2073 init (const GimpPaintCoreLoopsParams *params,
2074 State<Derived> *state,
2075 GeglBufferIterator *iter,
2076 const GeglRectangle *roi,
2077 const GeglRectangle *area) const
2078 {
2079 state->dest_buffer_iterator = gegl_buffer_iterator_add (
2080 iter, params->dest_buffer, area, 0, format,
2081 GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
2082
2083 /* initialize the base class *after* initializing the iterator, to make
2084 * sure that dest_buffer is the primary buffer of the iterator, if no
2085 * subclass added an iterator first.
2086 */
2087 Base::init (params, state, iter, roi, area);
2088 }
2089
2090 template <class Derived>
2091 void
init_stepMaskComponents2092 init_step (const GimpPaintCoreLoopsParams *params,
2093 State<Derived> *state,
2094 GeglBufferIterator *iter,
2095 const GeglRectangle *roi,
2096 const GeglRectangle *area,
2097 const GeglRectangle *rect) const
2098 {
2099 Base::init_step (params, state, iter, roi, area, rect);
2100
2101 state->dest_pixel =
2102 (guint8 *) iter->items[state->dest_buffer_iterator].data;
2103
2104 if (comp_fish)
2105 {
2106 state->comp_pixel = (guint8 *) gegl_scratch_alloc (
2107 rect->width * babl_format_get_bytes_per_pixel (format));
2108 }
2109 }
2110
2111 template <class Derived>
2112 void
process_rowMaskComponents2113 process_row (const GimpPaintCoreLoopsParams *params,
2114 State<Derived> *state,
2115 GeglBufferIterator *iter,
2116 const GeglRectangle *roi,
2117 const GeglRectangle *area,
2118 const GeglRectangle *rect,
2119 gint y) const
2120 {
2121 Base::process_row (params, state, iter, roi, area, rect, y);
2122
2123 gpointer comp_pixel;
2124
2125 if (comp_fish)
2126 {
2127 babl_process (comp_fish,
2128 state->comp_buffer_data, state->comp_pixel,
2129 rect->width);
2130
2131 comp_pixel = state->comp_pixel;
2132 }
2133 else
2134 {
2135 comp_pixel = state->comp_buffer_data;
2136 }
2137
2138 gimp_operation_mask_components_process (format,
2139 state->dest_pixel, comp_pixel,
2140 state->dest_pixel,
2141 rect->width, params->affect);
2142
2143 state->dest_pixel += rect->width * babl_format_get_bytes_per_pixel (format);
2144 }
2145
2146 template <class Derived>
2147 void
finalize_stepMaskComponents2148 finalize_step (const GimpPaintCoreLoopsParams *params,
2149 State<Derived> *state) const
2150 {
2151 if (comp_fish)
2152 gegl_scratch_free (state->comp_pixel);
2153
2154 Base::finalize_step (params, state);
2155 }
2156 };
2157
2158 static AlgorithmDispatch<
2159 MaskComponents,
2160 GIMP_PAINT_CORE_LOOPS_ALGORITHM_MASK_COMPONENTS,
2161 decltype (dispatch_temp_comp_buffer)
2162 >
2163 dispatch_mask_components;
2164
2165
2166 /* gimp_paint_core_loops_process():
2167 *
2168 * Performs the set of algorithms requested in 'algorithms', specified as a
2169 * bitwise-OR of 'GimpPaintCoreLoopsAlgorithm' values, given the set of
2170 * parameters 'params'.
2171 *
2172 * Note that the order in which the algorithms are performed is currently
2173 * fixed, and follows their order of appearance in the
2174 * 'GimpPaintCoreLoopsAlgorithm' enum.
2175 */
2176
2177 void
gimp_paint_core_loops_process(const GimpPaintCoreLoopsParams * params,GimpPaintCoreLoopsAlgorithm algorithms)2178 gimp_paint_core_loops_process (const GimpPaintCoreLoopsParams *params,
2179 GimpPaintCoreLoopsAlgorithm algorithms)
2180 {
2181 GeglRectangle roi;
2182
2183 if (params->paint_buf)
2184 {
2185 roi.x = params->paint_buf_offset_x;
2186 roi.y = params->paint_buf_offset_y;
2187 roi.width = gimp_temp_buf_get_width (params->paint_buf);
2188 roi.height = gimp_temp_buf_get_height (params->paint_buf);
2189 }
2190 else
2191 {
2192 roi.x = params->paint_buf_offset_x;
2193 roi.y = params->paint_buf_offset_y;
2194 roi.width = gimp_temp_buf_get_width (params->paint_mask) -
2195 params->paint_mask_offset_x;
2196 roi.height = gimp_temp_buf_get_height (params->paint_mask) -
2197 params->paint_mask_offset_y;
2198 }
2199
2200 dispatch (
2201 [&] (auto algorithm_type)
2202 {
2203 using Algorithm = typename decltype (algorithm_type)::type;
2204 using State = typename Algorithm::template State<Algorithm>;
2205
2206 Algorithm algorithm (params);
2207
2208 gegl_parallel_distribute_area (
2209 &roi, PIXELS_PER_THREAD,
2210 [=] (const GeglRectangle *area)
2211 {
2212 State state;
2213 gint y;
2214
2215 if (Algorithm::max_n_iterators > 0)
2216 {
2217 GeglBufferIterator *iter;
2218
2219 iter = gegl_buffer_iterator_empty_new (
2220 Algorithm::max_n_iterators);
2221
2222 algorithm.init (params, &state, iter, &roi, area);
2223
2224 while (gegl_buffer_iterator_next (iter))
2225 {
2226 const GeglRectangle *rect = &iter->items[0].roi;
2227
2228 algorithm.init_step (params, &state, iter, &roi, area, rect);
2229
2230 for (y = 0; y < rect->height; y++)
2231 {
2232 algorithm.process_row (params, &state,
2233 iter, &roi, area, rect,
2234 rect->y + y);
2235 }
2236
2237 algorithm.finalize_step (params, &state);
2238 }
2239
2240 algorithm.finalize (params, &state);
2241 }
2242 else
2243 {
2244 algorithm.init (params, &state, NULL, &roi, area);
2245 algorithm.init_step (params, &state, NULL, &roi, area, area);
2246
2247 for (y = 0; y < area->height; y++)
2248 {
2249 algorithm.process_row (params, &state,
2250 NULL, &roi, area, area,
2251 area->y + y);
2252 }
2253
2254 algorithm.finalize_step (params, &state);
2255 algorithm.finalize (params, &state);
2256 }
2257 });
2258 },
2259 params, algorithms, identity<AlgorithmBase> (),
2260 dispatch_combine_paint_mask_to_canvas_buffer_to_paint_buf_alpha,
2261 dispatch_combine_paint_mask_to_canvas_buffer,
2262 dispatch_canvas_buffer_to_paint_buf_alpha,
2263 dispatch_paint_mask_to_paint_buf_alpha,
2264 dispatch_canvas_buffer_to_comp_mask,
2265 dispatch_paint_mask_to_comp_mask,
2266 dispatch_do_layer_blend,
2267 dispatch_mask_components);
2268 }
2269