|
Packit Service |
2781ba |
/* GEGL is free software; you can redistribute it and/or
|
|
Packit Service |
2781ba |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
2781ba |
* version 3 of the License, or (at your option) any later version.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit Service |
2781ba |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
2781ba |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
2781ba |
* Lesser General Public License for more details.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* Copyright 2007, 2009 Øyvind Kolås <pippin@gimp.org>
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define ANGLE_PRIME 95273 /* the lookuptables are sized as primes to ensure */
|
|
Packit Service |
2781ba |
#define RADIUS_PRIME 29537 /* as good as possible variation when using both */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gfloat lut_cos[ANGLE_PRIME];
|
|
Packit Service |
2781ba |
static gfloat lut_sin[ANGLE_PRIME];
|
|
Packit Service |
2781ba |
static gfloat radiuses[RADIUS_PRIME];
|
|
Packit Service |
2781ba |
static gdouble luts_computed = 0.0;
|
|
Packit Service |
2781ba |
static gint angle_no=0;
|
|
Packit Service |
2781ba |
static gint radius_no=0;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void compute_luts(gdouble rgamma)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint i;
|
|
Packit Service |
2781ba |
GRand *rand;
|
|
Packit Service |
2781ba |
gfloat golden_angle = G_PI * (3-sqrt(5.0)); /* http://en.wikipedia.org/wiki/Golden_angle */
|
|
Packit Service |
2781ba |
gfloat angle = 0.0;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (luts_computed==rgamma)
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
luts_computed = rgamma;
|
|
Packit Service |
2781ba |
rand = g_rand_new();
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (i=0;i
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
angle += golden_angle;
|
|
Packit Service |
2781ba |
lut_cos[i] = cos(angle);
|
|
Packit Service |
2781ba |
lut_sin[i] = sin(angle);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
for (i=0;i
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
radiuses[i] = pow(g_rand_double_range (rand, 0.0, 1.0), rgamma);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_rand_free(rand);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void
|
|
Packit Service |
2781ba |
sample (gfloat *buf,
|
|
Packit Service |
2781ba |
gint width,
|
|
Packit Service |
2781ba |
gint height,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gfloat *dst)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gfloat *pixel = (buf + ((width * y) + x) * 4);
|
|
Packit Service |
2781ba |
gint c;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (c=0;c<4;c++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
dst[c] = pixel[c];
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void
|
|
Packit Service |
2781ba |
sample_min_max (gfloat *buf,
|
|
Packit Service |
2781ba |
gint width,
|
|
Packit Service |
2781ba |
gint height,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint radius,
|
|
Packit Service |
2781ba |
gint samples,
|
|
Packit Service |
2781ba |
gfloat *min,
|
|
Packit Service |
2781ba |
gfloat *max)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gfloat best_min[3];
|
|
Packit Service |
2781ba |
gfloat best_max[3];
|
|
Packit Service |
2781ba |
gfloat *center_pix = (buf + (width * y + x) * 4);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gint i, c;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (c=0;c<3;c++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
best_min[c]=center_pix[c];
|
|
Packit Service |
2781ba |
best_max[c]=center_pix[c];
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (i=0; i
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint u, v;
|
|
Packit Service |
2781ba |
gint angle;
|
|
Packit Service |
2781ba |
gfloat rmag;
|
|
Packit Service |
2781ba |
retry: /* if we've sampled outside the valid image
|
|
Packit Service |
2781ba |
area, we grab another sample instead, this
|
|
Packit Service |
2781ba |
should potentially work better than mirroring
|
|
Packit Service |
2781ba |
or extending the image
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
angle = angle_no++;
|
|
Packit Service |
2781ba |
rmag = radiuses[radius_no++] * radius;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (angle_no>=ANGLE_PRIME)
|
|
Packit Service |
2781ba |
angle_no=0;
|
|
Packit Service |
2781ba |
if (radius_no>=RADIUS_PRIME)
|
|
Packit Service |
2781ba |
radius_no=0;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
u = x + rmag * lut_cos[angle];
|
|
Packit Service |
2781ba |
v = y + rmag * lut_sin[angle];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (u>=width ||
|
|
Packit Service |
2781ba |
u<0 ||
|
|
Packit Service |
2781ba |
v>=height ||
|
|
Packit Service |
2781ba |
v<0)
|
|
Packit Service |
2781ba |
goto retry;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gfloat *pixel = (buf + ((width * v) + u) * 4);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (pixel[3]>0.0) /* ignore fully transparent pixels */
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
for (c=0;c<3;c++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (pixel[c]
|
|
Packit Service |
2781ba |
best_min[c]=pixel[c];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (pixel[c]>best_max[c])
|
|
Packit Service |
2781ba |
best_max[c]=pixel[c];
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
goto retry;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
for (c=0;c<3;c++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
min[c]=best_min[c];
|
|
Packit Service |
2781ba |
max[c]=best_max[c];
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void compute_envelopes (gfloat *buf,
|
|
Packit Service |
2781ba |
gint width,
|
|
Packit Service |
2781ba |
gint height,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint radius,
|
|
Packit Service |
2781ba |
gint samples,
|
|
Packit Service |
2781ba |
gint iterations,
|
|
Packit Service |
2781ba |
gboolean same_spray,
|
|
Packit Service |
2781ba |
gdouble rgamma,
|
|
Packit Service |
2781ba |
gfloat *min_envelope,
|
|
Packit Service |
2781ba |
gfloat *max_envelope)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint i;
|
|
Packit Service |
2781ba |
gint c;
|
|
Packit Service |
2781ba |
gfloat range_sum[4] = {0,0,0,0};
|
|
Packit Service |
2781ba |
gfloat relative_brightness_sum[4] = {0,0,0,0};
|
|
Packit Service |
2781ba |
gfloat *pixel = buf + (width*y+x)*4;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* compute lookuptables for the gamma, currently not used/exposed
|
|
Packit Service |
2781ba |
* as a tweakable property */
|
|
Packit Service |
2781ba |
compute_luts(rgamma);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (same_spray)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
angle_no = 0;
|
|
Packit Service |
2781ba |
radius_no = 0;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (i=0;i
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gfloat min[3], max[3];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
sample_min_max (buf,
|
|
Packit Service |
2781ba |
width,
|
|
Packit Service |
2781ba |
height,
|
|
Packit Service |
2781ba |
x, y,
|
|
Packit Service |
2781ba |
radius, samples,
|
|
Packit Service |
2781ba |
min, max);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (c=0;c<3;c++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gfloat range, relative_brightness;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
range = max[c] - min[c];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (range>0.0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
relative_brightness = (pixel[c] - min[c]) / range;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
relative_brightness = 0.5;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
relative_brightness_sum[c] += relative_brightness;
|
|
Packit Service |
2781ba |
range_sum[c] += range;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (c=0;c<3;c++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gfloat relative_brightness = relative_brightness_sum[c] / iterations;
|
|
Packit Service |
2781ba |
gfloat range = range_sum[c] / iterations;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (max_envelope)
|
|
Packit Service |
2781ba |
max_envelope[c] = pixel[c] + (1.0 - relative_brightness) * range;
|
|
Packit Service |
2781ba |
if (min_envelope)
|
|
Packit Service |
2781ba |
min_envelope[c] = pixel[c] - relative_brightness * range;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|