Created
November 26, 2017 23:09
-
-
Save sobotka/e77c6bf5bc5e04a53c9cbf09e4aeb417 to your computer and use it in GitHub Desktop.
Cubic Prefilter Patch against 587b2f105c4e14031f4d70c31d12f9d4da7439ca
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
diff --git a/source/blender/compositor/intern/COM_SocketReader.h b/source/blender/compositor/intern/COM_SocketReader.h | |
index 88b018ef8b..0563d9e1b0 100644 | |
--- a/source/blender/compositor/intern/COM_SocketReader.h | |
+++ b/source/blender/compositor/intern/COM_SocketReader.h | |
@@ -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; | |
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp | |
index fb3efbb67e..459b02afd3 100644 | |
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp | |
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp | |
@@ -40,6 +40,7 @@ BaseImageOperation::BaseImageOperation() : NodeOperation() | |
{ | |
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 @@ ImBuf *BaseImageOperation::getImBuf() | |
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::initExecution() | |
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 @@ void BaseImageOperation::determineResolution(unsigned int resolution[2], unsigne | |
} | |
} | |
+/* 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 @@ void ImageOperation::executePixel(float output[4], float x, float y, PixelSample | |
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 @@ void ImageAlphaOperation::executePixel(float output[4], float x, float y, PixelS | |
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]; | |
} | |
diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h | |
index e75e7daa18..9a7d2d4d79 100644 | |
--- a/source/blender/compositor/operations/COM_ImageOperation.h | |
+++ b/source/blender/compositor/operations/COM_ImageOperation.h | |
@@ -40,6 +40,7 @@ extern "C" { | |
class BaseImageOperation : public NodeOperation { | |
protected: | |
ImBuf *m_buffer; | |
+ ImBuf *m_secondaryBuffer; | |
Image *m_image; | |
ImageUser *m_imageUser; | |
float *m_imageBuffer; | |
@@ -65,14 +66,17 @@ public: | |
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: | |
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp | |
index af0d516183..f7450bd560 100644 | |
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp | |
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp | |
@@ -62,6 +62,13 @@ void MultilayerColorOperation::executePixel(float output[4], float x, float y, P | |
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 { | |
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h | |
index 28dbe11052..1049477ac1 100644 | |
--- a/source/blender/imbuf/IMB_imbuf.h | |
+++ b/source/blender/imbuf/IMB_imbuf.h | |
@@ -416,6 +416,20 @@ void bilinear_interpolation_color(struct ImBuf *in, unsigned char col[4], float | |
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 | |
*/ | |
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c | |
index 863b8424cc..f5662e4fa6 100644 | |
--- a/source/blender/imbuf/intern/imageprocess.c | |
+++ b/source/blender/imbuf/intern/imageprocess.c | |
@@ -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 @@ void neareast_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, i | |
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, | |
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c | |
index 0d7d20d04a..613526734a 100644 | |
--- a/source/blender/makesrna/intern/rna_nodetree.c | |
+++ b/source/blender/makesrna/intern/rna_nodetree.c | |
@@ -137,6 +137,7 @@ EnumPropertyItem node_sampler_type_items[] = { | |
{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} | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment