Untitled

 avatar
unknown
c_cpp
2 years ago
3.5 kB
7
Indexable
#ifndef KOCOMPOSITEOPWETOVER_H
#define KOCOMPOSITEOPWETOVER_H

#include "KoCompositeOpBase.h"
#include "KoCompositeOpFunctions.h"
#include "KoCompositeOpRegistry.h"

/**
 * Wet Normal compositor - uses the greater of two alpha values as final alpha,
 * color channels are blended with Over function (Normal blend).
 */

template<class CS_Traits>
class KoCompositeOpWetOver : public KoCompositeOpBase<CS_Traits, KoCompositeOpWetOver<CS_Traits>>
{
    typedef KoCompositeOpBase<CS_Traits, KoCompositeOpWetOver<CS_Traits>> base_class;
    typedef typename CS_Traits::channels_type channels_type;
    typedef typename KoColorSpaceMathsTraits<typename CS_Traits::channels_type>::compositetype composite_type;

    static const qint8 channels_nb = CS_Traits::channels_nb;
    static const qint8 alpha_pos = CS_Traits::alpha_pos;

public:
    KoCompositeOpWetOver(const KoColorSpace *cs)
        : base_class(cs, COMPOSITE_WET_OVER, KoCompositeOp::categoryMix())
    {
    }

public:
    template<bool alphaLocked, bool allChannelFlags>
    inline 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)
    {
        using namespace Arithmetic;

        srcAlpha = mul(srcAlpha, maskAlpha, opacity);

        if (alphaLocked) {
            if (dstAlpha != zeroValue<channels_type>()) {
                for (qint32 i = 0; i < channels_nb; i++) {
                    if (i != alpha_pos && (allChannelFlags || channelFlags.testBit(i)))
                        dst[i] = lerp(dst[i], cfOver(src[i], dst[i]), srcAlpha);
                }
            }

            return dstAlpha;
        } else {
            channels_type newDstAlpha = unionShapeOpacity(srcAlpha, dstAlpha);

            if (newDstAlpha != zeroValue<channels_type>()) {
                for (qint32 i = 0; i < channels_nb; i++) {
                    if (i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
                        //channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, src[i]);
                        channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, cfOver(src[i], dst[i]));
                        dst[i] = div(result, newDstAlpha);
                    }
                }
            }

            float dA = scale<float>(dstAlpha);

            float w = 1.0 / (1.0 + exp(-40.0 * (dA - scale<float>(srcAlpha))));
            float a = dA * w + scale<float>(srcAlpha) * (1.0 - w);
            if (a < 0.0f) {
                a = 0.0f;
            }
            if (a > 1.0f) {
                a = 1.0f;
            }

            // For a standard Over, the resulting alpha is: a = opacity*dstAlpha + (1-opacity)*srcAlpha
            // Let us assume we're blending with a color with srcAlpha = 1 here
            // Therefore, opacity = (1.0 - a)/(1.0 - dstAlpha)
            if (a < dA)
                a = dA;
            //            float fakeOpacity = 1.0f - (1.0f - a)/(1.0f - dA + 1e-16f);
            newDstAlpha = scale<channels_type>(a);

            return newDstAlpha;
        }
    }
};

#endif // KOCOMPOSITEOPWETOVER_H
Editor is loading...