2008-10-13 04:26:27 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2008-10-31 07:18:35 +08:00
|
|
|
* gimpoperationpointlayermode.c
|
2008-10-13 04:26:27 +08:00
|
|
|
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
|
2008-10-25 22:16:22 +08:00
|
|
|
* Copyright (C) 2008 Martin Nordholts <martinn@svn.gnome.org>
|
2008-10-13 04:26:27 +08:00
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2008-10-13 04:26:27 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2008-10-13 04:26:27 +08:00
|
|
|
* (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
|
2009-01-18 06:28:01 +08:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2008-10-13 04:26:27 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2008-10-25 22:16:22 +08:00
|
|
|
#include <gegl-plugin.h>
|
2008-10-13 04:26:27 +08:00
|
|
|
|
2008-10-30 05:25:35 +08:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
|
|
|
|
2009-02-21 23:06:49 +08:00
|
|
|
#include "gimp-gegl-types.h"
|
2008-10-13 04:26:27 +08:00
|
|
|
|
2008-11-01 05:02:26 +08:00
|
|
|
#include "paint-funcs/paint-funcs.h"
|
|
|
|
|
2008-10-25 22:16:22 +08:00
|
|
|
#include "gimpoperationpointlayermode.h"
|
2008-10-13 04:26:27 +08:00
|
|
|
|
|
|
|
|
2008-11-01 15:36:03 +08:00
|
|
|
/* The size of the area of which an evenly transparent Dissolve layer
|
|
|
|
* repeats its dissolve pattern
|
|
|
|
*/
|
|
|
|
#define DISSOLVE_REPEAT_WIDTH 400
|
|
|
|
#define DISSOLVE_REPEAT_HEIGHT 300
|
|
|
|
|
|
|
|
#define DISSOLVE_SEED 737893334
|
|
|
|
|
|
|
|
|
2008-11-01 17:52:58 +08:00
|
|
|
#define R (RED)
|
|
|
|
#define G (GREEN)
|
|
|
|
#define B (BLUE)
|
|
|
|
#define A (ALPHA)
|
2009-08-02 17:07:40 +08:00
|
|
|
#define L 0
|
|
|
|
#define C 1
|
|
|
|
#define H 2
|
2008-11-01 17:52:58 +08:00
|
|
|
#define inA (in[A])
|
|
|
|
#define inCa (in[c])
|
|
|
|
#define inC (in[A] ? in[c] / in[A] : 0.0)
|
|
|
|
#define layA (lay[A])
|
|
|
|
#define layCa (lay[c])
|
|
|
|
#define layC (lay[A] ? lay[c] / lay[A] : 0.0)
|
|
|
|
#define outCa (out[c])
|
|
|
|
#define outA (out[A])
|
|
|
|
#define outC (out[A] ? out[c] / out[A] : 0.0)
|
|
|
|
#define newCa (new[c])
|
2008-10-26 22:39:08 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
#define EACH_CHANNEL(expr) \
|
|
|
|
for (c = RED; c < ALPHA; c++) \
|
|
|
|
{ \
|
|
|
|
expr; \
|
|
|
|
}
|
|
|
|
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-25 21:29:55 +08:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
PROP_BLEND_MODE
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-10-25 22:16:22 +08:00
|
|
|
static void gimp_operation_point_layer_mode_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_operation_point_layer_mode_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
2008-10-25 21:29:55 +08:00
|
|
|
|
2008-10-25 22:16:22 +08:00
|
|
|
static void gimp_operation_point_layer_mode_prepare (GeglOperation *operation);
|
|
|
|
static gboolean gimp_operation_point_layer_mode_process (GeglOperation *operation,
|
|
|
|
void *in_buf,
|
|
|
|
void *aux_buf,
|
|
|
|
void *out_buf,
|
|
|
|
glong samples,
|
|
|
|
const GeglRectangle *roi);
|
2008-10-13 04:26:27 +08:00
|
|
|
|
|
|
|
|
2008-10-25 22:16:22 +08:00
|
|
|
G_DEFINE_TYPE (GimpOperationPointLayerMode, gimp_operation_point_layer_mode,
|
2008-10-25 21:29:55 +08:00
|
|
|
GEGL_TYPE_OPERATION_POINT_COMPOSER)
|
2008-10-13 04:26:27 +08:00
|
|
|
|
|
|
|
|
2008-11-01 15:36:03 +08:00
|
|
|
static guint32 dissolve_lut[DISSOLVE_REPEAT_WIDTH * DISSOLVE_REPEAT_HEIGHT];
|
|
|
|
|
|
|
|
|
2008-10-13 04:26:27 +08:00
|
|
|
static void
|
2008-10-25 22:16:22 +08:00
|
|
|
gimp_operation_point_layer_mode_class_init (GimpOperationPointLayerModeClass *klass)
|
2008-10-13 04:26:27 +08:00
|
|
|
{
|
2008-10-25 21:29:55 +08:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2008-10-13 04:26:27 +08:00
|
|
|
GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
|
|
|
|
GeglOperationPointComposerClass *point_class = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
|
2008-11-01 15:36:03 +08:00
|
|
|
GRand *rand = g_rand_new_with_seed (DISSOLVE_SEED);
|
|
|
|
int i;
|
2008-10-13 04:26:27 +08:00
|
|
|
|
2008-10-26 05:02:46 +08:00
|
|
|
object_class->set_property = gimp_operation_point_layer_mode_set_property;
|
|
|
|
object_class->get_property = gimp_operation_point_layer_mode_get_property;
|
2008-10-25 21:29:55 +08:00
|
|
|
|
2008-10-26 05:02:46 +08:00
|
|
|
operation_class->name = "gimp:point-layer-mode";
|
|
|
|
operation_class->description = "GIMP point layer mode operation";
|
2008-10-25 21:29:55 +08:00
|
|
|
operation_class->categories = "compositors";
|
2008-10-13 04:26:27 +08:00
|
|
|
|
2008-10-26 05:02:46 +08:00
|
|
|
operation_class->prepare = gimp_operation_point_layer_mode_prepare;
|
2008-10-25 17:47:09 +08:00
|
|
|
|
2008-10-26 05:02:46 +08:00
|
|
|
point_class->process = gimp_operation_point_layer_mode_process;
|
2008-10-25 21:29:55 +08:00
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_BLEND_MODE,
|
|
|
|
g_param_spec_enum ("blend-mode", NULL, NULL,
|
|
|
|
GIMP_TYPE_LAYER_MODE_EFFECTS,
|
|
|
|
GIMP_NORMAL_MODE,
|
|
|
|
GIMP_PARAM_READWRITE));
|
2008-11-01 15:36:03 +08:00
|
|
|
|
|
|
|
for (i = 0; i < DISSOLVE_REPEAT_WIDTH * DISSOLVE_REPEAT_HEIGHT; i++)
|
|
|
|
dissolve_lut[i] = g_rand_int (rand);
|
2008-10-13 04:26:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-10-25 22:16:22 +08:00
|
|
|
gimp_operation_point_layer_mode_init (GimpOperationPointLayerMode *self)
|
2008-10-13 04:26:27 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-10-25 21:29:55 +08:00
|
|
|
static void
|
2008-10-25 22:16:22 +08:00
|
|
|
gimp_operation_point_layer_mode_set_property (GObject *object,
|
2008-10-26 05:02:46 +08:00
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
2008-10-25 21:29:55 +08:00
|
|
|
{
|
2008-10-25 22:16:22 +08:00
|
|
|
GimpOperationPointLayerMode *self = GIMP_OPERATION_POINT_LAYER_MODE (object);
|
2008-10-25 21:29:55 +08:00
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_BLEND_MODE:
|
|
|
|
self->blend_mode = g_value_get_enum (value);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-10-25 22:16:22 +08:00
|
|
|
gimp_operation_point_layer_mode_get_property (GObject *object,
|
2008-10-26 05:02:46 +08:00
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
2008-10-25 21:29:55 +08:00
|
|
|
{
|
2008-10-25 22:16:22 +08:00
|
|
|
GimpOperationPointLayerMode *self = GIMP_OPERATION_POINT_LAYER_MODE (object);
|
2008-10-25 21:29:55 +08:00
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_BLEND_MODE:
|
|
|
|
g_value_set_enum (value, self->blend_mode);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-25 17:47:09 +08:00
|
|
|
static void
|
2008-10-25 22:16:22 +08:00
|
|
|
gimp_operation_point_layer_mode_prepare (GeglOperation *operation)
|
2008-10-25 17:47:09 +08:00
|
|
|
{
|
2009-01-21 04:11:23 +08:00
|
|
|
Babl *format = babl_format ("RaGaBaA float");
|
2008-10-25 17:47:09 +08:00
|
|
|
|
|
|
|
gegl_operation_set_format (operation, "input", format);
|
|
|
|
gegl_operation_set_format (operation, "output", format);
|
|
|
|
gegl_operation_set_format (operation, "aux", format);
|
|
|
|
}
|
|
|
|
|
2008-10-30 05:25:35 +08:00
|
|
|
static void
|
2009-08-02 17:07:40 +08:00
|
|
|
gimp_operation_point_layer_mode_get_new_color_lchab (GimpLayerModeEffects blend_mode,
|
|
|
|
const gfloat *in,
|
|
|
|
const gfloat *lay,
|
|
|
|
gfloat *new)
|
2008-10-30 05:25:35 +08:00
|
|
|
{
|
2009-08-02 17:07:40 +08:00
|
|
|
float in_lchab[3];
|
|
|
|
float lay_lchab[3];
|
|
|
|
float new_lchab[3];
|
|
|
|
Babl *ragabaa_to_lchab = babl_fish (babl_format ("RaGaBaA float"),
|
|
|
|
babl_format ("CIE LCH(ab) float"));
|
|
|
|
Babl *lchab_to_ragabaa = babl_fish (babl_format ("CIE LCH(ab) float"),
|
|
|
|
babl_format ("RaGaBaA float"));
|
2008-10-30 05:25:35 +08:00
|
|
|
|
2009-08-02 17:07:40 +08:00
|
|
|
babl_process (ragabaa_to_lchab, (void*)in, (void*)in_lchab, 1);
|
|
|
|
babl_process (ragabaa_to_lchab, (void*)lay, (void*)lay_lchab, 1);
|
2008-10-30 05:25:35 +08:00
|
|
|
|
|
|
|
switch (blend_mode)
|
|
|
|
{
|
|
|
|
case GIMP_HUE_MODE:
|
2009-08-02 17:07:40 +08:00
|
|
|
new_lchab[L] = in_lchab[L];
|
|
|
|
new_lchab[C] = in_lchab[C];
|
|
|
|
new_lchab[H] = lay_lchab[H];
|
2008-10-30 05:25:35 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_SATURATION_MODE:
|
2009-08-02 17:07:40 +08:00
|
|
|
new_lchab[L] = in_lchab[L];
|
|
|
|
new_lchab[C] = lay_lchab[C];
|
|
|
|
new_lchab[H] = in_lchab[H];
|
2008-10-30 05:25:35 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_COLOR_MODE:
|
2009-08-02 17:07:40 +08:00
|
|
|
new_lchab[L] = in_lchab[L];
|
|
|
|
new_lchab[C] = lay_lchab[C];
|
|
|
|
new_lchab[H] = lay_lchab[H];
|
2008-10-30 05:25:35 +08:00
|
|
|
break;
|
|
|
|
|
2009-08-02 17:07:40 +08:00
|
|
|
case GIMP_VALUE_MODE: /* GIMP_LIGHTNESS_MODE */
|
|
|
|
new_lchab[L] = lay_lchab[L];
|
|
|
|
new_lchab[C] = in_lchab[C];
|
|
|
|
new_lchab[H] = in_lchab[H];
|
2008-10-30 05:25:35 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-08-02 17:07:40 +08:00
|
|
|
babl_process (lchab_to_ragabaa, new_lchab, new, 1);
|
2008-10-30 05:25:35 +08:00
|
|
|
}
|
|
|
|
|
2008-11-01 05:02:26 +08:00
|
|
|
static void
|
|
|
|
gimp_operation_point_layer_mode_get_color_erase_color (const gfloat *in,
|
|
|
|
const gfloat *lay,
|
|
|
|
gfloat *out)
|
|
|
|
{
|
|
|
|
GimpRGB inRGB;
|
|
|
|
GimpRGB layRGB;
|
|
|
|
|
|
|
|
if (inA <= 0.0)
|
|
|
|
gimp_rgba_set (&inRGB, 0.0, 0.0, 0.0, inA);
|
|
|
|
else
|
|
|
|
gimp_rgba_set (&inRGB, in[R] / inA, in[G] / inA, in[B] / inA, inA);
|
|
|
|
|
|
|
|
if (layA <= 0.0)
|
|
|
|
gimp_rgba_set (&layRGB, 0.0, 0.0, 0.0, layA);
|
|
|
|
else
|
|
|
|
gimp_rgba_set (&layRGB, lay[R] / layA, lay[G] / layA, lay[B] / layA, layA);
|
|
|
|
|
|
|
|
paint_funcs_color_erase_helper (&inRGB, &layRGB);
|
|
|
|
|
|
|
|
out[A] = inRGB.a;
|
|
|
|
out[R] = inRGB.r * out[A];
|
|
|
|
out[G] = inRGB.g * out[A];
|
|
|
|
out[B] = inRGB.b * out[A];
|
|
|
|
}
|
|
|
|
|
2008-10-13 04:26:27 +08:00
|
|
|
static gboolean
|
2008-10-25 22:16:22 +08:00
|
|
|
gimp_operation_point_layer_mode_process (GeglOperation *operation,
|
2008-10-26 05:02:46 +08:00
|
|
|
void *in_buf,
|
|
|
|
void *aux_buf,
|
|
|
|
void *out_buf,
|
|
|
|
glong samples,
|
|
|
|
const GeglRectangle *roi)
|
2008-10-13 04:26:27 +08:00
|
|
|
{
|
2008-10-31 07:37:45 +08:00
|
|
|
GimpOperationPointLayerMode *self = GIMP_OPERATION_POINT_LAYER_MODE (operation);
|
|
|
|
GimpLayerModeEffects blend_mode = self->blend_mode;
|
|
|
|
|
|
|
|
gfloat *in = in_buf; /* composite of layers below */
|
|
|
|
gfloat *lay = aux_buf; /* layer */
|
|
|
|
gfloat *out = out_buf; /* resulting composite */
|
|
|
|
glong sample = samples;
|
|
|
|
gint c = 0;
|
2008-11-01 15:36:03 +08:00
|
|
|
gint x = 0;
|
|
|
|
gint y = 0;
|
2008-10-31 07:37:45 +08:00
|
|
|
gfloat new[3] = { 0.0, 0.0, 0.0 };
|
|
|
|
|
2008-10-31 07:18:35 +08:00
|
|
|
while (sample--)
|
2008-10-25 21:29:55 +08:00
|
|
|
{
|
2008-10-31 07:37:45 +08:00
|
|
|
switch (blend_mode)
|
2008-10-25 21:29:55 +08:00
|
|
|
{
|
2008-11-01 05:02:26 +08:00
|
|
|
case GIMP_ERASE_MODE:
|
|
|
|
case GIMP_ANTI_ERASE_MODE:
|
|
|
|
case GIMP_COLOR_ERASE_MODE:
|
|
|
|
case GIMP_REPLACE_MODE:
|
|
|
|
case GIMP_DISSOLVE_MODE:
|
|
|
|
/* These modes handle alpha themselves */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Porter-Duff model for the rest */
|
|
|
|
outA = layA + inA - layA * inA;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (blend_mode)
|
|
|
|
{
|
|
|
|
case GIMP_ERASE_MODE:
|
|
|
|
/* Eraser mode */
|
|
|
|
outA = inA - inA * layA;
|
|
|
|
if (inA <= 0.0)
|
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = 0.0)
|
2008-11-01 05:02:26 +08:00
|
|
|
else
|
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:52:58 +08:00
|
|
|
outCa = inC * outA);
|
2008-11-01 05:02:26 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ANTI_ERASE_MODE:
|
|
|
|
/* Eraser mode */
|
|
|
|
outA = inA + (1 - inA) * layA;
|
|
|
|
if (inA <= 0.0)
|
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = 0.0)
|
2008-11-01 05:02:26 +08:00
|
|
|
else
|
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:52:58 +08:00
|
|
|
outCa = inC * outA);
|
2008-11-01 05:02:26 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_COLOR_ERASE_MODE:
|
|
|
|
/* Paint mode */
|
|
|
|
gimp_operation_point_layer_mode_get_color_erase_color (in, lay, out);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_REPLACE_MODE:
|
|
|
|
/* Filter fade mode */
|
|
|
|
outA = layA;
|
|
|
|
EACH_CHANNEL(
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = layCa);
|
2008-11-01 05:02:26 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_DISSOLVE_MODE:
|
2008-11-01 15:36:03 +08:00
|
|
|
/* The layer pixel has layA probability of being composited
|
|
|
|
* with 100% opacity, else not all
|
2008-11-01 05:02:26 +08:00
|
|
|
*/
|
2008-11-01 15:36:03 +08:00
|
|
|
x = (roi->x + sample - (sample / roi->width) * roi->width) % DISSOLVE_REPEAT_WIDTH;
|
|
|
|
y = (roi->y + sample / roi->width) % DISSOLVE_REPEAT_HEIGHT;
|
2008-11-01 05:02:26 +08:00
|
|
|
|
2008-11-01 15:36:03 +08:00
|
|
|
if (layA * G_MAXUINT32 >= dissolve_lut[y * DISSOLVE_REPEAT_WIDTH + x])
|
2008-11-01 05:02:26 +08:00
|
|
|
{
|
|
|
|
outA = 1.0;
|
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:52:58 +08:00
|
|
|
outCa = layC);
|
2008-11-01 05:02:26 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outA = inA;
|
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = inCa);
|
2008-11-01 05:02:26 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_NORMAL_MODE:
|
2008-10-26 06:44:19 +08:00
|
|
|
/* Porter-Duff A over B */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = layCa + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-25 21:29:55 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_BEHIND_MODE:
|
2008-10-26 06:44:19 +08:00
|
|
|
/* Porter-Duff B over A */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = inCa + layCa * (1 - inA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_MULTIPLY_MODE:
|
2008-10-26 06:44:19 +08:00
|
|
|
/* SVG 1.2 multiply */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = layCa * inCa + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_SCREEN_MODE:
|
2008-10-26 06:44:19 +08:00
|
|
|
/* SVG 1.2 screen */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = layCa + inCa - layCa * inCa);
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_DIFFERENCE_MODE:
|
2008-10-26 06:44:19 +08:00
|
|
|
/* SVG 1.2 difference */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = inCa + layCa - 2 * MIN (layCa * inA, inCa * layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_DARKEN_ONLY_MODE:
|
2008-10-26 06:44:19 +08:00
|
|
|
/* SVG 1.2 darken */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = MIN (layCa * inA, inCa * layA) + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_LIGHTEN_ONLY_MODE:
|
2008-10-26 06:44:19 +08:00
|
|
|
/* SVG 1.2 lighten */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = MAX (layCa * inA, inCa * layA) + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-27 01:43:46 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_OVERLAY_MODE:
|
2008-10-27 01:43:46 +08:00
|
|
|
/* SVG 1.2 overlay */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
if (2 * inCa < inA)
|
|
|
|
outCa = 2 * layCa * inCa + layCa * (1 - inA) + inCa * (1 - layA);
|
2008-10-27 01:43:46 +08:00
|
|
|
else
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = layA * inA - 2 * (inA - inCa) * (layA - layCa) + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_DODGE_MODE:
|
2008-10-26 21:48:19 +08:00
|
|
|
/* SVG 1.2 color-dodge */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
if (layCa * inA + inCa * layA >= layA * inA)
|
|
|
|
outCa = layA * inA + layCa * (1 - inA) + inCa * (1 - layA);
|
2008-10-27 01:43:46 +08:00
|
|
|
else
|
2008-11-01 17:52:58 +08:00
|
|
|
outCa = inCa * layA / (1 - layC) + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-25 21:29:55 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_BURN_MODE:
|
2008-10-26 21:48:19 +08:00
|
|
|
/* SVG 1.2 color-burn */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
if (layCa * inA + inCa * layA <= layA * inA)
|
|
|
|
outCa = layCa * (1 - inA) + inCa * (1 - layA);
|
2008-10-27 01:43:46 +08:00
|
|
|
else
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = layA * (layCa * inA + inCa * layA - layA * inA) / layCa + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_HARDLIGHT_MODE:
|
2008-10-26 06:44:19 +08:00
|
|
|
/* SVG 1.2 hard-light */
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
if (2 * layCa < layA)
|
|
|
|
outCa = 2 * layCa * inCa + layCa * (1 - inA) + inCa * (1 - layA);
|
2008-10-27 01:43:46 +08:00
|
|
|
else
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = layA * inA - 2 * (inA - inCa) * (layA - layCa) + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_SOFTLIGHT_MODE:
|
Reuse the blending formula from the legacy Soft light. (Actually the
* app/gegl/gimpoperationpointlayermode.c
(gimp_operation_point_layer_mode_process): Reuse the blending
formula from the legacy Soft light. (Actually the formula comes
from legacy Overlay but legacy Overlay and Soft light blends
pixels exactly the same.) I hereby declare the porting of the
layer modes to this GEGL operation complete. Summary:
Completely works the same:
Normal, Dissolve, Behind, Color Erase, Erase, Anti Erase
Works the same for 100% opaque layers:
Lighten only, Screen, Dodge, Addition, Darken only, Multiply,
Dodge, Soft light, Hard light, Difference, Subtract, Grain
extract, Grain merge, Divide, Hue, Saturation, Color, Value
Works different but similar:
Overlay now uses the SVG 1.2 overlay formula which is different
but similar to legacy Overlay
Replace needs to be externally masked to not replace too much,
but that is outside the scope of the layer mode porting.
svn path=/trunk/; revision=27541
2008-11-04 07:00:40 +08:00
|
|
|
/* Custom SVG 1.2:
|
|
|
|
*
|
|
|
|
* f(Sc, Dc) = Dc * (Dc + (2 * Sc * (1 - Dc)))
|
2008-11-01 20:23:14 +08:00
|
|
|
*/
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
Reuse the blending formula from the legacy Soft light. (Actually the
* app/gegl/gimpoperationpointlayermode.c
(gimp_operation_point_layer_mode_process): Reuse the blending
formula from the legacy Soft light. (Actually the formula comes
from legacy Overlay but legacy Overlay and Soft light blends
pixels exactly the same.) I hereby declare the porting of the
layer modes to this GEGL operation complete. Summary:
Completely works the same:
Normal, Dissolve, Behind, Color Erase, Erase, Anti Erase
Works the same for 100% opaque layers:
Lighten only, Screen, Dodge, Addition, Darken only, Multiply,
Dodge, Soft light, Hard light, Difference, Subtract, Grain
extract, Grain merge, Divide, Hue, Saturation, Color, Value
Works different but similar:
Overlay now uses the SVG 1.2 overlay formula which is different
but similar to legacy Overlay
Replace needs to be externally masked to not replace too much,
but that is outside the scope of the layer mode porting.
svn path=/trunk/; revision=27541
2008-11-04 07:00:40 +08:00
|
|
|
outCa = inCa * (layA * inC + (2 * layCa * (1 - inC))) + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_ADDITION_MODE:
|
2008-10-27 03:28:47 +08:00
|
|
|
/* Custom SVG 1.2:
|
2008-10-25 21:29:55 +08:00
|
|
|
*
|
2008-10-27 03:28:47 +08:00
|
|
|
* if Dc + Sc >= 1
|
|
|
|
* f(Sc, Dc) = 1
|
|
|
|
* otherwise
|
|
|
|
* f(Sc, Dc) = Dc + Sc
|
2008-10-25 21:29:55 +08:00
|
|
|
*/
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
if (layCa * inA + inCa * layA >= layA * inA)
|
|
|
|
outCa = layA * inA + layCa * (1 - inA) + inCa * (1 - layA);
|
2008-10-27 03:28:47 +08:00
|
|
|
else
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = inCa + layCa);
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-25 21:29:55 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_SUBTRACT_MODE:
|
2008-10-27 03:28:47 +08:00
|
|
|
/* Custom SVG 1.2:
|
|
|
|
*
|
|
|
|
* if Dc - Sc <= 0
|
|
|
|
* f(Sc, Dc) = 0
|
|
|
|
* otherwise
|
|
|
|
* f(Sc, Dc) = Dc - Sc
|
|
|
|
*/
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
if (inCa * layA - layCa * inA <= 0)
|
|
|
|
outCa = layCa * (1 - inA) + inCa * (1 - layA);
|
2008-10-27 03:28:47 +08:00
|
|
|
else
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = inCa + layCa - 2 * layCa * inA);
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_GRAIN_EXTRACT_MODE:
|
2008-10-27 04:36:25 +08:00
|
|
|
/* Custom SVG 1.2:
|
|
|
|
*
|
|
|
|
* if Dc - Sc + 0.5 >= 1
|
|
|
|
* f(Sc, Dc) = 1
|
|
|
|
* otherwise if Dc - Sc + 0.5 <= 0
|
|
|
|
* f(Sc, Dc) = 0
|
|
|
|
* otherwise
|
|
|
|
* f(Sc, Dc) = f(Sc, Dc) = Dc - Sc + 0.5
|
|
|
|
*/
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
if (inCa * layA - layCa * inA + 0.5 * layA * inA >= layA * inA)
|
|
|
|
outCa = layA * inA + layCa * (1 - inA) + inCa * (1 - layA);
|
|
|
|
else if (inCa * layA - layCa * inA + 0.5 * layA * inA <= 0)
|
|
|
|
outCa = layCa * (1 - inA) + inCa * (1 - layA);
|
2008-10-27 04:36:25 +08:00
|
|
|
else
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = inCa + layCa - 2 * layCa * inA + 0.5 * inA * layA);
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 16:39:41 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_GRAIN_MERGE_MODE:
|
2008-10-27 04:36:25 +08:00
|
|
|
/* Custom SVG 1.2:
|
|
|
|
*
|
|
|
|
* if Dc + Sc - 0.5 >= 1
|
|
|
|
* f(Sc, Dc) = 1
|
|
|
|
* otherwise if Dc + Sc - 0.5 <= 0
|
|
|
|
* f(Sc, Dc) = 0
|
|
|
|
* otherwise
|
|
|
|
* f(Sc, Dc) = f(Sc, Dc) = Dc + Sc - 0.5
|
|
|
|
*/
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
if (inCa * layA + layCa * inA - 0.5 * layA * inA >= layA * inA)
|
|
|
|
outCa = layA * inA + layCa * (1 - inA) + inCa * (1 - layA);
|
|
|
|
else if (inCa * layA + layCa * inA - 0.5 * layA * inA <= 0)
|
|
|
|
outCa = layCa * (1 - inA) + inCa * (1 - layA);
|
2008-10-27 04:36:25 +08:00
|
|
|
else
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = inCa + layCa - 0.5 * inA * layA);
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 16:39:41 +08:00
|
|
|
|
2008-10-28 15:30:25 +08:00
|
|
|
case GIMP_DIVIDE_MODE:
|
2008-10-27 04:36:25 +08:00
|
|
|
/* Custom SVG 1.2:
|
|
|
|
*
|
|
|
|
* if Dc / Sc > 1
|
|
|
|
* f(Sc, Dc) = 1
|
|
|
|
* otherwise
|
|
|
|
* f(Sc, Dc) = Dc / Sc
|
|
|
|
*/
|
2008-10-28 15:30:25 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:52:58 +08:00
|
|
|
if (layA == 0.0 || inCa / layCa > inA / layA)
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = layA * inA + layCa * (1 - inA) + inCa * (1 - layA);
|
2008-10-27 04:36:25 +08:00
|
|
|
else
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = inCa * layA * layA / layCa + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-28 15:30:25 +08:00
|
|
|
break;
|
2008-10-26 06:44:19 +08:00
|
|
|
|
2008-10-25 21:29:55 +08:00
|
|
|
case GIMP_HUE_MODE:
|
|
|
|
case GIMP_SATURATION_MODE:
|
2008-10-30 05:25:35 +08:00
|
|
|
case GIMP_COLOR_MODE:
|
2009-08-03 03:35:10 +08:00
|
|
|
case GIMP_VALUE_MODE: /* GIMP_LIGHTNESS_MODE */
|
2008-10-30 05:25:35 +08:00
|
|
|
/* Custom SVG 1.2:
|
|
|
|
*
|
|
|
|
* f(Sc, Dc) = New color
|
|
|
|
*/
|
2009-08-02 17:07:40 +08:00
|
|
|
|
|
|
|
/* FIXME: Doing this call for each pixel is very slow, we
|
|
|
|
* should make conversions on larger chunks of data
|
|
|
|
*/
|
|
|
|
gimp_operation_point_layer_mode_get_new_color_lchab (blend_mode,
|
|
|
|
in,
|
|
|
|
lay,
|
|
|
|
new);
|
2008-10-30 05:25:35 +08:00
|
|
|
EACH_CHANNEL (
|
2008-11-01 17:43:27 +08:00
|
|
|
outCa = newCa * layA * inA + layCa * (1 - inA) + inCa * (1 - layA));
|
2008-10-26 16:39:41 +08:00
|
|
|
break;
|
|
|
|
|
2008-10-25 21:29:55 +08:00
|
|
|
default:
|
|
|
|
g_error ("Unknown layer mode");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-10-26 06:44:19 +08:00
|
|
|
in += 4;
|
|
|
|
lay += 4;
|
|
|
|
out += 4;
|
2008-10-25 21:29:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
2008-10-13 04:26:27 +08:00
|
|
|
}
|