37 using float_m =
typename float_v::batch_bool_type;
43 opacity = oparams.opacity;
44 const float_v opacity_vec(255.0f * opacity);
46 const float_v average_opacity_vec(255.0 * oparams.averageOpacity);
47 const float_v flow_norm_vec(oparams.flow);
49 const float_v uint8MaxRec2(1.0f / (255.0f * 255.0f));
50 const float_v uint8MaxRec1(1.0f / 255.0f);
51 const float_v uint8Max(255.0f);
52 const float_v zeroValue(0);
56 const float_v msk_norm_alpha = [&]() {
59 return src_alpha * mask_vec * uint8MaxRec2;
61 return src_alpha * uint8MaxRec1;
66 src_alpha = msk_norm_alpha * opacity_vec;
68 const float_m empty_dst_pixels_mask = dst_alpha == zeroValue;
80 const bool srcAlphaIsZero = xsimd::all(src_alpha == zeroValue);
81 if (srcAlphaIsZero)
return;
83 const bool dstAlphaIsZero = xsimd::all(empty_dst_pixels_mask);
85 const float_v dst_blend = src_alpha * uint8MaxRec1;
87 const bool srcAlphaIsUnit = xsimd::all(src_alpha == uint8Max);
93 }
else if (srcAlphaIsUnit) {
94 const bool dstAlphaIsUnit = xsimd::all(dst_alpha == uint8Max);
96 memcpy(dst, src, 4 * float_v::size);
103 }
else if (xsimd::none(empty_dst_pixels_mask)) {
105 dst_c1 = dst_blend * (src_c1 - dst_c1) + dst_c1;
106 dst_c2 = dst_blend * (src_c2 - dst_c2) + dst_c2;
107 dst_c3 = dst_blend * (src_c3 - dst_c3) + dst_c3;
110 dst_c1 = xsimd::select(empty_dst_pixels_mask, src_c1, dst_blend * (src_c1 - dst_c1) + dst_c1);
111 dst_c2 = xsimd::select(empty_dst_pixels_mask, src_c2, dst_blend * (src_c2 - dst_c2) + dst_c2);
112 dst_c3 = xsimd::select(empty_dst_pixels_mask, src_c3, dst_blend * (src_c3 - dst_c3) + dst_c3);
115 const float_v fullFlowAlpha = [&]() {
116 if (oparams.averageOpacity > opacity) {
117 const float_m fullFlowAlpha_mask = average_opacity_vec > dst_alpha;
119 if (xsimd::none(fullFlowAlpha_mask)) {
122 const float_v reverse_blend = dst_alpha / average_opacity_vec;
123 const float_v opt1 = (average_opacity_vec - src_alpha) * reverse_blend + src_alpha;
124 return xsimd::select(fullFlowAlpha_mask, opt1, dst_alpha);
127 const float_m fullFlowAlpha_mask = opacity_vec > dst_alpha;
129 if (xsimd::none(fullFlowAlpha_mask)) {
132 const float_v opt1 = (opacity_vec - dst_alpha) * msk_norm_alpha + dst_alpha;
133 return xsimd::select(fullFlowAlpha_mask, opt1, dst_alpha);
139 if (oparams.flow == 1.0) {
140 return fullFlowAlpha;
142 const float_v zeroFlowAlpha = ParamsWrapper::calculateZeroFlowAlpha(src_alpha, dst_alpha, uint8MaxRec1);
143 return (fullFlowAlpha - zeroFlowAlpha) * flow_norm_vec + zeroFlowAlpha;
157 const qint32 alpha_pos = 3;
159 const float uint8Rec1 = 1.0f / 255.0f;
160 const float uint8Rec2 = 1.0f / (255.0f * 255.0f);
161 const float uint8Max = 255.0;
167 opacity = oparams.opacity;
169 const quint8 dstAlphaInt = dst[alpha_pos];
170 const float dstAlphaNorm = dstAlphaInt ? dstAlphaInt * uint8Rec1 : 0.0;
171 const float mskAlphaNorm = [&]() {
173 return float(*mask) * uint8Rec2 * src[alpha_pos];
175 return src[alpha_pos] * uint8Rec1;
178 const float srcAlphaNorm = mskAlphaNorm * opacity;
180 if (dstAlphaInt != 0) {
185 const auto *s =
reinterpret_cast<const pixel_type*
>(src);
186 auto *d =
reinterpret_cast<pixel_type*
>(dst);
191 const float flow = oparams.flow;
192 const float averageOpacity = oparams.averageOpacity;
194 const float fullFlowAlpha = [&]() {
195 if (averageOpacity > opacity) {
196 return averageOpacity > dstAlphaNorm ?
lerp(srcAlphaNorm, averageOpacity, dstAlphaNorm / averageOpacity) : dstAlphaNorm;
198 return opacity > dstAlphaNorm ?
lerp(dstAlphaNorm, opacity, mskAlphaNorm) : dstAlphaNorm;
202 const float dstAlpha = [&](){
204 return fullFlowAlpha * uint8Max;
206 const float zeroFlowAlpha = ParamsWrapper::calculateZeroFlowAlpha(srcAlphaNorm, dstAlphaNorm);
207 return lerp(zeroFlowAlpha, fullFlowAlpha, flow) * uint8Max;