Files
gimp/app/core/gimpprojectable.c
Ell f0aec02dff app: add gimp_projectable_{begin,end}_render()
In pass-through mode, the group layer-stack's input is connected to
the backdrop.  However, when rendering the group's projection, we
want to render the stack independently of the backdrop.
Unfortunately, we can't use the stack's graph as a subgraph of two
different graphs.

To work around that, the next few commits add a mechanism for a
projectable to be notified before and after its graph is being
rendered.  We use this mechanism to disconnect the stack's graph
from the backdrop before rendering the projection, and reconnect
it afterwards.  Yep, it's ugly, but it's better than having to
maintain n copies of (each node of) the graph (each nesting level
requires an extra copy.)

This commit adds {begin,end}_render() functions to GimpProjectable.
These functions should be called right before/after rendering the
projectable's graph.
2017-08-08 15:39:27 -04:00

276 lines
7.1 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpprojectable.c
* Copyright (C) 2008 Michael Natterer <mitch@gimp.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "core-types.h"
#include "gimpmarshal.h"
#include "gimpprojectable.h"
#include "gimpviewable.h"
enum
{
INVALIDATE,
FLUSH,
STRUCTURE_CHANGED,
LAST_SIGNAL
};
/* local function prototypes */
static void gimp_projectable_iface_base_init (GimpProjectableInterface *iface);
static guint projectable_signals[LAST_SIGNAL] = { 0 };
GType
gimp_projectable_interface_get_type (void)
{
static GType projectable_iface_type = 0;
if (! projectable_iface_type)
{
const GTypeInfo projectable_iface_info =
{
sizeof (GimpProjectableInterface),
(GBaseInitFunc) gimp_projectable_iface_base_init,
(GBaseFinalizeFunc) NULL,
};
projectable_iface_type = g_type_register_static (G_TYPE_INTERFACE,
"GimpProjectableInterface",
&projectable_iface_info,
0);
g_type_interface_add_prerequisite (projectable_iface_type,
GIMP_TYPE_VIEWABLE);
}
return projectable_iface_type;
}
static void
gimp_projectable_iface_base_init (GimpProjectableInterface *iface)
{
static gboolean initialized = FALSE;
if (! initialized)
{
projectable_signals[INVALIDATE] =
g_signal_new ("invalidate",
G_TYPE_FROM_CLASS (iface),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpProjectableInterface, invalidate),
NULL, NULL,
gimp_marshal_VOID__INT_INT_INT_INT,
G_TYPE_NONE, 4,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_INT);
projectable_signals[FLUSH] =
g_signal_new ("flush",
G_TYPE_FROM_CLASS (iface),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpProjectableInterface, flush),
NULL, NULL,
gimp_marshal_VOID__BOOLEAN,
G_TYPE_NONE, 1,
G_TYPE_BOOLEAN);
projectable_signals[STRUCTURE_CHANGED] =
g_signal_new ("structure-changed",
G_TYPE_FROM_CLASS (iface),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpProjectableInterface, structure_changed),
NULL, NULL,
gimp_marshal_VOID__VOID,
G_TYPE_NONE, 0);
initialized = TRUE;
}
}
/* public functions */
void
gimp_projectable_invalidate (GimpProjectable *projectable,
gint x,
gint y,
gint width,
gint height)
{
g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
g_signal_emit (projectable, projectable_signals[INVALIDATE], 0,
x, y, width, height);
}
void
gimp_projectable_flush (GimpProjectable *projectable,
gboolean preview_invalidated)
{
g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
g_signal_emit (projectable, projectable_signals[FLUSH], 0,
preview_invalidated);
}
void
gimp_projectable_structure_changed (GimpProjectable *projectable)
{
g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
g_signal_emit (projectable, projectable_signals[STRUCTURE_CHANGED], 0);
}
GimpImage *
gimp_projectable_get_image (GimpProjectable *projectable)
{
GimpProjectableInterface *iface;
g_return_val_if_fail (GIMP_IS_PROJECTABLE (projectable), NULL);
iface = GIMP_PROJECTABLE_GET_INTERFACE (projectable);
if (iface->get_image)
return iface->get_image (projectable);
return NULL;
}
const Babl *
gimp_projectable_get_format (GimpProjectable *projectable)
{
GimpProjectableInterface *iface;
g_return_val_if_fail (GIMP_IS_PROJECTABLE (projectable), NULL);
iface = GIMP_PROJECTABLE_GET_INTERFACE (projectable);
if (iface->get_format)
return iface->get_format (projectable);
return 0;
}
void
gimp_projectable_get_offset (GimpProjectable *projectable,
gint *x,
gint *y)
{
GimpProjectableInterface *iface;
g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
g_return_if_fail (x != NULL);
g_return_if_fail (y != NULL);
iface = GIMP_PROJECTABLE_GET_INTERFACE (projectable);
*x = 0;
*y = 0;
if (iface->get_offset)
iface->get_offset (projectable, x, y);
}
void
gimp_projectable_get_size (GimpProjectable *projectable,
gint *width,
gint *height)
{
GimpProjectableInterface *iface;
g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
g_return_if_fail (width != NULL);
g_return_if_fail (height != NULL);
iface = GIMP_PROJECTABLE_GET_INTERFACE (projectable);
*width = 0;
*height = 0;
if (iface->get_size)
iface->get_size (projectable, width, height);
}
GeglNode *
gimp_projectable_get_graph (GimpProjectable *projectable)
{
GimpProjectableInterface *iface;
g_return_val_if_fail (GIMP_IS_PROJECTABLE (projectable), NULL);
iface = GIMP_PROJECTABLE_GET_INTERFACE (projectable);
if (iface->get_graph)
return iface->get_graph (projectable);
return NULL;
}
void
gimp_projectable_begin_render (GimpProjectable *projectable)
{
GimpProjectableInterface *iface;
g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
iface = GIMP_PROJECTABLE_GET_INTERFACE (projectable);
if (iface->begin_render)
iface->begin_render (projectable);
}
void
gimp_projectable_end_render (GimpProjectable *projectable)
{
GimpProjectableInterface *iface;
g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
iface = GIMP_PROJECTABLE_GET_INTERFACE (projectable);
if (iface->end_render)
iface->end_render (projectable);
}
void
gimp_projectable_invalidate_preview (GimpProjectable *projectable)
{
GimpProjectableInterface *iface;
g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
iface = GIMP_PROJECTABLE_GET_INTERFACE (projectable);
if (iface->invalidate_preview)
iface->invalidate_preview (projectable);
}