#include "bicubic.h"

#if 1

#define LDUMP(x)

#define up(x)  ((x) << 8)
#define dn(x)  ((x + (1 << 7)) >> 8)
#define dn2(x)  ((x + (1 << 15)) >> 16)

double BiCubicKernel3Imp(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(r / 6.0);
}

static int kernel[up(4)];

force_inline
int BiCubicKernel3(int x)
{
	x += up(2);
	ASSERT(x >= 0 && x <= up(4) + 1);
	return kernel[x];
}

Image RescaleBicubic3(Image& img, int cx, int cy)
{
	ONCELOCK {
		for(int i = 0; i < up(4); i++) {
			kernel[i] = int(up(1) * BiCubicKernel3Imp((double)i / up(1) - 2));
		}
	}
	Size isz = img.GetSize();
	ImageBuffer ib(cx, cy);
	RGBA *t = ~ib;
	for(int y = 0; y < cy; y++) {
		int sy = y * isz.cy / cy;
		int dy = up(y * isz.cy) / cy - up(sy);
		for(int x = 0; x < cx; x++) {
			int sx = x * isz.cx / cx;
			int dx = up(x * isz.cx) / cx - up(sx);
			int red   = 0;
			int green = 0;
			int blue  = 0;
			int alpha = 0;
			int w = 0;
			for(int yy = -1; yy <= 2; yy++) {
				int ky = BiCubicKernel3(up(yy) - dy);
				const RGBA *l = img[minmax(sy + yy, 0, isz.cy - 1)];
				for(int xx = -1; xx <= 2; xx++) {
					const RGBA& s = l[minmax(sx + xx, 0, isz.cx - 1)];
					int weight = ky * BiCubicKernel3(up(xx) - dx);
					LDUMP(weight);
					red   += weight * s.r;
					green += weight * s.g;
					blue  += weight * s.b;
					LDUMP((int)s.a);
					alpha += weight * s.a;
					LDUMP(alpha);
					w += weight;
				}
    		}
			t->r = dn2(red);
			t->g = dn2(green);
			t->b = dn2(blue);
			t->a = dn2(alpha);
			LDUMP((int)t->a);
			LDUMP(w);
	//		return ib;
			t++;
		}
	}
	return ib;
}

#endif