Blender  V2.93
COM_GaussianBokehBlurOperation.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2011, Blender Foundation.
17  */
18 
20 #include "BLI_math.h"
21 #include "MEM_guardedalloc.h"
22 
23 #include "RE_pipeline.h"
24 
25 namespace blender::compositor {
26 
28 {
29  this->m_gausstab = nullptr;
30 }
31 
33 {
34  lockMutex();
35  if (!this->m_sizeavailable) {
36  updateGauss();
37  }
38  void *buffer = getInputOperation(0)->initializeTileData(nullptr);
39  unlockMutex();
40  return buffer;
41 }
42 
44 {
46 
47  initMutex();
48 
49  if (this->m_sizeavailable) {
50  updateGauss();
51  }
52 }
53 
54 void GaussianBokehBlurOperation::updateGauss()
55 {
56  if (this->m_gausstab == nullptr) {
57  float radxf;
58  float radyf;
59  int n;
60  float *dgauss;
61  float *ddgauss;
62  int j, i;
63  const float width = this->getWidth();
64  const float height = this->getHeight();
65  if (!this->m_sizeavailable) {
66  updateSize();
67  }
68  radxf = this->m_size * (float)this->m_data.sizex;
69  CLAMP(radxf, 0.0f, width / 2.0f);
70 
71  /* vertical */
72  radyf = this->m_size * (float)this->m_data.sizey;
73  CLAMP(radyf, 0.0f, height / 2.0f);
74 
75  this->m_radx = ceil(radxf);
76  this->m_rady = ceil(radyf);
77 
78  int ddwidth = 2 * this->m_radx + 1;
79  int ddheight = 2 * this->m_rady + 1;
80  n = ddwidth * ddheight;
81 
82  /* create a full filter image */
83  ddgauss = (float *)MEM_mallocN(sizeof(float) * n, __func__);
84  dgauss = ddgauss;
85  float sum = 0.0f;
86  float facx = (radxf > 0.0f ? 1.0f / radxf : 0.0f);
87  float facy = (radyf > 0.0f ? 1.0f / radyf : 0.0f);
88  for (j = -this->m_rady; j <= this->m_rady; j++) {
89  for (i = -this->m_radx; i <= this->m_radx; i++, dgauss++) {
90  float fj = (float)j * facy;
91  float fi = (float)i * facx;
92  float dist = sqrt(fj * fj + fi * fi);
93  *dgauss = RE_filter_value(this->m_data.filtertype, dist);
94 
95  sum += *dgauss;
96  }
97  }
98 
99  if (sum > 0.0f) {
100  /* normalize */
101  float norm = 1.0f / sum;
102  for (j = n - 1; j >= 0; j--) {
103  ddgauss[j] *= norm;
104  }
105  }
106  else {
107  int center = m_rady * ddwidth + m_radx;
108  ddgauss[center] = 1.0f;
109  }
110 
111  this->m_gausstab = ddgauss;
112  }
113 }
114 
115 void GaussianBokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
116 {
117  float tempColor[4];
118  tempColor[0] = 0;
119  tempColor[1] = 0;
120  tempColor[2] = 0;
121  tempColor[3] = 0;
122  float multiplier_accum = 0;
123  MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
124  float *buffer = inputBuffer->getBuffer();
125  int bufferwidth = inputBuffer->getWidth();
126  const rcti &input_rect = inputBuffer->get_rect();
127  int bufferstartx = input_rect.xmin;
128  int bufferstarty = input_rect.ymin;
129 
130  int ymin = max_ii(y - this->m_rady, input_rect.ymin);
131  int ymax = min_ii(y + this->m_rady + 1, input_rect.ymax);
132  int xmin = max_ii(x - this->m_radx, input_rect.xmin);
133  int xmax = min_ii(x + this->m_radx + 1, input_rect.xmax);
134 
135  int index;
136  int step = QualityStepHelper::getStep();
137  int offsetadd = QualityStepHelper::getOffsetAdd();
138  const int addConst = (xmin - x + this->m_radx);
139  const int mulConst = (this->m_radx * 2 + 1);
140  for (int ny = ymin; ny < ymax; ny += step) {
141  index = ((ny - y) + this->m_rady) * mulConst + addConst;
142  int bufferindex = ((xmin - bufferstartx) * 4) + ((ny - bufferstarty) * 4 * bufferwidth);
143  for (int nx = xmin; nx < xmax; nx += step) {
144  const float multiplier = this->m_gausstab[index];
145  madd_v4_v4fl(tempColor, &buffer[bufferindex], multiplier);
146  multiplier_accum += multiplier;
147  index += step;
148  bufferindex += offsetadd;
149  }
150  }
151 
152  mul_v4_v4fl(output, tempColor, 1.0f / multiplier_accum);
153 }
154 
156 {
158 
159  if (this->m_gausstab) {
160  MEM_freeN(this->m_gausstab);
161  this->m_gausstab = nullptr;
162  }
163 
164  deinitMutex();
165 }
166 
168  rcti *input, ReadBufferOperation *readOperation, rcti *output)
169 {
170  rcti newInput;
171  rcti sizeInput;
172  sizeInput.xmin = 0;
173  sizeInput.ymin = 0;
174  sizeInput.xmax = 5;
175  sizeInput.ymax = 5;
176  NodeOperation *operation = this->getInputOperation(1);
177 
178  if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
179  return true;
180  }
181 
182  if (this->m_sizeavailable && this->m_gausstab != nullptr) {
183  newInput.xmin = 0;
184  newInput.ymin = 0;
185  newInput.xmax = this->getWidth();
186  newInput.ymax = this->getHeight();
187  }
188  else {
189  int addx = this->m_radx;
190  int addy = this->m_rady;
191  newInput.xmax = input->xmax + addx;
192  newInput.xmin = input->xmin - addx;
193  newInput.ymax = input->ymax + addy;
194  newInput.ymin = input->ymin - addy;
195  }
196  return BlurBaseOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
197 }
198 
199 // reference image
202 {
203  this->m_maintabs = nullptr;
204 }
205 
207 {
208  void *buffer = getInputOperation(0)->initializeTileData(nullptr);
209  return buffer;
210 }
211 
213 {
215  // setup gaustab
216  this->m_data.image_in_width = this->getWidth();
217  this->m_data.image_in_height = this->getHeight();
218  if (this->m_data.relative) {
219  switch (this->m_data.aspect) {
221  this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width);
222  this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height);
223  break;
225  this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width);
226  this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_width);
227  break;
229  this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_height);
230  this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height);
231  break;
232  }
233  }
234 
235  /* horizontal */
236  m_filtersizex = (float)this->m_data.sizex;
237  int imgx = getWidth() / 2;
238  if (m_filtersizex > imgx) {
239  m_filtersizex = imgx;
240  }
241  else if (m_filtersizex < 1) {
242  m_filtersizex = 1;
243  }
244  m_radx = (float)m_filtersizex;
245 
246  /* vertical */
247  m_filtersizey = (float)this->m_data.sizey;
248  int imgy = getHeight() / 2;
249  if (m_filtersizey > imgy) {
250  m_filtersizey = imgy;
251  }
252  else if (m_filtersizey < 1) {
253  m_filtersizey = 1;
254  }
255  m_rady = (float)m_filtersizey;
256  updateGauss();
257 }
258 
259 void GaussianBlurReferenceOperation::updateGauss()
260 {
261  int i;
262  int x = MAX2(m_filtersizex, m_filtersizey);
263  m_maintabs = (float **)MEM_mallocN(x * sizeof(float *), "gauss array");
264  for (i = 0; i < x; i++) {
265  m_maintabs[i] = make_gausstab(i + 1, i + 1);
266  }
267 }
268 
270 {
271  MemoryBuffer *memorybuffer = (MemoryBuffer *)data;
272  float *buffer = memorybuffer->getBuffer();
273  float *gausstabx, *gausstabcenty;
274  float *gausstaby, *gausstabcentx;
275  int i, j;
276  float *src;
277  float sum, val;
278  float rval, gval, bval, aval;
279  int imgx = getWidth();
280  int imgy = getHeight();
281  float tempSize[4];
282  this->m_inputSize->read(tempSize, x, y, data);
283  float refSize = tempSize[0];
284  int refradx = (int)(refSize * m_radx);
285  int refrady = (int)(refSize * m_rady);
286  if (refradx > m_filtersizex) {
287  refradx = m_filtersizex;
288  }
289  else if (refradx < 1) {
290  refradx = 1;
291  }
292  if (refrady > m_filtersizey) {
293  refrady = m_filtersizey;
294  }
295  else if (refrady < 1) {
296  refrady = 1;
297  }
298 
299  if (refradx == 1 && refrady == 1) {
300  memorybuffer->readNoCheck(output, x, y);
301  }
302  else {
303  int minxr = x - refradx < 0 ? -x : -refradx;
304  int maxxr = x + refradx > imgx ? imgx - x : refradx;
305  int minyr = y - refrady < 0 ? -y : -refrady;
306  int maxyr = y + refrady > imgy ? imgy - y : refrady;
307 
308  float *srcd = buffer + COM_DATA_TYPE_COLOR_CHANNELS * ((y + minyr) * imgx + x + minxr);
309 
310  gausstabx = m_maintabs[refradx - 1];
311  gausstabcentx = gausstabx + refradx;
312  gausstaby = m_maintabs[refrady - 1];
313  gausstabcenty = gausstaby + refrady;
314 
315  sum = gval = rval = bval = aval = 0.0f;
316  for (i = minyr; i < maxyr; i++, srcd += COM_DATA_TYPE_COLOR_CHANNELS * imgx) {
317  src = srcd;
318  for (j = minxr; j < maxxr; j++, src += COM_DATA_TYPE_COLOR_CHANNELS) {
319 
320  val = gausstabcenty[i] * gausstabcentx[j];
321  sum += val;
322  rval += val * src[0];
323  gval += val * src[1];
324  bval += val * src[2];
325  aval += val * src[3];
326  }
327  }
328  sum = 1.0f / sum;
329  output[0] = rval * sum;
330  output[1] = gval * sum;
331  output[2] = bval * sum;
332  output[3] = aval * sum;
333  }
334 }
335 
337 {
338  int x, i;
339  x = MAX2(this->m_filtersizex, this->m_filtersizey);
340  for (i = 0; i < x; i++) {
341  MEM_freeN(this->m_maintabs[i]);
342  }
343  MEM_freeN(this->m_maintabs);
345 }
346 
348  rcti *input, ReadBufferOperation *readOperation, rcti *output)
349 {
350  rcti newInput;
351  NodeOperation *operation = this->getInputOperation(1);
352 
353  if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
354  return true;
355  }
356 
357  int addx = this->m_data.sizex + 2;
358  int addy = this->m_data.sizey + 2;
359  newInput.xmax = input->xmax + addx;
360  newInput.xmin = input->xmin - addx;
361  newInput.ymax = input->ymax + addy;
362  newInput.ymin = input->ymin - addy;
363  return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
364 }
365 
366 } // namespace blender::compositor
typedef float(TangentPoint)[2]
sqrt(x)+1/max(0
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE void mul_v4_v4fl(float r[3], const float a[4], float f)
MINLINE void madd_v4_v4fl(float r[4], const float a[4], float f)
#define MAX2(a, b)
#define CMP_NODE_BLUR_ASPECT_X
#define CMP_NODE_BLUR_ASPECT_Y
#define CMP_NODE_BLUR_ASPECT_NONE
NSNotificationCenter * center
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble ny
_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 GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_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
Read Guarded memory(de)allocation.
Group RGB to Bright Vector Camera CLAMP
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume Image Sky Noise Wave Voronoi Brick Texture Vector Combine Vertex Color
#define output
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition: btVector3.h:263
float * make_gausstab(float rad, int size)
void executePixel(float output[4], int x, int y, void *data) override
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override
void executePixel(float output[4], int x, int y, void *data) override
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override
a MemoryBuffer contains access to the data of a chunk
void readNoCheck(float *result, int x, int y, MemoryBufferExtend extend_x=MemoryBufferExtend::Clip, MemoryBufferExtend extend_y=MemoryBufferExtend::Clip)
const rcti & get_rect() const
get the rect of this MemoryBuffer
const int getWidth() const
get the width of this MemoryBuffer
float * getBuffer()
get the data of this MemoryBuffer
NodeOperation contains calculation logic.
virtual void * initializeTileData(rcti *)
NodeOperation * getInputOperation(unsigned int inputSocketindex)
void read(float result[4], int x, int y, void *chunkData)
virtual bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
DataType
possible data types for sockets
Definition: COM_defines.h:27
float RE_filter_value(int type, float x)
Definition: initrender.c:128
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
constexpr int COM_DATA_TYPE_COLOR_CHANNELS
Definition: COM_defines.h:53
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79
ccl_device_inline float3 ceil(const float3 &a)