Commit ea1cd6fd authored by Øyvind Kolås's avatar Øyvind Kolås

modified not to use extent accessors instead of poking directly into

	* operations/**/*.c: modified not to use extent accessors instead of
	poking directly into GeglBuffer's deprecated ->width, ->height, ->x
	and ->y members.

svn path=/trunk/; revision=1641
parent b16eff3b
2007-09-13 Øyvind Kolås <pippin@gimp.org>
* operations/**/*.c: modified not to use extent accessors instead of
poking directly into GeglBuffer's deprecated ->width, ->height, ->x
and ->y members.
2007-09-13 Øyvind Kolås <pippin@gimp.org>
* gegl/buffer/gegl-buffer-private.[ch]: made the abyss and extent in
......
......@@ -33,10 +33,6 @@
#include "affine.h"
#include "module.h"
#include "matrix.h"
#include "nearest.h"
#include "linear.h"
#include "interpolate-lanczos.h"
#include "interpolate-cubic.h"
#include "buffer/gegl-interpolator.h"
enum
......@@ -589,32 +585,37 @@ affine_generic (GeglBuffer *dest,
Matrix3 matrix,
GeglInterpolation interpolation)
{
gint x, y;
gfloat *dest_buf,
*dest_ptr;
Matrix3 inverse;
gdouble u_start,
v_start,
u_float,
v_float;
Babl* format = babl_format ("RaGaBaA float");
gint dest_pixels;
GeglRectangle *dest_extent;
gint x, y;
gfloat *dest_buf,
*dest_ptr;
Matrix3 inverse;
gdouble u_start,
v_start,
u_float,
v_float;
Babl *format;
gint dest_pixels;
format = babl_format ("RaGaBaA float");
/* XXX: fast paths as existing in files in the same dir as affine.c
* should probably be hooked in here, and bailing out before using
* the generic code.
*/
g_object_get (dest, "pixels", &dest_pixels, NULL);
dest_extent = gegl_buffer_extent (dest);
dest_buf = g_new (gfloat, dest_pixels * 4);
matrix3_copy (inverse, matrix);
matrix3_invert (inverse);
u_start = inverse[0][0] * dest->x + inverse[0][1] * dest->y
u_start = inverse[0][0] * dest_extent->x + inverse[0][1] * dest_extent->y
+ inverse[0][2];
v_start = inverse[1][0] * dest->x + inverse[1][1] * dest->y
v_start = inverse[1][0] * dest_extent->x + inverse[1][1] * dest_extent->y
+ inverse[1][2];
/* correct rounding on e.g. negative scaling (is this sound?) */
......@@ -628,12 +629,12 @@ affine_generic (GeglBuffer *dest,
gegl_interpolator_prepare (src->interpolator);
}
for (dest_ptr = dest_buf, y = dest->height; y--;)
for (dest_ptr = dest_buf, y = dest_extent->height; y--;)
{
u_float = u_start;
v_float = v_start;
for (x = dest->width; x--;)
for (x = dest_extent->width; x--;)
{
gfloat pix[4];
gegl_buffer_sample (src, u_float, v_float, 1.0, pix, format, interpolation);
......
/* 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 2 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, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Copyright 2006 Geert Jordaens
*/
#include <string.h>
#include <math.h>
#include <gegl-plugin.h>
#include "interpolate-cubic.h"
#include "matrix.h"
#define CUBIC_ROW(dx, row, step) \
transform_cubic(dx,\
(row)[0], (row)[step], (row)[step+step], (row)[step+step+step])
#define CUBIC_SCALED_ROW(dx, row, arow, step) \
transform_cubic(dx, \
(arow)[0] * (row)[0], \
(arow)[step] * (row)[step], \
(arow)[step+step] * (row)[step+step], \
(arow)[step+step+step] * (row)[step+step+step])
static inline gdouble
transform_cubic (gdouble du,
gdouble jm1,
gdouble j,
gdouble jp1,
gdouble jp2)
{
gdouble result;
/* Catmull-Rom */
result = ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * du +
( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * du +
( - jm1 + jp1 ) ) * du + (j + j) ) / 2.0;
return result;
}
void
affine_cubic (GeglBuffer *dest,
GeglBuffer *src,
Matrix3 matrix)
{
gdouble arecip;
gint x, y,
i, j,
pos,
src_w = src->width,
src_h = src->height,
u,
u1 = src->x,
u2 = src_w - 1,
pu,
v,
v1 = src->y,
v2 = src_h - 1,
pv;
gfloat *src_buf,
*dest_buf,
*src_ptr,
*dest_ptr,
abyss = 0.;
gdouble newval[4];
gdouble data[64];
gdouble du, dv, fu, fv;
Matrix3 inverse;
gint src_pixels;
gint dest_pixels;
g_object_get (src, "pixels", &src_pixels, NULL);
g_object_get (dest, "pixels", &dest_pixels, NULL);
if (src_pixels == 0 ||
dest_pixels == 0)
return;
src_buf = g_new (gfloat, src_pixels << 2);
dest_buf = g_new (gfloat, dest_pixels << 2);
g_assert (src_buf && dest_buf);
gegl_buffer_get (src, NULL, 1.0, babl_format ("RaGaBaA float"), src_buf);
matrix3_copy (inverse, matrix);
matrix3_invert (inverse);
fu = du = inverse[0][0] * dest->x + inverse[0][1] * dest->y
+ inverse[0][2] - src->x;
fv = dv = inverse[1][0] * dest->x + inverse[1][1] * dest->y
+ inverse[1][2] - src->y;
for (dest_ptr = dest_buf, y = 0; y < dest->height; y++)
{
for (x = 0; x < dest->width; x++)
{
u = (gint) fu;
v = (gint) fv;
if (u < v1 || v < v1 || u >= u2 || v >= v2)
{
*dest_ptr++ = abyss;
*dest_ptr++ = abyss;
*dest_ptr++ = abyss;
*dest_ptr++ = abyss;
}
else
{
/* get source values */
for (pos=0, j = -2; j < 2; j++)
for (i = -2; i < 2; i++, pos+=4)
{
pu = CLAMP( u+i, u1, u2 );
pv = CLAMP( v+j, v1, v2 );
src_ptr = src_buf + ((pv * src_w + pu) << 2);
data[pos] = src_ptr[0];
data[pos+1] = src_ptr[1];
data[pos+2] = src_ptr[2];
data[pos+3] = src_ptr[3];
}
newval[3] = transform_cubic (fv-v,
CUBIC_ROW(fu-u, data+3, 4),
CUBIC_ROW(fu-u, data+3+16, 4),
CUBIC_ROW(fu-u, data+3+32, 4),
CUBIC_ROW(fu-u, data+3+48, 4));
for (i = 0; i < 3; i++)
{
newval[i] = transform_cubic (fv-v,
CUBIC_SCALED_ROW(fu-u, data+i, data+3, 4),
CUBIC_SCALED_ROW(fu-u, data+i+16, data+19, 4),
CUBIC_SCALED_ROW(fu-u, data+i+32, data+35, 4),
CUBIC_SCALED_ROW(fu-u, data+i+48, data+51, 4));
}
if (newval[3] <= 0.0)
{
arecip = 0.0;
newval[3] = 0;
}
else if (newval[3] > G_MAXDOUBLE)
{
arecip = 1.0 / newval[3];
newval[3] = G_MAXDOUBLE;
}
else
{
arecip = 1.0 / newval[3];
}
*dest_ptr++ = CLAMP(newval[0] * arecip, 0, G_MAXDOUBLE);
*dest_ptr++ = CLAMP(newval[1] * arecip, 0, G_MAXDOUBLE);
*dest_ptr++ = CLAMP(newval[2] * arecip, 0, G_MAXDOUBLE);
*dest_ptr++ = CLAMP(newval[3], 0, G_MAXDOUBLE);
}
fu += inverse [0][0];
fv += inverse [1][0];
}
du += inverse [0][1];
dv += inverse [1][1];
fu = du;
fv = dv;
}
gegl_buffer_set (dest, NULL, babl_format ("RaGaBaA float"), dest_buf);
g_free (src_buf);
g_free (dest_buf);
}
void
scale_cubic (GeglBuffer *dest,
GeglBuffer *src,
Matrix3 matrix)
{
affine_cubic (dest, src, matrix);
}
#ifndef __AFFINE_CUBIC_H__
#define __AFFINE_CUBIC_H__
#include <gegl.h>
#include "matrix.h"
void affine_cubic (GeglBuffer *input,
GeglBuffer *output,
Matrix3 matrix);
void scale_cubic (GeglBuffer *input,
GeglBuffer *output,
Matrix3 matrix);
#endif
/* 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 2 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, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Copyright 2006 Geert Jordaens
*/
#include <string.h>
#include <math.h>
#include <gegl-plugin.h>
#include "interpolate-lanczos.h"
#include "matrix.h"
static gdouble *create_lanczos_lookup_transform (gint lanczos_width,
gint lanczos_spp);
static inline gdouble
sinc (gdouble x)
{
gdouble y = x * G_PI;
if (ABS (x) < 0.0001)
return 1.0;
return sin (y) / y;
}
gdouble *
create_lanczos_lookup_transform (gint lanczos_width,
gint lanczos_spp)
{
const gint lanczos_samples = (lanczos_spp * (lanczos_width + 1));
const gdouble dx = (gdouble) lanczos_width / (gdouble) (lanczos_samples - 1);
gdouble *lanczos = g_new (gdouble, lanczos_samples);
gdouble x = 0.0;
gint i;
for (i = 0; i < lanczos_samples; i++)
{
lanczos[i] = ((ABS (x) < lanczos_width) ?
(sinc (x) * sinc (x / lanczos_width)) : 0.0);
x += dx;
}
return lanczos;
}
void
affine_lanczos (GeglBuffer *dest,
GeglBuffer *src,
Matrix3 matrix,
gint lanczos_width)
{
gdouble *lanczos = NULL; /* Lanczos lookup table */
gdouble x_sum, y_sum; /* sum of Lanczos weights */
gint lanczos_width2;
gint lanczos_spp;
gdouble x_kernel[lanczos_width*2+1],/* 1-D kernels of Lanczos window coeffs */
y_kernel[lanczos_width*2+1];
gdouble scale, arecip;
gint x, y,
i, j,
pos,
src_w = src->width,
src_h = src->height,
u,
u1 = src->x,
u2 = src_w - 1,
su, pu,
v,
v1 = src->y,
v2 = src_h - 1,
sv, pv;
gfloat *src_buf,
*dest_buf,
*src_ptr,
*dest_ptr,
abyss = 0.;
gdouble newval[4];
gdouble du, dv, fu, fv;
Matrix3 inverse;
gint src_pixels;
gint dest_pixels;
g_object_get (src, "pixels", &src_pixels, NULL);
g_object_get (dest, "pixels", &dest_pixels, NULL);
/*
* parameter corretions
* 1. lanczos_width we do not settle for less than lanczos(3)
* 2. Window width is 2 times lanczos_width + 1
* 3. The minimum number of recalculate samples lanczos_spp is
* lanczos_width2.
*/
lanczos_width = (lanczos_width < 3) ? 3 : lanczos_width;
lanczos_width2 = lanczos_width * 2 + 1;
lanczos_spp = lanczos_width2 * 10000;
if (src_pixels == 0 ||
dest_pixels == 0)
return;
src_buf = g_new (gfloat, src_pixels << 2);
dest_buf = g_new (gfloat, dest_pixels << 2);
g_assert (src_buf && dest_buf);
gegl_buffer_get (src, NULL, 1.0, babl_format ("RaGaBaA float"), src_buf);
matrix3_copy (inverse, matrix);
matrix3_invert (inverse);
fu = du = inverse[0][0] * dest->x + inverse[0][1] * dest->y
+ inverse[0][2] - src->x;
fv = dv = inverse[1][0] * dest->x + inverse[1][1] * dest->y
+ inverse[1][2] - src->y;
/*
* Allocate and fill lanczos lookup table
*/
if (matrix [0][0] > 1.0 || matrix [0][1] > 1.0)
{
scale = MAX (matrix[0][0], matrix[0][1]) + 1;
lanczos_spp *= (gint) scale;
}
lanczos = create_lanczos_lookup_transform (lanczos_width,
lanczos_spp);
for (dest_ptr = dest_buf, y = 0; y < dest->height; y++)
{
for (x = 0; x < dest->width; x++)
{
u = (gint) fu;
v = (gint) fv;
if (u < v1 || v < v1 || u >= u2 || v >= v2)
{
*((guint32 *) dest_ptr) = abyss;
dest_ptr += 4;
}
else
{
/* get weight for fractional error */
su = (gint) ((fu - u) * lanczos_spp);
sv = (gint) ((fv - v) * lanczos_spp);
/* fill 1D kernels */
for (x_sum = y_sum = 0.0, i = lanczos_width; i >= -lanczos_width; i--)
{
pos = i * lanczos_spp;
x_sum += x_kernel[lanczos_width + i] = lanczos[ABS (su - pos)];
y_sum += y_kernel[lanczos_width + i] = lanczos[ABS (sv - pos)];
}
/* normalise the weighted arrays */
for (i = 0; i < lanczos_width2; i++)
{
x_kernel[i] /= x_sum;
y_kernel[i] /= y_sum;
}
newval[0] = newval[1] = newval[2] = newval[3] = 0.0;
for (j = 0; j < lanczos_width2; j++)
for (i = 0; i < lanczos_width2; i++)
{
pu = CLAMP( u+i-lanczos_width, u1, u2 );
pv = CLAMP( v+j-lanczos_width, v1, v2 );
src_ptr = src_buf + ((pv * src_w + pu) << 2);
newval[0] += y_kernel[j] * x_kernel[i] * src_ptr[0] * src_ptr[3];
newval[1] += y_kernel[j] * x_kernel[i] * src_ptr[1] * src_ptr[3];
newval[2] += y_kernel[j] * x_kernel[i] * src_ptr[2] * src_ptr[3];
newval[3] += y_kernel[j] * x_kernel[i] * src_ptr[3];
}
if (newval[3] <= 0.0)
{
arecip = 0.0;
newval[3] = 0;
}
else if (newval[3] > G_MAXDOUBLE)
{
arecip = 1.0 / newval[3];
newval[3] = G_MAXDOUBLE;
}
else
{
arecip = 1.0 / newval[3];
}
*dest_ptr++ = CLAMP(newval[0] * arecip, 0, G_MAXDOUBLE);
*dest_ptr++ = CLAMP(newval[1] * arecip, 0, G_MAXDOUBLE);
*dest_ptr++ = CLAMP(newval[2] * arecip, 0, G_MAXDOUBLE);
*dest_ptr++ = CLAMP(newval[3], 0, G_MAXDOUBLE);
}
fu += inverse[0][0];
fv += inverse[1][0];
}
du += inverse[0][1];
dv += inverse[1][1];
fu = du;
fv = dv;
}
gegl_buffer_set (dest, NULL, babl_format ("RaGaBaA float"), dest_buf);
g_free (lanczos);
g_free (src_buf);
g_free (dest_buf);
}
void
scale_lanczos (GeglBuffer *dest,
GeglBuffer *src,
Matrix3 matrix,
gint lanczos_width)
{
affine_lanczos (dest, src, matrix, lanczos_width);
}
#ifndef __AFFINE_LANCZOS_H__
#define __AFFINE_LANCZOS_H__
#include <gegl.h>
#include "matrix.h"
void affine_lanczos (GeglBuffer *input,
GeglBuffer *output,
Matrix3 matrix,
gint lanczos_width);
void scale_lanczos (GeglBuffer *input,
GeglBuffer *output,
Matrix3 matrix,
gint lanczos_width);
#endif
/* 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 2 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, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Copyright 2006 Philip Lafleur
*/
#include <string.h>
#include <math.h>
#include <gegl-plugin.h>
#include "linear.h"
#include "matrix.h"
void
affine_linear (GeglBuffer *dest,
GeglBuffer *src,
Matrix3 matrix,
gboolean hard_edges)
{
gint x, y,
src_w = src->width,
src_w_m1 = src_w - 1,
src_h = src->height,
src_h_m1 = src_h - 1,
src_rowstride = src_w * 4;
gfloat *src_buf,
*dest_buf,
*src_ptr,
*dest_ptr,
abyss = 0.;
Matrix3 inverse;
gdouble u_start,
v_start;
gint src_pixels;
gint dest_pixels;
g_object_get (src, "pixels", &src_pixels, NULL);
g_object_get (dest, "pixels", &dest_pixels, NULL);
if (src_pixels == 0 ||
dest_pixels == 0)
return;
src_buf = g_new (gfloat, src_pixels * 4);
dest_buf = g_new (gfloat, dest_pixels * 4);
g_assert (src_buf && dest_buf);
gegl_buffer_get (src, NULL, 1.0, babl_format ("RaGaBaA float"), src_buf);
/* expand borders */
/* bottom row */
memcpy (src_buf + src_h_m1 * src_rowstride,
src_buf + (src_h_m1 - 1) * src_rowstride,
src_rowstride * sizeof (gfloat));
/* right column */
src_ptr = src_buf + src_w_m1 * 4;
for (y = src_h; y--; src_ptr += src_rowstride)
{
src_ptr[0] = *((gfloat *) (src_ptr - 4));
src_ptr[1] = *((gfloat *) (src_ptr - 3));
src_ptr[2] = *((gfloat *) (src_ptr - 2));
src_ptr[3] = *((gfloat *) (src_ptr - 1));
}
if (! hard_edges)
{
/* top row */
memcpy (src_buf, src_buf + src_rowstride, src_rowstride * sizeof (gfloat));
/* left column */
src_ptr = src_buf;
for (y = src_h; y--; src_ptr += src_rowstride)
{
src_ptr[0] = *((gfloat *) (src_ptr + 4));
src_ptr[1] = *((gfloat *) (src_ptr + 5));
src_ptr[2] = *((gfloat *) (src_ptr + 6));
src_ptr[3] = *((gfloat *) (src_ptr + 7));
}
/* make expanded borders transparent */
/* left column */
src_ptr = src_buf + 3;
for (y = src_h; y--; src_ptr += src_rowstride)
*src_ptr = 0.;
/* right column */
src_ptr = src_buf + src_w_m1 * 4 + 3;
for (y = src_h; y--; src_ptr += src_rowstride)
*src_ptr = 0.;
/* top row */
src_ptr = src_buf + 3;
for (x = src_w; x--; src_ptr += 4)
*src_ptr = 0.;
/* bottom row */
src_ptr = src_buf + src_h_m1 * src_rowstride + 3;
for (x = src_w; x--; src_ptr += 4)
*src_ptr = 0.;
}
matrix3_copy (inverse, matrix);
matrix3_invert (inverse);
u_start = inverse[0][0] * dest->x + inverse[0][1] * dest->y
+ inverse[0][2] - src->x;
v_start = inverse[1][0] * dest->x + inverse[1][1] * dest->y
+ inverse[1][2] - src->y;
for (dest_ptr = dest_buf, y = dest->height; y--;)
{
gdouble u_float = u_start,
v_float = v_start;
for (x = dest->width; x--;)
{
gint u = u_float,
v = v_float;
if (G_LIKELY (u >= 0 &&
v >= 0 &&
u < src_w_m1 &&
v < src_h_m1))
{
gdouble fu, fv,
fu_inv, fv_inv,
factor0,
factor1,
factor2,
factor3,
r, g, b, a;
fu = u_float - u;
fu = MAX (fu, 0.);
fu_inv = 1. - fu;
fv = v_float - v;
fv = MAX (fv, 0.);
fv_inv = 1. - fv;
factor0 = fv_inv * fu_inv;
factor1 = fv_inv * fu;
factor2 = fv * fu_inv;
factor3 = fv * fu;
src_ptr = src_buf + (v * src_w + u) * 4;
r = src_ptr [0] * factor0;
g = src_ptr [1] * factor0;