Krita Source Code Documentation
Loading...
Searching...
No Matches
KoCompositeOpGeneric.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6#ifndef _KOCOMPOSITEOP_GENERIC_H_
7#define _KOCOMPOSITEOP_GENERIC_H_
8
9#include "KoCompositeOpBase.h"
11
12namespace detail {
13
19template <class Traits,
20 typename Traits::channels_type compositeFunc(typename Traits::channels_type, typename Traits::channels_type)>
21struct CompositeFunctionWrapper : KoCompositeOpGenericFunctorBase<typename Traits::channels_type>
22{
23 using channels_type = typename Traits::channels_type;
24
26 return compositeFunc(src, dst);
27 }
28};
29
30template <class Traits,
31 void compositeFunc(float, float, float, float&, float&, float&)>
32struct CompositeFunctionWrapperHSL : KoCompositeOpGenericFunctorBase<typename Traits::channels_type>
33{
34 using channels_type = typename Traits::channels_type;
35
36 static inline void composeChannels(float sr, float sg, float sb, float &dr, float &dg, float &db) {
37 return compositeFunc(sr, sg, sb, dr, dg, db);
38 }
39};
40
41}
42
50template<
51 class Traits,
52 typename CompositeOpFunctor,
53 typename BlendingPolicy
54>
55class KoCompositeOpGenericSCFunctor: public KoCompositeOpBase< Traits, KoCompositeOpGenericSCFunctor<Traits,CompositeOpFunctor,BlendingPolicy> >
56{
58 typedef typename Traits::channels_type channels_type;
59
60 static const qint32 channels_nb = Traits::channels_nb;
61 static const qint32 alpha_pos = Traits::alpha_pos;
62
63public:
64 KoCompositeOpGenericSCFunctor(const KoColorSpace* cs, const QString& id, const QString& category)
65 : base_class(cs, id, category) { }
66
67public:
68 template<bool alphaLocked, bool allChannelFlags>
70 channels_type* dst, channels_type dstAlpha, channels_type maskAlpha,
71 channels_type opacity, const QBitArray& channelFlags) {
72 using namespace Arithmetic;
73
74 srcAlpha = mul(srcAlpha, maskAlpha, opacity);
75
76 if (isZeroValueFuzzy(srcAlpha)) {
77 return dstAlpha;
78 }
79
80 if(alphaLocked) {
81 if(!isZeroValueFuzzy(dstAlpha)) {
82 for(qint32 i=0; i <channels_nb; i++) {
83 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
84 const channels_type srcInBlendSpace =
85 CompositeOpFunctor::clampSourceChannelValue(
86 BlendingPolicy::toAdditiveSpace(
87 src[i]));
88 const channels_type dstInBlendSpace =
89 CompositeOpFunctor::clampDestinationChannelValue(
90 BlendingPolicy::toAdditiveSpace(
91 dst[i]));
92
93 dst[i] = BlendingPolicy::fromAdditiveSpace(
94 lerp(dstInBlendSpace,
95 CompositeOpFunctor::composeChannel(srcInBlendSpace, dstInBlendSpace),
96 srcAlpha));
97 }
98 }
99 }
100
101 return dstAlpha;
102 } else if (isZeroValueFuzzy(dstAlpha)) {
103 for(qint32 i=0; i <channels_nb; i++) {
104 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
105 dst[i] = BlendingPolicy::fromAdditiveSpace(
106 CompositeOpFunctor::clampSourceChannelValue(
107 BlendingPolicy::toAdditiveSpace(src[i])));
108 }
109 }
110 return srcAlpha;
111 } else if (isUnitValueFuzzy(dstAlpha)) {
112 for(qint32 i=0; i <channels_nb; i++) {
113 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
114 const channels_type srcInBlendSpace =
115 CompositeOpFunctor::clampSourceChannelValue(
116 BlendingPolicy::toAdditiveSpace(
117 src[i]));
118 const channels_type dstInBlendSpace =
119 CompositeOpFunctor::clampDestinationChannelValue(
120 BlendingPolicy::toAdditiveSpace(
121 dst[i]));
122
123 dst[i] = BlendingPolicy::fromAdditiveSpace(
124 lerp(dstInBlendSpace,
125 CompositeOpFunctor::composeChannel(srcInBlendSpace, dstInBlendSpace),
126 srcAlpha));
127 }
128 }
129 return unitValue<channels_type>();
130 } else if (isUnitValueFuzzy(srcAlpha)) {
131 for(qint32 i=0; i <channels_nb; i++) {
132 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
133 const channels_type srcInBlendSpace =
134 CompositeOpFunctor::clampSourceChannelValue(
135 BlendingPolicy::toAdditiveSpace(
136 src[i]));
137 const channels_type dstInBlendSpace =
138 CompositeOpFunctor::clampDestinationChannelValue(
139 BlendingPolicy::toAdditiveSpace(
140 dst[i]));
141
142 dst[i] = BlendingPolicy::fromAdditiveSpace(
143 lerp(srcInBlendSpace,
144 CompositeOpFunctor::composeChannel(srcInBlendSpace, dstInBlendSpace),
145 dstAlpha));
146 }
147 }
148 return unitValue<channels_type>();
149 } else {
150 channels_type newDstAlpha = unionShapeOpacity(srcAlpha, dstAlpha);
151
152 if (!isZeroValueFuzzy(newDstAlpha)) {
153
154 for(qint32 i=0; i <channels_nb; i++) {
155 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
156 const channels_type srcInBlendSpace =
157 CompositeOpFunctor::clampSourceChannelValue(
158 BlendingPolicy::toAdditiveSpace(
159 src[i]));
160 const channels_type dstInBlendSpace =
161 CompositeOpFunctor::clampDestinationChannelValue(
162 BlendingPolicy::toAdditiveSpace(
163 dst[i]));
164
165 channels_type result =
166 blend(srcInBlendSpace, srcAlpha,
167 dstInBlendSpace, dstAlpha,
168 CompositeOpFunctor::composeChannel(srcInBlendSpace, dstInBlendSpace));
169
170 dst[i] = BlendingPolicy::fromAdditiveSpace(div(result, newDstAlpha));
171 }
172 }
173 }
174
175 return newDstAlpha;
176 }
177 }
178};
179
180template<
181 class Traits,
182 typename Traits::channels_type compositeFunc(typename Traits::channels_type, typename Traits::channels_type),
183 typename BlendingPolicy
184>
185class KoCompositeOpGenericSC : public KoCompositeOpGenericSCFunctor<Traits, detail::CompositeFunctionWrapper<Traits, compositeFunc>, BlendingPolicy>
186{
187protected:
189public:
191};
192
200template<class Traits, typename CompositeOpFunctor>
201class KoCompositeOpGenericHSLFunctor: public KoCompositeOpBase< Traits, KoCompositeOpGenericHSLFunctor<Traits,CompositeOpFunctor> >
202{
204 typedef typename Traits::channels_type channels_type;
205
206 static const qint32 red_pos = Traits::red_pos;
207 static const qint32 green_pos = Traits::green_pos;
208 static const qint32 blue_pos = Traits::blue_pos;
209
210public:
211 KoCompositeOpGenericHSLFunctor(const KoColorSpace* cs, const QString& id, const QString& category)
212 : base_class(cs, id, category) { }
213
214public:
215 template<bool alphaLocked, bool allChannelFlags>
217 channels_type* dst, channels_type dstAlpha, channels_type maskAlpha,
218 channels_type opacity, const QBitArray& channelFlags) {
219 using namespace Arithmetic;
220
221 srcAlpha = mul(srcAlpha, maskAlpha, opacity);
222
223 if(alphaLocked) {
224 if(dstAlpha != zeroValue<channels_type>()) {
225 float srcR = scale<float>(CompositeOpFunctor::clampSourceChannelValue(src[red_pos]));
226 float srcG = scale<float>(CompositeOpFunctor::clampSourceChannelValue(src[green_pos]));
227 float srcB = scale<float>(CompositeOpFunctor::clampSourceChannelValue(src[blue_pos]));
228
229 float dstR = scale<float>(CompositeOpFunctor::clampDestinationChannelValue(dst[red_pos]));
230 float dstG = scale<float>(CompositeOpFunctor::clampDestinationChannelValue(dst[green_pos]));
231 float dstB = scale<float>(CompositeOpFunctor::clampDestinationChannelValue(dst[blue_pos]));
232
233 CompositeOpFunctor::composeChannels(srcR, srcG, srcB, dstR, dstG, dstB);
234
235 if(allChannelFlags || channelFlags.testBit(red_pos))
236 dst[red_pos] = lerp(dst[red_pos], scale<channels_type>(dstR), srcAlpha);
237
238 if(allChannelFlags || channelFlags.testBit(green_pos))
239 dst[green_pos] = lerp(dst[green_pos], scale<channels_type>(dstG), srcAlpha);
240
241 if(allChannelFlags || channelFlags.testBit(blue_pos))
242 dst[blue_pos] = lerp(dst[blue_pos], scale<channels_type>(dstB), srcAlpha);
243 }
244
245 return dstAlpha;
246 }
247 else {
248 channels_type newDstAlpha = unionShapeOpacity(srcAlpha, dstAlpha);
249
250 if(newDstAlpha != zeroValue<channels_type>()) {
251 float srcR = scale<float>(CompositeOpFunctor::clampSourceChannelValue(src[red_pos]));
252 float srcG = scale<float>(CompositeOpFunctor::clampSourceChannelValue(src[green_pos]));
253 float srcB = scale<float>(CompositeOpFunctor::clampSourceChannelValue(src[blue_pos]));
254
255 float dstR = scale<float>(CompositeOpFunctor::clampDestinationChannelValue(dst[red_pos]));
256 float dstG = scale<float>(CompositeOpFunctor::clampDestinationChannelValue(dst[green_pos]));
257 float dstB = scale<float>(CompositeOpFunctor::clampDestinationChannelValue(dst[blue_pos]));
258
259 CompositeOpFunctor::composeChannels(srcR, srcG, srcB, dstR, dstG, dstB);
260
261 if(allChannelFlags || channelFlags.testBit(red_pos))
262 dst[red_pos] = div(blend(src[red_pos], srcAlpha, dst[red_pos], dstAlpha, scale<channels_type>(dstR)), newDstAlpha);
263
264 if(allChannelFlags || channelFlags.testBit(green_pos))
265 dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], dstAlpha, scale<channels_type>(dstG)), newDstAlpha);
266
267 if(allChannelFlags || channelFlags.testBit(blue_pos))
268 dst[blue_pos] = div(blend(src[blue_pos], srcAlpha, dst[blue_pos], dstAlpha, scale<channels_type>(dstB)), newDstAlpha);
269 }
270
271 return newDstAlpha;
272 }
273 }
274};
275
276
277template<class Traits, void compositeFunc(float, float, float, float&, float&, float&)>
278class KoCompositeOpGenericHSL : public KoCompositeOpGenericHSLFunctor<Traits, detail::CompositeFunctionWrapperHSL<Traits, compositeFunc>>
279{
280protected:
282public:
284};
285
297template<class Traits, void compositeFunc(float, float, float&, float&), typename BlendingPolicy>
298class KoCompositeOpGenericSCAlpha: public KoCompositeOpBase< Traits, KoCompositeOpGenericSCAlpha<Traits,compositeFunc,BlendingPolicy> >
299{
301 typedef typename Traits::channels_type channels_type;
302
303 static const qint32 channels_nb = Traits::channels_nb;
304 static const qint32 alpha_pos = Traits::alpha_pos;
305
306public:
307 KoCompositeOpGenericSCAlpha(const KoColorSpace* cs, const QString& id, const QString& category)
308 : base_class(cs, id, category) { }
309
310public:
311 template<bool alphaLocked, bool allChannelFlags>
313 channels_type* dst, channels_type dstAlpha, channels_type maskAlpha,
314 channels_type opacity, const QBitArray& channelFlags)
315 {
316 using namespace Arithmetic;
317
318 srcAlpha = mul(srcAlpha, maskAlpha, opacity);
319
320 if(alphaLocked) {
321 channels_type oldAlpha = dstAlpha;
322 if(dstAlpha != zeroValue<channels_type>()) {
323 for(qint32 i=0; i <channels_nb; i++) {
324 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
325 float dstValueFloat = scale<float>(BlendingPolicy::toAdditiveSpace(dst[i]));
326 float dstAlphaFloat = scale<float>(oldAlpha);
327 compositeFunc(scale<float>(BlendingPolicy::toAdditiveSpace(src[i])), scale<float>(srcAlpha), dstValueFloat, dstAlphaFloat);
328 dst[i] = BlendingPolicy::fromAdditiveSpace(scale<channels_type>(dstValueFloat));
329 }
330 }
331 }
332
333 return dstAlpha;
334 }
335 else {
336 channels_type oldAlpha = dstAlpha;
337 channels_type newDstAlpha = unionShapeOpacity(srcAlpha, dstAlpha);
338
339 if(newDstAlpha != zeroValue<channels_type>()) {
340 for(qint32 i=0; i <channels_nb; i++) {
341 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
342 float dstFloat = scale<float>(BlendingPolicy::toAdditiveSpace(dst[i]));
343 float dstAlphaFloat = scale<float>(oldAlpha);
344 compositeFunc(scale<float>(BlendingPolicy::toAdditiveSpace(src[i])), scale<float>(srcAlpha), dstFloat, dstAlphaFloat);
345 dst[i] = BlendingPolicy::fromAdditiveSpace(scale<channels_type>(dstFloat));
346 }
347 }
348 }
349
350 return newDstAlpha;
351 }
352 }
353};
354
355
356
357#endif // _KOCOMPOSITEOP_GENERIC_H_
QPointF lerp(const QPointF &p1, const QPointF &p2, qreal t)
KoCompositeOpBase< Traits, KoCompositeOpGenericHSLFunctor< Traits, CompositeOpFunctor > > base_class
static channels_type composeColorChannels(const channels_type *src, channels_type srcAlpha, channels_type *dst, channels_type dstAlpha, channels_type maskAlpha, channels_type opacity, const QBitArray &channelFlags)
KoCompositeOpGenericHSLFunctor(const KoColorSpace *cs, const QString &id, const QString &category)
Traits::channels_type channels_type
KoCompositeOpGenericSCAlpha(const KoColorSpace *cs, const QString &id, const QString &category)
static channels_type composeColorChannels(const channels_type *src, channels_type srcAlpha, channels_type *dst, channels_type dstAlpha, channels_type maskAlpha, channels_type opacity, const QBitArray &channelFlags)
KoCompositeOpBase< Traits, KoCompositeOpGenericSCAlpha< Traits, compositeFunc, BlendingPolicy > > base_class
Traits::channels_type channels_type
KoCompositeOpGenericSCFunctor(const KoColorSpace *cs, const QString &id, const QString &category)
static channels_type composeColorChannels(const channels_type *src, channels_type srcAlpha, channels_type *dst, channels_type dstAlpha, channels_type maskAlpha, channels_type opacity, const QBitArray &channelFlags)
KoCompositeOpBase< Traits, KoCompositeOpGenericSCFunctor< Traits, CompositeOpFunctor, BlendingPolicy > > base_class
static void composeChannels(float sr, float sg, float sb, float &dr, float &dg, float &db)
typename Traits::channels_type channels_type
typename Traits::channels_type channels_type
static channels_type composeChannel(channels_type src, channels_type dst)