Blame operations/common/envelopes.h

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
}