Developer Documentation
FilterKernels.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 
51 #include <ACG/GL/ShaderCache.hh>
52 #include <ACG/GL/ScreenQuad.hh>
53 #include <ACG/GL/GLFormatInfo.hh>
54 #include <ACG/ShaderUtils/GLSLShader.hh>
55 
56 #include <ACG/GL/FBO.hh>
57 
58 #include "FilterKernels.hh"
59 
60 #include <QPainter>
61 
62 #include <fstream>
63 
64 
65 namespace ACG
66 {
67 
68 
69 BaseSeparableFilterKernel::BaseSeparableFilterKernel( int _texWidth, int _texHeight, GLenum _internalfmt )
70  : texWidth_(_texWidth),
71  texHeight_(_texHeight),
72  internalfmt_(_internalfmt),
73  externalfmt_(_internalfmt),
74  tempRT_(new FBO())
75 {
76  externalfmt_ = ACG::GLFormatInfo(internalfmt_).format();
77  texelSize_ = ACG::Vec2f(1.0f / float(_texWidth), 1.0f / float(_texHeight));
78 }
79 
80 
82 {
83  delete tempRT_;
84 }
85 
86 
87 bool BaseSeparableFilterKernel::execute( GLuint _srcTexture, ACG::FBO* _dstFBO, GLuint _dstColorAttachment, GLuint _tempColorAttachment )
88 {
89  bool success = true;
90 
91  GLuint tempTexture = 0;
92  if (!_dstFBO || !_tempColorAttachment)
93  {
94  tempTexture = tempRT_->getAttachment(GL_COLOR_ATTACHMENT0);
95 
96  if (!tempTexture)
97  {
98  tempRT_->attachTexture2D(GL_COLOR_ATTACHMENT0, texWidth_, texHeight_, internalfmt_, externalfmt_, GL_CLAMP, GL_LINEAR, GL_LINEAR);
99 
100  tempTexture = tempRT_->getAttachment(GL_COLOR_ATTACHMENT0);
101  }
102  }
103  else
104  {
105  tempTexture = _dstFBO->getAttachment(tempTexture);
106 
107  if (!tempTexture)
108  return false;
109  }
110 
111  GLint vp[4];
112  glGetIntegerv(GL_VIEWPORT, vp);
113  glViewport(0, 0, texWidth_, texHeight_);
114 
115  // temp target
116 
117  ACG::FBO* passFBO = 0;
118  if (_tempColorAttachment && _dstFBO)
119  {
120  _dstFBO->bind();
121  glDrawBuffer(_tempColorAttachment);
122  passFBO = _dstFBO;
123  }
124  else
125  {
126  tempRT_->bind();
127  glDrawBuffer(GL_COLOR_ATTACHMENT0);
128  passFBO = tempRT_;
129  }
130 
131 
132  // 1. pass
133 
134  GLSL::Program* passShader = setupPass(0, _srcTexture);
135 
136  if (passShader)
137  ACG::ScreenQuad::draw(passShader);
138  else
139  success = false;
140 
141  passFBO->unbind();
142 
143  // 2. pass
144 
145  if (_dstFBO && _dstColorAttachment)
146  {
147  _dstFBO->bind();
148  glDrawBuffer(_dstColorAttachment);
149  passFBO = _dstFBO;
150  }
151  else
152  {
153  // render to previously bound fbo
154  passFBO = 0;
155  }
156 
157 
158  passShader = setupPass(1, tempTexture);
159 
160  if (passShader)
161  ACG::ScreenQuad::draw(passShader);
162  else
163  success = false;
164 
165  // restore input fbo
166  if (passFBO)
167  passFBO->unbind();
168  glViewport(vp[0], vp[1], vp[2], vp[3]);
169 
170  return success;
171 }
172 
173 void BaseSeparableFilterKernel::resizeInput( int _texWidth, int _texHeight )
174 {
175  if ( (texWidth_ != _texWidth || texHeight_ != _texHeight) )
176  {
177  texWidth_ = _texWidth;
178  texHeight_ = _texHeight;
179  texelSize_ = ACG::Vec2f(1.0f / float(_texWidth), 1.0f / float(_texHeight));
180 
181  if (tempRT_->width())
182  tempRT_->resize(_texWidth, _texHeight);
183 
184  updateKernel();
185  }
186 }
187 
188 // ----------------------------------------------------------------------------
189 
190 
191 GaussianBlurFilter::GaussianBlurFilter( int _texWidth,
192  int _texHeight,
193  int _blurRadius,
194  float _blurSigma,
195  GLenum _internalfmt )
196  : BaseSeparableFilterKernel(_texWidth, _texHeight, _internalfmt),
197  radius_(_blurRadius),
198  samples_(2 * _blurRadius + 1),
199  sigma_(_blurSigma)
200 {
201  updateKernel();
202 }
203 
205 {
206 
207 }
208 
209 
210 void GaussianBlurFilter::updateKernel()
211 {
212  samples_ = radius_ * 2 + 1;
213 
214  offsetsX_.resize(samples_);
215  offsetsY_.resize(samples_);
216  weights_.resize(samples_);
217 
218  // center sample
219  offsetsX_[radius_] = ACG::Vec2f(0.0f, 0.0f);
220  offsetsY_[radius_] = ACG::Vec2f(0.0f, 0.0f);
221  weights_[radius_] = 1.0f;
222 
223  float weightSum = 1.0f; // 1.0 is the weight of the center sample
224 
225  // left and right taps
226  for (int i = 0; i < radius_; ++i)
227  {
228  // offset
229  ACG::Vec2f v = texelSize() * float(i + 1);
230  offsetsX_[i] = ACG::Vec2f(-v[0], 0.0f);
231  offsetsX_[radius_ + i + 1] = ACG::Vec2f(v[0], 0.0f);
232 
233  offsetsY_[i] = ACG::Vec2f(0.0f, -v[1]);
234  offsetsY_[radius_ + i + 1] = ACG::Vec2f(0.0f, v[1]);
235 
236  // weight
237  float w = expf(-float((i+1)*(i+1)) / (sigma_ * sigma_));
238  weights_[radius_ + i + 1] = weights_[i] = w;
239  weightSum += 2.0f * w;
240  }
241 
242 
243  // normalize
244  for (int i = 0; i < samples_; ++i)
245  weights_[i] /= weightSum;
246 
247  QString blurSamplesMacro;
248  blurSamplesMacro.sprintf("#define BLUR_SAMPLES %i", samples_);
249  macros_.clear();
250  macros_.push_back(blurSamplesMacro);
251 }
252 
253 
254 
255 void GaussianBlurFilter::setKernel( int _blurRadius, float _blurSigma )
256 {
257  radius_ = _blurRadius;
258  sigma_ = _blurSigma;
259  updateKernel();
260 }
261 
262 GLSL::Program* GaussianBlurFilter::setupPass(int _pass, GLuint _srcTex)
263 {
264  GLSL::Program* blurShader = ACG::ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Blur/kernel.glsl", &macros_);
265 
266  if (_pass == 0)
267  {
268  // 1. pass horizontal blur
269 
270  blurShader->use();
271 
272  blurShader->setUniform("g_InputTex", 0);
273  blurShader->setUniform("g_SampleOffsets", &offsetsX_[0], samples_);
274  blurShader->setUniform("g_SampleWeights", &weights_[0], samples_);
275 
276  glActiveTexture(GL_TEXTURE0);
277  glBindTexture(GL_TEXTURE_2D, _srcTex);
278  }
279  else
280  {
281  // 2. pass vertical blur
282 
283  blurShader->setUniform("g_SampleOffsets", &offsetsY_[0], samples_);
284 
285  glBindTexture(GL_TEXTURE_2D, _srcTex);
286  }
287 
288  return blurShader;
289 }
290 
291 
292 // ----------------------------------------------------------------------------
293 
294 
295 BilateralBlurFilter::BilateralBlurFilter(int _texWidth, int _texHeight,
296  int _blurRadius,
297  float _blurSigmaS,
298  float _blurSigmaR,
299  GLenum _internalfmt)
300  : BaseSeparableFilterKernel(_texWidth, _texHeight, _internalfmt),
301  radius_(_blurRadius),
302  samples_(2 * _blurRadius + 1),
303  sigma_(_blurSigmaS, _blurSigmaR),
304  depthTex_(0)
305 {
306  updateKernel();
307 }
308 
310 {
311 
312 }
313 
314 
315 void BilateralBlurFilter::updateKernel()
316 {
317  samples_ = radius_ * 2 + 1;
318 
319  sigma2Rcp_ = ACG::Vec2f(-1.0f / (2.0f * sigma_[0] * sigma_[0]),
320  -1.0f / (2.0f * sigma_[1] * sigma_[1]));
321 
322 
323  // compute filter kernel
324 
325  offsetsX_.resize(samples_);
326  offsetsY_.resize(samples_);
327  spatialKernel_.resize(samples_);
328 
329 
330  // center sample
331  offsetsX_[radius_] = ACG::Vec2f(0.0f, 0.0f);
332  offsetsY_[radius_] = ACG::Vec2f(0.0f, 0.0f);
333  spatialKernel_[radius_] = 0.0f;
334 
335  // left and right taps
336  for (int i = 0; i < radius_; ++i)
337  {
338  // offset
339  ACG::Vec2f v = texelSize() * float(i + 1);
340  offsetsX_[i] = ACG::Vec2f(-v[0], 0.0f);
341  offsetsX_[radius_ + i + 1] = ACG::Vec2f(v[0], 0.0f);
342 
343  offsetsY_[i] = ACG::Vec2f(0.0f, -v[1]);
344  offsetsY_[radius_ + i + 1] = ACG::Vec2f(0.0f, v[1]);
345 
346  // spatial kernel
347  float r2 = float((i+1)*(i+1));
348  spatialKernel_[radius_ + i + 1] = spatialKernel_[i] = r2 * sigma2Rcp_[0];
349  }
350 
351 
352  macros_.clear();
353 
354  QString radiusMacro;
355  radiusMacro.sprintf("#define BLUR_SAMPLES %i", samples_);
356 
357  int numChannels = GLFormatInfo(internalFormat()).channelCount();
358  numChannels = std::max(std::min(numChannels, 4), 1);
359 
360  const char* blurChannels[4] =
361  {
362  "BLUR_R",
363  "BLUR_RG",
364  "BLUR_RGB",
365  "BLUR_RGBA"
366  };
367 
368  QString channelMacro;
369  channelMacro.sprintf("#define BLUR_CHANNELS %s", blurChannels[numChannels - 1]);
370 
371  macros_.push_back(radiusMacro);
372  macros_.push_back(channelMacro);
373 }
374 
375 void BilateralBlurFilter::setKernel( int _blurRadius, float _blurSigmaS, float _blurSigmaR )
376 {
377  radius_ = _blurRadius;
378  sigma_ = ACG::Vec2f(_blurSigmaS, _blurSigmaR);
379  updateKernel();
380 }
381 
382 GLSL::Program* BilateralBlurFilter::setupPass(int _pass, GLuint _srcTex)
383 {
384  GLSL::Program* blurShader = ACG::ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Blur/bilateral.glsl", &macros_);
385 
386  if (_pass == 0)
387  {
388  // 1. pass horizontal blur
389 
390  blurShader->use();
391 
392  blurShader->setUniform("g_InputTex", 0);
393  blurShader->setUniform("g_DepthTex", 1);
394  blurShader->setUniform("g_P", proj_);
395 
396  blurShader->setUniform("g_BlurSigmaRcp2", sigma2Rcp_[1]);
397  blurShader->setUniform("g_SampleOffsets", &offsetsX_[0], samples_);
398  blurShader->setUniform("g_SpatialKernel", &spatialKernel_[0], samples_);
399 
400  glActiveTexture(GL_TEXTURE1);
401  glBindTexture(GL_TEXTURE_2D, depthTex_);
402 
403  glActiveTexture(GL_TEXTURE0);
404  glBindTexture(GL_TEXTURE_2D, _srcTex);
405  }
406  else
407  {
408  // 2. pass vertical blur
409 
410  blurShader->setUniform("g_SampleOffsets", &offsetsY_[0], samples_);
411 
412  glBindTexture(GL_TEXTURE_2D, _srcTex);
413  }
414 
415  return blurShader;
416 }
417 
418 
419 // ----------------------------------------------------------------------------
420 
421 
422 RadialBlurFilter::RadialBlurFilter( int _numSamples )
423  : samples_(0)
424 {
425  setKernel(_numSamples);
426 }
427 
428 bool RadialBlurFilter::execute( GLuint _srcTexture, float _blurRadius, float _blurIntensity, const ACG::Vec2f& _blurCenter )
429 {
430  GLSL::Program* blurShader = ACG::ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Blur/radial.glsl", &macros_);
431 
432  if (blurShader)
433  {
434  glActiveTexture(GL_TEXTURE0);
435  glBindTexture(GL_TEXTURE_2D, _srcTexture);
436 
437 
438  blurShader->use();
439 
440  blurShader->setUniform("g_InputTex", 0);
441  blurShader->setUniform("g_BlurCenter", _blurCenter);
442  blurShader->setUniform("g_BlurRadiusRcp2", 1.0f / (_blurRadius * _blurRadius));
443  blurShader->setUniform("g_BlurIntensity", _blurIntensity);
444 
445  ACG::ScreenQuad::draw(blurShader);
446 
447  return true;
448  }
449 
450  return false;
451 }
452 
453 void RadialBlurFilter::setKernel( int _numSamples )
454 {
455  samples_ = _numSamples;
456 
457  macros_.clear();
458  QString sampleMacro;
459  sampleMacro.sprintf("#define BLUR_SAMPLES %i", _numSamples);
460  macros_.push_back(sampleMacro);
461 }
462 
463 
464 // ----------------------------------------------------------------------------
465 
466 
467 PoissonBlurFilter::PoissonBlurFilter( float _radius, float _sampleDistance, int _numTris /*= 30*/ )
468  : radius_(_radius), sampleDistance_(_sampleDistance), numTries_(_numTris)
469 {
470  // "Fast Poisson Disk Sampling in Arbitrary Dimensions"
471  // http://people.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf
472 
473  // rejection test for disk domain
474 
475  // domain during generation is [0, 2 * radius]
476  // this is mapped to [-radius, radius] afterwards
477 
478  // step 0.
479 
480  // r = sampleDistance, n = 2
481  float cellSize = _sampleDistance / sqrtf(2.0f);
482 
483  int gridSize = int(2.0f * _radius / cellSize) + 1; // account for partially sized cell at the end
484 
485  std::vector<int> grid(gridSize * gridSize, -1);
486 
487 
488 
489  // step 1.
490 
491  ACG::Vec2f x0(0.0f, 0.0f);
492 
493  // initial uniform sample in disk
494  do
495  {
496  x0 = ACG::Vec2f(float(rand()) / float(RAND_MAX), float(rand()) / float(RAND_MAX));
497  } while ((x0 * 2.0f - ACG::Vec2f(1.0f, 1.0f)).sqrnorm() > _radius*_radius);
498 
499  x0 = x0 * 2.0f * _radius;
500 
501  std::list<int> activeList;
502 
503  samples_.reserve(32);
504  samples_.push_back(x0);
505  activeList.push_back(0);
506  int numSamples = 1;
507 
508  ACG::Vec2i gridPos0(int(x0[0] / cellSize), int(x0[1] / cellSize));
509 
510  grid[gridPos0[1] * gridSize + gridPos0[0]] = 0;
511 
512 
513  // step 2.
514 
515  float sampleDistance2 = _sampleDistance * _sampleDistance;
516 
517  while (!activeList.empty())
518  {
519  int listSize = activeList.size();
520  // random index i
521  int i = int((float(rand()) / float(RAND_MAX)) * float(listSize) + 0.5f);
522 
523  i = std::min(i, listSize - 1);
524 
525 // int sample_i = activeList[i];
526  int sample_i = -1;
527  std::list<int>::iterator it_i = activeList.begin();
528  for (int counter = 0; it_i != activeList.end(); ++it_i, ++counter)
529  {
530  if (counter == i)
531  {
532  sample_i = *it_i;
533  break;
534  }
535  }
536 
537  ACG::Vec2f x_i = samples_[sample_i];
538 
539  ACG::Vec2i gridPos_i(int(x_i[0] / cellSize), int(x_i[1] / cellSize));
540 
541  bool foundNextSample_i = false;
542 
543  // k uniform point samples in circle around x_i
544  for (int s = 0; s < _numTris; ++s)
545  {
546  float u = float(rand()) / float(RAND_MAX);
547  float v = float(rand()) / float(RAND_MAX);
548 
549  float alpha = float(M_PI) * 2.0f * u;
550  ACG::Vec2f x_s(cosf(alpha), sinf(alpha));
551 
552  // between r and 2r, where r = sample distance
553  x_s *= _sampleDistance + 2.0f * _sampleDistance * v;
554 
555  // centered around x_i
556  x_s += x_i;
557 
558  ACG::Vec2i gridPos_s(int(x_s[0] / cellSize), int(x_s[1] / cellSize));
559 
560  // oob check
561  if (x_s[0] < 0.0f || x_s[1] < 0.0f || gridPos_s[0] < 0 || gridPos_s[0] >= gridSize || gridPos_s[1] < 0 || gridPos_s[1] >= gridSize)
562  continue;
563 
564  // disk check
565  if ( (x_s - ACG::Vec2f(_radius, _radius)).sqrnorm() > _radius*_radius)
566  continue;
567 
568  // neighborhood check
569 
570  bool tooClose = false;
571 
572  for (int x = -1; x <= 1 && !tooClose; ++x)
573  {
574  for (int y = -1; y <= 1 && !tooClose; ++y)
575  {
576  ACG::Vec2i gridPos_t = gridPos_s + ACG::Vec2i(x,y);
577 
578  // oob check
579  if (gridPos_t[0] < 0 || gridPos_t[0] >= gridSize || gridPos_t[1] < 0 || gridPos_t[1] >= gridSize)
580  continue;
581 
582  int gridValue = grid[gridPos_t[1] * gridSize + gridPos_t[0]];
583 
584  if (gridValue >= 0)
585  {
586  ACG::Vec2f delta_t = samples_[gridValue] - x_s;
587  float d2 = delta_t | delta_t;
588 
589  if (d2 < sampleDistance2)
590  tooClose = true;
591  }
592  }
593  }
594 
595  if (!tooClose)
596  {
597  // new sample found
598  foundNextSample_i = true;
599 
600  grid[gridPos_s[1] * gridSize + gridPos_s[0]] = numSamples;
601  samples_.push_back(x_s);
602 
603  activeList.push_back(numSamples);
604 
605  ++numSamples;
606  }
607  }
608 
609  if (!foundNextSample_i)
610  {
611  // remove from list
612  activeList.erase(it_i);
613  }
614 
615  }
616 
617  // map to [-radius, radius]
618  for (int i = 0; i < numSamples; ++i)
619  samples_[i] = samples_[i] - ACG::Vec2f(_radius, _radius);
620 
621  samplesScaled_ = samples_;
622 
623 
624  QString samplesMacro;
625  samplesMacro.sprintf("#define BLUR_SAMPLES %i", numSamples);
626  macros_.push_back(samplesMacro);
627 }
628 
630 {
631 
632 }
633 
634 
635 void PoissonBlurFilter::dumpSamples( const char* _filename )
636 {
637  std::fstream f(_filename, std::ios_base::out);
638 
639  if (f.is_open())
640  {
641  for (size_t i = 0; i < samples_.size(); ++i)
642  f << "v " << samples_[i][0] << " " << samples_[i][1] << " 0" << std::endl;
643 
644  f.close();
645  }
646 }
647 
648 bool PoissonBlurFilter::execute( GLuint _srcTex, float _kernelScale )
649 {
650  // scale kernel
651  int n = numSamples();
652  for (int i = 0; i < n; ++i)
653  samplesScaled_[i] = samples_[i] * _kernelScale;
654 
655  GLSL::Program* blurShader = ACG::ShaderCache::getInstance()->getProgram("ScreenQuad/screenquad.glsl", "Blur/poisson.glsl", &macros_);
656 
657  if (blurShader)
658  {
659  blurShader->use();
660  blurShader->setUniform("g_InputTex", 0);
661  blurShader->setUniform("g_SampleOffsets", &samplesScaled_[0], n);
662 
663  glActiveTexture(GL_TEXTURE0);
664  glBindTexture(GL_TEXTURE_2D, _srcTex);
665 
666  ACG::ScreenQuad::draw(blurShader);
667 
668  return true;
669  }
670 
671  return false;
672 }
673 
674 void PoissonBlurFilter::plotSamples( QImage* _image )
675 {
676  // cross radius of samples in image
677  const int crossRadius = 2;
678 
679  if (_image)
680  {
681  int w = _image->width(),
682  h = _image->height();
683 
684  _image->fill(qRgb(255,255,255));
685 
686  // draw outer circle
687  QPainter plotter;
688  plotter.begin(_image);
689  plotter.setPen(QPen(qRgb(0,0,0)));
690  plotter.drawEllipse(0, 0, _image->width()-1, _image->height()-1);
691  plotter.end();
692 
693  // draw samples
694  for (int i = 0; i < numSamples(); ++i)
695  {
696  // map sample pos to [0,1]
697  Vec2f s = samples_[i];
698  s /= radius_;
699  s = s * 0.5f + Vec2f(0.5f, 0.5f);
700 
701  // map to [0, imageSize]
702  s *= Vec2f(w-1,h-1);
703 
704  // draw cross for samples
705  Vec2i pc(s[0] + 0.5f, s[1] + 0.5f); // pixel center
706 
707  for (int k = -crossRadius; k <= crossRadius; ++k)
708  {
709  for (int mirror = 0; mirror < 2; ++mirror)
710  {
711  Vec2i p = pc + Vec2i(k * (mirror ? -1 : 1),k);
712 
713  // clamp to image size
714  p[0] = std::min(std::max(p[0], 0), w-1);
715  p[1] = std::min(std::max(p[1], 0), h-1);
716 
717  _image->setPixel(p[0], p[1], qRgb(255, 0, 0));
718  }
719  }
720  }
721  }
722 }
723 
724 
725 }
VectorT< float, 2 > Vec2f
Definition: VectorT.hh:108
static void draw(GLSL::Program *_prog=0)
Draw the screen quad.
Definition: ScreenQuad.cc:147
GLsizei samples_
sample count if multisampling
Definition: FBO.hh:222
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
Definition: ShaderCache.cc:90
bool bind()
bind the fbo and sets it as rendertarget
Definition: FBO.cc:451
void dumpSamples(const char *_filename)
dump samples as point cloud in obj format
Definition: FBO.hh:83
GLuint getAttachment(GLenum _attachment)
return attached texture id
Definition: FBO.cc:529
virtual ~PoissonBlurFilter()
Class destructor.
void use()
Enables the program object for using.
Definition: GLSLShader.cc:351
VectorT< signed int, 2 > Vec2i
Definition: VectorT.hh:104
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:391
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
virtual ~BilateralBlurFilter()
Class destructor.
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
Definition: ShaderCache.cc:108
void unbind()
unbind fbo, go to normal rendering mode
Definition: FBO.cc:474
virtual ~GaussianBlurFilter()
Class destructor.
void plotSamples(QImage *_image)
plot samples on qt image
GLSL program class.
Definition: GLSLShader.hh:217
virtual ~BaseSeparableFilterKernel()
Class destructor.