Re: gdk_pixbuf interpolation tables



After a long discussion with Owen on this topic, we agreed that the
vectors should total to 1.0 rather than overall_alpha.  overall_alpha
is now included in the 2-d table that is computed in the
convert_vector_to_table function.  So now sqrt(overall_alpha)
is no longer computed and the need for the x_constant and y_constant
stack variables went away.  Other than these changes, the patch is
the same as the previous one.

The scale.c test program has also been updated with the same change.

Brian
Index: gtk+/gdk-pixbuf/pixops/pixops.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/pixops/pixops.c,v
retrieving revision 1.29
diff -u -p -u -p -r1.29 pixops.c
--- gtk+/gdk-pixbuf/pixops/pixops.c	13 Jun 2002 22:12:53 -0000	1.29
+++ gtk+/gdk-pixbuf/pixops/pixops.c	6 Mar 2003 11:37:44 -0000
@@ -14,11 +14,13 @@ typedef struct _PixopsFilter PixopsFilte
 
 struct _PixopsFilter
 {
-  int *weights;
+  double *x_weights;
+  double *y_weights;
   int n_x;
   int n_y;
   double x_offset;
   double y_offset;
+  double overall_alpha;
 }; 
 
 typedef guchar *(*PixopsLineFunc) (int *weights, int n_x, int n_y,
@@ -938,6 +940,63 @@ process_pixel (int *weights, int n_x, in
   (*pixel_func) (dest, dest_x, dest_channels, dest_has_alpha, src_has_alpha, check_size, color1, color2, r, g, b, a);
 }
 
+static void 
+correct_total (int    *weights, 
+               int    n_x, 
+               int    n_y,
+               int    total, 
+               double overall_alpha)
+{
+  int correction = (int)(0.5 + 65536 * overall_alpha) - total;
+
+  if (correction != 0)
+    {
+      int i;
+      for (i = n_x * n_y - 1; i >= 0; i--) 
+        {
+          if (*(weights + i) + correction >= 0) 
+            {
+              *(weights + i) += correction;
+              break;
+            }
+        }
+    }
+}
+
+static int *
+convert_vector_to_table(PixopsFilter *vector)
+{
+  int i_offset, j_offset;
+  int n_x = vector->n_x;
+  int n_y = vector->n_y;
+  int * weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
+
+  for (i_offset=0; i_offset < SUBSAMPLE; i_offset++)
+    for (j_offset=0; j_offset < SUBSAMPLE; j_offset++)
+      {
+        double weight;
+        int *pixel_weights = weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
+        int total = 0;
+        int i,j;
+
+        for (i=0; i < n_y; i++)
+          for (j=0; j < n_x; j++)
+            {
+              weight = vector->x_weights[(j_offset * n_x) + j] *
+                       vector->y_weights[(i_offset * n_y) + i] *
+                       vector->overall_alpha * 65536 + 0.5;
+
+              total += (int)weight;
+
+              *(pixel_weights + n_x * i + j) = weight;
+            }
+
+        correct_total (pixel_weights, n_x, n_y, total, vector->overall_alpha);
+      }
+
+  return weights;
+}
+
 static void
 pixops_process (guchar         *dest_buf,
 		int             render_x0,
@@ -968,6 +1027,8 @@ pixops_process (guchar         *dest_buf
   int x, y;			/* X and Y position in source (fixed_point) */
   guchar **line_bufs = g_new (guchar *, filter->n_y);
 
+  int *filter_weights = convert_vector_to_table(filter);
+
   int x_step = (1 << SCALE_SHIFT) / scale_x; /* X step in source (fixed point) */
   int y_step = (1 << SCALE_SHIFT) / scale_y; /* Y step in source (fixed point) */
 
@@ -997,7 +1058,9 @@ pixops_process (guchar         *dest_buf
       int dest_x;
       int y_start = y >> SCALE_SHIFT;
       int x_start;
-      int *run_weights = filter->weights + ((y >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * filter->n_x * filter->n_y * SUBSAMPLE;
+      int *run_weights = filter_weights +
+                         ((y >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) *
+                         filter->n_x * filter->n_y * SUBSAMPLE;
       guchar *new_outbuf;
       guint32 tcolor1, tcolor2;
       
@@ -1074,320 +1137,260 @@ pixops_process (guchar         *dest_buf
     }
 
   g_free (line_bufs);
+  g_free (filter_weights);
 }
 
-static void 
-correct_total (int    *weights, 
-	       int    n_x, 
-	       int    n_y,
-	       int    total, 
-	       double overall_alpha)
-{
-  int correction = (int)(0.5 + 65536 * overall_alpha) - total;
-  int i;
-  for (i = n_x * n_y - 1; i >= 0; i--) 
-    {
-      if (*(weights + i) + correction >= 0) 
-	{
-	  *(weights + i) += correction;
-	  break;
-	}
-    }
-}  
-
 static void
 tile_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
 {
-  int i_offset, j_offset;
-
-  int n_x = ceil(1/x_scale + 1);
-  int n_y = ceil(1/y_scale + 1);
+  double *x_pixel_weights;
+  double *y_pixel_weights;
+  int n_x = ceil (1/x_scale + 1);
+  int n_y = ceil (1/y_scale + 1);
+  int offset;
+  int i;
 
   filter->x_offset = 0;
   filter->y_offset = 0;
   filter->n_x = n_x;
   filter->n_y = n_y;
-  filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
-
-  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
-    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
-      {
-	int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
-	double x = (double)j_offset / SUBSAMPLE;
-	double y = (double)i_offset / SUBSAMPLE;
-	int i,j;
-	int total = 0;
-	  
-	for (i = 0; i < n_y; i++)
-	  {
-	    double tw, th;
-		
-	    if (i < y)
-	      {
-
-		if (i + 1 > y)
-		  th = MIN(i+1, y + 1/y_scale) - y;
-		else
-		  th = 0;
-	      }
-	    else
-	      {
-		if (y + 1/y_scale > i)
-		  th = MIN(i+1, y + 1/y_scale) - i;
-		else
-		  th = 0;
-	      }
-		
-	    for (j = 0; j < n_x; j++)
-	      {
-		int weight;
-		
-		if (j < x)
-		  {
-		    if (j + 1 > x)
-		      tw = MIN(j+1, x + 1/x_scale) - x;
-		    else
-		      tw = 0;
-		  }
-		else
-		  {
-		    if (x + 1/x_scale > j)
-		      tw = MIN(j+1, x + 1/x_scale) - j;
-		    else
-		      tw = 0;
-		  }
-
-		weight = 65536 * tw * x_scale * th * y_scale * overall_alpha + 0.5;
-		total += weight;
-		*(pixel_weights + n_x * i + j) = weight;
-	      }
-	  }
-	
-	correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
-      }
+  filter->x_weights = g_new (double, SUBSAMPLE * n_x);
+  filter->y_weights = g_new (double, SUBSAMPLE * n_y);
+  filter->overall_alpha = overall_alpha;
+
+  x_pixel_weights = filter->x_weights;
+  y_pixel_weights = filter->y_weights;
+
+  for (offset=0; offset < SUBSAMPLE; offset++)
+    {
+      double x = (double)offset / SUBSAMPLE;
+      double a = x + 1 / x_scale;
+      double b = x + 1 / y_scale;
+
+      for (i = 0; i < n_x; i++)
+        {
+          if (i < x)
+            {
+              if (i + 1 > x)
+                *(x_pixel_weights++)  = (MIN (i + 1, a) - x) * x_scale;
+              else
+                *(x_pixel_weights++) = 0;
+            }
+          else
+            {
+              if (a > i)
+                *(x_pixel_weights++)  = (MIN (i + 1, a) - i) * x_scale;
+              else
+                *(x_pixel_weights++) = 0;
+            }
+       }
+        
+      for (i = 0; i < n_y; i++)
+        {
+          if (i < x)
+            {
+              if (i + 1 > x)
+                *(y_pixel_weights++) = (MIN (i + 1, b) - x) * y_scale;
+              else
+                *(y_pixel_weights++) = 0;
+            }
+          else
+            {
+              if (b > i)
+                *(y_pixel_weights++) = (MIN (i + 1, b) - i) * y_scale;
+              else
+                *(y_pixel_weights++) = 0;
+            }
+        }
+    }
 }
 
 static void
 bilinear_make_fast_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
 {
-  int i_offset, j_offset;
-  double *x_weights, *y_weights;
+  double *x_pixel_weights;
+  double *y_pixel_weights;
   int n_x, n_y;
+  int offset;
+  int i;
 
-  if (x_scale > 1.0)		/* Bilinear */
+  if (x_scale > 1.0)            /* Bilinear */
     {
       n_x = 2;
-      filter->x_offset = 0.5 * (1/x_scale - 1);
+      filter->x_offset = 0.5 * (1 / x_scale - 1);
     }
-  else				/* Tile */
+  else                          /* Tile */
     {
-      n_x = ceil(1.0 + 1.0/x_scale);
+      n_x = ceil (1.0 + 1.0 / x_scale);
       filter->x_offset = 0.0;
     }
 
-  if (y_scale > 1.0)		/* Bilinear */
+  if (y_scale > 1.0)            /* Bilinear */
     {
       n_y = 2;
-      filter->y_offset = 0.5 * (1/y_scale - 1);
+      filter->y_offset = 0.5 * (1 / y_scale - 1);
     }
-  else				/* Tile */
+  else                          /* Tile */
     {
-      n_y = ceil(1.0 + 1.0/y_scale);
+      n_y = ceil (1.0 + 1.0 / y_scale);
       filter->y_offset = 0.0;
     }
 
   filter->n_y = n_y;
   filter->n_x = n_x;
-  filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
-
-  x_weights = g_new (double, n_x);
-  y_weights = g_new (double, n_y);
-
-  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
-    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
-      {
-	int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
-	double x = (double)j_offset / SUBSAMPLE;
-	double y = (double)i_offset / SUBSAMPLE;
-	int i,j;
-	int total = 0;
-
-	if (x_scale > 1.0)	/* Bilinear */
-	  {
-	    for (i = 0; i < n_x; i++)
-	      {
-		x_weights[i] = ((i == 0) ? (1 - x) : x) / x_scale;
-	      }
-	  }
-	else			/* Tile */
-	  {
-	    /*           x
-	     * ---------|--.-|----|--.-|-------  SRC
-	     * ------------|---------|---------  DEST
-	     */
-	    for (i = 0; i < n_x; i++)
-	      {
-		if (i < x)
-		  {
-		    if (i + 1 > x)
-		      x_weights[i] = MIN(i+1, x + 1/x_scale) - x;
-		    else
-		      x_weights[i] = 0;
-		  }
-		else
-		  {
-		    if (x + 1/x_scale > i)
-		      x_weights[i] = MIN(i+1, x + 1/x_scale) - i;
-		    else
-		      x_weights[i] = 0;
-		  }
-	      }
-	  }
-
-	if (y_scale > 1.0)	/* Bilinear */
-	  {
-	    for (i = 0; i < n_y; i++)
-	      {
-		y_weights[i] = ((i == 0) ? (1 - y) : y) / y_scale;
-	      }
-	  }
-	else			/* Tile */
-	  {
-	    /*           y
-	     * ---------|--.-|----|--.-|-------  SRC
-	     * ------------|---------|---------  DEST
-	     */
-	    for (i = 0; i < n_y; i++)
-	      {
-		if (i < y)
-		  {
-		    if (i + 1 > y)
-		      y_weights[i] = MIN(i+1, y + 1/y_scale) - y;
-		    else
-		      y_weights[i] = 0;
-		  }
-		else
-		  {
-		    if (y + 1/y_scale > i)
-		      y_weights[i] = MIN(i+1, y + 1/y_scale) - i;
-		    else
-		      y_weights[i] = 0;
-		  }
-	      }
-	  }
-
-	for (i = 0; i < n_y; i++)
-	  for (j = 0; j < n_x; j++)
-	    {
-	      int weight = 65536 * x_weights[j] * x_scale * y_weights[i] * y_scale * overall_alpha + 0.5;
-	      *(pixel_weights + n_x * i + j) = weight;
-	      total += weight;
-	    }
-
-	correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
-      }
+  filter->x_weights = g_new (double, SUBSAMPLE * n_x);
+  filter->y_weights = g_new (double, SUBSAMPLE * n_y);
+  filter->overall_alpha = overall_alpha;
+
+  x_pixel_weights = filter->x_weights;
+  y_pixel_weights = filter->y_weights;
+
+  for (offset=0; offset < SUBSAMPLE; offset++)
+    {
+      double x = (double)offset / SUBSAMPLE;
+
+      if (x_scale > 1.0)      /* Bilinear */
+        {
+          for (i = 0; i < n_x; i++)
+            *(x_pixel_weights++) = (((i == 0) ? (1 - x) : x) / x_scale) * x_scale;
+        }
+      else                  /* Tile */
+        {
+          double a = x + 1 / x_scale;
+
+          /*           x
+           * ---------|--.-|----|--.-|-------  SRC
+           * ------------|---------|---------  DEST
+           */
+          for (i = 0; i < n_x; i++)
+            {
+              if (i < x)
+                {
+                  if (i + 1 > x)
+                    *(x_pixel_weights++) = (MIN (i + 1, a) - x) * x_scale;
+                  else
+                    *(x_pixel_weights++) = 0;
+                }
+              else
+                {
+                  if (a > i)
+                    *(x_pixel_weights++) = (MIN (i + 1, a) - i) * x_scale;
+                  else
+                    *(x_pixel_weights++) = 0;
+                }
+            }
+        }
 
-  g_free (x_weights);
-  g_free (y_weights);
+      if (y_scale > 1.0)      /* Bilinear */
+        {
+          for (i = 0; i < n_y; i++)
+            *(y_pixel_weights++) = (((i == 0) ? (1 - x) : x) / y_scale) * y_scale;
+        }
+      else                  /* Tile */
+        {
+          double b = x + 1 / y_scale;
+
+          /*           x
+           * ---------|--.-|----|--.-|-------  SRC
+           * ------------|---------|---------  DEST
+           */
+          for (i = 0; i < n_y; i++)
+            {
+              if (i < x)
+                {
+                  if (i + 1 > x)
+                    *(y_pixel_weights++) = (MIN (i + 1, b) - x) * y_scale;
+                  else
+                    *(y_pixel_weights++) = 0;
+                }
+              else
+                {
+                  if (b > i)
+                    *(y_pixel_weights++) = (MIN (i + 1, b) - i) * y_scale;
+                  else
+                    *(y_pixel_weights++) = 0;
+                }
+            }
+        }
+    }
 }
 
 static double
-bilinear_quadrant (double bx0, double bx1, double by0, double by1)
+bilinear_quadrant (double b0, double b1)
 {
-  double ax0, ax1, ay0, ay1;
-  double x0, x1, y0, y1;
-
-  ax0 = 0.;
-  ax1 = 1.;
-  ay0 = 0.;
-  ay1 = 1.;
+  double a0, a1;
+  double x0, x1;
 
-  if (ax0 < bx0)
-    {
-      if (ax1 > bx0)
-	{
-	  x0 = bx0;
-	  x1 = MIN (ax1, bx1);
-	}
-      else
-	return 0;
-    }
-  else
-    {
-      if (bx1 > ax0)
-	{
-	  x0 = ax0;
-	  x1 = MIN (ax1, bx1);
-	}
-      else
-	return 0;
-    }
+  a0 = 0.;
+  a1 = 1.;
 
-  if (ay0 < by0)
+  if (a0 < b0)
     {
-      if (ay1 > by0)
-	{
-	  y0 = by0;
-	  y1 = MIN (ay1, by1);
-	}
+      if (a1 > b0)
+        {
+          x0 = b0;
+          x1 = MIN (a1, b1);
+        }
       else
-	return 0;
+        return 0;
     }
   else
     {
-      if (by1 > ay0)
-	{
-	  y0 = ay0;
-	  y1 = MIN (ay1, by1);
-	}
+      if (b1 > a0)
+        {
+          x0 = a0;
+          x1 = MIN (a1, b1);
+        }
       else
-	return 0;
+        return 0;
     }
 
-  return 0.25 * (x1*x1 - x0*x0) * (y1*y1 - y0*y0);
+  return (x1*x1 - x0*x0);
 }
 
 static void
 bilinear_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
 {
-  int i_offset, j_offset;
-
-  int n_x = ceil(1/x_scale + 2.0);
-  int n_y = ceil(1/y_scale + 2.0);
+  double *y_pixel_weights;
+  double *x_pixel_weights;
+  double w;
+  int n_x = ceil (1/x_scale + 2.0);
+  int n_y = ceil (1/y_scale + 2.0);
+  int offset, i;
 
   filter->x_offset = -1.0;
   filter->y_offset = -1.0;
   filter->n_x = n_x;
   filter->n_y = n_y;
-  
-  filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
-
-  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
-    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
-      {
-	int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
-	double x = (double)j_offset / SUBSAMPLE;
-	double y = (double)i_offset / SUBSAMPLE;
-	int i,j;
-	int total = 0;
-
-	for (i = 0; i < n_y; i++)
-	  for (j = 0; j < n_x; j++)
-	    {
-	      double w;
-	      int weight;
-	      
-	      w = bilinear_quadrant  (0.5 + j - (x + 1 / x_scale), 0.5 + j - x, 0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
-	      w += bilinear_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j, 0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
-	      w += bilinear_quadrant (0.5 + j - (x + 1 / x_scale), 0.5 + j - x, 1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
-	      w += bilinear_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j, 1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
-	      weight = 65536 * w * x_scale * y_scale * overall_alpha + 0.5;
-	      *(pixel_weights + n_x * i + j) = weight;
-	      total += weight;
-	    }
-	
-	correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
-      }
+  filter->x_weights = g_new (double, SUBSAMPLE * n_x);
+  filter->y_weights = g_new (double, SUBSAMPLE * n_y);
+  filter->overall_alpha = overall_alpha;
+
+  x_pixel_weights = filter->x_weights;
+  y_pixel_weights = filter->y_weights;
+
+  for (offset=0; offset < SUBSAMPLE; offset++)
+    {
+      double x = (double)offset / SUBSAMPLE;
+      double a = x + 1 / x_scale;
+      double b = x + 1 / y_scale;
+
+      for (i = 0; i < n_x; i++)
+        {
+          w  = 0.5 * bilinear_quadrant (0.5 + i - a, 0.5 + i - x);
+          w += 0.5 * bilinear_quadrant (1.5 + x - i, 1.5 + a - i);
+      
+          *(x_pixel_weights++) = w * x_scale;
+        }
+
+      for (i = 0; i < n_y; i++)
+        {
+          w =  0.5 * bilinear_quadrant (0.5 + i - b, 0.5 + i - x);
+          w += 0.5 * bilinear_quadrant (1.5 + x - i, 1.5 + b - i);
+      
+          *(y_pixel_weights++) = w * y_scale;
+        }
+    }
 }
 
 void
@@ -1474,7 +1477,8 @@ pixops_composite_color (guchar         *
 		  src_has_alpha, scale_x, scale_y, check_x, check_y, check_size, color1, color2,
 		  &filter, line_func, composite_pixel_color);
 
-  g_free (filter.weights);
+  g_free (filter.x_weights);
+  g_free (filter.y_weights);
 }
 
 /**
@@ -1584,7 +1588,8 @@ pixops_composite (guchar        *dest_bu
 		  src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0, 
 		  &filter, line_func, composite_pixel);
 
-  g_free (filter.weights);
+  g_free (filter.x_weights);
+  g_free (filter.y_weights);
 }
 
 void
@@ -1660,6 +1665,7 @@ pixops_scale (guchar        *dest_buf,
 		  src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
 		  &filter, line_func, scale_pixel);
 
-  g_free (filter.weights);
+  g_free (filter.x_weights);
+  g_free (filter.y_weights);
 }
 
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include <math.h>

#undef       MIN
#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
 
#define SUBSAMPLE_BITS 4
#define SUBSAMPLE (1 << SUBSAMPLE_BITS)
#define SUBSAMPLE_MASK ((1 << SUBSAMPLE_BITS)-1)
#define SCALE_SHIFT 16

#define DEBUG_PRINT_CORRECTION 0
#define DEBUG_PRINT_TABLE 0
#define DEBUG_PRINT_VECTOR 0

typedef struct _Pixops2dFilter Pixops2dFilter;
typedef struct _PixopsFilter PixopsFilter;

struct _Pixops2dFilter
{
  int *weights;
  int n_x;
  int n_y;
  double x_offset;
  double y_offset;
}; 

struct _PixopsFilter
{
  double *x_weights;
  double *y_weights;
  int n_x;
  int n_y;
  double x_offset;
  double y_offset;
  double overall_alpha;
}; 

/* Code common to all interpolation filters */

static void 
correct_total (int    *weights, 
	       int    n_x, 
	       int    n_y,
	       int    total, 
	       double overall_alpha)
{
  int correction = (int)(0.5 + 65536 * overall_alpha) - total;

  if (correction != 0)
    {
      int i;
      for (i = n_x * n_y - 1; i >= 0; i--) 
        {
          if (*(weights + i) + correction >= 0) 
            {
              *(weights + i) += correction;
              break;
            }
        }
    }
}

/* PIXOPS_INTERP_HYPER */

/* current code */

static double
bilinear_table_quadrant (double bx0, double bx1, double by0, double by1)
{
  double ax0, ax1, ay0, ay1;
  double x0, x1, y0, y1;

  ax0 = 0.;
  ax1 = 1.;
  ay0 = 0.;
  ay1 = 1.;

  if (ax0 < bx0)
    {
      if (ax1 > bx0)
	{
	  x0 = bx0;
	  x1 = MIN (ax1, bx1);
	}
      else
	return 0;
    }
  else
    {
      if (bx1 > ax0)
	{
	  x0 = ax0;
	  x1 = MIN (ax1, bx1);
	}
      else
	return 0;
    }

  if (ay0 < by0)
    {
      if (ay1 > by0)
	{
	  y0 = by0;
	  y1 = MIN (ay1, by1);
	}
      else
	return 0;
    }
  else
    {
      if (by1 > ay0)
	{
	  y0 = ay0;
	  y1 = MIN (ay1, by1);
	}
      else
	return 0;
    }

  return 0.25 * (x1*x1 - x0*x0) * (y1*y1 - y0*y0);
}

static void
bilinear_make_table_weights (Pixops2dFilter *filter, double x_scale, double y_scale, double overall_alpha)
{
  int i_offset, j_offset;

  int n_x = ceil (1/x_scale + 2.0);
  int n_y = ceil (1/y_scale + 2.0);

  filter->x_offset = -1.0;
  filter->y_offset = -1.0;
  filter->n_x = n_x;
  filter->n_y = n_y;
  
  filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);

  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
      {
	int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
	double x = (double)j_offset / SUBSAMPLE;
	double y = (double)i_offset / SUBSAMPLE;
	int i,j;
	int total = 0;

	for (i = 0; i < n_y; i++)
	  for (j = 0; j < n_x; j++)
	    {
	      double w;
	      int weight;
	      
	      w = bilinear_table_quadrant  (0.5 + j - (x + 1 / x_scale), 0.5 + j - x, 0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
	      w += bilinear_table_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j, 0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
	      w += bilinear_table_quadrant (0.5 + j - (x + 1 / x_scale), 0.5 + j - x, 1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
	      w += bilinear_table_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j, 1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
	      weight = 65536 * w * x_scale * y_scale * overall_alpha + 0.5;
	      *(pixel_weights + n_x * i + j) = weight;
	      total += weight;
	    }

	correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
      }
}

/* new code */

static double
bilinear_quadrant (double b0, double b1)
{
  double a0, a1;
  double x0, x1;

  a0 = 0.;
  a1 = 1.;

  if (a0 < b0)
    {
      if (a1 > b0)
	{
	  x0 = b0;
	  x1 = MIN (a1, b1);
	}
      else
	return 0;
    }
  else
    {
      if (b1 > a0)
	{
	  x0 = a0;
	  x1 = MIN (a1, b1);
	}
      else
	return 0;
    }

  return (x1*x1 - x0*x0);
}

static void
bilinear_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
{
  double *y_pixel_weights;
  double *x_pixel_weights;
  double w;
  int n_x = ceil (1/x_scale + 2.0);
  int n_y = ceil (1/y_scale + 2.0);
  int offset, i;

  filter->x_offset = -1.0;
  filter->y_offset = -1.0;
  filter->n_x = n_x;
  filter->n_y = n_y;
  filter->x_weights = g_new (double, SUBSAMPLE * n_x);
  filter->y_weights = g_new (double, SUBSAMPLE * n_y);
  filter->overall_alpha = overall_alpha;

  x_pixel_weights = filter->x_weights;
  y_pixel_weights = filter->y_weights;

  for (offset=0; offset < SUBSAMPLE; offset++)
    {
      double x = (double)offset / SUBSAMPLE;
      double a = x + 1 / x_scale;
      double b = x + 1 / y_scale;

      for (i = 0; i < n_x; i++)
        {
          w  = 0.5 * bilinear_quadrant (0.5 + i - a, 0.5 + i - x);
          w += 0.5 * bilinear_quadrant (1.5 + x - i, 1.5 + a - i);
      
          *(x_pixel_weights++) = w * x_scale;
        }

      for (i = 0; i < n_y; i++)
        {
          w =  0.5 * bilinear_quadrant (0.5 + i - b, 0.5 + i - x);
          w += 0.5 * bilinear_quadrant (1.5 + x - i, 1.5 + b - i);
      
          *(y_pixel_weights++) = w * y_scale;
        }
    }
}

/* PIXOPS_INTERP_BILINEAR */

/* current code */

static void
bilinear_make_fast_table_weights (Pixops2dFilter *filter, double x_scale, double y_scale, double overall_alpha)
{
  int i_offset, j_offset;
  double *x_weights, *y_weights;
  int n_x, n_y;

  if (x_scale > 1.0)		/* Bilinear */
    {
      n_x = 2;
      filter->x_offset = 0.5 * (1/x_scale - 1);
    }
  else				/* Tile */
    {
      n_x = ceil (1.0 + 1.0/x_scale);
      filter->x_offset = 0.0;
    }

  if (y_scale > 1.0)		/* Bilinear */
    {
      n_y = 2;
      filter->y_offset = 0.5 * (1/y_scale - 1);
    }
  else				/* Tile */
    {
      n_y = ceil (1.0 + 1.0/y_scale);
      filter->y_offset = 0.0;
    }

  filter->n_y = n_y;
  filter->n_x = n_x;
  filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);

  x_weights = g_new (double, n_x);
  y_weights = g_new (double, n_y);

  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
      {
	int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
	double x = (double)j_offset / SUBSAMPLE;
	double y = (double)i_offset / SUBSAMPLE;
	int i,j;
	int total = 0;

	if (x_scale > 1.0)	/* Bilinear */
	  {
	    for (i = 0; i < n_x; i++)
	      {
		x_weights[i] = ((i == 0) ? (1 - x) : x) / x_scale;
	      }
	  }
	else			/* Tile */
	  {
	    /*           x
	     * ---------|--.-|----|--.-|-------  SRC
	     * ------------|---------|---------  DEST
	     */
	    for (i = 0; i < n_x; i++)
	      {
		if (i < x)
		  {
		    if (i + 1 > x)
		      x_weights[i] = MIN (i+1, x + 1/x_scale) - x;
		    else
		      x_weights[i] = 0;
		  }
		else
		  {
		    if (x + 1/x_scale > i)
		      x_weights[i] = MIN (i+1, x + 1/x_scale) - i;
		    else
		      x_weights[i] = 0;
		  }
	      }
	  }

	if (y_scale > 1.0)	/* Bilinear */
	  {
	    for (i = 0; i < n_y; i++)
	      {
		y_weights[i] = ((i == 0) ? (1 - y) : y) / y_scale;
	      }
	  }
	else			/* Tile */
	  {
	    /*           y
	     * ---------|--.-|----|--.-|-------  SRC
	     * ------------|---------|---------  DEST
	     */
	    for (i = 0; i < n_y; i++)
	      {
		if (i < y)
		  {
		    if (i + 1 > y)
		      y_weights[i] = MIN (i+1, y + 1/y_scale) - y;
		    else
		      y_weights[i] = 0;
		  }
		else
		  {
		    if (y + 1/y_scale > i)
		      y_weights[i] = MIN (i+1, y + 1/y_scale) - i;
		    else
		      y_weights[i] = 0;
		  }
	      }
	  }

	for (i = 0; i < n_y; i++)
	  for (j = 0; j < n_x; j++)
	    {
	      int weight = 65536 * x_weights[j] * x_scale * y_weights[i] * y_scale * overall_alpha + 0.5;
	      *(pixel_weights + n_x * i + j) = weight;
	      total += weight;
	    }

	correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
      }

  g_free (x_weights);
  g_free (y_weights);
}

/* new code */

static void
bilinear_make_fast_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
{
  double *x_pixel_weights;
  double *y_pixel_weights;
  int n_x, n_y;
  int offset;
  int i;

  if (x_scale > 1.0)		/* Bilinear */
    {
      n_x = 2;
      filter->x_offset = 0.5 * (1 / x_scale - 1);
    }
  else				/* Tile */
    {
      n_x = ceil (1.0 + 1.0 / x_scale);
      filter->x_offset = 0.0;
    }

  if (y_scale > 1.0)		/* Bilinear */
    {
      n_y = 2;
      filter->y_offset = 0.5 * (1 / y_scale - 1);
    }
  else				/* Tile */
    {
      n_y = ceil (1.0 + 1.0 / y_scale);
      filter->y_offset = 0.0;
    }

  filter->n_y = n_y;
  filter->n_x = n_x;
  filter->x_weights = g_new (double, SUBSAMPLE * n_x);
  filter->y_weights = g_new (double, SUBSAMPLE * n_y);
  filter->overall_alpha = overall_alpha;

  x_pixel_weights = filter->x_weights;
  y_pixel_weights = filter->y_weights;

  for (offset=0; offset < SUBSAMPLE; offset++)
    {
      double x = (double)offset / SUBSAMPLE;

      if (x_scale > 1.0)      /* Bilinear */
        {
          for (i = 0; i < n_x; i++)
            *(x_pixel_weights++) = (((i == 0) ? (1 - x) : x) / x_scale) * x_scale;
        }
      else                  /* Tile */
        {
          double a = x + 1 / x_scale;

          /*           x
           * ---------|--.-|----|--.-|-------  SRC
           * ------------|---------|---------  DEST
           */
          for (i = 0; i < n_x; i++)
            {
              if (i < x)
                {
                  if (i + 1 > x)
                    *(x_pixel_weights++) = (MIN (i + 1, a) - x) * x_scale;
                  else
                    *(x_pixel_weights++) = 0;
                }
              else
                {
                  if (a > i)
                    *(x_pixel_weights++) = (MIN (i + 1, a) - i) * x_scale;
                  else
                    *(x_pixel_weights++) = 0;
                }
            }
        }

      if (y_scale > 1.0)      /* Bilinear */
        {
          for (i = 0; i < n_y; i++)
            *(y_pixel_weights++) = (((i == 0) ? (1 - x) : x) / y_scale) * y_scale;
        }
      else                  /* Tile */
        {
          double b = x + 1 / y_scale;

          /*           x
           * ---------|--.-|----|--.-|-------  SRC
           * ------------|---------|---------  DEST
           */
          for (i = 0; i < n_y; i++)
            {
              if (i < x)
                {
                  if (i + 1 > x)
                    *(y_pixel_weights++) = (MIN (i + 1, b) - x) * y_scale;
                  else
                    *(y_pixel_weights++) = 0;
                }
              else
                {
                  if (b > i)
                    *(y_pixel_weights++) = (MIN (i + 1, b) - i) * y_scale;
                  else
                    *(y_pixel_weights++) = 0;
                }
            }
        }
    }
}

/* PIXOPS_INTERP_TILE */

/* current code */

static void
tile_make_table_weights (Pixops2dFilter *filter, double x_scale, double y_scale, double overall_alpha)
{
  int i_offset, j_offset;

  int n_x = ceil (1/x_scale + 1);
  int n_y = ceil (1/y_scale + 1);

  filter->x_offset = 0;
  filter->y_offset = 0;
  filter->n_x = n_x;
  filter->n_y = n_y;
  filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);

  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
      {
	int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
	double x = (double)j_offset / SUBSAMPLE;
	double y = (double)i_offset / SUBSAMPLE;
	int i,j;
	int total = 0;
	  
	for (i = 0; i < n_y; i++)
	  {
	    double tw, th;
		
	    if (i < y)
	      {

		if (i + 1 > y)
		  th = MIN (i+1, y + 1/y_scale) - y;
		else
		  th = 0;
	      }
	    else
	      {
		if (y + 1/y_scale > i)
		  th = MIN (i+1, y + 1/y_scale) - i;
		else
		  th = 0;
	      }
		
	    for (j = 0; j < n_x; j++)
	      {
		int weight;
		
		if (j < x)
		  {
		    if (j + 1 > x)
		      tw = MIN (j+1, x + 1/x_scale) - x;
		    else
		      tw = 0;
		  }
		else
		  {
		    if (x + 1/x_scale > j)
		      tw = MIN (j+1, x + 1/x_scale) - j;
		    else
		      tw = 0;
		  }

		weight = 65536 * tw * x_scale * th * y_scale * overall_alpha + 0.5;
		total += weight;
		*(pixel_weights + n_x * i + j) = weight;
	      }
	  }
	
	correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
      }
}

/* new code */

static void
tile_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
{
  double *x_pixel_weights;
  double *y_pixel_weights;
  int n_x = ceil (1/x_scale + 1);
  int n_y = ceil (1/y_scale + 1);
  int offset;
  int i;

  filter->x_offset = 0;
  filter->y_offset = 0;
  filter->n_x = n_x;
  filter->n_y = n_y;
  filter->x_weights = g_new (double, SUBSAMPLE * n_x);
  filter->y_weights = g_new (double, SUBSAMPLE * n_y);
  filter->overall_alpha = overall_alpha;

  x_pixel_weights = filter->x_weights;
  y_pixel_weights = filter->y_weights;

  for (offset=0; offset < SUBSAMPLE; offset++)
    {
      double x = (double)offset / SUBSAMPLE;
      double a = x + 1 / x_scale;
      double b = x + 1 / y_scale;

      for (i = 0; i < n_x; i++)
        {
          if (i < x)
            {
              if (i + 1 > x)
                *(x_pixel_weights++)  = (MIN (i + 1, a) - x) * x_scale;
              else
                *(x_pixel_weights++) = 0;
            }
          else
            {
              if (a > i)
                *(x_pixel_weights++)  = (MIN (i + 1, a) - i) * x_scale;
              else
                *(x_pixel_weights++) = 0;
            }
       }
        
      for (i = 0; i < n_y; i++)
        {
          if (i < x)
            {
              if (i + 1 > x)
                *(y_pixel_weights++) = (MIN (i + 1, b) - x) * y_scale;
              else
                *(y_pixel_weights++) = 0;
            }
          else
            {
              if (b > i)
                *(y_pixel_weights++) = (MIN (i + 1, b) - i) * y_scale;
              else
                *(y_pixel_weights++) = 0;
            }
        }
    }
}

/* Test driver code */

void
print_vector(PixopsFilter *vector)
{
  int i, j, x, y;

  if (! DEBUG_PRINT_VECTOR)
     return;

  printf ("  vector->n_x = %d, vector->n_y = %d\n", vector->n_x, vector->n_y);
  printf ("  vector->x_offset = %f, vector->y_offset = %f\n",
          vector->x_offset, vector->y_offset);

  for (x=0; x < SUBSAMPLE; x++)
    {
      double sum = 0;
      printf ("  --- x_vector %d of %d---\n", x, SUBSAMPLE - 1);
      for (j = 0; j < vector->n_x; j++)
        {
          printf ("  %5.2f  ", vector->x_weights[(x * vector->n_x) + j]);
          sum += vector->x_weights[(x * vector->n_x) + j];
        }
      printf( "  sum is %5.2f\n", sum);
    }
  for (y=0; y < SUBSAMPLE; y++)
    {
      double sum = 0;
      printf ("  --- y_vector %d of %d---\n", y, SUBSAMPLE - 1);
      for (i = 0; i < vector->n_y; i++)
        {
          printf ("  %5.2f  ", vector->y_weights[(y * vector->n_y) + i]);
          sum +=  vector->y_weights[(y * vector->n_y) + i];
        }
      printf( "  sum is %5.2f\n", sum);
    }
}

static int *
convert_vector_to_table(PixopsFilter *vector)
{
  int i_offset, j_offset;
  int n_x = vector->n_x;
  int n_y = vector->n_y;
  int * weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);

  print_vector(vector);

  if (DEBUG_PRINT_CORRECTION)
    printf ("\n  ---\n");

  for (i_offset=0; i_offset < SUBSAMPLE; i_offset++)
    for (j_offset=0; j_offset < SUBSAMPLE; j_offset++)
      {
        double weight;
        int *pixel_weights = weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
        int total = 0;
        int i,j;

        for (i=0; i < n_y; i++)
          for (j=0; j < n_x; j++)
            {
              weight = vector->x_weights[(j_offset * n_x) + j] *
                       vector->y_weights[(i_offset * n_y) + i] *
                       vector->overall_alpha * 65536 + 0.5;

              total += (int)weight;
		
              *(pixel_weights + n_x * i + j) = weight;
            }

        if (DEBUG_PRINT_CORRECTION)
          {
            printf ("   Correcting table (%d %d) = %d\n", i_offset, j_offset,
                    (int)(0.5 + 65536 * vector->overall_alpha) - total);
          }
	
	correct_total (pixel_weights, n_x, n_y, total, vector->overall_alpha);
      }

  if (DEBUG_PRINT_CORRECTION)
    printf ("  ---\n\n");

  return weights;
}

void
print_table(Pixops2dFilter *filter)
{
  double w0;
  int i, j, x;

  if (! DEBUG_PRINT_TABLE)
     return;

  printf ("  filter->n_x = %d, filter->n_y = %d\n", filter->n_x, filter->n_y);
  printf ("  filter->x_offset = %f, filter->y_offset = %f\n",
          filter->x_offset, filter->y_offset);
  w0 = (double)filter->weights[0];

  for (x=0; x < SUBSAMPLE * SUBSAMPLE; x++)
    {
      printf ("  --- filter %d of %d---\n", x, SUBSAMPLE * SUBSAMPLE - 1);
      for (i = 0; i < filter->n_y; i++)
        {
          for (j = 0; j < filter->n_x; j++)
            printf ("  %5.2f  ", filter->weights[(i + (x * filter->n_y)) *
                    filter->n_x + j] / w0);

          printf( "\n");
        }
      printf( "\n");
    }
}

void
compare_filters (Pixops2dFilter *filter1, Pixops2dFilter *filter2)
{
  int x;
  int total_error_flag = 0;

  if (filter1->n_y != filter2->n_y || filter1->n_x != filter2->n_x)
     printf ("ERROR - Tables not same size\n");

  else
    {
      printf ("  --- filter check start ---\n");

      for (x=0; x < filter1->n_x * filter1->n_y * SUBSAMPLE * SUBSAMPLE; x++)
	{
	  if (filter1->weights[x] != filter2->weights[x])
            {
               printf ("ERROR - There is a problem with position %d %ld %ld\n",
		 x, filter1->weights[x], filter2->weights[x]);
		total_error_flag++;
            }
	}

      printf ("  --- filter check end ---\n");

      if (total_error_flag > 0)
        printf ("ERROR - %d total problems were found\n\n", total_error_flag);
      else
        printf ("  No problems were found\n\n");
    }
}

void do_hyper_test (double x_scale, double y_scale, double overall_alpha)
{
  Pixops2dFilter table;
  Pixops2dFilter converted_table;
  PixopsFilter   vector;

  bilinear_make_table_weights (&table, x_scale, y_scale, overall_alpha);
  printf ("x_scale = %f, y_scale = %f\n", x_scale, y_scale);
  print_table (&table);

  bilinear_make_weights (&vector, x_scale, y_scale, overall_alpha);
  printf ("x_scale = %f, y_scale = %f\n", x_scale, y_scale);

  converted_table.weights = convert_vector_to_table (&vector);
  converted_table.n_x = vector.n_x;
  converted_table.n_y = vector.n_y;
  converted_table.x_offset = vector.x_offset;
  converted_table.y_offset = vector.y_offset;

  print_table (&converted_table);

  compare_filters (&table, &converted_table);
}

void do_bilinear_test (double x_scale, double y_scale, double overall_alpha)
{
  Pixops2dFilter table;
  Pixops2dFilter converted_table;
  PixopsFilter   vector;

  bilinear_make_fast_table_weights (&table, x_scale, y_scale, overall_alpha);
  printf ("x_scale = %f, y_scale = %f\n", x_scale, y_scale);
  print_table (&table);

  bilinear_make_fast_weights (&vector, x_scale, y_scale, overall_alpha);
  printf ("x_scale = %f, y_scale = %f\n", x_scale, y_scale);

  converted_table.weights = convert_vector_to_table (&vector);
  converted_table.n_x = vector.n_x;
  converted_table.n_y = vector.n_y;
  converted_table.x_offset = vector.x_offset;
  converted_table.y_offset = vector.y_offset;

  print_table (&converted_table);

  compare_filters (&table, &converted_table);
}

void do_tile_test (double x_scale, double y_scale, double overall_alpha)
{
  Pixops2dFilter table;
  Pixops2dFilter converted_table;
  PixopsFilter   vector;

  tile_make_table_weights (&table, x_scale, y_scale, overall_alpha);
  printf ("  x_scale = %f, y_scale = %f\n", x_scale, y_scale);
  print_table (&table);

  tile_make_weights (&vector, x_scale, y_scale, overall_alpha);
  printf ("  x_scale = %f, y_scale = %f\n", x_scale, y_scale);

  converted_table.weights = convert_vector_to_table (&vector);
  converted_table.n_x = vector.n_x;
  converted_table.n_y = vector.n_y;
  converted_table.x_offset = vector.x_offset;
  converted_table.y_offset = vector.y_offset;

  print_table (&converted_table);

  compare_filters (&table, &converted_table);
}

int
main()
{
  printf ("\nDoing PIXOPS_INTERP_TILE tests:\n\n");
  do_tile_test (1.0,  1.0, 1.0);
  do_tile_test (0.5,  0.5, 1.0);
  do_tile_test (0.3,  0.3, 1.0);
  do_tile_test (0.25, 0.25, 1.0);
  do_tile_test (0.20, 0.20, 1.0);
  do_tile_test (0.15, 0.15, 1.0);
  do_tile_test (0.5,  1.0, 1.0);
  do_tile_test (0.5,  2.0, 1.0);
  do_tile_test (0.5,  3.0, 1.0);
  do_tile_test (0.5,  4.0, 1.0);
  do_tile_test (2.0,  2.0, 1.0);

  printf ("\nDoing PIXOPS_INTERP_BILINEAR tests:\n\n");
  do_bilinear_test (1.0,  1.0, 1.0);
  do_bilinear_test (0.5,  0.5, 1.0);
  do_bilinear_test (0.3,  0.3, 1.0);
  do_bilinear_test (0.25, 0.25, 1.0);
  do_bilinear_test (0.20, 0.20, 1.0);
  do_bilinear_test (0.15, 0.15, 1.0);
  do_bilinear_test (0.5,  1.0, 1.0);
  do_bilinear_test (0.5,  2.0, 1.0);
  do_bilinear_test (0.5,  3.0, 1.0);
  do_bilinear_test (0.5,  4.0, 1.0);
  do_bilinear_test (2.0,  2.0, 1.0);

  printf ("\nDoing PIXOPS_INTERP_HYPER tests:\n\n");
  do_hyper_test (1.0,  1.0, 1.0);
  do_hyper_test (0.5,  0.5, 1.0);
  do_hyper_test (0.3,  0.3, 1.0);
  do_hyper_test (0.25, 0.25, 1.0);
  do_hyper_test (0.20, 0.20, 1.0);
  do_hyper_test (0.15, 0.15, 1.0);
  do_hyper_test (0.5,  1.0, 1.0);
  do_hyper_test (0.5,  2.0, 1.0);
  do_hyper_test (0.5,  3.0, 1.0);
  do_hyper_test (0.5,  4.0, 1.0);
  do_hyper_test (2.0,  2.0, 1.0);

  exit (0);
}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]