static inline void process_channel(const fix15_t Cs, fix15_t &Cb) { const fix15_t two_Cs = fix15_double(Cs); fix15_t B = 0; if (two_Cs <= fix15_one) { B = fix15_one - fix15_mul(fix15_one - two_Cs, fix15_one - Cb); B = fix15_mul(B, Cb); } else { fix15_t D = 0; const fix15_t four_Cb = Cb << 2; if (four_Cb <= fix15_one) { const fix15_t Cb_squared = fix15_mul(Cb, Cb); D = four_Cb; /* which is always greater than... */ D += 16 * fix15_mul(Cb_squared, Cb); D -= 12 * Cb_squared; /* ... in the range 0 <= C_b <= 0.25 */ } else { D = fix15_sqrt(Cb); } #ifdef HEAVY_DEBUG /* Guard against underflows */ assert(two_Cs > fix15_one); assert(D >= Cb); #endif B = Cb + fix15_mul(2*Cs - fix15_one /* 2*Cs > 1 */, D - Cb /* D >= Cb */ ); } Cb = B; }
inline void operator() (const fix15_t src_r, const fix15_t src_g, const fix15_t src_b, fix15_t &dst_r, fix15_t &dst_g, fix15_t &dst_b) const { dst_r = dst_r + src_r - fix15_mul(dst_r, src_r); dst_g = dst_g + src_g - fix15_mul(dst_g, src_g); dst_b = dst_b + src_b - fix15_mul(dst_b, src_b); }
inline void operator() (const fix15_t src_r, const fix15_t src_g, const fix15_t src_b, fix15_t &dst_r, fix15_t &dst_g, fix15_t &dst_b) const { dst_r = fix15_mul(src_r, dst_r); dst_g = fix15_mul(src_g, dst_g); dst_b = fix15_mul(src_b, dst_b); }
inline void operator() (const fix15_t Rs, const fix15_t Gs, const fix15_t Bs, const fix15_t as, fix15_short_t &rb, fix15_short_t &gb, fix15_short_t &bb, fix15_short_t &ab) const { rb = fix15_short_clamp(fix15_mul(Rs, as) + rb); gb = fix15_short_clamp(fix15_mul(Gs, as) + gb); bb = fix15_short_clamp(fix15_mul(Bs, as) + bb); ab = fix15_short_clamp(ab + as); }
inline void operator() (const fix15_t Rs, const fix15_t Gs, const fix15_t Bs, const fix15_t as, fix15_short_t &rb, fix15_short_t &gb, fix15_short_t &bb, fix15_short_t &ab) const { rb = fix15_short_clamp(fix15_mul(rb, as)); gb = fix15_short_clamp(fix15_mul(gb, as)); bb = fix15_short_clamp(fix15_mul(bb, as)); ab = fix15_short_clamp(fix15_mul(ab, as)); }
static inline void process_channel(const fix15_t Cs, fix15_t &Cb) { const fix15_t two_Cs = fix15_double(Cs); if (two_Cs <= fix15_one) { Cb = fix15_mul(Cb, two_Cs); } else { const fix15_t tmp = two_Cs - fix15_one; Cb = Cb + tmp - fix15_mul(Cb, tmp); } }
inline void operator() (const fix15_short_t * const src, fix15_short_t * const dst, const fix15_short_t opac) const { for (unsigned int i=0; i<BUFSIZE; i+=4) { const fix15_t one_minus_Sa = fix15_one-fix15_mul(src[i+3], opac); dst[i+0] = fix15_mul(dst[i+0], one_minus_Sa); dst[i+1] = fix15_mul(dst[i+1], one_minus_Sa); dst[i+2] = fix15_mul(dst[i+2], one_minus_Sa); if (DSTALPHA) { dst[i+3] = fix15_mul(one_minus_Sa, dst[i+3]); } } }
inline void operator() (const fix15_short_t * const src, fix15_short_t * const dst, const fix15_short_t opac) const { for (unsigned int i=0; i<BUFSIZE; i+=4) { const fix15_t Sa = fix15_mul(src[i+3], opac); const fix15_t one_minus_Sa = fix15_one - Sa; dst[i+0] = fix15_sumprods(src[i], opac, one_minus_Sa, dst[i]); dst[i+1] = fix15_sumprods(src[i+1], opac, one_minus_Sa, dst[i+1]); dst[i+2] = fix15_sumprods(src[i+2], opac, one_minus_Sa, dst[i+2]); if (DSTALPHA) { fix15_t tmp = Sa + dst[i+3]; tmp -= fix15_mul(Sa, dst[i+3]); dst[i+3] = fix15_short_clamp(tmp); } } }
inline void operator() (const fix15_t Rs, const fix15_t Gs, const fix15_t Bs, const fix15_t as, fix15_short_t &rb, fix15_short_t &gb, fix15_short_t &bb, fix15_short_t &ab) const { const fix15_t j = fix15_one - as; const fix15_t k = fix15_mul(ab, j); rb = fix15_short_clamp(fix15_sumprods(as, Rs, j, rb)); gb = fix15_short_clamp(fix15_sumprods(as, Gs, j, gb)); bb = fix15_short_clamp(fix15_sumprods(as, Bs, j, bb)); ab = fix15_short_clamp(as + k); }
inline void operator() (const fix15_t Rs, const fix15_t Gs, const fix15_t Bs, const fix15_t as, fix15_short_t &rb, fix15_short_t &gb, fix15_short_t &bb, fix15_short_t &ab) const { // W3C spec: // co = as*Cs*(1-ab) + ab*Cb*as // where // Cs ∈ {Rs, Gs, Bs} -- input is non-premultiplied // cb ∈ {rb gb, bb} = ab*Cb -- output is premultiplied by alpha const fix15_t one_minus_ab = fix15_one - ab; const fix15_t as_mul_one_minus_ab = fix15_mul(as, one_minus_ab); rb = fix15_short_clamp(fix15_sumprods(as_mul_one_minus_ab, Rs, as, rb)); gb = fix15_short_clamp(fix15_sumprods(as_mul_one_minus_ab, Gs, as, gb)); bb = fix15_short_clamp(fix15_sumprods(as_mul_one_minus_ab, Bs, as, bb)); // W3C spec: // ao = as*(1-ab) + ab*as // ao = as ab = as; }
inline void operator() (const fix15_t Rs, const fix15_t Gs, const fix15_t Bs, const fix15_t as, fix15_short_t &rb, fix15_short_t &gb, fix15_short_t &bb, fix15_short_t &ab) const { // W3C spec: // co = as*Cs*ab + ab*Cb*(1-as) // where // Cs ∈ {Rs, Gs, Bs} -- input is non-premultiplied // cb ∈ {rb gb, bb} = ab*Cb -- output is premultiplied by alpha const fix15_t one_minus_as = fix15_one - as; const fix15_t ab_mul_as = fix15_mul(as, ab); rb = fix15_short_clamp(fix15_sumprods(ab_mul_as, Rs, one_minus_as, rb)); gb = fix15_short_clamp(fix15_sumprods(ab_mul_as, Gs, one_minus_as, gb)); bb = fix15_short_clamp(fix15_sumprods(ab_mul_as, Bs, one_minus_as, bb)); // W3C spec: // ao = as*ab + ab*(1-as) // ao = ab // (leave output alpha unchanged) }
inline void operator() (const fix15_short_t * const src, fix15_short_t * const dst, const fix15_short_t src_opacity) const { #ifndef HEAVY_DEBUG // Skip tile if it can't affect the backdrop const bool skip_empty_src = ! compositefunc.zero_alpha_has_effect; if (skip_empty_src && src_opacity == 0) { return; } #endif // Pixel loop fix15_t Rs,Gs,Bs,as, Rb,Gb,Bb,ab, one_minus_ab; #pragma omp parallel for private(Rs,Gs,Bs,as, Rb,Gb,Bb,ab, one_minus_ab) for (unsigned int i = 0; i < BUFSIZE; i += 4) { // Calculate unpremultiplied source RGB values as = src[i+3]; if (as == 0) { #ifndef HEAVY_DEBUG // Skip pixel if it can't affect the backdrop pixel if (skip_empty_src) { continue; } #endif // Otherwise just avoid the divide-by-zero by assuming the // value before premultiplication was also zero. Rs = Gs = Bs = 0; } else { Rs = fix15_short_clamp(fix15_div(src[i+0], as)); Gs = fix15_short_clamp(fix15_div(src[i+1], as)); Bs = fix15_short_clamp(fix15_div(src[i+2], as)); } #ifdef HEAVY_DEBUG assert(Rs <= fix15_one); assert(Rs >= 0); assert(Gs <= fix15_one); assert(Gs >= 0); assert(Bs <= fix15_one); assert(Bs >= 0); #endif // Calculate unpremultiplied backdrop RGB values if (DSTALPHA) { ab = dst[i+3]; if (ab == 0) { Rb = Gb = Bb = 0; } else { Rb = fix15_short_clamp(fix15_div(dst[i+0], ab)); Gb = fix15_short_clamp(fix15_div(dst[i+1], ab)); Bb = fix15_short_clamp(fix15_div(dst[i+2], ab)); } } else { ab = fix15_one; Rb = dst[i+0]; Gb = dst[i+1]; Bb = dst[i+2]; } #ifdef HEAVY_DEBUG assert(Rb <= fix15_one); assert(Rb >= 0); assert(Gb <= fix15_one); assert(Gb >= 0); assert(Bb <= fix15_one); assert(Bb >= 0); #endif // Apply the colour blend functor blendfunc(Rs, Gs, Bs, Rb, Gb, Bb); // Apply results of the blend in place if (DSTALPHA) { one_minus_ab = fix15_one - ab; Rb = fix15_sumprods(one_minus_ab, Rs, ab, Rb); Gb = fix15_sumprods(one_minus_ab, Gs, ab, Gb); Bb = fix15_sumprods(one_minus_ab, Bs, ab, Bb); } #ifdef HEAVY_DEBUG assert(Rb <= fix15_one); assert(Rb >= 0); assert(Gb <= fix15_one); assert(Gb >= 0); assert(Bb <= fix15_one); assert(Bb >= 0); #endif // Use the blend result as a source, and composite directly into // the destination buffer as premultiplied RGB. compositefunc(Rb, Gb, Bb, fix15_mul(as, src_opacity), dst[i+0], dst[i+1], dst[i+2], dst[i+3]); } }
static inline void process_channel(const fix15_t Cs, fix15_t &Cb) { Cb = Cb + Cs - fix15_double(fix15_mul(Cb, Cs)); }