diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2015-11-25 19:16:57 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2015-11-25 19:16:57 +0300 |
commit | feb574f21c5fcb883748bff843544f1f0c6a62a2 (patch) | |
tree | 90d1bf9303fb5658cd70c18779074e24f7bcc231 /source/blender/compositor | |
parent | bbd33b3a8ec563372bf230204290f7338a35eb29 (diff) |
Use different approach to the antialias node
It uses edge extrapolation code from Gimp's antialias plugin now,
which has advantage of giving symmetrical results, which makes it
possible to add two antialiased ID masks and have a constant 1.0
all over the frame. But has difference from the old implementation
because it uses 3x3 matrix only, which doesn't give so much smooth
looking edges. Perhaps it's not so bad, since if edges are really
need to be smooth one might use Blur node.
Another advantage is that the node is now nicely threaded.
Reviewers: campbellbarton
Reviewed By: campbellbarton
Subscribers: ania
Differential Revision: https://developer.blender.org/D1617
Diffstat (limited to 'source/blender/compositor')
-rw-r--r-- | source/blender/compositor/operations/COM_AntiAliasOperation.cpp | 136 | ||||
-rw-r--r-- | source/blender/compositor/operations/COM_AntiAliasOperation.h | 1 |
2 files changed, 91 insertions, 46 deletions
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp index 2e60c2d3e42..deb1ebb6dc6 100644 --- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp +++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp @@ -15,9 +15,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand + * Contributor(s): Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin */ #include "COM_AntiAliasOperation.h" @@ -31,76 +31,122 @@ extern "C" { } +/* An implementation of the Scale3X edge-extrapolation algorithm. + * + * Code from GIMP plugin, based on code from Adam D. Moss (adam@gimp.org) + * licensed by the MIT license. + */ +static int extrapolate9(float *E0, float *E1, float *E2, + float *E3, float *E4, float *E5, + float *E6, float *E7, float *E8, + const float *A, const float *B, const float *C, + const float *D, const float *E, const float *F, + const float *G, const float *H, const float *I) +{ +#define PEQ(X,Y) (fabsf(*X - *Y) < 1e-3f) +#define PCPY(DST,SRC) do{*DST = *SRC;}while(0) + if ((!PEQ(B,H)) && (!PEQ(D,F))) { + if (PEQ(D,B)) PCPY(E0,D); else PCPY(E0,E); + if ((PEQ(D,B) && !PEQ(E,C)) || (PEQ(B,F) && !PEQ(E,A))) + PCPY(E1,B); else PCPY(E1,E); + if (PEQ(B,F)) PCPY(E2,F); else PCPY(E2,E); + if ((PEQ(D,B) && !PEQ(E,G)) || (PEQ(D,H) && !PEQ(E,A))) + PCPY(E3,D); else PCPY(E3,E); + PCPY(E4,E); + if ((PEQ(B,F) && !PEQ(E,I)) || (PEQ(H,F) && !PEQ(E,C))) + PCPY(E5,F); else PCPY(E5,E); + if (PEQ(D,H)) PCPY(E6,D); else PCPY(E6,E); + if ((PEQ(D,H) && !PEQ(E,I)) || (PEQ(H,F) && !PEQ(E,G))) + PCPY(E7,H); else PCPY(E7,E); + if (PEQ(H,F)) PCPY(E8,F); else PCPY(E8,E); + return 1; + } + else { + return 0; + } +#undef PEQ +#undef PCPY +} + AntiAliasOperation::AntiAliasOperation() : NodeOperation() { this->addInputSocket(COM_DT_VALUE); this->addOutputSocket(COM_DT_VALUE); this->m_valueReader = NULL; - this->m_buffer = NULL; this->setComplex(true); } + void AntiAliasOperation::initExecution() { this->m_valueReader = this->getInputSocketReader(0); - NodeOperation::initMutex(); } -void AntiAliasOperation::executePixel(float output[4], int x, int y, void * /*data*/) +void AntiAliasOperation::executePixel(float output[4], + int x, int y, + void *data) { - if (y < 0 || (unsigned int)y >= this->m_height || x < 0 || (unsigned int)x >= this->m_width) { + MemoryBuffer *input_buffer = (MemoryBuffer *)data; + const int buffer_width = input_buffer->getWidth(), + buffer_height = input_buffer->getHeight(); + if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) { output[0] = 0.0f; } else { - int offset = y * this->m_width + x; - output[0] = this->m_buffer[offset] / 255.0f; + const float *buffer = input_buffer->getBuffer(); + const float *row_curr = &buffer[y * buffer_width]; + if (x == 0 || x == buffer_width - 1 || + y == 0 || y == buffer_height - 1) + { + output[0] = row_curr[x]; + return; + } + const float *row_prev = &buffer[(y - 1) * buffer_width], + *row_next = &buffer[(y + 1) * buffer_width]; + float ninepix[9]; + if (extrapolate9(&ninepix[0], &ninepix[1], &ninepix[2], + &ninepix[3], &ninepix[4], &ninepix[5], + &ninepix[6], &ninepix[7], &ninepix[8], + &row_prev[x - 1], &row_prev[x], &row_prev[x + 1], + &row_curr[x - 1], &row_curr[x], &row_curr[x + 1], + &row_next[x - 1], &row_next[x], &row_next[x + 1])) + { + /* Some rounding magic to so make weighting correct with the + * original coefficients. + */ + unsigned char result = ((3*ninepix[0] + 5*ninepix[1] + 3*ninepix[2] + + 5*ninepix[3] + 6*ninepix[4] + 5*ninepix[5] + + 3*ninepix[6] + 5*ninepix[7] + 3*ninepix[8]) * 255.0f + + 19.0f) / 38.0f; + output[0] = result / 255.0f; + } + else { + output[0] = row_curr[x]; + } } - } void AntiAliasOperation::deinitExecution() { this->m_valueReader = NULL; - if (this->m_buffer) { - MEM_freeN(this->m_buffer); - } - NodeOperation::deinitMutex(); } -bool AntiAliasOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output) +bool AntiAliasOperation::determineDependingAreaOfInterest( + rcti *input, + ReadBufferOperation *readOperation, + rcti *output) { rcti imageInput; - if (this->m_buffer) { - return false; - } - else { - NodeOperation *operation = getInputOperation(0); - imageInput.xmax = operation->getWidth(); - imageInput.xmin = 0; - imageInput.ymax = operation->getHeight(); - imageInput.ymin = 0; - if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output) ) { - return true; - } - } - return false; + NodeOperation *operation = getInputOperation(0); + imageInput.xmax = input->xmax + 1; + imageInput.xmin = input->xmin - 1; + imageInput.ymax = input->ymax + 1; + imageInput.ymin = input->ymin - 1; + return operation->determineDependingAreaOfInterest(&imageInput, + readOperation, + output); } void *AntiAliasOperation::initializeTileData(rcti *rect) { - if (this->m_buffer) { return this->m_buffer; } - lockMutex(); - if (this->m_buffer == NULL) { - MemoryBuffer *tile = (MemoryBuffer *)this->m_valueReader->initializeTileData(rect); - int size = tile->getHeight() * tile->getWidth(); - float *input = tile->getBuffer(); - char *valuebuffer = (char *)MEM_mallocN(sizeof(char) * size, __func__); - for (int i = 0; i < size; i++) { - float in = input[i]; - valuebuffer[i] = FTOCHAR(in); - } - antialias_tagbuf(tile->getWidth(), tile->getHeight(), valuebuffer); - this->m_buffer = valuebuffer; - } - unlockMutex(); - return this->m_buffer; + return getInputOperation(0)->initializeTileData(rect); } diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.h b/source/blender/compositor/operations/COM_AntiAliasOperation.h index 385d59fec3c..996c7c2fe41 100644 --- a/source/blender/compositor/operations/COM_AntiAliasOperation.h +++ b/source/blender/compositor/operations/COM_AntiAliasOperation.h @@ -36,7 +36,6 @@ protected: * @brief Cached reference to the reader */ SocketReader *m_valueReader; - char *m_buffer; public: AntiAliasOperation(); |