1 /*
2  * Copyright (c) 2011 Silvio Heinrich <plassy@web.de>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18 */
19 
20 #ifndef _KOCOMPOSITEOP_GENERIC_H_
21 #define _KOCOMPOSITEOP_GENERIC_H_
22 
23 #include "KoCompositeOpFunctions.h"
24 #include "KoCompositeOpBase.h"
25 
26 /**
27  * Generic CompositeOp for separable channel compositing functions
28  *
29  * A template to generate a KoCompositeOp class by just specifying a
30  * blending/compositing function. This template works with compositing functions
31  * for separable channels (means each channel of a pixel can be processed separately)
32  */
33 template<
34     class Traits,
35     typename Traits::channels_type compositeFunc(typename Traits::channels_type, typename Traits::channels_type)
36 >
37 class KoCompositeOpGenericSC: public KoCompositeOpBase< Traits, KoCompositeOpGenericSC<Traits,compositeFunc> >
38 {
39     typedef KoCompositeOpBase< Traits, KoCompositeOpGenericSC<Traits,compositeFunc> > base_class;
40     typedef typename Traits::channels_type                                            channels_type;
41 
42     static const qint32 channels_nb = Traits::channels_nb;
43     static const qint32 alpha_pos   = Traits::alpha_pos;
44 
45 public:
KoCompositeOpGenericSC(const KoColorSpace * cs,const QString & id,const QString & description,const QString & category)46     KoCompositeOpGenericSC(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category)
47         : base_class(cs, id, description, category) { }
48 
49 public:
50     template<bool alphaLocked, bool allChannelFlags>
composeColorChannels(const channels_type * src,channels_type srcAlpha,channels_type * dst,channels_type dstAlpha,channels_type maskAlpha,channels_type opacity,const QBitArray & channelFlags)51     inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
52                                                      channels_type*       dst, channels_type dstAlpha, channels_type maskAlpha,
53                                                      channels_type opacity, const QBitArray& channelFlags) {
54         using namespace Arithmetic;
55 
56         srcAlpha = mul(srcAlpha, maskAlpha, opacity);
57 
58         if(alphaLocked) {
59             if(dstAlpha != zeroValue<channels_type>()) {
60                 for(qint32 i=0; i <channels_nb; i++) {
61                     if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i)))
62                         dst[i] = lerp(dst[i], compositeFunc(src[i],dst[i]), srcAlpha);
63                 }
64             }
65 
66             return dstAlpha;
67         }
68         else {
69             channels_type newDstAlpha = unionShapeOpacity(srcAlpha, dstAlpha);
70 
71             if(newDstAlpha != zeroValue<channels_type>()) {
72                 for(qint32 i=0; i <channels_nb; i++) {
73                     if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
74                         channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, compositeFunc(src[i],dst[i]));
75                         dst[i] = div(result, newDstAlpha);
76                     }
77                 }
78             }
79 
80             return newDstAlpha;
81         }
82     }
83 };
84 
85 
86 /**
87  * Generic CompositeOp for nonseparable/HSL channel compositing functions
88  *
89  * A template to generate a KoCompositeOp class by just specifying a
90  * blending/compositing function. This template works with compositing functions
91  * for RGB channels only (the channels can not be processed separately)
92  */
93 template<class Traits, void compositeFunc(float, float, float, float&, float&, float&)>
94 class KoCompositeOpGenericHSL: public KoCompositeOpBase< Traits, KoCompositeOpGenericHSL<Traits,compositeFunc> >
95 {
96     typedef KoCompositeOpBase< Traits, KoCompositeOpGenericHSL<Traits,compositeFunc> > base_class;
97     typedef typename Traits::channels_type                                             channels_type;
98 
99     static const qint32 red_pos   = Traits::red_pos;
100     static const qint32 green_pos = Traits::green_pos;
101     static const qint32 blue_pos  = Traits::blue_pos;
102 
103 public:
KoCompositeOpGenericHSL(const KoColorSpace * cs,const QString & id,const QString & description,const QString & category)104     KoCompositeOpGenericHSL(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category)
105         : base_class(cs, id, description, category) { }
106 
107 public:
108     template<bool alphaLocked, bool allChannelFlags>
composeColorChannels(const channels_type * src,channels_type srcAlpha,channels_type * dst,channels_type dstAlpha,channels_type maskAlpha,channels_type opacity,const QBitArray & channelFlags)109     inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
110                                                      channels_type*       dst, channels_type dstAlpha, channels_type maskAlpha,
111                                                      channels_type opacity, const QBitArray& channelFlags) {
112         using namespace Arithmetic;
113 
114         srcAlpha = mul(srcAlpha, maskAlpha, opacity);
115 
116         if(alphaLocked) {
117             if(dstAlpha != zeroValue<channels_type>()) {
118                 float srcR = scale<float>(src[red_pos]);
119                 float srcG = scale<float>(src[green_pos]);
120                 float srcB = scale<float>(src[blue_pos]);
121 
122                 float dstR = scale<float>(dst[red_pos]);
123                 float dstG = scale<float>(dst[green_pos]);
124                 float dstB = scale<float>(dst[blue_pos]);
125 
126                 compositeFunc(srcR, srcG, srcB, dstR, dstG, dstB);
127 
128                 if(allChannelFlags || channelFlags.testBit(red_pos))
129                     dst[red_pos] = lerp(dst[red_pos], scale<channels_type>(dstR), srcAlpha);
130 
131                 if(allChannelFlags || channelFlags.testBit(green_pos))
132                     dst[green_pos] = lerp(dst[green_pos], scale<channels_type>(dstG), srcAlpha);
133 
134                 if(allChannelFlags || channelFlags.testBit(blue_pos))
135                     dst[blue_pos] = lerp(dst[blue_pos], scale<channels_type>(dstB), srcAlpha);
136             }
137 
138             return dstAlpha;
139         }
140         else {
141             channels_type newDstAlpha = unionShapeOpacity(srcAlpha, dstAlpha);
142 
143             if(newDstAlpha != zeroValue<channels_type>()) {
144                 float srcR = scale<float>(src[red_pos]);
145                 float srcG = scale<float>(src[green_pos]);
146                 float srcB = scale<float>(src[blue_pos]);
147 
148                 float dstR = scale<float>(dst[red_pos]);
149                 float dstG = scale<float>(dst[green_pos]);
150                 float dstB = scale<float>(dst[blue_pos]);
151 
152                 compositeFunc(srcR, srcG, srcB, dstR, dstG, dstB);
153 
154                 if(allChannelFlags || channelFlags.testBit(red_pos))
155                     dst[red_pos] = div(blend(src[red_pos], srcAlpha, dst[red_pos], dstAlpha, scale<channels_type>(dstR)), newDstAlpha);
156 
157                 if(allChannelFlags || channelFlags.testBit(green_pos))
158                     dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], dstAlpha, scale<channels_type>(dstG)), newDstAlpha);
159 
160                 if(allChannelFlags || channelFlags.testBit(blue_pos))
161                     dst[blue_pos] = div(blend(src[blue_pos], srcAlpha, dst[blue_pos], dstAlpha, scale<channels_type>(dstB)), newDstAlpha);
162             }
163 
164             return newDstAlpha;
165         }
166     }
167 };
168 
169 #endif // _KOCOMPOSITEOP_GENERIC_H_
170