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