Index: source/blender/makesrna/intern/rna_nodetree.c =================================================================== --- source/blender/makesrna/intern/rna_nodetree.c (revision 44566) +++ source/blender/makesrna/intern/rna_nodetree.c (working copy) @@ -2783,6 +2783,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); @@ -2830,6 +2831,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 44566) +++ source/blender/imbuf/intern/imageprocess.c (working copy) @@ -41,15 +41,13 @@ */ #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) { @@ -310,6 +308,152 @@ } } +void prefilter(ImBuf *in, ImBuf *out, unsigned int w, unsigned int h) +{ + // Pole of Z-Transform for Cubic Spline. + const float Zp = sqrt(3.0f)-2.0f; + // AntiPole + const float iZp = Zp / (Zp - 1.0f); + // Gain to normalize coefficients. + const float lambda = (1.0f - Zp) * (1.0f - (1.0f / Zp)); + // Horizon value of 12 or width, whatever is smaller. + const unsigned int horzx = MIN2(12,w); + // Horizon value of 12 or height, whatever is smaller. + const unsigned int horzy = MIN2(12,h); + // Count of floats in an RGBA quad for code legibility. + const int sizeRGBA = 4; + // Count of floats in an RGB triplet for code legibility. + const int sizeRGB = 3; + // Count of image pixels. + const int sizeImage = w * h * sizeRGBA; + // Storage for Zp^x. + float Zn = 0; + // Storage for the step factor for iteration. + int step = 0; + // A sum storage triplet (TODO: Consider alpha?). + float sum[3] = { 0, 0, 0 }; + // A previous coefficient storage triplet (TODO: Consider alpha?). + float prevcoeff[3] = { 0, 0, 0 }; + + float* curcoeff = NULL; + + int curRGB, x, y, n; + // A row of float coefficients. + float *coeff = out->rect_float; + + if (in == NULL || in->rect_float == NULL || out == NULL || + out->rect_float == NULL || w <= 2 || h <=2) + return; + + // Initialize our coefficients to our image base. + //for (y = 0; y < h; y++) + // for (x = 0; x < w; x++) + // Initialize with alpha (sizeRGBA), despite it not being used. + // for (curRGB = 0; curRGB < sizeRGBA; curRGB++) + // coeff[(y * w * sizeRGBA) + (x * sizeRGBA) + curRGB] = + // in->rect_float[(y * w * sizeRGBA) + (x * sizeRGBA) + curRGB]; + + // Iterate along x. + for (y = 0; y < h; y++) { + // Initialize the sum to the coefficient at the first pixel on our row. + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + sum[curRGB] = coeff[(y * w * sizeRGBA) + curRGB]; + + Zn = Zp; + + // Generate the initial causal. + for (n = 0; n < horzx; n++){ + curcoeff = &coeff[(y * w * sizeRGBA) + (n * sizeRGBA)]; + + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + sum[curRGB] += Zn * curcoeff[curRGB]; + + Zn *= Zp; + } + + // Set the initial RGB causal coefficients at the first pixel position. + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + coeff[(y * w * sizeRGBA) + curRGB] = prevcoeff[curRGB] = lambda * sum[curRGB]; + + // Perform the causal recursion along each row. n = 1 skips our + // first coefficient above. + for (x = 1; x < w; x++) + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + coeff[(y * w * sizeRGBA) + (x * sizeRGBA) + curRGB] = + prevcoeff[curRGB] = + (lambda * coeff[(y * w * sizeRGBA) + (x * sizeRGBA) + curRGB]) + + (Zp * prevcoeff[curRGB]); + + // Generate the initial anti-causal at the last pixel per row. + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + coeff[(y * w * sizeRGBA) + ((w - 1) * sizeRGBA) + curRGB] = + prevcoeff[curRGB] = + iZp * coeff[(y * w * sizeRGBA) + ((w - 1) * sizeRGBA) + curRGB]; + + // Perform anti-causal recursion along each row. n = w - 2 skips our + // last coefficient above. + for (x = w - 2; x >= 0; x--) + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + coeff[(y * w * sizeRGBA) + (x * sizeRGBA) + curRGB] = + prevcoeff[curRGB] = Zp * (prevcoeff[curRGB] - + coeff[(y * w * sizeRGBA) + (x * sizeRGBA) + curRGB]); + } + + // Iterate along y. + for (x = 0; x < w; x++) { + // Initialize the sum to the coefficient at the first pixel on our row. + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + sum[curRGB] = coeff[(x * sizeRGBA) + curRGB]; + + Zn = Zp; + + // Generate the initial causal. + for (n = 0; n < horzy; n++){ + curcoeff = &coeff[(x * sizeRGBA) + (n * w * sizeRGBA)]; + + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + sum[curRGB] += Zn * curcoeff[curRGB]; + + Zn *= Zp; + } + + // Set the initial RGB causal coefficients at the first pixel position. + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + coeff[(x * sizeRGBA) + curRGB] = prevcoeff[curRGB] = lambda * sum[curRGB]; + + // Perform the causal recursion along each row. n = 1 skips our + // first coefficient above. + for (y = 1; y < h; y++) + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + coeff[(x * sizeRGBA) + (y * w * sizeRGBA) + curRGB] = + prevcoeff[curRGB] = + (lambda * coeff[(x * sizeRGBA) + (y * w * sizeRGBA) + curRGB]) + + (Zp * prevcoeff[curRGB]); + + // Generate the initial anti-causal at the last pixel per row. + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + coeff[(x * sizeRGBA) + ((h - 1) * w * sizeRGBA) + curRGB] = + prevcoeff[curRGB] = + iZp * coeff[(x * sizeRGBA) + ((h - 1) * w * sizeRGBA) + curRGB]; + + // Perform anti-causal recursion along each row. n = w - 2 skips our + // last coefficient above. + for (y = h - 2; y >= 0; y--) + for (curRGB = 0; curRGB < sizeRGB; curRGB++) + coeff[(x * sizeRGBA) + (h * y * sizeRGBA) + curRGB] = + prevcoeff[curRGB] = Zp * (prevcoeff[curRGB] - + coeff[(x * sizeRGBA) + (h * y * sizeRGBA) + curRGB]); + } + + // Copy to the out ImBuf. + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) + // Copy with alpha (sizeRGBA). + for (curRGB = 0; curRGB < sizeRGBA; curRGB++) + out->rect_float[(y * w * sizeRGBA) + (x * sizeRGBA) + curRGB] = + coeff[(y * w * sizeRGBA) + (x * sizeRGBA) + curRGB]; +} + /* 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 44566) +++ source/blender/imbuf/IMB_imbuf.h (working copy) @@ -405,6 +405,9 @@ * * @attention defined in imageprocess.c */ + +void prefilter(struct ImBuf *in, struct ImBuf *out, unsigned int w, unsigned int h); + 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 44566) +++ 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,25 @@ 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) && ibuf && obuf) { + fbuf = IMB_dupImBuf(ibuf); + if (fbuf->rect_float) + prefilter(ibuf, fbuf, cbuf->x, cbuf->y); + } + + + 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,13 +108,19 @@ 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; } } } - + IMB_freeImBuf(ibuf); IMB_freeImBuf(obuf); } + + if (fbuf) + IMB_freeImBuf(fbuf); /* pass on output and free */ return stackbuf;