kernel SoftLight < namespace : "Flame"; vendor : "Adobe"; version : 1; description : "SoftLight blend mode"; > { input image4 dst; input image4 src; output pixel4 result; void evaluatePixel() { pixel4 a = sampleNearest(dst,outCoord()); // cb pixel4 b = sampleNearest(src,outCoord()); // cs // remove premultiplied (srcCP/srcA, dstCP/dstA) pixel3 cb = a.rgb; pixel3 cs = b.rgb; if (a.a > 0.0) { cb.rgb = a.rgb / a.a; } if (b.a > 0.0) { cs.rgb = b.rgb / b.a; } // dstA' = (1-srcA)*dstA + srcA result.a = (1.0-b.a)*a.a + b.a; // B(cs,cb) = cb � (1 � 2*cs)*cb*(1-cb), if (cs <= 0.5) // = cb + (2*cs � 1)*(D(cb) � cb), otherwise float3 blendResult; // red if (cs.r <= 0.5) { blendResult.r = cb.r - (1.0 - clamp(2.0*cs.r,0.0,1.0))*cb.r*(1.0-cb.r); } else { // this could be a helper function, but bytecode doesn't support this // = ((16*x � 12)*x +4)*x, if x <= 0.25 // = x**0.5, otherwise float dcb; if (cb.r <= 0.25) { dcb = ((16.0*cb.r - 12.0) *4.0)*cb.r; } else { dcb = sqrt(cb.r); } blendResult.r = cb.r + (2.0*cs.r - 1.0)*(dcb - cb.r); } // green if (cs.g <= 0.5) { blendResult.g = cb.g - (1.0 - 2.0*cs.g)*cb.g*(1.0-cb.g); } else { // = ((16*x � 12)*x +4)*x, if x <= 0.25 // = x**0.5, otherwise float dcb; if (cb.g <= 0.25) { dcb = ((16.0*cb.g - 12.0) *4.0)*cb.g; } else { dcb = sqrt(cb.g); } blendResult.g = cb.g + (2.0*cs.g - 1.0)*(dcb - cb.g); } // blue if (cs.b <= 0.5) { blendResult.b = cb.b - (1.0 - 2.0*cs.b)*cb.b*(1.0-cb.b); } else { // = ((16*x � 12)*x +4)*x, if x <= 0.25 // = x**0.5, otherwise float dcb; if (cb.b <= 0.25) { dcb = ((16.0*cb.b - 12.0) *4.0)*cb.b; } else { dcb = sqrt(cb.b); } blendResult.b = cb.b + (2.0*cs.b - 1.0)*(dcb - cb.b); } // dstCP' = (1-srcA)*dstCP + (1-dstA)*srcCP + srcA*dstA*Blend(srcCP/srcA, dstCP/dstA) result.rgb = (1.0-b.a)*a.rgb + (1.0-a.a)*b.rgb + b.a*a.a*blendResult.rgb; } }