Skip to content

Instantly share code, notes, and snippets.

@loentar
Created April 5, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loentar/bb7ccdda021f33b63516 to your computer and use it in GitHub Desktop.
Save loentar/bb7ccdda021f33b63516 to your computer and use it in GitHub Desktop.
diff --git a/lib/blending.hpp b/lib/blending.hpp
index d61c741..0c800ff 100644
--- a/lib/blending.hpp
+++ b/lib/blending.hpp
@@ -107,6 +107,32 @@ class BufferCombineFunc <DSTALPHA, BUFSIZE, BlendNormal, CompositeDestinationOut
// Da' = Da × (1 - Sa)
+template <bool DSTALPHA, unsigned int BUFSIZE>
+class BufferCombineFunc <DSTALPHA, BUFSIZE, BlendNormal, CompositeDestinationAtop>
+{
+ // Partial specialization for normal lainting layers,
+ // working in premultiplied alpha for speed.
+ public:
+ 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 as = fix15_mul(src[i+3], opac);
+ const fix15_t one_minus_ab = fix15_one - dst[i+3];
+ const fix15_t ab_mul_as = fix15_mul(dst[i+3], as);
+ const fix15_t as_mul_one_minus_ab = fix15_mul(as, one_minus_ab);
+ dst[i+0] = fix15_sumprods(src[i+0], as_mul_one_minus_ab, dst[i+0], ab_mul_as);
+ dst[i+1] = fix15_sumprods(src[i+1], as_mul_one_minus_ab, dst[i+1], ab_mul_as);
+ dst[i+2] = fix15_sumprods(src[i+2], as_mul_one_minus_ab, dst[i+2], ab_mul_as);
+ if (DSTALPHA) {
+ dst[i+3] = fix15_short_clamp(fix15_mul(as, one_minus_ab) + ab_mul_as);
+ }
+ }
+ }
+};
+
+
// Multiply: http://www.w3.org/TR/compositing/#blendingmultiply
class BlendMultiply : public BlendFunc
diff --git a/lib/compositing.hpp b/lib/compositing.hpp
index 5d983f7..dc956f4 100644
--- a/lib/compositing.hpp
+++ b/lib/compositing.hpp
@@ -269,6 +269,33 @@ class CompositeDestinationOut : public CompositeFunc
};
+// Destination-Atop: Destination which overlaps the source replaces the source.
+// Source is placed elsewhere.
+// http://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
+
+class CompositeDestinationAtop : public CompositeFunc
+{
+ public:
+ 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 one_minus_ab = fix15_one - ab;
+ const fix15_t as_mul_one_minus_ab = fix15_mul(as, one_minus_ab);
+ const fix15_t ab_mul_as = fix15_mul(as, ab);
+
+ rb = fix15_short_clamp(fix15_sumprods(as_mul_one_minus_ab, Rs, ab_mul_as, rb));
+ gb = fix15_short_clamp(fix15_sumprods(as_mul_one_minus_ab, Gs, ab_mul_as, gb));
+ bb = fix15_short_clamp(fix15_sumprods(as_mul_one_minus_ab, Bs, ab_mul_as, bb));
+ ab = fix15_short_clamp(as_mul_one_minus_ab + ab_mul_as);
+ }
+
+ static const bool zero_alpha_has_effect = true;
+ static const bool can_decrease_alpha = true;
+};
+
+
// W3C "Lighter", a.k.a. Porter-Duff "plus", a.k.a. "svg:plus". This just adds
// together corresponding channels of the destination and source.
// Ref: http://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
diff --git a/lib/layer/consts.py b/lib/layer/consts.py
index f50b95f..701db19 100644
--- a/lib/layer/consts.py
+++ b/lib/layer/consts.py
@@ -113,6 +113,10 @@ MODE_STRINGS = {
_("Destination Out"),
_("Uses the backdrop only where this layer doesn't cover it. "
"Everything else is ignored.")),
+ lib.mypaintlib.CombineDestinationAtop: (
+ _("Destination Atop"),
+ _("Destination which overlaps the source replaces the source. "
+ "Source is placed elsewhere.")),
}
for mode in STANDARD_MODES + STACK_MODES:
assert mode in MODE_STRINGS
diff --git a/lib/pixops.cpp b/lib/pixops.cpp
index 794ce4b..e0a9e54 100644
--- a/lib/pixops.cpp
+++ b/lib/pixops.cpp
@@ -675,7 +675,8 @@ static const TileDataCombineOp * combine_mode_info[NumCombineModes] =
// Normal blend mode + various compositing operators
new TileDataCombine<BlendNormal, CompositeLighter>("svg:plus"),
new TileDataCombine<BlendNormal, CompositeDestinationIn>("svg:dst-in"),
- new TileDataCombine<BlendNormal, CompositeDestinationOut>("svg:dst-out")
+ new TileDataCombine<BlendNormal, CompositeDestinationOut>("svg:dst-out"),
+ new TileDataCombine<BlendNormal, CompositeDestinationAtop>("svg:dst-atop")
};
diff --git a/lib/pixops.hpp b/lib/pixops.hpp
index 1e12c9f..972cf35 100644
--- a/lib/pixops.hpp
+++ b/lib/pixops.hpp
@@ -110,6 +110,7 @@ enum CombineMode {
CombineLighter, // normal blend mode, and W3C lightER (Porter-Duff PLUS)
CombineDestinationIn,
CombineDestinationOut,
+ CombineDestinationAtop,
NumCombineModes
};
diff --git a/lib/tiledsurface.py b/lib/tiledsurface.py
index 931873f..3be1678 100644
--- a/lib/tiledsurface.py
+++ b/lib/tiledsurface.py
@@ -319,7 +319,7 @@ class MyPaintSurface (object):
"""
if opacity == 0:
- if mode == mypaintlib.CombineDestinationIn:
+ if mode == mypaintlib.CombineDestinationIn or mode == mypaintlib.CombineDestinationAtop:
if dst_has_alpha:
mypaintlib.tile_clear_rgba16(dst)
return
@@ -333,7 +333,7 @@ class MyPaintSurface (object):
with self.tile_request(tx, ty, readonly=True) as src:
if src is transparent_tile.rgba:
- if mode == mypaintlib.CombineDestinationIn:
+ if mode == mypaintlib.CombineDestinationIn or mode == mypaintlib.CombineDestinationAtop:
if dst_has_alpha:
mypaintlib.tile_clear_rgba16(dst)
return
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment