Krita Source Code Documentation
Loading...
Searching...
No Matches
KoCompositeOpMarker.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006 Cyrille Berger <cberger@cberger.net>
3 * SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de>
4 * SPDX-FileCopyrightText: 2025 Carsten Hartenfels <carsten.hartenfels@pm.me>
5 *
6 * SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8
9#ifndef KOCOMPOSITEOPMARKER_H_
10#define KOCOMPOSITEOPMARKER_H_
11
14
15template<class Traits>
17{
18 typedef typename Traits::channels_type channels_type;
19
20 static constexpr qint32 channels_nb = Traits::channels_nb;
21 static constexpr qint32 alpha_pos = Traits::alpha_pos;
22 static constexpr qint32 pixel_size = Traits::pixelSize;
23
24public:
29
31
32 void composite(const KoCompositeOp::ParameterInfo &params) const override
33 {
34 bool useMask = params.maskRowStart != 0;
35 const QBitArray &flags = params.channelFlags.isEmpty() ? QBitArray(channels_nb, true) : params.channelFlags;
36 bool allChannelFlags = params.channelFlags.isEmpty() || params.channelFlags == QBitArray(channels_nb, true);
37 bool alphaLocked = (alpha_pos != -1) && !flags.testBit(alpha_pos);
38 if (useMask) {
39 if (alphaLocked) {
40 if (allChannelFlags) {
41 genericComposite<true, true, true>(params, &flags);
42 } else {
43 genericComposite<true, true, false>(params, &flags);
44 }
45 } else {
46 if (allChannelFlags) {
47 genericComposite<true, false, true>(params, &flags);
48 } else {
49 genericComposite<true, false, false>(params, &flags);
50 }
51 }
52 } else {
53 if (alphaLocked) {
54 if (allChannelFlags) {
55 genericComposite<false, true, true>(params, &flags);
56 } else {
57 genericComposite<false, true, false>(params, &flags);
58 }
59 } else {
60 if (allChannelFlags) {
61 genericComposite<false, false, true>(params, &flags);
62 } else {
63 genericComposite<false, false, false>(params, &flags);
64 }
65 }
66 }
67 }
68
69 template<bool useMask, bool alphaLocked, bool allChannelFlags>
70 void genericComposite(const KoCompositeOp::ParameterInfo &params, const QBitArray *channelFlags) const
71 {
72 using namespace Arithmetic;
73
74 KoAlphaDarkenParamsWrapperCreamy paramsWrapper(params);
75
76 qint32 srcInc = (params.srcRowStride == 0) ? 0 : channels_nb;
77 channels_type flow = scale<channels_type>(paramsWrapper.flow);
78 channels_type opacity = scale<channels_type>(paramsWrapper.opacity);
79 quint8 *dstRowStart = params.dstRowStart;
80 const quint8 *srcRowStart = params.srcRowStart;
81 const quint8 *maskRowStart = params.maskRowStart;
82
83 for (qint32 r = params.rows; r > 0; --r) {
84 const channels_type *src = reinterpret_cast<const channels_type *>(srcRowStart);
85 channels_type *dst = reinterpret_cast<channels_type *>(dstRowStart);
86 const quint8 *mask = maskRowStart;
87
88 for (qint32 c = params.cols; c > 0; --c) {
89 channels_type srcAlpha = (alpha_pos == -1) ? unitValue<channels_type>() : src[alpha_pos];
90 channels_type dstAlpha = (alpha_pos == -1) ? unitValue<channels_type>() : dst[alpha_pos];
91 channels_type mskAlpha = useMask ? mul(scale<channels_type>(*mask), srcAlpha) : srcAlpha;
92
93 srcAlpha = mul(mskAlpha, opacity);
94
95 if (dstAlpha != zeroValue<channels_type>()) {
98 for (qint32 i = 0; i < channels_nb; i++) {
99 if (i != alpha_pos && (allChannelFlags || channelFlags->testBit(i))) {
100 dst[i] = lerp(dst[i], src[i], t);
101 }
102 }
103 } else {
104 if constexpr (!allChannelFlags) {
105 memset(reinterpret_cast<quint8 *>(dst), 0, pixel_size);
106 }
107 for (qint32 i = 0; i < channels_nb; i++) {
108 if (i != alpha_pos && (allChannelFlags || channelFlags->testBit(i))) {
109 dst[i] = src[i];
110 }
111 }
112 }
113
114 if constexpr (alpha_pos != -1 && !alphaLocked) {
116 params,
117 paramsWrapper,
118 flow,
119 opacity,
120 srcAlpha,
121 dstAlpha,
122 mskAlpha);
123 }
124
125 src += srcInc;
126 dst += channels_nb;
127
128 if constexpr (useMask) {
129 ++mask;
130 }
131 }
132
133 srcRowStart += params.srcRowStride;
134 dstRowStart += params.dstRowStride;
135 maskRowStart += params.maskRowStride;
136 }
137 }
138};
139
140#endif // KOCOMPOSITEOPMARKER_H_
const QString COMPOSITE_MARKER
QPointF lerp(const QPointF &p1, const QPointF &p2, qreal t)
static _Tdst clampAfterScale(dst_compositetype val)
static channels_type calculateAlpha(const KoCompositeOp::ParameterInfo &params, const ParamsWrapper &paramsWrapper, channels_type flow, channels_type opacity, channels_type srcAlpha, channels_type dstAlpha, channels_type mskAlpha)
static constexpr qint32 pixel_size
Traits::channels_type channels_type
static constexpr qint32 alpha_pos
static constexpr qint32 channels_nb
void composite(const KoCompositeOp::ParameterInfo &params) const override
void genericComposite(const KoCompositeOp::ParameterInfo &params, const QBitArray *channelFlags) const
KoCompositeOpMarker(const KoColorSpace *cs)
void composite(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, float opacity, const QBitArray &channelFlags=QBitArray()) const
static QString categoryMix()