text: #include "Draw.h"
  
  namespace Upp {
  
  double BicubicKernel(double x)
  {
  	double r = 0;
  	double xp2 = x + 2;
  	double xp1 = x + 1;
  	double xm1 = x - 1;
  	if(xp2 > 0)
  		r += xp2 * xp2 * xp2;
  	if(xp1 > 0)
  		r -= 4 * xp1 * xp1 * xp1;
  	if(x > 0)
  		r += 6 * x * x * x;
  	if(xm1 > 0)
  		r -= 4 * xm1 * xm1 * xm1;
  	return 1 / 6.0 * r;
  }
  
  Image RescaleBicubic(const Image& img, Size sz, const Rect& sr, Gate<int, int> progress)
  {
  	ASSERT(sr.top >= 0 && sr.left >= 0 && sr.right <= img.GetWidth() && sr.bottom <= img.GetHeight());
  	Size isz = sr.GetSize();
  	ImageBuffer ib(sz);
  	RGBA *t = ~ib;
  	double inv_cx = 1.0 / sz.cx;
  	for(int y = 0; y < sz.cy; y++) {
  		if(progress(y, sz.cy))
  			return ib;
  		int sy = y * isz.cy / sz.cy;
  		double dy = y * isz.cy / (double)sz.cy - sy;
  		for(int x = 0; x < sz.cx; x++) {
  			int sx = x * isz.cx / sz.cx;
  			double dx = x * isz.cx * inv_cx - sx;
  			double red   = 0;
  			double green = 0;
  			double blue  = 0;
  			double alpha = 0;
  			for(int yy = -1; yy <= 2; yy++) {
  				double ky = BicubicKernel(yy - dy);
  				const RGBA *l = img[minmax(sy + yy + sr.top, sr.top, sr.bottom - 1)];
  				for(int xx = -1; xx <= 2; xx++) {
  					const RGBA& s = l[minmax(sx + xx + sr.left, sr.left, sr.right - 1)];
  					double weight = ky * BicubicKernel(xx - dx);
  					red   += weight * s.r;
  					green += weight * s.g;
  					blue  += weight * s.b;
  					alpha += weight * s.a;
  				}
      		}
  			t->r = (int)fround(red);
  			t->g = (int)fround(green);
  			t->b = (int)fround(blue);
  			t->a = (int)fround(alpha);
  			t++;
  		}
  	}
  	return ib;
  }
  
  Image RescaleBicubic(const Image& img, int cx, int cy, Gate<int, int> progress)
  {
  	return RescaleBicubic(img, Size(cx, cy), img.GetSize(), progress);
  }
  
  Image RescaleBicubic(const Image& img, Size sz, Gate<int, int> progress)
  {
  	return RescaleBicubic(img, sz, img.GetSize(), progress);
  }
  
  }
  