Initial checkin of Pika from heckimp
This commit is contained in:
53
app/operations/layer-modes/meson.build
Normal file
53
app/operations/layer-modes/meson.build
Normal file
@ -0,0 +1,53 @@
|
||||
libapplayermodes_composite = simd.check('pikaoperationlayermode-composite-simd',
|
||||
sse2: 'pikaoperationlayermode-composite-sse2.c',
|
||||
compiler: cc,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
dependencies: [
|
||||
cairo,
|
||||
gegl,
|
||||
gdk_pixbuf,
|
||||
],
|
||||
)
|
||||
|
||||
libapplayermodes_normal = simd.check('pikaoperationnormal-simd',
|
||||
sse2: 'pikaoperationnormal-sse2.c',
|
||||
sse41: 'pikaoperationnormal-sse4.c',
|
||||
compiler: cc,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
dependencies: [
|
||||
cairo,
|
||||
gegl,
|
||||
gdk_pixbuf,
|
||||
],
|
||||
)
|
||||
|
||||
libapplayermodes_sources = files(
|
||||
'pika-layer-modes.c',
|
||||
'pikaoperationantierase.c',
|
||||
'pikaoperationbehind.c',
|
||||
'pikaoperationdissolve.c',
|
||||
'pikaoperationerase.c',
|
||||
'pikaoperationlayermode-blend.c',
|
||||
'pikaoperationlayermode-composite.c',
|
||||
'pikaoperationlayermode.c',
|
||||
'pikaoperationmerge.c',
|
||||
'pikaoperationnormal.c',
|
||||
'pikaoperationpassthrough.c',
|
||||
'pikaoperationreplace.c',
|
||||
'pikaoperationsplit.c',
|
||||
)
|
||||
|
||||
libapplayermodes = static_library('applayermodes',
|
||||
libapplayermodes_sources,
|
||||
link_with: [
|
||||
libapplayermodes_composite[0],
|
||||
libapplayermodes_normal[0],
|
||||
],
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
c_args: '-DG_LOG_DOMAIN="Pika-Layer-Modes"',
|
||||
dependencies: [
|
||||
cairo,
|
||||
gegl,
|
||||
gdk_pixbuf,
|
||||
],
|
||||
)
|
1574
app/operations/layer-modes/pika-layer-modes.c
Normal file
1574
app/operations/layer-modes/pika-layer-modes.c
Normal file
File diff suppressed because it is too large
Load Diff
79
app/operations/layer-modes/pika-layer-modes.h
Normal file
79
app/operations/layer-modes/pika-layer-modes.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pika-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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_LAYER_MODES_H__
|
||||
#define __PIKA_LAYER_MODES_H__
|
||||
|
||||
|
||||
void pika_layer_modes_init (void);
|
||||
void pika_layer_modes_exit (void);
|
||||
|
||||
gboolean pika_layer_mode_is_legacy (PikaLayerMode mode);
|
||||
|
||||
gboolean pika_layer_mode_is_blend_space_mutable (PikaLayerMode mode);
|
||||
gboolean pika_layer_mode_is_composite_space_mutable (PikaLayerMode mode);
|
||||
gboolean pika_layer_mode_is_composite_mode_mutable (PikaLayerMode mode);
|
||||
|
||||
gboolean pika_layer_mode_is_subtractive (PikaLayerMode mode);
|
||||
gboolean pika_layer_mode_is_alpha_only (PikaLayerMode mode);
|
||||
gboolean pika_layer_mode_is_trivial (PikaLayerMode mode);
|
||||
|
||||
PikaLayerColorSpace pika_layer_mode_get_blend_space (PikaLayerMode mode);
|
||||
PikaLayerColorSpace pika_layer_mode_get_composite_space (PikaLayerMode mode);
|
||||
PikaLayerCompositeMode pika_layer_mode_get_composite_mode (PikaLayerMode mode);
|
||||
PikaLayerCompositeMode pika_layer_mode_get_paint_composite_mode (PikaLayerMode mode);
|
||||
|
||||
const gchar * pika_layer_mode_get_operation_name (PikaLayerMode mode);
|
||||
GeglOperation * pika_layer_mode_get_operation (PikaLayerMode mode);
|
||||
|
||||
PikaLayerModeFunc pika_layer_mode_get_function (PikaLayerMode mode);
|
||||
PikaLayerModeBlendFunc pika_layer_mode_get_blend_function (PikaLayerMode mode);
|
||||
|
||||
PikaLayerModeContext pika_layer_mode_get_context (PikaLayerMode mode);
|
||||
|
||||
PikaLayerMode * pika_layer_mode_get_context_array (PikaLayerMode mode,
|
||||
PikaLayerModeContext context,
|
||||
gint *n_modes);
|
||||
|
||||
PikaLayerModeGroup pika_layer_mode_get_group (PikaLayerMode mode);
|
||||
|
||||
const PikaLayerMode * pika_layer_mode_get_group_array (PikaLayerModeGroup group,
|
||||
gint *n_modes);
|
||||
|
||||
gboolean pika_layer_mode_get_for_group (PikaLayerMode old_mode,
|
||||
PikaLayerModeGroup new_group,
|
||||
PikaLayerMode *new_mode);
|
||||
|
||||
const Babl * pika_layer_mode_get_format (PikaLayerMode mode,
|
||||
PikaLayerColorSpace blend_space,
|
||||
PikaLayerColorSpace composite_space,
|
||||
PikaLayerCompositeMode composite_mode,
|
||||
const Babl *preferred_format);
|
||||
|
||||
PikaLayerCompositeRegion pika_layer_mode_get_included_region (PikaLayerMode mode,
|
||||
PikaLayerCompositeMode composite_mode);
|
||||
|
||||
|
||||
#endif /* __PIKA_LAYER_MODES_H__ */
|
192
app/operations/layer-modes/pikaoperationantierase.c
Normal file
192
app/operations/layer-modes/pikaoperationantierase.c
Normal file
@ -0,0 +1,192 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationantierase.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationantierase.h"
|
||||
|
||||
|
||||
|
||||
static gboolean pika_operation_anti_erase_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
static PikaLayerCompositeRegion pika_operation_anti_erase_get_affected_region (PikaOperationLayerMode *layer_mode);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationAntiErase, pika_operation_anti_erase,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_anti_erase_class_init (PikaOperationAntiEraseClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:anti-erase",
|
||||
"description", "PIKA anti erase mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_anti_erase_process;
|
||||
layer_mode_class->get_affected_region = pika_operation_anti_erase_get_affected_region;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_anti_erase_init (PikaOperationAntiErase *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_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)
|
||||
{
|
||||
PikaOperationLayerMode *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->composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_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 PIKA_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 PIKA_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 PIKA_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 PikaLayerCompositeRegion
|
||||
pika_operation_anti_erase_get_affected_region (PikaOperationLayerMode *layer_mode)
|
||||
{
|
||||
return PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
57
app/operations/layer-modes/pikaoperationantierase.h
Normal file
57
app/operations/layer-modes/pikaoperationantierase.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationantierase.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_ANTI_ERASE_H__
|
||||
#define __PIKA_OPERATION_ANTI_ERASE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_ANTI_ERASE (pika_operation_anti_erase_get_type ())
|
||||
#define PIKA_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_ANTI_ERASE, PikaOperationAntiErase))
|
||||
#define PIKA_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_ANTI_ERASE, PikaOperationAntiEraseClass))
|
||||
#define PIKA_IS_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_ANTI_ERASE))
|
||||
#define PIKA_IS_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_ANTI_ERASE))
|
||||
#define PIKA_OPERATION_ANTI_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_ANTI_ERASE, PikaOperationAntiEraseClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationAntiErase PikaOperationAntiErase;
|
||||
typedef struct _PikaOperationAntiEraseClass PikaOperationAntiEraseClass;
|
||||
|
||||
struct _PikaOperationAntiErase
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationAntiEraseClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_anti_erase_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_ANTI_ERASE_H__ */
|
240
app/operations/layer-modes/pikaoperationbehind.c
Normal file
240
app/operations/layer-modes/pikaoperationbehind.c
Normal file
@ -0,0 +1,240 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationbehind.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationbehind.h"
|
||||
|
||||
|
||||
|
||||
static gboolean pika_operation_behind_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationBehind, pika_operation_behind,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_behind_class_init (PikaOperationBehindClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:behind",
|
||||
"description", "PIKA behind mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_behind_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_behind_init (PikaOperationBehind *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_behind_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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->composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_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 PIKA_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 PIKA_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 PIKA_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;
|
||||
}
|
57
app/operations/layer-modes/pikaoperationbehind.h
Normal file
57
app/operations/layer-modes/pikaoperationbehind.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationbehind.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_BEHIND_H__
|
||||
#define __PIKA_OPERATION_BEHIND_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_BEHIND (pika_operation_behind_get_type ())
|
||||
#define PIKA_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_BEHIND, PikaOperationBehind))
|
||||
#define PIKA_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_BEHIND, PikaOperationBehindClass))
|
||||
#define PIKA_IS_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_BEHIND))
|
||||
#define PIKA_IS_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_BEHIND))
|
||||
#define PIKA_OPERATION_BEHIND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_BEHIND, PikaOperationBehindClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationBehind PikaOperationBehind;
|
||||
typedef struct _PikaOperationBehindClass PikaOperationBehindClass;
|
||||
|
||||
struct _PikaOperationBehind
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationBehindClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_behind_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_BEHIND_H__ */
|
179
app/operations/layer-modes/pikaoperationdissolve.c
Normal file
179
app/operations/layer-modes/pikaoperationdissolve.c
Normal file
@ -0,0 +1,179 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdissolve.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationdissolve.h"
|
||||
|
||||
|
||||
#define RANDOM_TABLE_SIZE 4096
|
||||
|
||||
|
||||
static gboolean pika_operation_dissolve_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
static PikaLayerCompositeRegion pika_operation_dissolve_get_affected_region (PikaOperationLayerMode *layer_mode);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationDissolve, pika_operation_dissolve,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static gint32 random_table[RANDOM_TABLE_SIZE];
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_dissolve_class_init (PikaOperationDissolveClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
GRand *gr;
|
||||
gint i;
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:dissolve",
|
||||
"description", "PIKA dissolve mode operation",
|
||||
"categories", "compositors",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_dissolve_process;
|
||||
layer_mode_class->get_affected_region = pika_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
|
||||
pika_operation_dissolve_init (PikaOperationDissolve *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_dissolve_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *result,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
|
||||
/* The offset can be negative. I could just abs() the result, but we
|
||||
* probably prefer to use different indexes of the table when possible for
|
||||
* nicer randomization, so let's cycle the modulo so that -1 is the last
|
||||
* table index.
|
||||
*/
|
||||
gr = g_rand_new_with_seed (random_table[((y % RANDOM_TABLE_SIZE) + RANDOM_TABLE_SIZE) % 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->composite_mode == PIKA_LAYER_COMPOSITE_UNION ||
|
||||
layer_mode->composite_mode == PIKA_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->composite_mode == PIKA_LAYER_COMPOSITE_UNION ||
|
||||
layer_mode->composite_mode == PIKA_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 PikaLayerCompositeRegion
|
||||
pika_operation_dissolve_get_affected_region (PikaOperationLayerMode *layer_mode)
|
||||
{
|
||||
return PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
57
app/operations/layer-modes/pikaoperationdissolve.h
Normal file
57
app/operations/layer-modes/pikaoperationdissolve.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationdissolve.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_DISSOLVE_H__
|
||||
#define __PIKA_OPERATION_DISSOLVE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_DISSOLVE (pika_operation_dissolve_get_type ())
|
||||
#define PIKA_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_DISSOLVE, PikaOperationDissolve))
|
||||
#define PIKA_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_DISSOLVE, PikaOperationDissolveClass))
|
||||
#define PIKA_IS_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_DISSOLVE))
|
||||
#define PIKA_IS_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_DISSOLVE))
|
||||
#define PIKA_OPERATION_DISSOLVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_DISSOLVE, PikaOperationDissolveClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationDissolve PikaOperationDissolve;
|
||||
typedef struct _PikaOperationDissolveClass PikaOperationDissolveClass;
|
||||
|
||||
struct _PikaOperationDissolveClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
struct _PikaOperationDissolve
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_dissolve_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_DISSOLVE_H__ */
|
218
app/operations/layer-modes/pikaoperationerase.c
Normal file
218
app/operations/layer-modes/pikaoperationerase.c
Normal file
@ -0,0 +1,218 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationerase.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationerase.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_erase_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationErase, pika_operation_erase,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_erase_class_init (PikaOperationEraseClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:erase",
|
||||
"description", "PIKA erase mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_erase_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_erase_init (PikaOperationErase *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_erase_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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->composite_mode)
|
||||
{
|
||||
case PIKA_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 PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
case PIKA_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 PIKA_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 PIKA_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;
|
||||
}
|
57
app/operations/layer-modes/pikaoperationerase.h
Normal file
57
app/operations/layer-modes/pikaoperationerase.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationerase.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_ERASE_H__
|
||||
#define __PIKA_OPERATION_ERASE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_ERASE (pika_operation_erase_get_type ())
|
||||
#define PIKA_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_ERASE, PikaOperationErase))
|
||||
#define PIKA_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_ERASE, PikaOperationEraseClass))
|
||||
#define PIKA_IS_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_ERASE))
|
||||
#define PIKA_IS_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_ERASE))
|
||||
#define PIKA_OPERATION_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_ERASE, PikaOperationEraseClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationErase PikaOperationErase;
|
||||
typedef struct _PikaOperationEraseClass PikaOperationEraseClass;
|
||||
|
||||
struct _PikaOperationErase
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationEraseClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_erase_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_ERASE_MODE_H__ */
|
1240
app/operations/layer-modes/pikaoperationlayermode-blend.c
Normal file
1240
app/operations/layer-modes/pikaoperationlayermode-blend.c
Normal file
File diff suppressed because it is too large
Load Diff
204
app/operations/layer-modes/pikaoperationlayermode-blend.h
Normal file
204
app/operations/layer-modes/pikaoperationlayermode-blend.h
Normal file
@ -0,0 +1,204 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode-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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_LAYER_MODE_BLEND_H__
|
||||
#define __PIKA_OPERATION_LAYER_MODE_BLEND_H__
|
||||
|
||||
|
||||
/* nonsubtractive blend functions */
|
||||
|
||||
void pika_operation_layer_mode_blend_addition (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_burn (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_darken_only (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_difference (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_divide (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_dodge (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_exclusion (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_grain_extract (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_grain_merge (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hard_mix (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hardlight (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hsl_color (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hsv_hue (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hsv_saturation (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_hsv_value (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lch_chroma (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lch_color (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lch_hue (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lch_lightness (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_lighten_only (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_linear_burn (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_linear_light (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_luma_darken_only (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_luma_lighten_only (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_luminance (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_multiply (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_overlay (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_pin_light (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_screen (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_softlight (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_subtract (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
void pika_operation_layer_mode_blend_vivid_light (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
|
||||
|
||||
/* subtractive blend functions */
|
||||
|
||||
void pika_operation_layer_mode_blend_color_erase (GeglOperation *operation,
|
||||
const gfloat *in,
|
||||
const gfloat *layer,
|
||||
gfloat *comp,
|
||||
gint samples);
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_LAYER_MODE_BLEND_H__ */
|
@ -0,0 +1,109 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode-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 <https://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 "pikaoperationlayermode-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
|
||||
pika_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)
|
||||
{
|
||||
pika_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 */
|
438
app/operations/layer-modes/pikaoperationlayermode-composite.c
Normal file
438
app/operations/layer-modes/pikaoperationlayermode-composite.c
Normal file
@ -0,0 +1,438 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode-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 <https://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 "pikaoperationlayermode-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
|
||||
pika_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
|
||||
pika_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
|
||||
pika_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
|
||||
pika_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
|
||||
pika_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
|
||||
pika_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
|
||||
pika_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
|
||||
pika_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++;
|
||||
}
|
||||
}
|
102
app/operations/layer-modes/pikaoperationlayermode-composite.h
Normal file
102
app/operations/layer-modes/pikaoperationlayermode-composite.h
Normal file
@ -0,0 +1,102 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode-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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_LAYER_MODE_COMPOSITE_H__
|
||||
#define __PIKA_OPERATION_LAYER_MODE_COMPOSITE_H__
|
||||
|
||||
|
||||
void pika_operation_layer_mode_composite_union (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
void pika_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 pika_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 pika_operation_layer_mode_composite_intersection (const gfloat *in,
|
||||
const gfloat *layer,
|
||||
const gfloat *comp,
|
||||
const gfloat *mask,
|
||||
gfloat opacity,
|
||||
gfloat *out,
|
||||
gint samples);
|
||||
|
||||
void pika_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 pika_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 pika_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 pika_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 pika_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 /* __PIKA_OPERATION_LAYER_MODE_COMPOSITE_H__ */
|
960
app/operations/layer-modes/pikaoperationlayermode.c
Normal file
960
app/operations/layer-modes/pikaoperationlayermode.c
Normal file
@ -0,0 +1,960 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pika-layer-modes.h"
|
||||
#include "pikaoperationlayermode.h"
|
||||
#include "pikaoperationlayermode-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 PIKA_COMPOSITE_BLEND_MAX_SAMPLES ((1 << 18) /* 256 KiB */ / \
|
||||
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 PIKA_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 pika_operation_layer_mode_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_operation_layer_mode_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_operation_layer_mode_prepare (GeglOperation *operation);
|
||||
static GeglRectangle pika_operation_layer_mode_get_bounding_box (GeglOperation *operation);
|
||||
static gboolean pika_operation_layer_mode_parent_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
|
||||
static gboolean pika_operation_layer_mode_process (GeglOperation *operation,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
static gboolean pika_operation_layer_mode_real_parent_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
static gboolean pika_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);
|
||||
|
||||
static void pika_operation_layer_mode_cache_fishes (PikaOperationLayerMode *op,
|
||||
const Babl *preferred_format);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationLayerMode, pika_operation_layer_mode,
|
||||
GEGL_TYPE_OPERATION_POINT_COMPOSER3)
|
||||
|
||||
#define parent_class pika_operation_layer_mode_parent_class
|
||||
|
||||
static CompositeFunc composite_union = pika_operation_layer_mode_composite_union;
|
||||
static CompositeFunc composite_clip_to_backdrop = pika_operation_layer_mode_composite_clip_to_backdrop;
|
||||
static CompositeFunc composite_clip_to_layer = pika_operation_layer_mode_composite_clip_to_layer;
|
||||
static CompositeFunc composite_intersection = pika_operation_layer_mode_composite_intersection;
|
||||
|
||||
static CompositeFunc composite_union_sub = pika_operation_layer_mode_composite_union_sub;
|
||||
static CompositeFunc composite_clip_to_backdrop_sub = pika_operation_layer_mode_composite_clip_to_backdrop_sub;
|
||||
static CompositeFunc composite_clip_to_layer_sub = pika_operation_layer_mode_composite_clip_to_layer_sub;
|
||||
static CompositeFunc composite_intersection_sub = pika_operation_layer_mode_composite_intersection_sub;
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_class_init (PikaOperationLayerModeClass *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", "pika:layer-mode", NULL);
|
||||
|
||||
object_class->set_property = pika_operation_layer_mode_set_property;
|
||||
object_class->get_property = pika_operation_layer_mode_get_property;
|
||||
|
||||
operation_class->prepare = pika_operation_layer_mode_prepare;
|
||||
operation_class->get_bounding_box = pika_operation_layer_mode_get_bounding_box;
|
||||
operation_class->process = pika_operation_layer_mode_parent_process;
|
||||
|
||||
point_composer3_class->process = pika_operation_layer_mode_process;
|
||||
|
||||
klass->parent_process = pika_operation_layer_mode_real_parent_process;
|
||||
klass->process = pika_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,
|
||||
PIKA_TYPE_LAYER_MODE,
|
||||
PIKA_LAYER_MODE_NORMAL,
|
||||
PIKA_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,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_BLEND_SPACE,
|
||||
g_param_spec_enum ("blend-space",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_LAYER_COLOR_SPACE,
|
||||
PIKA_LAYER_COLOR_SPACE_RGB_LINEAR,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
|
||||
g_object_class_install_property (object_class, PROP_COMPOSITE_SPACE,
|
||||
g_param_spec_enum ("composite-space",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_LAYER_COLOR_SPACE,
|
||||
PIKA_LAYER_COLOR_SPACE_RGB_LINEAR,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_COMPOSITE_MODE,
|
||||
g_param_spec_enum ("composite-mode",
|
||||
NULL, NULL,
|
||||
PIKA_TYPE_LAYER_COMPOSITE_MODE,
|
||||
PIKA_LAYER_COMPOSITE_UNION,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
|
||||
#if COMPILE_SSE2_INTRINISICS
|
||||
if (pika_cpu_accel_get_support () & PIKA_CPU_ACCEL_X86_SSE2)
|
||||
composite_clip_to_backdrop = pika_operation_layer_mode_composite_clip_to_backdrop_sse2;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_init (PikaOperationLayerMode *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationLayerMode *self = PIKA_OPERATION_LAYER_MODE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_LAYER_MODE:
|
||||
self->layer_mode = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_OPACITY:
|
||||
self->prop_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->prop_composite_mode = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaOperationLayerMode *self = PIKA_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->prop_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->prop_composite_mode);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_prepare (GeglOperation *operation)
|
||||
{
|
||||
PikaOperationLayerMode *self = PIKA_OPERATION_LAYER_MODE (operation);
|
||||
const GeglRectangle *input_extent;
|
||||
const GeglRectangle *mask_extent;
|
||||
const Babl *preferred_format;
|
||||
const Babl *format;
|
||||
|
||||
self->composite_mode = self->prop_composite_mode;
|
||||
|
||||
if (self->composite_mode == PIKA_LAYER_COMPOSITE_AUTO)
|
||||
{
|
||||
self->composite_mode =
|
||||
pika_layer_mode_get_composite_mode (self->layer_mode);
|
||||
|
||||
g_warn_if_fail (self->composite_mode != PIKA_LAYER_COMPOSITE_AUTO);
|
||||
}
|
||||
|
||||
self->function = pika_layer_mode_get_function (self->layer_mode);
|
||||
self->blend_function = pika_layer_mode_get_blend_function (self->layer_mode);
|
||||
|
||||
input_extent = gegl_operation_source_get_bounding_box (operation, "input");
|
||||
mask_extent = gegl_operation_source_get_bounding_box (operation, "aux2");
|
||||
|
||||
/* 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 (! (pika_operation_layer_mode_get_affected_region (self) &
|
||||
PIKA_LAYER_COMPOSITE_REGION_SOURCE))
|
||||
{
|
||||
self->function = process_last_node;
|
||||
}
|
||||
/* otherwise, use the original process function, but force the
|
||||
* composite mode to UNION.
|
||||
*/
|
||||
else
|
||||
{
|
||||
self->composite_mode = PIKA_LAYER_COMPOSITE_UNION;
|
||||
}
|
||||
|
||||
preferred_format = gegl_operation_get_source_format (operation, "aux");
|
||||
}
|
||||
|
||||
self->has_mask = mask_extent && ! gegl_rectangle_is_empty (mask_extent);
|
||||
|
||||
pika_operation_layer_mode_cache_fishes (self, preferred_format);
|
||||
|
||||
format = pika_layer_mode_get_format (self->layer_mode,
|
||||
self->blend_space,
|
||||
self->composite_space,
|
||||
self->composite_mode,
|
||||
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_with_space ("Y float", format));
|
||||
}
|
||||
|
||||
static GeglRectangle
|
||||
pika_operation_layer_mode_get_bounding_box (GeglOperation *op)
|
||||
{
|
||||
PikaOperationLayerMode *self = (gpointer) op;
|
||||
GeglRectangle *in_rect;
|
||||
GeglRectangle *aux_rect;
|
||||
GeglRectangle *aux2_rect;
|
||||
GeglRectangle src_rect = {};
|
||||
GeglRectangle dst_rect = {};
|
||||
GeglRectangle result;
|
||||
PikaLayerCompositeRegion included_region;
|
||||
|
||||
in_rect = gegl_operation_source_get_bounding_box (op, "input");
|
||||
aux_rect = gegl_operation_source_get_bounding_box (op, "aux");
|
||||
aux2_rect = gegl_operation_source_get_bounding_box (op, "aux2");
|
||||
|
||||
if (in_rect)
|
||||
dst_rect = *in_rect;
|
||||
|
||||
if (aux_rect)
|
||||
{
|
||||
src_rect = *aux_rect;
|
||||
|
||||
if (aux2_rect)
|
||||
gegl_rectangle_intersect (&src_rect, &src_rect, aux2_rect);
|
||||
}
|
||||
|
||||
if (self->is_last_node)
|
||||
{
|
||||
included_region = PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
included_region = pika_layer_mode_get_included_region (self->layer_mode,
|
||||
self->composite_mode);
|
||||
}
|
||||
|
||||
if (self->prop_opacity == 0.0)
|
||||
included_region &= ~PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
|
||||
gegl_rectangle_intersect (&result, &src_rect, &dst_rect);
|
||||
|
||||
if (included_region & PIKA_LAYER_COMPOSITE_REGION_SOURCE)
|
||||
gegl_rectangle_bounding_box (&result, &result, &src_rect);
|
||||
|
||||
if (included_region & PIKA_LAYER_COMPOSITE_REGION_DESTINATION)
|
||||
gegl_rectangle_bounding_box (&result, &result, &dst_rect);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_layer_mode_parent_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *point = PIKA_OPERATION_LAYER_MODE (operation);
|
||||
|
||||
point->opacity = point->prop_opacity;
|
||||
|
||||
/* if we have a mask, but it's not included in the output, pretend the
|
||||
* opacity is 0, so that we don't composite 'aux' over 'input' as if there
|
||||
* was no mask.
|
||||
*/
|
||||
if (point->has_mask)
|
||||
{
|
||||
GObject *mask;
|
||||
gboolean has_mask;
|
||||
|
||||
/* get the raw value. this does not increase the reference count. */
|
||||
mask = gegl_operation_context_get_object (context, "aux2");
|
||||
|
||||
/* disregard 'mask' if it's not included in the roi. */
|
||||
has_mask =
|
||||
mask &&
|
||||
gegl_rectangle_intersect (NULL,
|
||||
gegl_buffer_get_extent (GEGL_BUFFER (mask)),
|
||||
result);
|
||||
|
||||
if (! has_mask)
|
||||
point->opacity = 0.0;
|
||||
}
|
||||
|
||||
return PIKA_OPERATION_LAYER_MODE_GET_CLASS (point)->parent_process (
|
||||
operation, context, output_prop, result, level);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_layer_mode_process (GeglOperation *operation,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
return ((PikaOperationLayerMode *) operation)->function (
|
||||
operation, in, layer, mask, out, samples, roi, level);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_layer_mode_real_parent_process (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *point = PIKA_OPERATION_LAYER_MODE (operation);
|
||||
GObject *input;
|
||||
GObject *aux;
|
||||
gboolean has_input;
|
||||
gboolean has_aux;
|
||||
PikaLayerCompositeRegion 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 = PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
included_region = pika_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 & PIKA_LAYER_COMPOSITE_REGION_SOURCE))
|
||||
{
|
||||
PikaLayerCompositeRegion affected_region;
|
||||
|
||||
affected_region =
|
||||
pika_operation_layer_mode_get_affected_region (point);
|
||||
|
||||
/* ... and the op doesn't otherwise affect 'aux', or changes its
|
||||
* alpha ...
|
||||
*/
|
||||
if (! (affected_region & PIKA_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 & PIKA_LAYER_COMPOSITE_REGION_DESTINATION)
|
||||
{
|
||||
PikaLayerCompositeRegion affected_region;
|
||||
|
||||
affected_region =
|
||||
pika_operation_layer_mode_get_affected_region (point);
|
||||
|
||||
/* ... and the op doesn't otherwise affect 'input' ... */
|
||||
if (! (affected_region & PIKA_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
|
||||
pika_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)
|
||||
{
|
||||
PikaOperationLayerMode *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;
|
||||
PikaLayerColorSpace blend_space = layer_mode->blend_space;
|
||||
PikaLayerColorSpace composite_space = layer_mode->composite_space;
|
||||
PikaLayerCompositeMode composite_mode = layer_mode->composite_mode;
|
||||
PikaLayerModeBlendFunc 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 PIKA_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 > PIKA_COMPOSITE_BLEND_MAX_SAMPLES)
|
||||
{
|
||||
pika_operation_layer_mode_real_process (operation,
|
||||
in, layer, mask, out,
|
||||
PIKA_COMPOSITE_BLEND_MAX_SAMPLES,
|
||||
roi, level);
|
||||
|
||||
in += 4 * PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
layer += 4 * PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
if (mask)
|
||||
mask += PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
out += 4 * PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
|
||||
samples -= PIKA_COMPOSITE_BLEND_MAX_SAMPLES;
|
||||
}
|
||||
|
||||
composite_needs_in_color =
|
||||
composite_mode == PIKA_LAYER_COMPOSITE_UNION ||
|
||||
composite_mode == PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP;
|
||||
|
||||
blend_in = in;
|
||||
blend_layer = layer;
|
||||
blend_out = out;
|
||||
|
||||
if (blend_space != PIKA_LAYER_COLOR_SPACE_AUTO)
|
||||
{
|
||||
pika_assert (composite_space >= 1 && composite_space < 4);
|
||||
pika_assert (blend_space >= 1 && blend_space < 4);
|
||||
|
||||
/* Make sure the cache is set up from the start as the
|
||||
* operation's prepare() method may have not been run yet.
|
||||
*/
|
||||
pika_operation_layer_mode_cache_fishes (layer_mode, NULL);
|
||||
composite_to_blend_fish = layer_mode->space_fish [composite_space - 1]
|
||||
[blend_space - 1];
|
||||
|
||||
blend_to_composite_fish = layer_mode->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
|
||||
* PIKA_COMPOSITE_BLEND_SPLIT_THRESHOLD consecutive unblended
|
||||
* samples.
|
||||
*/
|
||||
|
||||
first = i;
|
||||
i += 4;
|
||||
last = i;
|
||||
|
||||
while (i < end && i - last < 4 * PIKA_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 (operation, 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 (operation, blend_in, blend_layer, blend_out, samples);
|
||||
}
|
||||
|
||||
if (! pika_layer_mode_is_subtractive (layer_mode->layer_mode))
|
||||
{
|
||||
switch (composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
composite_union (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
composite_clip_to_backdrop (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
composite_clip_to_layer (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
composite_intersection (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
composite_union_sub (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
composite_clip_to_backdrop_sub (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER:
|
||||
composite_clip_to_layer_sub (in, layer, blend_out, mask, opacity,
|
||||
out, samples);
|
||||
break;
|
||||
|
||||
case PIKA_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 = PIKA_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;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_layer_mode_cache_fishes (PikaOperationLayerMode *op,
|
||||
const Babl *preferred_format)
|
||||
{
|
||||
const Babl *format;
|
||||
|
||||
if (! preferred_format)
|
||||
{
|
||||
const GeglRectangle *input_extent;
|
||||
|
||||
input_extent = gegl_operation_source_get_bounding_box (GEGL_OPERATION (op), "input");
|
||||
|
||||
if (input_extent && ! gegl_rectangle_is_empty (input_extent))
|
||||
preferred_format = gegl_operation_get_source_format (GEGL_OPERATION (op), "input");
|
||||
else
|
||||
preferred_format = gegl_operation_get_source_format (GEGL_OPERATION (op), "aux");
|
||||
}
|
||||
|
||||
format = pika_layer_mode_get_format (op->layer_mode,
|
||||
op->blend_space,
|
||||
op->composite_space,
|
||||
op->composite_mode,
|
||||
preferred_format);
|
||||
if (op->cached_fish_format != format)
|
||||
{
|
||||
op->cached_fish_format = format;
|
||||
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_RGB_LINEAR - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] =
|
||||
babl_fish (babl_format_with_space ("RGBA float", format),
|
||||
babl_format_with_space ("R'G'B'A float", format));
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_RGB_LINEAR - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_LAB - 1] =
|
||||
babl_fish (babl_format_with_space ("RGBA float", format),
|
||||
babl_format_with_space ("CIE Lab alpha float", format));
|
||||
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_RGB_LINEAR - 1] =
|
||||
babl_fish (babl_format_with_space("R'G'B'A float", format),
|
||||
babl_format_with_space ( "RGBA float", format));
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_LAB - 1] =
|
||||
babl_fish (babl_format_with_space("R'G'B'A float", format),
|
||||
babl_format_with_space ( "CIE Lab alpha float", format));
|
||||
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_LAB - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_RGB_LINEAR - 1] =
|
||||
babl_fish (babl_format_with_space("CIE Lab alpha float", format),
|
||||
babl_format_with_space ( "RGBA float", format));
|
||||
op->space_fish
|
||||
/* from */ [PIKA_LAYER_COLOR_SPACE_LAB - 1]
|
||||
/* to */ [PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] =
|
||||
babl_fish (babl_format_with_space("CIE Lab alpha float", format),
|
||||
babl_format_with_space ( "R'G'B'A float", format));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
||||
PikaLayerCompositeRegion
|
||||
pika_operation_layer_mode_get_affected_region (PikaOperationLayerMode *layer_mode)
|
||||
{
|
||||
PikaOperationLayerModeClass *klass;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_OPERATION_LAYER_MODE (layer_mode),
|
||||
PIKA_LAYER_COMPOSITE_REGION_INTERSECTION);
|
||||
|
||||
klass = PIKA_OPERATION_LAYER_MODE_GET_CLASS (layer_mode);
|
||||
|
||||
if (klass->get_affected_region)
|
||||
return klass->get_affected_region (layer_mode);
|
||||
|
||||
return PIKA_LAYER_COMPOSITE_REGION_INTERSECTION;
|
||||
}
|
95
app/operations/layer-modes/pikaoperationlayermode.h
Normal file
95
app/operations/layer-modes/pikaoperationlayermode.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationlayermode.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_LAYER_MODE_H__
|
||||
#define __PIKA_OPERATION_LAYER_MODE_H__
|
||||
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_LAYER_MODE (pika_operation_layer_mode_get_type ())
|
||||
#define PIKA_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_LAYER_MODE, PikaOperationLayerMode))
|
||||
#define PIKA_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_LAYER_MODE, PikaOperationLayerModeClass))
|
||||
#define PIKA_IS_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_LAYER_MODE))
|
||||
#define PIKA_IS_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_LAYER_MODE))
|
||||
#define PIKA_OPERATION_LAYER_MODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_LAYER_MODE, PikaOperationLayerModeClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationLayerModeClass PikaOperationLayerModeClass;
|
||||
|
||||
struct _PikaOperationLayerMode
|
||||
{
|
||||
GeglOperationPointComposer3 parent_instance;
|
||||
|
||||
PikaLayerMode layer_mode;
|
||||
gdouble opacity;
|
||||
PikaLayerColorSpace blend_space;
|
||||
PikaLayerColorSpace composite_space;
|
||||
PikaLayerCompositeMode composite_mode;
|
||||
const Babl *cached_fish_format;
|
||||
const Babl *space_fish[3 /* from */][3 /* to */];
|
||||
|
||||
gdouble prop_opacity;
|
||||
PikaLayerCompositeMode prop_composite_mode;
|
||||
|
||||
PikaLayerModeFunc function;
|
||||
PikaLayerModeBlendFunc blend_function;
|
||||
gboolean is_last_node;
|
||||
gboolean has_mask;
|
||||
};
|
||||
|
||||
struct _PikaOperationLayerModeClass
|
||||
{
|
||||
GeglOperationPointComposer3Class parent_class;
|
||||
|
||||
/* virtual functions */
|
||||
gboolean (* parent_process) (GeglOperation *operation,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
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.
|
||||
*/
|
||||
PikaLayerCompositeRegion (* get_affected_region) (PikaOperationLayerMode *layer_mode);
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_layer_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaLayerCompositeRegion pika_operation_layer_mode_get_affected_region (PikaOperationLayerMode *layer_mode);
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_LAYER_MODE_H__ */
|
247
app/operations/layer-modes/pikaoperationmerge.c
Normal file
247
app/operations/layer-modes/pikaoperationmerge.c
Normal file
@ -0,0 +1,247 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationmerge.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationmerge.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_merge_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationMerge, pika_operation_merge,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_merge_class_init (PikaOperationMergeClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:merge",
|
||||
"description", "PIKA merge mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_merge_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_merge_init (PikaOperationMerge *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_merge_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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->composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_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 PIKA_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 PIKA_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 PIKA_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;
|
||||
}
|
58
app/operations/layer-modes/pikaoperationmerge.h
Normal file
58
app/operations/layer-modes/pikaoperationmerge.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationmerge.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_MERGE_H__
|
||||
#define __PIKA_OPERATION_MERGE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_MERGE (pika_operation_merge_get_type ())
|
||||
#define PIKA_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_MERGE, PikaOperationMerge))
|
||||
#define PIKA_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_MERGE, PikaOperationMergeClass))
|
||||
#define PIKA_IS_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_MERGE))
|
||||
#define PIKA_IS_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_MERGE))
|
||||
#define PIKA_OPERATION_MERGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_MERGE, PikaOperationMergeClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationMerge PikaOperationMerge;
|
||||
typedef struct _PikaOperationMergeClass PikaOperationMergeClass;
|
||||
|
||||
struct _PikaOperationMerge
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationMergeClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_merge_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_MERGE_H__ */
|
268
app/operations/layer-modes/pikaoperationnormal-sse2.c
Normal file
268
app/operations/layer-modes/pikaoperationnormal-sse2.c
Normal file
@ -0,0 +1,268 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationnormal-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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "operations/operations-types.h"
|
||||
|
||||
#include "pikaoperationnormal.h"
|
||||
|
||||
|
||||
#if COMPILE_SSE2_INTRINISICS
|
||||
|
||||
/* SSE2 */
|
||||
#include <emmintrin.h>
|
||||
|
||||
|
||||
gboolean
|
||||
pika_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 pika_operation_normal_process (op,
|
||||
in_p, layer_p, mask_p, out_p,
|
||||
samples, roi, level);
|
||||
}
|
||||
else
|
||||
{
|
||||
PikaOperationLayerMode *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->composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_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 PIKA_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 PIKA_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 PIKA_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 */
|
264
app/operations/layer-modes/pikaoperationnormal-sse4.c
Normal file
264
app/operations/layer-modes/pikaoperationnormal-sse4.c
Normal file
@ -0,0 +1,264 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationnormalmode-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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "operations/operations-types.h"
|
||||
|
||||
#include "pikaoperationnormal.h"
|
||||
|
||||
|
||||
#if COMPILE_SSE4_1_INTRINISICS
|
||||
|
||||
/* SSE4 */
|
||||
#include <smmintrin.h>
|
||||
|
||||
|
||||
gboolean
|
||||
pika_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 pika_operation_normal_process (op,
|
||||
in_p, layer_p, mask_p, out_p,
|
||||
samples, roi, level);
|
||||
}
|
||||
else
|
||||
{
|
||||
PikaOperationLayerMode *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->composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_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 PIKA_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 PIKA_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 PIKA_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 */
|
270
app/operations/layer-modes/pikaoperationnormal.c
Normal file
270
app/operations/layer-modes/pikaoperationnormal.c
Normal file
@ -0,0 +1,270 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationnormalmode.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationnormal.h"
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationNormal, pika_operation_normal,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
"<gegl>"
|
||||
"<node operation='pika: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
|
||||
pika_operation_normal_class_init (PikaOperationNormalClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:normal",
|
||||
"description", "PIKA normal mode operation",
|
||||
"reference-image", "normal-mode.png",
|
||||
"reference-composition", reference_xml,
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_normal_process;
|
||||
|
||||
#if COMPILE_SSE2_INTRINISICS
|
||||
if (pika_cpu_accel_get_support() & PIKA_CPU_ACCEL_X86_SSE2)
|
||||
layer_mode_class->process = pika_operation_normal_process_sse2;
|
||||
#endif /* COMPILE_SSE2_INTRINISICS */
|
||||
|
||||
#if COMPILE_SSE4_1_INTRINISICS
|
||||
if (pika_cpu_accel_get_support() & PIKA_CPU_ACCEL_X86_SSE4_1)
|
||||
layer_mode_class->process = pika_operation_normal_process_sse4;
|
||||
#endif /* COMPILE_SSE4_1_INTRINISICS */
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_normal_init (PikaOperationNormal *self)
|
||||
{
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_operation_normal_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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->composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_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 PIKA_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 PIKA_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 PIKA_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;
|
||||
}
|
95
app/operations/layer-modes/pikaoperationnormal.h
Normal file
95
app/operations/layer-modes/pikaoperationnormal.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationnormal.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_NORMAL_H__
|
||||
#define __PIKA_OPERATION_NORMAL_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_NORMAL (pika_operation_normal_get_type ())
|
||||
#define PIKA_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_NORMAL, PikaOperationNormal))
|
||||
#define PIKA_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_NORMAL, PikaOperationNormalClass))
|
||||
#define PIKA_IS_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_NORMAL))
|
||||
#define PIKA_IS_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_NORMAL))
|
||||
#define PIKA_OPERATION_NORMAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_NORMAL, PikaOperationNormalClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationNormal PikaOperationNormal;
|
||||
typedef struct _PikaOperationNormalClass PikaOperationNormalClass;
|
||||
|
||||
struct _PikaOperationNormal
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationNormalClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_normal_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
/* protected */
|
||||
|
||||
gboolean pika_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 pika_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 pika_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 /* __PIKA_OPERATION_NORMAL_H__ */
|
59
app/operations/layer-modes/pikaoperationpassthrough.c
Normal file
59
app/operations/layer-modes/pikaoperationpassthrough.c
Normal file
@ -0,0 +1,59 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationpassthrough.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationpassthrough.h"
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationPassThrough, pika_operation_pass_through,
|
||||
PIKA_TYPE_OPERATION_REPLACE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_pass_through_class_init (PikaOperationPassThroughClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:pass-through",
|
||||
"description", "PIKA pass through mode operation",
|
||||
NULL);
|
||||
|
||||
/* 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
|
||||
pika_operation_pass_through_init (PikaOperationPassThrough *self)
|
||||
{
|
||||
}
|
58
app/operations/layer-modes/pikaoperationpassthrough.h
Normal file
58
app/operations/layer-modes/pikaoperationpassthrough.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationpassthrough.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_PASS_THROUGH_H__
|
||||
#define __PIKA_OPERATION_PASS_THROUGH_H__
|
||||
|
||||
|
||||
#include "pikaoperationreplace.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_PASS_THROUGH (pika_operation_pass_through_get_type ())
|
||||
#define PIKA_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_PASS_THROUGH, PikaOperationPassThrough))
|
||||
#define PIKA_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_PASS_THROUGH, PikaOperationPassThroughClass))
|
||||
#define PIKA_IS_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_PASS_THROUGH))
|
||||
#define PIKA_IS_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_PASS_THROUGH))
|
||||
#define PIKA_OPERATION_PASS_THROUGH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_PASS_THROUGH, PikaOperationPassThroughClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationPassThrough PikaOperationPassThrough;
|
||||
typedef struct _PikaOperationPassThroughClass PikaOperationPassThroughClass;
|
||||
|
||||
struct _PikaOperationPassThrough
|
||||
{
|
||||
PikaOperationReplace parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationPassThroughClass
|
||||
{
|
||||
PikaOperationReplaceClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_pass_through_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_PASS_THROUGH_H__ */
|
351
app/operations/layer-modes/pikaoperationreplace.c
Normal file
351
app/operations/layer-modes/pikaoperationreplace.c
Normal file
@ -0,0 +1,351 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationreplace.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pika-layer-modes.h"
|
||||
#include "pikaoperationreplace.h"
|
||||
|
||||
|
||||
static GeglRectangle pika_operation_replace_get_bounding_box (GeglOperation *op);
|
||||
|
||||
static gboolean pika_operation_replace_parent_process (GeglOperation *op,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level);
|
||||
static gboolean pika_operation_replace_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
static PikaLayerCompositeRegion pika_operation_replace_get_affected_region (PikaOperationLayerMode *layer_mode);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationReplace, pika_operation_replace,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
#define parent_class pika_operation_replace_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_replace_class_init (PikaOperationReplaceClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:replace",
|
||||
"description", "PIKA replace mode operation",
|
||||
NULL);
|
||||
|
||||
operation_class->get_bounding_box = pika_operation_replace_get_bounding_box;
|
||||
|
||||
layer_mode_class->parent_process = pika_operation_replace_parent_process;
|
||||
layer_mode_class->process = pika_operation_replace_process;
|
||||
layer_mode_class->get_affected_region = pika_operation_replace_get_affected_region;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_replace_init (PikaOperationReplace *self)
|
||||
{
|
||||
}
|
||||
|
||||
static GeglRectangle
|
||||
pika_operation_replace_get_bounding_box (GeglOperation *op)
|
||||
{
|
||||
PikaOperationLayerMode *self = (gpointer) op;
|
||||
GeglRectangle *in_rect;
|
||||
GeglRectangle *aux_rect;
|
||||
GeglRectangle *aux2_rect;
|
||||
GeglRectangle src_rect = {};
|
||||
GeglRectangle dst_rect = {};
|
||||
GeglRectangle result;
|
||||
PikaLayerCompositeRegion included_region;
|
||||
|
||||
in_rect = gegl_operation_source_get_bounding_box (op, "input");
|
||||
aux_rect = gegl_operation_source_get_bounding_box (op, "aux");
|
||||
aux2_rect = gegl_operation_source_get_bounding_box (op, "aux2");
|
||||
|
||||
if (in_rect)
|
||||
dst_rect = *in_rect;
|
||||
|
||||
if (aux_rect)
|
||||
{
|
||||
src_rect = *aux_rect;
|
||||
|
||||
if (aux2_rect)
|
||||
gegl_rectangle_intersect (&src_rect, &src_rect, aux2_rect);
|
||||
}
|
||||
|
||||
if (self->is_last_node)
|
||||
{
|
||||
included_region = PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
included_region = pika_layer_mode_get_included_region (self->layer_mode,
|
||||
self->composite_mode);
|
||||
}
|
||||
|
||||
if (self->prop_opacity == 0.0)
|
||||
included_region &= ~PIKA_LAYER_COMPOSITE_REGION_SOURCE;
|
||||
else if (self->prop_opacity == 1.0 && ! aux2_rect)
|
||||
included_region &= ~PIKA_LAYER_COMPOSITE_REGION_DESTINATION;
|
||||
|
||||
gegl_rectangle_intersect (&result, &src_rect, &dst_rect);
|
||||
|
||||
if (included_region & PIKA_LAYER_COMPOSITE_REGION_SOURCE)
|
||||
gegl_rectangle_bounding_box (&result, &result, &src_rect);
|
||||
|
||||
if (included_region & PIKA_LAYER_COMPOSITE_REGION_DESTINATION)
|
||||
gegl_rectangle_bounding_box (&result, &result, &dst_rect);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_replace_parent_process (GeglOperation *op,
|
||||
GeglOperationContext *context,
|
||||
const gchar *output_prop,
|
||||
const GeglRectangle *result,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *layer_mode = (gpointer) op;
|
||||
PikaLayerCompositeRegion included_region;
|
||||
|
||||
included_region = pika_layer_mode_get_included_region
|
||||
(layer_mode->layer_mode, layer_mode->composite_mode);
|
||||
|
||||
/* if the layer's opacity is 100%, it has no mask, and its composite mode
|
||||
* contains "aux" (the latter should always be the case in practice,
|
||||
* currently,) we can just pass "aux" directly as output.
|
||||
*/
|
||||
if (layer_mode->opacity == 1.0 &&
|
||||
! gegl_operation_context_get_object (context, "aux2") &&
|
||||
(included_region & PIKA_LAYER_COMPOSITE_REGION_SOURCE))
|
||||
{
|
||||
GObject *aux;
|
||||
|
||||
aux = gegl_operation_context_get_object (context, "aux");
|
||||
|
||||
gegl_operation_context_set_object (context, "output", aux);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
/* the opposite case, where the opacity is 0%, is handled by
|
||||
* PikaOperationLayerMode.
|
||||
*/
|
||||
else if (layer_mode->opacity == 0.0)
|
||||
{
|
||||
}
|
||||
/* if both buffers are included in the result, and if both of them have the
|
||||
* same content -- i.e., if they share the same storage, same alignment, and
|
||||
* same abyss (or if the abyss is irrelevant) -- we can just pass either of
|
||||
* them directly as output.
|
||||
*/
|
||||
else if (included_region == PIKA_LAYER_COMPOSITE_REGION_UNION)
|
||||
{
|
||||
GObject *input;
|
||||
GObject *aux;
|
||||
|
||||
input = gegl_operation_context_get_object (context, "input");
|
||||
aux = gegl_operation_context_get_object (context, "aux");
|
||||
|
||||
if (input && aux &&
|
||||
gegl_buffer_share_storage (GEGL_BUFFER (input), GEGL_BUFFER (aux)))
|
||||
{
|
||||
gint input_shift_x;
|
||||
gint input_shift_y;
|
||||
gint aux_shift_x;
|
||||
gint aux_shift_y;
|
||||
|
||||
g_object_get (input,
|
||||
"shift-x", &input_shift_x,
|
||||
"shift-y", &input_shift_y,
|
||||
NULL);
|
||||
g_object_get (aux,
|
||||
"shift-x", &aux_shift_x,
|
||||
"shift-y", &aux_shift_y,
|
||||
NULL);
|
||||
|
||||
if (input_shift_x == aux_shift_x && input_shift_y == aux_shift_y)
|
||||
{
|
||||
const GeglRectangle *input_abyss;
|
||||
const GeglRectangle *aux_abyss;
|
||||
|
||||
input_abyss = gegl_buffer_get_abyss (GEGL_BUFFER (input));
|
||||
aux_abyss = gegl_buffer_get_abyss (GEGL_BUFFER (aux));
|
||||
|
||||
if (gegl_rectangle_equal (input_abyss, aux_abyss) ||
|
||||
(gegl_rectangle_contains (input_abyss, result) &&
|
||||
gegl_rectangle_contains (aux_abyss, result)))
|
||||
{
|
||||
gegl_operation_context_set_object (context, "output", input);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PIKA_OPERATION_LAYER_MODE_CLASS (parent_class)->parent_process (
|
||||
op, context, output_prop, result, level);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_replace_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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->composite_mode)
|
||||
{
|
||||
case PIKA_LAYER_COMPOSITE_UNION:
|
||||
case PIKA_LAYER_COMPOSITE_AUTO:
|
||||
while (samples--)
|
||||
{
|
||||
gfloat opacity_value = opacity;
|
||||
gfloat new_alpha;
|
||||
gfloat ratio;
|
||||
gint b;
|
||||
|
||||
if (has_mask)
|
||||
opacity_value *= *mask;
|
||||
|
||||
new_alpha = (layer[ALPHA] - in[ALPHA]) * opacity_value + in[ALPHA];
|
||||
|
||||
ratio = opacity_value;
|
||||
|
||||
if (new_alpha)
|
||||
ratio *= layer[ALPHA] / new_alpha;
|
||||
|
||||
for (b = RED; b < ALPHA; b++)
|
||||
out[b] = (layer[b] - in[b]) * ratio + in[b];
|
||||
|
||||
out[ALPHA] = new_alpha;
|
||||
|
||||
in += 4;
|
||||
layer += 4;
|
||||
out += 4;
|
||||
|
||||
if (has_mask)
|
||||
mask++;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_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 PIKA_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;
|
||||
|
||||
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 PIKA_LAYER_COMPOSITE_INTERSECTION:
|
||||
memset (out, 0, 4 * samples * sizeof (gfloat));
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static PikaLayerCompositeRegion
|
||||
pika_operation_replace_get_affected_region (PikaOperationLayerMode *layer_mode)
|
||||
{
|
||||
PikaLayerCompositeRegion affected_region = PIKA_LAYER_COMPOSITE_REGION_INTERSECTION;
|
||||
|
||||
if (layer_mode->prop_opacity != 0.0)
|
||||
affected_region |= PIKA_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;
|
||||
}
|
57
app/operations/layer-modes/pikaoperationreplace.h
Normal file
57
app/operations/layer-modes/pikaoperationreplace.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationreplace.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_REPLACE_H__
|
||||
#define __PIKA_OPERATION_REPLACE_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_REPLACE (pika_operation_replace_get_type ())
|
||||
#define PIKA_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_REPLACE, PikaOperationReplace))
|
||||
#define PIKA_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_REPLACE, PikaOperationReplaceClass))
|
||||
#define PIKA_IS_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_REPLACE))
|
||||
#define PIKA_IS_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_REPLACE))
|
||||
#define PIKA_OPERATION_REPLACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_REPLACE, PikaOperationReplaceClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationReplace PikaOperationReplace;
|
||||
typedef struct _PikaOperationReplaceClass PikaOperationReplaceClass;
|
||||
|
||||
struct _PikaOperationReplace
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationReplaceClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_replace_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_REPLACE_H__ */
|
217
app/operations/layer-modes/pikaoperationsplit.c
Normal file
217
app/operations/layer-modes/pikaoperationsplit.c
Normal file
@ -0,0 +1,217 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationsplit.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl-plugin.h>
|
||||
|
||||
#include "../operations-types.h"
|
||||
|
||||
#include "pikaoperationsplit.h"
|
||||
|
||||
|
||||
static gboolean pika_operation_split_process (GeglOperation *op,
|
||||
void *in,
|
||||
void *layer,
|
||||
void *mask,
|
||||
void *out,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaOperationSplit, pika_operation_split,
|
||||
PIKA_TYPE_OPERATION_LAYER_MODE)
|
||||
|
||||
|
||||
static void
|
||||
pika_operation_split_class_init (PikaOperationSplitClass *klass)
|
||||
{
|
||||
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
||||
PikaOperationLayerModeClass *layer_mode_class = PIKA_OPERATION_LAYER_MODE_CLASS (klass);
|
||||
|
||||
gegl_operation_class_set_keys (operation_class,
|
||||
"name", "pika:split",
|
||||
"description", "PIKA split mode operation",
|
||||
NULL);
|
||||
|
||||
layer_mode_class->process = pika_operation_split_process;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_operation_split_init (PikaOperationSplit *self)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_operation_split_process (GeglOperation *op,
|
||||
void *in_p,
|
||||
void *layer_p,
|
||||
void *mask_p,
|
||||
void *out_p,
|
||||
glong samples,
|
||||
const GeglRectangle *roi,
|
||||
gint level)
|
||||
{
|
||||
PikaOperationLayerMode *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->composite_mode)
|
||||
{
|
||||
case PIKA_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 PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP:
|
||||
case PIKA_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 PIKA_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 PIKA_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;
|
||||
}
|
58
app/operations/layer-modes/pikaoperationsplit.h
Normal file
58
app/operations/layer-modes/pikaoperationsplit.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaoperationsplit.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_OPERATION_SPLIT_H__
|
||||
#define __PIKA_OPERATION_SPLIT_H__
|
||||
|
||||
|
||||
#include "pikaoperationlayermode.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_OPERATION_SPLIT (pika_operation_split_get_type ())
|
||||
#define PIKA_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OPERATION_SPLIT, PikaOperationSplit))
|
||||
#define PIKA_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OPERATION_SPLIT, PikaOperationSplitClass))
|
||||
#define PIKA_IS_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OPERATION_SPLIT))
|
||||
#define PIKA_IS_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OPERATION_SPLIT))
|
||||
#define PIKA_OPERATION_SPLIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OPERATION_SPLIT, PikaOperationSplitClass))
|
||||
|
||||
|
||||
typedef struct _PikaOperationSplit PikaOperationSplit;
|
||||
typedef struct _PikaOperationSplitClass PikaOperationSplitClass;
|
||||
|
||||
struct _PikaOperationSplit
|
||||
{
|
||||
PikaOperationLayerMode parent_instance;
|
||||
};
|
||||
|
||||
struct _PikaOperationSplitClass
|
||||
{
|
||||
PikaOperationLayerModeClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_operation_split_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_OPERATION_SPLIT_H__ */
|
Reference in New Issue
Block a user