Blame gegl/buffer/gegl-sampler-linear.c

Packit bc1512
/* This file is part of GEGL
Packit bc1512
 *
Packit bc1512
 * GEGL is free software; you can redistribute it and/or modify it
Packit bc1512
 * under the terms of the GNU Lesser General Public License as
Packit bc1512
 * published by the Free Software Foundation; either version 3 of the
Packit bc1512
 * License, or (at your option) any later version.
Packit bc1512
 *
Packit bc1512
 * GEGL is distributed in the hope that it will be useful, but WITHOUT
Packit bc1512
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit bc1512
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
Packit bc1512
 * Public License for more details.
Packit bc1512
 *
Packit bc1512
 * You should have received a copy of the GNU Lesser General Public
Packit bc1512
 * License along with GEGL; if not, see
Packit bc1512
 * <http://www.gnu.org/licenses/>.
Packit bc1512
 *
Packit bc1512
 */
Packit bc1512
Packit bc1512
Packit bc1512
/*
Packit bc1512
 * FAST_PSEUDO_FLOOR is a floor and floorf replacement which has been
Packit bc1512
 * found to be faster on several linux boxes than the library
Packit bc1512
 * version. It returns the floor of its argument unless the argument
Packit bc1512
 * is a negative integer, in which case it returns one less than the
Packit bc1512
 * floor. For example:
Packit bc1512
 *
Packit bc1512
 * FAST_PSEUDO_FLOOR(0.5) = 0
Packit bc1512
 *
Packit bc1512
 * FAST_PSEUDO_FLOOR(0.f) = 0
Packit bc1512
 *
Packit bc1512
 * FAST_PSEUDO_FLOOR(-.5) = -1
Packit bc1512
 *
Packit bc1512
 * as expected, but
Packit bc1512
 *
Packit bc1512
 * FAST_PSEUDO_FLOOR(-1.f) = -2
Packit bc1512
 *
Packit bc1512
 * The locations of the discontinuities of FAST_PSEUDO_FLOOR are the
Packit bc1512
 * same as floor and floorf; it is just that at negative integers the
Packit bc1512
 * function is discontinuous on the right instead of the left.
Packit bc1512
 */
Packit bc1512
#define FAST_PSEUDO_FLOOR(x) ( (int)(x) - ( (x) < 0. ) )
Packit bc1512
/*
Packit bc1512
 * Alternative (if conditional move is fast and correctly identified
Packit bc1512
 * by the compiler):
Packit bc1512
 *
Packit bc1512
 * #define FAST_PSEUDO_FLOOR(x) ( (x)>=0 ? (int)(x) : (int)(x)-1 )
Packit bc1512
 */
Packit bc1512
Packit bc1512
#include "config.h"
Packit bc1512
#include <glib-object.h>
Packit bc1512
#include <glib/gstdio.h>
Packit bc1512
#include <glib/gprintf.h>
Packit bc1512
Packit bc1512
#include "gegl.h"
Packit bc1512
#include "gegl-types-internal.h"
Packit bc1512
#include "gegl-buffer-private.h"
Packit bc1512
#include "gegl-sampler-linear.h"
Packit bc1512
Packit bc1512
enum
Packit bc1512
{
Packit bc1512
  PROP_0,
Packit bc1512
  PROP_LAST
Packit bc1512
};
Packit bc1512
Packit bc1512
static void gegl_sampler_linear_get (GeglSampler* restrict self,
Packit bc1512
                                     const gdouble         x,
Packit bc1512
                                     const gdouble         y,
Packit bc1512
                                     GeglMatrix2          *scale,
Packit bc1512
                                     void*        restrict output);
Packit bc1512
Packit bc1512
static void set_property (GObject*      gobject,
Packit bc1512
                          guint         property_id,
Packit bc1512
                          const GValue* value,
Packit bc1512
                          GParamSpec*   pspec);
Packit bc1512
Packit bc1512
static void get_property (GObject*    gobject,
Packit bc1512
                          guint       property_id,
Packit bc1512
                          GValue*     value,
Packit bc1512
                          GParamSpec* pspec);
Packit bc1512
Packit bc1512
G_DEFINE_TYPE (GeglSamplerLinear, gegl_sampler_linear, GEGL_TYPE_SAMPLER)
Packit bc1512
Packit bc1512
static void
Packit bc1512
gegl_sampler_linear_class_init (GeglSamplerLinearClass *klass)
Packit bc1512
{
Packit bc1512
  GeglSamplerClass *sampler_class = GEGL_SAMPLER_CLASS (klass);
Packit bc1512
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit bc1512
Packit bc1512
  object_class->set_property = set_property;
Packit bc1512
  object_class->get_property = get_property;
Packit bc1512
Packit bc1512
  sampler_class->get = gegl_sampler_linear_get;
Packit bc1512
}
Packit bc1512
Packit bc1512
static void
Packit bc1512
gegl_sampler_linear_init (GeglSamplerLinear *self)
Packit bc1512
{
Packit bc1512
  GEGL_SAMPLER (self)->context_rect[0].x = 0;
Packit bc1512
  GEGL_SAMPLER (self)->context_rect[0].y = 0;
Packit bc1512
  GEGL_SAMPLER (self)->context_rect[0].width = 2;
Packit bc1512
  GEGL_SAMPLER (self)->context_rect[0].height = 2;
Packit bc1512
  GEGL_SAMPLER (self)->interpolate_format = babl_format ("RaGaBaA float");
Packit bc1512
}
Packit bc1512
Packit bc1512
static void
Packit bc1512
gegl_sampler_linear_get (GeglSampler* restrict self,
Packit bc1512
                         const gdouble         absolute_x,
Packit bc1512
                         const gdouble         absolute_y,
Packit bc1512
                         GeglMatrix2          *scale,
Packit bc1512
                         void*        restrict output)
Packit bc1512
{
Packit bc1512
  const gint pixels_per_buffer_row = 64;
Packit bc1512
  const gint channels = 4;
Packit bc1512
Packit bc1512
  /*
Packit bc1512
   * floor's surrogate FAST_PSEUDO_FLOOR is used to make
Packit bc1512
   * sure that the transition through 0 is smooth. If it is known that
Packit bc1512
   * negative absolute_x and absolute_y will never be used, plain
Packit bc1512
   * cast---that is, const gint ix = absolute_x---is recommended
Packit bc1512
   * instead.
Packit bc1512
   */
Packit bc1512
  const gint ix = FAST_PSEUDO_FLOOR (absolute_x);
Packit bc1512
  const gint iy = FAST_PSEUDO_FLOOR (absolute_y);
Packit bc1512
Packit bc1512
  /*
Packit bc1512
   * x is the x-coordinate of the sampling point relative to the
Packit bc1512
   * position of the top left pixel center. Similarly for y. Range of
Packit bc1512
   * values: [0,1].
Packit bc1512
   */
Packit bc1512
  const gfloat x = absolute_x - ix;
Packit bc1512
  const gfloat y = absolute_y - iy;
Packit bc1512
Packit bc1512
  /*
Packit bc1512
   * Point the data tile pointer to the first channel of the top_left
Packit bc1512
   * pixel value:
Packit bc1512
   */
Packit bc1512
  const gfloat* restrict in_bptr = gegl_sampler_get_ptr (self, ix, iy);
Packit bc1512
Packit bc1512
  /*
Packit bc1512
   * First bilinear weight:
Packit bc1512
   */
Packit bc1512
  const gfloat x_times_y = x * y;
Packit bc1512
Packit bc1512
  /*
Packit bc1512
   * Load top row:
Packit bc1512
   */
Packit bc1512
  const gfloat top_left_0 = *in_bptr++;
Packit bc1512
  const gfloat top_left_1 = *in_bptr++;
Packit bc1512
  const gfloat top_left_2 = *in_bptr++;
Packit bc1512
  const gfloat top_left_3 = *in_bptr++;
Packit bc1512
  const gfloat top_rite_0 = *in_bptr++;
Packit bc1512
  const gfloat top_rite_1 = *in_bptr++;
Packit bc1512
  const gfloat top_rite_2 = *in_bptr++;
Packit bc1512
  const gfloat top_rite_3 = *in_bptr;
Packit bc1512
Packit bc1512
  in_bptr += 1 + ( pixels_per_buffer_row - 2 ) * channels;
Packit bc1512
Packit bc1512
  {
Packit bc1512
  /*
Packit bc1512
   * More bilinear weights:
Packit bc1512
   *
Packit bc1512
   * (Note: w = 1-x and z = 1-y.)
Packit bc1512
   */
Packit bc1512
  const gfloat w_times_y = y - x_times_y;
Packit bc1512
  const gfloat x_times_z = x - x_times_y;
Packit bc1512
Packit bc1512
  /*
Packit bc1512
   * Load bottom row:
Packit bc1512
   */
Packit bc1512
  const gfloat bot_left_0 = *in_bptr++;
Packit bc1512
  const gfloat bot_left_1 = *in_bptr++;
Packit bc1512
  const gfloat bot_left_2 = *in_bptr++;
Packit bc1512
  const gfloat bot_left_3 = *in_bptr++;
Packit bc1512
  const gfloat bot_rite_0 = *in_bptr++;
Packit bc1512
  const gfloat bot_rite_1 = *in_bptr++;
Packit bc1512
  const gfloat bot_rite_2 = *in_bptr++;
Packit bc1512
  const gfloat bot_rite_3 = *in_bptr;
Packit bc1512
Packit bc1512
  /*
Packit bc1512
   * Last bilinear weight:
Packit bc1512
   */
Packit bc1512
  const gfloat w_times_z = 1.f - ( x + w_times_y );
Packit bc1512
Packit bc1512
  gfloat newval[4];
Packit bc1512
Packit bc1512
  newval[0] =
Packit bc1512
    x_times_y * bot_rite_0
Packit bc1512
    +
Packit bc1512
    w_times_y * bot_left_0
Packit bc1512
    +
Packit bc1512
    x_times_z * top_rite_0
Packit bc1512
    +
Packit bc1512
    w_times_z * top_left_0;
Packit bc1512
Packit bc1512
  newval[1] =
Packit bc1512
    x_times_y * bot_rite_1
Packit bc1512
    +
Packit bc1512
    w_times_y * bot_left_1
Packit bc1512
    +
Packit bc1512
    x_times_z * top_rite_1
Packit bc1512
    +
Packit bc1512
    w_times_z * top_left_1;
Packit bc1512
Packit bc1512
  newval[2] =
Packit bc1512
    x_times_y * bot_rite_2
Packit bc1512
    +
Packit bc1512
    w_times_y * bot_left_2
Packit bc1512
    +
Packit bc1512
    x_times_z * top_rite_2
Packit bc1512
    +
Packit bc1512
    w_times_z * top_left_2;
Packit bc1512
Packit bc1512
  newval[3] =
Packit bc1512
    x_times_y * bot_rite_3
Packit bc1512
    +
Packit bc1512
    w_times_y * bot_left_3
Packit bc1512
    +
Packit bc1512
    x_times_z * top_rite_3
Packit bc1512
    +
Packit bc1512
    w_times_z * top_left_3;
Packit bc1512
Packit bc1512
    babl_process (self->fish, newval, output, 1);
Packit bc1512
  }
Packit bc1512
}
Packit bc1512
Packit bc1512
static void
Packit bc1512
set_property (GObject*      gobject,
Packit bc1512
              guint         property_id,
Packit bc1512
              const GValue* value,
Packit bc1512
              GParamSpec*   pspec)
Packit bc1512
{
Packit bc1512
  G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
Packit bc1512
}
Packit bc1512
Packit bc1512
static void
Packit bc1512
get_property (GObject*    gobject,
Packit bc1512
              guint       property_id,
Packit bc1512
              GValue*     value,
Packit bc1512
              GParamSpec* pspec)
Packit bc1512
{
Packit bc1512
  G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
Packit bc1512
}
Packit bc1512