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