gimp/app/composite/gimp-composite.c

390 lines
14 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Gimp image compositing
* Copyright (C) 2003 Helvetix Victorinox, a pseudonym, <helvetix@gimp.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#include <glib-object.h>
#include "base/base-types.h"
#include "gimp-composite.h"
#include "gimp-composite-generic.h"
#ifdef ARCH_X86
#include "gimp-composite-mmx.h"
#include "gimp-composite-sse.h"
#endif
/*
* Details about pixel formats, bits-per-pixel alpha and non alpha
* versions of pixel formats.
*/
/*
* Report on the number of bytes a particular pixel format consumes per pixel.
*/
const guchar gimp_composite_pixel_bpp[] =
{
1, /* GIMP_PIXELFORMAT_V8 */
2, /* GIMP_PIXELFORMAT_VA8 */
3, /* GIMP_PIXELFORMAT_RGB8 */
4, /* GIMP_PIXELFORMAT_RGBA8 */
#if GIMP_COMPOSITE_16BIT
2, /* GIMP_PIXELFORMAT_V16 */
4, /* GIMP_PIXELFORMAT_VA16 */
6, /* GIMP_PIXELFORMAT_RGB16 */
8, /* GIMP_PIXELFORMAT_RGBA16 */
#endif
#if GIMP_COMPOSITE_32BIT
2, /* GIMP_PIXELFORMAT_V32 */
4, /* GIMP_PIXELFORMAT_VA32 */
6, /* GIMP_PIXELFORMAT_RGB32 */
8, /* GIMP_PIXELFORMAT_RGBA32 */
#endif
0, /* GIMP_PIXELFORMAT_ANY */
};
/*
* Report true (non-zero) if a pixel format has alpha.
*/
const guchar gimp_composite_pixel_alphap[] =
{
0, /* GIMP_PIXELFORMAT_V8 */
1, /* GIMP_PIXELFORMAT_VA8 */
0, /* GIMP_PIXELFORMAT_RGB8 */
1, /* GIMP_PIXELFORMAT_RGBA8 */
#if GIMP_COMPOSITE_16BIT
0, /* GIMP_PIXELFORMAT_V16 */
1, /* GIMP_PIXELFORMAT_VA16 */
0, /* GIMP_PIXELFORMAT_RGB16 */
1, /* GIMP_PIXELFORMAT_RGBA16 */
#endif
#if GIMP_COMPOSITE_32BIT
0, /* GIMP_PIXELFORMAT_V32 */
1, /* GIMP_PIXELFORMAT_VA32 */
0, /* GIMP_PIXELFORMAT_RGB32 */
1, /* GIMP_PIXELFORMAT_RGBA32 */
#endif
0, /* GIMP_PIXELFORMAT_UNKNOWN */
};
/*
* Convert to/from pixel formats with/without alpha.
*/
const GimpPixelFormat gimp_composite_pixel_alpha[] =
{
GIMP_PIXELFORMAT_VA8, /* GIMP_PIXELFORMAT_V8 */
GIMP_PIXELFORMAT_V8, /* GIMP_PIXELFORMAT_VA8 */
GIMP_PIXELFORMAT_RGBA8, /* GIMP_PIXELFORMAT_RGB8 */
GIMP_PIXELFORMAT_RGB8, /* GIMP_PIXELFORMAT_RGBA8 */
#if GIMP_COMPOSITE_16BIT
GIMP_PIXELFORMAT_VA16,
GIMP_PIXELFORMAT_V16,
GIMP_PIXELFORMAT_RGBA16,
GIMP_PIXELFORMAT_RGB16
#endif
#if GIMP_COMPOSITE_32BIT
GIMP_PIXELFORMAT_VA32,
GIMP_PIXELFORMAT_V32,
GIMP_PIXELFORMAT_RGBA32,
GIMP_PIXELFORMAT_RGB32
#endif
GIMP_PIXELFORMAT_ANY, /* GIMP_PIXELFORMAT_ANY */
};
/*
* XXX I don't like to put this here. I think this information,
* specific to the functions, ought to be with the function.
*/
struct GimpCompositeOperationEffects gimp_composite_operation_effects[] =
{
{ TRUE, TRUE, FALSE, }, /* GIMP_NORMAL_MODE */
{ TRUE, TRUE, FALSE, }, /* GIMP_DISSOLVE_MODE */
{ TRUE, TRUE, FALSE, }, /* GIMP_BEHIND_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_MULTIPLY_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_SCREEN_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_OVERLAY_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_DIFFERENCE_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_ADDITION_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_SUBTRACT_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_DARKEN_ONLY_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_LIGHTEN_ONLY_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_HUE_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_SATURATION_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_COLOR_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_VALUE_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_DIVIDE_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_DODGE_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_BURN_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_HARDLIGHT_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_SOFTLIGHT_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_GRAIN_EXTRACT_MODE */
{ FALSE, FALSE, FALSE, }, /* GIMP_GRAIN_MERGE_MODE */
{ TRUE, FALSE, TRUE, }, /* GIMP_COLOR_ERASE_MODE */
{ TRUE, FALSE, TRUE, }, /* GIMP_ERASE_MODE */
{ TRUE, TRUE, TRUE, }, /* GIMP_REPLACE_MODE */
{ TRUE, TRUE, FALSE, }, /* GIMP_ANTI_ERASE_MODE */
{ FALSE, FALSE, FALSE }, /* GIMP_SWAP */
{ FALSE, FALSE, FALSE }, /* GIMP_SCALE */
{ FALSE, FALSE, FALSE }, /* GIMP_CONVERT */
};
struct GimpCompositeOptions gimp_composite_options =
{
0
};
const gchar * gimp_composite_function_name[GIMP_COMPOSITE_N][GIMP_PIXELFORMAT_N][GIMP_PIXELFORMAT_N][GIMP_PIXELFORMAT_N];
void (* gimp_composite_function[GIMP_COMPOSITE_N][GIMP_PIXELFORMAT_N][GIMP_PIXELFORMAT_N][GIMP_PIXELFORMAT_N])(GimpCompositeContext *);
/**
* gimp_composite_dispatch:
* @ctx: The compositing context
*
* Given a compositing context, perform the compositing function
* dictated by the compositing context operation. There is no return
* value, all results are in the compositing context.
**/
void
gimp_composite_dispatch (GimpCompositeContext *ctx)
{
void (* function) (GimpCompositeContext *);
function = gimp_composite_function[ctx->op][ctx->pixelformat_A][ctx->pixelformat_B][ctx->pixelformat_D];
if (function)
{
if (gimp_composite_options.bits & GIMP_COMPOSITE_OPTION_VERBOSE)
{
g_print ("%s %s %s %s = %p\n",
gimp_composite_mode_astext (ctx->op),
gimp_composite_pixelformat_astext (ctx->pixelformat_A),
gimp_composite_pixelformat_astext (ctx->pixelformat_B),
gimp_composite_pixelformat_astext (ctx->pixelformat_D),
function);
}
function (ctx);
}
else
{
g_print ("gimp_composite: unsupported operation: %s %s %s %s\n",
gimp_composite_mode_astext (ctx->op),
gimp_composite_pixelformat_astext (ctx->pixelformat_A),
gimp_composite_pixelformat_astext (ctx->pixelformat_B),
gimp_composite_pixelformat_astext (ctx->pixelformat_D));
}
}
/**
* gimp_composite_context_print:
* @ctx: The context to print
*
* Print a human readable form of a GimpCompositeContext on stdout.
**/
void
gimp_composite_context_print (GimpCompositeContext *ctx)
{
g_print ("%p: op=%s\n A=%s(%d):%p\n B=%s(%d):%p\n D=%s(%d):%p\n M=%s(%d):%p\n n_pixels=%lu\n",
ctx,
gimp_composite_mode_astext (ctx->op),
gimp_composite_pixelformat_astext (ctx->pixelformat_A),
ctx->pixelformat_A, ctx->A,
gimp_composite_pixelformat_astext (ctx->pixelformat_B),
ctx->pixelformat_B, ctx->B,
gimp_composite_pixelformat_astext (ctx->pixelformat_D),
ctx->pixelformat_D, ctx->D,
gimp_composite_pixelformat_astext (ctx->pixelformat_M),
ctx->pixelformat_M, ctx->M,
ctx->n_pixels);
}
/**
* gimp_composite_mode_astext:
* @op:
*
* Given a GimpCompositeOperatin, return a string representation of the name
* of that operation.
*
* Returns: gchar *, the name
**/
const gchar *
gimp_composite_mode_astext (GimpCompositeOperation op)
{
switch (op)
{
case GIMP_COMPOSITE_NORMAL: return ("GIMP_COMPOSITE_NORMAL");
case GIMP_COMPOSITE_DISSOLVE: return ("GIMP_COMPOSITE_DISSOLVE");
case GIMP_COMPOSITE_BEHIND: return ("GIMP_COMPOSITE_BEHIND");
case GIMP_COMPOSITE_MULTIPLY: return ("GIMP_COMPOSITE_MULTIPLY");
case GIMP_COMPOSITE_SCREEN: return ("GIMP_COMPOSITE_SCREEN");
case GIMP_COMPOSITE_OVERLAY: return ("GIMP_COMPOSITE_OVERLAY");
case GIMP_COMPOSITE_DIFFERENCE: return ("GIMP_COMPOSITE_DIFFERENCE");
case GIMP_COMPOSITE_ADDITION: return ("GIMP_COMPOSITE_ADDITION");
case GIMP_COMPOSITE_SUBTRACT: return ("GIMP_COMPOSITE_SUBTRACT");
case GIMP_COMPOSITE_DARKEN: return ("GIMP_COMPOSITE_DARKEN");
case GIMP_COMPOSITE_LIGHTEN: return ("GIMP_COMPOSITE_LIGHTEN");
case GIMP_COMPOSITE_HUE: return ("GIMP_COMPOSITE_HUE");
case GIMP_COMPOSITE_SATURATION: return ("GIMP_COMPOSITE_SATURATION");
case GIMP_COMPOSITE_COLOR_ONLY: return ("GIMP_COMPOSITE_COLOR_ONLY");
case GIMP_COMPOSITE_VALUE: return ("GIMP_COMPOSITE_VALUE");
case GIMP_COMPOSITE_DIVIDE: return ("GIMP_COMPOSITE_DIVIDE");
case GIMP_COMPOSITE_DODGE: return ("GIMP_COMPOSITE_DODGE");
case GIMP_COMPOSITE_BURN: return ("GIMP_COMPOSITE_BURN");
case GIMP_COMPOSITE_HARDLIGHT: return ("GIMP_COMPOSITE_HARDLIGHT");
case GIMP_COMPOSITE_SOFTLIGHT: return ("GIMP_COMPOSITE_SOFTLIGHT");
case GIMP_COMPOSITE_GRAIN_EXTRACT: return ("GIMP_COMPOSITE_GRAIN_EXTRACT");
case GIMP_COMPOSITE_GRAIN_MERGE: return ("GIMP_COMPOSITE_GRAIN_MERGE");
case GIMP_COMPOSITE_COLOR_ERASE: return ("GIMP_COMPOSITE_COLOR_ERASE");
case GIMP_COMPOSITE_ERASE: return ("GIMP_COMPOSITE_ERASE");
case GIMP_COMPOSITE_REPLACE: return ("GIMP_COMPOSITE_REPLACE");
case GIMP_COMPOSITE_ANTI_ERASE: return ("GIMP_COMPOSITE_ANTI_ERASE");
case GIMP_COMPOSITE_BLEND: return ("GIMP_COMPOSITE_BLEND");
case GIMP_COMPOSITE_SHADE: return ("GIMP_COMPOSITE_SHADE");
case GIMP_COMPOSITE_SWAP: return ("GIMP_COMPOSITE_SWAP");
case GIMP_COMPOSITE_SCALE: return ("GIMP_COMPOSITE_SCALE");
case GIMP_COMPOSITE_CONVERT: return ("GIMP_COMPOSITE_CONVERT");
case GIMP_COMPOSITE_XOR: return ("GIMP_COMPOSITE_XOR");
default:
break;
}
return ("bad mode");
}
/**
* gimp_composite_pixelformat_astext:
* @format: The format.
*
* Given a GimpPixelFormat, return a string representation of the name
* of that format.
*
* Returns: gchar *, the name
**/
const gchar *
gimp_composite_pixelformat_astext (GimpPixelFormat format)
{
switch (format) {
case GIMP_PIXELFORMAT_V8: return ("V8");
case GIMP_PIXELFORMAT_VA8: return ("VA8");
case GIMP_PIXELFORMAT_RGB8: return ("RGB8");
case GIMP_PIXELFORMAT_RGBA8: return ("RGBA8");
#if GIMP_COMPOSITE_16BIT
case GIMP_PIXELFORMAT_V16: return ("V16");
case GIMP_PIXELFORMAT_VA16: return ("VA16");
case GIMP_PIXELFORMAT_RGB16: return ("RGB16");
case GIMP_PIXELFORMAT_RGBA16: return ("RGBA16");
#endif
#if GIMP_COMPOSITE_32BIT
case GIMP_PIXELFORMAT_V32: return ("V32");
case GIMP_PIXELFORMAT_VA32: return ("VA32");
case GIMP_PIXELFORMAT_RGB32: return ("RGB32");
case GIMP_PIXELFORMAT_RGBA32: return ("RGBA32");
#endif
case GIMP_PIXELFORMAT_ANY: return ("ANY");
default:
break;
}
return ("bad format");
}
/**
* gimp_composite_init:
* @be_verbose: whether to be verbose on stdout
* @use_cpu_accel: whether to use accelerated routines like MMX
*
* Initialise the Gimp Compositing subsystem. This includes checking
* for user options and environment, installing the generic set of
* compositing operation handlers, followed by overloading those which
* are supported by the current cpu/hardware.
**/
void
gimp_composite_init (gboolean be_verbose,
gboolean use_cpu_accel)
{
const gchar *p;
if ((p = g_getenv ("GIMP_COMPOSITE")))
{
gimp_composite_options.bits = strtoul(p, NULL, 16);
}
if (! use_cpu_accel)
gimp_composite_options.bits |= GIMP_COMPOSITE_OPTION_NOEXTENSIONS;
if (be_verbose)
g_printerr ("gimp_composite: verbose=%s\n",
(gimp_composite_options.bits & GIMP_COMPOSITE_OPTION_VERBOSE) ?
"yes" : "no");
gimp_composite_generic_install ();
/*
* Here is where you "glue" in the initialisation of your
* optimisations.
*
* Declare the install() function external, and then call it. A
* return value of TRUE from the install function means the
* installer was successful in instantiating itself. For example,
* it succeeded in hooking in the functions with the special
* optimisation instructions, or hardware, or whatever.
*/
if (! (gimp_composite_options.bits & GIMP_COMPOSITE_OPTION_NOEXTENSIONS))
{
extern gboolean gimp_composite_mmx_install (void);
extern gboolean gimp_composite_sse_install (void);
extern gboolean gimp_composite_sse2_install (void);
extern gboolean gimp_composite_3dnow_install (void);
extern gboolean gimp_composite_altivec_install (void);
extern gboolean gimp_composite_vis_install (void);
gboolean can_use_mmx = gimp_composite_mmx_install ();
gboolean can_use_sse = gimp_composite_sse_install ();
gboolean can_use_sse2 = gimp_composite_sse2_install ();
gboolean can_use_3dnow = gimp_composite_3dnow_install ();
gboolean can_use_altivec = gimp_composite_altivec_install ();
gboolean can_use_vis = gimp_composite_vis_install ();
if (be_verbose)
g_printerr ("Processor instruction sets: "
"%cmmx %csse %csse2 %c3dnow %caltivec %cvis\n",
can_use_mmx ? '+' : '-',
can_use_sse ? '+' : '-',
can_use_sse2 ? '+' : '-',
can_use_3dnow ? '+' : '-',
can_use_altivec ? '+' : '-',
can_use_vis ? '+' : '-');
}
}
gboolean
gimp_composite_use_cpu_accel (void)
{
return ! (gimp_composite_options.bits & GIMP_COMPOSITE_OPTION_NOEXTENSIONS);
}