Skip to content

Instantly share code, notes, and snippets.

@sobotka
Created January 1, 2018 20:49
Show Gist options
  • Save sobotka/087ff83cca6c729abc3654ae2c39fe73 to your computer and use it in GitHub Desktop.
Save sobotka/087ff83cca6c729abc3654ae2c39fe73 to your computer and use it in GitHub Desktop.
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