app: add GimpBrushCache which stores brush stuff based on transform parameters

such as masks and outlines. The cache is currently very stupid and
only cacheds the last transformed object. Add caches to GimpBrush for
its mask, its pixmap and its boundary, and remove the same caches and
a ton of members from GimpBrushCore. This involves adding lots of
const qualifiers because GimpBrush returns const pointers now for
trasnformed stuff.
This commit is contained in:
Michael Natterer 2011-04-05 22:11:27 +02:00
parent 8d5ac2c780
commit 21b8007b29
11 changed files with 766 additions and 396 deletions

View File

@ -62,6 +62,8 @@ libappcore_a_sources = \
gimpbrush-load.h \
gimpbrush-transform.c \
gimpbrush-transform.h \
gimpbrushcache.c \
gimpbrushcache.h \
gimpbrushclipboard.c \
gimpbrushclipboard.h \
gimpbrushgenerated.c \

View File

@ -101,6 +101,7 @@ typedef struct _GimpToolInfo GimpToolInfo;
typedef struct _GimpDataFactory GimpDataFactory;
typedef struct _GimpData GimpData;
typedef struct _GimpBrush GimpBrush;
typedef struct _GimpBrushCache GimpBrushCache;
typedef struct _GimpBrushClipboard GimpBrushClipboard;
typedef struct _GimpBrushGenerated GimpBrushGenerated;
typedef struct _GimpBrushPipe GimpBrushPipe;

View File

@ -38,7 +38,7 @@ gimp_brush_transform_boundary_exact (GimpBrush *brush,
gdouble angle,
gdouble hardness)
{
TempBuf *mask;
const TempBuf *mask;
mask = gimp_brush_transform_mask (brush,
scale, aspect_ratio, angle, hardness);
@ -49,7 +49,7 @@ gimp_brush_transform_boundary_exact (GimpBrush *brush,
BoundSeg *bound_segs;
gint n_bound_segs;
pixel_region_init_temp_buf (&maskPR, mask,
pixel_region_init_temp_buf (&maskPR, (TempBuf *) mask,
0, 0, mask->width, mask->height);
bound_segs = boundary_find (&maskPR, BOUNDARY_WITHIN_BOUNDS,
@ -57,8 +57,6 @@ gimp_brush_transform_boundary_exact (GimpBrush *brush,
0,
&n_bound_segs);
temp_buf_free (mask);
if (bound_segs)
{
BoundSeg *stroke_segs;

View File

@ -18,6 +18,7 @@
#include "config.h"
#include <glib-object.h>
#include <cairo.h>
#include "libgimpbase/gimpbase.h"
#include "libgimpmath/gimpmath.h"
@ -26,10 +27,12 @@
#include "base/temp-buf.h"
#include "gimpbezierdesc.h"
#include "gimpbrush.h"
#include "gimpbrush-boundary.h"
#include "gimpbrush-load.h"
#include "gimpbrush-transform.h"
#include "gimpbrushcache.h"
#include "gimpbrushgenerated.h"
#include "gimpmarshal.h"
#include "gimptagged.h"
@ -52,6 +55,7 @@ enum
static void gimp_brush_tagged_iface_init (GimpTaggedInterface *iface);
static void gimp_brush_finalize (GObject *object);
static void gimp_brush_set_property (GObject *object,
guint property_id,
const GValue *value,
@ -60,7 +64,6 @@ static void gimp_brush_get_property (GObject *obj
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_brush_finalize (GObject *object);
static gint64 gimp_brush_get_memsize (GimpObject *object,
gint64 *gui_size);
@ -74,6 +77,8 @@ static TempBuf * gimp_brush_get_new_preview (GimpViewable *vie
gint height);
static gchar * gimp_brush_get_description (GimpViewable *viewable,
gchar **tooltip);
static void gimp_brush_dirty (GimpData *data);
static const gchar * gimp_brush_get_extension (GimpData *data);
static GimpBrush * gimp_brush_real_select_brush (GimpBrush *brush,
@ -112,9 +117,9 @@ gimp_brush_class_init (GimpBrushClass *klass)
gimp_marshal_VOID__VOID,
G_TYPE_NONE, 0);
object_class->finalize = gimp_brush_finalize;
object_class->get_property = gimp_brush_get_property;
object_class->set_property = gimp_brush_set_property;
object_class->finalize = gimp_brush_finalize;
gimp_object_class->get_memsize = gimp_brush_get_memsize;
@ -123,6 +128,7 @@ gimp_brush_class_init (GimpBrushClass *klass)
viewable_class->get_new_preview = gimp_brush_get_new_preview;
viewable_class->get_description = gimp_brush_get_description;
data_class->dirty = gimp_brush_dirty;
data_class->get_extension = gimp_brush_get_extension;
klass->select_brush = gimp_brush_real_select_brush;
@ -160,6 +166,44 @@ gimp_brush_init (GimpBrush *brush)
brush->y_axis.y = 15.0;
}
static void
gimp_brush_finalize (GObject *object)
{
GimpBrush *brush = GIMP_BRUSH (object);
if (brush->mask)
{
temp_buf_free (brush->mask);
brush->mask = NULL;
}
if (brush->pixmap)
{
temp_buf_free (brush->pixmap);
brush->pixmap = NULL;
}
if (brush->mask_cache)
{
g_object_unref (brush->mask_cache);
brush->mask_cache = NULL;
}
if (brush->pixmap_cache)
{
g_object_unref (brush->pixmap_cache);
brush->pixmap_cache = NULL;
}
if (brush->boundary_cache)
{
g_object_unref (brush->boundary_cache);
brush->boundary_cache = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_brush_set_property (GObject *object,
guint property_id,
@ -200,26 +244,6 @@ gimp_brush_get_property (GObject *object,
}
}
static void
gimp_brush_finalize (GObject *object)
{
GimpBrush *brush = GIMP_BRUSH (object);
if (brush->mask)
{
temp_buf_free (brush->mask);
brush->mask = NULL;
}
if (brush->pixmap)
{
temp_buf_free (brush->pixmap);
brush->pixmap = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gint64
gimp_brush_get_memsize (GimpObject *object,
gint64 *gui_size)
@ -254,8 +278,9 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
gint height)
{
GimpBrush *brush = GIMP_BRUSH (viewable);
TempBuf *mask_buf = NULL;
TempBuf *pixmap_buf = NULL;
const TempBuf *mask_buf = NULL;
gboolean free_mask = FALSE;
const TempBuf *pixmap_buf = NULL;
TempBuf *return_buf = NULL;
gint mask_width;
gint mask_height;
@ -279,13 +304,20 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
if (scale != 1.0)
{
mask_buf = gimp_brush_transform_mask (brush, scale, 0.0, 0.0, 1.0);
gimp_brush_start_use (brush);
mask_buf = gimp_brush_transform_mask (brush, scale,
0.0, 0.0, 1.0);
if (! mask_buf)
{
mask_buf = temp_buf_new (1, 1, 1, 0, 0, transp);
free_mask = TRUE;
}
if (pixmap_buf)
pixmap_buf = gimp_brush_transform_pixmap (brush, scale, 0.0, 0.0, 1.0);
pixmap_buf = gimp_brush_transform_pixmap (brush, scale,
0.0, 0.0, 1.0);
mask_width = mask_buf->width;
mask_height = mask_buf->height;
@ -330,10 +362,10 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
if (scaled)
{
temp_buf_free (mask_buf);
if (free_mask)
temp_buf_free ((TempBuf *) mask_buf);
if (pixmap_buf)
temp_buf_free (pixmap_buf);
gimp_brush_end_use (brush);
}
return return_buf;
@ -351,6 +383,23 @@ gimp_brush_get_description (GimpViewable *viewable,
brush->mask->height);
}
static void
gimp_brush_dirty (GimpData *data)
{
GimpBrush *brush = GIMP_BRUSH (data);
if (brush->mask_cache)
gimp_brush_cache_clear (brush->mask_cache);
if (brush->pixmap_cache)
gimp_brush_cache_clear (brush->pixmap_cache);
if (brush->boundary_cache)
gimp_brush_cache_clear (brush->boundary_cache);
GIMP_DATA_CLASS (parent_class)->dirty (data);
}
static const gchar *
gimp_brush_get_extension (GimpData *data)
{
@ -486,54 +535,106 @@ gimp_brush_transform_size (GimpBrush *brush,
width, height);
}
TempBuf *
const TempBuf *
gimp_brush_transform_mask (GimpBrush *brush,
gdouble scale,
gdouble aspect_ratio,
gdouble angle,
gdouble hardness)
{
const TempBuf *mask;
gint width;
gint height;
g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
g_return_val_if_fail (scale > 0.0, NULL);
gimp_brush_transform_size (brush,
scale, aspect_ratio, angle,
&width, &height);
mask = gimp_brush_cache_get (brush->mask_cache,
width, height,
scale, aspect_ratio, angle, hardness);
if (! mask)
{
if (scale == 1.0 &&
aspect_ratio == 0.0 &&
angle == 0.0 &&
hardness == 1.0)
{
return temp_buf_copy (brush->mask, NULL);
mask = temp_buf_copy (brush->mask, NULL);
}
else
{
mask = GIMP_BRUSH_GET_CLASS (brush)->transform_mask (brush,
scale,
aspect_ratio,
angle,
hardness);
}
return GIMP_BRUSH_GET_CLASS (brush)->transform_mask (brush,
scale, aspect_ratio,
angle, hardness);
gimp_brush_cache_add (brush->mask_cache,
(gpointer) mask,
width, height,
scale, aspect_ratio, angle, hardness);
}
return mask;
}
TempBuf *
const TempBuf *
gimp_brush_transform_pixmap (GimpBrush *brush,
gdouble scale,
gdouble aspect_ratio,
gdouble angle,
gdouble hardness)
{
const TempBuf *pixmap;
gint width;
gint height;
g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
g_return_val_if_fail (brush->pixmap != NULL, NULL);
g_return_val_if_fail (scale > 0.0, NULL);
gimp_brush_transform_size (brush,
scale, aspect_ratio, angle,
&width, &height);
pixmap = gimp_brush_cache_get (brush->pixmap_cache,
width, height,
scale, aspect_ratio, angle, hardness);
if (! pixmap)
{
if (scale == 1.0 &&
aspect_ratio == 0.0 &&
angle == 0.0 &&
hardness == 1.0)
{
return temp_buf_copy (brush->pixmap, NULL);
pixmap = temp_buf_copy (brush->pixmap, NULL);
}
else
{
pixmap = GIMP_BRUSH_GET_CLASS (brush)->transform_pixmap (brush,
scale,
aspect_ratio,
angle,
hardness);
}
return GIMP_BRUSH_GET_CLASS (brush)->transform_pixmap (brush,
scale, aspect_ratio,
angle, hardness);
gimp_brush_cache_add (brush->pixmap_cache,
(gpointer) pixmap,
width, height,
scale, aspect_ratio, angle, hardness);
}
return pixmap;
}
GimpBezierDesc *
const GimpBezierDesc *
gimp_brush_transform_boundary (GimpBrush *brush,
gdouble scale,
gdouble aspect_ratio,
@ -542,15 +643,38 @@ gimp_brush_transform_boundary (GimpBrush *brush,
gint *width,
gint *height)
{
const GimpBezierDesc *boundary;
g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
g_return_val_if_fail (scale > 0.0, NULL);
g_return_val_if_fail (width != NULL, NULL);
g_return_val_if_fail (height != NULL, NULL);
return GIMP_BRUSH_GET_CLASS (brush)->transform_boundary (brush,
scale, aspect_ratio,
angle, hardness,
gimp_brush_transform_size (brush,
scale, aspect_ratio, angle,
width, height);
boundary = gimp_brush_cache_get (brush->boundary_cache,
*width, *height,
scale, aspect_ratio, angle, hardness);
if (! boundary)
{
boundary = GIMP_BRUSH_GET_CLASS (brush)->transform_boundary (brush,
scale,
aspect_ratio,
angle,
hardness,
width,
height);
gimp_brush_cache_add (brush->boundary_cache,
(gpointer) boundary,
*width, *height,
scale, aspect_ratio, angle, hardness);
}
return boundary;
}
gdouble
@ -612,6 +736,18 @@ gimp_brush_start_use (GimpBrush *brush)
g_return_if_fail (GIMP_IS_BRUSH (brush));
brush->use_count++;
if (brush->use_count == 1)
{
brush->mask_cache =
gimp_brush_cache_new ((GDestroyNotify) temp_buf_free, 'M', 'm');
brush->pixmap_cache =
gimp_brush_cache_new ((GDestroyNotify) temp_buf_free, 'P', 'p');
brush->boundary_cache =
gimp_brush_cache_new ((GDestroyNotify) gimp_bezier_desc_free, 'B', 'b');
}
}
void
@ -624,6 +760,13 @@ gimp_brush_end_use (GimpBrush *brush)
if (brush->use_count == 0)
{
/* flush caches */
g_object_unref (brush->mask_cache);
brush->mask_cache = NULL;
g_object_unref (brush->pixmap_cache);
brush->pixmap_cache = NULL;
g_object_unref (brush->boundary_cache);
brush->boundary_cache = NULL;
}
}

View File

@ -45,6 +45,9 @@ struct _GimpBrush
GimpVector2 y_axis; /* for calculating brush spacing */
gint use_count; /* for keeping the caches alive */
GimpBrushCache *mask_cache;
GimpBrushCache *pixmap_cache;
GimpBrushCache *boundary_cache;
};
struct _GimpBrushClass
@ -109,17 +112,17 @@ void gimp_brush_transform_size (GimpBrush *brush,
gdouble angle,
gint *width,
gint *height);
TempBuf * gimp_brush_transform_mask (GimpBrush *brush,
const TempBuf * gimp_brush_transform_mask (GimpBrush *brush,
gdouble scale,
gdouble aspect_ratio,
gdouble angle,
gdouble hardness);
TempBuf * gimp_brush_transform_pixmap (GimpBrush *brush,
const TempBuf * gimp_brush_transform_pixmap (GimpBrush *brush,
gdouble scale,
gdouble aspect_ratio,
gdouble angle,
gdouble hardness);
GimpBezierDesc * gimp_brush_transform_boundary (GimpBrush *brush,
const GimpBezierDesc * gimp_brush_transform_boundary (GimpBrush *brush,
gdouble scale,
gdouble aspect_ratio,
gdouble angle,

232
app/core/gimpbrushcache.c Normal file
View File

@ -0,0 +1,232 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpbrushcache.c
* Copyright (C) 2011 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 <gegl.h>
#include "core-types.h"
#include "gimpbrushcache.h"
#include "gimp-intl.h"
enum
{
PROP_0,
PROP_DATA_DESTROY
};
static void gimp_brush_cache_constructed (GObject *object);
static void gimp_brush_cache_finalize (GObject *object);
static void gimp_brush_cache_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_brush_cache_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (GimpBrushCache, gimp_brush_cache, GIMP_TYPE_OBJECT)
#define parent_class gimp_brush_cache_parent_class
static void
gimp_brush_cache_class_init (GimpBrushCacheClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = gimp_brush_cache_constructed;
object_class->finalize = gimp_brush_cache_finalize;
object_class->set_property = gimp_brush_cache_set_property;
object_class->get_property = gimp_brush_cache_get_property;
g_object_class_install_property (object_class, PROP_DATA_DESTROY,
g_param_spec_pointer ("data-destroy",
NULL, NULL,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
gimp_brush_cache_init (GimpBrushCache *brush)
{
}
static void
gimp_brush_cache_constructed (GObject *object)
{
GimpBrushCache *cache = GIMP_BRUSH_CACHE (object);
if (G_OBJECT_CLASS (parent_class)->constructed)
G_OBJECT_CLASS (parent_class)->constructed (object);
g_assert (cache->data_destroy != NULL);
}
static void
gimp_brush_cache_finalize (GObject *object)
{
GimpBrushCache *cache = GIMP_BRUSH_CACHE (object);
if (cache->last_data)
{
cache->data_destroy (cache->last_data);
cache->last_data = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_brush_cache_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpBrushCache *cache = GIMP_BRUSH_CACHE (object);
switch (property_id)
{
case PROP_DATA_DESTROY:
cache->data_destroy = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_brush_cache_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpBrushCache *cache = GIMP_BRUSH_CACHE (object);
switch (property_id)
{
case PROP_DATA_DESTROY:
g_value_set_pointer (value, cache->data_destroy);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* public functions */
GimpBrushCache *
gimp_brush_cache_new (GDestroyNotify data_destroy,
gchar debug_hit,
gchar debug_miss)
{
GimpBrushCache *cache;
g_return_val_if_fail (data_destroy != NULL, NULL);
cache = g_object_new (GIMP_TYPE_BRUSH_CACHE,
"data-destroy", data_destroy,
NULL);
cache->debug_hit = debug_hit;
cache->debug_miss = debug_miss;
return cache;
}
void
gimp_brush_cache_clear (GimpBrushCache *cache)
{
g_return_if_fail (GIMP_IS_BRUSH_CACHE (cache));
if (cache->last_data)
{
cache->data_destroy (cache->last_data);
cache->last_data = NULL;
}
}
gconstpointer
gimp_brush_cache_get (GimpBrushCache *cache,
gint width,
gint height,
gdouble scale,
gdouble aspect_ratio,
gdouble angle,
gdouble hardness)
{
g_return_val_if_fail (GIMP_IS_BRUSH_CACHE (cache), NULL);
if (cache->last_data &&
cache->last_width == width &&
cache->last_height == height &&
cache->last_scale == scale &&
cache->last_aspect_ratio == aspect_ratio &&
cache->last_angle == angle &&
cache->last_hardness == hardness)
{
g_printerr ("%c", cache->debug_hit);
return (gconstpointer) cache->last_data;
}
g_printerr ("%c", cache->debug_miss);
return NULL;
}
void
gimp_brush_cache_add (GimpBrushCache *cache,
gpointer data,
gint width,
gint height,
gdouble scale,
gdouble aspect_ratio,
gdouble angle,
gdouble hardness)
{
g_return_if_fail (GIMP_IS_BRUSH_CACHE (cache));
g_return_if_fail (data != NULL);
if (data == cache->last_data)
return;
if (cache->last_data)
cache->data_destroy (cache->last_data);
cache->last_data = data;
cache->last_width = width;
cache->last_height = height;
cache->last_scale = scale;
cache->last_aspect_ratio = aspect_ratio;
cache->last_angle = angle;
cache->last_hardness = hardness;
}

87
app/core/gimpbrushcache.h Normal file
View File

@ -0,0 +1,87 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpbrushcache.h
* Copyright (C) 2011 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/>.
*/
#ifndef __GIMP_BRUSH_CACHE_H__
#define __GIMP_BRUSH_CACHE_H__
#include "gimpobject.h"
#define GIMP_TYPE_BRUSH_CACHE (gimp_brush_cache_get_type ())
#define GIMP_BRUSH_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_BRUSH_CACHE, GimpBrushCache))
#define GIMP_BRUSH_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_BRUSH_CACHE, GimpBrushCacheClass))
#define GIMP_IS_BRUSH_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_BRUSH_CACHE))
#define GIMP_IS_BRUSH_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_BRUSH_CACHE))
#define GIMP_BRUSH_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_BRUSH_CACHE, GimpBrushCacheClass))
typedef struct _GimpBrushCacheClass GimpBrushCacheClass;
struct _GimpBrushCache
{
GimpObject parent_instance;
GDestroyNotify data_destroy;
gpointer last_data;
gint last_width;
gint last_height;
gdouble last_scale;
gdouble last_aspect_ratio;
gdouble last_angle;
gdouble last_hardness;
gchar debug_hit;
gchar debug_miss;
};
struct _GimpBrushCacheClass
{
GimpObjectClass parent_class;
};
GType gimp_brush_cache_get_type (void) G_GNUC_CONST;
GimpBrushCache * gimp_brush_cache_new (GDestroyNotify data_destory,
gchar debug_hit,
gchar debug_miss);
void gimp_brush_cache_clear (GimpBrushCache *cache);
gconstpointer gimp_brush_cache_get (GimpBrushCache *cache,
gint width,
gint height,
gdouble scale,
gdouble aspect_ratio,
gdouble angle,
gdouble hardness);
void gimp_brush_cache_add (GimpBrushCache *cache,
gpointer data,
gint width,
gint height,
gdouble scale,
gdouble aspect_ratio,
gdouble angle,
gdouble hardness);
#endif /* __GIMP_BRUSH_CACHE_H__ */

View File

@ -80,7 +80,7 @@ static void gimp_brush_core_interpolate (GimpPaintCore *core,
GimpPaintOptions *paint_options,
guint32 time);
static TempBuf *gimp_brush_core_get_paint_area (GimpPaintCore *paint_core,
static TempBuf * gimp_brush_core_get_paint_area (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GimpPaintOptions *paint_options,
const GimpCoords *coords);
@ -90,35 +90,32 @@ static void gimp_brush_core_real_set_brush (GimpBrushCore *core,
static void gimp_brush_core_real_set_dynamics (GimpBrushCore *core,
GimpDynamics *dynamics);
static inline void rotate_pointers (gulong **p,
guint32 n);
static TempBuf * gimp_brush_core_subsample_mask (GimpBrushCore *core,
TempBuf *mask,
static const TempBuf * gimp_brush_core_subsample_mask (GimpBrushCore *core,
const TempBuf *mask,
gdouble x,
gdouble y);
static TempBuf * gimp_brush_core_pressurize_mask (GimpBrushCore *core,
TempBuf *brush_mask,
static const TempBuf * gimp_brush_core_pressurize_mask (GimpBrushCore *core,
const TempBuf *brush_mask,
gdouble x,
gdouble y,
gdouble pressure);
static TempBuf * gimp_brush_core_solidify_mask (GimpBrushCore *core,
TempBuf *brush_mask,
static const TempBuf * gimp_brush_core_solidify_mask (GimpBrushCore *core,
const TempBuf *brush_mask,
gdouble x,
gdouble y);
static TempBuf * gimp_brush_core_transform_mask (GimpBrushCore *core,
static const TempBuf * gimp_brush_core_transform_mask (GimpBrushCore *core,
GimpBrush *brush);
static TempBuf * gimp_brush_core_transform_pixmap (GimpBrushCore *core,
static const TempBuf * gimp_brush_core_transform_pixmap (GimpBrushCore *core,
GimpBrush *brush);
static void gimp_brush_core_invalidate_cache (GimpBrush *brush,
GimpBrushCore *core);
/* brush pipe utility functions */
static void paint_line_pixmap_mask (GimpImage *dest,
static void gimp_brush_core_paint_line_pixmap_mask (GimpImage *dest,
GimpDrawable *drawable,
TempBuf *pixmap_mask,
TempBuf *brush_mask,
const TempBuf *pixmap_mask,
const TempBuf *brush_mask,
guchar *d,
gint x,
gint y,
@ -192,19 +189,12 @@ gimp_brush_core_init (GimpBrushCore *core)
core->pressure_brush = NULL;
core->last_solid_brush = NULL;
core->last_solid_brush_mask = NULL;
core->solid_cache_invalid = FALSE;
core->transform_brush = NULL;
core->last_transform_brush = NULL;
core->last_transform_width = 0;
core->last_transform_height = 0;
core->last_scale = 1.0;
core->transform_pixmap = NULL;
core->last_transform_pixmap = NULL;
core->last_transform_pixmap_width = 0;
core->last_transform_pixmap_height = 0;
core->last_brush_mask = NULL;
core->cache_invalid = FALSE;
@ -259,18 +249,6 @@ gimp_brush_core_finalize (GObject *object)
core->solid_brushes[i][j] = NULL;
}
if (core->transform_brush)
{
temp_buf_free (core->transform_brush);
core->transform_brush = NULL;
}
if (core->transform_pixmap)
{
temp_buf_free (core->transform_pixmap);
core->transform_pixmap = NULL;
}
if (core->rand)
{
g_rand_free (core->rand);
@ -934,7 +912,7 @@ gimp_brush_core_paste_canvas (GimpBrushCore *core,
gdouble dynamic_force,
GimpPaintApplicationMode mode)
{
TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core,
const TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core,
coords,
brush_hardness,
dynamic_force);
@ -954,7 +932,7 @@ gimp_brush_core_paste_canvas (GimpBrushCore *core,
off_x = (x < 0) ? -x : 0;
off_y = (y < 0) ? -y : 0;
pixel_region_init_temp_buf (&brush_maskPR, brush_mask,
pixel_region_init_temp_buf (&brush_maskPR, (TempBuf *) brush_mask,
off_x, off_y,
paint_core->canvas_buf->width,
paint_core->canvas_buf->height);
@ -980,7 +958,7 @@ gimp_brush_core_replace_canvas (GimpBrushCore *core,
gdouble dynamic_force,
GimpPaintApplicationMode mode)
{
TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core,
const TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core,
coords,
brush_hardness,
dynamic_force);
@ -1000,7 +978,7 @@ gimp_brush_core_replace_canvas (GimpBrushCore *core,
off_x = (x < 0) ? -x : 0;
off_y = (y < 0) ? -y : 0;
pixel_region_init_temp_buf (&brush_maskPR, brush_mask,
pixel_region_init_temp_buf (&brush_maskPR, (TempBuf *) brush_mask,
off_x, off_y,
paint_core->canvas_buf->width,
paint_core->canvas_buf->height);
@ -1047,9 +1025,9 @@ rotate_pointers (gulong **p,
p[i] = tmp;
}
static TempBuf *
static const TempBuf *
gimp_brush_core_subsample_mask (GimpBrushCore *core,
TempBuf *mask,
const TempBuf *mask,
gdouble x,
gdouble y)
{
@ -1181,9 +1159,9 @@ gimp_brush_core_subsample_mask (GimpBrushCore *core,
/* #define FANCY_PRESSURE */
static TempBuf *
static const TempBuf *
gimp_brush_core_pressurize_mask (GimpBrushCore *core,
TempBuf *brush_mask,
const TempBuf *brush_mask,
gdouble x,
gdouble y,
gdouble pressure)
@ -1191,7 +1169,7 @@ gimp_brush_core_pressurize_mask (GimpBrushCore *core,
static guchar mapi[256];
const guchar *source;
guchar *dest;
TempBuf *subsample_mask;
const TempBuf *subsample_mask;
const guchar empty = TRANSPARENT_OPACITY;
gint i;
@ -1296,9 +1274,9 @@ gimp_brush_core_pressurize_mask (GimpBrushCore *core,
return core->pressure_brush;
}
static TempBuf *
static const TempBuf *
gimp_brush_core_solidify_mask (GimpBrushCore *core,
TempBuf *brush_mask,
const TempBuf *brush_mask,
gdouble x,
gdouble y)
{
@ -1329,7 +1307,7 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core,
}
if (! core->solid_cache_invalid &&
brush_mask == core->last_solid_brush)
brush_mask == core->last_solid_brush_mask)
{
if (core->solid_brushes[dest_offset_y][dest_offset_x])
return core->solid_brushes[dest_offset_y][dest_offset_x];
@ -1344,7 +1322,7 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core,
core->solid_brushes[i][j] = NULL;
}
core->last_solid_brush = brush_mask;
core->last_solid_brush_mask = brush_mask;
core->solid_cache_invalid = FALSE;
}
@ -1370,123 +1348,62 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core,
return dest;
}
static TempBuf *
static const TempBuf *
gimp_brush_core_transform_mask (GimpBrushCore *core,
GimpBrush *brush)
{
gint width;
gint height;
const TempBuf *mask;
if (core->scale <= 0.0)
return NULL; /* Should never happen now, with scale clamping. */
if ((core->scale == 1.0) &&
(core->angle == 0.0) &&
(core->hardness == 1.0) &&
(core->aspect_ratio == 0.0))
return brush->mask;
gimp_brush_transform_size (brush,
core->scale, core->aspect_ratio, core->angle,
&width, &height);
if (! core->cache_invalid &&
core->transform_brush &&
brush->mask == core->last_transform_brush &&
width == core->last_transform_width &&
height == core->last_transform_height &&
core->scale == core->last_scale &&
core->angle == core->last_angle &&
core->hardness == core->last_hardness &&
core->aspect_ratio == core->last_aspect_ratio)
{
return core->transform_brush;
}
core->last_transform_brush = brush->mask;
core->last_transform_width = width;
core->last_transform_height = height;
core->last_scale = core->scale;
core->last_angle = core->angle;
core->last_hardness = core->hardness;
core->last_aspect_ratio = core->aspect_ratio;
if (core->transform_brush)
temp_buf_free (core->transform_brush);
core->transform_brush = gimp_brush_transform_mask (brush,
mask = gimp_brush_transform_mask (brush,
core->scale,
core->aspect_ratio,
core->angle,
core->hardness);
if (mask == core->transform_brush)
return mask;
core->transform_brush = mask;
core->cache_invalid = TRUE;
core->solid_cache_invalid = TRUE;
return core->transform_brush;
}
static TempBuf *
static const TempBuf *
gimp_brush_core_transform_pixmap (GimpBrushCore *core,
GimpBrush *brush)
{
gint width;
gint height;
const TempBuf *pixmap;
if (core->scale <= 0.0)
return NULL;
if ((core->scale == 1.0) &&
(core->angle == 0.0) &&
(core->hardness == 1.0) &&
(core->aspect_ratio == 0.0))
return brush->pixmap;
gimp_brush_transform_size (brush,
core->scale, core->aspect_ratio, core->angle,
&width, &height);
if (! core->cache_invalid &&
core->transform_pixmap &&
brush->pixmap == core->last_transform_pixmap &&
width == core->last_transform_pixmap_width &&
height == core->last_transform_pixmap_height &&
core->angle == core->last_angle &&
core->hardness == core->last_hardness &&
core->aspect_ratio == core->last_aspect_ratio)
{
return core->transform_pixmap;
}
core->last_transform_pixmap = brush->pixmap;
core->last_transform_pixmap_width = width;
core->last_transform_pixmap_height = height;
core->last_angle = core->angle;
core->last_hardness = core->hardness;
core->last_aspect_ratio = core->aspect_ratio;
if (core->transform_pixmap)
temp_buf_free (core->transform_pixmap);
core->transform_pixmap = gimp_brush_transform_pixmap (brush,
pixmap = gimp_brush_transform_pixmap (brush,
core->scale,
core->aspect_ratio,
core->angle,
core->hardness);
if (pixmap == core->transform_pixmap)
return pixmap;
core->transform_pixmap = pixmap;
core->cache_invalid = TRUE;
return core->transform_pixmap;
}
TempBuf *
const TempBuf *
gimp_brush_core_get_brush_mask (GimpBrushCore *core,
const GimpCoords *coords,
GimpBrushApplicationMode brush_hardness,
gdouble dynamic_force)
{
TempBuf *mask;
const TempBuf *mask;
mask = gimp_brush_core_transform_mask (core, core->brush);
@ -1496,29 +1413,26 @@ gimp_brush_core_get_brush_mask (GimpBrushCore *core,
switch (brush_hardness)
{
case GIMP_BRUSH_SOFT:
mask = gimp_brush_core_subsample_mask (core, mask,
return gimp_brush_core_subsample_mask (core, mask,
coords->x,
coords->y);
break;
case GIMP_BRUSH_HARD:
mask = gimp_brush_core_solidify_mask (core, mask,
return gimp_brush_core_solidify_mask (core, mask,
coords->x,
coords->y);
break;
case GIMP_BRUSH_PRESSURE:
mask = gimp_brush_core_pressurize_mask (core, mask,
return gimp_brush_core_pressurize_mask (core, mask,
coords->x,
coords->y,
dynamic_force);
break;
default:
break;
}
return mask;
g_return_val_if_reached (NULL);
}
void
@ -1625,8 +1539,8 @@ gimp_brush_core_color_area_with_pixmap (GimpBrushCore *core,
gint offsetx;
gint offsety;
gint y;
TempBuf *pixmap_mask;
TempBuf *brush_mask;
const TempBuf *pixmap_mask;
const TempBuf *brush_mask;
g_return_if_fail (GIMP_IS_BRUSH (core->brush));
g_return_if_fail (core->brush->pixmap != NULL);
@ -1672,7 +1586,8 @@ gimp_brush_core_color_area_with_pixmap (GimpBrushCore *core,
for (y = 0; y < destPR.h; y++)
{
paint_line_pixmap_mask (image, drawable, pixmap_mask, brush_mask,
gimp_brush_core_paint_line_pixmap_mask (image, drawable,
pixmap_mask, brush_mask,
d, offsetx, y + offsety,
destPR.bytes, destPR.w, mode);
d += destPR.rowstride;
@ -1681,10 +1596,10 @@ gimp_brush_core_color_area_with_pixmap (GimpBrushCore *core,
}
static void
paint_line_pixmap_mask (GimpImage *dest,
gimp_brush_core_paint_line_pixmap_mask (GimpImage *dest,
GimpDrawable *drawable,
TempBuf *pixmap_mask,
TempBuf *brush_mask,
const TempBuf *pixmap_mask,
const TempBuf *brush_mask,
guchar *d,
gint x,
gint y,

View File

@ -55,26 +55,15 @@ struct _GimpBrushCore
TempBuf *pressure_brush;
TempBuf *solid_brushes[BRUSH_CORE_SOLID_SUBSAMPLE][BRUSH_CORE_SOLID_SUBSAMPLE];
TempBuf *last_solid_brush;
const TempBuf *last_solid_brush_mask;
gboolean solid_cache_invalid;
TempBuf *transform_brush;
TempBuf *last_transform_brush;
gint last_transform_width;
gint last_transform_height;
gdouble last_scale;
gdouble last_angle;
gdouble last_hardness;
gdouble last_aspect_ratio;
TempBuf *transform_pixmap;
TempBuf *last_transform_pixmap;
gint last_transform_pixmap_width;
gint last_transform_pixmap_height;
const TempBuf *transform_brush;
const TempBuf *transform_pixmap;
TempBuf *kernel_brushes[BRUSH_CORE_SUBSAMPLE + 1][BRUSH_CORE_SUBSAMPLE + 1];
TempBuf *last_brush_mask;
const TempBuf *last_brush_mask;
gboolean cache_invalid;
gdouble jitter;
@ -93,6 +82,7 @@ struct _GimpBrushCoreClass
/* Set for tools that don't mind if the brush scales while painting */
gboolean handles_transforming_brush;
/* Set for tools that don't mind if the brush scales mid stroke */
gboolean handles_dynamic_transforming_brush;
@ -136,15 +126,17 @@ void gimp_brush_core_color_area_with_pixmap
TempBuf *area,
GimpBrushApplicationMode mode);
TempBuf * gimp_brush_core_get_brush_mask (GimpBrushCore *core,
const TempBuf * gimp_brush_core_get_brush_mask
(GimpBrushCore *core,
const GimpCoords *coords,
GimpBrushApplicationMode brush_hardness,
gdouble dynamic_hardness);
void gimp_brush_core_eval_transform_dynamics (GimpPaintCore *paint_core,
void gimp_brush_core_eval_transform_dynamics
(GimpPaintCore *paint_core,
GimpDrawable *drawable,
GimpPaintOptions *paint_options,
const GimpCoords *coords);
#endif /* __GIMP_BRUSH_CORE_H__ */

View File

@ -84,7 +84,7 @@ static void gimp_heal_laplace_loop (gdouble *matrix,
static PixelRegion *gimp_heal_region (PixelRegion *tempPR,
PixelRegion *srcPR,
TempBuf *mask_buf);
const TempBuf *mask_buf);
static void gimp_heal_motion (GimpSourceCore *source_core,
GimpDrawable *drawable,
@ -389,7 +389,7 @@ gimp_heal_laplace_loop (gdouble *matrix,
static PixelRegion *
gimp_heal_region (PixelRegion *tempPR,
PixelRegion *srcPR,
TempBuf *mask_buf)
const TempBuf *mask_buf)
{
gdouble *i_1 = g_new (gdouble, tempPR->h * tempPR->bytes * tempPR->w);
gdouble *i_2 = g_new (gdouble, tempPR->h * tempPR->bytes * tempPR->w);
@ -442,7 +442,7 @@ gimp_heal_motion (GimpSourceCore *source_core,
PixelRegion tempPR;
PixelRegion destPR;
GimpImageType src_type;
TempBuf *mask_buf;
const TempBuf *mask_buf;
gdouble fade_point;
gdouble hardness;

View File

@ -299,7 +299,7 @@ gimp_brush_tool_draw_brush (GimpBrushTool *brush_tool,
GimpBrushCore *brush_core;
GimpPaintOptions *options;
GimpDisplayShell *shell;
GimpBezierDesc *boundary = NULL;
const GimpBezierDesc *boundary = NULL;
gint width = 0;
gint height = 0;
@ -353,9 +353,6 @@ gimp_brush_tool_draw_brush (GimpBrushTool *brush_tool,
x, y,
5, 5, GIMP_HANDLE_ANCHOR_CENTER);
}
if (boundary)
gimp_bezier_desc_free (boundary);
}
static void