New upstream version 2.10.0~RC1

This commit is contained in:
Jeremy Bicha
2018-03-28 12:37:30 -04:00
8195 changed files with 1939281 additions and 1033470 deletions

View File

@ -0,0 +1,79 @@
## Process this file with automake to produce Makefile.in
AM_CPPFLAGS = \
-DG_LOG_DOMAIN=\"Gimp-Layer-Modes\" \
-I$(top_builddir) \
-I$(top_srcdir) \
-I$(top_builddir)/app \
-I$(top_srcdir)/app \
$(CAIRO_CFLAGS) \
$(GEGL_CFLAGS) \
$(GDK_PIXBUF_CFLAGS) \
-I$(includedir)
noinst_LIBRARIES = \
libapplayermodes-generic.a \
libapplayermodes-sse2.a \
libapplayermodes-sse4.a \
libapplayermodes.a
libapplayermodes_generic_a_sources = \
gimp-layer-modes.c \
gimp-layer-modes.h \
\
gimpoperationlayermode.c \
gimpoperationlayermode.h \
gimpoperationlayermode-blend.c \
gimpoperationlayermode-blend.h \
gimpoperationlayermode-composite.c \
gimpoperationlayermode-composite.h \
\
gimpoperationantierase.c \
gimpoperationantierase.h \
gimpoperationbehind.c \
gimpoperationbehind.h \
gimpoperationdissolve.c \
gimpoperationdissolve.h \
gimpoperationerase.c \
gimpoperationerase.h \
gimpoperationmerge.c \
gimpoperationmerge.h \
gimpoperationnormal.c \
gimpoperationnormal.h \
gimpoperationpassthrough.c \
gimpoperationpassthrough.h \
gimpoperationreplace.c \
gimpoperationreplace.h \
gimpoperationsplit.c \
gimpoperationsplit.h
libapplayermodes_sse2_a_sources = \
gimpoperationlayermode-composite-sse2.c \
\
gimpoperationnormal-sse2.c
libapplayermodes_sse4_a_sources = \
gimpoperationnormal-sse4.c
libapplayermodes_generic_a_SOURCES = $(libapplayermodes_generic_a_sources)
libapplayermodes_sse2_a_SOURCES = $(libapplayermodes_sse2_a_sources)
libapplayermodes_sse2_a_CFLAGS = $(SSE2_EXTRA_CFLAGS)
libapplayermodes_sse4_a_SOURCES = $(libapplayermodes_sse4_a_sources)
libapplayermodes_sse4_a_CFLAGS = $(SSE4_1_EXTRA_CFLAGS)
libapplayermodes_a_SOURCES =
libapplayermodes.a: libapplayermodes-generic.a \
libapplayermodes-sse2.a \
libapplayermodes-sse4.a
$(AR) $(ARFLAGS) libapplayermodes.a \
$(libapplayermodes_generic_a_OBJECTS) \
$(libapplayermodes_sse2_a_OBJECTS) \
$(libapplayermodes_sse4_a_OBJECTS)
$(RANLIB) libapplayermodes.a

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimp-layer-modes.h
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
* Øyvind Kolås <pippin@gimp.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_LAYER_MODES_H__
#define __GIMP_LAYER_MODES_H__
void gimp_layer_modes_init (void);
gboolean gimp_layer_mode_is_legacy (GimpLayerMode mode);
gboolean gimp_layer_mode_is_blend_space_mutable (GimpLayerMode mode);
gboolean gimp_layer_mode_is_composite_space_mutable (GimpLayerMode mode);
gboolean gimp_layer_mode_is_composite_mode_mutable (GimpLayerMode mode);
gboolean gimp_layer_mode_is_subtractive (GimpLayerMode mode);
GimpLayerColorSpace gimp_layer_mode_get_blend_space (GimpLayerMode mode);
GimpLayerColorSpace gimp_layer_mode_get_composite_space (GimpLayerMode mode);
GimpLayerCompositeMode gimp_layer_mode_get_composite_mode (GimpLayerMode mode);
GimpLayerCompositeMode gimp_layer_mode_get_paint_composite_mode (GimpLayerMode mode);
const gchar * gimp_layer_mode_get_operation (GimpLayerMode mode);
GimpLayerModeFunc gimp_layer_mode_get_function (GimpLayerMode mode);
GimpLayerModeBlendFunc gimp_layer_mode_get_blend_function (GimpLayerMode mode);
GimpLayerModeContext gimp_layer_mode_get_context (GimpLayerMode mode);
GimpLayerMode * gimp_layer_mode_get_context_array (GimpLayerMode mode,
GimpLayerModeContext context,
gint *n_modes);
GimpLayerModeGroup gimp_layer_mode_get_group (GimpLayerMode mode);
const GimpLayerMode * gimp_layer_mode_get_group_array (GimpLayerModeGroup group,
gint *n_modes);
gboolean gimp_layer_mode_get_for_group (GimpLayerMode old_mode,
GimpLayerModeGroup new_group,
GimpLayerMode *new_mode);
const Babl * gimp_layer_mode_get_format (GimpLayerMode mode,
GimpLayerColorSpace composite_space,
GimpLayerColorSpace blend_space,
const Babl *preferred_format);
GimpLayerCompositeRegion gimp_layer_mode_get_included_region (GimpLayerMode mode,
GimpLayerCompositeMode composite_mode);
#endif /* __GIMP_LAYER_MODES_H__ */

View File

@ -0,0 +1,188 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationantierase.c
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* 2012 Ville Sokk <ville.sokk@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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "../operations-types.h"
#include "gimpoperationantierase.h"
static gboolean gimp_operation_anti_erase_process (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
static GimpLayerCompositeRegion gimp_operation_anti_erase_get_affected_region (GimpOperationLayerMode *layer_mode);
G_DEFINE_TYPE (GimpOperationAntiErase, gimp_operation_anti_erase,
GIMP_TYPE_OPERATION_LAYER_MODE)
static void
gimp_operation_anti_erase_class_init (GimpOperationAntiEraseClass *klass)
{
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
gegl_operation_class_set_keys (operation_class,
"name", "gimp:anti-erase",
"description", "GIMP anti erase mode operation",
NULL);
layer_mode_class->process = gimp_operation_anti_erase_process;
layer_mode_class->get_affected_region = gimp_operation_anti_erase_get_affected_region;
}
static void
gimp_operation_anti_erase_init (GimpOperationAntiErase *self)
{
}
static gboolean
gimp_operation_anti_erase_process (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat *in = in_p;
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = layer_mode->opacity;
const gboolean has_mask = mask != NULL;
switch (layer_mode->real_composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
case GIMP_LAYER_COMPOSITE_AUTO:
while (samples--)
{
gfloat value = opacity;
gint b;
if (has_mask)
value *= *mask;
out[ALPHA] = in[ALPHA] + (1.0 - in[ALPHA]) * layer[ALPHA] * value;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
while (samples--)
{
gint b;
out[ALPHA] = in[ALPHA];
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
in += 4;
out += 4;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
while (samples--)
{
gfloat value = opacity;
gint b;
if (has_mask)
value *= *mask;
out[ALPHA] = layer[ALPHA] * value;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
while (samples--)
{
gfloat value = opacity;
gint b;
if (has_mask)
value *= *mask;
out[ALPHA] = in[ALPHA] * layer[ALPHA] * value;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
}
return TRUE;
}
static GimpLayerCompositeRegion
gimp_operation_anti_erase_get_affected_region (GimpOperationLayerMode *layer_mode)
{
return GIMP_LAYER_COMPOSITE_REGION_SOURCE;
}

View File

@ -0,0 +1,53 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationantierase.h
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_ANTI_ERASE_H__
#define __GIMP_OPERATION_ANTI_ERASE_H__
#include "gimpoperationlayermode.h"
#define GIMP_TYPE_OPERATION_ANTI_ERASE (gimp_operation_anti_erase_get_type ())
#define GIMP_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_ANTI_ERASE, GimpOperationAntiErase))
#define GIMP_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_ANTI_ERASE, GimpOperationAntiEraseClass))
#define GIMP_IS_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_ANTI_ERASE))
#define GIMP_IS_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_ANTI_ERASE))
#define GIMP_OPERATION_ANTI_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_ANTI_ERASE, GimpOperationAntiEraseClass))
typedef struct _GimpOperationAntiErase GimpOperationAntiErase;
typedef struct _GimpOperationAntiEraseClass GimpOperationAntiEraseClass;
struct _GimpOperationAntiErase
{
GimpOperationLayerMode parent_instance;
};
struct _GimpOperationAntiEraseClass
{
GimpOperationLayerModeClass parent_class;
};
GType gimp_operation_anti_erase_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_OPERATION_ANTI_ERASE_H__ */

View File

@ -0,0 +1,236 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationbehind.c
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* 2012 Ville Sokk <ville.sokk@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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "../operations-types.h"
#include "gimpoperationbehind.h"
static gboolean gimp_operation_behind_process (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
G_DEFINE_TYPE (GimpOperationBehind, gimp_operation_behind,
GIMP_TYPE_OPERATION_LAYER_MODE)
static void
gimp_operation_behind_class_init (GimpOperationBehindClass *klass)
{
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
gegl_operation_class_set_keys (operation_class,
"name", "gimp:behind",
"description", "GIMP behind mode operation",
NULL);
layer_mode_class->process = gimp_operation_behind_process;
}
static void
gimp_operation_behind_init (GimpOperationBehind *self)
{
}
static gboolean
gimp_operation_behind_process (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat *in = in_p;
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = layer_mode->opacity;
const gboolean has_mask = mask != NULL;
switch (layer_mode->real_composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
case GIMP_LAYER_COMPOSITE_AUTO:
while (samples--)
{
gfloat src1_alpha = in[ALPHA];
gfloat src2_alpha = layer[ALPHA] * opacity;
gfloat new_alpha;
gint b;
if (has_mask)
src2_alpha *= *mask;
new_alpha = src2_alpha + (1.0 - src2_alpha) * src1_alpha;
if (new_alpha)
{
gfloat ratio = in[ALPHA] / new_alpha;
gfloat compl_ratio = 1.0f - ratio;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b] * ratio + layer[b] * compl_ratio;
}
}
else
{
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
while (samples--)
{
gfloat src1_alpha = in[ALPHA];
gfloat new_alpha;
gint b;
new_alpha = src1_alpha;
if (new_alpha)
{
for (b = RED; b < ALPHA; b++)
out[b] = in[b];
}
else
{
for (b = RED; b < ALPHA; b++)
out[b] = layer[b];
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
while (samples--)
{
gfloat src1_alpha = in[ALPHA];
gfloat src2_alpha = layer[ALPHA] * opacity;
gfloat new_alpha;
gint b;
if (has_mask)
src2_alpha *= *mask;
new_alpha = src2_alpha;
if (new_alpha)
{
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b] + (in[b] - layer[b]) * src1_alpha;
}
}
else
{
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
while (samples--)
{
gfloat src1_alpha = in[ALPHA];
gfloat src2_alpha = layer[ALPHA] * opacity;
gfloat new_alpha;
gint b;
if (has_mask)
src2_alpha *= *mask;
new_alpha = src1_alpha * src2_alpha;
if (new_alpha)
{
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
else
{
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
}
return TRUE;
}

View File

@ -0,0 +1,53 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationbehind.h
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_BEHIND_H__
#define __GIMP_OPERATION_BEHIND_H__
#include "gimpoperationlayermode.h"
#define GIMP_TYPE_OPERATION_BEHIND (gimp_operation_behind_get_type ())
#define GIMP_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_BEHIND, GimpOperationBehind))
#define GIMP_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_BEHIND, GimpOperationBehindClass))
#define GIMP_IS_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_BEHIND))
#define GIMP_IS_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_BEHIND))
#define GIMP_OPERATION_BEHIND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_BEHIND, GimpOperationBehindClass))
typedef struct _GimpOperationBehind GimpOperationBehind;
typedef struct _GimpOperationBehindClass GimpOperationBehindClass;
struct _GimpOperationBehind
{
GimpOperationLayerMode parent_instance;
};
struct _GimpOperationBehindClass
{
GimpOperationLayerModeClass parent_class;
};
GType gimp_operation_behind_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_OPERATION_BEHIND_H__ */

View File

@ -0,0 +1,168 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationdissolve.c
* Copyright (C) 2012 Ville Sokk <ville.sokk@gmail.com>
* 2012 Øyvind Kolås <pippin@gimp.org>
* 2003 Helvetix Victorinox
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "../operations-types.h"
#include "gimpoperationdissolve.h"
#define RANDOM_TABLE_SIZE 4096
static gboolean gimp_operation_dissolve_process (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *result,
gint level);
static GimpLayerCompositeRegion gimp_operation_dissolve_get_affected_region (GimpOperationLayerMode *layer_mode);
G_DEFINE_TYPE (GimpOperationDissolve, gimp_operation_dissolve,
GIMP_TYPE_OPERATION_LAYER_MODE)
static gint32 random_table[RANDOM_TABLE_SIZE];
static void
gimp_operation_dissolve_class_init (GimpOperationDissolveClass *klass)
{
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
GRand *gr;
gint i;
gegl_operation_class_set_keys (operation_class,
"name", "gimp:dissolve",
"description", "GIMP dissolve mode operation",
"categories", "compositors",
NULL);
layer_mode_class->process = gimp_operation_dissolve_process;
layer_mode_class->get_affected_region = gimp_operation_dissolve_get_affected_region;
/* generate a table of random seeds */
gr = g_rand_new_with_seed (314159265);
for (i = 0; i < RANDOM_TABLE_SIZE; i++)
random_table[i] = g_rand_int (gr);
g_rand_free (gr);
}
static void
gimp_operation_dissolve_init (GimpOperationDissolve *self)
{
}
static gboolean
gimp_operation_dissolve_process (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *result,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat *in = in_p;
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = layer_mode->opacity;
const gboolean has_mask = mask != NULL;
gint x, y;
for (y = result->y; y < result->y + result->height; y++)
{
GRand *gr = g_rand_new_with_seed (random_table[y % RANDOM_TABLE_SIZE]);
/* fast forward through the rows pseudo random sequence */
for (x = 0; x < result->x; x++)
g_rand_int (gr);
for (x = result->x; x < result->x + result->width; x++)
{
gfloat value = layer[ALPHA] * opacity * 255;
if (has_mask)
value *= *mask;
if (g_rand_int_range (gr, 0, 255) >= value)
{
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
if (layer_mode->real_composite_mode == GIMP_LAYER_COMPOSITE_UNION ||
layer_mode->real_composite_mode == GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP)
{
out[3] = in[3];
}
else
{
out[3] = 0.0f;
}
}
else
{
out[0] = layer[0];
out[1] = layer[1];
out[2] = layer[2];
if (layer_mode->real_composite_mode == GIMP_LAYER_COMPOSITE_UNION ||
layer_mode->real_composite_mode == GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER)
{
out[3] = 1.0f;
}
else
{
out[3] = in[3];
}
}
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
g_rand_free (gr);
}
return TRUE;
}
static GimpLayerCompositeRegion
gimp_operation_dissolve_get_affected_region (GimpOperationLayerMode *layer_mode)
{
return GIMP_LAYER_COMPOSITE_REGION_SOURCE;
}

View File

@ -0,0 +1,53 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationdissolve.h
* Copyright (C) 2012 Ville Sokk <ville.sokk@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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_DISSOLVE_H__
#define __GIMP_OPERATION_DISSOLVE_H__
#include "gimpoperationlayermode.h"
#define GIMP_TYPE_OPERATION_DISSOLVE (gimp_operation_dissolve_get_type ())
#define GIMP_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_DISSOLVE, GimpOperationDissolve))
#define GIMP_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_DISSOLVE, GimpOperationDissolveClass))
#define GIMP_IS_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_DISSOLVE))
#define GIMP_IS_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_DISSOLVE))
#define GIMP_OPERATION_DISSOLVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_DISSOLVE, GimpOperationDissolveClass))
typedef struct _GimpOperationDissolve GimpOperationDissolve;
typedef struct _GimpOperationDissolveClass GimpOperationDissolveClass;
struct _GimpOperationDissolveClass
{
GimpOperationLayerModeClass parent_class;
};
struct _GimpOperationDissolve
{
GimpOperationLayerMode parent_instance;
};
GType gimp_operation_dissolve_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_OPERATION_DISSOLVE_H__ */

View File

@ -0,0 +1,214 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationerase.c
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* 2012 Ville Sokk <ville.sokk@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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "../operations-types.h"
#include "gimpoperationerase.h"
static gboolean gimp_operation_erase_process (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
G_DEFINE_TYPE (GimpOperationErase, gimp_operation_erase,
GIMP_TYPE_OPERATION_LAYER_MODE)
static void
gimp_operation_erase_class_init (GimpOperationEraseClass *klass)
{
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
gegl_operation_class_set_keys (operation_class,
"name", "gimp:erase",
"description", "GIMP erase mode operation",
NULL);
layer_mode_class->process = gimp_operation_erase_process;
}
static void
gimp_operation_erase_init (GimpOperationErase *self)
{
}
static gboolean
gimp_operation_erase_process (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat *in = in_p;
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = layer_mode->opacity;
const gboolean has_mask = mask != NULL;
switch (layer_mode->real_composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
while (samples--)
{
gfloat layer_alpha;
gfloat new_alpha;
gint b;
layer_alpha = layer[ALPHA] * opacity;
if (has_mask)
layer_alpha *= (*mask);
new_alpha = in[ALPHA] + layer_alpha - 2.0f * in[ALPHA] * layer_alpha;
if (new_alpha != 0.0f)
{
gfloat ratio;
ratio = (1.0f - in[ALPHA]) * layer_alpha / new_alpha;
for (b = RED; b < ALPHA; b++)
{
out[b] = ratio * layer[b] + (1.0f - ratio) * in[b];
}
}
else
{
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask ++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
case GIMP_LAYER_COMPOSITE_AUTO:
while (samples--)
{
gfloat layer_alpha;
gfloat new_alpha;
gint b;
layer_alpha = layer[ALPHA] * opacity;
if (has_mask)
layer_alpha *= (*mask);
new_alpha = (1.0f - layer_alpha) * in[ALPHA];
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask ++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
while (samples--)
{
gfloat layer_alpha;
gfloat new_alpha;
const gfloat *src;
gint b;
layer_alpha = layer[ALPHA] * opacity;
if (has_mask)
layer_alpha *= (*mask);
new_alpha = (1.0f - in[ALPHA]) * layer_alpha;
src = layer;
if (new_alpha == 0.0f)
src = in;
for (b = RED; b < ALPHA; b++)
{
out[b] = src[b];
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask ++;
}
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
while (samples--)
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
out[ALPHA] = 0.0f;
in += 4;
out += 4;
}
break;
}
return TRUE;
}

View File

@ -0,0 +1,53 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationerase.h
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_ERASE_H__
#define __GIMP_OPERATION_ERASE_H__
#include "gimpoperationlayermode.h"
#define GIMP_TYPE_OPERATION_ERASE (gimp_operation_erase_get_type ())
#define GIMP_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_ERASE, GimpOperationErase))
#define GIMP_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_ERASE, GimpOperationEraseClass))
#define GIMP_IS_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_ERASE))
#define GIMP_IS_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_ERASE))
#define GIMP_OPERATION_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_ERASE, GimpOperationEraseClass))
typedef struct _GimpOperationErase GimpOperationErase;
typedef struct _GimpOperationEraseClass GimpOperationEraseClass;
struct _GimpOperationErase
{
GimpOperationLayerMode parent_instance;
};
struct _GimpOperationEraseClass
{
GimpOperationLayerModeClass parent_class;
};
GType gimp_operation_erase_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_OPERATION_ERASE_MODE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationlayermode-blend.h
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
* 2017 Øyvind Kolås <pippin@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; withcomp even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_LAYER_MODE_BLEND_H__
#define __GIMP_OPERATION_LAYER_MODE_BLEND_H__
/* nonsubtractive blend functions */
void gimp_operation_layer_mode_blend_addition (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_burn (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_darken_only (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_difference (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_divide (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_dodge (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_exclusion (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_grain_extract (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_grain_merge (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_hard_mix (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_hardlight (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_hsl_color (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_hsv_hue (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_hsv_saturation (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_hsv_value (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_lch_chroma (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_lch_color (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_lch_hue (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_lch_lightness (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_lighten_only (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_linear_burn (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_linear_light (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_luma_darken_only (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_luma_lighten_only (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_luminance (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_multiply (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_overlay (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_pin_light (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_screen (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_softlight (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_subtract (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
void gimp_operation_layer_mode_blend_vivid_light (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
/* subtractive blend functions */
void gimp_operation_layer_mode_blend_color_erase (const gfloat *in,
const gfloat *layer,
gfloat *comp,
gint samples);
#endif /* __GIMP_OPERATION_LAYER_MODE_BLEND_H__ */

View File

@ -0,0 +1,105 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationlayermode-composite-sse2.c
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
* 2017 Øyvind Kolås <pippin@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "../operations-types.h"
#include "gimpoperationlayermode-composite.h"
#if COMPILE_SSE2_INTRINISICS
/* SSE2 */
#include <emmintrin.h>
/* non-subtractive compositing functions. these functions expect comp[ALPHA]
* to be the same as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are zero,
* the value of comp[RED..BLUE] is unconstrained (in particular, it may be
* NaN).
*/
void
gimp_operation_layer_mode_composite_clip_to_backdrop_sse2 (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples)
{
if ((((uintptr_t)in) | /* alignment check */
((uintptr_t)comp) |
((uintptr_t)out) ) & 0x0F)
{
gimp_operation_layer_mode_composite_clip_to_backdrop (in, layer, comp,
mask, opacity, out,
samples);
}
else
{
const __v4sf *v_in = (const __v4sf*) in;
const __v4sf *v_comp = (const __v4sf*) comp;
__v4sf *v_out = (__v4sf*) out;
const __v4sf v_one = _mm_set1_ps (1.0f);
const __v4sf v_opacity = _mm_set1_ps (opacity);
while (samples--)
{
__v4sf alpha, rgba_in, rgba_comp;
rgba_in = *v_in ++;
rgba_comp = *v_comp++;
alpha = (__v4sf)_mm_shuffle_epi32((__m128i)rgba_comp,_MM_SHUFFLE(3,3,3,3)) * v_opacity;
if (mask)
{
alpha = alpha * _mm_set1_ps (*mask++);
}
if (rgba_in[ALPHA] != 0.0f && _mm_ucomineq_ss (alpha, _mm_setzero_ps ()))
{
__v4sf out_pixel, out_pixel_rbaa, out_alpha;
out_alpha = (__v4sf)_mm_shuffle_epi32((__m128i)rgba_in,_MM_SHUFFLE(3,3,3,3));
out_pixel = rgba_comp * alpha + rgba_in * (v_one - alpha);
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0));
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
*v_out++ = out_pixel;
}
else
{
*v_out ++ = rgba_in;
}
}
}
}
#endif /* COMPILE_SSE2_INTRINISICS */

View File

@ -0,0 +1,434 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationlayermode-composite.c
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
* 2017 Øyvind Kolås <pippin@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "../operations-types.h"
#include "gimpoperationlayermode-composite.h"
/* non-subtractive compositing functions. these functions expect comp[ALPHA]
* to be the same as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are zero,
* the value of comp[RED..BLUE] is unconstrained (in particular, it may be
* NaN).
*/
void
gimp_operation_layer_mode_composite_union (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples)
{
while (samples--)
{
gfloat new_alpha;
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
if (mask)
layer_alpha *= *mask;
new_alpha = layer_alpha + (1.0f - layer_alpha) * in_alpha;
if (layer_alpha == 0.0f || new_alpha == 0.0f)
{
out[RED] = in[RED];
out[GREEN] = in[GREEN];
out[BLUE] = in[BLUE];
}
else if (in_alpha == 0.0f)
{
out[RED] = layer[RED];
out[GREEN] = layer[GREEN];
out[BLUE] = layer[BLUE];
}
else
{
gfloat ratio = layer_alpha / new_alpha;
gint b;
for (b = RED; b < ALPHA; b++)
out[b] = ratio * (in_alpha * (comp[b] - layer[b]) + layer[b] - in[b]) + in[b];
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
comp += 4;
out += 4;
if (mask)
mask++;
}
}
void
gimp_operation_layer_mode_composite_clip_to_backdrop (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples)
{
while (samples--)
{
gfloat layer_alpha = comp[ALPHA] * opacity;
if (mask)
layer_alpha *= *mask;
if (in[ALPHA] == 0.0f || layer_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] = comp[b] * layer_alpha + in[b] * (1.0f - layer_alpha);
}
out[ALPHA] = in[ALPHA];
in += 4;
comp += 4;
out += 4;
if (mask)
mask++;
}
}
void
gimp_operation_layer_mode_composite_clip_to_layer (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples)
{
while (samples--)
{
gfloat layer_alpha = layer[ALPHA] * opacity;
if (mask)
layer_alpha *= *mask;
if (layer_alpha == 0.0f)
{
out[RED] = in[RED];
out[GREEN] = in[GREEN];
out[BLUE] = in[BLUE];
}
else if (in[ALPHA] == 0.0f)
{
out[RED] = layer[RED];
out[GREEN] = layer[GREEN];
out[BLUE] = layer[BLUE];
}
else
{
gint b;
for (b = RED; b < ALPHA; b++)
out[b] = comp[b] * in[ALPHA] + layer[b] * (1.0f - in[ALPHA]);
}
out[ALPHA] = layer_alpha;
in += 4;
layer += 4;
comp += 4;
out += 4;
if (mask)
mask++;
}
}
void
gimp_operation_layer_mode_composite_intersection (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples)
{
while (samples--)
{
gfloat new_alpha = in[ALPHA] * comp[ALPHA] * opacity;
if (mask)
new_alpha *= *mask;
if (new_alpha == 0.0f)
{
out[RED] = in[RED];
out[GREEN] = in[GREEN];
out[BLUE] = in[BLUE];
}
else
{
out[RED] = comp[RED];
out[GREEN] = comp[GREEN];
out[BLUE] = comp[BLUE];
}
out[ALPHA] = new_alpha;
in += 4;
comp += 4;
out += 4;
if (mask)
mask++;
}
}
/* subtractive compositing functions. these functions expect comp[ALPHA] to
* specify the modified alpha of the overlapping content, as a fraction of the
* original overlapping content (i.e., an alpha of 1.0 specifies that no
* content is subtracted.) when in[ALPHA] or layer[ALPHA] are zero, the value
* of comp[RED..BLUE] is unconstrained (in particular, it may be NaN).
*/
void
gimp_operation_layer_mode_composite_union_sub (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples)
{
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gfloat comp_alpha = comp[ALPHA];
gfloat new_alpha;
if (mask)
layer_alpha *= *mask;
new_alpha = in_alpha + layer_alpha -
(2.0f - comp_alpha) * in_alpha * layer_alpha;
if (layer_alpha == 0.0f || new_alpha == 0.0f)
{
out[RED] = in[RED];
out[GREEN] = in[GREEN];
out[BLUE] = in[BLUE];
}
else if (in_alpha == 0.0f)
{
out[RED] = layer[RED];
out[GREEN] = layer[GREEN];
out[BLUE] = layer[BLUE];
}
else
{
gfloat ratio = in_alpha / new_alpha;
gfloat layer_coeff = 1.0f / in_alpha - 1.0f;
gint b;
for (b = RED; b < ALPHA; b++)
out[b] = ratio * (layer_alpha * (comp_alpha * comp[b] + layer_coeff * layer[b] - in[b]) + in[b]);
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
comp += 4;
out += 4;
if (mask)
mask++;
}
}
void
gimp_operation_layer_mode_composite_clip_to_backdrop_sub (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples)
{
while (samples--)
{
gfloat layer_alpha = layer[ALPHA] * opacity;
gfloat comp_alpha = comp[ALPHA];
gfloat new_alpha;
if (mask)
layer_alpha *= *mask;
comp_alpha *= layer_alpha;
new_alpha = 1.0f - layer_alpha + comp_alpha;
if (in[ALPHA] == 0.0f || comp_alpha == 0.0f)
{
out[RED] = in[RED];
out[GREEN] = in[GREEN];
out[BLUE] = in[BLUE];
}
else
{
gfloat ratio = comp_alpha / new_alpha;
gint b;
for (b = RED; b < ALPHA; b++)
out[b] = comp[b] * ratio + in[b] * (1.0f - ratio);
}
new_alpha *= in[ALPHA];
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
comp += 4;
out += 4;
if (mask)
mask++;
}
}
void
gimp_operation_layer_mode_composite_clip_to_layer_sub (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples)
{
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gfloat comp_alpha = comp[ALPHA];
gfloat new_alpha;
if (mask)
layer_alpha *= *mask;
comp_alpha *= in_alpha;
new_alpha = 1.0f - in_alpha + comp_alpha;
if (layer_alpha == 0.0f)
{
out[RED] = in[RED];
out[GREEN] = in[GREEN];
out[BLUE] = in[BLUE];
}
else if (in_alpha == 0.0f)
{
out[RED] = layer[RED];
out[GREEN] = layer[GREEN];
out[BLUE] = layer[BLUE];
}
else
{
gfloat ratio = comp_alpha / new_alpha;
gint b;
for (b = RED; b < ALPHA; b++)
out[b] = comp[b] * ratio + layer[b] * (1.0f - ratio);
}
new_alpha *= layer_alpha;
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
comp += 4;
out += 4;
if (mask)
mask++;
}
}
void
gimp_operation_layer_mode_composite_intersection_sub (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples)
{
while (samples--)
{
gfloat new_alpha = in[ALPHA] * layer[ALPHA] * comp[ALPHA] * opacity;
if (mask)
new_alpha *= *mask;
if (new_alpha == 0.0f)
{
out[RED] = in[RED];
out[GREEN] = in[GREEN];
out[BLUE] = in[BLUE];
}
else
{
out[RED] = comp[RED];
out[GREEN] = comp[GREEN];
out[BLUE] = comp[BLUE];
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
comp += 4;
out += 4;
if (mask)
mask++;
}
}

View File

@ -0,0 +1,98 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationlayermode-composite.h
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
* 2017 Øyvind Kolås <pippin@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__
#define __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__
void gimp_operation_layer_mode_composite_union (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples);
void gimp_operation_layer_mode_composite_clip_to_backdrop (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples);
void gimp_operation_layer_mode_composite_clip_to_layer (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples);
void gimp_operation_layer_mode_composite_intersection (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples);
void gimp_operation_layer_mode_composite_union_sub (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples);
void gimp_operation_layer_mode_composite_clip_to_backdrop_sub (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples);
void gimp_operation_layer_mode_composite_clip_to_layer_sub (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples);
void gimp_operation_layer_mode_composite_intersection_sub (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples);
#if COMPILE_SSE2_INTRINISICS
void gimp_operation_layer_mode_composite_clip_to_backdrop_sse2 (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
gfloat opacity,
gfloat *out,
gint samples);
#endif /* COMPILE_SSE2_INTRINISICS */
#endif /* __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__ */

View File

@ -0,0 +1,812 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationlayermode.c
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* Copyright (C) 2008 Martin Nordholts <martinn@svn.gnome.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "libgimpbase/gimpbase.h"
#include "../operations-types.h"
#include "gimp-layer-modes.h"
#include "gimpoperationlayermode.h"
#include "gimpoperationlayermode-composite.h"
/* the maximum number of samples to process in one go. used to limit
* the size of the buffers we allocate on the stack.
*/
#define GIMP_COMPOSITE_BLEND_MAX_SAMPLES ((1 << 19) /* 0.5 MiB */ / \
16 /* bytes per pixel */ / \
2 /* max number of buffers */)
/* number of consecutive unblended samples (whose source or destination alpha
* is zero) above which to split the blending process, in order to avoid
* performing too many unnecessary conversions.
*/
#define GIMP_COMPOSITE_BLEND_SPLIT_THRESHOLD 32
enum
{
PROP_0,
PROP_LAYER_MODE,
PROP_OPACITY,
PROP_BLEND_SPACE,
PROP_COMPOSITE_SPACE,
PROP_COMPOSITE_MODE
};
typedef void (* CompositeFunc) (const gfloat *in,
const gfloat *layer,
const gfloat *comp,
const gfloat *mask,
float opacity,
gfloat *out,
gint samples);
static void gimp_operation_layer_mode_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_operation_layer_mode_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_operation_layer_mode_prepare (GeglOperation *operation);
static gboolean gimp_operation_layer_mode_parent_process (GeglOperation *operation,
GeglOperationContext *context,
const gchar *output_prop,
const GeglRectangle *result,
gint level);
static gboolean gimp_operation_layer_mode_process (GeglOperation *operation,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
static gboolean gimp_operation_layer_mode_real_process (GeglOperation *operation,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
static gboolean process_last_node (GeglOperation *operation,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
G_DEFINE_TYPE (GimpOperationLayerMode, gimp_operation_layer_mode,
GEGL_TYPE_OPERATION_POINT_COMPOSER3)
#define parent_class gimp_operation_layer_mode_parent_class
static const Babl *gimp_layer_color_space_fish[3 /* from */][3 /* to */];
static CompositeFunc composite_union = gimp_operation_layer_mode_composite_union;
static CompositeFunc composite_clip_to_backdrop = gimp_operation_layer_mode_composite_clip_to_backdrop;
static CompositeFunc composite_clip_to_layer = gimp_operation_layer_mode_composite_clip_to_layer;
static CompositeFunc composite_intersection = gimp_operation_layer_mode_composite_intersection;
static CompositeFunc composite_union_sub = gimp_operation_layer_mode_composite_union_sub;
static CompositeFunc composite_clip_to_backdrop_sub = gimp_operation_layer_mode_composite_clip_to_backdrop_sub;
static CompositeFunc composite_clip_to_layer_sub = gimp_operation_layer_mode_composite_clip_to_layer_sub;
static CompositeFunc composite_intersection_sub = gimp_operation_layer_mode_composite_intersection_sub;
static void
gimp_operation_layer_mode_class_init (GimpOperationLayerModeClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GeglOperationPointComposer3Class *point_composer3_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
gegl_operation_class_set_keys (operation_class,
"name", "gimp:layer-mode", NULL);
object_class->set_property = gimp_operation_layer_mode_set_property;
object_class->get_property = gimp_operation_layer_mode_get_property;
operation_class->prepare = gimp_operation_layer_mode_prepare;
operation_class->process = gimp_operation_layer_mode_parent_process;
point_composer3_class->process = gimp_operation_layer_mode_process;
klass->process = gimp_operation_layer_mode_real_process;
klass->get_affected_region = NULL;
g_object_class_install_property (object_class, PROP_LAYER_MODE,
g_param_spec_enum ("layer-mode",
NULL, NULL,
GIMP_TYPE_LAYER_MODE,
GIMP_LAYER_MODE_NORMAL,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_OPACITY,
g_param_spec_double ("opacity",
NULL, NULL,
0.0, 1.0, 1.0,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_BLEND_SPACE,
g_param_spec_enum ("blend-space",
NULL, NULL,
GIMP_TYPE_LAYER_COLOR_SPACE,
GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_COMPOSITE_SPACE,
g_param_spec_enum ("composite-space",
NULL, NULL,
GIMP_TYPE_LAYER_COLOR_SPACE,
GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_COMPOSITE_MODE,
g_param_spec_enum ("composite-mode",
NULL, NULL,
GIMP_TYPE_LAYER_COMPOSITE_MODE,
GIMP_LAYER_COMPOSITE_UNION,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
gimp_layer_color_space_fish
/* from */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1]
/* to */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] =
babl_fish ("RGBA float", "R'G'B'A float");
gimp_layer_color_space_fish
/* from */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1]
/* to */ [GIMP_LAYER_COLOR_SPACE_LAB - 1] =
babl_fish ("RGBA float", "CIE Lab alpha float");
gimp_layer_color_space_fish
/* from */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1]
/* to */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1] =
babl_fish ("R'G'B'A float", "RGBA float");
gimp_layer_color_space_fish
/* from */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1]
/* to */ [GIMP_LAYER_COLOR_SPACE_LAB - 1] =
babl_fish ("R'G'B'A float", "CIE Lab alpha float");
gimp_layer_color_space_fish
/* from */ [GIMP_LAYER_COLOR_SPACE_LAB - 1]
/* to */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1] =
babl_fish ("CIE Lab alpha float", "RGBA float");
gimp_layer_color_space_fish
/* from */ [GIMP_LAYER_COLOR_SPACE_LAB - 1]
/* to */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] =
babl_fish ("CIE Lab alpha float", "R'G'B'A float");
#if COMPILE_SSE2_INTRINISICS
if (gimp_cpu_accel_get_support () & GIMP_CPU_ACCEL_X86_SSE2)
composite_clip_to_backdrop = gimp_operation_layer_mode_composite_clip_to_backdrop_sse2;
#endif
}
static void
gimp_operation_layer_mode_init (GimpOperationLayerMode *self)
{
}
static void
gimp_operation_layer_mode_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (object);
switch (property_id)
{
case PROP_LAYER_MODE:
self->layer_mode = g_value_get_enum (value);
break;
case PROP_OPACITY:
self->opacity = g_value_get_double (value);
break;
case PROP_BLEND_SPACE:
self->blend_space = g_value_get_enum (value);
break;
case PROP_COMPOSITE_SPACE:
self->composite_space = g_value_get_enum (value);
break;
case PROP_COMPOSITE_MODE:
self->composite_mode = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_operation_layer_mode_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (object);
switch (property_id)
{
case PROP_LAYER_MODE:
g_value_set_enum (value, self->layer_mode);
break;
case PROP_OPACITY:
g_value_set_double (value, self->opacity);
break;
case PROP_BLEND_SPACE:
g_value_set_enum (value, self->blend_space);
break;
case PROP_COMPOSITE_SPACE:
g_value_set_enum (value, self->composite_space);
break;
case PROP_COMPOSITE_MODE:
g_value_set_enum (value, self->composite_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_operation_layer_mode_prepare (GeglOperation *operation)
{
GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (operation);
const GeglRectangle *input_extent;
const Babl *preferred_format;
const Babl *format;
self->real_composite_mode = self->composite_mode;
if (self->real_composite_mode == GIMP_LAYER_COMPOSITE_AUTO)
{
self->real_composite_mode =
gimp_layer_mode_get_composite_mode (self->layer_mode);
g_warn_if_fail (self->real_composite_mode != GIMP_LAYER_COMPOSITE_AUTO);
}
self->function = gimp_layer_mode_get_function (self->layer_mode);
self->blend_function = gimp_layer_mode_get_blend_function (self->layer_mode);
input_extent = gegl_operation_source_get_bounding_box (operation, "input");
/* if the input pad has data, work as usual. */
if (input_extent && ! gegl_rectangle_is_empty (input_extent))
{
self->is_last_node = FALSE;
preferred_format = gegl_operation_get_source_format (operation, "input");
}
/* otherwise, we're the last node (corresponding to the bottom layer).
* in this case, we render the layer (as if) using UNION mode.
*/
else
{
self->is_last_node = TRUE;
/* if the layer mode doesn't affect the source, use a shortcut
* function that only applies the opacity/mask to the layer.
*/
if (! (gimp_operation_layer_mode_get_affected_region (self) &
GIMP_LAYER_COMPOSITE_REGION_SOURCE))
{
self->function = process_last_node;
}
/* otherwise, use the original process function, but force the
* composite mode to UNION.
*/
else
{
self->real_composite_mode = GIMP_LAYER_COMPOSITE_UNION;
}
preferred_format = gegl_operation_get_source_format (operation, "aux");
}
format = gimp_layer_mode_get_format (self->layer_mode,
self->composite_space,
self->blend_space,
preferred_format);
gegl_operation_set_format (operation, "input", format);
gegl_operation_set_format (operation, "output", format);
gegl_operation_set_format (operation, "aux", format);
gegl_operation_set_format (operation, "aux2", babl_format ("Y float"));
}
static gboolean
gimp_operation_layer_mode_parent_process (GeglOperation *operation,
GeglOperationContext *context,
const gchar *output_prop,
const GeglRectangle *result,
gint level)
{
GimpOperationLayerMode *point = GIMP_OPERATION_LAYER_MODE (operation);
GObject *input;
GObject *aux;
gboolean has_input;
gboolean has_aux;
GimpLayerCompositeRegion included_region;
/* get the raw values. this does not increase the reference count. */
input = gegl_operation_context_get_object (context, "input");
aux = gegl_operation_context_get_object (context, "aux");
/* disregard 'input' if it's not included in the roi. */
has_input =
input &&
gegl_rectangle_intersect (NULL,
gegl_buffer_get_extent (GEGL_BUFFER (input)),
result);
/* disregard 'aux' if it's not included in the roi, or if it's fully
* transparent.
*/
has_aux =
aux &&
point->opacity != 0.0 &&
gegl_rectangle_intersect (NULL,
gegl_buffer_get_extent (GEGL_BUFFER (aux)),
result);
if (point->is_last_node)
{
included_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE;
}
else
{
included_region = gimp_layer_mode_get_included_region (point->layer_mode,
point->composite_mode);
}
/* if there's no 'input' ... */
if (! has_input)
{
/* ... and there's 'aux', and the composite mode includes it (or we're
* the last node) ...
*/
if (has_aux && (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE))
{
GimpLayerCompositeRegion affected_region;
affected_region =
gimp_operation_layer_mode_get_affected_region (point);
/* ... and the op doesn't otherwise affect 'aux', or changes its
* alpha ...
*/
if (! (affected_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE) &&
point->opacity == 1.0 &&
! gegl_operation_context_get_object (context, "aux2"))
{
/* pass 'aux' directly as output; */
gegl_operation_context_set_object (context, "output", aux);
return TRUE;
}
/* otherwise, if the op affects 'aux', or changes its alpha, process
* it even though there's no 'input';
*/
}
/* otherwise, there's no 'aux', or the composite mode doesn't include it,
* and so ...
*/
else
{
/* ... the output is empty. */
gegl_operation_context_set_object (context, "output", NULL);
return TRUE;
}
}
/* otherwise, if there's 'input' but no 'aux' ... */
else if (! has_aux)
{
/* ... and the composite mode includes 'input' ... */
if (included_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION)
{
GimpLayerCompositeRegion affected_region;
affected_region =
gimp_operation_layer_mode_get_affected_region (point);
/* ... and the op doesn't otherwise affect 'input' ... */
if (! (affected_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION))
{
/* pass 'input' directly as output; */
gegl_operation_context_set_object (context, "output", input);
return TRUE;
}
/* otherwise, if the op affects 'input', process it even though
* there's no 'aux';
*/
}
/* otherwise, the output is fully transparent, but we process it anyway
* to maintain the 'input' color values.
*/
}
/* FIXME: we don't actually handle the case where one of the inputs
* is NULL -- it'll just segfault. 'input' is not expected to be NULL,
* but 'aux' might be, currently.
*/
if (! input || ! aux)
{
GObject *empty = G_OBJECT (gegl_buffer_new (NULL, NULL));
if (! input) gegl_operation_context_set_object (context, "input", empty);
if (! aux) gegl_operation_context_set_object (context, "aux", empty);
if (! input && ! aux)
gegl_object_set_has_forked (G_OBJECT (empty));
g_object_unref (empty);
}
/* chain up, which will create the needed buffers for our actual
* process function
*/
return GEGL_OPERATION_CLASS (parent_class)->process (operation, context,
output_prop, result,
level);
}
static gboolean
gimp_operation_layer_mode_process (GeglOperation *operation,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level)
{
return ((GimpOperationLayerMode *) operation)->function (
operation, in, layer, mask, out, samples, roi, level);
}
static gboolean
gimp_operation_layer_mode_real_process (GeglOperation *operation,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) operation;
gfloat *in = in_p;
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = layer_mode->opacity;
GimpLayerColorSpace blend_space = layer_mode->blend_space;
GimpLayerColorSpace composite_space = layer_mode->composite_space;
GimpLayerCompositeMode composite_mode = layer_mode->real_composite_mode;
GimpLayerModeBlendFunc blend_function = layer_mode->blend_function;
gboolean composite_needs_in_color;
gfloat *blend_in;
gfloat *blend_layer;
gfloat *blend_out;
const Babl *composite_to_blend_fish = NULL;
const Babl *blend_to_composite_fish = NULL;
/* make sure we don't process more than GIMP_COMPOSITE_BLEND_MAX_SAMPLES
* at a time, so that we don't overflow the stack if we allocate buffers
* on it. note that this has to be done with a nested function call,
* because alloca'd buffers remain for the duration of the stack frame.
*/
while (samples > GIMP_COMPOSITE_BLEND_MAX_SAMPLES)
{
gimp_operation_layer_mode_real_process (operation,
in, layer, mask, out,
GIMP_COMPOSITE_BLEND_MAX_SAMPLES,
roi, level);
in += 4 * GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
layer += 4 * GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
if (mask)
mask += GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
out += 4 * GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
samples -= GIMP_COMPOSITE_BLEND_MAX_SAMPLES;
}
composite_needs_in_color =
composite_mode == GIMP_LAYER_COMPOSITE_UNION ||
composite_mode == GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP;
blend_in = in;
blend_layer = layer;
blend_out = out;
if (blend_space != GIMP_LAYER_COLOR_SPACE_AUTO)
{
gimp_assert (composite_space >= 1 && composite_space < 4);
gimp_assert (blend_space >= 1 && blend_space < 4);
composite_to_blend_fish = gimp_layer_color_space_fish [composite_space - 1]
[blend_space - 1];
blend_to_composite_fish = gimp_layer_color_space_fish [blend_space - 1]
[composite_space - 1];
}
/* if we need to convert the samples between the composite and blend
* spaces...
*/
if (composite_to_blend_fish)
{
gint i;
gint end;
if (in != out || composite_needs_in_color)
{
/* don't convert input in-place if we're not doing in-place output,
* or if we're going to need the original input for compositing.
*/
blend_in = g_alloca (sizeof (gfloat) * 4 * samples);
}
blend_layer = g_alloca (sizeof (gfloat) * 4 * samples);
if (in == out) /* in-place detected, avoid clobbering since we need to
read 'in' for the compositing stage */
{
if (blend_layer != layer)
blend_out = blend_layer;
else
blend_out = g_alloca (sizeof (gfloat) * 4 * samples);
}
/* samples whose the source or destination alpha is zero are not blended,
* and therefore do not need to be converted. while it's generally
* desirable to perform conversion and blending in bulk, when we have
* more than a certain number of consecutive unblended samples, the cost
* of converting them outweighs the cost of splitting the process around
* them to avoid the conversion.
*/
i = ALPHA;
end = 4 * samples + ALPHA;
while (TRUE)
{
gint first;
gint last;
gint count;
/* skip any unblended samples. the color values of `blend_out` for
* these samples are unconstrained, in particular, they may be NaN,
* but the alpha values should generally be finite, and specifically
* 0 when the source alpha is 0.
*/
while (i < end && (in[i] == 0.0f || layer[i] == 0.0f))
{
blend_out[i] = 0.0f;
i += 4;
}
/* stop if there are no more samples */
if (i == end)
break;
/* otherwise, keep scanning the samples until we find
* GIMP_COMPOSITE_BLEND_SPLIT_THRESHOLD consecutive unblended
* samples.
*/
first = i;
i += 4;
last = i;
while (i < end && i - last < 4 * GIMP_COMPOSITE_BLEND_SPLIT_THRESHOLD)
{
gboolean blended;
blended = (in[i] != 0.0f && layer[i] != 0.0f);
i += 4;
if (blended)
last = i;
}
/* convert and blend the samples in the range [first, last) */
count = (last - first) / 4;
first -= ALPHA;
babl_process (composite_to_blend_fish,
in + first, blend_in + first, count);
babl_process (composite_to_blend_fish,
layer + first, blend_layer + first, count);
blend_function (blend_in + first, blend_layer + first,
blend_out + first, count);
babl_process (blend_to_composite_fish,
blend_out + first, blend_out + first, count);
/* make sure the alpha values of `blend_out` are valid for the
* trailing unblended samples.
*/
for (; last < i; last += 4)
blend_out[last] = 0.0f;
}
}
else
{
/* if both blending and compositing use the same color space, things are
* much simpler.
*/
if (in == out) /* in-place detected, avoid clobbering since we need to
read 'in' for the compositing stage */
{
blend_out = g_alloca (sizeof (gfloat) * 4 * samples);
}
blend_function (blend_in, blend_layer, blend_out, samples);
}
if (! gimp_layer_mode_is_subtractive (layer_mode->layer_mode))
{
switch (composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
case GIMP_LAYER_COMPOSITE_AUTO:
composite_union (in, layer, blend_out, mask, opacity,
out, samples);
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
composite_clip_to_backdrop (in, layer, blend_out, mask, opacity,
out, samples);
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
composite_clip_to_layer (in, layer, blend_out, mask, opacity,
out, samples);
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
composite_intersection (in, layer, blend_out, mask, opacity,
out, samples);
break;
}
}
else
{
switch (composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
case GIMP_LAYER_COMPOSITE_AUTO:
composite_union_sub (in, layer, blend_out, mask, opacity,
out, samples);
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
composite_clip_to_backdrop_sub (in, layer, blend_out, mask, opacity,
out, samples);
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
composite_clip_to_layer_sub (in, layer, blend_out, mask, opacity,
out, samples);
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
composite_intersection_sub (in, layer, blend_out, mask, opacity,
out, samples);
break;
}
}
return TRUE;
}
static gboolean
process_last_node (GeglOperation *operation,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = GIMP_OPERATION_LAYER_MODE (operation)->opacity;
while (samples--)
{
memcpy (out, layer, 3 * sizeof (gfloat));
out[ALPHA] = layer[ALPHA] * opacity;
if (mask)
out[ALPHA] *= *mask++;
layer += 4;
out += 4;
}
return TRUE;
}
/* public functions */
GimpLayerCompositeRegion
gimp_operation_layer_mode_get_affected_region (GimpOperationLayerMode *layer_mode)
{
GimpOperationLayerModeClass *klass;
g_return_val_if_fail (GIMP_IS_OPERATION_LAYER_MODE (layer_mode),
GIMP_LAYER_COMPOSITE_REGION_INTERSECTION);
klass = GIMP_OPERATION_LAYER_MODE_GET_CLASS (layer_mode);
if (klass->get_affected_region)
return klass->get_affected_region (layer_mode);
return GIMP_LAYER_COMPOSITE_REGION_INTERSECTION;
}

View File

@ -0,0 +1,81 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationlayermode.h
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_LAYER_MODE_H__
#define __GIMP_OPERATION_LAYER_MODE_H__
#include <gegl-plugin.h>
#define GIMP_TYPE_OPERATION_LAYER_MODE (gimp_operation_layer_mode_get_type ())
#define GIMP_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_LAYER_MODE, GimpOperationLayerMode))
#define GIMP_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_LAYER_MODE, GimpOperationLayerModeClass))
#define GIMP_IS_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_LAYER_MODE))
#define GIMP_IS_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_LAYER_MODE))
#define GIMP_OPERATION_LAYER_MODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_LAYER_MODE, GimpOperationLayerModeClass))
typedef struct _GimpOperationLayerModeClass GimpOperationLayerModeClass;
struct _GimpOperationLayerMode
{
GeglOperationPointComposer3 parent_instance;
GimpLayerMode layer_mode;
gdouble opacity;
GimpLayerColorSpace blend_space;
GimpLayerColorSpace composite_space;
GimpLayerCompositeMode composite_mode;
GimpLayerCompositeMode real_composite_mode;
GimpLayerModeFunc function;
GimpLayerModeBlendFunc blend_function;
gboolean is_last_node;
};
struct _GimpOperationLayerModeClass
{
GeglOperationPointComposer3Class parent_class;
/* virtual functions */
gboolean (* process) (GeglOperation *operation,
void *in,
void *aux,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
/* Returns the composite region (any combination of the layer and the
* backdrop) that the layer mode affects. Most modes only affect the
* overlapping region, and don't need to override this function.
*/
GimpLayerCompositeRegion (* get_affected_region) (GimpOperationLayerMode *layer_mode);
};
GType gimp_operation_layer_mode_get_type (void) G_GNUC_CONST;
GimpLayerCompositeRegion gimp_operation_layer_mode_get_affected_region (GimpOperationLayerMode *layer_mode);
#endif /* __GIMP_OPERATION_LAYER_MODE_H__ */

View File

@ -0,0 +1,243 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationmerge.c
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "../operations-types.h"
#include "gimpoperationmerge.h"
static gboolean gimp_operation_merge_process (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
G_DEFINE_TYPE (GimpOperationMerge, gimp_operation_merge,
GIMP_TYPE_OPERATION_LAYER_MODE)
static void
gimp_operation_merge_class_init (GimpOperationMergeClass *klass)
{
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
gegl_operation_class_set_keys (operation_class,
"name", "gimp:merge",
"description", "GIMP merge mode operation",
NULL);
layer_mode_class->process = gimp_operation_merge_process;
}
static void
gimp_operation_merge_init (GimpOperationMerge *self)
{
}
static gboolean
gimp_operation_merge_process (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat *in = in_p;
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = layer_mode->opacity;
const gboolean has_mask = mask != NULL;
switch (layer_mode->real_composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
case GIMP_LAYER_COMPOSITE_AUTO:
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gfloat new_alpha;
gint b;
if (has_mask)
layer_alpha *= *mask;
in_alpha = MIN (in_alpha, 1.0f - layer_alpha);
new_alpha = in_alpha + layer_alpha;
if (new_alpha)
{
gfloat ratio = layer_alpha / new_alpha;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b] + (layer[b] - in[b]) * ratio;
}
}
else
{
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gint b;
if (has_mask)
layer_alpha *= *mask;
layer_alpha -= 1.0f - in_alpha;
if (layer_alpha > 0.0f)
{
gfloat ratio = layer_alpha / in_alpha;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b] + (layer[b] - in[b]) * ratio;
}
}
else
{
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
out[ALPHA] = in_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
while (samples--)
{
gfloat layer_alpha = layer[ALPHA] * opacity;
gint b;
if (has_mask)
layer_alpha *= *mask;
if (layer_alpha != 0.0f)
{
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
else
{
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
out[ALPHA] = layer_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gint b;
if (has_mask)
layer_alpha *= *mask;
layer_alpha -= 1.0f - in_alpha;
layer_alpha = MAX (layer_alpha, 0.0f);
if (layer_alpha != 0.0f)
{
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
else
{
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
out[ALPHA] = layer_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
}
return TRUE;
}

View File

@ -0,0 +1,54 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationmerge.h
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_MERGE_H__
#define __GIMP_OPERATION_MERGE_H__
#include "gimpoperationlayermode.h"
#define GIMP_TYPE_OPERATION_MERGE (gimp_operation_merge_get_type ())
#define GIMP_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_MERGE, GimpOperationMerge))
#define GIMP_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_MERGE, GimpOperationMergeClass))
#define GIMP_IS_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_MERGE))
#define GIMP_IS_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_MERGE))
#define GIMP_OPERATION_MERGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_MERGE, GimpOperationMergeClass))
typedef struct _GimpOperationMerge GimpOperationMerge;
typedef struct _GimpOperationMergeClass GimpOperationMergeClass;
struct _GimpOperationMerge
{
GimpOperationLayerMode parent_instance;
};
struct _GimpOperationMergeClass
{
GimpOperationLayerModeClass parent_class;
};
GType gimp_operation_merge_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_OPERATION_MERGE_H__ */

View File

@ -0,0 +1,264 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationnormal-sse2.c
* Copyright (C) 2013 Daniel Sabo
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "operations/operations-types.h"
#include "gimpoperationnormal.h"
#if COMPILE_SSE2_INTRINISICS
/* SSE2 */
#include <emmintrin.h>
gboolean
gimp_operation_normal_process_sse2 (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
/* check alignment */
if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F)
{
return gimp_operation_normal_process (op,
in_p, layer_p, mask_p, out_p,
samples, roi, level);
}
else
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat opacity = layer_mode->opacity;
gfloat *mask = mask_p;
const __v4sf *v_in = (const __v4sf*) in_p;
const __v4sf *v_layer = (const __v4sf*) layer_p;
__v4sf *v_out = ( __v4sf*) out_p;
const __v4sf one = _mm_set1_ps (1.0f);
const __v4sf v_opacity = _mm_set1_ps (opacity);
switch (layer_mode->real_composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
case GIMP_LAYER_COMPOSITE_AUTO:
while (samples--)
{
__v4sf rgba_in, rgba_layer, alpha;
rgba_in = *v_in++;
rgba_layer = *v_layer++;
/* expand alpha */
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
_MM_SHUFFLE (3, 3, 3, 3));
if (mask)
{
__v4sf mask_alpha;
/* multiply layer's alpha by the mask */
mask_alpha = _mm_set1_ps (*mask++);
alpha = alpha * mask_alpha;
}
alpha = alpha * v_opacity;
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
{
__v4sf dst_alpha, a_term, out_pixel, out_alpha, out_pixel_rbaa;
/* expand alpha */
dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
_MM_SHUFFLE (3, 3, 3, 3));
/* a_term = dst_a * (1.0 - src_a) */
a_term = dst_alpha * (one - alpha);
/* out(color) = src * src_a + dst * a_term */
out_pixel = rgba_layer * alpha + rgba_in * a_term;
/* out(alpha) = 1.0 * src_a + 1.0 * a_term */
out_alpha = alpha + a_term;
/* un-premultiply */
out_pixel = out_pixel / out_alpha;
/* swap in the real alpha */
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0));
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
*v_out++ = out_pixel;
}
else
{
*v_out++ = rgba_in;
}
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
while (samples--)
{
__v4sf rgba_in, rgba_layer, alpha;
rgba_in = *v_in++;
rgba_layer = *v_layer++;
/* expand alpha */
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
_MM_SHUFFLE (3, 3, 3, 3));
if (mask)
{
__v4sf mask_alpha;
/* multiply layer's alpha by the mask */
mask_alpha = _mm_set1_ps (*mask++);
alpha = alpha * mask_alpha;
}
alpha = alpha * v_opacity;
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
{
__v4sf dst_alpha, out_pixel, out_pixel_rbaa;
/* expand alpha */
dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
_MM_SHUFFLE (3, 3, 3, 3));
/* out(color) = dst * (1 - src_a) + src * src_a */
out_pixel = rgba_in + (rgba_layer - rgba_in) * alpha;
/* swap in the real alpha */
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, dst_alpha, _MM_SHUFFLE (3, 3, 2, 0));
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
*v_out++ = out_pixel;
}
else
{
*v_out++ = rgba_in;
}
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
while (samples--)
{
__v4sf rgba_in, rgba_layer, alpha;
__v4sf out_pixel, out_pixel_rbaa;
rgba_in = *v_in++;
rgba_layer = *v_layer++;
/* expand alpha */
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
_MM_SHUFFLE (3, 3, 3, 3));
if (mask)
{
__v4sf mask_alpha;
/* multiply layer's alpha by the mask */
mask_alpha = _mm_set1_ps (*mask++);
alpha = alpha * mask_alpha;
}
alpha = alpha * v_opacity;
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
{
/* out(color) = src */
out_pixel = rgba_layer;
}
else
{
out_pixel = rgba_in;
}
/* swap in the real alpha */
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0));
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
*v_out++ = out_pixel;
}
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
while (samples--)
{
__v4sf rgba_in, rgba_layer, alpha;
__v4sf out_pixel, out_pixel_rbaa;
rgba_in = *v_in++;
rgba_layer = *v_layer++;
/* expand alpha */
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
_MM_SHUFFLE (3, 3, 3, 3));
if (mask)
{
__v4sf mask_alpha;
/* multiply layer's alpha by the mask */
mask_alpha = _mm_set1_ps (*mask++);
alpha = alpha * mask_alpha;
}
alpha = alpha * v_opacity;
/* multiply the alpha by in's alpha */
alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
_MM_SHUFFLE (3, 3, 3, 3));
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
{
/* out(color) = src */
out_pixel = rgba_layer;
}
else
{
out_pixel = rgba_in;
}
/* swap in the real alpha */
out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0));
out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0));
*v_out++ = out_pixel;
}
break;
}
}
return TRUE;
}
#endif /* COMPILE_SSE2_INTRINISICS */

View File

@ -0,0 +1,260 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationnormalmode-sse2.c
* Copyright (C) 2013 Daniel Sabo
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "operations/operations-types.h"
#include "gimpoperationnormal.h"
#if COMPILE_SSE4_1_INTRINISICS
/* SSE4 */
#include <smmintrin.h>
gboolean
gimp_operation_normal_process_sse4 (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
/* check alignment */
if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F)
{
return gimp_operation_normal_process (op,
in_p, layer_p, mask_p, out_p,
samples, roi, level);
}
else
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat opacity = layer_mode->opacity;
gfloat *mask = mask_p;
const __v4sf *v_in = (const __v4sf*) in_p;
const __v4sf *v_layer = (const __v4sf*) layer_p;
__v4sf *v_out = ( __v4sf*) out_p;
const __v4sf one = _mm_set1_ps (1.0f);
const __v4sf v_opacity = _mm_set1_ps (opacity);
switch (layer_mode->real_composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
case GIMP_LAYER_COMPOSITE_AUTO:
while (samples--)
{
__v4sf rgba_in, rgba_layer, alpha;
rgba_in = *v_in++;
rgba_layer = *v_layer++;
/* expand alpha */
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
_MM_SHUFFLE (3, 3, 3, 3));
if (mask)
{
__v4sf mask_alpha;
/* multiply layer's alpha by the mask */
mask_alpha = _mm_set1_ps (*mask++);
alpha = alpha * mask_alpha;
}
alpha = alpha * v_opacity;
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
{
__v4sf dst_alpha, a_term, out_pixel, out_alpha;
/* expand alpha */
dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
_MM_SHUFFLE (3, 3, 3, 3));
/* a_term = dst_a * (1.0 - src_a) */
a_term = dst_alpha * (one - alpha);
/* out(color) = src * src_a + dst * a_term */
out_pixel = rgba_layer * alpha + rgba_in * a_term;
/* out(alpha) = 1.0 * src_a + 1.0 * a_term */
out_alpha = alpha + a_term;
/* un-premultiply */
out_pixel = out_pixel / out_alpha;
/* swap in the real alpha */
out_pixel = _mm_blend_ps (out_pixel, out_alpha, 0x08);
*v_out++ = out_pixel;
}
else
{
*v_out++ = rgba_in;
}
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
while (samples--)
{
__v4sf rgba_in, rgba_layer, alpha;
rgba_in = *v_in++;
rgba_layer = *v_layer++;
/* expand alpha */
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
_MM_SHUFFLE (3, 3, 3, 3));
if (mask)
{
__v4sf mask_alpha;
/* multiply layer's alpha by the mask */
mask_alpha = _mm_set1_ps (*mask++);
alpha = alpha * mask_alpha;
}
alpha = alpha * v_opacity;
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
{
__v4sf dst_alpha, out_pixel;
/* expand alpha */
dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
_MM_SHUFFLE (3, 3, 3, 3));
/* out(color) = dst * (1 - src_a) + src * src_a */
out_pixel = rgba_in + (rgba_layer - rgba_in) * alpha;
/* swap in the real alpha */
out_pixel = _mm_blend_ps (out_pixel, dst_alpha, 0x08);
*v_out++ = out_pixel;
}
else
{
*v_out++ = rgba_in;
}
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
while (samples--)
{
__v4sf rgba_in, rgba_layer, alpha;
__v4sf out_pixel;
rgba_in = *v_in++;
rgba_layer = *v_layer++;
/* expand alpha */
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
_MM_SHUFFLE (3, 3, 3, 3));
if (mask)
{
__v4sf mask_alpha;
/* multiply layer's alpha by the mask */
mask_alpha = _mm_set1_ps (*mask++);
alpha = alpha * mask_alpha;
}
alpha = alpha * v_opacity;
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
{
/* out(color) = src */
out_pixel = rgba_layer;
}
else
{
out_pixel = rgba_in;
}
/* swap in the real alpha */
out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08);
*v_out++ = out_pixel;
}
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
while (samples--)
{
__v4sf rgba_in, rgba_layer, alpha;
__v4sf out_pixel;
rgba_in = *v_in++;
rgba_layer = *v_layer++;
/* expand alpha */
alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer,
_MM_SHUFFLE (3, 3, 3, 3));
if (mask)
{
__v4sf mask_alpha;
/* multiply layer's alpha by the mask */
mask_alpha = _mm_set1_ps (*mask++);
alpha = alpha * mask_alpha;
}
alpha = alpha * v_opacity;
/* multiply the alpha by in's alpha */
alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in,
_MM_SHUFFLE (3, 3, 3, 3));
if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ()))
{
/* out(color) = src */
out_pixel = rgba_layer;
}
else
{
out_pixel = rgba_in;
}
/* swap in the real alpha */
out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08);
*v_out++ = out_pixel;
}
break;
}
}
return TRUE;
}
#endif /* COMPILE_SSE4_1_INTRINISICS */

View File

@ -0,0 +1,266 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationnormalmode.c
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gio/gio.h>
#include <gegl-plugin.h>
#include "libgimpbase/gimpbase.h"
#include "../operations-types.h"
#include "gimpoperationnormal.h"
G_DEFINE_TYPE (GimpOperationNormal, gimp_operation_normal,
GIMP_TYPE_OPERATION_LAYER_MODE)
static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>"
"<gegl>"
"<node operation='gimp:normal'>"
" <node operation='gegl:load'>"
" <params>"
" <param name='path'>blending-test-B.png</param>"
" </params>"
" </node>"
"</node>"
"<node operation='gegl:load'>"
" <params>"
" <param name='path'>blending-test-A.png</param>"
" </params>"
"</node>"
"</gegl>";
static void
gimp_operation_normal_class_init (GimpOperationNormalClass *klass)
{
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
gegl_operation_class_set_keys (operation_class,
"name", "gimp:normal",
"description", "GIMP normal mode operation",
"reference-image", "normal-mode.png",
"reference-composition", reference_xml,
NULL);
layer_mode_class->process = gimp_operation_normal_process;
#if COMPILE_SSE2_INTRINISICS
if (gimp_cpu_accel_get_support() & GIMP_CPU_ACCEL_X86_SSE2)
layer_mode_class->process = gimp_operation_normal_process_sse2;
#endif /* COMPILE_SSE2_INTRINISICS */
#if COMPILE_SSE4_1_INTRINISICS
if (gimp_cpu_accel_get_support() & GIMP_CPU_ACCEL_X86_SSE4_1)
layer_mode_class->process = gimp_operation_normal_process_sse4;
#endif /* COMPILE_SSE4_1_INTRINISICS */
}
static void
gimp_operation_normal_init (GimpOperationNormal *self)
{
}
gboolean
gimp_operation_normal_process (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat *in = in_p;
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = layer_mode->opacity;
const gboolean has_mask = mask != NULL;
switch (layer_mode->real_composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
case GIMP_LAYER_COMPOSITE_AUTO:
while (samples--)
{
gfloat layer_alpha;
layer_alpha = layer[ALPHA] * opacity;
if (has_mask)
layer_alpha *= *mask;
out[ALPHA] = layer_alpha + in[ALPHA] - layer_alpha * in[ALPHA];
if (out[ALPHA])
{
gfloat layer_weight = layer_alpha / out[ALPHA];
gfloat in_weight = 1.0f - layer_weight;
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b] * layer_weight + in[b] * in_weight;
}
}
else
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
while (samples--)
{
gfloat layer_alpha;
layer_alpha = layer[ALPHA] * opacity;
if (has_mask)
layer_alpha *= *mask;
out[ALPHA] = in[ALPHA];
if (out[ALPHA])
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b] + (layer[b] - in[b]) * layer_alpha;
}
}
else
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
while (samples--)
{
gfloat layer_alpha;
layer_alpha = layer[ALPHA] * opacity;
if (has_mask)
layer_alpha *= *mask;
out[ALPHA] = layer_alpha;
if (out[ALPHA])
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
else
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
while (samples--)
{
gfloat layer_alpha;
layer_alpha = layer[ALPHA] * opacity;
if (has_mask)
layer_alpha *= *mask;
out[ALPHA] = in[ALPHA] * layer_alpha;
if (out[ALPHA])
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
else
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
}
return TRUE;
}

View File

@ -0,0 +1,91 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationnormal.h
* Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_NORMAL_H__
#define __GIMP_OPERATION_NORMAL_H__
#include "gimpoperationlayermode.h"
#define GIMP_TYPE_OPERATION_NORMAL (gimp_operation_normal_get_type ())
#define GIMP_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_NORMAL, GimpOperationNormal))
#define GIMP_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_NORMAL, GimpOperationNormalClass))
#define GIMP_IS_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_NORMAL))
#define GIMP_IS_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_NORMAL))
#define GIMP_OPERATION_NORMAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_NORMAL, GimpOperationNormalClass))
typedef struct _GimpOperationNormal GimpOperationNormal;
typedef struct _GimpOperationNormalClass GimpOperationNormalClass;
struct _GimpOperationNormal
{
GimpOperationLayerMode parent_instance;
};
struct _GimpOperationNormalClass
{
GimpOperationLayerModeClass parent_class;
};
GType gimp_operation_normal_get_type (void) G_GNUC_CONST;
/* protected */
gboolean gimp_operation_normal_process (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
#if COMPILE_SSE2_INTRINISICS
gboolean gimp_operation_normal_process_sse2 (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
#endif /* COMPILE_SSE2_INTRINISICS */
#if COMPILE_SSE4_1_INTRINISICS
gboolean gimp_operation_normal_process_sse4 (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
#endif /* COMPILE_SSE4_1_INTRINISICS */
#endif /* __GIMP_OPERATION_NORMAL_H__ */

View File

@ -0,0 +1,106 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationpassthrough.c
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "../operations-types.h"
#include "gimp-layer-modes.h"
#include "gimpoperationpassthrough.h"
static gboolean gimp_operation_pass_through_parent_process (GeglOperation *operation,
GeglOperationContext *context,
const gchar *output_prop,
const GeglRectangle *result,
gint level);
G_DEFINE_TYPE (GimpOperationPassThrough, gimp_operation_pass_through,
GIMP_TYPE_OPERATION_REPLACE)
#define parent_class gimp_operation_pass_through_parent_class
static void
gimp_operation_pass_through_class_init (GimpOperationPassThroughClass *klass)
{
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
gegl_operation_class_set_keys (operation_class,
"name", "gimp:pass-through",
"description", "GIMP pass through mode operation",
NULL);
operation_class->process = gimp_operation_pass_through_parent_process;
/* don't use REPLACE mode's specialized get_affected_region(); PASS_THROUGH
* behaves like an ordinary layer mode here.
*/
layer_mode_class->get_affected_region = NULL;
}
static void
gimp_operation_pass_through_init (GimpOperationPassThrough *self)
{
}
static gboolean
gimp_operation_pass_through_parent_process (GeglOperation *operation,
GeglOperationContext *context,
const gchar *output_prop,
const GeglRectangle *result,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) operation;
/* if the layer's opacity is 100%, it has no mask, and its composite mode
* contains "aux" (the latter should always be the case for pass through
* mode,) we can just pass "aux" directly as output. note that the same
* optimization would more generally apply to REPLACE mode, save for the fact
* that when both the backdrop and the layer have a pixel with 0% alpha, we
* want to maintain the color value of the backdrop, not the layer; since,
* for pass through groups, the layer is already composited against the
* backdrop, such pixels will have the same color value for both the backdrop
* and the layer.
*/
if (layer_mode->opacity == 1.0 &&
! gegl_operation_context_get_object (context, "aux2") &&
(gimp_layer_mode_get_included_region (layer_mode->layer_mode,
layer_mode->real_composite_mode) &
GIMP_LAYER_COMPOSITE_REGION_SOURCE))
{
GObject *aux;
aux = gegl_operation_context_get_object (context, "aux");
gegl_operation_context_set_object (context, "output", aux);
return TRUE;
}
return GEGL_OPERATION_CLASS (parent_class)->process (operation, context,
output_prop, result,
level);
}

View File

@ -0,0 +1,54 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationpassthrough.h
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_PASS_THROUGH_H__
#define __GIMP_OPERATION_PASS_THROUGH_H__
#include "gimpoperationreplace.h"
#define GIMP_TYPE_OPERATION_PASS_THROUGH (gimp_operation_pass_through_get_type ())
#define GIMP_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_PASS_THROUGH, GimpOperationPassThrough))
#define GIMP_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_PASS_THROUGH, GimpOperationPassThroughClass))
#define GIMP_IS_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_PASS_THROUGH))
#define GIMP_IS_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_PASS_THROUGH))
#define GIMP_OPERATION_PASS_THROUGH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_PASS_THROUGH, GimpOperationPassThroughClass))
typedef struct _GimpOperationPassThrough GimpOperationPassThrough;
typedef struct _GimpOperationPassThroughClass GimpOperationPassThroughClass;
struct _GimpOperationPassThrough
{
GimpOperationReplace parent_instance;
};
struct _GimpOperationPassThroughClass
{
GimpOperationReplaceClass parent_class;
};
GType gimp_operation_pass_through_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_OPERATION_PASS_THROUGH_H__ */

View File

@ -0,0 +1,213 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationreplace.c
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "../operations-types.h"
#include "gimpoperationreplace.h"
static gboolean gimp_operation_replace_process (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
static GimpLayerCompositeRegion gimp_operation_replace_get_affected_region (GimpOperationLayerMode *layer_mode);
G_DEFINE_TYPE (GimpOperationReplace, gimp_operation_replace,
GIMP_TYPE_OPERATION_LAYER_MODE)
static void
gimp_operation_replace_class_init (GimpOperationReplaceClass *klass)
{
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
gegl_operation_class_set_keys (operation_class,
"name", "gimp:replace",
"description", "GIMP replace mode operation",
NULL);
layer_mode_class->process = gimp_operation_replace_process;
layer_mode_class->get_affected_region = gimp_operation_replace_get_affected_region;
}
static void
gimp_operation_replace_init (GimpOperationReplace *self)
{
}
static gboolean
gimp_operation_replace_process (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat *in = in_p;
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = layer_mode->opacity;
const gboolean has_mask = mask != NULL;
switch (layer_mode->real_composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
case GIMP_LAYER_COMPOSITE_AUTO:
while (samples--)
{
gfloat opacity_value = opacity;
gfloat new_alpha;
gint b;
if (has_mask)
opacity_value *= *mask;
new_alpha = (layer[ALPHA] - in[ALPHA]) * opacity_value + in[ALPHA];
if (new_alpha)
{
gfloat ratio = opacity_value * layer[ALPHA] / new_alpha;
for (b = RED; b < ALPHA; b++)
out[b] = (layer[b] - in[b]) * ratio + in[b];
}
else
{
for (b = RED; b < ALPHA; b++)
out[b] = in[b];
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
while (samples--)
{
gfloat opacity_value = opacity;
gfloat new_alpha;
gint b;
if (has_mask)
opacity_value *= *mask;
new_alpha = in[ALPHA] * (1.0f - opacity_value);
for (b = RED; b < ALPHA; b++)
out[b] = in[b];
out[ALPHA] = new_alpha;
in += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
while (samples--)
{
gfloat opacity_value = opacity;
gfloat new_alpha;
gint b;
if (has_mask)
opacity_value *= *mask;
new_alpha = layer[ALPHA] * opacity_value;
if (new_alpha)
{
for (b = RED; b < ALPHA; b++)
out[b] = layer[b];
}
else
{
for (b = RED; b < ALPHA; b++)
out[b] = in[b];
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
while (samples--)
{
gint b;
for (b = RED; b < ALPHA; b++)
out[b] = in[b];
out[ALPHA] = 0.0f;
in += 4;
out += 4;
}
break;
}
return TRUE;
}
static GimpLayerCompositeRegion
gimp_operation_replace_get_affected_region (GimpOperationLayerMode *layer_mode)
{
GimpLayerCompositeRegion affected_region = GIMP_LAYER_COMPOSITE_REGION_INTERSECTION;
if (layer_mode->opacity != 0.0)
affected_region |= GIMP_LAYER_COMPOSITE_REGION_DESTINATION;
/* if opacity != 1.0, or we have a mask, then we also affect SOURCE, but this
* is considered the case anyway, so no need for special handling.
*/
return affected_region;
}

View File

@ -0,0 +1,53 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationreplace.h
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_REPLACE_H__
#define __GIMP_OPERATION_REPLACE_H__
#include "gimpoperationlayermode.h"
#define GIMP_TYPE_OPERATION_REPLACE (gimp_operation_replace_get_type ())
#define GIMP_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_REPLACE, GimpOperationReplace))
#define GIMP_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_REPLACE, GimpOperationReplaceClass))
#define GIMP_IS_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_REPLACE))
#define GIMP_IS_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_REPLACE))
#define GIMP_OPERATION_REPLACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_REPLACE, GimpOperationReplaceClass))
typedef struct _GimpOperationReplace GimpOperationReplace;
typedef struct _GimpOperationReplaceClass GimpOperationReplaceClass;
struct _GimpOperationReplace
{
GimpOperationLayerMode parent_instance;
};
struct _GimpOperationReplaceClass
{
GimpOperationLayerModeClass parent_class;
};
GType gimp_operation_replace_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_OPERATION_REPLACE_H__ */

View File

@ -0,0 +1,213 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationsplit.c
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl-plugin.h>
#include "../operations-types.h"
#include "gimpoperationsplit.h"
static gboolean gimp_operation_split_process (GeglOperation *op,
void *in,
void *layer,
void *mask,
void *out,
glong samples,
const GeglRectangle *roi,
gint level);
G_DEFINE_TYPE (GimpOperationSplit, gimp_operation_split,
GIMP_TYPE_OPERATION_LAYER_MODE)
static void
gimp_operation_split_class_init (GimpOperationSplitClass *klass)
{
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass);
gegl_operation_class_set_keys (operation_class,
"name", "gimp:split",
"description", "GIMP split mode operation",
NULL);
layer_mode_class->process = gimp_operation_split_process;
}
static void
gimp_operation_split_init (GimpOperationSplit *self)
{
}
static gboolean
gimp_operation_split_process (GeglOperation *op,
void *in_p,
void *layer_p,
void *mask_p,
void *out_p,
glong samples,
const GeglRectangle *roi,
gint level)
{
GimpOperationLayerMode *layer_mode = (gpointer) op;
gfloat *in = in_p;
gfloat *out = out_p;
gfloat *layer = layer_p;
gfloat *mask = mask_p;
gfloat opacity = layer_mode->opacity;
const gboolean has_mask = mask != NULL;
switch (layer_mode->real_composite_mode)
{
case GIMP_LAYER_COMPOSITE_UNION:
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gfloat new_alpha;
gint b;
if (has_mask)
layer_alpha *= *mask;
if (layer_alpha <= in_alpha)
{
new_alpha = in_alpha - layer_alpha;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
else
{
new_alpha = layer_alpha - in_alpha;
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
case GIMP_LAYER_COMPOSITE_AUTO:
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gfloat new_alpha;
gint b;
if (has_mask)
layer_alpha *= *mask;
new_alpha = MAX (in_alpha - layer_alpha, 0.0f);
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER:
while (samples--)
{
gfloat in_alpha = in[ALPHA];
gfloat layer_alpha = layer[ALPHA] * opacity;
gfloat new_alpha;
gint b;
if (has_mask)
layer_alpha *= *mask;
new_alpha = MAX (layer_alpha - in_alpha, 0.0f);
if (new_alpha != 0.0f)
{
for (b = RED; b < ALPHA; b++)
{
out[b] = layer[b];
}
}
else
{
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
}
out[ALPHA] = new_alpha;
in += 4;
layer += 4;
out += 4;
if (has_mask)
mask++;
}
break;
case GIMP_LAYER_COMPOSITE_INTERSECTION:
while (samples--)
{
gint b;
for (b = RED; b < ALPHA; b++)
{
out[b] = in[b];
}
out[ALPHA] = 0.0f;
in += 4;
out += 4;
}
break;
}
return TRUE;
}

View File

@ -0,0 +1,54 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpoperationsplit.h
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
* 2017 Ell
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_OPERATION_SPLIT_H__
#define __GIMP_OPERATION_SPLIT_H__
#include "gimpoperationlayermode.h"
#define GIMP_TYPE_OPERATION_SPLIT (gimp_operation_split_get_type ())
#define GIMP_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplit))
#define GIMP_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplitClass))
#define GIMP_IS_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SPLIT))
#define GIMP_IS_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SPLIT))
#define GIMP_OPERATION_SPLIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplitClass))
typedef struct _GimpOperationSplit GimpOperationSplit;
typedef struct _GimpOperationSplitClass GimpOperationSplitClass;
struct _GimpOperationSplit
{
GimpOperationLayerMode parent_instance;
};
struct _GimpOperationSplitClass
{
GimpOperationLayerModeClass parent_class;
};
GType gimp_operation_split_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_OPERATION_SPLIT_H__ */