Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/mypaint/lib/composite_rgbx.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'mypaint/lib/composite_rgbx.hpp')
-rw-r--r--mypaint/lib/composite_rgbx.hpp329
1 files changed, 329 insertions, 0 deletions
diff --git a/mypaint/lib/composite_rgbx.hpp b/mypaint/lib/composite_rgbx.hpp
new file mode 100644
index 0000000..d7bdc87
--- /dev/null
+++ b/mypaint/lib/composite_rgbx.hpp
@@ -0,0 +1,329 @@
+/* This file is part of MyPaint.
+ * Copyright (C) 2012 by Andrew Chadwick <a.t.chadwick@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+inline void
+#ifdef COMPOSITE_MODE_RGBA
+rgba_composite_src_over_rgba
+#else
+rgba_composite_src_over_rgbu
+#endif
+ (const uint16_t src_p[],
+ uint16_t dst_p[],
+ const uint16_t opac)
+{
+ const uint16_t src_alpha = CLAMP((uint32_t)(opac*src_p[3])>>15, 0, 1<<15);
+ const uint32_t one_minus_src_alpha = (1<<15) - src_alpha;
+
+ // Dca: destination component with premult alpha
+ // Da: destination alpha channel
+ //
+ // Dca' = Sca*Da + Sca*(1 - Da) + Dca*(1 - Sa)
+ // = Sca + Dca*(1 - Sa)
+ //
+ dst_p[0] = ((uint32_t)src_p[0]*opac + one_minus_src_alpha*dst_p[0]) >> 15;
+ dst_p[1] = ((uint32_t)src_p[1]*opac + one_minus_src_alpha*dst_p[1]) >> 15;
+ dst_p[2] = ((uint32_t)src_p[2]*opac + one_minus_src_alpha*dst_p[2]) >> 15;
+
+#ifdef COMPOSITE_MODE_RGBA
+ // Da' = Sa*Da + Sa*(1 - Da) + Da*(1 - Sa)
+ // = (Sa*Da + Sa - Sa*Da) + Da*(1 - Sa)
+ // = Sa + Da*(1 - Sa)
+ //
+ dst_p[3] = src_alpha + ((one_minus_src_alpha*dst_p[3]) >> 15);
+#endif
+}
+
+
+inline void
+#ifdef COMPOSITE_MODE_RGBA
+rgba_composite_multiply_rgba
+#else
+rgba_composite_multiply_rgbu
+#endif
+ (const uint16_t src_p[],
+ uint16_t dst_p[],
+ const uint16_t opac)
+{
+ // Dca' = Sca*Dca + Sca*(1 - Da) + Dca*(1 - Sa)
+ //
+ // If Da == 1, which is the case in RGBU mode, this becomes
+ //
+ // Dca' = Sca*Dca + 0 + Dca*(1 - Sa)
+ // = Dca * (Sca + (1 - Sa))
+ //
+ const uint16_t src_alpha = CLAMP((uint32_t)(opac * src_p[3]) / (1<<15),
+ 0, 1<<15);
+ const uint32_t one_minus_src_alpha = (1<<15) - src_alpha;
+ const uint32_t src_col0 = ((uint32_t) src_p[0] * opac) >> 15;
+ const uint32_t src_col1 = ((uint32_t) src_p[1] * opac) >> 15;
+ const uint32_t src_col2 = ((uint32_t) src_p[2] * opac) >> 15;
+ dst_p[0] = ((uint32_t)src_col0*dst_p[0]+one_minus_src_alpha*dst_p[0])>>15;
+ dst_p[1] = ((uint32_t)src_col1*dst_p[1]+one_minus_src_alpha*dst_p[1])>>15;
+ dst_p[2] = ((uint32_t)src_col2*dst_p[2]+one_minus_src_alpha*dst_p[2])>>15;
+#ifdef COMPOSITE_MODE_RGBA
+ // Sca*(1 - Da) != 0, add it in
+ const uint32_t one_minus_dst_alpha = (1<<15) - dst_p[3];
+ dst_p[0] += (((uint32_t)src_col0 * one_minus_dst_alpha) >> 15);
+ dst_p[1] += (((uint32_t)src_col1 * one_minus_dst_alpha) >> 15);
+ dst_p[2] += (((uint32_t)src_col2 * one_minus_dst_alpha) >> 15);
+
+ // Da' = Sa*Da + Sa*(1 - Da) + Da*(1 - Sa)
+ // = (Sa*Da + Sa - Sa*Da) + Da*(1 - Sa)
+ // = Sa + (1 - Sa)*Da
+ dst_p[3] = src_alpha + ((one_minus_src_alpha*dst_p[3]) >> 15);
+#endif
+}
+
+
+inline void
+#ifdef COMPOSITE_MODE_RGBA
+rgba_composite_screen_rgba
+#else
+rgba_composite_screen_rgbu
+#endif
+ (const uint16_t src_p[],
+ uint16_t dst_p[],
+ const uint16_t opac)
+{
+ // Dca' = (Sca*Da + Dca*Sa - Sca*Dca) + Sca*(1 - Da) + Dca*(1 - Sa)
+ // = Sca + Dca - Sca*Dca
+ const uint32_t col0 = ((uint32_t)src_p[0]*opac)
+ + (((uint32_t)dst_p[0]) << 15);
+ const uint32_t col1 = ((uint32_t)src_p[1]*opac)
+ + (((uint32_t)dst_p[1]) << 15);
+ const uint32_t col2 = ((uint32_t)src_p[2]*opac)
+ + (((uint32_t)dst_p[2]) << 15);
+ const uint32_t src_col0 = ((uint32_t)src_p[0] * opac) >> 15;
+ const uint32_t src_col1 = ((uint32_t)src_p[1] * opac) >> 15;
+ const uint32_t src_col2 = ((uint32_t)src_p[2] * opac) >> 15;
+ dst_p[0] = (col0 - ((uint32_t)src_col0*dst_p[0])) >> 15;
+ dst_p[1] = (col1 - ((uint32_t)src_col1*dst_p[1])) >> 15;
+ dst_p[2] = (col2 - ((uint32_t)src_col2*dst_p[2])) >> 15;
+#ifdef COMPOSITE_MODE_RGBA
+ // Da' = Sa + Da - Sa*Da
+ const uint32_t src_alpha = ((uint32_t)src_p[3] * opac) >> 15;
+ dst_p[3] = src_alpha + (uint32_t)dst_p[3]
+ - ((src_alpha * (uint32_t)dst_p[3]) >> 15);
+#endif
+}
+
+
+inline void
+#ifdef COMPOSITE_MODE_RGBA
+rgba_composite_color_dodge_rgba
+#else
+rgba_composite_color_dodge_rgbu
+#endif
+ (const uint16_t src_p[],
+ uint16_t dst_p[],
+ const uint16_t opac)
+{
+ const uint32_t src_alpha = ((uint32_t)src_p[3]*opac)>>15;
+ const uint32_t one_minus_src_alpha = (1<<15) - src_alpha;
+#ifdef COMPOSITE_MODE_RGBA
+ const uint32_t dst_alpha = dst_p[3];
+ const uint32_t one_minus_dst_alpha = (1<<15) - dst_alpha;
+#endif
+
+ for (int c=0; c<3; c++) {
+ const uint32_t s = ((uint32_t)src_p[c]*opac)>>15;
+ const uint32_t d = dst_p[c];
+ const uint32_t src_alpha_minus_src = src_alpha - s;
+ if (src_alpha_minus_src == 0 && d == 0) {
+ // Sca == Sa and Dca == 0
+ // Dca' = Sca*(1 - Da) + Dca*(1 - Sa)
+ // = Sca*(1 - Da)
+#ifdef COMPOSITE_MODE_RGBA
+ dst_p[c] = CLAMP((s * one_minus_dst_alpha) >> 15, 0, (1<<15));
+#else
+ dst_p[c] = 0;
+#endif
+ }
+ else if (src_alpha_minus_src == 0) {
+ // otherwise if Sca == Sa
+ // Dca' = Sa*Da + Sca*(1 - Da) + Dca*(1 - Sa)
+ // = Sca*Da + Sca*(1 - Da) + Dca*(1 - Sa)
+ // = Sca*(Da + 1 - Da) + Dca*(1 - Sa)
+ // = Sca + Dca*(1 - Sa)
+ dst_p[c] = CLAMP( s + ((d * one_minus_src_alpha)>>15),
+ 0, (1<<15) );
+ }
+ else {
+ // Sca < Sa
+ // Dca' = Sa*Da * min(1, Dca/Da * Sa/(Sa - Sca))
+ // + Sca*(1 - Da) + Dca*(1 - Sa)
+ const uint32_t dst_times_src_alpha_B30 = d*src_alpha;
+ // when 1 < Dca/Da * Sa/(Sa - Sca)
+ // 1 < (Dca*Sa) / (Da*(Sa - Sca)
+ // (Da*(Sa - Sca) < (Dca*Sa) because Sca - Sa is -ve and nonzero
+#ifdef COMPOSITE_MODE_RGBA
+ if (dst_times_src_alpha_B30 > (dst_alpha * src_alpha_minus_src))
+#else
+ if (dst_times_src_alpha_B30 > (src_alpha_minus_src << 15))
+#endif
+ {
+ // min(...)==1
+ // Dca' = Sa * Da * min(...) + Sca*(1 - Da) + Dca*(1 - Sa)
+ // Dca' = Sa * Da + Sca*(1 - Da) + Dca*(1 - Sa)
+ dst_p[c] = CLAMP(
+ ( (d * one_minus_src_alpha) // B30
+#ifdef COMPOSITE_MODE_RGBA
+ + (s * one_minus_dst_alpha) // B30
+ + (src_alpha * dst_alpha) // B30
+#else
+ // + (s * 0)
+ + (src_alpha << 15) // B30
+#endif
+ ) >> 15,
+ 0, 1<<15);
+ }
+ else {
+ // min(...) == Dca/Da * Sa/(Sa - Sca)
+ // Dca' = Sa * Da * min(...) + Sca*(1 - Da) + Dca*(1 - Sa)
+ // Dca' = Sa * Da * Dca/Da * Sa/(Sa - Sca)
+ // + Sca*(1 - Da) + Dca*(1 - Sa)
+ // Dca' = Sa * Dca * Sa/(Sa - Sca)
+ // + Sca*(1 - Da) + Dca*(1 - Sa)
+ dst_p[c] = CLAMP(
+ ( src_alpha * (dst_times_src_alpha_B30>>15)
+ / src_alpha_minus_src )
+#ifdef COMPOSITE_MODE_RGBA
+ + ((s * one_minus_dst_alpha) >> 15)
+#endif
+ + ((d * one_minus_src_alpha) >> 15),
+ 0, 1<<15);
+ }
+ }
+#ifdef HEAVY_DEBUG
+ assert(dst_p[c] <= (1<<15));
+ assert(src_p[c] <= (1<<15));
+#endif
+ }
+
+#ifdef COMPOSITE_MODE_RGBA
+ // Da' = Sa + Da - Sa*Da
+ dst_p[3] = CLAMP(src_alpha + dst_alpha - ((src_alpha*dst_alpha)>>15),
+ 0, (1<<15));
+#ifdef HEAVY_DEBUG
+ assert(src_p[0] <= src_p[3]);
+ assert(dst_p[0] <= dst_p[3]);
+ assert(src_p[1] <= src_p[3]);
+ assert(dst_p[1] <= dst_p[3]);
+ assert(src_p[2] <= src_p[3]);
+ assert(dst_p[2] <= dst_p[3]);
+#endif //HEAVY_DEBUG
+#endif //COMPOSITE_MODE_RGBA
+
+#ifdef HEAVY_DEBUG
+ assert(dst_p[3] <= (1<<15));
+ assert(src_p[3] <= (1<<15));
+#endif
+}
+
+
+
+inline void
+#ifdef COMPOSITE_MODE_RGBA
+rgba_composite_color_burn_rgba
+#else
+rgba_composite_color_burn_rgbu
+#endif
+ (const uint16_t src_p[],
+ uint16_t dst_p[],
+ const uint16_t opac)
+{
+ const uint32_t src_alpha30 = (uint32_t)src_p[3]*opac;
+ const uint32_t src_alpha = src_alpha30>>15;
+ const uint32_t one_minus_src_alpha = (1<<15) - src_alpha;
+#ifdef COMPOSITE_MODE_RGBA
+ const uint32_t dst_alpha = dst_p[3];
+ const uint32_t one_minus_dst_alpha = (1<<15) - dst_alpha;
+#else
+ const uint32_t dst_alpha = 1<<15;
+#endif
+ for (int c=0; c<3; c++) {
+ const uint32_t s30 = (uint32_t)src_p[c] * opac;
+ const uint32_t s = s30 >> 15;
+ const uint32_t d = dst_p[c];
+ if (s == 0) {
+ if (d != dst_alpha) {
+ //if Sca == 0 and Dca == Da
+ // Dca' = Sa*Da + Sca*(1 - Da) + Dca*(1 - Sa)
+ // = Sa*Dca + Dca*(1 - Sa)
+ // = Sa*Dca + Dca - Sa*Dca
+ // = Dca
+
+ //otherwise if Sca == 0
+ // Dca' = Sca*(1 - Da) + Dca*(1 - Sa)
+ // = Dca*(1 - Sa)
+ dst_p[c] = CLAMP(((d * one_minus_src_alpha) >> 15),
+ 0, (1<<15));
+ }
+ }
+ else {
+#ifdef HEAVY_DEBUG
+ assert(s <= (1<<15));
+ assert(s > 0);
+#endif
+ //otherwise if Sca > 0
+ // let i = Sca*(1 - Da) + Dca*(1 - Sa)
+ // let m = (1 - Dca/Da) * Sa/Sca
+ //
+ // Dca' = Sa*Da - Sa*Da * min(1, (1 - Dca/Da) * Sa/Sca) + i
+ // = Sa*Da * (1 - min(1, (1 - Dca/Da) * Sa/Sca)) + i
+
+#ifdef COMPOSITE_MODE_RGBA
+ uint32_t res = (s*one_minus_dst_alpha + d*one_minus_src_alpha)>>15;
+ if (dst_alpha > 0) {
+ const uint32_t m = ( ((1<<15) - ((d << 15) / dst_alpha))
+ * src_alpha) / s;
+ if (m < (1<<15)) {
+ res += ( ((src_alpha * dst_alpha) >> 15)
+ * ((1<<15) - m) ) >> 15;
+ }
+ }
+#else
+ uint32_t res = (d*one_minus_src_alpha)>>15;
+ const uint32_t m = (((1<<15) - d)
+ * src_alpha) / s;
+ if (m < (1<<15)) {
+ res += ( src_alpha
+ * ((1<<15) - m) ) >> 15;
+ }
+#endif
+ dst_p[c] = CLAMP(res, 0, (1<<15));
+ }
+#ifdef HEAVY_DEBUG
+ assert(dst_p[c] <= (1<<15));
+ assert(src_p[c] <= (1<<15));
+#endif
+ }
+
+#ifdef COMPOSITE_MODE_RGBA
+ // Da' = Sa + Da - Sa*Da
+ dst_p[3] = CLAMP(src_alpha + dst_alpha - ((src_alpha*dst_alpha)>>15),
+ 0, (1<<15));
+#ifdef HEAVY_DEBUG
+ assert(src_p[0] <= src_p[3]);
+ assert(dst_p[0] <= dst_p[3]);
+ assert(src_p[1] <= src_p[3]);
+ assert(dst_p[1] <= dst_p[3]);
+ assert(src_p[2] <= src_p[3]);
+ assert(dst_p[2] <= dst_p[3]);
+#endif //HEAVY_DEBUG
+#endif //COMPOSITE_MODE_RGBA
+
+#ifdef HEAVY_DEBUG
+ assert(dst_p[3] <= (1<<15));
+ assert(src_p[3] <= (1<<15));
+#endif
+}
+
+