Created
January 1, 2018 20:49
-
-
Save sobotka/087ff83cca6c729abc3654ae2c39fe73 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 <math.h> | |
+#include <string.h> | |
/* 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 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment