Index: source/blender/compositor/intern/COM_SocketReader.h =================================================================== --- source/blender/compositor/intern/COM_SocketReader.h (revision 51011) +++ source/blender/compositor/intern/COM_SocketReader.h (working copy) @@ -32,7 +32,8 @@ typedef enum PixelSampler { COM_PS_NEAREST = 0, COM_PS_BILINEAR = 1, - COM_PS_BICUBIC = 2 + COM_PS_BICUBIC = 2, + COM_PS_CUBICBSPLINEPREFILTER = 3 } PixelSampler; class MemoryBuffer; Index: source/blender/compositor/operations/COM_ImageOperation.h =================================================================== --- source/blender/compositor/operations/COM_ImageOperation.h (revision 51011) +++ source/blender/compositor/operations/COM_ImageOperation.h (working copy) @@ -40,6 +40,7 @@ class BaseImageOperation : public NodeOperation { protected: ImBuf *m_buffer; + ImBuf *m_secondaryBuffer; Image *m_image; ImageUser *m_imageUser; float *m_imageBuffer; @@ -65,14 +66,17 @@ void setImageUser(ImageUser *imageuser) { this->m_imageUser = imageuser; } void setFramenumber(int framenumber) { this->m_framenumber = framenumber; } + + void initSecondaryBuffer(int buffer_type); }; class ImageOperation : public BaseImageOperation { +protected: public: /** * Constructor */ ImageOperation(); - void executePixel(float output[4], float x, float y, PixelSampler sampler); + void executePixel(float output[4], float x, float y, PixelSampler sampler); }; class ImageAlphaOperation : public BaseImageOperation { public: Index: source/blender/compositor/operations/COM_MultilayerImageOperation.cpp =================================================================== --- source/blender/compositor/operations/COM_MultilayerImageOperation.cpp (revision 51011) +++ source/blender/compositor/operations/COM_MultilayerImageOperation.cpp (working copy) @@ -62,6 +62,13 @@ case COM_PS_BICUBIC: bicubic_interpolation_color(this->m_buffer, NULL, output, x, y); break; + case COM_PS_CUBICBSPLINEPREFILTER: + lockMutex(); + if (this->m_secondaryBuffer == NULL) { + BaseImageOperation::initSecondaryBuffer(BT_CUBICBSPLINEPREFILTER); + } + unlockMutex(); + bicubic_interpolation_color(this->m_secondaryBuffer, NULL, output, x, y); } } else { Index: source/blender/compositor/operations/COM_ImageOperation.cpp =================================================================== --- source/blender/compositor/operations/COM_ImageOperation.cpp (revision 51011) +++ source/blender/compositor/operations/COM_ImageOperation.cpp (working copy) @@ -40,6 +40,7 @@ { this->m_image = NULL; this->m_buffer = NULL; + this->m_secondaryBuffer = NULL; this->m_imageBuffer = NULL; this->m_imageUser = NULL; this->m_imagewidth = 0; @@ -80,6 +81,7 @@ void BaseImageOperation::initExecution() { ImBuf *stackbuf = getImBuf(); + this->initMutex(); this->m_buffer = stackbuf; if (stackbuf) { this->m_imageBuffer = stackbuf->rect_float; @@ -92,7 +94,12 @@ void BaseImageOperation::deinitExecution() { + this->deinitMutex(); this->m_imageBuffer = NULL; + if (this->m_secondaryBuffer) { + IMB_freeImBuf(m_secondaryBuffer); + m_secondaryBuffer = NULL; + } } void BaseImageOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) @@ -108,6 +115,20 @@ } } +/* Must be located in BaseImageOperation to avoid code duplication */ +void BaseImageOperation::initSecondaryBuffer(int buffer_type) +{ + switch (buffer_type) { + case BT_DUPLICATE: + this->m_secondaryBuffer = IMB_dupImBuf(this->m_buffer); + break; + case BT_CUBICBSPLINEPREFILTER: + this->m_secondaryBuffer = IMB_dupImBuf(this->m_buffer); + create_prefilter(this->m_buffer, this->m_secondaryBuffer); + break; + } +} + void ImageOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { if (this->m_imageBuffer == NULL || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) { @@ -124,6 +145,13 @@ case COM_PS_BICUBIC: bicubic_interpolation_color(this->m_buffer, NULL, output, x, y); break; + case COM_PS_CUBICBSPLINEPREFILTER: + lockMutex(); + if (this->m_secondaryBuffer == NULL) { + BaseImageOperation::initSecondaryBuffer(BT_CUBICBSPLINEPREFILTER); + } + unlockMutex(); + bicubic_interpolation_color(this->m_secondaryBuffer, NULL, output, x, y); } } } @@ -147,6 +175,13 @@ case COM_PS_BICUBIC: bicubic_interpolation_color(this->m_buffer, NULL, tempcolor, x, y); break; + case COM_PS_CUBICBSPLINEPREFILTER: + lockMutex(); + if (this->m_secondaryBuffer == NULL) { + BaseImageOperation::initSecondaryBuffer(BT_CUBICBSPLINEPREFILTER); + } + unlockMutex(); + bicubic_interpolation_color(this->m_secondaryBuffer, NULL, output, x, y); } output[0] = tempcolor[3]; } Index: source/blender/makesrna/intern/rna_nodetree.c =================================================================== --- source/blender/makesrna/intern/rna_nodetree.c (revision 51011) +++ source/blender/makesrna/intern/rna_nodetree.c (working copy) @@ -137,6 +137,7 @@ {0, "NEAREST", 0, "Nearest", ""}, {1, "BILINEAR", 0, "Bilinear", ""}, {2, "BICUBIC", 0, "Bicubic", ""}, + {3, "CUBICBSPLINEPREFILTER", 0, "Cubic B Spline with Prefilter", ""}, {0, NULL, 0, NULL, NULL} }; Index: source/blender/imbuf/intern/imageprocess.c =================================================================== --- source/blender/imbuf/intern/imageprocess.c (revision 51011) +++ source/blender/imbuf/intern/imageprocess.c (working copy) @@ -47,6 +47,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include +#include /* Only this one is used liberally here, and in imbuf */ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf) @@ -461,6 +462,117 @@ neareast_interpolation_color(in, outI, outF, x, y); } +/*********************** CubicBSpline Prefilter ****************************/ +/* This function creates a prefilter in the frequency domain. It can be + viewed as a compliment to a traditional bicubic filter. */ + +void create_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 + } +} + /*********************** Threaded image processing *************************/ void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_customdata, Index: source/blender/imbuf/IMB_imbuf.h =================================================================== --- source/blender/imbuf/IMB_imbuf.h (revision 51011) +++ source/blender/imbuf/IMB_imbuf.h (working copy) @@ -416,6 +416,20 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v); /** + * Establish the prefilter algorithm at lowest level to be adopted + * by other areas of Blender such as MIPmaps. + */ + +/* Buffer Types */ +#define BT_DUPLICATE 0 +#define BT_CUBICBSPLINEPREFILTER 1 + +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 create_prefilter(struct ImBuf *in, struct ImBuf *out); + +/** * * \attention defined in readimage.c */