[gimp/pippin/linear-is-the-new-black: 9/9] app: add abstraction for separate blend and composite modes, like LCH mods already do
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/pippin/linear-is-the-new-black: 9/9] app: add abstraction for separate blend and composite modes, like LCH mods already do
- Date: Sun, 15 Jan 2017 21:21:29 +0000 (UTC)
commit 208b3f0082f2e9ca9a6c5713839945093ca3cfe4
Author: Øyvind Kolås <pippin gimp org>
Date: Sun Jan 15 21:11:00 2017 +0100
app: add abstraction for separate blend and composite modes, like LCH mods already do
app/operations/layer-modes/gimpoperationaddition.c | 1 -
.../layer-modes/gimpoperationpointlayermode.h | 410 ++++++++++++++++++++
app/operations/layer-modes/gimpoperationscreen.c | 50 +--
3 files changed, 418 insertions(+), 43 deletions(-)
---
diff --git a/app/operations/layer-modes/gimpoperationaddition.c
b/app/operations/layer-modes/gimpoperationaddition.c
index df412f9..4b18832 100644
--- a/app/operations/layer-modes/gimpoperationaddition.c
+++ b/app/operations/layer-modes/gimpoperationaddition.c
@@ -76,7 +76,6 @@ gimp_operation_addition_process (GeglOperation *operation,
gint level)
{
gfloat opacity = GIMP_OPERATION_POINT_LAYER_MODE (operation)->opacity;
-
return gimp_operation_addition_process_pixels (in_buf, aux_buf, aux2_buf, out_buf, opacity, samples, roi,
level);
}
diff --git a/app/operations/layer-modes/gimpoperationpointlayermode.h
b/app/operations/layer-modes/gimpoperationpointlayermode.h
index af0a6e0..7ab229f 100644
--- a/app/operations/layer-modes/gimpoperationpointlayermode.h
+++ b/app/operations/layer-modes/gimpoperationpointlayermode.h
@@ -88,6 +88,416 @@ gimp_operation_layer_composite (const gfloat *in,
}
}
+typedef enum {
+ GIMP_LAYER_BLEND_RGB_LINEAR,
+ GIMP_LAYER_BLEND_RGB_PERCEPTUAL,
+ GIMP_LAYER_BLEND_LAB
+} GimpBlendTRC;
+typedef enum {
+ GIMP_LAYER_COMPOSITE_SRC_ATOP,
+ GIMP_LAYER_COMPOSITE_SRC_OVER,
+ GIMP_LAYER_COMPOSITE_SRC_IN,
+ GIMP_LAYER_COMPOSITE_DST_OVER
+} GimpLayerComposite;
+
+static inline void
+gimp_composite_blend (gfloat *in,
+ gfloat *layer,
+ gfloat *mask,
+ gfloat *out,
+ gfloat opacity,
+ glong samples,
+ GimpBlendTRC blend_trc,
+ GimpLayerComposite composite_mode,
+ void (*blendfun) (const float *dst,
+ const float *src,
+ float *out,
+ int samples))
+{
+ gfloat *blend_in = in;
+ gfloat *blend_layer = layer;
+
+ if (blend_trc == GIMP_LAYER_BLEND_RGB_LINEAR || blendfun == NULL)
+ {
+ if (blendfun)
+ blendfun (blend_in, blend_layer, out, samples);
+ else
+ memcpy (out, blend_layer, sizeof (gfloat) * 4 * samples);
+ }
+ else if (blend_trc == GIMP_LAYER_BLEND_RGB_PERCEPTUAL)
+ {
+ static const Babl *fish_to_perceptual = NULL;
+ static const Babl *fish_to_linear = NULL;
+ if (!fish_to_perceptual)
+ fish_to_perceptual = babl_fish("RGBA float", "R'G'B'A float");
+ if (!fish_to_linear)
+ fish_to_linear = babl_fish("R'G'B'A float", "RGBA float");
+
+ blend_in = alloca (sizeof (gfloat) * 4 * samples);
+ babl_process (fish_to_perceptual, in, blend_in, samples);
+ blend_layer = alloca (sizeof (gfloat) * 4 * samples);
+ babl_process (fish_to_perceptual, layer, blend_layer, samples);
+
+ blendfun (blend_in, blend_layer, out, samples);
+
+ babl_process (fish_to_linear, out, out, samples);
+ }
+ else if (blend_trc == GIMP_LAYER_BLEND_LAB)
+ {
+ static const Babl *fish_to_lab = NULL;
+ static const Babl *fish_to_rgb = NULL;
+ if (!fish_to_lab)
+ fish_to_lab = babl_fish("RGBA float", "CIE Lab alpha float");
+ if (!fish_to_rgb)
+ fish_to_rgb = babl_fish("CIE Lab alpha float", "RGBA float");
+
+ blend_in = alloca (sizeof (gfloat) * 4 * samples);
+ babl_process (fish_to_lab, in, blend_in, samples);
+ blend_layer = alloca (sizeof (gfloat) * 4 * samples);
+ babl_process (fish_to_lab, layer, blend_layer, samples);
+
+ blendfun (blend_in, blend_layer, out, samples);
+
+ babl_process (fish_to_rgb, out, out, samples);
+ }
+
+ switch (composite_mode)
+ {
+ case GIMP_LAYER_COMPOSITE_SRC_ATOP:
+ default:
+ while (samples--)
+ {
+ gfloat comp_alpha = out[ALPHA] * opacity;
+ if (mask)
+ comp_alpha *= *mask;
+
+ if (comp_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else
+ {
+ gint b;
+ for (b = RED; b < ALPHA; b++)
+ out[b] = out[b] * comp_alpha + in[b] * (1.0 - comp_alpha);
+ }
+
+ out[ALPHA] = in[ALPHA];
+
+ in += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+ break;
+ case GIMP_LAYER_COMPOSITE_SRC_OVER:
+ while (samples--)
+ {
+ gfloat comp_alpha = out[ALPHA] * opacity;
+ if (mask)
+ comp_alpha *= *mask;
+
+ if (comp_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else
+ {
+ gint b;
+ for (b = RED; b < ALPHA; b++)
+ out[b] = out[b] * comp_alpha + in[b] * (1.0 - comp_alpha);
+ }
+
+ out[ALPHA] = comp_alpha + in[ALPHA] * (1.0 - comp_alpha);
+
+ in += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+ break;
+ case GIMP_LAYER_COMPOSITE_DST_OVER: // XXX: strong need to verify visual results of this mode
+ while (samples--)
+ {
+ gfloat comp_alpha = out[ALPHA] * opacity;
+ if (mask)
+ comp_alpha *= *mask;
+
+ if (comp_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else
+ {
+ gint b;
+ for (b = RED; b < ALPHA; b++)
+ out[b] = out[b] * (1.0-comp_alpha) + in[b] * (comp_alpha);
+ }
+
+ out[ALPHA] = (1.0-comp_alpha) + in[ALPHA] * (comp_alpha);
+
+ in += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+ break;
+ case GIMP_LAYER_COMPOSITE_SRC_IN:
+ while (samples--)
+ {
+ gfloat comp_alpha = out[ALPHA] * opacity;
+ if (mask)
+ comp_alpha *= *mask;
+
+ if (comp_alpha == 0.0f)
+ {
+ out[RED] = in[RED];
+ out[GREEN] = in[GREEN];
+ out[BLUE] = in[BLUE];
+ }
+ else
+ {
+ gint b;
+ for (b = RED; b < ALPHA; b++)
+ out[b] = out[b] * comp_alpha + in[b] * (1.0 - comp_alpha);
+ }
+ out[ALPHA] = comp_alpha + in[ALPHA];
+ in += 4;
+ out += 4;
+
+ if (mask)
+ mask++;
+ }
+ break;
+ }
+}
+
+
+static inline void
+blendfun_screen (const float *dest,
+ const float *src,
+ float *out,
+ int samples)
+{
+ while (--samples)
+ {
+ if (src[ALPHA] != 0.0f)
+ {
+ int c;
+ for (c = 0; c < 3; c++)
+ out[c] = 1.0f - (1.0f - dest[c]) * (1.0f - src[c]);
+ }
+ out[ALPHA] = dest[ALPHA];
+ out += 4;
+ src += 4;
+ dest += 4;
+ }
+}
+
+static inline void
+blendfun_addition (const float *dest,
+ const float *src,
+ float *out,
+ int samples)
+{
+ while (--samples)
+ {
+ if (src[ALPHA] != 0.0f)
+ {
+ int c;
+ for (c = 0; c < 3; c++)
+ out[c] = dest[c] + src[c];
+ }
+ out[ALPHA] = dest[ALPHA];
+ out += 4;
+ src += 4;
+ dest += 4;
+ }
+}
+
+static inline void
+blendfun_subtract (const float *dest,
+ const float *src,
+ float *out,
+ int samples)
+{
+ while (--samples)
+ {
+ if (src[ALPHA] != 0.0f)
+ {
+ int c;
+ for (c = 0; c < 3; c++)
+ out[c] = dest[c] - src[c];
+ }
+ out[ALPHA] = dest[ALPHA];
+ out += 4;
+ src += 4;
+ dest += 4;
+ }
+}
+
+static inline void
+blendfun_burn (const float *dest,
+ const float *src,
+ float *out,
+ int samples)
+{
+ while (--samples)
+ {
+ if (src[ALPHA] != 0.0f)
+ {
+ int c;
+ for (c = 0; c < 3; c++)
+ {
+ gfloat comp = 1.0 - (1.0 - dest[c]) / src[c];
+ /* The CLAMP macro is deliberately inlined and written to map comp ==
+ * NAN (0 / 0) -> 1 */
+ out[c] = comp < 0 ? 0.0 : comp < 1.0 ? comp : 1.0;
+ }
+ }
+ out[ALPHA] = dest[ALPHA];
+ out += 4;
+ src += 4;
+ dest += 4;
+ }
+}
+
+static inline void
+blendfun_darken_only (const float *dest,
+ const float *src,
+ float *out,
+ int samples)
+{
+ while (--samples)
+ {
+ if (src[ALPHA] != 0.0f)
+ {
+ int c;
+ for (c = 0; c < 3; c++)
+ {
+ out[c] = MIN(dest[c], src[c]);
+ }
+ }
+ out[ALPHA] = dest[ALPHA];
+ out += 4;
+ src += 4;
+ dest += 4;
+ }
+}
+
+static inline void
+blendfun_lighten_only (const float *dest,
+ const float *src,
+ float *out,
+ int samples)
+{
+ while (--samples)
+ {
+ if (src[ALPHA] != 0.0f)
+ {
+ int c;
+ for (c = 0; c < 3; c++)
+ {
+ out[c] = MAX(dest[c], src[c]);
+ }
+ }
+ out[ALPHA] = dest[ALPHA];
+ out += 4;
+ src += 4;
+ dest += 4;
+ }
+}
+
+static inline void
+blendfun_difference (const float *dest,
+ const float *src,
+ float *out,
+ int samples)
+{
+ while (--samples)
+ {
+ if (src[ALPHA] != 0.0f)
+ {
+ int c;
+ for (c = 0; c < 3; c++)
+ {
+ out[c] = dest[c] - src[c];
+ if (out[c] < 0)
+ out[c] = -out[c];
+ }
+ }
+ out[ALPHA] = dest[ALPHA];
+ out += 4;
+ src += 4;
+ dest += 4;
+ }
+}
+
+
+static inline void
+blendfun_divide (const float *dest,
+ const float *src,
+ float *out,
+ int samples)
+{
+ while (--samples)
+ {
+ if (src[ALPHA] != 0.0f)
+ {
+ int c;
+ for (c = 0; c < 3; c++)
+ {
+ gfloat comp = dest[c] / src[c];
+
+ /* make infitinities(or NaN) correspond to a really high number,
+ * to get more predictable math */
+ if (!(comp > -4294967296.0f && comp < 4294967296.0f))
+ comp = 4294967296.0f;
+
+ out[c] = comp;
+ }
+ }
+ out[ALPHA] = dest[ALPHA];
+ out += 4;
+ src += 4;
+ dest += 4;
+ }
+}
+
+static inline void
+blendfun_dodge (const float *dest,
+ const float *src,
+ float *out,
+ int samples)
+{
+ while (--samples)
+ {
+ if (src[ALPHA] != 0.0f)
+ {
+ int c;
+ for (c = 0; c < 3; c++)
+ {
+ gfloat comp = dest[c] / (1.0 - src[c]);
+ comp = MIN (comp, 1.0);
+
+ out[c] = comp;
+ }
+ }
+ out[ALPHA] = dest[ALPHA];
+ out += 4;
+ src += 4;
+ dest += 4;
+ }
+}
#endif /* __GIMP_OPERATION_POINT_LAYER_MODE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationscreen.c
b/app/operations/layer-modes/gimpoperationscreen.c
index d2622c9..ecad8d6 100644
--- a/app/operations/layer-modes/gimpoperationscreen.c
+++ b/app/operations/layer-modes/gimpoperationscreen.c
@@ -65,6 +65,7 @@ gimp_operation_screen_init (GimpOperationScreen *self)
{
}
+
static gboolean
gimp_operation_screen_process (GeglOperation *operation,
void *in_buf,
@@ -76,7 +77,6 @@ gimp_operation_screen_process (GeglOperation *operation,
gint level)
{
gfloat opacity = GIMP_OPERATION_POINT_LAYER_MODE (operation)->opacity;
-
return gimp_operation_screen_process_pixels (in_buf, aux_buf, aux2_buf, out_buf, opacity, samples, roi,
level);
}
@@ -90,46 +90,12 @@ gimp_operation_screen_process_pixels (gfloat *in,
const GeglRectangle *roi,
gint level)
{
- const gboolean has_mask = mask != NULL;
-
- while (samples--)
- {
- gfloat comp_alpha;
-
- comp_alpha = layer[ALPHA] * opacity;
- if (has_mask)
- comp_alpha *= *mask;
-
- if (comp_alpha != 0.0f)
- {
- gint b;
-
- for (b = RED; b < ALPHA; b++)
- {
- gfloat comp = 1.0 - (1.0 - in[b]) * (1.0 - layer[b]);
-
- out[b] = comp * comp_alpha + in[b] * (1.0 - comp_alpha);
- }
- }
- else
- {
- gint b;
-
- for (b = RED; b < ALPHA; b++)
- {
- out[b] = in[b];
- }
- }
-
- out[ALPHA] = in[ALPHA];
-
- in += 4;
- layer += 4;
- out += 4;
-
- if (has_mask)
- mask++;
- }
-
+ gimp_composite_blend (
+ in, layer, mask, out, opacity, samples,
+ GIMP_LAYER_BLEND_RGB_LINEAR,
+ GIMP_LAYER_COMPOSITE_SRC_ATOP,
+ blendfun_screen
+ );
return TRUE;
}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]