gimp/app/gegl/gimptilehandlerprojection.c

326 lines
11 KiB
C
Raw Normal View History

/* GIMP - The GNU 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 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 <cairo.h>
#include <gegl.h>
#include "gimp-gegl-types.h"
#include "gimptilehandlerprojection.h"
enum
{
PROP_0,
PROP_FORMAT,
PROP_TILE_WIDTH,
PROP_TILE_HEIGHT
};
static void gimp_tile_handler_projection_finalize (GObject *object);
static void gimp_tile_handler_projection_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_tile_handler_projection_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gpointer gimp_tile_handler_projection_command (GeglTileSource *source,
GeglTileCommand command,
gint x,
gint y,
gint z,
gpointer data);
G_DEFINE_TYPE (GimpTileHandlerProjection, gimp_tile_handler_projection,
GEGL_TYPE_TILE_HANDLER)
#define parent_class gimp_tile_handler_projection_parent_class
static void
gimp_tile_handler_projection_class_init (GimpTileHandlerProjectionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gimp_tile_handler_projection_finalize;
object_class->set_property = gimp_tile_handler_projection_set_property;
object_class->get_property = gimp_tile_handler_projection_get_property;
g_object_class_install_property (object_class, PROP_FORMAT,
g_param_spec_pointer ("format", NULL, NULL,
GIMP_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_TILE_WIDTH,
g_param_spec_int ("tile-width", NULL, NULL,
1, G_MAXINT, 1,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_TILE_HEIGHT,
g_param_spec_int ("tile-height", NULL, NULL,
1, G_MAXINT, 1,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
}
static void
gimp_tile_handler_projection_init (GimpTileHandlerProjection *projection)
{
GeglTileSource *source = GEGL_TILE_SOURCE (projection);
source->command = gimp_tile_handler_projection_command;
projection->dirty_region = cairo_region_create ();
}
static void
gimp_tile_handler_projection_finalize (GObject *object)
{
GimpTileHandlerProjection *projection = GIMP_TILE_HANDLER_PROJECTION (object);
if (projection->graph)
{
g_object_unref (projection->graph);
projection->graph = NULL;
}
cairo_region_destroy (projection->dirty_region);
projection->dirty_region = NULL;
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_tile_handler_projection_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpTileHandlerProjection *projection = GIMP_TILE_HANDLER_PROJECTION (object);
switch (property_id)
{
case PROP_FORMAT:
projection->format = g_value_get_pointer (value);
break;
case PROP_TILE_WIDTH:
projection->tile_width = g_value_get_int (value);
break;
case PROP_TILE_HEIGHT:
projection->tile_height = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_tile_handler_projection_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpTileHandlerProjection *projection = GIMP_TILE_HANDLER_PROJECTION (object);
switch (property_id)
{
case PROP_FORMAT:
g_value_set_pointer (value, (gpointer) projection->format);
break;
case PROP_TILE_WIDTH:
g_value_set_int (value, projection->tile_width);
break;
case PROP_TILE_HEIGHT:
g_value_set_int (value, projection->tile_height);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static GeglTile *
gimp_tile_handler_projection_validate (GeglTileSource *source,
GeglTile *tile,
gint x,
gint y)
{
GimpTileHandlerProjection *projection;
cairo_region_t *tile_region;
cairo_rectangle_int_t tile_rect;
projection = GIMP_TILE_HANDLER_PROJECTION (source);
if (cairo_region_is_empty (projection->dirty_region))
return tile;
tile_region = cairo_region_copy (projection->dirty_region);
tile_rect.x = x * projection->tile_width;
tile_rect.y = y * projection->tile_height;
tile_rect.width = projection->tile_width;
tile_rect.height = projection->tile_height;
cairo_region_intersect_rectangle (tile_region, &tile_rect);
if (! cairo_region_is_empty (tile_region))
{
gint tile_bpp;
gint tile_stride;
gint n_rects;
gint i;
if (! tile)
tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (source),
x, y, 0);
cairo_region_subtract_rectangle (projection->dirty_region, &tile_rect);
tile_bpp = babl_format_get_bytes_per_pixel (projection->format);
tile_stride = tile_bpp * projection->tile_width;
gegl_tile_lock (tile);
n_rects = cairo_region_num_rectangles (tile_region);
#if 0
g_printerr ("%d ", n_rects);
#endif
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t blit_rect;
cairo_region_get_rectangle (tile_region, i, &blit_rect);
#if 0
g_printerr ("constructing projection at %d %d %d %d\n",
blit_rect.x,
blit_rect.y,
blit_rect.width,
blit_rect.height);
#endif
gegl_node_blit (projection->graph, 1.0,
GEGL_RECTANGLE (blit_rect.x,
blit_rect.y,
blit_rect.width,
blit_rect.height),
projection->format,
gegl_tile_get_data (tile) +
(blit_rect.y % projection->tile_height) * tile_stride +
(blit_rect.x % projection->tile_width) * tile_bpp,
tile_stride,
GEGL_BLIT_DEFAULT);
}
gegl_tile_unlock (tile);
}
cairo_region_destroy (tile_region);
return tile;
}
static gpointer
gimp_tile_handler_projection_command (GeglTileSource *source,
GeglTileCommand command,
gint x,
gint y,
gint z,
gpointer data)
{
gpointer retval;
retval = gegl_tile_handler_source_command (source, command, x, y, z, data);
if (command == GEGL_TILE_GET && z == 0)
retval = gimp_tile_handler_projection_validate (source, retval, x, y);
return retval;
}
GeglTileHandler *
gimp_tile_handler_projection_new (GeglNode *graph)
{
GimpTileHandlerProjection *projection;
g_return_val_if_fail (GEGL_IS_NODE (graph), NULL);
projection = g_object_new (GIMP_TYPE_TILE_HANDLER_PROJECTION, NULL);
projection->graph = g_object_ref (graph);
return GEGL_TILE_HANDLER (projection);
}
static void
gimp_tile_handler_projection_void_pyramid (GeglTileSource *source,
gint x,
gint y,
gint z)
{
gegl_tile_source_void (source, x, y, z);
if (x / 2 != x || y / 2 != y)
gimp_tile_handler_projection_void_pyramid (source, x / 2, y / 2, z + 1);
}
void
gimp_tile_handler_projection_invalidate (GimpTileHandlerProjection *projection,
gint x,
gint y,
gint width,
gint height)
{
cairo_rectangle_int_t rect = { x, y, width, height };
gint tile_x1;
gint tile_y1;
gint tile_x2;
gint tile_y2;
gint tile_x;
gint tile_y;
g_return_if_fail (GIMP_IS_TILE_HANDLER_PROJECTION (projection));
cairo_region_union_rectangle (projection->dirty_region, &rect);
tile_x1 = x / projection->tile_width;
tile_y1 = y / projection->tile_height;
tile_x2 = (x + width - 1) / projection->tile_width;
tile_y2 = (y + height - 1) / projection->tile_height;
for (tile_y = tile_y1; tile_y <= tile_y2; tile_y++)
{
for (tile_x = tile_x1; tile_x <= tile_x2; tile_x++)
{
gimp_tile_handler_projection_void_pyramid (GEGL_TILE_SOURCE (projection),
tile_x / 2, tile_y / 2, 1);
}
}
}