Index: source/blender/makesrna/intern/rna_nodetree.c =================================================================== --- source/blender/makesrna/intern/rna_nodetree.c (revision 44721) +++ source/blender/makesrna/intern/rna_nodetree.c (working copy) @@ -2732,6 +2732,7 @@ {0, "NEAREST", 0, "Nearest", ""}, {1, "BILINEAR", 0, "Bilinear", ""}, {2, "BICUBIC", 0, "Bicubic", ""}, + {3, "CUBICBSPLINE", 0, "Cubic B-Spline with Prefilter"}, {0, NULL, 0, NULL, NULL}}; prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); @@ -2779,6 +2780,7 @@ {0, "NEAREST", 0, "Nearest", ""}, {1, "BILINEAR", 0, "Bilinear", ""}, {2, "BICUBIC", 0, "Bicubic", ""}, + {3, "CUBICBSPLINE", 0, "Cubic B-Spline with Prefilter"}, {0, NULL, 0, NULL, NULL}}; prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE); Index: source/blender/imbuf/intern/imageprocess.c =================================================================== --- source/blender/imbuf/intern/imageprocess.c (revision 44721) +++ source/blender/imbuf/intern/imageprocess.c (working copy) @@ -41,15 +41,14 @@ */ #include +#include +#include #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "math.h" +#include "BLI_utildefines.h" -/* This define should be relocated to a global header some where Kent Mein -I stole it from util.h in the plugins api */ -#define MAX2(x,y) ( (x)>(y) ? (x) : (y) ) - /* Only this one is used liberally here, and in imbuf */ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf) { @@ -153,11 +152,11 @@ for(n= -1; n<= 2; n++){ x1= i+n; - if (x1>0 && x1 < in->x) { + if (x1>=0 && x1 < in->x) { wx = P(n-a); for(m= -1; m<= 2; m++){ y1= j+m; - if (y1>0 && y1y) { + if (y1>=0 && y1y) { /* normally we could do this */ /* w = P(n-a) * P(b-m); */ /* except that would call P() 16 times per pixel therefor pow() 64 times, better precalc these */ @@ -180,9 +179,9 @@ } } } - } + } -/* Done with optimized part */ +/* Done with optimized part */ #if 0 /* older, slower function, works the same as above */ @@ -190,15 +189,15 @@ for(m= -1; m<= 2; m++){ x1= i+n; y1= j+m; - if (x1>0 && x1 < in->x && y1>0 && y1y) { - if (do_float) { + if (x1>=0 && x1 < in->x && y1>=0 && y1y) { + if (outF) { dataF= in->rect_float + in->x * y1 * 4 + 4*x1; outR+= dataF[0] * P(n-a) * P(b-m); outG+= dataF[1] * P(n-a) * P(b-m); outB+= dataF[2] * P(n-a) * P(b-m); outA+= dataF[3] * P(n-a) * P(b-m); } - if (do_rect) { + if (outI) { dataI= (unsigned char*)in->rect + in->x * y1 * 4 + 4*x1; outR+= dataI[0] * P(n-a) * P(b-m); outG+= dataI[1] * P(n-a) * P(b-m); @@ -310,6 +309,114 @@ } } +void prefilter(ImBuf *in, ImBuf *out) +{ + int x, y; + + // A row of float coefficients. + float *coeff = out->rect_float; + + if (in == NULL || in->rect_float == NULL || out == NULL || + out->rect_float == NULL || in->x <= 2 || in->y <=2) + return; + + // Initialize + memcpy(coeff, in->rect_float, in->x * in->y * 4 * sizeof(float)); + + // X Recursion + for(y = 0; y < in->y; y++) + prefilter_doRecursion(&coeff[y * in->x * 4], in->x, 4); + // Y Recursion + for(x = 0; x < in->x; x++) + prefilter_doRecursion(&coeff[x * 4], in->y, in->x * 4); + + // Copy to the out ImBuf. + memcpy(out->rect_float, coeff, (in->x * in->y * 4 * sizeof(float))); +} + +// Get the initial causual coefficient for a given run of floats at stride count +// of floats. +void prefilter_initInitialCausal(float *coeffIn, float *sum, unsigned int length, unsigned int stride) +{ + const float Zp = sqrt(3.0f)-2.0f; + const float lambda = (1.0f - Zp) * (1.0f - 1.0f / Zp); + unsigned int count = 0, horizon = MIN2(12, length) * 4; + float Zn = Zp; + + sum[0] = coeffIn[0]; // R + sum[1] = coeffIn[1]; // G + sum[2] = coeffIn[2]; // B + sum[3] = coeffIn[3]; // A + + for (count = 0; count < horizon; count += stride) { + sum[0] += Zn * coeffIn[count]; // R + sum[1] += Zn * coeffIn[count+1]; // G + sum[2] += Zn * coeffIn[count+2]; // B + sum[3] += Zn * coeffIn[count+3]; // A + + Zn *= Zp; + } + + coeffIn[0] = (lambda * sum[0]); // R + coeffIn[1] = (lambda * sum[1]); // G + coeffIn[2] = (lambda * sum[2]); // B + coeffIn[3] = (lambda * sum[3]); // A +} + +// Set the initial anti-causual coefficient at the end of the given run of +// floats at stride count of floats. +void prefilter_initInitialAntiCausal(float *coeffIn) +{ + const float Zp = sqrt(3.0f)-2.0f; + const float iZp = (Zp / (Zp - 1.0f)); + + coeffIn[0] = iZp * coeffIn[0]; //R + coeffIn[1] = iZp * coeffIn[1]; //G + coeffIn[2] = iZp * coeffIn[2]; //B + coeffIn[3] = iZp * coeffIn[3]; //A +} + + +void prefilter_doRecursion(float *coeffIn, unsigned int length, unsigned int stride) +{ + const float Zp = sqrt(3.0f)-2.0f; + const float lambda = (1.0f - Zp) * (1.0f - 1.0f / Zp); + float prevcoeff[4] = { 0, 0, 0, 0 }; + float sum[4] = { 0, 0, 0, 0 }; + int count = 0; + unsigned int total_floats = length * 4; + + prefilter_initInitialCausal(coeffIn, sum, length, 4); + + prevcoeff[0] = coeffIn[0]; // R + prevcoeff[1] = coeffIn[1]; // G + prevcoeff[2] = coeffIn[2]; // B + prevcoeff[3] = coeffIn[3]; // A + + for (count = (1 * stride); count < total_floats; count += stride) { + coeffIn[count] = prevcoeff[0] = (lambda * coeffIn[count]) + (Zp * prevcoeff[0]); // R + coeffIn[count + 1] = prevcoeff[1] = (lambda * coeffIn[count + 1]) + (Zp * prevcoeff[1]); // G + coeffIn[count + 2] = prevcoeff[2] = (lambda * coeffIn[count + 2]) + (Zp * prevcoeff[2]); // B + coeffIn[count + 3] = prevcoeff[3] = (lambda * coeffIn[count + 3]) + (Zp * prevcoeff[3]); // A + } + + count -= stride; + prefilter_initInitialAntiCausal(&coeffIn[count]); + + prevcoeff[0] = coeffIn[count]; // R + prevcoeff[1] = coeffIn[count + 1]; // G + prevcoeff[2] = coeffIn[count + 2]; // B + prevcoeff[3] = coeffIn[count + 3]; // A + + for (count -= stride; count >= 0; count -= stride) { + coeffIn[count] = prevcoeff[0] = Zp * (prevcoeff[0] - coeffIn[count]); // R + coeffIn[count + 1] = prevcoeff[1] = Zp * (prevcoeff[1] - coeffIn[count + 1]); // G + coeffIn[count + 2] = prevcoeff[2] = Zp * (prevcoeff[2] - coeffIn[count + 2]); // B + coeffIn[count + 3] = prevcoeff[3] = Zp * (prevcoeff[3] - coeffIn[count + 3]); // A + } +} + + /* function assumes out to be zero'ed, only does RGBA */ /* BILINEAR INTERPOLATION */ Index: source/blender/imbuf/IMB_imbuf.h =================================================================== --- source/blender/imbuf/IMB_imbuf.h (revision 44721) +++ source/blender/imbuf/IMB_imbuf.h (working copy) @@ -404,6 +404,12 @@ * * \attention defined in imageprocess.c */ + +void prefilter_initInitialCausal(float *coeffIn, float *sum, unsigned int length, unsigned int stride); +void prefilter_initInitialAntiCausal(float *coeffIn); +void prefilter_doRecursion(float *coeffIn, unsigned int length, unsigned int stride); +void prefilter(struct ImBuf *in, struct ImBuf *out); + void bicubic_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout); void neareast_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout); void bilinear_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout); Index: source/blender/nodes/composite/nodes/node_composite_transform.c =================================================================== --- source/blender/nodes/composite/nodes/node_composite_transform.c (revision 44721) +++ source/blender/nodes/composite/nodes/node_composite_transform.c (working copy) @@ -51,7 +51,7 @@ CompBuf* node_composit_transform(CompBuf *cbuf, float x, float y, float angle, float scale, int filter_type) { CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); - ImBuf *ibuf, *obuf; + ImBuf *ibuf = NULL, *obuf = NULL,*fbuf = NULL; float mat[4][4], lmat[4][4], rmat[4][4], smat[4][4], cmat[4][4], icmat[4][4]; float svec[3]= {scale, scale, scale}, loc[2]= {x, y}; @@ -59,7 +59,7 @@ unit_m4(lmat); unit_m4(smat); unit_m4(cmat); - + /* image center as rotation center */ cmat[3][0]= (float)cbuf->x/2.0f; cmat[3][1]= (float)cbuf->y/2.0f; @@ -73,16 +73,24 @@ mul_serie_m4(mat, lmat, cmat, rmat, smat, icmat, NULL, NULL, NULL); invert_m4(mat); - + ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0); obuf= IMB_allocImBuf(stackbuf->x, stackbuf->y, 32, 0); - if(ibuf && obuf) { + if (ibuf && obuf) { + ibuf->rect_float= cbuf->rect; + obuf->rect_float= stackbuf->rect; + + if (filter_type == 3) { + fbuf = IMB_allocImBuf(cbuf->x, cbuf->y, 32, IB_rectfloat); + if (fbuf) + prefilter(ibuf, fbuf); + } + } + + if(ibuf && obuf && (fbuf || (filter_type != 3)) ) { int i, j; - ibuf->rect_float= cbuf->rect; - obuf->rect_float= stackbuf->rect; - for(j=0; jy; j++) { for(i=0; ix;i++) { float vec[3]= {i, j, 0}; @@ -99,10 +107,15 @@ case 2: bicubic_interpolation(ibuf, obuf, vec[0], vec[1], i, j); break; + case 3: + bicubic_interpolation(fbuf, obuf, vec[0], vec[1], i, j); + break; } } } - + + if (fbuf) + IMB_freeImBuf(fbuf); IMB_freeImBuf(ibuf); IMB_freeImBuf(obuf); }