mirror of https://github.com/GNOME/gimp.git
app: add GimpTileHandlerProjection and use it to validate the projection
as the projection buffer is being read from. Projection performance is now back at its old speed.
This commit is contained in:
parent
c743a4fc0a
commit
6b6d39fc64
|
@ -17,11 +17,13 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "gegl/gimp-gegl-utils.h"
|
||||
#include "gegl/gimptilehandlerprojection.h"
|
||||
|
||||
#include "gimp.h"
|
||||
#include "gimp-utils.h"
|
||||
|
@ -66,6 +68,7 @@ static gdouble gimp_projection_get_opacity_at (GimpPickable *picka
|
|||
gint x,
|
||||
gint y);
|
||||
|
||||
static void gimp_projection_free_buffer (GimpProjection *proj);
|
||||
static void gimp_projection_add_update_area (GimpProjection *proj,
|
||||
gint x,
|
||||
gint y,
|
||||
|
@ -138,11 +141,6 @@ gimp_projection_class_init (GimpProjectionClass *klass)
|
|||
static void
|
||||
gimp_projection_init (GimpProjection *proj)
|
||||
{
|
||||
proj->projectable = NULL;
|
||||
proj->buffer = NULL;
|
||||
proj->update_areas = NULL;
|
||||
proj->idle_render.idle_id = 0;
|
||||
proj->idle_render.update_areas = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -174,24 +172,7 @@ gimp_projection_finalize (GObject *object)
|
|||
gimp_area_list_free (proj->idle_render.update_areas);
|
||||
proj->idle_render.update_areas = NULL;
|
||||
|
||||
if (proj->buffer)
|
||||
{
|
||||
g_object_unref (proj->buffer);
|
||||
proj->buffer = NULL;
|
||||
}
|
||||
|
||||
if (proj->graph)
|
||||
{
|
||||
g_object_unref (proj->graph);
|
||||
proj->graph = NULL;
|
||||
proj->sink_node = NULL;
|
||||
}
|
||||
|
||||
if (proj->processor)
|
||||
{
|
||||
g_object_unref (proj->processor);
|
||||
proj->processor = NULL;
|
||||
}
|
||||
gimp_projection_free_buffer (proj);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -286,22 +267,22 @@ gimp_projection_get_buffer (GimpPickable *pickable)
|
|||
|
||||
if (! proj->buffer)
|
||||
{
|
||||
GeglNode *graph;
|
||||
const Babl *format;
|
||||
gint width;
|
||||
gint height;
|
||||
|
||||
graph = gimp_projectable_get_graph (proj->projectable);
|
||||
format = gimp_projection_get_format (GIMP_PICKABLE (proj));
|
||||
gimp_projectable_get_size (proj->projectable, &width, &height);
|
||||
|
||||
proj->buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
|
||||
format);
|
||||
|
||||
if (proj->sink_node)
|
||||
{
|
||||
gegl_node_set (proj->sink_node,
|
||||
"buffer", proj->buffer,
|
||||
NULL);
|
||||
}
|
||||
proj->validate_handler = gimp_tile_handler_projection_new (graph);
|
||||
gegl_buffer_add_handler (proj->buffer, proj->validate_handler);
|
||||
gimp_tile_handler_projection_invalidate (proj->validate_handler,
|
||||
0, 0, width, height);
|
||||
}
|
||||
|
||||
return proj->buffer;
|
||||
|
@ -360,44 +341,6 @@ gimp_projection_new (GimpProjectable *projectable)
|
|||
return proj;
|
||||
}
|
||||
|
||||
#ifdef USE_BUFFER
|
||||
GeglNode *
|
||||
gimp_projection_get_sink_node (GimpProjection *proj)
|
||||
{
|
||||
GeglNode *graph;
|
||||
GeglBuffer *buffer;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_PROJECTION (proj), NULL);
|
||||
|
||||
if (proj->sink_node)
|
||||
return proj->sink_node;
|
||||
|
||||
proj->graph = gegl_node_new ();
|
||||
|
||||
#if 0
|
||||
g_object_set (proj->graph,
|
||||
"dont-cache", TRUE,
|
||||
NULL);
|
||||
#endif
|
||||
|
||||
graph = gimp_projectable_get_graph (proj->projectable);
|
||||
gegl_node_add_child (proj->graph, graph);
|
||||
|
||||
buffer = gimp_projection_get_buffer (GIMP_PICKABLE (proj));
|
||||
|
||||
proj->sink_node =
|
||||
gegl_node_new_child (proj->graph,
|
||||
"operation", "gegl:write-buffer",
|
||||
"buffer", buffer,
|
||||
NULL);
|
||||
|
||||
gegl_node_connect_to (graph, "output",
|
||||
proj->sink_node, "input");
|
||||
|
||||
return proj->sink_node;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
gimp_projection_flush (GimpProjection *proj)
|
||||
{
|
||||
|
@ -423,10 +366,6 @@ gimp_projection_finish_draw (GimpProjection *proj)
|
|||
|
||||
if (proj->idle_render.idle_id)
|
||||
{
|
||||
#if 0
|
||||
g_printerr ("%s: flushing idle render queue\n", G_STRFUNC);
|
||||
#endif
|
||||
|
||||
g_source_remove (proj->idle_render.idle_id);
|
||||
proj->idle_render.idle_id = 0;
|
||||
|
||||
|
@ -437,6 +376,25 @@ gimp_projection_finish_draw (GimpProjection *proj)
|
|||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
gimp_projection_free_buffer (GimpProjection *proj)
|
||||
{
|
||||
if (proj->buffer)
|
||||
{
|
||||
if (proj->validate_handler)
|
||||
gegl_buffer_remove_handler (proj->buffer, proj->validate_handler);
|
||||
|
||||
g_object_unref (proj->buffer);
|
||||
proj->buffer = NULL;
|
||||
}
|
||||
|
||||
if (proj->validate_handler)
|
||||
{
|
||||
g_object_unref (proj->validate_handler);
|
||||
proj->validate_handler = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_projection_add_update_area (GimpProjection *proj,
|
||||
gint x,
|
||||
|
@ -695,36 +653,6 @@ gimp_projection_paint_area (GimpProjection *proj,
|
|||
y2 - y1);
|
||||
}
|
||||
|
||||
#ifdef USE_BUFFER
|
||||
static void
|
||||
gimp_projection_construct (GimpProjection *proj,
|
||||
gint x,
|
||||
gint y,
|
||||
gint w,
|
||||
gint h)
|
||||
{
|
||||
GeglRectangle rect = { x, y, w, h };
|
||||
|
||||
g_return_if_fail (GIMP_IS_PROJECTION (proj));
|
||||
|
||||
/* GEGL should really do this for us... */
|
||||
gegl_buffer_clear (gimp_projection_get_buffer (GIMP_PICKABLE (proj)), &rect);
|
||||
|
||||
if (! proj->processor)
|
||||
{
|
||||
GeglNode *sink = gimp_projection_get_sink_node (proj);
|
||||
|
||||
proj->processor = gegl_node_new_processor (sink, &rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
gegl_processor_set_rectangle (proj->processor, &rect);
|
||||
}
|
||||
|
||||
while (gegl_processor_work (proj->processor, NULL));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gimp_projection_invalidate (GimpProjection *proj,
|
||||
guint x,
|
||||
|
@ -732,11 +660,9 @@ gimp_projection_invalidate (GimpProjection *proj,
|
|||
guint w,
|
||||
guint h)
|
||||
{
|
||||
/* FIXME: this should happen as we actually *read* from the buffer
|
||||
*/
|
||||
#ifdef USE_BUFFER
|
||||
gimp_projection_construct (proj, x, y, w, h);
|
||||
#endif
|
||||
if (proj->validate_handler)
|
||||
gimp_tile_handler_projection_invalidate (proj->validate_handler,
|
||||
x, y, w, h);
|
||||
}
|
||||
|
||||
|
||||
|
@ -780,11 +706,7 @@ gimp_projection_projectable_changed (GimpProjectable *projectable,
|
|||
gimp_area_list_free (proj->update_areas);
|
||||
proj->update_areas = NULL;
|
||||
|
||||
if (proj->buffer)
|
||||
{
|
||||
g_object_unref (proj->buffer);
|
||||
proj->buffer = NULL;
|
||||
}
|
||||
gimp_projection_free_buffer (proj);
|
||||
|
||||
gimp_projectable_get_offset (proj->projectable, &off_x, &off_y);
|
||||
gimp_projectable_get_size (projectable, &width, &height);
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
#define __GIMP_PROJECTION_H__
|
||||
|
||||
|
||||
#define USE_BUFFER 1
|
||||
|
||||
|
||||
#include "gimpobject.h"
|
||||
|
||||
|
||||
|
@ -58,10 +55,7 @@ struct _GimpProjection
|
|||
GimpProjectable *projectable;
|
||||
|
||||
GeglBuffer *buffer;
|
||||
|
||||
GeglNode *graph;
|
||||
GeglNode *sink_node;
|
||||
GeglProcessor *processor;
|
||||
gpointer validate_handler;
|
||||
|
||||
GSList *update_areas;
|
||||
GimpProjectionIdleRender idle_render;
|
||||
|
@ -86,10 +80,6 @@ GType gimp_projection_get_type (void) G_GNUC_CONST;
|
|||
|
||||
GimpProjection * gimp_projection_new (GimpProjectable *projectable);
|
||||
|
||||
#if USE_BUFFER
|
||||
GeglNode * gimp_projection_get_sink_node (GimpProjection *proj);
|
||||
#endif
|
||||
|
||||
void gimp_projection_flush (GimpProjection *proj);
|
||||
void gimp_projection_flush_now (GimpProjection *proj);
|
||||
void gimp_projection_finish_draw (GimpProjection *proj);
|
||||
|
|
|
@ -51,42 +51,37 @@ gimp_display_shell_render (GimpDisplayShell *shell,
|
|||
gint w,
|
||||
gint h)
|
||||
{
|
||||
#ifdef USE_BUFFER
|
||||
GimpImage *image;
|
||||
GimpProjection *projection;
|
||||
GeglBuffer *buffer;
|
||||
#endif
|
||||
GimpImage *image;
|
||||
gint viewport_offset_x;
|
||||
gint viewport_offset_y;
|
||||
gint viewport_width;
|
||||
gint viewport_height;
|
||||
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (cr != NULL);
|
||||
g_return_if_fail (w > 0 && h > 0);
|
||||
|
||||
image = gimp_display_get_image (shell->display);
|
||||
|
||||
#ifdef USE_BUFFER
|
||||
image = gimp_display_get_image (shell->display);
|
||||
projection = gimp_image_get_projection (image);
|
||||
buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (projection));
|
||||
buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (projection));
|
||||
|
||||
gimp_display_shell_scroll_get_scaled_viewport (shell,
|
||||
&viewport_offset_x,
|
||||
&viewport_offset_y,
|
||||
&viewport_width,
|
||||
&viewport_height);
|
||||
|
||||
gegl_buffer_get (buffer,
|
||||
GEGL_RECTANGLE (x + shell->offset_x,
|
||||
y + shell->offset_y,
|
||||
GEGL_RECTANGLE (x + viewport_offset_x,
|
||||
y + viewport_offset_y,
|
||||
w, h),
|
||||
shell->scale_x,
|
||||
babl_format ("cairo-ARGB32"),
|
||||
cairo_image_surface_get_data (shell->render_surface),
|
||||
cairo_image_surface_get_stride (shell->render_surface),
|
||||
GEGL_ABYSS_NONE);
|
||||
#else
|
||||
gegl_node_blit (gimp_projectable_get_graph (GIMP_PROJECTABLE (image)),
|
||||
shell->scale_x,
|
||||
GEGL_RECTANGLE (src_x * shell->scale_x,
|
||||
src_y * shell->scale_y,
|
||||
w, h),
|
||||
babl_format ("cairo-ARGB32"),
|
||||
cairo_image_surface_get_data (shell->render_surface),
|
||||
cairo_image_surface_get_stride (shell->render_surface),
|
||||
0);
|
||||
#endif
|
||||
|
||||
/* apply filters to the rendered projection */
|
||||
if (shell->filter_stack)
|
||||
|
@ -136,24 +131,22 @@ gimp_display_shell_render (GimpDisplayShell *shell,
|
|||
#endif
|
||||
|
||||
/* put it to the screen */
|
||||
{
|
||||
cairo_save (cr);
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_rectangle (cr, x, y, w, h);
|
||||
cairo_clip (cr);
|
||||
cairo_rectangle (cr, x, y, w, h);
|
||||
cairo_clip (cr);
|
||||
|
||||
cairo_set_source_surface (cr, shell->render_surface, x, y);
|
||||
cairo_paint (cr);
|
||||
cairo_set_source_surface (cr, shell->render_surface, x, y);
|
||||
cairo_paint (cr);
|
||||
|
||||
#if 0
|
||||
if (shell->mask)
|
||||
{
|
||||
gimp_cairo_set_source_rgba (cr, &shell->mask_color);
|
||||
cairo_mask_surface (cr, shell->mask_surface,
|
||||
x + disp_xoffset, y + disp_yoffset);
|
||||
}
|
||||
if (shell->mask)
|
||||
{
|
||||
gimp_cairo_set_source_rgba (cr, &shell->mask_color);
|
||||
cairo_mask_surface (cr, shell->mask_surface,
|
||||
x + disp_xoffset, y + disp_yoffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
|
|
@ -1388,9 +1388,8 @@ gimp_display_shell_fill (GimpDisplayShell *shell,
|
|||
/* we double buffer image drawing manually */
|
||||
gtk_widget_set_double_buffered (shell->canvas, FALSE);
|
||||
|
||||
shell->fill_idle_id = g_idle_add_full (G_PRIORITY_LOW,
|
||||
(GSourceFunc) gimp_display_shell_fill_idle,
|
||||
shell, NULL);
|
||||
shell->fill_idle_id = g_idle_add ((GSourceFunc) gimp_display_shell_fill_idle,
|
||||
shell);
|
||||
}
|
||||
|
||||
/* We used to calculate the scale factor in the SCALEFACTOR_X() and
|
||||
|
|
|
@ -658,6 +658,9 @@ file_open_sanitize_image (GimpImage *image,
|
|||
*/
|
||||
gimp_image_clean_all (image);
|
||||
|
||||
#if 0
|
||||
/* XXX this is not needed any longer, remove it when sure */
|
||||
|
||||
/* make sure the entire projection is properly constructed, because
|
||||
* load plug-ins are not required to call gimp_drawable_update() or
|
||||
* anything.
|
||||
|
@ -670,6 +673,7 @@ file_open_sanitize_image (GimpImage *image,
|
|||
|
||||
/* same for drawable previews */
|
||||
gimp_image_invalidate_previews (image);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Converts items from one image to another */
|
||||
|
|
|
@ -35,7 +35,9 @@ libappgegl_a_sources = \
|
|||
gimp-gegl-utils.c \
|
||||
gimp-gegl-utils.h \
|
||||
gimpapplicator.c \
|
||||
gimpapplicator.h
|
||||
gimpapplicator.h \
|
||||
gimptilehandlerprojection.c \
|
||||
gimptilehandlerprojection.h
|
||||
|
||||
libappgegl_a_built_sources = gimp-gegl-enums.c
|
||||
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
/* 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_ABYSS_NONE);
|
||||
}
|
||||
|
||||
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) / projection->tile_width;
|
||||
tile_y2 = (y + height) / 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_TILE_HANDLER_PROJECTION_H__
|
||||
#define __GIMP_TILE_HANDLER_PROJECTION_H__
|
||||
|
||||
#include <gegl-buffer-backend.h>
|
||||
|
||||
/***
|
||||
* GimpTileHandlerProjection is a GeglTileHandler that renders the
|
||||
* projection.
|
||||
*/
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GIMP_TYPE_TILE_HANDLER_PROJECTION (gimp_tile_handler_projection_get_type ())
|
||||
#define GIMP_TILE_HANDLER_PROJECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TILE_HANDLER_PROJECTION, GimpTileHandlerProjection))
|
||||
#define GIMP_TILE_HANDLER_PROJECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TILE_HANDLER_PROJECTION, GimpTileHandlerProjectionClass))
|
||||
#define GIMP_IS_TILE_HANDLER_PROJECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TILE_HANDLER_PROJECTION))
|
||||
#define GIMP_IS_TILE_HANDLER_PROJECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TILE_HANDLER_PROJECTION))
|
||||
#define GIMP_TILE_HANDLER_PROJECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TILE_HANDLER_PROJECTION, GimpTileHandlerProjectionClass))
|
||||
|
||||
|
||||
typedef struct _GimpTileHandlerProjection GimpTileHandlerProjection;
|
||||
typedef struct _GimpTileHandlerProjectionClass GimpTileHandlerProjectionClass;
|
||||
|
||||
struct _GimpTileHandlerProjection
|
||||
{
|
||||
GeglTileHandler parent_instance;
|
||||
|
||||
GeglNode *graph;
|
||||
cairo_region_t *dirty_region;
|
||||
const Babl *format;
|
||||
gint tile_width;
|
||||
gint tile_height;
|
||||
};
|
||||
|
||||
struct _GimpTileHandlerProjectionClass
|
||||
{
|
||||
GeglTileHandlerClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType gimp_tile_handler_projection_get_type (void) G_GNUC_CONST;
|
||||
GeglTileHandler * gimp_tile_handler_projection_new (GeglNode *graph);
|
||||
|
||||
void gimp_tile_handler_projection_invalidate (GimpTileHandlerProjection *projection,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GIMP_TILE_HANDLER_PROJECTION_H__ */
|
Loading…
Reference in New Issue