This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
Sergey Sharybin feb574f21c 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
2015-11-25 21:16:57 +05:00

153 lines
4.9 KiB
C++

/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Jeroen Bakker
* Monique Dewanchand
* Sergey Sharybin
*/
#include "COM_AntiAliasOperation.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
extern "C" {
# include "RE_render_ext.h"
}
/* 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->setComplex(true);
}
void AntiAliasOperation::initExecution()
{
this->m_valueReader = this->getInputSocketReader(0);
}
void AntiAliasOperation::executePixel(float output[4],
int x, int y,
void *data)
{
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 {
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;
}
bool AntiAliasOperation::determineDependingAreaOfInterest(
rcti *input,
ReadBufferOperation *readOperation,
rcti *output)
{
rcti imageInput;
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)
{
return getInputOperation(0)->initializeTileData(rect);
}