File indexing completed on 2024-12-22 04:11:38
0001 /* 0002 * SPDX-FileCopyrightText: 2006, 2010 Cyrille Berger <cberger@cberger.net> 0003 * SPDX-FileCopyrightText: 2007 Emanuele Tamponi <emanuele@valinor.it> 0004 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com> 0005 * SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de> 0006 * 0007 * SPDX-License-Identifier: LGPL-2.1-or-later 0008 */ 0009 0010 #ifndef KO_COMPOSITEOP_COPY2_H 0011 #define KO_COMPOSITEOP_COPY2_H 0012 0013 #include "KoCompositeOpBase.h" 0014 0015 /** 0016 * Generic implementation of the COPY composite op which respects selection. 0017 * 0018 * Note: this composite op is necessary with the deform brush and should not 0019 * be hidden. 0020 */ 0021 template<class Traits> 0022 class KoCompositeOpCopy2: public KoCompositeOpBase< Traits, KoCompositeOpCopy2<Traits> > 0023 { 0024 typedef KoCompositeOpBase< Traits, KoCompositeOpCopy2<Traits> > base_class; 0025 typedef typename Traits::channels_type channels_type; 0026 0027 static const qint32 channels_nb = Traits::channels_nb; 0028 static const qint32 alpha_pos = Traits::alpha_pos; 0029 0030 public: 0031 KoCompositeOpCopy2(const KoColorSpace* cs) 0032 : base_class(cs, COMPOSITE_COPY, KoCompositeOp::categoryMisc()) { } 0033 0034 public: 0035 template<bool alphaLocked, bool allChannelFlags> 0036 inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, 0037 channels_type* dst, channels_type dstAlpha, channels_type maskAlpha, 0038 channels_type opacity, const QBitArray& channelFlags) { 0039 using namespace Arithmetic; 0040 opacity = mul(maskAlpha, opacity); 0041 0042 channels_type newAlpha = zeroValue<channels_type>(); 0043 0044 if (opacity == unitValue<channels_type>()) { 0045 if (!alphaLocked || srcAlpha != zeroValue<channels_type>()) { 0046 // don't blend if the color of the destination is undefined (has zero opacity) 0047 // copy the source channel instead 0048 for(qint32 i=0; i<channels_nb; ++i) 0049 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) 0050 dst[i] = src[i]; 0051 } 0052 0053 newAlpha = srcAlpha; 0054 0055 } else if (opacity == zeroValue<channels_type>()) { 0056 0057 newAlpha = dstAlpha; 0058 0059 } else { // opacity 0...1 0060 0061 if (!alphaLocked || srcAlpha != zeroValue<channels_type>()) { 0062 0063 newAlpha = lerp(dstAlpha, srcAlpha, opacity); 0064 0065 if (newAlpha == zeroValue<channels_type>()) { 0066 return newAlpha; 0067 } 0068 0069 // blend the color channels 0070 for(qint32 i=0; i<channels_nb; ++i) { 0071 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) { 0072 0073 // We use the most fundamental OVER algorithm here, 0074 // which multiplies, blends and then unmultiplies the 0075 // channels 0076 0077 typedef typename KoColorSpaceMathsTraits<channels_type>::compositetype composite_type; 0078 0079 channels_type dstMult = mul(dst[i], dstAlpha); 0080 channels_type srcMult = mul(src[i], srcAlpha); 0081 channels_type blendedValue = lerp(dstMult, srcMult, opacity); 0082 0083 composite_type normedValue = KoColorSpaceMaths<channels_type>::divide(blendedValue, newAlpha); 0084 0085 dst[i] = KoColorSpaceMaths<channels_type>::clampAfterScale(normedValue); 0086 } 0087 } 0088 } 0089 0090 } 0091 0092 return newAlpha; 0093 } 0094 }; 0095 0096 #endif // KO_COMPOSITEOP_COPY2_H