Commit 8ef1113d authored by Ell's avatar Ell

Issue #2372 - Reduced quality of the Parametric brush in 2.10

Promote the precision of generated brushes to 32-bit float, and
modify brush preview generation, and gimpbrushcore-loops, to handle
float brushes.  This avoids posterization in large brushes.

Note that non-generated brushes are still uint8.
parent 12dde445
......@@ -270,6 +270,7 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
GimpTempBuf *return_buf = NULL;
gint mask_width;
gint mask_height;
guchar *mask_data;
guchar *mask;
guchar *buf;
gint x, y;
......@@ -327,12 +328,18 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
babl_format ("R'G'B'A u8"));
gimp_temp_buf_data_clear (return_buf);
mask = gimp_temp_buf_get_data (mask_buf);
mask = mask_data = gimp_temp_buf_lock (mask_buf, babl_format ("Y u8"),
GEGL_ACCESS_READ);
buf = gimp_temp_buf_get_data (return_buf);
if (pixmap_buf)
{
guchar *pixmap = gimp_temp_buf_get_data (pixmap_buf);
guchar *pixmap_data;
guchar *pixmap;
pixmap = pixmap_data = gimp_temp_buf_lock (pixmap_buf,
babl_format ("R'G'B' u8"),
GEGL_ACCESS_READ);
for (y = 0; y < mask_height; y++)
{
......@@ -344,6 +351,8 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
*buf++ = *mask++;
}
}
gimp_temp_buf_unlock (pixmap_buf, pixmap_data);
}
else
{
......@@ -359,6 +368,8 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
}
}
gimp_temp_buf_unlock (mask_buf, mask_data);
if (scaled)
{
gimp_temp_buf_unref ((GimpTempBuf *) mask_buf);
......
......@@ -405,11 +405,11 @@ gauss (gdouble f)
}
/* set up lookup table */
static guchar *
static gfloat *
gimp_brush_generated_calc_lut (gdouble radius,
gdouble hardness)
{
guchar *lookup;
gfloat *lookup;
gint length;
gint x;
gdouble d;
......@@ -419,7 +419,7 @@ gimp_brush_generated_calc_lut (gdouble radius,
length = OVERSAMPLING * ceil (1 + sqrt (2 * SQR (ceil (radius + 1.0))));
lookup = g_malloc (length);
lookup = gegl_scratch_new (gfloat, length);
sum = 0.0;
if ((1.0 - hardness) < 0.0000004)
......@@ -449,12 +449,12 @@ gimp_brush_generated_calc_lut (gdouble radius,
buffer[x % OVERSAMPLING] = gauss (pow (d / radius, exponent));
sum += buffer[x % OVERSAMPLING];
lookup[x++] = RINT (sum * (255.0 / OVERSAMPLING));
lookup[x++] = sum / OVERSAMPLING;
}
while (x < length)
{
lookup[x++] = 0;
lookup[x++] = 0.0f;
}
return lookup;
......@@ -472,9 +472,9 @@ gimp_brush_generated_calc (GimpBrushGenerated *brush,
GimpVector2 *xaxis,
GimpVector2 *yaxis)
{
guchar *centerp;
guchar *lookup;
guchar a;
gfloat *centerp;
gfloat *lookup;
gfloat a;
gint x, y;
gdouble c, s, cs, ss;
GimpVector2 x_axis;
......@@ -497,12 +497,12 @@ gimp_brush_generated_calc (GimpBrushGenerated *brush,
&s, &c, &x_axis, &y_axis);
mask = gimp_temp_buf_new (width, height,
babl_format ("Y u8"));
babl_format ("Y float"));
half_width = width / 2;
half_height = height / 2;
centerp = gimp_temp_buf_get_data (mask) +
centerp = (gfloat *) gimp_temp_buf_get_data (mask) +
half_height * width + half_width;
lookup = gimp_brush_generated_calc_lut (radius, hardness);
......@@ -553,7 +553,7 @@ gimp_brush_generated_calc (GimpBrushGenerated *brush,
if (d < radius + 1)
a = lookup[(gint) RINT (d * OVERSAMPLING)];
else
a = 0;
a = 0.0f;
centerp[y * width + x] = a;
......@@ -562,7 +562,7 @@ gimp_brush_generated_calc (GimpBrushGenerated *brush,
}
}
g_free (lookup);
gegl_scratch_free (lookup);
if (xaxis)
*xaxis = x_axis;
......
......@@ -7,50 +7,110 @@
#ifndef __GIMP_BRUSH_CORE_KERNELS_H__
#define __GIMP_BRUSH_CORE_KERNELS_H__
#define KERNEL_WIDTH 3
#define KERNEL_HEIGHT 3
#define KERNEL_SUBSAMPLE 4
#define KERNEL_SUM 256
/* Brush pixel subsampling kernels */
static const int subsample[5][5][9] =
#ifdef __cplusplus
template <class T>
struct Kernel;
template <>
struct Kernel<guchar>
{
using value_type = guchar;
using kernel_type = guint;
using accum_type = gulong;
static constexpr kernel_type
coeff (kernel_type x)
{
{ 64, 64, 0, 64, 64, 0, 0, 0, 0, },
{ 25, 103, 0, 25, 103, 0, 0, 0, 0, },
{ 0, 128, 0, 0, 128, 0, 0, 0, 0, },
{ 0, 103, 25, 0, 103, 25, 0, 0, 0, },
{ 0, 64, 64, 0, 64, 64, 0, 0, 0, }
},
{
{ 25, 25, 0, 103, 103, 0, 0, 0, 0, },
{ 6, 44, 0, 44, 162, 0, 0, 0, 0, },
{ 0, 50, 0, 0, 206, 0, 0, 0, 0, },
{ 0, 44, 6, 0, 162, 44, 0, 0, 0, },
{ 0, 25, 25, 0, 103, 103, 0, 0, 0, }
},
return x;
}
static constexpr value_type
round (accum_type x)
{
{ 0, 0, 0, 128, 128, 0, 0, 0, 0, },
{ 0, 0, 0, 50, 206, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 256, 0, 0, 0, 0, },
{ 0, 0, 0, 0, 206, 50, 0, 0, 0, },
{ 0, 0, 0, 0, 128, 128, 0, 0, 0, }
},
return (x + 127) / 256;
}
};
template <>
struct Kernel<gfloat>
{
using value_type = gfloat;
using kernel_type = gfloat;
using accum_type = gfloat;
static constexpr kernel_type
coeff (kernel_type x)
{
{ 0, 0, 0, 103, 103, 0, 25, 25, 0, },
{ 0, 0, 0, 44, 162, 0, 6, 44, 0, },
{ 0, 0, 0, 0, 206, 0, 0, 50, 0, },
{ 0, 0, 0, 0, 162, 44, 0, 44, 6, },
{ 0, 0, 0, 0, 103, 103, 0, 25, 25, }
},
return x / 256.0f;
}
static constexpr value_type
round (accum_type x)
{
{ 0, 0, 0, 64, 64, 0, 64, 64, 0, },
{ 0, 0, 0, 25, 103, 0, 25, 103, 0, },
{ 0, 0, 0, 0, 128, 0, 0, 128, 0, },
{ 0, 0, 0, 0, 103, 25, 0, 103, 25, },
{ 0, 0, 0, 0, 64, 64, 0, 64, 64, }
return x;
}
};
/* Brush pixel subsampling kernels */
template <class T>
struct Subsample : Kernel<T>
{
#define C(x) (Subsample::coeff (x))
static constexpr typename Subsample::kernel_type kernel[5][5][9] =
{
{
{ C( 64), C( 64), C( 0), C( 64), C( 64), C( 0), C( 0), C( 0), C( 0), },
{ C( 25), C(103), C( 0), C( 25), C(103), C( 0), C( 0), C( 0), C( 0), },
{ C( 0), C(128), C( 0), C( 0), C(128), C( 0), C( 0), C( 0), C( 0), },
{ C( 0), C(103), C( 25), C( 0), C(103), C( 25), C( 0), C( 0), C( 0), },
{ C( 0), C( 64), C( 64), C( 0), C( 64), C( 64), C( 0), C( 0), C( 0), }
},
{
{ C( 25), C( 25), C( 0), C(103), C(103), C( 0), C( 0), C( 0), C( 0), },
{ C( 6), C( 44), C( 0), C( 44), C(162), C( 0), C( 0), C( 0), C( 0), },
{ C( 0), C( 50), C( 0), C( 0), C(206), C( 0), C( 0), C( 0), C( 0), },
{ C( 0), C( 44), C( 6), C( 0), C(162), C( 44), C( 0), C( 0), C( 0), },
{ C( 0), C( 25), C( 25), C( 0), C(103), C(103), C( 0), C( 0), C( 0), }
},
{
{ C( 0), C( 0), C( 0), C(128), C(128), C( 0), C( 0), C( 0), C( 0), },
{ C( 0), C( 0), C( 0), C( 50), C(206), C( 0), C( 0), C( 0), C( 0), },
{ C( 0), C( 0), C( 0), C( 0), C(256), C( 0), C( 0), C( 0), C( 0), },
{ C( 0), C( 0), C( 0), C( 0), C(206), C( 50), C( 0), C( 0), C( 0), },
{ C( 0), C( 0), C( 0), C( 0), C(128), C(128), C( 0), C( 0), C( 0), }
},
{
{ C( 0), C( 0), C( 0), C(103), C(103), C( 0), C( 25), C( 25), C( 0), },
{ C( 0), C( 0), C( 0), C( 44), C(162), C( 0), C( 6), C( 44), C( 0), },
{ C( 0), C( 0), C( 0), C( 0), C(206), C( 0), C( 0), C( 50), C( 0), },
{ C( 0), C( 0), C( 0), C( 0), C(162), C( 44), C( 0), C( 44), C( 6), },
{ C( 0), C( 0), C( 0), C( 0), C(103), C(103), C( 0), C( 25), C( 25), }
},
{
{ C( 0), C( 0), C( 0), C( 64), C( 64), C( 0), C( 64), C( 64), C( 0), },
{ C( 0), C( 0), C( 0), C( 25), C(103), C( 0), C( 25), C(103), C( 0), },
{ C( 0), C( 0), C( 0), C( 0), C(128), C( 0), C( 0), C(128), C( 0), },
{ C( 0), C( 0), C( 0), C( 0), C(103), C( 25), C( 0), C(103), C( 25), },
{ C( 0), C( 0), C( 0), C( 0), C( 64), C( 64), C( 0), C( 64), C( 64), }
}
};
#undef C
};
template <class T>
constexpr typename Subsample<T>::kernel_type Subsample<T>::kernel[5][5][9];
#endif /* __cplusplus */
#endif /* __GIMP_BRUSH_CORE_KERNELS_H__ */
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment