1998-01-22 15:02:57 +08:00
|
|
|
/* TODO: make sure has_alpha gets set */
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* The GIMP -- an image manipulation program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* 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 2 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, write to the Free Software
|
1998-04-13 13:44:11 +08:00
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
1998-09-01 01:31:19 +08:00
|
|
|
#include <string.h>
|
1998-09-24 09:19:57 +08:00
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
1997-11-25 06:05:25 +08:00
|
|
|
#include "drawable.h"
|
|
|
|
#include "errors.h"
|
|
|
|
#include "floating_sel.h"
|
|
|
|
#include "gdisplay.h"
|
|
|
|
#include "gimage.h"
|
|
|
|
#include "gimage_mask.h"
|
|
|
|
#include "layer.h"
|
|
|
|
#include "paint_funcs.h"
|
|
|
|
#include "temp_buf.h"
|
1998-10-30 18:21:33 +08:00
|
|
|
#include "parasitelist.h"
|
1997-11-25 06:05:25 +08:00
|
|
|
#include "undo.h"
|
1999-02-15 05:09:55 +08:00
|
|
|
#include "gimpsignal.h"
|
1999-06-24 07:01:14 +08:00
|
|
|
#include "gimppreviewcache.h"
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-12-16 08:37:09 +08:00
|
|
|
#include "libgimp/gimpintl.h"
|
1999-03-07 20:56:03 +08:00
|
|
|
#include "libgimp/parasite.h"
|
1998-12-16 08:37:09 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
#include "layer_pvt.h"
|
|
|
|
#include "tile_manager_pvt.h"
|
1998-08-12 01:35:34 +08:00
|
|
|
#include "tile.h" /* ick. */
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
enum {
|
1999-02-15 05:09:55 +08:00
|
|
|
REMOVED,
|
1998-01-22 15:02:57 +08:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static void gimp_layer_class_init (GimpLayerClass *klass);
|
|
|
|
static void gimp_layer_init (GimpLayer *layer);
|
|
|
|
static void gimp_layer_destroy (GtkObject *object);
|
|
|
|
static void layer_invalidate_preview (GtkObject *);
|
|
|
|
|
|
|
|
static void gimp_layer_mask_class_init (GimpLayerMaskClass *klass);
|
|
|
|
static void gimp_layer_mask_init (GimpLayerMask *layermask);
|
|
|
|
static void gimp_layer_mask_destroy (GtkObject *object);
|
|
|
|
|
1999-02-16 16:53:54 +08:00
|
|
|
static guint layer_signals[LAST_SIGNAL] = { 0 };
|
1999-08-22 19:45:31 +08:00
|
|
|
|
1999-02-15 05:09:55 +08:00
|
|
|
/*
|
1998-01-22 15:02:57 +08:00
|
|
|
static gint layer_mask_signals[LAST_SIGNAL] = { 0 };
|
1998-02-05 08:07:31 +08:00
|
|
|
*/
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
static GimpDrawableClass *layer_parent_class = NULL;
|
1999-08-22 19:45:31 +08:00
|
|
|
static GimpChannelClass *layer_mask_parent_class = NULL;
|
1998-01-22 15:02:57 +08:00
|
|
|
|
1998-06-28 16:01:38 +08:00
|
|
|
GtkType
|
1998-01-22 15:02:57 +08:00
|
|
|
gimp_layer_get_type ()
|
|
|
|
{
|
1998-06-28 16:01:38 +08:00
|
|
|
static GtkType layer_type = 0;
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
if (!layer_type)
|
|
|
|
{
|
|
|
|
GtkTypeInfo layer_info =
|
|
|
|
{
|
|
|
|
"GimpLayer",
|
|
|
|
sizeof (GimpLayer),
|
|
|
|
sizeof (GimpLayerClass),
|
|
|
|
(GtkClassInitFunc) gimp_layer_class_init,
|
|
|
|
(GtkObjectInitFunc) gimp_layer_init,
|
1998-07-05 08:03:06 +08:00
|
|
|
/* reserved_1 */ NULL,
|
|
|
|
/* reserved_2 */ NULL,
|
1998-06-28 16:01:38 +08:00
|
|
|
(GtkClassInitFunc) NULL,
|
1998-01-22 15:02:57 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
layer_type = gtk_type_unique (gimp_drawable_get_type (), &layer_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return layer_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_class_init (GimpLayerClass *class)
|
|
|
|
{
|
|
|
|
GtkObjectClass *object_class;
|
|
|
|
GimpDrawableClass *drawable_class;
|
|
|
|
|
|
|
|
object_class = (GtkObjectClass*) class;
|
|
|
|
drawable_class = (GimpDrawableClass*) class;
|
|
|
|
|
|
|
|
layer_parent_class = gtk_type_class (gimp_drawable_get_type ());
|
|
|
|
|
1999-02-15 05:09:55 +08:00
|
|
|
layer_signals[REMOVED] =
|
|
|
|
gimp_signal_new ("removed",
|
|
|
|
0, object_class->type, 0, gimp_sigtype_void);
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
gtk_object_class_add_signals (object_class, layer_signals, LAST_SIGNAL);
|
|
|
|
|
|
|
|
object_class->destroy = gimp_layer_destroy;
|
|
|
|
drawable_class->invalidate_preview = layer_invalidate_preview;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_init (GimpLayer *layer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1998-06-28 16:01:38 +08:00
|
|
|
GtkType
|
1998-01-22 15:02:57 +08:00
|
|
|
gimp_layer_mask_get_type ()
|
|
|
|
{
|
1998-06-28 16:01:38 +08:00
|
|
|
static GtkType layer_mask_type = 0;
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
if (!layer_mask_type)
|
|
|
|
{
|
|
|
|
GtkTypeInfo layer_mask_info =
|
|
|
|
{
|
|
|
|
"GimpLayerMask",
|
|
|
|
sizeof (GimpLayerMask),
|
|
|
|
sizeof (GimpLayerMaskClass),
|
|
|
|
(GtkClassInitFunc) gimp_layer_mask_class_init,
|
|
|
|
(GtkObjectInitFunc) gimp_layer_mask_init,
|
1998-07-05 08:03:06 +08:00
|
|
|
/* reserved_1 */ NULL,
|
|
|
|
/* reserved_2 */ NULL,
|
1998-06-28 16:01:38 +08:00
|
|
|
(GtkClassInitFunc) NULL,
|
1998-01-22 15:02:57 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
layer_mask_type = gtk_type_unique (gimp_channel_get_type (), &layer_mask_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return layer_mask_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_mask_class_init (GimpLayerMaskClass *class)
|
|
|
|
{
|
|
|
|
GtkObjectClass *object_class;
|
|
|
|
|
|
|
|
object_class = (GtkObjectClass*) class;
|
|
|
|
layer_mask_parent_class = gtk_type_class (gimp_channel_get_type ());
|
|
|
|
|
1998-02-05 08:07:31 +08:00
|
|
|
/*
|
1998-01-22 15:02:57 +08:00
|
|
|
gtk_object_class_add_signals (object_class, layer_mask_signals, LAST_SIGNAL);
|
1998-02-05 08:07:31 +08:00
|
|
|
*/
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
object_class->destroy = gimp_layer_mask_destroy;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_mask_init (GimpLayerMask *layermask)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* static functions */
|
|
|
|
|
|
|
|
static void transform_color (GImage *, PixelRegion *,
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
PixelRegion *, GimpDrawable *,
|
|
|
|
GimpImageBaseType);
|
1997-11-25 06:05:25 +08:00
|
|
|
static void layer_preview_scale (int, unsigned char *, PixelRegion *,
|
|
|
|
PixelRegion *, int);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Static variables
|
|
|
|
*/
|
1999-08-22 19:45:31 +08:00
|
|
|
gint layer_get_count = 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
/********************************/
|
|
|
|
/* Local function definitions */
|
1999-08-22 19:45:31 +08:00
|
|
|
/********************************/
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
static void
|
1998-01-22 15:02:57 +08:00
|
|
|
layer_invalidate_preview (GtkObject *object)
|
|
|
|
{
|
|
|
|
GimpLayer *layer;
|
|
|
|
|
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (object));
|
|
|
|
|
|
|
|
layer = GIMP_LAYER (object);
|
|
|
|
|
|
|
|
if (layer_is_floating_sel (layer))
|
|
|
|
floating_sel_invalidate (layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-08-20 03:53:30 +08:00
|
|
|
transform_color (GImage *gimage,
|
|
|
|
PixelRegion *layerPR,
|
|
|
|
PixelRegion *bufPR,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GimpImageBaseType type)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
int i, h;
|
|
|
|
unsigned char * s, * d;
|
|
|
|
void * pr;
|
|
|
|
|
|
|
|
for (pr = pixel_regions_register (2, layerPR, bufPR); pr != NULL; pr = pixel_regions_process (pr))
|
|
|
|
{
|
|
|
|
h = layerPR->h;
|
|
|
|
s = bufPR->data;
|
|
|
|
d = layerPR->data;
|
|
|
|
|
|
|
|
while (h--)
|
|
|
|
{
|
|
|
|
for (i = 0; i < layerPR->w; i++)
|
|
|
|
{
|
1998-01-22 15:02:57 +08:00
|
|
|
gimage_transform_color (gimage, drawable,
|
1997-11-25 06:05:25 +08:00
|
|
|
s + (i * bufPR->bytes),
|
|
|
|
d + (i * layerPR->bytes), type);
|
|
|
|
/* copy alpha channel */
|
|
|
|
d[(i + 1) * layerPR->bytes - 1] = s[(i + 1) * bufPR->bytes - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
s += bufPR->rowstride;
|
|
|
|
d += layerPR->rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************/
|
|
|
|
/* Function definitions */
|
1999-08-22 19:45:31 +08:00
|
|
|
/**************************/
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
Layer *
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_new (GimpImage *gimage,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
GimpImageType type,
|
|
|
|
gchar *name,
|
|
|
|
gint opacity,
|
|
|
|
LayerModeEffects mode)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
Layer * layer;
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
if (width == 0 || height == 0)
|
|
|
|
{
|
|
|
|
g_message (_("Zero width or height layers not allowed."));
|
|
|
|
return NULL;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
layer = gtk_type_new (gimp_layer_get_type ());
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gimp_drawable_configure (GIMP_DRAWABLE (layer),
|
1998-06-29 08:24:44 +08:00
|
|
|
gimage, width, height, type, name);
|
1999-08-22 19:45:31 +08:00
|
|
|
layer->linked = FALSE;
|
|
|
|
layer->preserve_trans = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* no layer mask is present at start */
|
1999-08-22 19:45:31 +08:00
|
|
|
layer->mask = NULL;
|
|
|
|
layer->apply_mask = FALSE;
|
|
|
|
layer->edit_mask = FALSE;
|
|
|
|
layer->show_mask = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* mode and opacity */
|
1999-08-22 19:45:31 +08:00
|
|
|
layer->mode = mode;
|
1997-11-25 06:05:25 +08:00
|
|
|
layer->opacity = opacity;
|
|
|
|
|
|
|
|
/* floating selection variables */
|
1999-08-22 19:45:31 +08:00
|
|
|
layer->fs.backing_store = NULL;
|
|
|
|
layer->fs.drawable = NULL;
|
|
|
|
layer->fs.initial = TRUE;
|
1997-11-25 06:05:25 +08:00
|
|
|
layer->fs.boundary_known = FALSE;
|
1999-08-22 19:45:31 +08:00
|
|
|
layer->fs.segs = NULL;
|
|
|
|
layer->fs.num_segs = 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
1998-02-05 08:07:31 +08:00
|
|
|
Layer *
|
|
|
|
layer_ref (Layer *layer)
|
|
|
|
{
|
|
|
|
gtk_object_ref (GTK_OBJECT (layer));
|
|
|
|
gtk_object_sink (GTK_OBJECT (layer));
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
layer_unref (Layer *layer)
|
|
|
|
{
|
|
|
|
gtk_object_unref (GTK_OBJECT (layer));
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
Layer *
|
1999-08-22 19:45:31 +08:00
|
|
|
layer_copy (Layer *layer,
|
|
|
|
gboolean add_alpha)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-08-22 19:45:31 +08:00
|
|
|
gchar * layer_name;
|
1997-11-25 06:05:25 +08:00
|
|
|
Layer * new_layer;
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpImageType new_type;
|
1999-08-22 19:45:31 +08:00
|
|
|
gchar *ext;
|
|
|
|
gint number;
|
|
|
|
gchar *name;
|
|
|
|
gint len;
|
1997-11-25 06:05:25 +08:00
|
|
|
PixelRegion srcPR, destPR;
|
|
|
|
|
|
|
|
/* formulate the new layer name */
|
1999-08-22 19:45:31 +08:00
|
|
|
name = layer_get_name (layer);
|
|
|
|
ext = strrchr (name, '#');
|
1998-12-26 02:22:01 +08:00
|
|
|
len = strlen (_("copy"));
|
|
|
|
if ((strlen(name) >= len &&
|
1999-08-22 19:45:31 +08:00
|
|
|
strcmp (&name[strlen (name) - len], _("copy")) == 0) ||
|
|
|
|
(ext && (number = atoi (ext + 1)) > 0 &&
|
|
|
|
((int) (log10 (number) + 1)) == strlen (ext + 1)))
|
1998-12-26 02:22:01 +08:00
|
|
|
/* don't have redundant "copy"s */
|
|
|
|
layer_name = g_strdup (name);
|
1998-09-24 09:19:57 +08:00
|
|
|
else
|
1998-12-26 02:22:01 +08:00
|
|
|
layer_name = g_strdup_printf (_("%s copy"), name);
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* when copying a layer, the copy ALWAYS has an alpha channel */
|
|
|
|
if (add_alpha)
|
|
|
|
{
|
1999-08-22 19:45:31 +08:00
|
|
|
switch (GIMP_DRAWABLE (layer)->type)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
case RGB_GIMAGE:
|
|
|
|
new_type = RGBA_GIMAGE;
|
|
|
|
break;
|
|
|
|
case GRAY_GIMAGE:
|
|
|
|
new_type = GRAYA_GIMAGE;
|
|
|
|
break;
|
|
|
|
case INDEXED_GIMAGE:
|
|
|
|
new_type = INDEXEDA_GIMAGE;
|
|
|
|
break;
|
|
|
|
default:
|
1999-08-22 19:45:31 +08:00
|
|
|
new_type = GIMP_DRAWABLE (layer)->type;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
1999-08-22 19:45:31 +08:00
|
|
|
new_type = GIMP_DRAWABLE (layer)->type;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* allocate a new layer object */
|
1999-08-22 19:45:31 +08:00
|
|
|
new_layer = layer_new (GIMP_DRAWABLE (layer)->gimage,
|
|
|
|
GIMP_DRAWABLE (layer)->width,
|
|
|
|
GIMP_DRAWABLE (layer)->height,
|
1997-11-25 06:05:25 +08:00
|
|
|
new_type, layer_name, layer->opacity, layer->mode);
|
1999-08-22 19:45:31 +08:00
|
|
|
if (!new_layer)
|
|
|
|
{
|
|
|
|
g_message (_("layer_copy: could not allocate new layer"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
GIMP_DRAWABLE (new_layer)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
|
|
|
|
GIMP_DRAWABLE (new_layer)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
|
|
|
|
GIMP_DRAWABLE (new_layer)->visible = GIMP_DRAWABLE (layer)->visible;
|
|
|
|
new_layer->linked = layer->linked;
|
1997-11-25 06:05:25 +08:00
|
|
|
new_layer->preserve_trans = layer->preserve_trans;
|
|
|
|
|
|
|
|
/* copy the contents across layers */
|
1999-08-22 19:45:31 +08:00
|
|
|
if (new_type == GIMP_DRAWABLE (layer)->type)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-01-22 15:02:57 +08:00
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(layer)->tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, FALSE);
|
|
|
|
pixel_region_init (&destPR, GIMP_DRAWABLE(new_layer)->tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, TRUE);
|
1997-11-25 06:05:25 +08:00
|
|
|
copy_region (&srcPR, &destPR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-01-22 15:02:57 +08:00
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(layer)->tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, FALSE);
|
|
|
|
pixel_region_init (&destPR, GIMP_DRAWABLE(new_layer)->tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, TRUE);
|
1997-11-25 06:05:25 +08:00
|
|
|
add_alpha_region (&srcPR, &destPR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* duplicate the layer mask if necessary */
|
|
|
|
if (layer->mask)
|
|
|
|
{
|
1998-02-15 03:19:16 +08:00
|
|
|
new_layer->mask = layer_mask_ref (layer_mask_copy (layer->mask));
|
1997-11-25 06:05:25 +08:00
|
|
|
new_layer->apply_mask = layer->apply_mask;
|
1999-08-22 19:45:31 +08:00
|
|
|
new_layer->edit_mask = layer->edit_mask;
|
|
|
|
new_layer->show_mask = layer->show_mask;
|
|
|
|
layer_mask_set_layer (new_layer->mask, new_layer);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1998-10-08 16:15:21 +08:00
|
|
|
/* copy the parasites */
|
1999-08-22 19:45:31 +08:00
|
|
|
GIMP_DRAWABLE (new_layer)->parasites
|
|
|
|
= parasite_list_copy (GIMP_DRAWABLE (layer)->parasites);
|
1998-10-08 16:15:21 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
cleanup:
|
|
|
|
/* free up the layer_name memory */
|
|
|
|
g_free (layer_name);
|
|
|
|
|
|
|
|
return new_layer;
|
|
|
|
}
|
|
|
|
|
|
|
|
Layer *
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_from_tiles (void *gimage_ptr,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
TileManager *tiles,
|
|
|
|
gchar *name,
|
|
|
|
gint opacity,
|
|
|
|
LayerModeEffects mode)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
GImage * gimage;
|
|
|
|
Layer * new_layer;
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpImageType layer_type;
|
1997-11-25 06:05:25 +08:00
|
|
|
PixelRegion layerPR, bufPR;
|
|
|
|
|
|
|
|
/* Function copies buffer to a layer
|
|
|
|
* taking into consideration the possibility of transforming
|
|
|
|
* the contents to meet the requirements of the target image type
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* If no tile manager, return NULL */
|
|
|
|
if (!tiles)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
gimage = (GImage *) gimage_ptr;
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
layer_type = drawable_type_with_alpha (drawable);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Create the new layer */
|
1998-08-16 03:17:36 +08:00
|
|
|
new_layer = layer_new (0, tiles->width, tiles->height,
|
1997-11-25 06:05:25 +08:00
|
|
|
layer_type, name, opacity, mode);
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
if (!new_layer)
|
|
|
|
{
|
|
|
|
g_message (_("layer_from_tiles: could not allocate new layer"));
|
|
|
|
return NULL;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Configure the pixel regions */
|
1999-08-22 19:45:31 +08:00
|
|
|
pixel_region_init (&layerPR, GIMP_DRAWABLE (new_layer)->tiles, 0, 0, GIMP_DRAWABLE (new_layer)->width, GIMP_DRAWABLE (new_layer)->height, TRUE);
|
|
|
|
pixel_region_init (&bufPR, tiles, 0, 0, GIMP_DRAWABLE (new_layer)->width, GIMP_DRAWABLE (new_layer)->height, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
if ((tiles->bpp == 4 && GIMP_DRAWABLE (new_layer)->type == RGBA_GIMAGE) ||
|
|
|
|
(tiles->bpp == 2 && GIMP_DRAWABLE (new_layer)->type == GRAYA_GIMAGE))
|
1997-11-25 06:05:25 +08:00
|
|
|
/* If we want a layer the same type as the buffer */
|
|
|
|
copy_region (&bufPR, &layerPR);
|
|
|
|
else
|
|
|
|
/* Transform the contents of the buf to the new_layer */
|
1999-08-22 19:45:31 +08:00
|
|
|
transform_color (gimage, &layerPR, &bufPR, GIMP_DRAWABLE (new_layer),
|
1998-08-16 03:17:36 +08:00
|
|
|
(tiles->bpp == 4) ? RGB : GRAY);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
return new_layer;
|
|
|
|
}
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
LayerMask *
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_add_mask (Layer *layer,
|
|
|
|
LayerMask *mask)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
if (layer->mask)
|
|
|
|
return NULL;
|
|
|
|
|
1998-02-15 03:19:16 +08:00
|
|
|
layer->mask = layer_mask_ref (mask);
|
1998-01-22 15:02:57 +08:00
|
|
|
mask->layer = layer;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Set the application mode in the layer to "apply" */
|
1999-08-22 19:45:31 +08:00
|
|
|
layer->apply_mask = TRUE;
|
|
|
|
layer->edit_mask = TRUE;
|
|
|
|
layer->show_mask = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE(layer),
|
|
|
|
0, 0,
|
|
|
|
GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
return layer->mask;
|
|
|
|
}
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
LayerMask *
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_create_mask (Layer *layer,
|
|
|
|
AddMaskType add_mask_type)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PixelRegion maskPR, layerPR;
|
1998-01-22 15:02:57 +08:00
|
|
|
LayerMask *mask;
|
1999-08-22 19:45:31 +08:00
|
|
|
gchar *mask_name;
|
|
|
|
guchar black[3] = {0, 0, 0};
|
|
|
|
guchar white_mask = OPAQUE_OPACITY;
|
|
|
|
guchar black_mask = TRANSPARENT_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
mask_name = g_strdup_printf (_("%s mask"), GIMP_DRAWABLE (layer)->name);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Create the layer mask */
|
1999-08-22 19:45:31 +08:00
|
|
|
mask = layer_mask_new (GIMP_DRAWABLE (layer)->gimage,
|
|
|
|
GIMP_DRAWABLE (layer)->width,
|
|
|
|
GIMP_DRAWABLE (layer)->height,
|
|
|
|
mask_name, OPAQUE_OPACITY, black);
|
|
|
|
GIMP_DRAWABLE (mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
|
|
|
|
GIMP_DRAWABLE (mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles, 0, 0, GIMP_DRAWABLE (mask)->width, GIMP_DRAWABLE (mask)->height, TRUE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
switch (add_mask_type)
|
|
|
|
{
|
1999-04-25 04:33:31 +08:00
|
|
|
case ADD_WHITE_MASK:
|
1997-11-25 06:05:25 +08:00
|
|
|
color_region (&maskPR, &white_mask);
|
|
|
|
break;
|
1999-04-25 04:33:31 +08:00
|
|
|
case ADD_BLACK_MASK:
|
1997-11-25 06:05:25 +08:00
|
|
|
color_region (&maskPR, &black_mask);
|
|
|
|
break;
|
1999-04-25 04:33:31 +08:00
|
|
|
case ADD_ALPHA_MASK:
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Extract the layer's alpha channel */
|
|
|
|
if (layer_has_alpha (layer))
|
|
|
|
{
|
1999-08-22 19:45:31 +08:00
|
|
|
pixel_region_init (&layerPR, GIMP_DRAWABLE (layer)->tiles, 0, 0, GIMP_DRAWABLE (layer)->width, GIMP_DRAWABLE (layer)->height, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
extract_alpha_region (&layerPR, NULL, &maskPR);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (mask_name);
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
Layer *
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_get_ID (gint ID)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-01-22 15:02:57 +08:00
|
|
|
GimpDrawable *drawable;
|
1999-08-22 19:45:31 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable = drawable_get_ID (ID);
|
|
|
|
if (drawable && GIMP_IS_LAYER (drawable))
|
|
|
|
return GIMP_LAYER (drawable);
|
|
|
|
else
|
|
|
|
return NULL;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_delete (Layer *layer)
|
1998-01-22 15:02:57 +08:00
|
|
|
{
|
1998-02-14 08:44:47 +08:00
|
|
|
gtk_object_unref (GTK_OBJECT (layer));
|
1998-01-22 15:02:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_destroy (GtkObject *object)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-01-22 15:02:57 +08:00
|
|
|
GimpLayer *layer;
|
|
|
|
|
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (object));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
layer = GIMP_LAYER (object);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* if a layer mask exists, free it */
|
|
|
|
if (layer->mask)
|
1998-01-22 15:02:57 +08:00
|
|
|
layer_mask_delete (layer->mask);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* free the layer boundary if it exists */
|
|
|
|
if (layer->fs.segs)
|
|
|
|
g_free (layer->fs.segs);
|
|
|
|
|
|
|
|
/* free the floating selection if it exists */
|
|
|
|
if (layer_is_floating_sel (layer))
|
|
|
|
{
|
|
|
|
tile_manager_destroy (layer->fs.backing_store);
|
|
|
|
}
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
if (GTK_OBJECT_CLASS (layer_parent_class)->destroy)
|
|
|
|
(*GTK_OBJECT_CLASS (layer_parent_class)->destroy) (object);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-02-15 05:09:55 +08:00
|
|
|
/* The removed signal is sent out when the layer is no longer
|
|
|
|
* associcated with an image. It's needed because layers aren't
|
|
|
|
* destroyed immediately, but kept around for undo purposes. Connect
|
|
|
|
* to the removed signal to update bits of UI that are tied to a
|
|
|
|
* particular layer. */
|
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_removed (Layer *layer,
|
|
|
|
gpointer image)
|
1999-02-15 05:09:55 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (layer != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (layer));
|
|
|
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (layer), layer_signals[REMOVED]);
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
1999-08-22 19:45:31 +08:00
|
|
|
layer_apply_mask (Layer *layer,
|
|
|
|
MaskApplyMode mode)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, maskPR;
|
|
|
|
|
|
|
|
if (!layer->mask)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* this operation can only be done to layers with an alpha channel */
|
|
|
|
if (! layer_has_alpha (layer))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Need to save the mask here for undo */
|
|
|
|
|
|
|
|
if (mode == APPLY)
|
|
|
|
{
|
1999-08-22 19:45:31 +08:00
|
|
|
/* Put this apply mask operation on the undo stack */
|
|
|
|
drawable_apply_image (GIMP_DRAWABLE (layer),
|
|
|
|
0, 0,
|
|
|
|
GIMP_DRAWABLE(layer)->width,
|
|
|
|
GIMP_DRAWABLE(layer)->height,
|
|
|
|
NULL, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Combine the current layer's alpha channel and the mask */
|
1998-01-22 15:02:57 +08:00
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(layer)->tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, TRUE);
|
|
|
|
pixel_region_init (&maskPR, GIMP_DRAWABLE(layer->mask)->tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-25 09:24:46 +08:00
|
|
|
apply_mask_to_region (&srcPR, &maskPR, OPAQUE_OPACITY);
|
1999-08-22 19:45:31 +08:00
|
|
|
GIMP_DRAWABLE (layer)->preview_valid = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
layer->mask = NULL;
|
|
|
|
layer->apply_mask = FALSE;
|
|
|
|
layer->edit_mask = FALSE;
|
|
|
|
layer->show_mask = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
else if (mode == DISCARD)
|
|
|
|
{
|
1999-08-22 19:45:31 +08:00
|
|
|
layer->mask = NULL;
|
|
|
|
layer->apply_mask = FALSE;
|
|
|
|
layer->edit_mask = FALSE;
|
|
|
|
layer->show_mask = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-07 23:16:45 +08:00
|
|
|
static void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_translate_lowlevel (Layer *layer,
|
|
|
|
gint off_x,
|
|
|
|
gint off_y,
|
|
|
|
gboolean temporary)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-02-07 23:16:45 +08:00
|
|
|
if (!temporary)
|
|
|
|
{
|
|
|
|
/* the undo call goes here */
|
|
|
|
/*g_warning ("setting undo for layer translation");*/
|
|
|
|
undo_push_layer_displace (GIMP_DRAWABLE(layer)->gimage, layer);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* update the affected region */
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE(layer), 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-02-07 23:16:45 +08:00
|
|
|
if (!temporary)
|
|
|
|
{
|
|
|
|
/* invalidate the selection boundary because of a layer modification */
|
|
|
|
layer_invalidate_boundary (layer);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* update the layer offsets */
|
1998-01-22 15:02:57 +08:00
|
|
|
GIMP_DRAWABLE(layer)->offset_x += off_x;
|
|
|
|
GIMP_DRAWABLE(layer)->offset_y += off_y;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* update the affected region */
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE(layer), 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
if (layer->mask)
|
|
|
|
{
|
|
|
|
GIMP_DRAWABLE(layer->mask)->offset_x += off_x;
|
|
|
|
GIMP_DRAWABLE(layer->mask)->offset_y += off_y;
|
1999-02-07 23:16:45 +08:00
|
|
|
|
|
|
|
if (!temporary)
|
|
|
|
{
|
|
|
|
/* invalidate the mask preview */
|
|
|
|
drawable_invalidate_preview (GIMP_DRAWABLE(layer->mask));
|
|
|
|
}
|
1998-01-22 15:02:57 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-02-07 23:16:45 +08:00
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_temporarily_translate (Layer *layer,
|
|
|
|
gint off_x,
|
|
|
|
gint off_y)
|
1999-02-07 23:16:45 +08:00
|
|
|
{
|
|
|
|
layer_translate_lowlevel (layer, off_x, off_y, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_translate (Layer *layer,
|
|
|
|
gint off_x,
|
|
|
|
gint off_y)
|
1999-02-07 23:16:45 +08:00
|
|
|
{
|
|
|
|
layer_translate_lowlevel (layer, off_x, off_y, FALSE);
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_add_alpha (Layer *layer)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, destPR;
|
|
|
|
TileManager *new_tiles;
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpImageType type;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Don't bother if the layer already has alpha */
|
1998-01-22 15:02:57 +08:00
|
|
|
switch (GIMP_DRAWABLE(layer)->type)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
case RGB_GIMAGE:
|
|
|
|
type = RGBA_GIMAGE;
|
|
|
|
break;
|
|
|
|
case GRAY_GIMAGE:
|
|
|
|
type = GRAYA_GIMAGE;
|
|
|
|
break;
|
|
|
|
case INDEXED_GIMAGE:
|
|
|
|
type = INDEXEDA_GIMAGE;
|
|
|
|
break;
|
|
|
|
case RGBA_GIMAGE:
|
|
|
|
case GRAYA_GIMAGE:
|
|
|
|
case INDEXEDA_GIMAGE:
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Configure the pixel regions */
|
1998-01-22 15:02:57 +08:00
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(layer)->tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Allocate the new layer, configure dest region */
|
1998-01-22 15:02:57 +08:00
|
|
|
new_tiles = tile_manager_new (GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, (GIMP_DRAWABLE(layer)->bytes + 1));
|
|
|
|
pixel_region_init (&destPR, new_tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, TRUE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Add an alpha channel */
|
|
|
|
add_alpha_region (&srcPR, &destPR);
|
|
|
|
|
|
|
|
/* Push the layer on the undo stack */
|
1998-06-29 08:24:44 +08:00
|
|
|
undo_push_layer_mod (GIMP_DRAWABLE(layer)->gimage, layer);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Configure the new layer */
|
1998-01-22 15:02:57 +08:00
|
|
|
GIMP_DRAWABLE(layer)->tiles = new_tiles;
|
|
|
|
GIMP_DRAWABLE(layer)->type = type;
|
|
|
|
GIMP_DRAWABLE(layer)->bytes = GIMP_DRAWABLE(layer)->bytes + 1;
|
|
|
|
GIMP_DRAWABLE(layer)->has_alpha = TYPE_HAS_ALPHA (type);
|
1999-07-07 05:19:34 +08:00
|
|
|
GIMP_DRAWABLE(layer)->preview_valid = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (gimp_drawable_gimage (GIMP_DRAWABLE (layer))),
|
|
|
|
"restructure");
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_scale (Layer *layer,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint local_origin)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, destPR;
|
|
|
|
TileManager *new_tiles;
|
|
|
|
|
|
|
|
if (new_width == 0 || new_height == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Update the old layer position */
|
1999-08-22 19:45:31 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE(layer),
|
|
|
|
0, 0,
|
|
|
|
GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Configure the pixel regions */
|
1998-01-22 15:02:57 +08:00
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(layer)->tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Allocate the new layer, configure dest region */
|
1998-01-22 15:02:57 +08:00
|
|
|
new_tiles = tile_manager_new (new_width, new_height, GIMP_DRAWABLE(layer)->bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);
|
|
|
|
|
|
|
|
/* Scale the layer -
|
|
|
|
* If the layer is of type INDEXED, then we don't use pixel-value
|
|
|
|
* resampling because that doesn't necessarily make sense for INDEXED
|
|
|
|
* images.
|
|
|
|
*/
|
1998-01-22 15:02:57 +08:00
|
|
|
if ((GIMP_DRAWABLE(layer)->type == INDEXED_GIMAGE) || (GIMP_DRAWABLE(layer)->type == INDEXEDA_GIMAGE))
|
1997-11-25 06:05:25 +08:00
|
|
|
scale_region_no_resample (&srcPR, &destPR);
|
|
|
|
else
|
|
|
|
scale_region (&srcPR, &destPR);
|
|
|
|
|
|
|
|
/* Push the layer on the undo stack */
|
1998-06-29 08:24:44 +08:00
|
|
|
undo_push_layer_mod (GIMP_DRAWABLE(layer)->gimage, layer);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Configure the new layer */
|
|
|
|
if (local_origin)
|
|
|
|
{
|
|
|
|
int cx, cy;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
cx = GIMP_DRAWABLE(layer)->offset_x + GIMP_DRAWABLE(layer)->width / 2;
|
|
|
|
cy = GIMP_DRAWABLE(layer)->offset_y + GIMP_DRAWABLE(layer)->height / 2;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
GIMP_DRAWABLE(layer)->offset_x = cx - (new_width / 2);
|
|
|
|
GIMP_DRAWABLE(layer)->offset_y = cy - (new_height / 2);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
double xrat, yrat;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
xrat = (double) new_width / (double) GIMP_DRAWABLE(layer)->width;
|
|
|
|
yrat = (double) new_height / (double) GIMP_DRAWABLE(layer)->height;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
GIMP_DRAWABLE(layer)->offset_x = (int) (xrat * GIMP_DRAWABLE(layer)->offset_x);
|
|
|
|
GIMP_DRAWABLE(layer)->offset_y = (int) (yrat * GIMP_DRAWABLE(layer)->offset_y);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
1998-01-22 15:02:57 +08:00
|
|
|
GIMP_DRAWABLE(layer)->tiles = new_tiles;
|
|
|
|
GIMP_DRAWABLE(layer)->width = new_width;
|
|
|
|
GIMP_DRAWABLE(layer)->height = new_height;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
/* If there is a layer mask, make sure it gets scaled also */
|
|
|
|
if (layer->mask)
|
|
|
|
{
|
|
|
|
GIMP_DRAWABLE(layer->mask)->offset_x = GIMP_DRAWABLE(layer)->offset_x;
|
|
|
|
GIMP_DRAWABLE(layer->mask)->offset_y = GIMP_DRAWABLE(layer)->offset_y;
|
|
|
|
channel_scale (GIMP_CHANNEL(layer->mask), new_width, new_height);
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Update the new layer position */
|
1999-08-22 19:45:31 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE(layer),
|
|
|
|
0, 0,
|
|
|
|
GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_resize (Layer *layer,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offx,
|
|
|
|
gint offy)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, destPR;
|
|
|
|
TileManager *new_tiles;
|
|
|
|
int w, h;
|
|
|
|
int x1, y1, x2, y2;
|
|
|
|
|
|
|
|
if (!new_width || !new_height)
|
|
|
|
return;
|
|
|
|
|
1998-06-29 08:24:44 +08:00
|
|
|
x1 = CLAMP (offx, 0, new_width);
|
|
|
|
y1 = CLAMP (offy, 0, new_height);
|
|
|
|
x2 = CLAMP ((offx + GIMP_DRAWABLE(layer)->width), 0, new_width);
|
|
|
|
y2 = CLAMP ((offy + GIMP_DRAWABLE(layer)->height), 0, new_height);
|
1997-11-25 06:05:25 +08:00
|
|
|
w = x2 - x1;
|
|
|
|
h = y2 - y1;
|
|
|
|
|
|
|
|
if (offx > 0)
|
|
|
|
{
|
|
|
|
x1 = 0;
|
|
|
|
x2 = offx;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x1 = -offx;
|
|
|
|
x2 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (offy > 0)
|
|
|
|
{
|
|
|
|
y1 = 0;
|
|
|
|
y2 = offy;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
y1 = -offy;
|
|
|
|
y2 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the old layer position */
|
1999-08-22 19:45:31 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE(layer),
|
|
|
|
0, 0,
|
|
|
|
GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Configure the pixel regions */
|
1998-01-22 15:02:57 +08:00
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(layer)->tiles, x1, y1, w, h, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Allocate the new layer, configure dest region */
|
1998-01-22 15:02:57 +08:00
|
|
|
new_tiles = tile_manager_new (new_width, new_height, GIMP_DRAWABLE(layer)->bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);
|
|
|
|
|
|
|
|
/* fill with the fill color */
|
|
|
|
if (layer_has_alpha (layer))
|
|
|
|
{
|
|
|
|
/* Set to transparent and black */
|
|
|
|
unsigned char bg[4] = {0, 0, 0, 0};
|
|
|
|
color_region (&destPR, bg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned char bg[3];
|
1998-06-29 08:24:44 +08:00
|
|
|
gimage_get_background (GIMP_DRAWABLE(layer)->gimage, GIMP_DRAWABLE(layer), bg);
|
1997-11-25 06:05:25 +08:00
|
|
|
color_region (&destPR, bg);
|
|
|
|
}
|
|
|
|
pixel_region_init (&destPR, new_tiles, x2, y2, w, h, TRUE);
|
|
|
|
|
|
|
|
/* copy from the old to the new */
|
|
|
|
if (w && h)
|
|
|
|
copy_region (&srcPR, &destPR);
|
|
|
|
|
|
|
|
/* Push the layer on the undo stack */
|
1998-06-29 08:24:44 +08:00
|
|
|
undo_push_layer_mod (GIMP_DRAWABLE(layer)->gimage, layer);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Configure the new layer */
|
1998-01-22 15:02:57 +08:00
|
|
|
GIMP_DRAWABLE(layer)->tiles = new_tiles;
|
|
|
|
GIMP_DRAWABLE(layer)->offset_x = x1 + GIMP_DRAWABLE(layer)->offset_x - x2;
|
|
|
|
GIMP_DRAWABLE(layer)->offset_y = y1 + GIMP_DRAWABLE(layer)->offset_y - y2;
|
|
|
|
GIMP_DRAWABLE(layer)->width = new_width;
|
|
|
|
GIMP_DRAWABLE(layer)->height = new_height;
|
|
|
|
|
|
|
|
/* If there is a layer mask, make sure it gets resized also */
|
1999-08-22 19:45:31 +08:00
|
|
|
if (layer->mask)
|
|
|
|
{
|
|
|
|
GIMP_DRAWABLE(layer->mask)->offset_x = GIMP_DRAWABLE(layer)->offset_x;
|
|
|
|
GIMP_DRAWABLE(layer->mask)->offset_y = GIMP_DRAWABLE(layer)->offset_y;
|
|
|
|
channel_resize (GIMP_CHANNEL (layer->mask),
|
|
|
|
new_width, new_height, offx, offy);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* update the new layer area */
|
1999-08-22 19:45:31 +08:00
|
|
|
drawable_update (GIMP_DRAWABLE(layer),
|
|
|
|
0, 0,
|
|
|
|
GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
BoundSeg *
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_boundary (Layer *layer,
|
|
|
|
gint *num_segs)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
BoundSeg *new_segs;
|
|
|
|
|
|
|
|
/* Create the four boundary segments that encompass this
|
|
|
|
* layer's boundary.
|
|
|
|
*/
|
|
|
|
new_segs = (BoundSeg *) g_malloc (sizeof (BoundSeg) * 4);
|
|
|
|
*num_segs = 4;
|
|
|
|
|
|
|
|
/* if the layer is a floating selection */
|
|
|
|
if (layer_is_floating_sel (layer))
|
|
|
|
{
|
|
|
|
/* if the owner drawable is a channel, just return nothing */
|
1999-08-22 19:45:31 +08:00
|
|
|
if (GIMP_IS_CHANNEL (layer->fs.drawable))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
*num_segs = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* otherwise, set the layer to the owner drawable */
|
|
|
|
else
|
1999-08-22 19:45:31 +08:00
|
|
|
layer = GIMP_LAYER (layer->fs.drawable);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
new_segs[0].x1 = GIMP_DRAWABLE(layer)->offset_x;
|
|
|
|
new_segs[0].y1 = GIMP_DRAWABLE(layer)->offset_y;
|
|
|
|
new_segs[0].x2 = GIMP_DRAWABLE(layer)->offset_x;
|
|
|
|
new_segs[0].y2 = GIMP_DRAWABLE(layer)->offset_y + GIMP_DRAWABLE(layer)->height;
|
1997-11-25 06:05:25 +08:00
|
|
|
new_segs[0].open = 1;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
new_segs[1].x1 = GIMP_DRAWABLE(layer)->offset_x;
|
|
|
|
new_segs[1].y1 = GIMP_DRAWABLE(layer)->offset_y;
|
|
|
|
new_segs[1].x2 = GIMP_DRAWABLE(layer)->offset_x + GIMP_DRAWABLE(layer)->width;
|
|
|
|
new_segs[1].y2 = GIMP_DRAWABLE(layer)->offset_y;
|
1997-11-25 06:05:25 +08:00
|
|
|
new_segs[1].open = 1;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
new_segs[2].x1 = GIMP_DRAWABLE(layer)->offset_x + GIMP_DRAWABLE(layer)->width;
|
|
|
|
new_segs[2].y1 = GIMP_DRAWABLE(layer)->offset_y;
|
|
|
|
new_segs[2].x2 = GIMP_DRAWABLE(layer)->offset_x + GIMP_DRAWABLE(layer)->width;
|
|
|
|
new_segs[2].y2 = GIMP_DRAWABLE(layer)->offset_y + GIMP_DRAWABLE(layer)->height;
|
1997-11-25 06:05:25 +08:00
|
|
|
new_segs[2].open = 0;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
new_segs[3].x1 = GIMP_DRAWABLE(layer)->offset_x;
|
|
|
|
new_segs[3].y1 = GIMP_DRAWABLE(layer)->offset_y + GIMP_DRAWABLE(layer)->height;
|
|
|
|
new_segs[3].x2 = GIMP_DRAWABLE(layer)->offset_x + GIMP_DRAWABLE(layer)->width;
|
|
|
|
new_segs[3].y2 = GIMP_DRAWABLE(layer)->offset_y + GIMP_DRAWABLE(layer)->height;
|
1997-11-25 06:05:25 +08:00
|
|
|
new_segs[3].open = 0;
|
|
|
|
|
|
|
|
return new_segs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_invalidate_boundary (Layer *layer)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
GImage *gimage;
|
|
|
|
Channel *mask;
|
|
|
|
|
|
|
|
/* first get the selection mask channel */
|
1999-08-22 19:45:31 +08:00
|
|
|
if (! (gimage = drawable_gimage (GIMP_DRAWABLE (layer))))
|
1997-11-25 06:05:25 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Turn the current selection off */
|
1998-06-29 08:24:44 +08:00
|
|
|
gdisplays_selection_visibility (gimage, SelectionOff);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-02-09 03:22:46 +08:00
|
|
|
/* clear the affected region surrounding the layer */
|
|
|
|
gdisplays_selection_visibility (gimage, SelectionLayerOff);
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
mask = gimage_get_mask (gimage);
|
|
|
|
|
|
|
|
/* Only bother with the bounds if there is a selection */
|
|
|
|
if (! channel_is_empty (mask))
|
|
|
|
{
|
1999-08-22 19:45:31 +08:00
|
|
|
mask->bounds_known = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
mask->boundary_known = FALSE;
|
|
|
|
}
|
|
|
|
|
1998-10-12 06:50:03 +08:00
|
|
|
if (layer_is_floating_sel(layer))
|
|
|
|
floating_sel_invalidate(layer);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gint
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_pick_correlate (Layer *layer,
|
|
|
|
gint x,
|
|
|
|
gint y)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
Tile *tile;
|
|
|
|
Tile *mask_tile;
|
|
|
|
int val;
|
|
|
|
|
|
|
|
/* Is the point inside the layer?
|
|
|
|
* First transform the point to layer coordinates...
|
|
|
|
*/
|
1998-01-22 15:02:57 +08:00
|
|
|
x -= GIMP_DRAWABLE(layer)->offset_x;
|
|
|
|
y -= GIMP_DRAWABLE(layer)->offset_y;
|
|
|
|
if (x >= 0 && x < GIMP_DRAWABLE(layer)->width &&
|
|
|
|
y >= 0 && y < GIMP_DRAWABLE(layer)->height &&
|
|
|
|
GIMP_DRAWABLE(layer)->visible)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
/* If the point is inside, and the layer has no
|
|
|
|
* alpha channel, success!
|
|
|
|
*/
|
|
|
|
if (! layer_has_alpha (layer))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* Otherwise, determine if the alpha value at
|
|
|
|
* the given point is non-zero
|
|
|
|
*/
|
1998-08-16 03:17:36 +08:00
|
|
|
tile = tile_manager_get_tile (GIMP_DRAWABLE(layer)->tiles, x, y, TRUE, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-10-25 13:55:36 +08:00
|
|
|
val = * ((unsigned char*) tile_data_pointer (tile,
|
1998-08-12 01:35:34 +08:00
|
|
|
x % TILE_WIDTH,
|
|
|
|
y % TILE_HEIGHT) +
|
|
|
|
tile_bpp (tile) - 1);
|
1997-11-25 06:05:25 +08:00
|
|
|
if (layer->mask)
|
|
|
|
{
|
1998-08-12 01:35:34 +08:00
|
|
|
unsigned char *ptr;
|
1998-08-16 03:17:36 +08:00
|
|
|
mask_tile = tile_manager_get_tile (GIMP_DRAWABLE(layer->mask)->tiles, x, y, TRUE, FALSE);
|
1998-08-12 01:35:34 +08:00
|
|
|
ptr = tile_data_pointer (mask_tile, x % TILE_WIDTH, y % TILE_HEIGHT);
|
|
|
|
val = val * (*ptr) / 255;
|
1998-07-10 10:43:12 +08:00
|
|
|
tile_release (mask_tile, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1998-07-10 10:43:12 +08:00
|
|
|
tile_release (tile, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
if (val > 63)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
/**********************/
|
|
|
|
/* access functions */
|
|
|
|
/**********************/
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-09-24 09:19:57 +08:00
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_set_name (Layer *layer,
|
|
|
|
gchar *name)
|
1998-09-24 09:19:57 +08:00
|
|
|
{
|
1999-08-20 03:53:30 +08:00
|
|
|
gimp_drawable_set_name (GIMP_DRAWABLE (layer), name);
|
1998-09-24 09:19:57 +08:00
|
|
|
}
|
|
|
|
|
1999-08-20 03:53:30 +08:00
|
|
|
gchar *
|
1998-09-24 09:19:57 +08:00
|
|
|
layer_get_name (Layer *layer)
|
|
|
|
{
|
1999-08-20 03:53:30 +08:00
|
|
|
return gimp_drawable_get_name (GIMP_DRAWABLE (layer));
|
1998-09-24 09:19:57 +08:00
|
|
|
}
|
|
|
|
|
1999-08-20 03:53:30 +08:00
|
|
|
guchar *
|
|
|
|
layer_data (Layer *layer)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
LayerMask *
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_get_mask (Layer *layer)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
return layer->mask;
|
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_has_alpha (Layer *layer)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-01-22 15:02:57 +08:00
|
|
|
if (GIMP_DRAWABLE(layer)->type == RGBA_GIMAGE ||
|
|
|
|
GIMP_DRAWABLE(layer)->type == GRAYA_GIMAGE ||
|
|
|
|
GIMP_DRAWABLE(layer)->type == INDEXEDA_GIMAGE)
|
1999-08-22 19:45:31 +08:00
|
|
|
return TRUE;
|
1997-11-25 06:05:25 +08:00
|
|
|
else
|
1999-08-22 19:45:31 +08:00
|
|
|
return FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
layer_is_floating_sel (Layer *layer)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-01-22 15:02:57 +08:00
|
|
|
if (layer->fs.drawable != NULL)
|
1999-08-22 19:45:31 +08:00
|
|
|
return TRUE;
|
1997-11-25 06:05:25 +08:00
|
|
|
else
|
1999-08-22 19:45:31 +08:00
|
|
|
return FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
1998-01-22 15:02:57 +08:00
|
|
|
layer_linked (Layer *layer)
|
|
|
|
{
|
|
|
|
return layer->linked;
|
|
|
|
}
|
|
|
|
|
1999-08-28 03:07:21 +08:00
|
|
|
static TempBuf *
|
|
|
|
layer_preview_private (Layer *layer,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
GImage *gimage;
|
|
|
|
TempBuf *preview_buf;
|
|
|
|
PixelRegion srcPR, destPR;
|
|
|
|
int type;
|
|
|
|
int bytes;
|
|
|
|
int subsample;
|
1999-06-24 07:01:14 +08:00
|
|
|
TempBuf *ret_buf;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
type = 0;
|
|
|
|
bytes = 0;
|
|
|
|
|
|
|
|
/* The easy way */
|
1998-01-22 15:02:57 +08:00
|
|
|
if (GIMP_DRAWABLE(layer)->preview_valid &&
|
1999-06-24 07:01:14 +08:00
|
|
|
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(layer)->preview_cache),
|
|
|
|
w,h)))
|
|
|
|
return ret_buf;
|
1997-11-25 06:05:25 +08:00
|
|
|
/* The hard way */
|
|
|
|
else
|
|
|
|
{
|
1998-06-29 08:24:44 +08:00
|
|
|
gimage = GIMP_DRAWABLE(layer)->gimage;
|
1998-01-22 15:02:57 +08:00
|
|
|
switch (GIMP_DRAWABLE(layer)->type)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
case RGB_GIMAGE: case RGBA_GIMAGE:
|
|
|
|
type = 0;
|
1998-01-22 15:02:57 +08:00
|
|
|
bytes = GIMP_DRAWABLE(layer)->bytes;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
case GRAY_GIMAGE: case GRAYA_GIMAGE:
|
|
|
|
type = 1;
|
1998-01-22 15:02:57 +08:00
|
|
|
bytes = GIMP_DRAWABLE(layer)->bytes;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
case INDEXED_GIMAGE: case INDEXEDA_GIMAGE:
|
|
|
|
type = 2;
|
1998-01-22 15:02:57 +08:00
|
|
|
bytes = (GIMP_DRAWABLE(layer)->type == INDEXED_GIMAGE) ? 3 : 4;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate 'acceptable' subsample */
|
|
|
|
subsample = 1;
|
1997-12-07 05:53:02 +08:00
|
|
|
/* handle some truncation errors */
|
|
|
|
if (w < 1) w = 1;
|
|
|
|
if (h < 1) h = 1;
|
1998-01-22 15:02:57 +08:00
|
|
|
while ((w * (subsample + 1) * 2 < GIMP_DRAWABLE(layer)->width) &&
|
|
|
|
(h * (subsample + 1) * 2 < GIMP_DRAWABLE(layer)->height))
|
1997-11-25 06:05:25 +08:00
|
|
|
subsample = subsample + 1;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(layer)->tiles, 0, 0, GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
preview_buf = temp_buf_new (w, h, bytes, 0, 0, NULL);
|
|
|
|
destPR.bytes = preview_buf->bytes;
|
|
|
|
destPR.w = w;
|
|
|
|
destPR.h = h;
|
|
|
|
destPR.rowstride = w * destPR.bytes;
|
|
|
|
destPR.data = temp_buf_data (preview_buf);
|
|
|
|
|
|
|
|
layer_preview_scale (type, gimage->cmap, &srcPR, &destPR, subsample);
|
|
|
|
|
1999-06-24 07:01:14 +08:00
|
|
|
if (!GIMP_DRAWABLE(layer)->preview_valid)
|
|
|
|
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(layer)->preview_cache));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
GIMP_DRAWABLE(layer)->preview_valid = TRUE;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-06-24 07:01:14 +08:00
|
|
|
gimp_preview_cache_add(&(GIMP_DRAWABLE(layer)->preview_cache),preview_buf);
|
|
|
|
return preview_buf;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TempBuf *
|
1999-08-28 03:07:21 +08:00
|
|
|
layer_preview (Layer *layer,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
|
|
|
{
|
|
|
|
/* Ok prime the cache with a large preview if the cache is invalid */
|
|
|
|
if(!GIMP_DRAWABLE(layer)->preview_valid &&
|
|
|
|
w <= PREVIEW_CACHE_PRIME_WIDTH &&
|
|
|
|
h <= PREVIEW_CACHE_PRIME_HEIGHT)
|
|
|
|
{
|
|
|
|
TempBuf * tb = layer_preview_private(layer,
|
|
|
|
PREVIEW_CACHE_PRIME_WIDTH,
|
|
|
|
PREVIEW_CACHE_PRIME_HEIGHT);
|
|
|
|
|
|
|
|
/* Save the 2nd call */
|
|
|
|
if(w == PREVIEW_CACHE_PRIME_WIDTH &&
|
|
|
|
h == PREVIEW_CACHE_PRIME_HEIGHT)
|
|
|
|
return tb;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Second call - should NOT visit the tile cache...*/
|
|
|
|
return layer_preview_private(layer,w,h);
|
|
|
|
}
|
|
|
|
|
|
|
|
static TempBuf *
|
|
|
|
layer_mask_preview_private (Layer *layer,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
TempBuf *preview_buf;
|
1998-01-22 15:02:57 +08:00
|
|
|
LayerMask *mask;
|
1997-11-25 06:05:25 +08:00
|
|
|
PixelRegion srcPR, destPR;
|
|
|
|
int subsample;
|
1999-06-24 07:01:14 +08:00
|
|
|
TempBuf *ret_buf;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
mask = layer->mask;
|
|
|
|
if (!mask)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* The easy way */
|
1998-01-22 15:02:57 +08:00
|
|
|
if (GIMP_DRAWABLE(mask)->preview_valid &&
|
1999-06-24 07:01:14 +08:00
|
|
|
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(mask)->preview_cache),
|
|
|
|
w,h)))
|
|
|
|
return ret_buf;
|
1997-11-25 06:05:25 +08:00
|
|
|
/* The hard way */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* calculate 'acceptable' subsample */
|
|
|
|
subsample = 1;
|
1997-12-07 05:53:02 +08:00
|
|
|
if (w < 1) w = 1;
|
|
|
|
if (h < 1) h = 1;
|
1998-01-22 15:02:57 +08:00
|
|
|
while ((w * (subsample + 1) * 2 < GIMP_DRAWABLE(layer)->width) &&
|
|
|
|
(h * (subsample + 1) * 2 < GIMP_DRAWABLE(layer)->height))
|
1997-11-25 06:05:25 +08:00
|
|
|
subsample = subsample + 1;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
preview_buf = temp_buf_new (w, h, 1, 0, 0, NULL);
|
|
|
|
destPR.bytes = preview_buf->bytes;
|
|
|
|
destPR.w = w;
|
|
|
|
destPR.h = h;
|
|
|
|
destPR.rowstride = w * destPR.bytes;
|
|
|
|
destPR.data = temp_buf_data (preview_buf);
|
|
|
|
|
|
|
|
layer_preview_scale (1 /* GRAY */, NULL, &srcPR, &destPR, subsample);
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
if(!GIMP_DRAWABLE (mask)->preview_valid)
|
|
|
|
gimp_preview_cache_invalidate (&(GIMP_DRAWABLE (mask)->preview_cache));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
GIMP_DRAWABLE (mask)->preview_valid = TRUE;
|
|
|
|
gimp_preview_cache_add (&(GIMP_DRAWABLE (mask)->preview_cache),
|
|
|
|
preview_buf);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-06-24 07:01:14 +08:00
|
|
|
return preview_buf;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-28 03:07:21 +08:00
|
|
|
TempBuf *
|
|
|
|
layer_mask_preview (Layer *layer,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
|
|
|
{
|
|
|
|
/* Ok prime the cache with a large preview if the cache is invalid */
|
|
|
|
if(!GIMP_DRAWABLE(layer->mask)->preview_valid &&
|
|
|
|
w <= PREVIEW_CACHE_PRIME_WIDTH &&
|
|
|
|
h <= PREVIEW_CACHE_PRIME_HEIGHT)
|
|
|
|
{
|
|
|
|
TempBuf * tb = layer_mask_preview_private(layer,
|
|
|
|
PREVIEW_CACHE_PRIME_WIDTH,
|
|
|
|
PREVIEW_CACHE_PRIME_HEIGHT);
|
|
|
|
|
|
|
|
/* Save the 2nd call */
|
|
|
|
if(w == PREVIEW_CACHE_PRIME_WIDTH &&
|
|
|
|
h == PREVIEW_CACHE_PRIME_HEIGHT)
|
|
|
|
return tb;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Second call - should NOT visit the tile cache...*/
|
|
|
|
return layer_mask_preview_private(layer,w,h);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-10-30 18:21:33 +08:00
|
|
|
Tattoo
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_get_tattoo (const Layer *layer)
|
1998-10-14 10:54:02 +08:00
|
|
|
{
|
1999-08-20 03:53:30 +08:00
|
|
|
return (gimp_drawable_get_tattoo (GIMP_DRAWABLE (layer)));
|
1998-10-14 10:54:02 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
void
|
1998-06-29 08:24:44 +08:00
|
|
|
layer_invalidate_previews (GimpImage* gimage)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-01-29 16:03:27 +08:00
|
|
|
GSList * tmp;
|
1997-11-25 06:05:25 +08:00
|
|
|
Layer * layer;
|
1998-01-22 15:02:57 +08:00
|
|
|
|
1998-07-08 23:47:38 +08:00
|
|
|
g_return_if_fail (gimage != NULL);
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
tmp = gimage->layers;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
while (tmp)
|
|
|
|
{
|
|
|
|
layer = (Layer *) tmp->data;
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable_invalidate_preview (GIMP_DRAWABLE(layer));
|
1998-01-29 16:03:27 +08:00
|
|
|
tmp = g_slist_next (tmp);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_preview_scale (gint type,
|
|
|
|
guchar *cmap,
|
|
|
|
PixelRegion *srcPR,
|
|
|
|
PixelRegion *destPR,
|
|
|
|
gint subsample)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
#define EPSILON 0.000001
|
|
|
|
unsigned char * src, * s;
|
|
|
|
unsigned char * dest, * d;
|
|
|
|
double * row, * r;
|
|
|
|
int destwidth;
|
|
|
|
int src_row, src_col;
|
|
|
|
int bytes, b;
|
|
|
|
int width, height;
|
|
|
|
int orig_width, orig_height;
|
|
|
|
double x_rat, y_rat;
|
|
|
|
double x_cum, y_cum;
|
|
|
|
double x_last, y_last;
|
|
|
|
double * x_frac, y_frac, tot_frac;
|
|
|
|
int i, j;
|
|
|
|
int frac;
|
|
|
|
int advance_dest;
|
|
|
|
unsigned char rgb[MAX_CHANNELS];
|
|
|
|
|
|
|
|
orig_width = srcPR->w / subsample;
|
|
|
|
orig_height = srcPR->h / subsample;
|
|
|
|
width = destPR->w;
|
|
|
|
height = destPR->h;
|
|
|
|
|
|
|
|
/* Some calculations... */
|
|
|
|
bytes = destPR->bytes;
|
|
|
|
destwidth = destPR->rowstride;
|
|
|
|
|
|
|
|
/* the data pointers... */
|
|
|
|
src = (unsigned char *) g_malloc (orig_width * bytes);
|
|
|
|
dest = destPR->data;
|
|
|
|
|
|
|
|
/* find the ratios of old x to new x and old y to new y */
|
|
|
|
x_rat = (double) orig_width / (double) width;
|
|
|
|
y_rat = (double) orig_height / (double) height;
|
|
|
|
|
|
|
|
/* allocate an array to help with the calculations */
|
|
|
|
row = (double *) g_malloc (sizeof (double) * width * bytes);
|
|
|
|
x_frac = (double *) g_malloc (sizeof (double) * (width + orig_width));
|
|
|
|
|
|
|
|
/* initialize the pre-calculated pixel fraction array */
|
|
|
|
src_col = 0;
|
|
|
|
x_cum = (double) src_col;
|
|
|
|
x_last = x_cum;
|
|
|
|
|
|
|
|
for (i = 0; i < width + orig_width; i++)
|
|
|
|
{
|
|
|
|
if (x_cum + x_rat <= (src_col + 1 + EPSILON))
|
|
|
|
{
|
|
|
|
x_cum += x_rat;
|
|
|
|
x_frac[i] = x_cum - x_last;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
src_col ++;
|
|
|
|
x_frac[i] = src_col - x_last;
|
|
|
|
}
|
|
|
|
x_last += x_frac[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear the "row" array */
|
|
|
|
memset (row, 0, sizeof (double) * width * bytes);
|
|
|
|
|
|
|
|
/* counters... */
|
|
|
|
src_row = 0;
|
|
|
|
y_cum = (double) src_row;
|
|
|
|
y_last = y_cum;
|
|
|
|
|
|
|
|
pixel_region_get_row (srcPR, 0, src_row * subsample, orig_width * subsample, src, subsample);
|
|
|
|
|
|
|
|
/* Scale the selected region */
|
|
|
|
for (i = 0; i < height; )
|
|
|
|
{
|
|
|
|
src_col = 0;
|
|
|
|
x_cum = (double) src_col;
|
|
|
|
|
|
|
|
/* determine the fraction of the src pixel we are using for y */
|
|
|
|
if (y_cum + y_rat <= (src_row + 1 + EPSILON))
|
|
|
|
{
|
|
|
|
y_cum += y_rat;
|
|
|
|
y_frac = y_cum - y_last;
|
|
|
|
advance_dest = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
src_row ++;
|
|
|
|
y_frac = src_row - y_last;
|
|
|
|
advance_dest = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
y_last += y_frac;
|
|
|
|
|
|
|
|
s = src;
|
|
|
|
r = row;
|
|
|
|
|
|
|
|
frac = 0;
|
|
|
|
j = width;
|
|
|
|
|
|
|
|
while (j)
|
|
|
|
{
|
|
|
|
tot_frac = x_frac[frac++] * y_frac;
|
|
|
|
|
|
|
|
/* If indexed, transform the color to RGB */
|
|
|
|
if (type == 2)
|
|
|
|
{
|
|
|
|
map_to_color (2, cmap, s, rgb);
|
|
|
|
|
|
|
|
r[RED_PIX] += rgb[RED_PIX] * tot_frac;
|
|
|
|
r[GREEN_PIX] += rgb[GREEN_PIX] * tot_frac;
|
|
|
|
r[BLUE_PIX] += rgb[BLUE_PIX] * tot_frac;
|
|
|
|
if (bytes == 4)
|
|
|
|
r[ALPHA_PIX] += s[ALPHA_I_PIX] * tot_frac;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for (b = 0; b < bytes; b++)
|
|
|
|
r[b] += s[b] * tot_frac;
|
|
|
|
|
|
|
|
/* increment the destination */
|
|
|
|
if (x_cum + x_rat <= (src_col + 1 + EPSILON))
|
|
|
|
{
|
|
|
|
r += bytes;
|
|
|
|
x_cum += x_rat;
|
|
|
|
j--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* increment the source */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s += srcPR->bytes;
|
|
|
|
src_col++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (advance_dest)
|
|
|
|
{
|
|
|
|
tot_frac = 1.0 / (x_rat * y_rat);
|
|
|
|
|
|
|
|
/* copy "row" to "dest" */
|
|
|
|
d = dest;
|
|
|
|
r = row;
|
|
|
|
|
|
|
|
j = width;
|
|
|
|
while (j--)
|
|
|
|
{
|
|
|
|
b = bytes;
|
|
|
|
while (b--)
|
1999-10-20 04:56:51 +08:00
|
|
|
*d++ = (unsigned char) ((*r++ * tot_frac)+0.5);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
dest += destwidth;
|
|
|
|
|
|
|
|
/* clear the "row" array */
|
|
|
|
memset (row, 0, sizeof (double) * destwidth);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pixel_region_get_row (srcPR, 0, src_row * subsample, orig_width * subsample, src, subsample);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free up temporary arrays */
|
|
|
|
g_free (row);
|
|
|
|
g_free (x_frac);
|
|
|
|
g_free (src);
|
|
|
|
}
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_layer_mask_destroy (GtkObject *object)
|
|
|
|
{
|
|
|
|
GimpLayerMask *layermask;
|
|
|
|
|
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER_MASK (object));
|
|
|
|
|
|
|
|
layermask = GIMP_LAYER_MASK (object);
|
|
|
|
|
|
|
|
if (GTK_OBJECT_CLASS (layer_mask_parent_class)->destroy)
|
|
|
|
(*GTK_OBJECT_CLASS (layer_mask_parent_class)->destroy) (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerMask *
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_mask_new (GimpImage *gimage,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gchar *name,
|
|
|
|
gint opacity,
|
|
|
|
guchar *col)
|
1998-01-22 15:02:57 +08:00
|
|
|
{
|
|
|
|
LayerMask * layer_mask;
|
1999-08-22 19:45:31 +08:00
|
|
|
gint i;
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
layer_mask = gtk_type_new (gimp_layer_mask_get_type ());
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gimp_drawable_configure (GIMP_DRAWABLE (layer_mask),
|
1998-06-29 08:24:44 +08:00
|
|
|
gimage, width, height, GRAY_GIMAGE, name);
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
/* set the layer_mask color and opacity */
|
|
|
|
for (i = 0; i < 3; i++)
|
1999-08-22 19:45:31 +08:00
|
|
|
GIMP_CHANNEL (layer_mask)->col[i] = col[i];
|
|
|
|
|
|
|
|
GIMP_CHANNEL (layer_mask)->opacity = opacity;
|
|
|
|
GIMP_CHANNEL (layer_mask)->show_masked = TRUE;
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
/* selection mask variables */
|
1999-08-22 19:45:31 +08:00
|
|
|
GIMP_CHANNEL (layer_mask)->empty = TRUE;
|
|
|
|
GIMP_CHANNEL (layer_mask)->segs_in = NULL;
|
|
|
|
GIMP_CHANNEL (layer_mask)->segs_out = NULL;
|
|
|
|
GIMP_CHANNEL (layer_mask)->num_segs_in = 0;
|
|
|
|
GIMP_CHANNEL (layer_mask)->num_segs_out = 0;
|
|
|
|
GIMP_CHANNEL (layer_mask)->bounds_known = TRUE;
|
|
|
|
GIMP_CHANNEL (layer_mask)->boundary_known = TRUE;
|
|
|
|
GIMP_CHANNEL (layer_mask)->x1 = GIMP_CHANNEL (layer_mask)->y1 = 0;
|
|
|
|
GIMP_CHANNEL (layer_mask)->x2 = width;
|
|
|
|
GIMP_CHANNEL (layer_mask)->y2 = height;
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
return layer_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerMask *
|
|
|
|
layer_mask_copy (LayerMask *layer_mask)
|
|
|
|
{
|
|
|
|
char * layer_mask_name;
|
|
|
|
LayerMask * new_layer_mask;
|
|
|
|
PixelRegion srcPR, destPR;
|
|
|
|
|
|
|
|
/* formulate the new layer_mask name */
|
1998-12-26 02:22:01 +08:00
|
|
|
layer_mask_name = g_strdup_printf (_("%s copy"), GIMP_DRAWABLE(layer_mask)->name);
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
/* allocate a new layer_mask object */
|
1998-06-29 08:24:44 +08:00
|
|
|
new_layer_mask = layer_mask_new (GIMP_DRAWABLE(layer_mask)->gimage,
|
1998-01-22 15:02:57 +08:00
|
|
|
GIMP_DRAWABLE(layer_mask)->width,
|
|
|
|
GIMP_DRAWABLE(layer_mask)->height,
|
|
|
|
layer_mask_name,
|
|
|
|
GIMP_CHANNEL(layer_mask)->opacity,
|
|
|
|
GIMP_CHANNEL(layer_mask)->col);
|
|
|
|
GIMP_DRAWABLE(new_layer_mask)->visible = GIMP_DRAWABLE(layer_mask)->visible;
|
|
|
|
GIMP_DRAWABLE(new_layer_mask)->offset_x = GIMP_DRAWABLE(layer_mask)->offset_x;
|
|
|
|
GIMP_DRAWABLE(new_layer_mask)->offset_y = GIMP_DRAWABLE(layer_mask)->offset_y;
|
|
|
|
GIMP_CHANNEL(new_layer_mask)->show_masked = GIMP_CHANNEL(layer_mask)->show_masked;
|
|
|
|
|
|
|
|
/* copy the contents across layer masks */
|
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(layer_mask)->tiles, 0, 0,
|
|
|
|
GIMP_DRAWABLE(layer_mask)->width,
|
|
|
|
GIMP_DRAWABLE(layer_mask)->height, FALSE);
|
|
|
|
pixel_region_init (&destPR, GIMP_DRAWABLE(new_layer_mask)->tiles, 0, 0, GIMP_DRAWABLE(layer_mask)->width, GIMP_DRAWABLE(layer_mask)->height, TRUE);
|
|
|
|
copy_region (&srcPR, &destPR);
|
|
|
|
|
|
|
|
/* free up the layer_mask_name memory */
|
|
|
|
g_free (layer_mask_name);
|
|
|
|
|
|
|
|
return new_layer_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerMask *
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_mask_get_ID (gint ID)
|
1998-01-22 15:02:57 +08:00
|
|
|
{
|
|
|
|
GimpDrawable *drawable;
|
|
|
|
drawable = drawable_get_ID (ID);
|
|
|
|
if (drawable && GIMP_IS_LAYER_MASK (drawable))
|
|
|
|
return GIMP_LAYER_MASK (drawable);
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
layer_mask_delete (LayerMask *layermask)
|
1998-01-22 15:02:57 +08:00
|
|
|
{
|
1998-02-15 03:19:16 +08:00
|
|
|
gtk_object_unref (GTK_OBJECT (layermask));
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerMask *
|
|
|
|
layer_mask_ref (LayerMask *mask)
|
|
|
|
{
|
|
|
|
gtk_object_ref (GTK_OBJECT (mask));
|
|
|
|
gtk_object_sink (GTK_OBJECT (mask));
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
layer_mask_unref (LayerMask *mask)
|
|
|
|
{
|
|
|
|
gtk_object_unref (GTK_OBJECT (mask));
|
1998-01-22 15:02:57 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
void
|
|
|
|
layer_mask_set_layer (LayerMask *mask,
|
|
|
|
Layer *layer)
|
|
|
|
{
|
|
|
|
mask->layer = layer;
|
|
|
|
}
|
|
|
|
|
1999-08-21 03:59:06 +08:00
|
|
|
Layer *
|
|
|
|
layer_mask_get_layer (LayerMask *mask)
|
|
|
|
{
|
|
|
|
return mask->layer;
|
|
|
|
}
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
void
|
1999-08-20 03:53:30 +08:00
|
|
|
channel_layer_mask (Channel *mask,
|
|
|
|
Layer *layer)
|
1998-01-22 15:02:57 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, destPR;
|
|
|
|
unsigned char empty = 0;
|
|
|
|
int x1, y1, x2, y2;
|
|
|
|
|
|
|
|
/* push the current mask onto the undo stack */
|
|
|
|
channel_push_undo (mask);
|
|
|
|
|
|
|
|
/* clear the mask */
|
|
|
|
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, 0, 0, GIMP_DRAWABLE(mask)->width, GIMP_DRAWABLE(mask)->height, TRUE);
|
|
|
|
color_region (&destPR, &empty);
|
|
|
|
|
1998-06-29 08:24:44 +08:00
|
|
|
x1 = CLAMP (GIMP_DRAWABLE(layer)->offset_x, 0, GIMP_DRAWABLE(mask)->width);
|
|
|
|
y1 = CLAMP (GIMP_DRAWABLE(layer)->offset_y, 0, GIMP_DRAWABLE(mask)->height);
|
|
|
|
x2 = CLAMP (GIMP_DRAWABLE(layer)->offset_x + GIMP_DRAWABLE(layer)->width, 0, GIMP_DRAWABLE(mask)->width);
|
|
|
|
y2 = CLAMP (GIMP_DRAWABLE(layer)->offset_y + GIMP_DRAWABLE(layer)->height, 0, GIMP_DRAWABLE(mask)->height);
|
1998-01-22 15:02:57 +08:00
|
|
|
|
|
|
|
pixel_region_init (&srcPR, GIMP_DRAWABLE(layer->mask)->tiles,
|
|
|
|
(x1 - GIMP_DRAWABLE(layer)->offset_x), (y1 - GIMP_DRAWABLE(layer)->offset_y),
|
|
|
|
(x2 - x1), (y2 - y1), FALSE);
|
|
|
|
pixel_region_init (&destPR, GIMP_DRAWABLE(mask)->tiles, x1, y1, (x2 - x1), (y2 - y1), TRUE);
|
|
|
|
copy_region (&srcPR, &destPR);
|
|
|
|
|
|
|
|
mask->bounds_known = FALSE;
|
|
|
|
}
|