Blender  V3.3
COM_AntiAliasOperation.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2011 Blender Foundation. */
3 
5 
6 namespace blender::compositor {
7 
8 /* An implementation of the Scale3X edge-extrapolation algorithm.
9  *
10  * Code from GIMP plugin, based on code from Adam D. Moss <adam@gimp.org>
11  * licensed by the MIT license.
12  */
13 static int extrapolate9(float *E0,
14  float *E1,
15  float *E2,
16  float *E3,
17  float *E4,
18  float *E5,
19  float *E6,
20  float *E7,
21  float *E8,
22  const float *A,
23  const float *B,
24  const float *C,
25  const float *D,
26  const float *E,
27  const float *F,
28  const float *G,
29  const float *H,
30  const float *I)
31 {
32 #define PEQ(X, Y) (fabsf(*X - *Y) < 1e-3f)
33 #define PCPY(DST, SRC) \
34  do { \
35  *DST = *SRC; \
36  } while (0)
37  if ((!PEQ(B, H)) && (!PEQ(D, F))) {
38  if (PEQ(D, B)) {
39  PCPY(E0, D);
40  }
41  else {
42  PCPY(E0, E);
43  }
44  if ((PEQ(D, B) && !PEQ(E, C)) || (PEQ(B, F) && !PEQ(E, A))) {
45  PCPY(E1, B);
46  }
47  else {
48  PCPY(E1, E);
49  }
50  if (PEQ(B, F)) {
51  PCPY(E2, F);
52  }
53  else {
54  PCPY(E2, E);
55  }
56  if ((PEQ(D, B) && !PEQ(E, G)) || (PEQ(D, H) && !PEQ(E, A))) {
57  PCPY(E3, D);
58  }
59  else {
60  PCPY(E3, E);
61  }
62  PCPY(E4, E);
63  if ((PEQ(B, F) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, C))) {
64  PCPY(E5, F);
65  }
66  else {
67  PCPY(E5, E);
68  }
69  if (PEQ(D, H)) {
70  PCPY(E6, D);
71  }
72  else {
73  PCPY(E6, E);
74  }
75  if ((PEQ(D, H) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, G))) {
76  PCPY(E7, H);
77  }
78  else {
79  PCPY(E7, E);
80  }
81  if (PEQ(H, F)) {
82  PCPY(E8, F);
83  }
84  else {
85  PCPY(E8, E);
86  }
87  return 1;
88  }
89 
90  return 0;
91 
92 #undef PEQ
93 #undef PCPY
94 }
95 
97 {
100  value_reader_ = nullptr;
101  flags_.complex = true;
102 }
103 
105 {
107 }
108 
109 void AntiAliasOperation::execute_pixel(float output[4], int x, int y, void *data)
110 {
111  MemoryBuffer *input_buffer = (MemoryBuffer *)data;
112  const int buffer_width = input_buffer->get_width(), buffer_height = input_buffer->get_height();
113  if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) {
114  output[0] = 0.0f;
115  }
116  else {
117  const float *buffer = input_buffer->get_buffer();
118  const float *row_curr = &buffer[y * buffer_width];
119  if (x == 0 || x == buffer_width - 1 || y == 0 || y == buffer_height - 1) {
120  output[0] = row_curr[x];
121  return;
122  }
123  const float *row_prev = &buffer[(y - 1) * buffer_width],
124  *row_next = &buffer[(y + 1) * buffer_width];
125  float ninepix[9];
126  if (extrapolate9(&ninepix[0],
127  &ninepix[1],
128  &ninepix[2],
129  &ninepix[3],
130  &ninepix[4],
131  &ninepix[5],
132  &ninepix[6],
133  &ninepix[7],
134  &ninepix[8],
135  &row_prev[x - 1],
136  &row_prev[x],
137  &row_prev[x + 1],
138  &row_curr[x - 1],
139  &row_curr[x],
140  &row_curr[x + 1],
141  &row_next[x - 1],
142  &row_next[x],
143  &row_next[x + 1])) {
144  /* Some rounding magic to so make weighting correct with the
145  * original coefficients.
146  */
147  unsigned char result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] + 5 * ninepix[3] +
148  6 * ninepix[4] + 5 * ninepix[5] + 3 * ninepix[6] + 5 * ninepix[7] +
149  3 * ninepix[8]) *
150  255.0f +
151  19.0f) /
152  38.0f;
153  output[0] = result / 255.0f;
154  }
155  else {
156  output[0] = row_curr[x];
157  }
158  }
159 }
160 
162 {
163  value_reader_ = nullptr;
164 }
165 
167  ReadBufferOperation *read_operation,
168  rcti *output)
169 {
170  rcti image_input;
171  NodeOperation *operation = get_input_operation(0);
172  image_input.xmax = input->xmax + 1;
173  image_input.xmin = input->xmin - 1;
174  image_input.ymax = input->ymax + 1;
175  image_input.ymin = input->ymin - 1;
176  return operation->determine_depending_area_of_interest(&image_input, read_operation, output);
177 }
178 
180 {
181  return get_input_operation(0)->initialize_tile_data(rect);
182 }
183 
185  const rcti &output_area,
186  rcti &r_input_area)
187 {
188  BLI_assert(input_idx == 0);
189  UNUSED_VARS_NDEBUG(input_idx);
190  r_input_area.xmax = output_area.xmax + 1;
191  r_input_area.xmin = output_area.xmin - 1;
192  r_input_area.ymax = output_area.ymax + 1;
193  r_input_area.ymin = output_area.ymin - 1;
194 }
195 
197  const rcti &area,
199 {
200  const MemoryBuffer *input = inputs[0];
201  const rcti &input_area = input->get_rect();
202  float ninepix[9];
203  for (int y = area.ymin; y < area.ymax; y++) {
204  float *out = output->get_elem(area.xmin, y);
205  const float *row_curr = input->get_elem(area.xmin, y);
206  const float *row_prev = row_curr - input->row_stride;
207  const float *row_next = row_curr + input->row_stride;
208  int x_offset = 0;
209  for (int x = area.xmin; x < area.xmax;
210  x++, out += output->elem_stride, x_offset += input->elem_stride) {
211  if (x == input_area.xmin || x == input_area.xmax - 1 || y == input_area.xmin ||
212  y == input_area.ymax - 1) {
213  out[0] = row_curr[x_offset];
214  continue;
215  }
216 
217  if (extrapolate9(&ninepix[0],
218  &ninepix[1],
219  &ninepix[2],
220  &ninepix[3],
221  &ninepix[4],
222  &ninepix[5],
223  &ninepix[6],
224  &ninepix[7],
225  &ninepix[8],
226  &row_prev[x_offset - input->elem_stride],
227  &row_prev[x_offset],
228  &row_prev[x_offset + input->elem_stride],
229  &row_curr[x_offset - input->elem_stride],
230  &row_curr[x_offset],
231  &row_curr[x_offset + input->elem_stride],
232  &row_next[x_offset - input->elem_stride],
233  &row_next[x_offset],
234  &row_next[x_offset + input->elem_stride])) {
235  /* Some rounding magic to make weighting correct with the
236  * original coefficients. */
237  unsigned char result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] +
238  5 * ninepix[3] + 6 * ninepix[4] + 5 * ninepix[5] +
239  3 * ninepix[6] + 5 * ninepix[7] + 3 * ninepix[8]) *
240  255.0f +
241  19.0f) /
242  38.0f;
243  out[0] = result / 255.0f;
244  }
245  else {
246  out[0] = row_curr[x_offset];
247  }
248  }
249  }
250 }
251 
252 } // namespace blender::compositor
#define D
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED_VARS_NDEBUG(...)
#define PEQ(X, Y)
#define PCPY(DST, SRC)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
#define C
Definition: RandGen.cpp:25
#define A
void execute_pixel(float output[4], int x, int y, void *data) override
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
SocketReader * value_reader_
Cached reference to the reader.
bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output) override
void * initialize_tile_data(rcti *rect) override
a MemoryBuffer contains access to the data of a chunk
const int get_width() const
get the width of this MemoryBuffer
const int get_height() const
get the height of this MemoryBuffer
float * get_buffer()
get the data of this MemoryBuffer
NodeOperation contains calculation logic.
void add_output_socket(DataType datatype)
SocketReader * get_input_socket_reader(unsigned int index)
NodeOperation * get_input_operation(int index)
virtual bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output)
void add_input_socket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
virtual void * initialize_tile_data(rcti *)
ccl_global float * buffer
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
#define B
#define F
#define G(x, y, z)
#define H(x, y, z)
static void area(int d1, int d2, int e1, int e2, float weights[2])
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)
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static bNodeSocketTemplate inputs[]
#define I
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63